{"_id":"p-abort","_rev":"3-3c86d6b7585f62c544126832c1031660","name":"p-abort","dist-tags":{"latest":"0.2.1"},"versions":{"0.1.0":{"name":"p-abort","version":"0.1.0","author":{"name":"RanolP","email":"me@ranolp.dev"},"license":"MIT","_id":"p-abort@0.1.0","maintainers":[{"name":"ranol_","email":"me@ranolp.dev"}],"homepage":"https://github.com/RanolP/npm-packages#readme","bugs":{"url":"https://github.com/RanolP/npm-packages/issues"},"dist":{"shasum":"974ad16bd5c9142ab499cf3cd0b83bdb9351837f","tarball":"https://registry.npmjs.org/p-abort/-/p-abort-0.1.0.tgz","fileCount":8,"integrity":"sha512-UsRLufZRffENhUHjhK9lO81zYCCsgamZK4eNjcWZXuuatiXmP2wMOZ/WKQcdTXcwXVDWixTA4WxB2vD74STxkA==","signatures":[{"sig":"MEQCIDtxK0px9S19TsSeuv0pZbBdYtG2N3I/K2jtsZizMVaBAiAgkpkw8EvDfPAAUTfdQm5Z2IPzihfMRB7JUT9JyAkXOw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":30042},"main":"./dist/index.js","type":"module","_from":"file:p-abort-0.1.0.tgz","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"scripts":{"test":"vitest","build":"tsdown","test:run":"vitest run"},"_npmUser":{"name":"ranol_","email":"me@ranolp.dev"},"_resolved":"/tmp/64e9f1d794941550847eddb169abbbcb/p-abort-0.1.0.tgz","_integrity":"sha512-UsRLufZRffENhUHjhK9lO81zYCCsgamZK4eNjcWZXuuatiXmP2wMOZ/WKQcdTXcwXVDWixTA4WxB2vD74STxkA==","repository":{"url":"git+https://github.com/RanolP/npm-packages.git","type":"git","directory":"packages/p-abort"},"_npmVersion":"11.3.0","description":"Abortable step-by-step operations","directories":{},"_nodeVersion":"24.1.0","_hasShrinkwrap":false,"devDependencies":{"tsdown":"^0.12.7","vitest":"^3.2.3","typescript":"5.8.3"},"_npmOperationalInternal":{"tmp":"tmp/p-abort_0.1.0_1753033701355_0.637485354406083","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"p-abort","version":"0.2.0","author":{"name":"RanolP","email":"me@ranolp.dev"},"license":"MIT","_id":"p-abort@0.2.0","maintainers":[{"name":"ranol_","email":"me@ranolp.dev"}],"homepage":"https://github.com/RanolP/npm-packages#readme","bugs":{"url":"https://github.com/RanolP/npm-packages/issues"},"dist":{"shasum":"94d9657308c4e88d9d33cae3a9870403109342e9","tarball":"https://registry.npmjs.org/p-abort/-/p-abort-0.2.0.tgz","fileCount":8,"integrity":"sha512-sahfIdVNbdS4NGjQiaUQObPYEEu4+0gxoZyj/TJTiZw9tSTsitg0ahEytrDsXjDd80lb7xWkHf9M0d6AJI9iEQ==","signatures":[{"sig":"MEUCIA++ZCxi2VxRfsKdpSk9Gpz1C49LZaubKY57QUVY852hAiEAl/NQC28IapLCn5V8rWxqOs0HutR7D+T5GqBrV5IWDEU=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":28963},"main":"./dist/index.js","type":"module","_from":"file:p-abort-0.2.0.tgz","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"scripts":{"test":"vitest","build":"tsdown","test:run":"vitest run"},"_npmUser":{"name":"ranol_","email":"me@ranolp.dev"},"_resolved":"/tmp/e33f12291ee49210a8ebe303082bb418/p-abort-0.2.0.tgz","_integrity":"sha512-sahfIdVNbdS4NGjQiaUQObPYEEu4+0gxoZyj/TJTiZw9tSTsitg0ahEytrDsXjDd80lb7xWkHf9M0d6AJI9iEQ==","repository":{"url":"git+https://github.com/RanolP/npm-packages.git","type":"git","directory":"packages/p-abort"},"_npmVersion":"10.8.2","description":"Abortable step-by-step operations","directories":{},"_nodeVersion":"20.19.3","_hasShrinkwrap":false,"devDependencies":{"tsdown":"^0.12.7","vitest":"^3.2.3","typescript":"5.8.3"},"_npmOperationalInternal":{"tmp":"tmp/p-abort_0.2.0_1753035453730_0.6595795414238319","host":"s3://npm-registry-packages-npm-production"}},"0.2.1":{"name":"p-abort","version":"0.2.1","description":"Abortable step-by-step operations","type":"module","main":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"repository":{"type":"git","url":"git+https://github.com/RanolP/npm-packages.git","directory":"packages/p-abort"},"author":{"name":"RanolP","email":"me@ranolp.dev"},"license":"MIT","devDependencies":{"tsdown":"^0.12.7","typescript":"5.8.3","vitest":"^3.2.3"},"scripts":{"build":"tsdown","test":"vitest","test:run":"vitest run"},"_id":"p-abort@0.2.1","bugs":{"url":"https://github.com/RanolP/npm-packages/issues"},"homepage":"https://github.com/RanolP/npm-packages#readme","_integrity":"sha512-8Kob0ewQVu+uWvrXU7yK2HH61A3ytBr5DSatL7uoeaPtTZxvZ4KuWeYUWAqXdpxYlELaIiXjV6jMuoIkjYNAnw==","_resolved":"/tmp/f06997f81999515a186ca4d8bd8e6b3e/p-abort-0.2.1.tgz","_from":"file:p-abort-0.2.1.tgz","_nodeVersion":"24.12.0","_npmVersion":"11.6.2","dist":{"integrity":"sha512-8Kob0ewQVu+uWvrXU7yK2HH61A3ytBr5DSatL7uoeaPtTZxvZ4KuWeYUWAqXdpxYlELaIiXjV6jMuoIkjYNAnw==","shasum":"c29974333ffda0a08365bb6da7774d5ab90514ac","tarball":"https://registry.npmjs.org/p-abort/-/p-abort-0.2.1.tgz","fileCount":9,"unpackedSize":33514,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/p-abort@0.2.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQCF01EWHTlRFfs9O8flFRMBICdkc81WqWiYWUg9KgNqkwIgeBTP8Nr9cP5ShQAZXGVihNK41QbjZEGQhdhmB4Ey2Dw="}]},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:a77a7501-212d-423a-8328-99cef7e877fc"}},"directories":{},"maintainers":[{"name":"ranol_","email":"me@ranolp.dev"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/p-abort_0.2.1_1766488486769_0.22695279694398862"},"_hasShrinkwrap":false}},"time":{"created":"2025-07-20T17:48:21.277Z","modified":"2025-12-23T11:14:47.257Z","0.1.0":"2025-07-20T17:48:21.531Z","0.2.0":"2025-07-20T18:17:33.907Z","0.2.1":"2025-12-23T11:14:46.910Z"},"bugs":{"url":"https://github.com/RanolP/npm-packages/issues"},"author":{"name":"RanolP","email":"me@ranolp.dev"},"license":"MIT","homepage":"https://github.com/RanolP/npm-packages#readme","repository":{"type":"git","url":"git+https://github.com/RanolP/npm-packages.git","directory":"packages/p-abort"},"description":"Abortable step-by-step operations","maintainers":[{"name":"ranol_","email":"me@ranolp.dev"}],"readme":"# p-abort\n\nAbortable step-by-step operations with automatic cleanup.\n\n## Installation\n\n```bash\nnpm install p-abort\n```\n\n```bash\npnpm add p-abort\n```\n\n```bash\nyarn add p-abort\n```\n\n## Overview\n\n`p-abort` provides a utility for creating abortable asynchronous operations that can be cleanly cancelled at any step. It's particularly useful for:\n\n- Long-running async operations that need cancellation support\n- Multi-step workflows where intermediate steps should be skippable\n- Resource cleanup when operations are aborted\n- Preventing race conditions in async code\n\n## Usage\n\n### Basic Example\n\n```typescript\nimport { abortable } from 'p-abort';\n\nconst operation = abortable($ => async (id: string) => {\n  // Step 1: Fetch user data\n  const user = await $(fetchUser(id));\n  \n  // Step 2: Fetch user's posts\n  const posts = await $(fetchPosts(user.id));\n  \n  // Step 3: Process posts\n  const processed = await $(processPosts(posts));\n  \n  return processed;\n});\n\n// Start the operation\nconst promise = operation('user123');\n\n// Later, abort if needed\nsetTimeout(() => {\n  promise.abort();\n}, 1000);\n\n// Handle result\nconst result = await promise;\nif (result.ok) {\n  console.log('Success:', result.data);\n} else {\n  console.log('Operation was aborted');\n}\n```\n\n### With Cleanup\n\n```typescript\nimport { abortable } from 'p-abort';\n\nconst uploadWithProgress = abortable($ => async (file: File) => {\n  const controller = new AbortController();\n  \n  // Register cleanup function\n  $.cleanup(() => {\n    controller.abort();\n    console.log('Upload cancelled, cleaning up...');\n  });\n  \n  // Start upload\n  const response = await $(uploadFile(file, { signal: controller.signal }));\n  \n  // Process response\n  return response;\n});\n\nconst upload = uploadWithProgress(myFile);\n\n// Cancel upload\nupload.abort();\n```\n\n### Function Wrapping\n\nThe `$` utility can also wrap functions to make them abort-aware:\n\n```typescript\nimport { abortable } from 'p-abort';\n\nconst processData = abortable($ => async (items: string[]) => {\n  // Wrap an existing function to be abort-aware\n  const abortableFetch = $(fetchData);\n  \n  const results = [];\n  for (const item of items) {\n    const data = await abortableFetch(item);\n    results.push(data);\n  }\n  \n  return results;\n});\n```\n\n### Parallel Operations\n\nUse `$.all()` to run multiple operations in parallel while maintaining abort capability:\n\n```typescript\nconst parallelFetch = abortable($ => async (ids: string[]) => {\n  // Fetch all data in parallel\n  const promises = ids.map(id => $(fetchData(id)));\n  const results = await $.all(promises);\n  \n  return results;\n});\n```\n\n## API\n\n### `abortable(fn)`\n\nCreates an abortable operation from a function that receives an abort-aware utility.\n\n#### Parameters\n\n- `fn`: A function that receives the `$` utility and returns an async function\n\n#### Returns\n\nA function that returns a `Promise` with an additional `abort()` method.\n\n#### Promise Result\n\nThe returned promise resolves to:\n- `{ ok: true, data: T }` on successful completion\n- `{ ok: false }` if the operation was aborted\n\n### `$` Utility\n\nThe `$` utility provides several methods for making operations abort-aware:\n\n#### `$(promise)`\nWraps a promise or value to be abort-aware. If the operation is aborted before completion, it throws an `AbortedError`.\n\n#### `$(fn)`\nWraps a function to make it abort-aware. The wrapped function will check for abortion before and after execution.\n\n#### `$.cleanup(fn)`\nRegisters a cleanup function to be called when the operation completes or is aborted. Cleanup functions are executed in reverse order of registration (LIFO). Useful for resource cleanup.\n\n#### `$.all(array)`\nWraps multiple promises in a Promise.all-like operation. All promises become abort-aware and the entire operation can be cancelled.\n\n#### `$.abort()`\nManually aborts the current operation from within the operation function.\n\n### `runAbortable(fn)`\n\nCreates and immediately runs an abortable operation without parameters.\n\n#### Parameters\n\n- `fn`: A function that receives the `$` utility and returns a value or promise\n\n#### Returns\n\nAn `AbortableTask` that can be aborted and resolves to a result object.\n\n```typescript\nimport { runAbortable } from 'p-abort';\n\nconst task = runAbortable(async $ => {\n  const data = await $(fetchData());\n  return data;\n});\n\n// Can abort the task\ntask.abort();\n\nconst result = await task;\nif (result.ok) {\n  console.log('Result:', result.data);\n} else {\n  console.log('Task was aborted');\n}\n```\n\n## Error Handling\n\nWhen an operation is aborted, any in-progress steps are cancelled and the promise resolves to `{ ok: false }`. Other errors are propagated normally. You don't need to manually handle `AbortedError` as it's handled internally.\n\n## Advanced Usage\n\n### Chaining Operations\n\n```typescript\nconst complexWorkflow = abortable($ => async (input: string) => {\n  // Step 1: Validate\n  const validated = await $(validateInput(input));\n  \n  // Step 2: Transform\n  const transformed = await $(transformData(validated));\n  \n  // Step 3: Save with retry\n  const saved = await $(retry(() => saveData(transformed), 3));\n  \n  // Step 4: Notify\n  await $(sendNotification(saved));\n  \n  return saved;\n});\n```\n\n### Resource Management\n\n```typescript\nconst fileProcessor = abortable($ => async (filePath: string) => {\n  const file = await $(openFile(filePath));\n  \n  // Ensure file is closed on abort\n  $.cleanup(() => {\n    file.close();\n    console.log('File closed due to abort');\n  });\n  \n  const content = await $(readFile(file));\n  const processed = await $(processContent(content));\n  \n  return processed;\n});\n```\n\n## TypeScript Support\n\nThis package is written in TypeScript and provides full type safety:\n\n```typescript\ninterface UserData {\n  id: string;\n  name: string;\n}\n\nconst getUser = abortable($ => async (id: string): Promise<UserData> => {\n  const response = await $(fetch(`/api/users/${id}`));\n  return response.json();\n});\n\n// Type is inferred as:\n// const getUser: (id: string) => Promise<\n//   { ok: true; data: UserData } | { ok: false }\n// > & { abort: () => void }\n```\n\n## License\n\nMIT © [RanolP](https://github.com/RanolP)\n","readmeFilename":"README.md"}