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.
- package/lib/command.js +19 -5
- package/lib/commands/dataconnect-sdk-generate.js +28 -24
- package/lib/commands/init.js +8 -0
- package/lib/deploy/functions/build.js +2 -13
- package/lib/deploy/functions/prepare.js +2 -1
- package/lib/deploy/functions/runtimes/discovery/index.js +1 -1
- package/lib/emulator/auth/operations.js +10 -1
- package/lib/emulator/dataconnectEmulator.js +27 -24
- package/lib/emulator/functionsEmulator.js +1 -1
- package/lib/emulator/hub.js +2 -4
- package/lib/experiments.js +5 -0
- package/lib/functions/env.js +12 -1
- package/lib/init/features/dataconnect/index.js +10 -25
- package/lib/init/features/dataconnect/sdk.js +0 -1
- package/lib/init/features/index.js +1 -2
- package/lib/init/index.js +0 -1
- package/lib/mcp/index.js +1 -1
- package/lib/mcp/prompts/core/deploy.js +1 -1
- package/lib/mcp/prompts/dataconnect/index.js +9 -0
- package/lib/mcp/prompts/dataconnect/schema.js +68 -0
- package/lib/mcp/prompts/index.js +2 -1
- package/lib/mcp/tools/core/init.js +11 -2
- package/lib/mcp/tools/dataconnect/compile.js +43 -0
- package/lib/mcp/tools/dataconnect/execute.js +71 -0
- package/lib/mcp/tools/dataconnect/index.js +6 -14
- package/lib/mcp/tools/dataconnect/info.js +120 -0
- package/lib/mcp/tools/firestore/list_collections.js +0 -3
- package/lib/mcp/tools/index.js +3 -0
- package/lib/mcp/util/dataconnect/compile.js +18 -0
- package/lib/mcp/util/dataconnect/content.js +655 -0
- package/lib/track.js +16 -0
- package/package.json +1 -1
- package/lib/mcp/tools/dataconnect/execute_graphql.js +0 -48
- package/lib/mcp/tools/dataconnect/execute_graphql_read.js +0 -48
- package/lib/mcp/tools/dataconnect/execute_mutation.js +0 -62
- package/lib/mcp/tools/dataconnect/execute_query.js +0 -62
- package/lib/mcp/tools/dataconnect/get_connector.js +0 -31
- package/lib/mcp/tools/dataconnect/get_schema.js +0 -31
- package/lib/mcp/tools/dataconnect/list_services.js +0 -23
- /package/lib/mcp/{tools → util}/dataconnect/converter.js +0 -0
- /package/lib/mcp/{tools → util}/dataconnect/emulator.js +0 -0
package/lib/command.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.validateProjectId = exports.Command = void 0;
|
|
4
4
|
const clc = require("colorette");
|
|
5
|
+
const path = require("node:path");
|
|
5
6
|
const lodash_1 = require("lodash");
|
|
6
7
|
const error_1 = require("./error");
|
|
7
8
|
const utils_1 = require("./utils");
|
|
@@ -193,17 +194,15 @@ class Command {
|
|
|
193
194
|
}
|
|
194
195
|
}
|
|
195
196
|
async applyRC(options) {
|
|
196
|
-
var _a
|
|
197
|
+
var _a;
|
|
197
198
|
const rc = (0, rc_1.loadRC)(options);
|
|
198
199
|
options.rc = rc;
|
|
199
|
-
let activeProject = options.projectRoot
|
|
200
|
-
? ((_a = configstore_1.configstore.get("activeProjects")) !== null && _a !== void 0 ? _a : {})[options.projectRoot]
|
|
201
|
-
: undefined;
|
|
200
|
+
let activeProject = this.configstoreProject(options.projectRoot || process.cwd());
|
|
202
201
|
const isUseCommand = process.argv.includes("use");
|
|
203
202
|
if ((0, env_1.isFirebaseStudio)() && !options.project && !isUseCommand) {
|
|
204
203
|
activeProject = await (0, studio_1.reconcileStudioFirebaseProject)(options, activeProject);
|
|
205
204
|
}
|
|
206
|
-
options.project = (
|
|
205
|
+
options.project = (_a = options.project) !== null && _a !== void 0 ? _a : activeProject;
|
|
207
206
|
if (options.config && !options.project) {
|
|
208
207
|
options.project = options.config.defaults.project;
|
|
209
208
|
}
|
|
@@ -222,6 +221,21 @@ class Command {
|
|
|
222
221
|
options.project = aliases["default"];
|
|
223
222
|
}
|
|
224
223
|
}
|
|
224
|
+
configstoreProject(dir) {
|
|
225
|
+
var _a;
|
|
226
|
+
const projectMap = (_a = configstore_1.configstore.get("activeProjects")) !== null && _a !== void 0 ? _a : {};
|
|
227
|
+
let currentDir = path.resolve(dir);
|
|
228
|
+
while (true) {
|
|
229
|
+
if (projectMap[currentDir]) {
|
|
230
|
+
return projectMap[currentDir];
|
|
231
|
+
}
|
|
232
|
+
const parentDir = path.dirname(currentDir);
|
|
233
|
+
if (parentDir === currentDir) {
|
|
234
|
+
return null;
|
|
235
|
+
}
|
|
236
|
+
currentDir = parentDir;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
225
239
|
async resolveProjectIdentifiers(options) {
|
|
226
240
|
var _a;
|
|
227
241
|
if ((_a = options.project) === null || _a === void 0 ? void 0 : _a.match(/^\d+$/)) {
|
|
@@ -8,37 +8,41 @@ const projectUtils_1 = require("../projectUtils");
|
|
|
8
8
|
const load_1 = require("../dataconnect/load");
|
|
9
9
|
const logger_1 = require("../logger");
|
|
10
10
|
const auth_1 = require("../auth");
|
|
11
|
+
const utils_1 = require("../utils");
|
|
11
12
|
exports.command = new command_1.Command("dataconnect:sdk:generate")
|
|
12
13
|
.description("generate typed SDKs for your Data Connect connectors")
|
|
13
14
|
.option("--watch", "watch for changes to your connector GQL files and regenerate your SDKs when updates occur")
|
|
14
15
|
.action(async (options) => {
|
|
15
16
|
const projectId = (0, projectUtils_1.needProjectId)(options);
|
|
16
17
|
const serviceInfos = await (0, load_1.loadAll)(projectId, options.config);
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
18
|
+
const serviceInfosWithSDKs = serviceInfos.filter((serviceInfo) => serviceInfo.connectorInfo.some((c) => {
|
|
19
|
+
var _a, _b, _c, _d;
|
|
20
|
+
return (((_a = c.connectorYaml.generate) === null || _a === void 0 ? void 0 : _a.javascriptSdk) ||
|
|
21
|
+
((_b = c.connectorYaml.generate) === null || _b === void 0 ? void 0 : _b.kotlinSdk) ||
|
|
22
|
+
((_c = c.connectorYaml.generate) === null || _c === void 0 ? void 0 : _c.swiftSdk) ||
|
|
23
|
+
((_d = c.connectorYaml.generate) === null || _d === void 0 ? void 0 : _d.dartSdk));
|
|
24
|
+
}));
|
|
25
|
+
if (!serviceInfosWithSDKs.length) {
|
|
26
|
+
logger_1.logger.warn("No generated SDKs have been declared in connector.yaml files.");
|
|
27
|
+
logger_1.logger.warn(`Run ${clc.bold("firebase init dataconnect:sdk")} to configure a generated SDK.`);
|
|
28
|
+
logger_1.logger.warn(`See https://firebase.google.com/docs/data-connect/web-sdk for more details of how to configure generated SDKs.`);
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
async function generateSDK(serviceInfo) {
|
|
32
|
+
return dataconnectEmulator_1.DataConnectEmulator.generate({
|
|
33
|
+
configDir: serviceInfo.sourceDirectory,
|
|
34
|
+
watch: options.watch,
|
|
35
|
+
account: (0, auth_1.getProjectDefaultAccount)(options.projectRoot),
|
|
25
36
|
});
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
const account = (0, auth_1.getProjectDefaultAccount)(options.projectRoot);
|
|
34
|
-
const output = await dataconnectEmulator_1.DataConnectEmulator.generate({
|
|
35
|
-
configDir,
|
|
36
|
-
connectorId: conn.connectorYaml.connectorId,
|
|
37
|
-
watch: options.watch,
|
|
38
|
-
account,
|
|
39
|
-
});
|
|
40
|
-
logger_1.logger.info(output);
|
|
41
|
-
logger_1.logger.info(`Generated SDKs for ${conn.connectorYaml.connectorId}`);
|
|
37
|
+
}
|
|
38
|
+
if (options.watch) {
|
|
39
|
+
await Promise.race(serviceInfosWithSDKs.map(generateSDK));
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
for (const s of serviceInfosWithSDKs) {
|
|
43
|
+
await generateSDK(s);
|
|
42
44
|
}
|
|
45
|
+
const services = serviceInfosWithSDKs.map((s) => s.dataConnectYaml.serviceId).join(", ");
|
|
46
|
+
(0, utils_1.logLabeledSuccess)("dataconnect", `Successfully Generated SDKs for services: ${clc.bold(services)}`);
|
|
43
47
|
}
|
|
44
48
|
});
|
package/lib/commands/init.js
CHANGED
|
@@ -16,6 +16,7 @@ const utils = require("../utils");
|
|
|
16
16
|
const experiments_1 = require("../experiments");
|
|
17
17
|
const templates_1 = require("../templates");
|
|
18
18
|
const error_1 = require("../error");
|
|
19
|
+
const utils_1 = require("../utils");
|
|
19
20
|
const homeDir = os.homedir();
|
|
20
21
|
const BANNER_TEXT = (0, templates_1.readTemplateSync)("banner.txt");
|
|
21
22
|
const GITIGNORE_TEMPLATE = (0, templates_1.readTemplateSync)("_gitignore");
|
|
@@ -166,6 +167,7 @@ async function initAction(feature, options) {
|
|
|
166
167
|
json: true,
|
|
167
168
|
fallback: {},
|
|
168
169
|
}),
|
|
170
|
+
instructions: [],
|
|
169
171
|
};
|
|
170
172
|
if (process.platform === "win32") {
|
|
171
173
|
if (!(await (0, prompt_1.confirm)("Are you ready to proceed?"))) {
|
|
@@ -218,5 +220,11 @@ async function initAction(feature, options) {
|
|
|
218
220
|
}
|
|
219
221
|
logger_1.logger.info();
|
|
220
222
|
utils.logSuccess("Firebase initialization complete!");
|
|
223
|
+
if (setup.instructions.length) {
|
|
224
|
+
logger_1.logger.info(`\n${clc.bold("To get started:")}\n`);
|
|
225
|
+
for (const i of setup.instructions) {
|
|
226
|
+
(0, utils_1.logBullet)(i + "\n");
|
|
227
|
+
}
|
|
228
|
+
}
|
|
221
229
|
}
|
|
222
230
|
exports.initAction = initAction;
|
|
@@ -3,11 +3,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.applyPrefix = exports.toBackend = exports.envWithTypes = exports.resolveBackend = exports.AllIngressSettings = exports.AllVpcEgressSettings = exports.AllFunctionsPlatforms = exports.isBlockingTriggered = exports.isTaskQueueTriggered = exports.isScheduleTriggered = exports.isEventTriggered = exports.isCallableTriggered = exports.isHttpsTriggered = exports.of = exports.empty = void 0;
|
|
4
4
|
const backend = require("./backend");
|
|
5
5
|
const proto = require("../../gcp/proto");
|
|
6
|
-
const api = require("
|
|
6
|
+
const api = require("../../api");
|
|
7
7
|
const params = require("./params");
|
|
8
8
|
const error_1 = require("../../error");
|
|
9
9
|
const functional_1 = require("../../functional");
|
|
10
|
-
const env_1 = require("../../functions/env");
|
|
11
10
|
const cel_1 = require("./cel");
|
|
12
11
|
function empty() {
|
|
13
12
|
return {
|
|
@@ -56,17 +55,7 @@ exports.AllIngressSettings = [
|
|
|
56
55
|
"ALLOW_INTERNAL_AND_GCLB",
|
|
57
56
|
];
|
|
58
57
|
async function resolveBackend(opts) {
|
|
59
|
-
|
|
60
|
-
paramValues = await params.resolveParams(opts.build.params, opts.firebaseConfig, envWithTypes(opts.build.params, opts.userEnvs), opts.nonInteractive, opts.isEmulator);
|
|
61
|
-
const toWrite = {};
|
|
62
|
-
for (const paramName of Object.keys(paramValues)) {
|
|
63
|
-
const paramValue = paramValues[paramName];
|
|
64
|
-
if (Object.prototype.hasOwnProperty.call(opts.userEnvs, paramName) || paramValue.internal) {
|
|
65
|
-
continue;
|
|
66
|
-
}
|
|
67
|
-
toWrite[paramName] = paramValue.toString();
|
|
68
|
-
}
|
|
69
|
-
(0, env_1.writeUserEnvs)(toWrite, opts.userEnvOpt);
|
|
58
|
+
const paramValues = await params.resolveParams(opts.build.params, opts.firebaseConfig, envWithTypes(opts.build.params, opts.userEnvs), opts.nonInteractive, opts.isEmulator);
|
|
70
59
|
return { backend: toBackend(opts.build, paramValues), envs: paramValues };
|
|
71
60
|
}
|
|
72
61
|
exports.resolveBackend = resolveBackend;
|
|
@@ -59,6 +59,7 @@ async function prepare(context, options, payload) {
|
|
|
59
59
|
if (allowFunctionsConfig && checkAPIsEnabled[1]) {
|
|
60
60
|
runtimeConfig = Object.assign(Object.assign({}, runtimeConfig), (await (0, prepareFunctionsUpload_1.getFunctionsConfig)(projectId)));
|
|
61
61
|
}
|
|
62
|
+
context.hasRuntimeConfig = Object.keys(runtimeConfig).some((k) => k !== "firebase");
|
|
62
63
|
const wantBuilds = await loadCodebases(context.config, options, firebaseConfig, runtimeConfig, context.filters);
|
|
63
64
|
if (Object.values(wantBuilds).some((b) => b.extensions)) {
|
|
64
65
|
const extContext = {};
|
|
@@ -83,11 +84,11 @@ async function prepare(context, options, payload) {
|
|
|
83
84
|
const { backend: wantBackend, envs: resolvedEnvs } = await build.resolveBackend({
|
|
84
85
|
build: wantBuild,
|
|
85
86
|
firebaseConfig,
|
|
86
|
-
userEnvOpt,
|
|
87
87
|
userEnvs,
|
|
88
88
|
nonInteractive: options.nonInteractive,
|
|
89
89
|
isEmulator: false,
|
|
90
90
|
});
|
|
91
|
+
functionsEnv.writeResolvedParams(resolvedEnvs, userEnvs, userEnvOpt);
|
|
91
92
|
let hasEnvsFromParams = false;
|
|
92
93
|
wantBackend.environmentVariables = envs;
|
|
93
94
|
for (const envName of Object.keys(resolvedEnvs)) {
|
|
@@ -6,7 +6,7 @@ const fs = require("fs");
|
|
|
6
6
|
const path = require("path");
|
|
7
7
|
const yaml = require("yaml");
|
|
8
8
|
const logger_1 = require("../../../../logger");
|
|
9
|
-
const api = require("
|
|
9
|
+
const api = require("../../../../api");
|
|
10
10
|
const v1alpha1 = require("./v1alpha1");
|
|
11
11
|
const error_1 = require("../../../../error");
|
|
12
12
|
const TIMEOUT_OVERRIDE_ENV_VAR = "FUNCTIONS_DISCOVERY_TIMEOUT";
|
|
@@ -1512,7 +1512,16 @@ async function mfaSignInFinalize(state, reqBody) {
|
|
|
1512
1512
|
(0, errors_1.assert)(sessionInfo, "MISSING_SESSION_INFO");
|
|
1513
1513
|
const phoneNumber = verifyPhoneNumber(state, sessionInfo, code);
|
|
1514
1514
|
let { user, signInProvider } = parsePendingCredential(state, reqBody.mfaPendingCredential);
|
|
1515
|
-
const enrollment = (_b = user.mfaInfo) === null || _b === void 0 ? void 0 : _b.find((enrollment) =>
|
|
1515
|
+
const enrollment = (_b = user.mfaInfo) === null || _b === void 0 ? void 0 : _b.find((enrollment) => {
|
|
1516
|
+
if (enrollment.unobfuscatedPhoneInfo === phoneNumber) {
|
|
1517
|
+
return true;
|
|
1518
|
+
}
|
|
1519
|
+
if (!!enrollment.unobfuscatedPhoneInfo &&
|
|
1520
|
+
obfuscatePhoneNumber(enrollment.unobfuscatedPhoneInfo) === phoneNumber) {
|
|
1521
|
+
return true;
|
|
1522
|
+
}
|
|
1523
|
+
return false;
|
|
1524
|
+
});
|
|
1516
1525
|
const { updates, extraClaims } = await fetchBlockingFunction(state, state_1.BlockingFunctionEvents.BEFORE_SIGN_IN, user, { signInMethod: signInProvider, signInSecondFactor: "phone" });
|
|
1517
1526
|
user = state.updateUserByLocalId(user.localId, Object.assign(Object.assign({}, updates), { lastLoginAt: Date.now().toString() }));
|
|
1518
1527
|
(0, errors_1.assert)(enrollment && enrollment.mfaEnrollmentId, "MFA_ENROLLMENT_NOT_FOUND");
|
|
@@ -15,7 +15,6 @@ const emulatorLogger_1 = require("./emulatorLogger");
|
|
|
15
15
|
const types_2 = require("../dataconnect/types");
|
|
16
16
|
const portUtils_1 = require("./portUtils");
|
|
17
17
|
const registry_1 = require("./registry");
|
|
18
|
-
const logger_1 = require("../logger");
|
|
19
18
|
const load_1 = require("../dataconnect/load");
|
|
20
19
|
const pgliteServer_1 = require("./dataconnect/pgliteServer");
|
|
21
20
|
const controller_1 = require("./controller");
|
|
@@ -156,33 +155,37 @@ class DataConnectEmulator {
|
|
|
156
155
|
}
|
|
157
156
|
static async generate(args) {
|
|
158
157
|
const commandInfo = await (0, downloadableEmulators_1.downloadIfNecessary)(types_1.Emulators.DATACONNECT);
|
|
159
|
-
const cmd = [
|
|
160
|
-
"--logtostderr",
|
|
161
|
-
"-v=2",
|
|
162
|
-
"generate",
|
|
163
|
-
`--config_dir=${args.configDir}`,
|
|
164
|
-
`--connector_id=${args.connectorId}`,
|
|
165
|
-
];
|
|
158
|
+
const cmd = ["--logtostderr", "-v=2", "sdk", "generate", `--config_dir=${args.configDir}`];
|
|
166
159
|
if (args.watch) {
|
|
167
160
|
cmd.push("--watch");
|
|
168
161
|
}
|
|
169
162
|
const env = await DataConnectEmulator.getEnv(args.account);
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
163
|
+
return new Promise((resolve, reject) => {
|
|
164
|
+
try {
|
|
165
|
+
const proc = childProcess.spawn(commandInfo.binary, cmd, { stdio: "inherit", env });
|
|
166
|
+
proc.on("close", (code) => {
|
|
167
|
+
if (code === 0) {
|
|
168
|
+
resolve();
|
|
169
|
+
}
|
|
170
|
+
else {
|
|
171
|
+
reject(new Error(`Command failed with exit code ${code}`));
|
|
172
|
+
}
|
|
173
|
+
});
|
|
174
|
+
proc.on("error", (err) => {
|
|
175
|
+
reject(err);
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
catch (e) {
|
|
179
|
+
if ((0, downloadableEmulators_1.isIncomaptibleArchError)(e)) {
|
|
180
|
+
reject(new error_1.FirebaseError(`Unknown system error when running the Data Connect toolkit. ` +
|
|
181
|
+
`You may be able to fix this by installing Rosetta: ` +
|
|
182
|
+
`softwareupdate --install-rosetta`));
|
|
183
|
+
}
|
|
184
|
+
else {
|
|
185
|
+
reject(e);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
});
|
|
186
189
|
}
|
|
187
190
|
static async build(args) {
|
|
188
191
|
var _a;
|
|
@@ -341,11 +341,11 @@ class FunctionsEmulator {
|
|
|
341
341
|
const resolution = await (0, build_1.resolveBackend)({
|
|
342
342
|
build: discoveredBuild,
|
|
343
343
|
firebaseConfig: JSON.parse(firebaseConfig),
|
|
344
|
-
userEnvOpt,
|
|
345
344
|
userEnvs,
|
|
346
345
|
nonInteractive: false,
|
|
347
346
|
isEmulator: true,
|
|
348
347
|
});
|
|
348
|
+
functionsEnv.writeResolvedParams(resolution.envs, userEnvs, userEnvOpt);
|
|
349
349
|
const discoveredBackend = resolution.backend;
|
|
350
350
|
const endpoints = backend.allEndpoints(discoveredBackend);
|
|
351
351
|
(0, functionsEmulatorShared_1.prepareEndpoints)(endpoints);
|
package/lib/emulator/hub.js
CHANGED
|
@@ -10,7 +10,6 @@ const types_1 = require("./types");
|
|
|
10
10
|
const hubExport_1 = require("./hubExport");
|
|
11
11
|
const registry_1 = require("./registry");
|
|
12
12
|
const ExpressBasedEmulator_1 = require("./ExpressBasedEmulator");
|
|
13
|
-
const vsCodeUtils_1 = require("../vsCodeUtils");
|
|
14
13
|
const pkg = require("../../package.json");
|
|
15
14
|
class EmulatorHub extends ExpressBasedEmulator_1.ExpressBasedEmulator {
|
|
16
15
|
static readLocatorFile(projectId) {
|
|
@@ -20,9 +19,8 @@ class EmulatorHub extends ExpressBasedEmulator_1.ExpressBasedEmulator {
|
|
|
20
19
|
}
|
|
21
20
|
const data = fs.readFileSync(locatorPath, "utf8").toString();
|
|
22
21
|
const locator = JSON.parse(data);
|
|
23
|
-
if (
|
|
24
|
-
logger_1.logger.debug(`Found locator with
|
|
25
|
-
return undefined;
|
|
22
|
+
if (locator.version !== this.CLI_VERSION) {
|
|
23
|
+
logger_1.logger.debug(`Found emulator locator with different version: ${JSON.stringify(locator)}, CLI_VERSION: ${this.CLI_VERSION}`);
|
|
26
24
|
}
|
|
27
25
|
return locator;
|
|
28
26
|
}
|
package/lib/experiments.js
CHANGED
|
@@ -116,6 +116,11 @@ exports.ALL_EXPERIMENTS = experiments({
|
|
|
116
116
|
default: true,
|
|
117
117
|
public: false,
|
|
118
118
|
},
|
|
119
|
+
mcpalpha: {
|
|
120
|
+
shortDescription: "Opt-in to early MCP features before they're widely released.",
|
|
121
|
+
default: false,
|
|
122
|
+
public: true,
|
|
123
|
+
},
|
|
119
124
|
apptesting: {
|
|
120
125
|
shortDescription: "Adds experimental App Testing feature",
|
|
121
126
|
public: true,
|
package/lib/functions/env.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.loadFirebaseEnvs = exports.loadUserEnvs = exports.checkForDuplicateKeys = exports.writeUserEnvs = exports.hasUserEnvs = exports.parseStrict = exports.validateKey = exports.KeyValidationError = exports.parse = void 0;
|
|
3
|
+
exports.writeResolvedParams = exports.loadFirebaseEnvs = exports.loadUserEnvs = exports.checkForDuplicateKeys = exports.writeUserEnvs = exports.hasUserEnvs = exports.parseStrict = exports.validateKey = exports.KeyValidationError = exports.parse = void 0;
|
|
4
4
|
const clc = require("colorette");
|
|
5
5
|
const fs = require("fs");
|
|
6
6
|
const path = require("path");
|
|
@@ -250,3 +250,14 @@ function loadFirebaseEnvs(firebaseConfig, projectId) {
|
|
|
250
250
|
};
|
|
251
251
|
}
|
|
252
252
|
exports.loadFirebaseEnvs = loadFirebaseEnvs;
|
|
253
|
+
function writeResolvedParams(resolvedEnvs, userEnvs, userEnvOpt) {
|
|
254
|
+
const toWrite = {};
|
|
255
|
+
for (const paramName of Object.keys(resolvedEnvs)) {
|
|
256
|
+
const paramValue = resolvedEnvs[paramName];
|
|
257
|
+
if (!paramValue.internal && !Object.prototype.hasOwnProperty.call(userEnvs, paramName)) {
|
|
258
|
+
toWrite[paramName] = paramValue.toString();
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
writeUserEnvs(toWrite, userEnvOpt);
|
|
262
|
+
}
|
|
263
|
+
exports.writeResolvedParams = writeResolvedParams;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.newUniqueId = exports.toDNSCompatibleId = exports.
|
|
3
|
+
exports.newUniqueId = exports.toDNSCompatibleId = exports.actuate = exports.askQuestions = void 0;
|
|
4
4
|
const path_1 = require("path");
|
|
5
5
|
const clc = require("colorette");
|
|
6
6
|
const fs = require("fs-extra");
|
|
@@ -103,6 +103,15 @@ async function actuate(setup, config, options) {
|
|
|
103
103
|
flow: info.analyticsFlow,
|
|
104
104
|
});
|
|
105
105
|
}
|
|
106
|
+
if (info.appDescription) {
|
|
107
|
+
setup.instructions.push(`You can visualize the Data Connect Schema in Firebase Console:
|
|
108
|
+
|
|
109
|
+
https://console.firebase.google.com/project/${setup.projectId}/dataconnect/locations/${info.locationId}/services/${info.serviceId}/schema`);
|
|
110
|
+
}
|
|
111
|
+
if (!setup.isBillingEnabled) {
|
|
112
|
+
setup.instructions.push((0, freeTrial_1.upgradeInstructions)(setup.projectId || "your-firebase-project"));
|
|
113
|
+
}
|
|
114
|
+
setup.instructions.push(`Install the Data Connect VS Code Extensions. You can explore Data Connect Query on local pgLite and Cloud SQL Postgres Instance.`);
|
|
106
115
|
}
|
|
107
116
|
exports.actuate = actuate;
|
|
108
117
|
async function actuateWithInfo(setup, config, info, options) {
|
|
@@ -222,30 +231,6 @@ function schemasDeploySequence(projectId, info, schemaFiles, linkToCloudSql) {
|
|
|
222
231
|
},
|
|
223
232
|
];
|
|
224
233
|
}
|
|
225
|
-
async function postSetup(setup) {
|
|
226
|
-
var _a;
|
|
227
|
-
const info = (_a = setup.featureInfo) === null || _a === void 0 ? void 0 : _a.dataconnect;
|
|
228
|
-
if (!info) {
|
|
229
|
-
throw new Error("Data Connect feature RequiredInfo is not provided");
|
|
230
|
-
}
|
|
231
|
-
const instructions = [];
|
|
232
|
-
if (info.appDescription) {
|
|
233
|
-
instructions.push(`You can visualize the Data Connect Schema in Firebase Console:
|
|
234
|
-
|
|
235
|
-
https://console.firebase.google.com/project/${setup.projectId}/dataconnect/locations/${info.locationId}/services/${info.serviceId}/schema`);
|
|
236
|
-
}
|
|
237
|
-
if (!setup.isBillingEnabled) {
|
|
238
|
-
instructions.push((0, freeTrial_1.upgradeInstructions)(setup.projectId || "your-firebase-project"));
|
|
239
|
-
}
|
|
240
|
-
instructions.push(`Install the Data Connect VS Code Extensions. You can explore Data Connect Query on local pgLite and Cloud SQL Postgres Instance.`);
|
|
241
|
-
if (instructions.length) {
|
|
242
|
-
logger_1.logger.info(`\n${clc.bold("To get started with Firebase Data Connect:")}`);
|
|
243
|
-
for (const i of instructions) {
|
|
244
|
-
(0, utils_1.logBullet)(i + "\n");
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
exports.postSetup = postSetup;
|
|
249
234
|
async function writeFiles(config, info, serviceGql, options) {
|
|
250
235
|
const dir = config.get("dataconnect.source") || "dataconnect";
|
|
251
236
|
const subbedDataconnectYaml = subDataconnectYamlValues(Object.assign(Object.assign({}, info), { connectorDirs: serviceGql.connectors.map((c) => c.path) }));
|
|
@@ -153,7 +153,6 @@ async function actuateWithInfo(setup, config, info) {
|
|
|
153
153
|
const account = (0, auth_1.getGlobalDefaultAccount)();
|
|
154
154
|
await dataconnectEmulator_1.DataConnectEmulator.generate({
|
|
155
155
|
configDir: connectorInfo.directory,
|
|
156
|
-
connectorId: connectorInfo.connectorYaml.connectorId,
|
|
157
156
|
account,
|
|
158
157
|
});
|
|
159
158
|
(0, utils_1.logLabeledSuccess)("dataconnect", `Installed generated SDKs for ${clc.bold(apps.map((a) => (0, appFinder_1.appDescription)(a)).join(", "))}`);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.aitools = exports.apptestingAcutate = exports.apptestingAskQuestions = exports.genkit = exports.apphosting = exports.dataconnectSdkActuate = exports.dataconnectSdkAskQuestions = exports.
|
|
3
|
+
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.hosting = 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");
|
|
@@ -29,7 +29,6 @@ Object.defineProperty(exports, "hostingGithub", { enumerable: true, get: functio
|
|
|
29
29
|
var dataconnect_1 = require("./dataconnect");
|
|
30
30
|
Object.defineProperty(exports, "dataconnectAskQuestions", { enumerable: true, get: function () { return dataconnect_1.askQuestions; } });
|
|
31
31
|
Object.defineProperty(exports, "dataconnectActuate", { enumerable: true, get: function () { return dataconnect_1.actuate; } });
|
|
32
|
-
Object.defineProperty(exports, "dataconnectPostSetup", { enumerable: true, get: function () { return dataconnect_1.postSetup; } });
|
|
33
32
|
var sdk_1 = require("./dataconnect/sdk");
|
|
34
33
|
Object.defineProperty(exports, "dataconnectSdkAskQuestions", { enumerable: true, get: function () { return sdk_1.askQuestions; } });
|
|
35
34
|
Object.defineProperty(exports, "dataconnectSdkActuate", { enumerable: true, get: function () { return sdk_1.actuate; } });
|
package/lib/init/index.js
CHANGED
package/lib/mcp/index.js
CHANGED
|
@@ -154,7 +154,7 @@ class FirebaseMcpServer {
|
|
|
154
154
|
const emulators = await hubClient.getEmulators();
|
|
155
155
|
const emulatorInfo = emulators[emulatorType];
|
|
156
156
|
if (!emulatorInfo) {
|
|
157
|
-
throw Error(
|
|
157
|
+
throw Error(`No ${emulatorType} Emulator found running. Make sure your project firebase.json file includes ${emulatorType} and then rerun emulator using \`firebase emulators:start\` from your project directory.`);
|
|
158
158
|
}
|
|
159
159
|
const host = emulatorInfo.host.includes(":") ? `[${emulatorInfo.host}]` : emulatorInfo.host;
|
|
160
160
|
return `http://${host}:${emulatorInfo.port}`;
|
|
@@ -83,7 +83,7 @@ Follow the steps below taking note of any user instructions provided above.
|
|
|
83
83
|
Create \`firebase.json\ with an "apphosting" configuration, setting backendId to the app's name in package.json: \`{"apphosting": {"backendId": "<backendId>"}}\
|
|
84
84
|
4b. If the app does NOT require SSR, configure Firebase Hosting:
|
|
85
85
|
Create \`firebase.json\ with a "hosting" configuration. Add a \`{"hosting": {"predeploy": "<build_script>"}}\` config to build before deploying.
|
|
86
|
-
5. Check if there is an active Firebase project for this environment (the \`firebase_get_environment\` tool may be helpful). If there is, proceed using that project. If there is not an active project, give the user two options:
|
|
86
|
+
5. Check if there is an active Firebase project for this environment (the \`firebase_get_environment\` tool may be helpful). If there is, provide the active project ID to the user and ask them if they want to proceed using that project. If there is not an active project, give the user two options: Provide an existing project ID or create a new project. Only use the list_projects tool on user request. Wait for their response before proceeding.
|
|
87
87
|
5a. If the user chooses to use an existing Firebase project, the \`firebase_list_projects\` tool may be helpful. Set the selected project as the active project (the \`firebase_update_environment\` tool may be helpful).
|
|
88
88
|
5b. If the user chooses to create a new project, use the \`firebase_create_project \` tool. Then set the new project as the active project (the \`firebase_update_environment\` tool may be helpful).
|
|
89
89
|
6. If firebase.json contains an "apphosting" configuration, check if a backend exists matching the provided backendId (the \`apphosting_list_backends\` tool may be helpful).
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.dataconnectPrompts = void 0;
|
|
4
|
+
const experiments_1 = require("../../../experiments");
|
|
5
|
+
const schema_1 = require("./schema");
|
|
6
|
+
exports.dataconnectPrompts = [];
|
|
7
|
+
if ((0, experiments_1.isEnabled)("mcpalpha")) {
|
|
8
|
+
exports.dataconnectPrompts.push(schema_1.schema);
|
|
9
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.schema = void 0;
|
|
4
|
+
const prompt_1 = require("../../prompt");
|
|
5
|
+
const load_1 = require("../../../dataconnect/load");
|
|
6
|
+
const content_1 = require("../../util/dataconnect/content");
|
|
7
|
+
const compile_1 = require("../../util/dataconnect/compile");
|
|
8
|
+
function renderServices(fdcServices) {
|
|
9
|
+
var _a;
|
|
10
|
+
if (!fdcServices.length)
|
|
11
|
+
return "Data Connect Status: <UNCONFIGURED>";
|
|
12
|
+
return `\n\n## Data Connect Schema
|
|
13
|
+
|
|
14
|
+
The following is the up-to-date content of existing schema files (their paths are relative to the Data Connect source directory).
|
|
15
|
+
|
|
16
|
+
${(_a = fdcServices[0].schema.source.files) === null || _a === void 0 ? void 0 : _a.map((f) => `\`\`\`graphql ${f.path}\n${f.content}\n\`\`\``).join("\n\n")}`;
|
|
17
|
+
}
|
|
18
|
+
function renderErrors(errors) {
|
|
19
|
+
return `\n\n## Current Schema Build Errors\n\n${errors || "<NO ERRORS>"}`;
|
|
20
|
+
}
|
|
21
|
+
exports.schema = (0, prompt_1.prompt)({
|
|
22
|
+
name: "schema",
|
|
23
|
+
description: "Generate or update your Firebase Data Connect schema.",
|
|
24
|
+
arguments: [
|
|
25
|
+
{
|
|
26
|
+
name: "prompt",
|
|
27
|
+
description: "describe the schema you want generated or the edits you want to make to your existing schema",
|
|
28
|
+
required: true,
|
|
29
|
+
},
|
|
30
|
+
],
|
|
31
|
+
annotations: {
|
|
32
|
+
title: "Generate Data Connect Schema",
|
|
33
|
+
},
|
|
34
|
+
}, async ({ prompt }, { config, projectId, accountEmail }) => {
|
|
35
|
+
const fdcServices = await (0, load_1.loadAll)(projectId, config);
|
|
36
|
+
const buildErrors = fdcServices.length
|
|
37
|
+
? await (0, compile_1.compileErrors)(fdcServices[0].sourceDirectory)
|
|
38
|
+
: "";
|
|
39
|
+
return [
|
|
40
|
+
{
|
|
41
|
+
role: "user",
|
|
42
|
+
content: {
|
|
43
|
+
type: "text",
|
|
44
|
+
text: `
|
|
45
|
+
${content_1.MAIN_INSTRUCTIONS}\n\n${content_1.BUILTIN_SDL}
|
|
46
|
+
|
|
47
|
+
==== CURRENT ENVIRONMENT INFO ====
|
|
48
|
+
|
|
49
|
+
User Email: ${accountEmail || "<NONE>"}
|
|
50
|
+
Project ID: ${projectId || "<NONE>"}
|
|
51
|
+
${renderServices(fdcServices)}${renderErrors(buildErrors)}
|
|
52
|
+
|
|
53
|
+
==== USER PROMPT ====
|
|
54
|
+
|
|
55
|
+
${prompt}
|
|
56
|
+
|
|
57
|
+
==== TASK INSTRUCTIONS ====
|
|
58
|
+
|
|
59
|
+
1. If Data Connect is marked as \`<UNCONFIGURED>\`, first run the \`firebase_init\` tool with \`{dataconnect: {}}\` arguments to initialize it.
|
|
60
|
+
2. If there is not an existing schema to work with (or the existing schema is the commented-out default schema about a movie app), follow the user's prompt to generate a robust schema meeting the specified requirements.
|
|
61
|
+
3. If there is already a schema, perform edits to the existing schema file(s) based on the user's instructions. If schema build errors are present and seem relevant to your changes, attempt to fix them.
|
|
62
|
+
4. After you have performed edits on the schema, run the \`dataconnect_compile\` tool to build the schema and see if there are any errors. Fix errors that are related to the user's prompt or your changes.
|
|
63
|
+
5. If there are errors, attempt to fix them. If you have attempted to fix them 3 times without success, ask the user for help.
|
|
64
|
+
6. If there are no errors, write a brief paragraph summarizing your changes.`,
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
];
|
|
68
|
+
});
|
package/lib/mcp/prompts/index.js
CHANGED
|
@@ -2,12 +2,13 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.availablePrompts = void 0;
|
|
4
4
|
const core_1 = require("./core");
|
|
5
|
+
const dataconnect_1 = require("./dataconnect");
|
|
5
6
|
const crashlytics_1 = require("./crashlytics");
|
|
6
7
|
const prompts = {
|
|
7
8
|
core: core_1.corePrompts,
|
|
8
9
|
firestore: [],
|
|
9
10
|
storage: [],
|
|
10
|
-
dataconnect:
|
|
11
|
+
dataconnect: dataconnect_1.dataconnectPrompts,
|
|
11
12
|
auth: [],
|
|
12
13
|
messaging: [],
|
|
13
14
|
remoteconfig: [],
|
|
@@ -149,10 +149,19 @@ exports.init = (0, tool_1.tool)({
|
|
|
149
149
|
projectId: projectId,
|
|
150
150
|
features: [...featuresList],
|
|
151
151
|
featureInfo: featureInfo,
|
|
152
|
+
instructions: [],
|
|
152
153
|
};
|
|
153
154
|
await (0, index_1.actuate)(setup, config, { force: true });
|
|
154
155
|
config.writeProjectFile("firebase.json", setup.config);
|
|
155
156
|
config.writeProjectFile(".firebaserc", setup.rcfile);
|
|
156
|
-
|
|
157
|
-
|
|
157
|
+
if (featureInfo.dataconnectSdk && !featureInfo.dataconnectSdk.apps.length) {
|
|
158
|
+
setup.instructions.push(`No app is found in the current folder. We recommend you create an app (web, ios, android) first, then re-run the 'firebase_init' MCP tool to add Data Connect SDKs to your apps.
|
|
159
|
+
Consider popular commands like 'npx create-react-app my-app', 'npx create-next-app my-app', 'flutter create my-app', etc`);
|
|
160
|
+
}
|
|
161
|
+
return (0, util_1.toContent)(`Successfully setup those features: ${featuresList.join(", ")}
|
|
162
|
+
|
|
163
|
+
To get started:
|
|
164
|
+
|
|
165
|
+
- ${setup.instructions.join("\n\n- ")}
|
|
166
|
+
`);
|
|
158
167
|
});
|