firebase-tools 14.2.1 → 14.2.2
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/bin/cli.js +131 -0
- package/lib/bin/firebase.js +7 -123
- package/lib/bin/mcp.js +38 -0
- package/lib/commands/index.js +3 -0
- package/lib/commands/mcp.js +11 -0
- package/lib/emulator/commandUtils.js +8 -6
- package/lib/emulator/downloadableEmulators.js +9 -9
- package/lib/emulator/env.js +19 -20
- package/lib/emulator/functionsEmulator.js +0 -1
- package/lib/emulator/hub.js +2 -1
- package/lib/emulator/ui.js +0 -2
- package/lib/experiments.js +5 -0
- package/lib/frameworks/index.js +4 -1
- package/lib/gcp/auth.js +56 -1
- package/lib/gcp/firestore.js +12 -1
- package/lib/hosting/api.js +4 -0
- package/lib/init/features/dataconnect/sdk.js +9 -7
- package/lib/logger.js +11 -2
- package/lib/mcp/errors.js +15 -0
- package/lib/mcp/index.js +109 -0
- package/lib/mcp/tool.js +11 -0
- package/lib/mcp/tools/auth/disable_auth_user.js +30 -0
- package/lib/mcp/tools/auth/get_auth_user.js +29 -0
- package/lib/mcp/tools/auth/index.js +7 -0
- package/lib/mcp/tools/auth/set_auth_claims.js +34 -0
- package/lib/mcp/tools/core/get_firebase_directory.js +20 -0
- package/lib/mcp/tools/core/index.js +6 -0
- package/lib/mcp/tools/core/set_firebase_directory.js +33 -0
- package/lib/mcp/tools/dataconnect/index.js +5 -0
- package/lib/mcp/tools/dataconnect/list_dataconnect_services.js +23 -0
- package/lib/mcp/tools/firestore/converter.js +57 -0
- package/lib/mcp/tools/firestore/get_documents.js +48 -0
- package/lib/mcp/tools/firestore/get_firestore_rules.js +26 -0
- package/lib/mcp/tools/firestore/index.js +7 -0
- package/lib/mcp/tools/firestore/list_collections.js +30 -0
- package/lib/mcp/tools/index.js +14 -0
- package/lib/mcp/tools/project/get_project.js +22 -0
- package/lib/mcp/tools/project/get_sdk_config.js +38 -0
- package/lib/mcp/tools/project/index.js +7 -0
- package/lib/mcp/tools/project/list_apps.js +29 -0
- package/lib/mcp/types.js +4 -0
- package/lib/mcp/util.js +52 -0
- package/package.json +5 -2
- package/templates/init/dataconnect/connector.yaml +3 -0
package/lib/bin/cli.js
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.cli = void 0;
|
|
4
|
+
const updateNotifierPkg = require("update-notifier-cjs");
|
|
5
|
+
const clc = require("colorette");
|
|
6
|
+
const marked_terminal_1 = require("marked-terminal");
|
|
7
|
+
const marked_1 = require("marked");
|
|
8
|
+
marked_1.marked.use((0, marked_terminal_1.markedTerminal)());
|
|
9
|
+
const node_path_1 = require("node:path");
|
|
10
|
+
const triple_beam_1 = require("triple-beam");
|
|
11
|
+
const node_util_1 = require("node:util");
|
|
12
|
+
const fs = require("node:fs");
|
|
13
|
+
const configstore_1 = require("../configstore");
|
|
14
|
+
const errorOut_1 = require("../errorOut");
|
|
15
|
+
const handlePreviewToggles_1 = require("../handlePreviewToggles");
|
|
16
|
+
const logger_1 = require("../logger");
|
|
17
|
+
const client = require("..");
|
|
18
|
+
const fsutils = require("../fsutils");
|
|
19
|
+
const utils = require("../utils");
|
|
20
|
+
const winston = require("winston");
|
|
21
|
+
const experiments_1 = require("../experiments");
|
|
22
|
+
const fetchMOTD_1 = require("../fetchMOTD");
|
|
23
|
+
function cli(pkg) {
|
|
24
|
+
const updateNotifier = updateNotifierPkg({ pkg });
|
|
25
|
+
const args = process.argv.slice(2);
|
|
26
|
+
let cmd;
|
|
27
|
+
function findAvailableLogFile() {
|
|
28
|
+
const candidates = ["firebase-debug.log"];
|
|
29
|
+
for (let i = 1; i < 10; i++) {
|
|
30
|
+
candidates.push(`firebase-debug.${i}.log`);
|
|
31
|
+
}
|
|
32
|
+
for (const c of candidates) {
|
|
33
|
+
const logFilename = (0, node_path_1.join)(process.cwd(), c);
|
|
34
|
+
try {
|
|
35
|
+
const fd = fs.openSync(logFilename, "r+");
|
|
36
|
+
fs.closeSync(fd);
|
|
37
|
+
return logFilename;
|
|
38
|
+
}
|
|
39
|
+
catch (e) {
|
|
40
|
+
if (e.code === "ENOENT") {
|
|
41
|
+
return logFilename;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
throw new Error("Unable to obtain permissions for firebase-debug.log");
|
|
46
|
+
}
|
|
47
|
+
const logFilename = findAvailableLogFile();
|
|
48
|
+
if (!process.env.DEBUG && args.includes("--debug")) {
|
|
49
|
+
process.env.DEBUG = "true";
|
|
50
|
+
}
|
|
51
|
+
process.env.IS_FIREBASE_CLI = "true";
|
|
52
|
+
logger_1.logger.add(new winston.transports.File({
|
|
53
|
+
level: "debug",
|
|
54
|
+
filename: logFilename,
|
|
55
|
+
format: winston.format.printf((info) => {
|
|
56
|
+
const segments = [info.message, ...(info[triple_beam_1.SPLAT] || [])].map(utils.tryStringify);
|
|
57
|
+
return `[${info.level}] ${(0, node_util_1.stripVTControlCharacters)(segments.join(" "))}`;
|
|
58
|
+
}),
|
|
59
|
+
}));
|
|
60
|
+
logger_1.logger.debug("-".repeat(70));
|
|
61
|
+
logger_1.logger.debug("Command: ", process.argv.join(" "));
|
|
62
|
+
logger_1.logger.debug("CLI Version: ", pkg.version);
|
|
63
|
+
logger_1.logger.debug("Platform: ", process.platform);
|
|
64
|
+
logger_1.logger.debug("Node Version: ", process.version);
|
|
65
|
+
logger_1.logger.debug("Time: ", new Date().toString());
|
|
66
|
+
if (utils.envOverrides.length) {
|
|
67
|
+
logger_1.logger.debug("Env Overrides:", utils.envOverrides.join(", "));
|
|
68
|
+
}
|
|
69
|
+
logger_1.logger.debug("-".repeat(70));
|
|
70
|
+
logger_1.logger.debug();
|
|
71
|
+
(0, experiments_1.enableExperimentsFromCliEnvVariable)();
|
|
72
|
+
(0, fetchMOTD_1.fetchMOTD)();
|
|
73
|
+
process.on("exit", (code) => {
|
|
74
|
+
code = process.exitCode || code;
|
|
75
|
+
if (!process.env.DEBUG && code < 2 && fsutils.fileExistsSync(logFilename)) {
|
|
76
|
+
fs.unlinkSync(logFilename);
|
|
77
|
+
}
|
|
78
|
+
if (code > 0 && process.stdout.isTTY) {
|
|
79
|
+
const lastError = configstore_1.configstore.get("lastError") || 0;
|
|
80
|
+
const timestamp = Date.now();
|
|
81
|
+
if (lastError > timestamp - 120000) {
|
|
82
|
+
let help;
|
|
83
|
+
if (code === 1 && cmd) {
|
|
84
|
+
help = "Having trouble? Try " + clc.bold("firebase [command] --help");
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
help = "Having trouble? Try again or contact support with contents of firebase-debug.log";
|
|
88
|
+
}
|
|
89
|
+
if (cmd) {
|
|
90
|
+
console.log();
|
|
91
|
+
console.log(help);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
configstore_1.configstore.set("lastError", timestamp);
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
configstore_1.configstore.delete("lastError");
|
|
98
|
+
}
|
|
99
|
+
try {
|
|
100
|
+
const installMethod = !process.env.FIREPIT_VERSION ? "npm" : "automatic script";
|
|
101
|
+
const updateCommand = !process.env.FIREPIT_VERSION
|
|
102
|
+
? "npm install -g firebase-tools"
|
|
103
|
+
: "curl -sL https://firebase.tools | upgrade=true bash";
|
|
104
|
+
const updateMessage = `Update available ${clc.gray("{currentVersion}")} → ${clc.green("{latestVersion}")}\n` +
|
|
105
|
+
`To update to the latest version using ${installMethod}, run\n${clc.cyan(updateCommand)}\n` +
|
|
106
|
+
`For other CLI management options, visit the ${(0, marked_1.marked)("[CLI documentation](https://firebase.google.com/docs/cli#update-cli)")}`;
|
|
107
|
+
updateNotifier.notify({ defer: false, isGlobal: true, message: updateMessage });
|
|
108
|
+
}
|
|
109
|
+
catch (err) {
|
|
110
|
+
logger_1.logger.debug("Error when notifying about new CLI updates:");
|
|
111
|
+
if (err instanceof Error) {
|
|
112
|
+
logger_1.logger.debug(err);
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
logger_1.logger.debug(`${err}`);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
process.on("uncaughtException", (err) => {
|
|
120
|
+
(0, errorOut_1.errorOut)(err);
|
|
121
|
+
});
|
|
122
|
+
if (!(0, handlePreviewToggles_1.handlePreviewToggles)(args)) {
|
|
123
|
+
if (!args.length) {
|
|
124
|
+
client.cli.help();
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
cmd = client.cli.parse(process.argv);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
exports.cli = cli;
|
package/lib/bin/firebase.js
CHANGED
|
@@ -2,134 +2,18 @@
|
|
|
2
2
|
"use strict";
|
|
3
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
4
|
const semver = require("semver");
|
|
5
|
+
const experiments_1 = require("../experiments");
|
|
5
6
|
const pkg = require("../../package.json");
|
|
6
7
|
const nodeVersion = process.version;
|
|
7
8
|
if (!semver.satisfies(nodeVersion, pkg.engines.node)) {
|
|
8
9
|
console.error(`Firebase CLI v${pkg.version} is incompatible with Node.js ${nodeVersion} Please upgrade Node.js to version ${pkg.engines.node}`);
|
|
9
10
|
process.exit(1);
|
|
10
11
|
}
|
|
11
|
-
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
const updateNotifier = updateNotifierPkg({ pkg });
|
|
15
|
-
const marked_1 = require("marked");
|
|
16
|
-
marked_1.marked.use((0, marked_terminal_1.markedTerminal)());
|
|
17
|
-
const node_path_1 = require("node:path");
|
|
18
|
-
const triple_beam_1 = require("triple-beam");
|
|
19
|
-
const node_util_1 = require("node:util");
|
|
20
|
-
const fs = require("node:fs");
|
|
21
|
-
const configstore_1 = require("../configstore");
|
|
22
|
-
const errorOut_1 = require("../errorOut");
|
|
23
|
-
const handlePreviewToggles_1 = require("../handlePreviewToggles");
|
|
24
|
-
const logger_1 = require("../logger");
|
|
25
|
-
const client = require("..");
|
|
26
|
-
const fsutils = require("../fsutils");
|
|
27
|
-
const utils = require("../utils");
|
|
28
|
-
const winston = require("winston");
|
|
29
|
-
const args = process.argv.slice(2);
|
|
30
|
-
let cmd;
|
|
31
|
-
function findAvailableLogFile() {
|
|
32
|
-
const candidates = ["firebase-debug.log"];
|
|
33
|
-
for (let i = 1; i < 10; i++) {
|
|
34
|
-
candidates.push(`firebase-debug.${i}.log`);
|
|
35
|
-
}
|
|
36
|
-
for (const c of candidates) {
|
|
37
|
-
const logFilename = (0, node_path_1.join)(process.cwd(), c);
|
|
38
|
-
try {
|
|
39
|
-
const fd = fs.openSync(logFilename, "r+");
|
|
40
|
-
fs.closeSync(fd);
|
|
41
|
-
return logFilename;
|
|
42
|
-
}
|
|
43
|
-
catch (e) {
|
|
44
|
-
if (e.code === "ENOENT") {
|
|
45
|
-
return logFilename;
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
throw new Error("Unable to obtain permissions for firebase-debug.log");
|
|
50
|
-
}
|
|
51
|
-
const logFilename = findAvailableLogFile();
|
|
52
|
-
if (!process.env.DEBUG && args.includes("--debug")) {
|
|
53
|
-
process.env.DEBUG = "true";
|
|
12
|
+
if ((0, experiments_1.isEnabled)("mcp") && process.argv[2] === "experimental:mcp") {
|
|
13
|
+
const { mcp } = require("./mcp");
|
|
14
|
+
mcp();
|
|
54
15
|
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
filename: logFilename,
|
|
59
|
-
format: winston.format.printf((info) => {
|
|
60
|
-
const segments = [info.message, ...(info[triple_beam_1.SPLAT] || [])].map(utils.tryStringify);
|
|
61
|
-
return `[${info.level}] ${(0, node_util_1.stripVTControlCharacters)(segments.join(" "))}`;
|
|
62
|
-
}),
|
|
63
|
-
}));
|
|
64
|
-
logger_1.logger.debug("-".repeat(70));
|
|
65
|
-
logger_1.logger.debug("Command: ", process.argv.join(" "));
|
|
66
|
-
logger_1.logger.debug("CLI Version: ", pkg.version);
|
|
67
|
-
logger_1.logger.debug("Platform: ", process.platform);
|
|
68
|
-
logger_1.logger.debug("Node Version: ", process.version);
|
|
69
|
-
logger_1.logger.debug("Time: ", new Date().toString());
|
|
70
|
-
if (utils.envOverrides.length) {
|
|
71
|
-
logger_1.logger.debug("Env Overrides:", utils.envOverrides.join(", "));
|
|
72
|
-
}
|
|
73
|
-
logger_1.logger.debug("-".repeat(70));
|
|
74
|
-
logger_1.logger.debug();
|
|
75
|
-
const experiments_1 = require("../experiments");
|
|
76
|
-
const fetchMOTD_1 = require("../fetchMOTD");
|
|
77
|
-
(0, experiments_1.enableExperimentsFromCliEnvVariable)();
|
|
78
|
-
(0, fetchMOTD_1.fetchMOTD)();
|
|
79
|
-
process.on("exit", (code) => {
|
|
80
|
-
code = process.exitCode || code;
|
|
81
|
-
if (!process.env.DEBUG && code < 2 && fsutils.fileExistsSync(logFilename)) {
|
|
82
|
-
fs.unlinkSync(logFilename);
|
|
83
|
-
}
|
|
84
|
-
if (code > 0 && process.stdout.isTTY) {
|
|
85
|
-
const lastError = configstore_1.configstore.get("lastError") || 0;
|
|
86
|
-
const timestamp = Date.now();
|
|
87
|
-
if (lastError > timestamp - 120000) {
|
|
88
|
-
let help;
|
|
89
|
-
if (code === 1 && cmd) {
|
|
90
|
-
help = "Having trouble? Try " + clc.bold("firebase [command] --help");
|
|
91
|
-
}
|
|
92
|
-
else {
|
|
93
|
-
help = "Having trouble? Try again or contact support with contents of firebase-debug.log";
|
|
94
|
-
}
|
|
95
|
-
if (cmd) {
|
|
96
|
-
console.log();
|
|
97
|
-
console.log(help);
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
configstore_1.configstore.set("lastError", timestamp);
|
|
101
|
-
}
|
|
102
|
-
else {
|
|
103
|
-
configstore_1.configstore.delete("lastError");
|
|
104
|
-
}
|
|
105
|
-
try {
|
|
106
|
-
const installMethod = !process.env.FIREPIT_VERSION ? "npm" : "automatic script";
|
|
107
|
-
const updateCommand = !process.env.FIREPIT_VERSION
|
|
108
|
-
? "npm install -g firebase-tools"
|
|
109
|
-
: "curl -sL https://firebase.tools | upgrade=true bash";
|
|
110
|
-
const updateMessage = `Update available ${clc.gray("{currentVersion}")} → ${clc.green("{latestVersion}")}\n` +
|
|
111
|
-
`To update to the latest version using ${installMethod}, run\n${clc.cyan(updateCommand)}\n` +
|
|
112
|
-
`For other CLI management options, visit the ${(0, marked_1.marked)("[CLI documentation](https://firebase.google.com/docs/cli#update-cli)")}`;
|
|
113
|
-
updateNotifier.notify({ defer: false, isGlobal: true, message: updateMessage });
|
|
114
|
-
}
|
|
115
|
-
catch (err) {
|
|
116
|
-
logger_1.logger.debug("Error when notifying about new CLI updates:");
|
|
117
|
-
if (err instanceof Error) {
|
|
118
|
-
logger_1.logger.debug(err);
|
|
119
|
-
}
|
|
120
|
-
else {
|
|
121
|
-
logger_1.logger.debug(`${err}`);
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
});
|
|
125
|
-
process.on("uncaughtException", (err) => {
|
|
126
|
-
(0, errorOut_1.errorOut)(err);
|
|
127
|
-
});
|
|
128
|
-
if (!(0, handlePreviewToggles_1.handlePreviewToggles)(args)) {
|
|
129
|
-
if (!args.length) {
|
|
130
|
-
client.cli.help();
|
|
131
|
-
}
|
|
132
|
-
else {
|
|
133
|
-
cmd = client.cli.parse(process.argv);
|
|
134
|
-
}
|
|
16
|
+
else {
|
|
17
|
+
const { cli } = require("./cli");
|
|
18
|
+
cli(pkg);
|
|
135
19
|
}
|
package/lib/bin/mcp.js
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.mcp = void 0;
|
|
5
|
+
const logger_1 = require("../logger");
|
|
6
|
+
(0, logger_1.silenceStdout)();
|
|
7
|
+
const index_1 = require("../mcp/index");
|
|
8
|
+
const util_1 = require("util");
|
|
9
|
+
const types_1 = require("../mcp/types");
|
|
10
|
+
const STARTUP_MESSAGE = `
|
|
11
|
+
This is a running process of the Firebase MCP server. This command should only be executed by an MCP client. An example MCP client configuration might be:
|
|
12
|
+
|
|
13
|
+
{
|
|
14
|
+
"mcpServers": {
|
|
15
|
+
"firebase": {
|
|
16
|
+
"command": "firebase",
|
|
17
|
+
"args": ["experimental:mcp", "--dir", "/path/to/firebase/project"]
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
`;
|
|
22
|
+
async function mcp() {
|
|
23
|
+
const { values } = (0, util_1.parseArgs)({
|
|
24
|
+
options: {
|
|
25
|
+
only: { type: "string", default: "" },
|
|
26
|
+
dir: { type: "string" },
|
|
27
|
+
},
|
|
28
|
+
allowPositionals: true,
|
|
29
|
+
});
|
|
30
|
+
const activeFeatures = (values.only || "")
|
|
31
|
+
.split(",")
|
|
32
|
+
.filter((f) => types_1.SERVER_FEATURES.includes(f));
|
|
33
|
+
const server = new index_1.FirebaseMcpServer({ activeFeatures, projectRoot: values.dir });
|
|
34
|
+
await server.start();
|
|
35
|
+
if (process.stdin.isTTY)
|
|
36
|
+
process.stderr.write(STARTUP_MESSAGE);
|
|
37
|
+
}
|
|
38
|
+
exports.mcp = mcp;
|
package/lib/commands/index.js
CHANGED
|
@@ -190,6 +190,9 @@ function load(client) {
|
|
|
190
190
|
client.login.list = loadCommand("login-list");
|
|
191
191
|
client.login.use = loadCommand("login-use");
|
|
192
192
|
client.logout = loadCommand("logout");
|
|
193
|
+
if (experiments.isEnabled("mcp")) {
|
|
194
|
+
client.mcp = loadCommand("mcp");
|
|
195
|
+
}
|
|
193
196
|
client.open = loadCommand("open");
|
|
194
197
|
client.projects = {};
|
|
195
198
|
client.projects.addfirebase = loadCommand("projects-addfirebase");
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.command = void 0;
|
|
4
|
+
const command_1 = require("../command");
|
|
5
|
+
const requireAuth_1 = require("../requireAuth");
|
|
6
|
+
exports.command = new command_1.Command("experimental:mcp")
|
|
7
|
+
.description("Start an MCP server with access to the current working directory's project and resources.")
|
|
8
|
+
.before(requireAuth_1.requireAuth)
|
|
9
|
+
.action(() => {
|
|
10
|
+
throw new Error("MCP logic is implemented elsewhere, this should never be reached.");
|
|
11
|
+
});
|
|
@@ -101,12 +101,14 @@ async function beforeEmulatorCommand(options) {
|
|
|
101
101
|
const canStartWithoutConfig = options.only &&
|
|
102
102
|
!controller.shouldStart(optionsWithConfig, types_1.Emulators.FUNCTIONS) &&
|
|
103
103
|
!controller.shouldStart(optionsWithConfig, types_1.Emulators.HOSTING);
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
104
|
+
if (!constants_1.Constants.isDemoProject(options.project)) {
|
|
105
|
+
try {
|
|
106
|
+
await (0, requireAuth_1.requireAuth)(options);
|
|
107
|
+
}
|
|
108
|
+
catch (e) {
|
|
109
|
+
logger_1.logger.debug(e);
|
|
110
|
+
utils.logLabeledWarning("emulators", `You are not currently authenticated so some features may not work correctly. Please run ${clc.bold("firebase login")} to authenticate the CLI.`);
|
|
111
|
+
}
|
|
110
112
|
}
|
|
111
113
|
if (canStartWithoutConfig && !options.config) {
|
|
112
114
|
utils.logWarning("Could not find config (firebase.json) so using defaults.");
|
|
@@ -48,20 +48,20 @@ const EMULATOR_UPDATE_DETAILS = {
|
|
|
48
48
|
},
|
|
49
49
|
dataconnect: process.platform === "darwin"
|
|
50
50
|
? {
|
|
51
|
-
version: "2.
|
|
52
|
-
expectedSize:
|
|
53
|
-
expectedChecksum: "
|
|
51
|
+
version: "2.4.0",
|
|
52
|
+
expectedSize: 27316992,
|
|
53
|
+
expectedChecksum: "615fb819b38dc61a36f18f0f8017379d",
|
|
54
54
|
}
|
|
55
55
|
: process.platform === "win32"
|
|
56
56
|
? {
|
|
57
|
-
version: "2.
|
|
58
|
-
expectedSize:
|
|
59
|
-
expectedChecksum: "
|
|
57
|
+
version: "2.4.0",
|
|
58
|
+
expectedSize: 27774464,
|
|
59
|
+
expectedChecksum: "1968300587f73fff246aa5c2cf9008fe",
|
|
60
60
|
}
|
|
61
61
|
: {
|
|
62
|
-
version: "2.
|
|
63
|
-
expectedSize:
|
|
64
|
-
expectedChecksum: "
|
|
62
|
+
version: "2.4.0",
|
|
63
|
+
expectedSize: 27230360,
|
|
64
|
+
expectedChecksum: "88407f13d5647aab496c3810666867a4",
|
|
65
65
|
},
|
|
66
66
|
};
|
|
67
67
|
exports.DownloadDetails = {
|
package/lib/emulator/env.js
CHANGED
|
@@ -6,7 +6,6 @@ const types_1 = require("./types");
|
|
|
6
6
|
const functionsEmulatorShared_1 = require("./functionsEmulatorShared");
|
|
7
7
|
const defaultCredentials_1 = require("../defaultCredentials");
|
|
8
8
|
function setEnvVarsForEmulators(env, emulators) {
|
|
9
|
-
maybeUsePortForwarding(emulators);
|
|
10
9
|
for (const emu of emulators) {
|
|
11
10
|
const host = (0, functionsEmulatorShared_1.formatHost)(emu);
|
|
12
11
|
switch (emu.name) {
|
|
@@ -60,29 +59,29 @@ async function getCredentialsEnvironment(account, logger, logLabel, silent = fal
|
|
|
60
59
|
return credentialEnv;
|
|
61
60
|
}
|
|
62
61
|
exports.getCredentialsEnvironment = getCredentialsEnvironment;
|
|
63
|
-
function maybeUsePortForwarding(
|
|
62
|
+
function maybeUsePortForwarding(i) {
|
|
64
63
|
var _a;
|
|
65
64
|
const portForwardingHost = process.env.WEB_HOST;
|
|
66
65
|
if (portForwardingHost) {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
}
|
|
71
|
-
const url = `${info.port}-${portForwardingHost}`;
|
|
72
|
-
info.host = url;
|
|
73
|
-
info.listen = (_a = info.listen) === null || _a === void 0 ? void 0 : _a.map((l) => {
|
|
74
|
-
l.address = url;
|
|
75
|
-
l.port = 443;
|
|
76
|
-
return l;
|
|
77
|
-
});
|
|
78
|
-
info.port = 443;
|
|
79
|
-
const fsInfo = info;
|
|
80
|
-
if (fsInfo.webSocketPort) {
|
|
81
|
-
fsInfo.webSocketHost = `${fsInfo.webSocketPort}-${portForwardingHost}`;
|
|
82
|
-
fsInfo.webSocketPort = 443;
|
|
83
|
-
}
|
|
66
|
+
const info = Object.assign({}, i);
|
|
67
|
+
if (info.host.includes(portForwardingHost)) {
|
|
68
|
+
return info;
|
|
84
69
|
}
|
|
70
|
+
const url = `${info.port}-${portForwardingHost}`;
|
|
71
|
+
info.host = url;
|
|
72
|
+
info.listen = (_a = info.listen) === null || _a === void 0 ? void 0 : _a.map((l) => {
|
|
73
|
+
l.address = url;
|
|
74
|
+
l.port = 443;
|
|
75
|
+
return l;
|
|
76
|
+
});
|
|
77
|
+
info.port = 443;
|
|
78
|
+
const fsInfo = info;
|
|
79
|
+
if (fsInfo.webSocketPort) {
|
|
80
|
+
fsInfo.webSocketHost = `${fsInfo.webSocketPort}-${portForwardingHost}`;
|
|
81
|
+
fsInfo.webSocketPort = 443;
|
|
82
|
+
}
|
|
83
|
+
return info;
|
|
85
84
|
}
|
|
86
|
-
return
|
|
85
|
+
return i;
|
|
87
86
|
}
|
|
88
87
|
exports.maybeUsePortForwarding = maybeUsePortForwarding;
|
|
@@ -912,7 +912,6 @@ class FunctionsEmulator {
|
|
|
912
912
|
if (this.args.remoteEmulators) {
|
|
913
913
|
emulatorInfos = emulatorInfos.concat(Object.values(this.args.remoteEmulators));
|
|
914
914
|
}
|
|
915
|
-
(0, env_1.maybeUsePortForwarding)(emulatorInfos);
|
|
916
915
|
(0, env_1.setEnvVarsForEmulators)(envs, emulatorInfos);
|
|
917
916
|
if (this.debugMode) {
|
|
918
917
|
envs["FUNCTION_DEBUG_MODE"] = "true";
|
package/lib/emulator/hub.js
CHANGED
|
@@ -11,6 +11,7 @@ const hubExport_1 = require("./hubExport");
|
|
|
11
11
|
const registry_1 = require("./registry");
|
|
12
12
|
const ExpressBasedEmulator_1 = require("./ExpressBasedEmulator");
|
|
13
13
|
const vsCodeUtils_1 = require("../vsCodeUtils");
|
|
14
|
+
const env_1 = require("./env");
|
|
14
15
|
const pkg = require("../../package.json");
|
|
15
16
|
class EmulatorHub extends ExpressBasedEmulator_1.ExpressBasedEmulator {
|
|
16
17
|
static readLocatorFile(projectId) {
|
|
@@ -44,7 +45,7 @@ class EmulatorHub extends ExpressBasedEmulator_1.ExpressBasedEmulator {
|
|
|
44
45
|
getRunningEmulatorsMapping() {
|
|
45
46
|
const emulators = {};
|
|
46
47
|
for (const info of registry_1.EmulatorRegistry.listRunningWithInfo()) {
|
|
47
|
-
emulators[info.name] = Object.assign({ listen: this.args.listenForEmulator[info.name] }, info);
|
|
48
|
+
emulators[info.name] = (0, env_1.maybeUsePortForwarding)(Object.assign({ listen: this.args.listenForEmulator[info.name] }, info));
|
|
48
49
|
}
|
|
49
50
|
return emulators;
|
|
50
51
|
}
|
package/lib/emulator/ui.js
CHANGED
|
@@ -12,7 +12,6 @@ const constants_1 = require("./constants");
|
|
|
12
12
|
const track_1 = require("../track");
|
|
13
13
|
const ExpressBasedEmulator_1 = require("./ExpressBasedEmulator");
|
|
14
14
|
const experiments_1 = require("../experiments");
|
|
15
|
-
const env_1 = require("./env");
|
|
16
15
|
class EmulatorUI extends ExpressBasedEmulator_1.ExpressBasedEmulator {
|
|
17
16
|
constructor(args) {
|
|
18
17
|
super({
|
|
@@ -37,7 +36,6 @@ class EmulatorUI extends ExpressBasedEmulator_1.ExpressBasedEmulator {
|
|
|
37
36
|
const webDir = path.join(downloadDetails.unzipDir, "client");
|
|
38
37
|
app.get("/api/config", this.jsonHandler(() => {
|
|
39
38
|
const emulatorInfos = hub.getRunningEmulatorsMapping();
|
|
40
|
-
(0, env_1.maybeUsePortForwarding)(Object.values(emulatorInfos));
|
|
41
39
|
const json = Object.assign({ projectId, experiments: enabledExperiments !== null && enabledExperiments !== void 0 ? enabledExperiments : [], analytics: emulatorGaSession }, emulatorInfos);
|
|
42
40
|
return Promise.resolve(json);
|
|
43
41
|
}));
|
package/lib/experiments.js
CHANGED
|
@@ -100,6 +100,11 @@ exports.ALL_EXPERIMENTS = experiments({
|
|
|
100
100
|
default: false,
|
|
101
101
|
public: true,
|
|
102
102
|
},
|
|
103
|
+
mcp: {
|
|
104
|
+
shortDescription: "Adds experimental `firebase mcp` command for running a Firebase MCP server.",
|
|
105
|
+
default: false,
|
|
106
|
+
public: false,
|
|
107
|
+
},
|
|
103
108
|
});
|
|
104
109
|
function isValidExperiment(name) {
|
|
105
110
|
return Object.keys(exports.ALL_EXPERIMENTS).includes(name);
|
package/lib/frameworks/index.js
CHANGED
|
@@ -82,8 +82,12 @@ async function prepareFrameworks(purpose, targetNames, context, options, emulato
|
|
|
82
82
|
var _a, _b, _c, _d, _e, _f;
|
|
83
83
|
var _g, _h, _j, _k, _l;
|
|
84
84
|
const project = (0, projectUtils_1.needProjectId)(context || options);
|
|
85
|
+
const isDemoProject = constants_1.Constants.isDemoProject(project);
|
|
85
86
|
const projectRoot = (0, projectPath_1.resolveProjectPath)(options, ".");
|
|
86
87
|
const account = (0, auth_1.getProjectDefaultAccount)(projectRoot);
|
|
88
|
+
if (isDemoProject) {
|
|
89
|
+
options.site = project;
|
|
90
|
+
}
|
|
87
91
|
if (!options.site) {
|
|
88
92
|
try {
|
|
89
93
|
await (0, requireHostingSite_1.requireHostingSite)(options);
|
|
@@ -150,7 +154,6 @@ async function prepareFrameworks(purpose, targetNames, context, options, emulato
|
|
|
150
154
|
});
|
|
151
155
|
let firebaseConfig = null;
|
|
152
156
|
if (usesFirebaseJsSdk) {
|
|
153
|
-
const isDemoProject = constants_1.Constants.isDemoProject(project);
|
|
154
157
|
const sites = isDemoProject ? (0, api_1.listDemoSites)(project) : await (0, api_1.listSites)(project);
|
|
155
158
|
const selectedSite = sites.find((it) => it.name && it.name.split("/").pop() === site);
|
|
156
159
|
if (selectedSite) {
|
package/lib/gcp/auth.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.updateAuthDomains = exports.getAuthDomains = void 0;
|
|
3
|
+
exports.setCustomClaim = exports.disableUser = exports.findUser = exports.updateAuthDomains = exports.getAuthDomains = void 0;
|
|
4
4
|
const apiv2_1 = require("../apiv2");
|
|
5
5
|
const api_1 = require("../api");
|
|
6
6
|
const apiClient = new apiv2_1.Client({ urlPrefix: (0, api_1.identityOrigin)(), auth: true });
|
|
@@ -17,3 +17,58 @@ async function updateAuthDomains(project, authDomains) {
|
|
|
17
17
|
return res.body.authorizedDomains;
|
|
18
18
|
}
|
|
19
19
|
exports.updateAuthDomains = updateAuthDomains;
|
|
20
|
+
async function findUser(project, email, phone, uid) {
|
|
21
|
+
const expression = {
|
|
22
|
+
email,
|
|
23
|
+
phoneNumber: phone,
|
|
24
|
+
userId: uid,
|
|
25
|
+
};
|
|
26
|
+
const res = await apiClient.post(`/v1/projects/${project}/accounts:query`, {
|
|
27
|
+
expression: [expression],
|
|
28
|
+
limit: "1",
|
|
29
|
+
});
|
|
30
|
+
if (res.body.userInfo.length === 0) {
|
|
31
|
+
throw new Error("No users found");
|
|
32
|
+
}
|
|
33
|
+
const modifiedUserInfo = res.body.userInfo.map((ui) => {
|
|
34
|
+
ui.uid = ui.localId;
|
|
35
|
+
delete ui.localId;
|
|
36
|
+
return ui;
|
|
37
|
+
});
|
|
38
|
+
return modifiedUserInfo[0];
|
|
39
|
+
}
|
|
40
|
+
exports.findUser = findUser;
|
|
41
|
+
async function disableUser(project, uid, disabled) {
|
|
42
|
+
const res = await apiClient.post("/v1/accounts:update", {
|
|
43
|
+
disableUser: disabled,
|
|
44
|
+
targetProjectId: project,
|
|
45
|
+
localId: uid,
|
|
46
|
+
});
|
|
47
|
+
return res.status === 200;
|
|
48
|
+
}
|
|
49
|
+
exports.disableUser = disableUser;
|
|
50
|
+
async function setCustomClaim(project, uid, claim, options) {
|
|
51
|
+
let user = await findUser(project, undefined, undefined, uid);
|
|
52
|
+
if (user.uid !== uid) {
|
|
53
|
+
throw new Error(`Could not find ${uid} in the auth db, please check the uid again.`);
|
|
54
|
+
}
|
|
55
|
+
let reqClaim = JSON.stringify(claim);
|
|
56
|
+
if (options === null || options === void 0 ? void 0 : options.merge) {
|
|
57
|
+
let attributeJson = new Map();
|
|
58
|
+
if (user.customAttributes !== undefined && user.customAttributes !== "") {
|
|
59
|
+
attributeJson = JSON.parse(user.customAttributes);
|
|
60
|
+
}
|
|
61
|
+
reqClaim = JSON.stringify(Object.assign(Object.assign({}, attributeJson), claim));
|
|
62
|
+
}
|
|
63
|
+
const res = await apiClient.post("/v1/accounts:update", {
|
|
64
|
+
customAttributes: reqClaim,
|
|
65
|
+
targetProjectId: project,
|
|
66
|
+
localId: uid,
|
|
67
|
+
});
|
|
68
|
+
if (res.status !== 200) {
|
|
69
|
+
throw new Error("something went wrong in the request");
|
|
70
|
+
}
|
|
71
|
+
user = await findUser(project, undefined, undefined, uid);
|
|
72
|
+
return user;
|
|
73
|
+
}
|
|
74
|
+
exports.setCustomClaim = setCustomClaim;
|
package/lib/gcp/firestore.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getBackupSchedule = exports.listBackupSchedules = exports.getBackup = exports.listBackups = exports.deleteBackupSchedule = exports.deleteBackup = exports.updateBackupSchedule = exports.createBackupSchedule = exports.deleteDocuments = exports.deleteDocument = exports.listCollectionIds = exports.getDatabase = exports.DayOfWeek = void 0;
|
|
3
|
+
exports.getBackupSchedule = exports.listBackupSchedules = exports.getBackup = exports.listBackups = exports.deleteBackupSchedule = exports.deleteBackup = exports.updateBackupSchedule = exports.createBackupSchedule = exports.deleteDocuments = exports.deleteDocument = exports.getDocuments = exports.listCollectionIds = exports.getDatabase = exports.DayOfWeek = void 0;
|
|
4
4
|
const api_1 = require("../api");
|
|
5
5
|
const apiv2_1 = require("../apiv2");
|
|
6
6
|
const logger_1 = require("../logger");
|
|
@@ -50,6 +50,17 @@ function listCollectionIds(project, allowEmulator = false) {
|
|
|
50
50
|
});
|
|
51
51
|
}
|
|
52
52
|
exports.listCollectionIds = listCollectionIds;
|
|
53
|
+
async function getDocuments(project, paths, allowEmulator) {
|
|
54
|
+
const apiClient = allowEmulator ? emuOrProdClient : prodOnlyClient;
|
|
55
|
+
const basePath = `projects/${project}/databases/(default)/documents`;
|
|
56
|
+
const url = `${basePath}:batchGet`;
|
|
57
|
+
const fullPaths = paths.map((p) => `${basePath}/${p}`);
|
|
58
|
+
const res = await apiClient.post(url, { documents: fullPaths });
|
|
59
|
+
const out = { documents: [], missing: [] };
|
|
60
|
+
res.body.map((r) => (r.missing ? out.missing.push(r.missing) : out.documents.push(r.found)));
|
|
61
|
+
return out;
|
|
62
|
+
}
|
|
63
|
+
exports.getDocuments = getDocuments;
|
|
53
64
|
async function deleteDocument(doc, allowEmulator = false) {
|
|
54
65
|
const apiClient = allowEmulator ? emuOrProdClient : prodOnlyClient;
|
|
55
66
|
return apiClient.delete(doc.name);
|
package/lib/hosting/api.js
CHANGED
|
@@ -9,6 +9,7 @@ const expireUtils_1 = require("../hosting/expireUtils");
|
|
|
9
9
|
const auth_1 = require("../gcp/auth");
|
|
10
10
|
const proto = require("../gcp/proto");
|
|
11
11
|
const utils_1 = require("../utils");
|
|
12
|
+
const constants_1 = require("../emulator/constants");
|
|
12
13
|
const ONE_WEEK_MS = 604800000;
|
|
13
14
|
var ReleaseType;
|
|
14
15
|
(function (ReleaseType) {
|
|
@@ -298,6 +299,9 @@ async function getAllSiteDomains(projectId, siteId) {
|
|
|
298
299
|
}
|
|
299
300
|
exports.getAllSiteDomains = getAllSiteDomains;
|
|
300
301
|
async function getDeploymentDomain(projectId, siteId, hostingChannel) {
|
|
302
|
+
if (constants_1.Constants.isDemoProject(projectId)) {
|
|
303
|
+
return null;
|
|
304
|
+
}
|
|
301
305
|
if (hostingChannel) {
|
|
302
306
|
const channel = await getChannel(projectId, siteId, hostingChannel);
|
|
303
307
|
return channel && (0, utils_1.getHostnameFromUrl)(channel === null || channel === void 0 ? void 0 : channel.url);
|