{"id":12696,"plugin_id":"plugins_6a8ddf314ab88191864c208fda197798","kind":"skill","collection_source":null,"comparison_source":null,"observed_at":"2026-09-30T23:02:02.120Z","digest":"03999708a3d5c21382a70234bfd2383027677d0112c5d46602f37ff7734bf8e0","against":null,"payload":{"name":"extension-to-functions-codebase","description":"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","included_files":[{"relative_path":"references/configuration-migration.md","size_in_bytes":6553},{"relative_path":"references/destructuring-shim.md","size_in_bytes":4466},{"relative_path":"references/signature-mapping.md","size_in_bytes":4350}],"skill_md_contents":"---\nname: extension-to-functions-codebase\ndescription: 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\nmetadata:\n  category: Serverless\n---\n\n# Extension to Functions Codebase & npm Package Migration\n\n## Overview\n\nMigrates a Firebase Extension into either:\n\n1. **A local Cloud Functions codebase** (`functions/src/` for app integration).\n1. **A publishable npm package** (reusable open-source package exporting V2\n   functions).\n\nLeverages native Cloud Functions features (declarative IAM, Parameterized\nConfig, SDK Lifecycle Hooks) and modernizes 1st Gen triggers to 2nd Gen using\nthe Destructuring Compatibility Shim.\n\n______________________________________________________________________\n\n## Target Migration Workflows\n\n- **Target A: Local Functions Codebase** (End-User App Integration)\n\n  - Output: Code under `functions/src/`. Config in `.env`.\n  - Deployment: `firebase deploy --only functions`.\n\n- **Target B: Publishable npm Package / Shareable Package**\n\n  - Output: Reusable npm package exporting V2 functions.\n  - Configuration: `package.json` specifying `exports` map,\n    `engines: { \"node\": \">=22\" }`, and\n    `peerDependencies: { \"firebase-functions\": \">=6.0.0\" }`.\n  - Usage: Consumers install package and re-export functions in `index.ts`\n    (`export * from \"<package-name>\"`).\n\n______________________________________________________________________\n\n## Core Rules & Constraints\n\n### 1. Declarative IAM & APIs (Zero-Local-Overhead)\n\nUse native SDK declarations instead of manual `gcloud` scripts or console\ninstructions:\n\n- Use `requiresRole(\"roles/...\")` for required GCP IAM permissions.\n- Use `requiresAPI(\"service.googleapis.com\", \"Description\")` for Google APIs.\n\n### 2. Global Parameter Access Restriction\n\n- **Never call `.value()` at top-level module load scope.**\n- Initialize global SDK instances inside `onInit()` or lazy getters:\n  ```typescript\n  import { defineString } from \"firebase-functions/params\";\n  import { onInit } from \"firebase-functions/v2\";\n\n  const dataset = defineString(\"DATASET_ID\");\n  let client: BigQuery;\n\n  onInit(() => {\n    client = new BigQuery({ datasetId: dataset.value() });\n  });\n  ```\n\n### 3. V2 Concurrency & Cost Parity\n\nV2 enables concurrency (up to 80 requests). To preserve V1 single-concurrency\npricing, set `cpu: \"gcf_gen1\"`.\n\n______________________________________________________________________\n\n## Step-by-Step Migration Execution\n\n### Step 1: Inventory Extension Resources\n\n1. **`extension.yaml`**:\n   - `params` → `defineString`, `defineInt`, `defineBoolean`, `defineSecret`.\n   - `apis` → `requiresAPI(...)`.\n   - `roles` → `requiresRole(...)`.\n   - `lifecycleEvents` → `afterFirstDeploy` & `afterRedeploy`.\n   - `resources` → Upgrade 1st Gen triggers to 2nd Gen (`onDocumentWritten`,\n     `onTaskDispatched`, `onRequest`).\n1. **Files & Scripts**: Preserve devDependencies, test framework (`jest`), and\n   test scripts.\n\n### Step 2: Configure `package.json`\n\n- Set `name: \"<package-name>\"`, `engines: { \"node\": \">=22\" }`.\n- Set `peerDependencies`:\n  ```json\n  \"peerDependencies\": {\n    \"firebase-admin\": \"^11.0.0 || ^12.0.0\",\n    \"firebase-functions\": \">=6.0.0\"\n  }\n  ```\n- Configure `exports` map targeting ESM/CommonJS and TypeScript declarations\n  (`lib/index.js`, `lib/index.d.ts`).\n\n### Step 3: Upgrade Triggers from V1 to V2\n\n- Firestore: Use `onDocumentWritten` from `firebase-functions/v2/firestore`.\n- Tasks: Use `onTaskDispatched` from `firebase-functions/v2/tasks`. Remove\n  `EXT_INSTANCE_ID` when enqueueing tasks.\n- HTTP: Use `onRequest` from `firebase-functions/v2/https`.\n- Apply Destructuring Compatibility Shim (`{ change, context }`,\n  `{ snapshot, context }`) where legacy 1st Gen handlers expect\n  `(change, context)`.\n\n### Step 4: Convert Lifecycle Events\n\nMap extension lifecycle events to SDK lifecycle hooks in `src/index.ts`:\n\n- `onInstall` → `afterFirstDeploy({ task: { function: \"initTask\" } })`\n- `onUpdate` / `onConfigure` →\n  `afterRedeploy({ task: { function: \"setupTask\" } })`\n\n### Step 5: Package README & Export Instructions\n\nGenerate `README.md` containing:\n\n1. Installation instructions (`npm install`).\n1. Re-export snippet (`export * from \"<package-name>\"`).\n1. Parameterized Configuration `.env` reference table.\n1. What Changed (Extension vs Package) comparison table.\n\n_Reminder: NEVER execute `npm publish`._\n"},"changes":[],"summary":"First saved snapshot. No earlier version is available for comparison.","summary_kind":"deterministic","summary_metadata":{}}