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.
Files changed (61) hide show
  1. package/lib/appUtils.js +14 -15
  2. package/lib/archiveDirectory.js +7 -45
  3. package/lib/bin/cli.js +35 -8
  4. package/lib/bin/mcp.js +46 -8
  5. package/lib/command.js +5 -1
  6. package/lib/commands/dataconnect-execute.js +1 -1
  7. package/lib/commands/dataconnect-sdk-generate.js +7 -5
  8. package/lib/commands/dataconnect-sql-diff.js +7 -5
  9. package/lib/commands/dataconnect-sql-grant.js +12 -12
  10. package/lib/commands/dataconnect-sql-migrate.js +6 -4
  11. package/lib/commands/dataconnect-sql-setup.js +6 -4
  12. package/lib/commands/dataconnect-sql-shell.js +6 -4
  13. package/lib/commands/firestore-backups-list.js +1 -1
  14. package/lib/commands/functions-config-clone.js +2 -2
  15. package/lib/commands/functions-config-export.js +137 -92
  16. package/lib/commands/functions-config-get.js +1 -2
  17. package/lib/commands/functions-config-set.js +2 -2
  18. package/lib/commands/functions-config-unset.js +2 -2
  19. package/lib/commands/help.js +1 -1
  20. package/lib/commands/index.js +15 -10
  21. package/lib/commands/init.js +8 -0
  22. package/lib/config.js +1 -5
  23. package/lib/dataconnect/load.js +18 -21
  24. package/lib/deploy/database/prepare.js +1 -3
  25. package/lib/deploy/functions/prepare.js +5 -1
  26. package/lib/deploy/functions/prepareFunctionsUpload.js +1 -2
  27. package/lib/deploy/functions/runtimes/node/index.js +11 -12
  28. package/lib/deploy/functions/runtimes/node/versioning.js +2 -2
  29. package/lib/deploy/functions/validate.js +49 -2
  30. package/lib/emulator/commandUtils.js +1 -1
  31. package/lib/emulator/controller.js +1 -2
  32. package/lib/emulator/databaseEmulator.js +1 -5
  33. package/lib/emulator/downloadableEmulatorInfo.json +30 -30
  34. package/lib/emulator/functionsEmulator.js +0 -40
  35. package/lib/emulator/functionsEmulatorRuntime.js +1 -118
  36. package/lib/emulator/functionsEmulatorShared.js +1 -6
  37. package/lib/experiments.js +8 -1
  38. package/lib/extensions/extensionsHelper.js +0 -1
  39. package/lib/frameworks/constants.js +1 -1
  40. package/lib/fsAsync.js +11 -3
  41. package/lib/functionsConfig.js +39 -1
  42. package/lib/gcp/cloudsql/cloudsqladmin.js +1 -1
  43. package/lib/index.js +44 -1
  44. package/lib/init/features/dataconnect/resolver.js +111 -0
  45. package/lib/init/features/index.js +4 -1
  46. package/lib/init/features/project.js +1 -0
  47. package/lib/init/index.js +5 -0
  48. package/lib/mcp/index.js +31 -22
  49. package/lib/mcp/tools/core/get_environment.js +4 -1
  50. package/lib/mcp/tools/dataconnect/compile.js +13 -7
  51. package/lib/mcp/tools/dataconnect/execute.js +10 -7
  52. package/lib/mcp/tools/dataconnect/generate_operation.js +7 -3
  53. package/lib/mcp/tools/index.js +53 -44
  54. package/package.json +1 -2
  55. package/lib/deploy/functions/runtimes/node/extractTriggers.js +0 -23
  56. package/lib/deploy/functions/runtimes/node/parseTriggers.js +0 -332
  57. package/lib/deploy/functions/runtimes/node/triggerParser.js +0 -72
  58. package/lib/functions/deprecationWarnings.js +0 -21
  59. package/lib/functions/runtimeConfigExport.js +0 -141
  60. package/lib/handlePreviewToggles.js +0 -38
  61. package/lib/parseBoltRules.js +0 -29
@@ -0,0 +1,111 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.addSchemaToDataConnectYaml = exports.actuate = exports.askQuestions = void 0;
4
+ const clc = require("colorette");
5
+ const fs = require("fs-extra");
6
+ const path_1 = require("path");
7
+ const yaml = require("yaml");
8
+ const prompt_1 = require("../../../prompt");
9
+ const utils_1 = require("../../../utils");
10
+ const load_1 = require("../../../dataconnect/load");
11
+ const names_1 = require("../../../dataconnect/names");
12
+ const experiments = require("../../../experiments");
13
+ const cloudbilling_1 = require("../../../gcp/cloudbilling");
14
+ const track_1 = require("../../../track");
15
+ async function askQuestions(setup, config) {
16
+ var _a;
17
+ const resolverInfo = {
18
+ id: "",
19
+ uri: "",
20
+ serviceInfo: {},
21
+ };
22
+ const serviceInfos = await (0, load_1.loadAll)(setup.projectId || "", config);
23
+ if (!serviceInfos.length) {
24
+ throw new Error(`No Firebase Data Connect workspace found. Run ${clc.bold("firebase init dataconnect")} to set up a service and main schema.`);
25
+ }
26
+ else if (serviceInfos.length === 1) {
27
+ resolverInfo.serviceInfo = serviceInfos[0];
28
+ }
29
+ else {
30
+ const choices = serviceInfos.map((si) => {
31
+ const serviceName = (0, names_1.parseServiceName)(si.serviceName);
32
+ return {
33
+ name: `${serviceName.location}/${serviceName.serviceId}`,
34
+ value: si,
35
+ };
36
+ });
37
+ resolverInfo.serviceInfo = await (0, prompt_1.select)({
38
+ message: "Which service would you like to set up a custom resolver for?",
39
+ choices,
40
+ });
41
+ }
42
+ resolverInfo.id = await (0, prompt_1.input)({
43
+ message: `What ID would you like to use for your custom resolver?`,
44
+ default: (0, utils_1.newUniqueId)(`resolver`, ((_a = resolverInfo.serviceInfo.dataConnectYaml.schemas) === null || _a === void 0 ? void 0 : _a.map((sch) => sch.id || "")) || []),
45
+ });
46
+ resolverInfo.uri = `https://${resolverInfo.id}-${setup.projectNumber || "PROJECT_NUMBER"}.${resolverInfo.serviceInfo.dataConnectYaml.location}.run.app/graphql`;
47
+ (0, utils_1.logBullet)("Setting " +
48
+ clc.bold(resolverInfo.uri) +
49
+ " as the custom resolver URL. To change this, update your " +
50
+ clc.bold(`dataconnect.yaml`) +
51
+ " later.");
52
+ setup.featureInfo = setup.featureInfo || {};
53
+ setup.featureInfo.dataconnectResolver = resolverInfo;
54
+ }
55
+ exports.askQuestions = askQuestions;
56
+ async function actuate(setup, config) {
57
+ var _a;
58
+ if (!experiments.isEnabled("fdcwebhooks")) {
59
+ return;
60
+ }
61
+ const resolverInfo = (_a = setup.featureInfo) === null || _a === void 0 ? void 0 : _a.dataconnectResolver;
62
+ if (!resolverInfo) {
63
+ throw new Error("Data Connect resolver feature ResolverRequiredInfo not provided");
64
+ }
65
+ const startTime = Date.now();
66
+ try {
67
+ actuateWithInfo(config, resolverInfo);
68
+ }
69
+ finally {
70
+ const source = "init_resolver";
71
+ void (0, track_1.trackGA4)("dataconnect_init", {
72
+ source,
73
+ project_status: setup.projectId
74
+ ? (await (0, cloudbilling_1.isBillingEnabled)(setup))
75
+ ? "blaze"
76
+ : "spark"
77
+ : "missing",
78
+ }, Date.now() - startTime);
79
+ }
80
+ }
81
+ exports.actuate = actuate;
82
+ function actuateWithInfo(config, info) {
83
+ var _a;
84
+ const dataConnectYaml = JSON.parse(JSON.stringify((_a = info.serviceInfo) === null || _a === void 0 ? void 0 : _a.dataConnectYaml));
85
+ addSchemaToDataConnectYaml(dataConnectYaml, info);
86
+ info.serviceInfo.dataConnectYaml = dataConnectYaml;
87
+ const dataConnectYamlContents = yaml.stringify(dataConnectYaml);
88
+ const dataConnectYamlPath = (0, path_1.join)(info.serviceInfo.sourceDirectory, "dataconnect.yaml");
89
+ config.writeProjectFile((0, path_1.relative)(config.projectDir, dataConnectYamlPath), dataConnectYamlContents);
90
+ fs.ensureFileSync((0, path_1.join)(info.serviceInfo.sourceDirectory, `schema_${info.id}`, "schema.gql"));
91
+ }
92
+ function addSchemaToDataConnectYaml(dataConnectYaml, info) {
93
+ const secondarySchema = {
94
+ source: `./schema_${info.id}`,
95
+ id: info.id,
96
+ datasource: {
97
+ httpGraphql: {
98
+ uri: info.uri,
99
+ },
100
+ },
101
+ };
102
+ if (!dataConnectYaml.schemas) {
103
+ dataConnectYaml.schemas = [];
104
+ if (dataConnectYaml.schema) {
105
+ dataConnectYaml.schemas.push(dataConnectYaml.schema);
106
+ dataConnectYaml.schema = undefined;
107
+ }
108
+ }
109
+ dataConnectYaml.schemas.push(secondarySchema);
110
+ }
111
+ exports.addSchemaToDataConnectYaml = addSchemaToDataConnectYaml;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.aiLogicActuate = exports.aiLogicAskQuestions = exports.aitools = exports.apptestingAcutate = exports.apptestingAskQuestions = exports.genkit = exports.apphosting = exports.dataconnectSdkActuate = exports.dataconnectSdkAskQuestions = exports.dataconnectActuate = exports.dataconnectAskQuestions = exports.hostingGithub = exports.remoteconfig = exports.project = exports.extensions = exports.emulators = exports.storageActuate = exports.storageAskQuestions = exports.hostingActuate = exports.hostingAskQuestions = exports.functions = exports.firestoreActuate = exports.firestoreAskQuestions = exports.databaseActuate = exports.databaseAskQuestions = exports.account = void 0;
3
+ exports.aiLogicActuate = exports.aiLogicAskQuestions = exports.aitools = exports.apptestingAcutate = exports.apptestingAskQuestions = exports.genkit = exports.apphosting = exports.dataconnectResolverActuate = exports.dataconnectResolverAskQuestions = exports.dataconnectSdkActuate = exports.dataconnectSdkAskQuestions = exports.dataconnectActuate = exports.dataconnectAskQuestions = exports.hostingGithub = exports.remoteconfig = exports.project = exports.extensions = exports.emulators = exports.storageActuate = exports.storageAskQuestions = exports.hostingActuate = exports.hostingAskQuestions = exports.functions = exports.firestoreActuate = exports.firestoreAskQuestions = exports.databaseActuate = exports.databaseAskQuestions = exports.account = void 0;
4
4
  var account_1 = require("./account");
5
5
  Object.defineProperty(exports, "account", { enumerable: true, get: function () { return account_1.doSetup; } });
6
6
  var database_1 = require("./database");
@@ -33,6 +33,9 @@ Object.defineProperty(exports, "dataconnectActuate", { enumerable: true, get: fu
33
33
  var sdk_1 = require("./dataconnect/sdk");
34
34
  Object.defineProperty(exports, "dataconnectSdkAskQuestions", { enumerable: true, get: function () { return sdk_1.askQuestions; } });
35
35
  Object.defineProperty(exports, "dataconnectSdkActuate", { enumerable: true, get: function () { return sdk_1.actuate; } });
36
+ var resolver_1 = require("./dataconnect/resolver");
37
+ Object.defineProperty(exports, "dataconnectResolverAskQuestions", { enumerable: true, get: function () { return resolver_1.askQuestions; } });
38
+ Object.defineProperty(exports, "dataconnectResolverActuate", { enumerable: true, get: function () { return resolver_1.actuate; } });
36
39
  var apphosting_1 = require("./apphosting");
37
40
  Object.defineProperty(exports, "apphosting", { enumerable: true, get: function () { return apphosting_1.doSetup; } });
38
41
  var genkit_1 = require("./genkit");
@@ -88,6 +88,7 @@ async function usingProjectMetadata(setup, config, pm) {
88
88
  }
89
89
  _.set(setup.rcfile, "projects.default", pm.projectId);
90
90
  setup.projectId = pm.projectId;
91
+ setup.projectNumber = pm.projectNumber;
91
92
  setup.instance = (_a = pm.resources) === null || _a === void 0 ? void 0 : _a.realtimeDatabaseInstance;
92
93
  setup.projectLocation = (_b = pm.resources) === null || _b === void 0 ? void 0 : _b.locationId;
93
94
  utils.makeActiveProject(config.projectDir, pm.projectId);
package/lib/init/index.js CHANGED
@@ -29,6 +29,11 @@ const featuresList = [
29
29
  askQuestions: features.dataconnectSdkAskQuestions,
30
30
  actuate: features.dataconnectSdkActuate,
31
31
  },
32
+ {
33
+ name: "dataconnect:resolver",
34
+ askQuestions: features.dataconnectResolverAskQuestions,
35
+ actuate: features.dataconnectResolverActuate,
36
+ },
32
37
  { name: "functions", doSetup: features.functions },
33
38
  {
34
39
  name: "hosting",
package/lib/mcp/index.js CHANGED
@@ -4,26 +4,27 @@ exports.FirebaseMcpServer = void 0;
4
4
  const index_js_1 = require("@modelcontextprotocol/sdk/server/index.js");
5
5
  const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
6
6
  const types_js_1 = require("@modelcontextprotocol/sdk/types.js");
7
- const util_1 = require("./util");
8
- const types_1 = require("./types");
9
- const index_1 = require("./tools/index");
10
- const index_2 = require("./prompts/index");
11
- const configstore_1 = require("../configstore");
7
+ const crossSpawn = require("cross-spawn");
8
+ const node_fs_1 = require("node:fs");
12
9
  const command_1 = require("../command");
13
- const requireAuth_1 = require("../requireAuth");
14
- const projectUtils_1 = require("../projectUtils");
15
- const errors_1 = require("./errors");
16
- const track_1 = require("../track");
17
10
  const config_1 = require("../config");
18
- const rc_1 = require("../rc");
11
+ const configstore_1 = require("../configstore");
19
12
  const hubClient_1 = require("../emulator/hubClient");
20
- const node_fs_1 = require("node:fs");
21
- const logging_transport_1 = require("./logging-transport");
22
13
  const env_1 = require("../env");
14
+ const projectUtils_1 = require("../projectUtils");
15
+ const rc_1 = require("../rc");
16
+ const requireAuth_1 = require("../requireAuth");
23
17
  const timeout_1 = require("../timeout");
18
+ const track_1 = require("../track");
19
+ const errors_1 = require("./errors");
20
+ const logging_transport_1 = require("./logging-transport");
21
+ const index_1 = require("./prompts/index");
24
22
  const resources_1 = require("./resources");
25
- const crossSpawn = require("cross-spawn");
23
+ const index_2 = require("./tools/index");
24
+ const types_1 = require("./types");
25
+ const util_1 = require("./util");
26
26
  const availability_1 = require("./util/availability");
27
+ const cloudbilling_1 = require("../gcp/cloudbilling");
27
28
  const SERVER_VERSION = "0.3.0";
28
29
  const cmd = new command_1.Command("mcp");
29
30
  const orderedLogLevels = [
@@ -55,6 +56,7 @@ class FirebaseMcpServer {
55
56
  this.currentLogLevel = process.env.FIREBASE_MCP_DEBUG_LOG ? "debug" : undefined;
56
57
  this.activeFeatures = options.activeFeatures;
57
58
  this.startupRoot = options.projectRoot || process.env.PROJECT_ROOT;
59
+ this.enabledTools = options.enabledTools;
58
60
  this.server = new index_js_1.Server({ name: "firebase", version: SERVER_VERSION });
59
61
  this.server.registerCapabilities({
60
62
  tools: { listChanged: true },
@@ -135,7 +137,8 @@ class FirebaseMcpServer {
135
137
  this.logger.debug("detecting active features of Firebase MCP server...");
136
138
  const projectId = (await this.getProjectId()) || "";
137
139
  const accountEmail = await this.getAuthenticatedUser();
138
- const ctx = this._createMcpContext(projectId, accountEmail);
140
+ const isBillingEnabled = projectId ? await (0, cloudbilling_1.checkBillingEnabled)(projectId) : false;
141
+ const ctx = this._createMcpContext(projectId, accountEmail, isBillingEnabled);
139
142
  const detected = await Promise.all(types_1.SERVER_FEATURES.map(async (f) => {
140
143
  const availabilityCheck = (0, availability_1.getDefaultFeatureAvailabilityCheck)(f);
141
144
  if (await availabilityCheck(ctx))
@@ -172,8 +175,9 @@ class FirebaseMcpServer {
172
175
  const features = ((_a = this.activeFeatures) === null || _a === void 0 ? void 0 : _a.length) ? this.activeFeatures : this.detectedFeatures;
173
176
  const projectId = (await this.getProjectId()) || "";
174
177
  const accountEmail = await this.getAuthenticatedUser();
175
- const ctx = this._createMcpContext(projectId, accountEmail);
176
- return (0, index_1.availableTools)(ctx, features);
178
+ const isBillingEnabled = projectId ? await (0, cloudbilling_1.checkBillingEnabled)(projectId) : false;
179
+ const ctx = this._createMcpContext(projectId, accountEmail, isBillingEnabled);
180
+ return (0, index_2.availableTools)(ctx, features, this.enabledTools);
177
181
  }
178
182
  async getTool(name) {
179
183
  const tools = await this.getAvailableTools();
@@ -184,8 +188,9 @@ class FirebaseMcpServer {
184
188
  const features = ((_a = this.activeFeatures) === null || _a === void 0 ? void 0 : _a.length) ? this.activeFeatures : this.detectedFeatures;
185
189
  const projectId = (await this.getProjectId()) || "";
186
190
  const accountEmail = await this.getAuthenticatedUser();
187
- const ctx = this._createMcpContext(projectId, accountEmail);
188
- return (0, index_2.availablePrompts)(ctx, features);
191
+ const isBillingEnabled = projectId ? await (0, cloudbilling_1.checkBillingEnabled)(projectId) : false;
192
+ const ctx = this._createMcpContext(projectId, accountEmail, isBillingEnabled);
193
+ return (0, index_1.availablePrompts)(ctx, features);
189
194
  }
190
195
  async getPrompt(name) {
191
196
  const prompts = await this.getAvailablePrompts();
@@ -218,7 +223,7 @@ class FirebaseMcpServer {
218
223
  return null;
219
224
  }
220
225
  }
221
- _createMcpContext(projectId, accountEmail) {
226
+ _createMcpContext(projectId, accountEmail, isBillingEnabled) {
222
227
  const options = { projectDir: this.cachedProjectDir, cwd: this.cachedProjectDir };
223
228
  return {
224
229
  projectId: projectId,
@@ -227,6 +232,7 @@ class FirebaseMcpServer {
227
232
  rc: (0, rc_1.loadRC)(options),
228
233
  accountEmail,
229
234
  firebaseCliCommand: this._getFirebaseCliCommand(),
235
+ isBillingEnabled,
230
236
  };
231
237
  }
232
238
  _getFirebaseCliCommand() {
@@ -282,7 +288,8 @@ class FirebaseMcpServer {
282
288
  if (err)
283
289
  return err;
284
290
  }
285
- const toolsCtx = this._createMcpContext(projectId, accountEmail);
291
+ const isBillingEnabled = projectId ? await (0, cloudbilling_1.checkBillingEnabled)(projectId) : false;
292
+ const toolsCtx = this._createMcpContext(projectId, accountEmail, isBillingEnabled);
286
293
  try {
287
294
  const res = await tool.fn(toolArgs, toolsCtx);
288
295
  await this.trackGA4("mcp_tool_call", {
@@ -332,7 +339,8 @@ class FirebaseMcpServer {
332
339
  projectId = projectId || "";
333
340
  const skipAutoAuthForStudio = (0, env_1.isFirebaseStudio)();
334
341
  const accountEmail = await this.getAuthenticatedUser(skipAutoAuthForStudio);
335
- const promptsCtx = this._createMcpContext(projectId, accountEmail);
342
+ const isBillingEnabled = projectId ? await (0, cloudbilling_1.checkBillingEnabled)(projectId) : false;
343
+ const promptsCtx = this._createMcpContext(projectId, accountEmail, isBillingEnabled);
336
344
  try {
337
345
  const messages = await prompt.fn(promptArgs, promptsCtx);
338
346
  await this.trackGA4("mcp_get_prompt", {
@@ -366,7 +374,8 @@ class FirebaseMcpServer {
366
374
  projectId = projectId || "";
367
375
  const skipAutoAuthForStudio = (0, env_1.isFirebaseStudio)();
368
376
  const accountEmail = await this.getAuthenticatedUser(skipAutoAuthForStudio);
369
- const resourceCtx = this._createMcpContext(projectId, accountEmail);
377
+ const isBillingEnabled = projectId ? await (0, cloudbilling_1.checkBillingEnabled)(projectId) : false;
378
+ const resourceCtx = this._createMcpContext(projectId, accountEmail, isBillingEnabled);
370
379
  const resolved = await (0, resources_1.resolveResource)(req.params.uri, resourceCtx);
371
380
  if (!resolved) {
372
381
  throw new types_js_1.McpError(types_js_1.ErrorCode.InvalidParams, `Resource '${req.params.uri}' could not be found.`);
@@ -15,6 +15,7 @@ function hydrateTemplate(config) {
15
15
  : "<NONE>";
16
16
  const projectConfigPath = config.projectConfigPath || "<NO CONFIG PRESENT>";
17
17
  const geminiTosAccepted = config.geminiTosAccepted ? "Accepted" : "<NOT ACCEPTED>";
18
+ const billingEnabled = config.projectId ? (config.isBillingEnabled ? "Yes" : "No") : "N/A";
18
19
  const authenticatedUser = config.authenticatedUser || "<NONE>";
19
20
  const detectedApps = Object.entries(config.detectedAppIds).length > 0
20
21
  ? `\n\n${(0, js_yaml_1.dump)(config.detectedAppIds).trim()}\n`
@@ -30,6 +31,7 @@ Project Directory: ${config.projectDir}
30
31
  Project Config Path: ${projectConfigPath}
31
32
  Active Project ID: ${activeProject}
32
33
  Gemini in Firebase Terms of Service: ${geminiTosAccepted}
34
+ Billing Enabled: ${billingEnabled}
33
35
  Authenticated User: ${authenticatedUser}
34
36
  Detected App IDs: ${detectedApps}
35
37
  Available Project Aliases (format: '[alias]: [projectId]'): ${availableProjects}${hasOtherAccounts ? `\nAvailable Accounts: \n\n${availableAccounts}` : ""}
@@ -63,7 +65,7 @@ exports.get_environment = (0, tool_1.tool)("core", {
63
65
  requiresAuth: false,
64
66
  requiresProject: false,
65
67
  },
66
- }, async (_, { projectId, host, accountEmail, rc, config }) => {
68
+ }, async (_, { projectId, host, accountEmail, rc, config, isBillingEnabled }) => {
67
69
  const aliases = projectId ? (0, projectUtils_1.getAliases)({ rc }, projectId) : [];
68
70
  const geminiTosAccepted = !!configstore_1.configstore.get("gemini");
69
71
  const projectFileExists = config.projectFileExists("firebase.json");
@@ -84,6 +86,7 @@ exports.get_environment = (0, tool_1.tool)("core", {
84
86
  projectDir: host.cachedProjectDir,
85
87
  projectConfigPath: projectFileExists ? config.path("firebase.json") : undefined,
86
88
  geminiTosAccepted,
89
+ isBillingEnabled,
87
90
  authenticatedUser: accountEmail || undefined,
88
91
  projectAliasMap: rc.projects,
89
92
  allAccounts,
@@ -3,8 +3,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.compile = void 0;
4
4
  const zod_1 = require("zod");
5
5
  const tool_1 = require("../../tool");
6
- const load_1 = require("../../../dataconnect/load");
7
6
  const compile_1 = require("../../util/dataconnect/compile");
7
+ const load_1 = require("../../../dataconnect/load");
8
8
  exports.compile = (0, tool_1.tool)("dataconnect", {
9
9
  name: "build",
10
10
  description: "Use this to compile Firebase Data Connect schema, operations, and/or connectors and check for build errors.",
@@ -16,7 +16,11 @@ exports.compile = (0, tool_1.tool)("dataconnect", {
16
16
  service_id: zod_1.z
17
17
  .string()
18
18
  .optional()
19
- .describe("The Firebase Data Connect service ID to look for. If omitted, builds all services defined in `firebase.json`."),
19
+ .describe(`Service ID of the Data Connect service to compile. Used to disambiguate when there are multiple Data Connect services in firebase.json.`),
20
+ location_id: zod_1.z
21
+ .string()
22
+ .optional()
23
+ .describe(`Data Connect Service location ID to disambiguate among multiple Data Connect services.`),
20
24
  }),
21
25
  annotations: {
22
26
  title: "Compile Data Connect",
@@ -26,15 +30,17 @@ exports.compile = (0, tool_1.tool)("dataconnect", {
26
30
  requiresProject: false,
27
31
  requiresAuth: false,
28
32
  },
29
- }, async ({ service_id, error_filter }, { projectId, config }) => {
30
- const serviceInfo = await (0, load_1.pickService)(projectId, config, service_id || undefined);
31
- const errors = await (0, compile_1.compileErrors)(serviceInfo.sourceDirectory, error_filter);
32
- if (errors)
33
+ }, async ({ service_id, location_id, error_filter }, { projectId, config }) => {
34
+ const serviceInfos = await (0, load_1.pickServices)(projectId, config, service_id || undefined, location_id || undefined);
35
+ const errors = (await Promise.all(serviceInfos.map(async (serviceInfo) => {
36
+ return await (0, compile_1.compileErrors)(serviceInfo.sourceDirectory, error_filter);
37
+ }))).flat();
38
+ if (errors.length > 0)
33
39
  return {
34
40
  content: [
35
41
  {
36
42
  type: "text",
37
- text: `The following errors were encountered while compiling Data Connect from directory \`${serviceInfo.sourceDirectory}\`:\n\n${errors}`,
43
+ text: `The following errors were encountered while compiling Data Connect:\n\n${errors.join("\n")}`,
38
44
  },
39
45
  ],
40
46
  isError: true,
@@ -15,11 +15,14 @@ exports.execute = (0, tool_1.tool)("dataconnect", {
15
15
  You can use the \`dataconnect_generate_operation\` tool to generate a query.
16
16
  Example Data Connect schema and example queries can be found in files ending in \`.graphql\` or \`.gql\`.
17
17
  `),
18
- service_id: zod_1.z.string().optional()
19
- .describe(`Data Connect Service ID to dis-ambulate if there are multiple.
20
- It's only necessary if there are multiple dataconnect sources in \`firebase.json\`.
21
- You can find candidate service_id in \`dataconnect.yaml\`
22
- `),
18
+ service_id: zod_1.z
19
+ .string()
20
+ .optional()
21
+ .describe(`Service ID of the Data Connect service to compile. Used to disambiguate when there are multiple Data Connect services in firebase.json.`),
22
+ location_id: zod_1.z
23
+ .string()
24
+ .optional()
25
+ .describe(`Data Connect Service location ID to disambiguate among multiple Data Connect services.`),
23
26
  variables_json: zod_1.z
24
27
  .string()
25
28
  .optional()
@@ -42,8 +45,8 @@ You can find candidate service_id in \`dataconnect.yaml\`
42
45
  requiresProject: true,
43
46
  requiresAuth: true,
44
47
  },
45
- }, async ({ query, service_id, variables_json: unparsedVariables, use_emulator, auth_token_json: unparsedAuthToken, }, { projectId, config, host }) => {
46
- const serviceInfo = await (0, load_1.pickService)(projectId, config, service_id || undefined);
48
+ }, async ({ query, service_id, location_id, variables_json: unparsedVariables, use_emulator, auth_token_json: unparsedAuthToken, }, { projectId, config, host }) => {
49
+ const serviceInfo = await (0, load_1.pickOneService)(projectId, config, service_id || undefined, location_id || undefined);
47
50
  let apiClient;
48
51
  if (use_emulator) {
49
52
  apiClient = await (0, emulator_1.getDataConnectEmulatorClient)(host);
@@ -16,7 +16,11 @@ exports.generate_operation = (0, tool_1.tool)("dataconnect", {
16
16
  service_id: zod_1.z
17
17
  .string()
18
18
  .optional()
19
- .describe("Optional: Uses the service ID from the firebase.json file if nothing provided. The service ID of the deployed Firebase resource."),
19
+ .describe(`Service ID of the Data Connect service to compile. Used to disambiguate when there are multiple Data Connect services in firebase.json.`),
20
+ location_id: zod_1.z
21
+ .string()
22
+ .optional()
23
+ .describe(`Data Connect Service location ID to disambiguate among multiple Data Connect services.`),
20
24
  }),
21
25
  annotations: {
22
26
  title: "Generate Data Connect Operation",
@@ -27,8 +31,8 @@ exports.generate_operation = (0, tool_1.tool)("dataconnect", {
27
31
  requiresAuth: true,
28
32
  requiresGemini: true,
29
33
  },
30
- }, async ({ prompt, service_id }, { projectId, config }) => {
31
- const serviceInfo = await (0, load_1.pickService)(projectId, config, service_id || undefined);
34
+ }, async ({ prompt, service_id, location_id }, { projectId, config }) => {
35
+ const serviceInfo = await (0, load_1.pickOneService)(projectId, config, service_id || undefined, location_id || undefined);
32
36
  const schema = await (0, fdcExperience_1.generateOperation)(prompt, serviceInfo.serviceName, projectId);
33
37
  return (0, util_1.toContent)(schema);
34
38
  });
@@ -1,20 +1,59 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.markdownDocsOfTools = exports.availableTools = void 0;
4
- const index_1 = require("./auth/index");
5
- const index_2 = require("./dataconnect/index");
6
- const index_3 = require("./firestore/index");
4
+ const index_1 = require("./apphosting/index");
5
+ const index_2 = require("./apptesting/index");
6
+ const index_3 = require("./auth/index");
7
7
  const index_4 = require("./core/index");
8
- const index_5 = require("./storage/index");
9
- const index_6 = require("./messaging/index");
10
- const index_7 = require("./remoteconfig/index");
11
- const index_8 = require("./crashlytics/index");
12
- const index_9 = require("./apphosting/index");
13
- const index_10 = require("./apptesting/index");
14
- const index_11 = require("./realtime_database/index");
15
- const index_12 = require("./functions/index");
16
- async function availableTools(ctx, activeFeatures) {
17
- const allTools = getAllTools(activeFeatures);
8
+ const index_5 = require("./crashlytics/index");
9
+ const index_6 = require("./dataconnect/index");
10
+ const index_7 = require("./firestore/index");
11
+ const index_8 = require("./functions/index");
12
+ const index_9 = require("./messaging/index");
13
+ const index_10 = require("./realtime_database/index");
14
+ const index_11 = require("./remoteconfig/index");
15
+ const index_12 = require("./storage/index");
16
+ function addFeaturePrefix(feature, tools) {
17
+ return tools.map((tool) => (Object.assign(Object.assign({}, tool), { mcp: Object.assign(Object.assign({}, tool.mcp), { name: `${feature}_${tool.mcp.name}`, _meta: Object.assign(Object.assign({}, tool.mcp._meta), { feature }) }) })));
18
+ }
19
+ const tools = {
20
+ apphosting: addFeaturePrefix("apphosting", index_1.appHostingTools),
21
+ apptesting: addFeaturePrefix("apptesting", index_2.apptestingTools),
22
+ auth: addFeaturePrefix("auth", index_3.authTools),
23
+ core: addFeaturePrefix("firebase", index_4.coreTools),
24
+ crashlytics: addFeaturePrefix("crashlytics", index_5.crashlyticsTools),
25
+ database: addFeaturePrefix("realtimedatabase", index_10.realtimeDatabaseTools),
26
+ dataconnect: addFeaturePrefix("dataconnect", index_6.dataconnectTools),
27
+ firestore: addFeaturePrefix("firestore", index_7.firestoreTools),
28
+ functions: addFeaturePrefix("functions", index_8.functionsTools),
29
+ messaging: addFeaturePrefix("messaging", index_9.messagingTools),
30
+ remoteconfig: addFeaturePrefix("remoteconfig", index_11.remoteConfigTools),
31
+ storage: addFeaturePrefix("storage", index_12.storageTools),
32
+ };
33
+ const allToolsMap = new Map(Object.values(tools)
34
+ .flat()
35
+ .sort((a, b) => a.mcp.name.localeCompare(b.mcp.name))
36
+ .map((t) => [t.mcp.name, t]));
37
+ function getToolsByName(names) {
38
+ const selectedTools = new Set();
39
+ for (const toolName of names) {
40
+ const tool = allToolsMap.get(toolName);
41
+ if (tool) {
42
+ selectedTools.add(tool);
43
+ }
44
+ }
45
+ return Array.from(selectedTools);
46
+ }
47
+ function getToolsByFeature(serverFeatures) {
48
+ const features = new Set((serverFeatures === null || serverFeatures === void 0 ? void 0 : serverFeatures.length) ? serverFeatures : Object.keys(tools));
49
+ features.add("core");
50
+ return Array.from(features).flatMap((feature) => tools[feature] || []);
51
+ }
52
+ async function availableTools(ctx, activeFeatures, enabledTools) {
53
+ if (enabledTools === null || enabledTools === void 0 ? void 0 : enabledTools.length) {
54
+ return getToolsByName(enabledTools);
55
+ }
56
+ const allTools = getToolsByFeature(activeFeatures);
18
57
  const availabilities = await Promise.all(allTools.map((t) => {
19
58
  if (t.isAvailable) {
20
59
  return t.isAvailable(ctx);
@@ -24,39 +63,9 @@ async function availableTools(ctx, activeFeatures) {
24
63
  return allTools.filter((_, i) => availabilities[i]);
25
64
  }
26
65
  exports.availableTools = availableTools;
27
- function getAllTools(activeFeatures) {
28
- const toolDefs = [];
29
- if (!(activeFeatures === null || activeFeatures === void 0 ? void 0 : activeFeatures.length)) {
30
- activeFeatures = Object.keys(tools);
31
- }
32
- if (!activeFeatures.includes("core")) {
33
- activeFeatures.unshift("core");
34
- }
35
- for (const key of activeFeatures) {
36
- toolDefs.push(...tools[key]);
37
- }
38
- return toolDefs;
39
- }
40
- const tools = {
41
- core: addFeaturePrefix("firebase", index_4.coreTools),
42
- firestore: addFeaturePrefix("firestore", index_3.firestoreTools),
43
- auth: addFeaturePrefix("auth", index_1.authTools),
44
- dataconnect: addFeaturePrefix("dataconnect", index_2.dataconnectTools),
45
- storage: addFeaturePrefix("storage", index_5.storageTools),
46
- messaging: addFeaturePrefix("messaging", index_6.messagingTools),
47
- functions: addFeaturePrefix("functions", index_12.functionsTools),
48
- remoteconfig: addFeaturePrefix("remoteconfig", index_7.remoteConfigTools),
49
- crashlytics: addFeaturePrefix("crashlytics", index_8.crashlyticsTools),
50
- apptesting: addFeaturePrefix("apptesting", index_10.apptestingTools),
51
- apphosting: addFeaturePrefix("apphosting", index_9.appHostingTools),
52
- database: addFeaturePrefix("realtimedatabase", index_11.realtimeDatabaseTools),
53
- };
54
- function addFeaturePrefix(feature, tools) {
55
- return tools.map((tool) => (Object.assign(Object.assign({}, tool), { mcp: Object.assign(Object.assign({}, tool.mcp), { name: `${feature}_${tool.mcp.name}`, _meta: Object.assign(Object.assign({}, tool.mcp._meta), { feature }) }) })));
56
- }
57
66
  function markdownDocsOfTools() {
58
67
  var _a, _b, _c;
59
- const allTools = getAllTools([]);
68
+ const allTools = getToolsByFeature([]);
60
69
  let doc = `
61
70
  | Tool Name | Feature Group | Description |
62
71
  | --------- | ------------- | ----------- |`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "firebase-tools",
3
- "version": "14.27.0",
3
+ "version": "15.1.0",
4
4
  "description": "Command-Line Interface for Firebase",
5
5
  "main": "./lib/index.js",
6
6
  "mcpName": "io.github.firebase/firebase-mcp",
@@ -125,7 +125,6 @@
125
125
  "stream-chain": "^2.2.4",
126
126
  "stream-json": "^1.7.3",
127
127
  "superstatic": "^10.0.0",
128
- "tar": "^6.1.11",
129
128
  "tcp-port-used": "^1.0.2",
130
129
  "tmp": "^0.2.3",
131
130
  "triple-beam": "^1.3.0",
@@ -1,23 +0,0 @@
1
- "use strict";
2
- var extractTriggers = function (mod, triggers, prefix) {
3
- prefix = prefix || "";
4
- for (var funcName of Object.keys(mod)) {
5
- var child = mod[funcName];
6
- if (typeof child === "function" && child.__trigger && typeof child.__trigger === "object") {
7
- if (funcName.indexOf("-") >= 0) {
8
- throw new Error('Function name "' + funcName + '" is invalid. Function names cannot contain dashes.');
9
- }
10
- var trigger = {};
11
- for (var key of Object.keys(child.__trigger)) {
12
- trigger[key] = child.__trigger[key];
13
- }
14
- trigger.name = prefix + funcName;
15
- trigger.entryPoint = trigger.name.replace(/-/g, ".");
16
- triggers.push(trigger);
17
- }
18
- else if (typeof child === "object" && child !== null) {
19
- extractTriggers(child, triggers, prefix + funcName + "-");
20
- }
21
- }
22
- };
23
- module.exports = extractTriggers;