astro 4.4.6 → 4.4.8

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.
@@ -19,6 +19,7 @@ import type { AstroDevToolbar, DevToolbarCanvas } from '../runtime/client/dev-to
19
19
  import type { Icon } from '../runtime/client/dev-toolbar/ui-library/icons.js';
20
20
  import type { DevToolbarBadge, DevToolbarButton, DevToolbarCard, DevToolbarHighlight, DevToolbarIcon, DevToolbarToggle, DevToolbarTooltip, DevToolbarWindow } from '../runtime/client/dev-toolbar/ui-library/index.js';
21
21
  import type { AstroComponentFactory, AstroComponentInstance } from '../runtime/server/index.js';
22
+ import type { TransitionBeforePreparationEvent, TransitionBeforeSwapEvent } from '../transitions/events.js';
22
23
  import type { DeepPartial, OmitIndexSignature, Simplify } from '../type-utils.js';
23
24
  import type { SUPPORTED_MARKDOWN_FILE_EXTENSIONS } from './../core/constants.js';
24
25
  export { type AstroIntegrationLogger };
@@ -2520,9 +2521,14 @@ declare global {
2520
2521
  'astro-dev-overlay-icon': DevToolbarIcon;
2521
2522
  'astro-dev-overlay-card': DevToolbarCard;
2522
2523
  }
2523
- }
2524
- declare global {
2525
2524
  namespace Config {
2526
2525
  type Database = Record<string, any>;
2527
2526
  }
2527
+ interface DocumentEventMap {
2528
+ 'astro:before-preparation': TransitionBeforePreparationEvent;
2529
+ 'astro:after-preparation': Event;
2530
+ 'astro:before-swap': TransitionBeforeSwapEvent;
2531
+ 'astro:after-swap': Event;
2532
+ 'astro:page-load': Event;
2533
+ }
2528
2534
  }
@@ -1,22 +1,43 @@
1
- import os from "os";
1
+ import os from "node:os";
2
+ import { isAbsolute } from "node:path";
3
+ import { fileURLToPath, pathToFileURL } from "node:url";
2
4
  import { isRemotePath, removeQueryString } from "@astrojs/internal-helpers/path";
3
5
  import { readFile } from "fs/promises";
4
6
  import mime from "mime/lite.js";
5
7
  import { getConfiguredImageService } from "../internal.js";
6
8
  import { etag } from "../utils/etag.js";
7
9
  import { isRemoteAllowed } from "../utils/remotePattern.js";
8
- import { assetsDir, imageConfig } from "astro:assets";
10
+ import { assetsDir, imageConfig, outDir } from "astro:assets";
9
11
  function replaceFileSystemReferences(src) {
10
12
  return os.platform().includes("win32") ? src.replace(/^\/@fs\//, "") : src.replace(/^\/@fs/, "");
11
13
  }
12
14
  async function loadLocalImage(src, url) {
13
- const filePath = import.meta.env.DEV ? removeQueryString(replaceFileSystemReferences(src)) : new URL("." + src, assetsDir);
15
+ const assetsDirPath = fileURLToPath(assetsDir);
16
+ let fileUrl;
17
+ if (import.meta.env.DEV) {
18
+ fileUrl = pathToFileURL(removeQueryString(replaceFileSystemReferences(src)));
19
+ } else {
20
+ try {
21
+ fileUrl = new URL("." + src, outDir);
22
+ const filePath = fileURLToPath(fileUrl);
23
+ if (!isAbsolute(filePath) || !filePath.startsWith(assetsDirPath)) {
24
+ return void 0;
25
+ }
26
+ } catch (err) {
27
+ return void 0;
28
+ }
29
+ }
14
30
  let buffer = void 0;
15
31
  try {
16
- buffer = await readFile(filePath);
32
+ buffer = await readFile(fileUrl);
17
33
  } catch (e) {
18
- const sourceUrl = new URL(src, url.origin);
19
- buffer = await loadRemoteImage(sourceUrl);
34
+ try {
35
+ const sourceUrl = new URL(src, url.origin);
36
+ buffer = await loadRemoteImage(sourceUrl);
37
+ } catch (err) {
38
+ console.error("Could not process image request:", err);
39
+ return void 0;
40
+ }
20
41
  }
21
42
  return buffer;
22
43
  }
@@ -40,7 +61,11 @@ const GET = async ({ request }) => {
40
61
  const url = new URL(request.url);
41
62
  const transform = await imageService.parseURL(url, imageConfig);
42
63
  if (!transform?.src) {
43
- throw new Error("Incorrect transform returned by `parseURL`");
64
+ const err = new Error(
65
+ "Incorrect transform returned by `parseURL`. Expected a transform with a `src` property."
66
+ );
67
+ console.error("Could not parse image transform from URL:", err);
68
+ return new Response("Internal Server Error", { status: 500 });
44
69
  }
45
70
  let inputBuffer = void 0;
46
71
  if (isRemotePath(transform.src)) {
@@ -52,7 +77,7 @@ const GET = async ({ request }) => {
52
77
  inputBuffer = await loadLocalImage(transform.src, url);
53
78
  }
54
79
  if (!inputBuffer) {
55
- return new Response("Not Found", { status: 404 });
80
+ return new Response("Internal Server Error", { status: 500 });
56
81
  }
57
82
  const { data, format } = await imageService.transform(inputBuffer, transform, imageConfig);
58
83
  return new Response(data, {
@@ -66,7 +91,12 @@ const GET = async ({ request }) => {
66
91
  });
67
92
  } catch (err) {
68
93
  console.error("Could not process image request:", err);
69
- return new Response(`Server Error: ${err}`, { status: 500 });
94
+ return new Response(
95
+ import.meta.env.DEV ? `Could not process image request: ${err}` : `Internal Server Error`,
96
+ {
97
+ status: 500
98
+ }
99
+ );
70
100
  }
71
101
  };
72
102
  export {
@@ -55,11 +55,12 @@ function assets({
55
55
  export { default as Picture } from "astro/components/Picture.astro";
56
56
 
57
57
  export const imageConfig = ${JSON.stringify(settings.config.image)};
58
- export const assetsDir = new URL(${JSON.stringify(
58
+ export const outDir = new URL(${JSON.stringify(
59
59
  new URL(
60
60
  isServerLikeOutput(settings.config) ? settings.config.build.client : settings.config.outDir
61
61
  )
62
62
  )});
63
+ export const assetsDir = new URL(${JSON.stringify(settings.config.build.assets)}, outDir);
63
64
  export const getImage = async (options) => await getImageInternal(options, imageConfig);
64
65
  `;
65
66
  }
@@ -326,7 +326,7 @@ function getUrlForPath(pathname, base, origin, format, trailingSlash, routeType)
326
326
  }
327
327
  async function generatePath(pathname, pipeline, gopts, route) {
328
328
  const { mod } = gopts;
329
- const { config, logger, options, serverLike } = pipeline;
329
+ const { config, logger, options } = pipeline;
330
330
  logger.debug("build", `Generating: ${pathname}`);
331
331
  if (route.type === "page") {
332
332
  addPageName(pathname, options);
@@ -346,10 +346,11 @@ async function generatePath(pathname, pipeline, gopts, route) {
346
346
  route.type
347
347
  );
348
348
  const request = createRequest({
349
+ base: config.base,
349
350
  url,
350
351
  headers: new Headers(),
351
352
  logger,
352
- ssr: serverLike
353
+ staticLike: true
353
354
  });
354
355
  const renderContext = RenderContext.create({ pipeline, pathname, request, routeData: route });
355
356
  let body;
@@ -1,4 +1,4 @@
1
- const ASTRO_VERSION = "4.4.6";
1
+ const ASTRO_VERSION = "4.4.8";
2
2
  const REROUTE_DIRECTIVE_HEADER = "X-Astro-Reroute";
3
3
  const ROUTE_TYPE_HEADER = "X-Astro-Route-Type";
4
4
  const REROUTABLE_STATUS_CODES = [404, 500];
@@ -23,7 +23,7 @@ async function dev(inlineConfig) {
23
23
  base: restart.container.settings.config.base
24
24
  })
25
25
  );
26
- const currentVersion = "4.4.6";
26
+ const currentVersion = "4.4.8";
27
27
  if (currentVersion.includes("-")) {
28
28
  logger.warn("SKIP_FORMAT", msg.prerelease({ currentVersion }));
29
29
  }
@@ -36,7 +36,7 @@ function serverStart({
36
36
  host,
37
37
  base
38
38
  }) {
39
- const version = "4.4.6";
39
+ const version = "4.4.8";
40
40
  const localPrefix = `${dim("\u2503")} Local `;
41
41
  const networkPrefix = `${dim("\u2503")} Network `;
42
42
  const emptyPrefix = " ".repeat(11);
@@ -261,7 +261,7 @@ function printHelp({
261
261
  message.push(
262
262
  linebreak(),
263
263
  ` ${bgGreen(black(` ${commandName} `))} ${green(
264
- `v${"4.4.6"}`
264
+ `v${"4.4.8"}`
265
265
  )} ${headline}`
266
266
  );
267
267
  }
@@ -4,15 +4,22 @@ import type { Logger } from './logger/core.js';
4
4
  type HeaderType = Headers | Record<string, any> | IncomingHttpHeaders;
5
5
  type RequestBody = ArrayBuffer | Blob | ReadableStream | URLSearchParams | FormData;
6
6
  export interface CreateRequestOptions {
7
+ base: string;
7
8
  url: URL | string;
8
9
  clientAddress?: string | undefined;
9
10
  headers: HeaderType;
10
11
  method?: string;
11
12
  body?: RequestBody | undefined;
12
13
  logger: Logger;
13
- ssr: boolean;
14
14
  locals?: object | undefined;
15
- removeParams?: boolean;
15
+ /**
16
+ * Whether the request is being created for a static build or for a prerendered page within a hybrid/SSR build, or for emulating one of those in dev mode.
17
+ *
18
+ * When `true`, the request will not include search parameters or body, and warn when headers are accessed.
19
+ *
20
+ * @default false
21
+ */
22
+ staticLike?: boolean;
16
23
  }
17
- export declare function createRequest({ url, headers, clientAddress, method, body, logger, ssr, locals, removeParams, }: CreateRequestOptions): Request;
24
+ export declare function createRequest({ base, url, headers, clientAddress, method, body, logger, locals, staticLike, }: CreateRequestOptions): Request;
18
25
  export {};
@@ -1,28 +1,31 @@
1
+ import { appendForwardSlash, prependForwardSlash } from "./path.js";
1
2
  const clientAddressSymbol = Symbol.for("astro.clientAddress");
2
3
  const clientLocalsSymbol = Symbol.for("astro.locals");
3
4
  function createRequest({
5
+ base,
4
6
  url,
5
7
  headers,
6
8
  clientAddress,
7
9
  method = "GET",
8
10
  body = void 0,
9
11
  logger,
10
- ssr,
11
12
  locals,
12
- removeParams = false
13
+ staticLike = false
13
14
  }) {
14
- let headersObj = headers instanceof Headers ? headers : new Headers(Object.entries(headers));
15
+ const headersObj = staticLike ? void 0 : headers instanceof Headers ? headers : new Headers(Object.entries(headers));
15
16
  if (typeof url === "string")
16
17
  url = new URL(url);
17
- if (removeParams && url.pathname !== "/_image") {
18
+ const imageEndpoint = prependForwardSlash(appendForwardSlash(base)) + "_image";
19
+ if (staticLike && url.pathname !== imageEndpoint) {
18
20
  url.search = "";
19
21
  }
20
22
  const request = new Request(url, {
21
23
  method,
22
24
  headers: headersObj,
23
- body
25
+ // body is made available only if the request is for a page that will be on-demand rendered
26
+ body: staticLike ? null : body
24
27
  });
25
- if (!ssr) {
28
+ if (staticLike) {
26
29
  const _headers = request.headers;
27
30
  const headersDesc = Object.getOwnPropertyDescriptor(request, "headers") || {};
28
31
  Object.defineProperty(request, "headers", {
@@ -28,6 +28,8 @@ const perf = [
28
28
  const htmlElement = element;
29
29
  if (htmlElement.offsetTop < window.innerHeight)
30
30
  return false;
31
+ if (htmlElement.src.startsWith("data:"))
32
+ return false;
31
33
  return true;
32
34
  }
33
35
  },
@@ -40,6 +42,8 @@ const perf = [
40
42
  const htmlElement = element;
41
43
  if (htmlElement.offsetTop > window.innerHeight)
42
44
  return false;
45
+ if (htmlElement.src.startsWith("data:"))
46
+ return false;
43
47
  return true;
44
48
  }
45
49
  },
@@ -8,7 +8,6 @@ import { createRequest } from "../core/request.js";
8
8
  import { matchAllRoutes } from "../core/routing/index.js";
9
9
  import { normalizeTheLocale } from "../i18n/index.js";
10
10
  import { getSortedPreloadedMatches } from "../prerender/routing.js";
11
- import { isServerLikeOutput } from "../prerender/utils.js";
12
11
  import { handle404Response, writeSSRResult, writeWebResponse } from "./response.js";
13
12
  function isLoggedRequest(url) {
14
13
  return url !== "/favicon.ico";
@@ -94,7 +93,6 @@ async function handleRoute({
94
93
  }
95
94
  return handle404Response(origin, incomingRequest, incomingResponse);
96
95
  }
97
- const buildingToSSR = isServerLikeOutput(config);
98
96
  let request;
99
97
  let renderContext;
100
98
  let mod = void 0;
@@ -125,10 +123,12 @@ async function handleRoute({
125
123
  return handle404Response(origin, incomingRequest, incomingResponse);
126
124
  }
127
125
  request = createRequest({
126
+ base: config.base,
128
127
  url,
129
- headers: buildingToSSR ? incomingRequest.headers : new Headers(),
128
+ headers: incomingRequest.headers,
130
129
  logger,
131
- ssr: buildingToSSR
130
+ // no route found, so we assume the default for rendering the 404 page
131
+ staticLike: config.output === "static" || config.output === "hybrid"
132
132
  });
133
133
  route = {
134
134
  component: "",
@@ -162,15 +162,14 @@ async function handleRoute({
162
162
  route = matchedRoute.route;
163
163
  const locals = Reflect.get(incomingRequest, clientLocalsSymbol);
164
164
  request = createRequest({
165
+ base: config.base,
165
166
  url,
166
- // Headers are only available when using SSR.
167
- headers: buildingToSSR ? incomingRequest.headers : new Headers(),
167
+ headers: incomingRequest.headers,
168
168
  method: incomingRequest.method,
169
169
  body,
170
170
  logger,
171
- ssr: buildingToSSR,
172
- clientAddress: buildingToSSR ? incomingRequest.socket.remoteAddress : void 0,
173
- removeParams: buildingToSSR === false || route.prerender
171
+ clientAddress: incomingRequest.socket.remoteAddress,
172
+ staticLike: config.output === "static" || route.prerender
174
173
  });
175
174
  for (const [name, value] of Object.entries(config.server.headers ?? {})) {
176
175
  if (value)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "astro",
3
- "version": "4.4.6",
3
+ "version": "4.4.8",
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",
@@ -158,7 +158,7 @@
158
158
  "tsconfck": "^3.0.0",
159
159
  "unist-util-visit": "^5.0.0",
160
160
  "vfile": "^6.0.1",
161
- "vite": "^5.1.2",
161
+ "vite": "^5.1.4",
162
162
  "vitefu": "^0.2.5",
163
163
  "which-pm": "^2.1.1",
164
164
  "yargs-parser": "^21.1.1",