astro 6.0.8 → 6.1.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 (87) hide show
  1. package/client.d.ts +30 -40
  2. package/dist/assets/build/generate.js +17 -19
  3. package/dist/assets/build/remote.d.ts +4 -4
  4. package/dist/assets/build/remote.js +12 -10
  5. package/dist/assets/fonts/infra/dev-font-file-id-generator.js +4 -1
  6. package/dist/assets/fonts/vite-plugin-fonts.js +8 -0
  7. package/dist/assets/services/sharp.d.ts +21 -2
  8. package/dist/assets/services/sharp.js +54 -12
  9. package/dist/assets/vite-plugin-assets.js +4 -1
  10. package/dist/cli/add/index.js +54 -0
  11. package/dist/cli/infra/build-time-astro-version-provider.js +1 -1
  12. package/dist/content/content-layer.js +3 -3
  13. package/dist/content/index.d.ts +1 -1
  14. package/dist/content/index.js +2 -3
  15. package/dist/content/runtime.d.ts +2 -0
  16. package/dist/content/runtime.js +2 -1
  17. package/dist/content/types-generator.js +4 -0
  18. package/dist/content/utils.d.ts +0 -1
  19. package/dist/content/utils.js +1 -10
  20. package/dist/core/app/dev/app.d.ts +5 -0
  21. package/dist/core/app/dev/app.js +7 -0
  22. package/dist/core/app/entrypoints/virtual/dev.js +4 -0
  23. package/dist/core/app/node.js +5 -4
  24. package/dist/core/app/validate-headers.d.ts +6 -0
  25. package/dist/core/app/validate-headers.js +4 -0
  26. package/dist/core/base-pipeline.d.ts +5 -0
  27. package/dist/core/base-pipeline.js +7 -0
  28. package/dist/core/build/generate.d.ts +47 -0
  29. package/dist/core/build/generate.js +43 -25
  30. package/dist/core/build/plugins/plugin-css.js +8 -4
  31. package/dist/core/config/schemas/base.d.ts +4 -2
  32. package/dist/core/config/schemas/base.js +22 -1
  33. package/dist/core/config/schemas/relative.d.ts +3 -3
  34. package/dist/core/constants.js +1 -1
  35. package/dist/core/create-vite.js +1 -1
  36. package/dist/core/dev/dev.js +13 -1
  37. package/dist/core/head-propagation/boundary.d.ts +8 -0
  38. package/dist/core/head-propagation/boundary.js +11 -0
  39. package/dist/core/head-propagation/buffer.d.ts +21 -0
  40. package/dist/core/head-propagation/buffer.js +18 -0
  41. package/dist/core/head-propagation/comment.d.ts +7 -0
  42. package/dist/core/head-propagation/comment.js +7 -0
  43. package/dist/core/head-propagation/graph.d.ts +18 -0
  44. package/dist/core/head-propagation/graph.js +32 -0
  45. package/dist/core/head-propagation/policy.d.ts +22 -0
  46. package/dist/core/head-propagation/policy.js +14 -0
  47. package/dist/core/head-propagation/resolver.d.ts +28 -0
  48. package/dist/core/head-propagation/resolver.js +25 -0
  49. package/dist/core/messages/runtime.d.ts +3 -0
  50. package/dist/core/messages/runtime.js +9 -1
  51. package/dist/core/middleware/vite-plugin.d.ts +1 -1
  52. package/dist/core/middleware/vite-plugin.js +25 -0
  53. package/dist/core/redirects/render.d.ts +17 -0
  54. package/dist/core/redirects/render.js +33 -24
  55. package/dist/core/routing/create-manifest.d.ts +15 -0
  56. package/dist/core/routing/create-manifest.js +131 -130
  57. package/dist/core/routing/prerender.d.ts +5 -0
  58. package/dist/core/routing/prerender.js +7 -1
  59. package/dist/core/server-islands/vite-plugin-server-islands.js +18 -6
  60. package/dist/integrations/hooks.js +4 -1
  61. package/dist/jsx/rehype.js +1 -1
  62. package/dist/manifest/serialized.js +5 -0
  63. package/dist/manifest/virtual-module.d.ts +4 -1
  64. package/dist/manifest/virtual-module.js +37 -35
  65. package/dist/runtime/client/dev-toolbar/apps/audit/rules/a11y.js +3 -3
  66. package/dist/runtime/server/render/astro/factory.js +6 -7
  67. package/dist/runtime/server/render/astro/instance.js +2 -4
  68. package/dist/runtime/server/render/astro/render.js +2 -11
  69. package/dist/runtime/server/render/common.js +3 -2
  70. package/dist/runtime/server/render/head-propagation/runtime.d.ts +20 -0
  71. package/dist/runtime/server/render/head-propagation/runtime.js +53 -0
  72. package/dist/runtime/server/render/page.js +5 -1
  73. package/dist/runtime/server/transition.d.ts +19 -1
  74. package/dist/runtime/server/transition.js +6 -1
  75. package/dist/transitions/events.d.ts +1 -1
  76. package/dist/transitions/events.js +5 -5
  77. package/dist/transitions/router.js +23 -19
  78. package/dist/types/public/config.d.ts +70 -11
  79. package/dist/types/public/integrations.d.ts +9 -2
  80. package/dist/vite-plugin-app/app.d.ts +5 -0
  81. package/dist/vite-plugin-app/app.js +17 -1
  82. package/dist/vite-plugin-app/createAstroServerApp.js +4 -0
  83. package/dist/vite-plugin-astro-server/plugin.js +2 -1
  84. package/dist/vite-plugin-astro-server/vite.js +2 -2
  85. package/dist/vite-plugin-head/index.js +63 -25
  86. package/dist/vite-plugin-scripts/index.js +5 -0
  87. package/package.json +11 -11
@@ -204,8 +204,11 @@ export interface AstroPrerenderer {
204
204
  getStaticPaths: () => Promise<PathWithRoute[]>;
205
205
  /**
206
206
  * Renders a single page. Called by Astro for each path returned by getStaticPaths.
207
- * @param request - The request to render
208
- * @param options - Render options including routeData
207
+ * @param request - The request to render. The URL reflects the build format
208
+ * (e.g. trailing slash for `directory` format). To get the canonical pathname,
209
+ * use the `pathname` from the `PathWithRoute` entry returned by `getStaticPaths`.
210
+ * @param options - Render options
211
+ * @param options.routeData - The matched route for this path
209
212
  */
210
213
  render: (request: Request, options: {
211
214
  routeData: RouteData;
@@ -379,6 +382,10 @@ export interface IntegrationResolvedRoute extends Pick<RouteData, 'params' | 'pa
379
382
  * {@link RouteData.redirectRoute}
380
383
  */
381
384
  redirectRoute?: IntegrationResolvedRoute;
385
+ /**
386
+ * {@link RouteData.fallbackRoutes}
387
+ */
388
+ fallbackRoutes: IntegrationResolvedRoute[];
382
389
  /**
383
390
  * @param {any} data The optional parameters of the route
384
391
  *
@@ -26,6 +26,11 @@ export declare class AstroServerApp extends BaseApp<RunnablePipeline> {
26
26
  * Called via HMR when content collection data changes.
27
27
  */
28
28
  clearRouteCache(): void;
29
+ /**
30
+ * Clears the cached middleware so it is re-resolved on the next request.
31
+ * Called via HMR when middleware files change.
32
+ */
33
+ clearMiddleware(): void;
29
34
  devMatch(pathname: string): Promise<DevMatch | undefined>;
30
35
  static create(manifest: SSRManifest, routesList: RoutesList, logger: Logger, loader: ModuleLoader, settings: AstroSettings, getDebugInfo: () => Promise<string>): Promise<AstroServerApp>;
31
36
  createPipeline(_streaming: boolean, manifest: SSRManifest, settings: AstroSettings, logger: Logger, loader: ModuleLoader, manifestData: RoutesList, getDebugInfo: () => Promise<string>): RunnablePipeline;
@@ -1,5 +1,6 @@
1
1
  import { removeTrailingForwardSlash } from "@astrojs/internal-helpers/path";
2
2
  import { BaseApp } from "../core/app/entrypoints/index.js";
3
+ import { getFirstForwardedValue, validateForwardedHeaders } from "../core/app/validate-headers.js";
3
4
  import { shouldAppendForwardSlash } from "../core/build/util.js";
4
5
  import { clientLocalsSymbol } from "../core/constants.js";
5
6
  import {
@@ -48,6 +49,13 @@ class AstroServerApp extends BaseApp {
48
49
  clearRouteCache() {
49
50
  this.pipeline.clearRouteCache();
50
51
  }
52
+ /**
53
+ * Clears the cached middleware so it is re-resolved on the next request.
54
+ * Called via HMR when middleware files change.
55
+ */
56
+ clearMiddleware() {
57
+ this.pipeline.clearMiddleware();
58
+ }
51
59
  async devMatch(pathname) {
52
60
  const matchedRoute = await matchRoute(
53
61
  pathname,
@@ -86,7 +94,15 @@ class AstroServerApp extends BaseApp {
86
94
  incomingResponse,
87
95
  isHttps
88
96
  }) {
89
- const origin = `${isHttps ? "https" : "http"}://${incomingRequest.headers[":authority"] ?? incomingRequest.headers.host}`;
97
+ const validated = validateForwardedHeaders(
98
+ getFirstForwardedValue(incomingRequest.headers["x-forwarded-proto"]),
99
+ getFirstForwardedValue(incomingRequest.headers["x-forwarded-host"]),
100
+ getFirstForwardedValue(incomingRequest.headers["x-forwarded-port"]),
101
+ this.manifest.allowedDomains
102
+ );
103
+ const protocol = validated.protocol ?? (isHttps ? "https" : "http");
104
+ const host = validated.host ?? incomingRequest.headers[":authority"] ?? incomingRequest.headers.host;
105
+ const origin = `${protocol}://${host}`;
90
106
  const url = new URL(origin + incomingRequest.url);
91
107
  let pathname;
92
108
  if (this.manifest.trailingSlash === "never" && !incomingRequest.url) {
@@ -58,6 +58,10 @@ async function createAstroServerApp(controller, settings, loader, logger) {
58
58
  app.clearRouteCache();
59
59
  actualLogger.debug("router", "Route cache cleared due to content change");
60
60
  });
61
+ import.meta.hot.on("astro:middleware-updated", () => {
62
+ app.clearMiddleware();
63
+ actualLogger.debug("router", "Middleware cache cleared due to file change");
64
+ });
61
65
  }
62
66
  return {
63
67
  handler(incomingRequest, incomingResponse) {
@@ -211,7 +211,8 @@ async function createDevelopmentManifest(settings) {
211
211
  componentMetadata: /* @__PURE__ */ new Map(),
212
212
  inlinedScripts: /* @__PURE__ */ new Map(),
213
213
  i18n: i18nManifest,
214
- checkOrigin: (settings.config.security?.checkOrigin && settings.buildOutput === "server") ?? false,
214
+ checkOrigin: settings.config.security?.checkOrigin ?? false,
215
+ allowedDomains: settings.config.security?.allowedDomains,
215
216
  actionBodySizeLimit: settings.config.security?.actionBodySizeLimit ? settings.config.security.actionBodySizeLimit : 1024 * 1024,
216
217
  // 1mb default
217
218
  serverIslandBodySizeLimit: settings.config.security?.serverIslandBodySizeLimit ? settings.config.security.serverIslandBodySizeLimit : 1024 * 1024,
@@ -1,9 +1,9 @@
1
1
  import npath from "node:path";
2
2
  import { isCSSRequest } from "vite";
3
3
  import { SUPPORTED_MARKDOWN_FILE_EXTENSIONS } from "../core/constants.js";
4
+ import { isPropagatedAssetBoundary } from "../core/head-propagation/boundary.js";
4
5
  import { unwrapId } from "../core/util.js";
5
6
  import { hasSpecialQueries } from "../vite-plugin-utils/index.js";
6
- import { PROPAGATED_ASSET_QUERY_PARAM } from "../content/consts.js";
7
7
  const fileExtensionsToSSR = /* @__PURE__ */ new Set([".astro", ".mdoc", ...SUPPORTED_MARKDOWN_FILE_EXTENSIONS]);
8
8
  const STRIP_QUERY_PARAMS_REGEX = /\?.*$/;
9
9
  async function* crawlGraph(environment, _id, isRootFile, scanned = /* @__PURE__ */ new Set()) {
@@ -35,7 +35,7 @@ async function* crawlGraph(environment, _id, isRootFile, scanned = /* @__PURE__
35
35
  if (!importedModule.id) continue;
36
36
  const importedModulePathname = importedModule.id.replace(STRIP_QUERY_PARAMS_REGEX, "");
37
37
  const isFileTypeNeedingSSR = fileExtensionsToSSR.has(npath.extname(importedModulePathname));
38
- const isPropagationStoppingPoint = importedModule.id.includes(PROPAGATED_ASSET_QUERY_PARAM);
38
+ const isPropagationStoppingPoint = isPropagatedAssetBoundary(importedModule.id);
39
39
  if (isFileTypeNeedingSSR && // Should not SSR a module with ?astroPropagatedAssets
40
40
  !isPropagationStoppingPoint) {
41
41
  const mod = environment.moduleGraph.getModuleById(importedModule.id);
@@ -1,23 +1,49 @@
1
- import { getParentModuleInfos, getTopLevelPageModuleInfos } from "../core/build/graph.js";
1
+ import { hasHeadInjectComment } from "../core/head-propagation/comment.js";
2
+ import {
3
+ buildImporterGraphFromModuleInfo,
4
+ computeInTreeAncestors
5
+ } from "../core/head-propagation/graph.js";
6
+ import { getTopLevelPageModuleInfos } from "../core/build/graph.js";
2
7
  import { getAstroMetadata } from "../vite-plugin-astro/index.js";
3
8
  import { ASTRO_VITE_ENVIRONMENT_NAMES } from "../core/constants.js";
4
- const injectExp = /(?:^\/\/|\/\/!)\s*astro-head-inject/;
5
9
  function configHeadVitePlugin() {
6
10
  let environment;
7
- function propagateMetadata(id, prop, value, seen = /* @__PURE__ */ new Set()) {
8
- if (seen.has(id)) return;
9
- seen.add(id);
10
- const mod = environment.moduleGraph.getModuleById(id);
11
- const info = this.getModuleInfo(id);
12
- if (info?.meta.astro) {
13
- const astroMetadata = getAstroMetadata(info);
14
- if (astroMetadata) {
15
- Reflect.set(astroMetadata, prop, value);
11
+ function buildImporterGraphFromEnvironment(seed) {
12
+ const queue = [seed];
13
+ const collected = /* @__PURE__ */ new Set();
14
+ while (queue.length > 0) {
15
+ const current = queue.pop();
16
+ if (collected.has(current)) continue;
17
+ collected.add(current);
18
+ const mod = environment.moduleGraph.getModuleById(current);
19
+ for (const importer of mod?.importers ?? []) {
20
+ if (importer.id) {
21
+ queue.push(importer.id);
22
+ }
16
23
  }
17
24
  }
18
- for (const parent of mod?.importers || []) {
19
- if (parent.id) {
20
- propagateMetadata.call(this, parent.id, prop, value, seen);
25
+ return buildImporterGraphFromModuleInfo(collected, (id) => {
26
+ const mod = environment.moduleGraph.getModuleById(id);
27
+ if (!mod) return null;
28
+ return {
29
+ importers: Array.from(mod.importers).map((importer) => importer.id).filter((moduleId) => !!moduleId),
30
+ dynamicImporters: []
31
+ };
32
+ });
33
+ }
34
+ function propagateMetadata(seed, prop, value) {
35
+ const importerGraph = buildImporterGraphFromEnvironment(seed);
36
+ const allAncestors = computeInTreeAncestors({
37
+ seeds: [seed],
38
+ importerGraph
39
+ });
40
+ for (const id of allAncestors) {
41
+ const info = this.getModuleInfo(id);
42
+ if (info?.meta.astro) {
43
+ const astroMetadata = getAstroMetadata(info);
44
+ if (astroMetadata) {
45
+ Reflect.set(astroMetadata, prop, value);
46
+ }
21
47
  }
22
48
  }
23
49
  }
@@ -52,7 +78,7 @@ function configHeadVitePlugin() {
52
78
  if (info && getAstroMetadata(info)?.containsHead) {
53
79
  propagateMetadata.call(this, id, "containsHead", true);
54
80
  }
55
- if (injectExp.test(source)) {
81
+ if (hasHeadInjectComment(source)) {
56
82
  propagateMetadata.call(this, id, "propagation", "in-tree");
57
83
  }
58
84
  }
@@ -66,6 +92,9 @@ function astroHeadBuildPlugin(internals) {
66
92
  },
67
93
  generateBundle(_opts, bundle) {
68
94
  const map = internals.componentMetadata;
95
+ const moduleIds = /* @__PURE__ */ new Set();
96
+ const selfPropagationSeeds = /* @__PURE__ */ new Set();
97
+ const commentPropagationSeeds = /* @__PURE__ */ new Set();
69
98
  function getOrCreateMetadata(id) {
70
99
  if (map.has(id)) return map.get(id);
71
100
  const metadata = {
@@ -78,6 +107,7 @@ function astroHeadBuildPlugin(internals) {
78
107
  for (const [, output] of Object.entries(bundle)) {
79
108
  if (output.type !== "chunk") continue;
80
109
  for (const [id, mod] of Object.entries(output.modules)) {
110
+ moduleIds.add(id);
81
111
  const modinfo = this.getModuleInfo(id);
82
112
  if (modinfo) {
83
113
  const meta = getAstroMetadata(modinfo);
@@ -88,21 +118,29 @@ function astroHeadBuildPlugin(internals) {
88
118
  }
89
119
  }
90
120
  if (meta?.propagation === "self") {
91
- for (const info of getParentModuleInfos(id, this)) {
92
- let metadata = getOrCreateMetadata(info.id);
93
- if (metadata.propagation !== "self") {
94
- metadata.propagation = "in-tree";
95
- }
96
- }
121
+ selfPropagationSeeds.add(id);
97
122
  }
98
123
  }
99
- if (mod.code && injectExp.test(mod.code)) {
100
- for (const info of getParentModuleInfos(id, this)) {
101
- getOrCreateMetadata(info.id).propagation = "in-tree";
102
- }
124
+ if (mod.code && hasHeadInjectComment(mod.code)) {
125
+ commentPropagationSeeds.add(id);
103
126
  }
104
127
  }
105
128
  }
129
+ const importerGraph = buildImporterGraphFromModuleInfo(
130
+ moduleIds,
131
+ (id) => this.getModuleInfo(id)
132
+ );
133
+ const allPropagationSeeds = /* @__PURE__ */ new Set([...selfPropagationSeeds, ...commentPropagationSeeds]);
134
+ const allAncestors = computeInTreeAncestors({
135
+ seeds: allPropagationSeeds,
136
+ importerGraph
137
+ });
138
+ for (const id of allAncestors) {
139
+ const metadata = getOrCreateMetadata(id);
140
+ if (metadata.propagation !== "self") {
141
+ metadata.propagation = "in-tree";
142
+ }
143
+ }
106
144
  }
107
145
  };
108
146
  }
@@ -4,8 +4,12 @@ const BEFORE_HYDRATION_SCRIPT_ID = `${SCRIPT_ID_PREFIX}${"before-hydration"}.js`
4
4
  const PAGE_SCRIPT_ID = `${SCRIPT_ID_PREFIX}${"page"}.js`;
5
5
  const PAGE_SSR_SCRIPT_ID = `${SCRIPT_ID_PREFIX}${"page-ssr"}.js`;
6
6
  function astroScriptsPlugin({ settings }) {
7
+ let command;
7
8
  return {
8
9
  name: "astro:scripts",
10
+ config(_, env) {
11
+ command = env.command;
12
+ },
9
13
  resolveId: {
10
14
  filter: {
11
15
  id: new RegExp(`^${SCRIPT_ID_PREFIX}`)
@@ -37,6 +41,7 @@ function astroScriptsPlugin({ settings }) {
37
41
  }
38
42
  },
39
43
  buildStart() {
44
+ if (command === "serve") return;
40
45
  const hasHydrationScripts = settings.scripts.some((s) => s.stage === "before-hydration");
41
46
  if (hasHydrationScripts && (this.environment.name === ASTRO_VITE_ENVIRONMENT_NAMES.client || this.environment.name === ASTRO_VITE_ENVIRONMENT_NAMES.prerender || this.environment.name === ASTRO_VITE_ENVIRONMENT_NAMES.ssr)) {
42
47
  this.emitFile({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "astro",
3
- "version": "6.0.8",
3
+ "version": "6.1.0",
4
4
  "description": "Astro is a modern site builder with web best practices, performance, and DX front-of-mind.",
5
5
  "type": "module",
6
6
  "author": "withastro",
@@ -101,9 +101,9 @@
101
101
  "README.md"
102
102
  ],
103
103
  "dependencies": {
104
- "@astrojs/compiler": "^3.0.0",
104
+ "@astrojs/compiler": "^3.0.1",
105
105
  "@capsizecss/unpack": "^4.0.0",
106
- "@clack/prompts": "^1.0.1",
106
+ "@clack/prompts": "^1.1.0",
107
107
  "@oslojs/encoding": "^1.1.0",
108
108
  "@rollup/pluginutils": "^5.3.0",
109
109
  "aria-query": "^5.3.2",
@@ -136,11 +136,11 @@
136
136
  "picomatch": "^4.0.3",
137
137
  "rehype": "^13.0.2",
138
138
  "semver": "^7.7.4",
139
- "shiki": "^4.0.0",
139
+ "shiki": "^4.0.2",
140
140
  "smol-toml": "^1.6.0",
141
- "svgo": "^4.0.0",
142
- "tinyclip": "^0.1.6",
143
- "tinyexec": "^1.0.2",
141
+ "svgo": "^4.0.1",
142
+ "tinyclip": "^0.1.12",
143
+ "tinyexec": "^1.0.4",
144
144
  "tinyglobby": "^0.2.15",
145
145
  "tsconfck": "^3.1.6",
146
146
  "ultrahtml": "^1.6.0",
@@ -154,14 +154,14 @@
154
154
  "yargs-parser": "^22.0.0",
155
155
  "zod": "^4.3.6",
156
156
  "@astrojs/internal-helpers": "0.8.0",
157
- "@astrojs/markdown-remark": "7.0.1",
157
+ "@astrojs/markdown-remark": "7.1.0",
158
158
  "@astrojs/telemetry": "3.3.0"
159
159
  },
160
160
  "optionalDependencies": {
161
161
  "sharp": "^0.34.0"
162
162
  },
163
163
  "devDependencies": {
164
- "@astrojs/compiler-rs": "^0.1.4",
164
+ "@astrojs/compiler-rs": "^0.1.6",
165
165
  "@playwright/test": "1.58.2",
166
166
  "@types/aria-query": "^5.0.4",
167
167
  "@types/dlv": "^1.1.5",
@@ -185,11 +185,11 @@
185
185
  "rehype-toc": "^3.0.2",
186
186
  "remark-code-titles": "^0.1.2",
187
187
  "rollup": "^4.58.0",
188
- "sass": "^1.97.3",
188
+ "sass": "^1.98.0",
189
189
  "typescript": "^5.9.3",
190
190
  "undici": "^7.22.0",
191
191
  "unified": "^11.0.5",
192
- "vitest": "^3.2.4",
192
+ "vitest": "^4.1.0",
193
193
  "@astrojs/check": "0.9.8",
194
194
  "astro-scripts": "0.0.14"
195
195
  },