export function makeCloudFunction()

in src/cloud-functions.ts [350:490]


export function makeCloudFunction<EventData>({
  after = () => {},
  before = () => {},
  contextOnlyHandler,
  dataConstructor = (raw: Event) => raw.data,
  eventType,
  handler,
  labels = {},
  legacyEventType,
  options = {},
  provider,
  service,
  triggerResource,
}: MakeCloudFunctionArgs<EventData>): CloudFunction<EventData> {
  const cloudFunction: any = (data: any, context: any) => {
    if (legacyEventType && context.eventType === legacyEventType) {
      /*
       * v1beta1 event flow has different format for context, transform them to
       * new format.
       */
      context.eventType = provider + '.' + eventType;
      context.resource = {
        service,
        name: context.resource,
      };
    }

    const event: Event = {
      data,
      context,
    };

    if (provider === 'google.firebase.database') {
      context.authType = _detectAuthType(event);
      if (context.authType !== 'ADMIN') {
        context.auth = _makeAuth(event, context.authType);
      } else {
        delete context.auth;
      }
    }

    if (triggerResource() == null) {
      Object.defineProperty(context, 'params', {
        get: () => {
          throw new Error(
            'context.params is not available when using the handler namespace.'
          );
        },
      });
    } else {
      context.params = context.params || _makeParams(context, triggerResource);
    }

    before(event);

    let promise;
    if (labels && labels['deployment-scheduled']) {
      // Scheduled function do not have meaningful data, so exclude it
      promise = contextOnlyHandler(context);
    } else {
      const dataOrChange = dataConstructor(event);
      promise = handler(dataOrChange, context);
    }
    if (typeof promise === 'undefined') {
      warn('Function returned undefined, expected Promise or value');
    }
    return Promise.resolve(promise)
      .then((result) => {
        after(event);
        return result;
      })
      .catch((err) => {
        after(event);
        return Promise.reject(err);
      });
  };

  Object.defineProperty(cloudFunction, '__trigger', {
    get: () => {
      if (triggerResource() == null) {
        return {};
      }

      const trigger: any = _.assign(optionsToTrigger(options), {
        eventTrigger: {
          resource: triggerResource(),
          eventType: legacyEventType || provider + '.' + eventType,
          service,
        },
      });
      if (!_.isEmpty(labels)) {
        trigger.labels = { ...trigger.labels, ...labels };
      }
      return trigger;
    },
  });

  Object.defineProperty(cloudFunction, '__endpoint', {
    get: () => {
      if (triggerResource() == null) {
        return undefined;
      }

      const endpoint: ManifestEndpoint = {
        platform: 'gcfv1',
        ...optionsToEndpoint(options),
      };

      if (options.schedule) {
        endpoint.scheduleTrigger = options.schedule;
      } else {
        endpoint.eventTrigger = {
          eventType: legacyEventType || provider + '.' + eventType,
          eventFilters: {
            resource: triggerResource(),
          },
          retry: !!options.failurePolicy,
        };
      }

      // Note: We intentionally don't make use of labels args here.
      // labels is used to pass SDK-defined labels to the trigger, which isn't
      // something we will do in the container contract world.
      endpoint.labels = { ...endpoint.labels };

      return endpoint;
    },
  });

  if (options.schedule) {
    cloudFunction.__requiredAPIs = [
      {
        api: 'cloudscheduler.googleapis.com',
        reason: 'Needed for scheduled functions.',
      },
    ];
  }

  cloudFunction.run = handler || contextOnlyHandler;
  return cloudFunction;
}