extension-to-functions-codebase

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Extension to Functions Codebase & npm Package Migration

扩展到Functions代码库与npm包迁移

Overview

概述

This skill guides the agent in migrating a Firebase Extension repository or instance into either:
  1. A standalone Cloud Functions for Firebase codebase (
    firebase-functions
    , for end-user app integration), or
  2. A publishable npm package / shareable open source package (for extension publishers distributing reusable V2 functions).
It leverages native Cloud Functions for Firebase GA capabilities to handle permissions, dependencies, and lifecycle hooks natively in code, and provides instructions for modernizing legacy V1 triggers to V2 using the Destructuring Compatibility Shim.

本技能指导Agent将Firebase扩展仓库或实例迁移至以下两种目标之一:
  1. 独立的Cloud Functions for Firebase代码库(基于
    firebase-functions
    ,用于终端用户应用集成),或
  2. 可发布的npm包/可共享开源包(供扩展发布者分发可复用的V2函数)。
它利用Cloud Functions for Firebase的正式版(GA)功能,在代码中原生处理权限、依赖项和生命周期钩子,并提供使用解构兼容垫片(Destructuring Compatibility Shim)将旧版V1触发器现代化升级到V2的说明。

Triggers

触发条件

Activate this skill when a user asks to:
  • Migrate or convert an installed Firebase Extension into a standalone functions codebase.
  • Convert an extension repository into a publishable npm package (shareable open source package).
  • Upgrade extension triggers from V1 to V2.

当用户提出以下需求时激活本技能:
  • 将已安装的Firebase Extension迁移或转换为独立的Functions代码库。
  • 将扩展仓库转换为可发布的npm包(可共享开源包)。
  • 将扩展触发器从V1升级到V2。

Target Migration Workflows

目标迁移流程

Before starting, determine the target destination with the developer:
  • Target A: Local Functions Codebase (End-User App Integration)
    • Output: Source code placed in the project's
      functions/src/
      folder.
    • Configuration: Parameters defined via
      defineString
      ,
      defineSecret
      , etc. in
      .env
      .
    • Deployment: Deployed directly via
      firebase deploy --only functions
      .
  • Target B: Publishable npm Package / Shareable Open Source Package
    • Output: Reusable npm package containing exported V2 functions.
    • Configuration:
      package.json
      with
      exports
      map and
      firebase-functions
      declared in
      dependencies
      (or
      peerDependencies
      ).
    • Usage: End users install the package (
      npm i <package-name>
      ) and re-export functions in their
      index.ts
      .

开始前,与开发者确认目标迁移方向:
  • 目标A:本地Functions代码库(终端用户应用集成)
    • 输出:源代码放置在项目的
      functions/src/
      目录下。
    • 配置:通过
      .env
      中的
      defineString
      defineSecret
      等定义参数。
    • 部署:直接通过
      firebase deploy --only functions
      命令部署。
  • 目标B:可发布的npm包/可共享开源包
    • 输出:包含导出V2函数的可复用npm包。
    • 配置:
      package.json
      中包含
      exports
      映射,且
      firebase-functions
      声明在
      dependencies
      (或
      peerDependencies
      )中。
    • 使用方式:终端用户安装包(
      npm i <package-name>
      )并在其
      index.ts
      中重新导出函数。

Getting Started & Git Safety

入门指南与Git安全规范

  1. Git Status: Verify the workspace has a clean git status before starting.
  2. In-Place Copying: If copying code to a new subdirectory within the same repository:
    • Use
      git cp
      (or copy files and commit) to copy the extension's source directory to the target directory.
    • Commit immediately:
      "Copying [extension-name] extension to [directory] in preparation for rewrite"

  1. Git状态检查:开始前确认工作区的Git状态为干净状态。
  2. 原地复制:如果要将代码复制到同一仓库内的新子目录:
    • 使用
      git cp
      (或复制文件后提交)将扩展的源码目录复制到目标目录。
    • 立即提交:
      "Copying [extension-name] extension to [directory] in preparation for rewrite"

Rules and Constraints

规则与约束

1. Zero-Local-Overhead (Cloud Functions Integration)

1. 零本地开销(Cloud Functions集成)

Assume Cloud Functions for Firebase Workload Identities, Declarative Security, and SDK Lifecycle Hooks are fully GA.
  • Do NOT output instructions or scripts telling users to run manual
    gcloud
    IAM commands or create service accounts.
  • Do NOT write code comments instructing users to manually enable Google APIs in the cloud console.
  • Instead, use declarative
    requiresAPI
    and
    requiresRole
    imports from the SDK.
假设Cloud Functions for Firebase的工作负载身份、声明式安全和SDK生命周期钩子均已正式发布(GA)。
  • 请勿输出指导用户手动执行
    gcloud
    IAM命令或创建服务账号的说明或脚本。
  • 请勿编写代码注释指导用户在云控制台中手动启用Google API。
  • 取而代之,使用SDK中的
    requiresAPI
    requiresRole
    导入声明。

2. Global Parameter Access Restriction

2. 全局参数访问限制

  • Never call
    .value()
    on any parameter at global scope.
  • If a global variable or class instance is initialized using a parameter value, declare the variable globally and initialize it inside the
    onInit()
    callback:
    typescript
    import { defineString } from "firebase-functions/params";
    import { onInit } from "firebase-functions/v2";
    
    const bqDataset = defineString("DATASET_ID");
    let bqClient: BigQuery;
    
    onInit(() => {
      bqClient = new BigQuery({ datasetId: bqDataset.value() });
    });
  • 绝对不要在全局作用域调用参数的
    .value()
    方法
  • 如果全局变量或类实例需要使用参数值初始化,请在全局声明变量并在
    onInit()
    回调中完成初始化:
    typescript
    import { defineString } from "firebase-functions/params";
    import { onInit } from "firebase-functions/v2";
    
    const bqDataset = defineString("DATASET_ID");
    let bqClient: BigQuery;
    
    onInit(() => {
      bqClient = new BigQuery({ datasetId: bqDataset.value() });
    });

3. Concurrency & Cost Parity for V2

3. V2触发器的并发与成本一致性

When upgrading triggers to V2:
  • By default, V2 functions enable concurrency (up to 80 requests per instance).
  • If you want to maintain V1 fractional CPU pricing (and disable concurrency), set
    cpu: "gcf_gen1"
    in the function's options object.

升级触发器到V2时:
  • 默认情况下,V2函数启用并发(每个实例最多处理80个请求)。
  • 如果希望保持V1的 fractional CPU定价(并禁用并发),请在函数的配置对象中设置
    cpu: "gcf_gen1"

Step-by-Step Migration Execution

分步迁移执行流程

Step 1: Inventory the Extension

步骤1:盘点扩展内容

Conduct a complete inventory of everything the extension declares, ships, and documents so that nothing is lost during migration:
  1. Inventory
    extension.yaml
    :
    • params
      : Convert to Functions params (
      defineString
      ,
      defineSecret
      , etc.).
    • apis
      : Convert to
      requiresAPI(...)
      declarations.
    • roles
      : Convert to
      requiresRole(...)
      declarations.
    • lifecycleEvents
      (
      onInstall
      ,
      onUpdate
      ,
      onConfigure
      ): Convert to
      afterFirstDeploy
      and
      afterRedeploy
      hooks.
    • resources
      : Note all function triggers to convert from 1st gen (
      firebase-functions/v1
      ) to 2nd gen (
      firebase-functions/v2
      ), including standard event triggers, HTTP handlers, and task queues (
      onTaskDispatched
      ).
  2. Inventory Files & Tooling:
    • functions/
      : Source code, triggers, helpers, and task queue handlers.
    • Documentation:
      README.md
      ,
      PREINSTALL.md
      , and
      POSTINSTALL.md
      .
    • scripts/
      : Note any backfill, import, or helper scripts shipped with the extension.
全面盘点扩展声明、交付和文档的所有内容,确保迁移过程中无内容丢失:
  1. 盘点
    extension.yaml
    • params
      :转换为Functions参数(
      defineString
      defineSecret
      等)。
    • apis
      :转换为
      requiresAPI(...)
      声明。
    • roles
      :转换为
      requiresRole(...)
      声明。
    • lifecycleEvents
      onInstall
      onUpdate
      onConfigure
      ):转换为
      afterFirstDeploy
      afterRedeploy
      钩子。
    • resources
      :记录所有需要从第一代(
      firebase-functions/v1
      )转换为第二代(
      firebase-functions/v2
      )的函数触发器,包括标准事件触发器、HTTP处理器和任务队列(
      onTaskDispatched
      )。
  2. 盘点文件与工具
    • functions/
      :源码、触发器、辅助工具和任务队列处理器。
    • 文档:
      README.md
      PREINSTALL.md
      POSTINSTALL.md
    • scripts/
      :记录扩展附带的任何回填、导入或辅助脚本。

Step 2: Create / Update
package.json

步骤2:创建/更新
package.json

Create an npm package for the migrated extension code (either at project root or in a dedicated workspace directory):
  • Set a publishable package name (
    name: "<package-name>"
    ).
  • Preserve Dev & Test Dependencies: Preserve all existing
    devDependencies
    , test runners (
    jest
    ,
    ts-jest
    ,
    @types/jest
    ,
    mocha
    ,
    @types/mocha
    ), and test scripts (
    "test": "..."
    ) from the legacy extension (
    functions/package.json
    or root
    package.json
    ). Do not drop test frameworks or type definitions.
  • Declare
    firebase-functions
    (e.g.
    ^7.0.0
    ) in
    dependencies
    (or
    peerDependencies
    if creating a lightweight middleware package where the root consumer manages the runtime version):
    json
    {
      "name": "<package-name>",
      "version": "1.0.0",
      "main": "lib/index.js",
      "types": "lib/index.d.ts",
      "exports": {
        ".": {
          "types": "./lib/index.d.ts",
          "default": "./lib/index.js"
        }
      },
      "engines": {
        "node": ">=22"
      },
      "dependencies": {
        "firebase-admin": "^12.0.0",
        "firebase-functions": "^7.0.0"
      }
    }
为迁移后的扩展代码创建npm包(位于项目根目录或专用工作区目录):
  • 设置可发布的包名(
    name: "<package-name>"
    )。
  • 保留开发与测试依赖:保留旧版扩展(
    functions/package.json
    或根目录
    package.json
    )中所有现有的
    devDependencies
    、测试运行器(
    jest
    ts-jest
    @types/jest
    mocha
    @types/mocha
    )和测试脚本(
    "test": "..."
    )。请勿丢弃测试框架或类型定义。
  • dependencies
    (如果创建轻量级中间件包且由根消费者管理运行时版本,则声明在
    peerDependencies
    )中声明
    firebase-functions
    (例如
    ^7.0.0
    ):
    json
    {
      "name": "<package-name>",
      "version": "1.0.0",
      "main": "lib/index.js",
      "types": "lib/index.d.ts",
      "exports": {
        ".": {
          "types": "./lib/index.d.ts",
          "default": "./lib/index.js"
        }
      },
      "engines": {
        "node": ">=22"
      },
      "dependencies": {
        "firebase-admin": "^12.0.0",
        "firebase-functions": "^7.0.0"
      }
    }

Step 3: Move Function Code & Expose Deployable Functions

步骤3:迁移函数代码并暴露可部署函数

Move the extension's function source into the package's
src/
folder:
  1. Keep normal Firebase trigger exports. The package must expose deployable functions that end users can re-export from their entrypoint (
    index.ts
    ).
  2. Document that consumers must deploy packaged functions by re-exporting them:
    typescript
    export * from "<package-name>";
    // Or named exports:
    // export { syncV2, initBigQuerySync } from "<package-name>";
    Note: A bare import (
    import "<package-name>"
    ) is not enough. The Firebase CLI only deploys functions exported from the user's root entry file.
将扩展的函数源码迁移到包的
src/
目录:
  1. 保留常规Firebase触发器导出。包必须暴露可部署的函数,以便终端用户可以从其入口文件(
    index.ts
    )重新导出。
  2. 文档说明消费者必须通过重新导出的方式部署打包后的函数:
    typescript
    export * from "<package-name>";
    // 或命名导出:
    // export { syncV2, initBigQuerySync } from "<package-name>";
    注意:仅导入(
    import "<package-name>"
    )是不够的。Firebase CLI仅部署从用户根入口文件导出的函数。

Step 4: Upgrade Functions from 1st Gen to 2nd Gen

步骤4:将函数从第一代升级到第二代

Convert each exported 1st gen function trigger (
onWrite
,
onRequest
,
tasks.taskQueue().onDispatch
) to its 2nd gen equivalent (
onDocumentWritten
,
onRequest
,
onTaskDispatched
from
firebase-functions/v2/...
):
  1. Signatures & Destructuring Shim: Use the Destructuring Compatibility Shim (
    { shimmedKey, context }
    ) to preserve V1 business logic without rewriting function bodies. See signature-mapping.md and destructuring-shim.md.
  2. Authentication Triggers Exception: If your extension uses v1 Authentication Triggers (
    auth.user().onCreate()
    ,
    auth.user().onDelete()
    ), instruct the agent to check live whether a 2nd gen alternative exists in the installed
    firebase-functions
    package or live documentation. If 2nd gen Auth triggers are not yet supported for those events, warn the user clearly and halt or refuse the migration for those specific triggers until a V2 alternative becomes available.
将每个导出的第一代函数触发器(
onWrite
onRequest
tasks.taskQueue().onDispatch
)转换为对应的第二代触发器(来自
firebase-functions/v2/...
onDocumentWritten
onRequest
onTaskDispatched
):
  1. 签名与解构垫片:使用解构兼容垫片(
    { shimmedKey, context }
    )保留V1业务逻辑,无需重写函数体。请参阅signature-mapping.mddestructuring-shim.md
  2. 身份验证触发器例外:如果扩展使用V1身份验证触发器(
    auth.user().onCreate()
    auth.user().onDelete()
    ),请指导Agent检查已安装的
    firebase-functions
    包或在线文档中是否存在第二代替代方案。如果这些事件的第二代Auth触发器尚未支持,请明确警告用户,并暂停或拒绝这些特定触发器的迁移,直到V2替代方案可用。

Step 5: Replace Extension Params with Functions Params

步骤5:将扩展参数替换为Functions参数

Each parameter in
extension.yaml
becomes a Parameterized Configuration call:
  1. Map parameter primitives and attributes:
    • Type
      string
      ->
      defineString("PARAM_NAME", { label: "...", description: "...", default: "..." })
    • Type
      secret
      ->
      defineSecret("PARAM_NAME")
    • Type
      int
      ->
      defineInt("PARAM_NAME", { label: "...", default: 123 })
    • Type
      boolean
      ->
      defineBoolean("PARAM_NAME", { default: true })
    • Type
      select
      /
      multiSelect
      -> map
      options
      into
      input
      :
      defineString("PARAM_NAME", { input: { select: { options: [{ value: "val", label: "Val" }] } } })
    • validationRegex
      -> map into text input options:
      defineString("PARAM_NAME", { input: { text: { validationRegex: "^[a-z]+$" } } })
    • required: true
      / Non-empty validation -> map
      nonEmpty: true
      into input options:
      defineString("PARAM_NAME", { input: { text: { nonEmpty: true } } })
  2. Read parameter values inside handlers using
    paramName.value()
    .
  3. Keep Exact Parameter Names: Never change parameter names (
    COLLECTION_PATH
    ,
    DATASET_ID
    , etc.) so that existing values carry over seamlessly in
    .env
    .
extension.yaml
中的每个参数都转换为参数化配置调用:
  1. 映射参数类型和属性:
    • 类型
      string
      ->
      defineString("PARAM_NAME", { label: "...", description: "...", default: "..." })
    • 类型
      secret
      ->
      defineSecret("PARAM_NAME")
    • 类型
      int
      ->
      defineInt("PARAM_NAME", { label: "...", default: 123 })
    • 类型
      boolean
      ->
      defineBoolean("PARAM_NAME", { default: true })
    • 类型
      select
      /
      multiSelect
      -> 将
      options
      映射到
      input
      defineString("PARAM_NAME", { input: { select: { options: [{ value: "val", label: "Val" }] } } })
    • validationRegex
      -> 映射到文本输入选项:
      defineString("PARAM_NAME", { input: { text: { validationRegex: "^[a-z]+$" } } })
    • required: true
      / 非空验证 -> 将
      nonEmpty: true
      映射到输入选项:
      defineString("PARAM_NAME", { input: { text: { nonEmpty: true } } })
  2. 在处理器内部使用
    paramName.value()
    读取参数值。
  3. 保留确切参数名称:永远不要更改参数名称(如
    COLLECTION_PATH
    DATASET_ID
    等),以便现有值可以在
    .env
    中无缝迁移。

Step 6: Migrate Internal Task Queue Calls (
queue.enqueue(...)
)

步骤6:迁移内部任务队列调用(
queue.enqueue(...)

If your extension code enqueues tasks onto its own queue using the Admin SDK (
getFunctions().taskQueue(...)
):
  • Under the Extensions runtime, the Admin SDK resolved queues by function name plus
    process.env.EXT_INSTANCE_ID
    .
  • In an npm package / regular codebase: Remove the second argument (
    EXT_INSTANCE_ID
    ) entirely. The Admin SDK automatically targets the current codebase:
    typescript
    // Before (extension runtime):
    // const queue = getFunctions().taskQueue(`locations/${region}/functions/syncBigQuery`, process.env.EXT_INSTANCE_ID);
    
    // After (npm package):
    const queue = getFunctions().taskQueue(`locations/${region}/functions/syncBigQuery`);
    await queue.enqueue(taskData);
如果扩展代码使用Admin SDK(
getFunctions().taskQueue(...)
)将任务加入自身队列:
  • 在Extensions运行时中,Admin SDK通过函数名称加上
    process.env.EXT_INSTANCE_ID
    解析队列。
  • 在npm包/常规代码库中:完全移除第二个参数(
    EXT_INSTANCE_ID
    )。Admin SDK会自动定位当前代码库:
    typescript
    // 之前(扩展运行时):
    // const queue = getFunctions().taskQueue(`locations/${region}/functions/syncBigQuery`, process.env.EXT_INSTANCE_ID);
    
    // 之后(npm包):
    const queue = getFunctions().taskQueue(`locations/${region}/functions/syncBigQuery`);
    await queue.enqueue(taskData);

Step 7: Migrate Secrets

步骤7:迁移密钥

For parameters declared with
type: secret
:
  1. Declare the secret explicitly:
    typescript
    import { defineSecret } from "firebase-functions/params";
    const apiKey = defineSecret("API_KEY");
  2. Bind the secret in the trigger options:
    typescript
    export const fn = onRequest({ secrets: [apiKey] }, handler);
  3. Keep exact secret names unchanged so existing Secret Manager bindings work.
对于声明为
type: secret
的参数:
  1. 显式声明密钥:
    typescript
    import { defineSecret } from "firebase-functions/params";
    const apiKey = defineSecret("API_KEY");
  2. 在触发器配置中绑定密钥:
    typescript
    export const fn = onRequest({ secrets: [apiKey] }, handler);
  3. 保留确切的密钥名称不变,以便现有的Secret Manager绑定继续生效。

Step 8: Declare Required APIs and IAM Roles

步骤8:声明所需API和IAM角色

Replace
apis
and
roles
from
extension.yaml
with declarative code in your entry file:
typescript
import { requiresAPI, requiresRole } from "firebase-functions";

requiresAPI("bigquery.googleapis.com", "Needed to write changelog rows");
requiresRole("roles/bigquery.dataEditor");
requiresRole("roles/bigquery.user");
At deploy time, the Firebase CLI automatically grants these roles to the managed runtime service account and enables the required APIs.
extension.yaml
中的
apis
roles
替换为入口文件中的声明式代码:
typescript
import { requiresAPI, requiresRole } from "firebase-functions";

requiresAPI("bigquery.googleapis.com", "Needed to write changelog rows");
requiresRole("roles/bigquery.dataEditor");
requiresRole("roles/bigquery.user");
在部署时,Firebase CLI会自动将这些角色授予托管运行时服务账号,并启用所需的API。

Step 9: Convert Lifecycle Hooks (
afterFirstDeploy
&
afterRedeploy
)

步骤9:转换生命周期钩子(
afterFirstDeploy
&
afterRedeploy

Replace
lifecycleEvents
(
onInstall
,
onUpdate
,
onConfigure
) with SDK lifecycle hooks:
  1. Convert task queue handlers (
    initBigQuerySync
    ,
    setupBigQuerySync
    ) to V2
    onTaskDispatched
    from
    firebase-functions/v2/tasks
    (removing legacy
    getExtensions().runtime().setProcessingState(...)
    calls).
  2. Register lifecycle hooks in code:
    typescript
    import { afterFirstDeploy, afterRedeploy } from "firebase-functions/v2";
    
    // Replaces onInstall:
    afterFirstDeploy({
      task: {
        function: "runInitialSetup",
        body: {}
      }
    });
    
    // Replaces onUpdate & onConfigure:
    afterRedeploy({
      task: {
        function: "runInitialSetup",
        body: { reconcile: true }
      }
    });
  3. Ensure handlers are idempotent and document manual rerun commands:
    bash
    firebase functions:lifecycle:run afterFirstDeploy CODEBASE_NAME
    firebase functions:lifecycle:run afterRedeploy CODEBASE_NAME
lifecycleEvents
onInstall
onUpdate
onConfigure
)替换为SDK生命周期钩子:
  1. 将任务队列处理器(
    initBigQuerySync
    setupBigQuerySync
    )转换为V2的
    onTaskDispatched
    (来自
    firebase-functions/v2/tasks
    ),移除旧版的
    getExtensions().runtime().setProcessingState(...)
    调用。
  2. 在代码中注册生命周期钩子:
    typescript
    import { afterFirstDeploy, afterRedeploy } from "firebase-functions/v2";
    
    // 替代onInstall:
    afterFirstDeploy({
      task: {
        function: "runInitialSetup",
        body: {}
      }
    });
    
    // 替代onUpdate & onConfigure:
    afterRedeploy({
      task: {
        function: "runInitialSetup",
        body: { reconcile: true }
      }
    });
  3. 确保处理器是幂等的,并记录手动重新运行的命令:
    bash
    firebase functions:lifecycle:run afterFirstDeploy CODEBASE_NAME
    firebase functions:lifecycle:run afterRedeploy CODEBASE_NAME

Step 10: Document Setup for Your Users (
README.md
)

步骤10:为用户编写设置文档(
README.md

Preserve whatever documentation, secrets, and setup instructions the original extension already documented in
README.md
(and
PREINSTALL.md
/
POSTINSTALL.md
), updating them as needed:
  1. Update Configuration References: Replace instructions referencing legacy
    extension.yaml
    installation prompts or
    ext-*.env
    files with standard
    .env
    Parameterized Configuration setup matching the
    defineString
    parameters.
  2. Include Re-export Snippet: Ensure the basic root re-export snippet is shown (
    export * from "<package-name>";
    ) so users know how to expose the functions in their root
    index.ts
    .
  3. Avoid Unnecessary Boilerplate: Do not generate redundant comparison tables or generic installation steps if the setup is self-evident in the code or already covered by existing README sections.
保留原始扩展已在
README.md
(以及
PREINSTALL.md
/
POSTINSTALL.md
)中记录的所有文档、密钥和设置说明,并按需更新:
  1. 更新配置引用:将引用旧版
    extension.yaml
    安装提示或
    ext-*.env
    文件的说明替换为与
    defineString
    参数匹配的标准
    .env
    参数化配置设置。
  2. 包含重新导出代码片段:确保展示基本的根重新导出代码片段(
    export * from "<package-name>";
    ),以便用户知道如何在其根
    index.ts
    中暴露函数。
  3. 避免不必要的模板内容:如果设置在代码中自明或已在现有README章节中涵盖,请不要生成冗余的对比表格或通用安装步骤。

Step 11: Build & Test Verification

步骤11:构建与测试验证

  1. Verify Source Compilation: Run
    npm run build
    (
    tsc
    ) to ensure no TypeScript compilation errors in
    src/
    .
  2. Verify Unit Test Suite & Type Definitions:
    • If existing unit tests (
      __tests__/
      ,
      test/
      ) are present in the extension:
      • Ensure
        @types/jest
        (or the original test framework types) are present in
        devDependencies
        so test files type-check cleanly.
      • Update test invocations for upgraded V2 triggers to pass a single destructured event object (
        ({ change: mockChange, context: mockContext })
        instead of positional arguments
        (mockChange, mockContext)
        ).
      • Run
        npm test
        or type-check test files (
        npx tsc --noEmit
        ) to verify zero regressions.

  1. 验证源码编译:运行
    npm run build
    tsc
    )确保
    src/
    目录中无TypeScript编译错误。
  2. 验证单元测试套件与类型定义
    • 如果扩展中存在现有单元测试(
      __tests__/
      test/
      ):
      • 确保
        @types/jest
        (或原始测试框架类型)存在于
        devDependencies
        中,以便测试文件可以干净地进行类型检查。
      • 更新升级后的V2触发器的测试调用,传递单个解构的事件对象(
        ({ change: mockChange, context: mockContext })
        而非位置参数
        (mockChange, mockContext)
        )。
      • 运行
        npm test
        或对测试文件进行类型检查(
        npx tsc --noEmit
        )以验证无回归问题。

References & Official Resources

参考资料与官方资源

  • Official Google Migration Guide: Prepare Firebase Extensions for migration to Cloud Functions
  • Publisher Support Contacts:
    • Support Email:
      firebase-extensions-migrator-support-external@google.com
    • Support Group Subscription:
      firebase-extensions-migrator-support-external+subscribe@google.com
  • Destructuring Shim: See destructuring-shim.md for details on event property translation.
  • Trigger Mapping: See signature-mapping.md for V1 vs V2 trigger definitions and shim keys.
  • Configuration & Parameters: See configuration-migration.md for
    runWith
    options, params, and secret bindings.
  • 官方Google迁移指南: Prepare Firebase Extensions for migration to Cloud Functions
  • 发布者支持联系方式:
    • 支持邮箱:
      firebase-extensions-migrator-support-external@google.com
    • 支持组订阅:
      firebase-extensions-migrator-support-external+subscribe@google.com
  • 解构垫片: 详情请参阅 destructuring-shim.md中的事件属性转换说明。
  • 触发器映射: 详情请参阅 signature-mapping.md中的V1与V2触发器定义及垫片键。
  • 配置与参数: 详情请参阅 configuration-migration.md中的
    runWith
    选项、参数和密钥绑定说明。