firebase-tools 10.2.2 → 10.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/lib/commands/deploy.js +1 -1
  2. package/lib/commands/experimental-functions-shell.js +1 -1
  3. package/lib/commands/ext-configure.js +68 -7
  4. package/lib/commands/ext-export.js +10 -9
  5. package/lib/commands/ext-install.js +73 -9
  6. package/lib/commands/ext-uninstall.js +9 -0
  7. package/lib/commands/ext-update.js +58 -3
  8. package/lib/commands/functions-config-export.js +2 -2
  9. package/lib/commands/functions-shell.js +1 -1
  10. package/lib/commands/hosting-channel-create.js +2 -2
  11. package/lib/commands/hosting-channel-delete.js +2 -2
  12. package/lib/commands/hosting-channel-deploy.js +2 -2
  13. package/lib/commands/hosting-channel-list.js +2 -2
  14. package/lib/commands/hosting-channel-open.js +2 -2
  15. package/lib/commands/hosting-sites-delete.js +2 -2
  16. package/lib/commands/serve.js +1 -1
  17. package/lib/commands/target-apply.js +2 -2
  18. package/lib/commands/target-clear.js +2 -2
  19. package/lib/commands/target-remove.js +2 -2
  20. package/lib/commands/target.js +2 -2
  21. package/lib/config.js +9 -3
  22. package/lib/deploy/extensions/planner.js +15 -9
  23. package/lib/deploy/functions/backend.js +10 -1
  24. package/lib/deploy/functions/checkIam.js +4 -4
  25. package/lib/deploy/functions/prepare.js +2 -1
  26. package/lib/deploy/functions/release/fabricator.js +4 -4
  27. package/lib/deploy/functions/release/planner.js +34 -20
  28. package/lib/deploy/functions/runtimes/discovery/v1alpha1.js +6 -1
  29. package/lib/deploy/functions/runtimes/node/index.js +27 -0
  30. package/lib/deploy/functions/runtimes/node/parseTriggers.js +36 -13
  31. package/lib/deploy/functions/services/firebaseAlerts.js +30 -0
  32. package/lib/deploy/functions/services/index.js +9 -1
  33. package/lib/deploy/functions/services/storage.js +10 -4
  34. package/lib/deploy/functions/triggerRegionHelper.js +1 -1
  35. package/lib/emulator/auth/apiSpec.js +37 -0
  36. package/lib/emulator/commandUtils.js +2 -2
  37. package/lib/emulator/constants.js +1 -0
  38. package/lib/emulator/controller.js +9 -7
  39. package/lib/emulator/extensions/validation.js +37 -2
  40. package/lib/emulator/extensionsEmulator.js +47 -9
  41. package/lib/emulator/functionsEmulator.js +17 -12
  42. package/lib/emulator/functionsEmulatorShared.js +34 -11
  43. package/lib/emulator/storage/apis/firebase.js +316 -341
  44. package/lib/emulator/storage/apis/gcloud.js +238 -113
  45. package/lib/emulator/storage/crc.js +5 -1
  46. package/lib/emulator/storage/errors.js +9 -0
  47. package/lib/emulator/storage/files.js +161 -304
  48. package/lib/emulator/storage/index.js +25 -74
  49. package/lib/emulator/storage/metadata.js +63 -49
  50. package/lib/emulator/storage/multipart.js +62 -0
  51. package/lib/emulator/storage/persistence.js +78 -0
  52. package/lib/emulator/storage/rules/config.js +34 -0
  53. package/lib/emulator/storage/rules/manager.js +98 -0
  54. package/lib/emulator/storage/rules/runtime.js +4 -0
  55. package/lib/emulator/storage/rules/utils.js +48 -0
  56. package/lib/emulator/storage/server.js +2 -2
  57. package/lib/emulator/storage/upload.js +106 -0
  58. package/lib/extensions/askUserForParam.js +77 -28
  59. package/lib/extensions/emulator/optionsHelper.js +35 -3
  60. package/lib/extensions/extensionsHelper.js +19 -10
  61. package/lib/extensions/manifest.js +142 -14
  62. package/lib/extensions/paramHelper.js +32 -9
  63. package/lib/fsutils.js +14 -1
  64. package/lib/functions/env.js +4 -6
  65. package/lib/functions/events/v2.js +11 -0
  66. package/lib/gcp/cloudfunctions.js +20 -7
  67. package/lib/gcp/cloudfunctionsv2.js +30 -12
  68. package/lib/gcp/resourceManager.js +4 -4
  69. package/lib/requireConfig.js +11 -9
  70. package/lib/serve/functions.js +2 -1
  71. package/lib/utils.js +14 -1
  72. package/npm-shrinkwrap.json +2 -2
  73. package/package.json +1 -1
  74. package/lib/deploy/extensions/params.js +0 -42
  75. package/lib/deploy/functions/eventTypes.js +0 -10
  76. package/lib/prepareUpload.js +0 -44
@@ -5705,6 +5705,28 @@ exports.default = {
5705
5705
  },
5706
5706
  type: "object",
5707
5707
  },
5708
+ GoogleCloudIdentitytoolkitAdminV2AllowByDefault: {
5709
+ description: "Defines a policy of allowing every region by default and adding disallowed regions to a disallow list.",
5710
+ properties: {
5711
+ disallowedRegions: {
5712
+ description: "Two letter unicode region codes to disallow as defined by https://cldr.unicode.org/ The full list of these region codes is here: https://github.com/unicode-cldr/cldr-localenames-full/blob/master/main/en/territories.json",
5713
+ items: { type: "string" },
5714
+ type: "array",
5715
+ },
5716
+ },
5717
+ type: "object",
5718
+ },
5719
+ GoogleCloudIdentitytoolkitAdminV2AllowlistOnly: {
5720
+ description: "Defines a policy of only allowing regions by explicitly adding them to an allowlist.",
5721
+ properties: {
5722
+ allowedRegions: {
5723
+ description: "Two letter unicode region codes to allow as defined by https://cldr.unicode.org/ The full list of these region codes is here: https://github.com/unicode-cldr/cldr-localenames-full/blob/master/main/en/territories.json",
5724
+ items: { type: "string" },
5725
+ type: "array",
5726
+ },
5727
+ },
5728
+ type: "object",
5729
+ },
5708
5730
  GoogleCloudIdentitytoolkitAdminV2Anonymous: {
5709
5731
  description: "Configuration options related to authenticating an anonymous user.",
5710
5732
  properties: {
@@ -6315,6 +6337,18 @@ exports.default = {
6315
6337
  },
6316
6338
  type: "object",
6317
6339
  },
6340
+ GoogleCloudIdentitytoolkitAdminV2SmsRegionConfig: {
6341
+ description: "Configures the regions where users are allowed to send verification SMS for the project or tenant. This is based on the calling code of the destination phone number.",
6342
+ properties: {
6343
+ allowByDefault: {
6344
+ $ref: "#/components/schemas/GoogleCloudIdentitytoolkitAdminV2AllowByDefault",
6345
+ },
6346
+ allowlistOnly: {
6347
+ $ref: "#/components/schemas/GoogleCloudIdentitytoolkitAdminV2AllowlistOnly",
6348
+ },
6349
+ },
6350
+ type: "object",
6351
+ },
6318
6352
  GoogleCloudIdentitytoolkitAdminV2SmsTemplate: {
6319
6353
  description: "The template to use when sending an SMS.",
6320
6354
  properties: {
@@ -6424,6 +6458,9 @@ exports.default = {
6424
6458
  readOnly: true,
6425
6459
  type: "string",
6426
6460
  },
6461
+ smsRegionConfig: {
6462
+ $ref: "#/components/schemas/GoogleCloudIdentitytoolkitAdminV2SmsRegionConfig",
6463
+ },
6427
6464
  testPhoneNumbers: {
6428
6465
  additionalProperties: { type: "string" },
6429
6466
  description: "A map of pairs that can be used for MFA. The phone number should be in E.164 format (https://www.itu.int/rec/T-REC-E.164/) and a maximum of 10 pairs can be added (error will be thrown once exceeded).",
@@ -10,7 +10,7 @@ const logger_1 = require("../logger");
10
10
  const path = require("path");
11
11
  const constants_1 = require("./constants");
12
12
  const requireAuth_1 = require("../requireAuth");
13
- const requireConfig = require("../requireConfig");
13
+ const requireConfig_1 = require("../requireConfig");
14
14
  const types_1 = require("./types");
15
15
  const error_1 = require("../error");
16
16
  const registry_1 = require("./registry");
@@ -102,7 +102,7 @@ async function beforeEmulatorCommand(options) {
102
102
  options.config = DEFAULT_CONFIG;
103
103
  }
104
104
  else {
105
- await requireConfig(options);
105
+ await (0, requireConfig_1.requireConfig)(options);
106
106
  }
107
107
  }
108
108
  exports.beforeEmulatorCommand = beforeEmulatorCommand;
@@ -90,6 +90,7 @@ class Constants {
90
90
  }
91
91
  exports.Constants = Constants;
92
92
  Constants.FAKE_PROJECT_ID_PREFIX = "demo-";
93
+ Constants.FAKE_PROJECT_NUMBER = "0";
93
94
  Constants.DEFAULT_DATABASE_EMULATOR_NAMESPACE = "fake-server";
94
95
  Constants.FIRESTORE_EMULATOR_HOST = "FIRESTORE_EMULATOR_HOST";
95
96
  Constants.FIREBASE_DATABASE_EMULATOR_HOST = "FIREBASE_DATABASE_EMULATOR_HOST";
@@ -33,6 +33,7 @@ const prompt_1 = require("../prompt");
33
33
  const commandUtils_1 = require("./commandUtils");
34
34
  const fsutils_1 = require("../fsutils");
35
35
  const storage_1 = require("./storage");
36
+ const config_1 = require("./storage/rules/config");
36
37
  const getDefaultDatabaseInstance_1 = require("../getDefaultDatabaseInstance");
37
38
  const auth_2 = require("../auth");
38
39
  const extensionsEmulator_1 = require("./extensionsEmulator");
@@ -259,12 +260,15 @@ async function startAll(options, showUI = true) {
259
260
  emulatableBackends.push({
260
261
  functionsDir,
261
262
  env: Object.assign({}, options.extDevEnv),
263
+ secretEnv: [],
262
264
  predefinedTriggers: options.extDevTriggers,
263
265
  nodeMajorVersion: (0, functionsEmulatorUtils_1.parseRuntimeVersion)(options.extDevNodeVersion || options.config.get("functions.runtime")),
264
266
  });
265
267
  }
266
268
  if (shouldStart(options, types_1.Emulators.EXTENSIONS) && previews_1.previews.extensionsemulator) {
267
- const projectNumber = await (0, projectUtils_1.needProjectNumber)(options);
269
+ const projectNumber = constants_1.Constants.isDemoProject(projectId)
270
+ ? constants_1.Constants.FAKE_PROJECT_NUMBER
271
+ : await (0, projectUtils_1.needProjectNumber)(options);
268
272
  const aliases = (0, projectUtils_1.getAliases)(options, projectId);
269
273
  const extensionEmulator = new extensionsEmulator_1.ExtensionsEmulator({
270
274
  projectId,
@@ -274,7 +278,8 @@ async function startAll(options, showUI = true) {
274
278
  extensions: options.config.get("extensions"),
275
279
  });
276
280
  const extensionsBackends = await extensionEmulator.getExtensionBackends();
277
- emulatableBackends.push(...extensionsBackends);
281
+ const filteredExtensionsBackends = extensionEmulator.filterUnemulatedTriggers(options, extensionsBackends);
282
+ emulatableBackends.push(...filteredExtensionsBackends);
278
283
  void track("Emulator Run", types_1.Emulators.EXTENSIONS);
279
284
  registry_1.EmulatorRegistry.registerExtensionsEmulator();
280
285
  }
@@ -302,6 +307,7 @@ async function startAll(options, showUI = true) {
302
307
  host: functionsAddr.host,
303
308
  port: functionsAddr.port,
304
309
  debugPort: inspectFunctions,
310
+ projectAlias: options.projectAlias,
305
311
  });
306
312
  await startEmulator(functionsEmulator);
307
313
  }
@@ -421,15 +427,11 @@ async function startAll(options, showUI = true) {
421
427
  }
422
428
  if (shouldStart(options, types_1.Emulators.STORAGE)) {
423
429
  const storageAddr = await getAndCheckAddress(types_1.Emulators.STORAGE, options);
424
- const storageConfig = options.config.data.storage;
425
- if (!(storageConfig === null || storageConfig === void 0 ? void 0 : storageConfig.rules)) {
426
- throw new error_1.FirebaseError("Cannot start the Storage emulator without rules file specified in firebase.json: run 'firebase init' and set up your Storage configuration");
427
- }
428
430
  const storageEmulator = new storage_1.StorageEmulator({
429
431
  host: storageAddr.host,
430
432
  port: storageAddr.port,
431
433
  projectId: projectId,
432
- rules: options.config.path(storageConfig.rules),
434
+ rules: (0, config_1.getStorageRulesConfig)(projectId, options),
433
435
  });
434
436
  await startEmulator(storageEmulator);
435
437
  if (exportMetadata.storage) {
@@ -1,8 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getUnemulatedAPIs = void 0;
3
+ exports.checkForUnemulatedTriggerTypes = exports.getUnemulatedAPIs = void 0;
4
4
  const planner = require("../../deploy/extensions/planner");
5
+ const controller_1 = require("../controller");
6
+ const constants_1 = require("../constants");
5
7
  const ensureApiEnabled_1 = require("../../ensureApiEnabled");
8
+ const functionsEmulatorShared_1 = require("../functionsEmulatorShared");
9
+ const types_1 = require("../types");
6
10
  const EMULATED_APIS = [
7
11
  "storage-component.googleapis.com",
8
12
  "firestore.googleapis.com",
@@ -20,7 +24,8 @@ async function getUnemulatedAPIs(projectId, instances) {
20
24
  unemulatedAPIs[api.apiName].instanceIds.push(i.instanceId);
21
25
  }
22
26
  else {
23
- const enabled = await (0, ensureApiEnabled_1.check)(projectId, api.apiName, "extensions", true);
27
+ const enabled = !constants_1.Constants.isDemoProject(projectId) &&
28
+ (await (0, ensureApiEnabled_1.check)(projectId, api.apiName, "extensions", true));
24
29
  unemulatedAPIs[api.apiName] = {
25
30
  apiName: api.apiName,
26
31
  instanceIds: [i.instanceId],
@@ -33,3 +38,33 @@ async function getUnemulatedAPIs(projectId, instances) {
33
38
  return Object.values(unemulatedAPIs);
34
39
  }
35
40
  exports.getUnemulatedAPIs = getUnemulatedAPIs;
41
+ function checkForUnemulatedTriggerTypes(backend, options) {
42
+ var _a;
43
+ const triggers = (_a = backend.predefinedTriggers) !== null && _a !== void 0 ? _a : [];
44
+ const unemulatedTriggers = triggers
45
+ .filter((definition) => {
46
+ if (definition.httpsTrigger) {
47
+ return false;
48
+ }
49
+ if (definition.eventTrigger) {
50
+ const service = (0, functionsEmulatorShared_1.getFunctionService)(definition);
51
+ switch (service) {
52
+ case constants_1.Constants.SERVICE_FIRESTORE:
53
+ return !(0, controller_1.shouldStart)(options, types_1.Emulators.FIRESTORE);
54
+ case constants_1.Constants.SERVICE_REALTIME_DATABASE:
55
+ return !(0, controller_1.shouldStart)(options, types_1.Emulators.DATABASE);
56
+ case constants_1.Constants.SERVICE_PUBSUB:
57
+ return !(0, controller_1.shouldStart)(options, types_1.Emulators.PUBSUB);
58
+ case constants_1.Constants.SERVICE_AUTH:
59
+ return !(0, controller_1.shouldStart)(options, types_1.Emulators.AUTH);
60
+ case constants_1.Constants.SERVICE_STORAGE:
61
+ return !(0, controller_1.shouldStart)(options, types_1.Emulators.STORAGE);
62
+ default:
63
+ return true;
64
+ }
65
+ }
66
+ })
67
+ .map((definition) => constants_1.Constants.getServiceName((0, functionsEmulatorShared_1.getFunctionService)(definition)));
68
+ return [...new Set(unemulatedTriggers)];
69
+ }
70
+ exports.checkForUnemulatedTriggerTypes = checkForUnemulatedTriggerTypes;
@@ -17,10 +17,12 @@ const types_1 = require("./types");
17
17
  const validation_1 = require("./extensions/validation");
18
18
  const ensureApiEnabled_1 = require("../ensureApiEnabled");
19
19
  const shortenUrl_1 = require("../shortenUrl");
20
+ const constants_1 = require("./constants");
20
21
  class ExtensionsEmulator {
21
22
  constructor(args) {
22
23
  this.want = [];
23
24
  this.logger = emulatorLogger_1.EmulatorLogger.forEmulator(types_1.Emulators.EXTENSIONS);
25
+ this.pendingDownloads = new Map();
24
26
  this.args = args;
25
27
  }
26
28
  async readManifest() {
@@ -31,7 +33,7 @@ class ExtensionsEmulator {
31
33
  aliases: (_a = this.args.aliases) !== null && _a !== void 0 ? _a : [],
32
34
  projectDir: this.args.projectDir,
33
35
  extensions: this.args.extensions,
34
- checkLocal: true,
36
+ emulatorMode: true,
35
37
  });
36
38
  }
37
39
  async ensureSourceCode(instance) {
@@ -42,19 +44,30 @@ class ExtensionsEmulator {
42
44
  const cacheDir = process.env.FIREBASE_EXTENSIONS_CACHE_PATH ||
43
45
  path.join(os.homedir(), ".cache", "firebase", "extensions");
44
46
  const sourceCodePath = path.join(cacheDir, ref);
47
+ if (this.pendingDownloads.get(ref)) {
48
+ await this.pendingDownloads.get(ref);
49
+ }
45
50
  if (!this.hasValidSource({ path: sourceCodePath, extRef: ref })) {
46
- const extensionVersion = await planner.getExtensionVersion(instance);
47
- await (0, download_1.downloadExtensionVersion)(ref, extensionVersion.sourceDownloadUri, sourceCodePath);
48
- this.installAndBuildSourceCode(sourceCodePath);
51
+ const promise = this.downloadSource(instance, ref, sourceCodePath);
52
+ this.pendingDownloads.set(ref, promise);
53
+ await promise;
49
54
  }
50
55
  return sourceCodePath;
51
56
  }
57
+ async downloadSource(instance, ref, sourceCodePath) {
58
+ const extensionVersion = await planner.getExtensionVersion(instance);
59
+ await (0, download_1.downloadExtensionVersion)(ref, extensionVersion.sourceDownloadUri, sourceCodePath);
60
+ this.installAndBuildSourceCode(sourceCodePath);
61
+ }
52
62
  hasValidSource(args) {
53
63
  const requiredFiles = [
54
64
  "./extension.yaml",
55
65
  "./functions/package.json",
56
66
  "./functions/node_modules",
57
67
  ];
68
+ if (!fs.existsSync(args.path)) {
69
+ return false;
70
+ }
58
71
  for (const requiredFile of requiredFiles) {
59
72
  const f = path.join(args.path, requiredFile);
60
73
  if (!fs.existsSync(f)) {
@@ -87,12 +100,13 @@ class ExtensionsEmulator {
87
100
  const extensionDir = await this.ensureSourceCode(instance);
88
101
  const functionsDir = path.join(extensionDir, "functions");
89
102
  const env = Object.assign(this.autoPopulatedParams(instance), instance.params);
90
- const { extensionTriggers, nodeMajorVersion } = await (0, optionsHelper_1.getExtensionFunctionInfo)(extensionDir, instance.instanceId, env);
103
+ const { extensionTriggers, nodeMajorVersion, nonSecretEnv, secretEnvVariables } = await (0, optionsHelper_1.getExtensionFunctionInfo)(extensionDir, instance.instanceId, env);
91
104
  const extension = await planner.getExtension(instance);
92
105
  const extensionVersion = await planner.getExtensionVersion(instance);
93
106
  return {
94
107
  functionsDir,
95
- env,
108
+ env: nonSecretEnv,
109
+ secretEnv: secretEnvVariables,
96
110
  predefinedTriggers: extensionTriggers,
97
111
  nodeMajorVersion: nodeMajorVersion,
98
112
  extensionInstanceId: instance.instanceId,
@@ -131,10 +145,34 @@ class ExtensionsEmulator {
131
145
  apiToWarn.enabled ? "" : clc.bold.underline(enablementUri),
132
146
  ]);
133
147
  }
134
- this.logger.logLabeled("WARN", "Extensions", `The following Extensions make calls to Google Cloud APIs that do not have Emulators. ` +
135
- `These calls will go to production Google Cloud APIs which may have real effects on ${this.args.projectId}.\n` +
136
- table.toString());
148
+ if (constants_1.Constants.isDemoProject(this.args.projectId)) {
149
+ this.logger.logLabeled("WARN", "Extensions", "The following Extensions make calls to Google Cloud APIs that do not have Emulators. " +
150
+ `${clc.bold(this.args.projectId)} is a demo project, so these Extensions may not work as expected.\n` +
151
+ table.toString());
152
+ }
153
+ else {
154
+ this.logger.logLabeled("WARN", "Extensions", "The following Extensions make calls to Google Cloud APIs that do not have Emulators. " +
155
+ `These calls will go to production Google Cloud APIs which may have real effects on ${clc.bold(this.args.projectId)}.\n` +
156
+ table.toString());
157
+ }
158
+ }
159
+ }
160
+ filterUnemulatedTriggers(options, backends) {
161
+ let foundUnemulatedTrigger = false;
162
+ const filteredBackends = backends.filter((backend) => {
163
+ const unemulatedServices = (0, validation_1.checkForUnemulatedTriggerTypes)(backend, options);
164
+ if (unemulatedServices.length) {
165
+ foundUnemulatedTrigger = true;
166
+ const msg = ` ignored becuase it includes ${unemulatedServices.join(", ")} triggered functions, and the ${unemulatedServices.join(", ")} emulator does not exist or is not running.`;
167
+ this.logger.logLabeled("WARN", `extensions[${backend.extensionInstanceId}]`, msg);
168
+ }
169
+ return unemulatedServices.length === 0;
170
+ });
171
+ if (foundUnemulatedTrigger) {
172
+ const msg = "No Cloud Functions for these instances will be emulated, because partially emulating an Extension can lead to unexpected behavior. ";
173
+ this.logger.log("WARN", msg);
137
174
  }
175
+ return filteredBackends;
138
176
  }
139
177
  }
140
178
  exports.ExtensionsEmulator = ExtensionsEmulator;
@@ -35,7 +35,6 @@ const runtimes = require("../deploy/functions/runtimes");
35
35
  const backend = require("../deploy/functions/backend");
36
36
  const functionsEnv = require("../functions/env");
37
37
  const EVENT_INVOKE = "functions:invoke";
38
- const LOCAL_SECRETS_FILE = ".secret.local";
39
38
  const DATABASE_PATH_PATTERN = new RegExp("^projects/[^/]+/instances/([^/]+)/refs(/.*)$");
40
39
  class FunctionsEmulator {
41
40
  constructor(args) {
@@ -79,7 +78,6 @@ class FunctionsEmulator {
79
78
  createHubServer() {
80
79
  this.workQueue.start();
81
80
  const hub = express();
82
- hub.use(cors({ origin: true }));
83
81
  const dataMiddleware = (req, res, next) => {
84
82
  const chunks = [];
85
83
  req.on("data", (chunk) => {
@@ -158,7 +156,7 @@ class FunctionsEmulator {
158
156
  const listBackendsHandler = (req, res) => {
159
157
  res.json({ backends: this.getBackendInfo() });
160
158
  };
161
- hub.get(listBackendsRoute, dataMiddleware, listBackendsHandler);
159
+ hub.get(listBackendsRoute, cors({ origin: true }), listBackendsHandler);
162
160
  hub.post(backgroundFunctionRoute, dataMiddleware, backgroundHandler);
163
161
  hub.post(multicastFunctionRoute, dataMiddleware, multicastHandler);
164
162
  hub.all(httpsFunctionRoutes, dataMiddleware, httpsHandler);
@@ -253,7 +251,7 @@ class FunctionsEmulator {
253
251
  }
254
252
  let triggerDefinitions;
255
253
  if (emulatableBackend.predefinedTriggers) {
256
- triggerDefinitions = (0, functionsEmulatorShared_1.emulatedFunctionsByRegion)(emulatableBackend.predefinedTriggers);
254
+ triggerDefinitions = (0, functionsEmulatorShared_1.emulatedFunctionsByRegion)(emulatableBackend.predefinedTriggers, emulatableBackend.secretEnv);
257
255
  }
258
256
  else {
259
257
  const runtimeConfig = this.getRuntimeConfig(emulatableBackend);
@@ -495,9 +493,13 @@ class FunctionsEmulator {
495
493
  .map((t) => t.def);
496
494
  return this.args.emulatableBackends.map((e) => {
497
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
+ }
498
500
  return {
499
501
  directory: e.functionsDir,
500
- env: e.env,
502
+ env: envWithSecrets,
501
503
  extensionInstanceId: e.extensionInstanceId,
502
504
  extension: e.extension,
503
505
  extensionVersion: e.extensionVersion,
@@ -570,6 +572,7 @@ class FunctionsEmulator {
570
572
  const projectInfo = {
571
573
  functionsSource: backend.functionsDir,
572
574
  projectId: this.args.projectId,
575
+ projectAlias: this.args.projectAlias,
573
576
  isEmulator: true,
574
577
  };
575
578
  if (functionsEnv.hasUserEnvs(projectInfo)) {
@@ -650,23 +653,25 @@ class FunctionsEmulator {
650
653
  }
651
654
  async resolveSecretEnvs(backend, trigger) {
652
655
  let secretEnvs = {};
656
+ const secretPath = (0, functionsEmulatorShared_1.getSecretLocalPath)(backend, this.args.projectDir);
653
657
  try {
654
- const data = fs.readFileSync(path.join(backend.functionsDir, LOCAL_SECRETS_FILE), "utf8");
658
+ const data = fs.readFileSync(secretPath, "utf8");
655
659
  secretEnvs = functionsEnv.parseStrict(data);
656
660
  }
657
661
  catch (e) {
658
662
  if (e.code !== "ENOENT") {
659
- 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}`);
660
664
  }
661
665
  }
662
666
  if (trigger) {
663
667
  const secrets = trigger.secretEnvironmentVariables || [];
664
668
  const accesses = secrets
665
- .filter((s) => !secretEnvs[s.secret])
669
+ .filter((s) => !secretEnvs[s.key])
666
670
  .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];
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];
670
675
  });
671
676
  const accessResults = await (0, utils_1.allSettled)(accesses);
672
677
  const errs = [];
@@ -682,7 +687,7 @@ class FunctionsEmulator {
682
687
  if (errs.length > 0) {
683
688
  this.logger.logLabeled("ERROR", "functions", "Unable to access secret environment variables from Google Cloud Secret Manager. " +
684
689
  "Make sure the credential used for the Functions Emulator have access " +
685
- `or provide override values in ${LOCAL_SECRETS_FILE}:\n\t` +
690
+ `or provide override values in ${secretPath}:\n\t` +
686
691
  errs.join("\n\t"));
687
692
  }
688
693
  }
@@ -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,39 @@ 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.isCallableTriggered(endpoint)) {
69
+ def.httpsTrigger = {};
70
+ def.labels = Object.assign(Object.assign({}, def.labels), { "deployment-callable": "true" });
71
+ }
72
+ else if (backend.isEventTriggered(endpoint)) {
67
73
  const eventTrigger = endpoint.eventTrigger;
68
74
  if (endpoint.platform === "gcfv1") {
75
+ const resourceFilter = backend.findEventFilter(endpoint, "resource");
76
+ if (!resourceFilter) {
77
+ logger_1.logger.debug(`Invalid event trigger ${JSON.stringify(endpoint)}, expected event filter with resource attribute. Skipping.`);
78
+ continue;
79
+ }
69
80
  def.eventTrigger = {
70
81
  eventType: eventTrigger.eventType,
71
- resource: eventTrigger.eventFilters.resource,
82
+ resource: resourceFilter.value,
72
83
  };
73
84
  }
74
85
  else {
75
- const { resource, topic, bucket } = endpoint.eventTrigger.eventFilters;
76
- const eventResource = resource || topic || bucket;
77
- if (!eventResource) {
86
+ const [eventFilter] = endpoint.eventTrigger.eventFilters;
87
+ if (!eventFilter) {
88
+ logger_1.logger.debug(`Invalid event trigger ${JSON.stringify(endpoint)}, expected at least one event filter. Skipping.`);
78
89
  continue;
79
90
  }
80
91
  def.eventTrigger = {
81
92
  eventType: eventTrigger.eventType,
82
- resource: eventResource,
93
+ resource: eventFilter.value,
83
94
  };
84
95
  }
85
96
  }
86
- else if ((0, backend_1.isScheduleTriggered)(endpoint)) {
97
+ else if (backend.isScheduleTriggered(endpoint)) {
87
98
  def.eventTrigger = { eventType: "pubsub", resource: "" };
88
99
  def.schedule = endpoint.scheduleTrigger;
89
100
  }
@@ -94,7 +105,7 @@ function emulatedFunctionsFromEndpoints(endpoints) {
94
105
  return regionDefinitions;
95
106
  }
96
107
  exports.emulatedFunctionsFromEndpoints = emulatedFunctionsFromEndpoints;
97
- function emulatedFunctionsByRegion(definitions) {
108
+ function emulatedFunctionsByRegion(definitions, secretEnvVariables = []) {
98
109
  const regionDefinitions = [];
99
110
  for (const def of definitions) {
100
111
  if (!def.regions) {
@@ -106,6 +117,7 @@ function emulatedFunctionsByRegion(definitions) {
106
117
  defDeepCopy.region = region;
107
118
  defDeepCopy.id = `${region}-${defDeepCopy.name}`;
108
119
  defDeepCopy.platform = defDeepCopy.platform || "gcfv1";
120
+ defDeepCopy.secretEnvironmentVariables = secretEnvVariables;
109
121
  regionDefinitions.push(defDeepCopy);
110
122
  }
111
123
  }
@@ -219,3 +231,14 @@ function getSignatureType(def) {
219
231
  return def.platform === "gcfv2" ? "cloudevent" : "event";
220
232
  }
221
233
  exports.getSignatureType = getSignatureType;
234
+ const LOCAL_SECRETS_FILE = ".secret.local";
235
+ function getSecretLocalPath(backend, projectDir) {
236
+ const secretsFile = backend.extensionInstanceId
237
+ ? `${backend.extensionInstanceId}${LOCAL_SECRETS_FILE}`
238
+ : LOCAL_SECRETS_FILE;
239
+ const secretDirectory = backend.extensionInstanceId
240
+ ? path.join(projectDir, manifest_1.ENV_DIRECTORY)
241
+ : backend.functionsDir;
242
+ return path.join(secretDirectory, secretsFile);
243
+ }
244
+ exports.getSecretLocalPath = getSecretLocalPath;