firebase-tools 10.4.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/functions-config-export.js +3 -1
- package/lib/config.js +11 -4
- 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/hosting/deploy.js +10 -0
- package/lib/emulator/controller.js +14 -8
- package/lib/emulator/downloadableEmulators.js +5 -5
- package/lib/extensions/askUserForParam.js +32 -6
- 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/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/accountExporter.js
CHANGED
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
const
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
const
|
|
10
|
-
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.serialExportUsers = exports.validateOptions = void 0;
|
|
4
|
+
const _ = require("lodash");
|
|
5
|
+
const os = require("os");
|
|
6
|
+
const path = require("path");
|
|
7
|
+
const apiv2_1 = require("./apiv2");
|
|
8
|
+
const error_1 = require("./error");
|
|
9
|
+
const api_1 = require("./api");
|
|
10
|
+
const utils = require("./utils");
|
|
11
|
+
const apiClient = new apiv2_1.Client({
|
|
12
|
+
urlPrefix: api_1.googleOrigin,
|
|
11
13
|
});
|
|
12
|
-
|
|
14
|
+
const EXPORTED_JSON_KEYS = [
|
|
13
15
|
"localId",
|
|
14
16
|
"email",
|
|
15
17
|
"emailVerified",
|
|
@@ -23,44 +25,53 @@ var EXPORTED_JSON_KEYS = [
|
|
|
23
25
|
"disabled",
|
|
24
26
|
"customAttributes",
|
|
25
27
|
];
|
|
26
|
-
|
|
28
|
+
const EXPORTED_JSON_KEYS_RENAMING = {
|
|
27
29
|
lastLoginAt: "lastSignedInAt",
|
|
28
30
|
};
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
"
|
|
32
|
-
"
|
|
33
|
-
"
|
|
34
|
-
"
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
31
|
+
const EXPORTED_PROVIDER_USER_INFO_KEYS = [
|
|
32
|
+
"providerId",
|
|
33
|
+
"rawId",
|
|
34
|
+
"email",
|
|
35
|
+
"displayName",
|
|
36
|
+
"photoUrl",
|
|
37
|
+
];
|
|
38
|
+
const PROVIDER_ID_INDEX_MAP = new Map([
|
|
39
|
+
["google.com", 7],
|
|
40
|
+
["facebook.com", 11],
|
|
41
|
+
["twitter.com", 15],
|
|
42
|
+
["github.com", 19],
|
|
43
|
+
]);
|
|
44
|
+
function escapeComma(str) {
|
|
45
|
+
if (str.includes(",")) {
|
|
38
46
|
return `"${str}"`;
|
|
39
47
|
}
|
|
40
48
|
return str;
|
|
41
|
-
}
|
|
42
|
-
|
|
49
|
+
}
|
|
50
|
+
function convertToNormalBase64(data) {
|
|
43
51
|
return data.replace(/_/g, "/").replace(/-/g, "+");
|
|
44
|
-
}
|
|
45
|
-
|
|
52
|
+
}
|
|
53
|
+
function addProviderUserInfo(providerInfo, arr, startPos) {
|
|
46
54
|
arr[startPos] = providerInfo.rawId;
|
|
47
55
|
arr[startPos + 1] = providerInfo.email || "";
|
|
48
|
-
arr[startPos + 2] =
|
|
56
|
+
arr[startPos + 2] = escapeComma(providerInfo.displayName || "");
|
|
49
57
|
arr[startPos + 3] = providerInfo.photoUrl || "";
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
|
|
58
|
+
}
|
|
59
|
+
function transUserToArray(user) {
|
|
60
|
+
const arr = Array(27).fill("");
|
|
53
61
|
arr[0] = user.localId;
|
|
54
62
|
arr[1] = user.email || "";
|
|
55
63
|
arr[2] = user.emailVerified || false;
|
|
56
|
-
arr[3] =
|
|
57
|
-
arr[4] =
|
|
58
|
-
arr[5] =
|
|
64
|
+
arr[3] = convertToNormalBase64(user.passwordHash || "");
|
|
65
|
+
arr[4] = convertToNormalBase64(user.salt || "");
|
|
66
|
+
arr[5] = escapeComma(user.displayName || "");
|
|
59
67
|
arr[6] = user.photoUrl || "";
|
|
60
|
-
for (
|
|
61
|
-
|
|
62
|
-
if (providerInfo
|
|
63
|
-
|
|
68
|
+
for (let i = 0; i < (!user.providerUserInfo ? 0 : user.providerUserInfo.length); i++) {
|
|
69
|
+
const providerInfo = user.providerUserInfo[i];
|
|
70
|
+
if (providerInfo) {
|
|
71
|
+
const providerIndex = PROVIDER_ID_INDEX_MAP.get(providerInfo.providerId);
|
|
72
|
+
if (providerIndex) {
|
|
73
|
+
addProviderUserInfo(providerInfo, arr, providerIndex);
|
|
74
|
+
}
|
|
64
75
|
}
|
|
65
76
|
}
|
|
66
77
|
arr[23] = user.createdAt;
|
|
@@ -69,36 +80,35 @@ var _transUserToArray = function (user) {
|
|
|
69
80
|
arr[26] = user.disabled;
|
|
70
81
|
arr[27] = user.customAttributes;
|
|
71
82
|
return arr;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
_.each(_.pick(user, EXPORTED_JSON_KEYS),
|
|
76
|
-
|
|
83
|
+
}
|
|
84
|
+
function transUserJson(user) {
|
|
85
|
+
const newUser = {};
|
|
86
|
+
_.each(_.pick(user, EXPORTED_JSON_KEYS), (value, key) => {
|
|
87
|
+
const newKey = EXPORTED_JSON_KEYS_RENAMING[key] || key;
|
|
77
88
|
newUser[newKey] = value;
|
|
78
89
|
});
|
|
79
90
|
if (newUser.passwordHash) {
|
|
80
|
-
newUser.passwordHash =
|
|
91
|
+
newUser.passwordHash = convertToNormalBase64(newUser.passwordHash);
|
|
81
92
|
}
|
|
82
93
|
if (newUser.salt) {
|
|
83
|
-
newUser.salt =
|
|
94
|
+
newUser.salt = convertToNormalBase64(newUser.salt);
|
|
84
95
|
}
|
|
85
96
|
if (user.providerUserInfo) {
|
|
86
97
|
newUser.providerUserInfo = [];
|
|
87
|
-
user.providerUserInfo
|
|
88
|
-
if (
|
|
89
|
-
|
|
98
|
+
for (const providerInfo of user.providerUserInfo) {
|
|
99
|
+
if (PROVIDER_ID_INDEX_MAP.has(providerInfo.providerId)) {
|
|
100
|
+
newUser.providerUserInfo.push(_.pick(providerInfo, EXPORTED_PROVIDER_USER_INFO_KEYS));
|
|
90
101
|
}
|
|
91
|
-
|
|
92
|
-
});
|
|
102
|
+
}
|
|
93
103
|
}
|
|
94
104
|
return newUser;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
|
|
105
|
+
}
|
|
106
|
+
function validateOptions(options, fileName) {
|
|
107
|
+
const exportOptions = {};
|
|
98
108
|
if (fileName === undefined) {
|
|
99
|
-
throw new FirebaseError("Must specify data file"
|
|
109
|
+
throw new error_1.FirebaseError("Must specify data file");
|
|
100
110
|
}
|
|
101
|
-
|
|
111
|
+
const extName = path.extname(fileName.toLowerCase());
|
|
102
112
|
if (extName === ".csv") {
|
|
103
113
|
exportOptions.format = "csv";
|
|
104
114
|
}
|
|
@@ -106,44 +116,44 @@ var validateOptions = function (options, fileName) {
|
|
|
106
116
|
exportOptions.format = "json";
|
|
107
117
|
}
|
|
108
118
|
else if (options.format) {
|
|
109
|
-
|
|
119
|
+
const format = options.format.toLowerCase();
|
|
110
120
|
if (format === "csv" || format === "json") {
|
|
111
121
|
exportOptions.format = format;
|
|
112
122
|
}
|
|
113
123
|
else {
|
|
114
|
-
throw new FirebaseError("Unsupported data file format, should be csv or json"
|
|
124
|
+
throw new error_1.FirebaseError("Unsupported data file format, should be csv or json");
|
|
115
125
|
}
|
|
116
126
|
}
|
|
117
127
|
else {
|
|
118
|
-
throw new FirebaseError("Please specify data file format in file name, or use `format` parameter"
|
|
119
|
-
exit: 1,
|
|
120
|
-
});
|
|
128
|
+
throw new error_1.FirebaseError("Please specify data file format in file name, or use `format` parameter");
|
|
121
129
|
}
|
|
122
130
|
return exportOptions;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
131
|
+
}
|
|
132
|
+
exports.validateOptions = validateOptions;
|
|
133
|
+
function createWriteUsersToFile() {
|
|
134
|
+
let jsonSep = "";
|
|
135
|
+
return (userList, format, writeStream) => {
|
|
136
|
+
userList.map((user) => {
|
|
128
137
|
if (user.passwordHash && user.version !== 0) {
|
|
129
138
|
delete user.passwordHash;
|
|
130
139
|
delete user.salt;
|
|
131
140
|
}
|
|
132
141
|
if (format === "csv") {
|
|
133
|
-
writeStream.write(
|
|
142
|
+
writeStream.write(transUserToArray(user).join(",") + "," + os.EOL, "utf8");
|
|
134
143
|
}
|
|
135
144
|
else {
|
|
136
|
-
writeStream.write(jsonSep + JSON.stringify(
|
|
145
|
+
writeStream.write(jsonSep + JSON.stringify(transUserJson(user), null, 2), "utf8");
|
|
137
146
|
jsonSep = "," + os.EOL;
|
|
138
147
|
}
|
|
139
148
|
});
|
|
140
149
|
};
|
|
141
|
-
}
|
|
142
|
-
|
|
150
|
+
}
|
|
151
|
+
async function serialExportUsers(projectId, options) {
|
|
152
|
+
var _a;
|
|
143
153
|
if (!options.writeUsersToFile) {
|
|
144
|
-
options.writeUsersToFile =
|
|
154
|
+
options.writeUsersToFile = createWriteUsersToFile();
|
|
145
155
|
}
|
|
146
|
-
|
|
156
|
+
const postBody = {
|
|
147
157
|
targetProjectId: projectId,
|
|
148
158
|
maxResults: options.batchSize,
|
|
149
159
|
};
|
|
@@ -153,13 +163,12 @@ var serialExportUsers = function (projectId, options) {
|
|
|
153
163
|
if (!options.timeoutRetryCount) {
|
|
154
164
|
options.timeoutRetryCount = 0;
|
|
155
165
|
}
|
|
156
|
-
|
|
157
|
-
.post("/identitytoolkit/v3/relyingparty/downloadAccount", postBody, {
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
.then(function (ret) {
|
|
166
|
+
try {
|
|
167
|
+
const ret = await apiClient.post("/identitytoolkit/v3/relyingparty/downloadAccount", postBody, {
|
|
168
|
+
skipLog: { resBody: true },
|
|
169
|
+
});
|
|
161
170
|
options.timeoutRetryCount = 0;
|
|
162
|
-
|
|
171
|
+
const userList = ret.body.users;
|
|
163
172
|
if (userList && userList.length > 0) {
|
|
164
173
|
options.writeUsersToFile(userList, options.format, options.writeStream);
|
|
165
174
|
utils.logSuccess("Exported " + userList.length + " account(s) successfully.");
|
|
@@ -169,19 +178,21 @@ var serialExportUsers = function (projectId, options) {
|
|
|
169
178
|
options.nextPageToken = ret.body.nextPageToken;
|
|
170
179
|
return serialExportUsers(projectId, options);
|
|
171
180
|
}
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
if (err.original.code === "ETIMEDOUT") {
|
|
181
|
+
}
|
|
182
|
+
catch (err) {
|
|
183
|
+
if (((_a = err.original) === null || _a === void 0 ? void 0 : _a.code) === "ETIMEDOUT") {
|
|
175
184
|
options.timeoutRetryCount++;
|
|
176
185
|
if (options.timeoutRetryCount > 5) {
|
|
177
186
|
return err;
|
|
178
187
|
}
|
|
179
188
|
return serialExportUsers(projectId, options);
|
|
180
189
|
}
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
}
|
|
187
|
-
|
|
190
|
+
if (err instanceof error_1.FirebaseError) {
|
|
191
|
+
throw err;
|
|
192
|
+
}
|
|
193
|
+
else {
|
|
194
|
+
throw new error_1.FirebaseError(`Failed to export accounts: ${err}`, { original: err });
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
exports.serialExportUsers = serialExportUsers;
|
|
@@ -13,6 +13,7 @@ const utils_1 = require("../utils");
|
|
|
13
13
|
const functional_1 = require("../functional");
|
|
14
14
|
const configExport = require("../functions/runtimeConfigExport");
|
|
15
15
|
const requireConfig_1 = require("../requireConfig");
|
|
16
|
+
const projectConfig_1 = require("../functions/projectConfig");
|
|
16
17
|
const REQUIRED_PERMISSIONS = [
|
|
17
18
|
"runtimeconfig.configs.list",
|
|
18
19
|
"runtimeconfig.configs.get",
|
|
@@ -79,6 +80,8 @@ exports.default = new command_1.Command("functions:config:export")
|
|
|
79
80
|
.before(requireConfig_1.requireConfig)
|
|
80
81
|
.before(requireInteractive_1.default)
|
|
81
82
|
.action(async (options) => {
|
|
83
|
+
const config = (0, projectConfig_1.normalizeAndValidate)(options.config.src.functions)[0];
|
|
84
|
+
const functionsDir = config.source;
|
|
82
85
|
let pInfos = configExport.getProjectInfos(options);
|
|
83
86
|
checkReservedAliases(pInfos);
|
|
84
87
|
(0, utils_1.logBullet)("Importing functions configs from projects [" +
|
|
@@ -108,7 +111,6 @@ exports.default = new command_1.Command("functions:config:export")
|
|
|
108
111
|
const filesToWrite = fromEntries((0, functional_1.zip)(filenames, dotEnvs));
|
|
109
112
|
filesToWrite[".env.local"] = `${header}\n# .env.local file contains environment variables for the Functions Emulator.\n`;
|
|
110
113
|
filesToWrite[".env"] = `${header}# .env file contains environment variables that applies to all projects.\n`;
|
|
111
|
-
const functionsDir = options.config.get("functions.source", ".");
|
|
112
114
|
for (const [filename, content] of Object.entries(filesToWrite)) {
|
|
113
115
|
await options.config.askWriteProjectFile(path.join(functionsDir, filename), content);
|
|
114
116
|
}
|
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) {
|
|
@@ -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 });
|
|
@@ -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 {
|
|
@@ -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
|
},
|
|
@@ -129,9 +129,9 @@ async function askForParam(args) {
|
|
|
129
129
|
valid = checkResponse(response, paramSpec);
|
|
130
130
|
break;
|
|
131
131
|
case extensionsApi_1.ParamType.SECRET:
|
|
132
|
-
|
|
133
|
-
secretLocations = await promptSecretLocations();
|
|
134
|
-
}
|
|
132
|
+
do {
|
|
133
|
+
secretLocations = await promptSecretLocations(paramSpec);
|
|
134
|
+
} while (!isValidSecretLocations(secretLocations, paramSpec));
|
|
135
135
|
if (secretLocations.includes(SecretLocation.CLOUD.toString())) {
|
|
136
136
|
response = args.reconfiguring
|
|
137
137
|
? await promptReconfigureSecret(args.projectId, args.instanceId, paramSpec)
|
|
@@ -155,14 +155,40 @@ async function askForParam(args) {
|
|
|
155
155
|
return Object.assign({ baseValue: response }, (responseForLocal ? { local: responseForLocal } : {}));
|
|
156
156
|
}
|
|
157
157
|
exports.askForParam = askForParam;
|
|
158
|
-
|
|
158
|
+
function isValidSecretLocations(secretLocations, paramSpec) {
|
|
159
|
+
if (paramSpec.required) {
|
|
160
|
+
return !!secretLocations.length;
|
|
161
|
+
}
|
|
162
|
+
return true;
|
|
163
|
+
}
|
|
164
|
+
async function promptSecretLocations(paramSpec) {
|
|
165
|
+
if (paramSpec.required) {
|
|
166
|
+
return await (0, prompt_1.promptOnce)({
|
|
167
|
+
name: "input",
|
|
168
|
+
type: "checkbox",
|
|
169
|
+
message: "Where would you like to store your secrets? You must select at least one value",
|
|
170
|
+
choices: [
|
|
171
|
+
{
|
|
172
|
+
checked: true,
|
|
173
|
+
name: "Google Cloud Secret Manager",
|
|
174
|
+
value: SecretLocation.CLOUD.toString(),
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
checked: false,
|
|
178
|
+
name: "Local file (Only used by Firebase Emulator)",
|
|
179
|
+
value: SecretLocation.LOCAL.toString(),
|
|
180
|
+
},
|
|
181
|
+
],
|
|
182
|
+
});
|
|
183
|
+
}
|
|
159
184
|
return await (0, prompt_1.promptOnce)({
|
|
160
185
|
name: "input",
|
|
161
186
|
type: "checkbox",
|
|
162
|
-
message: "Where would you like to store your secrets?
|
|
187
|
+
message: "Where would you like to store your secrets? " +
|
|
188
|
+
"If you don't want to set this optional secret, leave both options unselected to skip it",
|
|
163
189
|
choices: [
|
|
164
190
|
{
|
|
165
|
-
checked:
|
|
191
|
+
checked: false,
|
|
166
192
|
name: "Google Cloud Secret Manager",
|
|
167
193
|
value: SecretLocation.CLOUD.toString(),
|
|
168
194
|
},
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.normalizeAndValidate = exports.validate = exports.normalize = void 0;
|
|
4
|
+
const error_1 = require("../error");
|
|
5
|
+
function normalize(config) {
|
|
6
|
+
if (!config) {
|
|
7
|
+
throw new error_1.FirebaseError("No valid functions configuration detected in firebase.json");
|
|
8
|
+
}
|
|
9
|
+
if (Array.isArray(config)) {
|
|
10
|
+
if (config.length < 1) {
|
|
11
|
+
throw new error_1.FirebaseError("Requires at least one functions.source in firebase.json.");
|
|
12
|
+
}
|
|
13
|
+
return config;
|
|
14
|
+
}
|
|
15
|
+
return [config];
|
|
16
|
+
}
|
|
17
|
+
exports.normalize = normalize;
|
|
18
|
+
function validateSingle(config) {
|
|
19
|
+
if (!config.source) {
|
|
20
|
+
throw new error_1.FirebaseError("functions.source must be specified");
|
|
21
|
+
}
|
|
22
|
+
return Object.assign(Object.assign({}, config), { source: config.source });
|
|
23
|
+
}
|
|
24
|
+
function validate(config) {
|
|
25
|
+
if (config.length > 1) {
|
|
26
|
+
throw new error_1.FirebaseError("More than one functions.source detected in firebase.json.");
|
|
27
|
+
}
|
|
28
|
+
return [validateSingle(config[0])];
|
|
29
|
+
}
|
|
30
|
+
exports.validate = validate;
|
|
31
|
+
function normalizeAndValidate(config) {
|
|
32
|
+
return validate(normalize(config));
|
|
33
|
+
}
|
|
34
|
+
exports.normalizeAndValidate = normalizeAndValidate;
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.doSetup = void 0;
|
|
3
4
|
const clc = require("cli-color");
|
|
4
5
|
const logger_1 = require("../../../logger");
|
|
5
6
|
const prompt_1 = require("../../../prompt");
|
|
6
7
|
const requirePermissions_1 = require("../../../requirePermissions");
|
|
7
8
|
const previews_1 = require("../../../previews");
|
|
8
9
|
const ensureApiEnabled_1 = require("../../../ensureApiEnabled");
|
|
9
|
-
|
|
10
|
+
async function doSetup(setup, config, options) {
|
|
10
11
|
var _a, _b;
|
|
11
12
|
logger_1.logger.info();
|
|
12
13
|
logger_1.logger.info("A " + clc.bold("functions") + " directory will be created in your project with sample code");
|
|
@@ -44,4 +45,5 @@ module.exports = async function (setup, config, options) {
|
|
|
44
45
|
choices,
|
|
45
46
|
});
|
|
46
47
|
return require("./" + language)(setup, config);
|
|
47
|
-
}
|
|
48
|
+
}
|
|
49
|
+
exports.doSetup = doSetup;
|
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.doSetup = void 0;
|
|
2
4
|
const clc = require("cli-color");
|
|
3
5
|
const fs = require("fs");
|
|
4
|
-
const
|
|
5
|
-
const
|
|
6
|
-
const
|
|
7
|
-
const
|
|
6
|
+
const apiv2_1 = require("../../../apiv2");
|
|
7
|
+
const github_1 = require("./github");
|
|
8
|
+
const prompt_1 = require("../../../prompt");
|
|
9
|
+
const logger_1 = require("../../../logger");
|
|
8
10
|
const INDEX_TEMPLATE = fs.readFileSync(__dirname + "/../../../../templates/init/hosting/index.html", "utf8");
|
|
9
11
|
const MISSING_TEMPLATE = fs.readFileSync(__dirname + "/../../../../templates/init/hosting/404.html", "utf8");
|
|
10
12
|
const DEFAULT_IGNORES = ["firebase.json", "**/.*", "**/node_modules/**"];
|
|
11
|
-
|
|
13
|
+
async function doSetup(setup, config, options) {
|
|
12
14
|
setup.hosting = {};
|
|
13
|
-
logger.info();
|
|
14
|
-
logger.info(
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
logger.info(
|
|
18
|
-
|
|
19
|
-
logger.info();
|
|
20
|
-
return prompt(setup.hosting, [
|
|
15
|
+
logger_1.logger.info();
|
|
16
|
+
logger_1.logger.info(`Your ${clc.bold("public")} directory is the folder (relative to your project directory) that`);
|
|
17
|
+
logger_1.logger.info(`will contain Hosting assets to be uploaded with ${clc.bold("firebase deploy")}. If you`);
|
|
18
|
+
logger_1.logger.info("have a build process for your assets, use your build's output directory.");
|
|
19
|
+
logger_1.logger.info();
|
|
20
|
+
await (0, prompt_1.prompt)(setup.hosting, [
|
|
21
21
|
{
|
|
22
22
|
name: "public",
|
|
23
23
|
type: "input",
|
|
@@ -36,31 +36,22 @@ module.exports = function (setup, config, options) {
|
|
|
36
36
|
default: false,
|
|
37
37
|
message: "Set up automatic builds and deploys with GitHub?",
|
|
38
38
|
},
|
|
39
|
-
])
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
return config.askWriteProjectFile(setup.hosting.public + "/index.html", INDEX_TEMPLATE.replace(/{{VERSION}}/g, response.body.current.version));
|
|
59
|
-
})
|
|
60
|
-
.then(() => {
|
|
61
|
-
if (setup.hosting.github) {
|
|
62
|
-
return initGitHub(setup, config, options);
|
|
63
|
-
}
|
|
64
|
-
});
|
|
65
|
-
});
|
|
66
|
-
};
|
|
39
|
+
]);
|
|
40
|
+
setup.config.hosting = {
|
|
41
|
+
public: setup.hosting.public,
|
|
42
|
+
ignore: DEFAULT_IGNORES,
|
|
43
|
+
};
|
|
44
|
+
if (setup.hosting.spa) {
|
|
45
|
+
setup.config.hosting.rewrites = [{ source: "**", destination: "/index.html" }];
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
await config.askWriteProjectFile(`${setup.hosting.public}/404.html`, MISSING_TEMPLATE);
|
|
49
|
+
}
|
|
50
|
+
const c = new apiv2_1.Client({ urlPrefix: "https://www.gstatic.com", auth: false });
|
|
51
|
+
const response = await c.get("/firebasejs/releases.json");
|
|
52
|
+
await config.askWriteProjectFile(`${setup.hosting.public}/index.html`, INDEX_TEMPLATE.replace(/{{VERSION}}/g, response.body.current.version));
|
|
53
|
+
if (setup.hosting.github) {
|
|
54
|
+
return (0, github_1.initGitHub)(setup, config, options);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
exports.doSetup = doSetup;
|
|
@@ -1,13 +1,23 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
};
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.hostingGithub = exports.remoteconfig = exports.project = exports.emulators = exports.storage = exports.hosting = exports.functions = exports.firestore = exports.database = exports.account = void 0;
|
|
4
|
+
var account_1 = require("./account");
|
|
5
|
+
Object.defineProperty(exports, "account", { enumerable: true, get: function () { return account_1.doSetup; } });
|
|
6
|
+
var database_1 = require("./database");
|
|
7
|
+
Object.defineProperty(exports, "database", { enumerable: true, get: function () { return database_1.doSetup; } });
|
|
8
|
+
var firestore_1 = require("./firestore");
|
|
9
|
+
Object.defineProperty(exports, "firestore", { enumerable: true, get: function () { return firestore_1.doSetup; } });
|
|
10
|
+
var functions_1 = require("./functions");
|
|
11
|
+
Object.defineProperty(exports, "functions", { enumerable: true, get: function () { return functions_1.doSetup; } });
|
|
12
|
+
var hosting_1 = require("./hosting");
|
|
13
|
+
Object.defineProperty(exports, "hosting", { enumerable: true, get: function () { return hosting_1.doSetup; } });
|
|
14
|
+
var storage_1 = require("./storage");
|
|
15
|
+
Object.defineProperty(exports, "storage", { enumerable: true, get: function () { return storage_1.doSetup; } });
|
|
16
|
+
var emulators_1 = require("./emulators");
|
|
17
|
+
Object.defineProperty(exports, "emulators", { enumerable: true, get: function () { return emulators_1.doSetup; } });
|
|
18
|
+
var project_1 = require("./project");
|
|
19
|
+
Object.defineProperty(exports, "project", { enumerable: true, get: function () { return project_1.doSetup; } });
|
|
20
|
+
var remoteconfig_1 = require("./remoteconfig");
|
|
21
|
+
Object.defineProperty(exports, "remoteconfig", { enumerable: true, get: function () { return remoteconfig_1.doSetup; } });
|
|
22
|
+
var github_1 = require("./hosting/github");
|
|
23
|
+
Object.defineProperty(exports, "hostingGithub", { enumerable: true, get: function () { return github_1.initGitHub; } });
|
package/lib/init/index.js
CHANGED
|
@@ -1,22 +1,39 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.init = void 0;
|
|
4
|
-
const
|
|
4
|
+
const lodash_1 = require("lodash");
|
|
5
5
|
const clc = require("cli-color");
|
|
6
|
+
const error_1 = require("../error");
|
|
6
7
|
const logger_1 = require("../logger");
|
|
7
|
-
const
|
|
8
|
-
const
|
|
9
|
-
|
|
8
|
+
const features = require("./features");
|
|
9
|
+
const featureFns = new Map([
|
|
10
|
+
["account", features.account],
|
|
11
|
+
["database", features.database],
|
|
12
|
+
["firestore", features.firestore],
|
|
13
|
+
["functions", features.functions],
|
|
14
|
+
["hosting", features.hosting],
|
|
15
|
+
["storage", features.storage],
|
|
16
|
+
["emulators", features.emulators],
|
|
17
|
+
["project", features.project],
|
|
18
|
+
["remoteconfig", features.remoteconfig],
|
|
19
|
+
["hosting:github", features.hostingGithub],
|
|
20
|
+
]);
|
|
10
21
|
async function init(setup, config, options) {
|
|
11
|
-
|
|
22
|
+
var _a;
|
|
23
|
+
const nextFeature = (_a = setup.features) === null || _a === void 0 ? void 0 : _a.shift();
|
|
12
24
|
if (nextFeature) {
|
|
13
|
-
if (!
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
25
|
+
if (!featureFns.has(nextFeature)) {
|
|
26
|
+
const availableFeatures = Object.keys(features)
|
|
27
|
+
.filter((f) => f !== "project")
|
|
28
|
+
.join(", ");
|
|
29
|
+
throw new error_1.FirebaseError(`${clc.bold(nextFeature)} is not a valid feature. Must be one of ${availableFeatures}`);
|
|
17
30
|
}
|
|
18
|
-
logger_1.logger.info(clc.bold(
|
|
19
|
-
|
|
31
|
+
logger_1.logger.info(clc.bold(`\n${clc.white("===")} ${(0, lodash_1.capitalize)(nextFeature)} Setup`));
|
|
32
|
+
const fn = featureFns.get(nextFeature);
|
|
33
|
+
if (!fn) {
|
|
34
|
+
throw new error_1.FirebaseError(`We've lost the function to init ${nextFeature}`, { exit: 2 });
|
|
35
|
+
}
|
|
36
|
+
await fn(setup, config, options);
|
|
20
37
|
return init(setup, config, options);
|
|
21
38
|
}
|
|
22
39
|
}
|
package/lib/serve/functions.js
CHANGED
|
@@ -7,6 +7,7 @@ const emulatorServer_1 = require("../emulator/emulatorServer");
|
|
|
7
7
|
const functionsEmulatorUtils_1 = require("../emulator/functionsEmulatorUtils");
|
|
8
8
|
const projectUtils_1 = require("../projectUtils");
|
|
9
9
|
const auth_1 = require("../auth");
|
|
10
|
+
const projectConfig = require("../functions/projectConfig");
|
|
10
11
|
const utils = require("../utils");
|
|
11
12
|
class FunctionsServer {
|
|
12
13
|
constructor() {
|
|
@@ -20,11 +21,10 @@ class FunctionsServer {
|
|
|
20
21
|
}
|
|
21
22
|
async start(options, partialArgs) {
|
|
22
23
|
const projectId = (0, projectUtils_1.needProjectId)(options);
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
const functionsDir = path.join(options.config.projectDir, options.config.src.functions.source);
|
|
24
|
+
const config = projectConfig.normalizeAndValidate(options.config.src.functions)[0];
|
|
25
|
+
const functionsDir = path.join(options.config.projectDir, config.source);
|
|
26
26
|
const account = (0, auth_1.getProjectDefaultAccount)(options.config.projectDir);
|
|
27
|
-
const nodeMajorVersion = (0, functionsEmulatorUtils_1.parseRuntimeVersion)(
|
|
27
|
+
const nodeMajorVersion = (0, functionsEmulatorUtils_1.parseRuntimeVersion)(config.runtime);
|
|
28
28
|
this.backend = {
|
|
29
29
|
functionsDir,
|
|
30
30
|
nodeMajorVersion,
|
|
@@ -40,7 +40,7 @@ class FunctionsServer {
|
|
|
40
40
|
utils.assertIsNumber(options.port);
|
|
41
41
|
const targets = options.targets;
|
|
42
42
|
const port = options.port;
|
|
43
|
-
const hostingRunning = targets && targets.
|
|
43
|
+
const hostingRunning = targets && targets.includes("hosting");
|
|
44
44
|
if (hostingRunning) {
|
|
45
45
|
args.port = port + 1;
|
|
46
46
|
}
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "firebase-tools",
|
|
3
|
-
"version": "10.4.
|
|
3
|
+
"version": "10.4.1",
|
|
4
4
|
"lockfileVersion": 2,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "firebase-tools",
|
|
9
|
-
"version": "10.4.
|
|
9
|
+
"version": "10.4.1",
|
|
10
10
|
"license": "MIT",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"@google-cloud/pubsub": "^2.18.4",
|
package/package.json
CHANGED
|
@@ -326,54 +326,111 @@
|
|
|
326
326
|
"type": "object"
|
|
327
327
|
},
|
|
328
328
|
"functions": {
|
|
329
|
-
"
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
"
|
|
333
|
-
"
|
|
334
|
-
},
|
|
335
|
-
"type": "array"
|
|
336
|
-
},
|
|
337
|
-
"postdeploy": {
|
|
338
|
-
"anyOf": [
|
|
339
|
-
{
|
|
329
|
+
"anyOf": [
|
|
330
|
+
{
|
|
331
|
+
"additionalProperties": false,
|
|
332
|
+
"properties": {
|
|
333
|
+
"ignore": {
|
|
340
334
|
"items": {
|
|
341
335
|
"type": "string"
|
|
342
336
|
},
|
|
343
337
|
"type": "array"
|
|
344
338
|
},
|
|
345
|
-
{
|
|
339
|
+
"postdeploy": {
|
|
340
|
+
"anyOf": [
|
|
341
|
+
{
|
|
342
|
+
"items": {
|
|
343
|
+
"type": "string"
|
|
344
|
+
},
|
|
345
|
+
"type": "array"
|
|
346
|
+
},
|
|
347
|
+
{
|
|
348
|
+
"type": "string"
|
|
349
|
+
}
|
|
350
|
+
]
|
|
351
|
+
},
|
|
352
|
+
"predeploy": {
|
|
353
|
+
"anyOf": [
|
|
354
|
+
{
|
|
355
|
+
"items": {
|
|
356
|
+
"type": "string"
|
|
357
|
+
},
|
|
358
|
+
"type": "array"
|
|
359
|
+
},
|
|
360
|
+
{
|
|
361
|
+
"type": "string"
|
|
362
|
+
}
|
|
363
|
+
]
|
|
364
|
+
},
|
|
365
|
+
"runtime": {
|
|
366
|
+
"enum": [
|
|
367
|
+
"nodejs10",
|
|
368
|
+
"nodejs12",
|
|
369
|
+
"nodejs14",
|
|
370
|
+
"nodejs16"
|
|
371
|
+
],
|
|
372
|
+
"type": "string"
|
|
373
|
+
},
|
|
374
|
+
"source": {
|
|
346
375
|
"type": "string"
|
|
347
376
|
}
|
|
348
|
-
|
|
377
|
+
},
|
|
378
|
+
"type": "object"
|
|
349
379
|
},
|
|
350
|
-
|
|
351
|
-
"
|
|
352
|
-
|
|
353
|
-
|
|
380
|
+
{
|
|
381
|
+
"items": {
|
|
382
|
+
"additionalProperties": false,
|
|
383
|
+
"properties": {
|
|
384
|
+
"ignore": {
|
|
385
|
+
"items": {
|
|
386
|
+
"type": "string"
|
|
387
|
+
},
|
|
388
|
+
"type": "array"
|
|
389
|
+
},
|
|
390
|
+
"postdeploy": {
|
|
391
|
+
"anyOf": [
|
|
392
|
+
{
|
|
393
|
+
"items": {
|
|
394
|
+
"type": "string"
|
|
395
|
+
},
|
|
396
|
+
"type": "array"
|
|
397
|
+
},
|
|
398
|
+
{
|
|
399
|
+
"type": "string"
|
|
400
|
+
}
|
|
401
|
+
]
|
|
402
|
+
},
|
|
403
|
+
"predeploy": {
|
|
404
|
+
"anyOf": [
|
|
405
|
+
{
|
|
406
|
+
"items": {
|
|
407
|
+
"type": "string"
|
|
408
|
+
},
|
|
409
|
+
"type": "array"
|
|
410
|
+
},
|
|
411
|
+
{
|
|
412
|
+
"type": "string"
|
|
413
|
+
}
|
|
414
|
+
]
|
|
415
|
+
},
|
|
416
|
+
"runtime": {
|
|
417
|
+
"enum": [
|
|
418
|
+
"nodejs10",
|
|
419
|
+
"nodejs12",
|
|
420
|
+
"nodejs14",
|
|
421
|
+
"nodejs16"
|
|
422
|
+
],
|
|
354
423
|
"type": "string"
|
|
355
424
|
},
|
|
356
|
-
"
|
|
425
|
+
"source": {
|
|
426
|
+
"type": "string"
|
|
427
|
+
}
|
|
357
428
|
},
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
]
|
|
362
|
-
},
|
|
363
|
-
"runtime": {
|
|
364
|
-
"enum": [
|
|
365
|
-
"nodejs10",
|
|
366
|
-
"nodejs12",
|
|
367
|
-
"nodejs14",
|
|
368
|
-
"nodejs16"
|
|
369
|
-
],
|
|
370
|
-
"type": "string"
|
|
371
|
-
},
|
|
372
|
-
"source": {
|
|
373
|
-
"type": "string"
|
|
429
|
+
"type": "object"
|
|
430
|
+
},
|
|
431
|
+
"type": "array"
|
|
374
432
|
}
|
|
375
|
-
|
|
376
|
-
"type": "object"
|
|
433
|
+
]
|
|
377
434
|
},
|
|
378
435
|
"hosting": {
|
|
379
436
|
"anyOf": [
|