firebase-tools 11.4.2 → 11.7.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/accountImporter.js +1 -1
- package/lib/auth.js +3 -4
- package/lib/bin/firebase.js +4 -4
- package/lib/command.js +35 -10
- package/lib/commands/apps-android-sha-create.js +1 -1
- package/lib/commands/apps-android-sha-delete.js +1 -1
- package/lib/commands/apps-create.js +1 -1
- package/lib/commands/apps-list.js +1 -1
- package/lib/commands/auth-export.js +1 -1
- package/lib/commands/auth-import.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/database-instances-list.js +1 -1
- package/lib/commands/database-push.js +1 -1
- package/lib/commands/database-remove.js +1 -1
- package/lib/commands/database-set.js +1 -1
- package/lib/commands/database-update.js +1 -1
- package/lib/commands/emulators-exec.js +4 -1
- package/lib/commands/emulators-export.js +5 -2
- package/lib/commands/emulators-start.js +24 -18
- package/lib/commands/ext-dev-deprecate.js +1 -1
- package/lib/commands/ext-dev-emulators-exec.js +1 -1
- package/lib/commands/ext-dev-emulators-start.js +1 -1
- package/lib/commands/ext-dev-extension-delete.js +1 -1
- package/lib/commands/ext-dev-list.js +1 -1
- package/lib/commands/ext-dev-publish.js +4 -1
- package/lib/commands/ext-dev-register.js +1 -1
- package/lib/commands/ext-dev-undeprecate.js +1 -1
- package/lib/commands/ext-dev-unpublish.js +1 -1
- package/lib/commands/ext-dev-usage.js +1 -1
- package/lib/commands/ext-info.js +1 -1
- package/lib/commands/ext-install.js +2 -2
- package/lib/commands/ext-update.js +1 -1
- package/lib/commands/ext.js +1 -1
- package/lib/commands/firestore-delete.js +2 -2
- package/lib/commands/firestore-indexes-list.js +3 -3
- package/lib/commands/functions-config-clone.js +1 -1
- package/lib/commands/functions-config-export.js +1 -1
- package/lib/commands/functions-config-set.js +1 -1
- package/lib/commands/functions-config-unset.js +1 -1
- package/lib/commands/functions-delete.js +3 -1
- package/lib/commands/functions-secrets-get.js +2 -0
- package/lib/commands/functions-secrets-set.js +1 -1
- package/lib/commands/help.js +1 -1
- package/lib/commands/hosting-channel-create.js +5 -5
- package/lib/commands/hosting-channel-delete.js +3 -3
- package/lib/commands/hosting-channel-deploy.js +6 -6
- package/lib/commands/hosting-channel-list.js +2 -2
- package/lib/commands/hosting-channel-open.js +2 -2
- package/lib/commands/hosting-clone.js +8 -8
- package/lib/commands/hosting-disable.js +1 -1
- package/lib/commands/hosting-sites-create.js +4 -4
- package/lib/commands/hosting-sites-delete.js +4 -4
- package/lib/commands/hosting-sites-list.js +2 -2
- package/lib/commands/index.js +3 -0
- package/lib/commands/init.js +5 -5
- package/lib/commands/login-add.js +1 -1
- package/lib/commands/login-ci.js +2 -2
- package/lib/commands/login-list.js +1 -1
- package/lib/commands/login-use.js +1 -1
- package/lib/commands/login.js +3 -3
- package/lib/commands/logout.js +1 -1
- package/lib/commands/open.js +3 -3
- package/lib/commands/projects-list.js +2 -2
- package/lib/commands/serve.js +1 -1
- package/lib/commands/target-apply.js +1 -1
- package/lib/commands/target-clear.js +1 -1
- package/lib/commands/target-remove.js +1 -1
- package/lib/commands/target.js +1 -1
- package/lib/commands/use.js +7 -7
- package/lib/config.js +1 -1
- package/lib/crashlytics/buildToolsJarHelper.js +51 -0
- package/lib/deploy/database/prepare.js +3 -3
- package/lib/deploy/database/release.js +3 -3
- package/lib/deploy/extensions/deploymentSummary.js +1 -1
- package/lib/deploy/extensions/errors.js +1 -1
- package/lib/deploy/extensions/secrets.js +1 -1
- package/lib/deploy/extensions/tasks.js +2 -2
- package/lib/deploy/firestore/deploy.js +2 -2
- package/lib/deploy/firestore/prepare.js +2 -2
- package/lib/deploy/functions/backend.js +4 -4
- package/lib/deploy/functions/build.js +78 -8
- package/lib/deploy/functions/checkIam.js +9 -8
- package/lib/deploy/functions/containerCleaner.js +2 -2
- package/lib/deploy/functions/deploy.js +2 -2
- package/lib/deploy/functions/ensure.js +1 -1
- package/lib/deploy/functions/params.js +15 -15
- package/lib/deploy/functions/prepare.js +1 -1
- package/lib/deploy/functions/prepareFunctionsUpload.js +2 -2
- package/lib/deploy/functions/prompts.js +1 -1
- package/lib/deploy/functions/release/fabricator.js +24 -7
- package/lib/deploy/functions/release/index.js +3 -1
- package/lib/deploy/functions/release/reporter.js +1 -1
- 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/parseRuntimeAndValidateSDK.js +1 -1
- package/lib/deploy/functions/runtimes/node/parseTriggers.js +2 -6
- package/lib/deploy/functions/runtimes/node/versioning.js +4 -4
- package/lib/deploy/functions/validate.js +1 -1
- package/lib/deploy/hosting/deploy.js +10 -9
- package/lib/deploy/hosting/uploader.js +2 -2
- package/lib/deploy/hosting/validate.js +2 -2
- package/lib/deploy/index.js +7 -7
- package/lib/deploy/lifecycleHooks.js +5 -2
- package/lib/deploy/storage/prepare.js +5 -3
- package/lib/deploy/storage/release.js +7 -6
- package/lib/emulator/auth/index.js +7 -2
- package/lib/emulator/auth/operations.js +10 -10
- package/lib/emulator/commandUtils.js +33 -16
- package/lib/emulator/constants.js +14 -6
- package/lib/emulator/controller.js +50 -18
- package/lib/emulator/databaseEmulator.js +1 -1
- package/lib/emulator/downloadableEmulators.js +8 -8
- package/lib/emulator/emulatorLogger.js +1 -1
- package/lib/emulator/eventarcEmulator.js +148 -0
- package/lib/emulator/extensionsEmulator.js +5 -3
- package/lib/emulator/firestoreEmulator.js +1 -1
- package/lib/emulator/functionsEmulator.js +66 -14
- 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/loggingEmulator.js +2 -2
- package/lib/emulator/registry.js +1 -0
- package/lib/emulator/storage/apis/firebase.js +26 -12
- package/lib/emulator/storage/apis/gcloud.js +15 -8
- package/lib/emulator/storage/files.js +21 -4
- package/lib/emulator/storage/multipart.js +6 -5
- package/lib/emulator/storage/rules/runtime.js +3 -3
- package/lib/emulator/storage/rules/utils.js +4 -2
- package/lib/emulator/storage/server.js +2 -1
- package/lib/emulator/storage/upload.js +1 -0
- package/lib/emulator/types.js +4 -0
- package/lib/emulator/ui.js +7 -2
- package/lib/ensureApiEnabled.js +7 -7
- package/lib/extensions/askUserForConsent.js +1 -1
- package/lib/extensions/askUserForEventsConfig.js +1 -1
- package/lib/extensions/askUserForParam.js +1 -1
- package/lib/extensions/changelog.js +2 -2
- package/lib/extensions/checkProjectBilling.js +2 -2
- package/lib/extensions/displayExtensionInfo.js +1 -1
- package/lib/extensions/extensionsApi.js +3 -2
- package/lib/extensions/extensionsHelper.js +30 -2
- package/lib/extensions/listExtensions.js +1 -1
- package/lib/extensions/manifest.js +1 -1
- package/lib/extensions/metricsUtils.js +1 -1
- package/lib/extensions/paramHelper.js +1 -1
- package/lib/extensions/updateHelper.js +2 -2
- package/lib/extensions/warnings.js +2 -2
- package/lib/fetchMOTD.js +1 -1
- package/lib/firestore/delete.js +1 -1
- package/lib/firestore/indexes.js +2 -2
- package/lib/firestore/validator.js +1 -1
- package/lib/functions/env.js +11 -11
- package/lib/functions/runtimeConfigExport.js +1 -1
- package/lib/functionsConfig.js +1 -1
- package/lib/functionsConfigClone.js +1 -1
- package/lib/functionsShellCommandAction.js +1 -1
- package/lib/gcp/cloudfunctions.js +3 -3
- package/lib/gcp/cloudfunctionsv2.js +5 -5
- package/lib/gcp/cloudscheduler.js +63 -22
- package/lib/gcp/cloudtasks.js +17 -1
- package/lib/gcp/serviceusage.js +2 -2
- package/lib/handlePreviewToggles.js +4 -4
- package/lib/hosting/implicitInit.js +1 -1
- package/lib/hosting/normalizedHostingConfigs.js +3 -3
- package/lib/index.js +2 -2
- package/lib/init/features/database.js +1 -1
- package/lib/init/features/emulators.js +1 -1
- package/lib/init/features/firestore/index.js +2 -2
- package/lib/init/features/firestore/indexes.js +1 -1
- package/lib/init/features/firestore/rules.js +1 -1
- package/lib/init/features/functions/golang.js +1 -1
- package/lib/init/features/functions/index.js +8 -1
- package/lib/init/features/hosting/github.js +9 -9
- package/lib/init/features/hosting/index.js +1 -1
- package/lib/init/features/project.js +1 -1
- package/lib/init/features/remoteconfig.js +1 -1
- package/lib/init/features/storage.js +1 -1
- package/lib/init/index.js +1 -1
- package/lib/logError.js +3 -3
- package/lib/management/projects.js +1 -1
- package/lib/parseBoltRules.js +1 -1
- package/lib/profileReport.js +2 -2
- package/lib/projectUtils.js +1 -1
- package/lib/rc.js +1 -1
- package/lib/requireAuth.js +1 -1
- package/lib/requireDatabaseInstance.js +2 -2
- package/lib/requirePermissions.js +2 -2
- package/lib/rulesDeploy.js +11 -12
- package/lib/serve/hosting.js +2 -1
- package/lib/serve/index.js +15 -0
- package/lib/track.js +122 -3
- package/lib/utils.js +24 -11
- package/npm-shrinkwrap.json +523 -294
- package/package.json +6 -4
- package/schema/firebase-config.json +12 -0
- package/templates/extensions/CHANGELOG.md +1 -7
- package/templates/hosting/init.js +6 -2
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.EventarcEmulator = void 0;
|
|
4
|
+
const express = require("express");
|
|
5
|
+
const constants_1 = require("./constants");
|
|
6
|
+
const types_1 = require("./types");
|
|
7
|
+
const utils_1 = require("../utils");
|
|
8
|
+
const emulatorLogger_1 = require("./emulatorLogger");
|
|
9
|
+
const registry_1 = require("./registry");
|
|
10
|
+
const apiv2_1 = require("../apiv2");
|
|
11
|
+
const error_1 = require("../error");
|
|
12
|
+
class EventarcEmulator {
|
|
13
|
+
constructor(args) {
|
|
14
|
+
this.args = args;
|
|
15
|
+
this.logger = emulatorLogger_1.EmulatorLogger.forEmulator(types_1.Emulators.EVENTARC);
|
|
16
|
+
this.customEvents = {};
|
|
17
|
+
}
|
|
18
|
+
createHubServer() {
|
|
19
|
+
const registerTriggerRoute = `/emulator/v1/projects/:project_id/triggers/:trigger_name(*)`;
|
|
20
|
+
const registerTriggerHandler = (req, res) => {
|
|
21
|
+
const projectId = req.params.project_id;
|
|
22
|
+
const triggerName = req.params.trigger_name;
|
|
23
|
+
if (!projectId || !triggerName) {
|
|
24
|
+
const error = "Missing project ID or trigger name.";
|
|
25
|
+
this.logger.log("ERROR", error);
|
|
26
|
+
res.status(400).send({ error });
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
const bodyString = req.rawBody.toString();
|
|
30
|
+
const substituted = bodyString.replaceAll("${PROJECT_ID}", projectId);
|
|
31
|
+
const body = JSON.parse(substituted);
|
|
32
|
+
const eventTrigger = body.eventTrigger;
|
|
33
|
+
if (!eventTrigger) {
|
|
34
|
+
const error = `Missing event trigger for ${triggerName}.`;
|
|
35
|
+
this.logger.log("ERROR", error);
|
|
36
|
+
res.status(400).send({ error });
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
const key = `${eventTrigger.eventType}-${eventTrigger.channel}`;
|
|
40
|
+
this.logger.logLabeled("BULLET", "eventarc", `Registering custom event trigger for ${key} with trigger name ${triggerName}.`);
|
|
41
|
+
const customEventTriggers = this.customEvents[key] || [];
|
|
42
|
+
customEventTriggers.push({ projectId, triggerName, eventTrigger });
|
|
43
|
+
this.customEvents[key] = customEventTriggers;
|
|
44
|
+
res.status(200).send({ res: "OK" });
|
|
45
|
+
};
|
|
46
|
+
const publishEventsRoute = `/projects/:project_id/locations/:location/channels/:channel::publishEvents`;
|
|
47
|
+
const publishEventsHandler = (req, res) => {
|
|
48
|
+
const channel = `projects/${req.params.project_id}/locations/${req.params.location}/channels/${req.params.channel}`;
|
|
49
|
+
const body = JSON.parse(req.rawBody.toString());
|
|
50
|
+
for (const event of body.events) {
|
|
51
|
+
if (!event.type) {
|
|
52
|
+
res.sendStatus(400);
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
this.logger.log("INFO", `Received custom event at channel ${channel}: ${JSON.stringify(event, null, 2)}`);
|
|
56
|
+
this.triggerCustomEventFunction(channel, event);
|
|
57
|
+
}
|
|
58
|
+
res.sendStatus(200);
|
|
59
|
+
};
|
|
60
|
+
const dataMiddleware = (req, _, next) => {
|
|
61
|
+
const chunks = [];
|
|
62
|
+
req.on("data", (chunk) => {
|
|
63
|
+
chunks.push(chunk);
|
|
64
|
+
});
|
|
65
|
+
req.on("end", () => {
|
|
66
|
+
req.rawBody = Buffer.concat(chunks);
|
|
67
|
+
next();
|
|
68
|
+
});
|
|
69
|
+
};
|
|
70
|
+
const hub = express();
|
|
71
|
+
hub.post([registerTriggerRoute], dataMiddleware, registerTriggerHandler);
|
|
72
|
+
hub.post([publishEventsRoute], dataMiddleware, publishEventsHandler);
|
|
73
|
+
hub.all("*", (req, res) => {
|
|
74
|
+
this.logger.log("DEBUG", `Eventarc emulator received unknown request at path ${req.path}`);
|
|
75
|
+
res.sendStatus(404);
|
|
76
|
+
});
|
|
77
|
+
return hub;
|
|
78
|
+
}
|
|
79
|
+
async triggerCustomEventFunction(channel, event) {
|
|
80
|
+
const functionsEmulator = registry_1.EmulatorRegistry.get(types_1.Emulators.FUNCTIONS);
|
|
81
|
+
if (!functionsEmulator) {
|
|
82
|
+
this.logger.log("INFO", "Functions emulator not found. This should not happen.");
|
|
83
|
+
return Promise.reject();
|
|
84
|
+
}
|
|
85
|
+
const key = `${event.type}-${channel}`;
|
|
86
|
+
const triggers = this.customEvents[key] || [];
|
|
87
|
+
const apiClient = new apiv2_1.Client({
|
|
88
|
+
urlPrefix: `http://${registry_1.EmulatorRegistry.getInfoHostString(functionsEmulator.getInfo())}`,
|
|
89
|
+
auth: false,
|
|
90
|
+
});
|
|
91
|
+
return await Promise.all(triggers
|
|
92
|
+
.filter((trigger) => !trigger.eventTrigger.eventFilters ||
|
|
93
|
+
this.matchesAll(event, trigger.eventTrigger.eventFilters))
|
|
94
|
+
.map((trigger) => apiClient
|
|
95
|
+
.request({
|
|
96
|
+
method: "POST",
|
|
97
|
+
path: `/functions/projects/${trigger.projectId}/triggers/${trigger.triggerName}`,
|
|
98
|
+
body: JSON.stringify(event),
|
|
99
|
+
responseType: "stream",
|
|
100
|
+
resolveOnHTTPError: true,
|
|
101
|
+
})
|
|
102
|
+
.then((res) => {
|
|
103
|
+
if (res.status >= 400) {
|
|
104
|
+
throw new error_1.FirebaseError(`Received non-200 status code: ${res.status}`);
|
|
105
|
+
}
|
|
106
|
+
})
|
|
107
|
+
.catch((err) => {
|
|
108
|
+
this.logger.log("ERROR", `Failed to trigger Functions emulator for ${trigger.triggerName}: ${err}`);
|
|
109
|
+
})));
|
|
110
|
+
}
|
|
111
|
+
matchesAll(event, eventFilters) {
|
|
112
|
+
return Object.entries(eventFilters).every(([key, value]) => {
|
|
113
|
+
var _a, _b;
|
|
114
|
+
let attr = (_a = event[key]) !== null && _a !== void 0 ? _a : event.attributes[key];
|
|
115
|
+
if (typeof attr === "object" && !Array.isArray(attr)) {
|
|
116
|
+
attr = (_b = attr.ceTimestamp) !== null && _b !== void 0 ? _b : attr.ceString;
|
|
117
|
+
}
|
|
118
|
+
return attr === value;
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
async start() {
|
|
122
|
+
const { host, port } = this.getInfo();
|
|
123
|
+
const server = this.createHubServer().listen(port, host);
|
|
124
|
+
this.destroyServer = (0, utils_1.createDestroyer)(server);
|
|
125
|
+
return Promise.resolve();
|
|
126
|
+
}
|
|
127
|
+
async connect() {
|
|
128
|
+
return Promise.resolve();
|
|
129
|
+
}
|
|
130
|
+
async stop() {
|
|
131
|
+
if (this.destroyServer) {
|
|
132
|
+
await this.destroyServer();
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
getInfo() {
|
|
136
|
+
const host = this.args.host || constants_1.Constants.getDefaultHost();
|
|
137
|
+
const port = this.args.port || constants_1.Constants.getDefaultPort(types_1.Emulators.EVENTARC);
|
|
138
|
+
return {
|
|
139
|
+
name: this.getName(),
|
|
140
|
+
host,
|
|
141
|
+
port,
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
getName() {
|
|
145
|
+
return types_1.Emulators.EVENTARC;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
exports.EventarcEmulator = EventarcEmulator;
|
|
@@ -4,7 +4,7 @@ exports.ExtensionsEmulator = void 0;
|
|
|
4
4
|
const fs = require("fs-extra");
|
|
5
5
|
const os = require("os");
|
|
6
6
|
const path = require("path");
|
|
7
|
-
const clc = require("
|
|
7
|
+
const clc = require("colorette");
|
|
8
8
|
const Table = require("cli-table");
|
|
9
9
|
const spawn = require("cross-spawn");
|
|
10
10
|
const planner = require("../deploy/extensions/planner");
|
|
@@ -103,10 +103,11 @@ class ExtensionsEmulator {
|
|
|
103
103
|
for (const requiredFile of requiredFiles) {
|
|
104
104
|
const f = path.join(args.path, requiredFile);
|
|
105
105
|
if (!fs.existsSync(f)) {
|
|
106
|
-
|
|
106
|
+
this.logger.logLabeled("BULLET", "extensions", `Detected invalid source code for ${args.extTarget}, expected to find ${f}`);
|
|
107
107
|
return false;
|
|
108
108
|
}
|
|
109
109
|
}
|
|
110
|
+
this.logger.logLabeled("DEBUG", "extensions", `Source code valid for ${args.extTarget}`);
|
|
110
111
|
return true;
|
|
111
112
|
}
|
|
112
113
|
installAndBuildSourceCode(sourceCodePath) {
|
|
@@ -166,6 +167,7 @@ class ExtensionsEmulator {
|
|
|
166
167
|
STORAGE_BUCKET: `${projectId}.appspot.com`,
|
|
167
168
|
ALLOWED_EVENT_TYPES: instance.allowedEventTypes ? instance.allowedEventTypes.join(",") : "",
|
|
168
169
|
EVENTARC_CHANNEL: (_a = instance.eventarcChannel) !== null && _a !== void 0 ? _a : "",
|
|
170
|
+
EVENTARC_CLOUD_EVENT_SOURCE: `projects/${projectId}/instances/${instance.instanceId}`,
|
|
169
171
|
};
|
|
170
172
|
}
|
|
171
173
|
async checkAndWarnAPIs(instances) {
|
|
@@ -186,7 +188,7 @@ class ExtensionsEmulator {
|
|
|
186
188
|
apiToWarn.apiName,
|
|
187
189
|
apiToWarn.instanceIds,
|
|
188
190
|
apiToWarn.enabled ? "Yes" : "No",
|
|
189
|
-
apiToWarn.enabled ? "" : clc.bold.underline(enablementUri),
|
|
191
|
+
apiToWarn.enabled ? "" : clc.bold(clc.underline(enablementUri)),
|
|
190
192
|
]);
|
|
191
193
|
}
|
|
192
194
|
if (constants_1.Constants.isDemoProject(this.args.projectId)) {
|
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.FirestoreEmulator = void 0;
|
|
4
4
|
const chokidar = require("chokidar");
|
|
5
5
|
const fs = require("fs");
|
|
6
|
-
const clc = require("
|
|
6
|
+
const clc = require("colorette");
|
|
7
7
|
const path = require("path");
|
|
8
8
|
const utils = require("../utils");
|
|
9
9
|
const downloadableEmulators = require("./downloadableEmulators");
|
|
@@ -4,7 +4,7 @@ exports.FunctionsEmulator = void 0;
|
|
|
4
4
|
const fs = require("fs");
|
|
5
5
|
const path = require("path");
|
|
6
6
|
const express = require("express");
|
|
7
|
-
const clc = require("
|
|
7
|
+
const clc = require("colorette");
|
|
8
8
|
const http = require("http");
|
|
9
9
|
const jwt = require("jsonwebtoken");
|
|
10
10
|
const cors = require("cors");
|
|
@@ -35,6 +35,7 @@ const v1_1 = require("../functions/events/v1");
|
|
|
35
35
|
const apiv2_1 = require("../apiv2");
|
|
36
36
|
const build_1 = require("../deploy/functions/build");
|
|
37
37
|
const EVENT_INVOKE = "functions:invoke";
|
|
38
|
+
const EVENT_INVOKE_GA4 = "functions_invoke";
|
|
38
39
|
const DATABASE_PATH_PATTERN = new RegExp("^projects/[^/]+/instances/([^/]+)/refs(/.*)$");
|
|
39
40
|
class FunctionsEmulator {
|
|
40
41
|
constructor(args) {
|
|
@@ -89,7 +90,7 @@ class FunctionsEmulator {
|
|
|
89
90
|
next();
|
|
90
91
|
});
|
|
91
92
|
};
|
|
92
|
-
const backgroundFunctionRoute = `/functions/projects/:project_id/triggers/:trigger_name`;
|
|
93
|
+
const backgroundFunctionRoute = `/functions/projects/:project_id/triggers/:trigger_name(*)`;
|
|
93
94
|
const httpsFunctionRoute = `/${this.args.projectId}/:region/:trigger_name`;
|
|
94
95
|
const multicastFunctionRoute = `/functions/projects/:project_id/trigger_multicast`;
|
|
95
96
|
const httpsFunctionRoutes = [httpsFunctionRoute, `${httpsFunctionRoute}/*`];
|
|
@@ -245,15 +246,9 @@ class FunctionsEmulator {
|
|
|
245
246
|
await this.destroyServer();
|
|
246
247
|
}
|
|
247
248
|
}
|
|
248
|
-
async
|
|
249
|
-
this.workerPool.refresh();
|
|
250
|
-
if (!emulatableBackend.nodeBinary) {
|
|
251
|
-
throw new error_1.FirebaseError(`No node binary for ${emulatableBackend.functionsDir}. This should never happen.`);
|
|
252
|
-
}
|
|
253
|
-
this.blockingFunctionsConfig = {};
|
|
254
|
-
let triggerDefinitions;
|
|
249
|
+
async discoverTriggers(emulatableBackend) {
|
|
255
250
|
if (emulatableBackend.predefinedTriggers) {
|
|
256
|
-
|
|
251
|
+
return (0, functionsEmulatorShared_1.emulatedFunctionsByRegion)(emulatableBackend.predefinedTriggers, emulatableBackend.secretEnv);
|
|
257
252
|
}
|
|
258
253
|
else {
|
|
259
254
|
const runtimeConfig = this.getRuntimeConfig(emulatableBackend);
|
|
@@ -284,8 +279,26 @@ class FunctionsEmulator {
|
|
|
284
279
|
for (const e of endpoints) {
|
|
285
280
|
e.codebase = emulatableBackend.codebase;
|
|
286
281
|
}
|
|
287
|
-
|
|
282
|
+
return (0, functionsEmulatorShared_1.emulatedFunctionsFromEndpoints)(endpoints);
|
|
288
283
|
}
|
|
284
|
+
}
|
|
285
|
+
async loadTriggers(emulatableBackend, force = false) {
|
|
286
|
+
if (!emulatableBackend.nodeBinary) {
|
|
287
|
+
throw new error_1.FirebaseError(`No node binary for ${emulatableBackend.functionsDir}. This should never happen.`);
|
|
288
|
+
}
|
|
289
|
+
let triggerDefinitions = [];
|
|
290
|
+
try {
|
|
291
|
+
triggerDefinitions = await this.discoverTriggers(emulatableBackend);
|
|
292
|
+
this.logger.logLabeled("SUCCESS", "functions", `Loaded functions definitions from source: ${triggerDefinitions
|
|
293
|
+
.map((t) => t.entryPoint)
|
|
294
|
+
.join(", ")}.`);
|
|
295
|
+
}
|
|
296
|
+
catch (e) {
|
|
297
|
+
this.logger.logLabeled("ERROR", "functions", `Failed to load function definition from source: ${e}`);
|
|
298
|
+
return;
|
|
299
|
+
}
|
|
300
|
+
this.workerPool.refresh();
|
|
301
|
+
this.blockingFunctionsConfig = {};
|
|
289
302
|
const toSetup = triggerDefinitions.filter((definition) => {
|
|
290
303
|
if (force) {
|
|
291
304
|
return true;
|
|
@@ -305,8 +318,7 @@ class FunctionsEmulator {
|
|
|
305
318
|
(0, validate_1.functionIdsAreValid)([Object.assign(Object.assign({}, definition), { id: definition.name })]);
|
|
306
319
|
}
|
|
307
320
|
catch (e) {
|
|
308
|
-
|
|
309
|
-
continue;
|
|
321
|
+
throw new error_1.FirebaseError(`functions[${definition.id}]: Invalid function id: ${e.message}`);
|
|
310
322
|
}
|
|
311
323
|
let added = false;
|
|
312
324
|
let url = undefined;
|
|
@@ -329,6 +341,9 @@ class FunctionsEmulator {
|
|
|
329
341
|
case constants_1.Constants.SERVICE_PUBSUB:
|
|
330
342
|
added = await this.addPubsubTrigger(definition.name, key, definition.eventTrigger, signature, definition.schedule);
|
|
331
343
|
break;
|
|
344
|
+
case constants_1.Constants.SERVICE_EVENTARC:
|
|
345
|
+
added = await this.addEventarcTrigger(this.args.projectId, key, definition.eventTrigger);
|
|
346
|
+
break;
|
|
332
347
|
case constants_1.Constants.SERVICE_AUTH:
|
|
333
348
|
added = this.addAuthTrigger(this.args.projectId, key, definition.eventTrigger);
|
|
334
349
|
break;
|
|
@@ -368,6 +383,27 @@ class FunctionsEmulator {
|
|
|
368
383
|
this.startRuntime(emulatableBackend, { nodeBinary: emulatableBackend.nodeBinary });
|
|
369
384
|
}
|
|
370
385
|
}
|
|
386
|
+
addEventarcTrigger(projectId, key, eventTrigger) {
|
|
387
|
+
const eventarcEmu = registry_1.EmulatorRegistry.get(types_1.Emulators.EVENTARC);
|
|
388
|
+
if (!eventarcEmu) {
|
|
389
|
+
return Promise.resolve(false);
|
|
390
|
+
}
|
|
391
|
+
const bundle = {
|
|
392
|
+
eventTrigger: Object.assign(Object.assign({}, eventTrigger), { service: "eventarc.googleapis.com" }),
|
|
393
|
+
};
|
|
394
|
+
logger_1.logger.debug(`addEventarcTrigger`, JSON.stringify(bundle));
|
|
395
|
+
const client = new apiv2_1.Client({
|
|
396
|
+
urlPrefix: `http://${registry_1.EmulatorRegistry.getInfoHostString(eventarcEmu.getInfo())}`,
|
|
397
|
+
auth: false,
|
|
398
|
+
});
|
|
399
|
+
return client
|
|
400
|
+
.post(`/emulator/v1/projects/${projectId}/triggers/${key}`, bundle)
|
|
401
|
+
.then(() => true)
|
|
402
|
+
.catch((err) => {
|
|
403
|
+
this.logger.log("WARN", "Error adding Eventarc function: " + err);
|
|
404
|
+
return false;
|
|
405
|
+
});
|
|
406
|
+
}
|
|
371
407
|
async performPostLoadOperations() {
|
|
372
408
|
if (!this.blockingFunctionsConfig.triggers &&
|
|
373
409
|
!this.blockingFunctionsConfig.forwardInboundCredentials) {
|
|
@@ -544,7 +580,13 @@ class FunctionsEmulator {
|
|
|
544
580
|
return record;
|
|
545
581
|
}
|
|
546
582
|
getTriggerKey(def) {
|
|
547
|
-
|
|
583
|
+
if (def.eventTrigger) {
|
|
584
|
+
const triggerKey = `${def.id}-${this.triggerGeneration}`;
|
|
585
|
+
return def.eventTrigger.channel ? `${triggerKey}-${def.eventTrigger.channel}` : triggerKey;
|
|
586
|
+
}
|
|
587
|
+
else {
|
|
588
|
+
return def.id;
|
|
589
|
+
}
|
|
548
590
|
}
|
|
549
591
|
getBackendInfo() {
|
|
550
592
|
const cf3Triggers = this.getCF3Triggers();
|
|
@@ -688,6 +730,10 @@ class FunctionsEmulator {
|
|
|
688
730
|
const pubsubHost = (0, functionsEmulatorShared_1.formatHost)(pubsubEmulator);
|
|
689
731
|
process.env.PUBSUB_EMULATOR_HOST = pubsubHost;
|
|
690
732
|
}
|
|
733
|
+
const eventarcEmulator = this.getEmulatorInfo(types_1.Emulators.EVENTARC);
|
|
734
|
+
if (eventarcEmulator) {
|
|
735
|
+
envs[constants_1.Constants.CLOUD_EVENTARC_EMULATOR_HOST] = `http://${(0, functionsEmulatorShared_1.formatHost)(eventarcEmulator)}`;
|
|
736
|
+
}
|
|
691
737
|
if (this.args.debugPort) {
|
|
692
738
|
envs["FUNCTION_DEBUG_MODE"] = "true";
|
|
693
739
|
}
|
|
@@ -884,6 +930,9 @@ class FunctionsEmulator {
|
|
|
884
930
|
}
|
|
885
931
|
});
|
|
886
932
|
void (0, track_1.track)(EVENT_INVOKE, (0, functionsEmulatorShared_1.getFunctionService)(trigger));
|
|
933
|
+
void (0, track_1.trackEmulator)(EVENT_INVOKE_GA4, {
|
|
934
|
+
function_service: (0, functionsEmulatorShared_1.getFunctionService)(trigger),
|
|
935
|
+
});
|
|
887
936
|
worker.waitForDone().then(() => {
|
|
888
937
|
resolve({ status: "acknowledged" });
|
|
889
938
|
});
|
|
@@ -959,6 +1008,9 @@ class FunctionsEmulator {
|
|
|
959
1008
|
});
|
|
960
1009
|
await worker.waitForSocketReady();
|
|
961
1010
|
void (0, track_1.track)(EVENT_INVOKE, "https");
|
|
1011
|
+
void (0, track_1.trackEmulator)(EVENT_INVOKE_GA4, {
|
|
1012
|
+
function_service: "https",
|
|
1013
|
+
});
|
|
962
1014
|
this.logger.log("DEBUG", `[functions] Runtime ready! Sending request!`);
|
|
963
1015
|
const url = new url_1.URL(`${req.protocol}://${req.hostname}${req.url}`);
|
|
964
1016
|
const path = `${url.pathname}${url.search}`.replace(new RegExp(`\/${this.args.projectId}\/[^\/]*\/${triggerName}\/?`), "/");
|
|
@@ -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();
|
|
@@ -83,12 +83,14 @@ function emulatedFunctionsFromEndpoints(endpoints) {
|
|
|
83
83
|
else {
|
|
84
84
|
const { resource, topic, bucket } = endpoint.eventTrigger.eventFilters;
|
|
85
85
|
const eventResource = resource || topic || bucket;
|
|
86
|
-
if (!eventResource) {
|
|
86
|
+
if (!eventResource && !eventTrigger.channel) {
|
|
87
87
|
continue;
|
|
88
88
|
}
|
|
89
89
|
def.eventTrigger = {
|
|
90
90
|
eventType: eventTrigger.eventType,
|
|
91
91
|
resource: eventResource,
|
|
92
|
+
channel: eventTrigger.channel,
|
|
93
|
+
eventFilters: eventTrigger.eventFilters,
|
|
92
94
|
};
|
|
93
95
|
}
|
|
94
96
|
}
|
|
@@ -151,6 +153,9 @@ exports.getTemporarySocketPath = getTemporarySocketPath;
|
|
|
151
153
|
function getFunctionService(def) {
|
|
152
154
|
var _a;
|
|
153
155
|
if (def.eventTrigger) {
|
|
156
|
+
if (def.eventTrigger.channel) {
|
|
157
|
+
return constants_1.Constants.SERVICE_EVENTARC;
|
|
158
|
+
}
|
|
154
159
|
return (_a = def.eventTrigger.service) !== null && _a !== void 0 ? _a : getServiceFromEventType(def.eventTrigger.eventType);
|
|
155
160
|
}
|
|
156
161
|
if (def.blockingTrigger) {
|
package/lib/emulator/hub.js
CHANGED
|
@@ -32,10 +32,14 @@ class EmulatorHub {
|
|
|
32
32
|
res.json(body);
|
|
33
33
|
});
|
|
34
34
|
this.hub.post(EmulatorHub.PATH_EXPORT, async (req, res) => {
|
|
35
|
-
const
|
|
36
|
-
|
|
35
|
+
const path = req.body.path;
|
|
36
|
+
const initiatedBy = req.body.initiatedBy || "unknown";
|
|
37
|
+
utils.logLabeledBullet("emulators", `Received export request. Exporting data to ${path}.`);
|
|
37
38
|
try {
|
|
38
|
-
await new hubExport_1.HubExport(this.args.projectId,
|
|
39
|
+
await new hubExport_1.HubExport(this.args.projectId, {
|
|
40
|
+
path,
|
|
41
|
+
initiatedBy,
|
|
42
|
+
}).exportAll();
|
|
39
43
|
utils.logLabeledSuccess("emulators", "Export complete.");
|
|
40
44
|
res.status(200).send({
|
|
41
45
|
message: "OK",
|
|
@@ -21,9 +21,9 @@ class EmulatorHubClient {
|
|
|
21
21
|
const res = await apiClient.get(hub_1.EmulatorHub.PATH_EMULATORS);
|
|
22
22
|
return res.body;
|
|
23
23
|
}
|
|
24
|
-
async postExport(
|
|
24
|
+
async postExport(options) {
|
|
25
25
|
const apiClient = new apiv2_1.Client({ urlPrefix: this.origin, auth: false });
|
|
26
|
-
await apiClient.post(hub_1.EmulatorHub.PATH_EXPORT,
|
|
26
|
+
await apiClient.post(hub_1.EmulatorHub.PATH_EXPORT, options);
|
|
27
27
|
}
|
|
28
28
|
get origin() {
|
|
29
29
|
const locator = this.assertLocator();
|
|
@@ -13,10 +13,12 @@ const hub_1 = require("./hub");
|
|
|
13
13
|
const downloadableEmulators_1 = require("./downloadableEmulators");
|
|
14
14
|
const rimraf = require("rimraf");
|
|
15
15
|
const apiv2_1 = require("../apiv2");
|
|
16
|
+
const track_1 = require("../track");
|
|
16
17
|
class HubExport {
|
|
17
|
-
constructor(projectId,
|
|
18
|
+
constructor(projectId, options) {
|
|
18
19
|
this.projectId = projectId;
|
|
19
|
-
this.
|
|
20
|
+
this.options = options;
|
|
21
|
+
this.exportPath = options.path;
|
|
20
22
|
this.tmpDir = fs.mkdtempSync(`firebase-export-${new Date().getTime()}`);
|
|
21
23
|
}
|
|
22
24
|
static readMetadata(exportPath) {
|
|
@@ -66,6 +68,10 @@ class HubExport {
|
|
|
66
68
|
if (!fs.existsSync(this.exportPath)) {
|
|
67
69
|
fs.mkdirSync(this.exportPath);
|
|
68
70
|
}
|
|
71
|
+
void (0, track_1.trackEmulator)("emulator_export", {
|
|
72
|
+
initiated_by: this.options.initiatedBy,
|
|
73
|
+
emulator_name: types_1.Emulators.HUB,
|
|
74
|
+
});
|
|
69
75
|
const metadataPath = path.join(this.tmpDir, HubExport.METADATA_FILE_NAME);
|
|
70
76
|
fs.writeFileSync(metadataPath, JSON.stringify(metadata, undefined, 2));
|
|
71
77
|
logger_1.logger.debug(`hubExport: swapping ${this.tmpDir} with ${this.exportPath}`);
|
|
@@ -73,6 +79,10 @@ class HubExport {
|
|
|
73
79
|
fse.moveSync(this.tmpDir, this.exportPath);
|
|
74
80
|
}
|
|
75
81
|
async exportFirestore(metadata) {
|
|
82
|
+
void (0, track_1.trackEmulator)("emulator_export", {
|
|
83
|
+
initiated_by: this.options.initiatedBy,
|
|
84
|
+
emulator_name: types_1.Emulators.FIRESTORE,
|
|
85
|
+
});
|
|
76
86
|
const firestoreInfo = registry_1.EmulatorRegistry.get(types_1.Emulators.FIRESTORE).getInfo();
|
|
77
87
|
const firestoreHost = `http://${registry_1.EmulatorRegistry.getInfoHostString(firestoreInfo)}`;
|
|
78
88
|
const firestoreExportBody = {
|
|
@@ -115,6 +125,11 @@ class HubExport {
|
|
|
115
125
|
namespacesToExport.push(ns);
|
|
116
126
|
}
|
|
117
127
|
}
|
|
128
|
+
void (0, track_1.trackEmulator)("emulator_export", {
|
|
129
|
+
initiated_by: this.options.initiatedBy,
|
|
130
|
+
emulator_name: types_1.Emulators.DATABASE,
|
|
131
|
+
count: namespacesToExport.length,
|
|
132
|
+
});
|
|
118
133
|
const dbExportPath = path.join(this.tmpDir, metadata.database.path);
|
|
119
134
|
if (!fs.existsSync(dbExportPath)) {
|
|
120
135
|
fs.mkdirSync(dbExportPath);
|
|
@@ -132,6 +147,10 @@ class HubExport {
|
|
|
132
147
|
}
|
|
133
148
|
}
|
|
134
149
|
async exportAuth(metadata) {
|
|
150
|
+
void (0, track_1.trackEmulator)("emulator_export", {
|
|
151
|
+
initiated_by: this.options.initiatedBy,
|
|
152
|
+
emulator_name: types_1.Emulators.AUTH,
|
|
153
|
+
});
|
|
135
154
|
const { host, port } = registry_1.EmulatorRegistry.get(types_1.Emulators.AUTH).getInfo();
|
|
136
155
|
const authExportPath = path.join(this.tmpDir, metadata.auth.path);
|
|
137
156
|
if (!fs.existsSync(authExportPath)) {
|
|
@@ -164,6 +183,7 @@ class HubExport {
|
|
|
164
183
|
const storageHost = `http://${registry_1.EmulatorRegistry.getInfoHostString(storageEmulator.getInfo())}`;
|
|
165
184
|
const storageExportBody = {
|
|
166
185
|
path: storageExportPath,
|
|
186
|
+
initiatedBy: this.options.initiatedBy,
|
|
167
187
|
};
|
|
168
188
|
const client = new apiv2_1.Client({ urlPrefix: storageHost, auth: false });
|
|
169
189
|
const res = await client.request({
|
|
@@ -7,7 +7,7 @@ const triple_beam_1 = require("triple-beam");
|
|
|
7
7
|
const WebSocket = require("ws");
|
|
8
8
|
const TransportStream = require("winston-transport");
|
|
9
9
|
const logger_1 = require("../logger");
|
|
10
|
-
const
|
|
10
|
+
const stripAnsi = require("strip-ansi");
|
|
11
11
|
class LoggingEmulator {
|
|
12
12
|
constructor(args) {
|
|
13
13
|
this.args = args;
|
|
@@ -106,7 +106,7 @@ class WebSocketTransport extends TransportStream {
|
|
|
106
106
|
if (bundle.data && bundle.data.metadata && bundle.data.metadata.message) {
|
|
107
107
|
bundle.message = bundle.data.metadata.message;
|
|
108
108
|
}
|
|
109
|
-
bundle.message =
|
|
109
|
+
bundle.message = stripAnsi(bundle.message);
|
|
110
110
|
this.history.push(bundle);
|
|
111
111
|
this.connections.forEach((ws) => {
|
|
112
112
|
ws.send(JSON.stringify(bundle));
|
package/lib/emulator/registry.js
CHANGED
|
@@ -121,10 +121,22 @@ function createFirebaseEndpoints(emulator) {
|
|
|
121
121
|
var _a, _b, _c, _d;
|
|
122
122
|
const maxResults = (_a = req.query.maxResults) === null || _a === void 0 ? void 0 : _a.toString();
|
|
123
123
|
let listResponse;
|
|
124
|
+
let prefix = "";
|
|
125
|
+
if (req.query.prefix) {
|
|
126
|
+
prefix = req.query.prefix.toString();
|
|
127
|
+
if (prefix.charAt(prefix.length - 1) !== "/") {
|
|
128
|
+
return res.status(400).json({
|
|
129
|
+
error: {
|
|
130
|
+
code: 400,
|
|
131
|
+
message: "The prefix parameter is required to be empty or ends with a single / character.",
|
|
132
|
+
},
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
}
|
|
124
136
|
try {
|
|
125
137
|
listResponse = await storageLayer.listObjects({
|
|
126
138
|
bucketId: req.params.bucketId,
|
|
127
|
-
prefix:
|
|
139
|
+
prefix: prefix,
|
|
128
140
|
delimiter: req.query.delimiter ? req.query.delimiter.toString() : "",
|
|
129
141
|
pageToken: (_b = req.query.pageToken) === null || _b === void 0 ? void 0 : _b.toString(),
|
|
130
142
|
maxResults: maxResults ? +maxResults : undefined,
|
|
@@ -153,14 +165,17 @@ function createFirebaseEndpoints(emulator) {
|
|
|
153
165
|
});
|
|
154
166
|
});
|
|
155
167
|
const handleUpload = async (req, res) => {
|
|
156
|
-
|
|
157
|
-
res.sendStatus(400);
|
|
158
|
-
return;
|
|
159
|
-
}
|
|
168
|
+
var _a;
|
|
160
169
|
const bucketId = req.params.bucketId;
|
|
161
|
-
const objectId = req.
|
|
170
|
+
const objectId = req.params.objectId
|
|
171
|
+
? decodeURIComponent(req.params.objectId)
|
|
172
|
+
: ((_a = req.query.name) === null || _a === void 0 ? void 0 : _a.toString()) || null;
|
|
162
173
|
const uploadType = req.header("x-goog-upload-protocol");
|
|
163
174
|
if (uploadType === "multipart") {
|
|
175
|
+
if (!objectId) {
|
|
176
|
+
res.sendStatus(400);
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
164
179
|
const contentTypeHeader = req.header("content-type");
|
|
165
180
|
if (!contentTypeHeader) {
|
|
166
181
|
return res.sendStatus(400);
|
|
@@ -172,12 +187,7 @@ function createFirebaseEndpoints(emulator) {
|
|
|
172
187
|
}
|
|
173
188
|
catch (err) {
|
|
174
189
|
if (err instanceof Error) {
|
|
175
|
-
return res.status(400).
|
|
176
|
-
error: {
|
|
177
|
-
code: 400,
|
|
178
|
-
message: err.message,
|
|
179
|
-
},
|
|
180
|
-
});
|
|
190
|
+
return res.status(400).send(err.message);
|
|
181
191
|
}
|
|
182
192
|
throw err;
|
|
183
193
|
}
|
|
@@ -212,6 +222,10 @@ function createFirebaseEndpoints(emulator) {
|
|
|
212
222
|
return;
|
|
213
223
|
}
|
|
214
224
|
if (uploadCommand === "start") {
|
|
225
|
+
if (!objectId) {
|
|
226
|
+
res.sendStatus(400);
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
215
229
|
const upload = uploadService.startResumableUpload({
|
|
216
230
|
bucketId,
|
|
217
231
|
objectId,
|