{"id":14973110,"url":"https://github.com/andrebraghini/firebase-triggers","last_synced_at":"2026-03-03T15:04:25.581Z","repository":{"id":54631911,"uuid":"308493084","full_name":"andrebraghini/firebase-triggers","owner":"andrebraghini","description":"A TypeScript library that provides decorators to link class methods to Firebase Authentication, Firestore and PubSub triggers.","archived":false,"fork":false,"pushed_at":"2024-12-03T19:24:41.000Z","size":953,"stargazers_count":16,"open_issues_count":0,"forks_count":2,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-08-09T06:27:28.760Z","etag":null,"topics":["firebase","javascript","nodejs","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/andrebraghini.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-10-30T01:28:02.000Z","updated_at":"2025-04-09T10:17:11.000Z","dependencies_parsed_at":"2024-12-03T17:22:27.383Z","dependency_job_id":"7336e6de-84f8-410b-93fb-13a59b24fa63","html_url":"https://github.com/andrebraghini/firebase-triggers","commit_stats":{"total_commits":90,"total_committers":5,"mean_commits":18.0,"dds":"0.12222222222222223","last_synced_commit":"e4293632f52cecf0daf66de4f8d322d453fcdcaa"},"previous_names":[],"tags_count":16,"template":false,"template_full_name":null,"purl":"pkg:github/andrebraghini/firebase-triggers","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andrebraghini%2Ffirebase-triggers","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andrebraghini%2Ffirebase-triggers/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andrebraghini%2Ffirebase-triggers/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andrebraghini%2Ffirebase-triggers/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/andrebraghini","download_url":"https://codeload.github.com/andrebraghini/firebase-triggers/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andrebraghini%2Ffirebase-triggers/sbom","scorecard":{"id":192532,"data":{"date":"2025-08-11","repo":{"name":"github.com/andrebraghini/firebase-triggers","commit":"e6aede74a9f64e7847d2de5d17d9decd1574ce23"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3,"checks":[{"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":"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":"Code-Review","score":0,"reason":"Found 1/26 approved changesets -- score normalized to 0","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":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/ci.yml:1","Info: no jobLevel write permissions found"],"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":"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":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","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":"Pinned-Dependencies","score":3,"reason":"dependency not pinned by hash detected -- score normalized to 3","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:17: update your workflow using https://app.stepsecurity.io/secureworkflow/andrebraghini/firebase-triggers/ci.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:19: update your workflow using https://app.stepsecurity.io/secureworkflow/andrebraghini/firebase-triggers/ci.yml/main?enable=pin","Info:   0 out of   2 GitHub-owned GitHubAction dependencies pinned","Info:   1 out of   1 npmCommand dependencies pinned"],"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":"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":"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":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'main'"],"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 7 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"}},{"name":"Vulnerabilities","score":3,"reason":"7 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GHSA-968p-4wvh-cqc8","Warn: Project is vulnerable to: GHSA-v6h2-p8h4-qcjw","Warn: Project is vulnerable to: GHSA-grv7-fg5c-xmjg","Warn: Project is vulnerable to: GHSA-3xgq-45jj-v275","Warn: Project is vulnerable to: GHSA-fjxv-7rqg-78g4","Warn: Project is vulnerable to: GHSA-952p-6rrq-rcjv","Warn: Project is vulnerable to: GHSA-rhx6-c78j-4q9w"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-16T21:04:49.845Z","repository_id":54631911,"created_at":"2025-08-16T21:04:49.846Z","updated_at":"2025-08-16T21:04:49.846Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30050222,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-03T14:38:37.398Z","status":"ssl_error","status_checked_at":"2026-03-03T14:38:06.721Z","response_time":61,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["firebase","javascript","nodejs","typescript"],"created_at":"2024-09-24T13:48:08.515Z","updated_at":"2026-03-03T15:04:25.553Z","avatar_url":"https://github.com/andrebraghini.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"./doc/firebase-triggers.png\" alt=\"Firebase Triggers\" width=\"500\"/\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\t\n  \u003ca href=\"https://www.linkedin.com/in/andrebraghinis/\"\u003e\n    \u003cimg alt=\"André Braghini\" src=\"https://img.shields.io/badge/-AndreBraghiniS-FFCA28?style=flat\u0026logo=Linkedin\u0026logoColor=white\" /\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://www.npmjs.com/package/firebase-triggers\"\u003e\n    \u003cimg alt=\"npm version\" src=\"https://img.shields.io/npm/v/firebase-triggers?color=FFCA28\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://github.com/andrebraghini/firebase-triggers/blob/main/LICENSE\"\u003e\n    \u003cimg alt=\"License\" src=\"https://img.shields.io/badge/license-MIT-FFCA28\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://codecov.io/gh/andrebraghini/firebase-triggers\"\u003e\n    \u003cimg src=\"https://codecov.io/gh/andrebraghini/firebase-triggers/branch/main/graph/badge.svg?token=SF8KVUI3A8\"/\u003e\n  \u003c/a\u003e\n  \u003cimg alt=\"Build result\" src=\"https://travis-ci.org/andrebraghini/firebase-triggers.svg?branch=main\"\u003e\n\n  \u003cbr\u003e\n\n  \u003ci\u003e\n    A TypeScript library that provides decorators to link class methods to Firebase Authentication, Firestore and PubSub triggers. \n  \u003c/i\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"README.md\"\u003eEnglish\u003c/a\u003e\n  ·\n  \u003ca href=\"https://github.com/andrebraghini/firebase-triggers/blob/main/README.pt.md\"\u003ePortuguese\u003c/a\u003e\n\u003c/p\u003e\n\n\n## Content\n\n1. [Installation](#installation)\n\n2. [Usage](#usage)\n\n3. [Decorators](#decorators)\n\n4. [Schema validation](#schema-validation)\n\n5. [Sample project](https://github.com/andrebraghini/firebase-triggers-sample)\n\n\n## Installation\n\n`npm install --save firebase-triggers`\n\n\n## Usage\n\nBefore deploying to Firebase Functions you need to export the methods at the entry point of your application.\n\nThe `getFirebaseFunctionListToExport()` method returns an object with the list of methods found in the application.\n\nIterate the object by exporting each method individually with the property name as in the example below:\n\n```ts\nimport 'reflect-metadata';\nimport { getFirebaseFunctionListToExport } from 'firebase-triggers';\n\n// Obtain the \"Cloud Functions\" found in the code and export each one\nconst list = getFirebaseFunctionListToExport();\nfor (const key in list) {\n    exports[key] = list[key];\n}\n```\n\nCloud Functions will be exported grouped by class.\nAssuming you have an `UserCtrl` class with `update()` and `list()` methods, these methods will be exported with the names **user-update** and **user-list** respectively in Cloud Functions.\n\n\n### Simple example\n\n```ts\nimport 'reflect-metadata';\nimport { ParamsOf } from 'firebase-functions/lib/common/params';\nimport { FirestoreEvent, QueryDocumentSnapshot } from 'firebase-functions/v2/firestore';\nimport { Request } from 'firebase-functions/lib/common/providers/https';\nimport { Response } from 'firebase-functions';\nimport { getFirebaseFunctionListToExport, onFirestoreCreate, onRequest } from 'firebase-triggers';\n\nclass MyCtrl {\n    @onFirestoreCreate('todo/{id}')\n    docWrite(event: FirestoreEvent\u003cQueryDocumentSnapshot, ParamsOf\u003cstring\u003e\u003e) {\n        const id = event.params.uid;\n        const data = event.data.data();\n        console.log(`New task ${id} added: ${data.title} at ${data.time}`);\n    }\n\n    @onRequest('hello-world')\n    httpRequest(request: Request, response: Response) {\n        response.send('Hello World!');\n    }\n}\n\n// Obtain the \"Cloud Functions\" found in the code and export each one\nconst list = getFirebaseFunctionListToExport();\nfor (const key in list) {\n    exports[key] = list[key];\n}\n```\n\n## Decorators\n\nTo define Firebase Functions triggers, just add the desired decorator on the method, not forgetting to import the decorator:\n\ne.g. `import { onRequest } from 'firebase-triggers';`\n\n### @onFirebaseUserCreate()\n\nAdd the `@onFirebaseUserCreate()` decorator to a method to be executed whenever a new user is created in Firebase Authentication.\n\n```ts\nimport { onFirebaseUserCreate } from 'firebase-triggers';\nimport { AuthBlockingEvent } from 'firebase-functions/v2/identity';\nimport { EventContext } from 'firebase-functions';\n\nclass UserCtrl {\n    @onFirebaseUserCreate()\n    onCreate(event: AuthBlockingEvent) {\n        console.log(`${event.data.displayName} joined us`);\n    }\n}\n```\n\n\n### @onFirebaseUserDelete()\n\nAdd the `@onFirebaseUserDelete()` decorator to a method to be executed whenever a user is removed from Firebase Authentication.\n\n```ts\nimport { onFirebaseUserDelete } from 'firebase-triggers';\nimport { UserRecord } from 'firebase-functions/auth';\nimport { EventContext } from 'firebase-functions';\n\nclass UserCtrl {\n    @onFirebaseUserDelete()\n    onDelete(user: UserRecord, context: EventContext) {\n        console.log(`${user.displayName} left us`);\n    }\n}\n```\n\n\n### @onFirestoreCreate()\n\nAdd the `@onFirestoreCreate()` decorator to a method to be executed whenever a new document is **created** in Firestore, in the collection defined as a decorator parameter.\n\n```ts\nimport { FirestoreEvent, QueryDocumentSnapshot } from 'firebase-functions/v2/firestore';\nimport { ParamsOf } from 'firebase-functions/lib/common/params';\nimport { onFirestoreCreate } from 'firebase-triggers';\n\nclass TodoCtrl {\n    @onFirestoreCreate('todo/{id}')\n    onCreate(event: FirestoreEvent\u003cQueryDocumentSnapshot, ParamsOf\u003cstring\u003e\u003e) {\n        // Get an object representing the document. e.g. { title: 'Wash the dishes', time: '12:00' }\n        const newValue = event.data.data();\n        // access a particular field as you would any JS property\n        const title = newValue.title;\n        const time = newValue.time;\n\n        console.log(`New task added: ${title} at ${time}`);\n    }\n}\n```\n\n\n### @onFirestoreUpdate()\n\nAdd the `@onFirestoreUpdate()` decorator to a method to be executed whenever an existing document is **changed** in Firestore, in the collection defined as a decorator parameter.\n\n```ts\nimport { FirestoreEvent, QueryDocumentSnapshot } from 'firebase-functions/v2/firestore';\nimport { Change } from 'firebase-functions';\nimport { ParamsOf } from 'firebase-functions/lib/common/params';\nimport { onFirestoreUpdate } from 'firebase-triggers';\n\nclass TodoCtrl {\n    @onFirestoreUpdate('todo/{id}')\n    onUpdate(event: FirestoreEvent\u003cChange\u003cQueryDocumentSnapshot\u003e, ParamsOf\u003cstring\u003e\u003e) {\n        // Get an object representing the document. e.g. { title: 'Wash the dishes', time: '12:00' }\n        const newValue = event.data.after.data();\n        // ...or the previous value before this update\n        const previousValue = event.data.before.data();\n        // access a particular field as you would any JS property\n        const newTitle = newValue.title;\n        const oldTitle = previousValue.title;\n\n        console.log(`Changed the title from \"${oldTitle}\" to \"${newTitle}\"`);\n    }\n}\n```\n\n\n### @onFirestoreDelete()\n\nAdd the `@onFirestoreDelete()` decorator to a method to be executed whenever a document is **removed** from the Firestore, in the collection defined as a decorator parameter.\n\n```ts\nimport { FirestoreEvent, QueryDocumentSnapshot } from 'firebase-functions/v2/firestore';\nimport { ParamsOf } from 'firebase-functions/lib/common/params';\nimport { onFirestoreDelete } from 'firebase-triggers';\n\nclass TodoCtrl {\n    @onFirestoreDelete('todo/{id}')\n    onDelete(event: FirestoreEvent\u003cQueryDocumentSnapshot, ParamsOf\u003cstring\u003e\u003e) {\n        // Get an object representing the document. e.g. { title: 'Wash the dishes', time: '12:00' }\n        const oldValue = event.data.data();\n        // access a particular field as you would any JS property\n        const title = oldValue.title;\n\n        console.log(`Task \"${title}\" removed`);\n    }\n}\n```\n\n\n### @onFirestoreWrite()\n\nAdd the `onFirestoreWrite()`decorator to a method to be executed whenever a document is **created, changed or removed** from the Firestore, in the collection defined as a decorator parameter.\n\n```ts\nimport { FirestoreEvent, QueryDocumentSnapshot } from 'firebase-functions/v2/firestore';\nimport { Change } from 'firebase-functions';\nimport { ParamsOf } from 'firebase-functions/lib/common/params';\nimport { onFirestoreWrite } from 'firebase-triggers';\n\nclass TodoCtrl {\n    @onFirestoreWrite('todo/{id}')\n    onWrite(event: FirestoreEvent\u003cChange\u003cDocumentSnapshot\u003e, ParamsOf\u003cstring\u003e\u003e) {\n        // Get an object with the current document value. If the document does not exist, it has been deleted.\n        const newDocument = event.data.after.exists ? event.data.after.data() : null;\n        // Get an object with the previous document value (for update or delete)\n        const oldDocument = event.data.before.exists ? event.data.before.data() : null;\n\n        if (!newDocument) {\n            const title = oldDocument.title;\n            console.log(`Task \"${title}\" removed`);\n            return;\n        }\n\n        if (!oldDocument) {\n            const title = newDocument.title;\n            const time = newDocument.time;\n            console.log(`New task added: ${title} at ${time}`);\n            return;\n        }\n\n        const newTitle = newDocument.title;\n        const oldTitle = oldDocument.title;\n\n        console.log(`Changed the title from \"${oldTitle}\" to \"${newTitle}\"`);\n    }\n}\n```\n\n\n### @onPubSubPublish()\n\nAdd the `@onPubSubPublish()` decorator to a method to be executed whenever a publication is made via PubSub, on the topic defined as a parameter in the decorator.\n\n```ts\nimport { CloudEvent } from 'firebase-functions/lib/v2/core';\nimport { MessagePublishedData } from 'firebase-functions/v2/pubsub';\nimport { onPubSubPublish } from 'firebase-triggers';\n\nclass SampleCtrl {\n    @onPubSubPublish('my-topic')\n    doSomething(event: CloudEvent\u003cMessagePublishedData\u003cany\u003e\u003e) {\n        const publishedData = message.json;\n        console.log('Data published via PubSub on my-topic:', publishedData);\n    }\n}\n```\n\n\n### @onPubSubSchedule()\n\nAdd the `@onPubSubSchedule()` decorator in a method to be executed according to the interval defined as a parameter in the decorator, following the cron patterns.\n\nThe default time zone is **America/Los_Angeles**.\nAlternatively, you can enter a different time zone as follows: `@onPubSubSchedule({ interval: '* * * * *', timezone: 'America/Araguaina' })`.\n\nTo better understand how to set the time using the cron pattern see an example on the website [https://crontab.guru](https://crontab.guru).\n\n```ts\nimport { ScheduledEvent } from 'firebase-functions/v2/scheduler';\nimport { onPubSubSchedule } from 'firebase-triggers';\n\nclass TimerCtrl {\n    @onPubSubSchedule('0 5 * * *')\n    everyDayAtFiveAM(event: ScheduledEvent) {\n        console.log('Method executed every day at 5 AM');\n    }\n}\n```\n\n\n### @onRequest()\n\nAdd the `@onRequest()` decorator to a method to be executed whenever an HTTP request is made to the project address in Cloud Functions followed by the class and method name, using camelCase and ignoring the `Ctrl` suffix control class nomenclature.\n\ne.g. Considering the code below, where the class name is `UserCtrl` and the method is named `profile()`, then the external URL for the HTTP request would be `https://us-central1-project-name.cloudfunctions.net/user-profile`.\n\n```ts\nimport { Response } from 'firebase-functions';\nimport { onRequest } from 'firebase-triggers';\nimport { Request } from 'firebase-functions/lib/common/providers/https';\n\nclass UserCtrl {\n\n    /*\n     * This method will be exported as \"user-profile\" on Cloud Functions\n     * e.g. https://us-central1-project-name.cloudfunctions.net/user-profile\n     */\n    @onRequest()\n    async profile(request: Request, response: Response) {\n        const profile = await loadProfile(request.body.id);\n        response.json(profile);\n    }\n\n    /*\n     * This method will be exported as \"hello\" on Cloud Functions\n     * e.g. https://us-central1-project-name.cloudfunctions.net/hello\n     */\n    @onRequest('hello')\n    async sample(request: Request, response: Response) {\n        response.send('Hello World!');\n    }\n}\n```\n\nThis method also accepts a parameter, which when informed, becomes the name of the function in Cloud Functions and also the URL suffix for the request.\n\nConsidering the example above, if the decorator was declared with parameter 'api' (e.g. `@onRequest('api')`), in this case the external URL for the HTTP request would be `https://us-central1-project-name.cloudfunctions.net/api`, ignoring the control class naming rule.\n\n\n### @GET(), @POST(), @PUT(), @PATCH(), @DELETE()\n\nThe decorators `@GET()`, `@POST()`, `@PUT()`, `@PATCH()` and `@DELETE()` work in much the same way as decorator `@onRequest()`, with the difference that each responds to a unique HTTP method.\n\nBelow is a REST simulation of user data using the aforementioned decorators.\nIn this case the external URL for the HTTP request would be `https://us-central1-project-name.cloudfunctions.net/users`, ignoring the control class naming rule.\n\n```ts\nimport { Request } from 'firebase-functions/lib/common/providers/https';\nimport { Response } from 'firebase-functions';\nimport { GET, POST, PUT, PATCH, DELETE } from 'firebase-triggers';\n\nclass UserCtrl {\n\n    @GET('users')\n    async get(request: Request, response: Response) {\n        response.json([]);\n    }\n\n    @POST('users')\n    async post(request: Request, response: Response) {\n        response.status(201).send();\n    }\n\n    @PUT('users')\n    async put(request: Request, response: Response) {\n        response.status(201).send();\n    }\n\n    @PATCH('users')\n    async patch(request: Request, response: Response) {\n        response.status(201).send();\n    }\n\n    @DELETE('users')\n    async del(request: Request, response: Response) {\n        response.status(201).send();\n    }\n}\n```\n\n\n#### Schema validation\n\nRequests using the `@onRequest()` decorator can be validated through schema files that must be in the `schema` folder with the exact name of the function that will be exported to Cloud Functions.\nIf the file exists, validation will be performed.\n\nUsing the decorators `@GET()`, `@POST()`, `@PUT()`, `@PATCH()` or `@DELETE()`, it is necessary to add a suffix separated by an underscore in the name of the schema file for every need.\n\n__Samples:__\n\n`user-update.json` (Applied when using @onRequest() without specifying the HTTP method)\n\n`user-update_GET.json` (Applied to HTTP GET requests)\n\n`user-update_POST.json` (Applied to HTTP POST requests)\n\n`user-update_PUT.json` (Applied to HTTP PUT requests)\n\n`user-update_PATCH.json` (Applied to HTTP PATCH requests)\n\n`user-update_DELETE.json` (Applied to HTTP DELETE requests)\n\nIt is also possible on the client side to view the schema files by adding the suffix `/schema.json` to the URL of the exported method.\n\nYou can use the [jsonschema.net](https://jsonschema.net/) to generate your JSON schemas.\n\n\n### @onCall()\n\nAdd the decorator `@onCall()` to a method so you can call it straight from the Firebase SDK.\nThey call it [Callable methods](https://firebase.google.com/docs/functions/callable-reference).\n\nThe method name will be prefixed with the class name, using *camelCase* and ignoring the `Ctrl` suffix of the control class nomenclature.\n\n```ts\nimport { onCall } from 'firebase-triggers';\nimport { CallableRequest } from 'firebase-functions/lib/common/providers/https';\n\nclass TodoCtrl {\n    @onCall()\n    add(event: CallableRequest) {\n        console.log('Add new todo', event.data);\n    }\n}\n```\n\n\n### @onStorageArchive(), @onStorageDelete(), @onStorageFinalize(), @onStorageMetadataUpdate()\n\nAdd the decorator `onStorageArchive()` to a method to be executed whenever an item is archived on Cloud Storage.\n\nAdd the decorator `onStorageDelete()` to a method to be executed whenever an item is removed from Cloud Storage.\n\nAdd the decorator `onStorageFinalize()` to a method to be executed whenever an item is finished uploading on Cloud Storage.\n\nAdd the decorator `onStorageMetadataUpdate()` to a method to be executed whenever an item metadata is updated on _Cloud Storage_.\n\nIf the bucket is empty, the method will be executed for all buckets.\nSee [Cloud Storage Events](https://firebase.google.com/docs/functions/gcp-storage-events).\n\n```ts\nimport {onStorageArchive, onStorageDelete, onStorageFinalize, onStorageMetadataUpdate } from 'firebase-triggers';\nimport { StorageEvent } from 'firebase-functions/v2/storage';\n\nclass TodoCtrl {\n    @onStorageArchive('bucket-name')\n    archive(event: StorageEvent) {\n        console.log(`File ${event.data.name} archived`);\n    }\n    \n    @onStorageDelete('bucket-name')\n    del(event: StorageEvent) {\n        console.log(`File ${event.data.name} deleted`);\n    }\n\n    @onStorageFinalize('bucket-name')\n    uploaded(event: StorageEvent) {\n        console.log(`File ${event.data.name} uploaded`);\n    }\n\n    @onStorageMetadataUpdate('bucket-name')\n    updateMetadata(event: StorageEvent) {\n        console.log(`File ${event.data.name} updated`);\n    }\n}\n```\n\n\n## Runtime Options\n\nCloud Functions for Firebase lets you select runtime options such as the Node.js runtime version and per-function timeout, memory allocation, and minimum/maximum function instances.\n\nAs a best practice, these options (except for Node.js version) should be set on a configuration object inside the function code. This RuntimeOptions object is the source of truth for your function's runtime options, and will override options set via any other method (such as via the Google Cloud console or gcloud CLI).\n\nTo define runtime options in a Cloud Function, you can provide an options object with all options  in the desired decorator with the settings you want to define. See some examples below:\n\n```ts\nimport 'reflect-metadata';\nimport { getFirebaseFunctionListToExport, onFirestoreCreate, onRequest } from 'firebase-triggers';\n\nclass MyCtrl {\n    @onFirestoreCreate({\n        document: 'todo/{id}',\n        database: 'my-database-name',\n        namespace: 'some-namespace',\n        retry: false,\n        region: 'us-east1',\n        omit: false,\n        memory: '128MiB',\n        timeoutSeconds: 60,\n        minInstances: 2,\n        maxInstances: 4,\n        concurrency: 100,\n        cpu: 0.5,\n        vpcConnectorEgressSettings: 'ALL_TRAFFIC',\n        ingressSettings: 'ALLOW_ALL',\n        invoker: 'public',\n        labels: { someKey: 'my-label-value'},\n        preserveExternalChanges: false,\n    })\n    docWrite(event) {\n        const data = event.data.data();\n        console.log(`New task added: ${data.title} at ${data.time}`);\n    }\n\n    @onRequest({ path: 'hello-world', region: 'us-east1' })\n    httpRequest(request, response) {\n        response.send('Hello World!');\n    }\n}\n```","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fandrebraghini%2Ffirebase-triggers","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fandrebraghini%2Ffirebase-triggers","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fandrebraghini%2Ffirebase-triggers/lists"}