Firebase एक्सटेंशन को Cloud Functions पर माइग्रेट करना

इस गाइड में बताया गया है कि अपने एक्सटेंशन को बंद किए जा चुके Firebase Extensions एनवायरमेंट से, ऐसे फ़ंक्शन में कैसे माइग्रेट करें जिसे आपके उपयोगकर्ता, Firebase (दूसरी जनरेशन) के कोडबेस के लिए अपने Cloud Functions में इंस्टॉल और डिप्लॉय करते हैं.

हमारा सुझाव है कि आप माइग्रेशन के लिए इस पाथ का इस्तेमाल करें. Firebase, npm के आधिकारिक एक्सटेंशन की सूची बनाए रखेगा. इस गाइड में, आपको अपना एक्सटेंशन बनाने का तरीका बताया गया है.

इस पूरी गाइड में, Stream Cloud Firestore to BigQuery एक्सटेंशन (firestore-bigquery-export) का इस्तेमाल एक उदाहरण के तौर पर किया गया है. हर सेक्शन के आखिर में, हल किया गया उदाहरण दिया गया है. इससे पता चलता है कि माइग्रेशन से पहले एक्सटेंशन कैसा दिखता था और @firebase-function-kits/firestore-bigquery-export पैकेज के तौर पर माइग्रेट होने के बाद कैसा दिखता है.

एक्सटेंशन माइग्रेट करने के बारे में ज़्यादा जानकारी और मदद पाने के लिए साइन अप करें

अगर आपको Firebase Extensions से माइग्रेट करने के तरीके के बारे में कोई सवाल पूछना है, तो हमें firebase-extensions-migrator-support-external@google.com पर संपर्क करें. हम इस ग्रुप को भी ईमेल करेंगे, क्योंकि हम गाइड को अपडेट कर रहे हैं. इसमें 2nd gen फ़ंक्शन को पैकेज करने, टेस्ट करने, और डिस्ट्रिब्यूट करने के बारे में ज़्यादा जानकारी होगी.

इस ग्रुप में शामिल होने के लिए, firebase-extensions-migrator-support-external+subscribe@google.com पर मैसेज भेजें. इसके बाद, आपको सदस्यता के अनुरोध वाला ईमेल मिलेगा. आपको उस ईमेल का जवाब देना होगा. "इस ग्रुप में शामिल हों" बटन पर क्लिक न करें.

शुरू करने से पहले

इस माइग्रेशन को लिखकर पूरा करने के लिए, आपको Cloud Functions की इन सुविधाओं का इस्तेमाल करना होगा:

  • पैरामीटर के साथ कॉन्फ़िगरेशन. extension.yaml में एलान किया गया हर पैरामीटर, आपके पैकेज कोड में एक तय पैरामीटर बन जाता है.

  • आईएएम की भूमिकाओं और ज़रूरी एपीआई के बारे में एलान करना. extension.yaml में तय की गई हर भूमिका, requiresRole(...) कॉल बन जाती है. साथ ही, हर एपीआई आपके पैकेज कोड में requiresAPI(...) कॉल बन जाता है. डप्लॉय करने के समय, Firebase सीएलआई, मैनेज किए जा रहे रनटाइम सेवा खाते को बताई गई भूमिकाएं असाइन करता है. साथ ही, आपकी ओर से बताए गए एपीआई चालू करता है.

  • Cloud Functions कोडबेस के लिए लाइफ़साइकल इवेंट. Cloud Functions कोडबेस अब लाइफ़साइकल इवेंट के साथ काम करते हैं. ये Firebase Extensions के जैसे ही होते हैं. लाइफ़साइकल हुक afterFirstDeploy(...) और afterRedeploy(...) की मदद से, इंस्टॉल और अपडेट के समय के सेटअप का एलान करें. ये, lifecycleEvents की जगह लेते हैं जिन्हें extension.yaml में डिक्लेयर किया जाता है.

Firebase Extensions सोर्स को 2nd gen फ़ंक्शन पर माइग्रेट करना

(ज़रूरी नहीं) Firebase एजेंट स्किल की मदद से अपने-आप माइग्रेट होने की सुविधा

पहले से आठवें चरण (इन्वेंट्री के संसाधन, ट्रिगर अपग्रेड, पैरामीटर और सीक्रेट कन्वर्ज़न, डिक्लेरेटिव आईएएम, लाइफ़साइकल हुक, और पैकेज README जनरेट करना) को ऑटोमेट किया जा सकता है. इसके लिए, आधिकारिक extension-to-functions-codebase एआई एजेंट स्किल का इस्तेमाल करें.

स्किल इंस्टॉल करना

अगर आपने या आपके एआई कोडिंग असिस्टेंट (Firebase में Gemini, Cursor, Claude Code, GitHub Copilot) ने अब तक यह स्किल इंस्टॉल नहीं की है, तो skills CLI का इस्तेमाल करके यह कमांड चलाएं:

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

आपके प्रोजेक्ट में स्किल इंस्टॉल होने के बाद, एआई कोडिंग असिस्टेंट, माइग्रेशन के नियमों और बदलाव के चरणों का अपने-आप पालन करता है. इस प्रॉम्प्ट का इस्तेमाल किया जा सकता है:

"कृपया इस Firebase एक्सटेंशन को पब्लिश किए जा सकने वाले दूसरे जनरेशन के फ़ंक्शन किट पैकेज में माइग्रेट करें. इसके लिए, extension-to-functions-codebase स्किल में दिए गए निर्देशों का पालन करें."

1. एक्सटेंशन की इन्वेंट्री

अपने एक्सटेंशन की इन्वेंट्री बनाकर शुरुआत करें: एक्सटेंशन में मौजूद हर चीज़ की पूरी सूची बनाएं. जैसे, एक्सटेंशन में मौजूद फ़ाइलें, शिप की गई फ़ाइलें, और दस्तावेज़. इससे यह पक्का किया जा सकेगा कि 2nd gen फ़ंक्शन में हर व्यवहार का डेस्टिनेशन तय हो और डेटा दूसरी जगह भेजने के दौरान कोई भी फ़ाइल न छूटे.

यहां दी गई हर जानकारी को पढ़ें और देखें कि आपको क्या मिलता है:

  • extension.yaml, जिसमें आपके पैरामीटर, फ़ंक्शन, इवेंट, आईएएम भूमिकाएं, ज़रूरी एपीआई, सीक्रेट, और लाइफ़साइकल हुक शामिल होते हैं.

  • functions/, जिसमें आपके फ़ंक्शन का कोड, डिपेंडेंसी, बिल्ड कॉन्फ़िगरेशन, ट्रिगर, और टास्क क्यू फ़ंक्शन शामिल होते हैं.

  • README.md, PREINSTALL.md, और POSTINSTALL.md, जिनमें सेटअप करने के चरण, चेतावनियां, और बिलिंग से जुड़े नोट शामिल हैं.

  • scripts/. इसमें इंपोर्ट, बैकफ़िल, IAM, रिपेयर या माइग्रेशन की सुविधाएं शामिल होती हैं. साथ ही, इसमें एक्सटेंशन के साथ शिप की जाने वाली अन्य टूलिंग भी शामिल होती है.

इसके बाद, extension.yaml में मौजूद हर आइटम के लिए, यह तय करें कि उसे npm पैकेज में कहां रखना है:

  • उपयोगकर्ता के कॉन्फ़िगरेशन को Cloud Functions पैरामीटर में बदलें (चौथा चरण).

  • सीक्रेट को Cloud Functions सीक्रेट में बदलें (चौथा चरण).

  • IAM की भूमिकाओं को requiresRole(...) एलान (छठा चरण) में बदलें.

  • ज़रूरी Google API को requiresAPI(...) एलान में बदलें. ऐसा सिर्फ़ तब करें, जब ज़रूरी हो (छठा चरण).

  • इंस्टॉल और अपडेट करने के हुक को afterFirstDeploy(...) और afterRedeploy(...) के एलान में बदलें (सातवां चरण).

  • उदाहरण के आईडी को EXT_INSTANCE_ID से FIREBASE_KIT_INSTANCE_ID में बदलें (चौथा चरण).

उदाहरण: स्ट्रीम Cloud Firestore से BigQuery

firestore-bigquery-export/extension.yaml और functions/ पढ़ने पर, यह इन्वेंट्री मिलती है:

extension.yaml में गिनती / वैल्यू यह कहां जाता है
params 25 (COLLECTION_PATH, DATASET_ID, TABLE_ID, DATASET_LOCATION, VIEW_TYPE, …) Cloud Functions params (चौथा चरण)
apis bigquery.googleapis.com requiresAPI(...) (छठा चरण)
roles bigquery.dataEditor, datastore.user, bigquery.user requiresRole(...) (छठा चरण)
resources एक इवेंट ट्रिगर (fsexportbigquery) + टास्क क्यू फ़ंक्शन (initBigQuerySync, setupBigQuerySync) एक्सपोर्ट किए गए पैकेज फ़ंक्शन (तीसरा चरण)
lifecycleEvents onInstall → initBigQuerySync; onUpdate / onConfigure → setupBigQuerySync afterFirstDeploy / afterRedeploy (सातवां चरण)
इंस्टेंस आईडी इस्तेमाल नहीं किया गया (कोई EXT_INSTANCE_ID नहीं पढ़ा गया) माइग्रेट करने के लिए कुछ भी नहीं है
scripts/ import/ (बैकफ़िल), gen-schema-view/ इन्हें स्क्रिप्ट के तौर पर सेव किया जाता है (ये इस दायरे में नहीं आते)

विश्लेषण. एक्सटेंशन, किसी भी type: secret पैरामीटर का एलान नहीं करता है. इसलिए, चौथे चरण में सीक्रेट के लिए माइग्रेट करने के लिए कुछ भी नहीं है. इवेंट ट्रिगर पहले से ही दूसरी जनरेशन का है. सिर्फ़ टास्क क्यू फ़ंक्शन अब भी पहली जनरेशन के हैं (तीसरे चरण में काम के).

2. package.json फ़ाइल अपडेट करना

अपने एक्सटेंशन की package.json फ़ाइल अपडेट करें. अगर आपको सिर्फ़ एक एक्सटेंशन माइग्रेट करना है, तो यह रूट package.json हो सकता है. अगर आपको एक ही रिपॉज़िटरी में कई एक्सटेंशन माइग्रेट करने हैं, तो हर एक्सटेंशन को उसका अपना पैकेज दें.

एसडीके के कम से कम वर्शन: firebase-functions >= 7.4.0 और firebase-admin >= 14.2.0 को डिपेंडेंसी के तौर पर एलान करें. firebase-functions के अपने वर्शन को भी पीयर डिपेंडेंसी के तौर पर एलान करें, ताकि आपके उपयोगकर्ताओं के Cloud Functions प्रोजेक्ट में एसडीके का वही वर्शन हो जिसके साथ आपकी लाइब्रेरी लिखी गई थी.

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

उदाहरण: स्ट्रीम Cloud Firestore से BigQuery

पहले. एक्सटेंशन का functions/package.json निजी होता है. इसमें एक्सटेंशन आईडी का नाम होता है और firebase-functions को सीधे तौर पर डिपेंडेंसी के तौर पर दिखाया जाता है:

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

इसके बाद. पब्लिश किया जा सकने वाला पैकेज: स्कोप किया गया नाम, exports मैप, और firebase-functions को peerDependencies में ले जाया गया:

{
  "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. 1st gen से 2nd gen में अपग्रेड करने के फ़ंक्शन

अगर आपका एक्सटेंशन अब भी 1st gen फ़ंक्शन एक्सपोर्ट करता है, तो हर ट्रिगर को 2nd gen के बराबर में बदलें. firebase-functions/... मॉड्यूल से इंपोर्ट करें और ट्रिगर के विकल्पों में रनटाइम सेटिंग पास करें.

Cloud Functions दूसरी जनरेशन के Nest Hub Max को अपग्रेड करने से जुड़ी गाइड देखें. खास तौर पर, 2nd gen पैच किए गए इवेंट डेस्ट्रक्चरिंग का इस्तेमाल करके, फिर से लिखने की कोशिशों को कम किया जा सकता है. साथ ही, फ़ंक्शन लॉजिक को फिर से लिखने से बचा जा सकता है. इसकी वजह यह है कि 2nd gen एसडीके, v1 पैरामीटर को इवेंट ऑब्जेक्ट में फ़ील्ड के तौर पर दिखाता है. इससे आपको डेस्ट्रक्चर्ड/नाम वाले पैरामीटर का इस्तेमाल करने और अपने कारोबारी नियम को पहले जैसा रखने की सुविधा मिलती है.

पहले. पहली जनरेशन:

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

इसके बाद. दूसरी जनरेशन:

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

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

पहली जनरेशन और दूसरी जनरेशन के फ़ंक्शन के बीच के अंतर की पूरी सूची देखने के लिए, Cloud Functions वर्शन की तुलना करें.

4. एक्सटेंशन पैरामीटर और सीक्रेट को बदलना

Params

extension.yaml में एलान किया गया हर पैरामीटर, Cloud Functions param बन जाता है.

डायरेक्ट एनवायरमेंट से मिले डेटा को इस तरह से बदलें:

const collectionPath = process.env.COLLECTION_PATH;

Cloud Functions पैरामीटर में:

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

हैंडलर में मौजूद स्ट्रिंग को पढ़ने के लिए collectionPath.value() का इस्तेमाल करें. collectionPath का इस्तेमाल सीधे तौर पर उस जगह पर करें जहां प्लेसहोल्डर की ज़रूरत होती है. जैसे, फ़ंक्शन ट्रिगर पाथ.

Firebase सीएलआई, आपके पैरामीटर का पता लगाता है और .env, .env.<projectId> से उनकी वैल्यू पढ़ता है. इसके अलावा, यह डिप्लॉयमेंट के दौरान आपके उपयोगकर्ताओं को सूचनाएं भेजता है. पैरामीटर के नाम वही रखें, ताकि मौजूदा इंस्टॉलेशन से वैल्यू ट्रांसफ़र हो सकें.

यह ज़रूरी है कि आप अपने कोड में बताए गए पैरामीटर के नाम बिल्कुल भी न बदलें. एक्सटेंशन माइग्रेशन के दौरान, असली उपयोगकर्ता के पैरामीटर की मौजूदा वैल्यू अपने-आप सेव हो जाती हैं. हालांकि, ऐसा सिर्फ़ तब होता है, जब पैरामीटर के नाम में कोई बदलाव न किया गया हो.

उदाहरण: Cloud Firestore से BigQuery तक स्ट्रीम करना

पहले. extension.yaml में एलान किया गया पैरामीटर, जिसे config.ts में रॉ एनवायरमेंट वैरिएबल के तौर पर पढ़ा जाता है:

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

इसके बाद. एक defineString; सीएलआई इसका पता लगाता है और .env से पढ़ता है:

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

पैराम का नाम नहीं बदला गया है. इसलिए, मौजूदा .env काम करता रहेगा.

इंस्टेंस आईडी

एक्सटेंशन, अपने इंस्टेंस आईडी को EXT_INSTANCE_ID से पढ़ते हैं. इसे एक्सटेंशन रनटाइम इंजेक्ट करता है. फ़ंक्शन किट, अपने इंस्टेंस आईडी को FIREBASE_KIT_INSTANCE_ID से पढ़ती हैं. Firebase CLI, हर किट इंस्टेंस के लिए इसे सेट करता है. यह इंस्टेंस के आईडी को firebase.json में मौजूद instances मैप में इंस्टेंस की कुंजी के तौर पर सेट करता है. सीएलआई, इसे डिप्लॉय करने के दौरान, एम्युलेटर में, और डिप्लॉय किए गए फ़ंक्शन के लिए उपलब्ध कराता है.

इंस्टेंस आईडी कोई पैरामीटर नहीं है. इसलिए, इसे defineString के साथ न जोड़ें. दरअसल, FIREBASE_..., .env फ़ाइलों में रिज़र्व किया गया प्रीफ़िक्स है. इसलिए, उपयोगकर्ता इसे सेट नहीं कर पाएंगे या इसे बदल नहीं पाएंगे. सीएलआई से इंजेक्ट की गई वैल्यू, पैरामीटर सिस्टम को नहीं दिखती हैं. इसे सीधे एनवायरमेंट से पढ़ें:

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

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

यह वैरिएबल सिर्फ़ तब सेट होगा, जब आपका पैकेज किट के तौर पर डिप्लॉय किया जाएगा. अगर आपका कोड, स्टैंडअलोन कोडबेस के तौर पर भी डिप्लॉय किया गया है (नौवां चरण देखें), तो इसे वैकल्पिक के तौर पर मानें या कोड मौजूद न होने पर, साफ़ तौर पर मैसेज दिखाएं. अगर आपके एक्सटेंशन ने इंस्टेंस आईडी को उपयोगकर्ता के लिए उपलब्ध पैरामीटर के तौर पर दिखाया है, तो आपको उस पैरामीटर को हटाना होगा. ऐसा इसलिए, क्योंकि अब Firebase CLI के पास उस पैरामीटर की वैल्यू है.

कामकाजी उदाहरण: उपयोगकर्ता का डेटा मिटाना

(स्ट्रीम Cloud Firestore से BigQuery एक्सटेंशन, अपने इंस्टेंस आईडी को नहीं पढ़ता. इसलिए, वहां माइग्रेट करने के लिए कुछ भी नहीं है. Delete User Data एक्सटेंशन, इसका इस्तेमाल अपने Pub/Sub विषयों के नाम रखने के लिए करता है.)

पहले. इसे config.ts में रॉ एनवायरमेंट वैरिएबल के तौर पर पढ़ा जाता है. इसमें ext- प्रीफ़िक्स होता है, जिसका इस्तेमाल एक्सटेंशन अपने संसाधनों के लिए करता है:

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

इसके बाद. FIREBASE_KIT_INSTANCE_ID का सामान्य process.env, जिसका इस्तेमाल दो सामान्य पैरामीटर के लिए किया जाता है, ताकि उपयोगकर्ता विषय के नामों को बदल सकें:

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

डिफ़ॉल्ट वैल्यू खाली नहीं होनी चाहिए, क्योंकि ट्रिगर बाइंडिंग का पता इवेंट की पहचान के समय चलता है. डिफ़ॉल्ट रूप से खाली वैल्यू को डिप्लॉय मेनिफ़ेस्ट में विषय के नाम के तौर पर लिखा जाएगा. यह किट, किट के कॉन्टेक्स्ट से बाहर चलने से भी बचाव करती है. अगर वैरिएबल मौजूद नहीं है, तो मॉड्यूल-लेवल की डिफ़ॉल्ट वैल्यू kit-undefined-discovery पर सेट हो जाएगी. इसलिए, कॉन्फ़िगरेशन लोडर, गड़बड़ी की जानकारी देने वाले मैसेज के साथ काम नहीं करेगा:

// ...
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."
  );
}
// ...

यह जांच तब की जाती है, जब कोई हैंडलर पहली बार अपने कॉन्फ़िगरेशन को हल करता है. इसलिए, किसी वैरिएबल के मौजूद न होने पर, kit-undefined-* विषयों से चुपचाप बाइंड होने के बजाय, रनटाइम की गड़बड़ी साफ़ तौर पर दिखती है. अगर आपको डिप्लॉयमेंट को अस्वीकार करना है, तो मॉड्यूल के स्कोप पर जांच करें, ताकि यह जांच, खोज के दौरान हो सके. सीएलआई, इंस्टेंस आईडी को firebase.json से हासिल करता है. इसलिए, कॉन्फ़िगर किया जा सकने वाला INSTANCE_ID नहीं होता है. साथ ही, कई इंस्टेंस में सिंक करने के लिए कुछ भी नहीं होता है.

सीक्रेट

extension.yaml में, type: secret की मदद से सीक्रेट तय किए जाते हैं. एक्सटेंशन रनटाइम, इन कुकी को सेव करता है और उन्हें बाइंड करता है, ताकि आपका एक्सटेंशन कोड सीधे process.env.PARAM_NAME को पढ़ सके. किसी सामान्य Cloud Functions कोडबेस में, हर सीक्रेट का एलान किया जाता है और उसे साफ़ तौर पर बाइंड किया जाता है:

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

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

आपके एक्सटेंशन को npm पैकेज/किट में माइग्रेट करने के बाद, सीक्रेट के रेफ़रंस को असली उपयोगकर्ता की .env फ़ाइल में मैनेज किया जाता है. यह ज़रूरी है कि आप अपने कोड में बताए गए सीक्रेट नामों को बिल्कुल भी न बदलें. माइग्रेशन के दौरान, असली उपयोगकर्ताओं के सीक्रेट को माइग्रेट किया जाता है.

काम करने का उदाहरण: Cloud Firestore से ईमेल ट्रिगर करना

पहले. MAIL_COLLECTION और SMTP_PASSWORD को config.ts में रॉ एनवायरमेंट वैरिएबल के तौर पर पढ़ा जाता है:

# 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,

इसके बाद. एक defineString और एक defineSecret; सीएलआई, दोनों का पता लगाता है और .env से पढ़ता है:

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. इंटरनल टास्क-कतार वाले कॉल माइग्रेट करना

कुछ एक्सटेंशन, Firebase Admin SDK का इस्तेमाल करके, अपने फ़ंक्शन कोड में मौजूद खुद की टास्क कतारों में काम जोड़ते हैं. यह, भेजे गए टास्क को पाने से अलग है. इसके बारे में अपग्रेड फ़ंक्शन और कन्वर्ज़न लाइफ़साइकल हुक सेक्शन में बताया गया है. यहां आपका कोड, प्रोड्यूसर है जो queue.enqueue(...) को कॉल करता है.

Admin SDK के पिछले वर्शन में, एक्सटेंशन को अपने एक्सटेंशन इंस्टेंस आईडी को दूसरे पैरामीटर के तौर पर पास करना होता था, ताकि उसी एक्सटेंशन में टास्क क्यू फ़ंक्शन को टारगेट किया जा सके. firebase-admin 14.2.0 से, इसकी ज़रूरत नहीं है और न ही इसे इस्तेमाल करने का सुझाव दिया जाता है. Task Queue API अब डिफ़ॉल्ट रूप से, एक ही कॉन्टेक्स्ट (उदाहरण के लिए, एक्सटेंशन या किट) में टास्क कतारों को टारगेट करता है. इस पैरामीटर को अपने कोड से हटाना सुरक्षित है. साथ ही, हम आपको ऐसा करने का सुझाव देते हैं. इसे एक्सटेंशन और स्टैंडअलोन फ़ंक्शन, दोनों के तौर पर इस्तेमाल किया जा सकता है. इस पैरामीटर को हटाने से, पोर्टेबिलिटी और फ़ॉरवर्ड कंपैटिबिलिटी (आने वाले समय में काम करने की क्षमता) बनी रहती है.

enqueue कॉल के बारे में बाकी सभी जानकारी पहले जैसी ही रहती है. जैसे, locations/<region>/functions/<name> रिसॉर्स पाथ, टास्क पेलोड, और फिर से कोशिश करने का लॉजिक.

Cloud Tasks का इस्तेमाल करके फ़ंक्शन को कतार में लगाने के बारे में ज़्यादा जानने के लिए, Cloud Tasks की मदद से फ़ंक्शन को कतार में लगाना लेख पढ़ें.

पहले. पहली जनरेशन का एक्सटेंशन:

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

इसके बाद. दूसरी जनरेशन का एक्सटेंशन:

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

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

अगर आपका enqueue कॉल, प्रीफ़िक्स किए गए कोड बेस को टारगेट करता है, तो खोजे गए फ़ंक्शन के नाम में भी प्रीफ़िक्स जोड़ा जाता है. उदाहरण के लिए, orders-syncBigQuery. बदलाव वाले फ़ंक्शन किट इंस्टेंस की समीक्षा करना और उसे इंस्टॉल करना और फ़ंक्शन किट के तौर पर टेस्ट करना लेख पढ़ें.

6. ज़रूरी एपीआई और IAM रोल के बारे में जानकारी देना

अपने एक्सटेंशन के IAM और एपीआई से जुड़ी ज़रूरी शर्तों को extension.yaml से हटाकर कोड में जोड़ें:

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, कोडबेस के लिए मैनेज किया गया रनटाइम सेवा खाता बनाता है या उसे अपडेट करता है. साथ ही, उसे सभी बताई गई भूमिकाओं का यूनीयन देता है. अपने उपयोगकर्ताओं के लिए एक ऐसा दस्तावेज़ बनाएं जिसमें यह बताया गया हो कि कोडबेस के सभी फ़ंक्शन, उन भूमिकाओं के साथ काम करते हैं. हालांकि, अगर फ़ाइनल एपीआई किसी छोटे मॉडल के साथ काम करता है, तो ऐसा नहीं होगा.

उदाहरण: Cloud Firestore से BigQuery तक स्ट्रीम करना

पहले. extension.yaml में बताया गया है; एक्सटेंशन के रनटाइम ने एपीआई चालू किया और मैनेज किए जा रहे खाते को भूमिकाएं असाइन कीं:

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

इसके बाद. कोड में requiresAPI और requiresRole के साथ यह जानकारी दी गई है:

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

7. लाइफ़साइकल हुक को बदलना

अगर आपका एक्सटेंशन getExtensions().runtime() (उदाहरण के लिए, setProcessingState या setFatalError) को कॉल करता है, तो उन कॉल को मिटा दें. ऐसा इसलिए, क्योंकि सामान्य तौर पर डिप्लॉय किए गए 2nd gen फ़ंक्शन से कॉल करने पर, वे गड़बड़ी दिखाते हैं. लाइफ़साइकल की स्थिति अब afterFirstDeploy और afterRedeploy से तय होती है. यहां इस स्थिति को ट्रैक नहीं किया जाता.

जब कोई उपयोगकर्ता किसी एक्सटेंशन को इंस्टॉल, अपडेट या फिर से कॉन्फ़िगर करता है, तब Firebase Extensions सेटअप चला सकता है. अपने npm पैकेज में, कोड में लाइफ़साइकल के बराबर की कार्रवाइयां घोषित करें.

एक बार सेटअप करने के लिए:

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

कॉन्फ़िगरेशन या कोड अपडेट के लिए:

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

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

लाइफ़साइकल की कार्रवाइयों को आइडेमपोटेंट बनाएं. अगर डिसपैच या एक्ज़ीक्यूट करने में गड़बड़ी होती है, तो आपके उपयोगकर्ताओं को उन्हें मैन्युअल तरीके से फिर से चलाना पड़ सकता है:

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

उदाहरण: स्ट्रीम Cloud Firestore से BigQuery

पहले. lifecycleEvents में extension.yaml, Extensions runtime की मदद से:

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

इसके बाद. कोड में बताया गया है; टास्क, पहली बार डिप्लॉय करने पर BigQuery उपलब्ध कराता है:

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

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

प्रोविज़निंग एक आइडेमपोटेंट ऑपरेशन है. इसलिए, इसे फिर से चलाने पर डेटासेट, टेबल, और व्यू को फिर से व्यवस्थित किया जाता है. उपयोगकर्ता, firebase functions:lifecycle:run afterFirstDeploy CODEBASE_NAME की मदद से मैन्युअल तरीके से फिर से चला सकते हैं.

8. उपयोगकर्ताओं के लिए दस्तावेज़ सेटअप करना

पैकेज का README लिखें. इसमें कम से कम यह जानकारी शामिल होनी चाहिए:

  • .env की वे वैल्यू जिनकी पैकेज को ज़रूरत होती है.
  • पैकेज के लिए ज़रूरी सीक्रेट और मौजूदा सीक्रेट वैल्यू माइग्रेट करने का तरीका.
  • पैकेज में requiresRole(...) के साथ बताई गई IAM भूमिकाएं.
  • Google के वे एपीआई जिन्हें पैकेज चालू करता है या जिनके लिए पैकेज की ज़रूरत होती है.
  • लाइफ़साइकल हुक, जिन्हें पैकेज डिक्लेयर करता है. साथ ही, उन्हें मैन्युअल तरीके से फिर से चलाने का तरीका.
  • बिलिंग नोट.
  • ओरिजनल एक्सटेंशन की तुलना में क्या बदलाव किया गया है.
  • पैकेज को उसका इंस्टेंस आईडी (FIREBASE_KIT_INSTANCE_ID सीएलआई से सेट किया गया) कैसे मिलता है और इंस्टेंस के सभी फ़ंक्शन, kit-<instanceId>- प्रीफ़िक्स के साथ डिप्लॉय किए जाते हैं.

उदाहरण: Cloud Firestore से BigQuery तक स्ट्रीम करना

पैकेज README में, "क्या बदला" टेबल की जानकारी शामिल होती है:

चिंता एक्सटेंशन के तौर पर @firebase-function-kits/firestore-bigquery-export के तौर पर
कॉन्फ़िगरेशन एक्सटेंशन पैरामीटर Cloud Functions के ज़रिए .env पैरामीटर
IAM एक्सटेंशन से मिली अनुमति requiresRole(...), डिप्लॉय करते समय लागू किया गया
प्रावधान एक्सटेंशन के ज़रिए लाइफ़साइकल टास्क afterFirstDeploy / afterRedeploy टास्क
फ़ंक्शन के नाम ext-<instanceId>-fsexportbigquery fsexportbigquery (ज़रूरी नहीं है कि इसमें प्रीफ़िक्स शामिल हो)
इंस्टेंस आईडी EXT_INSTANCE_ID एक्सटेंशन की मदद से डाला गया FIREBASE_KIT_INSTANCE_ID, जिसे सीएलआई ने firebase.json से सेट किया है

9. अपने 2nd gen फ़ंक्शन को टेस्ट करें

अब आपके पास 2nd gen फ़ंक्शन होना चाहिए. इसे डिप्लॉय करने पर, यह आपके एक्सटेंशन के नए इंस्टॉलेशन की तरह काम करता है. अगला चरण, पुष्टि करना और इस दौरान हुई किसी भी समस्या को ठीक करना है.

डिफ़ॉल्ट क्षेत्र या सीपीयू जैसे ग्लोबल विकल्प सेट करने के लिए, setGlobalOptions को कॉल करने की सुविधा सिर्फ़ तब उपलब्ध होती है, जब किट को स्टैंडअलोन दूसरी जनरेशन के फ़ंक्शन के तौर पर डिप्लॉय किया जा रहा हो. जब आपकी किट को npm पैकेज के तौर पर इंस्टॉल किया जाता है, तब आपके उपयोगकर्ता इन पैरामीटर को कॉन्फ़िगर करने के लिए, अपने रैपिंग कोड में setGlobalOptions को कॉल करते हैं. अगर ऐसा दो बार होता है, तो उन्हें चेतावनियां मिलेंगी. FIREBASE_KIT_INSTANCE_ID एनवायरमेंट वैरिएबल की जांच करके, इस कॉल को सुरक्षित किया जा सकता है:

import { setGlobalOptions } from "firebase-functions";

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

पक्का करें कि आपने firebase-tools >= 15.32.0 का इस्तेमाल किया हो. साथ ही, 2nd gen फ़ंक्शन को टेस्ट प्रोजेक्ट में डिप्लॉय किया हो. इसके अलावा, यह भी पक्का करें कि आपने फ़ंक्शन के व्यवहार की जांच करने के लिए, सही संसाधनों का इस्तेमाल किया हो. अगर आपने एक्सटेंशन की टेस्टिंग के लिए पहले से ही कोई टेस्ट प्रोजेक्ट सेट अप किया है, तो यह कमांड चलाएं:

firebase deploy --only functions

इसके बाद, आपको एक विज़र्ड दिखेगा. इसमें आपको पैरामीटर की वैल्यू डालनी होंगी. इन्हें उसी तरह डालें जिस तरह आपने एक्सटेंशन के लिए, Firebase कंसोल में इंस्टॉलेशन फ़ॉर्म भरा था.

उदाहरण: स्ट्रीम Cloud Firestore से BigQuery

हम Cloud Firestore से BigQuery तक सिंक होने वाले डेटा के एंड-टू-एंड एन्क्रिप्शन की पुष्टि करते हैं:

  1. Firebase कंसोल के Cloud Firestore पेज पर, वह कलेक्शन बनाएं जिसे आपने COLLECTION_PATH (users) के तौर पर सेट किया है. ऐसा तब करें, जब वह कलेक्शन पहले से मौजूद न हो.
  2. bigquery-mirror-test नाम का एक दस्तावेज़ बनाएं. इसमें कोई भी फ़ील्ड और वैल्यू शामिल करें.
  3. Google Cloud कंसोल के BigQuery पेज में, बदलाव के रॉ डेटा वाली टेबल के लिए क्वेरी करें. इसमें दस्तावेज़ बनाने की जानकारी देने वाली एक लाइन होनी चाहिए:

    SELECT * FROM `PROJECT_ID.analytics.users_raw_changelog`
    
  4. लेटेस्ट व्यू के लिए क्वेरी करें. इससे मौजूद दस्तावेज़ (bigquery-mirror-test) के लिए, बदलाव से जुड़ा सबसे नया इवेंट दिखेगा:

    SELECT * FROM `PROJECT_ID.analytics.users_raw_latest`
    
  5. Cloud Firestore में मौजूद bigquery-mirror-test दस्तावेज़ को मिटाओ. यह बदलाव, हाल ही के बदलावों की सूची से हट जाता है. साथ ही, DELETE इवेंट को बदलाव के लॉग वाली टेबल में जोड़ दिया जाता है.

    किसी एक दस्तावेज़ का पूरा इतिहास देखने के लिए, इन तरीकों का इस्तेमाल किया जा सकता है:

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

एक्सटेंशन की टेस्टिंग से जुड़े अंतर:

  • ट्रिगर को fsexportbigquery के तौर पर डिप्लॉय किया जाता है. अगर इसे सामान्य दूसरी जनरेशन के फ़ंक्शन के तौर पर डिप्लॉय किया जाता है और यह किट नहीं है, तो इसमें कोई प्रीफ़िक्स नहीं होता. इसे ext-<instanceId>-fsexportbigquery के तौर पर डिप्लॉय नहीं किया जाता. Cloud Functionsडैशबोर्ड और लॉग में उस नाम को ढूंढें.
  • अब आपका कोड, Firebase Local Emulator Suite में सामान्य फ़ंक्शन के तौर पर काम करता है. .env.local की मदद से, एम्युलेटर में इस्तेमाल किए जाने वाले पैरामीटर की वैल्यू सेट की जा सकती है. firebase-functions-test SDK टूल का इस्तेमाल करके भी, अपने कोड की यूनिट टेस्ट की जा सकती है. इसके बारे में Cloud Functions की यूनिट टेस्टिंग में बताया गया है.
  • अब एक्सटेंशन रनटाइम के ज़रिए डिवाइस सेट अप नहीं किया जाता. अगर डिप्लॉय करने के बाद, बदलाव की जानकारी वाली टेबल मौजूद नहीं है, तो सेटअप टास्क को मैन्युअल तरीके से फिर से चलाएं: firebase functions:lifecycle:run afterFirstDeploy CODEBASE_NAME. टास्क को बार-बार चलाया जा सकता है. इसलिए, इसे फिर से चलाने पर डेटासेट, टेबल, और व्यू को फिर से व्यवस्थित किया जा सकता है.
  • पैरामीटर की वैल्यू, इंस्टॉलेशन फ़ॉर्म के बजाय .env से मिलती हैं. इसलिए, .env पूरा होने के बाद, firebase deploy को फिर से चलाने पर कोई इंटरैक्शन नहीं होता.

10. npm पर फ़ंक्शन किट पब्लिश करना

एक्सटेंशन से 2nd gen फ़ंक्शन में कन्वर्ज़न की पुष्टि हो जाने के बाद, npm पर रिलीज़ कैंडिडेट पब्लिश किया जा सकता है. इससे, यहां दिए गए किसी एक गाइड का इस्तेमाल करके, एंड-टू-एंड टेस्टिंग की जा सकती है:

npm पर किट पब्लिश होने के बाद, उसे firebase functions:kits:install की मदद से इंस्टॉल किया जा सकता है. साथ ही, उसे आपके एक्सटेंशन के आधिकारिक विकल्प के तौर पर लिस्ट किया जा सकता है.

हमारा सुझाव है कि सबसे पहले रिलीज़ कैंडिडेट को पब्लिश करें. किट, पैकेज के नाम और वर्शन के हिसाब से इंस्टॉल की जाती हैं. इसलिए, प्री-रिलीज़ की मदद से, रजिस्ट्री के हिसाब से इंस्टॉल करने के असली फ़्लो को टेस्ट किया जा सकता है. इससे, उन उपयोगकर्ताओं को अधूरा पैकेज नहीं दिखता जो डिफ़ॉल्ट latest टैग का इस्तेमाल करके इंस्टॉल करते हैं.

पब्लिश करने से पहले:

  1. पैकेज का नाम चुनें. स्कोप किए गए और स्कोप नहीं किए गए, दोनों तरह के नाम काम करते हैं. इसके बारे में जानने के लिए, ऊपर दिए गए दिशा-निर्देश देखें. ध्यान दें कि स्कोप किए गए पैकेज डिफ़ॉल्ट रूप से निजी होते हैं. इसलिए, --access public पास करें.
  2. शिपिंग के लिए उपलब्ध प्रॉडक्ट बनाएँ और देखें. main और types, आपके कंपाइल किए गए आउटपुट (हमारे उदाहरण में lib/) की ओर इशारा करते हैं. इसलिए, उस डायरेक्ट्री को पब्लिश की गई टार फ़ाइल में शामिल किया जाना चाहिए. .npmignore या files अनुमति वाली सूची का इस्तेमाल करें. साथ ही, npm pack --dry-run की मदद से नतीजे की जांच करें. prepublishOnly स्क्रिप्ट, आपके बिल्ड को चलाती है. इससे पुराना आउटपुट पब्लिश नहीं होता.

package.json में किए गए ये बदलाव, पब्लिशिंग को डिफ़ॉल्ट रूप से सुरक्षित बनाते हैं:

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

"publishConfig": { "tag": "next" } फ़ील्ड यह पक्का करता है कि सामान्य npm publish कभी भी latest को न बदले.

रिलीज़ कैंडिडेट को कट करना:

उदाहरण के लिए, 0.0.2-rc.3 से 0.0.2-rc.4 तक वर्शन को स्थानीय तौर पर बढ़ाने के लिए (अगर package.json, रिपॉज़िटरी रूट पर है, तो यह Git में कमिट और टैग करता है):

npm version prerelease --preid rc

रिलीज़ कैंडिडेट को पब्लिश करने और @your-org/your-kit@0.0.2-rc.4 को next टैग के तहत npm पर रजिस्टर करने के लिए:

npm publish

npm वेबसाइट पर नया वर्शन दिखने में कुछ मिनट लग सकते हैं; npm view सीधे तौर पर रजिस्ट्री से डेटा पढ़ता है:

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

इस गाइड के 11वें चरण और 12वें चरण को पूरा करने के बाद, पैकेज को स्टेबल वर्शन पर प्रमोट किया जा सकता है:

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

npm-shrinkwrap.json के बारे में जानकारी: हमारा सुझाव है कि आप अपने पैकेज में npm-shrinkwrap.json फ़ाइल शामिल करें. अगर ऐसा नहीं किया जाता है, तो सीएलआई, उपयोगकर्ताओं को इंस्टॉल करने के दौरान चेतावनी देता है. इससे यह पक्का होता है कि उपयोगकर्ता, उन डिपेंडेंसी का इस्तेमाल करें जिनकी आपने जांच की है. साथ ही, इससे सप्लाई चेन के हमलों से सुरक्षा मिलती है. हालांकि, श्रिंक रैप को आपके उपयोगकर्ताओं के प्रोजेक्ट में हूबहू लागू किया जाता है. इसमें Cloud Functionsबिल्ड (npm ci) के दौरान भी लागू किया जाता है. इस दौरान, सिर्फ़ डेवलपर के लिए उपलब्ध एंट्री EBADPLATFORM के साथ फ़ेल हो सकती हैं. आपको पब्लिश की गई श्रिंक रैप कॉपी से "dev": true एंट्री और devDependencies हटाने पड़ सकते हैं.

उदाहरण: Cloud Firestore से BigQuery तक स्ट्रीम करना

चौथे रिलीज़ कैंडिडेट के समय किट का 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" }
}

ध्यान दें कि इस मामले में, किट एक मोनोरिपो में मौजूद है. इसलिए, यह ज़रूरी है कि npm रजिस्ट्री के लिंक के लिए repository.directory शामिल किया जाए, ताकि यह सही फ़ोल्डर पर ले जाए. इसके CHANGELOG.md में, रिलीज़ होने वाले नोट मौजूद होते हैं.

11. फ़ंक्शन किट के तौर पर टेस्ट करना

किट पब्लिश करने के बाद, हमारा सुझाव है कि आप npm का इस्तेमाल करके, अपनी किट की जांच करें.

पक्का करें कि आपने firebase-tools >= 15.32.0 वर्शन का इस्तेमाल किया हो और किट इंस्टॉल की हो:

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

इससे, npm से आपका पैकेज डाउनलोड हो जाता है. साथ ही, इसे आपके किट के लिए नई सोर्स डायरेक्ट्री में सेट अप कर दिया जाता है. इसके अलावा, यह आपको एक्सटेंशन इंस्टॉल करने के फ़्लो की तरह ही, पहले इंस्टेंस को कॉन्फ़िगर करने का तरीका बताता है. अपने पैकेज को स्थानीय तौर पर इंस्टॉल और सेट अप करने के बाद, डिप्लॉय करें. इससे आपके Google Cloud प्रोजेक्ट में संसाधन बन जाएंगे:

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

इंस्टॉल होने के बाद, Firebase CLI, डिप्लॉय करने के लिए एक जैसी कमांड प्रिंट करता है. इसमें वही इंस्टेंस आईडी होता है जिसे आपने इंस्टॉलेशन के दौरान चुना था.

नौवां चरण. अपने 2nd gen फ़ंक्शन की जांच करें. अब किट का इस्तेमाल करके डिप्लॉय किया जा रहा है. इसलिए, आपके फ़ंक्शन के नाम के आगे kit-<instance-id>-<method-name> प्रीफ़िक्स लगाया गया है. इससे किट के कई इंस्टेंस बनाए जा सकते हैं. साथ ही, एक ही फ़ंक्शन को किसी प्रोजेक्ट में कई बार डिप्लॉय किया जा सकता है. हालांकि, हर इंस्टेंस का नाम अलग होना चाहिए.

12. माइग्रेशन की जगह पर टेस्ट करना

एक्सटेंशन का कोई वर्किंग इंस्टेंस सेट अप करें. इसके बाद, उपयोगकर्ता माइग्रेशन गाइड का इस्तेमाल करें. इसके लिए, firebase ext:migrate --package या फ़ंक्शन किट के सीएलआई कमांड का इस्तेमाल करें. इससे, माइग्रेशन के दौरान फ़ंक्शन किट को बदलने की प्रोसेस को टेस्ट किया जा सकेगा.

13. उपयोगकर्ताओं और Google को अपने आधिकारिक एक्सटेंशन को बदलने के बारे में सूचना देना

जब फ़ंक्शन किट का नया वर्शन तैयार हो जाए और npm पैकेज के तौर पर उपलब्ध हो जाए, तब उपयोगकर्ताओं को इस बारे में बताएं. साथ ही, Google को भी इसकी सूचना दें. GitHub रिपॉज़िटरी में मौजूद README.md फ़ाइल को अपडेट करें. इस रिपॉज़िटरी में आपका एक्सटेंशन होस्ट किया जाता है. इसके लिए, यह जानकारी शामिल करें:

<!-- 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, एक्सटेंशन के जाने-माने README फ़ाइलों में <!-- FIREBASE_EXTENSION_REPLACEMENT: extension="firebase/firestore-bigquery-export" package="@firebase-function-kits/firestore-bigquery-export" --> जैसे कमेंट स्कैन करता है. साथ ही, इसका इस्तेमाल firebase-tools रिपॉज़िटरी में सेव किए गए, आधिकारिक तौर पर रजिस्टर किए गए रिप्लेसमेंट की जानकारी भरने के लिए करता है. ऐसा replacements.json के तौर पर किया जाता है. यह देखने के लिए कि आपके एक्सटेंशन के लिए कौनसे README.md स्कैन किए जाएंगे, replacements.json पर भी जाएं. बदले गए कॉन्टेंट की आधिकारिक सूची को हर हफ़्ते अपडेट किया जाता है.

उदाहरण: Cloud Firestore से BigQuery तक स्ट्रीम करना

firestore-bigquery-export एक्सटेंशन में ये शामिल हैं: README.md

<!-- 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.