{"id":16058047,"url":"https://github.com/tylim88/firecaller","last_synced_at":"2025-10-28T16:09:35.374Z","repository":{"id":39903222,"uuid":"488052354","full_name":"tylim88/FireCaller","owner":"tylim88","description":"🔥Write callable functions systematically like a Firelord. No more chaotic error handling, no more unsafe endpoint data type, no more messy validation. Be the Master of Fire you always wanted to be.","archived":false,"fork":false,"pushed_at":"2022-11-08T08:23:28.000Z","size":680,"stargazers_count":4,"open_issues_count":1,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2024-05-21T12:08:43.577Z","etag":null,"topics":["firebase","firebase-functions","typescript"],"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/tylim88.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":"2022-05-03T02:16:35.000Z","updated_at":"2023-03-07T05:10:01.000Z","dependencies_parsed_at":"2022-07-06T04:01:20.005Z","dependency_job_id":null,"html_url":"https://github.com/tylim88/FireCaller","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/tylim88%2FFireCaller","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tylim88%2FFireCaller/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tylim88%2FFireCaller/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tylim88%2FFireCaller/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tylim88","download_url":"https://codeload.github.com/tylim88/FireCaller/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243902293,"owners_count":20366260,"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":["firebase","firebase-functions","typescript"],"created_at":"2024-10-09T03:06:07.612Z","updated_at":"2025-10-28T16:09:30.266Z","avatar_url":"https://github.com/tylim88.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003c!-- markdownlint-disable MD010 --\u003e\n\u003c!-- markdownlint-disable MD033 --\u003e\n\u003c!-- markdownlint-disable MD041 --\u003e\n\n\u003cdiv align=\"center\"\u003e\n\t\t\u003cimg src=\"https://raw.githubusercontent.com/tylim88/Firelord/main/img/ozai.png\" width=\"200px\"/\u003e\n\t\t\u003ch1\u003eFireCaller 烈火呼\u003c/h1\u003e\n\u003c/div\u003e\n\n\u003cdiv align=\"center\"\u003e\n\t\t\u003ca href=\"https://www.npmjs.com/package/firecaller\" target=\"_blank\"\u003e\n\t\t\t\t\u003cimg\n\t\t\t\t\tsrc=\"https://img.shields.io/npm/v/firecaller\"\n\t\t\t\t\talt=\"Created by tylim88\"\n\t\t\t\t/\u003e\n\t\t\t\u003c/a\u003e\n\t\t\t\u0026nbsp;\n\t\t\t\u003ca\n\t\t\t\thref=\"https://github.com/tylim88/firecaller/blob/main/LICENSE\"\n\t\t\t\ttarget=\"_blank\"\n\t\t\t\u003e\n\t\t\t\t\u003cimg\n\t\t\t\t\tsrc=\"https://img.shields.io/github/license/tylim88/firecaller\"\n\t\t\t\t\talt=\"License\"\n\t\t\t\t/\u003e\n\t\t\t\u003c/a\u003e\n\t\t\t\u0026nbsp;\n\t\t\t\u003ca\n\t\t\t\thref=\"https://www.npmjs.com/package/firecaller?activeTab=dependencies\"\n\t\t\t\ttarget=\"_blank\"\n\t\t\t\u003e\n\t\t\t\t\u003cimg\n\t\t\t\t\tsrc=\"https://img.shields.io/badge/dynamic/json?url=https://api.npmutil.com/package/firecaller\u0026label=dependencies\u0026query=$.dependencies.count\u0026color=brightgreen\"\n\t\t\t\t\talt=\"dependency count\"\n\t\t\t\t/\u003e\n\t\t\t\u003c/a\u003e\n\t\t\t\u0026nbsp;\n\t\t\t\u003cimg\n\t\t\t\tsrc=\"https://img.shields.io/badge/gzipped-0.5KB-brightgreen\"\n\t\t\t\talt=\"package size\"\n\t\t\t/\u003e\n\t\t\t\u0026nbsp;\n\t\t\t\u003ca href=\"https://github.com/tylim88/FireCaller/actions\" target=\"_blank\"\u003e\n\t\t\t\t\u003cimg\n\t\t\t\t\tsrc=\"https://github.com/tylim88/FireCaller/workflows/Main/badge.svg\"\n\t\t\t\t\talt=\"github action\"\n\t\t\t\t/\u003e\n\t\t\t\u003c/a\u003e\n\t\t\t\u0026nbsp;\n\t\t\t\u003ca href=\"https://codecov.io/gh/tylim88/FireCaller\" target=\"_blank\"\u003e\n\t\t\t\t\u003cimg\n\t\t\t\t\tsrc=\"https://codecov.io/gh/tylim88/FireCaller/branch/main/graph/badge.svg\"\n\t\t\t\t\talt=\"code coverage\"\n\t\t\t\t/\u003e\n\t\t\t\u003c/a\u003e\n\t\t\t\u0026nbsp;\n\t\t\t\u003ca href=\"https://github.com/tylim88/FireCaller/issues\" target=\"_blank\"\u003e\n\t\t\t\t\u003cimg\n\t\t\t\t\talt=\"GitHub issues\"\n\t\t\t\t\tsrc=\"https://img.shields.io/github/issues-raw/tylim88/FireCaller\"\n\t\t\t\t\u003e\u003c/img\u003e\n\t\t\t\u003c/a\u003e\n\t\t\t\u0026nbsp;\n\t\t\t\u003ca href=\"https://snyk.io/test/github/tylim88/FireCaller\" target=\"_blank\"\u003e\n\t\t\t\t\u003cimg\n\t\t\t\t\tsrc=\"https://snyk.io/test/github/tylim88/FireCaller/badge.svg\"\n\t\t\t\t\talt=\"code coverage\"\n\t\t\t\t/\u003e\n\t\t\t\u003c/a\u003e\n\t\t\t\u0026nbsp;\n\t\t\t\u003ca\n\t\t\t\thref=\"https://lgtm.com/projects/g/tylim88/FireCaller/alerts/\"\n\t\t\t\ttarget=\"_blank\"\n\t\t\t\u003e\n\t\t\t\t\u003cimg\n\t\t\t\t\talt=\"Total alerts\"\n\t\t\t\t\tsrc=\"https://img.shields.io/lgtm/alerts/g/tylim88/FireCaller.svg?logo=lgtm\u0026logoWidth=18\"\n\t\t\t\t/\u003e\n\t\t\t\u003c/a\u003e\n\t\t\t\u0026nbsp;\n\t\t\t\u003ca\n\t\t\t\thref=\"https://lgtm.com/projects/g/tylim88/FireCaller/context:javascript\"\n\t\t\t\ttarget=\"_blank\"\n\t\t\t\u003e\n\t\t\t\t\u003cimg\n\t\t\t\t\talt=\"Language grade: JavaScript\"\n\t\t\t\t\tsrc=\"https://img.shields.io/lgtm/grade/javascript/g/tylim88/FireCaller.svg?logo=lgtm\u0026logoWidth=18\"\n\t\t\t\t/\u003e\n\t\t\t\u003c/a\u003e\n\t\t\t\u003cbr/\u003e\n\t\t\t\u003cbr/\u003e\n\t\t\t\u003cp\u003e🔥 Write callable functions systematically like a Firelord. No more chaotic error handling, no more unsafe endpoint data type, no more messy validation. Be the Master of Fire you always wanted to be.\u003c/p\u003e\n\u003c/div\u003e\n\u003cbr/\u003e\n\u003cbr/\u003e\n\nFireCaller validate response and handle error from [FireCall](https://github.com/tylim88/FireCall).\n\nIt wraps around Firebase callable functions to provide type safety for you request data and response data with [zod](https://www.npmjs.com/package/zod).\n\nDo not use this library if you are not using FireCall.\n\nFireCaller is a library for Web, FireCall is for Nodejs.\n\nUsable with [Emulator](#usage-with-emulator)\n\n## Why Do You Need This? What Is The Problem FireCall Trying To Solve?\n\nRead [Here](https://github.com/tylim88/FireCall#why-do-you-need-this-what-is-the-problem-firecall-trying-to-solve)\n\n## Installation\n\n```bash\nnpm i firecaller firebase zod\n```\n\nand of course you need `typescript`.\n\n## Create Schema With Zod\n\nNormally this file is created on backend and share to frontend.\n\nTips: You can also use these schemas to validate your form, learn more at [zod](https://github.com/colinhacks/zod)!\n\n```ts\nimport { z } from 'zod'\n\nexport const updateUserSchema = {\n\t//request data schema\n\treq: z.object({\n\t\tname: z.string(),\n\t\tage: z.number(),\n\t\taddress: z.string(),\n\t}),\n\t// response data schema\n\tres: z.undefined(),\n\t// function name\n\tname: 'updateUser',\n}\n\nexport const getUserSchema = {\n\tres: z.string(), // userId\n\tres: z.object({\n\t\tname: z.string(),\n\t\tage: z.number(),\n\t}),\n\tname: 'getUser',\n}\n```\n\n## Create Callable Functions\n\n```ts\nimport { initializeApp } from 'firebase/app'\nimport { callable } from 'firecaller'\nimport { updateUserSchema, getUserSchema } from './someFile'\n\nexport const app = initializeApp(yourConfig) // must initialize app before using firecaller\n\nconst funRef = getFunctions(app)\n\n// now create the specific callable\nexport const updateUser = callable(updateUserSchema) // or callable(updateUserSchema, funRef)\nexport const getUser = callable(getUserSchema) // or callable(getUserSchema, funRef)\n```\n\n## Calling\n\n**FireCaller never throw**, all errors are caught and returned as object. We choose this pattern because it is impossible to type-safe rejected promise.\n\nBy checking the value of the `code`, you know how to deal with them:\n\n| code                                                                                                                                                                                                                                                                                                                                                                                                                                    | meaning                                                                                 |\n| --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------- |\n| ok                                                                                                                                                                                                                                                                                                                                                                                                                                      | success, you can access the `data` value                                                |\n| schema-out-of-sync                                                                                                                                                                                                                                                                                                                                                                                                                      | Incorrect response data shape, your schema is out of sync, you can access the `message` |\n| 'functions/cancelled', 'functions/unknown', 'functions/invalid-argument', 'functions/deadline-exceeded', 'functions/not-found', 'functions/already-exists', 'functions/permission-denied', 'functions/resource-exhausted', 'functions/failed-precondition', 'functions/aborted', 'functions/out-of-range', 'functions/unimplemented', 'functions/internal', 'functions/unavailable', 'functions/data-loss', 'functions/unauthenticated' | the error source is FireCall in NodeJS, you can access the `message`.                   |\n\n```ts\nimport { updateUser, getUser } from './someOtherFile'\n\nconst { name, age, address } = someFormData()\n\nupdateUser(\n\t// input type depends on schema.req\n\t{ name, age, address } // { name: string, age: number, address: string }\n).then(res =\u003e {\n\tconst { code } = res\n\tif (code === 'ok') {\n\t\tconst data = res.data // data type depends on what you define in schema.res\n\t} else {\n\t\tconst { code, message } = res\n\t\t// message is string\n\t}\n})\n```\n\n## Usage With Emulator\n\n```ts\nimport { initializeApp } from 'firebase/app'\nimport { getFunctions, connectFunctionsEmulator } from 'firebase/functions'\nimport { callable } from 'firecaller'\nimport { z } from 'zod'\n\nconst app = initializeApp({ projectId: `### YOUR_PROJECT_ID` })\nconst functions = getFunctions(app)\n\nconnectFunctionsEmulator(functions, 'localhost', f.emulators.functions.port)\n\nconst schema = {\n\treq: z.string(),\n\tres: z.string(),\n\tname: 'hello',\n}\n\nconst helloCallable = callable(schema, functions)\n\ndescribe('test callable', () =\u003e {\n\tit('success', async () =\u003e {\n\t\tconst result = await helloCallable('hello')\n\n\t\texpect(result.code).toBe('ok')\n\t\texpect(result.data).toEqual('hello')\n\t})\n\n\tit('invalid arguments', async () =\u003e {\n\t\t// @ts-expect-error\n\t\tconst result = await helloCallable(123) // wrong input type\n\n\t\texpect(result.code).toBe('functions/invalid-argument')\n\t\texpect(result.message).toEqual('invalid-argument')\n\t})\n})\n```\n\n## Related Projects\n\n1. [FirelordJS](https://github.com/tylim88/Firelordjs) - Typescript wrapper for Firestore Web V9\n2. [Firelord](https://github.com/tylim88/Firelord) - Typescript wrapper for Firestore Admin\n3. [Firelordrn](https://github.com/tylim88/firelordrn) - Typescript wrapper for Firestore React Native\n4. [FireLaw](https://github.com/tylim88/firelaw) - Write Firestore security rule with Typescript, utilizing Firelord type engine.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftylim88%2Ffirecaller","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftylim88%2Ffirecaller","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftylim88%2Ffirecaller/lists"}