astro 7.1.5 → 7.2.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 (113) hide show
  1. package/dist/assets/build/generate.d.ts +8 -1
  2. package/dist/assets/build/generate.js +21 -1
  3. package/dist/assets/fonts/providers/index.js +12 -2
  4. package/dist/assets/types.d.ts +13 -0
  5. package/dist/assets/vite-plugin-assets.js +8 -0
  6. package/dist/cli/add/index.js +1 -1
  7. package/dist/cli/agent.d.ts +1 -0
  8. package/dist/cli/agent.js +11 -0
  9. package/dist/cli/dev/background.d.ts +3 -16
  10. package/dist/cli/dev/background.js +7 -93
  11. package/dist/cli/dev/index.d.ts +12 -0
  12. package/dist/cli/dev/index.js +30 -23
  13. package/dist/cli/dev/logs.js +2 -64
  14. package/dist/cli/dev/status.d.ts +2 -9
  15. package/dist/cli/dev/status.js +6 -24
  16. package/dist/cli/dev/stop.d.ts +2 -6
  17. package/dist/cli/dev/stop.js +6 -14
  18. package/dist/cli/infra/build-time-astro-version-provider.js +1 -1
  19. package/dist/cli/install-package.js +1 -1
  20. package/dist/cli/preview/index.js +77 -3
  21. package/dist/cli/server.d.ts +60 -0
  22. package/dist/cli/server.js +274 -0
  23. package/dist/content/consts.d.ts +4 -0
  24. package/dist/content/consts.js +8 -0
  25. package/dist/content/content-layer.js +3 -3
  26. package/dist/content/data-store-writer.d.ts +1 -1
  27. package/dist/content/data-store-writer.js +4 -3
  28. package/dist/content/data-store.d.ts +3 -3
  29. package/dist/content/data-store.js +3 -3
  30. package/dist/content/mutable-data-store.d.ts +3 -3
  31. package/dist/content/mutable-data-store.js +5 -5
  32. package/dist/content/paths.d.ts +2 -1
  33. package/dist/content/paths.js +11 -0
  34. package/dist/content/runtime.d.ts +2 -0
  35. package/dist/content/runtime.js +2 -0
  36. package/dist/content/types-generator.js +1 -0
  37. package/dist/content/vite-plugin-content-assets.js +6 -1
  38. package/dist/content/vite-plugin-content-imports.js +12 -3
  39. package/dist/content/vite-plugin-content-virtual-mod.js +69 -31
  40. package/dist/core/app/entrypoints/index.d.ts +2 -0
  41. package/dist/core/app/entrypoints/index.js +14 -0
  42. package/dist/core/build/config-hash/index.d.ts +8 -0
  43. package/dist/core/build/config-hash/index.js +23 -0
  44. package/dist/core/build/config-hash/input.d.ts +199 -0
  45. package/dist/core/build/config-hash/input.js +43 -0
  46. package/dist/core/build/generate.d.ts +3 -1
  47. package/dist/core/build/generate.js +204 -62
  48. package/dist/core/build/incremental-content-collector.d.ts +10 -0
  49. package/dist/core/build/incremental-content-collector.js +33 -0
  50. package/dist/core/build/incremental-image-collector.d.ts +11 -0
  51. package/dist/core/build/incremental-image-collector.js +32 -0
  52. package/dist/core/build/incremental-metadata.d.ts +9 -0
  53. package/dist/core/build/incremental-metadata.js +17 -0
  54. package/dist/core/build/incremental.d.ts +123 -0
  55. package/dist/core/build/incremental.js +178 -0
  56. package/dist/core/build/index.d.ts +3 -0
  57. package/dist/core/build/index.js +6 -2
  58. package/dist/core/build/internal.d.ts +19 -0
  59. package/dist/core/build/lockfile/finder.d.ts +22 -0
  60. package/dist/core/build/lockfile/finder.js +45 -0
  61. package/dist/core/build/lockfile/hasher.d.ts +16 -0
  62. package/dist/core/build/lockfile/hasher.js +46 -0
  63. package/dist/core/build/lockfile/index.d.ts +9 -0
  64. package/dist/core/build/lockfile/index.js +16 -0
  65. package/dist/core/build/plugins/index.js +3 -1
  66. package/dist/core/build/plugins/plugin-incremental.d.ts +14 -0
  67. package/dist/core/build/plugins/plugin-incremental.js +134 -0
  68. package/dist/core/build/types.d.ts +2 -0
  69. package/dist/core/config/schemas/base.d.ts +7 -6
  70. package/dist/core/config/schemas/base.js +9 -1
  71. package/dist/core/config/schemas/defaults.d.ts +1 -0
  72. package/dist/core/config/schemas/defaults.js +1 -0
  73. package/dist/core/config/schemas/relative.d.ts +19 -10
  74. package/dist/core/constants.js +1 -1
  75. package/dist/core/create-vite.js +2 -1
  76. package/dist/core/dev/dev.js +5 -4
  77. package/dist/core/dev/lockfile.d.ts +8 -7
  78. package/dist/core/dev/lockfile.js +13 -13
  79. package/dist/core/encryption.d.ts +6 -0
  80. package/dist/core/encryption.js +14 -2
  81. package/dist/core/errors/default-handler.js +4 -5
  82. package/dist/core/fetch/index.js +1 -1
  83. package/dist/core/logger/config.d.ts +1 -1
  84. package/dist/core/logger/load.d.ts +3 -1
  85. package/dist/core/logger/load.js +3 -3
  86. package/dist/core/logger/utils.d.ts +6 -4
  87. package/dist/core/logger/utils.js +13 -5
  88. package/dist/core/logger/vite-plugin.js +1 -1
  89. package/dist/core/messages/runtime.js +1 -1
  90. package/dist/core/preview/static-preview-server.d.ts +2 -0
  91. package/dist/core/preview/static-preview-server.js +1 -0
  92. package/dist/core/routing/handler.js +1 -1
  93. package/dist/core/session/config.d.ts +2 -2
  94. package/dist/core/session/config.js +2 -1
  95. package/dist/core/session/provider-disabled.d.ts +2 -0
  96. package/dist/core/session/provider-disabled.js +7 -0
  97. package/dist/core/session/provider.d.ts +1 -0
  98. package/dist/core/session/provider.js +4 -0
  99. package/dist/core/session/utils.js +3 -0
  100. package/dist/core/session/vite-plugin.d.ts +3 -0
  101. package/dist/core/session/vite-plugin.js +41 -6
  102. package/dist/core/sync/index.js +5 -4
  103. package/dist/integrations/hooks.js +3 -1
  104. package/dist/runtime/prerender/static-paths.js +5 -1
  105. package/dist/runtime/server/render/util.js +3 -0
  106. package/dist/types/public/common.d.ts +1 -0
  107. package/dist/types/public/config.d.ts +73 -7
  108. package/dist/types/public/integrations.d.ts +29 -2
  109. package/dist/types/public/preview.d.ts +2 -0
  110. package/dist/vite-plugin-config-alias/index.js +1 -0
  111. package/dist/vite-plugin-environment/index.js +4 -1
  112. package/dist/vite-plugin-hmr-reload/index.js +60 -18
  113. package/package.json +2 -3
@@ -2,7 +2,7 @@ import type { StaticBuildOptions } from '../../core/build/types.js';
2
2
  import type { AstroLogger } from '../../core/logger/core.js';
3
3
  import type { MapValue } from '../../type-utils.js';
4
4
  import type { AstroConfig } from '../../types/public/config.js';
5
- import type { AssetsGlobalStaticImagesList } from '../types.js';
5
+ import type { AssetsGlobalStaticImagesList, SerializedStaticImage } from '../types.js';
6
6
  type AssetEnv = {
7
7
  logger: AstroLogger;
8
8
  isSSR: boolean;
@@ -20,4 +20,11 @@ type AssetEnv = {
20
20
  export declare function prepareAssetsGenerationEnv(options: StaticBuildOptions, totalCount: number): Promise<AssetEnv>;
21
21
  export declare function generateImagesForPath(originalFilePath: string, transformsAndPath: MapValue<AssetsGlobalStaticImagesList>, env: AssetEnv): Promise<void>;
22
22
  export declare function getStaticImageList(): AssetsGlobalStaticImagesList;
23
+ /**
24
+ * Replay transforms attributed to a skipped page back into the global list, so
25
+ * the asset pipeline emits its optimized images even though the page was not
26
+ * rendered this build. Existing transforms (already added by a rendered page
27
+ * that shares the image) are left untouched.
28
+ */
29
+ export declare function restoreStaticImages(images: SerializedStaticImage[]): void;
23
30
  export {};
@@ -233,6 +233,25 @@ function getStaticImageList() {
233
233
  }
234
234
  return globalThis.astroAsset.staticImages;
235
235
  }
236
+ function restoreStaticImages(images) {
237
+ if (!globalThis.astroAsset) {
238
+ globalThis.astroAsset = { referencedImages: /* @__PURE__ */ new Set() };
239
+ }
240
+ const staticImages = globalThis.astroAsset.staticImages ??= /* @__PURE__ */ new Map();
241
+ for (const image of images) {
242
+ let transformsForPath = staticImages.get(image.originalPath);
243
+ if (!transformsForPath) {
244
+ transformsForPath = { originalSrcPath: image.originalSrcPath, transforms: /* @__PURE__ */ new Map() };
245
+ staticImages.set(image.originalPath, transformsForPath);
246
+ }
247
+ if (!transformsForPath.transforms.has(image.hash)) {
248
+ transformsForPath.transforms.set(image.hash, {
249
+ finalPath: image.finalPath,
250
+ transform: image.transform
251
+ });
252
+ }
253
+ }
254
+ }
236
255
  async function loadImage(path, env) {
237
256
  if (isRemotePath(path)) {
238
257
  return await loadRemoteImage(path, void 0, env.imageConfig);
@@ -245,5 +264,6 @@ async function loadImage(path, env) {
245
264
  export {
246
265
  generateImagesForPath,
247
266
  getStaticImageList,
248
- prepareAssetsGenerationEnv
267
+ prepareAssetsGenerationEnv,
268
+ restoreStaticImages
249
269
  };
@@ -94,8 +94,18 @@ function googleicons() {
94
94
  async init(context) {
95
95
  initializedProvider = await provider(context);
96
96
  },
97
- async resolveFont({ familyName, ...rest }) {
98
- return await initializedProvider?.resolveFont(familyName, rest);
97
+ async resolveFont({ familyName, options, ...rest }) {
98
+ const patchedOptions = options?.experimental?.glyphs && options.experimental.glyphs.length > 1 ? {
99
+ ...options,
100
+ experimental: {
101
+ ...options.experimental,
102
+ glyphs: [options.experimental.glyphs.join(",")]
103
+ }
104
+ } : options;
105
+ return await initializedProvider?.resolveFont(familyName, {
106
+ options: patchedOptions,
107
+ ...rest
108
+ });
99
109
  },
100
110
  async listFonts() {
101
111
  return await initializedProvider?.listFonts?.();
@@ -14,6 +14,19 @@ export type AssetsGlobalStaticImagesList = Map<string, {
14
14
  transform: ImageTransform;
15
15
  }>;
16
16
  }>;
17
+ /**
18
+ * A single image transform flattened for persistence in the incremental build
19
+ * cache. `AssetsGlobalStaticImagesList` nests transforms under their original
20
+ * path; this carries the original path and transform hash inline so a skipped
21
+ * page's transforms can be replayed into the global list without a re-render.
22
+ */
23
+ export interface SerializedStaticImage {
24
+ originalPath: string;
25
+ hash: string;
26
+ finalPath: string;
27
+ originalSrcPath: string | undefined;
28
+ transform: ImageTransform;
29
+ }
17
30
  declare global {
18
31
  var astroAsset: {
19
32
  imageService?: ImageService;
@@ -9,6 +9,7 @@ import {
9
9
  removeBase,
10
10
  removeQueryString
11
11
  } from "../core/path.js";
12
+ import { recordStaticImage } from "../core/build/incremental-image-collector.js";
12
13
  import { normalizePath } from "../core/viteUtils.js";
13
14
  import { ASTRO_VITE_ENVIRONMENT_NAMES } from "../core/constants.js";
14
15
  import { isAstroServerEnvironment } from "../environments.js";
@@ -72,6 +73,13 @@ const addStaticImageFactory = (settings) => {
72
73
  transform: options
73
74
  });
74
75
  }
76
+ recordStaticImage({
77
+ originalPath: finalOriginalPath,
78
+ hash,
79
+ finalPath: finalFilePath,
80
+ originalSrcPath: originalFSPath,
81
+ transform: options
82
+ });
75
83
  const url = createPlaceholderURL(
76
84
  settings.config.build.assetsPrefix ? encodeURI(joinPaths(assetPrefix, finalFilePath)) : encodeURI(prependForwardSlash(joinPaths(settings.config.base, finalFilePath)))
77
85
  );
@@ -627,7 +627,7 @@ async function tryToInstallIntegrations({
627
627
  cwd,
628
628
  // Include the `install-metadata` strategy to have the package manager that's
629
629
  // used for installation take precedence
630
- strategies: ["install-metadata", "lockfile", "packageManager-field"]
630
+ strategies: ["install-metadata", "lockfile", "packageManager-field", "devEngines-field"]
631
631
  });
632
632
  logger.debug("add", `package manager: "${packageManager?.name}"`);
633
633
  if (!packageManager) return "none";
@@ -0,0 +1 @@
1
+ export declare function isRunByAgent(): boolean;
@@ -0,0 +1,11 @@
1
+ import { detectAgenticEnvironment } from "am-i-vibing";
2
+ function isRunByAgent() {
3
+ try {
4
+ return detectAgenticEnvironment().type === "agent";
5
+ } catch {
6
+ return false;
7
+ }
8
+ }
9
+ export {
10
+ isRunByAgent
11
+ };
@@ -1,21 +1,8 @@
1
1
  import type { AstroLogger } from '../../core/logger/core.js';
2
2
  import type { Flags } from '../flags.js';
3
- import { type LockFileData } from '../../core/dev/lockfile.js';
4
- export interface BackgroundResult {
5
- pid: number;
6
- url: string;
7
- existing?: boolean;
8
- }
9
- export interface BackgroundErrorResult {
10
- error: string;
11
- message: string;
12
- }
13
- export declare function formatBackgroundOutput(result: BackgroundResult | BackgroundErrorResult): string;
14
- /**
15
- * Build the human-readable message shown when a background dev server is running.
16
- * Lists every network address (when `--host` exposed any) so the output matches
17
- * the foreground dev server, then appends the management command hints.
18
- */
3
+ import type { LockFileData } from '../../core/dev/lockfile.js';
4
+ import { formatBackgroundOutput, type BackgroundErrorResult, type BackgroundResult } from '../server.js';
5
+ export { formatBackgroundOutput, type BackgroundErrorResult, type BackgroundResult };
19
6
  export declare function formatServerRunningMessage(data: LockFileData, { existing }?: {
20
7
  existing?: boolean;
21
8
  }): string;
@@ -1,103 +1,17 @@
1
- import { spawn } from "node:child_process";
2
- import { existsSync, mkdirSync, openSync } from "node:fs";
3
- import { createRequire } from "node:module";
4
- import { dirname, resolve } from "node:path";
5
- import { fileURLToPath, pathToFileURL } from "node:url";
6
1
  import {
7
- checkExistingServer,
8
- getLogFileURL,
9
- readLockFile,
10
- removeLockFile,
11
- isProcessAlive,
12
- killDevServer
13
- } from "../../core/dev/lockfile.js";
14
- import { resolveRoot } from "../../core/config/config.js";
15
- const require2 = createRequire(import.meta.url);
16
- function formatBackgroundOutput(result) {
17
- return JSON.stringify(result);
18
- }
2
+ background as startBackgroundServer,
3
+ devServerCommand,
4
+ formatBackgroundOutput,
5
+ formatServerRunningMessage as formatServerMessage
6
+ } from "../server.js";
19
7
  function formatServerRunningMessage(data, { existing = false } = {}) {
20
- const lines = [
21
- `Dev server ${existing ? "already running" : "running"} at ${data.url} (pid ${data.pid})`
22
- ];
23
- if (data.urls && data.urls.network.length > 0) {
24
- lines.push(" Network:");
25
- for (const url of data.urls.network) {
26
- lines.push(` ${url}`);
27
- }
28
- }
29
- lines.push(" Stop: astro dev stop", " Status: astro dev status", " Logs: astro dev logs");
30
- return lines.join("\n");
8
+ return formatServerMessage(data, devServerCommand, { existing });
31
9
  }
32
10
  async function background({
33
11
  flags,
34
12
  logger
35
13
  }) {
36
- const root = pathToFileURL(resolveRoot(flags.root) + "/");
37
- const existing = checkExistingServer(root);
38
- if (existing && !flags.force) {
39
- logger.info("SKIP_FORMAT", formatServerRunningMessage(existing, { existing: true }));
40
- return;
41
- }
42
- if (existing && flags.force) {
43
- await killDevServer(root, existing);
44
- }
45
- const args = ["dev"];
46
- if (flags.port) args.push("--port", String(flags.port));
47
- if (flags.host != null) {
48
- if (typeof flags.host === "string") {
49
- args.push("--host", flags.host);
50
- } else {
51
- args.push("--host");
52
- }
53
- }
54
- if (flags.config) args.push("--config", String(flags.config));
55
- if (flags.root) args.push("--root", String(flags.root));
56
- if (flags.allowedHosts) args.push("--allowed-hosts", String(flags.allowedHosts));
57
- if (flags.json) args.push("--json");
58
- const logFileURL = getLogFileURL(root);
59
- const logFilePath = fileURLToPath(logFileURL);
60
- const dotAstroDir = fileURLToPath(new URL(".astro/", root));
61
- if (!existsSync(dotAstroDir)) {
62
- mkdirSync(dotAstroDir, { recursive: true });
63
- }
64
- const logFd = openSync(logFilePath, "w");
65
- const rootPath = fileURLToPath(root);
66
- const astroBin = resolve(dirname(require2.resolve("astro/package.json")), "bin", "astro.mjs");
67
- const child = spawn(process.execPath, [astroBin, ...args], {
68
- detached: true,
69
- windowsHide: true,
70
- stdio: ["ignore", logFd, logFd],
71
- cwd: rootPath,
72
- env: { ...process.env, ASTRO_DEV_BACKGROUND: "1" }
73
- });
74
- child.unref();
75
- const childPid = child.pid;
76
- if (!childPid) {
77
- logger.error("SKIP_FORMAT", "Failed to spawn background dev server process.");
78
- process.exit(1);
79
- }
80
- const timeout = 3e4;
81
- const deadline = Date.now() + timeout;
82
- while (Date.now() < deadline) {
83
- if (!isProcessAlive(childPid)) {
84
- logger.error("SKIP_FORMAT", "Dev server process exited before becoming ready.");
85
- process.exit(1);
86
- }
87
- const lockData = readLockFile(root);
88
- if (lockData && lockData.pid === childPid) {
89
- logger.info("SKIP_FORMAT", formatServerRunningMessage(lockData));
90
- return;
91
- }
92
- await new Promise((r) => setTimeout(r, 200));
93
- }
94
- try {
95
- process.kill(childPid, "SIGTERM");
96
- } catch {
97
- }
98
- removeLockFile(root);
99
- logger.error("SKIP_FORMAT", `Dev server failed to start within ${timeout / 1e3}s.`);
100
- process.exit(1);
14
+ await startBackgroundServer({ flags, logger, config: devServerCommand });
101
15
  }
102
16
  export {
103
17
  background,
@@ -1,3 +1,4 @@
1
+ import type { ResolvedServerUrls } from 'vite';
1
2
  import { type Flags } from '../flags.js';
2
3
  interface DevOptions {
3
4
  flags: Flags;
@@ -13,6 +14,17 @@ export declare function isIgnoreLock(flags: Flags): boolean;
13
14
  * with `--ignore-lock`, or `null` if there's no conflict.
14
15
  */
15
16
  export declare function getBackgroundIgnoreLockConflict(flags: Flags, wantsBackground: boolean): string | null;
17
+ /**
18
+ * Pick the URL to record in the lock file.
19
+ *
20
+ * Vite only reports a `local` URL for loopback hosts. With `--host <custom-address>` set to a
21
+ * specific non-loopback address the URL lands in `network` instead and `local` is empty, so
22
+ * prefer `local` but fall back to `network` rather than reading `undefined`.
23
+ *
24
+ * Returns `null` when the server exposed no usable URL, which leaves the (purely bookkeeping)
25
+ * lock file unwritten instead of taking down an otherwise healthy dev server.
26
+ */
27
+ export declare function resolveLockFileUrl(resolvedUrls: ResolvedServerUrls): string | null;
16
28
  /**
17
29
  * `--force` (replace the existing server) and `--ignore-lock` (start alongside it,
18
30
  * untracked) express contradictory intent. Returns an error message if both are set,
@@ -1,4 +1,3 @@
1
- import { detectAgenticEnvironment } from "am-i-vibing";
2
1
  import colors from "piccolore";
3
2
  import devServer from "../../core/dev/index.js";
4
3
  import { pathToFileURL } from "node:url";
@@ -10,14 +9,8 @@ import {
10
9
  } from "../../core/dev/lockfile.js";
11
10
  import { resolveRoot } from "../../core/config/config.js";
12
11
  import { printHelp } from "../../core/messages/runtime.js";
12
+ import { isRunByAgent } from "../agent.js";
13
13
  import { createLoggerFromFlags, flagsToAstroInlineConfig } from "../flags.js";
14
- function isRunByAgent() {
15
- try {
16
- return detectAgenticEnvironment().type === "agent";
17
- } catch {
18
- return false;
19
- }
20
- }
21
14
  function isIgnoreLock(flags) {
22
15
  return flags.ignoreLock === true;
23
16
  }
@@ -33,6 +26,17 @@ function getBackgroundIgnoreLockConflict(flags, wantsBackground) {
33
26
  "Run the dev server in the foreground to use --ignore-lock."
34
27
  ].join("\n");
35
28
  }
29
+ function resolveLockFileUrl(resolvedUrls) {
30
+ const resolved = resolvedUrls.local[0] ?? resolvedUrls.network[0];
31
+ if (!resolved) {
32
+ return null;
33
+ }
34
+ try {
35
+ return new URL(resolved).origin;
36
+ } catch {
37
+ return null;
38
+ }
39
+ }
36
40
  function getForceIgnoreLockConflict(flags) {
37
41
  if (!flags.force) {
38
42
  return null;
@@ -155,25 +159,28 @@ Run \`astro dev --help\` to see available commands.`
155
159
  }
156
160
  const inlineConfig = flagsToAstroInlineConfig(flags);
157
161
  const server = await devServer(inlineConfig);
158
- const serverUrl = new URL(server.resolvedUrls.local[0]).origin;
159
- writeLockFile(root, {
160
- pid: process.pid,
161
- port: server.address.port,
162
- url: serverUrl,
163
- urls: server.resolvedUrls,
164
- background: !!process.env.ASTRO_DEV_BACKGROUND,
165
- startedAt: (/* @__PURE__ */ new Date()).toISOString()
166
- });
167
- const originalStop = server.stop.bind(server);
168
- server.stop = async () => {
169
- removeLockFile(root);
170
- await originalStop();
171
- };
162
+ const serverUrl = resolveLockFileUrl(server.resolvedUrls);
163
+ if (serverUrl) {
164
+ writeLockFile(root, {
165
+ pid: process.pid,
166
+ port: server.address.port,
167
+ url: serverUrl,
168
+ urls: server.resolvedUrls,
169
+ background: !!process.env.ASTRO_DEV_BACKGROUND,
170
+ startedAt: (/* @__PURE__ */ new Date()).toISOString()
171
+ });
172
+ const originalStop = server.stop.bind(server);
173
+ server.stop = async () => {
174
+ removeLockFile(root);
175
+ await originalStop();
176
+ };
177
+ }
172
178
  return server;
173
179
  }
174
180
  export {
175
181
  dev,
176
182
  getBackgroundIgnoreLockConflict,
177
183
  getForceIgnoreLockConflict,
178
- isIgnoreLock
184
+ isIgnoreLock,
185
+ resolveLockFileUrl
179
186
  };
@@ -1,71 +1,9 @@
1
- import { readFileSync, existsSync, statSync, createReadStream, watch } from "node:fs";
2
- import { fileURLToPath, pathToFileURL } from "node:url";
3
- import { checkExistingServer, getLogFileURL, isProcessAlive } from "../../core/dev/lockfile.js";
4
- import { resolveRoot } from "../../core/config/config.js";
1
+ import { devServerCommand, logs as serverLogs } from "../server.js";
5
2
  async function logs({
6
3
  flags,
7
4
  logger
8
5
  }) {
9
- const root = pathToFileURL(resolveRoot(flags.root) + "/");
10
- const existing = checkExistingServer(root);
11
- if (!existing) {
12
- logger.error("SKIP_FORMAT", "No dev server is running.");
13
- process.exit(1);
14
- }
15
- if (!existing.background) {
16
- logger.error(
17
- "SKIP_FORMAT",
18
- "The running dev server was not started with `astro dev --background`. View logs in the terminal where it was started."
19
- );
20
- process.exit(1);
21
- }
22
- const logFileURL = getLogFileURL(root);
23
- const logFilePath = fileURLToPath(logFileURL);
24
- if (!existsSync(logFilePath)) {
25
- logger.error("SKIP_FORMAT", "No log file found.");
26
- process.exit(1);
27
- }
28
- const follow = flags.follow || flags.f;
29
- if (!follow) {
30
- const content = readFileSync(logFilePath, "utf-8");
31
- process.stdout.write(content);
32
- return;
33
- }
34
- let offset = statSync(logFilePath).size;
35
- if (offset > 0) {
36
- const content = readFileSync(logFilePath, "utf-8");
37
- process.stdout.write(content);
38
- }
39
- const watcher = watch(logFilePath, () => {
40
- const currentSize = statSync(logFilePath).size;
41
- if (currentSize > offset) {
42
- const stream = createReadStream(logFilePath, { start: offset, encoding: "utf-8" });
43
- stream.on("data", (chunk) => process.stdout.write(chunk));
44
- stream.on("end", () => {
45
- offset = currentSize;
46
- });
47
- }
48
- });
49
- const aliveCheck = setInterval(() => {
50
- if (!isProcessAlive(existing.pid)) {
51
- const currentSize = statSync(logFilePath).size;
52
- if (currentSize > offset) {
53
- const remaining = readFileSync(logFilePath, { encoding: "utf-8" }).slice(offset);
54
- process.stdout.write(remaining);
55
- }
56
- watcher.close();
57
- clearInterval(aliveCheck);
58
- }
59
- }, 1e3);
60
- const cleanup = () => {
61
- watcher.close();
62
- clearInterval(aliveCheck);
63
- process.exit(0);
64
- };
65
- process.on("SIGINT", cleanup);
66
- process.on("SIGTERM", cleanup);
67
- await new Promise(() => {
68
- });
6
+ await serverLogs({ flags, logger, config: devServerCommand });
69
7
  }
70
8
  export {
71
9
  logs
@@ -1,14 +1,7 @@
1
1
  import type { AstroLogger } from '../../core/logger/core.js';
2
2
  import type { Flags } from '../flags.js';
3
- export interface StatusResult {
4
- running: boolean;
5
- pid?: number;
6
- url?: string;
7
- port?: number;
8
- background?: boolean;
9
- uptime?: number;
10
- }
11
- export declare function formatStatusOutput(result: StatusResult): string;
3
+ import { formatStatusOutput, type StatusResult } from '../server.js';
4
+ export { formatStatusOutput, type StatusResult };
12
5
  export declare function status({ flags, logger, }: {
13
6
  flags: Flags;
14
7
  logger: AstroLogger;
@@ -1,31 +1,13 @@
1
- import { pathToFileURL } from "node:url";
2
- import { checkExistingServer } from "../../core/dev/lockfile.js";
3
- import { resolveRoot } from "../../core/config/config.js";
4
- function formatStatusOutput(result) {
5
- return JSON.stringify(result);
6
- }
1
+ import {
2
+ devServerCommand,
3
+ formatStatusOutput,
4
+ status as serverStatus
5
+ } from "../server.js";
7
6
  async function status({
8
7
  flags,
9
8
  logger
10
9
  }) {
11
- const root = pathToFileURL(resolveRoot(flags.root) + "/");
12
- const existing = checkExistingServer(root);
13
- if (!existing) {
14
- logger.info("SKIP_FORMAT", "No dev server is running.");
15
- return;
16
- }
17
- const startedAt = new Date(existing.startedAt).getTime();
18
- const uptime = Math.floor((Date.now() - startedAt) / 1e3);
19
- const lines = [
20
- `Dev server running at ${existing.url} (pid ${existing.pid}, uptime ${uptime}s${existing.background ? ", background" : ""})`
21
- ];
22
- if (existing.urls && existing.urls.network.length > 0) {
23
- lines.push(" Network:");
24
- for (const url of existing.urls.network) {
25
- lines.push(` ${url}`);
26
- }
27
- }
28
- logger.info("SKIP_FORMAT", lines.join("\n"));
10
+ await serverStatus({ flags, logger, config: devServerCommand });
29
11
  }
30
12
  export {
31
13
  formatStatusOutput,
@@ -1,11 +1,7 @@
1
1
  import type { AstroLogger } from '../../core/logger/core.js';
2
2
  import type { Flags } from '../flags.js';
3
- export interface StopResult {
4
- stopped: boolean;
5
- pid?: number;
6
- reason?: string;
7
- }
8
- export declare function formatStopOutput(result: StopResult): string;
3
+ import { formatStopOutput, type StopResult } from '../server.js';
4
+ export { formatStopOutput, type StopResult };
9
5
  export declare function stop({ flags, logger, }: {
10
6
  flags: Flags;
11
7
  logger: AstroLogger;
@@ -1,21 +1,13 @@
1
- import { pathToFileURL } from "node:url";
2
- import { checkExistingServer, killDevServer } from "../../core/dev/lockfile.js";
3
- import { resolveRoot } from "../../core/config/config.js";
4
- function formatStopOutput(result) {
5
- return JSON.stringify(result);
6
- }
1
+ import {
2
+ devServerCommand,
3
+ formatStopOutput,
4
+ stop as stopServer
5
+ } from "../server.js";
7
6
  async function stop({
8
7
  flags,
9
8
  logger
10
9
  }) {
11
- const root = pathToFileURL(resolveRoot(flags.root) + "/");
12
- const existing = checkExistingServer(root);
13
- if (!existing) {
14
- logger.info("SKIP_FORMAT", "No dev server is running.");
15
- return;
16
- }
17
- await killDevServer(root, existing);
18
- logger.info("SKIP_FORMAT", `Stopped dev server (pid ${existing.pid}).`);
10
+ await stopServer({ flags, logger, config: devServerCommand });
19
11
  }
20
12
  export {
21
13
  formatStopOutput,
@@ -1,6 +1,6 @@
1
1
  class BuildTimeAstroVersionProvider {
2
2
  // Injected during the build through esbuild define
3
- version = "7.1.5";
3
+ version = "7.2.0";
4
4
  }
5
5
  export {
6
6
  BuildTimeAstroVersionProvider
@@ -40,7 +40,7 @@ async function installPackage(packageNames, options, logger) {
40
40
  cwd,
41
41
  // Include the `install-metadata` strategy to have the package manager that's
42
42
  // used for installation take precedence
43
- strategies: ["install-metadata", "lockfile", "packageManager-field"]
43
+ strategies: ["install-metadata", "lockfile", "packageManager-field", "devEngines-field"]
44
44
  });
45
45
  const installCommand = resolveCommand(packageManager?.agent ?? "npm", "add", []);
46
46
  if (!installCommand) return false;