firebase-tools 10.3.0 → 10.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/accountExporter.js +95 -84
- package/lib/commands/deploy.js +1 -1
- package/lib/commands/experimental-functions-shell.js +1 -1
- package/lib/commands/ext-configure.js +13 -6
- package/lib/commands/ext-export.js +7 -1
- package/lib/commands/ext-install.js +12 -7
- package/lib/commands/ext-update.js +5 -3
- package/lib/commands/functions-config-export.js +5 -3
- package/lib/commands/functions-shell.js +1 -1
- package/lib/commands/hosting-channel-create.js +2 -2
- package/lib/commands/hosting-channel-delete.js +2 -2
- package/lib/commands/hosting-channel-deploy.js +2 -2
- package/lib/commands/hosting-channel-list.js +2 -2
- package/lib/commands/hosting-channel-open.js +2 -2
- package/lib/commands/hosting-sites-delete.js +2 -2
- package/lib/commands/serve.js +1 -1
- package/lib/commands/target-apply.js +2 -2
- package/lib/commands/target-clear.js +2 -2
- package/lib/commands/target-remove.js +2 -2
- package/lib/commands/target.js +2 -2
- package/lib/config.js +14 -4
- package/lib/deploy/extensions/planner.js +9 -3
- 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/runtimes/node/parseTriggers.js +12 -5
- package/lib/deploy/hosting/deploy.js +10 -0
- package/lib/emulator/auth/apiSpec.js +37 -0
- package/lib/emulator/commandUtils.js +2 -2
- package/lib/emulator/controller.js +14 -8
- package/lib/emulator/downloadableEmulators.js +5 -5
- package/lib/emulator/extensionsEmulator.js +3 -0
- package/lib/emulator/functionsEmulator.js +4 -4
- package/lib/emulator/functionsEmulatorShared.js +17 -1
- package/lib/emulator/storage/apis/firebase.js +4 -6
- package/lib/emulator/storage/files.js +5 -5
- package/lib/emulator/storage/index.js +6 -9
- package/lib/emulator/storage/rules/config.js +6 -5
- package/lib/emulator/storage/rules/manager.js +49 -32
- package/lib/emulator/storage/rules/runtime.js +4 -0
- package/lib/emulator/storage/rules/utils.js +2 -2
- package/lib/emulator/storage/server.js +1 -1
- package/lib/extensions/askUserForParam.js +103 -28
- package/lib/extensions/manifest.js +38 -6
- package/lib/extensions/paramHelper.js +28 -6
- package/lib/fsutils.js +14 -1
- package/lib/functions/projectConfig.js +34 -0
- package/lib/gcp/cloudfunctions.js +5 -4
- 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/requireConfig.js +11 -9
- 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/prepareUpload.js +0 -44
|
@@ -8,13 +8,13 @@ const prompt_1 = require("../prompt");
|
|
|
8
8
|
const error_1 = require("../error");
|
|
9
9
|
const requirePermissions_1 = require("../requirePermissions");
|
|
10
10
|
const projectUtils_1 = require("../projectUtils");
|
|
11
|
-
const
|
|
11
|
+
const requireConfig_1 = require("../requireConfig");
|
|
12
12
|
const logger_1 = require("../logger");
|
|
13
13
|
const LOG_TAG = "hosting:sites";
|
|
14
14
|
exports.default = new command_1.Command("hosting:sites:delete <siteId>")
|
|
15
15
|
.description("delete a Firebase Hosting site")
|
|
16
16
|
.withForce()
|
|
17
|
-
.before(requireConfig)
|
|
17
|
+
.before(requireConfig_1.requireConfig)
|
|
18
18
|
.before(requirePermissions_1.requirePermissions, ["firebasehosting.sites.delete"])
|
|
19
19
|
.action(async (siteId, options) => {
|
|
20
20
|
const projectId = (0, projectUtils_1.needProjectId)(options);
|
package/lib/commands/serve.js
CHANGED
|
@@ -5,7 +5,7 @@ var { Command } = require("../command");
|
|
|
5
5
|
const { logger } = require("../logger");
|
|
6
6
|
var utils = require("../utils");
|
|
7
7
|
var { requirePermissions } = require("../requirePermissions");
|
|
8
|
-
var requireConfig = require("../requireConfig");
|
|
8
|
+
var { requireConfig } = require("../requireConfig");
|
|
9
9
|
var { serve } = require("../serve/index");
|
|
10
10
|
var { filterTargets } = require("../filterTargets");
|
|
11
11
|
var { needProjectNumber } = require("../projectUtils");
|
|
@@ -3,12 +3,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
const clc = require("cli-color");
|
|
4
4
|
const command_1 = require("../command");
|
|
5
5
|
const logger_1 = require("../logger");
|
|
6
|
-
const
|
|
6
|
+
const requireConfig_1 = require("../requireConfig");
|
|
7
7
|
const utils = require("../utils");
|
|
8
8
|
const error_1 = require("../error");
|
|
9
9
|
exports.default = new command_1.Command("target:apply <type> <name> <resources...>")
|
|
10
10
|
.description("apply a deploy target to a resource")
|
|
11
|
-
.before(requireConfig)
|
|
11
|
+
.before(requireConfig_1.requireConfig)
|
|
12
12
|
.action((type, name, resources, options) => {
|
|
13
13
|
if (!options.project) {
|
|
14
14
|
throw new error_1.FirebaseError(`Must have an active project to set deploy targets. Try ${clc.bold("firebase use --add")}`);
|
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const clc = require("cli-color");
|
|
4
4
|
const command_1 = require("../command");
|
|
5
|
-
const
|
|
5
|
+
const requireConfig_1 = require("../requireConfig");
|
|
6
6
|
const utils = require("../utils");
|
|
7
7
|
exports.default = new command_1.Command("target:clear <type> <target>")
|
|
8
8
|
.description("clear all resources from a named resource target")
|
|
9
|
-
.before(requireConfig)
|
|
9
|
+
.before(requireConfig_1.requireConfig)
|
|
10
10
|
.action((type, name, options) => {
|
|
11
11
|
const existed = options.rc.clearTarget(options.project, type, name);
|
|
12
12
|
if (existed) {
|
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const clc = require("cli-color");
|
|
4
4
|
const command_1 = require("../command");
|
|
5
|
-
const
|
|
5
|
+
const requireConfig_1 = require("../requireConfig");
|
|
6
6
|
const utils = require("../utils");
|
|
7
7
|
exports.default = new command_1.Command("target:remove <type> <resource>")
|
|
8
8
|
.description("remove a resource target")
|
|
9
|
-
.before(requireConfig)
|
|
9
|
+
.before(requireConfig_1.requireConfig)
|
|
10
10
|
.action((type, resource, options) => {
|
|
11
11
|
const name = options.rc.removeTarget(options.project, type, resource);
|
|
12
12
|
if (name) {
|
package/lib/commands/target.js
CHANGED
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
const clc = require("cli-color");
|
|
4
4
|
const command_1 = require("../command");
|
|
5
5
|
const logger_1 = require("../logger");
|
|
6
|
-
const
|
|
6
|
+
const requireConfig_1 = require("../requireConfig");
|
|
7
7
|
const utils = require("../utils");
|
|
8
8
|
function logTargets(type, targets) {
|
|
9
9
|
logger_1.logger.info(clc.cyan("[ " + type + " ]"));
|
|
@@ -13,7 +13,7 @@ function logTargets(type, targets) {
|
|
|
13
13
|
}
|
|
14
14
|
exports.default = new command_1.Command("target [type]")
|
|
15
15
|
.description("display configured deploy targets for the current project")
|
|
16
|
-
.before(requireConfig)
|
|
16
|
+
.before(requireConfig_1.requireConfig)
|
|
17
17
|
.action((type, options) => {
|
|
18
18
|
if (!options.project) {
|
|
19
19
|
return utils.reject("No active project, cannot list deploy targets.");
|
package/lib/config.js
CHANGED
|
@@ -39,10 +39,17 @@ class Config {
|
|
|
39
39
|
_.set(this.data, target, this.materialize(target));
|
|
40
40
|
}
|
|
41
41
|
});
|
|
42
|
-
if (this.projectDir &&
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
42
|
+
if (this.projectDir && fsutils.dirExistsSync(this.path(Config.DEFAULT_FUNCTIONS_SOURCE))) {
|
|
43
|
+
if (Array.isArray(this.get("functions"))) {
|
|
44
|
+
if (!this.get("functions.[0].source")) {
|
|
45
|
+
this.set("functions.[0].source", Config.DEFAULT_FUNCTIONS_SOURCE);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
if (!this.get("functions.source")) {
|
|
50
|
+
this.set("functions.source", Config.DEFAULT_FUNCTIONS_SOURCE);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
46
53
|
}
|
|
47
54
|
}
|
|
48
55
|
materialize(target) {
|
|
@@ -144,6 +151,9 @@ class Config {
|
|
|
144
151
|
fs.ensureFileSync(this.path(p));
|
|
145
152
|
fs.writeFileSync(this.path(p), content, "utf8");
|
|
146
153
|
}
|
|
154
|
+
projectFileExists(p) {
|
|
155
|
+
return fs.existsSync(this.path(p));
|
|
156
|
+
}
|
|
147
157
|
deleteProjectFile(p) {
|
|
148
158
|
fs.removeSync(this.path(p));
|
|
149
159
|
}
|
|
@@ -81,11 +81,17 @@ async function want(args) {
|
|
|
81
81
|
}
|
|
82
82
|
exports.want = want;
|
|
83
83
|
async function resolveVersion(ref) {
|
|
84
|
-
if (!ref.version || ref.version === "latest") {
|
|
85
|
-
return "latest";
|
|
86
|
-
}
|
|
87
84
|
const extensionRef = refs.toExtensionRef(ref);
|
|
88
85
|
const versions = await extensionsApi.listExtensionVersions(extensionRef);
|
|
86
|
+
if (versions.length === 0) {
|
|
87
|
+
throw new error_1.FirebaseError(`No versions found for ${extensionRef}`);
|
|
88
|
+
}
|
|
89
|
+
if (!ref.version || ref.version === "latest") {
|
|
90
|
+
return versions
|
|
91
|
+
.map((ev) => ev.spec.version)
|
|
92
|
+
.sort(semver.compare)
|
|
93
|
+
.pop();
|
|
94
|
+
}
|
|
89
95
|
const maxSatisfying = semver.maxSatisfying(versions.map((ev) => ev.spec.version), ref.version);
|
|
90
96
|
if (!maxSatisfying) {
|
|
91
97
|
throw new error_1.FirebaseError(`No version of ${extensionRef} matches requested version ${ref.version}`);
|
|
@@ -9,7 +9,6 @@ const utils_1 = require("../../utils");
|
|
|
9
9
|
const gcs = require("../../gcp/storage");
|
|
10
10
|
const gcf = require("../../gcp/cloudfunctions");
|
|
11
11
|
const gcfv2 = require("../../gcp/cloudfunctionsv2");
|
|
12
|
-
const utils = require("../../utils");
|
|
13
12
|
const backend = require("./backend");
|
|
14
13
|
(0, tmp_1.setGracefulCleanup)();
|
|
15
14
|
async function uploadSourceV1(context, region) {
|
|
@@ -33,7 +32,7 @@ async function uploadSourceV2(context, region) {
|
|
|
33
32
|
context.storage = Object.assign(Object.assign({}, context.storage), { [region]: res.storageSource });
|
|
34
33
|
}
|
|
35
34
|
async function deploy(context, options, payload) {
|
|
36
|
-
if (!
|
|
35
|
+
if (!context.config) {
|
|
37
36
|
return;
|
|
38
37
|
}
|
|
39
38
|
if (!context.functionsSourceV1 && !context.functionsSourceV2) {
|
|
@@ -53,12 +52,9 @@ async function deploy(context, options, payload) {
|
|
|
53
52
|
}
|
|
54
53
|
}
|
|
55
54
|
await Promise.all(uploads);
|
|
56
|
-
|
|
55
|
+
const source = context.config.source;
|
|
57
56
|
if (uploads.length) {
|
|
58
|
-
(0, utils_1.logSuccess)(clc.green.bold("functions:")
|
|
59
|
-
" " +
|
|
60
|
-
clc.bold(options.config.src.functions.source) +
|
|
61
|
-
" folder uploaded successfully");
|
|
57
|
+
(0, utils_1.logSuccess)(`${clc.green.bold("functions:")} ${clc.bold(source)} folder uploaded successfully`);
|
|
62
58
|
}
|
|
63
59
|
}
|
|
64
60
|
catch (err) {
|
|
@@ -19,6 +19,7 @@ const logger_1 = require("../../logger");
|
|
|
19
19
|
const triggerRegionHelper_1 = require("./triggerRegionHelper");
|
|
20
20
|
const checkIam_1 = require("./checkIam");
|
|
21
21
|
const error_1 = require("../../error");
|
|
22
|
+
const projectConfig_1 = require("../../functions/projectConfig");
|
|
22
23
|
function hasUserConfig(config) {
|
|
23
24
|
return Object.keys(config).length > 1;
|
|
24
25
|
}
|
|
@@ -28,16 +29,17 @@ function hasDotenv(opts) {
|
|
|
28
29
|
async function prepare(context, options, payload) {
|
|
29
30
|
const projectId = (0, projectUtils_1.needProjectId)(options);
|
|
30
31
|
const projectNumber = await (0, projectUtils_1.needProjectNumber)(options);
|
|
31
|
-
|
|
32
|
+
context.config = (0, projectConfig_1.normalizeAndValidate)(options.config.src.functions)[0];
|
|
33
|
+
const sourceDirName = context.config.source;
|
|
32
34
|
if (!sourceDirName) {
|
|
33
|
-
throw new error_1.FirebaseError(`No functions code detected at default location (./functions), and no functions
|
|
35
|
+
throw new error_1.FirebaseError(`No functions code detected at default location (./functions), and no functions source defined in firebase.json`);
|
|
34
36
|
}
|
|
35
37
|
const sourceDir = options.config.path(sourceDirName);
|
|
36
38
|
const delegateContext = {
|
|
37
39
|
projectId,
|
|
38
40
|
sourceDir,
|
|
39
41
|
projectDir: options.config.projectDir,
|
|
40
|
-
runtime:
|
|
42
|
+
runtime: context.config.runtime || "",
|
|
41
43
|
};
|
|
42
44
|
const runtimeDelegate = await runtimes.getRuntimeDelegate(delegateContext);
|
|
43
45
|
logger_1.logger.debug(`Validating ${runtimeDelegate.name} source`);
|
|
@@ -95,10 +97,10 @@ async function prepare(context, options, payload) {
|
|
|
95
97
|
" directory for uploading...");
|
|
96
98
|
}
|
|
97
99
|
if (backend.someEndpoint(wantBackend, (e) => e.platform === "gcfv1")) {
|
|
98
|
-
context.functionsSourceV1 = await (0, prepareFunctionsUpload_1.prepareFunctionsUpload)(
|
|
100
|
+
context.functionsSourceV1 = await (0, prepareFunctionsUpload_1.prepareFunctionsUpload)(sourceDir, context.config, runtimeConfig);
|
|
99
101
|
}
|
|
100
102
|
if (backend.someEndpoint(wantBackend, (e) => e.platform === "gcfv2")) {
|
|
101
|
-
context.functionsSourceV2 = await (0, prepareFunctionsUpload_1.prepareFunctionsUpload)(
|
|
103
|
+
context.functionsSourceV2 = await (0, prepareFunctionsUpload_1.prepareFunctionsUpload)(sourceDir, context.config);
|
|
102
104
|
}
|
|
103
105
|
for (const endpoint of backend.allEndpoints(wantBackend)) {
|
|
104
106
|
endpoint.environmentVariables = wantBackend.environmentVariables;
|
|
@@ -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 });
|
|
@@ -73,6 +73,7 @@ function mergeRequiredAPIs(backend) {
|
|
|
73
73
|
}
|
|
74
74
|
exports.mergeRequiredAPIs = mergeRequiredAPIs;
|
|
75
75
|
function addResourcesToBackend(projectId, runtime, annotation, want) {
|
|
76
|
+
var _a;
|
|
76
77
|
Object.freeze(annotation);
|
|
77
78
|
for (const region of annotation.regions || [api.functionsDefaultRegion]) {
|
|
78
79
|
let triggered;
|
|
@@ -88,12 +89,18 @@ function addResourcesToBackend(projectId, runtime, annotation, want) {
|
|
|
88
89
|
});
|
|
89
90
|
}
|
|
90
91
|
else if (annotation.httpsTrigger) {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
92
|
+
if ((_a = annotation.labels) === null || _a === void 0 ? void 0 : _a["deployment-callable"]) {
|
|
93
|
+
delete annotation.labels["deployment-callable"];
|
|
94
|
+
triggered = { callableTrigger: {} };
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
const trigger = {};
|
|
98
|
+
if (annotation.failurePolicy) {
|
|
99
|
+
logger_1.logger.warn(`Ignoring retry policy for HTTPS function ${annotation.name}`);
|
|
100
|
+
}
|
|
101
|
+
proto.copyIfPresent(trigger, annotation.httpsTrigger, "invoker");
|
|
102
|
+
triggered = { httpsTrigger: trigger };
|
|
94
103
|
}
|
|
95
|
-
proto.copyIfPresent(trigger, annotation.httpsTrigger, "invoker");
|
|
96
|
-
triggered = { httpsTrigger: trigger };
|
|
97
104
|
}
|
|
98
105
|
else if (annotation.schedule) {
|
|
99
106
|
want.requiredAPIs.push({
|
|
@@ -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 {
|
|
@@ -5705,6 +5705,28 @@ exports.default = {
|
|
|
5705
5705
|
},
|
|
5706
5706
|
type: "object",
|
|
5707
5707
|
},
|
|
5708
|
+
GoogleCloudIdentitytoolkitAdminV2AllowByDefault: {
|
|
5709
|
+
description: "Defines a policy of allowing every region by default and adding disallowed regions to a disallow list.",
|
|
5710
|
+
properties: {
|
|
5711
|
+
disallowedRegions: {
|
|
5712
|
+
description: "Two letter unicode region codes to disallow as defined by https://cldr.unicode.org/ The full list of these region codes is here: https://github.com/unicode-cldr/cldr-localenames-full/blob/master/main/en/territories.json",
|
|
5713
|
+
items: { type: "string" },
|
|
5714
|
+
type: "array",
|
|
5715
|
+
},
|
|
5716
|
+
},
|
|
5717
|
+
type: "object",
|
|
5718
|
+
},
|
|
5719
|
+
GoogleCloudIdentitytoolkitAdminV2AllowlistOnly: {
|
|
5720
|
+
description: "Defines a policy of only allowing regions by explicitly adding them to an allowlist.",
|
|
5721
|
+
properties: {
|
|
5722
|
+
allowedRegions: {
|
|
5723
|
+
description: "Two letter unicode region codes to allow as defined by https://cldr.unicode.org/ The full list of these region codes is here: https://github.com/unicode-cldr/cldr-localenames-full/blob/master/main/en/territories.json",
|
|
5724
|
+
items: { type: "string" },
|
|
5725
|
+
type: "array",
|
|
5726
|
+
},
|
|
5727
|
+
},
|
|
5728
|
+
type: "object",
|
|
5729
|
+
},
|
|
5708
5730
|
GoogleCloudIdentitytoolkitAdminV2Anonymous: {
|
|
5709
5731
|
description: "Configuration options related to authenticating an anonymous user.",
|
|
5710
5732
|
properties: {
|
|
@@ -6315,6 +6337,18 @@ exports.default = {
|
|
|
6315
6337
|
},
|
|
6316
6338
|
type: "object",
|
|
6317
6339
|
},
|
|
6340
|
+
GoogleCloudIdentitytoolkitAdminV2SmsRegionConfig: {
|
|
6341
|
+
description: "Configures the regions where users are allowed to send verification SMS for the project or tenant. This is based on the calling code of the destination phone number.",
|
|
6342
|
+
properties: {
|
|
6343
|
+
allowByDefault: {
|
|
6344
|
+
$ref: "#/components/schemas/GoogleCloudIdentitytoolkitAdminV2AllowByDefault",
|
|
6345
|
+
},
|
|
6346
|
+
allowlistOnly: {
|
|
6347
|
+
$ref: "#/components/schemas/GoogleCloudIdentitytoolkitAdminV2AllowlistOnly",
|
|
6348
|
+
},
|
|
6349
|
+
},
|
|
6350
|
+
type: "object",
|
|
6351
|
+
},
|
|
6318
6352
|
GoogleCloudIdentitytoolkitAdminV2SmsTemplate: {
|
|
6319
6353
|
description: "The template to use when sending an SMS.",
|
|
6320
6354
|
properties: {
|
|
@@ -6424,6 +6458,9 @@ exports.default = {
|
|
|
6424
6458
|
readOnly: true,
|
|
6425
6459
|
type: "string",
|
|
6426
6460
|
},
|
|
6461
|
+
smsRegionConfig: {
|
|
6462
|
+
$ref: "#/components/schemas/GoogleCloudIdentitytoolkitAdminV2SmsRegionConfig",
|
|
6463
|
+
},
|
|
6427
6464
|
testPhoneNumbers: {
|
|
6428
6465
|
additionalProperties: { type: "string" },
|
|
6429
6466
|
description: "A map of pairs that can be used for MFA. The phone number should be in E.164 format (https://www.itu.int/rec/T-REC-E.164/) and a maximum of 10 pairs can be added (error will be thrown once exceeded).",
|
|
@@ -10,7 +10,7 @@ const logger_1 = require("../logger");
|
|
|
10
10
|
const path = require("path");
|
|
11
11
|
const constants_1 = require("./constants");
|
|
12
12
|
const requireAuth_1 = require("../requireAuth");
|
|
13
|
-
const
|
|
13
|
+
const requireConfig_1 = require("../requireConfig");
|
|
14
14
|
const types_1 = require("./types");
|
|
15
15
|
const error_1 = require("../error");
|
|
16
16
|
const registry_1 = require("./registry");
|
|
@@ -102,7 +102,7 @@ async function beforeEmulatorCommand(options) {
|
|
|
102
102
|
options.config = DEFAULT_CONFIG;
|
|
103
103
|
}
|
|
104
104
|
else {
|
|
105
|
-
await requireConfig(options);
|
|
105
|
+
await (0, requireConfig_1.requireConfig)(options);
|
|
106
106
|
}
|
|
107
107
|
}
|
|
108
108
|
exports.beforeEmulatorCommand = beforeEmulatorCommand;
|
|
@@ -38,6 +38,7 @@ 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");
|
|
41
42
|
const START_LOGGING_EMULATOR = utils.envOverride("START_LOGGING_EMULATOR", "false", (val) => val === "true");
|
|
42
43
|
async function getAndCheckAddress(emulator, options) {
|
|
43
44
|
var _a, _b, _c, _d;
|
|
@@ -140,7 +141,7 @@ function filterEmulatorTargets(options) {
|
|
|
140
141
|
}
|
|
141
142
|
exports.filterEmulatorTargets = filterEmulatorTargets;
|
|
142
143
|
function shouldStart(options, name) {
|
|
143
|
-
var _a, _b
|
|
144
|
+
var _a, _b;
|
|
144
145
|
if (name === types_1.Emulators.HUB) {
|
|
145
146
|
return !!options.project;
|
|
146
147
|
}
|
|
@@ -155,9 +156,15 @@ function shouldStart(options, name) {
|
|
|
155
156
|
}
|
|
156
157
|
return (!!options.project && targets.some((target) => types_1.EMULATORS_SUPPORTED_BY_UI.includes(target)));
|
|
157
158
|
}
|
|
158
|
-
if (name === types_1.Emulators.FUNCTIONS && emulatorInTargets
|
|
159
|
-
|
|
160
|
-
|
|
159
|
+
if (name === types_1.Emulators.FUNCTIONS && emulatorInTargets) {
|
|
160
|
+
try {
|
|
161
|
+
(0, projectConfig_1.normalizeAndValidate)(options.config.src.functions);
|
|
162
|
+
return true;
|
|
163
|
+
}
|
|
164
|
+
catch (err) {
|
|
165
|
+
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")}?`);
|
|
166
|
+
return false;
|
|
167
|
+
}
|
|
161
168
|
}
|
|
162
169
|
if (name === types_1.Emulators.HOSTING && emulatorInTargets && !options.config.get("hosting")) {
|
|
163
170
|
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")}?`);
|
|
@@ -253,16 +260,15 @@ async function startAll(options, showUI = true) {
|
|
|
253
260
|
const emulatableBackends = [];
|
|
254
261
|
const projectDir = (options.extDevDir || options.config.projectDir);
|
|
255
262
|
if (shouldStart(options, types_1.Emulators.FUNCTIONS)) {
|
|
256
|
-
|
|
257
|
-
utils.assertDefined(options.config.src.functions.source, "Error: 'functions.source' is not defined");
|
|
263
|
+
const functionsCfg = (0, projectConfig_1.normalizeAndValidate)(options.config.src.functions)[0];
|
|
258
264
|
utils.assertIsStringOrUndefined(options.extDevDir);
|
|
259
|
-
const functionsDir = path.join(projectDir,
|
|
265
|
+
const functionsDir = path.join(projectDir, functionsCfg.source);
|
|
260
266
|
emulatableBackends.push({
|
|
261
267
|
functionsDir,
|
|
262
268
|
env: Object.assign({}, options.extDevEnv),
|
|
263
269
|
secretEnv: [],
|
|
264
270
|
predefinedTriggers: options.extDevTriggers,
|
|
265
|
-
nodeMajorVersion: (0, functionsEmulatorUtils_1.parseRuntimeVersion)(options.extDevNodeVersion ||
|
|
271
|
+
nodeMajorVersion: (0, functionsEmulatorUtils_1.parseRuntimeVersion)(options.extDevNodeVersion || functionsCfg.runtime),
|
|
266
272
|
});
|
|
267
273
|
}
|
|
268
274
|
if (shouldStart(options, types_1.Emulators.EXTENSIONS) && previews_1.previews.extensionsemulator) {
|
|
@@ -40,13 +40,13 @@ exports.DownloadDetails = {
|
|
|
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
|
},
|
|
@@ -65,6 +65,9 @@ class ExtensionsEmulator {
|
|
|
65
65
|
"./functions/package.json",
|
|
66
66
|
"./functions/node_modules",
|
|
67
67
|
];
|
|
68
|
+
if (!fs.existsSync(args.path)) {
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
68
71
|
for (const requiredFile of requiredFiles) {
|
|
69
72
|
const f = path.join(args.path, requiredFile);
|
|
70
73
|
if (!fs.existsSync(f)) {
|
|
@@ -35,7 +35,6 @@ const runtimes = require("../deploy/functions/runtimes");
|
|
|
35
35
|
const backend = require("../deploy/functions/backend");
|
|
36
36
|
const functionsEnv = require("../functions/env");
|
|
37
37
|
const EVENT_INVOKE = "functions:invoke";
|
|
38
|
-
const LOCAL_SECRETS_FILE = ".secret.local";
|
|
39
38
|
const DATABASE_PATH_PATTERN = new RegExp("^projects/[^/]+/instances/([^/]+)/refs(/.*)$");
|
|
40
39
|
class FunctionsEmulator {
|
|
41
40
|
constructor(args) {
|
|
@@ -654,13 +653,14 @@ class FunctionsEmulator {
|
|
|
654
653
|
}
|
|
655
654
|
async resolveSecretEnvs(backend, trigger) {
|
|
656
655
|
let secretEnvs = {};
|
|
656
|
+
const secretPath = (0, functionsEmulatorShared_1.getSecretLocalPath)(backend, this.args.projectDir);
|
|
657
657
|
try {
|
|
658
|
-
const data = fs.readFileSync(
|
|
658
|
+
const data = fs.readFileSync(secretPath, "utf8");
|
|
659
659
|
secretEnvs = functionsEnv.parseStrict(data);
|
|
660
660
|
}
|
|
661
661
|
catch (e) {
|
|
662
662
|
if (e.code !== "ENOENT") {
|
|
663
|
-
this.logger.logLabeled("ERROR", "functions", `Failed to read local secrets file ${
|
|
663
|
+
this.logger.logLabeled("ERROR", "functions", `Failed to read local secrets file ${secretPath}: ${e.message}`);
|
|
664
664
|
}
|
|
665
665
|
}
|
|
666
666
|
if (trigger) {
|
|
@@ -687,7 +687,7 @@ class FunctionsEmulator {
|
|
|
687
687
|
if (errs.length > 0) {
|
|
688
688
|
this.logger.logLabeled("ERROR", "functions", "Unable to access secret environment variables from Google Cloud Secret Manager. " +
|
|
689
689
|
"Make sure the credential used for the Functions Emulator have access " +
|
|
690
|
-
`or provide override values in ${
|
|
690
|
+
`or provide override values in ${secretPath}:\n\t` +
|
|
691
691
|
errs.join("\n\t"));
|
|
692
692
|
}
|
|
693
693
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getSignatureType = exports.formatHost = exports.findModuleRoot = exports.waitForBody = exports.getServiceFromEventType = exports.getFunctionService = exports.getTemporarySocketPath = exports.getEmulatedTriggersFromDefinitions = exports.emulatedFunctionsByRegion = exports.emulatedFunctionsFromEndpoints = exports.EmulatedTrigger = exports.HttpConstants = void 0;
|
|
3
|
+
exports.getSecretLocalPath = exports.getSignatureType = exports.formatHost = exports.findModuleRoot = exports.waitForBody = exports.getServiceFromEventType = exports.getFunctionService = exports.getTemporarySocketPath = exports.getEmulatedTriggersFromDefinitions = exports.emulatedFunctionsByRegion = exports.emulatedFunctionsFromEndpoints = exports.EmulatedTrigger = exports.HttpConstants = void 0;
|
|
4
4
|
const _ = require("lodash");
|
|
5
5
|
const os = require("os");
|
|
6
6
|
const path = require("path");
|
|
@@ -9,6 +9,7 @@ const backend = require("../deploy/functions/backend");
|
|
|
9
9
|
const constants_1 = require("./constants");
|
|
10
10
|
const proto_1 = require("../gcp/proto");
|
|
11
11
|
const logger_1 = require("../logger");
|
|
12
|
+
const manifest_1 = require("../extensions/manifest");
|
|
12
13
|
const memoryLookup = {
|
|
13
14
|
"128MB": 128,
|
|
14
15
|
"256MB": 256,
|
|
@@ -64,6 +65,10 @@ function emulatedFunctionsFromEndpoints(endpoints) {
|
|
|
64
65
|
if (backend.isHttpsTriggered(endpoint)) {
|
|
65
66
|
def.httpsTrigger = endpoint.httpsTrigger;
|
|
66
67
|
}
|
|
68
|
+
else if (backend.isCallableTriggered(endpoint)) {
|
|
69
|
+
def.httpsTrigger = {};
|
|
70
|
+
def.labels = Object.assign(Object.assign({}, def.labels), { "deployment-callable": "true" });
|
|
71
|
+
}
|
|
67
72
|
else if (backend.isEventTriggered(endpoint)) {
|
|
68
73
|
const eventTrigger = endpoint.eventTrigger;
|
|
69
74
|
if (endpoint.platform === "gcfv1") {
|
|
@@ -226,3 +231,14 @@ function getSignatureType(def) {
|
|
|
226
231
|
return def.platform === "gcfv2" ? "cloudevent" : "event";
|
|
227
232
|
}
|
|
228
233
|
exports.getSignatureType = getSignatureType;
|
|
234
|
+
const LOCAL_SECRETS_FILE = ".secret.local";
|
|
235
|
+
function getSecretLocalPath(backend, projectDir) {
|
|
236
|
+
const secretsFile = backend.extensionInstanceId
|
|
237
|
+
? `${backend.extensionInstanceId}${LOCAL_SECRETS_FILE}`
|
|
238
|
+
: LOCAL_SECRETS_FILE;
|
|
239
|
+
const secretDirectory = backend.extensionInstanceId
|
|
240
|
+
? path.join(projectDir, manifest_1.ENV_DIRECTORY)
|
|
241
|
+
: backend.functionsDir;
|
|
242
|
+
return path.join(secretDirectory, secretsFile);
|
|
243
|
+
}
|
|
244
|
+
exports.getSecretLocalPath = getSecretLocalPath;
|
|
@@ -52,8 +52,10 @@ function createFirebaseEndpoints(emulator) {
|
|
|
52
52
|
next();
|
|
53
53
|
});
|
|
54
54
|
}
|
|
55
|
-
firebaseStorageAPI.use((req, res, next) => {
|
|
56
|
-
|
|
55
|
+
firebaseStorageAPI.use(/.*\/b\/(.+?)\/.*/, (req, res, next) => {
|
|
56
|
+
const bucketId = req.params[0];
|
|
57
|
+
storageLayer.createBucket(bucketId);
|
|
58
|
+
if (!emulator.rulesManager.getRuleset(bucketId)) {
|
|
57
59
|
emulatorLogger_1.EmulatorLogger.forEmulator(types_1.Emulators.STORAGE).log("WARN", "Permission denied because no Storage ruleset is currently loaded, check your rules for syntax errors.");
|
|
58
60
|
return res.status(403).json({
|
|
59
61
|
error: {
|
|
@@ -64,10 +66,6 @@ function createFirebaseEndpoints(emulator) {
|
|
|
64
66
|
}
|
|
65
67
|
next();
|
|
66
68
|
});
|
|
67
|
-
firebaseStorageAPI.use(/.*\/b\/(.+?)\/.*/, (req, res, next) => {
|
|
68
|
-
storageLayer.createBucket(req.params[0]);
|
|
69
|
-
next();
|
|
70
|
-
});
|
|
71
69
|
firebaseStorageAPI.get("/b/:bucketId/o/:objectId", async (req, res) => {
|
|
72
70
|
var _a;
|
|
73
71
|
let metadata;
|