firebase-tools 12.2.1 → 12.3.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 (35) hide show
  1. package/lib/commands/functions-secrets-access.js +2 -0
  2. package/lib/commands/functions-secrets-destroy.js +1 -0
  3. package/lib/commands/functions-secrets-get.js +2 -0
  4. package/lib/commands/functions-secrets-prune.js +3 -2
  5. package/lib/commands/functions-secrets-set.js +8 -0
  6. package/lib/commands/hosting-channel-deploy.js +5 -3
  7. package/lib/commands/index.js +2 -0
  8. package/lib/commands/internaltesting-frameworks-compose.js +20 -0
  9. package/lib/deploy/functions/release/executor.js +19 -10
  10. package/lib/deploy/functions/release/fabricator.js +22 -8
  11. package/lib/deploy/index.js +1 -1
  12. package/lib/emulator/auth/operations.js +2 -2
  13. package/lib/emulator/commandUtils.js +1 -1
  14. package/lib/emulator/controller.js +6 -2
  15. package/lib/emulator/functionsEmulatorShared.js +3 -0
  16. package/lib/frameworks/angular/index.js +10 -9
  17. package/lib/frameworks/astro/index.js +8 -6
  18. package/lib/frameworks/compose/discover/index.js +23 -0
  19. package/lib/frameworks/compose/driver/docker.js +177 -0
  20. package/lib/frameworks/compose/driver/hooks.js +22 -0
  21. package/lib/frameworks/compose/driver/index.js +16 -0
  22. package/lib/frameworks/compose/driver/local.js +42 -0
  23. package/lib/frameworks/compose/index.js +30 -0
  24. package/lib/frameworks/compose/interfaces.js +21 -0
  25. package/lib/frameworks/index.js +57 -48
  26. package/lib/frameworks/next/index.js +18 -17
  27. package/lib/frameworks/nuxt/index.js +7 -7
  28. package/lib/frameworks/nuxt2/index.js +2 -1
  29. package/lib/frameworks/utils.js +37 -22
  30. package/lib/frameworks/vite/index.js +2 -1
  31. package/lib/functions/secrets.js +8 -1
  32. package/lib/serve/index.js +1 -1
  33. package/package.json +1 -1
  34. package/templates/extensions/extension.yaml +7 -57
  35. package/templates/extensions/javascript/index.js +1 -1
@@ -5,8 +5,10 @@ const command_1 = require("../command");
5
5
  const logger_1 = require("../logger");
6
6
  const projectUtils_1 = require("../projectUtils");
7
7
  const secretManager_1 = require("../gcp/secretManager");
8
+ const secrets = require("../functions/secrets");
8
9
  exports.command = new command_1.Command("functions:secrets:access <KEY>[@version]")
9
10
  .description("Access secret value given secret and its version. Defaults to accessing the latest version.")
11
+ .before(secrets.ensureApi)
10
12
  .action(async (key, options) => {
11
13
  const projectId = (0, projectUtils_1.needProjectId)(options);
12
14
  let [name, version] = key.split("@");
@@ -11,6 +11,7 @@ const backend = require("../deploy/functions/backend");
11
11
  exports.command = new command_1.Command("functions:secrets:destroy <KEY>[@version]")
12
12
  .description("Destroy a secret. Defaults to destroying the latest version.")
13
13
  .withForce("Destroys a secret without confirmation.")
14
+ .before(secrets.ensureApi)
14
15
  .action(async (key, options) => {
15
16
  const projectId = (0, projectUtils_1.needProjectId)(options);
16
17
  const projectNumber = await (0, projectUtils_1.needProjectNumber)(options);
@@ -7,8 +7,10 @@ const logger_1 = require("../logger");
7
7
  const projectUtils_1 = require("../projectUtils");
8
8
  const secretManager_1 = require("../gcp/secretManager");
9
9
  const requirePermissions_1 = require("../requirePermissions");
10
+ const secrets = require("../functions/secrets");
10
11
  exports.command = new command_1.Command("functions:secrets:get <KEY>")
11
12
  .description("Get metadata for secret and its versions")
13
+ .before(secrets.ensureApi)
12
14
  .before(requirePermissions_1.requirePermissions, ["secretmanager.secrets.get"])
13
15
  .action(async (key, options) => {
14
16
  const projectId = (0, projectUtils_1.needProjectId)(options);
@@ -4,7 +4,7 @@ exports.command = void 0;
4
4
  const backend = require("../deploy/functions/backend");
5
5
  const command_1 = require("../command");
6
6
  const projectUtils_1 = require("../projectUtils");
7
- const secrets_1 = require("../functions/secrets");
7
+ const secrets = require("../functions/secrets");
8
8
  const requirePermissions_1 = require("../requirePermissions");
9
9
  const deploymentTool_1 = require("../deploymentTool");
10
10
  const utils_1 = require("../utils");
@@ -13,6 +13,7 @@ const secretManager_1 = require("../gcp/secretManager");
13
13
  exports.command = new command_1.Command("functions:secrets:prune")
14
14
  .withForce("Destroys unused secrets without prompt")
15
15
  .description("Destroys unused secrets")
16
+ .before(secrets.ensureApi)
16
17
  .before(requirePermissions_1.requirePermissions, [
17
18
  "cloudfunctions.functions.list",
18
19
  "secretmanager.secrets.list",
@@ -27,7 +28,7 @@ exports.command = new command_1.Command("functions:secrets:prune")
27
28
  const haveEndpoints = backend
28
29
  .allEndpoints(haveBackend)
29
30
  .filter((e) => (0, deploymentTool_1.isFirebaseManaged)(e.labels || []));
30
- const pruned = await (0, secrets_1.pruneSecrets)({ projectNumber, projectId }, haveEndpoints);
31
+ const pruned = await secrets.pruneSecrets({ projectNumber, projectId }, haveEndpoints);
31
32
  if (pruned.length === 0) {
32
33
  (0, utils_1.logBullet)("All secrets are in use. Nothing to prune today.");
33
34
  return;
@@ -4,6 +4,7 @@ exports.command = void 0;
4
4
  const tty = require("tty");
5
5
  const fs = require("fs");
6
6
  const clc = require("colorette");
7
+ const logger_1 = require("../logger");
7
8
  const secrets_1 = require("../functions/secrets");
8
9
  const command_1 = require("../command");
9
10
  const requirePermissions_1 = require("../requirePermissions");
@@ -13,9 +14,11 @@ const projectUtils_1 = require("../projectUtils");
13
14
  const secretManager_1 = require("../gcp/secretManager");
14
15
  const secrets = require("../functions/secrets");
15
16
  const backend = require("../deploy/functions/backend");
17
+ const ensureApiEnabled_1 = require("../ensureApiEnabled");
16
18
  exports.command = new command_1.Command("functions:secrets:set <KEY>")
17
19
  .description("Create or update a secret for use in Cloud Functions for Firebase.")
18
20
  .withForce("Automatically updates functions to use the new secret.")
21
+ .before(secrets.ensureApi)
19
22
  .before(requirePermissions_1.requirePermissions, [
20
23
  "secretmanager.secrets.create",
21
24
  "secretmanager.secrets.get",
@@ -50,6 +53,11 @@ exports.command = new command_1.Command("functions:secrets:set <KEY>")
50
53
  clc.bold("firebase deploy --only functions"));
51
54
  return;
52
55
  }
56
+ const functionsEnabled = await (0, ensureApiEnabled_1.check)(projectId, "cloudfunctions.googleapis.com", "functions", true);
57
+ if (!functionsEnabled) {
58
+ logger_1.logger.debug("Customer set secrets before enabling functions. Exiting");
59
+ return;
60
+ }
53
61
  const haveBackend = await backend.existingBackend({ projectId });
54
62
  const endpointsToUpdate = backend
55
63
  .allEndpoints(haveBackend)
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.command = void 0;
3
+ exports.hostingChannelDeployAction = exports.command = void 0;
4
4
  const colorette_1 = require("colorette");
5
5
  const command_1 = require("../command");
6
6
  const error_1 = require("../error");
@@ -25,7 +25,8 @@ exports.command = new command_1.Command("hosting:channel:deploy [channelId]")
25
25
  .before(requireConfig_1.requireConfig)
26
26
  .before(requirePermissions_1.requirePermissions, ["firebasehosting.sites.update"])
27
27
  .before(requireHostingSite_1.requireHostingSite)
28
- .action(async (channelId, options) => {
28
+ .action(hostingChannelDeployAction);
29
+ async function hostingChannelDeployAction(channelId, options) {
29
30
  const projectId = (0, projectUtils_1.needProjectId)(options);
30
31
  if (options.open) {
31
32
  throw new error_1.FirebaseError("open is not yet implemented");
@@ -122,7 +123,8 @@ exports.command = new command_1.Command("hosting:channel:deploy [channelId]")
122
123
  (0, utils_1.logLabeledSuccess)(LOG_TAG, `Channel URL (${(0, colorette_1.bold)(d.site || d.target || "")}): ${d.url} ${expires}${version}`);
123
124
  });
124
125
  return deploys;
125
- });
126
+ }
127
+ exports.hostingChannelDeployAction = hostingChannelDeployAction;
126
128
  async function syncAuthState(projectId, sites) {
127
129
  const siteNames = sites.map((d) => d.site);
128
130
  const urlNames = sites.map((d) => d.url);
@@ -137,6 +137,8 @@ function load(client) {
137
137
  client.init = loadCommand("init");
138
138
  if (experiments.isEnabled("internaltesting")) {
139
139
  client.internaltesting = {};
140
+ client.internaltesting.frameworks = {};
141
+ client.internaltesting.frameworks.compose = loadCommand("internaltesting-frameworks-compose");
140
142
  client.internaltesting.functions = {};
141
143
  client.internaltesting.functions.discover = loadCommand("internaltesting-functions-discover");
142
144
  }
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.command = void 0;
4
+ const command_1 = require("../command");
5
+ const logger_1 = require("../logger");
6
+ const driver_1 = require("../frameworks/compose/driver");
7
+ const compose_1 = require("../frameworks/compose");
8
+ const error_1 = require("../error");
9
+ exports.command = new command_1.Command("internaltesting:frameworks:compose")
10
+ .option("-m, --mode <mode>", "Composer mode (local or docker)", "local")
11
+ .description("compose framework in current directory")
12
+ .action((options) => {
13
+ const mode = options.mode;
14
+ if (!driver_1.SUPPORTED_MODES.includes(mode)) {
15
+ throw new error_1.FirebaseError(`Unsupported mode ${mode}. Supported modes are [${driver_1.SUPPORTED_MODES.join(", ")}]`);
16
+ }
17
+ const bundle = (0, compose_1.compose)(mode);
18
+ logger_1.logger.info(JSON.stringify(bundle, null, 2));
19
+ return {};
20
+ });
@@ -1,21 +1,26 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.InlineExecutor = exports.QueueExecutor = void 0;
3
+ exports.InlineExecutor = exports.QueueExecutor = exports.DEFAULT_RETRY_CODES = void 0;
4
4
  const queue_1 = require("../../../throttler/queue");
5
- async function handler(op) {
5
+ exports.DEFAULT_RETRY_CODES = [429, 409, 503];
6
+ function parseErrorCode(err) {
6
7
  var _a, _b, _c, _d, _e, _f;
8
+ return (err.status ||
9
+ err.code ||
10
+ ((_b = (_a = err.context) === null || _a === void 0 ? void 0 : _a.response) === null || _b === void 0 ? void 0 : _b.statusCode) ||
11
+ ((_c = err.original) === null || _c === void 0 ? void 0 : _c.code) ||
12
+ ((_f = (_e = (_d = err.original) === null || _d === void 0 ? void 0 : _d.context) === null || _e === void 0 ? void 0 : _e.response) === null || _f === void 0 ? void 0 : _f.statusCode));
13
+ }
14
+ async function handler(op) {
7
15
  try {
8
16
  op.result = await op.func();
9
17
  }
10
18
  catch (err) {
11
- const code = err.status ||
12
- err.code ||
13
- ((_b = (_a = err.context) === null || _a === void 0 ? void 0 : _a.response) === null || _b === void 0 ? void 0 : _b.statusCode) ||
14
- ((_c = err.original) === null || _c === void 0 ? void 0 : _c.code) ||
15
- ((_f = (_e = (_d = err.original) === null || _d === void 0 ? void 0 : _d.context) === null || _e === void 0 ? void 0 : _e.response) === null || _f === void 0 ? void 0 : _f.statusCode);
16
- if (code === 429 || code === 409 || code === 503) {
19
+ const code = parseErrorCode(err);
20
+ if (op.retryCodes.includes(code)) {
17
21
  throw err;
18
22
  }
23
+ err.code = code;
19
24
  op.error = err;
20
25
  }
21
26
  return;
@@ -24,8 +29,12 @@ class QueueExecutor {
24
29
  constructor(options) {
25
30
  this.queue = new queue_1.Queue(Object.assign(Object.assign({}, options), { handler }));
26
31
  }
27
- async run(func) {
28
- const op = { func };
32
+ async run(func, opts) {
33
+ const retryCodes = (opts === null || opts === void 0 ? void 0 : opts.retryCodes) || exports.DEFAULT_RETRY_CODES;
34
+ const op = {
35
+ func,
36
+ retryCodes,
37
+ };
29
38
  await this.queue.run(op);
30
39
  if (op.error) {
31
40
  throw op.error;
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Fabricator = void 0;
4
4
  const clc = require("colorette");
5
+ const executor_1 = require("./executor");
5
6
  const error_1 = require("../../../error");
6
7
  const sourceTokenScraper_1 = require("./sourceTokenScraper");
7
8
  const timer_1 = require("./timer");
@@ -44,6 +45,7 @@ const eventarcPollerOptions = {
44
45
  masterTimeout: 25 * 60 * 1000,
45
46
  maxBackoff: 10000,
46
47
  };
48
+ const CLOUD_RUN_RESOURCE_EXHAUSTED_CODE = 8;
47
49
  const rethrowAs = (endpoint, op) => (err) => {
48
50
  logger_1.logger.error(err.message);
49
51
  throw new reporter.DeploymentError(endpoint, op, err);
@@ -269,12 +271,24 @@ class Fabricator {
269
271
  })
270
272
  .catch(rethrowAs(endpoint, "upsert eventarc channel"));
271
273
  }
272
- const resultFunction = await this.functionExecutor
273
- .run(async () => {
274
- const op = await gcfV2.createFunction(apiFunction);
275
- return await poller.pollOperation(Object.assign(Object.assign({}, gcfV2PollerOptions), { pollerName: `create-${endpoint.codebase}-${endpoint.region}-${endpoint.id}`, operationResourceName: op.name }));
276
- })
277
- .catch(rethrowAs(endpoint, "create"));
274
+ let resultFunction = null;
275
+ while (!resultFunction) {
276
+ resultFunction = await this.functionExecutor
277
+ .run(async () => {
278
+ const op = await gcfV2.createFunction(apiFunction);
279
+ return await poller.pollOperation(Object.assign(Object.assign({}, gcfV2PollerOptions), { pollerName: `create-${endpoint.codebase}-${endpoint.region}-${endpoint.id}`, operationResourceName: op.name }));
280
+ })
281
+ .catch(async (err) => {
282
+ if (err.code === CLOUD_RUN_RESOURCE_EXHAUSTED_CODE) {
283
+ await this.deleteV2Function(endpoint);
284
+ return null;
285
+ }
286
+ else {
287
+ logger_1.logger.error(err.message);
288
+ throw new reporter.DeploymentError(endpoint, "create", err);
289
+ }
290
+ });
291
+ }
278
292
  endpoint.uri = (_d = resultFunction.serviceConfig) === null || _d === void 0 ? void 0 : _d.uri;
279
293
  const serviceName = (_e = resultFunction.serviceConfig) === null || _e === void 0 ? void 0 : _e.service;
280
294
  endpoint.runServiceId = utils.last(serviceName === null || serviceName === void 0 ? void 0 : serviceName.split("/"));
@@ -367,7 +381,7 @@ class Fabricator {
367
381
  .run(async () => {
368
382
  const op = await gcfV2.updateFunction(apiFunction);
369
383
  return await poller.pollOperation(Object.assign(Object.assign({}, gcfV2PollerOptions), { pollerName: `update-${endpoint.codebase}-${endpoint.region}-${endpoint.id}`, operationResourceName: op.name }));
370
- })
384
+ }, { retryCodes: [...executor_1.DEFAULT_RETRY_CODES, CLOUD_RUN_RESOURCE_EXHAUSTED_CODE] })
371
385
  .catch(rethrowAs(endpoint, "update"));
372
386
  endpoint.uri = (_c = resultFunction.serviceConfig) === null || _c === void 0 ? void 0 : _c.uri;
373
387
  const serviceName = (_d = resultFunction.serviceConfig) === null || _d === void 0 ? void 0 : _d.service;
@@ -414,7 +428,7 @@ class Fabricator {
414
428
  const op = await gcfV2.deleteFunction(fnName);
415
429
  const pollerOptions = Object.assign(Object.assign({}, gcfV2PollerOptions), { pollerName: `delete-${endpoint.codebase}-${endpoint.region}-${endpoint.id}`, operationResourceName: op.name });
416
430
  await poller.pollOperation(pollerOptions);
417
- })
431
+ }, { retryCodes: [...executor_1.DEFAULT_RETRY_CODES, CLOUD_RUN_RESOURCE_EXHAUSTED_CODE] })
418
432
  .catch(rethrowAs(endpoint, "delete"));
419
433
  }
420
434
  async setRunTraits(serviceName, endpoint) {
@@ -52,7 +52,7 @@ const deploy = async function (targetNames, options, customContext = {}) {
52
52
  const config = options.config.get("hosting");
53
53
  if (Array.isArray(config) ? config.some((it) => it.source) : config.source) {
54
54
  experiments.assertEnabled("webframeworks", "deploy a web framework from source");
55
- await (0, frameworks_1.prepareFrameworks)(targetNames, context, options);
55
+ await (0, frameworks_1.prepareFrameworks)("deploy", targetNames, context, options);
56
56
  }
57
57
  }
58
58
  if (targetNames.includes("hosting") && (0, prepare_1.hasPinnedFunctions)(options)) {
@@ -146,13 +146,13 @@ async function signUp(state, reqBody, ctx) {
146
146
  (0, errors_1.assert)(state.enableAnonymousUser, "ADMIN_ONLY_OPERATION");
147
147
  }
148
148
  }
149
- if (reqBody.email) {
149
+ if (typeof reqBody.email === "string") {
150
150
  (0, errors_1.assert)((0, utils_1.isValidEmailAddress)(reqBody.email), "INVALID_EMAIL");
151
151
  const email = (0, utils_1.canonicalizeEmailAddress)(reqBody.email);
152
152
  (0, errors_1.assert)(!state.getUserByEmail(email), "EMAIL_EXISTS");
153
153
  updates.email = email;
154
154
  }
155
- if (reqBody.password) {
155
+ if (typeof reqBody.password === "string") {
156
156
  (0, errors_1.assert)(reqBody.password.length >= PASSWORD_MIN_LENGTH, `WEAK_PASSWORD : Password should be at least ${PASSWORD_MIN_LENGTH} characters`);
157
157
  updates.salt = "fakeSalt" + (0, utils_1.randomId)(20);
158
158
  updates.passwordHash = hashPassword(reqBody.password, updates.salt);
@@ -288,7 +288,7 @@ async function emulatorExec(script, options) {
288
288
  let deprecationNotices;
289
289
  try {
290
290
  const showUI = !!options.ui;
291
- ({ deprecationNotices } = await controller.startAll(options, showUI));
291
+ ({ deprecationNotices } = await controller.startAll(options, showUI, true));
292
292
  exitCode = await runScript(script, extraEnv);
293
293
  await controller.onExit(options);
294
294
  }
@@ -116,6 +116,10 @@ function shouldStart(options, name) {
116
116
  }
117
117
  exports.shouldStart = shouldStart;
118
118
  function findExportMetadata(importPath) {
119
+ const pathExists = fs.existsSync(importPath);
120
+ if (!pathExists) {
121
+ throw new error_1.FirebaseError(`Directory "${importPath}" does not exist.`);
122
+ }
119
123
  const pathIsDirectory = fs.lstatSync(importPath).isDirectory();
120
124
  if (!pathIsDirectory) {
121
125
  return;
@@ -151,7 +155,7 @@ function findExportMetadata(importPath) {
151
155
  return metadata;
152
156
  }
153
157
  }
154
- async function startAll(options, showUI = true) {
158
+ async function startAll(options, showUI = true, runningTestScript = false) {
155
159
  var _a, _b, _c, _d, _e, _f, _g;
156
160
  const targets = filterEmulatorTargets(options);
157
161
  options.targets = targets;
@@ -291,7 +295,7 @@ async function startAll(options, showUI = true) {
291
295
  });
292
296
  }
293
297
  }
294
- await (0, frameworks_1.prepareFrameworks)(targets, options, options, emulators);
298
+ await (0, frameworks_1.prepareFrameworks)(runningTestScript ? "test" : "emulate", targets, undefined, options, emulators);
295
299
  }
296
300
  const projectDir = (options.extDevDir || options.config.projectDir);
297
301
  if (shouldStart(options, types_1.Emulators.FUNCTIONS)) {
@@ -272,6 +272,9 @@ function getSignatureType(def) {
272
272
  if (def.httpsTrigger || def.blockingTrigger) {
273
273
  return "http";
274
274
  }
275
+ if (def.platform === "gcfv2" && def.schedule) {
276
+ return "http";
277
+ }
275
278
  return def.platform === "gcfv2" ? "cloudevent" : "event";
276
279
  }
277
280
  exports.getSignatureType = getSignatureType;
@@ -44,7 +44,7 @@ async function init(setup, config) {
44
44
  }
45
45
  exports.init = init;
46
46
  async function build(dir, configuration) {
47
- const { targets, serverTarget, serveOptimizedImages, locales, baseHref } = await (0, utils_2.getBuildConfig)(dir, configuration);
47
+ const { targets, serverTarget, serveOptimizedImages, locales, baseHref: baseUrl, } = await (0, utils_2.getBuildConfig)(dir, configuration);
48
48
  await (0, utils_1.warnIfCustomBuildScript)(dir, exports.name, DEFAULT_BUILD_SCRIPT);
49
49
  for (const target of targets) {
50
50
  const cli = (0, utils_1.getNodeModuleBin)("ng", dir);
@@ -60,12 +60,12 @@ async function build(dir, configuration) {
60
60
  ? []
61
61
  : [
62
62
  {
63
- source: path_1.posix.join(baseHref, "**"),
64
- destination: path_1.posix.join(baseHref, "index.html"),
63
+ source: path_1.posix.join(baseUrl, "**"),
64
+ destination: path_1.posix.join(baseUrl, "index.html"),
65
65
  },
66
66
  ];
67
67
  const i18n = !!locales;
68
- return { wantsBackend, i18n, rewrites };
68
+ return { wantsBackend, i18n, rewrites, baseUrl };
69
69
  }
70
70
  exports.build = build;
71
71
  async function getDevModeHandle(dir, configuration) {
@@ -73,7 +73,7 @@ async function getDevModeHandle(dir, configuration) {
73
73
  const { serveTarget } = await (0, utils_2.getContext)(dir, configuration);
74
74
  if (!serveTarget)
75
75
  throw new Error("Could not find the serveTarget");
76
- const host = new Promise((resolve) => {
76
+ const host = new Promise((resolve, reject) => {
77
77
  const cli = (0, utils_1.getNodeModuleBin)("ng", dir);
78
78
  const serve = (0, cross_spawn_1.spawn)(cli, ["run", targetStringFromTarget(serveTarget), "--host", "localhost"], {
79
79
  cwd: dir,
@@ -87,6 +87,7 @@ async function getDevModeHandle(dir, configuration) {
87
87
  serve.stderr.on("data", (data) => {
88
88
  process.stderr.write(data);
89
89
  });
90
+ serve.on("exit", reject);
90
91
  });
91
92
  return (0, utils_1.simpleProxy)(await host);
92
93
  }
@@ -114,7 +115,7 @@ async function getValidBuildTargets(purpose, dir) {
114
115
  const validTargetNames = new Set(["development", "production"]);
115
116
  try {
116
117
  const { workspaceProject, browserTarget, serverTarget, serveTarget } = await (0, utils_2.getContext)(dir);
117
- const { target } = ((purpose === "serve" && serveTarget) || serverTarget || browserTarget);
118
+ const { target } = ((purpose === "emulate" && serveTarget) || serverTarget || browserTarget);
118
119
  const workspaceTarget = workspaceProject.targets.get(target);
119
120
  Object.keys(workspaceTarget.configurations || {}).forEach((it) => validTargetNames.add(it));
120
121
  }
@@ -134,7 +135,7 @@ exports.shouldUseDevModeHandle = shouldUseDevModeHandle;
134
135
  async function ɵcodegenFunctionsDirectory(sourceDir, destDir, configuration) {
135
136
  var _a;
136
137
  var _b;
137
- const { packageJson, serverOutputPath, browserOutputPath, defaultLocale, serverLocales, browserLocales, bundleDependencies, externalDependencies, baseHref: baseUrl, serveOptimizedImages, } = await (0, utils_2.getServerConfig)(sourceDir, configuration);
138
+ const { packageJson, serverOutputPath, browserOutputPath, defaultLocale, serverLocales, browserLocales, bundleDependencies, externalDependencies, baseHref, serveOptimizedImages, } = await (0, utils_2.getServerConfig)(sourceDir, configuration);
138
139
  const dotEnv = { __NG_BROWSER_OUTPUT_PATH__: browserOutputPath };
139
140
  let rewriteSource = undefined;
140
141
  await Promise.all([
@@ -187,8 +188,8 @@ exports.handle = function(req,res) {
187
188
  }
188
189
  else {
189
190
  bootstrapScript = `exports.handle = (res, req) => req.sendStatus(404);\n`;
190
- rewriteSource = path_1.posix.join(baseUrl, "__image__");
191
+ rewriteSource = path_1.posix.join(baseHref, "__image__");
191
192
  }
192
- return { bootstrapScript, packageJson, baseUrl, dotEnv, rewriteSource };
193
+ return { bootstrapScript, packageJson, dotEnv, rewriteSource };
193
194
  }
194
195
  exports.ɵcodegenFunctionsDirectory = ɵcodegenFunctionsDirectory;
@@ -21,7 +21,7 @@ async function discover(dir) {
21
21
  return;
22
22
  const { output, publicDir: publicDirectory } = await (0, utils_2.getConfig)(dir);
23
23
  return {
24
- mayWantBackend: output === "server",
24
+ mayWantBackend: output !== "static",
25
25
  publicDirectory,
26
26
  };
27
27
  }
@@ -31,18 +31,19 @@ async function build(cwd) {
31
31
  const cli = (0, utils_1.getNodeModuleBin)("astro", cwd);
32
32
  await (0, utils_1.warnIfCustomBuildScript)(cwd, exports.name, DEFAULT_BUILD_SCRIPT);
33
33
  const { output, adapter } = await (0, utils_2.getConfig)(cwd);
34
- if (output === "server" && (adapter === null || adapter === void 0 ? void 0 : adapter.name) !== "@astrojs/node") {
35
- throw new error_1.FirebaseError("Deploying an Astro application with SSR on Firebase Hosting requires the @astrojs/node adapter.");
34
+ const wantsBackend = output !== "static";
35
+ if (wantsBackend && (adapter === null || adapter === void 0 ? void 0 : adapter.name) !== "@astrojs/node") {
36
+ throw new error_1.FirebaseError("Deploying an Astro application with SSR on Firebase Hosting requires the @astrojs/node adapter in middleware mode. https://docs.astro.build/en/guides/integrations-guide/node/");
36
37
  }
37
38
  const build = (0, cross_spawn_1.sync)(cli, ["build"], { cwd, stdio: "inherit" });
38
39
  if (build.status !== 0)
39
40
  throw new error_1.FirebaseError("Unable to build your Astro app");
40
- return { wantsBackend: output === "server" };
41
+ return { wantsBackend };
41
42
  }
42
43
  exports.build = build;
43
44
  async function ɵcodegenPublicDirectory(root, dest) {
44
45
  const { outDir, output } = await (0, utils_2.getConfig)(root);
45
- const assetPath = (0, path_1.join)(root, outDir, output === "server" ? "client" : "");
46
+ const assetPath = (0, path_1.join)(root, outDir, output !== "static" ? "client" : "");
46
47
  await (0, fs_extra_1.copy)(assetPath, dest);
47
48
  }
48
49
  exports.ɵcodegenPublicDirectory = ɵcodegenPublicDirectory;
@@ -57,7 +58,7 @@ async function ɵcodegenFunctionsDirectory(sourceDir, destDir) {
57
58
  }
58
59
  exports.ɵcodegenFunctionsDirectory = ɵcodegenFunctionsDirectory;
59
60
  async function getDevModeHandle(cwd) {
60
- const host = new Promise((resolve) => {
61
+ const host = new Promise((resolve, reject) => {
61
62
  const cli = (0, utils_1.getNodeModuleBin)("astro", cwd);
62
63
  const serve = (0, cross_spawn_1.spawn)(cli, ["dev"], { cwd });
63
64
  serve.stdout.on("data", (data) => {
@@ -69,6 +70,7 @@ async function getDevModeHandle(cwd) {
69
70
  serve.stderr.on("data", (data) => {
70
71
  process.stderr.write(data);
71
72
  });
73
+ serve.on("exit", reject);
72
74
  });
73
75
  return (0, utils_1.simpleProxy)(await host);
74
76
  }
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.discover = void 0;
4
+ function discover() {
5
+ return {
6
+ baseImage: "us-docker.pkg.dev/firestack-build/test/run:latest",
7
+ environmentVariables: {
8
+ NODE_ENV: "PRODUCTION",
9
+ },
10
+ installCommand: "npm install",
11
+ buildCommand: "npm run build",
12
+ startCommand: "npm run start",
13
+ afterInstall: (b) => {
14
+ console.log("HOOK: AFTER INSTALL");
15
+ return Object.assign(Object.assign({}, b), { version: "v1alpha", notes: "afterInstall" });
16
+ },
17
+ afterBuild(b) {
18
+ console.log("HOOK: AFTER BUILD");
19
+ return Object.assign(Object.assign({}, b), { version: "v1alpha", notes: "afterBuild" });
20
+ },
21
+ };
22
+ }
23
+ exports.discover = discover;