astro 7.2.3 → 7.2.5

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 (48) hide show
  1. package/bin/astro.mjs +15 -0
  2. package/client.d.ts +8 -4
  3. package/dist/assets/consts.d.ts +1 -1
  4. package/dist/assets/consts.js +1 -0
  5. package/dist/assets/fonts/infra/remote-runtime-font-file-url-resolver.d.ts +6 -4
  6. package/dist/assets/fonts/infra/remote-runtime-font-file-url-resolver.js +14 -7
  7. package/dist/assets/utils/node.js +3 -0
  8. package/dist/assets/utils/vendor/image-size/types/heif.js +8 -3
  9. package/dist/assets/utils/vendor/image-size/types/icns.js +10 -2
  10. package/dist/assets/utils/vendor/image-size/types/jp2.js +2 -2
  11. package/dist/assets/utils/vendor/image-size/types/jxl.js +5 -2
  12. package/dist/assets/utils/vendor/image-size/types/utils.d.ts +1 -1
  13. package/dist/assets/utils/vendor/image-size/types/utils.js +20 -6
  14. package/dist/cli/infra/build-time-astro-version-provider.js +1 -1
  15. package/dist/cli/server.js +13 -0
  16. package/dist/container/index.js +8 -5
  17. package/dist/content/config.d.ts +2 -1
  18. package/dist/content/content-layer.js +3 -3
  19. package/dist/content/loaders/glob.js +3 -3
  20. package/dist/content/mutable-data-store.js +49 -2
  21. package/dist/core/app/base.js +3 -7
  22. package/dist/core/build/plugins/plugin-incremental.js +8 -2
  23. package/dist/core/build/vite-build-config.js +15 -6
  24. package/dist/core/cache/memory-provider.js +6 -1
  25. package/dist/core/compile/compile.js +1 -1
  26. package/dist/core/constants.js +1 -1
  27. package/dist/core/create-vite.js +1 -1
  28. package/dist/core/dev/dev.js +1 -1
  29. package/dist/core/dev/lockfile.js +3 -0
  30. package/dist/core/errors/dev/utils.js +3 -3
  31. package/dist/core/fetch/fetch-state.js +11 -14
  32. package/dist/core/i18n/domain.js +4 -11
  33. package/dist/core/i18n/handler.js +5 -1
  34. package/dist/core/messages/runtime.js +1 -1
  35. package/dist/core/routing/match-request.js +2 -13
  36. package/dist/core/session/runtime.js +4 -2
  37. package/dist/core/session/types.d.ts +5 -5
  38. package/dist/core/util/normalized-url.d.ts +8 -0
  39. package/dist/core/util/normalized-url.js +10 -4
  40. package/dist/i18n/utils.js +3 -4
  41. package/dist/runtime/server/astro-global.js +2 -2
  42. package/dist/runtime/server/render/csp.js +13 -5
  43. package/dist/transitions/swap-functions.js +4 -2
  44. package/dist/types/public/config.d.ts +1 -1
  45. package/dist/vite-plugin-routes/index.js +1 -1
  46. package/package.json +7 -7
  47. package/templates/content/module.mjs +3 -3
  48. package/types/content.d.ts +2 -2
@@ -1,4 +1,5 @@
1
1
  import picomatch from "picomatch";
2
+ import { getCookiesFromResponse } from "../cookies/response.js";
2
3
  import { AstroError } from "../errors/errors.js";
3
4
  import { CacheQueryConfigConflict } from "../errors/errors-data.js";
4
5
  function parseCdnCacheControl(header) {
@@ -110,8 +111,12 @@ function matchesVary(request, entry) {
110
111
  }
111
112
  return true;
112
113
  }
114
+ function hasAtLeastOneCookie(cookies) {
115
+ return cookies ? !cookies.headers().next().done : false;
116
+ }
113
117
  function hasSetCookieHeader(response) {
114
- return response.headers.has("set-cookie");
118
+ if (response.headers.has("set-cookie")) return true;
119
+ return hasAtLeastOneCookie(getCookiesFromResponse(response));
115
120
  }
116
121
  function warnSkippedSetCookie(url) {
117
122
  console.warn(
@@ -31,7 +31,7 @@ async function compile({
31
31
  normalizedFilename: normalizeFilename(filename, astroConfig.root),
32
32
  sourcemap: "both",
33
33
  internalURL: "astro/compiler-runtime",
34
- // TODO: remove in Astro v7
34
+ // TODO: remove in Astro v8
35
35
  astroGlobalArgs: JSON.stringify(astroConfig.site),
36
36
  scopedStyleStrategy: astroConfig.scopedStyleStrategy,
37
37
  resultScopedSlot: true,
@@ -1,4 +1,4 @@
1
- const ASTRO_VERSION = "7.2.3";
1
+ const ASTRO_VERSION = "7.2.5";
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";
@@ -223,7 +223,7 @@ async function createVite(commandConfig, { settings, logger, mode, command, fs =
223
223
  find: "astro:middleware",
224
224
  replacement: "astro/virtual-modules/middleware.js"
225
225
  },
226
- // TODO: remove in Astro 7
226
+ // TODO: remove in Astro 8
227
227
  {
228
228
  find: "astro:schema",
229
229
  replacement: "astro/zod"
@@ -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.2.3";
29
+ const currentVersion = "7.2.5";
30
30
  const isPrerelease = currentVersion.includes("-");
31
31
  if (!isPrerelease) {
32
32
  try {
@@ -48,6 +48,9 @@ function isAstroCommand(command) {
48
48
  return ASTRO_COMMAND_PATTERN.test(command);
49
49
  }
50
50
  async function isLockFileProcessAlive(data, find = findProcess) {
51
+ if (data.pid === process.pid) {
52
+ return false;
53
+ }
51
54
  if (!isProcessAlive(data.pid)) {
52
55
  return false;
53
56
  }
@@ -12,8 +12,8 @@ import { normalizeLF } from "../utils.js";
12
12
  function collectErrorMetadata(e, rootFolder) {
13
13
  const err = AggregateError.is(e) || Array.isArray(e.errors) ? e.errors : [e];
14
14
  err.forEach((error) => {
15
- if (e.stack) {
16
- const stackInfo = collectInfoFromStacktrace(e);
15
+ if (error.stack) {
16
+ const stackInfo = collectInfoFromStacktrace(error);
17
17
  try {
18
18
  error.stack = stripVTControlCharacters(stackInfo.stack);
19
19
  } catch {
@@ -40,7 +40,7 @@ function collectErrorMetadata(e, rootFolder) {
40
40
  } catch {
41
41
  }
42
42
  }
43
- error.hint = generateHint(e);
43
+ error.hint = generateHint(error);
44
44
  if (error.message) {
45
45
  try {
46
46
  error.message = stripVTControlCharacters(error.message);
@@ -1,9 +1,8 @@
1
1
  import colors from "piccolore";
2
2
  import {
3
- collapseDuplicateLeadingSlashes,
4
3
  collapseDuplicateSlashes,
5
4
  prependForwardSlash,
6
- removeTrailingForwardSlash
5
+ stripRequestBase
7
6
  } from "@astrojs/internal-helpers/path";
8
7
  import { deserializeActionResult } from "../../actions/runtime/client.js";
9
8
  import { createCallAction, createGetActionResult, hasActionPayload } from "../../actions/utils.js";
@@ -28,6 +27,7 @@ import { getParams, getProps } from "../render/index.js";
28
27
  import { executeRewrite } from "../rewrites/handler.js";
29
28
  import { isRoute404or500, isRouteServerIsland } from "../routing/match.js";
30
29
  import { MultiLevelEncodingError, validateAndDecodePathname } from "../util/pathname.js";
30
+ import { setPathname } from "../util/normalized-url.js";
31
31
  import { getOriginPathname, setOriginPathname } from "../routing/rewrite.js";
32
32
  import { computePathnameFromDomain } from "../i18n/domain.js";
33
33
  import { getCustom404Route, routeHasHtmlExtension } from "../routing/helpers.js";
@@ -211,8 +211,8 @@ class FetchState {
211
211
  const url = new URL(request.url);
212
212
  const publicPathname = this.#normalizePathname(url.pathname);
213
213
  const pathname = this.#computePathname(publicPathname);
214
- url.pathname = publicPathname;
215
- url.pathname = collapseDuplicateSlashes(url.pathname);
214
+ setPathname(url, publicPathname);
215
+ setPathname(url, collapseDuplicateSlashes(url.pathname));
216
216
  const domainPathname = computePathnameFromDomain(
217
217
  request,
218
218
  url,
@@ -723,6 +723,9 @@ class FetchState {
723
723
  #stripHtmlExtension() {
724
724
  if (this.routeData && this.routeData.type === "page" && !routeHasHtmlExtension(this.routeData)) {
725
725
  this.pathname = this.pathname.replace(/\/index\.html$/, "/").replace(/\.html$/, "");
726
+ if (this.manifest.trailingSlash === "always" && this.pathname !== "" && !this.pathname.endsWith("/")) {
727
+ this.pathname += "/";
728
+ }
726
729
  }
727
730
  }
728
731
  #resolveRouteData() {
@@ -760,18 +763,12 @@ class FetchState {
760
763
  * Strips the manifest's base from a normalized request pathname and prepends
761
764
  * a forward slash.
762
765
  *
763
- * Mirrors `BaseApp.removeBase`, including the
764
- * `collapseDuplicateLeadingSlashes` fix that prevents middleware
765
- * authorization bypass when the URL starts with `//`.
766
+ * Mirrors `BaseApp.removeBase`: the router matches against this stripped path
767
+ * while middleware reads the un-stripped `context.url.pathname`, so both must
768
+ * strip the base identically.
766
769
  */
767
770
  #computePathname(normalizedPathname) {
768
- let pathname = collapseDuplicateLeadingSlashes(normalizedPathname);
769
- const base = this.manifest.base;
770
- if (pathname.startsWith(base)) {
771
- const baseWithoutTrailingSlash = removeTrailingForwardSlash(base);
772
- pathname = pathname.slice(baseWithoutTrailingSlash.length + 1);
773
- }
774
- return prependForwardSlash(pathname);
771
+ return prependForwardSlash(stripRequestBase(normalizedPathname, this.manifest.base));
775
772
  }
776
773
  /**
777
774
  * Decodes and normalizes the public request pathname before deriving the
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  appendForwardSlash,
3
- collapseDuplicateLeadingSlashes,
4
3
  joinPaths,
5
4
  prependForwardSlash,
6
- removeTrailingForwardSlash
5
+ removeTrailingForwardSlash,
6
+ stripRequestBase
7
7
  } from "@astrojs/internal-helpers/path";
8
8
  import { normalizeTheLocale } from "../../i18n/path.js";
9
9
  function computePathnameFromDomain(request, url, i18n, base, trailingSlash, logger, pathnameFromRequest) {
@@ -32,13 +32,13 @@ function computePathnameFromDomain(request, url, i18n, base, trailingSlash, logg
32
32
  }
33
33
  }
34
34
  if (locale) {
35
- const requestPathname = pathnameFromRequest ?? removeBase(url.pathname, base);
35
+ const requestPathname = pathnameFromRequest ?? stripRequestBase(url.pathname, base);
36
36
  pathname = prependForwardSlash(joinPaths(normalizeTheLocale(locale), requestPathname));
37
37
  if (trailingSlash === "always") {
38
38
  pathname = appendForwardSlash(pathname);
39
39
  } else if (trailingSlash === "never") {
40
40
  pathname = removeTrailingForwardSlash(pathname);
41
- } else if (requestPathname.endsWith("/")) {
41
+ } else if (url.pathname.endsWith("/")) {
42
42
  pathname = appendForwardSlash(pathname);
43
43
  }
44
44
  }
@@ -53,13 +53,6 @@ function computePathnameFromDomain(request, url, i18n, base, trailingSlash, logg
53
53
  }
54
54
  return pathname;
55
55
  }
56
- function removeBase(pathname, base) {
57
- pathname = collapseDuplicateLeadingSlashes(pathname);
58
- if (pathname.startsWith(base)) {
59
- return pathname.slice(removeTrailingForwardSlash(base).length + 1);
60
- }
61
- return pathname;
62
- }
63
56
  export {
64
57
  computePathnameFromDomain
65
58
  };
@@ -102,7 +102,11 @@ async function finalizeI18n(compiled, state, response) {
102
102
  headers: { Location: fallbackDecision.pathname + url.search }
103
103
  });
104
104
  case "rewrite":
105
- return await state.rewrite(fallbackDecision.pathname + url.search);
105
+ try {
106
+ return await state.rewrite(fallbackDecision.pathname + url.search);
107
+ } catch {
108
+ break;
109
+ }
106
110
  case "none":
107
111
  break;
108
112
  }
@@ -270,7 +270,7 @@ function printHelp({
270
270
  message.push(
271
271
  linebreak(),
272
272
  ` ${bgGreen(black(` ${commandName} `))} ${green(
273
- `v${"7.2.3"}`
273
+ `v${"7.2.5"}`
274
274
  )} ${headline}`
275
275
  );
276
276
  }
@@ -1,19 +1,8 @@
1
- import {
2
- collapseDuplicateLeadingSlashes,
3
- prependForwardSlash,
4
- removeTrailingForwardSlash
5
- } from "@astrojs/internal-helpers/path";
1
+ import { prependForwardSlash, stripRequestBase } from "@astrojs/internal-helpers/path";
6
2
  import { computePathnameFromDomain } from "../i18n/domain.js";
7
3
  import { AstroIntegrationLogger } from "../logger/core.js";
8
4
  import { getLogger } from "../logger/manifest-logger.js";
9
5
  import { matchAllRoutes, matchRoute } from "./route-table.js";
10
- function removeBase(manifest, pathname) {
11
- pathname = collapseDuplicateLeadingSlashes(pathname);
12
- if (pathname.startsWith(manifest.base)) {
13
- return pathname.slice(removeTrailingForwardSlash(manifest.base).length + 1);
14
- }
15
- return pathname;
16
- }
17
6
  function safeDecodeURI(manifest, pathname) {
18
7
  try {
19
8
  return decodeURI(pathname);
@@ -36,7 +25,7 @@ function matchRequest(manifest, request, allowPrerenderedRoutes = false) {
36
25
  getLogger(manifest)
37
26
  );
38
27
  if (!pathname) {
39
- pathname = prependForwardSlash(removeBase(manifest, url.pathname));
28
+ pathname = prependForwardSlash(stripRequestBase(url.pathname, manifest.base));
40
29
  }
41
30
  const routeData = matchRoute(manifest, safeDecodeURI(manifest, pathname));
42
31
  if (!routeData) return void 0;
@@ -5,6 +5,7 @@ import { createStorage } from "unstorage";
5
5
  const PERSIST_SYMBOL = /* @__PURE__ */ Symbol();
6
6
  const DEFAULT_COOKIE_NAME = "astro-session";
7
7
  const VALID_COOKIE_REGEX = /^[\w-]+$/;
8
+ const UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
8
9
  const unflatten = (parsed, _) => {
9
10
  return rawUnflatten(parsed, {
10
11
  URL: (href) => new URL(href)
@@ -170,7 +171,8 @@ class AstroSession {
170
171
  * Destroys the session, clearing the cookie and storage if it exists.
171
172
  */
172
173
  destroy() {
173
- const sessionId = this.#sessionID ?? this.#cookies.get(this.#cookieName)?.value;
174
+ const cookieValue = this.#cookies.get(this.#cookieName)?.value;
175
+ const sessionId = this.#sessionID ?? (cookieValue && UUID_REGEX.test(cookieValue) ? cookieValue : void 0);
174
176
  if (sessionId) {
175
177
  this.#toDestroy.add(sessionId);
176
178
  }
@@ -340,7 +342,7 @@ class AstroSession {
340
342
  #ensureSessionID() {
341
343
  if (!this.#sessionID) {
342
344
  const cookieValue = this.#cookies.get(this.#cookieName)?.value;
343
- if (cookieValue) {
345
+ if (cookieValue && UUID_REGEX.test(cookieValue)) {
344
346
  this.#sessionID = cookieValue;
345
347
  this.#sessionIDFromCookie = true;
346
348
  } else {
@@ -34,30 +34,30 @@ export interface BaseSessionConfig {
34
34
  interface DriverConfig<TDriver extends SessionDriverConfig> extends BaseSessionConfig {
35
35
  /** Config object for a session driver */
36
36
  driver: TDriver;
37
- /** @deprecated Pass options to the driver function directly. This will be removed in Astro 7 */
37
+ /** @deprecated Pass options to the driver function directly. This will be removed in Astro 8 */
38
38
  options?: never;
39
39
  }
40
40
  interface UnstorageConfig<TDriver extends keyof BuiltinDriverOptions | undefined, TOptions = TDriver extends keyof BuiltinDriverOptions ? NoInfer<BuiltinDriverOptions[TDriver]> : undefined> extends BaseSessionConfig {
41
41
  /**
42
42
  * Entrypoint for an unstorage session driver
43
- * @deprecated Use `import { sessionDrivers } from 'astro/config'` instead. This will be removed in Astro 7
43
+ * @deprecated Use `import { sessionDrivers } from 'astro/config'` instead. This will be removed in Astro 8
44
44
  */
45
45
  driver?: TDriver;
46
46
  /**
47
47
  * Options for the unstorage driver
48
- * @deprecated Use `import { sessionDrivers } from 'astro/config'` instead. This will be removed in Astro 7
48
+ * @deprecated Use `import { sessionDrivers } from 'astro/config'` instead. This will be removed in Astro 8
49
49
  */
50
50
  options?: TOptions;
51
51
  }
52
52
  interface CustomConfig extends BaseSessionConfig {
53
53
  /**
54
54
  * Entrypoint for a custom session driver
55
- * @deprecated Use the object shape (type `SessionDriverConfig`). This will be removed in Astro 7
55
+ * @deprecated Use the object shape (type `SessionDriverConfig`). This will be removed in Astro 8
56
56
  */
57
57
  driver?: string;
58
58
  /**
59
59
  * Options for the custom session driver
60
- * @deprecated Use the object shape (type `SessionDriverConfig`). This will be removed in Astro 7
60
+ * @deprecated Use the object shape (type `SessionDriverConfig`). This will be removed in Astro 8
61
61
  */
62
62
  options?: Record<string, unknown>;
63
63
  }
@@ -3,8 +3,16 @@
3
3
  * Decodes and validates the pathname, collapses duplicate slashes.
4
4
  */
5
5
  export declare function createNormalizedUrl(requestUrl: string): URL;
6
+ /**
7
+ * Assigns `url.pathname` only when the value differs.
8
+ * The setter re-parses the whole URL, so a no-op write is still expensive.
9
+ */
10
+ export declare function setPathname(url: URL, pathname: string): void;
6
11
  /**
7
12
  * Normalizes an already-parsed URL in place: decodes and validates the
8
13
  * pathname, collapses duplicate slashes. Returns the same URL object.
14
+ *
15
+ * Collapse runs after the decode is written back: the pathname setter
16
+ * rewrites `\` to `/`, so a decoded backslash only becomes `//` once assigned.
9
17
  */
10
18
  export declare function normalizeUrl(url: URL): URL;
@@ -3,19 +3,25 @@ import { validateAndDecodePathname } from "./pathname.js";
3
3
  function createNormalizedUrl(requestUrl) {
4
4
  return normalizeUrl(new URL(requestUrl));
5
5
  }
6
+ function setPathname(url, pathname) {
7
+ if (url.pathname !== pathname) {
8
+ url.pathname = pathname;
9
+ }
10
+ }
6
11
  function normalizeUrl(url) {
7
12
  try {
8
- url.pathname = validateAndDecodePathname(url.pathname);
13
+ setPathname(url, validateAndDecodePathname(url.pathname));
9
14
  } catch {
10
15
  try {
11
- url.pathname = decodeURI(url.pathname);
16
+ setPathname(url, decodeURI(url.pathname));
12
17
  } catch {
13
18
  }
14
19
  }
15
- url.pathname = collapseDuplicateSlashes(url.pathname);
20
+ setPathname(url, collapseDuplicateSlashes(url.pathname));
16
21
  return url;
17
22
  }
18
23
  export {
19
24
  createNormalizedUrl,
20
- normalizeUrl
25
+ normalizeUrl,
26
+ setPathname
21
27
  };
@@ -43,10 +43,9 @@ function sortAndFilterLocales(browserLocaleList, locales) {
43
43
  }
44
44
  return true;
45
45
  }).sort((a, b) => {
46
- if (a.qualityValue && b.qualityValue) {
47
- return Math.sign(b.qualityValue - a.qualityValue);
48
- }
49
- return 0;
46
+ const qa = a.locale === "*" ? a.qualityValue ?? 0 : a.qualityValue ?? 1;
47
+ const qb = b.locale === "*" ? b.qualityValue ?? 0 : b.qualityValue ?? 1;
48
+ return qb - qa;
50
49
  });
51
50
  }
52
51
  function computePreferredLocale(request, locales) {
@@ -8,14 +8,14 @@ function createError(name) {
8
8
  }
9
9
  function createAstro(site) {
10
10
  return {
11
- // TODO: throw in Astro 7
11
+ // TODO: throw in Astro 8
12
12
  get site() {
13
13
  console.warn(
14
14
  `Astro.site inside getStaticPaths is deprecated and will be removed in a future major version of Astro. Use import.meta.env.SITE instead`
15
15
  );
16
16
  return site ? new URL(site) : void 0;
17
17
  },
18
- // TODO: throw in Astro 7
18
+ // TODO: throw in Astro 8
19
19
  get generator() {
20
20
  console.warn(
21
21
  `Astro.generator inside getStaticPaths is deprecated and will be removed in a future major version of Astro.`
@@ -28,12 +28,14 @@ function renderCspContent(result) {
28
28
  const scriptElemActive = isEnabled(script.element);
29
29
  const styleElemActive = isEnabled(style.element);
30
30
  const strictDynamicSuffix = scriptDirective.strictDynamic ? ` 'strict-dynamic'` : "";
31
+ const scriptDefaultHasUnsafeInline = hasUnsafeInline(script.default.resources);
32
+ const styleDefaultHasUnsafeInline = hasUnsafeInline(style.default.resources);
31
33
  const scriptBaselineTokens = [
32
- ...scriptElemActive ? [] : [...finalScriptHashes],
34
+ ...scriptElemActive || scriptDefaultHasUnsafeInline ? [] : [...finalScriptHashes],
33
35
  ...scriptDirective.strictDynamic ? [`'strict-dynamic'`] : []
34
36
  ];
35
37
  const scriptSrc = `script-src ${scriptResources} ${scriptBaselineTokens.join(" ")};`;
36
- const styleSrc = `style-src ${styleResources} ${(styleElemActive ? [] : [...finalStyleHashes]).join(" ")};`;
38
+ const styleSrc = `style-src ${styleResources} ${(styleElemActive || styleDefaultHasUnsafeInline ? [] : [...finalStyleHashes]).join(" ")};`;
37
39
  const scriptSrcElem = scriptElemActive ? renderSpecificDirective(
38
40
  "script-src-elem",
39
41
  script.element.resources,
@@ -73,13 +75,19 @@ function renderCspContent(result) {
73
75
  styleSrcAttr
74
76
  ].filter(Boolean).join(" ");
75
77
  }
78
+ function hasUnsafeInline(resources) {
79
+ return resources.includes("'unsafe-inline'");
80
+ }
76
81
  function isEnabled(sources) {
77
82
  return sources.resources.length > 0 || sources.hashes.length > 0;
78
83
  }
79
84
  function renderSpecificDirective(name, resources, defaultResource, sharedHashes, ownHashes, suffix = "") {
80
- const hashes = new Set(sharedHashes);
81
- for (const hash of ownHashes) {
82
- hashes.add(`'${hash}'`);
85
+ const unsafeInline = hasUnsafeInline(resources);
86
+ const hashes = new Set(unsafeInline ? void 0 : sharedHashes);
87
+ if (!unsafeInline) {
88
+ for (const hash of ownHashes) {
89
+ hashes.add(`'${hash}'`);
90
+ }
83
91
  }
84
92
  let finalResources;
85
93
  if (resources.length > 0) {
@@ -93,6 +93,7 @@ function swapHeadElements(doc) {
93
93
  function swapBodyElement(newElement, oldElement) {
94
94
  const persistPairs = [];
95
95
  const docEl = oldElement.ownerDocument.documentElement;
96
+ const liveMedia = new Set(oldElement.querySelectorAll("video, audio"));
96
97
  const moveBefore = typeof docEl.moveBefore === "function" ? (parent, node, child) => parent.moveBefore(node, child) : null;
97
98
  for (const el of oldElement.querySelectorAll(`[${PERSIST_ATTR}]`)) {
98
99
  const id = el.getAttribute(PERSIST_ATTR);
@@ -119,10 +120,11 @@ function swapBodyElement(newElement, oldElement) {
119
120
  }
120
121
  }
121
122
  attachShadowRoots(newElement);
122
- reifyMediaElements(newElement);
123
+ reifyMediaElements(newElement, liveMedia);
123
124
  }
124
- function reifyMediaElements(root) {
125
+ function reifyMediaElements(root, liveMedia) {
125
126
  for (const media of root.querySelectorAll("video, audio")) {
127
+ if (liveMedia.has(media)) continue;
126
128
  const fresh = document.createElement(media.localName);
127
129
  for (const attr of media.attributes) {
128
130
  fresh.setAttribute(attr.name, attr.value);
@@ -749,7 +749,7 @@ export interface AstroUserConfig<TLocales extends Locales = never, TDriver exten
749
749
  * - External scripts and external styles are not supported out of the box, but you can [provide your own hashes](https://docs.astro.build/en/reference/configuration-reference/#securitycspscriptdirectivehashes).
750
750
  * - [Astro's view transitions](https://docs.astro.build/en/guides/view-transitions/) using the `<ClientRouter />` are not supported, but you can [consider migrating to the browser native View Transition API](https://events-3bg.pages.dev/jotter/astro-view-transitions/) instead if you are not using Astro's enhancements to the native View Transitions and Navigation APIs.
751
751
  * - Shiki isn't currently supported. By design, Shiki functions use inline styles that cannot work with Astro CSP implementation. Consider [using `<Prism />`](https://docs.astro.build/en/guides/syntax-highlighting/#prism-) when your project requires both CSP and syntax highlighting.
752
- * - `unsafe-inline` directives are incompatible with Astro's CSP implementation. By default, Astro will emit hashes for all its bundled scripts (e.g. client islands) and all modern browsers will automatically reject `unsafe-inline` when it occurs in a directive with a hash or nonce.
752
+ * - When `'unsafe-inline'` is included as a resource in a directive, Astro will not emit hashes on that directive. Per the CSP spec, browsers ignore `'unsafe-inline'` when a hash or nonce is present in the same directive, so Astro suppresses hashes to preserve `'unsafe-inline'` behavior. Note that this reduces the security of that directive to the level of `'unsafe-inline'`.
753
753
  *
754
754
  * :::note
755
755
  * Due to the nature of the Vite dev server, this feature isn't supported while working in `dev` mode. Instead, you can test this in your Astro project using `build` and `preview`.
@@ -137,7 +137,7 @@ async function astroPluginRoutes({
137
137
  return true;
138
138
  });
139
139
  const code = `
140
- import { deserializeRouteInfo } from 'astro/app';
140
+ import { deserializeRouteInfo } from 'astro/app/manifest';
141
141
  const serializedData = ${JSON.stringify(filteredRoutes)};
142
142
  const routes = serializedData.map(deserializeRouteInfo);
143
143
  export { routes };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "astro",
3
- "version": "7.2.3",
3
+ "version": "7.2.5",
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",
@@ -103,7 +103,7 @@
103
103
  "README.md"
104
104
  ],
105
105
  "dependencies": {
106
- "@astrojs/compiler-rs": "^0.3.2",
106
+ "@astrojs/compiler-rs": "^0.4.0",
107
107
  "@capsizecss/unpack": "^4.0.0",
108
108
  "@clack/prompts": "^1.1.0",
109
109
  "@oslojs/encoding": "^1.1.0",
@@ -115,7 +115,7 @@
115
115
  "common-ancestor-path": "^2.0.0",
116
116
  "cookie": "^2.0.1",
117
117
  "devalue": "^5.8.1",
118
- "diff": "^8.0.3",
118
+ "diff": "^9.0.0",
119
119
  "dset": "^3.1.4",
120
120
  "es-module-lexer": "^2.0.0",
121
121
  "esbuild": "^0.28.0",
@@ -153,15 +153,15 @@
153
153
  "xxhash-wasm": "^1.1.0",
154
154
  "yargs-parser": "^22.0.0",
155
155
  "zod": "^4.3.6",
156
- "@astrojs/internal-helpers": "0.10.3",
157
- "@astrojs/markdown-satteri": "0.3.6",
156
+ "@astrojs/internal-helpers": "0.10.4",
157
+ "@astrojs/markdown-satteri": "0.3.8",
158
158
  "@astrojs/telemetry": "3.3.3"
159
159
  },
160
160
  "optionalDependencies": {
161
161
  "sharp": "^0.34.0 || ^0.35.0"
162
162
  },
163
163
  "peerDependencies": {
164
- "@astrojs/markdown-remark": "7.2.3"
164
+ "@astrojs/markdown-remark": "7.2.4"
165
165
  },
166
166
  "peerDependenciesMeta": {
167
167
  "@astrojs/markdown-remark": {
@@ -194,7 +194,7 @@
194
194
  "undici": "^7.22.0",
195
195
  "vitest": "^4.1.0",
196
196
  "@astrojs/check": "0.9.10",
197
- "@astrojs/markdown-remark": "7.2.3",
197
+ "@astrojs/markdown-remark": "7.2.4",
198
198
  "astro-scripts": "0.0.14"
199
199
  },
200
200
  "engines": {
@@ -13,7 +13,7 @@ export {
13
13
  defineLiveCollection,
14
14
  renderEntry as render,
15
15
  } from 'astro/content/runtime';
16
- // TODO: remove in Astro 7
16
+ // TODO: remove in Astro 8
17
17
  export { z } from 'astro/zod';
18
18
 
19
19
  /* @@LIVE_CONTENT_CONFIG@@ */
@@ -38,8 +38,8 @@ export const getLiveEntry = createGetLiveEntry({
38
38
  liveCollections,
39
39
  });
40
40
 
41
- // TODO: remove in Astro 7
41
+ // TODO: remove in Astro 8
42
42
  export const getEntryBySlug = createDeprecatedFunction('getEntryBySlug');
43
43
 
44
- // TODO: remove in Astro 7
44
+ // TODO: remove in Astro 8
45
45
  export const getDataEntryById = createDeprecatedFunction('getDataEntryById');
@@ -10,11 +10,11 @@ declare module 'astro:content' {
10
10
  } from 'astro/content/config';
11
11
  export { defineLiveCollection, defineCollection } from 'astro/content/config';
12
12
 
13
- // TODO: remove in Astro 7
13
+ // TODO: remove in Astro 8
14
14
  /**
15
15
  * @deprecated
16
16
  * `import { z } from 'astro:content'` is deprecated and will be removed
17
- * in Astro 7. Use `import { z } from 'astro/zod'` instead.
17
+ * in Astro 8. Use `import { z } from 'astro/zod'` instead.
18
18
  */
19
19
  export const z = zod.z;
20
20