astro 7.0.2 → 7.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/dist/actions/vite-plugin-actions.d.ts +1 -1
  2. package/dist/actions/vite-plugin-actions.js +27 -1
  3. package/dist/assets/services/sharp.js +1 -1
  4. package/dist/cli/infra/build-time-astro-version-provider.js +1 -1
  5. package/dist/content/content-layer.js +3 -3
  6. package/dist/content/vite-plugin-content-virtual-mod.js +5 -1
  7. package/dist/core/app/base.d.ts +1 -1
  8. package/dist/core/app/base.js +9 -2
  9. package/dist/core/app/dev/app.d.ts +5 -0
  10. package/dist/core/app/dev/app.js +7 -0
  11. package/dist/core/app/dev/pipeline.d.ts +1 -0
  12. package/dist/core/app/dev/pipeline.js +4 -0
  13. package/dist/core/app/entrypoints/virtual/dev.js +4 -0
  14. package/dist/core/app/node.js +7 -2
  15. package/dist/core/build/generate.js +1 -1
  16. package/dist/core/build/plugins/plugin-manifest.js +1 -1
  17. package/dist/core/constants.js +1 -1
  18. package/dist/core/dev/dev.js +1 -1
  19. package/dist/core/errors/default-handler.js +14 -3
  20. package/dist/core/i18n/domain.js +1 -1
  21. package/dist/core/messages/runtime.js +1 -1
  22. package/dist/core/output-filename.d.ts +3 -0
  23. package/dist/core/output-filename.js +20 -0
  24. package/dist/core/render/route-cache.d.ts +7 -2
  25. package/dist/core/routing/create-manifest.js +9 -7
  26. package/dist/core/routing/dev.js +15 -2
  27. package/dist/core/util.d.ts +0 -7
  28. package/dist/core/util.js +1 -19
  29. package/dist/i18n/error-routes.d.ts +4 -0
  30. package/dist/i18n/error-routes.js +26 -0
  31. package/dist/i18n/index.d.ts +0 -14
  32. package/dist/i18n/index.js +1 -24
  33. package/dist/i18n/path.d.ts +15 -0
  34. package/dist/i18n/path.js +26 -0
  35. package/dist/i18n/router.js +1 -1
  36. package/dist/i18n/utils.js +2 -1
  37. package/dist/runtime/client/dev-toolbar/apps/audit/rules/a11y.js +49 -9
  38. package/dist/runtime/server/hydration.js +1 -1
  39. package/dist/runtime/server/render/page.js +3 -2
  40. package/dist/virtual-modules/i18n.d.ts +2 -1
  41. package/dist/virtual-modules/i18n.js +6 -2
  42. package/dist/vite-plugin-app/app.d.ts +5 -0
  43. package/dist/vite-plugin-app/app.js +21 -1
  44. package/dist/vite-plugin-app/createAstroServerApp.js +4 -0
  45. package/dist/vite-plugin-app/pipeline.d.ts +1 -0
  46. package/dist/vite-plugin-app/pipeline.js +4 -0
  47. package/package.json +4 -21
@@ -1,5 +1,5 @@
1
1
  import type fsMod from 'node:fs';
2
- import type { Plugin as VitePlugin } from 'vite';
2
+ import { type Plugin as VitePlugin } from 'vite';
3
3
  import type { BuildInternals } from '../core/build/internal.js';
4
4
  import type { StaticBuildOptions } from '../core/build/types.js';
5
5
  import type { AstroSettings } from '../types/astro.js';
@@ -1,3 +1,7 @@
1
+ import { fileURLToPath } from "node:url";
2
+ import {
3
+ normalizePath as viteNormalizePath
4
+ } from "vite";
1
5
  import { shouldAppendForwardSlash } from "../core/build/util.js";
2
6
  import { getServerOutputDirectory } from "../prerender/utils.js";
3
7
  import {
@@ -27,11 +31,13 @@ function vitePluginActionsBuild(opts, internals) {
27
31
  }
28
32
  };
29
33
  }
34
+ const ACTIONS_DIR_NAME = "actions";
30
35
  function vitePluginActions({
31
36
  fs,
32
37
  settings
33
38
  }) {
34
39
  let resolvedActionsId;
40
+ const normalizedSrcDir = viteNormalizePath(fileURLToPath(settings.config.srcDir));
35
41
  return {
36
42
  name: VIRTUAL_MODULE_ID,
37
43
  enforce: "pre",
@@ -69,7 +75,27 @@ function vitePluginActions({
69
75
  }
70
76
  }
71
77
  server.watcher.on("add", watcherCallback);
72
- server.watcher.on("change", watcherCallback);
78
+ server.watcher.on("change", (path) => {
79
+ watcherCallback();
80
+ const normalizedPath = viteNormalizePath(path);
81
+ if (!normalizedPath.startsWith(normalizedSrcDir)) return;
82
+ const relativePath = normalizedPath.slice(normalizedSrcDir.length);
83
+ if (!relativePath.startsWith(`${ACTIONS_DIR_NAME}/`)) return;
84
+ for (const name of [
85
+ ASTRO_VITE_ENVIRONMENT_NAMES.ssr,
86
+ ASTRO_VITE_ENVIRONMENT_NAMES.astro
87
+ ]) {
88
+ const environment = server.environments[name];
89
+ if (!environment) continue;
90
+ const virtualMod = environment.moduleGraph.getModuleById(
91
+ ACTIONS_RESOLVED_ENTRYPOINT_VIRTUAL_MODULE_ID
92
+ );
93
+ if (virtualMod) {
94
+ environment.moduleGraph.invalidateModule(virtualMod);
95
+ }
96
+ environment.hot.send("astro:actions-updated", {});
97
+ }
98
+ });
73
99
  },
74
100
  load: {
75
101
  filter: {
@@ -110,7 +110,7 @@ const sharpService = {
110
110
  });
111
111
  }
112
112
  const result = sharp(inputBuffer, {
113
- failOnError: false,
113
+ failOn: "none",
114
114
  pages: -1,
115
115
  limitInputPixels: config.service.config.limitInputPixels
116
116
  });
@@ -1,6 +1,6 @@
1
1
  class BuildTimeAstroVersionProvider {
2
2
  // Injected during the build through esbuild define
3
- version = "7.0.2";
3
+ version = "7.0.4";
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.2") {
200
+ if (previousAstroVersion && previousAstroVersion !== "7.0.4") {
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.2") {
209
- this.#store.metaStore().set("astro-version", "7.0.2");
208
+ if ("7.0.4") {
209
+ this.#store.metaStore().set("astro-version", "7.0.4");
210
210
  }
211
211
  if (currentConfigDigest) {
212
212
  this.#store.metaStore().set("content-config-digest", currentConfigDigest);
@@ -23,6 +23,7 @@ import {
23
23
  } from "./consts.js";
24
24
  import { getDataStoreFile } from "./content-layer.js";
25
25
  import { getContentPaths, isDeferredModule } from "./utils.js";
26
+ const LARGE_DATA_STORE_THRESHOLD = 5 * 1024 * 1024;
26
27
  function invalidateAssetImports(viteServer, filePath) {
27
28
  const timestamp = Date.now();
28
29
  for (const environment of Object.values(viteServer.environments)) {
@@ -70,10 +71,12 @@ function astroContentVirtualModPlugin({
70
71
  let dataStoreFile;
71
72
  let devServer;
72
73
  let liveConfig;
74
+ let isDev = false;
73
75
  return {
74
76
  name: "astro-content-virtual-mod-plugin",
75
77
  enforce: "pre",
76
78
  config(_, env) {
79
+ isDev = env.command === "serve";
77
80
  dataStoreFile = getDataStoreFile(settings, env.command === "serve");
78
81
  const contentPaths = getContentPaths(
79
82
  settings.config,
@@ -169,8 +172,9 @@ function astroContentVirtualModPlugin({
169
172
  const jsonData = await fs.promises.readFile(dataStoreFile, "utf-8");
170
173
  try {
171
174
  const parsed = JSON.parse(jsonData);
175
+ const useRuntimeJsonParse = isDev && Buffer.byteLength(jsonData) > LARGE_DATA_STORE_THRESHOLD;
172
176
  return {
173
- code: dataToEsm(parsed, {
177
+ code: useRuntimeJsonParse ? `export default JSON.parse(${JSON.stringify(jsonData)})` : dataToEsm(parsed, {
174
178
  compact: true
175
179
  }),
176
180
  map: { mappings: "" }
@@ -86,7 +86,7 @@ export interface RenderErrorOptions extends ResolvedRenderOptions {
86
86
  */
87
87
  pathname?: string;
88
88
  }
89
- type ErrorPagePath = `${string}/404` | `${string}/500` | `${string}/404/` | `${string}/500/` | `${string}404.html` | `${string}500.html`;
89
+ type ErrorPagePath = `${string}/404` | `${string}/500` | `${string}/404/` | `${string}/500/` | `${string}/404/index.html` | `${string}/500/index.html` | `${string}404.html` | `${string}500.html`;
90
90
  export declare abstract class BaseApp<P extends Pipeline = AppPipeline> {
91
91
  #private;
92
92
  manifest: SSRManifest;
@@ -5,6 +5,7 @@ import {
5
5
  } from "@astrojs/internal-helpers/path";
6
6
  import { matchPattern } from "@astrojs/internal-helpers/remote";
7
7
  import { computePathnameFromDomain } from "../i18n/domain.js";
8
+ import { isLocalizedErrorRoute } from "../../i18n/error-routes.js";
8
9
  import { PipelineFeatures } from "../base-pipeline.js";
9
10
  import { ASTRO_ERROR_HEADER, clientAddressSymbol } from "../constants.js";
10
11
  import { getSetCookiesFromResponse } from "../cookies/index.js";
@@ -13,6 +14,7 @@ import { AstroIntegrationLogger } from "../logger/core.js";
13
14
  import { DefaultFetchHandler } from "../fetch/default-handler.js";
14
15
  import { appSymbol } from "../constants.js";
15
16
  import { DefaultErrorHandler } from "../errors/default-handler.js";
17
+ import { isRoute404, isRoute500 } from "../routing/internal/route-errors.js";
16
18
  import { setRenderOptions } from "./render-options.js";
17
19
  class BaseApp {
18
20
  manifest;
@@ -332,8 +334,13 @@ class BaseApp {
332
334
  }
333
335
  }
334
336
  const route = removeTrailingForwardSlash(routeData.route);
335
- if (route.endsWith("/404")) return 404;
336
- if (route.endsWith("/500")) return 500;
337
+ const locales = this.manifest.i18n?.locales;
338
+ if (isRoute404(route) || isLocalizedErrorRoute(route, 404, locales)) {
339
+ return 404;
340
+ }
341
+ if (isRoute500(route) || isLocalizedErrorRoute(route, 500, locales)) {
342
+ return 500;
343
+ }
337
344
  return 200;
338
345
  }
339
346
  getManifest() {
@@ -14,6 +14,11 @@ export declare class DevApp extends BaseApp<NonRunnablePipeline> {
14
14
  * Called via HMR when middleware files change.
15
15
  */
16
16
  clearMiddleware(): void;
17
+ /**
18
+ * Clears the cached actions so they are re-resolved on the next request.
19
+ * Called via HMR when action files change.
20
+ */
21
+ clearActions(): void;
17
22
  /**
18
23
  * Updates the routes list when files change during development.
19
24
  * Called via HMR when new pages are added/removed.
@@ -25,6 +25,13 @@ class DevApp extends BaseApp {
25
25
  clearMiddleware() {
26
26
  this.pipeline.clearMiddleware();
27
27
  }
28
+ /**
29
+ * Clears the cached actions so they are re-resolved on the next request.
30
+ * Called via HMR when action files change.
31
+ */
32
+ clearActions() {
33
+ this.pipeline.clearActions();
34
+ }
28
35
  /**
29
36
  * Updates the routes list when files change during development.
30
37
  * Called via HMR when new pages are added/removed.
@@ -9,6 +9,7 @@ export declare class NonRunnablePipeline extends Pipeline {
9
9
  getName(): string;
10
10
  static create({ logger, manifest, streaming }: DevPipelineCreate): NonRunnablePipeline;
11
11
  headElements(routeData: RouteData): Promise<HeadElements>;
12
+ clearActions(): void;
12
13
  componentMetadata(): void;
13
14
  getComponentByRoute(routeData: RouteData): Promise<ComponentInstance>;
14
15
  tryRewrite(payload: RewritePayload, request: Request): Promise<TryRewriteResult>;
@@ -94,6 +94,10 @@ class NonRunnablePipeline extends Pipeline {
94
94
  }
95
95
  return { scripts, styles, links };
96
96
  }
97
+ // Called via HMR when action files change. Not available on production environment.
98
+ clearActions() {
99
+ this.resolvedActions = void 0;
100
+ }
97
101
  componentMetadata() {
98
102
  }
99
103
  async getComponentByRoute(routeData) {
@@ -29,6 +29,10 @@ const createApp = ({ streaming } = {}) => {
29
29
  if (!currentDevApp) return;
30
30
  currentDevApp.clearMiddleware();
31
31
  });
32
+ import.meta.hot.on("astro:actions-updated", () => {
33
+ if (!currentDevApp) return;
34
+ currentDevApp.clearActions();
35
+ });
32
36
  }
33
37
  return currentDevApp;
34
38
  };
@@ -42,8 +42,13 @@ function createRequestFromNodeRequest(req, {
42
42
  protocol,
43
43
  allowedDomains
44
44
  );
45
- const forwardedHost = getFirstForwardedValue(req.headers["x-forwarded-host"]);
46
- const hostValidated = validatedHostname !== void 0 || forwardedHost !== void 0 && allowedDomains.length > 0;
45
+ const validatedForwardedHost = validateForwardedHeaders(
46
+ void 0,
47
+ getFirstForwardedValue(req.headers["x-forwarded-host"]),
48
+ void 0,
49
+ allowedDomains
50
+ ).host;
51
+ const hostValidated = validatedHostname !== void 0 || validatedForwardedHost !== void 0;
47
52
  const forwardedClientIp = hostValidated ? getFirstForwardedValue(req.headers["x-forwarded-for"]) : void 0;
48
53
  const clientIp = forwardedClientIp || req.socket?.remoteAddress;
49
54
  if (clientIp) {
@@ -24,7 +24,7 @@ import { createRequest } from "../request.js";
24
24
  import { redirectTemplate } from "../routing/3xx.js";
25
25
  import { routeIsRedirect } from "../routing/helpers.js";
26
26
  import { matchRoute } from "../routing/match.js";
27
- import { getOutputFilename } from "../util.js";
27
+ import { getOutputFilename } from "../output-filename.js";
28
28
  import { getOutFile, getOutFolder } from "./common.js";
29
29
  import { createDefaultPrerenderer } from "./default-prerenderer.js";
30
30
  import { hasPrerenderedPages } from "./internal.js";
@@ -1,7 +1,7 @@
1
1
  import { fileURLToPath } from "node:url";
2
2
  import { glob } from "tinyglobby";
3
3
  import { getAssetsPrefix } from "../../../assets/utils/getAssetsPrefix.js";
4
- import { normalizeTheLocale } from "../../../i18n/index.js";
4
+ import { normalizeTheLocale } from "../../../i18n/path.js";
5
5
  import { resolveMiddlewareMode } from "../../../integrations/adapter-utils.js";
6
6
  import { runHookBuildSsr } from "../../../integrations/hooks.js";
7
7
  import { SERIALIZED_MANIFEST_RESOLVED_ID } from "../../../manifest/serialized.js";
@@ -1,4 +1,4 @@
1
- const ASTRO_VERSION = "7.0.2";
1
+ const ASTRO_VERSION = "7.0.4";
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.2";
29
+ const currentVersion = "7.0.4";
30
30
  const isPrerelease = currentVersion.includes("-");
31
31
  if (!isPrerelease) {
32
32
  try {
@@ -7,6 +7,8 @@ import { PagesHandler } from "../pages/handler.js";
7
7
  import { matchRoute } from "../routing/match.js";
8
8
  import { provideSession } from "../session/handler.js";
9
9
  import { validateHost } from "../app/validate-headers.js";
10
+ import { getErrorRoutePath } from "../../i18n/error-routes.js";
11
+ import { getOutputFilename } from "../output-filename.js";
10
12
  class DefaultErrorHandler {
11
13
  #app;
12
14
  #astroMiddleware;
@@ -26,17 +28,26 @@ class DefaultErrorHandler {
26
28
  }) {
27
29
  const app = this.#app;
28
30
  const resolvedPathname = pathname ?? new FetchState(app.pipeline, request).pathname;
29
- const errorRoutePath = `/${status}${app.manifest.trailingSlash === "always" ? "/" : ""}`;
31
+ const errorRoutePath = getErrorRoutePath(
32
+ resolvedPathname,
33
+ status,
34
+ app.manifestData.routes,
35
+ app.manifest.i18n?.locales,
36
+ app.manifest.trailingSlash === "always"
37
+ );
30
38
  const errorRouteData = matchRoute(errorRoutePath, app.manifestData);
31
39
  const url = new URL(request.url);
32
40
  if (errorRouteData) {
33
41
  if (errorRouteData.prerender) {
34
- const maybeDotHtml = errorRouteData.route.endsWith(`/${status}`) ? ".html" : "";
35
42
  const allowedDomains = app.manifest.allowedDomains;
36
43
  const validatedHost = validateHost(url.host, url.protocol.replace(":", ""), allowedDomains);
37
44
  const safeOrigin = validatedHost ? url.origin : `${url.protocol}//localhost`;
38
45
  const statusURL = new URL(
39
- `${app.baseWithoutTrailingSlash}/${status}${maybeDotHtml}`,
46
+ `${app.baseWithoutTrailingSlash}${getOutputFilename(
47
+ app.manifest.buildFormat,
48
+ errorRouteData.route,
49
+ errorRouteData
50
+ )}`,
40
51
  safeOrigin
41
52
  );
42
53
  if (statusURL.toString() !== request.url && resolvedRenderOptions.prerenderedErrorPageFetch) {
@@ -5,7 +5,7 @@ import {
5
5
  prependForwardSlash,
6
6
  removeTrailingForwardSlash
7
7
  } from "@astrojs/internal-helpers/path";
8
- import { normalizeTheLocale } from "../../i18n/index.js";
8
+ import { normalizeTheLocale } from "../../i18n/path.js";
9
9
  function computePathnameFromDomain(request, url, i18n, base, trailingSlash, logger) {
10
10
  let pathname = void 0;
11
11
  if (i18n && (i18n.strategy === "domains-prefix-always" || i18n.strategy === "domains-prefix-other-locales" || i18n.strategy === "domains-prefix-always-no-redirect")) {
@@ -269,7 +269,7 @@ function printHelp({
269
269
  message.push(
270
270
  linebreak(),
271
271
  ` ${bgGreen(black(` ${commandName} `))} ${green(
272
- `v${"7.0.2"}`
272
+ `v${"7.0.4"}`
273
273
  )} ${headline}`
274
274
  );
275
275
  }
@@ -0,0 +1,3 @@
1
+ import type { AstroConfig } from '../types/public/config.js';
2
+ import type { RouteData } from '../types/public/internal.js';
3
+ export declare function getOutputFilename(buildFormat: NonNullable<AstroConfig['build']>['format'], name: string, routeData: RouteData): string;
@@ -0,0 +1,20 @@
1
+ import { removeTrailingForwardSlash } from "./path.js";
2
+ const STATUS_CODE_PAGES = /* @__PURE__ */ new Set(["/404", "/500"]);
3
+ function getOutputFilename(buildFormat, name, routeData) {
4
+ if (routeData.type === "endpoint") {
5
+ return name;
6
+ }
7
+ if (name === "/" || name === "") {
8
+ return name === "" ? "index.html" : "/index.html";
9
+ }
10
+ if (buildFormat === "file" || STATUS_CODE_PAGES.has(name)) {
11
+ return `${removeTrailingForwardSlash(name || "index")}.html`;
12
+ }
13
+ if (buildFormat === "preserve" && !routeData.isIndex) {
14
+ return `${removeTrailingForwardSlash(name || "index")}.html`;
15
+ }
16
+ return `${removeTrailingForwardSlash(name)}/index.html`;
17
+ }
18
+ export {
19
+ getOutputFilename
20
+ };
@@ -18,8 +18,13 @@ interface RouteCacheEntry {
18
18
  }
19
19
  /**
20
20
  * Manage the route cache, responsible for caching data related to each route,
21
- * including the result of calling getStaticPath() so that it can be reused across
22
- * responses during dev and only ever called once during build.
21
+ * including the result of calling getStaticPaths(). This gives route matching,
22
+ * params/props resolution, and prerender generation a shared static-path table.
23
+ *
24
+ * In dev, this cache intentionally survives requests. It is invalidated by route
25
+ * module identity changes after HMR or by explicit cache clears from content data
26
+ * changes, not by each request. Dev route matching can call getStaticPaths()
27
+ * before rendering, and render-time props resolution may ask for it again.
23
28
  */
24
29
  export declare class RouteCache {
25
30
  private logger;
@@ -158,13 +158,14 @@ function createFileBasedRoutes({ settings, cwd, fsMod }, logger) {
158
158
  } else {
159
159
  const component = item.file;
160
160
  const pathname = segments.every((segment) => segment.length === 1 && !segment[0].dynamic) ? `/${segments.map((segment) => segment[0].content).join("/")}` : null;
161
+ const route = joinSegments(segments);
161
162
  const trailingSlash = trailingSlashForPath(
162
163
  pathname,
163
164
  settings.config,
164
- item.isPage ? "page" : "endpoint"
165
+ item.isPage ? "page" : "endpoint",
166
+ route
165
167
  );
166
168
  const pattern = getPattern(segments, settings.config.base, trailingSlash);
167
- const route = joinSegments(segments);
168
169
  routes.push({
169
170
  route,
170
171
  isIndex: item.isIndex,
@@ -277,13 +278,14 @@ function createRoutesFromEntriesByDir(entriesByDir, settings, logger, pagesDirRe
277
278
  } else {
278
279
  const component = item.file;
279
280
  const pathname = segments.every((segment) => segment.length === 1 && !segment[0].dynamic) ? `/${segments.map((segment) => segment[0].content).join("/")}` : null;
281
+ const route = joinSegments(segments);
280
282
  const trailingSlash = trailingSlashForPath(
281
283
  pathname,
282
284
  settings.config,
283
- item.isPage ? "page" : "endpoint"
285
+ item.isPage ? "page" : "endpoint",
286
+ route
284
287
  );
285
288
  const pattern = getPattern(segments, settings.config.base, trailingSlash);
286
- const route = joinSegments(segments);
287
289
  routes.push({
288
290
  route,
289
291
  isIndex: item.isIndex,
@@ -320,7 +322,7 @@ function groupEntriesByDir(entries) {
320
322
  }
321
323
  return entriesByDir;
322
324
  }
323
- const trailingSlashForPath = (pathname, config, type) => type === "endpoint" && pathname && hasFileExtension(pathname) ? "never" : config.trailingSlash;
325
+ const trailingSlashForPath = (pathname, config, type, route) => type === "endpoint" && hasFileExtension(pathname ?? route ?? "") ? "never" : config.trailingSlash;
324
326
  function createInjectedRoutes({ settings, cwd }) {
325
327
  const { config } = settings;
326
328
  const prerender = getPrerenderDefault(config);
@@ -334,10 +336,10 @@ function createInjectedRoutes({ settings, cwd }) {
334
336
  });
335
337
  const type = resolved.endsWith(".astro") ? "page" : "endpoint";
336
338
  const pathname = segments.every((segment) => segment.length === 1 && !segment[0].dynamic) ? `/${segments.map((segment) => segment[0].content).join("/")}` : null;
337
- const trailingSlash = trailingSlashForPath(pathname, config, type);
339
+ const route = joinSegments(segments);
340
+ const trailingSlash = trailingSlashForPath(pathname, config, type, route);
338
341
  const pattern = getPattern(segments, settings.config.base, trailingSlash);
339
342
  const params = segments.flat().filter((p) => p.dynamic).map((p) => p.content);
340
- const route = joinSegments(segments);
341
343
  routes.push({
342
344
  type,
343
345
  // For backwards compatibility, an injected route is never considered an index route.
@@ -4,6 +4,7 @@ import { getProps } from "../render/index.js";
4
4
  import { getCustom404Route } from "./helpers.js";
5
5
  import { NoMatchingStaticPathFound } from "../errors/errors-data.js";
6
6
  import { isAstroError } from "../errors/errors.js";
7
+ import { getErrorRoutePath } from "../../i18n/error-routes.js";
7
8
  async function matchRoute(pathname, routesList, pipeline, manifest) {
8
9
  const { logger, routeCache } = pipeline;
9
10
  const matches = matchAllRoutes(pathname, routesList);
@@ -11,6 +12,7 @@ async function matchRoute(pathname, routesList, pipeline, manifest) {
11
12
  matches,
12
13
  manifest
13
14
  });
15
+ let firstError = null;
14
16
  for await (const { route: maybeRoute, filePath } of preloadedMatches) {
15
17
  try {
16
18
  await getProps({
@@ -32,9 +34,13 @@ async function matchRoute(pathname, routesList, pipeline, manifest) {
32
34
  if (isAstroError(e) && e.title === NoMatchingStaticPathFound.title) {
33
35
  continue;
34
36
  }
35
- throw e;
37
+ firstError ??= e;
38
+ continue;
36
39
  }
37
40
  }
41
+ if (firstError) {
42
+ throw firstError;
43
+ }
38
44
  const altPathname = pathname.replace(/\/index\.html$/, "/").replace(/\.html$/, "");
39
45
  if (altPathname !== pathname) {
40
46
  return await matchRoute(altPathname, routesList, pipeline, manifest);
@@ -50,7 +56,14 @@ async function matchRoute(pathname, routesList, pipeline, manifest) {
50
56
  ${NoMatchingStaticPathFound.hint(possibleRoutes)}`
51
57
  );
52
58
  }
53
- const custom404 = getCustom404Route(routesList);
59
+ const errorRoutePath = getErrorRoutePath(
60
+ pathname,
61
+ 404,
62
+ routesList.routes,
63
+ manifest.i18n?.locales,
64
+ manifest.trailingSlash === "always"
65
+ );
66
+ const custom404 = routesList.routes.find((route) => route.route === errorRoutePath) ?? getCustom404Route(routesList);
54
67
  if (custom404) {
55
68
  const filePath = new URL(`./${custom404.component}`, manifest.rootDir);
56
69
  return {
@@ -1,16 +1,9 @@
1
1
  import type { AstroSettings } from '../types/astro.js';
2
2
  import type { AstroConfig } from '../types/public/config.js';
3
- import type { RouteData } from '../types/public/internal.js';
4
3
  /** Check if a file is a markdown file based on its extension */
5
4
  export declare function isMarkdownFile(fileId: string, option?: {
6
5
  suffix?: string;
7
6
  }): boolean;
8
- /**
9
- * Get the correct output filename for a route, based on your config.
10
- * Handles both "/foo" and "foo" `name` formats.
11
- * Handles `/404` and `/` correctly.
12
- */
13
- export declare function getOutputFilename(buildFormat: NonNullable<AstroConfig['build']>['format'], name: string, routeData: RouteData): string;
14
7
  /** is a specifier an npm package? */
15
8
  export declare function parseNpmName(spec: string): {
16
9
  scope?: string;
package/dist/core/util.js CHANGED
@@ -1,9 +1,8 @@
1
1
  import fs from "node:fs";
2
- import path from "node:path";
3
2
  import { fileURLToPath } from "node:url";
4
3
  import { hasSpecialQueries } from "../vite-plugin-utils/index.js";
5
4
  import { SUPPORTED_MARKDOWN_FILE_EXTENSIONS } from "./constants.js";
6
- import { removeQueryString, removeTrailingForwardSlash, slash } from "./path.js";
5
+ import { removeQueryString, slash } from "./path.js";
7
6
  function isMarkdownFile(fileId, option) {
8
7
  if (hasSpecialQueries(fileId)) {
9
8
  return false;
@@ -15,22 +14,6 @@ function isMarkdownFile(fileId, option) {
15
14
  }
16
15
  return false;
17
16
  }
18
- const STATUS_CODE_PAGES = /* @__PURE__ */ new Set(["/404", "/500"]);
19
- function getOutputFilename(buildFormat, name, routeData) {
20
- if (routeData.type === "endpoint") {
21
- return name;
22
- }
23
- if (name === "/" || name === "") {
24
- return path.posix.join(name, "index.html");
25
- }
26
- if (buildFormat === "file" || STATUS_CODE_PAGES.has(name)) {
27
- return `${removeTrailingForwardSlash(name || "index")}.html`;
28
- }
29
- if (buildFormat === "preserve" && !routeData.isIndex) {
30
- return `${removeTrailingForwardSlash(name || "index")}.html`;
31
- }
32
- return path.posix.join(name, "index.html");
33
- }
34
17
  function parseNpmName(spec) {
35
18
  if (!spec || spec[0] === "." || spec[0] === "/") return void 0;
36
19
  let scope;
@@ -119,7 +102,6 @@ function ensureProcessNodeEnv(defaultNodeEnv) {
119
102
  export {
120
103
  VALID_ID_PREFIX,
121
104
  ensureProcessNodeEnv,
122
- getOutputFilename,
123
105
  isEndpoint,
124
106
  isMarkdownFile,
125
107
  isPage,
@@ -0,0 +1,4 @@
1
+ import type { SSRManifest } from '../core/app/types.js';
2
+ import type { Locales } from '../types/public/config.js';
3
+ export declare function isLocalizedErrorRoute(route: string, status: 404 | 500, locales: Locales | undefined): boolean;
4
+ export declare function getErrorRoutePath(pathname: string, status: 404 | 500, routes: Pick<SSRManifest['routes'][number]['routeData'], 'route'>[], locales: Locales | undefined, appendTrailingSlash?: boolean): string;
@@ -0,0 +1,26 @@
1
+ import { pathHasLocale } from "./path.js";
2
+ function isLocalizedErrorRoute(route, status, locales) {
3
+ if (!locales) return false;
4
+ const suffix = `/${status}`;
5
+ if (!route.endsWith(suffix)) return false;
6
+ const localeSegment = route.slice(0, -suffix.length);
7
+ if (!localeSegment || localeSegment.includes("/", 1)) return false;
8
+ return pathHasLocale(localeSegment, locales);
9
+ }
10
+ function getErrorRoutePath(pathname, status, routes, locales, appendTrailingSlash = false) {
11
+ const suffix = appendTrailingSlash ? "/" : "";
12
+ if (locales) {
13
+ const firstSegment = pathname.split("/").find(Boolean);
14
+ if (firstSegment && pathHasLocale(`/${firstSegment}`, locales)) {
15
+ const localized = `/${firstSegment}/${status}`;
16
+ if (routes.some((route) => route.route === localized)) {
17
+ return `${localized}${suffix}`;
18
+ }
19
+ }
20
+ }
21
+ return `/${status}${suffix}`;
22
+ }
23
+ export {
24
+ getErrorRoutePath,
25
+ isLocalizedErrorRoute
26
+ };
@@ -3,7 +3,6 @@ import type { SSRManifest } from '../core/app/types.js';
3
3
  import type { AstroConfig, Locales, ValidRedirectStatus } from '../types/public/config.js';
4
4
  import type { APIContext } from '../types/public/context.js';
5
5
  export declare function requestHasLocale(locales: Locales): (context: APIContext) => boolean;
6
- export declare function pathHasLocale(path: string, locales: Locales): boolean;
7
6
  type GetLocaleRelativeUrl = GetLocaleOptions & {
8
7
  locale: string;
9
8
  base: string;
@@ -67,19 +66,6 @@ export declare function getPathByLocale(locale: string, locales: Locales): strin
67
66
  * @param locales
68
67
  */
69
68
  export declare function getLocaleByPath(path: string, locales: Locales): string;
70
- /**
71
- *
72
- * Given a locale, this function:
73
- * - replaces the `_` with a `-`;
74
- * - transforms all letters to be lowercase;
75
- */
76
- export declare function normalizeTheLocale(locale: string): string;
77
- /**
78
- *
79
- * Given a path or path segment, this function:
80
- * - removes the `.html` extension if it exists
81
- */
82
- export declare function normalizeThePath(path: string): string;
83
69
  /**
84
70
  * Returns an array of only locales, by picking the `code`
85
71
  * @param locales
@@ -8,26 +8,12 @@ import { getFetchStateFromAPIContext } from "../core/fetch/fetch-state.js";
8
8
  import { i18nNoLocaleFoundInPath, MissingLocale } from "../core/errors/errors-data.js";
9
9
  import { AstroError } from "../core/errors/index.js";
10
10
  import { createI18nMiddleware } from "./middleware.js";
11
+ import { normalizeTheLocale, pathHasLocale } from "./path.js";
11
12
  function requestHasLocale(locales) {
12
13
  return function(context) {
13
14
  return pathHasLocale(context.url.pathname, locales);
14
15
  };
15
16
  }
16
- function pathHasLocale(path, locales) {
17
- const segments = path.split("/").map(normalizeThePath);
18
- for (const segment of segments) {
19
- for (const locale of locales) {
20
- if (typeof locale === "string") {
21
- if (normalizeTheLocale(segment) === normalizeTheLocale(locale)) {
22
- return true;
23
- }
24
- } else if (segment === locale.path) {
25
- return true;
26
- }
27
- }
28
- }
29
- return false;
30
- }
31
17
  function getLocaleRelativeUrl({
32
18
  locale,
33
19
  base,
@@ -133,12 +119,6 @@ function getLocaleByPath(path, locales) {
133
119
  }
134
120
  throw new AstroError(i18nNoLocaleFoundInPath);
135
121
  }
136
- function normalizeTheLocale(locale) {
137
- return locale.replaceAll("_", "-").toLowerCase();
138
- }
139
- function normalizeThePath(path) {
140
- return path.endsWith(".html") ? path.slice(0, -5) : path;
141
- }
142
122
  function getAllCodes(locales) {
143
123
  const result = [];
144
124
  for (const loopLocale of locales) {
@@ -281,10 +261,7 @@ export {
281
261
  getLocaleRelativeUrl,
282
262
  getLocaleRelativeUrlList,
283
263
  getPathByLocale,
284
- normalizeTheLocale,
285
- normalizeThePath,
286
264
  notFound,
287
- pathHasLocale,
288
265
  redirectToDefaultLocale,
289
266
  redirectToFallback,
290
267
  requestHasLocale,
@@ -0,0 +1,15 @@
1
+ import type { Locales } from '../types/public/config.js';
2
+ export declare function pathHasLocale(path: string, locales: Locales): boolean;
3
+ /**
4
+ *
5
+ * Given a locale, this function:
6
+ * - replaces the `_` with a `-`;
7
+ * - transforms all letters to be lowercase;
8
+ */
9
+ export declare function normalizeTheLocale(locale: string): string;
10
+ /**
11
+ *
12
+ * Given a path or path segment, this function:
13
+ * - removes the `.html` extension if it exists
14
+ */
15
+ export declare function normalizeThePath(path: string): string;
@@ -0,0 +1,26 @@
1
+ function pathHasLocale(path, locales) {
2
+ const segments = path.split("/").map(normalizeThePath);
3
+ for (const segment of segments) {
4
+ for (const locale of locales) {
5
+ if (typeof locale === "string") {
6
+ if (normalizeTheLocale(segment) === normalizeTheLocale(locale)) {
7
+ return true;
8
+ }
9
+ } else if (segment === locale.path) {
10
+ return true;
11
+ }
12
+ }
13
+ }
14
+ return false;
15
+ }
16
+ function normalizeTheLocale(locale) {
17
+ return locale.replaceAll("_", "-").toLowerCase();
18
+ }
19
+ function normalizeThePath(path) {
20
+ return path.endsWith(".html") ? path.slice(0, -5) : path;
21
+ }
22
+ export {
23
+ normalizeTheLocale,
24
+ normalizeThePath,
25
+ pathHasLocale
26
+ };
@@ -1,5 +1,5 @@
1
1
  import { removeTrailingForwardSlash } from "@astrojs/internal-helpers/path";
2
- import { normalizeTheLocale, pathHasLocale } from "./index.js";
2
+ import { normalizeTheLocale, pathHasLocale } from "./path.js";
3
3
  class I18nRouter {
4
4
  #strategy;
5
5
  #defaultLocale;
@@ -1,4 +1,5 @@
1
- import { getAllCodes, normalizeTheLocale, normalizeThePath } from "./index.js";
1
+ import { getAllCodes } from "./index.js";
2
+ import { normalizeTheLocale, normalizeThePath } from "./path.js";
2
3
  function parseLocale(header) {
3
4
  if (header === "*") {
4
5
  return [{ locale: header, qualityValue: void 0 }];
@@ -200,6 +200,32 @@ function isInteractive(element) {
200
200
  }
201
201
  return true;
202
202
  }
203
+ function hasAccessibleName(element) {
204
+ return element.hasAttribute("aria-label") || element.hasAttribute("aria-labelledby");
205
+ }
206
+ const conditional_implicit_roles = /* @__PURE__ */ new Map([
207
+ ["a", (el) => el.hasAttribute("href") ? "link" : null],
208
+ [
209
+ "aside",
210
+ (el) => {
211
+ const isNested = !!el.parentElement?.closest("article, aside, nav, section");
212
+ return !isNested || hasAccessibleName(el) ? "complementary" : null;
213
+ }
214
+ ],
215
+ [
216
+ "img",
217
+ (el) => {
218
+ if (el.getAttribute("alt") === "") return null;
219
+ return "image";
220
+ }
221
+ ],
222
+ [
223
+ "section",
224
+ (el) => {
225
+ return hasAccessibleName(el) ? "region" : null;
226
+ }
227
+ ]
228
+ ]);
203
229
  const a11y = [
204
230
  {
205
231
  code: "a11y-accesskey",
@@ -378,19 +404,33 @@ const a11y = [
378
404
  code: "a11y-no-redundant-roles",
379
405
  title: "HTML element has redundant ARIA roles",
380
406
  message: "Giving these elements an ARIA role that is already set by the browser has no effect and is redundant.",
381
- selector: [...a11y_implicit_semantics.keys()].join(","),
407
+ // The selector is all elements that have an implicit role, as well as input elements since their implicit role can change based on their attributes
408
+ selector: `[role]:is(${[...a11y_implicit_semantics.keys()].join(",")},input)`,
382
409
  match(element) {
383
410
  const role = element.getAttribute("role");
384
- if (element.localName === "input") {
385
- const type = element.getAttribute("type");
386
- if (!type) return true;
411
+ if (!role) return false;
412
+ const localName = element.localName;
413
+ if (
414
+ // <ul>, <ol>, and <li> are legitimate workarounds to restore list semantics
415
+ // that some browsers (e.g., Safari) strip when CSS `list-style: none` is applied.
416
+ // Reference: https://bugs.webkit.org/show_bug.cgi?id=170179
417
+ localName === "ul" && role === "list" || localName === "ol" && role === "list" || localName === "li" && role === "listitem"
418
+ ) {
419
+ return false;
420
+ }
421
+ if (localName === "input") {
422
+ const type = element.getAttribute("type") || "text";
387
423
  const implicitRoleForType = input_type_to_implicit_role.get(type);
388
- if (!implicitRoleForType) return true;
389
- if (role === implicitRoleForType) return false;
424
+ return role === implicitRoleForType;
425
+ }
426
+ const getConditionalRole = conditional_implicit_roles.get(localName);
427
+ if (getConditionalRole) {
428
+ const effectiveRole = getConditionalRole(element);
429
+ return effectiveRole ? role === effectiveRole : false;
390
430
  }
391
- const implicitRole = a11y_implicit_semantics.get(element.localName);
392
- if (!implicitRole) return true;
393
- if (role === implicitRole) return false;
431
+ const implicitRole = a11y_implicit_semantics.get(localName);
432
+ if (!implicitRole) return false;
433
+ return role === implicitRole;
394
434
  }
395
435
  },
396
436
  {
@@ -116,7 +116,7 @@ async function generateHydrateScript(scriptOptions, metadata) {
116
116
  );
117
117
  transitionDirectivesToCopyOnIsland.forEach((name) => {
118
118
  if (typeof props[name] !== "undefined") {
119
- island.props[name] = props[name];
119
+ island.props[name] = escapeHTML(String(props[name]));
120
120
  }
121
121
  });
122
122
  return island;
@@ -1,3 +1,4 @@
1
+ import { isRoute404, isRoute500 } from "../../../core/routing/internal/route-errors.js";
1
2
  import { renderToAsyncIterable, renderToReadableStream, renderToString } from "./astro/render.js";
2
3
  import { encoder } from "./common.js";
3
4
  import { renderComponentToString } from "./component.js";
@@ -61,12 +62,12 @@ async function renderPage(result, componentFactory, props, children, streaming,
61
62
  }
62
63
  let status = init.status;
63
64
  let statusText = init.statusText;
64
- if (route?.route === "/404") {
65
+ if (route?.route && isRoute404(route.route)) {
65
66
  status = 404;
66
67
  if (statusText === "OK") {
67
68
  statusText = "Not Found";
68
69
  }
69
- } else if (route?.route === "/500") {
70
+ } else if (route?.route && isRoute500(route.route)) {
70
71
  status = 500;
71
72
  if (statusText === "OK") {
72
73
  statusText = "Internal Server Error";
@@ -1,5 +1,6 @@
1
1
  import type { RedirectToFallback } from '../i18n/index.js';
2
2
  import * as I18nInternals from '../i18n/index.js';
3
+ import { normalizeTheLocale as normalizeTheLocaleInternal } from '../i18n/path.js';
3
4
  import type { MiddlewareHandler } from '../types/public/common.js';
4
5
  import type { AstroConfig, ValidRedirectStatus } from '../types/public/config.js';
5
6
  import type { APIContext } from '../types/public/context.js';
@@ -249,7 +250,7 @@ export declare let middleware: (customOptions: I18nMiddlewareOptions) => Middlew
249
250
  * normalizeTheLocale("it_VT") // returns `it-vt`
250
251
  * ```
251
252
  */
252
- export declare const normalizeTheLocale: typeof I18nInternals.normalizeTheLocale;
253
+ export declare const normalizeTheLocale: typeof normalizeTheLocaleInternal;
253
254
  /**
254
255
  * Retrieves the configured locale codes for each locale defined in your
255
256
  * configuration. When multiple codes are associated to a locale, only the
@@ -7,6 +7,10 @@ import {
7
7
  } from "../core/errors/errors-data.js";
8
8
  import { AstroError } from "../core/errors/index.js";
9
9
  import * as I18nInternals from "../i18n/index.js";
10
+ import {
11
+ normalizeTheLocale as normalizeTheLocaleInternal,
12
+ pathHasLocale as pathHasLocaleInternal
13
+ } from "../i18n/path.js";
10
14
  const { trailingSlash, site, i18n, build } = config;
11
15
  const { format } = build;
12
16
  const isBuild = import.meta.env.PROD;
@@ -72,7 +76,7 @@ const getAbsoluteLocaleUrlList = (path, options) => I18nInternals.getLocaleAbsol
72
76
  });
73
77
  const getPathByLocale = (locale) => I18nInternals.getPathByLocale(locale, locales);
74
78
  const getLocaleByPath = (path) => I18nInternals.getLocaleByPath(path, locales);
75
- const pathHasLocale = (path) => I18nInternals.pathHasLocale(path, locales);
79
+ const pathHasLocale = (path) => pathHasLocaleInternal(path, locales);
76
80
  let redirectToDefaultLocale;
77
81
  if (i18n?.routing === "manual") {
78
82
  redirectToDefaultLocale = I18nInternals.redirectToDefaultLocale({
@@ -149,7 +153,7 @@ if (i18n?.routing === "manual") {
149
153
  } else {
150
154
  middleware = noop("middleware");
151
155
  }
152
- const normalizeTheLocale = I18nInternals.normalizeTheLocale;
156
+ const normalizeTheLocale = normalizeTheLocaleInternal;
153
157
  const toCodes = I18nInternals.toCodes;
154
158
  const toPaths = I18nInternals.toPaths;
155
159
  export {
@@ -30,6 +30,11 @@ export declare class AstroServerApp extends BaseApp<RunnablePipeline> {
30
30
  * Called via HMR when middleware files change.
31
31
  */
32
32
  clearMiddleware(): void;
33
+ /**
34
+ * Clears the cached actions so they are re-resolved on the next request.
35
+ * Called via HMR when action files change.
36
+ */
37
+ clearActions(): void;
33
38
  devMatch(pathname: string): Promise<DevMatch | undefined>;
34
39
  static create(manifest: SSRManifest, routesList: RoutesList, logger: AstroLogger, loader: ModuleLoader, settings: AstroSettings, getDebugInfo: () => Promise<string>): Promise<AstroServerApp>;
35
40
  createPipeline(_streaming: boolean, manifest: SSRManifest, settings: AstroSettings, logger: AstroLogger, loader: ModuleLoader, manifestData: RoutesList, getDebugInfo: () => Promise<string>): RunnablePipeline;
@@ -63,6 +63,13 @@ class AstroServerApp extends BaseApp {
63
63
  clearMiddleware() {
64
64
  this.pipeline.clearMiddleware();
65
65
  }
66
+ /**
67
+ * Clears the cached actions so they are re-resolved on the next request.
68
+ * Called via HMR when action files change.
69
+ */
70
+ clearActions() {
71
+ this.pipeline.clearActions();
72
+ }
66
73
  async devMatch(pathname) {
67
74
  const matchedRoute = await matchRoute(
68
75
  pathname,
@@ -148,6 +155,18 @@ class AstroServerApp extends BaseApp {
148
155
  });
149
156
  body = Buffer.concat(bytes);
150
157
  }
158
+ const abortController = new AbortController();
159
+ const socket = incomingRequest.socket;
160
+ const onSocketClose = () => {
161
+ if (!abortController.signal.aborted) {
162
+ abortController.abort();
163
+ }
164
+ };
165
+ if (socket.destroyed) {
166
+ onSocketClose();
167
+ } else {
168
+ socket.on("close", onSocketClose);
169
+ }
151
170
  const request = createRequest({
152
171
  url,
153
172
  headers: incomingRequest.headers,
@@ -155,7 +174,8 @@ class AstroServerApp extends BaseApp {
155
174
  body,
156
175
  logger: self.logger,
157
176
  isPrerendered: matchedRoute.routeData.prerender,
158
- routePattern: matchedRoute.routeData.component
177
+ routePattern: matchedRoute.routeData.component,
178
+ init: { signal: abortController.signal }
159
179
  });
160
180
  const locals = Reflect.get(incomingRequest, clientLocalsSymbol);
161
181
  for (const [name, value] of Object.entries(self.settings.config.server.headers ?? {})) {
@@ -58,6 +58,10 @@ async function createAstroServerApp(controller, settings, loader, logger) {
58
58
  app.clearMiddleware();
59
59
  actualLogger.debug("router", "Middleware cache cleared due to file change");
60
60
  });
61
+ import.meta.hot.on("astro:actions-updated", () => {
62
+ app.clearActions();
63
+ actualLogger.debug("router", "Actions cache cleared due to file change");
64
+ });
61
65
  }
62
66
  return {
63
67
  handler(incomingRequest, incomingResponse, options) {
@@ -14,6 +14,7 @@ export declare class RunnablePipeline extends Pipeline {
14
14
  readonly getDebugInfo: () => Promise<string>;
15
15
  private constructor();
16
16
  static create(manifestData: RoutesList, { loader, logger, manifest, settings, getDebugInfo, }: Pick<RunnablePipeline, 'loader' | 'logger' | 'manifest' | 'settings' | 'getDebugInfo'>): RunnablePipeline;
17
+ clearActions(): void;
17
18
  headElements(routeData: RouteData): Promise<HeadElements>;
18
19
  componentMetadata(routeData: RouteData): Promise<Map<string, import("../types/public/internal.js").SSRComponentMetadata>>;
19
20
  preload(routeData: RouteData, filePath: URL): Promise<ComponentInstance>;
@@ -57,6 +57,10 @@ class RunnablePipeline extends Pipeline {
57
57
  pipeline.routesList = manifestData;
58
58
  return pipeline;
59
59
  }
60
+ // Called via HMR when action files change. Not available on production.
61
+ clearActions() {
62
+ this.resolvedActions = void 0;
63
+ }
60
64
  async headElements(routeData) {
61
65
  const { manifest, runtimeMode, settings } = this;
62
66
  const filePath = new URL(`${routeData.component}`, manifest.rootDir);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "astro",
3
- "version": "7.0.2",
3
+ "version": "7.0.4",
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",
@@ -12,23 +12,6 @@
12
12
  },
13
13
  "bugs": "https://github.com/withastro/astro/issues",
14
14
  "homepage": "https://astro.build",
15
- "types": "./dist/index.d.ts",
16
- "typesVersions": {
17
- "*": {
18
- "app": [
19
- "./dist/core/app/index"
20
- ],
21
- "app/*": [
22
- "./dist/core/app/*"
23
- ],
24
- "hono": [
25
- "./dist/core/hono/index"
26
- ],
27
- "middleware": [
28
- "./dist/virtual-modules/middleware.d.ts"
29
- ]
30
- }
31
- },
32
15
  "exports": {
33
16
  ".": "./dist/index.js",
34
17
  "./env": "./env.d.ts",
@@ -113,7 +96,7 @@
113
96
  "README.md"
114
97
  ],
115
98
  "dependencies": {
116
- "@astrojs/compiler-rs": "^0.2.2",
99
+ "@astrojs/compiler-rs": "^0.3.0",
117
100
  "@capsizecss/unpack": "^4.0.0",
118
101
  "@clack/prompts": "^1.1.0",
119
102
  "@oslojs/encoding": "^1.1.0",
@@ -136,8 +119,8 @@
136
119
  "github-slugger": "^2.0.0",
137
120
  "html-escaper": "3.0.3",
138
121
  "http-cache-semantics": "^4.2.0",
139
- "jsonc-parser": "^3.3.1",
140
122
  "js-yaml": "^4.1.1",
123
+ "jsonc-parser": "^3.3.1",
141
124
  "magic-string": "^0.30.21",
142
125
  "magicast": "^0.5.2",
143
126
  "mrmime": "^2.0.1",
@@ -171,7 +154,7 @@
171
154
  "@astrojs/telemetry": "3.3.2"
172
155
  },
173
156
  "optionalDependencies": {
174
- "sharp": "^0.34.0"
157
+ "sharp": "^0.34.0 || ^0.35.0"
175
158
  },
176
159
  "peerDependencies": {
177
160
  "@astrojs/markdown-remark": "7.2.0"