astro 6.1.3 → 6.1.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 (50) hide show
  1. package/dist/assets/consts.d.ts +2 -0
  2. package/dist/assets/consts.js +4 -0
  3. package/dist/assets/utils/index.d.ts +1 -1
  4. package/dist/assets/utils/index.js +1 -9
  5. package/dist/assets/utils/vendor/image-size/utils/bit-reader.d.ts +2 -2
  6. package/dist/assets/utils/vendor/image-size/utils/bit-reader.js +5 -3
  7. package/dist/assets/vite-plugin-assets.js +33 -3
  8. package/dist/cli/add/index.js +38 -55
  9. package/dist/cli/infra/build-time-astro-version-provider.js +1 -1
  10. package/dist/cli/preferences/index.js +1 -1
  11. package/dist/content/content-layer.js +3 -3
  12. package/dist/content/loaders/errors.d.ts +2 -2
  13. package/dist/content/loaders/errors.js +3 -0
  14. package/dist/content/runtime.js +1 -1
  15. package/dist/core/app/base.js +1 -1
  16. package/dist/core/base-pipeline.d.ts +22 -35
  17. package/dist/core/base-pipeline.js +41 -8
  18. package/dist/core/build/generate.js +9 -1
  19. package/dist/core/build/pipeline.d.ts +3 -7
  20. package/dist/core/build/pipeline.js +30 -28
  21. package/dist/core/config/schemas/refined-validators.d.ts +44 -0
  22. package/dist/core/config/schemas/refined-validators.js +168 -0
  23. package/dist/core/config/schemas/refined.js +28 -141
  24. package/dist/core/constants.js +1 -1
  25. package/dist/core/cookies/cookies.js +1 -0
  26. package/dist/core/dev/dev.js +1 -1
  27. package/dist/core/dev/restart.js +63 -68
  28. package/dist/core/messages/runtime.js +1 -1
  29. package/dist/core/render-context.d.ts +2 -2
  30. package/dist/core/render-context.js +20 -0
  31. package/dist/core/routing/create-manifest.js +12 -4
  32. package/dist/core/routing/default.d.ts +2 -3
  33. package/dist/env/validators.d.ts +1 -1
  34. package/dist/integrations/features-validation.d.ts +3 -1
  35. package/dist/integrations/features-validation.js +2 -0
  36. package/dist/preferences/dlv.d.ts +1 -0
  37. package/dist/preferences/dlv.js +9 -0
  38. package/dist/preferences/index.js +1 -1
  39. package/dist/preferences/store.js +3 -2
  40. package/dist/runtime/server/render/component.js +6 -6
  41. package/dist/runtime/server/transition.d.ts +2 -2
  42. package/dist/runtime/server/transition.js +4 -2
  43. package/dist/transitions/swap-functions.js +1 -1
  44. package/dist/vite-plugin-app/pipeline.d.ts +4 -13
  45. package/dist/vite-plugin-app/pipeline.js +27 -12
  46. package/dist/vite-plugin-astro-server/base.d.ts +52 -0
  47. package/dist/vite-plugin-astro-server/base.js +66 -36
  48. package/dist/vite-plugin-astro-server/trailing-slash.d.ts +34 -0
  49. package/dist/vite-plugin-astro-server/trailing-slash.js +24 -11
  50. package/package.json +3 -5
@@ -4,13 +4,31 @@ import { appendForwardSlash, prependForwardSlash } from "@astrojs/internal-helpe
4
4
  import colors from "piccolore";
5
5
  import { notFoundTemplate, subpathNotUsedTemplate } from "../template/4xx.js";
6
6
  import { writeHtmlResponse } from "./response.js";
7
+ function resolveDevRoot(base, site) {
8
+ const effectiveBase = base || "/";
9
+ const siteUrl = site ? new URL(effectiveBase, site) : void 0;
10
+ const devRootURL = new URL(effectiveBase, "http://localhost");
11
+ const devRoot = siteUrl ? siteUrl.pathname : devRootURL.pathname;
12
+ const devRootReplacement = devRoot.endsWith("/") ? "/" : "";
13
+ return { devRoot, devRootReplacement };
14
+ }
15
+ function evaluateBaseRewrite(url, pathname, acceptHeader, devRoot, devRootReplacement) {
16
+ if (pathname.startsWith(devRoot)) {
17
+ let newUrl = url.replace(devRoot, devRootReplacement);
18
+ if (!newUrl.startsWith("/")) newUrl = prependForwardSlash(newUrl);
19
+ return { action: "rewrite", newUrl };
20
+ }
21
+ if (pathname === "/" || pathname === "/index.html") {
22
+ return { action: "not-found-subpath", pathname, devRoot };
23
+ }
24
+ if (acceptHeader?.includes("text/html")) {
25
+ return { action: "not-found", pathname };
26
+ }
27
+ return { action: "check-public" };
28
+ }
7
29
  function baseMiddleware(settings, logger) {
8
30
  const { config } = settings;
9
- const base = config.base || "/";
10
- const site = config.site ? new URL(base, config.site) : void 0;
11
- const devRootURL = new URL(base, "http://localhost");
12
- const devRoot = site ? site.pathname : devRootURL.pathname;
13
- const devRootReplacement = devRoot.endsWith("/") ? "/" : "";
31
+ const { devRoot, devRootReplacement } = resolveDevRoot(config.base, config.site);
14
32
  return function devBaseMiddleware(req, res, next) {
15
33
  const url = req.url;
16
34
  let pathname;
@@ -19,40 +37,52 @@ function baseMiddleware(settings, logger) {
19
37
  } catch (e) {
20
38
  return next(e);
21
39
  }
22
- if (pathname.startsWith(devRoot)) {
23
- req.url = url.replace(devRoot, devRootReplacement);
24
- if (!req.url.startsWith("/")) req.url = prependForwardSlash(req.url);
25
- return next();
26
- }
27
- if (pathname === "/" || pathname === "/index.html") {
28
- const html = subpathNotUsedTemplate(devRoot, pathname);
29
- return writeHtmlResponse(res, 404, html);
30
- }
31
- if (req.headers.accept?.includes("text/html")) {
32
- const html = notFoundTemplate(pathname);
33
- return writeHtmlResponse(res, 404, html);
34
- }
35
- const publicPath = new URL("." + req.url, config.publicDir);
36
- fs.stat(publicPath, (_err, stats) => {
37
- if (stats) {
38
- const publicDir = appendForwardSlash(
39
- path.posix.relative(config.root.pathname, config.publicDir.pathname)
40
- );
41
- const expectedLocation = new URL(devRootURL.pathname + url, devRootURL).pathname;
42
- logger.error(
43
- "router",
44
- `Request URLs for ${colors.bold(
45
- publicDir
46
- )} assets must also include your base. "${expectedLocation}" expected, but received "${url}".`
47
- );
48
- const html = subpathNotUsedTemplate(devRoot, pathname);
40
+ const decision = evaluateBaseRewrite(
41
+ url,
42
+ pathname,
43
+ req.headers.accept,
44
+ devRoot,
45
+ devRootReplacement
46
+ );
47
+ switch (decision.action) {
48
+ case "rewrite":
49
+ req.url = decision.newUrl;
50
+ return next();
51
+ case "not-found-subpath": {
52
+ const html = subpathNotUsedTemplate(decision.devRoot, decision.pathname);
53
+ return writeHtmlResponse(res, 404, html);
54
+ }
55
+ case "not-found": {
56
+ const html = notFoundTemplate(decision.pathname);
49
57
  return writeHtmlResponse(res, 404, html);
50
- } else {
51
- next();
52
58
  }
53
- });
59
+ case "check-public": {
60
+ const publicPath = new URL("." + req.url, config.publicDir);
61
+ fs.stat(publicPath, (_err, stats) => {
62
+ if (stats) {
63
+ const publicDir = appendForwardSlash(
64
+ path.posix.relative(config.root.pathname, config.publicDir.pathname)
65
+ );
66
+ const devRootURL = new URL(devRoot, "http://localhost");
67
+ const expectedLocation = new URL(devRootURL.pathname + url, devRootURL).pathname;
68
+ logger.error(
69
+ "router",
70
+ `Request URLs for ${colors.bold(
71
+ publicDir
72
+ )} assets must also include your base. "${expectedLocation}" expected, but received "${url}".`
73
+ );
74
+ const html = subpathNotUsedTemplate(devRoot, pathname);
75
+ return writeHtmlResponse(res, 404, html);
76
+ } else {
77
+ next();
78
+ }
79
+ });
80
+ }
81
+ }
54
82
  };
55
83
  }
56
84
  export {
57
- baseMiddleware
85
+ baseMiddleware,
86
+ evaluateBaseRewrite,
87
+ resolveDevRoot
58
88
  };
@@ -1,3 +1,37 @@
1
1
  import type * as vite from 'vite';
2
2
  import type { AstroSettings } from '../types/astro.js';
3
+ /**
4
+ * Outcome of the trailing-slash evaluation for a dev-server request.
5
+ *
6
+ * - **`next`** — The URL is acceptable. Pass the request through to the next
7
+ * middleware / route handler unchanged.
8
+ * - **`redirect`** — The URL contains duplicate trailing slashes (e.g.
9
+ * `/about//`). The client should be permanently redirected (301) to the
10
+ * collapsed form (`/about/`) so crawlers and browsers update their links.
11
+ * - **`reject`** — The URL's trailing-slash style conflicts with the project's
12
+ * `trailingSlash` config (`'always'` or `'never'`). The dev server responds
13
+ * with a 404 and a human-readable error page explaining the mismatch, giving
14
+ * the developer immediate feedback that their link is wrong before it reaches
15
+ * production.
16
+ */
17
+ export type TrailingSlashDecision = {
18
+ action: 'next';
19
+ } | {
20
+ action: 'redirect';
21
+ status: 301;
22
+ location: string;
23
+ } | {
24
+ action: 'reject';
25
+ status: 404;
26
+ pathname: string;
27
+ };
28
+ /**
29
+ * Pure decision function for trailing-slash dev-server behavior.
30
+ *
31
+ * Evaluates a decoded `pathname`, the query-string portion (including leading
32
+ * `?`), and the project's `trailingSlash` config and returns the action the
33
+ * middleware should take. The middleware is responsible for translating the
34
+ * decision into an HTTP response.
35
+ */
36
+ export declare function evaluateTrailingSlash(pathname: string, search: string, trailingSlash: 'always' | 'never' | 'ignore'): TrailingSlashDecision;
3
37
  export declare function trailingSlashMiddleware(settings: AstroSettings): vite.Connect.NextHandleFunction;
@@ -5,6 +5,19 @@ import {
5
5
  } from "@astrojs/internal-helpers/path";
6
6
  import { trailingSlashMismatchTemplate } from "../template/4xx.js";
7
7
  import { writeHtmlResponse, writeRedirectResponse } from "./response.js";
8
+ function evaluateTrailingSlash(pathname, search, trailingSlash) {
9
+ if (isInternalPath(pathname)) {
10
+ return { action: "next" };
11
+ }
12
+ const collapsed = collapseDuplicateTrailingSlashes(pathname, true);
13
+ if (pathname && collapsed !== pathname) {
14
+ return { action: "redirect", status: 301, location: `${collapsed}${search}` };
15
+ }
16
+ if (trailingSlash === "never" && pathname.endsWith("/") && pathname !== "/" || trailingSlash === "always" && !pathname.endsWith("/") && !hasFileExtension(pathname)) {
17
+ return { action: "reject", status: 404, pathname };
18
+ }
19
+ return { action: "next" };
20
+ }
8
21
  function trailingSlashMiddleware(settings) {
9
22
  const { trailingSlash } = settings.config;
10
23
  return function devTrailingSlash(req, res, next) {
@@ -15,20 +28,20 @@ function trailingSlashMiddleware(settings) {
15
28
  } catch (e) {
16
29
  return next(e);
17
30
  }
18
- if (isInternalPath(pathname)) {
19
- return next();
20
- }
21
- const destination = collapseDuplicateTrailingSlashes(pathname, true);
22
- if (pathname && destination !== pathname) {
23
- return writeRedirectResponse(res, 301, `${destination}${url.search}`);
24
- }
25
- if (trailingSlash === "never" && pathname.endsWith("/") && pathname !== "/" || trailingSlash === "always" && !pathname.endsWith("/") && !hasFileExtension(pathname)) {
26
- const html = trailingSlashMismatchTemplate(pathname, trailingSlash);
27
- return writeHtmlResponse(res, 404, html);
31
+ const decision = evaluateTrailingSlash(pathname, url.search, trailingSlash);
32
+ switch (decision.action) {
33
+ case "redirect":
34
+ return writeRedirectResponse(res, decision.status, decision.location);
35
+ case "reject": {
36
+ const html = trailingSlashMismatchTemplate(decision.pathname, trailingSlash);
37
+ return writeHtmlResponse(res, decision.status, html);
38
+ }
39
+ case "next":
40
+ return next();
28
41
  }
29
- return next();
30
42
  };
31
43
  }
32
44
  export {
45
+ evaluateTrailingSlash,
33
46
  trailingSlashMiddleware
34
47
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "astro",
3
- "version": "6.1.3",
3
+ "version": "6.1.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",
@@ -114,7 +114,6 @@
114
114
  "cookie": "^1.1.1",
115
115
  "devalue": "^5.6.3",
116
116
  "diff": "^8.0.3",
117
- "dlv": "^1.1.3",
118
117
  "dset": "^3.1.4",
119
118
  "es-module-lexer": "^2.0.0",
120
119
  "esbuild": "^0.27.3",
@@ -153,9 +152,9 @@
153
152
  "xxhash-wasm": "^1.1.0",
154
153
  "yargs-parser": "^22.0.0",
155
154
  "zod": "^4.3.6",
156
- "@astrojs/internal-helpers": "0.8.0",
157
155
  "@astrojs/markdown-remark": "7.1.0",
158
- "@astrojs/telemetry": "3.3.0"
156
+ "@astrojs/telemetry": "3.3.0",
157
+ "@astrojs/internal-helpers": "0.8.0"
159
158
  },
160
159
  "optionalDependencies": {
161
160
  "sharp": "^0.34.0"
@@ -164,7 +163,6 @@
164
163
  "@astrojs/compiler-rs": "^0.1.6",
165
164
  "@playwright/test": "1.58.2",
166
165
  "@types/aria-query": "^5.0.4",
167
- "@types/dlv": "^1.1.5",
168
166
  "@types/hast": "^3.0.4",
169
167
  "@types/html-escaper": "3.0.4",
170
168
  "@types/http-cache-semantics": "^4.2.0",