astro 7.0.9 → 7.1.1

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 (71) hide show
  1. package/dist/assets/fonts/infra/fs-font-file-content-resolver.js +1 -1
  2. package/dist/cli/dev/index.d.ts +17 -0
  3. package/dist/cli/dev/index.js +56 -2
  4. package/dist/cli/infra/build-time-astro-version-provider.js +1 -1
  5. package/dist/content/consts.d.ts +2 -0
  6. package/dist/content/consts.js +4 -0
  7. package/dist/content/content-layer.d.ts +0 -6
  8. package/dist/content/content-layer.js +4 -9
  9. package/dist/content/data-store-source.d.ts +36 -0
  10. package/dist/content/data-store-source.js +30 -0
  11. package/dist/content/data-store-writer.d.ts +67 -0
  12. package/dist/content/data-store-writer.js +94 -0
  13. package/dist/content/data-store.d.ts +15 -0
  14. package/dist/content/data-store.js +33 -3
  15. package/dist/content/loaders/glob.d.ts +7 -0
  16. package/dist/content/loaders/glob.js +2 -2
  17. package/dist/content/mutable-data-store.d.ts +8 -0
  18. package/dist/content/mutable-data-store.js +52 -15
  19. package/dist/content/paths.d.ts +14 -0
  20. package/dist/content/paths.js +11 -0
  21. package/dist/content/runtime.js +4 -4
  22. package/dist/content/vite-plugin-content-virtual-mod.js +29 -2
  23. package/dist/core/app/dev/pipeline.js +2 -1
  24. package/dist/core/app/types.d.ts +39 -5
  25. package/dist/core/base-pipeline.d.ts +1 -1
  26. package/dist/core/base-pipeline.js +6 -2
  27. package/dist/core/build/index.js +2 -1
  28. package/dist/core/build/plugins/plugin-manifest.js +23 -8
  29. package/dist/core/config/schemas/base.d.ts +38 -5
  30. package/dist/core/config/schemas/base.js +15 -8
  31. package/dist/core/config/schemas/relative.d.ts +73 -15
  32. package/dist/core/constants.js +1 -1
  33. package/dist/core/csp/common.d.ts +7 -7
  34. package/dist/core/csp/common.js +8 -9
  35. package/dist/core/csp/config.d.ts +45 -0
  36. package/dist/core/csp/config.js +44 -2
  37. package/dist/core/csp/runtime.d.ts +21 -1
  38. package/dist/core/csp/runtime.js +31 -0
  39. package/dist/core/dev/dev.js +9 -4
  40. package/dist/core/dev/restart.js +7 -1
  41. package/dist/core/errors/zod-error-map.js +7 -1
  42. package/dist/core/fetch/fetch-state.js +77 -29
  43. package/dist/core/i18n/domain.d.ts +1 -1
  44. package/dist/core/i18n/domain.js +4 -5
  45. package/dist/core/logger/config.d.ts +1 -1
  46. package/dist/core/logger/core.d.ts +4 -4
  47. package/dist/core/logger/impls/console.d.ts +2 -2
  48. package/dist/core/logger/impls/json.d.ts +2 -2
  49. package/dist/core/logger/impls/json.js +3 -14
  50. package/dist/core/logger/impls/node.d.ts +2 -2
  51. package/dist/core/logger/load.d.ts +2 -2
  52. package/dist/core/logger/load.js +19 -27
  53. package/dist/core/messages/runtime.d.ts +8 -0
  54. package/dist/core/messages/runtime.js +34 -1
  55. package/dist/core/render/paginate.js +21 -16
  56. package/dist/core/sync/index.js +23 -8
  57. package/dist/integrations/hooks.js +8 -0
  58. package/dist/manifest/serialized.js +21 -6
  59. package/dist/runtime/server/escape.d.ts +2 -0
  60. package/dist/runtime/server/escape.js +4 -0
  61. package/dist/runtime/server/render/csp.js +80 -19
  62. package/dist/runtime/server/render/server-islands.js +6 -4
  63. package/dist/runtime/server/transition.js +2 -2
  64. package/dist/types/astro.d.ts +2 -3
  65. package/dist/types/public/common.d.ts +13 -0
  66. package/dist/types/public/config.d.ts +196 -15
  67. package/dist/types/public/context.d.ts +27 -11
  68. package/dist/types/public/internal.d.ts +12 -11
  69. package/dist/vite-plugin-app/pipeline.js +2 -1
  70. package/dist/vite-plugin-astro-server/route-guard.js +3 -2
  71. package/package.json +3 -3
@@ -1,15 +1,21 @@
1
1
  import { existsSync, promises as fs } from "node:fs";
2
+ import { fileURLToPath } from "node:url";
2
3
  import * as devalue from "devalue";
3
4
  import { Traverse } from "neotraverse/modern";
4
5
  import { imageSrcToImportId, importIdToSymbolName } from "../assets/utils/resolveImports.js";
5
6
  import { AstroError, AstroErrorData } from "../core/errors/index.js";
6
- import { IMAGE_IMPORT_PREFIX } from "./consts.js";
7
+ import { DATA_STORE_MANIFEST_FILE, IMAGE_IMPORT_PREFIX } from "./consts.js";
8
+ import {
9
+ ChunkedWriter,
10
+ FileWriter,
11
+ serializeDataStore
12
+ } from "./data-store-writer.js";
7
13
  import { ImmutableDataStore } from "./data-store.js";
8
14
  import { contentModuleToId } from "./utils.js";
9
15
  const SAVE_DEBOUNCE_MS = 500;
10
16
  const MAX_DEPTH = 10;
11
17
  class MutableDataStore extends ImmutableDataStore {
12
- #file;
18
+ #writer;
13
19
  #assetsFile;
14
20
  #modulesFile;
15
21
  #saveTimeout;
@@ -201,7 +207,7 @@ ${lines.join(",\n")}]);
201
207
  clearTimeout(this.#saveTimeout);
202
208
  }
203
209
  this.#saveTimeout = void 0;
204
- if (this.#file) {
210
+ if (this.#writer) {
205
211
  await this.writeToDisk();
206
212
  }
207
213
  this.#maybeResolveSavePromise();
@@ -218,7 +224,7 @@ ${lines.join(",\n")}]);
218
224
  }
219
225
  this.#saveTimeout = setTimeout(async () => {
220
226
  this.#saveTimeout = void 0;
221
- if (this.#file) {
227
+ if (this.#writer) {
222
228
  await this.writeToDisk();
223
229
  }
224
230
  this.#maybeResolveSavePromise();
@@ -340,19 +346,13 @@ ${lines.join(",\n")}]);
340
346
  return this.#savePromise;
341
347
  }
342
348
  toString() {
343
- const sorted = new Map(
344
- [...this._collections.entries()].sort(([a], [b]) => a.localeCompare(b)).map(([key, collection]) => [
345
- key,
346
- new Map([...collection.entries()].sort(([a], [b]) => a.localeCompare(b)))
347
- ])
348
- );
349
- return devalue.stringify(sorted);
349
+ return serializeDataStore(this._collections);
350
350
  }
351
351
  async writeToDisk() {
352
352
  if (!this.#dirty) {
353
353
  return;
354
354
  }
355
- if (!this.#file) {
355
+ if (!this.#writer) {
356
356
  throw new AstroError(AstroErrorData.UnknownFilesystemError);
357
357
  }
358
358
  if (this.#writeInProgress) {
@@ -362,7 +362,7 @@ ${lines.join(",\n")}]);
362
362
  try {
363
363
  this.#dirty = false;
364
364
  this.#writeInProgress = true;
365
- await this.#writeFileAtomic(this.#file, this.toString());
365
+ await this.#writer.write(this._collections);
366
366
  } catch (err) {
367
367
  throw new AstroError(AstroErrorData.UnknownFilesystemError, { cause: err });
368
368
  } finally {
@@ -400,7 +400,7 @@ ${lines.join(",\n")}]);
400
400
  if (existsSync(filePath)) {
401
401
  const data = await fs.readFile(filePath, "utf-8");
402
402
  const store2 = await MutableDataStore.fromString(data);
403
- store2.#file = filePath;
403
+ store2.#writer = new FileWriter(filePath);
404
404
  return store2;
405
405
  } else {
406
406
  await fs.mkdir(new URL("./", filePath), { recursive: true });
@@ -408,7 +408,44 @@ ${lines.join(",\n")}]);
408
408
  } catch {
409
409
  }
410
410
  const store = new MutableDataStore();
411
- store.#file = filePath;
411
+ store.#writer = new FileWriter(filePath);
412
+ return store;
413
+ }
414
+ /**
415
+ * Loads a MutableDataStore from a chunked store directory (experimental
416
+ * `collectionStorage: 'chunked'`), reading the manifest and its referenced parts.
417
+ * If the directory has no manifest yet (fresh build) it starts empty. If the
418
+ * manifest exists but can't be read (corrupt cache), it warns and starts
419
+ * empty so loaders rebuild it, rather than failing the sync.
420
+ */
421
+ static async fromDir(dirPath) {
422
+ const manifestFile = new URL(`./${DATA_STORE_MANIFEST_FILE}`, dirPath);
423
+ if (existsSync(manifestFile)) {
424
+ try {
425
+ const manifestData = await fs.readFile(manifestFile, "utf-8");
426
+ const manifest = JSON.parse(manifestData);
427
+ const expanded = {};
428
+ for (const collectionName in manifest) {
429
+ expanded[collectionName] = await Promise.all(
430
+ manifest[collectionName].map(
431
+ (fileName) => fs.readFile(new URL(`./${fileName}`, dirPath), "utf-8")
432
+ )
433
+ );
434
+ }
435
+ const map = ImmutableDataStore.manifestToMap(expanded);
436
+ const store2 = await MutableDataStore.fromMap(map);
437
+ store2.#writer = new ChunkedWriter(dirPath);
438
+ return store2;
439
+ } catch (err) {
440
+ console.warn(
441
+ `[content] Could not read the chunked data store at ${fileURLToPath(dirPath)}, rebuilding from scratch.`,
442
+ err
443
+ );
444
+ }
445
+ }
446
+ await fs.mkdir(dirPath, { recursive: true });
447
+ const store = new MutableDataStore();
448
+ store.#writer = new ChunkedWriter(dirPath);
412
449
  return store;
413
450
  }
414
451
  }
@@ -0,0 +1,14 @@
1
+ import type { AstroSettings } from '../types/astro.js';
2
+ /**
3
+ * Get the path to the data store file.
4
+ * During development, this is in the `.astro` directory so that the Vite watcher can see it.
5
+ * In production, it's in the cache directory so that it's preserved between builds.
6
+ */
7
+ export declare function getDataStoreFile(settings: AstroSettings, isDev: boolean): URL;
8
+ /**
9
+ * Get the path to the data store directory, used when the store is split across
10
+ * multiple files (experimental `collectionStorage: 'chunked'`).
11
+ * During development, this is in the `.astro` directory so that the Vite watcher can see it.
12
+ * In production, it's in the cache directory so that it's preserved between builds.
13
+ */
14
+ export declare function getDataStoreDir(settings: AstroSettings, isDev: boolean): URL;
@@ -0,0 +1,11 @@
1
+ import { DATA_STORE_DIR, DATA_STORE_FILE } from "./consts.js";
2
+ function getDataStoreFile(settings, isDev) {
3
+ return new URL(DATA_STORE_FILE, isDev ? settings.dotAstroDir : settings.config.cacheDir);
4
+ }
5
+ function getDataStoreDir(settings, isDev) {
6
+ return new URL(DATA_STORE_DIR, isDev ? settings.dotAstroDir : settings.config.cacheDir);
7
+ }
8
+ export {
9
+ getDataStoreDir,
10
+ getDataStoreFile
11
+ };
@@ -73,10 +73,10 @@ function createGetCollection({
73
73
  }
74
74
  const hasFilter = typeof filter === "function";
75
75
  const store = await globalDataStore.get();
76
- if (store.hasCollection(collection)) {
76
+ if (await store.hasCollection(collection)) {
77
77
  const { default: imageAssetMap } = await import("astro:asset-imports");
78
78
  const result = [];
79
- for (const rawEntry of store.values(collection)) {
79
+ for (const rawEntry of await store.values(collection)) {
80
80
  const data = updateImageReferencesInData(rawEntry.data, rawEntry.filePath, imageAssetMap);
81
81
  let entry = {
82
82
  ...rawEntry,
@@ -127,8 +127,8 @@ function createGetEntry({ liveCollections }) {
127
127
  });
128
128
  }
129
129
  const store = await globalDataStore.get();
130
- if (store.hasCollection(collection)) {
131
- const entry = store.get(collection, lookupId);
130
+ if (await store.hasCollection(collection)) {
131
+ const entry = await store.get(collection, lookupId);
132
132
  if (!entry) {
133
133
  console.warn(`Entry ${collection} \u2192 ${lookupId} was not found.`);
134
134
  return;
@@ -13,6 +13,7 @@ import {
13
13
  ASSET_IMPORTS_VIRTUAL_ID,
14
14
  CONTENT_MODULE_FLAG,
15
15
  CONTENT_RENDER_FLAG,
16
+ DATA_STORE_MANIFEST_FILE,
16
17
  DATA_STORE_VIRTUAL_ID,
17
18
  MODULES_IMPORTS_FILE,
18
19
  MODULES_MJS_ID,
@@ -21,7 +22,7 @@ import {
21
22
  RESOLVED_VIRTUAL_MODULE_ID,
22
23
  VIRTUAL_MODULE_ID
23
24
  } from "./consts.js";
24
- import { getDataStoreFile } from "./content-layer.js";
25
+ import { getDataStoreDir, getDataStoreFile } from "./paths.js";
25
26
  import { getContentPaths, isDeferredModule } from "./utils.js";
26
27
  const LARGE_DATA_STORE_THRESHOLD = 5 * 1024 * 1024;
27
28
  function invalidateAssetImports(viteServer, filePath) {
@@ -70,6 +71,7 @@ function astroContentVirtualModPlugin({
70
71
  settings,
71
72
  fs
72
73
  }) {
74
+ let dataStoreDir;
73
75
  let dataStoreFile;
74
76
  let devServer;
75
77
  let liveConfig;
@@ -79,7 +81,12 @@ function astroContentVirtualModPlugin({
79
81
  enforce: "pre",
80
82
  config(_, env) {
81
83
  isDev = env.command === "serve";
82
- dataStoreFile = getDataStoreFile(settings, env.command === "serve");
84
+ if (settings.config.experimental.collectionStorage === "chunked") {
85
+ dataStoreDir = getDataStoreDir(settings, env.command === "serve");
86
+ dataStoreFile = new URL(DATA_STORE_MANIFEST_FILE, dataStoreDir);
87
+ } else {
88
+ dataStoreFile = getDataStoreFile(settings, env.command === "serve");
89
+ }
83
90
  const contentPaths = getContentPaths(
84
91
  settings.config,
85
92
  void 0,
@@ -172,6 +179,26 @@ function astroContentVirtualModPlugin({
172
179
  return { code: "export default new Map()" };
173
180
  }
174
181
  const jsonData = await fs.promises.readFile(dataStoreFile, "utf-8");
182
+ if (settings.config.experimental.collectionStorage === "chunked") {
183
+ try {
184
+ const manifest = JSON.parse(jsonData);
185
+ const rawImport = (fileName) => {
186
+ const path = rootRelativePath(
187
+ settings.config.root,
188
+ new URL(`./${fileName}`, dataStoreDir)
189
+ );
190
+ return `(await import(${JSON.stringify(`${path}?raw`)}))`;
191
+ };
192
+ const entries = Object.entries(manifest).map(
193
+ ([collection, parts]) => `${JSON.stringify(collection)}:[${parts.map(rawImport).join(",")}]`
194
+ );
195
+ const code = `export default{${entries.join(",")}}`;
196
+ return { code, map: { mappings: "" } };
197
+ } catch (err) {
198
+ const message = "Could not parse data store manifest JSON file";
199
+ this.error({ message, id, cause: err });
200
+ }
201
+ }
175
202
  try {
176
203
  const parsed = JSON.parse(jsonData);
177
204
  const useRuntimeJsonParse = isDev && Buffer.byteLength(jsonData) > LARGE_DATA_STORE_THRESHOLD;
@@ -2,6 +2,7 @@ import { Pipeline } from "../../base-pipeline.js";
2
2
  import { ASTRO_VERSION } from "../../constants.js";
3
3
  import { createModuleScriptElement, createStylesheetElementSet } from "../../render/ssr-element.js";
4
4
  import { findRouteToRewrite } from "../../routing/rewrite.js";
5
+ import { stringifyForScript } from "../../../runtime/server/escape.js";
5
6
  class NonRunnablePipeline extends Pipeline {
6
7
  getName() {
7
8
  return "NonRunnablePipeline";
@@ -73,7 +74,7 @@ class NonRunnablePipeline extends Pipeline {
73
74
  debugInfo: this.manifest.devToolbar.debugInfoOutput ?? "",
74
75
  placement: this.manifest.devToolbar.placement
75
76
  };
76
- const children = `window.__astro_dev_toolbar__ = ${JSON.stringify(additionalMetadata)}`;
77
+ const children = `window.__astro_dev_toolbar__ = ${stringifyForScript(additionalMetadata)}`;
77
78
  scripts.add({ props: {}, children });
78
79
  }
79
80
  const { devCSSMap } = await import("virtual:astro:dev-css-all");
@@ -4,8 +4,8 @@ import type { AstroMiddlewareInstance } from '../../types/public/common.js';
4
4
  import type { AstroConfig, CspAlgorithm, Locales, RemotePattern } from '../../types/public/config.js';
5
5
  import type { RouteData, SSRComponentMetadata, SSRLoadedRenderer, SSRResult } from '../../types/public/internal.js';
6
6
  import type { SinglePageBuiltModule } from '../build/types.js';
7
- import type { CspDirective } from '../csp/config.js';
8
- import type { AstroLoggerDestination, AstroLoggerLevel, AstroLoggerMessage } from '../logger/core.js';
7
+ import type { AstroLoggerDestination, AstroLoggerLevel } from '../logger/core.js';
8
+ import type { CspDirective, CspHashEntry, CspResourceEntry } from '../csp/config.js';
9
9
  import type { RoutingStrategies } from './common.js';
10
10
  import type { CacheProviderFactory, SSRManifestCache } from '../cache/types.js';
11
11
  import type { BaseSessionConfig, SessionDriverFactory } from '../session/types.js';
@@ -91,9 +91,9 @@ export type SSRManifest = {
91
91
  i18n: SSRManifestI18n | undefined;
92
92
  middleware?: () => Promise<AstroMiddlewareInstance> | AstroMiddlewareInstance;
93
93
  logger?: () => Promise<{
94
- default: AstroLoggerDestination<AstroLoggerMessage>;
94
+ default: AstroLoggerDestination;
95
95
  }> | {
96
- default: AstroLoggerDestination<AstroLoggerMessage>;
96
+ default: AstroLoggerDestination;
97
97
  };
98
98
  actions?: () => Promise<SSRActions> | SSRActions;
99
99
  sessionDriver?: () => Promise<{
@@ -152,15 +152,49 @@ export type SSRManifestI18n = {
152
152
  domainLookupTable: Record<string, string>;
153
153
  domains: Record<string, string> | undefined;
154
154
  };
155
+ /**
156
+ * The CSP section of the manifest. It mirrors the `security.csp` config: `directives` plus a
157
+ * `scriptDirective`/`styleDirective`, each holding `resources`/`hashes` entries that carry their
158
+ * `kind` (`default`/`element`/`attribute`). The `kind` is only interpreted at render time. Astro's
159
+ * generated hashes are appended to the relevant `hashes` array as `default`-kind entries.
160
+ */
155
161
  export type SSRManifestCSP = {
156
162
  cspDestination: 'adapter' | 'meta' | 'header' | undefined;
157
163
  algorithm: CspAlgorithm;
164
+ directives: CspDirective[];
165
+ /**
166
+ * @deprecated Use {@linkcode scriptDirective} instead. Holds the `default`-kind `script-src`
167
+ * hashes (the same values `scriptDirective.hashes` carries with `kind: "default"`).
168
+ */
158
169
  scriptHashes: string[];
170
+ /**
171
+ * @deprecated Use {@linkcode scriptDirective} instead. Holds the `default`-kind `script-src`
172
+ * resources.
173
+ */
159
174
  scriptResources: string[];
175
+ /**
176
+ * @deprecated Use {@linkcode scriptDirective}'s `strictDynamic` instead.
177
+ */
160
178
  isStrictDynamic: boolean;
179
+ /**
180
+ * @deprecated Use {@linkcode styleDirective} instead. Holds the `default`-kind `style-src`
181
+ * hashes.
182
+ */
161
183
  styleHashes: string[];
184
+ /**
185
+ * @deprecated Use {@linkcode styleDirective} instead. Holds the `default`-kind `style-src`
186
+ * resources.
187
+ */
162
188
  styleResources: string[];
163
- directives: CspDirective[];
189
+ scriptDirective: {
190
+ resources: CspResourceEntry[];
191
+ hashes: CspHashEntry[];
192
+ strictDynamic: boolean;
193
+ };
194
+ styleDirective: {
195
+ resources: CspResourceEntry[];
196
+ hashes: CspHashEntry[];
197
+ };
164
198
  };
165
199
  export interface SSRManifestSession extends BaseSessionConfig {
166
200
  driver: string;
@@ -6,7 +6,7 @@ import type { RuntimeMode } from '../types/public/config.js';
6
6
  import type { RouteData, SSRActions, SSRLoadedRenderer, SSRManifest, SSRResult } from '../types/public/internal.js';
7
7
  import type { ServerIslandMappings } from './app/types.js';
8
8
  import type { SinglePageBuiltModule } from './build/types.js';
9
- import type { AstroLogger } from './logger/core.js';
9
+ import { AstroLogger } from './logger/core.js';
10
10
  import { RouteCache } from './render/route-cache.js';
11
11
  import { type DefaultRouteParams } from './routing/default.js';
12
12
  import type { CacheProvider, CacheProviderFactory } from './cache/types.js';
@@ -2,6 +2,7 @@ import { NOOP_ACTIONS_MOD } from "../actions/noop-actions.js";
2
2
  import { createOriginCheckMiddleware } from "./app/origin-check.js";
3
3
  import { ActionNotFoundError } from "./errors/errors-data.js";
4
4
  import { AstroError } from "./errors/index.js";
5
+ import { AstroLogger } from "./logger/core.js";
5
6
  import { NOOP_MIDDLEWARE_FN } from "./middleware/noop-middleware.js";
6
7
  import { sequence } from "./middleware/sequence.js";
7
8
  import { RedirectSinglePageBuiltModule } from "./redirects/index.js";
@@ -10,7 +11,7 @@ import { createDefaultRoutes } from "./routing/default.js";
10
11
  import { ensure404Route } from "./routing/astro-designed-error-pages.js";
11
12
  import { Router } from "./routing/router.js";
12
13
  import { FORBIDDEN_PATH_KEYS } from "@astrojs/internal-helpers/object";
13
- import { loadLogger } from "./logger/load.js";
14
+ import { loadLoggerDestination } from "./logger/load.js";
14
15
  const PipelineFeatures = {
15
16
  redirects: 1 << 0,
16
17
  sessions: 1 << 1,
@@ -171,7 +172,10 @@ class Pipeline {
171
172
  }
172
173
  this.resolvedLogger = true;
173
174
  if (this.manifest.loggerConfig) {
174
- this.logger = await loadLogger(this.manifest.loggerConfig);
175
+ this.logger = new AstroLogger({
176
+ destination: await loadLoggerDestination(this.manifest.loggerConfig),
177
+ level: this.manifest.logLevel
178
+ });
175
179
  }
176
180
  return this.logger;
177
181
  }
@@ -24,13 +24,14 @@ import { ensureProcessNodeEnv } from "../util.js";
24
24
  import { collectPagesData } from "./page-data.js";
25
25
  import { viteBuild } from "./static-build.js";
26
26
  import { getTimeStat } from "./util.js";
27
- import { warnIfCspWithShiki } from "../messages/runtime.js";
27
+ import { warnIfCspResourceFallbackShadowing, warnIfCspWithShiki } from "../messages/runtime.js";
28
28
  async function build(inlineConfig, options = {}) {
29
29
  ensureProcessNodeEnv(options.devOutput ? "development" : "production");
30
30
  const { userConfig, astroConfig } = await resolveConfig(inlineConfig, "build");
31
31
  const logger = await loadOrCreateNodeLogger(astroConfig, inlineConfig ?? {});
32
32
  telemetry.record(eventCliSession("build", userConfig));
33
33
  warnIfCspWithShiki(astroConfig, logger);
34
+ warnIfCspResourceFallbackShadowing(astroConfig, logger);
34
35
  const settings = await createSettings(
35
36
  astroConfig,
36
37
  inlineConfig.logLevel,
@@ -20,6 +20,7 @@ import {
20
20
  trackScriptHashes,
21
21
  trackStyleHashes
22
22
  } from "../../csp/common.js";
23
+ import { partitionByKind } from "../../csp/runtime.js";
23
24
  import { encodeKey } from "../../encryption.js";
24
25
  import { fileExtension, joinPaths, prependForwardSlash } from "../../path.js";
25
26
  import { DEFAULT_COMPONENTS } from "../../routing/default.js";
@@ -192,25 +193,39 @@ async function buildManifest(opts, internals, staticFiles, encodedKey) {
192
193
  }
193
194
  let csp = void 0;
194
195
  if (shouldTrackCspHashes(settings.config.security.csp)) {
195
- const algorithm = getAlgorithm(settings.config.security.csp);
196
+ const cspConfig = settings.config.security.csp;
197
+ const algorithm = getAlgorithm(cspConfig);
196
198
  const scriptHashes = [
197
- ...getScriptHashes(settings.config.security.csp),
199
+ ...getScriptHashes(cspConfig),
198
200
  ...await trackScriptHashes(internals, settings, algorithm)
199
201
  ];
200
202
  const styleHashes = [
201
- ...getStyleHashes(settings.config.security.csp),
203
+ ...getStyleHashes(cspConfig),
202
204
  ...settings.injectedCsp.styleHashes,
203
205
  ...await trackStyleHashes(internals, settings, algorithm)
204
206
  ];
207
+ const scriptDirective = {
208
+ resources: getScriptResources(cspConfig),
209
+ hashes: scriptHashes,
210
+ strictDynamic: getStrictDynamic(cspConfig)
211
+ };
212
+ const styleDirective = {
213
+ resources: getStyleResources(cspConfig),
214
+ hashes: styleHashes
215
+ };
216
+ const scriptDefault = partitionByKind(scriptDirective).default;
217
+ const styleDefault = partitionByKind(styleDirective).default;
205
218
  csp = {
206
219
  cspDestination: settings.adapter?.adapterFeatures?.staticHeaders ? "adapter" : void 0,
207
- scriptHashes,
208
- scriptResources: getScriptResources(settings.config.security.csp),
209
- styleHashes,
210
- styleResources: getStyleResources(settings.config.security.csp),
211
220
  algorithm,
212
221
  directives: getDirectives(settings),
213
- isStrictDynamic: getStrictDynamic(settings.config.security.csp)
222
+ scriptHashes: scriptDefault.hashes,
223
+ scriptResources: scriptDefault.resources,
224
+ isStrictDynamic: scriptDirective.strictDynamic,
225
+ styleHashes: styleDefault.hashes,
226
+ styleResources: styleDefault.resources,
227
+ scriptDirective,
228
+ styleDirective
214
229
  };
215
230
  }
216
231
  let internalFetchHeaders = void 0;
@@ -80,6 +80,7 @@ export declare const ASTRO_CONFIG_DEFAULTS: {
80
80
  clientPrerender: false;
81
81
  contentIntellisense: false;
82
82
  chromeDevtoolsWorkspace: false;
83
+ collectionStorage: "single-file";
83
84
  };
84
85
  };
85
86
  export declare const AstroConfigSchema: z.ZodObject<{
@@ -368,12 +369,40 @@ export declare const AstroConfigSchema: z.ZodObject<{
368
369
  }>>>;
369
370
  directives: z.ZodOptional<z.ZodArray<z.ZodCustom<`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}`, `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}`>>>;
370
371
  styleDirective: z.ZodOptional<z.ZodObject<{
371
- resources: z.ZodOptional<z.ZodArray<z.ZodString>>;
372
- hashes: z.ZodOptional<z.ZodArray<z.ZodCustom<`sha256-${string}` | `sha384-${string}` | `sha512-${string}`, `sha256-${string}` | `sha384-${string}` | `sha512-${string}`>>>;
372
+ resources: z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
373
+ resource: z.ZodString;
374
+ kind: z.ZodEnum<{
375
+ default: "default";
376
+ attribute: "attribute";
377
+ element: "element";
378
+ }>;
379
+ }, z.core.$strip>]>>>;
380
+ hashes: z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodCustom<`sha256-${string}` | `sha384-${string}` | `sha512-${string}`, `sha256-${string}` | `sha384-${string}` | `sha512-${string}`>, z.ZodObject<{
381
+ hash: z.ZodCustom<`sha256-${string}` | `sha384-${string}` | `sha512-${string}`, `sha256-${string}` | `sha384-${string}` | `sha512-${string}`>;
382
+ kind: z.ZodEnum<{
383
+ default: "default";
384
+ attribute: "attribute";
385
+ element: "element";
386
+ }>;
387
+ }, z.core.$strip>]>>>;
373
388
  }, z.core.$strip>>;
374
389
  scriptDirective: z.ZodOptional<z.ZodObject<{
375
- resources: z.ZodOptional<z.ZodArray<z.ZodString>>;
376
- hashes: z.ZodOptional<z.ZodArray<z.ZodCustom<`sha256-${string}` | `sha384-${string}` | `sha512-${string}`, `sha256-${string}` | `sha384-${string}` | `sha512-${string}`>>>;
390
+ resources: z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
391
+ resource: z.ZodString;
392
+ kind: z.ZodEnum<{
393
+ default: "default";
394
+ attribute: "attribute";
395
+ element: "element";
396
+ }>;
397
+ }, z.core.$strip>]>>>;
398
+ hashes: z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodCustom<`sha256-${string}` | `sha384-${string}` | `sha512-${string}`, `sha256-${string}` | `sha384-${string}` | `sha512-${string}`>, z.ZodObject<{
399
+ hash: z.ZodCustom<`sha256-${string}` | `sha384-${string}` | `sha512-${string}`, `sha256-${string}` | `sha384-${string}` | `sha512-${string}`>;
400
+ kind: z.ZodEnum<{
401
+ default: "default";
402
+ attribute: "attribute";
403
+ element: "element";
404
+ }>;
405
+ }, z.core.$strip>]>>>;
377
406
  strictDynamic: z.ZodOptional<z.ZodBoolean>;
378
407
  }, z.core.$strip>>;
379
408
  }, z.core.$strip>]>>>;
@@ -458,7 +487,7 @@ export declare const AstroConfigSchema: z.ZodObject<{
458
487
  }>>>;
459
488
  fetchFile: z.ZodDefault<z.ZodOptional<z.ZodNullable<z.ZodString>>>;
460
489
  logger: z.ZodOptional<z.ZodObject<{
461
- entrypoint: z.ZodString;
490
+ entrypoint: z.ZodUnion<readonly [z.ZodString, z.ZodCustom<URL, URL>]>;
462
491
  config: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodAny>>;
463
492
  }, z.core.$strip>>;
464
493
  fonts: z.ZodOptional<z.ZodArray<z.ZodObject<{
@@ -524,6 +553,10 @@ export declare const AstroConfigSchema: z.ZodObject<{
524
553
  name: z.ZodString;
525
554
  optimize: z.ZodCustom<(contents: string) => string | Promise<string>, (contents: string) => string | Promise<string>>;
526
555
  }, z.core.$strip>>;
556
+ collectionStorage: z.ZodDefault<z.ZodOptional<z.ZodEnum<{
557
+ "single-file": "single-file";
558
+ chunked: "chunked";
559
+ }>>>;
527
560
  }, z.core.$strict>>;
528
561
  legacy: z.ZodPrefault<z.ZodObject<{
529
562
  collectionsBackwardsCompat: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
@@ -9,7 +9,12 @@ import { FontFamilySchema } from "../../../assets/fonts/config.js";
9
9
  import { SvgOptimizerSchema } from "../../../assets/svg/config.js";
10
10
  import { EnvSchema } from "../../../env/schema.js";
11
11
  import { CacheSchema, RouteRulesSchema } from "../../cache/config.js";
12
- import { allowedDirectivesSchema, cspAlgorithmSchema, cspHashSchema } from "../../csp/config.js";
12
+ import {
13
+ allowedDirectivesSchema,
14
+ cspAlgorithmSchema,
15
+ cspHashEntrySchema,
16
+ cspResourceEntrySchema
17
+ } from "../../csp/config.js";
13
18
  import { SessionSchema } from "../../session/config.js";
14
19
  const ASTRO_CONFIG_DEFAULTS = {
15
20
  root: ".",
@@ -68,7 +73,8 @@ const ASTRO_CONFIG_DEFAULTS = {
68
73
  experimental: {
69
74
  clientPrerender: false,
70
75
  contentIntellisense: false,
71
- chromeDevtoolsWorkspace: false
76
+ chromeDevtoolsWorkspace: false,
77
+ collectionStorage: "single-file"
72
78
  }
73
79
  };
74
80
  const highlighterTypesSchema = z.union([z.literal("shiki"), z.literal("prism")]).default(syntaxHighlightDefaults.type);
@@ -304,12 +310,12 @@ const AstroConfigSchema = z.object({
304
310
  algorithm: cspAlgorithmSchema,
305
311
  directives: z.array(allowedDirectivesSchema).optional(),
306
312
  styleDirective: z.object({
307
- resources: z.array(z.string()).optional(),
308
- hashes: z.array(cspHashSchema).optional()
313
+ resources: z.array(cspResourceEntrySchema).optional(),
314
+ hashes: z.array(cspHashEntrySchema).optional()
309
315
  }).optional(),
310
316
  scriptDirective: z.object({
311
- resources: z.array(z.string()).optional(),
312
- hashes: z.array(cspHashSchema).optional(),
317
+ resources: z.array(cspResourceEntrySchema).optional(),
318
+ hashes: z.array(cspHashEntrySchema).optional(),
313
319
  strictDynamic: z.boolean().optional()
314
320
  }).optional()
315
321
  })
@@ -323,7 +329,7 @@ const AstroConfigSchema = z.object({
323
329
  prerenderConflictBehavior: z.enum(["error", "warn", "ignore"]).optional().default(ASTRO_CONFIG_DEFAULTS.prerenderConflictBehavior),
324
330
  fetchFile: z.string().nullable().optional().default(ASTRO_CONFIG_DEFAULTS.fetchFile),
325
331
  logger: z.object({
326
- entrypoint: z.string(),
332
+ entrypoint: z.union([z.string(), z.instanceof(URL)]),
327
333
  config: z.record(z.string(), z.any()).optional()
328
334
  }).optional(),
329
335
  fonts: z.array(FontFamilySchema).optional(),
@@ -333,7 +339,8 @@ const AstroConfigSchema = z.object({
333
339
  clientPrerender: z.boolean().optional().default(ASTRO_CONFIG_DEFAULTS.experimental.clientPrerender),
334
340
  contentIntellisense: z.boolean().optional().default(ASTRO_CONFIG_DEFAULTS.experimental.contentIntellisense),
335
341
  chromeDevtoolsWorkspace: z.boolean().optional().default(ASTRO_CONFIG_DEFAULTS.experimental.chromeDevtoolsWorkspace),
336
- svgOptimizer: SvgOptimizerSchema.optional()
342
+ svgOptimizer: SvgOptimizerSchema.optional(),
343
+ collectionStorage: z.enum(["single-file", "chunked"]).optional().default(ASTRO_CONFIG_DEFAULTS.experimental.collectionStorage)
337
344
  }).prefault({}),
338
345
  legacy: z.object({
339
346
  collectionsBackwardsCompat: z.boolean().optional().default(false)