firebase-tools 11.8.1 → 11.10.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/bin/firebase.js +5 -5
- package/lib/commands/ext-install.js +2 -2
- package/lib/crashlytics/buildToolsJarHelper.js +1 -1
- package/lib/deploy/functions/build.js +3 -4
- package/lib/deploy/functions/cache/applyHash.js +2 -9
- package/lib/deploy/functions/cel.js +86 -47
- package/lib/deploy/functions/deploy.js +21 -2
- package/lib/deploy/functions/params.js +35 -8
- package/lib/deploy/functions/prepare.js +13 -2
- package/lib/deploy/functions/prepareFunctionsUpload.js +2 -2
- package/lib/deploy/functions/release/planner.js +1 -0
- package/lib/deploy/functions/services/index.js +11 -0
- package/lib/deploy/functions/services/remoteConfig.js +14 -0
- package/lib/emulator/auth/server.js +6 -0
- package/lib/emulator/auth/state.js +3 -1
- package/lib/emulator/downloadableEmulators.js +10 -10
- package/lib/emulator/functionsEmulator.js +71 -171
- package/lib/emulator/functionsEmulatorRuntime.js +104 -142
- package/lib/emulator/functionsEmulatorShared.js +3 -0
- package/lib/emulator/functionsEmulatorShell.js +1 -1
- package/lib/emulator/functionsRuntimeWorker.js +55 -36
- package/lib/emulator/storage/files.js +5 -5
- package/lib/emulator/storage/rules/runtime.js +41 -6
- package/lib/emulator/storage/rules/types.js +7 -1
- package/lib/emulator/storage/rules/utils.js +3 -1
- package/lib/emulator/storage/server.js +6 -0
- package/lib/ensureApiEnabled.js +2 -0
- package/lib/extensions/askUserForConsent.js +1 -38
- package/lib/extensions/displayExtensionInfo.js +27 -2
- package/lib/extensions/updateHelper.js +3 -35
- package/lib/functions/events/v2.js +2 -1
- package/lib/gcp/cloudfunctionsv2.js +5 -2
- package/lib/previews.js +1 -1
- package/lib/rulesDeploy.js +1 -2
- package/lib/serve/hosting.js +1 -1
- package/npm-shrinkwrap.json +69 -9
- package/package.json +3 -2
package/lib/bin/firebase.js
CHANGED
|
@@ -11,15 +11,11 @@ if (!semver.satisfies(nodeVersion, pkg.engines.node)) {
|
|
|
11
11
|
const updateNotifierPkg = require("update-notifier");
|
|
12
12
|
const clc = require("colorette");
|
|
13
13
|
const TerminalRenderer = require("marked-terminal");
|
|
14
|
-
const updateNotifier = updateNotifierPkg({ pkg
|
|
14
|
+
const updateNotifier = updateNotifierPkg({ pkg });
|
|
15
15
|
const marked_1 = require("marked");
|
|
16
16
|
marked_1.marked.setOptions({
|
|
17
17
|
renderer: new TerminalRenderer(),
|
|
18
18
|
});
|
|
19
|
-
const updateMessage = `Update available ${clc.gray("{currentVersion}")} → ${clc.green("{latestVersion}")}\n` +
|
|
20
|
-
`To update to the latest version using npm, run\n${clc.cyan("npm install -g firebase-tools")}\n` +
|
|
21
|
-
`For other CLI management options, visit the ${(0, marked_1.marked)("[CLI documentation](https://firebase.google.com/docs/cli#update-cli)")}`;
|
|
22
|
-
updateNotifier.notify({ defer: true, isGlobal: true, message: updateMessage });
|
|
23
19
|
const node_path_1 = require("node:path");
|
|
24
20
|
const triple_beam_1 = require("triple-beam");
|
|
25
21
|
const stripAnsi = require("strip-ansi");
|
|
@@ -106,6 +102,10 @@ process.on("exit", (code) => {
|
|
|
106
102
|
else {
|
|
107
103
|
configstore_1.configstore.delete("lastError");
|
|
108
104
|
}
|
|
105
|
+
const updateMessage = `Update available ${clc.gray("{currentVersion}")} → ${clc.green("{latestVersion}")}\n` +
|
|
106
|
+
`To update to the latest version using npm, run\n${clc.cyan("npm install -g firebase-tools")}\n` +
|
|
107
|
+
`For other CLI management options, visit the ${(0, marked_1.marked)("[CLI documentation](https://firebase.google.com/docs/cli#update-cli)")}`;
|
|
108
|
+
updateNotifier.notify({ defer: false, isGlobal: true, message: updateMessage });
|
|
109
109
|
});
|
|
110
110
|
process.on("uncaughtException", (err) => {
|
|
111
111
|
(0, errorOut_1.errorOut)(err);
|
|
@@ -62,7 +62,7 @@ exports.command = new command_1.Command("ext:install [extensionName]")
|
|
|
62
62
|
}
|
|
63
63
|
if ((0, extensionsHelper_1.isLocalPath)(extensionName)) {
|
|
64
64
|
source = await (0, extensionsHelper_1.createSourceFromLocation)((0, projectUtils_1.needProjectId)({ projectId }), extensionName);
|
|
65
|
-
(0, displayExtensionInfo_1.displayExtInfo)(extensionName, "", source.spec);
|
|
65
|
+
await (0, displayExtensionInfo_1.displayExtInfo)(extensionName, "", source.spec);
|
|
66
66
|
void (0, track_1.track)("Extension Install", "Install by Source", options.interactive ? 1 : 0);
|
|
67
67
|
}
|
|
68
68
|
else {
|
|
@@ -116,7 +116,7 @@ exports.command = new command_1.Command("ext:install [extensionName]")
|
|
|
116
116
|
async function infoExtensionVersion(args) {
|
|
117
117
|
const ref = refs.parse(args.extensionName);
|
|
118
118
|
const extension = await extensionsApi.getExtension(refs.toExtensionRef(ref));
|
|
119
|
-
(0, displayExtensionInfo_1.displayExtInfo)(args.extensionName, ref.publisherId, args.extensionVersion.spec, true);
|
|
119
|
+
await (0, displayExtensionInfo_1.displayExtInfo)(args.extensionName, ref.publisherId, args.extensionVersion.spec, true);
|
|
120
120
|
await (0, warnings_1.displayWarningPrompts)(ref.publisherId, extension.registryLaunchStage, args.extensionVersion);
|
|
121
121
|
}
|
|
122
122
|
async function installToManifest(options) {
|
|
@@ -12,7 +12,7 @@ const rimraf = require("rimraf");
|
|
|
12
12
|
const utils = require("../utils");
|
|
13
13
|
const JAR_CACHE_DIR = process.env.FIREBASE_CRASHLYTICS_BUILDTOOLS_PATH ||
|
|
14
14
|
path.join(os.homedir(), ".cache", "firebase", "crashlytics", "buildtools");
|
|
15
|
-
const JAR_VERSION = "2.9.
|
|
15
|
+
const JAR_VERSION = "2.9.2";
|
|
16
16
|
const JAR_URL = `https://dl.google.com/android/maven2/com/google/firebase/firebase-crashlytics-buildtools/${JAR_VERSION}/firebase-crashlytics-buildtools-${JAR_VERSION}.jar`;
|
|
17
17
|
async function fetchBuildtoolsJar() {
|
|
18
18
|
if (process.env.CRASHLYTICS_LOCAL_JAR) {
|
|
@@ -59,15 +59,14 @@ exports.AllIngressSettings = [
|
|
|
59
59
|
"ALLOW_INTERNAL_ONLY",
|
|
60
60
|
"ALLOW_INTERNAL_AND_GCLB",
|
|
61
61
|
];
|
|
62
|
-
async function resolveBackend(build, userEnvOpt, userEnvs, nonInteractive) {
|
|
63
|
-
const projectId = userEnvOpt.projectId;
|
|
62
|
+
async function resolveBackend(build, firebaseConfig, userEnvOpt, userEnvs, nonInteractive) {
|
|
64
63
|
let paramValues = {};
|
|
65
64
|
if (previews_1.previews.functionsparams) {
|
|
66
|
-
paramValues = await params.resolveParams(build.params,
|
|
65
|
+
paramValues = await params.resolveParams(build.params, firebaseConfig, envWithTypes(build.params, userEnvs), nonInteractive);
|
|
67
66
|
const toWrite = {};
|
|
68
67
|
for (const paramName of Object.keys(paramValues)) {
|
|
69
68
|
const paramValue = paramValues[paramName];
|
|
70
|
-
if (Object.prototype.hasOwnProperty.call(userEnvs, paramName) || paramValue.
|
|
69
|
+
if (Object.prototype.hasOwnProperty.call(userEnvs, paramName) || paramValue.internal) {
|
|
71
70
|
continue;
|
|
72
71
|
}
|
|
73
72
|
toWrite[paramName] = paramValue.toString();
|
|
@@ -3,27 +3,20 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.applyBackendHashToBackends = void 0;
|
|
4
4
|
const backend_1 = require("../backend");
|
|
5
5
|
const hash_1 = require("./hash");
|
|
6
|
-
const functionsDeployHelper_1 = require("../functionsDeployHelper");
|
|
7
6
|
function applyBackendHashToBackends(wantBackends, context) {
|
|
8
7
|
var _a;
|
|
9
8
|
for (const [codebase, wantBackend] of Object.entries(wantBackends)) {
|
|
10
|
-
if ((0, functionsDeployHelper_1.isCodebaseFiltered)(codebase, context.filters || [])) {
|
|
11
|
-
continue;
|
|
12
|
-
}
|
|
13
9
|
const source = (_a = context === null || context === void 0 ? void 0 : context.sources) === null || _a === void 0 ? void 0 : _a[codebase];
|
|
14
10
|
const envHash = (0, hash_1.getEnvironmentVariablesHash)(wantBackend);
|
|
15
|
-
applyBackendHashToEndpoints(wantBackend, envHash,
|
|
11
|
+
applyBackendHashToEndpoints(wantBackend, envHash, source === null || source === void 0 ? void 0 : source.functionsSourceV1Hash, source === null || source === void 0 ? void 0 : source.functionsSourceV2Hash);
|
|
16
12
|
}
|
|
17
13
|
}
|
|
18
14
|
exports.applyBackendHashToBackends = applyBackendHashToBackends;
|
|
19
|
-
function applyBackendHashToEndpoints(wantBackend, envHash,
|
|
15
|
+
function applyBackendHashToEndpoints(wantBackend, envHash, sourceV1Hash, sourceV2Hash) {
|
|
20
16
|
for (const endpoint of (0, backend_1.allEndpoints)(wantBackend)) {
|
|
21
17
|
const secretsHash = (0, hash_1.getSecretsHash)(endpoint);
|
|
22
18
|
const isV2 = endpoint.platform === "gcfv2";
|
|
23
19
|
const sourceHash = isV2 ? sourceV2Hash : sourceV1Hash;
|
|
24
|
-
if ((0, functionsDeployHelper_1.isEndpointFiltered)(endpoint, endpointFilters)) {
|
|
25
|
-
continue;
|
|
26
|
-
}
|
|
27
20
|
endpoint.hash = (0, hash_1.getEndpointHash)(sourceHash, envHash, secretsHash);
|
|
28
21
|
}
|
|
29
22
|
}
|
|
@@ -3,13 +3,14 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.resolveExpression = exports.ExprParseError = exports.isCelExpression = void 0;
|
|
4
4
|
const error_1 = require("../../error");
|
|
5
5
|
const functional_1 = require("../../functional");
|
|
6
|
+
const paramRegexp = /params\.(\S+)/;
|
|
7
|
+
const CMP = /((?:!=)|(?:==)|(?:>=)|(?:<=)|>|<)/.source;
|
|
6
8
|
const identityRegexp = /{{ params\.(\S+) }}/;
|
|
7
|
-
const
|
|
8
|
-
const
|
|
9
|
-
const dualTernaryRegexp = /{{ params\.(\S+)
|
|
10
|
-
const ternaryRegexp = /{{ params\.(\S+)
|
|
9
|
+
const dualComparisonRegexp = new RegExp(/{{ params\.(\S+) CMP params\.(\S+) }}/.source.replace("CMP", CMP));
|
|
10
|
+
const comparisonRegexp = new RegExp(/{{ params\.(\S+) CMP (.+) }}/.source.replace("CMP", CMP));
|
|
11
|
+
const dualTernaryRegexp = new RegExp(/{{ params\.(\S+) CMP params\.(\S+) \? (.+) : (.+) }/.source.replace("CMP", CMP));
|
|
12
|
+
const ternaryRegexp = new RegExp(/{{ params\.(\S+) CMP (.+) \? (.+) : (.+) }/.source.replace("CMP", CMP));
|
|
11
13
|
const literalTernaryRegexp = /{{ params\.(\S+) \? (.+) : (.+) }/;
|
|
12
|
-
const paramRegexp = /params\.(\S+)/;
|
|
13
14
|
function isCelExpression(value) {
|
|
14
15
|
return typeof value === "string" && value.includes("{{") && value.includes("}}");
|
|
15
16
|
}
|
|
@@ -17,11 +18,11 @@ exports.isCelExpression = isCelExpression;
|
|
|
17
18
|
function isIdentityExpression(value) {
|
|
18
19
|
return identityRegexp.test(value);
|
|
19
20
|
}
|
|
20
|
-
function
|
|
21
|
-
return
|
|
21
|
+
function isComparisonExpression(value) {
|
|
22
|
+
return comparisonRegexp.test(value);
|
|
22
23
|
}
|
|
23
|
-
function
|
|
24
|
-
return
|
|
24
|
+
function isDualComparisonExpression(value) {
|
|
25
|
+
return dualComparisonRegexp.test(value);
|
|
25
26
|
}
|
|
26
27
|
function isTernaryExpression(value) {
|
|
27
28
|
return ternaryRegexp.test(value);
|
|
@@ -48,11 +49,11 @@ function resolveExpression(wantType, expr, params) {
|
|
|
48
49
|
else if (isTernaryExpression(expr)) {
|
|
49
50
|
return resolveTernary(wantType, expr, params);
|
|
50
51
|
}
|
|
51
|
-
else if (
|
|
52
|
-
return
|
|
52
|
+
else if (isDualComparisonExpression(expr)) {
|
|
53
|
+
return resolveDualComparison(expr, params);
|
|
53
54
|
}
|
|
54
|
-
else if (
|
|
55
|
-
return
|
|
55
|
+
else if (isComparisonExpression(expr)) {
|
|
56
|
+
return resolveComparison(expr, params);
|
|
56
57
|
}
|
|
57
58
|
else {
|
|
58
59
|
throw new ExprParseError("CEL expression '" + expr + "' is of an unsupported form");
|
|
@@ -93,68 +94,106 @@ function resolveIdentity(wantType, expr, params) {
|
|
|
93
94
|
}
|
|
94
95
|
return readParamValue(wantType, name, value);
|
|
95
96
|
}
|
|
96
|
-
function
|
|
97
|
-
const match =
|
|
97
|
+
function resolveComparison(expr, params) {
|
|
98
|
+
const match = comparisonRegexp.exec(expr);
|
|
98
99
|
if (!match) {
|
|
99
|
-
throw new ExprParseError("Malformed CEL
|
|
100
|
-
}
|
|
100
|
+
throw new ExprParseError("Malformed CEL comparison expression '" + expr + "'");
|
|
101
|
+
}
|
|
102
|
+
const cmp = match[2];
|
|
103
|
+
const test = function (a, b) {
|
|
104
|
+
switch (cmp) {
|
|
105
|
+
case "!=":
|
|
106
|
+
return a !== b;
|
|
107
|
+
case "==":
|
|
108
|
+
return a === b;
|
|
109
|
+
case ">=":
|
|
110
|
+
return a >= b;
|
|
111
|
+
case "<=":
|
|
112
|
+
return a <= b;
|
|
113
|
+
case ">":
|
|
114
|
+
return a > b;
|
|
115
|
+
case "<":
|
|
116
|
+
return a < b;
|
|
117
|
+
default:
|
|
118
|
+
throw new ExprParseError("Illegal comparison operator '" + cmp + "'");
|
|
119
|
+
}
|
|
120
|
+
};
|
|
101
121
|
const lhsName = match[1];
|
|
102
122
|
const lhsVal = params[lhsName];
|
|
103
123
|
if (!lhsVal) {
|
|
104
|
-
throw new ExprParseError("CEL
|
|
124
|
+
throw new ExprParseError("CEL comparison expression '" + expr + "' references missing param " + lhsName);
|
|
105
125
|
}
|
|
106
126
|
let rhs;
|
|
107
127
|
if (lhsVal.legalString) {
|
|
108
|
-
rhs = resolveLiteral("string", match[
|
|
109
|
-
return lhsVal.asString()
|
|
128
|
+
rhs = resolveLiteral("string", match[3]);
|
|
129
|
+
return test(lhsVal.asString(), rhs);
|
|
110
130
|
}
|
|
111
131
|
else if (lhsVal.legalNumber) {
|
|
112
|
-
rhs = resolveLiteral("number", match[
|
|
113
|
-
return lhsVal.asNumber()
|
|
132
|
+
rhs = resolveLiteral("number", match[3]);
|
|
133
|
+
return test(lhsVal.asNumber(), rhs);
|
|
114
134
|
}
|
|
115
135
|
else if (lhsVal.legalBoolean) {
|
|
116
|
-
rhs = resolveLiteral("boolean", match[
|
|
117
|
-
return lhsVal.asBoolean()
|
|
136
|
+
rhs = resolveLiteral("boolean", match[3]);
|
|
137
|
+
return test(lhsVal.asBoolean(), rhs);
|
|
118
138
|
}
|
|
119
139
|
else {
|
|
120
|
-
throw new ExprParseError(`Could not infer type of param ${lhsName} used in
|
|
140
|
+
throw new ExprParseError(`Could not infer type of param ${lhsName} used in comparison operation`);
|
|
121
141
|
}
|
|
122
142
|
}
|
|
123
|
-
function
|
|
124
|
-
const match =
|
|
143
|
+
function resolveDualComparison(expr, params) {
|
|
144
|
+
const match = dualComparisonRegexp.exec(expr);
|
|
125
145
|
if (!match) {
|
|
126
|
-
throw new ExprParseError("Malformed CEL
|
|
127
|
-
}
|
|
146
|
+
throw new ExprParseError("Malformed CEL comparison expression '" + expr + "'");
|
|
147
|
+
}
|
|
148
|
+
const cmp = match[2];
|
|
149
|
+
const test = function (a, b) {
|
|
150
|
+
switch (cmp) {
|
|
151
|
+
case "!=":
|
|
152
|
+
return a !== b;
|
|
153
|
+
case "==":
|
|
154
|
+
return a === b;
|
|
155
|
+
case ">=":
|
|
156
|
+
return a >= b;
|
|
157
|
+
case "<=":
|
|
158
|
+
return a <= b;
|
|
159
|
+
case ">":
|
|
160
|
+
return a > b;
|
|
161
|
+
case "<":
|
|
162
|
+
return a < b;
|
|
163
|
+
default:
|
|
164
|
+
throw new ExprParseError("Illegal comparison operator '" + cmp + "'");
|
|
165
|
+
}
|
|
166
|
+
};
|
|
128
167
|
const lhsName = match[1];
|
|
129
168
|
const lhsVal = params[lhsName];
|
|
130
169
|
if (!lhsVal) {
|
|
131
|
-
throw new ExprParseError("CEL
|
|
170
|
+
throw new ExprParseError("CEL comparison expression '" + expr + "' references missing param " + lhsName);
|
|
132
171
|
}
|
|
133
|
-
const rhsName = match[
|
|
172
|
+
const rhsName = match[3];
|
|
134
173
|
const rhsVal = params[rhsName];
|
|
135
174
|
if (!rhsVal) {
|
|
136
|
-
throw new ExprParseError("CEL
|
|
175
|
+
throw new ExprParseError("CEL comparison expression '" + expr + "' references missing param " + lhsName);
|
|
137
176
|
}
|
|
138
177
|
if (lhsVal.legalString) {
|
|
139
178
|
if (!rhsVal.legalString) {
|
|
140
|
-
throw new ExprParseError(`CEL
|
|
179
|
+
throw new ExprParseError(`CEL comparison expression ${expr} has type mismatch between the operands`);
|
|
141
180
|
}
|
|
142
|
-
return lhsVal.asString()
|
|
181
|
+
return test(lhsVal.asString(), rhsVal.asString());
|
|
143
182
|
}
|
|
144
183
|
else if (lhsVal.legalNumber) {
|
|
145
184
|
if (!rhsVal.legalNumber) {
|
|
146
|
-
throw new ExprParseError(`CEL
|
|
185
|
+
throw new ExprParseError(`CEL comparison expression ${expr} has type mismatch between the operands`);
|
|
147
186
|
}
|
|
148
|
-
return lhsVal.asNumber()
|
|
187
|
+
return test(lhsVal.asNumber(), rhsVal.asNumber());
|
|
149
188
|
}
|
|
150
189
|
else if (lhsVal.legalBoolean) {
|
|
151
190
|
if (!rhsVal.legalBoolean) {
|
|
152
|
-
throw new ExprParseError(`CEL
|
|
191
|
+
throw new ExprParseError(`CEL comparison expression ${expr} has type mismatch between the operands`);
|
|
153
192
|
}
|
|
154
|
-
return lhsVal.asBoolean()
|
|
193
|
+
return test(lhsVal.asBoolean(), rhsVal.asBoolean());
|
|
155
194
|
}
|
|
156
195
|
else {
|
|
157
|
-
throw new ExprParseError(`could not infer type of param ${lhsName} used in
|
|
196
|
+
throw new ExprParseError(`could not infer type of param ${lhsName} used in comparison operation`);
|
|
158
197
|
}
|
|
159
198
|
}
|
|
160
199
|
function resolveTernary(wantType, expr, params) {
|
|
@@ -162,13 +201,13 @@ function resolveTernary(wantType, expr, params) {
|
|
|
162
201
|
if (!match) {
|
|
163
202
|
throw new ExprParseError("malformed CEL ternary expression '" + expr + "'");
|
|
164
203
|
}
|
|
165
|
-
const
|
|
166
|
-
const isTrue =
|
|
204
|
+
const comparisonExpr = `{{ params.${match[1]} ${match[2]} ${match[3]} }}`;
|
|
205
|
+
const isTrue = resolveComparison(comparisonExpr, params);
|
|
167
206
|
if (isTrue) {
|
|
168
|
-
return resolveParamOrLiteral(wantType, match[
|
|
207
|
+
return resolveParamOrLiteral(wantType, match[4], params);
|
|
169
208
|
}
|
|
170
209
|
else {
|
|
171
|
-
return resolveParamOrLiteral(wantType, match[
|
|
210
|
+
return resolveParamOrLiteral(wantType, match[5], params);
|
|
172
211
|
}
|
|
173
212
|
}
|
|
174
213
|
function resolveDualTernary(wantType, expr, params) {
|
|
@@ -176,13 +215,13 @@ function resolveDualTernary(wantType, expr, params) {
|
|
|
176
215
|
if (!match) {
|
|
177
216
|
throw new ExprParseError("Malformed CEL ternary expression '" + expr + "'");
|
|
178
217
|
}
|
|
179
|
-
const
|
|
180
|
-
const isTrue =
|
|
218
|
+
const comparisonExpr = `{{ params.${match[1]} ${match[2]} params.${match[3]} }}`;
|
|
219
|
+
const isTrue = resolveDualComparison(comparisonExpr, params);
|
|
181
220
|
if (isTrue) {
|
|
182
|
-
return resolveParamOrLiteral(wantType, match[
|
|
221
|
+
return resolveParamOrLiteral(wantType, match[4], params);
|
|
183
222
|
}
|
|
184
223
|
else {
|
|
185
|
-
return resolveParamOrLiteral(wantType, match[
|
|
224
|
+
return resolveParamOrLiteral(wantType, match[5], params);
|
|
186
225
|
}
|
|
187
226
|
}
|
|
188
227
|
function resolveLiteralTernary(wantType, expr, params) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.deploy = void 0;
|
|
3
|
+
exports.shouldUploadBeSkipped = exports.deploy = void 0;
|
|
4
4
|
const tmp_1 = require("tmp");
|
|
5
5
|
const clc = require("colorette");
|
|
6
6
|
const fs = require("fs");
|
|
@@ -11,6 +11,7 @@ const gcs = require("../../gcp/storage");
|
|
|
11
11
|
const gcf = require("../../gcp/cloudfunctions");
|
|
12
12
|
const gcfv2 = require("../../gcp/cloudfunctionsv2");
|
|
13
13
|
const backend = require("./backend");
|
|
14
|
+
const backend_1 = require("./backend");
|
|
14
15
|
(0, tmp_1.setGracefulCleanup)();
|
|
15
16
|
async function uploadSourceV1(projectId, source, wantBackend) {
|
|
16
17
|
const v1Endpoints = backend.allEndpoints(wantBackend).filter((e) => e.platform === "gcfv1");
|
|
@@ -78,9 +79,27 @@ async function deploy(context, options, payload) {
|
|
|
78
79
|
}
|
|
79
80
|
await (0, checkIam_1.checkHttpIam)(context, options, payload);
|
|
80
81
|
const uploads = [];
|
|
81
|
-
for (const [codebase, { wantBackend }] of Object.entries(payload.functions)) {
|
|
82
|
+
for (const [codebase, { wantBackend, haveBackend }] of Object.entries(payload.functions)) {
|
|
83
|
+
if (shouldUploadBeSkipped(wantBackend, haveBackend)) {
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
82
86
|
uploads.push(uploadCodebase(context, codebase, wantBackend));
|
|
83
87
|
}
|
|
84
88
|
await Promise.all(uploads);
|
|
85
89
|
}
|
|
86
90
|
exports.deploy = deploy;
|
|
91
|
+
function shouldUploadBeSkipped(wantBackend, haveBackend) {
|
|
92
|
+
const wantEndpoints = backend.allEndpoints(wantBackend);
|
|
93
|
+
const haveEndpoints = backend.allEndpoints(haveBackend);
|
|
94
|
+
if (wantEndpoints.length !== haveEndpoints.length) {
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
97
|
+
return wantEndpoints.every((wantEndpoint) => {
|
|
98
|
+
const haveEndpoint = (0, backend_1.findEndpoint)(haveBackend, (endpoint) => endpoint.id === wantEndpoint.id);
|
|
99
|
+
if (!haveEndpoint) {
|
|
100
|
+
return false;
|
|
101
|
+
}
|
|
102
|
+
return haveEndpoint.hash && wantEndpoint.hash && haveEndpoint.hash === wantEndpoint.hash;
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
exports.shouldUploadBeSkipped = shouldUploadBeSkipped;
|
|
@@ -58,9 +58,9 @@ function isResourceInput(input) {
|
|
|
58
58
|
}
|
|
59
59
|
exports.isResourceInput = isResourceInput;
|
|
60
60
|
class ParamValue {
|
|
61
|
-
constructor(rawValue,
|
|
61
|
+
constructor(rawValue, internal, types) {
|
|
62
62
|
this.rawValue = rawValue;
|
|
63
|
-
this.
|
|
63
|
+
this.internal = internal;
|
|
64
64
|
this.legalString = types.string || false;
|
|
65
65
|
this.legalBoolean = types.boolean || false;
|
|
66
66
|
this.legalNumber = types.number || false;
|
|
@@ -82,8 +82,7 @@ exports.ParamValue = ParamValue;
|
|
|
82
82
|
function resolveDefaultCEL(type, expr, currentEnv) {
|
|
83
83
|
const deps = dependenciesCEL(expr);
|
|
84
84
|
const allDepsFound = deps.every((dep) => !!currentEnv[dep]);
|
|
85
|
-
|
|
86
|
-
if (!allDepsFound || dependsOnSecret) {
|
|
85
|
+
if (!allDepsFound) {
|
|
87
86
|
throw new error_1.FirebaseError("Build specified parameter with un-resolvable default value " +
|
|
88
87
|
expr +
|
|
89
88
|
"; dependencies missing.");
|
|
@@ -114,8 +113,8 @@ function canSatisfyParam(param, value) {
|
|
|
114
113
|
}
|
|
115
114
|
(0, functional_1.assertExhaustive)(param);
|
|
116
115
|
}
|
|
117
|
-
async function resolveParams(params,
|
|
118
|
-
const paramValues =
|
|
116
|
+
async function resolveParams(params, firebaseConfig, userEnvs, nonInteractive) {
|
|
117
|
+
const paramValues = populateDefaultParams(firebaseConfig);
|
|
119
118
|
const [resolved, outstanding] = (0, functional_1.partition)(params, (param) => {
|
|
120
119
|
return {}.hasOwnProperty.call(userEnvs, param.name);
|
|
121
120
|
});
|
|
@@ -124,7 +123,7 @@ async function resolveParams(params, projectId, userEnvs, nonInteractive) {
|
|
|
124
123
|
}
|
|
125
124
|
const [needSecret, needPrompt] = (0, functional_1.partition)(outstanding, (param) => param.type === "secret");
|
|
126
125
|
for (const param of needSecret) {
|
|
127
|
-
await handleSecret(param, projectId);
|
|
126
|
+
await handleSecret(param, firebaseConfig.projectId);
|
|
128
127
|
}
|
|
129
128
|
if (nonInteractive && needPrompt.length > 0) {
|
|
130
129
|
const envNames = outstanding.map((p) => p.name).join(", ");
|
|
@@ -141,11 +140,39 @@ async function resolveParams(params, projectId, userEnvs, nonInteractive) {
|
|
|
141
140
|
if (paramDefault && !canSatisfyParam(param, paramDefault)) {
|
|
142
141
|
throw new error_1.FirebaseError("Parameter " + param.name + " has default value " + paramDefault + " of wrong type");
|
|
143
142
|
}
|
|
144
|
-
paramValues[param.name] = await promptParam(param, projectId, paramDefault);
|
|
143
|
+
paramValues[param.name] = await promptParam(param, firebaseConfig.projectId, paramDefault);
|
|
145
144
|
}
|
|
146
145
|
return paramValues;
|
|
147
146
|
}
|
|
148
147
|
exports.resolveParams = resolveParams;
|
|
148
|
+
function populateDefaultParams(config) {
|
|
149
|
+
const defaultParams = {};
|
|
150
|
+
if (config.databaseURL !== "") {
|
|
151
|
+
defaultParams["DATABASE_URL"] = new ParamValue(config.databaseURL, true, {
|
|
152
|
+
string: true,
|
|
153
|
+
boolean: false,
|
|
154
|
+
number: false,
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
defaultParams["PROJECT_ID"] = new ParamValue(config.projectId, true, {
|
|
158
|
+
string: true,
|
|
159
|
+
boolean: false,
|
|
160
|
+
number: false,
|
|
161
|
+
});
|
|
162
|
+
defaultParams["GCLOUD_PROJECT"] = new ParamValue(config.projectId, true, {
|
|
163
|
+
string: true,
|
|
164
|
+
boolean: false,
|
|
165
|
+
number: false,
|
|
166
|
+
});
|
|
167
|
+
if (config.storageBucket !== "") {
|
|
168
|
+
defaultParams["STORAGE_BUCKET"] = new ParamValue(config.storageBucket, true, {
|
|
169
|
+
string: true,
|
|
170
|
+
boolean: false,
|
|
171
|
+
number: false,
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
return defaultParams;
|
|
175
|
+
}
|
|
149
176
|
async function handleSecret(secretParam, projectId) {
|
|
150
177
|
const metadata = await secretManager.getSecretMetadata(projectId, secretParam.name, "latest");
|
|
151
178
|
if (!metadata.secret) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.resolveCpu = exports.inferBlockingDetails = exports.inferDetailsFromExisting = exports.prepare = void 0;
|
|
3
|
+
exports.resolveCpu = exports.inferBlockingDetails = exports.updateEndpointTargetedStatus = exports.inferDetailsFromExisting = exports.prepare = void 0;
|
|
4
4
|
const clc = require("colorette");
|
|
5
5
|
const backend = require("./backend");
|
|
6
6
|
const build = require("./build");
|
|
@@ -25,6 +25,7 @@ const v1_1 = require("../../functions/events/v1");
|
|
|
25
25
|
const serviceusage_1 = require("../../gcp/serviceusage");
|
|
26
26
|
const previews_1 = require("../../previews");
|
|
27
27
|
const applyHash_1 = require("./cache/applyHash");
|
|
28
|
+
const backend_1 = require("./backend");
|
|
28
29
|
function hasUserConfig(config) {
|
|
29
30
|
return Object.keys(config).length > 1;
|
|
30
31
|
}
|
|
@@ -81,12 +82,13 @@ async function prepare(context, options, payload) {
|
|
|
81
82
|
const userEnvs = functionsEnv.loadUserEnvs(userEnvOpt);
|
|
82
83
|
const envs = Object.assign(Object.assign({}, userEnvs), firebaseEnvs);
|
|
83
84
|
const wantBuild = await runtimeDelegate.discoverBuild(runtimeConfig, firebaseEnvs);
|
|
84
|
-
const { backend: wantBackend, envs: resolvedEnvs } = await build.resolveBackend(wantBuild, userEnvOpt, userEnvs, options.nonInteractive);
|
|
85
|
+
const { backend: wantBackend, envs: resolvedEnvs } = await build.resolveBackend(wantBuild, firebaseConfig, userEnvOpt, userEnvs, options.nonInteractive);
|
|
85
86
|
let hasEnvsFromParams = false;
|
|
86
87
|
wantBackend.environmentVariables = envs;
|
|
87
88
|
for (const envName of Object.keys(resolvedEnvs)) {
|
|
88
89
|
const envValue = (_a = resolvedEnvs[envName]) === null || _a === void 0 ? void 0 : _a.toString();
|
|
89
90
|
if (envValue &&
|
|
91
|
+
!resolvedEnvs[envName].internal &&
|
|
90
92
|
!Object.prototype.hasOwnProperty.call(wantBackend.environmentVariables, envName)) {
|
|
91
93
|
wantBackend.environmentVariables[envName] = envValue;
|
|
92
94
|
hasEnvsFromParams = true;
|
|
@@ -187,6 +189,7 @@ async function prepare(context, options, payload) {
|
|
|
187
189
|
await (0, checkIam_1.ensureServiceAgentRoles)(projectId, projectNumber, matchingBackend, haveBackend);
|
|
188
190
|
await validate.secretsAreValid(projectId, matchingBackend);
|
|
189
191
|
await ensure.secretAccess(projectId, matchingBackend, haveBackend);
|
|
192
|
+
updateEndpointTargetedStatus(wantBackends, context.filters || []);
|
|
190
193
|
if (previews_1.previews.skipdeployingnoopfunctions) {
|
|
191
194
|
(0, applyHash_1.applyBackendHashToBackends)(wantBackends, context);
|
|
192
195
|
}
|
|
@@ -229,6 +232,14 @@ function maybeCopyTriggerRegion(wantE, haveE) {
|
|
|
229
232
|
}
|
|
230
233
|
wantE.eventTrigger.region = haveE.eventTrigger.region;
|
|
231
234
|
}
|
|
235
|
+
function updateEndpointTargetedStatus(wantBackends, endpointFilters) {
|
|
236
|
+
for (const wantBackend of Object.values(wantBackends)) {
|
|
237
|
+
for (const endpoint of (0, backend_1.allEndpoints)(wantBackend)) {
|
|
238
|
+
endpoint.targetedByOnly = (0, functionsDeployHelper_1.endpointMatchesAnyFilter)(endpoint, endpointFilters);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
exports.updateEndpointTargetedStatus = updateEndpointTargetedStatus;
|
|
232
243
|
function inferBlockingDetails(want) {
|
|
233
244
|
var _a, _b, _c;
|
|
234
245
|
const authBlockingEndpoints = backend
|
|
@@ -37,10 +37,11 @@ async function getFunctionsConfig(projectId) {
|
|
|
37
37
|
}
|
|
38
38
|
exports.getFunctionsConfig = getFunctionsConfig;
|
|
39
39
|
async function pipeAsync(from, to) {
|
|
40
|
+
from.pipe(to);
|
|
41
|
+
await from.finalize();
|
|
40
42
|
return new Promise((resolve, reject) => {
|
|
41
43
|
to.on("finish", resolve);
|
|
42
44
|
to.on("error", reject);
|
|
43
|
-
from.pipe(to);
|
|
44
45
|
});
|
|
45
46
|
}
|
|
46
47
|
async function packageSource(sourceDir, config, runtimeConfig) {
|
|
@@ -72,7 +73,6 @@ async function packageSource(sourceDir, config, runtimeConfig) {
|
|
|
72
73
|
mode: 420,
|
|
73
74
|
});
|
|
74
75
|
}
|
|
75
|
-
await archive.finalize();
|
|
76
76
|
await pipeAsync(archive, fileStream);
|
|
77
77
|
}
|
|
78
78
|
catch (err) {
|
|
@@ -18,6 +18,7 @@ function calculateChangesets(want, have, keyFn, deleteAll) {
|
|
|
18
18
|
.map((id) => have[id]), keyFn);
|
|
19
19
|
const { skipdeployingnoopfunctions } = previews_1.previews;
|
|
20
20
|
const toSkipPredicate = (id) => !!(skipdeployingnoopfunctions &&
|
|
21
|
+
!want[id].targetedByOnly &&
|
|
21
22
|
have[id].hash &&
|
|
22
23
|
want[id].hash &&
|
|
23
24
|
want[id].hash === have[id].hash);
|
|
@@ -6,6 +6,7 @@ const auth_1 = require("./auth");
|
|
|
6
6
|
const storage_1 = require("./storage");
|
|
7
7
|
const firebaseAlerts_1 = require("./firebaseAlerts");
|
|
8
8
|
const database_1 = require("./database");
|
|
9
|
+
const remoteConfig_1 = require("./remoteConfig");
|
|
9
10
|
const noop = () => Promise.resolve();
|
|
10
11
|
exports.noop = noop;
|
|
11
12
|
const noopProjectBindings = () => Promise.resolve([]);
|
|
@@ -55,6 +56,15 @@ const databaseService = {
|
|
|
55
56
|
registerTrigger: exports.noop,
|
|
56
57
|
unregisterTrigger: exports.noop,
|
|
57
58
|
};
|
|
59
|
+
const remoteConfigService = {
|
|
60
|
+
name: "remoteconfig",
|
|
61
|
+
api: "firebaseremoteconfig.googleapis.com",
|
|
62
|
+
requiredProjectBindings: exports.noopProjectBindings,
|
|
63
|
+
ensureTriggerRegion: remoteConfig_1.ensureRemoteConfigTriggerRegion,
|
|
64
|
+
validateTrigger: exports.noop,
|
|
65
|
+
registerTrigger: exports.noop,
|
|
66
|
+
unregisterTrigger: exports.noop,
|
|
67
|
+
};
|
|
58
68
|
const EVENT_SERVICE_MAPPING = {
|
|
59
69
|
"google.cloud.pubsub.topic.v1.messagePublished": pubSubService,
|
|
60
70
|
"google.cloud.storage.object.v1.finalized": storageService,
|
|
@@ -68,6 +78,7 @@ const EVENT_SERVICE_MAPPING = {
|
|
|
68
78
|
"google.firebase.database.ref.v1.created": databaseService,
|
|
69
79
|
"google.firebase.database.ref.v1.updated": databaseService,
|
|
70
80
|
"google.firebase.database.ref.v1.deleted": databaseService,
|
|
81
|
+
"google.firebase.remoteconfig.remoteConfig.v1.updated": remoteConfigService,
|
|
71
82
|
};
|
|
72
83
|
function serviceForEndpoint(endpoint) {
|
|
73
84
|
if (backend.isEventTriggered(endpoint)) {
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ensureRemoteConfigTriggerRegion = void 0;
|
|
4
|
+
const error_1 = require("../../../error");
|
|
5
|
+
function ensureRemoteConfigTriggerRegion(endpoint) {
|
|
6
|
+
if (!endpoint.eventTrigger.region) {
|
|
7
|
+
endpoint.eventTrigger.region = "global";
|
|
8
|
+
}
|
|
9
|
+
if (endpoint.eventTrigger.region !== "global") {
|
|
10
|
+
throw new error_1.FirebaseError("A remote config trigger must specify 'global' trigger location");
|
|
11
|
+
}
|
|
12
|
+
return Promise.resolve();
|
|
13
|
+
}
|
|
14
|
+
exports.ensureRemoteConfigTriggerRegion = ensureRemoteConfigTriggerRegion;
|
|
@@ -70,6 +70,12 @@ function specWithEmulatorServer(protocol, host) {
|
|
|
70
70
|
async function createApp(defaultProjectId, projectStateForId = new Map()) {
|
|
71
71
|
const app = express();
|
|
72
72
|
app.set("json spaces", 2);
|
|
73
|
+
app.use("/", (req, res, next) => {
|
|
74
|
+
if (req.headers["access-control-request-private-network"]) {
|
|
75
|
+
res.setHeader("access-control-allow-private-network", "true");
|
|
76
|
+
}
|
|
77
|
+
next();
|
|
78
|
+
});
|
|
73
79
|
app.use(cors({ origin: true }));
|
|
74
80
|
app.delete("*", (req, _, next) => {
|
|
75
81
|
delete req.headers["content-type"];
|
|
@@ -290,8 +290,10 @@ class ProjectState {
|
|
|
290
290
|
if (this instanceof TenantProjectState) {
|
|
291
291
|
(0, errors_1.assert)(record.tenantId === this.tenantId, "TENANT_ID_MISMATCH");
|
|
292
292
|
}
|
|
293
|
+
const user = this.getUserByLocalId(record.localId);
|
|
294
|
+
(0, errors_1.assert)(user, "INVALID_REFRESH_TOKEN");
|
|
293
295
|
return {
|
|
294
|
-
user
|
|
296
|
+
user,
|
|
295
297
|
provider: record.provider,
|
|
296
298
|
extraClaims: record.extraClaims,
|
|
297
299
|
secondFactor: record.secondFactor,
|
|
@@ -18,13 +18,13 @@ const EMULATOR_INSTANCE_KILL_TIMEOUT = 4000;
|
|
|
18
18
|
const CACHE_DIR = process.env.FIREBASE_EMULATORS_PATH || path.join(os.homedir(), ".cache", "firebase", "emulators");
|
|
19
19
|
exports.DownloadDetails = {
|
|
20
20
|
database: {
|
|
21
|
-
downloadPath: path.join(CACHE_DIR, "firebase-database-emulator-v4.
|
|
22
|
-
version: "4.
|
|
21
|
+
downloadPath: path.join(CACHE_DIR, "firebase-database-emulator-v4.9.0.jar"),
|
|
22
|
+
version: "4.9.0",
|
|
23
23
|
opts: {
|
|
24
24
|
cacheDir: CACHE_DIR,
|
|
25
|
-
remoteUrl: "https://storage.googleapis.com/firebase-preview-drop/emulator/firebase-database-emulator-v4.
|
|
26
|
-
expectedSize:
|
|
27
|
-
expectedChecksum: "
|
|
25
|
+
remoteUrl: "https://storage.googleapis.com/firebase-preview-drop/emulator/firebase-database-emulator-v4.9.0.jar",
|
|
26
|
+
expectedSize: 34204485,
|
|
27
|
+
expectedChecksum: "1c3f5974f0ee5559ebf27b56f2e62108",
|
|
28
28
|
namePrefix: "firebase-database-emulator",
|
|
29
29
|
},
|
|
30
30
|
},
|
|
@@ -40,13 +40,13 @@ exports.DownloadDetails = {
|
|
|
40
40
|
},
|
|
41
41
|
},
|
|
42
42
|
storage: {
|
|
43
|
-
downloadPath: path.join(CACHE_DIR, "cloud-storage-rules-runtime-v1.
|
|
44
|
-
version: "1.
|
|
43
|
+
downloadPath: path.join(CACHE_DIR, "cloud-storage-rules-runtime-v1.1.1.jar"),
|
|
44
|
+
version: "1.1.1",
|
|
45
45
|
opts: {
|
|
46
46
|
cacheDir: CACHE_DIR,
|
|
47
|
-
remoteUrl: "https://storage.googleapis.com/firebase-preview-drop/emulator/cloud-storage-rules-runtime-v1.
|
|
48
|
-
expectedSize:
|
|
49
|
-
expectedChecksum: "
|
|
47
|
+
remoteUrl: "https://storage.googleapis.com/firebase-preview-drop/emulator/cloud-storage-rules-runtime-v1.1.1.jar",
|
|
48
|
+
expectedSize: 46448285,
|
|
49
|
+
expectedChecksum: "691982db4019d49d345a97151bdea7e2",
|
|
50
50
|
namePrefix: "cloud-storage-rules-emulator",
|
|
51
51
|
},
|
|
52
52
|
},
|