astro 7.0.0-alpha.1 → 7.0.0-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (153) hide show
  1. package/components/Code.astro +1 -1
  2. package/dist/assets/endpoint/dev.js +1 -1
  3. package/dist/assets/endpoint/generic.js +7 -16
  4. package/dist/assets/endpoint/loadImage.d.ts +11 -0
  5. package/dist/assets/endpoint/loadImage.js +19 -0
  6. package/dist/assets/fonts/config.d.ts +4 -4
  7. package/dist/assets/fonts/core/optimize-fallbacks.js +38 -13
  8. package/dist/assets/fonts/definitions.d.ts +2 -2
  9. package/dist/assets/fonts/infra/system-fallbacks-provider.d.ts +2 -2
  10. package/dist/assets/fonts/infra/system-fallbacks-provider.js +46 -9
  11. package/dist/assets/fonts/types.d.ts +1 -0
  12. package/dist/assets/internal.js +20 -16
  13. package/dist/assets/services/service.d.ts +1 -1
  14. package/dist/assets/services/service.js +9 -9
  15. package/dist/assets/services/sharp.js +48 -28
  16. package/dist/assets/utils/generateImageStylesCSS.js +26 -6
  17. package/dist/assets/utils/inferSourceFormat.d.ts +8 -3
  18. package/dist/assets/utils/inferSourceFormat.js +15 -4
  19. package/dist/assets/utils/metadata.js +1 -1
  20. package/dist/assets/utils/vendor/image-size/types/svg.js +1 -1
  21. package/dist/cli/dev/background.d.ts +16 -0
  22. package/dist/cli/dev/background.js +116 -0
  23. package/dist/cli/dev/index.js +82 -3
  24. package/dist/cli/dev/logs.d.ts +6 -0
  25. package/dist/cli/dev/logs.js +72 -0
  26. package/dist/cli/dev/status.d.ts +15 -0
  27. package/dist/cli/dev/status.js +27 -0
  28. package/dist/cli/dev/stop.d.ts +12 -0
  29. package/dist/cli/dev/stop.js +43 -0
  30. package/dist/cli/infra/build-time-astro-version-provider.js +1 -1
  31. package/dist/content/content-layer.js +16 -10
  32. package/dist/content/data-store.d.ts +1 -1
  33. package/dist/content/runtime-assets.d.ts +2 -2
  34. package/dist/content/runtime.d.ts +1 -1
  35. package/dist/content/runtime.js +9 -4
  36. package/dist/content/types-generator.js +5 -1
  37. package/dist/content/utils.d.ts +1 -1
  38. package/dist/content/utils.js +1 -1
  39. package/dist/core/app/base.d.ts +9 -0
  40. package/dist/core/app/base.js +47 -67
  41. package/dist/core/app/entrypoints/node.d.ts +1 -1
  42. package/dist/core/app/entrypoints/node.js +2 -0
  43. package/dist/core/app/node.d.ts +16 -0
  44. package/dist/core/app/node.js +59 -13
  45. package/dist/core/base-pipeline.d.ts +10 -0
  46. package/dist/core/base-pipeline.js +13 -1
  47. package/dist/core/build/generate.js +8 -1
  48. package/dist/core/build/index.d.ts +0 -11
  49. package/dist/core/build/index.js +0 -3
  50. package/dist/core/build/internal.d.ts +7 -0
  51. package/dist/core/build/plugins/plugin-chunk-imports.d.ts +6 -0
  52. package/dist/core/build/plugins/plugin-chunk-imports.js +29 -17
  53. package/dist/core/build/plugins/plugin-css.js +33 -0
  54. package/dist/core/build/plugins/plugin-internals.js +1 -1
  55. package/dist/core/build/static-build.js +22 -155
  56. package/dist/core/build/types.d.ts +0 -1
  57. package/dist/core/build/util.js +8 -1
  58. package/dist/core/build/vite-build-config.d.ts +28 -0
  59. package/dist/core/build/vite-build-config.js +165 -0
  60. package/dist/core/config/merge.js +4 -0
  61. package/dist/core/config/schemas/base.d.ts +19 -11
  62. package/dist/core/config/schemas/base.js +29 -4
  63. package/dist/core/config/schemas/relative.d.ts +69 -45
  64. package/dist/core/config/validate.js +59 -0
  65. package/dist/core/constants.js +1 -1
  66. package/dist/core/create-vite.js +3 -1
  67. package/dist/core/csp/config.js +17 -5
  68. package/dist/core/dev/dev.d.ts +1 -0
  69. package/dist/core/dev/dev.js +4 -1
  70. package/dist/core/dev/lockfile.d.ts +54 -0
  71. package/dist/core/dev/lockfile.js +93 -0
  72. package/dist/core/errors/errors-data.d.ts +43 -38
  73. package/dist/core/errors/errors-data.js +79 -73
  74. package/dist/core/errors/zod-error-map.js +3 -1
  75. package/dist/core/fetch/fetch-state.d.ts +12 -26
  76. package/dist/core/fetch/fetch-state.js +137 -20
  77. package/dist/core/fetch/types.d.ts +19 -0
  78. package/dist/core/fetch/vite-plugin.js +11 -4
  79. package/dist/core/hono/index.d.ts +1 -1
  80. package/dist/core/hono/index.js +6 -3
  81. package/dist/core/i18n/domain.d.ts +12 -0
  82. package/dist/core/i18n/domain.js +66 -0
  83. package/dist/core/i18n/handler.js +3 -0
  84. package/dist/core/logger/core.d.ts +1 -1
  85. package/dist/core/logger/core.js +1 -1
  86. package/dist/core/messages/runtime.js +1 -1
  87. package/dist/core/middleware/astro-middleware.js +3 -5
  88. package/dist/core/module-loader/vite.js +1 -2
  89. package/dist/core/pages/handler.js +1 -0
  90. package/dist/core/preview/index.js +6 -5
  91. package/dist/core/preview/static-preview-server.js +5 -2
  92. package/dist/core/render/params-and-props.js +1 -1
  93. package/dist/core/render/route-cache.d.ts +1 -0
  94. package/dist/core/render/route-cache.js +4 -4
  95. package/dist/core/routing/create-manifest.js +11 -1
  96. package/dist/core/routing/handler.js +5 -6
  97. package/dist/core/routing/parse-route.js +1 -1
  98. package/dist/core/routing/rewrite.js +1 -1
  99. package/dist/core/routing/router.d.ts +8 -0
  100. package/dist/core/routing/router.js +28 -0
  101. package/dist/core/routing/validation.js +1 -1
  102. package/dist/core/server-islands/vite-plugin-server-islands.d.ts +6 -1
  103. package/dist/core/server-islands/vite-plugin-server-islands.js +13 -3
  104. package/dist/core/session/config.d.ts +1 -1
  105. package/dist/core/util/normalized-url.js +5 -2
  106. package/dist/core/util/pathname.d.ts +10 -1
  107. package/dist/core/util/pathname.js +13 -4
  108. package/dist/environments.js +1 -1
  109. package/dist/events/session.d.ts +8 -0
  110. package/dist/events/session.js +11 -0
  111. package/dist/jsx/rehype.d.ts +1 -1
  112. package/dist/manifest/virtual-module.js +3 -1
  113. package/dist/markdown/index.d.ts +4 -0
  114. package/dist/markdown/index.js +14 -0
  115. package/dist/prerender/utils.js +5 -1
  116. package/dist/runtime/client/dev-toolbar/apps/audit/rules/a11y.js +9 -0
  117. package/dist/runtime/server/jsx.js +1 -1
  118. package/dist/runtime/server/render/component.js +8 -6
  119. package/dist/runtime/server/render/head.js +1 -5
  120. package/dist/runtime/server/render/util.js +2 -2
  121. package/dist/runtime/server/transition.d.ts +1 -6
  122. package/dist/runtime/server/transition.js +0 -8
  123. package/dist/transitions/events.d.ts +0 -14
  124. package/dist/transitions/events.js +0 -14
  125. package/dist/transitions/index.d.ts +0 -1
  126. package/dist/transitions/index.js +0 -2
  127. package/dist/transitions/vite-plugin-transitions.js +2 -4
  128. package/dist/types/public/config.d.ts +66 -18
  129. package/dist/types/public/content.d.ts +1 -1
  130. package/dist/types/public/index.d.ts +2 -1
  131. package/dist/types/public/integrations.d.ts +11 -3
  132. package/dist/types/public/manifest.d.ts +1 -1
  133. package/dist/virtual-modules/i18n.d.ts +2 -2
  134. package/dist/virtual-modules/i18n.js +1 -1
  135. package/dist/vite-plugin-app/app.d.ts +9 -1
  136. package/dist/vite-plugin-app/app.js +31 -21
  137. package/dist/vite-plugin-app/createAstroServerApp.d.ts +3 -1
  138. package/dist/vite-plugin-app/createAstroServerApp.js +4 -3
  139. package/dist/vite-plugin-astro-server/plugin.js +11 -5
  140. package/dist/vite-plugin-astro-server/route-guard.d.ts +33 -0
  141. package/dist/vite-plugin-astro-server/route-guard.js +42 -23
  142. package/dist/vite-plugin-dev-status/index.d.ts +2 -0
  143. package/dist/vite-plugin-dev-status/index.js +15 -0
  144. package/dist/vite-plugin-hmr-reload/index.d.ts +1 -1
  145. package/dist/vite-plugin-hmr-reload/index.js +23 -1
  146. package/dist/vite-plugin-integrations-container/index.js +15 -6
  147. package/dist/vite-plugin-markdown/content-entry-type.js +7 -4
  148. package/dist/vite-plugin-markdown/images.js +9 -11
  149. package/dist/vite-plugin-markdown/index.js +12 -11
  150. package/dist/vite-plugin-utils/index.js +7 -1
  151. package/package.json +13 -13
  152. package/templates/content/types.d.ts +1 -0
  153. package/types/transitions.d.ts +0 -7
@@ -10,7 +10,7 @@ async function imageMetadata(data, src) {
10
10
  message: AstroErrorData.NoImageMetadata.message(src)
11
11
  });
12
12
  }
13
- if (!result.height || !result.width || !result.type) {
13
+ if (result.height == null || result.width == null || !result.type) {
14
14
  throw new AstroError({
15
15
  ...AstroErrorData.NoImageMetadata,
16
16
  message: AstroErrorData.NoImageMetadata.message(src)
@@ -77,7 +77,7 @@ const SVG = {
77
77
  const root = extractorRegExps.root.exec(toUTF8String(input));
78
78
  if (root) {
79
79
  const attrs = parseAttributes(root[0]);
80
- if (attrs.width && attrs.height) {
80
+ if (attrs.width != null && attrs.height != null) {
81
81
  return calculateByDimensions(attrs);
82
82
  }
83
83
  if (attrs.viewbox) {
@@ -0,0 +1,16 @@
1
+ import type { AstroLogger } from '../../core/logger/core.js';
2
+ import type { Flags } from '../flags.js';
3
+ export interface BackgroundResult {
4
+ pid: number;
5
+ url: string;
6
+ existing?: boolean;
7
+ }
8
+ export interface BackgroundErrorResult {
9
+ error: string;
10
+ message: string;
11
+ }
12
+ export declare function formatBackgroundOutput(result: BackgroundResult | BackgroundErrorResult): string;
13
+ export declare function background({ flags, logger, }: {
14
+ flags: Flags;
15
+ logger: AstroLogger;
16
+ }): Promise<void>;
@@ -0,0 +1,116 @@
1
+ import { spawn } from "node:child_process";
2
+ import { existsSync, mkdirSync, openSync } from "node:fs";
3
+ import { resolve } from "node:path";
4
+ import { fileURLToPath, pathToFileURL } from "node:url";
5
+ import {
6
+ checkExistingServer,
7
+ getLogFileURL,
8
+ readLockFile,
9
+ removeLockFile,
10
+ isProcessAlive,
11
+ GRACEFUL_SHUTDOWN_TIMEOUT
12
+ } from "../../core/dev/lockfile.js";
13
+ import { resolveRoot } from "../../core/config/config.js";
14
+ function formatBackgroundOutput(result) {
15
+ return JSON.stringify(result);
16
+ }
17
+ async function background({
18
+ flags,
19
+ logger
20
+ }) {
21
+ const root = pathToFileURL(resolveRoot(flags.root) + "/");
22
+ const existing = checkExistingServer(root);
23
+ if (existing && !flags.force) {
24
+ logger.info(
25
+ "SKIP_FORMAT",
26
+ `Dev server already running at ${existing.url} (pid ${existing.pid})
27
+ Stop: astro dev stop
28
+ Status: astro dev status
29
+ Logs: astro dev logs`
30
+ );
31
+ return;
32
+ }
33
+ if (existing && flags.force) {
34
+ try {
35
+ process.kill(existing.pid, "SIGTERM");
36
+ } catch {
37
+ }
38
+ const deadline2 = Date.now() + GRACEFUL_SHUTDOWN_TIMEOUT;
39
+ while (Date.now() < deadline2) {
40
+ if (!isProcessAlive(existing.pid)) break;
41
+ await new Promise((r) => setTimeout(r, 100));
42
+ }
43
+ if (isProcessAlive(existing.pid)) {
44
+ try {
45
+ process.kill(existing.pid, "SIGKILL");
46
+ } catch {
47
+ }
48
+ }
49
+ removeLockFile(root);
50
+ }
51
+ const args = ["dev"];
52
+ if (flags.port) args.push("--port", String(flags.port));
53
+ if (flags.host != null) {
54
+ if (typeof flags.host === "string") {
55
+ args.push("--host", flags.host);
56
+ } else {
57
+ args.push("--host");
58
+ }
59
+ }
60
+ if (flags.config) args.push("--config", String(flags.config));
61
+ if (flags.root) args.push("--root", String(flags.root));
62
+ if (flags.allowedHosts) args.push("--allowed-hosts", String(flags.allowedHosts));
63
+ if (flags.experimentalJson) args.push("--experimental-json");
64
+ const logFileURL = getLogFileURL(root);
65
+ const logFilePath = fileURLToPath(logFileURL);
66
+ const dotAstroDir = fileURLToPath(new URL(".astro/", root));
67
+ if (!existsSync(dotAstroDir)) {
68
+ mkdirSync(dotAstroDir, { recursive: true });
69
+ }
70
+ const logFd = openSync(logFilePath, "w");
71
+ const rootPath = fileURLToPath(root);
72
+ const astroBin = resolve(rootPath, "node_modules", ".bin", "astro");
73
+ const child = spawn(astroBin, args, {
74
+ detached: true,
75
+ stdio: ["ignore", logFd, logFd],
76
+ cwd: rootPath,
77
+ env: { ...process.env, ASTRO_DEV_BACKGROUND: "1" }
78
+ });
79
+ child.unref();
80
+ const childPid = child.pid;
81
+ if (!childPid) {
82
+ logger.error("SKIP_FORMAT", "Failed to spawn background dev server process.");
83
+ process.exit(1);
84
+ }
85
+ const timeout = 3e4;
86
+ const deadline = Date.now() + timeout;
87
+ while (Date.now() < deadline) {
88
+ if (!isProcessAlive(childPid)) {
89
+ logger.error("SKIP_FORMAT", "Dev server process exited before becoming ready.");
90
+ process.exit(1);
91
+ }
92
+ const lockData = readLockFile(root);
93
+ if (lockData && lockData.pid === childPid) {
94
+ logger.info(
95
+ "SKIP_FORMAT",
96
+ `Dev server running at ${lockData.url} (pid ${lockData.pid})
97
+ Stop: astro dev stop
98
+ Status: astro dev status
99
+ Logs: astro dev logs`
100
+ );
101
+ return;
102
+ }
103
+ await new Promise((r) => setTimeout(r, 200));
104
+ }
105
+ try {
106
+ process.kill(childPid, "SIGTERM");
107
+ } catch {
108
+ }
109
+ removeLockFile(root);
110
+ logger.error("SKIP_FORMAT", `Dev server failed to start within ${timeout / 1e3}s.`);
111
+ process.exit(1);
112
+ }
113
+ export {
114
+ background,
115
+ formatBackgroundOutput
116
+ };
@@ -1,14 +1,31 @@
1
+ import { isAgent } from "am-i-vibing";
1
2
  import colors from "piccolore";
2
3
  import devServer from "../../core/dev/index.js";
4
+ import { pathToFileURL } from "node:url";
5
+ import { checkExistingServer, removeLockFile, writeLockFile } from "../../core/dev/lockfile.js";
6
+ import { resolveRoot } from "../../core/config/config.js";
3
7
  import { printHelp } from "../../core/messages/runtime.js";
4
- import { flagsToAstroInlineConfig } from "../flags.js";
8
+ import { createLoggerFromFlags, flagsToAstroInlineConfig } from "../flags.js";
9
+ function isRunByAgent() {
10
+ try {
11
+ return isAgent();
12
+ } catch {
13
+ return false;
14
+ }
15
+ }
5
16
  async function dev({ flags }) {
6
17
  if (flags.help || flags.h) {
7
18
  printHelp({
8
19
  commandName: "astro dev",
9
- usage: "[...flags]",
20
+ usage: "[command] [...flags]",
10
21
  tables: {
22
+ Commands: [
23
+ ["stop", "Stop a running background dev server."],
24
+ ["status", "Check if a dev server is running."],
25
+ ["logs [--follow]", "View logs from a background dev server."]
26
+ ],
11
27
  Flags: [
28
+ ["--background", "Start the dev server as a background process."],
12
29
  ["--mode", `Specify the mode of the project. Defaults to "development".`],
13
30
  ["--port", `Specify which port to run on. Defaults to 4321.`],
14
31
  ["--host", `Listen on all addresses, including LAN and public addresses.`],
@@ -28,8 +45,70 @@ async function dev({ flags }) {
28
45
  });
29
46
  return;
30
47
  }
48
+ const agentDetected = !process.env.ASTRO_DEV_BACKGROUND && isRunByAgent();
49
+ if (agentDetected) {
50
+ flags.experimentalJson = true;
51
+ }
52
+ const logger = createLoggerFromFlags(flags);
53
+ const subcommand = flags._[3]?.toString();
54
+ if (subcommand === "stop") {
55
+ const { stop } = await import("./stop.js");
56
+ await stop({ flags, logger });
57
+ return;
58
+ }
59
+ if (subcommand === "status") {
60
+ const { status } = await import("./status.js");
61
+ await status({ flags, logger });
62
+ return;
63
+ }
64
+ if (subcommand === "logs") {
65
+ const { logs } = await import("./logs.js");
66
+ await logs({ flags, logger });
67
+ return;
68
+ }
69
+ if (flags.background || agentDetected) {
70
+ const { background } = await import("./background.js");
71
+ await background({ flags, logger });
72
+ return;
73
+ }
74
+ if (subcommand) {
75
+ logger.error(
76
+ "SKIP_FORMAT",
77
+ `Unknown command: astro dev ${subcommand}
78
+
79
+ Run \`astro dev --help\` to see available commands.`
80
+ );
81
+ process.exit(1);
82
+ }
83
+ const root = pathToFileURL(resolveRoot(flags.root) + "/");
84
+ const existingServer = checkExistingServer(root);
85
+ if (existingServer) {
86
+ const message = [
87
+ "Another astro dev server is already running.",
88
+ "",
89
+ ` URL: ${existingServer.url}`,
90
+ ` PID: ${existingServer.pid}`,
91
+ "",
92
+ `Run \`astro dev stop\` to stop it, or use \`astro dev --force\` to replace it.`
93
+ ].join("\n");
94
+ throw new Error(message);
95
+ }
31
96
  const inlineConfig = flagsToAstroInlineConfig(flags);
32
- return await devServer(inlineConfig);
97
+ const server = await devServer(inlineConfig);
98
+ const serverUrl = new URL(server.resolvedUrls.local[0]).origin;
99
+ writeLockFile(root, {
100
+ pid: process.pid,
101
+ port: server.address.port,
102
+ url: serverUrl,
103
+ background: !!process.env.ASTRO_DEV_BACKGROUND,
104
+ startedAt: (/* @__PURE__ */ new Date()).toISOString()
105
+ });
106
+ const originalStop = server.stop.bind(server);
107
+ server.stop = async () => {
108
+ removeLockFile(root);
109
+ await originalStop();
110
+ };
111
+ return server;
33
112
  }
34
113
  export {
35
114
  dev
@@ -0,0 +1,6 @@
1
+ import type { AstroLogger } from '../../core/logger/core.js';
2
+ import type { Flags } from '../flags.js';
3
+ export declare function logs({ flags, logger, }: {
4
+ flags: Flags;
5
+ logger: AstroLogger;
6
+ }): Promise<void>;
@@ -0,0 +1,72 @@
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";
5
+ async function logs({
6
+ flags,
7
+ logger
8
+ }) {
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
+ });
69
+ }
70
+ export {
71
+ logs
72
+ };
@@ -0,0 +1,15 @@
1
+ import type { AstroLogger } from '../../core/logger/core.js';
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;
12
+ export declare function status({ flags, logger, }: {
13
+ flags: Flags;
14
+ logger: AstroLogger;
15
+ }): Promise<void>;
@@ -0,0 +1,27 @@
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
+ }
7
+ async function status({
8
+ flags,
9
+ logger
10
+ }) {
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
+ logger.info(
20
+ "SKIP_FORMAT",
21
+ `Dev server running at ${existing.url} (pid ${existing.pid}, uptime ${uptime}s${existing.background ? ", background" : ""})`
22
+ );
23
+ }
24
+ export {
25
+ formatStatusOutput,
26
+ status
27
+ };
@@ -0,0 +1,12 @@
1
+ import type { AstroLogger } from '../../core/logger/core.js';
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;
9
+ export declare function stop({ flags, logger, }: {
10
+ flags: Flags;
11
+ logger: AstroLogger;
12
+ }): Promise<void>;
@@ -0,0 +1,43 @@
1
+ import { pathToFileURL } from "node:url";
2
+ import {
3
+ checkExistingServer,
4
+ removeLockFile,
5
+ isProcessAlive,
6
+ GRACEFUL_SHUTDOWN_TIMEOUT
7
+ } from "../../core/dev/lockfile.js";
8
+ import { resolveRoot } from "../../core/config/config.js";
9
+ function formatStopOutput(result) {
10
+ return JSON.stringify(result);
11
+ }
12
+ async function stop({
13
+ flags,
14
+ logger
15
+ }) {
16
+ const root = pathToFileURL(resolveRoot(flags.root) + "/");
17
+ const existing = checkExistingServer(root);
18
+ if (!existing) {
19
+ logger.info("SKIP_FORMAT", "No dev server is running.");
20
+ return;
21
+ }
22
+ try {
23
+ process.kill(existing.pid, "SIGTERM");
24
+ } catch {
25
+ }
26
+ const deadline = Date.now() + GRACEFUL_SHUTDOWN_TIMEOUT;
27
+ while (Date.now() < deadline) {
28
+ if (!isProcessAlive(existing.pid)) break;
29
+ await new Promise((r) => setTimeout(r, 100));
30
+ }
31
+ if (isProcessAlive(existing.pid)) {
32
+ try {
33
+ process.kill(existing.pid, "SIGKILL");
34
+ } catch {
35
+ }
36
+ }
37
+ removeLockFile(root);
38
+ logger.info("SKIP_FORMAT", `Stopped dev server (pid ${existing.pid}).`);
39
+ }
40
+ export {
41
+ formatStopOutput,
42
+ stop
43
+ };
@@ -1,6 +1,6 @@
1
1
  class BuildTimeAstroVersionProvider {
2
2
  // Injected during the build through esbuild define
3
- version = "7.0.0-alpha.1";
3
+ version = "7.0.0-alpha.2";
4
4
  }
5
5
  export {
6
6
  BuildTimeAstroVersionProvider
@@ -1,8 +1,5 @@
1
1
  import { existsSync, promises as fs } from "node:fs";
2
- import {
3
- createMarkdownProcessor,
4
- parseFrontmatter
5
- } from "@astrojs/markdown-remark";
2
+ import { parseFrontmatter } from "@astrojs/internal-helpers/frontmatter";
6
3
  import PQueue from "p-queue";
7
4
  import xxhash from "xxhash-wasm";
8
5
  import { AstroError, AstroErrorData } from "../core/errors/index.js";
@@ -28,7 +25,7 @@ class ContentLayer {
28
25
  #watcher;
29
26
  #lastConfigDigest;
30
27
  #unsubscribe;
31
- #markdownProcessor;
28
+ #markdownRenderer;
32
29
  #generateDigest;
33
30
  #contentConfigObserver;
34
31
  #queue;
@@ -108,9 +105,18 @@ class ContentLayer {
108
105
  };
109
106
  }
110
107
  async #processMarkdown(content, options) {
111
- this.#markdownProcessor ??= await createMarkdownProcessor(this.#settings.config.markdown);
108
+ if (!this.#markdownRenderer) {
109
+ const { markdown, image } = this.#settings.config;
110
+ this.#markdownRenderer = await markdown.processor.createRenderer({
111
+ image,
112
+ syntaxHighlight: markdown.syntaxHighlight,
113
+ shikiConfig: markdown.shikiConfig,
114
+ gfm: markdown.gfm,
115
+ smartypants: markdown.smartypants
116
+ });
117
+ }
112
118
  const { frontmatter, content: body } = parseFrontmatter(content);
113
- const { code, metadata } = await this.#markdownProcessor.render(body, {
119
+ const { code, metadata } = await this.#markdownRenderer.render(body, {
114
120
  frontmatter,
115
121
  fileURL: options?.fileURL
116
122
  });
@@ -191,7 +197,7 @@ ${contentConfig.error.message}`
191
197
  logger.info("Content config changed");
192
198
  shouldClear = true;
193
199
  }
194
- if (previousAstroVersion && previousAstroVersion !== "7.0.0-alpha.1") {
200
+ if (previousAstroVersion && previousAstroVersion !== "7.0.0-alpha.2") {
195
201
  logger.info("Astro version changed");
196
202
  shouldClear = true;
197
203
  }
@@ -199,8 +205,8 @@ ${contentConfig.error.message}`
199
205
  logger.info("Clearing content store");
200
206
  this.#store.clearAll();
201
207
  }
202
- if ("7.0.0-alpha.1") {
203
- this.#store.metaStore().set("astro-version", "7.0.0-alpha.1");
208
+ if ("7.0.0-alpha.2") {
209
+ this.#store.metaStore().set("astro-version", "7.0.0-alpha.2");
204
210
  }
205
211
  if (currentConfigDigest) {
206
212
  this.#store.metaStore().set("content-config-digest", currentConfigDigest);
@@ -1,4 +1,4 @@
1
- import type { MarkdownHeading } from '@astrojs/markdown-remark';
1
+ import type { MarkdownHeading } from '@astrojs/internal-helpers/markdown';
2
2
  export interface RenderedContent {
3
3
  /** Rendered HTML string. If present then `render(entry)` will return a component that renders this HTML. */
4
4
  html: string;
@@ -2,10 +2,10 @@ import type { Rolldown } from 'vite';
2
2
  import * as z from 'zod/v4';
3
3
  export declare function createImage(pluginContext: Rolldown.PluginContext, shouldEmitFile: boolean, entryFilePath: string): () => z.ZodPipe<z.ZodString, z.ZodTransform<z.ZodNever | {
4
4
  ASTRO_ASSET: string;
5
- format: import("../assets/types.js").ImageInputFormat;
6
- src: string;
7
5
  width: number;
8
6
  height: number;
7
+ format: import("../assets/types.js").ImageInputFormat;
8
+ src: string;
9
9
  fsPath: string;
10
10
  orientation?: number | undefined;
11
11
  }, string>>;
@@ -1,4 +1,4 @@
1
- import type { MarkdownHeading } from '@astrojs/markdown-remark';
1
+ import type { MarkdownHeading } from '@astrojs/internal-helpers/markdown';
2
2
  import * as z from 'zod/v4';
3
3
  import type * as zCore from 'zod/v4/core';
4
4
  import type { ImageMetadata } from '../assets/types.js';
@@ -134,9 +134,10 @@ function createGetEntry({ liveCollections }) {
134
134
  return;
135
135
  }
136
136
  const { default: imageAssetMap } = await import("astro:asset-imports");
137
- entry.data = updateImageReferencesInData(entry.data, entry.filePath, imageAssetMap);
137
+ const data = updateImageReferencesInData(entry.data, entry.filePath, imageAssetMap);
138
138
  const result = {
139
139
  ...entry,
140
+ data,
140
141
  collection
141
142
  };
142
143
  warnForPropertyAccess(
@@ -321,7 +322,9 @@ async function updateImageReferencesInBody(html, fileName) {
321
322
  const { getImage } = await import("virtual:astro:get-image");
322
323
  for (const [_full, imagePath] of html.matchAll(CONTENT_LAYER_IMAGE_REGEX)) {
323
324
  try {
324
- const decodedImagePath = JSON.parse(imagePath.replaceAll("&#x22;", '"'));
325
+ const decodedImagePath = JSON.parse(
326
+ imagePath.replace(/&(?:#x22|quot);/g, '"').replace(/&(?:#x27|apos);/g, "'")
327
+ );
325
328
  let image;
326
329
  if (URL.canParse(decodedImagePath.src)) {
327
330
  image = await getImage(decodedImagePath);
@@ -350,11 +353,12 @@ async function updateImageReferencesInBody(html, fileName) {
350
353
  srcset: image.srcSet.attribute,
351
354
  // This attribute is used by the toolbar audit
352
355
  ...import.meta.env.DEV ? { "data-image-component": "true" } : {}
353
- }).map(([key, value]) => value ? `${key}="${escape(value)}"` : "").join(" ");
356
+ }).filter(([, value]) => value != null).map(([key, value]) => value === "" ? `${key}=""` : `${key}="${escape(String(value))}"`).join(" ");
354
357
  });
355
358
  }
356
359
  function updateImageReferencesInData(data, fileName, imageAssetMap) {
357
- return new Traverse(data).map(function(ctx, val) {
360
+ const copy = structuredClone(data);
361
+ new Traverse(copy).forEach(function(ctx, val) {
358
362
  if (typeof val === "string" && val.startsWith(IMAGE_IMPORT_PREFIX)) {
359
363
  const src = val.replace(IMAGE_IMPORT_PREFIX, "");
360
364
  const id = imageSrcToImportId(src, fileName);
@@ -375,6 +379,7 @@ function updateImageReferencesInData(data, fileName, imageAssetMap) {
375
379
  }
376
380
  }
377
381
  });
382
+ return copy;
378
383
  }
379
384
  async function renderEntry(entry) {
380
385
  if (!entry) {
@@ -447,7 +447,11 @@ async function generateJSONSchema(fsMod, collectionConfig, collectionKey, collec
447
447
  zodSchemaForJson = await getContentLayerSchema(collectionConfig, collectionKey);
448
448
  }
449
449
  if (collectionConfig.type === CONTENT_LAYER_TYPE && collectionConfig.loader.name === "file-loader") {
450
- zodSchemaForJson = z.object({}).catchall(zodSchemaForJson);
450
+ const itemSchema = zodSchemaForJson;
451
+ zodSchemaForJson = z.union([
452
+ z.array(itemSchema),
453
+ z.object({ $schema: z.string().optional() }).catchall(itemSchema)
454
+ ]);
451
455
  }
452
456
  if (zodSchemaForJson instanceof z.ZodObject) {
453
457
  const existingMeta = z.globalRegistry.get(zodSchemaForJson);
@@ -124,7 +124,7 @@ export declare function getContentEntryIdAndSlug({ entry, contentDir, collection
124
124
  slug: string;
125
125
  };
126
126
  export declare function getEntryType(entryPath: string, paths: Pick<ContentPaths, 'config' | 'contentDir' | 'root'>, contentFileExts: string[], dataFileExts: string[]): 'content' | 'data' | 'config' | 'ignored';
127
- export declare function safeParseFrontmatter(source: string, id?: string): import("@astrojs/markdown-remark").ParseFrontmatterResult;
127
+ export declare function safeParseFrontmatter(source: string, id?: string): import("@astrojs/internal-helpers/frontmatter").ParseFrontmatterResult;
128
128
  /**
129
129
  * The content config is loaded separately from other `src/` files.
130
130
  * This global observable lets dependent plugins (like the content flag plugin)
@@ -1,7 +1,7 @@
1
1
  import fsMod from "node:fs";
2
2
  import path from "node:path";
3
3
  import { fileURLToPath, pathToFileURL } from "node:url";
4
- import { parseFrontmatter } from "@astrojs/markdown-remark";
4
+ import { parseFrontmatter } from "@astrojs/internal-helpers/frontmatter";
5
5
  import { slug as githubSlug } from "github-slugger";
6
6
  import colors from "piccolore";
7
7
  import xxhash from "xxhash-wasm";
@@ -131,6 +131,15 @@ export declare abstract class BaseApp<P extends Pipeline = AppPipeline> {
131
131
  abstract createPipeline(streaming: boolean, manifest: SSRManifest, ...args: any[]): P;
132
132
  set setManifestData(newManifestData: RoutesList);
133
133
  removeBase(pathname: string): string;
134
+ /**
135
+ * Decodes a pathname with `decodeURI`, falling back to the raw pathname when it
136
+ * contains an invalid percent-sequence (e.g. `%C0%AF`, an overlong-UTF-8 encoding of
137
+ * `/` commonly sent by path-traversal scanners). A raw `decodeURI()` would throw
138
+ * `URIError: URI malformed`, and because `match()` runs before `render()` that error
139
+ * escapes the adapter's request handler as an uncaught exception (HTTP 500) that user
140
+ * middleware can't catch.
141
+ */
142
+ private safeDecodeURI;
134
143
  /**
135
144
  * Extracts the base-stripped, decoded pathname from a request.
136
145
  * Used by adapters to compute the pathname for dev-mode route matching.