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

Bu kılavuzda, uzantılarınızı kullanımdan kaldırılan Firebase Extensions ortamından, kullanıcılarınızın kendi Cloud Functions ortamlarında yükleyip dağıttığı bir işlevselliğe taşıma adımları gösterilmektedir. Bu işlevsellik, Firebase (2. nesil) kod tabanında kullanılabilir.

Bu, önerilen taşıma yoludur. Firebase, resmi npm eşdeğerlerine sahip uzantıların bir listesini tutar. Bu kılavuz, kendi listenizi oluşturma konusunda size yol gösterir.

Bu kılavuzda, Stream Cloud Firestore to BigQuery uzantısı (firestore-bigquery-export) örnek olarak kullanılmıştır. Her bölüm, taşıma işleminden önce uzantının nasıl göründüğünü ve @firebase-function-kits/firestore-bigquery-export paketi olarak nasıl göründüğünü gösteren bir çalışma örneğiyle sona erer.

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

Firebase Extensions sürümünden nasıl geçiş yapacağınızla ilgili sorularınız varsa firebase-extensions-migrator-support-external@google.com adresinden bize ulaşabilirsiniz. Ayrıca, kılavuzu 2. nesil işlevlerinizi paketleme, test etme ve dağıtma hakkında daha fazla bilgiyle güncelledikçe 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ıyla yanıt alacaksınız. "Bu Gruba Katıl" düğmesini tıklamadan e-postayı yanıtlamanız gerekir.

Başlamadan önce

Bu taşıma işlemini belirtildiği şekilde tamamlamak için Cloud Functions'nın aşağıdaki özelliklerini kullanacaksınız:

  • Parametreli Yapılandırma. extension.yaml içinde bildirdiğiniz her parametre, paket kodunuzda tanımlanmış bir parametre haline gelir.

  • Bildirimli IAM rolleri ve gerekli API'ler. extension.yaml içinde bildirdiğiniz 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, bildirilen rolleri yönetilen bir çalışma zamanı hizmet hesabına verir ve bildirilen API'leri sizin adınıza etkinleştirir.

  • Cloud Functions kod tabanları için yaşam döngüsü etkinlikleri Cloud Functions kod tabanları artık Firebase Extensions'ye benzer yaşam döngüsü etkinliklerini destekliyor. Yaşam döngüsü kancaları afterFirstDeploy(...) ve afterRedeploy(...) ile yükleme ve güncelleme zamanı kurulumunu tanımlayın. Bunlar, extension.yaml içinde tanımladığınız lifecycleEvents öğesinin 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 aracısı becerisini kullanarak 1 ila 8 arasındaki adımları (envanter kaynakları, yükseltmeleri tetikleme, param ve gizli dönüştürmeler, bildirimli IAM, yaşam döngüsü kancaları ve paket README'sini oluşturma) otomatikleştirebilirsiniz.

Beceriyi yükleyin

Siz veya yapay zeka kodlama asistanınız (Firebase'da Gemini, Cursor, Claude Code, GitHub Copilot) beceriyi henüz yüklemediyseniz beceri CLI'sı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 kodlama asistanınız, taşıma kurallarını ve dönüştürme adımlarını otomatik olarak uygular. Aşağıdaki istemi kullanabilirsiniz:

"Lütfen bu Firebase uzantısını extension-to-functions-codebase becerisindeki talimatları uygulayarak yayınlanabilir bir 2. nesil işlev kiti paketine taşıyın. becerisindeki talimatları uygulayarak yayınlanabilir bir 2. nesil işlev 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 bulgularınızı not edin:

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

  • functions/. Bu dosya; işlev kodunuzu, bağımlılıklarınızı, derleme yapılandırmanızı, tetikleyicilerinizi ve görev sırası işlevlerinizi içerir.

  • Kurulum adımları, uyarılar ve faturalandırma notları içeren README.md, PREINSTALL.md ve POSTINSTALL.md.

  • scripts/; içe aktarma, doldurma, IAM, onarım veya taşıma yardımcı programlarının yanı sıra uzantıyla birlikte gönderdiğiniz diğer tüm 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).

Çalışma örneği: Cloud Firestore'dan BigQuery'a yayın yapma

firestore-bigquery-export/extension.yaml ve functions/ ürünleri okunuyor. Bu envanter oluşturuluyor:

extension.yaml içinde Sayı / değer Nereye gider?
params 25 (COLLECTION_PATH, DATASET_ID, TABLE_ID, DATASET_LOCATION, VIEW_TYPE, …) Cloud Functions params (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 dosyaları olarak saklananlar (burada kapsam dışıdır)

Analiz. Uzantı herhangi bir type: secret parametresi bildirmediğinden 4. adımda gizli diziler 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 önemlidir).

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

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

Minimum SDK sürümleri: firebase-functions >= 7.4.0 ve firebase-admin >= 14.2.0 bağımlılıklarını tanımlayın. Kullanıcılarınızın Cloud Functions projesinde, kitaplığınızın yazıldığı SDK'nın aynı sürümü bulunması için firebase-functions sürümünüzü de eş bağımlılık olarak beyan edin.

{
  "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"
  }
}

Çalışma örneği: Cloud Firestore'dan BigQuery'a yayın yapma

Önce. Uzantının functions/package.json dosyası gizlidir, uzantı kimliğini adlandırır ve firebase-functions dosyasını 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 haritası ve firebase-functions, peerDependencies'ye 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. 1. nesilden 2. nesile yükseltme işlevleri

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 yama uygulanmış etkinlik yapılarını kullanarak yeniden yazma çabalarını en aza indirebilirsiniz. Ayrıca, 2. nesil SDK, v1 parametrelerini etkinlik nesnesindeki alanlar olarak kullanıma sunduğundan işlev mantığınızı yeniden yazmaktan kaçınabilirsiniz. Bu sayede, yapıları bozulmuş/adlandırılmış parametreleri kullanabilir ve iş mantığınızı değiştirmeden tutabilirsiniz.

Ö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ı 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ı konumda olması gerektiğidir. Kullanıcılar 1. nesil işlevleri kullanan bir uzantıdan 2. nesil işlevleri kullanan bir kitte geçiş yaptıklarında bu koşulu karşılamak için işlev konumlarını değiştirmeleri gerekebilir.

Kullanıcılarınızın seçtiği Cloud Functions konumları, mevcut konum korunacağından taşıma sırasında bozulabilir. Uzantınızın etkinliği tetikleyen işlevleri, kullanıcı tarafından sağlanan işlevlerin konumuna bağlıysa etkinlik tetikleme konumunu toplamak ve bunu yeni işlev konumuna eşlemek için uzantınıza yeni bir parametre eklemenizi öneririz.

Çalışma örneği: Cloud Firestore'dan BigQuery'a yayın yapma

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 istenecektir ve işlevler, 2. nesil etkinlik tarafından tetiklenen işlevlerdeki konum sorunlarını düzelterek yukarıdaki ilgili functionRegion dağıtılacaktır.

4. Uzantı parametrelerini ve sırlarını dönüştürme

Parametreler

extension.yaml içinde tanımladığınız her parametre, Cloud Functions parametreye dönüşür.

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

const collectionPath = process.env.COLLECTION_PATH;

Cloud Functions parametrelerine:

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);
  }
);

Bir işleyicinin içindeki dizeyi okumak için collectionPath.value(), yer tutucunun beklendiği yerlerde (ör. işlev tetikleme yolu) doğrudan collectionPath kullanın.

Firebase CLI, parametrelerinizi keşfeder ve değerlerini .env, .env.<projectId> veya dağıtım sırasında kullanıcılarınızdan okur. 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 yalnızca adlar değişmediğinde.

Çalışma örneği: Cloud Firestore'dan BigQuery'a yayın yapma

Ö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 varsa KSA bunu keşfeder ve .env dosyasından 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ği için mevcut bir .env çalışmaya devam eder.

Örnek Kimliği

Uzantılar, örnek kimliklerini Uzantılar çalışma zamanı tarafından yerleştirilen EXT_INSTANCE_ID öğesinden okur. İşlev kitleri, örnek kimliklerini FIREBASE_KIT_INSTANCE_ID konumundan okur. Firebase CLI, her bir kit örneği için konumunu firebase.json içindeki instances haritasında örneğin anahtarı olarak ayarlar. CLI, dağıtım zamanı keşfi sırasında, emülatörde ve dağıtılan işlevlere bu bilgiyi sağlar.

Örnek kimliği bir parametre değildir. Bu nedenle, defineString ile bildirmeyin. Aslında, FIREBASE_..., .env dosyalarında ayrılmış bir önek olduğundan kullanıcılar bunu ayarlayamaz veya geçersiz kılamaz. CLI'nın yerleştirdiği değerler, params sistemine görünmez. 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ım'a bakın) isteğe bağlı olarak değerlendirin veya eksik olduğunda net bir mesajla hızlıca başarısız olun. Uzantınız örnek kimliğini kullanıcıya yönelik bir parametre olarak kullanıma sunuyorsa bu parametreyi kaldırmanız gerekir. Çünkü Firebase CLI artık bu değerin sahibidir.

Çalışma örneği: Kullanıcı verilerini silme

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

Önce. Uzantıların kaynakları için kullandığı ext- önekiyle 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 normal parametre için kullanılan basit bir process.env FIREBASE_KIT_INSTANCE_ID okuma işlemi:

// 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`,
}),

Varsayılanlar boş olmamalıdır. Çünkü tetikleyici bağlamaları keşif sırasında çözülür. Boş bir varsayılan değer, dağıtım manifestine konu adı olarak yazılır. Kit, kit bağlamı dışında çalışmaya karşı da savunma 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 bunun yerine açıklayıcı bir hatayla 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ı üretir. Dağıtımı reddetmek için keşif sırasında çalışması amacıyla kontrolü modül kapsamında gerçekleştirin. CLI, örnek kimliğini firebase.json değerinden 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 type: secret ile sırları bildirirsiniz. Uzantı çalışma zamanı, uzantıları saklayıp bağlar. Böylece uzantı kodunuz process.env.PARAM_NAME öğesini doğrudan okuyabilir. Tipik bir Cloud Functions kod tabanında, her bir Gizli Anahtarı tanımlar ve 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ı sırları buna göre taşınır.

Çalışma örneği: 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; KSA her ikisini de keşfeder ve .env'dan 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şleri kendi görev kuyruklarına işlev kodlarının içinden ekler. Bu, gönderilen bir görevi almaktan farklıdır (Yükseltme işlevleri ve Dönüşüm yaşam döngüsü kancaları bölümlerinde ele alınmıştır). Burada kodunuz, queue.enqueue(...) işlevini çağıran üreticidir.

Admin SDK'nın önceki sürümlerinde, uzantıların aynı uzantıdaki bir görev sırası işlevini hedeflemek için kendi uzantı örneği kimliklerini ikinci bir parametre olarak iletmeleri gerekiyordu. firebase-admin 14.2.0 sürümünden itibaren bu işlem ne gereklidir ne de önerilir. Görev Kuyruğu API'si artık varsayılan olarak aynı bağlamdaki (ör. uzantı veya kit) görev kuyruklarını hedefler. Bu parametreyi kodunuzda hem uzantı hem de bağımsız işlevler olarak kaldırmak güvenlidir ve önerilir. Bu parametrenin kaldırılması, taşınabilirlik ve ileriye dönük uyumluluk sağlar.

Kuyruğa 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 alma hakkında daha fazla bilgi için Cloud Tasks ile işlevleri sıraya alma 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 ekleme çağrınız, önekli bir kod tabanını hedefliyorsa keşfedilen işlev adı da önekli olur (ör. orders-syncBigQuery). Değiştirme işlevi kiti örneğini inceleme ve yükleme ile İşlev kiti olarak test etme başlıklı makalelere bakın.

6. Gerekli API'leri ve IAM rollerini bildirme

Uzantınızın IAM ve API gereksinimlerini extension.yaml dışına taşıyıp kodun içine alı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üvenlik ile Firebase KSA, kod tabanı için yönetilen bir çalışma zamanı hizmet hesabı oluşturur veya günceller ve bu hesaba, bildirilen tüm 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ıza bildirin.

Çalışma örneği: Cloud Firestore'dan BigQuery'a yayın yapma

Önce. extension.yaml içinde belirtilir. Uzantılar çalışma zamanı, API'yi etkinleştirmiş ve rolleri yönetilen bir hesaba vermiştir:

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

Sonra. requiresAPI ve requiresRole ile kodda belirtilir:

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 içinde herhangi bir değişiklik yapılmasına gerek kalmadan Uzantılar tarafından gerçekleştiriliyordu. Bunu kodunuzda koşullu olarak yapabilirsiniz. Böylece kit, yalnızca özel bir Eventarc kanalı kullanıldığında bu izinleri 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üyle ilgili dikkat çekici girişleri dönüştürme

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

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

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 işlemi başarısız olursa kullanıcılarınızın bu işlemleri manuel olarak yeniden çalıştırması gerekebilir:

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

Çalışma örneği: Cloud Firestore'dan BigQuery'a yayın yapma

Önce. Uzantılar çalışma zamanı tarafından desteklenen extension.yaml içindeki lifecycleEvents:

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

Sonra. Kodda belirtilir. Görev, ilk dağıtımda BigQuery sağlar:

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

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

Sağlama işlemi, aynı sonucu veren bir işlemdir. Bu nedenle, yeniden çalıştırma işlemi veri kümesini, tabloyu ve görünümleri uzlaştırır. 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 sırlar ve mevcut sır değerlerinin nasıl taşınacağı.
  • Paketin requiresRole(...) ile bildirdiği IAM rolleri.
  • Paketin etkinleştirdiği veya gerektirdiği Google API'leri.
  • Paketin bildirdiği yaşam döngüsü kancaları ve bunların nasıl manuel olarak yeniden çalıştırılacağı.
  • Faturalandırma notları.
  • Orijinal uzantıya kıyasla ne değişti?
  • Paketin örnek kimliğini (CLI tarafından ayarlanan FIREBASE_KIT_INSTANCE_ID) nasıl aldığı ve tüm örnek işlevlerinin kit-<instanceId>- önekiyle dağıtıldığı.

Çalışma örneği: Cloud Firestore'dan BigQuery'a yayın yapma

README paketi, "ne değişti" tablosunu gönderir:

Endişe Uzantı olarak @firebase-function-kits/firestore-bigquery-export olarak
Yapılandırma Uzantı parametreleri Cloud Functions, .env üzerinden parametreler
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ılara göre yaşam döngüsü görevi afterFirstDeploy / afterRedeploy görev
İşlev adları ext-<instanceId>-fsexportbigquery fsexportbigquery (isteğe bağlı olarak önekli)
Örnek Kimliği EXT_INSTANCE_ID uzantılar tarafından yerleştirilen FIREBASE_KIT_INSTANCE_ID, KSA tarafından firebase.json tarihinden itibaren ayarlanır.

9. 2. nesil işlevinizi test etme

Artık, dağıtıldığında uzantınızın yeni yüklenmesiyle aynı şekilde çalışan 2. nesil bir işleviniz olmalıdır. Bir sonraki adım, bu süreçte yanlışlıkla ortaya çıkan sorunları doğrulayıp düzeltmektir.

Varsayılan bölge veya CPU gibi genel seçenekleri ayarlamak için setGlobalOptions'ı çağırmak istiyorsanız bunu yalnızca kitinizi bağımsız 2. nesil işlev olarak dağıtırken yapmanız gerekir. 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. Bu işlem iki kez gerçekleşirse kullanıcılar uyarı alır. 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ülmüş 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 daha önce bir test projesi oluşturduysanız aşağıdaki komutu çalıştırın:

firebase deploy --only functions

Parametre değerlerini isteyen sonuçtaki sihirbazı, uzantı için Firebase konsolundaki kurulum formunu doldurmuş gibi doldurun.

Çalışma örneği: Cloud Firestore'dan BigQuery'a yayın yapma

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

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

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

    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 DELETE etkinliği eklenir.

    Tek bir dokümanın tüm geçmişini şu yöntemlerle 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 farklılıklar:

  • Tetikleyici, fsexportbigquery (tipik bir 2. nesil işlev olarak dağıtılırken ve kit olarak dağıtılmazken ön ek yok) olarak dağıtılır, ext-<instanceId>-fsexportbigquery olarak dağıtılmaz. Bu adı Cloud Functions kontrol panelinde ve günlüklerde bulun.
  • Kodunuz artık Firebase Local Emulator Suite'da normal işlevler gibi çalışıyor. Parametrelerin değerini, emülatörde kullanılacak şekilde .env.local ile ayarlayabilirsiniz. Ayrıca, Birim testi Cloud Functions bölümünde açıklandığı gibi firebase-functions-test SDK'sını kullanarak kodunuzun birim testini de yapabilirsiniz.
  • Artık uzantılar çalışma zamanı tarafından sağlama yapılmıyor. 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, yinelemeli olduğundan yeniden çalıştırıldığında veri kümesi, tablo ve görünümler uzlaştırılır.
  • Parametre değerleri yükleme formundan değil .env kaynağından 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şlevlere dönüşümünüzü doğruladıktan sonra, aşağıdaki kılavuzlardan birini kullanarak uçtan uca test için npm'ye yayın adayı yayınlayabilirsiniz:

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

Öncelikle 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, varsayılan latest etiketiyle yükleme yapan kullanıcılara tamamlanmamış bir paket sunmadan gerçek yükleme akışını kayıt defterine göre test etmenize olanak tanır.

Yayınlamadan önce:

  1. Bir paket adı seçin. Hem kapsamlı hem de kapsamlı olmayan adlar çalışır (yukarıdaki kılavuzlara bakın). Kapsamlı paketlerin varsayılan olarak gizli olduğunu unutmayın. Bu nedenle, --access public iletin.
  2. Hangi ürünlerin gönderileceğini oluşturun ve kontrol edin. main ve types, derlenmiş çıktınızı ( çalışan örneğimizdeki lib/) gösterir. Bu nedenle, 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ı engeller.

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

{
  "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 öğesinin hiçbir zaman latest öğesinin üzerine yazmamasını sağlar.

Sürüm adayı oluşturma:

Örneğin, sürümü yerel olarak 0.0.2-rc.3'dan 0.0.2-rc.4'ye yükseltmek için (package.json, depo kökündeyse bu işlem Git'te commit ve etiketleme yapar):

npm version prerelease --preid rc

Sürüm adayını yayınlamak ve @your-org/your-kit@0.0.2-rc.4'yı next etiketi altında npm'ye 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ı bir 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: Paketinizle birlikte bir npm-shrinkwrap.json dosyası eklemenizi önemle tavsiye ederiz. Aksi takdirde KSA, yükleme sırasında kullanıcıları uyarır. Bu özellik, kullanıcıların test ettiğiniz bağımlılıkları kullanmasını sağlar ve tedarik zinciri saldırılarına karşı korunmaya yardımcı olur. Ancak, Cloud Functions derlemesi (npm ci) sırasında da dahil olmak üzere, kullanıcılarınızın projelerinde shrinkwrap aynen uygulanır. Bu durumda, yalnızca geliştiricilere yönelik girişler EBADPLATFORM ile başarısız olabilir. Yayınlanan shrinkwrap kopyasından "dev": true girişlerini ve devDependencies öğelerini kaldırmanız gerekebilir.

Çalışma örneği: Cloud Firestore'dan BigQuery'a yayın yapma

Dördüncü sürüm adayı yayınlandığında kitteki 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 tek depoda bulunduğunu unutmayın. Bu nedenle, npm kayıt bağlantısının doğru klasöre yönlendirilmesi için repository.directory eklemeniz ö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 >= 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 işlem, paketinizi npm'den indirir, kitiniz için yeni bir kaynak dizininde kurar ve ilk örneği uzantı yükleme akışına benzer şekilde yapılandırma konusunda size yol gösterir. Paketinizi yerel olarak yükleyip kurduktan sonra Google Cloud projenizde kaynak oluşturmak için dağıtım yapın:

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

Yüklemeden sonra Firebase CLI, yükleme sırasında seçtiğiniz tam örnek kimliğiyle benzer bir dağıtım komutu yazdırır.

9. adım bölümündeki talimatları kullanarak kitinizi tekrar doğrulayın. 2. nesil işlevinizi test edin. Artık kitleri kullanarak dağıtım yaptığınız için işlevleriniz kit-<instance-id>-<method-name> ön ekiyle adlandırılıyor. Bu sayede, kitler birden fazla örneğe sahip olabilir ve aynı işlevi bir projede birden çok kez dağıtabilir. Her örnek benzersiz bir ada sahiptir.

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

Çalışan bir uzantı örneği oluşturabilir ve ardından kullanıcı taşıma kılavuzunu (firebase ext:migrate --package veya işlev kiti CLI komutlarını kullanarak) kullanarak işlev kitinizi taşıma yerine geçecek şekilde test etmeyi tamamlayabilirsiniz.

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

İşlev kiti değiştirme işleminiz tamamlanıp kullanıcıların geçmesi gereken bir npm paketi olarak kullanıma sunulduğunda hem kullanıcılarınızı hem de Google'ı bu resmi değiştirme işlemi 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ı README'lerini <!-- FIREBASE_EXTENSION_REPLACEMENT: extension="firebase/firestore-bigquery-export" package="@firebase-function-kits/firestore-bigquery-export" --> gibi yorumlar için tarar ve firebase-tools deposunda replacements.json olarak depolanan resmi yedek kayıt defterimizi doldurmak için bu bilgileri kullanır. Uzantınız için hangi README.md öğelerinin taranacağını görmek üzere replacements.json işaretini de kontrol edebilirsiniz. Resmi yedek listesi haftalık olarak güncellenir.

Çalışma örneği: Cloud Firestore'dan BigQuery'a yayın yapma

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.