firebase-tools 10.2.1 → 10.2.2
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/appdistribution/options-parser-util.js +1 -1
- package/lib/auth.js +3 -3
- package/lib/command.js +1 -1
- package/lib/commands/apps-android-sha-create.js +2 -2
- package/lib/commands/apps-sdkconfig.js +1 -1
- package/lib/commands/database-rules-list.js +2 -2
- package/lib/commands/emulators-start.js +1 -1
- package/lib/commands/ext-dev-init.js +49 -49
- package/lib/commands/ext-export.js +12 -2
- package/lib/commands/ext-install.js +104 -104
- package/lib/commands/ext-uninstall.js +8 -8
- package/lib/commands/ext-update.js +9 -9
- package/lib/commands/functions-config-export.js +1 -1
- package/lib/commands/hosting-clone.js +3 -3
- package/lib/commands/remoteconfig-get.js +1 -1
- package/lib/deploy/extensions/deploymentSummary.js +3 -3
- package/lib/deploy/extensions/params.js +3 -0
- package/lib/deploy/extensions/planner.js +2 -1
- package/lib/deploy/extensions/tasks.js +1 -1
- package/lib/deploy/functions/backend.js +12 -5
- package/lib/deploy/functions/checkIam.js +1 -1
- package/lib/deploy/functions/containerCleaner.js +3 -3
- package/lib/deploy/functions/ensure.js +3 -3
- package/lib/deploy/functions/functionsDeployHelper.js +2 -2
- package/lib/deploy/functions/prepare.js +3 -2
- package/lib/deploy/functions/pricing.js +1 -1
- package/lib/deploy/functions/prompts.js +2 -2
- package/lib/deploy/functions/release/fabricator.js +3 -3
- package/lib/deploy/functions/release/index.js +1 -1
- package/lib/deploy/functions/release/planner.js +11 -8
- package/lib/deploy/functions/release/reporter.js +3 -0
- package/lib/deploy/functions/runtimes/discovery/index.js +6 -6
- package/lib/deploy/functions/runtimes/discovery/parsing.js +1 -1
- package/lib/deploy/functions/runtimes/discovery/v1alpha1.js +16 -11
- package/lib/deploy/functions/runtimes/golang/index.js +2 -2
- package/lib/deploy/functions/runtimes/node/index.js +26 -0
- package/lib/deploy/functions/runtimes/node/parseRuntimeAndValidateSDK.js +2 -2
- package/lib/deploy/functions/runtimes/node/parseTriggers.js +28 -7
- package/lib/deploy/functions/runtimes/node/versioning.js +2 -2
- package/lib/deploy/functions/validate.js +3 -3
- package/lib/deploy/hosting/deploy.js +2 -2
- package/lib/deploy/hosting/hashcache.js +21 -19
- package/lib/deploy/hosting/uploader.js +5 -5
- package/lib/deploy/remoteconfig/functions.js +2 -2
- package/lib/emulator/auth/cloudFunctions.js +1 -1
- package/lib/emulator/auth/operations.js +1 -1
- package/lib/emulator/constants.js +3 -0
- package/lib/emulator/controller.js +47 -19
- package/lib/emulator/download.js +18 -1
- package/lib/emulator/downloadableEmulators.js +1 -1
- package/lib/emulator/emulatorLogger.js +12 -1
- package/lib/emulator/extensions/validation.js +35 -0
- package/lib/emulator/extensionsEmulator.js +140 -0
- package/lib/emulator/functionsEmulator.js +86 -39
- package/lib/emulator/functionsEmulatorRuntime.js +44 -36
- package/lib/emulator/functionsEmulatorShell.js +1 -1
- package/lib/emulator/functionsEmulatorUtils.js +4 -4
- package/lib/emulator/functionsRuntimeWorker.js +2 -2
- package/lib/emulator/hub.js +4 -3
- package/lib/emulator/loggingEmulator.js +1 -1
- package/lib/emulator/pubsubEmulator.js +1 -1
- package/lib/emulator/registry.js +10 -2
- package/lib/emulator/storage/apis/firebase.js +31 -26
- package/lib/emulator/storage/apis/gcloud.js +7 -12
- package/lib/emulator/storage/files.js +36 -34
- package/lib/emulator/storage/index.js +2 -2
- package/lib/emulator/storage/metadata.js +2 -2
- package/lib/emulator/storage/rules/runtime.js +8 -7
- package/lib/emulator/types.js +3 -0
- package/lib/ensureApiEnabled.js +5 -1
- package/lib/error.js +1 -1
- package/lib/extensions/askUserForParam.js +1 -1
- package/lib/extensions/changelog.js +3 -1
- package/lib/extensions/checkProjectBilling.js +1 -1
- package/lib/extensions/displayExtensionInfo.js +1 -1
- package/lib/extensions/emulator/optionsHelper.js +24 -8
- package/lib/extensions/emulator/specHelper.js +10 -23
- package/lib/extensions/export.js +1 -51
- package/lib/extensions/extensionsApi.js +1 -1
- package/lib/extensions/extensionsHelper.js +13 -9
- package/lib/extensions/manifest.js +48 -0
- package/lib/extensions/metricsUtils.js +4 -4
- package/lib/extensions/paramHelper.js +4 -4
- package/lib/extensions/refs.js +1 -1
- package/lib/extensions/secretsUtils.js +3 -3
- package/lib/functional.js +1 -1
- package/lib/functions/env.js +2 -1
- package/lib/gcp/cloudfunctions.js +24 -5
- package/lib/gcp/cloudfunctionsv2.js +18 -5
- package/lib/gcp/cloudtasks.js +1 -1
- package/lib/gcp/docker.js +2 -2
- package/lib/gcp/run.js +2 -2
- package/lib/hosting/api.js +1 -1
- package/lib/hosting/proxy.js +2 -2
- package/lib/init/features/account.js +1 -1
- package/lib/management/database.js +1 -1
- package/lib/previews.js +1 -1
- package/lib/utils.js +1 -1
- package/npm-shrinkwrap.json +786 -393
- package/package.json +1 -1
- package/schema/firebase-config.json +5 -0
- package/templates/init/functions/javascript/package.lint.json +3 -3
- package/templates/init/functions/javascript/package.nolint.json +2 -2
- package/templates/init/functions/typescript/package.lint.json +7 -7
- package/templates/init/functions/typescript/package.nolint.json +3 -3
|
@@ -8,7 +8,9 @@ const express = require("express");
|
|
|
8
8
|
const clc = require("cli-color");
|
|
9
9
|
const http = require("http");
|
|
10
10
|
const jwt = require("jsonwebtoken");
|
|
11
|
+
const cors = require("cors");
|
|
11
12
|
const url_1 = require("url");
|
|
13
|
+
const events_1 = require("events");
|
|
12
14
|
const api = require("../api");
|
|
13
15
|
const logger_1 = require("../logger");
|
|
14
16
|
const track = require("../track");
|
|
@@ -19,7 +21,6 @@ const spawn = require("cross-spawn");
|
|
|
19
21
|
const child_process_1 = require("child_process");
|
|
20
22
|
const functionsEmulatorShared_1 = require("./functionsEmulatorShared");
|
|
21
23
|
const registry_1 = require("./registry");
|
|
22
|
-
const events_1 = require("events");
|
|
23
24
|
const emulatorLogger_1 = require("./emulatorLogger");
|
|
24
25
|
const functionsRuntimeWorker_1 = require("./functionsRuntimeWorker");
|
|
25
26
|
const error_1 = require("../error");
|
|
@@ -29,10 +30,10 @@ const defaultCredentials_1 = require("../defaultCredentials");
|
|
|
29
30
|
const adminSdkConfig_1 = require("./adminSdkConfig");
|
|
30
31
|
const types_2 = require("./events/types");
|
|
31
32
|
const validate_1 = require("../deploy/functions/validate");
|
|
32
|
-
const
|
|
33
|
+
const secretManager_1 = require("../gcp/secretManager");
|
|
34
|
+
const runtimes = require("../deploy/functions/runtimes");
|
|
33
35
|
const backend = require("../deploy/functions/backend");
|
|
34
36
|
const functionsEnv = require("../functions/env");
|
|
35
|
-
const secretManager_1 = require("../gcp/secretManager");
|
|
36
37
|
const EVENT_INVOKE = "functions:invoke";
|
|
37
38
|
const LOCAL_SECRETS_FILE = ".secret.local";
|
|
38
39
|
const DATABASE_PATH_PATTERN = new RegExp("^projects/[^/]+/instances/([^/]+)/refs(/.*)$");
|
|
@@ -78,6 +79,7 @@ class FunctionsEmulator {
|
|
|
78
79
|
createHubServer() {
|
|
79
80
|
this.workQueue.start();
|
|
80
81
|
const hub = express();
|
|
82
|
+
hub.use(cors({ origin: true }));
|
|
81
83
|
const dataMiddleware = (req, res, next) => {
|
|
82
84
|
const chunks = [];
|
|
83
85
|
req.on("data", (chunk) => {
|
|
@@ -92,6 +94,7 @@ class FunctionsEmulator {
|
|
|
92
94
|
const httpsFunctionRoute = `/${this.args.projectId}/:region/:trigger_name`;
|
|
93
95
|
const multicastFunctionRoute = `/functions/projects/:project_id/trigger_multicast`;
|
|
94
96
|
const httpsFunctionRoutes = [httpsFunctionRoute, `${httpsFunctionRoute}/*`];
|
|
97
|
+
const listBackendsRoute = `/backends`;
|
|
95
98
|
const backgroundHandler = (req, res) => {
|
|
96
99
|
var _a;
|
|
97
100
|
const region = req.params.region;
|
|
@@ -152,6 +155,10 @@ class FunctionsEmulator {
|
|
|
152
155
|
});
|
|
153
156
|
res.json({ status: "multicast_acknowledged" });
|
|
154
157
|
};
|
|
158
|
+
const listBackendsHandler = (req, res) => {
|
|
159
|
+
res.json({ backends: this.getBackendInfo() });
|
|
160
|
+
};
|
|
161
|
+
hub.get(listBackendsRoute, dataMiddleware, listBackendsHandler);
|
|
155
162
|
hub.post(backgroundFunctionRoute, dataMiddleware, backgroundHandler);
|
|
156
163
|
hub.post(multicastFunctionRoute, dataMiddleware, multicastHandler);
|
|
157
164
|
hub.all(httpsFunctionRoutes, dataMiddleware, httpsHandler);
|
|
@@ -161,9 +168,15 @@ class FunctionsEmulator {
|
|
|
161
168
|
});
|
|
162
169
|
return hub;
|
|
163
170
|
}
|
|
164
|
-
async
|
|
171
|
+
async invokeTrigger(backend, trigger, proto, runtimeOpts) {
|
|
165
172
|
const bundleTemplate = this.getBaseBundle();
|
|
166
173
|
const runtimeBundle = Object.assign(Object.assign({}, bundleTemplate), { proto });
|
|
174
|
+
if (this.args.debugPort) {
|
|
175
|
+
runtimeBundle.debug = {
|
|
176
|
+
functionTarget: trigger.entryPoint,
|
|
177
|
+
functionSignature: (0, functionsEmulatorShared_1.getSignatureType)(trigger),
|
|
178
|
+
};
|
|
179
|
+
}
|
|
167
180
|
if (!backend.nodeBinary) {
|
|
168
181
|
throw new error_1.FirebaseError(`No node binary for ${trigger.id}. This should never happen.`);
|
|
169
182
|
}
|
|
@@ -244,11 +257,15 @@ class FunctionsEmulator {
|
|
|
244
257
|
}
|
|
245
258
|
else {
|
|
246
259
|
const runtimeConfig = this.getRuntimeConfig(emulatableBackend);
|
|
247
|
-
const
|
|
260
|
+
const runtimeDelegateContext = {
|
|
248
261
|
projectId: this.args.projectId,
|
|
249
262
|
projectDir: this.args.projectDir,
|
|
250
263
|
sourceDir: emulatableBackend.functionsDir,
|
|
251
|
-
}
|
|
264
|
+
};
|
|
265
|
+
if (emulatableBackend.nodeMajorVersion) {
|
|
266
|
+
runtimeDelegateContext.runtime = `nodejs${emulatableBackend.nodeMajorVersion}`;
|
|
267
|
+
}
|
|
268
|
+
const runtimeDelegate = await runtimes.getRuntimeDelegate(runtimeDelegateContext);
|
|
252
269
|
logger_1.logger.debug(`Validating ${runtimeDelegate.name} source`);
|
|
253
270
|
await runtimeDelegate.validate();
|
|
254
271
|
logger_1.logger.debug(`Building ${runtimeDelegate.name} source`);
|
|
@@ -331,6 +348,9 @@ class FunctionsEmulator {
|
|
|
331
348
|
this.logger.logLabeled("SUCCESS", `functions[${definition.id}]`, msg);
|
|
332
349
|
}
|
|
333
350
|
}
|
|
351
|
+
if (this.args.debugPort) {
|
|
352
|
+
this.startRuntime(emulatableBackend, { nodeBinary: emulatableBackend.nodeBinary });
|
|
353
|
+
}
|
|
334
354
|
}
|
|
335
355
|
addRealtimeDatabaseTrigger(projectId, key, eventTrigger) {
|
|
336
356
|
const databaseEmu = registry_1.EmulatorRegistry.get(types_1.Emulators.DATABASE);
|
|
@@ -469,8 +489,22 @@ class FunctionsEmulator {
|
|
|
469
489
|
getTriggerKey(def) {
|
|
470
490
|
return def.eventTrigger ? `${def.id}-${this.triggerGeneration}` : def.id;
|
|
471
491
|
}
|
|
472
|
-
|
|
473
|
-
|
|
492
|
+
getBackendInfo() {
|
|
493
|
+
const cf3Triggers = Object.values(this.triggers)
|
|
494
|
+
.filter((t) => !t.backend.extensionInstanceId)
|
|
495
|
+
.map((t) => t.def);
|
|
496
|
+
return this.args.emulatableBackends.map((e) => {
|
|
497
|
+
var _a;
|
|
498
|
+
return {
|
|
499
|
+
directory: e.functionsDir,
|
|
500
|
+
env: e.env,
|
|
501
|
+
extensionInstanceId: e.extensionInstanceId,
|
|
502
|
+
extension: e.extension,
|
|
503
|
+
extensionVersion: e.extensionVersion,
|
|
504
|
+
extensionSpec: e.extensionSpec,
|
|
505
|
+
functionTriggers: (_a = e.predefinedTriggers) !== null && _a !== void 0 ? _a : cf3Triggers,
|
|
506
|
+
};
|
|
507
|
+
});
|
|
474
508
|
}
|
|
475
509
|
addTriggerRecord(def, opts) {
|
|
476
510
|
const key = this.getTriggerKey(def);
|
|
@@ -589,6 +623,9 @@ class FunctionsEmulator {
|
|
|
589
623
|
const pubsubHost = (0, functionsEmulatorShared_1.formatHost)(pubsubEmulator);
|
|
590
624
|
process.env.PUBSUB_EMULATOR_HOST = pubsubHost;
|
|
591
625
|
}
|
|
626
|
+
if (this.args.debugPort) {
|
|
627
|
+
envs["FUNCTION_DEBUG_MODE"] = "true";
|
|
628
|
+
}
|
|
592
629
|
return envs;
|
|
593
630
|
}
|
|
594
631
|
getFirebaseConfig() {
|
|
@@ -622,44 +659,50 @@ class FunctionsEmulator {
|
|
|
622
659
|
this.logger.logLabeled("ERROR", "functions", `Failed to read local secrets file ${LOCAL_SECRETS_FILE}: ${e.message}`);
|
|
623
660
|
}
|
|
624
661
|
}
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
662
|
+
if (trigger) {
|
|
663
|
+
const secrets = trigger.secretEnvironmentVariables || [];
|
|
664
|
+
const accesses = secrets
|
|
665
|
+
.filter((s) => !secretEnvs[s.secret])
|
|
666
|
+
.map(async (s) => {
|
|
667
|
+
this.logger.logLabeled("INFO", "functions", `Trying to access secret ${s.key}@latest`);
|
|
668
|
+
const value = await (0, secretManager_1.accessSecretVersion)(this.getProjectId(), s.key, "latest");
|
|
669
|
+
return [s.secret, value];
|
|
670
|
+
});
|
|
671
|
+
const accessResults = await (0, utils_1.allSettled)(accesses);
|
|
672
|
+
const errs = [];
|
|
673
|
+
for (const result of accessResults) {
|
|
674
|
+
if (result.status === "rejected") {
|
|
675
|
+
errs.push(result.reason);
|
|
676
|
+
}
|
|
677
|
+
else {
|
|
678
|
+
const [k, v] = result.value;
|
|
679
|
+
secretEnvs[k] = v;
|
|
680
|
+
}
|
|
638
681
|
}
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
682
|
+
if (errs.length > 0) {
|
|
683
|
+
this.logger.logLabeled("ERROR", "functions", "Unable to access secret environment variables from Google Cloud Secret Manager. " +
|
|
684
|
+
"Make sure the credential used for the Functions Emulator have access " +
|
|
685
|
+
`or provide override values in ${LOCAL_SECRETS_FILE}:\n\t` +
|
|
686
|
+
errs.join("\n\t"));
|
|
642
687
|
}
|
|
643
688
|
}
|
|
644
|
-
if (errs.length > 0) {
|
|
645
|
-
this.logger.logLabeled("ERROR", "functions", "Unable to access secret environment variables from Google Cloud Secret Manager. " +
|
|
646
|
-
"Make sure the credential used for the Functions Emulator have access " +
|
|
647
|
-
`or provide override values in ${LOCAL_SECRETS_FILE}:\n\t` +
|
|
648
|
-
errs.join("\n\t"));
|
|
649
|
-
}
|
|
650
689
|
return secretEnvs;
|
|
651
690
|
}
|
|
652
691
|
async invokeRuntime(backend, trigger, frb, opts) {
|
|
653
|
-
if (this.workerPool.readyForWork(trigger.id)) {
|
|
654
|
-
|
|
692
|
+
if (!this.workerPool.readyForWork(trigger.id)) {
|
|
693
|
+
await this.startRuntime(backend, opts, trigger);
|
|
655
694
|
}
|
|
695
|
+
return this.workerPool.submitWork(trigger.id, frb, opts);
|
|
696
|
+
}
|
|
697
|
+
async startRuntime(backend, opts, trigger) {
|
|
698
|
+
var _a;
|
|
656
699
|
const emitter = new events_1.EventEmitter();
|
|
657
700
|
const args = [path.join(__dirname, "functionsEmulatorRuntime")];
|
|
658
701
|
if (opts.ignore_warnings) {
|
|
659
702
|
args.unshift("--no-warnings");
|
|
660
703
|
}
|
|
661
704
|
if (this.args.debugPort) {
|
|
662
|
-
if (process.env.FIREPIT_VERSION && process.execPath
|
|
705
|
+
if (process.env.FIREPIT_VERSION && process.execPath === opts.nodeBinary) {
|
|
663
706
|
const requestedMajorNodeVersion = this.getNodeBinary(backend);
|
|
664
707
|
this.logger.log("WARN", `To enable function inspection, please run "${process.execPath} is:npm i node@${requestedMajorNodeVersion} --save-dev" in your functions directory`);
|
|
665
708
|
}
|
|
@@ -721,8 +764,12 @@ class FunctionsEmulator {
|
|
|
721
764
|
return childProcess.send(JSON.stringify(args));
|
|
722
765
|
},
|
|
723
766
|
};
|
|
724
|
-
|
|
725
|
-
|
|
767
|
+
const extensionLogInfo = {
|
|
768
|
+
instanceId: backend.extensionInstanceId,
|
|
769
|
+
ref: (_a = backend.extensionVersion) === null || _a === void 0 ? void 0 : _a.ref,
|
|
770
|
+
};
|
|
771
|
+
this.workerPool.addWorker(trigger === null || trigger === void 0 ? void 0 : trigger.id, runtime, extensionLogInfo);
|
|
772
|
+
return;
|
|
726
773
|
}
|
|
727
774
|
async disableBackgroundTriggers() {
|
|
728
775
|
Object.values(this.triggers).forEach((record) => {
|
|
@@ -748,7 +795,7 @@ class FunctionsEmulator {
|
|
|
748
795
|
}
|
|
749
796
|
const trigger = record.def;
|
|
750
797
|
const service = (0, functionsEmulatorShared_1.getFunctionService)(trigger);
|
|
751
|
-
const worker = await this.
|
|
798
|
+
const worker = await this.invokeTrigger(record.backend, trigger, proto);
|
|
752
799
|
return new Promise((resolve, reject) => {
|
|
753
800
|
if (projectId !== this.args.projectId) {
|
|
754
801
|
if (service !== constants_1.Constants.SERVICE_REALTIME_DATABASE) {
|
|
@@ -767,7 +814,7 @@ class FunctionsEmulator {
|
|
|
767
814
|
reject({ code: 500, body: el.text });
|
|
768
815
|
}
|
|
769
816
|
});
|
|
770
|
-
track(EVENT_INVOKE, (0, functionsEmulatorShared_1.getFunctionService)(trigger));
|
|
817
|
+
void track(EVENT_INVOKE, (0, functionsEmulatorShared_1.getFunctionService)(trigger));
|
|
771
818
|
worker.waitForDone().then(() => {
|
|
772
819
|
resolve({ status: "acknowledged" });
|
|
773
820
|
});
|
|
@@ -835,14 +882,14 @@ class FunctionsEmulator {
|
|
|
835
882
|
req.headers[functionsEmulatorShared_1.HttpConstants.CALLABLE_AUTH_HEADER] = encodeURIComponent(JSON.stringify(contextAuth));
|
|
836
883
|
}
|
|
837
884
|
}
|
|
838
|
-
const worker = await this.
|
|
885
|
+
const worker = await this.invokeTrigger(record.backend, trigger);
|
|
839
886
|
worker.onLogs((el) => {
|
|
840
887
|
if (el.level === "FATAL") {
|
|
841
888
|
res.status(500).send(el.text);
|
|
842
889
|
}
|
|
843
890
|
});
|
|
844
891
|
await worker.waitForSocketReady();
|
|
845
|
-
track(EVENT_INVOKE, "https");
|
|
892
|
+
void track(EVENT_INVOKE, "https");
|
|
846
893
|
this.logger.log("DEBUG", `[functions] Runtime ready! Sending request!`);
|
|
847
894
|
if (!worker.lastArgs) {
|
|
848
895
|
throw new error_1.FirebaseError("Cannot execute on a worker with no arguments");
|
|
@@ -10,9 +10,10 @@ const types_1 = require("./types");
|
|
|
10
10
|
const constants_1 = require("./constants");
|
|
11
11
|
const functionsEmulatorShared_1 = require("./functionsEmulatorShared");
|
|
12
12
|
const functionsEmulatorUtils_1 = require("./functionsEmulatorUtils");
|
|
13
|
-
let
|
|
13
|
+
let functionModule;
|
|
14
14
|
let FUNCTION_TARGET_NAME;
|
|
15
15
|
let FUNCTION_SIGNATURE;
|
|
16
|
+
let FUNCTION_DEBUG_MODE;
|
|
16
17
|
let developerPkgJSON;
|
|
17
18
|
const dynamicImport = new Function("modulePath", "return import(modulePath)");
|
|
18
19
|
function isFeatureEnabled(frb, feature) {
|
|
@@ -484,7 +485,7 @@ async function initializeFunctionsConfigHelper(frb) {
|
|
|
484
485
|
function rawBodySaver(req, res, buf) {
|
|
485
486
|
req.rawBody = buf;
|
|
486
487
|
}
|
|
487
|
-
async function processHTTPS(frb) {
|
|
488
|
+
async function processHTTPS(trigger, frb) {
|
|
488
489
|
const ephemeralServer = express();
|
|
489
490
|
const functionRouter = express.Router();
|
|
490
491
|
const socketPath = frb.socketPath;
|
|
@@ -506,7 +507,7 @@ async function processHTTPS(frb) {
|
|
|
506
507
|
}
|
|
507
508
|
});
|
|
508
509
|
});
|
|
509
|
-
await runHTTPS([req, res]);
|
|
510
|
+
await runHTTPS(trigger, [req, res]);
|
|
510
511
|
}
|
|
511
512
|
catch (err) {
|
|
512
513
|
rejectEphemeralServer(err);
|
|
@@ -540,11 +541,11 @@ async function processHTTPS(frb) {
|
|
|
540
541
|
instance.on("error", rejectEphemeralServer);
|
|
541
542
|
});
|
|
542
543
|
}
|
|
543
|
-
async function processBackground(frb, signature) {
|
|
544
|
+
async function processBackground(trigger, frb, signature) {
|
|
544
545
|
const proto = frb.proto;
|
|
545
546
|
logDebug("ProcessBackground", proto);
|
|
546
547
|
if (signature === "cloudevent") {
|
|
547
|
-
return runCloudEvent(proto);
|
|
548
|
+
return runCloudEvent(trigger, proto);
|
|
548
549
|
}
|
|
549
550
|
const data = proto.data;
|
|
550
551
|
delete proto.data;
|
|
@@ -555,7 +556,7 @@ async function processBackground(frb, signature) {
|
|
|
555
556
|
context.resource = context.resource.name;
|
|
556
557
|
}
|
|
557
558
|
}
|
|
558
|
-
await runBackground({ data, context });
|
|
559
|
+
await runBackground(trigger, { data, context });
|
|
559
560
|
}
|
|
560
561
|
async function runFunction(func) {
|
|
561
562
|
let caughtErr;
|
|
@@ -570,24 +571,24 @@ async function runFunction(func) {
|
|
|
570
571
|
throw caughtErr;
|
|
571
572
|
}
|
|
572
573
|
}
|
|
573
|
-
async function runBackground(proto) {
|
|
574
|
+
async function runBackground(trigger, proto) {
|
|
574
575
|
logDebug("RunBackground", proto);
|
|
575
576
|
await runFunction(() => {
|
|
576
|
-
return
|
|
577
|
+
return trigger(proto.data, proto.context);
|
|
577
578
|
});
|
|
578
579
|
}
|
|
579
|
-
async function runCloudEvent(event) {
|
|
580
|
+
async function runCloudEvent(trigger, event) {
|
|
580
581
|
logDebug("RunCloudEvent", event);
|
|
581
582
|
await runFunction(() => {
|
|
582
|
-
return
|
|
583
|
+
return trigger(event);
|
|
583
584
|
});
|
|
584
585
|
}
|
|
585
|
-
async function runHTTPS(args) {
|
|
586
|
+
async function runHTTPS(trigger, args) {
|
|
586
587
|
if (args.length < 2) {
|
|
587
588
|
throw new Error("Function must be passed 2 args.");
|
|
588
589
|
}
|
|
589
590
|
await runFunction(() => {
|
|
590
|
-
return
|
|
591
|
+
return trigger(args[0], args[1]);
|
|
591
592
|
});
|
|
592
593
|
}
|
|
593
594
|
async function moduleResolutionDetective(frb, error) {
|
|
@@ -611,7 +612,7 @@ async function moduleResolutionDetective(frb, error) {
|
|
|
611
612
|
function logDebug(msg, data) {
|
|
612
613
|
new types_1.EmulatorLog("DEBUG", "runtime-status", `[${process.pid}] ${msg}`, data).log();
|
|
613
614
|
}
|
|
614
|
-
async function invokeTrigger(frb) {
|
|
615
|
+
async function invokeTrigger(trigger, frb) {
|
|
615
616
|
new types_1.EmulatorLog("INFO", "runtime-status", `Beginning execution of "${FUNCTION_TARGET_NAME}"`, {
|
|
616
617
|
frb,
|
|
617
618
|
}).log();
|
|
@@ -636,10 +637,10 @@ async function invokeTrigger(frb) {
|
|
|
636
637
|
switch (FUNCTION_SIGNATURE) {
|
|
637
638
|
case "event":
|
|
638
639
|
case "cloudevent":
|
|
639
|
-
await processBackground(frb, FUNCTION_SIGNATURE);
|
|
640
|
+
await processBackground(trigger, frb, FUNCTION_SIGNATURE);
|
|
640
641
|
break;
|
|
641
642
|
case "http":
|
|
642
|
-
await processHTTPS(frb);
|
|
643
|
+
await processHTTPS(trigger, frb);
|
|
643
644
|
break;
|
|
644
645
|
}
|
|
645
646
|
if (timeoutId) {
|
|
@@ -649,15 +650,18 @@ async function invokeTrigger(frb) {
|
|
|
649
650
|
new types_1.EmulatorLog("INFO", "runtime-status", `Finished "${FUNCTION_TARGET_NAME}" in ~${Math.max(seconds, 1)}s`).log();
|
|
650
651
|
}
|
|
651
652
|
async function initializeRuntime(frb) {
|
|
652
|
-
|
|
653
|
-
if (!
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
653
|
+
FUNCTION_DEBUG_MODE = process.env.FUNCTION_DEBUG_MODE || "";
|
|
654
|
+
if (!FUNCTION_DEBUG_MODE) {
|
|
655
|
+
FUNCTION_TARGET_NAME = process.env.FUNCTION_TARGET || "";
|
|
656
|
+
if (!FUNCTION_TARGET_NAME) {
|
|
657
|
+
new types_1.EmulatorLog("FATAL", "runtime-status", `Environment variable FUNCTION_TARGET cannot be empty. This shouldn't happen.`).log();
|
|
658
|
+
await flushAndExit(1);
|
|
659
|
+
}
|
|
660
|
+
FUNCTION_SIGNATURE = process.env.FUNCTION_SIGNATURE_TYPE || "";
|
|
661
|
+
if (!FUNCTION_SIGNATURE) {
|
|
662
|
+
new types_1.EmulatorLog("FATAL", "runtime-status", `Environment variable FUNCTION_SIGNATURE_TYPE cannot be empty. This shouldn't happen.`).log();
|
|
663
|
+
await flushAndExit(1);
|
|
664
|
+
}
|
|
661
665
|
}
|
|
662
666
|
logDebug(`Disabled runtime features: ${JSON.stringify(frb.disabled_features)}`);
|
|
663
667
|
const verified = await verifyDeveloperNodeModules(frb);
|
|
@@ -671,7 +675,7 @@ async function initializeRuntime(frb) {
|
|
|
671
675
|
await initializeFirebaseFunctionsStubs(frb);
|
|
672
676
|
await initializeFirebaseAdminStubs(frb);
|
|
673
677
|
}
|
|
674
|
-
async function
|
|
678
|
+
async function loadTriggers(frb, serializedFunctionTrigger) {
|
|
675
679
|
let triggerModule;
|
|
676
680
|
if (serializedFunctionTrigger) {
|
|
677
681
|
triggerModule = eval(serializedFunctionTrigger)();
|
|
@@ -690,13 +694,7 @@ async function loadTrigger(frb, functionTarget, serializedFunctionTrigger) {
|
|
|
690
694
|
triggerModule = await dynamicImport(moduleURL);
|
|
691
695
|
}
|
|
692
696
|
}
|
|
693
|
-
|
|
694
|
-
return mod === null || mod === void 0 ? void 0 : mod[functionTargetPart];
|
|
695
|
-
}, triggerModule);
|
|
696
|
-
if (!maybeTrigger) {
|
|
697
|
-
throw new Error(`Failed to find function ${functionTarget} in the loaded module`);
|
|
698
|
-
}
|
|
699
|
-
return maybeTrigger;
|
|
697
|
+
return triggerModule;
|
|
700
698
|
}
|
|
701
699
|
async function flushAndExit(code) {
|
|
702
700
|
await types_1.EmulatorLog.waitForFlush();
|
|
@@ -716,22 +714,32 @@ async function handleMessage(message) {
|
|
|
716
714
|
await flushAndExit(1);
|
|
717
715
|
return;
|
|
718
716
|
}
|
|
719
|
-
if (!
|
|
717
|
+
if (!functionModule) {
|
|
720
718
|
try {
|
|
721
719
|
await initializeRuntime(runtimeArgs.frb);
|
|
722
720
|
const serializedTriggers = runtimeArgs.opts ? runtimeArgs.opts.serializedTriggers : undefined;
|
|
723
|
-
|
|
721
|
+
functionModule = await loadTriggers(runtimeArgs.frb, serializedTriggers);
|
|
724
722
|
}
|
|
725
723
|
catch (e) {
|
|
726
724
|
logDebug(e);
|
|
727
|
-
new types_1.EmulatorLog("FATAL", "runtime-status", `Failed to initialize and load
|
|
725
|
+
new types_1.EmulatorLog("FATAL", "runtime-status", `Failed to initialize and load triggers. This shouldn't happen: ${e.message}`).log();
|
|
728
726
|
await flushAndExit(1);
|
|
729
727
|
return;
|
|
730
728
|
}
|
|
731
729
|
}
|
|
730
|
+
if (FUNCTION_DEBUG_MODE) {
|
|
731
|
+
FUNCTION_TARGET_NAME = runtimeArgs.frb.debug.functionTarget;
|
|
732
|
+
FUNCTION_SIGNATURE = runtimeArgs.frb.debug.functionSignature;
|
|
733
|
+
}
|
|
734
|
+
const trigger = FUNCTION_TARGET_NAME.split(".").reduce((mod, functionTargetPart) => {
|
|
735
|
+
return mod === null || mod === void 0 ? void 0 : mod[functionTargetPart];
|
|
736
|
+
}, functionModule);
|
|
737
|
+
if (!trigger) {
|
|
738
|
+
throw new Error(`Failed to find function ${FUNCTION_TARGET_NAME} in the loaded module`);
|
|
739
|
+
}
|
|
732
740
|
logDebug(`Beginning invocation function ${FUNCTION_TARGET_NAME}!`);
|
|
733
741
|
try {
|
|
734
|
-
await invokeTrigger(runtimeArgs.frb);
|
|
742
|
+
await invokeTrigger(trigger, runtimeArgs.frb);
|
|
735
743
|
if (runtimeArgs.opts && runtimeArgs.opts.serializedTriggers) {
|
|
736
744
|
await flushAndExit(0);
|
|
737
745
|
}
|
|
@@ -42,7 +42,7 @@ class FunctionsEmulatorShell {
|
|
|
42
42
|
auth: opts.auth,
|
|
43
43
|
data,
|
|
44
44
|
};
|
|
45
|
-
this.emu.
|
|
45
|
+
this.emu.invokeTrigger(this.backend, trigger, proto);
|
|
46
46
|
}
|
|
47
47
|
getTrigger(name) {
|
|
48
48
|
const result = this.triggers.find((trigger) => {
|
|
@@ -52,7 +52,7 @@ function parseRuntimeVersion(runtime) {
|
|
|
52
52
|
return undefined;
|
|
53
53
|
}
|
|
54
54
|
const runtimeRe = /(nodejs)?([0-9]+)/;
|
|
55
|
-
const match =
|
|
55
|
+
const match = runtimeRe.exec(runtime);
|
|
56
56
|
if (match) {
|
|
57
57
|
return Number.parseInt(match[2]);
|
|
58
58
|
}
|
|
@@ -73,13 +73,13 @@ exports.parseVersionString = parseVersionString;
|
|
|
73
73
|
function compareVersionStrings(a, b) {
|
|
74
74
|
const versionA = parseVersionString(a);
|
|
75
75
|
const versionB = parseVersionString(b);
|
|
76
|
-
if (versionA.major
|
|
76
|
+
if (versionA.major !== versionB.major) {
|
|
77
77
|
return versionA.major - versionB.major;
|
|
78
78
|
}
|
|
79
|
-
if (versionA.minor
|
|
79
|
+
if (versionA.minor !== versionB.minor) {
|
|
80
80
|
return versionA.minor - versionB.minor;
|
|
81
81
|
}
|
|
82
|
-
if (versionA.patch
|
|
82
|
+
if (versionA.patch !== versionB.patch) {
|
|
83
83
|
return versionA.patch - versionB.patch;
|
|
84
84
|
}
|
|
85
85
|
return 0;
|
|
@@ -170,14 +170,14 @@ class RuntimeWorkerPool {
|
|
|
170
170
|
}
|
|
171
171
|
return;
|
|
172
172
|
}
|
|
173
|
-
addWorker(triggerId, runtime) {
|
|
173
|
+
addWorker(triggerId, runtime, extensionLogInfo) {
|
|
174
174
|
const worker = new RuntimeWorker(this.getKey(triggerId), runtime);
|
|
175
175
|
this.log(`addWorker(${worker.key})`);
|
|
176
176
|
const keyWorkers = this.getTriggerWorkers(triggerId);
|
|
177
177
|
keyWorkers.push(worker);
|
|
178
178
|
this.setTriggerWorkers(triggerId, keyWorkers);
|
|
179
179
|
const logger = triggerId
|
|
180
|
-
? emulatorLogger_1.EmulatorLogger.forFunction(triggerId)
|
|
180
|
+
? emulatorLogger_1.EmulatorLogger.forFunction(triggerId, extensionLogInfo)
|
|
181
181
|
: emulatorLogger_1.EmulatorLogger.forEmulator(types_1.Emulators.FUNCTIONS);
|
|
182
182
|
worker.onLogs((log) => {
|
|
183
183
|
logger.handleRuntimeLog(log);
|
package/lib/emulator/hub.js
CHANGED
|
@@ -25,9 +25,10 @@ class EmulatorHub {
|
|
|
25
25
|
});
|
|
26
26
|
this.hub.get(EmulatorHub.PATH_EMULATORS, (req, res) => {
|
|
27
27
|
const body = {};
|
|
28
|
-
registry_1.EmulatorRegistry.listRunning()
|
|
29
|
-
|
|
30
|
-
|
|
28
|
+
for (const emulator of registry_1.EmulatorRegistry.listRunning()) {
|
|
29
|
+
const info = registry_1.EmulatorRegistry.getInfo(emulator);
|
|
30
|
+
body[emulator] = info;
|
|
31
|
+
}
|
|
31
32
|
res.json(body);
|
|
32
33
|
});
|
|
33
34
|
this.hub.post(EmulatorHub.PATH_EXPORT, async (req, res) => {
|
|
@@ -82,7 +82,7 @@ class WebSocketTransport extends TransportStream {
|
|
|
82
82
|
};
|
|
83
83
|
const splat = [info.message, ...(info[triple_beam_1.SPLAT] || [])]
|
|
84
84
|
.map((value) => {
|
|
85
|
-
if (typeof value
|
|
85
|
+
if (typeof value === "string") {
|
|
86
86
|
try {
|
|
87
87
|
bundle.data = Object.assign(Object.assign({}, bundle.data), JSON.parse(value));
|
|
88
88
|
return null;
|
|
@@ -88,7 +88,7 @@ class PubsubEmulator {
|
|
|
88
88
|
this.subscriptionForTopic.set(topicName, sub);
|
|
89
89
|
}
|
|
90
90
|
ensureFunctionsClient() {
|
|
91
|
-
if (this.client
|
|
91
|
+
if (this.client !== undefined)
|
|
92
92
|
return;
|
|
93
93
|
const funcEmulator = registry_1.EmulatorRegistry.get(types_1.Emulators.FUNCTIONS);
|
|
94
94
|
if (!funcEmulator) {
|
package/lib/emulator/registry.js
CHANGED
|
@@ -17,6 +17,9 @@ class EmulatorRegistry {
|
|
|
17
17
|
const info = instance.getInfo();
|
|
18
18
|
await portUtils.waitForPortClosed(info.port, info.host);
|
|
19
19
|
}
|
|
20
|
+
static registerExtensionsEmulator() {
|
|
21
|
+
this.extensionsEmulatorRegistered = true;
|
|
22
|
+
}
|
|
20
23
|
static async stop(name) {
|
|
21
24
|
emulatorLogger_1.EmulatorLogger.forEmulator(name).logLabeled("BULLET", name, `Stopping ${constants_1.Constants.description(name)}`);
|
|
22
25
|
const instance = this.get(name);
|
|
@@ -29,7 +32,8 @@ class EmulatorRegistry {
|
|
|
29
32
|
static async stopAll() {
|
|
30
33
|
const stopPriority = {
|
|
31
34
|
ui: 0,
|
|
32
|
-
|
|
35
|
+
extensions: 1,
|
|
36
|
+
functions: 1.1,
|
|
33
37
|
hosting: 2,
|
|
34
38
|
database: 3.0,
|
|
35
39
|
firestore: 3.1,
|
|
@@ -52,6 +56,9 @@ class EmulatorRegistry {
|
|
|
52
56
|
}
|
|
53
57
|
}
|
|
54
58
|
static isRunning(emulator) {
|
|
59
|
+
if (emulator === types_1.Emulators.EXTENSIONS) {
|
|
60
|
+
return this.extensionsEmulatorRegistered && this.isRunning(types_1.Emulators.FUNCTIONS);
|
|
61
|
+
}
|
|
55
62
|
const instance = this.INSTANCES.get(emulator);
|
|
56
63
|
return instance !== undefined;
|
|
57
64
|
}
|
|
@@ -67,7 +74,7 @@ class EmulatorRegistry {
|
|
|
67
74
|
return this.INSTANCES.get(emulator);
|
|
68
75
|
}
|
|
69
76
|
static getInfo(emulator) {
|
|
70
|
-
const instance = this.INSTANCES.get(emulator);
|
|
77
|
+
const instance = this.INSTANCES.get(emulator === types_1.Emulators.EXTENSIONS ? types_1.Emulators.FUNCTIONS : emulator);
|
|
71
78
|
if (!instance) {
|
|
72
79
|
return undefined;
|
|
73
80
|
}
|
|
@@ -97,4 +104,5 @@ class EmulatorRegistry {
|
|
|
97
104
|
}
|
|
98
105
|
}
|
|
99
106
|
exports.EmulatorRegistry = EmulatorRegistry;
|
|
107
|
+
EmulatorRegistry.extensionsEmulatorRegistered = false;
|
|
100
108
|
EmulatorRegistry.INSTANCES = new Map();
|