Переназначьте код Cloud Functions как расширение Firebase.

1. Прежде чем начать

Расширение Firebase выполняет определенную задачу или набор задач в ответ на HTTP-запросы или на события, вызванные другими продуктами Firebase и Google, такими как Firebase Cloud Messaging, Cloud Firestore или Pub/Sub.

Что ты построишь

В этой лаборатории кода вы создадите расширение Firebase для геохеширования . После развертывания ваше расширение преобразует координаты X и Y в геохеши в ответ на события Firestore или посредством вызовов вызываемых функций. Это можно использовать в качестве альтернативы внедрению библиотеки geofire на всех ваших целевых платформах для хранения данных, что сэкономит ваше время.

Расширение геохеша, отображаемое в консоли Firebase

Что вы узнаете

  • Как взять существующий код Cloud Functions и превратить его в распространяемое расширение Firebase
  • Как настроить файл extension.yaml
  • Как хранить конфиденциальные строки (ключи API) в расширении
  • Как позволить разработчикам расширения настроить его под свои нужды
  • Как протестировать и развернуть расширение

Что вам понадобится

  • Firebase CLI (установка и вход в систему)
  • Учетная запись Google, например учетная запись Gmail
  • Node.js и npm
  • Ваша любимая среда разработки

2. Настройте

Получить код

Все, что вам нужно для этого расширения, находится в репозитории GitHub. Для начала возьмите код и откройте его в любимой среде разработки.

  1. Распакуйте загруженный zip-файл.
  2. Чтобы установить необходимые зависимости, откройте терминал в каталоге functions и выполните команду npm install .

Настройте Firebase

Эта лаборатория кода настоятельно рекомендует использовать эмуляторы Firebase. Если вы хотите опробовать разработку расширений на реальном проекте Firebase, см. раздел Создание проекта Firebase . В этой лаборатории кода используются облачные функции, поэтому, если вы используете настоящий проект Firebase вместо эмуляторов, вам необходимо перейти на тарифный план Blaze .

Хотите пропустить вперед?

Вы можете скачать полную версию codelab. Если вы застряли на этом пути или хотите посмотреть, как выглядит готовое расширение, посетите ветку codelab-end репозитория GitHub или загрузите готовый zip-архив.

3. Просмотрите код

  • Откройте файл index.ts из zip-архива. Обратите внимание, что он содержит два объявления Cloud Functions.

Что делают эти функции?

Эти демонстрационные функции используются для геохеширования. Они берут пару координат и преобразуют их в формат, оптимизированный для географических запросов в Firestore. Функции имитируют использование вызова API, чтобы вы могли больше узнать об обработке конфиденциальных типов данных в расширениях. Дополнительную информацию см. в документации по выполнению географических запросов к данным в Firestore .

Функциональные константы

Константы объявляются вначале, в верхней части файла index.ts . На некоторые из этих констант имеются ссылки в триггерах, определенных расширением.

index.ts

import {firestore} from "firebase-functions";
import {initializeApp} from "firebase-admin/app";
import {GeoHashService, ResultStatusCode} from "./fake-geohash-service";
import {onCall} from "firebase-functions/v1/https";
import {fieldValueExists} from "./utils";

const documentPath = "users/{uid}";
const xField = "xv";
const yField = "yv";
const apiKey = "1234567890";
const outputField = "hash";

initializeApp();

const service = new GeoHashService(apiKey);

Триггер пожарного магазина

Первая функция в файле index.ts выглядит так:

index.ts

export const locationUpdate = firestore.document(documentPath)
  .onWrite((change) => {
    // item deleted
    if (change.after == null) {
      return 0;
    }
    // double check that both values exist for computation
    if (
      !fieldValueExists(change.after.data(), xField) ||
      !fieldValueExists(change.after.data(), yField)
    ) {
      return 0;
    }
    const x: number = change.after.data()![xField];
    const y: number = change.after.data()![yField];
    const hash = service.convertToHash(x, y);
    // This is to check whether the hash value has changed. If
    // it hasn't, you don't want to write to the document again as it
    // would create a recursive write loop.
    if (fieldValueExists(change.after.data(), outputField)
      && change.after.data()![outputField] == hash) {
      return 0;
    }
    return change.after.ref
      .update(
        {
          [outputField]: hash.hash,
        }
      );
  });

Эта функция является триггером Firestore . Когда в базе данных происходит событие записи, функция реагирует на это событие поиском поля xv и поля yv , и, если оба этих поля существуют, она вычисляет геохеш и записывает выходные данные в указанное место вывода документа. Входной документ определяется константой users/{uid} , что означает, что функция считывает каждый документ, записанный в коллекцию users/ , а затем обрабатывает геохэш для этих документов. Затем он выводит хэш в хеш-поле того же документа.

Вызываемые функции

Следующая функция в файле index.ts выглядит так:

index.ts

export const callableHash = onCall((data, context) => {
  if (context.auth == undefined) {
    return {error: "Only authorized users are allowed to call this endpoint"};
  }
  const x = data[xField];
  const y = data[yField];
  if (x == undefined || y == undefined) {
    return {error: "Either x or y parameter was not declared"};
  }
  const result = service.convertToHash(x, y);
  if (result.status != ResultStatusCode.ok) {
    return {error: `Something went wrong ${result.message}`};
  }
  return {result: result.hash};
});

Обратите внимание на функцию onCall . Это указывает на то, что эта функция является вызываемой функцией , которую можно вызвать из кода вашего клиентского приложения. Эта вызываемая функция принимает параметры x и y и возвращает геохэш. Хотя эта функция не будет вызываться напрямую в этой лаборатории кода, она включена сюда как пример того, что можно настроить в расширении Firebase.

4. Настройте файл Extension.yaml.

Теперь, когда вы знаете, что делает код Cloud Functions в вашем расширении, вы готовы упаковать его для распространения. Каждое расширение Firebase поставляется с файлом extension.yaml , который описывает, что делает расширение и как оно себя ведет.

Файл extension.yaml требует некоторых исходных метаданных о вашем расширении. Каждый из следующих шагов поможет вам понять, что означают все поля и зачем они вам нужны.

  1. Создайте файл extension.yaml в корневом каталоге проекта, который вы скачали ранее. Начните с добавления следующего:
name: geohash-ext
version: 0.0.1
specVersion: v1beta  # Firebase Extensions specification version (do not edit)

Имя расширения используется в качестве основы идентификатора экземпляра расширения (пользователи могут установить несколько экземпляров расширения, каждый со своим собственным идентификатором). Затем Firebase генерирует имена сервисных учетных записей расширения и ресурсов, специфичных для расширения, используя этот идентификатор экземпляра. Номер версии указывает версию вашего расширения. Оно должно соответствовать семантическому управлению версиями , и вам необходимо обновлять его всякий раз, когда вы вносите изменения в функциональность расширения. Версия спецификации расширения используется для определения того, какой спецификации расширений Firebase следует следовать, в данном случае используется v1beta .

  1. Добавьте некоторые удобные детали в файл YAML:
...

displayName: Latitude and longitude to GeoHash converter
description: A converter for changing your Latitude and longitude coordinates to geohashes.

Отображаемое имя — это удобное представление имени вашего расширения, когда разработчики взаимодействуют с вашим расширением. В описании дается краткий обзор того, что делает расширение. Когда расширение развернуто на Extensions.dev , оно выглядит примерно так:

Расширение Geohash Converter, как показано на Extensions.dev

  1. Укажите лицензию для кода в вашем расширении.
...

license: Apache-2.0  # The license you want for the extension
  1. Укажите, кто написал расширение и требуется ли оплата за его установку:
...

author:
  authorName: AUTHOR_NAME
  url: https://github.com/Firebase

billingRequired: true

Раздел « author используется для того, чтобы пользователи знали, к кому обращаться, если у них возникнут проблемы с расширением или им понадобится дополнительная информация о нем. billingRequired — обязательный параметр, и для него должно быть установлено значение true , поскольку все расширения используют облачные функции, для которых требуется план Blaze.

Это охватывает минимальное количество полей, необходимых в файле extension.yaml для идентификации этого расширения. Более подробную информацию о другой идентифицирующей информации, которую вы можете указать в расширении, смотрите в документации .

5. Преобразуйте код облачных функций в ресурс расширений.

Ресурс расширения — это элемент, который Firebase создает в проекте во время установки расширения. Затем расширение владеет этими ресурсами и имеет специальную учетную запись службы, которая с ними работает. В этом проекте этими ресурсами являются облачные функции, которые необходимо определить в файле extension.yaml , поскольку расширение не будет автоматически создавать ресурсы из кода в папке функций. Если ваши облачные функции не объявлены явно как ресурс, их нельзя будет развернуть при развертывании расширения.

Определяемое пользователем место развертывания

  1. Позвольте пользователю указать место, где он хочет развернуть это расширение, и решить, будет ли лучше разместить расширение ближе к конечным пользователям или ближе к их базе данных. В файле extension.yaml включите возможность выбора местоположения.

расширение.yaml

Теперь вы готовы написать конфигурацию ресурса функции.

  1. В файле extension.yaml создайте объект ресурса для функции locationUpdate . Добавьте следующее в файл extension.yaml :
resources:
  - name: locationUpdate
    type: firebaseextensions.v1beta.function
    properties:
      eventTrigger:
        eventType: providers/cloud.firestore/eventTypes/document.write
        resource: projects/${PROJECT_ID}/databases/(default)/documents/users/{uid}

Вы определяете name как имя функции, определенное в файле index.ts проекта. Вы указываете type развертываемой функции, который на данный момент всегда должен быть firebaseextensions.v1beta.function . Затем вы определяете properties этой функции. Первое свойство, которое вы определяете, — это eventTrigger , связанный с этой функцией. Чтобы отразить то, что расширение поддерживает в настоящее время, вы используете eventType providers/cloud.firestore/eventTypes/document.write , который находится в документации по облачным функциям записи вашего расширения . Вы определяете resource как расположение документов. Поскольку ваша текущая цель — отразить то, что существует в коде, путь к документу прослушивает users/{uid} с предшествующим ему расположением базы данных по умолчанию.

  1. Расширению необходимы разрешения на чтение и запись для базы данных Firestore. В самом конце файла extension.yaml укажите роли IAM, к которым расширение должно иметь доступ для работы с базой данных в проекте Firebase разработчика.
roles:
  - role: datastore.user
    reason: Allows the extension to read / write to your Firestore instance.

Роль datastore.user взята из списка поддерживаемых ролей IAM для расширений . Поскольку расширение будет выполнять чтение и запись, роль datastore.user здесь подойдет.

  1. Также необходимо добавить вызываемую функцию. В файле extension.yaml создайте новый ресурс в свойстве resources. Эти свойства специфичны для вызываемой функции:
  - name: callableHash
    type: firebaseextensions.v1beta.function
    properties:
      httpsTrigger: {}

Хотя предыдущий ресурс использовал eventTrigger , здесь вы используете httpsTrigger , который охватывает как вызываемые функции, так и функции HTTPS.

Проверка кода

Потребовалось много настроек, чтобы ваш extension.yaml соответствовал всему, что делает код в вашем файле index.ts . Вот как должен выглядеть готовый файл extension.yaml на данный момент:

расширение.yaml

name: geohash-ext
version: 0.0.1
specVersion: v1beta  # Firebase Extensions specification version (do not edit)

displayName: Latitude and Longitude to GeoHash converter
description: A converter for changing your Latitude and Longitude coordinates to geohashes.

license: Apache-2.0  # The license you want for the extension

author:
  authorName: Sparky
  url: https://github.com/Firebase

billingRequired: true

resources:
  - name: locationUpdate
    type: firebaseextensions.v1beta.function
    properties:
      eventTrigger:
        eventType: providers/cloud.firestore/eventTypes/document.write
        resource: projects/${PROJECT_ID}/databases/(default)/documents/users/{uid}
  - name: callableHash
    type: firebaseextensions.v1beta.function
    properties:
      httpsTrigger: {}

roles:
  - role: datastore.user
    reason: Allows the extension to read / write to your Firestore instance.

Проверка статуса

На данный момент у вас есть начальные функциональные части расширения, поэтому вы можете опробовать его с помощью эмуляторов Firebase!

  1. Если вы еще этого не сделали, вызовите npm run build в папке функций загруженного проекта расширений.
  2. Создайте новый каталог в своей хост-системе и подключите этот каталог к ​​вашему проекту Firebase с помощью firebase init .
cd ..
mkdir sample-proj
cd sample-proj
firebase init --project=projectID-or-alias
    This command creates a `firebase.json` file in the directory. In the following steps, you push the configuration specified in this file to Firebase.
  1. Из того же каталога запустите firebase ext:install . Замените /path/to/extension абсолютным путем к каталогу, содержащему файл extension.yaml .
firebase ext:install /path/to/extension
    This command does two things:
  • Он предложит вам указать конфигурацию экземпляра расширения и создаст файл *.env , содержащий информацию о конфигурации экземпляра.
  • Он добавляет экземпляр расширения в раздел extensions вашего firebase.json . Это действует как сопоставление идентификатора экземпляра с версией расширения.
  • Поскольку вы развертываете проект локально, вы можете указать, что хотите использовать локальный файл, а не Google Cloud Secret Manager.

Снимок экрана процесса установки расширения, показывающий, что локальный файл используется для секретов при установке этого расширения.

  1. Запустите эмуляторы Firebase с новой конфигурацией:
firebase emulators:start
  1. После запуска emulators:start перейдите на вкладку Firestore в веб-представлении эмуляторов.
  2. Добавьте документ в коллекцию users с полем номера xv и полем номера yv .

Диалоговое окно, которое отображается в эмуляторах Firebase для запуска коллекции с идентификатором коллекции, содержащим фразу.

  1. Если вам удалось установить расширение, оно создаст в документе новое поле под названием hash .

Коллекция пользователей с пользовательским документом, имеющим поля xv, yv и хэш.

Наведите порядок, чтобы избежать конфликтов

  • После завершения тестирования удалите расширение — вы собираетесь обновить код расширения и не хотите в дальнейшем конфликтовать с текущим расширением.

Расширения позволяют одновременно устанавливать несколько версий одного и того же расширения, поэтому, удалив его, вы гарантируете отсутствие конфликтов с ранее установленным расширением.

firebase ext:uninstall geohash-ext

Текущее решение работает, но, как упоминалось в начале проекта, существует жестко запрограммированный ключ API для имитации взаимодействия со службой. Как можно использовать ключ API конечного пользователя вместо первоначально предоставленного? Читай дальше что бы узнать.

6. Сделайте расширение настраиваемым пользователем.

На этом этапе кодовой лаборатории у вас есть расширение, настроенное для использования с тщательно продуманной настройкой функций, которые вы уже написали, но что, если ваш пользователь захочет использовать широту и долготу вместо y и x для полей, указывающих местоположение на декартовой плоскости? Кроме того, как вы можете заставить конечного пользователя предоставить свой собственный ключ API, а не позволять ему использовать предоставленный ключ API? Вы можете быстро превысить квоту для этого API. В этом случае вы настраиваете и используете параметры.

Определите основные параметры в файле extension.yaml .

Начните с преобразования элементов, для которых у разработчиков потенциально может быть специальная конфигурация. Первыми будут параметры XFIELD и YFIELD .

  1. В файл extension.yaml добавьте следующий код, который использует параметры полей XFIELD и YFIELD . Эти параметры находятся внутри ранее определенного свойства YAML params :

расширение.yaml

params:
  - param: XFIELD
    label: The X Field Name
    description: >-
      The X Field is also known as the **longitude** value. What does
      your Firestore instance refer to as the X value or the longitude
      value. If no value is specified, the extension searches for
      field 'xv'.
    type: string
    validationRegex: ^\D([0-9a-zA-Z_.]{0,375})$
    validationErrorMessage: >-
      The field can only contain uppercase or lowercase letter, numbers,
      _, and . characters and must be less than 1500 bytes long. The field
      must also not start with a number.
    default: xv
    required: false
    immutable: false
    example: xv
  - param: YFIELD
    label: The Y Field Name
    description: >-
      The Y Field is also known as the **latitude** value. What does
      your Firestore instance refer to as the Y value or the latitude
      value. If no value is specified, the extension searches for
      field 'yv'.
    type: string
    validationRegex: ^\D([0-9a-zA-Z_.]{0,375})$
    validationErrorMessage: >-
      The field can only contain uppercase or lowercase letter, numbers,
      _, and . characters and must be less than 1500 bytes long. The field
      must also not start with a number.
    default: yv
    required: false
    immutable: false
    example: yv
  • param называет параметр таким образом, чтобы он был виден вам, производителю расширения. Используйте это значение позже при указании значений параметров.
  • label — это удобочитаемый идентификатор для разработчика, позволяющий ему узнать, что делает параметр.
  • описание дает подробное описание значения. Поскольку это поддерживает уценку, оно может ссылаться на дополнительную документацию или выделять слова, которые могут быть важны для разработчика.
  • type определяет механизм ввода того, как пользователь будет устанавливать значение параметра. Существует множество типов, включая string , select , multiSelect , selectResource и secret . Подробнее о каждой из этих опций можно узнать в документации .
  • validationRegex ограничивает запись разработчика определенным значением регулярного выражения (в примере оно основано на простых рекомендациях по именам полей, найденных здесь ); а если это не удастся...
  • validationErrorMessage предупреждает разработчика о значении ошибки.
  • по умолчанию — это то, какое значение было бы, если бы разработчик не ввел никакого текста.
  • «Обязательно» означает, что разработчику не требуется вводить какой-либо текст.
  • immutable позволяет разработчику обновлять это расширение и изменять это значение. В этом случае разработчик должен иметь возможность изменять имена полей по мере изменения требований.
  • Пример дает представление о том, как может выглядеть допустимый ввод.

Это было очень важно понять!

  1. Прежде чем добавлять специальный параметр, вам нужно добавить в файл extension.yaml еще три параметра.
  - param: INPUTPATH
    label: The input document to listen to for changes
    description: >-
      This is the document where you write an x and y value to. Once
      that document has received a value, it notifies the extension to
      calculate a geohash and store that in an output document in a certain
      field. This accepts function [wildcard parameters](https://firebase.google.com/docs/functions/firestore-events#wildcards-parameters)
    type: string
    validationRegex: ^[^/]+(/[^/]*/[^/]*)*/[^/]+$
    validationErrorMessage: >-
      This must point to a document path, not a collection path from the root
      of the database. It must also not start or end with a '/' character.
    required: true
    immutable: false
    example: users/{uid}
  - param: OUTPUTFIELD
    label: Geohash field
    description: >-
      This specifies the field in the output document to store the geohash in.
    type: string
    validationRegex: ^\D([0-9a-zA-Z_.]{0,375})$
    validationErrorMessage: >-
      The field can only contain uppercase or lowercase letter, numbers,
      _, and . characters and must be less than 1500 bytes long. The field
      must also not start with a number.
    required: false
    default: hash
    immutable: false
    example: hash

Определите чувствительные параметры

Теперь вам нужно управлять ключом API, который указывает пользователь. Это конфиденциальная строка, которую не следует хранить в функции в виде обычного текста. Вместо этого сохраните это значение в диспетчере секретов Cloud . Это особое место в облаке, где хранятся зашифрованные секреты и предотвращается их случайная утечка. Это требует от разработчика оплаты за использование этой услуги, но это добавляет дополнительный уровень безопасности к его ключам API и потенциально ограничивает мошенническую деятельность. Пользовательская документация предупреждает разработчика, что это платная услуга, чтобы не было сюрпризов при выставлении счетов. В целом, использование аналогично другим строковым ресурсам, упомянутым выше. Единственная разница — это тип, который называется secret .

  • В файл extension.yaml добавьте следующий код:

расширение.yaml

  - param: APIKEY
    label: GeohashService API Key
    description: >-
      Your geohash service API Key. Since this is a demo, and not a real
      service, you can use : 1234567890.
    type: secret
    required: true
    immutable: false

Обновите атрибуты resource , чтобы использовать параметры.

Как упоминалось ранее, ресурс (а не функция) определяет способ наблюдения за ресурсом, поэтому ресурс locationUpdate необходимо обновить, чтобы использовать новый параметр.

  • В файл extension.yaml добавьте следующий код:

расширение.yaml

## Change from this
  - name: locationUpdate
    type: firebaseextensions.v1beta.function
    properties:
      eventTrigger:
        eventType: providers/cloud.firestore/eventTypes/document.write
        resource: projects/${PROJECT_ID}/databases/(default)/documents/users/{uid}]

## To this
  - name: locationUpdate
    type: firebaseextensions.v1beta.function
    properties:
      eventTrigger:
        eventType: providers/cloud.firestore/eventTypes/document.write
        resource: projects/${PROJECT_ID}/databases/(default)/documents/${INPUTPATH}

Проверьте файл extension.yaml .

  • Просмотрите файл extension.yaml . Это должно выглядеть примерно так:

расширение.yaml

name: geohash-ext
version: 0.0.1
specVersion: v1beta  # Firebase Extensions specification version (do not edit)

displayName: Latitude and Longitude to GeoHash converter
description: A converter for changing your Latitude and Longitude coordinates to geohashes.

license: Apache-2.0  # The license you want to use for the extension

author:
  authorName: Sparky
  url: https://github.com/Firebase

billingRequired: true

params:
  - param: XFIELD
    label: The X Field Name
    description: >-
      The X Field is also known as the **longitude** value. What does
      your Firestore instance refer to as the X value or the longitude
      value. If you don't provide a value for this field, the extension will use 'xv' as the default value.
    type: string
    validationRegex: ^\D([0-9a-zA-Z_.]{0,375})$
    validationErrorMessage: >-
      The field can only contain uppercase or lowercase letter, numbers,
      _, and . characters and must be less than 1500 bytes long. The field
      must also not start with a number.
    default: xv
    required: false
    immutable: false
    example: xv
  - param: YFIELD
    label: The Y Field Name
    description: >-
      The Y Field is also known as the **latitude** value. What does
      your Firestore instance refer to as the Y value or the latitude
      Value. If you don't provide a value for this field, the extension will use 'yv' as the default value.
    type: string
    validationRegex: ^\D([0-9a-zA-Z_.]{0,375})$
    validationErrorMessage: >-
      The field can only contain uppercase or lowercase letter, numbers,
      _, and . characters and must be less than 1500 bytes long. The field
      must also not start with a number.
    default: yv
    required: false
    immutable: false
    example: yv
  - param: INPUTPATH
    label: The input document to listen to for changes
    description: >-
      This is the document where you write an x and y value to. Once
      that document has been modified, it notifies the extension to
      compute a geohash and store that in an output document in a certain
      field. This accepts function [wildcard parameters](https://firebase.google.com/docs/functions/firestore-events#wildcards-parameters)
    type: string
    validationRegex: ^[^/]+(/[^/]*/[^/]*)*/[^/]+$
    validationErrorMessage: >-
      This must point to a document path, not a collection path from the root
      of the database. It must also not start or end with a '/' character.
    required: true
    immutable: false
    example: users/{uid}
  - param: OUTPUTFIELD
    label: Geohash field
    description: >-
      This specifies the field in the output document to store the geohash in.
    type: string
    validationRegex: ^\D([0-9a-zA-Z_.]{0,375})$
    validationErrorMessage: >-
      The field can only contain uppercase or lowercase letter, numbers,
      _, and . characters and must be less than 1500 bytes long. The field
      must also not start with a number.
    required: false
    default: hash
    immutable: false
    example: hash
  - param: APIKEY
    label: GeohashService API Key
    description: >-
      Your geohash service API Key. Since this is a demo, and not a real
      service, you can use : 1234567890.
    type: secret
    required: true
    immutable: false

resources:
  - name: locationUpdate
    type: firebaseextensions.v1beta.function
    properties:
      eventTrigger:
        eventType: providers/cloud.firestore/eventTypes/document.write
        resource: projects/${PROJECT_ID}/databases/(default)/documents/${INPUTPATH}
  - name: callableHash
    type: firebaseextensions.v1beta.function
    properties:
      httpsTrigger: {}

roles:
  - role: datastore.user
    reason: Allows the extension to read / write to your Firestore instance.

Доступ к параметрам в коде

Теперь, когда все параметры настроены в файле extension.yaml , добавьте их в файл index.ts .

  • В файле index.ts замените значения по умолчанию process.env.PARAMETER_NAME , который извлекает соответствующие значения параметров и заполняет их в функциональном коде, развернутом в проекте Firebase разработчика.

index.ts

// Replace this:
const documentPath = "users/{uid}";
const xField = "xv";
const yField = "yv";
const apiKey = "1234567890";
const outputField = "hash";

// with this:
const documentPath = process.env.INPUTPATH!; // this value is ignored since its read from the resource
const xField = process.env.XFIELD!;
const yField = process.env.YFIELD!;
const apiKey = process.env.APIKEY!;
const outputField = process.env.OUTPUTFIELD!;

Обычно вы хотите выполнить проверку на нулевое значение для значений переменных среды, но в этом случае вы уверены, что значения параметров скопированы правильно. Теперь код настроен для работы с параметрами расширения.

7. Создайте пользовательскую документацию

Прежде чем тестировать код на эмуляторах или на рынке расширений Firebase, расширение необходимо задокументировать, чтобы разработчики знали, что они получают, когда используют расширение.

  1. Начните с создания файла PREINSTALL.md , который используется для описания функциональности, любых предварительных требований для установки и потенциальных последствий для выставления счетов.

PREINSTALL.md

Use this extension to automatically convert documents with a latitude and
longitude to a geohash in your database. Additionally, this extension includes a callable function that allows users to make one-time calls
to convert an x,y coordinate into a geohash.

Geohashing is supported for latitudes between 90 and -90 and longitudes
between 180 and -180.

#### Third Party API Key

This extension uses a fictitious third-party API for calculating the
geohash. You need to supply your own API keys. (Since it's fictitious,
you can use 1234567890 as an API key).

#### Additional setup

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

After installing this extension, you'll need to:

- Update your client code to point to the callable geohash function if you
want to perform arbitrary geohashes.

Detailed information for these post-installation tasks are provided after
you install this extension.

#### 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:
 - Cloud Firestore
 - Cloud Functions (Node.js 16+ runtime. [See
FAQs](https://firebase.google.com/support/faq#extensions-pricing))
 - [Cloud Secret Manager](https://cloud.google.com/secret-manager/pricing)
  1. Чтобы сэкономить время на написании README.md для этого проекта, используйте удобный метод:
firebase ext:info . --markdown > README.md

Он объединяет содержимое вашего файла PREINSTALL.md и дополнительную информацию о вашем расширении из файла extension.yaml .

Наконец, сообщите разработчику расширения о некоторых дополнительных деталях, касающихся только что установленного расширения. Разработчик может получить некоторые дополнительные инструкции и информацию после завершения установки, а также получить некоторые подробные задачи после установки, такие как настройка клиентского кода здесь.

  1. Создайте файл POSTINSTALL.md и включите в него следующую информацию после установки:

POSTINSTALL.md

Congratulations on installing the geohash extension!

#### Function information

* **Firestore Trigger** - ${function:locationUpdate.name} was installed
and is invoked when both an x field (${param:XFIELD}) and y field
(${param:YFIELD}) contain a value.

* **Callable Trigger** - ${function:callableHash.name} was installed and
can be invoked by writing the following client code:
 ```javascript
import { getFunctions, httpsCallable } from "firebase/functions";
const functions = getFunctions();
const geoHash = httpsCallable(functions, '${function:callableHash.name}');
geoHash({ ${param:XFIELD}: -122.0840, ${param:YFIELD}: 37.4221 })
  .then((result) => {
    // Read result of the Cloud Function.
    /** @type {any} */
    const data = result.data;
    const error = data.error;
    if (error != null) {
        console.error(`callable error : ${error}`);
    }
    const result = data.result;
    console.log(result);
  });

Мониторинг

Рекомендуется отслеживать активность установленного расширения, включая проверку его работоспособности, использования и журналов.

The output rendering looks something like this when it's deployed:

<img src="img/82b54a5c6ca34b3c.png" alt="A preview of the latitude and longitude geohash converter extension in the firebase console"  width="957.00" />


## Test the extension with the full configuration
Duration: 03:00


It's time to make sure that the user-configurable extension is working the way it is intended.

* Change into the functions folder and ensure that the latest compiled version of the extensions exists. In the extensions project functions directory, call:

```console
npm run build

При этом функции перекомпилируются, поэтому последний исходный код готов к развертыванию вместе с расширением при его развертывании в эмуляторе или непосредственно в Firebase.

Затем создайте новый каталог для тестирования расширения. Поскольку расширение было разработано на основе существующих функций, не выполняйте тестирование из папки, в которой было настроено расширение, поскольку оно также пытается развернуть вместе с ним функции и правила Firebase.

Установите и протестируйте эмуляторы Firebase.

  1. Создайте новый каталог в своей хост-системе и подключите этот каталог к ​​вашему проекту Firebase с помощью firebase init .
mkdir sample-proj
cd sample-proj
firebase init --project=projectID-or-alias
  1. Из этого каталога запустите firebase ext:install , чтобы установить расширение. Замените /path/to/extension абсолютным путем к каталогу, содержащему файл extension.yaml . Это запустит процесс установки вашего расширения и создаст файл .env , содержащий ваши конфигурации, прежде чем отправить конфигурацию в Firebase или в эмуляторы.
firebase ext:install /path/to/extension
  • Поскольку вы развертываете проект локально, укажите, что вы хотите использовать локальный файл, а не Google Cloud Secret Manager.

da928c65ffa8ce15.png

  1. Запустите локальный эмулятор:
firebase emulators:start

Установите и протестируйте реальный проект Firebase.

Вы можете установить свое расширение в реальный проект Firebase. Для тестирования рекомендуется использовать тестовый проект. Используйте этот рабочий процесс тестирования, если вы хотите протестировать сквозной процесс вашего расширения или если триггер вашего расширения еще не поддерживается набором эмуляторов Firebase (см. опцию «Эмулятор расширений » ). В настоящее время эмуляторы поддерживают функции, запускаемые HTTP-запросами, и функции, запускаемые фоновыми событиями, для Cloud Firestore, базы данных Realtime и Pub/Sub.

  1. Создайте новый каталог в своей хост-системе и подключите этот каталог к ​​вашему проекту Firebase с помощью firebase init .
cd ..
mkdir sample-proj
cd sample-proj
firebase init --project=projectID-or-alias
  1. Затем из этого каталога запустите firebase ext:install , чтобы установить расширение. Замените /path/to/extension абсолютным путем к каталогу, содержащему файл extension.yaml . Это запустит процесс установки вашего расширения и создаст файл .env , содержащий ваши конфигурации, прежде чем отправить конфигурацию в Firebase или в эмуляторы.
firebase ext:install /path/to/extension
  • Поскольку вы хотите выполнить развертывание напрямую в Firebase и использовать Google Cloud Secret Manager, вам необходимо активировать API Secret Manager перед установкой расширения.
  1. Разверните в свой проект Firebase.
firebase deploy

Протестируйте расширение

  1. После запуска firebase deploy или firebase emulators:start перейдите на вкладку Firestore либо в консоли Firebase , либо в веб-просмотре эмуляторов, в зависимости от ситуации.
  2. Добавьте документ в коллекцию, указанную полями x и y . В этом случае обновленные документы располагаются по адресу u/{uid} с полем x , равным xv , и полем y , равным yv .

Экран эмуляторов Firebase для добавления записи Firestore

  1. Если вам удалось установить расширение, оно создаст в документе новое поле под названием hash после сохранения двух полей.

Экран базы данных Firestore из эмулятора, показывающий добавленный хэш

8. Поздравляем!

Вы успешно преобразовали свою первую облачную функцию в расширение Firebase!

Вы добавили файл extension.yaml и настроили его, чтобы разработчики могли выбрать способ развертывания вашего расширения. Затем вы создали пользовательскую документацию, содержащую инструкции о том, что разработчикам расширения следует делать перед настройкой расширения и какие шаги им может потребоваться предпринять после успешной установки расширения.

Теперь вы знаете ключевые шаги, необходимые для преобразования функции Firebase в распространяемое расширение Firebase.

Что дальше?