firebase-tools 9.16.6 → 9.20.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 +1 -3
- package/lib/api.js +1 -0
- package/lib/apiv2.js +1 -1
- 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 +8 -6
- 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-init.js +18 -9
- package/lib/commands/ext-dev-publish.js +11 -4
- package/lib/commands/ext-dev-unpublish.js +2 -1
- package/lib/commands/ext-install.js +115 -48
- package/lib/commands/ext-uninstall.js +6 -0
- package/lib/commands/ext-update.js +67 -43
- package/lib/commands/functions-config-export.js +115 -0
- package/lib/commands/functions-delete.js +44 -35
- 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 +47 -12
- package/lib/deploy/functions/containerCleaner.js +5 -1
- package/lib/deploy/functions/deploy.js +7 -5
- package/lib/deploy/functions/prepare.js +9 -7
- package/lib/deploy/functions/prompts.js +3 -21
- package/lib/deploy/functions/runtimes/discovery/v1alpha1.js +2 -1
- package/lib/deploy/functions/runtimes/index.js +2 -1
- package/lib/deploy/functions/runtimes/node/parseRuntimeAndValidateSDK.js +4 -3
- package/lib/deploy/functions/runtimes/node/parseTriggers.js +14 -9
- package/lib/deploy/functions/triggerRegionHelper.js +32 -0
- package/lib/downloadUtils.js +37 -0
- package/lib/emulator/auth/apiSpec.js +1758 -404
- package/lib/emulator/auth/handlers.js +6 -5
- package/lib/emulator/auth/operations.js +429 -40
- package/lib/emulator/auth/server.js +18 -11
- package/lib/emulator/auth/state.js +186 -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 +102 -17
- 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/extensions/askUserForConsent.js +16 -13
- package/lib/extensions/askUserForParam.js +72 -3
- package/lib/extensions/billingMigrationHelper.js +1 -11
- package/lib/extensions/changelog.js +93 -0
- package/lib/extensions/displayExtensionInfo.js +38 -38
- package/lib/extensions/emulator/optionsHelper.js +3 -3
- package/lib/extensions/emulator/triggerHelper.js +2 -32
- package/lib/extensions/extensionsApi.js +69 -95
- package/lib/extensions/extensionsHelper.js +75 -50
- package/lib/extensions/paramHelper.js +79 -36
- package/lib/extensions/refs.js +59 -0
- package/lib/extensions/resolveSource.js +2 -20
- package/lib/extensions/secretsUtils.js +58 -0
- package/lib/extensions/updateHelper.js +39 -105
- 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/listFunctions.js +10 -0
- package/lib/functions/runtimeConfigExport.js +137 -0
- package/lib/gcp/cloudfunctions.js +84 -9
- package/lib/gcp/cloudfunctionsv2.js +99 -7
- package/lib/gcp/cloudlogging.js +27 -21
- 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/package.json +5 -4
- package/schema/firebase-config.json +2 -1
- package/templates/extensions/CHANGELOG.md +7 -0
- package/templates/init/hosting/index.html +10 -10
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.checkAvailability = exports.existingBackend = exports.scheduleIdForFunction = exports.topicName = exports.scheduleName = exports.sameFunctionName = exports.functionName = exports.isEmptyBackend = exports.empty = exports.SCHEDULED_FUNCTION_LABEL = exports.memoryOptionDisplayName = exports.triggerTag = exports.isEventTrigger = void 0;
|
|
3
|
+
exports.compareFunctions = exports.checkAvailability = exports.existingBackend = exports.scheduleIdForFunction = exports.topicName = exports.scheduleName = exports.sameFunctionName = exports.functionName = exports.isEmptyBackend = exports.empty = exports.isScheduleTriggered = exports.isEventTriggered = exports.isHttpsTriggered = exports.SCHEDULED_FUNCTION_LABEL = exports.memoryOptionDisplayName = exports.triggerTag = exports.isEventTrigger = void 0;
|
|
4
4
|
const gcf = require("../../gcp/cloudfunctions");
|
|
5
5
|
const gcfV2 = require("../../gcp/cloudfunctionsv2");
|
|
6
6
|
const utils = require("../../utils");
|
|
@@ -46,9 +46,22 @@ function memoryOptionDisplayName(option) {
|
|
|
46
46
|
}
|
|
47
47
|
exports.memoryOptionDisplayName = memoryOptionDisplayName;
|
|
48
48
|
exports.SCHEDULED_FUNCTION_LABEL = Object.freeze({ deployment: "firebase-schedule" });
|
|
49
|
+
function isHttpsTriggered(triggered) {
|
|
50
|
+
return {}.hasOwnProperty.call(triggered, "httpsTrigger");
|
|
51
|
+
}
|
|
52
|
+
exports.isHttpsTriggered = isHttpsTriggered;
|
|
53
|
+
function isEventTriggered(triggered) {
|
|
54
|
+
return {}.hasOwnProperty.call(triggered, "eventTrigger");
|
|
55
|
+
}
|
|
56
|
+
exports.isEventTriggered = isEventTriggered;
|
|
57
|
+
function isScheduleTriggered(triggered) {
|
|
58
|
+
return {}.hasOwnProperty.call(triggered, "scheduleTrigger");
|
|
59
|
+
}
|
|
60
|
+
exports.isScheduleTriggered = isScheduleTriggered;
|
|
49
61
|
function empty() {
|
|
50
62
|
return {
|
|
51
63
|
requiredAPIs: {},
|
|
64
|
+
endpoints: [],
|
|
52
65
|
cloudFunctions: [],
|
|
53
66
|
schedules: [],
|
|
54
67
|
topics: [],
|
|
@@ -91,15 +104,9 @@ async function existingBackend(context, forceRefresh) {
|
|
|
91
104
|
}
|
|
92
105
|
exports.existingBackend = existingBackend;
|
|
93
106
|
async function loadExistingBackend(ctx) {
|
|
94
|
-
var _a, _b, _c;
|
|
107
|
+
var _a, _b, _c, _d;
|
|
95
108
|
ctx.loadedExistingBackend = true;
|
|
96
|
-
ctx.existingBackend = {
|
|
97
|
-
requiredAPIs: {},
|
|
98
|
-
cloudFunctions: [],
|
|
99
|
-
schedules: [],
|
|
100
|
-
topics: [],
|
|
101
|
-
environmentVariables: {},
|
|
102
|
-
};
|
|
109
|
+
ctx.existingBackend = Object.assign({}, empty());
|
|
103
110
|
ctx.unreachableRegions = {
|
|
104
111
|
gcfV1: [],
|
|
105
112
|
gcfV2: [],
|
|
@@ -137,12 +144,21 @@ async function loadExistingBackend(ctx) {
|
|
|
137
144
|
if (!previews_1.previews.functionsv2) {
|
|
138
145
|
return;
|
|
139
146
|
}
|
|
140
|
-
|
|
147
|
+
let gcfV2Results;
|
|
148
|
+
try {
|
|
149
|
+
gcfV2Results = await gcfV2.listAllFunctions(ctx.projectId);
|
|
150
|
+
}
|
|
151
|
+
catch (err) {
|
|
152
|
+
if (err.status === 404 && ((_b = err.message) === null || _b === void 0 ? void 0 : _b.toLowerCase().includes("method not found"))) {
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
throw err;
|
|
156
|
+
}
|
|
141
157
|
for (const apiFunction of gcfV2Results.functions) {
|
|
142
158
|
const specFunction = gcfV2.specFromFunction(apiFunction);
|
|
143
159
|
ctx.existingBackend.cloudFunctions.push(specFunction);
|
|
144
|
-
const pubsubScheduled = ((
|
|
145
|
-
const httpsScheduled = ((
|
|
160
|
+
const pubsubScheduled = ((_c = apiFunction.labels) === null || _c === void 0 ? void 0 : _c["deployment-scheduled"]) === "true";
|
|
161
|
+
const httpsScheduled = ((_d = apiFunction.labels) === null || _d === void 0 ? void 0 : _d["deployment-scheduled"]) === "https";
|
|
146
162
|
if (pubsubScheduled) {
|
|
147
163
|
const id = scheduleIdForFunction(specFunction);
|
|
148
164
|
ctx.existingBackend.schedules.push({
|
|
@@ -221,3 +237,22 @@ async function checkAvailability(context, want) {
|
|
|
221
237
|
}
|
|
222
238
|
}
|
|
223
239
|
exports.checkAvailability = checkAvailability;
|
|
240
|
+
function compareFunctions(left, right) {
|
|
241
|
+
if (left.platform != right.platform) {
|
|
242
|
+
return right.platform < left.platform ? -1 : 1;
|
|
243
|
+
}
|
|
244
|
+
if (left.region < right.region) {
|
|
245
|
+
return -1;
|
|
246
|
+
}
|
|
247
|
+
if (left.region > right.region) {
|
|
248
|
+
return 1;
|
|
249
|
+
}
|
|
250
|
+
if (left.id < right.id) {
|
|
251
|
+
return -1;
|
|
252
|
+
}
|
|
253
|
+
if (left.id > right.id) {
|
|
254
|
+
return 1;
|
|
255
|
+
}
|
|
256
|
+
return 0;
|
|
257
|
+
}
|
|
258
|
+
exports.compareFunctions = compareFunctions;
|
|
@@ -37,10 +37,14 @@ async function retry(func) {
|
|
|
37
37
|
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
38
38
|
const MAX_RETRIES = 3;
|
|
39
39
|
const INITIAL_BACKOFF = 100;
|
|
40
|
+
const TIMEOUT_MS = 10000;
|
|
40
41
|
let retry = 0;
|
|
41
42
|
while (true) {
|
|
42
43
|
try {
|
|
43
|
-
|
|
44
|
+
const timeout = new Promise((resolve, reject) => {
|
|
45
|
+
setTimeout(() => reject(new Error("Timeout")), TIMEOUT_MS);
|
|
46
|
+
});
|
|
47
|
+
return await Promise.race([func(), timeout]);
|
|
44
48
|
}
|
|
45
49
|
catch (error) {
|
|
46
50
|
logger_1.logger.debug("Failed docker command with error", error);
|
|
@@ -37,10 +37,10 @@ async function deploy(context, options, payload) {
|
|
|
37
37
|
if (!options.config.src.functions) {
|
|
38
38
|
return;
|
|
39
39
|
}
|
|
40
|
-
await checkIam_1.checkHttpIam(context, options, payload);
|
|
41
40
|
if (!context.functionsSourceV1 && !context.functionsSourceV2) {
|
|
42
41
|
return;
|
|
43
42
|
}
|
|
43
|
+
await checkIam_1.checkHttpIam(context, options, payload);
|
|
44
44
|
try {
|
|
45
45
|
const want = payload.functions.backend;
|
|
46
46
|
const uploads = [];
|
|
@@ -61,10 +61,12 @@ async function deploy(context, options, payload) {
|
|
|
61
61
|
}
|
|
62
62
|
await Promise.all(uploads);
|
|
63
63
|
utils.assertDefined(options.config.src.functions.source, "Error: 'functions.source' is not defined");
|
|
64
|
-
|
|
65
|
-
"
|
|
66
|
-
|
|
67
|
-
|
|
64
|
+
if (uploads.length) {
|
|
65
|
+
utils_1.logSuccess(clc.green.bold("functions:") +
|
|
66
|
+
" " +
|
|
67
|
+
clc.bold(options.config.src.functions.source) +
|
|
68
|
+
" folder uploaded successfully");
|
|
69
|
+
}
|
|
68
70
|
}
|
|
69
71
|
catch (err) {
|
|
70
72
|
utils_1.logWarning(clc.yellow("functions:") + " Upload Error: " + err.message);
|
|
@@ -18,6 +18,7 @@ const runtimes = require("./runtimes");
|
|
|
18
18
|
const validate = require("./validate");
|
|
19
19
|
const utils = require("../../utils");
|
|
20
20
|
const logger_1 = require("../../logger");
|
|
21
|
+
const triggerRegionHelper_1 = require("./triggerRegionHelper");
|
|
21
22
|
function hasUserConfig(config) {
|
|
22
23
|
return Object.keys(config).length > 1;
|
|
23
24
|
}
|
|
@@ -64,25 +65,25 @@ async function prepare(context, options, payload) {
|
|
|
64
65
|
const wantBackend = await runtimeDelegate.discoverSpec(runtimeConfig, firebaseEnvs);
|
|
65
66
|
wantBackend.environmentVariables = Object.assign(Object.assign({}, userEnvs), firebaseEnvs);
|
|
66
67
|
payload.functions = { backend: wantBackend };
|
|
67
|
-
if (backend.isEmptyBackend(wantBackend)) {
|
|
68
|
-
return;
|
|
69
|
-
}
|
|
70
68
|
if (wantBackend.cloudFunctions.find((f) => f.platform === "gcfv2")) {
|
|
71
69
|
const V2_APIS = {
|
|
72
70
|
artifactregistry: "artifactregistry.googleapis.com",
|
|
73
71
|
cloudrun: "run.googleapis.com",
|
|
74
72
|
eventarc: "eventarc.googleapis.com",
|
|
75
73
|
pubsub: "pubsub.googleapis.com",
|
|
74
|
+
storage: "storage.googleapis.com",
|
|
76
75
|
};
|
|
77
76
|
const enablements = Object.entries(V2_APIS).map(([tag, api]) => {
|
|
78
77
|
return ensureApiEnabled.ensure(context.projectId, api, tag);
|
|
79
78
|
});
|
|
80
79
|
await Promise.all(enablements);
|
|
81
80
|
}
|
|
82
|
-
|
|
83
|
-
"
|
|
84
|
-
|
|
85
|
-
|
|
81
|
+
if (wantBackend.cloudFunctions.length) {
|
|
82
|
+
utils_1.logBullet(clc.cyan.bold("functions:") +
|
|
83
|
+
" preparing " +
|
|
84
|
+
clc.bold(options.config.src.functions.source) +
|
|
85
|
+
" directory for uploading...");
|
|
86
|
+
}
|
|
86
87
|
if (wantBackend.cloudFunctions.find((fn) => fn.platform === "gcfv1")) {
|
|
87
88
|
context.functionsSourceV1 = await prepareFunctionsUpload_1.prepareFunctionsUpload(runtimeConfig, options);
|
|
88
89
|
}
|
|
@@ -101,6 +102,7 @@ async function prepare(context, options, payload) {
|
|
|
101
102
|
return functionsDeployHelper_1.functionMatchesAnyGroup(fn, context.filters);
|
|
102
103
|
});
|
|
103
104
|
const haveFunctions = (await backend.existingBackend(context)).cloudFunctions;
|
|
105
|
+
await triggerRegionHelper_1.setTriggerRegion(wantFunctions, haveFunctions);
|
|
104
106
|
await prompts_1.promptForFailurePolicies(options, wantFunctions, haveFunctions);
|
|
105
107
|
await prompts_1.promptForMinInstances(options, wantFunctions, haveFunctions);
|
|
106
108
|
await backend.checkAvailability(context, wantBackend);
|
|
@@ -9,24 +9,6 @@ const logger_1 = require("../../logger");
|
|
|
9
9
|
const backend = require("./backend");
|
|
10
10
|
const pricing = require("./pricing");
|
|
11
11
|
const utils = require("../../utils");
|
|
12
|
-
function compareFunctions(left, right) {
|
|
13
|
-
if (left.platform != right.platform) {
|
|
14
|
-
return right.platform < left.platform ? -1 : 1;
|
|
15
|
-
}
|
|
16
|
-
if (left.region < right.region) {
|
|
17
|
-
return -1;
|
|
18
|
-
}
|
|
19
|
-
if (left.region > right.region) {
|
|
20
|
-
return 1;
|
|
21
|
-
}
|
|
22
|
-
if (left.id < right.id) {
|
|
23
|
-
return -1;
|
|
24
|
-
}
|
|
25
|
-
if (left.id > right.id) {
|
|
26
|
-
return 1;
|
|
27
|
-
}
|
|
28
|
-
return 0;
|
|
29
|
-
}
|
|
30
12
|
async function promptForFailurePolicies(options, want, have) {
|
|
31
13
|
const retryFunctions = want.filter((fn) => {
|
|
32
14
|
return backend.isEventTrigger(fn.trigger) && fn.trigger.retry;
|
|
@@ -44,7 +26,7 @@ async function promptForFailurePolicies(options, want, have) {
|
|
|
44
26
|
return;
|
|
45
27
|
}
|
|
46
28
|
const warnMessage = "The following functions will newly be retried in case of failure: " +
|
|
47
|
-
clc.bold(newRetryFunctions.sort(compareFunctions).map(functionsDeployHelper_1.getFunctionLabel).join(", ")) +
|
|
29
|
+
clc.bold(newRetryFunctions.sort(backend.compareFunctions).map(functionsDeployHelper_1.getFunctionLabel).join(", ")) +
|
|
48
30
|
". " +
|
|
49
31
|
"Retried executions are billed as any other execution, and functions are retried repeatedly until they either successfully execute or the maximum retry period has elapsed, which can be up to 7 days. " +
|
|
50
32
|
"For safety, you might want to ensure that your functions are idempotent; see https://firebase.google.com/docs/functions/retries to learn more.";
|
|
@@ -74,7 +56,7 @@ async function promptForFunctionDeletion(functionsToDelete, force, nonInteractiv
|
|
|
74
56
|
return true;
|
|
75
57
|
}
|
|
76
58
|
const deleteList = functionsToDelete
|
|
77
|
-
.sort(compareFunctions)
|
|
59
|
+
.sort(backend.compareFunctions)
|
|
78
60
|
.map((fn) => "\t" + functionsDeployHelper_1.getFunctionLabel(fn))
|
|
79
61
|
.join("\n");
|
|
80
62
|
if (nonInteractive) {
|
|
@@ -136,7 +118,7 @@ async function promptForMinInstances(options, want, have) {
|
|
|
136
118
|
}
|
|
137
119
|
const functionLines = want
|
|
138
120
|
.filter((fn) => fn.minInstances)
|
|
139
|
-
.sort(compareFunctions)
|
|
121
|
+
.sort(backend.compareFunctions)
|
|
140
122
|
.map((fn) => {
|
|
141
123
|
return (`\t${functionsDeployHelper_1.getFunctionLabel(fn)}: ${fn.minInstances} instances, ` +
|
|
142
124
|
backend.memoryOptionDisplayName(fn.availableMemoryMb || 256) +
|
|
@@ -15,6 +15,7 @@ function tryValidate(typed) {
|
|
|
15
15
|
var _a, _b;
|
|
16
16
|
parsing_1.assertKeyTypes("", typed, {
|
|
17
17
|
requiredAPIs: "object",
|
|
18
|
+
endpoints: "array",
|
|
18
19
|
cloudFunctions: "array",
|
|
19
20
|
topics: "array",
|
|
20
21
|
schedules: "array",
|
|
@@ -59,7 +60,6 @@ function tryValidate(typed) {
|
|
|
59
60
|
}
|
|
60
61
|
else {
|
|
61
62
|
parsing_1.assertKeyTypes(prefix + ".trigger", func.trigger, {
|
|
62
|
-
allowInsecure: "boolean",
|
|
63
63
|
invoker: "array",
|
|
64
64
|
});
|
|
65
65
|
}
|
|
@@ -115,6 +115,7 @@ function fillDefaults(want, project, region, runtime) {
|
|
|
115
115
|
want.environmentVariables = want.environmentVariables || {};
|
|
116
116
|
want.schedules = want.schedules || [];
|
|
117
117
|
want.topics = want.topics || [];
|
|
118
|
+
want.endpoints = want.endpoints || [];
|
|
118
119
|
for (const cloudFunction of want.cloudFunctions) {
|
|
119
120
|
if (!cloudFunction.project) {
|
|
120
121
|
cloudFunction.project = project;
|
|
@@ -5,7 +5,7 @@ const golang = require("./golang");
|
|
|
5
5
|
const node = require("./node");
|
|
6
6
|
const validate = require("../validate");
|
|
7
7
|
const error_1 = require("../../../error");
|
|
8
|
-
const RUNTIMES = ["nodejs10", "nodejs12", "nodejs14"];
|
|
8
|
+
const RUNTIMES = ["nodejs10", "nodejs12", "nodejs14", "nodejs16"];
|
|
9
9
|
const EXPERIMENTAL_RUNTIMES = ["go113"];
|
|
10
10
|
const DEPRECATED_RUNTIMES = ["nodejs6", "nodejs8"];
|
|
11
11
|
function isDeprecatedRuntime(runtime) {
|
|
@@ -22,6 +22,7 @@ const MESSAGE_FRIENDLY_RUNTIMES = {
|
|
|
22
22
|
nodejs10: "Node.js 10",
|
|
23
23
|
nodejs12: "Node.js 12",
|
|
24
24
|
nodejs14: "Node.js 14",
|
|
25
|
+
nodejs16: "Node.js 16",
|
|
25
26
|
go113: "Go 1.13",
|
|
26
27
|
};
|
|
27
28
|
function getHumanFriendlyRuntimeName(runtime) {
|
|
@@ -13,17 +13,18 @@ const ENGINE_RUNTIMES = {
|
|
|
13
13
|
10: "nodejs10",
|
|
14
14
|
12: "nodejs12",
|
|
15
15
|
14: "nodejs14",
|
|
16
|
+
16: "nodejs16",
|
|
16
17
|
};
|
|
17
18
|
const ENGINE_RUNTIMES_NAMES = Object.values(ENGINE_RUNTIMES);
|
|
18
19
|
exports.RUNTIME_NOT_SET = "`runtime` field is required but was not found in firebase.json.\n" +
|
|
19
20
|
"To fix this, add the following lines to the `functions` section of your firebase.json:\n" +
|
|
20
21
|
'"runtime": "nodejs14"\n';
|
|
21
22
|
exports.UNSUPPORTED_NODE_VERSION_FIREBASE_JSON_MSG = clc.bold(`functions.runtime value is unsupported. ` +
|
|
22
|
-
`Valid choices are: ${clc.bold("
|
|
23
|
+
`Valid choices are: ${clc.bold("nodejs{10|12|14|16}")}.`);
|
|
23
24
|
exports.UNSUPPORTED_NODE_VERSION_PACKAGE_JSON_MSG = clc.bold(`package.json in functions directory has an engines field which is unsupported. ` +
|
|
24
|
-
`Valid choices are: ${clc.bold('{"node":
|
|
25
|
+
`Valid choices are: ${clc.bold('{"node": 10|12|14|16}')}`);
|
|
25
26
|
exports.DEPRECATED_NODE_VERSION_INFO = `\n\nDeploys to runtimes below Node.js 10 are now disabled in the Firebase CLI. ` +
|
|
26
|
-
`${clc.bold(`Existing Node.js 8 functions ${clc.underline("will stop executing
|
|
27
|
+
`${clc.bold(`Existing Node.js 8 functions ${clc.underline("will stop executing at a future date")}`)}. Update existing functions to Node.js 10 or greater as soon as possible.`;
|
|
27
28
|
function getRuntimeChoiceFromPackageJson(sourceDir) {
|
|
28
29
|
const packageJsonPath = path.join(sourceDir, "package.json");
|
|
29
30
|
let loaded;
|
|
@@ -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,6 +64,7 @@ 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
70
|
let trigger;
|
|
@@ -65,14 +72,7 @@ function addResourcesToBackend(projectId, runtime, annotation, want) {
|
|
|
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
|
+
trigger = {};
|
|
76
76
|
if (annotation.failurePolicy) {
|
|
77
77
|
logger_1.logger.warn(`Ignoring retry policy for HTTPS function ${annotation.name}`);
|
|
78
78
|
}
|
|
@@ -86,6 +86,11 @@ function addResourcesToBackend(projectId, runtime, annotation, want) {
|
|
|
86
86
|
},
|
|
87
87
|
retry: !!annotation.failurePolicy,
|
|
88
88
|
};
|
|
89
|
+
if (exports.GCS_EVENTS.has(((_a = annotation.eventTrigger) === null || _a === void 0 ? void 0 : _a.eventType) || "")) {
|
|
90
|
+
trigger.eventFilters = {
|
|
91
|
+
bucket: annotation.eventTrigger.resource,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
89
94
|
}
|
|
90
95
|
const cloudFunctionName = {
|
|
91
96
|
id: annotation.name,
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.setTriggerRegion = void 0;
|
|
4
|
+
const backend = require("./backend");
|
|
5
|
+
const storage = require("../../gcp/storage");
|
|
6
|
+
const error_1 = require("../../error");
|
|
7
|
+
async function setTriggerRegion(want, have) {
|
|
8
|
+
var _a;
|
|
9
|
+
for (const wantFn of want) {
|
|
10
|
+
if (wantFn.platform === "gcfv1" || !backend.isEventTrigger(wantFn.trigger)) {
|
|
11
|
+
continue;
|
|
12
|
+
}
|
|
13
|
+
const match = (_a = have.find(backend.sameFunctionName(wantFn))) === null || _a === void 0 ? void 0 : _a.trigger;
|
|
14
|
+
if (match === null || match === void 0 ? void 0 : match.region) {
|
|
15
|
+
wantFn.trigger.region = match.region;
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
18
|
+
await setTriggerRegionFromTriggerType(wantFn.trigger);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
exports.setTriggerRegion = setTriggerRegion;
|
|
23
|
+
async function setTriggerRegionFromTriggerType(trigger) {
|
|
24
|
+
if (trigger.eventFilters.bucket) {
|
|
25
|
+
try {
|
|
26
|
+
trigger.region = (await storage.getBucket(trigger.eventFilters.bucket)).location.toLowerCase();
|
|
27
|
+
}
|
|
28
|
+
catch (err) {
|
|
29
|
+
throw new error_1.FirebaseError("Can't find the storage bucket region", { original: err });
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -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;
|