firebase-tools 13.20.2 → 13.21.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 (35) hide show
  1. package/lib/apphosting/githubConnections.js +19 -1
  2. package/lib/apphosting/index.js +12 -46
  3. package/lib/apphosting/rollout.js +127 -0
  4. package/lib/command.js +10 -3
  5. package/lib/commands/apphosting-rollouts-create.js +13 -13
  6. package/lib/commands/emulators-start.js +1 -1
  7. package/lib/config.js +14 -4
  8. package/lib/dataconnect/fileUtils.js +7 -43
  9. package/lib/dataconnect/freeTrial.js +44 -10
  10. package/lib/dataconnect/provisionCloudSql.js +4 -4
  11. package/lib/dataconnect/types.js +3 -2
  12. package/lib/dataconnect/webhook.js +2 -1
  13. package/lib/deploy/dataconnect/prepare.js +5 -0
  14. package/lib/emulator/apphosting/config.js +45 -0
  15. package/lib/emulator/apphosting/index.js +9 -11
  16. package/lib/emulator/apphosting/serve.js +16 -10
  17. package/lib/emulator/apphosting/utils.js +18 -0
  18. package/lib/emulator/controller.js +6 -1
  19. package/lib/emulator/downloadableEmulators.js +12 -12
  20. package/lib/emulator/eventarcEmulator.js +1 -1
  21. package/lib/emulator/extensionsEmulator.js +38 -6
  22. package/lib/emulator/functionsEmulator.js +85 -41
  23. package/lib/emulator/functionsEmulatorShared.js +2 -1
  24. package/lib/error.js +24 -1
  25. package/lib/extensions/emulator/triggerHelper.js +1 -1
  26. package/lib/extensions/extensionsApi.js +11 -8
  27. package/lib/extensions/runtimes/common.js +11 -19
  28. package/lib/extensions/runtimes/node.js +25 -22
  29. package/lib/extensions/types.js +16 -1
  30. package/lib/gcp/cloudmonitoring.js +3 -3
  31. package/lib/gcp/devConnect.js +38 -1
  32. package/lib/init/features/dataconnect/index.js +69 -85
  33. package/lib/init/features/dataconnect/sdk.js +69 -86
  34. package/lib/init/spawn.js +2 -1
  35. package/package.json +1 -1
@@ -1,34 +1,32 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.AppHostingEmulator = void 0;
4
- const emulatorLogger_1 = require("../emulatorLogger");
5
4
  const types_1 = require("../types");
6
5
  const serve_1 = require("./serve");
6
+ const utils_1 = require("./utils");
7
7
  class AppHostingEmulator {
8
8
  constructor(args) {
9
9
  this.args = args;
10
- this.logger = emulatorLogger_1.EmulatorLogger.forEmulator(types_1.Emulators.APPHOSTING);
11
10
  }
12
11
  async start() {
13
- this.args.options.host = this.args.host;
14
- this.args.options.port = this.args.port;
15
- this.logger.logLabeled("INFO", types_1.Emulators.APPHOSTING, "starting apphosting emulator");
16
- const { port } = await (0, serve_1.start)(this.args.options);
17
- this.logger.logLabeled("INFO", types_1.Emulators.APPHOSTING, `serving on port ${port}`);
12
+ utils_1.logger.logLabeled("INFO", types_1.Emulators.APPHOSTING, "starting apphosting emulator");
13
+ const { hostname, port } = await (0, serve_1.start)();
14
+ this.args.options.host = hostname;
15
+ this.args.options.port = port;
18
16
  }
19
17
  connect() {
20
- this.logger.logLabeled("INFO", types_1.Emulators.APPHOSTING, "connecting apphosting emulator");
18
+ utils_1.logger.logLabeled("INFO", types_1.Emulators.APPHOSTING, "connecting apphosting emulator");
21
19
  return Promise.resolve();
22
20
  }
23
21
  stop() {
24
- this.logger.logLabeled("INFO", types_1.Emulators.APPHOSTING, "stopping apphosting emulator");
22
+ utils_1.logger.logLabeled("INFO", types_1.Emulators.APPHOSTING, "stopping apphosting emulator");
25
23
  return Promise.resolve();
26
24
  }
27
25
  getInfo() {
28
26
  return {
29
27
  name: types_1.Emulators.APPHOSTING,
30
- host: this.args.host,
31
- port: this.args.port,
28
+ host: this.args.options.host,
29
+ port: this.args.options.port,
32
30
  };
33
31
  }
34
32
  getName() {
@@ -1,18 +1,28 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.serve = exports.start = void 0;
3
+ exports.start = void 0;
4
4
  const net_1 = require("net");
5
5
  const portUtils_1 = require("../portUtils");
6
+ const utils_1 = require("./utils");
7
+ const constants_1 = require("../constants");
6
8
  const spawn_1 = require("../../init/spawn");
7
- async function start(options) {
8
- let port = options.port;
9
- while (!(await availablePort(options.host, port))) {
9
+ const config_1 = require("./config");
10
+ async function start() {
11
+ const hostname = constants_1.DEFAULT_HOST;
12
+ let port = constants_1.DEFAULT_PORTS.apphosting;
13
+ while (!(await availablePort(hostname, port))) {
10
14
  port += 1;
11
15
  }
12
- serve(options, port);
13
- return { port };
16
+ serve(port);
17
+ return { hostname, port };
14
18
  }
15
19
  exports.start = start;
20
+ async function serve(port) {
21
+ const rootDir = process.cwd();
22
+ const packageManager = await (0, utils_1.discoverPackageManager)(rootDir);
23
+ const apphostingLocalConfig = await (0, config_1.getLocalAppHostingConfiguration)(rootDir);
24
+ await (0, spawn_1.wrapSpawn)(packageManager, ["run", "dev"], rootDir, Object.assign(Object.assign({}, apphostingLocalConfig.environmentVariables), { PORT: port }));
25
+ }
16
26
  function availablePort(host, port) {
17
27
  return (0, portUtils_1.checkListenable)({
18
28
  address: host,
@@ -20,7 +30,3 @@ function availablePort(host, port) {
20
30
  family: (0, net_1.isIPv4)(host) ? "IPv4" : "IPv6",
21
31
  });
22
32
  }
23
- async function serve(options, port) {
24
- await (0, spawn_1.wrapSpawn)("npm", ["run", "dev", "--", "-H", options.host, "-p", port], process.cwd());
25
- }
26
- exports.serve = serve;
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.discoverPackageManager = exports.logger = void 0;
4
+ const fs_extra_1 = require("fs-extra");
5
+ const path_1 = require("path");
6
+ const emulatorLogger_1 = require("../emulatorLogger");
7
+ const types_1 = require("../types");
8
+ exports.logger = emulatorLogger_1.EmulatorLogger.forEmulator(types_1.Emulators.APPHOSTING);
9
+ async function discoverPackageManager(rootdir) {
10
+ if (await (0, fs_extra_1.pathExists)((0, path_1.join)(rootdir, "pnpm-lock.yaml"))) {
11
+ return "pnpm";
12
+ }
13
+ if (await (0, fs_extra_1.pathExists)((0, path_1.join)(rootdir, "yarn.lock"))) {
14
+ return "yarn";
15
+ }
16
+ return "npm";
17
+ }
18
+ exports.discoverPackageManager = discoverPackageManager;
@@ -79,6 +79,9 @@ function filterEmulatorTargets(options) {
79
79
  targets = targets.filter((e) => {
80
80
  return options.config.has(e) || options.config.has(`emulators.${e}`);
81
81
  });
82
+ if (targets.includes(types_1.Emulators.FUNCTIONS) && !targets.includes(types_1.Emulators.EXTENSIONS)) {
83
+ targets.push(types_1.Emulators.EXTENSIONS);
84
+ }
82
85
  const onlyOptions = options.only;
83
86
  if (onlyOptions) {
84
87
  const only = onlyOptions.split(",").map((o) => {
@@ -210,6 +213,7 @@ async function startAll(options, showUI = true, runningTestScript = false) {
210
213
  : await (0, projectUtils_1.needProjectNumber)(options);
211
214
  const aliases = (0, projectUtils_1.getAliases)(options, projectId);
212
215
  extensionEmulator = new extensionsEmulator_1.ExtensionsEmulator({
216
+ options,
213
217
  projectId,
214
218
  projectDir: options.config.projectDir,
215
219
  projectNumber,
@@ -217,7 +221,7 @@ async function startAll(options, showUI = true, runningTestScript = false) {
217
221
  extensions: options.config.get("extensions"),
218
222
  });
219
223
  const extensionsBackends = await extensionEmulator.getExtensionBackends();
220
- const filteredExtensionsBackends = extensionEmulator.filterUnemulatedTriggers(options, extensionsBackends);
224
+ const filteredExtensionsBackends = extensionEmulator.filterUnemulatedTriggers(extensionsBackends);
221
225
  emulatableBackends.push(...filteredExtensionsBackends);
222
226
  (0, track_1.trackGA4)("extensions_emulated", {
223
227
  number_of_extensions_emulated: filteredExtensionsBackends.length,
@@ -374,6 +378,7 @@ async function startAll(options, showUI = true, runningTestScript = false) {
374
378
  debugPort: inspectFunctions,
375
379
  verbosity: options.logVerbosity,
376
380
  projectAlias: options.projectAlias,
381
+ extensionsEmulator: extensionEmulator,
377
382
  });
378
383
  await startEmulator(functionsEmulator);
379
384
  const eventarcAddr = legacyGetFirstAddr(types_1.Emulators.EVENTARC);
@@ -37,9 +37,9 @@ const EMULATOR_UPDATE_DETAILS = {
37
37
  ui: experiments.isEnabled("emulatoruisnapshot")
38
38
  ? { version: "SNAPSHOT", expectedSize: -1, expectedChecksum: "" }
39
39
  : {
40
- version: "1.13.0",
41
- expectedSize: 3605485,
42
- expectedChecksum: "ec0aa91592c56af9ff7df18168d58459",
40
+ version: "1.14.0",
41
+ expectedSize: 3615311,
42
+ expectedChecksum: "30763ff4a8b81e2c482f05b56799b5c0",
43
43
  },
44
44
  pubsub: {
45
45
  version: "0.8.14",
@@ -48,20 +48,20 @@ const EMULATOR_UPDATE_DETAILS = {
48
48
  },
49
49
  dataconnect: process.platform === "darwin"
50
50
  ? {
51
- version: "1.4.4",
52
- expectedSize: 25142016,
53
- expectedChecksum: "9b071275feaba21e04bbb0db842f945d",
51
+ version: "1.5.0",
52
+ expectedSize: 25215744,
53
+ expectedChecksum: "670ad771cf36b07c52a71f580df89994",
54
54
  }
55
55
  : process.platform === "win32"
56
56
  ? {
57
- version: "1.4.4",
58
- expectedSize: 25567744,
59
- expectedChecksum: "d23bf88b04a09d666ae927a107317611",
57
+ version: "1.5.0",
58
+ expectedSize: 25643520,
59
+ expectedChecksum: "b565e4609f08eb2299b7bec7e0cac0dc",
60
60
  }
61
61
  : {
62
- version: "1.4.4",
63
- expectedSize: 25055384,
64
- expectedChecksum: "9c04a6c4738088305eb1a7b2a5d34df4",
62
+ version: "1.5.0",
63
+ expectedSize: 25129112,
64
+ expectedChecksum: "9a08671b89f557d096c075f6a5ac87db",
65
65
  },
66
66
  };
67
67
  exports.DownloadDetails = {
@@ -53,7 +53,7 @@ class EventarcEmulator {
53
53
  const key = `${eventTrigger.eventType}-${channel}`;
54
54
  return { projectId, triggerName, eventTrigger, key };
55
55
  };
56
- const removeTriggerRoute = `/emulator/v1/remove/projects/:project_id/triggers/:trigger_name`;
56
+ const removeTriggerRoute = `/emulator/v1/remove/projects/:project_id/triggers/:trigger_name(*)`;
57
57
  const removeTriggerHandler = (req, res) => {
58
58
  try {
59
59
  const { projectId, triggerName, eventTrigger, key } = getTriggerIdentifiers(req);
@@ -19,10 +19,14 @@ const emulatorLogger_1 = require("./emulatorLogger");
19
19
  const validation_1 = require("./extensions/validation");
20
20
  const registry_1 = require("./registry");
21
21
  const types_1 = require("./types");
22
+ const common_1 = require("../extensions/runtimes/common");
22
23
  class ExtensionsEmulator {
23
24
  constructor(args) {
24
25
  this.want = [];
26
+ this.wantDynamic = {};
25
27
  this.backends = [];
28
+ this.staticBackends = [];
29
+ this.dynamicBackends = {};
26
30
  this.logger = emulatorLogger_1.EmulatorLogger.forEmulator(types_1.Emulators.EXTENSIONS);
27
31
  this.pendingDownloads = new Map();
28
32
  this.args = args;
@@ -128,12 +132,40 @@ class ExtensionsEmulator {
128
132
  this.logger.logLabeled("DEBUG", "Extensions", `Finished "npm run gcp-build" for ${sourceCodePath}`);
129
133
  }
130
134
  async getExtensionBackends() {
135
+ this.backends = await this.getStaticExtensionBackends();
136
+ for (const backends of Object.values(this.dynamicBackends)) {
137
+ this.backends.push(...backends);
138
+ }
139
+ return this.backends;
140
+ }
141
+ async getStaticExtensionBackends() {
131
142
  await this.readManifest();
132
143
  await this.checkAndWarnAPIs(this.want);
133
- this.backends = await Promise.all(this.want.map((i) => {
144
+ this.staticBackends = await Promise.all(this.want.map((i) => {
134
145
  return this.toEmulatableBackend(i);
135
146
  }));
136
- return this.backends;
147
+ return this.staticBackends;
148
+ }
149
+ getDynamicExtensionBackends() {
150
+ const dynamicBackends = [];
151
+ for (const backends of Object.values(this.dynamicBackends)) {
152
+ dynamicBackends.push(...backends);
153
+ }
154
+ return dynamicBackends;
155
+ }
156
+ async addDynamicExtensions(codebase, build) {
157
+ const extensions = (0, common_1.extractExtensionsFromBuilds)({ build });
158
+ this.wantDynamic[codebase] = await planner.wantDynamic({
159
+ projectId: this.args.projectId,
160
+ projectNumber: this.args.projectNumber,
161
+ extensions,
162
+ emulatorMode: true,
163
+ });
164
+ await this.checkAndWarnAPIs(this.wantDynamic[codebase]);
165
+ this.dynamicBackends[codebase] = await Promise.all(this.wantDynamic[codebase].map((i) => {
166
+ return this.toEmulatableBackend(i);
167
+ }));
168
+ await this.getExtensionBackends();
137
169
  }
138
170
  async toEmulatableBackend(instance) {
139
171
  const extensionDir = await this.ensureSourceCode(instance);
@@ -206,10 +238,10 @@ class ExtensionsEmulator {
206
238
  }
207
239
  }
208
240
  }
209
- filterUnemulatedTriggers(options, backends) {
241
+ filterUnemulatedTriggers(backends) {
210
242
  let foundUnemulatedTrigger = false;
211
243
  const filteredBackends = backends.filter((backend) => {
212
- const unemulatedServices = (0, validation_1.checkForUnemulatedTriggerTypes)(backend, options);
244
+ const unemulatedServices = (0, validation_1.checkForUnemulatedTriggerTypes)(backend, this.args.options);
213
245
  if (unemulatedServices.length) {
214
246
  foundUnemulatedTrigger = true;
215
247
  const msg = ` ignored becuase it includes ${unemulatedServices.join(", ")} triggered functions, and the ${unemulatedServices.join(", ")} emulator does not exist or is not running.`;
@@ -231,9 +263,9 @@ class ExtensionsEmulator {
231
263
  uiUrl.pathname = `/${types_1.Emulators.EXTENSIONS}/${backend.extensionInstanceId}`;
232
264
  return clc.underline(clc.bold(uiUrl.toString()));
233
265
  }
234
- extensionsInfoTable(options) {
266
+ extensionsInfoTable() {
235
267
  var _a;
236
- const filtedBackends = this.filterUnemulatedTriggers(options, this.backends);
268
+ const filtedBackends = this.filterUnemulatedTriggers(this.backends);
237
269
  const uiRunning = registry_1.EmulatorRegistry.isRunning(types_1.Emulators.UI);
238
270
  const tableHead = ["Extension Instance Name", "Extension Ref"];
239
271
  if (uiRunning) {
@@ -81,10 +81,13 @@ class FunctionsEmulator {
81
81
  this.logger = emulatorLogger_1.EmulatorLogger.forEmulator(types_1.Emulators.FUNCTIONS);
82
82
  this.multicastTriggers = {};
83
83
  this.blockingFunctionsConfig = {};
84
+ this.staticBackends = [];
85
+ this.dynamicBackends = [];
84
86
  this.debugMode = false;
87
+ this.staticBackends = args.emulatableBackends;
85
88
  emulatorLogger_1.EmulatorLogger.setVerbosity(this.args.verbosity ? emulatorLogger_1.Verbosity[this.args.verbosity] : emulatorLogger_1.Verbosity["DEBUG"]);
86
89
  if (this.args.debugPort) {
87
- const maybeNodeCodebases = this.args.emulatableBackends.filter((b) => !b.runtime || b.runtime.startsWith("node"));
90
+ const maybeNodeCodebases = this.staticBackends.filter((b) => !b.runtime || b.runtime.startsWith("node"));
88
91
  if (maybeNodeCodebases.length > 1 && typeof this.args.debugPort === "number") {
89
92
  throw new error_1.FirebaseError("Cannot debug on a single port with multiple codebases. " +
90
93
  "Use --inspect-functions=true to assign dynamic ports to each codebase");
@@ -96,12 +99,37 @@ class FunctionsEmulator {
96
99
  this.adminSdkConfig = Object.assign(Object.assign({}, this.args.adminSdkConfig), { projectId: this.args.projectId });
97
100
  const mode = this.debugMode ? types_1.FunctionsExecutionMode.SEQUENTIAL : types_1.FunctionsExecutionMode.AUTO;
98
101
  this.workerPools = {};
99
- for (const backend of this.args.emulatableBackends) {
102
+ for (const backend of this.staticBackends) {
100
103
  const pool = new functionsRuntimeWorker_1.RuntimeWorkerPool(mode);
101
104
  this.workerPools[backend.codebase] = pool;
102
105
  }
103
106
  this.workQueue = new workQueue_1.WorkQueue(mode);
104
107
  }
108
+ async loadDynamicExtensionBackends() {
109
+ if (this.args.extensionsEmulator) {
110
+ const unfilteredBackends = this.args.extensionsEmulator.getDynamicExtensionBackends();
111
+ this.dynamicBackends =
112
+ this.args.extensionsEmulator.filterUnemulatedTriggers(unfilteredBackends);
113
+ const mode = this.debugMode ? types_1.FunctionsExecutionMode.SEQUENTIAL : types_1.FunctionsExecutionMode.AUTO;
114
+ const credentialEnv = await this.getCredentialsEnvironment();
115
+ for (const backend of this.dynamicBackends) {
116
+ backend.env = Object.assign(Object.assign({}, credentialEnv), backend.env);
117
+ if (this.workerPools[backend.codebase]) {
118
+ if (this.debugMode) {
119
+ this.workerPools[backend.codebase].exit();
120
+ }
121
+ else {
122
+ this.workerPools[backend.codebase].refresh();
123
+ }
124
+ }
125
+ else {
126
+ const pool = new functionsRuntimeWorker_1.RuntimeWorkerPool(mode);
127
+ this.workerPools[backend.codebase] = pool;
128
+ }
129
+ await this.loadTriggers(backend, true);
130
+ }
131
+ }
132
+ }
105
133
  async getCredentialsEnvironment() {
106
134
  const credentialEnv = {};
107
135
  if (process.env.GOOGLE_APPLICATION_CREDENTIALS) {
@@ -228,7 +256,7 @@ class FunctionsEmulator {
228
256
  }
229
257
  async start() {
230
258
  const credentialEnv = await this.getCredentialsEnvironment();
231
- for (const e of this.args.emulatableBackends) {
259
+ for (const e of this.staticBackends) {
232
260
  e.env = Object.assign(Object.assign({}, credentialEnv), e.env);
233
261
  }
234
262
  if (Object.keys(this.adminSdkConfig || {}).length <= 1) {
@@ -249,7 +277,7 @@ class FunctionsEmulator {
249
277
  }
250
278
  async connect() {
251
279
  var _a, _b;
252
- for (const backend of this.args.emulatableBackends) {
280
+ for (const backend of this.staticBackends) {
253
281
  this.logger.logLabeled("BULLET", "functions", `Watching "${backend.functionsDir}" for Cloud Functions...`);
254
282
  const watcher = chokidar.watch(backend.functionsDir, {
255
283
  ignored: [
@@ -315,6 +343,10 @@ class FunctionsEmulator {
315
343
  };
316
344
  const userEnvs = functionsEnv.loadUserEnvs(userEnvOpt);
317
345
  const discoveredBuild = await runtimeDelegate.discoverBuild(runtimeConfig, environment);
346
+ if (discoveredBuild.extensions && this.args.extensionsEmulator) {
347
+ await this.args.extensionsEmulator.addDynamicExtensions(emulatableBackend.codebase, discoveredBuild);
348
+ await this.loadDynamicExtensionBackends();
349
+ }
318
350
  const resolution = await (0, build_1.resolveBackend)({
319
351
  build: discoveredBuild,
320
352
  firebaseConfig: JSON.parse(firebaseConfig),
@@ -353,6 +385,9 @@ class FunctionsEmulator {
353
385
  }
354
386
  const toRemove = Object.keys(this.triggers).filter((recordKey) => {
355
387
  const record = this.getTriggerRecordByKey(recordKey);
388
+ if (record.backend.codebase !== emulatableBackend.codebase) {
389
+ return false;
390
+ }
356
391
  if (force) {
357
392
  return true;
358
393
  }
@@ -430,17 +465,17 @@ class FunctionsEmulator {
430
465
  }
431
466
  const ignored = !added;
432
467
  this.addTriggerRecord(definition, { backend: emulatableBackend, ignored, url });
433
- const type = definition.httpsTrigger
468
+ const triggerType = definition.httpsTrigger
434
469
  ? "http"
435
470
  : constants_1.Constants.getServiceName((0, functionsEmulatorShared_1.getFunctionService)(definition));
436
471
  if (ignored) {
437
- const msg = `function ignored because the ${type} emulator does not exist or is not running.`;
472
+ const msg = `function ignored because the ${triggerType} emulator does not exist or is not running.`;
438
473
  this.logger.logLabeled("BULLET", `functions[${definition.id}]`, msg);
439
474
  }
440
475
  else {
441
476
  const msg = url
442
- ? `${clc.bold(type)} function initialized (${url}).`
443
- : `${clc.bold(type)} function initialized.`;
477
+ ? `${clc.bold(triggerType)} function initialized (${url}).`
478
+ : `${clc.bold(triggerType)} function initialized.`;
444
479
  this.logger.logLabeled("SUCCESS", `functions[${definition.id}]`, msg);
445
480
  }
446
481
  }
@@ -483,23 +518,24 @@ class FunctionsEmulator {
483
518
  }
484
519
  }
485
520
  }
486
- addEventarcTrigger(projectId, key, eventTrigger) {
521
+ async addEventarcTrigger(projectId, key, eventTrigger) {
487
522
  if (!registry_1.EmulatorRegistry.isRunning(types_1.Emulators.EVENTARC)) {
488
- return Promise.resolve(false);
523
+ return false;
489
524
  }
490
525
  const bundle = {
491
526
  eventTrigger: Object.assign(Object.assign({}, eventTrigger), { service: "eventarc.googleapis.com" }),
492
527
  };
493
528
  logger_1.logger.debug(`addEventarcTrigger`, JSON.stringify(bundle));
494
- return registry_1.EmulatorRegistry.client(types_1.Emulators.EVENTARC)
495
- .post(`/emulator/v1/projects/${projectId}/triggers/${key}`, bundle)
496
- .then(() => true)
497
- .catch((err) => {
529
+ try {
530
+ await registry_1.EmulatorRegistry.client(types_1.Emulators.EVENTARC).post(`/emulator/v1/projects/${projectId}/triggers/${key}`, bundle);
531
+ return true;
532
+ }
533
+ catch (err) {
498
534
  this.logger.log("WARN", "Error adding Eventarc function: " + err);
499
- return false;
500
- });
535
+ }
536
+ return false;
501
537
  }
502
- removeEventarcTrigger(projectId, key, eventTrigger) {
538
+ async removeEventarcTrigger(projectId, key, eventTrigger) {
503
539
  if (!registry_1.EmulatorRegistry.isRunning(types_1.Emulators.EVENTARC)) {
504
540
  return Promise.resolve(false);
505
541
  }
@@ -507,45 +543,48 @@ class FunctionsEmulator {
507
543
  eventTrigger: Object.assign(Object.assign({}, eventTrigger), { service: "eventarc.googleapis.com" }),
508
544
  };
509
545
  logger_1.logger.debug(`removeEventarcTrigger`, JSON.stringify(bundle));
510
- return registry_1.EmulatorRegistry.client(types_1.Emulators.EVENTARC)
511
- .post(`/emulator/v1/remove/projects/${projectId}/triggers/${key}`, bundle)
512
- .then(() => true)
513
- .catch((err) => {
546
+ try {
547
+ await registry_1.EmulatorRegistry.client(types_1.Emulators.EVENTARC).post(`/emulator/v1/remove/projects/${projectId}/triggers/${key}`, bundle);
548
+ return true;
549
+ }
550
+ catch (err) {
514
551
  this.logger.log("WARN", "Error removing Eventarc function: " + err);
515
- return false;
516
- });
552
+ }
553
+ return false;
517
554
  }
518
- addFirealertsTrigger(projectId, key, eventTrigger) {
555
+ async addFirealertsTrigger(projectId, key, eventTrigger) {
519
556
  if (!registry_1.EmulatorRegistry.isRunning(types_1.Emulators.EVENTARC)) {
520
- return Promise.resolve(false);
557
+ return false;
521
558
  }
522
559
  const bundle = {
523
560
  eventTrigger: Object.assign(Object.assign({}, eventTrigger), { service: "firebasealerts.googleapis.com" }),
524
561
  };
525
562
  logger_1.logger.debug(`addFirealertsTrigger`, JSON.stringify(bundle));
526
- return registry_1.EmulatorRegistry.client(types_1.Emulators.EVENTARC)
527
- .post(`/emulator/v1/projects/${projectId}/triggers/${key}`, bundle)
528
- .then(() => true)
529
- .catch((err) => {
563
+ try {
564
+ await registry_1.EmulatorRegistry.client(types_1.Emulators.EVENTARC).post(`/emulator/v1/projects/${projectId}/triggers/${key}`, bundle);
565
+ return true;
566
+ }
567
+ catch (err) {
530
568
  this.logger.log("WARN", "Error adding FireAlerts function: " + err);
531
- return false;
532
- });
569
+ }
570
+ return false;
533
571
  }
534
- removeFirealertsTrigger(projectId, key, eventTrigger) {
572
+ async removeFirealertsTrigger(projectId, key, eventTrigger) {
535
573
  if (!registry_1.EmulatorRegistry.isRunning(types_1.Emulators.EVENTARC)) {
536
- return Promise.resolve(false);
574
+ return false;
537
575
  }
538
576
  const bundle = {
539
577
  eventTrigger: Object.assign(Object.assign({}, eventTrigger), { service: "firebasealerts.googleapis.com" }),
540
578
  };
541
579
  logger_1.logger.debug(`removeFirealertsTrigger`, JSON.stringify(bundle));
542
- return registry_1.EmulatorRegistry.client(types_1.Emulators.EVENTARC)
543
- .post(`/emulator/v1/remove/projects/${projectId}/triggers/${key}`, bundle)
544
- .then(() => true)
545
- .catch((err) => {
580
+ try {
581
+ await registry_1.EmulatorRegistry.client(types_1.Emulators.EVENTARC).post(`/emulator/v1/remove/projects/${projectId}/triggers/${key}`, bundle);
582
+ return true;
583
+ }
584
+ catch (err) {
546
585
  this.logger.log("WARN", "Error removing FireAlerts function: " + err);
547
- return false;
548
- });
586
+ }
587
+ return false;
549
588
  }
550
589
  async performPostLoadOperations() {
551
590
  if (!this.blockingFunctionsConfig.triggers &&
@@ -809,9 +848,14 @@ class FunctionsEmulator {
809
848
  }
810
849
  getBackendInfo() {
811
850
  const cf3Triggers = this.getCF3Triggers();
812
- return this.args.emulatableBackends.map((e) => {
851
+ const backendInfo = this.staticBackends.map((e) => {
813
852
  return (0, functionsEmulatorShared_1.toBackendInfo)(e, cf3Triggers);
814
853
  });
854
+ const dynamicInfo = this.dynamicBackends.map((e) => {
855
+ return (0, functionsEmulatorShared_1.toBackendInfo)(e, cf3Triggers, { createdBy: "SDK" });
856
+ });
857
+ backendInfo.push(...dynamicInfo);
858
+ return backendInfo;
815
859
  }
816
860
  getCF3Triggers() {
817
861
  return Object.values(this.triggers)
@@ -1049,7 +1093,7 @@ class FunctionsEmulator {
1049
1093
  async reloadTriggers() {
1050
1094
  this.triggerGeneration++;
1051
1095
  this.blockingFunctionsConfig = {};
1052
- for (const backend of this.args.emulatableBackends) {
1096
+ for (const backend of this.staticBackends.concat(this.dynamicBackends)) {
1053
1097
  await this.loadTriggers(backend);
1054
1098
  }
1055
1099
  await this.performPostLoadOperations();
@@ -310,7 +310,7 @@ function getSecretLocalPath(backend, projectDir) {
310
310
  return path.join(secretDirectory, secretsFile);
311
311
  }
312
312
  exports.getSecretLocalPath = getSecretLocalPath;
313
- function toBackendInfo(e, cf3Triggers) {
313
+ function toBackendInfo(e, cf3Triggers, labels) {
314
314
  var _a, _b;
315
315
  const envWithSecrets = Object.assign({}, e.env);
316
316
  for (const s of e.secretEnv) {
@@ -337,6 +337,7 @@ function toBackendInfo(e, cf3Triggers) {
337
337
  extension: e.extension,
338
338
  extensionVersion: extensionVersion,
339
339
  extensionSpec: extensionSpec,
340
+ labels,
340
341
  functionTriggers: (_b = e.predefinedTriggers) !== null && _b !== void 0 ? _b : cf3Triggers.filter((t) => t.codebase === e.codebase),
341
342
  }));
342
343
  }
package/lib/error.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.isBillingError = exports.FirebaseError = void 0;
3
+ exports.isBillingError = exports.getErrStatus = exports.getErrMsg = exports.FirebaseError = void 0;
4
4
  const lodash_1 = require("lodash");
5
5
  const DEFAULT_CHILDREN = [];
6
6
  const DEFAULT_EXIT = 1;
@@ -18,6 +18,29 @@ class FirebaseError extends Error {
18
18
  }
19
19
  }
20
20
  exports.FirebaseError = FirebaseError;
21
+ function getErrMsg(err, defaultMsg) {
22
+ if (err instanceof Error) {
23
+ return err.message;
24
+ }
25
+ else if (typeof err === "string") {
26
+ return err;
27
+ }
28
+ else if (defaultMsg) {
29
+ return defaultMsg;
30
+ }
31
+ return JSON.stringify(err);
32
+ }
33
+ exports.getErrMsg = getErrMsg;
34
+ function isObject(value) {
35
+ return typeof value === "object" && value !== null;
36
+ }
37
+ function getErrStatus(err, defaultStatus) {
38
+ if (isObject(err) && err.status && typeof err.status === "number") {
39
+ return err.status;
40
+ }
41
+ return defaultStatus || DEFAULT_STATUS;
42
+ }
43
+ exports.getErrStatus = getErrStatus;
21
44
  function isBillingError(e) {
22
45
  var _a, _b, _c, _d;
23
46
  return !!((_d = (_c = (_b = (_a = e.context) === null || _a === void 0 ? void 0 : _a.body) === null || _b === void 0 ? void 0 : _b.error) === null || _c === void 0 ? void 0 : _c.details) === null || _d === void 0 ? void 0 : _d.find((d) => {
@@ -58,7 +58,7 @@ function functionResourceToEmulatedTriggerDefintion(resource, systemParams = {})
58
58
  };
59
59
  }
60
60
  else {
61
- emulatorLogger_1.EmulatorLogger.forEmulator(types_1.Emulators.FUNCTIONS).log("WARN", `Function '${resource.name} is missing a trigger in extension.yaml. Please add one, as triggers defined in code are ignored.`);
61
+ emulatorLogger_1.EmulatorLogger.forEmulator(types_1.Emulators.FUNCTIONS).log("WARN", `Function '${resource.name}' is missing a trigger in extension.yaml. Please add one, as triggers defined in code are ignored.`);
62
62
  }
63
63
  return etd;
64
64
  }
@@ -9,6 +9,7 @@ const error_1 = require("../error");
9
9
  const logger_1 = require("../logger");
10
10
  const operationPoller = require("../operation-poller");
11
11
  const refs = require("./refs");
12
+ const types_1 = require("./types");
12
13
  const EXTENSIONS_API_VERSION = "v1beta";
13
14
  const PAGE_SIZE_MAX = 100;
14
15
  const extensionsApiClient = new apiv2_1.Client({
@@ -81,10 +82,12 @@ exports.deleteInstance = deleteInstance;
81
82
  async function getInstance(projectId, instanceId) {
82
83
  try {
83
84
  const res = await extensionsApiClient.get(`/projects/${projectId}/instances/${instanceId}`);
84
- return res.body;
85
+ if ((0, types_1.isExtensionInstance)(res.body)) {
86
+ return res.body;
87
+ }
85
88
  }
86
89
  catch (err) {
87
- if (err.status === 404) {
90
+ if ((0, error_1.getErrStatus)(err) === 404) {
88
91
  throw new error_1.FirebaseError(`Extension instance '${clc.bold(instanceId)}' not found in project '${clc.bold(projectId)}'.`, { status: 404 });
89
92
  }
90
93
  throw err;
@@ -235,7 +238,7 @@ function populateSpec(spec) {
235
238
  }
236
239
  }
237
240
  catch (err) {
238
- logger_1.logger.debug(`[ext] failed to parse resource properties yaml: ${err}`);
241
+ logger_1.logger.debug(`[ext] failed to parse resource properties yaml: ${(0, error_1.getErrMsg)(err)}`);
239
242
  }
240
243
  }
241
244
  spec.params = (_a = spec.params) !== null && _a !== void 0 ? _a : [];
@@ -281,13 +284,13 @@ async function getExtensionVersion(extensionVersionRef) {
281
284
  return res.body;
282
285
  }
283
286
  catch (err) {
284
- if (err.status === 404) {
287
+ if ((0, error_1.getErrStatus)(err) === 404) {
285
288
  throw refNotFoundError(ref);
286
289
  }
287
290
  else if (err instanceof error_1.FirebaseError) {
288
291
  throw err;
289
292
  }
290
- throw new error_1.FirebaseError(`Failed to query the extension version '${clc.bold(extensionVersionRef)}': ${err}`);
293
+ throw new error_1.FirebaseError(`Failed to query the extension version '${clc.bold(extensionVersionRef)}': ${(0, error_1.getErrMsg)(err)}`);
291
294
  }
292
295
  }
293
296
  exports.getExtensionVersion = getExtensionVersion;
@@ -341,14 +344,14 @@ async function getExtension(extensionRef) {
341
344
  return res.body;
342
345
  }
343
346
  catch (err) {
344
- if (err.status === 404) {
347
+ if ((0, error_1.getErrStatus)(err) === 404) {
345
348
  throw refNotFoundError(ref);
346
349
  }
347
350
  else if (err instanceof error_1.FirebaseError) {
348
351
  throw err;
349
352
  }
350
- throw new error_1.FirebaseError(`Failed to query the extension '${clc.bold(extensionRef)}': ${err}`, {
351
- status: err.status,
353
+ throw new error_1.FirebaseError(`Failed to query the extension '${clc.bold(extensionRef)}': ${(0, error_1.getErrMsg)(err)}`, {
354
+ status: (0, error_1.getErrStatus)(err),
352
355
  });
353
356
  }
354
357
  }