Menambahkan hook pengguna ke ekstensi
Tetap teratur dengan koleksi
Simpan dan kategorikan konten berdasarkan preferensi Anda.
Anda dapat memberi pengguna yang menginstal ekstensi Anda kemampuan untuk memasukkan logika kustom mereka sendiri ke dalam eksekusi ekstensi Anda. Ada dua cara untuk
melakukannya:
Peristiwa Eventarc: untuk memberi pengguna cara bereaksi secara asinkron terhadap peristiwa, Anda dapat memublikasikan ke Eventarc. Pengguna dapat men-deploy fungsi pengendali peristiwa yang, misalnya, mengirim notifikasi setelah tugas yang berjalan lama selesai, atau mereka dapat menentukan fungsi pascapemrosesannya sendiri.
Hook sinkron: untuk memberi pengguna cara menambahkan logika pemblokiran ke ekstensi, Anda dapat menambahkan hook sinkron pada titik-titik yang telah ditentukan dalam pengoperasian ekstensi. Pada tahap ini, Anda akan menjalankan fungsi penyedia pengguna dan melanjutkan hanya setelah selesai. Tugas pra-pemrosesan sering kali termasuk dalam kategori ini.
Ekstensi dapat menggunakan salah satu atau kedua metode tersebut.
Peristiwa Eventarc
Untuk memublikasikan peristiwa dari ekstensi:
Deklarasikan jenis peristiwa yang akan Anda publikasikan dalam file extension.yaml
:
events:
- type: publisher-id.extension-name.version.event-name
description: event-description
- type: publisher-id.extension-name.version.another-event-name
description: another-event-description
ID type
terdiri dari beberapa kolom yang dipisahkan titik. Kolom
ID penayang, nama ekstensi, dan nama peristiwa
diperlukan. Sebaiknya gunakan kolom versi. Pilih nama peristiwa yang unik dan deskriptif
untuk setiap jenis peristiwa yang Anda publikasikan.
Misalnya, ekstensi storage-resize-images
mendeklarasikan jenis peristiwa tunggal:
events:
- type: firebase.extensions.storage-resize-images.v1.complete
description: |
Occurs when image resizing completes. The event will contain further
details about specific formats and sizes.
Pengguna akan dapat memilih untuk berlangganan peristiwa saat
menginstal ekstensi tersebut.
Dalam fungsi ekstensi Anda, impor Eventarc API dari Admin SDK
dan lakukan inisialisasi saluran peristiwa menggunakan setelan penginstalan pengguna.
Setelan ini diekspos menggunakan variabel lingkungan berikut:
EVENTARC_CHANNEL
: nama saluran Eventarc yang sepenuhnya memenuhi syarat tempat pengguna memilih untuk memublikasikan peristiwa.
EXT_SELECTED_EVENTS
: daftar yang dipisahkan koma dari jenis-jenis peristiwa yang dipilih pengguna untuk dipublikasikan. Saat Anda menginisialisasi saluran dengan nilai ini, Admin SDK otomatis memfilter peristiwa yang tidak dipilih pengguna.
EVENTARC_CLOUD_EVENT_SOURCE
: ID sumber Peristiwa Cloud. Admin SDK otomatis meneruskan nilai ini di kolom source
peristiwa-peristiwa yang dipublikasikan. Biasanya, Anda tidak perlu menggunakan variabel ini secara eksplisit.
Jika peristiwa tidak diaktifkan saat penginstalan, variabel ini tidak akan ditentukan. Anda dapat menggunakan fakta ini untuk menginisialisasi saluran peristiwa hanya saat peristiwa diaktifkan:
import * as admin from "firebase-admin";
import {getEventarc} from 'firebase-admin/eventarc';
admin.initializeApp();
// 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,
});
Publikasikan peristiwa ke saluran pada titik-titik dalam ekstensi yang ingin Anda ekspos kepada pengguna. Contoh:
// If events are enabled, publish a `complete` event to the configured
// channel.
eventChannel && eventChannel.publish({
type: 'firebase.extensions.storage-resize-images.v1.complete',
subject: filename, // the name of the original file
data: {
// ...
}
});
Dokumentasikan peristiwa yang Anda publikasikan, dalam file PREINSTALL atau POSTINSTALL.
Untuk setiap peristiwa, dokumentasikan hal berikut:
- Tujuan yang dimaksudkan
- Titik di logika ekstensi yang dijalankan
- Data output yang dicakup
- Kondisi untuk eksekusinya
Selain itu, peringatkan pengguna untuk tidak melakukan tindakan apa pun dalam pengendali peristiwa yang mungkin memicu ekstensi yang sama, yang akan menghasilkan loop tak terbatas.
Saat Anda memublikasikan peristiwa dari ekstensi, pengguna dapat men-deploy pengendali peristiwa untuk merespons dengan logika kustom.
Misalnya, contoh berikut menghapus gambar asli setelah ukurannya diubah. Perlu diperhatikan bahwa pengendali contoh ini menggunakan properti subject
peristiwa, yang dalam hal ini adalah nama file asli dari gambar.
exports.onimageresized = onCustomEventPublished(
"firebase.extensions.storage-resize-images.v1.complete",
(event) => {
logger.info("Received image resize completed event", event);
// For example, delete the original.
return admin.storage()
.bucket("my-project.firebasestorage.app")
.file(event.subject)
.delete();
});
Lihat Pemicu peristiwa kustom untuk mengetahui informasi selengkapnya.
Contoh
Ekstensi Resize Images resmi menyediakan hook asinkron dengan memublikasikan ke Eventarc setelah mengubah ukuran gambar.
Hook sinkron
Jika Anda ingin memberi hook kepada pengguna yang harus berhasil diselesaikan agar salah satu fungsi ekstensi Anda dapat beroperasi, gunakan hook sinkron.
Hook sinkron memanggil Cloud Function callable HTTPS yang ditentukan pengguna dan menunggu penyelesaian (mungkin dengan nilai yang ditampilkan) sebelum melanjutkan. Error dalam fungsi yang diberikan pengguna menghasilkan error dalam fungsi ekstensi.
Untuk mengekspos hook sinkron:
Tambahkan parameter ke ekstensi Anda yang memungkinkan pengguna dapat mengonfigurasi ekstensi dengan URL ke Cloud Function kustom mereka. Contoh:
- param: PREPROCESSING_FUNCTION
label: Pre-processing function URL
description: >
An HTTPS callable function that will be called to transform the input data
before it is processed by this function.
type: string
example: https://us-west1-my-project-id.cloudfunctions.net/preprocessData
required: false
Pada titik di ekstensi tempat Anda ingin mengekspos hook, panggil fungsi menggunakan URL-nya. Contoh:
const functions = require('firebase-functions/v1');
const fetch = require('node-fetch');
const preprocessFunctionURL = process.env.PREPROCESSING_FUNCTION;
exports.yourFunctionName = functions.firestore.document("collection/{doc_id}")
.onWrite((change, context) => {
// PREPROCESSING_FUNCTION hook begins here.
// If a preprocessing function is defined, call it before continuing.
if (preprocessFunctionURL) {
try {
await fetch(preprocessFunctionURL); // Could also be a POST request if you want to send data.
} catch (e) {
// Preprocessing failure causes the function to fail.
functions.logger.error("Preprocessor error:", e);
return;
}
}
// End of PREPROCESSING_FUNCTION hook.
// Main function logic follows.
// ...
});
Dokumentasikan hook yang Anda sediakan dalam file PREINSTALL atau POSTINSTALL.
Untuk setiap hook, dokumentasikan hal berikut:
- Tujuan yang dimaksudkan
- Titik di logika ekstensi yang dijalankan
- Input dan output yang diharapkan
- Kondisi (atau opsi) untuk eksekusinya
Selain itu, peringatkan pengguna untuk tidak melakukan tindakan apa pun dalam fungsi hook yang mungkin memicu ekstensi yang sama, yang akan menghasilkan loop tak terbatas.
Contoh
Ekstensi Algolia Search menyediakan hook sinkron untuk memanggil fungsi transformasi yang disediakan pengguna sebelum menulis ke Algolia.
Kecuali dinyatakan lain, konten di halaman ini dilisensikan berdasarkan Lisensi Creative Commons Attribution 4.0, sedangkan contoh kode dilisensikan berdasarkan Lisensi Apache 2.0. Untuk mengetahui informasi selengkapnya, lihat Kebijakan Situs Google Developers. Java adalah merek dagang terdaftar dari Oracle dan/atau afiliasinya.
Terakhir diperbarui pada 2025-08-14 UTC.
[null,null,["Terakhir diperbarui pada 2025-08-14 UTC."],[],[],null,["\u003cbr /\u003e\n\nYou can provide users who install your extension the ability to insert their own\ncustom logic into the execution of your extension. There are two ways to\naccomplish this:\n\n- **Eventarc events**: to give users a way to asynchronously react to\n events, you can publish to Eventarc. Users can deploy event handler\n functions that, for example, send notifications after long-running\n tasks complete, or they can define their own post-processing functions.\n\n- **Synchronous hooks**: to give users a way to add blocking logic to your\n extension, you can add synchronous hooks at predefined points in the\n extension's operation. At these points, you run a user-provider function\n and proceed only after it completes. Pre-processing tasks often fall under\n this category.\n\nAn extension can use either or both methods.\n\nEventarc events\n\nTo publish events from an extension:\n\n1. Declare the event types you will publish in the `extension.yaml` file:\n\n events:\n - type: publisher-id.extension-name.version.event-name\n description: event-description\n - type: publisher-id.extension-name.version.another-event-name\n description: another-event-description\n\n The `type` identifier is made of several dot-delimited fields. The\n [publisher ID](/docs/extensions/publishers/register), extension name, and event name fields are\n required. The version field is recommended. Choose a unique and descriptive\n event name for each event type you publish.\n\n For example, the [`storage-resize-images` extension](https://github.com/firebase/extensions/blob/next/storage-resize-images/extension.yaml)\n declares a single event type: \n\n events:\n - type: firebase.extensions.storage-resize-images.v1.complete\n description: |\n Occurs when image resizing completes. The event will contain further\n details about specific formats and sizes.\n\n Users will be able to choose which events to subscribe to when they\n install the extension.\n2. In your extension functions, import the Eventarc API from the Admin SDK\n and initialize an event channel using the user's installation settings.\n These settings are exposed using the following environment variables:\n\n - `EVENTARC_CHANNEL`: the fully-qualified name of the Eventarc channel to which the user chose to publish events.\n - `EXT_SELECTED_EVENTS`: a comma-separated list of event types the user chose to publish. When you initialize a channel with this value, the Admin SDK automatically filters out events user did not select.\n - `EVENTARC_CLOUD_EVENT_SOURCE`: the Cloud Event source identifier. The Admin SDK automatically passes this value in the `source` field of published events. You typically don't need to explicitly use this variable.\n\n If events weren't enabled at installation, these variables will be\n undefined. You can use this fact to initialize an event channel only when\n events are enabled: \n\n import * as admin from \"firebase-admin\";\n import {getEventarc} from 'firebase-admin/eventarc';\n\n admin.initializeApp();\n\n // Set eventChannel to a newly-initialized channel, or `undefined` if events\n // aren't enabled.\n const eventChannel =\n process.env.EVENTARC_CHANNEL &&\n getEventarc().channel(process.env.EVENTARC_CHANNEL, {\n allowedEventTypes: process.env.EXT_SELECTED_EVENTS,\n });\n\n3. Publish events to the channel at the points in your extension you want to\n expose to users. For example:\n\n // If events are enabled, publish a `complete` event to the configured\n // channel.\n eventChannel && eventChannel.publish({\n type: 'firebase.extensions.storage-resize-images.v1.complete',\n subject: filename, // the name of the original file\n data: {\n // ...\n }\n });\n\n4. Document the events you publish, in either the PREINSTALL or POSTINSTALL\n file.\n\n For each event, document the following:\n - Its intended purpose\n - The point in your extension's logic it runs\n - The output data it includes\n - The conditions for its execution\n\n Additionally, warn users not to perform any actions in their event\n handlers that might trigger the same extension, resulting in an infinite\n loop.\n\nWhen you publish events from an extension, users can deploy event handlers\nto respond with custom logic.\n\nFor example, the following example deletes the original image after it has been\nresized. Note that this example handler makes use of the `subject` property of\nthe event, which in this case is the image's original filename. \n\n exports.onimageresized = onCustomEventPublished(\n \"firebase.extensions.storage-resize-images.v1.complete\",\n (event) =\u003e {\n logger.info(\"Received image resize completed event\", event);\n // For example, delete the original.\n return admin.storage()\n .bucket(\"my-project.firebasestorage.app\")\n .file(event.subject)\n .delete();\n });\n\nSee [Custom event triggers](/docs/functions/custom-events#handle-events) for more\ninformation.\n\nExample\n\nThe official [Resize Images extension](https://github.com/firebase/extensions/tree/next/storage-resize-images)\nprovides an asynchronous hook by [publishing to Eventarc](https://github.com/firebase/extensions/blob/c29781c7e67c004e2491e4ce3c43b25b05bd3de6/storage-resize-images/functions/src/index.ts#L109-L117)\nafter resizing an image.\n\nSynchronous hooks\n\nWhen you want to provide users with a hook that must complete successfully\nfor one of your extension functions to operate, use *synchronous hooks*.\n\nA synchronous hook calls a user-defined [HTTPS callable Cloud\nFunction](/docs/functions/http-events) and awaits completion (possibly with a\nreturned value) before continuing. An error in the user-provided function\nresults in an error in the extension function.\n\nTo expose a synchronous hook:\n\n1. Add a parameter to your extension that allows users to configure the\n extension with the URL to their custom Cloud Function. For example:\n\n - param: PREPROCESSING_FUNCTION\n label: Pre-processing function URL\n description: \u003e\n An HTTPS callable function that will be called to transform the input data\n before it is processed by this function.\n type: string\n example: https://us-west1-my-project-id.cloudfunctions.net/preprocessData\n required: false\n\n2. At the point in your extension where you want to expose the hook, call the\n function using its URL. For example:\n\n const functions = require('firebase-functions/v1');\n const fetch = require('node-fetch');\n\n const preprocessFunctionURL = process.env.PREPROCESSING_FUNCTION;\n\n exports.yourFunctionName = functions.firestore.document(\"collection/{doc_id}\")\n .onWrite((change, context) =\u003e {\n // PREPROCESSING_FUNCTION hook begins here.\n // If a preprocessing function is defined, call it before continuing.\n if (preprocessFunctionURL) {\n try {\n await fetch(preprocessFunctionURL); // Could also be a POST request if you want to send data.\n } catch (e) {\n // Preprocessing failure causes the function to fail.\n functions.logger.error(\"Preprocessor error:\", e);\n return;\n }\n }\n // End of PREPROCESSING_FUNCTION hook.\n\n // Main function logic follows.\n // ...\n });\n\n3. Document any hooks you make available in either the PREINSTALL or\n POSTINSTALL file.\n\n For each hook, document the following:\n - Its intended purpose\n - The point in your extension's logic it runs\n - Its expected inputs and outputs\n - The conditions (or options) for its execution\n\n Additionally, warn users not to perform any actions in the hook\n function that might trigger the same extension, resulting in an infinite\n loop.\n\nExample\n\nThe [Algolia Search extension](https://github.com/algolia/firestore-algolia-search/)\nprovides a synchronous hook to [call a user-supplied transform function](https://github.com/algolia/firestore-algolia-search/blob/34592d513eac22691d76917874a6466032976f67/functions/src/transform.ts)\nprior to writing to Algolia."]]