firebase-tools 9.17.0 → 9.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 (95) hide show
  1. package/CHANGELOG.md +3 -7
  2. package/lib/api.js +1 -0
  3. package/lib/apiv2.js +5 -3
  4. package/lib/appdistribution/client.js +84 -72
  5. package/lib/appdistribution/distribution.js +8 -26
  6. package/lib/appdistribution/options-parser-util.js +51 -0
  7. package/lib/command.js +1 -1
  8. package/lib/commands/appdistribution-distribute.js +74 -91
  9. package/lib/commands/appdistribution-testers-add.js +18 -0
  10. package/lib/commands/appdistribution-testers-remove.js +32 -0
  11. package/lib/commands/crashlytics-symbols-upload.js +146 -0
  12. package/lib/commands/ext-configure.js +9 -1
  13. package/lib/commands/ext-dev-extension-delete.js +2 -1
  14. package/lib/commands/ext-dev-publish.js +11 -4
  15. package/lib/commands/ext-dev-unpublish.js +12 -4
  16. package/lib/commands/ext-install.js +115 -48
  17. package/lib/commands/ext-uninstall.js +6 -0
  18. package/lib/commands/ext-update.js +61 -18
  19. package/lib/commands/functions-config-export.js +115 -0
  20. package/lib/commands/functions-delete.js +45 -25
  21. package/lib/commands/functions-list.js +54 -0
  22. package/lib/commands/functions-log.js +5 -22
  23. package/lib/commands/hosting-channel-deploy.js +6 -4
  24. package/lib/commands/index.js +12 -0
  25. package/lib/deploy/functions/backend.js +118 -121
  26. package/lib/deploy/functions/checkIam.js +8 -8
  27. package/lib/deploy/functions/containerCleaner.js +5 -1
  28. package/lib/deploy/functions/deploy.js +11 -15
  29. package/lib/deploy/functions/functionsDeployHelper.js +3 -68
  30. package/lib/deploy/functions/prepare.js +67 -33
  31. package/lib/deploy/functions/pricing.js +17 -17
  32. package/lib/deploy/functions/prompts.js +24 -41
  33. package/lib/deploy/functions/release/executor.js +39 -0
  34. package/lib/deploy/functions/release/fabricator.js +362 -0
  35. package/lib/deploy/functions/release/index.js +69 -0
  36. package/lib/deploy/functions/release/planner.js +159 -0
  37. package/lib/deploy/functions/release/reporter.js +162 -0
  38. package/lib/deploy/functions/release/sourceTokenScraper.js +28 -0
  39. package/lib/deploy/functions/release/timer.js +14 -0
  40. package/lib/deploy/functions/runtimes/discovery/v1alpha1.js +102 -126
  41. package/lib/deploy/functions/runtimes/node/parseTriggers.js +34 -50
  42. package/lib/deploy/functions/triggerRegionHelper.js +40 -0
  43. package/lib/deploy/functions/validate.js +1 -24
  44. package/lib/downloadUtils.js +37 -0
  45. package/lib/emulator/auth/apiSpec.js +1788 -403
  46. package/lib/emulator/auth/handlers.js +6 -5
  47. package/lib/emulator/auth/operations.js +439 -40
  48. package/lib/emulator/auth/server.js +32 -11
  49. package/lib/emulator/auth/state.js +205 -5
  50. package/lib/emulator/auth/widget_ui.js +2 -2
  51. package/lib/emulator/download.js +2 -31
  52. package/lib/emulator/downloadableEmulators.js +7 -7
  53. package/lib/emulator/emulatorLogger.js +0 -3
  54. package/lib/emulator/events/types.js +16 -0
  55. package/lib/emulator/functionsEmulator.js +117 -20
  56. package/lib/emulator/functionsEmulatorRuntime.js +46 -121
  57. package/lib/emulator/functionsEmulatorShared.js +51 -7
  58. package/lib/emulator/functionsEmulatorShell.js +1 -1
  59. package/lib/emulator/pubsubEmulator.js +61 -40
  60. package/lib/emulator/storage/cloudFunctions.js +37 -7
  61. package/lib/extensions/askUserForConsent.js +16 -13
  62. package/lib/extensions/askUserForParam.js +72 -3
  63. package/lib/extensions/billingMigrationHelper.js +1 -11
  64. package/lib/extensions/changelog.js +2 -1
  65. package/lib/extensions/displayExtensionInfo.js +35 -33
  66. package/lib/extensions/emulator/optionsHelper.js +3 -3
  67. package/lib/extensions/emulator/triggerHelper.js +2 -32
  68. package/lib/extensions/extensionsApi.js +67 -94
  69. package/lib/extensions/extensionsHelper.js +49 -35
  70. package/lib/extensions/paramHelper.js +79 -36
  71. package/lib/extensions/refs.js +59 -0
  72. package/lib/extensions/secretsUtils.js +58 -0
  73. package/lib/extensions/updateHelper.js +21 -45
  74. package/lib/extensions/warnings.js +1 -7
  75. package/lib/functional.js +64 -0
  76. package/lib/functions/env.js +26 -13
  77. package/lib/functions/functionslog.js +40 -0
  78. package/lib/functions/runtimeConfigExport.js +137 -0
  79. package/lib/gcp/cloudfunctions.js +46 -38
  80. package/lib/gcp/cloudfunctionsv2.js +47 -47
  81. package/lib/gcp/cloudlogging.js +27 -21
  82. package/lib/gcp/cloudscheduler.js +22 -16
  83. package/lib/gcp/pubsub.js +1 -9
  84. package/lib/gcp/secretManager.js +111 -0
  85. package/lib/gcp/storage.js +16 -0
  86. package/lib/previews.js +1 -1
  87. package/lib/requireInteractive.js +12 -0
  88. package/lib/utils.js +30 -1
  89. package/package.json +5 -4
  90. package/lib/deploy/functions/deploymentPlanner.js +0 -113
  91. package/lib/deploy/functions/deploymentTimer.js +0 -23
  92. package/lib/deploy/functions/errorHandler.js +0 -75
  93. package/lib/deploy/functions/release.js +0 -116
  94. package/lib/deploy/functions/tasks.js +0 -324
  95. package/lib/functionsDelete.js +0 -60
@@ -17,6 +17,7 @@ const lodash_1 = require("lodash");
17
17
  const handlers_1 = require("./handlers");
18
18
  const bodyParser = require("body-parser");
19
19
  const url_1 = require("url");
20
+ const jsonwebtoken_1 = require("jsonwebtoken");
20
21
  const apiSpec = apiSpec_1.default;
21
22
  const API_SPEC_PATH = "/emulator/openapi.json";
22
23
  const AUTH_HEADER_PREFIX = "bearer ";
@@ -70,6 +71,10 @@ async function createApp(defaultProjectId, projectStateForId = new Map()) {
70
71
  const app = express();
71
72
  app.set("json spaces", 2);
72
73
  app.use(cors({ origin: true }));
74
+ app.delete("*", (req, _, next) => {
75
+ delete req.headers["content-type"];
76
+ next();
77
+ });
73
78
  app.get("/", (req, res) => {
74
79
  return res.json({
75
80
  authEmulator: {
@@ -83,7 +88,7 @@ async function createApp(defaultProjectId, projectStateForId = new Map()) {
83
88
  res.json(specWithEmulatorServer(req.protocol, req.headers.host));
84
89
  });
85
90
  registerLegacyRoutes(app);
86
- handlers_1.registerHandlers(app, (apiKey) => getProjectStateById(getProjectIdByApiKey(apiKey)));
91
+ handlers_1.registerHandlers(app, (apiKey, tenantId) => getProjectStateById(getProjectIdByApiKey(apiKey), tenantId));
87
92
  const apiKeyAuthenticator = (ctx, info) => {
88
93
  if (info.in !== "query") {
89
94
  throw new Error('apiKey must be defined as in: "query" in API spec.');
@@ -169,6 +174,9 @@ async function createApp(defaultProjectId, projectStateForId = new Map()) {
169
174
  "google-fieldmask"() {
170
175
  return true;
171
176
  },
177
+ "google-duration"() {
178
+ return true;
179
+ },
172
180
  uint64() {
173
181
  return true;
174
182
  },
@@ -234,13 +242,16 @@ async function createApp(defaultProjectId, projectStateForId = new Map()) {
234
242
  apiKey;
235
243
  return defaultProjectId;
236
244
  }
237
- function getProjectStateById(projectId) {
238
- let state = projectStateForId.get(projectId);
239
- if (!state) {
240
- state = new state_1.ProjectState(projectId);
241
- projectStateForId.set(projectId, state);
245
+ function getProjectStateById(projectId, tenantId) {
246
+ let agentState = projectStateForId.get(projectId);
247
+ if (!agentState) {
248
+ agentState = new state_1.AgentProjectState(projectId);
249
+ projectStateForId.set(projectId, agentState);
242
250
  }
243
- return state;
251
+ if (!tenantId) {
252
+ return agentState;
253
+ }
254
+ return agentState.getTenantProject(tenantId);
244
255
  }
245
256
  }
246
257
  exports.createApp = createApp;
@@ -328,7 +339,7 @@ function toExegesisController(ops, getProjectStateById) {
328
339
  }
329
340
  function toExegesisOperation(operation) {
330
341
  return (ctx) => {
331
- var _a, _b, _c, _d;
342
+ var _a, _b, _c, _d, _e, _f, _g;
332
343
  let targetProjectId = ctx.params.path.targetProjectId || ((_a = ctx.requestBody) === null || _a === void 0 ? void 0 : _a.targetProjectId);
333
344
  if (targetProjectId) {
334
345
  if ((_b = ctx.api.operationObject.security) === null || _b === void 0 ? void 0 : _b.some((sec) => sec.Oauth2)) {
@@ -338,10 +349,20 @@ function toExegesisController(ops, getProjectStateById) {
338
349
  else {
339
350
  targetProjectId = ctx.user;
340
351
  }
341
- if (ctx.params.path.tenantId || ((_d = ctx.requestBody) === null || _d === void 0 ? void 0 : _d.tenantId)) {
342
- throw new errors_2.NotImplementedError("Multi-tenancy is unimplemented.");
352
+ let targetTenantId = undefined;
353
+ if (ctx.params.path.tenantId && ((_d = ctx.requestBody) === null || _d === void 0 ? void 0 : _d.tenantId)) {
354
+ errors_2.assert(ctx.params.path.tenantId === ctx.requestBody.tenantId, "TENANT_ID_MISMATCH");
355
+ }
356
+ targetTenantId = ctx.params.path.tenantId || ((_e = ctx.requestBody) === null || _e === void 0 ? void 0 : _e.tenantId);
357
+ if ((_f = ctx.requestBody) === null || _f === void 0 ? void 0 : _f.idToken) {
358
+ const idToken = (_g = ctx.requestBody) === null || _g === void 0 ? void 0 : _g.idToken;
359
+ const decoded = jsonwebtoken_1.decode(idToken, { complete: true });
360
+ if ((decoded === null || decoded === void 0 ? void 0 : decoded.payload.firebase.tenant) && targetTenantId) {
361
+ errors_2.assert((decoded === null || decoded === void 0 ? void 0 : decoded.payload.firebase.tenant) === targetTenantId, "TENANT_ID_MISMATCH");
362
+ }
363
+ targetTenantId = targetTenantId || (decoded === null || decoded === void 0 ? void 0 : decoded.payload.firebase.tenant);
343
364
  }
344
- return operation(getProjectStateById(targetProjectId), ctx.requestBody, ctx);
365
+ return operation(getProjectStateById(targetProjectId, targetTenantId), ctx.requestBody, ctx);
345
366
  };
346
367
  }
347
368
  }
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ProjectState = exports.SIGNIN_METHOD_EMAIL_LINK = exports.PROVIDER_CUSTOM = exports.PROVIDER_ANONYMOUS = exports.PROVIDER_PHONE = exports.PROVIDER_PASSWORD = void 0;
3
+ exports.UsageMode = exports.TenantProjectState = exports.AgentProjectState = exports.ProjectState = exports.SIGNIN_METHOD_EMAIL_LINK = exports.PROVIDER_GAME_CENTER = exports.PROVIDER_CUSTOM = exports.PROVIDER_ANONYMOUS = exports.PROVIDER_PHONE = exports.PROVIDER_PASSWORD = void 0;
4
4
  const utils_1 = require("./utils");
5
5
  const cloudFunctions_1 = require("./cloudFunctions");
6
6
  const errors_1 = require("./errors");
@@ -8,6 +8,7 @@ exports.PROVIDER_PASSWORD = "password";
8
8
  exports.PROVIDER_PHONE = "phone";
9
9
  exports.PROVIDER_ANONYMOUS = "anonymous";
10
10
  exports.PROVIDER_CUSTOM = "custom";
11
+ exports.PROVIDER_GAME_CENTER = "gc.apple.com";
11
12
  exports.SIGNIN_METHOD_EMAIL_LINK = "emailLink";
12
13
  class ProjectState {
13
14
  constructor(projectId) {
@@ -23,8 +24,6 @@ class ProjectState {
23
24
  this.oobs = new Map();
24
25
  this.verificationCodes = new Map();
25
26
  this.temporaryProofs = new Map();
26
- this.oneAccountPerEmail = true;
27
- this.authCloudFunction = new cloudFunctions_1.AuthCloudFunction(projectId);
28
27
  }
29
28
  get projectNumber() {
30
29
  return "12345";
@@ -281,10 +280,16 @@ class ProjectState {
281
280
  getUserByLocalId(localId) {
282
281
  return this.users.get(localId);
283
282
  }
284
- createRefreshTokenFor(userInfo, provider, extraClaims = {}) {
283
+ createRefreshTokenFor(userInfo, provider, { extraClaims = {}, secondFactor, } = {}) {
285
284
  const localId = userInfo.localId;
286
285
  const refreshToken = utils_1.randomBase64UrlStr(204);
287
- this.refreshTokens.set(refreshToken, { localId, provider, extraClaims });
286
+ this.refreshTokens.set(refreshToken, {
287
+ localId,
288
+ provider,
289
+ extraClaims,
290
+ secondFactor,
291
+ tenantId: userInfo.tenantId,
292
+ });
288
293
  let refreshTokens = this.refreshTokensForLocalId.get(localId);
289
294
  if (!refreshTokens) {
290
295
  refreshTokens = new Set();
@@ -302,6 +307,7 @@ class ProjectState {
302
307
  user: this.getUserByLocalIdAssertingExists(record.localId),
303
308
  provider: record.provider,
304
309
  extraClaims: record.extraClaims,
310
+ secondFactor: record.secondFactor,
305
311
  };
306
312
  }
307
313
  createOob(email, requestType, generateLink) {
@@ -413,6 +419,195 @@ class ProjectState {
413
419
  }
414
420
  }
415
421
  exports.ProjectState = ProjectState;
422
+ class AgentProjectState extends ProjectState {
423
+ constructor(projectId) {
424
+ super(projectId);
425
+ this._oneAccountPerEmail = true;
426
+ this._usageMode = UsageMode.DEFAULT;
427
+ this.tenantProjectForTenantId = new Map();
428
+ this._authCloudFunction = new cloudFunctions_1.AuthCloudFunction(this.projectId);
429
+ }
430
+ get authCloudFunction() {
431
+ return this._authCloudFunction;
432
+ }
433
+ get oneAccountPerEmail() {
434
+ return this._oneAccountPerEmail;
435
+ }
436
+ set oneAccountPerEmail(oneAccountPerEmail) {
437
+ this._oneAccountPerEmail = oneAccountPerEmail;
438
+ }
439
+ get usageMode() {
440
+ return this._usageMode;
441
+ }
442
+ set usageMode(usageMode) {
443
+ this._usageMode = usageMode;
444
+ }
445
+ get allowPasswordSignup() {
446
+ return true;
447
+ }
448
+ get disableAuth() {
449
+ return false;
450
+ }
451
+ get mfaConfig() {
452
+ return { state: "ENABLED", enabledProviders: ["PHONE_SMS"] };
453
+ }
454
+ get enableAnonymousUser() {
455
+ return true;
456
+ }
457
+ get enableEmailLinkSignin() {
458
+ return true;
459
+ }
460
+ getTenantProject(tenantId) {
461
+ if (!this.tenantProjectForTenantId.has(tenantId)) {
462
+ this.createTenantWithTenantId(tenantId, {
463
+ tenantId,
464
+ allowPasswordSignup: true,
465
+ disableAuth: false,
466
+ mfaConfig: {
467
+ state: "ENABLED",
468
+ enabledProviders: ["PHONE_SMS"],
469
+ },
470
+ enableAnonymousUser: true,
471
+ enableEmailLinkSignin: true,
472
+ });
473
+ }
474
+ return this.tenantProjectForTenantId.get(tenantId);
475
+ }
476
+ listTenants(startToken) {
477
+ const tenantProjects = [];
478
+ for (const tenantProject of this.tenantProjectForTenantId.values()) {
479
+ if (!startToken || tenantProject.tenantId > startToken) {
480
+ tenantProjects.push(tenantProject);
481
+ }
482
+ }
483
+ tenantProjects.sort((a, b) => {
484
+ if (a.tenantId < b.tenantId) {
485
+ return -1;
486
+ }
487
+ else if (a.tenantId > b.tenantId) {
488
+ return 1;
489
+ }
490
+ return 0;
491
+ });
492
+ return tenantProjects.map((tenantProject) => tenantProject.tenantConfig);
493
+ }
494
+ createTenant(tenant) {
495
+ for (let i = 0; i < 10; i++) {
496
+ const tenantId = utils_1.randomId(28);
497
+ const createdTenant = this.createTenantWithTenantId(tenantId, tenant);
498
+ if (createdTenant) {
499
+ return createdTenant;
500
+ }
501
+ }
502
+ throw new Error("Could not generate a random unique tenantId after 10 tries");
503
+ }
504
+ createTenantWithTenantId(tenantId, tenant) {
505
+ if (this.tenantProjectForTenantId.has(tenantId)) {
506
+ return undefined;
507
+ }
508
+ tenant.name = `projects/${this.projectId}/tenants/${tenantId}`;
509
+ tenant.tenantId = tenantId;
510
+ this.tenantProjectForTenantId.set(tenantId, new TenantProjectState(this.projectId, tenantId, tenant, this));
511
+ return tenant;
512
+ }
513
+ deleteTenant(tenantId) {
514
+ this.tenantProjectForTenantId.delete(tenantId);
515
+ }
516
+ }
517
+ exports.AgentProjectState = AgentProjectState;
518
+ class TenantProjectState extends ProjectState {
519
+ constructor(projectId, tenantId, _tenantConfig, parentProject) {
520
+ super(projectId);
521
+ this.tenantId = tenantId;
522
+ this._tenantConfig = _tenantConfig;
523
+ this.parentProject = parentProject;
524
+ }
525
+ get oneAccountPerEmail() {
526
+ return this.parentProject.oneAccountPerEmail;
527
+ }
528
+ get authCloudFunction() {
529
+ return this.parentProject.authCloudFunction;
530
+ }
531
+ get usageMode() {
532
+ return this.parentProject.usageMode;
533
+ }
534
+ get tenantConfig() {
535
+ return this._tenantConfig;
536
+ }
537
+ get allowPasswordSignup() {
538
+ return this._tenantConfig.allowPasswordSignup;
539
+ }
540
+ get disableAuth() {
541
+ return this._tenantConfig.disableAuth;
542
+ }
543
+ get mfaConfig() {
544
+ return this._tenantConfig.mfaConfig;
545
+ }
546
+ get enableAnonymousUser() {
547
+ return this._tenantConfig.enableAnonymousUser;
548
+ }
549
+ get enableEmailLinkSignin() {
550
+ return this._tenantConfig.enableEmailLinkSignin;
551
+ }
552
+ delete() {
553
+ this.parentProject.deleteTenant(this.tenantId);
554
+ }
555
+ updateTenant(update, updateMask) {
556
+ var _a, _b, _c, _d, _e;
557
+ if (!updateMask) {
558
+ const mfaConfig = (_a = update.mfaConfig) !== null && _a !== void 0 ? _a : {};
559
+ if (!("state" in mfaConfig)) {
560
+ mfaConfig.state = "DISABLED";
561
+ }
562
+ if (!("enabledProviders" in mfaConfig)) {
563
+ mfaConfig.enabledProviders = [];
564
+ }
565
+ this._tenantConfig = {
566
+ tenantId: this.tenantId,
567
+ name: this.tenantConfig.name,
568
+ allowPasswordSignup: (_b = update.allowPasswordSignup) !== null && _b !== void 0 ? _b : false,
569
+ disableAuth: (_c = update.disableAuth) !== null && _c !== void 0 ? _c : false,
570
+ mfaConfig: mfaConfig,
571
+ enableAnonymousUser: (_d = update.enableAnonymousUser) !== null && _d !== void 0 ? _d : false,
572
+ enableEmailLinkSignin: (_e = update.enableEmailLinkSignin) !== null && _e !== void 0 ? _e : false,
573
+ displayName: update.displayName,
574
+ };
575
+ return this.tenantConfig;
576
+ }
577
+ const paths = updateMask.split(",");
578
+ for (const path of paths) {
579
+ const fields = path.split(".");
580
+ let updateField = update;
581
+ let existingField = this._tenantConfig;
582
+ let field;
583
+ for (let i = 0; i < fields.length - 1; i++) {
584
+ field = fields[i];
585
+ if (updateField[field] == null) {
586
+ console.warn(`Unable to find field '${field}' in update '${updateField}`);
587
+ break;
588
+ }
589
+ if (Array.isArray(updateField[field]) ||
590
+ Object(updateField[field]) !== updateField[field]) {
591
+ console.warn(`Field '${field}' is singular and cannot have sub-fields`);
592
+ break;
593
+ }
594
+ if (!existingField[field]) {
595
+ existingField[field] = {};
596
+ }
597
+ updateField = updateField[field];
598
+ existingField = existingField[field];
599
+ }
600
+ field = fields[fields.length - 1];
601
+ if (updateField[field] == null) {
602
+ console.warn(`Unable to find field '${field}' in update '${JSON.stringify(updateField)}`);
603
+ continue;
604
+ }
605
+ existingField[field] = updateField[field];
606
+ }
607
+ return this.tenantConfig;
608
+ }
609
+ }
610
+ exports.TenantProjectState = TenantProjectState;
416
611
  function getProviderEmailsForUser(user) {
417
612
  var _a;
418
613
  const emails = new Set();
@@ -423,3 +618,8 @@ function getProviderEmailsForUser(user) {
423
618
  });
424
619
  return emails;
425
620
  }
621
+ var UsageMode;
622
+ (function (UsageMode) {
623
+ UsageMode["DEFAULT"] = "DEFAULT";
624
+ UsageMode["PASSTHROUGH"] = "PASSTHROUGH";
625
+ })(UsageMode = exports.UsageMode || (exports.UsageMode = {}));
@@ -488,7 +488,7 @@ exports.WIDGET_UI = `
488
488
  <meta charset="utf-8">
489
489
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
490
490
  <title>Auth Emulator IDP Login Widget</title>
491
- <link href="https://unpkg.com/material-components-web@latest/dist/material-components-web.min.css" rel="stylesheet">
491
+ <link href="https://unpkg.com/material-components-web@10/dist/material-components-web.min.css" rel="stylesheet">
492
492
  <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
493
493
  <link href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;500&display=swap" rel="stylesheet">
494
494
  <style>${STYLE}</style>
@@ -601,6 +601,6 @@ exports.WIDGET_UI = `
601
601
  </div>
602
602
  </div>
603
603
  </div>
604
- <script src="https://unpkg.com/material-components-web@latest/dist/material-components-web.min.js"></script>
604
+ <script src="https://unpkg.com/material-components-web@10/dist/material-components-web.min.js"></script>
605
605
  <script>${SCRIPT}</script>
606
606
  `;
@@ -1,23 +1,21 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.downloadEmulator = void 0;
4
- const url_1 = require("url");
5
4
  const crypto = require("crypto");
6
5
  const fs = require("fs-extra");
7
6
  const path = require("path");
8
- const ProgressBar = require("progress");
9
7
  const tmp = require("tmp");
10
8
  const unzipper = require("unzipper");
11
- const apiv2_1 = require("../apiv2");
12
9
  const emulatorLogger_1 = require("./emulatorLogger");
13
10
  const error_1 = require("../error");
14
11
  const downloadableEmulators = require("./downloadableEmulators");
12
+ const downloadUtils = require("../downloadUtils");
15
13
  tmp.setGracefulCleanup();
16
14
  async function downloadEmulator(name) {
17
15
  const emulator = downloadableEmulators.getDownloadDetails(name);
18
16
  emulatorLogger_1.EmulatorLogger.forEmulator(name).logLabeled("BULLET", name, `downloading ${path.basename(emulator.downloadPath)}...`);
19
17
  fs.ensureDirSync(emulator.opts.cacheDir);
20
- const tmpfile = await downloadToTmp(emulator.opts.remoteUrl);
18
+ const tmpfile = await downloadUtils.downloadToTmp(emulator.opts.remoteUrl);
21
19
  if (!emulator.opts.skipChecksumAndSize) {
22
20
  await validateSize(tmpfile, emulator.opts.expectedSize);
23
21
  await validateChecksum(tmpfile, emulator.opts.expectedChecksum);
@@ -58,33 +56,6 @@ function removeOldFiles(name, emulator, removeAllVersions = false) {
58
56
  }
59
57
  }
60
58
  }
61
- async function downloadToTmp(remoteUrl) {
62
- const u = new url_1.URL(remoteUrl);
63
- const c = new apiv2_1.Client({ urlPrefix: u.origin, auth: false });
64
- const tmpfile = tmp.fileSync();
65
- const writeStream = fs.createWriteStream(tmpfile.name);
66
- const res = await c.request({
67
- method: "GET",
68
- path: u.pathname,
69
- queryParams: u.searchParams,
70
- responseType: "stream",
71
- resolveOnHTTPError: true,
72
- });
73
- if (res.status !== 200) {
74
- throw new error_1.FirebaseError(`download failed, status ${res.status}`, { exit: 1 });
75
- }
76
- const total = parseInt(res.response.headers.get("content-length") || "0", 10);
77
- const totalMb = Math.ceil(total / 1000000);
78
- const bar = new ProgressBar(`Progress: :bar (:percent of ${totalMb}MB)`, { total, head: ">" });
79
- res.body.on("data", (chunk) => {
80
- bar.tick(chunk.length);
81
- });
82
- await new Promise((resolve) => {
83
- writeStream.on("finish", resolve);
84
- res.body.pipe(writeStream);
85
- });
86
- return tmpfile.name;
87
- }
88
59
  function validateSize(filepath, expectedSize) {
89
60
  return new Promise((resolve, reject) => {
90
61
  const stat = fs.statSync(filepath);
@@ -50,15 +50,15 @@ exports.DownloadDetails = {
50
50
  },
51
51
  },
52
52
  ui: {
53
- version: "1.6.3",
54
- downloadPath: path.join(CACHE_DIR, "ui-v1.6.3.zip"),
55
- unzipDir: path.join(CACHE_DIR, "ui-v1.6.3"),
56
- binaryPath: path.join(CACHE_DIR, "ui-v1.6.3", "server.bundle.js"),
53
+ version: "1.6.4",
54
+ downloadPath: path.join(CACHE_DIR, "ui-v1.6.4.zip"),
55
+ unzipDir: path.join(CACHE_DIR, "ui-v1.6.4"),
56
+ binaryPath: path.join(CACHE_DIR, "ui-v1.6.4", "server.bundle.js"),
57
57
  opts: {
58
58
  cacheDir: CACHE_DIR,
59
- remoteUrl: "https://storage.googleapis.com/firebase-preview-drop/emulator/ui-v1.6.3.zip",
60
- expectedSize: 3757268,
61
- expectedChecksum: "153090a46072545aadeb307397cc8f45",
59
+ remoteUrl: "https://storage.googleapis.com/firebase-preview-drop/emulator/ui-v1.6.4.zip",
60
+ expectedSize: 3757300,
61
+ expectedChecksum: "20d4ee71e4ff7527b1843b6a8636142e",
62
62
  namePrefix: "ui",
63
63
  },
64
64
  },
@@ -168,9 +168,6 @@ You can probably fix this by running "npm install ${systemLog.data.name}@latest"
168
168
  case "function-runtimeconfig-json-invalid":
169
169
  this.log("WARN", "Found .runtimeconfig.json but the JSON format is invalid.");
170
170
  break;
171
- case "function-env-load-failed":
172
- this.log("WARN", "Failed to load environment variables: " + systemLog.text);
173
- break;
174
171
  default:
175
172
  }
176
173
  }
@@ -9,5 +9,21 @@ class EventUtils {
9
9
  static isLegacyEvent(proto) {
10
10
  return _.has(proto, "data") && _.has(proto, "resource");
11
11
  }
12
+ static isBinaryCloudEvent(req) {
13
+ return !!(req.header("ce-type") &&
14
+ req.header("ce-specversion") &&
15
+ req.header("ce-source") &&
16
+ req.header("ce-id"));
17
+ }
18
+ static extractBinaryCloudEventContext(req) {
19
+ const context = {};
20
+ for (const name of Object.keys(req.headers)) {
21
+ if (name.startsWith("ce-")) {
22
+ const attributeName = name.substr("ce-".length);
23
+ context[attributeName] = req.header(name);
24
+ }
25
+ }
26
+ return context;
27
+ }
12
28
  }
13
29
  exports.EventUtils = EventUtils;