astro 6.3.8 → 6.4.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 (47) hide show
  1. package/components/Code.astro +1 -1
  2. package/dist/assets/fonts/config.d.ts +4 -4
  3. package/dist/cli/infra/build-time-astro-version-provider.js +1 -1
  4. package/dist/content/content-layer.js +16 -10
  5. package/dist/content/data-store.d.ts +1 -1
  6. package/dist/content/runtime-assets.d.ts +2 -2
  7. package/dist/content/runtime.d.ts +1 -1
  8. package/dist/content/runtime.js +3 -1
  9. package/dist/content/utils.d.ts +1 -1
  10. package/dist/content/utils.js +1 -1
  11. package/dist/core/app/entrypoints/node.d.ts +1 -1
  12. package/dist/core/app/entrypoints/node.js +2 -0
  13. package/dist/core/app/node.d.ts +16 -0
  14. package/dist/core/app/node.js +56 -13
  15. package/dist/core/build/static-build.js +13 -8
  16. package/dist/core/config/merge.js +4 -0
  17. package/dist/core/config/schemas/base.d.ts +16 -10
  18. package/dist/core/config/schemas/base.js +23 -3
  19. package/dist/core/config/schemas/relative.d.ts +60 -42
  20. package/dist/core/config/validate.js +52 -0
  21. package/dist/core/constants.js +1 -1
  22. package/dist/core/dev/dev.js +1 -1
  23. package/dist/core/fetch/fetch-state.js +49 -0
  24. package/dist/core/messages/runtime.js +1 -1
  25. package/dist/core/preview/index.js +6 -5
  26. package/dist/core/preview/static-preview-server.js +2 -1
  27. package/dist/core/render/params-and-props.js +1 -1
  28. package/dist/core/render/route-cache.js +1 -1
  29. package/dist/core/routing/validation.js +1 -1
  30. package/dist/core/server-islands/vite-plugin-server-islands.d.ts +6 -1
  31. package/dist/core/server-islands/vite-plugin-server-islands.js +13 -3
  32. package/dist/core/session/config.d.ts +1 -1
  33. package/dist/markdown/index.d.ts +4 -0
  34. package/dist/markdown/index.js +14 -0
  35. package/dist/prerender/utils.js +5 -1
  36. package/dist/types/public/config.d.ts +32 -1
  37. package/dist/types/public/content.d.ts +1 -1
  38. package/dist/types/public/index.d.ts +1 -1
  39. package/dist/types/public/integrations.d.ts +8 -0
  40. package/dist/vite-plugin-app/app.js +2 -9
  41. package/dist/vite-plugin-integrations-container/index.js +15 -6
  42. package/dist/vite-plugin-markdown/content-entry-type.js +7 -4
  43. package/dist/vite-plugin-markdown/images.js +9 -11
  44. package/dist/vite-plugin-markdown/index.js +12 -11
  45. package/package.json +4 -6
  46. package/dist/jsx/rehype.d.ts +0 -5
  47. package/dist/jsx/rehype.js +0 -241
@@ -1,5 +1,5 @@
1
1
  ---
2
- import { createShikiHighlighter, type ThemePresets } from '@astrojs/markdown-remark/shiki';
2
+ import { createShikiHighlighter, type ThemePresets } from '@astrojs/internal-helpers/shiki';
3
3
  import type { ShikiTransformer, ThemeRegistration, ThemeRegistrationRaw } from 'shiki';
4
4
  import { bundledLanguages } from 'shiki/langs';
5
5
  import type { CodeLanguage } from '../dist/types/public/common.js';
@@ -7,11 +7,11 @@ export declare const StyleSchema: z.ZodEnum<{
7
7
  oblique: "oblique";
8
8
  }>;
9
9
  export declare const DisplaySchema: z.ZodEnum<{
10
- optional: "optional";
11
10
  auto: "auto";
11
+ optional: "optional";
12
+ fallback: "fallback";
12
13
  block: "block";
13
14
  swap: "swap";
14
- fallback: "fallback";
15
15
  }>;
16
16
  export declare const FontProviderSchema: z.ZodCustom<FontProvider<never>, FontProvider<never>>;
17
17
  export declare const FontFamilySchema: z.ZodObject<{
@@ -45,11 +45,11 @@ export declare const FontFamilySchema: z.ZodObject<{
45
45
  fallbacks: z.ZodOptional<z.ZodArray<z.ZodString>>;
46
46
  optimizedFallbacks: z.ZodOptional<z.ZodBoolean>;
47
47
  display: z.ZodOptional<z.ZodEnum<{
48
- optional: "optional";
49
48
  auto: "auto";
49
+ optional: "optional";
50
+ fallback: "fallback";
50
51
  block: "block";
51
52
  swap: "swap";
52
- fallback: "fallback";
53
53
  }>>;
54
54
  stretch: z.ZodOptional<z.ZodString>;
55
55
  featureSettings: z.ZodOptional<z.ZodString>;
@@ -1,6 +1,6 @@
1
1
  class BuildTimeAstroVersionProvider {
2
2
  // Injected during the build through esbuild define
3
- version = "6.3.8";
3
+ version = "6.4.0";
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 !== "6.3.8") {
200
+ if (previousAstroVersion && previousAstroVersion !== "6.4.0") {
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 ("6.3.8") {
203
- this.#store.metaStore().set("astro-version", "6.3.8");
208
+ if ("6.4.0") {
209
+ this.#store.metaStore().set("astro-version", "6.4.0");
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 { PluginContext } from 'rollup';
2
2
  import * as z from 'zod/v4';
3
3
  export declare function createImage(pluginContext: 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';
@@ -322,7 +322,9 @@ async function updateImageReferencesInBody(html, fileName) {
322
322
  const { getImage } = await import("virtual:astro:get-image");
323
323
  for (const [_full, imagePath] of html.matchAll(CONTENT_LAYER_IMAGE_REGEX)) {
324
324
  try {
325
- const decodedImagePath = JSON.parse(imagePath.replaceAll("&#x22;", '"'));
325
+ const decodedImagePath = JSON.parse(
326
+ imagePath.replace(/&(?:#x22|quot);/g, '"').replace(/&(?:#x27|apos);/g, "'")
327
+ );
326
328
  let image;
327
329
  if (URL.canParse(decodedImagePath.src)) {
328
330
  image = await getImage(decodedImagePath);
@@ -125,7 +125,7 @@ export declare function getContentEntryIdAndSlug({ entry, contentDir, collection
125
125
  slug: string;
126
126
  };
127
127
  export declare function getEntryType(entryPath: string, paths: Pick<ContentPaths, 'config' | 'contentDir' | 'root'>, contentFileExts: string[], dataFileExts: string[]): 'content' | 'data' | 'config' | 'ignored';
128
- export declare function safeParseFrontmatter(source: string, id?: string): import("@astrojs/markdown-remark").ParseFrontmatterResult;
128
+ export declare function safeParseFrontmatter(source: string, id?: string): import("@astrojs/internal-helpers/frontmatter").ParseFrontmatterResult;
129
129
  /**
130
130
  * The content config is loaded separately from other `src/` files.
131
131
  * 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";
@@ -1 +1 @@
1
- export { NodeApp, loadApp, loadManifest, createRequest, writeResponse, getAbortControllerCleanup, } from '../node.js';
1
+ export { NodeApp, loadApp, loadManifest, createRequest, createRequestFromNodeRequest, writeResponse, getAbortControllerCleanup, } from '../node.js';
@@ -3,12 +3,14 @@ import {
3
3
  loadApp,
4
4
  loadManifest,
5
5
  createRequest,
6
+ createRequestFromNodeRequest,
6
7
  writeResponse,
7
8
  getAbortControllerCleanup
8
9
  } from "../node.js";
9
10
  export {
10
11
  NodeApp,
11
12
  createRequest,
13
+ createRequestFromNodeRequest,
12
14
  getAbortControllerCleanup,
13
15
  loadApp,
14
16
  loadManifest,
@@ -25,6 +25,22 @@ interface NodeRequest extends IncomingMessage {
25
25
  * })
26
26
  * ```
27
27
  */
28
+ /**
29
+ * Internal version of `createRequest` that skips X-Forwarded-* header
30
+ * validation. Forwarded headers are resolved later inside `FetchState`,
31
+ * so doing it here too would duplicate work on every request.
32
+ *
33
+ * Use this for all internal call sites that go through `app.render()`
34
+ * (which creates a `FetchState`). The public `createRequest` keeps the
35
+ * forwarded header logic for external adapters that may not use
36
+ * `FetchState`.
37
+ */
38
+ export declare function createRequestFromNodeRequest(req: NodeRequest, { skipBody, allowedDomains, bodySizeLimit, port: serverPort, }?: {
39
+ skipBody?: boolean;
40
+ allowedDomains?: Partial<RemotePattern>[];
41
+ bodySizeLimit?: number;
42
+ port?: number;
43
+ }): Request;
28
44
  export declare function createRequest(req: NodeRequest, { skipBody, allowedDomains, bodySizeLimit, port: serverPort, }?: {
29
45
  skipBody?: boolean;
30
46
  allowedDomains?: Partial<RemotePattern>[];
@@ -9,6 +9,48 @@ import {
9
9
  validateForwardedHeaders,
10
10
  validateHost
11
11
  } from "./validate-headers.js";
12
+ function createRequestFromNodeRequest(req, {
13
+ skipBody = false,
14
+ allowedDomains = [],
15
+ bodySizeLimit,
16
+ port: serverPort
17
+ } = {}) {
18
+ const controller = new AbortController();
19
+ const isEncrypted = "encrypted" in req.socket && req.socket.encrypted;
20
+ const protocol = isEncrypted ? "https" : "http";
21
+ const hostname = typeof req.headers.host === "string" ? req.headers.host : typeof req.headers[":authority"] === "string" ? req.headers[":authority"] : serverPort ? `localhost:${serverPort}` : "localhost";
22
+ let url;
23
+ try {
24
+ url = new URL(`${protocol}://${hostname}${req.url}`);
25
+ } catch {
26
+ url = new URL(`${protocol}://${hostname}`);
27
+ }
28
+ const options = {
29
+ method: req.method || "GET",
30
+ headers: makeRequestHeaders(req),
31
+ signal: controller.signal
32
+ };
33
+ const bodyAllowed = options.method !== "HEAD" && options.method !== "GET" && skipBody === false;
34
+ if (bodyAllowed) {
35
+ Object.assign(options, makeRequestBody(req, bodySizeLimit));
36
+ }
37
+ const request = new Request(url, options);
38
+ wireAbortController(req, controller);
39
+ const untrustedHostname = req.headers.host ?? req.headers[":authority"];
40
+ const validatedHostname = validateHost(
41
+ typeof untrustedHostname === "string" ? untrustedHostname : void 0,
42
+ protocol,
43
+ allowedDomains
44
+ );
45
+ const forwardedHost = getFirstForwardedValue(req.headers["x-forwarded-host"]);
46
+ const hostValidated = validatedHostname !== void 0 || forwardedHost !== void 0 && allowedDomains.length > 0;
47
+ const forwardedClientIp = hostValidated ? getFirstForwardedValue(req.headers["x-forwarded-for"]) : void 0;
48
+ const clientIp = forwardedClientIp || req.socket?.remoteAddress;
49
+ if (clientIp) {
50
+ Reflect.set(request, clientAddressSymbol, clientIp);
51
+ }
52
+ return request;
53
+ }
12
54
  function createRequest(req, {
13
55
  skipBody = false,
14
56
  allowedDomains = [],
@@ -51,6 +93,16 @@ function createRequest(req, {
51
93
  Object.assign(options, makeRequestBody(req, bodySizeLimit));
52
94
  }
53
95
  const request = new Request(url, options);
96
+ wireAbortController(req, controller);
97
+ const hostValidated = validated.host !== void 0 || validatedHostname !== void 0;
98
+ const forwardedClientIp = hostValidated ? getFirstForwardedValue(req.headers["x-forwarded-for"]) : void 0;
99
+ const clientIp = forwardedClientIp || req.socket?.remoteAddress;
100
+ if (clientIp) {
101
+ Reflect.set(request, clientAddressSymbol, clientIp);
102
+ }
103
+ return request;
104
+ }
105
+ function wireAbortController(req, controller) {
54
106
  const socket = getRequestSocket(req);
55
107
  if (socket && typeof socket.on === "function") {
56
108
  const existingCleanup = getAbortControllerCleanup(req);
@@ -85,13 +137,6 @@ function createRequest(req, {
85
137
  onSocketClose();
86
138
  }
87
139
  }
88
- const hostValidated = validated.host !== void 0 || validatedHostname !== void 0;
89
- const forwardedClientIp = hostValidated ? getFirstForwardedValue(req.headers["x-forwarded-for"]) : void 0;
90
- const clientIp = forwardedClientIp || req.socket?.remoteAddress;
91
- if (clientIp) {
92
- Reflect.set(request, clientAddressSymbol, clientIp);
93
- }
94
- return request;
95
140
  }
96
141
  async function writeResponse(source, destination) {
97
142
  const { status, headers, body, statusText } = source;
@@ -147,18 +192,15 @@ class NodeApp extends App {
147
192
  }
148
193
  match(req, allowPrerenderedRoutes = false) {
149
194
  if (!(req instanceof Request)) {
150
- req = createRequest(req, {
151
- skipBody: true,
152
- allowedDomains: this.manifest.allowedDomains
195
+ req = createRequestFromNodeRequest(req, {
196
+ skipBody: true
153
197
  });
154
198
  }
155
199
  return super.match(req, allowPrerenderedRoutes);
156
200
  }
157
201
  render(request, options) {
158
202
  if (!(request instanceof Request)) {
159
- request = createRequest(request, {
160
- allowedDomains: this.manifest.allowedDomains
161
- });
203
+ request = createRequestFromNodeRequest(request);
162
204
  }
163
205
  return super.render(request, options);
164
206
  }
@@ -283,6 +325,7 @@ async function loadApp(rootFolder) {
283
325
  export {
284
326
  NodeApp,
285
327
  createRequest,
328
+ createRequestFromNodeRequest,
286
329
  getAbortControllerCleanup,
287
330
  loadApp,
288
331
  loadManifest,
@@ -10,10 +10,9 @@ import { emptyDir, removeEmptyDirs } from "../../core/fs/index.js";
10
10
  import { appendForwardSlash, prependForwardSlash } from "../../core/path.js";
11
11
  import { runHookBuildSetup } from "../../integrations/hooks.js";
12
12
  import { SERIALIZED_MANIFEST_RESOLVED_ID } from "../../manifest/serialized.js";
13
- import { getPrerenderOutputDirectory } from "../../prerender/utils.js";
13
+ import { getPrerenderOutputDirectory, getServerOutputDirectory } from "../../prerender/utils.js";
14
14
  import { PAGE_SCRIPT_ID } from "../../vite-plugin-scripts/index.js";
15
15
  import { routeIsRedirect } from "../routing/helpers.js";
16
- import { getOutDirWithinCwd } from "./common.js";
17
16
  import { generatePages } from "./generate.js";
18
17
  import { trackPageData } from "./internal.js";
19
18
  import { getAllBuildPlugins } from "./plugins/index.js";
@@ -23,7 +22,10 @@ import { getTimeStat, viteBuildReturnToRollupOutputs } from "./util.js";
23
22
  import { NOOP_MODULE_ID } from "./plugins/plugin-noop.js";
24
23
  import { ASTRO_VITE_ENVIRONMENT_NAMES } from "../constants.js";
25
24
  import { getSSRAssets } from "./internal.js";
26
- import { SERVER_ISLAND_MAP_MARKER } from "../server-islands/vite-plugin-server-islands.js";
25
+ import {
26
+ SERVER_ISLAND_MAP_MARKER,
27
+ hasServerIslands
28
+ } from "../server-islands/vite-plugin-server-islands.js";
27
29
  import { createViteBuildConfig } from "./vite-build-config.js";
28
30
  const PRERENDER_ENTRY_FILENAME_PREFIX = "prerender-entry";
29
31
  function extractRelevantChunks(outputs, prerender) {
@@ -155,7 +157,7 @@ async function buildEnvironments(opts, internals) {
155
157
  const prerenderChunks = extractRelevantChunks(prerenderOutputs, true);
156
158
  prerenderOutput = void 0;
157
159
  let ssrChunks = [];
158
- if (settings.buildOutput !== "static") {
160
+ if (needsServerBuild(settings, builder2)) {
159
161
  settings.timer.start("SSR build");
160
162
  let ssrOutput = await builder2.build(
161
163
  builder2.environments[ASTRO_VITE_ENVIRONMENT_NAMES.ssr]
@@ -231,15 +233,12 @@ async function runManifestInjection(opts, internals, chunks, buildPostHooks) {
231
233
  }
232
234
  async function writeMutatedChunks(opts, mutations) {
233
235
  const { settings } = opts;
234
- const config = settings.config;
235
236
  for (const [fileName, mutation] of mutations) {
236
237
  let root;
237
238
  if (mutation.prerender) {
238
239
  root = getPrerenderOutputDirectory(settings);
239
- } else if (settings.buildOutput === "server") {
240
- root = config.build.server;
241
240
  } else {
242
- root = getOutDirWithinCwd(config.outDir);
241
+ root = getServerOutputDirectory(settings);
243
242
  }
244
243
  const fullPath = path.join(fileURLToPath(root), fileName);
245
244
  const fileURL = pathToFileURL(fullPath);
@@ -297,6 +296,12 @@ function getClientInput(internals, settings) {
297
296
  }
298
297
  return clientInput;
299
298
  }
299
+ function needsServerBuild(settings, builder) {
300
+ if (settings.buildOutput === "server") {
301
+ return true;
302
+ }
303
+ return hasServerIslands(builder.environments.prerender);
304
+ }
300
305
  function makeAstroPageEntryPointFileName(prefix, facadeModuleId, routes) {
301
306
  const pageModuleId = facadeModuleId.replace(prefix, "").replace(ASTRO_PAGE_EXTENSION_POST_PATTERN, ".");
302
307
  const route = routes.find((routeData) => routeData.component === pageModuleId);
@@ -38,6 +38,10 @@ function mergeConfigRecursively(defaults, overrides, rootPath) {
38
38
  merged[key] = value;
39
39
  continue;
40
40
  }
41
+ if (key === "processor" && rootPath === "markdown" && isObject(value) && typeof value.createRenderer === "function") {
42
+ merged[key] = value;
43
+ continue;
44
+ }
41
45
  if (isObject(existing) && isObject(value)) {
42
46
  merged[key] = mergeConfigRecursively(existing, value, rootPath ? `${rootPath}.${key}` : key);
43
47
  continue;
@@ -1,4 +1,4 @@
1
- import type { RehypePlugin as _RehypePlugin, RemarkPlugin as _RemarkPlugin, RemarkRehype as _RemarkRehype, Smartypants as _Smartypants, ShikiConfig } from '@astrojs/markdown-remark';
1
+ import type { RehypePlugin as _RehypePlugin, RemarkPlugin as _RemarkPlugin, RemarkRehype as _RemarkRehype, Smartypants as _Smartypants, ShikiConfig } from '@astrojs/internal-helpers/markdown';
2
2
  import type { OutgoingHttpHeaders } from 'node:http';
3
3
  import * as z from 'zod/v4';
4
4
  import type { ViteUserConfig } from '../../../types/public/config.js';
@@ -57,7 +57,7 @@ export declare const ASTRO_CONFIG_DEFAULTS: {
57
57
  allowedHosts: never[];
58
58
  };
59
59
  integrations: never[];
60
- markdown: Required<import("@astrojs/markdown-remark").AstroMarkdownOptions>;
60
+ markdown: Required<Omit<import("@astrojs/markdown-remark").AstroMarkdownOptions, "image">>;
61
61
  vite: {};
62
62
  legacy: {
63
63
  collectionsBackwardsCompat: false;
@@ -121,8 +121,8 @@ export declare const AstroConfigSchema: z.ZodObject<{
121
121
  redirects: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
122
122
  inlineStylesheets: z.ZodDefault<z.ZodOptional<z.ZodEnum<{
123
123
  never: "never";
124
- auto: "auto";
125
124
  always: "always";
125
+ auto: "auto";
126
126
  }>>>;
127
127
  concurrency: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
128
128
  }, z.core.$strip>>;
@@ -140,10 +140,10 @@ export declare const AstroConfigSchema: z.ZodObject<{
140
140
  prefetch: z.ZodOptional<z.ZodUnion<readonly [z.ZodBoolean, z.ZodObject<{
141
141
  prefetchAll: z.ZodOptional<z.ZodBoolean>;
142
142
  defaultStrategy: z.ZodOptional<z.ZodEnum<{
143
- load: "load";
144
143
  tap: "tap";
145
144
  hover: "hover";
146
145
  viewport: "viewport";
146
+ load: "load";
147
147
  }>>;
148
148
  }, z.core.$strip>]>>;
149
149
  image: z.ZodPrefault<z.ZodObject<{
@@ -165,9 +165,9 @@ export declare const AstroConfigSchema: z.ZodObject<{
165
165
  }, z.core.$strip>>>;
166
166
  layout: z.ZodOptional<z.ZodEnum<{
167
167
  fixed: "fixed";
168
- none: "none";
169
168
  constrained: "constrained";
170
169
  "full-width": "full-width";
170
+ none: "none";
171
171
  }>>;
172
172
  objectFit: z.ZodOptional<z.ZodString>;
173
173
  objectPosition: z.ZodOptional<z.ZodString>;
@@ -331,8 +331,14 @@ export declare const AstroConfigSchema: z.ZodObject<{
331
331
  remarkPlugins: z.ZodDefault<z.ZodArray<z.ZodUnion<readonly [z.ZodString, z.ZodTuple<[z.ZodString, z.ZodAny], null>, z.ZodCustom<RemarkPlugin, RemarkPlugin>, z.ZodTuple<[z.ZodCustom<RemarkPlugin, RemarkPlugin>, z.ZodAny], null>]>>>;
332
332
  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>]>>>;
333
333
  remarkRehype: z.ZodDefault<z.ZodCustom<RemarkRehype, RemarkRehype>>;
334
- gfm: z.ZodDefault<z.ZodBoolean>;
335
- 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>>>;
334
+ gfm: z.ZodOptional<z.ZodBoolean>;
335
+ smartypants: z.ZodOptional<z.ZodPipe<z.ZodUnion<readonly [z.ZodBoolean, z.ZodType<Smartypants, unknown, z.core.$ZodTypeInternals<Smartypants, unknown>>]>, z.ZodTransform<false | Smartypants, boolean | Smartypants>>>;
336
+ processor: z.ZodDefault<z.ZodObject<{
337
+ name: z.ZodString;
338
+ options: z.ZodDefault<z.ZodCustom<object, object>>;
339
+ createRenderer: z.ZodCustom<(shared: import("@astrojs/markdown-remark").AstroMarkdownOptions) => Promise<import("@astrojs/markdown-remark").MarkdownRenderer>, (shared: import("@astrojs/markdown-remark").AstroMarkdownOptions) => Promise<import("@astrojs/markdown-remark").MarkdownRenderer>>;
340
+ createMdxRenderer: z.ZodOptional<z.ZodCustom<((shared: import("@astrojs/markdown-remark").AstroMarkdownOptions, mdx: import("@astrojs/internal-helpers/markdown").MdxRendererOptions) => Promise<import("@astrojs/internal-helpers/markdown").MdxRenderer>) | undefined, ((shared: import("@astrojs/markdown-remark").AstroMarkdownOptions, mdx: import("@astrojs/internal-helpers/markdown").MdxRendererOptions) => Promise<import("@astrojs/internal-helpers/markdown").MdxRenderer>) | undefined>>;
341
+ }, z.core.$strip>>;
336
342
  }, z.core.$strip>>;
337
343
  vite: z.ZodDefault<z.ZodCustom<ViteUserConfig, ViteUserConfig>>;
338
344
  i18n: z.ZodOptional<z.ZodOptional<z.ZodObject<{
@@ -442,9 +448,9 @@ export declare const AstroConfigSchema: z.ZodObject<{
442
448
  path: z.ZodOptional<z.ZodString>;
443
449
  maxAge: z.ZodOptional<z.ZodNumber>;
444
450
  sameSite: z.ZodOptional<z.ZodUnion<readonly [z.ZodEnum<{
451
+ none: "none";
445
452
  strict: "strict";
446
453
  lax: "lax";
447
- none: "none";
448
454
  }>, z.ZodBoolean]>>;
449
455
  secure: z.ZodOptional<z.ZodBoolean>;
450
456
  }, z.core.$strip>, z.ZodPipe<z.ZodString, z.ZodTransform<{
@@ -488,11 +494,11 @@ export declare const AstroConfigSchema: z.ZodObject<{
488
494
  fallbacks: z.ZodOptional<z.ZodArray<z.ZodString>>;
489
495
  optimizedFallbacks: z.ZodOptional<z.ZodBoolean>;
490
496
  display: z.ZodOptional<z.ZodEnum<{
491
- optional: "optional";
492
497
  auto: "auto";
498
+ optional: "optional";
499
+ fallback: "fallback";
493
500
  block: "block";
494
501
  swap: "swap";
495
- fallback: "fallback";
496
502
  }>>;
497
503
  stretch: z.ZodOptional<z.ZodString>;
498
504
  featureSettings: z.ZodOptional<z.ZodString>;
@@ -1,4 +1,8 @@
1
- import { markdownConfigDefaults, syntaxHighlightDefaults } from "@astrojs/markdown-remark";
1
+ import {
2
+ markdownConfigDefaults,
3
+ syntaxHighlightDefaults
4
+ } from "@astrojs/internal-helpers/markdown";
5
+ import { unified } from "@astrojs/markdown-remark";
2
6
  import { bundledThemes } from "shiki";
3
7
  import * as z from "zod/v4";
4
8
  import { FontFamilySchema } from "../../../assets/fonts/config.js";
@@ -239,11 +243,27 @@ const AstroConfigSchema = z.object({
239
243
  z.tuple([z.custom((data) => typeof data === "function"), z.any()])
240
244
  ]).array().default(ASTRO_CONFIG_DEFAULTS.markdown.rehypePlugins),
241
245
  remarkRehype: z.custom((data) => data instanceof Object && !Array.isArray(data)).default(ASTRO_CONFIG_DEFAULTS.markdown.remarkRehype),
242
- gfm: z.boolean().default(ASTRO_CONFIG_DEFAULTS.markdown.gfm),
246
+ // Deprecated: left undefined unless the user explicitly sets them, so the
247
+ // deprecation warning only fires when actually used. The active processor
248
+ // (`unified()`) supplies the real default (`gfm`/smart punctuation on) when
249
+ // these are absent.
250
+ gfm: z.boolean().optional(),
243
251
  smartypants: z.union([z.boolean(), smartypantsOptionsSchema]).transform((val) => {
244
252
  if (val === true) return smartypantsOptionsSchema.parse({});
245
253
  return val;
246
- }).prefault(ASTRO_CONFIG_DEFAULTS.markdown.smartypants)
254
+ }).optional(),
255
+ processor: z.object({
256
+ name: z.string(),
257
+ // `z.custom` preserves reference identity; `z.record` would clone, breaking
258
+ // the closure inside `createRenderer` that reads `processor.options.*`.
259
+ options: z.custom((v) => typeof v === "object" && v !== null && !Array.isArray(v)).default(() => ({})),
260
+ createRenderer: z.custom(
261
+ (v) => typeof v === "function"
262
+ ),
263
+ createMdxRenderer: z.custom(
264
+ (v) => v === void 0 || typeof v === "function"
265
+ ).optional()
266
+ }).default(() => unified())
247
267
  }).prefault({}),
248
268
  vite: z.custom((data) => data instanceof Object && !Array.isArray(data)).default(ASTRO_CONFIG_DEFAULTS.vite),
249
269
  i18n: z.optional(