firebase-tools 13.25.0 → 13.27.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/lib/appdistribution/client.js +62 -8
  2. package/lib/appdistribution/distribution.js +1 -1
  3. package/lib/apphosting/backend.js +4 -4
  4. package/lib/apphosting/config.js +86 -9
  5. package/lib/apphosting/secrets/index.js +5 -43
  6. package/lib/apphosting/yaml.js +3 -0
  7. package/lib/archiveDirectory.js +1 -1
  8. package/lib/auth.js +1 -1
  9. package/lib/command.js +9 -1
  10. package/lib/commands/appdistribution-distribute.js +4 -4
  11. package/lib/commands/{appdistribution-group-create.js → appdistribution-groups-create.js} +2 -1
  12. package/lib/commands/{appdistribution-group-delete.js → appdistribution-groups-delete.js} +3 -2
  13. package/lib/commands/appdistribution-groups-list.js +56 -0
  14. package/lib/commands/appdistribution-testers-list.js +54 -0
  15. package/lib/commands/appdistribution-testers-remove.js +1 -1
  16. package/lib/commands/apphosting-backends-delete.js +3 -1
  17. package/lib/commands/apphosting-backends-get.js +1 -1
  18. package/lib/commands/apphosting-config-export.js +4 -26
  19. package/lib/commands/database-import.js +4 -2
  20. package/lib/commands/database-push.js +4 -2
  21. package/lib/commands/database-set.js +4 -2
  22. package/lib/commands/database-settings-get.js +1 -1
  23. package/lib/commands/database-settings-set.js +1 -1
  24. package/lib/commands/ext-dev-init.js +2 -2
  25. package/lib/commands/ext-dev-list.js +1 -1
  26. package/lib/commands/ext-dev-register.js +2 -2
  27. package/lib/commands/ext-dev-upload.js +2 -2
  28. package/lib/commands/ext-dev-usage.js +2 -2
  29. package/lib/commands/ext-install.js +2 -2
  30. package/lib/commands/index.js +7 -6
  31. package/lib/commands/use.js +1 -1
  32. package/lib/deploy/extensions/deploy.js +3 -1
  33. package/lib/deploy/extensions/deploymentSummary.js +4 -1
  34. package/lib/deploy/extensions/planner.js +14 -3
  35. package/lib/deploy/extensions/prepare.js +9 -9
  36. package/lib/deploy/functions/ensure.js +1 -1
  37. package/lib/deploy/functions/release/fabricator.js +3 -3
  38. package/lib/deploy/lifecycleHooks.js +2 -1
  39. package/lib/emulator/apphosting/config.js +13 -3
  40. package/lib/emulator/apphosting/developmentServer.js +32 -0
  41. package/lib/emulator/apphosting/index.js +5 -3
  42. package/lib/emulator/apphosting/serve.js +15 -12
  43. package/lib/emulator/commandUtils.js +2 -1
  44. package/lib/emulator/controller.js +27 -18
  45. package/lib/emulator/dataconnect/pgliteServer.js +51 -18
  46. package/lib/emulator/dataconnectEmulator.js +26 -2
  47. package/lib/emulator/downloadableEmulators.js +11 -11
  48. package/lib/emulator/hub.js +26 -7
  49. package/lib/emulator/hubExport.js +23 -0
  50. package/lib/emulator/initEmulators.js +49 -0
  51. package/lib/emulator/types.js +2 -2
  52. package/lib/emulator/ui.js +47 -25
  53. package/lib/error.js +8 -1
  54. package/lib/gcp/cloudfunctionsv2.js +1 -0
  55. package/lib/getProjectNumber.js +1 -1
  56. package/lib/init/features/emulators.js +8 -0
  57. package/lib/init/features/project.js +7 -6
  58. package/lib/logger.js +2 -2
  59. package/lib/management/projects.js +24 -4
  60. package/lib/projectUtils.js +1 -1
  61. package/lib/requireDatabaseInstance.js +1 -1
  62. package/lib/requirePermissions.js +1 -1
  63. package/lib/rulesDeploy.js +1 -1
  64. package/lib/templates.js +2 -2
  65. package/lib/utils.js +20 -8
  66. package/lib/vsCodeUtils.js +8 -0
  67. package/package.json +2 -2
  68. package/schema/firebase-config.json +6 -0
  69. package/lib/emulator/apphosting/utils.js +0 -18
@@ -27,7 +27,7 @@ exports.command = new command_1.Command("apphosting:backends:get <backend>")
27
27
  }
28
28
  }
29
29
  catch (err) {
30
- throw new error_1.FirebaseError(`Failed to get backend: ${backend}. Please check the parameters you have provided.`, { original: err });
30
+ throw new error_1.FirebaseError(`Failed to get backend: ${backend}. Please check the parameters you have provided.`, { original: (0, error_1.getError)(err) });
31
31
  }
32
32
  if (backendsList.length === 0) {
33
33
  (0, utils_1.logWarning)(`Backend "${backend}" not found`);
@@ -2,17 +2,13 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.command = void 0;
4
4
  const command_1 = require("../command");
5
- const logger_1 = require("../logger");
6
5
  const projectUtils_1 = require("../projectUtils");
7
6
  const requireAuth_1 = require("../requireAuth");
8
7
  const secretManager = require("../gcp/secretManager");
9
8
  const requirePermissions_1 = require("../requirePermissions");
10
9
  const config_1 = require("../apphosting/config");
11
- const secrets_1 = require("../apphosting/secrets");
12
- const path_1 = require("path");
13
- const fs = require("../fsutils");
14
- const yaml_1 = require("../apphosting/yaml");
15
10
  const error_1 = require("../error");
11
+ const detectProjectRoot_1 = require("../detectProjectRoot");
16
12
  exports.command = new command_1.Command("apphosting:config:export")
17
13
  .description("Export App Hosting configurations such as secrets into an apphosting.local.yaml file")
18
14
  .option("-s, --secrets <apphosting.yaml or apphosting.<environment>.yaml file to export secrets from>", "This command combines the base apphosting.yaml with the specified environment-specific file (e.g., apphosting.staging.yaml). If keys conflict, the environment-specific file takes precedence.")
@@ -20,32 +16,14 @@ exports.command = new command_1.Command("apphosting:config:export")
20
16
  .before(secretManager.ensureApi)
21
17
  .before(requirePermissions_1.requirePermissions, ["secretmanager.versions.access"])
22
18
  .action(async (options) => {
19
+ var _a;
23
20
  const projectId = (0, projectUtils_1.needProjectId)(options);
24
21
  const environmentConfigFile = options.secrets;
25
22
  const cwd = process.cwd();
26
- let localAppHostingConfig = yaml_1.AppHostingYamlConfig.empty();
27
23
  const backendRoot = (0, config_1.discoverBackendRoot)(cwd);
28
24
  if (!backendRoot) {
29
25
  throw new error_1.FirebaseError("Missing apphosting.yaml: This command requires an apphosting.yaml configuration file. Please run 'firebase init apphosting' and try again.");
30
26
  }
31
- const localAppHostingConfigPath = (0, path_1.resolve)(backendRoot, config_1.APPHOSTING_LOCAL_YAML_FILE);
32
- if (fs.fileExistsSync(localAppHostingConfigPath)) {
33
- localAppHostingConfig = await yaml_1.AppHostingYamlConfig.loadFromFile(localAppHostingConfigPath);
34
- }
35
- const configToExport = await (0, secrets_1.loadConfigToExport)(cwd, environmentConfigFile);
36
- const secretsToExport = configToExport.secrets;
37
- if (!secretsToExport) {
38
- logger_1.logger.warn("No secrets found to export in the chosen App Hosting config files");
39
- return;
40
- }
41
- const secretMaterial = await (0, secrets_1.fetchSecrets)(projectId, secretsToExport);
42
- for (const [key, value] of secretMaterial) {
43
- localAppHostingConfig.addEnvironmentVariable({
44
- variable: key,
45
- value: value,
46
- availability: ["RUNTIME"],
47
- });
48
- }
49
- localAppHostingConfig.upsertFile(localAppHostingConfigPath);
50
- logger_1.logger.info(`Wrote secrets as environment variables to ${config_1.APPHOSTING_LOCAL_YAML_FILE}.`);
27
+ const projectRoot = (_a = (0, detectProjectRoot_1.detectProjectRoot)({})) !== null && _a !== void 0 ? _a : backendRoot;
28
+ await (0, config_1.exportConfig)(cwd, projectRoot, backendRoot, projectId, environmentConfigFile);
51
29
  });
@@ -71,8 +71,10 @@ exports.command = new command_1.Command("database:import <path> [infile]")
71
71
  if (err instanceof error_1.FirebaseError) {
72
72
  throw err;
73
73
  }
74
- logger_1.logger.debug(err);
75
- throw new error_1.FirebaseError(`Unexpected error while importing data: ${err}`, { exit: 2 });
74
+ logger_1.logger.debug((0, error_1.getErrMsg)(err));
75
+ throw new error_1.FirebaseError(`Unexpected error while importing data: ${(0, error_1.getErrMsg)(err)}`, {
76
+ exit: 2,
77
+ });
76
78
  }
77
79
  if (responses.length) {
78
80
  utils.logSuccess("Data persisted successfully");
@@ -49,8 +49,10 @@ exports.command = new command_1.Command("database:push <path> [infile]")
49
49
  });
50
50
  }
51
51
  catch (err) {
52
- logger_1.logger.debug(err);
53
- throw new error_1.FirebaseError(`Unexpected error while pushing data: ${err}`, { exit: 2 });
52
+ logger_1.logger.debug((0, error_1.getErrMsg)(err));
53
+ throw new error_1.FirebaseError(`Unexpected error while pushing data: ${(0, error_1.getErrMsg)(err)}`, {
54
+ exit: 2,
55
+ });
54
56
  }
55
57
  if (!path.endsWith("/")) {
56
58
  path += "/";
@@ -59,8 +59,10 @@ exports.command = new command_1.Command("database:set <path> [infile]")
59
59
  });
60
60
  }
61
61
  catch (err) {
62
- logger_1.logger.debug(err);
63
- throw new error_1.FirebaseError(`Unexpected error while setting data: ${err}`, { exit: 2 });
62
+ logger_1.logger.debug((0, error_1.getErrMsg)(err));
63
+ throw new error_1.FirebaseError(`Unexpected error while setting data: ${(0, error_1.getErrMsg)(err)}`, {
64
+ exit: 2,
65
+ });
64
66
  }
65
67
  utils.logSuccess("Data persisted successfully");
66
68
  logger_1.logger.info();
@@ -34,7 +34,7 @@ exports.command = new command_1.Command("database:settings:get <path>")
34
34
  catch (err) {
35
35
  throw new error_1.FirebaseError(`Unexpected error fetching configs at ${path}`, {
36
36
  exit: 2,
37
- original: err,
37
+ original: (0, error_1.getError)(err),
38
38
  });
39
39
  }
40
40
  if (typeof res.body === "object") {
@@ -38,7 +38,7 @@ exports.command = new command_1.Command("database:settings:set <path> <value>")
38
38
  catch (err) {
39
39
  throw new error_1.FirebaseError(`Unexpected error fetching configs at ${path}`, {
40
40
  exit: 2,
41
- original: err,
41
+ original: (0, error_1.getError)(err),
42
42
  });
43
43
  }
44
44
  utils.logSuccess("Successfully set setting.");
@@ -66,8 +66,8 @@ exports.command = new command_1.Command("ext:dev:init")
66
66
  }
67
67
  catch (err) {
68
68
  if (!(err instanceof error_1.FirebaseError)) {
69
- throw new error_1.FirebaseError(`Error occurred when initializing files for new extension: ${err.message}`, {
70
- original: err,
69
+ throw new error_1.FirebaseError(`Error occurred when initializing files for new extension: ${(0, error_1.getErrMsg)(err)}`, {
70
+ original: (0, error_1.getError)(err),
71
71
  });
72
72
  }
73
73
  throw err;
@@ -19,7 +19,7 @@ exports.command = new command_1.Command("ext:dev:list <publisherId>")
19
19
  extensions = await (0, publisherApi_1.listExtensions)(publisherId);
20
20
  }
21
21
  catch (err) {
22
- throw new error_1.FirebaseError(err);
22
+ throw new error_1.FirebaseError((0, error_1.getErrMsg)(err));
23
23
  }
24
24
  if (extensions.length < 1) {
25
25
  throw new error_1.FirebaseError(`There are no extensions uploaded under publisher ID ${clc.bold(publisherId)}. This could happen for two reasons:\n` +
@@ -35,7 +35,7 @@ exports.command = new command_1.Command("ext:dev:register")
35
35
  profile = await (0, publisherApi_1.registerPublisherProfile)(projectId, publisherId);
36
36
  }
37
37
  catch (err) {
38
- if (err.status === 409) {
38
+ if ((0, error_1.getErrStatus)(err) === 409) {
39
39
  const error = `Couldn't register the publisher ID '${clc.bold(publisherId)}' to the project '${clc.bold(projectId)}'.` +
40
40
  " This can happen for either of two reasons:\n\n" +
41
41
  ` - Publisher ID '${clc.bold(publisherId)}' is registered to another project\n` +
@@ -43,7 +43,7 @@ exports.command = new command_1.Command("ext:dev:register")
43
43
  ` Try again with a unique publisher ID or a new project. If your business’s name has been registered to another project, contact Firebase support ${(0, marked_1.marked)("(https://firebase.google.com/support/troubleshooter/contact).")}`;
44
44
  throw new error_1.FirebaseError(error, { exit: 1 });
45
45
  }
46
- throw new error_1.FirebaseError(`Failed to register publisher ID ${clc.bold(publisherId)} for project ${clc.bold(projectId)}: ${err.message}`);
46
+ throw new error_1.FirebaseError(`Failed to register publisher ID ${clc.bold(publisherId)} for project ${clc.bold(projectId)}: ${(0, error_1.getErrMsg)(err)}`);
47
47
  }
48
48
  utils.logLabeledSuccess(extensionsHelper_1.logPrefix, `Publisher ID '${clc.bold(publisherId)}' has been registered to project ${clc.bold(projectId)}. View and edit your profile at ${utils.consoleUrl(projectId, `/publisher`)}`);
49
49
  return profile;
@@ -44,13 +44,13 @@ async function uploadExtensionAction(extensionRef, options) {
44
44
  profile = await (0, publisherApi_1.getPublisherProfile)("-", publisherId);
45
45
  }
46
46
  catch (err) {
47
- if (err.status === 404) {
47
+ if ((0, error_1.getErrStatus)(err) === 404) {
48
48
  throw (0, extensionsHelper_1.getMissingPublisherError)(publisherId);
49
49
  }
50
50
  throw err;
51
51
  }
52
52
  const projectNumber = `${(0, extensionsHelper_2.getPublisherProjectFromName)(profile.name)}`;
53
- const { projectId } = await (0, projects_1.getFirebaseProject)(projectNumber);
53
+ const { projectId } = await (0, projects_1.getProject)(projectNumber);
54
54
  await (0, tos_1.acceptLatestPublisherTOS)(options, projectNumber);
55
55
  let res;
56
56
  if (options.local) {
@@ -36,7 +36,7 @@ exports.command = new command_1.Command("ext:dev:usage <publisherId>")
36
36
  extensions = await (0, publisherApi_1.listExtensions)(publisherId);
37
37
  }
38
38
  catch (err) {
39
- throw new error_1.FirebaseError(err);
39
+ throw new error_1.FirebaseError((0, error_1.getErrMsg)(err));
40
40
  }
41
41
  if (extensions.length < 1) {
42
42
  throw new error_1.FirebaseError(`There are no published extensions associated with publisher ID ${clc.bold(publisherId)}. This could happen for two reasons:\n` +
@@ -77,7 +77,7 @@ exports.command = new command_1.Command("ext:dev:usage <publisherId>")
77
77
  }
78
78
  catch (err) {
79
79
  throw new error_1.FirebaseError(`Error occurred when fetching usage data for extension ${extensionName}`, {
80
- original: err,
80
+ original: (0, error_1.getError)(err),
81
81
  });
82
82
  }
83
83
  if (!response) {
@@ -110,8 +110,8 @@ exports.command = new command_1.Command("ext:install [extensionRef]")
110
110
  }
111
111
  catch (err) {
112
112
  if (!(err instanceof error_1.FirebaseError)) {
113
- throw new error_1.FirebaseError(`Error occurred saving the extension to manifest: ${err.message}`, {
114
- original: err,
113
+ throw new error_1.FirebaseError(`Error occurred saving the extension to manifest: ${(0, error_1.getErrMsg)(err)}`, {
114
+ original: (0, error_1.getError)(err),
115
115
  });
116
116
  }
117
117
  throw err;
@@ -17,11 +17,14 @@ function load(client) {
17
17
  client.appdistribution = {};
18
18
  client.appdistribution.distribute = loadCommand("appdistribution-distribute");
19
19
  client.appdistribution.testers = {};
20
+ client.appdistribution.testers.list = loadCommand("appdistribution-testers-list");
20
21
  client.appdistribution.testers.add = loadCommand("appdistribution-testers-add");
21
22
  client.appdistribution.testers.delete = loadCommand("appdistribution-testers-remove");
22
23
  client.appdistribution.group = {};
23
- client.appdistribution.group.create = loadCommand("appdistribution-group-create");
24
- client.appdistribution.group.delete = loadCommand("appdistribution-group-delete");
24
+ client.appdistribution.group.list = loadCommand("appdistribution-groups-list");
25
+ client.appdistribution.group.create = loadCommand("appdistribution-groups-create");
26
+ client.appdistribution.group.delete = loadCommand("appdistribution-groups-delete");
27
+ client.appdistribution.groups = client.appdistribution.group;
25
28
  client.apps = {};
26
29
  client.apps.create = loadCommand("apps-create");
27
30
  client.apps.list = loadCommand("apps-list");
@@ -169,6 +172,8 @@ function load(client) {
169
172
  client.apphosting.secrets.grantaccess = loadCommand("apphosting-secrets-grantaccess");
170
173
  client.apphosting.secrets.describe = loadCommand("apphosting-secrets-describe");
171
174
  client.apphosting.secrets.access = loadCommand("apphosting-secrets-access");
175
+ client.apphosting.config = {};
176
+ client.apphosting.config.export = loadCommand("apphosting-config-export");
172
177
  if (experiments.isEnabled("internaltesting")) {
173
178
  client.apphosting.builds = {};
174
179
  client.apphosting.builds.get = loadCommand("apphosting-builds-get");
@@ -179,10 +184,6 @@ function load(client) {
179
184
  client.apphosting.rollouts.create = loadCommand("apphosting-rollouts-create");
180
185
  client.apphosting.rollouts.list = loadCommand("apphosting-rollouts-list");
181
186
  }
182
- if (experiments.isEnabled("emulatorapphosting")) {
183
- client.apphosting.config = {};
184
- client.apphosting.config.export = loadCommand("apphosting-config-export");
185
- }
186
187
  }
187
188
  client.login = loadCommand("login");
188
189
  client.login.add = loadCommand("login-add");
@@ -53,7 +53,7 @@ exports.command = new command_1.Command("use [alias_or_project_id]")
53
53
  const hasAlias = options.rc.hasProjectAlias(newActive);
54
54
  const resolvedProject = options.rc.resolveAlias(newActive);
55
55
  (0, command_2.validateProjectId)(resolvedProject);
56
- return (0, projects_1.getFirebaseProject)(resolvedProject)
56
+ return (0, projects_1.getProject)(resolvedProject)
57
57
  .then((foundProject) => {
58
58
  project = foundProject;
59
59
  })
@@ -18,7 +18,9 @@ async function deploy(context, options, payload) {
18
18
  ...((_b = payload.instancesToUpdate) !== null && _b !== void 0 ? _b : []),
19
19
  ...((_c = payload.instancesToConfigure) !== null && _c !== void 0 ? _c : []),
20
20
  ]);
21
- await (0, secrets_1.handleSecretParams)(payload, context.have, options.nonInteractive);
21
+ if (context.have) {
22
+ await (0, secrets_1.handleSecretParams)(payload, context.have, options.nonInteractive);
23
+ }
22
24
  const errorHandler = new errors_1.ErrorHandler();
23
25
  const validationQueue = new queue_1.default({
24
26
  retries: 5,
@@ -11,7 +11,7 @@ const humanReadableUpdate = (from, to) => {
11
11
  to.ref &&
12
12
  from.ref.publisherId === to.ref.publisherId &&
13
13
  from.ref.extensionId === to.ref.extensionId) {
14
- return `\t${clc.bold(from.instanceId)} (${refs.toExtensionVersionRef(from.ref)} => ${(_a = to.ref) === null || _a === void 0 ? void 0 : _a.version})`;
14
+ return `\t${clc.bold(from.instanceId)} (${refs.toExtensionVersionRef(from.ref)} => ${((_a = to.ref) === null || _a === void 0 ? void 0 : _a.version) || ""})`;
15
15
  }
16
16
  else {
17
17
  const fromRef = from.ref
@@ -32,6 +32,9 @@ function updatesSummary(toUpdate, have) {
32
32
  const instancesToUpdate = toUpdate
33
33
  .map((to) => {
34
34
  const from = have.find((exists) => exists.instanceId === to.instanceId);
35
+ if (!from) {
36
+ return "";
37
+ }
35
38
  return humanReadableUpdate(from, to);
36
39
  })
37
40
  .join("\n");
@@ -46,6 +46,9 @@ async function getExtensionSpec(i) {
46
46
  throw new error_1.FirebaseError("InstanceSpec had no ref or localPath, unable to get extensionSpec");
47
47
  }
48
48
  }
49
+ if (!i.extensionSpec) {
50
+ throw new error_1.FirebaseError("Internal error getting extension");
51
+ }
49
52
  return i.extensionSpec;
50
53
  }
51
54
  exports.getExtensionSpec = getExtensionSpec;
@@ -54,8 +57,12 @@ async function haveDynamic(projectId) {
54
57
  .filter((i) => { var _a; return ((_a = i.labels) === null || _a === void 0 ? void 0 : _a.createdBy) === "SDK"; })
55
58
  .map((i) => {
56
59
  var _a;
60
+ const instanceId = i.name.split("/").pop();
61
+ if (!instanceId) {
62
+ throw new error_1.FirebaseError(`Internal error getting instanceId from ${i.name}`);
63
+ }
57
64
  const dep = {
58
- instanceId: i.name.split("/").pop(),
65
+ instanceId,
59
66
  params: i.config.params,
60
67
  systemParams: (_a = i.config.systemParams) !== null && _a !== void 0 ? _a : {},
61
68
  allowedEventTypes: i.config.allowedEventTypes,
@@ -77,8 +84,12 @@ async function have(projectId) {
77
84
  .filter((i) => { var _a; return !(((_a = i.labels) === null || _a === void 0 ? void 0 : _a.createdBy) === "SDK"); })
78
85
  .map((i) => {
79
86
  var _a;
87
+ const instanceId = i.name.split("/").pop();
88
+ if (!instanceId) {
89
+ throw new error_1.FirebaseError(`Internal error getting instanceId from ${i.name}`);
90
+ }
80
91
  const dep = {
81
- instanceId: i.name.split("/").pop(),
92
+ instanceId,
82
93
  params: i.config.params,
83
94
  systemParams: (_a = i.config.systemParams) !== null && _a !== void 0 ? _a : {},
84
95
  allowedEventTypes: i.config.allowedEventTypes,
@@ -196,7 +207,7 @@ async function want(args) {
196
207
  }
197
208
  }
198
209
  catch (err) {
199
- logger_1.logger.debug(`Got error reading extensions entry ${e}: ${err}`);
210
+ logger_1.logger.debug(`Got error reading extensions entry ${e[0]} (${e[1]}): ${(0, error_1.getErrMsg)(err)}`);
200
211
  errors.push(err);
201
212
  }
202
213
  }
@@ -18,6 +18,15 @@ const v2FunctionHelper_1 = require("./v2FunctionHelper");
18
18
  const tos_1 = require("../../extensions/tos");
19
19
  const common_1 = require("../../extensions/runtimes/common");
20
20
  const functionsDeployHelper_1 = require("../functions/functionsDeployHelper");
21
+ const matchesInstanceId = (dep) => (test) => {
22
+ return dep.instanceId === test.instanceId;
23
+ };
24
+ const isUpdate = (dep) => (test) => {
25
+ return dep.instanceId === test.instanceId && !refs.equal(dep.ref, test.ref);
26
+ };
27
+ const isConfigure = (dep) => (test) => {
28
+ return dep.instanceId === test.instanceId && refs.equal(dep.ref, test.ref);
29
+ };
21
30
  async function prepareHelper(context, options, payload, wantExtensions, haveExtensions, isDynamic) {
22
31
  var _a, _b;
23
32
  const projectId = (0, projectUtils_1.needProjectId)(options);
@@ -146,12 +155,3 @@ async function prepare(context, options, payload) {
146
155
  return prepareHelper(context, options, payload, wantExtensions, haveExtensions, false);
147
156
  }
148
157
  exports.prepare = prepare;
149
- const matchesInstanceId = (dep) => (test) => {
150
- return dep.instanceId === test.instanceId;
151
- };
152
- const isUpdate = (dep) => (test) => {
153
- return dep.instanceId === test.instanceId && !refs.equal(dep.ref, test.ref);
154
- };
155
- const isConfigure = (dep) => (test) => {
156
- return dep.instanceId === test.instanceId && refs.equal(dep.ref, test.ref);
157
- };
@@ -15,7 +15,7 @@ const metadataCallCache = new Map();
15
15
  async function defaultServiceAccount(e) {
16
16
  let metadataCall = metadataCallCache.get(e.project);
17
17
  if (!metadataCall) {
18
- metadataCall = (0, projects_1.getFirebaseProject)(e.project);
18
+ metadataCall = (0, projects_1.getProject)(e.project);
19
19
  metadataCallCache.set(e.project, metadataCall);
20
20
  }
21
21
  const metadata = await metadataCall;
@@ -224,7 +224,7 @@ class Fabricator {
224
224
  }
225
225
  }
226
226
  async createV2Function(endpoint, scraper) {
227
- var _a, _b, _c, _d, _e;
227
+ var _a, _b, _c, _d;
228
228
  const storageSource = (_a = this.sources[endpoint.codebase]) === null || _a === void 0 ? void 0 : _a.storage;
229
229
  if (!storageSource) {
230
230
  logger_1.logger.debug("Precondition failed. Cannot create a GCFv2 function without storage");
@@ -295,8 +295,8 @@ class Fabricator {
295
295
  }
296
296
  });
297
297
  }
298
- endpoint.uri = (_d = resultFunction.serviceConfig) === null || _d === void 0 ? void 0 : _d.uri;
299
- const serviceName = (_e = resultFunction.serviceConfig) === null || _e === void 0 ? void 0 : _e.service;
298
+ endpoint.uri = resultFunction.url;
299
+ const serviceName = (_d = resultFunction.serviceConfig) === null || _d === void 0 ? void 0 : _d.service;
300
300
  endpoint.runServiceId = utils.last(serviceName === null || serviceName === void 0 ? void 0 : serviceName.split("/"));
301
301
  if (!serviceName) {
302
302
  logger_1.logger.debug("Result function unexpectedly didn't have a service name.");
@@ -8,9 +8,10 @@ const error_1 = require("../error");
8
8
  const needProjectId = require("../projectUtils").needProjectId;
9
9
  const logger_1 = require("../logger");
10
10
  const path = require("path");
11
+ const vsCodeUtils_1 = require("../vsCodeUtils");
11
12
  function runCommand(command, childOptions) {
12
13
  const escapedCommand = command.replace(/\"/g, '\\"');
13
- const isVSCode = utils.isVSCodeExtension();
14
+ const isVSCode = (0, vsCodeUtils_1.isVSCodeExtension)();
14
15
  const nodeExecutable = isVSCode ? "node" : process.execPath;
15
16
  const crossEnvShellPath = isVSCode
16
17
  ? path.resolve(__dirname, "./cross-env/dist/bin/cross-env-shell.js")
@@ -3,8 +3,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getLocalAppHostingConfiguration = void 0;
4
4
  const path_1 = require("path");
5
5
  const config_1 = require("../../apphosting/config");
6
- async function getLocalAppHostingConfiguration(cwd) {
7
- const appHostingConfigPaths = (0, config_1.discoverConfigsAtBackendRoot)(cwd);
6
+ const yaml_1 = require("../../apphosting/yaml");
7
+ async function getLocalAppHostingConfiguration(backendDir) {
8
+ const appHostingConfigPaths = (0, config_1.listAppHostingFilesInPath)(backendDir);
8
9
  const fileNameToPathMap = new Map();
9
10
  for (const path of appHostingConfigPaths) {
10
11
  const fileName = (0, path_1.basename)(path);
@@ -12,6 +13,15 @@ async function getLocalAppHostingConfiguration(cwd) {
12
13
  }
13
14
  const baseFilePath = fileNameToPathMap.get(config_1.APPHOSTING_BASE_YAML_FILE);
14
15
  const localFilePath = fileNameToPathMap.get(config_1.APPHOSTING_LOCAL_YAML_FILE);
15
- return await (0, config_1.loadConfigForEnvironment)(localFilePath !== null && localFilePath !== void 0 ? localFilePath : baseFilePath, baseFilePath);
16
+ if (!baseFilePath && !localFilePath) {
17
+ return yaml_1.AppHostingYamlConfig.empty();
18
+ }
19
+ if (!baseFilePath || !localFilePath) {
20
+ return await yaml_1.AppHostingYamlConfig.loadFromFile((baseFilePath || localFilePath));
21
+ }
22
+ const localYamlConfig = await yaml_1.AppHostingYamlConfig.loadFromFile(localFilePath);
23
+ const baseConfig = await yaml_1.AppHostingYamlConfig.loadFromFile(baseFilePath);
24
+ baseConfig.merge(localYamlConfig);
25
+ return baseConfig;
16
26
  }
17
27
  exports.getLocalAppHostingConfiguration = getLocalAppHostingConfiguration;
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.detectStartCommand = exports.detectPackageManager = exports.logger = void 0;
4
+ const fs_extra_1 = require("fs-extra");
5
+ const path_1 = require("path");
6
+ const emulatorLogger_1 = require("../emulatorLogger");
7
+ const types_1 = require("../types");
8
+ const error_1 = require("../../error");
9
+ exports.logger = emulatorLogger_1.EmulatorLogger.forEmulator(types_1.Emulators.APPHOSTING);
10
+ async function detectPackageManager(rootdir) {
11
+ if (await (0, fs_extra_1.pathExists)((0, path_1.join)(rootdir, "pnpm-lock.yaml"))) {
12
+ return "pnpm";
13
+ }
14
+ if (await (0, fs_extra_1.pathExists)((0, path_1.join)(rootdir, "yarn.lock"))) {
15
+ return "yarn";
16
+ }
17
+ if (await (0, fs_extra_1.pathExists)((0, path_1.join)(rootdir, "package-lock.json"))) {
18
+ return "npm";
19
+ }
20
+ throw new error_1.FirebaseError("Unsupported package manager");
21
+ }
22
+ exports.detectPackageManager = detectPackageManager;
23
+ async function detectStartCommand(rootDir) {
24
+ try {
25
+ const packageManager = await detectPackageManager(rootDir);
26
+ return `${packageManager} run dev`;
27
+ }
28
+ catch (e) {
29
+ throw new error_1.FirebaseError("Failed to auto-detect your project's start command. Consider manually setting the start command by setting `firebase.json#emulators.apphosting.startCommandOverride`");
30
+ }
31
+ }
32
+ exports.detectStartCommand = detectStartCommand;
@@ -3,24 +3,26 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.AppHostingEmulator = void 0;
4
4
  const types_1 = require("../types");
5
5
  const serve_1 = require("./serve");
6
- const utils_1 = require("./utils");
6
+ const developmentServer_1 = require("./developmentServer");
7
7
  class AppHostingEmulator {
8
8
  constructor(args) {
9
9
  this.args = args;
10
10
  }
11
11
  async start() {
12
12
  const { hostname, port } = await (0, serve_1.start)({
13
+ port: this.args.port,
13
14
  startCommand: this.args.startCommandOverride,
15
+ rootDirectory: this.args.rootDirectory,
14
16
  });
15
17
  this.args.options.host = hostname;
16
18
  this.args.options.port = port;
17
19
  }
18
20
  connect() {
19
- utils_1.logger.logLabeled("INFO", types_1.Emulators.APPHOSTING, "connecting apphosting emulator");
21
+ developmentServer_1.logger.logLabeled("INFO", types_1.Emulators.APPHOSTING, "connecting apphosting emulator");
20
22
  return Promise.resolve();
21
23
  }
22
24
  stop() {
23
- utils_1.logger.logLabeled("INFO", types_1.Emulators.APPHOSTING, "stopping apphosting emulator");
25
+ developmentServer_1.logger.logLabeled("INFO", types_1.Emulators.APPHOSTING, "stopping apphosting emulator");
24
26
  return Promise.resolve();
25
27
  }
26
28
  getInfo() {
@@ -3,38 +3,41 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.start = void 0;
4
4
  const net_1 = require("net");
5
5
  const portUtils_1 = require("../portUtils");
6
- const utils_1 = require("./utils");
6
+ const developmentServer_1 = require("./developmentServer");
7
7
  const constants_1 = require("../constants");
8
8
  const spawn_1 = require("../../init/spawn");
9
- const utils_2 = require("./utils");
9
+ const developmentServer_2 = require("./developmentServer");
10
10
  const types_1 = require("../types");
11
11
  const config_1 = require("./config");
12
+ const projectPath_1 = require("../../projectPath");
12
13
  async function start(options) {
14
+ var _a;
13
15
  const hostname = constants_1.DEFAULT_HOST;
14
- let port = constants_1.DEFAULT_PORTS.apphosting;
16
+ let port = (_a = options === null || options === void 0 ? void 0 : options.port) !== null && _a !== void 0 ? _a : constants_1.DEFAULT_PORTS.apphosting;
15
17
  while (!(await availablePort(hostname, port))) {
16
18
  port += 1;
17
19
  }
18
- serve(port, options === null || options === void 0 ? void 0 : options.startCommand);
20
+ serve(port, options === null || options === void 0 ? void 0 : options.startCommand, options === null || options === void 0 ? void 0 : options.rootDirectory);
19
21
  return { hostname, port };
20
22
  }
21
23
  exports.start = start;
22
- async function serve(port, startCommand) {
23
- const rootDir = process.cwd();
24
- const apphostingLocalConfig = await (0, config_1.getLocalAppHostingConfiguration)(rootDir);
24
+ async function serve(port, startCommand, backendRelativeDir) {
25
+ backendRelativeDir = backendRelativeDir !== null && backendRelativeDir !== void 0 ? backendRelativeDir : "./";
26
+ const backendRoot = (0, projectPath_1.resolveProjectPath)({}, backendRelativeDir);
27
+ const apphostingLocalConfig = await (0, config_1.getLocalAppHostingConfiguration)(backendRoot);
25
28
  const environmentVariablesAsRecord = {};
26
29
  for (const env of apphostingLocalConfig.environmentVariables) {
27
30
  environmentVariablesAsRecord[env.variable] = env.value;
28
31
  }
29
32
  const environmentVariablesToInject = Object.assign(Object.assign({}, environmentVariablesAsRecord), { PORT: port.toString() });
30
33
  if (startCommand) {
31
- utils_2.logger.logLabeled("BULLET", types_1.Emulators.APPHOSTING, `running custom start command: '${startCommand}'`);
32
- await (0, spawn_1.spawnWithCommandString)(startCommand, rootDir, environmentVariablesToInject);
34
+ developmentServer_2.logger.logLabeled("BULLET", types_1.Emulators.APPHOSTING, `running custom start command: '${startCommand}'`);
35
+ await (0, spawn_1.spawnWithCommandString)(startCommand, backendRoot, environmentVariablesToInject);
33
36
  return;
34
37
  }
35
- const packageManager = await (0, utils_1.discoverPackageManager)(rootDir);
36
- utils_2.logger.logLabeled("BULLET", types_1.Emulators.APPHOSTING, `starting app with: '${packageManager} run dev'`);
37
- await (0, spawn_1.wrapSpawn)(packageManager, ["run", "dev"], rootDir, environmentVariablesToInject);
38
+ const detectedStartCommand = await (0, developmentServer_1.detectStartCommand)(backendRoot);
39
+ developmentServer_2.logger.logLabeled("BULLET", types_1.Emulators.APPHOSTING, `starting app with: '${detectedStartCommand}'`);
40
+ await (0, spawn_1.spawnWithCommandString)(detectedStartCommand, backendRoot, environmentVariablesToInject);
38
41
  }
39
42
  function availablePort(host, port) {
40
43
  return (0, portUtils_1.checkListenable)({
@@ -300,8 +300,9 @@ async function emulatorExec(script, options) {
300
300
  exitCode = await runScript(script, extraEnv);
301
301
  await controller.onExit(options);
302
302
  }
303
- catch (_a) {
303
+ catch (err) {
304
304
  await (0, webhook_1.sendVSCodeMessage)({ message: webhook_1.VSCODE_MESSAGE.EMULATORS_START_ERRORED });
305
+ throw err;
305
306
  }
306
307
  finally {
307
308
  await controller.cleanShutdown();