firebase-tools 10.2.1 → 10.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (125) 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-configure.js +67 -7
  9. package/lib/commands/ext-dev-init.js +49 -49
  10. package/lib/commands/ext-export.js +7 -2
  11. package/lib/commands/ext-install.js +173 -109
  12. package/lib/commands/ext-uninstall.js +17 -8
  13. package/lib/commands/ext-update.js +67 -12
  14. package/lib/commands/functions-config-export.js +1 -1
  15. package/lib/commands/hosting-clone.js +3 -3
  16. package/lib/commands/remoteconfig-get.js +1 -1
  17. package/lib/config.js +6 -3
  18. package/lib/deploy/extensions/deploymentSummary.js +3 -3
  19. package/lib/deploy/extensions/planner.js +7 -6
  20. package/lib/deploy/extensions/tasks.js +1 -1
  21. package/lib/deploy/functions/backend.js +21 -5
  22. package/lib/deploy/functions/checkIam.js +5 -5
  23. package/lib/deploy/functions/containerCleaner.js +3 -3
  24. package/lib/deploy/functions/ensure.js +3 -3
  25. package/lib/deploy/functions/functionsDeployHelper.js +2 -2
  26. package/lib/deploy/functions/prepare.js +5 -3
  27. package/lib/deploy/functions/pricing.js +1 -1
  28. package/lib/deploy/functions/prompts.js +2 -2
  29. package/lib/deploy/functions/release/fabricator.js +7 -7
  30. package/lib/deploy/functions/release/index.js +1 -1
  31. package/lib/deploy/functions/release/planner.js +43 -26
  32. package/lib/deploy/functions/release/reporter.js +3 -0
  33. package/lib/deploy/functions/runtimes/discovery/index.js +6 -6
  34. package/lib/deploy/functions/runtimes/discovery/parsing.js +1 -1
  35. package/lib/deploy/functions/runtimes/discovery/v1alpha1.js +22 -12
  36. package/lib/deploy/functions/runtimes/golang/index.js +2 -2
  37. package/lib/deploy/functions/runtimes/node/index.js +53 -0
  38. package/lib/deploy/functions/runtimes/node/parseRuntimeAndValidateSDK.js +2 -2
  39. package/lib/deploy/functions/runtimes/node/parseTriggers.js +64 -20
  40. package/lib/deploy/functions/runtimes/node/versioning.js +2 -2
  41. package/lib/deploy/functions/services/firebaseAlerts.js +30 -0
  42. package/lib/deploy/functions/services/index.js +9 -1
  43. package/lib/deploy/functions/services/storage.js +10 -4
  44. package/lib/deploy/functions/triggerRegionHelper.js +1 -1
  45. package/lib/deploy/functions/validate.js +3 -3
  46. package/lib/deploy/hosting/deploy.js +2 -2
  47. package/lib/deploy/hosting/hashcache.js +21 -19
  48. package/lib/deploy/hosting/uploader.js +5 -5
  49. package/lib/deploy/remoteconfig/functions.js +2 -2
  50. package/lib/emulator/auth/cloudFunctions.js +1 -1
  51. package/lib/emulator/auth/operations.js +1 -1
  52. package/lib/emulator/constants.js +4 -0
  53. package/lib/emulator/controller.js +54 -24
  54. package/lib/emulator/download.js +18 -1
  55. package/lib/emulator/downloadableEmulators.js +1 -1
  56. package/lib/emulator/emulatorLogger.js +12 -1
  57. package/lib/emulator/extensions/validation.js +70 -0
  58. package/lib/emulator/extensionsEmulator.js +175 -0
  59. package/lib/emulator/functionsEmulator.js +95 -43
  60. package/lib/emulator/functionsEmulatorRuntime.js +44 -36
  61. package/lib/emulator/functionsEmulatorShared.js +30 -11
  62. package/lib/emulator/functionsEmulatorShell.js +1 -1
  63. package/lib/emulator/functionsEmulatorUtils.js +4 -4
  64. package/lib/emulator/functionsRuntimeWorker.js +2 -2
  65. package/lib/emulator/hub.js +4 -3
  66. package/lib/emulator/loggingEmulator.js +1 -1
  67. package/lib/emulator/pubsubEmulator.js +1 -1
  68. package/lib/emulator/registry.js +10 -2
  69. package/lib/emulator/storage/apis/firebase.js +314 -332
  70. package/lib/emulator/storage/apis/gcloud.js +241 -121
  71. package/lib/emulator/storage/crc.js +5 -1
  72. package/lib/emulator/storage/errors.js +9 -0
  73. package/lib/emulator/storage/files.js +159 -300
  74. package/lib/emulator/storage/index.js +27 -73
  75. package/lib/emulator/storage/metadata.js +65 -51
  76. package/lib/emulator/storage/multipart.js +62 -0
  77. package/lib/emulator/storage/persistence.js +78 -0
  78. package/lib/emulator/storage/rules/config.js +33 -0
  79. package/lib/emulator/storage/rules/manager.js +81 -0
  80. package/lib/emulator/storage/rules/runtime.js +8 -7
  81. package/lib/emulator/storage/rules/utils.js +48 -0
  82. package/lib/emulator/storage/server.js +2 -2
  83. package/lib/emulator/storage/upload.js +106 -0
  84. package/lib/emulator/types.js +3 -0
  85. package/lib/ensureApiEnabled.js +5 -1
  86. package/lib/error.js +1 -1
  87. package/lib/extensions/askUserForParam.js +31 -25
  88. package/lib/extensions/changelog.js +3 -1
  89. package/lib/extensions/checkProjectBilling.js +1 -1
  90. package/lib/extensions/displayExtensionInfo.js +1 -1
  91. package/lib/extensions/emulator/optionsHelper.js +56 -8
  92. package/lib/extensions/emulator/specHelper.js +10 -23
  93. package/lib/extensions/export.js +1 -51
  94. package/lib/extensions/extensionsApi.js +1 -1
  95. package/lib/extensions/extensionsHelper.js +32 -19
  96. package/lib/extensions/manifest.js +144 -0
  97. package/lib/extensions/metricsUtils.js +4 -4
  98. package/lib/extensions/paramHelper.js +34 -12
  99. package/lib/extensions/refs.js +1 -1
  100. package/lib/extensions/secretsUtils.js +3 -3
  101. package/lib/functional.js +1 -1
  102. package/lib/functions/env.js +6 -7
  103. package/lib/functions/events/v2.js +11 -0
  104. package/lib/gcp/cloudfunctions.js +43 -11
  105. package/lib/gcp/cloudfunctionsv2.js +48 -17
  106. package/lib/gcp/cloudtasks.js +1 -1
  107. package/lib/gcp/docker.js +2 -2
  108. package/lib/gcp/resourceManager.js +4 -4
  109. package/lib/gcp/run.js +2 -2
  110. package/lib/hosting/api.js +1 -1
  111. package/lib/hosting/proxy.js +2 -2
  112. package/lib/init/features/account.js +1 -1
  113. package/lib/management/database.js +1 -1
  114. package/lib/previews.js +1 -1
  115. package/lib/serve/functions.js +2 -1
  116. package/lib/utils.js +15 -2
  117. package/npm-shrinkwrap.json +786 -393
  118. package/package.json +1 -1
  119. package/schema/firebase-config.json +5 -0
  120. package/templates/init/functions/javascript/package.lint.json +3 -3
  121. package/templates/init/functions/javascript/package.nolint.json +2 -2
  122. package/templates/init/functions/typescript/package.lint.json +7 -7
  123. package/templates/init/functions/typescript/package.nolint.json +3 -3
  124. package/lib/deploy/extensions/params.js +0 -39
  125. package/lib/deploy/functions/eventTypes.js +0 -10
@@ -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,12 +30,11 @@ 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
- const LOCAL_SECRETS_FILE = ".secret.local";
38
38
  const DATABASE_PATH_PATTERN = new RegExp("^projects/[^/]+/instances/([^/]+)/refs(/.*)$");
39
39
  class FunctionsEmulator {
40
40
  constructor(args) {
@@ -92,6 +92,7 @@ class FunctionsEmulator {
92
92
  const httpsFunctionRoute = `/${this.args.projectId}/:region/:trigger_name`;
93
93
  const multicastFunctionRoute = `/functions/projects/:project_id/trigger_multicast`;
94
94
  const httpsFunctionRoutes = [httpsFunctionRoute, `${httpsFunctionRoute}/*`];
95
+ const listBackendsRoute = `/backends`;
95
96
  const backgroundHandler = (req, res) => {
96
97
  var _a;
97
98
  const region = req.params.region;
@@ -152,6 +153,10 @@ class FunctionsEmulator {
152
153
  });
153
154
  res.json({ status: "multicast_acknowledged" });
154
155
  };
156
+ const listBackendsHandler = (req, res) => {
157
+ res.json({ backends: this.getBackendInfo() });
158
+ };
159
+ hub.get(listBackendsRoute, cors({ origin: true }), listBackendsHandler);
155
160
  hub.post(backgroundFunctionRoute, dataMiddleware, backgroundHandler);
156
161
  hub.post(multicastFunctionRoute, dataMiddleware, multicastHandler);
157
162
  hub.all(httpsFunctionRoutes, dataMiddleware, httpsHandler);
@@ -161,9 +166,15 @@ class FunctionsEmulator {
161
166
  });
162
167
  return hub;
163
168
  }
164
- async startFunctionRuntime(backend, trigger, proto, runtimeOpts) {
169
+ async invokeTrigger(backend, trigger, proto, runtimeOpts) {
165
170
  const bundleTemplate = this.getBaseBundle();
166
171
  const runtimeBundle = Object.assign(Object.assign({}, bundleTemplate), { proto });
172
+ if (this.args.debugPort) {
173
+ runtimeBundle.debug = {
174
+ functionTarget: trigger.entryPoint,
175
+ functionSignature: (0, functionsEmulatorShared_1.getSignatureType)(trigger),
176
+ };
177
+ }
167
178
  if (!backend.nodeBinary) {
168
179
  throw new error_1.FirebaseError(`No node binary for ${trigger.id}. This should never happen.`);
169
180
  }
@@ -240,15 +251,19 @@ class FunctionsEmulator {
240
251
  }
241
252
  let triggerDefinitions;
242
253
  if (emulatableBackend.predefinedTriggers) {
243
- triggerDefinitions = (0, functionsEmulatorShared_1.emulatedFunctionsByRegion)(emulatableBackend.predefinedTriggers);
254
+ triggerDefinitions = (0, functionsEmulatorShared_1.emulatedFunctionsByRegion)(emulatableBackend.predefinedTriggers, emulatableBackend.secretEnv);
244
255
  }
245
256
  else {
246
257
  const runtimeConfig = this.getRuntimeConfig(emulatableBackend);
247
- const runtimeDelegate = await (0, runtimes_1.getRuntimeDelegate)({
258
+ const runtimeDelegateContext = {
248
259
  projectId: this.args.projectId,
249
260
  projectDir: this.args.projectDir,
250
261
  sourceDir: emulatableBackend.functionsDir,
251
- });
262
+ };
263
+ if (emulatableBackend.nodeMajorVersion) {
264
+ runtimeDelegateContext.runtime = `nodejs${emulatableBackend.nodeMajorVersion}`;
265
+ }
266
+ const runtimeDelegate = await runtimes.getRuntimeDelegate(runtimeDelegateContext);
252
267
  logger_1.logger.debug(`Validating ${runtimeDelegate.name} source`);
253
268
  await runtimeDelegate.validate();
254
269
  logger_1.logger.debug(`Building ${runtimeDelegate.name} source`);
@@ -331,6 +346,9 @@ class FunctionsEmulator {
331
346
  this.logger.logLabeled("SUCCESS", `functions[${definition.id}]`, msg);
332
347
  }
333
348
  }
349
+ if (this.args.debugPort) {
350
+ this.startRuntime(emulatableBackend, { nodeBinary: emulatableBackend.nodeBinary });
351
+ }
334
352
  }
335
353
  addRealtimeDatabaseTrigger(projectId, key, eventTrigger) {
336
354
  const databaseEmu = registry_1.EmulatorRegistry.get(types_1.Emulators.DATABASE);
@@ -469,8 +487,26 @@ class FunctionsEmulator {
469
487
  getTriggerKey(def) {
470
488
  return def.eventTrigger ? `${def.id}-${this.triggerGeneration}` : def.id;
471
489
  }
472
- getBackends() {
473
- return this.args.emulatableBackends;
490
+ getBackendInfo() {
491
+ const cf3Triggers = Object.values(this.triggers)
492
+ .filter((t) => !t.backend.extensionInstanceId)
493
+ .map((t) => t.def);
494
+ return this.args.emulatableBackends.map((e) => {
495
+ var _a;
496
+ const envWithSecrets = Object.assign({}, e.env);
497
+ for (const s of e.secretEnv) {
498
+ envWithSecrets[s.key] = backend.secretVersionName(s);
499
+ }
500
+ return {
501
+ directory: e.functionsDir,
502
+ env: envWithSecrets,
503
+ extensionInstanceId: e.extensionInstanceId,
504
+ extension: e.extension,
505
+ extensionVersion: e.extensionVersion,
506
+ extensionSpec: e.extensionSpec,
507
+ functionTriggers: (_a = e.predefinedTriggers) !== null && _a !== void 0 ? _a : cf3Triggers,
508
+ };
509
+ });
474
510
  }
475
511
  addTriggerRecord(def, opts) {
476
512
  const key = this.getTriggerKey(def);
@@ -536,6 +572,7 @@ class FunctionsEmulator {
536
572
  const projectInfo = {
537
573
  functionsSource: backend.functionsDir,
538
574
  projectId: this.args.projectId,
575
+ projectAlias: this.args.projectAlias,
539
576
  isEmulator: true,
540
577
  };
541
578
  if (functionsEnv.hasUserEnvs(projectInfo)) {
@@ -589,6 +626,9 @@ class FunctionsEmulator {
589
626
  const pubsubHost = (0, functionsEmulatorShared_1.formatHost)(pubsubEmulator);
590
627
  process.env.PUBSUB_EMULATOR_HOST = pubsubHost;
591
628
  }
629
+ if (this.args.debugPort) {
630
+ envs["FUNCTION_DEBUG_MODE"] = "true";
631
+ }
592
632
  return envs;
593
633
  }
594
634
  getFirebaseConfig() {
@@ -613,53 +653,61 @@ class FunctionsEmulator {
613
653
  }
614
654
  async resolveSecretEnvs(backend, trigger) {
615
655
  let secretEnvs = {};
656
+ const secretPath = (0, functionsEmulatorShared_1.getSecretLocalPath)(backend, this.args.projectDir);
616
657
  try {
617
- const data = fs.readFileSync(path.join(backend.functionsDir, LOCAL_SECRETS_FILE), "utf8");
658
+ const data = fs.readFileSync(secretPath, "utf8");
618
659
  secretEnvs = functionsEnv.parseStrict(data);
619
660
  }
620
661
  catch (e) {
621
662
  if (e.code !== "ENOENT") {
622
- this.logger.logLabeled("ERROR", "functions", `Failed to read local secrets file ${LOCAL_SECRETS_FILE}: ${e.message}`);
663
+ this.logger.logLabeled("ERROR", "functions", `Failed to read local secrets file ${secretPath}: ${e.message}`);
623
664
  }
624
665
  }
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);
666
+ if (trigger) {
667
+ const secrets = trigger.secretEnvironmentVariables || [];
668
+ const accesses = secrets
669
+ .filter((s) => !secretEnvs[s.key])
670
+ .map(async (s) => {
671
+ var _a;
672
+ this.logger.logLabeled("INFO", "functions", `Trying to access secret ${s.secret}@latest`);
673
+ const value = await (0, secretManager_1.accessSecretVersion)(this.getProjectId(), s.secret, (_a = s.version) !== null && _a !== void 0 ? _a : "latest");
674
+ return [s.key, value];
675
+ });
676
+ const accessResults = await (0, utils_1.allSettled)(accesses);
677
+ const errs = [];
678
+ for (const result of accessResults) {
679
+ if (result.status === "rejected") {
680
+ errs.push(result.reason);
681
+ }
682
+ else {
683
+ const [k, v] = result.value;
684
+ secretEnvs[k] = v;
685
+ }
638
686
  }
639
- else {
640
- const [k, v] = result.value;
641
- secretEnvs[k] = v;
687
+ if (errs.length > 0) {
688
+ this.logger.logLabeled("ERROR", "functions", "Unable to access secret environment variables from Google Cloud Secret Manager. " +
689
+ "Make sure the credential used for the Functions Emulator have access " +
690
+ `or provide override values in ${secretPath}:\n\t` +
691
+ errs.join("\n\t"));
642
692
  }
643
693
  }
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
694
  return secretEnvs;
651
695
  }
652
696
  async invokeRuntime(backend, trigger, frb, opts) {
653
- if (this.workerPool.readyForWork(trigger.id)) {
654
- return this.workerPool.submitWork(trigger.id, frb, opts);
697
+ if (!this.workerPool.readyForWork(trigger.id)) {
698
+ await this.startRuntime(backend, opts, trigger);
655
699
  }
700
+ return this.workerPool.submitWork(trigger.id, frb, opts);
701
+ }
702
+ async startRuntime(backend, opts, trigger) {
703
+ var _a;
656
704
  const emitter = new events_1.EventEmitter();
657
705
  const args = [path.join(__dirname, "functionsEmulatorRuntime")];
658
706
  if (opts.ignore_warnings) {
659
707
  args.unshift("--no-warnings");
660
708
  }
661
709
  if (this.args.debugPort) {
662
- if (process.env.FIREPIT_VERSION && process.execPath == opts.nodeBinary) {
710
+ if (process.env.FIREPIT_VERSION && process.execPath === opts.nodeBinary) {
663
711
  const requestedMajorNodeVersion = this.getNodeBinary(backend);
664
712
  this.logger.log("WARN", `To enable function inspection, please run "${process.execPath} is:npm i node@${requestedMajorNodeVersion} --save-dev" in your functions directory`);
665
713
  }
@@ -721,8 +769,12 @@ class FunctionsEmulator {
721
769
  return childProcess.send(JSON.stringify(args));
722
770
  },
723
771
  };
724
- this.workerPool.addWorker(trigger.id, runtime);
725
- return this.workerPool.submitWork(trigger.id, frb, opts);
772
+ const extensionLogInfo = {
773
+ instanceId: backend.extensionInstanceId,
774
+ ref: (_a = backend.extensionVersion) === null || _a === void 0 ? void 0 : _a.ref,
775
+ };
776
+ this.workerPool.addWorker(trigger === null || trigger === void 0 ? void 0 : trigger.id, runtime, extensionLogInfo);
777
+ return;
726
778
  }
727
779
  async disableBackgroundTriggers() {
728
780
  Object.values(this.triggers).forEach((record) => {
@@ -748,7 +800,7 @@ class FunctionsEmulator {
748
800
  }
749
801
  const trigger = record.def;
750
802
  const service = (0, functionsEmulatorShared_1.getFunctionService)(trigger);
751
- const worker = await this.startFunctionRuntime(record.backend, trigger, proto);
803
+ const worker = await this.invokeTrigger(record.backend, trigger, proto);
752
804
  return new Promise((resolve, reject) => {
753
805
  if (projectId !== this.args.projectId) {
754
806
  if (service !== constants_1.Constants.SERVICE_REALTIME_DATABASE) {
@@ -767,7 +819,7 @@ class FunctionsEmulator {
767
819
  reject({ code: 500, body: el.text });
768
820
  }
769
821
  });
770
- track(EVENT_INVOKE, (0, functionsEmulatorShared_1.getFunctionService)(trigger));
822
+ void track(EVENT_INVOKE, (0, functionsEmulatorShared_1.getFunctionService)(trigger));
771
823
  worker.waitForDone().then(() => {
772
824
  resolve({ status: "acknowledged" });
773
825
  });
@@ -835,14 +887,14 @@ class FunctionsEmulator {
835
887
  req.headers[functionsEmulatorShared_1.HttpConstants.CALLABLE_AUTH_HEADER] = encodeURIComponent(JSON.stringify(contextAuth));
836
888
  }
837
889
  }
838
- const worker = await this.startFunctionRuntime(record.backend, trigger);
890
+ const worker = await this.invokeTrigger(record.backend, trigger);
839
891
  worker.onLogs((el) => {
840
892
  if (el.level === "FATAL") {
841
893
  res.status(500).send(el.text);
842
894
  }
843
895
  });
844
896
  await worker.waitForSocketReady();
845
- track(EVENT_INVOKE, "https");
897
+ void track(EVENT_INVOKE, "https");
846
898
  this.logger.log("DEBUG", `[functions] Runtime ready! Sending request!`);
847
899
  if (!worker.lastArgs) {
848
900
  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
  }
@@ -1,13 +1,15 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getSignatureType = exports.formatHost = exports.findModuleRoot = exports.waitForBody = exports.getServiceFromEventType = exports.getFunctionService = exports.getTemporarySocketPath = exports.getEmulatedTriggersFromDefinitions = exports.emulatedFunctionsByRegion = exports.emulatedFunctionsFromEndpoints = exports.EmulatedTrigger = exports.HttpConstants = void 0;
3
+ exports.getSecretLocalPath = exports.getSignatureType = exports.formatHost = exports.findModuleRoot = exports.waitForBody = exports.getServiceFromEventType = exports.getFunctionService = exports.getTemporarySocketPath = exports.getEmulatedTriggersFromDefinitions = exports.emulatedFunctionsByRegion = exports.emulatedFunctionsFromEndpoints = exports.EmulatedTrigger = exports.HttpConstants = void 0;
4
4
  const _ = require("lodash");
5
5
  const os = require("os");
6
6
  const path = require("path");
7
7
  const fs = require("fs");
8
+ const backend = require("../deploy/functions/backend");
8
9
  const constants_1 = require("./constants");
9
- const backend_1 = require("../deploy/functions/backend");
10
10
  const proto_1 = require("../gcp/proto");
11
+ const logger_1 = require("../logger");
12
+ const manifest_1 = require("../extensions/manifest");
11
13
  const memoryLookup = {
12
14
  "128MB": 128,
13
15
  "256MB": 256,
@@ -60,30 +62,35 @@ function emulatedFunctionsFromEndpoints(endpoints) {
60
62
  id: `${endpoint.region}-${endpoint.id}`,
61
63
  };
62
64
  (0, proto_1.copyIfPresent)(def, endpoint, "timeout", "availableMemoryMb", "labels", "platform", "secretEnvironmentVariables");
63
- if ((0, backend_1.isHttpsTriggered)(endpoint)) {
65
+ if (backend.isHttpsTriggered(endpoint)) {
64
66
  def.httpsTrigger = endpoint.httpsTrigger;
65
67
  }
66
- else if ((0, backend_1.isEventTriggered)(endpoint)) {
68
+ else if (backend.isEventTriggered(endpoint)) {
67
69
  const eventTrigger = endpoint.eventTrigger;
68
70
  if (endpoint.platform === "gcfv1") {
71
+ const resourceFilter = backend.findEventFilter(endpoint, "resource");
72
+ if (!resourceFilter) {
73
+ logger_1.logger.debug(`Invalid event trigger ${JSON.stringify(endpoint)}, expected event filter with resource attribute. Skipping.`);
74
+ continue;
75
+ }
69
76
  def.eventTrigger = {
70
77
  eventType: eventTrigger.eventType,
71
- resource: eventTrigger.eventFilters.resource,
78
+ resource: resourceFilter.value,
72
79
  };
73
80
  }
74
81
  else {
75
- const { resource, topic, bucket } = endpoint.eventTrigger.eventFilters;
76
- const eventResource = resource || topic || bucket;
77
- if (!eventResource) {
82
+ const [eventFilter] = endpoint.eventTrigger.eventFilters;
83
+ if (!eventFilter) {
84
+ logger_1.logger.debug(`Invalid event trigger ${JSON.stringify(endpoint)}, expected at least one event filter. Skipping.`);
78
85
  continue;
79
86
  }
80
87
  def.eventTrigger = {
81
88
  eventType: eventTrigger.eventType,
82
- resource: eventResource,
89
+ resource: eventFilter.value,
83
90
  };
84
91
  }
85
92
  }
86
- else if ((0, backend_1.isScheduleTriggered)(endpoint)) {
93
+ else if (backend.isScheduleTriggered(endpoint)) {
87
94
  def.eventTrigger = { eventType: "pubsub", resource: "" };
88
95
  def.schedule = endpoint.scheduleTrigger;
89
96
  }
@@ -94,7 +101,7 @@ function emulatedFunctionsFromEndpoints(endpoints) {
94
101
  return regionDefinitions;
95
102
  }
96
103
  exports.emulatedFunctionsFromEndpoints = emulatedFunctionsFromEndpoints;
97
- function emulatedFunctionsByRegion(definitions) {
104
+ function emulatedFunctionsByRegion(definitions, secretEnvVariables = []) {
98
105
  const regionDefinitions = [];
99
106
  for (const def of definitions) {
100
107
  if (!def.regions) {
@@ -106,6 +113,7 @@ function emulatedFunctionsByRegion(definitions) {
106
113
  defDeepCopy.region = region;
107
114
  defDeepCopy.id = `${region}-${defDeepCopy.name}`;
108
115
  defDeepCopy.platform = defDeepCopy.platform || "gcfv1";
116
+ defDeepCopy.secretEnvironmentVariables = secretEnvVariables;
109
117
  regionDefinitions.push(defDeepCopy);
110
118
  }
111
119
  }
@@ -219,3 +227,14 @@ function getSignatureType(def) {
219
227
  return def.platform === "gcfv2" ? "cloudevent" : "event";
220
228
  }
221
229
  exports.getSignatureType = getSignatureType;
230
+ const LOCAL_SECRETS_FILE = ".secret.local";
231
+ function getSecretLocalPath(backend, projectDir) {
232
+ const secretsFile = backend.extensionInstanceId
233
+ ? `${backend.extensionInstanceId}${LOCAL_SECRETS_FILE}`
234
+ : LOCAL_SECRETS_FILE;
235
+ const secretDirectory = backend.extensionInstanceId
236
+ ? path.join(projectDir, manifest_1.ENV_DIRECTORY)
237
+ : backend.functionsDir;
238
+ return path.join(secretDirectory, secretsFile);
239
+ }
240
+ exports.getSecretLocalPath = getSecretLocalPath;
@@ -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) {