firebase-tools 9.18.0 → 9.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +3 -6
- package/lib/api.js +3 -0
- package/lib/apiv2.js +8 -5
- package/lib/command.js +1 -1
- package/lib/commands/crashlytics-symbols-upload.js +146 -0
- package/lib/commands/deploy.js +9 -1
- package/lib/commands/ext-configure.js +9 -2
- package/lib/commands/ext-dev-deprecate.js +63 -0
- package/lib/commands/ext-dev-extension-delete.js +2 -1
- package/lib/commands/ext-dev-publish.js +10 -4
- package/lib/commands/ext-dev-undeprecate.js +56 -0
- package/lib/commands/ext-dev-unpublish.js +12 -4
- package/lib/commands/ext-export.js +44 -0
- package/lib/commands/ext-install.js +50 -13
- package/lib/commands/ext-uninstall.js +6 -0
- package/lib/commands/ext-update.js +60 -18
- package/lib/commands/functions-config-export.js +115 -0
- package/lib/commands/functions-delete.js +47 -25
- package/lib/commands/functions-list.js +12 -12
- package/lib/commands/index.js +9 -0
- package/lib/commands/init.js +3 -0
- package/lib/config.js +3 -2
- package/lib/deploy/extensions/args.js +2 -0
- package/lib/deploy/extensions/deploy.js +49 -0
- package/lib/deploy/extensions/deploymentSummary.js +52 -0
- package/lib/deploy/extensions/errors.js +31 -0
- package/lib/deploy/extensions/index.js +8 -0
- package/lib/deploy/extensions/planner.js +95 -0
- package/lib/deploy/extensions/prepare.js +103 -0
- package/lib/deploy/extensions/release.js +43 -0
- package/lib/deploy/extensions/secrets.js +150 -0
- package/lib/deploy/extensions/tasks.js +98 -0
- package/lib/deploy/extensions/validate.js +17 -0
- package/lib/deploy/functions/backend.js +93 -115
- package/lib/deploy/functions/checkIam.js +8 -8
- package/lib/deploy/functions/containerCleaner.js +82 -22
- package/lib/deploy/functions/deploy.js +4 -10
- package/lib/deploy/functions/functionsDeployHelper.js +3 -68
- package/lib/deploy/functions/prepare.js +62 -27
- package/lib/deploy/functions/pricing.js +17 -17
- package/lib/deploy/functions/prompts.js +22 -21
- package/lib/deploy/functions/release/executor.js +39 -0
- package/lib/deploy/functions/release/fabricator.js +422 -0
- package/lib/deploy/functions/release/index.js +73 -0
- package/lib/deploy/functions/release/planner.js +162 -0
- package/lib/deploy/functions/release/reporter.js +165 -0
- package/lib/deploy/functions/release/sourceTokenScraper.js +28 -0
- package/lib/deploy/functions/release/timer.js +14 -0
- package/lib/deploy/functions/runtimes/discovery/v1alpha1.js +129 -126
- package/lib/deploy/functions/runtimes/node/parseTriggers.js +41 -45
- package/lib/deploy/functions/triggerRegionHelper.js +40 -0
- package/lib/deploy/functions/validate.js +1 -24
- package/lib/deploy/index.js +1 -0
- package/lib/downloadUtils.js +37 -0
- package/lib/emulator/auth/apiSpec.js +1788 -403
- package/lib/emulator/auth/handlers.js +6 -5
- package/lib/emulator/auth/operations.js +439 -40
- package/lib/emulator/auth/server.js +32 -11
- package/lib/emulator/auth/state.js +205 -5
- package/lib/emulator/auth/widget_ui.js +2 -2
- package/lib/emulator/download.js +2 -31
- package/lib/emulator/downloadableEmulators.js +7 -7
- package/lib/emulator/emulatorLogger.js +0 -3
- package/lib/emulator/events/types.js +16 -0
- package/lib/emulator/functionsEmulator.js +120 -21
- package/lib/emulator/functionsEmulatorRuntime.js +46 -121
- package/lib/emulator/functionsEmulatorShared.js +51 -7
- package/lib/emulator/functionsEmulatorShell.js +1 -1
- package/lib/emulator/pubsubEmulator.js +61 -40
- package/lib/emulator/storage/cloudFunctions.js +37 -7
- package/lib/extensions/askUserForConsent.js +14 -1
- package/lib/extensions/askUserForParam.js +81 -4
- package/lib/extensions/billingMigrationHelper.js +1 -11
- package/lib/extensions/changelog.js +2 -1
- package/lib/extensions/checkProjectBilling.js +7 -7
- package/lib/extensions/displayExtensionInfo.js +35 -33
- package/lib/extensions/emulator/optionsHelper.js +3 -3
- package/lib/extensions/emulator/triggerHelper.js +2 -32
- package/lib/extensions/export.js +107 -0
- package/lib/extensions/extensionsApi.js +149 -97
- package/lib/extensions/extensionsHelper.js +36 -32
- package/lib/extensions/listExtensions.js +16 -11
- package/lib/extensions/paramHelper.js +73 -40
- package/lib/extensions/provisioningHelper.js +16 -3
- package/lib/extensions/refs.js +67 -0
- package/lib/extensions/secretsUtils.js +59 -0
- package/lib/extensions/updateHelper.js +33 -47
- package/lib/extensions/versionHelper.js +14 -0
- package/lib/extensions/warnings.js +33 -1
- package/lib/functional.js +64 -0
- package/lib/functions/env.js +26 -13
- package/lib/functions/runtimeConfigExport.js +137 -0
- package/lib/gcp/artifactregistry.js +16 -0
- package/lib/gcp/cloudfunctions.js +65 -35
- package/lib/gcp/cloudfunctionsv2.js +56 -43
- package/lib/gcp/cloudscheduler.js +22 -16
- package/lib/gcp/cloudtasks.js +143 -0
- package/lib/gcp/docker.js +7 -1
- package/lib/gcp/proto.js +2 -2
- package/lib/gcp/pubsub.js +1 -9
- package/lib/gcp/secretManager.js +132 -0
- package/lib/gcp/storage.js +16 -0
- package/lib/previews.js +1 -1
- package/lib/requireInteractive.js +12 -0
- package/lib/utils.js +30 -1
- package/package.json +6 -4
- package/schema/firebase-config.json +9 -0
- package/lib/deploy/functions/deploymentPlanner.js +0 -113
- package/lib/deploy/functions/deploymentTimer.js +0 -23
- package/lib/deploy/functions/errorHandler.js +0 -75
- package/lib/deploy/functions/release.js +0 -116
- package/lib/deploy/functions/tasks.js +0 -324
- package/lib/functions/listFunctions.js +0 -10
- package/lib/functionsDelete.js +0 -60
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.functionFromEndpoint = exports.endpointFromFunction = exports.listAllFunctions = exports.listFunctions = exports.deleteFunction = exports.updateFunction = exports.setInvokerUpdate = exports.setInvokerCreate = exports.getIamPolicy = exports.setIamPolicy = exports.createFunction = exports.generateUploadUrl = exports.API_VERSION = void 0;
|
|
4
4
|
const clc = require("cli-color");
|
|
5
5
|
const error_1 = require("../error");
|
|
6
6
|
const logger_1 = require("../logger");
|
|
7
|
+
const previews_1 = require("../previews");
|
|
7
8
|
const api = require("../api");
|
|
8
9
|
const backend = require("../deploy/functions/backend");
|
|
9
10
|
const utils = require("../utils");
|
|
@@ -50,7 +51,11 @@ async function createFunction(cloudFunction) {
|
|
|
50
51
|
const apiPath = cloudFunction.name.substring(0, cloudFunction.name.lastIndexOf("/"));
|
|
51
52
|
const endpoint = `/${exports.API_VERSION}/${apiPath}`;
|
|
52
53
|
try {
|
|
54
|
+
const headers = previews_1.previews.artifactregistry
|
|
55
|
+
? { "X-Firebase-Artifact-Registry": "optin" }
|
|
56
|
+
: undefined;
|
|
53
57
|
const res = await api.request("POST", endpoint, {
|
|
58
|
+
headers,
|
|
54
59
|
auth: true,
|
|
55
60
|
data: cloudFunction,
|
|
56
61
|
origin: api.functionsOrigin,
|
|
@@ -145,7 +150,11 @@ async function updateFunction(cloudFunction) {
|
|
|
145
150
|
const endpoint = `/${exports.API_VERSION}/${cloudFunction.name}`;
|
|
146
151
|
const fieldMasks = proto.fieldMasks(cloudFunction, "labels", "environmentVariables");
|
|
147
152
|
try {
|
|
153
|
+
const headers = previews_1.previews.artifactregistry
|
|
154
|
+
? { "X-Firebase-Artifact-Registry": "optin" }
|
|
155
|
+
: undefined;
|
|
148
156
|
const res = await api.request("PATCH", endpoint, {
|
|
157
|
+
headers,
|
|
149
158
|
qs: {
|
|
150
159
|
updateMask: fieldMasks.join(","),
|
|
151
160
|
},
|
|
@@ -198,9 +207,11 @@ async function list(projectId, region) {
|
|
|
198
207
|
};
|
|
199
208
|
}
|
|
200
209
|
catch (err) {
|
|
201
|
-
logger_1.logger.debug(
|
|
210
|
+
logger_1.logger.debug(`[functions] failed to list functions for ${projectId}`);
|
|
202
211
|
logger_1.logger.debug(`[functions] ${err === null || err === void 0 ? void 0 : err.message}`);
|
|
203
|
-
|
|
212
|
+
throw new error_1.FirebaseError(`Failed to list functions for ${projectId}`, {
|
|
213
|
+
original: err,
|
|
214
|
+
});
|
|
204
215
|
}
|
|
205
216
|
}
|
|
206
217
|
async function listFunctions(projectId, region) {
|
|
@@ -212,70 +223,89 @@ async function listAllFunctions(projectId) {
|
|
|
212
223
|
return list(projectId, "-");
|
|
213
224
|
}
|
|
214
225
|
exports.listAllFunctions = listAllFunctions;
|
|
215
|
-
function
|
|
216
|
-
var _a;
|
|
226
|
+
function endpointFromFunction(gcfFunction) {
|
|
227
|
+
var _a, _b, _c;
|
|
217
228
|
const [, project, , region, , id] = gcfFunction.name.split("/");
|
|
218
229
|
let trigger;
|
|
219
230
|
let uri;
|
|
220
|
-
if (gcfFunction.
|
|
221
|
-
trigger = {
|
|
231
|
+
if ((_a = gcfFunction.labels) === null || _a === void 0 ? void 0 : _a["deployment-scheduled"]) {
|
|
232
|
+
trigger = {
|
|
233
|
+
scheduleTrigger: {},
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
else if ((_b = gcfFunction.labels) === null || _b === void 0 ? void 0 : _b["deployment-taskqueue"]) {
|
|
237
|
+
trigger = {
|
|
238
|
+
taskQueueTrigger: {},
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
else if (gcfFunction.httpsTrigger) {
|
|
242
|
+
trigger = { httpsTrigger: {} };
|
|
222
243
|
uri = gcfFunction.httpsTrigger.url;
|
|
223
244
|
}
|
|
224
245
|
else {
|
|
225
246
|
trigger = {
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
247
|
+
eventTrigger: {
|
|
248
|
+
eventType: gcfFunction.eventTrigger.eventType,
|
|
249
|
+
eventFilters: {
|
|
250
|
+
resource: gcfFunction.eventTrigger.resource,
|
|
251
|
+
},
|
|
252
|
+
retry: !!((_c = gcfFunction.eventTrigger.failurePolicy) === null || _c === void 0 ? void 0 : _c.retry),
|
|
229
253
|
},
|
|
230
|
-
retry: !!((_a = gcfFunction.eventTrigger.failurePolicy) === null || _a === void 0 ? void 0 : _a.retry),
|
|
231
254
|
};
|
|
232
255
|
}
|
|
233
256
|
if (!runtimes.isValidRuntime(gcfFunction.runtime)) {
|
|
234
257
|
logger_1.logger.debug("GCFv1 function has a deprecated runtime:", JSON.stringify(gcfFunction, null, 2));
|
|
235
258
|
}
|
|
236
|
-
const
|
|
237
|
-
platform: "gcfv1",
|
|
238
|
-
id,
|
|
259
|
+
const endpoint = Object.assign(Object.assign({ platform: "gcfv1", id,
|
|
239
260
|
project,
|
|
240
|
-
region,
|
|
241
|
-
trigger,
|
|
242
|
-
entryPoint: gcfFunction.entryPoint,
|
|
243
|
-
runtime: gcfFunction.runtime,
|
|
244
|
-
};
|
|
261
|
+
region }, trigger), { entryPoint: gcfFunction.entryPoint, runtime: gcfFunction.runtime });
|
|
245
262
|
if (uri) {
|
|
246
|
-
|
|
263
|
+
endpoint.uri = uri;
|
|
247
264
|
}
|
|
248
|
-
proto.copyIfPresent(
|
|
249
|
-
return
|
|
265
|
+
proto.copyIfPresent(endpoint, gcfFunction, "serviceAccountEmail", "availableMemoryMb", "timeout", "minInstances", "maxInstances", "vpcConnector", "vpcConnectorEgressSettings", "ingressSettings", "labels", "environmentVariables", "sourceUploadUrl");
|
|
266
|
+
return endpoint;
|
|
250
267
|
}
|
|
251
|
-
exports.
|
|
252
|
-
function
|
|
253
|
-
if (
|
|
268
|
+
exports.endpointFromFunction = endpointFromFunction;
|
|
269
|
+
function functionFromEndpoint(endpoint, sourceUploadUrl) {
|
|
270
|
+
if (endpoint.platform != "gcfv1") {
|
|
254
271
|
throw new error_1.FirebaseError("Trying to create a v1 CloudFunction with v2 API. This should never happen");
|
|
255
272
|
}
|
|
256
|
-
if (!runtimes.isValidRuntime(
|
|
273
|
+
if (!runtimes.isValidRuntime(endpoint.runtime)) {
|
|
257
274
|
throw new error_1.FirebaseError("Failed internal assertion. Trying to deploy a new function with a deprecated runtime." +
|
|
258
275
|
" This should never happen");
|
|
259
276
|
}
|
|
260
277
|
const gcfFunction = {
|
|
261
|
-
name: backend.functionName(
|
|
278
|
+
name: backend.functionName(endpoint),
|
|
262
279
|
sourceUploadUrl: sourceUploadUrl,
|
|
263
|
-
entryPoint:
|
|
264
|
-
runtime:
|
|
280
|
+
entryPoint: endpoint.entryPoint,
|
|
281
|
+
runtime: endpoint.runtime,
|
|
265
282
|
};
|
|
266
|
-
|
|
283
|
+
proto.copyIfPresent(gcfFunction, endpoint, "labels");
|
|
284
|
+
if (backend.isEventTriggered(endpoint)) {
|
|
267
285
|
gcfFunction.eventTrigger = {
|
|
268
|
-
eventType:
|
|
269
|
-
resource:
|
|
286
|
+
eventType: endpoint.eventTrigger.eventType,
|
|
287
|
+
resource: endpoint.eventTrigger.eventFilters.resource,
|
|
270
288
|
};
|
|
271
|
-
gcfFunction.eventTrigger.failurePolicy =
|
|
289
|
+
gcfFunction.eventTrigger.failurePolicy = endpoint.eventTrigger.retry
|
|
272
290
|
? { retry: {} }
|
|
273
291
|
: undefined;
|
|
274
292
|
}
|
|
293
|
+
else if (backend.isScheduleTriggered(endpoint)) {
|
|
294
|
+
const id = backend.scheduleIdForFunction(endpoint);
|
|
295
|
+
gcfFunction.eventTrigger = {
|
|
296
|
+
eventType: "google.pubsub.topic.publish",
|
|
297
|
+
resource: `projects/${endpoint.project}/topics/${id}`,
|
|
298
|
+
};
|
|
299
|
+
gcfFunction.labels = Object.assign(Object.assign({}, gcfFunction.labels), { "deployment-scheduled": "true" });
|
|
300
|
+
}
|
|
301
|
+
else if (backend.isTaskQueueTriggered(endpoint)) {
|
|
302
|
+
gcfFunction.httpsTrigger = {};
|
|
303
|
+
gcfFunction.labels = Object.assign(Object.assign({}, gcfFunction.labels), { "deployment-taskqueue": "true" });
|
|
304
|
+
}
|
|
275
305
|
else {
|
|
276
306
|
gcfFunction.httpsTrigger = {};
|
|
277
307
|
}
|
|
278
|
-
proto.copyIfPresent(gcfFunction,
|
|
308
|
+
proto.copyIfPresent(gcfFunction, endpoint, "serviceAccountEmail", "timeout", "availableMemoryMb", "minInstances", "maxInstances", "vpcConnector", "vpcConnectorEgressSettings", "ingressSettings", "environmentVariables");
|
|
279
309
|
return gcfFunction;
|
|
280
310
|
}
|
|
281
|
-
exports.
|
|
311
|
+
exports.functionFromEndpoint = functionFromEndpoint;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.endpointFromFunction = exports.functionFromEndpoint = exports.deleteFunction = exports.updateFunction = exports.listAllFunctions = exports.listFunctions = exports.getFunction = exports.createFunction = exports.generateUploadUrl = exports.PUBSUB_PUBLISH_EVENT = exports.API_VERSION = void 0;
|
|
4
4
|
const clc = require("cli-color");
|
|
5
5
|
const apiv2_1 = require("../apiv2");
|
|
6
6
|
const error_1 = require("../error");
|
|
@@ -115,19 +115,19 @@ async function deleteFunction(cloudFunction) {
|
|
|
115
115
|
}
|
|
116
116
|
}
|
|
117
117
|
exports.deleteFunction = deleteFunction;
|
|
118
|
-
function
|
|
119
|
-
if (
|
|
118
|
+
function functionFromEndpoint(endpoint, source) {
|
|
119
|
+
if (endpoint.platform != "gcfv2") {
|
|
120
120
|
throw new error_1.FirebaseError("Trying to create a v2 CloudFunction with v1 API. This should never happen");
|
|
121
121
|
}
|
|
122
|
-
if (!runtimes.isValidRuntime(
|
|
122
|
+
if (!runtimes.isValidRuntime(endpoint.runtime)) {
|
|
123
123
|
throw new error_1.FirebaseError("Failed internal assertion. Trying to deploy a new function with a deprecated runtime." +
|
|
124
124
|
" This should never happen");
|
|
125
125
|
}
|
|
126
126
|
const gcfFunction = {
|
|
127
|
-
name: backend.functionName(
|
|
127
|
+
name: backend.functionName(endpoint),
|
|
128
128
|
buildConfig: {
|
|
129
|
-
runtime:
|
|
130
|
-
entryPoint:
|
|
129
|
+
runtime: endpoint.runtime,
|
|
130
|
+
entryPoint: endpoint.entryPoint,
|
|
131
131
|
source: {
|
|
132
132
|
storageSource: source,
|
|
133
133
|
},
|
|
@@ -135,70 +135,83 @@ function functionFromSpec(cloudFunction, source) {
|
|
|
135
135
|
},
|
|
136
136
|
serviceConfig: {},
|
|
137
137
|
};
|
|
138
|
-
proto.copyIfPresent(gcfFunction
|
|
139
|
-
proto.
|
|
140
|
-
proto.renameIfPresent(gcfFunction.serviceConfig,
|
|
141
|
-
proto.renameIfPresent(gcfFunction.serviceConfig,
|
|
142
|
-
|
|
138
|
+
proto.copyIfPresent(gcfFunction, endpoint, "labels");
|
|
139
|
+
proto.copyIfPresent(gcfFunction.serviceConfig, endpoint, "availableMemoryMb", "environmentVariables", "vpcConnector", "vpcConnectorEgressSettings", "serviceAccountEmail", "ingressSettings");
|
|
140
|
+
proto.renameIfPresent(gcfFunction.serviceConfig, endpoint, "timeoutSeconds", "timeout", proto.secondsFromDuration);
|
|
141
|
+
proto.renameIfPresent(gcfFunction.serviceConfig, endpoint, "minInstanceCount", "minInstances");
|
|
142
|
+
proto.renameIfPresent(gcfFunction.serviceConfig, endpoint, "maxInstanceCount", "maxInstances");
|
|
143
|
+
if (backend.isEventTriggered(endpoint)) {
|
|
143
144
|
gcfFunction.eventTrigger = {
|
|
144
|
-
eventType:
|
|
145
|
+
eventType: endpoint.eventTrigger.eventType,
|
|
145
146
|
};
|
|
146
147
|
if (gcfFunction.eventTrigger.eventType === exports.PUBSUB_PUBLISH_EVENT) {
|
|
147
|
-
gcfFunction.eventTrigger.pubsubTopic =
|
|
148
|
+
gcfFunction.eventTrigger.pubsubTopic = endpoint.eventTrigger.eventFilters.resource;
|
|
148
149
|
}
|
|
149
150
|
else {
|
|
150
151
|
gcfFunction.eventTrigger.eventFilters = [];
|
|
151
|
-
for (const [attribute, value] of Object.entries(
|
|
152
|
+
for (const [attribute, value] of Object.entries(endpoint.eventTrigger.eventFilters)) {
|
|
152
153
|
gcfFunction.eventTrigger.eventFilters.push({ attribute, value });
|
|
153
154
|
}
|
|
154
155
|
}
|
|
155
|
-
if (
|
|
156
|
-
logger_1.logger.warn("Cannot set a retry policy on Cloud Function",
|
|
156
|
+
if (endpoint.eventTrigger.retry) {
|
|
157
|
+
logger_1.logger.warn("Cannot set a retry policy on Cloud Function", endpoint.id);
|
|
157
158
|
}
|
|
158
159
|
}
|
|
159
|
-
|
|
160
|
+
else if (backend.isScheduleTriggered(endpoint)) {
|
|
161
|
+
gcfFunction.labels = Object.assign(Object.assign({}, gcfFunction.labels), { "deployment-scheduled": "true" });
|
|
162
|
+
}
|
|
163
|
+
else if (backend.isTaskQueueTriggered(endpoint)) {
|
|
164
|
+
gcfFunction.labels = Object.assign(Object.assign({}, gcfFunction.labels), { "deployment-taskqueue": "true" });
|
|
165
|
+
}
|
|
160
166
|
return gcfFunction;
|
|
161
167
|
}
|
|
162
|
-
exports.
|
|
163
|
-
function
|
|
168
|
+
exports.functionFromEndpoint = functionFromEndpoint;
|
|
169
|
+
function endpointFromFunction(gcfFunction) {
|
|
170
|
+
var _a, _b;
|
|
164
171
|
const [, project, , region, , id] = gcfFunction.name.split("/");
|
|
165
172
|
let trigger;
|
|
166
|
-
if (gcfFunction.
|
|
173
|
+
if (((_a = gcfFunction.labels) === null || _a === void 0 ? void 0 : _a["deployment-scheduled"]) === "true") {
|
|
174
|
+
trigger = {
|
|
175
|
+
scheduleTrigger: {},
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
else if (((_b = gcfFunction.labels) === null || _b === void 0 ? void 0 : _b["deployment-taskqueue"]) === "true") {
|
|
167
179
|
trigger = {
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
180
|
+
taskQueueTrigger: {},
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
else if (gcfFunction.eventTrigger) {
|
|
184
|
+
trigger = {
|
|
185
|
+
eventTrigger: {
|
|
186
|
+
eventType: gcfFunction.eventTrigger.eventType,
|
|
187
|
+
eventFilters: {},
|
|
188
|
+
retry: false,
|
|
189
|
+
},
|
|
171
190
|
};
|
|
172
191
|
if (gcfFunction.eventTrigger.pubsubTopic) {
|
|
173
|
-
trigger.eventFilters.resource = gcfFunction.eventTrigger.pubsubTopic;
|
|
192
|
+
trigger.eventTrigger.eventFilters.resource = gcfFunction.eventTrigger.pubsubTopic;
|
|
174
193
|
}
|
|
175
194
|
else {
|
|
176
195
|
for (const { attribute, value } of gcfFunction.eventTrigger.eventFilters || []) {
|
|
177
|
-
trigger.eventFilters[attribute] = value;
|
|
196
|
+
trigger.eventTrigger.eventFilters[attribute] = value;
|
|
178
197
|
}
|
|
179
198
|
}
|
|
199
|
+
proto.renameIfPresent(trigger.eventTrigger, gcfFunction.eventTrigger, "region", "triggerRegion");
|
|
180
200
|
}
|
|
181
201
|
else {
|
|
182
|
-
trigger = {};
|
|
202
|
+
trigger = { httpsTrigger: {} };
|
|
183
203
|
}
|
|
184
204
|
if (!runtimes.isValidRuntime(gcfFunction.buildConfig.runtime)) {
|
|
185
205
|
logger_1.logger.debug("GCFv2 function has a deprecated runtime:", JSON.stringify(gcfFunction, null, 2));
|
|
186
206
|
}
|
|
187
|
-
const
|
|
188
|
-
platform: "gcfv2",
|
|
189
|
-
id,
|
|
207
|
+
const endpoint = Object.assign(Object.assign({ platform: "gcfv2", id,
|
|
190
208
|
project,
|
|
191
|
-
region,
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
proto.renameIfPresent(cloudFunction, gcfFunction.serviceConfig, "timeout", "timeoutSeconds", proto.durationFromSeconds);
|
|
199
|
-
proto.renameIfPresent(cloudFunction, gcfFunction.serviceConfig, "minInstances", "minInstanceCount");
|
|
200
|
-
proto.renameIfPresent(cloudFunction, gcfFunction.serviceConfig, "maxInstances", "maxInstanceCount");
|
|
201
|
-
proto.copyIfPresent(cloudFunction, gcfFunction, "labels");
|
|
202
|
-
return cloudFunction;
|
|
209
|
+
region }, trigger), { entryPoint: gcfFunction.buildConfig.entryPoint, runtime: gcfFunction.buildConfig.runtime, uri: gcfFunction.serviceConfig.uri });
|
|
210
|
+
proto.copyIfPresent(endpoint, gcfFunction.serviceConfig, "serviceAccountEmail", "availableMemoryMb", "vpcConnector", "vpcConnectorEgressSettings", "ingressSettings", "environmentVariables");
|
|
211
|
+
proto.renameIfPresent(endpoint, gcfFunction.serviceConfig, "timeout", "timeoutSeconds", proto.durationFromSeconds);
|
|
212
|
+
proto.renameIfPresent(endpoint, gcfFunction.serviceConfig, "minInstances", "minInstanceCount");
|
|
213
|
+
proto.renameIfPresent(endpoint, gcfFunction.serviceConfig, "maxInstances", "maxInstanceCount");
|
|
214
|
+
proto.copyIfPresent(endpoint, gcfFunction, "labels");
|
|
215
|
+
return endpoint;
|
|
203
216
|
}
|
|
204
|
-
exports.
|
|
217
|
+
exports.endpointFromFunction = endpointFromFunction;
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.jobFromEndpoint = exports.createOrReplaceJob = exports.updateJob = exports.getJob = exports.deleteJob = exports.createJob = exports.assertValidJob = void 0;
|
|
4
4
|
const _ = require("lodash");
|
|
5
5
|
const error_1 = require("../error");
|
|
6
6
|
const logger_1 = require("../logger");
|
|
7
7
|
const api = require("../api");
|
|
8
8
|
const backend = require("../deploy/functions/backend");
|
|
9
9
|
const proto = require("./proto");
|
|
10
|
+
const functional_1 = require("../functional");
|
|
10
11
|
const VERSION = "v1beta1";
|
|
11
12
|
const DEFAULT_TIME_ZONE = "America/Los_Angeles";
|
|
12
13
|
function assertValidJob(job) {
|
|
@@ -86,21 +87,26 @@ function isIdentical(job, otherJob) {
|
|
|
86
87
|
job.timeZone === otherJob.timeZone &&
|
|
87
88
|
_.isEqual(job.retryConfig, otherJob.retryConfig));
|
|
88
89
|
}
|
|
89
|
-
function
|
|
90
|
-
const job = {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
90
|
+
function jobFromEndpoint(endpoint, appEngineLocation) {
|
|
91
|
+
const job = {};
|
|
92
|
+
if (endpoint.platform === "gcfv1") {
|
|
93
|
+
const id = backend.scheduleIdForFunction(endpoint);
|
|
94
|
+
const region = appEngineLocation;
|
|
95
|
+
job.name = `projects/${endpoint.project}/locations/${region}/jobs/${id}`;
|
|
96
|
+
job.pubsubTarget = {
|
|
97
|
+
topicName: `projects/${endpoint.project}/topics/${id}`,
|
|
98
|
+
attributes: {
|
|
99
|
+
scheduled: "true",
|
|
100
|
+
},
|
|
101
|
+
};
|
|
97
102
|
}
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
}
|
|
103
|
+
else if (endpoint.platform === "gcfv2") {
|
|
104
|
+
throw new error_1.FirebaseError("Do not know how to create a scheduled GCFv2 function");
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
functional_1.assertExhaustive(endpoint.platform);
|
|
108
|
+
}
|
|
109
|
+
proto.copyIfPresent(job, endpoint.scheduleTrigger, "schedule", "retryConfig", "timeZone");
|
|
104
110
|
return job;
|
|
105
111
|
}
|
|
106
|
-
exports.
|
|
112
|
+
exports.jobFromEndpoint = jobFromEndpoint;
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.queueFromEndpoint = exports.queueNameForEndpoint = exports.setEnqueuer = exports.getIamPolicy = exports.setIamPolicy = exports.deleteQueue = exports.purgeQueue = exports.upsertQueue = exports.updateQueue = exports.getQueue = exports.createQueue = exports.DEFAULT_SETTINGS = void 0;
|
|
4
|
+
const proto = require("./proto");
|
|
5
|
+
const apiv2_1 = require("../apiv2");
|
|
6
|
+
const api_1 = require("../api");
|
|
7
|
+
const API_VERSION = "v2";
|
|
8
|
+
const client = new apiv2_1.Client({
|
|
9
|
+
urlPrefix: api_1.cloudTasksOrigin,
|
|
10
|
+
auth: true,
|
|
11
|
+
apiVersion: API_VERSION,
|
|
12
|
+
});
|
|
13
|
+
exports.DEFAULT_SETTINGS = {
|
|
14
|
+
rateLimits: {
|
|
15
|
+
maxConcurrentDispatches: 1000,
|
|
16
|
+
maxBurstSize: 100,
|
|
17
|
+
maxDispatchesPerSecond: 500,
|
|
18
|
+
},
|
|
19
|
+
state: "RUNNING",
|
|
20
|
+
retryConfig: {
|
|
21
|
+
maxDoublings: 16,
|
|
22
|
+
maxAttempts: 3,
|
|
23
|
+
maxBackoff: "3600s",
|
|
24
|
+
minBackoff: "0.100s",
|
|
25
|
+
},
|
|
26
|
+
};
|
|
27
|
+
async function createQueue(queue) {
|
|
28
|
+
const path = queue.name.substring(0, queue.name.lastIndexOf("/"));
|
|
29
|
+
const res = await client.post(path, queue);
|
|
30
|
+
return res.body;
|
|
31
|
+
}
|
|
32
|
+
exports.createQueue = createQueue;
|
|
33
|
+
async function getQueue(name) {
|
|
34
|
+
const res = await client.get(name);
|
|
35
|
+
return res.body;
|
|
36
|
+
}
|
|
37
|
+
exports.getQueue = getQueue;
|
|
38
|
+
async function updateQueue(queue) {
|
|
39
|
+
const res = await client.patch(queue.name, queue, {
|
|
40
|
+
queryParams: { updateMask: proto.fieldMasks(queue).join(",") },
|
|
41
|
+
});
|
|
42
|
+
return res.body;
|
|
43
|
+
}
|
|
44
|
+
exports.updateQueue = updateQueue;
|
|
45
|
+
async function upsertQueue(queue) {
|
|
46
|
+
var _a, _b;
|
|
47
|
+
try {
|
|
48
|
+
const existing = await module.exports.getQueue(queue.name);
|
|
49
|
+
if (JSON.stringify(queue) === JSON.stringify(existing)) {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
if (existing.state === "DISABLED") {
|
|
53
|
+
await module.exports.purgeQueue(queue.name);
|
|
54
|
+
}
|
|
55
|
+
await module.exports.updateQueue(queue);
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
catch (err) {
|
|
59
|
+
if (((_b = (_a = err === null || err === void 0 ? void 0 : err.context) === null || _a === void 0 ? void 0 : _a.response) === null || _b === void 0 ? void 0 : _b.statusCode) === 404) {
|
|
60
|
+
await module.exports.createQueue(queue);
|
|
61
|
+
return true;
|
|
62
|
+
}
|
|
63
|
+
throw err;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
exports.upsertQueue = upsertQueue;
|
|
67
|
+
async function purgeQueue(name) {
|
|
68
|
+
await client.post(`${name}:purge`);
|
|
69
|
+
}
|
|
70
|
+
exports.purgeQueue = purgeQueue;
|
|
71
|
+
async function deleteQueue(name) {
|
|
72
|
+
await client.delete(name);
|
|
73
|
+
}
|
|
74
|
+
exports.deleteQueue = deleteQueue;
|
|
75
|
+
async function setIamPolicy(name, policy) {
|
|
76
|
+
const res = await client.post(`${name}:setIamPolicy`, {
|
|
77
|
+
policy,
|
|
78
|
+
});
|
|
79
|
+
return res.body;
|
|
80
|
+
}
|
|
81
|
+
exports.setIamPolicy = setIamPolicy;
|
|
82
|
+
async function getIamPolicy(name) {
|
|
83
|
+
const res = await client.post(`${name}:getIamPolicy`);
|
|
84
|
+
return res.body;
|
|
85
|
+
}
|
|
86
|
+
exports.getIamPolicy = getIamPolicy;
|
|
87
|
+
const ENQUEUER_ROLE = "roles/cloudtasks.enqueuer";
|
|
88
|
+
async function setEnqueuer(name, invoker, assumeEmpty = false) {
|
|
89
|
+
var _a, _b;
|
|
90
|
+
let existing;
|
|
91
|
+
if (assumeEmpty) {
|
|
92
|
+
existing = {
|
|
93
|
+
bindings: [],
|
|
94
|
+
etag: "",
|
|
95
|
+
version: 3,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
existing = await module.exports.getIamPolicy(name);
|
|
100
|
+
}
|
|
101
|
+
const [, project] = name.split("/");
|
|
102
|
+
const invokerMembers = proto.getInvokerMembers(invoker, project);
|
|
103
|
+
while (true) {
|
|
104
|
+
const policy = {
|
|
105
|
+
bindings: existing.bindings.filter((binding) => binding.role != ENQUEUER_ROLE),
|
|
106
|
+
etag: existing.etag,
|
|
107
|
+
version: existing.version,
|
|
108
|
+
};
|
|
109
|
+
if (invokerMembers.length) {
|
|
110
|
+
policy.bindings.push({ role: ENQUEUER_ROLE, members: invokerMembers });
|
|
111
|
+
}
|
|
112
|
+
if (JSON.stringify(policy) === JSON.stringify(existing)) {
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
try {
|
|
116
|
+
await module.exports.setIamPolicy(name, policy);
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
catch (err) {
|
|
120
|
+
if (((_b = (_a = err === null || err === void 0 ? void 0 : err.context) === null || _a === void 0 ? void 0 : _a.response) === null || _b === void 0 ? void 0 : _b.statusCode) === 429) {
|
|
121
|
+
existing = await module.exports.getIamPolicy(name);
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
throw err;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
exports.setEnqueuer = setEnqueuer;
|
|
129
|
+
function queueNameForEndpoint(endpoint) {
|
|
130
|
+
return `projects/${endpoint.project}/locations/${endpoint.region}/queues/${endpoint.id}`;
|
|
131
|
+
}
|
|
132
|
+
exports.queueNameForEndpoint = queueNameForEndpoint;
|
|
133
|
+
function queueFromEndpoint(endpoint) {
|
|
134
|
+
const queue = Object.assign(Object.assign({}, JSON.parse(JSON.stringify(exports.DEFAULT_SETTINGS))), { name: queueNameForEndpoint(endpoint) });
|
|
135
|
+
if (endpoint.taskQueueTrigger.rateLimits) {
|
|
136
|
+
proto.copyIfPresent(queue.rateLimits, endpoint.taskQueueTrigger.rateLimits, "maxBurstSize", "maxConcurrentDispatches", "maxDispatchesPerSecond");
|
|
137
|
+
}
|
|
138
|
+
if (endpoint.taskQueueTrigger.retryConfig) {
|
|
139
|
+
proto.copyIfPresent(queue.retryConfig, endpoint.taskQueueTrigger.retryConfig, "maxAttempts", "maxBackoff", "maxDoublings", "maxRetryDuration", "minBackoff");
|
|
140
|
+
}
|
|
141
|
+
return queue;
|
|
142
|
+
}
|
|
143
|
+
exports.queueFromEndpoint = queueFromEndpoint;
|
package/lib/gcp/docker.js
CHANGED
|
@@ -4,7 +4,7 @@ exports.Client = void 0;
|
|
|
4
4
|
const error_1 = require("../error");
|
|
5
5
|
const api = require("../apiv2");
|
|
6
6
|
function isErrors(response) {
|
|
7
|
-
return Object.prototype.hasOwnProperty.call(response, "errors");
|
|
7
|
+
return !!response && Object.prototype.hasOwnProperty.call(response, "errors");
|
|
8
8
|
}
|
|
9
9
|
const API_VERSION = "v2";
|
|
10
10
|
class Client {
|
|
@@ -27,6 +27,9 @@ class Client {
|
|
|
27
27
|
async deleteTag(path, tag) {
|
|
28
28
|
var _a;
|
|
29
29
|
const response = await this.client.delete(`${path}/manifests/${tag}`);
|
|
30
|
+
if (!response.body) {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
30
33
|
if (((_a = response.body.errors) === null || _a === void 0 ? void 0 : _a.length) != 0) {
|
|
31
34
|
throw new error_1.FirebaseError(`Failed to delete tag ${tag} at path ${path}`, {
|
|
32
35
|
children: response.body.errors,
|
|
@@ -36,6 +39,9 @@ class Client {
|
|
|
36
39
|
async deleteImage(path, digest) {
|
|
37
40
|
var _a;
|
|
38
41
|
const response = await this.client.delete(`${path}/manifests/${digest}`);
|
|
42
|
+
if (!response.body) {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
39
45
|
if (((_a = response.body.errors) === null || _a === void 0 ? void 0 : _a.length) != 0) {
|
|
40
46
|
throw new error_1.FirebaseError(`Failed to delete image ${digest} at path ${path}`, {
|
|
41
47
|
children: response.body.errors,
|
package/lib/gcp/proto.js
CHANGED
|
@@ -67,10 +67,10 @@ function fieldMasksHelper(prefixes, cursor, doNotRecurseIn, masks) {
|
|
|
67
67
|
}
|
|
68
68
|
}
|
|
69
69
|
function getInvokerMembers(invoker, projectId) {
|
|
70
|
-
if (invoker
|
|
70
|
+
if (invoker.includes("private")) {
|
|
71
71
|
return [];
|
|
72
72
|
}
|
|
73
|
-
if (invoker
|
|
73
|
+
if (invoker.includes("public")) {
|
|
74
74
|
return ["allUsers"];
|
|
75
75
|
}
|
|
76
76
|
return invoker.map((inv) => formatServiceAccount(inv, projectId));
|
package/lib/gcp/pubsub.js
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.deleteTopic = exports.updateTopic = exports.getTopic = exports.createTopic = void 0;
|
|
4
4
|
const apiv2_1 = require("../apiv2");
|
|
5
5
|
const api_1 = require("../api");
|
|
6
|
-
const backend = require("../deploy/functions/backend");
|
|
7
6
|
const proto = require("./proto");
|
|
8
7
|
const API_VERSION = "v1";
|
|
9
8
|
const client = new apiv2_1.Client({
|
|
@@ -33,10 +32,3 @@ async function deleteTopic(name) {
|
|
|
33
32
|
await client.delete(name);
|
|
34
33
|
}
|
|
35
34
|
exports.deleteTopic = deleteTopic;
|
|
36
|
-
function topicFromSpec(spec) {
|
|
37
|
-
return {
|
|
38
|
-
name: backend.topicName(spec),
|
|
39
|
-
labels: Object.assign({}, spec.labels),
|
|
40
|
-
};
|
|
41
|
-
}
|
|
42
|
-
exports.topicFromSpec = topicFromSpec;
|