firebase-tools 15.18.0 → 15.19.1

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.
@@ -40,10 +40,16 @@ const PROVIDER_ID_INDEX_MAP = new Map([
40
40
  ["facebook.com", 11],
41
41
  ["twitter.com", 15],
42
42
  ["github.com", 19],
43
+ ["apple.com", 28],
44
+ ["microsoft.com", 32],
45
+ ["gc.apple.com", 36],
46
+ ["playgames.google.com", 40],
47
+ ["linkedin.com", 44],
48
+ ["yahoo.com", 48],
43
49
  ]);
44
- function escapeComma(str) {
45
- if (str.includes(",")) {
46
- return `"${str}"`;
50
+ function escapeCsv(str) {
51
+ if (str.includes(",") || str.includes('"') || str.includes("\n") || str.includes("\r")) {
52
+ return `"${str.replace(/"/g, '""')}"`;
47
53
  }
48
54
  return str;
49
55
  }
@@ -53,17 +59,18 @@ function convertToNormalBase64(data) {
53
59
  function addProviderUserInfo(providerInfo, arr, startPos) {
54
60
  arr[startPos] = providerInfo.rawId;
55
61
  arr[startPos + 1] = providerInfo.email || "";
56
- arr[startPos + 2] = escapeComma(providerInfo.displayName || "");
62
+ arr[startPos + 2] = escapeCsv(providerInfo.displayName || "");
57
63
  arr[startPos + 3] = providerInfo.photoUrl || "";
58
64
  }
59
65
  function transUserToArray(user) {
60
- const arr = Array(27).fill("");
66
+ const arrLength = Math.max(...PROVIDER_ID_INDEX_MAP.values()) + 4;
67
+ const arr = Array(arrLength).fill("");
61
68
  arr[0] = user.localId;
62
69
  arr[1] = user.email || "";
63
70
  arr[2] = user.emailVerified || false;
64
71
  arr[3] = convertToNormalBase64(user.passwordHash || "");
65
72
  arr[4] = convertToNormalBase64(user.salt || "");
66
- arr[5] = escapeComma(user.displayName || "");
73
+ arr[5] = escapeCsv(user.displayName || "");
67
74
  arr[6] = user.photoUrl || "";
68
75
  for (let i = 0; i < (!user.providerUserInfo ? 0 : user.providerUserInfo.length); i++) {
69
76
  const providerInfo = user.providerUserInfo[i];
@@ -32,7 +32,18 @@ const ALLOWED_JSON_KEYS_RENAMING = {
32
32
  lastSignedInAt: "lastLoginAt",
33
33
  };
34
34
  const ALLOWED_PROVIDER_USER_INFO_KEYS = ["providerId", "rawId", "email", "displayName", "photoUrl"];
35
- const ALLOWED_PROVIDER_IDS = ["google.com", "facebook.com", "twitter.com", "github.com"];
35
+ const ALLOWED_PROVIDER_IDS = [
36
+ "google.com",
37
+ "facebook.com",
38
+ "twitter.com",
39
+ "github.com",
40
+ "apple.com",
41
+ "microsoft.com",
42
+ "gc.apple.com",
43
+ "playgames.google.com",
44
+ "linkedin.com",
45
+ "yahoo.com",
46
+ ];
36
47
  function isValidBase64(str) {
37
48
  const expected = Buffer.from(str, "base64").toString("base64");
38
49
  if (str.length < expected.length && !str.endsWith("=")) {
@@ -125,6 +136,12 @@ function transArrayToUser(arr) {
125
136
  addProviderUserInfo(user, "facebook.com", arr.slice(11, 15));
126
137
  addProviderUserInfo(user, "twitter.com", arr.slice(15, 19));
127
138
  addProviderUserInfo(user, "github.com", arr.slice(19, 23));
139
+ addProviderUserInfo(user, "apple.com", arr.slice(28, 32));
140
+ addProviderUserInfo(user, "microsoft.com", arr.slice(32, 36));
141
+ addProviderUserInfo(user, "gc.apple.com", arr.slice(36, 40));
142
+ addProviderUserInfo(user, "playgames.google.com", arr.slice(40, 44));
143
+ addProviderUserInfo(user, "linkedin.com", arr.slice(44, 48));
144
+ addProviderUserInfo(user, "yahoo.com", arr.slice(48, 52));
128
145
  if (user.passwordHash && !isValidBase64(user.passwordHash)) {
129
146
  return {
130
147
  error: "Password hash should be base64 encoded.",
@@ -17,11 +17,12 @@ async function installAgentSkills(options) {
17
17
  if (!utils.commandExistsSync("npx")) {
18
18
  return;
19
19
  }
20
+ const skillPackage = options.skillPackage || "firebase/agent-skills";
20
21
  const args = [
21
22
  "-y",
22
23
  "skills",
23
24
  "add",
24
- "firebase/agent-skills",
25
+ skillPackage,
25
26
  "--skill",
26
27
  "*",
27
28
  "-y",
package/lib/api.js CHANGED
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.hostingApiOrigin = exports.firebaseStorageOrigin = exports.storageOrigin = exports.runtimeconfigOrigin = exports.rulesOrigin = exports.resourceManagerOrigin = exports.crashlyticsApiOrigin = exports.messagingApiOrigin = exports.remoteConfigApiOrigin = exports.rtdbMetadataOrigin = exports.rtdbManagementOrigin = exports.realtimeOrigin = exports.extensionsTOSOrigin = exports.extensionsPublisherOrigin = exports.extensionsOrigin = exports.iamOrigin = exports.identityOrigin = exports.hostingOrigin = exports.googleOrigin = exports.pubsubOrigin = exports.cloudTasksOrigin = exports.cloudschedulerOrigin = exports.cloudbuildOrigin = exports.functionsDefaultRegion = exports.runOrigin = exports.functionsV2Origin = exports.functionsOrigin = exports.firestoreOrigin = exports.firestoreOriginOrEmulator = exports.firedataOrigin = exports.firebaseExtensionsRegistryOrigin = exports.firebaseApiOrigin = exports.eventarcOrigin = exports.consoleOrigin = exports.authManagementOrigin = exports.authOrigin = exports.apphostingGitHubAppInstallationURL = exports.apphostingP4SADomain = exports.apphostingOrigin = exports.appDistributionOrigin = exports.artifactRegistryDomain = exports.developerConnectP4SADomain = exports.developerConnectOrigin = exports.containerRegistryDomain = exports.cloudMonitoringOrigin = exports.cloudloggingOrigin = exports.cloudbillingOrigin = exports.clientSecret = exports.clientId = exports.authProxyOrigin = void 0;
4
- exports.developerKnowledgeOrigin = exports.cloudTestingOrigin = exports.appTestingOrigin = exports.cloudAiCompanionOrigin = exports.aiLogicProxyOrigin = exports.vertexAIOrigin = exports.cloudSQLAdminOrigin = exports.dataConnectLocalConnString = exports.dataconnectP4SADomain = exports.dataconnectOrigin = exports.githubClientSecret = exports.githubClientId = exports.computeOrigin = exports.secretManagerOrigin = exports.githubApiOrigin = exports.githubOrigin = exports.studioApiOrigin = exports.serviceUsageOrigin = exports.cloudRunApiOrigin = void 0;
4
+ exports.developerKnowledgeOrigin = exports.cloudTestingOrigin = exports.appTestingOrigin = exports.aiLogicProxyOrigin = exports.vertexAIOrigin = exports.cloudSQLAdminOrigin = exports.dataConnectLocalConnString = exports.dataconnectP4SADomain = exports.dataconnectOrigin = exports.githubClientSecret = exports.githubClientId = exports.computeOrigin = exports.secretManagerOrigin = exports.githubApiOrigin = exports.githubOrigin = exports.studioApiOrigin = exports.serviceUsageOrigin = exports.cloudRunApiOrigin = void 0;
5
5
  exports.getScopes = getScopes;
6
6
  exports.setScopes = setScopes;
7
7
  const constants_1 = require("./emulator/constants");
@@ -144,8 +144,6 @@ const vertexAIOrigin = () => utils.envOverride("VERTEX_AI_URL", "https://aiplatf
144
144
  exports.vertexAIOrigin = vertexAIOrigin;
145
145
  const aiLogicProxyOrigin = () => utils.envOverride("AI_LOGIC_PROXY_URL", "https://firebasevertexai.googleapis.com");
146
146
  exports.aiLogicProxyOrigin = aiLogicProxyOrigin;
147
- const cloudAiCompanionOrigin = () => utils.envOverride("CLOUD_AI_COMPANION_URL", "https://cloudaicompanion.googleapis.com");
148
- exports.cloudAiCompanionOrigin = cloudAiCompanionOrigin;
149
147
  const appTestingOrigin = () => utils.envOverride("FIREBASE_APP_TESTING_URL", "https://firebaseapptesting.googleapis.com");
150
148
  exports.appTestingOrigin = appTestingOrigin;
151
149
  const cloudTestingOrigin = () => utils.envOverride("CLOUD_TESTING_URL", "https://testing.googleapis.com");
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ALLOWED_DEPLOY_METHODS = exports.DEFAULT_DEPLOY_METHOD = exports.DEFAULT_LOCATION = void 0;
3
+ exports.LOCAL_BUILD_DIR_NAME = exports.ALLOWED_DEPLOY_METHODS = exports.DEFAULT_DEPLOY_METHOD = exports.DEFAULT_LOCATION = void 0;
4
4
  exports.DEFAULT_LOCATION = "us-east4";
5
5
  exports.DEFAULT_DEPLOY_METHOD = "github";
6
6
  exports.ALLOWED_DEPLOY_METHODS = [{ name: "Deploy using github", value: "github" }];
7
+ exports.LOCAL_BUILD_DIR_NAME = ".local_build";
@@ -11,21 +11,23 @@ const error_1 = require("../error");
11
11
  const logger_1 = require("../logger");
12
12
  const utils_1 = require("../utils");
13
13
  const universalMakerDownload_1 = require("./universalMakerDownload");
14
- async function runUniversalMaker(projectRoot, framework) {
14
+ async function runUniversalMaker(projectRoot, addedEnv) {
15
15
  const universalMakerBinary = await (0, universalMakerDownload_1.getOrDownloadUniversalMaker)();
16
- executeUniversalMakerBinary(universalMakerBinary, projectRoot);
17
- return processUniversalMakerOutput(projectRoot, framework);
16
+ executeUniversalMakerBinary(universalMakerBinary, projectRoot, addedEnv);
17
+ return processUniversalMakerOutput(projectRoot);
18
18
  }
19
- function executeUniversalMakerBinary(universalMakerBinary, projectRoot) {
19
+ function executeUniversalMakerBinary(universalMakerBinary, projectRoot, addedEnv) {
20
20
  try {
21
- const bundleOutput = path.join(projectRoot, "bundle_output");
22
- fs.removeSync(bundleOutput);
23
- fs.ensureDirSync(bundleOutput);
21
+ const targetAppHosting = path.join(projectRoot, ".apphosting");
22
+ fs.removeSync(targetAppHosting);
23
+ fs.ensureDirSync(targetAppHosting);
24
24
  const res = childProcess.spawnSync(universalMakerBinary, ["-application_dir", projectRoot, "-output_dir", projectRoot, "-output_format", "json"], {
25
+ cwd: projectRoot,
25
26
  env: {
26
27
  ...process.env,
28
+ ...addedEnv,
27
29
  X_GOOGLE_TARGET_PLATFORM: "fah",
28
- FIREBASE_OUTPUT_BUNDLE_DIR: bundleOutput,
30
+ FIREBASE_OUTPUT_BUNDLE_DIR: targetAppHosting,
29
31
  },
30
32
  stdio: "pipe",
31
33
  });
@@ -57,33 +59,16 @@ function parseBundleYaml(projectRoot, defaultRunCommand) {
57
59
  const bundleRaw = fs.readFileSync(bundleYamlPath, "utf-8");
58
60
  const bundleData = (0, utils_1.wrappedSafeLoad)(bundleRaw);
59
61
  const runCommand = bundleData?.runConfig?.runCommand ?? defaultRunCommand;
60
- const outputFiles = bundleData?.outputFiles?.serverApp?.include;
61
- if (!outputFiles) {
62
- throw new error_1.FirebaseError("Failed to resolve build artifacts. Ensure Universal Maker produced a valid bundle.yaml with outputFiles.");
63
- }
62
+ const outputFiles = bundleData?.outputFiles?.serverApp?.include ?? [];
64
63
  return { runCommand, outputFiles };
65
64
  }
66
- function processUniversalMakerOutput(projectRoot, framework) {
65
+ function processUniversalMakerOutput(projectRoot) {
67
66
  const outputFilePath = path.join(projectRoot, "build_output.json");
68
67
  if (!fs.existsSync(outputFilePath)) {
69
68
  throw new error_1.FirebaseError(`Universal Maker did not produce the expected output file at ${outputFilePath}`);
70
69
  }
71
70
  const outputRaw = fs.readFileSync(outputFilePath, "utf-8");
72
71
  fs.unlinkSync(outputFilePath);
73
- const bundleOutput = path.join(projectRoot, "bundle_output");
74
- const targetAppHosting = path.join(projectRoot, ".apphosting");
75
- if (fs.existsSync(bundleOutput)) {
76
- fs.ensureDirSync(targetAppHosting);
77
- const files = fs.readdirSync(bundleOutput);
78
- for (const file of files) {
79
- const dest = path.join(targetAppHosting, file);
80
- if (fs.existsSync(dest)) {
81
- fs.removeSync(dest);
82
- }
83
- fs.moveSync(path.join(bundleOutput, file), dest);
84
- }
85
- fs.removeSync(bundleOutput);
86
- }
87
72
  let umOutput;
88
73
  try {
89
74
  umOutput = JSON.parse(outputRaw);
@@ -94,11 +79,6 @@ function processUniversalMakerOutput(projectRoot, framework) {
94
79
  const defaultRunCommand = `${umOutput.command} ${umOutput.args.join(" ")}`;
95
80
  const { runCommand: finalRunCommand, outputFiles: finalOutputFiles } = parseBundleYaml(projectRoot, defaultRunCommand);
96
81
  return {
97
- metadata: {
98
- language: umOutput.language,
99
- runtime: umOutput.runtime,
100
- framework: framework || "nextjs",
101
- },
102
82
  runConfig: {
103
83
  runCommand: finalRunCommand,
104
84
  environmentVariables: Object.entries(umOutput.envVars || {})
@@ -116,7 +96,7 @@ function processUniversalMakerOutput(projectRoot, framework) {
116
96
  },
117
97
  };
118
98
  }
119
- async function localBuild(projectId, projectRoot, framework, env = {}, options) {
99
+ async function localBuild(projectId, projectRoot, env = {}, options) {
120
100
  const hasBuildAvailableSecrets = Object.values(env).some((v) => v.secret && (!v.availability || v.availability.includes("BUILD")));
121
101
  if (hasBuildAvailableSecrets && !options?.allowLocalBuildSecrets) {
122
102
  if (options?.nonInteractive) {
@@ -129,26 +109,8 @@ async function localBuild(projectId, projectRoot, framework, env = {}, options)
129
109
  throw new error_1.FirebaseError("Cancelled local build due to BUILD-available secrets.");
130
110
  }
131
111
  }
132
- const originalEnv = { ...process.env };
133
112
  const addedEnv = await toProcessEnv(projectId, env);
134
- for (const [key, value] of Object.entries(addedEnv)) {
135
- process.env[key] = value;
136
- }
137
- let apphostingBuildOutput;
138
- try {
139
- apphostingBuildOutput = await runUniversalMaker(projectRoot, framework);
140
- }
141
- finally {
142
- for (const key in process.env) {
143
- if (!(key in originalEnv)) {
144
- delete process.env[key];
145
- }
146
- }
147
- for (const [key, value] of Object.entries(originalEnv)) {
148
- process.env[key] = value;
149
- }
150
- }
151
- const annotations = Object.fromEntries(Object.entries(apphostingBuildOutput.metadata).map(([key, value]) => [key, String(value)]));
113
+ const apphostingBuildOutput = await runUniversalMaker(projectRoot, addedEnv);
152
114
  const discoveredEnv = apphostingBuildOutput.runConfig.environmentVariables?.map(({ variable, value, availability }) => ({
153
115
  variable,
154
116
  value,
@@ -156,7 +118,6 @@ async function localBuild(projectId, projectRoot, framework, env = {}, options)
156
118
  }));
157
119
  return {
158
120
  outputFiles: apphostingBuildOutput.outputFiles?.serverApp.include ?? [],
159
- annotations,
160
121
  buildConfig: {
161
122
  runCommand: apphostingBuildOutput.runConfig.runCommand,
162
123
  env: discoveredEnv ?? [],
@@ -164,18 +125,14 @@ async function localBuild(projectId, projectRoot, framework, env = {}, options)
164
125
  };
165
126
  }
166
127
  async function toProcessEnv(projectId, env) {
167
- const entries = await Promise.all(Object.entries(env).map(async ([key, value]) => {
168
- if (value.availability && !value.availability.includes("BUILD")) {
169
- return null;
170
- }
171
- if (value.secret) {
172
- const resolvedValue = await (0, index_1.loadSecret)(projectId, value.secret);
173
- return [key, resolvedValue];
174
- }
175
- else {
176
- return [key, value.value || ""];
177
- }
128
+ const buildVars = Object.entries(env).filter(([, value]) => {
129
+ return !value.availability || value.availability.includes("BUILD");
130
+ });
131
+ const resolvedEntries = await Promise.all(buildVars.map(async ([key, value]) => {
132
+ const resolvedValue = value.secret
133
+ ? await (0, index_1.loadSecret)(projectId, value.secret)
134
+ : value.value || "";
135
+ return [key, resolvedValue];
178
136
  }));
179
- const filteredEntries = entries.filter((entry) => entry !== null);
180
- return Object.fromEntries(filteredEntries);
137
+ return Object.fromEntries(resolvedEntries);
181
138
  }
@@ -1,15 +1,15 @@
1
1
  {
2
2
  "darwin_arm64": {
3
3
  "version": "1.0.0",
4
- "expectedSize": 16111618,
5
- "expectedChecksumSHA256": "4b77d02a5f80f26d9bd1428f388c293c1fb264995d75b51c7d50fec7c87bcf58",
4
+ "expectedSize": 16266914,
5
+ "expectedChecksumSHA256": "72dae4eeefedc096649134f6ee592248c17dba5cdaec5bf679f367b2093d41cc",
6
6
  "remoteUrl": "https://artifactregistry.googleapis.com/download/v1/projects/serverless-runtimes-qa/locations/us-central1/repositories/universal-maker/files/darwin-arm64%3A1.0.0%3Auniversal_maker:download?alt=media",
7
7
  "downloadPathRelativeToCacheDir": "universal-maker-darwin-arm64-1.0.0"
8
8
  },
9
9
  "linux_x64": {
10
10
  "version": "1.0.0",
11
- "expectedSize": 16856277,
12
- "expectedChecksumSHA256": "dfc8357b8ce23ef1897e5590d4390f166e27734f241b770f721d68273118845c",
11
+ "expectedSize": 17023802,
12
+ "expectedChecksumSHA256": "ba74d2d2ce61d1b773f5b9eefeb09ef48a6890f2767581b57f9871869693823d",
13
13
  "remoteUrl": "https://artifactregistry.googleapis.com/download/v1/projects/serverless-runtimes-qa/locations/us-central1/repositories/universal-maker/files/x86-64%3A1.0.0%3Auniversal_maker:download?alt=media",
14
14
  "downloadPathRelativeToCacheDir": "universal-maker-linux-x64-1.0.0"
15
15
  }
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.archiveFile = archiveFile;
4
+ const archiver = require("archiver");
5
+ const fs = require("fs");
6
+ const path = require("path");
7
+ const tmp = require("tmp");
8
+ async function archiveFile(filePath, options) {
9
+ const tmpFileObj = tmp.fileSync({ postfix: ".zip" });
10
+ const tmpFile = tmpFileObj.name;
11
+ fs.closeSync(tmpFileObj.fd);
12
+ const fileStream = fs.createWriteStream(tmpFile, {
13
+ flags: "w",
14
+ encoding: "binary",
15
+ });
16
+ const archive = archiver("zip");
17
+ const name = options?.archivedFileName ?? path.basename(filePath);
18
+ archive.file(filePath, { name });
19
+ await pipeAsync(archive, fileStream);
20
+ return tmpFile;
21
+ }
22
+ async function pipeAsync(from, to) {
23
+ return new Promise((resolve, reject) => {
24
+ to.on("finish", resolve);
25
+ to.on("error", reject);
26
+ from.on("error", reject);
27
+ from.pipe(to);
28
+ from.finalize().catch(reject);
29
+ });
30
+ }
package/lib/command.js CHANGED
@@ -185,6 +185,13 @@ class Command {
185
185
  .filter(Boolean)
186
186
  .join(",");
187
187
  }
188
+ const exceptOption = (0, utils_1.getInheritedOption)(options, "except");
189
+ if (exceptOption) {
190
+ options.except = exceptOption
191
+ .split(/[\s,]+/)
192
+ .filter(Boolean)
193
+ .join(",");
194
+ }
188
195
  try {
189
196
  options.config = config_1.Config.load(options);
190
197
  }
@@ -0,0 +1,61 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.command = void 0;
4
+ const path = require("path");
5
+ const fs_extra_1 = require("fs-extra");
6
+ const fsAsync_1 = require("../fsAsync");
7
+ const command_1 = require("../command");
8
+ const error_1 = require("../error");
9
+ const utils_1 = require("../utils");
10
+ const projectUtils_1 = require("../projectUtils");
11
+ const getProjectNumber_1 = require("../getProjectNumber");
12
+ const requireAuth_1 = require("../requireAuth");
13
+ const sourcemap_1 = require("../crashlytics/sourcemap");
14
+ exports.command = new command_1.Command("crashlytics:sourcemap:upload [mappingFiles]")
15
+ .description("upload javascript source maps to de-minify stack traces")
16
+ .option("--app <appID>", "the app id of your Firebase app")
17
+ .option("--bucket-location <bucketLocation>", 'the location of the Google Cloud Storage bucket (default: "US-CENTRAL1"')
18
+ .option("--app-version <appVersion>", "the version of your Firebase app (defaults to Git commit hash, if available)")
19
+ .before(requireAuth_1.requireAuth)
20
+ .action(async (mappingFiles, options) => {
21
+ (0, sourcemap_1.checkGoogleAppID)(options);
22
+ const appVersion = (0, sourcemap_1.getAppVersion)(options);
23
+ const projectId = (0, projectUtils_1.needProjectId)(options);
24
+ const projectNumber = await (0, getProjectNumber_1.getProjectNumber)(options);
25
+ const bucketName = await (0, sourcemap_1.upsertBucket)(projectId, projectNumber, options);
26
+ const rootDir = path.resolve(options.projectRoot ?? process.cwd());
27
+ const filePath = mappingFiles ? path.resolve(mappingFiles) : rootDir;
28
+ let fstat;
29
+ try {
30
+ fstat = (0, fs_extra_1.statSync)(filePath);
31
+ }
32
+ catch (e) {
33
+ throw new error_1.FirebaseError("provide a valid directory to mapping file(s), e.g. app/build/outputs");
34
+ }
35
+ let successCount = 0;
36
+ const failedFiles = [];
37
+ if (fstat.isDirectory()) {
38
+ (0, utils_1.logLabeledBullet)("crashlytics", "Looking for mapping files in your directory...");
39
+ const files = await (0, fsAsync_1.readdirRecursive)({
40
+ path: filePath,
41
+ ignoreStrings: ["node_modules", ".git"],
42
+ maxDepth: 20,
43
+ });
44
+ const mappings = await (0, sourcemap_1.findSourceMapMappings)(files, rootDir);
45
+ const result = await (0, sourcemap_1.uploadSourceMaps)(mappings, {
46
+ projectId,
47
+ bucketName,
48
+ appVersion,
49
+ options,
50
+ });
51
+ successCount = result.successCount;
52
+ failedFiles.push(...result.failedFiles);
53
+ }
54
+ else {
55
+ throw new error_1.FirebaseError("provide a valid directory to mapping file(s), e.g. app/build/outputs");
56
+ }
57
+ (0, utils_1.logLabeledBullet)("crashlytics", `Uploaded ${successCount} (${failedFiles.length} failed) mapping files to ${bucketName}`);
58
+ if (failedFiles.length > 0) {
59
+ (0, utils_1.logLabeledBullet)("crashlytics", `Could not upload the following files:\n${failedFiles.join("\n")}`);
60
+ }
61
+ });
@@ -103,6 +103,9 @@ exports.command = new command_1.Command("dataconnect:sql:shell")
103
103
  user: username,
104
104
  database: databaseId,
105
105
  });
106
+ pool.on("error", (err) => {
107
+ logger_1.logger.debug("PostgreSQL pool error:", err);
108
+ });
106
109
  const conn = await pool.connect();
107
110
  await conn.query(`SET search_path TO "${schemaName}"`);
108
111
  logger_1.logger.info(`Logged in as ${username}`);
@@ -110,8 +113,23 @@ exports.command = new command_1.Command("dataconnect:sql:shell")
110
113
  logger_1.logger.info(clc.gray("Type your your SQL query or '.exit' to quit, queries should end with ';' or add empty line to execute."));
111
114
  await mainShellLoop(conn);
112
115
  logger_1.logger.info(clc.yellow("Exiting shell..."));
113
- conn.release();
114
- await pool.end();
115
- connector.close();
116
+ try {
117
+ conn.release();
118
+ }
119
+ catch (err) {
120
+ logger_1.logger.debug("Error releasing pg connection:", err);
121
+ }
122
+ try {
123
+ connector.close();
124
+ }
125
+ catch (err) {
126
+ logger_1.logger.debug("Error closing Cloud SQL connector:", err);
127
+ }
128
+ try {
129
+ await pool.end();
130
+ }
131
+ catch (err) {
132
+ logger_1.logger.debug("Error ending pg pool:", err);
133
+ }
116
134
  return { projectId };
117
135
  });
@@ -57,6 +57,10 @@ function load(client) {
57
57
  client.crashlytics.mappingfile = {};
58
58
  client.crashlytics.mappingfile.generateid = loadCommand("crashlytics-mappingfile-generateid");
59
59
  client.crashlytics.mappingfile.upload = loadCommand("crashlytics-mappingfile-upload");
60
+ if (experiments.isEnabled("crashlyticsWeb")) {
61
+ client.crashlytics.sourcemap = {};
62
+ client.crashlytics.sourcemap.upload = loadCommand("crashlytics-sourcemap-upload");
63
+ }
60
64
  client.database = {};
61
65
  client.database.get = loadCommand("database-get");
62
66
  client.database.import = loadCommand("database-import");