একটি এক্সটেনশন নির্মাণ শুরু করুন

এই পৃষ্ঠাটি আপনাকে একটি সাধারণ ফায়ারবেস এক্সটেনশন তৈরি করার জন্য প্রয়োজনীয় পদক্ষেপগুলির মধ্যে নিয়ে যায়, যা আপনি আপনার প্রকল্পগুলিতে ইনস্টল করতে বা অন্যদের সাথে ভাগ করতে পারেন৷ একটি Firebase এক্সটেনশনের এই সাধারণ উদাহরণটি আপনার বার্তাগুলির জন্য রিয়েলটাইম ডেটাবেস দেখবে এবং সেগুলিকে বড় হাতের অক্ষরে রূপান্তর করবে৷

1. আপনার পরিবেশ সেট আপ করুন এবং একটি প্রকল্প শুরু করুন

আপনি একটি এক্সটেনশন নির্মাণ শুরু করার আগে, আপনাকে প্রয়োজনীয় সরঞ্জামগুলির সাথে একটি বিল্ড পরিবেশ সেট আপ করতে হবে৷

  1. Node.js 16 বা নতুন ইনস্টল করুন। নোড ইনস্টল করার একটি উপায় হল nvm (বা nvm-windows ) ব্যবহার করে।

  2. Firebase CLI- এর সর্বশেষ সংস্করণে ইনস্টল বা আপডেট করুন। npm ব্যবহার করে ইনস্টল বা আপডেট করতে, এই কমান্ডটি চালান:

    npm install -g firebase-tools

এখন একটি নতুন এক্সটেনশন প্রকল্প শুরু করতে Firebase CLI ব্যবহার করুন:

  1. আপনার এক্সটেনশনের জন্য একটি ডিরেক্টরি তৈরি করুন এবং এতে cd :

    mkdir rtdb-uppercase-messages && cd rtdb-uppercase-messages
  2. Firebase CLI-এর ext:dev:init কমান্ড চালান:

    firebase ext:dev:init

    প্রম্পট করা হলে, ফাংশনগুলির জন্য ভাষা হিসাবে JavaScript বেছে নিন (কিন্তু মনে রাখবেন যে আপনি যখন নিজের এক্সটেনশন তৈরি করেন তখন আপনি TypeScript ব্যবহার করতে পারেন), এবং, যখন নির্ভরতা ইনস্টল করতে বলা হয়, তখন "হ্যাঁ" উত্তর দিন। (অন্য যেকোন বিকল্পের জন্য ডিফল্ট গ্রহণ করুন।) এই কমান্ডটি একটি নতুন এক্সটেনশনের জন্য একটি কঙ্কাল কোডবেস সেট আপ করবে, যেখান থেকে আপনি আপনার এক্সটেনশনের বিকাশ শুরু করতে পারেন।

2. এমুলেটর ব্যবহার করে উদাহরণ এক্সটেনশন চেষ্টা করুন

যখন Firebase CLI নতুন এক্সটেনশন ডিরেক্টরি শুরু করে, তখন এটি একটি সাধারণ উদাহরণ ফাংশন এবং একটি integration-tests ডিরেক্টরি তৈরি করে যাতে Firebase এমুলেটর স্যুট ব্যবহার করে একটি এক্সটেনশন চালানোর জন্য প্রয়োজনীয় ফাইল থাকে।

এমুলেটরে উদাহরণ এক্সটেনশন চালানোর চেষ্টা করুন:

  1. integration-tests ডিরেক্টরিতে পরিবর্তন করুন:

    cd functions/integration-tests
  2. একটি ডেমো প্রকল্পের সাথে এমুলেটর শুরু করুন:

    firebase emulators:start --project=demo-test

    এমুলেটর এক্সটেনশনটিকে একটি পূর্বনির্ধারিত "ডামি" প্রকল্পে ( demo-test ) লোড করে। এক্সটেনশনটিতে এখন পর্যন্ত একটি একক HTTP-ট্রিগার করা ফাংশন রয়েছে, greetTheWorld , যা অ্যাক্সেস করার সময় একটি "হ্যালো ওয়ার্ল্ড" বার্তা প্রদান করে।

  3. এমুলেটর এখনও চলমান থাকা অবস্থায়, আপনি যখন এটি শুরু করেছিলেন তখন এটি মুদ্রিত URLটিতে গিয়ে এক্সটেনশনের greetTheWorld ফাংশনটি ব্যবহার করে দেখুন৷

    আপনার ব্রাউজার "হ্যালো ওয়ার্ল্ড ফ্রম গ্রীট-দ্য-ওয়ার্ল্ড" বার্তাটি প্রদর্শন করে।

  4. এই ফাংশনের সোর্স কোডটি এক্সটেনশনের functions ডিরেক্টরিতে রয়েছে। আপনার পছন্দের সম্পাদক বা IDE-এ উৎসটি খুলুন:

    functions/index.js

    const functions = require("firebase-functions/v1");
    
    exports.greetTheWorld = functions.https.onRequest((req, res) => {
      // Here we reference a user-provided parameter
      // (its value is provided by the user during installation)
      const consumerProvidedGreeting = process.env.GREETING;
    
      // And here we reference an auto-populated parameter
      // (its value is provided by Firebase after installation)
      const instanceId = process.env.EXT_INSTANCE_ID;
    
      const greeting = `${consumerProvidedGreeting} World from ${instanceId}`;
    
      res.send(greeting);
    });
    
  5. এমুলেটর চলাকালীন, এটি স্বয়ংক্রিয়ভাবে আপনার ফাংশন কোডে আপনার করা যেকোনো পরিবর্তন পুনরায় লোড করবে। greetTheWorld ফাংশনে একটি ছোট পরিবর্তন করার চেষ্টা করুন:

    functions/index.js

    const greeting = `${consumerProvidedGreeting} everyone, from ${instanceId}`;
    

    আপনার পরিবর্তন সংরক্ষণ করুন. এমুলেটর আপনার কোড পুনরায় লোড করবে, এবং এখন, যখন আপনি ফাংশন URL-এ যান, আপনি আপডেট করা শুভেচ্ছা দেখতে পাবেন।

3. extension.yaml-এ মৌলিক তথ্য যোগ করুন

এখন আপনার একটি উন্নয়ন পরিবেশ সেট আপ করা হয়েছে এবং এক্সটেনশন এমুলেটর চালাচ্ছেন, আপনি নিজের এক্সটেনশন লেখা শুরু করতে পারেন।

একটি বিনয়ী প্রথম পদক্ষেপ হিসাবে, greet-the-world এর পরিবর্তে আপনি যে এক্সটেনশনটি লিখতে চান তা প্রতিফলিত করতে পূর্বনির্ধারিত এক্সটেনশন মেটাডেটা সম্পাদনা করুন। এই মেটাডেটা extension.yaml ফাইলে সংরক্ষিত আছে।

  1. আপনার এডিটরে extension.yaml খুলুন, এবং ফাইলের সম্পূর্ণ বিষয়বস্তু নিম্নলিখিতগুলির সাথে প্রতিস্থাপন করুন:

    name: rtdb-uppercase-messages
    version: 0.0.1
    specVersion: v1beta  # Firebase Extensions specification version; don't change
    
    # Friendly display name for your extension (~3-5 words)
    displayName: Convert messages to upper case
    
    # Brief description of the task your extension performs (~1 sentence)
    description: >-
      Converts messages in RTDB to upper case
    
    author:
      authorName: Your Name
      url: https://your-site.example.com
    
    license: Apache-2.0  # Required license
    
    # Public URL for the source code of your extension
    sourceUrl: https://github.com/your-name/your-repo
    

    name ক্ষেত্রে ব্যবহৃত নামকরণের নিয়মটি লক্ষ্য করুন: অফিসিয়াল ফায়ারবেস এক্সটেনশনের নামকরণ করা হয় একটি প্রিফিক্স সহ যেটি এক্সটেনশনটি কাজ করে তা প্রাথমিক Firebase পণ্য নির্দেশ করে, তারপরে এক্সটেনশনটি কী করে তার একটি বর্ণনা। আপনার নিজের এক্সটেনশনে একই কনভেনশন ব্যবহার করা উচিত।

  2. যেহেতু আপনি আপনার এক্সটেনশনের নাম পরিবর্তন করেছেন, তাই আপনাকে নতুন নাম দিয়ে আপনার এমুলেটর কনফিগারেশনও আপডেট করতে হবে:

    1. functions/integration-tests/firebase.json , greet-the-world rtdb-uppercase-messages এ পরিবর্তন করুন।
    2. functions/integration-tests/extensions/greet-the-world.env এর নাম পরিবর্তন করে functions/integration-tests/extensions/rtdb-uppercase-messages.env করুন।

আপনার এক্সটেনশন কোডে greet-the-world এক্সটেনশনের কিছু অবশিষ্টাংশ এখনও অবশিষ্ট আছে, কিন্তু আপাতত সেগুলি ছেড়ে দিন। আপনি পরবর্তী কয়েকটি বিভাগে সেগুলি আপডেট করবেন।

4. একটি ক্লাউড ফাংশন লিখুন এবং এটিকে একটি এক্সটেনশন সম্পদ হিসাবে ঘোষণা করুন৷

এখন আপনি কিছু কোড লেখা শুরু করতে পারেন। এই ধাপে, আপনি একটি ক্লাউড ফাংশন লিখবেন যা আপনার এক্সটেনশনের মূল কাজটি সম্পাদন করে, যা বার্তাগুলির জন্য আপনার রিয়েলটাইম ডেটাবেস দেখা এবং সেগুলিকে বড় হাতের অক্ষরে রূপান্তর করা।

  1. আপনার পছন্দের এডিটর বা IDE-এ এক্সটেনশনের ফাংশন (এক্সটেনশনের functions ডিরেক্টরিতে) জন্য উৎস খুলুন। এর বিষয়বস্তুগুলি নিম্নলিখিতগুলির সাথে প্রতিস্থাপন করুন:

    functions/index.js

    import { database, logger } from "firebase-functions/v1";
    
    const app = initializeApp();
    
    // Listens for new messages added to /messages/{pushId}/original and creates an
    // uppercase version of the message to /messages/{pushId}/uppercase
    // for all databases in 'us-central1'
    export const makeuppercase = database
      .ref("/messages/{pushId}/uppercase")
      .onCreate(async (snapshot, context) => {
        // Grab the current value of what was written to the Realtime Database.
        const original = snapshot.val();
    
        // Convert it to upper case.
        logger.log("Uppercasing", context.params.pushId, original);
        const uppercase = original.toUpperCase();
    
        // Setting an "uppercase" sibling in the Realtime Database.
        const upperRef = snapshot.ref.parent.child("upper");
        await upperRef.set(uppercase);
    });
    

    পুরানো ফাংশন, যা আপনি প্রতিস্থাপন করেছেন, এটি একটি HTTP-ট্রিগারড ফাংশন, যেটি চলত যখন একটি HTTP এন্ডপয়েন্ট অ্যাক্সেস করা হয়। নতুন ফাংশনটি রিয়েল-টাইম ডাটাবেস ইভেন্ট দ্বারা ট্রিগার করা হয়: এটি একটি নির্দিষ্ট পথে নতুন আইটেমগুলির জন্য নজর রাখে এবং যখন একটি সনাক্ত করা হয়, এটি ডাটাবেসে মানের বড় হাতের সংস্করণ লিখে।

    যাইহোক, এই নতুন ফাইলটি সাধারণজে ( require ) এর পরিবর্তে ইসমা স্ক্রিপ্ট মডিউল সিনট্যাক্স ( importexport ) ব্যবহার করে। নোডে ES মডিউল ব্যবহার করতে, functions/package.json"type": "module" উল্লেখ করুন:

    {
      "name": "rtdb-uppercase-messages",
      "main": "index.js",
      "type": "module",
      
    }
    
  2. আপনার এক্সটেনশনের প্রতিটি ফাংশন extension.yaml ফাইলে ঘোষণা করতে হবে। উদাহরণ এক্সটেনশনটি greetTheWorld এক্সটেনশনের একমাত্র ক্লাউড ফাংশন হিসাবে ঘোষণা করেছে; এখন আপনি এটিকে makeuppercase দিয়ে প্রতিস্থাপন করেছেন, আপনাকে এর ঘোষণা আপডেট করতে হবে।

    extension.yaml খুলুন এবং একটি resources ক্ষেত্র যোগ করুন:

    resources:
      - name: makeuppercase
        type: firebaseextensions.v1beta.function
        properties:
          eventTrigger:
            eventType: providers/google.firebase.database/eventTypes/ref.create
            # DATABASE_INSTANCE (project's default instance) is an auto-populated
            # parameter value. You can also specify an instance.
            resource: projects/_/instances/${DATABASE_INSTANCE}/refs/messages/{pushId}/original
          runtime: "nodejs18"
    
  3. যেহেতু আপনার এক্সটেনশন এখন ট্রিগার হিসাবে রিয়েলটাইম ডেটাবেস ব্যবহার করছে, তাই ক্লাউড ফাংশন এমুলেটরের পাশাপাশি RTDB এমুলেটর চালানোর জন্য আপনাকে আপনার এমুলেটর কনফিগারেশন আপডেট করতে হবে:

    1. যদি এমুলেটর এখনও চলছে, Ctrl-C টিপে এটি বন্ধ করুন।

    2. functions/integration-tests ডিরেক্টরি থেকে, নিম্নলিখিত কমান্ডটি চালান:

      firebase init emulators

      যখন জিজ্ঞাসা করা হয়, একটি ডিফল্ট প্রকল্প সেট আপ এড়িয়ে যান, তারপর ফাংশন এবং ডেটাবেস এমুলেটর নির্বাচন করুন। ডিফল্ট পোর্টগুলি গ্রহণ করুন এবং সেটআপ টুলটিকে প্রয়োজনীয় ফাইল ডাউনলোড করার অনুমতি দিন।

    3. এমুলেটর পুনরায় চালু করুন:

      firebase emulators:start --project=demo-test
  4. আপনার আপডেট করা এক্সটেনশন ব্যবহার করে দেখুন:

    1. ডাটাবেস এমুলেটর UI খুলুন যখন আপনি এটি শুরু করেছিলেন তখন এমুলেটরটি মুদ্রিত লিঙ্কটি ব্যবহার করে।

    2. ডাটাবেসের রুট নোড সম্পাদনা করুন:

      • ক্ষেত্র: messages
      • প্রকার: json
      • মান: {"11": {"original": "recipe"}}

      যদি সবকিছু সঠিকভাবে সেট আপ করা হয়, আপনি যখন আপনার ডাটাবেসের পরিবর্তনগুলি সংরক্ষণ করেন, তখন এক্সটেনশনের makeuppercase ফাংশনটি ট্রিগার করবে এবং "upper": "RECIPE" বিষয়বস্তু সহ মেসেজ 11-এ একটি চাইল্ড রেকর্ড যুক্ত করবে। প্রত্যাশিত ফলাফল নিশ্চিত করতে এমুলেটর UI এর লগ এবং ডাটাবেস ট্যাবগুলি দেখুন।

    3. messages নোডে আরও কিছু শিশু যোগ করার চেষ্টা করুন ( {"original":"any text"} )। যখনই আপনি একটি নতুন রেকর্ড যোগ করবেন, এক্সটেনশনটি একটি uppercase ক্ষেত্র যোগ করবে যাতে original ক্ষেত্রের বড় হাতের কন্টেন্ট থাকে।

আপনার কাছে এখন একটি সম্পূর্ণ, যদিও সহজ, এক্সটেনশন রয়েছে যা একটি RTDB উদাহরণে কাজ করে। অনুসরণ করা বিভাগগুলিতে, আপনি কিছু অতিরিক্ত বৈশিষ্ট্য সহ এই এক্সটেনশনটি পরিমার্জন করবেন৷ তারপরে, আপনি এক্সটেনশনটি অন্যদের কাছে বিতরণ করার জন্য প্রস্তুত পাবেন এবং অবশেষে, এক্সটেনশন হাবে আপনার এক্সটেনশনটি কীভাবে প্রকাশ করবেন তা শিখুন।

5. API এবং ভূমিকা ঘোষণা করুন

ফায়ারবেস একটি ইনস্টল করা এক্সটেনশনের প্রতিটি দৃষ্টান্ত মঞ্জুর করে একটি প্রতি-ইনস্ট্যান্স পরিষেবা অ্যাকাউন্ট ব্যবহার করে প্রকল্প এবং এর ডেটাতে সীমিত অ্যাক্সেস। প্রতিটি অ্যাকাউন্ট পরিচালনার জন্য প্রয়োজনীয় অনুমতিগুলির ন্যূনতম সেট রয়েছে। এই কারণে, আপনার এক্সটেনশনের জন্য প্রয়োজনীয় যেকোন IAM ভূমিকা আপনাকে স্পষ্টভাবে ঘোষণা করতে হবে; যখন ব্যবহারকারীরা আপনার এক্সটেনশন ইনস্টল করেন, তখন Firebase এই ভূমিকাগুলি দিয়ে একটি পরিষেবা অ্যাকাউন্ট তৈরি করে এবং এক্সটেনশন চালানোর জন্য এটি ব্যবহার করে।

একটি পণ্যের ইভেন্টগুলিকে ট্রিগার করার জন্য আপনাকে ভূমিকা ঘোষণা করতে হবে না, তবে অন্যথায় এটির সাথে ইন্টারঅ্যাক্ট করার জন্য আপনাকে একটি ভূমিকা ঘোষণা করতে হবে। যেহেতু শেষ ধাপে আপনি যে ফাংশনটি যোগ করেছেন তা রিয়েলটাইম ডেটাবেসে লিখছে, আপনাকে extension.yaml এ নিম্নলিখিত ঘোষণা যোগ করতে হবে:

roles:
  - role: firebasedatabase.admin
    reason: Allows the extension to write to RTDB.

একইভাবে, আপনি Google API ঘোষণা করেন যা একটি এক্সটেনশন apis ক্ষেত্রে ব্যবহার করে। যখন ব্যবহারকারীরা আপনার এক্সটেনশন ইনস্টল করেন, তখন তাদের জিজ্ঞাসা করা হবে যে তারা তাদের প্রকল্পের জন্য এই APIগুলি স্বয়ংক্রিয়ভাবে সক্ষম করতে চান কিনা৷ এটি সাধারণত শুধুমাত্র নন-ফায়ারবেস Google API-এর জন্য প্রয়োজনীয় এবং এই গাইডের জন্য প্রয়োজন নেই।

6. ব্যবহারকারী-কনফিগারযোগ্য পরামিতি সংজ্ঞায়িত করুন

শেষ দুই ধাপে আপনি যে ফাংশনটি তৈরি করেছেন তা আগত বার্তাগুলির জন্য একটি নির্দিষ্ট RTDB অবস্থান দেখেছে। কখনও কখনও, একটি নির্দিষ্ট অবস্থান দেখতে সত্যিই আপনি যা চান, যেমন যখন আপনার এক্সটেনশন একটি ডাটাবেস কাঠামোতে কাজ করে যা আপনি আপনার এক্সটেনশনের জন্য একচেটিয়াভাবে ব্যবহার করেন৷ যাইহোক, বেশিরভাগ সময়, আপনি এই মানগুলিকে তাদের প্রকল্পগুলিতে আপনার এক্সটেনশন ইনস্টল করার ব্যবহারকারীদের দ্বারা কনফিগারযোগ্য করতে চাইবেন৷ এইভাবে, ব্যবহারকারীরা তাদের বিদ্যমান ডাটাবেস সেটআপের সাথে কাজ করতে আপনার এক্সটেনশন ব্যবহার করতে পারে।

এক্সটেনশন নতুন বার্তাগুলির জন্য ব্যবহারকারী-কনফিগারযোগ্য পাথ তৈরি করুন:

  1. extension.yaml ফাইলে, একটি params বিভাগ যোগ করুন:

    - param: MESSAGE_PATH
      label: Message path
      description: >-
        What is the path at which the original text of a message can be found?
      type: string
      default: /messages/{pushId}/original
      required: true
      immutable: false
    

    এটি একটি নতুন স্ট্রিং প্যারামিটার সংজ্ঞায়িত করে যা ব্যবহারকারীরা আপনার এক্সটেনশন ইনস্টল করার সময় সেট করতে অনুরোধ জানানো হবে।

  2. এখনও extension.yaml ফাইলে, আপনার makeuppercase ঘোষণায় ফিরে যান এবং resource ক্ষেত্রটিকে নিম্নলিখিতগুলিতে পরিবর্তন করুন:

    resource: projects/_/instances/${DATABASE_INSTANCE}/refs/${param:MESSAGE_PATH}
    

    ${param:MESSAGE_PATH} টোকেন হল আপনার এইমাত্র সংজ্ঞায়িত প্যারামিটারের একটি রেফারেন্স। যখন আপনার এক্সটেনশন চলে, এই টোকেনটি ব্যবহারকারীর সেই প্যারামিটারের জন্য কনফিগার করা যাই হোক না কেন মান দ্বারা প্রতিস্থাপিত হবে, ফলে makeuppercase ফাংশন ব্যবহারকারীর নির্দিষ্ট করা পথ শুনবে। আপনি extension.yaml এ (এবং POSTINSTALL.md এ আরও পরে) যে কোনও ব্যবহারকারী-সংজ্ঞায়িত প্যারামিটার উল্লেখ করতে এই সিনট্যাক্সটি ব্যবহার করতে পারেন।

  3. আপনি আপনার ফাংশন কোড থেকে ব্যবহারকারী-সংজ্ঞায়িত পরামিতি অ্যাক্সেস করতে পারেন।

    আপনি শেষ বিভাগে যে ফাংশনটি লিখেছেন, আপনি পরিবর্তনগুলি দেখার জন্য পাথটি হার্ড-কোড করেছেন৷ পরিবর্তে ব্যবহারকারী-সংজ্ঞায়িত মান উল্লেখ করতে ট্রিগার সংজ্ঞা পরিবর্তন করুন:

    functions/index.js

    export const makeuppercase = database.ref(process.env.MESSAGE_PATH).onCreate
    

    মনে রাখবেন যে ফায়ারবেস এক্সটেনশনে, এই পরিবর্তনটি সম্পূর্ণরূপে ডকুমেন্টেশনের জন্য: যখন একটি ক্লাউড ফাংশন একটি এক্সটেনশনের অংশ হিসাবে স্থাপন করা হয়, তখন এটি extension.yaml ফাইল থেকে ট্রিগার সংজ্ঞা ব্যবহার করে এবং ফাংশনের সংজ্ঞায় উল্লেখিত মানটিকে উপেক্ষা করে। তবুও, এই মানটি কোথা থেকে এসেছে তা আপনার কোডে নথিভুক্ত করা একটি ভাল ধারণা।

  4. কোনো রানটাইম প্রভাব নেই এমন একটি কোড পরিবর্তন করা আপনার কাছে হতাশাজনক মনে হতে পারে, কিন্তু গুরুত্বপূর্ণ শিক্ষাটি হ'ল আপনি আপনার ফাংশন কোডে ব্যবহারকারী-সংজ্ঞায়িত প্যারামিটার অ্যাক্সেস করতে পারেন এবং ফাংশনের যুক্তিতে এটিকে একটি সাধারণ মান হিসাবে ব্যবহার করতে পারেন। এই ক্ষমতার জন্য একটি সম্মতি হিসাবে, নিম্নলিখিত লগ স্টেটমেন্ট যোগ করুন প্রদর্শন করতে যে আপনি প্রকৃতপক্ষে ব্যবহারকারীর দ্বারা সংজ্ঞায়িত মানটি অ্যাক্সেস করছেন:

    functions/index.js

    export const makeuppercase = database.ref(process.env.MESSAGE_PATH).onCreate(
      async (snapshot, context) => {
        logger.log("Found new message at ", snapshot.ref);
    
        // Grab the current value of what was written to the Realtime Database.
        ...
    
  5. সাধারণত, ব্যবহারকারীরা যখন একটি এক্সটেনশন ইনস্টল করেন তখন প্যারামিটারের জন্য মান প্রদান করার জন্য অনুরোধ করা হয়। আপনি যখন পরীক্ষা এবং বিকাশের জন্য এমুলেটর ব্যবহার করেন, তবে, আপনি ইনস্টলেশন প্রক্রিয়াটি এড়িয়ে যান, তাই আপনি পরিবর্তে একটি env ফাইল ব্যবহার করে ব্যবহারকারী-সংজ্ঞায়িত পরামিতিগুলির জন্য মান প্রদান করেন।

    functions/integration-tests/extensions/rtdb-uppercase-messages.env খুলুন এবং GREETING সংজ্ঞাটি নিম্নলিখিত দিয়ে প্রতিস্থাপন করুন:

    MESSAGE_PATH=/msgs/{pushId}/original
    

    লক্ষ্য করুন যে উপরের পাথটি ডিফল্ট পাথ থেকে এবং আপনি পূর্বে সংজ্ঞায়িত পথ থেকে ভিন্ন; এটি শুধুমাত্র নিজেকে প্রমাণ করার জন্য যখন আপনি আপনার আপডেট করা এক্সটেনশন চেষ্টা করেন যে আপনার সংজ্ঞা কার্যকর হচ্ছে।

  6. এখন, এমুলেটরটি পুনরায় চালু করুন এবং আবার ডাটাবেস এমুলেটর UI দেখুন।

    আপনি উপরে সংজ্ঞায়িত পথ ব্যবহার করে ডাটাবেসের রুট নোড সম্পাদনা করুন:

    • ক্ষেত্র: msgs
    • প্রকার: json
    • মান: {"11": {"original": "recipe"}}

    আপনি যখন আপনার ডাটাবেসের পরিবর্তনগুলি সংরক্ষণ করেন, তখন এক্সটেনশনের makeuppercase ফাংশনটি আগের মতো ট্রিগার হওয়া উচিত, তবে এখন এটি কনসোল লগে ব্যবহারকারী-সংজ্ঞায়িত প্যারামিটারটিও প্রিন্ট করবে৷

7. ব্যবহারকারী-সংজ্ঞায়িত যুক্তির জন্য ইভেন্ট হুক প্রদান করুন

আপনি ইতিমধ্যেই একজন এক্সটেনশন লেখক হিসাবে দেখেছেন, কিভাবে একটি ফায়ারবেস পণ্য আপনার এক্সটেনশন-প্রদত্ত যুক্তিকে ট্রিগার করতে পারে: রিয়েলটাইম ডেটাবেসে নতুন রেকর্ড তৈরি করা আপনার makeuppercase ফাংশনকে ট্রিগার করে। যে ব্যবহারকারীরা আপনার এক্সটেনশন ইনস্টল করেন তাদের সাথে আপনার এক্সটেনশনের একটি সাদৃশ্যপূর্ণ সম্পর্ক থাকতে পারে: আপনার এক্সটেনশন ব্যবহারকারীর সংজ্ঞায়িত যুক্তিকে ট্রিগার করতে পারে।

একটি এক্সটেনশন সিঙ্ক্রোনাস হুক , অ্যাসিঙ্ক্রোনাস হুক বা উভয়ই প্রদান করতে পারে। সিঙ্ক্রোনাস হুকগুলি ব্যবহারকারীদের এমন কাজগুলি সম্পাদন করার একটি উপায় দেয় যা এক্সটেনশনের ফাংশনগুলির একটির সমাপ্তি ব্লক করে৷ এটি কার্যকর হতে পারে, উদাহরণস্বরূপ, একটি এক্সটেনশন কাজ করার আগে ব্যবহারকারীদের কাস্টম প্রিপ্রসেসিং সঞ্চালনের একটি উপায় দিতে।

এই নির্দেশিকায়, আপনি আপনার এক্সটেনশনে একটি অ্যাসিঙ্ক্রোনাস হুক যোগ করবেন, যা ব্যবহারকারীদের তাদের নিজস্ব প্রক্রিয়াকরণের পদক্ষেপগুলিকে সংজ্ঞায়িত করতে সক্ষম করবে যা আপনার এক্সটেনশনটি রিয়েলটাইম ডেটাবেসে বড় হাতের বার্তা লেখার পরে চালানো হবে৷ অ্যাসিঙ্ক্রোনাস হুক ব্যবহারকারী-সংজ্ঞায়িত ফাংশন ট্রিগার করতে Eventarc ব্যবহার করে। এক্সটেনশনগুলি তারা যে ধরণের ইভেন্টগুলি নির্গত করে তা ঘোষণা করে এবং ব্যবহারকারীরা যখন এক্সটেনশন ইনস্টল করেন, তখন তারা কোন ইভেন্টের ধরনগুলিতে আগ্রহী তা চয়ন করেন৷ যদি তারা অন্তত একটি ইভেন্ট বেছে নেন, Firebase ইনস্টলেশন প্রক্রিয়ার অংশ হিসাবে এক্সটেনশনের জন্য একটি Eventarc চ্যানেলের ব্যবস্থা করবে৷ ব্যবহারকারীরা তখন তাদের নিজস্ব ক্লাউড ফাংশন স্থাপন করতে পারে যা সেই চ্যানেলে শোনে এবং যখন এক্সটেনশন নতুন ইভেন্ট প্রকাশ করে তখন ট্রিগার করে।

একটি অ্যাসিঙ্ক্রোনাস হুক যোগ করতে এই পদক্ষেপগুলি অনুসরণ করুন:

  1. extension.yaml ফাইলে, নিম্নলিখিত বিভাগটি যোগ করুন, যা ঘোষণা করে যে এক ইভেন্টের ধরন এক্সটেনশন নির্গত হয়:

    events:
      - type: test-publisher.rtdb-uppercase-messages.v1.complete
        description: >-
          Occurs when message uppercasing completes. The event subject will contain
          the RTDB URL of the uppercase message.
    

    ইভেন্টের ধরন অবশ্যই সর্বজনীনভাবে অনন্য হতে হবে; স্বতন্ত্রতা নিশ্চিত করতে, সর্বদা নিম্নলিখিত বিন্যাস ব্যবহার করে আপনার ইভেন্টের নাম দিন: <publisher-id>.<extension-id>.<version>.<description> । (আপনার কাছে এখনও কোনো প্রকাশক আইডি নেই, তাই আপাতত test-publisher ব্যবহার করুন।)

  2. makeuppercase ফাংশনের শেষে, এমন কিছু কোড যোগ করুন যা আপনি ঘোষণা করেছেন এমন একটি ইভেন্ট প্রকাশ করে:

    functions/index.js

    // Import the Eventarc library:
    import { initializeApp } from "firebase-admin/app";
    import { getEventarc } from "firebase-admin/eventarc";
    
    const app = initializeApp();
    
    // In makeuppercase, after upperRef.set(uppercase), add:
    
    // Set eventChannel to a newly-initialized channel, or `undefined` if events
    // aren't enabled.
    const eventChannel =
      process.env.EVENTARC_CHANNEL &&
      getEventarc().channel(process.env.EVENTARC_CHANNEL, {
        allowedEventTypes: process.env.EXT_SELECTED_EVENTS,
      });
    
    // If events are enabled, publish a `complete` event to the configured
    // channel.
    eventChannel &&
      eventChannel.publish({
        type: "test-publisher.rtdb-uppercase-messages.v1.complete",
        subject: upperRef.toString(),
        data: {
          "original": original,
          "uppercase": uppercase,
        },
      });
    

    এই উদাহরণ কোডটি এই সত্যের সুবিধা নেয় যে EVENTARC_CHANNEL পরিবেশ পরিবর্তনশীল শুধুমাত্র তখনই সংজ্ঞায়িত করা হয় যখন ব্যবহারকারী কমপক্ষে একটি ইভেন্ট টাইপ সক্ষম করে। যদি EVENTARC_CHANNEL সংজ্ঞায়িত না হয়, কোডটি কোনো ঘটনা প্রকাশ করার চেষ্টা করে না।

    আপনি একটি Eventarc ইভেন্টে অতিরিক্ত তথ্য সংযুক্ত করতে পারেন। উপরের উদাহরণে, ইভেন্টটির একটি subject ক্ষেত্র রয়েছে যাতে নতুন তৈরি করা মানের একটি রেফারেন্স রয়েছে এবং একটি data পেলোড রয়েছে যাতে মূল এবং বড় হাতের বার্তা রয়েছে৷ ব্যবহারকারী-সংজ্ঞায়িত ফাংশন যে ইভেন্ট বন্ধ ট্রিগার এই তথ্য ব্যবহার করতে পারেন.

  3. সাধারণত, EVENTARC_CHANNEL এবং EXT_SELECTED_EVENTS এনভায়রনমেন্ট ভেরিয়েবলগুলি ইনস্টলেশনের সময় ব্যবহারকারীর দ্বারা নির্বাচিত বিকল্পগুলির উপর ভিত্তি করে সংজ্ঞায়িত করা হয়। এমুলেটর দিয়ে পরীক্ষা করার জন্য, rtdb-uppercase-messages.env ফাইলে এই ভেরিয়েবলগুলিকে ম্যানুয়ালি সংজ্ঞায়িত করুন:

    EVENTARC_CHANNEL=locations/us-central1/channels/firebase
    EXT_SELECTED_EVENTS=test-publisher.rtdb-uppercase-messages.v1.complete
    

এই মুহুর্তে, আপনি আপনার এক্সটেনশনে একটি অ্যাসিঙ্ক্রোনাস ইভেন্ট হুক যোগ করার জন্য প্রয়োজনীয় পদক্ষেপগুলি সম্পন্ন করেছেন৷

এই নতুন বৈশিষ্ট্যটি চেষ্টা করার জন্য যা আপনি এইমাত্র প্রয়োগ করেছেন, পরবর্তী কয়েকটি ধাপে, একজন ব্যবহারকারীর ভূমিকা অনুমান করুন যিনি এক্সটেনশনটি ইনস্টল করছেন:

  1. functions/integration-tests ডিরেক্টরি থেকে, একটি নতুন ফায়ারবেস প্রকল্প শুরু করুন:

    firebase init functions

    যখন অনুরোধ করা হয়, একটি ডিফল্ট প্রকল্প সেট আপ করতে অস্বীকার করুন, ক্লাউড ফাংশন ভাষা হিসাবে JavaScript নির্বাচন করুন এবং প্রয়োজনীয় নির্ভরতাগুলি ইনস্টল করুন৷ এই প্রকল্পটি একটি ব্যবহারকারীর প্রকল্পের প্রতিনিধিত্ব করে, যেখানে আপনার এক্সটেনশন ইনস্টল করা আছে।

  2. integration-tests/functions/index.js সম্পাদনা করুন এবং নিম্নলিখিত কোড পেস্ট করুন:

    import { logger } from "firebase-functions/v1";
    import { onCustomEventPublished } from "firebase-functions/v2/eventarc";
    
    import { initializeApp } from "firebase-admin/app";
    import { getDatabase } from "firebase-admin/database";
    
    const app = initializeApp();
    
    export const extraemphasis = onCustomEventPublished(
      "test-publisher.rtdb-uppercase-messages.v1.complete",
      async (event) => {
        logger.info("Received makeuppercase completed event", event);
    
        const refUrl = event.subject;
        const ref = getDatabase().refFromURL(refUrl);
        const upper = (await ref.get()).val();
        return ref.set(`${upper}!!!`);
      }
    );
    

    এটি একটি পোস্ট-প্রসেসিং ফাংশনের একটি উদাহরণ যা একজন ব্যবহারকারী লিখতে পারে। এই ক্ষেত্রে, ফাংশনটি একটি complete ইভেন্ট প্রকাশ করার জন্য এক্সটেনশনের জন্য শোনে এবং ট্রিগার করা হলে, নতুন-বড় হাতের বার্তায় তিনটি বিস্ময়বোধক বিন্দু যোগ করে।

  3. এমুলেটর পুনরায় চালু করুন। এমুলেটর এক্সটেনশনের ফাংশন এবং পোস্ট-প্রসেসিং ফাংশন "ব্যবহারকারী" সংজ্ঞায়িত লোড করবে।

  4. আপনি উপরে সংজ্ঞায়িত পথটি ব্যবহার করে ডাটাবেস এমুলেটর ইউআই দেখুন এবং ডাটাবেসের মূল নোড সম্পাদনা করুন:

    • ক্ষেত্র: msgs
    • প্রকার: json
    • মান: {"11": {"original": "recipe"}}

    আপনি যখন আপনার ডাটাবেসের পরিবর্তনগুলি সংরক্ষণ করেন, তখন এক্সটেনশনের makeuppercase ফাংশন এবং ব্যবহারকারীর extraemphasis ফাংশনটি ক্রমানুসারে ট্রিগার হওয়া উচিত, যার ফলে upper ক্ষেত্রটি RECIPE!!! .

8. জীবনচক্র ইভেন্ট হ্যান্ডলার যোগ করুন

আপনি এখন পর্যন্ত যে এক্সটেনশনটি লিখেছেন তা তৈরি হওয়ার সাথে সাথে বার্তাগুলিকে প্রক্রিয়া করে। কিন্তু যদি আপনার ব্যবহারকারীরা এক্সটেনশন ইনস্টল করার সময় ইতিমধ্যেই বার্তাগুলির একটি ডাটাবেস থাকে? ফায়ারবেস এক্সটেনশনে লাইফসাইকেল ইভেন্ট হুক নামে একটি বৈশিষ্ট্য রয়েছে যা আপনি আপনার এক্সটেনশন ইনস্টল, আপডেট বা পুনরায় কনফিগার করা হলে অ্যাকশন ট্রিগার করতে ব্যবহার করতে পারেন। এই বিভাগে, আপনি লাইফসাইকেল ইভেন্ট হুকগুলি ব্যবহার করবেন একটি প্রকল্পের বিদ্যমান বার্তা ডাটাবেসকে বড় হাতের বার্তাগুলির সাথে ব্যাকফিল করার জন্য যখন একজন ব্যবহারকারী আপনার এক্সটেনশন ইনস্টল করবেন৷

আপনার লাইফসাইকেল ইভেন্ট হ্যান্ডলার চালানোর জন্য Firebase এক্সটেনশনগুলি ক্লাউড টাস্ক ব্যবহার করে। আপনি ক্লাউড ফাংশন ব্যবহার করে ইভেন্ট হ্যান্ডলারদের সংজ্ঞায়িত করেন; যখনই আপনার এক্সটেনশনের একটি উদাহরণ সমর্থিত লাইফসাইকেল ইভেন্টগুলির একটিতে পৌঁছায়, যদি আপনি একটি হ্যান্ডলারকে সংজ্ঞায়িত করে থাকেন, এটি হ্যান্ডলারটিকে একটি ক্লাউড টাস্ক সারিতে যুক্ত করবে। ক্লাউড টাস্কগুলি তখন হ্যান্ডলারকে অ্যাসিঙ্ক্রোনাসভাবে চালাবে। যখন একটি লাইফসাইকেল ইভেন্ট হ্যান্ডলার চলছে, তখন Firebase কনসোল ব্যবহারকারীকে রিপোর্ট করবে যে এক্সটেনশন ইন্সট্যান্সের একটি প্রসেসিং কাজ চলছে। এটি আপনার হ্যান্ডলার ফাংশনের উপর নির্ভর করে ব্যবহারকারীর কাছে চলমান স্থিতি এবং কার্য সমাপ্তির প্রতিবেদন করা।

একটি লাইফসাইকেল ইভেন্ট হ্যান্ডলার যোগ করতে যা বিদ্যমান বার্তাগুলিকে ব্যাকফিল করে, নিম্নলিখিতগুলি করুন:

  1. একটি নতুন ক্লাউড ফাংশন সংজ্ঞায়িত করুন যা টাস্ক কিউ ইভেন্ট দ্বারা ট্রিগার হয়:

    ফাংশন/সূচক.জেএস

    import { tasks } from "firebase-functions/v1";
    
    import { getDatabase } from "firebase-admin/database";
    import { getExtensions } from "firebase-admin/extensions";
    import { getFunctions } from "firebase-admin/functions";
    
    export const backfilldata = tasks.taskQueue().onDispatch(async () => {
      const batch = await getDatabase()
        .ref(process.env.MESSAGE_PATH)
        .parent.parent.orderByChild("upper")
        .limitToFirst(20)
        .get();
    
      const promises = [];
      for (const key in batch.val()) {
        const msg = batch.child(key);
        if (msg.hasChild("original") && !msg.hasChild("upper")) {
          const upper = msg.child("original").val().toUpperCase();
          promises.push(msg.child("upper").ref.set(upper));
        }
      }
      await Promise.all(promises);
    
      if (promises.length > 0) {
        const queue = getFunctions().taskQueue(
          "backfilldata",
          process.env.EXT_INSTANCE_ID
        );
        return queue.enqueue({});
      } else {
        return getExtensions()
          .runtime()
          .setProcessingState("PROCESSING_COMPLETE", "Backfill complete.");
      }
    });
    

    লক্ষ্য করুন যে ফাংশনটি টাস্ক সারিতে নিজেকে যুক্ত করার আগে শুধুমাত্র কয়েকটি রেকর্ড প্রক্রিয়া করে। এটি একটি ক্লাউড ফাংশনের টাইমআউট উইন্ডোর মধ্যে সম্পন্ন করতে পারে না এমন প্রক্রিয়াকরণ কাজগুলি মোকাবেলা করার জন্য একটি সাধারণভাবে ব্যবহৃত কৌশল৷ যেহেতু আপনি ভবিষ্যদ্বাণী করতে পারবেন না যে ব্যবহারকারীরা আপনার এক্সটেনশন ইনস্টল করার সময় তাদের ডাটাবেসে ইতিমধ্যে কতগুলি বার্তা থাকতে পারে, এই কৌশলটি একটি উপযুক্ত।

  2. extension.yaml ফাইলে, আপনার ব্যাকফিল ফাংশনটিকে একটি এক্সটেনশন রিসোর্স হিসাবে ঘোষণা করুন যাতে taskQueueTrigger সম্পত্তি রয়েছে:

    resources:
      - name: makeuppercase
        ...
      - name: backfilldata
        type: firebaseextensions.v1beta.function
        description: >-
          Backfill existing messages with uppercase versions
        properties:
          runtime: "nodejs18"
          taskQueueTrigger: {}
    

    তারপর onInstall লাইফসাইকেল ইভেন্টের জন্য হ্যান্ডলার হিসাবে ফাংশনটিকে ঘোষণা করুন:

    lifecycleEvents:
      onInstall:
        function: backfilldata
        processingMessage: Uppercasing existing messages
    
  3. যদিও বিদ্যমান বার্তাগুলিকে ব্যাকফিল করা ভাল, তবে এক্সটেনশনটি এখনও এটি ছাড়াই কাজ করতে পারে৷ এই ধরনের পরিস্থিতিতে, আপনার লাইফসাইকেল ইভেন্ট হ্যান্ডলার চালানো ঐচ্ছিক করা উচিত।

    এটি করতে, extension.yaml এ একটি নতুন প্যারামিটার যোগ করুন:

    - param: DO_BACKFILL
      label: Backfill existing messages
      description: >-
        Generate uppercase versions of existing messages?
      type: select
      required: true
      options:
        - label: Yes
          value: true
        - label: No
          value: false
    

    তারপরে ব্যাকফিল ফাংশনের শুরুতে, DO_BACKFILL প্যারামিটারের মানটি পরীক্ষা করুন এবং এটি সেট না থাকলে তাড়াতাড়ি প্রস্থান করুন:

    functions/index.js

    if (!process.env.DO_BACKFILL) {
      return getExtensions()
        .runtime()
        .setProcessingState("PROCESSING_COMPLETE", "Backfill skipped.");
    }
    

উপরের পরিবর্তনগুলির সাথে, এক্সটেনশনটি এখন বিদ্যমান বার্তাগুলিকে বড় হাতের অক্ষরে রূপান্তর করবে যখন এটি ইনস্টল করা হবে।

এই বিন্দু পর্যন্ত, আপনি আপনার এক্সটেনশন বিকাশ করতে এবং চলমান পরিবর্তনগুলি পরীক্ষা করতে এক্সটেনশন এমুলেটর ব্যবহার করেছেন। যাইহোক, এক্সটেনশন এমুলেটর ইনস্টলেশন প্রক্রিয়াটি এড়িয়ে যায়, তাই আপনার onInstall ইভেন্ট হ্যান্ডলার পরীক্ষা করতে, আপনাকে একটি বাস্তব প্রকল্পে এক্সটেনশনটি ইনস্টল করতে হবে। যদিও এটি ঠিক তেমনি, যেহেতু এই স্বয়ংক্রিয় ব্যাকফিল বৈশিষ্ট্যটি যোগ করার সাথে সাথে, টিউটোরিয়াল এক্সটেনশনটি এখন কোড-সম্পূর্ণ!

9. একটি বাস্তব ফায়ারবেস প্রকল্পে স্থাপন করুন

যদিও এক্সটেনশন এমুলেটরটি বিকাশের সময় একটি এক্সটেনশনে দ্রুত পুনরাবৃত্তি করার জন্য একটি দুর্দান্ত সরঞ্জাম, কিছু সময়ে আপনি এটি একটি বাস্তব প্রকল্পে চেষ্টা করতে চাইবেন।

এটি করতে, প্রথমে কিছু পরিষেবা সক্ষম করে একটি নতুন প্রকল্প সেট আপ করুন:

  1. Firebase কনসোলে , একটি নতুন প্রকল্প যোগ করুন।
  2. আপনার প্রজেক্টকে পে-অ্যাজ-ইউ-গো ব্লেজ প্ল্যানে আপগ্রেড করুন । Firebase-এর জন্য ক্লাউড ফাংশনগুলির জন্য আপনার প্রকল্পের একটি বিলিং অ্যাকাউন্ট থাকা প্রয়োজন, তাই একটি এক্সটেনশন ইনস্টল করার জন্য আপনার একটি বিলিং অ্যাকাউন্টও প্রয়োজন৷
  3. আপনার নতুন প্রকল্পে, রিয়েল-টাইম ডেটাবেস সক্ষম করুন
  4. যেহেতু আপনি ইনস্টলেশনে বিদ্যমান ডেটা ব্যাকফিল করার জন্য আপনার এক্সটেনশনের ক্ষমতা পরীক্ষা করতে চান, তাই আপনার রিয়েল-টাইম ডাটাবেস উদাহরণে কিছু নমুনা ডেটা আমদানি করুন:
    1. কিছু বীজ RTDB ডেটা ডাউনলোড করুন।
    2. Firebase কনসোলের রিয়েল-টাইম ডেটাবেস পৃষ্ঠায়, (আরও) > JSON আমদানিতে ক্লিক করুন এবং আপনি যে ফাইলটি ডাউনলোড করেছেন সেটি নির্বাচন করুন।
  5. orderByChild পদ্ধতি ব্যবহার করার জন্য ব্যাকফিল ফাংশন সক্ষম করতে, upper মানের উপর বার্তা সূচীতে ডাটাবেস কনফিগার করুন:

    {
      "rules": {
        ".read": false,
        ".write": false,
        "messages": {
          ".indexOn": "upper"
        }
      }
    }
    

এখন নতুন প্রকল্পে স্থানীয় উত্স থেকে আপনার এক্সটেনশন ইনস্টল করুন:

  1. আপনার ফায়ারবেস প্রকল্পের জন্য একটি নতুন ডিরেক্টরি তৈরি করুন:

    mkdir ~/extensions-live-test && cd ~/extensions-live-test
    
  2. ওয়ার্কিং ডিরেক্টরিতে একটি ফায়ারবেস প্রকল্প শুরু করুন:

    firebase init database

    যখন অনুরোধ করা হয়, আপনি এইমাত্র তৈরি করা প্রকল্পটি নির্বাচন করুন।

  3. আপনার স্থানীয় ফায়ারবেস প্রকল্পে এক্সটেনশনটি ইনস্টল করুন:

    firebase ext:install /path/to/rtdb-uppercase-messages

    এখানে আপনি Firebase CLI টুল ব্যবহার করে একটি এক্সটেনশন ইনস্টল করার সময় ব্যবহারকারীর অভিজ্ঞতা কেমন তা দেখতে পারেন। আপনি আপনার বিদ্যমান ডাটাবেস ব্যাকফিল করতে চান কিনা কনফিগারেশন টুল জিজ্ঞাসা করলে "হ্যাঁ" নির্বাচন করতে ভুলবেন না।

    আপনি কনফিগারেশন বিকল্পগুলি নির্বাচন করার পরে, Firebase CLI আপনার কনফিগারেশনটি extensions ডিরেক্টরিতে সংরক্ষণ করবে এবং firebase.json ফাইলে এক্সটেনশন উত্স অবস্থান রেকর্ড করবে৷ সম্মিলিতভাবে, এই দুটি রেকর্ডকে বলা হয় এক্সটেনশন ম্যানিফেস্ট । ব্যবহারকারীরা তাদের এক্সটেনশন কনফিগারেশন সংরক্ষণ করতে এবং বিভিন্ন প্রকল্পে এটি স্থাপন করতে ম্যানিফেস্ট ব্যবহার করতে পারেন।

  4. আপনার লাইভ প্রকল্পে আপনার এক্সটেনশন কনফিগারেশন স্থাপন করুন:

    firebase deploy --only extensions

সবকিছু ঠিকঠাক থাকলে, Firebase CLI-কে আপনার প্রজেক্টে আপনার এক্সটেনশন আপলোড করে ইনস্টল করতে হবে। ইনস্টলেশন সম্পূর্ণ হওয়ার পরে, ব্যাকফিল টাস্কটি চলবে এবং কয়েক মিনিটের মধ্যে, আপনার ডাটাবেস বড় হাতের বার্তাগুলির সাথে আপডেট করা হবে। বার্তা ডাটাবেসে কিছু নতুন নোড যোগ করুন এবং নিশ্চিত করুন যে এক্সটেনশনটি নতুন বার্তাগুলির জন্যও কাজ করছে।

10. ডকুমেন্টেশন লিখুন

আপনি ব্যবহারকারীদের সাথে আপনার এক্সটেনশন শেয়ার করার আগে, তাদের সফল হওয়ার জন্য আপনি যথেষ্ট ডকুমেন্টেশন প্রদান করছেন তা নিশ্চিত করুন।

আপনি যখন এক্সটেনশন প্রজেক্ট শুরু করেন, তখন Firebase CLI ন্যূনতম প্রয়োজনীয় ডকুমেন্টেশনের স্টাব সংস্করণ তৈরি করে। আপনি যে এক্সটেনশনটি তৈরি করেছেন তা সঠিকভাবে প্রতিফলিত করতে এই ফাইলগুলি আপডেট করুন৷

extension.yaml

আপনি ইতিমধ্যে এই ফাইলটি আপডেট করছেন যেহেতু আপনি এই এক্সটেনশনটি তৈরি করেছেন, তাই আপনাকে এখনই আর কোনো আপডেট করতে হবে না৷

যাইহোক, এই ফাইলটিতে থাকা ডকুমেন্টেশনের গুরুত্বকে উপেক্ষা করবেন না। একটি এক্সটেনশনের গুরুত্বপূর্ণ শনাক্তকরণ তথ্য-নাম, বিবরণ, লেখক, অফিসিয়াল রিপোজিটরি অবস্থান-এর পাশাপাশি extension.yaml ফাইলটিতে প্রতিটি সংস্থান এবং ব্যবহারকারী-কনফিগারযোগ্য প্যারামিটারের জন্য ব্যবহারকারী-মুখী ডকুমেন্টেশন রয়েছে। এই তথ্যটি Firebase কনসোল, এক্সটেনশন হাব এবং Firebase CLI-এর ব্যবহারকারীদের কাছে প্রকাশ করা হয়েছে।

PREINSTALL.md

এই ফাইলে, আপনার এক্সটেনশন ইনস্টল করার আগে ব্যবহারকারীর প্রয়োজনীয় তথ্য প্রদান করুন: এক্সটেনশনটি কী করে তা সংক্ষেপে বর্ণনা করুন, কোনো পূর্বশর্ত ব্যাখ্যা করুন এবং এক্সটেনশন ইনস্টল করার বিলিং প্রভাব সম্পর্কে ব্যবহারকারীকে তথ্য দিন। আপনার যদি অতিরিক্ত তথ্য সহ একটি ওয়েবসাইট থাকে তবে এটি লিঙ্ক করার জন্য এটি একটি ভাল জায়গা।

এই ফাইলের পাঠ্য ব্যবহারকারীর কাছে Extensions Hub এবং firebase ext:info কমান্ড দ্বারা প্রদর্শিত হয়।

এখানে একটি প্রিইনস্টল ফাইলের একটি উদাহরণ রয়েছে:

Use this extension to automatically convert strings to upper case when added to
a specified Realtime Database path.

This extension expects a database layout like the following example:

    "messages": {
      MESSAGE_ID: {
        "original": MESSAGE_TEXT
      },
      MESSAGE_ID: {
        "original": MESSAGE_TEXT
      },
    }

When you create new string records, this extension creates a new sibling record
with upper-cased text:

    MESSAGE_ID: {
      "original": MESSAGE_TEXT,
      "upper": UPPERCASE_MESSAGE_TEXT,
    }

#### Additional setup

Before installing this extension, make sure that you've
[set up Realtime Database](https://firebase.google.com/docs/database/quickstart)
in your Firebase project.

#### Billing

To install an extension, your project must be on the
[Blaze (pay as you go) plan](https://firebase.google.com/pricing).

- This extension uses other Firebase and Google Cloud Platform services, which
  have associated charges if you exceed the service's no-cost tier:
  - Realtime Database
  - Cloud Functions (Node.js 10+ runtime)
    [See FAQs](https://firebase.google.com/support/faq#extensions-pricing)
- If you enable events,
  [Eventarc fees apply](https://cloud.google.com/eventarc/pricing).

POSTINSTALL.md

এই ফাইলটিতে ব্যবহারকারীরা সফলভাবে আপনার এক্সটেনশন ইনস্টল করার পরে তাদের জন্য উপযোগী তথ্য রয়েছে: উদাহরণস্বরূপ, ফলো-আপ সেটআপ পদক্ষেপ, এক্সটেনশনের কার্যকারিতার উদাহরণ এবং আরও অনেক কিছু।

একটি এক্সটেনশন কনফিগার এবং ইনস্টল করার পরে POSTINSTALL.md এর বিষয়বস্তু Firebase কনসোলে প্রদর্শিত হয়। আপনি এই ফাইলে ব্যবহারকারীর পরামিতি উল্লেখ করতে পারেন এবং সেগুলি কনফিগার করা মান দ্বারা প্রতিস্থাপিত হবে।

এখানে টিউটোরিয়াল এক্সটেনশনের জন্য পোস্ট-ইনস্টল ফাইলের একটি উদাহরণ রয়েছে:

### See it in action

You can test out this extension right away!

1.  Go to your
    [Realtime Database dashboard](https://console.firebase.google.com/project/${param:PROJECT_ID}/database/${param:PROJECT_ID}/data) in the Firebase console.

1.  Add a message string to a path that matches the pattern `${param:MESSAGE_PATH}`.

1.  In a few seconds, you'll see a sibling node named `upper` that contains the
    message in upper case.

### Using the extension

We recommend adding data by pushing -- for example,
`firebase.database().ref().push()` -- because pushing assigns an automatically
generated ID to the node in the database. During retrieval, these nodes are
guaranteed to be ordered by the time they were added. Learn more about reading
and writing data for your platform (iOS, Android, or Web) in the
[Realtime Database documentation](https://firebase.google.com/docs/database/).

### Monitoring

As a best practice, you can
[monitor the activity](https://firebase.google.com/docs/extensions/manage-installed-extensions#monitor)
of your installed extension, including checks on its health, usage, and logs.

CHANGELOG.md

আপনি CHANGELOG.md ফাইলে একটি এক্সটেনশনের রিলিজের মধ্যে যে পরিবর্তনগুলি করেছেন তাও নথিভুক্ত করা উচিত।

যেহেতু উদাহরণ এক্সটেনশনটি আগে কখনো প্রকাশিত হয়নি, পরিবর্তন লগে শুধুমাত্র একটি এন্ট্রি আছে:

## Version 0.0.1

Initial release of the _Convert messages to upper case_ extension.

README.md

বেশিরভাগ এক্সটেনশনগুলি এক্সটেনশনের সংগ্রহস্থলে যাওয়া ব্যবহারকারীদের সুবিধার জন্য একটি রিডমি ফাইলও প্রদান করে। আপনি এই ফাইলটি হাতে লিখতে পারেন বা কমান্ড ব্যবহার করে একটি read me তৈরি করতে পারেন।

এই গাইডের উদ্দেশ্যে, একটি রিডমি ফাইল লেখা এড়িয়ে যান।

অতিরিক্ত ডকুমেন্টেশন

উপরে আলোচনা করা ডকুমেন্টেশন হল ডকুমেন্টেশনের ন্যূনতম সেট যা আপনাকে ব্যবহারকারীদের প্রদান করতে হবে। ব্যবহারকারীদের সফলভাবে ব্যবহার করার জন্য অনেক এক্সটেনশনের আরো বিস্তারিত ডকুমেন্টেশন প্রয়োজন। যখন এটি হয়, তখন আপনাকে অতিরিক্ত ডকুমেন্টেশন লিখতে হবে এবং এটি হোস্ট করা উচিত যেখানে আপনি ব্যবহারকারীদের নির্দেশ করতে পারেন।

এই গাইডের উদ্দেশ্যে, আরও বিস্তৃত ডকুমেন্টেশন লেখা এড়িয়ে যান।

11. এক্সটেনশন হাবে প্রকাশ করুন৷

এখন যেহেতু আপনার এক্সটেনশনটি কোড সম্পূর্ণ এবং নথিভুক্ত, আপনি এটিকে এক্সটেনশন হাবে বিশ্বের সাথে ভাগ করতে প্রস্তুত৷ কিন্তু যেহেতু এটি শুধুমাত্র একটি টিউটোরিয়াল, আসলে তা করবেন না। যান এবং আপনি এখানে যা শিখেছেন তা ব্যবহার করে আপনার নিজের এক্সটেনশন লিখতে শুরু করুন এবং Firebase এক্সটেনশন প্রকাশক ডকুমেন্টেশনের বাকি অংশে, এবং অফিসিয়াল, Firebase-লিখিত, এক্সটেনশনের উৎস পরীক্ষা করে।

যখন আপনি Extensions Hub-এ আপনার কাজ প্রকাশ করতে প্রস্তুত হন তখন আপনি এটি কীভাবে করবেন তা এখানে রয়েছে:

  1. আপনি যদি আপনার প্রথম এক্সটেনশন প্রকাশ করেন, তাহলে একটি এক্সটেনশন প্রকাশক হিসাবে নিবন্ধন করুন ৷ যখন আপনি একটি এক্সটেনশন প্রকাশক হিসাবে নিবন্ধন করেন, তখন আপনি একটি প্রকাশক আইডি তৈরি করেন যা ব্যবহারকারীদের দ্রুত আপনাকে আপনার এক্সটেনশনের লেখক হিসাবে সনাক্ত করতে দেয়৷
  2. আপনার এক্সটেনশনের সোর্স কোড একটি সর্বজনীনভাবে যাচাইযোগ্য স্থানে হোস্ট করুন। যখন আপনার কোড একটি যাচাইযোগ্য উৎস থেকে পাওয়া যায়, তখন Firebase সরাসরি এই অবস্থান থেকে আপনার এক্সটেনশন প্রকাশ করতে পারে। এটি করা নিশ্চিত করতে সাহায্য করে যে আপনি আপনার এক্সটেনশনের বর্তমানে প্রকাশিত সংস্করণ প্রকাশ করছেন এবং ব্যবহারকারীদের তাদের প্রকল্পগুলিতে ইনস্টল করা কোড পরীক্ষা করতে দিয়ে তাদের সহায়তা করে৷

    বর্তমানে, এর অর্থ হল আপনার এক্সটেনশনটি একটি সর্বজনীন GitHub সংগ্রহস্থলে উপলব্ধ করা।

  3. firebase ext:dev:upload কমান্ড ব্যবহার করে এক্সটেনশন হাবে আপনার এক্সটেনশন আপলোড করুন।

  4. Firebase কনসোলে আপনার প্রকাশক ড্যাশবোর্ডে যান, আপনি এইমাত্র আপলোড করা এক্সটেনশনটি খুঁজুন এবং "এক্সটেনশন হাবে প্রকাশ করুন" এ ক্লিক করুন৷ এটি আমাদের পর্যালোচনা কর্মীদের কাছ থেকে একটি পর্যালোচনার অনুরোধ করে, এতে কয়েক দিন সময় লাগতে পারে৷ অনুমোদিত হলে, এক্সটেনশনটি এক্সটেনশন হাবে প্রকাশ করা হবে। প্রত্যাখ্যান করা হলে, আপনি কারণ ব্যাখ্যা করে একটি বার্তা পাবেন; তারপরে আপনি রিপোর্ট করা সমস্যাগুলির সমাধান করতে পারেন এবং পর্যালোচনার জন্য আবার জমা দিতে পারেন৷

,

এই পৃষ্ঠাটি আপনাকে একটি সাধারণ ফায়ারবেস এক্সটেনশন তৈরি করার জন্য প্রয়োজনীয় পদক্ষেপগুলির মধ্যে নিয়ে যায়, যা আপনি আপনার প্রকল্পগুলিতে ইনস্টল করতে বা অন্যদের সাথে ভাগ করতে পারেন৷ একটি Firebase এক্সটেনশনের এই সাধারণ উদাহরণটি আপনার বার্তাগুলির জন্য রিয়েলটাইম ডেটাবেস দেখবে এবং সেগুলিকে বড় হাতের অক্ষরে রূপান্তর করবে৷

1. আপনার পরিবেশ সেট আপ করুন এবং একটি প্রকল্প শুরু করুন

আপনি একটি এক্সটেনশন নির্মাণ শুরু করার আগে, আপনাকে প্রয়োজনীয় সরঞ্জামগুলির সাথে একটি বিল্ড পরিবেশ সেট আপ করতে হবে৷

  1. Node.js 16 বা নতুন ইনস্টল করুন। নোড ইনস্টল করার একটি উপায় হল nvm (বা nvm-windows ) ব্যবহার করে।

  2. Firebase CLI- এর সর্বশেষ সংস্করণে ইনস্টল বা আপডেট করুন। npm ব্যবহার করে ইনস্টল বা আপডেট করতে, এই কমান্ডটি চালান:

    npm install -g firebase-tools

এখন একটি নতুন এক্সটেনশন প্রকল্প শুরু করতে Firebase CLI ব্যবহার করুন:

  1. আপনার এক্সটেনশনের জন্য একটি ডিরেক্টরি তৈরি করুন এবং এতে cd :

    mkdir rtdb-uppercase-messages && cd rtdb-uppercase-messages
  2. Firebase CLI-এর ext:dev:init কমান্ড চালান:

    firebase ext:dev:init

    প্রম্পট করা হলে, ফাংশনগুলির জন্য ভাষা হিসাবে JavaScript বেছে নিন (কিন্তু মনে রাখবেন যে আপনি যখন নিজের এক্সটেনশন তৈরি করেন তখন আপনি TypeScript ব্যবহার করতে পারেন), এবং, যখন নির্ভরতা ইনস্টল করতে বলা হয়, তখন "হ্যাঁ" উত্তর দিন। (অন্য যেকোন বিকল্পের জন্য ডিফল্ট গ্রহণ করুন।) এই কমান্ডটি একটি নতুন এক্সটেনশনের জন্য একটি কঙ্কাল কোডবেস সেট আপ করবে, যেখান থেকে আপনি আপনার এক্সটেনশনের বিকাশ শুরু করতে পারেন।

2. এমুলেটর ব্যবহার করে উদাহরণ এক্সটেনশন চেষ্টা করুন

যখন ফায়ারবেস সিএলআই নতুন এক্সটেনশন ডিরেক্টরিটি শুরু করেছিল, এটি একটি সাধারণ উদাহরণ ফাংশন এবং একটি integration-tests ডিরেক্টরি তৈরি করেছে যাতে ফায়ারবেস এমুলেটর স্যুট ব্যবহার করে একটি এক্সটেনশন চালানোর জন্য প্রয়োজনীয় ফাইলগুলি রয়েছে।

এমুলেটরে উদাহরণ এক্সটেনশনটি চালানোর চেষ্টা করুন:

  1. integration-tests ডিরেক্টরিতে পরিবর্তন করুন:

    cd functions/integration-tests
  2. একটি ডেমো প্রকল্প দিয়ে এমুলেটরটি শুরু করুন:

    firebase emulators:start --project=demo-test

    এমুলেটরটি এক্সটেনশনটিকে পূর্বনির্ধারিত "ডামি" প্রকল্পে ( demo-test ) লোড করে। এখনও অবধি এক্সটেনশনে একটি একক এইচটিটিপি-ট্রিগারড ফাংশন, greetTheWorld রয়েছে যা অ্যাক্সেস করার সময় একটি "হ্যালো ওয়ার্ল্ড" বার্তা দেয়।

  3. এমুলেটরটি এখনও চলমান থাকায়, আপনি যখন এটি শুরু করেছিলেন তখন এটি মুদ্রিত ইউআরএলটি পরিদর্শন করে এক্সটেনশনের greetTheWorld ফাংশনটি ব্যবহার করে দেখুন।

    আপনার ব্রাউজারটি "শুভেচ্ছা-দ্য ওয়ার্ল্ড থেকে হ্যালো ওয়ার্ল্ড" বার্তাটি প্রদর্শন করে।

  4. এই ফাংশনের উত্স কোডটি এক্সটেনশনের functions ডিরেক্টরিতে রয়েছে। আপনার পছন্দের সম্পাদক বা আইডিইতে উত্সটি খুলুন:

    ফাংশন/সূচক.জেএস

    const functions = require("firebase-functions/v1");
    
    exports.greetTheWorld = functions.https.onRequest((req, res) => {
      // Here we reference a user-provided parameter
      // (its value is provided by the user during installation)
      const consumerProvidedGreeting = process.env.GREETING;
    
      // And here we reference an auto-populated parameter
      // (its value is provided by Firebase after installation)
      const instanceId = process.env.EXT_INSTANCE_ID;
    
      const greeting = `${consumerProvidedGreeting} World from ${instanceId}`;
    
      res.send(greeting);
    });
    
  5. এমুলেটর চলমান থাকাকালীন, এটি আপনার ফাংশন কোডে যে কোনও পরিবর্তন স্বয়ংক্রিয়ভাবে পুনরায় লোড করবে। greetTheWorld ফাংশনে একটি ছোট পরিবর্তন করার চেষ্টা করুন:

    ফাংশন/সূচক.জেএস

    const greeting = `${consumerProvidedGreeting} everyone, from ${instanceId}`;
    

    আপনার পরিবর্তন সংরক্ষণ করুন. এমুলেটরটি আপনার কোডটি পুনরায় লোড করবে এবং এখন, আপনি যখন ফাংশন ইউআরএল পরিদর্শন করবেন, আপনি আপডেট হওয়া শুভেচ্ছা দেখতে পাবেন।

3 .. এক্সটেনশন.ইমলে প্রাথমিক তথ্য যুক্ত করুন

এখন যেহেতু আপনার একটি উন্নয়ন পরিবেশ স্থাপন করা হয়েছে এবং এক্সটেনশন এমুলেটরটি চালাচ্ছেন, আপনি নিজের এক্সটেনশনটি লেখা শুরু করতে পারেন।

একটি পরিমিত প্রথম পদক্ষেপ হিসাবে, আপনি greet-the-world পরিবর্তে লিখতে চান এমন এক্সটেনশনটি প্রতিফলিত করতে পূর্বনির্ধারিত এক্সটেনশন মেটাডেটা সম্পাদনা করুন। এই মেটাডেটা extension.yaml ফাইলে সংরক্ষণ করা হয়।

  1. আপনার সম্পাদকটিতে extension.yaml খুলুন এবং ফাইলের পুরো বিষয়বস্তুগুলি নিম্নলিখিতগুলির সাথে প্রতিস্থাপন করুন:

    name: rtdb-uppercase-messages
    version: 0.0.1
    specVersion: v1beta  # Firebase Extensions specification version; don't change
    
    # Friendly display name for your extension (~3-5 words)
    displayName: Convert messages to upper case
    
    # Brief description of the task your extension performs (~1 sentence)
    description: >-
      Converts messages in RTDB to upper case
    
    author:
      authorName: Your Name
      url: https://your-site.example.com
    
    license: Apache-2.0  # Required license
    
    # Public URL for the source code of your extension
    sourceUrl: https://github.com/your-name/your-repo
    

    name ক্ষেত্রটিতে ব্যবহৃত নামকরণ কনভেনশনটি নোট করুন: অফিসিয়াল ফায়ারবেস এক্সটেনশনের নামকরণ করা হয়েছে একটি উপসর্গের সাথে প্রাথমিক ফায়ারবেস পণ্যটি নির্দেশ করে যে এক্সটেনশনটি পরিচালিত হয়, তারপরে এক্সটেনশনটি কী করে তার বিবরণ দেওয়া হয়। আপনার নিজের এক্সটেনশনে একই সম্মেলনটি ব্যবহার করা উচিত।

  2. যেহেতু আপনি আপনার এক্সটেনশনের নাম পরিবর্তন করেছেন, আপনার নতুন নামের সাথে আপনার এমুলেটর কনফিগারেশনটিও আপডেট করা উচিত:

    1. functions/integration-tests/firebase.json , rtdb-uppercase-messages greet-the-world পরিবর্তন করুন।
    2. functions/integration-tests/extensions/greet-the-world.env functions/integration-tests/extensions/rtdb-uppercase-messages.env নামকরণ করুন।

আপনার এক্সটেনশন কোডে অবশিষ্ট greet-the-world এক্সটেনশনের কিছু অবশিষ্টাংশ এখনও রয়েছে তবে আপাতত এগুলি ছেড়ে দিন। আপনি পরবর্তী কয়েকটি বিভাগে সেগুলি আপডেট করবেন।

4 ... একটি ক্লাউড ফাংশন লিখুন এবং এটিকে একটি এক্সটেনশন রিসোর্স হিসাবে ঘোষণা করুন

এখন আপনি কিছু কোড লিখতে শুরু করতে পারেন। এই পদক্ষেপে, আপনি একটি ক্লাউড ফাংশন লিখবেন যা আপনার এক্সটেনশনের মূল কাজটি সম্পাদন করে, যা বার্তাগুলির জন্য আপনার রিয়েলটাইম ডাটাবেসটি দেখতে এবং তাদেরকে উচ্চতর ক্ষেত্রে রূপান্তরিত করে।

  1. আপনার পছন্দের সম্পাদক বা আইডিইতে এক্সটেনশনের ফাংশনগুলির (এক্সটেনশনের functions ডিরেক্টরিতে) উত্সটি খুলুন। নিম্নলিখিতগুলির সাথে এর সামগ্রীগুলি প্রতিস্থাপন করুন:

    ফাংশন/সূচক.জেএস

    import { database, logger } from "firebase-functions/v1";
    
    const app = initializeApp();
    
    // Listens for new messages added to /messages/{pushId}/original and creates an
    // uppercase version of the message to /messages/{pushId}/uppercase
    // for all databases in 'us-central1'
    export const makeuppercase = database
      .ref("/messages/{pushId}/uppercase")
      .onCreate(async (snapshot, context) => {
        // Grab the current value of what was written to the Realtime Database.
        const original = snapshot.val();
    
        // Convert it to upper case.
        logger.log("Uppercasing", context.params.pushId, original);
        const uppercase = original.toUpperCase();
    
        // Setting an "uppercase" sibling in the Realtime Database.
        const upperRef = snapshot.ref.parent.child("upper");
        await upperRef.set(uppercase);
    });
    

    পুরানো ফাংশনটি, যা আপনি প্রতিস্থাপন করেছেন, এটি একটি এইচটিটিপি-ট্রিগারযুক্ত ফাংশন ছিল, যা এইচটিটিপি এন্ডপয়েন্টটি অ্যাক্সেস করার সময় চলেছিল। নতুন ফাংশনটি রিয়েল-টাইম ডাটাবেস ইভেন্টগুলি দ্বারা ট্রিগার করা হয়: এটি একটি নির্দিষ্ট পথে নতুন আইটেমগুলির জন্য নজর রাখে এবং যখন একটি সনাক্ত করা হয়, তখন এটি ডাটাবেসে মানের ফিরে মানটির বড় হাতের সংস্করণটি লিখে।

    যাইহোক, এই নতুন ফাইলটি সাধারণজে ( require ) এর পরিবর্তে ইসমা স্ক্রিপ্ট মডিউল সিনট্যাক্স ( importexport ) ব্যবহার করে। নোডে ইএস মডিউলগুলি ব্যবহার করতে, functions/package.json "type": "module" নির্দিষ্ট করুন:

    {
      "name": "rtdb-uppercase-messages",
      "main": "index.js",
      "type": "module",
      
    }
    
  2. আপনার এক্সটেনশনের প্রতিটি ফাংশন অবশ্যই extension.yaml ফাইলে ঘোষণা করতে হবে। উদাহরণ এক্সটেনশনটি এক্সটেনশনের একমাত্র মেঘ ফাংশন হিসাবে greetTheWorld ঘোষণা করেছে; এখন আপনি এটি makeuppercase সাথে প্রতিস্থাপন করেছেন, আপনাকে এর ঘোষণাটিও আপডেট করতে হবে।

    extension.yaml খুলুন এবং একটি resources ক্ষেত্র যুক্ত করুন:

    resources:
      - name: makeuppercase
        type: firebaseextensions.v1beta.function
        properties:
          eventTrigger:
            eventType: providers/google.firebase.database/eventTypes/ref.create
            # DATABASE_INSTANCE (project's default instance) is an auto-populated
            # parameter value. You can also specify an instance.
            resource: projects/_/instances/${DATABASE_INSTANCE}/refs/messages/{pushId}/original
          runtime: "nodejs18"
    
  3. যেহেতু আপনার এক্সটেনশনটি এখন ট্রিগার হিসাবে রিয়েলটাইম ডাটাবেস ব্যবহার করছে, তাই ক্লাউড ফাংশন এমুলেটর পাশাপাশি আরটিডিবি এমুলেটর চালানোর জন্য আপনাকে আপনার এমুলেটর কনফিগারেশন আপডেট করতে হবে:

    1. যদি এমুলেটরটি এখনও চলছে, তবে সিটিআরএল-সি টিপে এটি বন্ধ করুন।

    2. functions/integration-tests ডিরেক্টরি থেকে, নিম্নলিখিত কমান্ডটি চালান:

      firebase init emulators

      যখন জিজ্ঞাসা করা হয়, একটি ডিফল্ট প্রকল্প সেট আপ করা এড়িয়ে যান, তারপরে ফাংশন এবং ডাটাবেস এমুলেটরগুলি নির্বাচন করুন। ডিফল্ট পোর্টগুলি গ্রহণ করুন এবং সেটআপ সরঞ্জামটিকে কোনও প্রয়োজনীয় ফাইল ডাউনলোড করার অনুমতি দিন।

    3. এমুলেটর পুনরায় চালু করুন:

      firebase emulators:start --project=demo-test
  4. আপনার আপডেট হওয়া এক্সটেনশনটি ব্যবহার করে দেখুন:

    1. আপনি যখন এটি শুরু করেছিলেন তখন প্রিন্ট করা লিঙ্কটি ব্যবহার করে ডাটাবেস এমুলেটর ইউআই খুলুন।

    2. ডাটাবেসের মূল নোড সম্পাদনা করুন:

      • ক্ষেত্র: messages
      • প্রকার: json
      • মান: {"11": {"original": "recipe"}}

      যদি সবকিছু সঠিকভাবে সেট আপ করা হয়, আপনি যখন আপনার ডাটাবেস পরিবর্তনগুলি সংরক্ষণ করেন, তখন এক্সটেনশনের makeuppercase ফাংশনটি ট্রিগার করা উচিত এবং "upper": "RECIPE" বিষয়বস্তু সহ 11 বার্তায় একটি শিশু রেকর্ড যুক্ত করা উচিত। প্রত্যাশিত ফলাফলগুলি নিশ্চিত করতে এমুলেটর ইউআইয়ের লগগুলি এবং ডাটাবেস ট্যাবগুলি একবার দেখুন।

    3. messages নোডে আরও কিছু শিশু যুক্ত করার চেষ্টা করুন ( {"original":"any text"} )। আপনি যখনই একটি নতুন রেকর্ড যুক্ত করবেন, এক্সটেনশনে original ক্ষেত্রের বড় হাতের সামগ্রীযুক্ত একটি uppercase ক্ষেত্র যুক্ত করা উচিত।

আপনার কাছে এখন একটি সম্পূর্ণ, যদিও সহজ, এক্সটেনশন যা একটি আরটিডিবি উদাহরণে কাজ করে। নিম্নলিখিত বিভাগগুলিতে, আপনি কিছু অতিরিক্ত বৈশিষ্ট্য সহ এই এক্সটেনশনটি পরিমার্জন করবেন। তারপরে, আপনি অন্যকে বিতরণ করার জন্য এক্সটেনশনটি প্রস্তুত পাবেন এবং শেষ পর্যন্ত কীভাবে এক্সটেনশন হাবটিতে আপনার এক্সটেনশনটি প্রকাশ করবেন তা শিখুন।

5। এপিআই এবং ভূমিকা ঘোষণা করুন

ফায়ারবেস একটি ইনস্টল এক্সটেনশনের প্রতিটি উদাহরণকে প্রকল্পে সীমিত অ্যাক্সেস এবং প্রতি-অনুপ্রেরণা পরিষেবা অ্যাকাউন্ট ব্যবহার করে এর ডেটা মঞ্জুর করে। প্রতিটি অ্যাকাউন্টে পরিচালনার জন্য প্রয়োজনীয় ন্যূনতম অনুমতিগুলির সেট রয়েছে। এই কারণে, আপনাকে অবশ্যই আপনার এক্সটেনশনের প্রয়োজনীয় কোনও আইএএম ভূমিকা স্পষ্টভাবে ঘোষণা করতে হবে; ব্যবহারকারীরা যখন আপনার এক্সটেনশন ইনস্টল করেন, ফায়ারবেস মঞ্জুর করা এই ভূমিকাগুলির সাথে একটি পরিষেবা অ্যাকাউন্ট তৈরি করে এবং এটি এক্সটেনশনটি চালানোর জন্য ব্যবহার করে।

কোনও পণ্যের ইভেন্টগুলি ট্রিগার করার জন্য আপনার ভূমিকা ঘোষণা করার দরকার নেই, তবে অন্যথায় এটির সাথে যোগাযোগের জন্য আপনাকে একটি ভূমিকা ঘোষণা করতে হবে। আপনি শেষ ধাপে যে ফাংশনটি যুক্ত করেছেন তা রিয়েলটাইম ডাটাবেসে লিখেছেন, আপনাকে নিম্নলিখিত ঘোষণাটি extension.yaml যুক্ত করতে হবে y

roles:
  - role: firebasedatabase.admin
    reason: Allows the extension to write to RTDB.

একইভাবে, আপনি গুগল এপিআইগুলিকে ঘোষণা করেন যে কোনও এক্সটেনশন apis ক্ষেত্রে ব্যবহার করে। ব্যবহারকারীরা যখন আপনার এক্সটেনশনটি ইনস্টল করেন, তাদের জিজ্ঞাসা করা হবে যে তারা তাদের প্রকল্পের জন্য এই এপিআইগুলি স্বয়ংক্রিয়ভাবে সক্ষম করতে চায় কিনা। এটি সাধারণত নন-ফায়ারবেস গুগল এপিআইয়ের জন্য প্রয়োজনীয় এবং এই গাইডের জন্য প্রয়োজন হয় না।

6 .. ব্যবহারকারী-কনফিগারযোগ্য পরামিতিগুলি সংজ্ঞায়িত করুন

শেষ দুটি পদক্ষেপে আপনি যে ফাংশনটি তৈরি করেছেন তা আগত বার্তাগুলির জন্য একটি নির্দিষ্ট আরটিডিবি অবস্থান দেখেছে। কখনও কখনও, একটি নির্দিষ্ট অবস্থান দেখা সত্যিই আপনি যা চান তা হ'ল যেমন আপনার এক্সটেনশনটি যখন কোনও ডাটাবেস কাঠামোর উপর কাজ করে যা আপনি আপনার এক্সটেনশনের জন্য একচেটিয়াভাবে ব্যবহার করেন। তবে, বেশিরভাগ সময়, আপনি এই মানগুলি তাদের প্রকল্পগুলিতে আপনার এক্সটেনশন ইনস্টল করা ব্যবহারকারীদের দ্বারা কনফিগারযোগ্য করে তুলতে চাইবেন। এইভাবে, ব্যবহারকারীরা তাদের বিদ্যমান ডাটাবেস সেটআপের সাথে কাজ করতে আপনার এক্সটেনশনটি ব্যবহার করতে পারেন।

নতুন বার্তাগুলির জন্য এক্সটেনশনটি যে পথটি ব্যবহার করে তা ব্যবহারকারী-কনফিগারযোগ্য: সেই পথটি তৈরি করুন:

  1. extension.yaml ফাইলে, একটি params বিভাগ যুক্ত করুন:

    - param: MESSAGE_PATH
      label: Message path
      description: >-
        What is the path at which the original text of a message can be found?
      type: string
      default: /messages/{pushId}/original
      required: true
      immutable: false
    

    এটি একটি নতুন স্ট্রিং প্যারামিটার সংজ্ঞায়িত করে যা ব্যবহারকারীরা আপনার এক্সটেনশন ইনস্টল করার সময় সেট করতে অনুরোধ জানানো হবে।

  2. এখনও extension.yaml ফাইলে, আপনার makeuppercase ঘোষণায় ফিরে যান এবং resource ক্ষেত্রটি নিম্নলিখিতগুলিতে পরিবর্তন করুন:

    resource: projects/_/instances/${DATABASE_INSTANCE}/refs/${param:MESSAGE_PATH}
    

    ${param:MESSAGE_PATH} টোকেন হ'ল আপনি সবেমাত্র সংজ্ঞায়িত প্যারামিটারের একটি রেফারেন্স। যখন আপনার এক্সটেনশনটি চলে, এই টোকেনটি সেই প্যারামিটারের জন্য কনফিগার করা ব্যবহারকারী যে কোনও মান দ্বারা প্রতিস্থাপন করা হবে, ফলস্বরূপ যে makeuppercase ফাংশনটি ব্যবহারকারী নির্দিষ্ট করা পথটি শুনবে। আপনি যে কোনও ব্যবহারকারী-সংজ্ঞায়িত প্যারামিটারটি extension.yaml (এবং POSTINSTALL.md তে পরে আরও পরে) রেফারেন্স করতে এই সিনট্যাক্সটি ব্যবহার করতে পারেন।

  3. আপনি আপনার ফাংশন কোড থেকে ব্যবহারকারী-সংজ্ঞায়িত পরামিতিগুলি অ্যাক্সেস করতে পারেন।

    আপনি শেষ বিভাগে যে ফাংশনটি লিখেছেন, আপনি পরিবর্তনের জন্য দেখার জন্য কঠোর কোড করেছেন। পরিবর্তে ব্যবহারকারী-সংজ্ঞায়িত মান উল্লেখ করতে ট্রিগার সংজ্ঞাটি পরিবর্তন করুন:

    ফাংশন/সূচক.জেএস

    export const makeuppercase = database.ref(process.env.MESSAGE_PATH).onCreate
    

    নোট করুন যে ফায়ারবেস এক্সটেনশনে, এই পরিবর্তনটি নিখুঁতভাবে ডকুমেন্টেশনের স্বার্থে: যখন কোনও ক্লাউড ফাংশন কোনও এক্সটেনশনের অংশ হিসাবে মোতায়েন করা হয়, তখন এটি extension.yaml ফাইল থেকে ট্রিগার সংজ্ঞাটি ব্যবহার করে এবং ফাংশন সংজ্ঞাতে নির্দিষ্ট মান উপেক্ষা করে। তবুও, আপনার কোডটি যেখানে এই মানটি এসেছে সেখানে ডকুমেন্ট করা ভাল ধারণা।

  4. আপনি কোনও কোড পরিবর্তন করতে হতাশাব্যঞ্জক হতে পারেন যার কোনও রানটাইম প্রভাব নেই, তবে তা সরিয়ে নেওয়ার গুরুত্বপূর্ণ পাঠটি হ'ল আপনি আপনার ফাংশন কোডের যে কোনও ব্যবহারকারী-সংজ্ঞায়িত প্যারামিটার অ্যাক্সেস করতে পারেন এবং এটি ফাংশনের যুক্তিতে একটি সাধারণ মান হিসাবে ব্যবহার করতে পারেন। এই সামর্থ্যের সম্মতি হিসাবে, নিম্নলিখিত লগ স্টেটমেন্টটি যুক্ত করুন যে আপনি ব্যবহারকারী যে মানটি সংজ্ঞায়িত করেছেন তা সত্যই অ্যাক্সেস করছেন:

    ফাংশন/সূচক.জেএস

    export const makeuppercase = database.ref(process.env.MESSAGE_PATH).onCreate(
      async (snapshot, context) => {
        logger.log("Found new message at ", snapshot.ref);
    
        // Grab the current value of what was written to the Realtime Database.
        ...
    
  5. সাধারণত, ব্যবহারকারীরা যখন কোনও এক্সটেনশন ইনস্টল করে তখন প্যারামিটারগুলির জন্য মান সরবরাহ করতে অনুরোধ করা হয়। আপনি যখন পরীক্ষা এবং বিকাশের জন্য এমুলেটরটি ব্যবহার করেন, তবে আপনি ইনস্টলেশন প্রক্রিয়াটি এড়িয়ে যান, সুতরাং আপনি পরিবর্তে একটি env ফাইল ব্যবহার করে ব্যবহারকারী-সংজ্ঞায়িত পরামিতিগুলির জন্য মান সরবরাহ করেন।

    ওপেন functions/integration-tests/extensions/rtdb-uppercase-messages.env এবং GREETING সংজ্ঞাটি নিম্নলিখিতগুলির সাথে প্রতিস্থাপন করুন:

    MESSAGE_PATH=/msgs/{pushId}/original
    

    লক্ষ্য করুন যে উপরের পথটি ডিফল্ট পথ থেকে এবং আপনি পূর্বে সংজ্ঞায়িত পথ থেকে পৃথক; আপনি যখন আপনার সংজ্ঞাটি কার্যকর করছেন এমন আপডেট এক্সটেনশনের চেষ্টা করার সময় এটি কেবল নিজেকে প্রমাণ করার জন্য।

  6. এখন, এমুলেটরটি পুনরায় চালু করুন এবং আবারও ডাটাবেস এমুলেটর ইউআই দেখুন।

    আপনি উপরে সংজ্ঞায়িত পথটি ব্যবহার করে ডাটাবেসের মূল নোডটি সম্পাদনা করুন:

    • ক্ষেত্র: msgs
    • প্রকার: json
    • মান: {"11": {"original": "recipe"}}

    আপনি যখন আপনার ডাটাবেস পরিবর্তনগুলি সংরক্ষণ করেন, এক্সটেনশনের makeuppercase ফাংশনটি আগের মতো ট্রিগার করা উচিত, তবে এখন এটি কনসোল লগতে ব্যবহারকারী-সংজ্ঞায়িত প্যারামিটারটিও মুদ্রণ করা উচিত।

7 .. ব্যবহারকারী-সংজ্ঞায়িত যুক্তির জন্য ইভেন্ট হুক সরবরাহ করুন

আপনি ইতিমধ্যে দেখেছেন, এক্সটেনশন লেখক হিসাবে, কীভাবে একটি ফায়ারবেস পণ্য আপনার এক্সটেনশন-সরবরাহিত যুক্তি ট্রিগার করতে পারে: রিয়েলটাইম ডাটাবেসে নতুন রেকর্ড তৈরি করা আপনার makeuppercase ফাংশনকে ট্রিগার করে। আপনার এক্সটেনশনে আপনার এক্সটেনশন ইনস্টল করা ব্যবহারকারীদের সাথে একটি সাদৃশ্যপূর্ণ সম্পর্ক থাকতে পারে: আপনার এক্সটেনশনটি ব্যবহারকারী সংজ্ঞায়িত যুক্তি ট্রিগার করতে পারে।

একটি এক্সটেনশন সিঙ্ক্রোনাস হুক , অ্যাসিনক্রোনাস হুক বা উভয়ই সরবরাহ করতে পারে। সিঙ্ক্রোনাস হুকগুলি ব্যবহারকারীদের এক্সটেনশনের কোনও ক্রিয়াকলাপের সমাপ্তি অবরুদ্ধ করে এমন কাজগুলি সম্পাদনের একটি উপায় দেয়। এটি কার্যকর হতে পারে, উদাহরণস্বরূপ, ব্যবহারকারীদের কোনও এক্সটেনশনের কাজ করার আগে কাস্টম প্রিপ্রোসেসিং সম্পাদনের একটি উপায় দেওয়া।

এই গাইডে, আপনি আপনার এক্সটেনশনে একটি অ্যাসিঙ্ক্রোনাস হুক যুক্ত করবেন, যা ব্যবহারকারীদের আপনার এক্সটেনশানটি রিয়েলটাইম ডাটাবেসে বড় হাতের বার্তা লেখার পরে তাদের নিজস্ব প্রক্রিয়াকরণ পদক্ষেপগুলি সংজ্ঞায়িত করতে সক্ষম করবে। অ্যাসিঙ্ক্রোনাস হুকগুলি ব্যবহারকারী-সংজ্ঞায়িত ফাংশনগুলি ট্রিগার করতে ইভেন্টার্ক ব্যবহার করে। এক্সটেনশানগুলি তাদের নির্গত ইভেন্টগুলির ধরণগুলি ঘোষণা করে এবং ব্যবহারকারীরা যখন এক্সটেনশনটি ইনস্টল করেন, তারা কোন ইভেন্টে আগ্রহী তারা বেছে নেন els এরপরে ব্যবহারকারীরা তাদের নিজস্ব ক্লাউড ফাংশনগুলি স্থাপন করতে পারেন যা সেই চ্যানেলে শোনেন এবং ট্রিগারটি যখন এক্সটেনশনটি নতুন ইভেন্টগুলি প্রকাশ করে।

অ্যাসিনক্রোনাস হুক যুক্ত করতে এই পদক্ষেপগুলি অনুসরণ করুন:

  1. extension.yaml ফাইলে, নিম্নলিখিত বিভাগটি যুক্ত করুন, যা একটি ইভেন্টের প্রকারের ঘোষণা করে এক্সটেনশনটি নির্গত করে:

    events:
      - type: test-publisher.rtdb-uppercase-messages.v1.complete
        description: >-
          Occurs when message uppercasing completes. The event subject will contain
          the RTDB URL of the uppercase message.
    

    ইভেন্টের ধরণগুলি অবশ্যই সর্বজনীনভাবে অনন্য হতে হবে; স্বতন্ত্রতা নিশ্চিত করতে, সর্বদা নিম্নলিখিত ফর্ম্যাটটি ব্যবহার করে আপনার ইভেন্টগুলির নাম দিন: <publisher-id>.<extension-id>.<version>.<description> >। (আপনার কাছে এখনও কোনও প্রকাশক আইডি নেই, তাই আপাতত কেবল test-publisher ব্যবহার করুন))

  2. makeuppercase ফাংশন শেষে, এমন কিছু কোড যুক্ত করুন যা আপনি সবেমাত্র ঘোষণা করেছেন এমন ধরণের একটি ইভেন্ট প্রকাশ করে:

    ফাংশন/সূচক.জেএস

    // Import the Eventarc library:
    import { initializeApp } from "firebase-admin/app";
    import { getEventarc } from "firebase-admin/eventarc";
    
    const app = initializeApp();
    
    // In makeuppercase, after upperRef.set(uppercase), add:
    
    // Set eventChannel to a newly-initialized channel, or `undefined` if events
    // aren't enabled.
    const eventChannel =
      process.env.EVENTARC_CHANNEL &&
      getEventarc().channel(process.env.EVENTARC_CHANNEL, {
        allowedEventTypes: process.env.EXT_SELECTED_EVENTS,
      });
    
    // If events are enabled, publish a `complete` event to the configured
    // channel.
    eventChannel &&
      eventChannel.publish({
        type: "test-publisher.rtdb-uppercase-messages.v1.complete",
        subject: upperRef.toString(),
        data: {
          "original": original,
          "uppercase": uppercase,
        },
      });
    

    এই উদাহরণ কোডটি এই সত্যটি গ্রহণ করে যে EVENTARC_CHANNEL এনভায়রনমেন্ট ভেরিয়েবলটি কেবল তখনই সংজ্ঞায়িত করা হয় যখন ব্যবহারকারী কমপক্ষে একটি ইভেন্টের ধরণ সক্ষম করে। যদি EVENTARC_CHANNEL সংজ্ঞায়িত না করা হয় তবে কোডটি কোনও ইভেন্ট প্রকাশের চেষ্টা করে না।

    আপনি কোনও ইভেন্টের ইভেন্টে অতিরিক্ত তথ্য সংযুক্ত করতে পারেন। উপরের উদাহরণে, ইভেন্টটির একটি subject ক্ষেত্র রয়েছে যা সদ্য নির্মিত মানের মানের একটি রেফারেন্স এবং একটি data পে-লোড রয়েছে যাতে মূল এবং বড় হাতের বার্তা রয়েছে। ইভেন্টটি বন্ধ করে দেওয়া ব্যবহারকারী-সংজ্ঞায়িত ফাংশনগুলি এই তথ্যটি ব্যবহার করতে পারে।

  3. সাধারণত, EVENTARC_CHANNEL এবং EXT_SELECTED_EVENTS এনভায়রনমেন্ট ভেরিয়েবলগুলি ইনস্টলেশনের সময় নির্বাচিত বিকল্পগুলির উপর ভিত্তি করে সংজ্ঞায়িত করা হয়। এমুলেটর দিয়ে পরীক্ষার জন্য, rtdb-uppercase-messages.env ফাইলটিতে ম্যানুয়ালি এই ভেরিয়েবলগুলি সংজ্ঞায়িত করুন:

    EVENTARC_CHANNEL=locations/us-central1/channels/firebase
    EXT_SELECTED_EVENTS=test-publisher.rtdb-uppercase-messages.v1.complete
    

এই মুহুর্তে, আপনি আপনার এক্সটেনশনে একটি অ্যাসিঙ্ক্রোনাস ইভেন্ট হুক যুক্ত করার জন্য প্রয়োজনীয় পদক্ষেপগুলি সম্পন্ন করেছেন।

আপনি সবেমাত্র বাস্তবায়িত হয়েছে এমন নতুন বৈশিষ্ট্যটি চেষ্টা করে দেখুন, পরবর্তী কয়েকটি পদক্ষেপে, এক্সটেনশনটি ইনস্টল করা ব্যবহারকারীর ভূমিকা গ্রহণ করুন:

  1. functions/integration-tests ডিরেক্টরি থেকে, একটি নতুন ফায়ারবেস প্রকল্প শুরু করুন:

    firebase init functions

    যখন অনুরোধ করা হয়, একটি ডিফল্ট প্রকল্প সেট আপ করতে অস্বীকার করুন, ক্লাউড ফাংশন ভাষা হিসাবে জাভাস্ক্রিপ্ট নির্বাচন করুন এবং প্রয়োজনীয় নির্ভরতা ইনস্টল করুন। এই প্রকল্পটি কোনও ব্যবহারকারীর প্রকল্পের প্রতিনিধিত্ব করে, যা আপনার এক্সটেনশন ইনস্টল করা আছে।

  2. integration-tests/functions/index.js সম্পাদনা করুন এবং নিম্নলিখিত কোডটি আটকান:

    import { logger } from "firebase-functions/v1";
    import { onCustomEventPublished } from "firebase-functions/v2/eventarc";
    
    import { initializeApp } from "firebase-admin/app";
    import { getDatabase } from "firebase-admin/database";
    
    const app = initializeApp();
    
    export const extraemphasis = onCustomEventPublished(
      "test-publisher.rtdb-uppercase-messages.v1.complete",
      async (event) => {
        logger.info("Received makeuppercase completed event", event);
    
        const refUrl = event.subject;
        const ref = getDatabase().refFromURL(refUrl);
        const upper = (await ref.get()).val();
        return ref.set(`${upper}!!!`);
      }
    );
    

    এটি কোনও ব্যবহারকারী লিখতে পারে এমন পোস্ট-প্রসেসিং ফাংশনের উদাহরণ। এই ক্ষেত্রে, ফাংশনটি একটি complete ইভেন্ট প্রকাশের জন্য এক্সটেনশনের জন্য শোনায় এবং যখন ট্রিগার করা হয়, তখন সদ্য আপত্তিজনক বার্তায় তিনটি বিস্ময়কর পয়েন্ট যুক্ত করে।

  3. এমুলেটর পুনরায় চালু করুন। এমুলেটর এক্সটেনশনের ফাংশনগুলি পাশাপাশি পোস্ট-প্রসেসিং ফাংশনটি "ব্যবহারকারী" সংজ্ঞায়িত করে লোড করবে।

  4. আপনি উপরে সংজ্ঞায়িত পথটি ব্যবহার করে ডাটাবেস এমুলেটর ইউআই দেখুন এবং ডাটাবেসের মূল নোড সম্পাদনা করুন:

    • ক্ষেত্র: msgs
    • প্রকার: json
    • মান: {"11": {"original": "recipe"}}

    আপনি যখন আপনার ডাটাবেস পরিবর্তনগুলি সংরক্ষণ করেন, তখন এক্সটেনশনের makeuppercase ফাংশন এবং ব্যবহারকারীর extraemphasis ফাংশনটি ক্রমানুসারে ট্রিগার করা উচিত, যার ফলে upper ক্ষেত্রটি মান RECIPE!!! .

8 .. লাইফসাইকেল ইভেন্ট হ্যান্ডলারগুলি যুক্ত করুন

আপনি যে এক্সটেনশনটি লিখেছেন তা এখন পর্যন্ত বার্তাগুলি তৈরি হওয়ার সাথে সাথে প্রক্রিয়া করে। তবে যদি আপনার ব্যবহারকারীদের এক্সটেনশনটি ইনস্টল করার সময় ইতিমধ্যে বার্তাগুলির একটি ডাটাবেস থাকে তবে কী হবে? ফায়ারবেস এক্সটেনশনের লাইফসাইকেল ইভেন্ট হুকস নামে একটি বৈশিষ্ট্য রয়েছে যা আপনি যখন আপনার এক্সটেনশনটি ইনস্টল, আপডেট বা পুনর্গঠিত হয়ে যায় তখন ক্রিয়াকলাপগুলি ট্রিগার করতে ব্যবহার করতে পারেন। এই বিভাগে, আপনি যখন কোনও ব্যবহারকারী আপনার এক্সটেনশন ইনস্টল করেন তখন কোনও প্রকল্পের বিদ্যমান বার্তা ডাটাবেসকে বড় বার্তাগুলির সাথে ব্যাকফিল করতে আপনি লাইফসাইকেল ইভেন্ট হুক ব্যবহার করবেন।

ফায়ারবেস এক্সটেনশানগুলি আপনার লাইফসাইকেল ইভেন্ট হ্যান্ডলারগুলি চালানোর জন্য ক্লাউড কাজগুলি ব্যবহার করে। আপনি ক্লাউড ফাংশন ব্যবহার করে ইভেন্ট হ্যান্ডলারগুলি সংজ্ঞায়িত করেন; যখনই আপনার এক্সটেনশনের কোনও উদাহরণ সমর্থিত লাইফসাইকেল ইভেন্টগুলির মধ্যে একটিতে পৌঁছে যায়, আপনি যদি কোনও হ্যান্ডলারকে সংজ্ঞায়িত করেন তবে এটি হ্যান্ডলারটিকে ক্লাউড টাস্কস সারিতে যুক্ত করবে। ক্লাউড টাস্কগুলি তখন অ্যাসিঙ্ক্রোনালি হ্যান্ডলারটি কার্যকর করবে। একটি লাইফসাইকেল ইভেন্ট হ্যান্ডলার চলাকালীন, ফায়ারবেস কনসোলটি ব্যবহারকারীকে রিপোর্ট করবে যে এক্সটেনশন ইনস্ট্যান্সের একটি প্রক্রিয়াজাতকরণ কাজ চলছে। চলমান স্থিতি এবং ব্যবহারকারীর কাছে টাস্ক সমাপ্তির প্রতিবেদন করার জন্য এটি আপনার হ্যান্ডলার ফাংশনের উপর নির্ভর করে।

একটি লাইফসাইকেল ইভেন্ট হ্যান্ডলার যুক্ত করতে যা বিদ্যমান বার্তাগুলি ব্যাকফিল করে, নিম্নলিখিতগুলি করুন:

  1. একটি নতুন ক্লাউড ফাংশন সংজ্ঞায়িত করুন যা টাস্ক সারি ইভেন্টগুলি দ্বারা ট্রিগার করা হয়েছে:

    ফাংশন/সূচক.জেএস

    import { tasks } from "firebase-functions/v1";
    
    import { getDatabase } from "firebase-admin/database";
    import { getExtensions } from "firebase-admin/extensions";
    import { getFunctions } from "firebase-admin/functions";
    
    export const backfilldata = tasks.taskQueue().onDispatch(async () => {
      const batch = await getDatabase()
        .ref(process.env.MESSAGE_PATH)
        .parent.parent.orderByChild("upper")
        .limitToFirst(20)
        .get();
    
      const promises = [];
      for (const key in batch.val()) {
        const msg = batch.child(key);
        if (msg.hasChild("original") && !msg.hasChild("upper")) {
          const upper = msg.child("original").val().toUpperCase();
          promises.push(msg.child("upper").ref.set(upper));
        }
      }
      await Promise.all(promises);
    
      if (promises.length > 0) {
        const queue = getFunctions().taskQueue(
          "backfilldata",
          process.env.EXT_INSTANCE_ID
        );
        return queue.enqueue({});
      } else {
        return getExtensions()
          .runtime()
          .setProcessingState("PROCESSING_COMPLETE", "Backfill complete.");
      }
    });
    

    লক্ষ্য করুন যে ফাংশনটি কেবল টাস্ক কাতারে নিজেকে যুক্ত করার আগে কয়েকটি রেকর্ড প্রক্রিয়া করে। এটি প্রসেসিং কার্যগুলি মোকাবেলার জন্য একটি সাধারণভাবে ব্যবহৃত কৌশল যা মেঘ ফাংশনের সময়সীমা উইন্ডোর মধ্যে সম্পূর্ণ করতে পারে না। যেহেতু আপনি আপনার এক্সটেনশনটি ইনস্টল করার সময় কোনও ব্যবহারকারীর ইতিমধ্যে তাদের ডাটাবেসে কতগুলি বার্তা থাকতে পারে তা আপনি পূর্বাভাস দিতে পারবেন না, এই কৌশলটি একটি ভাল ফিট।

  2. extension.yaml ফাইলে, আপনার ব্যাকফিল ফাংশনটিকে একটি এক্সটেনশন রিসোর্স হিসাবে ঘোষণা করুন যাতে taskQueueTrigger সম্পত্তি রয়েছে:

    resources:
      - name: makeuppercase
        ...
      - name: backfilldata
        type: firebaseextensions.v1beta.function
        description: >-
          Backfill existing messages with uppercase versions
        properties:
          runtime: "nodejs18"
          taskQueueTrigger: {}
    

    তারপরে ফাংশনটিকে onInstall লাইফসাইকেল ইভেন্টের হ্যান্ডলার হিসাবে ঘোষণা করুন:

    lifecycleEvents:
      onInstall:
        function: backfilldata
        processingMessage: Uppercasing existing messages
    
  3. যদিও বিদ্যমান বার্তাগুলি ব্যাকফিলিং করা ভাল তবে এক্সটেনশনটি এখনও এটি ছাড়া কাজ করতে পারে। এই জাতীয় পরিস্থিতিতে আপনার লাইফসাইকেল ইভেন্ট হ্যান্ডলারগুলি al চ্ছিক চালানো উচিত।

    এটি করতে, extension.yaml একটি নতুন প্যারামিটার যুক্ত করুন y

    - param: DO_BACKFILL
      label: Backfill existing messages
      description: >-
        Generate uppercase versions of existing messages?
      type: select
      required: true
      options:
        - label: Yes
          value: true
        - label: No
          value: false
    

    তারপরে ব্যাকফিল ফাংশনের শুরুতে, DO_BACKFILL প্যারামিটারের মানটি পরীক্ষা করুন এবং এটি সেট না থাকলে তাড়াতাড়ি প্রস্থান করুন:

    ফাংশন/সূচক.জেএস

    if (!process.env.DO_BACKFILL) {
      return getExtensions()
        .runtime()
        .setProcessingState("PROCESSING_COMPLETE", "Backfill skipped.");
    }
    

উপরোক্ত পরিবর্তনগুলির সাথে, এক্সটেনশনটি এখন বিদ্যমান বার্তাগুলি ইনস্টল করার সময় বড় হাতের কাছে রূপান্তর করবে।

এই অবধি, আপনি আপনার এক্সটেনশন এবং চলমান পরিবর্তনগুলি পরীক্ষা করতে এক্সটেনশন এমুলেটরটি ব্যবহার করেছেন। যাইহোক, এক্সটেনশন এমুলেটরটি ইনস্টলেশন প্রক্রিয়াটি এড়িয়ে যায়, সুতরাং আপনার onInstall ইভেন্ট হ্যান্ডলারটি পরীক্ষা করার জন্য আপনাকে একটি বাস্তব প্রকল্পে এক্সটেনশনটি ইনস্টল করতে হবে। যদিও এটি ঠিক তেমনই, যেহেতু এই স্বয়ংক্রিয় ব্যাকফিল বৈশিষ্ট্যটি যুক্ত করার সাথে সাথে টিউটোরিয়াল এক্সটেনশনটি এখন কোড-সম্পূর্ণ!

9। একটি বাস্তব ফায়ারবেস প্রকল্পে স্থাপন করুন

যদিও এক্সটেনশানস এমুলেটরটি বিকাশের সময় কোনও এক্সটেনশনে দ্রুত পুনরাবৃত্তি করার জন্য একটি দুর্দান্ত সরঞ্জাম, তবে এক পর্যায়ে আপনি এটি একটি বাস্তব প্রকল্পে চেষ্টা করতে চাইবেন।

এটি করার জন্য, প্রথমে কিছু পরিষেবা সক্ষম করে একটি নতুন প্রকল্প সেট আপ করুন:

  1. ফায়ারবেস কনসোলে একটি নতুন প্রকল্প যুক্ত করুন।
  2. আপনার প্রকল্পটি আপনার কাছে যাওয়ার মতো ব্লেজ পরিকল্পনায় আপগ্রেড করুন । ফায়ারবেসের জন্য ক্লাউড ফাংশনগুলির জন্য আপনার প্রকল্পের একটি বিলিং অ্যাকাউন্ট থাকা দরকার, তাই আপনার একটি এক্সটেনশন ইনস্টল করার জন্য একটি বিলিং অ্যাকাউন্টও প্রয়োজন।
  3. আপনার নতুন প্রকল্পে, রিয়েল-টাইম ডাটাবেস সক্ষম করুন
  4. যেহেতু আপনি ইনস্টলেশনে বিদ্যমান ডেটা ব্যাকফিল করার জন্য আপনার এক্সটেনশনের দক্ষতা পরীক্ষা করতে চান, তাই আপনার রিয়েল-টাইম ডাটাবেস উদাহরণে কিছু নমুনা ডেটা আমদানি করুন:
    1. কিছু বীজ আরটিডিবি ডেটা ডাউনলোড করুন।
    2. ফায়ারবেস কনসোলের রিয়েল-টাইম ডাটাবেস পৃষ্ঠায়, (আরও)> ক্লিক করুন ক্লিক করুন JSON এবং আপনি সবে ডাউনলোড করা ফাইলটি নির্বাচন করুন।
  5. orderByChild পদ্ধতিটি ব্যবহার করতে ব্যাকফিল ফাংশন সক্ষম করতে, upper মানটিতে সূচক বার্তাগুলিতে ডাটাবেসটি কনফিগার করুন:

    {
      "rules": {
        ".read": false,
        ".write": false,
        "messages": {
          ".indexOn": "upper"
        }
      }
    }
    

এখন স্থানীয় উত্স থেকে আপনার এক্সটেনশনটি নতুন প্রকল্পে ইনস্টল করুন:

  1. আপনার ফায়ারবেস প্রকল্পের জন্য একটি নতুন ডিরেক্টরি তৈরি করুন:

    mkdir ~/extensions-live-test && cd ~/extensions-live-test
    
  2. ওয়ার্কিং ডিরেক্টরিতে একটি ফায়ারবেস প্রকল্প শুরু করুন:

    firebase init database

    যখন অনুরোধ করা হয়, আপনি সবেমাত্র তৈরি করা প্রকল্পটি নির্বাচন করুন।

  3. আপনার স্থানীয় ফায়ারবেস প্রকল্পে এক্সটেনশনটি ইনস্টল করুন:

    firebase ext:install /path/to/rtdb-uppercase-messages

    এখানে আপনি ফায়ারবেস সিএলআই সরঞ্জামটি ব্যবহার করে কোনও এক্সটেনশন ইনস্টল করার সময় ব্যবহারকারীর অভিজ্ঞতা কেমন তা দেখতে পারেন। কনফিগারেশন সরঞ্জামটি যখন আপনি আপনার বিদ্যমান ডাটাবেসটি ব্যাকফিল করতে চান তবে "হ্যাঁ" নির্বাচন করতে ভুলবেন না।

    আপনি কনফিগারেশন বিকল্পগুলি নির্বাচন করার পরে, ফায়ারবেস সিএলআই extensions ডিরেক্টরিতে আপনার কনফিগারেশনটি সংরক্ষণ করবে এবং firebase.json ফাইলে এক্সটেনশন উত্সের অবস্থানটি রেকর্ড করবে। সম্মিলিতভাবে, এই দুটি রেকর্ডকে এক্সটেনশনস ম্যানিফেস্ট বলা হয়। ব্যবহারকারীরা তাদের এক্সটেনশন কনফিগারেশন সংরক্ষণ করতে এবং এটি বিভিন্ন প্রকল্পে স্থাপন করতে ম্যানিফেস্টটি ব্যবহার করতে পারেন।

  4. আপনার লাইভ প্রকল্পে আপনার এক্সটেনশন কনফিগারেশন স্থাপন করুন:

    firebase deploy --only extensions

যদি সবকিছু ঠিকঠাক হয় তবে ফায়ারবেস সিএলআই আপনার প্রকল্পে আপনার এক্সটেনশনটি আপলোড করে এটি ইনস্টল করা উচিত। ইনস্টলেশন শেষ হওয়ার পরে, ব্যাকফিল টাস্কটি চলবে এবং কয়েক মিনিটের মধ্যে আপনার ডাটাবেসটি বড় হাতের বার্তাগুলির সাথে আপডেট করা হবে। বার্তা ডাটাবেসে কিছু নতুন নোড যুক্ত করুন এবং নিশ্চিত করুন যে এক্সটেনশনটিও নতুন বার্তাগুলির জন্য কাজ করছে।

10। ডকুমেন্টেশন লিখুন

ব্যবহারকারীদের সাথে আপনার এক্সটেনশনটি ভাগ করার আগে, নিশ্চিত হয়ে নিন যে আপনি তাদের সফল হওয়ার জন্য পর্যাপ্ত ডকুমেন্টেশন সরবরাহ করছেন।

আপনি যখন এক্সটেনশন প্রকল্পটি শুরু করেছিলেন, ফায়ারবেস সিএলআই ন্যূনতম প্রয়োজনীয় ডকুমেন্টেশনের স্টাব সংস্করণ তৈরি করেছে। আপনার নির্মিত এক্সটেনশনটি সঠিকভাবে প্রতিফলিত করতে এই ফাইলগুলি আপডেট করুন।

এক্সটেনশন.ইমল

আপনি এই এক্সটেনশনটি বিকাশের সাথে সাথে ইতিমধ্যে এই ফাইলটি আপডেট করছেন, সুতরাং এখনই আপনাকে আরও কোনও আপডেট করার দরকার নেই।

তবে এই ফাইলটিতে থাকা ডকুমেন্টেশনের গুরুত্ব উপেক্ষা করবেন না। একটি এক্সটেনশনের গুরুত্বপূর্ণ সনাক্তকারী তথ্য ছাড়াও-নাম, বিবরণ, লেখক, অফিসিয়াল রিপোজিটরি অবস্থান- extension.yaml ফাইলটিতে প্রতিটি সংস্থান এবং ব্যবহারকারী-কনফিগারযোগ্য প্যারামিটারের জন্য ব্যবহারকারী-মুখোমুখি ডকুমেন্টেশন রয়েছে। এই তথ্যটি ফায়ারবেস কনসোল, এক্সটেনশন হাব এবং ফায়ারবেস সিএলআইয়ের ব্যবহারকারীদের কাছে প্রকাশিত হয়েছে।

Preinstall.md

এই ফাইলে, ব্যবহারকারীর আপনার এক্সটেনশন ইনস্টল করার আগে প্রয়োজনীয় তথ্য সরবরাহ করুন: এক্সটেনশনটি কী করে তা সংক্ষেপে বর্ণনা করুন, যে কোনও পূর্বশর্ত ব্যাখ্যা করুন এবং ব্যবহারকারীকে এক্সটেনশন ইনস্টল করার বিলিংয়ের প্রভাব সম্পর্কে তথ্য দিন। আপনার যদি অতিরিক্ত তথ্য সহ কোনও ওয়েবসাইট থাকে তবে এটি লিঙ্ক করার জন্য এটিও একটি ভাল জায়গা।

এই ফাইলের পাঠ্যটি এক্সটেনশন হাব এবং firebase ext:info কমান্ড দ্বারা ব্যবহারকারীর কাছে প্রদর্শিত হয়।

এখানে একটি প্রিনস্টল ফাইলের উদাহরণ রয়েছে:

Use this extension to automatically convert strings to upper case when added to
a specified Realtime Database path.

This extension expects a database layout like the following example:

    "messages": {
      MESSAGE_ID: {
        "original": MESSAGE_TEXT
      },
      MESSAGE_ID: {
        "original": MESSAGE_TEXT
      },
    }

When you create new string records, this extension creates a new sibling record
with upper-cased text:

    MESSAGE_ID: {
      "original": MESSAGE_TEXT,
      "upper": UPPERCASE_MESSAGE_TEXT,
    }

#### Additional setup

Before installing this extension, make sure that you've
[set up Realtime Database](https://firebase.google.com/docs/database/quickstart)
in your Firebase project.

#### Billing

To install an extension, your project must be on the
[Blaze (pay as you go) plan](https://firebase.google.com/pricing).

- This extension uses other Firebase and Google Cloud Platform services, which
  have associated charges if you exceed the service's no-cost tier:
  - Realtime Database
  - Cloud Functions (Node.js 10+ runtime)
    [See FAQs](https://firebase.google.com/support/faq#extensions-pricing)
- If you enable events,
  [Eventarc fees apply](https://cloud.google.com/eventarc/pricing).

Postinstall.md

এই ফাইলটিতে ব্যবহারকারীরা আপনার এক্সটেনশানটি সফলভাবে ইনস্টল করার পরে ব্যবহারকারীদের জন্য দরকারী তথ্য রয়েছে: উদাহরণস্বরূপ, ফলো-আপ সেটআপ পদক্ষেপগুলি, ক্রিয়াকলাপের এক্সটেনশনের উদাহরণ ইত্যাদি।

একটি এক্সটেনশন কনফিগার করা এবং ইনস্টল করার পরে ফায়ারবেস কনসোলে পোস্টইনস্টল.এমডি এর বিষয়বস্তু প্রদর্শিত হয়। আপনি এই ফাইলটিতে ব্যবহারকারীর পরামিতিগুলি উল্লেখ করতে পারেন এবং সেগুলি কনফিগার করা মান দ্বারা প্রতিস্থাপন করা হবে।

টিউটোরিয়াল এক্সটেনশনের জন্য পোস্ট-ইনস্টল ফাইলের উদাহরণ এখানে:

### See it in action

You can test out this extension right away!

1.  Go to your
    [Realtime Database dashboard](https://console.firebase.google.com/project/${param:PROJECT_ID}/database/${param:PROJECT_ID}/data) in the Firebase console.

1.  Add a message string to a path that matches the pattern `${param:MESSAGE_PATH}`.

1.  In a few seconds, you'll see a sibling node named `upper` that contains the
    message in upper case.

### Using the extension

We recommend adding data by pushing -- for example,
`firebase.database().ref().push()` -- because pushing assigns an automatically
generated ID to the node in the database. During retrieval, these nodes are
guaranteed to be ordered by the time they were added. Learn more about reading
and writing data for your platform (iOS, Android, or Web) in the
[Realtime Database documentation](https://firebase.google.com/docs/database/).

### Monitoring

As a best practice, you can
[monitor the activity](https://firebase.google.com/docs/extensions/manage-installed-extensions#monitor)
of your installed extension, including checks on its health, usage, and logs.

CHANGELOG.md

আপনার CHANGELOG.md ফাইলে কোনও এক্সটেনশনের রিলিজের মধ্যে যে পরিবর্তনগুলি করা হয়েছে সেগুলিও আপনার নথিভুক্ত করা উচিত।

যেহেতু উদাহরণ এক্সটেনশনটি আগে কখনও প্রকাশিত হয়নি, তাই পরিবর্তন লগটিতে কেবল একটি এন্ট্রি রয়েছে:

## Version 0.0.1

Initial release of the _Convert messages to upper case_ extension.

README.md

বেশিরভাগ এক্সটেনশানগুলি এক্সটেনশনের সংগ্রহস্থলে পরিদর্শন করা ব্যবহারকারীদের সুবিধার জন্য একটি README ফাইলও সরবরাহ করে। আপনি এই ফাইলটি হাতে লিখে লিখতে পারেন বা কমান্ডটি ব্যবহার করে আমাকে পড়ুন।

এই গাইডের উদ্দেশ্যে, একটি রিডমে ফাইল লিখতে এড়িয়ে যান।

অতিরিক্ত ডকুমেন্টেশন

উপরে আলোচিত ডকুমেন্টেশন হ'ল আপনার ব্যবহারকারীদের সরবরাহ করা উচিত ন্যূনতম ডকুমেন্টেশনের সেট। অনেক এক্সটেনশনের জন্য ব্যবহারকারীদের সফলভাবে সেগুলি ব্যবহার করার জন্য আরও বিশদ ডকুমেন্টেশন প্রয়োজন। যখন এটি হয়, আপনার অতিরিক্ত ডকুমেন্টেশন লিখতে হবে এবং এটি ব্যবহারকারীদের নির্দেশ করতে পারেন এমন কোথাও এটি হোস্ট করা উচিত।

এই গাইডের উদ্দেশ্যে, আরও বিস্তৃত ডকুমেন্টেশন লেখা এড়িয়ে যান।

11। এক্সটেনশন হাব এ প্রকাশ করুন

এখন যেহেতু আপনার এক্সটেনশনটি কোড সম্পূর্ণ এবং নথিভুক্ত, আপনি এটি এক্সটেনশন হাবের সাথে বিশ্বের সাথে ভাগ করে নিতে প্রস্তুত। তবে যেহেতু এটি কেবল একটি টিউটোরিয়াল, আসলে এটি করবেন না। আপনি এখানে যা শিখেছেন তা ব্যবহার করে এবং ফায়ারবেস এক্সটেনশনের বাকী প্রকাশক ডকুমেন্টেশন এবং অফিসিয়াল, ফায়ারবেস-লিখিত, এক্সটেনশনের উত্স পরীক্ষা করে আপনার নিজের এক্সটেনশনটি লিখতে শুরু করুন।

আপনি যখন এক্সটেনশান হাবের উপর আপনার কাজ প্রকাশ করতে প্রস্তুত হন তখন আপনি কীভাবে এটি করবেন তা এখানে:

  1. আপনি যদি আপনার প্রথম এক্সটেনশন প্রকাশ করছেন তবে এক্সটেনশন প্রকাশক হিসাবে নিবন্ধন করুন । আপনি যখন এক্সটেনশন প্রকাশক হিসাবে নিবন্ধন করেন, আপনি একটি প্রকাশক আইডি তৈরি করেন যা ব্যবহারকারীদের দ্রুত আপনাকে আপনার এক্সটেনশনের লেখক হিসাবে সনাক্ত করতে দেয়।
  2. আপনার এক্সটেনশনের উত্স কোডটি সর্বজনীনভাবে যাচাইযোগ্য স্থানে হোস্ট করুন। যখন আপনার কোডটি যাচাইযোগ্য উত্স থেকে পাওয়া যায়, ফায়ারবেস সরাসরি এই অবস্থান থেকে আপনার এক্সটেনশনটি প্রকাশ করতে পারে। এটি করা নিশ্চিত করতে সহায়তা করে যে আপনি আপনার এক্সটেনশনের বর্তমানে প্রকাশিত সংস্করণ প্রকাশ করছেন এবং ব্যবহারকারীদের তাদের প্রকল্পগুলিতে ইনস্টল করা কোডটি পরীক্ষা করে তাদের সহায়তা করে।

    বর্তমানে, এর অর্থ আপনার পাবলিক গিটহাব সংগ্রহস্থলে আপনার এক্সটেনশনটি উপলব্ধ করা।

  3. firebase ext:dev:upload কমান্ড ব্যবহার করে এক্সটেনশন হাবটিতে আপনার এক্সটেনশনটি আপলোড করুন।

  4. ফায়ারবেস কনসোলে আপনার প্রকাশক ড্যাশবোর্ডে যান, আপনি সবেমাত্র আপলোড করা এক্সটেনশনটি সন্ধান করুন এবং "এক্সটেনশন হাব প্রকাশ করুন" ক্লিক করুন। এটি আমাদের পর্যালোচনা কর্মীদের কাছ থেকে একটি পর্যালোচনার জন্য অনুরোধ করে, যা কয়েক দিন সময় নিতে পারে। অনুমোদিত হলে, এক্সটেনশন এক্সটেনশন হাবে প্রকাশিত হবে। যদি প্রত্যাখ্যান করা হয় তবে আপনি কারণ ব্যাখ্যা করে একটি বার্তা পাবেন; তারপরে আপনি রিপোর্ট করা সমস্যাগুলি সমাধান করতে পারেন এবং পর্যালোচনার জন্য পুনরায় জমা দিতে পারেন।

,

এই পৃষ্ঠাটি আপনাকে একটি সাধারণ ফায়ারবেস এক্সটেনশন তৈরির জন্য প্রয়োজনীয় পদক্ষেপগুলির মধ্য দিয়ে চলেছে, যা আপনি আপনার প্রকল্পগুলিতে ইনস্টল করতে পারেন বা অন্যের সাথে ভাগ করতে পারেন। ফায়ারবেস এক্সটেনশনের এই সাধারণ উদাহরণটি বার্তাগুলির জন্য আপনার রিয়েলটাইম ডাটাবেস দেখবে এবং এগুলিকে উচ্চতর ক্ষেত্রে রূপান্তর করবে।

1। আপনার পরিবেশ সেট আপ করুন এবং একটি প্রকল্প শুরু করুন

আপনি কোনও এক্সটেনশন তৈরি শুরু করার আগে, আপনাকে প্রয়োজনীয় সরঞ্জামগুলি সহ একটি বিল্ড পরিবেশ সেট আপ করতে হবে।

  1. নোড.জেএস 16 বা আরও নতুন ইনস্টল করুন। নোড ইনস্টল করার একটি উপায় হ'ল এনভিএম (বা এনভিএম-উইন্ডো ) ব্যবহার করে।

  2. ফায়ারবেস সিএলআইয়ের সর্বশেষ সংস্করণে ইনস্টল করুন বা আপডেট করুন। npm ব্যবহার করে ইনস্টল বা আপডেট করতে, এই কমান্ডটি চালান:

    npm install -g firebase-tools

এখন একটি নতুন এক্সটেনশন প্রকল্প শুরু করতে ফায়ারবেস সিএলআই ব্যবহার করুন:

  1. এটিতে আপনার এক্সটেনশন এবং cd জন্য একটি ডিরেক্টরি তৈরি করুন:

    mkdir rtdb-uppercase-messages && cd rtdb-uppercase-messages
  2. ফায়ারবেস সিএলআই এর ext:dev:init কমান্ড:

    firebase ext:dev:init

    যখন অনুরোধ করা হয়, জাভাস্ক্রিপ্ট ফাংশনগুলির ভাষা হিসাবে চয়ন করুন (তবে নোট করুন যে আপনি নিজের এক্সটেনশনটি বিকাশ করার সময় আপনি টাইপস্ক্রিপ্টও ব্যবহার করতে পারেন), এবং যখন নির্ভরতা ইনস্টল করতে বলা হয়, "হ্যাঁ" উত্তর দিন। (অন্য যে কোনও বিকল্পের জন্য ডিফল্টগুলি গ্রহণ করুন)) এই কমান্ডটি একটি নতুন এক্সটেনশনের জন্য একটি কঙ্কাল কোডবেস সেট আপ করবে, যা থেকে আপনি আপনার এক্সটেনশনটি বিকাশ শুরু করতে পারেন।

2। এমুলেটর ব্যবহার করে উদাহরণ এক্সটেনশনটি ব্যবহার করে দেখুন

যখন ফায়ারবেস সিএলআই নতুন এক্সটেনশন ডিরেক্টরিটি শুরু করেছিল, এটি একটি সাধারণ উদাহরণ ফাংশন এবং একটি integration-tests ডিরেক্টরি তৈরি করেছে যাতে ফায়ারবেস এমুলেটর স্যুট ব্যবহার করে একটি এক্সটেনশন চালানোর জন্য প্রয়োজনীয় ফাইলগুলি রয়েছে।

এমুলেটরে উদাহরণ এক্সটেনশনটি চালানোর চেষ্টা করুন:

  1. integration-tests ডিরেক্টরিতে পরিবর্তন করুন:

    cd functions/integration-tests
  2. একটি ডেমো প্রকল্প দিয়ে এমুলেটরটি শুরু করুন:

    firebase emulators:start --project=demo-test

    এমুলেটরটি এক্সটেনশনটিকে পূর্বনির্ধারিত "ডামি" প্রকল্পে ( demo-test ) লোড করে। এখনও অবধি এক্সটেনশনে একটি একক এইচটিটিপি-ট্রিগারড ফাংশন, greetTheWorld রয়েছে যা অ্যাক্সেস করার সময় একটি "হ্যালো ওয়ার্ল্ড" বার্তা দেয়।

  3. এমুলেটরটি এখনও চলমান থাকায়, আপনি যখন এটি শুরু করেছিলেন তখন এটি মুদ্রিত ইউআরএলটি পরিদর্শন করে এক্সটেনশনের greetTheWorld ফাংশনটি ব্যবহার করে দেখুন।

    Your browser displays the message "Hello World from greet-the-world".

  4. The source code for this function is in the extension's functions directory. Open the source in the editor or IDE of your choice:

    functions/index.js

    const functions = require("firebase-functions/v1");
    
    exports.greetTheWorld = functions.https.onRequest((req, res) => {
      // Here we reference a user-provided parameter
      // (its value is provided by the user during installation)
      const consumerProvidedGreeting = process.env.GREETING;
    
      // And here we reference an auto-populated parameter
      // (its value is provided by Firebase after installation)
      const instanceId = process.env.EXT_INSTANCE_ID;
    
      const greeting = `${consumerProvidedGreeting} World from ${instanceId}`;
    
      res.send(greeting);
    });
    
  5. While the emulator is running, it will automatically reload any changes you make to your Functions code. Try making a small change to the greetTheWorld function:

    functions/index.js

    const greeting = `${consumerProvidedGreeting} everyone, from ${instanceId}`;
    

    আপনার পরিবর্তন সংরক্ষণ করুন. The emulator will reload your code, and now, when you visit the function URL, you'll see the updated greeting.

3. Add basic information to extension.yaml

Now that you have a development environment set up and are running the extensions emulator, you can start writing your own extension.

As a modest first step, edit the predefined extension metadata to reflect the extension you want to write instead of greet-the-world . This metadata is stored in the extension.yaml file.

  1. Open extension.yaml in your editor, and replace the entire contents of the file with the following:

    name: rtdb-uppercase-messages
    version: 0.0.1
    specVersion: v1beta  # Firebase Extensions specification version; don't change
    
    # Friendly display name for your extension (~3-5 words)
    displayName: Convert messages to upper case
    
    # Brief description of the task your extension performs (~1 sentence)
    description: >-
      Converts messages in RTDB to upper case
    
    author:
      authorName: Your Name
      url: https://your-site.example.com
    
    license: Apache-2.0  # Required license
    
    # Public URL for the source code of your extension
    sourceUrl: https://github.com/your-name/your-repo
    

    Note the naming convention used in the name field: official Firebase extensions are named with a prefix indicating the primary Firebase product the extension operates on, followed by a description of what the extension does. You should use the same convention in your own extensions.

  2. Since you've changed the name of your extension, you should also update your emulator configuration with the new name:

    1. In functions/integration-tests/firebase.json , change greet-the-world to rtdb-uppercase-messages .
    2. Rename functions/integration-tests/extensions/greet-the-world.env to functions/integration-tests/extensions/rtdb-uppercase-messages.env .

There are still some remnants of the greet-the-world extension remaining in your extension code, but leave them for now. You'll update those in the next few sections.

4. Write a Cloud Function and declare it as an extension resource

Now you can get started writing some code. In this step, you will write a Cloud Function that performs the core task of your extension, which is to watch your Realtime Database for messages and convert them to upper case.

  1. Open the source for the extension's functions (in the extension's functions directory) in the editor or IDE of your choice. Replace its contents with the following:

    functions/index.js

    import { database, logger } from "firebase-functions/v1";
    
    const app = initializeApp();
    
    // Listens for new messages added to /messages/{pushId}/original and creates an
    // uppercase version of the message to /messages/{pushId}/uppercase
    // for all databases in 'us-central1'
    export const makeuppercase = database
      .ref("/messages/{pushId}/uppercase")
      .onCreate(async (snapshot, context) => {
        // Grab the current value of what was written to the Realtime Database.
        const original = snapshot.val();
    
        // Convert it to upper case.
        logger.log("Uppercasing", context.params.pushId, original);
        const uppercase = original.toUpperCase();
    
        // Setting an "uppercase" sibling in the Realtime Database.
        const upperRef = snapshot.ref.parent.child("upper");
        await upperRef.set(uppercase);
    });
    

    The old function, which you replaced, was an HTTP-triggered function, which ran when an HTTP endpoint was accessed. The new function is triggered by real-time database events: it watches for new items at a particular path and, when one is detected, it writes the uppercase version of the value back to the database.

    By the way, this new file uses ECMAScript module syntax ( import and export ) instead of CommonJS ( require ). To use ES modules in Node, specify "type": "module" in functions/package.json :

    {
      "name": "rtdb-uppercase-messages",
      "main": "index.js",
      "type": "module",
      
    }
    
  2. Every function in your extension must be declared in the extension.yaml file. The example extension declared greetTheWorld as the extension's only Cloud Function; now that you've replaced it with makeuppercase , you also need to update its declaration.

    Open extension.yaml and add a resources field:

    resources:
      - name: makeuppercase
        type: firebaseextensions.v1beta.function
        properties:
          eventTrigger:
            eventType: providers/google.firebase.database/eventTypes/ref.create
            # DATABASE_INSTANCE (project's default instance) is an auto-populated
            # parameter value. You can also specify an instance.
            resource: projects/_/instances/${DATABASE_INSTANCE}/refs/messages/{pushId}/original
          runtime: "nodejs18"
    
  3. Since your extension is now using Realtime Database as a trigger, you need to update your emulator configuration to run the RTDB emulator alongside the Cloud Functions emulator:

    1. If the emulator is still running, stop it by pressing Ctrl-C.

    2. From the functions/integration-tests directory, run the following command:

      firebase init emulators

      When asked, skip setting up a default project, then select the Functions and Database emulators. Accept the default ports and allow the setup tool to download any required files.

    3. Restart the emulator:

      firebase emulators:start --project=demo-test
  4. Try out your updated extension:

    1. Open the Database emulator UI using the link the emulator printed when you started it.

    2. Edit the root node of the database:

      • Field: messages
      • Type: json
      • Value: {"11": {"original": "recipe"}}

      If everything is set up correctly, when you save your database changes, the extension's makeuppercase function should trigger and add a child record to message 11 with the contents "upper": "RECIPE" . Take a look at the logs and the database tabs of the emulator UI to confirm the expected results.

    3. Try adding some more children to the messages node ( {"original":"any text"} ). Whenever you add a new record, the extension should add an uppercase field containing the uppercase contents of the original field.

You now have a complete, though simple, extension that operates on an RTDB instance. In the sections that follow, you will refine this extension with some additional features. Then, you'll get the extension ready to distribute to others, and finally, learn how to publish your extension on Extensions Hub.

5. Declare APIs and roles

Firebase grants each instance of an installed extension limited access to the project and its data using a per-instance service account. Each account has the minimum set of permissions needed to operate. For this reason, you must explicitly declare any IAM roles your extension requires; when users install your extension, Firebase creates a service account with these roles granted and uses it to run the extension.

You don't need to declare roles to trigger off a product's events, but you do need to declare a role to otherwise interact with it. Because the function you added in the last step writes to Realtime Database, you need to add the following declaration to extension.yaml :

roles:
  - role: firebasedatabase.admin
    reason: Allows the extension to write to RTDB.

Similarly, you declare the Google APIs that an extension uses in the apis field. When users install your extension, they will be asked if they want to automatically enable these APIs for their project. This is typically only necessary for non-Firebase Google APIs, and isn't needed for this guide.

6. Define user-configurable parameters

The function you created in the last two steps watched a specific RTDB location for incoming messages. Sometimes, watching a specific location really is what you want, such as when your extension operates on a database structure that you use exclusively for your extension. However, most of the time, you will want to make these values configurable by users who install your extension in their projects. This way, users can make use of your extension to work with their existing database setup.

Make the path that the extension watches for new messages user-configurable:

  1. In the extension.yaml file, add a params section:

    - param: MESSAGE_PATH
      label: Message path
      description: >-
        What is the path at which the original text of a message can be found?
      type: string
      default: /messages/{pushId}/original
      required: true
      immutable: false
    

    This defines a new string parameter that users will be prompted to set when they install your extension.

  2. Still in the extension.yaml file, go back to your makeuppercase declaration and change the resource field to the following:

    resource: projects/_/instances/${DATABASE_INSTANCE}/refs/${param:MESSAGE_PATH}
    

    The ${param:MESSAGE_PATH} token is a reference to the parameter you just defined. When your extension runs, this token will be replaced by whatever value the user configured for that parameter, with the result that the makeuppercase function will listen to the path the user specified. You can use this syntax to reference any user-defined parameter anywhere in extension.yaml (and in POSTINSTALL.md —more on that later).

  3. You can also access user-defined parameters from your functions code.

    In the function you wrote in the last section, you hard-coded the path to watch for changes. Change the trigger definition to reference the user-defined value instead:

    functions/index.js

    export const makeuppercase = database.ref(process.env.MESSAGE_PATH).onCreate
    

    Note that in Firebase Extensions, this change is purely for the sake of documentation: when a Cloud Function is deployed as part of an extension, it uses the trigger definition from the extension.yaml file and ignores the value specified in the function definition. Nevertheless, it's a good idea to document in your code where this value comes from.

  4. You might find it disappointing to make a code change that has no runtime effect, but the important lesson to take away is that you can access any user-defined parameter in your function code and use it as an ordinary value in the function's logic. As a nod to this capability, add the following log statement to demonstrate that you are indeed accessing the value that the user defined:

    functions/index.js

    export const makeuppercase = database.ref(process.env.MESSAGE_PATH).onCreate(
      async (snapshot, context) => {
        logger.log("Found new message at ", snapshot.ref);
    
        // Grab the current value of what was written to the Realtime Database.
        ...
    
  5. Normally, users are prompted to provide values for parameters when they install an extension. When you use the emulator for testing and development, however, you skip the installation process, so you instead provide values for user-defined parameters using an env file.

    Open functions/integration-tests/extensions/rtdb-uppercase-messages.env and replace the GREETING definition with the following:

    MESSAGE_PATH=/msgs/{pushId}/original
    

    Notice that the path above is different from the default path and from the path you defined previously; this is just to prove to yourself when you try your updated extension that your definition is taking effect.

  6. Now, restart the emulator and once again visit the database emulator UI.

    Edit the root node of the database, using the path you defined above:

    • Field: msgs
    • Type: json
    • Value: {"11": {"original": "recipe"}}

    When you save your database changes, the extension's makeuppercase function should trigger as it did before, but now it should also print the user-defined parameter to the console log.

7. Provide event hooks for user-defined logic

You've already seen, as an extension author, how a Firebase product can trigger your extension-provided logic: the creation of new records in Realtime Database triggers your makeuppercase function. Your extension can have an analogous relationship with the users who install your extension: your extension can trigger logic that the user defines.

An extension can provide synchronous hooks , asynchronous hooks , or both. Synchronous hooks give users a way to perform tasks that block the completion of one of the extension's functions. This can be useful, for example, to give users a way to perform custom preprocessing before an extension does its work.

In this guide, you'll add an asynchronous hook to your extension, which will enable users to define their own processing steps to be run after your extension writes the uppercase message to Realtime Database. Asynchronous hooks use Eventarc to trigger user-defined functions. Extensions declare the types of events they emit, and when users install the extension, they choose which event types they're interested in. If they choose at least one event, Firebase will provision an Eventarc channel for the extension as part of the installation process. Users can then deploy their own cloud functions that listen on that channel and trigger when the extension publishes new events.

Follow these steps to add an asynchronous hook:

  1. In the extension.yaml file, add the following section, which declares the one event type the extension emits:

    events:
      - type: test-publisher.rtdb-uppercase-messages.v1.complete
        description: >-
          Occurs when message uppercasing completes. The event subject will contain
          the RTDB URL of the uppercase message.
    

    Event types must be universally unique; to ensure uniqueness, always name your events using the following format: <publisher-id>.<extension-id>.<version>.<description> . (You don't have a publisher ID yet, so just use test-publisher for now.)

  2. At the end of the makeuppercase function, add some code that publishes an event of the type you just declared:

    functions/index.js

    // Import the Eventarc library:
    import { initializeApp } from "firebase-admin/app";
    import { getEventarc } from "firebase-admin/eventarc";
    
    const app = initializeApp();
    
    // In makeuppercase, after upperRef.set(uppercase), add:
    
    // Set eventChannel to a newly-initialized channel, or `undefined` if events
    // aren't enabled.
    const eventChannel =
      process.env.EVENTARC_CHANNEL &&
      getEventarc().channel(process.env.EVENTARC_CHANNEL, {
        allowedEventTypes: process.env.EXT_SELECTED_EVENTS,
      });
    
    // If events are enabled, publish a `complete` event to the configured
    // channel.
    eventChannel &&
      eventChannel.publish({
        type: "test-publisher.rtdb-uppercase-messages.v1.complete",
        subject: upperRef.toString(),
        data: {
          "original": original,
          "uppercase": uppercase,
        },
      });
    

    This example code takes advantage of the fact that the EVENTARC_CHANNEL environment variable is defined only when the user enabled at least one event type. if EVENTARC_CHANNEL is not defined, the code does not attempt to publish any events.

    You can attach extra information to an Eventarc event. In the example above, the event has a subject field that contains a reference to the newly-created value, and a data payload that contains the original and uppercase messages. User-defined functions that trigger off the event can make use of this information.

  3. Normally, the EVENTARC_CHANNEL and EXT_SELECTED_EVENTS environment variables are defined based on the options the user selected during installation. For testing with the emulator, manually define these variables in the rtdb-uppercase-messages.env file:

    EVENTARC_CHANNEL=locations/us-central1/channels/firebase
    EXT_SELECTED_EVENTS=test-publisher.rtdb-uppercase-messages.v1.complete
    

At this point, you have completed the steps needed to add an asynchronous event hook to your extension.

To try out this new feature that you have just implemented, in the next few steps, assume the role of a user who is installing the extension:

  1. From the functions/integration-tests directory, initialize a new Firebase project:

    firebase init functions

    When prompted, decline to set up a default project, select JavaScript as the Cloud Functions language, and install the required dependencies. This project represents a user's project, which has your extension installed.

  2. Edit integration-tests/functions/index.js and paste the following code:

    import { logger } from "firebase-functions/v1";
    import { onCustomEventPublished } from "firebase-functions/v2/eventarc";
    
    import { initializeApp } from "firebase-admin/app";
    import { getDatabase } from "firebase-admin/database";
    
    const app = initializeApp();
    
    export const extraemphasis = onCustomEventPublished(
      "test-publisher.rtdb-uppercase-messages.v1.complete",
      async (event) => {
        logger.info("Received makeuppercase completed event", event);
    
        const refUrl = event.subject;
        const ref = getDatabase().refFromURL(refUrl);
        const upper = (await ref.get()).val();
        return ref.set(`${upper}!!!`);
      }
    );
    

    This is an example of a post-processing function a user might write. In this case, the function listens for the extension to publish a complete event, and when triggered, adds three exclamation points to the newly-uppercased message.

  3. Restart the emulator. The emulator will load the extension's functions as well as the post-processing function the "user" defined.

  4. Visit the database emulator UI and edit the root node of the database, using the path you defined above:

    • Field: msgs
    • Type: json
    • Value: {"11": {"original": "recipe"}}

    When you save your database changes, the extension's makeuppercase function and the user's extraemphasis function should trigger in sequence, resulting in the upper field getting the value RECIPE!!! .

8. Add lifecycle event handlers

The extension you've written so far processes messages as they are created. But what if your users already have a database of messages when they install the extension? Firebase Extensions has a feature called lifecycle event hooks that you can use to trigger actions when your extension gets installed, updated, or reconfigured. In this section, you will use lifecycle event hooks to backfill a project's existing message database with uppercased messages when a user installs your extension.

Firebase Extensions uses Cloud Tasks to run your lifecycle event handlers. You define event handlers using Cloud Functions; whenever an instance of your extension reaches one of the supported lifecycle events, if you have defined a handler, it will add the handler to a Cloud Tasks queue. Cloud Tasks will then asynchronously execute the handler. While a lifecycle event handler is running, the Firebase console will report to the user that the extension instance has a processing task in progress. It's up to your handler function to report ongoing status and task completion back to the user.

To add a lifecycle event handler that backfills existing messages, do the following:

  1. Define a new Cloud Function that's triggered by task queue events:

    functions/index.js

    import { tasks } from "firebase-functions/v1";
    
    import { getDatabase } from "firebase-admin/database";
    import { getExtensions } from "firebase-admin/extensions";
    import { getFunctions } from "firebase-admin/functions";
    
    export const backfilldata = tasks.taskQueue().onDispatch(async () => {
      const batch = await getDatabase()
        .ref(process.env.MESSAGE_PATH)
        .parent.parent.orderByChild("upper")
        .limitToFirst(20)
        .get();
    
      const promises = [];
      for (const key in batch.val()) {
        const msg = batch.child(key);
        if (msg.hasChild("original") && !msg.hasChild("upper")) {
          const upper = msg.child("original").val().toUpperCase();
          promises.push(msg.child("upper").ref.set(upper));
        }
      }
      await Promise.all(promises);
    
      if (promises.length > 0) {
        const queue = getFunctions().taskQueue(
          "backfilldata",
          process.env.EXT_INSTANCE_ID
        );
        return queue.enqueue({});
      } else {
        return getExtensions()
          .runtime()
          .setProcessingState("PROCESSING_COMPLETE", "Backfill complete.");
      }
    });
    

    Notice that the function only processes a few records before adding itself back to the task queue. This is a commonly used strategy to deal with processing tasks that cannot complete within the timeout window of a Cloud Function. Since you can't predict how many messages a user might already have in their database when they install your extension, this strategy is a good fit.

  2. In the extension.yaml file, declare your backfill function as an extension resource that has the taskQueueTrigger property:

    resources:
      - name: makeuppercase
        ...
      - name: backfilldata
        type: firebaseextensions.v1beta.function
        description: >-
          Backfill existing messages with uppercase versions
        properties:
          runtime: "nodejs18"
          taskQueueTrigger: {}
    

    Then declare the function as the handler for the onInstall lifecycle event:

    lifecycleEvents:
      onInstall:
        function: backfilldata
        processingMessage: Uppercasing existing messages
    
  3. Although backfilling existing messages is nice to have, the extension could still function without it. In situations like this, you should make running the lifecycle event handlers optional.

    To do so, add a new parameter to extension.yaml :

    - param: DO_BACKFILL
      label: Backfill existing messages
      description: >-
        Generate uppercase versions of existing messages?
      type: select
      required: true
      options:
        - label: Yes
          value: true
        - label: No
          value: false
    

    Then at the beginning of the backfill function, check the value of the DO_BACKFILL parameter and exit early if it's not set:

    functions/index.js

    if (!process.env.DO_BACKFILL) {
      return getExtensions()
        .runtime()
        .setProcessingState("PROCESSING_COMPLETE", "Backfill skipped.");
    }
    

With the above changes, the extension will now convert existing messages to uppercase when it is installed.

Up to this point, you used the extension emulator to develop your extension and test ongoing changes. However, the extension emulator skips the installation process, so to test your onInstall event handler, you'll need to install the extension in a real project. That's just as well though, since with the addition of this automatic backfill feature, the tutorial extension is now code-complete!

9. Deploy into a real Firebase project

Although the extensions emulator is a great tool for rapidly iterating on an extension during development, at some point you'll want to try it in a real project.

To do so, first set up a new project with some services enabled:

  1. In the Firebase console , add a new project.
  2. Upgrade your project to the pay-as-you-go Blaze plan. Cloud Functions for Firebase requires your project to have a billing account, so you also need a billing account to install an extension.
  3. In your new project, enable Real-time Database .
  4. Since you want to test your extension's ability to backfill existing data on installation, import some sample data into your real-time database instance:
    1. Download some seed RTDB data .
    2. On the Real-time Database page of the Firebase console, click (more) > Import JSON and select the file you just downloaded.
  5. To enable the backfill function to use the orderByChild method, configure the database to index messages on the value of upper :

    {
      "rules": {
        ".read": false,
        ".write": false,
        "messages": {
          ".indexOn": "upper"
        }
      }
    }
    

Now install your extension from local source into the new project:

  1. Create a new directory for your Firebase project:

    mkdir ~/extensions-live-test && cd ~/extensions-live-test
    
  2. Initialize a Firebase project in the working directory:

    firebase init database

    When prompted, select the project you just created.

  3. Install the extension into your local Firebase project:

    firebase ext:install /path/to/rtdb-uppercase-messages

    Here you can see what the user experience is like when installing an extension using the Firebase CLI tool. Be sure to select "yes" when the configuration tool asks if you want to backfill your existing database.

    After you select configuration options, the Firebase CLI will save your configuration in the extensions directory and record the extension source location in the firebase.json file. Collectively, these two records are called the extensions manifest . Users can use the manifest to save their extensions configuration and deploy it to different projects.

  4. Deploy your extension configuration to your live project:

    firebase deploy --only extensions

If all goes well, the Firebase CLI should upload your extension to your project and install it. After installation completes, the backfill task will run and, in a few minutes, your database will be updated with uppercase messages. Add some new nodes to the messages database and make sure the extension is also working for new messages.

10. Write documentation

Before you share your extension with users, make sure you're providing enough documentation for them to be successful.

When you initialized the extension project, the Firebase CLI created stub versions of the minimum required documentation. Update these files to accurately reflect the extension you've built.

extension.yaml

You've already been updating this file as you've developed this extension, so you don't need to make any more updates right now.

However, don't overlook the importance of the documentation contained in this file. In addition to an extension's crucial identifying information—name, description, author, official repository location—the extension.yaml file contains user-facing documentation for every resource and user-configurable parameter. This information is surfaced to users in the Firebase console, Extensions Hub, and Firebase CLI.

PREINSTALL.md

In this file, provide information the user needs before they install your extension: briefly describe what the extension does, explain any prerequisites, and give the user information on the billing implications of installing the extension. If you have a website with additional information, this is also a good place to link it.

The text of this file is displayed to the user in Extensions Hub and by the firebase ext:info command.

Here is an example of a PREINSTALL file:

Use this extension to automatically convert strings to upper case when added to
a specified Realtime Database path.

This extension expects a database layout like the following example:

    "messages": {
      MESSAGE_ID: {
        "original": MESSAGE_TEXT
      },
      MESSAGE_ID: {
        "original": MESSAGE_TEXT
      },
    }

When you create new string records, this extension creates a new sibling record
with upper-cased text:

    MESSAGE_ID: {
      "original": MESSAGE_TEXT,
      "upper": UPPERCASE_MESSAGE_TEXT,
    }

#### Additional setup

Before installing this extension, make sure that you've
[set up Realtime Database](https://firebase.google.com/docs/database/quickstart)
in your Firebase project.

#### Billing

To install an extension, your project must be on the
[Blaze (pay as you go) plan](https://firebase.google.com/pricing).

- This extension uses other Firebase and Google Cloud Platform services, which
  have associated charges if you exceed the service's no-cost tier:
  - Realtime Database
  - Cloud Functions (Node.js 10+ runtime)
    [See FAQs](https://firebase.google.com/support/faq#extensions-pricing)
- If you enable events,
  [Eventarc fees apply](https://cloud.google.com/eventarc/pricing).

POSTINSTALL.md

This file contains information useful for users after they have successfully installed your extension: for example, follow-up setup steps, an example of the extension in action, and so on.

The contents of POSTINSTALL.md are displayed in the Firebase console after an extension is configured and installed. You can reference user parameters in this file and they will be replaced by the configured values.

Here is an example post-install file for the tutorial extension:

### See it in action

You can test out this extension right away!

1.  Go to your
    [Realtime Database dashboard](https://console.firebase.google.com/project/${param:PROJECT_ID}/database/${param:PROJECT_ID}/data) in the Firebase console.

1.  Add a message string to a path that matches the pattern `${param:MESSAGE_PATH}`.

1.  In a few seconds, you'll see a sibling node named `upper` that contains the
    message in upper case.

### Using the extension

We recommend adding data by pushing -- for example,
`firebase.database().ref().push()` -- because pushing assigns an automatically
generated ID to the node in the database. During retrieval, these nodes are
guaranteed to be ordered by the time they were added. Learn more about reading
and writing data for your platform (iOS, Android, or Web) in the
[Realtime Database documentation](https://firebase.google.com/docs/database/).

### Monitoring

As a best practice, you can
[monitor the activity](https://firebase.google.com/docs/extensions/manage-installed-extensions#monitor)
of your installed extension, including checks on its health, usage, and logs.

CHANGELOG.md

You should also document the changes you make between releases of an extension in the CHANGELOG.md file.

Since the example extension has never been published before, the change log has only one entry:

## Version 0.0.1

Initial release of the _Convert messages to upper case_ extension.

README.md

Most extensions also provide a readme file for the benefit of users visiting the extension's repository. you can write this file by hand or generate a read me using the command.

For the purpose of this guide, skip writing a readme file.

অতিরিক্ত ডকুমেন্টেশন

The documentation discussed above is the minimum set of documentation you should provide users. Many extensions require more detailed documentation for users to successfully use them. When this is the case, you should write additional documentation and host it somewhere you can point users to.

For the purpose of this guide, skip writing more extensive documentation.

11. Publish on Extensions Hub

Now that your extension is code complete and documented, you are ready to share it with the world on Extensions Hub. But since this is just a tutorial, don't actually do that. Go and start writing your own extension using what you've learned here and in the rest of the Firebase Extensions publisher documentation, and by examining the source of the official, Firebase-written, extensions.

When you're ready to publish your work on Extensions Hub here's how you will do it:

  1. If you are publishing your first extension, register as an extension publisher . When you register as an extensions publisher, you create a publisher ID that lets users quickly identify you as the author of your extensions.
  2. Host your extension's source code in a publicly verifiable location. When your code is available from a verifiable source, Firebase can publish your extension directly from this location. Doing so helps ensure that you're publishing the currently released version of your extension, and helps users by letting them examine the code they're installing into their projects.

    Currently, this means making your extension available in a public GitHub repository.

  3. Upload your extension to Extensions Hub using the firebase ext:dev:upload command.

  4. Go to your publisher dashboard in the Firebase console, find the extension you just uploaded, and click "Publish to Extensions Hub". This requests a review from our review staff, which can take a few days. If approved, the extension will be published to Extensions Hub. If rejected, you'll get a message explaining the reason; you can then address the reported issues and resubmit for review.

,

This page walks you through the steps required to build a simple Firebase Extension, which you can install in your projects or share with others. This simple example of a Firebase Extension will watch your Realtime Database for messages and convert them to upper case.

1. Set up your environment and initialize a project

Before you can start building an extension, you'll need to set up a build environment with the required tools.

  1. Install Node.js 16 or newer. One way to install Node is by using nvm (or nvm-windows ).

  2. Install or update to the latest version of the Firebase CLI . To install or update using npm , run this command:

    npm install -g firebase-tools

Now use the Firebase CLI to initialize a new extension project:

  1. Create a directory for your extension and cd into it:

    mkdir rtdb-uppercase-messages && cd rtdb-uppercase-messages
  2. Run the Firebase CLI's ext:dev:init command:

    firebase ext:dev:init

    When prompted, choose JavaScript as the language for functions (but note that you can also use TypeScript when you develop your own extension), and, when asked to install dependencies, answer "yes". (Accept the defaults for any other options.) This command will set up a skeleton codebase for a new extension, from which you can start developing your extension.

2. Try the example extension using the emulator

When the Firebase CLI initialized the new extensions directory, it created a simple example function and an integration-tests directory that contains the files necessary to run an extension using the Firebase emulator suite.

Try running the example extension in the emulator:

  1. Change to the integration-tests directory:

    cd functions/integration-tests
  2. Start the emulator with a demo project:

    firebase emulators:start --project=demo-test

    The emulator loads the extension into a predefined "dummy" project ( demo-test ). The extension so far consists of a single HTTP-triggered function, greetTheWorld , which returns a "hello world" message when accessed.

  3. With the emulator still running, try the extension's greetTheWorld function by visiting the URL it printed when you started it.

    Your browser displays the message "Hello World from greet-the-world".

  4. The source code for this function is in the extension's functions directory. Open the source in the editor or IDE of your choice:

    functions/index.js

    const functions = require("firebase-functions/v1");
    
    exports.greetTheWorld = functions.https.onRequest((req, res) => {
      // Here we reference a user-provided parameter
      // (its value is provided by the user during installation)
      const consumerProvidedGreeting = process.env.GREETING;
    
      // And here we reference an auto-populated parameter
      // (its value is provided by Firebase after installation)
      const instanceId = process.env.EXT_INSTANCE_ID;
    
      const greeting = `${consumerProvidedGreeting} World from ${instanceId}`;
    
      res.send(greeting);
    });
    
  5. While the emulator is running, it will automatically reload any changes you make to your Functions code. Try making a small change to the greetTheWorld function:

    functions/index.js

    const greeting = `${consumerProvidedGreeting} everyone, from ${instanceId}`;
    

    আপনার পরিবর্তন সংরক্ষণ করুন. The emulator will reload your code, and now, when you visit the function URL, you'll see the updated greeting.

3. Add basic information to extension.yaml

Now that you have a development environment set up and are running the extensions emulator, you can start writing your own extension.

As a modest first step, edit the predefined extension metadata to reflect the extension you want to write instead of greet-the-world . This metadata is stored in the extension.yaml file.

  1. Open extension.yaml in your editor, and replace the entire contents of the file with the following:

    name: rtdb-uppercase-messages
    version: 0.0.1
    specVersion: v1beta  # Firebase Extensions specification version; don't change
    
    # Friendly display name for your extension (~3-5 words)
    displayName: Convert messages to upper case
    
    # Brief description of the task your extension performs (~1 sentence)
    description: >-
      Converts messages in RTDB to upper case
    
    author:
      authorName: Your Name
      url: https://your-site.example.com
    
    license: Apache-2.0  # Required license
    
    # Public URL for the source code of your extension
    sourceUrl: https://github.com/your-name/your-repo
    

    Note the naming convention used in the name field: official Firebase extensions are named with a prefix indicating the primary Firebase product the extension operates on, followed by a description of what the extension does. You should use the same convention in your own extensions.

  2. Since you've changed the name of your extension, you should also update your emulator configuration with the new name:

    1. In functions/integration-tests/firebase.json , change greet-the-world to rtdb-uppercase-messages .
    2. Rename functions/integration-tests/extensions/greet-the-world.env to functions/integration-tests/extensions/rtdb-uppercase-messages.env .

There are still some remnants of the greet-the-world extension remaining in your extension code, but leave them for now. You'll update those in the next few sections.

4. Write a Cloud Function and declare it as an extension resource

Now you can get started writing some code. In this step, you will write a Cloud Function that performs the core task of your extension, which is to watch your Realtime Database for messages and convert them to upper case.

  1. Open the source for the extension's functions (in the extension's functions directory) in the editor or IDE of your choice. Replace its contents with the following:

    functions/index.js

    import { database, logger } from "firebase-functions/v1";
    
    const app = initializeApp();
    
    // Listens for new messages added to /messages/{pushId}/original and creates an
    // uppercase version of the message to /messages/{pushId}/uppercase
    // for all databases in 'us-central1'
    export const makeuppercase = database
      .ref("/messages/{pushId}/uppercase")
      .onCreate(async (snapshot, context) => {
        // Grab the current value of what was written to the Realtime Database.
        const original = snapshot.val();
    
        // Convert it to upper case.
        logger.log("Uppercasing", context.params.pushId, original);
        const uppercase = original.toUpperCase();
    
        // Setting an "uppercase" sibling in the Realtime Database.
        const upperRef = snapshot.ref.parent.child("upper");
        await upperRef.set(uppercase);
    });
    

    The old function, which you replaced, was an HTTP-triggered function, which ran when an HTTP endpoint was accessed. The new function is triggered by real-time database events: it watches for new items at a particular path and, when one is detected, it writes the uppercase version of the value back to the database.

    By the way, this new file uses ECMAScript module syntax ( import and export ) instead of CommonJS ( require ). To use ES modules in Node, specify "type": "module" in functions/package.json :

    {
      "name": "rtdb-uppercase-messages",
      "main": "index.js",
      "type": "module",
      
    }
    
  2. Every function in your extension must be declared in the extension.yaml file. The example extension declared greetTheWorld as the extension's only Cloud Function; now that you've replaced it with makeuppercase , you also need to update its declaration.

    Open extension.yaml and add a resources field:

    resources:
      - name: makeuppercase
        type: firebaseextensions.v1beta.function
        properties:
          eventTrigger:
            eventType: providers/google.firebase.database/eventTypes/ref.create
            # DATABASE_INSTANCE (project's default instance) is an auto-populated
            # parameter value. You can also specify an instance.
            resource: projects/_/instances/${DATABASE_INSTANCE}/refs/messages/{pushId}/original
          runtime: "nodejs18"
    
  3. Since your extension is now using Realtime Database as a trigger, you need to update your emulator configuration to run the RTDB emulator alongside the Cloud Functions emulator:

    1. If the emulator is still running, stop it by pressing Ctrl-C.

    2. From the functions/integration-tests directory, run the following command:

      firebase init emulators

      When asked, skip setting up a default project, then select the Functions and Database emulators. Accept the default ports and allow the setup tool to download any required files.

    3. Restart the emulator:

      firebase emulators:start --project=demo-test
  4. Try out your updated extension:

    1. Open the Database emulator UI using the link the emulator printed when you started it.

    2. Edit the root node of the database:

      • Field: messages
      • Type: json
      • Value: {"11": {"original": "recipe"}}

      If everything is set up correctly, when you save your database changes, the extension's makeuppercase function should trigger and add a child record to message 11 with the contents "upper": "RECIPE" . Take a look at the logs and the database tabs of the emulator UI to confirm the expected results.

    3. Try adding some more children to the messages node ( {"original":"any text"} ). Whenever you add a new record, the extension should add an uppercase field containing the uppercase contents of the original field.

You now have a complete, though simple, extension that operates on an RTDB instance. In the sections that follow, you will refine this extension with some additional features. Then, you'll get the extension ready to distribute to others, and finally, learn how to publish your extension on Extensions Hub.

5. Declare APIs and roles

Firebase grants each instance of an installed extension limited access to the project and its data using a per-instance service account. Each account has the minimum set of permissions needed to operate. For this reason, you must explicitly declare any IAM roles your extension requires; when users install your extension, Firebase creates a service account with these roles granted and uses it to run the extension.

You don't need to declare roles to trigger off a product's events, but you do need to declare a role to otherwise interact with it. Because the function you added in the last step writes to Realtime Database, you need to add the following declaration to extension.yaml :

roles:
  - role: firebasedatabase.admin
    reason: Allows the extension to write to RTDB.

Similarly, you declare the Google APIs that an extension uses in the apis field. When users install your extension, they will be asked if they want to automatically enable these APIs for their project. This is typically only necessary for non-Firebase Google APIs, and isn't needed for this guide.

6. Define user-configurable parameters

The function you created in the last two steps watched a specific RTDB location for incoming messages. Sometimes, watching a specific location really is what you want, such as when your extension operates on a database structure that you use exclusively for your extension. However, most of the time, you will want to make these values configurable by users who install your extension in their projects. This way, users can make use of your extension to work with their existing database setup.

Make the path that the extension watches for new messages user-configurable:

  1. In the extension.yaml file, add a params section:

    - param: MESSAGE_PATH
      label: Message path
      description: >-
        What is the path at which the original text of a message can be found?
      type: string
      default: /messages/{pushId}/original
      required: true
      immutable: false
    

    This defines a new string parameter that users will be prompted to set when they install your extension.

  2. Still in the extension.yaml file, go back to your makeuppercase declaration and change the resource field to the following:

    resource: projects/_/instances/${DATABASE_INSTANCE}/refs/${param:MESSAGE_PATH}
    

    The ${param:MESSAGE_PATH} token is a reference to the parameter you just defined. When your extension runs, this token will be replaced by whatever value the user configured for that parameter, with the result that the makeuppercase function will listen to the path the user specified. You can use this syntax to reference any user-defined parameter anywhere in extension.yaml (and in POSTINSTALL.md —more on that later).

  3. You can also access user-defined parameters from your functions code.

    In the function you wrote in the last section, you hard-coded the path to watch for changes. Change the trigger definition to reference the user-defined value instead:

    functions/index.js

    export const makeuppercase = database.ref(process.env.MESSAGE_PATH).onCreate
    

    Note that in Firebase Extensions, this change is purely for the sake of documentation: when a Cloud Function is deployed as part of an extension, it uses the trigger definition from the extension.yaml file and ignores the value specified in the function definition. Nevertheless, it's a good idea to document in your code where this value comes from.

  4. You might find it disappointing to make a code change that has no runtime effect, but the important lesson to take away is that you can access any user-defined parameter in your function code and use it as an ordinary value in the function's logic. As a nod to this capability, add the following log statement to demonstrate that you are indeed accessing the value that the user defined:

    functions/index.js

    export const makeuppercase = database.ref(process.env.MESSAGE_PATH).onCreate(
      async (snapshot, context) => {
        logger.log("Found new message at ", snapshot.ref);
    
        // Grab the current value of what was written to the Realtime Database.
        ...
    
  5. Normally, users are prompted to provide values for parameters when they install an extension. When you use the emulator for testing and development, however, you skip the installation process, so you instead provide values for user-defined parameters using an env file.

    Open functions/integration-tests/extensions/rtdb-uppercase-messages.env and replace the GREETING definition with the following:

    MESSAGE_PATH=/msgs/{pushId}/original
    

    Notice that the path above is different from the default path and from the path you defined previously; this is just to prove to yourself when you try your updated extension that your definition is taking effect.

  6. Now, restart the emulator and once again visit the database emulator UI.

    Edit the root node of the database, using the path you defined above:

    • Field: msgs
    • Type: json
    • Value: {"11": {"original": "recipe"}}

    When you save your database changes, the extension's makeuppercase function should trigger as it did before, but now it should also print the user-defined parameter to the console log.

7. Provide event hooks for user-defined logic

You've already seen, as an extension author, how a Firebase product can trigger your extension-provided logic: the creation of new records in Realtime Database triggers your makeuppercase function. Your extension can have an analogous relationship with the users who install your extension: your extension can trigger logic that the user defines.

An extension can provide synchronous hooks , asynchronous hooks , or both. Synchronous hooks give users a way to perform tasks that block the completion of one of the extension's functions. This can be useful, for example, to give users a way to perform custom preprocessing before an extension does its work.

In this guide, you'll add an asynchronous hook to your extension, which will enable users to define their own processing steps to be run after your extension writes the uppercase message to Realtime Database. Asynchronous hooks use Eventarc to trigger user-defined functions. Extensions declare the types of events they emit, and when users install the extension, they choose which event types they're interested in. If they choose at least one event, Firebase will provision an Eventarc channel for the extension as part of the installation process. Users can then deploy their own cloud functions that listen on that channel and trigger when the extension publishes new events.

Follow these steps to add an asynchronous hook:

  1. In the extension.yaml file, add the following section, which declares the one event type the extension emits:

    events:
      - type: test-publisher.rtdb-uppercase-messages.v1.complete
        description: >-
          Occurs when message uppercasing completes. The event subject will contain
          the RTDB URL of the uppercase message.
    

    Event types must be universally unique; to ensure uniqueness, always name your events using the following format: <publisher-id>.<extension-id>.<version>.<description> . (You don't have a publisher ID yet, so just use test-publisher for now.)

  2. At the end of the makeuppercase function, add some code that publishes an event of the type you just declared:

    functions/index.js

    // Import the Eventarc library:
    import { initializeApp } from "firebase-admin/app";
    import { getEventarc } from "firebase-admin/eventarc";
    
    const app = initializeApp();
    
    // In makeuppercase, after upperRef.set(uppercase), add:
    
    // Set eventChannel to a newly-initialized channel, or `undefined` if events
    // aren't enabled.
    const eventChannel =
      process.env.EVENTARC_CHANNEL &&
      getEventarc().channel(process.env.EVENTARC_CHANNEL, {
        allowedEventTypes: process.env.EXT_SELECTED_EVENTS,
      });
    
    // If events are enabled, publish a `complete` event to the configured
    // channel.
    eventChannel &&
      eventChannel.publish({
        type: "test-publisher.rtdb-uppercase-messages.v1.complete",
        subject: upperRef.toString(),
        data: {
          "original": original,
          "uppercase": uppercase,
        },
      });
    

    This example code takes advantage of the fact that the EVENTARC_CHANNEL environment variable is defined only when the user enabled at least one event type. if EVENTARC_CHANNEL is not defined, the code does not attempt to publish any events.

    You can attach extra information to an Eventarc event. In the example above, the event has a subject field that contains a reference to the newly-created value, and a data payload that contains the original and uppercase messages. User-defined functions that trigger off the event can make use of this information.

  3. Normally, the EVENTARC_CHANNEL and EXT_SELECTED_EVENTS environment variables are defined based on the options the user selected during installation. For testing with the emulator, manually define these variables in the rtdb-uppercase-messages.env file:

    EVENTARC_CHANNEL=locations/us-central1/channels/firebase
    EXT_SELECTED_EVENTS=test-publisher.rtdb-uppercase-messages.v1.complete
    

At this point, you have completed the steps needed to add an asynchronous event hook to your extension.

To try out this new feature that you have just implemented, in the next few steps, assume the role of a user who is installing the extension:

  1. From the functions/integration-tests directory, initialize a new Firebase project:

    firebase init functions

    When prompted, decline to set up a default project, select JavaScript as the Cloud Functions language, and install the required dependencies. This project represents a user's project, which has your extension installed.

  2. Edit integration-tests/functions/index.js and paste the following code:

    import { logger } from "firebase-functions/v1";
    import { onCustomEventPublished } from "firebase-functions/v2/eventarc";
    
    import { initializeApp } from "firebase-admin/app";
    import { getDatabase } from "firebase-admin/database";
    
    const app = initializeApp();
    
    export const extraemphasis = onCustomEventPublished(
      "test-publisher.rtdb-uppercase-messages.v1.complete",
      async (event) => {
        logger.info("Received makeuppercase completed event", event);
    
        const refUrl = event.subject;
        const ref = getDatabase().refFromURL(refUrl);
        const upper = (await ref.get()).val();
        return ref.set(`${upper}!!!`);
      }
    );
    

    This is an example of a post-processing function a user might write. In this case, the function listens for the extension to publish a complete event, and when triggered, adds three exclamation points to the newly-uppercased message.

  3. Restart the emulator. The emulator will load the extension's functions as well as the post-processing function the "user" defined.

  4. Visit the database emulator UI and edit the root node of the database, using the path you defined above:

    • Field: msgs
    • Type: json
    • Value: {"11": {"original": "recipe"}}

    When you save your database changes, the extension's makeuppercase function and the user's extraemphasis function should trigger in sequence, resulting in the upper field getting the value RECIPE!!! .

8. Add lifecycle event handlers

The extension you've written so far processes messages as they are created. But what if your users already have a database of messages when they install the extension? Firebase Extensions has a feature called lifecycle event hooks that you can use to trigger actions when your extension gets installed, updated, or reconfigured. In this section, you will use lifecycle event hooks to backfill a project's existing message database with uppercased messages when a user installs your extension.

Firebase Extensions uses Cloud Tasks to run your lifecycle event handlers. You define event handlers using Cloud Functions; whenever an instance of your extension reaches one of the supported lifecycle events, if you have defined a handler, it will add the handler to a Cloud Tasks queue. Cloud Tasks will then asynchronously execute the handler. While a lifecycle event handler is running, the Firebase console will report to the user that the extension instance has a processing task in progress. It's up to your handler function to report ongoing status and task completion back to the user.

To add a lifecycle event handler that backfills existing messages, do the following:

  1. Define a new Cloud Function that's triggered by task queue events:

    functions/index.js

    import { tasks } from "firebase-functions/v1";
    
    import { getDatabase } from "firebase-admin/database";
    import { getExtensions } from "firebase-admin/extensions";
    import { getFunctions } from "firebase-admin/functions";
    
    export const backfilldata = tasks.taskQueue().onDispatch(async () => {
      const batch = await getDatabase()
        .ref(process.env.MESSAGE_PATH)
        .parent.parent.orderByChild("upper")
        .limitToFirst(20)
        .get();
    
      const promises = [];
      for (const key in batch.val()) {
        const msg = batch.child(key);
        if (msg.hasChild("original") && !msg.hasChild("upper")) {
          const upper = msg.child("original").val().toUpperCase();
          promises.push(msg.child("upper").ref.set(upper));
        }
      }
      await Promise.all(promises);
    
      if (promises.length > 0) {
        const queue = getFunctions().taskQueue(
          "backfilldata",
          process.env.EXT_INSTANCE_ID
        );
        return queue.enqueue({});
      } else {
        return getExtensions()
          .runtime()
          .setProcessingState("PROCESSING_COMPLETE", "Backfill complete.");
      }
    });
    

    Notice that the function only processes a few records before adding itself back to the task queue. This is a commonly used strategy to deal with processing tasks that cannot complete within the timeout window of a Cloud Function. Since you can't predict how many messages a user might already have in their database when they install your extension, this strategy is a good fit.

  2. In the extension.yaml file, declare your backfill function as an extension resource that has the taskQueueTrigger property:

    resources:
      - name: makeuppercase
        ...
      - name: backfilldata
        type: firebaseextensions.v1beta.function
        description: >-
          Backfill existing messages with uppercase versions
        properties:
          runtime: "nodejs18"
          taskQueueTrigger: {}
    

    Then declare the function as the handler for the onInstall lifecycle event:

    lifecycleEvents:
      onInstall:
        function: backfilldata
        processingMessage: Uppercasing existing messages
    
  3. Although backfilling existing messages is nice to have, the extension could still function without it. In situations like this, you should make running the lifecycle event handlers optional.

    To do so, add a new parameter to extension.yaml :

    - param: DO_BACKFILL
      label: Backfill existing messages
      description: >-
        Generate uppercase versions of existing messages?
      type: select
      required: true
      options:
        - label: Yes
          value: true
        - label: No
          value: false
    

    Then at the beginning of the backfill function, check the value of the DO_BACKFILL parameter and exit early if it's not set:

    functions/index.js

    if (!process.env.DO_BACKFILL) {
      return getExtensions()
        .runtime()
        .setProcessingState("PROCESSING_COMPLETE", "Backfill skipped.");
    }
    

With the above changes, the extension will now convert existing messages to uppercase when it is installed.

Up to this point, you used the extension emulator to develop your extension and test ongoing changes. However, the extension emulator skips the installation process, so to test your onInstall event handler, you'll need to install the extension in a real project. That's just as well though, since with the addition of this automatic backfill feature, the tutorial extension is now code-complete!

9. Deploy into a real Firebase project

Although the extensions emulator is a great tool for rapidly iterating on an extension during development, at some point you'll want to try it in a real project.

To do so, first set up a new project with some services enabled:

  1. In the Firebase console , add a new project.
  2. Upgrade your project to the pay-as-you-go Blaze plan. Cloud Functions for Firebase requires your project to have a billing account, so you also need a billing account to install an extension.
  3. In your new project, enable Real-time Database .
  4. Since you want to test your extension's ability to backfill existing data on installation, import some sample data into your real-time database instance:
    1. Download some seed RTDB data .
    2. On the Real-time Database page of the Firebase console, click (more) > Import JSON and select the file you just downloaded.
  5. To enable the backfill function to use the orderByChild method, configure the database to index messages on the value of upper :

    {
      "rules": {
        ".read": false,
        ".write": false,
        "messages": {
          ".indexOn": "upper"
        }
      }
    }
    

Now install your extension from local source into the new project:

  1. Create a new directory for your Firebase project:

    mkdir ~/extensions-live-test && cd ~/extensions-live-test
    
  2. Initialize a Firebase project in the working directory:

    firebase init database

    When prompted, select the project you just created.

  3. Install the extension into your local Firebase project:

    firebase ext:install /path/to/rtdb-uppercase-messages

    Here you can see what the user experience is like when installing an extension using the Firebase CLI tool. Be sure to select "yes" when the configuration tool asks if you want to backfill your existing database.

    After you select configuration options, the Firebase CLI will save your configuration in the extensions directory and record the extension source location in the firebase.json file. Collectively, these two records are called the extensions manifest . Users can use the manifest to save their extensions configuration and deploy it to different projects.

  4. Deploy your extension configuration to your live project:

    firebase deploy --only extensions

If all goes well, the Firebase CLI should upload your extension to your project and install it. After installation completes, the backfill task will run and, in a few minutes, your database will be updated with uppercase messages. Add some new nodes to the messages database and make sure the extension is also working for new messages.

10. Write documentation

Before you share your extension with users, make sure you're providing enough documentation for them to be successful.

When you initialized the extension project, the Firebase CLI created stub versions of the minimum required documentation. Update these files to accurately reflect the extension you've built.

extension.yaml

You've already been updating this file as you've developed this extension, so you don't need to make any more updates right now.

However, don't overlook the importance of the documentation contained in this file. In addition to an extension's crucial identifying information—name, description, author, official repository location—the extension.yaml file contains user-facing documentation for every resource and user-configurable parameter. This information is surfaced to users in the Firebase console, Extensions Hub, and Firebase CLI.

PREINSTALL.md

In this file, provide information the user needs before they install your extension: briefly describe what the extension does, explain any prerequisites, and give the user information on the billing implications of installing the extension. If you have a website with additional information, this is also a good place to link it.

The text of this file is displayed to the user in Extensions Hub and by the firebase ext:info command.

Here is an example of a PREINSTALL file:

Use this extension to automatically convert strings to upper case when added to
a specified Realtime Database path.

This extension expects a database layout like the following example:

    "messages": {
      MESSAGE_ID: {
        "original": MESSAGE_TEXT
      },
      MESSAGE_ID: {
        "original": MESSAGE_TEXT
      },
    }

When you create new string records, this extension creates a new sibling record
with upper-cased text:

    MESSAGE_ID: {
      "original": MESSAGE_TEXT,
      "upper": UPPERCASE_MESSAGE_TEXT,
    }

#### Additional setup

Before installing this extension, make sure that you've
[set up Realtime Database](https://firebase.google.com/docs/database/quickstart)
in your Firebase project.

#### Billing

To install an extension, your project must be on the
[Blaze (pay as you go) plan](https://firebase.google.com/pricing).

- This extension uses other Firebase and Google Cloud Platform services, which
  have associated charges if you exceed the service's no-cost tier:
  - Realtime Database
  - Cloud Functions (Node.js 10+ runtime)
    [See FAQs](https://firebase.google.com/support/faq#extensions-pricing)
- If you enable events,
  [Eventarc fees apply](https://cloud.google.com/eventarc/pricing).

POSTINSTALL.md

This file contains information useful for users after they have successfully installed your extension: for example, follow-up setup steps, an example of the extension in action, and so on.

The contents of POSTINSTALL.md are displayed in the Firebase console after an extension is configured and installed. You can reference user parameters in this file and they will be replaced by the configured values.

Here is an example post-install file for the tutorial extension:

### See it in action

You can test out this extension right away!

1.  Go to your
    [Realtime Database dashboard](https://console.firebase.google.com/project/${param:PROJECT_ID}/database/${param:PROJECT_ID}/data) in the Firebase console.

1.  Add a message string to a path that matches the pattern `${param:MESSAGE_PATH}`.

1.  In a few seconds, you'll see a sibling node named `upper` that contains the
    message in upper case.

### Using the extension

We recommend adding data by pushing -- for example,
`firebase.database().ref().push()` -- because pushing assigns an automatically
generated ID to the node in the database. During retrieval, these nodes are
guaranteed to be ordered by the time they were added. Learn more about reading
and writing data for your platform (iOS, Android, or Web) in the
[Realtime Database documentation](https://firebase.google.com/docs/database/).

### Monitoring

As a best practice, you can
[monitor the activity](https://firebase.google.com/docs/extensions/manage-installed-extensions#monitor)
of your installed extension, including checks on its health, usage, and logs.

CHANGELOG.md

You should also document the changes you make between releases of an extension in the CHANGELOG.md file.

Since the example extension has never been published before, the change log has only one entry:

## Version 0.0.1

Initial release of the _Convert messages to upper case_ extension.

README.md

Most extensions also provide a readme file for the benefit of users visiting the extension's repository. you can write this file by hand or generate a read me using the command.

For the purpose of this guide, skip writing a readme file.

অতিরিক্ত ডকুমেন্টেশন

The documentation discussed above is the minimum set of documentation you should provide users. Many extensions require more detailed documentation for users to successfully use them. When this is the case, you should write additional documentation and host it somewhere you can point users to.

For the purpose of this guide, skip writing more extensive documentation.

11. Publish on Extensions Hub

Now that your extension is code complete and documented, you are ready to share it with the world on Extensions Hub. But since this is just a tutorial, don't actually do that. Go and start writing your own extension using what you've learned here and in the rest of the Firebase Extensions publisher documentation, and by examining the source of the official, Firebase-written, extensions.

When you're ready to publish your work on Extensions Hub here's how you will do it:

  1. If you are publishing your first extension, register as an extension publisher . When you register as an extensions publisher, you create a publisher ID that lets users quickly identify you as the author of your extensions.
  2. Host your extension's source code in a publicly verifiable location. When your code is available from a verifiable source, Firebase can publish your extension directly from this location. Doing so helps ensure that you're publishing the currently released version of your extension, and helps users by letting them examine the code they're installing into their projects.

    Currently, this means making your extension available in a public GitHub repository.

  3. Upload your extension to Extensions Hub using the firebase ext:dev:upload command.

  4. Go to your publisher dashboard in the Firebase console, find the extension you just uploaded, and click "Publish to Extensions Hub". This requests a review from our review staff, which can take a few days. If approved, the extension will be published to Extensions Hub. If rejected, you'll get a message explaining the reason; you can then address the reported issues and resubmit for review.