{"id":32977171,"url":"https://github.com/futurize/future-io","last_synced_at":"2026-01-18T05:19:32.686Z","repository":{"id":47930729,"uuid":"53243083","full_name":"futurize/future-io","owner":"futurize","description":null,"archived":false,"fork":false,"pushed_at":"2017-05-30T15:23:01.000Z","size":80,"stargazers_count":14,"open_issues_count":11,"forks_count":3,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-12-01T01:56:22.888Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","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/futurize.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":"2016-03-06T07:26:42.000Z","updated_at":"2024-11-14T03:12:56.000Z","dependencies_parsed_at":"2022-08-12T14:31:15.302Z","dependency_job_id":null,"html_url":"https://github.com/futurize/future-io","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/futurize/future-io","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/futurize%2Ffuture-io","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/futurize%2Ffuture-io/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/futurize%2Ffuture-io/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/futurize%2Ffuture-io/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/futurize","download_url":"https://codeload.github.com/futurize/future-io/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/futurize%2Ffuture-io/sbom","scorecard":{"id":414886,"data":{"date":"2025-08-11","repo":{"name":"github.com/futurize/future-io","commit":"1a69c426c46d5a675c87da5abeb913441abf9404"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":4,"checks":[{"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":"Code-Review","score":7,"reason":"Found 21/30 approved changesets -- score normalized to 7","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":"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":"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":"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":"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":"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":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE: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 'master'"],"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":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 21 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-18T23:34:44.281Z","repository_id":47930729,"created_at":"2025-08-18T23:34:44.281Z","updated_at":"2025-08-18T23:34:44.281Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28530810,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-18T00:39:45.795Z","status":"online","status_checked_at":"2026-01-18T02:00:07.578Z","response_time":98,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":[],"created_at":"2025-11-13T06:00:32.662Z","updated_at":"2026-01-18T05:19:32.675Z","avatar_url":"https://github.com/futurize.png","language":"JavaScript","readme":"# future-io\n[![NPM version](http://img.shields.io/npm/v/future-io.svg?style=flat-square)](https://www.npmjs.com/package/future-io)\n[![Build status](http://img.shields.io/travis/futurize/future-io/master.svg?style=flat-square)](https://travis-ci.org/futurize/future-io)\n[![Dependencies](https://img.shields.io/david/futurize/future-io.svg?style=flat-square)](https://david-dm.org/futurize/future-io)\n\nA [fantasy-land](https://github.com/fantasyland/fantasy-land) compliant monadic IO library for Node.js.\n\nBuilding a simple cli that tells you if a number is even can look something like this:\n\n```js\n#!/usr/bin/node\n\nconst io = require('future-io')\nconst ioProcess = require('future-io/node/process')\n\nconst even = ioProcess.argv\n  .map(argv =\u003e (parseInt(argv[2]) % 2) === 0)\n  .chain(even =\u003e ioProcess.stdout.write('Is even: ' + even))\n\nio.unsafePerform(even)\n```\n\n# API\n\n## IO-returning functions\nTo get you started fast this library mimics the interface of the native node modules.\nIt just returns io's instead of taking callbacks!\n\nGetting complete coverage of all io related functionality in node is still a work in progress.\nIf you're missing something, please feel free to open an issue or pull request.\n\nAt the moment the following modules are exported.\nFor some recipes demonstrating their use check out the examples directory.\n\n### `future-io/node/console`\n\n### `future-io/node/fs`\n\n### `future-io/node/module`\n\n### `future-io/node/process`\n\n### `future-io/node/child_process`\n\n## performing IO actions\n\n### `unsafePerform :: IO e a -\u003e ()`\nThis will execute the io.\nIf the io represents an error value, this function will throw.\nIf this is not what you want, use `IO.prototype.catch`.\n\n## IO methods\nIO implements the [fantasy-land](https://github.com/fantasyland/fantasy-land) Functor, Apply and Monad specifications.\n\n### `IO.of :: a -\u003e IO e a`\n\n### `IO.error :: e -\u003e IO e a`\n\n### `IO.prototype.map :: IO e a ~\u003e (a -\u003e b) -\u003e IO e b`\n\n### `IO.prototype.ap :: IO e (a -\u003e b) ~\u003e IO e a -\u003e IO e b`\n\n### `IO.prototype.chain :: IO e a ~\u003e (a -\u003e IO e b) -\u003e IO e b`\n\n### `IO.prototype.catch :: IO e a ~\u003e (e -\u003e IO f a) -\u003e IO f a`\n\n## Wrapping custom IO functions\nOften you'll find the need to define your own io returning functions, or wrap functions provided by a library.\nLuckily, this is very simple:\n\n```js\n  const io = require('future-io')\n\n  // Wrapping a function performing some side effects in an IO.\n  // The `customOperation` function should return a promise, task or plan value.\n  const customIO = io.wrapMethod(\n    'customOperation',\n    customOperation\n  )\n```\n\n# Testing\nTesting code performing a lot of IO is usually pretty painful.\nNot so when using future-io!\n\nSimply use `fakePerform` instead of `unsafePerform` to execute your IO actions in tests.\nNow you can step through your io functions step by step,\nchecking the arguments being passed in and choosing values to return.\n\n`fakePerform()` return an object with three methods:\n- `take(actionName)`: Proceed until the next action call.\n  Assert it has type `actionName`.\n  Return a promise containg the arguments the action is being called with as an array\n- `put(returnValue)`: Call after a `take` resolves to send a return value.\n  Also call this when not returning a value, to ensure execution of the IO continues.\n- `error(ioError)`: Like `put`, but returns an error value.\n\nWhen the io execution finishes, fakePerform triggers a last `end` action.\nThis action is passed an `ioError`, if one exists, in the first-argument position.\n\n\n## Example using [ava](https://github.com/sindresorhus/ava) and async/await\n```js\nimport test from 'ava'\nimport {fakePerform} from 'future-io'\nimport ioProcess from 'future-io/node/process'\n\ntest('logging the current working directory', async t =\u003e {\n  const io = ioProcess.cwd().chain(ioProcess.stdout.write)\n  const { put, take } = fakePerform(io)\n  const cwd = '/home/foo'\n\n  await take('process.cwd')\n  put(cwd)\n\n  const [ loggedCwd ] = await take('process.stdout.write')\n  t.is(loggedCwd, cwd)\n  put()\n\n  const [ ioError ] = await take('end')\n  t.falsy(ioError)\n})\n```\n\n## Example using [mocha](https://github.com/sindresorhus/ava) and [co](https://github.com/tj/co)\n```js\nimport co from 'co'\nimport {fakePerform} from 'future-io'\nimport ioProcess from 'future-io/node/process'\nimport assert from 'assert'\n\nit('logs the current working directory', co.wrap(function* () {\n  const io = ioProcess.cwd().chain(ioProcess.stdout.write)\n  const { put, take } = fakePerform(io)\n  const cwd = '/home/foo'\n\n  yield take('process.cwd')\n  yield put(cwd)\n\n  const [ loggedCwd ] = yield take('process.stdout.write')\n  assert.equal(loggedCwd, cwd)\n  put()\n\n  const [ ioError ] = yield take('end')\n  assert.ifError(ioError)\n}))\n```\n","funding_links":[],"categories":["Libraries"],"sub_categories":["[Javascript](https://developer.mozilla.org/en-US/docs/Web/JavaScript)"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffuturize%2Ffuture-io","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffuturize%2Ffuture-io","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffuturize%2Ffuture-io/lists"}