firebase-tools 10.6.0 → 10.7.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (97) hide show
  1. package/lib/command.js +4 -4
  2. package/lib/commands/deploy.js +1 -1
  3. package/lib/commands/emulators-start.js +7 -2
  4. package/lib/commands/ext-configure.js +15 -5
  5. package/lib/commands/ext-export.js +6 -5
  6. package/lib/commands/ext-install.js +28 -44
  7. package/lib/commands/ext-update.js +9 -1
  8. package/lib/commands/functions-delete.js +7 -3
  9. package/lib/commands/hosting-channel-deploy.js +2 -2
  10. package/lib/deploy/database/deploy.js +4 -0
  11. package/lib/deploy/database/index.js +1 -0
  12. package/lib/deploy/extensions/deploy.js +4 -4
  13. package/lib/deploy/extensions/deploymentSummary.js +8 -5
  14. package/lib/deploy/extensions/planner.js +36 -9
  15. package/lib/deploy/extensions/prepare.js +1 -1
  16. package/lib/deploy/extensions/secrets.js +2 -2
  17. package/lib/deploy/extensions/tasks.js +60 -21
  18. package/lib/deploy/functions/backend.js +37 -2
  19. package/lib/deploy/functions/build.js +173 -0
  20. package/lib/deploy/functions/checkIam.js +11 -14
  21. package/lib/deploy/functions/containerCleaner.js +8 -7
  22. package/lib/deploy/functions/deploy.js +49 -28
  23. package/lib/deploy/functions/ensure.js +4 -4
  24. package/lib/deploy/functions/functionsDeployHelper.js +99 -24
  25. package/lib/deploy/functions/prepare.js +129 -71
  26. package/lib/deploy/functions/prepareFunctionsUpload.js +16 -21
  27. package/lib/deploy/functions/pricing.js +6 -3
  28. package/lib/deploy/functions/prompts.js +1 -7
  29. package/lib/deploy/functions/release/executor.js +1 -1
  30. package/lib/deploy/functions/release/fabricator.js +69 -25
  31. package/lib/deploy/functions/release/index.js +20 -6
  32. package/lib/deploy/functions/release/planner.js +18 -10
  33. package/lib/deploy/functions/release/reporter.js +14 -11
  34. package/lib/deploy/functions/runtimes/discovery/parsing.js +12 -6
  35. package/lib/deploy/functions/runtimes/discovery/v1alpha1.js +50 -3
  36. package/lib/deploy/functions/runtimes/golang/index.js +3 -0
  37. package/lib/deploy/functions/runtimes/node/index.js +7 -0
  38. package/lib/deploy/functions/runtimes/node/parseRuntimeAndValidateSDK.js +3 -3
  39. package/lib/deploy/functions/runtimes/node/parseTriggers.js +132 -6
  40. package/lib/deploy/functions/runtimes/node/versioning.js +2 -2
  41. package/lib/deploy/functions/services/auth.js +95 -0
  42. package/lib/deploy/functions/services/index.js +41 -21
  43. package/lib/deploy/functions/validate.js +33 -7
  44. package/lib/deploy/hosting/args.js +2 -0
  45. package/lib/deploy/hosting/convertConfig.js +39 -8
  46. package/lib/deploy/hosting/deploy.js +3 -3
  47. package/lib/deploy/hosting/prepare.js +2 -2
  48. package/lib/deploy/hosting/release.js +6 -2
  49. package/lib/deploy/index.js +82 -93
  50. package/lib/deploy/remoteconfig/deploy.js +4 -0
  51. package/lib/deploy/remoteconfig/index.js +3 -1
  52. package/lib/emulator/auth/cloudFunctions.js +6 -2
  53. package/lib/emulator/auth/operations.js +5 -1
  54. package/lib/emulator/auth/server.js +8 -1
  55. package/lib/emulator/auth/state.js +27 -24
  56. package/lib/emulator/auth/utils.js +3 -25
  57. package/lib/emulator/controller.js +17 -14
  58. package/lib/emulator/databaseEmulator.js +36 -3
  59. package/lib/emulator/downloadableEmulators.js +39 -23
  60. package/lib/emulator/extensions/validation.js +2 -2
  61. package/lib/emulator/extensionsEmulator.js +85 -21
  62. package/lib/emulator/functionsEmulator.js +89 -15
  63. package/lib/emulator/functionsEmulatorRuntime.js +1 -1
  64. package/lib/emulator/functionsEmulatorShared.js +25 -2
  65. package/lib/emulator/functionsEmulatorShell.js +2 -3
  66. package/lib/emulator/functionsEmulatorUtils.js +5 -1
  67. package/lib/emulator/pubsubEmulator.js +13 -9
  68. package/lib/emulator/registry.js +34 -12
  69. package/lib/emulator/storage/apis/firebase.js +33 -6
  70. package/lib/emulator/storage/apis/gcloud.js +6 -3
  71. package/lib/emulator/storage/files.js +9 -1
  72. package/lib/ensureApiEnabled.js +8 -4
  73. package/lib/extensions/changelog.js +1 -1
  74. package/lib/extensions/emulator/optionsHelper.js +4 -3
  75. package/lib/extensions/emulator/specHelper.js +7 -1
  76. package/lib/extensions/extensionsHelper.js +30 -24
  77. package/lib/extensions/manifest.js +27 -7
  78. package/lib/extensions/paramHelper.js +7 -5
  79. package/lib/extensions/provisioningHelper.js +2 -2
  80. package/lib/extensions/warnings.js +11 -4
  81. package/lib/functions/events/index.js +7 -0
  82. package/lib/functions/events/v1.js +6 -0
  83. package/lib/functions/projectConfig.js +32 -6
  84. package/lib/functionsShellCommandAction.js +1 -1
  85. package/lib/gcp/cloudfunctions.js +38 -5
  86. package/lib/gcp/cloudfunctionsv2.js +46 -7
  87. package/lib/gcp/identityPlatform.js +44 -0
  88. package/lib/gcp/secretManager.js +1 -1
  89. package/lib/metaprogramming.js +2 -0
  90. package/lib/previews.js +1 -1
  91. package/lib/serve/functions.js +16 -19
  92. package/lib/serve/hosting.js +25 -12
  93. package/lib/serve/index.js +6 -0
  94. package/lib/track.js +15 -21
  95. package/npm-shrinkwrap.json +256 -527
  96. package/package.json +6 -3
  97. package/schema/firebase-config.json +6 -0
@@ -1,47 +1,67 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.serviceForEndpoint = exports.EVENT_SERVICE_MAPPING = exports.FirebaseAlertsService = exports.StorageService = exports.PubSubService = exports.NoOpService = void 0;
3
+ exports.serviceForEndpoint = exports.noopProjectBindings = exports.noop = void 0;
4
4
  const backend = require("../backend");
5
+ const auth_1 = require("./auth");
5
6
  const storage_1 = require("./storage");
6
7
  const firebaseAlerts_1 = require("./firebaseAlerts");
7
8
  const noop = () => Promise.resolve();
9
+ exports.noop = noop;
8
10
  const noopProjectBindings = () => Promise.resolve([]);
9
- exports.NoOpService = {
11
+ exports.noopProjectBindings = noopProjectBindings;
12
+ const noOpService = {
10
13
  name: "noop",
11
14
  api: "",
12
- requiredProjectBindings: undefined,
13
- ensureTriggerRegion: noop,
15
+ ensureTriggerRegion: exports.noop,
16
+ validateTrigger: exports.noop,
17
+ registerTrigger: exports.noop,
18
+ unregisterTrigger: exports.noop,
14
19
  };
15
- exports.PubSubService = {
20
+ const pubSubService = {
16
21
  name: "pubsub",
17
22
  api: "pubsub.googleapis.com",
18
- requiredProjectBindings: undefined,
19
- ensureTriggerRegion: noop,
23
+ requiredProjectBindings: exports.noopProjectBindings,
24
+ ensureTriggerRegion: exports.noop,
25
+ validateTrigger: exports.noop,
26
+ registerTrigger: exports.noop,
27
+ unregisterTrigger: exports.noop,
20
28
  };
21
- exports.StorageService = {
29
+ const storageService = {
22
30
  name: "storage",
23
31
  api: "storage.googleapis.com",
24
32
  requiredProjectBindings: storage_1.obtainStorageBindings,
25
33
  ensureTriggerRegion: storage_1.ensureStorageTriggerRegion,
34
+ validateTrigger: exports.noop,
35
+ registerTrigger: exports.noop,
36
+ unregisterTrigger: exports.noop,
26
37
  };
27
- exports.FirebaseAlertsService = {
38
+ const firebaseAlertsService = {
28
39
  name: "firebasealerts",
29
- api: "logging.googleapis.com",
30
- requiredProjectBindings: noopProjectBindings,
40
+ api: "firebasealerts.googleapis.com",
41
+ requiredProjectBindings: exports.noopProjectBindings,
31
42
  ensureTriggerRegion: firebaseAlerts_1.ensureFirebaseAlertsTriggerRegion,
43
+ validateTrigger: exports.noop,
44
+ registerTrigger: exports.noop,
45
+ unregisterTrigger: exports.noop,
32
46
  };
33
- exports.EVENT_SERVICE_MAPPING = {
34
- "google.cloud.pubsub.topic.v1.messagePublished": exports.PubSubService,
35
- "google.cloud.storage.object.v1.finalized": exports.StorageService,
36
- "google.cloud.storage.object.v1.archived": exports.StorageService,
37
- "google.cloud.storage.object.v1.deleted": exports.StorageService,
38
- "google.cloud.storage.object.v1.metadataUpdated": exports.StorageService,
39
- "google.firebase.firebasealerts.alerts.v1.published": exports.FirebaseAlertsService,
47
+ const authBlockingService = new auth_1.AuthBlockingService();
48
+ const EVENT_SERVICE_MAPPING = {
49
+ "google.cloud.pubsub.topic.v1.messagePublished": pubSubService,
50
+ "google.cloud.storage.object.v1.finalized": storageService,
51
+ "google.cloud.storage.object.v1.archived": storageService,
52
+ "google.cloud.storage.object.v1.deleted": storageService,
53
+ "google.cloud.storage.object.v1.metadataUpdated": storageService,
54
+ "google.firebase.firebasealerts.alerts.v1.published": firebaseAlertsService,
55
+ "providers/cloud.auth/eventTypes/user.beforeCreate": authBlockingService,
56
+ "providers/cloud.auth/eventTypes/user.beforeSignIn": authBlockingService,
40
57
  };
41
58
  function serviceForEndpoint(endpoint) {
42
- if (!backend.isEventTriggered(endpoint)) {
43
- return exports.NoOpService;
59
+ if (backend.isEventTriggered(endpoint)) {
60
+ return EVENT_SERVICE_MAPPING[endpoint.eventTrigger.eventType] || noOpService;
44
61
  }
45
- return exports.EVENT_SERVICE_MAPPING[endpoint.eventTrigger.eventType] || exports.NoOpService;
62
+ if (backend.isBlockingTriggered(endpoint)) {
63
+ return EVENT_SERVICE_MAPPING[endpoint.blockingTrigger.eventType] || noOpService;
64
+ }
65
+ return noOpService;
46
66
  }
47
67
  exports.serviceForEndpoint = serviceForEndpoint;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.secretsAreValid = exports.functionIdsAreValid = exports.functionsDirectoryExists = exports.endpointsAreValid = void 0;
3
+ exports.secretsAreValid = exports.functionIdsAreValid = exports.functionsDirectoryExists = exports.endpointsAreUnique = exports.endpointsAreValid = void 0;
4
4
  const path = require("path");
5
5
  const clc = require("cli-color");
6
6
  const error_1 = require("../../error");
@@ -10,18 +10,21 @@ const fsutils = require("../../fsutils");
10
10
  const backend = require("./backend");
11
11
  const utils = require("../../utils");
12
12
  const secrets = require("../../functions/secrets");
13
+ const services_1 = require("./services");
13
14
  function endpointsAreValid(wantBackend) {
14
- functionIdsAreValid(backend.allEndpoints(wantBackend));
15
- const gcfV1WithConcurrency = backend
16
- .allEndpoints(wantBackend)
15
+ const endpoints = backend.allEndpoints(wantBackend);
16
+ functionIdsAreValid(endpoints);
17
+ for (const ep of endpoints) {
18
+ (0, services_1.serviceForEndpoint)(ep).validateTrigger(ep, wantBackend);
19
+ }
20
+ const gcfV1WithConcurrency = endpoints
17
21
  .filter((endpoint) => (endpoint.concurrency || 1) !== 1 && endpoint.platform === "gcfv1")
18
22
  .map((endpoint) => endpoint.id);
19
23
  if (gcfV1WithConcurrency.length) {
20
24
  const msg = `Cannot set concurrency on the functions ${gcfV1WithConcurrency.join(",")} because they are GCF gen 1`;
21
25
  throw new error_1.FirebaseError(msg);
22
26
  }
23
- const tooSmallForConcurrency = backend
24
- .allEndpoints(wantBackend)
27
+ const tooSmallForConcurrency = endpoints
25
28
  .filter((endpoint) => {
26
29
  if ((endpoint.concurrency || 1) === 1) {
27
30
  return false;
@@ -36,6 +39,29 @@ function endpointsAreValid(wantBackend) {
36
39
  }
37
40
  }
38
41
  exports.endpointsAreValid = endpointsAreValid;
42
+ function endpointsAreUnique(backends) {
43
+ const endpointToCodebases = {};
44
+ for (const [codebase, b] of Object.entries(backends)) {
45
+ for (const endpoint of backend.allEndpoints(b)) {
46
+ const key = backend.functionName(endpoint);
47
+ const cs = endpointToCodebases[key] || new Set();
48
+ cs.add(codebase);
49
+ endpointToCodebases[key] = cs;
50
+ }
51
+ }
52
+ const conflicts = {};
53
+ for (const [fn, codebases] of Object.entries(endpointToCodebases)) {
54
+ if (codebases.size > 1) {
55
+ conflicts[fn] = Array.from(codebases);
56
+ }
57
+ }
58
+ if (Object.keys(conflicts).length === 0) {
59
+ return;
60
+ }
61
+ const msgs = Object.entries(conflicts).map(([fn, codebases]) => `${fn}: ${codebases.join(",")}`);
62
+ throw new error_1.FirebaseError("More than one codebase claims following functions:\n\t" + `${msgs.join("\n\t")}`);
63
+ }
64
+ exports.endpointsAreUnique = endpointsAreUnique;
39
65
  function functionsDirectoryExists(sourceDir, projectDir) {
40
66
  if (!fsutils.dirExistsSync(sourceDir)) {
41
67
  const sourceDirName = path.relative(projectDir, sourceDir);
@@ -60,7 +86,7 @@ function functionIdsAreValid(functions) {
60
86
  return fn.platform === "gcfv2" && !v2FunctionName.test(fn.id);
61
87
  });
62
88
  if (invalidV2Ids.length !== 0) {
63
- const msg = `${invalidV2Ids.map((f) => f.id).join(", ")} v2 function name(s) can only contin lower ` +
89
+ const msg = `${invalidV2Ids.map((f) => f.id).join(", ")} v2 function name(s) can only contain lower ` +
64
90
  `case letters, numbers, hyphens, and not exceed 62 characters in length`;
65
91
  throw new error_1.FirebaseError(msg);
66
92
  }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.convertConfig = void 0;
4
4
  const error_1 = require("../../error");
5
+ const backend_1 = require("../functions/backend");
5
6
  function has(obj, k) {
6
7
  return obj[k] !== undefined;
7
8
  }
@@ -28,7 +29,7 @@ function extractPattern(type, spec) {
28
29
  }
29
30
  throw new error_1.FirebaseError(`Cannot specify a ${type} with no pattern (either a glob or regex required).`);
30
31
  }
31
- function convertConfig(config) {
32
+ async function convertConfig(context, payload, config, finalize) {
32
33
  if (Array.isArray(config)) {
33
34
  throw new error_1.FirebaseError(`convertConfig should be given a single configuration, not an array.`, {
34
35
  exit: 2,
@@ -38,29 +39,59 @@ function convertConfig(config) {
38
39
  if (!config) {
39
40
  return out;
40
41
  }
42
+ const endpointBeingDeployed = (serviceId, region = "us-central1") => {
43
+ var _a;
44
+ for (const { wantBackend } of Object.values(payload.functions || {})) {
45
+ const endpoint = (_a = wantBackend === null || wantBackend === void 0 ? void 0 : wantBackend.endpoints[region]) === null || _a === void 0 ? void 0 : _a[serviceId];
46
+ if (endpoint && (0, backend_1.isHttpsTriggered)(endpoint) && endpoint.platform === "gcfv2")
47
+ return endpoint;
48
+ }
49
+ return undefined;
50
+ };
51
+ const matchingEndpoint = async (serviceId, region = "us-central1") => {
52
+ const pendingEndpoint = endpointBeingDeployed(serviceId, region);
53
+ if (pendingEndpoint)
54
+ return pendingEndpoint;
55
+ const backend = await (0, backend_1.existingBackend)(context);
56
+ return (0, backend_1.allEndpoints)(backend).find((it) => (0, backend_1.isHttpsTriggered)(it) &&
57
+ it.platform === "gcfv2" &&
58
+ it.id === serviceId &&
59
+ it.region === region);
60
+ };
41
61
  if (Array.isArray(config.rewrites)) {
42
- out.rewrites = config.rewrites.map((rewrite) => {
62
+ out.rewrites = [];
63
+ for (const rewrite of config.rewrites) {
43
64
  const vRewrite = extractPattern("rewrite", rewrite);
44
65
  if ("destination" in rewrite) {
45
66
  vRewrite.path = rewrite.destination;
46
67
  }
47
68
  else if ("function" in rewrite) {
48
- vRewrite.function = rewrite.function;
49
- if (rewrite.region) {
50
- vRewrite.functionRegion = rewrite.region;
69
+ if (!finalize && endpointBeingDeployed(rewrite.function, rewrite.region))
70
+ continue;
71
+ const endpoint = await matchingEndpoint(rewrite.function, rewrite.region);
72
+ if (endpoint) {
73
+ vRewrite.run = { serviceId: endpoint.id, region: endpoint.region };
51
74
  }
52
75
  else {
53
- vRewrite.functionRegion = "us-central1";
76
+ vRewrite.function = rewrite.function;
77
+ if (rewrite.region) {
78
+ vRewrite.functionRegion = rewrite.region;
79
+ }
80
+ else {
81
+ vRewrite.functionRegion = "us-central1";
82
+ }
54
83
  }
55
84
  }
56
85
  else if ("dynamicLinks" in rewrite) {
57
86
  vRewrite.dynamicLinks = rewrite.dynamicLinks;
58
87
  }
59
88
  else if ("run" in rewrite) {
89
+ if (!finalize && endpointBeingDeployed(rewrite.run.serviceId, rewrite.run.region))
90
+ continue;
60
91
  vRewrite.run = Object.assign({ region: "us-central1" }, rewrite.run);
61
92
  }
62
- return vRewrite;
63
- });
93
+ out.rewrites.push(vRewrite);
94
+ }
64
95
  }
65
96
  if (Array.isArray(config.redirects)) {
66
97
  out.redirects = config.redirects.map((redirect) => {
@@ -5,7 +5,7 @@ const uploader_1 = require("./uploader");
5
5
  const detectProjectRoot_1 = require("../../detectProjectRoot");
6
6
  const listFiles_1 = require("../../listFiles");
7
7
  const logger_1 = require("../../logger");
8
- const track = require("../../track");
8
+ const track_1 = require("../../track");
9
9
  const utils_1 = require("../../utils");
10
10
  const clc = require("cli-color");
11
11
  const SPINNER = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
@@ -63,7 +63,7 @@ async function deploy(context, options) {
63
63
  await uploader.start();
64
64
  }
65
65
  catch (err) {
66
- void track("Hosting Deploy", "failure");
66
+ void (0, track_1.track)("Hosting Deploy", "failure");
67
67
  throw err;
68
68
  }
69
69
  finally {
@@ -75,7 +75,7 @@ async function deploy(context, options) {
75
75
  (0, utils_1.logLabeledSuccess)("hosting[" + deploy.site + "]", "file upload complete");
76
76
  const dt = Date.now() - t0;
77
77
  logger_1.logger.debug("[hosting] deploy completed after " + dt + "ms");
78
- void track("Hosting Deploy", "success", dt);
78
+ void (0, track_1.track)("Hosting Deploy", "success", dt);
79
79
  return runDeploys(deploys, debugging);
80
80
  }
81
81
  const debugging = !!(options.debug || options.nonInteractive);
@@ -8,7 +8,7 @@ const normalizedHostingConfigs_1 = require("../../hosting/normalizedHostingConfi
8
8
  const validate_1 = require("./validate");
9
9
  const convertConfig_1 = require("./convertConfig");
10
10
  const deploymentTool = require("../../deploymentTool");
11
- async function prepare(context, options) {
11
+ async function prepare(context, options, payload) {
12
12
  if (options.public) {
13
13
  if (Array.isArray(options.config.get("hosting"))) {
14
14
  throw new error_1.FirebaseError("Cannot specify --public option with multi-site configuration.");
@@ -30,7 +30,7 @@ async function prepare(context, options) {
30
30
  const cfg = deploy.config;
31
31
  (0, validate_1.validateDeploy)(deploy, options);
32
32
  const data = {
33
- config: (0, convertConfig_1.convertConfig)(cfg),
33
+ config: await (0, convertConfig_1.convertConfig)(context, payload, cfg, false),
34
34
  labels: deploymentTool.labels(),
35
35
  };
36
36
  versionCreates.push(client_1.client
@@ -5,7 +5,8 @@ const client_1 = require("./client");
5
5
  const logger_1 = require("../../logger");
6
6
  const projectUtils_1 = require("../../projectUtils");
7
7
  const utils = require("../../utils");
8
- async function release(context, options) {
8
+ const convertConfig_1 = require("./convertConfig");
9
+ async function release(context, options, payload) {
9
10
  if (!context.hosting || !context.hosting.deploys) {
10
11
  return;
11
12
  }
@@ -13,7 +14,10 @@ async function release(context, options) {
13
14
  logger_1.logger.debug(JSON.stringify(context.hosting.deploys, null, 2));
14
15
  await Promise.all(context.hosting.deploys.map(async (deploy) => {
15
16
  utils.logLabeledBullet(`hosting[${deploy.site}]`, "finalizing version...");
16
- const finalizeResult = await client_1.client.patch(`/${deploy.version}`, { status: "FINALIZED" }, { queryParams: { updateMask: "status" } });
17
+ const config = await (0, convertConfig_1.convertConfig)(context, payload, deploy.config, true);
18
+ const data = { status: "FINALIZED", config };
19
+ const queryParams = { updateMask: "status,config" };
20
+ const finalizeResult = await client_1.client.patch(`/${deploy.version}`, data, { queryParams });
17
21
  logger_1.logger.debug(`[hosting] finalized version for ${deploy.site}:${finalizeResult.body}`);
18
22
  utils.logLabeledSuccess(`hosting[${deploy.site}]`, "version finalized");
19
23
  utils.logLabeledBullet(`hosting[${deploy.site}]`, "releasing new version...");
@@ -1,103 +1,92 @@
1
1
  "use strict";
2
- const { logger } = require("../logger");
3
- var api = require("../api");
4
- var clc = require("cli-color");
5
- var _ = require("lodash");
6
- var needProjectId = require("../projectUtils").needProjectId;
7
- var utils = require("../utils");
8
- var { FirebaseError } = require("../error");
9
- var track = require("../track");
10
- var lifecycleHooks = require("./lifecycleHooks");
11
- var TARGETS = {
12
- hosting: require("./hosting"),
13
- database: require("./database"),
14
- firestore: require("./firestore"),
15
- functions: require("./functions"),
16
- storage: require("./storage"),
17
- remoteconfig: require("./remoteconfig"),
18
- extensions: require("./extensions"),
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.deploy = void 0;
4
+ const logger_1 = require("../logger");
5
+ const api_1 = require("../api");
6
+ const cli_color_1 = require("cli-color");
7
+ const lodash_1 = require("lodash");
8
+ const projectUtils_1 = require("../projectUtils");
9
+ const utils_1 = require("../utils");
10
+ const error_1 = require("../error");
11
+ const track_1 = require("../track");
12
+ const lifecycleHooks = require("./lifecycleHooks");
13
+ const previews_1 = require("../previews");
14
+ const HostingTarget = require("./hosting");
15
+ const DatabaseTarget = require("./database");
16
+ const FirestoreTarget = require("./firestore");
17
+ const FunctionsTarget = require("./functions");
18
+ const StorageTarget = require("./storage");
19
+ const RemoteConfigTarget = require("./remoteconfig");
20
+ const ExtensionsTarget = require("./extensions");
21
+ const TARGETS = {
22
+ hosting: HostingTarget,
23
+ database: DatabaseTarget,
24
+ firestore: FirestoreTarget,
25
+ functions: FunctionsTarget,
26
+ storage: StorageTarget,
27
+ remoteconfig: RemoteConfigTarget,
28
+ extensions: ExtensionsTarget,
19
29
  };
20
- var _noop = function () {
21
- return Promise.resolve();
22
- };
23
- var _chain = function (fns, context, options, payload) {
24
- var latest = (fns.shift() || _noop)(context, options, payload);
25
- if (fns.length) {
26
- return latest.then(function () {
27
- return _chain(fns, context, options, payload);
28
- });
30
+ const chain = async function (fns, context, options, payload) {
31
+ for (const latest of fns) {
32
+ await latest(context, options, payload);
29
33
  }
30
- return latest;
31
34
  };
32
- var deploy = function (targetNames, options, customContext = {}) {
33
- var projectId = needProjectId(options);
34
- var payload = {};
35
- var context = Object.assign({ projectId }, customContext);
36
- var predeploys = [];
37
- var prepares = [];
38
- var deploys = [];
39
- var releases = [];
40
- var postdeploys = [];
41
- var startTime = Date.now();
42
- for (var i = 0; i < targetNames.length; i++) {
43
- var targetName = targetNames[i];
44
- var target = TARGETS[targetName];
35
+ const deploy = async function (targetNames, options, customContext = {}) {
36
+ const projectId = (0, projectUtils_1.needProjectId)(options);
37
+ const payload = {};
38
+ const context = Object.assign({ projectId }, customContext);
39
+ const predeploys = [];
40
+ const prepares = [];
41
+ const deploys = [];
42
+ const releases = [];
43
+ const postdeploys = [];
44
+ const startTime = Date.now();
45
+ if (previews_1.previews.frameworkawareness && targetNames.includes("hosting")) {
46
+ const config = options.config.get("hosting");
47
+ if (Array.isArray(config) ? config.some((it) => it.source) : config.source) {
48
+ await require("firebase-frameworks").prepare(targetNames, context, options);
49
+ }
50
+ }
51
+ for (const targetName of targetNames) {
52
+ const target = TARGETS[targetName];
45
53
  if (!target) {
46
- return Promise.reject(new FirebaseError(clc.bold(targetName) + " is not a valid deploy target", { exit: 1 }));
54
+ return Promise.reject(new error_1.FirebaseError((0, cli_color_1.bold)(targetName) + " is not a valid deploy target", { exit: 1 }));
47
55
  }
48
56
  predeploys.push(lifecycleHooks(targetName, "predeploy"));
49
- if (target.prepare) {
50
- prepares.push(target.prepare);
51
- }
52
- if (target.deploy) {
53
- deploys.push(target.deploy);
54
- }
55
- if (target.release) {
56
- releases.push(target.release);
57
- }
57
+ prepares.push(target.prepare);
58
+ deploys.push(target.deploy);
59
+ releases.push(target.release);
58
60
  postdeploys.push(lifecycleHooks(targetName, "postdeploy"));
59
61
  }
60
- logger.info();
61
- logger.info(clc.bold(clc.white("===") + " Deploying to '" + projectId + "'..."));
62
- logger.info();
63
- utils.logBullet("deploying " + clc.bold(targetNames.join(", ")));
64
- return _chain(predeploys, context, options, payload)
65
- .then(function () {
66
- return _chain(prepares, context, options, payload);
67
- })
68
- .then(function () {
69
- return _chain(deploys, context, options, payload);
70
- })
71
- .then(function () {
72
- return _chain(releases, context, options, payload);
73
- })
74
- .then(function () {
75
- return _chain(postdeploys, context, options, payload);
76
- })
77
- .then(function () {
78
- if (_.has(options, "config.notes.databaseRules")) {
79
- return track("Rules Deploy", options.config.notes.databaseRules);
80
- }
81
- return;
82
- })
83
- .then(function () {
84
- const duration = Date.now() - startTime;
85
- return track("Product Deploy", [...targetNames].sort().join(","), duration);
86
- })
87
- .then(function () {
88
- logger.info();
89
- utils.logSuccess(clc.underline.bold("Deploy complete!"));
90
- logger.info();
91
- var deployedHosting = _.includes(targetNames, "hosting");
92
- logger.info(clc.bold("Project Console:"), utils.consoleUrl(options.project, "/overview"));
93
- if (deployedHosting) {
94
- _.each(context.hosting.deploys, function (deploy) {
95
- logger.info(clc.bold("Hosting URL:"), utils.addSubdomain(api.hostingOrigin, deploy.site));
96
- });
97
- const versionNames = context.hosting.deploys.map((deploy) => deploy.version);
98
- return { hosting: versionNames.length === 1 ? versionNames[0] : versionNames };
99
- }
100
- });
62
+ logger_1.logger.info();
63
+ logger_1.logger.info((0, cli_color_1.bold)((0, cli_color_1.white)("===") + " Deploying to '" + projectId + "'..."));
64
+ logger_1.logger.info();
65
+ (0, utils_1.logBullet)("deploying " + (0, cli_color_1.bold)(targetNames.join(", ")));
66
+ await chain(predeploys, context, options, payload);
67
+ await chain(prepares, context, options, payload);
68
+ await chain(deploys, context, options, payload);
69
+ await chain(releases, context, options, payload);
70
+ await chain(postdeploys, context, options, payload);
71
+ if ((0, lodash_1.has)(options, "config.notes.databaseRules")) {
72
+ await (0, track_1.track)("Rules Deploy", options.config.notes.databaseRules);
73
+ }
74
+ const duration = Date.now() - startTime;
75
+ await (0, track_1.track)("Product Deploy", [...targetNames].sort().join(","), duration);
76
+ logger_1.logger.info();
77
+ (0, utils_1.logSuccess)(cli_color_1.bold.underline("Deploy complete!"));
78
+ logger_1.logger.info();
79
+ const deployedHosting = (0, lodash_1.includes)(targetNames, "hosting");
80
+ logger_1.logger.info((0, cli_color_1.bold)("Project Console:"), (0, utils_1.consoleUrl)(options.project, "/overview"));
81
+ if (deployedHosting) {
82
+ (0, lodash_1.each)(context.hosting.deploys, (deploy) => {
83
+ logger_1.logger.info((0, cli_color_1.bold)("Hosting URL:"), (0, utils_1.addSubdomain)(api_1.hostingOrigin, deploy.site));
84
+ });
85
+ const versionNames = context.hosting.deploys.map((deploy) => deploy.version);
86
+ return { hosting: versionNames.length === 1 ? versionNames[0] : versionNames };
87
+ }
88
+ else {
89
+ return { hosting: undefined };
90
+ }
101
91
  };
102
- deploy.TARGETS = TARGETS;
103
- module.exports = deploy;
92
+ exports.deploy = deploy;
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ async function default_1() { }
4
+ exports.default = default_1;
@@ -1,7 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.release = exports.prepare = void 0;
3
+ exports.deploy = exports.release = exports.prepare = void 0;
4
4
  const prepare_1 = require("./prepare");
5
5
  exports.prepare = prepare_1.default;
6
6
  const release_1 = require("./release");
7
7
  exports.release = release_1.default;
8
+ const deploy_1 = require("./deploy");
9
+ exports.deploy = deploy_1.default;
@@ -62,8 +62,12 @@ class AuthCloudFunction {
62
62
  phoneNumber: user.phoneNumber,
63
63
  disabled: user.disabled,
64
64
  metadata: {
65
- creationTime: user.createdAt,
66
- lastSignInTime: user.lastLoginAt,
65
+ creationTime: user.createdAt
66
+ ? new Date(parseInt(user.createdAt, 10)).toISOString()
67
+ : undefined,
68
+ lastSignInTime: user.lastLoginAt
69
+ ? new Date(parseInt(user.lastLoginAt, 10)).toISOString()
70
+ : undefined,
67
71
  },
68
72
  customClaims: JSON.parse(user.customAttributes || "{}"),
69
73
  providerData: user.providerUserInfo,
@@ -39,6 +39,7 @@ exports.authOperations = {
39
39
  projects: {
40
40
  createSessionCookie,
41
41
  queryAccounts,
42
+ getConfig,
42
43
  updateConfig,
43
44
  accounts: {
44
45
  _: signUp,
@@ -1209,7 +1210,6 @@ function grantToken(state, reqBody) {
1209
1210
  (0, errors_1.assert)(reqBody.grantType === "refresh_token", "INVALID_GRANT_TYPE");
1210
1211
  (0, errors_1.assert)(reqBody.refreshToken, "MISSING_REFRESH_TOKEN");
1211
1212
  const refreshTokenRecord = state.validateRefreshToken(reqBody.refreshToken);
1212
- (0, errors_1.assert)(refreshTokenRecord, "INVALID_REFRESH_TOKEN");
1213
1213
  (0, errors_1.assert)(!refreshTokenRecord.user.disabled, "USER_DISABLED");
1214
1214
  const tokens = issueTokens(state, refreshTokenRecord.user, refreshTokenRecord.provider, {
1215
1215
  extraClaims: refreshTokenRecord.extraClaims,
@@ -1380,6 +1380,10 @@ function mfaSignInFinalize(state, reqBody) {
1380
1380
  refreshToken,
1381
1381
  };
1382
1382
  }
1383
+ function getConfig(state, reqBody, ctx) {
1384
+ (0, errors_1.assert)(state instanceof state_1.AgentProjectState, "((Can only get top-level configurations on agent projects.))");
1385
+ return state.config;
1386
+ }
1383
1387
  function updateConfig(state, reqBody, ctx) {
1384
1388
  var _a;
1385
1389
  (0, errors_1.assert)(state instanceof state_1.AgentProjectState, "((Can only update top-level configurations on agent projects.))");
@@ -342,7 +342,7 @@ function toExegesisController(ops, getProjectStateById) {
342
342
  }
343
343
  function toExegesisOperation(operation) {
344
344
  return (ctx) => {
345
- var _a, _b, _c, _d, _e, _f, _g;
345
+ var _a, _b, _c, _d, _e, _f, _g, _h;
346
346
  let targetProjectId = ctx.params.path.targetProjectId || ((_a = ctx.requestBody) === null || _a === void 0 ? void 0 : _a.targetProjectId);
347
347
  if (targetProjectId) {
348
348
  if ((_b = ctx.api.operationObject.security) === null || _b === void 0 ? void 0 : _b.some((sec) => sec.Oauth2)) {
@@ -365,6 +365,13 @@ function toExegesisController(ops, getProjectStateById) {
365
365
  }
366
366
  targetTenantId = targetTenantId || (decoded === null || decoded === void 0 ? void 0 : decoded.payload.firebase.tenant);
367
367
  }
368
+ if ((_h = ctx.requestBody) === null || _h === void 0 ? void 0 : _h.refreshToken) {
369
+ const refreshTokenRecord = (0, state_1.decodeRefreshToken)(ctx.requestBody.refreshToken);
370
+ if (refreshTokenRecord.tenantId && targetTenantId) {
371
+ (0, errors_2.assert)(refreshTokenRecord.tenantId === targetTenantId, "TENANT_ID_MISMATCH: ((Refresh token tenant ID does not match target tenant ID.))");
372
+ }
373
+ targetTenantId = targetTenantId || refreshTokenRecord.tenantId;
374
+ }
368
375
  return operation(getProjectStateById(targetProjectId, targetTenantId), ctx.requestBody, ctx);
369
376
  };
370
377
  }