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.
- package/README.md +13 -5
- package/lib/apiv2.js +12 -2
- package/lib/appUtils.js +32 -13
- package/lib/appdistribution/client.js +62 -16
- package/lib/appdistribution/types.js +1 -12
- package/lib/appdistribution/yaml_helper.js +69 -0
- package/lib/commands/appdistribution-groups-list.js +3 -5
- package/lib/commands/appdistribution-testcases-export.js +32 -0
- package/lib/commands/appdistribution-testcases-import.js +34 -0
- package/lib/commands/appdistribution-testers-list.js +3 -5
- package/lib/commands/dataconnect-sdk-generate.js +3 -2
- package/lib/commands/index.js +8 -5
- package/lib/commands/init.js +5 -7
- package/lib/deploy/functions/services/dataconnect.js +14 -0
- package/lib/deploy/functions/services/index.js +11 -0
- package/lib/emulator/auth/operations.js +7 -1
- package/lib/emulator/downloadableEmulatorInfo.json +33 -25
- package/lib/emulator/downloadableEmulators.js +59 -47
- package/lib/emulator/functionsEmulatorRuntime.js +8 -0
- package/lib/emulator/taskQueue.js +5 -0
- package/lib/experiments.js +0 -6
- package/lib/firestore/api.js +22 -4
- package/lib/functions/events/v2.js +2 -1
- package/lib/init/features/dataconnect/sdk.js +18 -0
- package/lib/init/features/hosting/github.js +6 -6
- package/lib/init/features/hosting/index.js +37 -37
- package/lib/management/provisioning/errorHandler.js +54 -0
- package/lib/management/provisioning/provision.js +2 -5
- package/lib/mcp/tools/crashlytics/events.js +92 -9
- package/lib/mcp/tools/functions/index.js +2 -1
- package/lib/mcp/tools/functions/list_functions.js +48 -0
- package/lib/utils.js +4 -1
- package/package.json +2 -2
- package/schema/connector-yaml.json +30 -0
- 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
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
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
|
|
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
|
-
|
|
41
|
-
return
|
|
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
|
-
|
|
68
|
-
return
|
|
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
|
-
|
|
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 ||
|
|
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.
|
|
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": "^
|
|
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" },
|