text: import { _registerComponent, getApp, _getProvider, registerVersion } from '@firebase/app';
  import { FirebaseError, getModularInstance } from '@firebase/util';
  import { Component } from '@firebase/component';
  
  /**
   * @license
   * Copyright 2017 Google LLC
   *
   * 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.
   */
  const LONG_TYPE = 'type.googleapis.com/google.protobuf.Int64Value';
  const UNSIGNED_LONG_TYPE = 'type.googleapis.com/google.protobuf.UInt64Value';
  function mapValues(
  // { [k: string]: unknown } is no longer a wildcard assignment target after typescript 3.5
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  o, f) {
      const result = {};
      for (const key in o) {
          if (o.hasOwnProperty(key)) {
              result[key] = f(o[key]);
          }
      }
      return result;
  }
  /**
   * Takes data and encodes it in a JSON-friendly way, such that types such as
   * Date are preserved.
   * @internal
   * @param data - Data to encode.
   */
  function encode(data) {
      if (data == null) {
          return null;
      }
      if (data instanceof Number) {
          data = data.valueOf();
      }
      if (typeof data === 'number' && isFinite(data)) {
          // Any number in JS is safe to put directly in JSON and parse as a double
          // without any loss of precision.
          return data;
      }
      if (data === true || data === false) {
          return data;
      }
      if (Object.prototype.toString.call(data) === '[object String]') {
          return data;
      }
      if (data instanceof Date) {
          return data.toISOString();
      }
      if (Array.isArray(data)) {
          return data.map(x => encode(x));
      }
      if (typeof data === 'function' || typeof data === 'object') {
          return mapValues(data, x => encode(x));
      }
      // If we got this far, the data is not encodable.
      throw new Error('Data cannot be encoded in JSON: ' + data);
  }
  /**
   * Takes data that's been encoded in a JSON-friendly form and returns a form
   * with richer datatypes, such as Dates, etc.
   * @internal
   * @param json - JSON to convert.
   */
  function decode(json) {
      if (json == null) {
          return json;
      }
      if (json['@type']) {
          switch (json['@type']) {
              case LONG_TYPE:
              // Fall through and handle this the same as unsigned.
              case UNSIGNED_LONG_TYPE: {
                  // Technically, this could work return a valid number for malformed
                  // data if there was a number followed by garbage. But it's just not
                  // worth all the extra code to detect that case.
                  const value = Number(json['value']);
                  if (isNaN(value)) {
                      throw new Error('Data cannot be decoded from JSON: ' + json);
                  }
                  return value;
              }
              default: {
                  throw new Error('Data cannot be decoded from JSON: ' + json);
              }
          }
      }
      if (Array.isArray(json)) {
          return json.map(x => decode(x));
      }
      if (typeof json === 'function' || typeof json === 'object') {
          return mapValues(json, x => decode(x));
      }
      // Anything else is safe to return.
      return json;
  }
  
  /**
   * @license
   * Copyright 2020 Google LLC
   *
   * 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.
   */
  /**
   * Type constant for Firebase Functions.
   */
  const FUNCTIONS_TYPE = 'functions';
  
  /**
   * @license
   * Copyright 2017 Google LLC
   *
   * 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.
   */
  /**
   * Standard error codes for different ways a request can fail, as defined by:
   * https://github.com/googleapis/googleapis/blob/master/google/rpc/code.proto
   *
   * This map is used primarily to convert from a backend error code string to
   * a client SDK error code string, and make sure it's in the supported set.
   */
  const errorCodeMap = {
      OK: 'ok',
      CANCELLED: 'cancelled',
      UNKNOWN: 'unknown',
      INVALID_ARGUMENT: 'invalid-argument',
      DEADLINE_EXCEEDED: 'deadline-exceeded',
      NOT_FOUND: 'not-found',
      ALREADY_EXISTS: 'already-exists',
      PERMISSION_DENIED: 'permission-denied',
      UNAUTHENTICATED: 'unauthenticated',
      RESOURCE_EXHAUSTED: 'resource-exhausted',
      FAILED_PRECONDITION: 'failed-precondition',
      ABORTED: 'aborted',
      OUT_OF_RANGE: 'out-of-range',
      UNIMPLEMENTED: 'unimplemented',
      INTERNAL: 'internal',
      UNAVAILABLE: 'unavailable',
      DATA_LOSS: 'data-loss'
  };
  /**
   * An explicit error that can be thrown from a handler to send an error to the
   * client that called the function.
   */
  class FunctionsError extends FirebaseError {
      constructor(
      /**
       * A standard error code that will be returned to the client. This also
       * determines the HTTP status code of the response, as defined in code.proto.
       */
      code, message, 
      /**
       * Extra data to be converted to JSON and included in the error response.
       */
      details) {
          super(`${FUNCTIONS_TYPE}/${code}`, message || '');
          this.details = details;
      }
  }
  /**
   * Takes an HTTP status code and returns the corresponding ErrorCode.
   * This is the standard HTTP status code -> error mapping defined in:
   * https://github.com/googleapis/googleapis/blob/master/google/rpc/code.proto
   *
   * @param status An HTTP status code.
   * @return The corresponding ErrorCode, or ErrorCode.UNKNOWN if none.
   */
  function codeForHTTPStatus(status) {
      // Make sure any successful status is OK.
      if (status >= 200 && status < 300) {
          return 'ok';
      }
      switch (status) {
          case 0:
              // This can happen if the server returns 500.
              return 'internal';
          case 400:
              return 'invalid-argument';
          case 401:
              return 'unauthenticated';
          case 403:
              return 'permission-denied';
          case 404:
              return 'not-found';
          case 409:
              return 'aborted';
          case 429:
              return 'resource-exhausted';
          case 499:
              return 'cancelled';
          case 500:
              return 'internal';
          case 501:
              return 'unimplemented';
          case 503:
              return 'unavailable';
          case 504:
              return 'deadline-exceeded';
      }
      return 'unknown';
  }
  /**
   * Takes an HTTP response and returns the corresponding Error, if any.
   */
  function _errorForResponse(status, bodyJSON) {
      let code = codeForHTTPStatus(status);
      // Start with reasonable defaults from the status code.
      let description = code;
      let details = undefined;
      // Then look through the body for explicit details.
      try {
          const errorJSON = bodyJSON && bodyJSON.error;
          if (errorJSON) {
              const status = errorJSON.status;
              if (typeof status === 'string') {
                  if (!errorCodeMap[status]) {
                      // They must've included an unknown error code in the body.
                      return new FunctionsError('internal', 'internal');
                  }
                  code = errorCodeMap[status];
                  // TODO(klimt): Add better default descriptions for error enums.
                  // The default description needs to be updated for the new code.
                  description = status;
              }
              const message = errorJSON.message;
              if (typeof message === 'string') {
                  description = message;
              }
              details = errorJSON.details;
              if (details !== undefined) {
                  details = decode(details);
              }
          }
      }
      catch (e) {
          // If we couldn't parse explicit error data, that's fine.
      }
      if (code === 'ok') {
          // Technically, there's an edge case where a developer could explicitly
          // return an error code of OK, and we will treat it as success, but that
          // seems reasonable.
          return null;
      }
      return new FunctionsError(code, description, details);
  }
  
  /**
   * @license
   * Copyright 2017 Google LLC
   *
   * 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.
   */
  /**
   * Helper class to get metadata that should be included with a function call.
   * @internal
   */
  class ContextProvider {
      constructor(authProvider, messagingProvider, appCheckProvider) {
          this.auth = null;
          this.messaging = null;
          this.appCheck = null;
          this.auth = authProvider.getImmediate({ optional: true });
          this.messaging = messagingProvider.getImmediate({
              optional: true
          });
          if (!this.auth) {
              authProvider.get().then(auth => (this.auth = auth), () => {
                  /* get() never rejects */
              });
          }
          if (!this.messaging) {
              messagingProvider.get().then(messaging => (this.messaging = messaging), () => {
                  /* get() never rejects */
              });
          }
          if (!this.appCheck) {
              appCheckProvider.get().then(appCheck => (this.appCheck = appCheck), () => {
                  /* get() never rejects */
              });
          }
      }
      async getAuthToken() {
          if (!this.auth) {
              return undefined;
          }
          try {
              const token = await this.auth.getToken();
              return token === null || token === void 0 ? void 0 : token.accessToken;
          }
          catch (e) {
              // If there's any error when trying to get the auth token, leave it off.
              return undefined;
          }
      }
      async getMessagingToken() {
          if (!this.messaging ||
              !('Notification' in self) ||
              Notification.permission !== 'granted') {
              return undefined;
          }
          try {
              return await this.messaging.getToken();
          }
          catch (e) {
              // We don't warn on this, because it usually means messaging isn't set up.
              // console.warn('Failed to retrieve instance id token.', e);
              // If there's any error when trying to get the token, leave it off.
              return undefined;
          }
      }
      async getAppCheckToken() {
          if (this.appCheck) {
              const result = await this.appCheck.getToken();
              if (result.error) {
                  // Do not send the App Check header to the functions endpoint if
                  // there was an error from the App Check exchange endpoint. The App
                  // Check SDK will already have logged the error to console.
                  return null;
              }
              return result.token;
          }
          return null;
      }
      async getContext() {
          const authToken = await this.getAuthToken();
          const messagingToken = await this.getMessagingToken();
          const appCheckToken = await this.getAppCheckToken();
          return { authToken, messagingToken, appCheckToken };
      }
  }
  
  /**
   * @license
   * Copyright 2017 Google LLC
   *
   * 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.
   */
  const DEFAULT_REGION = 'us-central1';
  /**
   * Returns a Promise that will be rejected after the given duration.
   * The error will be of type FunctionsError.
   *
   * @param millis Number of milliseconds to wait before rejecting.
   */
  function failAfter(millis) {
      return new Promise((_, reject) => {
          setTimeout(() => {
              reject(new FunctionsError('deadline-exceeded', 'deadline-exceeded'));
          }, millis);
      });
  }
  /**
   * The main class for the Firebase Functions SDK.
   * @internal
   */
  class FunctionsService {
      /**
       * Creates a new Functions service for the given app.
       * @param app - The FirebaseApp to use.
       */
      constructor(app, authProvider, messagingProvider, appCheckProvider, regionOrCustomDomain = DEFAULT_REGION, fetchImpl) {
          this.app = app;
          this.fetchImpl = fetchImpl;
          this.emulatorOrigin = null;
          this.contextProvider = new ContextProvider(authProvider, messagingProvider, appCheckProvider);
          // Cancels all ongoing requests when resolved.
          this.cancelAllRequests = new Promise(resolve => {
              this.deleteService = () => {
                  return Promise.resolve(resolve());
              };
          });
          // Resolve the region or custom domain overload by attempting to parse it.
          try {
              const url = new URL(regionOrCustomDomain);
              this.customDomain = url.origin;
              this.region = DEFAULT_REGION;
          }
          catch (e) {
              this.customDomain = null;
              this.region = regionOrCustomDomain;
          }
      }
      _delete() {
          return this.deleteService();
      }
      /**
       * Returns the URL for a callable with the given name.
       * @param name - The name of the callable.
       * @internal
       */
      _url(name) {
          const projectId = this.app.options.projectId;
          if (this.emulatorOrigin !== null) {
              const origin = this.emulatorOrigin;
              return `${origin}/${projectId}/${this.region}/${name}`;
          }
          if (this.customDomain !== null) {
              return `${this.customDomain}/${name}`;
          }
          return `https://${this.region}-${projectId}.cloudfunctions.net/${name}`;
      }
  }
  /**
   * Modify this instance to communicate with the Cloud Functions emulator.
   *
   * Note: this must be called before this instance has been used to do any operations.
   *
   * @param host The emulator host (ex: localhost)
   * @param port The emulator port (ex: 5001)
   * @public
   */
  function connectFunctionsEmulator$1(functionsInstance, host, port) {
      functionsInstance.emulatorOrigin = `http://${host}:${port}`;
  }
  /**
   * Returns a reference to the callable https trigger with the given name.
   * @param name - The name of the trigger.
   * @public
   */
  function httpsCallable$1(functionsInstance, name, options) {
      return (data => {
          return call(functionsInstance, name, data, options || {});
      });
  }
  /**
   * Does an HTTP POST and returns the completed response.
   * @param url The url to post to.
   * @param body The JSON body of the post.
   * @param headers The HTTP headers to include in the request.
   * @return A Promise that will succeed when the request finishes.
   */
  async function postJSON(url, body, headers, fetchImpl) {
      headers['Content-Type'] = 'application/json';
      let response;
      try {
          response = await fetchImpl(url, {
              method: 'POST',
              body: JSON.stringify(body),
              headers
          });
      }
      catch (e) {
          // This could be an unhandled error on the backend, or it could be a
          // network error. There's no way to know, since an unhandled error on the
          // backend will fail to set the proper CORS header, and thus will be
          // treated as a network error by fetch.
          return {
              status: 0,
              json: null
          };
      }
      let json = null;
      try {
          json = await response.json();
      }
      catch (e) {
          // If we fail to parse JSON, it will fail the same as an empty body.
      }
      return {
          status: response.status,
          json
      };
  }
  /**
   * Calls a callable function asynchronously and returns the result.
   * @param name The name of the callable trigger.
   * @param data The data to pass as params to the function.s
   */
  async function call(functionsInstance, name, data, options) {
      const url = functionsInstance._url(name);
      // Encode any special types, such as dates, in the input data.
      data = encode(data);
      const body = { data };
      // Add a header for the authToken.
      const headers = {};
      const context = await functionsInstance.contextProvider.getContext();
      if (context.authToken) {
          headers['Authorization'] = 'Bearer ' + context.authToken;
      }
      if (context.messagingToken) {
          headers['Firebase-Instance-ID-Token'] = context.messagingToken;
      }
      if (context.appCheckToken !== null) {
          headers['X-Firebase-AppCheck'] = context.appCheckToken;
      }
      // Default timeout to 70s, but let the options override it.
      const timeout = options.timeout || 70000;
      const response = await Promise.race([
          postJSON(url, body, headers, functionsInstance.fetchImpl),
          failAfter(timeout),
          functionsInstance.cancelAllRequests
      ]);
      // If service was deleted, interrupted response throws an error.
      if (!response) {
          throw new FunctionsError('cancelled', 'Firebase Functions instance was deleted.');
      }
      // Check for an error status, regardless of http status.
      const error = _errorForResponse(response.status, response.json);
      if (error) {
          throw error;
      }
      if (!response.json) {
          throw new FunctionsError('internal', 'Response is not valid JSON object.');
      }
      let responseData = response.json.data;
      // TODO(klimt): For right now, allow "result" instead of "data", for
      // backwards compatibility.
      if (typeof responseData === 'undefined') {
          responseData = response.json.result;
      }
      if (typeof responseData === 'undefined') {
          // Consider the response malformed.
          throw new FunctionsError('internal', 'Response is missing data field.');
      }
      // Decode any special types, such as dates, in the returned data.
      const decodedData = decode(responseData);
      return { data: decodedData };
  }
  
  /**
   * @license
   * Copyright 2019 Google LLC
   *
   * 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.
   */
  const AUTH_INTERNAL_NAME = 'auth-internal';
  const APP_CHECK_INTERNAL_NAME = 'app-check-internal';
  const MESSAGING_INTERNAL_NAME = 'messaging-internal';
  function registerFunctions(fetchImpl) {
      const factory = (container, { instanceIdentifier: regionOrCustomDomain }) => {
          // Dependencies
          const app = container.getProvider('app').getImmediate();
          const authProvider = container.getProvider(AUTH_INTERNAL_NAME);
          const messagingProvider = container.getProvider(MESSAGING_INTERNAL_NAME);
          const appCheckProvider = container.getProvider(APP_CHECK_INTERNAL_NAME);
          // eslint-disable-next-line @typescript-eslint/no-explicit-any
          return new FunctionsService(app, authProvider, messagingProvider, appCheckProvider, regionOrCustomDomain, fetchImpl);
      };
      _registerComponent(new Component(FUNCTIONS_TYPE, factory, "PUBLIC" /* PUBLIC */).setMultipleInstances(true));
  }
  
  const name = "@firebase/functions";
  const version = "0.7.1";
  
  /**
   * @license
   * Copyright 2020 Google LLC
   *
   * 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.
   */
  /**
   * Returns a {@link Functions} instance for the given app.
   * @param app - The {@link @firebase/app#FirebaseApp} to use.
   * @param regionOrCustomDomain - one of:
   *   a) The region the callable functions are located in (ex: us-central1)
   *   b) A custom domain hosting the callable functions (ex: https://mydomain.com)
   * @public
   */
  function getFunctions(app = getApp(), regionOrCustomDomain = DEFAULT_REGION) {
      // Dependencies
      const functionsProvider = _getProvider(getModularInstance(app), FUNCTIONS_TYPE);
      const functionsInstance = functionsProvider.getImmediate({
          identifier: regionOrCustomDomain
      });
      return functionsInstance;
  }
  /**
   * Modify this instance to communicate with the Cloud Functions emulator.
   *
   * Note: this must be called before this instance has been used to do any operations.
   *
   * @param host - The emulator host (ex: localhost)
   * @param port - The emulator port (ex: 5001)
   * @public
   */
  function connectFunctionsEmulator(functionsInstance, host, port) {
      connectFunctionsEmulator$1(getModularInstance(functionsInstance), host, port);
  }
  /**
   * Returns a reference to the callable HTTPS trigger with the given name.
   * @param name - The name of the trigger.
   * @public
   */
  function httpsCallable(functionsInstance, name, options) {
      return httpsCallable$1(getModularInstance(functionsInstance), name, options);
  }
  
  /**
   * Cloud Functions for Firebase
   *
   * @packageDocumentation
   */
  registerFunctions(fetch.bind(self));
  registerVersion(name, version);
  
  export { connectFunctionsEmulator, getFunctions, httpsCallable };
  //# sourceMappingURL=index.esm2017.js.map
  