firebase-tools 9.17.0 → 9.21.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 -7
- package/lib/api.js +1 -0
- package/lib/apiv2.js +5 -3
- package/lib/appdistribution/client.js +84 -72
- package/lib/appdistribution/distribution.js +8 -26
- package/lib/appdistribution/options-parser-util.js +51 -0
- package/lib/command.js +1 -1
- package/lib/commands/appdistribution-distribute.js +74 -91
- package/lib/commands/appdistribution-testers-add.js +18 -0
- package/lib/commands/appdistribution-testers-remove.js +32 -0
- package/lib/commands/crashlytics-symbols-upload.js +146 -0
- package/lib/commands/ext-configure.js +9 -1
- package/lib/commands/ext-dev-extension-delete.js +2 -1
- package/lib/commands/ext-dev-publish.js +11 -4
- package/lib/commands/ext-dev-unpublish.js +12 -4
- package/lib/commands/ext-install.js +115 -48
- package/lib/commands/ext-uninstall.js +6 -0
- package/lib/commands/ext-update.js +61 -18
- package/lib/commands/functions-config-export.js +115 -0
- package/lib/commands/functions-delete.js +45 -25
- package/lib/commands/functions-list.js +54 -0
- package/lib/commands/functions-log.js +5 -22
- package/lib/commands/hosting-channel-deploy.js +6 -4
- package/lib/commands/index.js +12 -0
- package/lib/deploy/functions/backend.js +118 -121
- package/lib/deploy/functions/checkIam.js +8 -8
- package/lib/deploy/functions/containerCleaner.js +5 -1
- package/lib/deploy/functions/deploy.js +11 -15
- package/lib/deploy/functions/functionsDeployHelper.js +3 -68
- package/lib/deploy/functions/prepare.js +67 -33
- package/lib/deploy/functions/pricing.js +17 -17
- package/lib/deploy/functions/prompts.js +24 -41
- package/lib/deploy/functions/release/executor.js +39 -0
- package/lib/deploy/functions/release/fabricator.js +362 -0
- package/lib/deploy/functions/release/index.js +69 -0
- package/lib/deploy/functions/release/planner.js +159 -0
- package/lib/deploy/functions/release/reporter.js +162 -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 +102 -126
- package/lib/deploy/functions/runtimes/node/parseTriggers.js +34 -50
- package/lib/deploy/functions/triggerRegionHelper.js +40 -0
- package/lib/deploy/functions/validate.js +1 -24
- 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 +117 -20
- 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 +16 -13
- package/lib/extensions/askUserForParam.js +72 -3
- package/lib/extensions/billingMigrationHelper.js +1 -11
- package/lib/extensions/changelog.js +2 -1
- 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/extensionsApi.js +67 -94
- package/lib/extensions/extensionsHelper.js +49 -35
- package/lib/extensions/paramHelper.js +79 -36
- package/lib/extensions/refs.js +59 -0
- package/lib/extensions/secretsUtils.js +58 -0
- package/lib/extensions/updateHelper.js +21 -45
- package/lib/extensions/warnings.js +1 -7
- package/lib/functional.js +64 -0
- package/lib/functions/env.js +26 -13
- package/lib/functions/functionslog.js +40 -0
- package/lib/functions/runtimeConfigExport.js +137 -0
- package/lib/gcp/cloudfunctions.js +46 -38
- package/lib/gcp/cloudfunctionsv2.js +47 -47
- package/lib/gcp/cloudlogging.js +27 -21
- package/lib/gcp/cloudscheduler.js +22 -16
- package/lib/gcp/pubsub.js +1 -9
- package/lib/gcp/secretManager.js +111 -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 +5 -4
- 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/functionsDelete.js +0 -60
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.addResourcesToBackend = exports.discoverBackend = exports.useStrategy = void 0;
|
|
3
|
+
exports.addResourcesToBackend = exports.discoverBackend = exports.useStrategy = exports.GCS_EVENTS = void 0;
|
|
4
4
|
const path = require("path");
|
|
5
5
|
const _ = require("lodash");
|
|
6
6
|
const child_process_1 = require("child_process");
|
|
@@ -10,6 +10,12 @@ const backend = require("../../backend");
|
|
|
10
10
|
const api = require("../../../../api");
|
|
11
11
|
const proto = require("../../../../gcp/proto");
|
|
12
12
|
const TRIGGER_PARSER = path.resolve(__dirname, "./triggerParser.js");
|
|
13
|
+
exports.GCS_EVENTS = new Set([
|
|
14
|
+
"google.cloud.storage.object.v1.finalized",
|
|
15
|
+
"google.cloud.storage.object.v1.archived",
|
|
16
|
+
"google.cloud.storage.object.v1.deleted",
|
|
17
|
+
"google.cloud.storage.object.v1.metadataUpdated",
|
|
18
|
+
]);
|
|
13
19
|
function removeInspectOptions(options) {
|
|
14
20
|
return options.filter((opt) => !opt.startsWith("--inspect"));
|
|
15
21
|
}
|
|
@@ -58,75 +64,53 @@ async function discoverBackend(projectId, sourceDir, runtime, configValues, envs
|
|
|
58
64
|
}
|
|
59
65
|
exports.discoverBackend = discoverBackend;
|
|
60
66
|
function addResourcesToBackend(projectId, runtime, annotation, want) {
|
|
67
|
+
var _a;
|
|
61
68
|
Object.freeze(annotation);
|
|
62
69
|
for (const region of annotation.regions || [api.functionsDefaultRegion]) {
|
|
63
|
-
let
|
|
70
|
+
let triggered;
|
|
64
71
|
if (!!annotation.httpsTrigger == !!annotation.eventTrigger) {
|
|
65
72
|
throw new error_1.FirebaseError("Unexpected annotation generated by the Firebase Functions SDK. This should never happen.");
|
|
66
73
|
}
|
|
67
74
|
if (annotation.httpsTrigger) {
|
|
68
|
-
|
|
69
|
-
if ("allowInsecure" in annotation.httpsTrigger) {
|
|
70
|
-
allowInsecure = !!annotation.httpsTrigger.allowInsecure;
|
|
71
|
-
}
|
|
72
|
-
else {
|
|
73
|
-
allowInsecure = !annotation.platform || annotation.platform === "gcfv1";
|
|
74
|
-
}
|
|
75
|
-
trigger = { allowInsecure };
|
|
75
|
+
const trigger = {};
|
|
76
76
|
if (annotation.failurePolicy) {
|
|
77
77
|
logger_1.logger.warn(`Ignoring retry policy for HTTPS function ${annotation.name}`);
|
|
78
78
|
}
|
|
79
|
-
proto.copyIfPresent(trigger, annotation.httpsTrigger, "invoker"
|
|
79
|
+
proto.copyIfPresent(trigger, annotation.httpsTrigger, "invoker");
|
|
80
|
+
triggered = { httpsTrigger: trigger };
|
|
81
|
+
}
|
|
82
|
+
else if (annotation.schedule) {
|
|
83
|
+
want.requiredAPIs["pubsub"] = "pubsub.googleapis.com";
|
|
84
|
+
want.requiredAPIs["scheduler"] = "cloudscheduler.googleapis.com";
|
|
85
|
+
triggered = { scheduleTrigger: annotation.schedule };
|
|
80
86
|
}
|
|
81
87
|
else {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
88
|
+
triggered = {
|
|
89
|
+
eventTrigger: {
|
|
90
|
+
eventType: annotation.eventTrigger.eventType,
|
|
91
|
+
eventFilters: {
|
|
92
|
+
resource: annotation.eventTrigger.resource,
|
|
93
|
+
},
|
|
94
|
+
retry: !!annotation.failurePolicy,
|
|
86
95
|
},
|
|
87
|
-
retry: !!annotation.failurePolicy,
|
|
88
96
|
};
|
|
97
|
+
if (exports.GCS_EVENTS.has(((_a = annotation.eventTrigger) === null || _a === void 0 ? void 0 : _a.eventType) || "")) {
|
|
98
|
+
triggered.eventTrigger.eventFilters = {
|
|
99
|
+
bucket: annotation.eventTrigger.resource,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
89
102
|
}
|
|
90
|
-
const
|
|
91
|
-
id: annotation.name,
|
|
92
|
-
region: region,
|
|
93
|
-
project: projectId,
|
|
94
|
-
};
|
|
95
|
-
const cloudFunction = Object.assign(Object.assign({ platform: annotation.platform || "gcfv1" }, cloudFunctionName), { entryPoint: annotation.entryPoint, runtime: runtime, trigger: trigger });
|
|
103
|
+
const endpoint = Object.assign({ platform: annotation.platform || "gcfv1", id: annotation.name, region: region, project: projectId, entryPoint: annotation.entryPoint, runtime: runtime }, triggered);
|
|
96
104
|
if (annotation.vpcConnector) {
|
|
97
105
|
let maybeId = annotation.vpcConnector;
|
|
98
106
|
if (!maybeId.includes("/")) {
|
|
99
107
|
maybeId = `projects/${projectId}/locations/${region}/connectors/${maybeId}`;
|
|
100
108
|
}
|
|
101
|
-
|
|
102
|
-
}
|
|
103
|
-
proto.copyIfPresent(cloudFunction, annotation, "concurrency", "serviceAccountEmail", "labels", "vpcConnectorEgressSettings", "ingressSettings", "timeout", "maxInstances", "minInstances", "availableMemoryMb");
|
|
104
|
-
if (annotation.schedule) {
|
|
105
|
-
want.requiredAPIs["pubsub"] = "pubsub.googleapis.com";
|
|
106
|
-
want.requiredAPIs["scheduler"] = "cloudscheduler.googleapis.com";
|
|
107
|
-
const id = backend.scheduleIdForFunction(cloudFunctionName);
|
|
108
|
-
const schedule = {
|
|
109
|
-
id,
|
|
110
|
-
project: projectId,
|
|
111
|
-
schedule: annotation.schedule.schedule,
|
|
112
|
-
transport: "pubsub",
|
|
113
|
-
targetService: cloudFunctionName,
|
|
114
|
-
};
|
|
115
|
-
proto.copyIfPresent(schedule, annotation.schedule, "timeZone", "retryConfig");
|
|
116
|
-
want.schedules.push(schedule);
|
|
117
|
-
const topic = {
|
|
118
|
-
id,
|
|
119
|
-
project: projectId,
|
|
120
|
-
labels: backend.SCHEDULED_FUNCTION_LABEL,
|
|
121
|
-
targetService: cloudFunctionName,
|
|
122
|
-
};
|
|
123
|
-
want.topics.push(topic);
|
|
124
|
-
if (backend.isEventTrigger(cloudFunction.trigger)) {
|
|
125
|
-
cloudFunction.trigger.eventFilters.resource = `${cloudFunction.trigger.eventFilters.resource}/${id}`;
|
|
126
|
-
}
|
|
127
|
-
cloudFunction.labels = Object.assign(Object.assign({}, cloudFunction.labels), { "deployment-scheduled": "true" });
|
|
109
|
+
endpoint.vpcConnector = maybeId;
|
|
128
110
|
}
|
|
129
|
-
|
|
111
|
+
proto.copyIfPresent(endpoint, annotation, "concurrency", "serviceAccountEmail", "labels", "vpcConnectorEgressSettings", "ingressSettings", "timeout", "maxInstances", "minInstances", "availableMemoryMb");
|
|
112
|
+
want.endpoints[region] = want.endpoints[region] || {};
|
|
113
|
+
want.endpoints[region][endpoint.id] = endpoint;
|
|
130
114
|
}
|
|
131
115
|
}
|
|
132
116
|
exports.addResourcesToBackend = addResourcesToBackend;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.lookupMissingTriggerRegions = void 0;
|
|
4
|
+
const backend = require("./backend");
|
|
5
|
+
const storage = require("../../gcp/storage");
|
|
6
|
+
const error_1 = require("../../error");
|
|
7
|
+
const logger_1 = require("../../logger");
|
|
8
|
+
const noop = () => Promise.resolve();
|
|
9
|
+
const LOOKUP_BY_EVENT_TYPE = {
|
|
10
|
+
"google.cloud.pubsub.topic.v1.messagePublished": noop,
|
|
11
|
+
"google.cloud.storage.object.v1.finalized": lookupBucketRegion,
|
|
12
|
+
"google.cloud.storage.object.v1.archived": lookupBucketRegion,
|
|
13
|
+
"google.cloud.storage.object.v1.deleted": lookupBucketRegion,
|
|
14
|
+
"google.cloud.storage.object.v1.metadataUpdated": lookupBucketRegion,
|
|
15
|
+
};
|
|
16
|
+
async function lookupMissingTriggerRegions(want) {
|
|
17
|
+
const regionLookups = [];
|
|
18
|
+
for (const ep of backend.allEndpoints(want)) {
|
|
19
|
+
if (ep.platform === "gcfv1" || !backend.isEventTriggered(ep) || ep.eventTrigger.region) {
|
|
20
|
+
continue;
|
|
21
|
+
}
|
|
22
|
+
const lookup = LOOKUP_BY_EVENT_TYPE[ep.eventTrigger.eventType];
|
|
23
|
+
if (!lookup) {
|
|
24
|
+
logger_1.logger.debug("Don't know how to look up trigger region for event type", ep.eventTrigger.eventType, ". Deploy will fail unless this event type is global");
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
regionLookups.push(lookup(ep));
|
|
28
|
+
}
|
|
29
|
+
await Promise.all(regionLookups);
|
|
30
|
+
}
|
|
31
|
+
exports.lookupMissingTriggerRegions = lookupMissingTriggerRegions;
|
|
32
|
+
async function lookupBucketRegion(endpoint) {
|
|
33
|
+
try {
|
|
34
|
+
const bucket = await storage.getBucket(endpoint.eventTrigger.eventFilters.bucket);
|
|
35
|
+
endpoint.eventTrigger.region = bucket.location.toLowerCase();
|
|
36
|
+
}
|
|
37
|
+
catch (err) {
|
|
38
|
+
throw new error_1.FirebaseError("Can't find the storage bucket region", { original: err });
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.functionIdsAreValid = exports.functionsDirectoryExists = void 0;
|
|
4
4
|
const clc = require("cli-color");
|
|
5
5
|
const error_1 = require("../../error");
|
|
6
|
-
const functionsDeployHelper_1 = require("./functionsDeployHelper");
|
|
7
|
-
const backend = require("./backend");
|
|
8
6
|
const fsutils = require("../../fsutils");
|
|
9
7
|
const projectPath = require("../../projectPath");
|
|
10
8
|
function functionsDirectoryExists(options, sourceDirName) {
|
|
@@ -36,24 +34,3 @@ function functionIdsAreValid(functions) {
|
|
|
36
34
|
}
|
|
37
35
|
}
|
|
38
36
|
exports.functionIdsAreValid = functionIdsAreValid;
|
|
39
|
-
function checkForInvalidChangeOfTrigger(fn, exFn) {
|
|
40
|
-
var _a, _b;
|
|
41
|
-
const wantEventTrigger = backend.isEventTrigger(fn.trigger);
|
|
42
|
-
const haveEventTrigger = backend.isEventTrigger(exFn.trigger);
|
|
43
|
-
if (!wantEventTrigger && haveEventTrigger) {
|
|
44
|
-
throw new error_1.FirebaseError(`[${functionsDeployHelper_1.getFunctionLabel(fn)}] Changing from a background triggered function to an HTTPS function is not allowed. Please delete your function and create a new one instead.`);
|
|
45
|
-
}
|
|
46
|
-
if (wantEventTrigger && !haveEventTrigger) {
|
|
47
|
-
throw new error_1.FirebaseError(`[${functionsDeployHelper_1.getFunctionLabel(fn)}] Changing from an HTTPS function to an background triggered function is not allowed. Please delete your function and create a new one instead.`);
|
|
48
|
-
}
|
|
49
|
-
if (fn.platform == "gcfv2" && exFn.platform == "gcfv1") {
|
|
50
|
-
throw new error_1.FirebaseError(`[${functionsDeployHelper_1.getFunctionLabel(fn)}] Upgrading from GCFv1 to GCFv2 is not yet supported. Please delete your old function or wait for this feature to be ready.`);
|
|
51
|
-
}
|
|
52
|
-
if (fn.platform == "gcfv1" && exFn.platform == "gcfv2") {
|
|
53
|
-
throw new error_1.FirebaseError(`[${functionsDeployHelper_1.getFunctionLabel(fn)}] Functions cannot be downgraded from GCFv2 to GCFv1`);
|
|
54
|
-
}
|
|
55
|
-
if (((_a = exFn.labels) === null || _a === void 0 ? void 0 : _a["deployment-scheduled"]) && !((_b = fn.labels) === null || _b === void 0 ? void 0 : _b["deployment-scheduled"])) {
|
|
56
|
-
throw new error_1.FirebaseError(`[${functionsDeployHelper_1.getFunctionLabel(fn)}] Scheduled functions cannot be changed to event handler or HTTP functions`);
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
exports.checkForInvalidChangeOfTrigger = checkForInvalidChangeOfTrigger;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.downloadToTmp = void 0;
|
|
4
|
+
const url_1 = require("url");
|
|
5
|
+
const fs = require("fs-extra");
|
|
6
|
+
const ProgressBar = require("progress");
|
|
7
|
+
const tmp = require("tmp");
|
|
8
|
+
const apiv2_1 = require("./apiv2");
|
|
9
|
+
const error_1 = require("./error");
|
|
10
|
+
async function downloadToTmp(remoteUrl) {
|
|
11
|
+
const u = new url_1.URL(remoteUrl);
|
|
12
|
+
const c = new apiv2_1.Client({ urlPrefix: u.origin, auth: false });
|
|
13
|
+
const tmpfile = tmp.fileSync();
|
|
14
|
+
const writeStream = fs.createWriteStream(tmpfile.name);
|
|
15
|
+
const res = await c.request({
|
|
16
|
+
method: "GET",
|
|
17
|
+
path: u.pathname,
|
|
18
|
+
queryParams: u.searchParams,
|
|
19
|
+
responseType: "stream",
|
|
20
|
+
resolveOnHTTPError: true,
|
|
21
|
+
});
|
|
22
|
+
if (res.status !== 200) {
|
|
23
|
+
throw new error_1.FirebaseError(`download failed, status ${res.status}`, { exit: 1 });
|
|
24
|
+
}
|
|
25
|
+
const total = parseInt(res.response.headers.get("content-length") || "0", 10);
|
|
26
|
+
const totalMb = Math.ceil(total / 1000000);
|
|
27
|
+
const bar = new ProgressBar(`Progress: :bar (:percent of ${totalMb}MB)`, { total, head: ">" });
|
|
28
|
+
res.body.on("data", (chunk) => {
|
|
29
|
+
bar.tick(chunk.length);
|
|
30
|
+
});
|
|
31
|
+
await new Promise((resolve) => {
|
|
32
|
+
writeStream.on("finish", resolve);
|
|
33
|
+
res.body.pipe(writeStream);
|
|
34
|
+
});
|
|
35
|
+
return tmpfile.name;
|
|
36
|
+
}
|
|
37
|
+
exports.downloadToTmp = downloadToTmp;
|