{"_id":"soon-fetch","_rev":"36-ca7cc2b44b9c5cd5e9a0718bb22518f4","name":"soon-fetch","dist-tags":{"latest":"4.1.0","beta":"4.0.2-beta.1"},"versions":{"0.0.1":{"name":"soon-fetch","version":"0.0.1","keywords":["request","fetch","lightweight","timeout","http","axios"],"author":"","license":"MIT","_id":"soon-fetch@0.0.1","maintainers":[{"name":"leafnote","email":"leafnote@outlook.com"}],"homepage":"https://github.com/leafio/soon-fetch","dist":{"shasum":"fb6765b73f6a4ca58e44caae4e3c3eaed9676860","tarball":"https://registry.npmjs.org/soon-fetch/-/soon-fetch-0.0.1.tgz","fileCount":5,"integrity":"sha512-WYvstq1FbvAGK/UWRZU3KY8eQrdrYNluCSMJY0uGW7fhNfEsonsvD4QyZYZWqh3WvNfCTnHCoMuEo/cxvB695w==","signatures":[{"sig":"MEQCIGc2Zh3PoxsPh2jeoiDRTNlM1KptItUS+fbyQmxsnMXTAiBAUJYutlzc9Gkbnw6ZCSKtfiQLXWOcoy9Hdb+ywdDQ8Q==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":24121},"main":"./dist/index.cjs.js","types":"./dist/index.d.ts","module":"/dist/index.js","gitHead":"bbd974ccf35e3340f986f26553c376eb2e726163","scripts":{"test":"echo \"Error: no test specified\" && exit 1","build":"rollup --config","build:types":"tsc"},"_npmUser":{"name":"leafnote","email":"leafnote@outlook.com"},"_npmVersion":"10.2.3","description":"a lightweight request library based on fetch with TS prompt","directories":{},"_nodeVersion":"20.10.0","dependencies":{},"_hasShrinkwrap":false,"devDependencies":{"tslib":"^2.6.0","rollup":"^3.26.3","typescript":"^5.1.6","@babel/core":"^7.22.9","@babel/preset-env":"^7.22.9","rollup-plugin-dts":"^5.3.0","@rollup/plugin-babel":"^6.0.3","@rollup/plugin-terser":"^0.4.3","rollup-plugin-commonjs":"^10.1.0","rollup-plugin-typescript":"^1.0.1","@rollup/plugin-node-resolve":"^15.1.0"},"_npmOperationalInternal":{"tmp":"tmp/soon-fetch_0.0.1_1725313823998_0.22583689672036322","host":"s3://npm-registry-packages"}},"0.0.2":{"name":"soon-fetch","version":"0.0.2","keywords":["request","fetch","lightweight","timeout","http","axios"],"author":"","license":"MIT","_id":"soon-fetch@0.0.2","maintainers":[{"name":"leafnote","email":"leafnote@outlook.com"}],"homepage":"https://github.com/leafio/soon-fetch","dist":{"shasum":"985282ca0a510278fefafa5244f57e05769b845b","tarball":"https://registry.npmjs.org/soon-fetch/-/soon-fetch-0.0.2.tgz","fileCount":5,"integrity":"sha512-h22EFmFbU+16MSyql0M3991j1NQiJHVKctnXL6u0Kbskkyof1Je0av8r8QA6XdAdWM1JPXMBzcnXZbPpacv2dQ==","signatures":[{"sig":"MEUCIG+pecFaBbosBnwqRPLIGUx5Yvw9r7zXnJ6ztaVc2HdcAiEAlDkSysK0oJ5vSQUnQRCxy3K8cn7tiKzYPiWfBjHZs7M=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":24218},"main":"./dist/index.cjs.js","types":"./dist/index.d.ts","module":"/dist/index.js","gitHead":"770b84fae60e0b61d3db96610206814f7e2005ab","scripts":{"test":"echo \"Error: no test specified\" && exit 1","build":"rollup --config","build:types":"tsc"},"_npmUser":{"name":"leafnote","email":"leafnote@outlook.com"},"_npmVersion":"10.2.3","description":"a lightweight request library based on fetch with TS prompt","directories":{},"_nodeVersion":"20.10.0","dependencies":{},"_hasShrinkwrap":false,"devDependencies":{"tslib":"^2.6.0","rollup":"^3.26.3","typescript":"^5.1.6","@babel/core":"^7.22.9","@babel/preset-env":"^7.22.9","rollup-plugin-dts":"^5.3.0","@rollup/plugin-babel":"^6.0.3","@rollup/plugin-terser":"^0.4.3","rollup-plugin-commonjs":"^10.1.0","rollup-plugin-typescript":"^1.0.1","@rollup/plugin-node-resolve":"^15.1.0"},"_npmOperationalInternal":{"tmp":"tmp/soon-fetch_0.0.2_1725540176044_0.8173033899041622","host":"s3://npm-registry-packages"}},"1.0.0":{"name":"soon-fetch","version":"1.0.0","keywords":["request","fetch","lightweight","timeout","http","axios"],"author":"","license":"MIT","_id":"soon-fetch@1.0.0","maintainers":[{"name":"leafnote","email":"leafnote@outlook.com"}],"homepage":"https://github.com/leafio/soon-fetch","dist":{"shasum":"c9b97067af73b5da8ab92bb982add760e79b6ba0","tarball":"https://registry.npmjs.org/soon-fetch/-/soon-fetch-1.0.0.tgz","fileCount":5,"integrity":"sha512-xCfav6aDQa1srdYIpwEbglNudouNJOOJgjty/WOZvxzUrCvgCEzkGphbmKK1OJmoPd0ifK7P8Ob6NgMsS69ihA==","signatures":[{"sig":"MEQCIGmQgUmVod7VMzfXAgHA15nuX2RwUReNAbnDxUubcT5hAiAx6vlDbM/PdzG5SmHhgCuM5Tj1rmkzyENkXlzqN+QD7w==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":19516},"main":"./dist/index.cjs.js","types":"./dist/index.d.ts","module":"/dist/index.js","gitHead":"c67d312a2590d3312b3f3a2d9907bb7f2a3e9d25","scripts":{"test":"echo \"Error: no test specified\" && exit 1","build":"rollup --config","build:types":"tsc"},"_npmUser":{"name":"leafnote","email":"leafnote@outlook.com"},"_npmVersion":"10.2.3","description":"a 2Kb request lib alternative to axios","directories":{},"_nodeVersion":"20.10.0","dependencies":{},"_hasShrinkwrap":false,"devDependencies":{"tslib":"^2.7.0","rollup":"^4.22.0","typescript":"^5.6.2","@babel/core":"^7.25.2","@babel/preset-env":"^7.25.4","rollup-plugin-dts":"^6.1.1","@rollup/plugin-babel":"^6.0.3","@rollup/plugin-terser":"^0.4.3","rollup-plugin-commonjs":"^10.1.0","rollup-plugin-typescript":"^1.0.1","@rollup/plugin-node-resolve":"^15.1.0"},"_npmOperationalInternal":{"tmp":"tmp/soon-fetch_1.0.0_1727536297062_0.0863389515695363","host":"s3://npm-registry-packages"}},"1.1.0":{"name":"soon-fetch","version":"1.1.0","keywords":["request","fetch","lightweight","timeout","http","axios"],"author":"","license":"MIT","_id":"soon-fetch@1.1.0","maintainers":[{"name":"leafnote","email":"leafnote@outlook.com"}],"homepage":"https://github.com/leafio/soon-fetch","dist":{"shasum":"7182846755b66520c5d0fda6c92c826a8e844536","tarball":"https://registry.npmjs.org/soon-fetch/-/soon-fetch-1.1.0.tgz","fileCount":5,"integrity":"sha512-JIDwMk6mYMFvQkbnOaGiOzlqxYg3Xkz5LsVgVizom0A1voEyUPIK0VjTjH2ETCVQ9dliK/uXuBIt+E6YnWaPww==","signatures":[{"sig":"MEQCIC1nlx8QPTezxGx5dQrs1HzVJEVx41mw3u8XVObhQtvGAiBa+wmJzWdqrKj+xZ5+pL7xvCmMCFlTKfcXXWpzyPmd5g==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":18655},"main":"./dist/index.cjs.js","types":"./dist/index.d.ts","module":"/dist/index.js","gitHead":"c5b213149214cd875d3963142a25fe10c40bc383","scripts":{"test":"echo \"Error: no test specified\" && exit 1","build":"rollup --config","build:types":"tsc"},"_npmUser":{"name":"leafnote","email":"leafnote@outlook.com"},"_npmVersion":"10.2.3","description":"a 3Kb request lib alternative to axios","directories":{},"_nodeVersion":"20.10.0","dependencies":{},"_hasShrinkwrap":false,"devDependencies":{"tslib":"^2.7.0","rollup":"^4.22.0","typescript":"^5.6.2","@babel/core":"^7.25.2","@babel/preset-env":"^7.25.4","rollup-plugin-dts":"^6.1.1","@rollup/plugin-babel":"^6.0.3","@rollup/plugin-terser":"^0.4.3","rollup-plugin-commonjs":"^10.1.0","rollup-plugin-typescript":"^1.0.1","@rollup/plugin-node-resolve":"^15.1.0"},"_npmOperationalInternal":{"tmp":"tmp/soon-fetch_1.1.0_1733181917633_0.09205785877391937","host":"s3://npm-registry-packages"}},"2.0.0":{"name":"soon-fetch","version":"2.0.0","keywords":["request","fetch","lightweight","timeout","http","axios"],"author":"","license":"MIT","_id":"soon-fetch@2.0.0","maintainers":[{"name":"leafnote","email":"leafnote@outlook.com"}],"homepage":"https://github.com/leafio/soon-fetch","dist":{"shasum":"dc02cb5f92ccae74085a8be8af03b80fa27c8b22","tarball":"https://registry.npmjs.org/soon-fetch/-/soon-fetch-2.0.0.tgz","fileCount":5,"integrity":"sha512-uE0UY2db9cc7cb6aVX6qNDG+djrYPtSOXqI3cBufp7JoMyp6CccJDpCySyIqmgJSYmCS+92tla4Fe5XsfgH21w==","signatures":[{"sig":"MEUCIDp+CRS7kSSezlZ7lYGyIzjdUEAWfAlTg6pkA3Lg87+tAiEA95vP/ry13u11rbzWJ/3nnvgLh1sJdvVzkQwxfzyQWmA=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":18428},"main":"./dist/index.cjs.js","types":"./dist/index.d.ts","module":"/dist/index.js","gitHead":"5975cf22b56d3b4b2dbf0c05fa25d2b73392479b","scripts":{"test":"echo \"Error: no test specified\" && exit 1","build":"rollup --config","build:types":"tsc"},"_npmUser":{"name":"leafnote","email":"leafnote@outlook.com"},"_npmVersion":"10.9.2","description":"a 3Kb request lib alternative to axios","directories":{},"_nodeVersion":"23.4.0","dependencies":{},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tslib":"^2.7.0","rollup":"^4.22.0","typescript":"^5.6.2","@babel/core":"^7.25.2","@babel/preset-env":"^7.25.4","rollup-plugin-dts":"^6.1.1","@rollup/plugin-babel":"^6.0.3","@rollup/plugin-terser":"^0.4.3","rollup-plugin-commonjs":"^10.1.0","rollup-plugin-typescript":"^1.0.1","@rollup/plugin-node-resolve":"^15.1.0"},"_npmOperationalInternal":{"tmp":"tmp/soon-fetch_2.0.0_1735833105537_0.5022783250056015","host":"s3://npm-registry-packages-npm-production"}},"2.0.1":{"name":"soon-fetch","version":"2.0.1","keywords":["request","fetch","lightweight","timeout","http","axios"],"author":"","license":"MIT","_id":"soon-fetch@2.0.1","maintainers":[{"name":"leafnote","email":"leafnote@outlook.com"}],"homepage":"https://github.com/leafio/soon-fetch","dist":{"shasum":"f55a32697a889ea574da604d4f434ce511880368","tarball":"https://registry.npmjs.org/soon-fetch/-/soon-fetch-2.0.1.tgz","fileCount":5,"integrity":"sha512-orVm5TmNr24ufUS9Tr3AY+Y+dhNTwgDJ+KYtQa/ONRkKhzmLhymLcT+47jANiXJDC9CccdhSdsHr4de5lD+evg==","signatures":[{"sig":"MEUCIQCRicctCTip9Y5QAoIrW5XPfTbQBWccNzXNuf4/WO9eGQIgdhjedn6gs5Cbf0Te8IPQmhHJ61O5shHu0oJr7Xt4RsI=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":17445},"main":"./dist/index.cjs.js","types":"./dist/index.d.ts","module":"/dist/index.js","gitHead":"4a71c68fd9ded49ba1541a13bd96280c55d27513","scripts":{"test":"echo \"Error: no test specified\" && exit 1","build":"rollup --config","build:types":"tsc"},"_npmUser":{"name":"leafnote","email":"leafnote@outlook.com"},"_npmVersion":"10.9.2","description":"a 3Kb request lib alternative to axios","directories":{},"_nodeVersion":"23.4.0","dependencies":{},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tslib":"^2.7.0","rollup":"^4.22.0","typescript":"^5.6.2","@babel/core":"^7.25.2","@babel/preset-env":"^7.25.4","rollup-plugin-dts":"^6.1.1","@rollup/plugin-babel":"^6.0.3","@rollup/plugin-terser":"^0.4.3","rollup-plugin-commonjs":"^10.1.0","rollup-plugin-typescript":"^1.0.1","@rollup/plugin-node-resolve":"^15.1.0"},"_npmOperationalInternal":{"tmp":"tmp/soon-fetch_2.0.1_1735913064299_0.8199768305007173","host":"s3://npm-registry-packages-npm-production"}},"2.1.0":{"name":"soon-fetch","version":"2.1.0","keywords":["request","fetch","lightweight","timeout","http","axios"],"author":"","license":"MIT","_id":"soon-fetch@2.1.0","maintainers":[{"name":"leafnote","email":"leafnote@outlook.com"}],"homepage":"https://github.com/leafio/soon-fetch","dist":{"shasum":"0f0c29d0543ce41e2c2d9d27c8d73764e82814a2","tarball":"https://registry.npmjs.org/soon-fetch/-/soon-fetch-2.1.0.tgz","fileCount":5,"integrity":"sha512-omAYKxMgPmEKIcL3cWzMXXdVW/xKJzOnDV2e+t6pB6gsu+vwzadRpwlDo7KVfFE94kOjEw07rtj75si4bzAC4w==","signatures":[{"sig":"MEUCIDvN2NplaZVZly5gwGpzK20cim+gfeZLI0sqJX5/X+LYAiEAwK6TTY1J1Z0xgNtCOu62Llbe/in0Wc0e/g10PbjZu7w=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":19224},"main":"./dist/index.cjs.js","types":"./dist/index.d.ts","module":"/dist/index.js","gitHead":"67cb95b8a727e9aad9a717985b8736d7e5d604d7","scripts":{"test":"echo \"Error: no test specified\" && exit 1","build":"rollup --config","build:types":"tsc"},"_npmUser":{"name":"leafnote","email":"leafnote@outlook.com"},"_npmVersion":"10.9.2","description":"a 3Kb request lib alternative to axios","directories":{},"_nodeVersion":"23.4.0","dependencies":{},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tslib":"^2.7.0","rollup":"^4.22.0","typescript":"^5.6.2","@babel/core":"^7.25.2","@babel/preset-env":"^7.25.4","rollup-plugin-dts":"^6.1.1","@rollup/plugin-babel":"^6.0.3","@rollup/plugin-terser":"^0.4.3","rollup-plugin-commonjs":"^10.1.0","rollup-plugin-typescript":"^1.0.1","@rollup/plugin-node-resolve":"^15.1.0"},"_npmOperationalInternal":{"tmp":"tmp/soon-fetch_2.1.0_1736863307329_0.775379335428191","host":"s3://npm-registry-packages-npm-production"}},"2.1.1":{"name":"soon-fetch","version":"2.1.1","keywords":["request","fetch","lightweight","timeout","http","axios"],"author":"","license":"MIT","_id":"soon-fetch@2.1.1","maintainers":[{"name":"leafnote","email":"leafnote@outlook.com"}],"homepage":"https://github.com/leafio/soon-fetch","dist":{"shasum":"6062827da6bfa772f289b37447eb4ef0683d10c9","tarball":"https://registry.npmjs.org/soon-fetch/-/soon-fetch-2.1.1.tgz","fileCount":5,"integrity":"sha512-4IvazK3g7uk31UrVVkWo7loSgUG+AvEUB4FvveyMeDTQqTolzkVR7WQWv0hMpmzufIKV39LK/0oT2njkrFYjMw==","signatures":[{"sig":"MEUCIQCkqc/MVaaAK75rRwTLJHAr1Kkywq7/pCTUe9yZ4j3eQgIgIPkE8MojMuAtHmnOXAdBWhWVY70eHb/Sca4a/yekoIk=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":20440},"main":"./dist/index.cjs.js","types":"./dist/index.d.ts","module":"/dist/index.js","gitHead":"dfeee2a228f87c31af0c8317f2c6907676633272","scripts":{"test":"echo \"Error: no test specified\" && exit 1","build":"rollup --config","build:types":"tsc"},"_npmUser":{"name":"leafnote","email":"leafnote@outlook.com"},"_npmVersion":"10.9.2","description":"a 3Kb request lib alternative to axios","directories":{},"_nodeVersion":"23.4.0","dependencies":{},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tslib":"^2.7.0","rollup":"^4.22.0","typescript":"^5.6.2","@babel/core":"^7.25.2","@babel/preset-env":"^7.25.4","rollup-plugin-dts":"^6.1.1","@rollup/plugin-babel":"^6.0.3","@rollup/plugin-terser":"^0.4.3","rollup-plugin-commonjs":"^10.1.0","rollup-plugin-typescript":"^1.0.1","@rollup/plugin-node-resolve":"^15.1.0"},"_npmOperationalInternal":{"tmp":"tmp/soon-fetch_2.1.1_1737146050591_0.17591431438383553","host":"s3://npm-registry-packages-npm-production"}},"3.0.0-beta.1":{"name":"soon-fetch","version":"3.0.0-beta.1","keywords":["request","fetch","lightweight","timeout","http","axios"],"author":"","license":"MIT","_id":"soon-fetch@3.0.0-beta.1","maintainers":[{"name":"leafnote","email":"leafnote@outlook.com"}],"homepage":"https://github.com/leafio/soon-fetch","dist":{"shasum":"761ac4d50f6935a0a5edfc7b400b1a7d8a0a7ffe","tarball":"https://registry.npmjs.org/soon-fetch/-/soon-fetch-3.0.0-beta.1.tgz","fileCount":5,"integrity":"sha512-gmyXoc9TLRukKsxoGm+9Aoln5vbFG1NrZrBDEzM0tM/VVMZKZU3PKWjwIrs32gnRcHRmh1PsuhN6bKgGS59OwA==","signatures":[{"sig":"MEUCIQDSsFmC8N7aDRIu3Y81tdHJGI8Qcerhax48r5JT5ygDdwIgYIQleJkJH+dGXj33u7OK8O7qtGnZA4qxv9eurNqToTU=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":36110},"main":"./dist/index.cjs.js","types":"./dist/index.d.ts","module":"/dist/index.js","gitHead":"0b62c726e033270cddf8c88bdb80b6511b936564","scripts":{"test":"echo \"Error: no test specified\" && exit 1","build":"rollup --config","build:types":"tsc"},"_npmUser":{"name":"leafnote","actor":{"name":"leafnote","type":"user","email":"leafnote@outlook.com"},"email":"leafnote@outlook.com"},"_npmVersion":"10.9.0","description":"a 3Kb request lib alternative to axios","directories":{},"_nodeVersion":"22.11.0","dependencies":{},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tslib":"^2.7.0","rollup":"^4.22.0","typescript":"^5.6.2","@babel/core":"^7.25.2","@babel/preset-env":"^7.25.4","rollup-plugin-dts":"^6.1.1","@rollup/plugin-babel":"^6.0.3","@rollup/plugin-terser":"^0.4.3","rollup-plugin-commonjs":"^10.1.0","rollup-plugin-typescript":"^1.0.1","@rollup/plugin-node-resolve":"^15.1.0"},"_npmOperationalInternal":{"tmp":"tmp/soon-fetch_3.0.0-beta.1_1751295693104_0.6875484138311709","host":"s3://npm-registry-packages-npm-production"}},"3.0.0-beta.2":{"name":"soon-fetch","version":"3.0.0-beta.2","keywords":["request","fetch","lightweight","timeout","http","axios"],"author":"","license":"MIT","_id":"soon-fetch@3.0.0-beta.2","maintainers":[{"name":"leafnote","email":"leafnote@outlook.com"}],"homepage":"https://github.com/leafio/soon-fetch","dist":{"shasum":"f7e581421e941155b55ce9f1fa010b88a7da33d7","tarball":"https://registry.npmjs.org/soon-fetch/-/soon-fetch-3.0.0-beta.2.tgz","fileCount":5,"integrity":"sha512-LLQnZRVEerbwOVWT1W6NHYvlShxfZYSndUURQlV5SF9kCg5bFCsL9xDYQgiHWVzpf0fBRF6crfJSyLQUDWfwtA==","signatures":[{"sig":"MEQCIESnMGtk7o+9QaUKjBfokpDHITnurwY1kIaUUtsg3b9OAiAMX1Wl9nzveM2m02xX1cPRtCIC6mbXz7z6mGYVCjpRdg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":31874},"main":"./dist/index.cjs.js","types":"./dist/index.d.ts","module":"/dist/index.js","gitHead":"aae3a785ca0713f04c4c2d14d8e9c0fbffb9927f","scripts":{"test":"echo \"Error: no test specified\" && exit 1","build":"rollup --config","build:types":"tsc"},"_npmUser":{"name":"leafnote","actor":{"name":"leafnote","type":"user","email":"leafnote@outlook.com"},"email":"leafnote@outlook.com"},"_npmVersion":"10.9.0","description":"a 3Kb request lib alternative to axios","directories":{},"_nodeVersion":"22.12.0","dependencies":{},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tslib":"^2.7.0","rollup":"^4.22.0","typescript":"^5.6.2","@babel/core":"^7.25.2","@babel/preset-env":"^7.25.4","rollup-plugin-dts":"^6.1.1","@rollup/plugin-babel":"^6.0.3","@rollup/plugin-terser":"^0.4.3","rollup-plugin-commonjs":"^10.1.0","rollup-plugin-typescript":"^1.0.1","@rollup/plugin-node-resolve":"^15.1.0"},"_npmOperationalInternal":{"tmp":"tmp/soon-fetch_3.0.0-beta.2_1752166996758_0.005759613911853423","host":"s3://npm-registry-packages-npm-production"}},"3.0.0-beta.3":{"name":"soon-fetch","version":"3.0.0-beta.3","keywords":["request","fetch","lightweight","timeout","http","axios"],"author":"","license":"MIT","_id":"soon-fetch@3.0.0-beta.3","maintainers":[{"name":"leafnote","email":"leafnote@outlook.com"}],"homepage":"https://github.com/leafio/soon-fetch","dist":{"shasum":"1bf59f89ede3bff60e1d505e7108e41ba39dd266","tarball":"https://registry.npmjs.org/soon-fetch/-/soon-fetch-3.0.0-beta.3.tgz","fileCount":5,"integrity":"sha512-SkoweXKW6M3lov6jwABdW60cAXj/ii/L9igRalnPsfCruP6B3kvnBrzzHKvCT4rbPLmSAHMqr51lfUxMBlCJVw==","signatures":[{"sig":"MEUCIErUKX59Zl/yleiiYR/X4Nd6VA8/GYYxnFPBN6UEiMqBAiEAq1m3i4DM6VS48BlVccz4JMYN8khoG+LeuBeIq44FVow=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":33007},"main":"./dist/index.cjs.js","types":"./dist/index.d.ts","module":"/dist/index.js","gitHead":"05067ccf905539ea091438c3c7d0d8789bb51226","scripts":{"test":"echo \"Error: no test specified\" && exit 1","build":"rollup --config","build:types":"tsc"},"_npmUser":{"name":"leafnote","email":"leafnote@outlook.com"},"_npmVersion":"10.9.0","description":"a 5Kb request lib alternative to axios","directories":{},"_nodeVersion":"22.12.0","dependencies":{},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tslib":"^2.7.0","rollup":"^4.22.0","typescript":"^5.6.2","@babel/core":"^7.25.2","@babel/preset-env":"^7.25.4","rollup-plugin-dts":"^6.1.1","@rollup/plugin-babel":"^6.0.3","@rollup/plugin-terser":"^0.4.3","rollup-plugin-commonjs":"^10.1.0","rollup-plugin-typescript":"^1.0.1","@rollup/plugin-node-resolve":"^15.1.0"},"_npmOperationalInternal":{"tmp":"tmp/soon-fetch_3.0.0-beta.3_1752397269442_0.537829432205194","host":"s3://npm-registry-packages-npm-production"}},"3.0.0-beta.4":{"name":"soon-fetch","version":"3.0.0-beta.4","keywords":["request","fetch","lightweight","timeout","http","axios"],"author":"","license":"MIT","_id":"soon-fetch@3.0.0-beta.4","maintainers":[{"name":"leafnote","email":"leafnote@outlook.com"}],"homepage":"https://github.com/leafio/soon-fetch","dist":{"shasum":"ce9541b0eefd5014d18d28957fadba989fb97789","tarball":"https://registry.npmjs.org/soon-fetch/-/soon-fetch-3.0.0-beta.4.tgz","fileCount":5,"integrity":"sha512-W4eIEJNE1P52+M0qnolk2CvU33Ujmgt3FJw45UW2iHIZ7gvxq6Q5EwaCEHPyM0iOY7Dd3hq77kb4nKmaztWR2Q==","signatures":[{"sig":"MEYCIQDC7l7+E8r0D82CO1g1g9McTtRYKjFSfZYkd7GwEhk1JQIhAJ0ByVLHIbavcxFv0Vzfpp3tt3Qvs/1yaN+O0o5eOhqk","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":33982},"main":"./dist/index.cjs.js","types":"./dist/index.d.ts","module":"/dist/index.js","gitHead":"dfa74a65b6340ca12605ba4eea8a120ee843f806","scripts":{"test":"echo \"Error: no test specified\" && exit 1","build":"rollup --config","build:types":"tsc"},"_npmUser":{"name":"leafnote","email":"leafnote@outlook.com"},"_npmVersion":"10.9.0","description":"a 5Kb request lib alternative to axios with timeout, request reusing ,cache ,race ...","directories":{},"_nodeVersion":"22.12.0","dependencies":{},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tslib":"^2.7.0","rollup":"^4.22.0","typescript":"^5.6.2","@babel/core":"^7.25.2","@babel/preset-env":"^7.25.4","rollup-plugin-dts":"^6.1.1","@rollup/plugin-babel":"^6.0.3","@rollup/plugin-terser":"^0.4.3","rollup-plugin-commonjs":"^10.1.0","rollup-plugin-typescript":"^1.0.1","@rollup/plugin-node-resolve":"^15.1.0"},"_npmOperationalInternal":{"tmp":"tmp/soon-fetch_3.0.0-beta.4_1753113020650_0.29859783665066497","host":"s3://npm-registry-packages-npm-production"}},"3.0.0":{"name":"soon-fetch","version":"3.0.0","keywords":["request","fetch","lightweight","timeout","http","axios"],"author":"","license":"MIT","_id":"soon-fetch@3.0.0","maintainers":[{"name":"leafnote","email":"leafnote@outlook.com"}],"homepage":"https://github.com/leafio/soon-fetch","dist":{"shasum":"b51929f9ee525adbe98863fde4bb4b7e54677efb","tarball":"https://registry.npmjs.org/soon-fetch/-/soon-fetch-3.0.0.tgz","fileCount":5,"integrity":"sha512-LK+kwPJksfsqf7XXtulpTh8bQ/0b2QV5JhQIPItjBK5lnLtJVihyRSeB9pxT6kbA8kbzGWoZUK3rxvhob9lInQ==","signatures":[{"sig":"MEQCIC/q4sw02D8T1/FZkUYZIhyOVa3XcopFKEiG28TefDCiAiAsD+DJLF+mSpgMYdIHizFAXmSp88IPfAeQANX+SURtuw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":34486},"main":"./dist/index.cjs.js","types":"./dist/index.d.ts","module":"/dist/index.js","gitHead":"167d4db2408addeab6b4d9e8bc6a7ca25effb9d2","scripts":{"test":"echo \"Error: no test specified\" && exit 1","build":"rollup --config","build:types":"tsc"},"_npmUser":{"name":"leafnote","email":"leafnote@outlook.com"},"_npmVersion":"10.9.0","description":"a 5Kb request lib alternative to axios with timeout, request reusing, race, response cache ...","directories":{},"_nodeVersion":"22.12.0","dependencies":{},"_hasShrinkwrap":false,"devDependencies":{"tslib":"^2.7.0","rollup":"^4.22.0","typescript":"^5.6.2","@babel/core":"^7.25.2","@babel/preset-env":"^7.25.4","rollup-plugin-dts":"^6.1.1","@rollup/plugin-babel":"^6.0.3","@rollup/plugin-terser":"^0.4.3","rollup-plugin-commonjs":"^10.1.0","rollup-plugin-typescript":"^1.0.1","@rollup/plugin-node-resolve":"^15.1.0"},"_npmOperationalInternal":{"tmp":"tmp/soon-fetch_3.0.0_1753741516286_0.8323013926645042","host":"s3://npm-registry-packages-npm-production"}},"3.0.1":{"name":"soon-fetch","version":"3.0.1","keywords":["request","fetch","lightweight","timeout","http","axios"],"author":"","license":"MIT","_id":"soon-fetch@3.0.1","maintainers":[{"name":"leafnote","email":"leafnote@outlook.com"}],"homepage":"https://github.com/leafio/soon-fetch","dist":{"shasum":"2b46a5fd5e8fa75ce2e96cbd83cd31b083a2909e","tarball":"https://registry.npmjs.org/soon-fetch/-/soon-fetch-3.0.1.tgz","fileCount":5,"integrity":"sha512-dXAqUwl9ZHM9ebZUmv9oGe4dSjBrpvDmtykQ2sqydpmzBB6HHpJB+cXohLmJGRB706JiSulE3Hw/ZrNSq8lX1w==","signatures":[{"sig":"MEYCIQDSDIVJEBWbX8P2of0XJLv8B25mYmG3PTZCsB8ZJQPD1AIhAKOwzc+26bly7V4p2rKyF8bdjTXskb5LT3873/HDBVh/","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":34895},"main":"./dist/index.cjs.js","types":"./dist/index.d.ts","module":"/dist/index.js","gitHead":"8deb0def4feba27271dc77baae6eccb7d5ff0aa0","scripts":{"test":"echo \"Error: no test specified\" && exit 1","build":"rollup --config","build:types":"tsc"},"_npmUser":{"name":"leafnote","email":"leafnote@outlook.com"},"_npmVersion":"10.9.0","description":"a 5Kb request lib alternative to axios with timeout, request reusing, race, response cache ...","directories":{},"_nodeVersion":"22.12.0","dependencies":{},"_hasShrinkwrap":false,"devDependencies":{"tslib":"^2.7.0","rollup":"^4.22.0","typescript":"^5.6.2","@babel/core":"^7.25.2","@babel/preset-env":"^7.25.4","rollup-plugin-dts":"^6.1.1","@rollup/plugin-babel":"^6.0.3","@rollup/plugin-terser":"^0.4.3","rollup-plugin-commonjs":"^10.1.0","rollup-plugin-typescript":"^1.0.1","@rollup/plugin-node-resolve":"^15.1.0"},"_npmOperationalInternal":{"tmp":"tmp/soon-fetch_3.0.1_1753908645079_0.6305822272534132","host":"s3://npm-registry-packages-npm-production"}},"3.1.0":{"name":"soon-fetch","version":"3.1.0","keywords":["request","fetch","lightweight","timeout","http","axios"],"author":"","license":"MIT","_id":"soon-fetch@3.1.0","maintainers":[{"name":"leafnote","email":"leafnote@outlook.com"}],"homepage":"https://github.com/leafio/soon-fetch","dist":{"shasum":"5171891d7e7f67ea95ff08b2eb578b7bbd39b9cd","tarball":"https://registry.npmjs.org/soon-fetch/-/soon-fetch-3.1.0.tgz","fileCount":5,"integrity":"sha512-fWBfFc798fH1zz7S+Uc5tPlhiJDqtvRrUVorIQ6R07GtiQjA7fD95aP5Vun4V+PQRHlROQy5G7E5bCRFZcgSuA==","signatures":[{"sig":"MEUCIQDHz1L2uVsRgH6BVRRa7xy43qr8f6sixmlSAOZpOQ7rtAIgZ6UHXrcwmte22KZQ4u48O2xVXzIvwgAXK5KcuoutbPA=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":55143},"main":"./dist/index.cjs.js","types":"./dist/index.d.ts","module":"/dist/index.js","gitHead":"a4132424f2396943123b9aba4a909473656c05ab","scripts":{"test":"echo \"Error: no test specified\" && exit 1","build":"rollup --config","build:types":"tsc"},"_npmUser":{"name":"leafnote","email":"leafnote@outlook.com"},"_npmVersion":"10.9.0","description":"a 5Kb request lib alternative to axios with timeout, request reusing, race, response cache ...","directories":{},"_nodeVersion":"22.12.0","dependencies":{},"_hasShrinkwrap":false,"devDependencies":{"tslib":"^2.7.0","rollup":"^4.22.0","typescript":"^5.6.2","@babel/core":"^7.25.2","@babel/preset-env":"^7.25.4","rollup-plugin-dts":"^6.1.1","@rollup/plugin-babel":"^6.0.3","@rollup/plugin-terser":"^0.4.3","rollup-plugin-commonjs":"^10.1.0","rollup-plugin-typescript":"^1.0.1","@rollup/plugin-node-resolve":"^15.1.0"},"_npmOperationalInternal":{"tmp":"tmp/soon-fetch_3.1.0_1755557745169_0.4104061284162548","host":"s3://npm-registry-packages-npm-production"}},"3.1.1":{"name":"soon-fetch","version":"3.1.1","keywords":["request","fetch","lightweight","timeout","http","axios"],"author":"","license":"MIT","_id":"soon-fetch@3.1.1","maintainers":[{"name":"leafnote","email":"leafnote@outlook.com"}],"homepage":"https://github.com/leafio/soon-fetch","dist":{"shasum":"bf30ce686d9c81371f86735c445d32fa63fe55b2","tarball":"https://registry.npmjs.org/soon-fetch/-/soon-fetch-3.1.1.tgz","fileCount":5,"integrity":"sha512-G+EEzBKRq1K9J/zsZC2c2CPY2kCgzxrv0911fud6r43nxmsGPe+3hQJEvF6rpIEuz4Vd+1ubm66zTspZ3fhH8A==","signatures":[{"sig":"MEUCIGm7JI1PVyNrKSL/SPR5DWuBQesYskia9o8tfRAY25GrAiEAx7bIpENU/WfUw1mrzlp2PuieNknsKa0pc+z1ltTbwhM=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":55303},"main":"./dist/index.cjs.js","types":"./dist/index.d.ts","module":"/dist/index.js","gitHead":"1e163e56b04b4a41ff4e1be90be3adbddf0c7e66","scripts":{"test":"echo \"Error: no test specified\" && exit 1","build":"rollup --config","build:types":"tsc"},"_npmUser":{"name":"leafnote","email":"leafnote@outlook.com"},"_npmVersion":"10.9.0","description":"a 5Kb request lib alternative to axios with timeout, request reusing, race, response cache ...","directories":{},"_nodeVersion":"22.12.0","dependencies":{},"_hasShrinkwrap":false,"devDependencies":{"tslib":"^2.7.0","rollup":"^4.22.0","typescript":"^5.6.2","@babel/core":"^7.25.2","@babel/preset-env":"^7.25.4","rollup-plugin-dts":"^6.1.1","@rollup/plugin-babel":"^6.0.3","@rollup/plugin-terser":"^0.4.3","rollup-plugin-commonjs":"^10.1.0","rollup-plugin-typescript":"^1.0.1","@rollup/plugin-node-resolve":"^15.1.0"},"_npmOperationalInternal":{"tmp":"tmp/soon-fetch_3.1.1_1755642453559_0.2982906635586364","host":"s3://npm-registry-packages-npm-production"}},"3.1.2":{"name":"soon-fetch","version":"3.1.2","keywords":["request","fetch","lightweight","timeout","http","axios"],"author":"","license":"MIT","_id":"soon-fetch@3.1.2","maintainers":[{"name":"leafnote","email":"leafnote@outlook.com"}],"homepage":"https://github.com/leafio/soon-fetch","dist":{"shasum":"48788a61c774bee0946c7c7eaf31686ddedb0abd","tarball":"https://registry.npmjs.org/soon-fetch/-/soon-fetch-3.1.2.tgz","fileCount":5,"integrity":"sha512-pNT6rWbsV8xYDzHZAtUOf87aoqFSFCUMWGXVE/4lDX6enUkWzoqF5QTE2Wt70vUQoEBUErkcc2sbvhnmauj9cA==","signatures":[{"sig":"MEQCIBNhKKnwhAN9l058BicGM18xl3QNsOZi261zzWYb6TLVAiBMPAvPv0M5IqK7kVjLn9rp1PhZmdr9WfMQ1RaOaw/2Ww==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":55437},"main":"./dist/index.cjs.js","types":"./dist/index.d.ts","module":"/dist/index.js","gitHead":"31eeea32ea120626a188afcd30f15b625110b17a","scripts":{"test":"echo \"Error: no test specified\" && exit 1","build":"rollup --config","build:types":"tsc"},"_npmUser":{"name":"leafnote","email":"leafnote@outlook.com"},"_npmVersion":"10.9.0","description":"a request lib alternative to axios with timeout, request reusing, race, response cache ...","directories":{},"_nodeVersion":"22.12.0","dependencies":{},"_hasShrinkwrap":false,"devDependencies":{"tslib":"^2.7.0","rollup":"^4.22.0","typescript":"^5.6.2","@babel/core":"^7.25.2","@babel/preset-env":"^7.25.4","rollup-plugin-dts":"^6.1.1","@rollup/plugin-babel":"^6.0.3","@rollup/plugin-terser":"^0.4.3","rollup-plugin-commonjs":"^10.1.0","rollup-plugin-typescript":"^1.0.1","@rollup/plugin-node-resolve":"^15.1.0"},"_npmOperationalInternal":{"tmp":"tmp/soon-fetch_3.1.2_1758812947357_0.37361375983038014","host":"s3://npm-registry-packages-npm-production"}},"4.0.0-beta.0":{"name":"soon-fetch","version":"4.0.0-beta.0","keywords":["request","fetch","lightweight","timeout","http","axios"],"author":"","license":"MIT","_id":"soon-fetch@4.0.0-beta.0","maintainers":[{"name":"leafnote","email":"leafnote@outlook.com"}],"homepage":"https://github.com/leafio/soon-fetch","dist":{"shasum":"5bb91877703ee0c7b98df0b179dfac0a08fbf068","tarball":"https://registry.npmjs.org/soon-fetch/-/soon-fetch-4.0.0-beta.0.tgz","fileCount":5,"integrity":"sha512-TB3OD5oO2UzkZINoqvJxA2jNgahg8RqLcjN/rB9vhQtC6glv59/tONW2gH6+42Z4EUAhho8QS6nVgczoQVHaBg==","signatures":[{"sig":"MEUCIQDw/KuChdydtGhnZzftqp/1OcrzBVGHdZ7aoyOTaYxIpgIgH5qqe+uWAxrPxsL5y58fU0zCC0tWR0zcJtqibMZXKxw=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":77065},"main":"./dist/index.cjs.js","types":"./dist/index.d.ts","module":"/dist/index.js","gitHead":"bfc46df32fa0aa96be6c29a671f26e35c1f3f4be","scripts":{"test":"jest","build":"rollup --config","test:watch":"jest --watch","build:types":"tsc","test:coverage":"jest --coverage"},"_npmUser":{"name":"leafnote","email":"leafnote@outlook.com"},"_npmVersion":"11.6.2","description":"a request lib alternative to axios with timeout, request reusing, race, response cache ...","directories":{},"_nodeVersion":"24.12.0","_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"jest":"^29.7.0","tslib":"^2.7.0","rollup":"^4.22.0","ts-jest":"^29.4.6","typescript":"^5.6.2","@babel/core":"^7.25.2","@types/jest":"^29.5.14","@babel/preset-env":"^7.25.4","rollup-plugin-dts":"^6.1.1","@rollup/plugin-babel":"^6.0.3","@rollup/plugin-terser":"^0.4.3","rollup-plugin-commonjs":"^10.1.0","rollup-plugin-typescript":"^1.0.1","@rollup/plugin-node-resolve":"^15.1.0"},"_npmOperationalInternal":{"tmp":"tmp/soon-fetch_4.0.0-beta.0_1772983009343_0.8096712248489879","host":"s3://npm-registry-packages-npm-production"}},"4.0.0-beta.1":{"name":"soon-fetch","version":"4.0.0-beta.1","keywords":["request","fetch","lightweight","timeout","http","axios"],"author":"","license":"MIT","_id":"soon-fetch@4.0.0-beta.1","maintainers":[{"name":"leafnote","email":"leafnote@outlook.com"}],"homepage":"https://github.com/leafio/soon-fetch","dist":{"shasum":"1e129b788d66760b98b009b38d96a0c3896b2e43","tarball":"https://registry.npmjs.org/soon-fetch/-/soon-fetch-4.0.0-beta.1.tgz","fileCount":5,"integrity":"sha512-8itaNKMKEA60dwAXK72k+DrEAYAADgV40//xOasHJn3Ulbbqy/SZj274ot+rVqoPvLnhcvQ96JLIgF8SWE1ZCQ==","signatures":[{"sig":"MEYCIQCWEHmerSDza3X2PNqZQ43gttM1s3FCTCEZpcqLicfr8QIhAOQo5yVSBLbI8Hz/fYWbrfzZkpNxSlal3uPHl8ov/Ieu","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":78324},"main":"./dist/index.cjs.js","types":"./dist/index.d.ts","module":"/dist/index.js","gitHead":"63834e0098c8855764f4a55c0bde61e7049340aa","scripts":{"test":"jest","build":"rollup --config","test:watch":"jest --watch","build:types":"tsc","test:coverage":"jest --coverage"},"_npmUser":{"name":"leafnote","email":"leafnote@outlook.com"},"_npmVersion":"11.6.2","description":"a request lib alternative to axios with timeout, request reusing, race, response cache ...","directories":{},"_nodeVersion":"24.12.0","_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"jest":"^29.7.0","tslib":"^2.7.0","rollup":"^4.22.0","ts-jest":"^29.4.6","typescript":"^5.6.2","@babel/core":"^7.25.2","@types/jest":"^29.5.14","@babel/preset-env":"^7.25.4","rollup-plugin-dts":"^6.1.1","@rollup/plugin-babel":"^6.0.3","@rollup/plugin-terser":"^0.4.3","rollup-plugin-commonjs":"^10.1.0","rollup-plugin-typescript":"^1.0.1","@rollup/plugin-node-resolve":"^15.1.0"},"_npmOperationalInternal":{"tmp":"tmp/soon-fetch_4.0.0-beta.1_1773147197271_0.9027234248497116","host":"s3://npm-registry-packages-npm-production"}},"4.0.0-beta.2":{"name":"soon-fetch","version":"4.0.0-beta.2","keywords":["request","fetch","lightweight","timeout","http","axios"],"author":"","license":"MIT","_id":"soon-fetch@4.0.0-beta.2","maintainers":[{"name":"leafnote","email":"leafnote@outlook.com"}],"homepage":"https://github.com/leafio/soon-fetch","dist":{"shasum":"6aa80a3ab2afd1beef620a56fe651b62d5e3aa4b","tarball":"https://registry.npmjs.org/soon-fetch/-/soon-fetch-4.0.0-beta.2.tgz","fileCount":5,"integrity":"sha512-pkEX2d1K0mnm7js2ipDQ7p5mnC6knKa4OCf1n+5/iTZ3SmZKDcywewLQ2lQlnzoMOQd6nJerzxVeDByQM9ediA==","signatures":[{"sig":"MEYCIQDqztUDWaABbm4APQd9JO78gsYnfvuPBZDKng33bu/77AIhAJRQqgUT6AwWwBLn1JBWrL4J5gq9uupVm/cjTu/YTuF5","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":79559},"main":"./dist/index.cjs.js","types":"./dist/index.d.ts","module":"/dist/index.js","gitHead":"bca3897eeb4c0bdbab7466327b7872628d3281f9","scripts":{"test":"jest","build":"rollup --config","test:watch":"jest --watch","build:types":"tsc","test:coverage":"jest --coverage"},"_npmUser":{"name":"leafnote","email":"leafnote@outlook.com"},"_npmVersion":"11.6.2","description":"a request lib alternative to axios with timeout, request reusing, race, response cache ...","directories":{},"_nodeVersion":"25.0.0","_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"jest":"^29.7.0","tslib":"^2.7.0","rollup":"^4.22.0","ts-jest":"^29.4.6","typescript":"^5.6.2","@babel/core":"^7.25.2","@types/jest":"^29.5.14","@babel/preset-env":"^7.25.4","rollup-plugin-dts":"^6.1.1","@rollup/plugin-babel":"^6.0.3","@rollup/plugin-terser":"^0.4.3","rollup-plugin-commonjs":"^10.1.0","rollup-plugin-typescript":"^1.0.1","@rollup/plugin-node-resolve":"^15.1.0"},"_npmOperationalInternal":{"tmp":"tmp/soon-fetch_4.0.0-beta.2_1774880937413_0.6004482297714349","host":"s3://npm-registry-packages-npm-production"}},"4.0.0-beta.3":{"name":"soon-fetch","version":"4.0.0-beta.3","keywords":["request","fetch","lightweight","timeout","http","axios"],"author":"","license":"MIT","_id":"soon-fetch@4.0.0-beta.3","maintainers":[{"name":"leafnote","email":"leafnote@outlook.com"}],"homepage":"https://github.com/leafio/soon-fetch","dist":{"shasum":"1010ce481fff79c4591cb6103ccbb8f0ed4df102","tarball":"https://registry.npmjs.org/soon-fetch/-/soon-fetch-4.0.0-beta.3.tgz","fileCount":6,"integrity":"sha512-TnKnXk8IgyE+8NvVkBVHPBFZLzwh3w+o51j7gQcCyfWJCcmYTXSRRgvkq1aiN/GtZyg2+u6XxLc5lfIBtX5aIA==","signatures":[{"sig":"MEQCIDNTqDK9l1UbPyBFJm/e2K1EgpyKqpi4WpKV/dGSS4pCAiBfMT7X5XiFTvfEcMMOCSYMbof7N+lWIAoZTylYcR9Pew==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":131474},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","unpkg":"./dist/index.global.js","module":"./dist/index.js","gitHead":"bccdb62fe52c9fc428fc40bd8bec473c9c1a2678","scripts":{"test":"vitest src/__tests__","build":"tsdown","test:watch":"vitest watch src/__tests__","test:coverage":"vitest run --coverage src/__tests__"},"_npmUser":{"name":"leafnote","email":"leafnote@outlook.com"},"_npmVersion":"11.6.2","description":"a request lib alternative to axios with timeout, request reusing, race, response cache ...","directories":{},"_nodeVersion":"25.0.0","_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsup":"^8.5.1","tsdown":"^0.21.7","vitest":"^2.1.1","typescript":"^5.6.2"},"_npmOperationalInternal":{"tmp":"tmp/soon-fetch_4.0.0-beta.3_1775051643627_0.909704149790924","host":"s3://npm-registry-packages-npm-production"}},"4.0.0-beta.4":{"name":"soon-fetch","version":"4.0.0-beta.4","keywords":["request","fetch","lightweight","timeout","http","axios"],"author":"","license":"MIT","_id":"soon-fetch@4.0.0-beta.4","maintainers":[{"name":"leafnote","email":"leafnote@outlook.com"}],"homepage":"https://github.com/leafio/soon-fetch","dist":{"shasum":"0e0bbec73c8c17bb3f8d35fbaa376bd5c780cc7b","tarball":"https://registry.npmjs.org/soon-fetch/-/soon-fetch-4.0.0-beta.4.tgz","fileCount":7,"integrity":"sha512-FhSodFq0Ym/GezPbOpjzCAVqTe+rxGeaugnV0R5uJ44AIBKnZZz1/7Vatrtro4EecrP1YcdQWx4YHwz6P7jH3Q==","signatures":[{"sig":"MEYCIQDP+xMzCgJ1CAOw5VdRTxbC6C+kXhrEYzW3vJCkH1nREgIhAM9EWb6VTKiPzm6iohQZN697M5Dt3uE5Ge5HBWV/S6yH","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":139965},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.mts","unpkg":"./dist/index.iife.js","module":"./dist/index.js","gitHead":"bccdb62fe52c9fc428fc40bd8bec473c9c1a2678","scripts":{"test":"vitest src/__tests__","build":"tsdown","test:watch":"vitest watch src/__tests__","test:coverage":"vitest run --coverage src/__tests__"},"_npmUser":{"name":"leafnote","email":"leafnote@outlook.com"},"_npmVersion":"11.6.2","description":"a request lib alternative to axios with timeout, request reusing, race, response cache ...","directories":{},"_nodeVersion":"25.0.0","_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsup":"^8.5.1","tsdown":"^0.21.7","vitest":"^2.1.1","typescript":"^5.6.2"},"_npmOperationalInternal":{"tmp":"tmp/soon-fetch_4.0.0-beta.4_1775575220568_0.2916245667382005","host":"s3://npm-registry-packages-npm-production"}},"4.0.0-beta.5":{"name":"soon-fetch","version":"4.0.0-beta.5","keywords":["request","fetch","lightweight","axios","timeout","request reusing","race","response cache","abort controller"],"author":{"name":"leaf"},"license":"MIT","_id":"soon-fetch@4.0.0-beta.5","maintainers":[{"name":"leafnote","email":"leafnote@outlook.com"}],"homepage":"https://github.com/leafio/soon-fetch","dist":{"shasum":"199b5e5449fdb7a75273ce7101b33dd64c0c43a1","tarball":"https://registry.npmjs.org/soon-fetch/-/soon-fetch-4.0.0-beta.5.tgz","fileCount":7,"integrity":"sha512-0Q3P2spU62O42IalE1STv1SnXT4MeNcvTtl22lDCVFg3BGx2U4pPbrrKveKViGG6Xy/QNL9RuN91EEd4vteGZA==","signatures":[{"sig":"MEQCIAPIRZAo3vuSvn6E39jC+/LsgkhHtS1QKLJGogJWsPAHAiBCbG+w3XpSsI1HxomX6NJFwWdwV9jkKDvQ85KYJnmmwQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":140055},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.mts","unpkg":"./dist/index.iife.js","module":"./dist/index.js","gitHead":"bdc5756d306034786ff0bd25183b9343c1732fbc","scripts":{"test":"vitest src/__tests__","build":"tsdown","test:watch":"vitest watch src/__tests__","test:coverage":"vitest run --coverage src/__tests__"},"_npmUser":{"name":"leafnote","email":"leafnote@outlook.com"},"_npmVersion":"11.6.2","description":"a request lib alternative to axios with timeout, request reusing, race, response cache ...","directories":{},"_nodeVersion":"25.0.0","_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"tsdown":"^0.21.7","vitest":"^1.3.1","typescript":"^5.4.3","@types/node":"^20.11.30"},"_npmOperationalInternal":{"tmp":"tmp/soon-fetch_4.0.0-beta.5_1775647146545_0.9455730392447412","host":"s3://npm-registry-packages-npm-production"}},"4.0.0":{"name":"soon-fetch","version":"4.0.0","keywords":["request","fetch","lightweight","axios","timeout","request reusing","race","response cache","abort controller"],"author":{"name":"leaf"},"license":"MIT","_id":"soon-fetch@4.0.0","maintainers":[{"name":"leafnote","email":"leafnote@outlook.com"}],"homepage":"https://github.com/leafio/soon-fetch","dist":{"shasum":"ac6dec29f5ec418203757ffb1fb28cdcde94ecb5","tarball":"https://registry.npmjs.org/soon-fetch/-/soon-fetch-4.0.0.tgz","fileCount":7,"integrity":"sha512-49DeHtmMi4G3bt/9Ki09Y9PmXrMxa0leUAp8OAaMK8d8wGWrEbaMVNaxQTgQ0cDF3up94roRy/oKpsQWjhNjgw==","signatures":[{"sig":"MEUCIA+egu+qXbXt0C+/FogOQJ9cLBgsM7HIJHnDcYgmL+dsAiEA5MIv89DgADE0A59XTaczB82IPcMFcv5486rYmIj6Jb4=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":138488},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.mts","unpkg":"./dist/index.iife.js","module":"./dist/index.js","gitHead":"d69260172d74717f1317466e182d2f280e74af9d","scripts":{"test":"vitest src/__tests__","build":"tsdown","test:watch":"vitest watch src/__tests__","test:coverage":"vitest run --coverage src/__tests__"},"_npmUser":{"name":"leafnote","email":"leafnote@outlook.com"},"_npmVersion":"11.6.2","description":"a request lib alternative to axios with timeout, request reusing, race, response cache ...","directories":{},"_nodeVersion":"25.0.0","_hasShrinkwrap":false,"devDependencies":{"tsdown":"^0.21.7","vitest":"^1.3.1","typescript":"^5.4.3","@types/node":"^20.11.30"},"_npmOperationalInternal":{"tmp":"tmp/soon-fetch_4.0.0_1775878172570_0.4065783503562068","host":"s3://npm-registry-packages-npm-production"}},"4.0.1":{"name":"soon-fetch","version":"4.0.1","keywords":["request","fetch","lightweight","axios","timeout","request reusing","race","response cache","abort controller"],"author":{"name":"leaf"},"license":"MIT","_id":"soon-fetch@4.0.1","maintainers":[{"name":"leafnote","email":"leafnote@outlook.com"}],"homepage":"https://github.com/leafio/soon-fetch","dist":{"shasum":"56f06c818754a2835609b3c60bb27fec44e4cb9e","tarball":"https://registry.npmjs.org/soon-fetch/-/soon-fetch-4.0.1.tgz","fileCount":5,"integrity":"sha512-uy60GoA50w+5eXj6VziIykLJrNNCVTJCMSwNP3NvpMGaSAgVNvq615nb86nvoUQAP4yR0lKYqXfD7NF4ViDWUQ==","signatures":[{"sig":"MEQCIDhOVPXRPeHN24mxiV6NmEXoKbmRV3olX4SB4nclD+l7AiApfSakdvfG6+1FxQ2bkrlQ3ic4UEvXQI7DonVuToiqXw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":110430},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","unpkg":"./dist/index.umd.js","module":"./dist/index.js","gitHead":"7b700835cc9777570d152e5d76dea572f897c446","scripts":{"test":"vitest src/__tests__","build":"vite build","test:watch":"vitest watch src/__tests__","test:coverage":"vitest run --coverage src/__tests__"},"_npmUser":{"name":"leafnote","email":"leafnote@outlook.com"},"_npmVersion":"11.6.2","description":"a request lib alternative to axios with timeout, request reusing, race, response cache ...","directories":{},"_nodeVersion":"25.0.0","_hasShrinkwrap":false,"devDependencies":{"vite":"^8.0.0","terser":"^5.37.0","vitest":"^1.3.1","typescript":"^5.4.3","@types/node":"^20.11.30","vite-plugin-dts":"^4.0.0"},"_npmOperationalInternal":{"tmp":"tmp/soon-fetch_4.0.1_1776787997813_0.4638898877794033","host":"s3://npm-registry-packages-npm-production"}},"4.0.2-beta.0":{"name":"soon-fetch","version":"4.0.2-beta.0","keywords":["request","fetch","lightweight","axios","timeout","request reusing","race","response cache","abort controller"],"author":{"name":"leaf"},"license":"MIT","_id":"soon-fetch@4.0.2-beta.0","maintainers":[{"name":"leafnote","email":"leafnote@outlook.com"}],"homepage":"https://github.com/leafio/soon-fetch","dist":{"shasum":"c2e02b0b227653271415a36d79a2203d88266163","tarball":"https://registry.npmjs.org/soon-fetch/-/soon-fetch-4.0.2-beta.0.tgz","fileCount":5,"integrity":"sha512-YswezA+lOOHsUBSQ6QkPhDDdGeZ8B9fddE7Ma3zE+rRn6HQpy9Gr0bSmOf3un0MQ2KSmP9Oxl3w8CzK5+VuiWw==","signatures":[{"sig":"MEUCIQDjkljK0goOAyIj8ABgou0larObg/jp1YfthhmMuFMkygIgcywTVjDJ2+79cIKsZ/bJwiUzWFBoavsqXMZxBggLk0s=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":151988},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","unpkg":"./dist/index.umd.js","module":"./dist/index.js","gitHead":"4b16b5874aeaaa7ff4aa3c637b37eeff13cb40c0","scripts":{"test":"vitest src/__tests__","build":"vite build","test:watch":"vitest watch src/__tests__","test:coverage":"vitest run --coverage src/__tests__"},"_npmUser":{"name":"leafnote","email":"leafnote@outlook.com"},"_npmVersion":"11.6.2","description":"a request lib alternative to axios with timeout, request reusing, race, response cache ...","directories":{},"_nodeVersion":"25.0.0","_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"vite":"^8.0.0","terser":"^5.37.0","vitest":"^1.3.1","typescript":"^5.4.3","@types/node":"^20.11.30","vite-plugin-dts":"^4.0.0"},"_npmOperationalInternal":{"tmp":"tmp/soon-fetch_4.0.2-beta.0_1781299035999_0.047587382017829194","host":"s3://npm-registry-packages-npm-production"}},"4.0.2-beta.1":{"name":"soon-fetch","version":"4.0.2-beta.1","keywords":["request","fetch","lightweight","axios","timeout","request reusing","race","response cache","abort controller"],"author":{"name":"leaf"},"license":"MIT","_id":"soon-fetch@4.0.2-beta.1","maintainers":[{"name":"leafnote","email":"leafnote@outlook.com"}],"homepage":"https://github.com/leafio/soon-fetch","dist":{"shasum":"023cfa90d2239bf590f7f4c651611810e9d094d4","tarball":"https://registry.npmjs.org/soon-fetch/-/soon-fetch-4.0.2-beta.1.tgz","fileCount":5,"integrity":"sha512-dJtla9o37rxNFiB2kTyUbuxTsk7G9UHAtyrq5cidgiJFLSzQOLNFQ0RLXihmBqM2nIojp1IxWCeMVIuPTtLNpA==","signatures":[{"sig":"MEUCIQCPvCgYxn0ovklmc2buo6fFxzwYJCC26Gc1pMC7VS//7AIgV6ESle74vExizWJyvcKCusgPhC8VK6IVNyCmGl6yLLI=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":156194},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","unpkg":"./dist/index.umd.js","module":"./dist/index.js","gitHead":"687cfa2b859322fd81cddfe102955cd44d475712","scripts":{"test":"vitest src/__tests__","build":"vite build","test:watch":"vitest watch src/__tests__","test:coverage":"vitest run --coverage src/__tests__"},"_npmUser":{"name":"leafnote","email":"leafnote@outlook.com"},"_npmVersion":"11.6.2","description":"a request lib alternative to axios with timeout, request reusing, race, response cache ...","directories":{},"_nodeVersion":"25.0.0","_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"vite":"^8.0.0","terser":"^5.37.0","vitest":"^1.3.1","typescript":"^5.4.3","@types/node":"^20.11.30","vite-plugin-dts":"^4.0.0"},"_npmOperationalInternal":{"tmp":"tmp/soon-fetch_4.0.2-beta.1_1781617382859_0.34689181841634253","host":"s3://npm-registry-packages-npm-production"}},"4.1.0":{"name":"soon-fetch","version":"4.1.0","description":"a request lib alternative to axios with timeout, request reusing, race, response cache ...","homepage":"https://github.com/leafio/soon-fetch","type":"module","main":"./dist/index.js","module":"./dist/index.js","types":"./dist/index.d.ts","unpkg":"./dist/index.umd.js","scripts":{"build":"vite build","test":"vitest src/__tests__","test:watch":"vitest watch src/__tests__","test:coverage":"vitest run --coverage src/__tests__"},"keywords":["request","fetch","lightweight","axios","timeout","request reusing","race","response cache","abort controller"],"author":{"name":"leaf"},"license":"MIT","devDependencies":{"@types/node":"^20.11.30","terser":"^5.37.0","typescript":"^5.4.3","vite":"^8.0.0","vite-plugin-dts":"^4.0.0","vitest":"^1.3.1"},"gitHead":"3b79165fdd1db1e2ce0a236f92b27068d6f5b7f6","_id":"soon-fetch@4.1.0","_nodeVersion":"25.0.0","_npmVersion":"11.6.2","dist":{"integrity":"sha512-4ZXNJOVZEdeRJXS7k8/tBvwTrCsZ4KaY1QP5fKGj91heK2r96G99jB4zgVQwZZbRSQXsFq8Oa4ERmSDFz9UTiA==","shasum":"400d391002b6d70005fc137f80a2580666222c8b","tarball":"https://registry.npmjs.org/soon-fetch/-/soon-fetch-4.1.0.tgz","fileCount":5,"unpackedSize":156189,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQDLnOiqyGzIMkRSxIXVpQGxt4gCkIFY7maGCSbspCvwtQIhAO4GwX0N+5XP4ji5gDYGYUXSDQNEPXXP1kV9CiWqrh2/"}]},"_npmUser":{"name":"leafnote","email":"leafnote@outlook.com"},"directories":{},"maintainers":[{"name":"leafnote","email":"leafnote@outlook.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/soon-fetch_4.1.0_1781699728646_0.15886076592751608"},"_hasShrinkwrap":false}},"time":{"created":"2024-08-31T16:36:54.309Z","modified":"2026-06-17T12:35:28.988Z","0.0.1-beta.10":"2024-08-31T16:36:54.497Z","0.0.1-beta.11":"2024-09-01T23:05:06.471Z","0.0.1":"2024-09-02T21:50:24.279Z","0.0.2":"2024-09-05T12:42:56.237Z","0.1.0":"2024-09-25T14:45:31.415Z","1.0.0":"2024-09-28T15:11:37.299Z","1.1.0":"2024-12-02T23:25:17.819Z","2.0.0":"2025-01-02T15:51:45.775Z","2.0.1":"2025-01-03T14:04:24.529Z","2.1.0":"2025-01-14T14:01:47.505Z","2.1.1":"2025-01-17T20:34:10.816Z","3.0.0-beta.1":"2025-06-30T15:01:33.285Z","3.0.0-beta.2":"2025-07-10T17:03:16.940Z","3.0.0-beta.3":"2025-07-13T09:01:09.615Z","3.0.0-beta.4":"2025-07-21T15:50:20.854Z","3.0.0":"2025-07-28T22:25:16.515Z","3.0.1":"2025-07-30T20:50:45.311Z","3.1.0":"2025-08-18T22:55:45.388Z","3.1.1":"2025-08-19T22:27:33.763Z","3.1.2":"2025-09-25T15:09:07.543Z","4.0.0-beta.0":"2026-03-08T15:16:49.526Z","4.0.0-beta.1":"2026-03-10T12:53:17.419Z","4.0.0-beta.2":"2026-03-30T14:28:57.558Z","4.0.0-beta.3":"2026-04-01T13:54:03.809Z","4.0.0-beta.4":"2026-04-07T15:20:20.698Z","4.0.0-beta.5":"2026-04-08T11:19:06.698Z","4.0.0":"2026-04-11T03:29:32.709Z","4.0.1":"2026-04-21T16:13:17.955Z","4.0.2-beta.0":"2026-06-12T21:17:16.152Z","4.0.2-beta.1":"2026-06-16T13:43:03.002Z","4.1.0":"2026-06-17T12:35:28.881Z"},"author":{"name":"leaf"},"license":"MIT","homepage":"https://github.com/leafio/soon-fetch","keywords":["request","fetch","lightweight","axios","timeout","request reusing","race","response cache","abort controller"],"description":"a request lib alternative to axios with timeout, request reusing, race, response cache ...","maintainers":[{"name":"leafnote","email":"leafnote@outlook.com"}],"readme":"[English](#soon-fetch) | [中文](#soon-fetch-1) | [Installation](#安装-installation)\n\n<!-- omit in toc -->\n\n### soon-fetch\n\n**A lightweight http request lib , alternative to axios with timeout, request reusing, race, response cache ...**\n\n> - 🌐 automatic parse restful api url parameters\n> - ⭐ rapid define a request api\n> - 🎯 fork sub-instance with prefix and default options\n> - ⌛ timeout disconnect\n> - 📦 request reusing\n> - 🚀 request race\n> - 📝 response cache\n> - 🔤 automatic serialization of JSON\n> - 📏 .min size less than **10K**, smaller after zip\n> - 💡 smart type tips with Typescript\n\n- [Example](#example)\n- [Features](#features)\n  - [Shortcut](#shortcut)\n  - [Restful Url Params](#restful-url-params)\n  - [Timeout](#timeout)\n  - [Share pending request](#share-pending-request)\n  - [Response cache](#response-cache)\n  - [Request race](#request-race)\n  - [Rapid Define APIs](#rapid-define-apis)\n- [API](#api)\n\n### Example\n\n> [github: soon-admin-vue3 ](https://github.com/leafio/soon-admin-vue3)  \n> [github: soon-admin-react-nextjs ](https://github.com/leafio/soon-admin-react-nextjs)\n\n```typescript\nimport { createSoon, soonFetch } from \"soon-fetch\";\n\n// 使用 soonFetch 作为基础请求函数\nconst request = async <T>(url: string, options?: SoonOptions): Promise<T> => {\n  const isGet = !options?.method || options?.method.toLocaleLowerCase() === \"get\";\n  const response = await soonFetch({\n    url,\n    options,\n    baseURL: '/api',\n    baseOptions: {\n      timeout: 20 * 1000,\n      headers: new Headers({\n        Authorization: \"Bearer \" + localStorage.getItem(\"token\"),\n      }),\n      share: isGet ? true : false,\n      staleTime: isGet ? 2 * 1000 : 0,\n    },\n  });\n  \n  if (!response.ok) {\n    throw new Error(`HTTP ${response.status}: ${response.statusText}`);\n  }\n  \n  return response.json() as Promise<T>;\n};\n\nconst soon = createSoon(request);\n\n/** GET */\nsoon.get(\"/user?id=123\");\nsoon.get(\"/user\", { query: { id: 123 } });\nsoon.get(\"/user/:id\", { params: { id: 123 } });\n\n/** POST */\nsoon.post(\"/login\", { body: { username: \"admin\", password: \"123456\" } });\n\n/**Define API */\nexport const login = soon\n  .POST(\"/user/login\")\n  .Body<{ username: string; password: string }>()\n  .Ok<{ token: string }>();\n//the develop tools will have type tips for request and response\nlogin({ username: \"admin\", password: \"123\" }).then((res) => {\n  localStorage.setItem(\"token\", res.token);\n});\n```\n\n### Features\n\n##### Shortcut\n\n```typescript\nsoon.get(url, options);\nsoon.post(url, options);\nsoon.put(url, options);\nsoon.patch(url, options);\nsoon.delete(url, options);\nsoon.head(url, options);\nsoon.options(url, options);\n```\n\n##### Restful Url Params\n\nurl like /:key , will handle the key\n\n```typescript\nsoon.get(\"/api/user/:id\", { params: { id: 1 } });\n// api/user/1\nsoon.get(\"/api/:job/:year\", { params: { job: \"engineer\", year: 5 } });\n//api/engineer/5\n```\n\n##### Timeout\n\n```typescript\n//** the request level timeout, will override the instance level timeout  */\nsoon.get(url, { timeout: 1000 * 20 });\n```\n\n##### Share pending request\n\nIf a request is made again before the first completes, will reuse the first request instead of making a new request.\n\n```ts\nsoon.get(url, { share: true });\n```\n\n##### Response cache\n\nA cached response will be returned if the request is made again within the specified time.\n\n```ts\nsoon.get(url, { staleTime: 1000 * 60 * 5 });\n```\n\n##### Request race\n\n‌If a second request is made before the first completes, abort the first to avoid race conditions from out-of-order responses.\n\n```tsx\nimport { useEffect, useRef, useState } from \"react\";\n\ntype User = { name: string; job: string };\nconst api = soon.GET(\"/api/users\").Query<{ page: number }>().Ok<User[]>();\nexport default function App() {\n  const refAbort = useRef<[AbortController] | []>([]);\n  const [list, setList] = useState<User[]>([]);\n  const [page, setPage] = useState(1);\n  useEffect(() => {\n    api({ page }, { aborts: refAbort.current })\n      .then(setList)\n      .catch(console.log);\n  }, [page]);\n  return (\n    <div>\n      <button onClick={() => setPage((pre) => pre + 1)}>next</button>\n      <div>\n        {list.map((item) => (\n          <div key={item.name}>{item.name}</div>\n        ))}\n      </div>\n    </div>\n  );\n}\n```\n\n##### Rapid Define APIs\n\n```ts\n  //可以是 GET POST PATCH PUT DELETE\n  //GET 请求数据传递至query,其他方法请求数据传递至body\n  soon.GET(url:string).Query<Query>().Ok<Response>()\n  soon.POST(url:string).Body<Body>().Ok<Response>()\n  soon.GET(url:string).Options({ timeout: 5000 }).Ok<Response>()\n  soon.POST(url:string).Body<Body>().Options({ timeout: 5000 }).Ok<Response>()\n\n  //define an api\nexport const getUserInfo = soon.GET(\"/user/:id\").Ok();\n//then use in any where\ngetUserInfo({ id: 2 }).then((res) => console.log(res));\n//define an api with options\nexport const getUserInfoWithOptions = soon.GET(\"/user/:id\").Options({ timeout: 5000 }).Ok();\n//then use in any where\ngetUserInfoWithOptions({ id: 2 }).then((res) => console.log(res));\n\n//with typescript,\nexport const login = soon\n  .POST(\"/user/login\")\n  .Body<{ username: string; password: string }>()\n  .Ok<{ token: string }>();\n//the develop tools will have type tips for request and response\nlogin({ username: \"admin\", password: \"123\" }).then((res) => {\n  localStorage.setItem(\"token\", res.token);\n});\n\n//with Params for type safety\nexport const getUserById = soon.GET(\"/user/:id\").Params<{ id: number }>().Ok<{ id: number; name: string }>();\ngetUserById({ id: 1 }).then((res) => console.log(res));\n```\n\n### API\n\n#### SoonOptions\n\n```ts\n// function fetch(input: RequestInfo | URL, init?: RequestInit): Promise<Response>\n// RequestInit  is fetch's init options\ntype SoonOptions = Omit<RequestInit, \"body\"> & {\n  body?: RequestInit[\"body\"] | object;\n  query?:\n    | Record<\n        string,\n        | string\n        | number\n        | boolean\n        | null\n        | undefined\n        | (string | number | boolean | null | undefined)[]\n      >\n    | URLSearchParams;\n  params?: Record<string, string | number>;\n  timeout?: number;\n  aborts?: AbortController[] | never[];\n  share?: boolean;\n  staleTime?: number;\n};\n```\n\n#### createSoon\n\nCreate a soon request instance.\n\n**Parameters:**\n\n- `request`: A function to handle the actual request, receives url and options, returns a Promise\n\n**Returns:** An object containing request method, API methods (GET, POST, PUT, DELETE, PATCH), shortcut methods (get, post, put, delete, patch, head, options), and fork method for creating sub-instances\n\n**Example:**\n\n```typescript\nimport { createSoon, soonFetch } from \"soon-fetch\";\n\n// Define custom request wrapper with business logic\nconst request = async <T>(url: string, options?: SoonOptions): Promise<T> => {\n  const isGet = !options?.method || options?.method.toLowerCase() === \"get\";\n  \n  const response = await soonFetch({\n    url,\n    options,\n    baseURL: '/api',\n    baseOptions: {\n      timeout: 20 * 1000,\n      headers: new Headers({\n        Authorization: \"Bearer \" + localStorage.getItem(\"token\"),\n      }),\n      share: isGet,\n      staleTime: isGet ? 2 * 1000 : 0,\n    },\n  });\n  \n  if (!response.ok) {\n    throw new Error(`HTTP ${response.status}: ${response.statusText}`);\n  }\n  \n  return response.json() as Promise<T>;\n};\n\n// Create soon instance\nconst soon = createSoon(request);\n\n// Usage 1: Shortcut methods with generics\nconst users = await soon.get<{ id: number; name: string }[]>(\"/api/users\");\n\n// Usage 2: Define typed APIs with chain calls\nexport const getUserById = soon\n  .GET(\"/user/:id\")\n  .Params<{ id: number }>()\n  .Ok<{ id: number; name: string }>();\n\nexport const createUser = soon\n  .POST(\"/user\")\n  .Body<{ name: string; email: string }>()\n  .Ok<{ id: number }>();\n\n// Usage 3: Use defined APIs\nconst user = await getUserById({ id: 1 });\nconst newUser = await createUser({ name: \"John\", email: \"john@example.com\" });\n```\n\n#### fork\n\nCreate a sub-instance with a URL prefix and default options.\n\n**Parameters:**\n\n- `prefix`: URL prefix string (e.g. \"/api/v1\")\n- `defaultOptions?`: Default options that apply to all requests via this sub-instance\n\n**Returns:** A new `createSoon` instance with the prefix and default options pre-applied.\n\n**Example:**\n\n```typescript\n// Create a forked sub-instance for a specific API version\nconst v1 = soon.fork(\"/api/v1\", { timeout: 5000 });\nconst v2 = soon.fork(\"/api/v2\", { timeout: 10000 });\n\n// All requests are automatically prefixed and use default options\nv1.get(\"/users\");            // GET /api/v1/users with timeout: 5000\nv2.get(\"/users\");            // GET /api/v2/users with timeout: 10000\n\n// Options can still be overridden per request\nv1.get(\"/users\", { timeout: 8000 });  // GET /api/v1/users with timeout: 8000\n\n// Chain API definitions work too\nconst getUser = v1.GET(\"/users/:id\").Params<{ id: number }>().Ok<User>();\ngetUser({ id: 1 });  // GET /api/v1/users/1 with timeout: 5000\n\n// Fork can be nested\nconst admin = v1.fork(\"/admin\");\nadmin.get(\"/stats\");  // GET /api/v1/admin/stats with timeout: 5000\n\n// Absolute URLs bypass the prefix\nv1.get(\"https://other-api.com/data\");  // Uses the absolute URL directly\n```\n\n#### createShortApi\n\nFactory function to create API shortcut methods.\nUsed to generate type-safe API calling methods, supporting path parameters, query parameters, and request body.\n\n**Parameters:**\n\n- `wrapper`: Wrapper function to handle actual request logic\n\n**Returns:** An object containing GET, POST, PUT, DELETE, PATCH and other methods, each method supports chain calling\n\n**Example:**\n\n```typescript\nconst API = createShortApi(\n  async <T>(url: string, method: string, params: Record<string, string | number> | undefined, query: any, body: any, options: any): Promise<T> => {\n    // Handle request logic\n    const { url: _url } = parseUrl(url, { params, query });\n    const response = await fetch(_url, { ...options, method, body });\n    return response.json();\n  }\n);\n\n// Usage example\nconst getUser = API.GET(\"/api/users/:id\").Ok<{ id: number; name: string }>();\nconst userData = await getUser({ id: 1 });\n\n// With Params for type safety\nconst getUserById = API.GET(\"/api/users/:id\").Params<{ id: number }>().Ok<{ id: number; name: string }>();\nconst userData = await getUserById({ id: 1 });\n```\n\n#### createShortMethods\n\nFactory function to create shortcut methods.\n\n**Parameters:**\n\n- `methods`: HTTP methods array\n- `wrapper`: Wrapper function that receives method name and returns a function to process requests\n\n**Returns:** Shortcut call object containing specified methods\n\n**Example:**\n\n```typescript\nconst methods = createShortMethods([\"get\", \"post\"] as const, (method) => {\n  return async <T>(url: string, options?: SoonOptions): Promise<T> => {\n    const response = await fetch(url, { ...options, method });\n    return response.json();\n  };\n});\n// Usage: methods.get<{ id: number; name: string }[]>('/api/users')\n```\n\n#### parseOptions\n\nParse URL options.\n\n**Parameters:**\n\n- `urlOptions`: Object containing url, options, baseURL and baseOptions\n\n**Returns:** Object containing parsed url, options, is_body_json, and abortController\n\n**Example:**\n\n```typescript\nconst parsed = parseOptions({\n  url: \"/api/users/:id\",\n  options: { params: { id: \"123\" } },\n  baseURL: \"https://api.example.com\",\n});\n// Returns: { url: 'https://api.example.com/api/users/123', options: {...}, is_body_json: false, abortController: AbortController }\n```\n\n#### mergeHeaders\n\nMerge multiple Headers objects.\n\n**Parameters:**\n\n- `headersList`: List of Headers objects to merge\n\n**Returns:** Merged Headers object, later ones will overwrite earlier ones with the same name\n\n**Example:**\n\n```typescript\nconst headers1: HeadersInit = { \"Content-Type\": \"application/json\" };\nconst headers2: HeadersInit = { Authorization: \"Bearer token\" };\nconst mergedHeaders = mergeHeaders(headers1, headers2);\n```\n\n#### mergeSignals\n\nMerge multiple AbortSignal signals.\n\n**Parameters:**\n\n- `signals`: Array of AbortSignals to merge\n- `timeout`: Optional timeout time (milliseconds)\n\n**Returns:** Merged AbortSignal, any signal termination will trigger termination\n\n**Example:**\n\n```typescript\nconst controller1 = new AbortController();\nconst controller2 = new AbortController();\nconst mergedSignal = mergeSignals(\n  [controller1.signal, controller2.signal],\n  5000\n);\n```\n\n#### parseUrl\n\nMerge URL and its related parameters.\nHandle baseURL, path parameters and query parameters to generate complete URL.\n\n**Parameters:**\n\n- `url`: Original URL\n- `config`: Configuration object, including query parameters, path parameters and base URL\n\n**Returns:** Object containing `url` (complete URL string), `path` (URL without query string), and `query` (URLSearchParams instance)\n\n**Example:**\n\n```typescript\nconst { url } = parseUrl(\"/api/users/:id\", {\n  params: { id: \"123\" },\n  query: { filter: \"active\" },\n  baseURL: \"https://api.example.com\",\n});\n// Returns: 'https://api.example.com/api/users/123?filter=active'\n```\n\n#### parseQuery2Arr\n\nParse query parameters into a `[key, value][]` array.\nSupports multiple input formats: string, URLSearchParams, Record, and array-of-tuples.\n\n**Parameters:**\n\n- `query`: Query parameters in any supported format (string, URLSearchParams, Record, array-of-tuples)\n\n**Returns:** Array of `[key, value]` pairs\n\n**Example:**\n\n```typescript\nparseQuery2Arr(\"page=1&size=10\");\n// Returns: [[\"page\", \"1\"], [\"size\", \"10\"]]\n\nparseQuery2Arr({ id: 123, status: \"active\" });\n// Returns: [[\"id\", \"123\"], [\"status\", \"active\"]]\n\nparseQuery2Arr(new URLSearchParams(\"page=1\"));\n// Returns: [[\"page\", \"1\"]]\n```\n\n#### mergeOptions\n\nMerge multiple option objects.\nMerge request options, including special handling of headers and signals.\n\n**Parameters:**\n\n- `optionsList`: List of option objects to merge\n\n**Returns:** Merged option object\n\n**Example:**\n\n```typescript\nconst defaultOptions = {\n  timeout: 5000,\n  headers: { \"Content-Type\": \"application/json\" },\n};\nconst requestOptions = {\n  method: \"POST\",\n  body: JSON.stringify({ name: \"John\" }),\n};\nconst mergedOptions = mergeOptions(defaultOptions, requestOptions);\n```\n\n#### isBodyJson\n\nDetermine if the request body is a JSON object.\nCheck if body is a plain object, not special types like FormData or Blob.\n\n**Parameters:**\n\n- `body`: Request body\n\n**Returns:** Returns true if it is a JSON object, otherwise false\n\n**Example:**\n\n```typescript\nisBodyJson({ name: \"John\" }); // true\nisBodyJson(new FormData()); // false\nisBodyJson(\"string\"); // false\n```\n\n#### genRequestKey\n\nGenerate a unique identification key for the request (sync).\nGenerate a unique key value based on the request's URL, method, headers, query parameters, etc., used for caching and request sharing.\n\n> **Note:** This is the synchronous version. For body types like `Blob`/`FormData` that require async processing (e.g., SHA-256 digest), it falls back to a non-deterministic key (nonce-based) to avoid blocking. Use `genRequestKeyAsync` for fully deterministic key generation.\n> **Note:** The SHA-256 digest used by `genRequestKeyAsync` requires a [secure context](https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts) (HTTPS). Under plain HTTP, `crypto.subtle.digest` is unavailable, and `genRequestKeyAsync` will fall back to a non-deterministic key for `Blob`/`ArrayBuffer`/`DataView` bodies, preventing incorrect cache hits or request sharing.\n\n**Parameters:**\n\n- `req`: Request object containing url and options\n- `sortObjKeys?`: Whether to sort object keys for stable serialization\n\n**Returns:** The unique identification string of the request\n\n**Example:**\n\n```typescript\nconst key = genRequestKey({\n  url: \"/api/users\",\n  options: { method: \"GET\", params: { id: 1 } },\n});\n```\n\n#### genRequestKeyAsync\n\nGenerate a unique identification key for the request (async).\nSame as `genRequestKey`, but supports async digest of `Blob`/`FormData` bodies for fully deterministic key generation.\n\n**Parameters:**\n\n- `req`: Request object containing url and options\n- `sortObjKeys?`: Whether to sort object keys for stable serialization\n\n**Returns:** Promise resolving to the unique identification string of the request\n\n**Example:**\n\n```typescript\nconst key = await genRequestKeyAsync({\n  url: \"/api/users\",\n  options: { method: \"GET\", params: { id: 1 } },\n});\n```\n\n#### createRequestStore\n\nCreate request store instance.\nProvides request caching, sharing, and race condition handling.\n\n**Parameters:**\n\n- `options`: Configuration options\n  - `maxCacheSize`: Maximum cache size (default: 100000)\n\n**Returns:** Request store object with the following methods:\n- `entry(key)`: Get entry for specific request key\n- `dispose()`: Dispose the store and clear intervals\n- `get(key)`: Get request by key\n- `set(key, value)`: Set request by key\n- `remove(key)`: Remove request by key\n- `getAll()`: Get all requests\n- `removeAll()`: Remove all requests\n- `clearCache()`: Clear all cache\n- `clearExpiredCache()`: Clear expired cache\n- `abortAll()`: Abort all requests\n\n**Example:**\n\n```typescript\nconst store = createRequestStore({ maxCacheSize: 1000 });\n// Use store in requests\n```\n\n#### deepSort\n\nDeep sort object keys.\nRecursively sort the keys of an object to generate a stable object serialization result.\n\n**Parameters:**\n\n- `obj`: Object to sort\n- `sortArr`: Whether to sort arrays (default: false)\n\n**Returns:** Object with sorted keys\n\n**Example:**\n\n```typescript\nconst obj = { b: 2, a: 1, c: { z: 3, y: 2 } };\nconst sorted = deepSort(obj);\n// Returns: { a: 1, b: 2, c: { y: 2, z: 3 } }\n```\n\n#### createSilentRefresh\n\nCreate silent refresh instance.\nUsed to handle silent refresh functionality when token expires.\n\n**Parameters:**\n\n- `refresh_token_fn`: Function to refresh token\n\n**Returns:** Function that accepts success and failure callbacks\n\n**Example:**\n\n```typescript\nconst silentRefresh = createSilentRefresh(async () => {\n  // Refresh token logic\n  await refreshToken();\n});\n\n// Usage example\nsilentRefresh(\n  () => console.log(\"Refresh successful\"),\n  () => console.log(\"Refresh failed\")\n);\n```\n\n#### soonFetch\n\nA lightweight fetch wrapper with caching, sharing, and race condition handling.\n\n**Parameters:**\n\n- `config`: Configuration object\n  - `url`: Request URL\n  - `options`: Request options (SoonOptions)\n  - `baseURL`: Base URL\n  - `baseOptions`: Base request options\n  - `store`: Custom request store\n  - `sortRequestKey`: Whether to sort request key\n\n**Returns:** Promise that resolves to Response\n\n**Example:**\n\n```typescript\nconst response = await soonFetch({\n  url: \"/api/users\",\n  options: {\n    method: \"GET\",\n    query: { page: 1 },\n    share: true,\n    staleTime: 5000,\n  },\n  baseURL: \"https://api.example.com\",\n});\n\nif (!response.ok) {\n  throw new Error(`HTTP ${response.status}: ${response.statusText}`);\n}\n\nconst data = await response.json() as User[];\n```\n\n#### toFormData\n\nConvert object to FormData.\nUsed to convert plain objects to FormData format, supports files and regular values.\n\n**Parameters:**\n\n- `body`: Object to convert\n\n**Returns:** Converted FormData object\n\n**Example:**\n\n```typescript\nconst formData = toFormData({\n  name: \"John\",\n  avatar: fileBlob,\n  age: 30,\n});\n```\n\n#### progressDownload\n\nDownload with progress tracking.\nUsed to download files with progress updates.\n\n**Parameters:**\n\n- `response`: Response object\n- `onProgress`: Progress callback function\n\n**Returns:** Promise that resolves to ArrayBuffer\n\n**Example:**\n\n```typescript\nconst response = await fetch(\"/api/download\");\nconst buffer = await progressDownload(response, (progress, downloaded, total) => {\n  console.log(`Progress: ${progress}%, Downloaded: ${downloaded}/${total}`);\n});\n```\n\n#### progressReadBody\n\nRead response body with progress tracking.\nUsed to read response bodies with progress updates.\n\n**Parameters:**\n\n- `body`: ReadableStream<Uint8Array>\n- `onProgress`: Progress callback function\n- `total`: Total size in bytes (default: 0)\n\n**Returns:** Promise that resolves to ArrayBuffer\n\n**Example:**\n\n```typescript\nconst response = await fetch(\"/api/download\");\nconst buffer = await progressReadBody(response.body!, (progress, downloaded, total) => {\n  console.log(`Progress: ${progress}%, Downloaded: ${downloaded}/${total}`);\n});\n```\n\n#### requestWithStore\n\nRequest wrapper with store support.\nUsed to handle requests with caching, sharing, and race condition handling.\n\n**Parameters:**\n\n- `store`: Request store instance\n- `requestFn`: Request function\n- `requestKey`: Request key\n- `fetchAbort`: AbortController\n- `options`: Options object\n\n**Returns:** Promise that resolves to the response\n\n**Example:**\n\n```typescript\nconst store = createRequestStore();\nconst data = await requestWithStore(store, () => fetch(url, options), requestKey, abortController, {\n  share: true,\n  staleTime: 5000,\n});\n```\n\n[English](#soon-fetch) | [中文](#soon-fetch-1) | [Installation](#安装-installation)\n\n<!-- omit in toc -->\n\n#### soon-fetch\n\n**极轻量的请求库，不到 10K**\n\n> - 🌐 自动解析 rest Url 的参数\n> - ⭐ 快捷定义请求 api\n> - 🎯 fork 子实例（前缀+默认选项）\n> - ⌛ 超时断开\n> - 📦 请求复用\n> - 🚀 请求竞态\n> - 📝 响应缓存\n> - 🔤 自动处理 JSON\n> - 📏 不到 **10K** , zip 后会更小\n> - 💡 用 typescript 有智能类型提醒\n\n- [示例](#示例)\n\n- [特别功能](#特别功能)\n\n  - [快捷方法](#快捷方法)\n  - [Restful Url 参数自动处理](#restful-url-参数自动处理)\n  - [共享未完成的请求](#共享未完成的请求)\n  - [超时](#超时)\n  - [响应缓存](#响应缓存)\n  - [请求竞态](#请求竞态)\n  - [快速定义 API](#快速定义-api)\n\n- [API](#api-1)\n\n### 示例\n\n> [github: soon-admin-vue3 ](https://github.com/leafio/soon-admin-vue3)  \n> [github: soon-admin-react-nextjs ](https://github.com/leafio/soon-admin-react-nextjs)\n\n```typescript\nimport { createSoon, soonFetch } from \"soon-fetch\";\n\n// 使用 soonFetch 作为基础请求函数\nconst request = async <T>(url: string, options?: SoonOptions): Promise<T> => {\n  const isGet = !options?.method || options?.method.toLocaleLowerCase() === \"get\";\n  const response = await soonFetch({\n    url,\n    options,\n    baseURL: '/api',\n    baseOptions: {\n      timeout: 20 * 1000,\n      headers: new Headers({\n        Authorization: \"Bearer \" + localStorage.getItem(\"token\"),\n      }),\n      share: isGet ? true : false,\n      staleTime: isGet ? 2 * 1000 : 0,\n    },\n  });\n  \n  if (!response.ok) {\n    throw new Error(`HTTP ${response.status}: ${response.statusText}`);\n  }\n  \n  return response.json() as Promise<T>;\n};\n\nconst soon = createSoon(request);\n\n/** GET */\nsoon.get(\"/user?id=123\");\nsoon.get(\"/user\", { query: { id: 123 } });\nsoon.get(\"/user/:id\", { params: { id: 123 } });\n\n/** POST */\nsoon.post(\"/login\", { body: { username: \"admin\", password: \"123456\" } });\n\n/**定义 API */\nexport const login = soon\n  .POST(\"/user/login\")\n  .Body<{ username: string; password: string }>()\n  .Ok<{ token: string }>();\n\n//开发工具会有请求和响应的智能提醒\nlogin({ username: \"admin\", password: \"123\" }).then((res) => {\n  localStorage.setItem(\"token\", res.token);\n});\n\n//使用 Params 进行类型安全定义\nexport const getUserById = soon.GET(\"/user/:id\").Params<{ id: number }>().Ok<{ id: number; name: string }>();\ngetUserById({ id: 1 }).then((res) => console.log(res));\n```\n\n### 特别功能\n\n##### 快捷方法\n\n```typescript\nsoon.get(url, options);\nsoon.post(url, options);\nsoon.put(url, options);\nsoon.patch(url, options);\nsoon.delete(url, options);\nsoon.head(url, options);\nsoon.options(url, options);\n```\n\n###### Restful Url 参数自动处理\n\nurl 包含 /:key 会解析匹配 key\n\n```typescript\nsoon.get(\"/api/user/:id\", { params: { id: 1 } });\n// api/user/1\nsoon.get(\"/api/:job/:year\", { params: { job: \"engineer\", year: 5 } });\n//api/engineer/5\n```\n\n##### 超时\n\n```typescript\n//** 请求级超时, 会覆盖实例级超时  */\nsoon.get(url, { timeout: 1000 * 20 });\n```\n\n##### 共享未完成的请求\n\n如果在第一个请求完成之前再次发起相同的请求，则会复用第一个请求，而不是发起新的请求。\n\n```ts\nsoon.get(url, { share: true });\n```\n\n##### 响应缓存\n\n如果在指定时间内再次发起相同的请求，则会返回缓存的响应。\n\n```ts\nsoon.get(url, { staleTime: 1000 * 60 * 5 });\n```\n\n##### 请求竞态\n\n如果在第一个请求完成之前发起第二个请求，则会中止第一个请求，以避免因响应顺序错乱导致的问题。\n\n```tsx\nimport { useEffect, useRef, useState } from \"react\";\n\ntype User = { name: string; job: string };\nconst api = soon.GET(\"/api/users\").Query<{ page: number }>().Ok<User[]>();\nexport default function App() {\n  const refAbort = useRef<[AbortController] | []>([]);\n  const [list, setList] = useState<User[]>([]);\n  const [page, setPage] = useState(1);\n  useEffect(() => {\n    api({ page }, { aborts: refAbort.current })\n      .then(setList)\n      .catch(console.log);\n  }, [page]);\n  return (\n    <div>\n      <button onClick={() => setPage((pre) => pre + 1)}>next</button>\n      <div>\n        {list.map((item) => (\n          <div key={item.name}>{item.name}</div>\n        ))}\n      </div>\n    </div>\n  );\n}\n```\n\n##### 快速定义 API\n\n```ts\n  //可以是 GET POST PATCH PUT DELETE\n  //GET 请求数据传递至query,其他方法请求数据传递至body\n  soon.GET(url:string).Query<Query>().Ok<Response>()\n  soon.POST(url:string).Body<Body>().Ok<Response>()\n  soon.GET(url:string).Options({ timeout: 5000 }).Ok<Response>()\n  soon.POST(url:string).Body<Body>().Options({ timeout: 5000 }).Ok<Response>()\n\n  //定义一个api\n export const getUserInfo=soon.GET('/user/:id').Ok()\n  //使用\n  getUserInfo({id:2}).then(res=>console.log(res))\n  //定义一个带选项的api\n export const getUserInfoWithOptions=soon.GET('/user/:id').Options({ timeout: 5000 }).Ok()\n  //使用\n  getUserInfoWithOptions({id:2}).then(res=>console.log(res))\n\n  //用typescript,\n export const login=soon\n  .POST('/user/login')\n  .Body<{username:string,password:string}>()\n  .Ok<{token:string}>()\n //开发工具会有请求和响应的智能提醒\n  login({username:'admin',password:'123'}).then(res=>{\n    localStorage.setItem('token', res.token);\n  })\n\n  //使用 Params 进行类型安全定义\n  export const getUserById = soon.GET('/user/:id').Params<{ id: number }>().Ok<{ id: number; name: string }>();\n  getUserById({ id: 1 }).then(res => console.log(res));\n```\n\n### API\n\n#### SoonOptions\n\n```ts\n// function fetch(input: RequestInfo | URL, init?: RequestInit): Promise<Response>\n// RequestInit  为原生 fetch 的 init 选项\ntype SoonOptions = Omit<RequestInit, \"body\"> & {\n  body?: RequestInit[\"body\"] | object;\n  query?:\n    | Record<\n        string,\n        | string\n        | number\n        | boolean\n        | null\n        | undefined\n        | (string | number | boolean | null | undefined)[]\n      >\n    | URLSearchParams;\n  params?: Record<string, string | number>;\n  timeout?: number;\n  aborts?: AbortController[] | never[];\n  share?: boolean;\n  staleTime?: number;\n};\n```\n\n#### createSoon\n\n创建一个 soon 请求实例。\n\n**参数:**\n\n- `request`: 用于处理实际请求的函数，接收 url 和 options，返回一个 Promise\n\n**返回:** 包含 request 方法、API 方法（GET、POST、PUT、DELETE、PATCH）和快捷方法（get、post、put、delete、patch、head、options）以及 fork 方法的对象\n\n**示例:**\n\n```typescript\nconst soon = createSoon(\n  async (url, options) => {\n    const response = await fetch(url, options);\n    return response.json();\n  }\n);\n\n// 使用示例\nconst data = await soon.get(\"/api/users\");\n\n// 定义带选项的 API\nexport const login = soon\n  .POST(\"/user/login\")\n  .Body<{ username: string; password: string }>()\n  .Ok<{ token: string }>();\n\nlogin({ username: \"admin\", password: \"123\" }).then((res) => {\n  localStorage.setItem(\"token\", res.token);\n});\n```\n\n#### fork\n\n创建一个带有 URL 前缀和默认选项的子实例。\n\n**参数:**\n\n- `prefix`: URL 前缀字符串（如 \"/api/v1\"）\n- `defaultOptions?`: 默认选项，对该子实例的所有请求生效\n\n**返回:** 一个新的 `createSoon` 实例，已预置前缀和默认选项。\n\n**示例:**\n\n```typescript\n// 为不同 API 版本创建 fork 子实例\nconst v1 = soon.fork(\"/api/v1\", { timeout: 5000 });\nconst v2 = soon.fork(\"/api/v2\", { timeout: 10000 });\n\n// 所有请求会自动添加前缀并使用默认选项\nv1.get(\"/users\");            // GET /api/v1/users with timeout: 5000\nv2.get(\"/users\");            // GET /api/v2/users with timeout: 10000\n\n// 单次请求仍可覆盖默认选项\nv1.get(\"/users\", { timeout: 8000 });  // GET /api/v1/users with timeout: 8000\n\n// 链式 API 定义同样适用\nconst getUser = v1.GET(\"/users/:id\").Params<{ id: number }>().Ok<User>();\ngetUser({ id: 1 });  // GET /api/v1/users/1 with timeout: 5000\n\n// fork 支持嵌套\nconst admin = v1.fork(\"/admin\");\nadmin.get(\"/stats\");  // GET /api/v1/admin/stats with timeout: 5000\n\n// 绝对 URL 会绕过前缀\nv1.get(\"https://other-api.com/data\");  // 直接使用该 URL\n```\n\n#### createShortApi\n\n创建 API 快捷方法的工厂函数。\n用于生成类型安全的 API 调用方法，支持路径参数、查询参数和请求体。\n\n**参数:**\n\n- `wrapper`: 包装函数，用于处理实际的请求逻辑\n\n**返回:** 包含 GET、POST、PUT、DELETE、PATCH 等方法的对象，每个方法都支持链式调用\n\n**示例:**\n\n```typescript\nconst API = createShortApi(\n  async (url, method, params, query, body, options) => {\n    // 处理请求逻辑\n    const { url: _url } = parseUrl(url, { params, query });\n    const response = await fetch(_url, { ...options, method, body });\n    return response.json();\n  }\n);\n\n// 使用示例\nconst getUser = API.GET(\"/api/users/:id\").Ok();\nconst userData = await getUser({ id: 1 });\n\n// 使用 Params 进行类型安全定义\nconst getUserById = API.GET(\"/api/users/:id\").Params<{ id: number }>().Ok<{ id: number; name: string }>();\nconst userData = await getUserById({ id: 1 });\n```\n\n#### createShortMethods\n\n创建快捷方法的工厂函数。\n\n**参数:**\n\n- `methods`: HTTP 方法数组\n- `wrapper`: 包装函数，接收方法名，返回处理请求的函数\n\n**返回:** 包含指定方法的快捷调用对象\n\n**示例:**\n\n```typescript\nconst methods = createShortMethods([\"get\", \"post\"] as const, (method) => {\n  return (url, options) => fetch(url, { ...options, method });\n});\n// 使用: methods.get('/api/users')\n```\n\n#### parseOptions\n\n解析 URL 选项。\n\n**参数:**\n\n- `urlOptions`: 包含 url、options、baseURL 和 baseOptions 的对象\n\n**返回:** 包含解析后的 url、options、is_body_json 和 abortController 的对象\n\n**示例:**\n\n```typescript\nconst parsed = parseOptions({\n  url: \"/api/users/:id\",\n  options: { params: { id: \"123\" } },\n  baseURL: \"https://api.example.com\",\n});\n// 返回: { url: 'https://api.example.com/api/users/123', options: {...}, is_body_json: false, abortController: AbortController }\n```\n\n#### mergeHeaders\n\n合并多个 Headers 对象。\n\n**参数:**\n\n- `headersList`: 要合并的 Headers 对象列表\n\n**返回:** 合并后的 Headers 对象，后面的会覆盖前面的同名 header\n\n**示例:**\n\n```typescript\nconst headers1: HeadersInit = { \"Content-Type\": \"application/json\" };\nconst headers2: HeadersInit = { Authorization: \"Bearer token\" };\nconst mergedHeaders = mergeHeaders(headers1, headers2);\n```\n\n#### mergeSignals\n\n合并多个 AbortSignal 信号。\n\n**参数:**\n\n- `signals`: 要合并的 AbortSignal 数组\n- `timeout`: 可选的超时时间（毫秒）\n\n**返回:** 合并后的 AbortSignal，任意一个信号终止都会触发终止\n\n**示例:**\n\n```typescript\nconst controller1 = new AbortController();\nconst controller2 = new AbortController();\nconst mergedSignal = mergeSignals(\n  [controller1.signal, controller2.signal],\n  5000\n);\n```\n\n#### parseUrl\n\n合并 URL 及其相关参数。\n处理 baseURL、路径参数和查询参数，生成完整 URL。\n\n**参数:**\n\n- `url`: 原始 URL\n- `config`: 配置对象，包含查询参数、路径参数和基础 URL\n\n**返回:** 包含 `url`（完整 URL 字符串）、`path`（不含查询参数的 URL）和 `query`（URLSearchParams 实例）的对象\n\n**示例:**\n\n```typescript\nconst { url } = parseUrl(\"/api/users/:id\", {\n  params: { id: \"123\" },\n  query: { filter: \"active\" },\n  baseURL: \"https://api.example.com\",\n});\n// url: 'https://api.example.com/api/users/123?filter=active'\n```\n\n#### parseQuery2Arr\n\n将查询参数解析为 `[key, value][]` 数组。\n支持多种输入格式：string、URLSearchParams、Record 和元组数组。\n\n**参数:**\n\n- `query`: 任意支持的查询参数格式（string、URLSearchParams、Record、元组数组）\n\n**返回:** `[key, value]` 键值对数组\n\n**示例:**\n\n```typescript\nparseQuery2Arr(\"page=1&size=10\");\n// 返回: [[\"page\", \"1\"], [\"size\", \"10\"]]\n\nparseQuery2Arr({ id: 123, status: \"active\" });\n// 返回: [[\"id\", \"123\"], [\"status\", \"active\"]]\n\nparseQuery2Arr(new URLSearchParams(\"page=1\"));\n// 返回: [[\"page\", \"1\"]]\n```\n\n#### mergeOptions\n\n合并多个选项对象。\n合并请求选项，包括 headers 和 signal 等特殊处理。\n\n**参数:**\n\n- `optionsList`: 要合并的选项对象列表\n\n**返回:** 合并后的选项对象\n\n**示例:**\n\n```typescript\nconst defaultOptions = {\n  timeout: 5000,\n  headers: { \"Content-Type\": \"application/json\" },\n};\nconst requestOptions = {\n  method: \"POST\",\n  body: JSON.stringify({ name: \"John\" }),\n};\nconst mergedOptions = mergeOptions(defaultOptions, requestOptions);\n```\n\n#### isBodyJson\n\n判断请求体是否为 JSON 对象。\n检查 body 是否为普通对象，而不是 FormData、Blob 等特殊类型。\n\n**参数:**\n\n- `body`: 请求体\n\n**返回:** 如果是 JSON 对象返回 true，否则返回 false\n\n**示例:**\n\n```typescript\nisBodyJson({ name: \"John\" }); // true\nisBodyJson(new FormData()); // false\nisBodyJson(\"string\"); // false\n```\n\n#### genRequestKey\n\n生成请求的唯一标识键（同步）。\n根据请求的 URL、方法、headers、查询参数等生成唯一键值，用于缓存和请求共享。\n\n> **注意：** 这是同步版本。对于 `Blob`/`FormData` 等需要异步处理的 body 类型，会回退为非确定性 key（基于 nonce）。使用 `genRequestKeyAsync` 可生成完全确定性的 key。\n> **注意：** `genRequestKeyAsync` 使用的 SHA-256 摘要需要[安全上下文](https://developer.mozilla.org/zh-CN/docs/Web/Security/Secure_Contexts)（HTTPS）。在纯 HTTP 下 `crypto.subtle.digest` 不可用，`genRequestKeyAsync` 会对 `Blob`/`ArrayBuffer`/`DataView` body 回退为非确定性 key，避免错误命中缓存或请求共享。\n\n**参数:**\n\n- `req`: 包含 url 和 options 的请求对象\n- `sortObjKeys?`: 是否对对象键进行排序以获得稳定序列化\n\n**返回:** 唯一标识字符串\n\n**示例:**\n\n```typescript\nconst key = genRequestKey({\n  url: \"/api/users\",\n  options: { method: \"GET\", params: { id: 1 } },\n});\n```\n\n#### genRequestKeyAsync\n\n生成请求的唯一标识键（异步）。\n与 `genRequestKey` 功能相同，但支持异步处理 `Blob`/`FormData` body，生成完全确定性的 key。\n\n**参数:**\n\n- `req`: 包含 url 和 options 的请求对象\n- `sortObjKeys?`: 是否对对象键进行排序以获得稳定序列化\n\n**返回:** 解析为唯一标识字符串的 Promise\n\n**示例:**\n\n```typescript\nconst key = await genRequestKeyAsync({\n  url: \"/api/users\",\n  options: { method: \"GET\", params: { id: 1 } },\n});\n```\n\n#### createRequestStore\n\n创建请求存储实例。\n提供请求缓存、共享和竞态条件处理。\n\n**参数:**\n\n- `options`: 配置选项\n  - `maxCacheSize`: 最大缓存大小（默认: 100000）\n\n**返回:** 请求存储对象，包含以下方法：\n- `entry(key)`: 获取特定请求键的条目\n- `dispose()`: 销毁存储并清除定时器\n- `get(key)`: 根据键获取请求\n- `set(key, value)`: 根据键设置请求\n- `remove(key)`: 根据键移除请求\n- `getAll()`: 获取所有请求\n- `removeAll()`: 移除所有请求\n- `clearCache()`: 清除所有缓存\n- `clearExpiredCache()`: 清除过期缓存\n- `abortAll()`: 中止所有请求\n\n**示例:**\n\n```typescript\nconst store = createRequestStore({ maxCacheSize: 1000 });\n// 在请求中使用 store\n```\n\n#### deepSort\n\n深度排序对象键。\n递归地对对象的键进行排序，用于生成稳定的对象序列化结果。\n\n**参数:**\n\n- `obj`: 要排序的对象\n- `sortArr`: 是否对数组进行排序（默认: false）\n\n**返回:** 键排序后的对象\n\n**示例:**\n\n```typescript\nconst obj = { b: 2, a: 1, c: { z: 3, y: 2 } };\nconst sorted = deepSort(obj);\n// 返回: { a: 1, b: 2, c: { y: 2, z: 3 } }\n```\n\n#### createSilentRefresh\n\n创建静默刷新实例。\n用于处理 token 过期时的静默刷新功能。\n\n**参数:**\n\n- `refresh_token_fn`: 刷新 token 的函数\n\n**返回:** 接收成功和失败回调的函数\n\n**示例:**\n\n```typescript\nconst silentRefresh = createSilentRefresh(async () => {\n  // 刷新token逻辑\n  await refreshToken();\n});\n\n// 使用示例\nsilentRefresh(\n  () => console.log(\"刷新成功\"),\n  () => console.log(\"刷新失败\")\n);\n```\n\n#### soonFetch\n\n一个轻量级的 fetch 包装器，支持缓存、共享和竞态条件处理。\n\n**参数:**\n\n- `config`: 配置对象\n  - `url`: 请求 URL\n  - `options`: 请求选项 (SoonOptions)\n  - `baseURL`: 基础 URL\n  - `baseOptions`: 基础请求选项\n  - `store`: 自定义请求存储\n  - `sortRequestKey`: 是否对请求键进行排序\n\n**返回:** 解析为 Response 的 Promise\n\n**示例:**\n\n```typescript\nconst response = await soonFetch({\n  url: \"/api/users\",\n  options: {\n    method: \"GET\",\n    query: { page: 1 },\n    share: true,\n    staleTime: 5000,\n  },\n  baseURL: \"https://api.example.com\",\n});\n\nif (!response.ok) {\n  throw new Error(`HTTP ${response.status}: ${response.statusText}`);\n}\n\nconst data = await response.json() as User[];\n```\n\n#### toFormData\n\n将对象转换为 FormData。\n用于将普通对象转换为 FormData 格式，支持文件和普通值。\n\n**参数:**\n\n- `body`: 要转换的对象\n\n**返回:** 转换后的 FormData 对象\n\n**示例:**\n\n```typescript\nconst formData = toFormData({\n  name: \"John\",\n  avatar: fileBlob,\n  age: 30,\n});\n```\n\n#### progressDownload\n\n带进度的下载。\n用于下载文件并跟踪进度。\n\n**参数:**\n\n- `response`: 响应对象\n- `onProgress`: 进度回调函数\n\n**返回:** 解析为 ArrayBuffer 的 Promise\n\n**示例:**\n\n```typescript\nconst response = await fetch(\"/api/download\");\nconst buffer = await progressDownload(response, (progress, downloaded, total) => {\n  console.log(`进度: ${progress}%, 已下载: ${downloaded}/${total}`);\n});\n```\n\n#### progressReadBody\n\n带进度的读取响应体。\n用于读取响应体并跟踪进度。\n\n**参数:**\n\n- `body`: ReadableStream<Uint8Array>\n- `onProgress`: 进度回调函数\n- `total`: 总大小（字节，默认: 0）\n\n**返回:** 解析为 ArrayBuffer 的 Promise\n\n**示例:**\n\n```typescript\nconst response = await fetch(\"/api/download\");\nconst buffer = await progressReadBody(response.body, (progress, downloaded, total) => {\n  console.log(`进度: ${progress}%, 已下载: ${downloaded}/${total}`);\n});\n```\n\n#### requestWithStore\n\n带存储支持的请求包装器。\n用于处理带有缓存、共享和竞态条件处理的请求。\n\n**参数:**\n\n- `store`: 请求存储实例\n- `requestFn`: 请求函数\n- `requestKey`: 请求键\n- `fetchAbort`: AbortController\n- `options`: 选项对象\n\n**返回:** 解析为响应的 Promise\n\n**示例:**\n\n```typescript\nconst store = createRequestStore();\nconst data = await requestWithStore(store, () => fetch(url, options), requestKey, abortController, {\n  share: true,\n  staleTime: 5000,\n});\n```\n\n\n[English](#soon-fetch) | [中文](#soon-fetch-1) | [Installation](#安装-installation)\n\n<!-- omit in toc -->\n\n##### 安装 Installation\n\n```\n    npm install soon-fetch\n```\n\n## Best Practices / 最佳实践\n\n#### Real-World Project Structure / 真实项目结构\n\nBased on [soon-admin-vue](https://github.com/leafio/soon-admin-vue):\n\n#### File Organization / 文件组织\n\n```\nsrc/api/\n├── request.ts          # Request wrapper with unified error handling\n├── types.ts            # Shared type definitions (e.g., PagedParams)\n├── index.ts            # Export all API modules\n└── modules/\n    ├── auth.ts         # Authentication APIs\n    ├── user.ts         # User management APIs\n    ├── role.ts         # Role management APIs\n    ├── dept.ts         # Department management APIs\n    └── ...             # Other domain-specific modules\n```\n\n#### Step 1: Create Request Wrapper (src/api/request.ts)\n\n```typescript\nimport { createSoon, soonFetch } from \"soon-fetch\";\nimport type { SoonOptions } from \"soon-fetch\";\n\ntype ReqOpts = SoonOptions & {\n  retry?: { max?: number; enable?: (result: any) => boolean };\n  toastErr?: boolean;\n};\n\nconst request = async <T>(url: string, options?: ReqOpts): Promise<T> => {\n  const isGet = !options?.method || options?.method.toLowerCase() === \"get\";\n  \n  try {\n    const response = await soonFetch({\n      url,\n      options,\n      baseURL: import.meta.env.VITE_API_BASE,\n      baseOptions: {\n        timeout: 20 * 1000,\n        headers: new Headers({ Authorization: localStorage.getItem(\"token\") ?? \"\" }),\n        share: isGet,\n        staleTime: isGet ? 2 * 1000 : 0,\n      },\n    });\n\n    if (!response.ok) {\n      throw new Error(`HTTP ${response.status}`);\n    }\n\n    // Auto-parse JSON\n    if (response.headers.get(\"content-type\")?.includes(\"json\")) {\n      const body = await response.json();\n      return body.data as T;\n    }\n    \n    return response as unknown as T;\n  } catch (error: any) {\n    // Unified error handling\n    if (error.name === \"TimeoutError\") {\n      ElMessage.error(\"Request timeout\");\n    } else if (error.name !== \"AbortError\" && options?.toastErr !== false) {\n      ElMessage.error(error.message);\n    }\n    throw error;\n  }\n};\n\nexport const soon = createSoon<ReqOpts>(request);\n```\n\n**Key Points:**\n- ✅ **Centralized error handling**: All HTTP errors, timeouts, and business errors handled in one place\n- ✅ **Auto Token refresh**: Handle 401 errors and retry automatically\n- ✅ **Smart caching**: GET requests cached by default, write operations not cached\n- ✅ **No repetitive try-catch**: Components call APIs directly without error handling boilerplate\n\n---\n\n#### Step 2: Define Typed APIs (src/api/modules/user.ts)\n\n```typescript\nimport { downloadBlob, getHeaderFilename } from \"soon-utils\";\nimport type { PagedParams } from \"../types\";\nimport type { Dept } from \"./dept\";\nimport type { Role } from \"./role\";\nimport { soon } from \"../request\";\n\n// Type definitions\nexport type User = {\n  id: number;\n  username: string;\n  email: string | null;\n  phone: string | null;\n  name: string | null;\n  avatar: string | null;\n  roleId: number | undefined;\n  deptId: number | undefined;\n  status: number;\n};\n\nexport type UserInfo = User & {\n  createTime: Date;\n  updateTime: Date | null;\n  dept?: Pick<Dept, \"id\" | \"name\">;\n  role?: Pick<Role, \"id\" | \"name\">;\n};\n\ntype ListQueryUser = PagedParams & { \n  keyword?: string; \n  timeRange?: [string, string]; \n};\n\n// CRUD APIs - simple and type-safe\nexport const list_user = soon.GET(\"/user\").Query<ListQueryUser>().Ok<{ list: UserInfo[] }>();\nexport const add_user = soon.POST(\"/user\").Body<User>().Ok();\nexport const update_user = soon.PUT(\"/user/:id\").Body<User>().Ok();\nexport const del_user = soon.DELETE(\"/user/:id\").Ok();\nexport const detail_user = soon.GET(\"/user/:id\").Ok<UserInfo>();\n\n// File download - returns Response for custom handling\nexport const download_user_table = async (query: ListQueryUser) => {\n  return soon.get<Response>(\"/user/export\", { query }).then(async (res) => {\n    const body = await res.blob();\n    const filename = getHeaderFilename(res.headers) ?? \"user.xlsx\";\n    downloadBlob(body, filename);\n  });\n};\n\n// Captcha example\nexport const getCaptcha = soon.GET(\"/captcha\").Ok<{ id: number; img: string }>();\n```\n\n**Key Points:**\n- ✅ **Domain-based modules**: Each module handles one business domain (user, role, dept, etc.)\n- ✅ **Type safety**: Use `.Params<>()`, `.Body<>()`, `.Ok<>()` for full type inference\n- ✅ **Shared types**: Import cross-domain types from sibling modules\n- ✅ **Special operations**: Complex logic (file download) wrapped in async functions\n- ✅ **Naming convention**: Use snake_case for API exports (e.g., `list_user`, `add_user`)\n\n---\n\n#### Step 3: Centralized Exports (src/api/index.ts)\n\n```typescript\nexport * from \"./modules/auth\";\nexport * from \"./modules/user\";\nexport * from \"./modules/role\";\n// ... other modules\n```\n\n**Usage in components:**\n```typescript\nimport { list_user, add_user, del_user } from \"@/api\";\n```\n\n---\n\n#### Step 4: Use in Components - Clean and Simple!\n\n**Vue 3 Example:**\n```typescript\n<script setup lang=\"ts\">\nimport { ref, onMounted } from \"vue\";\nimport { list_user, del_user } from \"@/api\";\nimport type { UserInfo } from \"@/api\";\n\nconst users = ref<UserInfo[]>([]);\nconst loading = ref(false);\n\nconst fetchUsers = async () => {\n  loading.value = true;\n  try {\n    const { list } = await list_user({ page: 1, pageSize: 10 });\n    users.value = list;\n  } finally {\n    loading.value = false;\n  }\n};\n\nconst handleDelete = async (id: number) => {\n  await del_user({ id });\n  await fetchUsers();\n};\n\nonMounted(fetchUsers);\n</script>\n```\n\n**React Example with Race Condition Handling:**\n```typescript\nimport { useEffect, useRef, useState } from \"react\";\nimport { list_user } from \"@/api\";\nimport type { UserInfo } from \"@/api\";\n\nexport default function UserList() {\n  const [users, setUsers] = useState<UserInfo[]>([]);\n  const [loading, setLoading] = useState(false);\n  const abortRef = useRef<[AbortController] | []>([]);\n\n  useEffect(() => {\n    setLoading(true);\n    list_user({ page: 1, pageSize: 10 }, { aborts: abortRef.current })\n      .then(({ list }) => setUsers(list))\n      .catch((err) => {\n        if (err.name !== \"AbortError\") console.error(err);\n      })\n      .finally(() => setLoading(false));\n  }, []);\n\n  if (loading) return <div>Loading...</div>;\n\n  return (\n    <ul>\n      {users.map(u => (\n        <li key={u.id}>{u.name}</li>\n      ))}\n    </ul>\n  );\n}\n```\n\n**Key Points:**\n- ✅ **No repetitive error handling**: Errors already handled in request wrapper\n- ✅ **Race condition control**: Use `useRef` to manage `aborts` parameter\n- ✅ **Clean code**: Focus on business logic, not network error boilerplate\n- ✅ **Type safety**: Full TypeScript support with autocomplete and type checking\n\n---\n\n### Summary / 总结\n\n**Architecture Benefits:**\n1. **Separation of Concerns**: Network layer (request.ts) vs Business layer (modules/) vs UI layer (components)\n2. **DRY Principle**: Error handling written once, used everywhere\n3. **Type Safety**: End-to-end type inference from API definition to component usage\n4. **Maintainability**: Domain-based modules make it easy to find and modify APIs\n5. **Scalability**: Easy to add new domains by creating new module files\n\n**Core Philosophy:**\n- 🎯 **Centralize common logic** in request wrapper (errors, retries, caching)\n- 🎯 **Keep API definitions simple** with chainable type-safe methods\n- 🎯 **Components focus on UI** without repetitive error handling code\n- 🎯 **Handle edge cases** only when needed (race conditions, special business logic)\n","readmeFilename":"README.md"}