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;
}