astro 6.0.8 → 6.1.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 (89) 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 +55 -1
  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/errors/errors-data.d.ts +2 -2
  38. package/dist/core/head-propagation/boundary.d.ts +8 -0
  39. package/dist/core/head-propagation/boundary.js +11 -0
  40. package/dist/core/head-propagation/buffer.d.ts +21 -0
  41. package/dist/core/head-propagation/buffer.js +18 -0
  42. package/dist/core/head-propagation/comment.d.ts +7 -0
  43. package/dist/core/head-propagation/comment.js +7 -0
  44. package/dist/core/head-propagation/graph.d.ts +18 -0
  45. package/dist/core/head-propagation/graph.js +32 -0
  46. package/dist/core/head-propagation/policy.d.ts +22 -0
  47. package/dist/core/head-propagation/policy.js +14 -0
  48. package/dist/core/head-propagation/resolver.d.ts +28 -0
  49. package/dist/core/head-propagation/resolver.js +25 -0
  50. package/dist/core/messages/runtime.d.ts +3 -0
  51. package/dist/core/messages/runtime.js +9 -1
  52. package/dist/core/middleware/vite-plugin.d.ts +1 -1
  53. package/dist/core/middleware/vite-plugin.js +25 -0
  54. package/dist/core/redirects/render.d.ts +17 -0
  55. package/dist/core/redirects/render.js +33 -24
  56. package/dist/core/routing/create-manifest.d.ts +15 -0
  57. package/dist/core/routing/create-manifest.js +131 -130
  58. package/dist/core/routing/prerender.d.ts +5 -0
  59. package/dist/core/routing/prerender.js +7 -1
  60. package/dist/core/server-islands/vite-plugin-server-islands.js +18 -6
  61. package/dist/integrations/hooks.js +4 -1
  62. package/dist/jsx/rehype.js +1 -1
  63. package/dist/manifest/serialized.js +5 -0
  64. package/dist/manifest/virtual-module.d.ts +4 -1
  65. package/dist/manifest/virtual-module.js +37 -35
  66. package/dist/runtime/client/dev-toolbar/apps/audit/rules/a11y.js +15 -5
  67. package/dist/runtime/server/render/astro/factory.js +6 -7
  68. package/dist/runtime/server/render/astro/instance.js +2 -4
  69. package/dist/runtime/server/render/astro/render.js +2 -11
  70. package/dist/runtime/server/render/common.js +3 -2
  71. package/dist/runtime/server/render/head-propagation/runtime.d.ts +20 -0
  72. package/dist/runtime/server/render/head-propagation/runtime.js +53 -0
  73. package/dist/runtime/server/render/page.js +5 -1
  74. package/dist/runtime/server/transition.d.ts +19 -1
  75. package/dist/runtime/server/transition.js +6 -1
  76. package/dist/transitions/events.d.ts +1 -1
  77. package/dist/transitions/events.js +5 -5
  78. package/dist/transitions/router.js +23 -19
  79. package/dist/transitions/swap-functions.js +6 -0
  80. package/dist/types/public/config.d.ts +71 -12
  81. package/dist/types/public/integrations.d.ts +9 -2
  82. package/dist/vite-plugin-app/app.d.ts +5 -0
  83. package/dist/vite-plugin-app/app.js +17 -1
  84. package/dist/vite-plugin-app/createAstroServerApp.js +4 -0
  85. package/dist/vite-plugin-astro-server/plugin.js +2 -1
  86. package/dist/vite-plugin-astro-server/vite.js +2 -2
  87. package/dist/vite-plugin-head/index.js +63 -25
  88. package/dist/vite-plugin-scripts/index.js +5 -0
  89. package/package.json +11 -11
@@ -24,6 +24,13 @@ class DevApp extends BaseApp {
24
24
  isDev() {
25
25
  return true;
26
26
  }
27
+ /**
28
+ * Clears the cached middleware so it is re-resolved on the next request.
29
+ * Called via HMR when middleware files change.
30
+ */
31
+ clearMiddleware() {
32
+ this.pipeline.clearMiddleware();
33
+ }
27
34
  /**
28
35
  * Updates the routes list when files change during development.
29
36
  * Called via HMR when new pages are added/removed.
@@ -23,6 +23,10 @@ const createApp = ({ streaming } = {}) => {
23
23
  if (!currentDevApp) return;
24
24
  currentDevApp.pipeline.routeCache.clearAll();
25
25
  });
26
+ import.meta.hot.on("astro:middleware-updated", () => {
27
+ if (!currentDevApp) return;
28
+ currentDevApp.clearMiddleware();
29
+ });
26
30
  }
27
31
  return currentDevApp;
28
32
  };
@@ -4,7 +4,11 @@ import { clientAddressSymbol, nodeRequestAbortControllerCleanupSymbol } from "..
4
4
  import { deserializeManifest } from "./manifest.js";
5
5
  import { createOutgoingHttpHeaders } from "./createOutgoingHttpHeaders.js";
6
6
  import { App } from "./app.js";
7
- import { validateForwardedHeaders, validateHost } from "./validate-headers.js";
7
+ import {
8
+ getFirstForwardedValue,
9
+ validateForwardedHeaders,
10
+ validateHost
11
+ } from "./validate-headers.js";
8
12
  function createRequest(req, {
9
13
  skipBody = false,
10
14
  allowedDomains = [],
@@ -13,9 +17,6 @@ function createRequest(req, {
13
17
  } = {}) {
14
18
  const controller = new AbortController();
15
19
  const isEncrypted = "encrypted" in req.socket && req.socket.encrypted;
16
- const getFirstForwardedValue = (multiValueHeader) => {
17
- return multiValueHeader?.toString()?.split(",").map((e) => e.trim())?.[0];
18
- };
19
20
  const providedProtocol = isEncrypted ? "https" : "http";
20
21
  const untrustedHostname = req.headers.host ?? req.headers[":authority"];
21
22
  const validated = validateForwardedHeaders(
@@ -1,4 +1,10 @@
1
1
  import { type RemotePattern } from '@astrojs/internal-helpers/remote';
2
+ /**
3
+ * Parses a potentially comma-separated multi-value header (as produced by
4
+ * proxy chains) and returns the first value, trimmed of whitespace.
5
+ * Returns `undefined` when the header is absent or empty.
6
+ */
7
+ export declare function getFirstForwardedValue(multiValueHeader: string | string[] | undefined): string | undefined;
2
8
  /**
3
9
  * Validate a host against allowedDomains.
4
10
  * Returns the host only if it matches an allowed pattern; otherwise, undefined.
@@ -1,4 +1,7 @@
1
1
  import { matchPattern } from "@astrojs/internal-helpers/remote";
2
+ function getFirstForwardedValue(multiValueHeader) {
3
+ return multiValueHeader?.toString().split(",").map((e) => e.trim())[0];
4
+ }
2
5
  function sanitizeHost(hostname) {
3
6
  if (!hostname) return void 0;
4
7
  if (/[/\\]/.test(hostname)) return void 0;
@@ -75,6 +78,7 @@ function validateForwardedHeaders(forwardedProtocol, forwardedHost, forwardedPor
75
78
  return result;
76
79
  }
77
80
  export {
81
+ getFirstForwardedValue,
78
82
  validateForwardedHeaders,
79
83
  validateHost
80
84
  };
@@ -124,6 +124,11 @@ export declare abstract class Pipeline {
124
124
  * it returns a no-op function
125
125
  */
126
126
  getMiddleware(): Promise<MiddlewareHandler>;
127
+ /**
128
+ * Clears the cached middleware so it is re-resolved on the next request.
129
+ * Called via HMR when middleware files change during development.
130
+ */
131
+ clearMiddleware(): void;
127
132
  getActions(): Promise<SSRActions>;
128
133
  getSessionDriver(): Promise<SessionDriverFactory | null>;
129
134
  getCacheProvider(): Promise<CacheProvider | null>;
@@ -78,6 +78,13 @@ class Pipeline {
78
78
  return this.resolvedMiddleware;
79
79
  }
80
80
  }
81
+ /**
82
+ * Clears the cached middleware so it is re-resolved on the next request.
83
+ * Called via HMR when middleware files change during development.
84
+ */
85
+ clearMiddleware() {
86
+ this.resolvedMiddleware = void 0;
87
+ }
81
88
  async getActions() {
82
89
  if (this.resolvedActions) {
83
90
  return this.resolvedActions;
@@ -1,3 +1,50 @@
1
+ import type { Logger } from '../logger/core.js';
2
+ import type { AstroPrerenderer, RouteToHeaders } from '../../types/public/index.js';
3
+ import type { RouteData } from '../../types/public/internal.js';
1
4
  import { type BuildInternals } from './internal.js';
2
5
  import type { StaticBuildOptions } from './types.js';
3
6
  export declare function generatePages(options: StaticBuildOptions, internals: BuildInternals, prerenderOutputDir: URL): Promise<void>;
7
+ /**
8
+ * The result of rendering a single path, ready to be written to the filesystem.
9
+ * `null` means no file should be written (empty body, redirect skipped, or a file with the
10
+ * same output path already exists in `publicDir`).
11
+ */
12
+ export interface RenderPathResult {
13
+ body: string | Uint8Array;
14
+ outFile: URL;
15
+ outFolder: URL;
16
+ }
17
+ interface RenderToPathPayload {
18
+ prerenderer: AstroPrerenderer;
19
+ pathname: string;
20
+ route: RouteData;
21
+ options: StaticBuildOptions;
22
+ routeToHeaders?: RouteToHeaders;
23
+ logger: Logger;
24
+ }
25
+ /**
26
+ * Renders a single prerendered path to an in-memory result.
27
+ *
28
+ * This function is intentionally free of filesystem writes — it only calls
29
+ * `prerenderer.render()` and computes output paths. The caller is responsible
30
+ * for persisting the returned `body` to disk (or any other destination).
31
+ *
32
+ * Returning `null` signals that no output file should be created for this path:
33
+ * - the response body was empty
34
+ * - the redirect was suppressed by `config.build.redirects`
35
+ * - a file with the same output path already exists in `publicDir` (public files
36
+ * take priority over generated pages, so the generated page is skipped)
37
+ *
38
+ * @param params
39
+ * @param params.prerenderer - The prerenderer used to obtain a `Response` for the path.
40
+ * @param params.pathname - The URL pathname being rendered (e.g. `/about`).
41
+ * @param params.route - Route data for the page being rendered.
42
+ * @param params.options - Build options; `options.fsMod` is used to check whether a
43
+ * file already exists in `publicDir` at the output path.
44
+ * @param [params.routeToHeaders=new Map()] - Mutable map populated with response headers when
45
+ * the adapter requests static-header tracking. Callers that do
46
+ * not need to inspect the headers after the call can omit this.
47
+ * @param params.logger - Logger instance.
48
+ */
49
+ export declare function renderPath({ prerenderer, pathname, route, options, routeToHeaders, logger, }: RenderToPathPayload): Promise<RenderPathResult | null>;
50
+ export {};
@@ -1,6 +1,5 @@
1
- import fs from "node:fs";
1
+ import nodeFs from "node:fs";
2
2
  import os from "node:os";
3
- import { fileURLToPath } from "node:url";
4
3
  import PLimit from "p-limit";
5
4
  import PQueue from "p-queue";
6
5
  import colors from "piccolore";
@@ -205,14 +204,15 @@ ${colors.bgGreen(colors.black(` ${verb} static routes `))}`);
205
204
  });
206
205
  }
207
206
  const THRESHOLD_SLOW_RENDER_TIME_MS = 500;
208
- async function generatePathWithPrerenderer(prerenderer, pathname, route, options, routeToHeaders, logger) {
209
- const timeStart = performance.now();
207
+ async function renderPath({
208
+ prerenderer,
209
+ pathname,
210
+ route,
211
+ options,
212
+ routeToHeaders = /* @__PURE__ */ new Map(),
213
+ logger
214
+ }) {
210
215
  const { config } = options.settings;
211
- const filePath = getOutputFilename(config.build.format, pathname, route);
212
- logger.info(null, ` ${colors.blue("\u251C\u2500")} ${colors.dim(filePath)}`, false);
213
- if (route.type === "page") {
214
- addPageName(pathname, options);
215
- }
216
216
  if (route.type === "fallback" && route.pathname !== "/") {
217
217
  if (options.routesList.routes.some((routeData) => {
218
218
  if (routeData.pattern.test(pathname)) {
@@ -228,7 +228,7 @@ async function generatePathWithPrerenderer(prerenderer, pathname, route, options
228
228
  return false;
229
229
  }
230
230
  })) {
231
- return;
231
+ return null;
232
232
  }
233
233
  }
234
234
  const url = getUrlForPath(
@@ -260,8 +260,7 @@ async function generatePathWithPrerenderer(prerenderer, pathname, route, options
260
260
  const responseHeaders = response.headers;
261
261
  if (response.status >= 300 && response.status < 400) {
262
262
  if (routeIsRedirect(route) && !config.build.redirects) {
263
- logRenderTime(logger, timeStart, false);
264
- return;
263
+ return null;
265
264
  }
266
265
  const locationSite = getRedirectLocationOrThrow(responseHeaders);
267
266
  const siteURL = config.site;
@@ -281,8 +280,7 @@ async function generatePathWithPrerenderer(prerenderer, pathname, route, options
281
280
  }
282
281
  } else {
283
282
  if (!response.body) {
284
- logRenderTime(logger, timeStart, true);
285
- return;
283
+ return null;
286
284
  }
287
285
  body = Buffer.from(await response.arrayBuffer());
288
286
  }
@@ -298,9 +296,31 @@ async function generatePathWithPrerenderer(prerenderer, pathname, route, options
298
296
  if (options.settings.adapter?.adapterFeatures?.staticHeaders) {
299
297
  routeToHeaders.set(pathname, { headers: responseHeaders, route: integrationRoute });
300
298
  }
301
- if (checkPublicConflict(outFile, route, options.settings, logger)) return;
302
- await fs.promises.mkdir(outFolder, { recursive: true });
303
- await fs.promises.writeFile(outFile, body);
299
+ if (checkPublicConflict(outFile, route, options.settings, logger)) return null;
300
+ return { body, outFile, outFolder };
301
+ }
302
+ async function generatePathWithPrerenderer(prerenderer, pathname, route, options, routeToHeaders, logger) {
303
+ const timeStart = performance.now();
304
+ const { config } = options.settings;
305
+ const filePath = getOutputFilename(config.build.format, pathname, route);
306
+ logger.info(null, ` ${colors.blue("\u251C\u2500")} ${colors.dim(filePath)}`, false);
307
+ if (route.type === "page") {
308
+ addPageName(pathname, options);
309
+ }
310
+ const result = await renderPath({
311
+ prerenderer,
312
+ pathname,
313
+ route,
314
+ options,
315
+ routeToHeaders,
316
+ logger
317
+ });
318
+ if (!result) {
319
+ logRenderTime(logger, timeStart, true);
320
+ return;
321
+ }
322
+ await nodeFs.promises.mkdir(result.outFolder, { recursive: true });
323
+ await nodeFs.promises.writeFile(result.outFile, result.body);
304
324
  logRenderTime(logger, timeStart, false);
305
325
  }
306
326
  function logRenderTime(logger, timeStart, notCreated) {
@@ -347,13 +367,10 @@ function getUrlForPath(pathname, base, origin, format, trailingSlash, routeType)
347
367
  return new URL(buildPathname, origin);
348
368
  }
349
369
  function checkPublicConflict(outFile, route, settings, logger) {
350
- const outFilePath = fileURLToPath(outFile);
351
- const outRoot = fileURLToPath(
352
- settings.buildOutput === "static" && !settings.adapter?.adapterFeatures?.preserveBuildClientDir ? settings.config.outDir : settings.config.build.client
353
- );
354
- const relativePath = outFilePath.slice(outRoot.length);
355
- const publicFilePath = new URL(relativePath, settings.config.publicDir);
356
- if (fs.existsSync(publicFilePath)) {
370
+ const outRoot = settings.buildOutput === "static" && !settings.adapter?.adapterFeatures?.preserveBuildClientDir ? settings.config.outDir : settings.config.build.client;
371
+ const relativePath = outFile.href.slice(outRoot.href.length);
372
+ const publicFileUrl = new URL(relativePath, settings.config.publicDir);
373
+ if (nodeFs.existsSync(publicFileUrl)) {
357
374
  logger.warn(
358
375
  "build",
359
376
  `Skipping ${route.component} because a file with the same name exists in the public folder: ${relativePath}`
@@ -363,5 +380,6 @@ function checkPublicConflict(outFile, route, settings, logger) {
363
380
  return false;
364
381
  }
365
382
  export {
366
- generatePages
383
+ generatePages,
384
+ renderPath
367
385
  };
@@ -1,6 +1,6 @@
1
1
  import { isCSSRequest } from "vite";
2
- import { hasAssetPropagationFlag } from "../../../content/index.js";
3
2
  import { ASTRO_VITE_ENVIRONMENT_NAMES } from "../../constants.js";
3
+ import { isPropagatedAssetBoundary } from "../../head-propagation/boundary.js";
4
4
  import {
5
5
  getParentExtendedModuleInfos,
6
6
  getParentModuleInfos,
@@ -95,7 +95,7 @@ function rollupPluginAstroBuildCSS(options) {
95
95
  const parentModuleInfos = getParentExtendedModuleInfos(
96
96
  scopedToModule,
97
97
  this,
98
- hasAssetPropagationFlag
98
+ isPropagatedAssetBoundary
99
99
  );
100
100
  for (const { info: pageInfo, depth, order } of parentModuleInfos) {
101
101
  if (moduleIsTopLevelPage(pageInfo)) {
@@ -152,9 +152,13 @@ function rollupPluginAstroBuildCSS(options) {
152
152
  }
153
153
  for (const id of Object.keys(chunk.modules)) {
154
154
  if (!isCSSRequest(id)) continue;
155
- const parentModuleInfos = getParentExtendedModuleInfos(id, this, hasAssetPropagationFlag);
155
+ const parentModuleInfos = getParentExtendedModuleInfos(
156
+ id,
157
+ this,
158
+ isPropagatedAssetBoundary
159
+ );
156
160
  for (const { info: pageInfo, depth, order } of parentModuleInfos) {
157
- if (hasAssetPropagationFlag(pageInfo.id)) {
161
+ if (isPropagatedAssetBoundary(pageInfo.id)) {
158
162
  const propagatedCss = moduleIdToPropagatedCss[pageInfo.id] ??= /* @__PURE__ */ new Set();
159
163
  for (const css of meta.importedCss) {
160
164
  propagatedCss.add(css);
@@ -1,5 +1,5 @@
1
1
  import type { OutgoingHttpHeaders } from 'node:http';
2
- import type { RehypePlugin as _RehypePlugin, RemarkPlugin as _RemarkPlugin, RemarkRehype as _RemarkRehype, ShikiConfig } from '@astrojs/markdown-remark';
2
+ import type { RehypePlugin as _RehypePlugin, RemarkPlugin as _RemarkPlugin, RemarkRehype as _RemarkRehype, ShikiConfig, Smartypants as _Smartypants } from '@astrojs/markdown-remark';
3
3
  import type { Config as SvgoConfig } from 'svgo';
4
4
  import * as z from 'zod/v4';
5
5
  import type { ViteUserConfig } from '../../../types/public/config.js';
@@ -15,6 +15,8 @@ type RehypePlugin = ComplexifyWithUnion<_RehypePlugin>;
15
15
  type RemarkPlugin = ComplexifyWithUnion<_RemarkPlugin>;
16
16
  /** @lintignore */
17
17
  export type RemarkRehype = ComplexifyWithOmit<_RemarkRehype>;
18
+ /** @lintignore */
19
+ export type Smartypants = ComplexifyWithOmit<_Smartypants>;
18
20
  export declare const ASTRO_CONFIG_DEFAULTS: {
19
21
  root: string;
20
22
  srcDir: string;
@@ -326,7 +328,7 @@ export declare const AstroConfigSchema: z.ZodObject<{
326
328
  rehypePlugins: z.ZodDefault<z.ZodArray<z.ZodUnion<readonly [z.ZodString, z.ZodTuple<[z.ZodString, z.ZodAny], null>, z.ZodCustom<RehypePlugin, RehypePlugin>, z.ZodTuple<[z.ZodCustom<RehypePlugin, RehypePlugin>, z.ZodAny], null>]>>>;
327
329
  remarkRehype: z.ZodDefault<z.ZodCustom<RemarkRehype, RemarkRehype>>;
328
330
  gfm: z.ZodDefault<z.ZodBoolean>;
329
- smartypants: z.ZodDefault<z.ZodBoolean>;
331
+ smartypants: z.ZodPrefault<z.ZodPipe<z.ZodUnion<readonly [z.ZodBoolean, z.ZodType<Smartypants, unknown, z.core.$ZodTypeInternals<Smartypants, unknown>>]>, z.ZodTransform<false | Smartypants, boolean | Smartypants>>>;
330
332
  }, z.core.$strip>>;
331
333
  vite: z.ZodDefault<z.ZodCustom<ViteUserConfig, ViteUserConfig>>;
332
334
  i18n: z.ZodOptional<z.ZodOptional<z.ZodObject<{
@@ -70,6 +70,24 @@ const ASTRO_CONFIG_DEFAULTS = {
70
70
  }
71
71
  };
72
72
  const highlighterTypesSchema = z.union([z.literal("shiki"), z.literal("prism")]).default(syntaxHighlightDefaults.type);
73
+ const quoteCharacterMapSchema = z.object({
74
+ double: z.string(),
75
+ single: z.string()
76
+ });
77
+ const smartypantsOptionsSchema = z.object({
78
+ backticks: z.union([z.boolean(), z.literal("all")]).default(true),
79
+ closingQuotes: quoteCharacterMapSchema.default({
80
+ double: "\u201D",
81
+ single: "\u2019"
82
+ }),
83
+ dashes: z.union([z.boolean(), z.literal("inverted"), z.literal("oldschool")]).default(true),
84
+ ellipses: z.union([z.boolean(), z.literal("spaced"), z.literal("unspaced")]).default(true),
85
+ openingQuotes: quoteCharacterMapSchema.default({
86
+ double: "\u201C",
87
+ single: "\u2018"
88
+ }),
89
+ quotes: z.boolean().default(true)
90
+ });
73
91
  const AstroConfigSchema = z.object({
74
92
  root: z.string().optional().default(ASTRO_CONFIG_DEFAULTS.root).transform((val) => new URL(val)),
75
93
  srcDir: z.string().optional().default(ASTRO_CONFIG_DEFAULTS.srcDir).transform((val) => new URL(val)),
@@ -216,7 +234,10 @@ const AstroConfigSchema = z.object({
216
234
  ]).array().default(ASTRO_CONFIG_DEFAULTS.markdown.rehypePlugins),
217
235
  remarkRehype: z.custom((data) => data instanceof Object && !Array.isArray(data)).default(ASTRO_CONFIG_DEFAULTS.markdown.remarkRehype),
218
236
  gfm: z.boolean().default(ASTRO_CONFIG_DEFAULTS.markdown.gfm),
219
- smartypants: z.boolean().default(ASTRO_CONFIG_DEFAULTS.markdown.smartypants)
237
+ smartypants: z.union([z.boolean(), smartypantsOptionsSchema]).transform((val) => {
238
+ if (val === true) return smartypantsOptionsSchema.parse({});
239
+ return val;
240
+ }).prefault(ASTRO_CONFIG_DEFAULTS.markdown.smartypants)
220
241
  }).prefault({}),
221
242
  vite: z.custom((data) => data instanceof Object && !Array.isArray(data)).default(ASTRO_CONFIG_DEFAULTS.vite),
222
243
  i18n: z.optional(
@@ -212,7 +212,7 @@ export declare function createRelativeSchema(cmd: string, fileProtocolRoot: stri
212
212
  rehypePlugins: z.ZodDefault<z.ZodArray<z.ZodUnion<readonly [z.ZodString, z.ZodTuple<[z.ZodString, z.ZodAny], null>, z.ZodCustom<import("@astrojs/markdown-remark").RehypePlugin & import("./base.js").ComplexifyUnionObj, import("@astrojs/markdown-remark").RehypePlugin & import("./base.js").ComplexifyUnionObj>, z.ZodTuple<[z.ZodCustom<import("@astrojs/markdown-remark").RehypePlugin & import("./base.js").ComplexifyUnionObj, import("@astrojs/markdown-remark").RehypePlugin & import("./base.js").ComplexifyUnionObj>, z.ZodAny], null>]>>>;
213
213
  remarkRehype: z.ZodDefault<z.ZodCustom<import("./base.js").RemarkRehype, import("./base.js").RemarkRehype>>;
214
214
  gfm: z.ZodDefault<z.ZodBoolean>;
215
- smartypants: z.ZodDefault<z.ZodBoolean>;
215
+ smartypants: z.ZodPrefault<z.ZodPipe<z.ZodUnion<readonly [z.ZodBoolean, z.ZodType<import("./base.js").Smartypants, unknown, z.core.$ZodTypeInternals<import("./base.js").Smartypants, unknown>>]>, z.ZodTransform<false | import("./base.js").Smartypants, boolean | import("./base.js").Smartypants>>>;
216
216
  }, z.core.$strip>>;
217
217
  vite: z.ZodDefault<z.ZodCustom<import("../../../index.js").ViteUserConfig, import("../../../index.js").ViteUserConfig>>;
218
218
  i18n: z.ZodOptional<z.ZodOptional<z.ZodObject<{
@@ -497,7 +497,7 @@ export declare function createRelativeSchema(cmd: string, fileProtocolRoot: stri
497
497
  rehypePlugins: (string | (import("@astrojs/markdown-remark").RehypePlugin & import("./base.js").ComplexifyUnionObj) | [string, any] | [import("@astrojs/markdown-remark").RehypePlugin & import("./base.js").ComplexifyUnionObj, any])[];
498
498
  remarkRehype: import("./base.js").RemarkRehype;
499
499
  gfm: boolean;
500
- smartypants: boolean;
500
+ smartypants: false | import("./base.js").Smartypants;
501
501
  };
502
502
  vite: import("../../../index.js").ViteUserConfig;
503
503
  security: {
@@ -739,7 +739,7 @@ export declare function createRelativeSchema(cmd: string, fileProtocolRoot: stri
739
739
  rehypePlugins: (string | (import("@astrojs/markdown-remark").RehypePlugin & import("./base.js").ComplexifyUnionObj) | [string, any] | [import("@astrojs/markdown-remark").RehypePlugin & import("./base.js").ComplexifyUnionObj, any])[];
740
740
  remarkRehype: import("./base.js").RemarkRehype;
741
741
  gfm: boolean;
742
- smartypants: boolean;
742
+ smartypants: false | import("./base.js").Smartypants;
743
743
  };
744
744
  vite: import("../../../index.js").ViteUserConfig;
745
745
  security: {
@@ -1,4 +1,4 @@
1
- const ASTRO_VERSION = "6.0.8";
1
+ const ASTRO_VERSION = "6.1.1";
2
2
  const ASTRO_GENERATOR = `Astro v${ASTRO_VERSION}`;
3
3
  const REROUTE_DIRECTIVE_HEADER = "X-Astro-Reroute";
4
4
  const REWRITE_DIRECTIVE_HEADER_KEY = "X-Astro-Rewrite";
@@ -103,7 +103,7 @@ async function createVite(commandConfig, { settings, logger, mode, command, fs =
103
103
  }),
104
104
  vitePluginStaticPaths(),
105
105
  await astroPluginRoutes({ routesList, settings, logger, fsMod: fs, command }),
106
- astroVirtualManifestPlugin(),
106
+ astroVirtualManifestPlugin({ settings }),
107
107
  vitePluginEnvironment({ settings, astroPkgsConfig, command }),
108
108
  pluginPage({ routesList }),
109
109
  pluginPages({ routesList }),
@@ -1,4 +1,5 @@
1
1
  import fs from "node:fs";
2
+ import { createRequire } from "node:module";
2
3
  import { performance } from "node:perf_hooks";
3
4
  import colors from "piccolore";
4
5
  import { gt, major, minor, patch } from "semver";
@@ -20,13 +21,23 @@ import {
20
21
  } from "./update-check.js";
21
22
  import { BuildTimeAstroVersionProvider } from "../../cli/infra/build-time-astro-version-provider.js";
22
23
  import { piccoloreTextStyler } from "../../cli/infra/piccolore-text-styler.js";
24
+ function warnIfVite8({ root, logger }) {
25
+ try {
26
+ const require2 = createRequire(root);
27
+ const { version } = require2("vite/package.json");
28
+ if (major(version) >= 8) {
29
+ logger.warn("SKIP_FORMAT", msg.vite8Warning({ viteVersion: version }));
30
+ }
31
+ } catch {
32
+ }
33
+ }
23
34
  async function dev(inlineConfig) {
24
35
  ensureProcessNodeEnv("development");
25
36
  const devStart = performance.now();
26
37
  await telemetry.record([]);
27
38
  const restart = await createContainerWithAutomaticRestart({ inlineConfig, fs });
28
39
  const logger = restart.container.logger;
29
- const currentVersion = "6.0.8";
40
+ const currentVersion = "6.1.1";
30
41
  const isPrerelease = currentVersion.includes("-");
31
42
  if (!isPrerelease) {
32
43
  try {
@@ -100,6 +111,7 @@ async function dev(inlineConfig) {
100
111
  if (restart.container.viteServer.config.server?.fs?.strict === false) {
101
112
  logger.warn("SKIP_FORMAT", msg.fsStrictWarning());
102
113
  }
114
+ setImmediate(() => warnIfVite8({ root: restart.container.settings.config.root, logger }));
103
115
  logger.info(null, colors.green("watching for file changes..."));
104
116
  return {
105
117
  address: devServerAddressInfo,
@@ -29,7 +29,7 @@ export declare const UnknownCompilerError: {
29
29
  /**
30
30
  * @docs
31
31
  * @see
32
- * - [Official integrations](https://docs.astro.build/en/guides/integrations-guide/#official-integrations)
32
+ * - [Official integrations](https://docs.astro.build/en/guides/integrations/#official-integrations)
33
33
  * - [Astro.clientAddress](https://docs.astro.build/en/reference/api-reference/#clientaddress)
34
34
  * @description
35
35
  * The adapter you're using unfortunately does not support `Astro.clientAddress`.
@@ -128,7 +128,7 @@ export declare const MissingMediaQueryDirective: {
128
128
  * @message Unable to render `COMPONENT_NAME`. There are `RENDERER_COUNT` renderer(s) configured in your `astro.config.mjs` file, but none were able to server-side render `COMPONENT_NAME`.
129
129
  * @see
130
130
  * - [Frameworks components](https://docs.astro.build/en/guides/framework-components/)
131
- * - [UI Frameworks](https://docs.astro.build/en/guides/integrations-guide/#official-integrations)
131
+ * - [UI Frameworks](https://docs.astro.build/en/guides/integrations/#official-integrations)
132
132
  * @description
133
133
  * None of the installed integrations were able to render the component you imported. Make sure to install the appropriate integration for the type of component you are trying to include in your page.
134
134
  *
@@ -0,0 +1,8 @@
1
+ /**
2
+ * True when a module id is a propagated-assets boundary.
3
+ *
4
+ * @example
5
+ * `/src/post.mdx?astroPropagatedAssets` stops CSS graph traversal so styles
6
+ * from one content render do not bleed into unrelated pages.
7
+ */
8
+ export declare function isPropagatedAssetBoundary(id: string): boolean;
@@ -0,0 +1,11 @@
1
+ import { PROPAGATED_ASSET_FLAG } from "../../content/consts.js";
2
+ function isPropagatedAssetBoundary(id) {
3
+ try {
4
+ return new URL(id, "file://").searchParams.has(PROPAGATED_ASSET_FLAG);
5
+ } catch {
6
+ return false;
7
+ }
8
+ }
9
+ export {
10
+ isPropagatedAssetBoundary
11
+ };
@@ -0,0 +1,21 @@
1
+ import type { SSRResult } from '../../types/public/internal.js';
2
+ export interface HeadPropagator {
3
+ init(result: SSRResult): unknown | Promise<unknown>;
4
+ }
5
+ /**
6
+ * Runs all registered propagators and collects emitted head HTML strings.
7
+ *
8
+ * This iterates the live `Set`, so propagators discovered during iteration
9
+ * are also processed in the same pass.
10
+ *
11
+ * @example
12
+ * If a layout initializes and discovers a nested component that also emits
13
+ * `<link rel="stylesheet">`, both head chunks are collected before flush.
14
+ */
15
+ export declare function collectPropagatedHeadParts(input: {
16
+ propagators: Set<HeadPropagator>;
17
+ result: SSRResult;
18
+ isHeadAndContent: (value: unknown) => value is {
19
+ head: string;
20
+ };
21
+ }): Promise<string[]>;
@@ -0,0 +1,18 @@
1
+ async function collectPropagatedHeadParts(input) {
2
+ const collectedHeadParts = [];
3
+ const iterator = input.propagators.values();
4
+ while (true) {
5
+ const { value, done } = iterator.next();
6
+ if (done) {
7
+ break;
8
+ }
9
+ const returnValue = await value.init(input.result);
10
+ if (input.isHeadAndContent(returnValue) && returnValue.head) {
11
+ collectedHeadParts.push(returnValue.head);
12
+ }
13
+ }
14
+ return collectedHeadParts;
15
+ }
16
+ export {
17
+ collectPropagatedHeadParts
18
+ };
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Returns true when source contains the `astro-head-inject` marker comment.
3
+ *
4
+ * @example
5
+ * `//! astro-head-inject` in a helper module marks parent importers as `in-tree`.
6
+ */
7
+ export declare function hasHeadInjectComment(source: string): boolean;
@@ -0,0 +1,7 @@
1
+ const HEAD_INJECT_COMMENT_EXP = /(?:^\/\/|\/\/!)\s*astro-head-inject/;
2
+ function hasHeadInjectComment(source) {
3
+ return HEAD_INJECT_COMMENT_EXP.test(source);
4
+ }
5
+ export {
6
+ hasHeadInjectComment
7
+ };
@@ -0,0 +1,18 @@
1
+ export type ModuleId = string;
2
+ export type ImporterGraph = Map<ModuleId, Set<ModuleId>>;
3
+ /**
4
+ * Computes all importer ancestors that should be treated as `in-tree`.
5
+ *
6
+ * @example
7
+ * If `Button.astro` is imported by `PostLayout.astro`, which is imported by
8
+ * `src/pages/blog.astro`, then seeding with `Button.astro` marks all three.
9
+ */
10
+ export declare function computeInTreeAncestors(input: {
11
+ seeds: Iterable<ModuleId>;
12
+ importerGraph: ImporterGraph;
13
+ stopAt?: (id: ModuleId) => boolean;
14
+ }): Set<ModuleId>;
15
+ export declare function buildImporterGraphFromModuleInfo(moduleIds: Iterable<ModuleId>, getModuleInfo: (id: string) => {
16
+ importers: readonly string[];
17
+ dynamicImporters: readonly string[];
18
+ } | null): ImporterGraph;
@@ -0,0 +1,32 @@
1
+ function computeInTreeAncestors(input) {
2
+ const inTree = /* @__PURE__ */ new Set();
3
+ const seen = /* @__PURE__ */ new Set();
4
+ function walk(moduleId) {
5
+ if (seen.has(moduleId)) return;
6
+ seen.add(moduleId);
7
+ if (input.stopAt?.(moduleId)) {
8
+ return;
9
+ }
10
+ inTree.add(moduleId);
11
+ for (const importer of input.importerGraph.get(moduleId) ?? []) {
12
+ walk(importer);
13
+ }
14
+ }
15
+ for (const seed of input.seeds) {
16
+ walk(seed);
17
+ }
18
+ return inTree;
19
+ }
20
+ function buildImporterGraphFromModuleInfo(moduleIds, getModuleInfo) {
21
+ const graph = /* @__PURE__ */ new Map();
22
+ for (const id of moduleIds) {
23
+ const mod = getModuleInfo(id);
24
+ if (!mod) continue;
25
+ graph.set(id, /* @__PURE__ */ new Set([...mod.importers, ...mod.dynamicImporters]));
26
+ }
27
+ return graph;
28
+ }
29
+ export {
30
+ buildImporterGraphFromModuleInfo,
31
+ computeInTreeAncestors
32
+ };
@@ -0,0 +1,22 @@
1
+ export interface HeadInstructionRenderState {
2
+ hasRenderedHead: boolean;
3
+ headInTree: boolean;
4
+ partial: boolean;
5
+ }
6
+ /**
7
+ * Policy for explicit `head` instructions.
8
+ *
9
+ * @example
10
+ * A page with `<head>{Astro.head}</head>` renders once, then blocks repeats.
11
+ */
12
+ export declare function shouldRenderHeadInstruction(state: HeadInstructionRenderState): boolean;
13
+ /**
14
+ * Policy for fallback `maybe-head` instructions.
15
+ *
16
+ * @example
17
+ * A layout without `<head>` can inject styles with `maybe-head`, but only when
18
+ * no explicit `<head>` exists in the rendered tree.
19
+ */
20
+ export declare function shouldRenderMaybeHeadInstruction(state: HeadInstructionRenderState): boolean;
21
+ /** Dispatches to the policy function for `head` or `maybe-head`. */
22
+ export declare function shouldRenderInstruction(type: 'head' | 'maybe-head', state: HeadInstructionRenderState): boolean;
@@ -0,0 +1,14 @@
1
+ function shouldRenderHeadInstruction(state) {
2
+ return !state.hasRenderedHead && !state.partial;
3
+ }
4
+ function shouldRenderMaybeHeadInstruction(state) {
5
+ return !state.hasRenderedHead && !state.headInTree && !state.partial;
6
+ }
7
+ function shouldRenderInstruction(type, state) {
8
+ return type === "head" ? shouldRenderHeadInstruction(state) : shouldRenderMaybeHeadInstruction(state);
9
+ }
10
+ export {
11
+ shouldRenderHeadInstruction,
12
+ shouldRenderInstruction,
13
+ shouldRenderMaybeHeadInstruction
14
+ };