{"_id":"fetchdts","_rev":"12-2d2f1ffeff78e20c4a588d483868caa9","name":"fetchdts","dist-tags":{"latest":"0.2.0"},"versions":{"0.0.0":{"name":"fetchdts","version":"0.0.0","author":{"name":"Daniel Roe","email":"daniel@roe.dev"},"_id":"fetchdts@0.0.0","maintainers":[{"name":"danielroe","email":"daniel@roe.dev"}],"dist":{"shasum":"72f16a6f26a9b8e2ae4a0eaee122a6c2cb960643","tarball":"https://registry.npmjs.org/fetchdts/-/fetchdts-0.0.0.tgz","fileCount":2,"integrity":"sha512-6kCqDjoDo5pwxFScpARBQr1eNTG58Ezrk9DPdnO1V++7EoToLVJOnsVxyVb0TU00aVmG9nCYOacWvIUM77e/cA==","signatures":[{"sig":"MEQCID7ozn+qNa/ds/yZCKvH+CK2CA1lSjHCk33hV5MBrFlXAiB4r1pIa/MyS/7SghTKwNkj337VVc0shiPfc6jpgMqVZQ==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":118},"gitHead":"2076451926cbe1b95c45cc9a33a77faa0acd2bdb","_npmUser":{"name":"danielroe","email":"daniel@roe.dev"},"_npmVersion":"10.7.0","directories":{},"_nodeVersion":"18.20.4","_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/fetchdts_0.0.0_1726221569223_0.2803058973604533","host":"s3://npm-registry-packages"}},"0.0.1":{"name":"fetchdts","version":"0.0.1","license":"MIT","_id":"fetchdts@0.0.1","maintainers":[{"name":"danielroe","email":"daniel@roe.dev"}],"homepage":"https://github.com/danielroe/fetchdts#readme","bugs":{"url":"https://github.com/danielroe/fetchdts/issues"},"dist":{"shasum":"df31f69c9ae8eb09223d94fe4d5248e58546e2d9","tarball":"https://registry.npmjs.org/fetchdts/-/fetchdts-0.0.1.tgz","fileCount":5,"integrity":"sha512-pMWZRPXMF6ZjMa+Wg8JjO7geJqjWvzJSdYmQGt3sWlUqs3fIDxFPUNocQBSJpseNTsKlyBdSzPB6ejIGjGzo0g==","signatures":[{"sig":"MEUCIHPk/qZm/Ku0jmYgVAhy5ABe8yOhVXwQ26RYPD7/A7bBAiEAi+A+rrC5TlPZDZde3VHgartDwrQHEMu3ThIgAaVttyE=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":9313},"main":"./dist/index.js","type":"module","_from":"file:fetchdts-0.0.1.tgz","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":"./dist/index.js"},"scripts":{"dev":"vitest dev","lint":"eslint . --fix","test":"pnpm test:unit && pnpm test:types","build":"unbuild","release":"bumpp && pnpm publish","test:knip":"knip","test:unit":"vitest --typecheck","test:types":"tsc --noEmit","test:versions":"installed-check -d --no-workspaces"},"_npmUser":{"name":"danielroe","email":"daniel@roe.dev"},"_resolved":"/private/var/folders/48/0bsggqvn049_nfcq7msw2njw0000gn/T/59cfceed4b478afb9a4a3a46fc358a6b/fetchdts-0.0.1.tgz","_integrity":"sha512-pMWZRPXMF6ZjMa+Wg8JjO7geJqjWvzJSdYmQGt3sWlUqs3fIDxFPUNocQBSJpseNTsKlyBdSzPB6ejIGjGzo0g==","repository":{"url":"git+https://github.com/danielroe/fetchdts.git","type":"git"},"_npmVersion":"10.9.0","description":"A suite of type utilities for building strongly-typed APIs","directories":{},"lint-staged":{"*.{js,ts,mjs,cjs,json,.*rc}":["npx eslint --fix"]},"resolutions":{"fetchdts":"link:."},"sideEffects":false,"_nodeVersion":"22.12.0","_hasShrinkwrap":false,"devDependencies":{"knip":"latest","bumpp":"latest","eslint":"latest","vitest":"latest","unbuild":"latest","typescript":"latest","lint-staged":"latest","changelogithub":"latest","installed-check":"latest","simple-git-hooks":"latest","@vitest/coverage-v8":"latest","@antfu/eslint-config":"latest"},"simple-git-hooks":{"pre-commit":"npx lint-staged"},"_npmOperationalInternal":{"tmp":"tmp/fetchdts_0.0.1_1737675194439_0.5172064837679342","host":"s3://npm-registry-packages-npm-production"}},"0.0.2":{"name":"fetchdts","version":"0.0.2","author":{"url":"https://roe.dev","name":"Daniel Roe","email":"daniel@roe.dev"},"license":"MIT","_id":"fetchdts@0.0.2","maintainers":[{"name":"danielroe","email":"daniel@roe.dev"}],"homepage":"https://github.com/unjs/fetchdts#readme","bugs":{"url":"https://github.com/unjs/fetchdts/issues"},"dist":{"shasum":"04cbf40aceb937a68c5255d0aae43be8efc36206","tarball":"https://registry.npmjs.org/fetchdts/-/fetchdts-0.0.2.tgz","fileCount":5,"integrity":"sha512-2O/zKDGhj3/yDfr/ar5xI0HjHpsWKKQnlkPpLISw5DkAlYN0Mz5gVDC9g1QOfwtnoDowL7Yd4oZCeo5tr8Y+AA==","signatures":[{"sig":"MEUCIQCBb46wA6IltIIPkgRIA0wOaesDATr0NAkoEnIJR29NzAIgMsUSOejY87+Pj+F5yoxLn354ImB4I83Qcj2TM3ElIy0=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":13686},"main":"./dist/index.mjs","type":"module","_from":"file:fetchdts-0.0.2.tgz","types":"./dist/index.d.mts","module":"./dist/index.mjs","exports":{".":"./dist/index.mjs"},"scripts":{"dev":"vitest dev","lint":"eslint .","test":"pnpm test:unit && pnpm test:types","build":"unbuild","release":"bumpp && pnpm publish","test:knip":"knip","test:unit":"vitest --typecheck","test:types":"tsc --noEmit","test:versions":"installed-check -d --no-workspaces"},"_npmUser":{"name":"danielroe","email":"daniel@roe.dev"},"_resolved":"/private/var/folders/6z/46zhtr8n22zg8nh3bp7cq7c40000gn/T/25b0e182eac6e58988b72f649c85b4be/fetchdts-0.0.2.tgz","_integrity":"sha512-2O/zKDGhj3/yDfr/ar5xI0HjHpsWKKQnlkPpLISw5DkAlYN0Mz5gVDC9g1QOfwtnoDowL7Yd4oZCeo5tr8Y+AA==","repository":{"url":"git+https://github.com/unjs/fetchdts.git","type":"git"},"_npmVersion":"10.9.2","description":"A suite of type utilities for building strongly-typed APIs","directories":{},"lint-staged":{"*.{js,ts,mjs,cjs,json,.*rc}":["npx eslint --fix"]},"resolutions":{"fetchdts":"link:."},"sideEffects":false,"_nodeVersion":"22.14.0","_hasShrinkwrap":false,"devDependencies":{"knip":"5.53.0","bumpp":"10.1.0","eslint":"9.26.0","vitest":"3.1.3","unbuild":"3.5.0","typescript":"5.8.3","@types/node":"latest","lint-staged":"15.5.1","changelogithub":"13.13.0","installed-check":"9.3.0","simple-git-hooks":"2.13.0","@vitest/coverage-v8":"3.1.3","@antfu/eslint-config":"4.12.0"},"simple-git-hooks":{"pre-commit":"npx lint-staged"},"_npmOperationalInternal":{"tmp":"tmp/fetchdts_0.0.2_1746734644046_0.862841170938639","host":"s3://npm-registry-packages-npm-production"}},"0.0.3":{"name":"fetchdts","version":"0.0.3","author":{"url":"https://roe.dev","name":"Daniel Roe","email":"daniel@roe.dev"},"license":"MIT","_id":"fetchdts@0.0.3","maintainers":[{"name":"danielroe","email":"daniel@roe.dev"}],"homepage":"https://github.com/unjs/fetchdts#readme","bugs":{"url":"https://github.com/unjs/fetchdts/issues"},"dist":{"shasum":"3ab8aa70160a41a8036fb07aa58b318794114402","tarball":"https://registry.npmjs.org/fetchdts/-/fetchdts-0.0.3.tgz","fileCount":5,"integrity":"sha512-3F9KoJZAJ3V0y7040UCao5ZbM7Kefknj3mowA+LOsuvZcu2ddkHakhDaAdqiKNuW2SyMF60N0EZSC/YkQbSYpQ==","signatures":[{"sig":"MEUCIDUPxlb/1tg3xGHZuXZfJMUc9kKdwfhr+xbYC4fNVP5jAiEAnt5NJan/Y+MOHskE2aT6Rayx5hUQirQT1AbmNO2UKKc=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":91193},"main":"./dist/index.mjs","type":"module","_from":"file:fetchdts-0.0.3.tgz","types":"./dist/index.d.mts","module":"./dist/index.mjs","exports":{".":"./dist/index.mjs"},"scripts":{"dev":"vitest dev","lint":"eslint .","test":"pnpm test:unit && pnpm test:types","build":"unbuild","release":"bumpp && pnpm publish","test:knip":"knip","test:unit":"vitest --typecheck","test:types":"tsc --noEmit","test:versions":"installed-check -d --no-workspaces"},"_npmUser":{"name":"danielroe","email":"daniel@roe.dev"},"_resolved":"/private/var/folders/6z/46zhtr8n22zg8nh3bp7cq7c40000gn/T/b629ae0750f6dc72e6daec246c91b74a/fetchdts-0.0.3.tgz","_integrity":"sha512-3F9KoJZAJ3V0y7040UCao5ZbM7Kefknj3mowA+LOsuvZcu2ddkHakhDaAdqiKNuW2SyMF60N0EZSC/YkQbSYpQ==","repository":{"url":"git+https://github.com/unjs/fetchdts.git","type":"git"},"_npmVersion":"10.9.2","description":"A suite of type utilities for building strongly-typed APIs","directories":{},"lint-staged":{"*.{js,ts,mjs,cjs,json,.*rc}":["npx eslint --fix"]},"resolutions":{"fetchdts":"link:."},"sideEffects":false,"_nodeVersion":"22.14.0","_hasShrinkwrap":false,"devDependencies":{"knip":"5.53.0","bumpp":"10.1.0","eslint":"9.26.0","vitest":"3.1.3","unbuild":"3.5.0","typescript":"5.8.3","@types/node":"latest","lint-staged":"15.5.1","changelogithub":"13.13.0","installed-check":"9.3.0","simple-git-hooks":"2.13.0","@vitest/coverage-v8":"3.1.3","@antfu/eslint-config":"4.12.0"},"simple-git-hooks":{"pre-commit":"npx lint-staged"},"_npmOperationalInternal":{"tmp":"tmp/fetchdts_0.0.3_1746779171072_0.3876829179801229","host":"s3://npm-registry-packages-npm-production"}},"0.1.0":{"name":"fetchdts","version":"0.1.0","author":{"url":"https://roe.dev","name":"Daniel Roe","email":"daniel@roe.dev"},"license":"MIT","_id":"fetchdts@0.1.0","maintainers":[{"name":"danielroe","email":"daniel@roe.dev"}],"homepage":"https://github.com/unjs/fetchdts#readme","bugs":{"url":"https://github.com/unjs/fetchdts/issues"},"dist":{"shasum":"7afcbf86d1d6e762285d944bdb5eb2ca17a9200d","tarball":"https://registry.npmjs.org/fetchdts/-/fetchdts-0.1.0.tgz","fileCount":5,"integrity":"sha512-jQPsXjIz6YlAJRVHfDqalsiCaFij1118XbcIL/qEIbCGpvkatBxnyRE6A1NTVyt1fO4/21CmAHNGG+GYKmNrTw==","signatures":[{"sig":"MEYCIQDP23eLY6zDlC+EBJGJZ1lvojW/wR70YHJnJKUKAFikugIhAK3muYloqN/lXZUrNpSC3wMd7yTvkBkyAMQH7WuyybXM","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":91640},"main":"./dist/index.mjs","type":"module","_from":"file:fetchdts-0.1.0.tgz","types":"./dist/index.d.mts","module":"./dist/index.mjs","exports":{".":"./dist/index.mjs"},"scripts":{"dev":"vitest dev","lint":"eslint .","test":"pnpm test:unit && pnpm test:types","build":"unbuild","release":"bumpp && pnpm publish","test:knip":"knip","test:unit":"vitest --typecheck","test:types":"tsc --noEmit","test:versions":"installed-check -d --no-workspaces"},"_npmUser":{"name":"danielroe","email":"daniel@roe.dev"},"_resolved":"/private/var/folders/48/0bsggqvn049_nfcq7msw2njw0000gn/T/bb4c624a2ef10f8289d1d084d119ed29/fetchdts-0.1.0.tgz","_integrity":"sha512-jQPsXjIz6YlAJRVHfDqalsiCaFij1118XbcIL/qEIbCGpvkatBxnyRE6A1NTVyt1fO4/21CmAHNGG+GYKmNrTw==","repository":{"url":"git+https://github.com/unjs/fetchdts.git","type":"git"},"_npmVersion":"10.9.2","description":"A suite of type utilities for building strongly-typed APIs","directories":{},"lint-staged":{"*.{js,ts,mjs,cjs,json,.*rc}":["npx eslint --fix"]},"resolutions":{"fetchdts":"link:."},"sideEffects":false,"_nodeVersion":"22.14.0","_hasShrinkwrap":false,"devDependencies":{"knip":"5.59.1","bumpp":"10.1.1","eslint":"9.26.0","vitest":"3.1.4","unbuild":"3.5.0","typescript":"5.8.3","@types/node":"latest","lint-staged":"16.1.0","changelogithub":"13.15.0","installed-check":"9.3.0","simple-git-hooks":"2.13.0","@vitest/coverage-v8":"3.1.4","@antfu/eslint-config":"4.13.2"},"simple-git-hooks":{"pre-commit":"npx lint-staged"},"_npmOperationalInternal":{"tmp":"tmp/fetchdts_0.1.0_1748593414540_0.3673131512840604","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"fetchdts","version":"0.1.1","author":{"url":"https://roe.dev","name":"Daniel Roe","email":"daniel@roe.dev"},"license":"MIT","_id":"fetchdts@0.1.1","maintainers":[{"name":"danielroe","email":"daniel@roe.dev"}],"homepage":"https://github.com/unjs/fetchdts#readme","bugs":{"url":"https://github.com/unjs/fetchdts/issues"},"dist":{"shasum":"9af8c8642469718f365672ddf5a09ad7cd0e4f87","tarball":"https://registry.npmjs.org/fetchdts/-/fetchdts-0.1.1.tgz","fileCount":5,"integrity":"sha512-6kyKr/PtvU2Bj2Kmk8vH9JuB6FMBpXnAAaIPst7J1mSQRg4WxLmSl7KM3deP9l84kNGM6V/jv9kz3RFtu1eLoA==","signatures":[{"sig":"MEQCIFMPBOSL2sZObTBrdOMSuLpHQZQl91vjNDS2g911OAEYAiBXopp3T/9402knFsi+mD60Rj1x9h97o2OmWekl69Xe8w==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":101291},"main":"./dist/index.mjs","type":"module","_from":"file:fetchdts-0.1.1.tgz","types":"./dist/index.d.mts","module":"./dist/index.mjs","exports":{".":"./dist/index.mjs"},"scripts":{"dev":"vitest dev","lint":"eslint .","test":"pnpm test:unit && pnpm test:types","build":"unbuild","release":"bumpp && pnpm publish","test:knip":"knip","test:unit":"vitest --typecheck","test:types":"tsc --noEmit","test:versions":"installed-check -d --no-workspaces"},"_npmUser":{"name":"danielroe","email":"daniel@roe.dev"},"_resolved":"/private/var/folders/48/0bsggqvn049_nfcq7msw2njw0000gn/T/71c94059a0c4ded7197948dd5a252f9d/fetchdts-0.1.1.tgz","_integrity":"sha512-6kyKr/PtvU2Bj2Kmk8vH9JuB6FMBpXnAAaIPst7J1mSQRg4WxLmSl7KM3deP9l84kNGM6V/jv9kz3RFtu1eLoA==","repository":{"url":"git+https://github.com/unjs/fetchdts.git","type":"git"},"_npmVersion":"10.9.2","description":"A suite of type utilities for building strongly-typed APIs","directories":{},"lint-staged":{"*.{js,ts,mjs,cjs,json,.*rc}":["npx eslint --fix"]},"resolutions":{"fetchdts":"link:."},"sideEffects":false,"_nodeVersion":"22.14.0","_hasShrinkwrap":false,"devDependencies":{"knip":"5.59.1","bumpp":"10.1.1","eslint":"9.27.0","vitest":"3.1.4","unbuild":"3.5.0","typescript":"5.8.3","@types/node":"latest","lint-staged":"16.1.0","changelogithub":"13.15.0","installed-check":"9.3.0","simple-git-hooks":"2.13.0","@vitest/coverage-v8":"3.1.4","@antfu/eslint-config":"4.13.2"},"simple-git-hooks":{"pre-commit":"npx lint-staged"},"_npmOperationalInternal":{"tmp":"tmp/fetchdts_0.1.1_1748616009032_0.8387340369190743","host":"s3://npm-registry-packages-npm-production"}},"0.1.3":{"name":"fetchdts","version":"0.1.3","author":{"url":"https://roe.dev","name":"Daniel Roe","email":"daniel@roe.dev"},"license":"MIT","_id":"fetchdts@0.1.3","maintainers":[{"name":"danielroe","email":"daniel@roe.dev"}],"homepage":"https://github.com/unjs/fetchdts#readme","bugs":{"url":"https://github.com/unjs/fetchdts/issues"},"dist":{"shasum":"fcd7cd242571ce1d645ffcd3e30e8ae42fd257cc","tarball":"https://registry.npmjs.org/fetchdts/-/fetchdts-0.1.3.tgz","fileCount":5,"integrity":"sha512-3sypjmvtv3TKl67qRoejPULUddI8BpduKRnppX/oB3FYQxPMVsO0nIP3LWp+8d4ddYNxg6Kh7TU5zztsfE2g4g==","signatures":[{"sig":"MEUCICODBSo7UCKjPqouTddvWHIixEClUeVOX3s6z18jXIHPAiEAwmbzVkBIwWu9t+Hgl8GnNYJ+g42+C45nLsiUzd4MgQI=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":101297},"main":"./dist/index.mjs","type":"module","_from":"file:fetchdts-0.1.3.tgz","types":"./dist/index.d.mts","module":"./dist/index.mjs","exports":{".":"./dist/index.mjs"},"scripts":{"dev":"vitest dev","lint":"eslint .","test":"pnpm test:unit && pnpm test:types","build":"unbuild","release":"bumpp && pnpm publish","test:knip":"knip","test:unit":"vitest --typecheck","test:types":"tsc --noEmit","test:versions":"installed-check -d --no-workspaces"},"_npmUser":{"name":"danielroe","email":"daniel@roe.dev"},"_resolved":"/private/var/folders/6z/46zhtr8n22zg8nh3bp7cq7c40000gn/T/1b2eb2f78828692f7c4b95c8dba7eb89/fetchdts-0.1.3.tgz","_integrity":"sha512-3sypjmvtv3TKl67qRoejPULUddI8BpduKRnppX/oB3FYQxPMVsO0nIP3LWp+8d4ddYNxg6Kh7TU5zztsfE2g4g==","repository":{"url":"git+https://github.com/unjs/fetchdts.git","type":"git"},"_npmVersion":"11.3.0","description":"A suite of type utilities for building strongly-typed APIs","directories":{},"lint-staged":{"*.{js,ts,mjs,cjs,json,.*rc}":["npx eslint --fix"]},"resolutions":{"fetchdts":"link:."},"sideEffects":false,"_nodeVersion":"24.0.2","_hasShrinkwrap":false,"devDependencies":{"knip":"5.59.1","bumpp":"10.1.1","eslint":"9.28.0","vitest":"3.2.2","unbuild":"3.5.0","typescript":"5.8.3","@types/node":"latest","lint-staged":"16.1.0","changelogithub":"13.15.0","installed-check":"9.3.0","simple-git-hooks":"2.13.0","@vitest/coverage-v8":"3.2.2","@antfu/eslint-config":"4.13.2"},"simple-git-hooks":{"pre-commit":"npx lint-staged"},"_npmOperationalInternal":{"tmp":"tmp/fetchdts_0.1.3_1749478491629_0.8168857024451459","host":"s3://npm-registry-packages-npm-production"}},"0.1.4":{"name":"fetchdts","version":"0.1.4","author":{"url":"https://roe.dev","name":"Daniel Roe","email":"daniel@roe.dev"},"license":"MIT","_id":"fetchdts@0.1.4","maintainers":[{"name":"danielroe","email":"daniel@roe.dev"}],"homepage":"https://github.com/unjs/fetchdts#readme","bugs":{"url":"https://github.com/unjs/fetchdts/issues"},"dist":{"shasum":"4fa36d53116386ec3105e5d21fde91c61c9bd99a","tarball":"https://registry.npmjs.org/fetchdts/-/fetchdts-0.1.4.tgz","fileCount":5,"integrity":"sha512-ickQgaQs/RbVxaJauBqmpiNSk9wLoxWRsSjDFP6JpiO3MCguqaSRltwL6HF9V9hJr2Prnqq0ic9b2bTBK8LqRA==","signatures":[{"sig":"MEUCIQD9N83Wo3+772eTC2XwIZU+xcryL8DiWfu65SWY+389RAIgOfe1YEIl8QnYC2L6bSa6DB1PdvJNrZJdR6xN3TJzyGo=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":103627},"main":"./dist/index.mjs","type":"module","_from":"file:fetchdts-0.1.4.tgz","types":"./dist/index.d.mts","module":"./dist/index.mjs","exports":{".":"./dist/index.mjs"},"scripts":{"dev":"vitest dev","lint":"eslint .","test":"pnpm test:unit && pnpm test:types","build":"unbuild","release":"bumpp && pnpm publish","test:knip":"knip","test:unit":"vitest --typecheck","test:types":"tsc --noEmit","test:versions":"installed-check -d --no-workspaces"},"_npmUser":{"name":"danielroe","email":"daniel@roe.dev"},"_resolved":"/private/var/folders/6z/46zhtr8n22zg8nh3bp7cq7c40000gn/T/e80da3d7860dae5e58fdcea3ba583f9e/fetchdts-0.1.4.tgz","_integrity":"sha512-ickQgaQs/RbVxaJauBqmpiNSk9wLoxWRsSjDFP6JpiO3MCguqaSRltwL6HF9V9hJr2Prnqq0ic9b2bTBK8LqRA==","repository":{"url":"git+https://github.com/unjs/fetchdts.git","type":"git"},"_npmVersion":"11.3.0","description":"A suite of type utilities for building strongly-typed APIs","directories":{},"lint-staged":{"*.{js,ts,mjs,cjs,json,.*rc}":["npx eslint --fix"]},"resolutions":{"fetchdts":"link:."},"sideEffects":false,"_nodeVersion":"24.0.2","_hasShrinkwrap":false,"devDependencies":{"knip":"5.59.1","bumpp":"10.1.1","eslint":"9.28.0","vitest":"3.2.2","unbuild":"3.5.0","typescript":"5.8.3","@types/node":"latest","lint-staged":"16.1.0","changelogithub":"13.15.0","installed-check":"9.3.0","simple-git-hooks":"2.13.0","@vitest/coverage-v8":"3.2.2","@antfu/eslint-config":"4.13.2"},"simple-git-hooks":{"pre-commit":"npx lint-staged"},"_npmOperationalInternal":{"tmp":"tmp/fetchdts_0.1.4_1749482993663_0.2313601918629664","host":"s3://npm-registry-packages-npm-production"}},"0.1.5":{"name":"fetchdts","version":"0.1.5","author":{"url":"https://roe.dev","name":"Daniel Roe","email":"daniel@roe.dev"},"license":"MIT","_id":"fetchdts@0.1.5","maintainers":[{"name":"danielroe","email":"daniel@roe.dev"}],"homepage":"https://github.com/unjs/fetchdts#readme","bugs":{"url":"https://github.com/unjs/fetchdts/issues"},"dist":{"shasum":"29d7ef0d794bd95e395430257a0bb94c8b4ae37c","tarball":"https://registry.npmjs.org/fetchdts/-/fetchdts-0.1.5.tgz","fileCount":5,"integrity":"sha512-GCxyHdCCUm56atms+sIjOsAENvhebk3HAM1CfzgKCgMRjPUylpkkPmNknsaXe1gDRqM3cJbMhpkXMhCzXSE+Jg==","signatures":[{"sig":"MEQCIHblUSWbtOvI7D2/iW5usqPfn8I3XcUvd+Bmbw9RevYDAiAX7mBHJWg7gSdc7RqIQByfE7sRMpSIGz4yMjaEli6EsQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":103643},"main":"./dist/index.mjs","type":"module","_from":"file:fetchdts-0.1.5.tgz","types":"./dist/index.d.mts","module":"./dist/index.mjs","exports":{".":"./dist/index.mjs"},"scripts":{"dev":"vitest dev","lint":"eslint .","test":"pnpm test:unit && pnpm test:types","build":"unbuild","release":"bumpp && pnpm publish","test:knip":"knip","test:unit":"vitest --typecheck","test:types":"tsc --noEmit","test:versions":"installed-check -d --no-workspaces"},"_npmUser":{"name":"danielroe","actor":{"name":"danielroe","type":"user","email":"daniel@roe.dev"},"email":"daniel@roe.dev"},"_resolved":"/private/var/folders/48/0bsggqvn049_nfcq7msw2njw0000gn/T/0992af8a7221d4a1455755908e96841f/fetchdts-0.1.5.tgz","_integrity":"sha512-GCxyHdCCUm56atms+sIjOsAENvhebk3HAM1CfzgKCgMRjPUylpkkPmNknsaXe1gDRqM3cJbMhpkXMhCzXSE+Jg==","repository":{"url":"git+https://github.com/unjs/fetchdts.git","type":"git"},"_npmVersion":"11.3.0","description":"A suite of type utilities for building strongly-typed APIs","directories":{},"lint-staged":{"*.{js,ts,mjs,cjs,json,.*rc}":["npx eslint --fix"]},"resolutions":{"fetchdts":"link:."},"sideEffects":false,"_nodeVersion":"24.2.0","_hasShrinkwrap":false,"devDependencies":{"knip":"5.61.3","bumpp":"10.2.0","eslint":"9.29.0","vitest":"3.2.4","unbuild":"3.5.0","typescript":"5.8.3","@types/node":"latest","lint-staged":"16.1.2","changelogithub":"13.16.0","installed-check":"9.3.0","simple-git-hooks":"2.13.0","@vitest/coverage-v8":"3.2.4","@antfu/eslint-config":"4.16.1"},"simple-git-hooks":{"pre-commit":"npx lint-staged"},"_npmOperationalInternal":{"tmp":"tmp/fetchdts_0.1.5_1751132439439_0.1127372317455948","host":"s3://npm-registry-packages-npm-production"}},"0.1.6":{"name":"fetchdts","version":"0.1.6","author":{"url":"https://roe.dev","name":"Daniel Roe","email":"daniel@roe.dev"},"license":"MIT","_id":"fetchdts@0.1.6","maintainers":[{"name":"danielroe","email":"daniel@roe.dev"}],"homepage":"https://github.com/unjs/fetchdts#readme","bugs":{"url":"https://github.com/unjs/fetchdts/issues"},"dist":{"shasum":"0e1d7832883dd707fa78dab84223e10788f56e39","tarball":"https://registry.npmjs.org/fetchdts/-/fetchdts-0.1.6.tgz","fileCount":5,"integrity":"sha512-yR7rc9v+7KOEnSU5sOJfH9OaxhWRfrrk3am1CUliTCy6Bc+JQtGcxFT9MxvmbU34wA8HYkCk5r9lVRAld8IAcQ==","signatures":[{"sig":"MEQCIB5lfXTu5c2bDS09QNXOGO8Drt/xhdnCwhwibtmtt46oAiA0FtSsVEN63jhxcbQMXCJisaPkci/2eKxdh93nKnKyhQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":103641},"main":"./dist/index.mjs","type":"module","_from":"file:fetchdts-0.1.6.tgz","types":"./dist/index.d.mts","module":"./dist/index.mjs","exports":{".":"./dist/index.mjs"},"scripts":{"dev":"vitest dev","lint":"eslint .","test":"pnpm test:unit && pnpm test:types","build":"unbuild","release":"bumpp && pnpm publish","test:knip":"knip","test:unit":"vitest --typecheck","test:types":"tsc --noEmit","test:versions":"installed-check -d --no-workspaces"},"_npmUser":{"name":"danielroe","email":"daniel@roe.dev"},"_resolved":"/private/var/folders/5g/r5lg700163d_r_6t_547flw80000gn/T/dfd080abac6dd19aa403b9a4aa66b829/fetchdts-0.1.6.tgz","_integrity":"sha512-yR7rc9v+7KOEnSU5sOJfH9OaxhWRfrrk3am1CUliTCy6Bc+JQtGcxFT9MxvmbU34wA8HYkCk5r9lVRAld8IAcQ==","repository":{"url":"git+https://github.com/unjs/fetchdts.git","type":"git"},"_npmVersion":"11.4.2","description":"A suite of type utilities for building strongly-typed APIs","directories":{},"lint-staged":{"*.{js,ts,mjs,cjs,json,.*rc}":["npx eslint --fix"]},"resolutions":{"fetchdts":"link:."},"sideEffects":false,"_nodeVersion":"24.4.0","_hasShrinkwrap":false,"devDependencies":{"knip":"5.62.0","bumpp":"10.2.2","eslint":"9.32.0","vitest":"3.2.4","unbuild":"3.6.0","typescript":"5.9.2","@types/node":"latest","lint-staged":"16.1.4","changelogithub":"13.16.0","installed-check":"9.3.0","simple-git-hooks":"2.13.1","@vitest/coverage-v8":"3.2.4","@antfu/eslint-config":"5.1.0"},"simple-git-hooks":{"pre-commit":"npx lint-staged"},"_npmOperationalInternal":{"tmp":"tmp/fetchdts_0.1.6_1754293193302_0.8311294441640822","host":"s3://npm-registry-packages-npm-production"}},"0.1.7":{"name":"fetchdts","version":"0.1.7","author":{"url":"https://roe.dev","name":"Daniel Roe","email":"daniel@roe.dev"},"license":"MIT","_id":"fetchdts@0.1.7","maintainers":[{"name":"danielroe","email":"daniel@roe.dev"}],"homepage":"https://github.com/unjs/fetchdts#readme","bugs":{"url":"https://github.com/unjs/fetchdts/issues"},"dist":{"shasum":"38f2fd01fb1a22cb46b3cd482ea3fb76d3ad91ab","tarball":"https://registry.npmjs.org/fetchdts/-/fetchdts-0.1.7.tgz","fileCount":5,"integrity":"sha512-YoZjBdafyLIop9lSxXVI33oLD5kN31q4Td+CasofLLYeLXRFeOsuOw0Uo+XNRi9PZlbfdlN2GmRtm4tCEQ9/KA==","signatures":[{"sig":"MEUCIQCye/+tEX2h6vVX6jhQV3p11ALP80KTm3xdWXxlBSbOtAIgAZQ/FdLtnHEinjf/UkJLic25zlUzEOxBVJvoEPaF0ts=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":104098},"main":"./dist/index.mjs","type":"module","_from":"file:fetchdts-0.1.7.tgz","types":"./dist/index.d.mts","module":"./dist/index.mjs","exports":{".":"./dist/index.mjs"},"scripts":{"dev":"vitest dev","lint":"eslint .","test":"pnpm test:unit && pnpm test:types","build":"unbuild","release":"bumpp && pnpm publish","test:knip":"knip","test:unit":"vitest --typecheck","test:types":"tsc --noEmit","test:versions":"installed-check -d --no-workspaces"},"_npmUser":{"name":"danielroe","email":"daniel@roe.dev"},"_resolved":"/private/var/folders/6z/46zhtr8n22zg8nh3bp7cq7c40000gn/T/92dbc12742e9760c6be2765c24227f09/fetchdts-0.1.7.tgz","_integrity":"sha512-YoZjBdafyLIop9lSxXVI33oLD5kN31q4Td+CasofLLYeLXRFeOsuOw0Uo+XNRi9PZlbfdlN2GmRtm4tCEQ9/KA==","repository":{"url":"git+https://github.com/unjs/fetchdts.git","type":"git"},"_npmVersion":"11.3.0","description":"A suite of type utilities for building strongly-typed APIs","directories":{},"lint-staged":{"*.{js,ts,mjs,cjs,json,.*rc}":["npx eslint --fix"]},"resolutions":{"fetchdts":"link:."},"sideEffects":false,"_nodeVersion":"24.0.2","_hasShrinkwrap":false,"devDependencies":{"knip":"5.63.0","bumpp":"10.2.3","eslint":"9.34.0","vitest":"3.2.4","unbuild":"3.6.1","typescript":"5.9.2","@types/node":"latest","lint-staged":"16.1.6","changelogithub":"13.16.0","installed-check":"9.3.0","simple-git-hooks":"2.13.1","@vitest/coverage-v8":"3.2.4","@antfu/eslint-config":"5.2.1"},"simple-git-hooks":{"pre-commit":"npx lint-staged"},"_npmOperationalInternal":{"tmp":"tmp/fetchdts_0.1.7_1756896255613_0.14863410652086873","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"_id":"fetchdts@0.2.0","bugs":{"url":"https://github.com/unjs/fetchdts/issues"},"dist":{"shasum":"f65de59f3f058ae45ee29d8a1eb6fe091d11d234","tarball":"https://registry.npmjs.org/fetchdts/-/fetchdts-0.2.0.tgz","integrity":"sha512-PJb4ZTGT2/wK78RmVrxZITStWabhZlKBsL52VOgq+c7clEkdHdEB+0rtzrXCbZJqeYJj+IwNWYqB5/G6vouA6A==","fileCount":9,"unpackedSize":145599,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/fetchdts@0.2.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQC5anfpv6PxNT0ane61Qi3czQTI8HIkNjK0FnerpvSCrQIgSwyEjLZjmp6Ds7j8fjr9HqwBGXFVfcoOGE7Do3LPcKw="}]},"name":"fetchdts","type":"module","_from":"file:/home/runner/work/_temp/uppt-tarballs/fetchdts-0.2.0.tgz","types":"./dist/index.d.mts","author":{"url":"https://roe.dev","name":"Daniel Roe","email":"daniel@roe.dev"},"exports":{".":"./dist/index.mjs","./compiler":"./dist/compiler.mjs","./package.json":"./package.json"},"license":"MIT","scripts":{"dev":"vitest dev","lint":"eslint .","test":"pnpm test:unit && pnpm test:types","bench":"node bench/instantiations.mjs","build":"tsdown","test:knip":"knip","test:unit":"vitest --typecheck","test:types":"tsc --noEmit","test:versions":"installed-check -d --no-workspaces"},"version":"0.2.0","_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:30d6f430-ae8b-4363-a438-7378db550cd9"},"approver":{"name":"danielroe","email":"daniel@roe.dev"}},"homepage":"https://github.com/unjs/fetchdts#readme","_resolved":"/home/runner/work/_temp/uppt-tarballs/fetchdts-0.2.0.tgz","_integrity":"sha512-PJb4ZTGT2/wK78RmVrxZITStWabhZlKBsL52VOgq+c7clEkdHdEB+0rtzrXCbZJqeYJj+IwNWYqB5/G6vouA6A==","repository":{"url":"git+https://github.com/unjs/fetchdts.git","type":"git"},"_npmVersion":"12.0.2","description":"A suite of type utilities for building strongly-typed APIs","directories":{},"lint-staged":{"*.{js,ts,mjs,cjs,json,.*rc}":["npx eslint --fix"]},"maintainers":[{"name":"danielroe","email":"daniel@roe.dev"}],"sideEffects":false,"_nodeVersion":"24.19.0","devDependencies":{"knip":"6.33.0","eslint":"10.9.1","tsdown":"0.22.14","vitest":"4.1.11","fast-check":"4.9.0","pkg-pr-new":"0.0.88","typescript":"6.0.3","@types/node":"26.4.0","lint-staged":"17.4.1","installed-check":"11.0.0","simple-git-hooks":"2.14.0","@vitest/coverage-v8":"4.1.11","@antfu/eslint-config":"9.3.0"},"simple-git-hooks":{"pre-commit":"npx lint-staged"},"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/fetchdts_0.2.0_1788194946547_0.9334699634856336"},"_hasShrinkwrap":false}},"time":{"created":"2024-09-13T09:59:29.088Z","modified":"2026-08-31T16:49:06.971Z","0.0.0":"2024-09-13T09:59:29.368Z","0.0.1":"2025-01-23T23:33:14.630Z","0.0.2":"2025-05-08T20:04:04.235Z","0.0.3":"2025-05-09T08:26:11.284Z","0.1.0":"2025-05-30T08:23:34.731Z","0.1.1":"2025-05-30T14:40:09.203Z","0.1.3":"2025-06-09T14:14:51.790Z","0.1.4":"2025-06-09T15:29:53.831Z","0.1.5":"2025-06-28T17:40:39.620Z","0.1.6":"2025-08-04T07:39:53.476Z","0.1.7":"2025-09-03T10:44:15.828Z","0.2.0":"2026-08-31T16:49:06.660Z"},"bugs":{"url":"https://github.com/unjs/fetchdts/issues"},"author":{"url":"https://roe.dev","name":"Daniel Roe","email":"daniel@roe.dev"},"license":"MIT","homepage":"https://github.com/unjs/fetchdts#readme","repository":{"url":"git+https://github.com/unjs/fetchdts.git","type":"git"},"description":"A suite of type utilities for building strongly-typed APIs","maintainers":[{"name":"danielroe","email":"daniel@roe.dev"}],"readme":"# fetchdts\n\n[![npm version][npm-version-src]][npm-version-href]\n[![npm downloads][npm-downloads-src]][npm-downloads-href]\n[![Github Actions][github-actions-src]][github-actions-href]\n[![Codecov][codecov-src]][codecov-href]\n\n> A suite of type utilities for building strongly-typed APIs\n\n🚧 Under active development\n\n- [▶️ &nbsp;Online playground](https://stackblitz.com/github/unjs/fetchdts/tree/main/playground)\n\n## Features\n\n- 💪 Strongly-typed query, body, headers, response.\n- 🗺️ Static path segments, as well as dynamic and wildcard parameters.\n- 📦 Exposes core utilities for building typed fetch functions.\n\n## Usage\n\nInstall package:\n\n```sh\n# npm\nnpm install fetchdts\n\n# pnpm\npnpm install fetchdts\n```\n\n## Quick Start\n\nDefine your API schema and create a strongly-typed fetch function:\n\n```ts\nimport type { DynamicParam, Endpoint, TypedFetchInput, TypedFetchRequestInit, TypedFetchResponseBody, TypedResponse } from 'fetchdts'\n\n// Define your API schema\ninterface APISchema {\n  '/users': {\n    [Endpoint]: {\n      GET: {\n        response: { id: number, name: string }[]\n      }\n      POST: {\n        body: { name: string, email: string }\n        response: { id: number, name: string, email: string }\n      }\n    }\n    [DynamicParam]: { // matches /users/123\n      [Endpoint]: {\n        GET: {\n          response: { id: number, name: string, email: string }\n        }\n        DELETE: {\n          response: { success: boolean }\n        }\n      }\n    }\n  }\n}\n\n// Create your typed fetch function\nasync function api<T extends TypedFetchInput<APISchema>>(\n  input: T,\n  init?: TypedFetchRequestInit<APISchema, T>,\n) {\n  return fetch(input, init as RequestInit) as unknown as Promise<TypedResponse<TypedFetchResponseBody<APISchema, T>>>\n}\n\n// Use with full type safety\nconst users = await api('/users').then(r => r.json()) // Type: { id: number; name: string }[]\nconst user = await api('/users/123').then(r => r.json()) // Type: { id: number; name: string; email: string }\n```\n\n## Core Concepts\n\n### Schema Definition\n\nYour API schema describes the structure of your endpoints using TypeScript interfaces:\n\n```ts\ninterface Schema {\n  '/path': {\n    [Endpoint]: {\n      [HTTPMethod]: {\n        query?: { param: string } // Query parameters\n        body?: { data: any } // Request body\n        headers?: { auth: string } // Required headers\n        response: { result: any } // Response data\n        responseHeaders?: { 'x-rate-limit': string } // Response headers\n      }\n    }\n  }\n}\n```\n\n### Path Types\n\n**Static Paths**: Exact string matches\n```ts\ninterface Schema {\n  '/api/users': {\n    [Endpoint]: {\n      GET: { response: User[] }\n    }\n  }\n}\n```\n\n**Dynamic Parameters**: Single path segments\n```ts\ninterface Schema {\n  '/api/users': {\n    [DynamicParam]: { // matches /api/users/123, /api/users/abc, etc.\n      [Endpoint]: {\n        GET: { response: User }\n      }\n    }\n  }\n}\n```\n\n**Wildcard Parameters**: Zero or more path segments\n```ts\ninterface Schema {\n  '/api': {\n    [WildcardParam]: { // matches /api, /api/anything, /api/nested/deep\n      [Endpoint]: {\n        GET: { response: any }\n      }\n    }\n  }\n}\n```\n\n**Matching order**: a static segment is preferred to a dynamic parameter, and a dynamic parameter to\na wildcard, as in a router. Where the more specific match does not answer the method being\nrequested, the less specific one is used, so a `POST`-only static route and a `GET` wildcard sibling\nare both reachable at the same path:\n\n```ts\ninterface Schema {\n  '/api/blog': {\n    '/thing': { [Endpoint]: { POST: { response: D } } }\n    [WildcardParam]: { [Endpoint]: { GET: { response: C } } }\n  }\n}\n\ntype A = TypedFetchResponseBody<Schema, '/api/blog/thing', 'POST'> // D\ntype B = TypedFetchResponseBody<Schema, '/api/blog/thing', 'GET'> // C\n```\n\nA query string, a fragment and a trailing slash are ignored when a path is resolved, so\n`'/api/users?page=2'` resolves as `'/api/users'` does.\n\n### Symbols Reference\n\nfetchdts uses special symbols to define different types of route matching:\n\n```ts\nimport { DynamicParam, Endpoint, WildcardParam } from 'fetchdts'\n\ninterface Schema {\n  // Endpoint: Marks where HTTP methods are defined\n  [Endpoint]: {\n    GET: { response: Data }\n    POST: { body: Input, response: Data }\n  }\n\n  // DynamicParam: Matches a single path segment (e.g. the `123` of /users/123)\n  [DynamicParam]: {\n    [Endpoint]: {\n      GET: { response: User }\n    }\n  }\n\n  // WildcardParam: Matches the rest of the path, which may be empty (e.g. the `a/b.txt` of /files/a/b.txt)\n  [WildcardParam]: {\n    [Endpoint]: {\n      GET: { response: File }\n    }\n  }\n}\n```\n\n### HTTP Methods\n\nAll standard HTTP methods are supported:\n- `GET`, `POST`, `PUT`, `DELETE`, `PATCH`\n- `OPTIONS`, `HEAD`, `CONNECT`, `TRACE`\n\nMethods may be written in either case (`'POST'` or `'post'`), as a router compares them\ncase-insensitively. A route registered for `GET` also answers `HEAD`, as it does in h3, which serves\nthe `GET` handler and discards the body; an endpoint that registers `HEAD` itself is used in\npreference.\n\n```ts\ninterface RESTSchema {\n  '/api/users': {\n    [Endpoint]: {\n      GET: { response: User[] }\n      POST: { body: CreateUser, response: User }\n    }\n    [DynamicParam]: {\n      [Endpoint]: {\n        GET: { response: User }\n        PUT: { body: UpdateUser, response: User }\n        PATCH: { body: Partial<UpdateUser>, response: User }\n        DELETE: { response: { success: boolean } }\n      }\n    }\n  }\n}\n```\n\n## API Reference\n\n### Core Types\n\n#### `TypedFetchInput<Schema>`\nExtracts valid URL paths from your schema:\n```ts\ntype ValidPaths = TypedFetchInput<APISchema>\n// Result: '/users' | '/users/${string}'\n```\n\nA parameter is a `${string}` placeholder, and `${string}` may contain a slash, so a member covering a\nparameter is a pattern that also matches a path with extra segments: `'/users/1/2'` is assignable to\n`` `/users/${string}` ``. The union is what gives an editor its completions; `ValidFetchInput` is what\nrejects a path the schema does not resolve.\n\n#### `AnyFetchPath`\n\nThe shape any path may take, for use as the constraint of the type parameter a path is inferred into:\n\n```ts\ndeclare function $fetch<T extends AnyFetchPath>(input: T /* ... */): unknown\n```\n\nConstrain to this rather than to `string`, which loses the path of `useFetch(ref('/api/users'))`:\n`ref()` and `computed()` infer their own type parameter from the argument, and a literal widens where\nthe type it is inferred into is constrained by `string` and keeps its literal type where the\nconstraint is a pattern. A direct literal, a getter and a pre-declared `Ref<'/api/users'>` are\nunaffected either way, and a union of paths has the same effect as a pattern, so a signature\nconstrained to `TypedFetchInput<Schema>` does not need this as well.\n\n#### `ValidFetchInput<Schema, Path, Method?>`\n\nWhether a path resolves, for use in parameter position:\n\n```ts\ndeclare function $fetch<T extends AnyFetchPath, M extends AnyHTTPMethod = 'GET'>(\n  input: T & ValidFetchInput<Schema, T, M>,\n  init?: TypedFetchRequestInit<Schema, T, M> & { method?: M },\n): TypedFetchResponseBody<Schema, T, M>\n```\n\nThis is an alternative to constraining the input with `TypedFetchInput`, which materialises the\nunion of every path in the schema. Validating one path costs no more than its depth, where checking\na union costs the size of the schema, so on a large generated schema this is substantially cheaper:\nat 1500 routes and 200 call sites it checks in around 0.4s where the union takes around 3s\n(`pnpm bench --routes 1500 --calls 200 [--valid-input]`). It accepts a query string or a fragment\nwithout enumerating either, and narrows by method.\n\nA path that resolves gives `unknown`, which leaves the parameter as `T`. One that does not gives a\ntype no string satisfies, whose single key carries the reason, so the failure reads as:\n\n```text\nArgument of type '\"/api/nope\"' is not assignable to parameter of type\n  '\"/api/nope\" & { \"fetchdts: no GET route matches '/api/nope'\": never }'\n```\n\nThe text is a diagnostic rather than API, and may change.\n\nPut it on *every* signature that admits a path, including one already constrained by\n`TypedFetchInput`: the union carries no method, so a signature constrained by it alone accepts a path\nthe schema knows for a method that path does not answer.\n\nAn input that is not a path, such as a `Request` or a `URL`, which `fetch` also takes, carries nothing to\ncheck and is accepted, so a client admitting them can validate every signature without rejecting\nthem.\n\nEvery member of a union of paths must resolve, so a value narrowed to one of several paths cannot\npass on the strength of one of them. A path known only to be a `string` matches nothing and is\nrejected; if callers should be able to request an arbitrary path, add a signature taking `string` and\nreturning `unknown`, so that the escape hatch is explicit.\n\nThe trade-off is completion: a validator has no literals for an editor to offer, so put the union in\nthe constraint alongside it, as [Typing a Fetch Function](#typing-a-fetch-function) shows.\n\n#### `TypedFetchRequestInit<Schema, Path, Method?>`\nProvides typed request options for a specific path:\n```ts\n// For paths requiring body/headers/query parameters\nawait api('/users', {\n  method: 'POST',\n  body: { name: 'John' }, // ✅ Typed based on schema\n  headers: { authorization: 'Bearer token' }\n})\n```\n\nPass `Method` where it is known. The methods a path answers depend on it, since a path may reach one\nendpoint for one method and a different one for another, so a method-agnostic init describes only\nwhat every reachable endpoint has in common:\n\n```ts\ntype A = TypedFetchRequestInit<Schema, '/users', 'POST'>['body'] // { name: string }\ntype B = TypedFetchRequestInit<Schema, '/users'>['body'] // BodyInit | null | undefined\n```\n\n#### `TypedFetchResponseBody<Schema, Path>`\nReturns the typed response body for a given path:\n```ts\nconst response = await api('/users/123')\n// Type automatically inferred from schema\n```\n\n#### `TypedFetchMethods<Schema, Path>`\n\nThe methods a path answers, in either case, or every method where it resolves to nothing. Constrain a signature's\nmethod parameter with it (`method?: M & TypedFetchMethods<Schema, T>`) to reject a method the path\ndoes not answer, which a path union cannot express on its own.\n\n#### `TypedFetchRequestBody` / `TypedFetchRequestQuery` / `TypedFetchRequestHeaders` / `TypedFetchRequires`\n\nThe shape an endpoint declares for one field of the request, or a fallback where it declares none,\nplus whether the field is required.\n\nUse these instead of `TypedFetchRequestInit` where the options type has to be *extensible*. A whole\ninit is built from conditionals, and an interface may only extend a type whose members are statically\nknown, so `interface Options<T> extends Omit<TypedFetchRequestInit<Schema, T>, 'method'>` does not\ncompile (`TS2312`) as soon as the path is generic. Writing the keys out avoids it:\n\n```ts\ninterface Options<Path extends string, Method extends AnyHTTPMethod> {\n  body?: TypedFetchRequestBody<Schema, Path, Method>\n  query?: TypedFetchRequestQuery<Schema, Path, Method>\n  headers?: TypedFetchRequestHeaders<Schema, Path, Method>\n}\n\n// and a consumer of yours can extend it\ninterface MyOptions<Path extends string, Method extends AnyHTTPMethod> extends Options<Path, Method> {\n  retries?: number\n}\n```\n\n`TypedFetchRequires<Schema, Path, Method, 'body' | 'query' | 'headers'>` reports whether a field is\nrequired, for making the corresponding member required at a call signature.\n\nPass `never` as the fallback where you need to tell \"the endpoint declared this\" from \"it did not\".\nThat is what lets a client widen only the declared case, which is what request headers want: an\nendpoint declares the headers it *requires*, not the only ones a request may carry.\n\n```ts\ntype Declared<Path extends string, Method extends AnyHTTPMethod> = TypedFetchRequestHeaders<Schema, Path, Method, never>\n\ntype Headers<Path extends string, Method extends AnyHTTPMethod> = [Declared<Path, Method>] extends [never]\n  ? Record<string, string>\n  : Declared<Path, Method> & Record<string, string>\n```\n\nThe declared header stays required and typed, and a request may carry others. The same shape applies\nto `query` for an endpoint that declares one but should still accept more.\n\nA field declared as `never` counts as declared, and means the field cannot be supplied: the fallback\nis not reached and the option resolves to `never`. That is the intended reading for a hand-written\n`body: never`, and a trap for a generator that emits an extractor call per field rather than deciding\nwhether one applies: `queryType: QueryOf<typeof handler>` on a handler that validates nothing\nresolves to `never`, and the endpoint then has an option no value satisfies rather than an open one.\nOmit the field instead, or, where the generator cannot tell, ask with `never` as the fallback and\ntreat that as undeclared, as above.\n\nA field declared as `unknown` is the other case: not \"cannot be supplied\" but \"cannot be typed\". It is\nnever required, and the option accepts anything, so it is the right thing for a generator to emit\nwhere its extractor gives up.\n\nAn extractor written as a conditional over a naked type parameter reaches `never` more often than its\nauthor expects, since such a conditional distributes and short-circuits: one that cannot read a\nhandler yields `never`, which then reads here as \"cannot be supplied\" rather than as the fallback the\nauthor had in mind. Guard the entry point with `[T] extends [never]`, and prefer omitting a field to\nemitting an extractor call that can fail.\n\nA path that resolves to nothing, including one known only to be a `string`, falls back on every field\nand requires none of them, so a client that accepts an opaque path still has usable options. The\nresponse and error accessors differ deliberately: they resolve to `never` for such a path, since\nthere is no response to describe, and to `unknown` for a `Request` or a `URL`, which are accepted\ninputs carrying no path to resolve.\n\n#### `TypedHeaders<HeaderMap>`\nProvides typed header access:\n```ts\nconst contentType = response.headers.get('content-type') // string | null\nconst customHeader = response.headers.get('x-custom') // Typed based on schema\n```\n\n#### `LooseTypedHeaders<HeaderMap>` / `LooseTypedRequest<Body, HeaderMap>`\n\nVariants that type header *names* but leave every value as `string`. Use them when the header map is\nnot known where the type is declared, such as when it comes from a generic parameter of your own\ntype:\n\n```ts\ninterface MyRequest<HeaderMap extends Record<string, string>> {\n  headers: LooseTypedHeaders<HeaderMap>\n}\n```\n\n`TypedHeaders` resolves each value with a conditional lookup into the map, which TypeScript cannot\nreduce while the map is still generic, so a plain `Headers` is neither assignable to nor from\n`TypedHeaders<HeaderMap>` in that position.\n\n### Utilities\n\n#### `compileRoutes(sets, options?)` from `fetchdts/compiler`\n\nCompile route sets into a module of types specialised to them. Each route is a list of segments,\nalready split; `fetchdts` does not parse route patterns.\n\n```ts\nimport { compileRoutes } from 'fetchdts/compiler'\n\nconst { code, strategy, stats } = compileRoutes([\n  { routes: serverRoutes },\n  { routes: externalRoutes, origin: 'https://api.example.com' },\n], { name: 'ServerRoutes', moduleSpecifier: 'nuxt/app' })\n```\n\n`imports` on the result lists the names the emitted module imports, so a consumer re-exporting them\nfrom its own entry can assert it covers them. An import the specifier does not provide resolves to\n`any` rather than failing, because `skipLibCheck` suppresses the error in a declaration file, and\nevery type built on it then accepts anything.\n\nThe emitted module exports the route tree, an exact-match table where one is worth emitting, the path\nunion, and accessors specialised to the route set: `ValidInput`, `Response`, `ResponseHeaders`,\n`ErrorBody`, `RequestBody`, `RequestQuery`, `RequestHeaders` and `Requires`. A consumer's signatures\nthen name only the emitted types and `AnyFetchPath`, so how a path is resolved is free to change\nbetween versions of `fetchdts` without changing the signatures a consumer writes, since regenerating is\nenough.\n\nAn artefact left behind by an upgrade fails to compile, because the emitted module imports the type\nnames it uses. That holds only where the name changed, so an emitted-surface type is renamed whenever\nits meaning changes rather than quietly resolving to something else.\n\nWhere a consumer's route map can be extended by hand, pass `resolveAgainst` with the name of an\ninterface extending the emitted one:\n\n```ts\n// generated.ts, emitted with { name: 'GeneratedRoutes', resolveAgainst: 'ServerRoutes' }\n// routes.ts\nexport interface ServerRoutes extends GeneratedRoutes {}\n```\n\nThe accessors then resolve against `ServerRoutes`, so a route someone adds by augmenting it is found,\nwhile every path known at generation time still short-circuits through the exact-match table.\nWithout this the accessors are bound to the emitted interface, and an augmentation, which targets\nthe consumer's own interface, is invisible to them, so a hand-added route reads as a typo. Pass any\nimports the emitted module needs for that name, or for types its metadata references, as `imports`.\n\nEvery strategy emits the same names. Which one is chosen depends on the route set: an exact-match\ntable is emitted for any static path, since a lookup replaces a walk, and the path union while the\npaths reached through a parameter are few enough for it to stay cheap (`unionLimit`, 200 by default).\n`strategy` in the result and a comment at the head of the module record what was chosen and the counts\nthat chose it; pass `strategy` to force one.\n\nA type a route's handler cannot give up belongs in that route's metadata, not in an augmentation of\nthe emitted module: an override reaches the table and the union, so it is offered as a completion,\nwhere a merged route reaches neither.\n\nMethod names are uppercased, as a router compares them case-insensitively, and a route with no\nsegments is emitted as `'/'`.\n\nRoute segments, method names and metadata fields come from whatever generated them, so every lookup\ntable built from them has a null prototype, a metadata value that is not a string is skipped, and an\ninterface name, a module specifier or a segment the compiler cannot emit is a `TypeError` rather than\ninvalid output. A static segment is also escaped where it lands inside an emitted template literal\ntype.\n\n```ts\nimport { DynamicParam } from 'fetchdts'\nimport { compileRoutes } from 'fetchdts/compiler'\n\nconst { code } = compileRoutes([{ routes: [\n  {\n    segments: ['/users'],\n    metadata: {\n      GET: {\n        responseType: 'User[]'\n      },\n      POST: {\n        bodyType: '{ name: string }',\n        responseType: 'User'\n      }\n    }\n  },\n  {\n    segments: ['/users', DynamicParam, '/posts'],\n    metadata: {\n      GET: {\n        responseType: 'Post[]'\n      }\n    }\n  }\n] }], { name: 'APISchema' })\n\nconsole.log(code)\n// Outputs the generated module\n```\n\nA segment is either static or a parameter:\n\n| Segment | Meaning |\n| --- | --- |\n| `'/users'`, `'users'`, `{ type: 'static', value: 'users' }` | a static segment |\n| `'https://api.example.com'` | an origin, for cross-domain schemas |\n| `DynamicParam`, `{ type: 'dynamic' }` | exactly one segment |\n| `WildcardParam`, `{ type: 'wildcard' }` | the rest of the path, which may be empty; nothing may follow it |\n\nA static segment spanning several path segments is split into one key per segment, and an origin is\nkept whole. A path is resolved by looking up a single segment as a key, so one key per segment is the\nshape that keeps resolution independent of how many routes a node holds; a key spanning several is\nstill matched, by scanning the node's keys.\n\nThe object form exists so that tools which cannot pass symbols across a serialisation boundary can\nstill describe a route. Both forms produce identical output, and a static segment may itself contain\nslashes (`'/api/users'`), which keeps the emitted tree shallower.\n\n#### Converting route patterns\n\n`fetchdts` does not parse route patterns. Every router spells a parameter differently, and the\nschema only needs to know which segments are static, which match one segment, and which match the\nrest, so the conversion belongs to whichever tool already owns your patterns.\n\nIf your patterns are [rou3](https://github.com/h3js/rou3) patterns, `routeNodeKeys` gives the\ncanonical form directly, and gives it to you from the router that will serve the request, so the\ngenerated types cannot drift from the routing:\n\n```ts\nimport { DynamicParam, WildcardParam } from 'fetchdts'\nimport { compileRoutes } from 'fetchdts/compiler'\nimport { routeNodeKeys } from 'rou3'\n\nconst routes = endpoints.flatMap(({ pattern, method, responseType }) =>\n  // one pattern can land on several nodes: `/users/:id?` -> ['/users', '/users/*']\n  routeNodeKeys(pattern).map(key => ({\n    segments: key.split('/').slice(1).map(segment =>\n      segment === '*'\n        ? DynamicParam\n        : segment === '**'\n          ? WildcardParam\n          // escapes are preserved, so a literal `*` arrives as `\\*`\n          : segment.replace(/\\\\(.)/g, '$1'),\n    ),\n    // a handler with no method is valid for every verb\n    metadata: { [method ?? 'ALL']: { responseType } },\n  })),\n)\n\nconst { code } = compileRoutes([{ routes }], { name: 'APISchema' })\n```\n\nFor filesystem routes, [`unrouting`](https://github.com/unjs/unrouting) parses the major conventions\nand converts between them, reporting each lossy step rather than silently widening a pattern.\n\nConstrained parameters collapse onto one node: `/users/:id(\\d+)` and `/users/:slug([a-z]+)` share a\nsingle dynamic segment in the schema, so their response types are unioned. Radix-tree routers group\nthem the same way and re-check the constraint per node, which a type cannot do.\n\n## Advanced Examples\n\n### Typed Headers and Query Parameters\n\n```ts\ninterface APISchema {\n  '/search': {\n    [Endpoint]: {\n      GET: {\n        query: { q: string, limit?: number }\n        headers: { 'x-api-key': string }\n        response: { results: string[], total: number }\n        responseHeaders: { 'x-rate-limit-remaining': string }\n      }\n    }\n  }\n}\n\n// Usage with required query and headers\nconst results = await api('/search', {\n  query: { q: 'typescript', limit: 10 },\n  headers: { 'x-api-key': 'your-key' }\n})\n\n// Access typed response headers\nconst rateLimit = results.headers.get('x-rate-limit-remaining') // string | null\n```\n\n### Mixed Static and Dynamic Routes\n\n```ts\ninterface APISchema {\n  '/api': {\n    '/health': {\n      [Endpoint]: {\n        GET: { response: { status: 'ok' | 'error' } }\n      }\n    }\n    '/users': {\n      [Endpoint]: {\n        GET: { response: User[] }\n        POST: { body: CreateUser, response: User }\n      }\n      [DynamicParam]: {\n        [Endpoint]: {\n          GET: { response: User }\n          PUT: { body: UpdateUser, response: User }\n          DELETE: { response: { deleted: boolean } }\n        }\n        '/posts': {\n          [Endpoint]: {\n            GET: { response: Post[] }\n          }\n          [DynamicParam]: {\n            [Endpoint]: {\n              GET: { response: Post }\n            }\n          }\n        }\n      }\n    }\n  }\n}\n\n// All of these are now typed:\nawait api('/api/health') // { status: 'ok' | 'error' }\nawait api('/api/users') // User[]\nawait api('/api/users/123') // User\nawait api('/api/users/123/posts') // Post[]\nawait api('/api/users/123/posts/456') // Post\n```\n\n### Handlers Registered for Every Method\n\nA handler that is valid for every HTTP verb can be expressed compactly with `Record<HTTPMethod, ...>`:\n\n```ts\ninterface APISchema {\n  '/api': {\n    '/hello': {\n      [Endpoint]: Record<HTTPMethod, { response: { hello: string } }>\n    }\n  }\n}\n```\n\n`compileRoutes` emits that form for an `ALL` entry, which is worth using over spelling out every\nmethod, as the generated file is several times smaller:\n\n```ts\ncompileRoutes([{ routes: [\n  {\n    segments: ['/api', '/hello'],\n    metadata: {\n      ALL: { responseType: '{ hello: string }' },\n      // a specific method takes precedence over `ALL`\n      POST: { bodyType: '{ name: string }', responseType: 'Created' }\n    }\n  }\n] }])\n```\n\n### Registering a Route Without a Return Type\n\nA route whose response type isn't known, because a handler couldn't be resolved or is a proxy, is\nstill a route, and should stay callable rather than looking like a typo. Register it for every method\nwith nothing else declared:\n\n```ts\ncompileRoutes([{ routes: [\n  { segments: ['/api', '/proxy'], metadata: { ALL: {} } },\n] }])\n\n// [Endpoint]: Record<HTTPMethod, {}>\n```\n\nThe path is then a valid input, takes any method, and its response is `unknown`. A path that matches\nnothing, or a method an endpoint doesn't register, is still `never`, so the two cases stay\ndistinguishable:\n\n```ts\ntype A = TypedFetchResponseBody<APISchema, '/api/proxy'> // unknown\ntype B = TypedFetchResponseBody<APISchema, '/api/typo'> // never\n```\n\nOmitting `metadata` entirely is not the same thing: it emits no endpoint at all, so the path is not\noffered. That is deliberate, so that a generator which skips handlers it cannot type doesn't widen\nits surface by accident.\n\n### Requests Built From Runtime Values\n\n`` $fetch(`/api/posts/${id}`) `` has the type `` `/api/posts/${string}` ``, so it matches the dynamic\nparameter, but at runtime `id` could be `'static'` and hit a static sibling instead. A segment that\nis not known in full reaches every branch it could take, so the response is the union of them:\n\n```ts\ninterface APISchema {\n  '/api/posts': {\n    '/static': { [Endpoint]: { GET: { response: Static } } }\n    [DynamicParam]: { [Endpoint]: { GET: { response: Post } } }\n  }\n}\n\ntype A = TypedFetchResponseBody<APISchema, `/api/posts/${string}`> // Post | Static\ntype B = TypedFetchResponseBody<APISchema, '/api/posts/123'> // Post\ntype C = TypedFetchResponseBody<APISchema, '/api/posts/static'> // Static\n```\n\nThis holds for a segment that is only partly known (`` `/api/posts/item-${string}` `` reaches\n`/api/posts/item-1` and the parameter, but no other sibling), and for endpoints below the segment, so\n`` `/api/users/${string}/posts` `` accounts for a `/api/users/me/posts` sibling.\n\nA static key spanning several segments (`'/api/users'` written as a single key) is matched by prefix\nonly, so a partly known segment does not reach it.\n\nWhere the union should be something other than what the schema implies, an endpoint can declare the\nresponse to use when the segment reaching it was not a literal, which takes precedence:\n\n```ts\ninterface APISchema {\n  '/api/posts': {\n    '/static': { [Endpoint]: { GET: { response: Static } } }\n    [DynamicParam]: {\n      [Endpoint]: {\n        GET: {\n          response: Post\n          ambiguousResponse: Post | Static\n        }\n      }\n    }\n  }\n}\n\ntype A = TypedFetchResponseBody<APISchema, `/api/posts/${string}`> // Post | Static\ntype B = TypedFetchResponseBody<APISchema, '/api/posts/123'> // Post\ntype C = TypedFetchResponseBody<APISchema, '/api/posts/static'> // Static\n```\n\n`compileRoutes` carries an `ambiguousResponseType` like any other metadata field, so a generator that\nalready knows the union can declare it rather than have it derived. The declared response is used\nonly where a *parameter* consumed a non-literal segment; a wildcard is unaffected, since it matches\nthe rest of the path either way.\n\n### Cross-Domain API Support\n\n```ts\ninterface Schema {\n  'https://api.github.com': {\n    '/users': {\n      [DynamicParam]: {\n        [Endpoint]: {\n          GET: { response: GitHubUser }\n        }\n        '/repos': {\n          [Endpoint]: {\n            GET: { response: Repository[] }\n          }\n        }\n      }\n    }\n  }\n}\n\n// Works with full URLs\nconst user = await api('https://api.github.com/users/octocat')\nconst repos = await api('https://api.github.com/users/octocat/repos')\n```\n\n### Error Handling with Types\n\n```ts\ninterface APISchema {\n  '/api/users': {\n    [DynamicParam]: {\n      [Endpoint]: {\n        GET: {\n          response: User | { error: string, code: number }\n        }\n      }\n    }\n  }\n}\n\nconst result = await api('/api/users/123')\n// result is typed as: User | { error: string; code: number }\n\nif ('error' in result) {\n  console.error(`Error ${result.code}: ${result.error}`)\n}\nelse {\n  console.log(`User: ${result.name}`)\n}\n```\n\n## Best Practices\n\n### Typing a Fetch Function\n\nConstrain the path by the union, keep the path parameter itself plain, and constrain the *method* by\nwhat that path answers:\n\n```ts\ndeclare function $fetch<T extends Paths, M extends AnyHTTPMethod = 'GET'>(\n  input: T,\n  init?: TypedFetchRequestInit<Schema, T, M> & { method?: M & TypedFetchMethods<Schema, T> },\n): TypedFetchResponseBody<Schema, T, M>\ndeclare function $fetch<T extends AnyFetchPath, M extends AnyHTTPMethod = 'GET'>(\n  input: T & ValidFetchInput<Schema, T, M>,\n  init?: TypedFetchRequestInit<Schema, T, M> & { method?: M },\n): TypedFetchResponseBody<Schema, T, M>\n```\n\nThe first signature answers a path the union covers: the union gives an editor its completions, and\nthe plain parameter is what lets `` `/api/users/${id}` `` infer as a template literal type. The second\ntakes what the union cannot express (a query string, a fragment, a trailing slash, a `Request` or a\n`URL`) and validates it.\n\nThe cost of the plain parameter is that a union member covering a route parameter is a pattern, so\n`'/api/users/1/2'` satisfies `` `/api/users/${string}` `` and the first signature accepts it, with the\nresponse resolving to `never`. Validate the first signature as well if that matters more than\ninferring `` `/api/users/${id}` ``, since the two cannot both hold: intersecting the validator stops a\ntemplate literal argument from inferring, and the path then resolves as the whole union.\n\nThree things have to be true at once and they pull against each other, so the shape is worth\nunderstanding rather than copying:\n\n| wanted | needs |\n| --- | --- |\n| completions from `` $fetch(' `` | the union in the constraint of the *first* signature |\n| `` `/api/users/${id}` `` to resolve | the path parameter **not** intersected with anything |\n| a method the path does not answer to be rejected | the method constrained, since a path union carries no method |\n\nIntersecting the validator onto the path parameter satisfies the third and breaks the second: a\ntemplate literal argument stops inferring as a template literal type and arrives as `string`, so the\ncall resolves to `unknown` or is rejected outright. Constraining the method with\n`TypedFetchMethods<Schema, T>` closes the same hole without touching the path.\n\nNote the method is constrained on the init *member* (`method?: M & TypedFetchMethods<Schema, T>`)\nrather than on the type parameter. Constraining the parameter itself would make the `= 'GET'` default\nillegal, and it is the same rule as [never constraining a type parameter by a type computed from the\nroute map](#typedfetchinputschema).\n\nIf your signature also lets a caller override the response type, widen the method's default when they\ndo. Naming any type argument turns inference off for the rest, so `$fetch<Foo>(url, { method: 'post' })`\nwould otherwise fall back to `'GET'` and reject the method:\n\n```ts\ndeclare function $fetch<\n  R = void,\n  T extends Paths = Paths,\n  M extends AnyHTTPMethod = R extends void ? 'GET' : AnyHTTPMethod,\n>(input: T, init?: { method?: M & TypedFetchMethods<Schema, T> }): R extends void ? TypedFetchResponseBody<Schema, T, M> : R\n```\n\nOnce the caller has named the response, the method no longer decides what comes back, so widening the\ndefault costs nothing.\n\nThe init belongs in *parameter* position, and the method is worth passing to it as well as to the\nresponse: it is otherwise resolved for every method the path answers, and describes only what they\nhave in common. Constrain the method parameter by `AnyHTTPMethod` rather than `HTTPMethod`, or\n`method: 'post'` fails to infer and the call is rejected for a method the endpoint answers.\n\nThe union in the constraint is compared against the requested path at every call site, so that part\nof checking tracks the size of the schema; validation walks it instead, which costs the depth of one\npath. That is the whole of the difference between the three figures above.\n\nConstraining a type parameter to the init type instead looks equivalent, but is not:\n\n```ts\n// avoid: `Init` is constrained by every path in the schema\ndeclare function $fetch<T extends TypedFetchInput<Schema>, Init extends TypedFetchRequestInit<Schema, T>>(\n  input: T,\n  init?: Init,\n): TypedFetchResponseBody<Schema, T, Init['method'] extends HTTPMethod ? Init['method'] : 'GET'>\n```\n\nThe constraint is instantiated with `T` as the whole path union, so the request init is computed for\nevery route in the schema before a single call site is checked. On a schema of any size this\ndominates everything else: the cost stops tracking the number of call sites and starts tracking the\nnumber of routes, several times over. `pnpm bench --eager-init` measures the difference.\n\nTwo smaller notes on the same signature. An endpoint declares the headers it *requires*, so add\n`{ headers?: Record<string, string> }` to the init if callers should be free to send others.\nAnd if some paths only accept a method other than `GET`, a second overload constrained to\n`TypedFetchInput<Schema, 'GET'>` with an optional init keeps those paths from being called without\none.\n\n### Wrapping the Fetch Function in a Composable\n\nWhere the path arrives wrapped, as it does in a composable taking a ref or a getter, intersect the\nvalidator with the *whole* parameter rather than with the path inside it:\n\n```ts\ndeclare function useFetch<T extends AnyFetchPath, M extends AnyHTTPMethod = 'GET'>(\n  url: MaybeRefOrGetter<T> & ValidFetchInput<Schema, T, M>,\n  options?: UseFetchOptions<Schema, T, M> & TypedFetchRequestInit<Schema, T, M> & { method?: M },\n): { data: Ref<TypedFetchResponseBody<Schema, T, M> | null> }\n```\n\nTypeScript cannot infer through an intersection, so\n`MaybeRefOrGetter<T & ValidFetchInput<Schema, T, M>>` leaves `T` at its constraint and every path\nresolves to nothing. Intersected at the top level, `T` is still inferred from the ref or the getter,\nand the failure still reports on the `url` argument.\n\nOptions that narrow the response, as `transform` and `pick` do, layer on top: resolve the response\nonce with `TypedFetchResponseBody` and let the further type parameters default from it, since the\npath and method are already resolved by the time they are read.\n\n### Schema Organization\n\nFor large APIs, consider organizing your schemas into modules:\n\n```ts\n// types/api.ts\ninterface UserAPI {\n  '/api/users': {\n    [Endpoint]: {\n      GET: { response: User[] }\n      POST: { body: CreateUser, response: User }\n    }\n    [DynamicParam]: {\n      [Endpoint]: {\n        GET: { response: User }\n        PUT: { body: UpdateUser, response: User }\n        DELETE: { response: { success: boolean } }\n      }\n    }\n  }\n}\n\ninterface PostAPI {\n  '/api/posts': {\n    [Endpoint]: {\n      GET: { query?: { limit?: number }, response: Post[] }\n      POST: { body: CreatePost, response: Post }\n    }\n    [DynamicParam]: {\n      [Endpoint]: {\n        GET: { response: Post }\n        PUT: { body: UpdatePost, response: Post }\n        DELETE: { response: { success: boolean } }\n      }\n    }\n  }\n}\n\n// Combine them\ntype APISchema = UserAPI & PostAPI\n```\n\n### Runtime Validation\n\nWhile fetchdts provides compile-time type safety, consider adding runtime validation:\n\n```ts\nimport { z } from 'zod'\n\nconst UserSchema = z.object({\n  id: z.number(),\n  name: z.string(),\n  email: z.string().email()\n})\n\nasync function api<T extends TypedFetchInput<APISchema>>(\n  input: T,\n  init?: TypedFetchRequestInit<APISchema, T>\n): Promise<TypedFetchResponseBody<APISchema, T>> {\n  const response = await fetch(input, init as RequestInit)\n  const data = await response.json()\n\n  // Runtime validation for critical endpoints\n  if (input.startsWith('/api/users/') && init?.method !== 'DELETE') {\n    return UserSchema.parse(data) // Throws if invalid\n  }\n\n  return data\n}\n```\n\n### Error Handling\n\nDesign your schemas with error handling in mind:\n\n```ts\ninterface APISchema {\n  '/api/users': {\n    [DynamicParam]: {\n      [Endpoint]: {\n        GET: {\n          response:\n            | { success: true, data: User }\n            | { success: false, error: string, code: number }\n        }\n      }\n    }\n  }\n}\n\n// Usage\nconst result = await api('/api/users/123')\nif (result.success) {\n  console.log(result.data.name) // ✅ Type-safe access\n}\nelse {\n  console.error(`Error ${result.code}: ${result.error}`)\n}\n```\n\n## Troubleshooting\n\n### TypeScript Configuration\n\nFor the best experience, ensure your `tsconfig.json` includes:\n\n```json\n{\n  \"compilerOptions\": {\n    \"strict\": true,\n    \"exactOptionalPropertyTypes\": true,\n    \"noUncheckedIndexedAccess\": true\n  }\n}\n```\n\n## 💻 Development\n\nI would welcome contributions! Please see the [Code of Conduct](./CODE_OF_CONDUCT.md).\n\n- Clone this repository\n- Enable [Corepack](https://github.com/nodejs/corepack) using `corepack enable`\n- Install dependencies using `pnpm install`\n- Run interactive tests using `pnpm dev` and type tests with `pnpm test:types`\n\n## License\n\nMade with ❤️\n\nPublished under [MIT License](./LICENCE).\n\n<!-- Badges -->\n\n[npm-version-src]: https://npmx.dev/api/registry/badge/version/fetchdts\n[npm-version-href]: https://npmx.dev/package/fetchdts\n[npm-downloads-src]: https://npmx.dev/api/registry/badge/downloads/fetchdts\n[npm-downloads-href]: https://npm.chart.dev/fetchdts\n[github-actions-src]: https://img.shields.io/github/actions/workflow/status/unjs/fetchdts/ci.yml?branch=main&style=flat-square\n[github-actions-href]: https://github.com/unjs/fetchdts/actions?query=workflow%3Aci\n[codecov-src]: https://img.shields.io/codecov/c/gh/unjs/fetchdts/main?style=flat-square\n[codecov-href]: https://codecov.io/gh/unjs/fetchdts\n","readmeFilename":"README.md"}