UNPKG

11.5 kBJavaScriptView Raw
1"use strict";
2// The MIT License (MIT)
3//
4// Copyright (c) 2017 Firebase
5//
6// Permission is hereby granted, free of charge, to any person obtaining a copy
7// of this software and associated documentation files (the "Software"), to deal
8// in the Software without restriction, including without limitation the rights
9// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10// copies of the Software, and to permit persons to whom the Software is
11// furnished to do so, subject to the following conditions:
12//
13// The above copyright notice and this permission notice shall be included in all
14// copies or substantial portions of the Software.
15//
16// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22// SOFTWARE.
23Object.defineProperty(exports, "__esModule", { value: true });
24exports.optionsToEndpoint = exports.optionsToTrigger = exports.makeCloudFunction = exports.Change = void 0;
25const logger_1 = require("../logger");
26const function_configuration_1 = require("./function-configuration");
27const encoding_1 = require("../common/encoding");
28const manifest_1 = require("../runtime/manifest");
29const options_1 = require("../common/options");
30const types_1 = require("../params/types");
31const onInit_1 = require("../common/onInit");
32var change_1 = require("../common/change");
33Object.defineProperty(exports, "Change", { enumerable: true, get: function () { return change_1.Change; } });
34/** @internal */
35const WILDCARD_REGEX = new RegExp("{[^/{}]*}", "g");
36/** @internal */
37function makeCloudFunction({ contextOnlyHandler, dataConstructor = (raw) => raw.data, eventType, handler, labels = {}, legacyEventType, options = {}, provider, service, triggerResource, }) {
38 handler = (0, onInit_1.withInit)(handler !== null && handler !== void 0 ? handler : contextOnlyHandler);
39 const cloudFunction = (data, context) => {
40 if (legacyEventType && context.eventType === legacyEventType) {
41 /*
42 * v1beta1 event flow has different format for context, transform them to
43 * new format.
44 */
45 context.eventType = provider + "." + eventType;
46 context.resource = {
47 service,
48 name: context.resource,
49 };
50 }
51 const event = {
52 data,
53 context,
54 };
55 if (provider === "google.firebase.database") {
56 context.authType = _detectAuthType(event);
57 if (context.authType !== "ADMIN") {
58 context.auth = _makeAuth(event, context.authType);
59 }
60 else {
61 delete context.auth;
62 }
63 }
64 if (triggerResource() == null) {
65 Object.defineProperty(context, "params", {
66 get: () => {
67 throw new Error("context.params is not available when using the handler namespace.");
68 },
69 });
70 }
71 else {
72 context.params = context.params || _makeParams(context, triggerResource);
73 }
74 let promise;
75 if (labels && labels["deployment-scheduled"]) {
76 // Scheduled function do not have meaningful data, so exclude it
77 promise = contextOnlyHandler(context);
78 }
79 else {
80 const dataOrChange = dataConstructor(event);
81 promise = handler(dataOrChange, context);
82 }
83 if (typeof promise === "undefined") {
84 (0, logger_1.warn)("Function returned undefined, expected Promise or value");
85 }
86 return Promise.resolve(promise);
87 };
88 Object.defineProperty(cloudFunction, "__trigger", {
89 get: () => {
90 if (triggerResource() == null) {
91 return {};
92 }
93 const trigger = {
94 ...optionsToTrigger(options),
95 eventTrigger: {
96 resource: triggerResource(),
97 eventType: legacyEventType || provider + "." + eventType,
98 service,
99 },
100 };
101 if (!!labels && Object.keys(labels).length) {
102 trigger.labels = { ...trigger.labels, ...labels };
103 }
104 return trigger;
105 },
106 });
107 Object.defineProperty(cloudFunction, "__endpoint", {
108 get: () => {
109 if (triggerResource() == null) {
110 return undefined;
111 }
112 const endpoint = {
113 platform: "gcfv1",
114 ...(0, manifest_1.initV1Endpoint)(options),
115 ...optionsToEndpoint(options),
116 };
117 if (options.schedule) {
118 endpoint.scheduleTrigger = (0, manifest_1.initV1ScheduleTrigger)(options.schedule.schedule, options);
119 (0, encoding_1.copyIfPresent)(endpoint.scheduleTrigger, options.schedule, "timeZone");
120 (0, encoding_1.copyIfPresent)(endpoint.scheduleTrigger.retryConfig, options.schedule.retryConfig, "retryCount", "maxDoublings", "maxBackoffDuration", "maxRetryDuration", "minBackoffDuration");
121 }
122 else {
123 endpoint.eventTrigger = {
124 eventType: legacyEventType || provider + "." + eventType,
125 eventFilters: {
126 resource: triggerResource(),
127 },
128 retry: !!options.failurePolicy,
129 };
130 }
131 // Note: We intentionally don't make use of labels args here.
132 // labels is used to pass SDK-defined labels to the trigger, which isn't
133 // something we will do in the container contract world.
134 endpoint.labels = { ...endpoint.labels };
135 return endpoint;
136 },
137 });
138 if (options.schedule) {
139 cloudFunction.__requiredAPIs = [
140 {
141 api: "cloudscheduler.googleapis.com",
142 reason: "Needed for scheduled functions.",
143 },
144 ];
145 }
146 cloudFunction.run = handler || contextOnlyHandler;
147 return cloudFunction;
148}
149exports.makeCloudFunction = makeCloudFunction;
150function _makeParams(context, triggerResourceGetter) {
151 var _a, _b, _c;
152 if (context.params) {
153 // In unit testing, user may directly provide `context.params`.
154 return context.params;
155 }
156 if (!context.resource) {
157 // In unit testing, `resource` may be unpopulated for a test event.
158 return {};
159 }
160 const triggerResource = triggerResourceGetter();
161 const wildcards = triggerResource.match(WILDCARD_REGEX);
162 const params = {};
163 // Note: some tests don't set context.resource.name
164 const eventResourceParts = (_c = (_b = (_a = context === null || context === void 0 ? void 0 : context.resource) === null || _a === void 0 ? void 0 : _a.name) === null || _b === void 0 ? void 0 : _b.split) === null || _c === void 0 ? void 0 : _c.call(_b, "/");
165 if (wildcards && eventResourceParts) {
166 const triggerResourceParts = triggerResource.split("/");
167 for (const wildcard of wildcards) {
168 const wildcardNoBraces = wildcard.slice(1, -1);
169 const position = triggerResourceParts.indexOf(wildcard);
170 params[wildcardNoBraces] = eventResourceParts[position];
171 }
172 }
173 return params;
174}
175function _makeAuth(event, authType) {
176 var _a, _b, _c, _d, _e, _f;
177 if (authType === "UNAUTHENTICATED") {
178 return null;
179 }
180 return {
181 uid: (_c = (_b = (_a = event.context) === null || _a === void 0 ? void 0 : _a.auth) === null || _b === void 0 ? void 0 : _b.variable) === null || _c === void 0 ? void 0 : _c.uid,
182 token: (_f = (_e = (_d = event.context) === null || _d === void 0 ? void 0 : _d.auth) === null || _e === void 0 ? void 0 : _e.variable) === null || _f === void 0 ? void 0 : _f.token,
183 };
184}
185function _detectAuthType(event) {
186 var _a, _b, _c, _d;
187 if ((_b = (_a = event.context) === null || _a === void 0 ? void 0 : _a.auth) === null || _b === void 0 ? void 0 : _b.admin) {
188 return "ADMIN";
189 }
190 if ((_d = (_c = event.context) === null || _c === void 0 ? void 0 : _c.auth) === null || _d === void 0 ? void 0 : _d.variable) {
191 return "USER";
192 }
193 return "UNAUTHENTICATED";
194}
195/** @hidden */
196function optionsToTrigger(options) {
197 const trigger = {};
198 (0, encoding_1.copyIfPresent)(trigger, options, "regions", "schedule", "minInstances", "maxInstances", "ingressSettings", "vpcConnectorEgressSettings", "vpcConnector", "labels", "secrets");
199 (0, encoding_1.convertIfPresent)(trigger, options, "failurePolicy", "failurePolicy", (policy) => {
200 if (policy === false) {
201 return undefined;
202 }
203 else if (policy === true) {
204 return function_configuration_1.DEFAULT_FAILURE_POLICY;
205 }
206 else {
207 return policy;
208 }
209 });
210 (0, encoding_1.convertIfPresent)(trigger, options, "timeout", "timeoutSeconds", encoding_1.durationFromSeconds);
211 (0, encoding_1.convertIfPresent)(trigger, options, "availableMemoryMb", "memory", (mem) => {
212 const memoryLookup = {
213 "128MB": 128,
214 "256MB": 256,
215 "512MB": 512,
216 "1GB": 1024,
217 "2GB": 2048,
218 "4GB": 4096,
219 "8GB": 8192,
220 };
221 return memoryLookup[mem];
222 });
223 (0, encoding_1.convertIfPresent)(trigger, options, "serviceAccountEmail", "serviceAccount", encoding_1.serviceAccountFromShorthand);
224 return trigger;
225}
226exports.optionsToTrigger = optionsToTrigger;
227function optionsToEndpoint(options) {
228 const endpoint = {};
229 (0, encoding_1.copyIfPresent)(endpoint, options, "omit", "minInstances", "maxInstances", "ingressSettings", "labels", "timeoutSeconds");
230 (0, encoding_1.convertIfPresent)(endpoint, options, "region", "regions");
231 (0, encoding_1.convertIfPresent)(endpoint, options, "serviceAccountEmail", "serviceAccount", (sa) => sa);
232 (0, encoding_1.convertIfPresent)(endpoint, options, "secretEnvironmentVariables", "secrets", (secrets) => secrets.map((secret) => ({ key: secret instanceof types_1.SecretParam ? secret.name : secret })));
233 if ((options === null || options === void 0 ? void 0 : options.vpcConnector) !== undefined) {
234 if (options.vpcConnector === null || options.vpcConnector instanceof options_1.ResetValue) {
235 endpoint.vpc = function_configuration_1.RESET_VALUE;
236 }
237 else {
238 const vpc = { connector: options.vpcConnector };
239 (0, encoding_1.convertIfPresent)(vpc, options, "egressSettings", "vpcConnectorEgressSettings");
240 endpoint.vpc = vpc;
241 }
242 }
243 (0, encoding_1.convertIfPresent)(endpoint, options, "availableMemoryMb", "memory", (mem) => {
244 const memoryLookup = {
245 "128MB": 128,
246 "256MB": 256,
247 "512MB": 512,
248 "1GB": 1024,
249 "2GB": 2048,
250 "4GB": 4096,
251 "8GB": 8192,
252 };
253 return typeof mem === "object" ? mem : memoryLookup[mem];
254 });
255 return endpoint;
256}
257exports.optionsToEndpoint = optionsToEndpoint;