Skill for converting an installed Firebase Extension (or extension source) into a standalone Cloud Functions for Firebase codebase or publishable npm package, including V1 to V2 trigger upgrades, lifecycle hooks, and declarative security
58
67%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Passed
No findings from the security scan
Fix and improve this skill with Tessl
tessl review fix ./skills/extension-to-functions-codebase/SKILL.mdMigrates a Firebase Extension into either:
functions/src/ for app integration).Leverages native Cloud Functions features (declarative IAM, Parameterized Config, SDK Lifecycle Hooks) and modernizes 1st Gen triggers to 2nd Gen using the Destructuring Compatibility Shim.
Target A: Local Functions Codebase (End-User App Integration)
functions/src/. Config in .env.firebase deploy --only functions.Target B: Publishable npm Package / Shareable Package
package.json specifying exports map,
engines: { "node": ">=22" }, and
peerDependencies: { "firebase-functions": ">=6.0.0" }.index.ts
(export * from "<package-name>").Use native SDK declarations instead of manual gcloud scripts or console
instructions:
requiresRole("roles/...") for required GCP IAM permissions.requiresAPI("service.googleapis.com", "Description") for Google APIs..value() at top-level module load scope.onInit() or lazy getters:
import { defineString } from "firebase-functions/params";
import { onInit } from "firebase-functions/v2";
const dataset = defineString("DATASET_ID");
let client: BigQuery;
onInit(() => {
client = new BigQuery({ datasetId: dataset.value() });
});V2 enables concurrency (up to 80 requests). To preserve V1 single-concurrency
pricing, set cpu: "gcf_gen1".
extension.yaml:
params → defineString, defineInt, defineBoolean, defineSecret.apis → requiresAPI(...).roles → requiresRole(...).lifecycleEvents → afterFirstDeploy & afterRedeploy.resources → Upgrade 1st Gen triggers to 2nd Gen (onDocumentWritten,
onTaskDispatched, onRequest).jest), and
test scripts.package.jsonname: "<package-name>", engines: { "node": ">=22" }.peerDependencies:
"peerDependencies": {
"firebase-admin": "^11.0.0 || ^12.0.0",
"firebase-functions": ">=6.0.0"
}exports map targeting ESM/CommonJS and TypeScript declarations
(lib/index.js, lib/index.d.ts).onDocumentWritten from firebase-functions/v2/firestore.onTaskDispatched from firebase-functions/v2/tasks. Remove
EXT_INSTANCE_ID when enqueueing tasks.onRequest from firebase-functions/v2/https.{ change, context },
{ snapshot, context }) where legacy 1st Gen handlers expect
(change, context).Map extension lifecycle events to SDK lifecycle hooks in src/index.ts:
onInstall → afterFirstDeploy({ task: { function: "initTask" } })onUpdate / onConfigure →
afterRedeploy({ task: { function: "setupTask" } })Generate README.md containing:
npm install).export * from "<package-name>")..env reference table.Reminder: NEVER execute npm publish.
a0b4e14
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.