[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill-firebase-extension-to-functions-codebase":3,"mdc--4y04f8-key":34,"related-org-firebase-extension-to-functions-codebase":3599,"related-repo-firebase-extension-to-functions-codebase":3787},{"slug":4,"name":4,"fn":5,"description":6,"org":7,"tags":11,"stars":23,"repoUrl":24,"updatedAt":25,"license":26,"forks":27,"topics":28,"repo":29,"sourceUrl":32,"mdContent":33},"extension-to-functions-codebase","convert Firebase Extensions to Cloud Functions","Skill for converting an installed Firebase Extension (or extension source) to a standalone Cloud Functions for Firebase codebase or publishable npm package, including upgrading triggers from V1 to V2 and configuring lifecycle hooks and declarative security",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},"firebase","Firebase (Google)","https:\u002F\u002Fpexgzepcugksgbtrxkhf.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Forg-logos\u002Ffirebase.png",[12,16,18,21],{"name":13,"slug":14,"type":15},"Migration","migration","tag",{"name":17,"slug":17,"type":15},"npm",{"name":19,"slug":20,"type":15},"Cloud Functions","cloud-functions",{"name":22,"slug":8,"type":15},"Firebase",376,"https:\u002F\u002Fgithub.com\u002Ffirebase\u002Fagent-skills","2026-07-31T06:23:32.436718",null,75,[],{"repoUrl":24,"stars":23,"forks":27,"topics":30,"description":31},[],"Agent Skills for Firebase","https:\u002F\u002Fgithub.com\u002Ffirebase\u002Fagent-skills\u002Ftree\u002FHEAD\u002Fskills\u002Fextension-to-functions-codebase","---\nname: extension-to-functions-codebase\ndescription: Skill for converting an installed Firebase Extension (or extension source) to a standalone Cloud Functions for Firebase codebase or publishable npm package, including upgrading triggers from V1 to V2 and configuring lifecycle hooks and declarative security\n---\n\n# Extension to Functions Codebase & npm Package Migration\n\n## Overview\n\nThis skill guides the agent in migrating a Firebase Extension repository or\ninstance into either:\n\n1. **A standalone Cloud Functions for Firebase codebase** (`firebase-functions`,\n   for end-user app integration), or\n1. **A publishable npm package \u002F shareable open source package** (for extension\n   publishers distributing reusable V2 functions).\n\nIt leverages native Cloud Functions for Firebase GA capabilities to handle\npermissions, dependencies, and lifecycle hooks natively in code, and provides\ninstructions for modernizing legacy V1 triggers to V2 using the Destructuring\nCompatibility Shim.\n\n______________________________________________________________________\n\n## Triggers\n\nActivate this skill when a user asks to:\n\n- Migrate or convert an installed Firebase Extension into a standalone functions\n  codebase.\n- Convert an extension repository into a publishable npm package (shareable open\n  source package).\n- Upgrade extension triggers from V1 to V2.\n\n______________________________________________________________________\n\n## Target Migration Workflows\n\nBefore starting, determine the target destination with the developer:\n\n- **Target A: Local Functions Codebase** (End-User App Integration)\n\n  - Output: Source code placed in the project's `functions\u002Fsrc\u002F` folder.\n  - Configuration: Parameters defined via `defineString`, `defineSecret`, etc.\n    in `.env`.\n  - Deployment: Deployed directly via `firebase deploy --only functions`.\n\n- **Target B: Publishable npm Package \u002F Shareable Open Source Package**\n\n  - Output: Reusable npm package containing exported V2 functions.\n  - Configuration: `package.json` with `exports` map and `firebase-functions`\n    declared in `dependencies` (or `peerDependencies`).\n  - Usage: End users install the package (`npm i \u003Cpackage-name>`) and re-export\n    functions in their `index.ts`.\n\n______________________________________________________________________\n\n## Getting Started & Git Safety\n\n1. **Git Status**: Verify the workspace has a clean git status before starting.\n1. **In-Place Copying**: If copying code to a new subdirectory within the same\n   repository:\n   - Use `git cp` (or copy files and commit) to copy the extension's source\n     directory to the target directory.\n   - Commit immediately:\n     `\"Copying [extension-name] extension to [directory] in preparation for rewrite\"`\n\n______________________________________________________________________\n\n## Rules and Constraints\n\n### 1. Zero-Local-Overhead (Cloud Functions Integration)\n\nAssume Cloud Functions for Firebase Workload Identities, Declarative Security,\nand SDK Lifecycle Hooks are fully GA.\n\n- **Do NOT** output instructions or scripts telling users to run manual `gcloud`\n  IAM commands or create service accounts.\n- **Do NOT** write code comments instructing users to manually enable Google\n  APIs in the cloud console.\n- Instead, use declarative `requiresAPI` and `requiresRole` imports from the\n  SDK.\n\n### 2. Global Parameter Access Restriction\n\n- **Never call `.value()` on any parameter at global scope.**\n- If a global variable or class instance is initialized using a parameter value,\n  declare the variable globally and initialize it inside the `onInit()`\n  callback:\n  ```typescript\n  import { defineString } from \"firebase-functions\u002Fparams\";\n  import { onInit } from \"firebase-functions\u002Fv2\";\n\n  const bqDataset = defineString(\"DATASET_ID\");\n  let bqClient: BigQuery;\n\n  onInit(() => {\n    bqClient = new BigQuery({ datasetId: bqDataset.value() });\n  });\n  ```\n\n### 3. Concurrency & Cost Parity for V2\n\nWhen upgrading triggers to V2:\n\n- By default, V2 functions enable concurrency (up to 80 requests per instance).\n- If you want to maintain V1 fractional CPU pricing (and disable concurrency),\n  set `cpu: \"gcf_gen1\"` in the function's options object.\n\n______________________________________________________________________\n\n## Step-by-Step Migration Execution\n\n### Step 1: Inventory the Extension\n\nConduct a complete inventory of everything the extension declares, ships, and\ndocuments so that nothing is lost during migration:\n\n1. **Inventory `extension.yaml`**:\n   - `params`: Convert to Functions params (`defineString`, `defineSecret`,\n     etc.).\n   - `apis`: Convert to `requiresAPI(...)` declarations.\n   - `roles`: Convert to `requiresRole(...)` declarations.\n   - `lifecycleEvents` (`onInstall`, `onUpdate`, `onConfigure`): Convert to\n     `afterFirstDeploy` and `afterRedeploy` hooks.\n   - `resources`: Note all function triggers to convert from 1st gen\n     (`firebase-functions\u002Fv1`) to 2nd gen (`firebase-functions\u002Fv2`), including\n     standard event triggers, HTTP handlers, and task queues\n     (`onTaskDispatched`).\n1. **Inventory Files & Tooling**:\n   - `functions\u002F`: Source code, triggers, helpers, and task queue handlers.\n   - Documentation: `README.md`, `PREINSTALL.md`, and `POSTINSTALL.md`.\n   - `scripts\u002F`: Note any backfill, import, or helper scripts shipped with the\n     extension.\n\n### Step 2: Create \u002F Update `package.json`\n\nCreate an npm package for the migrated extension code (either at project root or\nin a dedicated workspace directory):\n\n- Set a publishable package name (`name: \"\u003Cpackage-name>\"`).\n- **Preserve Dev & Test Dependencies**: Preserve all existing `devDependencies`,\n  test runners (`jest`, `ts-jest`, `@types\u002Fjest`, `mocha`, `@types\u002Fmocha`), and\n  test scripts (`\"test\": \"...\"`) from the legacy extension\n  (`functions\u002Fpackage.json` or root `package.json`). Do not drop test frameworks\n  or type definitions.\n- Declare `firebase-functions` (e.g. `^7.0.0`) in `dependencies` (or\n  `peerDependencies` if creating a lightweight middleware package where the root\n  consumer manages the runtime version):\n  ```json\n  {\n    \"name\": \"\u003Cpackage-name>\",\n    \"version\": \"1.0.0\",\n    \"main\": \"lib\u002Findex.js\",\n    \"types\": \"lib\u002Findex.d.ts\",\n    \"exports\": {\n      \".\": {\n        \"types\": \".\u002Flib\u002Findex.d.ts\",\n        \"default\": \".\u002Flib\u002Findex.js\"\n      }\n    },\n    \"engines\": {\n      \"node\": \">=22\"\n    },\n    \"dependencies\": {\n      \"firebase-admin\": \"^12.0.0\",\n      \"firebase-functions\": \"^7.0.0\"\n    }\n  }\n  ```\n\n### Step 3: Move Function Code & Expose Deployable Functions\n\nMove the extension's function source into the package's `src\u002F` folder:\n\n1. Keep normal Firebase trigger exports. The package must expose deployable\n   functions that end users can re-export from their entrypoint (`index.ts`).\n1. Document that consumers must deploy packaged functions by re-exporting them:\n   ```typescript\n   export * from \"\u003Cpackage-name>\";\n   \u002F\u002F Or named exports:\n   \u002F\u002F export { syncV2, initBigQuerySync } from \"\u003Cpackage-name>\";\n   ```\n   *Note*: A bare import (`import \"\u003Cpackage-name>\"`) is not enough. The Firebase\n   CLI only deploys functions exported from the user's root entry file.\n\n### Step 4: Upgrade Functions from 1st Gen to 2nd Gen\n\nConvert each exported 1st gen function trigger (`onWrite`, `onRequest`,\n`tasks.taskQueue().onDispatch`) to its 2nd gen equivalent (`onDocumentWritten`,\n`onRequest`, `onTaskDispatched` from `firebase-functions\u002Fv2\u002F...`):\n\n1. **Signatures & Destructuring Shim**: Use the Destructuring Compatibility Shim\n   (`{ shimmedKey, context }`) to preserve V1 business logic without rewriting\n   function bodies. See [signature-mapping.md](references\u002Fsignature-mapping.md)\n   and [destructuring-shim.md](references\u002Fdestructuring-shim.md).\n1. **Authentication Triggers Exception**: If your extension uses v1\n   Authentication Triggers (`auth.user().onCreate()`, `auth.user().onDelete()`),\n   instruct the agent to check live whether a 2nd gen alternative exists in the\n   installed `firebase-functions` package or live documentation. If 2nd gen Auth\n   triggers are not yet supported for those events, warn the user clearly and\n   halt or refuse the migration for those specific triggers until a V2\n   alternative becomes available.\n\n### Step 5: Replace Extension Params with Functions Params\n\nEach parameter in `extension.yaml` becomes a Parameterized Configuration call:\n\n1. Map parameter primitives and attributes:\n   - Type `string` ->\n     `defineString(\"PARAM_NAME\", { label: \"...\", description: \"...\", default: \"...\" })`\n   - Type `secret` -> `defineSecret(\"PARAM_NAME\")`\n   - Type `int` -> `defineInt(\"PARAM_NAME\", { label: \"...\", default: 123 })`\n   - Type `boolean` -> `defineBoolean(\"PARAM_NAME\", { default: true })`\n   - Type `select` \u002F `multiSelect` -> map `options` into `input`:\n     `defineString(\"PARAM_NAME\", { input: { select: { options: [{ value: \"val\", label: \"Val\" }] } } })`\n   - `validationRegex` -> map into text input options:\n     `defineString(\"PARAM_NAME\", { input: { text: { validationRegex: \"^[a-z]+$\" } } })`\n   - `required: true` \u002F Non-empty validation -> map `nonEmpty: true` into input\n     options:\n     `defineString(\"PARAM_NAME\", { input: { text: { nonEmpty: true } } })`\n1. Read parameter values inside handlers using `paramName.value()`.\n1. **Keep Exact Parameter Names**: Never change parameter names\n   (`COLLECTION_PATH`, `DATASET_ID`, etc.) so that existing values carry over\n   seamlessly in `.env`.\n\n### Step 6: Migrate Internal Task Queue Calls (`queue.enqueue(...)`)\n\nIf your extension code enqueues tasks onto its own queue using the Admin SDK\n(`getFunctions().taskQueue(...)`):\n\n- Under the Extensions runtime, the Admin SDK resolved queues by function name\n  plus `process.env.EXT_INSTANCE_ID`.\n- **In an npm package \u002F regular codebase**: Remove the second argument\n  (`EXT_INSTANCE_ID`) entirely. The Admin SDK automatically targets the current\n  codebase:\n  ```typescript\n  \u002F\u002F Before (extension runtime):\n  \u002F\u002F const queue = getFunctions().taskQueue(`locations\u002F${region}\u002Ffunctions\u002FsyncBigQuery`, process.env.EXT_INSTANCE_ID);\n\n  \u002F\u002F After (npm package):\n  const queue = getFunctions().taskQueue(`locations\u002F${region}\u002Ffunctions\u002FsyncBigQuery`);\n  await queue.enqueue(taskData);\n  ```\n\n### Step 7: Migrate Secrets\n\nFor parameters declared with `type: secret`:\n\n1. Declare the secret explicitly:\n   ```typescript\n   import { defineSecret } from \"firebase-functions\u002Fparams\";\n   const apiKey = defineSecret(\"API_KEY\");\n   ```\n1. Bind the secret in the trigger options:\n   ```typescript\n   export const fn = onRequest({ secrets: [apiKey] }, handler);\n   ```\n1. Keep exact secret names unchanged so existing Secret Manager bindings work.\n\n### Step 8: Declare Required APIs and IAM Roles\n\nReplace `apis` and `roles` from `extension.yaml` with declarative code in your\nentry file:\n\n```typescript\nimport { requiresAPI, requiresRole } from \"firebase-functions\";\n\nrequiresAPI(\"bigquery.googleapis.com\", \"Needed to write changelog rows\");\nrequiresRole(\"roles\u002Fbigquery.dataEditor\");\nrequiresRole(\"roles\u002Fbigquery.user\");\n```\n\nAt deploy time, the Firebase CLI automatically grants these roles to the managed\nruntime service account and enables the required APIs.\n\n### Step 9: Convert Lifecycle Hooks (`afterFirstDeploy` & `afterRedeploy`)\n\nReplace `lifecycleEvents` (`onInstall`, `onUpdate`, `onConfigure`) with SDK\nlifecycle hooks:\n\n1. Convert task queue handlers (`initBigQuerySync`, `setupBigQuerySync`) to V2\n   `onTaskDispatched` from `firebase-functions\u002Fv2\u002Ftasks` (removing legacy\n   `getExtensions().runtime().setProcessingState(...)` calls).\n1. Register lifecycle hooks in code:\n   ```typescript\n   import { afterFirstDeploy, afterRedeploy } from \"firebase-functions\u002Fv2\";\n\n   \u002F\u002F Replaces onInstall:\n   afterFirstDeploy({\n     task: {\n       function: \"runInitialSetup\",\n       body: {}\n     }\n   });\n\n   \u002F\u002F Replaces onUpdate & onConfigure:\n   afterRedeploy({\n     task: {\n       function: \"runInitialSetup\",\n       body: { reconcile: true }\n     }\n   });\n   ```\n1. Ensure handlers are idempotent and document manual rerun commands:\n   ```bash\n   firebase functions:lifecycle:run afterFirstDeploy CODEBASE_NAME\n   firebase functions:lifecycle:run afterRedeploy CODEBASE_NAME\n   ```\n\n### Step 10: Document Setup for Your Users (`README.md`)\n\nPreserve whatever documentation, secrets, and setup instructions the original\nextension already documented in `README.md` (and `PREINSTALL.md` \u002F\n`POSTINSTALL.md`), updating them as needed:\n\n1. **Update Configuration References**: Replace instructions referencing legacy\n   `extension.yaml` installation prompts or `ext-*.env` files with standard\n   `.env` Parameterized Configuration setup matching the `defineString`\n   parameters.\n1. **Include Re-export Snippet**: Ensure the basic root re-export snippet is\n   shown (`export * from \"\u003Cpackage-name>\";`) so users know how to expose the\n   functions in their root `index.ts`.\n1. **Avoid Unnecessary Boilerplate**: Do not generate redundant comparison\n   tables or generic installation steps if the setup is self-evident in the code\n   or already covered by existing README sections.\n\n### Step 11: Build & Test Verification\n\n1. **Verify Source Compilation**: Run `npm run build` (`tsc`) to ensure no\n   TypeScript compilation errors in `src\u002F`.\n1. **Verify Unit Test Suite & Type Definitions**:\n   - If existing unit tests (`__tests__\u002F`, `test\u002F`) are present in the\n     extension:\n     - Ensure `@types\u002Fjest` (or the original test framework types) are present\n       in `devDependencies` so test files type-check cleanly.\n     - Update test invocations for upgraded V2 triggers to pass a single\n       destructured event object\n       (`({ change: mockChange, context: mockContext })` instead of positional\n       arguments `(mockChange, mockContext)`).\n     - Run `npm test` or type-check test files (`npx tsc --noEmit`) to verify\n       zero regressions.\n\n______________________________________________________________________\n\n## References & Official Resources\n\n- **Official Google Migration Guide**:\n  [Prepare Firebase Extensions for migration to Cloud Functions](https:\u002F\u002Ffirebase.google.com\u002Fdocs\u002Fextensions\u002Fpublishers\u002Fmigrate)\n- **Publisher Support Contacts**:\n  - Support Email: `firebase-extensions-migrator-support-external@google.com`\n  - Support Group Subscription:\n    `firebase-extensions-migrator-support-external+subscribe@google.com`\n- **Destructuring Shim**: See\n  [destructuring-shim.md](references\u002Fdestructuring-shim.md) for details on event\n  property translation.\n- **Trigger Mapping**: See\n  [signature-mapping.md](references\u002Fsignature-mapping.md) for V1 vs V2 trigger\n  definitions and shim keys.\n- **Configuration & Parameters**: See\n  [configuration-migration.md](references\u002Fconfiguration-migration.md) for\n  `runWith` options, params, and secret bindings.\n",{"data":35,"body":36},{"name":4,"description":6},{"type":37,"children":38},"root",[39,48,55,61,96,101,105,111,116,135,138,144,149,299,302,308,358,361,367,374,379,430,436,793,799,804,825,828,834,840,845,1068,1079,1084,1693,1699,1712,1804,1810,1865,1934,1940,1952,2159,2172,2184,2365,2371,2383,2562,2568,2592,2769,2774,2793,2822,3225,3237,3263,3339,3345,3474,3477,3483,3593],{"type":40,"tag":41,"props":42,"children":44},"element","h1",{"id":43},"extension-to-functions-codebase-npm-package-migration",[45],{"type":46,"value":47},"text","Extension to Functions Codebase & npm Package Migration",{"type":40,"tag":49,"props":50,"children":52},"h2",{"id":51},"overview",[53],{"type":46,"value":54},"Overview",{"type":40,"tag":56,"props":57,"children":58},"p",{},[59],{"type":46,"value":60},"This skill guides the agent in migrating a Firebase Extension repository or\ninstance into either:",{"type":40,"tag":62,"props":63,"children":64},"ol",{},[65,86],{"type":40,"tag":66,"props":67,"children":68},"li",{},[69,75,77,84],{"type":40,"tag":70,"props":71,"children":72},"strong",{},[73],{"type":46,"value":74},"A standalone Cloud Functions for Firebase codebase",{"type":46,"value":76}," (",{"type":40,"tag":78,"props":79,"children":81},"code",{"className":80},[],[82],{"type":46,"value":83},"firebase-functions",{"type":46,"value":85},",\nfor end-user app integration), or",{"type":40,"tag":66,"props":87,"children":88},{},[89,94],{"type":40,"tag":70,"props":90,"children":91},{},[92],{"type":46,"value":93},"A publishable npm package \u002F shareable open source package",{"type":46,"value":95}," (for extension\npublishers distributing reusable V2 functions).",{"type":40,"tag":56,"props":97,"children":98},{},[99],{"type":46,"value":100},"It leverages native Cloud Functions for Firebase GA capabilities to handle\npermissions, dependencies, and lifecycle hooks natively in code, and provides\ninstructions for modernizing legacy V1 triggers to V2 using the Destructuring\nCompatibility Shim.",{"type":40,"tag":102,"props":103,"children":104},"hr",{},[],{"type":40,"tag":49,"props":106,"children":108},{"id":107},"triggers",[109],{"type":46,"value":110},"Triggers",{"type":40,"tag":56,"props":112,"children":113},{},[114],{"type":46,"value":115},"Activate this skill when a user asks to:",{"type":40,"tag":117,"props":118,"children":119},"ul",{},[120,125,130],{"type":40,"tag":66,"props":121,"children":122},{},[123],{"type":46,"value":124},"Migrate or convert an installed Firebase Extension into a standalone functions\ncodebase.",{"type":40,"tag":66,"props":126,"children":127},{},[128],{"type":46,"value":129},"Convert an extension repository into a publishable npm package (shareable open\nsource package).",{"type":40,"tag":66,"props":131,"children":132},{},[133],{"type":46,"value":134},"Upgrade extension triggers from V1 to V2.",{"type":40,"tag":102,"props":136,"children":137},{},[],{"type":40,"tag":49,"props":139,"children":141},{"id":140},"target-migration-workflows",[142],{"type":46,"value":143},"Target Migration Workflows",{"type":40,"tag":56,"props":145,"children":146},{},[147],{"type":46,"value":148},"Before starting, determine the target destination with the developer:",{"type":40,"tag":117,"props":150,"children":151},{},[152,219],{"type":40,"tag":66,"props":153,"children":154},{},[155,160,162],{"type":40,"tag":70,"props":156,"children":157},{},[158],{"type":46,"value":159},"Target A: Local Functions Codebase",{"type":46,"value":161}," (End-User App Integration)",{"type":40,"tag":117,"props":163,"children":164},{},[165,178,207],{"type":40,"tag":66,"props":166,"children":167},{},[168,170,176],{"type":46,"value":169},"Output: Source code placed in the project's ",{"type":40,"tag":78,"props":171,"children":173},{"className":172},[],[174],{"type":46,"value":175},"functions\u002Fsrc\u002F",{"type":46,"value":177}," folder.",{"type":40,"tag":66,"props":179,"children":180},{},[181,183,189,191,197,199,205],{"type":46,"value":182},"Configuration: Parameters defined via ",{"type":40,"tag":78,"props":184,"children":186},{"className":185},[],[187],{"type":46,"value":188},"defineString",{"type":46,"value":190},", ",{"type":40,"tag":78,"props":192,"children":194},{"className":193},[],[195],{"type":46,"value":196},"defineSecret",{"type":46,"value":198},", etc.\nin ",{"type":40,"tag":78,"props":200,"children":202},{"className":201},[],[203],{"type":46,"value":204},".env",{"type":46,"value":206},".",{"type":40,"tag":66,"props":208,"children":209},{},[210,212,218],{"type":46,"value":211},"Deployment: Deployed directly via ",{"type":40,"tag":78,"props":213,"children":215},{"className":214},[],[216],{"type":46,"value":217},"firebase deploy --only functions",{"type":46,"value":206},{"type":40,"tag":66,"props":220,"children":221},{},[222,227],{"type":40,"tag":70,"props":223,"children":224},{},[225],{"type":46,"value":226},"Target B: Publishable npm Package \u002F Shareable Open Source Package",{"type":40,"tag":117,"props":228,"children":229},{},[230,235,279],{"type":40,"tag":66,"props":231,"children":232},{},[233],{"type":46,"value":234},"Output: Reusable npm package containing exported V2 functions.",{"type":40,"tag":66,"props":236,"children":237},{},[238,240,246,248,254,256,261,263,269,271,277],{"type":46,"value":239},"Configuration: ",{"type":40,"tag":78,"props":241,"children":243},{"className":242},[],[244],{"type":46,"value":245},"package.json",{"type":46,"value":247}," with ",{"type":40,"tag":78,"props":249,"children":251},{"className":250},[],[252],{"type":46,"value":253},"exports",{"type":46,"value":255}," map and ",{"type":40,"tag":78,"props":257,"children":259},{"className":258},[],[260],{"type":46,"value":83},{"type":46,"value":262},"\ndeclared in ",{"type":40,"tag":78,"props":264,"children":266},{"className":265},[],[267],{"type":46,"value":268},"dependencies",{"type":46,"value":270}," (or ",{"type":40,"tag":78,"props":272,"children":274},{"className":273},[],[275],{"type":46,"value":276},"peerDependencies",{"type":46,"value":278},").",{"type":40,"tag":66,"props":280,"children":281},{},[282,284,290,292,298],{"type":46,"value":283},"Usage: End users install the package (",{"type":40,"tag":78,"props":285,"children":287},{"className":286},[],[288],{"type":46,"value":289},"npm i \u003Cpackage-name>",{"type":46,"value":291},") and re-export\nfunctions in their ",{"type":40,"tag":78,"props":293,"children":295},{"className":294},[],[296],{"type":46,"value":297},"index.ts",{"type":46,"value":206},{"type":40,"tag":102,"props":300,"children":301},{},[],{"type":40,"tag":49,"props":303,"children":305},{"id":304},"getting-started-git-safety",[306],{"type":46,"value":307},"Getting Started & Git Safety",{"type":40,"tag":62,"props":309,"children":310},{},[311,321],{"type":40,"tag":66,"props":312,"children":313},{},[314,319],{"type":40,"tag":70,"props":315,"children":316},{},[317],{"type":46,"value":318},"Git Status",{"type":46,"value":320},": Verify the workspace has a clean git status before starting.",{"type":40,"tag":66,"props":322,"children":323},{},[324,329,331],{"type":40,"tag":70,"props":325,"children":326},{},[327],{"type":46,"value":328},"In-Place Copying",{"type":46,"value":330},": If copying code to a new subdirectory within the same\nrepository:\n",{"type":40,"tag":117,"props":332,"children":333},{},[334,347],{"type":40,"tag":66,"props":335,"children":336},{},[337,339,345],{"type":46,"value":338},"Use ",{"type":40,"tag":78,"props":340,"children":342},{"className":341},[],[343],{"type":46,"value":344},"git cp",{"type":46,"value":346}," (or copy files and commit) to copy the extension's source\ndirectory to the target directory.",{"type":40,"tag":66,"props":348,"children":349},{},[350,352],{"type":46,"value":351},"Commit immediately:\n",{"type":40,"tag":78,"props":353,"children":355},{"className":354},[],[356],{"type":46,"value":357},"\"Copying [extension-name] extension to [directory] in preparation for rewrite\"",{"type":40,"tag":102,"props":359,"children":360},{},[],{"type":40,"tag":49,"props":362,"children":364},{"id":363},"rules-and-constraints",[365],{"type":46,"value":366},"Rules and Constraints",{"type":40,"tag":368,"props":369,"children":371},"h3",{"id":370},"_1-zero-local-overhead-cloud-functions-integration",[372],{"type":46,"value":373},"1. Zero-Local-Overhead (Cloud Functions Integration)",{"type":40,"tag":56,"props":375,"children":376},{},[377],{"type":46,"value":378},"Assume Cloud Functions for Firebase Workload Identities, Declarative Security,\nand SDK Lifecycle Hooks are fully GA.",{"type":40,"tag":117,"props":380,"children":381},{},[382,400,409],{"type":40,"tag":66,"props":383,"children":384},{},[385,390,392,398],{"type":40,"tag":70,"props":386,"children":387},{},[388],{"type":46,"value":389},"Do NOT",{"type":46,"value":391}," output instructions or scripts telling users to run manual ",{"type":40,"tag":78,"props":393,"children":395},{"className":394},[],[396],{"type":46,"value":397},"gcloud",{"type":46,"value":399},"\nIAM commands or create service accounts.",{"type":40,"tag":66,"props":401,"children":402},{},[403,407],{"type":40,"tag":70,"props":404,"children":405},{},[406],{"type":46,"value":389},{"type":46,"value":408}," write code comments instructing users to manually enable Google\nAPIs in the cloud console.",{"type":40,"tag":66,"props":410,"children":411},{},[412,414,420,422,428],{"type":46,"value":413},"Instead, use declarative ",{"type":40,"tag":78,"props":415,"children":417},{"className":416},[],[418],{"type":46,"value":419},"requiresAPI",{"type":46,"value":421}," and ",{"type":40,"tag":78,"props":423,"children":425},{"className":424},[],[426],{"type":46,"value":427},"requiresRole",{"type":46,"value":429}," imports from the\nSDK.",{"type":40,"tag":368,"props":431,"children":433},{"id":432},"_2-global-parameter-access-restriction",[434],{"type":46,"value":435},"2. Global Parameter Access Restriction",{"type":40,"tag":117,"props":437,"children":438},{},[439,455],{"type":40,"tag":66,"props":440,"children":441},{},[442],{"type":40,"tag":70,"props":443,"children":444},{},[445,447,453],{"type":46,"value":446},"Never call ",{"type":40,"tag":78,"props":448,"children":450},{"className":449},[],[451],{"type":46,"value":452},".value()",{"type":46,"value":454}," on any parameter at global scope.",{"type":40,"tag":66,"props":456,"children":457},{},[458,460,466,468],{"type":46,"value":459},"If a global variable or class instance is initialized using a parameter value,\ndeclare the variable globally and initialize it inside the ",{"type":40,"tag":78,"props":461,"children":463},{"className":462},[],[464],{"type":46,"value":465},"onInit()",{"type":46,"value":467},"\ncallback:\n",{"type":40,"tag":469,"props":470,"children":475},"pre",{"className":471,"code":472,"language":473,"meta":474,"style":474},"language-typescript shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","import { defineString } from \"firebase-functions\u002Fparams\";\nimport { onInit } from \"firebase-functions\u002Fv2\";\n\nconst bqDataset = defineString(\"DATASET_ID\");\nlet bqClient: BigQuery;\n\nonInit(() => {\n  bqClient = new BigQuery({ datasetId: bqDataset.value() });\n});\n","typescript","",[476],{"type":40,"tag":78,"props":477,"children":478},{"__ignoreMap":474},[479,534,576,586,638,667,675,703,777],{"type":40,"tag":480,"props":481,"children":484},"span",{"class":482,"line":483},"line",1,[485,491,497,503,508,513,518,524,529],{"type":40,"tag":480,"props":486,"children":488},{"style":487},"--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic",[489],{"type":46,"value":490},"import",{"type":40,"tag":480,"props":492,"children":494},{"style":493},"--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF",[495],{"type":46,"value":496}," {",{"type":40,"tag":480,"props":498,"children":500},{"style":499},"--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8",[501],{"type":46,"value":502}," defineString",{"type":40,"tag":480,"props":504,"children":505},{"style":493},[506],{"type":46,"value":507}," }",{"type":40,"tag":480,"props":509,"children":510},{"style":487},[511],{"type":46,"value":512}," from",{"type":40,"tag":480,"props":514,"children":515},{"style":493},[516],{"type":46,"value":517}," \"",{"type":40,"tag":480,"props":519,"children":521},{"style":520},"--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D",[522],{"type":46,"value":523},"firebase-functions\u002Fparams",{"type":40,"tag":480,"props":525,"children":526},{"style":493},[527],{"type":46,"value":528},"\"",{"type":40,"tag":480,"props":530,"children":531},{"style":493},[532],{"type":46,"value":533},";\n",{"type":40,"tag":480,"props":535,"children":537},{"class":482,"line":536},2,[538,542,546,551,555,559,563,568,572],{"type":40,"tag":480,"props":539,"children":540},{"style":487},[541],{"type":46,"value":490},{"type":40,"tag":480,"props":543,"children":544},{"style":493},[545],{"type":46,"value":496},{"type":40,"tag":480,"props":547,"children":548},{"style":499},[549],{"type":46,"value":550}," onInit",{"type":40,"tag":480,"props":552,"children":553},{"style":493},[554],{"type":46,"value":507},{"type":40,"tag":480,"props":556,"children":557},{"style":487},[558],{"type":46,"value":512},{"type":40,"tag":480,"props":560,"children":561},{"style":493},[562],{"type":46,"value":517},{"type":40,"tag":480,"props":564,"children":565},{"style":520},[566],{"type":46,"value":567},"firebase-functions\u002Fv2",{"type":40,"tag":480,"props":569,"children":570},{"style":493},[571],{"type":46,"value":528},{"type":40,"tag":480,"props":573,"children":574},{"style":493},[575],{"type":46,"value":533},{"type":40,"tag":480,"props":577,"children":579},{"class":482,"line":578},3,[580],{"type":40,"tag":480,"props":581,"children":583},{"emptyLinePlaceholder":582},true,[584],{"type":46,"value":585},"\n",{"type":40,"tag":480,"props":587,"children":589},{"class":482,"line":588},4,[590,596,601,606,611,616,620,625,629,634],{"type":40,"tag":480,"props":591,"children":593},{"style":592},"--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA",[594],{"type":46,"value":595},"const",{"type":40,"tag":480,"props":597,"children":598},{"style":499},[599],{"type":46,"value":600}," bqDataset ",{"type":40,"tag":480,"props":602,"children":603},{"style":493},[604],{"type":46,"value":605},"=",{"type":40,"tag":480,"props":607,"children":609},{"style":608},"--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF",[610],{"type":46,"value":502},{"type":40,"tag":480,"props":612,"children":613},{"style":499},[614],{"type":46,"value":615},"(",{"type":40,"tag":480,"props":617,"children":618},{"style":493},[619],{"type":46,"value":528},{"type":40,"tag":480,"props":621,"children":622},{"style":520},[623],{"type":46,"value":624},"DATASET_ID",{"type":40,"tag":480,"props":626,"children":627},{"style":493},[628],{"type":46,"value":528},{"type":40,"tag":480,"props":630,"children":631},{"style":499},[632],{"type":46,"value":633},")",{"type":40,"tag":480,"props":635,"children":636},{"style":493},[637],{"type":46,"value":533},{"type":40,"tag":480,"props":639,"children":641},{"class":482,"line":640},5,[642,647,652,657,663],{"type":40,"tag":480,"props":643,"children":644},{"style":592},[645],{"type":46,"value":646},"let",{"type":40,"tag":480,"props":648,"children":649},{"style":499},[650],{"type":46,"value":651}," bqClient",{"type":40,"tag":480,"props":653,"children":654},{"style":493},[655],{"type":46,"value":656},":",{"type":40,"tag":480,"props":658,"children":660},{"style":659},"--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B",[661],{"type":46,"value":662}," BigQuery",{"type":40,"tag":480,"props":664,"children":665},{"style":493},[666],{"type":46,"value":533},{"type":40,"tag":480,"props":668,"children":670},{"class":482,"line":669},6,[671],{"type":40,"tag":480,"props":672,"children":673},{"emptyLinePlaceholder":582},[674],{"type":46,"value":585},{"type":40,"tag":480,"props":676,"children":678},{"class":482,"line":677},7,[679,684,688,693,698],{"type":40,"tag":480,"props":680,"children":681},{"style":608},[682],{"type":46,"value":683},"onInit",{"type":40,"tag":480,"props":685,"children":686},{"style":499},[687],{"type":46,"value":615},{"type":40,"tag":480,"props":689,"children":690},{"style":493},[691],{"type":46,"value":692},"()",{"type":40,"tag":480,"props":694,"children":695},{"style":592},[696],{"type":46,"value":697}," =>",{"type":40,"tag":480,"props":699,"children":700},{"style":493},[701],{"type":46,"value":702}," {\n",{"type":40,"tag":480,"props":704,"children":706},{"class":482,"line":705},8,[707,712,717,722,726,731,736,741,745,750,754,759,764,769,773],{"type":40,"tag":480,"props":708,"children":709},{"style":499},[710],{"type":46,"value":711},"  bqClient",{"type":40,"tag":480,"props":713,"children":714},{"style":493},[715],{"type":46,"value":716}," =",{"type":40,"tag":480,"props":718,"children":719},{"style":493},[720],{"type":46,"value":721}," new",{"type":40,"tag":480,"props":723,"children":724},{"style":608},[725],{"type":46,"value":662},{"type":40,"tag":480,"props":727,"children":729},{"style":728},"--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178",[730],{"type":46,"value":615},{"type":40,"tag":480,"props":732,"children":733},{"style":493},[734],{"type":46,"value":735},"{",{"type":40,"tag":480,"props":737,"children":738},{"style":728},[739],{"type":46,"value":740}," datasetId",{"type":40,"tag":480,"props":742,"children":743},{"style":493},[744],{"type":46,"value":656},{"type":40,"tag":480,"props":746,"children":747},{"style":499},[748],{"type":46,"value":749}," bqDataset",{"type":40,"tag":480,"props":751,"children":752},{"style":493},[753],{"type":46,"value":206},{"type":40,"tag":480,"props":755,"children":756},{"style":608},[757],{"type":46,"value":758},"value",{"type":40,"tag":480,"props":760,"children":761},{"style":728},[762],{"type":46,"value":763},"() ",{"type":40,"tag":480,"props":765,"children":766},{"style":493},[767],{"type":46,"value":768},"}",{"type":40,"tag":480,"props":770,"children":771},{"style":728},[772],{"type":46,"value":633},{"type":40,"tag":480,"props":774,"children":775},{"style":493},[776],{"type":46,"value":533},{"type":40,"tag":480,"props":778,"children":780},{"class":482,"line":779},9,[781,785,789],{"type":40,"tag":480,"props":782,"children":783},{"style":493},[784],{"type":46,"value":768},{"type":40,"tag":480,"props":786,"children":787},{"style":499},[788],{"type":46,"value":633},{"type":40,"tag":480,"props":790,"children":791},{"style":493},[792],{"type":46,"value":533},{"type":40,"tag":368,"props":794,"children":796},{"id":795},"_3-concurrency-cost-parity-for-v2",[797],{"type":46,"value":798},"3. Concurrency & Cost Parity for V2",{"type":40,"tag":56,"props":800,"children":801},{},[802],{"type":46,"value":803},"When upgrading triggers to V2:",{"type":40,"tag":117,"props":805,"children":806},{},[807,812],{"type":40,"tag":66,"props":808,"children":809},{},[810],{"type":46,"value":811},"By default, V2 functions enable concurrency (up to 80 requests per instance).",{"type":40,"tag":66,"props":813,"children":814},{},[815,817,823],{"type":46,"value":816},"If you want to maintain V1 fractional CPU pricing (and disable concurrency),\nset ",{"type":40,"tag":78,"props":818,"children":820},{"className":819},[],[821],{"type":46,"value":822},"cpu: \"gcf_gen1\"",{"type":46,"value":824}," in the function's options object.",{"type":40,"tag":102,"props":826,"children":827},{},[],{"type":40,"tag":49,"props":829,"children":831},{"id":830},"step-by-step-migration-execution",[832],{"type":46,"value":833},"Step-by-Step Migration Execution",{"type":40,"tag":368,"props":835,"children":837},{"id":836},"step-1-inventory-the-extension",[838],{"type":46,"value":839},"Step 1: Inventory the Extension",{"type":40,"tag":56,"props":841,"children":842},{},[843],{"type":46,"value":844},"Conduct a complete inventory of everything the extension declares, ships, and\ndocuments so that nothing is lost during migration:",{"type":40,"tag":62,"props":846,"children":847},{},[848,1007],{"type":40,"tag":66,"props":849,"children":850},{},[851,862,864],{"type":40,"tag":70,"props":852,"children":853},{},[854,856],{"type":46,"value":855},"Inventory ",{"type":40,"tag":78,"props":857,"children":859},{"className":858},[],[860],{"type":46,"value":861},"extension.yaml",{"type":46,"value":863},":\n",{"type":40,"tag":117,"props":865,"children":866},{},[867,891,910,927,974],{"type":40,"tag":66,"props":868,"children":869},{},[870,876,878,883,884,889],{"type":40,"tag":78,"props":871,"children":873},{"className":872},[],[874],{"type":46,"value":875},"params",{"type":46,"value":877},": Convert to Functions params (",{"type":40,"tag":78,"props":879,"children":881},{"className":880},[],[882],{"type":46,"value":188},{"type":46,"value":190},{"type":40,"tag":78,"props":885,"children":887},{"className":886},[],[888],{"type":46,"value":196},{"type":46,"value":890},",\netc.).",{"type":40,"tag":66,"props":892,"children":893},{},[894,900,902,908],{"type":40,"tag":78,"props":895,"children":897},{"className":896},[],[898],{"type":46,"value":899},"apis",{"type":46,"value":901},": Convert to ",{"type":40,"tag":78,"props":903,"children":905},{"className":904},[],[906],{"type":46,"value":907},"requiresAPI(...)",{"type":46,"value":909}," declarations.",{"type":40,"tag":66,"props":911,"children":912},{},[913,919,920,926],{"type":40,"tag":78,"props":914,"children":916},{"className":915},[],[917],{"type":46,"value":918},"roles",{"type":46,"value":901},{"type":40,"tag":78,"props":921,"children":923},{"className":922},[],[924],{"type":46,"value":925},"requiresRole(...)",{"type":46,"value":909},{"type":40,"tag":66,"props":928,"children":929},{},[930,936,937,943,944,950,951,957,959,965,966,972],{"type":40,"tag":78,"props":931,"children":933},{"className":932},[],[934],{"type":46,"value":935},"lifecycleEvents",{"type":46,"value":76},{"type":40,"tag":78,"props":938,"children":940},{"className":939},[],[941],{"type":46,"value":942},"onInstall",{"type":46,"value":190},{"type":40,"tag":78,"props":945,"children":947},{"className":946},[],[948],{"type":46,"value":949},"onUpdate",{"type":46,"value":190},{"type":40,"tag":78,"props":952,"children":954},{"className":953},[],[955],{"type":46,"value":956},"onConfigure",{"type":46,"value":958},"): Convert to\n",{"type":40,"tag":78,"props":960,"children":962},{"className":961},[],[963],{"type":46,"value":964},"afterFirstDeploy",{"type":46,"value":421},{"type":40,"tag":78,"props":967,"children":969},{"className":968},[],[970],{"type":46,"value":971},"afterRedeploy",{"type":46,"value":973}," hooks.",{"type":40,"tag":66,"props":975,"children":976},{},[977,983,985,991,993,998,1000,1006],{"type":40,"tag":78,"props":978,"children":980},{"className":979},[],[981],{"type":46,"value":982},"resources",{"type":46,"value":984},": Note all function triggers to convert from 1st gen\n(",{"type":40,"tag":78,"props":986,"children":988},{"className":987},[],[989],{"type":46,"value":990},"firebase-functions\u002Fv1",{"type":46,"value":992},") to 2nd gen (",{"type":40,"tag":78,"props":994,"children":996},{"className":995},[],[997],{"type":46,"value":567},{"type":46,"value":999},"), including\nstandard event triggers, HTTP handlers, and task queues\n(",{"type":40,"tag":78,"props":1001,"children":1003},{"className":1002},[],[1004],{"type":46,"value":1005},"onTaskDispatched",{"type":46,"value":278},{"type":40,"tag":66,"props":1008,"children":1009},{},[1010,1015,1016],{"type":40,"tag":70,"props":1011,"children":1012},{},[1013],{"type":46,"value":1014},"Inventory Files & Tooling",{"type":46,"value":863},{"type":40,"tag":117,"props":1017,"children":1018},{},[1019,1030,1057],{"type":40,"tag":66,"props":1020,"children":1021},{},[1022,1028],{"type":40,"tag":78,"props":1023,"children":1025},{"className":1024},[],[1026],{"type":46,"value":1027},"functions\u002F",{"type":46,"value":1029},": Source code, triggers, helpers, and task queue handlers.",{"type":40,"tag":66,"props":1031,"children":1032},{},[1033,1035,1041,1042,1048,1050,1056],{"type":46,"value":1034},"Documentation: ",{"type":40,"tag":78,"props":1036,"children":1038},{"className":1037},[],[1039],{"type":46,"value":1040},"README.md",{"type":46,"value":190},{"type":40,"tag":78,"props":1043,"children":1045},{"className":1044},[],[1046],{"type":46,"value":1047},"PREINSTALL.md",{"type":46,"value":1049},", and ",{"type":40,"tag":78,"props":1051,"children":1053},{"className":1052},[],[1054],{"type":46,"value":1055},"POSTINSTALL.md",{"type":46,"value":206},{"type":40,"tag":66,"props":1058,"children":1059},{},[1060,1066],{"type":40,"tag":78,"props":1061,"children":1063},{"className":1062},[],[1064],{"type":46,"value":1065},"scripts\u002F",{"type":46,"value":1067},": Note any backfill, import, or helper scripts shipped with the\nextension.",{"type":40,"tag":368,"props":1069,"children":1071},{"id":1070},"step-2-create-update-packagejson",[1072,1074],{"type":46,"value":1073},"Step 2: Create \u002F Update ",{"type":40,"tag":78,"props":1075,"children":1077},{"className":1076},[],[1078],{"type":46,"value":245},{"type":40,"tag":56,"props":1080,"children":1081},{},[1082],{"type":46,"value":1083},"Create an npm package for the migrated extension code (either at project root or\nin a dedicated workspace directory):",{"type":40,"tag":117,"props":1085,"children":1086},{},[1087,1099,1176],{"type":40,"tag":66,"props":1088,"children":1089},{},[1090,1092,1098],{"type":46,"value":1091},"Set a publishable package name (",{"type":40,"tag":78,"props":1093,"children":1095},{"className":1094},[],[1096],{"type":46,"value":1097},"name: \"\u003Cpackage-name>\"",{"type":46,"value":278},{"type":40,"tag":66,"props":1100,"children":1101},{},[1102,1107,1109,1115,1117,1123,1124,1130,1131,1137,1138,1144,1145,1151,1153,1159,1161,1167,1169,1174],{"type":40,"tag":70,"props":1103,"children":1104},{},[1105],{"type":46,"value":1106},"Preserve Dev & Test Dependencies",{"type":46,"value":1108},": Preserve all existing ",{"type":40,"tag":78,"props":1110,"children":1112},{"className":1111},[],[1113],{"type":46,"value":1114},"devDependencies",{"type":46,"value":1116},",\ntest runners (",{"type":40,"tag":78,"props":1118,"children":1120},{"className":1119},[],[1121],{"type":46,"value":1122},"jest",{"type":46,"value":190},{"type":40,"tag":78,"props":1125,"children":1127},{"className":1126},[],[1128],{"type":46,"value":1129},"ts-jest",{"type":46,"value":190},{"type":40,"tag":78,"props":1132,"children":1134},{"className":1133},[],[1135],{"type":46,"value":1136},"@types\u002Fjest",{"type":46,"value":190},{"type":40,"tag":78,"props":1139,"children":1141},{"className":1140},[],[1142],{"type":46,"value":1143},"mocha",{"type":46,"value":190},{"type":40,"tag":78,"props":1146,"children":1148},{"className":1147},[],[1149],{"type":46,"value":1150},"@types\u002Fmocha",{"type":46,"value":1152},"), and\ntest scripts (",{"type":40,"tag":78,"props":1154,"children":1156},{"className":1155},[],[1157],{"type":46,"value":1158},"\"test\": \"...\"",{"type":46,"value":1160},") from the legacy extension\n(",{"type":40,"tag":78,"props":1162,"children":1164},{"className":1163},[],[1165],{"type":46,"value":1166},"functions\u002Fpackage.json",{"type":46,"value":1168}," or root ",{"type":40,"tag":78,"props":1170,"children":1172},{"className":1171},[],[1173],{"type":46,"value":245},{"type":46,"value":1175},"). Do not drop test frameworks\nor type definitions.",{"type":40,"tag":66,"props":1177,"children":1178},{},[1179,1181,1186,1188,1194,1196,1201,1203,1208,1210],{"type":46,"value":1180},"Declare ",{"type":40,"tag":78,"props":1182,"children":1184},{"className":1183},[],[1185],{"type":46,"value":83},{"type":46,"value":1187}," (e.g. ",{"type":40,"tag":78,"props":1189,"children":1191},{"className":1190},[],[1192],{"type":46,"value":1193},"^7.0.0",{"type":46,"value":1195},") in ",{"type":40,"tag":78,"props":1197,"children":1199},{"className":1198},[],[1200],{"type":46,"value":268},{"type":46,"value":1202}," (or\n",{"type":40,"tag":78,"props":1204,"children":1206},{"className":1205},[],[1207],{"type":46,"value":276},{"type":46,"value":1209}," if creating a lightweight middleware package where the root\nconsumer manages the runtime version):\n",{"type":40,"tag":469,"props":1211,"children":1215},{"className":1212,"code":1213,"language":1214,"meta":474,"style":474},"language-json shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","{\n  \"name\": \"\u003Cpackage-name>\",\n  \"version\": \"1.0.0\",\n  \"main\": \"lib\u002Findex.js\",\n  \"types\": \"lib\u002Findex.d.ts\",\n  \"exports\": {\n    \".\": {\n      \"types\": \".\u002Flib\u002Findex.d.ts\",\n      \"default\": \".\u002Flib\u002Findex.js\"\n    }\n  },\n  \"engines\": {\n    \"node\": \">=22\"\n  },\n  \"dependencies\": {\n    \"firebase-admin\": \"^12.0.0\",\n    \"firebase-functions\": \"^7.0.0\"\n  }\n}\n","json",[1216],{"type":40,"tag":78,"props":1217,"children":1218},{"__ignoreMap":474},[1219,1227,1266,1303,1340,1377,1400,1424,1462,1496,1505,1514,1539,1573,1581,1605,1643,1675,1684],{"type":40,"tag":480,"props":1220,"children":1221},{"class":482,"line":483},[1222],{"type":40,"tag":480,"props":1223,"children":1224},{"style":493},[1225],{"type":46,"value":1226},"{\n",{"type":40,"tag":480,"props":1228,"children":1229},{"class":482,"line":536},[1230,1235,1240,1244,1248,1252,1257,1261],{"type":40,"tag":480,"props":1231,"children":1232},{"style":493},[1233],{"type":46,"value":1234},"  \"",{"type":40,"tag":480,"props":1236,"children":1237},{"style":592},[1238],{"type":46,"value":1239},"name",{"type":40,"tag":480,"props":1241,"children":1242},{"style":493},[1243],{"type":46,"value":528},{"type":40,"tag":480,"props":1245,"children":1246},{"style":493},[1247],{"type":46,"value":656},{"type":40,"tag":480,"props":1249,"children":1250},{"style":493},[1251],{"type":46,"value":517},{"type":40,"tag":480,"props":1253,"children":1254},{"style":520},[1255],{"type":46,"value":1256},"\u003Cpackage-name>",{"type":40,"tag":480,"props":1258,"children":1259},{"style":493},[1260],{"type":46,"value":528},{"type":40,"tag":480,"props":1262,"children":1263},{"style":493},[1264],{"type":46,"value":1265},",\n",{"type":40,"tag":480,"props":1267,"children":1268},{"class":482,"line":578},[1269,1273,1278,1282,1286,1290,1295,1299],{"type":40,"tag":480,"props":1270,"children":1271},{"style":493},[1272],{"type":46,"value":1234},{"type":40,"tag":480,"props":1274,"children":1275},{"style":592},[1276],{"type":46,"value":1277},"version",{"type":40,"tag":480,"props":1279,"children":1280},{"style":493},[1281],{"type":46,"value":528},{"type":40,"tag":480,"props":1283,"children":1284},{"style":493},[1285],{"type":46,"value":656},{"type":40,"tag":480,"props":1287,"children":1288},{"style":493},[1289],{"type":46,"value":517},{"type":40,"tag":480,"props":1291,"children":1292},{"style":520},[1293],{"type":46,"value":1294},"1.0.0",{"type":40,"tag":480,"props":1296,"children":1297},{"style":493},[1298],{"type":46,"value":528},{"type":40,"tag":480,"props":1300,"children":1301},{"style":493},[1302],{"type":46,"value":1265},{"type":40,"tag":480,"props":1304,"children":1305},{"class":482,"line":588},[1306,1310,1315,1319,1323,1327,1332,1336],{"type":40,"tag":480,"props":1307,"children":1308},{"style":493},[1309],{"type":46,"value":1234},{"type":40,"tag":480,"props":1311,"children":1312},{"style":592},[1313],{"type":46,"value":1314},"main",{"type":40,"tag":480,"props":1316,"children":1317},{"style":493},[1318],{"type":46,"value":528},{"type":40,"tag":480,"props":1320,"children":1321},{"style":493},[1322],{"type":46,"value":656},{"type":40,"tag":480,"props":1324,"children":1325},{"style":493},[1326],{"type":46,"value":517},{"type":40,"tag":480,"props":1328,"children":1329},{"style":520},[1330],{"type":46,"value":1331},"lib\u002Findex.js",{"type":40,"tag":480,"props":1333,"children":1334},{"style":493},[1335],{"type":46,"value":528},{"type":40,"tag":480,"props":1337,"children":1338},{"style":493},[1339],{"type":46,"value":1265},{"type":40,"tag":480,"props":1341,"children":1342},{"class":482,"line":640},[1343,1347,1352,1356,1360,1364,1369,1373],{"type":40,"tag":480,"props":1344,"children":1345},{"style":493},[1346],{"type":46,"value":1234},{"type":40,"tag":480,"props":1348,"children":1349},{"style":592},[1350],{"type":46,"value":1351},"types",{"type":40,"tag":480,"props":1353,"children":1354},{"style":493},[1355],{"type":46,"value":528},{"type":40,"tag":480,"props":1357,"children":1358},{"style":493},[1359],{"type":46,"value":656},{"type":40,"tag":480,"props":1361,"children":1362},{"style":493},[1363],{"type":46,"value":517},{"type":40,"tag":480,"props":1365,"children":1366},{"style":520},[1367],{"type":46,"value":1368},"lib\u002Findex.d.ts",{"type":40,"tag":480,"props":1370,"children":1371},{"style":493},[1372],{"type":46,"value":528},{"type":40,"tag":480,"props":1374,"children":1375},{"style":493},[1376],{"type":46,"value":1265},{"type":40,"tag":480,"props":1378,"children":1379},{"class":482,"line":669},[1380,1384,1388,1392,1396],{"type":40,"tag":480,"props":1381,"children":1382},{"style":493},[1383],{"type":46,"value":1234},{"type":40,"tag":480,"props":1385,"children":1386},{"style":592},[1387],{"type":46,"value":253},{"type":40,"tag":480,"props":1389,"children":1390},{"style":493},[1391],{"type":46,"value":528},{"type":40,"tag":480,"props":1393,"children":1394},{"style":493},[1395],{"type":46,"value":656},{"type":40,"tag":480,"props":1397,"children":1398},{"style":493},[1399],{"type":46,"value":702},{"type":40,"tag":480,"props":1401,"children":1402},{"class":482,"line":677},[1403,1408,1412,1416,1420],{"type":40,"tag":480,"props":1404,"children":1405},{"style":493},[1406],{"type":46,"value":1407},"    \"",{"type":40,"tag":480,"props":1409,"children":1410},{"style":659},[1411],{"type":46,"value":206},{"type":40,"tag":480,"props":1413,"children":1414},{"style":493},[1415],{"type":46,"value":528},{"type":40,"tag":480,"props":1417,"children":1418},{"style":493},[1419],{"type":46,"value":656},{"type":40,"tag":480,"props":1421,"children":1422},{"style":493},[1423],{"type":46,"value":702},{"type":40,"tag":480,"props":1425,"children":1426},{"class":482,"line":705},[1427,1432,1437,1441,1445,1449,1454,1458],{"type":40,"tag":480,"props":1428,"children":1429},{"style":493},[1430],{"type":46,"value":1431},"      \"",{"type":40,"tag":480,"props":1433,"children":1435},{"style":1434},"--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C",[1436],{"type":46,"value":1351},{"type":40,"tag":480,"props":1438,"children":1439},{"style":493},[1440],{"type":46,"value":528},{"type":40,"tag":480,"props":1442,"children":1443},{"style":493},[1444],{"type":46,"value":656},{"type":40,"tag":480,"props":1446,"children":1447},{"style":493},[1448],{"type":46,"value":517},{"type":40,"tag":480,"props":1450,"children":1451},{"style":520},[1452],{"type":46,"value":1453},".\u002Flib\u002Findex.d.ts",{"type":40,"tag":480,"props":1455,"children":1456},{"style":493},[1457],{"type":46,"value":528},{"type":40,"tag":480,"props":1459,"children":1460},{"style":493},[1461],{"type":46,"value":1265},{"type":40,"tag":480,"props":1463,"children":1464},{"class":482,"line":779},[1465,1469,1474,1478,1482,1486,1491],{"type":40,"tag":480,"props":1466,"children":1467},{"style":493},[1468],{"type":46,"value":1431},{"type":40,"tag":480,"props":1470,"children":1471},{"style":1434},[1472],{"type":46,"value":1473},"default",{"type":40,"tag":480,"props":1475,"children":1476},{"style":493},[1477],{"type":46,"value":528},{"type":40,"tag":480,"props":1479,"children":1480},{"style":493},[1481],{"type":46,"value":656},{"type":40,"tag":480,"props":1483,"children":1484},{"style":493},[1485],{"type":46,"value":517},{"type":40,"tag":480,"props":1487,"children":1488},{"style":520},[1489],{"type":46,"value":1490},".\u002Flib\u002Findex.js",{"type":40,"tag":480,"props":1492,"children":1493},{"style":493},[1494],{"type":46,"value":1495},"\"\n",{"type":40,"tag":480,"props":1497,"children":1499},{"class":482,"line":1498},10,[1500],{"type":40,"tag":480,"props":1501,"children":1502},{"style":493},[1503],{"type":46,"value":1504},"    }\n",{"type":40,"tag":480,"props":1506,"children":1508},{"class":482,"line":1507},11,[1509],{"type":40,"tag":480,"props":1510,"children":1511},{"style":493},[1512],{"type":46,"value":1513},"  },\n",{"type":40,"tag":480,"props":1515,"children":1517},{"class":482,"line":1516},12,[1518,1522,1527,1531,1535],{"type":40,"tag":480,"props":1519,"children":1520},{"style":493},[1521],{"type":46,"value":1234},{"type":40,"tag":480,"props":1523,"children":1524},{"style":592},[1525],{"type":46,"value":1526},"engines",{"type":40,"tag":480,"props":1528,"children":1529},{"style":493},[1530],{"type":46,"value":528},{"type":40,"tag":480,"props":1532,"children":1533},{"style":493},[1534],{"type":46,"value":656},{"type":40,"tag":480,"props":1536,"children":1537},{"style":493},[1538],{"type":46,"value":702},{"type":40,"tag":480,"props":1540,"children":1542},{"class":482,"line":1541},13,[1543,1547,1552,1556,1560,1564,1569],{"type":40,"tag":480,"props":1544,"children":1545},{"style":493},[1546],{"type":46,"value":1407},{"type":40,"tag":480,"props":1548,"children":1549},{"style":659},[1550],{"type":46,"value":1551},"node",{"type":40,"tag":480,"props":1553,"children":1554},{"style":493},[1555],{"type":46,"value":528},{"type":40,"tag":480,"props":1557,"children":1558},{"style":493},[1559],{"type":46,"value":656},{"type":40,"tag":480,"props":1561,"children":1562},{"style":493},[1563],{"type":46,"value":517},{"type":40,"tag":480,"props":1565,"children":1566},{"style":520},[1567],{"type":46,"value":1568},">=22",{"type":40,"tag":480,"props":1570,"children":1571},{"style":493},[1572],{"type":46,"value":1495},{"type":40,"tag":480,"props":1574,"children":1576},{"class":482,"line":1575},14,[1577],{"type":40,"tag":480,"props":1578,"children":1579},{"style":493},[1580],{"type":46,"value":1513},{"type":40,"tag":480,"props":1582,"children":1584},{"class":482,"line":1583},15,[1585,1589,1593,1597,1601],{"type":40,"tag":480,"props":1586,"children":1587},{"style":493},[1588],{"type":46,"value":1234},{"type":40,"tag":480,"props":1590,"children":1591},{"style":592},[1592],{"type":46,"value":268},{"type":40,"tag":480,"props":1594,"children":1595},{"style":493},[1596],{"type":46,"value":528},{"type":40,"tag":480,"props":1598,"children":1599},{"style":493},[1600],{"type":46,"value":656},{"type":40,"tag":480,"props":1602,"children":1603},{"style":493},[1604],{"type":46,"value":702},{"type":40,"tag":480,"props":1606,"children":1608},{"class":482,"line":1607},16,[1609,1613,1618,1622,1626,1630,1635,1639],{"type":40,"tag":480,"props":1610,"children":1611},{"style":493},[1612],{"type":46,"value":1407},{"type":40,"tag":480,"props":1614,"children":1615},{"style":659},[1616],{"type":46,"value":1617},"firebase-admin",{"type":40,"tag":480,"props":1619,"children":1620},{"style":493},[1621],{"type":46,"value":528},{"type":40,"tag":480,"props":1623,"children":1624},{"style":493},[1625],{"type":46,"value":656},{"type":40,"tag":480,"props":1627,"children":1628},{"style":493},[1629],{"type":46,"value":517},{"type":40,"tag":480,"props":1631,"children":1632},{"style":520},[1633],{"type":46,"value":1634},"^12.0.0",{"type":40,"tag":480,"props":1636,"children":1637},{"style":493},[1638],{"type":46,"value":528},{"type":40,"tag":480,"props":1640,"children":1641},{"style":493},[1642],{"type":46,"value":1265},{"type":40,"tag":480,"props":1644,"children":1646},{"class":482,"line":1645},17,[1647,1651,1655,1659,1663,1667,1671],{"type":40,"tag":480,"props":1648,"children":1649},{"style":493},[1650],{"type":46,"value":1407},{"type":40,"tag":480,"props":1652,"children":1653},{"style":659},[1654],{"type":46,"value":83},{"type":40,"tag":480,"props":1656,"children":1657},{"style":493},[1658],{"type":46,"value":528},{"type":40,"tag":480,"props":1660,"children":1661},{"style":493},[1662],{"type":46,"value":656},{"type":40,"tag":480,"props":1664,"children":1665},{"style":493},[1666],{"type":46,"value":517},{"type":40,"tag":480,"props":1668,"children":1669},{"style":520},[1670],{"type":46,"value":1193},{"type":40,"tag":480,"props":1672,"children":1673},{"style":493},[1674],{"type":46,"value":1495},{"type":40,"tag":480,"props":1676,"children":1678},{"class":482,"line":1677},18,[1679],{"type":40,"tag":480,"props":1680,"children":1681},{"style":493},[1682],{"type":46,"value":1683},"  }\n",{"type":40,"tag":480,"props":1685,"children":1687},{"class":482,"line":1686},19,[1688],{"type":40,"tag":480,"props":1689,"children":1690},{"style":493},[1691],{"type":46,"value":1692},"}\n",{"type":40,"tag":368,"props":1694,"children":1696},{"id":1695},"step-3-move-function-code-expose-deployable-functions",[1697],{"type":46,"value":1698},"Step 3: Move Function Code & Expose Deployable Functions",{"type":40,"tag":56,"props":1700,"children":1701},{},[1702,1704,1710],{"type":46,"value":1703},"Move the extension's function source into the package's ",{"type":40,"tag":78,"props":1705,"children":1707},{"className":1706},[],[1708],{"type":46,"value":1709},"src\u002F",{"type":46,"value":1711}," folder:",{"type":40,"tag":62,"props":1713,"children":1714},{},[1715,1726],{"type":40,"tag":66,"props":1716,"children":1717},{},[1718,1720,1725],{"type":46,"value":1719},"Keep normal Firebase trigger exports. The package must expose deployable\nfunctions that end users can re-export from their entrypoint (",{"type":40,"tag":78,"props":1721,"children":1723},{"className":1722},[],[1724],{"type":46,"value":297},{"type":46,"value":278},{"type":40,"tag":66,"props":1727,"children":1728},{},[1729,1731,1788,1794,1796,1802],{"type":46,"value":1730},"Document that consumers must deploy packaged functions by re-exporting them:\n",{"type":40,"tag":469,"props":1732,"children":1734},{"className":471,"code":1733,"language":473,"meta":474,"style":474},"export * from \"\u003Cpackage-name>\";\n\u002F\u002F Or named exports:\n\u002F\u002F export { syncV2, initBigQuerySync } from \"\u003Cpackage-name>\";\n",[1735],{"type":40,"tag":78,"props":1736,"children":1737},{"__ignoreMap":474},[1738,1771,1780],{"type":40,"tag":480,"props":1739,"children":1740},{"class":482,"line":483},[1741,1746,1751,1755,1759,1763,1767],{"type":40,"tag":480,"props":1742,"children":1743},{"style":487},[1744],{"type":46,"value":1745},"export",{"type":40,"tag":480,"props":1747,"children":1748},{"style":493},[1749],{"type":46,"value":1750}," *",{"type":40,"tag":480,"props":1752,"children":1753},{"style":487},[1754],{"type":46,"value":512},{"type":40,"tag":480,"props":1756,"children":1757},{"style":493},[1758],{"type":46,"value":517},{"type":40,"tag":480,"props":1760,"children":1761},{"style":520},[1762],{"type":46,"value":1256},{"type":40,"tag":480,"props":1764,"children":1765},{"style":493},[1766],{"type":46,"value":528},{"type":40,"tag":480,"props":1768,"children":1769},{"style":493},[1770],{"type":46,"value":533},{"type":40,"tag":480,"props":1772,"children":1773},{"class":482,"line":536},[1774],{"type":40,"tag":480,"props":1775,"children":1777},{"style":1776},"--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic",[1778],{"type":46,"value":1779},"\u002F\u002F Or named exports:\n",{"type":40,"tag":480,"props":1781,"children":1782},{"class":482,"line":578},[1783],{"type":40,"tag":480,"props":1784,"children":1785},{"style":1776},[1786],{"type":46,"value":1787},"\u002F\u002F export { syncV2, initBigQuerySync } from \"\u003Cpackage-name>\";\n",{"type":40,"tag":1789,"props":1790,"children":1791},"em",{},[1792],{"type":46,"value":1793},"Note",{"type":46,"value":1795},": A bare import (",{"type":40,"tag":78,"props":1797,"children":1799},{"className":1798},[],[1800],{"type":46,"value":1801},"import \"\u003Cpackage-name>\"",{"type":46,"value":1803},") is not enough. The Firebase\nCLI only deploys functions exported from the user's root entry file.",{"type":40,"tag":368,"props":1805,"children":1807},{"id":1806},"step-4-upgrade-functions-from-1st-gen-to-2nd-gen",[1808],{"type":46,"value":1809},"Step 4: Upgrade Functions from 1st Gen to 2nd Gen",{"type":40,"tag":56,"props":1811,"children":1812},{},[1813,1815,1821,1822,1828,1829,1835,1837,1843,1844,1849,1850,1855,1857,1863],{"type":46,"value":1814},"Convert each exported 1st gen function trigger (",{"type":40,"tag":78,"props":1816,"children":1818},{"className":1817},[],[1819],{"type":46,"value":1820},"onWrite",{"type":46,"value":190},{"type":40,"tag":78,"props":1823,"children":1825},{"className":1824},[],[1826],{"type":46,"value":1827},"onRequest",{"type":46,"value":1265},{"type":40,"tag":78,"props":1830,"children":1832},{"className":1831},[],[1833],{"type":46,"value":1834},"tasks.taskQueue().onDispatch",{"type":46,"value":1836},") to its 2nd gen equivalent (",{"type":40,"tag":78,"props":1838,"children":1840},{"className":1839},[],[1841],{"type":46,"value":1842},"onDocumentWritten",{"type":46,"value":1265},{"type":40,"tag":78,"props":1845,"children":1847},{"className":1846},[],[1848],{"type":46,"value":1827},{"type":46,"value":190},{"type":40,"tag":78,"props":1851,"children":1853},{"className":1852},[],[1854],{"type":46,"value":1005},{"type":46,"value":1856}," from ",{"type":40,"tag":78,"props":1858,"children":1860},{"className":1859},[],[1861],{"type":46,"value":1862},"firebase-functions\u002Fv2\u002F...",{"type":46,"value":1864},"):",{"type":40,"tag":62,"props":1866,"children":1867},{},[1868,1902],{"type":40,"tag":66,"props":1869,"children":1870},{},[1871,1876,1878,1884,1886,1893,1895,1901],{"type":40,"tag":70,"props":1872,"children":1873},{},[1874],{"type":46,"value":1875},"Signatures & Destructuring Shim",{"type":46,"value":1877},": Use the Destructuring Compatibility Shim\n(",{"type":40,"tag":78,"props":1879,"children":1881},{"className":1880},[],[1882],{"type":46,"value":1883},"{ shimmedKey, context }",{"type":46,"value":1885},") to preserve V1 business logic without rewriting\nfunction bodies. See ",{"type":40,"tag":1887,"props":1888,"children":1890},"a",{"href":1889},"references\u002Fsignature-mapping.md",[1891],{"type":46,"value":1892},"signature-mapping.md",{"type":46,"value":1894},"\nand ",{"type":40,"tag":1887,"props":1896,"children":1898},{"href":1897},"references\u002Fdestructuring-shim.md",[1899],{"type":46,"value":1900},"destructuring-shim.md",{"type":46,"value":206},{"type":40,"tag":66,"props":1903,"children":1904},{},[1905,1910,1912,1918,1919,1925,1927,1932],{"type":40,"tag":70,"props":1906,"children":1907},{},[1908],{"type":46,"value":1909},"Authentication Triggers Exception",{"type":46,"value":1911},": If your extension uses v1\nAuthentication Triggers (",{"type":40,"tag":78,"props":1913,"children":1915},{"className":1914},[],[1916],{"type":46,"value":1917},"auth.user().onCreate()",{"type":46,"value":190},{"type":40,"tag":78,"props":1920,"children":1922},{"className":1921},[],[1923],{"type":46,"value":1924},"auth.user().onDelete()",{"type":46,"value":1926},"),\ninstruct the agent to check live whether a 2nd gen alternative exists in the\ninstalled ",{"type":40,"tag":78,"props":1928,"children":1930},{"className":1929},[],[1931],{"type":46,"value":83},{"type":46,"value":1933}," package or live documentation. If 2nd gen Auth\ntriggers are not yet supported for those events, warn the user clearly and\nhalt or refuse the migration for those specific triggers until a V2\nalternative becomes available.",{"type":40,"tag":368,"props":1935,"children":1937},{"id":1936},"step-5-replace-extension-params-with-functions-params",[1938],{"type":46,"value":1939},"Step 5: Replace Extension Params with Functions Params",{"type":40,"tag":56,"props":1941,"children":1942},{},[1943,1945,1950],{"type":46,"value":1944},"Each parameter in ",{"type":40,"tag":78,"props":1946,"children":1948},{"className":1947},[],[1949],{"type":46,"value":861},{"type":46,"value":1951}," becomes a Parameterized Configuration call:",{"type":40,"tag":62,"props":1953,"children":1954},{},[1955,2117,2129],{"type":40,"tag":66,"props":1956,"children":1957},{},[1958,1960],{"type":46,"value":1959},"Map parameter primitives and attributes:\n",{"type":40,"tag":117,"props":1961,"children":1962},{},[1963,1982,2000,2017,2034,2075,2092],{"type":40,"tag":66,"props":1964,"children":1965},{},[1966,1968,1974,1976],{"type":46,"value":1967},"Type ",{"type":40,"tag":78,"props":1969,"children":1971},{"className":1970},[],[1972],{"type":46,"value":1973},"string",{"type":46,"value":1975}," ->\n",{"type":40,"tag":78,"props":1977,"children":1979},{"className":1978},[],[1980],{"type":46,"value":1981},"defineString(\"PARAM_NAME\", { label: \"...\", description: \"...\", default: \"...\" })",{"type":40,"tag":66,"props":1983,"children":1984},{},[1985,1986,1992,1994],{"type":46,"value":1967},{"type":40,"tag":78,"props":1987,"children":1989},{"className":1988},[],[1990],{"type":46,"value":1991},"secret",{"type":46,"value":1993}," -> ",{"type":40,"tag":78,"props":1995,"children":1997},{"className":1996},[],[1998],{"type":46,"value":1999},"defineSecret(\"PARAM_NAME\")",{"type":40,"tag":66,"props":2001,"children":2002},{},[2003,2004,2010,2011],{"type":46,"value":1967},{"type":40,"tag":78,"props":2005,"children":2007},{"className":2006},[],[2008],{"type":46,"value":2009},"int",{"type":46,"value":1993},{"type":40,"tag":78,"props":2012,"children":2014},{"className":2013},[],[2015],{"type":46,"value":2016},"defineInt(\"PARAM_NAME\", { label: \"...\", default: 123 })",{"type":40,"tag":66,"props":2018,"children":2019},{},[2020,2021,2027,2028],{"type":46,"value":1967},{"type":40,"tag":78,"props":2022,"children":2024},{"className":2023},[],[2025],{"type":46,"value":2026},"boolean",{"type":46,"value":1993},{"type":40,"tag":78,"props":2029,"children":2031},{"className":2030},[],[2032],{"type":46,"value":2033},"defineBoolean(\"PARAM_NAME\", { default: true })",{"type":40,"tag":66,"props":2035,"children":2036},{},[2037,2038,2044,2046,2052,2054,2060,2062,2068,2069],{"type":46,"value":1967},{"type":40,"tag":78,"props":2039,"children":2041},{"className":2040},[],[2042],{"type":46,"value":2043},"select",{"type":46,"value":2045}," \u002F ",{"type":40,"tag":78,"props":2047,"children":2049},{"className":2048},[],[2050],{"type":46,"value":2051},"multiSelect",{"type":46,"value":2053}," -> map ",{"type":40,"tag":78,"props":2055,"children":2057},{"className":2056},[],[2058],{"type":46,"value":2059},"options",{"type":46,"value":2061}," into ",{"type":40,"tag":78,"props":2063,"children":2065},{"className":2064},[],[2066],{"type":46,"value":2067},"input",{"type":46,"value":863},{"type":40,"tag":78,"props":2070,"children":2072},{"className":2071},[],[2073],{"type":46,"value":2074},"defineString(\"PARAM_NAME\", { input: { select: { options: [{ value: \"val\", label: \"Val\" }] } } })",{"type":40,"tag":66,"props":2076,"children":2077},{},[2078,2084,2086],{"type":40,"tag":78,"props":2079,"children":2081},{"className":2080},[],[2082],{"type":46,"value":2083},"validationRegex",{"type":46,"value":2085}," -> map into text input options:\n",{"type":40,"tag":78,"props":2087,"children":2089},{"className":2088},[],[2090],{"type":46,"value":2091},"defineString(\"PARAM_NAME\", { input: { text: { validationRegex: \"^[a-z]+$\" } } })",{"type":40,"tag":66,"props":2093,"children":2094},{},[2095,2101,2103,2109,2111],{"type":40,"tag":78,"props":2096,"children":2098},{"className":2097},[],[2099],{"type":46,"value":2100},"required: true",{"type":46,"value":2102}," \u002F Non-empty validation -> map ",{"type":40,"tag":78,"props":2104,"children":2106},{"className":2105},[],[2107],{"type":46,"value":2108},"nonEmpty: true",{"type":46,"value":2110}," into input\noptions:\n",{"type":40,"tag":78,"props":2112,"children":2114},{"className":2113},[],[2115],{"type":46,"value":2116},"defineString(\"PARAM_NAME\", { input: { text: { nonEmpty: true } } })",{"type":40,"tag":66,"props":2118,"children":2119},{},[2120,2122,2128],{"type":46,"value":2121},"Read parameter values inside handlers using ",{"type":40,"tag":78,"props":2123,"children":2125},{"className":2124},[],[2126],{"type":46,"value":2127},"paramName.value()",{"type":46,"value":206},{"type":40,"tag":66,"props":2130,"children":2131},{},[2132,2137,2139,2145,2146,2151,2153,2158],{"type":40,"tag":70,"props":2133,"children":2134},{},[2135],{"type":46,"value":2136},"Keep Exact Parameter Names",{"type":46,"value":2138},": Never change parameter names\n(",{"type":40,"tag":78,"props":2140,"children":2142},{"className":2141},[],[2143],{"type":46,"value":2144},"COLLECTION_PATH",{"type":46,"value":190},{"type":40,"tag":78,"props":2147,"children":2149},{"className":2148},[],[2150],{"type":46,"value":624},{"type":46,"value":2152},", etc.) so that existing values carry over\nseamlessly in ",{"type":40,"tag":78,"props":2154,"children":2156},{"className":2155},[],[2157],{"type":46,"value":204},{"type":46,"value":206},{"type":40,"tag":368,"props":2160,"children":2162},{"id":2161},"step-6-migrate-internal-task-queue-calls-queueenqueue",[2163,2165,2171],{"type":46,"value":2164},"Step 6: Migrate Internal Task Queue Calls (",{"type":40,"tag":78,"props":2166,"children":2168},{"className":2167},[],[2169],{"type":46,"value":2170},"queue.enqueue(...)",{"type":46,"value":633},{"type":40,"tag":56,"props":2173,"children":2174},{},[2175,2177,2183],{"type":46,"value":2176},"If your extension code enqueues tasks onto its own queue using the Admin SDK\n(",{"type":40,"tag":78,"props":2178,"children":2180},{"className":2179},[],[2181],{"type":46,"value":2182},"getFunctions().taskQueue(...)",{"type":46,"value":1864},{"type":40,"tag":117,"props":2185,"children":2186},{},[2187,2199],{"type":40,"tag":66,"props":2188,"children":2189},{},[2190,2192,2198],{"type":46,"value":2191},"Under the Extensions runtime, the Admin SDK resolved queues by function name\nplus ",{"type":40,"tag":78,"props":2193,"children":2195},{"className":2194},[],[2196],{"type":46,"value":2197},"process.env.EXT_INSTANCE_ID",{"type":46,"value":206},{"type":40,"tag":66,"props":2200,"children":2201},{},[2202,2207,2209,2215,2217],{"type":40,"tag":70,"props":2203,"children":2204},{},[2205],{"type":46,"value":2206},"In an npm package \u002F regular codebase",{"type":46,"value":2208},": Remove the second argument\n(",{"type":40,"tag":78,"props":2210,"children":2212},{"className":2211},[],[2213],{"type":46,"value":2214},"EXT_INSTANCE_ID",{"type":46,"value":2216},") entirely. The Admin SDK automatically targets the current\ncodebase:\n",{"type":40,"tag":469,"props":2218,"children":2220},{"className":471,"code":2219,"language":473,"meta":474,"style":474},"\u002F\u002F Before (extension runtime):\n\u002F\u002F const queue = getFunctions().taskQueue(`locations\u002F${region}\u002Ffunctions\u002FsyncBigQuery`, process.env.EXT_INSTANCE_ID);\n\n\u002F\u002F After (npm package):\nconst queue = getFunctions().taskQueue(`locations\u002F${region}\u002Ffunctions\u002FsyncBigQuery`);\nawait queue.enqueue(taskData);\n",[2221],{"type":40,"tag":78,"props":2222,"children":2223},{"__ignoreMap":474},[2224,2232,2240,2247,2255,2334],{"type":40,"tag":480,"props":2225,"children":2226},{"class":482,"line":483},[2227],{"type":40,"tag":480,"props":2228,"children":2229},{"style":1776},[2230],{"type":46,"value":2231},"\u002F\u002F Before (extension runtime):\n",{"type":40,"tag":480,"props":2233,"children":2234},{"class":482,"line":536},[2235],{"type":40,"tag":480,"props":2236,"children":2237},{"style":1776},[2238],{"type":46,"value":2239},"\u002F\u002F const queue = getFunctions().taskQueue(`locations\u002F${region}\u002Ffunctions\u002FsyncBigQuery`, process.env.EXT_INSTANCE_ID);\n",{"type":40,"tag":480,"props":2241,"children":2242},{"class":482,"line":578},[2243],{"type":40,"tag":480,"props":2244,"children":2245},{"emptyLinePlaceholder":582},[2246],{"type":46,"value":585},{"type":40,"tag":480,"props":2248,"children":2249},{"class":482,"line":588},[2250],{"type":40,"tag":480,"props":2251,"children":2252},{"style":1776},[2253],{"type":46,"value":2254},"\u002F\u002F After (npm package):\n",{"type":40,"tag":480,"props":2256,"children":2257},{"class":482,"line":640},[2258,2262,2267,2271,2276,2280,2284,2289,2293,2298,2303,2308,2313,2317,2322,2326,2330],{"type":40,"tag":480,"props":2259,"children":2260},{"style":592},[2261],{"type":46,"value":595},{"type":40,"tag":480,"props":2263,"children":2264},{"style":499},[2265],{"type":46,"value":2266}," queue ",{"type":40,"tag":480,"props":2268,"children":2269},{"style":493},[2270],{"type":46,"value":605},{"type":40,"tag":480,"props":2272,"children":2273},{"style":608},[2274],{"type":46,"value":2275}," getFunctions",{"type":40,"tag":480,"props":2277,"children":2278},{"style":499},[2279],{"type":46,"value":692},{"type":40,"tag":480,"props":2281,"children":2282},{"style":493},[2283],{"type":46,"value":206},{"type":40,"tag":480,"props":2285,"children":2286},{"style":608},[2287],{"type":46,"value":2288},"taskQueue",{"type":40,"tag":480,"props":2290,"children":2291},{"style":499},[2292],{"type":46,"value":615},{"type":40,"tag":480,"props":2294,"children":2295},{"style":493},[2296],{"type":46,"value":2297},"`",{"type":40,"tag":480,"props":2299,"children":2300},{"style":520},[2301],{"type":46,"value":2302},"locations\u002F",{"type":40,"tag":480,"props":2304,"children":2305},{"style":493},[2306],{"type":46,"value":2307},"${",{"type":40,"tag":480,"props":2309,"children":2310},{"style":499},[2311],{"type":46,"value":2312},"region",{"type":40,"tag":480,"props":2314,"children":2315},{"style":493},[2316],{"type":46,"value":768},{"type":40,"tag":480,"props":2318,"children":2319},{"style":520},[2320],{"type":46,"value":2321},"\u002Ffunctions\u002FsyncBigQuery",{"type":40,"tag":480,"props":2323,"children":2324},{"style":493},[2325],{"type":46,"value":2297},{"type":40,"tag":480,"props":2327,"children":2328},{"style":499},[2329],{"type":46,"value":633},{"type":40,"tag":480,"props":2331,"children":2332},{"style":493},[2333],{"type":46,"value":533},{"type":40,"tag":480,"props":2335,"children":2336},{"class":482,"line":669},[2337,2342,2347,2351,2356,2361],{"type":40,"tag":480,"props":2338,"children":2339},{"style":487},[2340],{"type":46,"value":2341},"await",{"type":40,"tag":480,"props":2343,"children":2344},{"style":499},[2345],{"type":46,"value":2346}," queue",{"type":40,"tag":480,"props":2348,"children":2349},{"style":493},[2350],{"type":46,"value":206},{"type":40,"tag":480,"props":2352,"children":2353},{"style":608},[2354],{"type":46,"value":2355},"enqueue",{"type":40,"tag":480,"props":2357,"children":2358},{"style":499},[2359],{"type":46,"value":2360},"(taskData)",{"type":40,"tag":480,"props":2362,"children":2363},{"style":493},[2364],{"type":46,"value":533},{"type":40,"tag":368,"props":2366,"children":2368},{"id":2367},"step-7-migrate-secrets",[2369],{"type":46,"value":2370},"Step 7: Migrate Secrets",{"type":40,"tag":56,"props":2372,"children":2373},{},[2374,2376,2382],{"type":46,"value":2375},"For parameters declared with ",{"type":40,"tag":78,"props":2377,"children":2379},{"className":2378},[],[2380],{"type":46,"value":2381},"type: secret",{"type":46,"value":656},{"type":40,"tag":62,"props":2384,"children":2385},{},[2386,2483,2557],{"type":40,"tag":66,"props":2387,"children":2388},{},[2389,2391],{"type":46,"value":2390},"Declare the secret explicitly:\n",{"type":40,"tag":469,"props":2392,"children":2394},{"className":471,"code":2393,"language":473,"meta":474,"style":474},"import { defineSecret } from \"firebase-functions\u002Fparams\";\nconst apiKey = defineSecret(\"API_KEY\");\n",[2395],{"type":40,"tag":78,"props":2396,"children":2397},{"__ignoreMap":474},[2398,2438],{"type":40,"tag":480,"props":2399,"children":2400},{"class":482,"line":483},[2401,2405,2409,2414,2418,2422,2426,2430,2434],{"type":40,"tag":480,"props":2402,"children":2403},{"style":487},[2404],{"type":46,"value":490},{"type":40,"tag":480,"props":2406,"children":2407},{"style":493},[2408],{"type":46,"value":496},{"type":40,"tag":480,"props":2410,"children":2411},{"style":499},[2412],{"type":46,"value":2413}," defineSecret",{"type":40,"tag":480,"props":2415,"children":2416},{"style":493},[2417],{"type":46,"value":507},{"type":40,"tag":480,"props":2419,"children":2420},{"style":487},[2421],{"type":46,"value":512},{"type":40,"tag":480,"props":2423,"children":2424},{"style":493},[2425],{"type":46,"value":517},{"type":40,"tag":480,"props":2427,"children":2428},{"style":520},[2429],{"type":46,"value":523},{"type":40,"tag":480,"props":2431,"children":2432},{"style":493},[2433],{"type":46,"value":528},{"type":40,"tag":480,"props":2435,"children":2436},{"style":493},[2437],{"type":46,"value":533},{"type":40,"tag":480,"props":2439,"children":2440},{"class":482,"line":536},[2441,2445,2450,2454,2458,2462,2466,2471,2475,2479],{"type":40,"tag":480,"props":2442,"children":2443},{"style":592},[2444],{"type":46,"value":595},{"type":40,"tag":480,"props":2446,"children":2447},{"style":499},[2448],{"type":46,"value":2449}," apiKey ",{"type":40,"tag":480,"props":2451,"children":2452},{"style":493},[2453],{"type":46,"value":605},{"type":40,"tag":480,"props":2455,"children":2456},{"style":608},[2457],{"type":46,"value":2413},{"type":40,"tag":480,"props":2459,"children":2460},{"style":499},[2461],{"type":46,"value":615},{"type":40,"tag":480,"props":2463,"children":2464},{"style":493},[2465],{"type":46,"value":528},{"type":40,"tag":480,"props":2467,"children":2468},{"style":520},[2469],{"type":46,"value":2470},"API_KEY",{"type":40,"tag":480,"props":2472,"children":2473},{"style":493},[2474],{"type":46,"value":528},{"type":40,"tag":480,"props":2476,"children":2477},{"style":499},[2478],{"type":46,"value":633},{"type":40,"tag":480,"props":2480,"children":2481},{"style":493},[2482],{"type":46,"value":533},{"type":40,"tag":66,"props":2484,"children":2485},{},[2486,2488],{"type":46,"value":2487},"Bind the secret in the trigger options:\n",{"type":40,"tag":469,"props":2489,"children":2491},{"className":471,"code":2490,"language":473,"meta":474,"style":474},"export const fn = onRequest({ secrets: [apiKey] }, handler);\n",[2492],{"type":40,"tag":78,"props":2493,"children":2494},{"__ignoreMap":474},[2495],{"type":40,"tag":480,"props":2496,"children":2497},{"class":482,"line":483},[2498,2502,2507,2512,2516,2521,2525,2529,2534,2538,2543,2548,2553],{"type":40,"tag":480,"props":2499,"children":2500},{"style":487},[2501],{"type":46,"value":1745},{"type":40,"tag":480,"props":2503,"children":2504},{"style":592},[2505],{"type":46,"value":2506}," const",{"type":40,"tag":480,"props":2508,"children":2509},{"style":499},[2510],{"type":46,"value":2511}," fn ",{"type":40,"tag":480,"props":2513,"children":2514},{"style":493},[2515],{"type":46,"value":605},{"type":40,"tag":480,"props":2517,"children":2518},{"style":608},[2519],{"type":46,"value":2520}," onRequest",{"type":40,"tag":480,"props":2522,"children":2523},{"style":499},[2524],{"type":46,"value":615},{"type":40,"tag":480,"props":2526,"children":2527},{"style":493},[2528],{"type":46,"value":735},{"type":40,"tag":480,"props":2530,"children":2531},{"style":728},[2532],{"type":46,"value":2533}," secrets",{"type":40,"tag":480,"props":2535,"children":2536},{"style":493},[2537],{"type":46,"value":656},{"type":40,"tag":480,"props":2539,"children":2540},{"style":499},[2541],{"type":46,"value":2542}," [apiKey] ",{"type":40,"tag":480,"props":2544,"children":2545},{"style":493},[2546],{"type":46,"value":2547},"},",{"type":40,"tag":480,"props":2549,"children":2550},{"style":499},[2551],{"type":46,"value":2552}," handler)",{"type":40,"tag":480,"props":2554,"children":2555},{"style":493},[2556],{"type":46,"value":533},{"type":40,"tag":66,"props":2558,"children":2559},{},[2560],{"type":46,"value":2561},"Keep exact secret names unchanged so existing Secret Manager bindings work.",{"type":40,"tag":368,"props":2563,"children":2565},{"id":2564},"step-8-declare-required-apis-and-iam-roles",[2566],{"type":46,"value":2567},"Step 8: Declare Required APIs and IAM Roles",{"type":40,"tag":56,"props":2569,"children":2570},{},[2571,2573,2578,2579,2584,2585,2590],{"type":46,"value":2572},"Replace ",{"type":40,"tag":78,"props":2574,"children":2576},{"className":2575},[],[2577],{"type":46,"value":899},{"type":46,"value":421},{"type":40,"tag":78,"props":2580,"children":2582},{"className":2581},[],[2583],{"type":46,"value":918},{"type":46,"value":1856},{"type":40,"tag":78,"props":2586,"children":2588},{"className":2587},[],[2589],{"type":46,"value":861},{"type":46,"value":2591}," with declarative code in your\nentry file:",{"type":40,"tag":469,"props":2593,"children":2595},{"className":471,"code":2594,"language":473,"meta":474,"style":474},"import { requiresAPI, requiresRole } from \"firebase-functions\";\n\nrequiresAPI(\"bigquery.googleapis.com\", \"Needed to write changelog rows\");\nrequiresRole(\"roles\u002Fbigquery.dataEditor\");\nrequiresRole(\"roles\u002Fbigquery.user\");\n",[2596],{"type":40,"tag":78,"props":2597,"children":2598},{"__ignoreMap":474},[2599,2649,2656,2705,2737],{"type":40,"tag":480,"props":2600,"children":2601},{"class":482,"line":483},[2602,2606,2610,2615,2620,2625,2629,2633,2637,2641,2645],{"type":40,"tag":480,"props":2603,"children":2604},{"style":487},[2605],{"type":46,"value":490},{"type":40,"tag":480,"props":2607,"children":2608},{"style":493},[2609],{"type":46,"value":496},{"type":40,"tag":480,"props":2611,"children":2612},{"style":499},[2613],{"type":46,"value":2614}," requiresAPI",{"type":40,"tag":480,"props":2616,"children":2617},{"style":493},[2618],{"type":46,"value":2619},",",{"type":40,"tag":480,"props":2621,"children":2622},{"style":499},[2623],{"type":46,"value":2624}," requiresRole",{"type":40,"tag":480,"props":2626,"children":2627},{"style":493},[2628],{"type":46,"value":507},{"type":40,"tag":480,"props":2630,"children":2631},{"style":487},[2632],{"type":46,"value":512},{"type":40,"tag":480,"props":2634,"children":2635},{"style":493},[2636],{"type":46,"value":517},{"type":40,"tag":480,"props":2638,"children":2639},{"style":520},[2640],{"type":46,"value":83},{"type":40,"tag":480,"props":2642,"children":2643},{"style":493},[2644],{"type":46,"value":528},{"type":40,"tag":480,"props":2646,"children":2647},{"style":493},[2648],{"type":46,"value":533},{"type":40,"tag":480,"props":2650,"children":2651},{"class":482,"line":536},[2652],{"type":40,"tag":480,"props":2653,"children":2654},{"emptyLinePlaceholder":582},[2655],{"type":46,"value":585},{"type":40,"tag":480,"props":2657,"children":2658},{"class":482,"line":578},[2659,2663,2667,2671,2676,2680,2684,2688,2693,2697,2701],{"type":40,"tag":480,"props":2660,"children":2661},{"style":608},[2662],{"type":46,"value":419},{"type":40,"tag":480,"props":2664,"children":2665},{"style":499},[2666],{"type":46,"value":615},{"type":40,"tag":480,"props":2668,"children":2669},{"style":493},[2670],{"type":46,"value":528},{"type":40,"tag":480,"props":2672,"children":2673},{"style":520},[2674],{"type":46,"value":2675},"bigquery.googleapis.com",{"type":40,"tag":480,"props":2677,"children":2678},{"style":493},[2679],{"type":46,"value":528},{"type":40,"tag":480,"props":2681,"children":2682},{"style":493},[2683],{"type":46,"value":2619},{"type":40,"tag":480,"props":2685,"children":2686},{"style":493},[2687],{"type":46,"value":517},{"type":40,"tag":480,"props":2689,"children":2690},{"style":520},[2691],{"type":46,"value":2692},"Needed to write changelog rows",{"type":40,"tag":480,"props":2694,"children":2695},{"style":493},[2696],{"type":46,"value":528},{"type":40,"tag":480,"props":2698,"children":2699},{"style":499},[2700],{"type":46,"value":633},{"type":40,"tag":480,"props":2702,"children":2703},{"style":493},[2704],{"type":46,"value":533},{"type":40,"tag":480,"props":2706,"children":2707},{"class":482,"line":588},[2708,2712,2716,2720,2725,2729,2733],{"type":40,"tag":480,"props":2709,"children":2710},{"style":608},[2711],{"type":46,"value":427},{"type":40,"tag":480,"props":2713,"children":2714},{"style":499},[2715],{"type":46,"value":615},{"type":40,"tag":480,"props":2717,"children":2718},{"style":493},[2719],{"type":46,"value":528},{"type":40,"tag":480,"props":2721,"children":2722},{"style":520},[2723],{"type":46,"value":2724},"roles\u002Fbigquery.dataEditor",{"type":40,"tag":480,"props":2726,"children":2727},{"style":493},[2728],{"type":46,"value":528},{"type":40,"tag":480,"props":2730,"children":2731},{"style":499},[2732],{"type":46,"value":633},{"type":40,"tag":480,"props":2734,"children":2735},{"style":493},[2736],{"type":46,"value":533},{"type":40,"tag":480,"props":2738,"children":2739},{"class":482,"line":640},[2740,2744,2748,2752,2757,2761,2765],{"type":40,"tag":480,"props":2741,"children":2742},{"style":608},[2743],{"type":46,"value":427},{"type":40,"tag":480,"props":2745,"children":2746},{"style":499},[2747],{"type":46,"value":615},{"type":40,"tag":480,"props":2749,"children":2750},{"style":493},[2751],{"type":46,"value":528},{"type":40,"tag":480,"props":2753,"children":2754},{"style":520},[2755],{"type":46,"value":2756},"roles\u002Fbigquery.user",{"type":40,"tag":480,"props":2758,"children":2759},{"style":493},[2760],{"type":46,"value":528},{"type":40,"tag":480,"props":2762,"children":2763},{"style":499},[2764],{"type":46,"value":633},{"type":40,"tag":480,"props":2766,"children":2767},{"style":493},[2768],{"type":46,"value":533},{"type":40,"tag":56,"props":2770,"children":2771},{},[2772],{"type":46,"value":2773},"At deploy time, the Firebase CLI automatically grants these roles to the managed\nruntime service account and enables the required APIs.",{"type":40,"tag":368,"props":2775,"children":2777},{"id":2776},"step-9-convert-lifecycle-hooks-afterfirstdeploy-afterredeploy",[2778,2780,2785,2787,2792],{"type":46,"value":2779},"Step 9: Convert Lifecycle Hooks (",{"type":40,"tag":78,"props":2781,"children":2783},{"className":2782},[],[2784],{"type":46,"value":964},{"type":46,"value":2786}," & ",{"type":40,"tag":78,"props":2788,"children":2790},{"className":2789},[],[2791],{"type":46,"value":971},{"type":46,"value":633},{"type":40,"tag":56,"props":2794,"children":2795},{},[2796,2797,2802,2803,2808,2809,2814,2815,2820],{"type":46,"value":2572},{"type":40,"tag":78,"props":2798,"children":2800},{"className":2799},[],[2801],{"type":46,"value":935},{"type":46,"value":76},{"type":40,"tag":78,"props":2804,"children":2806},{"className":2805},[],[2807],{"type":46,"value":942},{"type":46,"value":190},{"type":40,"tag":78,"props":2810,"children":2812},{"className":2811},[],[2813],{"type":46,"value":949},{"type":46,"value":190},{"type":40,"tag":78,"props":2816,"children":2818},{"className":2817},[],[2819],{"type":46,"value":956},{"type":46,"value":2821},") with SDK\nlifecycle hooks:",{"type":40,"tag":62,"props":2823,"children":2824},{},[2825,2867,3171],{"type":40,"tag":66,"props":2826,"children":2827},{},[2828,2830,2836,2837,2843,2845,2850,2851,2857,2859,2865],{"type":46,"value":2829},"Convert task queue handlers (",{"type":40,"tag":78,"props":2831,"children":2833},{"className":2832},[],[2834],{"type":46,"value":2835},"initBigQuerySync",{"type":46,"value":190},{"type":40,"tag":78,"props":2838,"children":2840},{"className":2839},[],[2841],{"type":46,"value":2842},"setupBigQuerySync",{"type":46,"value":2844},") to V2\n",{"type":40,"tag":78,"props":2846,"children":2848},{"className":2847},[],[2849],{"type":46,"value":1005},{"type":46,"value":1856},{"type":40,"tag":78,"props":2852,"children":2854},{"className":2853},[],[2855],{"type":46,"value":2856},"firebase-functions\u002Fv2\u002Ftasks",{"type":46,"value":2858}," (removing legacy\n",{"type":40,"tag":78,"props":2860,"children":2862},{"className":2861},[],[2863],{"type":46,"value":2864},"getExtensions().runtime().setProcessingState(...)",{"type":46,"value":2866}," calls).",{"type":40,"tag":66,"props":2868,"children":2869},{},[2870,2872],{"type":46,"value":2871},"Register lifecycle hooks in code:\n",{"type":40,"tag":469,"props":2873,"children":2875},{"className":471,"code":2874,"language":473,"meta":474,"style":474},"import { afterFirstDeploy, afterRedeploy } from \"firebase-functions\u002Fv2\";\n\n\u002F\u002F Replaces onInstall:\nafterFirstDeploy({\n  task: {\n    function: \"runInitialSetup\",\n    body: {}\n  }\n});\n\n\u002F\u002F Replaces onUpdate & onConfigure:\nafterRedeploy({\n  task: {\n    function: \"runInitialSetup\",\n    body: { reconcile: true }\n  }\n});\n",[2876],{"type":40,"tag":78,"props":2877,"children":2878},{"__ignoreMap":474},[2879,2928,2935,2943,2958,2974,3003,3020,3027,3042,3049,3057,3072,3087,3114,3149,3156],{"type":40,"tag":480,"props":2880,"children":2881},{"class":482,"line":483},[2882,2886,2890,2895,2899,2904,2908,2912,2916,2920,2924],{"type":40,"tag":480,"props":2883,"children":2884},{"style":487},[2885],{"type":46,"value":490},{"type":40,"tag":480,"props":2887,"children":2888},{"style":493},[2889],{"type":46,"value":496},{"type":40,"tag":480,"props":2891,"children":2892},{"style":499},[2893],{"type":46,"value":2894}," afterFirstDeploy",{"type":40,"tag":480,"props":2896,"children":2897},{"style":493},[2898],{"type":46,"value":2619},{"type":40,"tag":480,"props":2900,"children":2901},{"style":499},[2902],{"type":46,"value":2903}," afterRedeploy",{"type":40,"tag":480,"props":2905,"children":2906},{"style":493},[2907],{"type":46,"value":507},{"type":40,"tag":480,"props":2909,"children":2910},{"style":487},[2911],{"type":46,"value":512},{"type":40,"tag":480,"props":2913,"children":2914},{"style":493},[2915],{"type":46,"value":517},{"type":40,"tag":480,"props":2917,"children":2918},{"style":520},[2919],{"type":46,"value":567},{"type":40,"tag":480,"props":2921,"children":2922},{"style":493},[2923],{"type":46,"value":528},{"type":40,"tag":480,"props":2925,"children":2926},{"style":493},[2927],{"type":46,"value":533},{"type":40,"tag":480,"props":2929,"children":2930},{"class":482,"line":536},[2931],{"type":40,"tag":480,"props":2932,"children":2933},{"emptyLinePlaceholder":582},[2934],{"type":46,"value":585},{"type":40,"tag":480,"props":2936,"children":2937},{"class":482,"line":578},[2938],{"type":40,"tag":480,"props":2939,"children":2940},{"style":1776},[2941],{"type":46,"value":2942},"\u002F\u002F Replaces onInstall:\n",{"type":40,"tag":480,"props":2944,"children":2945},{"class":482,"line":588},[2946,2950,2954],{"type":40,"tag":480,"props":2947,"children":2948},{"style":608},[2949],{"type":46,"value":964},{"type":40,"tag":480,"props":2951,"children":2952},{"style":499},[2953],{"type":46,"value":615},{"type":40,"tag":480,"props":2955,"children":2956},{"style":493},[2957],{"type":46,"value":1226},{"type":40,"tag":480,"props":2959,"children":2960},{"class":482,"line":640},[2961,2966,2970],{"type":40,"tag":480,"props":2962,"children":2963},{"style":728},[2964],{"type":46,"value":2965},"  task",{"type":40,"tag":480,"props":2967,"children":2968},{"style":493},[2969],{"type":46,"value":656},{"type":40,"tag":480,"props":2971,"children":2972},{"style":493},[2973],{"type":46,"value":702},{"type":40,"tag":480,"props":2975,"children":2976},{"class":482,"line":669},[2977,2982,2986,2990,2995,2999],{"type":40,"tag":480,"props":2978,"children":2979},{"style":728},[2980],{"type":46,"value":2981},"    function",{"type":40,"tag":480,"props":2983,"children":2984},{"style":493},[2985],{"type":46,"value":656},{"type":40,"tag":480,"props":2987,"children":2988},{"style":493},[2989],{"type":46,"value":517},{"type":40,"tag":480,"props":2991,"children":2992},{"style":520},[2993],{"type":46,"value":2994},"runInitialSetup",{"type":40,"tag":480,"props":2996,"children":2997},{"style":493},[2998],{"type":46,"value":528},{"type":40,"tag":480,"props":3000,"children":3001},{"style":493},[3002],{"type":46,"value":1265},{"type":40,"tag":480,"props":3004,"children":3005},{"class":482,"line":677},[3006,3011,3015],{"type":40,"tag":480,"props":3007,"children":3008},{"style":728},[3009],{"type":46,"value":3010},"    body",{"type":40,"tag":480,"props":3012,"children":3013},{"style":493},[3014],{"type":46,"value":656},{"type":40,"tag":480,"props":3016,"children":3017},{"style":493},[3018],{"type":46,"value":3019}," {}\n",{"type":40,"tag":480,"props":3021,"children":3022},{"class":482,"line":705},[3023],{"type":40,"tag":480,"props":3024,"children":3025},{"style":493},[3026],{"type":46,"value":1683},{"type":40,"tag":480,"props":3028,"children":3029},{"class":482,"line":779},[3030,3034,3038],{"type":40,"tag":480,"props":3031,"children":3032},{"style":493},[3033],{"type":46,"value":768},{"type":40,"tag":480,"props":3035,"children":3036},{"style":499},[3037],{"type":46,"value":633},{"type":40,"tag":480,"props":3039,"children":3040},{"style":493},[3041],{"type":46,"value":533},{"type":40,"tag":480,"props":3043,"children":3044},{"class":482,"line":1498},[3045],{"type":40,"tag":480,"props":3046,"children":3047},{"emptyLinePlaceholder":582},[3048],{"type":46,"value":585},{"type":40,"tag":480,"props":3050,"children":3051},{"class":482,"line":1507},[3052],{"type":40,"tag":480,"props":3053,"children":3054},{"style":1776},[3055],{"type":46,"value":3056},"\u002F\u002F Replaces onUpdate & onConfigure:\n",{"type":40,"tag":480,"props":3058,"children":3059},{"class":482,"line":1516},[3060,3064,3068],{"type":40,"tag":480,"props":3061,"children":3062},{"style":608},[3063],{"type":46,"value":971},{"type":40,"tag":480,"props":3065,"children":3066},{"style":499},[3067],{"type":46,"value":615},{"type":40,"tag":480,"props":3069,"children":3070},{"style":493},[3071],{"type":46,"value":1226},{"type":40,"tag":480,"props":3073,"children":3074},{"class":482,"line":1541},[3075,3079,3083],{"type":40,"tag":480,"props":3076,"children":3077},{"style":728},[3078],{"type":46,"value":2965},{"type":40,"tag":480,"props":3080,"children":3081},{"style":493},[3082],{"type":46,"value":656},{"type":40,"tag":480,"props":3084,"children":3085},{"style":493},[3086],{"type":46,"value":702},{"type":40,"tag":480,"props":3088,"children":3089},{"class":482,"line":1575},[3090,3094,3098,3102,3106,3110],{"type":40,"tag":480,"props":3091,"children":3092},{"style":728},[3093],{"type":46,"value":2981},{"type":40,"tag":480,"props":3095,"children":3096},{"style":493},[3097],{"type":46,"value":656},{"type":40,"tag":480,"props":3099,"children":3100},{"style":493},[3101],{"type":46,"value":517},{"type":40,"tag":480,"props":3103,"children":3104},{"style":520},[3105],{"type":46,"value":2994},{"type":40,"tag":480,"props":3107,"children":3108},{"style":493},[3109],{"type":46,"value":528},{"type":40,"tag":480,"props":3111,"children":3112},{"style":493},[3113],{"type":46,"value":1265},{"type":40,"tag":480,"props":3115,"children":3116},{"class":482,"line":1583},[3117,3121,3125,3129,3134,3138,3144],{"type":40,"tag":480,"props":3118,"children":3119},{"style":728},[3120],{"type":46,"value":3010},{"type":40,"tag":480,"props":3122,"children":3123},{"style":493},[3124],{"type":46,"value":656},{"type":40,"tag":480,"props":3126,"children":3127},{"style":493},[3128],{"type":46,"value":496},{"type":40,"tag":480,"props":3130,"children":3131},{"style":728},[3132],{"type":46,"value":3133}," reconcile",{"type":40,"tag":480,"props":3135,"children":3136},{"style":493},[3137],{"type":46,"value":656},{"type":40,"tag":480,"props":3139,"children":3141},{"style":3140},"--shiki-light:#FF5370;--shiki-default:#FF9CAC;--shiki-dark:#FF9CAC",[3142],{"type":46,"value":3143}," true",{"type":40,"tag":480,"props":3145,"children":3146},{"style":493},[3147],{"type":46,"value":3148}," }\n",{"type":40,"tag":480,"props":3150,"children":3151},{"class":482,"line":1607},[3152],{"type":40,"tag":480,"props":3153,"children":3154},{"style":493},[3155],{"type":46,"value":1683},{"type":40,"tag":480,"props":3157,"children":3158},{"class":482,"line":1645},[3159,3163,3167],{"type":40,"tag":480,"props":3160,"children":3161},{"style":493},[3162],{"type":46,"value":768},{"type":40,"tag":480,"props":3164,"children":3165},{"style":499},[3166],{"type":46,"value":633},{"type":40,"tag":480,"props":3168,"children":3169},{"style":493},[3170],{"type":46,"value":533},{"type":40,"tag":66,"props":3172,"children":3173},{},[3174,3176],{"type":46,"value":3175},"Ensure handlers are idempotent and document manual rerun commands:\n",{"type":40,"tag":469,"props":3177,"children":3181},{"className":3178,"code":3179,"language":3180,"meta":474,"style":474},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","firebase functions:lifecycle:run afterFirstDeploy CODEBASE_NAME\nfirebase functions:lifecycle:run afterRedeploy CODEBASE_NAME\n","bash",[3182],{"type":40,"tag":78,"props":3183,"children":3184},{"__ignoreMap":474},[3185,3206],{"type":40,"tag":480,"props":3186,"children":3187},{"class":482,"line":483},[3188,3192,3197,3201],{"type":40,"tag":480,"props":3189,"children":3190},{"style":659},[3191],{"type":46,"value":8},{"type":40,"tag":480,"props":3193,"children":3194},{"style":520},[3195],{"type":46,"value":3196}," functions:lifecycle:run",{"type":40,"tag":480,"props":3198,"children":3199},{"style":520},[3200],{"type":46,"value":2894},{"type":40,"tag":480,"props":3202,"children":3203},{"style":520},[3204],{"type":46,"value":3205}," CODEBASE_NAME\n",{"type":40,"tag":480,"props":3207,"children":3208},{"class":482,"line":536},[3209,3213,3217,3221],{"type":40,"tag":480,"props":3210,"children":3211},{"style":659},[3212],{"type":46,"value":8},{"type":40,"tag":480,"props":3214,"children":3215},{"style":520},[3216],{"type":46,"value":3196},{"type":40,"tag":480,"props":3218,"children":3219},{"style":520},[3220],{"type":46,"value":2903},{"type":40,"tag":480,"props":3222,"children":3223},{"style":520},[3224],{"type":46,"value":3205},{"type":40,"tag":368,"props":3226,"children":3228},{"id":3227},"step-10-document-setup-for-your-users-readmemd",[3229,3231,3236],{"type":46,"value":3230},"Step 10: Document Setup for Your Users (",{"type":40,"tag":78,"props":3232,"children":3234},{"className":3233},[],[3235],{"type":46,"value":1040},{"type":46,"value":633},{"type":40,"tag":56,"props":3238,"children":3239},{},[3240,3242,3247,3249,3254,3256,3261],{"type":46,"value":3241},"Preserve whatever documentation, secrets, and setup instructions the original\nextension already documented in ",{"type":40,"tag":78,"props":3243,"children":3245},{"className":3244},[],[3246],{"type":46,"value":1040},{"type":46,"value":3248}," (and ",{"type":40,"tag":78,"props":3250,"children":3252},{"className":3251},[],[3253],{"type":46,"value":1047},{"type":46,"value":3255}," \u002F\n",{"type":40,"tag":78,"props":3257,"children":3259},{"className":3258},[],[3260],{"type":46,"value":1055},{"type":46,"value":3262},"), updating them as needed:",{"type":40,"tag":62,"props":3264,"children":3265},{},[3266,3305,3329],{"type":40,"tag":66,"props":3267,"children":3268},{},[3269,3274,3276,3281,3283,3289,3291,3296,3298,3303],{"type":40,"tag":70,"props":3270,"children":3271},{},[3272],{"type":46,"value":3273},"Update Configuration References",{"type":46,"value":3275},": Replace instructions referencing legacy\n",{"type":40,"tag":78,"props":3277,"children":3279},{"className":3278},[],[3280],{"type":46,"value":861},{"type":46,"value":3282}," installation prompts or ",{"type":40,"tag":78,"props":3284,"children":3286},{"className":3285},[],[3287],{"type":46,"value":3288},"ext-*.env",{"type":46,"value":3290}," files with standard\n",{"type":40,"tag":78,"props":3292,"children":3294},{"className":3293},[],[3295],{"type":46,"value":204},{"type":46,"value":3297}," Parameterized Configuration setup matching the ",{"type":40,"tag":78,"props":3299,"children":3301},{"className":3300},[],[3302],{"type":46,"value":188},{"type":46,"value":3304},"\nparameters.",{"type":40,"tag":66,"props":3306,"children":3307},{},[3308,3313,3315,3321,3323,3328],{"type":40,"tag":70,"props":3309,"children":3310},{},[3311],{"type":46,"value":3312},"Include Re-export Snippet",{"type":46,"value":3314},": Ensure the basic root re-export snippet is\nshown (",{"type":40,"tag":78,"props":3316,"children":3318},{"className":3317},[],[3319],{"type":46,"value":3320},"export * from \"\u003Cpackage-name>\";",{"type":46,"value":3322},") so users know how to expose the\nfunctions in their root ",{"type":40,"tag":78,"props":3324,"children":3326},{"className":3325},[],[3327],{"type":46,"value":297},{"type":46,"value":206},{"type":40,"tag":66,"props":3330,"children":3331},{},[3332,3337],{"type":40,"tag":70,"props":3333,"children":3334},{},[3335],{"type":46,"value":3336},"Avoid Unnecessary Boilerplate",{"type":46,"value":3338},": Do not generate redundant comparison\ntables or generic installation steps if the setup is self-evident in the code\nor already covered by existing README sections.",{"type":40,"tag":368,"props":3340,"children":3342},{"id":3341},"step-11-build-test-verification",[3343],{"type":46,"value":3344},"Step 11: Build & Test Verification",{"type":40,"tag":62,"props":3346,"children":3347},{},[3348,3379],{"type":40,"tag":66,"props":3349,"children":3350},{},[3351,3356,3358,3364,3365,3371,3373,3378],{"type":40,"tag":70,"props":3352,"children":3353},{},[3354],{"type":46,"value":3355},"Verify Source Compilation",{"type":46,"value":3357},": Run ",{"type":40,"tag":78,"props":3359,"children":3361},{"className":3360},[],[3362],{"type":46,"value":3363},"npm run build",{"type":46,"value":76},{"type":40,"tag":78,"props":3366,"children":3368},{"className":3367},[],[3369],{"type":46,"value":3370},"tsc",{"type":46,"value":3372},") to ensure no\nTypeScript compilation errors in ",{"type":40,"tag":78,"props":3374,"children":3376},{"className":3375},[],[3377],{"type":46,"value":1709},{"type":46,"value":206},{"type":40,"tag":66,"props":3380,"children":3381},{},[3382,3387,3388],{"type":40,"tag":70,"props":3383,"children":3384},{},[3385],{"type":46,"value":3386},"Verify Unit Test Suite & Type Definitions",{"type":46,"value":863},{"type":40,"tag":117,"props":3389,"children":3390},{},[3391],{"type":40,"tag":66,"props":3392,"children":3393},{},[3394,3396,3402,3403,3409,3411],{"type":46,"value":3395},"If existing unit tests (",{"type":40,"tag":78,"props":3397,"children":3399},{"className":3398},[],[3400],{"type":46,"value":3401},"__tests__\u002F",{"type":46,"value":190},{"type":40,"tag":78,"props":3404,"children":3406},{"className":3405},[],[3407],{"type":46,"value":3408},"test\u002F",{"type":46,"value":3410},") are present in the\nextension:\n",{"type":40,"tag":117,"props":3412,"children":3413},{},[3414,3433,3453],{"type":40,"tag":66,"props":3415,"children":3416},{},[3417,3419,3424,3426,3431],{"type":46,"value":3418},"Ensure ",{"type":40,"tag":78,"props":3420,"children":3422},{"className":3421},[],[3423],{"type":46,"value":1136},{"type":46,"value":3425}," (or the original test framework types) are present\nin ",{"type":40,"tag":78,"props":3427,"children":3429},{"className":3428},[],[3430],{"type":46,"value":1114},{"type":46,"value":3432}," so test files type-check cleanly.",{"type":40,"tag":66,"props":3434,"children":3435},{},[3436,3438,3444,3446,3452],{"type":46,"value":3437},"Update test invocations for upgraded V2 triggers to pass a single\ndestructured event object\n(",{"type":40,"tag":78,"props":3439,"children":3441},{"className":3440},[],[3442],{"type":46,"value":3443},"({ change: mockChange, context: mockContext })",{"type":46,"value":3445}," instead of positional\narguments ",{"type":40,"tag":78,"props":3447,"children":3449},{"className":3448},[],[3450],{"type":46,"value":3451},"(mockChange, mockContext)",{"type":46,"value":278},{"type":40,"tag":66,"props":3454,"children":3455},{},[3456,3458,3464,3466,3472],{"type":46,"value":3457},"Run ",{"type":40,"tag":78,"props":3459,"children":3461},{"className":3460},[],[3462],{"type":46,"value":3463},"npm test",{"type":46,"value":3465}," or type-check test files (",{"type":40,"tag":78,"props":3467,"children":3469},{"className":3468},[],[3470],{"type":46,"value":3471},"npx tsc --noEmit",{"type":46,"value":3473},") to verify\nzero regressions.",{"type":40,"tag":102,"props":3475,"children":3476},{},[],{"type":40,"tag":49,"props":3478,"children":3480},{"id":3479},"references-official-resources",[3481],{"type":46,"value":3482},"References & Official Resources",{"type":40,"tag":117,"props":3484,"children":3485},{},[3486,3503,3537,3553,3568],{"type":40,"tag":66,"props":3487,"children":3488},{},[3489,3494,3495],{"type":40,"tag":70,"props":3490,"children":3491},{},[3492],{"type":46,"value":3493},"Official Google Migration Guide",{"type":46,"value":863},{"type":40,"tag":1887,"props":3496,"children":3500},{"href":3497,"rel":3498},"https:\u002F\u002Ffirebase.google.com\u002Fdocs\u002Fextensions\u002Fpublishers\u002Fmigrate",[3499],"nofollow",[3501],{"type":46,"value":3502},"Prepare Firebase Extensions for migration to Cloud Functions",{"type":40,"tag":66,"props":3504,"children":3505},{},[3506,3511,3512],{"type":40,"tag":70,"props":3507,"children":3508},{},[3509],{"type":46,"value":3510},"Publisher Support Contacts",{"type":46,"value":863},{"type":40,"tag":117,"props":3513,"children":3514},{},[3515,3526],{"type":40,"tag":66,"props":3516,"children":3517},{},[3518,3520],{"type":46,"value":3519},"Support Email: ",{"type":40,"tag":78,"props":3521,"children":3523},{"className":3522},[],[3524],{"type":46,"value":3525},"firebase-extensions-migrator-support-external@google.com",{"type":40,"tag":66,"props":3527,"children":3528},{},[3529,3531],{"type":46,"value":3530},"Support Group Subscription:\n",{"type":40,"tag":78,"props":3532,"children":3534},{"className":3533},[],[3535],{"type":46,"value":3536},"firebase-extensions-migrator-support-external+subscribe@google.com",{"type":40,"tag":66,"props":3538,"children":3539},{},[3540,3545,3547,3551],{"type":40,"tag":70,"props":3541,"children":3542},{},[3543],{"type":46,"value":3544},"Destructuring Shim",{"type":46,"value":3546},": See\n",{"type":40,"tag":1887,"props":3548,"children":3549},{"href":1897},[3550],{"type":46,"value":1900},{"type":46,"value":3552}," for details on event\nproperty translation.",{"type":40,"tag":66,"props":3554,"children":3555},{},[3556,3561,3562,3566],{"type":40,"tag":70,"props":3557,"children":3558},{},[3559],{"type":46,"value":3560},"Trigger Mapping",{"type":46,"value":3546},{"type":40,"tag":1887,"props":3563,"children":3564},{"href":1889},[3565],{"type":46,"value":1892},{"type":46,"value":3567}," for V1 vs V2 trigger\ndefinitions and shim keys.",{"type":40,"tag":66,"props":3569,"children":3570},{},[3571,3576,3577,3583,3585,3591],{"type":40,"tag":70,"props":3572,"children":3573},{},[3574],{"type":46,"value":3575},"Configuration & Parameters",{"type":46,"value":3546},{"type":40,"tag":1887,"props":3578,"children":3580},{"href":3579},"references\u002Fconfiguration-migration.md",[3581],{"type":46,"value":3582},"configuration-migration.md",{"type":46,"value":3584}," for\n",{"type":40,"tag":78,"props":3586,"children":3588},{"className":3587},[],[3589],{"type":46,"value":3590},"runWith",{"type":46,"value":3592}," options, params, and secret bindings.",{"type":40,"tag":3594,"props":3595,"children":3596},"style",{},[3597],{"type":46,"value":3598},"html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"items":3600,"total":1516},[3601,3608,3625,3645,3660,3676,3696,3712,3725,3738,3756,3772],{"slug":4,"name":4,"fn":5,"description":6,"org":3602,"tags":3603,"stars":23,"repoUrl":24,"updatedAt":25},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3604,3605,3606,3607],{"name":19,"slug":20,"type":15},{"name":22,"slug":8,"type":15},{"name":13,"slug":14,"type":15},{"name":17,"slug":17,"type":15},{"slug":3609,"name":3609,"fn":3610,"description":3611,"org":3612,"tags":3613,"stars":23,"repoUrl":24,"updatedAt":3624},"firebase-ai-logic-basics","integrate Firebase AI Logic","Official skill for integrating Firebase AI Logic (Gemini API) into web applications. Covers setup, multimodal inference, structured output, and security.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3614,3617,3618,3621],{"name":3615,"slug":3616,"type":15},"Backend","backend",{"name":22,"slug":8,"type":15},{"name":3619,"slug":3620,"type":15},"Gemini","gemini",{"name":3622,"slug":3623,"type":15},"LLM","llm","2026-07-31T05:53:23.557174",{"slug":3626,"name":3626,"fn":3627,"description":3628,"org":3629,"tags":3630,"stars":23,"repoUrl":24,"updatedAt":3644},"firebase-app-hosting-basics","deploy web apps with Firebase App Hosting","Deploys and manages full-stack web applications (Next.js, Angular) with Server-Side Rendering (SSR) using Firebase App Hosting. Use when deploying Next.js\u002FAngular apps, configuring apphosting.yaml or firebase.json apphosting blocks, managing secrets, setting up GitHub CI\u002FCD, or configuring Blaze billing requirements. Don't use for classic static web hosting, Auth, Firestore, Crashlytics, or Xcode.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3631,3634,3637,3638,3641],{"name":3632,"slug":3633,"type":15},"Angular","angular",{"name":3635,"slug":3636,"type":15},"Deployment","deployment",{"name":22,"slug":8,"type":15},{"name":3639,"slug":3640,"type":15},"Frontend","frontend",{"name":3642,"slug":3643,"type":15},"Next.js","next-js","2026-07-31T05:53:19.57287",{"slug":3646,"name":3646,"fn":3647,"description":3648,"org":3649,"tags":3650,"stars":23,"repoUrl":24,"updatedAt":3659},"firebase-auth-basics","set up Firebase Authentication","Guide for setting up and using Firebase Authentication. Use this skill when the user's app requires user sign-in, user management, or secure data access using auth rules.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3651,3654,3655,3656],{"name":3652,"slug":3653,"type":15},"Auth","auth",{"name":3615,"slug":3616,"type":15},{"name":22,"slug":8,"type":15},{"name":3657,"slug":3658,"type":15},"Security","security","2026-07-31T05:53:20.79137",{"slug":3661,"name":3661,"fn":3662,"description":3663,"org":3664,"tags":3665,"stars":23,"repoUrl":24,"updatedAt":3675},"firebase-basics","build applications with Firebase","Provides foundational Firebase CLI setup, CLI installation, version checks (`firebase-tools@latest --version`), CLI login (including --no-localhost), project creation, project selection (`firebase use`), and app config file downloads (`google-services.json`, `GoogleService-Info.plist`). Use ONLY for CLI login, project creation\u002Fswitching, or downloading app config files. Don't use for Firebase Hosting deploy, Firestore, Auth, App Hosting, Data Connect, Crashlytics, or Remote Config.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3666,3669,3670,3673,3674],{"name":3667,"slug":3668,"type":15},"Authentication","authentication",{"name":3615,"slug":3616,"type":15},{"name":3671,"slug":3672,"type":15},"Database","database",{"name":3635,"slug":3636,"type":15},{"name":22,"slug":8,"type":15},"2026-07-31T05:53:21.570684",{"slug":3677,"name":3677,"fn":3678,"description":3679,"org":3680,"tags":3681,"stars":23,"repoUrl":24,"updatedAt":3695},"firebase-crashlytics","set up and manage Firebase Crashlytics","Comprehensive guide for Firebase Crashlytics, including provisioning and SDK usage. Use this skill when the user needs help setting up Crashlytics, adding crash reporting, or using the Crashlytics SDK in their application.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3682,3685,3686,3689,3692],{"name":3683,"slug":3684,"type":15},"Android","android",{"name":22,"slug":8,"type":15},{"name":3687,"slug":3688,"type":15},"iOS","ios",{"name":3690,"slug":3691,"type":15},"Mobile","mobile",{"name":3693,"slug":3694,"type":15},"Observability","observability","2026-05-01T05:54:14.072678",{"slug":3697,"name":3697,"fn":3698,"description":3699,"org":3700,"tags":3701,"stars":23,"repoUrl":24,"updatedAt":3711},"firebase-data-connect","build backends with Firebase Data Connect","Builds and deploys Firebase SQL Connect (aka Firebase Data Connect) backends with PostgreSQL securely. Use when designing schemas with tables and relations, writing authorized queries and mutations, configuring real-time data updates, or generating type-safe SDKs. Use when you need a relational database with Firebase, or when the user mentions SQL Connect or Data Connect.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3702,3703,3704,3705,3708],{"name":3615,"slug":3616,"type":15},{"name":3671,"slug":3672,"type":15},{"name":22,"slug":8,"type":15},{"name":3706,"slug":3707,"type":15},"GraphQL","graphql",{"name":3709,"slug":3710,"type":15},"PostgreSQL","postgresql","2026-04-06T18:12:07.681031",{"slug":3713,"name":3713,"fn":3714,"description":3715,"org":3716,"tags":3717,"stars":23,"repoUrl":24,"updatedAt":3724},"firebase-firestore","manage and query Cloud Firestore databases","Sets up, manages, queries, and configures Cloud Firestore databases (Standard\u002FEnterprise edition), including data modeling, security rules, indexes, and SDK integrations (Web, Python, iOS, Android, Flutter). Use when creating\u002Flisting Firestore databases, defining data models\u002Findexes, writing SDK queries, or integrating Firestore SDKs. Don't use for Firebase Hosting, Data Connect, Auth, Storage\u002FGCS, Crashlytics, Functions, or BigQuery.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3718,3719,3720,3721],{"name":3615,"slug":3616,"type":15},{"name":3671,"slug":3672,"type":15},{"name":22,"slug":8,"type":15},{"name":3722,"slug":3723,"type":15},"NoSQL","nosql","2026-07-31T05:53:17.562137",{"slug":3726,"name":3726,"fn":3727,"description":3728,"org":3729,"tags":3730,"stars":23,"repoUrl":24,"updatedAt":3737},"firebase-hosting-basics","deploy static apps with Firebase Hosting","Deploys and configures classic Firebase Hosting for static websites, single-page apps (SPAs), and microservices. Use when deploying static sites\u002FSPAs, setting up custom domains, configuring firebase.json hosting settings (redirects, rewrites, headers, multi-site), or managing preview channels. Don't use for Firebase App Hosting (Next.js\u002FSSR), Auth, Firestore queries\u002Frules, Data Connect, or Crashlytics.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3731,3732,3733,3734],{"name":3635,"slug":3636,"type":15},{"name":22,"slug":8,"type":15},{"name":3639,"slug":3640,"type":15},{"name":3735,"slug":3736,"type":15},"Web Development","web-development","2026-07-31T05:53:22.565034",{"slug":3739,"name":3739,"fn":3740,"description":3741,"org":3742,"tags":3743,"stars":23,"repoUrl":24,"updatedAt":3755},"firebase-remote-config-basics","manage Firebase Remote Config and feature flags","Manages Firebase Remote Config templates, feature flags, loading strategies, and SDKs (Android, iOS). Use when downloading\u002Fdeploying remoteconfig JSON templates, managing version history\u002Ffeature flags, setting in-app defaults, fetchAndActivate(), real-time listeners, or SDK setup. Don't use for Firebase Hosting, Auth, Firestore, Data Connect, Crashlytics, or App Hosting.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3744,3747,3750,3751,3752],{"name":3745,"slug":3746,"type":15},"Configuration","configuration",{"name":3748,"slug":3749,"type":15},"Feature Flags","feature-flags",{"name":22,"slug":8,"type":15},{"name":3690,"slug":3691,"type":15},{"name":3753,"slug":3754,"type":15},"SDK","sdk","2026-07-31T05:53:18.552749",{"slug":3757,"name":3757,"fn":3758,"description":3759,"org":3760,"tags":3761,"stars":23,"repoUrl":24,"updatedAt":3771},"firebase-security-rules-auditor","audit Firestore security rules","Audits Firebase (Firestore, Cloud Storage) security rules for vulnerabilities, privilege escalation, role bypasses, create vs update inconsistencies, resource exhaustion, type safety, size limits, and hasOnly ownership checks. Use when auditing\u002Freviewing rules, running red-team rule assessments, or scoring against auditor checklists. Don't use for Firebase CLI (login, deploy), Auth, Crashlytics, Remote Config, or database queries.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3762,3765,3768,3769,3770],{"name":3763,"slug":3764,"type":15},"Audit","audit",{"name":3766,"slug":3767,"type":15},"Compliance","compliance",{"name":3671,"slug":3672,"type":15},{"name":22,"slug":8,"type":15},{"name":3657,"slug":3658,"type":15},"2026-07-31T05:53:16.588011",{"slug":3773,"name":3773,"fn":3774,"description":3775,"org":3776,"tags":3777,"stars":23,"repoUrl":24,"updatedAt":3786},"xcode-project-setup","manage Xcode project dependencies and packages","Safely modifies Xcode projects (.pbxproj) to add Swift Packages and link files. Use this skill whenever an iOS project needs dependencies installed (e.g. Firebase, Alamofire).",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3778,3779,3780,3783],{"name":3687,"slug":3688,"type":15},{"name":3690,"slug":3691,"type":15},{"name":3781,"slug":3782,"type":15},"Swift","swift",{"name":3784,"slug":3785,"type":15},"Xcode","xcode","2026-05-01T05:54:12.834251",{"items":3788,"total":1516},[3789,3796,3803,3811,3818,3826,3834],{"slug":4,"name":4,"fn":5,"description":6,"org":3790,"tags":3791,"stars":23,"repoUrl":24,"updatedAt":25},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3792,3793,3794,3795],{"name":19,"slug":20,"type":15},{"name":22,"slug":8,"type":15},{"name":13,"slug":14,"type":15},{"name":17,"slug":17,"type":15},{"slug":3609,"name":3609,"fn":3610,"description":3611,"org":3797,"tags":3798,"stars":23,"repoUrl":24,"updatedAt":3624},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3799,3800,3801,3802],{"name":3615,"slug":3616,"type":15},{"name":22,"slug":8,"type":15},{"name":3619,"slug":3620,"type":15},{"name":3622,"slug":3623,"type":15},{"slug":3626,"name":3626,"fn":3627,"description":3628,"org":3804,"tags":3805,"stars":23,"repoUrl":24,"updatedAt":3644},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3806,3807,3808,3809,3810],{"name":3632,"slug":3633,"type":15},{"name":3635,"slug":3636,"type":15},{"name":22,"slug":8,"type":15},{"name":3639,"slug":3640,"type":15},{"name":3642,"slug":3643,"type":15},{"slug":3646,"name":3646,"fn":3647,"description":3648,"org":3812,"tags":3813,"stars":23,"repoUrl":24,"updatedAt":3659},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3814,3815,3816,3817],{"name":3652,"slug":3653,"type":15},{"name":3615,"slug":3616,"type":15},{"name":22,"slug":8,"type":15},{"name":3657,"slug":3658,"type":15},{"slug":3661,"name":3661,"fn":3662,"description":3663,"org":3819,"tags":3820,"stars":23,"repoUrl":24,"updatedAt":3675},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3821,3822,3823,3824,3825],{"name":3667,"slug":3668,"type":15},{"name":3615,"slug":3616,"type":15},{"name":3671,"slug":3672,"type":15},{"name":3635,"slug":3636,"type":15},{"name":22,"slug":8,"type":15},{"slug":3677,"name":3677,"fn":3678,"description":3679,"org":3827,"tags":3828,"stars":23,"repoUrl":24,"updatedAt":3695},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3829,3830,3831,3832,3833],{"name":3683,"slug":3684,"type":15},{"name":22,"slug":8,"type":15},{"name":3687,"slug":3688,"type":15},{"name":3690,"slug":3691,"type":15},{"name":3693,"slug":3694,"type":15},{"slug":3697,"name":3697,"fn":3698,"description":3699,"org":3835,"tags":3836,"stars":23,"repoUrl":24,"updatedAt":3711},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3837,3838,3839,3840,3841],{"name":3615,"slug":3616,"type":15},{"name":3671,"slug":3672,"type":15},{"name":22,"slug":8,"type":15},{"name":3706,"slug":3707,"type":15},{"name":3709,"slug":3710,"type":15}]