{"id":22407568,"url":"https://github.com/f5io/csp","last_synced_at":"2026-03-08T06:32:42.758Z","repository":{"id":42801011,"uuid":"102276239","full_name":"f5io/csp","owner":"f5io","description":"A library for Communicating Sequential Processes in Node.js, built on top of async/await","archived":false,"fork":false,"pushed_at":"2022-03-26T21:31:57.000Z","size":546,"stargazers_count":62,"open_issues_count":8,"forks_count":3,"subscribers_count":11,"default_branch":"master","last_synced_at":"2025-04-07T08:11:15.541Z","etag":null,"topics":["concurrency","csp","nodejs"],"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/f5io.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-09-03T15:58:55.000Z","updated_at":"2024-03-31T18:13:56.000Z","dependencies_parsed_at":"2022-08-23T01:41:14.883Z","dependency_job_id":null,"html_url":"https://github.com/f5io/csp","commit_stats":null,"previous_names":[],"tags_count":18,"template":false,"template_full_name":null,"purl":"pkg:github/f5io/csp","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/f5io%2Fcsp","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/f5io%2Fcsp/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/f5io%2Fcsp/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/f5io%2Fcsp/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/f5io","download_url":"https://codeload.github.com/f5io/csp/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/f5io%2Fcsp/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30247362,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-08T05:41:50.788Z","status":"ssl_error","status_checked_at":"2026-03-08T05:41:39.075Z","response_time":56,"last_error":"SSL_read: 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":["concurrency","csp","nodejs"],"created_at":"2024-12-05T11:14:46.480Z","updated_at":"2026-03-08T06:32:42.711Z","avatar_url":"https://github.com/f5io.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# @f5io/csp\n\nA library for Communicating Sequential Processes in Node.js, built on top of `async/await` and `AsyncIterable`.\n\n[![npm version](https://badge.fury.io/js/%40f5io%2Fcsp.svg)](https://badge.fury.io/js/%40f5io%2Fcsp)\n\n## Installation\n\nThis library requires `async/await` support in your Node.js runtime, so ideally `node\u003e=7.4`.\n\n```\n$ npm install --save @f5io/csp\n```\n\nor\n\n```\n$ yarn add @f5io/csp\n```\n\n## Example Usage\n\nBelow is a trivial example of usage, that plays on the standard ping-pong example.\n\n```javascript\nconst { channel, put, take } = require('@f5io/csp');\n\nconst timeout = ms =\u003e new Promise(resolve =\u003e setTimeout(resolve, ms));\n\nconst wiff = channel();\nconst waff = channel();\n\nconst createBall = () =\u003e ({ hits: 0, status: '' });\n\nconst createBat = async (inbound, outbound) =\u003e {\n  for await (const ball of inbound) {\n    ball.hits++;\n    ball.status = ball.status === 'wiff!' ? 'waff!' : 'wiff!';\n    console.log(`🎾  Ball hit ${ball.hits} time(s), ${ball.status}`);\n    await timeout(500); // assume it's going to take a bit to hit the ball\n    await put(outbound, ball); // smash the ball back\n  }\n};\n\ncreateBat(waff, wiff); // create a bat that will wiff waffs\ncreateBat(wiff, waff); // create a bat that will waff wiffs\n\nput(waff, createBall());\n```\n\n![ping pong](/assets/pingpong.gif?raw=true)\n\n## API\n\nThis library exposes 5 functions and one factory.\n\n### `channel()`\n\nThis factory method constructs a new `channel` and returns it. A channel contains no publicly accessible properties, but contains information about interactions with the `channel`.\n\n```javascript\nconst chan = channel();\n```\n\n### `put(channel, message)` -\u003e `Promise`\n\nThe `put` function requires the `channel` on which to put the supplied `message`. The `put` method returns a `Promise` which can be optionally awaited and will resolve when something is ready to take the `message` from the `channel`.\n\n```javascript\nconst chan = channel();\nput(chan, 42);\n\n// ...or...\n\nawait put(chan, 42);\n```\n\n### `take(channel)` -\u003e `Promise`\n\nThe `take` function requires the `channel` to take from. The `take` method returns a `Promise` which should always be awaited and will resolve with a message, when a message is available.\n\n```javascript\nconst chan = channel();\n\nput(chan, 42);\n\nconst msg = await take(chan); // will receive 42\n```\n\n### `alts(...channels)` -\u003e `Promise`\n\nThe `alts` function will race taking values from multiple `channels`.\n\n```javascript\nconst chan1 = channel();\nconst chan2 = channel();\n\nput(chan2, 42);\nconst msg = await alts(chan1, chan2); // will receive 42\n```\n\n### `select(Map\u003c*, channel\u003e|Set\u003cchannel\u003e|Array\u003cchannel\u003e|Object\u003cstring, channel\u003e)` -\u003e `Promise`\n\nThe `select` function will race taking values from multiple `channels`, similar to `alts`, but will also return the key of the channel that was selected.\n\n```javascript\nconst chan1 = channel();\nconst chan2 = channel();\n\nput(chan2, 42);\nconst channels = [chan1, chan2];\nconst result = await select(channels); // will receive [1, 42]\n```\n\nWorks with `Map` and `Set` as well as with plain-old javascript arrays and objects.\n\nA more complex TypeScript example might look like the following:\n\n```typescript\ntype Error = { message: string; };\ntype Result = { success: boolean; };\n\nconst errors = channel\u003cError\u003e();\nconst results = channel\u003cResult\u003e();\nconst channels = new Set([ errors, results ]);\n\nfor await (const [ chan, msg ] of select\u003cError | Result\u003e(channels)) {\n  switch (chan) {\n    case errors: {\n      const { message }: Error = msg;\n      console.log(message);\n      break;\n    }\n    case results: {\n      const { success }: Result = msg;\n      console.log(success);\n      break;\n    }\n  }\n}\n```\n\n### `drain(channel)` -\u003e `Promise`\n\nThe `drain` function requires a `channel` which it will drain all messages from until empty, returning an array of messages.\n\n```javascript\nconst chan = channel();\nput(chan, 42);\nput(chan, 41);\nput(chan, 40);\nput(chan, 39);\n\nconst msgs = await drain(chan); // will receive [ 42, 41, 40, 39 ]\n```\n\n## Contributions\n\nContributions are welcomed and appreciated!\n\n1. Fork this repository.\n1. Make your changes, documenting your new code with comments.\n1. Submit a pull request with a sane commit message.\n\nFeel free to get in touch if you have any questions.\n\n## License\n\nPlease see the `LICENSE` file for more information.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ff5io%2Fcsp","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ff5io%2Fcsp","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ff5io%2Fcsp/lists"}