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.
Files changed (105) hide show
  1. package/lib/appdistribution/options-parser-util.js +1 -1
  2. package/lib/auth.js +3 -3
  3. package/lib/command.js +1 -1
  4. package/lib/commands/apps-android-sha-create.js +2 -2
  5. package/lib/commands/apps-sdkconfig.js +1 -1
  6. package/lib/commands/database-rules-list.js +2 -2
  7. package/lib/commands/emulators-start.js +1 -1
  8. package/lib/commands/ext-dev-init.js +49 -49
  9. package/lib/commands/ext-export.js +12 -2
  10. package/lib/commands/ext-install.js +104 -104
  11. package/lib/commands/ext-uninstall.js +8 -8
  12. package/lib/commands/ext-update.js +9 -9
  13. package/lib/commands/functions-config-export.js +1 -1
  14. package/lib/commands/hosting-clone.js +3 -3
  15. package/lib/commands/remoteconfig-get.js +1 -1
  16. package/lib/deploy/extensions/deploymentSummary.js +3 -3
  17. package/lib/deploy/extensions/params.js +3 -0
  18. package/lib/deploy/extensions/planner.js +2 -1
  19. package/lib/deploy/extensions/tasks.js +1 -1
  20. package/lib/deploy/functions/backend.js +12 -5
  21. package/lib/deploy/functions/checkIam.js +1 -1
  22. package/lib/deploy/functions/containerCleaner.js +3 -3
  23. package/lib/deploy/functions/ensure.js +3 -3
  24. package/lib/deploy/functions/functionsDeployHelper.js +2 -2
  25. package/lib/deploy/functions/prepare.js +3 -2
  26. package/lib/deploy/functions/pricing.js +1 -1
  27. package/lib/deploy/functions/prompts.js +2 -2
  28. package/lib/deploy/functions/release/fabricator.js +3 -3
  29. package/lib/deploy/functions/release/index.js +1 -1
  30. package/lib/deploy/functions/release/planner.js +11 -8
  31. package/lib/deploy/functions/release/reporter.js +3 -0
  32. package/lib/deploy/functions/runtimes/discovery/index.js +6 -6
  33. package/lib/deploy/functions/runtimes/discovery/parsing.js +1 -1
  34. package/lib/deploy/functions/runtimes/discovery/v1alpha1.js +16 -11
  35. package/lib/deploy/functions/runtimes/golang/index.js +2 -2
  36. package/lib/deploy/functions/runtimes/node/index.js +26 -0
  37. package/lib/deploy/functions/runtimes/node/parseRuntimeAndValidateSDK.js +2 -2
  38. package/lib/deploy/functions/runtimes/node/parseTriggers.js +28 -7
  39. package/lib/deploy/functions/runtimes/node/versioning.js +2 -2
  40. package/lib/deploy/functions/validate.js +3 -3
  41. package/lib/deploy/hosting/deploy.js +2 -2
  42. package/lib/deploy/hosting/hashcache.js +21 -19
  43. package/lib/deploy/hosting/uploader.js +5 -5
  44. package/lib/deploy/remoteconfig/functions.js +2 -2
  45. package/lib/emulator/auth/cloudFunctions.js +1 -1
  46. package/lib/emulator/auth/operations.js +1 -1
  47. package/lib/emulator/constants.js +3 -0
  48. package/lib/emulator/controller.js +47 -19
  49. package/lib/emulator/download.js +18 -1
  50. package/lib/emulator/downloadableEmulators.js +1 -1
  51. package/lib/emulator/emulatorLogger.js +12 -1
  52. package/lib/emulator/extensions/validation.js +35 -0
  53. package/lib/emulator/extensionsEmulator.js +140 -0
  54. package/lib/emulator/functionsEmulator.js +86 -39
  55. package/lib/emulator/functionsEmulatorRuntime.js +44 -36
  56. package/lib/emulator/functionsEmulatorShell.js +1 -1
  57. package/lib/emulator/functionsEmulatorUtils.js +4 -4
  58. package/lib/emulator/functionsRuntimeWorker.js +2 -2
  59. package/lib/emulator/hub.js +4 -3
  60. package/lib/emulator/loggingEmulator.js +1 -1
  61. package/lib/emulator/pubsubEmulator.js +1 -1
  62. package/lib/emulator/registry.js +10 -2
  63. package/lib/emulator/storage/apis/firebase.js +31 -26
  64. package/lib/emulator/storage/apis/gcloud.js +7 -12
  65. package/lib/emulator/storage/files.js +36 -34
  66. package/lib/emulator/storage/index.js +2 -2
  67. package/lib/emulator/storage/metadata.js +2 -2
  68. package/lib/emulator/storage/rules/runtime.js +8 -7
  69. package/lib/emulator/types.js +3 -0
  70. package/lib/ensureApiEnabled.js +5 -1
  71. package/lib/error.js +1 -1
  72. package/lib/extensions/askUserForParam.js +1 -1
  73. package/lib/extensions/changelog.js +3 -1
  74. package/lib/extensions/checkProjectBilling.js +1 -1
  75. package/lib/extensions/displayExtensionInfo.js +1 -1
  76. package/lib/extensions/emulator/optionsHelper.js +24 -8
  77. package/lib/extensions/emulator/specHelper.js +10 -23
  78. package/lib/extensions/export.js +1 -51
  79. package/lib/extensions/extensionsApi.js +1 -1
  80. package/lib/extensions/extensionsHelper.js +13 -9
  81. package/lib/extensions/manifest.js +48 -0
  82. package/lib/extensions/metricsUtils.js +4 -4
  83. package/lib/extensions/paramHelper.js +4 -4
  84. package/lib/extensions/refs.js +1 -1
  85. package/lib/extensions/secretsUtils.js +3 -3
  86. package/lib/functional.js +1 -1
  87. package/lib/functions/env.js +2 -1
  88. package/lib/gcp/cloudfunctions.js +24 -5
  89. package/lib/gcp/cloudfunctionsv2.js +18 -5
  90. package/lib/gcp/cloudtasks.js +1 -1
  91. package/lib/gcp/docker.js +2 -2
  92. package/lib/gcp/run.js +2 -2
  93. package/lib/hosting/api.js +1 -1
  94. package/lib/hosting/proxy.js +2 -2
  95. package/lib/init/features/account.js +1 -1
  96. package/lib/management/database.js +1 -1
  97. package/lib/previews.js +1 -1
  98. package/lib/utils.js +1 -1
  99. package/npm-shrinkwrap.json +786 -393
  100. package/package.json +1 -1
  101. package/schema/firebase-config.json +5 -0
  102. package/templates/init/functions/javascript/package.lint.json +3 -3
  103. package/templates/init/functions/javascript/package.nolint.json +2 -2
  104. package/templates/init/functions/typescript/package.lint.json +7 -7
  105. 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 runtimes_1 = require("../deploy/functions/runtimes");
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 startFunctionRuntime(backend, trigger, proto, runtimeOpts) {
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 runtimeDelegate = await (0, runtimes_1.getRuntimeDelegate)({
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
- getBackends() {
473
- return this.args.emulatableBackends;
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
- const secrets = trigger.secretEnvironmentVariables || [];
626
- const accesses = secrets
627
- .filter((s) => !secretEnvs[s.secret])
628
- .map(async (s) => {
629
- this.logger.logLabeled("INFO", "functions", `Trying to access secret ${s.key}@latest`);
630
- const value = await (0, secretManager_1.accessSecretVersion)(this.getProjectId(), s.key, "latest");
631
- return [s.secret, value];
632
- });
633
- const accessResults = await (0, utils_1.allSettled)(accesses);
634
- const errs = [];
635
- for (const result of accessResults) {
636
- if (result.status === "rejected") {
637
- errs.push(result.reason);
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
- else {
640
- const [k, v] = result.value;
641
- secretEnvs[k] = v;
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
- return this.workerPool.submitWork(trigger.id, frb, opts);
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 == opts.nodeBinary) {
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
- this.workerPool.addWorker(trigger.id, runtime);
725
- return this.workerPool.submitWork(trigger.id, frb, opts);
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.startFunctionRuntime(record.backend, trigger, proto);
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.startFunctionRuntime(record.backend, trigger);
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 functionTrigger;
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 functionTrigger(proto.data, proto.context);
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 functionTrigger(event);
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 functionTrigger(args[0], args[1]);
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
- FUNCTION_TARGET_NAME = process.env.FUNCTION_TARGET || "";
653
- if (!FUNCTION_TARGET_NAME) {
654
- new types_1.EmulatorLog("FATAL", "runtime-status", `Environment variable FUNCTION_TARGET cannot be empty. This shouldn't happen.`).log();
655
- await flushAndExit(1);
656
- }
657
- FUNCTION_SIGNATURE = process.env.FUNCTION_SIGNATURE_TYPE || "";
658
- if (!FUNCTION_SIGNATURE) {
659
- new types_1.EmulatorLog("FATAL", "runtime-status", `Environment variable FUNCTION_SIGNATURE_TYPE cannot be empty. This shouldn't happen.`).log();
660
- await flushAndExit(1);
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 loadTrigger(frb, functionTarget, serializedFunctionTrigger) {
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
- const maybeTrigger = functionTarget.split(".").reduce((mod, functionTargetPart) => {
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 (!functionTrigger) {
717
+ if (!functionModule) {
720
718
  try {
721
719
  await initializeRuntime(runtimeArgs.frb);
722
720
  const serializedTriggers = runtimeArgs.opts ? runtimeArgs.opts.serializedTriggers : undefined;
723
- functionTrigger = await loadTrigger(runtimeArgs.frb, FUNCTION_TARGET_NAME, serializedTriggers);
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 trigger. This shouldn't happen: ${e.message}`).log();
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.startFunctionRuntime(this.backend, trigger, proto);
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 = runtime.match(runtimeRe);
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 != versionB.major) {
76
+ if (versionA.major !== versionB.major) {
77
77
  return versionA.major - versionB.major;
78
78
  }
79
- if (versionA.minor != versionB.minor) {
79
+ if (versionA.minor !== versionB.minor) {
80
80
  return versionA.minor - versionB.minor;
81
81
  }
82
- if (versionA.patch != versionB.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);
@@ -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().forEach((name) => {
29
- body[name] = registry_1.EmulatorRegistry.get(name).getInfo();
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 == "string") {
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 != undefined)
91
+ if (this.client !== undefined)
92
92
  return;
93
93
  const funcEmulator = registry_1.EmulatorRegistry.get(types_1.Emulators.FUNCTIONS);
94
94
  if (!funcEmulator) {
@@ -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
- functions: 1,
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();