astro 7.2.6 → 7.2.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.
@@ -1,5 +1,5 @@
1
1
  import * as z from 'zod/v4';
2
2
  export declare const SvgOptimizerSchema: z.ZodObject<{
3
3
  name: z.ZodString;
4
- optimize: z.ZodCustom<(contents: string) => string | Promise<string>, (contents: string) => string | Promise<string>>;
4
+ optimize: z.ZodCustom<(contents: string, path: string) => string | Promise<string>, (contents: string, path: string) => string | Promise<string>>;
5
5
  }, z.core.$strip>;
@@ -2,7 +2,7 @@ import { optimize } from "svgo";
2
2
  function svgoOptimizer(config) {
3
3
  return {
4
4
  name: "svgo",
5
- optimize: (contents) => optimize(contents, config).data
5
+ optimize: (contents, path) => optimize(contents, { ...config, path }).data
6
6
  };
7
7
  }
8
8
  export {
@@ -1,4 +1,4 @@
1
1
  export interface SvgOptimizer {
2
2
  name: string;
3
- optimize: (contents: string) => string | Promise<string>;
3
+ optimize: (contents: string, path: string) => string | Promise<string>;
4
4
  }
@@ -9,7 +9,7 @@ async function parseSvg({
9
9
  let processedContents = contents;
10
10
  if (svgOptimizer) {
11
11
  try {
12
- processedContents = await svgOptimizer.optimize(contents);
12
+ processedContents = await svgOptimizer.optimize(contents, path);
13
13
  } catch (cause) {
14
14
  throw new AstroError(
15
15
  {
@@ -0,0 +1 @@
1
+ export declare function getCloudflareCompatibilityDate(root: URL): Promise<string>;
@@ -0,0 +1,12 @@
1
+ import { createRequire } from "node:module";
2
+ import { pathToFileURL } from "node:url";
3
+ async function getCloudflareCompatibilityDate(root) {
4
+ const require2 = createRequire(root);
5
+ const infoPath = require2.resolve("@astrojs/cloudflare/info");
6
+ const infoUrl = pathToFileURL(infoPath).toString();
7
+ const infoModule = await import(infoUrl);
8
+ return infoModule.getLocalWorkerdCompatibilityDate().date;
9
+ }
10
+ export {
11
+ getCloudflareCompatibilityDate
12
+ };
@@ -28,6 +28,7 @@ import { eventCliSession, telemetry } from "../../events/index.js";
28
28
  import { exec } from "../exec.js";
29
29
  import { createLoggerFromFlags, flagsToAstroInlineConfig } from "../flags.js";
30
30
  import { fetchPackageJson, fetchPackageVersions } from "../install-package.js";
31
+ import { getCloudflareCompatibilityDate } from "./cloudflare.js";
31
32
  const { bold, cyan, dim, green, magenta, red, yellow } = colors;
32
33
  const ALIASES = /* @__PURE__ */ new Map([
33
34
  ["solid", "solid-js"],
@@ -167,7 +168,7 @@ async function add(names, { flags }) {
167
168
  );
168
169
  if (await askToContinue({ flags, logger })) {
169
170
  const data = await getPackageJson();
170
- let compatibilityDate = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
171
+ const compatibilityDate = await getCloudflareCompatibilityDate(root);
171
172
  await fs.writeFile(
172
173
  wranglerConfigURL,
173
174
  STUBS.CLOUDFLARE_WRANGLER_CONFIG(data?.name ?? "example", compatibilityDate),
@@ -1,6 +1,6 @@
1
1
  class BuildTimeAstroVersionProvider {
2
2
  // Injected during the build through esbuild define
3
- version = "7.2.6";
3
+ version = "7.2.8";
4
4
  }
5
5
  export {
6
6
  BuildTimeAstroVersionProvider
@@ -196,7 +196,7 @@ ${contentConfig.error.message}`
196
196
  logger.info("Content config changed");
197
197
  shouldClear = true;
198
198
  }
199
- if (previousAstroVersion && previousAstroVersion !== "7.2.6") {
199
+ if (previousAstroVersion && previousAstroVersion !== "7.2.8") {
200
200
  logger.info("Astro version changed");
201
201
  shouldClear = true;
202
202
  }
@@ -204,8 +204,8 @@ ${contentConfig.error.message}`
204
204
  logger.info("Clearing content store");
205
205
  this.#store.clearAll();
206
206
  }
207
- if ("7.2.6") {
208
- this.#store.metaStore().set("astro-version", "7.2.6");
207
+ if ("7.2.8") {
208
+ this.#store.metaStore().set("astro-version", "7.2.8");
209
209
  }
210
210
  if (currentConfigDigest) {
211
211
  this.#store.metaStore().set("content-config-digest", currentConfigDigest);
@@ -144,14 +144,11 @@ export declare abstract class BaseApp {
144
144
  set setManifestData(newManifestData: RoutesList);
145
145
  removeBase(pathname: string): string;
146
146
  /**
147
- * Decodes a pathname with `decodeURI`, falling back to the raw pathname when it
148
- * contains an invalid percent-sequence (e.g. `%C0%AF`, an overlong-UTF-8 encoding of
149
- * `/` commonly sent by path-traversal scanners). A raw `decodeURI()` would throw
150
- * `URIError: URI malformed`, and because `match()` runs before `render()` that error
151
- * escapes the adapter's request handler as an uncaught exception (HTTP 500) that user
152
- * middleware can't catch.
153
- */
154
- private safeDecodeURI;
147
+ * Fully decodes a pathname, falling back to a single decode and then the raw pathname
148
+ * when validation fails. Adapter matching runs before `render()`, so it must not throw
149
+ * for request input that render-time validation handles.
150
+ */
151
+ private safeDecodePathname;
155
152
  /**
156
153
  * Extracts the base-stripped, decoded pathname from a request.
157
154
  * Used by adapters to compute the pathname for dev-mode route matching.
@@ -18,6 +18,7 @@ import { handleRequest } from "../routing/handler.js";
18
18
  import { getDefaultStatusCode } from "../routing/helpers.js";
19
19
  import { matchRequest } from "../routing/match-request.js";
20
20
  import { getRouteTable, matchRoute, updateRouteTable } from "../routing/route-table.js";
21
+ import { validateAndDecodePathname } from "../util/pathname.js";
21
22
  import { setRenderOptions } from "./render-options.js";
22
23
  class BaseApp {
23
24
  manifest;
@@ -149,19 +150,20 @@ class BaseApp {
149
150
  return stripRequestBase(pathname, this.manifest.base);
150
151
  }
151
152
  /**
152
- * Decodes a pathname with `decodeURI`, falling back to the raw pathname when it
153
- * contains an invalid percent-sequence (e.g. `%C0%AF`, an overlong-UTF-8 encoding of
154
- * `/` commonly sent by path-traversal scanners). A raw `decodeURI()` would throw
155
- * `URIError: URI malformed`, and because `match()` runs before `render()` that error
156
- * escapes the adapter's request handler as an uncaught exception (HTTP 500) that user
157
- * middleware can't catch.
153
+ * Fully decodes a pathname, falling back to a single decode and then the raw pathname
154
+ * when validation fails. Adapter matching runs before `render()`, so it must not throw
155
+ * for request input that render-time validation handles.
158
156
  */
159
- safeDecodeURI(pathname) {
157
+ safeDecodePathname(pathname) {
160
158
  try {
161
- return decodeURI(pathname);
159
+ return validateAndDecodePathname(pathname);
162
160
  } catch (e) {
163
161
  this.adapterLogger.debug(e.toString());
164
- return pathname;
162
+ try {
163
+ return decodeURI(pathname);
164
+ } catch {
165
+ return pathname;
166
+ }
165
167
  }
166
168
  }
167
169
  /**
@@ -171,7 +173,7 @@ class BaseApp {
171
173
  getPathnameFromRequest(request) {
172
174
  const url = new URL(request.url);
173
175
  const pathname = prependForwardSlash(this.removeBase(url.pathname));
174
- return this.safeDecodeURI(pathname);
176
+ return this.safeDecodePathname(pathname);
175
177
  }
176
178
  /**
177
179
  * Given a `Request`, it returns the `RouteData` that matches its `pathname`. By default, prerendered
@@ -243,7 +245,7 @@ class BaseApp {
243
245
  if (!routeData) {
244
246
  const domainPathname = this.computePathnameFromDomain(request);
245
247
  if (domainPathname) {
246
- routeData = matchRoute(this.manifest, this.safeDecodeURI(domainPathname));
248
+ routeData = matchRoute(this.manifest, this.safeDecodePathname(domainPathname));
247
249
  }
248
250
  }
249
251
  const resolvedOptions = {
@@ -8,8 +8,6 @@ function deserializeManifest(serializedManifest, routesList) {
8
8
  ...serializedRoute,
9
9
  routeData: deserializeRouteData(serializedRoute.routeData)
10
10
  });
11
- const route = serializedRoute;
12
- route.routeData = deserializeRouteData(serializedRoute.routeData);
13
11
  }
14
12
  }
15
13
  if (routesList) {
@@ -487,7 +487,7 @@ export declare const AstroConfigSchema: z.ZodObject<{
487
487
  incrementalBuild: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
488
488
  svgOptimizer: z.ZodOptional<z.ZodObject<{
489
489
  name: z.ZodString;
490
- optimize: z.ZodCustom<(contents: string) => string | Promise<string>, (contents: string) => string | Promise<string>>;
490
+ optimize: z.ZodCustom<(contents: string, path: string) => string | Promise<string>, (contents: string, path: string) => string | Promise<string>>;
491
491
  }, z.core.$strip>>;
492
492
  collectionStorage: z.ZodDefault<z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<"single-file">, z.ZodLiteral<"chunked">, z.ZodObject<{
493
493
  type: z.ZodLiteral<"chunked">;
@@ -439,7 +439,7 @@ export declare function createRelativeSchema(cmd: string, fileProtocolRoot: stri
439
439
  incrementalBuild: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
440
440
  svgOptimizer: z.ZodOptional<z.ZodObject<{
441
441
  name: z.ZodString;
442
- optimize: z.ZodCustom<(contents: string) => string | Promise<string>, (contents: string) => string | Promise<string>>;
442
+ optimize: z.ZodCustom<(contents: string, path: string) => string | Promise<string>, (contents: string, path: string) => string | Promise<string>>;
443
443
  }, z.core.$strip>>;
444
444
  collectionStorage: z.ZodDefault<z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<"single-file">, z.ZodLiteral<"chunked">, z.ZodObject<{
445
445
  type: z.ZodLiteral<"chunked">;
@@ -638,7 +638,7 @@ export declare function createRelativeSchema(cmd: string, fileProtocolRoot: stri
638
638
  };
639
639
  svgOptimizer?: {
640
640
  name: string;
641
- optimize: (contents: string) => string | Promise<string>;
641
+ optimize: (contents: string, path: string) => string | Promise<string>;
642
642
  } | undefined;
643
643
  };
644
644
  legacy: {
@@ -905,7 +905,7 @@ export declare function createRelativeSchema(cmd: string, fileProtocolRoot: stri
905
905
  };
906
906
  svgOptimizer?: {
907
907
  name: string;
908
- optimize: (contents: string) => string | Promise<string>;
908
+ optimize: (contents: string, path: string) => string | Promise<string>;
909
909
  } | undefined;
910
910
  };
911
911
  legacy: {
@@ -1,4 +1,4 @@
1
- const ASTRO_VERSION = "7.2.6";
1
+ const ASTRO_VERSION = "7.2.8";
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.2.6";
29
+ const currentVersion = "7.2.8";
30
30
  const isPrerelease = currentVersion.includes("-");
31
31
  if (!isPrerelease) {
32
32
  try {
@@ -1,6 +1,6 @@
1
1
  import { existsSync, readFileSync, unlinkSync, writeFileSync, mkdirSync } from "node:fs";
2
2
  import { fileURLToPath } from "node:url";
3
- import findProcess from "find-process";
3
+ import findProcess from "find-proc";
4
4
  const GRACEFUL_SHUTDOWN_TIMEOUT = 5e3;
5
5
  function getLockFileURL(root, command = "dev") {
6
6
  return new URL(`.astro/${command}.json`, root);
@@ -270,7 +270,7 @@ function printHelp({
270
270
  message.push(
271
271
  linebreak(),
272
272
  ` ${bgGreen(black(` ${commandName} `))} ${green(
273
- `v${"7.2.6"}`
273
+ `v${"7.2.8"}`
274
274
  )} ${headline}`
275
275
  );
276
276
  }
@@ -3,7 +3,7 @@ import { getEnvironment } from "../environment/index.js";
3
3
  import { ForbiddenRewrite } from "../errors/errors-data.js";
4
4
  import { AstroError } from "../errors/index.js";
5
5
  import { getParams } from "../render/params-and-props.js";
6
- import { setOriginPathname } from "../routing/rewrite.js";
6
+ import { copyRequest, setOriginPathname } from "../routing/rewrite.js";
7
7
  import { defineMiddleware } from "./defineMiddleware.js";
8
8
  function sequence(...handlers) {
9
9
  const filtered = handlers.filter((h) => !!h);
@@ -21,17 +21,6 @@ function sequence(...handlers) {
21
21
  const result = handle(handleContext, async (payload) => {
22
22
  if (i < length - 1) {
23
23
  if (payload) {
24
- let newRequest;
25
- if (payload instanceof Request) {
26
- newRequest = payload;
27
- } else if (payload instanceof URL) {
28
- newRequest = new Request(payload, handleContext.request.clone());
29
- } else {
30
- newRequest = new Request(
31
- new URL(payload, handleContext.url.origin),
32
- handleContext.request.clone()
33
- );
34
- }
35
24
  const oldPathname = handleContext.url.pathname;
36
25
  const state = Reflect.get(handleContext, fetchStateSymbol);
37
26
  if (!state) {
@@ -45,6 +34,14 @@ function sequence(...handlers) {
45
34
  payload,
46
35
  handleContext.request
47
36
  );
37
+ let newRequest;
38
+ if (payload instanceof Request) {
39
+ newRequest = payload;
40
+ } else {
41
+ const request = handleContext.request.method === "GET" || handleContext.request.method === "HEAD" ? handleContext.request : handleContext.request.clone();
42
+ const newUrl = payload instanceof URL ? payload : new URL(payload, handleContext.url.origin);
43
+ newRequest = copyRequest(newUrl, request, false, state.logger, routeData.route);
44
+ }
48
45
  if (manifest.serverLike === true && handleContext.isPrerendered === false && routeData.prerender === true) {
49
46
  throw new AstroError({
50
47
  ...ForbiddenRewrite,
@@ -2,15 +2,20 @@ import { prependForwardSlash, stripRequestBase } from "@astrojs/internal-helpers
2
2
  import { computePathnameFromDomain } from "../i18n/domain.js";
3
3
  import { AstroIntegrationLogger } from "../logger/core.js";
4
4
  import { getLogger } from "../logger/manifest-logger.js";
5
+ import { validateAndDecodePathname } from "../util/pathname.js";
5
6
  import { matchAllRoutes, matchRoute } from "./route-table.js";
6
- function safeDecodeURI(manifest, pathname) {
7
+ function safeDecodePathname(manifest, pathname) {
7
8
  try {
8
- return decodeURI(pathname);
9
+ return validateAndDecodePathname(pathname);
9
10
  } catch (e) {
10
11
  new AstroIntegrationLogger(getLogger(manifest).options, manifest.adapterName).debug(
11
12
  e.toString()
12
13
  );
13
- return pathname;
14
+ try {
15
+ return decodeURI(pathname);
16
+ } catch {
17
+ return pathname;
18
+ }
14
19
  }
15
20
  }
16
21
  function matchRequest(manifest, request, allowPrerenderedRoutes = false) {
@@ -27,14 +32,15 @@ function matchRequest(manifest, request, allowPrerenderedRoutes = false) {
27
32
  if (!pathname) {
28
33
  pathname = prependForwardSlash(stripRequestBase(url.pathname, manifest.base));
29
34
  }
30
- const routeData = matchRoute(manifest, safeDecodeURI(manifest, pathname));
35
+ pathname = safeDecodePathname(manifest, pathname);
36
+ const routeData = matchRoute(manifest, pathname);
31
37
  if (!routeData) return void 0;
32
38
  if (allowPrerenderedRoutes) {
33
39
  return routeData;
34
40
  }
35
41
  if (routeData.prerender) {
36
42
  if (routeData.params.length > 0) {
37
- const allMatches = matchAllRoutes(manifest, safeDecodeURI(manifest, pathname));
43
+ const allMatches = matchAllRoutes(manifest, pathname);
38
44
  return allMatches.find((r) => !r.prerender);
39
45
  }
40
46
  return void 0;
@@ -80,13 +80,14 @@ function findRouteToRewrite({
80
80
  }
81
81
  }
82
82
  function copyRequest(newUrl, oldRequest, isPrerendered, logger, routePattern) {
83
- if (oldRequest.bodyUsed) {
83
+ const canHaveBody = oldRequest.method !== "GET" && oldRequest.method !== "HEAD";
84
+ if (canHaveBody && oldRequest.bodyUsed) {
84
85
  throw new AstroError(AstroErrorData.RewriteWithBodyUsed);
85
86
  }
86
87
  return createRequest({
87
88
  url: newUrl,
88
89
  method: oldRequest.method,
89
- body: oldRequest.body,
90
+ body: canHaveBody ? oldRequest.body : void 0,
90
91
  isPrerendered,
91
92
  logger,
92
93
  headers: isPrerendered ? {} : oldRequest.headers,
@@ -5,6 +5,7 @@ import { getEnvironment, setEnvironment } from "../core/environment/index.js";
5
5
  import { createSafeError } from "../core/errors/index.js";
6
6
  import { setLogger } from "../core/logger/manifest-logger.js";
7
7
  import { createRequest } from "../core/request.js";
8
+ import { validateAndDecodePathname } from "../core/util/pathname.js";
8
9
  import { SERIALIZED_MANIFEST_ID } from "../manifest/serialized.js";
9
10
  import { recordServerError } from "../vite-plugin-astro-server/error.js";
10
11
  import { runWithErrorHandling } from "../vite-plugin-astro-server/index.js";
@@ -39,7 +40,11 @@ async function handleDevRequest(app, deps, { incomingRequest, incomingResponse,
39
40
  if (manifest.trailingSlash === "never" && !incomingRequest.url) {
40
41
  pathname = "";
41
42
  } else {
42
- pathname = decodeURI(url.pathname);
43
+ try {
44
+ pathname = validateAndDecodePathname(url.pathname);
45
+ } catch {
46
+ pathname = decodeURI(url.pathname);
47
+ }
43
48
  }
44
49
  url.pathname = removeTrailingForwardSlash(manifest.base) + url.pathname;
45
50
  if (url.pathname.endsWith("/") && !shouldAppendForwardSlash(manifest.trailingSlash, manifest.buildFormat)) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "astro",
3
- "version": "7.2.6",
3
+ "version": "7.2.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",
@@ -119,7 +119,7 @@
119
119
  "dset": "^3.1.4",
120
120
  "es-module-lexer": "^2.0.0",
121
121
  "esbuild": "^0.28.0",
122
- "find-process": "^2.1.1",
122
+ "find-proc": "0.1.0",
123
123
  "flattie": "^1.1.1",
124
124
  "fontace": "~0.4.1",
125
125
  "get-tsconfig": "5.0.0-beta.4",
@@ -153,12 +153,12 @@
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.4",
157
156
  "@astrojs/markdown-satteri": "0.3.8",
157
+ "@astrojs/internal-helpers": "0.10.4",
158
158
  "@astrojs/telemetry": "3.3.3"
159
159
  },
160
160
  "optionalDependencies": {
161
- "sharp": "^0.34.0 || ^0.35.0"
161
+ "sharp": "^0.35.4"
162
162
  },
163
163
  "peerDependencies": {
164
164
  "@astrojs/markdown-remark": "7.2.4"