firebase-tools 10.3.0 → 10.4.1

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 (60) hide show
  1. package/lib/accountExporter.js +95 -84
  2. package/lib/commands/deploy.js +1 -1
  3. package/lib/commands/experimental-functions-shell.js +1 -1
  4. package/lib/commands/ext-configure.js +13 -6
  5. package/lib/commands/ext-export.js +7 -1
  6. package/lib/commands/ext-install.js +12 -7
  7. package/lib/commands/ext-update.js +5 -3
  8. package/lib/commands/functions-config-export.js +5 -3
  9. package/lib/commands/functions-shell.js +1 -1
  10. package/lib/commands/hosting-channel-create.js +2 -2
  11. package/lib/commands/hosting-channel-delete.js +2 -2
  12. package/lib/commands/hosting-channel-deploy.js +2 -2
  13. package/lib/commands/hosting-channel-list.js +2 -2
  14. package/lib/commands/hosting-channel-open.js +2 -2
  15. package/lib/commands/hosting-sites-delete.js +2 -2
  16. package/lib/commands/serve.js +1 -1
  17. package/lib/commands/target-apply.js +2 -2
  18. package/lib/commands/target-clear.js +2 -2
  19. package/lib/commands/target-remove.js +2 -2
  20. package/lib/commands/target.js +2 -2
  21. package/lib/config.js +14 -4
  22. package/lib/deploy/extensions/planner.js +9 -3
  23. package/lib/deploy/functions/deploy.js +3 -7
  24. package/lib/deploy/functions/prepare.js +7 -5
  25. package/lib/deploy/functions/prepareFunctionsUpload.js +7 -13
  26. package/lib/deploy/functions/release/fabricator.js +13 -1
  27. package/lib/deploy/functions/release/index.js +1 -1
  28. package/lib/deploy/functions/runtimes/node/parseTriggers.js +12 -5
  29. package/lib/deploy/hosting/deploy.js +10 -0
  30. package/lib/emulator/auth/apiSpec.js +37 -0
  31. package/lib/emulator/commandUtils.js +2 -2
  32. package/lib/emulator/controller.js +14 -8
  33. package/lib/emulator/downloadableEmulators.js +5 -5
  34. package/lib/emulator/extensionsEmulator.js +3 -0
  35. package/lib/emulator/functionsEmulator.js +4 -4
  36. package/lib/emulator/functionsEmulatorShared.js +17 -1
  37. package/lib/emulator/storage/apis/firebase.js +4 -6
  38. package/lib/emulator/storage/files.js +5 -5
  39. package/lib/emulator/storage/index.js +6 -9
  40. package/lib/emulator/storage/rules/config.js +6 -5
  41. package/lib/emulator/storage/rules/manager.js +49 -32
  42. package/lib/emulator/storage/rules/runtime.js +4 -0
  43. package/lib/emulator/storage/rules/utils.js +2 -2
  44. package/lib/emulator/storage/server.js +1 -1
  45. package/lib/extensions/askUserForParam.js +103 -28
  46. package/lib/extensions/manifest.js +38 -6
  47. package/lib/extensions/paramHelper.js +28 -6
  48. package/lib/fsutils.js +14 -1
  49. package/lib/functions/projectConfig.js +34 -0
  50. package/lib/gcp/cloudfunctions.js +5 -4
  51. package/lib/init/features/functions/index.js +4 -2
  52. package/lib/init/features/hosting/index.js +32 -41
  53. package/lib/init/features/index.js +22 -12
  54. package/lib/init/index.js +28 -11
  55. package/lib/requireConfig.js +11 -9
  56. package/lib/serve/functions.js +5 -5
  57. package/npm-shrinkwrap.json +2 -2
  58. package/package.json +1 -1
  59. package/schema/firebase-config.json +93 -36
  60. package/lib/prepareUpload.js +0 -44
@@ -1,15 +1,17 @@
1
1
  "use strict";
2
- var os = require("os");
3
- var path = require("path");
4
- var _ = require("lodash");
5
- const { Client } = require("./apiv2");
6
- const { googleOrigin } = require("./api");
7
- var { FirebaseError } = require("./error");
8
- var utils = require("./utils");
9
- const apiClient = new Client({
10
- urlPrefix: googleOrigin,
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.serialExportUsers = exports.validateOptions = void 0;
4
+ const _ = require("lodash");
5
+ const os = require("os");
6
+ const path = require("path");
7
+ const apiv2_1 = require("./apiv2");
8
+ const error_1 = require("./error");
9
+ const api_1 = require("./api");
10
+ const utils = require("./utils");
11
+ const apiClient = new apiv2_1.Client({
12
+ urlPrefix: api_1.googleOrigin,
11
13
  });
12
- var EXPORTED_JSON_KEYS = [
14
+ const EXPORTED_JSON_KEYS = [
13
15
  "localId",
14
16
  "email",
15
17
  "emailVerified",
@@ -23,44 +25,53 @@ var EXPORTED_JSON_KEYS = [
23
25
  "disabled",
24
26
  "customAttributes",
25
27
  ];
26
- var EXPORTED_JSON_KEYS_RENAMING = {
28
+ const EXPORTED_JSON_KEYS_RENAMING = {
27
29
  lastLoginAt: "lastSignedInAt",
28
30
  };
29
- var EXPORTED_PROVIDER_USER_INFO_KEYS = ["providerId", "rawId", "email", "displayName", "photoUrl"];
30
- var PROVIDER_ID_INDEX_MAP = {
31
- "google.com": 7,
32
- "facebook.com": 11,
33
- "twitter.com": 15,
34
- "github.com": 19,
35
- };
36
- var _escapeComma = function (str) {
37
- if (str.indexOf(",") !== -1) {
31
+ const EXPORTED_PROVIDER_USER_INFO_KEYS = [
32
+ "providerId",
33
+ "rawId",
34
+ "email",
35
+ "displayName",
36
+ "photoUrl",
37
+ ];
38
+ const PROVIDER_ID_INDEX_MAP = new Map([
39
+ ["google.com", 7],
40
+ ["facebook.com", 11],
41
+ ["twitter.com", 15],
42
+ ["github.com", 19],
43
+ ]);
44
+ function escapeComma(str) {
45
+ if (str.includes(",")) {
38
46
  return `"${str}"`;
39
47
  }
40
48
  return str;
41
- };
42
- var _convertToNormalBase64 = function (data) {
49
+ }
50
+ function convertToNormalBase64(data) {
43
51
  return data.replace(/_/g, "/").replace(/-/g, "+");
44
- };
45
- var _addProviderUserInfo = function (providerInfo, arr, startPos) {
52
+ }
53
+ function addProviderUserInfo(providerInfo, arr, startPos) {
46
54
  arr[startPos] = providerInfo.rawId;
47
55
  arr[startPos + 1] = providerInfo.email || "";
48
- arr[startPos + 2] = _escapeComma(providerInfo.displayName || "");
56
+ arr[startPos + 2] = escapeComma(providerInfo.displayName || "");
49
57
  arr[startPos + 3] = providerInfo.photoUrl || "";
50
- };
51
- var _transUserToArray = function (user) {
52
- var arr = Array(27).fill("");
58
+ }
59
+ function transUserToArray(user) {
60
+ const arr = Array(27).fill("");
53
61
  arr[0] = user.localId;
54
62
  arr[1] = user.email || "";
55
63
  arr[2] = user.emailVerified || false;
56
- arr[3] = _convertToNormalBase64(user.passwordHash || "");
57
- arr[4] = _convertToNormalBase64(user.salt || "");
58
- arr[5] = _escapeComma(user.displayName || "");
64
+ arr[3] = convertToNormalBase64(user.passwordHash || "");
65
+ arr[4] = convertToNormalBase64(user.salt || "");
66
+ arr[5] = escapeComma(user.displayName || "");
59
67
  arr[6] = user.photoUrl || "";
60
- for (var i = 0; i < (!user.providerUserInfo ? 0 : user.providerUserInfo.length); i++) {
61
- var providerInfo = user.providerUserInfo[i];
62
- if (providerInfo && PROVIDER_ID_INDEX_MAP[providerInfo.providerId]) {
63
- _addProviderUserInfo(providerInfo, arr, PROVIDER_ID_INDEX_MAP[providerInfo.providerId]);
68
+ for (let i = 0; i < (!user.providerUserInfo ? 0 : user.providerUserInfo.length); i++) {
69
+ const providerInfo = user.providerUserInfo[i];
70
+ if (providerInfo) {
71
+ const providerIndex = PROVIDER_ID_INDEX_MAP.get(providerInfo.providerId);
72
+ if (providerIndex) {
73
+ addProviderUserInfo(providerInfo, arr, providerIndex);
74
+ }
64
75
  }
65
76
  }
66
77
  arr[23] = user.createdAt;
@@ -69,36 +80,35 @@ var _transUserToArray = function (user) {
69
80
  arr[26] = user.disabled;
70
81
  arr[27] = user.customAttributes;
71
82
  return arr;
72
- };
73
- var _transUserJson = function (user) {
74
- var newUser = {};
75
- _.each(_.pick(user, EXPORTED_JSON_KEYS), function (value, key) {
76
- var newKey = EXPORTED_JSON_KEYS_RENAMING[key] || key;
83
+ }
84
+ function transUserJson(user) {
85
+ const newUser = {};
86
+ _.each(_.pick(user, EXPORTED_JSON_KEYS), (value, key) => {
87
+ const newKey = EXPORTED_JSON_KEYS_RENAMING[key] || key;
77
88
  newUser[newKey] = value;
78
89
  });
79
90
  if (newUser.passwordHash) {
80
- newUser.passwordHash = _convertToNormalBase64(newUser.passwordHash);
91
+ newUser.passwordHash = convertToNormalBase64(newUser.passwordHash);
81
92
  }
82
93
  if (newUser.salt) {
83
- newUser.salt = _convertToNormalBase64(newUser.salt);
94
+ newUser.salt = convertToNormalBase64(newUser.salt);
84
95
  }
85
96
  if (user.providerUserInfo) {
86
97
  newUser.providerUserInfo = [];
87
- user.providerUserInfo.forEach(function (providerInfo) {
88
- if (!_.includes(Object.keys(PROVIDER_ID_INDEX_MAP), providerInfo.providerId)) {
89
- return;
98
+ for (const providerInfo of user.providerUserInfo) {
99
+ if (PROVIDER_ID_INDEX_MAP.has(providerInfo.providerId)) {
100
+ newUser.providerUserInfo.push(_.pick(providerInfo, EXPORTED_PROVIDER_USER_INFO_KEYS));
90
101
  }
91
- newUser.providerUserInfo.push(_.pick(providerInfo, EXPORTED_PROVIDER_USER_INFO_KEYS));
92
- });
102
+ }
93
103
  }
94
104
  return newUser;
95
- };
96
- var validateOptions = function (options, fileName) {
97
- var exportOptions = {};
105
+ }
106
+ function validateOptions(options, fileName) {
107
+ const exportOptions = {};
98
108
  if (fileName === undefined) {
99
- throw new FirebaseError("Must specify data file", { exit: 1 });
109
+ throw new error_1.FirebaseError("Must specify data file");
100
110
  }
101
- var extName = path.extname(fileName.toLowerCase());
111
+ const extName = path.extname(fileName.toLowerCase());
102
112
  if (extName === ".csv") {
103
113
  exportOptions.format = "csv";
104
114
  }
@@ -106,44 +116,44 @@ var validateOptions = function (options, fileName) {
106
116
  exportOptions.format = "json";
107
117
  }
108
118
  else if (options.format) {
109
- var format = options.format.toLowerCase();
119
+ const format = options.format.toLowerCase();
110
120
  if (format === "csv" || format === "json") {
111
121
  exportOptions.format = format;
112
122
  }
113
123
  else {
114
- throw new FirebaseError("Unsupported data file format, should be csv or json", { exit: 1 });
124
+ throw new error_1.FirebaseError("Unsupported data file format, should be csv or json");
115
125
  }
116
126
  }
117
127
  else {
118
- throw new FirebaseError("Please specify data file format in file name, or use `format` parameter", {
119
- exit: 1,
120
- });
128
+ throw new error_1.FirebaseError("Please specify data file format in file name, or use `format` parameter");
121
129
  }
122
130
  return exportOptions;
123
- };
124
- var _createWriteUsersToFile = function () {
125
- var jsonSep = "";
126
- return function (userList, format, writeStream) {
127
- userList.map(function (user) {
131
+ }
132
+ exports.validateOptions = validateOptions;
133
+ function createWriteUsersToFile() {
134
+ let jsonSep = "";
135
+ return (userList, format, writeStream) => {
136
+ userList.map((user) => {
128
137
  if (user.passwordHash && user.version !== 0) {
129
138
  delete user.passwordHash;
130
139
  delete user.salt;
131
140
  }
132
141
  if (format === "csv") {
133
- writeStream.write(_transUserToArray(user).join(",") + "," + os.EOL, "utf8");
142
+ writeStream.write(transUserToArray(user).join(",") + "," + os.EOL, "utf8");
134
143
  }
135
144
  else {
136
- writeStream.write(jsonSep + JSON.stringify(_transUserJson(user), null, 2), "utf8");
145
+ writeStream.write(jsonSep + JSON.stringify(transUserJson(user), null, 2), "utf8");
137
146
  jsonSep = "," + os.EOL;
138
147
  }
139
148
  });
140
149
  };
141
- };
142
- var serialExportUsers = function (projectId, options) {
150
+ }
151
+ async function serialExportUsers(projectId, options) {
152
+ var _a;
143
153
  if (!options.writeUsersToFile) {
144
- options.writeUsersToFile = _createWriteUsersToFile();
154
+ options.writeUsersToFile = createWriteUsersToFile();
145
155
  }
146
- var postBody = {
156
+ const postBody = {
147
157
  targetProjectId: projectId,
148
158
  maxResults: options.batchSize,
149
159
  };
@@ -153,13 +163,12 @@ var serialExportUsers = function (projectId, options) {
153
163
  if (!options.timeoutRetryCount) {
154
164
  options.timeoutRetryCount = 0;
155
165
  }
156
- return apiClient
157
- .post("/identitytoolkit/v3/relyingparty/downloadAccount", postBody, {
158
- skipLog: { resBody: true },
159
- })
160
- .then(function (ret) {
166
+ try {
167
+ const ret = await apiClient.post("/identitytoolkit/v3/relyingparty/downloadAccount", postBody, {
168
+ skipLog: { resBody: true },
169
+ });
161
170
  options.timeoutRetryCount = 0;
162
- var userList = ret.body.users;
171
+ const userList = ret.body.users;
163
172
  if (userList && userList.length > 0) {
164
173
  options.writeUsersToFile(userList, options.format, options.writeStream);
165
174
  utils.logSuccess("Exported " + userList.length + " account(s) successfully.");
@@ -169,19 +178,21 @@ var serialExportUsers = function (projectId, options) {
169
178
  options.nextPageToken = ret.body.nextPageToken;
170
179
  return serialExportUsers(projectId, options);
171
180
  }
172
- })
173
- .catch((err) => {
174
- if (err.original.code === "ETIMEDOUT") {
181
+ }
182
+ catch (err) {
183
+ if (((_a = err.original) === null || _a === void 0 ? void 0 : _a.code) === "ETIMEDOUT") {
175
184
  options.timeoutRetryCount++;
176
185
  if (options.timeoutRetryCount > 5) {
177
186
  return err;
178
187
  }
179
188
  return serialExportUsers(projectId, options);
180
189
  }
181
- });
182
- };
183
- var accountExporter = {
184
- validateOptions: validateOptions,
185
- serialExportUsers: serialExportUsers,
186
- };
187
- module.exports = accountExporter;
190
+ if (err instanceof error_1.FirebaseError) {
191
+ throw err;
192
+ }
193
+ else {
194
+ throw new error_1.FirebaseError(`Failed to export accounts: ${err}`, { original: err });
195
+ }
196
+ }
197
+ }
198
+ exports.serialExportUsers = serialExportUsers;
@@ -6,7 +6,7 @@ const { checkServiceAccountIam } = require("../deploy/functions/checkIam");
6
6
  const checkValidTargetFilters = require("../checkValidTargetFilters");
7
7
  const { Command } = require("../command");
8
8
  const deploy = require("../deploy");
9
- const requireConfig = require("../requireConfig");
9
+ const { requireConfig } = require("../requireConfig");
10
10
  const { filterTargets } = require("../filterTargets");
11
11
  const { requireHostingSite } = require("../requireHostingSite");
12
12
  const VALID_TARGETS = [
@@ -2,7 +2,7 @@
2
2
  var { Command } = require("../command");
3
3
  var { requirePermissions } = require("../requirePermissions");
4
4
  var { actionFunction } = require("../functionsShellCommandAction");
5
- var requireConfig = require("../requireConfig");
5
+ var { requireConfig } = require("../requireConfig");
6
6
  module.exports = new Command("experimental:functions:shell")
7
7
  .description("launch full Node shell with emulated functions. (Alias for `firebase functions:shell.)")
8
8
  .option("-p, --port <port>", "the port on which to emulate functions (default: 5000)", 5000)
@@ -18,6 +18,7 @@ const logger_1 = require("../logger");
18
18
  const refs = require("../extensions/refs");
19
19
  const manifest = require("../extensions/manifest");
20
20
  const functional_1 = require("../functional");
21
+ const paramHelper_1 = require("../extensions/paramHelper");
21
22
  marked.setOptions({
22
23
  renderer: new TerminalRenderer(),
23
24
  });
@@ -49,7 +50,7 @@ exports.default = new command_1.Command("ext:configure <extensionInstanceId>")
49
50
  const [immutableParams, tbdParams] = (0, functional_1.partition)(extensionVersion.spec.params, (param) => { var _a; return (_a = param.immutable) !== null && _a !== void 0 ? _a : false; });
50
51
  infoImmutableParams(immutableParams, oldParamValues);
51
52
  paramHelper.setNewDefaults(tbdParams, oldParamValues);
52
- const mutableParamsValues = await paramHelper.getParams({
53
+ const mutableParamsBindingOptions = await paramHelper.getParams({
53
54
  projectId,
54
55
  paramSpecs: tbdParams,
55
56
  nonInteractive: false,
@@ -57,12 +58,13 @@ exports.default = new command_1.Command("ext:configure <extensionInstanceId>")
57
58
  instanceId,
58
59
  reconfiguring: true,
59
60
  });
60
- const newParamValues = Object.assign(Object.assign({}, oldParamValues), mutableParamsValues);
61
+ const newParamOptions = Object.assign(Object.assign({}, (0, paramHelper_1.buildBindingOptionsWithBaseValue)(oldParamValues)), mutableParamsBindingOptions);
61
62
  await manifest.writeToManifest([
62
63
  {
63
64
  instanceId,
64
65
  ref: targetRef,
65
- params: newParamValues,
66
+ params: newParamOptions,
67
+ paramSpecs: extensionVersion.spec.params,
66
68
  },
67
69
  ], config, {
68
70
  nonInteractive: false,
@@ -87,7 +89,7 @@ exports.default = new command_1.Command("ext:configure <extensionInstanceId>")
87
89
  }
88
90
  const paramSpecWithNewDefaults = paramHelper.getParamsWithCurrentValuesAsDefaults(existingInstance);
89
91
  const immutableParams = _.remove(paramSpecWithNewDefaults, (param) => param.immutable);
90
- const params = await paramHelper.getParams({
92
+ const paramBindingOptions = await paramHelper.getParams({
91
93
  projectId,
92
94
  paramSpecs: paramSpecWithNewDefaults,
93
95
  nonInteractive: options.nonInteractive,
@@ -95,13 +97,14 @@ exports.default = new command_1.Command("ext:configure <extensionInstanceId>")
95
97
  instanceId,
96
98
  reconfiguring: true,
97
99
  });
100
+ const paramBindings = (0, paramHelper_1.getBaseParamBindings)(paramBindingOptions);
98
101
  if (immutableParams.length) {
99
102
  const plural = immutableParams.length > 1;
100
103
  logger_1.logger.info(`The following param${plural ? "s are" : " is"} immutable:`);
101
104
  for (const { param } of immutableParams) {
102
105
  const value = _.get(existingInstance, `config.params.${param}`);
103
106
  logger_1.logger.info(`param: ${param}, value: ${value}`);
104
- params[param] = value;
107
+ paramBindings[param] = value;
105
108
  }
106
109
  logger_1.logger.info((plural
107
110
  ? "To set different values for these params"
@@ -109,7 +112,11 @@ exports.default = new command_1.Command("ext:configure <extensionInstanceId>")
109
112
  ", uninstall the extension, then install a new instance of this extension.");
110
113
  }
111
114
  spinner.start();
112
- const res = await extensionsApi.configureInstance({ projectId, instanceId, params });
115
+ const res = await extensionsApi.configureInstance({
116
+ projectId,
117
+ instanceId,
118
+ params: paramBindings,
119
+ });
113
120
  spinner.stop();
114
121
  utils.logLabeledSuccess(extensionsHelper_1.logPrefix, `successfully configured ${clc.bold(instanceId)}.`);
115
122
  utils.logLabeledBullet(extensionsHelper_1.logPrefix, marked(`You can view your reconfigured instance in the Firebase console: ${utils.consoleUrl(projectId, `/extensions/instances/${instanceId}?tab=config`)}`));
@@ -6,6 +6,7 @@ const planner = require("../deploy/extensions/planner");
6
6
  const export_1 = require("../extensions/export");
7
7
  const extensionsHelper_1 = require("../extensions/extensionsHelper");
8
8
  const manifest = require("../extensions/manifest");
9
+ const paramHelper_1 = require("../extensions/paramHelper");
9
10
  const functional_1 = require("../functional");
10
11
  const getProjectNumber_1 = require("../getProjectNumber");
11
12
  const logger_1 = require("../logger");
@@ -41,8 +42,13 @@ module.exports = new command_1.Command("ext:export")
41
42
  logger_1.logger.info("Exiting. No changes made.");
42
43
  return;
43
44
  }
45
+ const manifestSpecs = withRef.map((spec) => ({
46
+ instanceId: spec.instanceId,
47
+ ref: spec.ref,
48
+ params: (0, paramHelper_1.buildBindingOptionsWithBaseValue)(spec.params),
49
+ }));
44
50
  const existingConfig = manifest.loadConfig(options);
45
- await manifest.writeToManifest(withRef, existingConfig, {
51
+ await manifest.writeToManifest(manifestSpecs, existingConfig, {
46
52
  nonInteractive: options.nonInteractive,
47
53
  force: options.force,
48
54
  }, true);
@@ -28,6 +28,7 @@ const track_1 = require("../track");
28
28
  const logger_1 = require("../logger");
29
29
  const previews_1 = require("../previews");
30
30
  const manifest = require("../extensions/manifest");
31
+ const paramHelper_1 = require("../extensions/paramHelper");
31
32
  marked.setOptions({
32
33
  renderer: new TerminalRenderer(),
33
34
  });
@@ -175,7 +176,7 @@ async function installToManifest(options) {
175
176
  while (manifest.instanceExists(instanceId, config)) {
176
177
  instanceId = await (0, extensionsHelper_1.promptForValidInstanceId)(`${spec.name}-${(0, utils_1.getRandomString)(4)}`);
177
178
  }
178
- const params = await paramHelper.getParams({
179
+ const paramBindingOptions = await paramHelper.getParams({
179
180
  projectId,
180
181
  paramSpecs: spec.params,
181
182
  nonInteractive,
@@ -187,7 +188,8 @@ async function installToManifest(options) {
187
188
  {
188
189
  instanceId,
189
190
  ref,
190
- params,
191
+ params: paramBindingOptions,
192
+ paramSpecs: spec.params,
191
193
  },
192
194
  ], config, { nonInteractive, force: force !== null && force !== void 0 ? force : false });
193
195
  manifest.showPreviewWarning();
@@ -259,17 +261,19 @@ async function installExtension(options) {
259
261
  else {
260
262
  choice = "installNew";
261
263
  }
262
- let params;
264
+ let paramBindingOptions;
265
+ let paramBindings;
263
266
  switch (choice) {
264
267
  case "installNew":
265
268
  instanceId = await (0, extensionsHelper_1.promptForValidInstanceId)(`${instanceId}-${(0, utils_1.getRandomString)(4)}`);
266
- params = await paramHelper.getParams({
269
+ paramBindingOptions = await paramHelper.getParams({
267
270
  projectId,
268
271
  paramSpecs: spec.params,
269
272
  nonInteractive,
270
273
  paramsEnvPath,
271
274
  instanceId,
272
275
  });
276
+ paramBindings = (0, paramHelper_1.getBaseParamBindings)(paramBindingOptions);
273
277
  spinner.text = "Installing your extension instance. This usually takes 3 to 5 minutes...";
274
278
  spinner.start();
275
279
  await extensionsApi.createInstance({
@@ -277,20 +281,21 @@ async function installExtension(options) {
277
281
  instanceId,
278
282
  extensionSource: source,
279
283
  extensionVersionRef: extVersion === null || extVersion === void 0 ? void 0 : extVersion.ref,
280
- params,
284
+ params: paramBindings,
281
285
  });
282
286
  spinner.stop();
283
287
  utils.logLabeledSuccess(extensionsHelper_1.logPrefix, `Successfully installed your instance of ${clc.bold(spec.displayName || spec.name)}! ` +
284
288
  `Its Instance ID is ${clc.bold(instanceId)}.`);
285
289
  break;
286
290
  case "updateExisting":
287
- params = await paramHelper.getParams({
291
+ paramBindingOptions = await paramHelper.getParams({
288
292
  projectId,
289
293
  paramSpecs: spec.params,
290
294
  nonInteractive,
291
295
  paramsEnvPath,
292
296
  instanceId,
293
297
  });
298
+ paramBindings = (0, paramHelper_1.getBaseParamBindings)(paramBindingOptions);
294
299
  spinner.text = "Updating your extension instance. This usually takes 3 to 5 minutes...";
295
300
  spinner.start();
296
301
  await (0, updateHelper_1.update)({
@@ -298,7 +303,7 @@ async function installExtension(options) {
298
303
  instanceId,
299
304
  source,
300
305
  extRef: extVersion === null || extVersion === void 0 ? void 0 : extVersion.ref,
301
- params,
306
+ params: paramBindings,
302
307
  });
303
308
  spinner.stop();
304
309
  utils.logLabeledSuccess(extensionsHelper_1.logPrefix, `Successfully updated your instance of ${clc.bold(spec.displayName || spec.name)}! ` +
@@ -70,7 +70,7 @@ exports.default = new command_1.Command("ext:update <extensionInstanceId> [updat
70
70
  instanceId,
71
71
  projectDir: config.projectDir,
72
72
  });
73
- const newParams = await paramHelper.getParamsForUpdate({
73
+ const newParamBindingOptions = await paramHelper.getParamsForUpdate({
74
74
  spec: oldExtensionVersion.spec,
75
75
  newSpec: newExtensionVersion.spec,
76
76
  currentParams: oldParamValues,
@@ -83,7 +83,8 @@ exports.default = new command_1.Command("ext:update <extensionInstanceId> [updat
83
83
  {
84
84
  instanceId,
85
85
  ref: refs.parse(newExtensionVersion.ref),
86
- params: newParams,
86
+ params: newParamBindingOptions,
87
+ paramSpecs: newExtensionVersion.spec.params,
87
88
  },
88
89
  ], config, {
89
90
  nonInteractive: options.nonInteractive,
@@ -195,7 +196,7 @@ exports.default = new command_1.Command("ext:update <extensionInstanceId> [updat
195
196
  }
196
197
  }
197
198
  const oldParamValues = Object.assign({}, existingParams);
198
- const newParams = await paramHelper.getParamsForUpdate({
199
+ const newParamBindings = await paramHelper.getParamsForUpdate({
199
200
  spec: existingSpec,
200
201
  newSpec,
201
202
  currentParams: existingParams,
@@ -204,6 +205,7 @@ exports.default = new command_1.Command("ext:update <extensionInstanceId> [updat
204
205
  nonInteractive: options.nonInteractive,
205
206
  instanceId,
206
207
  });
208
+ const newParams = paramHelper.getBaseParamBindings(newParamBindings);
207
209
  spinner.start();
208
210
  const updateOptions = {
209
211
  projectId,
@@ -12,7 +12,8 @@ const requirePermissions_1 = require("../requirePermissions");
12
12
  const utils_1 = require("../utils");
13
13
  const functional_1 = require("../functional");
14
14
  const configExport = require("../functions/runtimeConfigExport");
15
- const requireConfig = require("../requireConfig");
15
+ const requireConfig_1 = require("../requireConfig");
16
+ const projectConfig_1 = require("../functions/projectConfig");
16
17
  const REQUIRED_PERMISSIONS = [
17
18
  "runtimeconfig.configs.list",
18
19
  "runtimeconfig.configs.get",
@@ -76,9 +77,11 @@ exports.default = new command_1.Command("functions:config:export")
76
77
  "runtimeconfig.variables.list",
77
78
  "runtimeconfig.variables.get",
78
79
  ])
79
- .before(requireConfig)
80
+ .before(requireConfig_1.requireConfig)
80
81
  .before(requireInteractive_1.default)
81
82
  .action(async (options) => {
83
+ const config = (0, projectConfig_1.normalizeAndValidate)(options.config.src.functions)[0];
84
+ const functionsDir = config.source;
82
85
  let pInfos = configExport.getProjectInfos(options);
83
86
  checkReservedAliases(pInfos);
84
87
  (0, utils_1.logBullet)("Importing functions configs from projects [" +
@@ -108,7 +111,6 @@ exports.default = new command_1.Command("functions:config:export")
108
111
  const filesToWrite = fromEntries((0, functional_1.zip)(filenames, dotEnvs));
109
112
  filesToWrite[".env.local"] = `${header}\n# .env.local file contains environment variables for the Functions Emulator.\n`;
110
113
  filesToWrite[".env"] = `${header}# .env file contains environment variables that applies to all projects.\n`;
111
- const functionsDir = options.config.get("functions.source", ".");
112
114
  for (const [filename, content] of Object.entries(filesToWrite)) {
113
115
  await options.config.askWriteProjectFile(path.join(functionsDir, filename), content);
114
116
  }
@@ -2,7 +2,7 @@
2
2
  var { Command } = require("../command");
3
3
  var { requirePermissions } = require("../requirePermissions");
4
4
  var { actionFunction } = require("../functionsShellCommandAction");
5
- var requireConfig = require("../requireConfig");
5
+ var { requireConfig } = require("../requireConfig");
6
6
  var commandUtils = require("../emulator/commandUtils");
7
7
  module.exports = new Command("functions:shell")
8
8
  .description("launch full Node shell with emulated functions")
@@ -10,7 +10,7 @@ const prompt_1 = require("../prompt");
10
10
  const requirePermissions_1 = require("../requirePermissions");
11
11
  const projectUtils_1 = require("../projectUtils");
12
12
  const logger_1 = require("../logger");
13
- const requireConfig = require("../requireConfig");
13
+ const requireConfig_1 = require("../requireConfig");
14
14
  const { marked } = require("marked");
15
15
  const requireHostingSite_1 = require("../requireHostingSite");
16
16
  const LOG_TAG = "hosting:channel";
@@ -18,7 +18,7 @@ exports.default = new command_1.Command("hosting:channel:create [channelId]")
18
18
  .description("create a Firebase Hosting channel")
19
19
  .option("-e, --expires <duration>", "duration string (e.g. 12h or 30d) for channel expiration, max 30d")
20
20
  .option("--site <siteId>", "site for which to create the channel")
21
- .before(requireConfig)
21
+ .before(requireConfig_1.requireConfig)
22
22
  .before(requirePermissions_1.requirePermissions, ["firebasehosting.sites.update"])
23
23
  .before(requireHostingSite_1.requireHostingSite)
24
24
  .action(async (channelId, options) => {
@@ -9,13 +9,13 @@ const prompt_1 = require("../prompt");
9
9
  const requireHostingSite_1 = require("../requireHostingSite");
10
10
  const requirePermissions_1 = require("../requirePermissions");
11
11
  const projectUtils_1 = require("../projectUtils");
12
- const requireConfig = require("../requireConfig");
12
+ const requireConfig_1 = require("../requireConfig");
13
13
  const logger_1 = require("../logger");
14
14
  exports.default = new command_1.Command("hosting:channel:delete <channelId>")
15
15
  .description("delete a Firebase Hosting channel")
16
16
  .withForce()
17
17
  .option("--site <siteId>", "site in which the channel exists")
18
- .before(requireConfig)
18
+ .before(requireConfig_1.requireConfig)
19
19
  .before(requirePermissions_1.requirePermissions, ["firebasehosting.sites.update"])
20
20
  .before(requireHostingSite_1.requireHostingSite)
21
21
  .action(async (channelId, options) => {
@@ -9,7 +9,7 @@ const requirePermissions_1 = require("../requirePermissions");
9
9
  const deploy = require("../deploy");
10
10
  const projectUtils_1 = require("../projectUtils");
11
11
  const logger_1 = require("../logger");
12
- const requireConfig = require("../requireConfig");
12
+ const requireConfig_1 = require("../requireConfig");
13
13
  const expireUtils_1 = require("../hosting/expireUtils");
14
14
  const utils_1 = require("../utils");
15
15
  const { marked } = require("marked");
@@ -21,7 +21,7 @@ exports.default = new command_1.Command("hosting:channel:deploy [channelId]")
21
21
  .option("--only <target1,target2...>", "only create previews for specified targets")
22
22
  .option("--open", "open a browser to the channel after deploying")
23
23
  .option("--no-authorized-domains", "do not sync channel domains with Firebase Auth")
24
- .before(requireConfig)
24
+ .before(requireConfig_1.requireConfig)
25
25
  .before(requirePermissions_1.requirePermissions, ["firebasehosting.sites.update"])
26
26
  .before(requireHostingSite_1.requireHostingSite)
27
27
  .action(async (channelId, options) => {
@@ -7,14 +7,14 @@ const command_1 = require("../command");
7
7
  const requirePermissions_1 = require("../requirePermissions");
8
8
  const projectUtils_1 = require("../projectUtils");
9
9
  const logger_1 = require("../logger");
10
- const requireConfig = require("../requireConfig");
10
+ const requireConfig_1 = require("../requireConfig");
11
11
  const utils_1 = require("../utils");
12
12
  const requireHostingSite_1 = require("../requireHostingSite");
13
13
  const TABLE_HEAD = ["Channel ID", "Last Release Time", "URL", "Expire Time"];
14
14
  exports.default = new command_1.Command("hosting:channel:list")
15
15
  .description("list all Firebase Hosting channels for your project")
16
16
  .option("--site <siteName>", "list channels for the specified site")
17
- .before(requireConfig)
17
+ .before(requireConfig_1.requireConfig)
18
18
  .before(requirePermissions_1.requirePermissions, ["firebasehosting.sites.update"])
19
19
  .before(requireHostingSite_1.requireHostingSite)
20
20
  .action(async (options) => {
@@ -8,7 +8,7 @@ const error_1 = require("../error");
8
8
  const api_1 = require("../hosting/api");
9
9
  const requirePermissions_1 = require("../requirePermissions");
10
10
  const projectUtils_1 = require("../projectUtils");
11
- const requireConfig = require("../requireConfig");
11
+ const requireConfig_1 = require("../requireConfig");
12
12
  const utils_1 = require("../utils");
13
13
  const prompt_1 = require("../prompt");
14
14
  const requireHostingSite_1 = require("../requireHostingSite");
@@ -16,7 +16,7 @@ exports.default = new command_1.Command("hosting:channel:open [channelId]")
16
16
  .description("opens the URL for a Firebase Hosting channel")
17
17
  .help("if unable to open the URL in a browser, it will be displayed in the output")
18
18
  .option("--site <siteId>", "the site to which the channel belongs")
19
- .before(requireConfig)
19
+ .before(requireConfig_1.requireConfig)
20
20
  .before(requirePermissions_1.requirePermissions, ["firebasehosting.sites.get"])
21
21
  .before(requireHostingSite_1.requireHostingSite)
22
22
  .action(async (channelId, options) => {