text: /*! firebase-admin v5.8.1 */
  "use strict";
  /*!
   * Copyright 2017 Google Inc.
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *   http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  Object.defineProperty(exports, "__esModule", { value: true });
  var fs = require("fs");
  var deep_copy_1 = require("./utils/deep-copy");
  var error_1 = require("./utils/error");
  var firebase_app_1 = require("./firebase-app");
  var credential_1 = require("./auth/credential");
  var auth_1 = require("./auth/auth");
  var messaging_1 = require("./messaging/messaging");
  var storage_1 = require("./storage/storage");
  var instance_id_1 = require("./instance-id/instance-id");
  var validator = require("./utils/validator");
  var DEFAULT_APP_NAME = '[DEFAULT]';
  /**
   * Constant holding the environment variable name with the default config.
   * If the environmet variable contains a string that starts with '{' it will be parsed as JSON,
   * otherwise it will be assumed to be pointing to a file.
   */
  exports.FIREBASE_CONFIG_VAR = 'FIREBASE_CONFIG';
  var globalAppDefaultCred;
  var globalCertCreds = {};
  var globalRefreshTokenCreds = {};
  /**
   * Internals of a FirebaseNamespace instance.
   */
  var FirebaseNamespaceInternals = /** @class */ (function () {
      function FirebaseNamespaceInternals(firebase_) {
          this.firebase_ = firebase_;
          this.serviceFactories = {};
          this.apps_ = {};
          this.appHooks_ = {};
      }
      /**
       * Initializes the FirebaseApp instance.
       *
       * @param {FirebaseAppOptions} options Optional options for the FirebaseApp instance. If none present
       *                             will try to initialize from the FIREBASE_CONFIG environment variable.
       *                             If the environmet variable contains a string that starts with '{'
       *                             it will be parsed as JSON,
       *                             otherwise it will be assumed to be pointing to a file.
       * @param {string} [appName] Optional name of the FirebaseApp instance.
       *
       * @return {FirebaseApp} A new FirebaseApp instance.
       */
      FirebaseNamespaceInternals.prototype.initializeApp = function (options, appName) {
          if (appName === void 0) { appName = DEFAULT_APP_NAME; }
          if (typeof options === 'undefined') {
              options = this.loadOptionsFromEnvVar();
              options.credential = new credential_1.ApplicationDefaultCredential();
          }
          if (typeof appName !== 'string' || appName === '') {
              throw new error_1.FirebaseAppError(error_1.AppErrorCodes.INVALID_APP_NAME, "Invalid Firebase app name \"" + appName + "\" provided. App name must be a non-empty string.");
          }
          else if (appName in this.apps_) {
              if (appName === DEFAULT_APP_NAME) {
                  throw new error_1.FirebaseAppError(error_1.AppErrorCodes.DUPLICATE_APP, 'The default Firebase app already exists. This means you called initializeApp() ' +
                      'more than once without providing an app name as the second argument. In most cases ' +
                      'you only need to call initializeApp() once. But if you do want to initialize ' +
                      'multiple apps, pass a second argument to initializeApp() to give each app a unique ' +
                      'name.');
              }
              else {
                  throw new error_1.FirebaseAppError(error_1.AppErrorCodes.DUPLICATE_APP, "Firebase app named \"" + appName + "\" already exists. This means you called initializeApp() " +
                      'more than once with the same app name as the second argument. Make sure you provide a ' +
                      'unique name every time you call initializeApp().');
              }
          }
          var app = new firebase_app_1.FirebaseApp(options, appName, this);
          this.apps_[appName] = app;
          this.callAppHooks_(app, 'create');
          return app;
      };
      /**
       * Returns the FirebaseApp instance with the provided name (or the default FirebaseApp instance
       * if no name is provided).
       *
       * @param {string} [appName=DEFAULT_APP_NAME] Optional name of the FirebaseApp instance to return.
       * @return {FirebaseApp} The FirebaseApp instance which has the provided name.
       */
      FirebaseNamespaceInternals.prototype.app = function (appName) {
          if (appName === void 0) { appName = DEFAULT_APP_NAME; }
          if (typeof appName !== 'string' || appName === '') {
              throw new error_1.FirebaseAppError(error_1.AppErrorCodes.INVALID_APP_NAME, "Invalid Firebase app name \"" + appName + "\" provided. App name must be a non-empty string.");
          }
          else if (!(appName in this.apps_)) {
              var errorMessage = void 0;
              if (appName === DEFAULT_APP_NAME) {
                  errorMessage = 'The default Firebase app does not exist. ';
              }
              else {
                  errorMessage = "Firebase app named \"" + appName + "\" does not exist. ";
              }
              errorMessage += 'Make sure you call initializeApp() before using any of the Firebase services.';
              throw new error_1.FirebaseAppError(error_1.AppErrorCodes.NO_APP, errorMessage);
          }
          return this.apps_[appName];
      };
      Object.defineProperty(FirebaseNamespaceInternals.prototype, "apps", {
          /*
           * Returns an array of all the non-deleted FirebaseApp instances.
           *
           * @return {Array<FirebaseApp>} An array of all the non-deleted FirebaseApp instances
           */
          get: function () {
              var _this = this;
              // Return a copy so the caller cannot mutate the array
              return Object.keys(this.apps_).map(function (appName) { return _this.apps_[appName]; });
          },
          enumerable: true,
          configurable: true
      });
      /*
       * Removes the specified FirebaseApp instance.
       *
       * @param {string} appName The name of the FirebaseApp instance to remove.
       */
      FirebaseNamespaceInternals.prototype.removeApp = function (appName) {
          if (typeof appName === 'undefined') {
              throw new error_1.FirebaseAppError(error_1.AppErrorCodes.INVALID_APP_NAME, "No Firebase app name provided. App name must be a non-empty string.");
          }
          var appToRemove = this.app(appName);
          this.callAppHooks_(appToRemove, 'delete');
          delete this.apps_[appName];
      };
      /*
       * Registers a new service on this Firebase namespace.
       *
       * @param {string} serviceName The name of the Firebase service to register.
       * @param {FirebaseServiceFactory} createService A factory method to generate an instance of the Firebase service.
       * @param {Object} [serviceProperties] Optional properties to extend this Firebase namespace with.
       * @param {AppHook} [appHook] Optional callback that handles app-related events like app creation and deletion.
       * @return {FirebaseServiceNamespace<FirebaseServiceInterface>} The Firebase service's namespace.
       */
      FirebaseNamespaceInternals.prototype.registerService = function (serviceName, createService, serviceProperties, appHook) {
          var _this = this;
          var errorMessage;
          if (typeof serviceName === 'undefined') {
              errorMessage = "No service name provided. Service name must be a non-empty string.";
          }
          else if (typeof serviceName !== 'string' || serviceName === '') {
              errorMessage = "Invalid service name \"" + serviceName + "\" provided. Service name must be a non-empty string.";
          }
          else if (serviceName in this.serviceFactories) {
              errorMessage = "Firebase service named \"" + serviceName + "\" has already been registered.";
          }
          if (typeof errorMessage !== 'undefined') {
              throw new error_1.FirebaseAppError(error_1.AppErrorCodes.INTERNAL_ERROR, "INTERNAL ASSERT FAILED: " + errorMessage);
          }
          this.serviceFactories[serviceName] = createService;
          if (appHook) {
              this.appHooks_[serviceName] = appHook;
          }
          var serviceNamespace;
          // The service namespace is an accessor function which takes a FirebaseApp instance
          // or uses the default app if no FirebaseApp instance is provided
          serviceNamespace = function (appArg) {
              if (typeof appArg === 'undefined') {
                  appArg = _this.app();
              }
              // Forward service instance lookup to the FirebaseApp
              return appArg[serviceName]();
          };
          // ... and a container for service-level properties.
          if (serviceProperties !== undefined) {
              deep_copy_1.deepExtend(serviceNamespace, serviceProperties);
          }
          // Monkey-patch the service namespace onto the Firebase namespace
          this.firebase_[serviceName] = serviceNamespace;
          return serviceNamespace;
      };
      /**
       * Calls the app hooks corresponding to the provided event name for each service within the
       * provided FirebaseApp instance.
       *
       * @param {FirebaseApp} app The FirebaseApp instance whose app hooks to call.
       * @param {string} eventName The event name representing which app hooks to call.
       */
      FirebaseNamespaceInternals.prototype.callAppHooks_ = function (app, eventName) {
          var _this = this;
          Object.keys(this.serviceFactories).forEach(function (serviceName) {
              if (_this.appHooks_[serviceName]) {
                  _this.appHooks_[serviceName](eventName, app);
              }
          });
      };
      /**
       * Parse the file pointed to by the FIREBASE_CONFIG_VAR, if it exists.
       * Or if the FIREBASE_CONFIG_ENV contains a valid JSON object, parse it directly.
       * If the environmet variable contains a string that starts with '{' it will be parsed as JSON,
       * otherwise it will be assumed to be pointing to a file.
       */
      FirebaseNamespaceInternals.prototype.loadOptionsFromEnvVar = function () {
          var config = process.env[exports.FIREBASE_CONFIG_VAR];
          if (!validator.isNonEmptyString(config)) {
              return {};
          }
          try {
              var contents = void 0;
              if (config.startsWith('{')) {
                  // Assume json object.
                  contents = config;
              }
              else {
                  // Assume filename.
                  contents = fs.readFileSync(config, 'utf8');
              }
              return JSON.parse(contents);
          }
          catch (error) {
              // Throw a nicely formed error message if the file contents cannot be parsed
              throw new error_1.FirebaseAppError(error_1.AppErrorCodes.INVALID_APP_OPTIONS, 'Failed to parse app options file: ' + error);
          }
      };
      return FirebaseNamespaceInternals;
  }());
  exports.FirebaseNamespaceInternals = FirebaseNamespaceInternals;
  var firebaseCredential = {
      cert: function (serviceAccountPathOrObject) {
          var stringifiedServiceAccount = JSON.stringify(serviceAccountPathOrObject);
          if (!(stringifiedServiceAccount in globalCertCreds)) {
              globalCertCreds[stringifiedServiceAccount] = new credential_1.CertCredential(serviceAccountPathOrObject);
          }
          return globalCertCreds[stringifiedServiceAccount];
      },
      refreshToken: function (refreshTokenPathOrObject) {
          var stringifiedRefreshToken = JSON.stringify(refreshTokenPathOrObject);
          if (!(stringifiedRefreshToken in globalRefreshTokenCreds)) {
              globalRefreshTokenCreds[stringifiedRefreshToken] = new credential_1.RefreshTokenCredential(refreshTokenPathOrObject);
          }
          return globalRefreshTokenCreds[stringifiedRefreshToken];
      },
      applicationDefault: function () {
          if (typeof globalAppDefaultCred === 'undefined') {
              globalAppDefaultCred = new credential_1.ApplicationDefaultCredential();
          }
          return globalAppDefaultCred;
      },
  };
  /**
   * Global Firebase context object.
   */
  var FirebaseNamespace = /** @class */ (function () {
      /* tslint:enable */
      function FirebaseNamespace() {
          // Hack to prevent Babel from modifying the object returned as the default admin namespace.
          /* tslint:disable:variable-name */
          this.__esModule = true;
          /* tslint:enable:variable-name */
          this.credential = firebaseCredential;
          this.SDK_VERSION = '5.8.1';
          /* tslint:disable */
          // TODO(jwenger): Database is the only consumer of firebase.Promise. We should update it to use
          // use the native Promise and then remove this.
          this.Promise = Promise;
          this.INTERNAL = new FirebaseNamespaceInternals(this);
      }
      Object.defineProperty(FirebaseNamespace.prototype, "auth", {
          /**
           * Gets the `Auth` service namespace. The returned namespace can be used to get the
           * `Auth` service for the default app or an explicitly specified app.
           */
          get: function () {
              var ns = this;
              var fn = function (app) {
                  return ns.ensureApp(app).auth();
              };
              return Object.assign(fn, { Auth: auth_1.Auth });
          },
          enumerable: true,
          configurable: true
      });
      Object.defineProperty(FirebaseNamespace.prototype, "database", {
          /**
           * Gets the `Database` service namespace. The returned namespace can be used to get the
           * `Database` service for the default app or an explicitly specified app.
           */
          get: function () {
              var ns = this;
              var fn = function (app) {
                  return ns.ensureApp(app).database();
              };
              return Object.assign(fn, require('@firebase/database'));
          },
          enumerable: true,
          configurable: true
      });
      Object.defineProperty(FirebaseNamespace.prototype, "messaging", {
          /**
           * Gets the `Messaging` service namespace. The returned namespace can be used to get the
           * `Messaging` service for the default app or an explicitly specified app.
           */
          get: function () {
              var ns = this;
              var fn = function (app) {
                  return ns.ensureApp(app).messaging();
              };
              return Object.assign(fn, { Messaging: messaging_1.Messaging });
          },
          enumerable: true,
          configurable: true
      });
      Object.defineProperty(FirebaseNamespace.prototype, "storage", {
          /**
           * Gets the `Storage` service namespace. The returned namespace can be used to get the
           * `Storage` service for the default app or an explicitly specified app.
           */
          get: function () {
              var ns = this;
              var fn = function (app) {
                  return ns.ensureApp(app).storage();
              };
              return Object.assign(fn, { Storage: storage_1.Storage });
          },
          enumerable: true,
          configurable: true
      });
      Object.defineProperty(FirebaseNamespace.prototype, "firestore", {
          /**
           * Gets the `Firestore` service namespace. The returned namespace can be used to get the
           * `Firestore` service for the default app or an explicitly specified app.
           */
          get: function () {
              var ns = this;
              var fn = function (app) {
                  return ns.ensureApp(app).firestore();
              };
              return Object.assign(fn, require('@google-cloud/firestore'));
          },
          enumerable: true,
          configurable: true
      });
      Object.defineProperty(FirebaseNamespace.prototype, "instanceId", {
          /**
           * Gets the `InstanceId` service namespace. The returned namespace can be used to get the
           * `Instance` service for the default app or an explicitly specified app.
           */
          get: function () {
              var ns = this;
              var fn = function (app) {
                  return ns.ensureApp(app).instanceId();
              };
              return Object.assign(fn, { InstanceId: instance_id_1.InstanceId });
          },
          enumerable: true,
          configurable: true
      });
      /**
       * Initializes the FirebaseApp instance.
       *
       * @param {FirebaseAppOptions} [options] Optional options for the FirebaseApp instance.
       *   If none present will try to initialize from the FIREBASE_CONFIG environment variable.
       *   If the environmet variable contains a string that starts with '{' it will be parsed as JSON,
       *   otherwise it will be assumed to be pointing to a file.
       * @param {string} [appName] Optional name of the FirebaseApp instance.
       *
       * @return {FirebaseApp} A new FirebaseApp instance.
       */
      FirebaseNamespace.prototype.initializeApp = function (options, appName) {
          return this.INTERNAL.initializeApp(options, appName);
      };
      /**
       * Returns the FirebaseApp instance with the provided name (or the default FirebaseApp instance
       * if no name is provided).
       *
       * @param {string} [appName] Optional name of the FirebaseApp instance to return.
       * @return {FirebaseApp} The FirebaseApp instance which has the provided name.
       */
      FirebaseNamespace.prototype.app = function (appName) {
          return this.INTERNAL.app(appName);
      };
      Object.defineProperty(FirebaseNamespace.prototype, "apps", {
          /*
           * Returns an array of all the non-deleted FirebaseApp instances.
           *
           * @return {Array<FirebaseApp>} An array of all the non-deleted FirebaseApp instances
           */
          get: function () {
              return this.INTERNAL.apps;
          },
          enumerable: true,
          configurable: true
      });
      FirebaseNamespace.prototype.ensureApp = function (app) {
          if (typeof app === 'undefined') {
              app = this.app();
          }
          return app;
      };
      return FirebaseNamespace;
  }());
  exports.FirebaseNamespace = FirebaseNamespace;
  