{"id":26255214,"url":"https://github.com/reaxi/promises","last_synced_at":"2025-06-19T01:37:57.831Z","repository":{"id":59513203,"uuid":"465626064","full_name":"reaxi/promises","owner":"reaxi","description":null,"archived":false,"fork":false,"pushed_at":"2022-09-19T02:47:01.000Z","size":84013,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2025-03-13T19:17:47.677Z","etag":null,"topics":["hackertoberfest"],"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/reaxi.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","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":"2022-03-03T08:10:43.000Z","updated_at":"2025-03-01T19:24:46.000Z","dependencies_parsed_at":"2023-01-18T13:45:42.596Z","dependency_job_id":null,"html_url":"https://github.com/reaxi/promises","commit_stats":null,"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"purl":"pkg:github/reaxi/promises","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/reaxi%2Fpromises","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/reaxi%2Fpromises/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/reaxi%2Fpromises/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/reaxi%2Fpromises/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/reaxi","download_url":"https://codeload.github.com/reaxi/promises/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/reaxi%2Fpromises/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":260664572,"owners_count":23044209,"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":["hackertoberfest"],"created_at":"2025-03-13T19:17:52.890Z","updated_at":"2025-06-19T01:37:52.811Z","avatar_url":"https://github.com/reaxi.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# @reaxi/promises\n\nPromise (async/await) reusable structure for functions\n\n\u003e modern promises runtime to avoid [callback hell](http://callbackhell.com/)\n\n\u003e inspired by monad's design structure\n\n```sh\nyarn add @reaxi/promises\n\n# npm i @reaxi/promises\n```\n\n## Features\n\n-   functions run error secure with try/catch\n-   typescript powered\n-   build better programs\n-   code consistency (dry)\n-   cleaner code\n\n\u003e please note: this package is not an polyfill or Promise implementation, you still write your pure functions and tests isolated\n\n## promise\n\n```ts\nimport { promise } from '@reaxi/promises';\n\nasync function myApp() {\n    const [result1, err1] = await promise(() =\u003e myFunctionA({ arg: 1 }));\n    const [result2, err2] = await promise(() =\u003e myFunctionB({ arg: 2 }));\n    const [result3, err3] = await promise(() =\u003e myFunctionC({ arg: 3 }));\n    const [result3, err4] = await promise(() =\u003e myFunctionD({ arg: 4 }));\n    const [result5, err5] = await promise(myFunctionE); //function with no args\n\n    if()//....\n\n    // very clean 👌\n}\n```\n\n### Signature\n\n```ts\n//    data | Error\nconst [data, null ] = await promise(() =\u003e myFn(myArgs), options); //if your function return data\nconst [null, error] = await promise(() =\u003e myFn(myArgs), options); //if your function fails (Error)\n```\n\n### What about **then** ?\n\n```ts\nconst [one] = await promise(() =\u003e 1, { then: res =\u003e res.toString() }); // '1'\n\nconst [posts] = await promise(() =\u003e fetch('/posts'), {\n    then: res =\u003e res.json(),\n}); //\n```\n\n### On Error\n\n```ts\nconst [data] = await promise(() =\u003e fetch('/possible-err'), {\n    onError: error =\u003e console.log(error),\n}); //\n```\n\n### On Finally\n\n```ts\nconst [data] = await promise(() =\u003e fetch('/user'), {\n    onFinally: () =\u003e console.log('done'),\n}); //\n```\n\n### skipping\n\n\u003e you can skip function call with a pre-flight parameter\n\n```ts\nconst [reports] = await promise(() =\u003e fetch('/reports'), {\n    skip: true, // or any function that returns a boolean like: validate(x): boolean\n}); //\n```\n\n### options re-usage\n\n```ts\nimport type { PromiseOptionsGen } from '@reaxi/promises';\n\ntype R = Awaited\u003cReturnType\u003ctypeof MyFn\u003e\u003e;\n\nconst options: PromiseOptionsGen\u003cR\u003e = {\n    then: res =\u003e [res],\n    onError: console.log,\n    skip: isGuest(),\n};\n\nconst [result1, err1] = await promise(() =\u003e MyFn({ id: 1 }), options);\nconst [result2, err2] = await promise(() =\u003e MyFn({ id: 2 }), options);\nconst [result3, err3] = await promise(() =\u003e MyFn({ id: 3 }), options);\n```\n\n## How it works?\n\nES6/ES8 Features\n\n-   Promises\n-   async/await\n-   try/catch\n-   async generators\n\n## Options\n\n```ts\nconst options: PromiseOptionsGen = {\n    then: (result: R) =\u003e T, //function\n    onError: (e: Error) =\u003e any, //function\n    onFinally: () =\u003e any, //function\n    skip: true | false, //boolean\n};\n```\n\n## Examples:\n\nthey are trivial examples, you can use `promise` better with your application context\n\n### fetch\n\n```ts\nimport { promise } from '@reaxi/promises';\nimport fetch from 'cross-fetch';\n\ntype TodoResponse = {\n    userId: number;\n    id: number;\n    title: string;\n    completed: boolean;\n};\n\nexport async function myPackage() {\n    const [val, err] = await promise(\n        () =\u003e fetch('https://jsonplaceholder.typicode.com/todos/1xx'),\n        {\n            then: res =\u003e {\n                if (res.status === 404) throw new Error('Todo Not found');\n                return res.json() as Promise\u003cTodoResponse\u003e;\n            },\n        }\n    );\n\n    if (val) console.log(val?.title);\n    if (err) console.log(err.message);\n}\n\nmyPackage();\n```\n\n### Options re-usage\n\n```ts\ntype R = Awaited\u003cReturnType\u003ctypeof getTodos\u003e\u003e;\n\nconst getTodos = (id?: number) =\u003e\n    fetch(`https://jsonplaceholder.typicode.com/todos/${id}`);\n\nconst opts = {\n    then: (res: R) =\u003e {\n        if (res.status === 404) throw new Error('Todo Not found');\n        return res.json() as Promise\u003cTodoResponse\u003e;\n    },\n};\n\nexport async function myPackage() {\n    const [todo1, err1] = await promise(() =\u003e getTodos(1), opts);\n    const [todo2, err2] = await promise(() =\u003e getTodos(999), opts);\n    // ...\n\n    if (todo1) console.log(todo1?.title); // 'delectus aut autem'\n    if (err1) console.log(err1.message); // null\n\n    if (todo2) console.log(todo2?.title); // null\n    if (err2) console.log(err2.message); // 'Todo Not found'\n}\n```\n\n### nextjs api handlers\n\n\u003e this example works for similar request/request handlers too\n\n```ts\nimport { NextApiRequest, NextApiResponse } from 'next';\nimport { promise } from '@reaxi/promises';\n\nasync function getData(id) {\n    const response = await get(`/data/${id}`);\n    if (!response.data) throw new Error(`No Data found with id: ${id}`);\n\n    return response.data;\n}\n\nasync function validateRequest(RequestMethod, allowedMethod) {\n    if (RequestMethod !== allowedMethod) throw new Error('Method Not Allowed');\n}\n\nexport default async (req: NextApiRequest, res: NextApiResponse) =\u003e {\n    await promise(() =\u003e validateRequest(req.method, 'GET'), {\n        onError: e =\u003e res.status(405).end(e.message), // e.message: 'Method Not Allowed'\n    });\n\n    const [id] = await promise(() =\u003e req.body.id, {\n        onError: e =\u003e res.status(400).end('Missing id'),\n    });\n\n    await promise(() =\u003e getData(id), {\n        then: data =\u003e res.status(200).json(data),\n        onError: e =\u003e res.status(403).end(e?.message),\n    });\n};\n```\n\n### subsequent functions\n\nthis example will showcase an pipeline of subsequent functions\n\nevery time you call `promise` your function will be executed safely with try/catch,\neven if return an Error the program will continue the next functions,\nto stop you can re-throw the error or stop the program\n\n```ts\nexport async function myWorkflow() {\n    await promise(() =\u003e init(), {\n        onError: process.exit, // stop the program on error\n    });\n    await promise(setup, {\n        onError: e =\u003e {\n            throw e;\n        }, // re-throw the catch Error to be handled by the outer function (if the outer function doesn't catch, the program stops with the Error)\n    });\n    await promise(optionalRuntime); // optional function without args (the program will continue on error)\n    await promise(() =\u003e calculate(a, b)); // optional function with args (the program will continue on error)\n    const [app] = await promise(startApp, {\n        then: () =\u003e console.log('app started'),\n    });\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Freaxi%2Fpromises","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Freaxi%2Fpromises","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Freaxi%2Fpromises/lists"}