firebase-tools 14.15.0 → 14.15.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.
Files changed (41) hide show
  1. package/lib/command.js +19 -5
  2. package/lib/commands/dataconnect-sdk-generate.js +28 -24
  3. package/lib/commands/init.js +8 -0
  4. package/lib/deploy/functions/build.js +2 -13
  5. package/lib/deploy/functions/prepare.js +2 -1
  6. package/lib/deploy/functions/runtimes/discovery/index.js +1 -1
  7. package/lib/emulator/auth/operations.js +10 -1
  8. package/lib/emulator/dataconnectEmulator.js +27 -24
  9. package/lib/emulator/functionsEmulator.js +1 -1
  10. package/lib/emulator/hub.js +2 -4
  11. package/lib/experiments.js +5 -0
  12. package/lib/functions/env.js +12 -1
  13. package/lib/init/features/dataconnect/index.js +10 -25
  14. package/lib/init/features/dataconnect/sdk.js +0 -1
  15. package/lib/init/features/index.js +1 -2
  16. package/lib/init/index.js +0 -1
  17. package/lib/mcp/index.js +1 -1
  18. package/lib/mcp/prompts/core/deploy.js +1 -1
  19. package/lib/mcp/prompts/dataconnect/index.js +9 -0
  20. package/lib/mcp/prompts/dataconnect/schema.js +68 -0
  21. package/lib/mcp/prompts/index.js +2 -1
  22. package/lib/mcp/tools/core/init.js +11 -2
  23. package/lib/mcp/tools/dataconnect/compile.js +43 -0
  24. package/lib/mcp/tools/dataconnect/execute.js +71 -0
  25. package/lib/mcp/tools/dataconnect/index.js +6 -14
  26. package/lib/mcp/tools/dataconnect/info.js +120 -0
  27. package/lib/mcp/tools/firestore/list_collections.js +0 -3
  28. package/lib/mcp/tools/index.js +3 -0
  29. package/lib/mcp/util/dataconnect/compile.js +18 -0
  30. package/lib/mcp/util/dataconnect/content.js +655 -0
  31. package/lib/track.js +16 -0
  32. package/package.json +1 -1
  33. package/lib/mcp/tools/dataconnect/execute_graphql.js +0 -48
  34. package/lib/mcp/tools/dataconnect/execute_graphql_read.js +0 -48
  35. package/lib/mcp/tools/dataconnect/execute_mutation.js +0 -62
  36. package/lib/mcp/tools/dataconnect/execute_query.js +0 -62
  37. package/lib/mcp/tools/dataconnect/get_connector.js +0 -31
  38. package/lib/mcp/tools/dataconnect/get_schema.js +0 -31
  39. package/lib/mcp/tools/dataconnect/list_services.js +0 -23
  40. /package/lib/mcp/{tools → util}/dataconnect/converter.js +0 -0
  41. /package/lib/mcp/{tools → util}/dataconnect/emulator.js +0 -0
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.compile = void 0;
4
+ const zod_1 = require("zod");
5
+ const tool_1 = require("../../tool");
6
+ const load_1 = require("../../../dataconnect/load");
7
+ const compile_1 = require("../../util/dataconnect/compile");
8
+ exports.compile = (0, tool_1.tool)({
9
+ name: "build",
10
+ description: "Use this to compile Firebase Data Connect schema, operations, and/or connectors and check for build errors.",
11
+ inputSchema: zod_1.z.object({
12
+ error_filter: zod_1.z
13
+ .enum(["all", "schema", "operations"])
14
+ .describe("filter errors to a specific type only. defaults to `all` if omitted.")
15
+ .optional(),
16
+ service_id: zod_1.z
17
+ .string()
18
+ .optional()
19
+ .describe("The Firebase Data Connect service ID to look for. If omitted, builds all services defined in `firebase.json`."),
20
+ }),
21
+ annotations: {
22
+ title: "Compile Data Connect",
23
+ readOnlyHint: true,
24
+ },
25
+ _meta: {
26
+ requiresProject: false,
27
+ requiresAuth: false,
28
+ },
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
+ return {
34
+ content: [
35
+ {
36
+ type: "text",
37
+ text: `The following errors were encountered while compiling Data Connect from directory \`${serviceInfo.sourceDirectory}\`:\n\n${errors}`,
38
+ },
39
+ ],
40
+ isError: true,
41
+ };
42
+ return { content: [{ type: "text", text: "Compiled successfully." }] };
43
+ });
@@ -0,0 +1,71 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.execute = void 0;
4
+ const zod_1 = require("zod");
5
+ const tool_1 = require("../../tool");
6
+ const dataplane = require("../../../dataconnect/dataplaneClient");
7
+ const load_1 = require("../../../dataconnect/load");
8
+ const converter_1 = require("../../util/dataconnect/converter");
9
+ const emulator_1 = require("../../util/dataconnect/emulator");
10
+ exports.execute = (0, tool_1.tool)({
11
+ name: "execute",
12
+ description: "Executes a GraphQL operation against a Data Connect service or its emulator.",
13
+ inputSchema: zod_1.z.object({
14
+ query: zod_1.z.string().describe(`A Firebase Data Connect GraphQL query or mutation to execute.
15
+ You can use the \`dataconnect_generate_operation\` tool to generate a query.
16
+ Example Data Connect schema and example queries can be found in files ending in \`.graphql\` or \`.gql\`.
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
+ `),
23
+ variables_json: zod_1.z
24
+ .string()
25
+ .optional()
26
+ .describe("GraphQL variables to pass into the query. MUST be a valid stringified JSON object."),
27
+ auth_token_json: zod_1.z
28
+ .string()
29
+ .optional()
30
+ .describe("Firebase Auth Token JWT to use in this query. MUST be a valid stringified JSON object." +
31
+ 'Importantly, when executing queries with `@auth(level: USER)` or `auth.uid`, a valid Firebase Auth Token JWT with "sub" field is required. ' +
32
+ '"auth.uid" expression in the query evaluates to the value of "sub" field in Firebase Auth token.'),
33
+ use_emulator: zod_1.z
34
+ .boolean()
35
+ .default(false)
36
+ .describe("If true, target the DataConnect emulator. Run `firebase emulators:start` to start it"),
37
+ }),
38
+ annotations: {
39
+ title: "Execute Firebase Data Connect Query",
40
+ },
41
+ _meta: {
42
+ requiresProject: true,
43
+ requiresAuth: true,
44
+ },
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);
47
+ let apiClient;
48
+ if (use_emulator) {
49
+ apiClient = await (0, emulator_1.getDataConnectEmulatorClient)(host);
50
+ }
51
+ else {
52
+ apiClient = dataplane.dataconnectDataplaneClient();
53
+ }
54
+ let executeGraphQL = dataplane.executeGraphQL;
55
+ if (query.startsWith("query")) {
56
+ executeGraphQL = dataplane.executeGraphQLRead;
57
+ }
58
+ const response = await executeGraphQL(apiClient, serviceInfo.serviceName, {
59
+ name: "",
60
+ query,
61
+ variables: (0, converter_1.parseVariables)(unparsedVariables),
62
+ extensions: {
63
+ impersonate: unparsedAuthToken
64
+ ? {
65
+ authClaims: (0, converter_1.parseVariables)(unparsedAuthToken),
66
+ }
67
+ : undefined,
68
+ },
69
+ });
70
+ return (0, converter_1.graphqlResponseToToolResponse)(response.body);
71
+ });
@@ -3,21 +3,13 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.dataconnectTools = void 0;
4
4
  const generate_operation_1 = require("./generate_operation");
5
5
  const generate_schema_1 = require("./generate_schema");
6
- const list_services_1 = require("./list_services");
7
- const get_schema_1 = require("./get_schema");
8
- const get_connector_1 = require("./get_connector");
9
- const execute_graphql_1 = require("./execute_graphql");
10
- const execute_graphql_read_1 = require("./execute_graphql_read");
11
- const execute_query_1 = require("./execute_query");
12
- const execute_mutation_1 = require("./execute_mutation");
6
+ const info_1 = require("./info");
7
+ const compile_1 = require("./compile");
8
+ const execute_1 = require("./execute");
13
9
  exports.dataconnectTools = [
14
- list_services_1.list_services,
10
+ compile_1.compile,
15
11
  generate_schema_1.generate_schema,
16
12
  generate_operation_1.generate_operation,
17
- get_schema_1.get_schema,
18
- get_connector_1.get_connectors,
19
- execute_graphql_1.execute_graphql,
20
- execute_graphql_read_1.execute_graphql_read,
21
- execute_mutation_1.execute_mutation,
22
- execute_query_1.execute_query,
13
+ info_1.info,
14
+ execute_1.execute,
23
15
  ];
@@ -0,0 +1,120 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.info = void 0;
4
+ const zod_1 = require("zod");
5
+ const path = require("path");
6
+ const tool_1 = require("../../tool");
7
+ const util_1 = require("../../util");
8
+ const client = require("../../../dataconnect/client");
9
+ const load_1 = require("../../../dataconnect/load");
10
+ const js_yaml_1 = require("js-yaml");
11
+ const logger_1 = require("../../../logger");
12
+ exports.info = (0, tool_1.tool)({
13
+ name: "info",
14
+ description: "Get information about the Firebase Data Connect local and deployed resources.",
15
+ inputSchema: zod_1.z.object({}),
16
+ annotations: {
17
+ title: "Get information about Firebase Data Connect",
18
+ readOnlyHint: true,
19
+ },
20
+ _meta: {
21
+ requiresProject: false,
22
+ requiresAuth: false,
23
+ },
24
+ }, async (_, { projectId, config }) => {
25
+ const localServiceInfos = await (0, load_1.loadAll)(projectId, config);
26
+ const serviceInfos = new Map();
27
+ for (const l of localServiceInfos) {
28
+ serviceInfos.set(`locations/${l.dataConnectYaml.location}/services/${l.dataConnectYaml.serviceId}`, { local: l });
29
+ }
30
+ if (projectId) {
31
+ try {
32
+ const [services, schemas, connectors] = await Promise.all([
33
+ client.listAllServices(projectId),
34
+ client.listSchemas(`projects/${projectId}/locations/-/services/-`),
35
+ client.listConnectors(`projects/${projectId}/locations/-/services/-`),
36
+ ]);
37
+ console.log(services, schemas, connectors);
38
+ for (const s of services) {
39
+ const k = s.name.split("/").slice(2, 6).join("/");
40
+ const st = serviceInfos.get(k) || {};
41
+ st.deployed = st.deployed || {};
42
+ st.deployed.service = s;
43
+ serviceInfos.set(k, st);
44
+ }
45
+ for (const s of schemas) {
46
+ const k = s.name.split("/").slice(2, 6).join("/");
47
+ const st = serviceInfos.get(k) || {};
48
+ st.deployed = st.deployed || {};
49
+ st.deployed.schemas = st.deployed.schemas || [];
50
+ st.deployed.schemas.push(s);
51
+ serviceInfos.set(k, st);
52
+ }
53
+ for (const s of connectors) {
54
+ const k = s.name.split("/").slice(2, 6).join("/");
55
+ const st = serviceInfos.get(k) || {};
56
+ st.deployed = st.deployed || {};
57
+ st.deployed.connectors = st.deployed.connectors || [];
58
+ st.deployed.connectors.push(s);
59
+ serviceInfos.set(k, st);
60
+ }
61
+ }
62
+ catch (e) {
63
+ logger_1.logger.debug("cannot fetch dataconnect resources in the backend", e);
64
+ }
65
+ }
66
+ const localServices = Array.from(serviceInfos.values()).filter((s) => s.local);
67
+ const remoteOnlyServices = Array.from(serviceInfos.values()).filter((s) => !s.local);
68
+ const output = [];
69
+ function includeDeployedServiceInfo(deployed) {
70
+ var _a, _b;
71
+ if ((_a = deployed.schemas) === null || _a === void 0 ? void 0 : _a.length) {
72
+ output.push(`### Schemas`);
73
+ for (const s of deployed.schemas) {
74
+ clearCCFEFields(s);
75
+ output.push((0, js_yaml_1.dump)(s));
76
+ }
77
+ }
78
+ if ((_b = deployed.connectors) === null || _b === void 0 ? void 0 : _b.length) {
79
+ output.push(`### Connectors`);
80
+ for (const c of deployed.connectors) {
81
+ clearCCFEFields(c);
82
+ output.push((0, js_yaml_1.dump)(c));
83
+ }
84
+ }
85
+ }
86
+ if (localServices.length) {
87
+ output.push(`# Local Data Connect Sources`);
88
+ for (const s of localServices) {
89
+ const local = s.local;
90
+ output.push((0, js_yaml_1.dump)(local.dataConnectYaml));
91
+ const schemaDir = path.join(local.sourceDirectory, local.dataConnectYaml.schema.source);
92
+ output.push(`You can find all of schema sources under ${schemaDir}/`);
93
+ if (s.deployed) {
94
+ output.push(`It's already deployed in the backend:\n`);
95
+ includeDeployedServiceInfo(s.deployed);
96
+ }
97
+ }
98
+ }
99
+ if (remoteOnlyServices.length) {
100
+ output.push(`# Data Connect Services in project ${projectId}`);
101
+ for (const s of remoteOnlyServices) {
102
+ if (s.deployed) {
103
+ includeDeployedServiceInfo(s.deployed);
104
+ }
105
+ }
106
+ }
107
+ output.push(`\n# What's next?`);
108
+ if (!localServices.length) {
109
+ output.push(`- There is no local Data Connect service in the local workspace. Consider use the \`firebase_init\` MCP tool to setup one.`);
110
+ }
111
+ output.push(`- You can use the \`dataconnect_compile\` tool to compile all local Data Connect schemas and query sources.`);
112
+ output.push(`- You run \`firebase deploy\` in command line to deploy the Data Connect schemas, connector and perform SQL migrations.`);
113
+ return (0, util_1.toContent)(output.join("\n"));
114
+ });
115
+ function clearCCFEFields(r) {
116
+ const fieldsToClear = ["updateTime", "uid", "etag"];
117
+ for (const k of fieldsToClear) {
118
+ delete r[k];
119
+ }
120
+ }
@@ -5,7 +5,6 @@ const zod_1 = require("zod");
5
5
  const tool_1 = require("../../tool");
6
6
  const util_1 = require("../../util");
7
7
  const firestore_1 = require("../../../gcp/firestore");
8
- const errors_1 = require("../../errors");
9
8
  const types_1 = require("../../../emulator/types");
10
9
  exports.list_collections = (0, tool_1.tool)({
11
10
  name: "list_collections",
@@ -30,7 +29,5 @@ exports.list_collections = (0, tool_1.tool)({
30
29
  if (use_emulator) {
31
30
  emulatorUrl = await host.getEmulatorUrl(types_1.Emulators.FIRESTORE);
32
31
  }
33
- if (!projectId)
34
- return errors_1.NO_PROJECT_ERROR;
35
32
  return (0, util_1.toContent)(await (0, firestore_1.listCollectionIds)(projectId, database, emulatorUrl));
36
33
  });
@@ -16,6 +16,9 @@ function availableTools(activeFeatures) {
16
16
  if (!(activeFeatures === null || activeFeatures === void 0 ? void 0 : activeFeatures.length)) {
17
17
  activeFeatures = Object.keys(tools);
18
18
  }
19
+ if (!activeFeatures.includes("core")) {
20
+ activeFeatures.unshift("core");
21
+ }
19
22
  for (const key of activeFeatures) {
20
23
  toolDefs.push(...tools[key]);
21
24
  }
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.compileErrors = void 0;
4
+ const graphqlError_1 = require("../../../dataconnect/graphqlError");
5
+ const dataconnectEmulator_1 = require("../../../emulator/dataconnectEmulator");
6
+ async function compileErrors(configDir, errorFilter) {
7
+ const errors = (await dataconnectEmulator_1.DataConnectEmulator.build({ configDir })).errors;
8
+ return ((errors === null || errors === void 0 ? void 0 : errors.filter((e) => {
9
+ var _a;
10
+ const isOperationError = ["query", "mutation"].includes((_a = e.path) === null || _a === void 0 ? void 0 : _a[0]);
11
+ if (errorFilter === "operations")
12
+ return isOperationError;
13
+ if (errorFilter === "schema")
14
+ return !isOperationError;
15
+ return true;
16
+ }).map(graphqlError_1.prettify).join("\n")) || "");
17
+ }
18
+ exports.compileErrors = compileErrors;