firebase-tools 11.6.0 → 11.8.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/auth.js +1 -1
- 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/functions-delete.js +2 -0
- package/lib/commands/functions-secrets-get.js +2 -0
- package/lib/commands/index.js +3 -0
- package/lib/crashlytics/buildToolsJarHelper.js +51 -0
- package/lib/deploy/functions/backend.js +4 -4
- package/lib/deploy/functions/build.js +98 -17
- package/lib/deploy/functions/cache/applyHash.js +29 -0
- package/lib/deploy/functions/cache/hash.js +30 -0
- package/lib/deploy/functions/cel.js +249 -0
- package/lib/deploy/functions/checkIam.js +6 -5
- package/lib/deploy/functions/functionsDeployHelper.js +12 -1
- package/lib/deploy/functions/params.js +262 -105
- package/lib/deploy/functions/prepare.js +34 -4
- package/lib/deploy/functions/prepareFunctionsUpload.js +12 -4
- package/lib/deploy/functions/release/fabricator.js +39 -6
- package/lib/deploy/functions/release/index.js +2 -0
- package/lib/deploy/functions/release/planner.js +17 -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 +10 -1
- package/lib/emulator/constants.js +1 -1
- package/lib/emulator/controller.js +6 -11
- package/lib/emulator/extensionsEmulator.js +1 -0
- package/lib/emulator/functionsEmulator.js +18 -59
- package/lib/emulator/functionsEmulatorRuntime.js +12 -23
- package/lib/emulator/functionsRuntimeWorker.js +38 -7
- package/lib/emulator/storage/apis/firebase.js +145 -129
- package/lib/emulator/storage/apis/gcloud.js +102 -42
- package/lib/emulator/storage/files.js +25 -15
- package/lib/emulator/storage/metadata.js +86 -56
- package/lib/emulator/storage/multipart.js +2 -2
- package/lib/emulator/storage/rules/runtime.js +10 -2
- package/lib/emulator/storage/upload.js +45 -9
- package/lib/extensions/extensionsHelper.js +1 -1
- package/lib/functions/constants.js +14 -0
- package/lib/functions/env.js +9 -9
- package/lib/functions/secrets.js +8 -1
- package/lib/gcp/cloudfunctions.js +15 -18
- package/lib/gcp/cloudfunctionsv2.js +15 -18
- package/lib/gcp/cloudscheduler.js +32 -14
- package/lib/gcp/secretManager.js +15 -1
- package/lib/gcp/storage.js +15 -1
- package/lib/previews.js +1 -1
- package/lib/track.js +3 -0
- package/npm-shrinkwrap.json +563 -30
- package/package.json +7 -5
- package/templates/init/storage/storage.rules +1 -1
|
@@ -54,7 +54,11 @@ class FunctionsEmulator {
|
|
|
54
54
|
const mode = this.args.debugPort
|
|
55
55
|
? types_1.FunctionsExecutionMode.SEQUENTIAL
|
|
56
56
|
: types_1.FunctionsExecutionMode.AUTO;
|
|
57
|
-
this.
|
|
57
|
+
this.workerPools = {};
|
|
58
|
+
for (const backend of this.args.emulatableBackends) {
|
|
59
|
+
const pool = new functionsRuntimeWorker_1.RuntimeWorkerPool(mode);
|
|
60
|
+
this.workerPools[backend.codebase] = pool;
|
|
61
|
+
}
|
|
58
62
|
this.workQueue = new workQueue_1.WorkQueue(mode);
|
|
59
63
|
}
|
|
60
64
|
static getHttpFunctionUrl(host, port, projectId, name, region) {
|
|
@@ -241,7 +245,9 @@ class FunctionsEmulator {
|
|
|
241
245
|
this.logger.logLabeled("WARN", "functions", "Functions emulator work queue did not empty before stopping");
|
|
242
246
|
}
|
|
243
247
|
this.workQueue.stop();
|
|
244
|
-
this.
|
|
248
|
+
for (const pool of Object.values(this.workerPools)) {
|
|
249
|
+
pool.exit();
|
|
250
|
+
}
|
|
245
251
|
if (this.destroyServer) {
|
|
246
252
|
await this.destroyServer();
|
|
247
253
|
}
|
|
@@ -273,7 +279,8 @@ class FunctionsEmulator {
|
|
|
273
279
|
projectAlias: this.args.projectAlias,
|
|
274
280
|
};
|
|
275
281
|
const discoveredBuild = await runtimeDelegate.discoverBuild(runtimeConfig, environment);
|
|
276
|
-
const
|
|
282
|
+
const resolution = await (0, build_1.resolveBackend)(discoveredBuild, userEnvOpt, environment);
|
|
283
|
+
const discoveredBackend = resolution.backend;
|
|
277
284
|
const endpoints = backend.allEndpoints(discoveredBackend);
|
|
278
285
|
(0, functionsEmulatorShared_1.prepareEndpoints)(endpoints);
|
|
279
286
|
for (const e of endpoints) {
|
|
@@ -297,7 +304,7 @@ class FunctionsEmulator {
|
|
|
297
304
|
this.logger.logLabeled("ERROR", "functions", `Failed to load function definition from source: ${e}`);
|
|
298
305
|
return;
|
|
299
306
|
}
|
|
300
|
-
this.
|
|
307
|
+
this.workerPools[emulatableBackend.codebase].refresh();
|
|
301
308
|
this.blockingFunctionsConfig = {};
|
|
302
309
|
const toSetup = triggerDefinitions.filter((definition) => {
|
|
303
310
|
if (force) {
|
|
@@ -380,7 +387,7 @@ class FunctionsEmulator {
|
|
|
380
387
|
}
|
|
381
388
|
}
|
|
382
389
|
if (this.args.debugPort) {
|
|
383
|
-
this.startRuntime(emulatableBackend, { nodeBinary: emulatableBackend.nodeBinary });
|
|
390
|
+
await this.startRuntime(emulatableBackend, { nodeBinary: emulatableBackend.nodeBinary });
|
|
384
391
|
}
|
|
385
392
|
}
|
|
386
393
|
addEventarcTrigger(projectId, key, eventTrigger) {
|
|
@@ -802,10 +809,11 @@ class FunctionsEmulator {
|
|
|
802
809
|
return secretEnvs;
|
|
803
810
|
}
|
|
804
811
|
async invokeRuntime(backend, trigger, frb, opts) {
|
|
805
|
-
|
|
812
|
+
const pool = this.workerPools[backend.codebase];
|
|
813
|
+
if (!pool.readyForWork(trigger.id)) {
|
|
806
814
|
await this.startRuntime(backend, opts, trigger);
|
|
807
815
|
}
|
|
808
|
-
return
|
|
816
|
+
return pool.submitWork(trigger.id, frb, opts);
|
|
809
817
|
}
|
|
810
818
|
async startRuntime(backend, opts, trigger) {
|
|
811
819
|
var _a;
|
|
@@ -838,52 +846,18 @@ class FunctionsEmulator {
|
|
|
838
846
|
env: Object.assign(Object.assign(Object.assign(Object.assign({ node: opts.nodeBinary }, process.env), runtimeEnv), secretEnvs), { PORT: socketPath }),
|
|
839
847
|
stdio: ["pipe", "pipe", "pipe", "ipc"],
|
|
840
848
|
});
|
|
841
|
-
if (!childProcess.stderr) {
|
|
842
|
-
throw new error_1.FirebaseError(`childProcess.stderr is undefined.`);
|
|
843
|
-
}
|
|
844
|
-
if (!childProcess.stdout) {
|
|
845
|
-
throw new error_1.FirebaseError(`childProcess.stdout is undefined.`);
|
|
846
|
-
}
|
|
847
|
-
const buffers = {
|
|
848
|
-
stderr: { pipe: childProcess.stderr, value: "" },
|
|
849
|
-
stdout: { pipe: childProcess.stdout, value: "" },
|
|
850
|
-
};
|
|
851
|
-
const ipcBuffer = { value: "" };
|
|
852
|
-
childProcess.on("message", (message) => {
|
|
853
|
-
this.onData(childProcess, emitter, ipcBuffer, message);
|
|
854
|
-
});
|
|
855
|
-
for (const id in buffers) {
|
|
856
|
-
if (buffers.hasOwnProperty(id)) {
|
|
857
|
-
const buffer = buffers[id];
|
|
858
|
-
buffer.pipe.on("data", (buf) => {
|
|
859
|
-
this.onData(childProcess, emitter, buffer, buf);
|
|
860
|
-
});
|
|
861
|
-
}
|
|
862
|
-
}
|
|
863
849
|
const runtime = {
|
|
864
|
-
|
|
865
|
-
exit: new Promise((resolve) => {
|
|
866
|
-
childProcess.on("exit", resolve);
|
|
867
|
-
}),
|
|
850
|
+
process: childProcess,
|
|
868
851
|
events: emitter,
|
|
869
852
|
cwd: backend.functionsDir,
|
|
870
853
|
socketPath,
|
|
871
|
-
shutdown: () => {
|
|
872
|
-
childProcess.kill();
|
|
873
|
-
},
|
|
874
|
-
kill: (signal) => {
|
|
875
|
-
childProcess.kill(signal);
|
|
876
|
-
emitter.emit("log", new types_1.EmulatorLog("SYSTEM", "runtime-status", "killed"));
|
|
877
|
-
},
|
|
878
|
-
send: (args) => {
|
|
879
|
-
return childProcess.send(JSON.stringify(args));
|
|
880
|
-
},
|
|
881
854
|
};
|
|
882
855
|
const extensionLogInfo = {
|
|
883
856
|
instanceId: backend.extensionInstanceId,
|
|
884
857
|
ref: (_a = backend.extensionVersion) === null || _a === void 0 ? void 0 : _a.ref,
|
|
885
858
|
};
|
|
886
|
-
|
|
859
|
+
const pool = this.workerPools[backend.codebase];
|
|
860
|
+
pool.addWorker(trigger === null || trigger === void 0 ? void 0 : trigger.id, runtime, extensionLogInfo);
|
|
887
861
|
return;
|
|
888
862
|
}
|
|
889
863
|
async disableBackgroundTriggers() {
|
|
@@ -1057,20 +1031,5 @@ class FunctionsEmulator {
|
|
|
1057
1031
|
});
|
|
1058
1032
|
await worker.waitForDone();
|
|
1059
1033
|
}
|
|
1060
|
-
onData(runtime, emitter, buffer, buf) {
|
|
1061
|
-
buffer.value += buf.toString();
|
|
1062
|
-
const lines = buffer.value.split("\n");
|
|
1063
|
-
if (lines.length > 1) {
|
|
1064
|
-
lines.slice(0, -1).forEach((line) => {
|
|
1065
|
-
const log = types_1.EmulatorLog.fromJSON(line);
|
|
1066
|
-
emitter.emit("log", log);
|
|
1067
|
-
if (log.level === "FATAL") {
|
|
1068
|
-
emitter.emit("log", new types_1.EmulatorLog("SYSTEM", "runtime-status", "killed"));
|
|
1069
|
-
runtime.kill();
|
|
1070
|
-
}
|
|
1071
|
-
});
|
|
1072
|
-
}
|
|
1073
|
-
buffer.value = lines[lines.length - 1];
|
|
1074
|
-
}
|
|
1075
1034
|
}
|
|
1076
1035
|
exports.FunctionsEmulator = FunctionsEmulator;
|
|
@@ -675,24 +675,19 @@ async function initializeRuntime() {
|
|
|
675
675
|
await initializeFirebaseFunctionsStubs();
|
|
676
676
|
await initializeFirebaseAdminStubs();
|
|
677
677
|
}
|
|
678
|
-
async function loadTriggers(
|
|
678
|
+
async function loadTriggers() {
|
|
679
679
|
let triggerModule;
|
|
680
|
-
|
|
681
|
-
triggerModule =
|
|
680
|
+
try {
|
|
681
|
+
triggerModule = require(process.cwd());
|
|
682
682
|
}
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
catch (err) {
|
|
688
|
-
if (err.code !== "ERR_REQUIRE_ESM") {
|
|
689
|
-
await moduleResolutionDetective(err);
|
|
690
|
-
throw err;
|
|
691
|
-
}
|
|
692
|
-
const modulePath = require.resolve(process.cwd());
|
|
693
|
-
const moduleURL = (0, url_1.pathToFileURL)(modulePath).href;
|
|
694
|
-
triggerModule = await dynamicImport(moduleURL);
|
|
683
|
+
catch (err) {
|
|
684
|
+
if (err.code !== "ERR_REQUIRE_ESM") {
|
|
685
|
+
await moduleResolutionDetective(err);
|
|
686
|
+
throw err;
|
|
695
687
|
}
|
|
688
|
+
const modulePath = require.resolve(process.cwd());
|
|
689
|
+
const moduleURL = (0, url_1.pathToFileURL)(modulePath).href;
|
|
690
|
+
triggerModule = await dynamicImport(moduleURL);
|
|
696
691
|
}
|
|
697
692
|
return triggerModule;
|
|
698
693
|
}
|
|
@@ -716,8 +711,7 @@ async function handleMessage(message) {
|
|
|
716
711
|
}
|
|
717
712
|
if (!functionModule) {
|
|
718
713
|
try {
|
|
719
|
-
|
|
720
|
-
functionModule = await loadTriggers(serializedTriggers);
|
|
714
|
+
functionModule = await loadTriggers();
|
|
721
715
|
}
|
|
722
716
|
catch (e) {
|
|
723
717
|
logDebug(e);
|
|
@@ -739,12 +733,7 @@ async function handleMessage(message) {
|
|
|
739
733
|
logDebug(`Beginning invocation function ${FUNCTION_TARGET_NAME}!`);
|
|
740
734
|
try {
|
|
741
735
|
await invokeTrigger(trigger, runtimeArgs.frb);
|
|
742
|
-
|
|
743
|
-
await flushAndExit(0);
|
|
744
|
-
}
|
|
745
|
-
else {
|
|
746
|
-
await goIdle();
|
|
747
|
-
}
|
|
736
|
+
await goIdle();
|
|
748
737
|
}
|
|
749
738
|
catch (err) {
|
|
750
739
|
new types_1.EmulatorLog("FATAL", "runtime-error", err.stack ? err.stack : err).log();
|
|
@@ -30,21 +30,52 @@ class RuntimeWorker {
|
|
|
30
30
|
}
|
|
31
31
|
else if (this.state === RuntimeWorkerState.FINISHING) {
|
|
32
32
|
this.log(`IDLE --> FINISHING`);
|
|
33
|
-
this.runtime.
|
|
33
|
+
this.runtime.process.kill();
|
|
34
34
|
}
|
|
35
35
|
}
|
|
36
36
|
}
|
|
37
37
|
});
|
|
38
|
-
this.runtime.
|
|
38
|
+
const childProc = this.runtime.process;
|
|
39
|
+
let msgBuffer = "";
|
|
40
|
+
childProc.on("message", (msg) => {
|
|
41
|
+
msgBuffer = this.processStream(msg, msgBuffer);
|
|
42
|
+
});
|
|
43
|
+
let stdBuffer = "";
|
|
44
|
+
if (childProc.stdout) {
|
|
45
|
+
childProc.stdout.on("data", (data) => {
|
|
46
|
+
stdBuffer = this.processStream(data, stdBuffer);
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
if (childProc.stderr) {
|
|
50
|
+
childProc.stderr.on("data", (data) => {
|
|
51
|
+
stdBuffer = this.processStream(data, stdBuffer);
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
childProc.on("exit", () => {
|
|
39
55
|
this.log("exited");
|
|
40
56
|
this.state = RuntimeWorkerState.FINISHED;
|
|
41
57
|
});
|
|
42
58
|
}
|
|
59
|
+
processStream(s, buf) {
|
|
60
|
+
buf += s.toString();
|
|
61
|
+
const lines = buf.split("\n");
|
|
62
|
+
if (lines.length > 1) {
|
|
63
|
+
lines.slice(0, -1).forEach((line) => {
|
|
64
|
+
const log = types_1.EmulatorLog.fromJSON(line);
|
|
65
|
+
this.runtime.events.emit("log", log);
|
|
66
|
+
if (log.level === "FATAL") {
|
|
67
|
+
this.runtime.events.emit("log", new types_1.EmulatorLog("SYSTEM", "runtime-status", "killed"));
|
|
68
|
+
this.runtime.process.kill();
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
return lines[lines.length - 1];
|
|
73
|
+
}
|
|
43
74
|
execute(frb, opts) {
|
|
44
75
|
const execFrb = Object.assign({}, frb);
|
|
45
76
|
const args = { frb: execFrb, opts };
|
|
46
77
|
this.state = RuntimeWorkerState.BUSY;
|
|
47
|
-
this.runtime.send(args);
|
|
78
|
+
this.runtime.process.send(JSON.stringify(args));
|
|
48
79
|
}
|
|
49
80
|
get state() {
|
|
50
81
|
return this._state;
|
|
@@ -102,7 +133,7 @@ class RuntimeWorker {
|
|
|
102
133
|
const timeout = new Promise((resolve, reject) => {
|
|
103
134
|
setTimeout(() => {
|
|
104
135
|
reject(new error_1.FirebaseError("Failed to load function."));
|
|
105
|
-
},
|
|
136
|
+
}, 30000);
|
|
106
137
|
});
|
|
107
138
|
while (true) {
|
|
108
139
|
try {
|
|
@@ -142,7 +173,7 @@ class RuntimeWorkerPool {
|
|
|
142
173
|
if (w.state === RuntimeWorkerState.IDLE) {
|
|
143
174
|
this.log(`Shutting down IDLE worker (${w.key})`);
|
|
144
175
|
w.state = RuntimeWorkerState.FINISHING;
|
|
145
|
-
w.runtime.
|
|
176
|
+
w.runtime.process.kill();
|
|
146
177
|
}
|
|
147
178
|
else if (w.state === RuntimeWorkerState.BUSY) {
|
|
148
179
|
this.log(`Marking BUSY worker to finish (${w.key})`);
|
|
@@ -155,10 +186,10 @@ class RuntimeWorkerPool {
|
|
|
155
186
|
for (const arr of this.workers.values()) {
|
|
156
187
|
arr.forEach((w) => {
|
|
157
188
|
if (w.state === RuntimeWorkerState.IDLE) {
|
|
158
|
-
w.runtime.
|
|
189
|
+
w.runtime.process.kill();
|
|
159
190
|
}
|
|
160
191
|
else {
|
|
161
|
-
w.runtime.kill();
|
|
192
|
+
w.runtime.process.kill();
|
|
162
193
|
}
|
|
163
194
|
});
|
|
164
195
|
}
|
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.createFirebaseEndpoints = void 0;
|
|
4
4
|
const emulatorLogger_1 = require("../../emulatorLogger");
|
|
5
5
|
const types_1 = require("../../types");
|
|
6
|
+
const uuid = require("uuid");
|
|
6
7
|
const zlib_1 = require("zlib");
|
|
7
8
|
const metadata_1 = require("../metadata");
|
|
8
9
|
const express_1 = require("express");
|
|
@@ -93,8 +94,8 @@ function createFirebaseEndpoints(emulator) {
|
|
|
93
94
|
}
|
|
94
95
|
throw err;
|
|
95
96
|
}
|
|
96
|
-
if (
|
|
97
|
-
metadata.addDownloadToken();
|
|
97
|
+
if (metadata.downloadTokens.length === 0) {
|
|
98
|
+
metadata.addDownloadToken(true);
|
|
98
99
|
}
|
|
99
100
|
if (req.query.alt === "media") {
|
|
100
101
|
const isGZipped = metadata.contentEncoding === "gzip";
|
|
@@ -102,7 +103,8 @@ function createFirebaseEndpoints(emulator) {
|
|
|
102
103
|
data = (0, zlib_1.gunzipSync)(data);
|
|
103
104
|
}
|
|
104
105
|
res.setHeader("Accept-Ranges", "bytes");
|
|
105
|
-
res.setHeader("Content-Type", metadata.contentType);
|
|
106
|
+
res.setHeader("Content-Type", metadata.contentType || "application/octet-stream");
|
|
107
|
+
res.setHeader("Content-Disposition", metadata.contentDisposition || "inline");
|
|
106
108
|
setObjectHeaders(res, metadata, { "Content-Encoding": isGZipped ? "identity" : undefined });
|
|
107
109
|
const byteRange = req.range(data.byteLength, { combine: true });
|
|
108
110
|
if (Array.isArray(byteRange) && byteRange.type === "bytes" && byteRange.length > 0) {
|
|
@@ -165,47 +167,26 @@ function createFirebaseEndpoints(emulator) {
|
|
|
165
167
|
});
|
|
166
168
|
});
|
|
167
169
|
const handleUpload = async (req, res) => {
|
|
168
|
-
|
|
169
|
-
res.sendStatus(400);
|
|
170
|
-
return;
|
|
171
|
-
}
|
|
170
|
+
var _a, _b;
|
|
172
171
|
const bucketId = req.params.bucketId;
|
|
173
|
-
const objectId = req.
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
172
|
+
const objectId = req.params.objectId
|
|
173
|
+
? decodeURIComponent(req.params.objectId)
|
|
174
|
+
: ((_a = req.query.name) === null || _a === void 0 ? void 0 : _a.toString()) || null;
|
|
175
|
+
const uploadType = (_b = req.header("x-goog-upload-protocol")) === null || _b === void 0 ? void 0 : _b.toString();
|
|
176
|
+
async function finalizeOneShotUpload(upload) {
|
|
177
|
+
var _a, _b, _c;
|
|
178
|
+
if (!((_b = (_a = upload.metadata) === null || _a === void 0 ? void 0 : _a.metadata) === null || _b === void 0 ? void 0 : _b.firebaseStorageDownloadTokens)) {
|
|
179
|
+
const customMetadata = Object.assign(Object.assign({}, (((_c = upload.metadata) === null || _c === void 0 ? void 0 : _c.metadata) || {})), { firebaseStorageDownloadTokens: uuid.v4() });
|
|
180
|
+
upload.metadata = Object.assign(Object.assign({}, (upload.metadata || {})), { metadata: customMetadata });
|
|
179
181
|
}
|
|
180
|
-
let metadataRaw;
|
|
181
|
-
let dataRaw;
|
|
182
|
-
try {
|
|
183
|
-
({ metadataRaw, dataRaw } = (0, multipart_1.parseObjectUploadMultipartRequest)(contentTypeHeader, await (0, request_1.reqBodyToBuffer)(req)));
|
|
184
|
-
}
|
|
185
|
-
catch (err) {
|
|
186
|
-
if (err instanceof Error) {
|
|
187
|
-
return res.status(400).json({
|
|
188
|
-
error: {
|
|
189
|
-
code: 400,
|
|
190
|
-
message: err.message,
|
|
191
|
-
},
|
|
192
|
-
});
|
|
193
|
-
}
|
|
194
|
-
throw err;
|
|
195
|
-
}
|
|
196
|
-
const upload = uploadService.multipartUpload({
|
|
197
|
-
bucketId,
|
|
198
|
-
objectId,
|
|
199
|
-
metadataRaw,
|
|
200
|
-
dataRaw: dataRaw,
|
|
201
|
-
authorization: req.header("authorization"),
|
|
202
|
-
});
|
|
203
182
|
let metadata;
|
|
204
183
|
try {
|
|
205
184
|
metadata = await storageLayer.uploadObject(upload);
|
|
206
185
|
}
|
|
207
186
|
catch (err) {
|
|
208
187
|
if (err instanceof errors_1.ForbiddenError) {
|
|
188
|
+
res.header("x-goog-upload-status", "final");
|
|
189
|
+
uploadService.setResponseCode(upload.id, 403);
|
|
209
190
|
return res.status(403).json({
|
|
210
191
|
error: {
|
|
211
192
|
code: 403,
|
|
@@ -215,120 +196,153 @@ function createFirebaseEndpoints(emulator) {
|
|
|
215
196
|
}
|
|
216
197
|
throw err;
|
|
217
198
|
}
|
|
218
|
-
metadata.
|
|
199
|
+
if (!metadata.contentDisposition) {
|
|
200
|
+
metadata.contentDisposition = "inline";
|
|
201
|
+
}
|
|
219
202
|
return res.status(200).json(new metadata_1.OutgoingFirebaseMetadata(metadata));
|
|
220
203
|
}
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
authorization: req.header("authorization"),
|
|
232
|
-
});
|
|
233
|
-
res.header("x-goog-upload-chunk-granularity", "10000");
|
|
234
|
-
res.header("x-goog-upload-control-url", "");
|
|
235
|
-
res.header("x-goog-upload-status", "active");
|
|
236
|
-
res.header("x-gupload-uploadid", upload.id);
|
|
237
|
-
const uploadUrl = registry_1.EmulatorRegistry.url(types_1.Emulators.STORAGE, req);
|
|
238
|
-
uploadUrl.pathname = `/v0/b/${bucketId}/o`;
|
|
239
|
-
uploadUrl.searchParams.set("name", objectId);
|
|
240
|
-
uploadUrl.searchParams.set("upload_id", upload.id);
|
|
241
|
-
uploadUrl.searchParams.set("upload_protocol", "resumable");
|
|
242
|
-
res.header("x-goog-upload-url", uploadUrl.toString());
|
|
243
|
-
return res.sendStatus(200);
|
|
244
|
-
}
|
|
245
|
-
if (!req.query.upload_id) {
|
|
246
|
-
return res.sendStatus(400);
|
|
247
|
-
}
|
|
248
|
-
const uploadId = req.query.upload_id.toString();
|
|
249
|
-
if (uploadCommand === "query") {
|
|
250
|
-
let upload;
|
|
251
|
-
try {
|
|
252
|
-
upload = uploadService.getResumableUpload(uploadId);
|
|
253
|
-
}
|
|
254
|
-
catch (err) {
|
|
255
|
-
if (err instanceof errors_1.NotFoundError) {
|
|
256
|
-
return res.sendStatus(404);
|
|
204
|
+
if (uploadType === "resumable") {
|
|
205
|
+
const uploadCommand = req.header("x-goog-upload-command");
|
|
206
|
+
if (!uploadCommand) {
|
|
207
|
+
res.sendStatus(400);
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
if (uploadCommand === "start") {
|
|
211
|
+
if (!objectId) {
|
|
212
|
+
res.sendStatus(400);
|
|
213
|
+
return;
|
|
257
214
|
}
|
|
258
|
-
|
|
215
|
+
const upload = uploadService.startResumableUpload({
|
|
216
|
+
bucketId,
|
|
217
|
+
objectId,
|
|
218
|
+
metadataRaw: JSON.stringify(req.body),
|
|
219
|
+
authorization: req.header("authorization"),
|
|
220
|
+
});
|
|
221
|
+
res.header("x-goog-upload-chunk-granularity", "10000");
|
|
222
|
+
res.header("x-goog-upload-control-url", "");
|
|
223
|
+
res.header("x-goog-upload-status", "active");
|
|
224
|
+
res.header("x-gupload-uploadid", upload.id);
|
|
225
|
+
const uploadUrl = registry_1.EmulatorRegistry.url(types_1.Emulators.STORAGE, req);
|
|
226
|
+
uploadUrl.pathname = `/v0/b/${bucketId}/o`;
|
|
227
|
+
uploadUrl.searchParams.set("name", objectId);
|
|
228
|
+
uploadUrl.searchParams.set("upload_id", upload.id);
|
|
229
|
+
uploadUrl.searchParams.set("upload_protocol", "resumable");
|
|
230
|
+
res.header("x-goog-upload-url", uploadUrl.toString());
|
|
231
|
+
return res.sendStatus(200);
|
|
259
232
|
}
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
}
|
|
263
|
-
if (uploadCommand === "cancel") {
|
|
264
|
-
try {
|
|
265
|
-
uploadService.cancelResumableUpload(uploadId);
|
|
233
|
+
if (!req.query.upload_id) {
|
|
234
|
+
return res.sendStatus(400);
|
|
266
235
|
}
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
236
|
+
const uploadId = req.query.upload_id.toString();
|
|
237
|
+
if (uploadCommand === "query") {
|
|
238
|
+
let upload;
|
|
239
|
+
try {
|
|
240
|
+
upload = uploadService.getResumableUpload(uploadId);
|
|
270
241
|
}
|
|
271
|
-
|
|
272
|
-
|
|
242
|
+
catch (err) {
|
|
243
|
+
if (err instanceof errors_1.NotFoundError) {
|
|
244
|
+
return res.sendStatus(404);
|
|
245
|
+
}
|
|
246
|
+
throw err;
|
|
273
247
|
}
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
return res.sendStatus(200);
|
|
277
|
-
}
|
|
278
|
-
if (uploadCommand.includes("upload")) {
|
|
279
|
-
let upload;
|
|
280
|
-
try {
|
|
281
|
-
upload = uploadService.continueResumableUpload(uploadId, await (0, request_1.reqBodyToBuffer)(req));
|
|
248
|
+
res.header("X-Goog-Upload-Size-Received", upload.size.toString());
|
|
249
|
+
return res.sendStatus(200);
|
|
282
250
|
}
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
251
|
+
if (uploadCommand === "cancel") {
|
|
252
|
+
try {
|
|
253
|
+
uploadService.cancelResumableUpload(uploadId);
|
|
286
254
|
}
|
|
287
|
-
|
|
288
|
-
|
|
255
|
+
catch (err) {
|
|
256
|
+
if (err instanceof errors_1.NotFoundError) {
|
|
257
|
+
return res.sendStatus(404);
|
|
258
|
+
}
|
|
259
|
+
else if (err instanceof upload_1.NotCancellableError) {
|
|
260
|
+
return res.sendStatus(400);
|
|
261
|
+
}
|
|
262
|
+
throw err;
|
|
289
263
|
}
|
|
290
|
-
throw err;
|
|
291
|
-
}
|
|
292
|
-
if (!uploadCommand.includes("finalize")) {
|
|
293
|
-
res.header("x-goog-upload-status", "active");
|
|
294
|
-
res.header("x-gupload-uploadid", upload.id);
|
|
295
264
|
return res.sendStatus(200);
|
|
296
265
|
}
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
266
|
+
if (uploadCommand.includes("upload")) {
|
|
267
|
+
let upload;
|
|
268
|
+
try {
|
|
269
|
+
upload = uploadService.continueResumableUpload(uploadId, await (0, request_1.reqBodyToBuffer)(req));
|
|
270
|
+
}
|
|
271
|
+
catch (err) {
|
|
272
|
+
if (err instanceof errors_1.NotFoundError) {
|
|
273
|
+
return res.sendStatus(404);
|
|
274
|
+
}
|
|
275
|
+
else if (err instanceof upload_1.UploadNotActiveError) {
|
|
276
|
+
return res.sendStatus(400);
|
|
277
|
+
}
|
|
278
|
+
throw err;
|
|
279
|
+
}
|
|
280
|
+
if (!uploadCommand.includes("finalize")) {
|
|
281
|
+
res.header("x-goog-upload-status", "active");
|
|
282
|
+
res.header("x-gupload-uploadid", upload.id);
|
|
283
|
+
return res.sendStatus(200);
|
|
284
|
+
}
|
|
302
285
|
}
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
286
|
+
if (uploadCommand.includes("finalize")) {
|
|
287
|
+
let upload;
|
|
288
|
+
try {
|
|
289
|
+
upload = uploadService.finalizeResumableUpload(uploadId);
|
|
306
290
|
}
|
|
307
|
-
|
|
308
|
-
|
|
291
|
+
catch (err) {
|
|
292
|
+
if (err instanceof errors_1.NotFoundError) {
|
|
293
|
+
uploadService.setResponseCode(uploadId, 404);
|
|
294
|
+
return res.sendStatus(404);
|
|
295
|
+
}
|
|
296
|
+
else if (err instanceof upload_1.UploadNotActiveError) {
|
|
297
|
+
uploadService.setResponseCode(uploadId, 400);
|
|
298
|
+
return res.sendStatus(400);
|
|
299
|
+
}
|
|
300
|
+
else if (err instanceof upload_1.UploadPreviouslyFinalizedError) {
|
|
301
|
+
res.header("x-goog-upload-status", "final");
|
|
302
|
+
return res.sendStatus(uploadService.getPreviousResponseCode(uploadId));
|
|
303
|
+
}
|
|
304
|
+
throw err;
|
|
309
305
|
}
|
|
310
|
-
|
|
306
|
+
res.header("x-goog-upload-status", "final");
|
|
307
|
+
return await finalizeOneShotUpload(upload);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
if (!objectId) {
|
|
311
|
+
res.sendStatus(400);
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
314
|
+
if (uploadType === "multipart") {
|
|
315
|
+
const contentTypeHeader = req.header("content-type");
|
|
316
|
+
if (!contentTypeHeader) {
|
|
317
|
+
return res.sendStatus(400);
|
|
311
318
|
}
|
|
312
|
-
let
|
|
319
|
+
let metadataRaw;
|
|
320
|
+
let dataRaw;
|
|
313
321
|
try {
|
|
314
|
-
|
|
322
|
+
({ metadataRaw, dataRaw } = (0, multipart_1.parseObjectUploadMultipartRequest)(contentTypeHeader, await (0, request_1.reqBodyToBuffer)(req)));
|
|
315
323
|
}
|
|
316
324
|
catch (err) {
|
|
317
|
-
if (err instanceof
|
|
318
|
-
return res.status(
|
|
319
|
-
error: {
|
|
320
|
-
code: 403,
|
|
321
|
-
message: `Permission denied. No WRITE permission.`,
|
|
322
|
-
},
|
|
323
|
-
});
|
|
325
|
+
if (err instanceof Error) {
|
|
326
|
+
return res.status(400).send(err.message);
|
|
324
327
|
}
|
|
325
328
|
throw err;
|
|
326
329
|
}
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
+
const upload = uploadService.multipartUpload({
|
|
331
|
+
bucketId,
|
|
332
|
+
objectId,
|
|
333
|
+
metadataRaw,
|
|
334
|
+
dataRaw: dataRaw,
|
|
335
|
+
authorization: req.header("authorization"),
|
|
336
|
+
});
|
|
337
|
+
return await finalizeOneShotUpload(upload);
|
|
330
338
|
}
|
|
331
|
-
|
|
339
|
+
const upload = uploadService.mediaUpload({
|
|
340
|
+
bucketId: req.params.bucketId,
|
|
341
|
+
objectId: objectId,
|
|
342
|
+
dataRaw: await (0, request_1.reqBodyToBuffer)(req),
|
|
343
|
+
authorization: req.header("authorization"),
|
|
344
|
+
});
|
|
345
|
+
return await finalizeOneShotUpload(upload);
|
|
332
346
|
};
|
|
333
347
|
const handleTokenRequest = (req, res) => {
|
|
334
348
|
var _a, _b;
|
|
@@ -467,11 +481,13 @@ function createFirebaseEndpoints(emulator) {
|
|
|
467
481
|
}
|
|
468
482
|
exports.createFirebaseEndpoints = createFirebaseEndpoints;
|
|
469
483
|
function setObjectHeaders(res, metadata, headerOverride = { "Content-Encoding": undefined }) {
|
|
470
|
-
|
|
484
|
+
if (metadata.contentDisposition) {
|
|
485
|
+
res.setHeader("Content-Disposition", metadata.contentDisposition);
|
|
486
|
+
}
|
|
471
487
|
if (headerOverride["Content-Encoding"]) {
|
|
472
488
|
res.setHeader("Content-Encoding", headerOverride["Content-Encoding"]);
|
|
473
489
|
}
|
|
474
|
-
else {
|
|
490
|
+
else if (metadata.contentEncoding) {
|
|
475
491
|
res.setHeader("Content-Encoding", metadata.contentEncoding);
|
|
476
492
|
}
|
|
477
493
|
if (metadata.cacheControl) {
|