astro 6.0.0-beta.16 → 6.0.0-beta.17

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.
@@ -99,9 +99,10 @@ function getActionContext(context) {
99
99
  }
100
100
  throw error;
101
101
  }
102
+ const bodySizeLimit = pipeline.manifest.actionBodySizeLimit;
102
103
  let input;
103
104
  try {
104
- input = await parseRequestBody(context.request);
105
+ input = await parseRequestBody(context.request, bodySizeLimit);
105
106
  } catch (e) {
106
107
  if (e instanceof ActionError) {
107
108
  return { data: void 0, error: e };
@@ -149,22 +150,21 @@ function getCallerInfo(ctx) {
149
150
  }
150
151
  return void 0;
151
152
  }
152
- const DEFAULT_ACTION_BODY_SIZE_LIMIT = 1024 * 1024;
153
- async function parseRequestBody(request) {
153
+ async function parseRequestBody(request, bodySizeLimit) {
154
154
  const contentType = request.headers.get("content-type");
155
155
  const contentLengthHeader = request.headers.get("content-length");
156
156
  const contentLength = contentLengthHeader ? Number.parseInt(contentLengthHeader, 10) : void 0;
157
157
  const hasContentLength = typeof contentLength === "number" && Number.isFinite(contentLength);
158
158
  if (!contentType) return void 0;
159
- if (hasContentLength && contentLength > DEFAULT_ACTION_BODY_SIZE_LIMIT) {
159
+ if (hasContentLength && contentLength > bodySizeLimit) {
160
160
  throw new ActionError({
161
161
  code: "CONTENT_TOO_LARGE",
162
- message: `Request body exceeds ${DEFAULT_ACTION_BODY_SIZE_LIMIT} bytes`
162
+ message: `Request body exceeds ${bodySizeLimit} bytes`
163
163
  });
164
164
  }
165
165
  if (hasContentType(contentType, formContentTypes)) {
166
166
  if (!hasContentLength) {
167
- const body = await readRequestBodyWithLimit(request.clone(), DEFAULT_ACTION_BODY_SIZE_LIMIT);
167
+ const body = await readRequestBodyWithLimit(request.clone(), bodySizeLimit);
168
168
  const formRequest = new Request(request.url, {
169
169
  method: request.method,
170
170
  headers: request.headers,
@@ -177,7 +177,7 @@ async function parseRequestBody(request) {
177
177
  if (hasContentType(contentType, ["application/json"])) {
178
178
  if (contentLength === 0) return void 0;
179
179
  if (!hasContentLength) {
180
- const body = await readRequestBodyWithLimit(request.clone(), DEFAULT_ACTION_BODY_SIZE_LIMIT);
180
+ const body = await readRequestBodyWithLimit(request.clone(), bodySizeLimit);
181
181
  if (body.byteLength === 0) return void 0;
182
182
  return JSON.parse(new TextDecoder().decode(body));
183
183
  }
@@ -1,6 +1,6 @@
1
1
  class BuildTimeAstroVersionProvider {
2
2
  // Injected during the build through esbuild define
3
- version = "6.0.0-beta.16";
3
+ version = "6.0.0-beta.17";
4
4
  }
5
5
  export {
6
6
  BuildTimeAstroVersionProvider
@@ -33,6 +33,7 @@ function createManifest(manifest, renderers, middleware) {
33
33
  compressHTML: manifest?.compressHTML ?? ASTRO_CONFIG_DEFAULTS.compressHTML,
34
34
  assetsDir: manifest?.assetsDir ?? ASTRO_CONFIG_DEFAULTS.build.assets,
35
35
  serverLike: manifest?.serverLike ?? true,
36
+ middlewareMode: manifest?.middlewareMode ?? "classic",
36
37
  assets: manifest?.assets ?? /* @__PURE__ */ new Set(),
37
38
  assetsPrefix: manifest?.assetsPrefix ?? void 0,
38
39
  entryModules: manifest?.entryModules ?? {},
@@ -47,6 +48,7 @@ function createManifest(manifest, renderers, middleware) {
47
48
  i18n: manifest?.i18n,
48
49
  checkOrigin: false,
49
50
  allowedDomains: manifest?.allowedDomains ?? [],
51
+ actionBodySizeLimit: 1024 * 1024,
50
52
  middleware: manifest?.middleware ?? middlewareInstance,
51
53
  key: createKey(),
52
54
  csp: manifest?.csp,
@@ -3,15 +3,17 @@ import type { Logger } from '../core/logger/core.js';
3
3
  import type { AstroSettings } from '../types/astro.js';
4
4
  import type { RefreshContentOptions } from '../types/public/content.js';
5
5
  import type { MutableDataStore } from './mutable-data-store.js';
6
- interface ContentLayerOptions {
6
+ import { type ContentObservable } from './utils.js';
7
+ export interface ContentLayerOptions {
7
8
  store: MutableDataStore;
8
9
  settings: AstroSettings;
9
10
  logger: Logger;
10
11
  watcher?: FSWatcher;
12
+ contentConfigObserver?: ContentObservable;
11
13
  }
12
- declare class ContentLayer {
14
+ export declare class ContentLayer {
13
15
  #private;
14
- constructor({ settings, logger, store, watcher }: ContentLayerOptions);
16
+ constructor({ settings, logger, store, watcher, contentConfigObserver, }: ContentLayerOptions);
15
17
  /**
16
18
  * Whether the content layer is currently loading content
17
19
  */
@@ -37,9 +39,3 @@ declare class ContentLayer {
37
39
  * In production, it's in the cache directory so that it's preserved between builds.
38
40
  */
39
41
  export declare function getDataStoreFile(settings: AstroSettings, isDev: boolean): URL;
40
- export declare const globalContentLayer: {
41
- init: (options: ContentLayerOptions) => ContentLayer;
42
- get: () => ContentLayer | null;
43
- dispose: () => void;
44
- };
45
- export {};
@@ -30,12 +30,20 @@ class ContentLayer {
30
30
  #unsubscribe;
31
31
  #markdownProcessor;
32
32
  #generateDigest;
33
+ #contentConfigObserver;
33
34
  #queue;
34
- constructor({ settings, logger, store, watcher }) {
35
+ constructor({
36
+ settings,
37
+ logger,
38
+ store,
39
+ watcher,
40
+ contentConfigObserver = globalContentConfigObserver
41
+ }) {
35
42
  watcher?.setMaxListeners(50);
36
43
  this.#logger = logger;
37
44
  this.#store = store;
38
45
  this.#settings = settings;
46
+ this.#contentConfigObserver = contentConfigObserver;
39
47
  if (watcher) {
40
48
  this.#watcher = createWatcherWrapper(watcher);
41
49
  }
@@ -52,7 +60,7 @@ class ContentLayer {
52
60
  */
53
61
  watchContentConfig() {
54
62
  this.#unsubscribe?.();
55
- this.#unsubscribe = globalContentConfigObserver.subscribe(async (ctx) => {
63
+ this.#unsubscribe = this.#contentConfigObserver.subscribe(async (ctx) => {
56
64
  if (ctx.status === "loaded" && ctx.config.digest !== this.#lastConfigDigest) {
57
65
  this.sync();
58
66
  }
@@ -122,12 +130,12 @@ class ContentLayer {
122
130
  return this.#queue.add(() => this.#doSync(options));
123
131
  }
124
132
  async #doSync(options) {
125
- let contentConfig = globalContentConfigObserver.get();
133
+ let contentConfig = this.#contentConfigObserver.get();
126
134
  const logger = this.#logger.forkIntegrationLogger("content");
127
135
  if (contentConfig?.status === "loading") {
128
136
  contentConfig = await Promise.race([
129
137
  new Promise((resolve) => {
130
- const unsub = globalContentConfigObserver.subscribe((ctx) => {
138
+ const unsub = this.#contentConfigObserver.subscribe((ctx) => {
131
139
  unsub();
132
140
  resolve(ctx);
133
141
  });
@@ -170,9 +178,9 @@ ${contentConfig.error.message}`
170
178
  const { digest: currentConfigDigest } = contentConfig.config;
171
179
  this.#lastConfigDigest = currentConfigDigest;
172
180
  let shouldClear = false;
173
- const previousConfigDigest = await this.#store.metaStore().get("content-config-digest");
174
- const previousAstroConfigDigest = await this.#store.metaStore().get("astro-config-digest");
175
- const previousAstroVersion = await this.#store.metaStore().get("astro-version");
181
+ const previousConfigDigest = this.#store.metaStore().get("content-config-digest");
182
+ const previousAstroConfigDigest = this.#store.metaStore().get("astro-config-digest");
183
+ const previousAstroVersion = this.#store.metaStore().get("astro-version");
176
184
  if (previousAstroConfigDigest && previousAstroConfigDigest !== astroConfigDigest) {
177
185
  logger.info("Astro config changed");
178
186
  shouldClear = true;
@@ -181,7 +189,7 @@ ${contentConfig.error.message}`
181
189
  logger.info("Content config changed");
182
190
  shouldClear = true;
183
191
  }
184
- if (previousAstroVersion && previousAstroVersion !== "6.0.0-beta.16") {
192
+ if (previousAstroVersion && previousAstroVersion !== "6.0.0-beta.17") {
185
193
  logger.info("Astro version changed");
186
194
  shouldClear = true;
187
195
  }
@@ -189,14 +197,14 @@ ${contentConfig.error.message}`
189
197
  logger.info("Clearing content store");
190
198
  this.#store.clearAll();
191
199
  }
192
- if ("6.0.0-beta.16") {
193
- await this.#store.metaStore().set("astro-version", "6.0.0-beta.16");
200
+ if ("6.0.0-beta.17") {
201
+ this.#store.metaStore().set("astro-version", "6.0.0-beta.17");
194
202
  }
195
203
  if (currentConfigDigest) {
196
- await this.#store.metaStore().set("content-config-digest", currentConfigDigest);
204
+ this.#store.metaStore().set("content-config-digest", currentConfigDigest);
197
205
  }
198
206
  if (astroConfigDigest) {
199
- await this.#store.metaStore().set("astro-config-digest", astroConfigDigest);
207
+ this.#store.metaStore().set("astro-config-digest", astroConfigDigest);
200
208
  }
201
209
  if (!options?.loaders?.length) {
202
210
  this.#watcher?.removeAllTrackedListeners();
@@ -354,23 +362,7 @@ ${JSON.stringify({ ...raw, id: void 0 }, null, 2)}`
354
362
  function getDataStoreFile(settings, isDev) {
355
363
  return new URL(DATA_STORE_FILE, isDev ? settings.dotAstroDir : settings.config.cacheDir);
356
364
  }
357
- function contentLayerSingleton() {
358
- let instance = null;
359
- return {
360
- init: (options) => {
361
- instance?.dispose();
362
- instance = new ContentLayer(options);
363
- return instance;
364
- },
365
- get: () => instance,
366
- dispose: () => {
367
- instance?.dispose();
368
- instance = null;
369
- }
370
- };
371
- }
372
- const globalContentLayer = contentLayerSingleton();
373
365
  export {
374
- getDataStoreFile,
375
- globalContentLayer
366
+ ContentLayer,
367
+ getDataStoreFile
376
368
  };
@@ -0,0 +1,17 @@
1
+ import type { FSWatcher } from 'vite';
2
+ import { ContentLayer } from './content-layer.js';
3
+ import type { Logger } from '../core/logger/core.js';
4
+ import type { AstroSettings } from '../types/astro.js';
5
+ import type { MutableDataStore } from './mutable-data-store.js';
6
+ interface ContentLayerOptions {
7
+ store: MutableDataStore;
8
+ settings: AstroSettings;
9
+ logger: Logger;
10
+ watcher?: FSWatcher;
11
+ }
12
+ export declare const globalContentLayer: {
13
+ init: (options: ContentLayerOptions) => ContentLayer;
14
+ get: () => ContentLayer | null;
15
+ dispose: () => void;
16
+ };
17
+ export {};
@@ -0,0 +1,20 @@
1
+ import { ContentLayer } from "./content-layer.js";
2
+ function contentLayerSingleton() {
3
+ let instance = null;
4
+ return {
5
+ init: (options) => {
6
+ instance?.dispose();
7
+ instance = new ContentLayer(options);
8
+ return instance;
9
+ },
10
+ get: () => instance,
11
+ dispose: () => {
12
+ instance?.dispose();
13
+ instance = null;
14
+ }
15
+ };
16
+ }
17
+ const globalContentLayer = contentLayerSingleton();
18
+ export {
19
+ globalContentLayer
20
+ };
@@ -9,6 +9,7 @@ import type { LoggerLevel } from '../logger/core.js';
9
9
  import type { RoutingStrategies } from './common.js';
10
10
  import type { BaseSessionConfig, SessionDriverFactory } from '../session/types.js';
11
11
  import type { DevToolbarPlacement } from '../../types/public/toolbar.js';
12
+ import type { MiddlewareMode } from '../../types/public/integrations.js';
12
13
  import type { BaseApp } from './base.js';
13
14
  type ComponentPath = string;
14
15
  export type StylesheetAsset = {
@@ -74,6 +75,12 @@ export type SSRManifest = {
74
75
  * the creation of `dist/client` and `dist/server` folders.
75
76
  */
76
77
  serverLike: boolean;
78
+ /**
79
+ * The middleware mode determines when and how middleware executes.
80
+ * - 'classic' (default): Build-time for prerendered pages, request-time for SSR pages
81
+ * - 'edge': Middleware deployed as separate edge function
82
+ */
83
+ middlewareMode: MiddlewareMode;
77
84
  /**
78
85
  * Map of directive name (e.g. `load`) to the directive script code
79
86
  */
@@ -94,6 +101,7 @@ export type SSRManifest = {
94
101
  }>;
95
102
  checkOrigin: boolean;
96
103
  allowedDomains?: Partial<RemotePattern>[];
104
+ actionBodySizeLimit: number;
97
105
  sessionConfig?: SSRManifestSession;
98
106
  cacheDir: URL;
99
107
  srcDir: URL;
@@ -60,7 +60,8 @@ class Pipeline {
60
60
  async getMiddleware() {
61
61
  if (this.resolvedMiddleware) {
62
62
  return this.resolvedMiddleware;
63
- } else if (this.middleware) {
63
+ }
64
+ if (this.middleware) {
64
65
  const middlewareInstance = await this.middleware();
65
66
  const onRequest = middlewareInstance.onRequest ?? NOOP_MIDDLEWARE_FN;
66
67
  const internalMiddlewares = [onRequest];
@@ -2,6 +2,7 @@ import { fileURLToPath } from "node:url";
2
2
  import { glob } from "tinyglobby";
3
3
  import { getAssetsPrefix } from "../../../assets/utils/getAssetsPrefix.js";
4
4
  import { normalizeTheLocale } from "../../../i18n/index.js";
5
+ import { resolveMiddlewareMode } from "../../../integrations/adapter-utils.js";
5
6
  import { runHookBuildSsr } from "../../../integrations/hooks.js";
6
7
  import { SERIALIZED_MANIFEST_RESOLVED_ID } from "../../../manifest/serialized.js";
7
8
  import { BEFORE_HYDRATION_SCRIPT_ID, PAGE_SCRIPT_ID } from "../../../vite-plugin-scripts/index.js";
@@ -37,7 +38,8 @@ async function manifestBuildPostHook(options, internals, {
37
38
  (c) => !c.prerender && c.moduleIds.includes(SERIALIZED_MANIFEST_RESOLVED_ID)
38
39
  );
39
40
  if (ssrManifestChunk) {
40
- const shouldPassMiddlewareEntryPoint = options.settings.adapter?.adapterFeatures?.edgeMiddleware;
41
+ const middlewareMode = resolveMiddlewareMode(options.settings.adapter?.adapterFeatures);
42
+ const shouldPassMiddlewareEntryPoint = middlewareMode === "edge";
41
43
  await runHookBuildSsr({
42
44
  config: options.settings.config,
43
45
  manifest,
@@ -196,6 +198,7 @@ async function buildManifest(opts, internals, staticFiles, encodedKey) {
196
198
  internalFetchHeaders = headers;
197
199
  }
198
200
  }
201
+ const middlewareMode = resolveMiddlewareMode(opts.settings.adapter?.adapterFeatures);
199
202
  return {
200
203
  rootDir: opts.settings.config.root.toString(),
201
204
  cacheDir: opts.settings.config.cacheDir.toString(),
@@ -208,6 +211,7 @@ async function buildManifest(opts, internals, staticFiles, encodedKey) {
208
211
  assetsDir: opts.settings.config.build.assets,
209
212
  routes,
210
213
  serverLike: opts.settings.buildOutput === "server",
214
+ middlewareMode,
211
215
  site: settings.config.site,
212
216
  base: settings.config.base,
213
217
  userAssetsBase: settings.config?.vite?.base,
@@ -228,6 +232,7 @@ async function buildManifest(opts, internals, staticFiles, encodedKey) {
228
232
  i18n: i18nManifest,
229
233
  buildFormat: settings.config.build.format,
230
234
  checkOrigin: (settings.config.security?.checkOrigin && settings.buildOutput === "server") ?? false,
235
+ actionBodySizeLimit: settings.config.security?.actionBodySizeLimit && settings.buildOutput === "server" ? settings.config.security.actionBodySizeLimit : 1024 * 1024,
231
236
  allowedDomains: settings.config.security?.allowedDomains,
232
237
  key: encodedKey,
233
238
  sessionConfig: sessionConfigToManifest(settings.config.session),
@@ -65,6 +65,7 @@ export declare const ASTRO_CONFIG_DEFAULTS: {
65
65
  checkOrigin: true;
66
66
  allowedDomains: never[];
67
67
  csp: false;
68
+ actionBodySizeLimit: number;
68
69
  };
69
70
  env: {
70
71
  schema: {};
@@ -349,6 +350,7 @@ export declare const AstroConfigSchema: z.ZodObject<{
349
350
  protocol: z.ZodOptional<z.ZodString>;
350
351
  port: z.ZodOptional<z.ZodString>;
351
352
  }, z.core.$strip>>>>;
353
+ actionBodySizeLimit: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
352
354
  csp: z.ZodDefault<z.ZodOptional<z.ZodUnion<readonly [z.ZodDefault<z.ZodOptional<z.ZodBoolean>>, z.ZodObject<{
353
355
  algorithm: z.ZodDefault<z.ZodOptional<z.ZodEnum<{
354
356
  "SHA-256": "SHA-256";
@@ -48,7 +48,8 @@ const ASTRO_CONFIG_DEFAULTS = {
48
48
  security: {
49
49
  checkOrigin: true,
50
50
  allowedDomains: [],
51
- csp: false
51
+ csp: false,
52
+ actionBodySizeLimit: 1024 * 1024
52
53
  },
53
54
  env: {
54
55
  schema: {},
@@ -253,6 +254,7 @@ const AstroConfigSchema = z.object({
253
254
  port: z.string().optional()
254
255
  })
255
256
  ).optional().default(ASTRO_CONFIG_DEFAULTS.security.allowedDomains),
257
+ actionBodySizeLimit: z.number().optional().default(ASTRO_CONFIG_DEFAULTS.security.actionBodySizeLimit),
256
258
  csp: z.union([
257
259
  z.boolean().optional().default(ASTRO_CONFIG_DEFAULTS.security.csp),
258
260
  z.object({
@@ -237,6 +237,7 @@ export declare function createRelativeSchema(cmd: string, fileProtocolRoot: stri
237
237
  protocol: z.ZodOptional<z.ZodString>;
238
238
  port: z.ZodOptional<z.ZodString>;
239
239
  }, z.core.$strip>>>>;
240
+ actionBodySizeLimit: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
240
241
  csp: z.ZodDefault<z.ZodOptional<z.ZodUnion<readonly [z.ZodDefault<z.ZodOptional<z.ZodBoolean>>, z.ZodObject<{
241
242
  algorithm: z.ZodDefault<z.ZodOptional<z.ZodEnum<{
242
243
  "SHA-256": "SHA-256";
@@ -491,6 +492,7 @@ export declare function createRelativeSchema(cmd: string, fileProtocolRoot: stri
491
492
  protocol?: string | undefined;
492
493
  port?: string | undefined;
493
494
  }[];
495
+ actionBodySizeLimit: number;
494
496
  csp: boolean | {
495
497
  algorithm: "SHA-256" | "SHA-384" | "SHA-512";
496
498
  directives?: (`base-uri${string}` | `child-src${string}` | `connect-src${string}` | `default-src${string}` | `fenced-frame-src${string}` | `font-src${string}` | `form-action${string}` | `frame-ancestors${string}` | `frame-src${string}` | `img-src${string}` | `manifest-src${string}` | `media-src${string}` | `object-src${string}` | `referrer${string}` | `report-to${string}` | `report-uri${string}` | `require-trusted-types-for${string}` | `sandbox${string}` | `trusted-types${string}` | `upgrade-insecure-requests${string}` | `worker-src${string}`)[] | undefined;
@@ -719,6 +721,7 @@ export declare function createRelativeSchema(cmd: string, fileProtocolRoot: stri
719
721
  protocol?: string | undefined;
720
722
  port?: string | undefined;
721
723
  }[];
724
+ actionBodySizeLimit: number;
722
725
  csp: boolean | {
723
726
  algorithm: "SHA-256" | "SHA-384" | "SHA-512";
724
727
  directives?: (`base-uri${string}` | `child-src${string}` | `connect-src${string}` | `default-src${string}` | `fenced-frame-src${string}` | `font-src${string}` | `form-action${string}` | `frame-ancestors${string}` | `frame-src${string}` | `img-src${string}` | `manifest-src${string}` | `media-src${string}` | `object-src${string}` | `referrer${string}` | `report-to${string}` | `report-uri${string}` | `require-trusted-types-for${string}` | `sandbox${string}` | `trusted-types${string}` | `upgrade-insecure-requests${string}` | `worker-src${string}`)[] | undefined;
@@ -1,4 +1,4 @@
1
- const ASTRO_VERSION = "6.0.0-beta.16";
1
+ const ASTRO_VERSION = "6.0.0-beta.17";
2
2
  const ASTRO_GENERATOR = `Astro v${ASTRO_VERSION}`;
3
3
  const REROUTE_DIRECTIVE_HEADER = "X-Astro-Reroute";
4
4
  const REWRITE_DIRECTIVE_HEADER_KEY = "X-Astro-Rewrite";
@@ -2,7 +2,8 @@ import fs from "node:fs";
2
2
  import { performance } from "node:perf_hooks";
3
3
  import colors from "piccolore";
4
4
  import { gt, major, minor, patch } from "semver";
5
- import { getDataStoreFile, globalContentLayer } from "../../content/content-layer.js";
5
+ import { getDataStoreFile } from "../../content/content-layer.js";
6
+ import { globalContentLayer } from "../../content/instance.js";
6
7
  import { attachContentServerListeners } from "../../content/index.js";
7
8
  import { MutableDataStore } from "../../content/mutable-data-store.js";
8
9
  import { globalContentConfigObserver } from "../../content/utils.js";
@@ -25,7 +26,7 @@ async function dev(inlineConfig) {
25
26
  await telemetry.record([]);
26
27
  const restart = await createContainerWithAutomaticRestart({ inlineConfig, fs });
27
28
  const logger = restart.container.logger;
28
- const currentVersion = "6.0.0-beta.16";
29
+ const currentVersion = "6.0.0-beta.17";
29
30
  const isPrerelease = currentVersion.includes("-");
30
31
  if (!isPrerelease) {
31
32
  try {
@@ -1,6 +1,6 @@
1
1
  import { fileURLToPath } from "node:url";
2
2
  import * as vite from "vite";
3
- import { globalContentLayer } from "../../content/content-layer.js";
3
+ import { globalContentLayer } from "../../content/instance.js";
4
4
  import { attachContentServerListeners } from "../../content/server-listeners.js";
5
5
  import { eventCliSession, telemetry } from "../../events/index.js";
6
6
  import { SETTINGS_FILE } from "../../preferences/constants.js";
@@ -269,7 +269,7 @@ function printHelp({
269
269
  message.push(
270
270
  linebreak(),
271
271
  ` ${bgGreen(black(` ${commandName} `))} ${green(
272
- `v${"6.0.0-beta.16"}`
272
+ `v${"6.0.0-beta.17"}`
273
273
  )} ${headline}`
274
274
  );
275
275
  }
@@ -6,7 +6,8 @@ import colors from "piccolore";
6
6
  import { createServer } from "vite";
7
7
  import { syncFonts } from "../../assets/fonts/sync.js";
8
8
  import { CONTENT_TYPES_FILE } from "../../content/consts.js";
9
- import { getDataStoreFile, globalContentLayer } from "../../content/content-layer.js";
9
+ import { getDataStoreFile } from "../../content/content-layer.js";
10
+ import { globalContentLayer } from "../../content/instance.js";
10
11
  import { createContentTypesGenerator } from "../../content/index.js";
11
12
  import { MutableDataStore } from "../../content/mutable-data-store.js";
12
13
  import { getContentPaths, globalContentConfigObserver } from "../../content/utils.js";
@@ -0,0 +1,19 @@
1
+ import type { AstroAdapterFeatures, MiddlewareMode } from '../types/public/integrations.js';
2
+ /**
3
+ * Resolves the middleware mode from adapter features.
4
+ * Handles backward compatibility with the deprecated `edgeMiddleware` flag.
5
+ *
6
+ * @example
7
+ * ```ts
8
+ * // New way
9
+ * resolveMiddlewareMode({ middlewareMode: 'always' }) // 'always'
10
+ *
11
+ * // Backward compatibility
12
+ * resolveMiddlewareMode({ edgeMiddleware: true }) // 'edge'
13
+ * resolveMiddlewareMode({ edgeMiddleware: false }) // 'classic'
14
+ *
15
+ * // Default
16
+ * resolveMiddlewareMode({}) // 'classic'
17
+ * ```
18
+ */
19
+ export declare function resolveMiddlewareMode(features?: AstroAdapterFeatures): MiddlewareMode;
@@ -0,0 +1,12 @@
1
+ function resolveMiddlewareMode(features) {
2
+ if (features?.middlewareMode) {
3
+ return features.middlewareMode;
4
+ }
5
+ if (features?.edgeMiddleware === true) {
6
+ return "edge";
7
+ }
8
+ return "classic";
9
+ }
10
+ export {
11
+ resolveMiddlewareMode
12
+ };
@@ -5,7 +5,7 @@ import { mergeConfig as mergeViteConfig } from "vite";
5
5
  import astroIntegrationActionsRouteHandler from "../actions/integration.js";
6
6
  import { isActionsFilePresent } from "../actions/utils.js";
7
7
  import { CONTENT_LAYER_TYPE } from "../content/consts.js";
8
- import { globalContentLayer } from "../content/content-layer.js";
8
+ import { globalContentLayer } from "../content/instance.js";
9
9
  import { globalContentConfigObserver } from "../content/utils.js";
10
10
  import { buildClientDirectiveEntrypoint } from "../core/client-directive/index.js";
11
11
  import { mergeConfig } from "../core/config/merge.js";
@@ -21,6 +21,7 @@ import { ASTRO_RENDERERS_MODULE_ID } from "../vite-plugin-renderers/index.js";
21
21
  import { ASTRO_ROUTES_MODULE_ID } from "../vite-plugin-routes/index.js";
22
22
  import { sessionConfigToManifest } from "../core/session/utils.js";
23
23
  import { ASTRO_VITE_ENVIRONMENT_NAMES } from "../core/constants.js";
24
+ import { resolveMiddlewareMode } from "../integrations/adapter-utils.js";
24
25
  const SERIALIZED_MANIFEST_ID = "virtual:astro:manifest";
25
26
  const SERIALIZED_MANIFEST_RESOLVED_ID = "\0" + SERIALIZED_MANIFEST_ID;
26
27
  function serializedManifestPlugin({
@@ -133,6 +134,7 @@ async function createSerializedManifest(settings) {
133
134
  buildFormat: settings.config.build.format,
134
135
  compressHTML: settings.config.compressHTML,
135
136
  serverLike: settings.buildOutput === "server",
137
+ middlewareMode: resolveMiddlewareMode(settings.adapter?.adapterFeatures),
136
138
  assets: [],
137
139
  entryModules: {},
138
140
  routes: [],
@@ -147,6 +149,8 @@ async function createSerializedManifest(settings) {
147
149
  inlinedScripts: [],
148
150
  i18n: i18nManifest,
149
151
  checkOrigin: (settings.config.security?.checkOrigin && settings.buildOutput === "server") ?? false,
152
+ actionBodySizeLimit: settings.config.security?.actionBodySizeLimit ? settings.config.security.actionBodySizeLimit : 1024 * 1024,
153
+ // 1mb default
150
154
  key: await encodeKey(hasEnvironmentKey() ? await getEnvironmentKey() : await createKey()),
151
155
  sessionConfig: sessionConfigToManifest(settings.config.session),
152
156
  csp,
@@ -600,6 +600,30 @@ export interface AstroUserConfig<TLocales extends Locales = never, TDriver exten
600
600
  * When not configured, `X-Forwarded-Host` headers are not trusted and will be ignored.
601
601
  */
602
602
  allowedDomains?: Partial<RemotePattern>[];
603
+ /**
604
+ * @docs
605
+ * @name security.actionBodySizeLimit
606
+ * @kind h4
607
+ * @type {number}
608
+ * @default `1048576` (1 MB)
609
+ * @version 5.18.0
610
+ * @description
611
+ *
612
+ * Sets the maximum size in bytes allowed for action request bodies.
613
+ *
614
+ * By default, action request bodies are limited to 1 MB (1048576 bytes) to prevent abuse.
615
+ * You can increase this limit if your actions need to accept larger payloads, for example when handling file uploads.
616
+ *
617
+ * ```js
618
+ * // astro.config.mjs
619
+ * export default defineConfig({
620
+ * security: {
621
+ * actionBodySizeLimit: 10 * 1024 * 1024 // 10 MB
622
+ * }
623
+ * })
624
+ * ```
625
+ */
626
+ actionBodySizeLimit?: number;
603
627
  /**
604
628
  * @docs
605
629
  * @name security.csp
@@ -65,12 +65,22 @@ export type AdapterSupportWithMessage = {
65
65
  suppress?: 'all' | 'default';
66
66
  };
67
67
  export type AdapterSupport = AdapterSupportsKind | AdapterSupportWithMessage;
68
+ export type MiddlewareMode = 'classic' | 'edge';
68
69
  export interface AstroAdapterFeatures {
69
70
  /**
70
- * Defines whether any on-demand rendering middleware code will be bundled when built. When enabled, this prevents
71
- * middleware code from being bundled and imported by all pages during the build.
71
+ * Creates an edge function that will communicate with the Astro middleware
72
+ *
73
+ * @deprecated Use `middlewareMode: 'edge'` instead
74
+ */
75
+ edgeMiddleware?: boolean;
76
+ /**
77
+ * Determines when and how middleware executes:
78
+ * - `'classic'` (default): Middleware runs for prerendered pages at build time, and for SSR pages at request time. Does not run for prerendered pages at request time.
79
+ * - `'edge'`: Middleware is deployed as a separate edge function. Middleware code will not be bundled and imported by all pages during the build.
80
+ *
81
+ * @default 'classic'
72
82
  */
73
- edgeMiddleware: boolean;
83
+ middlewareMode?: MiddlewareMode;
74
84
  /**
75
85
  * Allows you to force a specific output shape for the build. This can be useful for adapters that only work with
76
86
  * a specific output type. For example, your adapter might expect a static website so it can create host-specific
@@ -19,6 +19,7 @@ import { getViteErrorPayload } from "../core/errors/dev/index.js";
19
19
  import { AstroError, AstroErrorData } from "../core/errors/index.js";
20
20
  import { NOOP_MIDDLEWARE_FN } from "../core/middleware/noop-middleware.js";
21
21
  import { createViteLoader } from "../core/module-loader/index.js";
22
+ import { resolveMiddlewareMode } from "../integrations/adapter-utils.js";
22
23
  import { SERIALIZED_MANIFEST_ID } from "../manifest/serialized.js";
23
24
  import { ASTRO_DEV_SERVER_APP_ID } from "../vite-plugin-app/index.js";
24
25
  import { baseMiddleware } from "./base.js";
@@ -137,6 +138,7 @@ async function createDevelopmentManifest(settings) {
137
138
  compressHTML: settings.config.compressHTML,
138
139
  assetsDir: settings.config.build.assets,
139
140
  serverLike: settings.buildOutput === "server",
141
+ middlewareMode: resolveMiddlewareMode(settings.adapter?.adapterFeatures),
140
142
  assets: /* @__PURE__ */ new Set(),
141
143
  entryModules: {},
142
144
  routes: [],
@@ -151,6 +153,8 @@ async function createDevelopmentManifest(settings) {
151
153
  inlinedScripts: /* @__PURE__ */ new Map(),
152
154
  i18n: i18nManifest,
153
155
  checkOrigin: (settings.config.security?.checkOrigin && settings.buildOutput === "server") ?? false,
156
+ actionBodySizeLimit: settings.config.security?.actionBodySizeLimit ? settings.config.security.actionBodySizeLimit : 1024 * 1024,
157
+ // 1mb default
154
158
  key: hasEnvironmentKey() ? getEnvironmentKey() : createKey(),
155
159
  middleware() {
156
160
  return {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "astro",
3
- "version": "6.0.0-beta.16",
3
+ "version": "6.0.0-beta.17",
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",
@@ -151,9 +151,9 @@
151
151
  "xxhash-wasm": "^1.1.0",
152
152
  "yargs-parser": "^22.0.0",
153
153
  "zod": "^4.3.6",
154
- "@astrojs/markdown-remark": "7.0.0-beta.7",
155
- "@astrojs/telemetry": "3.3.0",
156
- "@astrojs/internal-helpers": "0.8.0-beta.1"
154
+ "@astrojs/internal-helpers": "0.8.0-beta.1",
155
+ "@astrojs/markdown-remark": "7.0.0-beta.8",
156
+ "@astrojs/telemetry": "3.3.0"
157
157
  },
158
158
  "optionalDependencies": {
159
159
  "sharp": "^0.34.0"