firebase-tools 14.27.0 → 15.1.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/lib/appUtils.js +14 -15
- package/lib/archiveDirectory.js +7 -45
- package/lib/bin/cli.js +35 -8
- package/lib/bin/mcp.js +46 -8
- package/lib/command.js +5 -1
- package/lib/commands/dataconnect-execute.js +1 -1
- package/lib/commands/dataconnect-sdk-generate.js +7 -5
- package/lib/commands/dataconnect-sql-diff.js +7 -5
- package/lib/commands/dataconnect-sql-grant.js +12 -12
- package/lib/commands/dataconnect-sql-migrate.js +6 -4
- package/lib/commands/dataconnect-sql-setup.js +6 -4
- package/lib/commands/dataconnect-sql-shell.js +6 -4
- package/lib/commands/firestore-backups-list.js +1 -1
- package/lib/commands/functions-config-clone.js +2 -2
- package/lib/commands/functions-config-export.js +137 -92
- package/lib/commands/functions-config-get.js +1 -2
- package/lib/commands/functions-config-set.js +2 -2
- package/lib/commands/functions-config-unset.js +2 -2
- package/lib/commands/help.js +1 -1
- package/lib/commands/index.js +15 -10
- package/lib/commands/init.js +8 -0
- package/lib/config.js +1 -5
- package/lib/dataconnect/load.js +18 -21
- package/lib/deploy/database/prepare.js +1 -3
- package/lib/deploy/functions/prepare.js +5 -1
- package/lib/deploy/functions/prepareFunctionsUpload.js +1 -2
- package/lib/deploy/functions/runtimes/node/index.js +11 -12
- package/lib/deploy/functions/runtimes/node/versioning.js +2 -2
- package/lib/deploy/functions/validate.js +49 -2
- package/lib/emulator/commandUtils.js +1 -1
- package/lib/emulator/controller.js +1 -2
- package/lib/emulator/databaseEmulator.js +1 -5
- package/lib/emulator/downloadableEmulatorInfo.json +30 -30
- package/lib/emulator/functionsEmulator.js +0 -40
- package/lib/emulator/functionsEmulatorRuntime.js +1 -118
- package/lib/emulator/functionsEmulatorShared.js +1 -6
- package/lib/experiments.js +8 -1
- package/lib/extensions/extensionsHelper.js +0 -1
- package/lib/frameworks/constants.js +1 -1
- package/lib/fsAsync.js +11 -3
- package/lib/functionsConfig.js +39 -1
- package/lib/gcp/cloudsql/cloudsqladmin.js +1 -1
- package/lib/index.js +44 -1
- package/lib/init/features/dataconnect/resolver.js +111 -0
- package/lib/init/features/index.js +4 -1
- package/lib/init/features/project.js +1 -0
- package/lib/init/index.js +5 -0
- package/lib/mcp/index.js +31 -22
- package/lib/mcp/tools/core/get_environment.js +4 -1
- package/lib/mcp/tools/dataconnect/compile.js +13 -7
- package/lib/mcp/tools/dataconnect/execute.js +10 -7
- package/lib/mcp/tools/dataconnect/generate_operation.js +7 -3
- package/lib/mcp/tools/index.js +53 -44
- package/package.json +1 -2
- package/lib/deploy/functions/runtimes/node/extractTriggers.js +0 -23
- package/lib/deploy/functions/runtimes/node/parseTriggers.js +0 -332
- package/lib/deploy/functions/runtimes/node/triggerParser.js +0 -72
- package/lib/functions/deprecationWarnings.js +0 -21
- package/lib/functions/runtimeConfigExport.js +0 -141
- package/lib/handlePreviewToggles.js +0 -38
- package/lib/parseBoltRules.js +0 -29
|
@@ -1,119 +1,164 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.command = void 0;
|
|
4
|
-
const path = require("path");
|
|
5
4
|
const clc = require("colorette");
|
|
6
|
-
const
|
|
5
|
+
const semver = require("semver");
|
|
6
|
+
const functionsConfig = require("../functionsConfig");
|
|
7
7
|
const command_1 = require("../command");
|
|
8
8
|
const error_1 = require("../error");
|
|
9
|
-
const iam_1 = require("../gcp/iam");
|
|
10
|
-
const logger_1 = require("../logger");
|
|
11
9
|
const prompt_1 = require("../prompt");
|
|
12
10
|
const requirePermissions_1 = require("../requirePermissions");
|
|
13
11
|
const utils_1 = require("../utils");
|
|
14
|
-
const functional_1 = require("../functional");
|
|
15
|
-
const configExport = require("../functions/runtimeConfigExport");
|
|
16
12
|
const requireConfig_1 = require("../requireConfig");
|
|
17
|
-
const
|
|
18
|
-
const
|
|
13
|
+
const secrets_1 = require("../functions/secrets");
|
|
14
|
+
const secretManager_1 = require("../gcp/secretManager");
|
|
15
|
+
const projectUtils_1 = require("../projectUtils");
|
|
16
|
+
const requireAuth_1 = require("../requireAuth");
|
|
17
|
+
const secretManager_2 = require("../gcp/secretManager");
|
|
18
|
+
const versioning_1 = require("../deploy/functions/runtimes/node/versioning");
|
|
19
|
+
const RUNTIME_CONFIG_PERMISSIONS = [
|
|
19
20
|
"runtimeconfig.configs.list",
|
|
20
21
|
"runtimeconfig.configs.get",
|
|
21
22
|
"runtimeconfig.variables.list",
|
|
22
23
|
"runtimeconfig.variables.get",
|
|
23
24
|
];
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
pInfos = pInfos.filter((pInfo) => !pInfo.config);
|
|
37
|
-
const testPermissions = pInfos.map((pInfo) => (0, iam_1.testIamPermissions)(pInfo.projectId, REQUIRED_PERMISSIONS));
|
|
38
|
-
const results = await Promise.all(testPermissions);
|
|
39
|
-
for (const [pInfo, result] of (0, functional_1.zip)(pInfos, results)) {
|
|
40
|
-
if (result.passed) {
|
|
41
|
-
throw new error_1.FirebaseError(`Unexpectedly failed to fetch runtime config for project ${pInfo.projectId}`);
|
|
42
|
-
}
|
|
43
|
-
(0, utils_1.logWarning)("You are missing the following permissions to read functions config on project " +
|
|
44
|
-
`${clc.bold(pInfo.projectId)}:\n\t${result.missing.join("\n\t")}`);
|
|
45
|
-
const confirmed = await (0, prompt_1.confirm)({
|
|
46
|
-
message: `Continue without importing configs from project ${pInfo.projectId}?`,
|
|
47
|
-
default: true,
|
|
48
|
-
});
|
|
49
|
-
if (!confirmed) {
|
|
50
|
-
throw new error_1.FirebaseError("Command aborted!");
|
|
25
|
+
const SECRET_MANAGER_PERMISSIONS = [
|
|
26
|
+
"secretmanager.secrets.create",
|
|
27
|
+
"secretmanager.secrets.get",
|
|
28
|
+
"secretmanager.secrets.update",
|
|
29
|
+
"secretmanager.versions.add",
|
|
30
|
+
];
|
|
31
|
+
const DEFAULT_SECRET_NAME = "FUNCTIONS_CONFIG_EXPORT";
|
|
32
|
+
function maskConfigValues(obj) {
|
|
33
|
+
if (typeof obj === "object" && obj !== null && !Array.isArray(obj)) {
|
|
34
|
+
const masked = {};
|
|
35
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
36
|
+
masked[key] = maskConfigValues(value);
|
|
51
37
|
}
|
|
38
|
+
return masked;
|
|
52
39
|
}
|
|
53
|
-
|
|
54
|
-
async function promptForPrefix(errMsg) {
|
|
55
|
-
(0, utils_1.logWarning)("The following configs keys could not be exported as environment variables:\n");
|
|
56
|
-
(0, utils_1.logWarning)(errMsg);
|
|
57
|
-
return await (0, prompt_1.input)({
|
|
58
|
-
default: "CONFIG_",
|
|
59
|
-
message: "Enter a PREFIX to rename invalid environment variable keys:",
|
|
60
|
-
});
|
|
61
|
-
}
|
|
62
|
-
function fromEntries(itr) {
|
|
63
|
-
const obj = {};
|
|
64
|
-
for (const [k, v] of itr) {
|
|
65
|
-
obj[k] = v;
|
|
66
|
-
}
|
|
67
|
-
return obj;
|
|
40
|
+
return "******";
|
|
68
41
|
}
|
|
69
42
|
exports.command = new command_1.Command("functions:config:export")
|
|
70
|
-
.description("export environment config as
|
|
71
|
-
.
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
])
|
|
43
|
+
.description("export environment config as a JSON secret to store in Cloud Secret Manager")
|
|
44
|
+
.option("--secret <name>", `name of the secret to create (default: ${DEFAULT_SECRET_NAME})`)
|
|
45
|
+
.withForce("use default secret name without prompting")
|
|
46
|
+
.before(requireAuth_1.requireAuth)
|
|
47
|
+
.before(secretManager_2.ensureApi)
|
|
48
|
+
.before(requirePermissions_1.requirePermissions, [...RUNTIME_CONFIG_PERMISSIONS, ...SECRET_MANAGER_PERMISSIONS])
|
|
77
49
|
.before(requireConfig_1.requireConfig)
|
|
78
|
-
.before(requireInteractive_1.default)
|
|
79
50
|
.action(async (options) => {
|
|
80
|
-
|
|
81
|
-
const
|
|
82
|
-
|
|
83
|
-
|
|
51
|
+
var _a;
|
|
52
|
+
const projectId = (0, projectUtils_1.needProjectId)(options);
|
|
53
|
+
(0, utils_1.logBullet)("This command retrieves your Runtime Config values (accessed via " +
|
|
54
|
+
clc.bold("functions.config()") +
|
|
55
|
+
") and exports them as a Secret Manager secret.");
|
|
56
|
+
console.log("");
|
|
57
|
+
(0, utils_1.logBullet)(`Fetching your existing functions.config() from ${clc.bold(projectId)}...`);
|
|
58
|
+
let configJson;
|
|
59
|
+
try {
|
|
60
|
+
configJson = await functionsConfig.materializeAll(projectId);
|
|
61
|
+
}
|
|
62
|
+
catch (err) {
|
|
63
|
+
throw new error_1.FirebaseError(`Failed to fetch runtime config for project ${projectId}. ` +
|
|
64
|
+
"Ensure you have the required permissions:\n\t" +
|
|
65
|
+
RUNTIME_CONFIG_PERMISSIONS.join("\n\t"), { original: err });
|
|
66
|
+
}
|
|
67
|
+
if (Object.keys(configJson).length === 0) {
|
|
68
|
+
(0, utils_1.logSuccess)("Your functions.config() is empty. Nothing to do.");
|
|
69
|
+
return;
|
|
84
70
|
}
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
(
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
let prefix = "";
|
|
97
|
-
while (true) {
|
|
98
|
-
if (attempts >= MAX_ATTEMPTS) {
|
|
99
|
-
throw new error_1.FirebaseError("Exceeded max attempts to fix invalid config keys.");
|
|
71
|
+
(0, utils_1.logSuccess)("Fetched your existing functions.config().");
|
|
72
|
+
console.log("");
|
|
73
|
+
if (!options.nonInteractive) {
|
|
74
|
+
(0, utils_1.logBullet)(clc.bold("Configuration to be exported:"));
|
|
75
|
+
console.log(JSON.stringify(maskConfigValues(configJson), null, 2));
|
|
76
|
+
console.log("");
|
|
77
|
+
}
|
|
78
|
+
let secretName = options.secret;
|
|
79
|
+
if (!secretName) {
|
|
80
|
+
if (options.force) {
|
|
81
|
+
secretName = DEFAULT_SECRET_NAME;
|
|
100
82
|
}
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
83
|
+
else {
|
|
84
|
+
secretName = await (0, prompt_1.input)({
|
|
85
|
+
message: "What would you like to name the new secret for your configuration?",
|
|
86
|
+
default: DEFAULT_SECRET_NAME,
|
|
87
|
+
nonInteractive: options.nonInteractive,
|
|
88
|
+
});
|
|
104
89
|
}
|
|
105
|
-
prefix = await promptForPrefix(errMsg);
|
|
106
|
-
attempts += 1;
|
|
107
90
|
}
|
|
108
|
-
const
|
|
109
|
-
|
|
110
|
-
const
|
|
111
|
-
const
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
91
|
+
const key = await (0, secrets_1.ensureValidKey)(secretName, options);
|
|
92
|
+
await (0, secrets_1.ensureSecret)(projectId, key, options);
|
|
93
|
+
const versions = await (0, secretManager_1.listSecretVersions)(projectId, key);
|
|
94
|
+
const enabledVersions = versions.filter((v) => v.state === "ENABLED");
|
|
95
|
+
enabledVersions.sort((a, b) => (b.createTime || "").localeCompare(a.createTime || ""));
|
|
96
|
+
const latest = enabledVersions[0];
|
|
97
|
+
if (latest) {
|
|
98
|
+
(0, utils_1.logBullet)(`Secret ${clc.bold(key)} already exists (latest version: ${clc.bold(latest.versionId)}, created: ${latest.createTime}).`);
|
|
99
|
+
const proceed = await (0, prompt_1.confirm)({
|
|
100
|
+
message: "Do you want to add a new version to this secret?",
|
|
101
|
+
default: false,
|
|
102
|
+
nonInteractive: options.nonInteractive,
|
|
103
|
+
force: options.force,
|
|
104
|
+
});
|
|
105
|
+
if (!proceed) {
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
console.log("");
|
|
109
|
+
}
|
|
110
|
+
const secretValue = JSON.stringify(configJson, null, 2);
|
|
111
|
+
const sizeInBytes = Buffer.byteLength(secretValue, "utf8");
|
|
112
|
+
const maxSize = 64 * 1024;
|
|
113
|
+
if (sizeInBytes > maxSize) {
|
|
114
|
+
throw new error_1.FirebaseError(`Configuration size (${sizeInBytes} bytes) exceeds the 64KB limit for JSON secrets. ` +
|
|
115
|
+
"Please reduce the size of your configuration or split it into multiple secrets.");
|
|
116
|
+
}
|
|
117
|
+
const secretVersion = await (0, secretManager_1.addVersion)(projectId, key, secretValue);
|
|
118
|
+
console.log("");
|
|
119
|
+
(0, utils_1.logSuccess)(`Created new secret version ${(0, secretManager_1.toSecretVersionResourceName)(secretVersion)}`);
|
|
120
|
+
console.log("");
|
|
121
|
+
(0, utils_1.logBullet)(clc.bold("To complete the migration, update your code:"));
|
|
122
|
+
console.log("");
|
|
123
|
+
console.log(clc.gray(` // Before:
|
|
124
|
+
const functions = require('firebase-functions');
|
|
125
|
+
|
|
126
|
+
exports.myFunction = functions.https.onRequest((req, res) => {
|
|
127
|
+
const apiKey = functions.config().service.key;
|
|
128
|
+
// ...
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
// After:
|
|
132
|
+
const functions = require('firebase-functions');
|
|
133
|
+
const { defineJsonSecret } = require('firebase-functions/params');
|
|
134
|
+
|
|
135
|
+
const config = defineJsonSecret("${key}");
|
|
136
|
+
|
|
137
|
+
exports.myFunction = functions
|
|
138
|
+
.runWith({ secrets: [config] }) // Bind secret here
|
|
139
|
+
.https.onRequest((req, res) => {
|
|
140
|
+
const apiKey = config.value().service.key;
|
|
141
|
+
// ...
|
|
142
|
+
});`));
|
|
143
|
+
console.log("");
|
|
144
|
+
let sdkVersion;
|
|
145
|
+
try {
|
|
146
|
+
const functionsConfig = options.config.get("functions");
|
|
147
|
+
const source = Array.isArray(functionsConfig)
|
|
148
|
+
? (_a = functionsConfig[0]) === null || _a === void 0 ? void 0 : _a.source
|
|
149
|
+
: functionsConfig === null || functionsConfig === void 0 ? void 0 : functionsConfig.source;
|
|
150
|
+
if (source) {
|
|
151
|
+
const sourceDir = options.config.path(source);
|
|
152
|
+
sdkVersion = (0, versioning_1.getFunctionsSDKVersion)(sourceDir);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
catch (e) {
|
|
156
|
+
}
|
|
157
|
+
if (!sdkVersion || semver.lt(sdkVersion, "6.6.0")) {
|
|
158
|
+
(0, utils_1.logBullet)(clc.bold("Note: ") +
|
|
159
|
+
"defineJsonSecret requires firebase-functions v6.6.0 or later. " +
|
|
160
|
+
`Update to a newer version with ${clc.bold("npm i firebase-functions @latest")}${!sdkVersion ? " if needed" : ""}.`);
|
|
118
161
|
}
|
|
162
|
+
(0, utils_1.logBullet)("Then deploy your functions:\n " + clc.bold("firebase deploy --only functions"));
|
|
163
|
+
return secretName;
|
|
119
164
|
});
|
|
@@ -8,7 +8,6 @@ const logger_1 = require("../logger");
|
|
|
8
8
|
const projectUtils_1 = require("../projectUtils");
|
|
9
9
|
const requirePermissions_1 = require("../requirePermissions");
|
|
10
10
|
const functionsConfig = require("../functionsConfig");
|
|
11
|
-
const deprecationWarnings_1 = require("../functions/deprecationWarnings");
|
|
12
11
|
async function materialize(projectId, path) {
|
|
13
12
|
if (path === undefined) {
|
|
14
13
|
return functionsConfig.materializeAll(projectId);
|
|
@@ -32,6 +31,6 @@ exports.command = new command_1.Command("functions:config:get [path]")
|
|
|
32
31
|
.action(async (path, options) => {
|
|
33
32
|
const result = await materialize((0, projectUtils_1.needProjectId)(options), path);
|
|
34
33
|
logger_1.logger.info(JSON.stringify(result, null, 2));
|
|
35
|
-
|
|
34
|
+
functionsConfig.logFunctionsConfigDeprecationWarning();
|
|
36
35
|
return result;
|
|
37
36
|
});
|
|
@@ -9,9 +9,9 @@ const projectUtils_1 = require("../projectUtils");
|
|
|
9
9
|
const requirePermissions_1 = require("../requirePermissions");
|
|
10
10
|
const functionsConfig = require("../functionsConfig");
|
|
11
11
|
const utils = require("../utils");
|
|
12
|
-
const deprecationWarnings_1 = require("../functions/deprecationWarnings");
|
|
13
12
|
exports.command = new command_1.Command("functions:config:set [values...]")
|
|
14
13
|
.description("set environment config with key=value syntax")
|
|
14
|
+
.before(functionsConfig.ensureLegacyRuntimeConfigCommandsEnabled)
|
|
15
15
|
.before(requirePermissions_1.requirePermissions, [
|
|
16
16
|
"runtimeconfig.configs.list",
|
|
17
17
|
"runtimeconfig.configs.create",
|
|
@@ -41,5 +41,5 @@ exports.command = new command_1.Command("functions:config:set [values...]")
|
|
|
41
41
|
await Promise.all(promises);
|
|
42
42
|
utils.logSuccess("Functions config updated.");
|
|
43
43
|
logger_1.logger.info(`\nPlease deploy your functions for the change to take effect by running ${clc.bold("firebase deploy --only functions")}\n`);
|
|
44
|
-
|
|
44
|
+
functionsConfig.logFunctionsConfigDeprecationWarning();
|
|
45
45
|
});
|
|
@@ -10,9 +10,9 @@ const functionsConfig = require("../functionsConfig");
|
|
|
10
10
|
const runtimeconfig = require("../gcp/runtimeconfig");
|
|
11
11
|
const utils = require("../utils");
|
|
12
12
|
const error_1 = require("../error");
|
|
13
|
-
const deprecationWarnings_1 = require("../functions/deprecationWarnings");
|
|
14
13
|
exports.command = new command_1.Command("functions:config:unset [keys...]")
|
|
15
14
|
.description("unset environment config at the specified path(s)")
|
|
15
|
+
.before(functionsConfig.ensureLegacyRuntimeConfigCommandsEnabled)
|
|
16
16
|
.before(requirePermissions_1.requirePermissions, [
|
|
17
17
|
"runtimeconfig.configs.list",
|
|
18
18
|
"runtimeconfig.configs.create",
|
|
@@ -40,5 +40,5 @@ exports.command = new command_1.Command("functions:config:unset [keys...]")
|
|
|
40
40
|
}));
|
|
41
41
|
utils.logSuccess("Environment updated.");
|
|
42
42
|
logger_1.logger.info(`\nPlease deploy your functions for the change to take effect by running ${clc.bold("firebase deploy --only functions")}\n`);
|
|
43
|
-
|
|
43
|
+
functionsConfig.logFunctionsConfigDeprecationWarning();
|
|
44
44
|
});
|
package/lib/commands/help.js
CHANGED
|
@@ -9,7 +9,7 @@ exports.command = new command_1.Command("help [command]")
|
|
|
9
9
|
.description("display help information")
|
|
10
10
|
.action(function (commandName) {
|
|
11
11
|
const client = this.client;
|
|
12
|
-
const cmd = client.getCommand(commandName);
|
|
12
|
+
const cmd = commandName ? client.getCommand(commandName) : undefined;
|
|
13
13
|
if (cmd) {
|
|
14
14
|
cmd.outputHelp();
|
|
15
15
|
}
|
package/lib/commands/index.js
CHANGED
|
@@ -4,14 +4,19 @@ exports.load = void 0;
|
|
|
4
4
|
const experiments = require("../experiments");
|
|
5
5
|
function load(client) {
|
|
6
6
|
function loadCommand(name) {
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
7
|
+
const load = () => {
|
|
8
|
+
const { command: cmd } = require(`./${name}`);
|
|
9
|
+
cmd.register(client);
|
|
10
|
+
return cmd.runner();
|
|
11
|
+
};
|
|
12
|
+
const runner = (async (...args) => {
|
|
13
|
+
const run = load();
|
|
14
|
+
return run(...args);
|
|
15
|
+
});
|
|
16
|
+
runner.load = () => {
|
|
17
|
+
require(`./${name}`).command.register(client);
|
|
18
|
+
};
|
|
19
|
+
return runner;
|
|
15
20
|
}
|
|
16
21
|
const t0 = process.hrtime.bigint();
|
|
17
22
|
client.appdistribution = {};
|
|
@@ -19,7 +24,7 @@ function load(client) {
|
|
|
19
24
|
client.appdistribution.testers = {};
|
|
20
25
|
client.appdistribution.testers.list = loadCommand("appdistribution-testers-list");
|
|
21
26
|
client.appdistribution.testers.add = loadCommand("appdistribution-testers-add");
|
|
22
|
-
client.appdistribution.testers.
|
|
27
|
+
client.appdistribution.testers.remove = loadCommand("appdistribution-testers-remove");
|
|
23
28
|
client.appdistribution.groups = {};
|
|
24
29
|
client.appdistribution.groups.list = loadCommand("appdistribution-groups-list");
|
|
25
30
|
client.appdistribution.groups.create = loadCommand("appdistribution-groups-create");
|
|
@@ -40,7 +45,7 @@ function load(client) {
|
|
|
40
45
|
client.apps.android.sha.delete = loadCommand("apps-android-sha-delete");
|
|
41
46
|
client.auth = {};
|
|
42
47
|
client.auth.export = loadCommand("auth-export");
|
|
43
|
-
client.auth.
|
|
48
|
+
client.auth.import = loadCommand("auth-import");
|
|
44
49
|
client.crashlytics = {};
|
|
45
50
|
client.crashlytics.symbols = {};
|
|
46
51
|
client.crashlytics.symbols.upload = loadCommand("crashlytics-symbols-upload");
|
package/lib/commands/init.js
CHANGED
|
@@ -87,6 +87,14 @@ let choices = [
|
|
|
87
87
|
hidden: true,
|
|
88
88
|
},
|
|
89
89
|
];
|
|
90
|
+
if ((0, experiments_1.isEnabled)("fdcwebhooks")) {
|
|
91
|
+
choices.push({
|
|
92
|
+
value: "dataconnect:resolver",
|
|
93
|
+
name: "Data Connect: Set up a custom resolver for your Firebase Data Connect service",
|
|
94
|
+
checked: false,
|
|
95
|
+
hidden: true,
|
|
96
|
+
});
|
|
97
|
+
}
|
|
90
98
|
if ((0, experiments_1.isEnabled)("genkit")) {
|
|
91
99
|
choices = [
|
|
92
100
|
...choices.slice(0, 2),
|
package/lib/config.js
CHANGED
|
@@ -14,7 +14,6 @@ const utils = require("./utils");
|
|
|
14
14
|
const firebaseConfigValidate_1 = require("./firebaseConfigValidate");
|
|
15
15
|
const logger_1 = require("./logger");
|
|
16
16
|
const loadCJSON_1 = require("./loadCJSON");
|
|
17
|
-
const parseBoltRules = require("./parseBoltRules");
|
|
18
17
|
class Config {
|
|
19
18
|
constructor(src, options = {}) {
|
|
20
19
|
var _a, _b;
|
|
@@ -116,10 +115,7 @@ class Config {
|
|
|
116
115
|
}
|
|
117
116
|
return (0, loadCJSON_1.loadCJSON)(fullPath);
|
|
118
117
|
case ".bolt":
|
|
119
|
-
|
|
120
|
-
this.notes.databaseRules = "bolt";
|
|
121
|
-
}
|
|
122
|
-
return parseBoltRules(fullPath);
|
|
118
|
+
throw new error_1.FirebaseError("As of firebase-tools@15.0.0, .bolt rules are no longer supported.");
|
|
123
119
|
default:
|
|
124
120
|
throw new error_1.FirebaseError("Parse Error: " + filePath + " is not of a supported config file type", { exit: 1 });
|
|
125
121
|
}
|
package/lib/dataconnect/load.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.squashGraphQL = exports.readGQLFiles = exports.readConnectorYaml = exports.readDataConnectYaml = exports.readFirebaseJson = exports.load = exports.loadAll = exports.
|
|
3
|
+
exports.squashGraphQL = exports.readGQLFiles = exports.readConnectorYaml = exports.readDataConnectYaml = exports.readFirebaseJson = exports.load = exports.loadAll = exports.pickServices = exports.pickOneService = void 0;
|
|
4
4
|
const path = require("path");
|
|
5
5
|
const fs = require("fs-extra");
|
|
6
6
|
const clc = require("colorette");
|
|
@@ -9,33 +9,30 @@ const error_1 = require("../error");
|
|
|
9
9
|
const types_1 = require("./types");
|
|
10
10
|
const utils_1 = require("../utils");
|
|
11
11
|
const experiments = require("../experiments");
|
|
12
|
-
async function
|
|
12
|
+
async function pickOneService(projectId, config, service, location) {
|
|
13
|
+
const services = await pickServices(projectId, config, service, location);
|
|
14
|
+
if (services.length > 1) {
|
|
15
|
+
const serviceIds = services.map((i) => `${i.dataConnectYaml.location}:${i.dataConnectYaml.serviceId}`);
|
|
16
|
+
throw new error_1.FirebaseError(`Multiple services matched. Please specify a service and location. Matched services: ${serviceIds.join(", ")}`);
|
|
17
|
+
}
|
|
18
|
+
return services[0];
|
|
19
|
+
}
|
|
20
|
+
exports.pickOneService = pickOneService;
|
|
21
|
+
async function pickServices(projectId, config, serviceId, location) {
|
|
13
22
|
const serviceInfos = await loadAll(projectId, config);
|
|
14
23
|
if (serviceInfos.length === 0) {
|
|
15
24
|
throw new error_1.FirebaseError("No Data Connect services found in firebase.json." +
|
|
16
25
|
`\nYou can run ${clc.bold("firebase init dataconnect")} to add a Data Connect service.`);
|
|
17
26
|
}
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
}
|
|
23
|
-
return serviceInfos[0];
|
|
24
|
-
}
|
|
25
|
-
else {
|
|
26
|
-
if (!serviceId) {
|
|
27
|
-
throw new error_1.FirebaseError("Multiple Data Connect services found in firebase.json. Please specify a service ID to use.");
|
|
28
|
-
}
|
|
29
|
-
const maybe = serviceInfos.find((i) => i.dataConnectYaml.serviceId === serviceId);
|
|
30
|
-
if (!maybe) {
|
|
31
|
-
const serviceIds = serviceInfos.map((i) => i.dataConnectYaml.serviceId);
|
|
32
|
-
throw new error_1.FirebaseError(`No service named ${serviceId} declared in firebase.json. Found ${serviceIds.join(", ")}.` +
|
|
33
|
-
`\nYou can run ${clc.bold("firebase init dataconnect")} to add this Data Connect service.`);
|
|
34
|
-
}
|
|
35
|
-
return maybe;
|
|
27
|
+
const matchingServices = serviceInfos.filter((i) => (!serviceId || i.dataConnectYaml.serviceId === serviceId) &&
|
|
28
|
+
(!location || i.dataConnectYaml.location === location));
|
|
29
|
+
if (matchingServices.length === 0) {
|
|
30
|
+
const serviceIds = serviceInfos.map((i) => `${i.dataConnectYaml.location}:${i.dataConnectYaml.serviceId}`);
|
|
31
|
+
throw new error_1.FirebaseError(`No service matched service in firebase.json. Available services: ${serviceIds.join(", ")}`);
|
|
36
32
|
}
|
|
33
|
+
return matchingServices;
|
|
37
34
|
}
|
|
38
|
-
exports.
|
|
35
|
+
exports.pickServices = pickServices;
|
|
39
36
|
async function loadAll(projectId, config) {
|
|
40
37
|
const serviceCfgs = readFirebaseJson(config);
|
|
41
38
|
return await Promise.all(serviceCfgs.map((c) => load(projectId, config, c.source)));
|
|
@@ -4,7 +4,6 @@ exports.prepare = void 0;
|
|
|
4
4
|
const clc = require("colorette");
|
|
5
5
|
const path = require("path");
|
|
6
6
|
const error_1 = require("../../error");
|
|
7
|
-
const parseBoltRules_1 = require("../../parseBoltRules");
|
|
8
7
|
const rtdb = require("../../rtdb");
|
|
9
8
|
const utils = require("../../utils");
|
|
10
9
|
const dbRulesConfig = require("../../database/rulesConfig");
|
|
@@ -29,8 +28,7 @@ function prepare(context, options) {
|
|
|
29
28
|
ruleFiles[file] = options.config.readProjectFile(file);
|
|
30
29
|
break;
|
|
31
30
|
case ".bolt":
|
|
32
|
-
|
|
33
|
-
break;
|
|
31
|
+
throw new error_1.FirebaseError("As of firebase-tools@15.0.0, .bolt rules are no longer supported.");
|
|
34
32
|
default:
|
|
35
33
|
throw new error_1.FirebaseError("Unexpected rules format " + path.extname(file));
|
|
36
34
|
}
|
|
@@ -30,6 +30,7 @@ const backend_1 = require("./backend");
|
|
|
30
30
|
const functional_1 = require("../../functional");
|
|
31
31
|
const prepare_1 = require("../extensions/prepare");
|
|
32
32
|
const prompt = require("../../prompt");
|
|
33
|
+
const experiments = require("../../experiments");
|
|
33
34
|
exports.EVENTARC_SOURCE_ENV = "EVENTARC_CLOUD_EVENT_SOURCE";
|
|
34
35
|
async function prepare(context, options, payload) {
|
|
35
36
|
var _a, _b;
|
|
@@ -54,8 +55,11 @@ async function prepare(context, options, payload) {
|
|
|
54
55
|
context.firebaseConfig = firebaseConfig;
|
|
55
56
|
context.codebaseDeployEvents = {};
|
|
56
57
|
let runtimeConfig = { firebase: firebaseConfig };
|
|
58
|
+
const allowFunctionsConfig = experiments.isEnabled("legacyRuntimeConfigCommands");
|
|
57
59
|
const targetedCodebaseConfigs = context.config.filter((cfg) => codebases.includes(cfg.codebase));
|
|
58
|
-
if (
|
|
60
|
+
if (allowFunctionsConfig &&
|
|
61
|
+
checkAPIsEnabled[1] &&
|
|
62
|
+
targetedCodebaseConfigs.some(projectConfig_1.shouldUseRuntimeConfig)) {
|
|
59
63
|
runtimeConfig = Object.assign(Object.assign({}, runtimeConfig), (await (0, prepareFunctionsUpload_1.getFunctionsConfig)(projectId)));
|
|
60
64
|
}
|
|
61
65
|
context.hasRuntimeConfig = Object.keys(runtimeConfig).some((k) => k !== "firebase");
|
|
@@ -13,7 +13,6 @@ const hash_1 = require("./cache/hash");
|
|
|
13
13
|
const functionsConfig = require("../../functionsConfig");
|
|
14
14
|
const utils = require("../../utils");
|
|
15
15
|
const fsAsync = require("../../fsAsync");
|
|
16
|
-
const deprecationWarnings_1 = require("../../functions/deprecationWarnings");
|
|
17
16
|
const CONFIG_DEST_FILE = ".runtimeconfig.json";
|
|
18
17
|
async function getFunctionsConfig(projectId) {
|
|
19
18
|
var _a, _b;
|
|
@@ -75,7 +74,7 @@ async function packageSource(sourceDir, config, runtimeConfig) {
|
|
|
75
74
|
mode: 420,
|
|
76
75
|
});
|
|
77
76
|
if (Object.keys(runtimeConfig).some((k) => k !== "firebase")) {
|
|
78
|
-
|
|
77
|
+
functionsConfig.logFunctionsConfigDeprecationWarning();
|
|
79
78
|
}
|
|
80
79
|
}
|
|
81
80
|
await pipeAsync(archive, fileStream);
|
|
@@ -16,7 +16,6 @@ const discovery = require("../discovery");
|
|
|
16
16
|
const supported = require("../supported");
|
|
17
17
|
const validate = require("./validate");
|
|
18
18
|
const versioning = require("./versioning");
|
|
19
|
-
const parseTriggers = require("./parseTriggers");
|
|
20
19
|
const fsutils_1 = require("../../../../fsutils");
|
|
21
20
|
const MIN_FUNCTIONS_SDK_VERSION = "3.20.0";
|
|
22
21
|
const MIN_FUNCTIONS_SDK_VERSION_FOR_EXTENSIONS_FEATURES = "5.1.0";
|
|
@@ -162,18 +161,18 @@ class Delegate {
|
|
|
162
161
|
});
|
|
163
162
|
}
|
|
164
163
|
async discoverBuild(config, env) {
|
|
165
|
-
if (
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
(
|
|
171
|
-
`
|
|
172
|
-
|
|
164
|
+
if (semver.valid(this.sdkVersion)) {
|
|
165
|
+
if (semver.lt(this.sdkVersion, MIN_FUNCTIONS_SDK_VERSION)) {
|
|
166
|
+
throw new error_1.FirebaseError(`You are using an old version of firebase-functions SDK (${this.sdkVersion}). ` +
|
|
167
|
+
`Please update firebase-functions SDK to >=${MIN_FUNCTIONS_SDK_VERSION}`);
|
|
168
|
+
}
|
|
169
|
+
if (semver.lt(this.sdkVersion, MIN_FUNCTIONS_SDK_VERSION_FOR_EXTENSIONS_FEATURES)) {
|
|
170
|
+
(0, utils_1.logLabeledBullet)("functions", `You are using a version of firebase-functions SDK (${this.sdkVersion}) that does not have support for the newest Firebase Extensions features. ` +
|
|
171
|
+
`Please update firebase-functions SDK to >=${MIN_FUNCTIONS_SDK_VERSION_FOR_EXTENSIONS_FEATURES} to use them correctly`);
|
|
172
|
+
}
|
|
173
173
|
}
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
`Please update firebase-functions SDK to >=${MIN_FUNCTIONS_SDK_VERSION_FOR_EXTENSIONS_FEATURES} to use them correctly`);
|
|
174
|
+
else {
|
|
175
|
+
logger_1.logger.debug(`Could not parse firebase-functions version '${this.sdkVersion}' into semver.`);
|
|
177
176
|
}
|
|
178
177
|
let discovered = await discovery.detectFromYaml(this.sourceDir, this.projectId, this.runtime);
|
|
179
178
|
if (!discovered) {
|
|
@@ -8,12 +8,12 @@ const spawn = require("cross-spawn");
|
|
|
8
8
|
const semver = require("semver");
|
|
9
9
|
const logger_1 = require("../../../../logger");
|
|
10
10
|
const utils = require("../../../../utils");
|
|
11
|
-
const MIN_SDK_VERSION = "
|
|
11
|
+
const MIN_SDK_VERSION = "3.20.0";
|
|
12
12
|
const NPM_COMMAND_TIMEOUT_MILLIES = 10000;
|
|
13
13
|
exports.FUNCTIONS_SDK_VERSION_TOO_OLD_WARNING = clc.bold(clc.yellow("functions: ")) +
|
|
14
14
|
"You must have a " +
|
|
15
15
|
clc.bold("firebase-functions") +
|
|
16
|
-
" version that is at least
|
|
16
|
+
" version that is at least 3.20.0. Please run " +
|
|
17
17
|
clc.bold("npm i --save firebase-functions@latest") +
|
|
18
18
|
" in the functions folder.";
|
|
19
19
|
function findModuleVersion(name, resolvedPath) {
|