astro 7.1.4 → 7.1.6

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 (43) hide show
  1. package/dist/cli/infra/build-time-astro-version-provider.js +1 -1
  2. package/dist/container/index.js +1 -2
  3. package/dist/content/consts.d.ts +4 -0
  4. package/dist/content/consts.js +8 -0
  5. package/dist/content/content-layer.js +3 -3
  6. package/dist/content/data-store-writer.d.ts +1 -1
  7. package/dist/content/data-store-writer.js +4 -3
  8. package/dist/content/data-store.d.ts +3 -3
  9. package/dist/content/data-store.js +3 -3
  10. package/dist/content/mutable-data-store.d.ts +3 -3
  11. package/dist/content/mutable-data-store.js +5 -5
  12. package/dist/content/paths.d.ts +2 -1
  13. package/dist/content/paths.js +11 -0
  14. package/dist/content/vite-plugin-content-virtual-mod.js +41 -15
  15. package/dist/core/app/types.d.ts +0 -2
  16. package/dist/core/base-pipeline.js +9 -3
  17. package/dist/core/build/generate.js +58 -51
  18. package/dist/core/build/plugins/plugin-manifest.js +1 -6
  19. package/dist/core/config/schemas/base.d.ts +4 -4
  20. package/dist/core/config/schemas/base.js +8 -1
  21. package/dist/core/config/schemas/relative.d.ts +12 -6
  22. package/dist/core/constants.js +1 -1
  23. package/dist/core/create-vite.js +2 -0
  24. package/dist/core/dev/dev.js +5 -4
  25. package/dist/core/errors/default-handler.d.ts +1 -1
  26. package/dist/core/errors/default-handler.js +16 -0
  27. package/dist/core/errors/dev-handler.d.ts +1 -1
  28. package/dist/core/errors/dev-handler.js +10 -0
  29. package/dist/core/errors/handler.d.ts +14 -0
  30. package/dist/core/errors/handler.js +7 -0
  31. package/dist/core/logger/load.d.ts +4 -0
  32. package/dist/core/logger/load.js +25 -51
  33. package/dist/core/logger/utils.d.ts +21 -0
  34. package/dist/core/logger/utils.js +20 -0
  35. package/dist/core/logger/vite-plugin.d.ts +30 -0
  36. package/dist/core/logger/vite-plugin.js +79 -0
  37. package/dist/core/messages/runtime.js +1 -1
  38. package/dist/core/routing/handler.js +16 -2
  39. package/dist/core/sync/index.js +5 -4
  40. package/dist/manifest/serialized.js +4 -6
  41. package/dist/types/public/config.d.ts +17 -8
  42. package/dist/vite-plugin-hmr-reload/index.js +60 -18
  43. package/package.json +7 -7
@@ -48,6 +48,7 @@ import { ServerIslandsState } from "./server-islands/shared-state.js";
48
48
  import { vitePluginServerIslands } from "./server-islands/vite-plugin-server-islands.js";
49
49
  import { vitePluginCacheProvider } from "./cache/vite-plugin.js";
50
50
  import { vitePluginSessionDriver } from "./session/vite-plugin.js";
51
+ import { vitePluginLogger } from "./logger/vite-plugin.js";
51
52
  import { isObject } from "./util-runtime.js";
52
53
  import { vitePluginEnvironment } from "../vite-plugin-environment/index.js";
53
54
  import { ASTRO_VITE_ENVIRONMENT_NAMES } from "./constants.js";
@@ -180,6 +181,7 @@ async function createVite(commandConfig, { settings, logger, mode, command, fs =
180
181
  vitePluginServerIslands({ settings, logger, serverIslandsState }),
181
182
  vitePluginSessionDriver({ settings }),
182
183
  vitePluginCacheProvider({ settings }),
184
+ vitePluginLogger({ settings }),
183
185
  astroContainer(),
184
186
  astroHmrReloadPlugin(),
185
187
  vitePluginChromedevtools({ settings }),
@@ -2,7 +2,7 @@ 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 { getDataStoreDir, getDataStoreFile } from "../../content/paths.js";
5
+ import { getDataStoreChunkSize, getDataStoreDir, getDataStoreFile } from "../../content/paths.js";
6
6
  import { globalContentLayer } from "../../content/instance.js";
7
7
  import { attachContentServerListeners } from "../../content/index.js";
8
8
  import { MutableDataStore } from "../../content/mutable-data-store.js";
@@ -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.1.4";
29
+ const currentVersion = "7.1.6";
30
30
  const isPrerelease = currentVersion.includes("-");
31
31
  if (!isPrerelease) {
32
32
  try {
@@ -56,9 +56,10 @@ async function dev(inlineConfig) {
56
56
  }
57
57
  let store;
58
58
  try {
59
- if (restart.container.settings.config.experimental.collectionStorage === "chunked") {
59
+ const chunkSize = getDataStoreChunkSize(restart.container.settings);
60
+ if (chunkSize !== void 0) {
60
61
  const dataStoreDir = getDataStoreDir(restart.container.settings, true);
61
- store = await MutableDataStore.fromDir(dataStoreDir);
62
+ store = await MutableDataStore.fromDir(dataStoreDir, chunkSize);
62
63
  } else {
63
64
  const dataStoreFile = getDataStoreFile(restart.container.settings, true);
64
65
  store = await MutableDataStore.fromFile(dataStoreFile);
@@ -1,6 +1,6 @@
1
1
  import type { BaseApp, RenderErrorOptions } from '../app/base.js';
2
2
  import type { Pipeline } from '../base-pipeline.js';
3
- import type { ErrorHandler } from './handler.js';
3
+ import { type ErrorHandler } from './handler.js';
4
4
  /**
5
5
  * The default error handler used in production SSR. Attempts to render the
6
6
  * matching error route (404.astro / 500.astro), falling back to a plain
@@ -9,6 +9,7 @@ import { provideSession } from "../session/handler.js";
9
9
  import { validateHost } from "../app/validate-headers.js";
10
10
  import { getErrorRoutePath } from "../../i18n/error-routes.js";
11
11
  import { getOutputFilename } from "../output-filename.js";
12
+ import { rewroteToEmptyErrorResponse } from "./handler.js";
12
13
  class DefaultErrorHandler {
13
14
  #app;
14
15
  #astroMiddleware;
@@ -82,6 +83,21 @@ class DefaultErrorHandler {
82
83
  errorState,
83
84
  this.#pagesHandler.handle.bind(this.#pagesHandler)
84
85
  );
86
+ if (rewroteToEmptyErrorResponse(
87
+ skipMiddleware,
88
+ errorRouteData,
89
+ errorState.routeData,
90
+ response2
91
+ )) {
92
+ return this.renderError(request, {
93
+ ...resolvedRenderOptions,
94
+ status,
95
+ error,
96
+ response: originalResponse,
97
+ skipMiddleware: true,
98
+ pathname: resolvedPathname
99
+ });
100
+ }
85
101
  const newResponse = mergeResponses(response2, originalResponse);
86
102
  prepareResponse(newResponse, resolvedRenderOptions);
87
103
  return newResponse;
@@ -1,6 +1,6 @@
1
1
  import type { BaseApp, RenderErrorOptions } from '../app/base.js';
2
2
  import type { Pipeline } from '../base-pipeline.js';
3
- import type { ErrorHandler } from './handler.js';
3
+ import { type ErrorHandler } from './handler.js';
4
4
  export interface DevErrorHandlerOptions {
5
5
  /**
6
6
  * Whether to inject CSP meta tags into the rendered error page response.
@@ -4,6 +4,7 @@ import { PagesHandler } from "../pages/handler.js";
4
4
  import { getCustom404Route, getCustom500Route } from "../routing/helpers.js";
5
5
  import { isAstroError } from "./index.js";
6
6
  import { MiddlewareNoDataOrNextCalled, MiddlewareNotAResponse } from "./errors-data.js";
7
+ import { rewroteToEmptyErrorResponse } from "./handler.js";
7
8
  class DevErrorHandler {
8
9
  #app;
9
10
  #shouldInjectCspMetaTags;
@@ -46,6 +47,15 @@ class DevErrorHandler {
46
47
  errorState,
47
48
  this.#pagesHandler.handle.bind(this.#pagesHandler)
48
49
  );
50
+ if (rewroteToEmptyErrorResponse(skipMiddleware, routeData, errorState.routeData, response)) {
51
+ return this.renderError(request, {
52
+ ...resolvedRenderOptions,
53
+ status,
54
+ error,
55
+ skipMiddleware: true,
56
+ pathname: resolvedPathname
57
+ });
58
+ }
49
59
  if (error) {
50
60
  app.logger.error("router", error.stack || error.message);
51
61
  }
@@ -1,4 +1,5 @@
1
1
  import type { RenderErrorOptions } from '../app/base.js';
2
+ import type { RouteData } from '../../types/public/index.js';
2
3
  /**
3
4
  * A strategy for rendering error responses (404, 500, etc.). Each execution
4
5
  * environment (prod SSR, build/prerender, dev server) supplies its own
@@ -7,3 +8,16 @@ import type { RenderErrorOptions } from '../app/base.js';
7
8
  export interface ErrorHandler {
8
9
  renderError(request: Request, options: RenderErrorOptions): Promise<Response>;
9
10
  }
11
+ /**
12
+ * Whether a middleware rewrite (`ctx.rewrite()` / `next(payload)`) issued while
13
+ * rendering the error page dead-ended in another empty reroutable (404/500)
14
+ * response. The rewrite swaps the state's routeData away from the error route,
15
+ * so returning that render as-is would produce a blank page; the error handler
16
+ * should instead retry rendering the error page without middleware.
17
+ *
18
+ * @param skipMiddleware Whether middleware was already skipped for this render.
19
+ * @param errorRouteData The error route matched before middleware ran.
20
+ * @param renderedRouteData The route data on the state after middleware ran.
21
+ * @param response The response produced by the middleware-driven render.
22
+ */
23
+ export declare function rewroteToEmptyErrorResponse(skipMiddleware: boolean, errorRouteData: RouteData, renderedRouteData: RouteData | undefined, response: Response): boolean;
@@ -0,0 +1,7 @@
1
+ import { REROUTABLE_STATUS_CODES } from "../constants.js";
2
+ function rewroteToEmptyErrorResponse(skipMiddleware, errorRouteData, renderedRouteData, response) {
3
+ return skipMiddleware === false && renderedRouteData !== errorRouteData && response.body === null && REROUTABLE_STATUS_CODES.includes(response.status);
4
+ }
5
+ export {
6
+ rewroteToEmptyErrorResponse
7
+ };
@@ -1,6 +1,10 @@
1
1
  import { AstroLogger, type AstroLoggerDestination } from './core.js';
2
2
  import type { LoggerHandlerConfig } from './config.js';
3
3
  import type { AstroConfig, AstroInlineConfig } from '../../types/public/index.js';
4
+ /**
5
+ * Loads a logger destination in a Node context, i.e. outside of a built server bundle.
6
+ * Inside the bundle, the destination comes from the `virtual:astro:logger` module instead.
7
+ */
4
8
  export declare function loadLoggerDestination(config: LoggerHandlerConfig): Promise<AstroLoggerDestination>;
5
9
  /**
6
10
  * It attempts to load a logger from the entrypoint.
@@ -1,64 +1,38 @@
1
+ import { isAbsolute } from "node:path";
2
+ import { pathToFileURL } from "node:url";
1
3
  import { AstroLogger } from "./core.js";
2
4
  import { AstroError } from "../errors/index.js";
3
5
  import { UnableToLoadLogger } from "../errors/errors-data.js";
4
- import { default as nodeLoggerCreator, createNodeLoggerFromFlags } from "./impls/node.js";
5
- import { default as consoleLoggerCreator } from "./impls/console.js";
6
- import { default as jsonLoggerCreator } from "./impls/json.js";
7
- import { default as composeLoggerCreator } from "./impls/compose.js";
8
- function normalizeEntrypoint(entrypoint) {
9
- return entrypoint instanceof URL ? entrypoint.href : entrypoint;
6
+ import { createNodeLoggerFromFlags } from "./impls/node.js";
7
+ import {
8
+ COMPOSE_LOGGER_ENTRYPOINT,
9
+ normalizeLoggerConfig
10
+ } from "./utils.js";
11
+ async function createDestination(config) {
12
+ const specifier = isAbsolute(config.entrypoint) ? pathToFileURL(config.entrypoint).href : config.entrypoint;
13
+ const logger = await import(
14
+ /* @vite-ignore */
15
+ specifier
16
+ );
17
+ if (config.entrypoint === COMPOSE_LOGGER_ENTRYPOINT) {
18
+ return logger.default(await Promise.all((config.loggers ?? []).map(createDestination)));
19
+ }
20
+ return logger.default(config.config);
10
21
  }
11
22
  async function loadLoggerDestination(config) {
12
- let cause = void 0;
13
- const entrypoint = normalizeEntrypoint(config.entrypoint);
23
+ const normalized = normalizeLoggerConfig(config);
14
24
  try {
15
- switch (config.entrypoint) {
16
- case "astro/logger/node": {
17
- return nodeLoggerCreator(config.config);
18
- }
19
- case "astro/logger/console": {
20
- return consoleLoggerCreator(config.config);
21
- }
22
- case "astro/logger/json": {
23
- return jsonLoggerCreator(config.config);
24
- }
25
- case "astro/logger/compose": {
26
- let destinations = [];
27
- if (config.config?.loggers) {
28
- const loggers = config.config?.loggers;
29
- destinations = await Promise.all(
30
- loggers.map(async (loggerConfig) => {
31
- const logger = await import(
32
- /* @vite-ignore */
33
- normalizeEntrypoint(loggerConfig.entrypoint)
34
- );
35
- return logger.default(loggerConfig.config);
36
- })
37
- );
38
- }
39
- return composeLoggerCreator(destinations);
40
- }
41
- default: {
42
- const logger = await import(
43
- /* @vite-ignore */
44
- entrypoint
45
- );
46
- return logger.default(config.config);
47
- }
48
- }
25
+ return await createDestination(normalized);
49
26
  } catch (e) {
27
+ const error = new AstroError({
28
+ ...UnableToLoadLogger,
29
+ message: UnableToLoadLogger.message(normalized.entrypoint)
30
+ });
50
31
  if (e instanceof Error) {
51
- cause = e;
32
+ error.cause = e;
52
33
  }
34
+ throw error;
53
35
  }
54
- const error = new AstroError({
55
- ...UnableToLoadLogger,
56
- message: UnableToLoadLogger.message(entrypoint)
57
- });
58
- if (cause) {
59
- error.cause = cause;
60
- }
61
- throw error;
62
36
  }
63
37
  async function loadOrCreateNodeLogger(astroConfig, inlineAstroConfig) {
64
38
  if (inlineAstroConfig._logger) return inlineAstroConfig._logger;
@@ -0,0 +1,21 @@
1
+ import type { LoggerHandlerConfig } from './config.js';
2
+ export declare const COMPOSE_LOGGER_ENTRYPOINT = "astro/logger/compose";
3
+ export interface NormalizedLoggerConfig {
4
+ /** An absolute file path or a package specifier */
5
+ entrypoint: string;
6
+ /** Serializable options passed to the handler factory */
7
+ config?: Record<string, any> | undefined;
8
+ /** The composed handlers. Only set for `astro/logger/compose` */
9
+ loggers?: NormalizedLoggerConfig[];
10
+ }
11
+ /**
12
+ * Normalizes a user-provided logger config by turning its `entrypoint` into a string that
13
+ * can be resolved as-is, either by Vite (see `vitePluginLogger`) or by Node
14
+ * (see `loadLoggerDestination`), and by applying the same treatment to the handlers
15
+ * composed through `astro/logger/compose`.
16
+ *
17
+ * Concretely, a `URL` entrypoint becomes an absolute file path — mirroring what session
18
+ * drivers do, since both Vite and `import()` can handle those — while a string entrypoint,
19
+ * e.g. a package specifier, is left untouched.
20
+ */
21
+ export declare function normalizeLoggerConfig(logger: LoggerHandlerConfig): NormalizedLoggerConfig;
@@ -0,0 +1,20 @@
1
+ import { fileURLToPath } from "node:url";
2
+ const COMPOSE_LOGGER_ENTRYPOINT = "astro/logger/compose";
3
+ function normalizeLoggerConfig(logger) {
4
+ const entrypoint = normalizeEntrypoint(logger.entrypoint);
5
+ if (entrypoint === COMPOSE_LOGGER_ENTRYPOINT) {
6
+ const loggers = logger.config?.loggers ?? [];
7
+ return {
8
+ entrypoint,
9
+ loggers: loggers.map((nested) => normalizeLoggerConfig(nested))
10
+ };
11
+ }
12
+ return { entrypoint, config: logger.config };
13
+ }
14
+ function normalizeEntrypoint(entrypoint) {
15
+ return entrypoint instanceof URL ? fileURLToPath(entrypoint) : entrypoint;
16
+ }
17
+ export {
18
+ COMPOSE_LOGGER_ENTRYPOINT,
19
+ normalizeLoggerConfig
20
+ };
@@ -0,0 +1,30 @@
1
+ import type { Plugin as VitePlugin } from 'vite';
2
+ import type { AstroSettings } from '../../types/astro.js';
3
+ import { type NormalizedLoggerConfig } from './utils.js';
4
+ export declare const VIRTUAL_LOGGER_ID = "virtual:astro:logger";
5
+ /** Resolves an entrypoint to a module id, or `null` if it cannot be resolved. */
6
+ type ResolveEntrypoint = (entrypoint: string) => Promise<string | null>;
7
+ interface EmittedDestination {
8
+ /** The expression instantiating the destination, e.g. `_logger0({ level: 'info' })` */
9
+ expression: string;
10
+ /** The import statements `expression` depends on, in declaration order */
11
+ imports: string[];
12
+ }
13
+ /**
14
+ * Emits the source of a logger destination, so that the handler is part of the bundle
15
+ * rather than imported at runtime from a path that no longer exists once deployed.
16
+ *
17
+ * This is the build-time counterpart of `createDestination()` in `./load.ts`: both walk
18
+ * the same normalized config, but this one *generates code* that instantiates the
19
+ * destination, while the Node one instantiates it directly through `import()`.
20
+ */
21
+ export declare function emitDestination(config: NormalizedLoggerConfig, resolveEntrypoint: ResolveEntrypoint,
22
+ /**
23
+ * Import names must be unique across the whole virtual module, so nested
24
+ * destinations continue numbering where their parent left off.
25
+ */
26
+ nameOffset?: number): Promise<EmittedDestination>;
27
+ export declare function vitePluginLogger({ settings, }: {
28
+ settings: AstroSettings;
29
+ }): VitePlugin | undefined;
30
+ export {};
@@ -0,0 +1,79 @@
1
+ import { fileURLToPath } from "node:url";
2
+ import { UnableToLoadLogger } from "../errors/errors-data.js";
3
+ import { AstroError } from "../errors/index.js";
4
+ import { normalizeLoggerConfig } from "./utils.js";
5
+ const VIRTUAL_LOGGER_ID = "virtual:astro:logger";
6
+ const RESOLVED_VIRTUAL_LOGGER_ID = "\0" + VIRTUAL_LOGGER_ID;
7
+ async function emitDestination(config, resolveEntrypoint, nameOffset = 0) {
8
+ let resolved = null;
9
+ let cause;
10
+ try {
11
+ resolved = await resolveEntrypoint(config.entrypoint);
12
+ } catch (e) {
13
+ cause = e;
14
+ }
15
+ if (!resolved) {
16
+ const error = new AstroError({
17
+ ...UnableToLoadLogger,
18
+ message: UnableToLoadLogger.message(config.entrypoint)
19
+ });
20
+ if (cause instanceof Error) {
21
+ error.cause = cause;
22
+ }
23
+ throw error;
24
+ }
25
+ const name = `_logger${nameOffset}`;
26
+ const imports = [`import ${name} from ${JSON.stringify(resolved)};`];
27
+ if (config.loggers) {
28
+ const expressions = [];
29
+ for (const nested of config.loggers) {
30
+ const emitted = await emitDestination(nested, resolveEntrypoint, nameOffset + imports.length);
31
+ imports.push(...emitted.imports);
32
+ expressions.push(emitted.expression);
33
+ }
34
+ return { expression: `${name}([${expressions.join(", ")}])`, imports };
35
+ }
36
+ return { expression: `${name}(${JSON.stringify(config.config) ?? "undefined"})`, imports };
37
+ }
38
+ function vitePluginLogger({
39
+ settings
40
+ }) {
41
+ const loggerConfig = settings.config.logger;
42
+ if (!loggerConfig) {
43
+ return;
44
+ }
45
+ return {
46
+ name: VIRTUAL_LOGGER_ID,
47
+ enforce: "pre",
48
+ resolveId: {
49
+ filter: {
50
+ id: new RegExp(`^${VIRTUAL_LOGGER_ID}$`)
51
+ },
52
+ handler() {
53
+ return RESOLVED_VIRTUAL_LOGGER_ID;
54
+ }
55
+ },
56
+ load: {
57
+ filter: {
58
+ id: new RegExp(`^${RESOLVED_VIRTUAL_LOGGER_ID}$`)
59
+ },
60
+ async handler() {
61
+ const importerPath = fileURLToPath(new URL("package.json", settings.config.root));
62
+ const { expression, imports } = await emitDestination(
63
+ normalizeLoggerConfig(loggerConfig),
64
+ async (entrypoint) => (await this.resolve(entrypoint, importerPath))?.id ?? null
65
+ );
66
+ return {
67
+ code: `${imports.join("\n")}
68
+ export default ${expression};
69
+ `
70
+ };
71
+ }
72
+ }
73
+ };
74
+ }
75
+ export {
76
+ VIRTUAL_LOGGER_ID,
77
+ emitDestination,
78
+ vitePluginLogger
79
+ };
@@ -270,7 +270,7 @@ function printHelp({
270
270
  message.push(
271
271
  linebreak(),
272
272
  ` ${bgGreen(black(` ${commandName} `))} ${green(
273
- `v${"7.1.4"}`
273
+ `v${"7.1.6"}`
274
274
  )} ${headline}`
275
275
  );
276
276
  }
@@ -93,6 +93,7 @@ class AstroHandler {
93
93
  const defaultStatus = this.#app.getDefaultStatusCode(routeData, pathname);
94
94
  state.status = defaultStatus;
95
95
  let response;
96
+ let finalizeError;
96
97
  try {
97
98
  const sessionP = this.#hasSession ? provideSession(state) : void 0;
98
99
  const cacheP = provideCache(state);
@@ -143,8 +144,21 @@ class AstroHandler {
143
144
  pathname: state.pathname
144
145
  });
145
146
  } finally {
146
- const finalize = state.finalizeAll();
147
- if (finalize) await finalize;
147
+ try {
148
+ const finalize = state.finalizeAll();
149
+ if (finalize) await finalize;
150
+ } catch (err) {
151
+ finalizeError = err;
152
+ this.#app.logger.error(null, err.stack || err.message || String(err));
153
+ }
154
+ }
155
+ if (finalizeError) {
156
+ return this.#app.renderError(request, {
157
+ ...state.renderOptions,
158
+ status: 500,
159
+ error: finalizeError,
160
+ pathname: state.pathname
161
+ });
148
162
  }
149
163
  if (REROUTABLE_STATUS_CODES.includes(response.status) && // If the body isn't null, that means the user sets the 404 status
150
164
  // but uses the current route to handle the 404
@@ -6,7 +6,7 @@ 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 { getDataStoreDir, getDataStoreFile } from "../../content/paths.js";
9
+ import { getDataStoreChunkSize, getDataStoreDir, getDataStoreFile } from "../../content/paths.js";
10
10
  import { globalContentLayer } from "../../content/instance.js";
11
11
  import { createContentTypesGenerator } from "../../content/index.js";
12
12
  import { MutableDataStore } from "../../content/mutable-data-store.js";
@@ -59,7 +59,7 @@ async function clearContentLayerCache({
59
59
  fs = fsMod,
60
60
  isDev
61
61
  }) {
62
- if (settings.config.experimental.collectionStorage === "chunked") {
62
+ if (getDataStoreChunkSize(settings) !== void 0) {
63
63
  const dataStore = getDataStoreDir(settings, isDev);
64
64
  if (fs.existsSync(dataStore)) {
65
65
  logger.debug("content", "clearing data store");
@@ -98,9 +98,10 @@ async function syncInternal({
98
98
  settings.timer.start("Sync content layer");
99
99
  let store;
100
100
  try {
101
- if (settings.config.experimental.collectionStorage === "chunked") {
101
+ const chunkSize = getDataStoreChunkSize(settings);
102
+ if (chunkSize !== void 0) {
102
103
  const dataStoreDir = getDataStoreDir(settings, isDev);
103
- store = await MutableDataStore.fromDir(dataStoreDir);
104
+ store = await MutableDataStore.fromDir(dataStoreDir, chunkSize);
104
105
  } else {
105
106
  const dataStoreFile = getDataStoreFile(settings, isDev);
106
107
  store = await MutableDataStore.fromFile(dataStoreFile);
@@ -20,6 +20,7 @@ import { MIDDLEWARE_MODULE_ID } from "../core/middleware/vite-plugin.js";
20
20
  import { SERVER_ISLAND_MANIFEST } from "../core/server-islands/vite-plugin-server-islands.js";
21
21
  import { VIRTUAL_CACHE_PROVIDER_ID } from "../core/cache/vite-plugin.js";
22
22
  import { VIRTUAL_SESSION_DRIVER_ID } from "../core/session/vite-plugin.js";
23
+ import { VIRTUAL_LOGGER_ID } from "../core/logger/vite-plugin.js";
23
24
  import { VIRTUAL_PAGES_MODULE_ID } from "../vite-plugin-pages/index.js";
24
25
  import { ASTRO_RENDERERS_MODULE_ID } from "../vite-plugin-renderers/index.js";
25
26
  import { ASTRO_ROUTES_MODULE_ID } from "../vite-plugin-routes/index.js";
@@ -86,6 +87,7 @@ function serializedManifestPlugin({
86
87
  }
87
88
  const hasCacheConfig = !!settings.config.cache?.provider;
88
89
  const cacheProviderLine = hasCacheConfig ? `cacheProvider: () => import('${VIRTUAL_CACHE_PROVIDER_ID}'),` : "";
90
+ const loggerLine = settings.config.logger ? `logger: () => import('${VIRTUAL_LOGGER_ID}'),` : "";
89
91
  const code = `
90
92
  import { deserializeManifest as _deserializeManifest } from 'astro/app';
91
93
  import { renderers } from '${ASTRO_RENDERERS_MODULE_ID}';
@@ -106,6 +108,7 @@ function serializedManifestPlugin({
106
108
  middleware: () => import('${MIDDLEWARE_MODULE_ID}'),
107
109
  sessionDriver: () => import('${VIRTUAL_SESSION_DRIVER_ID}'),
108
110
  ${cacheProviderLine}
111
+ ${loggerLine}
109
112
  serverIslandMappings: () => import('${SERVER_ISLAND_MANIFEST}'),
110
113
  routes: manifestRoutes,
111
114
  pageMap,
@@ -157,10 +160,6 @@ async function createSerializedManifest(settings, encodedKey) {
157
160
  styleDirective
158
161
  };
159
162
  }
160
- let loggerConfig = void 0;
161
- if (settings.config.logger) {
162
- loggerConfig = settings.config.logger;
163
- }
164
163
  return {
165
164
  rootDir: settings.config.root.toString(),
166
165
  srcDir: settings.config.srcDir.toString(),
@@ -210,8 +209,7 @@ async function createSerializedManifest(settings, encodedKey) {
210
209
  placement: settings.config.devToolbar.placement
211
210
  },
212
211
  logLevel: settings.logLevel,
213
- shouldInjectCspMetaTags: false,
214
- loggerConfig
212
+ shouldInjectCspMetaTags: false
215
213
  };
216
214
  }
217
215
  export {
@@ -1516,8 +1516,7 @@ export interface AstroUserConfig<TLocales extends Locales = never, TDriver exten
1516
1516
  *
1517
1517
  * By default, Astro uses a built-in logger that outputs human-friendly logs to the console. You can customize this behavior by providing [your own logger handler](https://docs.astro.build/en/reference/logger-reference/#custom-loggers) or by using one of the [built-in log handlers](https://docs.astro.build/en/reference/logger-reference/#built-in-loggers):
1518
1518
  *
1519
- * ```js
1520
- * // astro.config.mjs
1519
+ * ```js title="astro.config.mjs"
1521
1520
  * import { defineConfig, logHandlers } from 'astro/config';
1522
1521
  *
1523
1522
  * export default defineConfig({
@@ -1535,7 +1534,8 @@ export interface AstroUserConfig<TLocales extends Locales = never, TDriver exten
1535
1534
  * @version 7.0.0
1536
1535
  * @description
1537
1536
  *
1538
- * The entrypoint of the log handler. This can be a path to a file in your project or an npm package:
1537
+ * The entrypoint for the [logger implementation](https://docs.astro.build/en/reference/logger-reference/#the-logger-implementation).
1538
+ * This can be an npm package, or a `URL` pointing to a file in your project:
1539
1539
  *
1540
1540
  * ```js title="astro.config.mjs"
1541
1541
  * import { defineConfig } from 'astro/config';
@@ -3128,7 +3128,7 @@ export interface AstroUserConfig<TLocales extends Locales = never, TDriver exten
3128
3128
  svgOptimizer?: SvgOptimizer;
3129
3129
  /**
3130
3130
  * @name experimental.collectionStorage
3131
- * @type {'single-file' | 'chunked'}
3131
+ * @type {'single-file' | 'chunked' | { type: 'chunked', chunkSize: number }}
3132
3132
  * @default `'single-file'`
3133
3133
  * @version 7.1.0
3134
3134
  * @description
@@ -3139,22 +3139,31 @@ export interface AstroUserConfig<TLocales extends Locales = never, TDriver exten
3139
3139
  * file. For very large content collections, this file can grow large
3140
3140
  * enough to hit platform file-size limits.
3141
3141
  *
3142
- * When set to `'chunked'`, the store is split across many smaller,
3143
- * content-addressed files so that no single file grows unbounded.
3142
+ * When set to `'chunked'`, the store is split into files
3143
+ * with a maximum size of 20 MiB each. To customize the maximum size,
3144
+ * pass an object with `type: 'chunked'` and `chunkSize`. A 1 MiB limit
3145
+ * is recommended for broad adapter compatibility.
3144
3146
  *
3145
3147
  * ```js
3146
3148
  * import { defineConfig } from 'astro/config';
3147
3149
  *
3148
3150
  * export default defineConfig({
3149
3151
  * experimental: {
3150
- * collectionStorage: 'chunked',
3152
+ * collectionStorage: {
3153
+ * type: 'chunked',
3154
+ * chunkSize: 1024 * 1024,
3155
+ * },
3151
3156
  * },
3152
3157
  * });
3153
3158
  * ```
3154
3159
  *
3155
3160
  * See the [experimental data store chunking documentation](https://docs.astro.build/en/reference/experimental-flags/collection-storage/) for more information.
3156
3161
  */
3157
- collectionStorage?: 'single-file' | 'chunked';
3162
+ collectionStorage?: 'single-file' | 'chunked' | {
3163
+ type: 'chunked';
3164
+ /** Maximum UTF-8 byte size of each data store chunk. */
3165
+ chunkSize: number;
3166
+ };
3158
3167
  };
3159
3168
  }
3160
3169
  /**