firebase-tools 11.2.1 → 11.4.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/apiv2.js +5 -0
- package/lib/checkValidTargetFilters.js +3 -2
- package/lib/commands/ext-export.js +2 -0
- package/lib/database/rulesConfig.js +35 -8
- package/lib/deploy/extensions/planner.js +1 -0
- package/lib/deploy/extensions/prepare.js +18 -1
- package/lib/deploy/extensions/release.js +4 -0
- package/lib/deploy/functions/build.js +43 -52
- package/lib/deploy/functions/params.js +189 -0
- package/lib/deploy/functions/prepare.js +1 -1
- package/lib/deploy/functions/release/index.js +4 -0
- package/lib/deploy/functions/runtimes/discovery/v1alpha1.js +3 -0
- package/lib/deploy/functions/runtimes/node/parseTriggers.js +1 -1
- package/lib/deploy/hosting/convertConfig.js +76 -16
- package/lib/deploy/index.js +1 -1
- package/lib/deploy/lifecycleHooks.js +1 -1
- package/lib/deploy/storage/prepare.js +29 -6
- package/lib/downloadUtils.js +1 -1
- package/lib/emulator/controller.js +0 -1
- package/lib/emulator/downloadableEmulators.js +9 -9
- package/lib/emulator/functionsEmulator.js +9 -1
- package/lib/emulator/functionsEmulatorRuntime.js +68 -58
- package/lib/emulator/functionsRuntimeWorker.js +35 -9
- package/lib/emulator/storage/apis/gcloud.js +1 -1
- package/lib/extensions/etags.js +28 -0
- package/lib/extensions/warnings.js +7 -1
- package/lib/functions/env.js +51 -2
- package/lib/functionsConfig.js +1 -1
- package/lib/gcp/iam.js +20 -17
- package/lib/gcp/rules.js +2 -3
- package/lib/gcp/runtimeconfig.js +1 -1
- package/lib/hosting/api.js +9 -11
- package/lib/hosting/expireUtils.js +2 -2
- package/lib/management/projects.js +6 -7
- package/lib/profileReport.js +16 -14
- package/lib/rc.js +14 -10
- package/lib/requireConfig.js +6 -6
- package/lib/rulesDeploy.js +1 -1
- package/npm-shrinkwrap.json +2 -2
- package/package.json +2 -1
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.detectEtagChanges = exports.saveEtags = void 0;
|
|
4
|
+
function saveEtags(rc, projectId, instances) {
|
|
5
|
+
rc.setEtags(projectId, "extensionInstances", etagsMap(instances));
|
|
6
|
+
}
|
|
7
|
+
exports.saveEtags = saveEtags;
|
|
8
|
+
function detectEtagChanges(rc, projectId, instances) {
|
|
9
|
+
const lastDeployedEtags = rc.getEtags(projectId).extensionInstances;
|
|
10
|
+
const currentEtags = etagsMap(instances);
|
|
11
|
+
if (!lastDeployedEtags || !Object.keys(lastDeployedEtags).length) {
|
|
12
|
+
return [];
|
|
13
|
+
}
|
|
14
|
+
const changedExtensionInstances = Object.entries(lastDeployedEtags)
|
|
15
|
+
.filter(([instanceName, etag]) => etag !== currentEtags[instanceName])
|
|
16
|
+
.map((i) => i[0]);
|
|
17
|
+
const newExtensionInstances = Object.keys(currentEtags).filter((instanceName) => !lastDeployedEtags[instanceName]);
|
|
18
|
+
return newExtensionInstances.concat(changedExtensionInstances);
|
|
19
|
+
}
|
|
20
|
+
exports.detectEtagChanges = detectEtagChanges;
|
|
21
|
+
function etagsMap(instances) {
|
|
22
|
+
return instances.reduce((acc, i) => {
|
|
23
|
+
if (i.etag) {
|
|
24
|
+
acc[i.instanceId] = i.etag;
|
|
25
|
+
}
|
|
26
|
+
return acc;
|
|
27
|
+
}, {});
|
|
28
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.paramsFlagDeprecationWarning = exports.displayWarningsForDeploy = exports.displayWarningPrompts = void 0;
|
|
3
|
+
exports.outOfBandChangesWarning = exports.paramsFlagDeprecationWarning = exports.displayWarningsForDeploy = exports.displayWarningPrompts = void 0;
|
|
4
4
|
const { marked } = require("marked");
|
|
5
5
|
const clc = require("cli-color");
|
|
6
6
|
const types_1 = require("./types");
|
|
@@ -75,3 +75,9 @@ function paramsFlagDeprecationWarning() {
|
|
|
75
75
|
"See https://firebase.google.com/docs/extensions/manifest for more details");
|
|
76
76
|
}
|
|
77
77
|
exports.paramsFlagDeprecationWarning = paramsFlagDeprecationWarning;
|
|
78
|
+
function outOfBandChangesWarning(instanceIds) {
|
|
79
|
+
logger_1.logger.warn("The following instances may have been changed in the Firebase console or by another machine since the last deploy from this machine.\n\t" +
|
|
80
|
+
clc.bold(instanceIds.join("\n\t")) +
|
|
81
|
+
"\nIf you proceed with this deployment, those changes will be overwritten. To avoid this, run `firebase ext:export` to sync these changes to your local extensions manifest.");
|
|
82
|
+
}
|
|
83
|
+
exports.outOfBandChangesWarning = outOfBandChangesWarning;
|
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.hasUserEnvs = exports.parseStrict = exports.validateKey = exports.KeyValidationError = exports.parse = void 0;
|
|
3
|
+
exports.loadFirebaseEnvs = exports.loadUserEnvs = exports.writeUserEnvs = exports.hasUserEnvs = exports.parseStrict = exports.validateKey = exports.KeyValidationError = exports.parse = void 0;
|
|
4
4
|
const clc = require("cli-color");
|
|
5
5
|
const fs = require("fs");
|
|
6
6
|
const path = require("path");
|
|
@@ -51,6 +51,17 @@ const ESCAPE_SEQUENCES_TO_CHARACTERS = {
|
|
|
51
51
|
"\\'": "'",
|
|
52
52
|
'\\"': '"',
|
|
53
53
|
};
|
|
54
|
+
const ALL_ESCAPE_SEQUENCES_RE = /\\[nrtv\\'"]/g;
|
|
55
|
+
const CHARACTERS_TO_ESCAPE_SEQUENCES = {
|
|
56
|
+
"\n": "\\n",
|
|
57
|
+
"\r": "\\r",
|
|
58
|
+
"\t": "\\t",
|
|
59
|
+
"\v": "\\v",
|
|
60
|
+
"\\": "\\\\",
|
|
61
|
+
"'": "\\'",
|
|
62
|
+
'"': '\\"',
|
|
63
|
+
};
|
|
64
|
+
const ALL_ESCAPABLE_CHARACTERS_RE = /[\n\r\t\v\\'"]/g;
|
|
54
65
|
function parse(data) {
|
|
55
66
|
const envs = {};
|
|
56
67
|
const errors = [];
|
|
@@ -63,7 +74,7 @@ function parse(data) {
|
|
|
63
74
|
if ((quotesMatch = /^(["'])(.*)\1$/ms.exec(v)) != null) {
|
|
64
75
|
v = quotesMatch[2];
|
|
65
76
|
if (quotesMatch[1] === '"') {
|
|
66
|
-
v = v.replace(
|
|
77
|
+
v = v.replace(ALL_ESCAPE_SEQUENCES_RE, (match) => ESCAPE_SEQUENCES_TO_CHARACTERS[match]);
|
|
67
78
|
}
|
|
68
79
|
}
|
|
69
80
|
envs[k] = v;
|
|
@@ -145,6 +156,44 @@ function hasUserEnvs({ functionsSource, projectId, projectAlias, isEmulator, })
|
|
|
145
156
|
return findEnvfiles(functionsSource, projectId, projectAlias, isEmulator).length > 0;
|
|
146
157
|
}
|
|
147
158
|
exports.hasUserEnvs = hasUserEnvs;
|
|
159
|
+
function writeUserEnvs(toWrite, envOpts) {
|
|
160
|
+
if (Object.keys(toWrite).length === 0) {
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
const { functionsSource, projectId, projectAlias, isEmulator } = envOpts;
|
|
164
|
+
let envFiles = findEnvfiles(functionsSource, projectId, projectAlias, isEmulator);
|
|
165
|
+
if (envFiles.length === 0) {
|
|
166
|
+
envFiles = [createEnvFile(envOpts)];
|
|
167
|
+
}
|
|
168
|
+
const currentEnvs = loadUserEnvs(envOpts);
|
|
169
|
+
for (const k of Object.keys(toWrite)) {
|
|
170
|
+
validateKey(k);
|
|
171
|
+
if (currentEnvs.hasOwnProperty(k)) {
|
|
172
|
+
throw new error_1.FirebaseError(`Attempted to write param-defined key ${k} to .env files, but it was already defined.`);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
const mostSpecificEnv = path.join(functionsSource, envFiles[envFiles.length - 1]);
|
|
176
|
+
(0, utils_1.logBullet)(clc.cyan.bold("functions: ") + `Writing new parameter values to disk: ${mostSpecificEnv}`);
|
|
177
|
+
for (const k of Object.keys(toWrite)) {
|
|
178
|
+
fs.appendFileSync(mostSpecificEnv, formatUserEnvForWrite(k, toWrite[k]));
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
exports.writeUserEnvs = writeUserEnvs;
|
|
182
|
+
function createEnvFile(envOpts) {
|
|
183
|
+
const fileToWrite = envOpts.isEmulator
|
|
184
|
+
? FUNCTIONS_EMULATOR_DOTENV
|
|
185
|
+
: `.env.${envOpts.projectAlias || envOpts.projectId}`;
|
|
186
|
+
logger_1.logger.debug(`Creating ${fileToWrite}...`);
|
|
187
|
+
fs.writeFileSync(path.join(envOpts.functionsSource, fileToWrite), "", { flag: "wx" });
|
|
188
|
+
return fileToWrite;
|
|
189
|
+
}
|
|
190
|
+
function formatUserEnvForWrite(key, value) {
|
|
191
|
+
const escapedValue = value.replace(ALL_ESCAPABLE_CHARACTERS_RE, (match) => CHARACTERS_TO_ESCAPE_SEQUENCES[match]);
|
|
192
|
+
if (escapedValue !== value) {
|
|
193
|
+
return `${key}="${escapedValue}"\n`;
|
|
194
|
+
}
|
|
195
|
+
return `${key}=${escapedValue}\n`;
|
|
196
|
+
}
|
|
148
197
|
function loadUserEnvs({ functionsSource, projectId, projectAlias, isEmulator, }) {
|
|
149
198
|
var _a;
|
|
150
199
|
const envFiles = findEnvfiles(functionsSource, projectId, projectAlias, isEmulator);
|
package/lib/functionsConfig.js
CHANGED
|
@@ -70,7 +70,7 @@ async function setVariablesRecursive(projectId, configId, varPath, val) {
|
|
|
70
70
|
catch (e) {
|
|
71
71
|
}
|
|
72
72
|
}
|
|
73
|
-
if (
|
|
73
|
+
if (typeof parsed === "object" && parsed !== null) {
|
|
74
74
|
return Promise.all(Object.entries(parsed).map(([key, item]) => {
|
|
75
75
|
const newVarPath = varPath ? [varPath, key].join("/") : key;
|
|
76
76
|
return setVariablesRecursive(projectId, configId, newVarPath, item);
|
package/lib/gcp/iam.js
CHANGED
|
@@ -2,11 +2,9 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.testIamPermissions = exports.testResourceIamPermissions = exports.getRole = exports.deleteServiceAccount = exports.createServiceAccountKey = exports.getServiceAccount = exports.createServiceAccount = void 0;
|
|
4
4
|
const api_1 = require("../api");
|
|
5
|
-
const lodash_1 = require("lodash");
|
|
6
5
|
const logger_1 = require("../logger");
|
|
7
6
|
const apiv2_1 = require("../apiv2");
|
|
8
|
-
const
|
|
9
|
-
const apiClient = new apiv2_1.Client({ urlPrefix: api_1.iamOrigin, apiVersion: API_VERSION });
|
|
7
|
+
const apiClient = new apiv2_1.Client({ urlPrefix: api_1.iamOrigin, apiVersion: "v1" });
|
|
10
8
|
async function createServiceAccount(projectId, accountId, description, displayName) {
|
|
11
9
|
const response = await apiClient.post(`/projects/${projectId}/serviceAccounts`, {
|
|
12
10
|
accountId,
|
|
@@ -31,8 +29,8 @@ async function createServiceAccountKey(projectId, serviceAccountName) {
|
|
|
31
29
|
return response.body;
|
|
32
30
|
}
|
|
33
31
|
exports.createServiceAccountKey = createServiceAccountKey;
|
|
34
|
-
function deleteServiceAccount(projectId, accountEmail) {
|
|
35
|
-
|
|
32
|
+
async function deleteServiceAccount(projectId, accountEmail) {
|
|
33
|
+
await apiClient.delete(`/projects/${projectId}/serviceAccounts/${accountEmail}`, {
|
|
36
34
|
resolveOnHTTPError: true,
|
|
37
35
|
});
|
|
38
36
|
}
|
|
@@ -44,25 +42,30 @@ async function getRole(role) {
|
|
|
44
42
|
return response.body;
|
|
45
43
|
}
|
|
46
44
|
exports.getRole = getRole;
|
|
47
|
-
async function testResourceIamPermissions(origin, apiVersion, resourceName, permissions) {
|
|
45
|
+
async function testResourceIamPermissions(origin, apiVersion, resourceName, permissions, quotaUser = "") {
|
|
48
46
|
const localClient = new apiv2_1.Client({ urlPrefix: origin, apiVersion });
|
|
49
47
|
if (process.env.FIREBASE_SKIP_INFORMATIONAL_IAM) {
|
|
50
|
-
logger_1.logger.debug(
|
|
51
|
-
return { allowed: permissions, missing: [], passed: true };
|
|
48
|
+
logger_1.logger.debug(`[iam] skipping informational check of permissions ${JSON.stringify(permissions)} on resource ${resourceName}`);
|
|
49
|
+
return { allowed: Array.from(permissions).sort(), missing: [], passed: true };
|
|
50
|
+
}
|
|
51
|
+
const headers = {};
|
|
52
|
+
if (quotaUser) {
|
|
53
|
+
headers["x-goog-quota-user"] = quotaUser;
|
|
54
|
+
}
|
|
55
|
+
const response = await localClient.post(`/${resourceName}:testIamPermissions`, { permissions }, { headers });
|
|
56
|
+
const allowed = new Set(response.body.permissions || []);
|
|
57
|
+
const missing = new Set(permissions);
|
|
58
|
+
for (const p of allowed) {
|
|
59
|
+
missing.delete(p);
|
|
52
60
|
}
|
|
53
|
-
const response = await localClient.post(`/${resourceName}:testIamPermissions`, {
|
|
54
|
-
permissions,
|
|
55
|
-
});
|
|
56
|
-
const allowed = (response.body.permissions || []).sort();
|
|
57
|
-
const missing = (0, lodash_1.difference)(permissions, allowed);
|
|
58
61
|
return {
|
|
59
|
-
allowed,
|
|
60
|
-
missing,
|
|
61
|
-
passed: missing.
|
|
62
|
+
allowed: Array.from(allowed).sort(),
|
|
63
|
+
missing: Array.from(missing).sort(),
|
|
64
|
+
passed: missing.size === 0,
|
|
62
65
|
};
|
|
63
66
|
}
|
|
64
67
|
exports.testResourceIamPermissions = testResourceIamPermissions;
|
|
65
68
|
async function testIamPermissions(projectId, permissions) {
|
|
66
|
-
return testResourceIamPermissions(api_1.resourceManagerOrigin, "v1", `projects/${projectId}`, permissions);
|
|
69
|
+
return testResourceIamPermissions(api_1.resourceManagerOrigin, "v1", `projects/${projectId}`, permissions, `projects/${projectId}`);
|
|
67
70
|
}
|
|
68
71
|
exports.testIamPermissions = testIamPermissions;
|
package/lib/gcp/rules.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.testRuleset = exports.updateOrCreateRelease = exports.updateRelease = exports.createRelease = exports.createRuleset = exports.deleteRuleset = exports.getRulesetId = exports.listAllRulesets = exports.listRulesets = exports.getRulesetContent = exports.listAllReleases = exports.listReleases = exports.getLatestRulesetName = void 0;
|
|
4
|
-
const _ = require("lodash");
|
|
5
4
|
const api_1 = require("../api");
|
|
6
5
|
const apiv2_1 = require("../apiv2");
|
|
7
6
|
const logger_1 = require("../logger");
|
|
@@ -51,7 +50,7 @@ async function listAllReleases(projectId) {
|
|
|
51
50
|
}
|
|
52
51
|
pageToken = response.nextPageToken;
|
|
53
52
|
} while (pageToken);
|
|
54
|
-
return
|
|
53
|
+
return releases.sort((a, b) => b.createTime.localeCompare(a.createTime));
|
|
55
54
|
}
|
|
56
55
|
exports.listAllReleases = listAllReleases;
|
|
57
56
|
async function getRulesetContent(name) {
|
|
@@ -90,7 +89,7 @@ async function listAllRulesets(projectId) {
|
|
|
90
89
|
}
|
|
91
90
|
pageToken = response.nextPageToken;
|
|
92
91
|
} while (pageToken);
|
|
93
|
-
return
|
|
92
|
+
return rulesets.sort((a, b) => b.createTime.localeCompare(a.createTime));
|
|
94
93
|
}
|
|
95
94
|
exports.listAllRulesets = listAllRulesets;
|
|
96
95
|
function getRulesetId(ruleset) {
|
package/lib/gcp/runtimeconfig.js
CHANGED
package/lib/hosting/api.js
CHANGED
|
@@ -43,7 +43,7 @@ async function getChannel(project = "-", site, channelId) {
|
|
|
43
43
|
return res.body;
|
|
44
44
|
}
|
|
45
45
|
catch (e) {
|
|
46
|
-
if (e.status === 404) {
|
|
46
|
+
if (e instanceof error_1.FirebaseError && e.status === 404) {
|
|
47
47
|
return null;
|
|
48
48
|
}
|
|
49
49
|
throw e;
|
|
@@ -51,23 +51,22 @@ async function getChannel(project = "-", site, channelId) {
|
|
|
51
51
|
}
|
|
52
52
|
exports.getChannel = getChannel;
|
|
53
53
|
async function listChannels(project = "-", site) {
|
|
54
|
-
var _a, _b;
|
|
55
54
|
const channels = [];
|
|
56
55
|
let nextPageToken = "";
|
|
57
56
|
for (;;) {
|
|
58
57
|
try {
|
|
59
58
|
const res = await apiClient.get(`/projects/${project}/sites/${site}/channels`, { queryParams: { pageToken: nextPageToken, pageSize: 10 } });
|
|
60
|
-
const c =
|
|
59
|
+
const c = res.body.channels;
|
|
61
60
|
if (c) {
|
|
62
61
|
channels.push(...c);
|
|
63
62
|
}
|
|
64
|
-
nextPageToken =
|
|
63
|
+
nextPageToken = res.body.nextPageToken || "";
|
|
65
64
|
if (!nextPageToken) {
|
|
66
65
|
return channels;
|
|
67
66
|
}
|
|
68
67
|
}
|
|
69
68
|
catch (e) {
|
|
70
|
-
if (e.status === 404) {
|
|
69
|
+
if (e instanceof error_1.FirebaseError && e.status === 404) {
|
|
71
70
|
throw new error_1.FirebaseError(`could not find channels for site "${site}"`, {
|
|
72
71
|
original: e,
|
|
73
72
|
});
|
|
@@ -116,23 +115,22 @@ async function createRelease(site, channel, version) {
|
|
|
116
115
|
}
|
|
117
116
|
exports.createRelease = createRelease;
|
|
118
117
|
async function listSites(project) {
|
|
119
|
-
var _a, _b;
|
|
120
118
|
const sites = [];
|
|
121
119
|
let nextPageToken = "";
|
|
122
120
|
for (;;) {
|
|
123
121
|
try {
|
|
124
122
|
const res = await apiClient.get(`/projects/${project}/sites`, { queryParams: { pageToken: nextPageToken, pageSize: 10 } });
|
|
125
|
-
const c =
|
|
123
|
+
const c = res.body.sites;
|
|
126
124
|
if (c) {
|
|
127
125
|
sites.push(...c);
|
|
128
126
|
}
|
|
129
|
-
nextPageToken =
|
|
127
|
+
nextPageToken = res.body.nextPageToken || "";
|
|
130
128
|
if (!nextPageToken) {
|
|
131
129
|
return sites;
|
|
132
130
|
}
|
|
133
131
|
}
|
|
134
132
|
catch (e) {
|
|
135
|
-
if (e.status === 404) {
|
|
133
|
+
if (e instanceof error_1.FirebaseError && e.status === 404) {
|
|
136
134
|
throw new error_1.FirebaseError(`could not find sites for project "${project}"`, {
|
|
137
135
|
original: e,
|
|
138
136
|
});
|
|
@@ -148,7 +146,7 @@ async function getSite(project, site) {
|
|
|
148
146
|
return res.body;
|
|
149
147
|
}
|
|
150
148
|
catch (e) {
|
|
151
|
-
if (e.status === 404) {
|
|
149
|
+
if (e instanceof error_1.FirebaseError && e.status === 404) {
|
|
152
150
|
throw new error_1.FirebaseError(`could not find site "${site}" for project "${project}"`, {
|
|
153
151
|
original: e,
|
|
154
152
|
});
|
|
@@ -158,7 +156,7 @@ async function getSite(project, site) {
|
|
|
158
156
|
}
|
|
159
157
|
exports.getSite = getSite;
|
|
160
158
|
async function createSite(project, site, appId = "") {
|
|
161
|
-
const res = await apiClient.post(`/projects/${project}/sites`, { appId: appId }, { queryParams: {
|
|
159
|
+
const res = await apiClient.post(`/projects/${project}/sites`, { appId: appId }, { queryParams: { siteId: site } });
|
|
162
160
|
return res.body;
|
|
163
161
|
}
|
|
164
162
|
exports.createSite = createSite;
|
|
@@ -16,8 +16,8 @@ const DURATIONS = {
|
|
|
16
16
|
};
|
|
17
17
|
exports.MAX_DURATION = 30 * Duration.DAY;
|
|
18
18
|
exports.DEFAULT_DURATION = 7 * Duration.DAY;
|
|
19
|
-
function calculateChannelExpireTTL(flag) {
|
|
20
|
-
const match = exports.DURATION_REGEX.exec(flag
|
|
19
|
+
function calculateChannelExpireTTL(flag = "") {
|
|
20
|
+
const match = exports.DURATION_REGEX.exec(flag);
|
|
21
21
|
if (!match) {
|
|
22
22
|
throw new error_1.FirebaseError(`"expires" flag must be a duration string (e.g. 24h or 7d) at most 30d`);
|
|
23
23
|
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.getFirebaseProject = exports.listFirebaseProjects = exports.getAvailableCloudProjectPage = exports.getFirebaseProjectPage = exports.addFirebaseToCloudProject = exports.createCloudProject = exports.promptAvailableProjectId = exports.getOrPromptProject = exports.addFirebaseToCloudProjectAndLog = exports.createFirebaseProjectAndLog = exports.PROJECTS_CREATE_QUESTIONS = exports.ProjectParentResourceType = void 0;
|
|
4
|
-
const _ = require("lodash");
|
|
5
4
|
const clc = require("cli-color");
|
|
6
5
|
const ora = require("ora");
|
|
7
6
|
const apiv2_1 = require("../apiv2");
|
|
@@ -110,15 +109,15 @@ async function selectProjectByPrompting() {
|
|
|
110
109
|
return await getFirebaseProject(projectId);
|
|
111
110
|
}
|
|
112
111
|
async function selectProjectFromList(projects = []) {
|
|
113
|
-
|
|
112
|
+
const choices = projects
|
|
114
113
|
.filter((p) => !!p)
|
|
115
114
|
.map((p) => {
|
|
116
115
|
return {
|
|
117
116
|
name: p.projectId + (p.displayName ? ` (${p.displayName})` : ""),
|
|
118
117
|
value: p.projectId,
|
|
119
118
|
};
|
|
120
|
-
})
|
|
121
|
-
|
|
119
|
+
})
|
|
120
|
+
.sort((a, b) => a.name.localeCompare(b.name));
|
|
122
121
|
if (choices.length >= 25) {
|
|
123
122
|
utils.logBullet(`Don't want to scroll through all your projects? If you know your project ID, ` +
|
|
124
123
|
`you can initialize it directly using ${clc.bold("firebase init --project <project_id>")}.\n`);
|
|
@@ -151,7 +150,7 @@ async function promptAvailableProjectId() {
|
|
|
151
150
|
});
|
|
152
151
|
}
|
|
153
152
|
else {
|
|
154
|
-
|
|
153
|
+
const choices = projects
|
|
155
154
|
.filter((p) => !!p)
|
|
156
155
|
.map((p) => {
|
|
157
156
|
const projectId = getProjectId(p);
|
|
@@ -159,8 +158,8 @@ async function promptAvailableProjectId() {
|
|
|
159
158
|
name: projectId + (p.displayName ? ` (${p.displayName})` : ""),
|
|
160
159
|
value: projectId,
|
|
161
160
|
};
|
|
162
|
-
})
|
|
163
|
-
|
|
161
|
+
})
|
|
162
|
+
.sort((a, b) => a.name.localeCompare(b.name));
|
|
164
163
|
return await (0, prompt_1.promptOnce)({
|
|
165
164
|
type: "list",
|
|
166
165
|
name: "id",
|
package/lib/profileReport.js
CHANGED
|
@@ -303,14 +303,14 @@ class ProfileReport {
|
|
|
303
303
|
});
|
|
304
304
|
});
|
|
305
305
|
const paths = Object.keys(unindexed);
|
|
306
|
-
|
|
306
|
+
for (const path of paths) {
|
|
307
307
|
const indices = Object.keys(unindexed[path]);
|
|
308
|
-
|
|
308
|
+
for (const index of indices) {
|
|
309
309
|
const data = unindexed[path][index];
|
|
310
310
|
const row = [path, extractReadableIndex(data.query), formatNumber(data.times)];
|
|
311
311
|
table.push(row);
|
|
312
|
-
}
|
|
313
|
-
}
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
314
|
return table;
|
|
315
315
|
}
|
|
316
316
|
renderBandwidth(pureData) {
|
|
@@ -327,8 +327,10 @@ class ProfileReport {
|
|
|
327
327
|
times: b1.times + b2.times,
|
|
328
328
|
};
|
|
329
329
|
});
|
|
330
|
-
const paths =
|
|
331
|
-
|
|
330
|
+
const paths = Object.keys(data).sort((a, b) => {
|
|
331
|
+
return data[b].bytes - data[a].bytes;
|
|
332
|
+
});
|
|
333
|
+
for (const path of paths) {
|
|
332
334
|
const bandwidth = data[path];
|
|
333
335
|
const row = [
|
|
334
336
|
path,
|
|
@@ -337,7 +339,7 @@ class ProfileReport {
|
|
|
337
339
|
formatBytes(bandwidth.bytes / bandwidth.times),
|
|
338
340
|
];
|
|
339
341
|
table.push(row);
|
|
340
|
-
}
|
|
342
|
+
}
|
|
341
343
|
return table;
|
|
342
344
|
}
|
|
343
345
|
renderOutgoingBandwidth() {
|
|
@@ -392,12 +394,12 @@ class ProfileReport {
|
|
|
392
394
|
rejected: s1.rejected + s2.rejected,
|
|
393
395
|
};
|
|
394
396
|
});
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
const
|
|
398
|
-
return
|
|
399
|
-
}
|
|
400
|
-
|
|
397
|
+
const paths = Object.keys(data).sort((a, b) => {
|
|
398
|
+
const speedA = data[a].millis / data[a].times;
|
|
399
|
+
const speedB = data[b].millis / data[b].times;
|
|
400
|
+
return speedB - speedA;
|
|
401
|
+
});
|
|
402
|
+
for (const path of paths) {
|
|
401
403
|
const speed = data[path];
|
|
402
404
|
const row = [
|
|
403
405
|
path,
|
|
@@ -409,7 +411,7 @@ class ProfileReport {
|
|
|
409
411
|
row.push(formatNumber(speed.rejected));
|
|
410
412
|
}
|
|
411
413
|
table.push(row);
|
|
412
|
-
}
|
|
414
|
+
}
|
|
413
415
|
return table;
|
|
414
416
|
}
|
|
415
417
|
renderReadSpeed() {
|
package/lib/rc.js
CHANGED
|
@@ -25,7 +25,7 @@ exports.loadRC = loadRC;
|
|
|
25
25
|
class RC {
|
|
26
26
|
constructor(rcpath, data) {
|
|
27
27
|
this.path = rcpath;
|
|
28
|
-
this.data = Object.assign({ projects: {}, targets: {} }, data);
|
|
28
|
+
this.data = Object.assign({ projects: {}, targets: {}, etags: {} }, data);
|
|
29
29
|
}
|
|
30
30
|
static loadFile(rcpath) {
|
|
31
31
|
let data = {};
|
|
@@ -136,18 +136,22 @@ class RC {
|
|
|
136
136
|
requireTarget(project, type, name) {
|
|
137
137
|
const target = this.target(project, type, name);
|
|
138
138
|
if (!target.length) {
|
|
139
|
-
throw new error_1.FirebaseError(
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
clc.bold(project) +
|
|
143
|
-
". Configure with:\n\n firebase target:apply " +
|
|
144
|
-
type +
|
|
145
|
-
" " +
|
|
146
|
-
name +
|
|
147
|
-
" <resources...>");
|
|
139
|
+
throw new error_1.FirebaseError(`Deploy target ${clc.bold(name)} not configured for project ${clc.bold(project)}. Configure with:
|
|
140
|
+
|
|
141
|
+
firebase target:apply ${type} ${name} <resources...>`);
|
|
148
142
|
}
|
|
149
143
|
return target;
|
|
150
144
|
}
|
|
145
|
+
getEtags(projectId) {
|
|
146
|
+
return this.data.etags[projectId] || { extensionInstances: {} };
|
|
147
|
+
}
|
|
148
|
+
setEtags(projectId, resourceType, etagData) {
|
|
149
|
+
if (!this.data.etags[projectId]) {
|
|
150
|
+
this.data.etags[projectId] = {};
|
|
151
|
+
}
|
|
152
|
+
this.data.etags[projectId][resourceType] = etagData;
|
|
153
|
+
this.save();
|
|
154
|
+
}
|
|
151
155
|
save() {
|
|
152
156
|
if (this.path) {
|
|
153
157
|
fs.writeFileSync(this.path, JSON.stringify(this.data, null, 2), {
|
package/lib/requireConfig.js
CHANGED
|
@@ -3,11 +3,11 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.requireConfig = void 0;
|
|
4
4
|
const error_1 = require("./error");
|
|
5
5
|
async function requireConfig(options) {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
?
|
|
10
|
-
: new error_1.FirebaseError("Not in a Firebase project directory (could not locate firebase.json)");
|
|
11
|
-
}
|
|
6
|
+
return new Promise((resolve, reject) => {
|
|
7
|
+
var _a;
|
|
8
|
+
return options.config
|
|
9
|
+
? resolve()
|
|
10
|
+
: reject((_a = options.configError) !== null && _a !== void 0 ? _a : new error_1.FirebaseError("Not in a Firebase project directory (could not locate firebase.json)"));
|
|
11
|
+
});
|
|
12
12
|
}
|
|
13
13
|
exports.requireConfig = requireConfig;
|
package/lib/rulesDeploy.js
CHANGED
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.RulesDeploy = exports.RulesetServiceType = void 0;
|
|
4
4
|
const _ = require("lodash");
|
|
5
5
|
const clc = require("cli-color");
|
|
6
|
-
const fs = require("fs");
|
|
6
|
+
const fs = require("fs-extra");
|
|
7
7
|
const gcp = require("./gcp");
|
|
8
8
|
const logger_1 = require("./logger");
|
|
9
9
|
const error_1 = require("./error");
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "firebase-tools",
|
|
3
|
-
"version": "11.
|
|
3
|
+
"version": "11.4.0",
|
|
4
4
|
"lockfileVersion": 2,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "firebase-tools",
|
|
9
|
-
"version": "11.
|
|
9
|
+
"version": "11.4.0",
|
|
10
10
|
"license": "MIT",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"@google-cloud/pubsub": "^3.0.1",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "firebase-tools",
|
|
3
|
-
"version": "11.
|
|
3
|
+
"version": "11.4.0",
|
|
4
4
|
"description": "Command-Line Interface for Firebase",
|
|
5
5
|
"main": "./lib/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -30,6 +30,7 @@
|
|
|
30
30
|
"test:extensions-deploy": "bash ./scripts/extensions-deploy-tests/run.sh",
|
|
31
31
|
"test:extensions-emulator": "bash ./scripts/extensions-emulator-tests/run.sh",
|
|
32
32
|
"test:hosting": "bash ./scripts/hosting-tests/run.sh",
|
|
33
|
+
"test:hosting-rewrites": "bash ./scripts/hosting-tests/rewrites-tests/run.sh",
|
|
33
34
|
"test:triggers-end-to-end": "bash ./scripts/triggers-end-to-end-tests/run.sh",
|
|
34
35
|
"test:storage-deploy": "bash ./scripts/storage-deploy-tests/run.sh",
|
|
35
36
|
"test:storage-emulator-integration": "bash ./scripts/storage-emulator-integration/run.sh"
|