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

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

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

Что вы построите

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

Расширение geohash, отображаемое в консоли 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» . В этой лабораторной работе используются функции Cloud Functions, поэтому, если вы используете настоящий проект Firebase вместо эмуляторов, вам необходимо перейти на тарифный план Blaze .

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

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

3. Проверьте код.

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

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

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

Константы функций

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

индекс.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);

Триггер Firestore

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

индекс.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 выглядит так:

индекс.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 поскольку все расширения используют Cloud Functions, для которого требуется план 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 , который находится в документации Write Cloud Functions для вашего расширения . Вы определяете 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 и hash.

Уборка во избежание конфликтов

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

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

firebase ext:uninstall geohash-ext

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

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

На этом этапе работы над кодовой лабораторией у вас есть расширение, настроенное для использования с уже написанными вами функциями, но что, если пользователь захочет использовать широту и долготу вместо y и x для полей, указывающих местоположение на декартовой плоскости? Кроме того, как заставить конечного пользователя предоставить собственный ключ 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 — это понятный человеку идентификатор, позволяющий разработчику понять, что делает параметр.
  • Описание содержит подробное описание значения. Поскольку поддерживается разметка, оно может ссылаться на дополнительную документацию или выделять слова, которые могут быть важны для разработчика.
  • Тип определяет механизм ввода, с помощью которого пользователь может задать значение параметра. Существует множество типов, включая string , select , multiSelect , selectResource и secret . Подробнее о каждом из этих параметров см. в документации .
  • validationRegex ограничивает запись разработчика определенным значением регулярного выражения (в примере оно основано на простых рекомендациях по именам полей, которые можно найти здесь ); и если это не удается...
  • validationErrorMessage оповещает разработчика о значении ошибки.
  • default — это то значение, которое было бы, если бы разработчик не ввел никакого текста.
  • required означает, что разработчику не требуется вводить какой-либо текст.
  • Неизменяемость позволяет разработчику обновлять это расширение и изменять это значение. В этом случае разработчик должен иметь возможность изменять имена полей по мере изменения своих требований.
  • пример дает представление о том, как могут выглядеть допустимые входные данные.

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

  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 Secret Manager . Это специальное место в облаке, где хранятся зашифрованные секреты, предотвращая их случайную утечку. Это требует от разработчика оплаты за использование этого сервиса, но добавляет дополнительный уровень безопасности к его ключам 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 разработчика.

индекс.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!;

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

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 Database и 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.

Что дальше?