firebase-tools 10.4.0 → 10.5.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/accountExporter.js +95 -84
- package/lib/bin/firebase.js +1 -1
- package/lib/commands/emulators-start.js +6 -1
- package/lib/commands/ext-configure.js +4 -4
- package/lib/commands/ext-dev-emulators-start.js +5 -1
- package/lib/commands/ext-install.js +5 -4
- package/lib/commands/ext-update.js +2 -1
- package/lib/commands/functions-config-export.js +3 -1
- package/lib/config.js +11 -4
- package/lib/deploy/functions/checkIam.js +44 -1
- package/lib/deploy/functions/deploy.js +3 -7
- package/lib/deploy/functions/prepare.js +7 -5
- package/lib/deploy/functions/prepareFunctionsUpload.js +7 -13
- package/lib/deploy/functions/release/fabricator.js +13 -1
- package/lib/deploy/functions/release/index.js +1 -1
- package/lib/deploy/functions/services/firebaseAlerts.js +1 -17
- package/lib/deploy/functions/services/index.js +2 -1
- package/lib/deploy/hosting/deploy.js +10 -0
- package/lib/emulator/auth/operations.js +21 -20
- package/lib/emulator/auth/state.js +79 -43
- package/lib/emulator/commandUtils.js +72 -2
- package/lib/emulator/controller.js +23 -8
- package/lib/emulator/downloadableEmulators.js +18 -11
- package/lib/emulator/functionsEmulator.js +8 -18
- package/lib/emulator/functionsEmulatorShared.js +27 -1
- package/lib/emulator/shared/request.js +19 -0
- package/lib/emulator/storage/apis/firebase.js +20 -28
- package/lib/emulator/storage/apis/gcloud.js +69 -57
- package/lib/emulator/storage/files.js +42 -49
- package/lib/emulator/storage/index.js +14 -2
- package/lib/emulator/storage/rules/utils.js +11 -3
- package/lib/extensions/askUserForParam.js +43 -15
- package/lib/extensions/extensionsHelper.js +11 -2
- package/lib/extensions/paramHelper.js +7 -3
- package/lib/functions/projectConfig.js +34 -0
- package/lib/init/features/functions/index.js +4 -2
- package/lib/init/features/hosting/index.js +32 -41
- package/lib/init/features/index.js +22 -12
- package/lib/init/index.js +28 -11
- package/lib/requirePermissions.js +4 -1
- package/lib/serve/functions.js +5 -5
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
- package/schema/firebase-config.json +93 -36
- package/lib/emulator/storage/list.js +0 -18
|
@@ -48,15 +48,14 @@ async function pipeAsync(from, to) {
|
|
|
48
48
|
from.pipe(to);
|
|
49
49
|
});
|
|
50
50
|
}
|
|
51
|
-
async function packageSource(
|
|
52
|
-
var _a;
|
|
51
|
+
async function packageSource(sourceDir, config, runtimeConfig) {
|
|
53
52
|
const tmpFile = tmp.fileSync({ prefix: "firebase-functions-", postfix: ".zip" }).name;
|
|
54
53
|
const fileStream = fs.createWriteStream(tmpFile, {
|
|
55
54
|
flags: "w",
|
|
56
55
|
encoding: "binary",
|
|
57
56
|
});
|
|
58
57
|
const archive = archiver("zip");
|
|
59
|
-
const ignore =
|
|
58
|
+
const ignore = config.ignore || ["node_modules", ".git"];
|
|
60
59
|
ignore.push("firebase-debug.log", "firebase-debug.*.log", CONFIG_DEST_FILE);
|
|
61
60
|
try {
|
|
62
61
|
const files = await fsAsync.readdirRecursive({ path: sourceDir, ignore: ignore });
|
|
@@ -66,8 +65,8 @@ async function packageSource(options, sourceDir, configValues) {
|
|
|
66
65
|
mode: file.mode,
|
|
67
66
|
});
|
|
68
67
|
});
|
|
69
|
-
if (typeof
|
|
70
|
-
archive.append(JSON.stringify(
|
|
68
|
+
if (typeof runtimeConfig !== "undefined") {
|
|
69
|
+
archive.append(JSON.stringify(runtimeConfig, null, 2), {
|
|
71
70
|
name: CONFIG_DEST_FILE,
|
|
72
71
|
mode: 420,
|
|
73
72
|
});
|
|
@@ -81,20 +80,15 @@ async function packageSource(options, sourceDir, configValues) {
|
|
|
81
80
|
exit: 1,
|
|
82
81
|
});
|
|
83
82
|
}
|
|
84
|
-
utils.assertDefined(options.config.src.functions);
|
|
85
|
-
utils.assertDefined(options.config.src.functions.source, "Error: 'functions.source' is not defined");
|
|
86
83
|
utils.logBullet(clc.cyan.bold("functions:") +
|
|
87
84
|
" packaged " +
|
|
88
|
-
clc.bold(
|
|
85
|
+
clc.bold(sourceDir) +
|
|
89
86
|
" (" +
|
|
90
87
|
filesize(archive.pointer()) +
|
|
91
88
|
") for uploading");
|
|
92
89
|
return tmpFile;
|
|
93
90
|
}
|
|
94
|
-
async function prepareFunctionsUpload(
|
|
95
|
-
|
|
96
|
-
utils.assertDefined(options.config.src.functions.source, "Error: 'functions.source' is not defined");
|
|
97
|
-
const sourceDir = options.config.path(options.config.src.functions.source);
|
|
98
|
-
return packageSource(options, sourceDir, runtimeConfig);
|
|
91
|
+
async function prepareFunctionsUpload(sourceDir, config, runtimeConfig) {
|
|
92
|
+
return packageSource(sourceDir, config, runtimeConfig);
|
|
99
93
|
}
|
|
100
94
|
exports.prepareFunctionsUpload = prepareFunctionsUpload;
|
|
@@ -180,6 +180,13 @@ class Fabricator {
|
|
|
180
180
|
.catch(rethrowAs(endpoint, "set invoker"));
|
|
181
181
|
}
|
|
182
182
|
}
|
|
183
|
+
else if (backend.isCallableTriggered(endpoint)) {
|
|
184
|
+
await this.executor
|
|
185
|
+
.run(async () => {
|
|
186
|
+
await gcf.setInvokerCreate(endpoint.project, backend.functionName(endpoint), ["public"]);
|
|
187
|
+
})
|
|
188
|
+
.catch(rethrowAs(endpoint, "set invoker"));
|
|
189
|
+
}
|
|
183
190
|
else if (backend.isTaskQueueTriggered(endpoint)) {
|
|
184
191
|
const invoker = endpoint.taskQueueTrigger.invoker;
|
|
185
192
|
if (invoker && !invoker.includes("private")) {
|
|
@@ -232,12 +239,17 @@ class Fabricator {
|
|
|
232
239
|
.catch(rethrowAs(endpoint, "set invoker"));
|
|
233
240
|
}
|
|
234
241
|
}
|
|
242
|
+
else if (backend.isCallableTriggered(endpoint)) {
|
|
243
|
+
await this.executor
|
|
244
|
+
.run(() => run.setInvokerCreate(endpoint.project, serviceName, ["public"]))
|
|
245
|
+
.catch(rethrowAs(endpoint, "set invoker"));
|
|
246
|
+
}
|
|
235
247
|
else if (backend.isTaskQueueTriggered(endpoint)) {
|
|
236
248
|
const invoker = endpoint.taskQueueTrigger.invoker;
|
|
237
249
|
if (invoker && !invoker.includes("private")) {
|
|
238
250
|
await this.executor
|
|
239
251
|
.run(async () => {
|
|
240
|
-
await
|
|
252
|
+
await run.setInvokerCreate(endpoint.project, serviceName, invoker);
|
|
241
253
|
})
|
|
242
254
|
.catch(rethrowAs(endpoint, "set invoker"));
|
|
243
255
|
}
|
|
@@ -15,7 +15,7 @@ const functionsConfig_1 = require("../../../functionsConfig");
|
|
|
15
15
|
const functionsDeployHelper_1 = require("../functionsDeployHelper");
|
|
16
16
|
const error_1 = require("../../../error");
|
|
17
17
|
async function release(context, options, payload) {
|
|
18
|
-
if (!
|
|
18
|
+
if (!context.config) {
|
|
19
19
|
return;
|
|
20
20
|
}
|
|
21
21
|
const plan = planner.createDeploymentPlan(payload.functions.backend, await backend.existingBackend(context), { filters: context.filters });
|
|
@@ -1,23 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ensureFirebaseAlertsTriggerRegion =
|
|
3
|
+
exports.ensureFirebaseAlertsTriggerRegion = void 0;
|
|
4
4
|
const error_1 = require("../../../error");
|
|
5
|
-
exports.SERVICE_ACCOUNT_TOKEN_CREATOR_ROLE = "roles/iam.serviceAccountTokenCreator";
|
|
6
|
-
function obtainFirebaseAlertsBindings(projectNumber, existingPolicy) {
|
|
7
|
-
const pubsubServiceAgent = `serviceAccount:service-${projectNumber}@gcp-sa-pubsub.iam.gserviceaccount.com`;
|
|
8
|
-
let pubsubBinding = existingPolicy.bindings.find((b) => b.role === exports.SERVICE_ACCOUNT_TOKEN_CREATOR_ROLE);
|
|
9
|
-
if (!pubsubBinding) {
|
|
10
|
-
pubsubBinding = {
|
|
11
|
-
role: exports.SERVICE_ACCOUNT_TOKEN_CREATOR_ROLE,
|
|
12
|
-
members: [],
|
|
13
|
-
};
|
|
14
|
-
}
|
|
15
|
-
if (!pubsubBinding.members.find((m) => m === pubsubServiceAgent)) {
|
|
16
|
-
pubsubBinding.members.push(pubsubServiceAgent);
|
|
17
|
-
}
|
|
18
|
-
return Promise.resolve([pubsubBinding]);
|
|
19
|
-
}
|
|
20
|
-
exports.obtainFirebaseAlertsBindings = obtainFirebaseAlertsBindings;
|
|
21
5
|
function ensureFirebaseAlertsTriggerRegion(endpoint) {
|
|
22
6
|
if (!endpoint.eventTrigger.region) {
|
|
23
7
|
endpoint.eventTrigger.region = "global";
|
|
@@ -5,6 +5,7 @@ const backend = require("../backend");
|
|
|
5
5
|
const storage_1 = require("./storage");
|
|
6
6
|
const firebaseAlerts_1 = require("./firebaseAlerts");
|
|
7
7
|
const noop = () => Promise.resolve();
|
|
8
|
+
const noopProjectBindings = () => Promise.resolve([]);
|
|
8
9
|
exports.NoOpService = {
|
|
9
10
|
name: "noop",
|
|
10
11
|
api: "",
|
|
@@ -26,7 +27,7 @@ exports.StorageService = {
|
|
|
26
27
|
exports.FirebaseAlertsService = {
|
|
27
28
|
name: "firebasealerts",
|
|
28
29
|
api: "logging.googleapis.com",
|
|
29
|
-
requiredProjectBindings:
|
|
30
|
+
requiredProjectBindings: noopProjectBindings,
|
|
30
31
|
ensureTriggerRegion: firebaseAlerts_1.ensureFirebaseAlertsTriggerRegion,
|
|
31
32
|
};
|
|
32
33
|
exports.EVENT_SERVICE_MAPPING = {
|
|
@@ -41,12 +41,22 @@ async function deploy(context, options) {
|
|
|
41
41
|
const publicDir = options.config.path(deploy.config.public);
|
|
42
42
|
const files = (0, listFiles_1.listFiles)(publicDir, deploy.config.ignore);
|
|
43
43
|
(0, utils_1.logLabeledBullet)(`hosting[${deploy.site}]`, `found ${files.length} files in ${clc.bold(deploy.config.public)}`);
|
|
44
|
+
let concurrency = 200;
|
|
45
|
+
const envConcurrency = (0, utils_1.envOverride)("FIREBASE_HOSTING_UPLOAD_CONCURRENCY", "");
|
|
46
|
+
if (envConcurrency) {
|
|
47
|
+
const c = parseInt(envConcurrency, 10);
|
|
48
|
+
if (!isNaN(c) && c > 0) {
|
|
49
|
+
concurrency = c;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
logger_1.logger.debug(`[hosting] uploading with ${concurrency} concurrency`);
|
|
44
53
|
const uploader = new uploader_1.Uploader({
|
|
45
54
|
version: deploy.version,
|
|
46
55
|
files: files,
|
|
47
56
|
public: publicDir,
|
|
48
57
|
cwd: options.cwd,
|
|
49
58
|
projectRoot: (0, detectProjectRoot_1.detectProjectRoot)(options),
|
|
59
|
+
uploadConcurrency: concurrency,
|
|
50
60
|
});
|
|
51
61
|
const progressInterval = setInterval(() => updateSpinner(uploader.statusMessage(), debugging), debugging ? 2000 : 200);
|
|
52
62
|
try {
|
|
@@ -39,6 +39,7 @@ exports.authOperations = {
|
|
|
39
39
|
projects: {
|
|
40
40
|
createSessionCookie,
|
|
41
41
|
queryAccounts,
|
|
42
|
+
updateConfig,
|
|
42
43
|
accounts: {
|
|
43
44
|
_: signUp,
|
|
44
45
|
delete: deleteAccount,
|
|
@@ -1236,28 +1237,17 @@ function getEmulatorProjectConfig(state) {
|
|
|
1236
1237
|
usageMode: state.usageMode,
|
|
1237
1238
|
};
|
|
1238
1239
|
}
|
|
1239
|
-
function updateEmulatorProjectConfig(state, reqBody) {
|
|
1240
|
+
function updateEmulatorProjectConfig(state, reqBody, ctx) {
|
|
1240
1241
|
var _a;
|
|
1241
|
-
const
|
|
1242
|
-
if (allowDuplicateEmails != null) {
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
if (usageMode != null) {
|
|
1248
|
-
(0, errors_1.assert)(state instanceof state_1.AgentProjectState, "((Only top level projects can set usageMode.))");
|
|
1249
|
-
switch (usageMode) {
|
|
1250
|
-
case "PASSTHROUGH":
|
|
1251
|
-
(0, errors_1.assert)(state.getUserCount() === 0, "Users are present, unable to set passthrough mode");
|
|
1252
|
-
state.usageMode = state_1.UsageMode.PASSTHROUGH;
|
|
1253
|
-
break;
|
|
1254
|
-
case "DEFAULT":
|
|
1255
|
-
state.usageMode = state_1.UsageMode.DEFAULT;
|
|
1256
|
-
break;
|
|
1257
|
-
default:
|
|
1258
|
-
throw new errors_1.BadRequestError("Invalid usage mode provided");
|
|
1259
|
-
}
|
|
1242
|
+
const updateMask = [];
|
|
1243
|
+
if (((_a = reqBody.signIn) === null || _a === void 0 ? void 0 : _a.allowDuplicateEmails) != null) {
|
|
1244
|
+
updateMask.push("signIn.allowDuplicateEmails");
|
|
1245
|
+
}
|
|
1246
|
+
if (reqBody.usageMode) {
|
|
1247
|
+
updateMask.push("usageMode");
|
|
1260
1248
|
}
|
|
1249
|
+
ctx.params.query.updateMask = updateMask.join();
|
|
1250
|
+
updateConfig(state, reqBody, ctx);
|
|
1261
1251
|
return getEmulatorProjectConfig(state);
|
|
1262
1252
|
}
|
|
1263
1253
|
function listOobCodesInProject(state) {
|
|
@@ -1390,6 +1380,17 @@ function mfaSignInFinalize(state, reqBody) {
|
|
|
1390
1380
|
refreshToken,
|
|
1391
1381
|
};
|
|
1392
1382
|
}
|
|
1383
|
+
function updateConfig(state, reqBody, ctx) {
|
|
1384
|
+
var _a;
|
|
1385
|
+
(0, errors_1.assert)(state instanceof state_1.AgentProjectState, "((Can only update top-level configurations on agent projects.))");
|
|
1386
|
+
for (const event in (_a = reqBody.blockingFunctions) === null || _a === void 0 ? void 0 : _a.triggers) {
|
|
1387
|
+
if (Object.prototype.hasOwnProperty.call(reqBody.blockingFunctions.triggers, event)) {
|
|
1388
|
+
(0, errors_1.assert)(Object.values(state_1.BlockingFunctionEvents).includes(event), "INVALID_BLOCKING_FUNCTION: ((Event type is invalid.))");
|
|
1389
|
+
(0, errors_1.assert)((0, utils_1.parseAbsoluteUri)(reqBody.blockingFunctions.triggers[event].functionUri), "INVALID_BLOCKING_FUNCTION: ((Expected an absolute URI with valid scheme and host.))");
|
|
1390
|
+
}
|
|
1391
|
+
}
|
|
1392
|
+
return state.updateConfig(reqBody, ctx.params.query.updateMask);
|
|
1393
|
+
}
|
|
1393
1394
|
function coercePrimitiveToString(value) {
|
|
1394
1395
|
switch (typeof value) {
|
|
1395
1396
|
case "string":
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.UsageMode = exports.TenantProjectState = exports.AgentProjectState = exports.ProjectState = exports.SIGNIN_METHOD_EMAIL_LINK = exports.PROVIDER_GAME_CENTER = exports.PROVIDER_CUSTOM = exports.PROVIDER_ANONYMOUS = exports.PROVIDER_PHONE = exports.PROVIDER_PASSWORD = void 0;
|
|
3
|
+
exports.BlockingFunctionEvents = exports.UsageMode = exports.TenantProjectState = exports.AgentProjectState = exports.ProjectState = exports.SIGNIN_METHOD_EMAIL_LINK = exports.PROVIDER_GAME_CENTER = exports.PROVIDER_CUSTOM = exports.PROVIDER_ANONYMOUS = exports.PROVIDER_PHONE = exports.PROVIDER_PASSWORD = void 0;
|
|
4
4
|
const utils_1 = require("./utils");
|
|
5
5
|
const cloudFunctions_1 = require("./cloudFunctions");
|
|
6
6
|
const errors_1 = require("./errors");
|
|
@@ -422,25 +422,28 @@ exports.ProjectState = ProjectState;
|
|
|
422
422
|
class AgentProjectState extends ProjectState {
|
|
423
423
|
constructor(projectId) {
|
|
424
424
|
super(projectId);
|
|
425
|
-
this._oneAccountPerEmail = true;
|
|
426
|
-
this._usageMode = UsageMode.DEFAULT;
|
|
427
425
|
this.tenantProjectForTenantId = new Map();
|
|
428
426
|
this._authCloudFunction = new cloudFunctions_1.AuthCloudFunction(this.projectId);
|
|
427
|
+
this._config = {
|
|
428
|
+
signIn: { allowDuplicateEmails: false },
|
|
429
|
+
usageMode: UsageMode.DEFAULT,
|
|
430
|
+
blockingFunctions: {},
|
|
431
|
+
};
|
|
429
432
|
}
|
|
430
433
|
get authCloudFunction() {
|
|
431
434
|
return this._authCloudFunction;
|
|
432
435
|
}
|
|
433
436
|
get oneAccountPerEmail() {
|
|
434
|
-
return this.
|
|
437
|
+
return !this._config.signIn.allowDuplicateEmails;
|
|
435
438
|
}
|
|
436
439
|
set oneAccountPerEmail(oneAccountPerEmail) {
|
|
437
|
-
this.
|
|
440
|
+
this._config.signIn.allowDuplicateEmails = !oneAccountPerEmail;
|
|
438
441
|
}
|
|
439
442
|
get usageMode() {
|
|
440
|
-
return this.
|
|
443
|
+
return this._config.usageMode;
|
|
441
444
|
}
|
|
442
445
|
set usageMode(usageMode) {
|
|
443
|
-
this.
|
|
446
|
+
this._config.usageMode = usageMode;
|
|
444
447
|
}
|
|
445
448
|
get allowPasswordSignup() {
|
|
446
449
|
return true;
|
|
@@ -457,6 +460,31 @@ class AgentProjectState extends ProjectState {
|
|
|
457
460
|
get enableEmailLinkSignin() {
|
|
458
461
|
return true;
|
|
459
462
|
}
|
|
463
|
+
get config() {
|
|
464
|
+
return this._config;
|
|
465
|
+
}
|
|
466
|
+
get blockingFunctionsConfig() {
|
|
467
|
+
return this._config.blockingFunctions;
|
|
468
|
+
}
|
|
469
|
+
set blockingFunctionsConfig(blockingFunctions) {
|
|
470
|
+
this._config.blockingFunctions = blockingFunctions;
|
|
471
|
+
}
|
|
472
|
+
updateConfig(update, updateMask) {
|
|
473
|
+
var _a, _b, _c, _d;
|
|
474
|
+
if (update.usageMode) {
|
|
475
|
+
(0, errors_1.assert)(update.usageMode !== UsageMode.USAGE_MODE_UNSPECIFIED, "INVALID_USAGE_MODE: ((Invalid usage mode provided.))");
|
|
476
|
+
if (update.usageMode === UsageMode.PASSTHROUGH) {
|
|
477
|
+
(0, errors_1.assert)(this.getUserCount() === 0, "USERS_STILL_EXIST: ((Users are present, unable to set passthrough mode.))");
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
if (!updateMask) {
|
|
481
|
+
this.oneAccountPerEmail = (_b = !((_a = update.signIn) === null || _a === void 0 ? void 0 : _a.allowDuplicateEmails)) !== null && _b !== void 0 ? _b : true;
|
|
482
|
+
this.blockingFunctionsConfig = (_c = update.blockingFunctions) !== null && _c !== void 0 ? _c : {};
|
|
483
|
+
this.usageMode = (_d = update.usageMode) !== null && _d !== void 0 ? _d : UsageMode.DEFAULT;
|
|
484
|
+
return this.config;
|
|
485
|
+
}
|
|
486
|
+
return applyMask(updateMask, this.config, update);
|
|
487
|
+
}
|
|
460
488
|
getTenantProject(tenantId) {
|
|
461
489
|
if (!this.tenantProjectForTenantId.has(tenantId)) {
|
|
462
490
|
this.createTenantWithTenantId(tenantId, {
|
|
@@ -574,40 +602,21 @@ class TenantProjectState extends ProjectState {
|
|
|
574
602
|
};
|
|
575
603
|
return this.tenantConfig;
|
|
576
604
|
}
|
|
577
|
-
|
|
578
|
-
for (const path of paths) {
|
|
579
|
-
const fields = path.split(".");
|
|
580
|
-
let updateField = update;
|
|
581
|
-
let existingField = this._tenantConfig;
|
|
582
|
-
let field;
|
|
583
|
-
for (let i = 0; i < fields.length - 1; i++) {
|
|
584
|
-
field = fields[i];
|
|
585
|
-
if (updateField[field] == null) {
|
|
586
|
-
console.warn(`Unable to find field '${field}' in update '${updateField}`);
|
|
587
|
-
break;
|
|
588
|
-
}
|
|
589
|
-
if (Array.isArray(updateField[field]) ||
|
|
590
|
-
Object(updateField[field]) !== updateField[field]) {
|
|
591
|
-
console.warn(`Field '${field}' is singular and cannot have sub-fields`);
|
|
592
|
-
break;
|
|
593
|
-
}
|
|
594
|
-
if (!existingField[field]) {
|
|
595
|
-
existingField[field] = {};
|
|
596
|
-
}
|
|
597
|
-
updateField = updateField[field];
|
|
598
|
-
existingField = existingField[field];
|
|
599
|
-
}
|
|
600
|
-
field = fields[fields.length - 1];
|
|
601
|
-
if (updateField[field] == null) {
|
|
602
|
-
console.warn(`Unable to find field '${field}' in update '${JSON.stringify(updateField)}`);
|
|
603
|
-
continue;
|
|
604
|
-
}
|
|
605
|
-
existingField[field] = updateField[field];
|
|
606
|
-
}
|
|
607
|
-
return this.tenantConfig;
|
|
605
|
+
return applyMask(updateMask, this.tenantConfig, update);
|
|
608
606
|
}
|
|
609
607
|
}
|
|
610
608
|
exports.TenantProjectState = TenantProjectState;
|
|
609
|
+
var UsageMode;
|
|
610
|
+
(function (UsageMode) {
|
|
611
|
+
UsageMode["USAGE_MODE_UNSPECIFIED"] = "USAGE_MODE_UNSPECIFIED";
|
|
612
|
+
UsageMode["DEFAULT"] = "DEFAULT";
|
|
613
|
+
UsageMode["PASSTHROUGH"] = "PASSTHROUGH";
|
|
614
|
+
})(UsageMode = exports.UsageMode || (exports.UsageMode = {}));
|
|
615
|
+
var BlockingFunctionEvents;
|
|
616
|
+
(function (BlockingFunctionEvents) {
|
|
617
|
+
BlockingFunctionEvents["BEFORE_CREATE"] = "beforeCreate";
|
|
618
|
+
BlockingFunctionEvents["BEFORE_SIGN_IN"] = "beforeSignIn";
|
|
619
|
+
})(BlockingFunctionEvents = exports.BlockingFunctionEvents || (exports.BlockingFunctionEvents = {}));
|
|
611
620
|
function getProviderEmailsForUser(user) {
|
|
612
621
|
var _a;
|
|
613
622
|
const emails = new Set();
|
|
@@ -618,8 +627,35 @@ function getProviderEmailsForUser(user) {
|
|
|
618
627
|
});
|
|
619
628
|
return emails;
|
|
620
629
|
}
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
630
|
+
function applyMask(updateMask, dest, update) {
|
|
631
|
+
const paths = updateMask.split(",");
|
|
632
|
+
for (const path of paths) {
|
|
633
|
+
const fields = path.split(".");
|
|
634
|
+
let updateField = update;
|
|
635
|
+
let existingField = dest;
|
|
636
|
+
let field;
|
|
637
|
+
for (let i = 0; i < fields.length - 1; i++) {
|
|
638
|
+
field = fields[i];
|
|
639
|
+
if (updateField[field] == null) {
|
|
640
|
+
console.warn(`Unable to find field '${field}' in update '${updateField}`);
|
|
641
|
+
break;
|
|
642
|
+
}
|
|
643
|
+
if (Array.isArray(updateField[field]) || Object(updateField[field]) !== updateField[field]) {
|
|
644
|
+
console.warn(`Field '${field}' is singular and cannot have sub-fields`);
|
|
645
|
+
break;
|
|
646
|
+
}
|
|
647
|
+
if (!existingField[field]) {
|
|
648
|
+
existingField[field] = {};
|
|
649
|
+
}
|
|
650
|
+
updateField = updateField[field];
|
|
651
|
+
existingField = existingField[field];
|
|
652
|
+
}
|
|
653
|
+
field = fields[fields.length - 1];
|
|
654
|
+
if (updateField[field] == null) {
|
|
655
|
+
console.warn(`Unable to find field '${field}' in update '${JSON.stringify(updateField)}`);
|
|
656
|
+
continue;
|
|
657
|
+
}
|
|
658
|
+
existingField[field] = updateField[field];
|
|
659
|
+
}
|
|
660
|
+
return dest;
|
|
661
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.emulatorExec = exports.shutdownWhenKilled = exports.setExportOnExitOptions = exports.parseInspectionPort = exports.beforeEmulatorCommand = exports.warnEmulatorNotSupported = exports.printNoticeIfEmulated = exports.DESC_TEST_PARAMS = exports.FLAG_TEST_PARAMS = exports.DESC_TEST_CONFIG = exports.FLAG_TEST_CONFIG = exports.DESC_UI = exports.FLAG_UI = exports.EXPORT_ON_EXIT_CWD_DANGER = exports.EXPORT_ON_EXIT_USAGE_ERROR = exports.DESC_EXPORT_ON_EXIT = exports.FLAG_EXPORT_ON_EXIT = exports.FLAG_EXPORT_ON_EXIT_NAME = exports.DESC_IMPORT = exports.FLAG_IMPORT = exports.DESC_INSPECT_FUNCTIONS = exports.FLAG_INSPECT_FUNCTIONS = exports.DESC_ONLY = exports.FLAG_ONLY = void 0;
|
|
3
|
+
exports.JAVA_DEPRECATION_WARNING = exports.checkJavaSupported = exports.emulatorExec = exports.shutdownWhenKilled = exports.setExportOnExitOptions = exports.parseInspectionPort = exports.beforeEmulatorCommand = exports.warnEmulatorNotSupported = exports.printNoticeIfEmulated = exports.DESC_TEST_PARAMS = exports.FLAG_TEST_PARAMS = exports.DESC_TEST_CONFIG = exports.FLAG_TEST_CONFIG = exports.DESC_UI = exports.FLAG_UI = exports.EXPORT_ON_EXIT_CWD_DANGER = exports.EXPORT_ON_EXIT_USAGE_ERROR = exports.DESC_EXPORT_ON_EXIT = exports.FLAG_EXPORT_ON_EXIT = exports.FLAG_EXPORT_ON_EXIT_NAME = exports.DESC_IMPORT = exports.FLAG_IMPORT = exports.DESC_INSPECT_FUNCTIONS = exports.FLAG_INSPECT_FUNCTIONS = exports.DESC_ONLY = exports.FLAG_ONLY = void 0;
|
|
4
4
|
const clc = require("cli-color");
|
|
5
5
|
const childProcess = require("child_process");
|
|
6
6
|
const controller = require("../emulator/controller");
|
|
@@ -287,15 +287,19 @@ async function emulatorExec(script, options) {
|
|
|
287
287
|
extraEnv.GCLOUD_PROJECT = projectId;
|
|
288
288
|
}
|
|
289
289
|
let exitCode = 0;
|
|
290
|
+
let deprecationNotices;
|
|
290
291
|
try {
|
|
291
292
|
const showUI = !!options.ui;
|
|
292
|
-
await controller.startAll(options, showUI);
|
|
293
|
+
({ deprecationNotices } = await controller.startAll(options, showUI));
|
|
293
294
|
exitCode = await runScript(script, extraEnv);
|
|
294
295
|
await (0, controller_1.onExit)(options);
|
|
295
296
|
}
|
|
296
297
|
finally {
|
|
297
298
|
await controller.cleanShutdown();
|
|
298
299
|
}
|
|
300
|
+
for (const notice of deprecationNotices) {
|
|
301
|
+
utils.logLabeledWarning("emulators", notice, "warn");
|
|
302
|
+
}
|
|
299
303
|
if (exitCode !== 0) {
|
|
300
304
|
throw new error_1.FirebaseError(`Script "${clc.bold(script)}" exited with code ${exitCode}`, {
|
|
301
305
|
exit: exitCode,
|
|
@@ -303,3 +307,69 @@ async function emulatorExec(script, options) {
|
|
|
303
307
|
}
|
|
304
308
|
}
|
|
305
309
|
exports.emulatorExec = emulatorExec;
|
|
310
|
+
const JAVA_VERSION_REGEX = /version "([1-9][0-9]*)/;
|
|
311
|
+
const MIN_SUPPORTED_JAVA_MAJOR_VERSION = 11;
|
|
312
|
+
const JAVA_HINT = "Please make sure Java is installed and on your system PATH.";
|
|
313
|
+
async function checkJavaSupported() {
|
|
314
|
+
return new Promise((resolve, reject) => {
|
|
315
|
+
var _a, _b;
|
|
316
|
+
let child;
|
|
317
|
+
try {
|
|
318
|
+
child = childProcess.spawn("java", ["-Duser.language=en", "-Dfile.encoding=UTF-8", "-version"], {
|
|
319
|
+
stdio: ["inherit", "pipe", "pipe"],
|
|
320
|
+
});
|
|
321
|
+
}
|
|
322
|
+
catch (err) {
|
|
323
|
+
return reject(new error_1.FirebaseError(`Could not spawn \`java -version\`. ${JAVA_HINT}`, { original: err }));
|
|
324
|
+
}
|
|
325
|
+
let output = "";
|
|
326
|
+
let error = "";
|
|
327
|
+
(_a = child.stdout) === null || _a === void 0 ? void 0 : _a.on("data", (data) => {
|
|
328
|
+
const str = data.toString("utf8");
|
|
329
|
+
logger_1.logger.debug(str);
|
|
330
|
+
output += str;
|
|
331
|
+
});
|
|
332
|
+
(_b = child.stderr) === null || _b === void 0 ? void 0 : _b.on("data", (data) => {
|
|
333
|
+
const str = data.toString("utf8");
|
|
334
|
+
logger_1.logger.debug(str);
|
|
335
|
+
error += str;
|
|
336
|
+
});
|
|
337
|
+
child.once("error", (err) => {
|
|
338
|
+
reject(new error_1.FirebaseError(`Could not spawn \`java -version\`. ${JAVA_HINT}`, { original: err }));
|
|
339
|
+
});
|
|
340
|
+
child.once("exit", (code, signal) => {
|
|
341
|
+
if (signal) {
|
|
342
|
+
reject(new error_1.FirebaseError(`Process \`java -version\` was killed by signal ${signal}.`));
|
|
343
|
+
}
|
|
344
|
+
else if (code && code !== 0) {
|
|
345
|
+
reject(new error_1.FirebaseError(`Process \`java -version\` has exited with code ${code}. ${JAVA_HINT}\n` +
|
|
346
|
+
`-----Original stdout-----\n${output}` +
|
|
347
|
+
`-----Original stderr-----\n${error}`));
|
|
348
|
+
}
|
|
349
|
+
else {
|
|
350
|
+
resolve(`${output}\n${error}`);
|
|
351
|
+
}
|
|
352
|
+
});
|
|
353
|
+
}).then((output) => {
|
|
354
|
+
const match = output.match(JAVA_VERSION_REGEX);
|
|
355
|
+
if (match) {
|
|
356
|
+
const version = match[1];
|
|
357
|
+
const versionInt = parseInt(version, 10);
|
|
358
|
+
if (!versionInt) {
|
|
359
|
+
utils.logLabeledWarning("emulators", `Failed to parse Java version. Got "${match[0]}".`, "warn");
|
|
360
|
+
}
|
|
361
|
+
else {
|
|
362
|
+
logger_1.logger.debug(`Parsed Java major version: ${versionInt}`);
|
|
363
|
+
return versionInt >= MIN_SUPPORTED_JAVA_MAJOR_VERSION;
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
else {
|
|
367
|
+
logger_1.logger.debug("java -version outputs:", output);
|
|
368
|
+
logger_1.logger.warn(`Failed to parse Java version.`);
|
|
369
|
+
}
|
|
370
|
+
return false;
|
|
371
|
+
});
|
|
372
|
+
}
|
|
373
|
+
exports.checkJavaSupported = checkJavaSupported;
|
|
374
|
+
exports.JAVA_DEPRECATION_WARNING = "Support for Java version <= 10 will be dropped soon in firebase-tools@11. " +
|
|
375
|
+
"Please upgrade to Java version 11 or above to continue using the emulators.";
|
|
@@ -38,6 +38,8 @@ const getDefaultDatabaseInstance_1 = require("../getDefaultDatabaseInstance");
|
|
|
38
38
|
const auth_2 = require("../auth");
|
|
39
39
|
const extensionsEmulator_1 = require("./extensionsEmulator");
|
|
40
40
|
const previews_1 = require("../previews");
|
|
41
|
+
const projectConfig_1 = require("../functions/projectConfig");
|
|
42
|
+
const downloadableEmulators_1 = require("./downloadableEmulators");
|
|
41
43
|
const START_LOGGING_EMULATOR = utils.envOverride("START_LOGGING_EMULATOR", "false", (val) => val === "true");
|
|
42
44
|
async function getAndCheckAddress(emulator, options) {
|
|
43
45
|
var _a, _b, _c, _d;
|
|
@@ -140,7 +142,7 @@ function filterEmulatorTargets(options) {
|
|
|
140
142
|
}
|
|
141
143
|
exports.filterEmulatorTargets = filterEmulatorTargets;
|
|
142
144
|
function shouldStart(options, name) {
|
|
143
|
-
var _a, _b
|
|
145
|
+
var _a, _b;
|
|
144
146
|
if (name === types_1.Emulators.HUB) {
|
|
145
147
|
return !!options.project;
|
|
146
148
|
}
|
|
@@ -155,9 +157,15 @@ function shouldStart(options, name) {
|
|
|
155
157
|
}
|
|
156
158
|
return (!!options.project && targets.some((target) => types_1.EMULATORS_SUPPORTED_BY_UI.includes(target)));
|
|
157
159
|
}
|
|
158
|
-
if (name === types_1.Emulators.FUNCTIONS && emulatorInTargets
|
|
159
|
-
|
|
160
|
-
|
|
160
|
+
if (name === types_1.Emulators.FUNCTIONS && emulatorInTargets) {
|
|
161
|
+
try {
|
|
162
|
+
(0, projectConfig_1.normalizeAndValidate)(options.config.src.functions);
|
|
163
|
+
return true;
|
|
164
|
+
}
|
|
165
|
+
catch (err) {
|
|
166
|
+
emulatorLogger_1.EmulatorLogger.forEmulator(types_1.Emulators.FUNCTIONS).logLabeled("WARN", "functions", `The functions emulator is configured but there is no functions source directory. Have you run ${clc.bold("firebase init functions")}?`);
|
|
167
|
+
return false;
|
|
168
|
+
}
|
|
161
169
|
}
|
|
162
170
|
if (name === types_1.Emulators.HOSTING && emulatorInTargets && !options.config.get("hosting")) {
|
|
163
171
|
emulatorLogger_1.EmulatorLogger.forEmulator(types_1.Emulators.HOSTING).logLabeled("WARN", "hosting", `The hosting emulator is configured but there is no hosting configuration. Have you run ${clc.bold("firebase init hosting")}?`);
|
|
@@ -209,6 +217,13 @@ async function startAll(options, showUI = true) {
|
|
|
209
217
|
if (targets.length === 0) {
|
|
210
218
|
throw new error_1.FirebaseError(`No emulators to start, run ${clc.bold("firebase init emulators")} to get started.`);
|
|
211
219
|
}
|
|
220
|
+
const deprecationNotices = [];
|
|
221
|
+
if (targets.some(downloadableEmulators_1.requiresJava)) {
|
|
222
|
+
if (!(await commandUtils.checkJavaSupported())) {
|
|
223
|
+
utils.logLabeledWarning("emulators", commandUtils_1.JAVA_DEPRECATION_WARNING, "warn");
|
|
224
|
+
deprecationNotices.push(commandUtils_1.JAVA_DEPRECATION_WARNING);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
212
227
|
const hubLogger = emulatorLogger_1.EmulatorLogger.forEmulator(types_1.Emulators.HUB);
|
|
213
228
|
hubLogger.logLabeled("BULLET", "emulators", `Starting emulators: ${targets.join(", ")}`);
|
|
214
229
|
const projectId = (0, projectUtils_1.getProjectId)(options) || "";
|
|
@@ -253,16 +268,15 @@ async function startAll(options, showUI = true) {
|
|
|
253
268
|
const emulatableBackends = [];
|
|
254
269
|
const projectDir = (options.extDevDir || options.config.projectDir);
|
|
255
270
|
if (shouldStart(options, types_1.Emulators.FUNCTIONS)) {
|
|
256
|
-
|
|
257
|
-
utils.assertDefined(options.config.src.functions.source, "Error: 'functions.source' is not defined");
|
|
271
|
+
const functionsCfg = (0, projectConfig_1.normalizeAndValidate)(options.config.src.functions)[0];
|
|
258
272
|
utils.assertIsStringOrUndefined(options.extDevDir);
|
|
259
|
-
const functionsDir = path.join(projectDir,
|
|
273
|
+
const functionsDir = path.join(projectDir, functionsCfg.source);
|
|
260
274
|
emulatableBackends.push({
|
|
261
275
|
functionsDir,
|
|
262
276
|
env: Object.assign({}, options.extDevEnv),
|
|
263
277
|
secretEnv: [],
|
|
264
278
|
predefinedTriggers: options.extDevTriggers,
|
|
265
|
-
nodeMajorVersion: (0, functionsEmulatorUtils_1.parseRuntimeVersion)(options.extDevNodeVersion ||
|
|
279
|
+
nodeMajorVersion: (0, functionsEmulatorUtils_1.parseRuntimeVersion)(options.extDevNodeVersion || functionsCfg.runtime),
|
|
266
280
|
});
|
|
267
281
|
}
|
|
268
282
|
if (shouldStart(options, types_1.Emulators.EXTENSIONS) && previews_1.previews.extensionsemulator) {
|
|
@@ -473,6 +487,7 @@ async function startAll(options, showUI = true) {
|
|
|
473
487
|
await instance.connect();
|
|
474
488
|
}
|
|
475
489
|
}
|
|
490
|
+
return { deprecationNotices };
|
|
476
491
|
}
|
|
477
492
|
exports.startAll = startAll;
|
|
478
493
|
async function exportEmulatorData(exportPath, options) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.start = exports.downloadIfNecessary = exports.stop = exports.getPID = exports.get = exports.getDownloadDetails = exports.handleEmulatorProcessError = exports._getCommand = exports.getLogFileName = exports.DownloadDetails = void 0;
|
|
3
|
+
exports.start = exports.downloadIfNecessary = exports.stop = exports.getPID = exports.get = exports.getDownloadDetails = exports.requiresJava = exports.handleEmulatorProcessError = exports._getCommand = exports.getLogFileName = exports.DownloadDetails = void 0;
|
|
4
4
|
const types_1 = require("./types");
|
|
5
5
|
const constants_1 = require("./constants");
|
|
6
6
|
const error_1 = require("../error");
|
|
@@ -29,24 +29,24 @@ exports.DownloadDetails = {
|
|
|
29
29
|
},
|
|
30
30
|
},
|
|
31
31
|
firestore: {
|
|
32
|
-
downloadPath: path.join(CACHE_DIR, "cloud-firestore-emulator-v1.
|
|
33
|
-
version: "1.
|
|
32
|
+
downloadPath: path.join(CACHE_DIR, "cloud-firestore-emulator-v1.14.1.jar"),
|
|
33
|
+
version: "1.14.1",
|
|
34
34
|
opts: {
|
|
35
35
|
cacheDir: CACHE_DIR,
|
|
36
|
-
remoteUrl: "https://storage.googleapis.com/firebase-preview-drop/emulator/cloud-firestore-emulator-v1.
|
|
37
|
-
expectedSize:
|
|
38
|
-
expectedChecksum: "
|
|
36
|
+
remoteUrl: "https://storage.googleapis.com/firebase-preview-drop/emulator/cloud-firestore-emulator-v1.14.1.jar",
|
|
37
|
+
expectedSize: 60416634,
|
|
38
|
+
expectedChecksum: "33cffe8065d4250816f257eb19245932",
|
|
39
39
|
namePrefix: "cloud-firestore-emulator",
|
|
40
40
|
},
|
|
41
41
|
},
|
|
42
42
|
storage: {
|
|
43
|
-
downloadPath: path.join(CACHE_DIR, "cloud-storage-rules-runtime-v1.0.
|
|
44
|
-
version: "1.0.
|
|
43
|
+
downloadPath: path.join(CACHE_DIR, "cloud-storage-rules-runtime-v1.0.2.jar"),
|
|
44
|
+
version: "1.0.2",
|
|
45
45
|
opts: {
|
|
46
46
|
cacheDir: CACHE_DIR,
|
|
47
|
-
remoteUrl: "https://storage.googleapis.com/firebase-preview-drop/emulator/cloud-storage-rules-runtime-v1.0.
|
|
48
|
-
expectedSize:
|
|
49
|
-
expectedChecksum: "
|
|
47
|
+
remoteUrl: "https://storage.googleapis.com/firebase-preview-drop/emulator/cloud-storage-rules-runtime-v1.0.2.jar",
|
|
48
|
+
expectedSize: 35704306,
|
|
49
|
+
expectedChecksum: "0dd3e17939610fc3dbdf53fb24cfda86",
|
|
50
50
|
namePrefix: "cloud-storage-rules-emulator",
|
|
51
51
|
},
|
|
52
52
|
},
|
|
@@ -236,6 +236,13 @@ async function handleEmulatorProcessError(emulator, err) {
|
|
|
236
236
|
}
|
|
237
237
|
}
|
|
238
238
|
exports.handleEmulatorProcessError = handleEmulatorProcessError;
|
|
239
|
+
function requiresJava(emulator) {
|
|
240
|
+
if (emulator in Commands) {
|
|
241
|
+
return Commands[emulator].binary === "java";
|
|
242
|
+
}
|
|
243
|
+
return false;
|
|
244
|
+
}
|
|
245
|
+
exports.requiresJava = requiresJava;
|
|
239
246
|
async function _runBinary(emulator, command, extraEnv) {
|
|
240
247
|
return new Promise((resolve) => {
|
|
241
248
|
var _a, _b;
|