{"_id":"@dacodedbeat/with-defer-js","_rev":"4-fa9ae89de7698d2ac5f65cfcea284830","name":"@dacodedbeat/with-defer-js","dist-tags":{"latest":"1.1.0"},"versions":{"0.0.1":{"name":"@dacodedbeat/with-defer-js","version":"0.0.1","author":{"name":"Arun Philip","email":"dacodedbeat@gmail.com"},"license":"MPL-2.0","_id":"@dacodedbeat/with-defer-js@0.0.1","maintainers":[{"name":"dacodedbeat","email":"dacodedbeat@gmail.com"}],"dist":{"shasum":"c62db2ad782eeb84d5d9573ddb466f59fa4b9d6e","tarball":"https://registry.npmjs.org/@dacodedbeat/with-defer-js/-/with-defer-js-0.0.1.tgz","fileCount":9,"integrity":"sha512-C/amKjLc7zn16CMjx06cNyVevZv/lrFvu9Tg7OZUpuhj/QqfdSulu9S+NlcNLfqK9vFZr/XS550cIhCjFr1C5A==","signatures":[{"sig":"MEYCIQC2Y7M3lxl3fSXGGpBekAUhuU5/E3GnHaloeT4CPtn1eAIhANGSWDbwg8uwmShVjQux5d8AIhtPWmFQGM+EcQb6JRGS","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":30579},"main":"index.js","type":"module","gitHead":"059aaf5f579b6fc26811a4d1ed10364a8dcd50d0","scripts":{"lint":"biome check .","test":"vitest"},"_npmUser":{"name":"dacodedbeat","email":"dacodedbeat@gmail.com"},"_npmVersion":"10.7.0","description":"A simple and lightweight JavaScript library for scheduling deferred function callbacks to execute after a function, like Golang.","directories":{},"_nodeVersion":"20.14.0","_hasShrinkwrap":false,"devDependencies":{"vitest":"^2.1.3","typescript":"^5.6.3","@biomejs/biome":"^1.9.3"},"_npmOperationalInternal":{"tmp":"tmp/with-defer-js_0.0.1_1729058403813_0.06046210488850745","host":"s3://npm-registry-packages"}},"0.0.2":{"name":"@dacodedbeat/with-defer-js","version":"0.0.2","author":{"name":"Arun Philip","email":"dacodedbeat@gmail.com"},"license":"MPL-2.0","_id":"@dacodedbeat/with-defer-js@0.0.2","maintainers":[{"name":"dacodedbeat","email":"dacodedbeat@gmail.com"}],"homepage":"https://github.com/dacodedbeat/with-defer-js#readme","bugs":{"url":"https://github.com/dacodedbeat/with-defer-js/issues"},"dist":{"shasum":"54d2a29957b8aedd977f0ece4437c667ea28e476","tarball":"https://registry.npmjs.org/@dacodedbeat/with-defer-js/-/with-defer-js-0.0.2.tgz","fileCount":4,"integrity":"sha512-+V33IUwlc72RYSYpTIpt5cvf61kXqtSKeHAvcGLPrqi2uWxWeDuI0DTJOitvM8WypN037RtvfZG7+yhlzmBEEA==","signatures":[{"sig":"MEUCIC8oUDbL8gG+KfGgHZHTuCo8d8fzo45eQr6pgnI8ul0sAiEAuEJjjmYuNfgSdKlrDp4jHH7uVfJ0YRKdp2OQWb49Ztg=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":27333},"main":"index.js","type":"module","gitHead":"73018d4f151bc5735af4d7ff2a12b92a200321ac","scripts":{"lint":"biome check .","test":"vitest"},"_npmUser":{"name":"dacodedbeat","email":"dacodedbeat@gmail.com"},"repository":{"url":"git+https://github.com/dacodedbeat/with-defer-js.git","type":"git"},"_npmVersion":"10.7.0","description":"A simple and lightweight JavaScript library for scheduling deferred function callbacks to execute after a function, like Golang.","directories":{},"_nodeVersion":"20.14.0","_hasShrinkwrap":false,"devDependencies":{"vitest":"^2.1.3","typescript":"^5.6.3","@biomejs/biome":"^1.9.3"},"_npmOperationalInternal":{"tmp":"tmp/with-defer-js_0.0.2_1729059465658_0.3035210431160942","host":"s3://npm-registry-packages"}},"1.0.0":{"name":"@dacodedbeat/with-defer-js","version":"1.0.0","keywords":["defer","cleanup","javascript","async","promise","golang","error-handling","timeout","cancellation"],"author":{"name":"Arun Philip","email":"dacodedbeat@gmail.com"},"license":"MPL-2.0","_id":"@dacodedbeat/with-defer-js@1.0.0","maintainers":[{"name":"dacodedbeat","email":"dacodedbeat@gmail.com"}],"homepage":"https://github.com/DAcodedBEAT/with-defer-js#readme","bugs":{"url":"https://github.com/DAcodedBEAT/with-defer-js/issues"},"dist":{"shasum":"ad317a43154ebec61d6be70f10af208c501eedd4","tarball":"https://registry.npmjs.org/@dacodedbeat/with-defer-js/-/with-defer-js-1.0.0.tgz","fileCount":5,"integrity":"sha512-dPT9huvy8JbTG/acU26yWwlo7BBDgq6BZ9dHyHCaNoCS+swEhYWtjwbYCRBII+OA4LbSLuztoApTgOruP9gnQQ==","signatures":[{"sig":"MEQCIEwsCfV1T33bd/HlRV0kIzea9MMlRmpyxNGKPDPzYI9VAiBB4k5JdHrs78NNQkblMQmbZnYNWlu8gMlvJYwsIPoA+A==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@dacodedbeat%2fwith-defer-js@1.0.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":41703},"main":"src/with-defer.js","type":"module","types":"./src/with-defer.d.ts","engines":{"node":">=16.0.0"},"exports":{".":{"types":"./src/with-defer.d.ts","import":"./src/with-defer.js"}},"gitHead":"453b81b7ddb545562490151450461fcaabd5bd8b","scripts":{"lint":"biome check .","test":"vitest","prepack":"npm run lint && npm run typecheck && npm run test:run && npm run generate:types","lint:fix":"biome check . --write","test:run":"vitest --run --reporter=verbose","typecheck":"tsc --noEmit","test:coverage":"vitest --coverage","generate:types":"tsc"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:a00ce70c-6a30-4032-8fe3-cd8161a74968"}},"repository":{"url":"git+https://github.com/DAcodedBEAT/with-defer-js.git","type":"git"},"_npmVersion":"11.7.0","description":"A simple and lightweight JavaScript library for scheduling deferred function callbacks to execute after a function, like Golang.","directories":{},"_nodeVersion":"24.12.0","_hasShrinkwrap":false,"devDependencies":{"vitest":"^4.0.16","typescript":"^5.9.3","@biomejs/biome":"^2.3.10","semantic-release":"^25.0.2","@semantic-release/git":"^10.0.1","@semantic-release/changelog":"^6.0.3"},"_npmOperationalInternal":{"tmp":"tmp/with-defer-js_1.0.0_1766109121368_0.6274993316412034","host":"s3://npm-registry-packages-npm-production"}},"1.1.0":{"_id":"@dacodedbeat/with-defer-js@1.1.0","bugs":{"url":"https://github.com/DAcodedBEAT/with-defer-js/issues"},"dist":{"shasum":"6022c18e3c40b641f6e69f28641009c2431f2834","tarball":"https://registry.npmjs.org/@dacodedbeat/with-defer-js/-/with-defer-js-1.1.0.tgz","fileCount":7,"integrity":"sha512-2eS8cttKOpJsNStGQ5ZaitjgyxmLWKn5DnyTrbpdSomM/p2LxYurPRGAtunQQAD1eijwkZA7R+eNiYOB7IGTiw==","signatures":[{"sig":"MEUCIQD2XmqdOhSX/DnsbHW9ZngvSIL+NBfQgKMSLyqP1TkKdgIgR00YL0Gf0o89wNRMCiptYIkpZryCxrSxOh807+jQrdA=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIHRk/W9tpDRx/fUmlrsaAm5AAhsizUKPinlUwtXrs+6PAiBpcbuxyVW00dN3SjtwzkJHWKb0x9GynhMPyf9dSSK3tA=="}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@dacodedbeat%2fwith-defer-js@1.1.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":69435},"main":"dist/cjs/with-defer.js","name":"@dacodedbeat/with-defer-js","type":"module","author":{"name":"Arun Philip","email":"dacodedbeat@gmail.com"},"engines":{"node":"^20.0.0 || ^22.0.0 || >=24.0.0"},"exports":{".":{"types":"./src/with-defer.d.ts","import":"./src/with-defer.js","default":"./src/with-defer.js","require":"./dist/cjs/with-defer.js"}},"gitHead":"4643aedbe9dfd510ada77dae0403d6f0c6e921a4","license":"MPL-2.0","scripts":{"fmt":"oxfmt --check .","lint":"oxlint .","test":"vitest","build":"npm run generate:types && npm run build:cjs","check":"npm run lint && npm run fmt","fmt:fix":"oxfmt .","prepack":"npm run check && npm run typecheck && npm run test:run && npm run build","lint:fix":"oxlint --fix .","test:run":"vitest --run --reporter=verbose","build:cjs":"tsc -p tsconfig.cjs.json && echo '{\"type\":\"commonjs\"}' > dist/cjs/package.json","check:fix":"npm run lint:fix && npm run fmt:fix","typecheck":"tsc --noEmit","test:coverage":"vitest --coverage","generate:types":"tsc && oxfmt src/with-defer.d.ts"},"version":"1.1.0","_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:a00ce70c-6a30-4032-8fe3-cd8161a74968"}},"homepage":"https://github.com/DAcodedBEAT/with-defer-js#readme","keywords":["async","cancellation","cleanup","defer","error-handling","golang","javascript","promise","timeout"],"repository":{"url":"git+https://github.com/DAcodedBEAT/with-defer-js.git","type":"git"},"_npmVersion":"11.19.1","description":"A simple and lightweight JavaScript library for scheduling deferred function callbacks to execute after a function, like Golang.","directories":{},"maintainers":[{"name":"dacodedbeat","email":"dacodedbeat@gmail.com"}],"_nodeVersion":"24.20.0","_hasShrinkwrap":false,"devDependencies":{"oxfmt":"*","oxlint":"*","vitest":"^4.1.11","typescript":"^6.0.2","semantic-release":"^25.0.9","@vitest/coverage-v8":"^4.1.11","@semantic-release/git":"^10.0.1","@semantic-release/changelog":"^6.0.3"},"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/with-defer-js_1.1.0_1789510888669_0.3205259530299822"}}},"time":{"created":"2024-10-16T06:00:03.620Z","modified":"2026-09-15T22:21:29.148Z","0.0.1":"2024-10-16T06:00:04.026Z","0.0.2":"2024-10-16T06:17:45.843Z","1.0.0":"2025-12-19T01:52:01.576Z","1.1.0":"2026-09-15T22:21:28.752Z"},"bugs":{"url":"https://github.com/DAcodedBEAT/with-defer-js/issues"},"author":{"name":"Arun Philip","email":"dacodedbeat@gmail.com"},"license":"MPL-2.0","homepage":"https://github.com/DAcodedBEAT/with-defer-js#readme","keywords":["async","cancellation","cleanup","defer","error-handling","golang","javascript","promise","timeout"],"repository":{"url":"git+https://github.com/DAcodedBEAT/with-defer-js.git","type":"git"},"description":"A simple and lightweight JavaScript library for scheduling deferred function callbacks to execute after a function, like Golang.","maintainers":[{"name":"dacodedbeat","email":"dacodedbeat@gmail.com"}],"readme":"# `with-defer.js`\n\n[![npm version](https://img.shields.io/npm/v/@dacodedbeat/with-defer-js.svg)](https://www.npmjs.com/package/@dacodedbeat/with-defer-js)\n[![License: MPL 2.0](https://img.shields.io/badge/License-MPL_2.0-brightgreen.svg)](https://opensource.org/licenses/MPL-2.0)\n[![Formatted with oxfmt](https://img.shields.io/badge/Formatted_with-oxfmt-orange?style=flat)](https://oxc.rs/docs/guide/usage/formatter)\n\n**`with-defer.js`** is a simple and lightweight JavaScript library that allows you to schedule function callbacks after\nthe execution of a function, just like Golang’s `defer`. Perfect for cleanup tasks, error handling, and more for both\nasynchronous and synchronous operations.\n\n## Why `with-defer.js`?\n\nInspired by Golang’s `defer`, this library gives you the same power in JavaScript.\n\nIn Go, `defer` lets you schedule a function to run after the current function ends - whether it finishes normally or\nwith an error. This is useful for tasks like closing files or releasing resources without messing up the main flow of\nthe program.\n\nIn JavaScript, especially with async operations, you often need similar cleanup tasks, but there's no built-in `defer`\nkeyword. This library brings the simplicity of Go's defer to JavaScript.\n\nTL;DR: Stack up tasks, run them after your main code finishes (even if it crashes), and keep your code tidy.\n\n### Golang vs. `with-defer.js`\n\n#### Golang:\n\n```go\nfunc main() {\n    defer cleanup1()\n    defer cleanup2()\n    // do stuff\n}\n```\n\n#### `with-defer.js`:\n\n```javascript\nimport { withDefer } from \"@dacodedbeat/with-defer-js\";\n\nconst mainFunction = (defer) => {\n\tdefer(() => console.log(\"Cleanup 1\"));\n\tdefer(() => console.log(\"Cleanup 2\"));\n\t// do stuff\n};\n\nwithDefer(mainFunction)();\n```\n\n#### How the two align\n\n1. **Automatic Execution After Function Ends:** Just like in Go, functions in `with-defer.js` run after the main\n   function finishes, whether it succeeds or fails. This makes sure cleanup tasks are done.\n\n2. **Last-In, First-Out Execution:** Deferred functions in both Go and `with-defer.js` run in reverse/LIFO(Last-In,\n   First-Out) order, meaning the last function added runs first. This helps with cleaning up resources in the correct\n   order.\n\n3. **User-Friendly API:** The `defer()` in `with-defer.js` is similar to Go’s, making it easy to use for scheduling\n   functions in JavaScript.\n\n4. **`recover()` + named-return mutation:** Just like Go's `recover()` inside a deferred function can stop a panic and\n   set the function's named return value, a deferred callback here can inspect the main function's pending\n   error/return value via a `RunContext` argument and call `ctx.recover(value)` to suppress the error and/or change\n   what `withDefer()` ultimately resolves with. See [Recovering from errors](#recovering-from-errors--named-return-mutation) below.\n\nSame vibe, right?\n\n#### A note on argument evaluation timing\n\nOne place Go and `with-defer.js` genuinely differ: Go's `defer f(x)` evaluates `x` **immediately** at the `defer`\nline — only the call itself is delayed. A JS closure captures variables live, so `defer(() => f(x))` reads `x`'s\nvalue at _execution_ time, which matters if `x` changes afterward:\n\n```javascript\nlet x = 1;\ndefer(() => console.log(x)); // logs 2, not 1 - x is read when the deferred runs\nx = 2;\n```\n\nTo snapshot a value the way Go does, capture it into its own binding at `defer()`-call time:\n\n```javascript\nconst snapshotX = x;\ndefer(() => console.log(snapshotX)); // logs 1, exactly like Go\n```\n\n## Features\n\n- Stack up deferred functions to run after your main code.\n- Set timeouts and cancel deferred tasks.\n- Built-in error reporting with optional error throwing.\n- Optional debug mode for the curious souls.\n- Full TypeScript support with complete type definitions.\n- Production ready with comprehensive input validation.\n- Well tested with extensive edge case coverage.\n\n## Install\n\n### npm\n\n```bash\nnpm install @dacodedbeat/with-defer-js\n```\n\n### Deno\n\n```bash\nimport { withDefer } from 'npm:@dacodedbeat/with-defer-js';\n```\n\n### Bun\n\n```bash\nbun add @dacodedbeat/with-defer-js\n```\n\nShips as both ESM and CommonJS — `import` gets the ESM source directly; `require()` gets a generated CJS build\n(`dist/cjs/with-defer.js`, produced by `npm run build`). Both expose the same API.\n\n## Usage\n\nWrap your function with `withDefer` and use `defer` to schedule tasks.\n\n```javascript\nimport { withDefer } from \"@dacodedbeat/with-defer-js\";\n\nconst mainFunction = async (defer) => {\n\tdefer(() => console.log(\"Deferred task!\"), { timeout: 5000 });\n\n\tconsole.log(\"Doing main stuff!\");\n};\n\nwithDefer(mainFunction)();\n```\n\n### TypeScript Usage\n\n```typescript\nimport { withDefer, type DeferFunction } from \"@dacodedbeat/with-defer-js\";\n\nconst mainFunction = async (defer: DeferFunction) => {\n\tdefer(() => console.log(\"Cleanup complete!\"));\n\n\t// Your main logic here\n\treturn \"Success!\";\n};\n\nawait withDefer(mainFunction)();\n```\n\n### Options\n\n> [!IMPORTANT]\n> When implementing, please verify this with the your installed version of the source code, as this is can change over\n> time.\n\nSet options when you wrap your function, as well as on each deferred callback:\n\n| Option          | Type       | Default | Description                                  |\n| --------------- | ---------- | ------- | -------------------------------------------- |\n| `timeout`       | `number`   | `null`  | Max time (ms) for deferred functions.        |\n| `debug`         | `boolean`  | `false` | Debug mode.                                  |\n| `throwOnError`  | `boolean`  | `false` | Throw error if a deferred function fails.    |\n| `errorReporter` | `function` | `null`  | Custom error handler for deferred functions. |\n\n## Error Handling & Debugging\n\n- Use `throwOnError` to fail hard if a deferred function crashes.\n- Use `errorReporter` for custom error handling.\n- Enable `debug` to get logs.\n\n## Cancel a Deferred Task\n\n```javascript\nconst { cancel } = defer(() => console.log('This won't run if canceled.'));\ncancel();\n```\n\n## Execution Guarantees\n\n### Return Value Capture\n\nYour main function's return value is captured and available when `withDefer()` resolves:\n\n```javascript\nconst example = withDefer(async (defer) => {\n\tdefer(() => console.log(\"cleanup\"));\n\treturn { userId: 123 };\n});\n\nconst result = await example();\n// result === { userId: 123 }\n// Cleanup has already executed\n```\n\n### Execution Order\n\nDeferreds execute in **LIFO (Last-In-First-Out)** order, matching Go's defer semantics:\n\n```javascript\nconst example = withDefer(async (defer) => {\n\tdefer(() => console.log(\"3. First registered\"));\n\tdefer(() => console.log(\"2. Second registered\"));\n\tdefer(() => console.log(\"1. Third registered\"));\n});\n\nawait example();\n// Output:\n// 1. Third registered\n// 2. Second registered\n// 3. First registered\n```\n\n### Recovering from Errors & Named-Return Mutation\n\nEvery deferred callback optionally receives a `RunContext` argument reflecting the main function's pending outcome —\nmirroring Go's `recover()` (which can stop a panic) and named-return mutation (which can change what the function\nreturns), both in one mechanism:\n\n```typescript\ntype RunContext = {\n\thasError: boolean; // true if the main function threw/rejected and hasn't been recovered yet\n\terror: unknown; // the pending error, meaningful only when hasError is true\n\tvalue: unknown; // the pending return value, meaningful only when hasError is false\n\trecover: (newValue: unknown) => void; // suppress the error (if any) and set the final return value\n};\n```\n\n**Recovering a thrown error** (like Go's `defer func() { if r := recover(); r != nil { ... } }()`):\n\n```javascript\nconst example = withDefer(async (defer) => {\n\tdefer((ctx) => {\n\t\tif (ctx.hasError) {\n\t\t\tconsole.error(\"recovered from:\", ctx.error);\n\t\t\tctx.recover(\"fallback value\");\n\t\t}\n\t});\n\n\tthrow new Error(\"boom\");\n});\n\nawait example(); // resolves \"fallback value\" instead of rejecting\n```\n\n**Mutating the return value on success** (like Go's named-return mutation):\n\n```javascript\nconst example = withDefer(async (defer) => {\n\tdefer((ctx) => {\n\t\tctx.recover(ctx.value + 1);\n\t});\n\n\treturn 1;\n});\n\nawait example(); // resolves 2\n```\n\nDeferreds run LIFO, so `ctx` always reflects whatever the most-recently-executed (i.e. earlier-registered) deferred\nalready did — the last deferred to call `recover()` wins, matching Go's semantics where an outer deferred's\n`recover()`/return-mutation is the one that's actually observed by the caller. Callbacks that don't declare the `ctx`\nparameter are unaffected — this is fully backward compatible.\n\n> [!IMPORTANT]\n>\n> - **Call `recover()` synchronously within your callback, before it settles.** Once a deferred's own callback has\n>   settled — including a callback that lost its `timeout` race but keeps running in the background afterward — any\n>   later `recover()` call from it is a no-op. `recover()` is for the deferred that's currently running to decide the\n>   outcome, not for a stale, already-finished (or abandoned) one to reach back and change it.\n> - **A deferred's own failure and `recover()` are independent.** `recover()` only affects what `run()` itself\n>   resolves/rejects with. If that same deferred (or any other) also throws and has `throwOnError: true`, the\n>   resulting `AggregateError` is still thrown — a successful `recover()` does not suppress a separately-reported\n>   deferred failure. Without `throwOnError`, the deferred's own error is just reported via `errorReporter`/`debug` as\n>   usual, and the `recover()` call's effect on the final value still stands.\n\n### Error Handling\n\nWhen errors occur in deferred functions:\n\n1. Debug logging (if enabled)\n2. Error reporter callback (if provided)\n3. Error aggregation and optional throwing\n\nErrors don't mutate original error objects; use `.cause` property to access the original error:\n\n```javascript\ntry {\n\tawait example();\n} catch (aggErr) {\n\tif (aggErr instanceof AggregateError) {\n\t\tconst wrappedErr = aggErr.errors[0];\n\t\tconst originalErr = wrappedErr.cause; // Original error preserved\n\t}\n}\n```\n\n> [!IMPORTANT]\n> The `promise` returned by `defer()` **always resolves**, even when the deferred callback throws, times out, or is\n> cancelled — it never rejects. On failure it resolves with the raw error value (check with `instanceof Error`); on\n> cancellation it resolves with the string `\"deferred function was cancelled\"`. Use `throwOnError` and/or\n> `errorReporter` at the `withDefer()`/`defer()` level to be notified of failures — don't rely on `.catch()` on an\n> individual deferred's `promise`.\n\n### Timeout Precision\n\nTimeouts are implemented with `setTimeout()`, which has platform-dependent precision:\n\n- **Node.js:** ±1-5ms typical\n- **Browser:** ±1-10ms typical\n- **Electron:** ±5-15ms typical\n\nTimeouts are properly cleaned up after completion and never fire before the specified interval.\n\n> [!IMPORTANT]\n> A timeout only stops **waiting** for the callback — it does not abort or cancel the callback itself. If a timed-out\n> deferred callback is still running (e.g. an in-flight `await`), it keeps executing in the background after the\n> timeout is reported, and its eventual result/rejection is discarded. There is no `AbortSignal` passed into deferred\n> callbacks today; if your cleanup needs real cancellation, wire your own `AbortController` through the callback.\n\n### Important Limitation: Fire-and-Forget Async Operations\n\nIf a deferred callback returns a promise that rejects **after** the deferred execution phase completes, the rejection is not caught:\n\n```javascript\n// ❌ BAD: Unhandled promise rejection\ndefer(() => {\n\tsetTimeout(() => Promise.reject(new Error(\"late error\")), 100);\n});\n\n// ✅ GOOD: Await all async operations\ndefer(async () => {\n\tawait fetch(\"/cleanup\");\n});\n\n// ✅ GOOD: Explicitly handle unhandled rejections\ndefer(() => {\n\tfetch(\"/cleanup\").catch((err) => console.error(\"failed:\", err));\n});\n```\n\n### Concurrency\n\nMultiple `withDefer()` calls are independent and don't interfere with each other:\n\n```javascript\nconst [result1, result2] = await Promise.all([\n\twithDefer(async (defer) => {\n\t\tdefer(() => db.close());\n\t\treturn \"db cleaned\";\n\t})(),\n\twithDefer(async (defer) => {\n\t\tdefer(() => server.close());\n\t\treturn \"server cleaned\";\n\t})(),\n]);\n// Both execute in parallel, independently\n```\n\n## Breaking Changes (v0.0.3)\n\nThis release makes `with-defer.js` truly concurrent-safe and Go-compatible:\n\n- **Isolated defer stacks per invocation:** Each call to `withDefer(fn)()` now gets its own independent defer queue, preventing interference between concurrent calls\n- **Sequential LIFO execution:** Deferreds now execute sequentially in LIFO order instead of concurrently, matching Go's semantics\n- **No nested defer calls:** Calling `defer()` during deferred execution now throws an error instead of silently failing\n\n**Migration:** If your code relied on concurrent deferred execution, you'll need to adjust expectations. Deferreds now execute strictly in order, one at a time, in LIFO (Last-In-First-Out) order - just like Go.\n\n## Contributing\n\nIf you'd like to contribute to `with-defer.js`, we welcome your input! Please read\nour [Contributing Guidelines](https://github.com/DAcodedBEAT/with-defer-js/blob/main/CONTRIBUTING.md) to get started.\n\n## License\n\n`with-defer.js` is licensed under the Mozilla Public License 2.0. See the [\n`LICENSE`](https://github.com/DAcodedBEAT/with-defer-js/blob/main/LICENSE) file for more details.\n","readmeFilename":"README.md"}