{"id":19884225,"url":"https://github.com/yawaramin/prometo","last_synced_at":"2025-05-02T15:30:50.607Z","repository":{"id":147930882,"uuid":"226610868","full_name":"yawaramin/prometo","owner":"yawaramin","description":"A type-safe JavaScript promise library for ReasonML","archived":false,"fork":false,"pushed_at":"2020-09-28T02:41:43.000Z","size":49,"stargazers_count":31,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-04-24T23:04:19.125Z","etag":null,"topics":["bucklescript","ocaml","reasonml"],"latest_commit_sha":null,"homepage":"https://yawaramin.github.io/prometo/","language":"Reason","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/yawaramin.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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":"2019-12-08T03:50:52.000Z","updated_at":"2024-11-05T00:46:11.000Z","dependencies_parsed_at":null,"dependency_job_id":"d33640d2-69c3-4b9d-8ecb-06c41f727707","html_url":"https://github.com/yawaramin/prometo","commit_stats":null,"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yawaramin%2Fprometo","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yawaramin%2Fprometo/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yawaramin%2Fprometo/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yawaramin%2Fprometo/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/yawaramin","download_url":"https://codeload.github.com/yawaramin/prometo/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252062711,"owners_count":21688587,"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":["bucklescript","ocaml","reasonml"],"created_at":"2024-11-12T17:25:51.115Z","updated_at":"2025-05-02T15:30:50.601Z","avatar_url":"https://github.com/yawaramin.png","language":"Reason","funding_links":[],"categories":[],"sub_categories":[],"readme":"## Prometo\n\n[![npm](https://img.shields.io/npm/v/@yawaramin/prometo.svg)](https://npmjs.org/package/@yawaramin/prometo)\n[![Build Status](https://dev.azure.com/yawaramin/prometo/_apis/build/status/yawaramin.prometo?branchName=main)](https://dev.azure.com/yawaramin/prometo/_build/latest?definitionId=1\u0026branchName=main)\n\nA type-safe promise type for ReasonML, built directly on top of\nJavaScript but adding fine-grained error control and promise\ncancellation.\n\n## How it works\n\nPrometo is type-safe because of the following:\n\n- It's not just a 'promise of your data', it's a 'promise of result of\n  your data'. In other words, it can't be affected by JavaScript\n  promises' well-known unsoundness issue where a 'promise of promise of\n  data' is collapsed at runtime to a 'promise of data'.\n- Also because a Prometo promise is a 'promise of result of data', it\n  encodes an error at the type-level using the Reason `result('a, 'e)`\n  type. In fact, Prometo ensures that its wrapped promises are not\n  rejected, as long as you use its operations. So you can be sure that a\n  Prometo promise is actually not going to throw at runtime. The only\n  point at which you need to care about catching a possible exception is\n  when converting it back into a normal JavaScript promise.\n\nBecause it's just a JavaScript promise wrapper, it's also easy to\nconvert back and forth between JavaScript and Prometo promises.\n\n## Fine-grained error management\n\nUsing the technique described in\n[Composable Error Handling in OCaml](https://keleshev.com/composable-error-handling-in-ocaml),\nPrometo exposes an error type `'e` directly in its main polymorphic\npromise type `Prometo.t('a, 'e)`. This allows you to explicitly track\nand manage errors at every point of the code where you use these\npromises.\n\n## Interoperability\n\nIt's easy to interop with JavaScript promises:\n\n- Use `fromPromise` to convert from a JavaScript Promise to a Prometo\n  promise\n- `toPromise` to convert from Prometo to a JavaScript promise\n- `thenPromise` to chain together a Prometo promise and a function that\n  returns a JavaScript Promise, and keep the result as a type-safe\n  Prometo promise.\n\n## Cancellation\n\nPrometo promises can be cancelled at any point of usage in the code,\nusing `Prometo.cancel`. The only caveat is that when you cancel a\npromise, it doesn't _immediately_ halt whatever is running inside that\npromise, but lets it run until its result is used by the next `flatMap`\nin the promise chain. At that point, the _next_ promise automatically\nturns into a cancelled promise, stopping whatever was about to happen\nnext from happening.\n\nThis also does mean that if you want to cancel a promise chain, you need\nto ensure that you keep a reference to the _first_ promise in the chain\nand cancel _that._\n\nWhile not as immediate as something like\n[abortable fetch](https://developers.google.com/web/updates/2017/09/abortable-fetch),\nin practice this is more general-purpose (it works with any promise, not\njust ones returned by `fetch`), and it's enough to prevent errors like\n[calling `setState` on an unmounted React component](https://reactjs.org/blog/2015/12/16/ismounted-antipattern.html).\nFor example:\n\n```reason\nlet example = fetch(\"https://example.com\");\nPrometo.forEach(~f=setState, example);\n\n// later...\nPrometo.cancel(example); // this will prevent setState from being called\n```\n\nCancelling a promise too late in the chain won't work:\n\n```reason\nlet result = \"https://example.com\"\n  |\u003e fetch\n  |\u003e Prometo.map(~f=setState);\n\n// later...\nPrometo.cancel(result); // won't work, too late, setState has already been called\n```\n\n## Add to project\n\n- Add the `@yawaramin/prometo` project to your `package.json` (version\n  number in badge at the top of the readme)\n- Add the `@yawaramin/prometo` dependency to your `bs-dependencies` list\n  in `bsconfig.json`\n- Run `npx bsb -clean-world`, then `npx bsb -make-world`\n- (Optional but\n  [recmomended](https://dev.to/yawaramin/consuming-a-modular-ocaml-project-structure-1a2e))\n  if you don't have one already, create a `Yawaramin.re` (or `.ml`) file\n  under `src/` and alias the Prometo main module there:\n  `module Prometo = Yawaramin__Prometo`. This lets you access it under\n  the `Yawaramin.Prometo` namespace throughout your project \n\n## API docs\n\nPlease go to https://yawaramin.github.io/prometo/\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyawaramin%2Fprometo","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fyawaramin%2Fprometo","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyawaramin%2Fprometo/lists"}