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
|
@@ -9,12 +9,10 @@ var __asyncValues = (this && this.__asyncValues) || function (o) {
|
|
|
9
9
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
10
|
exports.StorageLayer = exports.StoredFile = void 0;
|
|
11
11
|
const fs_1 = require("fs");
|
|
12
|
-
const list_1 = require("./list");
|
|
13
12
|
const metadata_1 = require("./metadata");
|
|
14
13
|
const errors_1 = require("./errors");
|
|
15
14
|
const path = require("path");
|
|
16
15
|
const fse = require("fs-extra");
|
|
17
|
-
const cloudFunctions_1 = require("./cloudFunctions");
|
|
18
16
|
const logger_1 = require("../../logger");
|
|
19
17
|
const adminSdkConfig_1 = require("../adminSdkConfig");
|
|
20
18
|
const types_1 = require("./rules/types");
|
|
@@ -39,17 +37,14 @@ class StoredFile {
|
|
|
39
37
|
}
|
|
40
38
|
exports.StoredFile = StoredFile;
|
|
41
39
|
class StorageLayer {
|
|
42
|
-
constructor(_projectId, _rulesValidator, _adminCredsValidator, _persistence) {
|
|
40
|
+
constructor(_projectId, _files, _buckets, _rulesValidator, _adminCredsValidator, _persistence, _cloudFunctions) {
|
|
43
41
|
this._projectId = _projectId;
|
|
42
|
+
this._files = _files;
|
|
43
|
+
this._buckets = _buckets;
|
|
44
44
|
this._rulesValidator = _rulesValidator;
|
|
45
45
|
this._adminCredsValidator = _adminCredsValidator;
|
|
46
46
|
this._persistence = _persistence;
|
|
47
|
-
this.
|
|
48
|
-
this._cloudFunctions = new cloudFunctions_1.StorageCloudFunctions(this._projectId);
|
|
49
|
-
}
|
|
50
|
-
reset() {
|
|
51
|
-
this._files = new Map();
|
|
52
|
-
this._buckets = new Map();
|
|
47
|
+
this._cloudFunctions = _cloudFunctions;
|
|
53
48
|
}
|
|
54
49
|
createBucket(id) {
|
|
55
50
|
if (!this._buckets.has(id)) {
|
|
@@ -66,11 +61,11 @@ class StorageLayer {
|
|
|
66
61
|
}
|
|
67
62
|
return [...this._buckets.values()];
|
|
68
63
|
}
|
|
69
|
-
async
|
|
64
|
+
async getObject(request) {
|
|
70
65
|
var _a;
|
|
71
66
|
const metadata = this.getMetadata(request.bucketId, request.decodedObjectId);
|
|
72
67
|
const hasValidDownloadToken = ((metadata === null || metadata === void 0 ? void 0 : metadata.downloadTokens) || []).includes((_a = request.downloadToken) !== null && _a !== void 0 ? _a : "");
|
|
73
|
-
let authorized =
|
|
68
|
+
let authorized = hasValidDownloadToken;
|
|
74
69
|
if (!authorized) {
|
|
75
70
|
authorized = await this._rulesValidator.validate(["b", request.bucketId, "o", request.decodedObjectId].join("/"), request.bucketId, types_1.RulesetOperationMethod.GET, { before: metadata === null || metadata === void 0 ? void 0 : metadata.asRulesResource() }, request.authorization);
|
|
76
71
|
}
|
|
@@ -99,10 +94,9 @@ class StorageLayer {
|
|
|
99
94
|
}
|
|
100
95
|
return undefined;
|
|
101
96
|
}
|
|
102
|
-
async
|
|
97
|
+
async deleteObject(request) {
|
|
103
98
|
const storedMetadata = this.getMetadata(request.bucketId, request.decodedObjectId);
|
|
104
|
-
const authorized =
|
|
105
|
-
(await this._rulesValidator.validate(["b", request.bucketId, "o", request.decodedObjectId].join("/"), request.bucketId, types_1.RulesetOperationMethod.DELETE, { before: storedMetadata === null || storedMetadata === void 0 ? void 0 : storedMetadata.asRulesResource() }, request.authorization));
|
|
99
|
+
const authorized = await this._rulesValidator.validate(["b", request.bucketId, "o", request.decodedObjectId].join("/"), request.bucketId, types_1.RulesetOperationMethod.DELETE, { before: storedMetadata === null || storedMetadata === void 0 ? void 0 : storedMetadata.asRulesResource() }, request.authorization);
|
|
106
100
|
if (!authorized) {
|
|
107
101
|
throw new errors_1.ForbiddenError();
|
|
108
102
|
}
|
|
@@ -131,13 +125,12 @@ class StorageLayer {
|
|
|
131
125
|
return true;
|
|
132
126
|
}
|
|
133
127
|
}
|
|
134
|
-
async
|
|
128
|
+
async updateObjectMetadata(request) {
|
|
135
129
|
const storedMetadata = this.getMetadata(request.bucketId, request.decodedObjectId);
|
|
136
|
-
const authorized =
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
}, request.authorization));
|
|
130
|
+
const authorized = await this._rulesValidator.validate(["b", request.bucketId, "o", request.decodedObjectId].join("/"), request.bucketId, types_1.RulesetOperationMethod.UPDATE, {
|
|
131
|
+
before: storedMetadata === null || storedMetadata === void 0 ? void 0 : storedMetadata.asRulesResource(),
|
|
132
|
+
after: storedMetadata === null || storedMetadata === void 0 ? void 0 : storedMetadata.asRulesResource(request.metadata),
|
|
133
|
+
}, request.authorization);
|
|
141
134
|
if (!authorized) {
|
|
142
135
|
throw new errors_1.ForbiddenError();
|
|
143
136
|
}
|
|
@@ -147,7 +140,7 @@ class StorageLayer {
|
|
|
147
140
|
storedMetadata.update(request.metadata);
|
|
148
141
|
return storedMetadata;
|
|
149
142
|
}
|
|
150
|
-
async
|
|
143
|
+
async uploadObject(upload) {
|
|
151
144
|
if (upload.status !== upload_1.UploadStatus.FINISHED) {
|
|
152
145
|
throw new Error(`Unexpected upload status encountered: ${upload.status}.`);
|
|
153
146
|
}
|
|
@@ -162,8 +155,7 @@ class StorageLayer {
|
|
|
162
155
|
cacheControl: upload.metadata.cacheControl,
|
|
163
156
|
customMetadata: upload.metadata.metadata,
|
|
164
157
|
}, this._cloudFunctions, this._persistence.readBytes(upload.path, upload.size));
|
|
165
|
-
const authorized =
|
|
166
|
-
(await this._rulesValidator.validate(["b", upload.bucketId, "o", upload.objectId].join("/"), upload.bucketId, types_1.RulesetOperationMethod.CREATE, { after: metadata === null || metadata === void 0 ? void 0 : metadata.asRulesResource() }, upload.authorization));
|
|
158
|
+
const authorized = await this._rulesValidator.validate(["b", upload.bucketId, "o", upload.objectId].join("/"), upload.bucketId, types_1.RulesetOperationMethod.CREATE, { after: metadata === null || metadata === void 0 ? void 0 : metadata.asRulesResource() }, upload.authorization);
|
|
167
159
|
if (!authorized) {
|
|
168
160
|
this._persistence.deleteFile(upload.path);
|
|
169
161
|
throw new errors_1.ForbiddenError();
|
|
@@ -174,17 +166,24 @@ class StorageLayer {
|
|
|
174
166
|
this._cloudFunctions.dispatch("finalize", new metadata_1.CloudStorageObjectMetadata(metadata));
|
|
175
167
|
return metadata;
|
|
176
168
|
}
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
this.
|
|
182
|
-
|
|
183
|
-
|
|
169
|
+
copyObject({ sourceBucket, sourceObject, destinationBucket, destinationObject, incomingMetadata, authorization, }) {
|
|
170
|
+
if (!this._adminCredsValidator.validate(authorization)) {
|
|
171
|
+
throw new errors_1.ForbiddenError();
|
|
172
|
+
}
|
|
173
|
+
const sourceMetadata = this.getMetadata(sourceBucket, sourceObject);
|
|
174
|
+
if (!sourceMetadata) {
|
|
175
|
+
throw new errors_1.NotFoundError();
|
|
176
|
+
}
|
|
177
|
+
const sourceBytes = this.getBytes(sourceBucket, sourceObject);
|
|
178
|
+
const destinationFilePath = this.path(destinationBucket, destinationObject);
|
|
179
|
+
this._persistence.deleteFile(destinationFilePath, true);
|
|
180
|
+
this._persistence.appendBytes(destinationFilePath, sourceBytes);
|
|
181
|
+
const newMetadata = Object.assign(Object.assign(Object.assign({}, sourceMetadata), { metadata: sourceMetadata.customMetadata }), incomingMetadata);
|
|
182
|
+
if (sourceMetadata.downloadTokens.length &&
|
|
184
183
|
!((incomingMetadata === null || incomingMetadata === void 0 ? void 0 : incomingMetadata.metadata) && Object.keys(incomingMetadata === null || incomingMetadata === void 0 ? void 0 : incomingMetadata.metadata).length)) {
|
|
185
184
|
if (!newMetadata.metadata)
|
|
186
185
|
newMetadata.metadata = {};
|
|
187
|
-
newMetadata.metadata.firebaseStorageDownloadTokens =
|
|
186
|
+
newMetadata.metadata.firebaseStorageDownloadTokens = sourceMetadata.downloadTokens.join(",");
|
|
188
187
|
}
|
|
189
188
|
if (newMetadata.metadata) {
|
|
190
189
|
for (const [k, v] of Object.entries(newMetadata.metadata)) {
|
|
@@ -201,27 +200,23 @@ class StorageLayer {
|
|
|
201
200
|
contentLanguage: newMetadata.contentLanguage,
|
|
202
201
|
cacheControl: newMetadata.cacheControl,
|
|
203
202
|
customMetadata: newMetadata.metadata,
|
|
204
|
-
}, this._cloudFunctions,
|
|
205
|
-
const file = new StoredFile(copiedFileMetadata, this._persistence.getDiskPath(
|
|
206
|
-
this._files.set(
|
|
203
|
+
}, this._cloudFunctions, sourceBytes, incomingMetadata);
|
|
204
|
+
const file = new StoredFile(copiedFileMetadata, this._persistence.getDiskPath(destinationFilePath));
|
|
205
|
+
this._files.set(destinationFilePath, file);
|
|
207
206
|
this._cloudFunctions.dispatch("finalize", new metadata_1.CloudStorageObjectMetadata(file.metadata));
|
|
208
207
|
return file.metadata;
|
|
209
208
|
}
|
|
210
|
-
async
|
|
211
|
-
var _a
|
|
212
|
-
const
|
|
213
|
-
|
|
209
|
+
async listObjects(request) {
|
|
210
|
+
var _a;
|
|
211
|
+
const { bucketId, prefix, delimiter, pageToken, authorization } = request;
|
|
212
|
+
const authorized = await this._rulesValidator.validate(["b", bucketId, "o", prefix].join("/"), bucketId, types_1.RulesetOperationMethod.LIST, {}, authorization);
|
|
214
213
|
if (!authorized) {
|
|
215
214
|
throw new errors_1.ForbiddenError();
|
|
216
215
|
}
|
|
217
|
-
const itemsResults = this.listItems(request.bucketId, request.prefix, request.delimiter, request.pageToken, request.maxResults);
|
|
218
|
-
return new list_1.ListResponse((_a = itemsResults.prefixes) !== null && _a !== void 0 ? _a : [], (_c = (_b = itemsResults.items) === null || _b === void 0 ? void 0 : _b.map((i) => new list_1.ListItem(i.name, i.bucket))) !== null && _c !== void 0 ? _c : [], itemsResults.nextPageToken);
|
|
219
|
-
}
|
|
220
|
-
listItems(bucket, prefix, delimiter, pageToken, maxResults) {
|
|
221
216
|
let items = [];
|
|
222
217
|
const prefixes = new Set();
|
|
223
218
|
for (const [, file] of this._files) {
|
|
224
|
-
if (file.metadata.bucket !==
|
|
219
|
+
if (file.metadata.bucket !== bucketId) {
|
|
225
220
|
continue;
|
|
226
221
|
}
|
|
227
222
|
const name = file.metadata.name;
|
|
@@ -258,9 +253,7 @@ class StorageLayer {
|
|
|
258
253
|
items = items.slice(idx);
|
|
259
254
|
}
|
|
260
255
|
}
|
|
261
|
-
|
|
262
|
-
maxResults = 1000;
|
|
263
|
-
}
|
|
256
|
+
const maxResults = (_a = request.maxResults) !== null && _a !== void 0 ? _a : 1000;
|
|
264
257
|
let nextPageToken = undefined;
|
|
265
258
|
if (items.length > maxResults) {
|
|
266
259
|
nextPageToken = items[maxResults].name;
|
|
@@ -269,10 +262,10 @@ class StorageLayer {
|
|
|
269
262
|
return {
|
|
270
263
|
nextPageToken,
|
|
271
264
|
prefixes: prefixes.size > 0 ? [...prefixes].sort() : undefined,
|
|
272
|
-
items: items.length > 0 ? items
|
|
265
|
+
items: items.length > 0 ? items : undefined,
|
|
273
266
|
};
|
|
274
267
|
}
|
|
275
|
-
|
|
268
|
+
createDownloadToken(request) {
|
|
276
269
|
if (!this._adminCredsValidator.validate(request.authorization)) {
|
|
277
270
|
throw new errors_1.ForbiddenError();
|
|
278
271
|
}
|
|
@@ -283,7 +276,7 @@ class StorageLayer {
|
|
|
283
276
|
metadata.addDownloadToken();
|
|
284
277
|
return metadata;
|
|
285
278
|
}
|
|
286
|
-
|
|
279
|
+
deleteDownloadToken(request) {
|
|
287
280
|
if (!this._adminCredsValidator.validate(request.authorization)) {
|
|
288
281
|
throw new errors_1.ForbiddenError();
|
|
289
282
|
}
|
|
@@ -13,19 +13,30 @@ const runtime_1 = require("./rules/runtime");
|
|
|
13
13
|
const utils_1 = require("./rules/utils");
|
|
14
14
|
const persistence_1 = require("./persistence");
|
|
15
15
|
const upload_1 = require("./upload");
|
|
16
|
+
const cloudFunctions_1 = require("./cloudFunctions");
|
|
16
17
|
class StorageEmulator {
|
|
17
18
|
constructor(args) {
|
|
18
19
|
this.args = args;
|
|
19
20
|
this._logger = emulatorLogger_1.EmulatorLogger.forEmulator(types_1.Emulators.STORAGE);
|
|
21
|
+
this._files = new Map();
|
|
22
|
+
this._buckets = new Map();
|
|
20
23
|
this._rulesRuntime = new runtime_1.StorageRulesRuntime();
|
|
21
24
|
this._rulesManager = (0, manager_1.createStorageRulesManager)(this.args.rules, this._rulesRuntime);
|
|
25
|
+
this._cloudFunctions = new cloudFunctions_1.StorageCloudFunctions(args.projectId);
|
|
22
26
|
this._persistence = new persistence_1.Persistence(this.getPersistenceTmpDir());
|
|
23
|
-
this._storageLayer = new files_1.StorageLayer(args.projectId, (0, utils_1.getRulesValidator)((resource) => this._rulesManager.getRuleset(resource)), (0, utils_1.getAdminCredentialValidator)(), this._persistence);
|
|
24
27
|
this._uploadService = new upload_1.UploadService(this._persistence);
|
|
28
|
+
const createStorageLayer = (rulesValidator) => {
|
|
29
|
+
return new files_1.StorageLayer(args.projectId, this._files, this._buckets, rulesValidator, (0, utils_1.getAdminCredentialValidator)(), this._persistence, this._cloudFunctions);
|
|
30
|
+
};
|
|
31
|
+
this._storageLayer = createStorageLayer((0, utils_1.getFirebaseRulesValidator)((resource) => this._rulesManager.getRuleset(resource)));
|
|
32
|
+
this._adminStorageLayer = createStorageLayer((0, utils_1.getAdminOnlyFirebaseRulesValidator)());
|
|
25
33
|
}
|
|
26
34
|
get storageLayer() {
|
|
27
35
|
return this._storageLayer;
|
|
28
36
|
}
|
|
37
|
+
get adminStorageLayer() {
|
|
38
|
+
return this._adminStorageLayer;
|
|
39
|
+
}
|
|
29
40
|
get uploadService() {
|
|
30
41
|
return this._uploadService;
|
|
31
42
|
}
|
|
@@ -36,7 +47,8 @@ class StorageEmulator {
|
|
|
36
47
|
return this._logger;
|
|
37
48
|
}
|
|
38
49
|
reset() {
|
|
39
|
-
this.
|
|
50
|
+
this._files.clear();
|
|
51
|
+
this._buckets.clear();
|
|
40
52
|
this._persistence.reset(this.getPersistenceTmpDir());
|
|
41
53
|
this._uploadService.reset();
|
|
42
54
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.isPermitted = exports.getAdminCredentialValidator = exports.
|
|
3
|
+
exports.isPermitted = exports.getAdminCredentialValidator = exports.getAdminOnlyFirebaseRulesValidator = exports.getFirebaseRulesValidator = void 0;
|
|
4
4
|
const emulatorLogger_1 = require("../../emulatorLogger");
|
|
5
5
|
const types_1 = require("../../types");
|
|
6
|
-
function
|
|
6
|
+
function getFirebaseRulesValidator(rulesetProvider) {
|
|
7
7
|
return {
|
|
8
8
|
validate: async (path, bucketId, method, variableOverrides, authorization) => {
|
|
9
9
|
return await isPermitted({
|
|
@@ -16,7 +16,15 @@ function getRulesValidator(rulesetProvider) {
|
|
|
16
16
|
},
|
|
17
17
|
};
|
|
18
18
|
}
|
|
19
|
-
exports.
|
|
19
|
+
exports.getFirebaseRulesValidator = getFirebaseRulesValidator;
|
|
20
|
+
function getAdminOnlyFirebaseRulesValidator() {
|
|
21
|
+
return {
|
|
22
|
+
validate: (_path, _bucketId, _method, _variableOverrides, _authorization) => {
|
|
23
|
+
return Promise.resolve(true);
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
exports.getAdminOnlyFirebaseRulesValidator = getAdminOnlyFirebaseRulesValidator;
|
|
20
28
|
function getAdminCredentialValidator() {
|
|
21
29
|
return { validate: isValidAdminCredentials };
|
|
22
30
|
}
|
|
@@ -12,6 +12,7 @@ const utils_1 = require("./utils");
|
|
|
12
12
|
const logger_1 = require("../logger");
|
|
13
13
|
const prompt_1 = require("../prompt");
|
|
14
14
|
const utils = require("../utils");
|
|
15
|
+
const projectUtils_1 = require("../projectUtils");
|
|
15
16
|
var SecretLocation;
|
|
16
17
|
(function (SecretLocation) {
|
|
17
18
|
SecretLocation[SecretLocation["CLOUD"] = 1] = "CLOUD";
|
|
@@ -60,21 +61,21 @@ function checkResponse(response, spec) {
|
|
|
60
61
|
return valid;
|
|
61
62
|
}
|
|
62
63
|
exports.checkResponse = checkResponse;
|
|
63
|
-
async function ask(
|
|
64
|
-
if (_.isEmpty(paramSpecs)) {
|
|
64
|
+
async function ask(args) {
|
|
65
|
+
if (_.isEmpty(args.paramSpecs)) {
|
|
65
66
|
logger_1.logger.debug("No params were specified for this extension.");
|
|
66
67
|
return {};
|
|
67
68
|
}
|
|
68
69
|
utils.logLabeledBullet(extensionsHelper_1.logPrefix, "answer the questions below to configure your extension:");
|
|
69
|
-
const substituted = (0, extensionsHelper_1.substituteParams)(paramSpecs, firebaseProjectParams);
|
|
70
|
+
const substituted = (0, extensionsHelper_1.substituteParams)(args.paramSpecs, args.firebaseProjectParams);
|
|
70
71
|
const result = {};
|
|
71
72
|
const promises = _.map(substituted, (paramSpec) => {
|
|
72
73
|
return async () => {
|
|
73
74
|
result[paramSpec.param] = await askForParam({
|
|
74
|
-
projectId,
|
|
75
|
-
instanceId,
|
|
76
|
-
paramSpec,
|
|
77
|
-
reconfiguring,
|
|
75
|
+
projectId: args.projectId,
|
|
76
|
+
instanceId: args.instanceId,
|
|
77
|
+
paramSpec: paramSpec,
|
|
78
|
+
reconfiguring: args.reconfiguring,
|
|
78
79
|
});
|
|
79
80
|
};
|
|
80
81
|
});
|
|
@@ -129,13 +130,14 @@ async function askForParam(args) {
|
|
|
129
130
|
valid = checkResponse(response, paramSpec);
|
|
130
131
|
break;
|
|
131
132
|
case extensionsApi_1.ParamType.SECRET:
|
|
132
|
-
|
|
133
|
-
secretLocations = await promptSecretLocations();
|
|
134
|
-
}
|
|
133
|
+
do {
|
|
134
|
+
secretLocations = await promptSecretLocations(paramSpec);
|
|
135
|
+
} while (!isValidSecretLocations(secretLocations, paramSpec));
|
|
135
136
|
if (secretLocations.includes(SecretLocation.CLOUD.toString())) {
|
|
137
|
+
const projectId = (0, projectUtils_1.needProjectId)({ projectId: args.projectId });
|
|
136
138
|
response = args.reconfiguring
|
|
137
|
-
? await promptReconfigureSecret(
|
|
138
|
-
: await promptCreateSecret(
|
|
139
|
+
? await promptReconfigureSecret(projectId, args.instanceId, paramSpec)
|
|
140
|
+
: await promptCreateSecret(projectId, args.instanceId, paramSpec);
|
|
139
141
|
}
|
|
140
142
|
if (secretLocations.includes(SecretLocation.LOCAL.toString())) {
|
|
141
143
|
responseForLocal = await promptLocalSecret(args.instanceId, paramSpec);
|
|
@@ -155,14 +157,40 @@ async function askForParam(args) {
|
|
|
155
157
|
return Object.assign({ baseValue: response }, (responseForLocal ? { local: responseForLocal } : {}));
|
|
156
158
|
}
|
|
157
159
|
exports.askForParam = askForParam;
|
|
158
|
-
|
|
160
|
+
function isValidSecretLocations(secretLocations, paramSpec) {
|
|
161
|
+
if (paramSpec.required) {
|
|
162
|
+
return !!secretLocations.length;
|
|
163
|
+
}
|
|
164
|
+
return true;
|
|
165
|
+
}
|
|
166
|
+
async function promptSecretLocations(paramSpec) {
|
|
167
|
+
if (paramSpec.required) {
|
|
168
|
+
return await (0, prompt_1.promptOnce)({
|
|
169
|
+
name: "input",
|
|
170
|
+
type: "checkbox",
|
|
171
|
+
message: "Where would you like to store your secrets? You must select at least one value",
|
|
172
|
+
choices: [
|
|
173
|
+
{
|
|
174
|
+
checked: true,
|
|
175
|
+
name: "Google Cloud Secret Manager",
|
|
176
|
+
value: SecretLocation.CLOUD.toString(),
|
|
177
|
+
},
|
|
178
|
+
{
|
|
179
|
+
checked: false,
|
|
180
|
+
name: "Local file (Only used by Firebase Emulator)",
|
|
181
|
+
value: SecretLocation.LOCAL.toString(),
|
|
182
|
+
},
|
|
183
|
+
],
|
|
184
|
+
});
|
|
185
|
+
}
|
|
159
186
|
return await (0, prompt_1.promptOnce)({
|
|
160
187
|
name: "input",
|
|
161
188
|
type: "checkbox",
|
|
162
|
-
message: "Where would you like to store your secrets?
|
|
189
|
+
message: "Where would you like to store your secrets? " +
|
|
190
|
+
"If you don't want to set this optional secret, leave both options unselected to skip it",
|
|
163
191
|
choices: [
|
|
164
192
|
{
|
|
165
|
-
checked:
|
|
193
|
+
checked: false,
|
|
166
194
|
name: "Google Cloud Secret Manager",
|
|
167
195
|
value: SecretLocation.CLOUD.toString(),
|
|
168
196
|
},
|
|
@@ -80,6 +80,9 @@ function getDBInstanceFromURL(databaseUrl = "") {
|
|
|
80
80
|
exports.getDBInstanceFromURL = getDBInstanceFromURL;
|
|
81
81
|
async function getFirebaseProjectParams(projectId, emulatorMode = false) {
|
|
82
82
|
var _a, _b;
|
|
83
|
+
if (!projectId) {
|
|
84
|
+
return {};
|
|
85
|
+
}
|
|
83
86
|
const body = emulatorMode
|
|
84
87
|
? await (0, adminSdkConfig_1.getProjectAdminSdkConfigOrCached)(projectId)
|
|
85
88
|
: await (0, functionsConfig_1.getFirebaseConfig)({ project: projectId });
|
|
@@ -263,7 +266,10 @@ async function promptForValidInstanceId(instanceId) {
|
|
|
263
266
|
}
|
|
264
267
|
exports.promptForValidInstanceId = promptForValidInstanceId;
|
|
265
268
|
async function ensureExtensionsApiEnabled(options) {
|
|
266
|
-
const projectId = (0, projectUtils_1.
|
|
269
|
+
const projectId = (0, projectUtils_1.getProjectId)(options);
|
|
270
|
+
if (!projectId) {
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
267
273
|
return await (0, ensureApiEnabled_1.ensure)(projectId, "firebaseextensions.googleapis.com", "extensions", options.markdown);
|
|
268
274
|
}
|
|
269
275
|
exports.ensureExtensionsApiEnabled = ensureExtensionsApiEnabled;
|
|
@@ -519,7 +525,10 @@ async function confirm(args) {
|
|
|
519
525
|
}
|
|
520
526
|
exports.confirm = confirm;
|
|
521
527
|
async function diagnoseAndFixProject(options) {
|
|
522
|
-
const projectId = (0, projectUtils_1.
|
|
528
|
+
const projectId = (0, projectUtils_1.getProjectId)(options);
|
|
529
|
+
if (!projectId) {
|
|
530
|
+
return;
|
|
531
|
+
}
|
|
523
532
|
const ok = await (0, diagnose_1.diagnose)(projectId);
|
|
524
533
|
if (!ok) {
|
|
525
534
|
throw new error_1.FirebaseError("Unable to proceed until all issues are resolved.");
|
|
@@ -57,14 +57,19 @@ async function getParams(args) {
|
|
|
57
57
|
}
|
|
58
58
|
else if (args.paramsEnvPath) {
|
|
59
59
|
params = getParamsFromFile({
|
|
60
|
-
projectId: args.projectId,
|
|
61
60
|
paramSpecs: args.paramSpecs,
|
|
62
61
|
paramsEnvPath: args.paramsEnvPath,
|
|
63
62
|
});
|
|
64
63
|
}
|
|
65
64
|
else {
|
|
66
65
|
const firebaseProjectParams = await (0, extensionsHelper_1.getFirebaseProjectParams)(args.projectId);
|
|
67
|
-
params = await askUserForParam.ask(
|
|
66
|
+
params = await askUserForParam.ask({
|
|
67
|
+
projectId: args.projectId,
|
|
68
|
+
instanceId: args.instanceId,
|
|
69
|
+
paramSpecs: args.paramSpecs,
|
|
70
|
+
firebaseProjectParams,
|
|
71
|
+
reconfiguring: !!args.reconfiguring,
|
|
72
|
+
});
|
|
68
73
|
}
|
|
69
74
|
void track("Extension Params", _.isEmpty(params) ? "Not Present" : "Present", _.size(params));
|
|
70
75
|
return params;
|
|
@@ -85,7 +90,6 @@ async function getParamsForUpdate(args) {
|
|
|
85
90
|
}
|
|
86
91
|
else if (args.paramsEnvPath) {
|
|
87
92
|
params = getParamsFromFile({
|
|
88
|
-
projectId: args.projectId,
|
|
89
93
|
paramSpecs: args.newSpec.params,
|
|
90
94
|
paramsEnvPath: args.paramsEnvPath,
|
|
91
95
|
});
|
|
@@ -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; } });
|