firebase-tools 9.19.0 → 9.23.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 +3 -0
- package/lib/apiv2.js +7 -4
- package/lib/commands/crashlytics-symbols-upload.js +146 -0
- package/lib/commands/deploy.js +9 -1
- package/lib/commands/ext-configure.js +3 -1
- package/lib/commands/ext-dev-deprecate.js +63 -0
- package/lib/commands/ext-dev-undeprecate.js +56 -0
- package/lib/commands/ext-dev-unpublish.js +10 -3
- package/lib/commands/ext-export.js +44 -0
- package/lib/commands/ext-install.js +24 -3
- package/lib/commands/ext-uninstall.js +6 -0
- package/lib/commands/ext-update.js +10 -3
- 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/params.js +39 -0
- package/lib/deploy/extensions/planner.js +94 -0
- package/lib/deploy/extensions/prepare.js +111 -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 +71 -14
- package/lib/deploy/functions/deploy.js +4 -10
- package/lib/deploy/functions/functionsDeployHelper.js +3 -68
- package/lib/deploy/functions/prepare.js +63 -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 +10 -1
- package/lib/downloadUtils.js +37 -0
- package/lib/emulator/auth/apiSpec.js +549 -6
- package/lib/emulator/auth/handlers.js +4 -3
- package/lib/emulator/auth/operations.js +154 -14
- package/lib/emulator/auth/server.js +26 -15
- package/lib/emulator/auth/state.js +151 -13
- package/lib/emulator/download.js +2 -31
- package/lib/emulator/downloadableEmulators.js +7 -7
- package/lib/emulator/functionsEmulator.js +18 -4
- package/lib/emulator/functionsEmulatorRuntime.js +29 -7
- 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/checkProjectBilling.js +7 -7
- package/lib/extensions/export.js +107 -0
- package/lib/extensions/extensionsApi.js +104 -21
- package/lib/extensions/extensionsHelper.js +6 -2
- package/lib/extensions/listExtensions.js +16 -11
- package/lib/extensions/paramHelper.js +9 -6
- package/lib/extensions/provisioningHelper.js +16 -3
- package/lib/extensions/refs.js +9 -1
- package/lib/extensions/secretsUtils.js +59 -0
- package/lib/extensions/updateHelper.js +12 -2
- package/lib/extensions/versionHelper.js +14 -0
- package/lib/extensions/warnings.js +33 -1
- package/lib/functional.js +8 -1
- package/lib/functions/env.js +10 -4
- package/lib/functions/runtimeConfigExport.js +137 -0
- package/lib/gcp/artifactregistry.js +16 -0
- package/lib/gcp/cloudfunctions.js +20 -74
- package/lib/gcp/cloudfunctionsv2.js +12 -90
- 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/projectUtils.js +10 -1
- package/lib/requireInteractive.js +12 -0
- package/lib/utils.js +30 -1
- package/package.json +5 -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,12 +1,15 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.displayWarningPrompts = void 0;
|
|
3
|
+
exports.displayWarningsForDeploy = exports.displayWarningPrompts = void 0;
|
|
4
4
|
const marked = require("marked");
|
|
5
5
|
const clc = require("cli-color");
|
|
6
6
|
const extensionsApi_1 = require("./extensionsApi");
|
|
7
7
|
const displayExtensionInfo_1 = require("./displayExtensionInfo");
|
|
8
8
|
const extensionsHelper_1 = require("./extensionsHelper");
|
|
9
9
|
const resolveSource_1 = require("./resolveSource");
|
|
10
|
+
const deploymentSummary_1 = require("../deploy/extensions/deploymentSummary");
|
|
11
|
+
const planner_1 = require("../deploy/extensions/planner");
|
|
12
|
+
const functional_1 = require("../functional");
|
|
10
13
|
const utils = require("../utils");
|
|
11
14
|
function displayEAPWarning({ publisherId, sourceDownloadUri, githubLink, }) {
|
|
12
15
|
const publisherNameLink = githubLink ? `[${publisherId}](${githubLink})` : publisherId;
|
|
@@ -35,3 +38,32 @@ async function displayWarningPrompts(publisherId, launchStage, extensionVersion)
|
|
|
35
38
|
}
|
|
36
39
|
}
|
|
37
40
|
exports.displayWarningPrompts = displayWarningPrompts;
|
|
41
|
+
const toListEntry = (i) => {
|
|
42
|
+
var _a, _b, _c, _d;
|
|
43
|
+
const idAndRef = deploymentSummary_1.humanReadable(i);
|
|
44
|
+
const sourceCodeLink = `\n\t[Source Code](${(_a = i.extensionVersion) === null || _a === void 0 ? void 0 : _a.sourceDownloadUri})`;
|
|
45
|
+
const githubLink = ((_c = (_b = i.extensionVersion) === null || _b === void 0 ? void 0 : _b.spec) === null || _c === void 0 ? void 0 : _c.sourceUrl) ? `\n\t[Publisher Contact](${(_d = i.extensionVersion) === null || _d === void 0 ? void 0 : _d.spec.sourceUrl})`
|
|
46
|
+
: "";
|
|
47
|
+
return `${idAndRef}${sourceCodeLink}${githubLink}`;
|
|
48
|
+
};
|
|
49
|
+
async function displayWarningsForDeploy(instancesToCreate) {
|
|
50
|
+
const trustedPublishers = await resolveSource_1.getTrustedPublishers();
|
|
51
|
+
for (const i of instancesToCreate) {
|
|
52
|
+
await planner_1.getExtension(i);
|
|
53
|
+
await planner_1.getExtensionVersion(i);
|
|
54
|
+
}
|
|
55
|
+
const [eapExtensions, nonEapExtensions] = functional_1.partition(instancesToCreate, (i) => { var _a, _b; return !trustedPublishers.includes((_b = (_a = i.ref) === null || _a === void 0 ? void 0 : _a.publisherId) !== null && _b !== void 0 ? _b : ""); });
|
|
56
|
+
const experimental = nonEapExtensions.filter((i) => i.extension.registryLaunchStage === extensionsApi_1.RegistryLaunchStage.EXPERIMENTAL);
|
|
57
|
+
if (experimental.length) {
|
|
58
|
+
const humanReadableList = experimental.map((i) => `\t${deploymentSummary_1.humanReadable(i)}`).join("\n");
|
|
59
|
+
utils.logLabeledBullet(extensionsHelper_1.logPrefix, marked(`The following are instances of ${clc.bold("experimental")} extensions.They may not be production-ready. Their functionality may change in backward-incompatible ways before their official release, or they may be discontinued.\n${humanReadableList}\n`));
|
|
60
|
+
}
|
|
61
|
+
if (eapExtensions.length) {
|
|
62
|
+
const humanReadableList = eapExtensions.map(toListEntry).join("\n");
|
|
63
|
+
utils.logLabeledBullet(extensionsHelper_1.logPrefix, marked(`These extensions are in preview and are built by a developer in the Extensions Publisher Early Access Program (http://bit.ly/firex-provider. Their functionality might change in backwards-incompatible ways. Since these extensions aren't built by Firebase, reach out to their publisher with questions about them.` +
|
|
64
|
+
` They are provided “AS IS”, without any warranty, express or implied, from Google.` +
|
|
65
|
+
` Google disclaims all liability for any damages, direct or indirect, resulting from the use of these extensions\n${humanReadableList}`));
|
|
66
|
+
}
|
|
67
|
+
return experimental.length > 0 || eapExtensions.length > 0;
|
|
68
|
+
}
|
|
69
|
+
exports.displayWarningsForDeploy = displayWarningsForDeploy;
|
package/lib/functional.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.assertExhaustive = exports.zipIn = exports.zip = exports.reduceFlat = exports.flatten = exports.flattenArray = exports.flattenObject = void 0;
|
|
3
|
+
exports.partition = exports.assertExhaustive = exports.zipIn = exports.zip = exports.reduceFlat = exports.flatten = exports.flattenArray = exports.flattenObject = void 0;
|
|
4
4
|
function* flattenObject(obj) {
|
|
5
5
|
function* helper(path, obj) {
|
|
6
6
|
for (const [k, v] of Object.entries(obj)) {
|
|
@@ -55,3 +55,10 @@ function assertExhaustive(val) {
|
|
|
55
55
|
throw new Error(`Never has a value (${val}). This should be impossible`);
|
|
56
56
|
}
|
|
57
57
|
exports.assertExhaustive = assertExhaustive;
|
|
58
|
+
function partition(arr, callbackFn) {
|
|
59
|
+
return arr.reduce((acc, elem) => {
|
|
60
|
+
acc[callbackFn(elem) ? 0 : 1].push(elem);
|
|
61
|
+
return acc;
|
|
62
|
+
}, [[], []]);
|
|
63
|
+
}
|
|
64
|
+
exports.partition = partition;
|
package/lib/functions/env.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.loadFirebaseEnvs = exports.loadUserEnvs = exports.hasUserEnvs = exports.validateKey = exports.parse = void 0;
|
|
3
|
+
exports.loadFirebaseEnvs = exports.loadUserEnvs = exports.hasUserEnvs = exports.validateKey = exports.KeyValidationError = exports.parse = void 0;
|
|
4
4
|
const clc = require("cli-color");
|
|
5
5
|
const fs = require("fs");
|
|
6
6
|
const path = require("path");
|
|
@@ -72,17 +72,23 @@ function parse(data) {
|
|
|
72
72
|
}
|
|
73
73
|
exports.parse = parse;
|
|
74
74
|
class KeyValidationError extends Error {
|
|
75
|
+
constructor(key, message) {
|
|
76
|
+
super(`Failed to validate key ${key}: ${message}`);
|
|
77
|
+
this.key = key;
|
|
78
|
+
this.message = message;
|
|
79
|
+
}
|
|
75
80
|
}
|
|
81
|
+
exports.KeyValidationError = KeyValidationError;
|
|
76
82
|
function validateKey(key) {
|
|
77
83
|
if (RESERVED_KEYS.includes(key)) {
|
|
78
|
-
throw new KeyValidationError(`Key ${key} is reserved for internal use.`);
|
|
84
|
+
throw new KeyValidationError(key, `Key ${key} is reserved for internal use.`);
|
|
79
85
|
}
|
|
80
86
|
if (!/^[A-Z_][A-Z0-9_]*$/.test(key)) {
|
|
81
|
-
throw new KeyValidationError(`Key ${key} must start with an uppercase ASCII letter or underscore` +
|
|
87
|
+
throw new KeyValidationError(key, `Key ${key} must start with an uppercase ASCII letter or underscore` +
|
|
82
88
|
", and then consist of uppercase ASCII letters, digits, and underscores.");
|
|
83
89
|
}
|
|
84
90
|
if (key.startsWith("X_GOOGLE_") || key.startsWith("FIREBASE_")) {
|
|
85
|
-
throw new KeyValidationError(`Key ${key} starts with a reserved prefix (X_GOOGLE_ or FIREBASE_)`);
|
|
91
|
+
throw new KeyValidationError(key, `Key ${key} starts with a reserved prefix (X_GOOGLE_ or FIREBASE_)`);
|
|
86
92
|
}
|
|
87
93
|
}
|
|
88
94
|
exports.validateKey = validateKey;
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generateDotenvFilename = exports.toDotenvFormat = exports.hydrateEnvs = exports.configToEnv = exports.convertKey = exports.hydrateConfigs = exports.getProjectInfos = void 0;
|
|
4
|
+
const clc = require("cli-color");
|
|
5
|
+
const env = require("./env");
|
|
6
|
+
const functionsConfig = require("../functionsConfig");
|
|
7
|
+
const error_1 = require("../error");
|
|
8
|
+
const logger_1 = require("../logger");
|
|
9
|
+
const projectUtils_1 = require("../projectUtils");
|
|
10
|
+
const rc_1 = require("../rc");
|
|
11
|
+
const utils_1 = require("../utils");
|
|
12
|
+
const functional_1 = require("../functional");
|
|
13
|
+
function getProjectInfos(options) {
|
|
14
|
+
const result = {};
|
|
15
|
+
const rc = rc_1.loadRC(options);
|
|
16
|
+
if (rc.projects) {
|
|
17
|
+
for (const [alias, projectId] of Object.entries(rc.projects)) {
|
|
18
|
+
if (Object.keys(result).includes(projectId)) {
|
|
19
|
+
utils_1.logWarning(`Multiple aliases found for ${clc.bold(projectId)}. ` +
|
|
20
|
+
`Preferring alias (${clc.bold(result[projectId])}) over (${clc.bold(alias)}).`);
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
result[projectId] = alias;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
const projectId = projectUtils_1.getProjectId(options);
|
|
27
|
+
if (projectId && !Object.keys(result).includes(projectId)) {
|
|
28
|
+
result[projectId] = projectId;
|
|
29
|
+
}
|
|
30
|
+
return Object.entries(result).map(([k, v]) => {
|
|
31
|
+
const result = { projectId: k };
|
|
32
|
+
if (k !== v) {
|
|
33
|
+
result.alias = v;
|
|
34
|
+
}
|
|
35
|
+
return result;
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
exports.getProjectInfos = getProjectInfos;
|
|
39
|
+
async function hydrateConfigs(pInfos) {
|
|
40
|
+
const hydrate = pInfos.map((info) => {
|
|
41
|
+
return functionsConfig
|
|
42
|
+
.materializeAll(info.projectId)
|
|
43
|
+
.then((config) => {
|
|
44
|
+
info.config = config;
|
|
45
|
+
return;
|
|
46
|
+
})
|
|
47
|
+
.catch((err) => {
|
|
48
|
+
logger_1.logger.debug(`Failed to fetch runtime config for project ${info.projectId}: ${err.message}`);
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
await Promise.all(hydrate);
|
|
52
|
+
}
|
|
53
|
+
exports.hydrateConfigs = hydrateConfigs;
|
|
54
|
+
function convertKey(configKey, prefix) {
|
|
55
|
+
const baseKey = configKey
|
|
56
|
+
.toUpperCase()
|
|
57
|
+
.replace(/\./g, "_")
|
|
58
|
+
.replace(/-/g, "_");
|
|
59
|
+
let envKey = baseKey;
|
|
60
|
+
try {
|
|
61
|
+
env.validateKey(envKey);
|
|
62
|
+
}
|
|
63
|
+
catch (err) {
|
|
64
|
+
if (err instanceof env.KeyValidationError) {
|
|
65
|
+
envKey = prefix + envKey;
|
|
66
|
+
env.validateKey(envKey);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return envKey;
|
|
70
|
+
}
|
|
71
|
+
exports.convertKey = convertKey;
|
|
72
|
+
function configToEnv(configs, prefix) {
|
|
73
|
+
const success = [];
|
|
74
|
+
const errors = [];
|
|
75
|
+
for (const [configKey, value] of functional_1.flatten(configs)) {
|
|
76
|
+
try {
|
|
77
|
+
const envKey = convertKey(configKey, prefix);
|
|
78
|
+
success.push({ origKey: configKey, newKey: envKey, value: value });
|
|
79
|
+
}
|
|
80
|
+
catch (err) {
|
|
81
|
+
if (err instanceof env.KeyValidationError) {
|
|
82
|
+
errors.push({
|
|
83
|
+
origKey: configKey,
|
|
84
|
+
newKey: err.key,
|
|
85
|
+
err: err.message,
|
|
86
|
+
value: value,
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
throw new error_1.FirebaseError("Unexpected error while converting config", {
|
|
91
|
+
exit: 2,
|
|
92
|
+
original: err,
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return { success, errors };
|
|
98
|
+
}
|
|
99
|
+
exports.configToEnv = configToEnv;
|
|
100
|
+
function hydrateEnvs(pInfos, prefix) {
|
|
101
|
+
let errMsg = "";
|
|
102
|
+
for (const pInfo of pInfos) {
|
|
103
|
+
const { success, errors } = configToEnv(pInfo.config, prefix);
|
|
104
|
+
if (errors.length > 0) {
|
|
105
|
+
const msg = `${pInfo.projectId} ` +
|
|
106
|
+
`${pInfo.alias ? "(" + pInfo.alias + ")" : ""}:\n` +
|
|
107
|
+
errors.map((err) => `\t${err.origKey} => ${clc.bold(err.newKey)} (${err.err})`).join("\n") +
|
|
108
|
+
"\n";
|
|
109
|
+
errMsg += msg;
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
pInfo.envs = success;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return errMsg;
|
|
116
|
+
}
|
|
117
|
+
exports.hydrateEnvs = hydrateEnvs;
|
|
118
|
+
function escape(s) {
|
|
119
|
+
const result = s
|
|
120
|
+
.replace("\n", "\\n")
|
|
121
|
+
.replace("\r", "\\r")
|
|
122
|
+
.replace("\t", "\\t")
|
|
123
|
+
.replace("\v", "\\v");
|
|
124
|
+
return result.replace(/(['"])/g, "\\$1");
|
|
125
|
+
}
|
|
126
|
+
function toDotenvFormat(envs, header = "") {
|
|
127
|
+
const lines = envs.map(({ newKey, value }) => `${newKey}="${escape(value)}"`);
|
|
128
|
+
const maxLineLen = Math.max(...lines.map((l) => l.length));
|
|
129
|
+
return (`${header}\n` +
|
|
130
|
+
lines.map((line, idx) => `${line.padEnd(maxLineLen)} # from ${envs[idx].origKey}`).join("\n"));
|
|
131
|
+
}
|
|
132
|
+
exports.toDotenvFormat = toDotenvFormat;
|
|
133
|
+
function generateDotenvFilename(pInfo) {
|
|
134
|
+
var _a;
|
|
135
|
+
return `.env.${(_a = pInfo.alias) !== null && _a !== void 0 ? _a : pInfo.projectId}`;
|
|
136
|
+
}
|
|
137
|
+
exports.generateDotenvFilename = generateDotenvFilename;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.deletePackage = exports.API_VERSION = void 0;
|
|
4
|
+
const apiv2_1 = require("../apiv2");
|
|
5
|
+
const api_1 = require("../api");
|
|
6
|
+
exports.API_VERSION = "v1beta2";
|
|
7
|
+
const client = new apiv2_1.Client({
|
|
8
|
+
urlPrefix: api_1.artifactRegistryDomain,
|
|
9
|
+
auth: true,
|
|
10
|
+
apiVersion: exports.API_VERSION,
|
|
11
|
+
});
|
|
12
|
+
async function deletePackage(name) {
|
|
13
|
+
const res = await client.delete(name);
|
|
14
|
+
return res.body;
|
|
15
|
+
}
|
|
16
|
+
exports.deletePackage = deletePackage;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.functionFromEndpoint = exports.endpointFromFunction = 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");
|
|
@@ -51,6 +51,7 @@ async function createFunction(cloudFunction) {
|
|
|
51
51
|
const endpoint = `/${exports.API_VERSION}/${apiPath}`;
|
|
52
52
|
try {
|
|
53
53
|
const res = await api.request("POST", endpoint, {
|
|
54
|
+
headers: { "X-Firebase-Artifact-Registry": "optin" },
|
|
54
55
|
auth: true,
|
|
55
56
|
data: cloudFunction,
|
|
56
57
|
origin: api.functionsOrigin,
|
|
@@ -146,6 +147,7 @@ async function updateFunction(cloudFunction) {
|
|
|
146
147
|
const fieldMasks = proto.fieldMasks(cloudFunction, "labels", "environmentVariables");
|
|
147
148
|
try {
|
|
148
149
|
const res = await api.request("PATCH", endpoint, {
|
|
150
|
+
headers: { "X-Firebase-Artifact-Registry": "optin" },
|
|
149
151
|
qs: {
|
|
150
152
|
updateMask: fieldMasks.join(","),
|
|
151
153
|
},
|
|
@@ -198,9 +200,11 @@ async function list(projectId, region) {
|
|
|
198
200
|
};
|
|
199
201
|
}
|
|
200
202
|
catch (err) {
|
|
201
|
-
logger_1.logger.debug(
|
|
203
|
+
logger_1.logger.debug(`[functions] failed to list functions for ${projectId}`);
|
|
202
204
|
logger_1.logger.debug(`[functions] ${err === null || err === void 0 ? void 0 : err.message}`);
|
|
203
|
-
|
|
205
|
+
throw new error_1.FirebaseError(`Failed to list functions for ${projectId}`, {
|
|
206
|
+
original: err,
|
|
207
|
+
});
|
|
204
208
|
}
|
|
205
209
|
}
|
|
206
210
|
async function listFunctions(projectId, region) {
|
|
@@ -212,87 +216,25 @@ async function listAllFunctions(projectId) {
|
|
|
212
216
|
return list(projectId, "-");
|
|
213
217
|
}
|
|
214
218
|
exports.listAllFunctions = listAllFunctions;
|
|
215
|
-
function
|
|
216
|
-
var _a;
|
|
219
|
+
function endpointFromFunction(gcfFunction) {
|
|
220
|
+
var _a, _b, _c;
|
|
217
221
|
const [, project, , region, , id] = gcfFunction.name.split("/");
|
|
218
222
|
let trigger;
|
|
219
223
|
let uri;
|
|
220
|
-
if (gcfFunction.
|
|
221
|
-
trigger = {};
|
|
222
|
-
uri = gcfFunction.httpsTrigger.url;
|
|
223
|
-
}
|
|
224
|
-
else {
|
|
224
|
+
if ((_a = gcfFunction.labels) === null || _a === void 0 ? void 0 : _a["deployment-scheduled"]) {
|
|
225
225
|
trigger = {
|
|
226
|
-
|
|
227
|
-
eventFilters: {
|
|
228
|
-
resource: gcfFunction.eventTrigger.resource,
|
|
229
|
-
},
|
|
230
|
-
retry: !!((_a = gcfFunction.eventTrigger.failurePolicy) === null || _a === void 0 ? void 0 : _a.retry),
|
|
226
|
+
scheduleTrigger: {},
|
|
231
227
|
};
|
|
232
228
|
}
|
|
233
|
-
if (
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
const cloudFunction = {
|
|
237
|
-
platform: "gcfv1",
|
|
238
|
-
id,
|
|
239
|
-
project,
|
|
240
|
-
region,
|
|
241
|
-
trigger,
|
|
242
|
-
entryPoint: gcfFunction.entryPoint,
|
|
243
|
-
runtime: gcfFunction.runtime,
|
|
244
|
-
};
|
|
245
|
-
if (uri) {
|
|
246
|
-
cloudFunction.uri = uri;
|
|
247
|
-
}
|
|
248
|
-
proto.copyIfPresent(cloudFunction, gcfFunction, "serviceAccountEmail", "availableMemoryMb", "timeout", "minInstances", "maxInstances", "vpcConnector", "vpcConnectorEgressSettings", "ingressSettings", "labels", "environmentVariables", "sourceUploadUrl");
|
|
249
|
-
return cloudFunction;
|
|
250
|
-
}
|
|
251
|
-
exports.specFromFunction = specFromFunction;
|
|
252
|
-
function functionFromSpec(cloudFunction, sourceUploadUrl) {
|
|
253
|
-
if (cloudFunction.platform != "gcfv1") {
|
|
254
|
-
throw new error_1.FirebaseError("Trying to create a v1 CloudFunction with v2 API. This should never happen");
|
|
255
|
-
}
|
|
256
|
-
if (!runtimes.isValidRuntime(cloudFunction.runtime)) {
|
|
257
|
-
throw new error_1.FirebaseError("Failed internal assertion. Trying to deploy a new function with a deprecated runtime." +
|
|
258
|
-
" This should never happen");
|
|
259
|
-
}
|
|
260
|
-
const gcfFunction = {
|
|
261
|
-
name: backend.functionName(cloudFunction),
|
|
262
|
-
sourceUploadUrl: sourceUploadUrl,
|
|
263
|
-
entryPoint: cloudFunction.entryPoint,
|
|
264
|
-
runtime: cloudFunction.runtime,
|
|
265
|
-
};
|
|
266
|
-
if (backend.isEventTrigger(cloudFunction.trigger)) {
|
|
267
|
-
gcfFunction.eventTrigger = {
|
|
268
|
-
eventType: cloudFunction.trigger.eventType,
|
|
269
|
-
resource: cloudFunction.trigger.eventFilters.resource,
|
|
229
|
+
else if ((_b = gcfFunction.labels) === null || _b === void 0 ? void 0 : _b["deployment-taskqueue"]) {
|
|
230
|
+
trigger = {
|
|
231
|
+
taskQueueTrigger: {},
|
|
270
232
|
};
|
|
271
|
-
gcfFunction.eventTrigger.failurePolicy = cloudFunction.trigger.retry
|
|
272
|
-
? { retry: {} }
|
|
273
|
-
: undefined;
|
|
274
233
|
}
|
|
275
|
-
else {
|
|
276
|
-
gcfFunction.httpsTrigger = {};
|
|
277
|
-
}
|
|
278
|
-
proto.copyIfPresent(gcfFunction, cloudFunction, "serviceAccountEmail", "timeout", "availableMemoryMb", "minInstances", "maxInstances", "vpcConnector", "vpcConnectorEgressSettings", "ingressSettings", "labels", "environmentVariables");
|
|
279
|
-
return gcfFunction;
|
|
280
|
-
}
|
|
281
|
-
exports.functionFromSpec = functionFromSpec;
|
|
282
|
-
function endpointFromFunction(gcfFunction) {
|
|
283
|
-
var _a, _b;
|
|
284
|
-
const [, project, , region, , id] = gcfFunction.name.split("/");
|
|
285
|
-
let trigger;
|
|
286
|
-
let uri;
|
|
287
|
-
if (gcfFunction.httpsTrigger) {
|
|
234
|
+
else if (gcfFunction.httpsTrigger) {
|
|
288
235
|
trigger = { httpsTrigger: {} };
|
|
289
236
|
uri = gcfFunction.httpsTrigger.url;
|
|
290
237
|
}
|
|
291
|
-
else if ((_a = gcfFunction.labels) === null || _a === void 0 ? void 0 : _a["deployment-scheduled"]) {
|
|
292
|
-
trigger = {
|
|
293
|
-
scheduleTrigger: {},
|
|
294
|
-
};
|
|
295
|
-
}
|
|
296
238
|
else {
|
|
297
239
|
trigger = {
|
|
298
240
|
eventTrigger: {
|
|
@@ -300,7 +242,7 @@ function endpointFromFunction(gcfFunction) {
|
|
|
300
242
|
eventFilters: {
|
|
301
243
|
resource: gcfFunction.eventTrigger.resource,
|
|
302
244
|
},
|
|
303
|
-
retry: !!((
|
|
245
|
+
retry: !!((_c = gcfFunction.eventTrigger.failurePolicy) === null || _c === void 0 ? void 0 : _c.retry),
|
|
304
246
|
},
|
|
305
247
|
};
|
|
306
248
|
}
|
|
@@ -349,6 +291,10 @@ function functionFromEndpoint(endpoint, sourceUploadUrl) {
|
|
|
349
291
|
};
|
|
350
292
|
gcfFunction.labels = Object.assign(Object.assign({}, gcfFunction.labels), { "deployment-scheduled": "true" });
|
|
351
293
|
}
|
|
294
|
+
else if (backend.isTaskQueueTriggered(endpoint)) {
|
|
295
|
+
gcfFunction.httpsTrigger = {};
|
|
296
|
+
gcfFunction.labels = Object.assign(Object.assign({}, gcfFunction.labels), { "deployment-taskqueue": "true" });
|
|
297
|
+
}
|
|
352
298
|
else {
|
|
353
299
|
gcfFunction.httpsTrigger = {};
|
|
354
300
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.endpointFromFunction = exports.functionFromEndpoint = 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,93 +115,6 @@ async function deleteFunction(cloudFunction) {
|
|
|
115
115
|
}
|
|
116
116
|
}
|
|
117
117
|
exports.deleteFunction = deleteFunction;
|
|
118
|
-
function functionFromSpec(cloudFunction, source) {
|
|
119
|
-
if (cloudFunction.platform != "gcfv2") {
|
|
120
|
-
throw new error_1.FirebaseError("Trying to create a v2 CloudFunction with v1 API. This should never happen");
|
|
121
|
-
}
|
|
122
|
-
if (!runtimes.isValidRuntime(cloudFunction.runtime)) {
|
|
123
|
-
throw new error_1.FirebaseError("Failed internal assertion. Trying to deploy a new function with a deprecated runtime." +
|
|
124
|
-
" This should never happen");
|
|
125
|
-
}
|
|
126
|
-
const gcfFunction = {
|
|
127
|
-
name: backend.functionName(cloudFunction),
|
|
128
|
-
buildConfig: {
|
|
129
|
-
runtime: cloudFunction.runtime,
|
|
130
|
-
entryPoint: cloudFunction.entryPoint,
|
|
131
|
-
source: {
|
|
132
|
-
storageSource: source,
|
|
133
|
-
},
|
|
134
|
-
environmentVariables: {},
|
|
135
|
-
},
|
|
136
|
-
serviceConfig: {},
|
|
137
|
-
};
|
|
138
|
-
proto.copyIfPresent(gcfFunction.serviceConfig, cloudFunction, "availableMemoryMb", "environmentVariables", "vpcConnector", "vpcConnectorEgressSettings", "serviceAccountEmail", "ingressSettings");
|
|
139
|
-
proto.renameIfPresent(gcfFunction.serviceConfig, cloudFunction, "timeoutSeconds", "timeout", proto.secondsFromDuration);
|
|
140
|
-
proto.renameIfPresent(gcfFunction.serviceConfig, cloudFunction, "minInstanceCount", "minInstances");
|
|
141
|
-
proto.renameIfPresent(gcfFunction.serviceConfig, cloudFunction, "maxInstanceCount", "maxInstances");
|
|
142
|
-
if (backend.isEventTrigger(cloudFunction.trigger)) {
|
|
143
|
-
gcfFunction.eventTrigger = {
|
|
144
|
-
eventType: cloudFunction.trigger.eventType,
|
|
145
|
-
};
|
|
146
|
-
if (gcfFunction.eventTrigger.eventType === exports.PUBSUB_PUBLISH_EVENT) {
|
|
147
|
-
gcfFunction.eventTrigger.pubsubTopic = cloudFunction.trigger.eventFilters.resource;
|
|
148
|
-
}
|
|
149
|
-
else {
|
|
150
|
-
gcfFunction.eventTrigger.eventFilters = [];
|
|
151
|
-
for (const [attribute, value] of Object.entries(cloudFunction.trigger.eventFilters)) {
|
|
152
|
-
gcfFunction.eventTrigger.eventFilters.push({ attribute, value });
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
if (cloudFunction.trigger.retry) {
|
|
156
|
-
logger_1.logger.warn("Cannot set a retry policy on Cloud Function", cloudFunction.id);
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
proto.copyIfPresent(gcfFunction, cloudFunction, "labels");
|
|
160
|
-
return gcfFunction;
|
|
161
|
-
}
|
|
162
|
-
exports.functionFromSpec = functionFromSpec;
|
|
163
|
-
function specFromFunction(gcfFunction) {
|
|
164
|
-
const [, project, , region, , id] = gcfFunction.name.split("/");
|
|
165
|
-
let trigger;
|
|
166
|
-
if (gcfFunction.eventTrigger) {
|
|
167
|
-
trigger = {
|
|
168
|
-
eventType: gcfFunction.eventTrigger.eventType,
|
|
169
|
-
eventFilters: {},
|
|
170
|
-
retry: false,
|
|
171
|
-
};
|
|
172
|
-
if (gcfFunction.eventTrigger.pubsubTopic) {
|
|
173
|
-
trigger.eventFilters.resource = gcfFunction.eventTrigger.pubsubTopic;
|
|
174
|
-
}
|
|
175
|
-
else {
|
|
176
|
-
for (const { attribute, value } of gcfFunction.eventTrigger.eventFilters || []) {
|
|
177
|
-
trigger.eventFilters[attribute] = value;
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
else {
|
|
182
|
-
trigger = {};
|
|
183
|
-
}
|
|
184
|
-
if (!runtimes.isValidRuntime(gcfFunction.buildConfig.runtime)) {
|
|
185
|
-
logger_1.logger.debug("GCFv2 function has a deprecated runtime:", JSON.stringify(gcfFunction, null, 2));
|
|
186
|
-
}
|
|
187
|
-
const cloudFunction = {
|
|
188
|
-
platform: "gcfv2",
|
|
189
|
-
id,
|
|
190
|
-
project,
|
|
191
|
-
region,
|
|
192
|
-
trigger,
|
|
193
|
-
entryPoint: gcfFunction.buildConfig.entryPoint,
|
|
194
|
-
runtime: gcfFunction.buildConfig.runtime,
|
|
195
|
-
uri: gcfFunction.serviceConfig.uri,
|
|
196
|
-
};
|
|
197
|
-
proto.copyIfPresent(cloudFunction, gcfFunction.serviceConfig, "serviceAccountEmail", "availableMemoryMb", "vpcConnector", "vpcConnectorEgressSettings", "ingressSettings", "environmentVariables");
|
|
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;
|
|
203
|
-
}
|
|
204
|
-
exports.specFromFunction = specFromFunction;
|
|
205
118
|
function functionFromEndpoint(endpoint, source) {
|
|
206
119
|
if (endpoint.platform != "gcfv2") {
|
|
207
120
|
throw new error_1.FirebaseError("Trying to create a v2 CloudFunction with v1 API. This should never happen");
|
|
@@ -245,13 +158,16 @@ function functionFromEndpoint(endpoint, source) {
|
|
|
245
158
|
}
|
|
246
159
|
}
|
|
247
160
|
else if (backend.isScheduleTriggered(endpoint)) {
|
|
248
|
-
gcfFunction.labels = Object.assign(Object.assign({}, gcfFunction.labels), {
|
|
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" });
|
|
249
165
|
}
|
|
250
166
|
return gcfFunction;
|
|
251
167
|
}
|
|
252
168
|
exports.functionFromEndpoint = functionFromEndpoint;
|
|
253
169
|
function endpointFromFunction(gcfFunction) {
|
|
254
|
-
var _a;
|
|
170
|
+
var _a, _b;
|
|
255
171
|
const [, project, , region, , id] = gcfFunction.name.split("/");
|
|
256
172
|
let trigger;
|
|
257
173
|
if (((_a = gcfFunction.labels) === null || _a === void 0 ? void 0 : _a["deployment-scheduled"]) === "true") {
|
|
@@ -259,6 +175,11 @@ function endpointFromFunction(gcfFunction) {
|
|
|
259
175
|
scheduleTrigger: {},
|
|
260
176
|
};
|
|
261
177
|
}
|
|
178
|
+
else if (((_b = gcfFunction.labels) === null || _b === void 0 ? void 0 : _b["deployment-taskqueue"]) === "true") {
|
|
179
|
+
trigger = {
|
|
180
|
+
taskQueueTrigger: {},
|
|
181
|
+
};
|
|
182
|
+
}
|
|
262
183
|
else if (gcfFunction.eventTrigger) {
|
|
263
184
|
trigger = {
|
|
264
185
|
eventTrigger: {
|
|
@@ -275,6 +196,7 @@ function endpointFromFunction(gcfFunction) {
|
|
|
275
196
|
trigger.eventTrigger.eventFilters[attribute] = value;
|
|
276
197
|
}
|
|
277
198
|
}
|
|
199
|
+
proto.renameIfPresent(trigger.eventTrigger, gcfFunction.eventTrigger, "region", "triggerRegion");
|
|
278
200
|
}
|
|
279
201
|
else {
|
|
280
202
|
trigger = { httpsTrigger: {} };
|
|
@@ -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;
|