{"id":44638352,"url":"https://github.com/bytesfield/sweet-pipeline","last_synced_at":"2026-02-14T18:06:21.479Z","repository":{"id":57376074,"uuid":"374623748","full_name":"bytesfield/sweet-pipeline","owner":"bytesfield","description":"Sweet-Pipeline is a node package for defining and executing a simple sequential flow from process to process using functional programming principle.","archived":false,"fork":false,"pushed_at":"2025-01-15T12:11:46.000Z","size":427,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-10-02T01:43:48.812Z","etag":null,"topics":["asynchronous","converts","pipeline","pipes-returns","promise","sweet"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bytesfield.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2021-06-07T10:23:44.000Z","updated_at":"2025-01-15T12:05:06.000Z","dependencies_parsed_at":"2022-09-26T16:50:37.373Z","dependency_job_id":null,"html_url":"https://github.com/bytesfield/sweet-pipeline","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/bytesfield/sweet-pipeline","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bytesfield%2Fsweet-pipeline","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bytesfield%2Fsweet-pipeline/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bytesfield%2Fsweet-pipeline/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bytesfield%2Fsweet-pipeline/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bytesfield","download_url":"https://codeload.github.com/bytesfield/sweet-pipeline/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bytesfield%2Fsweet-pipeline/sbom","scorecard":{"id":260394,"data":{"date":"2025-08-11","repo":{"name":"github.com/bytesfield/sweet-pipeline","commit":"be79bd432bf3f58c27420741f740d85790e6fb46"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":2.8,"checks":[{"name":"Code-Review","score":0,"reason":"Found 0/22 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE.md:0","Info: FSF or OSI recognized license: MIT License: LICENSE.md:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'main'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Vulnerabilities","score":8,"reason":"2 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GHSA-968p-4wvh-cqc8","Warn: Project is vulnerable to: GHSA-v6h2-p8h4-qcjw"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 9 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-17T10:42:55.803Z","repository_id":57376074,"created_at":"2025-08-17T10:42:55.804Z","updated_at":"2025-08-17T10:42:55.804Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29452093,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-14T15:52:44.973Z","status":"ssl_error","status_checked_at":"2026-02-14T15:52:11.208Z","response_time":53,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["asynchronous","converts","pipeline","pipes-returns","promise","sweet"],"created_at":"2026-02-14T18:06:21.394Z","updated_at":"2026-02-14T18:06:21.469Z","avatar_url":"https://github.com/bytesfield.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp\u003e\u003cimg src=\"/images/pipeline.jpg\" alt=\"Sweet Pipeline Preview\"\u003e\u003c/p\u003e\n\n# Sweet-Pipeline Package\n\n[![npm version](https://badge.fury.io/js/sweet-pipeline.svg)](https://badge.fury.io/js/sweet-pipeline)\n[![GitHub license](https://img.shields.io/github/license/bytesfield/sweet-pipeline)](https://github.com/bytesfield/sweet-pipeline/blob/main/LICENSE.md)\n[![Build Status](https://travis-ci.com/bytesfield/sweet-pipeline.svg?branch=main)](https://travis-ci.com/bytesfield/sweet-pipeline)\n[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/bytesfield/sweet-pipeline/badges/quality-score.png?b=main)](https://scrutinizer-ci.com/g/bytesfield/sweet-pipeline/?branch=main)\n[![GitHub issues](https://img.shields.io/github/issues/bytesfield/sweet-pipeline)](https://github.com/bytesfield/sweet-pipeline/issues)\n\u003cbr /\u003e\n\n# Description\n\n`Sweet Pipeline` is a flexible and powerful pipeline package for JavaScript/TypeScript, inspired by the Laravel pipeline design pattern. It enables you to define a simple sequential flow of processes leveraging on `functional programming` principles, making it easy to build complex workflows with a clear and readable structure.\n\n## Installation\n\n[Node](https://nodejs.org/en/) 16 + is required.\n\nTo get the latest version of Sweet-Pipeline, simply install it\n\n```bash\nnpm install sweet-pipeline\n```\n\n## Usage\n\nProcesses which are referred to as `pipes` in the pipeline are callable `functions`, `closures` or anything that can be invoked.\n\nTo begin require it at the top.\n\n```typescript\nimport { Pipeline } from \"sweet-pipeline\"\n```\n\n### Basic Usage\n\nThe basic idea behind the `pipeline` is to send data through a series of steps. Each step (or \"pipe\") modifies the data and passes it to the next step.\n\n```typescript\nconst pipeline = new Pipeline\u003cnumber\u003e();\n\nconst result = await pipeline\n        .send(1)  // The initial data\n        .through([\n          (value) =\u003e value + 1,     // First step: Add 1\n          (value) =\u003e value * 2,     // Second step: Multiply by 2\n        ])\n        .then(result =\u003e {\n          console.log(result); // Output: 4 (1 + 1 = 2, 2 * 2 = 4)\n        });\n```\n\n#### Pipes\n\nA `pipe` is a function that processes the data in the pipeline. Each pipe receives the data (`passable`) and can either return a value directly or a `Promise`.\n\n##### Pipe as a Function\nA function that takes the current passable object and a next function. The next function calls the next pipe.\n\n```typescript\n(value) =\u003e value + 1\n```\n\n```typescript\nexport const addOnePipe: (value: number) =\u003e Promise\u003cnumber\u003e = async (value) =\u003e {\n  return value + 1;  // Add 1 and return the result\n};\n```\n\n##### Pipe as an `Object` or `Class` with `handle` method\nAn object with a `handle` method that follows the same signature as the function pipe.\n\n```typescript\nconst pipeObject = {\n  handle: (value) =\u003e value * 2,\n};\n```\n```typescript\nexport class MultiplyByTwoPipe {\n  async handle(value: number): Promise\u003cnumber\u003e {\n    return value * 2;  // Multiply by 2 and return the result\n  }\n}\n```\n\n##### Combining `Object` or `Class` with `handle` method and a `Function`\nAn object/class with a `handle` method that follows the same signature as the function pipe can be passed.\n\n```typescript\nconst pipeline = new Pipeline\u003cnumber\u003e();\n\nconst result = await pipeline\n        .send(1)  // The initial data\n        .through([\n          addOnePipe,     // First step: Add 1 (Function)\n          new MultiplyByTwoPipe(),     // Second step: Multiply by 2 (Class)\n        ])\n        .then(result =\u003e {\n          console.log(result); // Output: 4 (1 + 1 = 2, 2 * 2 = 4)\n        });\n```\n\n#### Handling Promises\n\nYou can use `async` pipes that return `promises`. The pipeline will `wait` for the promise to resolve before passing the result to the next pipe.\n\n```typescript\nconst result = await new Pipeline\u003cnumber\u003e()\n        .send(1)\n        .through([\n          async (value) =\u003e value + 1,     // First step: Add 1 (async)\n          async (value) =\u003e value * 2,     // Second step: Multiply by 2 (async)\n        ])\n        .then(result =\u003e console.log(result)); // Output: 4\n```\n\n#### Breaking the Pipeline\n\nYou can `break` out of the pipeline early by using the `.break()` method. If a pipe returns `true` for the `break` condition, the pipeline will stop processing further pipes.\n\n```typescript\nconst result = await new Pipeline\u003cnumber\u003e()\n        .send(1)\n        .through([\n          (value) =\u003e value + 1,     // First step: Add 1\n          (value) =\u003e value * 2,     // Second step: Multiply by 2\n        ])\n        .break(true)  // Stop after the first pipe\n        .then(result =\u003e console.log(result)); // Output: 2 (1 + 1)\n```\n\n#### Chaining with `then`\n\nThe `then` method allows you to specify the final step in the pipeline after all pipes have been executed. This is where you define the ultimate result you want to achieve after passing through the pipeline.\n\n\n```typescript\nconst result = await new Pipeline\u003cnumber\u003e()\n        .send(1)\n        .through([\n          (value) =\u003e value + 1,     // Add 1\n          (value) =\u003e value * 2,     // Multiply by 2\n        ])\n        .then(result =\u003e {\n          console.log(result); // Output: 4\n          return result * 2;   // You can also return a value for further chaining\n        })\n        .then(console.log);     // Output: 8\n```\n\n### API\n#### `send(passable: T): this`\nSets the initial data (`passable`) that will be passed through the `pipeline`.\n\n```typescript\npipeline.send(10);\n```\n\n#### `through(pipes: Pipe\u003cT\u003e[] | Pipe\u003cT\u003e): this`\nSets the pipes (steps) that will transform the data. This can be an array of pipes, which can be `functions` or `objects` with a `handle` method\n\n```typescript\npipeline.through([\n  (value) =\u003e value + 1,\n  (value) =\u003e value * 2,\n]);\n\n```\n\n#### `then(destination: (value: T) =\u003e Promise\u003cT\u003e): Promise\u003cT\u003e`\nExecutes the `pipeline` and returns the final result. Pipes are reduced into a single composed function that calls each pipe in sequence. The destination is the final step of the pipeline.\n\n```typescript\nconst result = await pipeline.then(value =\u003e value + 5);\n```\n\n#### Note\n_While `Sweet Pipeline` follows many `functional programming` principles—such as immutability, first-class functions, composition, and higher-order functions—it doesn't enforce pure functional programming strictly. It still allows for impure functions (if the user decides to use them), and side effects can be introduced in the pipes. However, if used correctly with pure functions, the package aligns well with functional programming principles_\n\n### Changelog\n\nPlease see [CHANGELOG](CHANGELOG.md) for more information what has changed recently.\n\n## Contributing\n\nPlease see [CONTRIBUTING](CONTRIBUTING.md) for details.\n\n### Security\n\nIf you discover any security related issues, please email `abrahamudele@gmail.com` instead of using the issue tracker.\n\n## Credits\n\n  ### Abraham Udele (Software Engineer) \u003cbr/\u003e\n  - Find me on \u003cbr/\u003e\n  \u003ca href=\"https://www.abrahamudele.com\"\u003eWebsite.\u003c/a\u003e \u003cbr/\u003e\n  \u003ca href=\"https://github.com/bytesfield/\"\u003eGithub.\u003c/a\u003e \u003cbr/\u003e\n  \u003ca href=\"https://x.com/mr_udele/\"\u003eX (Twitter).\u003c/a\u003e \u003cbr/\u003e\n  \u003ca href=\"https://www.linkedin.com/in/abrahamudele/\"\u003eLinkedin.\u003c/a\u003e\n\n## License\n\nThe MIT License (MIT). Please see [License File](LICENSE.md) for more information.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbytesfield%2Fsweet-pipeline","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbytesfield%2Fsweet-pipeline","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbytesfield%2Fsweet-pipeline/lists"}