diff --git a/CHANGELOG.md b/CHANGELOG.md index be97bd5..3f54936 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,12 @@ # Saborter Changelog -## v2.0.0 +## v2.0.1 (March 1th, 2026) + +### Bug Fixes + +- Fixed argument injection in `setTimeoutAsync` and `debounce` functions [#54](https://github.com/TENSIILE/saborter/pull/54) + +## v2.0.0 (February 24th, 2026) ### Breaking Changes diff --git a/docs/errors.md b/docs/errors.md index e59e372..9890435 100644 --- a/docs/errors.md +++ b/docs/errors.md @@ -52,6 +52,12 @@ import { AbortError } from 'saborter/errors'; - **Type:** `string` - **Description:** The default stack field is 'Error' without extended information. To enable extended information, [see here](#🎯-usage-examples). +`metadata?` + +- **Type:** `any` +- **Description:** Interrupt-related data. The best way to pass any data inside the error. This field will not be overridden in any way. +- **Optional:** `true` + `initiator` - **Type:** `'timeout' | 'user' | 'system'` @@ -76,7 +82,7 @@ new AbortError(message, options?) - `options?: Object` - `type?: 'cancelled' | 'aborted'` (Default is `aborted`) - Abort type. - `reason?: any` - Additional reason for interruption. - - `signal?: AbortSignal` - AbortSignal that was just interrupted. + - `metadata?: any` - Interrupt-related data. The best way to pass any data inside the error. ## 🎯 Usage Examples @@ -89,28 +95,16 @@ console.error(error.message); // 'The operation was interrupted' console.error(error.type); // 'aborted' ``` -### Creation with type and reason +### Creation with type and metadata ```javascript const error = new AbortError('Request cancelled', { type: 'cancelled', - reason: { requestId: '123', userId: 'user_456' } + metadata: { requestId: '123', userId: 'user_456' } }); console.error(error.type); // 'cancelled' -console.error(error.reason); // { requestId: '123', userId: 'user_456' } -``` - -### Creation with signal - -```javascript -const aborter = new Aborter(); // You can also use AbortController - -const error = new AbortError('The operation was interrupted', { - signal: aborter.signal -}); - -console.log(error.signal); // The signal that was transmitted +console.error(error.metadata); // { requestId: '123', userId: 'user_456' } ``` ### Active additional debug information in the error stack diff --git a/docs/libs.md b/docs/libs.md index ccc9ed9..8107bf5 100644 --- a/docs/libs.md +++ b/docs/libs.md @@ -206,12 +206,11 @@ try { ### `setTimeoutAsync` -Schedules the execution of a handler (either a function or a string of code) after a specified delay. The operation can be cancelled using an `AbortSignal`. This function returns a promise that resolves with the handler's result or rejects if the timeout is aborted or if the handler throws an error. +Schedules the execution of a handler after a specified delay. The operation can be cancelled using an `AbortSignal`. This function returns a promise that resolves with the handler's result or rejects if the timeout is aborted or if the handler throws an error. **Parameters:** -- `handler: string | ((signal: AbortSignal) => T | Promise)`: Can be either: - - A string of code to evaluate (similar to the first argument of `setTimeout`). +- `handler: ((signal: AbortSignal) => T | Promise)`: - A function that accepts an `AbortSignal` and returns a value or a `Promise`. This function will be called with the signal to allow cleanup on abort. - `delay?: number` - The time in milliseconds to wait before executing the handler. If omitted, the handler is scheduled without a delay (i.e., as soon as possible). - `options?: Object`: @@ -232,11 +231,15 @@ Schedules the execution of a handler (either a function or a string of code) aft ```typescript const controller = new AbortController(); -setTimeoutAsync((signal) => { - return fetch('/api/data', { signal }).then((res) => res.json(); -}), 5000, { - signal: controller.signal -}) +setTimeoutAsync( + (signal) => { + return fetch('/api/data', { signal }).then((res) => res.json()); + }, + 5000, + { + signal: controller.signal + } +) .then((data) => console.log(data)) .catch((error) => console.log(error.name)); // 'AbortError' if aborted ``` @@ -248,7 +251,7 @@ const controller = new AbortController(); try { const data = await setTimeoutAsync( async (signal) => { - const response = fetch('/api/data', { signal }); + const response = await fetch('/api/data', { signal }); return await response.json(); }, 5000, @@ -262,7 +265,7 @@ try { #### The `setTimeoutAsync` function can be used as a delay function if you need it: ```typescript -const delay = (ms: number) => setTimeoutAsync('', ms); +const delay = (ms: number) => setTimeoutAsync(() => null, ms); console.log('Hello'); await delay(2000); diff --git a/integrations/project/package-lock.json b/integrations/project/package-lock.json index ea0e13e..2a8f40f 100644 --- a/integrations/project/package-lock.json +++ b/integrations/project/package-lock.json @@ -10,7 +10,7 @@ "dependencies": { "react": "^19.2.0", "react-dom": "^19.2.0", - "saborter": "file:../../unreleased-packages/saborter-2.0.0.tgz" + "saborter": "file:../../unreleased-packages/saborter-2.0.1.tgz" }, "devDependencies": { "@eslint/js": "^9.39.1", @@ -1042,9 +1042,9 @@ "license": "MIT" }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.54.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.54.0.tgz", - "integrity": "sha512-OywsdRHrFvCdvsewAInDKCNyR3laPA2mc9bRYJ6LBp5IyvF3fvXbbNR0bSzHlZVFtn6E0xw2oZlyjg4rKCVcng==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.59.0.tgz", + "integrity": "sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==", "cpu": [ "arm" ], @@ -1056,9 +1056,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.54.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.54.0.tgz", - "integrity": "sha512-Skx39Uv+u7H224Af+bDgNinitlmHyQX1K/atIA32JP3JQw6hVODX5tkbi2zof/E69M1qH2UoN3Xdxgs90mmNYw==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.59.0.tgz", + "integrity": "sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q==", "cpu": [ "arm64" ], @@ -1070,9 +1070,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.54.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.54.0.tgz", - "integrity": "sha512-k43D4qta/+6Fq+nCDhhv9yP2HdeKeP56QrUUTW7E6PhZP1US6NDqpJj4MY0jBHlJivVJD5P8NxrjuobZBJTCRw==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.59.0.tgz", + "integrity": "sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg==", "cpu": [ "arm64" ], @@ -1084,9 +1084,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.54.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.54.0.tgz", - "integrity": "sha512-cOo7biqwkpawslEfox5Vs8/qj83M/aZCSSNIWpVzfU2CYHa2G3P1UN5WF01RdTHSgCkri7XOlTdtk17BezlV3A==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.59.0.tgz", + "integrity": "sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w==", "cpu": [ "x64" ], @@ -1098,9 +1098,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.54.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.54.0.tgz", - "integrity": "sha512-miSvuFkmvFbgJ1BevMa4CPCFt5MPGw094knM64W9I0giUIMMmRYcGW/JWZDriaw/k1kOBtsWh1z6nIFV1vPNtA==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.59.0.tgz", + "integrity": "sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA==", "cpu": [ "arm64" ], @@ -1112,9 +1112,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.54.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.54.0.tgz", - "integrity": "sha512-KGXIs55+b/ZfZsq9aR026tmr/+7tq6VG6MsnrvF4H8VhwflTIuYh+LFUlIsRdQSgrgmtM3fVATzEAj4hBQlaqQ==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.59.0.tgz", + "integrity": "sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg==", "cpu": [ "x64" ], @@ -1126,9 +1126,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.54.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.54.0.tgz", - "integrity": "sha512-EHMUcDwhtdRGlXZsGSIuXSYwD5kOT9NVnx9sqzYiwAc91wfYOE1g1djOEDseZJKKqtHAHGwnGPQu3kytmfaXLQ==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.59.0.tgz", + "integrity": "sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==", "cpu": [ "arm" ], @@ -1140,9 +1140,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.54.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.54.0.tgz", - "integrity": "sha512-+pBrqEjaakN2ySv5RVrj/qLytYhPKEUwk+e3SFU5jTLHIcAtqh2rLrd/OkbNuHJpsBgxsD8ccJt5ga/SeG0JmA==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.59.0.tgz", + "integrity": "sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==", "cpu": [ "arm" ], @@ -1154,9 +1154,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.54.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.54.0.tgz", - "integrity": "sha512-NSqc7rE9wuUaRBsBp5ckQ5CVz5aIRKCwsoa6WMF7G01sX3/qHUw/z4pv+D+ahL1EIKy6Enpcnz1RY8pf7bjwng==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.59.0.tgz", + "integrity": "sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==", "cpu": [ "arm64" ], @@ -1168,9 +1168,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.54.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.54.0.tgz", - "integrity": "sha512-gr5vDbg3Bakga5kbdpqx81m2n9IX8M6gIMlQQIXiLTNeQW6CucvuInJ91EuCJ/JYvc+rcLLsDFcfAD1K7fMofg==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.59.0.tgz", + "integrity": "sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==", "cpu": [ "arm64" ], @@ -1182,9 +1182,23 @@ ] }, "node_modules/@rollup/rollup-linux-loong64-gnu": { - "version": "4.54.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.54.0.tgz", - "integrity": "sha512-gsrtB1NA3ZYj2vq0Rzkylo9ylCtW/PhpLEivlgWe0bpgtX5+9j9EZa0wtZiCjgu6zmSeZWyI/e2YRX1URozpIw==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.59.0.tgz", + "integrity": "sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.59.0.tgz", + "integrity": "sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==", "cpu": [ "loong64" ], @@ -1196,9 +1210,23 @@ ] }, "node_modules/@rollup/rollup-linux-ppc64-gnu": { - "version": "4.54.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.54.0.tgz", - "integrity": "sha512-y3qNOfTBStmFNq+t4s7Tmc9hW2ENtPg8FeUD/VShI7rKxNW7O4fFeaYbMsd3tpFlIg1Q8IapFgy7Q9i2BqeBvA==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.59.0.tgz", + "integrity": "sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.59.0.tgz", + "integrity": "sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==", "cpu": [ "ppc64" ], @@ -1210,9 +1238,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.54.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.54.0.tgz", - "integrity": "sha512-89sepv7h2lIVPsFma8iwmccN7Yjjtgz0Rj/Ou6fEqg3HDhpCa+Et+YSufy27i6b0Wav69Qv4WBNl3Rs6pwhebQ==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.59.0.tgz", + "integrity": "sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==", "cpu": [ "riscv64" ], @@ -1224,9 +1252,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.54.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.54.0.tgz", - "integrity": "sha512-ZcU77ieh0M2Q8Ur7D5X7KvK+UxbXeDHwiOt/CPSBTI1fBmeDMivW0dPkdqkT4rOgDjrDDBUed9x4EgraIKoR2A==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.59.0.tgz", + "integrity": "sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==", "cpu": [ "riscv64" ], @@ -1238,9 +1266,9 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.54.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.54.0.tgz", - "integrity": "sha512-2AdWy5RdDF5+4YfG/YesGDDtbyJlC9LHmL6rZw6FurBJ5n4vFGupsOBGfwMRjBYH7qRQowT8D/U4LoSvVwOhSQ==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.59.0.tgz", + "integrity": "sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==", "cpu": [ "s390x" ], @@ -1252,9 +1280,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.54.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.54.0.tgz", - "integrity": "sha512-WGt5J8Ij/rvyqpFexxk3ffKqqbLf9AqrTBbWDk7ApGUzaIs6V+s2s84kAxklFwmMF/vBNGrVdYgbblCOFFezMQ==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.59.0.tgz", + "integrity": "sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==", "cpu": [ "x64" ], @@ -1266,9 +1294,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.54.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.54.0.tgz", - "integrity": "sha512-JzQmb38ATzHjxlPHuTH6tE7ojnMKM2kYNzt44LO/jJi8BpceEC8QuXYA908n8r3CNuG/B3BV8VR3Hi1rYtmPiw==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.59.0.tgz", + "integrity": "sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==", "cpu": [ "x64" ], @@ -1279,10 +1307,24 @@ "linux" ] }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.59.0.tgz", + "integrity": "sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, "node_modules/@rollup/rollup-openharmony-arm64": { - "version": "4.54.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.54.0.tgz", - "integrity": "sha512-huT3fd0iC7jigGh7n3q/+lfPcXxBi+om/Rs3yiFxjvSxbSB6aohDFXbWvlspaqjeOh+hx7DDHS+5Es5qRkWkZg==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.59.0.tgz", + "integrity": "sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA==", "cpu": [ "arm64" ], @@ -1294,9 +1336,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.54.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.54.0.tgz", - "integrity": "sha512-c2V0W1bsKIKfbLMBu/WGBz6Yci8nJ/ZJdheE0EwB73N3MvHYKiKGs3mVilX4Gs70eGeDaMqEob25Tw2Gb9Nqyw==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.59.0.tgz", + "integrity": "sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A==", "cpu": [ "arm64" ], @@ -1308,9 +1350,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.54.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.54.0.tgz", - "integrity": "sha512-woEHgqQqDCkAzrDhvDipnSirm5vxUXtSKDYTVpZG3nUdW/VVB5VdCYA2iReSj/u3yCZzXID4kuKG7OynPnB3WQ==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.59.0.tgz", + "integrity": "sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA==", "cpu": [ "ia32" ], @@ -1322,9 +1364,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-gnu": { - "version": "4.54.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.54.0.tgz", - "integrity": "sha512-dzAc53LOuFvHwbCEOS0rPbXp6SIhAf2txMP5p6mGyOXXw5mWY8NGGbPMPrs4P1WItkfApDathBj/NzMLUZ9rtQ==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.59.0.tgz", + "integrity": "sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA==", "cpu": [ "x64" ], @@ -1336,9 +1378,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.54.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.54.0.tgz", - "integrity": "sha512-hYT5d3YNdSh3mbCU1gwQyPgQd3T2ne0A3KG8KSBdav5TiBg6eInVmV+TeR5uHufiIgSFg0XsOWGW5/RhNcSvPg==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.59.0.tgz", + "integrity": "sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA==", "cpu": [ "x64" ], @@ -1524,9 +1566,9 @@ } }, "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", + "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", "dev": true, "license": "MIT", "dependencies": { @@ -2401,9 +2443,9 @@ "license": "ISC" }, "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "dev": true, "license": "ISC", "dependencies": { @@ -2647,9 +2689,9 @@ } }, "node_modules/rollup": { - "version": "4.54.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.54.0.tgz", - "integrity": "sha512-3nk8Y3a9Ea8szgKhinMlGMhGMw89mqule3KWczxhIzqudyHdCIOHw8WJlj/r329fACjKLEh13ZSk7oE22kyeIw==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.59.0.tgz", + "integrity": "sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==", "dev": true, "license": "MIT", "dependencies": { @@ -2663,35 +2705,38 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.54.0", - "@rollup/rollup-android-arm64": "4.54.0", - "@rollup/rollup-darwin-arm64": "4.54.0", - "@rollup/rollup-darwin-x64": "4.54.0", - "@rollup/rollup-freebsd-arm64": "4.54.0", - "@rollup/rollup-freebsd-x64": "4.54.0", - "@rollup/rollup-linux-arm-gnueabihf": "4.54.0", - "@rollup/rollup-linux-arm-musleabihf": "4.54.0", - "@rollup/rollup-linux-arm64-gnu": "4.54.0", - "@rollup/rollup-linux-arm64-musl": "4.54.0", - "@rollup/rollup-linux-loong64-gnu": "4.54.0", - "@rollup/rollup-linux-ppc64-gnu": "4.54.0", - "@rollup/rollup-linux-riscv64-gnu": "4.54.0", - "@rollup/rollup-linux-riscv64-musl": "4.54.0", - "@rollup/rollup-linux-s390x-gnu": "4.54.0", - "@rollup/rollup-linux-x64-gnu": "4.54.0", - "@rollup/rollup-linux-x64-musl": "4.54.0", - "@rollup/rollup-openharmony-arm64": "4.54.0", - "@rollup/rollup-win32-arm64-msvc": "4.54.0", - "@rollup/rollup-win32-ia32-msvc": "4.54.0", - "@rollup/rollup-win32-x64-gnu": "4.54.0", - "@rollup/rollup-win32-x64-msvc": "4.54.0", + "@rollup/rollup-android-arm-eabi": "4.59.0", + "@rollup/rollup-android-arm64": "4.59.0", + "@rollup/rollup-darwin-arm64": "4.59.0", + "@rollup/rollup-darwin-x64": "4.59.0", + "@rollup/rollup-freebsd-arm64": "4.59.0", + "@rollup/rollup-freebsd-x64": "4.59.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.59.0", + "@rollup/rollup-linux-arm-musleabihf": "4.59.0", + "@rollup/rollup-linux-arm64-gnu": "4.59.0", + "@rollup/rollup-linux-arm64-musl": "4.59.0", + "@rollup/rollup-linux-loong64-gnu": "4.59.0", + "@rollup/rollup-linux-loong64-musl": "4.59.0", + "@rollup/rollup-linux-ppc64-gnu": "4.59.0", + "@rollup/rollup-linux-ppc64-musl": "4.59.0", + "@rollup/rollup-linux-riscv64-gnu": "4.59.0", + "@rollup/rollup-linux-riscv64-musl": "4.59.0", + "@rollup/rollup-linux-s390x-gnu": "4.59.0", + "@rollup/rollup-linux-x64-gnu": "4.59.0", + "@rollup/rollup-linux-x64-musl": "4.59.0", + "@rollup/rollup-openbsd-x64": "4.59.0", + "@rollup/rollup-openharmony-arm64": "4.59.0", + "@rollup/rollup-win32-arm64-msvc": "4.59.0", + "@rollup/rollup-win32-ia32-msvc": "4.59.0", + "@rollup/rollup-win32-x64-gnu": "4.59.0", + "@rollup/rollup-win32-x64-msvc": "4.59.0", "fsevents": "~2.3.2" } }, "node_modules/saborter": { - "version": "2.0.0", - "resolved": "file:../../unreleased-packages/saborter-2.0.0.tgz", - "integrity": "sha512-RShTlGSpesZHxQQLGk66OkSK10Z9UoBs2JPwMRoCHo9LierKVXzVDvki5Kz8in81E1D7HiMEadLxkvfl+71wfQ==", + "version": "2.0.1", + "resolved": "file:../../unreleased-packages/saborter-2.0.1.tgz", + "integrity": "sha512-zQ5sLfcAzbnDHKhu1sRxKtVAMzFQ4QAHt+t+9gE0SxC4tH6XoX+YNoeyqH22f6PLyFZkIHkPykm/IPsmhwqcgA==", "license": "MIT" }, "node_modules/scheduler": { diff --git a/integrations/project/package.json b/integrations/project/package.json index 4df827a..8de81ce 100644 --- a/integrations/project/package.json +++ b/integrations/project/package.json @@ -12,7 +12,7 @@ "dependencies": { "react": "^19.2.0", "react-dom": "^19.2.0", - "saborter": "file:../../unreleased-packages/saborter-2.0.0.tgz" + "saborter": "file:../../unreleased-packages/saborter-2.0.1.tgz" }, "devDependencies": { "@eslint/js": "^9.39.1", diff --git a/integrations/project/src/app.component.tsx b/integrations/project/src/app.component.tsx index db707a6..537b2d6 100644 --- a/integrations/project/src/app.component.tsx +++ b/integrations/project/src/app.component.tsx @@ -7,7 +7,9 @@ interface User { } const getUsers = async (signal: AbortSignal) => { - return fetch('https://apimocker.com/users?_delay=3000', { signal }); + const response = await fetch('https://apimocker.com/users?_delay=3000', { signal }); + + return (await response.json()) as { data: User[] }; }; export const App = () => { @@ -21,9 +23,9 @@ export const App = () => { setLoading(true); setUsers([]); - const data = await aborterRef.current.try<{ data: User[] }>(getUsers); + const users = await aborterRef.current.try(getUsers); - setUsers(data.data); + setUsers(users.data); } catch (error) { console.log(error); } finally { diff --git a/package.json b/package.json index fac99c6..2c8d336 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "saborter", - "version": "2.0.0", + "version": "2.0.1", "description": "A simple and efficient library for canceling asynchronous requests using AbortController", "main": "dist/index.cjs.js", "module": "dist/index.es.js", diff --git a/readme.md b/readme.md index 2d63632..16a8da2 100644 --- a/readme.md +++ b/readme.md @@ -117,7 +117,7 @@ The `Aborter` class makes it easy to cancel running requests after a period of t const aborter = new Aborter(); // Start a long-running request and cancel the request after 2 seconds -const longRequest = aborter.try( +const results = aborter.try( (signal) => { return fetch('/api/long-task', { signal }); }, @@ -125,7 +125,24 @@ const longRequest = aborter.try( ); ``` -### 3. Multiple request aborts through a single `ReusableAborter` instance +### 3. Built-in debounce functionality + +The `Aborter` class allows integration with the debounce utility: + +```javascript +import { debounce } from 'saborter/lib'; + +const aborter = new Aborter(); + +// The request will be delayed for 2 seconds and then executed. +const results = aborter.try( + debounce((signal) => { + return fetch('/api/long-task', { signal }); + }, 2000) +); +``` + +### 4. Multiple request aborts through a single `ReusableAborter` instance The `ReusableAborter` class allows you to easily cancel requests an unlimited number of times while preserving all listeners: @@ -146,7 +163,7 @@ reusableAborter.abort(); // call of the listener -> console.log('aborted', e) reusableAborter.abort(); // listener recall -> console.log('aborted', e) ``` -### 4. Working with Multiple Requests +### 5. Working with Multiple Requests You can create separate instances for different groups of requests: diff --git a/src/features/lib/debounce/debounce.lib.ts b/src/features/lib/debounce/debounce.lib.ts index 426d49e..2920162 100644 --- a/src/features/lib/debounce/debounce.lib.ts +++ b/src/features/lib/debounce/debounce.lib.ts @@ -46,12 +46,12 @@ import { AbortError } from '../../abort-error'; * @see setTimeoutAsync – The underlying delay mechanism. */ export const debounce = ( - handler: Parameters>['0'] & Function, + handler: Parameters>['0'], delay?: number -): ((signal: AbortSignal) => Promise) => { - return (signal: AbortSignal) => { +): ((signal: AbortSignal, args?: unknown[]) => Promise) => { + return (signal: AbortSignal, args?: unknown[]) => { try { - return setTimeoutAsync(handler, delay, { signal }); + return setTimeoutAsync(handler, delay, { signal, args }); } catch (error) { if (error instanceof AbortError) { error.cause = new AbortError(error.message, { ...error, cause: error }); diff --git a/src/features/lib/set-timeout-async/set-timeout-async.lib.ts b/src/features/lib/set-timeout-async/set-timeout-async.lib.ts index 59c820f..d226d6d 100644 --- a/src/features/lib/set-timeout-async/set-timeout-async.lib.ts +++ b/src/features/lib/set-timeout-async/set-timeout-async.lib.ts @@ -6,17 +6,15 @@ import { logger } from '../../../shared/logger'; * supporting abort signal for cancellation. * * @template T The return type of the handler function. - * @param {string | ((signal: AbortSignal) => T | Promise)} handler - - * Either a string of code to evaluate or a function that takes an AbortSignal - * and returns a value or Promise. If it's a function, it will be called with - * the AbortSignal to allow cleanup on abort. + * @param {((signal: AbortSignal) => T | Promise)} handler - + * A function that accepts an AbortSignal and returns a value or Promise. + * This function will be called with an AbortSignal to ensure cleanup upon interruption. * @param {number} [delay] - Optional timeout in milliseconds. If not provided, * the handler will be scheduled without a delay. * @param {Object} [options] - Configuration options. * @param {AbortSignal} [options.signal] - AbortSignal to cancel the timeout. * If not provided, a new AbortController will be created internally. - * @param {any[]} [options.args] - Arguments to pass to the handler if it's a string. - * These arguments will be passed as parameters to the code string when evaluated. + * @param {any[]} [options.args] - Arguments to pass to the handler. * @returns {Promise} A promise that resolves with the handler's result or rejects * with an AbortError if the operation is aborted, or with any error thrown by the handler. * @@ -33,18 +31,18 @@ import { logger } from '../../../shared/logger'; * console.log(error.name) // 'AbortError' Saborter's Error * } */ -export const setTimeoutAsync = ( - handler: string | ((signal: AbortSignal) => T | Promise), +export const setTimeoutAsync = ( + handler: (signal: AbortSignal, args: A extends [] ? undefined : A) => T | Promise, delay?: number, options?: { signal?: AbortSignal; - args?: any[]; + args?: A; } ): Promise => { - const { args = [], signal = new AbortController().signal } = options ?? {}; + const { args, signal = new AbortController().signal } = options ?? {}; return new Promise((resolve, reject) => { - let timeoutId: number | undefined; + let timeoutId: NodeJS.Timeout | undefined; if (signal.aborted) { if (!signal.reason?.message) { @@ -76,27 +74,21 @@ export const setTimeoutAsync = ( reject(error); }; - timeoutId = setTimeout( - typeof handler === 'string' - ? handler - : () => { - try { - const promise = handler(signal); + timeoutId = setTimeout(() => { + try { + const promise = handler(signal, args as A extends [] ? undefined : A); - if (promise instanceof Promise) { - return promise.then(resolve).catch(reject); - } + if (promise instanceof Promise) { + return promise.then(resolve).catch(reject); + } - return resolve(promise); - } catch (error) { - reject(error); - } finally { - signal?.removeEventListener('abort', handleEventListener); - } - }, - delay, - ...args - ); + return resolve(promise); + } catch (error) { + reject(error); + } finally { + signal?.removeEventListener('abort', handleEventListener); + } + }, delay); signal?.addEventListener('abort', handleEventListener, { once: true }); }); diff --git a/src/modules/aborter/aborter.ts b/src/modules/aborter/aborter.ts index b4de70e..d5dbe7a 100644 --- a/src/modules/aborter/aborter.ts +++ b/src/modules/aborter/aborter.ts @@ -87,7 +87,7 @@ export class Aborter { * @param options an object that receives a set of settings for performing a request attempt * @returns Promise */ - public try(request: Types.AbortableRequest, options?: Types.FnTryOptions): Promise; + public try(request: Types.AbortableRequest, options?: Types.FnTryOptions): Promise; public try(request: Types.AbortableRequest, options?: Types.FnTryOptions): Promise; @@ -134,6 +134,10 @@ export class Aborter { this.setRequestState('fulfilled'); if (unpackData && response instanceof Response) { + if (!response.ok) { + logger.warn('Request failed, something went wrong', response); + } + return response.json().then(resolve).catch(reject); } diff --git a/unreleased-packages/saborter-2.0.1.tgz b/unreleased-packages/saborter-2.0.1.tgz new file mode 100644 index 0000000..a6d8e27 Binary files /dev/null and b/unreleased-packages/saborter-2.0.1.tgz differ