firebase-tools 11.16.0 → 11.16.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/deploy/functions/build.js +3 -0
- package/lib/deploy/functions/release/fabricator.js +2 -2
- package/lib/deploy/functions/release/sourceTokenScraper.js +34 -7
- package/lib/deploy/functions/runtimes/discovery/v1alpha1.js +2 -1
- package/lib/emulator/download.js +2 -1
- package/lib/emulator/downloadableEmulators.js +3 -3
- package/lib/emulator/extensionsEmulator.js +1 -1
- package/lib/emulator/functionsEmulator.js +2 -1
- package/lib/emulator/storage/apis/firebase.js +7 -27
- package/lib/emulator/storage/apis/gcloud.js +9 -33
- package/lib/emulator/storage/apis/shared.js +43 -0
- package/lib/emulator/storage/rules/config.js +9 -0
- package/lib/emulator/storage/upload.js +2 -2
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
- package/templates/emulators/default_storage.rules +8 -0
- package/templates/init/functions/golang/functions.go +1 -1
- package/templates/init/functions/javascript/index.js +2 -2
- package/templates/init/functions/typescript/index.ts +1 -1
|
@@ -160,6 +160,9 @@ function toBackend(build, paramValues) {
|
|
|
160
160
|
const bkEndpoints = [];
|
|
161
161
|
for (const endpointId of Object.keys(build.endpoints)) {
|
|
162
162
|
const bdEndpoint = build.endpoints[endpointId];
|
|
163
|
+
if (r.resolveBoolean(bdEndpoint.omit || false)) {
|
|
164
|
+
continue;
|
|
165
|
+
}
|
|
163
166
|
let regions = bdEndpoint.region;
|
|
164
167
|
if (typeof regions === "undefined") {
|
|
165
168
|
regions = [api.functionsDefaultRegion];
|
|
@@ -167,9 +167,9 @@ class Fabricator {
|
|
|
167
167
|
if (apiFunction.httpsTrigger) {
|
|
168
168
|
apiFunction.httpsTrigger.securityLevel = "SECURE_ALWAYS";
|
|
169
169
|
}
|
|
170
|
-
apiFunction.sourceToken = await scraper.tokenPromise();
|
|
171
170
|
const resultFunction = await this.functionExecutor
|
|
172
171
|
.run(async () => {
|
|
172
|
+
apiFunction.sourceToken = await scraper.getToken();
|
|
173
173
|
const op = await gcf.createFunction(apiFunction);
|
|
174
174
|
return poller.pollOperation(Object.assign(Object.assign({}, gcfV1PollerOptions), { pollerName: `create-${endpoint.codebase}-${endpoint.region}-${endpoint.id}`, operationResourceName: op.name, onPoll: scraper.poller }));
|
|
175
175
|
})
|
|
@@ -301,9 +301,9 @@ class Fabricator {
|
|
|
301
301
|
throw new Error("Precondition failed");
|
|
302
302
|
}
|
|
303
303
|
const apiFunction = gcf.functionFromEndpoint(endpoint, sourceUrl);
|
|
304
|
-
apiFunction.sourceToken = await scraper.tokenPromise();
|
|
305
304
|
const resultFunction = await this.functionExecutor
|
|
306
305
|
.run(async () => {
|
|
306
|
+
apiFunction.sourceToken = await scraper.getToken();
|
|
307
307
|
const op = await gcf.updateFunction(apiFunction);
|
|
308
308
|
return await poller.pollOperation(Object.assign(Object.assign({}, gcfV1PollerOptions), { pollerName: `update-${endpoint.codebase}-${endpoint.region}-${endpoint.id}`, operationResourceName: op.name, onPoll: scraper.poller }));
|
|
309
309
|
})
|
|
@@ -1,18 +1,43 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.SourceTokenScraper = void 0;
|
|
4
|
+
const error_1 = require("../../../error");
|
|
5
|
+
const functional_1 = require("../../../functional");
|
|
4
6
|
const logger_1 = require("../../../logger");
|
|
5
7
|
class SourceTokenScraper {
|
|
6
|
-
constructor() {
|
|
7
|
-
this.
|
|
8
|
+
constructor(validDurationMs = 1500000) {
|
|
9
|
+
this.tokenValidDurationMs = validDurationMs;
|
|
8
10
|
this.promise = new Promise((resolve) => (this.resolve = resolve));
|
|
11
|
+
this.fetchState = "NONE";
|
|
9
12
|
}
|
|
10
|
-
|
|
11
|
-
if (this.
|
|
12
|
-
this.
|
|
13
|
-
return
|
|
13
|
+
async getToken() {
|
|
14
|
+
if (this.fetchState === "NONE") {
|
|
15
|
+
this.fetchState = "FETCHING";
|
|
16
|
+
return undefined;
|
|
14
17
|
}
|
|
15
|
-
|
|
18
|
+
else if (this.fetchState === "FETCHING") {
|
|
19
|
+
return this.promise;
|
|
20
|
+
}
|
|
21
|
+
else if (this.fetchState === "VALID") {
|
|
22
|
+
if (this.isTokenExpired()) {
|
|
23
|
+
this.fetchState = "FETCHING";
|
|
24
|
+
this.promise = new Promise((resolve) => (this.resolve = resolve));
|
|
25
|
+
return undefined;
|
|
26
|
+
}
|
|
27
|
+
return this.promise;
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
(0, functional_1.assertExhaustive)(this.fetchState);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
isTokenExpired() {
|
|
34
|
+
if (this.expiry === undefined) {
|
|
35
|
+
throw new error_1.FirebaseError("Your deployment is checking the expiration of a source token that has not yet been polled. " +
|
|
36
|
+
"Hitting this case should never happen and should be considered a bug. " +
|
|
37
|
+
"Please file an issue at https://github.com/firebase/firebase-tools/issues " +
|
|
38
|
+
"and try deploying your functions again.");
|
|
39
|
+
}
|
|
40
|
+
return Date.now() >= this.expiry;
|
|
16
41
|
}
|
|
17
42
|
get poller() {
|
|
18
43
|
return (op) => {
|
|
@@ -21,6 +46,8 @@ class SourceTokenScraper {
|
|
|
21
46
|
const [, , , region] = ((_c = (_b = op.metadata) === null || _b === void 0 ? void 0 : _b.target) === null || _c === void 0 ? void 0 : _c.split("/")) || [];
|
|
22
47
|
logger_1.logger.debug(`Got source token ${(_d = op.metadata) === null || _d === void 0 ? void 0 : _d.sourceToken} for region ${region}`);
|
|
23
48
|
this.resolve((_e = op.metadata) === null || _e === void 0 ? void 0 : _e.sourceToken);
|
|
49
|
+
this.fetchState = "VALID";
|
|
50
|
+
this.expiry = Date.now() + this.tokenValidDurationMs;
|
|
24
51
|
}
|
|
25
52
|
};
|
|
26
53
|
}
|
|
@@ -51,6 +51,7 @@ function assertBuildEndpoint(ep, id) {
|
|
|
51
51
|
region: "array",
|
|
52
52
|
platform: (platform) => build.AllFunctionsPlatforms.includes(platform),
|
|
53
53
|
entryPoint: "string",
|
|
54
|
+
omit: "Field<boolean>?",
|
|
54
55
|
availableMemoryMb: (mem) => mem === null || isCEL(mem) || build.isValidMemoryOption(mem),
|
|
55
56
|
maxInstances: "Field<number>?",
|
|
56
57
|
minInstances: "Field<number>?",
|
|
@@ -259,7 +260,7 @@ function parseEndpointForBuild(id, ep, project, defaultRegion, runtime) {
|
|
|
259
260
|
if ("serviceAccountEmail" in ep) {
|
|
260
261
|
parsed.serviceAccount = ep.serviceAccountEmail;
|
|
261
262
|
}
|
|
262
|
-
(0, proto_1.copyIfPresent)(parsed, ep, "availableMemoryMb", "cpu", "maxInstances", "minInstances", "concurrency", "timeoutSeconds", "vpc", "labels", "ingressSettings", "environmentVariables", "serviceAccount");
|
|
263
|
+
(0, proto_1.copyIfPresent)(parsed, ep, "omit", "availableMemoryMb", "cpu", "maxInstances", "minInstances", "concurrency", "timeoutSeconds", "vpc", "labels", "ingressSettings", "environmentVariables", "serviceAccount");
|
|
263
264
|
(0, proto_1.convertIfPresent)(parsed, ep, "secretEnvironmentVariables", (senvs) => {
|
|
264
265
|
if (!senvs) {
|
|
265
266
|
return null;
|
package/lib/emulator/download.js
CHANGED
|
@@ -27,6 +27,7 @@ async function downloadEmulator(name) {
|
|
|
27
27
|
if (emulator.unzipDir) {
|
|
28
28
|
await unzip(emulator.downloadPath, emulator.unzipDir);
|
|
29
29
|
}
|
|
30
|
+
await new Promise((f) => setTimeout(f, 2000));
|
|
30
31
|
const executablePath = emulator.binaryPath || emulator.downloadPath;
|
|
31
32
|
fs.chmodSync(executablePath, 0o755);
|
|
32
33
|
removeOldFiles(name, emulator);
|
|
@@ -54,7 +55,7 @@ function unzip(zipPath, unzipDir) {
|
|
|
54
55
|
fs.createReadStream(zipPath)
|
|
55
56
|
.pipe(unzipper.Extract({ path: unzipDir }))
|
|
56
57
|
.on("error", reject)
|
|
57
|
-
.on("
|
|
58
|
+
.on("close", resolve);
|
|
58
59
|
});
|
|
59
60
|
}
|
|
60
61
|
function removeOldFiles(name, emulator, removeAllVersions = false) {
|
|
@@ -40,9 +40,9 @@ const EMULATOR_UPDATE_DETAILS = {
|
|
|
40
40
|
expectedChecksum: "a4944414518be206280b495f526f18bf",
|
|
41
41
|
},
|
|
42
42
|
pubsub: {
|
|
43
|
-
version: "0.1
|
|
44
|
-
expectedSize:
|
|
45
|
-
expectedChecksum: "
|
|
43
|
+
version: "0.7.1",
|
|
44
|
+
expectedSize: 65137179,
|
|
45
|
+
expectedChecksum: "b59a6e705031a54a69e5e1dced7ca9bf",
|
|
46
46
|
},
|
|
47
47
|
};
|
|
48
48
|
exports.DownloadDetails = {
|
|
@@ -44,7 +44,7 @@ class ExtensionsEmulator {
|
|
|
44
44
|
if (!functionsEmulator) {
|
|
45
45
|
throw new error_1.FirebaseError("Extensions Emulator is running but Functions emulator is not. This should never happen.");
|
|
46
46
|
}
|
|
47
|
-
return functionsEmulator.getInfo();
|
|
47
|
+
return Object.assign(Object.assign({}, functionsEmulator.getInfo()), { name: this.getName() });
|
|
48
48
|
}
|
|
49
49
|
getName() {
|
|
50
50
|
return types_1.Emulators.EXTENSIONS;
|
|
@@ -137,10 +137,11 @@ class FunctionsEmulator {
|
|
|
137
137
|
method: req.method,
|
|
138
138
|
path: `/functions/projects/${projectId}/triggers/${triggerId}`,
|
|
139
139
|
headers: req.headers,
|
|
140
|
-
}
|
|
140
|
+
});
|
|
141
141
|
trigReq.on("error", reject);
|
|
142
142
|
trigReq.write(rawBody);
|
|
143
143
|
trigReq.end();
|
|
144
|
+
resolve();
|
|
144
145
|
});
|
|
145
146
|
});
|
|
146
147
|
});
|
|
@@ -4,9 +4,9 @@ exports.createFirebaseEndpoints = void 0;
|
|
|
4
4
|
const emulatorLogger_1 = require("../../emulatorLogger");
|
|
5
5
|
const types_1 = require("../../types");
|
|
6
6
|
const uuid = require("uuid");
|
|
7
|
-
const zlib_1 = require("zlib");
|
|
8
7
|
const metadata_1 = require("../metadata");
|
|
9
8
|
const express_1 = require("express");
|
|
9
|
+
const shared_1 = require("./shared");
|
|
10
10
|
const registry_1 = require("../../registry");
|
|
11
11
|
const multipart_1 = require("../multipart");
|
|
12
12
|
const errors_1 = require("../errors");
|
|
@@ -17,7 +17,7 @@ function createFirebaseEndpoints(emulator) {
|
|
|
17
17
|
const { storageLayer, uploadService } = emulator;
|
|
18
18
|
if (process.env.STORAGE_EMULATOR_DEBUG) {
|
|
19
19
|
firebaseStorageAPI.use((req, res, next) => {
|
|
20
|
-
console.log("--------------INCOMING REQUEST--------------");
|
|
20
|
+
console.log("--------------INCOMING FIREBASE REQUEST--------------");
|
|
21
21
|
console.log(`${req.method.toUpperCase()} ${req.path}`);
|
|
22
22
|
console.log("-- query:");
|
|
23
23
|
console.log(JSON.stringify(req.query, undefined, 2));
|
|
@@ -98,24 +98,7 @@ function createFirebaseEndpoints(emulator) {
|
|
|
98
98
|
metadata.addDownloadToken(true);
|
|
99
99
|
}
|
|
100
100
|
if (req.query.alt === "media") {
|
|
101
|
-
|
|
102
|
-
if (isGZipped) {
|
|
103
|
-
data = (0, zlib_1.gunzipSync)(data);
|
|
104
|
-
}
|
|
105
|
-
res.setHeader("Accept-Ranges", "bytes");
|
|
106
|
-
res.setHeader("Content-Type", metadata.contentType || "application/octet-stream");
|
|
107
|
-
res.setHeader("Content-Disposition", metadata.contentDisposition || "inline");
|
|
108
|
-
setObjectHeaders(res, metadata, { "Content-Encoding": isGZipped ? "identity" : undefined });
|
|
109
|
-
const byteRange = req.range(data.byteLength, { combine: true });
|
|
110
|
-
if (Array.isArray(byteRange) && byteRange.type === "bytes" && byteRange.length > 0) {
|
|
111
|
-
const range = byteRange[0];
|
|
112
|
-
res.setHeader("Content-Range", `${byteRange.type} ${range.start}-${range.end}/${data.byteLength}`);
|
|
113
|
-
res.status(206).end(data.slice(range.start, range.end + 1));
|
|
114
|
-
}
|
|
115
|
-
else {
|
|
116
|
-
res.end(data);
|
|
117
|
-
}
|
|
118
|
-
return;
|
|
101
|
+
return (0, shared_1.sendFileBytes)(metadata, data, req, res);
|
|
119
102
|
}
|
|
120
103
|
return res.json(new metadata_1.OutgoingFirebaseMetadata(metadata));
|
|
121
104
|
});
|
|
@@ -215,7 +198,7 @@ function createFirebaseEndpoints(emulator) {
|
|
|
215
198
|
const upload = uploadService.startResumableUpload({
|
|
216
199
|
bucketId,
|
|
217
200
|
objectId,
|
|
218
|
-
|
|
201
|
+
metadata: req.body,
|
|
219
202
|
authorization: req.header("authorization"),
|
|
220
203
|
});
|
|
221
204
|
res.header("x-goog-upload-chunk-granularity", "10000");
|
|
@@ -330,7 +313,7 @@ function createFirebaseEndpoints(emulator) {
|
|
|
330
313
|
const upload = uploadService.multipartUpload({
|
|
331
314
|
bucketId,
|
|
332
315
|
objectId,
|
|
333
|
-
metadataRaw,
|
|
316
|
+
metadata: JSON.parse(metadataRaw),
|
|
334
317
|
dataRaw: dataRaw,
|
|
335
318
|
authorization: req.header("authorization"),
|
|
336
319
|
});
|
|
@@ -480,14 +463,11 @@ function createFirebaseEndpoints(emulator) {
|
|
|
480
463
|
return firebaseStorageAPI;
|
|
481
464
|
}
|
|
482
465
|
exports.createFirebaseEndpoints = createFirebaseEndpoints;
|
|
483
|
-
function setObjectHeaders(res, metadata
|
|
466
|
+
function setObjectHeaders(res, metadata) {
|
|
484
467
|
if (metadata.contentDisposition) {
|
|
485
468
|
res.setHeader("Content-Disposition", metadata.contentDisposition);
|
|
486
469
|
}
|
|
487
|
-
if (
|
|
488
|
-
res.setHeader("Content-Encoding", headerOverride["Content-Encoding"]);
|
|
489
|
-
}
|
|
490
|
-
else if (metadata.contentEncoding) {
|
|
470
|
+
if (metadata.contentEncoding) {
|
|
491
471
|
res.setHeader("Content-Encoding", metadata.contentEncoding);
|
|
492
472
|
}
|
|
493
473
|
if (metadata.cacheControl) {
|
|
@@ -2,12 +2,11 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.createCloudEndpoints = void 0;
|
|
4
4
|
const express_1 = require("express");
|
|
5
|
-
const zlib_1 = require("zlib");
|
|
6
5
|
const types_1 = require("../../types");
|
|
7
6
|
const metadata_1 = require("../metadata");
|
|
7
|
+
const shared_1 = require("./shared");
|
|
8
8
|
const registry_1 = require("../../registry");
|
|
9
9
|
const emulatorLogger_1 = require("../../emulatorLogger");
|
|
10
|
-
const crc_1 = require("../crc");
|
|
11
10
|
const multipart_1 = require("../multipart");
|
|
12
11
|
const upload_1 = require("../upload");
|
|
13
12
|
const errors_1 = require("../errors");
|
|
@@ -17,7 +16,7 @@ function createCloudEndpoints(emulator) {
|
|
|
17
16
|
const { adminStorageLayer, uploadService } = emulator;
|
|
18
17
|
if (process.env.STORAGE_EMULATOR_DEBUG) {
|
|
19
18
|
gcloudStorageAPI.use((req, res, next) => {
|
|
20
|
-
console.log("--------------INCOMING REQUEST--------------");
|
|
19
|
+
console.log("--------------INCOMING GCS REQUEST--------------");
|
|
21
20
|
console.log(`${req.method.toUpperCase()} ${req.path}`);
|
|
22
21
|
console.log("-- query:");
|
|
23
22
|
console.log(JSON.stringify(req.query, undefined, 2));
|
|
@@ -86,7 +85,7 @@ function createCloudEndpoints(emulator) {
|
|
|
86
85
|
throw err;
|
|
87
86
|
}
|
|
88
87
|
if (req.query.alt === "media") {
|
|
89
|
-
return sendFileBytes(getObjectResponse.metadata, getObjectResponse.data, req, res);
|
|
88
|
+
return (0, shared_1.sendFileBytes)(getObjectResponse.metadata, getObjectResponse.data, req, res);
|
|
90
89
|
}
|
|
91
90
|
return res.json(new metadata_1.CloudStorageObjectMetadata(getObjectResponse.metadata));
|
|
92
91
|
});
|
|
@@ -110,7 +109,7 @@ function createCloudEndpoints(emulator) {
|
|
|
110
109
|
}
|
|
111
110
|
return res.json(new metadata_1.CloudStorageObjectMetadata(updatedMetadata));
|
|
112
111
|
});
|
|
113
|
-
gcloudStorageAPI.get("/b/:bucketId/o", async (req, res) => {
|
|
112
|
+
gcloudStorageAPI.get(["/b/:bucketId/o", "/storage/v1/b/:bucketId/o"], async (req, res) => {
|
|
114
113
|
var _a;
|
|
115
114
|
let listResponse;
|
|
116
115
|
try {
|
|
@@ -228,10 +227,11 @@ function createCloudEndpoints(emulator) {
|
|
|
228
227
|
res.sendStatus(400);
|
|
229
228
|
return;
|
|
230
229
|
}
|
|
230
|
+
const contentType = req.header("x-upload-content-type");
|
|
231
231
|
const upload = uploadService.startResumableUpload({
|
|
232
232
|
bucketId: req.params.bucketId,
|
|
233
233
|
objectId: name,
|
|
234
|
-
|
|
234
|
+
metadata: Object.assign({ contentType }, req.body),
|
|
235
235
|
authorization: req.header("authorization"),
|
|
236
236
|
});
|
|
237
237
|
const uploadUrl = registry_1.EmulatorRegistry.url(types_1.Emulators.STORAGE, req);
|
|
@@ -256,6 +256,7 @@ function createCloudEndpoints(emulator) {
|
|
|
256
256
|
}
|
|
257
257
|
if (uploadType === "multipart") {
|
|
258
258
|
const contentTypeHeader = req.header("content-type") || req.header("x-upload-content-type");
|
|
259
|
+
const contentType = req.header("x-upload-content-type");
|
|
259
260
|
if (!contentTypeHeader) {
|
|
260
261
|
return res.sendStatus(400);
|
|
261
262
|
}
|
|
@@ -283,7 +284,7 @@ function createCloudEndpoints(emulator) {
|
|
|
283
284
|
const upload = uploadService.multipartUpload({
|
|
284
285
|
bucketId: req.params.bucketId,
|
|
285
286
|
objectId: name,
|
|
286
|
-
|
|
287
|
+
metadata: Object.assign({ contentType }, JSON.parse(metadataRaw)),
|
|
287
288
|
dataRaw: dataRaw,
|
|
288
289
|
authorization: req.header("authorization"),
|
|
289
290
|
});
|
|
@@ -318,7 +319,7 @@ function createCloudEndpoints(emulator) {
|
|
|
318
319
|
}
|
|
319
320
|
throw err;
|
|
320
321
|
}
|
|
321
|
-
return sendFileBytes(getObjectResponse.metadata, getObjectResponse.data, req, res);
|
|
322
|
+
return (0, shared_1.sendFileBytes)(getObjectResponse.metadata, getObjectResponse.data, req, res);
|
|
322
323
|
});
|
|
323
324
|
gcloudStorageAPI.post("/b/:bucketId/o/:objectId/:method(rewriteTo|copyTo)/b/:destBucketId/o/:destObjectId", (req, res, next) => {
|
|
324
325
|
if (req.params.method === "rewriteTo" && req.query.rewriteToken) {
|
|
@@ -375,31 +376,6 @@ function createCloudEndpoints(emulator) {
|
|
|
375
376
|
return gcloudStorageAPI;
|
|
376
377
|
}
|
|
377
378
|
exports.createCloudEndpoints = createCloudEndpoints;
|
|
378
|
-
function sendFileBytes(md, data, req, res) {
|
|
379
|
-
const isGZipped = md.contentEncoding === "gzip";
|
|
380
|
-
if (isGZipped) {
|
|
381
|
-
data = (0, zlib_1.gunzipSync)(data);
|
|
382
|
-
}
|
|
383
|
-
res.setHeader("Accept-Ranges", "bytes");
|
|
384
|
-
res.setHeader("Content-Type", md.contentType || "application/octet-stream");
|
|
385
|
-
res.setHeader("Content-Disposition", md.contentDisposition || "attachment");
|
|
386
|
-
res.setHeader("Content-Encoding", isGZipped ? "identity" : md.contentEncoding || "");
|
|
387
|
-
res.setHeader("ETag", md.etag);
|
|
388
|
-
res.setHeader("Cache-Control", md.cacheControl || "");
|
|
389
|
-
res.setHeader("x-goog-generation", `${md.generation}`);
|
|
390
|
-
res.setHeader("x-goog-metadatageneration", `${md.metageneration}`);
|
|
391
|
-
res.setHeader("x-goog-storage-class", md.storageClass);
|
|
392
|
-
res.setHeader("x-goog-hash", `crc32c=${(0, crc_1.crc32cToString)(md.crc32c)},md5=${md.md5Hash}`);
|
|
393
|
-
const byteRange = req.range(data.byteLength, { combine: true });
|
|
394
|
-
if (Array.isArray(byteRange) && byteRange.type === "bytes" && byteRange.length > 0) {
|
|
395
|
-
const range = byteRange[0];
|
|
396
|
-
res.setHeader("Content-Range", `${byteRange.type} ${range.start}-${range.end}/${data.byteLength}`);
|
|
397
|
-
res.status(206).end(data.slice(range.start, range.end + 1));
|
|
398
|
-
}
|
|
399
|
-
else {
|
|
400
|
-
res.end(data);
|
|
401
|
-
}
|
|
402
|
-
}
|
|
403
379
|
function sendObjectNotFound(req, res) {
|
|
404
380
|
res.status(404);
|
|
405
381
|
const message = `No such object: ${req.params.bucketId}/${req.params.objectId}`;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.sendFileBytes = void 0;
|
|
4
|
+
const zlib_1 = require("zlib");
|
|
5
|
+
const crc_1 = require("../crc");
|
|
6
|
+
function sendFileBytes(md, data, req, res) {
|
|
7
|
+
let didGunzip = false;
|
|
8
|
+
if (md.contentEncoding === "gzip") {
|
|
9
|
+
const acceptEncoding = req.header("accept-encoding") || "";
|
|
10
|
+
const shouldGunzip = !acceptEncoding.includes("gzip");
|
|
11
|
+
if (shouldGunzip) {
|
|
12
|
+
data = (0, zlib_1.gunzipSync)(data);
|
|
13
|
+
didGunzip = true;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
res.setHeader("Accept-Ranges", "bytes");
|
|
17
|
+
res.setHeader("Content-Type", md.contentType || "application/octet-stream");
|
|
18
|
+
res.setHeader("Content-Disposition", md.contentDisposition || "attachment");
|
|
19
|
+
if (didGunzip) {
|
|
20
|
+
res.setHeader("Transfer-Encoding", "chunked");
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
res.setHeader("Content-Encoding", md.contentEncoding || "");
|
|
24
|
+
}
|
|
25
|
+
res.setHeader("ETag", md.etag);
|
|
26
|
+
res.setHeader("Cache-Control", md.cacheControl || "");
|
|
27
|
+
res.setHeader("x-goog-generation", `${md.generation}`);
|
|
28
|
+
res.setHeader("x-goog-metadatageneration", `${md.metageneration}`);
|
|
29
|
+
res.setHeader("x-goog-storage-class", md.storageClass);
|
|
30
|
+
res.setHeader("x-goog-hash", `crc32c=${(0, crc_1.crc32cToString)(md.crc32c)},md5=${md.md5Hash}`);
|
|
31
|
+
const shouldRespectContentRange = !didGunzip;
|
|
32
|
+
if (shouldRespectContentRange) {
|
|
33
|
+
const byteRange = req.range(data.byteLength, { combine: true });
|
|
34
|
+
if (Array.isArray(byteRange) && byteRange.type === "bytes" && byteRange.length > 0) {
|
|
35
|
+
const range = byteRange[0];
|
|
36
|
+
res.setHeader("Content-Range", `${byteRange.type} ${range.start}-${range.end}/${data.byteLength}`);
|
|
37
|
+
res.status(206).end(data.slice(range.start, range.end + 1));
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
res.end(data);
|
|
42
|
+
}
|
|
43
|
+
exports.sendFileBytes = sendFileBytes;
|
|
@@ -3,6 +3,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.getStorageRulesConfig = void 0;
|
|
4
4
|
const error_1 = require("../../../error");
|
|
5
5
|
const fsutils_1 = require("../../../fsutils");
|
|
6
|
+
const constants_1 = require("../../constants");
|
|
7
|
+
const types_1 = require("../../types");
|
|
8
|
+
const emulatorLogger_1 = require("../../emulatorLogger");
|
|
6
9
|
function getSourceFile(rules, options) {
|
|
7
10
|
const path = options.config.path(rules);
|
|
8
11
|
return { name: path, content: (0, fsutils_1.readFile)(path) };
|
|
@@ -10,6 +13,12 @@ function getSourceFile(rules, options) {
|
|
|
10
13
|
function getStorageRulesConfig(projectId, options) {
|
|
11
14
|
const storageConfig = options.config.data.storage;
|
|
12
15
|
if (!storageConfig) {
|
|
16
|
+
if (constants_1.Constants.isDemoProject(projectId)) {
|
|
17
|
+
const storageLogger = emulatorLogger_1.EmulatorLogger.forEmulator(types_1.Emulators.STORAGE);
|
|
18
|
+
storageLogger.logLabeled("BULLET", "storage", `Detected demo project ID "${projectId}", using a default (open) rules configuration.`);
|
|
19
|
+
const path = __dirname + "/../../../../templates/emulators/default_storage.rules";
|
|
20
|
+
return { name: path, content: (0, fsutils_1.readFile)(path) };
|
|
21
|
+
}
|
|
13
22
|
throw new error_1.FirebaseError("Cannot start the Storage emulator without rules file specified in firebase.json: run 'firebase init' and set up your Storage configuration");
|
|
14
23
|
}
|
|
15
24
|
if (!Array.isArray(storageConfig)) {
|
|
@@ -50,7 +50,7 @@ class UploadService {
|
|
|
50
50
|
objectId: request.objectId,
|
|
51
51
|
uploadType: UploadType.MULTIPART,
|
|
52
52
|
dataRaw: request.dataRaw,
|
|
53
|
-
metadata:
|
|
53
|
+
metadata: request.metadata,
|
|
54
54
|
authorization: request.authorization,
|
|
55
55
|
});
|
|
56
56
|
this._persistence.deleteFile(upload.path, true);
|
|
@@ -82,7 +82,7 @@ class UploadService {
|
|
|
82
82
|
type: UploadType.RESUMABLE,
|
|
83
83
|
path: this.getStagingFileName(id, request.bucketId, request.objectId),
|
|
84
84
|
status: UploadStatus.ACTIVE,
|
|
85
|
-
metadata:
|
|
85
|
+
metadata: request.metadata,
|
|
86
86
|
size: 0,
|
|
87
87
|
authorization: request.authorization,
|
|
88
88
|
};
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "firebase-tools",
|
|
3
|
-
"version": "11.16.
|
|
3
|
+
"version": "11.16.1",
|
|
4
4
|
"lockfileVersion": 2,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "firebase-tools",
|
|
9
|
-
"version": "11.16.
|
|
9
|
+
"version": "11.16.1",
|
|
10
10
|
"license": "MIT",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"@google-cloud/pubsub": "^3.0.1",
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const functions = require("firebase-functions");
|
|
2
2
|
|
|
3
|
-
// // Create and
|
|
4
|
-
// // https://firebase.google.com/docs/functions/
|
|
3
|
+
// // Create and deploy your first functions
|
|
4
|
+
// // https://firebase.google.com/docs/functions/get-started
|
|
5
5
|
//
|
|
6
6
|
// exports.helloWorld = functions.https.onRequest((request, response) => {
|
|
7
7
|
// functions.logger.info("Hello logs!", {structuredData: true});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as functions from "firebase-functions";
|
|
2
2
|
|
|
3
|
-
// // Start writing
|
|
3
|
+
// // Start writing functions
|
|
4
4
|
// // https://firebase.google.com/docs/functions/typescript
|
|
5
5
|
//
|
|
6
6
|
// export const helloWorld = functions.https.onRequest((request, response) => {
|