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
package/client.d.ts CHANGED
@@ -30,36 +30,36 @@ interface ImportMeta {
30
30
  }
31
31
 
32
32
  declare module 'astro:assets' {
33
- // Exporting things one by one is a bit cumbersome, not sure if there's a better way - erika, 2023-02-03
34
- type AstroAssets = {
35
- // getImage's type here is different from the internal function since the Vite module implicitly pass the service config
36
- /**
37
- * Get an optimized image and the necessary attributes to render it.
38
- *
39
- * **Example**
40
- * ```astro
41
- * ---
42
- * import { getImage } from 'astro:assets';
43
- * import originalImage from '../assets/image.png';
44
- *
45
- * const optimizedImage = await getImage({src: originalImage, width: 1280 });
46
- * ---
47
- * <img src={optimizedImage.src} {...optimizedImage.attributes} />
48
- * ```
49
- *
50
- * This is functionally equivalent to using the `<Image />` component, as the component calls this function internally.
51
- */
52
- getImage: (
53
- options: import('./dist/assets/types.js').UnresolvedImageTransform,
54
- ) => Promise<import('./dist/assets/types.js').GetImageResult>;
55
- imageConfig: import('./dist/types/public/config.js').AstroConfig['image'];
56
- getConfiguredImageService: typeof import('./dist/assets/index.js').getConfiguredImageService;
57
- inferRemoteSize: typeof import('./dist/assets/utils/index.js').inferRemoteSize;
58
- Image: typeof import('./components/Image.astro').default;
59
- Picture: typeof import('./components/Picture.astro').default;
60
- Font: typeof import('./components/Font.astro').default;
61
- fontData: Record<import('astro:assets').CssVariable, Array<import('astro:assets').FontData>>;
62
- };
33
+ // getImage's type here is different from the internal function since the Vite module implicitly pass the service config
34
+ /**
35
+ * Get an optimized image and the necessary attributes to render it.
36
+ *
37
+ * **Example**
38
+ * ```astro
39
+ * ---
40
+ * import { getImage } from 'astro:assets';
41
+ * import originalImage from '../assets/image.png';
42
+ *
43
+ * const optimizedImage = await getImage({src: originalImage, width: 1280 });
44
+ * ---
45
+ * <img src={optimizedImage.src} {...optimizedImage.attributes} />
46
+ * ```
47
+ *
48
+ * This is functionally equivalent to using the `<Image />` component, as the component calls this function internally.
49
+ */
50
+ export const getImage: (
51
+ options: import('./dist/assets/types.js').UnresolvedImageTransform,
52
+ ) => Promise<import('./dist/assets/types.js').GetImageResult>;
53
+ export const imageConfig: import('./dist/types/public/config.js').AstroConfig['image'];
54
+ export const getConfiguredImageService: typeof import('./dist/assets/index.js').getConfiguredImageService;
55
+ export const inferRemoteSize: typeof import('./dist/assets/utils/index.js').inferRemoteSize;
56
+ export const Image: typeof import('./components/Image.astro').default;
57
+ export const Picture: typeof import('./components/Picture.astro').default;
58
+ export const Font: typeof import('./components/Font.astro').default;
59
+ export const fontData: Record<
60
+ import('astro:assets').CssVariable,
61
+ Array<import('astro:assets').FontData>
62
+ >;
63
63
 
64
64
  type ImgAttributes = import('./dist/type-utils.js').WithRequired<
65
65
  Omit<import('./types').HTMLAttributes<'img'>, 'src' | 'width' | 'height'>,
@@ -72,16 +72,6 @@ declare module 'astro:assets' {
72
72
  export type RemoteImageProps = import('./dist/type-utils.js').Simplify<
73
73
  import('./dist/assets/types.js').RemoteImageProps<ImgAttributes>
74
74
  >;
75
- export const {
76
- getImage,
77
- getConfiguredImageService,
78
- imageConfig,
79
- Image,
80
- Picture,
81
- Font,
82
- inferRemoteSize,
83
- fontData,
84
- }: AstroAssets;
85
75
  }
86
76
 
87
77
  declare module 'virtual:astro:image-styles.css' {
@@ -95,12 +95,11 @@ async function generateImagesForPath(originalFilePath, transformsAndPath, env) {
95
95
  };
96
96
  } else {
97
97
  const JSONData = JSON.parse(readFileSync(cachedMetaFileURL, "utf-8"));
98
- if (!JSONData.expires) {
99
- try {
100
- await fs.promises.unlink(cachedFileURL);
101
- } catch {
102
- }
103
- await fs.promises.unlink(cachedMetaFileURL);
98
+ if (typeof JSONData.expires !== "number") {
99
+ await Promise.allSettled([
100
+ fs.promises.unlink(cachedFileURL),
101
+ fs.promises.unlink(cachedMetaFileURL)
102
+ ]);
104
103
  throw new Error(
105
104
  `Malformed cache entry for ${filepath}, cache will be regenerated for this file.`
106
105
  );
@@ -114,9 +113,7 @@ async function generateImagesForPath(originalFilePath, transformsAndPath, env) {
114
113
  }
115
114
  if (JSONData.expires > Date.now()) {
116
115
  await fs.promises.copyFile(cachedFileURL, finalFileURL, fs.constants.COPYFILE_FICLONE);
117
- return {
118
- cached: "hit"
119
- };
116
+ return { cached: "hit" };
120
117
  }
121
118
  if (JSONData.etag || JSONData.lastModified) {
122
119
  try {
@@ -124,15 +121,13 @@ async function generateImagesForPath(originalFilePath, transformsAndPath, env) {
124
121
  etag: JSONData.etag,
125
122
  lastModified: JSONData.lastModified
126
123
  });
127
- if (revalidatedData.data.length) {
124
+ if (revalidatedData.data !== null) {
128
125
  originalImage = revalidatedData;
129
126
  } else {
130
- await writeCacheMetaFile(cachedMetaFileURL, revalidatedData, env);
131
- await fs.promises.copyFile(
132
- cachedFileURL,
133
- finalFileURL,
134
- fs.constants.COPYFILE_FICLONE
135
- );
127
+ await Promise.all([
128
+ writeCacheMetaFile(cachedMetaFileURL, revalidatedData, env),
129
+ fs.promises.copyFile(cachedFileURL, finalFileURL, fs.constants.COPYFILE_FICLONE)
130
+ ]);
136
131
  return { cached: "revalidated" };
137
132
  }
138
133
  } catch (e) {
@@ -144,8 +139,10 @@ async function generateImagesForPath(originalFilePath, transformsAndPath, env) {
144
139
  return { cached: "hit" };
145
140
  }
146
141
  }
147
- await fs.promises.unlink(cachedFileURL);
148
- await fs.promises.unlink(cachedMetaFileURL);
142
+ await Promise.allSettled([
143
+ fs.promises.unlink(cachedFileURL),
144
+ fs.promises.unlink(cachedMetaFileURL)
145
+ ]);
149
146
  }
150
147
  } catch (e) {
151
148
  if (e.code !== "ENOENT") {
@@ -219,7 +216,8 @@ async function writeCacheMetaFile(cachedMetaFileURL, resultData, env) {
219
216
  expires: resultData.expires,
220
217
  etag: resultData.etag,
221
218
  lastModified: resultData.lastModified
222
- })
219
+ }),
220
+ "utf-8"
223
221
  );
224
222
  } catch (e) {
225
223
  env.logger.warn(
@@ -4,7 +4,7 @@ export type RemoteCacheEntry = {
4
4
  etag?: string;
5
5
  lastModified?: string;
6
6
  };
7
- export declare function loadRemoteImage(src: string): Promise<{
7
+ export declare function loadRemoteImage(src: string, fetchFn?: typeof fetch): Promise<{
8
8
  data: Buffer<ArrayBuffer>;
9
9
  expires: number;
10
10
  etag: string | undefined;
@@ -17,13 +17,13 @@ export declare function loadRemoteImage(src: string): Promise<{
17
17
  * The remote server may respond that the cached asset is still up-to-date if the entity-tag or modification time matches (304 Not Modified), or respond with an updated asset (200 OK)
18
18
  * @param src - url to remote asset
19
19
  * @param revalidationData - an object containing the stored Entity-Tag of the cached asset and/or the Last Modified time
20
- * @returns An ImageData object containing the asset data, a new expiry time, and the asset's etag. The data buffer will be empty if the asset was not modified.
20
+ * @returns An object containing the refreshed expiry time and cache headers. `data` will be a `Buffer` of the new image if the asset was modified (200 OK), or `null` if the cached version is still valid (304 Not Modified).
21
21
  */
22
22
  export declare function revalidateRemoteImage(src: string, revalidationData: {
23
23
  etag?: string;
24
24
  lastModified?: string;
25
- }): Promise<{
26
- data: Buffer<ArrayBuffer>;
25
+ }, fetchFn?: typeof fetch): Promise<{
26
+ data: Buffer<ArrayBuffer> | null;
27
27
  expires: number;
28
28
  etag: string | undefined;
29
29
  lastModified: string | undefined;
@@ -1,7 +1,7 @@
1
1
  import CachePolicy from "http-cache-semantics";
2
- async function loadRemoteImage(src) {
2
+ async function loadRemoteImage(src, fetchFn = globalThis.fetch) {
3
3
  const req = new Request(src);
4
- const res = await fetch(req, { redirect: "manual" });
4
+ const res = await fetchFn(req, { redirect: "manual" });
5
5
  if (res.status >= 300 && res.status < 400) {
6
6
  throw new Error(`Failed to load remote image ${src}. The request was redirected.`);
7
7
  }
@@ -19,35 +19,37 @@ async function loadRemoteImage(src) {
19
19
  lastModified: res.headers.get("Last-Modified") ?? void 0
20
20
  };
21
21
  }
22
- async function revalidateRemoteImage(src, revalidationData) {
22
+ async function revalidateRemoteImage(src, revalidationData, fetchFn = globalThis.fetch) {
23
23
  const headers = {
24
24
  ...revalidationData.etag && { "If-None-Match": revalidationData.etag },
25
25
  ...revalidationData.lastModified && { "If-Modified-Since": revalidationData.lastModified }
26
26
  };
27
27
  const req = new Request(src, { headers, cache: "no-cache" });
28
- const res = await fetch(req, { redirect: "manual" });
29
- if (res.status >= 300 && res.status < 400) {
30
- throw new Error(`Failed to revalidate cached remote image ${src}. The request was redirected.`);
31
- }
28
+ const res = await fetchFn(req, { redirect: "manual" });
32
29
  if (!res.ok && res.status !== 304) {
30
+ if (res.status >= 300 && res.status < 400) {
31
+ throw new Error(
32
+ `Failed to revalidate cached remote image ${src}. The request was redirected.`
33
+ );
34
+ }
33
35
  throw new Error(
34
36
  `Failed to revalidate cached remote image ${src}. The request did not return a 200 OK / 304 NOT MODIFIED response. (received ${res.status} ${res.statusText})`
35
37
  );
36
38
  }
37
39
  const data = Buffer.from(await res.arrayBuffer());
38
40
  if (res.ok && !data.length) {
39
- return await loadRemoteImage(src);
41
+ return await loadRemoteImage(src, fetchFn);
40
42
  }
41
43
  const policy = new CachePolicy(
42
44
  webToCachePolicyRequest(req),
43
45
  webToCachePolicyResponse(
44
46
  res.ok ? res : new Response(null, { status: 200, headers: res.headers })
45
47
  )
46
- // 304 responses themselves are not cacheable, so just pretend to get the refreshed TTL
48
+ // 304 responses are not cacheable, so just use its headers to get the refreshed TTL
47
49
  );
48
50
  const expires = policy.storable() ? policy.timeToLive() : 0;
49
51
  return {
50
- data,
52
+ data: res.ok ? data : null,
51
53
  expires: Date.now() + expires,
52
54
  // While servers should respond with the same headers as a 200 response, if they don't we should reuse the stored value
53
55
  etag: res.headers.get("Etag") ?? (res.ok ? void 0 : revalidationData.etag),
@@ -17,6 +17,9 @@ class DevFontFileIdGenerator {
17
17
  }
18
18
  return weight?.replace(/\s+/g, "-");
19
19
  }
20
+ #formatStyle(style) {
21
+ return style?.replace(/\s+/g, "-");
22
+ }
20
23
  generate({
21
24
  cssVariable,
22
25
  originalUrl,
@@ -26,7 +29,7 @@ class DevFontFileIdGenerator {
26
29
  return [
27
30
  cssVariable.slice(2),
28
31
  this.#formatWeight(font.weight),
29
- font.style,
32
+ this.#formatStyle(font.style),
30
33
  font.meta?.subset,
31
34
  `${this.#hasher.hashString(this.#contentResolver.resolve(originalUrl))}.${type}`
32
35
  ].filter(Boolean).join("-");
@@ -51,6 +51,7 @@ function fontsPlugin({ settings, sync, logger }) {
51
51
  let isBuild;
52
52
  let fontFetcher = null;
53
53
  let fontTypeExtractor = null;
54
+ let built = false;
54
55
  const cleanup = () => {
55
56
  componentDataByCssVariable = null;
56
57
  fontDataByCssVariable = null;
@@ -63,6 +64,9 @@ function fontsPlugin({ settings, sync, logger }) {
63
64
  isBuild = command === "build";
64
65
  },
65
66
  async buildStart() {
67
+ if (sync) {
68
+ return;
69
+ }
66
70
  const { root } = settings.config;
67
71
  const hasher = await XxhashHasher.create();
68
72
  const storage = new UnstorageFsStorage({
@@ -252,6 +256,9 @@ function fontsPlugin({ settings, sync, logger }) {
252
256
  }
253
257
  },
254
258
  async buildEnd() {
259
+ if (built) {
260
+ return;
261
+ }
255
262
  if (sync || !settings.config.fonts?.length || !isBuild) {
256
263
  cleanup();
257
264
  return;
@@ -282,6 +289,7 @@ function fontsPlugin({ settings, sync, logger }) {
282
289
  }
283
290
  } finally {
284
291
  cleanup();
292
+ built = true;
285
293
  }
286
294
  }
287
295
  };
@@ -1,5 +1,5 @@
1
- import type { ResizeOptions, SharpOptions } from 'sharp';
2
- import { type LocalImageService } from './service.js';
1
+ import type { AvifOptions, JpegOptions, PngOptions, ResizeOptions, SharpOptions, WebpOptions } from 'sharp';
2
+ import { type BaseServiceTransform, type LocalImageService } from './service.js';
3
3
  export interface SharpImageServiceConfig {
4
4
  /**
5
5
  * The `limitInputPixels` option passed to Sharp. See https://sharp.pixelplumbing.com/api-constructor for more information
@@ -9,6 +9,25 @@ export interface SharpImageServiceConfig {
9
9
  * The `kernel` option is passed to resize calls. See https://sharp.pixelplumbing.com/api-resize/ for more information
10
10
  */
11
11
  kernel?: ResizeOptions['kernel'];
12
+ /**
13
+ * The default encoder options passed to `sharp().jpeg()`.
14
+ */
15
+ jpeg?: JpegOptions;
16
+ /**
17
+ * The default encoder options passed to `sharp().png()`.
18
+ */
19
+ png?: PngOptions;
20
+ /**
21
+ * The default encoder options passed to `sharp().webp()`.
22
+ */
23
+ webp?: WebpOptions;
24
+ /**
25
+ * The default encoder options passed to `sharp().avif()`.
26
+ */
27
+ avif?: AvifOptions;
12
28
  }
29
+ export declare function resolveSharpEncoderOptions(transform: Pick<BaseServiceTransform, 'format' | 'quality'>, inputFormat: string | undefined, serviceConfig?: SharpImageServiceConfig): JpegOptions | PngOptions | WebpOptions | AvifOptions | {
30
+ quality?: number;
31
+ } | undefined;
13
32
  declare const sharpService: LocalImageService<SharpImageServiceConfig>;
14
33
  export default sharpService;
@@ -10,6 +10,47 @@ const qualityTable = {
10
10
  high: 80,
11
11
  max: 100
12
12
  };
13
+ function resolveSharpQuality(quality) {
14
+ if (!quality) return void 0;
15
+ const parsedQuality = parseQuality(quality);
16
+ if (typeof parsedQuality === "number") {
17
+ return parsedQuality;
18
+ }
19
+ return quality in qualityTable ? qualityTable[quality] : void 0;
20
+ }
21
+ function resolveSharpEncoderOptions(transform, inputFormat, serviceConfig = {}) {
22
+ const quality = resolveSharpQuality(transform.quality);
23
+ switch (transform.format) {
24
+ case "jpg":
25
+ case "jpeg":
26
+ return {
27
+ ...serviceConfig.jpeg,
28
+ ...quality === void 0 ? {} : { quality }
29
+ };
30
+ case "png":
31
+ return {
32
+ ...serviceConfig.png,
33
+ ...quality === void 0 ? {} : { quality }
34
+ };
35
+ case "webp": {
36
+ const webpOptions = {
37
+ ...serviceConfig.webp,
38
+ ...quality === void 0 ? {} : { quality }
39
+ };
40
+ if (inputFormat === "gif") {
41
+ webpOptions.loop ??= 0;
42
+ }
43
+ return webpOptions;
44
+ }
45
+ case "avif":
46
+ return {
47
+ ...serviceConfig.avif,
48
+ ...quality === void 0 ? {} : { quality }
49
+ };
50
+ default:
51
+ return quality === void 0 ? void 0 : { quality };
52
+ }
53
+ }
13
54
  async function loadSharp() {
14
55
  let sharpImport;
15
56
  try {
@@ -75,19 +116,19 @@ const sharpService = {
75
116
  result.flatten({ background: transform.background });
76
117
  }
77
118
  if (transform.format) {
78
- let quality = void 0;
79
- if (transform.quality) {
80
- const parsedQuality = parseQuality(transform.quality);
81
- if (typeof parsedQuality === "number") {
82
- quality = parsedQuality;
83
- } else {
84
- quality = transform.quality in qualityTable ? qualityTable[transform.quality] : void 0;
85
- }
86
- }
119
+ const encoderOptions = resolveSharpEncoderOptions(transform, format, config.service.config);
87
120
  if (transform.format === "webp" && format === "gif") {
88
- result.webp({ quality: typeof quality === "number" ? quality : void 0, loop: 0 });
121
+ result.webp(encoderOptions);
122
+ } else if (transform.format === "webp") {
123
+ result.webp(encoderOptions);
124
+ } else if (transform.format === "png") {
125
+ result.png(encoderOptions);
126
+ } else if (transform.format === "avif") {
127
+ result.avif(encoderOptions);
128
+ } else if (transform.format === "jpeg" || transform.format === "jpg") {
129
+ result.jpeg(encoderOptions);
89
130
  } else {
90
- result.toFormat(transform.format, { quality });
131
+ result.toFormat(transform.format, encoderOptions);
91
132
  }
92
133
  }
93
134
  const { data, info } = await result.toBuffer({ resolveWithObject: true });
@@ -100,5 +141,6 @@ const sharpService = {
100
141
  };
101
142
  var sharp_default = sharpService;
102
143
  export {
103
- sharp_default as default
144
+ sharp_default as default,
145
+ resolveSharpEncoderOptions
104
146
  };
@@ -122,7 +122,10 @@ function assets({ fs, settings, sync, logger }) {
122
122
  const getImageExport = isServerEnvironment ? `import { getImage as getImageInternal } from "astro/assets";
123
123
  export const getImage = async (options) => await getImageInternal(options, imageConfig);` : `import { AstroError, AstroErrorData } from "astro/errors";
124
124
  export const getImage = async () => {
125
- throw new AstroError(AstroErrorData.GetImageNotUsedOnServer);
125
+ throw new AstroError(
126
+ AstroErrorData.GetImageNotUsedOnServer.message,
127
+ AstroErrorData.GetImageNotUsedOnServer.hint,
128
+ );
126
129
  };`;
127
130
  return {
128
131
  code: `
@@ -207,6 +207,12 @@ async function add(names, { flags }) {
207
207
  logger,
208
208
  scripts: { "generate-types": "wrangler types" }
209
209
  });
210
+ await updatePackageJsonOverrides({
211
+ configURL,
212
+ flags,
213
+ logger,
214
+ overrides: { vite: "^7" }
215
+ });
210
216
  }
211
217
  if (integrations.find((integration) => integration.id === "tailwind")) {
212
218
  const dir = new URL("./styles/", new URL(userConfig.srcDir ?? "./src/", root));
@@ -601,6 +607,54 @@ async function updateAstroConfig({
601
607
  return 2 /* cancelled */;
602
608
  }
603
609
  }
610
+ async function updatePackageJsonOverrides({
611
+ configURL,
612
+ flags,
613
+ logger,
614
+ overrides
615
+ }) {
616
+ const pkgURL = new URL("./package.json", configURL);
617
+ if (!existsSync(pkgURL)) {
618
+ logger.debug("add", "No package.json found, skipping overrides update");
619
+ return 0 /* none */;
620
+ }
621
+ const pkgPath = fileURLToPath(pkgURL);
622
+ const input = await fs.readFile(pkgPath, { encoding: "utf-8" });
623
+ const pkgJson = JSON.parse(input);
624
+ pkgJson.overrides ??= {};
625
+ let hasChanges = false;
626
+ for (const [name, range] of Object.entries(overrides)) {
627
+ if (!(name in pkgJson.overrides)) {
628
+ pkgJson.overrides[name] = range;
629
+ hasChanges = true;
630
+ }
631
+ }
632
+ if (!hasChanges) {
633
+ return 0 /* none */;
634
+ }
635
+ const output = JSON.stringify(pkgJson, null, 2);
636
+ const diff = getDiffContent(input, output);
637
+ if (!diff) {
638
+ return 0 /* none */;
639
+ }
640
+ logger.info(
641
+ "SKIP_FORMAT",
642
+ `
643
+ ${magenta("Astro will add the following overrides to your package.json:")}`
644
+ );
645
+ clack.box(diff, "package.json", {
646
+ rounded: true,
647
+ withGuide: false,
648
+ width: "auto"
649
+ });
650
+ if (await askToContinue({ flags, logger })) {
651
+ await fs.writeFile(pkgPath, output, { encoding: "utf-8" });
652
+ logger.debug("add", "Updated package.json overrides");
653
+ return 1 /* updated */;
654
+ } else {
655
+ return 2 /* cancelled */;
656
+ }
657
+ }
604
658
  async function updatePackageJsonScripts({
605
659
  configURL,
606
660
  flags,
@@ -1,6 +1,6 @@
1
1
  class BuildTimeAstroVersionProvider {
2
2
  // Injected during the build through esbuild define
3
- version = "6.0.8";
3
+ version = "6.1.0";
4
4
  }
5
5
  export {
6
6
  BuildTimeAstroVersionProvider
@@ -192,7 +192,7 @@ ${contentConfig.error.message}`
192
192
  logger.info("Content config changed");
193
193
  shouldClear = true;
194
194
  }
195
- if (previousAstroVersion && previousAstroVersion !== "6.0.8") {
195
+ if (previousAstroVersion && previousAstroVersion !== "6.1.0") {
196
196
  logger.info("Astro version changed");
197
197
  shouldClear = true;
198
198
  }
@@ -200,8 +200,8 @@ ${contentConfig.error.message}`
200
200
  logger.info("Clearing content store");
201
201
  this.#store.clearAll();
202
202
  }
203
- if ("6.0.8") {
204
- this.#store.metaStore().set("astro-version", "6.0.8");
203
+ if ("6.1.0") {
204
+ this.#store.metaStore().set("astro-version", "6.1.0");
205
205
  }
206
206
  if (currentConfigDigest) {
207
207
  this.#store.metaStore().set("content-config-digest", currentConfigDigest);
@@ -1,6 +1,6 @@
1
1
  export { attachContentServerListeners } from './server-listeners.js';
2
2
  export { createContentTypesGenerator } from './types-generator.js';
3
- export { getContentPaths, hasAssetPropagationFlag } from './utils.js';
3
+ export { getContentPaths } from './utils.js';
4
4
  export { astroContentAssetPropagationPlugin } from './vite-plugin-content-assets.js';
5
5
  export { astroContentImportPlugin } from './vite-plugin-content-imports.js';
6
6
  export { astroContentVirtualModPlugin } from './vite-plugin-content-virtual-mod.js';
@@ -1,6 +1,6 @@
1
1
  import { attachContentServerListeners } from "./server-listeners.js";
2
2
  import { createContentTypesGenerator } from "./types-generator.js";
3
- import { getContentPaths, hasAssetPropagationFlag } from "./utils.js";
3
+ import { getContentPaths } from "./utils.js";
4
4
  import { astroContentAssetPropagationPlugin } from "./vite-plugin-content-assets.js";
5
5
  import { astroContentImportPlugin } from "./vite-plugin-content-imports.js";
6
6
  import { astroContentVirtualModPlugin } from "./vite-plugin-content-virtual-mod.js";
@@ -10,6 +10,5 @@ export {
10
10
  astroContentVirtualModPlugin,
11
11
  attachContentServerListeners,
12
12
  createContentTypesGenerator,
13
- getContentPaths,
14
- hasAssetPropagationFlag
13
+ getContentPaths
15
14
  };
@@ -1,6 +1,7 @@
1
1
  import type { MarkdownHeading } from '@astrojs/markdown-remark';
2
2
  import * as z from 'zod/v4';
3
3
  import type * as zCore from 'zod/v4/core';
4
+ import type { ImageMetadata } from '../assets/types.js';
4
5
  import { type AstroComponentFactory } from '../runtime/server/index.js';
5
6
  import type { LiveDataCollectionResult, LiveDataEntryResult } from '../types/public/content.js';
6
7
  import { type LIVE_CONTENT_TYPE } from './consts.js';
@@ -67,6 +68,7 @@ type RenderResult = {
67
68
  headings: MarkdownHeading[];
68
69
  remarkPluginFrontmatter: Record<string, any>;
69
70
  };
71
+ export declare function updateImageReferencesInData<T extends Record<string, unknown>>(data: T, fileName?: string, imageAssetMap?: Map<string, ImageMetadata>): T;
70
72
  export declare function renderEntry(entry: DataEntry): Promise<RenderResult>;
71
73
  export declare function createReference(): (collection: string) => z.ZodPipe<z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
72
74
  id: z.ZodString;
@@ -554,5 +554,6 @@ export {
554
554
  createReference,
555
555
  defineCollection,
556
556
  defineLiveCollection,
557
- renderEntry
557
+ renderEntry,
558
+ updateImageReferencesInData
558
559
  };
@@ -450,9 +450,13 @@ async function generateJSONSchema(fsMod, collectionConfig, collectionKey, collec
450
450
  zodSchemaForJson = z.object({}).catchall(zodSchemaForJson);
451
451
  }
452
452
  if (zodSchemaForJson instanceof z.ZodObject) {
453
+ const existingMeta = z.globalRegistry.get(zodSchemaForJson);
453
454
  zodSchemaForJson = zodSchemaForJson.extend({
454
455
  $schema: z.string().optional()
455
456
  });
457
+ if (existingMeta) {
458
+ z.globalRegistry.add(zodSchemaForJson, existingMeta);
459
+ }
456
460
  }
457
461
  try {
458
462
  const schema = z.toJSONSchema(zodSchemaForJson, {
@@ -187,7 +187,6 @@ export declare function getEntrySlug({ id, collection, generatedSlug, contentEnt
187
187
  fileUrl: URL;
188
188
  contentEntryType: Pick<ContentEntryType, 'getEntryInfo'>;
189
189
  }): Promise<string>;
190
- export declare function hasAssetPropagationFlag(id: string): boolean;
191
190
  /**
192
191
  * Unlike `path.posix.relative`, this function will accept a platform path and return a posix path.
193
192
  */
@@ -15,8 +15,7 @@ import {
15
15
  CONTENT_MODULE_FLAG,
16
16
  DEFERRED_MODULE,
17
17
  IMAGE_IMPORT_PREFIX,
18
- LIVE_CONTENT_TYPE,
19
- PROPAGATED_ASSET_FLAG
18
+ LIVE_CONTENT_TYPE
20
19
  } from "./consts.js";
21
20
  import { glob, secretLegacyFlag } from "./loaders/glob.js";
22
21
  import { createImage } from "./runtime-assets.js";
@@ -620,13 +619,6 @@ function globWithUnderscoresIgnored(relContentDir, exts) {
620
619
  `!${contentDir}**/_*${extGlob}`
621
620
  ];
622
621
  }
623
- function hasAssetPropagationFlag(id) {
624
- try {
625
- return new URL(id, "file://").searchParams.has(PROPAGATED_ASSET_FLAG);
626
- } catch {
627
- return false;
628
- }
629
- }
630
622
  function posixifyPath(filePath) {
631
623
  return filePath.split(path.sep).join("/");
632
624
  }
@@ -674,7 +666,6 @@ export {
674
666
  getEntryType,
675
667
  getSymlinkedContentCollections,
676
668
  globalContentConfigObserver,
677
- hasAssetPropagationFlag,
678
669
  hasContentFlag,
679
670
  isDeferredModule,
680
671
  loaderReturnSchema,
@@ -9,6 +9,11 @@ export declare class DevApp extends BaseApp<NonRunnablePipeline> {
9
9
  constructor(manifest: SSRManifest, streaming: boolean | undefined, logger: Logger);
10
10
  createPipeline(streaming: boolean, manifest: SSRManifest, logger: Logger): NonRunnablePipeline;
11
11
  isDev(): boolean;
12
+ /**
13
+ * Clears the cached middleware so it is re-resolved on the next request.
14
+ * Called via HMR when middleware files change.
15
+ */
16
+ clearMiddleware(): void;
12
17
  /**
13
18
  * Updates the routes list when files change during development.
14
19
  * Called via HMR when new pages are added/removed.