{"id":13618082,"url":"https://github.com/TomerAberbach/grfn","last_synced_at":"2025-04-14T10:31:01.759Z","repository":{"id":45740474,"uuid":"325729490","full_name":"TomerAberbach/grfn","owner":"TomerAberbach","description":"🦅 A tiny (~315B) utility that executes a dependency graph of async functions as concurrently as possible.","archived":false,"fork":false,"pushed_at":"2024-10-15T03:14:34.000Z","size":1085,"stargazers_count":616,"open_issues_count":3,"forks_count":5,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-04-13T15:09:28.930Z","etag":null,"topics":["async","concurrency","graph","node-module","node-package","package"],"latest_commit_sha":null,"homepage":"https://npm.im/grfn","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/TomerAberbach.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":"contributing.md","funding":null,"license":"license","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-12-31T06:15:34.000Z","updated_at":"2025-04-07T16:36:43.000Z","dependencies_parsed_at":"2024-05-12T04:31:41.369Z","dependency_job_id":"67d319b7-1d98-45f4-ac4a-7012bc54a1d1","html_url":"https://github.com/TomerAberbach/grfn","commit_stats":{"total_commits":111,"total_committers":3,"mean_commits":37.0,"dds":"0.018018018018018056","last_synced_commit":"3cf70695e38b6f2aac5d5ede187e1016d27f5f56"},"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TomerAberbach%2Fgrfn","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TomerAberbach%2Fgrfn/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TomerAberbach%2Fgrfn/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TomerAberbach%2Fgrfn/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/TomerAberbach","download_url":"https://codeload.github.com/TomerAberbach/grfn/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248732486,"owners_count":21152852,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["async","concurrency","graph","node-module","node-package","package"],"created_at":"2024-08-01T20:01:54.232Z","updated_at":"2025-04-14T10:31:01.739Z","avatar_url":"https://github.com/TomerAberbach.png","language":"TypeScript","funding_links":["https://github.com/sponsors/TomerAberbach"],"categories":["JavaScript","TypeScript"],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n  \u003cimg src=\"grfn.svg\" alt=\"grfn\" width=\"400\" /\u003e\n\u003c/div\u003e\n\n\u003ch1 align=\"center\"\u003e\n  grfn\n\u003c/h1\u003e\n\n\u003cdiv align=\"center\"\u003e\n  \u003ca href=\"https://npmjs.org/package/grfn\"\u003e\n    \u003cimg src=\"https://badgen.now.sh/npm/v/grfn\" alt=\"version\" /\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://github.com/TomerAberbach/grfn/actions\"\u003e\n    \u003cimg src=\"https://github.com/TomerAberbach/grfn/workflows/CI/badge.svg\" alt=\"CI\" /\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://unpkg.com/grfn/dist/index.min.js\"\u003e\n    \u003cimg src=\"https://deno.bundlejs.com/?q=grfn\u0026badge\" alt=\"gzip size\" /\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://unpkg.com/grfn/dist/index.min.js\"\u003e\n    \u003cimg src=\"https://deno.bundlejs.com/?q=grfn\u0026config={%22compression%22:{%22type%22:%22brotli%22}}\u0026badge\" alt=\"brotli size\" /\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://licenses.dev/npm/grfn\"\u003e\n    \u003cimg src=\"https://licenses.dev/b/npm/grfn\" alt=\"licenses\" /\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://github.com/sponsors/TomerAberbach\"\u003e\n    \u003cimg src=\"https://img.shields.io/static/v1?label=Sponsor\u0026message=%E2%9D%A4\u0026logo=GitHub\u0026color=%23fe8e86\" alt=\"Sponsor\"\u003e\n  \u003c/a\u003e\n\u003c/div\u003e\n\n\u003cdiv align=\"center\"\u003e\n  A tiny (~315B) utility that executes a dependency graph of async functions as concurrently as possible.\n\u003c/div\u003e\n\n## Features\n\n- **Lightweight:** ~315 bytes gzipped\n- **Unobtrusive and Unopinionated:** takes normal functions; returns a normal\n  function!\n- **Isomorphic:** works in node and the browser\n- **Easy Debugging:** provides type-level validation of the input graph,\n  including cycle detection!\n- **Awesome Logo:** designed by [Jill Marbach](https://jillmarbach.com)!\n\n## Table of Contents\n\n- [Install](#install)\n- [Usage](#usage)\n- [API](#api)\n- [Contributing](#contributing)\n- [License](#license)\n\n## Install\n\n```sh\n$ npm i grfn\n```\n\n## Usage\n\n\u003cimg src=\"animation.gif\" width=\"350\" align=\"right\"\u003e\n\n```js\nimport { setTimeout } from 'node:timers/promises'\nimport grfn from 'grfn'\n\nconst fn = grfn({\n  // `e` depends on `a`, `c`, and `d`. Call `e` with the results of the\n  // functions once their returned promises resolve.\n  e: [\n    async (a, c, d) =\u003e {\n      await setTimeout(10)\n      return a * c * d\n    },\n    [`a`, `c`, `d`],\n  ],\n\n  // `d` depends on `b`.\n  d: [\n    async b =\u003e {\n      await setTimeout(1)\n      return b * 2\n    },\n    [`b`],\n  ],\n\n  // `c` depends on `a` and `b`.\n  c: [\n    async (a, b) =\u003e {\n      await setTimeout(5)\n      return a + b\n    },\n    [`a`, `b`],\n  ],\n\n  // `a` and `b` have no dependencies! But they must still be listed. They take\n  // the input given to `fn`.\n  a: async (n1, n2, n3) =\u003e {\n    await setTimeout(15)\n    return n1 + n2 + n3\n  },\n  b: async (n1, n2, n3) =\u003e {\n    await setTimeout(10)\n    return n1 * n2 * n3\n  },\n})\n\nconst output = await fn(4, 2, 3)\n\n// This will be the output of `e` because no function depends on it!\nconsole.log(`final output: ${output}`)\n```\n\nOutput:\n\n```\nfinal output: 14256\n```\n\n### Debugging\n\nThe graph will be automatically validated, including cycle detection, via\nTypeScript magic!\n\n## API\n\n### `grfn(vertices) =\u003e (...args) =\u003e Promise`\n\nReturns a function that runs the dependency graph of functions described by\n`vertices`:\n\n- Input: passed to the functions that don't have dependencies in the graph.\n- Output: a `Promise` that resolves to the value returned from the graph's\n  _output function_, the function that is not depended on by any function.\n\n#### `vertices`\n\nType: `{ [key: string]: Function | [Function, string[]?] }`\n\nAn object describing a dependency graph of functions.\n\nEach value in `vertices` must be either:\n\n- A pair containing a function and its array of dependencies by key (e.g.\n  `[fnA, ['keyB', 'keyC']]`)\n- Or a function (equivalent to `[fn, []]`)\n\nThe following constraints, which are validated via TypeScript magic, must also\nbe met:\n\n- Each dependency in `vertices` must also appear as a non-dependency:\n  - Not okay (`b` doesn't appear as a non-dependency):\n    ```js\n    grfn({\n      a: [fnA, [`b`]],\n    })\n    ```\n  - Okay:\n    ```js\n    grfn({\n      a: [fnA, [`b`]],\n      b: fnB,\n    })\n    ```\n- `vertices` must describe an\n  [acyclic](https://en.wikipedia.org/wiki/Directed_acyclic_graph) dependency\n  graph:\n  - Not okay (cycle: `a -\u003e b -\u003e a`):\n    ```js\n    grfn({\n      a: [fnA, [`b`]],\n      b: [fnB, [`a`]],\n    })\n    ```\n  - Okay:\n    ```js\n    grfn({\n      a: [fnA, [`b`]],\n      b: fnB,\n    })\n    ```\n- `vertices` must have exactly one _output function_, a function that is not\n  depended on by any function:\n  - Not okay (both `b` and `c` are not depended on by any function):\n    ```js\n    grfn({\n      b: [fnB, [`a`]],\n      c: [fnC, [`a`]],\n      a: fnA,\n    })\n    ```\n  - Okay:\n    ```js\n    grfn({\n      d: [fnD, [`b`, `c`]],\n      b: [fnB, [`a`]],\n      c: [fnC, [`a`]],\n      a: fnA,\n    })\n    ```\n\n## Contributing\n\nStars are always welcome!\n\nFor bugs and feature requests,\n[please create an issue](https://github.com/TomerAberbach/grfn/issues/new).\n\nFor pull requests, please read the\n[contributing guidelines](https://github.com/TomerAberbach/grfn/blob/main/contributing.md).\n\n## License\n\n[Apache 2.0](https://github.com/TomerAberbach/grfn/blob/main/license)\n\nThis is not an official Google product.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FTomerAberbach%2Fgrfn","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FTomerAberbach%2Fgrfn","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FTomerAberbach%2Fgrfn/lists"}