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.
- package/lib/accountExporter.js +13 -6
- package/lib/accountImporter.js +18 -1
- package/lib/agentSkills.js +2 -1
- package/lib/api.js +1 -3
- package/lib/apphosting/constants.js +2 -1
- package/lib/apphosting/localbuilds.js +23 -66
- package/lib/apphosting/universalMakerInfo.json +4 -4
- package/lib/archiveFile.js +30 -0
- package/lib/command.js +7 -0
- package/lib/commands/crashlytics-sourcemap-upload.js +61 -0
- package/lib/commands/dataconnect-sql-shell.js +21 -3
- package/lib/commands/index.js +4 -0
- package/lib/crashlytics/sourcemap.js +270 -0
- package/lib/dataconnect/ensureApis.js +0 -13
- package/lib/deploy/apphosting/deploy.js +39 -23
- package/lib/deploy/apphosting/prepare.js +28 -6
- package/lib/deploy/apphosting/util.js +34 -21
- package/lib/deploy/functions/prepare.js +8 -10
- package/lib/deploy/functions/services/ailogic.js +4 -6
- package/lib/emulator/downloadableEmulatorInfo.json +31 -31
- package/lib/experiments.js +8 -3
- package/lib/firebase_studio/migrate.js +8 -0
- package/lib/gcp/cloudsql/connect.js +49 -25
- package/lib/gemini/fdcExperience.js +171 -26
- package/lib/init/features/dataconnect/index.js +49 -15
- package/lib/tsconfig.compile.tsbuildinfo +1 -1
- package/lib/tsconfig.publish.tsbuildinfo +1 -1
- package/lib/utils.js +48 -0
- package/package.json +19 -4
- package/templates/init/functions/dart/_gitignore +1 -9
- package/lib/dataconnect/cloudAICompanionTypes.js +0 -2
package/lib/accountExporter.js
CHANGED
|
@@ -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
|
|
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] =
|
|
62
|
+
arr[startPos + 2] = escapeCsv(providerInfo.displayName || "");
|
|
57
63
|
arr[startPos + 3] = providerInfo.photoUrl || "";
|
|
58
64
|
}
|
|
59
65
|
function transUserToArray(user) {
|
|
60
|
-
const
|
|
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] =
|
|
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];
|
package/lib/accountImporter.js
CHANGED
|
@@ -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 = [
|
|
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.",
|
package/lib/agentSkills.js
CHANGED
|
@@ -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
|
-
|
|
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.
|
|
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,
|
|
14
|
+
async function runUniversalMaker(projectRoot, addedEnv) {
|
|
15
15
|
const universalMakerBinary = await (0, universalMakerDownload_1.getOrDownloadUniversalMaker)();
|
|
16
|
-
executeUniversalMakerBinary(universalMakerBinary, projectRoot);
|
|
17
|
-
return processUniversalMakerOutput(projectRoot
|
|
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
|
|
22
|
-
fs.removeSync(
|
|
23
|
-
fs.ensureDirSync(
|
|
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:
|
|
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
|
|
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,
|
|
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
|
-
|
|
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
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
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
|
-
|
|
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":
|
|
5
|
-
"expectedChecksumSHA256": "
|
|
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":
|
|
12
|
-
"expectedChecksumSHA256": "
|
|
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
|
-
|
|
114
|
-
|
|
115
|
-
|
|
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
|
});
|
package/lib/commands/index.js
CHANGED
|
@@ -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");
|