firebase-tools 11.5.0 → 11.8.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/command.js +33 -7
- package/lib/commands/crashlytics-mappingfile-generateid.js +26 -0
- package/lib/commands/crashlytics-mappingfile-upload.js +46 -0
- package/lib/commands/crashlytics-symbols-upload.js +18 -87
- package/lib/commands/emulators-exec.js +4 -1
- package/lib/commands/emulators-export.js +5 -2
- package/lib/commands/emulators-start.js +23 -17
- package/lib/commands/ext-dev-publish.js +3 -0
- package/lib/commands/functions-delete.js +2 -0
- package/lib/commands/functions-secrets-get.js +2 -0
- package/lib/commands/index.js +3 -0
- package/lib/commands/login.js +2 -2
- package/lib/crashlytics/buildToolsJarHelper.js +51 -0
- package/lib/deploy/functions/backend.js +4 -4
- package/lib/deploy/functions/build.js +76 -9
- package/lib/deploy/functions/checkIam.js +6 -5
- package/lib/deploy/functions/params.js +22 -16
- package/lib/deploy/functions/prepare.js +1 -1
- package/lib/deploy/functions/release/fabricator.js +22 -5
- package/lib/deploy/functions/release/index.js +2 -0
- package/lib/deploy/functions/runtimes/discovery/index.js +1 -16
- package/lib/deploy/functions/runtimes/discovery/parsing.js +16 -0
- package/lib/deploy/functions/runtimes/discovery/v1alpha1.js +59 -131
- package/lib/deploy/functions/runtimes/node/parseTriggers.js +1 -1
- package/lib/emulator/auth/index.js +7 -2
- package/lib/emulator/auth/operations.js +10 -10
- package/lib/emulator/commandUtils.js +32 -15
- package/lib/emulator/constants.js +14 -6
- package/lib/emulator/controller.js +49 -17
- package/lib/emulator/downloadableEmulators.js +7 -7
- package/lib/emulator/eventarcEmulator.js +148 -0
- package/lib/emulator/extensionsEmulator.js +3 -1
- package/lib/emulator/functionsEmulator.js +44 -4
- package/lib/emulator/functionsEmulatorRuntime.js +12 -23
- package/lib/emulator/functionsEmulatorShared.js +6 -1
- package/lib/emulator/hub.js +7 -3
- package/lib/emulator/hubClient.js +2 -2
- package/lib/emulator/hubExport.js +22 -2
- package/lib/emulator/registry.js +1 -0
- package/lib/emulator/storage/apis/firebase.js +145 -129
- package/lib/emulator/storage/apis/gcloud.js +102 -42
- package/lib/emulator/storage/files.js +39 -17
- package/lib/emulator/storage/metadata.js +76 -55
- package/lib/emulator/storage/multipart.js +2 -2
- package/lib/emulator/storage/rules/runtime.js +12 -4
- package/lib/emulator/storage/server.js +2 -1
- package/lib/emulator/storage/upload.js +46 -9
- package/lib/emulator/types.js +3 -0
- package/lib/emulator/ui.js +7 -2
- package/lib/extensions/extensionsApi.js +2 -1
- package/lib/extensions/extensionsHelper.js +29 -1
- package/lib/functions/constants.js +14 -0
- package/lib/functions/env.js +9 -9
- package/lib/gcp/cloudfunctions.js +15 -18
- package/lib/gcp/cloudfunctionsv2.js +15 -18
- package/lib/gcp/cloudscheduler.js +32 -14
- package/lib/serve/index.js +15 -0
- package/lib/track.js +122 -3
- package/lib/utils.js +14 -1
- package/npm-shrinkwrap.json +542 -9
- package/package.json +5 -4
- package/schema/firebase-config.json +12 -0
- package/templates/extensions/CHANGELOG.md +1 -7
|
@@ -7,19 +7,19 @@ const registry_1 = require("../registry");
|
|
|
7
7
|
const types_1 = require("../types");
|
|
8
8
|
const crc_1 = require("./crc");
|
|
9
9
|
class StoredFileMetadata {
|
|
10
|
-
constructor(opts, _cloudFunctions, bytes
|
|
10
|
+
constructor(opts, _cloudFunctions, bytes) {
|
|
11
11
|
this._cloudFunctions = _cloudFunctions;
|
|
12
12
|
this.name = opts.name;
|
|
13
13
|
this.bucket = opts.bucket;
|
|
14
|
-
this.contentType = opts.contentType;
|
|
15
14
|
this.metageneration = opts.metageneration || 1;
|
|
16
15
|
this.generation = opts.generation || Date.now();
|
|
16
|
+
this.contentType = opts.contentType || "application/octet-stream";
|
|
17
17
|
this.storageClass = opts.storageClass || "STANDARD";
|
|
18
|
-
this.contentDisposition = opts.contentDisposition
|
|
19
|
-
this.cacheControl = opts.cacheControl
|
|
18
|
+
this.contentDisposition = opts.contentDisposition;
|
|
19
|
+
this.cacheControl = opts.cacheControl;
|
|
20
20
|
this.contentLanguage = opts.contentLanguage;
|
|
21
21
|
this.customTime = opts.customTime;
|
|
22
|
-
this.contentEncoding = opts.contentEncoding
|
|
22
|
+
this.contentEncoding = opts.contentEncoding;
|
|
23
23
|
this.customMetadata = opts.customMetadata;
|
|
24
24
|
this.downloadTokens = opts.downloadTokens || [];
|
|
25
25
|
if (opts.etag) {
|
|
@@ -43,42 +43,54 @@ class StoredFileMetadata {
|
|
|
43
43
|
else {
|
|
44
44
|
throw new Error("Must pass bytes array or opts object with size, md5hash, and crc32c");
|
|
45
45
|
}
|
|
46
|
-
if (incomingMetadata) {
|
|
47
|
-
this.update(incomingMetadata, false);
|
|
48
|
-
}
|
|
49
46
|
this.deleteFieldsSetAsNull();
|
|
50
47
|
this.setDownloadTokensFromCustomMetadata();
|
|
51
48
|
}
|
|
52
|
-
|
|
53
|
-
|
|
49
|
+
clone() {
|
|
50
|
+
const clone = new StoredFileMetadata({
|
|
54
51
|
name: this.name,
|
|
55
52
|
bucket: this.bucket,
|
|
56
53
|
generation: this.generation,
|
|
57
54
|
metageneration: this.metageneration,
|
|
55
|
+
contentType: this.contentType,
|
|
56
|
+
storageClass: this.storageClass,
|
|
58
57
|
size: this.size,
|
|
59
|
-
timeCreated: this.timeCreated,
|
|
60
|
-
updated: this.updated,
|
|
61
58
|
md5Hash: this.md5Hash,
|
|
59
|
+
contentEncoding: this.contentEncoding,
|
|
60
|
+
contentDisposition: this.contentDisposition,
|
|
61
|
+
contentLanguage: this.contentLanguage,
|
|
62
|
+
cacheControl: this.cacheControl,
|
|
63
|
+
customTime: this.customTime,
|
|
62
64
|
crc32c: this.crc32c,
|
|
63
65
|
etag: this.etag,
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
66
|
+
downloadTokens: this.downloadTokens,
|
|
67
|
+
customMetadata: this.customMetadata,
|
|
68
|
+
}, this._cloudFunctions);
|
|
69
|
+
clone.timeCreated = this.timeCreated;
|
|
70
|
+
clone.updated = this.updated;
|
|
71
|
+
return clone;
|
|
72
|
+
}
|
|
73
|
+
asRulesResource(proposedChanges) {
|
|
74
|
+
const proposedMetadata = this.clone();
|
|
69
75
|
if (proposedChanges) {
|
|
70
|
-
|
|
71
|
-
rulesResource.generation = Date.now();
|
|
72
|
-
rulesResource.metageneration = 1;
|
|
73
|
-
rulesResource.timeCreated = new Date();
|
|
74
|
-
rulesResource.updated = rulesResource.timeCreated;
|
|
75
|
-
}
|
|
76
|
-
else {
|
|
77
|
-
rulesResource.metageneration++;
|
|
78
|
-
}
|
|
79
|
-
rulesResource = Object.assign(Object.assign({}, rulesResource), proposedChanges);
|
|
76
|
+
proposedMetadata.update(proposedChanges, false);
|
|
80
77
|
}
|
|
81
|
-
return
|
|
78
|
+
return {
|
|
79
|
+
name: proposedMetadata.name,
|
|
80
|
+
bucket: proposedMetadata.bucket,
|
|
81
|
+
generation: proposedMetadata.generation,
|
|
82
|
+
metageneration: proposedMetadata.metageneration,
|
|
83
|
+
size: proposedMetadata.size,
|
|
84
|
+
timeCreated: proposedMetadata.timeCreated,
|
|
85
|
+
updated: proposedMetadata.updated,
|
|
86
|
+
md5Hash: proposedMetadata.md5Hash,
|
|
87
|
+
crc32c: proposedMetadata.crc32c,
|
|
88
|
+
etag: proposedMetadata.etag,
|
|
89
|
+
contentDisposition: proposedMetadata.contentDisposition,
|
|
90
|
+
contentEncoding: proposedMetadata.contentEncoding,
|
|
91
|
+
contentType: proposedMetadata.contentType,
|
|
92
|
+
metadata: proposedMetadata.customMetadata || {},
|
|
93
|
+
};
|
|
82
94
|
}
|
|
83
95
|
setDownloadTokensFromCustomMetadata() {
|
|
84
96
|
if (!this.customMetadata) {
|
|
@@ -118,43 +130,52 @@ class StoredFileMetadata {
|
|
|
118
130
|
}
|
|
119
131
|
}
|
|
120
132
|
update(incoming, shouldTrigger = true) {
|
|
121
|
-
if (incoming.contentDisposition) {
|
|
122
|
-
this.contentDisposition =
|
|
133
|
+
if (incoming.contentDisposition !== undefined) {
|
|
134
|
+
this.contentDisposition =
|
|
135
|
+
incoming.contentDisposition === null ? undefined : incoming.contentDisposition;
|
|
123
136
|
}
|
|
124
|
-
if (incoming.contentType) {
|
|
125
|
-
this.contentType = incoming.contentType;
|
|
137
|
+
if (incoming.contentType !== undefined) {
|
|
138
|
+
this.contentType = incoming.contentType === null ? undefined : incoming.contentType;
|
|
126
139
|
}
|
|
127
|
-
if (incoming.
|
|
128
|
-
this.
|
|
129
|
-
|
|
130
|
-
this.customMetadata[k] = v === null ? null : String(v);
|
|
131
|
-
}
|
|
140
|
+
if (incoming.contentLanguage !== undefined) {
|
|
141
|
+
this.contentLanguage =
|
|
142
|
+
incoming.contentLanguage === null ? undefined : incoming.contentLanguage;
|
|
132
143
|
}
|
|
133
|
-
if (incoming.
|
|
134
|
-
this.
|
|
144
|
+
if (incoming.contentEncoding !== undefined) {
|
|
145
|
+
this.contentEncoding =
|
|
146
|
+
incoming.contentEncoding === null ? undefined : incoming.contentEncoding;
|
|
135
147
|
}
|
|
136
|
-
if (incoming.
|
|
137
|
-
this.
|
|
148
|
+
if (incoming.cacheControl !== undefined) {
|
|
149
|
+
this.cacheControl = incoming.cacheControl === null ? undefined : incoming.cacheControl;
|
|
138
150
|
}
|
|
139
|
-
if (
|
|
140
|
-
|
|
151
|
+
if (incoming.metadata !== undefined) {
|
|
152
|
+
if (incoming.metadata === null) {
|
|
153
|
+
this.customMetadata = undefined;
|
|
154
|
+
}
|
|
155
|
+
else {
|
|
156
|
+
this.customMetadata = this.customMetadata || {};
|
|
157
|
+
for (const [k, v] of Object.entries(incoming.metadata)) {
|
|
158
|
+
if (v === null) {
|
|
159
|
+
delete this.customMetadata[k];
|
|
160
|
+
}
|
|
161
|
+
else {
|
|
162
|
+
this.customMetadata[k] = String(v);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
if (Object.keys(this.customMetadata).length === 0) {
|
|
166
|
+
this.customMetadata = undefined;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
141
169
|
}
|
|
170
|
+
this.metageneration++;
|
|
142
171
|
this.updated = new Date();
|
|
143
|
-
if (incoming.cacheControl) {
|
|
144
|
-
this.cacheControl = incoming.cacheControl;
|
|
145
|
-
}
|
|
146
172
|
this.setDownloadTokensFromCustomMetadata();
|
|
147
|
-
this.deleteFieldsSetAsNull();
|
|
148
173
|
if (shouldTrigger) {
|
|
149
174
|
this._cloudFunctions.dispatch("metadataUpdate", new CloudStorageObjectMetadata(this));
|
|
150
175
|
}
|
|
151
176
|
}
|
|
152
177
|
addDownloadToken(shouldTrigger = true) {
|
|
153
|
-
|
|
154
|
-
this.downloadTokens.push(uuid.v4());
|
|
155
|
-
return;
|
|
156
|
-
}
|
|
157
|
-
this.downloadTokens = [...this.downloadTokens, uuid.v4()];
|
|
178
|
+
this.downloadTokens = [...(this.downloadTokens || []), uuid.v4()];
|
|
158
179
|
this.update({}, shouldTrigger);
|
|
159
180
|
}
|
|
160
181
|
deleteDownloadToken(token) {
|
|
@@ -197,7 +218,7 @@ class OutgoingFirebaseMetadata {
|
|
|
197
218
|
this.crc32c = metadata.crc32c;
|
|
198
219
|
this.etag = metadata.etag;
|
|
199
220
|
this.downloadTokens = metadata.downloadTokens.join(",");
|
|
200
|
-
this.contentEncoding = metadata.contentEncoding;
|
|
221
|
+
this.contentEncoding = metadata.contentEncoding || "identity";
|
|
201
222
|
this.contentDisposition = metadata.contentDisposition;
|
|
202
223
|
this.metadata = metadata.customMetadata;
|
|
203
224
|
this.contentLanguage = metadata.contentLanguage;
|
|
@@ -208,7 +229,7 @@ exports.OutgoingFirebaseMetadata = OutgoingFirebaseMetadata;
|
|
|
208
229
|
class CloudStorageBucketMetadata {
|
|
209
230
|
constructor(id) {
|
|
210
231
|
var _a, _b;
|
|
211
|
-
this.kind = "#
|
|
232
|
+
this.kind = "storage#bucket";
|
|
212
233
|
this.name = id;
|
|
213
234
|
this.id = id;
|
|
214
235
|
this.selfLink = `http://${(_a = registry_1.EmulatorRegistry.getInfo(types_1.Emulators.STORAGE)) === null || _a === void 0 ? void 0 : _a.host}:${(_b = registry_1.EmulatorRegistry.getInfo(types_1.Emulators.STORAGE)) === null || _b === void 0 ? void 0 : _b.port}/v1/b/${this.id}`;
|
|
@@ -240,7 +261,7 @@ exports.CloudStorageObjectAccessControlMetadata = CloudStorageObjectAccessContro
|
|
|
240
261
|
class CloudStorageObjectMetadata {
|
|
241
262
|
constructor(metadata) {
|
|
242
263
|
var _a, _b, _c, _d;
|
|
243
|
-
this.kind = "
|
|
264
|
+
this.kind = "storage#object";
|
|
244
265
|
this.name = metadata.name;
|
|
245
266
|
this.bucket = metadata.bucket;
|
|
246
267
|
this.generation = metadata.generation.toString();
|
|
@@ -45,11 +45,11 @@ function parseMultipartRequestBodyPart(bodyPart) {
|
|
|
45
45
|
}
|
|
46
46
|
function parseObjectUploadMultipartRequest(contentTypeHeader, body) {
|
|
47
47
|
if (!contentTypeHeader.startsWith("multipart/related")) {
|
|
48
|
-
throw new Error(`
|
|
48
|
+
throw new Error(`Bad content type. ${contentTypeHeader}`);
|
|
49
49
|
}
|
|
50
50
|
const boundaryId = contentTypeHeader.split("boundary=")[1];
|
|
51
51
|
if (!boundaryId) {
|
|
52
|
-
throw new Error(`
|
|
52
|
+
throw new Error(`Bad content type. ${contentTypeHeader}`);
|
|
53
53
|
}
|
|
54
54
|
const parsedBody = parseMultipartRequestBody(boundaryId, body);
|
|
55
55
|
if (parsedBody.length !== 2) {
|
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.StorageRulesRuntime = exports.StorageRulesIssues = exports.StorageRulesetInstance = void 0;
|
|
4
4
|
const cross_spawn_1 = require("cross-spawn");
|
|
5
5
|
const error_1 = require("../../../error");
|
|
6
|
+
const AsyncLock = require("async-lock");
|
|
6
7
|
const types_1 = require("./types");
|
|
7
8
|
const jwt = require("jsonwebtoken");
|
|
8
9
|
const emulatorLogger_1 = require("../../emulatorLogger");
|
|
@@ -13,6 +14,8 @@ const constants_1 = require("../../constants");
|
|
|
13
14
|
const download_1 = require("../../download");
|
|
14
15
|
const fs = require("fs-extra");
|
|
15
16
|
const downloadableEmulators_1 = require("../../downloadableEmulators");
|
|
17
|
+
const lock = new AsyncLock();
|
|
18
|
+
const synchonizationKey = "key";
|
|
16
19
|
class StorageRulesetInstance {
|
|
17
20
|
constructor(runtime, rulesVersion, rulesetName) {
|
|
18
21
|
this.runtime = runtime;
|
|
@@ -65,12 +68,12 @@ class StorageRulesRuntime {
|
|
|
65
68
|
get alive() {
|
|
66
69
|
return this._alive;
|
|
67
70
|
}
|
|
68
|
-
async start(
|
|
71
|
+
async start(autoDownload = true) {
|
|
69
72
|
var _a, _b;
|
|
70
73
|
const downloadDetails = downloadableEmulators_1.DownloadDetails[types_2.Emulators.STORAGE];
|
|
71
74
|
const hasEmulator = fs.existsSync(downloadDetails.downloadPath);
|
|
72
75
|
if (!hasEmulator) {
|
|
73
|
-
if (
|
|
76
|
+
if (autoDownload) {
|
|
74
77
|
if (process.env.CI) {
|
|
75
78
|
utils.logWarning(`It appears you are running in a CI environment. You can avoid downloading the ${constants_1.Constants.description(types_2.Emulators.STORAGE)} repeatedly by caching the ${downloadDetails.opts.cacheDir} directory.`);
|
|
76
79
|
}
|
|
@@ -154,13 +157,18 @@ class StorageRulesRuntime {
|
|
|
154
157
|
throw new error_1.FirebaseError("Attempted to send Cloud Storage rules request with stale id");
|
|
155
158
|
}
|
|
156
159
|
return new Promise((resolve) => {
|
|
157
|
-
var _a, _b;
|
|
158
160
|
this._requests[runtimeActionRequest.id] = {
|
|
159
161
|
request: runtimeActionRequest,
|
|
160
162
|
handler: resolve,
|
|
161
163
|
};
|
|
162
164
|
const serializedRequest = JSON.stringify(runtimeActionRequest);
|
|
163
|
-
(
|
|
165
|
+
lock.acquire(synchonizationKey, (done) => {
|
|
166
|
+
var _a, _b;
|
|
167
|
+
(_b = (_a = this._childprocess) === null || _a === void 0 ? void 0 : _a.stdin) === null || _b === void 0 ? void 0 : _b.write(serializedRequest + "\n");
|
|
168
|
+
setTimeout(() => {
|
|
169
|
+
done();
|
|
170
|
+
}, 15);
|
|
171
|
+
});
|
|
164
172
|
});
|
|
165
173
|
}
|
|
166
174
|
async loadRuleset(source) {
|
|
@@ -36,12 +36,13 @@ function createApp(defaultProjectId, emulator) {
|
|
|
36
36
|
type: ["application/json"],
|
|
37
37
|
}));
|
|
38
38
|
app.post("/internal/export", async (req, res) => {
|
|
39
|
+
const initiatedBy = req.body.initiatedBy || "unknown";
|
|
39
40
|
const path = req.body.path;
|
|
40
41
|
if (!path) {
|
|
41
42
|
res.status(400).send("Export request body must include 'path'.");
|
|
42
43
|
return;
|
|
43
44
|
}
|
|
44
|
-
await storageLayer.export(path);
|
|
45
|
+
await storageLayer.export(path, { initiatedBy });
|
|
45
46
|
res.sendStatus(200);
|
|
46
47
|
});
|
|
47
48
|
app.put("/internal/setRules", async (req, res) => {
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.UploadService = exports.NotCancellableError = exports.UploadNotActiveError = exports.UploadStatus = exports.UploadType = void 0;
|
|
3
|
+
exports.UploadService = exports.NotCancellableError = exports.UploadPreviouslyFinalizedError = exports.UploadNotActiveError = exports.UploadStatus = exports.UploadType = void 0;
|
|
4
4
|
const uuid_1 = require("uuid");
|
|
5
5
|
const errors_1 = require("./errors");
|
|
6
6
|
var UploadType;
|
|
7
7
|
(function (UploadType) {
|
|
8
|
-
UploadType[UploadType["
|
|
9
|
-
UploadType[UploadType["
|
|
8
|
+
UploadType[UploadType["MEDIA"] = 0] = "MEDIA";
|
|
9
|
+
UploadType[UploadType["MULTIPART"] = 1] = "MULTIPART";
|
|
10
|
+
UploadType[UploadType["RESUMABLE"] = 2] = "RESUMABLE";
|
|
10
11
|
})(UploadType = exports.UploadType || (exports.UploadType = {}));
|
|
11
12
|
var UploadStatus;
|
|
12
13
|
(function (UploadStatus) {
|
|
@@ -17,6 +18,9 @@ var UploadStatus;
|
|
|
17
18
|
class UploadNotActiveError extends Error {
|
|
18
19
|
}
|
|
19
20
|
exports.UploadNotActiveError = UploadNotActiveError;
|
|
21
|
+
class UploadPreviouslyFinalizedError extends Error {
|
|
22
|
+
}
|
|
23
|
+
exports.UploadPreviouslyFinalizedError = UploadPreviouslyFinalizedError;
|
|
20
24
|
class NotCancellableError extends Error {
|
|
21
25
|
}
|
|
22
26
|
exports.NotCancellableError = NotCancellableError;
|
|
@@ -28,23 +32,42 @@ class UploadService {
|
|
|
28
32
|
reset() {
|
|
29
33
|
this._uploads = new Map();
|
|
30
34
|
}
|
|
35
|
+
mediaUpload(request) {
|
|
36
|
+
const upload = this.startOneShotUpload({
|
|
37
|
+
bucketId: request.bucketId,
|
|
38
|
+
objectId: request.objectId,
|
|
39
|
+
uploadType: UploadType.MEDIA,
|
|
40
|
+
dataRaw: request.dataRaw,
|
|
41
|
+
authorization: request.authorization,
|
|
42
|
+
});
|
|
43
|
+
this._persistence.deleteFile(upload.path, true);
|
|
44
|
+
this._persistence.appendBytes(upload.path, request.dataRaw);
|
|
45
|
+
return upload;
|
|
46
|
+
}
|
|
31
47
|
multipartUpload(request) {
|
|
32
|
-
const upload = this.
|
|
48
|
+
const upload = this.startOneShotUpload({
|
|
49
|
+
bucketId: request.bucketId,
|
|
50
|
+
objectId: request.objectId,
|
|
51
|
+
uploadType: UploadType.MULTIPART,
|
|
52
|
+
dataRaw: request.dataRaw,
|
|
53
|
+
metadata: JSON.parse(request.metadataRaw),
|
|
54
|
+
authorization: request.authorization,
|
|
55
|
+
});
|
|
33
56
|
this._persistence.deleteFile(upload.path, true);
|
|
34
57
|
this._persistence.appendBytes(upload.path, request.dataRaw);
|
|
35
58
|
return upload;
|
|
36
59
|
}
|
|
37
|
-
|
|
60
|
+
startOneShotUpload(request) {
|
|
38
61
|
const id = (0, uuid_1.v4)();
|
|
39
62
|
const upload = {
|
|
40
|
-
id
|
|
63
|
+
id,
|
|
41
64
|
bucketId: request.bucketId,
|
|
42
65
|
objectId: request.objectId,
|
|
43
|
-
type:
|
|
66
|
+
type: request.uploadType,
|
|
44
67
|
path: this.getStagingFileName(id, request.bucketId, request.objectId),
|
|
45
68
|
status: UploadStatus.FINISHED,
|
|
46
|
-
metadata:
|
|
47
|
-
size:
|
|
69
|
+
metadata: request.metadata,
|
|
70
|
+
size: request.dataRaw.byteLength,
|
|
48
71
|
authorization: request.authorization,
|
|
49
72
|
};
|
|
50
73
|
this._uploads.set(upload.id, upload);
|
|
@@ -65,6 +88,7 @@ class UploadService {
|
|
|
65
88
|
};
|
|
66
89
|
this._uploads.set(upload.id, upload);
|
|
67
90
|
this._persistence.deleteFile(upload.path, true);
|
|
91
|
+
this._persistence.appendBytes(upload.path, Buffer.alloc(0));
|
|
68
92
|
return upload;
|
|
69
93
|
}
|
|
70
94
|
continueResumableUpload(uploadId, dataRaw) {
|
|
@@ -93,12 +117,25 @@ class UploadService {
|
|
|
93
117
|
}
|
|
94
118
|
finalizeResumableUpload(uploadId) {
|
|
95
119
|
const upload = this.getResumableUpload(uploadId);
|
|
120
|
+
if (upload.status === UploadStatus.FINISHED) {
|
|
121
|
+
throw new UploadPreviouslyFinalizedError();
|
|
122
|
+
}
|
|
96
123
|
if (upload.status === UploadStatus.CANCELLED) {
|
|
97
124
|
throw new UploadNotActiveError();
|
|
98
125
|
}
|
|
99
126
|
upload.status = UploadStatus.FINISHED;
|
|
100
127
|
return upload;
|
|
101
128
|
}
|
|
129
|
+
setResponseCode(uploadId, code) {
|
|
130
|
+
const upload = this._uploads.get(uploadId);
|
|
131
|
+
if (upload) {
|
|
132
|
+
upload.prevResponseCode = code;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
getPreviousResponseCode(uploadId) {
|
|
136
|
+
var _a;
|
|
137
|
+
return ((_a = this._uploads.get(uploadId)) === null || _a === void 0 ? void 0 : _a.prevResponseCode) || 200;
|
|
138
|
+
}
|
|
102
139
|
getStagingFileName(uploadId, bucketId, objectId) {
|
|
103
140
|
return encodeURIComponent(`${uploadId}_b_${bucketId}_o_${objectId}`);
|
|
104
141
|
}
|
package/lib/emulator/types.js
CHANGED
|
@@ -14,6 +14,7 @@ var Emulators;
|
|
|
14
14
|
Emulators["LOGGING"] = "logging";
|
|
15
15
|
Emulators["STORAGE"] = "storage";
|
|
16
16
|
Emulators["EXTENSIONS"] = "extensions";
|
|
17
|
+
Emulators["EVENTARC"] = "eventarc";
|
|
17
18
|
})(Emulators = exports.Emulators || (exports.Emulators = {}));
|
|
18
19
|
exports.DOWNLOADABLE_EMULATORS = [
|
|
19
20
|
Emulators.FIRESTORE,
|
|
@@ -36,12 +37,14 @@ exports.ALL_SERVICE_EMULATORS = [
|
|
|
36
37
|
Emulators.HOSTING,
|
|
37
38
|
Emulators.PUBSUB,
|
|
38
39
|
Emulators.STORAGE,
|
|
40
|
+
Emulators.EVENTARC,
|
|
39
41
|
].filter((v) => v);
|
|
40
42
|
exports.EMULATORS_SUPPORTED_BY_FUNCTIONS = [
|
|
41
43
|
Emulators.FIRESTORE,
|
|
42
44
|
Emulators.DATABASE,
|
|
43
45
|
Emulators.PUBSUB,
|
|
44
46
|
Emulators.STORAGE,
|
|
47
|
+
Emulators.EVENTARC,
|
|
45
48
|
];
|
|
46
49
|
exports.EMULATORS_SUPPORTED_BY_UI = [
|
|
47
50
|
Emulators.AUTH,
|
package/lib/emulator/ui.js
CHANGED
|
@@ -6,6 +6,7 @@ const downloadableEmulators = require("./downloadableEmulators");
|
|
|
6
6
|
const registry_1 = require("./registry");
|
|
7
7
|
const error_1 = require("../error");
|
|
8
8
|
const constants_1 = require("./constants");
|
|
9
|
+
const track_1 = require("../track");
|
|
9
10
|
class EmulatorUI {
|
|
10
11
|
constructor(args) {
|
|
11
12
|
this.args = args;
|
|
@@ -15,14 +16,18 @@ class EmulatorUI {
|
|
|
15
16
|
throw new error_1.FirebaseError(`Cannot start ${constants_1.Constants.description(types_1.Emulators.UI)} without ${constants_1.Constants.description(types_1.Emulators.HUB)}!`);
|
|
16
17
|
}
|
|
17
18
|
const hubInfo = registry_1.EmulatorRegistry.get(types_1.Emulators.HUB).getInfo();
|
|
18
|
-
const { auto_download, host, port, projectId } = this.args;
|
|
19
|
+
const { auto_download: autoDownload, host, port, projectId } = this.args;
|
|
19
20
|
const env = {
|
|
20
21
|
HOST: host.toString(),
|
|
21
22
|
PORT: port.toString(),
|
|
22
23
|
GCLOUD_PROJECT: projectId,
|
|
23
24
|
[constants_1.Constants.FIREBASE_EMULATOR_HUB]: registry_1.EmulatorRegistry.getInfoHostString(hubInfo),
|
|
24
25
|
};
|
|
25
|
-
|
|
26
|
+
const session = (0, track_1.emulatorSession)();
|
|
27
|
+
if (session) {
|
|
28
|
+
env[constants_1.Constants.FIREBASE_GA_SESSION] = JSON.stringify(session);
|
|
29
|
+
}
|
|
30
|
+
return downloadableEmulators.start(types_1.Emulators.UI, { auto_download: autoDownload }, env);
|
|
26
31
|
}
|
|
27
32
|
connect() {
|
|
28
33
|
return Promise.resolve();
|
|
@@ -291,13 +291,14 @@ async function listExtensions(publisherId) {
|
|
|
291
291
|
return extensions;
|
|
292
292
|
}
|
|
293
293
|
exports.listExtensions = listExtensions;
|
|
294
|
-
async function listExtensionVersions(ref, filter = "") {
|
|
294
|
+
async function listExtensionVersions(ref, filter = "", showPrereleases = false) {
|
|
295
295
|
const { publisherId, extensionId } = refs.parse(ref);
|
|
296
296
|
const extensionVersions = [];
|
|
297
297
|
const getNextPage = async (pageToken = "") => {
|
|
298
298
|
const res = await apiClient.get(`/publishers/${publisherId}/extensions/${extensionId}/versions`, {
|
|
299
299
|
queryParams: {
|
|
300
300
|
filter,
|
|
301
|
+
showPrereleases: String(showPrereleases),
|
|
301
302
|
pageSize: PAGE_SIZE_MAX,
|
|
302
303
|
pageToken,
|
|
303
304
|
},
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.canonicalizeRefInput = exports.diagnoseAndFixProject = exports.confirm = exports.getSourceOrigin = exports.isLocalOrURLPath = exports.isLocalPath = exports.isUrlPath = exports.instanceIdExists = exports.promptForRepeatInstance = exports.promptForOfficialExtension = exports.displayReleaseNotes = exports.getPublisherProjectFromName = exports.createSourceFromLocation = exports.publishExtensionVersionFromLocalSource = exports.ensureExtensionsApiEnabled = exports.promptForValidInstanceId = exports.validateSpec = exports.validateCommandLineParams = exports.populateDefaultParams = exports.substituteParams = exports.getFirebaseProjectParams = exports.getDBInstanceFromURL = exports.resourceTypeToNiceName = exports.AUTOPOULATED_PARAM_PLACEHOLDERS = exports.EXTENSIONS_BUCKET_NAME = exports.URL_REGEX = exports.logPrefix = exports.SourceOrigin = exports.SpecParamType = void 0;
|
|
3
|
+
exports.canonicalizeRefInput = exports.diagnoseAndFixProject = exports.confirm = exports.getSourceOrigin = exports.isLocalOrURLPath = exports.isLocalPath = exports.isUrlPath = exports.instanceIdExists = exports.promptForRepeatInstance = exports.promptForOfficialExtension = exports.displayReleaseNotes = exports.getPublisherProjectFromName = exports.createSourceFromLocation = exports.publishExtensionVersionFromLocalSource = exports.incrementPrereleaseVersion = exports.ensureExtensionsApiEnabled = exports.promptForValidInstanceId = exports.validateSpec = exports.validateCommandLineParams = exports.populateDefaultParams = exports.substituteParams = exports.getFirebaseProjectParams = exports.getDBInstanceFromURL = exports.resourceTypeToNiceName = exports.AUTOPOULATED_PARAM_PLACEHOLDERS = exports.EXTENSIONS_BUCKET_NAME = exports.URL_REGEX = exports.logPrefix = exports.SourceOrigin = exports.SpecParamType = void 0;
|
|
4
4
|
const clc = require("colorette");
|
|
5
5
|
const ora = require("ora");
|
|
6
6
|
const semver = require("semver");
|
|
@@ -282,6 +282,33 @@ async function archiveAndUploadSource(extPath, bucketName) {
|
|
|
282
282
|
const res = await (0, storage_1.uploadObject)(zippedSource, bucketName);
|
|
283
283
|
return `/${res.bucket}/${res.object}`;
|
|
284
284
|
}
|
|
285
|
+
async function incrementPrereleaseVersion(ref, extensionVersion, stage) {
|
|
286
|
+
var _a;
|
|
287
|
+
const stageOptions = ["stable", "alpha", "beta", "rc"];
|
|
288
|
+
if (!stageOptions.includes(stage)) {
|
|
289
|
+
throw new error_1.FirebaseError(`--stage flag only supports the following values: ${stageOptions}`);
|
|
290
|
+
}
|
|
291
|
+
if (stage !== "stable") {
|
|
292
|
+
const version = semver.parse(extensionVersion);
|
|
293
|
+
if (version.prerelease.length > 0 || version.build.length > 0) {
|
|
294
|
+
throw new error_1.FirebaseError(`Cannot combine the --stage flag with a version with a prerelease annotation in extension.yaml.`);
|
|
295
|
+
}
|
|
296
|
+
let extensionVersions = [];
|
|
297
|
+
try {
|
|
298
|
+
extensionVersions = await (0, extensionsApi_1.listExtensionVersions)(ref, `id="${version.version}"`, true);
|
|
299
|
+
}
|
|
300
|
+
catch (e) {
|
|
301
|
+
}
|
|
302
|
+
const latestVersion = (_a = extensionVersions
|
|
303
|
+
.map((version) => semver.parse(version.spec.version))
|
|
304
|
+
.filter((version) => version.prerelease.length > 0 && version.prerelease[0] === stage)
|
|
305
|
+
.sort((v1, v2) => semver.compare(v1, v2))
|
|
306
|
+
.pop()) !== null && _a !== void 0 ? _a : `${version}-${stage}`;
|
|
307
|
+
return semver.inc(latestVersion, "prerelease", undefined, stage);
|
|
308
|
+
}
|
|
309
|
+
return extensionVersion;
|
|
310
|
+
}
|
|
311
|
+
exports.incrementPrereleaseVersion = incrementPrereleaseVersion;
|
|
285
312
|
async function publishExtensionVersionFromLocalSource(args) {
|
|
286
313
|
const extensionSpec = await (0, localHelper_1.getLocalExtensionSpec)(args.rootDirectory);
|
|
287
314
|
if (extensionSpec.name !== args.extensionId) {
|
|
@@ -290,6 +317,7 @@ async function publishExtensionVersionFromLocalSource(args) {
|
|
|
290
317
|
const subbedSpec = JSON.parse(JSON.stringify(extensionSpec));
|
|
291
318
|
subbedSpec.params = substituteParams(extensionSpec.params || [], exports.AUTOPOULATED_PARAM_PLACEHOLDERS);
|
|
292
319
|
validateSpec(subbedSpec);
|
|
320
|
+
extensionSpec.version = await incrementPrereleaseVersion(`${args.publisherId}/${args.extensionId}`, extensionSpec.version, args.stage);
|
|
293
321
|
let extension;
|
|
294
322
|
try {
|
|
295
323
|
extension = await (0, extensionsApi_1.getExtension)(`${args.publisherId}/${args.extensionId}`);
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.BLOCKING_EVENT_TO_LABEL_KEY = exports.BLOCKING_LABEL_KEY_TO_EVENT = exports.BLOCKING_LABEL = exports.HASH_LABEL = exports.CODEBASE_LABEL = void 0;
|
|
4
|
+
exports.CODEBASE_LABEL = "firebase-functions-codebase";
|
|
5
|
+
exports.HASH_LABEL = "firebase-functions-hash";
|
|
6
|
+
exports.BLOCKING_LABEL = "deployment-blocking";
|
|
7
|
+
exports.BLOCKING_LABEL_KEY_TO_EVENT = {
|
|
8
|
+
"before-create": "providers/cloud.auth/eventTypes/user.beforeCreate",
|
|
9
|
+
"before-sign-in": "providers/cloud.auth/eventTypes/user.beforeSignIn",
|
|
10
|
+
};
|
|
11
|
+
exports.BLOCKING_EVENT_TO_LABEL_KEY = {
|
|
12
|
+
"providers/cloud.auth/eventTypes/user.beforeCreate": "before-create",
|
|
13
|
+
"providers/cloud.auth/eventTypes/user.beforeSignIn": "before-sign-in",
|
|
14
|
+
};
|
package/lib/functions/env.js
CHANGED
|
@@ -161,9 +161,11 @@ function writeUserEnvs(toWrite, envOpts) {
|
|
|
161
161
|
return;
|
|
162
162
|
}
|
|
163
163
|
const { functionsSource, projectId, projectAlias, isEmulator } = envOpts;
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
164
|
+
const envFiles = findEnvfiles(functionsSource, projectId, projectAlias, isEmulator);
|
|
165
|
+
const projectScopedFileName = `.env.${projectId}`;
|
|
166
|
+
const projectScopedFileExists = envFiles.includes(projectScopedFileName);
|
|
167
|
+
if (!projectScopedFileExists) {
|
|
168
|
+
createEnvFile(envOpts);
|
|
167
169
|
}
|
|
168
170
|
const currentEnvs = loadUserEnvs(envOpts);
|
|
169
171
|
for (const k of Object.keys(toWrite)) {
|
|
@@ -172,17 +174,15 @@ function writeUserEnvs(toWrite, envOpts) {
|
|
|
172
174
|
throw new error_1.FirebaseError(`Attempted to write param-defined key ${k} to .env files, but it was already defined.`);
|
|
173
175
|
}
|
|
174
176
|
}
|
|
175
|
-
|
|
176
|
-
|
|
177
|
+
(0, utils_1.logBullet)(clc.cyan(clc.bold("functions: ")) +
|
|
178
|
+
`Writing new parameter values to disk: ${projectScopedFileName}`);
|
|
177
179
|
for (const k of Object.keys(toWrite)) {
|
|
178
|
-
fs.appendFileSync(
|
|
180
|
+
fs.appendFileSync(path.join(functionsSource, projectScopedFileName), formatUserEnvForWrite(k, toWrite[k]));
|
|
179
181
|
}
|
|
180
182
|
}
|
|
181
183
|
exports.writeUserEnvs = writeUserEnvs;
|
|
182
184
|
function createEnvFile(envOpts) {
|
|
183
|
-
const fileToWrite = envOpts.isEmulator
|
|
184
|
-
? FUNCTIONS_EMULATOR_DOTENV
|
|
185
|
-
: `.env.${envOpts.projectAlias || envOpts.projectId}`;
|
|
185
|
+
const fileToWrite = envOpts.isEmulator ? FUNCTIONS_EMULATOR_DOTENV : `.env.${envOpts.projectId}`;
|
|
186
186
|
logger_1.logger.debug(`Creating ${fileToWrite}...`);
|
|
187
187
|
fs.writeFileSync(path.join(envOpts.functionsSource, fileToWrite), "", { flag: "wx" });
|
|
188
188
|
return fileToWrite;
|