Firebase Extensions'ı Cloud Functions'a taşıma

Bu kılavuzda, uzantılarınızı desteği sonlandırılan Firebase Extensions ortamından, kullanıcılarınızın kendi Firebase (2. nesil) kod tabanı için Cloud Functions ortamlarına yükleyip dağıttığı bir işleve nasıl taşıyacağınız gösterilmektedir.

Bu, önerilen taşıma yoludur. Firebase, resmi npm eşdeğerleri olan uzantıların bir listesini tutar. Bu kılavuzda, kendi uzantınızı nasıl oluşturacağınız açıklanmaktadır.

Bu kılavuzda, Stream Cloud Firestore to BigQuery uzantısı (firestore-bigquery-export) örnek olarak kullanılmıştır. Her bölüm, ilgili uzantının taşıma işleminden önceki ve sonraki (@firebase-function-kits/firestore-bigquery-export paketi olarak) görünümünü gösteren bir Uygulamalı örnek ile biter.

Uzantıları taşıma hakkında daha fazla bilgi ve yardım almak için kaydolun

Firebase Extensions sürümünden geçişle ilgili sorularınız varsa firebase-extensions-migrator-support-external@google.com adresinden bize ulaşabilirsiniz. Ayrıca 2. nesil işlevlerinizi paketleme, test etme ve dağıtma hakkında daha fazla bilgi ekleyerek kılavuzu güncellediğimizde bu gruba e-posta göndereceğiz.

Bu gruba katılmak için firebase-extensions-migrator-support-external+subscribe@google.com adresine mesaj gönderin. Bu adresten üyelik isteği e-postası gönderilir. Bu e-postayı yanıtlamanız gerekir. "Bu Gruba Katıl" düğmesini tıklamayın.

Başlamadan önce

Bu taşıma işlemini yazılı olarak tamamlamak için Cloud Functions ürününün aşağıdaki özelliklerini kullanacaksınız:

  • Parameterized Configuration. extension.yaml içinde tanımladığınız her parametre, paket kodunuzda tanımlı bir parametre haline gelir.

  • Bildirim temelli IAM rolleri ve gerekli API'ler. extension.yaml içinde tanımladığınız her rol bir requiresRole(...) çağrısı, her API ise paket kodunuzda bir requiresAPI(...) çağrısı olur. Dağıtım sırasında Firebase KSA'sı, belirtilen rolleri yönetilen bir çalışma zamanı hizmet hesabına verir ve belirtilen API'leri sizin adınıza etkinleştirir.

  • Cloud Functions kod tabanları için yaşam döngüsü olayları. Cloud Functions kod tabanları artık Firebase Extensions ile benzer yaşam döngüsü olaylarını destekliyor. Yükleme ve güncelleme zamanı kurulumunu afterFirstDeploy(...) ve afterRedeploy(...) yaşam döngüsü kancalarıyla bildirin. Bunlar, extension.yaml içinde beyan ettiğiniz lifecycleEvents değerinin yerini alır.

Firebase Extensions kaynağını 2. nesil bir işleve taşıma

(İsteğe bağlı) Firebase Agent Skill ile otomatik taşıma

Resmi extension-to-functions-codebase yapay zeka temsilcisi becerisini kullanarak 1 ile 8 arasındaki adımları (kaynakları envantere ekleme, yükseltmeleri tetikleme, parametre ve gizli anahtar dönüşümleri, açıklayıcı IAM, yaşam döngüsü kancaları ve paketin README dosyasını oluşturma) otomatikleştirebilirsiniz.

Beceriyi yükleme

Siz veya yapay zeka kod yazma asistanınız (Firebase'da Gemini, Cursor, Claude Code, GitHub Copilot) beceriyi henüz yüklemediyseniz beceri CLI'ını kullanarak aşağıdaki komutu çalıştırın:

npx skills add firebase/agent-skills --skill extension-to-functions-codebase

Beceri projenize yüklendikten sonra yapay zeka kod yazma asistanınız, taşıma kurallarını ve dönüşüm adımlarını otomatik olarak uygular. Şu istemi kullanabilirsiniz:

"Lütfen extension-to-functions-codebase becerisindeki talimatları uygulayarak bu Firebase Extensions'ı yayınlanabilir bir 2. nesil Functions kiti paketine taşıyın."

1. Uzantıyı envantere ekleme

Uzantınızın envanterini çıkararak başlayın: Uzantının bildirdiği, gönderdiği ve belgelediği her şeyin tam listesi. Böylece her davranışın 2. nesil işlevde tanımlanmış bir hedefi olur ve taşıma sırasında hiçbir şey kaybolmaz.

Aşağıdakilerin her birini inceleyin ve bulduklarınızı not edin:

  • Parametrelerinizi, işlevlerinizi, etkinliklerinizi, IAM rollerinizi, gerekli API'lerinizi, gizli anahtarlarınızı ve yaşam döngüsü kancalarınızı tanımlayan extension.yaml.

  • functions/. Bu dizinde işlev kodunuz, bağımlılıklarınız, derleme yapılandırmanız, tetikleyicileriniz ve görev sırası işlevleriniz bulunur.

  • README.md, PREINSTALL.md ve POSTINSTALL.md.

  • scripts/: İçe aktarma, dolgu, IAM, onarım veya taşıma yardımcı programlarının yanı sıra uzantıyla birlikte gönderdiğiniz diğer araçları içerir.

Ardından, extension.yaml içindeki her öğenin npm paketinde nereye gideceğine karar verin:

  • Kullanıcı yapılandırmasını Cloud Functions parametrelerine dönüştürün (4. adım).

  • Gizli anahtarları Cloud Functions gizli anahtarlarına dönüştürün (4. adım).

  • IAM rollerini requiresRole(...) beyanlarına dönüştürün (6. adım).

  • Gerekli Google API'lerini uygun yerlerde requiresAPI(...) beyanlarına dönüştürün (6. adım).

  • Yükleme ve güncelleme kancalarını afterFirstDeploy(...) ve afterRedeploy(...) beyanlarına dönüştürün (7. adım).

  • Örnek kimliklerini EXT_INSTANCE_ID biçiminden FIREBASE_KIT_INSTANCE_ID biçimine dönüştürün (4. adım).

Örnek: Cloud Firestore'ten BigQuery'e akış

firestore-bigquery-export/extension.yaml ve functions/ okunurken şu envanter oluşturulur:

extension.yaml içinde Sayı/değer Nereye gider?
params 25 (COLLECTION_PATH, DATASET_ID, TABLE_ID, DATASET_LOCATION, VIEW_TYPE, …) Cloud Functions parametreleri (4. adım)
apis bigquery.googleapis.com requiresAPI(...) (6. adım)
roles bigquery.dataEditor, datastore.user, bigquery.user requiresRole(...) (6. adım)
resources 1 etkinlik tetikleyici (fsexportbigquery) + görev sırası işlevleri (initBigQuerySync, setupBigQuerySync) Dışa aktarılan paket işlevleri (3. adım)
lifecycleEvents onInstall → initBigQuerySync; onUpdate / onConfigure → setupBigQuerySync afterFirstDeploy/afterRedeploy (7. adım)
Örnek Kimliği Kullanılmıyor (EXT_INSTANCE_ID okuma yok) Taşınacak öğe yok
scripts/ import/ (dolgu), gen-schema-view/ Komut dosyası olarak tutulur (burada kapsam dışıdır)

Analiz. Uzantı, type: secret parametresi beyan etmediği için 4. adımda gizli anahtarlar için taşınacak bir şey yoktur. Etkinlik tetikleyici zaten 2. nesildir. Yalnızca görev sırası işlevleri hâlâ 1. nesildir (3. adımda geçerlidir).

2. package.json dosyasını güncelleme

Uzantınızın package.json dosyasını güncelleyin. Bir uzantıyı taşıyorsanız bu, kök package.json olabilir. Tek bir depoda çok sayıda uzantıyı taşıyorsanız her uzantıya kendi paketini verin.

Minimum SDK sürümleri: Bağımlılık olarak firebase-functions >= 7.4.0 ve firebase-admin >= 14.2.0'yi tanımlayın. firebase-functions sürümünüzü eş bağımlılık olarak da beyan edin. Böylece kullanıcılarınızın Cloud Functions projesinde, kitaplığınızın yazıldığı SDK sürümü kullanılır.

{
  "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"
  },
  "peerDependencies": {
    "firebase-functions": "^7.4.0"
  },
  "dependencies": {
    "firebase-functions": "^7.4.0",
    "firebase-admin": "^14.2.0"
  }
}

Örnek: Cloud Firestore'den BigQuery'e akış

Önce. Uzantının functions/package.json dosyası gizlidir, uzantı kimliğini adlandırır ve firebase-functions öğesini doğrudan bağımlılık olarak bildirir:

{
  "name": "firestore-bigquery-export",
  "main": "lib/index.js",
  "private": true,
  "dependencies": {
    "@firebaseextensions/firestore-bigquery-change-tracker": "^2.0.4",
    "firebase-admin": "^14.2.0",
    "firebase-functions": "^6.3.2"
  }
}

Sonra. Yayınlanabilir bir paket: kapsamlı ad, exports eşlemesi ve firebase-functions, peerDependencies konumuna taşındı:

{
  "name": "@firebase-function-kits/firestore-bigquery-export",
  "version": "0.1.0",
  "main": "lib/index.js",
  "types": "lib/index.d.ts",
  "exports": {
    ".": {
      "types": "./lib/index.d.ts",
      "default": "./lib/index.js"
    }
  },
  "engines": {
    "node": "22"
  },
  "peerDependencies": {
    "firebase-functions": "^7.4.0"
  },
  "dependencies": {
    "@firebaseextensions/firestore-bigquery-change-tracker": "^2.0.4",
    "firebase-admin": "^14.2.0",
    "firebase-functions": "^7.4.0"
  }
}

3. İşlevleri 1. nesilden 2. nesle yükseltme

Uzantınız hâlâ 1. nesil işlevleri dışa aktarıyorsa her tetikleyiciyi 2. nesil eşdeğerine dönüştürün. firebase-functions/... modüllerinden içe aktarın ve tetikleyici seçeneklerinde çalışma zamanı ayarlarını iletin.

Cloud Functions 2. nesil yükseltme kılavuzuna bakın. Özellikle, 2. nesil yamalı etkinlik yapı sökümünü kullanarak yeniden yazma çalışmalarını en aza indirebilir ve işlev mantığınızı yeniden yazmaktan kaçınabilirsiniz. Bunun nedeni, 2. nesil SDK'nın v1 parametrelerini etkinlik nesnesinde alanlar olarak göstermesi, yapı sökümü yapılmış/adlandırılmış parametreleri kullanmanıza ve iş mantığınızı değiştirmeden korumanıza olanak tanımasıdır.

Önce. 1. nesil:

import * as functions from "firebase-functions/v1";

export const sync = functions.firestore
  .document("{collectionId}/{documentId}")
  .onWrite(async (change, context) => {
    await handleWrite(change.before, change.after, context.params);
  });

Sonra. 2. nesil:

import { onDocumentWritten } from "firebase-functions/firestore";

export const syncV2 = onDocumentWritten(
  { document: "{collectionId}/{documentId}" },
  async ({ change, context }) =>
    await handleWrite(change.before, change.after, context.params)
);

1. nesil ve 2. nesil işlevler arasındaki farkların kapsamlı bir listesi için Cloud Functions sürüm karşılaştırmasına bakın.

1. ve 2. nesil işlevler arasındaki önemli bir fark, 2. nesil işlevlerin tetikleyici kaynaklarıyla aynı yerde bulunması gerektiğidir. Kullanıcılar, 1. nesil işlevleri kullanan bir uzantıdan 2. nesil işlevleri kullanan bir kite geçiş yaptığında bu koşulu karşılamak için işlev konumlarını değiştirmeleri gerekebilir.

Mevcut konum korunduğundan, kullanıcılarınızın seçtiği Cloud Functions konumları taşıma işlemi sırasında bozulabilir. Uzantınızın etkinlikle tetiklenen işlevleri, kullanıcı tarafından sağlanan işlev konumuna bağlıysa uzantınıza yeni bir parametre ekleyerek etkinlik tetikleme konumunu toplamanızı ve bunu yeni işlev konumuna eşlemenizi öneririz.

Örnek: Cloud Firestore'ten BigQuery'e akış

defineString("DATABASE_REGION", {
  label: "Firestore Instance Location",
  description:
    "Where is the Firestore database located? You can check your current database location at https://console.cloud.google.com/firestore/databases. The functions in this kit deploy to the Cloud Run region closest to this location.",
  input: select({
    "Multi-region (Europe - Belgium and Netherlands)": "eur3",
    "Multi-region (United States)": "nam5",
    "Multi-region (Iowa, North Virginia, and Oklahoma)": "nam7",
    "Iowa (us-central1)": "us-central1",
    // More locations...
  })
});

// Firestore multi-region locations are not Cloud Run regions; deploying a
// function to one hard-fails, so they map to a region inside the multi-region.
const MULTI_REGION_TO_FUNCTION_REGION: Record<string, string> = {
  nam5: "us-central1",
  nam7: "us-central1",
  eur3: "europe-west1",
};

/**
 * Maps a Firestore database location to the Cloud Run region the functions
 * should deploy to. The lookup is case-insensitive and ignores surrounding
 * whitespace, as the CLI's own region handling is. Regional locations pass
 * through lowercased; an unset or blank location returns `undefined`, meaning
 * the functions declare no region.
 */
export function firestoreLocationToFunctionRegion(
  location: string | undefined
): string | undefined {
  const normalized = location?.trim().toLowerCase();
  if (!normalized) {
    return undefined;
  }
  return MULTI_REGION_TO_FUNCTION_REGION[normalized] ?? normalized;
}

const functionRegion = firestoreLocationToFunctionRegion(
  process.env.DATABASE_REGION
);

export const fsexportbigquery = onDocumentWritten(
  {
    region: functionRegion,
    // Other configuration
  },
  (event) => handleDocumentWrite(event, getHandlerContext())
);

Kit ilk kez dağıtıldığında kullanıcılardan DATABASE_REGION istenir ve işlevler yukarıdaki ilgili functionRegion konumuna dağıtılır. Böylece 2. nesil etkinlikle tetiklenen işlevlerindeki konum sorunları düzeltilir.

4. Uzantı parametrelerini ve gizli anahtarlarını dönüştürme

Parametreler

extension.yaml içinde tanımladığınız her parametre bir Cloud Functions parametresi olur.

Doğrudan ortam okumalarını dönüştürme:

const collectionPath = process.env.COLLECTION_PATH;

Cloud Functions parametreye dönüştürün:

import { defineString } from "firebase-functions/params";
import { onDocumentWritten } from "firebase-functions/firestore";

const collectionPath = defineString("COLLECTION_PATH");

// Pass the param directly when used as a placeholder (e.g. trigger path)
export const sync = onDocumentWritten(
  { document: collectionPath },
  async (event) => {
    // Call .value() to read the string inside a handler
    const path = collectionPath.value();
    await handleWrite(path, event);
  }
);

İşleyici içindeki dizeyi okumak için collectionPath.value() kullanın. İşlev tetikleyici yolu gibi bir yer tutucunun beklendiği yerlerde doğrudan collectionPath kullanın.

Firebase CLI, parametrelerinizi bulur ve değerlerini .env, .env.<projectId> üzerinden okur veya dağıtım sırasında kullanıcılarınıza sorar. Mevcut bir kurulumdaki değerlerin aktarılması için aynı parametre adlarını kullanın.

Kodunuzda belirtilen parametre adlarını hiçbir şekilde değiştirmemeniz önemlidir. Uzantı taşıma işlemi, mevcut son kullanıcı parametre değerlerini otomatik olarak korur ancak bu yalnızca adlar değişmediğinde geçerlidir.

Örnek: Cloud Firestore'ten BigQuery'e akış

Önce. extension.yaml içinde tanımlanan ve config.ts içinde ham ortam değişkeni olarak okunan bir parametre:

# extension.yaml
- param: COLLECTION_PATH
  label: Collection path
  type: string
  required: true
// functions/src/config.ts
collectionPath: process.env.COLLECTION_PATH,

Sonra. Bir defineString; CLI bunu keşfeder ve .env'den okur:

// src/config.ts
import { defineString } from "firebase-functions/params";

collectionPath: defineString("COLLECTION_PATH", {
  label: "Collection path",
  // We now support "nonEmpty: true" to ensure a value other than the empty string
  // is entered, analogous to "required: true" in extension.yaml
  input: { text: { nonEmpty: true } }
}),

Parametre adı değişmediğinden mevcut .env çalışmaya devam eder.

Örnek Kimliği

Uzantılar, örnek kimliklerini Uzantılar çalışma zamanı tarafından eklenen EXT_INSTANCE_ID konumundan okur. İşlev kitleri, örnek kimliklerini FIREBASE_KIT_INSTANCE_ID adresinden okur. Firebase CLI, her kit örneği için bu kimliği firebase.json içindeki instances eşlemesinde örneğin anahtarına ayarlar. CLI, bu bilgileri dağıtım zamanı keşfi sırasında, emülatörde ve dağıtılan işlevlere sağlar.

Örnek kimliği bir parametre olmadığından defineString ile tanımlamayın. Aslında FIREBASE_..., .env dosyalarında ayrılmış bir önek olduğundan kullanıcılar bu öneki ayarlayamaz veya geçersiz kılamaz. CLI'nın eklediği değerler, params sistemi tarafından görülemez. Doğrudan ortamdan okuyun:

// Before
const instanceId = process.env.EXT_INSTANCE_ID;

// After
const instanceId = process.env.FIREBASE_KIT_INSTANCE_ID;

Değişken yalnızca paketiniz kit olarak dağıtıldığında ayarlanır. Kodunuz bağımsız bir kod tabanı olarak da dağıtılıyorsa (9. adıma bakın) bunu isteğe bağlı olarak değerlendirin veya eksik olduğunda net bir mesajla hızlı bir şekilde başarısız olun. Uzantınız, örnek kimliğini kullanıcılara yönelik bir parametre olarak gösteriyorsa Firebase CLI artık değere sahip olduğundan bu parametreyi kaldırmanız gerekir.

Örnek: Kullanıcı verilerini silme

(Stream Cloud Firestore to BigQuery uzantısı, örnek kimliğini okumadığı için taşınacak bir şey yoktur. Kullanıcı Verilerini Silme uzantısı, Pub/Sub konularını adlandırmak için bu kimliği kullanır.)

Önce. Uzantılar'ın kaynakları için kullandığı ext- ön ekiyle config.ts içinde ham ortam değişkeni olarak okunur:

// functions/src/config.ts
discoveryTopic: `ext-${process.env.EXT_INSTANCE_ID}-discovery`,
deletionTopic: `ext-${process.env.EXT_INSTANCE_ID}-deletion`,

Sonra. Kullanıcıların konu adlarını geçersiz kılabilmesi için iki sıradan parametre için kullanılan FIREBASE_KIT_INSTANCE_ID'in basit bir process.env okuması:

// src/config.ts
const instanceId = process.env.FIREBASE_KIT_INSTANCE_ID;

// Non-empty defaults so Pub/Sub trigger bindings resolve during deploy
// discovery without freezing an empty topic name into the manifest.
discoveryTopicName: defineString("DISCOVERY_TOPIC_NAME", {
  default: `kit-${instanceId}-discovery`,
}),
deletionTopicName: defineString("DELETION_TOPIC_NAME", {
  default: `kit-${instanceId}-deletion`,
}),

Tetikleyici bağlamaları keşif sırasında çözümlendiğinden varsayılan değerler boş olmamalıdır. Dağıtım manifestine konu adı olarak boş bir varsayılan değer yazılır. Kit, kit bağlamı dışında çalıştırılmaya karşı da koruma sağlar. Değişken eksikse modül düzeyindeki varsayılan değer kit-undefined-discovery olarak değerlendirilir. Bu nedenle, yapılandırma yükleyici açıklayıcı bir hata ile başarısız olur:

// ...
const instanceId = process.env.FIREBASE_KIT_INSTANCE_ID;
if (!instanceId) {
  throw new Error(
    "FIREBASE_KIT_INSTANCE_ID is not set. It is provided automatically to " +
      "kit instances by firebase-tools >= 15.32.0; deploy or emulate this " +
      "kit with a supported CLI version."
  );
}
// ...

Bu kontrol, bir işleyici yapılandırmasını ilk kez çözdüğünde çalışır. Bu nedenle, eksik bir değişken, kit-undefined-* konularına sessizce bağlı işlevler yerine net bir çalışma zamanı hatası oluşturur. Dağıtımın kendisini reddetmek için kontrolü modül kapsamında gerçekleştirin. Böylece kontrol, keşif sırasında çalışır. CLI, örnek kimliğini firebase.json öğesinden türettiği için yapılandırılabilir bir INSTANCE_ID yoktur ve birden fazla örnek arasında senkronize edilecek bir şey yoktur.

Gizli Anahtarlar

extension.yaml içinde, gizli anahtarları type: secret ile bildirirsiniz. Uzantılar çalışma zamanı bunları depolar ve bağlar. Böylece uzantı kodunuz process.env.PARAM_NAME değerini doğrudan okuyabilir. Tipik bir Cloud Functions kod tabanında her gizli anahtarı açıkça tanımlayıp bağlarsınız:

import { defineSecret } from "firebase-functions/params";
import { onRequest } from "firebase-functions/https";

const apiKey = defineSecret("API_KEY");
export const fn = onRequest({ secrets: [apiKey] }, handler);

Uzantınız bir npm paketine/kitine taşındıktan sonra gizli referanslar, son kullanıcının .env dosyasında yönetilir. Kodunuzda belirtilen gizli adları hiçbir şekilde değiştirmemeniz önemlidir. Taşıma sırasında son kullanıcı gizli anahtarları da taşınır.

Uygulamalı örnek: Cloud Firestore adresinden e-posta tetikleme

Önce. MAIL_COLLECTION ve SMTP_PASSWORD, config.ts içinde ham ortam değişkenleri olarak okunur:

# extension.yaml
- param: MAIL_COLLECTION
  label: Email documents collection
  type: string
  default: mail
  required: true

- param: SMTP_PASSWORD
  label: SMTP password
  type: secret
// functions/src/config.ts
mailCollection: process.env.MAIL_COLLECTION,
smtpPassword: process.env.SMTP_PASSWORD,

Sonra. Bir defineString ve bir defineSecret; CLI her ikisini de bulur ve .env dosyasından okur:

import { defineString, defineSecret } from "firebase-functions/params";
import { onDocumentWritten } from "firebase-functions/firestore";

const mailCollection = defineString("MAIL_COLLECTION", {
  label: "Email documents collection",
  default: "mail"
});

const smtpPassword = defineSecret("SMTP_PASSWORD", { label: "SMTP password" });

export const processQueue = onDocumentWritten(
  { document: `${mailCollection}/{documentId}`, secrets: [smtpPassword] },
  async (event) => {
    const collection = mailCollection.value();
    const password = smtpPassword.value();
    // ...
  }
);

5. Dahili görev sırası çağrılarını taşıma

Bazı uzantılar, Firebase Admin SDK kullanarak işlev kodlarının içinden kendi görev sıralarına iş ekler. Bu, gönderilen bir görevi almaktan farklıdır (İşlevleri yükseltme ve Yaşam döngüsü kancalarını dönüştürme bölümlerinde ele alınmıştır). Burada kodunuz, queue.enqueue(...) yöntemini çağıran üreticidir.

Admin SDK'ın önceki sürümlerinde, aynı uzantıdaki bir görev sırası işlevini hedeflemek için uzantıların kendi uzantı örneği kimliklerini ikinci bir parametre olarak iletmesi gerekiyordu. firebase-admin 14.2.0 sürümünden itibaren bu işlem gerekli değildir ve önerilmez. Task Queue API artık varsayılan olarak aynı bağlamdaki (ör. bir uzantı veya kit) görev sıralarını hedefliyor. Kodunuzda bu parametreyi hem uzantı hem de bağımsız işlev olarak kaldırmak güvenlidir ve önerilir. Bu parametrenin kaldırılması, taşınabilirlik ve ileriye dönük uyumluluk sağlar.

Sıraya alma çağrısıyla ilgili diğer her şey (locations/<region>/functions/<name> kaynak yolu, görev yükü ve yeniden deneme mantığınız) aynı kalır.

Cloud Tasks ile işlevleri sıraya ekleme hakkında daha fazla bilgi için Cloud Tasks ile işlevleri sıraya ekleme başlıklı makaleyi inceleyin.

Önce. 1. nesil uzantı:

import { getFunctions } from "firebase-admin/functions";

const queue = getFunctions().taskQueue(
  `locations/${config.location}/functions/syncBigQuery`,
  process.env.EXT_INSTANCE_ID, // extension instance ID, injected by the runtime
);
await queue.enqueue(taskData);

Sonra. 2. nesil uzantı:

import { getFunctions } from "firebase-admin/functions";

const queue = getFunctions().taskQueue(
  `locations/${process.env.FUNCTION_REGION}/functions/syncBigQuery`
);
await queue.enqueue(taskData);

Sıraya alma çağrınız ön ekli bir kod tabanını hedefliyorsa keşfedilen işlev adı da ön ekli olur (örneğin, orders-syncBigQuery). Yedek işlev kiti örneğini inceleme ve yükleme ve İşlev kiti olarak test etme bölümlerine bakın.

6. Gerekli API'leri ve IAM rollerini bildirme

Uzantınızın IAM ve API gereksinimlerini extension.yaml yerine koda taşıyın:

import { requiresAPI, requiresRole } from "firebase-functions";

requiresAPI("bigquery.googleapis.com", "Needed to write changelog rows");
requiresRole("roles/bigquery.dataEditor");
requiresRole("roles/bigquery.user");

Bildirim temelli güvenlikte Firebase CLI, kod tabanı için yönetilen bir çalışma zamanı hizmet hesabı oluşturur veya günceller ve bu hesaba tüm beyan edilen rollerin birleşimini verir. Son API daha dar bir modeli desteklemediği sürece kod tabanındaki tüm işlevlerin bu rollerle çalıştığını kullanıcılarınız için belgeleyin.

Örnek: Cloud Firestore'ten BigQuery'e akış

Önce. extension.yaml içinde tanımlanır. Extensions çalışma zamanı, API'yi etkinleştirir ve rolleri yönetilen bir hesaba verir:

apis:
  - apiName: bigquery.googleapis.com
roles:
  - role: bigquery.dataEditor
  - role: datastore.user
  - role: bigquery.user

Sonra. requiresAPI ve requiresRole ile kodda beyan edilir:

import { requiresAPI, requiresRole } from "firebase-functions";

requiresAPI(
  "bigquery.googleapis.com",
  "Needed to write changelog rows and views"
);
requiresRole("roles/bigquery.dataEditor");
requiresRole("roles/datastore.user");
requiresRole("roles/bigquery.user");

Uzantınız Eventarc etkinlikleri yayınlıyorsa etkinlik yayınlamak için gerekli rolleri ve API'leri de ayarlamanız gerekir. Bu işlem daha önce extensions.yaml üzerinde herhangi bir değişiklik yapılmasına gerek kalmadan uzantılar tarafından gerçekleştiriliyordu. Bu işlemi kodunuzda koşullu olarak yapabilirsiniz. Böylece kit, bu izinleri yalnızca özel bir Eventarc kanalı kullanıldığında ister.

if (!!process.env.EVENTARC_CHANNEL) {
  requiresRole("roles/eventarc.publisher");
  requiresAPI(
    "eventarcpublishing.googleapis.com",
    "Publishes the extension's custom events to its Eventarc channel."
  );
}

7. Yaşam döngüsü kancalarını dönüştürme

Uzantınız getExtensions().runtime() (ör. setProcessingState veya setFatalError) çağrısı yapıyorsa normal şekilde dağıtılan 2. nesil bir işlevden çağrıldığında hata vereceğinden bu çağrıları silin. Yaşam döngüsü durumu artık afterFirstDeploy ve afterRedeploy tarafından yönetiliyor. Bu durum izleme özelliği kullanılmıyor.

Firebase Extensions, bir kullanıcı bir uzantıyı yüklediğinde, güncellediğinde veya yeniden yapılandırdığında kurulumu çalıştırabilir. npm paketinizde, kodda eşdeğer yaşam döngüsü işlemlerini bildirin.

Tek seferlik kurulum için:

import { afterFirstDeploy } from "firebase-functions/lifecycle";
import { onTaskDispatched } from "firebase-functions/tasks";

export const runInitialSetup = onTaskDispatched(async (request) => {
  await initializeResources(request.data);
});

afterFirstDeploy({
  task: {
    function: "runInitialSetup",
    body: {}
  }
});

Yapılandırma veya kod güncellemeleri için:

import { afterRedeploy } from "firebase-functions/lifecycle";

afterRedeploy({
  task: {
    function: "runInitialSetup",
    body: { reconcile: true }
  }
});

Yaşam döngüsü işlemlerinizi idempotent yapın. Gönderme veya yürütme başarısız olursa kullanıcılarınızın bunları manuel olarak yeniden çalıştırması gerekebilir:

firebase functions:lifecycle:run afterFirstDeploy CODEBASE_NAME
firebase functions:lifecycle:run afterRedeploy CODEBASE_NAME

Örnek: Cloud Firestore'ten BigQuery'e akış

Önce. lifecycleEvents, extension.yaml içinde, Uzantılar çalışma zamanı tarafından desteklenir:

lifecycleEvents:
  onInstall:
    function: initBigQuerySync
    processingMessage: Configuring BigQuery Sync.
  onUpdate:
    function: setupBigQuerySync
    processingMessage: Configuring BigQuery Sync
  onConfigure:
    function: setupBigQuerySync
    processingMessage: Configuring BigQuery Sync

Sonra. Kodda tanımlanır; görev, ilk dağıtımda BigQuery sağlar:

import { afterFirstDeploy, afterRedeploy } from "firebase-functions/lifecycle";

afterFirstDeploy({ task: { function: "initBigQuerySync" } });
afterRedeploy({ task: { function: "setupBigQuerySync" } });

Temel hazırlık işlemi idempotent olduğundan yeniden çalıştırma işlemi veri kümesini, tabloyu ve görünümleri mutabık kılar. Kullanıcılar firebase functions:lifecycle:run afterFirstDeploy CODEBASE_NAME ile manuel olarak yeniden çalıştırabilir.

8. Kullanıcılarınız için doküman kurulumu

En azından aşağıdakileri açıklayan bir paket README yazın:

  • Paketin gerektirdiği .env değerleri.
  • Paketin gerektirdiği gizli anahtarlar ve mevcut gizli anahtar değerlerinin nasıl taşınacağı.
  • Paketin requiresRole(...) ile beyan ettiği IAM rolleri.
  • Paketin etkinleştirdiği veya gerektirdiği Google API'leri.
  • Paketin bildirdiği yaşam döngüsü kancaları ve bunları manuel olarak yeniden çalıştırma yöntemi.
  • Faturalandırma notları.
  • Orijinal uzantıya kıyasla nelerin değiştiği.
  • Paketin örnek kimliğini (CLI tarafından ayarlanan FIREBASE_KIT_INSTANCE_ID) nasıl aldığı ve tüm örnek işlevlerinin kit-<instanceId>- ön ekiyle nasıl dağıtıldığı.

Örnek: Cloud Firestore'ten BigQuery'e akış

README paketi, somut bir "değişiklikler" tablosu içerir:

Endişe Uzantı olarak @firebase-function-kits/firestore-bigquery-export olarak
Yapılandırma Uzantı parametreleri .env üzerinden Cloud Functions parametre
IAM ile yönetin. Uzantılar tarafından verilen izinler requiresRole(...), dağıtım sırasında uygulandı
Temel hazırlık yapılıyor Uzantılar tarafından gerçekleştirilen yaşam döngüsü görevi afterFirstDeploy/afterRedeploy görev
İşlev adları ext-<instanceId>-fsexportbigquery fsexportbigquery (isteğe bağlı olarak ön ekli)
Örnek Kimliği Uzantılar tarafından yerleştirilen EXT_INSTANCE_ID FIREBASE_KIT_INSTANCE_ID, firebase.json tarafından KSA'dan ayarlandı

9. 2. nesil işlevinizi test etme

Artık dağıtıldığında uzantınızın yeni bir yüklemesiyle aynı şekilde davranan 2. nesil bir işleviniz olmalıdır. Sonraki adım, süreçte yanlışlıkla ortaya çıkan sorunları doğrulamak ve düzeltmektir.

Varsayılan bölge veya CPU gibi genel seçenekleri ayarlamak için setGlobalOptions işlevini yalnızca kitinizi bağımsız bir 2. nesil işlev olarak dağıtırken çağırabilirsiniz. Kitiniz bir npm paketi olarak yüklendiğinde kullanıcılarınız bu parametreleri yapılandırmak için sarmalama kodlarında setGlobalOptions işlevini çağırır ve bu işlem iki kez gerçekleşirse uyarı alırlar. FIREBASE_KIT_INSTANCE_ID ortam değişkenini kontrol ederek bu çağrıyı koruyabilirsiniz:

import { setGlobalOptions } from "firebase-functions";

if (!process.env.FIREBASE_KIT_INSTANCE_ID) {
  setGlobalOptions({
    region: "us-east1",
    maxInstances: 10,
  });
}

firebase-tools >= 15.32.0 kullandığınızdan emin olun ve dönüştürülen 2. nesil işlevinizi, davranışını test etmek için uygun kaynaklara sahip bir test projesine dağıtın. Uzantınızı test etmek için oluşturduğunuz bir test projeniz varsa aşağıdaki komutu çalıştırın:

firebase deploy --only functions

Parametre değerlerini girmenizi isteyen sihirbazı, uzantı için Firebase konsolundaki yükleme formunu doldurduğunuz şekilde doldurun.

Örnek: Cloud Firestore'ten BigQuery'e akış

Cloud Firestore ile BigQuery arasındaki senkronizasyonu uçtan uca doğrularız:

  1. Firebase konsolunun Cloud Firestore sayfasında, COLLECTION_PATH (users) olarak ayarladığınız koleksiyonu oluşturun (henüz oluşturulmamışsa).
  2. Herhangi bir değer içeren alanlara sahip bigquery-mirror-test adlı bir doküman oluşturun.
  3. Google Cloud konsolunun BigQuery sayfasında ham değişiklik günlüğü tablosunu sorgulayın. Doküman oluşturma işlemini kaydeden tek bir satır içermelidir:

    SELECT * FROM `PROJECT_ID.analytics.users_raw_changelog`
    
  4. Mevcut tek doküman (bigquery-mirror-test) için en son değişiklik etkinliğini döndürmesi gereken en son görünümü sorgulayın:

    SELECT * FROM `PROJECT_ID.analytics.users_raw_latest`
    
  5. Cloud Firestore içindeki bigquery-mirror-test dokümanını silin. En son görünümden kaybolur ve ham değişiklik günlüğü tablosuna bir DELETE etkinliği eklenir.

    Tek bir dokümanın tüm geçmişini şunlarla inceleyebilirsiniz:

    SELECT *
       FROM `PROJECT_ID.analytics.users_raw_changelog`
       WHERE document_name = "bigquery-mirror-test"
       ORDER BY timestamp ASC
    

Uzantıyı test etme işleminden farkları:

  • Tetikleyici, ext-<instanceId>-fsexportbigquery olarak değil, fsexportbigquery (normal bir 2. nesil işlev olarak dağıtıldığında ve kit olmadığında ön ek kullanılmaz) olarak dağıtılır. Cloud Functions kontrol panelinde ve günlüklerinde bu adı arayın.
  • Kodunuz artık Firebase Local Emulator Suite içinde normal işlevler olarak çalışır. Emülatörde kullanılacak parametrelerin değerini .env.local ile ayarlayabilirsiniz. Cloud Functions birim testi bölümünde açıklandığı gibi firebase-functions-test SDK'sını kullanarak kodunuzu birim testine de tabi tutabilirsiniz.
  • Temel hazırlık artık Uzantılar çalışma zamanı tarafından yönetilmez. Dağıtımdan sonra değişiklik günlüğü tablosu eksikse kurulum görevini manuel olarak yeniden çalıştırın: firebase functions:lifecycle:run afterFirstDeploy CODEBASE_NAME. Görev, eş güçlü olduğundan yeniden çalıştırıldığında veri kümesini, tabloyu ve görünümleri mutabık kılar.
  • Parametre değerleri, yükleme formu yerine .env üzerinden alınır. Bu nedenle, .env tamamlandıktan sonra firebase deploy yeniden çalıştırıldığında etkileşimli olmaz.

10. İşlev kitinizi npm'de yayınlama

Uzantıdan 2. nesil işleve dönüşümünüzü doğruladıktan sonra, aşağıdaki kılavuzlardan birini kullanarak uçtan uca test için npm'de bir sürüm adayı yayınlayabilirsiniz:

Kitiniz npm'de yayınlandığında firebase functions:kits:install ile yüklenebilir ve uzantınızın resmi alternatifi olarak listelenir.

Öncelikle bir sürüm adayı yayınlamanızı önemle tavsiye ederiz. Kitler paket adı ve sürümüne göre yüklenir. Bu nedenle, yayın öncesi sürüm sayesinde tamamlanmamış bir paketi varsayılan latest etiketiyle yükleyen kullanıcılara göstermeden gerçek yükleme akışını kayıt defterine göre test edebilirsiniz.

Yayınlamadan önce:

  1. Bir paket adı seçin. Hem kapsamlı hem de kapsamsız adlar kullanılabilir (yukarıdaki kılavuzlara bakın). Kapsamlı paketlerin varsayılan olarak gizli olduğunu unutmayın. Bu nedenle --access public parametresini iletin.
  2. Derleme yapın ve nelerin gönderildiğini kontrol edin. main ve types, derlenmiş çıkışınızı (örneğimizde lib/) işaret eder. Bu nedenle, bu dizin yayınlanan tar dosyasına dahil edilmelidir. .npmignore veya files izin verilenler listesi kullanın ve sonucu npm pack --dry-run ile inceleyin. Derlemenizi çalıştıran bir prepublishOnly komut dosyası, eski çıkışın yayınlanmasını önler.

Yayınlamayı varsayılan olarak güvenli hale getiren package.json ekleme:

{
  "files": ["lib", "README.md", "CHANGELOG.md"],
  "publishConfig": { "access": "public", "tag": "next" },
  "scripts": {
    "build": "tsc -b",
    "prepublishOnly": "npm run build && npm test"
  }
}

"publishConfig": { "tag": "next" } alanı, düz bir npm publish değerinin hiçbir zaman latest değerinin üzerine yazmamasını sağlar.

Sürüm adayı oluşturma:

Örneğin, sürümü yerel olarak 0.0.2-rc.3 değerinden 0.0.2-rc.4 değerine yükseltmek için (package.json, depo kökündeyse bu işlem Git'te kaydeder ve etiketler):

npm version prerelease --preid rc

Sürüm adayını yayınlamak ve @your-org/your-kit@0.0.2-rc.4 paketini npm'de next etiketiyle kaydetmek için:

npm publish

npm web sitesinin yeni sürümü göstermesi birkaç dakika sürebilir. npm view, kayıt defterini doğrudan okur:

npm view @your-org/your-kit versions dist-tags

Bu kılavuzdaki 11. adım ve 12. adım tamamlandıktan sonra paketi kararlı sürüme yükseltebilirsiniz:

npm version 0.0.2
npm publish --tag latest
npm dist-tag add @your-org/your-kit@0.0.2 next

npm-shrinkwrap.json ile ilgili not: Paketinize bir npm-shrinkwrap.json dosyası eklemenizi önemle tavsiye ederiz. Eklememeniz durumunda CLI, yükleme sırasında kullanıcıları uyarır. Bu sayede kullanıcılar, test ettiğiniz bağımlılıkları kullanır ve tedarik zinciri saldırılarına karşı korunur. Ancak shrinkwrap, kullanıcılarınızın projelerinde Cloud Functions derlemesi (npm ci) de dahil olmak üzere kelimesi kelimesine uygulanır. Bu durumda, yalnızca geliştirme amaçlı girişler EBADPLATFORM ile başarısız olabilir. Yayınlanan shrinkwrap kopyasından "dev": true girişlerini ve devDependencies öğesini çıkarmanız gerekebilir.

Örnek: Cloud Firestore'ten BigQuery'e akış

Dördüncü sürüm adayı yayınlandığında kitin package.json:

{
  "name": "@firebase-function-kits/firestore-bigquery-export",
  "version": "0.0.2-rc.4",
  "repository": {
    "type": "git",
    "url": "https://github.com/firebase/extensions.git",
    "directory": "kits/firestore-bigquery-export"
  },
  "main": "lib/index.js",
  "types": "lib/index.d.ts",
  "engines": { "node": "22" },
  "scripts": { "build": "tsc -b" }
}

Bu durumda kitin bir monorepo'da bulunduğunu unutmayın. Bu nedenle, npm kayıt defteri bağlantısının doğru klasörü işaret etmesi için repository.directory ifadesini eklemek önemlidir. CHANGELOG.md, bekleyen sürümle ilgili notları içerir.

11. İşlev kiti olarak test etme

Kitinizi yayınladıktan sonra npm kullanarak test etmenizi öneririz.

firebase-tools'in >= 15.32.0 sürümünü kullandığınızdan emin olun ve kiti yükleyin:

firebase functions:kits:install --package <your-package-name>@<your-prerelease-version>

Bu komut, paketinizi npm'den indirir, kitiniz için yeni bir kaynak dizininde ayarlar ve uzantı yükleme akışına benzer şekilde ilk örneği yapılandırma konusunda size yol gösterir. Paketinizi yerel olarak yükleyip ayarladıktan sonra Google Cloud projenizde kaynakları oluşturmak için bir dağıtım çalıştırın:

firebase deploy --only functions:<your-kit-instance-id>

Yükleme işleminden sonra Firebase CLI, yükleme sırasında seçtiğiniz örnek kimliğini içeren benzer bir dağıtım komutu yazdırır.

9. adımda 2. nesil işlevinizi test etme Artık kitleri kullanarak dağıtım yaptığınız için işlevleriniz kit-<instance-id>-<method-name> ön ekiyle adlandırılır. Bu sayede kitler birden fazla örneğe sahip olabilir ve aynı işlevi bir projede her biri benzersiz bir ada sahip olacak şekilde birden fazla kez dağıtabilir.

12. Test taşıma işlemini değiştirme

Çalışan bir uzantı örneği oluşturabilir ve ardından işlev kitinizi geçiş alternatifi olarak test etmeyi tamamlamak için kullanıcı geçiş rehberini (firebase ext:migrate --package veya işlev kiti CLI komutlarını kullanarak) kullanabilirsiniz.

13. Kullanıcıları ve Google'ı resmi uzantı değişikliğiniz hakkında bilgilendirme

İşlev kiti değişiminiz hazır olduğunda ve kullanıcıların geçiş yapması gereken bir npm paketi olarak sunulduğunda hem kullanıcılarınızı hem de Google'ı bu resmi değişim hakkında bilgilendirin. Uzantınızı barındıran GitHub deposundaki README.md dosyasını aşağıdaki bilgilerle güncelleyin:

<!-- FIREBASE_EXTENSION_REPLACEMENT: extension="<your-extesion-id>" package="<your-npm-package-name>" -->
> [!WARNING]
> **Deprecation Notice:** The Firebase Extension `<your-extension>` is deprecated. Migrate to the [<your-npm-package-name>](<link-to-your-npm-package>) package.

Google, bilinen uzantıların BENİOKU dosyalarını <!-- FIREBASE_EXTENSION_REPLACEMENT: extension="firebase/firestore-bigquery-export" package="@firebase-function-kits/firestore-bigquery-export" --> gibi yorumlar için tarar ve bunu, firebase-tools deposunda replacements.json olarak depolanan resmi değişiklik kayıt defterimizi doldurmak için kullanır. Uzantınız için hangi README.md öğelerinin taranacağını görmek üzere replacements.json sayfasını da kontrol edebilirsiniz. Resmi yedek listesi haftalık olarak güncellenir.

Örnek: Cloud Firestore'ten BigQuery'e akış

firestore-bigquery-export uzantısı README.md şunları içerir:

<!-- FIREBASE_EXTENSION_REPLACEMENT: extension="firebase/firestore-bigquery-export" package="@firebase-function-kits/firestore-bigquery-export" -->
> [!WARNING]
> **Deprecation Notice:** The Firebase Extension `firebase/firestore-bigquery-export` is deprecated. Please migrate to the [`@firebase-function-kits/firestore-bigquery-export`](https://www.npmjs.com/package/@firebase-function-kits/firestore-bigquery-export) package.