firebase-tools 14.20.0 → 14.22.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.
Files changed (93) hide show
  1. package/lib/appUtils.js +2 -1
  2. package/lib/command.js +5 -9
  3. package/lib/commands/dataconnect-sdk-generate.js +66 -11
  4. package/lib/commands/deploy.js +6 -4
  5. package/lib/commands/firestore-databases-clone.js +99 -0
  6. package/lib/commands/functions-secrets-set.js +19 -1
  7. package/lib/commands/hosting-sites-create.js +4 -3
  8. package/lib/commands/index.js +1 -0
  9. package/lib/commands/init.js +12 -8
  10. package/lib/commands/internaltesting-functions-discover.js +1 -3
  11. package/lib/dataconnect/provisionCloudSql.js +3 -2
  12. package/lib/deploy/extensions/prepare.js +3 -1
  13. package/lib/deploy/functions/checkIam.js +1 -1
  14. package/lib/deploy/functions/functionsDeployHelper.js +8 -7
  15. package/lib/deploy/functions/params.js +15 -5
  16. package/lib/deploy/functions/prepare.js +9 -6
  17. package/lib/detectProjectRoot.js +1 -1
  18. package/lib/emulator/downloadableEmulatorInfo.json +18 -18
  19. package/lib/emulator/hubExport.js +5 -0
  20. package/lib/experiments.js +0 -7
  21. package/lib/firestore/api.js +15 -0
  22. package/lib/firestore/util.js +22 -1
  23. package/lib/frameworks/angular/index.js +1 -1
  24. package/lib/frameworks/flutter/index.js +1 -1
  25. package/lib/frameworks/next/index.js +1 -1
  26. package/lib/frameworks/nuxt/index.js +1 -1
  27. package/lib/frameworks/vite/index.js +5 -2
  28. package/lib/functions/projectConfig.js +5 -1
  29. package/lib/functions/secrets.js +14 -1
  30. package/lib/hosting/interactive.js +14 -19
  31. package/lib/init/features/dataconnect/index.js +21 -20
  32. package/lib/init/features/dataconnect/sdk.js +44 -21
  33. package/lib/init/features/functions/index.js +1 -0
  34. package/lib/init/features/hosting/index.js +96 -93
  35. package/lib/init/features/index.js +3 -2
  36. package/lib/init/index.js +7 -3
  37. package/lib/mcp/index.js +46 -18
  38. package/lib/mcp/prompt.js +4 -1
  39. package/lib/mcp/prompts/core/consult.js +1 -1
  40. package/lib/mcp/prompts/core/deploy.js +1 -1
  41. package/lib/mcp/prompts/core/init.js +1 -1
  42. package/lib/mcp/prompts/crashlytics/connect.js +1 -1
  43. package/lib/mcp/prompts/dataconnect/schema.js +1 -1
  44. package/lib/mcp/prompts/index.js +20 -10
  45. package/lib/mcp/resources/guides/init_backend.js +3 -26
  46. package/lib/mcp/resources/guides/init_hosting.js +15 -10
  47. package/lib/mcp/tool.js +17 -2
  48. package/lib/mcp/tools/apphosting/fetch_logs.js +1 -1
  49. package/lib/mcp/tools/apphosting/list_backends.js +1 -1
  50. package/lib/mcp/tools/auth/get_users.js +1 -1
  51. package/lib/mcp/tools/auth/set_sms_region_policy.js +1 -1
  52. package/lib/mcp/tools/auth/update_user.js +1 -1
  53. package/lib/mcp/tools/core/create_android_sha.js +1 -1
  54. package/lib/mcp/tools/core/create_app.js +1 -1
  55. package/lib/mcp/tools/core/create_project.js +1 -1
  56. package/lib/mcp/tools/core/get_environment.js +1 -1
  57. package/lib/mcp/tools/core/get_project.js +1 -1
  58. package/lib/mcp/tools/core/get_sdk_config.js +1 -1
  59. package/lib/mcp/tools/core/get_security_rules.js +1 -1
  60. package/lib/mcp/tools/core/init.js +30 -2
  61. package/lib/mcp/tools/core/list_apps.js +1 -1
  62. package/lib/mcp/tools/core/list_projects.js +1 -1
  63. package/lib/mcp/tools/core/login.js +1 -1
  64. package/lib/mcp/tools/core/logout.js +1 -1
  65. package/lib/mcp/tools/core/read_resources.js +1 -1
  66. package/lib/mcp/tools/core/update_environment.js +1 -1
  67. package/lib/mcp/tools/core/validate_security_rules.js +15 -1
  68. package/lib/mcp/tools/crashlytics/events.js +3 -3
  69. package/lib/mcp/tools/crashlytics/issues.js +3 -3
  70. package/lib/mcp/tools/crashlytics/notes.js +4 -4
  71. package/lib/mcp/tools/crashlytics/reports.js +6 -6
  72. package/lib/mcp/tools/dataconnect/compile.js +1 -1
  73. package/lib/mcp/tools/dataconnect/execute.js +1 -1
  74. package/lib/mcp/tools/dataconnect/generate_operation.js +1 -1
  75. package/lib/mcp/tools/dataconnect/generate_schema.js +1 -1
  76. package/lib/mcp/tools/dataconnect/list_services.js +1 -1
  77. package/lib/mcp/tools/firestore/delete_document.js +1 -1
  78. package/lib/mcp/tools/firestore/get_documents.js +1 -1
  79. package/lib/mcp/tools/firestore/list_collections.js +1 -1
  80. package/lib/mcp/tools/firestore/query_collection.js +1 -1
  81. package/lib/mcp/tools/functions/get_logs.js +1 -1
  82. package/lib/mcp/tools/index.js +14 -4
  83. package/lib/mcp/tools/messaging/send_message.js +1 -1
  84. package/lib/mcp/tools/realtime_database/get_data.js +1 -1
  85. package/lib/mcp/tools/realtime_database/set_data.js +1 -1
  86. package/lib/mcp/tools/remoteconfig/get_template.js +1 -1
  87. package/lib/mcp/tools/remoteconfig/update_template.js +1 -1
  88. package/lib/mcp/tools/storage/get_download_url.js +1 -1
  89. package/lib/mcp/util/availability.js +22 -0
  90. package/lib/mcp/util/crashlytics/availability.js +81 -0
  91. package/lib/mcp/util.js +26 -6
  92. package/package.json +1 -1
  93. package/schema/firebase-config.json +3 -0
@@ -12,20 +12,30 @@ const index_8 = require("./crashlytics/index");
12
12
  const index_9 = require("./apphosting/index");
13
13
  const index_10 = require("./realtime_database/index");
14
14
  const index_11 = require("./functions/index");
15
- function availableTools(activeFeatures) {
15
+ async function availableTools(ctx, activeFeatures) {
16
+ const allTools = getAllTools(activeFeatures);
17
+ const availabilities = await Promise.all(allTools.map((t) => {
18
+ if (t.isAvailable) {
19
+ return t.isAvailable(ctx);
20
+ }
21
+ return true;
22
+ }));
23
+ return allTools.filter((_, i) => availabilities[i]);
24
+ }
25
+ exports.availableTools = availableTools;
26
+ function getAllTools(activeFeatures) {
16
27
  const toolDefs = [];
17
28
  if (!(activeFeatures === null || activeFeatures === void 0 ? void 0 : activeFeatures.length)) {
18
29
  activeFeatures = Object.keys(tools);
19
30
  }
20
31
  if (!activeFeatures.includes("core")) {
21
- activeFeatures = ["core", ...activeFeatures];
32
+ activeFeatures.unshift("core");
22
33
  }
23
34
  for (const key of activeFeatures) {
24
35
  toolDefs.push(...tools[key]);
25
36
  }
26
37
  return toolDefs;
27
38
  }
28
- exports.availableTools = availableTools;
29
39
  const tools = {
30
40
  core: addFeaturePrefix("firebase", index_4.coreTools),
31
41
  firestore: addFeaturePrefix("firestore", index_3.firestoreTools),
@@ -44,7 +54,7 @@ function addFeaturePrefix(feature, tools) {
44
54
  }
45
55
  function markdownDocsOfTools() {
46
56
  var _a, _b, _c;
47
- const allTools = availableTools([]);
57
+ const allTools = getAllTools([]);
48
58
  let doc = `
49
59
  | Tool Name | Feature Group | Description |
50
60
  | --------- | ------------- | ----------- |`;
@@ -5,7 +5,7 @@ const zod_1 = require("zod");
5
5
  const tool_1 = require("../../tool");
6
6
  const util_1 = require("../../util");
7
7
  const sendMessage_1 = require("../../../messaging/sendMessage");
8
- exports.send_message = (0, tool_1.tool)({
8
+ exports.send_message = (0, tool_1.tool)("messaging", {
9
9
  name: "send_message",
10
10
  description: "Use this to send a message to a Firebase Cloud Messaging registration token or topic. ONLY ONE of `registration_token` or `topic` may be supplied in a specific call.",
11
11
  inputSchema: zod_1.z.object({
@@ -8,7 +8,7 @@ const url = require("node:url");
8
8
  const apiv2_1 = require("../../../apiv2");
9
9
  const consumers_1 = require("node:stream/consumers");
10
10
  const node_path_1 = require("node:path");
11
- exports.get_data = (0, tool_1.tool)({
11
+ exports.get_data = (0, tool_1.tool)("database", {
12
12
  name: "get_data",
13
13
  description: "Use this to retrieve data from the specified location in a Firebase Realtime Database.",
14
14
  inputSchema: zod_1.z.object({
@@ -9,7 +9,7 @@ const utils_1 = require("../../../utils");
9
9
  const apiv2_1 = require("../../../apiv2");
10
10
  const error_1 = require("../../../error");
11
11
  const node_path_1 = require("node:path");
12
- exports.set_data = (0, tool_1.tool)({
12
+ exports.set_data = (0, tool_1.tool)("database", {
13
13
  name: "set_data",
14
14
  description: "Use this to write data to the specified location in a Firebase Realtime Database.",
15
15
  inputSchema: zod_1.z.object({
@@ -5,7 +5,7 @@ const zod_1 = require("zod");
5
5
  const tool_1 = require("../../tool");
6
6
  const util_1 = require("../../util");
7
7
  const get_1 = require("../../../remoteconfig/get");
8
- exports.get_template = (0, tool_1.tool)({
8
+ exports.get_template = (0, tool_1.tool)("remoteconfig", {
9
9
  name: "get_template",
10
10
  description: "Use this to retrieve the specified Firebase Remote Config template from the currently active Firebase Project.",
11
11
  inputSchema: zod_1.z.object({
@@ -6,7 +6,7 @@ const tool_1 = require("../../tool");
6
6
  const util_1 = require("../../util");
7
7
  const publish_1 = require("../../../remoteconfig/publish");
8
8
  const rollback_1 = require("../../../remoteconfig/rollback");
9
- exports.update_template = (0, tool_1.tool)({
9
+ exports.update_template = (0, tool_1.tool)("remoteconfig", {
10
10
  name: "update_template",
11
11
  description: "Use this to publish a new remote config template or roll back to a specific version for the project",
12
12
  inputSchema: zod_1.z
@@ -6,7 +6,7 @@ const tool_1 = require("../../tool");
6
6
  const util_1 = require("../../util");
7
7
  const storage_1 = require("../../../gcp/storage");
8
8
  const types_1 = require("../../../emulator/types");
9
- exports.get_object_download_url = (0, tool_1.tool)({
9
+ exports.get_object_download_url = (0, tool_1.tool)("storage", {
10
10
  name: "get_object_download_url",
11
11
  description: "Use this to retrieve the download URL for an object in a Cloud Storage for Firebase bucket.",
12
12
  inputSchema: zod_1.z.object({
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getDefaultFeatureAvailabilityCheck = void 0;
4
+ const util_1 = require("../util");
5
+ const availability_1 = require("./crashlytics/availability");
6
+ const DEFAULT_AVAILABILITY_CHECKS = {
7
+ core: async (ctx) => true,
8
+ firestore: (ctx) => (0, util_1.checkFeatureActive)("firestore", ctx.projectId, { config: ctx.config }),
9
+ storage: (ctx) => (0, util_1.checkFeatureActive)("storage", ctx.projectId, { config: ctx.config }),
10
+ dataconnect: (ctx) => (0, util_1.checkFeatureActive)("dataconnect", ctx.projectId, { config: ctx.config }),
11
+ auth: (ctx) => (0, util_1.checkFeatureActive)("auth", ctx.projectId, { config: ctx.config }),
12
+ messaging: (ctx) => (0, util_1.checkFeatureActive)("messaging", ctx.projectId, { config: ctx.config }),
13
+ functions: (ctx) => (0, util_1.checkFeatureActive)("functions", ctx.projectId, { config: ctx.config }),
14
+ remoteconfig: (ctx) => (0, util_1.checkFeatureActive)("remoteconfig", ctx.projectId, { config: ctx.config }),
15
+ crashlytics: availability_1.isCrashlyticsAvailable,
16
+ apphosting: (ctx) => (0, util_1.checkFeatureActive)("apphosting", ctx.projectId, { config: ctx.config }),
17
+ database: (ctx) => (0, util_1.checkFeatureActive)("database", ctx.projectId, { config: ctx.config }),
18
+ };
19
+ function getDefaultFeatureAvailabilityCheck(feature) {
20
+ return DEFAULT_AVAILABILITY_CHECKS[feature];
21
+ }
22
+ exports.getDefaultFeatureAvailabilityCheck = getDefaultFeatureAvailabilityCheck;
@@ -0,0 +1,81 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isCrashlyticsAvailable = void 0;
4
+ const appUtils_1 = require("../../../appUtils");
5
+ const fs = require("fs-extra");
6
+ const path = require("path");
7
+ async function isCrashlyticsAvailable(ctx) {
8
+ ctx.host.log("debug", `Looking for whether crashlytics is installed...`);
9
+ return await isCrashlyticsInstalled(ctx);
10
+ }
11
+ exports.isCrashlyticsAvailable = isCrashlyticsAvailable;
12
+ async function isCrashlyticsInstalled(ctx) {
13
+ const host = ctx.host;
14
+ const projectDir = ctx.config.projectDir;
15
+ const platforms = await (0, appUtils_1.getPlatformsFromFolder)(projectDir);
16
+ if (!platforms.includes(appUtils_1.Platform.FLUTTER) &&
17
+ !platforms.includes(appUtils_1.Platform.ANDROID) &&
18
+ !platforms.includes(appUtils_1.Platform.IOS)) {
19
+ host.log("debug", `Found no supported Crashlytics platforms.`);
20
+ return false;
21
+ }
22
+ if (platforms.includes(appUtils_1.Platform.FLUTTER) && (await flutterAppUsesCrashlytics(projectDir))) {
23
+ host.log("debug", `Found Flutter app using Crashlytics`);
24
+ return true;
25
+ }
26
+ if (platforms.includes(appUtils_1.Platform.ANDROID) && (await androidAppUsesCrashlytics(projectDir))) {
27
+ host.log("debug", `Found Android app using Crashlytics`);
28
+ return true;
29
+ }
30
+ if (platforms.includes(appUtils_1.Platform.IOS) && (await iosAppUsesCrashlytics(projectDir))) {
31
+ host.log("debug", `Found iOS app using Crashlytics`);
32
+ return true;
33
+ }
34
+ host.log("debug", `Found supported platforms ${JSON.stringify(platforms)}, but did not find a Crashlytics dependency.`);
35
+ return false;
36
+ }
37
+ async function androidAppUsesCrashlytics(appPath) {
38
+ const buildGradleFiles = await (0, appUtils_1.detectFiles)(appPath, "build.gradle*");
39
+ const crashlyticsPattern = /(firebase-crashlytics|firebase\.crashlytics|com\.google\.firebase\.crashlytics)/;
40
+ for (const file of buildGradleFiles) {
41
+ const content = await fs.readFile(path.join(appPath, file), "utf8");
42
+ if (crashlyticsPattern.test(content)) {
43
+ return true;
44
+ }
45
+ }
46
+ return false;
47
+ }
48
+ async function iosAppUsesCrashlytics(appPath) {
49
+ const podfiles = await (0, appUtils_1.detectFiles)(appPath, "Podfile");
50
+ for (const file of podfiles) {
51
+ const content = await fs.readFile(path.join(appPath, file), "utf8");
52
+ if (content.includes("Crashlytics")) {
53
+ return true;
54
+ }
55
+ }
56
+ const swiftPackageFiles = await (0, appUtils_1.detectFiles)(appPath, "Package.swift");
57
+ for (const file of swiftPackageFiles) {
58
+ const content = await fs.readFile(path.join(appPath, file), "utf8");
59
+ if (content.includes("Crashlytics")) {
60
+ return true;
61
+ }
62
+ }
63
+ const cartFiles = await (0, appUtils_1.detectFiles)(appPath, "Cartfile*");
64
+ for (const file of cartFiles) {
65
+ const content = await fs.readFile(path.join(appPath, file), "utf8");
66
+ if (content.includes("Crashlytics")) {
67
+ return true;
68
+ }
69
+ }
70
+ return false;
71
+ }
72
+ async function flutterAppUsesCrashlytics(appPath) {
73
+ const pubspecFiles = await (0, appUtils_1.detectFiles)(appPath, "pubspec.yaml");
74
+ for (const file of pubspecFiles) {
75
+ const content = await fs.readFile(path.join(appPath, file), "utf8");
76
+ if (content.includes("firebase_crashlytics")) {
77
+ return true;
78
+ }
79
+ }
80
+ return false;
81
+ }
package/lib/mcp/util.js CHANGED
@@ -52,17 +52,37 @@ const SERVER_FEATURE_APIS = {
52
52
  apphosting: (0, api_1.apphostingOrigin)(),
53
53
  database: (0, api_1.realtimeOrigin)(),
54
54
  };
55
+ const DETECTED_API_FEATURES = {
56
+ core: undefined,
57
+ firestore: undefined,
58
+ storage: undefined,
59
+ dataconnect: undefined,
60
+ auth: undefined,
61
+ messaging: undefined,
62
+ functions: undefined,
63
+ remoteconfig: undefined,
64
+ crashlytics: undefined,
65
+ apphosting: undefined,
66
+ database: undefined,
67
+ };
55
68
  async function checkFeatureActive(feature, projectId, options) {
56
69
  var _a;
57
70
  if (feature in (((_a = options === null || options === void 0 ? void 0 : options.config) === null || _a === void 0 ? void 0 : _a.data) || {}))
58
71
  return true;
59
- try {
60
- if (projectId)
61
- return await (0, timeout_1.timeoutFallback)((0, ensureApiEnabled_1.check)(projectId, SERVER_FEATURE_APIS[feature], "", true), true, 3000);
62
- }
63
- catch (e) {
64
- return true;
72
+ if (DETECTED_API_FEATURES[feature] !== undefined)
73
+ return DETECTED_API_FEATURES[feature];
74
+ if (projectId) {
75
+ try {
76
+ const isActive = await (0, timeout_1.timeoutFallback)((0, ensureApiEnabled_1.check)(projectId, SERVER_FEATURE_APIS[feature], "", true), true, 3000);
77
+ DETECTED_API_FEATURES[feature] = isActive;
78
+ return isActive;
79
+ }
80
+ catch (e) {
81
+ DETECTED_API_FEATURES[feature] = true;
82
+ return true;
83
+ }
65
84
  }
85
+ DETECTED_API_FEATURES[feature] = false;
66
86
  return false;
67
87
  }
68
88
  exports.checkFeatureActive = checkFeatureActive;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "firebase-tools",
3
- "version": "14.20.0",
3
+ "version": "14.22.0",
4
4
  "description": "Command-Line Interface for Firebase",
5
5
  "main": "./lib/index.js",
6
6
  "bin": {
@@ -872,6 +872,9 @@
872
872
  "configDir": {
873
873
  "type": "string"
874
874
  },
875
+ "disallowLegacyRuntimeConfig": {
876
+ "type": "boolean"
877
+ },
875
878
  "ignore": {
876
879
  "items": {
877
880
  "type": "string"