firebase-tools 14.15.1 → 14.16.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/dataconnect-sdk-generate.js +28 -24
- 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/dataconnect/ensureApis.js +3 -3
- package/lib/deploy/functions/build.js +2 -13
- package/lib/deploy/functions/deploy.js +4 -3
- package/lib/deploy/functions/prepare.js +10 -7
- package/lib/deploy/functions/runtimes/discovery/index.js +1 -1
- package/lib/emulator/auth/operations.js +10 -1
- package/lib/emulator/commandUtils.js +7 -1
- package/lib/emulator/controller.js +15 -31
- package/lib/emulator/dataconnectEmulator.js +27 -24
- package/lib/emulator/downloadableEmulatorInfo.json +18 -18
- package/lib/emulator/functionsEmulator.js +1 -1
- package/lib/emulator/hub.js +9 -5
- 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/env.js +12 -1
- 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 +72 -56
- package/lib/init/features/dataconnect/sdk.js +23 -11
- package/lib/mcp/errors.js +2 -10
- package/lib/mcp/index.js +1 -4
- package/lib/mcp/prompts/core/deploy.js +1 -1
- 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/dataconnect/execute.js +71 -0
- package/lib/mcp/tools/dataconnect/index.js +3 -13
- package/lib/mcp/tools/dataconnect/list_services.js +104 -7
- package/lib/mcp/util.js +1 -17
- package/lib/serve/functions.js +4 -3
- package/lib/track.js +16 -0
- 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/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/database/set_rules.js +0 -41
- 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
|
@@ -98,7 +98,7 @@ exports.filterEmulatorTargets = filterEmulatorTargets;
|
|
|
98
98
|
function shouldStart(options, name) {
|
|
99
99
|
var _a, _b;
|
|
100
100
|
if (name === types_1.Emulators.HUB) {
|
|
101
|
-
return
|
|
101
|
+
return true;
|
|
102
102
|
}
|
|
103
103
|
const targets = filterEmulatorTargets(options);
|
|
104
104
|
const emulatorInTargets = targets.includes(name);
|
|
@@ -109,7 +109,7 @@ function shouldStart(options, name) {
|
|
|
109
109
|
if (((_b = (_a = options.config.src.emulators) === null || _a === void 0 ? void 0 : _a.ui) === null || _b === void 0 ? void 0 : _b.enabled) === false) {
|
|
110
110
|
return false;
|
|
111
111
|
}
|
|
112
|
-
return
|
|
112
|
+
return targets.some((target) => types_1.EMULATORS_SUPPORTED_BY_UI.includes(target));
|
|
113
113
|
}
|
|
114
114
|
if (name === types_1.Emulators.FUNCTIONS && emulatorInTargets) {
|
|
115
115
|
try {
|
|
@@ -188,7 +188,7 @@ async function startAll(options, showUI = true, runningTestScript = false) {
|
|
|
188
188
|
}
|
|
189
189
|
const hubLogger = emulatorLogger_1.EmulatorLogger.forEmulator(types_1.Emulators.HUB);
|
|
190
190
|
hubLogger.logLabeled("BULLET", "emulators", `Starting emulators: ${targets.join(", ")}`);
|
|
191
|
-
const projectId = (0, projectUtils_1.getProjectId)(options) ||
|
|
191
|
+
const projectId = (0, projectUtils_1.getProjectId)(options) || hub_1.EmulatorHub.MISSING_PROJECT_PLACEHOLDER;
|
|
192
192
|
const isDemoProject = constants_1.Constants.isDemoProject(projectId);
|
|
193
193
|
if (isDemoProject) {
|
|
194
194
|
hubLogger.logLabeled("BULLET", "emulators", `Detected demo project ID "${projectId}", emulated services will use a demo configuration and attempts to access non-emulated services for this project will fail.`);
|
|
@@ -340,7 +340,8 @@ async function startAll(options, showUI = true, runningTestScript = false) {
|
|
|
340
340
|
const functionsCfg = (0, projectConfig_1.normalizeAndValidate)(options.config.src.functions);
|
|
341
341
|
utils.assertIsStringOrUndefined(options.extDevDir);
|
|
342
342
|
for (const cfg of functionsCfg) {
|
|
343
|
-
const
|
|
343
|
+
const localCfg = (0, projectConfig_1.requireLocal)(cfg, "Remote sources are not supported in the Functions emulator.");
|
|
344
|
+
const functionsDir = path.join(projectDir, localCfg.source);
|
|
344
345
|
const runtime = ((_g = options.extDevRuntime) !== null && _g !== void 0 ? _g : cfg.runtime);
|
|
345
346
|
if (runtime && !(0, supported_1.isRuntime)(runtime)) {
|
|
346
347
|
throw new error_1.FirebaseError(`Cannot load functions from ${functionsDir} because it has invalid runtime ${runtime}`);
|
|
@@ -348,14 +349,14 @@ async function startAll(options, showUI = true, runningTestScript = false) {
|
|
|
348
349
|
const backend = {
|
|
349
350
|
functionsDir,
|
|
350
351
|
runtime,
|
|
351
|
-
codebase:
|
|
352
|
-
prefix:
|
|
352
|
+
codebase: localCfg.codebase,
|
|
353
|
+
prefix: localCfg.prefix,
|
|
353
354
|
env: Object.assign({}, options.extDevEnv),
|
|
354
355
|
secretEnv: [],
|
|
355
356
|
predefinedTriggers: options.extDevTriggers,
|
|
356
|
-
ignore:
|
|
357
|
+
ignore: localCfg.ignore,
|
|
357
358
|
};
|
|
358
|
-
proto.convertIfPresent(backend,
|
|
359
|
+
proto.convertIfPresent(backend, localCfg, "configDir", (cd) => path.join(projectDir, cd));
|
|
359
360
|
emulatableBackends.push(backend);
|
|
360
361
|
}
|
|
361
362
|
}
|
|
@@ -372,7 +373,6 @@ async function startAll(options, showUI = true, runningTestScript = false) {
|
|
|
372
373
|
}
|
|
373
374
|
const functionsLogger = emulatorLogger_1.EmulatorLogger.forEmulator(types_1.Emulators.FUNCTIONS);
|
|
374
375
|
const functionsAddr = legacyGetFirstAddr(types_1.Emulators.FUNCTIONS);
|
|
375
|
-
const projectId = (0, projectUtils_1.needProjectId)(options);
|
|
376
376
|
const inspectFunctions = commandUtils.parseInspectionPort(options);
|
|
377
377
|
if (inspectFunctions) {
|
|
378
378
|
functionsLogger.logLabeled("WARN", "functions", `You are running the Functions emulator in debug mode. This means that functions will execute in sequence rather than in parallel.`);
|
|
@@ -461,13 +461,8 @@ async function startAll(options, showUI = true, runningTestScript = false) {
|
|
|
461
461
|
firestoreLogger.logLabeled("WARN", "firestore", "The emulator will default to allowing all reads and writes. Learn more about this option: https://firebase.google.com/docs/emulator-suite/install_and_configure#security_rules_configuration.");
|
|
462
462
|
}
|
|
463
463
|
if (singleProjectModeEnabled) {
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
args.single_project_mode_error = false;
|
|
467
|
-
}
|
|
468
|
-
else {
|
|
469
|
-
firestoreLogger.logLabeled("DEBUG", "firestore", "Could not enable single_project_mode: missing projectId.");
|
|
470
|
-
}
|
|
464
|
+
args.single_project_mode = true;
|
|
465
|
+
args.single_project_mode_error = false;
|
|
471
466
|
}
|
|
472
467
|
const firestoreEmulator = new firestoreEmulator_1.FirestoreEmulator(args);
|
|
473
468
|
await startEmulator(firestoreEmulator);
|
|
@@ -525,9 +520,6 @@ async function startAll(options, showUI = true, runningTestScript = false) {
|
|
|
525
520
|
}
|
|
526
521
|
}
|
|
527
522
|
if (listenForEmulator.auth) {
|
|
528
|
-
if (!projectId) {
|
|
529
|
-
throw new error_1.FirebaseError(`Cannot start the ${constants_1.Constants.description(types_1.Emulators.AUTH)} without a project: run 'firebase init' or provide the --project flag`);
|
|
530
|
-
}
|
|
531
523
|
const authAddr = legacyGetFirstAddr(types_1.Emulators.AUTH);
|
|
532
524
|
const authEmulator = new auth_2.AuthEmulator({
|
|
533
525
|
host: authAddr.host,
|
|
@@ -546,9 +538,6 @@ async function startAll(options, showUI = true, runningTestScript = false) {
|
|
|
546
538
|
}
|
|
547
539
|
}
|
|
548
540
|
if (listenForEmulator.pubsub) {
|
|
549
|
-
if (!projectId) {
|
|
550
|
-
throw new error_1.FirebaseError("Cannot start the Pub/Sub emulator without a project: run 'firebase init' or provide the --project flag");
|
|
551
|
-
}
|
|
552
541
|
const pubsubAddr = legacyGetFirstAddr(types_1.Emulators.PUBSUB);
|
|
553
542
|
const pubsubEmulator = new pubsubEmulator_1.PubsubEmulator({
|
|
554
543
|
host: pubsubAddr.host,
|
|
@@ -571,7 +560,6 @@ async function startAll(options, showUI = true, runningTestScript = false) {
|
|
|
571
560
|
projectId,
|
|
572
561
|
auto_download: true,
|
|
573
562
|
configDir: config[0].source,
|
|
574
|
-
rc: options.rc,
|
|
575
563
|
config: options.config,
|
|
576
564
|
autoconnectToPostgres: true,
|
|
577
565
|
postgresListen: listenForEmulator["dataconnect.postgres"],
|
|
@@ -612,7 +600,7 @@ async function startAll(options, showUI = true, runningTestScript = false) {
|
|
|
612
600
|
const storageEmulator = new storage_1.StorageEmulator({
|
|
613
601
|
host: storageAddr.host,
|
|
614
602
|
port: storageAddr.port,
|
|
615
|
-
projectId
|
|
603
|
+
projectId,
|
|
616
604
|
rules: (0, config_1.getStorageRulesConfig)(projectId, options),
|
|
617
605
|
});
|
|
618
606
|
await startEmulator(storageEmulator);
|
|
@@ -671,13 +659,12 @@ async function startAll(options, showUI = true, runningTestScript = false) {
|
|
|
671
659
|
await startEmulator(loggingEmulator);
|
|
672
660
|
}
|
|
673
661
|
if (showUI && !shouldStart(options, types_1.Emulators.UI)) {
|
|
674
|
-
hubLogger.logLabeled("WARN", "emulators", "The Emulator UI is not starting
|
|
675
|
-
"emulators have a UI component
|
|
676
|
-
"determine the Project ID. Pass the --project flag to specify a project.");
|
|
662
|
+
hubLogger.logLabeled("WARN", "emulators", "The Emulator UI is not starting because none of the running " +
|
|
663
|
+
"emulators have a UI component.");
|
|
677
664
|
}
|
|
678
665
|
if (listenForEmulator.ui) {
|
|
679
666
|
const ui = new ui_1.EmulatorUI({
|
|
680
|
-
projectId
|
|
667
|
+
projectId,
|
|
681
668
|
listen: listenForEmulator[types_1.Emulators.UI],
|
|
682
669
|
});
|
|
683
670
|
await startEmulator(ui);
|
|
@@ -726,9 +713,6 @@ function getListenConfig(options, emulator) {
|
|
|
726
713
|
}
|
|
727
714
|
async function exportEmulatorData(exportPath, options, initiatedBy) {
|
|
728
715
|
const projectId = options.project;
|
|
729
|
-
if (!projectId) {
|
|
730
|
-
throw new error_1.FirebaseError("Could not determine project ID, make sure you're running in a Firebase project directory or add the --project flag.", { exit: 1 });
|
|
731
|
-
}
|
|
732
716
|
const hubClient = new hubClient_1.EmulatorHubClient(projectId);
|
|
733
717
|
if (!hubClient.foundHub()) {
|
|
734
718
|
throw new error_1.FirebaseError(`Did not find any running emulators for project ${clc.bold(projectId)}.`, { exit: 1 });
|
|
@@ -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;
|
|
@@ -54,28 +54,28 @@
|
|
|
54
54
|
},
|
|
55
55
|
"dataconnect": {
|
|
56
56
|
"darwin": {
|
|
57
|
-
"version": "2.
|
|
58
|
-
"expectedSize":
|
|
59
|
-
"expectedChecksum": "
|
|
60
|
-
"expectedChecksumSHA256": "
|
|
61
|
-
"remoteUrl": "https://storage.googleapis.com/firemat-preview-drop/emulator/dataconnect-emulator-macos-v2.
|
|
62
|
-
"downloadPathRelativeToCacheDir": "dataconnect-emulator-2.
|
|
57
|
+
"version": "2.13.0",
|
|
58
|
+
"expectedSize": 29475680,
|
|
59
|
+
"expectedChecksum": "8bceed44e84d08f135ad10b8b62337e9",
|
|
60
|
+
"expectedChecksumSHA256": "92e0cda1a3fd690421cae4edd7d985e5c5de7069e731ad200ba6988c2321d76c",
|
|
61
|
+
"remoteUrl": "https://storage.googleapis.com/firemat-preview-drop/emulator/dataconnect-emulator-macos-v2.13.0",
|
|
62
|
+
"downloadPathRelativeToCacheDir": "dataconnect-emulator-2.13.0"
|
|
63
63
|
},
|
|
64
64
|
"win32": {
|
|
65
|
-
"version": "2.
|
|
66
|
-
"expectedSize":
|
|
67
|
-
"expectedChecksum": "
|
|
68
|
-
"expectedChecksumSHA256": "
|
|
69
|
-
"remoteUrl": "https://storage.googleapis.com/firemat-preview-drop/emulator/dataconnect-emulator-windows-v2.
|
|
70
|
-
"downloadPathRelativeToCacheDir": "dataconnect-emulator-2.
|
|
65
|
+
"version": "2.13.0",
|
|
66
|
+
"expectedSize": 29965312,
|
|
67
|
+
"expectedChecksum": "67794a3cb334805a06fffd872be7d67c",
|
|
68
|
+
"expectedChecksumSHA256": "2905c570d40e586dd1ca0aeee10785786dc0486500640064e4e1e43be3b97899",
|
|
69
|
+
"remoteUrl": "https://storage.googleapis.com/firemat-preview-drop/emulator/dataconnect-emulator-windows-v2.13.0",
|
|
70
|
+
"downloadPathRelativeToCacheDir": "dataconnect-emulator-2.13.0.exe"
|
|
71
71
|
},
|
|
72
72
|
"linux": {
|
|
73
|
-
"version": "2.
|
|
74
|
-
"expectedSize":
|
|
75
|
-
"expectedChecksum": "
|
|
76
|
-
"expectedChecksumSHA256": "
|
|
77
|
-
"remoteUrl": "https://storage.googleapis.com/firemat-preview-drop/emulator/dataconnect-emulator-linux-v2.
|
|
78
|
-
"downloadPathRelativeToCacheDir": "dataconnect-emulator-2.
|
|
73
|
+
"version": "2.13.0",
|
|
74
|
+
"expectedSize": 29401272,
|
|
75
|
+
"expectedChecksum": "d72e185be8b782b8d4bca86d6bc76d2d",
|
|
76
|
+
"expectedChecksumSHA256": "87cb9541f157c3e9986b6eba80d161e6ef1debd17075e4d95e78861d3cdd353f",
|
|
77
|
+
"remoteUrl": "https://storage.googleapis.com/firemat-preview-drop/emulator/dataconnect-emulator-linux-v2.13.0",
|
|
78
|
+
"downloadPathRelativeToCacheDir": "dataconnect-emulator-2.13.0"
|
|
79
79
|
}
|
|
80
80
|
}
|
|
81
81
|
}
|
|
@@ -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,16 +19,20 @@ 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
|
}
|
|
29
27
|
static getLocatorFilePath(projectId) {
|
|
30
28
|
const dir = os.tmpdir();
|
|
29
|
+
if (!projectId) {
|
|
30
|
+
projectId = EmulatorHub.MISSING_PROJECT_PLACEHOLDER;
|
|
31
|
+
}
|
|
31
32
|
const filename = `hub-${projectId}.json`;
|
|
32
|
-
|
|
33
|
+
const locatorPath = path.join(dir, filename);
|
|
34
|
+
logger_1.logger.debug(`Emulator locator file path: ${locatorPath}`);
|
|
35
|
+
return locatorPath;
|
|
33
36
|
}
|
|
34
37
|
constructor(args) {
|
|
35
38
|
super({
|
|
@@ -179,6 +182,7 @@ class EmulatorHub extends ExpressBasedEmulator_1.ExpressBasedEmulator {
|
|
|
179
182
|
}
|
|
180
183
|
}
|
|
181
184
|
exports.EmulatorHub = EmulatorHub;
|
|
185
|
+
EmulatorHub.MISSING_PROJECT_PLACEHOLDER = "demo-no-project";
|
|
182
186
|
EmulatorHub.CLI_VERSION = pkg.version;
|
|
183
187
|
EmulatorHub.PATH_EXPORT = "/_admin/export";
|
|
184
188
|
EmulatorHub.PATH_DISABLE_FUNCTIONS = "/functions/disableBackgroundTriggers";
|
|
@@ -135,13 +135,14 @@ exports.copyDirectory = copyDirectory;
|
|
|
135
135
|
async function getCodebaseRuntime(options) {
|
|
136
136
|
const config = (0, projectConfig_1.normalizeAndValidate)(options.config.src.functions);
|
|
137
137
|
const codebaseConfig = (0, projectConfig_1.configForCodebase)(config, options.codebase || projectConfig_1.DEFAULT_CODEBASE);
|
|
138
|
-
const
|
|
138
|
+
const localCfg = (0, projectConfig_1.requireLocal)(codebaseConfig);
|
|
139
|
+
const sourceDirName = localCfg.source;
|
|
139
140
|
const sourceDir = options.config.path(sourceDirName);
|
|
140
141
|
const delegateContext = {
|
|
141
142
|
projectId: "",
|
|
142
143
|
sourceDir,
|
|
143
144
|
projectDir: options.config.projectDir,
|
|
144
|
-
runtime:
|
|
145
|
+
runtime: localCfg.runtime,
|
|
145
146
|
};
|
|
146
147
|
let delegate;
|
|
147
148
|
try {
|
package/lib/firestore/api.js
CHANGED
|
@@ -544,6 +544,19 @@ class FirestoreApi {
|
|
|
544
544
|
}
|
|
545
545
|
return database;
|
|
546
546
|
}
|
|
547
|
+
async bulkDeleteDocuments(project, databaseId, collectionIds) {
|
|
548
|
+
var _a;
|
|
549
|
+
const name = `/projects/${project}/databases/${databaseId}`;
|
|
550
|
+
const url = `${name}:bulkDeleteDocuments`;
|
|
551
|
+
const payload = {
|
|
552
|
+
name,
|
|
553
|
+
collectionIds,
|
|
554
|
+
};
|
|
555
|
+
const res = await this.apiClient.post(url, payload);
|
|
556
|
+
return {
|
|
557
|
+
name: (_a = res.body) === null || _a === void 0 ? void 0 : _a.name,
|
|
558
|
+
};
|
|
559
|
+
}
|
|
547
560
|
async restoreDatabase(project, databaseId, backupName, encryptionConfig) {
|
|
548
561
|
const url = `/projects/${project}/databases:restore`;
|
|
549
562
|
const payload = {
|
|
@@ -559,5 +572,37 @@ class FirestoreApi {
|
|
|
559
572
|
}
|
|
560
573
|
return database;
|
|
561
574
|
}
|
|
575
|
+
async listOperations(project, databaseId, limit) {
|
|
576
|
+
const url = `/projects/${project}/databases/${databaseId}/operations`;
|
|
577
|
+
const res = await this.apiClient.get(url, {
|
|
578
|
+
queryParams: {
|
|
579
|
+
pageSize: limit,
|
|
580
|
+
},
|
|
581
|
+
});
|
|
582
|
+
return res.body;
|
|
583
|
+
}
|
|
584
|
+
async describeOperation(project, databaseId, operationName) {
|
|
585
|
+
const url = `/projects/${project}/databases/${databaseId}/operations/${operationName}`;
|
|
586
|
+
const res = await this.apiClient.get(url);
|
|
587
|
+
return res.body;
|
|
588
|
+
}
|
|
589
|
+
async cancelOperation(project, databaseId, operationName) {
|
|
590
|
+
var _a, _b, _c, _d;
|
|
591
|
+
const url = `/projects/${project}/databases/${databaseId}/operations/${operationName}:cancel`;
|
|
592
|
+
try {
|
|
593
|
+
const res = await this.apiClient.post(url);
|
|
594
|
+
return { success: res.status === 200 };
|
|
595
|
+
}
|
|
596
|
+
catch (error) {
|
|
597
|
+
const reason = "Cannot cancel an operation that is completed.";
|
|
598
|
+
const details = ((_c = (_b = (_a = error.context) === null || _a === void 0 ? void 0 : _a.body) === null || _b === void 0 ? void 0 : _b.error) === null || _c === void 0 ? void 0 : _c.details) || [];
|
|
599
|
+
for (const detail of details) {
|
|
600
|
+
if ((_d = detail.detail) === null || _d === void 0 ? void 0 : _d.includes(reason)) {
|
|
601
|
+
throw new error_1.FirebaseError(reason);
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
throw error;
|
|
605
|
+
}
|
|
606
|
+
}
|
|
562
607
|
}
|
|
563
608
|
exports.FirestoreApi = FirestoreApi;
|
|
@@ -120,6 +120,29 @@ class PrettyPrint {
|
|
|
120
120
|
table.push(["Name", clc.yellow(backup.name)], ["Database", clc.yellow(backup.database)], ["Database UID", clc.yellow(backup.databaseUid)], ["State", clc.yellow(backup.state)], ["Snapshot Time", clc.yellow(backup.snapshotTime)], ["Expire Time", clc.yellow(backup.expireTime)], ["Stats", clc.yellow(backup.stats)]);
|
|
121
121
|
logger_1.logger.info(table.toString());
|
|
122
122
|
}
|
|
123
|
+
prettyPrintOperation(operation) {
|
|
124
|
+
const table = new Table({
|
|
125
|
+
head: ["Operation", ""],
|
|
126
|
+
});
|
|
127
|
+
table.push(["Name", clc.yellow(operation.name)], ["Done?", clc.yellow(operation.done ? "YES" : "NO")], ["Metadata", clc.yellow(JSON.stringify(operation.metadata, undefined, 2))]);
|
|
128
|
+
if (operation.response) {
|
|
129
|
+
table.push(["Response", clc.yellow(JSON.stringify(operation.response, undefined, 2))]);
|
|
130
|
+
}
|
|
131
|
+
logger_1.logger.info(table.toString());
|
|
132
|
+
}
|
|
133
|
+
prettyPrintOperations(operations) {
|
|
134
|
+
if (operations.length === 0) {
|
|
135
|
+
logger_1.logger.info("No operations found.");
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
const table = new Table({
|
|
139
|
+
head: ["Operation Name", "Done"],
|
|
140
|
+
});
|
|
141
|
+
for (const op of operations) {
|
|
142
|
+
table.push([clc.yellow(op.name), op.done ? clc.green("YES") : clc.yellow("NO")]);
|
|
143
|
+
}
|
|
144
|
+
logger_1.logger.info(table.toString());
|
|
145
|
+
}
|
|
123
146
|
prettyPrintLocations(locations) {
|
|
124
147
|
if (locations.length === 0) {
|
|
125
148
|
logger_1.logger.info("No Locations Available");
|
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,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",
|