firebase-tools 11.1.0 → 11.2.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 (101) hide show
  1. package/lib/accountExporter.js +11 -4
  2. package/lib/accountImporter.js +5 -6
  3. package/lib/appdistribution/client.js +7 -9
  4. package/lib/auth.js +3 -5
  5. package/lib/checkValidTargetFilters.js +28 -18
  6. package/lib/commands/database-profile.js +2 -3
  7. package/lib/commands/database-push.js +2 -3
  8. package/lib/commands/database-remove.js +1 -2
  9. package/lib/commands/database-set.js +1 -2
  10. package/lib/commands/deploy.js +5 -6
  11. package/lib/commands/ext-dev-emulators-exec.js +1 -1
  12. package/lib/commands/ext-dev-emulators-start.js +1 -1
  13. package/lib/commands/ext-dev-list.js +6 -7
  14. package/lib/commands/ext-export.js +2 -0
  15. package/lib/commands/ext-info.js +12 -13
  16. package/lib/commands/ext.js +2 -3
  17. package/lib/commands/functions-delete.js +1 -7
  18. package/lib/commands/open.js +5 -6
  19. package/lib/commands/serve.js +3 -5
  20. package/lib/commands/use.js +2 -3
  21. package/lib/config.js +4 -3
  22. package/lib/deploy/database/prepare.js +2 -3
  23. package/lib/deploy/extensions/planner.js +1 -0
  24. package/lib/deploy/extensions/prepare.js +18 -1
  25. package/lib/deploy/extensions/release.js +4 -0
  26. package/lib/deploy/extensions/secrets.js +3 -3
  27. package/lib/deploy/functions/build.js +35 -53
  28. package/lib/deploy/functions/ensure.js +1 -11
  29. package/lib/deploy/functions/params.js +189 -0
  30. package/lib/deploy/functions/prepare.js +3 -13
  31. package/lib/deploy/functions/prepareFunctionsUpload.js +2 -3
  32. package/lib/deploy/functions/release/fabricator.js +0 -1
  33. package/lib/deploy/functions/release/index.js +1 -5
  34. package/lib/deploy/functions/runtimes/discovery/index.js +18 -3
  35. package/lib/deploy/functions/runtimes/discovery/v1alpha1.js +3 -2
  36. package/lib/deploy/functions/runtimes/golang/index.js +2 -22
  37. package/lib/deploy/functions/runtimes/node/index.js +3 -7
  38. package/lib/deploy/functions/runtimes/node/parseTriggers.js +2 -2
  39. package/lib/deploy/lifecycleHooks.js +8 -11
  40. package/lib/deploy/storage/prepare.js +2 -2
  41. package/lib/emulator/auth/index.js +1 -1
  42. package/lib/emulator/auth/operations.js +336 -64
  43. package/lib/emulator/auth/server.js +2 -2
  44. package/lib/emulator/auth/state.js +32 -7
  45. package/lib/emulator/commandUtils.js +1 -1
  46. package/lib/emulator/constants.js +1 -1
  47. package/lib/emulator/controller.js +6 -5
  48. package/lib/emulator/databaseEmulator.js +2 -2
  49. package/lib/emulator/download.js +1 -1
  50. package/lib/emulator/downloadableEmulators.js +6 -6
  51. package/lib/emulator/events/types.js +2 -3
  52. package/lib/emulator/firestoreEmulator.js +2 -2
  53. package/lib/emulator/functionsEmulator.js +36 -45
  54. package/lib/emulator/functionsEmulatorRuntime.js +12 -16
  55. package/lib/emulator/functionsEmulatorShared.js +7 -5
  56. package/lib/emulator/functionsRuntimeWorker.js +0 -6
  57. package/lib/emulator/hostingEmulator.js +1 -1
  58. package/lib/emulator/hub.js +1 -1
  59. package/lib/emulator/loggingEmulator.js +1 -1
  60. package/lib/emulator/pubsubEmulator.js +1 -1
  61. package/lib/emulator/storage/crc.js +4 -4
  62. package/lib/emulator/storage/index.js +1 -1
  63. package/lib/emulator/types.js +1 -1
  64. package/lib/extensions/askUserForConsent.js +1 -2
  65. package/lib/extensions/askUserForParam.js +15 -18
  66. package/lib/extensions/emulator/optionsHelper.js +4 -4
  67. package/lib/extensions/etags.js +28 -0
  68. package/lib/extensions/extensionsApi.js +1 -22
  69. package/lib/extensions/extensionsHelper.js +6 -6
  70. package/lib/extensions/listExtensions.js +9 -10
  71. package/lib/extensions/manifest.js +2 -2
  72. package/lib/extensions/resolveSource.js +11 -7
  73. package/lib/extensions/secretsUtils.js +3 -3
  74. package/lib/extensions/types.js +24 -0
  75. package/lib/extensions/updateHelper.js +1 -1
  76. package/lib/extensions/utils.js +1 -2
  77. package/lib/extensions/warnings.js +10 -4
  78. package/lib/firestore/encodeFirestoreValue.js +11 -8
  79. package/lib/fsAsync.js +3 -3
  80. package/lib/functions/env.js +5 -1
  81. package/lib/functionsConfig.js +18 -15
  82. package/lib/functionsConfigClone.js +10 -12
  83. package/lib/gcp/cloudfunctions.js +2 -15
  84. package/lib/gcp/rules.js +3 -4
  85. package/lib/gcp/runtimeconfig.js +2 -2
  86. package/lib/hosting/api.js +9 -11
  87. package/lib/hosting/expireUtils.js +2 -2
  88. package/lib/hosting/proxy.js +1 -1
  89. package/lib/init/features/hosting/github.js +1 -1
  90. package/lib/init/features/hosting/index.js +2 -2
  91. package/lib/localFunction.js +4 -4
  92. package/lib/management/projects.js +6 -7
  93. package/lib/previews.js +1 -1
  94. package/lib/profileReport.js +24 -22
  95. package/lib/prompt.js +1 -2
  96. package/lib/rc.js +12 -2
  97. package/lib/rulesDeploy.js +2 -2
  98. package/lib/serve/index.js +4 -5
  99. package/lib/utils.js +30 -6
  100. package/npm-shrinkwrap.json +2 -2
  101. package/package.json +10 -9
package/lib/config.js CHANGED
@@ -18,6 +18,7 @@ const loadCJSON_1 = require("./loadCJSON");
18
18
  const parseBoltRules = require("./parseBoltRules");
19
19
  class Config {
20
20
  constructor(src, options = {}) {
21
+ var _a;
21
22
  this.data = {};
22
23
  this.defaults = {};
23
24
  this.notes = {};
@@ -31,8 +32,8 @@ class Config {
31
32
  clc.bold("firebase use --add") +
32
33
  " instead");
33
34
  }
34
- if (_.has(this._src, "rules")) {
35
- _.set(this._src, "database.rules", this._src.rules);
35
+ if ((_a = this._src) === null || _a === void 0 ? void 0 : _a.rules) {
36
+ this._src.database = Object.assign(Object.assign({}, this._src.database), { rules: this._src.rules });
36
37
  }
37
38
  Config.MATERIALIZE_TARGETS.forEach((target) => {
38
39
  if (_.get(this._src, target)) {
@@ -58,7 +59,7 @@ class Config {
58
59
  let out = this.parseFile(target, val);
59
60
  const segments = target.split(".");
60
61
  const lastSegment = segments[segments.length - 1];
61
- if (Object.keys(out).length === 1 && _.has(out, lastSegment)) {
62
+ if (Object.keys(out).length === 1 && out[lastSegment]) {
62
63
  out = out[lastSegment];
63
64
  }
64
65
  return out;
@@ -1,7 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.prepare = void 0;
4
- const _ = require("lodash");
5
4
  const clc = require("cli-color");
6
5
  const path = require("path");
7
6
  const error_1 = require("../../error");
@@ -24,7 +23,7 @@ function prepare(context, options) {
24
23
  ruleFiles[ruleConfig.rules] = null;
25
24
  deploys.push(ruleConfig);
26
25
  });
27
- _.forEach(ruleFiles, (v, file) => {
26
+ for (const file of Object.keys(ruleFiles)) {
28
27
  switch (path.extname(file)) {
29
28
  case ".json":
30
29
  ruleFiles[file] = options.config.readProjectFile(file);
@@ -35,7 +34,7 @@ function prepare(context, options) {
35
34
  default:
36
35
  throw new error_1.FirebaseError("Unexpected rules format " + path.extname(file));
37
36
  }
38
- });
37
+ }
39
38
  context.database = {
40
39
  deploys: deploys,
41
40
  ruleFiles: ruleFiles,
@@ -54,6 +54,7 @@ async function have(projectId) {
54
54
  params: i.config.params,
55
55
  allowedEventTypes: i.config.allowedEventTypes,
56
56
  eventarcChannel: i.config.eventarcChannel,
57
+ etag: i.etag,
57
58
  };
58
59
  if (i.config.extensionRef) {
59
60
  const ref = refs.parse(i.config.extensionRef);
@@ -13,6 +13,7 @@ const extensionsHelper_1 = require("../../extensions/extensionsHelper");
13
13
  const secretsUtils_1 = require("../../extensions/secretsUtils");
14
14
  const secrets_1 = require("./secrets");
15
15
  const warnings_1 = require("../../extensions/warnings");
16
+ const etags_1 = require("../../extensions/etags");
16
17
  async function prepare(context, options, payload) {
17
18
  var _a;
18
19
  const projectId = (0, projectUtils_1.needProjectId)(options);
@@ -28,6 +29,22 @@ async function prepare(context, options, payload) {
28
29
  projectDir: options.config.projectDir,
29
30
  extensions: options.config.get("extensions"),
30
31
  });
32
+ const etagsChanged = (0, etags_1.detectEtagChanges)(options.rc, projectId, context.have);
33
+ if (etagsChanged.length) {
34
+ (0, warnings_1.outOfBandChangesWarning)(etagsChanged);
35
+ if (!options.force && options.nonInteractive) {
36
+ throw new error_1.FirebaseError("Pass the --force flag to overwrite out of band changes in non-interactive mode");
37
+ }
38
+ else if (!options.force &&
39
+ !options.nonInteractive &&
40
+ !(await prompt.promptOnce({
41
+ type: "confirm",
42
+ message: `Do you wish to continue deploying these extension instances?`,
43
+ default: false,
44
+ }))) {
45
+ throw new error_1.FirebaseError("Deployment cancelled");
46
+ }
47
+ }
31
48
  const usingSecrets = await Promise.all((_a = context.want) === null || _a === void 0 ? void 0 : _a.map(secrets_1.checkSpecForSecrets));
32
49
  if (usingSecrets.some((i) => i)) {
33
50
  await (0, secretsUtils_1.ensureSecretManagerApiEnabled)(options);
@@ -44,7 +61,7 @@ async function prepare(context, options, payload) {
44
61
  !options.nonInteractive &&
45
62
  !(await prompt.promptOnce({
46
63
  type: "confirm",
47
- message: `Do you wish to continue deploying these extensions?`,
64
+ message: `Do you wish to continue deploying these extension instances?`,
48
65
  default: true,
49
66
  }))) {
50
67
  throw new error_1.FirebaseError("Deployment cancelled");
@@ -3,9 +3,11 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.release = void 0;
4
4
  const queue_1 = require("../../throttler/queue");
5
5
  const tasks = require("./tasks");
6
+ const planner = require("./planner");
6
7
  const error_1 = require("../../error");
7
8
  const errors_1 = require("./errors");
8
9
  const projectUtils_1 = require("../../projectUtils");
10
+ const etags_1 = require("../../extensions/etags");
9
11
  async function release(context, options, payload) {
10
12
  var _a, _b, _c, _d;
11
13
  const projectId = (0, projectUtils_1.needProjectId)(options);
@@ -35,6 +37,8 @@ async function release(context, options, payload) {
35
37
  deploymentQueue.process();
36
38
  deploymentQueue.close();
37
39
  await deploymentPromise;
40
+ const newHave = await planner.have(projectId);
41
+ (0, etags_1.saveEtags)(options.rc, projectId, newHave);
38
42
  if (errorHandler.hasErrors()) {
39
43
  errorHandler.print();
40
44
  throw new error_1.FirebaseError(`Extensions deployment failed.`);
@@ -6,7 +6,7 @@ const secretUtils = require("../../extensions/secretsUtils");
6
6
  const secretManager = require("../../gcp/secretManager");
7
7
  const planner_1 = require("./planner");
8
8
  const askUserForParam_1 = require("../../extensions/askUserForParam");
9
- const extensionsApi_1 = require("../../extensions/extensionsApi");
9
+ const types_1 = require("../../extensions/types");
10
10
  const error_1 = require("../../error");
11
11
  const logger_1 = require("../../logger");
12
12
  const utils_1 = require("../../utils");
@@ -34,7 +34,7 @@ async function checkSpecForSecrets(i) {
34
34
  }
35
35
  exports.checkSpecForSecrets = checkSpecForSecrets;
36
36
  const secretsInSpec = (spec) => {
37
- return spec.params.filter((p) => p.type === extensionsApi_1.ParamType.SECRET);
37
+ return spec.params.filter((p) => p.type === types_1.ParamType.SECRET);
38
38
  };
39
39
  async function handleSecretsCreateInstance(i, nonInteractive) {
40
40
  const extensionVersion = await (0, planner_1.getExtensionVersion)(i);
@@ -49,7 +49,7 @@ async function handleSecretsUpdateInstance(i, prevSpec, nonInteractive) {
49
49
  const secretParams = secretsInSpec(extensionVersion.spec);
50
50
  for (const s of secretParams) {
51
51
  const prevParam = prevExtensionVersion.spec.params.find((p) => p.param === s.param);
52
- if ((prevParam === null || prevParam === void 0 ? void 0 : prevParam.type) === extensionsApi_1.ParamType.SECRET && prevSpec.params[prevParam === null || prevParam === void 0 ? void 0 : prevParam.param]) {
52
+ if ((prevParam === null || prevParam === void 0 ? void 0 : prevParam.type) === types_1.ParamType.SECRET && prevSpec.params[prevParam === null || prevParam === void 0 ? void 0 : prevParam.param]) {
53
53
  await handleSecretParamForUpdate(s, i, prevSpec.params[prevParam === null || prevParam === void 0 ? void 0 : prevParam.param], nonInteractive);
54
54
  }
55
55
  else {
@@ -1,9 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.resolveBackend = exports.of = exports.empty = void 0;
3
+ exports.toBackend = exports.resolveBackend = exports.of = exports.empty = void 0;
4
4
  const backend = require("./backend");
5
5
  const proto = require("../../gcp/proto");
6
6
  const api = require("../../.../../api");
7
+ const params = require("./params");
8
+ const previews_1 = require("../../previews");
7
9
  const error_1 = require("../../error");
8
10
  const functional_1 = require("../../functional");
9
11
  function empty() {
@@ -20,45 +22,19 @@ function of(endpoints) {
20
22
  return build;
21
23
  }
22
24
  exports.of = of;
23
- function resolveInt(from) {
24
- if (from == null) {
25
- return 0;
26
- }
27
- else if (typeof from === "string") {
28
- throw new error_1.FirebaseError("CEL evaluation of expression '" + from + "' not yet supported");
29
- }
30
- return from;
31
- }
32
- function resolveString(from) {
33
- if (from == null) {
34
- return "";
35
- }
36
- else if (from.includes("{{") && from.includes("}}")) {
37
- throw new error_1.FirebaseError("CEL evaluation of expression '" + from + "' not yet supported");
38
- }
39
- return from;
40
- }
41
- function resolveBoolean(from) {
42
- if (from == null) {
43
- return false;
44
- }
45
- else if (typeof from === "string") {
46
- throw new error_1.FirebaseError("CEL evaluation of expression '" + from + "' not yet supported");
47
- }
48
- return from;
49
- }
50
25
  function isMemoryOption(value) {
51
26
  return value == null || [128, 256, 512, 1024, 2048, 4096, 8192].includes(value);
52
27
  }
53
- function resolveBackend(build, userEnvs) {
54
- for (const param of build.params) {
55
- const expectedEnv = param.param;
56
- if (!userEnvs.hasOwnProperty(expectedEnv)) {
57
- throw new error_1.FirebaseError("Build specified parameter " +
58
- expectedEnv +
59
- " but it was not present in the user dotenv files or Cloud Secret Manager");
60
- }
28
+ async function resolveBackend(build, userEnvOpt, userEnvs) {
29
+ const projectId = userEnvOpt.projectId;
30
+ let paramValues = {};
31
+ if (previews_1.previews.functionsparams) {
32
+ paramValues = await params.resolveParams(build.params, projectId, userEnvs);
61
33
  }
34
+ return toBackend(build, paramValues);
35
+ }
36
+ exports.resolveBackend = resolveBackend;
37
+ function toBackend(build, paramValues) {
62
38
  const bkEndpoints = [];
63
39
  for (const endpointId of Object.keys(build.endpoints)) {
64
40
  const bdEndpoint = build.endpoints[endpointId];
@@ -67,7 +43,7 @@ function resolveBackend(build, userEnvs) {
67
43
  regions = [api.functionsDefaultRegion];
68
44
  }
69
45
  for (const region of regions) {
70
- const trigger = discoverTrigger(bdEndpoint);
46
+ const trigger = discoverTrigger(bdEndpoint, paramValues);
71
47
  if (typeof bdEndpoint.platform === "undefined") {
72
48
  throw new error_1.FirebaseError("platform can't be undefined");
73
49
  }
@@ -76,25 +52,30 @@ function resolveBackend(build, userEnvs) {
76
52
  }
77
53
  let timeout;
78
54
  if (bdEndpoint.timeoutSeconds) {
79
- timeout = resolveInt(bdEndpoint.timeoutSeconds);
55
+ timeout = params.resolveInt(bdEndpoint.timeoutSeconds, paramValues);
80
56
  }
81
57
  else {
82
58
  timeout = 60;
83
59
  }
84
60
  const bkEndpoint = Object.assign({ id: endpointId, project: bdEndpoint.project, region: region, entryPoint: bdEndpoint.entryPoint, platform: bdEndpoint.platform, runtime: bdEndpoint.runtime, timeoutSeconds: timeout }, trigger);
85
- proto.renameIfPresent(bkEndpoint, bdEndpoint, "maxInstances", "maxInstances", resolveInt);
86
- proto.renameIfPresent(bkEndpoint, bdEndpoint, "minInstances", "minInstances", resolveInt);
87
- proto.renameIfPresent(bkEndpoint, bdEndpoint, "concurrency", "concurrency", resolveInt);
61
+ proto.renameIfPresent(bkEndpoint, bdEndpoint, "maxInstances", "maxInstances", (from) => {
62
+ return params.resolveInt(from, paramValues);
63
+ });
64
+ proto.renameIfPresent(bkEndpoint, bdEndpoint, "minInstances", "minInstances", (from) => {
65
+ return params.resolveInt(from, paramValues);
66
+ });
67
+ proto.renameIfPresent(bkEndpoint, bdEndpoint, "concurrency", "concurrency", (from) => {
68
+ return params.resolveInt(from, paramValues);
69
+ });
88
70
  proto.copyIfPresent(bkEndpoint, bdEndpoint, "ingressSettings", "availableMemoryMb", "environmentVariables", "labels");
89
71
  proto.copyIfPresent(bkEndpoint, bdEndpoint, "secretEnvironmentVariables");
90
72
  if (bdEndpoint.vpc) {
91
- bkEndpoint.vpc = {
92
- connector: resolveString(bdEndpoint.vpc.connector).replace("$REGION", region),
93
- };
73
+ bkEndpoint.vpc = { connector: params.resolveString(bdEndpoint.vpc.connector, paramValues) };
94
74
  proto.copyIfPresent(bkEndpoint.vpc, bdEndpoint.vpc, "egressSettings");
95
75
  }
96
- if (bdEndpoint.serviceAccount) {
97
- bkEndpoint.serviceAccountEmail = bdEndpoint.serviceAccount;
76
+ proto.renameIfPresent(bkEndpoint, bdEndpoint, "serviceAccountEmail", "serviceAccount");
77
+ if ("serviceAccountEmail" in bkEndpoint && !bdEndpoint.serviceAccount) {
78
+ delete bkEndpoint.serviceAccountEmail;
98
79
  }
99
80
  bkEndpoints.push(bkEndpoint);
100
81
  }
@@ -103,8 +84,11 @@ function resolveBackend(build, userEnvs) {
103
84
  bkend.requiredAPIs = build.requiredAPIs;
104
85
  return bkend;
105
86
  }
106
- exports.resolveBackend = resolveBackend;
107
- function discoverTrigger(endpoint) {
87
+ exports.toBackend = toBackend;
88
+ function discoverTrigger(endpoint, paramValues) {
89
+ const resolveInt = (from) => params.resolveInt(from, paramValues);
90
+ const resolveString = (from) => params.resolveString(from, paramValues);
91
+ const resolveBoolean = (from) => params.resolveBoolean(from, paramValues);
108
92
  let trigger;
109
93
  if ("httpsTrigger" in endpoint) {
110
94
  const bkHttps = {};
@@ -121,15 +105,13 @@ function discoverTrigger(endpoint) {
121
105
  }
122
106
  else if ("eventTrigger" in endpoint) {
123
107
  const bkEventFilters = {};
124
- for (const key in endpoint.eventTrigger.eventFilters) {
125
- if (typeof key === "string") {
126
- bkEventFilters[key] = resolveString(endpoint.eventTrigger.eventFilters[key]);
127
- }
108
+ for (const [key, value] of Object.entries(endpoint.eventTrigger.eventFilters)) {
109
+ bkEventFilters[key] = params.resolveString(value, paramValues);
128
110
  }
129
111
  const bkEvent = {
130
112
  eventType: endpoint.eventTrigger.eventType,
131
113
  eventFilters: bkEventFilters,
132
- retry: resolveBoolean(endpoint.eventTrigger.retry),
114
+ retry: resolveBoolean(endpoint.eventTrigger.retry || false),
133
115
  };
134
116
  if (endpoint.eventTrigger.serviceAccount) {
135
117
  bkEvent.serviceAccountEmail = endpoint.eventTrigger.serviceAccount;
@@ -1,17 +1,15 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.secretAccess = exports.maybeEnableAR = exports.cloudBuildEnabled = exports.defaultServiceAccount = void 0;
3
+ exports.secretAccess = exports.cloudBuildEnabled = exports.defaultServiceAccount = void 0;
4
4
  const clc = require("cli-color");
5
5
  const ensureApiEnabled_1 = require("../../ensureApiEnabled");
6
6
  const error_1 = require("../../error");
7
7
  const utils_1 = require("../../utils");
8
8
  const secretManager_1 = require("../../gcp/secretManager");
9
- const previews_1 = require("../../previews");
10
9
  const projects_1 = require("../../management/projects");
11
10
  const functional_1 = require("../../functional");
12
11
  const track_1 = require("../../track");
13
12
  const backend = require("./backend");
14
- const ensureApiEnabled = require("../../ensureApiEnabled");
15
13
  const FAQ_URL = "https://firebase.google.com/support/faq#functions-runtime";
16
14
  const CLOUD_BUILD_API = "cloudbuild.googleapis.com";
17
15
  async function defaultServiceAccount(e) {
@@ -66,14 +64,6 @@ async function cloudBuildEnabled(projectId) {
66
64
  }
67
65
  }
68
66
  exports.cloudBuildEnabled = cloudBuildEnabled;
69
- async function maybeEnableAR(projectId) {
70
- if (!previews_1.previews.artifactregistry) {
71
- return ensureApiEnabled.check(projectId, "artifactregistry.googleapis.com", "functions", true);
72
- }
73
- await ensureApiEnabled.ensure(projectId, "artifactregistry.googleapis.com", "functions");
74
- return true;
75
- }
76
- exports.maybeEnableAR = maybeEnableAR;
77
67
  async function secretsToServiceAccounts(b) {
78
68
  const secretsToSa = {};
79
69
  for (const e of backend.allEndpoints(b)) {
@@ -0,0 +1,189 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.resolveParams = exports.resolveBoolean = exports.resolveString = exports.resolveInt = void 0;
4
+ const logger_1 = require("../../logger");
5
+ const error_1 = require("../../error");
6
+ const prompt_1 = require("../../prompt");
7
+ const functional_1 = require("../../functional");
8
+ function isCEL(expr) {
9
+ return typeof expr === "string" && expr.includes("{{") && expr.includes("}}");
10
+ }
11
+ function dependenciesCEL(expr) {
12
+ const deps = [];
13
+ const paramCapture = /{{ params\.(\w+) }}/g;
14
+ let match;
15
+ while ((match = paramCapture.exec(expr)) != null) {
16
+ deps.push(match[1]);
17
+ }
18
+ return deps;
19
+ }
20
+ function resolveInt(from, paramValues) {
21
+ if (typeof from === "number") {
22
+ return from;
23
+ }
24
+ const match = /\A{{ params\.(\w+) }}\z/.exec(from);
25
+ if (!match) {
26
+ throw new error_1.FirebaseError("CEL evaluation of expression '" + from + "' not yet supported");
27
+ }
28
+ const referencedParamValue = paramValues[match[1]];
29
+ if (typeof referencedParamValue !== "number") {
30
+ throw new error_1.FirebaseError("Referenced numeric parameter '" +
31
+ match +
32
+ "' resolved to non-number value " +
33
+ referencedParamValue);
34
+ }
35
+ return referencedParamValue;
36
+ }
37
+ exports.resolveInt = resolveInt;
38
+ function resolveString(from, paramValues) {
39
+ if (!isCEL(from)) {
40
+ return from;
41
+ }
42
+ let output = from;
43
+ const paramCapture = /{{ params\.(\w+) }}/g;
44
+ let match;
45
+ while ((match = paramCapture.exec(from)) != null) {
46
+ const referencedParamValue = paramValues[match[1]];
47
+ if (typeof referencedParamValue !== "string") {
48
+ throw new error_1.FirebaseError("Referenced string parameter '" +
49
+ match[1] +
50
+ "' resolved to non-string value " +
51
+ referencedParamValue);
52
+ }
53
+ output = output.replace(`{{ params.${match[1]} }}`, referencedParamValue);
54
+ }
55
+ if (isCEL(output)) {
56
+ throw new error_1.FirebaseError("CEL evaluation of non-identity expression '" + from + "' not yet supported");
57
+ }
58
+ return output;
59
+ }
60
+ exports.resolveString = resolveString;
61
+ function resolveBoolean(from, paramValues) {
62
+ if (typeof from === "string" && /{{ params\.(\w+) }}/.test(from)) {
63
+ const match = /{{ params\.(\w+) }}/.exec(from);
64
+ const referencedParamValue = paramValues[match[1]];
65
+ if (typeof referencedParamValue !== "boolean") {
66
+ throw new error_1.FirebaseError("Referenced boolean parameter '" +
67
+ match +
68
+ "' resolved to non-boolean value " +
69
+ referencedParamValue);
70
+ }
71
+ return referencedParamValue;
72
+ }
73
+ else if (typeof from === "string") {
74
+ throw new error_1.FirebaseError("CEL evaluation of expression '" + from + "' not yet supported");
75
+ }
76
+ return from;
77
+ }
78
+ exports.resolveBoolean = resolveBoolean;
79
+ function resolveDefaultCEL(type, expr, currentEnv) {
80
+ const deps = dependenciesCEL(expr);
81
+ const allDepsFound = deps.every((dep) => !!currentEnv[dep]);
82
+ if (!allDepsFound) {
83
+ throw new error_1.FirebaseError("Build specified parameter with un-resolvable default value " +
84
+ expr +
85
+ "; dependencies missing.");
86
+ }
87
+ switch (type) {
88
+ case "string":
89
+ return resolveString(expr, currentEnv);
90
+ case "int":
91
+ return resolveInt(expr, currentEnv);
92
+ default:
93
+ throw new error_1.FirebaseError("Build specified parameter with default " + expr + " of unsupported type");
94
+ }
95
+ }
96
+ function canSatisfyParam(param, value) {
97
+ if (param.type === "string") {
98
+ return typeof value === "string";
99
+ }
100
+ else if (param.type === "int") {
101
+ return typeof value === "number" && Number.isInteger(value);
102
+ }
103
+ (0, functional_1.assertExhaustive)(param);
104
+ }
105
+ async function resolveParams(params, projectId, userEnvs) {
106
+ const paramValues = {};
107
+ for (const param of params.filter((param) => userEnvs.hasOwnProperty(param.param))) {
108
+ if (!canSatisfyParam(param, userEnvs[param.param])) {
109
+ throw new error_1.FirebaseError("Parameter " +
110
+ param.param +
111
+ " resolved to value from dotenv files " +
112
+ userEnvs[param.param] +
113
+ " of wrong type");
114
+ }
115
+ paramValues[param.param] = userEnvs[param.param];
116
+ }
117
+ for (const param of params.filter((param) => !userEnvs.hasOwnProperty(param.param))) {
118
+ let paramDefault = param.default;
119
+ if (paramDefault && isCEL(paramDefault)) {
120
+ paramDefault = resolveDefaultCEL(param.type, paramDefault, paramValues);
121
+ }
122
+ if (paramDefault && !canSatisfyParam(param, paramDefault)) {
123
+ throw new error_1.FirebaseError("Parameter " + param.param + " has default value " + paramDefault + " of wrong type");
124
+ }
125
+ paramValues[param.param] = await promptParam(param, paramDefault);
126
+ }
127
+ return paramValues;
128
+ }
129
+ exports.resolveParams = resolveParams;
130
+ async function promptParam(param, resolvedDefault) {
131
+ if (param.type === "string") {
132
+ return promptStringParam(param, resolvedDefault);
133
+ }
134
+ else if (param.type === "int") {
135
+ return promptIntParam(param, resolvedDefault);
136
+ }
137
+ (0, functional_1.assertExhaustive)(param);
138
+ }
139
+ async function promptStringParam(param, resolvedDefault) {
140
+ if (!param.input) {
141
+ const defaultToText = { type: "text", text: {} };
142
+ param.input = defaultToText;
143
+ }
144
+ switch (param.input.type) {
145
+ case "select":
146
+ throw new error_1.FirebaseError("Build specified string parameter " + param.param + " with unsupported input type 'select'");
147
+ case "text":
148
+ default:
149
+ let prompt = `Enter a value for ${param.label || param.param}`;
150
+ if (param.description) {
151
+ prompt += ` \n(${param.description})`;
152
+ }
153
+ return await (0, prompt_1.promptOnce)({
154
+ name: param.param,
155
+ type: "input",
156
+ default: resolvedDefault,
157
+ message: prompt,
158
+ });
159
+ }
160
+ }
161
+ async function promptIntParam(param, resolvedDefault) {
162
+ if (!param.input) {
163
+ const defaultToText = { type: "text", text: {} };
164
+ param.input = defaultToText;
165
+ }
166
+ switch (param.input.type) {
167
+ case "select":
168
+ throw new error_1.FirebaseError("Build specified int parameter " + param.param + " with unsupported input type 'select'");
169
+ case "text":
170
+ default:
171
+ let prompt = `Enter a value for ${param.label || param.param}`;
172
+ if (param.description) {
173
+ prompt += ` \n(${param.description})`;
174
+ }
175
+ let res;
176
+ while (true) {
177
+ res = await (0, prompt_1.promptOnce)({
178
+ name: param.param,
179
+ type: "number",
180
+ default: resolvedDefault,
181
+ message: prompt,
182
+ });
183
+ if (Number.isInteger(res)) {
184
+ return res;
185
+ }
186
+ logger_1.logger.error(`${param.label || param.param} must be an integer; retrying...`);
187
+ }
188
+ }
189
+ }
@@ -21,7 +21,6 @@ const triggerRegionHelper_1 = require("./triggerRegionHelper");
21
21
  const checkIam_1 = require("./checkIam");
22
22
  const error_1 = require("../../error");
23
23
  const projectConfig_1 = require("../../functions/projectConfig");
24
- const previews_1 = require("../../previews");
25
24
  const v1_1 = require("../../functions/events/v1");
26
25
  const serviceusage_1 = require("../../gcp/serviceusage");
27
26
  function hasUserConfig(config) {
@@ -40,9 +39,8 @@ async function prepare(context, options, payload) {
40
39
  ensureApiEnabled.ensure(projectId, "cloudfunctions.googleapis.com", "functions"),
41
40
  ensureApiEnabled.check(projectId, "runtimeconfig.googleapis.com", "runtimeconfig", true),
42
41
  ensure.cloudBuildEnabled(projectId),
43
- ensure.maybeEnableAR(projectId),
42
+ ensureApiEnabled.ensure(projectId, "artifactregistry.googleapis.com", "artifactregistry"),
44
43
  ]);
45
- context.artifactRegistryEnabled = checkAPIsEnabled[3];
46
44
  const firebaseConfig = await functionsConfig.getFirebaseConfig(options);
47
45
  context.firebaseConfig = firebaseConfig;
48
46
  let runtimeConfig = { firebase: firebaseConfig };
@@ -79,15 +77,8 @@ async function prepare(context, options, payload) {
79
77
  };
80
78
  const userEnvs = functionsEnv.loadUserEnvs(userEnvOpt);
81
79
  const envs = Object.assign(Object.assign({}, userEnvs), firebaseEnvs);
82
- let wantBackend;
83
- if (previews_1.previews.functionsparams) {
84
- const wantBuild = await runtimeDelegate.discoverBuild(runtimeConfig, firebaseEnvs);
85
- wantBackend = build.resolveBackend(wantBuild, userEnvs);
86
- }
87
- else {
88
- logger_1.logger.debug(`Analyzing ${runtimeDelegate.name} backend spec`);
89
- wantBackend = await runtimeDelegate.discoverSpec(runtimeConfig, firebaseEnvs);
90
- }
80
+ const wantBuild = await runtimeDelegate.discoverBuild(runtimeConfig, firebaseEnvs);
81
+ const wantBackend = await build.resolveBackend(wantBuild, userEnvOpt, userEnvs);
91
82
  wantBackend.environmentVariables = envs;
92
83
  for (const endpoint of backend.allEndpoints(wantBackend)) {
93
84
  endpoint.environmentVariables = wantBackend.environmentVariables;
@@ -145,7 +136,6 @@ async function prepare(context, options, payload) {
145
136
  }));
146
137
  if (backend.someEndpoint(wantBackend, (e) => e.platform === "gcfv2")) {
147
138
  const V2_APIS = [
148
- "artifactregistry.googleapis.com",
149
139
  "run.googleapis.com",
150
140
  "eventarc.googleapis.com",
151
141
  "pubsub.googleapis.com",
@@ -1,7 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.prepareFunctionsUpload = exports.getFunctionsConfig = void 0;
4
- const _ = require("lodash");
5
4
  const archiver = require("archiver");
6
5
  const clc = require("cli-color");
7
6
  const filesize = require("filesize");
@@ -54,12 +53,12 @@ async function packageSource(sourceDir, config, runtimeConfig) {
54
53
  ignore.push("firebase-debug.log", "firebase-debug.*.log", CONFIG_DEST_FILE);
55
54
  try {
56
55
  const files = await fsAsync.readdirRecursive({ path: sourceDir, ignore: ignore });
57
- _.forEach(files, (file) => {
56
+ for (const file of files) {
58
57
  archive.file(file.name, {
59
58
  name: path.relative(sourceDir, file.name),
60
59
  mode: file.mode,
61
60
  });
62
- });
61
+ }
63
62
  if (typeof runtimeConfig !== "undefined") {
64
63
  archive.append(JSON.stringify(runtimeConfig, null, 2), {
65
64
  name: CONFIG_DEST_FILE,
@@ -36,7 +36,6 @@ const gcfV2PollerOptions = {
36
36
  masterTimeout: 25 * 60 * 1000,
37
37
  maxBackoff: 10000,
38
38
  };
39
- const DEFAULT_GCFV2_CONCURRENCY = 80;
40
39
  const rethrowAs = (endpoint, op) => (err) => {
41
40
  logger_1.logger.error(err.message);
42
41
  throw new reporter.DeploymentError(endpoint, op, err);
@@ -63,11 +63,7 @@ async function release(context, options, payload) {
63
63
  const deletedEndpoints = Object.values(plan)
64
64
  .map((r) => r.endpointsToDelete)
65
65
  .reduce(functional_1.reduceFlat, []);
66
- const opts = {};
67
- if (!context.artifactRegistryEnabled) {
68
- opts.ar = new containerCleaner.NoopArtifactRegistryCleaner();
69
- }
70
- await containerCleaner.cleanupBuildImages(haveEndpoints, deletedEndpoints, opts);
66
+ await containerCleaner.cleanupBuildImages(haveEndpoints, deletedEndpoints);
71
67
  const allErrors = summary.results.filter((r) => r.error).map((r) => r.error);
72
68
  if (allErrors.length) {
73
69
  const opts = allErrors.length === 1 ? { original: allErrors[0] } : { children: allErrors };
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.detectFromPort = exports.detectFromYaml = exports.yamlToBackend = exports.readFileAsync = void 0;
3
+ exports.detectFromPort = exports.detectFromYaml = exports.yamlToBuild = exports.yamlToBackend = exports.readFileAsync = void 0;
4
4
  const node_fetch_1 = require("node-fetch");
5
5
  const fs = require("fs");
6
6
  const path = require("path");
@@ -26,6 +26,21 @@ function yamlToBackend(yaml, project, region, runtime) {
26
26
  }
27
27
  }
28
28
  exports.yamlToBackend = yamlToBackend;
29
+ function yamlToBuild(yaml, project, region, runtime) {
30
+ try {
31
+ if (!yaml.specVersion) {
32
+ throw new error_1.FirebaseError("Expect manifest yaml to specify a version number");
33
+ }
34
+ if (yaml.specVersion === "v1alpha1") {
35
+ return v1alpha1.buildFromV1Alpha1(yaml, project, region, runtime);
36
+ }
37
+ throw new error_1.FirebaseError("It seems you are using a newer SDK than this version of the CLI can handle. Please update your CLI with `npm install -g firebase-tools`");
38
+ }
39
+ catch (err) {
40
+ throw new error_1.FirebaseError("Failed to parse build specification", { children: [err] });
41
+ }
42
+ }
43
+ exports.yamlToBuild = yamlToBuild;
29
44
  async function detectFromYaml(directory, project, runtime) {
30
45
  let text;
31
46
  try {
@@ -42,7 +57,7 @@ async function detectFromYaml(directory, project, runtime) {
42
57
  }
43
58
  logger_1.logger.debug("Found functions.yaml. Got spec:", text);
44
59
  const parsed = yaml.load(text);
45
- return yamlToBackend(parsed, project, api.functionsDefaultRegion, runtime);
60
+ return yamlToBuild(parsed, project, api.functionsDefaultRegion, runtime);
46
61
  }
47
62
  exports.detectFromYaml = detectFromYaml;
48
63
  async function detectFromPort(port, project, runtime, timeout = 30000) {
@@ -74,6 +89,6 @@ async function detectFromPort(port, project, runtime, timeout = 30000) {
74
89
  logger_1.logger.debug("Failed to parse functions.yaml", err);
75
90
  throw new error_1.FirebaseError(`Failed to load function definition from source: ${text}`);
76
91
  }
77
- return yamlToBackend(parsed, project, api.functionsDefaultRegion, runtime);
92
+ return yamlToBuild(parsed, project, api.functionsDefaultRegion, runtime);
78
93
  }
79
94
  exports.detectFromPort = detectFromPort;