{"_id":"@cvzxeov/lite-saga","_rev":"6-7d1c69dba57588ea87df0228126323dd","name":"@cvzxeov/lite-saga","dist-tags":{"latest":"1.2.0"},"versions":{"1.0.1":{"name":"@cvzxeov/lite-saga","version":"1.0.1","keywords":["saga","transactions","rollback","typescript","promise","state-machine"],"author":{"name":"Awesome Developer"},"license":"MIT","_id":"@cvzxeov/lite-saga@1.0.1","maintainers":[{"name":"cvzxeov","email":"artur.mutsueff@yandex.ru"}],"dist":{"shasum":"61b2b780ec06f941e0ff9aa65c68ed81adc2f012","tarball":"https://registry.npmjs.org/@cvzxeov/lite-saga/-/lite-saga-1.0.1.tgz","fileCount":27,"integrity":"sha512-TS2m7EE6QR4MUXt33jRgGPP1VMNvRCJ3v3fxJo5sMjULNX7bz8ld+cCoV70U5tqSKnnfxsX4Yml864djzMQEGQ==","signatures":[{"sig":"MEUCIQDkDDXJ33iRSFqVhgeUJZCte8zfeuRX3vaTXnnWXf2r7gIgZcJR7gRe1EDVnYJOcECY/y/hCgfr/97he3omtYQTy8Y=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":46579},"main":"dist/index.js","types":"dist/index.d.ts","gitHead":"30adb308c8260b8e890f6aa89eebc7c0f7b24c12","scripts":{"test":"echo \"Error: no test specified\" && exit 1","build":"tsc","prepublishOnly":"npm run build"},"_npmUser":{"name":"cvzxeov","email":"artur.mutsueff@yandex.ru"},"_npmVersion":"10.9.3","description":"Magical, zero-dependency, strongly typed Saga pattern (compensating transactions) for Node.js and Browser.","directories":{},"_nodeVersion":"22.19.0","_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.0.0"},"_npmOperationalInternal":{"tmp":"tmp/lite-saga_1.0.1_1781311119069_0.6109510276027084","host":"s3://npm-registry-packages-npm-production"}},"1.0.2":{"name":"@cvzxeov/lite-saga","version":"1.0.2","keywords":["saga","transactions","rollback","typescript","promise","state-machine"],"author":{"name":"Awesome Developer"},"license":"MIT","_id":"@cvzxeov/lite-saga@1.0.2","maintainers":[{"name":"cvzxeov","email":"artur.mutsueff@yandex.ru"}],"dist":{"shasum":"14688dd8011dd3b2034b5ee167f0b8d96a43791e","tarball":"https://registry.npmjs.org/@cvzxeov/lite-saga/-/lite-saga-1.0.2.tgz","fileCount":27,"integrity":"sha512-BgBMcRfqaR9Xl8g8/35L8jIlYqi+RJ1YN11dAEWmlRd6tO+vnt/Z3M8vPI2suApJgw2BABYNbzKJbqNkfBOTcw==","signatures":[{"sig":"MEYCIQDTftHMXdaAzyj1T40Lut0jzbr41Xu0RQ5xkFXFurdIWgIhAPZ63cRNqZ6cGlPXqBDeNKnVtXoXj9Hn1K76CAULvJMq","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":46432},"main":"dist/index.js","types":"dist/index.d.ts","gitHead":"e9d704ad0100481fc34acd6b441c93070740ee5e","scripts":{"test":"echo \"Error: no test specified\" && exit 1","build":"tsc","prepublishOnly":"npm run build"},"_npmUser":{"name":"cvzxeov","email":"artur.mutsueff@yandex.ru"},"_npmVersion":"10.9.3","description":"Magical, zero-dependency, strongly typed Saga pattern (compensating transactions) for Node.js and Browser.","directories":{},"_nodeVersion":"22.19.0","_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.0.0"},"_npmOperationalInternal":{"tmp":"tmp/lite-saga_1.0.2_1781311704685_0.11781009184695623","host":"s3://npm-registry-packages-npm-production"}},"1.0.3":{"name":"@cvzxeov/lite-saga","version":"1.0.3","keywords":["saga","transactions","rollback","typescript","promise","state-machine"],"author":{"name":"Awesome Developer"},"license":"MIT","_id":"@cvzxeov/lite-saga@1.0.3","maintainers":[{"name":"cvzxeov","email":"artur.mutsueff@yandex.ru"}],"dist":{"shasum":"a38046ef2bb4ea6c3593e00466a6f57b9e47ea48","tarball":"https://registry.npmjs.org/@cvzxeov/lite-saga/-/lite-saga-1.0.3.tgz","fileCount":27,"integrity":"sha512-xmj/Ko9JbXtpc6mhKVLRMa5ukfujnsJV6rcqfbhSOGM4+gV3sWsqvorMrm4Q3IF7TVZFKmViceWw26+jWBUVMg==","signatures":[{"sig":"MEYCIQCbNoJ8hzYnfSOP4/1J0sn9hmP5SOyHvkgXVZU8K68CGwIhAKTeAQ6PM+u/DCKo1yuYG+8gN7nSTaA2oFy4SiszE5RZ","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":46432},"main":"dist/index.js","types":"dist/index.d.ts","gitHead":"5850dd77a019c0e5d08bff512a1b878884e99608","scripts":{"test":"echo \"Error: no test specified\" && exit 1","build":"tsc","prepublishOnly":"npm run build"},"_npmUser":{"name":"cvzxeov","email":"artur.mutsueff@yandex.ru"},"_npmVersion":"10.9.3","description":"Magical, zero-dependency, strongly typed Saga pattern (compensating transactions) for Node.js and Browser.","directories":{},"_nodeVersion":"22.19.0","_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.0.0"},"_npmOperationalInternal":{"tmp":"tmp/lite-saga_1.0.3_1781311784417_0.557678102236107","host":"s3://npm-registry-packages-npm-production"}},"1.0.4":{"name":"@cvzxeov/lite-saga","version":"1.0.4","keywords":["saga","transactions","rollback","typescript","promise","state-machine","microservices","distributed-transactions","compensating-transactions","orchestration"],"author":{"name":"Awesome Developer"},"license":"MIT","_id":"@cvzxeov/lite-saga@1.0.4","maintainers":[{"name":"cvzxeov","email":"artur.mutsueff@yandex.ru"}],"dist":{"shasum":"276a905d2289b5ebd29e3ea6a1298cfdabd71e7c","tarball":"https://registry.npmjs.org/@cvzxeov/lite-saga/-/lite-saga-1.0.4.tgz","fileCount":27,"integrity":"sha512-MfsUtJAFf3xVOaTFUwxDbJWHokTW2uFkEiz69M4ksmIlYJgyRqnYGsBVcdkdi1HjY6zGGHHjzJhs4yNQR7LgDA==","signatures":[{"sig":"MEQCIFzO+qm7I4coFDtxcu2nQPN5ZaZl/9b+4ftS7lM4O40lAiBgdA09tyY5a0eBkrPsISIqGfcGUp4+i4uYve8XWOsRRQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":46822},"main":"dist/index.js","types":"dist/index.d.ts","gitHead":"5850dd77a019c0e5d08bff512a1b878884e99608","scripts":{"test":"echo \"Error: no test specified\" && exit 1","build":"tsc","prepublishOnly":"npm run build"},"_npmUser":{"name":"cvzxeov","email":"artur.mutsueff@yandex.ru"},"_npmVersion":"10.9.3","description":"Magical, zero-dependency, strongly typed Saga pattern (compensating transactions) for Node.js and Browser.","directories":{},"_nodeVersion":"22.19.0","_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.0.0"},"_npmOperationalInternal":{"tmp":"tmp/lite-saga_1.0.4_1781312315916_0.8237464496232785","host":"s3://npm-registry-packages-npm-production"}},"1.1.0":{"name":"@cvzxeov/lite-saga","version":"1.1.0","keywords":["saga","transactions","rollback","typescript","promise","state-machine","microservices","distributed-transactions","compensating-transactions","orchestration"],"author":{"name":"Awesome Developer"},"license":"MIT","_id":"@cvzxeov/lite-saga@1.1.0","maintainers":[{"name":"cvzxeov","email":"artur.mutsueff@yandex.ru"}],"dist":{"shasum":"9234ca994d9f08a250f384fbc25bd6f9b3486152","tarball":"https://registry.npmjs.org/@cvzxeov/lite-saga/-/lite-saga-1.1.0.tgz","fileCount":18,"integrity":"sha512-eeEzVIKDhkmKCq2J5ODIS4/FEH7T7swH5wfYMW0C0Li6Q3oxsFo0u6YH7/uQXnHz2GBr+CteqndbtMyDdeTETA==","signatures":[{"sig":"MEUCIQCuBx0+noOpT0N+ghckSZaujLctDtshqeIBrRUflStjbQIgQxMv5lHIBCtOJtEp0WKaUnrWz6zFlKPNxz3quqJFLjA=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":33754},"main":"dist/index.js","types":"dist/index.d.ts","gitHead":"e0a69be739016ccdd42f218009063c07ac7ef8c0","scripts":{"test":"echo \"Error: no test specified\" && exit 1","build":"tsc","prepublishOnly":"npm run build"},"_npmUser":{"name":"cvzxeov","email":"artur.mutsueff@yandex.ru"},"_npmVersion":"10.9.3","description":"Magical, zero-dependency, strongly typed Saga pattern (compensating transactions) for Node.js and Browser.","directories":{},"_nodeVersion":"22.19.0","_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.0.0"},"_npmOperationalInternal":{"tmp":"tmp/lite-saga_1.1.0_1781551051721_0.2718687718673398","host":"s3://npm-registry-packages-npm-production"}},"1.2.0":{"name":"@cvzxeov/lite-saga","version":"1.2.0","description":"Magical, zero-dependency, strongly typed Saga pattern (compensating transactions) for Node.js and Browser.","main":"dist/index.js","types":"dist/index.d.ts","scripts":{"build":"tsc","test":"echo \"Error: no test specified\" && exit 1","prepublishOnly":"npm run build"},"keywords":["saga","transactions","rollback","typescript","promise","state-machine","microservices","distributed-transactions","compensating-transactions","orchestration"],"author":{"name":"Awesome Developer"},"license":"MIT","devDependencies":{"typescript":"^5.0.0"},"_id":"@cvzxeov/lite-saga@1.2.0","gitHead":"cff21164cbb911774c89f890b6f35bdd655be563","_nodeVersion":"22.19.0","_npmVersion":"10.9.3","dist":{"integrity":"sha512-1IayyBjjDWEdhVcw+dNBZU4NSgLBOUz15LI6bnaffhaQbWjgY3YVcJLHreFXu31BVh8IXcuVewlE5jsOzelzTA==","shasum":"76ca26eb191ab94e7404750b838b1c208cf58e0a","tarball":"https://registry.npmjs.org/@cvzxeov/lite-saga/-/lite-saga-1.2.0.tgz","fileCount":18,"unpackedSize":38459,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIBEB6RxYija/wCGnofoYEjIgtWlsVNkTtpC3qNv7MpQIAiBXFdqPL675PbpF2fWRLPyvTC/9W8lsR+CETz7ctSfoNw=="}]},"_npmUser":{"name":"cvzxeov","email":"artur.mutsueff@yandex.ru"},"directories":{},"maintainers":[{"name":"cvzxeov","email":"artur.mutsueff@yandex.ru"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/lite-saga_1.2.0_1781559852522_0.38314154455985205"},"_hasShrinkwrap":false}},"time":{"created":"2026-06-13T00:38:38.931Z","modified":"2026-06-15T21:44:12.790Z","1.0.1":"2026-06-13T00:38:39.202Z","1.0.2":"2026-06-13T00:48:24.835Z","1.0.3":"2026-06-13T00:49:44.614Z","1.0.4":"2026-06-13T00:58:36.060Z","1.1.0":"2026-06-15T19:17:31.851Z","1.2.0":"2026-06-15T21:44:12.680Z"},"author":{"name":"Awesome Developer"},"license":"MIT","keywords":["saga","transactions","rollback","typescript","promise","state-machine","microservices","distributed-transactions","compensating-transactions","orchestration"],"description":"Magical, zero-dependency, strongly typed Saga pattern (compensating transactions) for Node.js and Browser.","maintainers":[{"name":"cvzxeov","email":"artur.mutsueff@yandex.ru"}],"readme":"# 🌟 @cvzxeov/lite-saga\r\n\r\nA magical, zero-dependency, strongly typed Saga pattern (compensating transactions) for Node.js and Browser.\r\n\r\n[![npm version](https://img.shields.io/npm/v/@cvzxeov/lite-saga.svg)](https://www.npmjs.com/package/@cvzxeov/lite-saga)\r\n[![npm downloads](https://img.shields.io/npm/dm/@cvzxeov/lite-saga.svg)](https://www.npmjs.com/package/@cvzxeov/lite-saga)\r\n[![TypeScript](https://img.shields.io/badge/TypeScript-Ready-blue.svg)](https://www.typescriptlang.org/)\r\n\r\n`@cvzxeov/lite-saga` helps you manage complex, distributed transactions across microservices, databases, or third-party APIs. If one step of a complex process fails, `@cvzxeov/lite-saga` automatically rolls back all previously successful steps in reverse order, ensuring your system remains in a consistent state.\r\n\r\n## 📖 Table of Contents\r\n\r\n- ✨ Features\r\n- 🤔 What is a Saga? (For Beginners)\r\n- 📦 Installation\r\n- 🚀 Quick Start\r\n- 🌐 Using with Axios / Fetch\r\n- 📚 Advanced Usage\r\n  - ⚡ Parallel Execution\r\n  - 🔀 Conditional Steps (`stepIf`)\r\n  - ⏳ Timeouts and Retries\r\n  - 🚑 Fallbacks & Compensation Retries\r\n  - 🛑 Canceling Sagas (`AbortController`)\r\n  - 🔌 Middlewares (Plugins)\r\n  - 🎣 Lifecycle Hooks\r\n- 📄 License\r\n\r\n---\r\n\r\n## ✨ Features\r\n\r\n- 📦 **Zero Dependencies:** Ultra-lightweight and fast.\r\n- 🛡️ **Strongly Typed:** First-class TypeScript support with context propagation.\r\n- 🔄 **Compensating Transactions:** Automatic rollback on failure.\r\n- ⚡ **Parallel Execution:** Run independent steps concurrently.\r\n- 🔀 **Conditional Steps:** Skip steps based on dynamic runtime conditions.\r\n- 🧅 **Nested Sagas:** Compose complex sagas from smaller, reusable sub-sagas.\r\n- ⏳ **Resilience built-in:** Retries, timeouts, and delays out of the box.\r\n- 🔌 **Middlewares:** Intercept steps for logging, profiling, or state snapshots.\r\n- 🎣 **Lifecycle Hooks:** Tap into `onStart`, `onStepSuccess`, `onFailure`, etc.\r\n- 🚑 **Fallbacks:** Provide alternative actions to prevent saga failures.\r\n- 🛑 **Abortable:** Safely cancel running sagas using `AbortController`.\r\n- 🛡️ **Reliable Rollbacks:** Built-in compensation retries.\r\n\r\n---\r\n\r\n## 🤔 What is a Saga? (For Beginners)\r\n\r\nIn modern web development (especially with microservices), a single user action might require calling multiple different APIs or databases. \r\n\r\n**The Problem:** What happens if Step 1 and Step 2 succeed, but Step 3 fails? Your system is now in a broken, half-finished state. A simple `try/catch` won't magically undo the database changes made in Step 1!\r\n\r\n**The Solution:** The **Saga Pattern**! A Saga is a sequence of transactions. Each step has two parts:\r\n1. **Action:** Do the work (e.g., *charge a card, create a user*).\r\n2. **Compensation (Rollback):** Undo the work (e.g., *refund the card, delete the user*).\r\n\r\nIf *any* step fails, `@cvzxeov/lite-saga` catches the error and **automatically runs the compensations for all previously completed steps in reverse order**. Your system goes back to exactly how it was before, keeping your data clean and safe!\r\n\r\n---\r\n\r\n## 📦 Installation\r\n\r\n```bash\r\nnpm install @cvzxeov/lite-saga\r\n```\r\n*or using yarn / pnpm:*\r\n```bash\r\nyarn add @cvzxeov/lite-saga\r\npnpm add @cvzxeov/lite-saga\r\n```\r\n\r\n---\r\n\r\n## 🚀 Quick Start\r\n\r\nImagine an e-commerce order process: you need to save the order to the database, charge the user's credit card, and send an email. If charging the card fails, you **must** delete the order from the database.\r\n\r\n```typescript\r\nimport { SagaBuilder } from 'lite-saga';\r\n\r\n// 1. Define your shared context (state)\r\ninterface OrderContext {\r\n  orderId?: string;\r\n  userId: string;\r\n  amount: number;\r\n}\r\n\r\n// 2. Build your saga\r\nconst orderSaga = new SagaBuilder<OrderContext>()\r\n  .step(\r\n    'Create DB Order',\r\n    async (ctx) => {\r\n      const order = await db.createOrder(ctx.userId, ctx.amount);\r\n      ctx.orderId = order.id; // Share data with next steps\r\n      return order;\r\n    },\r\n    async (ctx) => {\r\n      // Rollback: if subsequent steps fail, delete the order\r\n      if (ctx.orderId) await db.deleteOrder(ctx.orderId);\r\n    }\r\n  )\r\n  .step(\r\n    'Charge Credit Card',\r\n    async (ctx) => {\r\n      await stripe.charge(ctx.userId, ctx.amount);\r\n    },\r\n    async (ctx) => {\r\n      // Rollback: Refund the money\r\n      await stripe.refund(ctx.userId, ctx.amount);\r\n    }\r\n  )\r\n  .build();\r\n\r\n// 3. Execute the saga\r\ntry {\r\n  const finalState = await orderSaga.execute({ userId: 'user-123', amount: 150 });\r\n  console.log('Order processed successfully!', finalState.orderId);\r\n} catch (error) {\r\n  // If Stripe fails, the DB order is automatically deleted!\r\n  console.error('Order failed, all actions rolled back:', error.message);\r\n}\r\n```\r\n\r\n---\r\n\r\n## 🌐 Using with Axios / Fetch\r\n\r\n`lite-saga` is completely agnostic to how you make your network requests. It works perfectly with `axios`, `fetch`, `got`, or any Promise-based library.\r\n\r\nSince `axios` automatically throws an error for HTTP statuses outside the `2xx` range, it integrates flawlessly with `lite-saga`. If a request fails, the saga automatically stops and starts rolling back!\r\n\r\n```typescript\r\nimport axios from 'axios';\r\nimport { SagaBuilder } from 'lite-saga';\r\n\r\ninterface UserContext {\r\n  userData: { name: string; email: string };\r\n  createdUserId?: string;\r\n}\r\n\r\nconst userRegistrationSaga = new SagaBuilder<UserContext>()\r\n  .step(\r\n    'Create User in Auth Service',\r\n    async (ctx) => {\r\n      // Axios throws on 4xx/5xx. If this fails, the saga halts here.\r\n      const response = await axios.post('https://api.example.com/users', ctx.userData);\r\n      \r\n      // Save the new User ID to the context so we can delete it during rollback!\r\n      ctx.createdUserId = response.data.id;\r\n    },\r\n    async (ctx) => {\r\n      // ROLLBACK: This runs ONLY if a future step fails.\r\n      // We use the ID saved in the main action to undo the operation.\r\n      if (ctx.createdUserId) {\r\n        await axios.delete(`https://api.example.com/users/${ctx.createdUserId}`);\r\n      }\r\n    }\r\n  )\r\n  .step(\r\n    'Send Welcome Email',\r\n    async (ctx) => {\r\n      // If this email service returns a 500 Error, this step fails.\r\n      // The saga will then automatically execute the 'Create User' rollback above!\r\n      await axios.post('https://api.example.com/emails/welcome', { to: ctx.userData.email });\r\n    }\r\n  )\r\n  .build();\r\n```\r\n\r\n---\r\n\r\n## 📚 Advanced Usage\r\n\r\n### ⚡ Parallel Execution\r\nYou can group independent steps to run them concurrently. If *any* step in the parallel group fails, the saga will wait for the others to finish, and then correctly roll back *all* successful steps.\r\n\r\n```typescript\r\nsagaBuilder.parallel('Book Travel', [\r\n  {\r\n    name: 'Book Flight',\r\n    action: api.bookFlight,\r\n    compensation: api.cancelFlight,\r\n  },\r\n  {\r\n    name: 'Book Hotel',\r\n    action: api.bookHotel,\r\n    compensation: api.cancelHotel,\r\n  }\r\n])\r\n```\r\n\r\n### 🔀 Conditional Steps (`stepIf`)\r\nExecute a step only if a certain condition is met. If the condition is `false`, the step is skipped (and won't be rolled back).\r\n\r\n```typescript\r\nsagaBuilder.stepIf(\r\n  (ctx) => ctx.isVipUser, // Condition\r\n  'Add VIP Bonus Points',\r\n  async (ctx) => { /* Add points */ },\r\n  async (ctx) => { /* Remove points */ }\r\n)\r\n```\r\n\r\n### ⏳ Timeouts and Retries\r\nNetwork requests can be flaky. Add resilience to your steps natively:\r\n\r\n```typescript\r\nsagaBuilder.step(\r\n  'External API Call',\r\n  async () => fetch('https://api.example.com/data'),\r\n  async () => fetch('https://api.example.com/rollback'),\r\n  {\r\n    retries: 3,        // Try up to 3 times before failing\r\n    retryDelay: 1000,  // Wait 1 second between retries\r\n    timeout: 5000      // Cancel step if it takes more than 5 seconds\r\n  }\r\n)\r\n```\r\n\r\nFor production systems, you can also use **Exponential Backoff** by passing a function to `retryDelay`:\r\n\r\n```typescript\r\nsagaBuilder.step(\r\n  'External API Call',\r\n  async () => fetch('https://api.example.com/data'),\r\n  async () => fetch('https://api.example.com/rollback'),\r\n  {\r\n    retries: 3,\r\n    // Attempt 1: wait 1s, Attempt 2: wait 2s, Attempt 3: wait 3s\r\n    retryDelay: (attempt) => attempt * 1000, \r\n    compensationRetries: 3,\r\n    // 2s, 4s, 8s backoff for rollback\r\n    compensationRetryDelay: (attempt) => Math.pow(2, attempt) * 1000 \r\n  }\r\n)\r\n```\r\n\r\n### 🚑 Fallbacks & Compensation Retries\r\nMake your sagas bulletproof by providing fallback actions when the main step fails, and retrying rollback actions to prevent inconsistent states.\r\n\r\n```typescript\r\nsagaBuilder.step(\r\n  'Charge User',\r\n  async () => api.chargeWithStripe(),\r\n  async () => api.refundWithStripe(),\r\n  {\r\n    retries: 2,\r\n    fallback: async () => api.chargeWithPayPal(), // If Stripe fails, try PayPal\r\n    compensationRetries: 3, // If refund fails, retry up to 3 times\r\n    compensationRetryDelay: 1000\r\n  }\r\n)\r\n```\r\n\r\n### 🛑 Canceling Sagas (`AbortController`)\r\nYou can safely cancel a running saga. This immediately aborts the execution and automatically triggers the rollback process for all previously successful steps to maintain data consistency.\r\n\r\n```typescript\r\nconst controller = new AbortController();\r\n\r\nsaga.execute({ userId: 1 }, { signal: controller.signal })\r\n  .catch(err => console.log('Saga aborted:', err.message));\r\n\r\n// Cancel the saga execution after 2 seconds\r\nsetTimeout(() => controller.abort(), 2000);\r\n```\r\n\r\n### 🔌 Middlewares (Plugins)\r\n`lite-saga` supports an Onion Middleware architecture (similar to Koa or Redux). \r\n\r\nYou can use the built-in `loggerMiddleware` or write your own to measure execution time, integrate with Sentry, or take state snapshots.\r\n\r\n```typescript\r\nimport { SagaBuilder, loggerMiddleware } from 'lite-saga';\r\n\r\nconst saga = new SagaBuilder()\r\n  .use(loggerMiddleware) // Ready-to-use console logger\r\n  .use(async (step, ctx, next) => {\r\n    console.log(`Before step: ${step.name}`);\r\n    \r\n    const result = await next(); // Wait for the step and next middlewares\r\n    \r\n    console.log(`After step: ${step.name}`);\r\n    return result;\r\n  })\r\n  // .step(...)\r\n  .build();\r\n```\r\n\r\n### 🎣 Lifecycle Hooks\r\nAttach global hooks for monitoring and metrics:\r\n\r\n```typescript\r\nsagaBuilder.withHooks({\r\n  onStart: (ctx) => console.log('Saga started'),\r\n  onStepSuccess: (stepName, result, ctx) => console.log(`${stepName} succeeded`),\r\n  onFailure: (error, ctx) => console.error('Saga failed globally', error),\r\n  onCompensationFailed: (stepName, err) => console.error(`CRITICAL: Rollback failed for ${stepName}`, err),\r\n})\r\n```\r\n\r\n---\r\n\r\n## 📄 License\r\n\r\nCVZXEOV 2026. See the LICENSE file for details.","readmeFilename":"README.md"}