{"_id":"@cancjs/promise","_rev":"8-627c07de14858177c5491de95e854a45","name":"@cancjs/promise","dist-tags":{"latest":"1.0.0","beta":"1.0.0-beta.20"},"versions":{"1.0.0-beta.17":{"name":"@cancjs/promise","version":"1.0.0-beta.17","keywords":[],"author":{"name":"bisubus"},"license":"MIT","_id":"@cancjs/promise@1.0.0-beta.17","maintainers":[{"name":"busybus","email":"busybus8@proton.me"}],"homepage":"https://github.com/cancjs/canc/packages/canc-promise#readme","bugs":{"url":"https://github.com/cancjs/canc/issues"},"dist":{"shasum":"f0e056bf52857c767d03f12ee86b6da27d938099","tarball":"https://registry.npmjs.org/@cancjs/promise/-/promise-1.0.0-beta.17.tgz","fileCount":25,"integrity":"sha512-qNs+8pz6SGPtOJmNRVzuogBwk7LHyTy23s78IqnaSVORUuZezS38UWtx7YiZMI/h7oLTeGIxdg+Ndq5gFpj1DA==","signatures":[{"sig":"MEUCIQCL8G9ZrDmYsO66V3tiLXG1uAe7uMnbjfeQRJL0Q4iFIQIgOs0rcs6Xs4ERvxmCwhAYPJVHvDfL+stCdXLgxoJF098=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":652951},"main":"dist/index.cjs","type":"commonjs","types":"dist/types/index.d.ts","unpkg":"dist/index.umd.min.js","module":"dist/index.mjs","engines":{"npm":">=9","node":">=18"},"exports":{".":{"types":"./dist/types/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.cjs","types@<4.7":"./dist/types-ts4.2/index.d.ts"}},"gitHead":"c32f6aaf26b06a1a463990ccf36962f39cc886f5","scripts":{"lint":"eslint .","test":"jest --colors","build":"rimraf dist && rollup --config ./rollup.config.mjs","check":"tsc --noEmit --project ./tsconfig.prod.json","format":"eslint --fix .","lint:src":"eslint ./src","format:src":"eslint --fix ./src","test:watch":"jest --colors --watch"},"_npmUser":{"name":"busybus","email":"busybus8@proton.me"},"jsdelivr":"dist/index.umd.min.js","repository":{"url":"git+https://github.com/cancjs/canc.git","type":"git","directory":"packages/canc-promise"},"_npmVersion":"11.6.3","description":"<div align=\"center\">   <img src=\"https://raw.githubusercontent.com/cancjs/canc/master/assets/canc-logo.svg\" style=\"width: 400px; max-width: 100%; height: auto;\" title=\"canc &#x2BBF; A crafty foundation for cancelable promises\" alt=\"canc &#x2BBF; A crafty ","directories":{},"sideEffects":false,"_nodeVersion":"24.18.1","publishConfig":{"access":"public"},"typesVersions":{"<4.7":{"dist/types/*":["dist/types-ts4.2/*"]}},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/promise_1.0.0-beta.17_1785795295052_0.09245270092184099","host":"s3://npm-registry-packages-npm-production"}},"1.0.0-beta.18":{"name":"@cancjs/promise","version":"1.0.0-beta.18","keywords":["promise","cancel","cancelable","async"],"author":{"name":"bisubus"},"license":"MIT","_id":"@cancjs/promise@1.0.0-beta.18","maintainers":[{"name":"busybus","email":"busybus8@proton.me"}],"homepage":"https://github.com/cancjs/canc/tree/master/packages/canc-promise#readme","bugs":{"url":"https://github.com/cancjs/canc/issues"},"dist":{"shasum":"3a6d36a02dca07302db776bc8e3117f3d01a4bd1","tarball":"https://registry.npmjs.org/@cancjs/promise/-/promise-1.0.0-beta.18.tgz","fileCount":25,"integrity":"sha512-g0au8uV1Qd2KRdq1YOGvdOBn9C1MBQDlKt2LXseOkOMu2T3HzLv2hUCweCzsI9vz3zLdZR4OQ9pE3m21T77a8g==","signatures":[{"sig":"MEUCICLa9ALb70jhSjSt40KVgSm7JWnCaazhF+fTrKl94e3nAiEAwuQReC/F1wCeufDdzjwMV3TKEbKQJWk7f8Ikaaz8ojk=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":653841},"main":"dist/index.cjs","type":"commonjs","types":"dist/types/index.d.ts","unpkg":"dist/index.umd.min.js","module":"dist/index.mjs","engines":{"npm":">=9","node":">=18"},"exports":{".":{"import":{"types":"./dist/types/index.d.mts","default":"./dist/index.mjs","types@<4.7":"./dist/types-ts4.2/index.d.mts"},"require":{"types":"./dist/types/index.d.ts","default":"./dist/index.cjs","types@<4.7":"./dist/types-ts4.2/index.d.ts"}}},"gitHead":"17debd83ea144e803b99804d93e63d83291e505c","scripts":{"lint":"eslint .","test":"jest --colors","build":"rimraf dist && rollup --config ./rollup.config.mjs","check":"tsc --noEmit --project ./tsconfig.prod.json","format":"eslint --fix .","lint:src":"eslint ./src","format:src":"eslint --fix ./src","test:watch":"jest --colors --watch"},"_npmUser":{"name":"busybus","email":"busybus8@proton.me"},"jsdelivr":"dist/index.umd.min.js","repository":{"url":"git+https://github.com/cancjs/canc.git","type":"git","directory":"packages/canc-promise"},"_npmVersion":"11.6.3","description":"Cancelable promise implementation based on native Promise.","directories":{},"sideEffects":false,"_nodeVersion":"24.18.1","publishConfig":{"access":"public"},"typesVersions":{"<4.7":{"dist/types/*":["dist/types-ts4.2/*"]}},"_hasShrinkwrap":false,"readmeFilename":"README.md","_npmOperationalInternal":{"tmp":"tmp/promise_1.0.0-beta.18_1785833180831_0.23526430279091914","host":"s3://npm-registry-packages-npm-production"}},"1.0.0-beta.19":{"name":"@cancjs/promise","version":"1.0.0-beta.19","keywords":["promise","cancel","cancelable","async"],"author":{"name":"bisubus"},"license":"MIT","_id":"@cancjs/promise@1.0.0-beta.19","maintainers":[{"name":"busybus","email":"busybus8@proton.me"}],"homepage":"https://github.com/cancjs/canc/tree/master/packages/canc-promise#readme","bugs":{"url":"https://github.com/cancjs/canc/issues"},"dist":{"shasum":"88729526bd5c5c95a355c72c298474097b050155","tarball":"https://registry.npmjs.org/@cancjs/promise/-/promise-1.0.0-beta.19.tgz","fileCount":55,"integrity":"sha512-L9+t4qADkIQWttcZ63cr4RXQN9DhofVNxZw8A3kmYlvWhymoHfvlk37hlOXABfYEk0c298MblS8hOFftfUmn6A==","signatures":[{"sig":"MEYCIQCdsPUG1eMY/InIX8dfslf3+pknvVC+P+dnlDls88EoyQIhAKQYF7duZQ5SJeUtcwUQBvy158H3vsgcqiIBpISkbpTj","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":744117},"main":"dist/index.cjs","type":"commonjs","types":"dist/types/index.d.ts","unpkg":"dist/index.umd.min.js","module":"dist/index.mjs","engines":{"npm":">=9","node":">=18"},"exports":{".":{"import":{"types":"./dist/types/index.d.mts","default":"./dist/index.mjs","types@<4.7":"./dist/types-ts4.2/index.d.mts"},"require":{"types":"./dist/types/index.d.ts","default":"./dist/index.cjs","types@<4.7":"./dist/types-ts4.2/index.d.ts"}}},"gitHead":"e4a4191717ce108afb9e105063ec59a6d056b6b1","scripts":{"lint":"eslint .","test":"jest --colors","build":"rimraf dist && rollup --config ./rollup.config.mjs","check":"tsc --noEmit --project ./tsconfig.prod.json","format":"eslint --fix .","lint:src":"eslint ./src","format:src":"eslint --fix ./src","test:watch":"jest --colors --watch"},"_npmUser":{"name":"busybus","email":"busybus8@proton.me"},"jsdelivr":"dist/index.umd.min.js","repository":{"url":"git+https://github.com/cancjs/canc.git","type":"git","directory":"packages/canc-promise"},"_npmVersion":"11.6.3","description":"Cancelable promise implementation based on native Promise.","directories":{},"sideEffects":false,"_nodeVersion":"24.18.1","publishConfig":{"access":"public"},"typesVersions":{"<4.7":{"dist/types/*":["dist/types-ts4.2/*"]}},"_hasShrinkwrap":false,"readmeFilename":"README.md","_npmOperationalInternal":{"tmp":"tmp/promise_1.0.0-beta.19_1785840141606_0.30151836832979684","host":"s3://npm-registry-packages-npm-production"}},"1.0.0-beta.20":{"name":"@cancjs/promise","version":"1.0.0-beta.20","keywords":["promise","cancel","cancelable","async"],"author":{"name":"bisubus"},"license":"MIT","_id":"@cancjs/promise@1.0.0-beta.20","maintainers":[{"name":"busybus","email":"busybus8@proton.me"}],"homepage":"https://github.com/cancjs/canc/tree/master/packages/canc-promise#readme","bugs":{"url":"https://github.com/cancjs/canc/issues"},"dist":{"shasum":"689df3f37073e14ffbf8d52d33fbfd622737933b","tarball":"https://registry.npmjs.org/@cancjs/promise/-/promise-1.0.0-beta.20.tgz","fileCount":59,"integrity":"sha512-q80WmEg7FFJ93wJwr1A5sLIolPrIw+KuzK4IfF71UIwfj+9vqYzK4zXykipsVLhXDHH5jg0hhsbQkkZL4tahIw==","signatures":[{"sig":"MEQCIEbDJFfr8WCKGyRKLI/bXMPZptqmsFhiwPV0zmy67AYWAiASxrbEFAy5utwIotCqxqTYoAv2wVNJt4KCXf3OTUmg4w==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":756712},"main":"dist/index.cjs","type":"commonjs","types":"dist/types/index.d.ts","unpkg":"dist/index.umd.min.js","module":"dist/index.mjs","engines":{"npm":">=9","node":">=18"},"exports":{".":{"import":{"types":"./dist/types/index.d.mts","default":"./dist/index.mjs","types@<4.7":"./dist/types-ts4.2/index.d.mts"},"require":{"types":"./dist/types/index.d.ts","default":"./dist/index.cjs","types@<4.7":"./dist/types-ts4.2/index.d.ts"}}},"gitHead":"3fcdda94f6abbb8e1eb0cb8c27b14e2f4386faed","scripts":{"lint":"eslint .","test":"jest --colors","build":"rimraf dist && rollup --config ./rollup.config.mjs","check":"tsc --noEmit --project ./tsconfig.prod.json","format":"eslint --fix .","lint:src":"eslint ./src","format:src":"eslint --fix ./src","test:watch":"jest --colors --watch"},"_npmUser":{"name":"busybus","email":"busybus8@proton.me"},"jsdelivr":"dist/index.umd.min.js","repository":{"url":"git+https://github.com/cancjs/canc.git","type":"git","directory":"packages/canc-promise"},"_npmVersion":"11.6.3","description":"Cancelable promise implementation based on native Promise.","directories":{},"sideEffects":false,"_nodeVersion":"24.18.1","publishConfig":{"access":"public"},"typesVersions":{"<4.7":{"dist/types/*":["dist/types-ts4.2/*"]}},"_hasShrinkwrap":false,"readmeFilename":"README.md","_npmOperationalInternal":{"tmp":"tmp/promise_1.0.0-beta.20_1785873826557_0.43048837700268705","host":"s3://npm-registry-packages-npm-production"}},"1.0.0":{"name":"@cancjs/promise","version":"1.0.0","description":"Cancelable promise implementation based on native Promise.","license":"MIT","repository":{"type":"git","url":"git+https://github.com/cancjs/canc.git","directory":"packages/canc-promise"},"homepage":"https://github.com/cancjs/canc/tree/master/packages/canc-promise#readme","bugs":{"url":"https://github.com/cancjs/canc/issues"},"author":{"name":"bisubus"},"type":"commonjs","exports":{".":{"import":{"types@<4.7":"./dist/types-ts4.2/index.d.mts","types":"./dist/types/index.d.mts","default":"./dist/index.mjs"},"require":{"types@<4.7":"./dist/types-ts4.2/index.d.ts","types":"./dist/types/index.d.ts","default":"./dist/index.cjs"}}},"main":"dist/index.cjs","module":"dist/index.mjs","types":"dist/types/index.d.ts","sideEffects":false,"engines":{"node":">=18","npm":">=9"},"publishConfig":{"access":"public"},"scripts":{"build":"rimraf dist && rollup --config ./rollup.config.mjs","check":"tsc --noEmit --project ./tsconfig.prod.json","format:src":"eslint --fix ./src","format":"eslint --fix .","lint:src":"eslint ./src","lint":"eslint .","test":"jest --colors","test:watch":"jest --colors --watch"},"keywords":["promise","cancel","cancelable","async"],"unpkg":"dist/index.umd.min.js","jsdelivr":"dist/index.umd.min.js","typesVersions":{"<4.7":{"dist/types/*":["dist/types-ts4.2/*"]}},"gitHead":"3fcdda94f6abbb8e1eb0cb8c27b14e2f4386faed","_id":"@cancjs/promise@1.0.0","_nodeVersion":"22.23.1","_npmVersion":"12.0.2","dist":{"integrity":"sha512-Ez4MhJ7T09q87xNMW650VgE8jS/gP+Zm92WGaJH/M1mv9IDkyXZOnZboZen20PNUoOdS0ftNAD7227CzOu+2ng==","shasum":"12c29bc02a76707f59436c47dc151eccd1876e33","tarball":"https://registry.npmjs.org/@cancjs/promise/-/promise-1.0.0.tgz","fileCount":59,"unpackedSize":756685,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@cancjs%2fpromise@1.0.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQCFuzxe9ObvvyLRAdPMgBwtylf5qqYPPrgwiJa+IftCowIgQ76IC1hdKta+NvYUuoAhhC2XPwthx6rRTjMtPo4esBw="}]},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:073f5b27-91b3-4e56-be07-bda6139a069b"}},"directories":{},"maintainers":[{"name":"busybus","email":"busybus8@proton.me"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/promise_1.0.0_1785883286412_0.26167584683399947"},"_hasShrinkwrap":false}},"time":{"created":"2026-08-03T22:14:54.680Z","modified":"2026-08-04T22:41:27.015Z","1.0.0-beta.17":"2026-08-03T22:14:55.251Z","1.0.0-beta.18":"2026-08-04T08:46:20.997Z","1.0.0-beta.19":"2026-08-04T10:42:21.769Z","1.0.0-beta.20":"2026-08-04T20:03:46.777Z","1.0.0":"2026-08-04T22:41:26.597Z"},"bugs":{"url":"https://github.com/cancjs/canc/issues"},"author":{"name":"bisubus"},"license":"MIT","homepage":"https://github.com/cancjs/canc/tree/master/packages/canc-promise#readme","keywords":["promise","cancel","cancelable","async"],"repository":{"type":"git","url":"git+https://github.com/cancjs/canc.git","directory":"packages/canc-promise"},"description":"Cancelable promise implementation based on native Promise.","maintainers":[{"name":"busybus","email":"busybus8@proton.me"}],"readme":"<div align=\"center\">\n  <img src=\"https://raw.githubusercontent.com/cancjs/canc/master/assets/canc-logo.svg\" style=\"width: 400px; max-width: 100%; height: auto;\" title=\"canc &#x2BBF; A crafty foundation for cancelable promises\" alt=\"canc &#x2BBF; A crafty foundation for cancelable promises\">\n  <div>&nbsp;</div>\n</div>\n\n<h1 align=\"center\">@cancjs/promise</h1>\n\n<p align=\"center\">\nCancelable promise implementation based on native <code>Promise</code>.\n</p>\n\n---\n\n## Introduction\n\n`CancelablePromise` is a `Promise` with a `cancel()` method. It is built on the native\nimplementation, so it settles at the same microtask timing, works with `await`, and can be handed\nto any code that expects a promise.\n\nCancellation is a rejection with a `CancelError`, not a silent skip and not a promise that never\nsettles. Regular `try`/`catch` and `.catch()` keep working, and code that does not care about\ncancellation does not need to know it happened.\n\nThis package is the foundation of the `canc` ecosystem. On its own it covers the promise layer:\ncancelable chains, two-way propagation, combinators, cleanup. The rest of the ecosystem builds on\nit: [coroutines](https://github.com/cancjs/canc/tree/master/packages/canc-coroutine) replace\n`async`/`await` with generator functions that cancel at every yield point, the\n[toolbox](https://github.com/cancjs/canc/tree/master/packages/canc-toolbox) adds timing helpers,\nadapters and signal interop,\n[fetch](https://github.com/cancjs/canc/tree/master/packages/canc-fetch) wraps the Fetch API, and\n[decorators](https://github.com/cancjs/canc/tree/master/packages/canc-decorators) bring cancelable\ncoroutines to class methods. See the\n[repository](https://github.com/cancjs/canc) for the full ecosystem.\n\n## Features\n\n- cancelable promise built on top of native ES `Promise`\n- cancellation is a special rejection (`CancelError`), normal `try`/`catch`/`.then`/`.catch`\n  semantics preserved\n- two-way cancellation: propagates down the chain, bubbles back up when every consumer has\n  canceled and the value is unconsumed\n- combinators that cancel the promises whose results are no longer needed\n- `AbortSignal` interop in both directions\n- explicit resource management through `using` and `await using`\n- no dependencies\n\n## Getting Started\n\n### Installation\n\n```sh\nnpm install @cancjs/promise\n```\n\nThis package is core tier: it follows strict semver, so the default caret pin, `^1`, is safe. See\n[Versioning](https://github.com/cancjs/canc/blob/master/docs/versioning.md) for the full policy.\n\n### Usage\n\nThe executor receives a context object for registering cleanup and obtaining a signal. Cleanup\nruns when the promise is canceled:\n\n```js\nimport { CancelablePromise, isCancelError } from '@cancjs/promise';\n\nconst delayed = new CancelablePromise((resolve, reject, { handleCancel }) => {\n  const timerId = setTimeout(resolve, 1000, 'done');\n  handleCancel(() => clearTimeout(timerId));\n});\n\ndelayed\n  .then((value) => console.log(value))\n  .catch((err) => {\n    if (isCancelError(err)) {\n      console.log('canceled');\n      return;\n    }\n\n    throw err;\n  });\n\ndelayed.cancel();\n```\n\nCancellation applies to the whole chain, not to a single promise:\n\n```js\nconst report = loadOrders()\n  .then((orders) => buildReport(orders))\n  .then((rendered) => render(rendered));\n\n// Cancels the request, the report build, and the render step.\nreport.cancel();\n```\n\nCombinators keep the same behavior, and they stop the work whose result nobody will read:\n\n```js\nconst fastest = CancelablePromise.race([fetchPrimary(), fetchMirror()]);\n// When one wins, the other is canceled instead of running to completion.\n```\n\nFor most real tasks, you rarely need to write `new CancelablePromise` directly.\n[`cancelify` and `promisify`](https://github.com/cancjs/canc/tree/master/packages/canc-toolbox#adapters)\nwrap existing APIs into cancelable ones at the boundary, so the rest of your code works with\nplain cancellation without managing signals or constructors.\n\n## How It Works\n\n### Cancellation is a rejection\n\n`cancel(reason)` rejects the promise with a `CancelError`. The reason is normalized: a\n`CancelError` passes through unchanged, any other object becomes its `cause`, a string becomes its\nmessage. Handlers registered through `handleCancel` still receive the original reason.\n\nBecause it is an ordinary rejection, a canceled promise that nobody handles triggers\n`unhandledRejection` like any other. Import `@cancjs/unhandled-rejection/register` as the first\nline of your application entry point, or handle cancellation explicitly with `catchCancel`/`suppressCancel`\nat each call site. Library code should use `catchCancel`/`suppressCancel` instead of a global handler.\n\n### Down the chain\n\nCanceling a promise cancels everything derived from it. The pending step rejects with the\n`CancelError`, every step after it is skipped, and the registered cancel handlers of the canceled\nnode run so in-flight work can be torn down.\n\nDown-propagation cannot be intercepted. If an upstream promise is canceled, a downstream promise\nadopts that rejection, the same way it would adopt any other rejection. This is native `Promise`\nbehavior, and breaking it would break `try`/`catch`.\n\n### Up the chain\n\nA promise chain is treated as a subscription. Each derived promise counts as a consumer of its\nparent. When every consumer has been canceled and the parent's value is no longer wanted, the\nparent cancels itself and its own cleanup runs, so the original request does not keep going for\nnobody.\n\nBubbling is on by default. Turn it off per promise with `bubble: false` when the work has side\neffects that should not be discarded implicitly, for example a write that must complete once\nstarted.\n\n### Combinators\n\n`race` and `any` cancel the losers once a winner settles. `all` cancels the remaining inputs on\nthe first rejection. `allSettled` cancels nothing, by definition it waits for everything. Inputs\nconstructed with `bubble: false` are never canceled by this mechanism.\n\nCanceling a combinator result does not cascade into its inputs, because an input may be shared\nwith another consumer.\n\n### Disposal\n\nA pending promise cancels itself when it leaves a `using` or `await using` scope. The async form\nwaits for the cancel handlers to settle, so cleanup finishes before the scope exits. Disposing an\nalready settled promise, or a shielded one, is a no-op rather than an error.\n\n```js\nasync function loadReport(id) {\n  await using request = fetchReport(id);\n  return await request;\n  // Leaving the scope early, by return or by throw, cancels a request still in flight.\n}\n```\n\n### Coroutines\n\nA cancelable promise chain is cancelable, but `async`/`await` functions are not, because `await`\ndoes not pass control back in a way that can be interrupted.\n[Coroutines](https://github.com/cancjs/canc/tree/master/packages/canc-coroutine) solve this with\ngenerator functions that cancel at every `yield*` point, making deep cancelable flows practical\nwithout manual chaining.\n\n## Description\n\n### Options\n\nEvery option is accepted by the constructor and by the statics, and the current values are\nreadable through the `options` getter.\n\n| Option            | Default | Meaning                                                                                     |\n| ----------------- | ------- | ------------------------------------------------------------------------------------------- |\n| `bubble`          | `true`  | Cancellation bubbles to the parent when all consumers are canceled                          |\n| `asyncCancel`     | `true`  | `cancel()` settles failing cancel handlers asynchronously instead of throwing               |\n| `forceCancelable` | `true`  | The result stays cancelable even when the executor resolves with another promise            |\n| `strict`          | `false` | Throws on cancellation problems instead of ignoring them                                    |\n| `shield`          | `false` | Protects this promise's own work from cancellation coming from below or outside             |\n| `signal`          | none    | Cancels the promise when the signal aborts. One `AbortSignal` or an array, first abort wins |\n\n`shield` is an upward and self shield only. A direct `cancel()` becomes a no-op and a bubble\narriving from canceled children stops there, but a canceled or rejected upstream still propagates\ndown into a shielded promise. It is per promise and is not inherited by `then`-derived children.\n\nFlags are also exposed as writable properties (`promise.bubble = false`), and the class-wide\ndefaults live in `CancelablePromise.defaultOptions`.\n\n### Detecting cancellation\n\nUse the exported guards. They are brand-based, so they keep working across realms and across two\ncopies of the package in one dependency tree, which `instanceof` does not:\n\n```js\nimport { isCancelError, isCancPromise, isAggregateError } from '@cancjs/promise';\n```\n\n`isCancelError` matches the brand only: a foreign error merely named `CancelError` is never\ntreated as one. `isAggregateError` also falls back to `error.name`.\n\nA promise canceled through an `AbortSignal` rejects with a `CancelError` whose `cause` is the\nabort reason, not with a `DOMException`. Check `err.aborted`, or `err.timedOut` when the signal\ncame from `AbortSignal.timeout()`, on the `CancelError` when the difference matters. For standalone\nerror classes and guards (`AbortError`, `isAbortError`, `TimeoutError`, `isTimeoutError`), see\n`@cancjs/toolbox`.\n\n`CancelError` also carries `bubbled` (the cancellation came from the consumer side) and `disposed`\n(it came from leaving a `using` scope).\n\nThe underlying `Symbol.for` brand symbols are exported as `CANCEL_ERROR_BRAND` (`Symbol.for('@cancjs/promise:CancelError')`), `CANCEL_PROMISE_BRAND` (`Symbol.for('@cancjs/promise:CancelablePromise')`), and `CANCEL_SIGNAL_BRAND` (`Symbol.for('@cancjs/promise:CancelSignal')`).\n\n### Ending a cancelable flow\n\nAt the boundary where a flow is consumed, cancellation is usually an expected outcome rather than\nan error. Two helpers say so explicitly:\n\n```js\nconst outcome = await catchCancel(searchProducts(query));\n\nif (isCancelError(outcome)) {\n  showStatus('Search canceled');\n  return;\n}\n\nrender(outcome);\n```\n\n`suppressCancel(promise)` is the shorter form when the reason does not matter: it resolves to\n`undefined` on cancellation and rethrows everything else. Both accept options (like `{ bubble: false }`)\npassed through to the underlying promise, wire cancellation (canceling the result cancels the input promise),\nand accept either a promise or a raw caught error. Both also take `{ abort: true }` to treat an\n`AbortError` (or a `CancelError` caused by an abort) as an expected stop, and `{ timeout: true }` for\na `TimeoutError`.\n\nFor custom error matcher factories (`createSuppressError`, `createCatchError`) or standalone error filtering\nhelpers (`catchAbort`, `suppressAbort`, `catchTimeout`, `suppressTimeout`), see\n[`@cancjs/toolbox`](https://github.com/cancjs/canc/tree/master/packages/canc-toolbox).\n\n### AbortSignal interop\n\nPass an existing signal to have it cancel the promise. The listener is removed when the promise\nsettles, an already aborted signal cancels immediately, and an array composes several sources with\nfirst abort winning:\n\n```js\nconst quotes = new CancelablePromise(executor, {\n  signal: [userSignal, AbortSignal.timeout(5000)],\n});\n```\n\nInside the executor, `getSignal()` returns an `AbortSignal` that aborts when the promise is\ncanceled, so signal-aware APIs can be connected directly:\n\n```js\nconst data = new CancelablePromise((resolve, reject, { getSignal }) => {\n  fetch('/api/data', { signal: getSignal() }).then(resolve, reject);\n});\n```\n\nFor the other direction, `createCancelSignal()` mints a signal that aborts with a `CancelError`,\nso downstream code that only speaks `AbortSignal` still sees a genuine cancellation. The\n[toolbox](https://github.com/cancjs/canc/tree/master/packages/canc-toolbox) has the higher-level\nwrappers, including `cancelify` and `toAbortSignal`.\n\n### Awaiting cleanup\n\nBy default `cancel()` returns a promise that settles once every cancel handler has settled, so\ncleanup can be awaited when it matters:\n\n```js\nawait checkout.cancel();\n```\n\nHandlers start synchronously the moment the cancel takes effect, whatever triggered it. Only\nwaiting for their results is asynchronous. With `asyncCancel: false` handlers run synchronously\nand `cancel()` returns nothing.\n\n### Adopting a foreign promise\n\n`makeCancelable(promise)` wraps an existing promise so the chain around it is cancelable. If the\nwrapped promise has its own `cancel()` method, for example a Bluebird or p-cancelable promise,\ncanceling the wrapper calls through to it. If the wrapped promise is plain, canceling stops the\nchain from continuing but the underlying operation runs to completion. To add cancellation to a\nplain-promise API at its source, use\n[`cancelify` or `promisify`](https://github.com/cancjs/canc/tree/master/packages/canc-toolbox#adapters)\nfrom the toolbox.\n\n### Pluggable implementation\n\nEcosystem packages (toolbox, coroutine) pick which promise implementation to build on through a\nsmall registry exported here. Register one implementation at app startup and every consumer that\nhas no more specific override uses it:\n\n```js\nimport { setPromiseImpl, getPromiseImpl } from '@cancjs/promise';\n\nsetPromiseImpl(MyPromiseImpl); // default is CancelablePromise\ngetPromiseImpl(); // MyPromiseImpl\nsetPromiseImpl(); // clears the registration, back to CancelablePromise\n```\n\nConsumers resolve the implementation for each call in this order, highest first: a per-call\n`options.impl`, then the consumer's own class static, then this registry, then the built-in\n`CancelablePromise`. Per-call and static injection pass the implementation by reference, so they\nalways work. The registry is the convenience layer for the common case where one implementation\napplies process-wide.\n\n#### Troubleshooting: registration seems to be ignored\n\nThe registry is module state in this package. It works app-wide because ecosystem packages declare\n`@cancjs/promise` as a `peerDependency`, so the package manager installs a single shared copy. If\ntwo different versions end up in the same dependency tree, each carries its own registry: a\n`setPromiseImpl` call made through one copy is invisible to code reading through the other, and\nthe second copy silently falls back to its built-in default.\n\nSymptoms: `setPromiseImpl` runs without error but a consumer still uses `CancelablePromise`, or\n`getPromiseImpl()` returns a different value than the one that was set.\n\nFixes: keep `@cancjs/promise` deduplicated to one version, and run `npm ls @cancjs/promise` to\nconfirm a single copy. When a single copy cannot be guaranteed, pass the implementation through\nper-call options or a class static instead of relying on the registry.\n\n## API\n\n### `CancelablePromise`\n\n`new CancelablePromise(executor, options?)`, where `executor` is\n`(resolve, reject, context) => void`. The context object provides `handleCancel` for registering\ncleanup and `getSignal` for obtaining an `AbortSignal` tied to the promise. Also the default\nexport.\n\nStatics, each taking an optional trailing options argument: `all`, `allSettled`, `any`, `race`,\n`resolve`, `reject`, `withResolvers`, `try`. The options configure the promise the static returns,\nand combinator inputs are adopted with them.\n\nInstance methods: `then`, `catch`, `finally`, `handleCancel(onCancel, options?)`,\n`cancel(reason?)`, `[Symbol.dispose]`, `[Symbol.asyncDispose]`.\n\n`handleCancel` registers cleanup outside the executor and returns the promise, so it chains.\nWith `{ immediate: true }` the handler also fires when the promise is already canceled at\nregistration time.\n\nInstance getters: `canceled`, `cancelable`, `options`. The flags `bubble`, `asyncCancel`,\n`forceCancelable`, `strict` and `shield` are readable and writable.\n\nClass-wide defaults: `CancelablePromise.defaultOptions`.\n\n### `CancelError`\n\n`new CancelError(reason?, { cause })`. Properties: `name`, `message`, `cause`, `bubbled`,\n`disposed`, and the `aborted` and `timedOut` getters, true when the cause is an abort or a\ntimeout respectively.\n\n### Helpers\n\n`isCancelError(error)`, `isCancPromise(value)`, `isAggregateError(error)`, `isCancelSignal(value)`,\n`catchCancel(promiseOrError, options?)`, `suppressCancel(promiseOrError, options?)`,\n`makeCancelable(promise, options?)`, `createCancelSignal(reason?)`.\n\n`catchCancel` and `suppressCancel` take promise options (e.g. `{ bubble: false }`), pass cancellation\ndown to the input promise, and accept either a promise or a caught error. They also accept `{ abort: true }`\nto match an abort and `{ timeout: true }` to match a timeout.\n\n`AggregateError` is exported for use with `CancelablePromise.any`. Other error classes, guards, and matcher\nfactories (`AbortError`, `isAbortError`, `TimeoutError`, `isTimeoutError`, `createCatchError`,\n`createSuppressError`) are published by `@cancjs/toolbox`.\n\n### Implementation registry\n\n`setPromiseImpl(impl?)`, `getPromiseImpl()`, `resolvePromiseImpl(options?, staticImpl?)`.\n\n## Compatibility\n\n`CancelablePromise` implements `Promise` methods up to ES2026 and needs only an ES2015-compliant\n`Promise` to work correctly. No method polyfills are necessary in older environments. Signal\ninterop (`signal` option, `createCancelSignal`) additionally requires a spec-compliant\n`AbortController`.\n\nNode.js 18 and later is the tested and supported baseline, declared in `engines`. Current browsers\nare supported out of the box. TypeScript 4.2 and later. Two type variants ship and the right one\nis selected automatically.\n\nFour builds are produced from the same ES5-targeted source, only the module wrapper differs:\n`dist/index.cjs` for `require`, `dist/index.mjs` for `import` and bundlers, `dist/index.umd.js`\nand `dist/index.umd.min.js` for `<script>` tags and CDNs.\n\nBecause the output is ES5, it also runs on engines outside the test matrix, including embedded\nones such as QuickJS, XS and Hermes.\n\n## Documentation\n\n- [Coroutines](https://github.com/cancjs/canc/tree/master/packages/canc-coroutine) for the\n  `async`/`await` replacement built on this package\n- [Toolbox](https://github.com/cancjs/canc/tree/master/packages/canc-toolbox) for timing helpers,\n  adapters and signal interop\n- [Fetch](https://github.com/cancjs/canc/tree/master/packages/canc-fetch) for cancelable requests\n- [Examples](https://github.com/cancjs/canc/tree/master/examples) for runnable projects, starting\n  with `demo-promise-basics` and `demo-chain-propagation`\n- [Repository](https://github.com/cancjs/canc) for the ecosystem overview\n\n## Contributing\n\nYou are welcome to participate through issues and pull requests!\n\n## License\n\n[MIT](./LICENSE)\n","readmeFilename":"README.md"}