firebase-tools 14.15.2 → 14.17.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/lib/commands/firestore-bulkdelete.js +73 -0
- package/lib/commands/firestore-operations-cancel.js +44 -0
- package/lib/commands/firestore-operations-describe.js +29 -0
- package/lib/commands/firestore-operations-list.js +29 -0
- package/lib/commands/firestore-utils.js +15 -0
- package/lib/commands/functions-config-export.js +5 -2
- package/lib/commands/index.js +5 -0
- package/lib/config.js +16 -4
- package/lib/crashlytics/{listNotes.js → events.js} +11 -9
- package/lib/crashlytics/filters.js +77 -0
- package/lib/crashlytics/issues.js +50 -0
- package/lib/crashlytics/notes.js +67 -0
- package/lib/crashlytics/reports.js +47 -0
- package/lib/crashlytics/types.js +60 -0
- package/lib/dataconnect/ensureApis.js +3 -3
- package/lib/deploy/apphosting/deploy.js +2 -1
- package/lib/deploy/apphosting/util.js +5 -8
- package/lib/deploy/functions/deploy.js +4 -3
- package/lib/deploy/functions/prepare.js +8 -6
- package/lib/emulator/apphosting/developmentServer.js +3 -3
- package/lib/emulator/apphosting/serve.js +29 -29
- package/lib/emulator/commandUtils.js +7 -1
- package/lib/emulator/controller.js +15 -31
- package/lib/emulator/downloadableEmulatorInfo.json +18 -18
- package/lib/emulator/hub.js +7 -1
- package/lib/emulator/initEmulators.js +1 -1
- package/lib/extensions/runtimes/common.js +3 -2
- package/lib/firestore/api.js +45 -0
- package/lib/firestore/pretty-print.js +23 -0
- package/lib/functions/projectConfig.js +69 -9
- package/lib/gcp/cloudfunctions.js +1 -6
- package/lib/gcp/cloudfunctionsv2.js +1 -9
- package/lib/gcp/cloudsql/cloudsqladmin.js +2 -2
- package/lib/init/features/dataconnect/create_app.js +7 -2
- package/lib/init/features/dataconnect/index.js +101 -60
- package/lib/init/features/dataconnect/sdk.js +35 -17
- package/lib/mcp/errors.js +2 -10
- package/lib/mcp/index.js +0 -3
- package/lib/mcp/prompts/crashlytics/connect.js +114 -0
- package/lib/mcp/prompts/crashlytics/index.js +2 -3
- package/lib/mcp/tools/auth/disable_user.js +1 -1
- package/lib/mcp/tools/auth/get_user.js +9 -2
- package/lib/mcp/tools/core/index.js +4 -0
- package/lib/mcp/tools/core/init.js +11 -2
- package/lib/mcp/tools/core/login.js +46 -0
- package/lib/mcp/tools/core/logout.js +62 -0
- package/lib/mcp/tools/crashlytics/events.js +42 -0
- package/lib/mcp/tools/crashlytics/index.js +16 -20
- package/lib/mcp/tools/crashlytics/issues.js +56 -0
- package/lib/mcp/tools/crashlytics/notes.js +78 -0
- package/lib/mcp/tools/crashlytics/reports.js +100 -0
- package/lib/mcp/tools/dataconnect/index.js +2 -2
- package/lib/mcp/tools/dataconnect/{info.js → list_services.js} +5 -5
- package/lib/mcp/util.js +1 -17
- package/lib/serve/functions.js +4 -3
- package/lib/unzip.js +13 -0
- package/lib/utils.js +17 -1
- package/package.json +1 -1
- package/schema/firebase-config.json +160 -59
- package/lib/crashlytics/addNote.js +0 -27
- package/lib/crashlytics/deleteNote.js +0 -23
- package/lib/crashlytics/getIssueDetails.js +0 -26
- package/lib/crashlytics/getSampleCrash.js +0 -34
- package/lib/crashlytics/listTopDevices.js +0 -33
- package/lib/crashlytics/listTopIssues.js +0 -30
- package/lib/crashlytics/listTopOperatingSystems.js +0 -32
- package/lib/crashlytics/listTopVersions.js +0 -32
- package/lib/crashlytics/updateIssue.js +0 -35
- package/lib/mcp/prompts/crashlytics/common.js +0 -10
- package/lib/mcp/prompts/crashlytics/fix_issue.js +0 -89
- package/lib/mcp/prompts/crashlytics/prioritize_issues.js +0 -79
- package/lib/mcp/tools/crashlytics/add_note.js +0 -32
- package/lib/mcp/tools/crashlytics/constants.js +0 -11
- package/lib/mcp/tools/crashlytics/delete_note.js +0 -35
- package/lib/mcp/tools/crashlytics/get_issue_details.js +0 -31
- package/lib/mcp/tools/crashlytics/get_sample_crash.js +0 -43
- package/lib/mcp/tools/crashlytics/list_notes.js +0 -37
- package/lib/mcp/tools/crashlytics/list_top_devices.js +0 -33
- package/lib/mcp/tools/crashlytics/list_top_issues.js +0 -38
- package/lib/mcp/tools/crashlytics/list_top_operating_systems.js +0 -33
- package/lib/mcp/tools/crashlytics/list_top_versions.js +0 -33
- package/lib/mcp/tools/crashlytics/update_issue.js +0 -37
- package/lib/mcp/tools/database/set_rules.js +0 -41
|
@@ -1,6 +1,17 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __rest = (this && this.__rest) || function (s, e) {
|
|
3
|
+
var t = {};
|
|
4
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
5
|
+
t[p] = s[p];
|
|
6
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
7
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
8
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
9
|
+
t[p[i]] = s[p[i]];
|
|
10
|
+
}
|
|
11
|
+
return t;
|
|
12
|
+
};
|
|
2
13
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.configForCodebase = exports.normalizeAndValidate = exports.validate = exports.assertUnique = exports.validatePrefix = exports.validateCodebase = exports.normalize = exports.DEFAULT_CODEBASE = void 0;
|
|
14
|
+
exports.resolveConfigDir = exports.requireLocal = exports.isRemoteConfig = exports.isLocalConfig = exports.configForCodebase = exports.normalizeAndValidate = exports.validate = exports.assertUnique = exports.validatePrefix = exports.validateCodebase = exports.normalize = exports.DEFAULT_CODEBASE = void 0;
|
|
4
15
|
const error_1 = require("../error");
|
|
5
16
|
exports.DEFAULT_CODEBASE = "default";
|
|
6
17
|
function normalize(config) {
|
|
@@ -33,17 +44,33 @@ function validatePrefix(prefix) {
|
|
|
33
44
|
}
|
|
34
45
|
exports.validatePrefix = validatePrefix;
|
|
35
46
|
function validateSingle(config) {
|
|
36
|
-
|
|
37
|
-
|
|
47
|
+
const { source, remoteSource, runtime, codebase: providedCodebase } = config, rest = __rest(config, ["source", "remoteSource", "runtime", "codebase"]);
|
|
48
|
+
if (source && remoteSource) {
|
|
49
|
+
throw new error_1.FirebaseError("Cannot specify both 'source' and 'remoteSource' in a single functions config. Please choose one.");
|
|
38
50
|
}
|
|
39
|
-
if (!
|
|
40
|
-
|
|
51
|
+
if (!source && !remoteSource) {
|
|
52
|
+
throw new error_1.FirebaseError("codebase source must be specified. Must specify either 'source' or 'remoteSource' in a functions config.");
|
|
41
53
|
}
|
|
42
|
-
|
|
54
|
+
const codebase = providedCodebase !== null && providedCodebase !== void 0 ? providedCodebase : exports.DEFAULT_CODEBASE;
|
|
55
|
+
validateCodebase(codebase);
|
|
43
56
|
if (config.prefix) {
|
|
44
57
|
validatePrefix(config.prefix);
|
|
45
58
|
}
|
|
46
|
-
|
|
59
|
+
const commonConfig = Object.assign({ codebase }, rest);
|
|
60
|
+
if (source) {
|
|
61
|
+
return Object.assign(Object.assign(Object.assign({}, commonConfig), { source }), (runtime ? { runtime } : {}));
|
|
62
|
+
}
|
|
63
|
+
else if (remoteSource) {
|
|
64
|
+
if (!remoteSource.repository || !remoteSource.ref) {
|
|
65
|
+
throw new error_1.FirebaseError("remoteSource requires 'repository' and 'ref' to be specified.");
|
|
66
|
+
}
|
|
67
|
+
if (!runtime) {
|
|
68
|
+
throw new error_1.FirebaseError("functions.runtime is required when using remoteSource in firebase.json.");
|
|
69
|
+
}
|
|
70
|
+
return Object.assign(Object.assign({}, commonConfig), { remoteSource,
|
|
71
|
+
runtime });
|
|
72
|
+
}
|
|
73
|
+
throw new error_1.FirebaseError("Invalid functions config.");
|
|
47
74
|
}
|
|
48
75
|
function assertUnique(config, property, propval) {
|
|
49
76
|
const values = new Set();
|
|
@@ -63,9 +90,22 @@ function assertUniqueSourcePrefixPair(config) {
|
|
|
63
90
|
var _a;
|
|
64
91
|
const sourcePrefixPairs = new Set();
|
|
65
92
|
for (const c of config) {
|
|
66
|
-
|
|
93
|
+
let sourceIdentifier;
|
|
94
|
+
let sourceDescription;
|
|
95
|
+
if (c.source) {
|
|
96
|
+
sourceIdentifier = c.source;
|
|
97
|
+
sourceDescription = `source directory ('${c.source}')`;
|
|
98
|
+
}
|
|
99
|
+
else if (c.remoteSource) {
|
|
100
|
+
sourceIdentifier = `remote:${c.remoteSource.repository}#${c.remoteSource.ref}@dir:${c.remoteSource.dir || "."}`;
|
|
101
|
+
sourceDescription = `remote source ('${c.remoteSource.repository}')`;
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
const key = JSON.stringify({ source: sourceIdentifier, prefix: c.prefix || "" });
|
|
67
107
|
if (sourcePrefixPairs.has(key)) {
|
|
68
|
-
throw new error_1.FirebaseError(`More than one functions config specifies the same
|
|
108
|
+
throw new error_1.FirebaseError(`More than one functions config specifies the same ${sourceDescription} and prefix ('${(_a = c.prefix) !== null && _a !== void 0 ? _a : ""}'). Please add a unique 'prefix' to each function configuration that shares this source to resolve the conflict.`);
|
|
69
109
|
}
|
|
70
110
|
sourcePrefixPairs.add(key);
|
|
71
111
|
}
|
|
@@ -89,3 +129,23 @@ function configForCodebase(config, codebase) {
|
|
|
89
129
|
return codebaseCfg;
|
|
90
130
|
}
|
|
91
131
|
exports.configForCodebase = configForCodebase;
|
|
132
|
+
function isLocalConfig(c) {
|
|
133
|
+
return c.source !== undefined;
|
|
134
|
+
}
|
|
135
|
+
exports.isLocalConfig = isLocalConfig;
|
|
136
|
+
function isRemoteConfig(c) {
|
|
137
|
+
return c.remoteSource !== undefined;
|
|
138
|
+
}
|
|
139
|
+
exports.isRemoteConfig = isRemoteConfig;
|
|
140
|
+
function requireLocal(c, purpose) {
|
|
141
|
+
if (!isLocalConfig(c)) {
|
|
142
|
+
const msg = purpose !== null && purpose !== void 0 ? purpose : "This operation requires a local functions source directory, but the codebase is configured with a remote source.";
|
|
143
|
+
throw new error_1.FirebaseError(msg);
|
|
144
|
+
}
|
|
145
|
+
return c;
|
|
146
|
+
}
|
|
147
|
+
exports.requireLocal = requireLocal;
|
|
148
|
+
function resolveConfigDir(c) {
|
|
149
|
+
return c.configDir || c.source;
|
|
150
|
+
}
|
|
151
|
+
exports.resolveConfigDir = resolveConfigDir;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.functionFromEndpoint = exports.endpointFromFunction = exports.listAllFunctions = exports.
|
|
3
|
+
exports.functionFromEndpoint = exports.endpointFromFunction = exports.listAllFunctions = exports.deleteFunction = exports.updateFunction = exports.setInvokerUpdate = exports.setInvokerCreate = exports.getIamPolicy = exports.setIamPolicy = exports.createFunction = exports.generateUploadUrl = exports.captureRuntimeValidationError = exports.API_VERSION = void 0;
|
|
4
4
|
const clc = require("colorette");
|
|
5
5
|
const error_1 = require("../error");
|
|
6
6
|
const logger_1 = require("../logger");
|
|
@@ -200,11 +200,6 @@ async function list(projectId, region) {
|
|
|
200
200
|
});
|
|
201
201
|
}
|
|
202
202
|
}
|
|
203
|
-
async function listFunctions(projectId, region) {
|
|
204
|
-
const res = await list(projectId, region);
|
|
205
|
-
return res.functions;
|
|
206
|
-
}
|
|
207
|
-
exports.listFunctions = listFunctions;
|
|
208
203
|
async function listAllFunctions(projectId) {
|
|
209
204
|
return list(projectId, "-");
|
|
210
205
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.endpointFromFunction = exports.functionFromEndpoint = exports.deleteFunction = exports.updateFunction = exports.listAllFunctions = exports.
|
|
3
|
+
exports.endpointFromFunction = exports.functionFromEndpoint = exports.deleteFunction = exports.updateFunction = exports.listAllFunctions = exports.getFunction = exports.createFunction = exports.generateUploadUrl = exports.API_VERSION = void 0;
|
|
4
4
|
const apiv2_1 = require("../apiv2");
|
|
5
5
|
const error_1 = require("../error");
|
|
6
6
|
const api_1 = require("../api");
|
|
@@ -84,14 +84,6 @@ async function getFunction(projectId, location, functionId) {
|
|
|
84
84
|
return res.body;
|
|
85
85
|
}
|
|
86
86
|
exports.getFunction = getFunction;
|
|
87
|
-
async function listFunctions(projectId, region) {
|
|
88
|
-
const res = await listFunctionsInternal(projectId, region);
|
|
89
|
-
if (res.unreachable.includes(region)) {
|
|
90
|
-
throw new error_1.FirebaseError(`Cloud Functions region ${region} is unavailable`);
|
|
91
|
-
}
|
|
92
|
-
return res.functions;
|
|
93
|
-
}
|
|
94
|
-
exports.listFunctions = listFunctions;
|
|
95
87
|
async function listAllFunctions(projectId) {
|
|
96
88
|
return await listFunctionsInternal(projectId, "-");
|
|
97
89
|
}
|
|
@@ -151,7 +151,7 @@ async function deleteDatabase(projectId, instanceId, databaseId) {
|
|
|
151
151
|
return res.body;
|
|
152
152
|
}
|
|
153
153
|
exports.deleteDatabase = deleteDatabase;
|
|
154
|
-
async function createUser(projectId, instanceId, type, username, password) {
|
|
154
|
+
async function createUser(projectId, instanceId, type, username, password, retryTimeout) {
|
|
155
155
|
const maxRetries = 3;
|
|
156
156
|
let retries = 0;
|
|
157
157
|
while (true) {
|
|
@@ -180,7 +180,7 @@ async function createUser(projectId, instanceId, type, username, password) {
|
|
|
180
180
|
if (builtinRoleNotReady(err.message) && retries < maxRetries) {
|
|
181
181
|
retries++;
|
|
182
182
|
await new Promise((resolve) => {
|
|
183
|
-
setTimeout(resolve, 1000 * retries);
|
|
183
|
+
setTimeout(resolve, retryTimeout !== null && retryTimeout !== void 0 ? retryTimeout : 1000 * retries);
|
|
184
184
|
});
|
|
185
185
|
}
|
|
186
186
|
else {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.createNextApp = exports.createReactApp = void 0;
|
|
3
|
+
exports.createFlutterApp = exports.createNextApp = exports.createReactApp = void 0;
|
|
4
4
|
const child_process_1 = require("child_process");
|
|
5
5
|
const clc = require("colorette");
|
|
6
6
|
const utils_1 = require("../../../utils");
|
|
@@ -26,8 +26,13 @@ async function createNextApp(webAppId) {
|
|
|
26
26
|
await executeCommand("npx", args);
|
|
27
27
|
}
|
|
28
28
|
exports.createNextApp = createNextApp;
|
|
29
|
+
async function createFlutterApp(webAppId) {
|
|
30
|
+
const args = ["create", webAppId];
|
|
31
|
+
await executeCommand("flutter", args);
|
|
32
|
+
}
|
|
33
|
+
exports.createFlutterApp = createFlutterApp;
|
|
29
34
|
async function executeCommand(command, args) {
|
|
30
|
-
(0, utils_1.logLabeledBullet)("dataconnect",
|
|
35
|
+
(0, utils_1.logLabeledBullet)("dataconnect", `> ${clc.bold(`${command} ${args.join(" ")}`)}`);
|
|
31
36
|
return new Promise((resolve, reject) => {
|
|
32
37
|
const childProcess = (0, child_process_1.spawn)(command, args, {
|
|
33
38
|
stdio: "inherit",
|
|
@@ -26,26 +26,25 @@ const CONNECTOR_YAML_TEMPLATE = (0, templates_1.readTemplateSync)("init/dataconn
|
|
|
26
26
|
const SCHEMA_TEMPLATE = (0, templates_1.readTemplateSync)("init/dataconnect/schema.gql");
|
|
27
27
|
const QUERIES_TEMPLATE = (0, templates_1.readTemplateSync)("init/dataconnect/queries.gql");
|
|
28
28
|
const MUTATIONS_TEMPLATE = (0, templates_1.readTemplateSync)("init/dataconnect/mutations.gql");
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
files: [],
|
|
33
|
-
};
|
|
34
|
-
const defaultConnector = {
|
|
35
|
-
id: "example",
|
|
36
|
-
path: "./example",
|
|
37
|
-
files: [
|
|
38
|
-
{
|
|
39
|
-
path: "queries.gql",
|
|
40
|
-
content: QUERIES_TEMPLATE,
|
|
41
|
-
},
|
|
29
|
+
const templateServiceInfo = {
|
|
30
|
+
schemaGql: [{ path: "schema.gql", content: SCHEMA_TEMPLATE }],
|
|
31
|
+
connectors: [
|
|
42
32
|
{
|
|
43
|
-
|
|
44
|
-
|
|
33
|
+
id: "example",
|
|
34
|
+
path: "./example",
|
|
35
|
+
files: [
|
|
36
|
+
{
|
|
37
|
+
path: "queries.gql",
|
|
38
|
+
content: QUERIES_TEMPLATE,
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
path: "mutations.gql",
|
|
42
|
+
content: MUTATIONS_TEMPLATE,
|
|
43
|
+
},
|
|
44
|
+
],
|
|
45
45
|
},
|
|
46
46
|
],
|
|
47
47
|
};
|
|
48
|
-
const defaultSchema = { path: "schema.gql", content: SCHEMA_TEMPLATE };
|
|
49
48
|
async function askQuestions(setup) {
|
|
50
49
|
const info = {
|
|
51
50
|
analyticsFlow: "cli",
|
|
@@ -54,6 +53,7 @@ async function askQuestions(setup) {
|
|
|
54
53
|
locationId: "",
|
|
55
54
|
cloudSqlInstanceId: "",
|
|
56
55
|
cloudSqlDatabase: "",
|
|
56
|
+
shouldProvisionCSQL: false,
|
|
57
57
|
};
|
|
58
58
|
if (setup.projectId) {
|
|
59
59
|
const hasBilling = await (0, cloudbilling_1.isBillingEnabled)(setup);
|
|
@@ -101,6 +101,7 @@ async function actuate(setup, config, options) {
|
|
|
101
101
|
void (0, track_1.trackGA4)("dataconnect_init", {
|
|
102
102
|
project_status: setup.projectId ? (setup.isBillingEnabled ? "blaze" : "spark") : "missing",
|
|
103
103
|
flow: info.analyticsFlow,
|
|
104
|
+
provision_cloud_sql: String(info.shouldProvisionCSQL),
|
|
104
105
|
});
|
|
105
106
|
}
|
|
106
107
|
if (info.appDescription) {
|
|
@@ -118,10 +119,11 @@ async function actuateWithInfo(setup, config, info, options) {
|
|
|
118
119
|
const projectId = setup.projectId;
|
|
119
120
|
if (!projectId) {
|
|
120
121
|
info.analyticsFlow += "_save_template";
|
|
121
|
-
return await writeFiles(config, info,
|
|
122
|
+
return await writeFiles(config, info, templateServiceInfo, options);
|
|
122
123
|
}
|
|
123
|
-
|
|
124
|
-
|
|
124
|
+
await (0, ensureApis_1.ensureApis)(projectId, true);
|
|
125
|
+
const provisionCSQL = info.shouldProvisionCSQL && (await (0, cloudbilling_1.isBillingEnabled)(setup));
|
|
126
|
+
if (provisionCSQL) {
|
|
125
127
|
await (0, provisionCloudSql_1.setupCloudSql)({
|
|
126
128
|
projectId: projectId,
|
|
127
129
|
location: info.locationId,
|
|
@@ -130,15 +132,18 @@ async function actuateWithInfo(setup, config, info, options) {
|
|
|
130
132
|
requireGoogleMlIntegration: false,
|
|
131
133
|
});
|
|
132
134
|
}
|
|
135
|
+
const serviceName = `projects/${projectId}/locations/${info.locationId}/services/${info.serviceId}`;
|
|
133
136
|
if (!info.appDescription) {
|
|
137
|
+
if (!info.serviceGql) {
|
|
138
|
+
await downloadService(info, serviceName);
|
|
139
|
+
}
|
|
134
140
|
if (info.serviceGql) {
|
|
135
141
|
info.analyticsFlow += "_save_downloaded";
|
|
136
142
|
return await writeFiles(config, info, info.serviceGql, options);
|
|
137
143
|
}
|
|
138
144
|
info.analyticsFlow += "_save_template";
|
|
139
|
-
return await writeFiles(config, info,
|
|
145
|
+
return await writeFiles(config, info, templateServiceInfo, options);
|
|
140
146
|
}
|
|
141
|
-
const serviceName = `projects/${projectId}/locations/${info.locationId}/services/${info.serviceId}`;
|
|
142
147
|
const serviceAlreadyExists = !(await (0, client_1.createService)(projectId, info.locationId, info.serviceId));
|
|
143
148
|
const schemaGql = await (0, utils_1.promiseWithSpinner)(() => (0, fdcExperience_1.generateSchema)(info.appDescription, projectId), "Generating the Data Connect Schema...");
|
|
144
149
|
const schemaFiles = [{ path: "schema.gql", content: schemaGql }];
|
|
@@ -148,7 +153,7 @@ async function actuateWithInfo(setup, config, info, options) {
|
|
|
148
153
|
return await writeFiles(config, info, { schemaGql: schemaFiles, connectors: [] }, options);
|
|
149
154
|
}
|
|
150
155
|
await (0, utils_1.promiseWithSpinner)(async () => {
|
|
151
|
-
const [saveSchemaGql, waitForCloudSQLProvision] = schemasDeploySequence(projectId, info, schemaFiles,
|
|
156
|
+
const [saveSchemaGql, waitForCloudSQLProvision] = schemasDeploySequence(projectId, info, schemaFiles, provisionCSQL);
|
|
152
157
|
await (0, client_1.upsertSchema)(saveSchemaGql);
|
|
153
158
|
if (waitForCloudSQLProvision) {
|
|
154
159
|
void (0, client_1.upsertSchema)(waitForCloudSQLProvision);
|
|
@@ -284,7 +289,6 @@ function subConnectorYamlValues(replacementValues) {
|
|
|
284
289
|
return replaced;
|
|
285
290
|
}
|
|
286
291
|
async function promptForExistingServices(setup, info) {
|
|
287
|
-
var _a, _b, _c, _d, _e;
|
|
288
292
|
if (!setup.projectId) {
|
|
289
293
|
return;
|
|
290
294
|
}
|
|
@@ -292,10 +296,7 @@ async function promptForExistingServices(setup, info) {
|
|
|
292
296
|
if (!existingServices.length) {
|
|
293
297
|
return;
|
|
294
298
|
}
|
|
295
|
-
const
|
|
296
|
-
return { service: s, schema: await (0, client_1.getSchema)(s.name) };
|
|
297
|
-
}));
|
|
298
|
-
const choice = await chooseExistingService(existingServicesAndSchemas);
|
|
299
|
+
const choice = await chooseExistingService(existingServices);
|
|
299
300
|
if (!choice) {
|
|
300
301
|
const existingServiceIds = existingServices.map((s) => s.name.split("/").pop());
|
|
301
302
|
info.serviceId = (0, utils_1.newUniqueId)(defaultServiceId(), existingServiceIds);
|
|
@@ -303,39 +304,50 @@ async function promptForExistingServices(setup, info) {
|
|
|
303
304
|
return;
|
|
304
305
|
}
|
|
305
306
|
info.analyticsFlow += "_pick_existing_service";
|
|
306
|
-
const serviceName = (0, names_1.parseServiceName)(choice.
|
|
307
|
+
const serviceName = (0, names_1.parseServiceName)(choice.name);
|
|
307
308
|
info.serviceId = serviceName.serviceId;
|
|
308
309
|
info.locationId = serviceName.location;
|
|
310
|
+
await downloadService(info, choice.name);
|
|
311
|
+
}
|
|
312
|
+
async function downloadService(info, serviceName) {
|
|
313
|
+
var _a, _b, _c, _d, _e;
|
|
314
|
+
const schema = await (0, client_1.getSchema)(serviceName);
|
|
315
|
+
if (!schema) {
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
309
318
|
info.serviceGql = {
|
|
310
319
|
schemaGql: [],
|
|
311
|
-
connectors: [
|
|
320
|
+
connectors: [
|
|
321
|
+
{
|
|
322
|
+
id: "example",
|
|
323
|
+
path: "./example",
|
|
324
|
+
files: [],
|
|
325
|
+
},
|
|
326
|
+
],
|
|
312
327
|
};
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
});
|
|
336
|
-
}
|
|
328
|
+
const primaryDatasource = schema.datasources.find((d) => d.postgresql);
|
|
329
|
+
if ((_b = (_a = primaryDatasource === null || primaryDatasource === void 0 ? void 0 : primaryDatasource.postgresql) === null || _a === void 0 ? void 0 : _a.cloudSql) === null || _b === void 0 ? void 0 : _b.instance) {
|
|
330
|
+
const instanceName = (0, names_1.parseCloudSQLInstanceName)(primaryDatasource.postgresql.cloudSql.instance);
|
|
331
|
+
info.cloudSqlInstanceId = instanceName.instanceId;
|
|
332
|
+
}
|
|
333
|
+
if ((_c = schema.source.files) === null || _c === void 0 ? void 0 : _c.length) {
|
|
334
|
+
info.serviceGql.schemaGql = schema.source.files;
|
|
335
|
+
}
|
|
336
|
+
info.cloudSqlDatabase = (_e = (_d = primaryDatasource === null || primaryDatasource === void 0 ? void 0 : primaryDatasource.postgresql) === null || _d === void 0 ? void 0 : _d.database) !== null && _e !== void 0 ? _e : "";
|
|
337
|
+
const connectors = await (0, client_1.listConnectors)(serviceName, [
|
|
338
|
+
"connectors.name",
|
|
339
|
+
"connectors.source.files",
|
|
340
|
+
]);
|
|
341
|
+
if (connectors.length) {
|
|
342
|
+
info.serviceGql.connectors = connectors.map((c) => {
|
|
343
|
+
const id = c.name.split("/").pop();
|
|
344
|
+
return {
|
|
345
|
+
id,
|
|
346
|
+
path: connectors.length === 1 ? "./example" : `./${id}`,
|
|
347
|
+
files: c.source.files || [],
|
|
348
|
+
};
|
|
349
|
+
});
|
|
337
350
|
}
|
|
338
|
-
return;
|
|
339
351
|
}
|
|
340
352
|
async function chooseExistingService(existing) {
|
|
341
353
|
const fdcConnector = (0, utils_1.envOverride)("FDC_CONNECTOR", "");
|
|
@@ -344,7 +356,7 @@ async function chooseExistingService(existing) {
|
|
|
344
356
|
if (serviceEnvVar) {
|
|
345
357
|
const [serviceLocationFromEnvVar, serviceIdFromEnvVar] = serviceEnvVar.split("/");
|
|
346
358
|
const serviceFromEnvVar = existing.find((s) => {
|
|
347
|
-
const serviceName = (0, names_1.parseServiceName)(s.
|
|
359
|
+
const serviceName = (0, names_1.parseServiceName)(s.name);
|
|
348
360
|
return (serviceName.serviceId === serviceIdFromEnvVar &&
|
|
349
361
|
serviceName.location === serviceLocationFromEnvVar);
|
|
350
362
|
});
|
|
@@ -356,7 +368,7 @@ async function chooseExistingService(existing) {
|
|
|
356
368
|
(0, utils_1.logWarning)(`Unable to pick up an existing service based on ${envVarName}=${serviceEnvVar}.`);
|
|
357
369
|
}
|
|
358
370
|
const choices = existing.map((s) => {
|
|
359
|
-
const serviceName = (0, names_1.parseServiceName)(s.
|
|
371
|
+
const serviceName = (0, names_1.parseServiceName)(s.name);
|
|
360
372
|
return {
|
|
361
373
|
name: `${serviceName.location}/${serviceName.serviceId}`,
|
|
362
374
|
value: s,
|
|
@@ -412,7 +424,11 @@ async function promptForCloudSQL(setup, info) {
|
|
|
412
424
|
info.locationId = await (0, prompt_1.select)({
|
|
413
425
|
message: "What location would like to use?",
|
|
414
426
|
choices,
|
|
415
|
-
default: "us-
|
|
427
|
+
default: "us-east4",
|
|
428
|
+
});
|
|
429
|
+
info.shouldProvisionCSQL = await (0, prompt_1.confirm)({
|
|
430
|
+
message: `Would you like to provision your Cloud SQL instance and database now?`,
|
|
431
|
+
default: true,
|
|
416
432
|
});
|
|
417
433
|
}
|
|
418
434
|
if (info.cloudSqlInstanceId !== "" && info.cloudSqlDatabase === "") {
|
|
@@ -436,14 +452,39 @@ async function locationChoices(setup) {
|
|
|
436
452
|
}
|
|
437
453
|
else {
|
|
438
454
|
return [
|
|
439
|
-
{ name: "
|
|
440
|
-
{ name: "
|
|
455
|
+
{ name: "asia-east1", value: "asia-east1" },
|
|
456
|
+
{ name: "asia-east2", value: "asia-east2" },
|
|
457
|
+
{ name: "asia-northeast1", value: "asia-northeast1" },
|
|
458
|
+
{ name: "asia-northeast2", value: "asia-northeast2" },
|
|
459
|
+
{ name: "asia-northeast3", value: "asia-northeast3" },
|
|
460
|
+
{ name: "asia-south1", value: "asia-south1" },
|
|
461
|
+
{ name: "asia-southeast1", value: "asia-southeast1" },
|
|
462
|
+
{ name: "asia-southeast2", value: "asia-southeast2" },
|
|
463
|
+
{ name: "australia-southeast1", value: "australia-southeast1" },
|
|
464
|
+
{ name: "australia-southeast2", value: "australia-southeast2" },
|
|
441
465
|
{ name: "europe-central2", value: "europe-central2" },
|
|
466
|
+
{ name: "europe-north1", value: "europe-north1" },
|
|
467
|
+
{ name: "europe-southwest1", value: "europe-southwest1" },
|
|
442
468
|
{ name: "europe-west1", value: "europe-west1" },
|
|
469
|
+
{ name: "europe-west2", value: "europe-west2" },
|
|
470
|
+
{ name: "europe-west3", value: "europe-west3" },
|
|
471
|
+
{ name: "europe-west4", value: "europe-west4" },
|
|
472
|
+
{ name: "europe-west6", value: "europe-west6" },
|
|
473
|
+
{ name: "europe-west8", value: "europe-west8" },
|
|
474
|
+
{ name: "europe-west9", value: "europe-west9" },
|
|
475
|
+
{ name: "me-west1", value: "me-west1" },
|
|
476
|
+
{ name: "northamerica-northeast1", value: "northamerica-northeast1" },
|
|
477
|
+
{ name: "northamerica-northeast2", value: "northamerica-northeast2" },
|
|
478
|
+
{ name: "southamerica-east1", value: "southamerica-east1" },
|
|
443
479
|
{ name: "southamerica-west1", value: "southamerica-west1" },
|
|
480
|
+
{ name: "us-central1", value: "us-central1" },
|
|
481
|
+
{ name: "us-east1", value: "us-east1" },
|
|
444
482
|
{ name: "us-east4", value: "us-east4" },
|
|
483
|
+
{ name: "us-south1", value: "us-south1" },
|
|
445
484
|
{ name: "us-west1", value: "us-west1" },
|
|
446
|
-
{ name: "
|
|
485
|
+
{ name: "us-west2", value: "us-west2" },
|
|
486
|
+
{ name: "us-west3", value: "us-west3" },
|
|
487
|
+
{ name: "us-west4", value: "us-west4" },
|
|
447
488
|
];
|
|
448
489
|
}
|
|
449
490
|
}
|
|
@@ -26,25 +26,38 @@ async function askQuestions(setup) {
|
|
|
26
26
|
};
|
|
27
27
|
info.apps = await chooseApp();
|
|
28
28
|
if (!info.apps.length) {
|
|
29
|
-
const
|
|
30
|
-
|
|
29
|
+
const npxMissingWarning = (0, utils_1.commandExistsSync)("npx")
|
|
30
|
+
? ""
|
|
31
|
+
: clc.yellow(" (you need to install Node.js first)");
|
|
32
|
+
const flutterMissingWarning = (0, utils_1.commandExistsSync)("flutter")
|
|
33
|
+
? ""
|
|
34
|
+
: clc.yellow(" (you need to install Flutter first)");
|
|
31
35
|
const choice = await (0, prompt_1.select)({
|
|
32
36
|
message: `Do you want to create an app template?`,
|
|
33
37
|
choices: [
|
|
34
|
-
{ name:
|
|
35
|
-
{ name:
|
|
38
|
+
{ name: `React${npxMissingWarning}`, value: "react" },
|
|
39
|
+
{ name: `Next.JS${npxMissingWarning}`, value: "next" },
|
|
40
|
+
{ name: `Flutter${flutterMissingWarning}`, value: "flutter" },
|
|
36
41
|
{ name: "no", value: "no" },
|
|
37
42
|
],
|
|
38
43
|
});
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
44
|
+
try {
|
|
45
|
+
switch (choice) {
|
|
46
|
+
case "react":
|
|
47
|
+
await (0, create_app_1.createReactApp)((0, utils_1.newUniqueId)("web-app", (0, fsutils_1.listFiles)(cwd)));
|
|
48
|
+
break;
|
|
49
|
+
case "next":
|
|
50
|
+
await (0, create_app_1.createNextApp)((0, utils_1.newUniqueId)("web-app", (0, fsutils_1.listFiles)(cwd)));
|
|
51
|
+
break;
|
|
52
|
+
case "flutter":
|
|
53
|
+
await (0, create_app_1.createFlutterApp)((0, utils_1.newUniqueId)("flutter_app", (0, fsutils_1.listFiles)(cwd)));
|
|
54
|
+
break;
|
|
55
|
+
case "no":
|
|
56
|
+
break;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
catch (err) {
|
|
60
|
+
(0, utils_1.logLabeledError)("dataconnect", `Failed to create a ${choice} app template`);
|
|
48
61
|
}
|
|
49
62
|
}
|
|
50
63
|
setup.featureInfo = setup.featureInfo || {};
|
|
@@ -151,10 +164,15 @@ async function actuateWithInfo(setup, config, info) {
|
|
|
151
164
|
config.writeProjectFile(path.relative(config.projectDir, connectorYamlPath), connectorYamlContents);
|
|
152
165
|
(0, utils_1.logLabeledBullet)("dataconnect", `Installing the generated SDKs ...`);
|
|
153
166
|
const account = (0, auth_1.getGlobalDefaultAccount)();
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
167
|
+
try {
|
|
168
|
+
await dataconnectEmulator_1.DataConnectEmulator.generate({
|
|
169
|
+
configDir: connectorInfo.directory,
|
|
170
|
+
account,
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
catch (e) {
|
|
174
|
+
(0, utils_1.logLabeledError)("dataconnect", `Failed to generate Data Connect SDKs\n${e === null || e === void 0 ? void 0 : e.message}`);
|
|
175
|
+
}
|
|
158
176
|
(0, utils_1.logLabeledSuccess)("dataconnect", `Installed generated SDKs for ${clc.bold(apps.map((a) => (0, appFinder_1.appDescription)(a)).join(", "))}`);
|
|
159
177
|
if (apps.some((a) => a.platform === types_1.Platform.IOS)) {
|
|
160
178
|
(0, utils_1.logBullet)(clc.bold("Please follow the instructions here to add your generated sdk to your XCode project:\n\thttps://firebase.google.com/docs/data-connect/ios-sdk#set-client"));
|
package/lib/mcp/errors.js
CHANGED
|
@@ -4,18 +4,10 @@ exports.mcpGeminiError = exports.mcpAuthError = exports.NO_PROJECT_ERROR = void
|
|
|
4
4
|
const util_1 = require("./util");
|
|
5
5
|
exports.NO_PROJECT_ERROR = (0, util_1.mcpError)('No active project was found. Use the `firebase_update_environment` tool to set the project directory to an absolute folder location containing a firebase.json config file. Alternatively, change the MCP server config to add [...,"--dir","/absolute/path/to/project/directory"] in its command-line arguments.', "PRECONDITION_FAILED");
|
|
6
6
|
function mcpAuthError(skipADC) {
|
|
7
|
-
const cmd = (0, util_1.commandExistsSync)("firebase") ? "firebase" : "npx -y firebase-tools";
|
|
8
7
|
if (skipADC) {
|
|
9
|
-
return (0, util_1.mcpError)(`The user is not currently logged into the Firebase CLI, which is required to use this tool. Please
|
|
10
|
-
\`\`\`sh
|
|
11
|
-
${cmd} login
|
|
12
|
-
\`\`\``);
|
|
8
|
+
return (0, util_1.mcpError)(`The user is not currently logged into the Firebase CLI, which is required to use this tool. Please run the 'firebase_login' tool to log in.`);
|
|
13
9
|
}
|
|
14
|
-
return (0, util_1.mcpError)(`The user is not currently logged into the Firebase CLI, which is required to use this tool. Please
|
|
15
|
-
\`\`\`sh
|
|
16
|
-
${cmd} login
|
|
17
|
-
\`\`\`
|
|
18
|
-
|
|
10
|
+
return (0, util_1.mcpError)(`The user is not currently logged into the Firebase CLI, which is required to use this tool. Please run the 'firebase_login' tool to log in, or instruct the user to configure [Application Default Credentials][ADC] on their machine.
|
|
19
11
|
[ADC]: https://cloud.google.com/docs/authentication/application-default-credentials`);
|
|
20
12
|
}
|
|
21
13
|
exports.mcpAuthError = mcpAuthError;
|
package/lib/mcp/index.js
CHANGED
|
@@ -140,9 +140,6 @@ class FirebaseMcpServer {
|
|
|
140
140
|
return this.emulatorHubClient;
|
|
141
141
|
}
|
|
142
142
|
const projectId = await this.getProjectId();
|
|
143
|
-
if (!projectId) {
|
|
144
|
-
return;
|
|
145
|
-
}
|
|
146
143
|
this.emulatorHubClient = new hubClient_1.EmulatorHubClient(projectId);
|
|
147
144
|
return this.emulatorHubClient;
|
|
148
145
|
}
|