astro 5.17.3 → 5.18.0

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.
@@ -159,9 +159,10 @@ function getActionContext(context) {
159
159
  }
160
160
  throw error;
161
161
  }
162
+ const bodySizeLimit = pipeline.manifest.actionBodySizeLimit;
162
163
  let input;
163
164
  try {
164
- input = await parseRequestBody(context.request);
165
+ input = await parseRequestBody(context.request, bodySizeLimit);
165
166
  } catch (e) {
166
167
  if (e instanceof ActionError) {
167
168
  return { data: void 0, error: e };
@@ -209,22 +210,21 @@ function getCallerInfo(ctx) {
209
210
  }
210
211
  return void 0;
211
212
  }
212
- const DEFAULT_ACTION_BODY_SIZE_LIMIT = 1024 * 1024;
213
- async function parseRequestBody(request) {
213
+ async function parseRequestBody(request, bodySizeLimit) {
214
214
  const contentType = request.headers.get("content-type");
215
215
  const contentLengthHeader = request.headers.get("content-length");
216
216
  const contentLength = contentLengthHeader ? Number.parseInt(contentLengthHeader, 10) : void 0;
217
217
  const hasContentLength = typeof contentLength === "number" && Number.isFinite(contentLength);
218
218
  if (!contentType) return void 0;
219
- if (hasContentLength && contentLength > DEFAULT_ACTION_BODY_SIZE_LIMIT) {
219
+ if (hasContentLength && contentLength > bodySizeLimit) {
220
220
  throw new ActionError({
221
221
  code: "CONTENT_TOO_LARGE",
222
- message: `Request body exceeds ${DEFAULT_ACTION_BODY_SIZE_LIMIT} bytes`
222
+ message: `Request body exceeds ${bodySizeLimit} bytes`
223
223
  });
224
224
  }
225
225
  if (hasContentType(contentType, formContentTypes)) {
226
226
  if (!hasContentLength) {
227
- const body = await readRequestBodyWithLimit(request.clone(), DEFAULT_ACTION_BODY_SIZE_LIMIT);
227
+ const body = await readRequestBodyWithLimit(request.clone(), bodySizeLimit);
228
228
  const formRequest = new Request(request.url, {
229
229
  method: request.method,
230
230
  headers: request.headers,
@@ -237,7 +237,7 @@ async function parseRequestBody(request) {
237
237
  if (hasContentType(contentType, ["application/json"])) {
238
238
  if (contentLength === 0) return void 0;
239
239
  if (!hasContentLength) {
240
- const body = await readRequestBodyWithLimit(request.clone(), DEFAULT_ACTION_BODY_SIZE_LIMIT);
240
+ const body = await readRequestBodyWithLimit(request.clone(), bodySizeLimit);
241
241
  if (body.byteLength === 0) return void 0;
242
242
  return JSON.parse(new TextDecoder().decode(body));
243
243
  }
@@ -1,6 +1,6 @@
1
1
  class BuildTimeAstroVersionProvider {
2
2
  // Injected during the build through esbuild define
3
- version = "5.17.3";
3
+ version = "5.18.0";
4
4
  }
5
5
  export {
6
6
  BuildTimeAstroVersionProvider
@@ -45,6 +45,7 @@ function createManifest(manifest, renderers, middleware) {
45
45
  i18n: manifest?.i18n,
46
46
  checkOrigin: false,
47
47
  allowedDomains: manifest?.allowedDomains ?? [],
48
+ actionBodySizeLimit: 1024 * 1024,
48
49
  middleware: manifest?.middleware ?? middlewareInstance,
49
50
  key: createKey(),
50
51
  csp: manifest?.csp
@@ -164,7 +164,7 @@ ${contentConfig.error.message}`);
164
164
  logger.info("Content config changed");
165
165
  shouldClear = true;
166
166
  }
167
- if (previousAstroVersion && previousAstroVersion !== "5.17.3") {
167
+ if (previousAstroVersion && previousAstroVersion !== "5.18.0") {
168
168
  logger.info("Astro version changed");
169
169
  shouldClear = true;
170
170
  }
@@ -172,8 +172,8 @@ ${contentConfig.error.message}`);
172
172
  logger.info("Clearing content store");
173
173
  this.#store.clearAll();
174
174
  }
175
- if ("5.17.3") {
176
- await this.#store.metaStore().set("astro-version", "5.17.3");
175
+ if ("5.18.0") {
176
+ await this.#store.metaStore().set("astro-version", "5.18.0");
177
177
  }
178
178
  if (currentConfigDigest) {
179
179
  await this.#store.metaStore().set("content-config-digest", currentConfigDigest);
@@ -71,6 +71,7 @@ export type SSRManifest = {
71
71
  actions?: () => Promise<SSRActions> | SSRActions;
72
72
  checkOrigin: boolean;
73
73
  allowedDomains?: Partial<RemotePattern>[];
74
+ actionBodySizeLimit: number;
74
75
  sessionConfig?: ResolvedSessionConfig<any>;
75
76
  cacheDir: string | URL;
76
77
  srcDir: string | URL;
@@ -39,7 +39,9 @@ function validateForwardedHeaders(forwardedProtocol, forwardedHost, forwardedPor
39
39
  if (hasProtocolPatterns) {
40
40
  try {
41
41
  const testUrl = new URL(`${forwardedProtocol}://example.com`);
42
- const isAllowed = allowedDomains.some((pattern) => matchPattern(testUrl, pattern));
42
+ const isAllowed = allowedDomains.some(
43
+ (pattern) => matchPattern(testUrl, { protocol: pattern.protocol })
44
+ );
43
45
  if (isAllowed) {
44
46
  result.protocol = forwardedProtocol;
45
47
  }
@@ -500,6 +500,7 @@ async function createBuildManifest(settings, internals, renderers, middleware, a
500
500
  },
501
501
  actions: () => actions,
502
502
  checkOrigin: (settings.config.security?.checkOrigin && settings.buildOutput === "server") ?? false,
503
+ actionBodySizeLimit: settings.config.security.actionBodySizeLimit,
503
504
  key,
504
505
  csp
505
506
  };
@@ -300,6 +300,7 @@ async function buildManifest(opts, internals, staticFiles, encodedKey) {
300
300
  buildFormat: settings.config.build.format,
301
301
  checkOrigin: (settings.config.security?.checkOrigin && settings.buildOutput === "server") ?? false,
302
302
  allowedDomains: settings.config.security?.allowedDomains,
303
+ actionBodySizeLimit: settings.config.security.actionBodySizeLimit,
303
304
  serverIslandNameMap: Array.from(settings.serverIslandNameMap),
304
305
  key: encodedKey,
305
306
  sessionConfig: settings.config.session,
@@ -64,6 +64,7 @@ export declare const ASTRO_CONFIG_DEFAULTS: {
64
64
  security: {
65
65
  checkOrigin: true;
66
66
  allowedDomains: never[];
67
+ actionBodySizeLimit: number;
67
68
  };
68
69
  env: {
69
70
  schema: {};
@@ -456,6 +457,7 @@ export declare const AstroConfigSchema: z.ZodObject<{
456
457
  protocol?: string | undefined;
457
458
  hostname?: string | undefined;
458
459
  }>, "many">>>;
460
+ actionBodySizeLimit: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
459
461
  }, "strip", z.ZodTypeAny, {
460
462
  checkOrigin: boolean;
461
463
  allowedDomains: {
@@ -463,6 +465,7 @@ export declare const AstroConfigSchema: z.ZodObject<{
463
465
  protocol?: string | undefined;
464
466
  hostname?: string | undefined;
465
467
  }[];
468
+ actionBodySizeLimit: number;
466
469
  }, {
467
470
  checkOrigin?: boolean | undefined;
468
471
  allowedDomains?: {
@@ -470,6 +473,7 @@ export declare const AstroConfigSchema: z.ZodObject<{
470
473
  protocol?: string | undefined;
471
474
  hostname?: string | undefined;
472
475
  }[] | undefined;
476
+ actionBodySizeLimit?: number | undefined;
473
477
  }>>>;
474
478
  env: z.ZodDefault<z.ZodOptional<z.ZodObject<{
475
479
  schema: z.ZodDefault<z.ZodOptional<z.ZodRecord<z.ZodEffects<z.ZodEffects<z.ZodString, string, string>, string, string>, z.ZodIntersection<z.ZodEffects<z.ZodType<{
@@ -1097,6 +1101,7 @@ export declare const AstroConfigSchema: z.ZodObject<{
1097
1101
  protocol?: string | undefined;
1098
1102
  hostname?: string | undefined;
1099
1103
  }[];
1104
+ actionBodySizeLimit: number;
1100
1105
  };
1101
1106
  experimental: {
1102
1107
  clientPrerender: boolean;
@@ -1344,6 +1349,7 @@ export declare const AstroConfigSchema: z.ZodObject<{
1344
1349
  protocol?: string | undefined;
1345
1350
  hostname?: string | undefined;
1346
1351
  }[] | undefined;
1352
+ actionBodySizeLimit?: number | undefined;
1347
1353
  } | undefined;
1348
1354
  experimental?: {
1349
1355
  fonts?: {
@@ -46,7 +46,8 @@ const ASTRO_CONFIG_DEFAULTS = {
46
46
  redirects: {},
47
47
  security: {
48
48
  checkOrigin: true,
49
- allowedDomains: []
49
+ allowedDomains: [],
50
+ actionBodySizeLimit: 1024 * 1024
50
51
  },
51
52
  env: {
52
53
  schema: {},
@@ -252,7 +253,8 @@ const AstroConfigSchema = z.object({
252
253
  protocol: z.string().optional(),
253
254
  port: z.string().optional()
254
255
  })
255
- ).optional().default(ASTRO_CONFIG_DEFAULTS.security.allowedDomains)
256
+ ).optional().default(ASTRO_CONFIG_DEFAULTS.security.allowedDomains),
257
+ actionBodySizeLimit: z.number().optional().default(ASTRO_CONFIG_DEFAULTS.security.actionBodySizeLimit)
256
258
  }).optional().default(ASTRO_CONFIG_DEFAULTS.security),
257
259
  env: z.object({
258
260
  schema: EnvSchema.optional().default(ASTRO_CONFIG_DEFAULTS.env.schema),
@@ -301,6 +301,7 @@ export declare function createRelativeSchema(cmd: string, fileProtocolRoot: stri
301
301
  protocol?: string | undefined;
302
302
  hostname?: string | undefined;
303
303
  }>, "many">>>;
304
+ actionBodySizeLimit: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
304
305
  }, "strip", z.ZodTypeAny, {
305
306
  checkOrigin: boolean;
306
307
  allowedDomains: {
@@ -308,6 +309,7 @@ export declare function createRelativeSchema(cmd: string, fileProtocolRoot: stri
308
309
  protocol?: string | undefined;
309
310
  hostname?: string | undefined;
310
311
  }[];
312
+ actionBodySizeLimit: number;
311
313
  }, {
312
314
  checkOrigin?: boolean | undefined;
313
315
  allowedDomains?: {
@@ -315,6 +317,7 @@ export declare function createRelativeSchema(cmd: string, fileProtocolRoot: stri
315
317
  protocol?: string | undefined;
316
318
  hostname?: string | undefined;
317
319
  }[] | undefined;
320
+ actionBodySizeLimit?: number | undefined;
318
321
  }>>>;
319
322
  env: z.ZodDefault<z.ZodOptional<z.ZodObject<{
320
323
  schema: z.ZodDefault<z.ZodOptional<z.ZodRecord<z.ZodEffects<z.ZodEffects<z.ZodString, string, string>, string, string>, z.ZodIntersection<z.ZodEffects<z.ZodType<{
@@ -1020,6 +1023,7 @@ export declare function createRelativeSchema(cmd: string, fileProtocolRoot: stri
1020
1023
  protocol?: string | undefined;
1021
1024
  hostname?: string | undefined;
1022
1025
  }[];
1026
+ actionBodySizeLimit: number;
1023
1027
  };
1024
1028
  experimental: {
1025
1029
  clientPrerender: boolean;
@@ -1267,6 +1271,7 @@ export declare function createRelativeSchema(cmd: string, fileProtocolRoot: stri
1267
1271
  protocol?: string | undefined;
1268
1272
  hostname?: string | undefined;
1269
1273
  }[] | undefined;
1274
+ actionBodySizeLimit?: number | undefined;
1270
1275
  } | undefined;
1271
1276
  experimental?: {
1272
1277
  fonts?: {
@@ -1450,6 +1455,7 @@ export declare function createRelativeSchema(cmd: string, fileProtocolRoot: stri
1450
1455
  protocol?: string | undefined;
1451
1456
  hostname?: string | undefined;
1452
1457
  }[];
1458
+ actionBodySizeLimit: number;
1453
1459
  };
1454
1460
  experimental: {
1455
1461
  clientPrerender: boolean;
@@ -1697,6 +1703,7 @@ export declare function createRelativeSchema(cmd: string, fileProtocolRoot: stri
1697
1703
  protocol?: string | undefined;
1698
1704
  hostname?: string | undefined;
1699
1705
  }[] | undefined;
1706
+ actionBodySizeLimit?: number | undefined;
1700
1707
  } | undefined;
1701
1708
  experimental?: {
1702
1709
  fonts?: {
@@ -1,4 +1,4 @@
1
- const ASTRO_VERSION = "5.17.3";
1
+ const ASTRO_VERSION = "5.18.0";
2
2
  const REROUTE_DIRECTIVE_HEADER = "X-Astro-Reroute";
3
3
  const REWRITE_DIRECTIVE_HEADER_KEY = "X-Astro-Rewrite";
4
4
  const REWRITE_DIRECTIVE_HEADER_VALUE = "yes";
@@ -22,7 +22,7 @@ async function dev(inlineConfig) {
22
22
  await telemetry.record([]);
23
23
  const restart = await createContainerWithAutomaticRestart({ inlineConfig, fs });
24
24
  const logger = restart.container.logger;
25
- const currentVersion = "5.17.3";
25
+ const currentVersion = "5.18.0";
26
26
  const isPrerelease = currentVersion.includes("-");
27
27
  if (!isPrerelease) {
28
28
  try {
@@ -38,7 +38,7 @@ function serverStart({
38
38
  host,
39
39
  base
40
40
  }) {
41
- const version = "5.17.3";
41
+ const version = "5.18.0";
42
42
  const localPrefix = `${dim("\u2503")} Local `;
43
43
  const networkPrefix = `${dim("\u2503")} Network `;
44
44
  const emptyPrefix = " ".repeat(11);
@@ -275,7 +275,7 @@ function printHelp({
275
275
  message.push(
276
276
  linebreak(),
277
277
  ` ${bgGreen(black(` ${commandName} `))} ${green(
278
- `v${"5.17.3"}`
278
+ `v${"5.18.0"}`
279
279
  )} ${headline}`
280
280
  );
281
281
  }
@@ -563,6 +563,30 @@ export interface AstroUserConfig<TLocales extends Locales = never, TSession exte
563
563
  * When not configured, `X-Forwarded-Host` headers are not trusted and will be ignored.
564
564
  */
565
565
  allowedDomains?: Partial<RemotePattern>[];
566
+ /**
567
+ * @docs
568
+ * @name security.actionBodySizeLimit
569
+ * @kind h4
570
+ * @type {number}
571
+ * @default `1048576` (1 MB)
572
+ * @version 5.18.0
573
+ * @description
574
+ *
575
+ * Sets the maximum size in bytes allowed for action request bodies.
576
+ *
577
+ * By default, action request bodies are limited to 1 MB (1048576 bytes) to prevent abuse.
578
+ * You can increase this limit if your actions need to accept larger payloads, for example when handling file uploads.
579
+ *
580
+ * ```js
581
+ * // astro.config.mjs
582
+ * export default defineConfig({
583
+ * security: {
584
+ * actionBodySizeLimit: 10 * 1024 * 1024 // 10 MB
585
+ * }
586
+ * })
587
+ * ```
588
+ */
589
+ actionBodySizeLimit?: number;
566
590
  };
567
591
  /**
568
592
  * @docs
@@ -106,6 +106,7 @@ function createVitePluginAstroServer({
106
106
  }
107
107
  warnMissingAdapter(logger, settings);
108
108
  pipeline.manifest.checkOrigin = settings.config.security.checkOrigin && settings.buildOutput === "server";
109
+ pipeline.manifest.actionBodySizeLimit = settings.config.security.actionBodySizeLimit;
109
110
  pipeline.setManifestData(routesList);
110
111
  }
111
112
  viteServer.watcher.on("add", rebuildManifest.bind(null, null));
@@ -251,6 +252,7 @@ function createDevelopmentManifest(settings) {
251
252
  inlinedScripts: /* @__PURE__ */ new Map(),
252
253
  i18n: i18nManifest,
253
254
  checkOrigin: (settings.config.security?.checkOrigin && settings.buildOutput === "server") ?? false,
255
+ actionBodySizeLimit: settings.config.security.actionBodySizeLimit,
254
256
  key: hasEnvironmentKey() ? getEnvironmentKey() : createKey(),
255
257
  middleware() {
256
258
  return {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "astro",
3
- "version": "5.17.3",
3
+ "version": "5.18.0",
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",
@@ -154,8 +154,8 @@
154
154
  "zod-to-json-schema": "^3.25.1",
155
155
  "zod-to-ts": "^1.2.0",
156
156
  "@astrojs/internal-helpers": "0.7.5",
157
- "@astrojs/telemetry": "3.3.0",
158
- "@astrojs/markdown-remark": "6.3.10"
157
+ "@astrojs/markdown-remark": "6.3.10",
158
+ "@astrojs/telemetry": "3.3.0"
159
159
  },
160
160
  "optionalDependencies": {
161
161
  "sharp": "^0.34.0"
@@ -193,8 +193,8 @@
193
193
  "undici": "^6.23.0",
194
194
  "unified": "^11.0.5",
195
195
  "vitest": "^3.2.4",
196
- "@astrojs/check": "0.9.6",
197
- "astro-scripts": "0.0.14"
196
+ "astro-scripts": "0.0.14",
197
+ "@astrojs/check": "0.9.6"
198
198
  },
199
199
  "engines": {
200
200
  "node": "18.20.8 || ^20.3.0 || >=22.0.0",