astro 7.0.0-beta.5 → 7.0.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.
@@ -1,6 +1,6 @@
1
1
  class BuildTimeAstroVersionProvider {
2
2
  // Injected during the build through esbuild define
3
- version = "7.0.0-beta.5";
3
+ version = "7.0.0";
4
4
  }
5
5
  export {
6
6
  BuildTimeAstroVersionProvider
@@ -197,7 +197,7 @@ ${contentConfig.error.message}`
197
197
  logger.info("Content config changed");
198
198
  shouldClear = true;
199
199
  }
200
- if (previousAstroVersion && previousAstroVersion !== "7.0.0-beta.5") {
200
+ if (previousAstroVersion && previousAstroVersion !== "7.0.0") {
201
201
  logger.info("Astro version changed");
202
202
  shouldClear = true;
203
203
  }
@@ -205,8 +205,8 @@ ${contentConfig.error.message}`
205
205
  logger.info("Clearing content store");
206
206
  this.#store.clearAll();
207
207
  }
208
- if ("7.0.0-beta.5") {
209
- this.#store.metaStore().set("astro-version", "7.0.0-beta.5");
208
+ if ("7.0.0") {
209
+ this.#store.metaStore().set("astro-version", "7.0.0");
210
210
  }
211
211
  if (currentConfigDigest) {
212
212
  this.#store.metaStore().set("content-config-digest", currentConfigDigest);
@@ -258,10 +258,7 @@ async function buildManifest(opts, internals, staticFiles, encodedKey) {
258
258
  allowedDomains: settings.config.security?.allowedDomains,
259
259
  key: encodedKey,
260
260
  sessionConfig: sessionConfigToManifest(settings.config.session),
261
- cacheConfig: cacheConfigToManifest(
262
- settings.config.experimental?.cache,
263
- settings.config.experimental?.routeRules
264
- ),
261
+ cacheConfig: cacheConfigToManifest(settings.config.cache, settings.config.routeRules),
265
262
  csp,
266
263
  image: {
267
264
  objectFit: settings.config.image.objectFit,
@@ -35,6 +35,12 @@ function createViteBuildConfig(opts) {
35
35
  ...viteConfig.build?.rolldownOptions,
36
36
  // Setting as `exports-only` allows us to safely delete inputs that are only used during prerendering
37
37
  preserveEntrySignatures: "exports-only",
38
+ checks: {
39
+ ...viteConfig.build?.rolldownOptions?.checks,
40
+ // Disable Rolldown's built-in plugin timing warnings. These fire by default
41
+ // and produce noisy warnings about slow plugins during normal builds.
42
+ pluginTimings: false
43
+ },
38
44
  ...legacyAdapter && settings.buildOutput === "server" ? { input: LEGACY_SSR_ENTRY_VIRTUAL_MODULE } : {},
39
45
  output: {
40
46
  hoistTransitiveImports: false,
@@ -1,7 +1,7 @@
1
1
  import * as z from 'zod/v4';
2
2
  /**
3
- * Cache provider configuration (experimental.cache).
4
- * Provider only - routes are configured via experimental.routeRules.
3
+ * Cache provider configuration (`cache`).
4
+ * Provider only - routes are configured via `routeRules`.
5
5
  */
6
6
  export declare const CacheSchema: z.ZodObject<{
7
7
  provider: z.ZodOptional<z.ZodObject<{
@@ -11,14 +11,15 @@ export declare const CacheSchema: z.ZodObject<{
11
11
  }, z.core.$strip>>;
12
12
  }, z.core.$strip>;
13
13
  /**
14
- * Route rules configuration (experimental.routeRules).
15
- * Maps glob patterns to route rules.
14
+ * Route rules configuration (`routeRules`).
15
+ * Maps route patterns to route rules. Patterns use the same `[param]` and
16
+ * `[...rest]` syntax as file-based routing; glob wildcards (`*`) are not supported.
16
17
  *
17
18
  * Example:
18
19
  * ```ts
19
20
  * routeRules: {
20
- * '/api/*': { swr: 600 },
21
- * '/products/*': { maxAge: 3600, tags: ['products'] },
21
+ * '/api/[...path]': { swr: 600 },
22
+ * '/products/[...slug]': { maxAge: 3600, tags: ['products'] },
22
23
  * }
23
24
  * ```
24
25
  */
@@ -62,7 +62,7 @@ class CacheHandler {
62
62
  },
63
63
  async () => {
64
64
  const res = await next();
65
- applyCacheHeaders(cache, res);
65
+ applyCacheHeaders(cache, res, state.request);
66
66
  return res;
67
67
  }
68
68
  );
@@ -71,7 +71,7 @@ class CacheHandler {
71
71
  return response2;
72
72
  }
73
73
  const response = await next();
74
- applyCacheHeaders(cache, response);
74
+ applyCacheHeaders(cache, response, state.request);
75
75
  return response;
76
76
  }
77
77
  }
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Shared utilities for CDN cache providers.
3
+ *
4
+ * These helpers are used by first-party adapter cache providers
5
+ * (@astrojs/netlify/cache, @astrojs/vercel/cache, @astrojs/cloudflare/cache)
6
+ * to implement common patterns like cache-control header generation,
7
+ * path-based invalidation via tags, and tag normalization.
8
+ */
9
+ import type { CacheOptions, InvalidateOptions } from './types.js';
10
+ /**
11
+ * Generate a cache tag for a given path.
12
+ * Used by Netlify and Vercel providers to support `invalidate({ path })`.
13
+ */
14
+ export declare function pathTag(path: string): string;
15
+ /**
16
+ * Build cache-control directives from CacheOptions.
17
+ * Returns the directive string (e.g. `"public, max-age=300, stale-while-revalidate=60"`)
18
+ * without the header name, so each provider can use its own header
19
+ * (`Netlify-CDN-Cache-Control`, `Vercel-CDN-Cache-Control`, `Cloudflare-CDN-Cache-Control`).
20
+ *
21
+ * Returns `undefined` if no caching directives are present.
22
+ */
23
+ export declare function buildCacheControlDirectives(options: CacheOptions, extraDirectives?: string[]): string | undefined;
24
+ /**
25
+ * Set common conditional headers (Last-Modified, ETag) on a Headers object.
26
+ */
27
+ export declare function setConditionalHeaders(headers: Headers, options: CacheOptions): void;
28
+ /**
29
+ * Normalize `InvalidateOptions.tags` to a flat string array.
30
+ */
31
+ export declare function normalizeTags(tags: string | string[] | undefined): string[];
32
+ /**
33
+ * Collect all tags needed to invalidate the given options,
34
+ * including the path tag if `options.path` is set.
35
+ * Used by providers that implement path invalidation via tags
36
+ * (Netlify, Vercel) rather than native path purge (Cloudflare).
37
+ */
38
+ export declare function collectInvalidationTags(options: InvalidateOptions): string[];
@@ -0,0 +1,43 @@
1
+ const PATH_TAG_PREFIX = "astro-path:";
2
+ function pathTag(path) {
3
+ return `${PATH_TAG_PREFIX}${path}`;
4
+ }
5
+ function buildCacheControlDirectives(options, extraDirectives) {
6
+ const directives = [];
7
+ if (extraDirectives) {
8
+ directives.push(...extraDirectives);
9
+ }
10
+ if (options.maxAge !== void 0) {
11
+ directives.push(`max-age=${options.maxAge}`);
12
+ }
13
+ if (options.swr !== void 0) {
14
+ directives.push(`stale-while-revalidate=${options.swr}`);
15
+ }
16
+ return directives.length > 0 ? directives.join(", ") : void 0;
17
+ }
18
+ function setConditionalHeaders(headers, options) {
19
+ if (options.lastModified) {
20
+ headers.set("Last-Modified", options.lastModified.toUTCString());
21
+ }
22
+ if (options.etag) {
23
+ headers.set("ETag", options.etag);
24
+ }
25
+ }
26
+ function normalizeTags(tags) {
27
+ if (!tags) return [];
28
+ return Array.isArray(tags) ? tags : [tags];
29
+ }
30
+ function collectInvalidationTags(options) {
31
+ const tags = normalizeTags(options.tags);
32
+ if (options.path) {
33
+ tags.push(pathTag(options.path));
34
+ }
35
+ return tags;
36
+ }
37
+ export {
38
+ buildCacheControlDirectives,
39
+ collectInvalidationTags,
40
+ normalizeTags,
41
+ pathTag,
42
+ setConditionalHeaders
43
+ };
@@ -35,7 +35,7 @@ export declare class AstroCache implements CacheLike {
35
35
  /**
36
36
  * Apply cache headers to a response.
37
37
  */
38
- export declare function applyCacheHeaders(cache: CacheLike, response: Response): void;
38
+ export declare function applyCacheHeaders(cache: CacheLike, response: Response, request: Request): void;
39
39
  /**
40
40
  * Check whether the cache has any active state worth acting on.
41
41
  */
@@ -67,11 +67,11 @@ class AstroCache {
67
67
  return this.#provider.invalidate(options);
68
68
  }
69
69
  /** @internal */
70
- [APPLY_HEADERS](response) {
70
+ [APPLY_HEADERS](response, request) {
71
71
  if (this.#disabled) return;
72
72
  const finalOptions = { ...this.#options, tags: this.tags };
73
73
  if (finalOptions.maxAge === void 0 && !finalOptions.tags?.length) return;
74
- const headers = this.#provider?.setHeaders?.(finalOptions) ?? defaultSetHeaders(finalOptions);
74
+ const headers = this.#provider?.setHeaders?.(finalOptions, request) ?? defaultSetHeaders(finalOptions);
75
75
  for (const [key, value] of headers) {
76
76
  response.headers.set(key, value);
77
77
  }
@@ -81,9 +81,9 @@ class AstroCache {
81
81
  return !this.#disabled && (this.#options.maxAge !== void 0 || this.#tags.size > 0);
82
82
  }
83
83
  }
84
- function applyCacheHeaders(cache, response) {
84
+ function applyCacheHeaders(cache, response, request) {
85
85
  if (APPLY_HEADERS in cache) {
86
- cache[APPLY_HEADERS](response);
86
+ cache[APPLY_HEADERS](response, request);
87
87
  }
88
88
  }
89
89
  function isCacheActive(cache) {
@@ -26,7 +26,7 @@ class DisabledAstroCache {
26
26
  hasWarned = true;
27
27
  this.#logger?.warn(
28
28
  "cache",
29
- "`cache.set()` was called but caching is not enabled. Configure a cache provider in your Astro config under `experimental.cache` to enable caching."
29
+ "`cache.set()` was called but caching is not enabled. Configure a cache provider in your Astro config under `cache` to enable caching."
30
30
  );
31
31
  }
32
32
  }
@@ -22,7 +22,7 @@ export interface InvalidateOptions {
22
22
  }
23
23
  export interface CacheProvider {
24
24
  name: string;
25
- setHeaders?(options: CacheOptions): Headers;
25
+ setHeaders?(options: CacheOptions, request: Request): Headers;
26
26
  onRequest?(context: {
27
27
  request: Request;
28
28
  url: URL;
@@ -10,7 +10,7 @@ export declare function normalizeRouteRuleCacheOptions(rule: {
10
10
  tags?: string[];
11
11
  } | undefined): CacheOptions | undefined;
12
12
  /**
13
- * Extract cache routes from experimental.routeRules config.
13
+ * Extract cache routes from the `routeRules` config.
14
14
  */
15
- export declare function extractCacheRoutesFromRouteRules(routeRules: AstroConfig['experimental']['routeRules']): Record<string, CacheOptions> | undefined;
16
- export declare function cacheConfigToManifest(cacheConfig: AstroConfig['experimental']['cache'], routeRulesConfig: AstroConfig['experimental']['routeRules']): SSRManifestCache | undefined;
15
+ export declare function extractCacheRoutesFromRouteRules(routeRules: AstroConfig['routeRules']): Record<string, CacheOptions> | undefined;
16
+ export declare function cacheConfigToManifest(cacheConfig: AstroConfig['cache'], routeRulesConfig: AstroConfig['routeRules']): SSRManifestCache | undefined;
@@ -7,7 +7,7 @@ const RESOLVED_VIRTUAL_CACHE_PROVIDER_ID = "\0" + VIRTUAL_CACHE_PROVIDER_ID;
7
7
  function vitePluginCacheProvider({
8
8
  settings
9
9
  }) {
10
- const providerConfig = settings.config.experimental?.cache?.provider;
10
+ const providerConfig = settings.config.cache?.provider;
11
11
  if (!providerConfig) {
12
12
  return;
13
13
  }
@@ -504,6 +504,18 @@ export declare const AstroConfigSchema: z.ZodObject<{
504
504
  unicodeRange: z.ZodOptional<z.ZodTuple<[z.ZodString], z.ZodString>>;
505
505
  options: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodAny>>;
506
506
  }, z.core.$strict>>>;
507
+ cache: z.ZodOptional<z.ZodObject<{
508
+ provider: z.ZodOptional<z.ZodObject<{
509
+ config: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodAny>>;
510
+ entrypoint: z.ZodUnion<readonly [z.ZodString, z.ZodCustom<URL, URL>]>;
511
+ name: z.ZodOptional<z.ZodString>;
512
+ }, z.core.$strip>>;
513
+ }, z.core.$strip>>;
514
+ routeRules: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
515
+ maxAge: z.ZodOptional<z.ZodNumber>;
516
+ swr: z.ZodOptional<z.ZodNumber>;
517
+ tags: z.ZodOptional<z.ZodArray<z.ZodString>>;
518
+ }, z.core.$strip>>>;
507
519
  experimental: z.ZodPrefault<z.ZodObject<{
508
520
  clientPrerender: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
509
521
  contentIntellisense: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
@@ -512,18 +524,6 @@ export declare const AstroConfigSchema: z.ZodObject<{
512
524
  name: z.ZodString;
513
525
  optimize: z.ZodCustom<(contents: string) => string | Promise<string>, (contents: string) => string | Promise<string>>;
514
526
  }, z.core.$strip>>;
515
- cache: z.ZodOptional<z.ZodObject<{
516
- provider: z.ZodOptional<z.ZodObject<{
517
- config: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodAny>>;
518
- entrypoint: z.ZodUnion<readonly [z.ZodString, z.ZodCustom<URL, URL>]>;
519
- name: z.ZodOptional<z.ZodString>;
520
- }, z.core.$strip>>;
521
- }, z.core.$strip>>;
522
- routeRules: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
523
- maxAge: z.ZodOptional<z.ZodNumber>;
524
- swr: z.ZodOptional<z.ZodNumber>;
525
- tags: z.ZodOptional<z.ZodArray<z.ZodString>>;
526
- }, z.core.$strip>>>;
527
527
  }, z.core.$strict>>;
528
528
  legacy: z.ZodPrefault<z.ZodObject<{
529
529
  collectionsBackwardsCompat: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
@@ -327,13 +327,13 @@ const AstroConfigSchema = z.object({
327
327
  config: z.record(z.string(), z.any()).optional()
328
328
  }).optional(),
329
329
  fonts: z.array(FontFamilySchema).optional(),
330
+ cache: CacheSchema.optional(),
331
+ routeRules: RouteRulesSchema.optional(),
330
332
  experimental: z.strictObject({
331
333
  clientPrerender: z.boolean().optional().default(ASTRO_CONFIG_DEFAULTS.experimental.clientPrerender),
332
334
  contentIntellisense: z.boolean().optional().default(ASTRO_CONFIG_DEFAULTS.experimental.contentIntellisense),
333
335
  chromeDevtoolsWorkspace: z.boolean().optional().default(ASTRO_CONFIG_DEFAULTS.experimental.chromeDevtoolsWorkspace),
334
- svgOptimizer: SvgOptimizerSchema.optional(),
335
- cache: CacheSchema.optional(),
336
- routeRules: RouteRulesSchema.optional()
336
+ svgOptimizer: SvgOptimizerSchema.optional()
337
337
  }).prefault({}),
338
338
  legacy: z.object({
339
339
  collectionsBackwardsCompat: z.boolean().optional().default(false)
@@ -392,6 +392,18 @@ export declare function createRelativeSchema(cmd: string, fileProtocolRoot: stri
392
392
  unicodeRange: z.ZodOptional<z.ZodTuple<[z.ZodString], z.ZodString>>;
393
393
  options: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodAny>>;
394
394
  }, z.core.$strict>>>;
395
+ cache: z.ZodOptional<z.ZodObject<{
396
+ provider: z.ZodOptional<z.ZodObject<{
397
+ config: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodAny>>;
398
+ entrypoint: z.ZodUnion<readonly [z.ZodString, z.ZodCustom<URL, URL>]>;
399
+ name: z.ZodOptional<z.ZodString>;
400
+ }, z.core.$strip>>;
401
+ }, z.core.$strip>>;
402
+ routeRules: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
403
+ maxAge: z.ZodOptional<z.ZodNumber>;
404
+ swr: z.ZodOptional<z.ZodNumber>;
405
+ tags: z.ZodOptional<z.ZodArray<z.ZodString>>;
406
+ }, z.core.$strip>>>;
395
407
  experimental: z.ZodPrefault<z.ZodObject<{
396
408
  clientPrerender: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
397
409
  contentIntellisense: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
@@ -400,18 +412,6 @@ export declare function createRelativeSchema(cmd: string, fileProtocolRoot: stri
400
412
  name: z.ZodString;
401
413
  optimize: z.ZodCustom<(contents: string) => string | Promise<string>, (contents: string) => string | Promise<string>>;
402
414
  }, z.core.$strip>>;
403
- cache: z.ZodOptional<z.ZodObject<{
404
- provider: z.ZodOptional<z.ZodObject<{
405
- config: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodAny>>;
406
- entrypoint: z.ZodUnion<readonly [z.ZodString, z.ZodCustom<URL, URL>]>;
407
- name: z.ZodOptional<z.ZodString>;
408
- }, z.core.$strip>>;
409
- }, z.core.$strip>>;
410
- routeRules: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
411
- maxAge: z.ZodOptional<z.ZodNumber>;
412
- swr: z.ZodOptional<z.ZodNumber>;
413
- tags: z.ZodOptional<z.ZodArray<z.ZodString>>;
414
- }, z.core.$strip>>>;
415
415
  }, z.core.$strict>>;
416
416
  legacy: z.ZodPrefault<z.ZodObject<{
417
417
  collectionsBackwardsCompat: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
@@ -590,18 +590,6 @@ export declare function createRelativeSchema(cmd: string, fileProtocolRoot: stri
590
590
  name: string;
591
591
  optimize: (contents: string) => string | Promise<string>;
592
592
  } | undefined;
593
- cache?: {
594
- provider?: {
595
- entrypoint: string | URL;
596
- config?: Record<string, any> | undefined;
597
- name?: string | undefined;
598
- } | undefined;
599
- } | undefined;
600
- routeRules?: Record<string, {
601
- maxAge?: number | undefined;
602
- swr?: number | undefined;
603
- tags?: string[] | undefined;
604
- }> | undefined;
605
593
  };
606
594
  legacy: {
607
595
  collectionsBackwardsCompat: boolean;
@@ -696,6 +684,18 @@ export declare function createRelativeSchema(cmd: string, fileProtocolRoot: stri
696
684
  unicodeRange?: [string, ...string[]] | undefined;
697
685
  options?: Record<string, any> | undefined;
698
686
  }[] | undefined;
687
+ cache?: {
688
+ provider?: {
689
+ entrypoint: string | URL;
690
+ config?: Record<string, any> | undefined;
691
+ name?: string | undefined;
692
+ } | undefined;
693
+ } | undefined;
694
+ routeRules?: Record<string, {
695
+ maxAge?: number | undefined;
696
+ swr?: number | undefined;
697
+ tags?: string[] | undefined;
698
+ }> | undefined;
699
699
  }, {
700
700
  base: string;
701
701
  trailingSlash: "never" | "ignore" | "always";
@@ -840,18 +840,6 @@ export declare function createRelativeSchema(cmd: string, fileProtocolRoot: stri
840
840
  name: string;
841
841
  optimize: (contents: string) => string | Promise<string>;
842
842
  } | undefined;
843
- cache?: {
844
- provider?: {
845
- entrypoint: string | URL;
846
- config?: Record<string, any> | undefined;
847
- name?: string | undefined;
848
- } | undefined;
849
- } | undefined;
850
- routeRules?: Record<string, {
851
- maxAge?: number | undefined;
852
- swr?: number | undefined;
853
- tags?: string[] | undefined;
854
- }> | undefined;
855
843
  };
856
844
  legacy: {
857
845
  collectionsBackwardsCompat: boolean;
@@ -946,4 +934,16 @@ export declare function createRelativeSchema(cmd: string, fileProtocolRoot: stri
946
934
  unicodeRange?: [string, ...string[]] | undefined;
947
935
  options?: Record<string, any> | undefined;
948
936
  }[] | undefined;
937
+ cache?: {
938
+ provider?: {
939
+ entrypoint: string | URL;
940
+ config?: Record<string, any> | undefined;
941
+ name?: string | undefined;
942
+ } | undefined;
943
+ } | undefined;
944
+ routeRules?: Record<string, {
945
+ maxAge?: number | undefined;
946
+ swr?: number | undefined;
947
+ tags?: string[] | undefined;
948
+ }> | undefined;
949
949
  }>>;
@@ -1,4 +1,4 @@
1
- const ASTRO_VERSION = "7.0.0-beta.5";
1
+ const ASTRO_VERSION = "7.0.0";
2
2
  const ASTRO_GENERATOR = `Astro v${ASTRO_VERSION}`;
3
3
  const ASTRO_ERROR_HEADER = "X-Astro-Error";
4
4
  const DEFAULT_404_COMPONENT = "astro-default-404.astro";
@@ -26,7 +26,7 @@ async function dev(inlineConfig) {
26
26
  await telemetry.record([]);
27
27
  const restart = await createContainerWithAutomaticRestart({ inlineConfig, fs });
28
28
  const logger = restart.container.logger;
29
- const currentVersion = "7.0.0-beta.5";
29
+ const currentVersion = "7.0.0";
30
30
  const isPrerelease = currentVersion.includes("-");
31
31
  if (!isPrerelease) {
32
32
  try {
@@ -793,8 +793,8 @@ const CacheProviderNotFound = {
793
793
  const CacheNotEnabled = {
794
794
  name: "CacheNotEnabled",
795
795
  title: "Cache is not enabled.",
796
- message: "`Astro.cache` is not available because the cache feature is not enabled. To use caching, configure a cache provider in your Astro config under `experimental.cache`.",
797
- hint: 'Use an adapter that provides a default cache provider, or set one explicitly: `experimental: { cache: { provider: "..." } }`. See https://docs.astro.build/en/reference/experimental-flags/route-caching/.'
796
+ message: "`Astro.cache` is not available because the cache feature is not enabled. To use caching, configure a cache provider in your Astro config under `cache`.",
797
+ hint: 'Use an adapter that provides a default cache provider, or set one explicitly: `cache: { provider: "..." }`. See https://docs.astro.build/en/guides/caching/.'
798
798
  };
799
799
  const CacheQueryConfigConflict = {
800
800
  name: "CacheQueryConfigConflict",
@@ -8,9 +8,7 @@ export declare const logHandlers: {
8
8
  * @example
9
9
  * ```js
10
10
  * export default defineConfig({
11
- * experimental: {
12
- * logger: logHandlers.json({ pretty: true })
13
- * }
11
+ * logger: logHandlers.json({ pretty: true })
14
12
  * })
15
13
  * ```
16
14
  */
@@ -21,9 +19,7 @@ export declare const logHandlers: {
21
19
  * @example
22
20
  * ```js
23
21
  * export default defineConfig({
24
- * experimental: {
25
- * logger: logHandlers.node({ pretty: true })
26
- * }
22
+ * logger: logHandlers.node({ pretty: true })
27
23
  * })
28
24
  * ```
29
25
  */
@@ -34,9 +30,7 @@ export declare const logHandlers: {
34
30
  * @example
35
31
  * ```js
36
32
  * export default defineConfig({
37
- * experimental: {
38
- * logger: logHandlers.console({ pretty: true })
39
- * }
33
+ * logger: logHandlers.console({ pretty: true })
40
34
  * })
41
35
  * ```
42
36
  */
@@ -47,12 +41,10 @@ export declare const logHandlers: {
47
41
  * @example
48
42
  * ```js
49
43
  * export default defineConfig({
50
- * experimental: {
51
- * logger: logHandlers.compose(
52
- * logHandlers.console(),
53
- * logHandlers.json(),
54
- * )
55
- * }
44
+ * logger: logHandlers.compose(
45
+ * logHandlers.console(),
46
+ * logHandlers.json(),
47
+ * )
56
48
  * })
57
49
  * ```
58
50
  */
@@ -4,9 +4,7 @@ const logHandlers = {
4
4
  * @example
5
5
  * ```js
6
6
  * export default defineConfig({
7
- * experimental: {
8
- * logger: logHandlers.json({ pretty: true })
9
- * }
7
+ * logger: logHandlers.json({ pretty: true })
10
8
  * })
11
9
  * ```
12
10
  */
@@ -22,9 +20,7 @@ const logHandlers = {
22
20
  * @example
23
21
  * ```js
24
22
  * export default defineConfig({
25
- * experimental: {
26
- * logger: logHandlers.node({ pretty: true })
27
- * }
23
+ * logger: logHandlers.node({ pretty: true })
28
24
  * })
29
25
  * ```
30
26
  */
@@ -40,9 +36,7 @@ const logHandlers = {
40
36
  * @example
41
37
  * ```js
42
38
  * export default defineConfig({
43
- * experimental: {
44
- * logger: logHandlers.console({ pretty: true })
45
- * }
39
+ * logger: logHandlers.console({ pretty: true })
46
40
  * })
47
41
  * ```
48
42
  */
@@ -58,12 +52,10 @@ const logHandlers = {
58
52
  * @example
59
53
  * ```js
60
54
  * export default defineConfig({
61
- * experimental: {
62
- * logger: logHandlers.compose(
63
- * logHandlers.console(),
64
- * logHandlers.json(),
65
- * )
66
- * }
55
+ * logger: logHandlers.compose(
56
+ * logHandlers.console(),
57
+ * logHandlers.json(),
58
+ * )
67
59
  * })
68
60
  * ```
69
61
  */
@@ -269,7 +269,7 @@ function printHelp({
269
269
  message.push(
270
270
  linebreak(),
271
271
  ` ${bgGreen(black(` ${commandName} `))} ${green(
272
- `v${"7.0.0-beta.5"}`
272
+ `v${"7.0.0"}`
273
273
  )} ${headline}`
274
274
  );
275
275
  }
@@ -83,7 +83,7 @@ function serializedManifestPlugin({
83
83
  const serialized = await createSerializedManifest(settings, await getEncodedKey());
84
84
  manifestData = JSON.stringify(serialized);
85
85
  }
86
- const hasCacheConfig = !!settings.config.experimental?.cache?.provider;
86
+ const hasCacheConfig = !!settings.config.cache?.provider;
87
87
  const cacheProviderLine = hasCacheConfig ? `cacheProvider: () => import('${VIRTUAL_CACHE_PROVIDER_ID}'),` : "";
88
88
  const code = `
89
89
  import { deserializeManifest as _deserializeManifest } from 'astro/app';
@@ -181,10 +181,7 @@ async function createSerializedManifest(settings, encodedKey) {
181
181
  // 1mb default
182
182
  key: encodedKey ?? await encodeKey(hasEnvironmentKey() ? await getEnvironmentKey() : await createKey()),
183
183
  sessionConfig: sessionConfigToManifest(settings.config.session),
184
- cacheConfig: cacheConfigToManifest(
185
- settings.config.experimental?.cache,
186
- settings.config.experimental?.routeRules
187
- ),
184
+ cacheConfig: cacheConfigToManifest(settings.config.cache, settings.config.routeRules),
188
185
  csp,
189
186
  image: {
190
187
  objectFit: settings.config.image.objectFit,
@@ -1348,7 +1348,7 @@ export interface AstroUserConfig<TLocales extends Locales = never, TDriver exten
1348
1348
  * });
1349
1349
  * ```
1350
1350
  *
1351
- * Learn more about customizing the request pipeline in the [advanced routing guide](https://v7.docs.astro.build/en/guides/routing/#advanced-routing).
1351
+ * Learn more about customizing the request pipeline in the [advanced routing guide](https://docs.astro.build/en/guides/routing/#advanced-routing).
1352
1352
  */
1353
1353
  fetchFile?: string | null;
1354
1354
  /**
@@ -1362,7 +1362,7 @@ export interface AstroUserConfig<TLocales extends Locales = never, TDriver exten
1362
1362
  *
1363
1363
  * Configures how Astro logs messages during development and production.
1364
1364
  *
1365
- * By default, Astro uses a built-in logger that outputs human-friendly logs to the console. You can customize this behavior by providing [your own logger handler](https://v7.docs.astro.build/en/reference/logger-reference/#custom-loggers) or by using one of the [built-in log handlers](https://v7.docs.astro.build/en/reference/logger-reference/#built-in-loggers):
1365
+ * By default, Astro uses a built-in logger that outputs human-friendly logs to the console. You can customize this behavior by providing [your own logger handler](https://docs.astro.build/en/reference/logger-reference/#custom-loggers) or by using one of the [built-in log handlers](https://docs.astro.build/en/reference/logger-reference/#built-in-loggers):
1366
1366
  *
1367
1367
  * ```js
1368
1368
  * // astro.config.mjs
@@ -1373,7 +1373,7 @@ export interface AstroUserConfig<TLocales extends Locales = never, TDriver exten
1373
1373
  * });
1374
1374
  * ```
1375
1375
  *
1376
- * See [the logger API reference](https://v7.docs.astro.build/en/reference/logger-reference/) for more information.
1376
+ * See [the logger API reference](https://docs.astro.build/en/reference/logger-reference/) for more information.
1377
1377
  */
1378
1378
  logger?: LoggerHandlerConfig;
1379
1379
  /**
@@ -2752,6 +2752,85 @@ export interface AstroUserConfig<TLocales extends Locales = never, TDriver exten
2752
2752
  fonts?: [TFontProviders] extends [never] ? Array<FontFamily> : {
2753
2753
  [K in keyof TFontProviders]: FontFamily<TFontProviders[K]>;
2754
2754
  };
2755
+ /**
2756
+ * @docs
2757
+ * @kind heading
2758
+ * @name cache
2759
+ * @type {object}
2760
+ * @default `undefined`
2761
+ * @version 7.0.0
2762
+ * @description
2763
+ *
2764
+ * Enables route caching for SSR responses. Provides a platform-agnostic API
2765
+ * for caching rendered pages and API responses, with pluggable providers
2766
+ * that adapters can configure automatically.
2767
+ *
2768
+ * ```js
2769
+ * // astro.config.mjs
2770
+ * import { memoryCache } from 'astro/config';
2771
+ *
2772
+ * {
2773
+ * cache: {
2774
+ * provider: memoryCache(),
2775
+ * },
2776
+ * routeRules: {
2777
+ * '/blog/[...path]': { maxAge: 300, swr: 60 },
2778
+ * },
2779
+ * }
2780
+ * ```
2781
+ *
2782
+ * Use `Astro.cache.set()` in routes and `context.cache.set()` in middleware
2783
+ * or API routes to control caching per-request.
2784
+ */
2785
+ cache?: {
2786
+ /**
2787
+ * @docs
2788
+ * @name cache.provider
2789
+ * @type {CacheProviderConfig}
2790
+ * @version 7.0.0
2791
+ * @description
2792
+ *
2793
+ * A provider that controls how responses are cached.
2794
+ *
2795
+ * Use the provider's config function to get type-safe configuration:
2796
+ *
2797
+ * ```js
2798
+ * import { defineConfig, memoryCache } from 'astro/config';
2799
+ *
2800
+ * export default defineConfig({
2801
+ * cache: { provider: memoryCache() },
2802
+ * });
2803
+ * ```
2804
+ */
2805
+ provider?: CacheProviderConfig;
2806
+ };
2807
+ /**
2808
+ * @docs
2809
+ * @kind heading
2810
+ * @name routeRules
2811
+ * @type {Record<string, RouteRule>}
2812
+ * @default `undefined`
2813
+ * @version 7.0.0
2814
+ * @description
2815
+ *
2816
+ * Route patterns mapped to cache rules.
2817
+ * Uses the same `[param]` and `[...rest]` syntax as [file-based routing](/en/guides/routing/#route-priority-order).
2818
+ * Use a `[...rest]` parameter to match a group of routes:
2819
+ *
2820
+ * ```js
2821
+ * // astro.config.mjs
2822
+ * import { memoryCache } from 'astro/config';
2823
+ *
2824
+ * {
2825
+ * cache: { provider: memoryCache() },
2826
+ * routeRules: {
2827
+ * '/api/[...path]': { swr: 600 },
2828
+ * '/products/[...slug]': { maxAge: 3600, tags: ['products'] },
2829
+ * },
2830
+ * }
2831
+ * ```
2832
+ */
2833
+ routeRules?: RouteRules;
2755
2834
  /**
2756
2835
  *
2757
2836
  * @kind heading
@@ -2895,83 +2974,6 @@ export interface AstroUserConfig<TLocales extends Locales = never, TDriver exten
2895
2974
  * See the [experimental SVG optimization docs](https://docs.astro.build/en/reference/experimental-flags/svg-optimization/) for more information.
2896
2975
  */
2897
2976
  svgOptimizer?: SvgOptimizer;
2898
- /**
2899
- * @name experimental.cache
2900
- * @type {object}
2901
- * @default `undefined`
2902
- * @description
2903
- *
2904
- * Enables route caching for SSR responses. Provides a platform-agnostic API
2905
- * for caching rendered pages and API responses, with pluggable providers
2906
- * that adapters can configure automatically.
2907
- *
2908
- * ```js
2909
- * // astro.config.mjs
2910
- * import { memoryCache } from 'astro/config';
2911
- *
2912
- * {
2913
- * experimental: {
2914
- * cache: {
2915
- * provider: memoryCache(),
2916
- * },
2917
- * routeRules: {
2918
- * '/blog/[...path]': { maxAge: 300, swr: 60 },
2919
- * },
2920
- * },
2921
- * }
2922
- * ```
2923
- *
2924
- * Use `Astro.cache.set()` in routes and `context.cache.set()` in middleware
2925
- * or API routes to control caching per-request.
2926
- */
2927
- cache?: {
2928
- /**
2929
- * @name experimental.cache.provider
2930
- * @type {import('../../core/cache/types.js').CacheProviderConfig}
2931
- * @description
2932
- *
2933
- * The cache provider. Adapters typically set a default, but you can
2934
- * override it with your own.
2935
- *
2936
- * Use the provider's config function to get type-safe configuration:
2937
- *
2938
- * ```js
2939
- * import { memoryCache } from 'astro/config';
2940
- *
2941
- * export default defineConfig({
2942
- * experimental: {
2943
- * cache: { provider: memoryCache() },
2944
- * },
2945
- * });
2946
- * ```
2947
- */
2948
- provider?: CacheProviderConfig;
2949
- };
2950
- /**
2951
- * @name experimental.routeRules
2952
- * @type {Record<string, RouteRule>}
2953
- * @default `undefined`
2954
- * @description
2955
- *
2956
- * Route patterns mapped to cache rules.
2957
- * Uses the same `[param]` and `[...rest]` syntax as file-based routing.
2958
- *
2959
- * ```js
2960
- * // astro.config.mjs
2961
- * import { memoryCache } from 'astro/config';
2962
- *
2963
- * {
2964
- * experimental: {
2965
- * cache: { provider: memoryCache() },
2966
- * routeRules: {
2967
- * '/api/*': { swr: 600 },
2968
- * '/products/*': { maxAge: 3600, tags: ['products'] },
2969
- * },
2970
- * },
2971
- * }
2972
- * ```
2973
- */
2974
- routeRules?: RouteRules;
2975
2977
  };
2976
2978
  }
2977
2979
  /**
@@ -1,6 +1,6 @@
1
1
  import { type Plugin as VitePlugin } from 'vite';
2
2
  import type { AstroSettings } from '../types/astro.js';
3
- /** Returns a Vite plugin used to alias paths from tsconfig.json and jsconfig.json. */
3
+ /** Returns Vite plugins used to alias paths from tsconfig.json and jsconfig.json. */
4
4
  export default function configAliasVitePlugin({ settings, }: {
5
5
  settings: AstroSettings;
6
- }): VitePlugin | null;
6
+ }): VitePlugin[] | null;
@@ -31,81 +31,86 @@ const getConfigAlias = (settings) => {
31
31
  }
32
32
  return aliases;
33
33
  };
34
- const getViteResolveAlias = (settings) => {
35
- const { tsConfig, tsConfigPath } = settings;
36
- if (!tsConfig || !tsConfigPath || !tsConfig.compilerOptions) return [];
37
- const { baseUrl, paths } = tsConfig.compilerOptions;
38
- const effectiveBaseUrl = baseUrl ?? (paths ? "." : void 0);
39
- if (!effectiveBaseUrl) return [];
40
- const resolvedBaseUrl = path.resolve(path.dirname(tsConfigPath), effectiveBaseUrl);
41
- const aliases = [];
42
- if (paths) {
43
- for (const [aliasPattern, values] of Object.entries(paths)) {
44
- const resolvedValues = values.map((v) => path.resolve(resolvedBaseUrl, v));
45
- const customResolver = (id) => {
46
- for (const resolvedValue of resolvedValues) {
47
- const resolved = resolvedValue.replace("*", id);
48
- const stats = fs.statSync(resolved, { throwIfNoEntry: false });
49
- if (stats && stats.isFile()) {
50
- return normalizePath(resolved);
51
- }
52
- }
53
- return null;
54
- };
55
- aliases.push({
56
- // Build regex from alias pattern (e.g., '@styles/*' -> /^@styles\/(.+)$/)
57
- // First, escape special regex chars. Then replace * with a capture group (.+)
58
- find: new RegExp(
59
- `^${aliasPattern.replace(/[\\^$+?.()|[\]{}]/g, "\\$&").replace(/\*/g, "(.+)")}$`
60
- ),
61
- replacement: aliasPattern.includes("*") ? "$1" : aliasPattern,
62
- customResolver
63
- });
34
+ function resolveWithAlias(id, configAlias) {
35
+ for (const alias of configAlias) {
36
+ if (alias.find.test(id)) {
37
+ const updatedId = id.replace(alias.find, alias.replacement);
38
+ const stats = fs.statSync(updatedId, { throwIfNoEntry: false });
39
+ if (stats && stats.isFile()) {
40
+ return normalizePath(updatedId);
41
+ }
64
42
  }
65
43
  }
66
- return aliases;
67
- };
44
+ return null;
45
+ }
46
+ const cssImportRE = /@import\s+(?:url\(\s*)?['"]([^'"]+)['"]\s*\)?/g;
68
47
  function configAliasVitePlugin({
69
48
  settings
70
49
  }) {
71
50
  const configAlias = getConfigAlias(settings);
72
51
  if (!configAlias) return null;
73
- const plugin = {
74
- name: "astro:tsconfig-alias",
75
- // use post to only resolve ids that all other plugins before it can't
76
- enforce: "post",
77
- config() {
78
- return {
79
- resolve: {
80
- alias: getViteResolveAlias(settings)
52
+ return [
53
+ // Pre-plugin: rewrite CSS @import aliases to absolute paths before Vite's CSS plugin.
54
+ // Vite's internal CSS @import resolver (postcss-import) uses a mini plugin container
55
+ // that doesn't include user resolveId hooks, so we must rewrite aliases in a transform
56
+ // hook that runs before Vite's CSS processing.
57
+ {
58
+ name: "astro:tsconfig-alias-css",
59
+ enforce: "pre",
60
+ transform: {
61
+ filter: {
62
+ id: {
63
+ include: /\.css$/
64
+ }
65
+ },
66
+ handler(code) {
67
+ if (!code.includes("@import")) return;
68
+ let hasReplacement = false;
69
+ const result = code.replace(cssImportRE, (match, importId) => {
70
+ if (!importId) return match;
71
+ const resolved = resolveWithAlias(importId, configAlias);
72
+ if (resolved) {
73
+ hasReplacement = true;
74
+ return match.replace(importId, resolved);
75
+ }
76
+ return match;
77
+ });
78
+ if (hasReplacement) {
79
+ return { code: result, map: null };
80
+ }
81
81
  }
82
- };
82
+ }
83
83
  },
84
- resolveId: {
85
- filter: {
86
- id: {
87
- include: configAlias.map((alias) => alias.find),
88
- exclude: /(?:\0|^virtual:|^astro:)/
89
- }
90
- },
91
- async handler(id, importer, options) {
92
- for (const alias of configAlias) {
93
- if (alias.find.test(id)) {
94
- const updatedId = id.replace(alias.find, alias.replacement);
95
- if (updatedId.includes("*")) {
96
- return updatedId;
84
+ // Post-plugin: resolve JS/TS imports using tsconfig path aliases via resolveId.
85
+ {
86
+ name: "astro:tsconfig-alias",
87
+ // use post to only resolve ids that all other plugins before it can't
88
+ enforce: "post",
89
+ resolveId: {
90
+ filter: {
91
+ id: {
92
+ include: configAlias.map((alias) => alias.find),
93
+ exclude: /(?:\0|^virtual:|^astro:)/
94
+ }
95
+ },
96
+ async handler(id, importer, options) {
97
+ for (const alias of configAlias) {
98
+ if (alias.find.test(id)) {
99
+ const updatedId = id.replace(alias.find, alias.replacement);
100
+ if (updatedId.includes("*")) {
101
+ return updatedId;
102
+ }
103
+ const resolved = await this.resolve(updatedId, importer, {
104
+ skipSelf: true,
105
+ ...options
106
+ });
107
+ if (resolved) return resolved;
97
108
  }
98
- const resolved = await this.resolve(updatedId, importer, {
99
- skipSelf: true,
100
- ...options
101
- });
102
- if (resolved) return resolved;
103
109
  }
104
110
  }
105
111
  }
106
112
  }
107
- };
108
- return plugin;
113
+ ];
109
114
  }
110
115
  export {
111
116
  configAliasVitePlugin as default
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "astro",
3
- "version": "7.0.0-beta.5",
3
+ "version": "7.0.0",
4
4
  "description": "Astro is a modern site builder with web best practices, performance, and DX front-of-mind.",
5
5
  "type": "module",
6
6
  "author": "withastro",
@@ -75,6 +75,7 @@
75
75
  "./assets/services/sharp": "./dist/assets/services/sharp.js",
76
76
  "./assets/services/noop": "./dist/assets/services/noop.js",
77
77
  "./cache/memory": "./dist/core/cache/memory-provider.js",
78
+ "./cache/provider-utils": "./dist/core/cache/provider-utils.js",
78
79
  "./fetch": "./dist/core/fetch/index.js",
79
80
  "./hono": "./dist/core/hono/index.js",
80
81
  "./assets/fonts/runtime.js": "./dist/assets/fonts/runtime.js",
@@ -166,7 +167,7 @@
166
167
  "yargs-parser": "^22.0.0",
167
168
  "zod": "^4.3.6",
168
169
  "@astrojs/internal-helpers": "0.10.0",
169
- "@astrojs/markdown-satteri": "0.3.1-beta.1",
170
+ "@astrojs/markdown-satteri": "0.3.1",
170
171
  "@astrojs/telemetry": "3.3.2"
171
172
  },
172
173
  "optionalDependencies": {