firebase-tools 14.22.0 → 14.24.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 (35) hide show
  1. package/README.md +13 -5
  2. package/lib/apiv2.js +12 -2
  3. package/lib/appUtils.js +32 -13
  4. package/lib/appdistribution/client.js +62 -16
  5. package/lib/appdistribution/types.js +1 -12
  6. package/lib/appdistribution/yaml_helper.js +69 -0
  7. package/lib/commands/appdistribution-groups-list.js +3 -5
  8. package/lib/commands/appdistribution-testcases-export.js +32 -0
  9. package/lib/commands/appdistribution-testcases-import.js +34 -0
  10. package/lib/commands/appdistribution-testers-list.js +3 -5
  11. package/lib/commands/dataconnect-sdk-generate.js +3 -2
  12. package/lib/commands/index.js +8 -5
  13. package/lib/commands/init.js +5 -7
  14. package/lib/deploy/functions/services/dataconnect.js +14 -0
  15. package/lib/deploy/functions/services/index.js +11 -0
  16. package/lib/emulator/auth/operations.js +7 -1
  17. package/lib/emulator/downloadableEmulatorInfo.json +33 -25
  18. package/lib/emulator/downloadableEmulators.js +59 -47
  19. package/lib/emulator/functionsEmulatorRuntime.js +8 -0
  20. package/lib/emulator/taskQueue.js +5 -0
  21. package/lib/experiments.js +0 -6
  22. package/lib/firestore/api.js +22 -4
  23. package/lib/functions/events/v2.js +2 -1
  24. package/lib/init/features/dataconnect/sdk.js +18 -0
  25. package/lib/init/features/hosting/github.js +6 -6
  26. package/lib/init/features/hosting/index.js +37 -37
  27. package/lib/management/provisioning/errorHandler.js +54 -0
  28. package/lib/management/provisioning/provision.js +2 -5
  29. package/lib/mcp/tools/crashlytics/events.js +92 -9
  30. package/lib/mcp/tools/functions/index.js +2 -1
  31. package/lib/mcp/tools/functions/list_functions.js +48 -0
  32. package/lib/utils.js +4 -1
  33. package/package.json +2 -2
  34. package/schema/connector-yaml.json +30 -0
  35. package/schema/firebase-config.json +0 -1
@@ -3,16 +3,93 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.batch_get_events = exports.list_events = void 0;
4
4
  const zod_1 = require("zod");
5
5
  const tool_1 = require("../../tool");
6
+ const js_yaml_1 = require("js-yaml");
6
7
  const events_1 = require("../../../crashlytics/events");
7
8
  const types_1 = require("../../../crashlytics/types");
8
9
  const filters_1 = require("../../../crashlytics/filters");
9
10
  const util_1 = require("../../util");
10
- function pruneThreads(sample) {
11
- var _a, _b, _c;
12
- if (((_a = sample.issue) === null || _a === void 0 ? void 0 : _a.errorType) === types_1.ErrorType.FATAL || ((_b = sample.issue) === null || _b === void 0 ? void 0 : _b.errorType) === types_1.ErrorType.ANR) {
13
- sample.threads = (_c = sample.threads) === null || _c === void 0 ? void 0 : _c.filter((t) => t.crashed || t.blamed);
11
+ const DUMP_OPTIONS = { lineWidth: 200 };
12
+ function formatFrames(origFrames, maxFrames = 20) {
13
+ const frames = origFrames || [];
14
+ const shouldTruncate = frames.length > maxFrames;
15
+ const framesToFormat = shouldTruncate ? frames.slice(0, maxFrames - 1) : frames;
16
+ const formatted = framesToFormat.map((frame) => {
17
+ let line = `at`;
18
+ if (frame.symbol) {
19
+ line += ` ${frame.symbol}`;
20
+ }
21
+ if (frame.file) {
22
+ line += ` (${frame.file}`;
23
+ if (frame.line) {
24
+ line += `:${frame.line}`;
25
+ }
26
+ line += ")";
27
+ }
28
+ return line;
29
+ });
30
+ if (shouldTruncate) {
31
+ formatted.push("... frames omitted ...");
14
32
  }
15
- return sample;
33
+ return formatted;
34
+ }
35
+ function toText(event) {
36
+ var _a, _b;
37
+ const result = {};
38
+ for (const [key, value] of Object.entries(event)) {
39
+ if (key === "logs") {
40
+ const logs = value || [];
41
+ const slicedLogs = logs.length > 100 ? logs.slice(logs.length - 100) : logs;
42
+ const logLines = slicedLogs.map((log) => `[${log.logTime}] ${log.message}`);
43
+ result["logs"] = logLines.join("\n");
44
+ }
45
+ else if (key === "breadcrumbs") {
46
+ const breadcrumbs = value || [];
47
+ const slicedBreadcrumbs = breadcrumbs.length > 10 ? breadcrumbs.slice(-10) : breadcrumbs;
48
+ const breadcrumbLines = slicedBreadcrumbs.map((b) => {
49
+ const paramString = Object.entries(b.params)
50
+ .map(([k, v]) => `${k}: ${v}`)
51
+ .join(", ");
52
+ const params = paramString ? ` { ${paramString} }` : "";
53
+ return `[${b.eventTime}] ${b.title}${params}`;
54
+ });
55
+ result["breadcrumbs"] = breadcrumbLines.join("\n");
56
+ }
57
+ else if (key === "threads") {
58
+ let threads = value || [];
59
+ if (((_a = event.issue) === null || _a === void 0 ? void 0 : _a.errorType) === types_1.ErrorType.FATAL || ((_b = event.issue) === null || _b === void 0 ? void 0 : _b.errorType) === types_1.ErrorType.ANR) {
60
+ threads = threads.filter((t) => t.crashed || t.blamed);
61
+ }
62
+ const threadStrings = threads.map((thread) => {
63
+ const header = `Thread: ${thread.name || thread.threadId || ""}${thread.crashed ? " (crashed)" : ""}`;
64
+ const frameStrings = formatFrames(thread.frames || []);
65
+ return [header, ...frameStrings].join("\n");
66
+ });
67
+ result["threads"] = threadStrings.join("\n\n");
68
+ }
69
+ else if (key === "exceptions") {
70
+ const exceptions = value || [];
71
+ const exceptionStrings = exceptions.map((exception) => {
72
+ const header = exception.nested ? "Caused by: " : "";
73
+ const exceptionHeader = `${header}${exception.type || ""}: ${exception.exceptionMessage || ""}`;
74
+ const frameStrings = formatFrames(exception.frames || []);
75
+ return [exceptionHeader, ...frameStrings].join("\n");
76
+ });
77
+ result["exceptions"] = exceptionStrings.join("\n\n");
78
+ }
79
+ else if (key === "errors") {
80
+ const errors = value || [];
81
+ const errorStrings = errors.map((error) => {
82
+ const header = `Error: ${error.title || "error"}`;
83
+ const frameStrings = formatFrames(error.frames || []);
84
+ return [header, ...frameStrings].join("\n");
85
+ });
86
+ result["errors"] = errorStrings.join("\n\n");
87
+ }
88
+ else {
89
+ result[key] = (0, js_yaml_1.dump)(value, DUMP_OPTIONS);
90
+ }
91
+ }
92
+ return result;
16
93
  }
17
94
  exports.list_events = (0, tool_1.tool)("crashlytics", {
18
95
  name: "list_events",
@@ -32,13 +109,16 @@ exports.list_events = (0, tool_1.tool)("crashlytics", {
32
109
  requiresAuth: true,
33
110
  },
34
111
  }, async ({ appId, filter, pageSize }) => {
112
+ var _a;
35
113
  if (!appId)
36
114
  return (0, util_1.mcpError)(`Must specify 'appId' parameter.`);
37
115
  if (!filter || (!filter.issueId && !filter.issueVariantId))
38
116
  return (0, util_1.mcpError)(`Must specify 'filter.issueId' or 'filter.issueVariantId' parameters.`);
39
117
  const response = await (0, events_1.listEvents)(appId, filter, pageSize);
40
- response.events = response.events ? response.events.map((e) => pruneThreads(e)) : [];
41
- return (0, util_1.toContent)(response);
118
+ const eventsContent = ((_a = response.events) === null || _a === void 0 ? void 0 : _a.map((e) => toText(e))) || [];
119
+ return {
120
+ content: [{ type: "text", text: (0, js_yaml_1.dump)(eventsContent, DUMP_OPTIONS) }],
121
+ };
42
122
  });
43
123
  exports.batch_get_events = (0, tool_1.tool)("crashlytics", {
44
124
  name: "batch_get_events",
@@ -59,11 +139,14 @@ exports.batch_get_events = (0, tool_1.tool)("crashlytics", {
59
139
  requiresAuth: true,
60
140
  },
61
141
  }, async ({ appId, names }) => {
142
+ var _a;
62
143
  if (!appId)
63
144
  return (0, util_1.mcpError)(`Must specify 'appId' parameter.`);
64
145
  if (!names || names.length === 0)
65
146
  return (0, util_1.mcpError)(`Must provide event resource names in name parameter.`);
66
147
  const response = await (0, events_1.batchGetEvents)(appId, names);
67
- response.events = response.events ? response.events.map((e) => pruneThreads(e)) : [];
68
- return (0, util_1.toContent)(response);
148
+ const eventsContent = ((_a = response.events) === null || _a === void 0 ? void 0 : _a.map((e) => toText(e))) || [];
149
+ return {
150
+ content: [{ type: "text", text: (0, js_yaml_1.dump)(eventsContent, DUMP_OPTIONS) }],
151
+ };
69
152
  });
@@ -2,4 +2,5 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.functionsTools = void 0;
4
4
  const get_logs_1 = require("./get_logs");
5
- exports.functionsTools = [get_logs_1.get_logs];
5
+ const list_functions_1 = require("./list_functions");
6
+ exports.functionsTools = [get_logs_1.get_logs, list_functions_1.list_functions];
@@ -0,0 +1,48 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.list_functions = void 0;
4
+ const zod_1 = require("zod");
5
+ const tool_1 = require("../../tool");
6
+ const util_1 = require("../../util");
7
+ const backend = require("../../../deploy/functions/backend");
8
+ const error_1 = require("../../../error");
9
+ exports.list_functions = (0, tool_1.tool)("functions", {
10
+ name: "list_functions",
11
+ description: "List all deployed functions in your Firebase project.",
12
+ inputSchema: zod_1.z.object({}),
13
+ annotations: {
14
+ title: "List Deployed Functions",
15
+ readOnlyHint: true,
16
+ openWorldHint: true,
17
+ },
18
+ _meta: {
19
+ requiresAuth: true,
20
+ requiresProject: true,
21
+ },
22
+ }, async (_, { projectId }) => {
23
+ const context = {
24
+ projectId,
25
+ };
26
+ try {
27
+ const existing = await backend.existingBackend(context);
28
+ const endpointsList = backend.allEndpoints(existing).sort(backend.compareFunctions);
29
+ const formattedList = endpointsList.map((endpoint) => ({
30
+ function: endpoint.id,
31
+ version: endpoint.platform === "gcfv2" ? "v2" : "v1",
32
+ trigger: backend.endpointTriggerType(endpoint),
33
+ location: endpoint.region,
34
+ memory: endpoint.availableMemoryMb || "---",
35
+ runtime: endpoint.runtime,
36
+ }));
37
+ if (!formattedList.length) {
38
+ return (0, util_1.toContent)([], {
39
+ contentPrefix: "No functions found in this project.\n\n",
40
+ });
41
+ }
42
+ return (0, util_1.toContent)(formattedList);
43
+ }
44
+ catch (err) {
45
+ const errMsg = (0, error_1.getErrMsg)((err === null || err === void 0 ? void 0 : err.original) || err, "Failed to list functions.");
46
+ return (0, util_1.mcpError)(errMsg);
47
+ }
48
+ });
package/lib/utils.js CHANGED
@@ -357,7 +357,10 @@ function datetimeString(d) {
357
357
  }
358
358
  exports.datetimeString = datetimeString;
359
359
  function isCloudEnvironment() {
360
- return !!process.env.CODESPACES || !!process.env.GOOGLE_CLOUD_WORKSTATIONS;
360
+ return (!!process.env.CODESPACES ||
361
+ !!process.env.GOOGLE_CLOUD_WORKSTATIONS ||
362
+ !!process.env.CLOUD_SHELL ||
363
+ !!process.env.GOOGLE_CLOUD_SHELL);
361
364
  }
362
365
  exports.isCloudEnvironment = isCloudEnvironment;
363
366
  function isRunningInWSL() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "firebase-tools",
3
- "version": "14.22.0",
3
+ "version": "14.24.0",
4
4
  "description": "Command-Line Interface for Firebase",
5
5
  "main": "./lib/index.js",
6
6
  "bin": {
@@ -66,7 +66,7 @@
66
66
  "@electric-sql/pglite": "^0.3.3",
67
67
  "@electric-sql/pglite-tools": "^0.2.8",
68
68
  "@google-cloud/cloud-sql-connector": "^1.3.3",
69
- "@google-cloud/pubsub": "^4.5.0",
69
+ "@google-cloud/pubsub": "^5.2.0",
70
70
  "@inquirer/prompts": "^7.4.0",
71
71
  "@modelcontextprotocol/sdk": "^1.10.2",
72
72
  "abort-controller": "^3.0.0",
@@ -2,6 +2,24 @@
2
2
  "$schema": "http://json-schema.org/draft-07/schema#",
3
3
  "additionalProperties": false,
4
4
  "definitions": {
5
+ "adminNodeSdk": {
6
+ "additionalProperties": true,
7
+ "type": "object",
8
+ "properties": {
9
+ "outputDir": {
10
+ "type": "string",
11
+ "description": "Path to the directory where generated files should be written to."
12
+ },
13
+ "package": {
14
+ "type": "string",
15
+ "description": "The package name to use for the generated code."
16
+ },
17
+ "packageJSONDir": {
18
+ "type": "string",
19
+ "description": "The directory containing the package.json to install the generated package in."
20
+ }
21
+ }
22
+ },
5
23
  "javascriptSdk": {
6
24
  "additionalProperties": true,
7
25
  "type": "object",
@@ -90,6 +108,18 @@
90
108
  ],
91
109
  "description": "Configuration for a generated Javascript SDK"
92
110
  },
111
+ "adminNodeSdk": {
112
+ "oneOf": [
113
+ { "$ref": "#/definitions/adminNodeSdk" },
114
+ {
115
+ "type": "array",
116
+ "items": {
117
+ "$ref": "#/definitions/adminNodeSdk"
118
+ }
119
+ }
120
+ ],
121
+ "description": "Configuration for a generated Admin Node SDK"
122
+ },
93
123
  "dartSdk": {
94
124
  "oneOf": [
95
125
  { "$ref": "#/definitions/dartSdk" },
@@ -1090,7 +1090,6 @@
1090
1090
  },
1091
1091
  "properties": {
1092
1092
  "$schema": {
1093
- "format": "uri",
1094
1093
  "type": "string"
1095
1094
  },
1096
1095
  "apphosting": {