astro 5.8.1 → 5.9.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.
Files changed (70) hide show
  1. package/dist/actions/runtime/utils.d.ts +1 -1
  2. package/dist/assets/fonts/config.d.ts +21 -21
  3. package/dist/container/index.js +2 -1
  4. package/dist/content/content-layer.js +14 -3
  5. package/dist/content/loaders/types.d.ts +3 -0
  6. package/dist/content/utils.d.ts +26 -10
  7. package/dist/content/utils.js +1 -0
  8. package/dist/core/app/types.d.ts +12 -1
  9. package/dist/core/base-pipeline.js +3 -3
  10. package/dist/core/build/generate.d.ts +1 -1
  11. package/dist/core/build/generate.js +38 -4
  12. package/dist/core/build/internal.d.ts +1 -0
  13. package/dist/core/build/internal.js +2 -1
  14. package/dist/core/build/plugins/index.js +1 -1
  15. package/dist/core/build/plugins/plugin-internals.d.ts +2 -1
  16. package/dist/core/build/plugins/plugin-internals.js +7 -4
  17. package/dist/core/build/plugins/plugin-manifest.js +37 -3
  18. package/dist/core/config/schemas/base.d.ts +435 -331
  19. package/dist/core/config/schemas/base.js +20 -2
  20. package/dist/core/config/schemas/index.d.ts +1 -1
  21. package/dist/core/config/schemas/index.js +4 -1
  22. package/dist/core/config/schemas/relative.d.ts +681 -552
  23. package/dist/core/constants.js +1 -1
  24. package/dist/core/csp/common.d.ts +16 -0
  25. package/dist/core/csp/common.js +116 -0
  26. package/dist/core/csp/config.d.ts +16 -0
  27. package/dist/core/csp/config.js +52 -0
  28. package/dist/core/dev/dev.js +1 -1
  29. package/dist/core/encryption.d.ts +8 -0
  30. package/dist/core/encryption.js +7 -0
  31. package/dist/core/errors/errors-data.d.ts +12 -0
  32. package/dist/core/errors/errors-data.js +6 -0
  33. package/dist/core/messages.js +2 -2
  34. package/dist/core/middleware/index.js +10 -0
  35. package/dist/core/middleware/sequence.js +2 -2
  36. package/dist/core/render-context.d.ts +1 -0
  37. package/dist/core/render-context.js +77 -5
  38. package/dist/env/schema.d.ts +34 -34
  39. package/dist/integrations/features-validation.js +36 -30
  40. package/dist/integrations/hooks.d.ts +3 -2
  41. package/dist/runtime/server/astro-island-styles.d.ts +1 -0
  42. package/dist/runtime/server/astro-island-styles.js +4 -0
  43. package/dist/runtime/server/index.d.ts +1 -0
  44. package/dist/runtime/server/render/astro/factory.d.ts +3 -2
  45. package/dist/runtime/server/render/astro/factory.js +6 -1
  46. package/dist/runtime/server/render/astro/head-and-content.d.ts +7 -0
  47. package/dist/runtime/server/render/astro/head-and-content.js +6 -0
  48. package/dist/runtime/server/render/astro/render.d.ts +1 -0
  49. package/dist/runtime/server/render/astro/render.js +2 -1
  50. package/dist/runtime/server/render/common.d.ts +1 -1
  51. package/dist/runtime/server/render/common.js +5 -3
  52. package/dist/runtime/server/render/component.js +8 -2
  53. package/dist/runtime/server/render/csp.d.ts +2 -0
  54. package/dist/runtime/server/render/csp.js +35 -0
  55. package/dist/runtime/server/render/head.js +14 -0
  56. package/dist/runtime/server/render/page.d.ts +1 -1
  57. package/dist/runtime/server/render/page.js +1 -1
  58. package/dist/runtime/server/render/server-islands.d.ts +14 -3
  59. package/dist/runtime/server/render/server-islands.js +100 -69
  60. package/dist/runtime/server/render/util.js +3 -0
  61. package/dist/runtime/server/scripts.d.ts +1 -1
  62. package/dist/runtime/server/scripts.js +2 -5
  63. package/dist/runtime/server/transition.d.ts +1 -1
  64. package/dist/runtime/server/transition.js +7 -2
  65. package/dist/types/public/config.d.ts +240 -0
  66. package/dist/types/public/context.d.ts +51 -0
  67. package/dist/types/public/integrations.d.ts +9 -0
  68. package/dist/types/public/internal.d.ts +24 -2
  69. package/dist/vite-plugin-astro-server/plugin.js +26 -4
  70. package/package.json +2 -2
@@ -1,4 +1,4 @@
1
- const ASTRO_VERSION = "5.8.1";
1
+ const ASTRO_VERSION = "5.9.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";
@@ -0,0 +1,16 @@
1
+ import type { AstroSettings } from '../../types/astro.js';
2
+ import type { AstroConfig, CspAlgorithm } from '../../types/public/index.js';
3
+ import type { BuildInternals } from '../build/internal.js';
4
+ import type { CspDirective } from './config.js';
5
+ type EnabledCsp = Exclude<AstroConfig['experimental']['csp'], false>;
6
+ export declare function shouldTrackCspHashes(csp: any): csp is EnabledCsp;
7
+ export declare function getAlgorithm(csp: EnabledCsp): CspAlgorithm;
8
+ export declare function getScriptHashes(csp: EnabledCsp): string[];
9
+ export declare function getScriptResources(csp: EnabledCsp): string[];
10
+ export declare function getStyleHashes(csp: EnabledCsp): string[];
11
+ export declare function getStyleResources(csp: EnabledCsp): string[];
12
+ export declare function getDirectives(csp: EnabledCsp): CspDirective[];
13
+ export declare function getStrictDynamic(csp: EnabledCsp): boolean;
14
+ export declare function trackStyleHashes(internals: BuildInternals, settings: AstroSettings, algorithm: CspAlgorithm): Promise<string[]>;
15
+ export declare function trackScriptHashes(internals: BuildInternals, settings: AstroSettings, algorithm: CspAlgorithm): Promise<string[]>;
16
+ export {};
@@ -0,0 +1,116 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { fileURLToPath } from "node:url";
3
+ import { ISLAND_STYLES } from "../../runtime/server/astro-island-styles.js";
4
+ import astroIslandPrebuiltDev from "../../runtime/server/astro-island.prebuilt-dev.js";
5
+ import astroIslandPrebuilt from "../../runtime/server/astro-island.prebuilt.js";
6
+ import { generateCspDigest } from "../encryption.js";
7
+ function shouldTrackCspHashes(csp) {
8
+ return csp === true || typeof csp === "object";
9
+ }
10
+ function getAlgorithm(csp) {
11
+ if (csp === true) {
12
+ return "SHA-256";
13
+ }
14
+ return csp.algorithm;
15
+ }
16
+ function getScriptHashes(csp) {
17
+ if (csp === true) {
18
+ return [];
19
+ } else {
20
+ return csp.scriptDirective?.hashes ?? [];
21
+ }
22
+ }
23
+ function getScriptResources(csp) {
24
+ if (csp === true) {
25
+ return [];
26
+ }
27
+ return csp.scriptDirective?.resources ?? [];
28
+ }
29
+ function getStyleHashes(csp) {
30
+ if (csp === true) {
31
+ return [];
32
+ }
33
+ return csp.styleDirective?.hashes ?? [];
34
+ }
35
+ function getStyleResources(csp) {
36
+ if (csp === true) {
37
+ return [];
38
+ }
39
+ return csp.styleDirective?.resources ?? [];
40
+ }
41
+ function getDirectives(csp) {
42
+ if (csp === true) {
43
+ return [];
44
+ }
45
+ return csp.directives ?? [];
46
+ }
47
+ function getStrictDynamic(csp) {
48
+ if (csp === true) {
49
+ return false;
50
+ }
51
+ return csp.scriptDirective?.strictDynamic ?? false;
52
+ }
53
+ async function trackStyleHashes(internals, settings, algorithm) {
54
+ const clientStyleHashes = [];
55
+ for (const [_, page] of internals.pagesByViteID.entries()) {
56
+ for (const style of page.styles) {
57
+ if (style.sheet.type === "inline") {
58
+ clientStyleHashes.push(await generateCspDigest(style.sheet.content, algorithm));
59
+ }
60
+ }
61
+ }
62
+ for (const clientAsset in internals.clientChunksAndAssets) {
63
+ const contents = readFileSync(
64
+ fileURLToPath(new URL(clientAsset, settings.config.build.client)),
65
+ "utf-8"
66
+ );
67
+ if (clientAsset.endsWith(".css") || clientAsset.endsWith(".css")) {
68
+ clientStyleHashes.push(await generateCspDigest(contents, algorithm));
69
+ }
70
+ }
71
+ if (settings.renderers.length > 0) {
72
+ clientStyleHashes.push(await generateCspDigest(ISLAND_STYLES, algorithm));
73
+ }
74
+ return clientStyleHashes;
75
+ }
76
+ async function trackScriptHashes(internals, settings, algorithm) {
77
+ const clientScriptHashes = [];
78
+ for (const script of internals.inlinedScripts.values()) {
79
+ clientScriptHashes.push(await generateCspDigest(script, algorithm));
80
+ }
81
+ for (const directiveContent of Array.from(settings.clientDirectives.values())) {
82
+ clientScriptHashes.push(await generateCspDigest(directiveContent, algorithm));
83
+ }
84
+ for (const clientAsset in internals.clientChunksAndAssets) {
85
+ const contents = readFileSync(
86
+ fileURLToPath(new URL(clientAsset, settings.config.build.client)),
87
+ "utf-8"
88
+ );
89
+ if (clientAsset.endsWith(".js") || clientAsset.endsWith(".mjs")) {
90
+ clientScriptHashes.push(await generateCspDigest(contents, algorithm));
91
+ }
92
+ }
93
+ for (const script of settings.scripts) {
94
+ const { content, stage } = script;
95
+ if (stage === "head-inline" || stage === "before-hydration") {
96
+ clientScriptHashes.push(await generateCspDigest(content, algorithm));
97
+ }
98
+ }
99
+ if (settings.renderers.length > 0) {
100
+ clientScriptHashes.push(await generateCspDigest(astroIslandPrebuilt, algorithm));
101
+ clientScriptHashes.push(await generateCspDigest(astroIslandPrebuiltDev, algorithm));
102
+ }
103
+ return clientScriptHashes;
104
+ }
105
+ export {
106
+ getAlgorithm,
107
+ getDirectives,
108
+ getScriptHashes,
109
+ getScriptResources,
110
+ getStrictDynamic,
111
+ getStyleHashes,
112
+ getStyleResources,
113
+ shouldTrackCspHashes,
114
+ trackScriptHashes,
115
+ trackStyleHashes
116
+ };
@@ -0,0 +1,16 @@
1
+ import { z } from 'zod';
2
+ export declare const ALGORITHMS: {
3
+ readonly 'SHA-256': "sha256-";
4
+ readonly 'SHA-384': "sha384-";
5
+ readonly 'SHA-512': "sha512-";
6
+ };
7
+ type Algorithms = typeof ALGORITHMS;
8
+ export type CspAlgorithm = keyof Algorithms;
9
+ export declare const cspAlgorithmSchema: z.ZodDefault<z.ZodOptional<z.ZodEnum<["SHA-256", "SHA-384", "SHA-512"]>>>;
10
+ export declare const cspHashSchema: z.ZodType<`sha256-${string}` | `sha384-${string}` | `sha512-${string}`, z.ZodTypeDef, `sha256-${string}` | `sha384-${string}` | `sha512-${string}`>;
11
+ export type CspHash = z.infer<typeof cspHashSchema>;
12
+ declare const ALLOWED_DIRECTIVES: readonly ["base-uri", "child-src", "connect-src", "default-src", "fenced-frame-src", "font-src", "form-action", "frame-ancestors", "frame-src", "img-src", "manifest-src", "media-src", "object-src", "referrer", "report-to", "require-trusted-types-for", "sandbox", "trusted-types", "upgrade-insecure-requests", "worker-src"];
13
+ export type CspDirective = `${AllowedDirectives} ${string}`;
14
+ export declare const allowedDirectivesSchema: z.ZodType<`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}` | `require-trusted-types-for ${string}` | `sandbox ${string}` | `trusted-types ${string}` | `upgrade-insecure-requests ${string}` | `worker-src ${string}`, z.ZodTypeDef, `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}` | `require-trusted-types-for ${string}` | `sandbox ${string}` | `trusted-types ${string}` | `upgrade-insecure-requests ${string}` | `worker-src ${string}`>;
15
+ type AllowedDirectives = (typeof ALLOWED_DIRECTIVES)[number];
16
+ export {};
@@ -0,0 +1,52 @@
1
+ import { z } from "zod";
2
+ const ALGORITHMS = {
3
+ "SHA-256": "sha256-",
4
+ "SHA-384": "sha384-",
5
+ "SHA-512": "sha512-"
6
+ };
7
+ const ALGORITHM_VALUES = Object.values(ALGORITHMS);
8
+ const cspAlgorithmSchema = z.enum(Object.keys(ALGORITHMS)).optional().default("SHA-256");
9
+ const cspHashSchema = z.custom((value) => {
10
+ if (typeof value !== "string") {
11
+ return false;
12
+ }
13
+ return ALGORITHM_VALUES.some((allowedValue) => {
14
+ return value.startsWith(allowedValue);
15
+ });
16
+ });
17
+ const ALLOWED_DIRECTIVES = [
18
+ "base-uri",
19
+ "child-src",
20
+ "connect-src",
21
+ "default-src",
22
+ "fenced-frame-src",
23
+ "font-src",
24
+ "form-action",
25
+ "frame-ancestors",
26
+ "frame-src",
27
+ "img-src",
28
+ "manifest-src",
29
+ "media-src",
30
+ "object-src",
31
+ "referrer",
32
+ "report-to",
33
+ "require-trusted-types-for",
34
+ "sandbox",
35
+ "trusted-types",
36
+ "upgrade-insecure-requests",
37
+ "worker-src"
38
+ ];
39
+ const allowedDirectivesSchema = z.custom((value) => {
40
+ if (typeof value !== "string") {
41
+ return false;
42
+ }
43
+ return ALLOWED_DIRECTIVES.some((allowedValue) => {
44
+ return value.startsWith(allowedValue);
45
+ });
46
+ });
47
+ export {
48
+ ALGORITHMS,
49
+ allowedDirectivesSchema,
50
+ cspAlgorithmSchema,
51
+ cspHashSchema
52
+ };
@@ -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.8.1";
25
+ const currentVersion = "5.9.0";
26
26
  const isPrerelease = currentVersion.includes("-");
27
27
  if (!isPrerelease) {
28
28
  try {
@@ -1,3 +1,5 @@
1
+ import type { CspAlgorithm } from '../types/public/index.js';
2
+ import { type CspHash } from './csp/config.js';
1
3
  /**
2
4
  * Creates a CryptoKey object that can be used to encrypt any string.
3
5
  */
@@ -26,3 +28,9 @@ export declare function encryptString(key: CryptoKey, raw: string): Promise<stri
26
28
  * Takes a base64 encoded string, decodes it and returns the decrypted text.
27
29
  */
28
30
  export declare function decryptString(key: CryptoKey, encoded: string): Promise<string>;
31
+ /**
32
+ * Generates an SHA-256 digest of the given string.
33
+ * @param {string} data The string to hash.
34
+ * @param {CspAlgorithm} algorithm The algorithm to use.
35
+ */
36
+ export declare function generateCspDigest(data: string, algorithm: CspAlgorithm): Promise<CspHash>;
@@ -1,4 +1,5 @@
1
1
  import { decodeBase64, decodeHex, encodeBase64, encodeHexUpperCase } from "@oslojs/encoding";
2
+ import { ALGORITHMS } from "./csp/config.js";
2
3
  const ALGORITHM = "AES-GCM";
3
4
  async function createKey() {
4
5
  const key = await crypto.subtle.generateKey(
@@ -66,12 +67,18 @@ async function decryptString(key, encoded) {
66
67
  const decryptedString = decoder.decode(decryptedBuffer);
67
68
  return decryptedString;
68
69
  }
70
+ async function generateCspDigest(data, algorithm) {
71
+ const hashBuffer = await crypto.subtle.digest(algorithm, encoder.encode(data));
72
+ const hash = encodeBase64(new Uint8Array(hashBuffer));
73
+ return `${ALGORITHMS[algorithm]}${hash}`;
74
+ }
69
75
  export {
70
76
  createKey,
71
77
  decodeKey,
72
78
  decryptString,
73
79
  encodeKey,
74
80
  encryptString,
81
+ generateCspDigest,
75
82
  getEnvironmentKey,
76
83
  hasEnvironmentKey
77
84
  };
@@ -1230,6 +1230,18 @@ export declare const FontFamilyNotFound: {
1230
1230
  message: (family: string) => string;
1231
1231
  hint: string;
1232
1232
  };
1233
+ /**
1234
+ * @docs
1235
+ * @description
1236
+ * The CSP feature isn't enabled
1237
+ * @message
1238
+ * The `experimental.csp` configuration isn't enabled.
1239
+ */
1240
+ export declare const CspNotEnabled: {
1241
+ name: string;
1242
+ title: string;
1243
+ message: string;
1244
+ };
1233
1245
  /**
1234
1246
  * @docs
1235
1247
  * @kind heading
@@ -464,6 +464,11 @@ const FontFamilyNotFound = {
464
464
  message: (family) => `No data was found for the \`"${family}"\` family passed to the \`<Font>\` component.`,
465
465
  hint: "This is often caused by a typo. Check that your Font component is using a `cssVariable` specified in your config."
466
466
  };
467
+ const CspNotEnabled = {
468
+ name: "CspNotEnabled",
469
+ title: "CSP feature isn't enabled",
470
+ message: "The `experimental.csp` configuration isn't enabled."
471
+ };
467
472
  const UnknownCSSError = {
468
473
  name: "UnknownCSSError",
469
474
  title: "Unknown CSS Error."
@@ -736,6 +741,7 @@ export {
736
741
  ContentLoaderReturnsInvalidId,
737
742
  ContentSchemaContainsSlugError,
738
743
  CouldNotTransformImage,
744
+ CspNotEnabled,
739
745
  DataCollectionEntryParseError,
740
746
  DuplicateContentEntrySlugError,
741
747
  EndpointDidNotReturnAResponse,
@@ -37,7 +37,7 @@ function serverStart({
37
37
  host,
38
38
  base
39
39
  }) {
40
- const version = "5.8.1";
40
+ const version = "5.9.0";
41
41
  const localPrefix = `${dim("\u2503")} Local `;
42
42
  const networkPrefix = `${dim("\u2503")} Network `;
43
43
  const emptyPrefix = " ".repeat(11);
@@ -274,7 +274,7 @@ function printHelp({
274
274
  message.push(
275
275
  linebreak(),
276
276
  ` ${bgGreen(black(` ${commandName} `))} ${green(
277
- `v${"5.8.1"}`
277
+ `v${"5.9.0"}`
278
278
  )} ${headline}`
279
279
  );
280
280
  }
@@ -82,6 +82,16 @@ function createContext({
82
82
  },
83
83
  set locals(_) {
84
84
  throw new AstroError(AstroErrorData.LocalsReassigned);
85
+ },
86
+ insertDirective() {
87
+ },
88
+ insertScriptResource() {
89
+ },
90
+ insertStyleResource() {
91
+ },
92
+ insertScriptHash() {
93
+ },
94
+ insertStyleHash() {
85
95
  }
86
96
  };
87
97
  return Object.assign(context, {
@@ -25,11 +25,11 @@ function sequence(...handlers) {
25
25
  if (payload instanceof Request) {
26
26
  newRequest = payload;
27
27
  } else if (payload instanceof URL) {
28
- newRequest = new Request(payload, handleContext.request);
28
+ newRequest = new Request(payload, handleContext.request.clone());
29
29
  } else {
30
30
  newRequest = new Request(
31
31
  new URL(payload, handleContext.url.origin),
32
- handleContext.request
32
+ handleContext.request.clone()
33
33
  );
34
34
  }
35
35
  const oldPathname = handleContext.url.pathname;
@@ -38,6 +38,7 @@ export declare class RenderContext {
38
38
  * A safety net in case of loops
39
39
  */
40
40
  counter: number;
41
+ result: SSRResult | undefined;
41
42
  static create({ locals, middleware, pathname, pipeline, request, routeData, clientAddress, status, props, partial, actions, }: Pick<RenderContext, 'pathname' | 'pipeline' | 'request' | 'routeData' | 'clientAddress'> & Partial<Pick<RenderContext, 'locals' | 'middleware' | 'status' | 'props' | 'partial' | 'actions'>>): Promise<RenderContext>;
42
43
  /**
43
44
  * The main function of the RenderContext.
@@ -20,7 +20,7 @@ import {
20
20
  } from "./constants.js";
21
21
  import { AstroCookies, attachCookiesToResponse } from "./cookies/index.js";
22
22
  import { getCookiesFromResponse } from "./cookies/response.js";
23
- import { ForbiddenRewrite } from "./errors/errors-data.js";
23
+ import { CspNotEnabled, ForbiddenRewrite } from "./errors/errors-data.js";
24
24
  import { AstroError, AstroErrorData } from "./errors/index.js";
25
25
  import { callMiddleware } from "./middleware/callMiddleware.js";
26
26
  import { sequence } from "./middleware/index.js";
@@ -56,6 +56,7 @@ class RenderContext {
56
56
  * A safety net in case of loops
57
57
  */
58
58
  counter = 0;
59
+ result = void 0;
59
60
  static async create({
60
61
  locals = {},
61
62
  middleware,
@@ -181,10 +182,10 @@ class RenderContext {
181
182
  case "redirect":
182
183
  return renderRedirect(this);
183
184
  case "page": {
184
- const result = await this.createResult(componentInstance, actionApiContext);
185
+ this.result = await this.createResult(componentInstance, actionApiContext);
185
186
  try {
186
187
  response2 = await renderPage(
187
- result,
188
+ this.result,
188
189
  componentInstance?.default,
189
190
  props,
190
191
  slots,
@@ -192,7 +193,7 @@ class RenderContext {
192
193
  this.routeData
193
194
  );
194
195
  } catch (e) {
195
- result.cancelled = true;
196
+ this.result.cancelled = true;
196
197
  throw e;
197
198
  }
198
199
  response2.headers.set(ROUTE_TYPE_HEADER, "page");
@@ -324,6 +325,36 @@ class RenderContext {
324
325
  return void 0;
325
326
  }
326
327
  return renderContext.session;
328
+ },
329
+ insertDirective(payload) {
330
+ if (!pipeline.manifest.csp) {
331
+ throw new AstroError(CspNotEnabled);
332
+ }
333
+ renderContext.result?.directives.push(payload);
334
+ },
335
+ insertScriptResource(resource) {
336
+ if (!pipeline.manifest.csp) {
337
+ throw new AstroError(CspNotEnabled);
338
+ }
339
+ renderContext.result?.scriptResources.push(resource);
340
+ },
341
+ insertStyleResource(resource) {
342
+ if (!pipeline.manifest.csp) {
343
+ throw new AstroError(CspNotEnabled);
344
+ }
345
+ renderContext.result?.styleResources.push(resource);
346
+ },
347
+ insertStyleHash(hash) {
348
+ if (!pipeline.manifest.csp) {
349
+ throw new AstroError(CspNotEnabled);
350
+ }
351
+ renderContext.result?.styleHashes.push(hash);
352
+ },
353
+ insertScriptHash(hash) {
354
+ if (!!pipeline.manifest.csp === false) {
355
+ throw new AstroError(CspNotEnabled);
356
+ }
357
+ renderContext.result?.scriptHashes.push(hash);
327
358
  }
328
359
  };
329
360
  }
@@ -380,8 +411,19 @@ class RenderContext {
380
411
  hasRenderedServerIslandRuntime: false,
381
412
  headInTree: false,
382
413
  extraHead: [],
414
+ extraStyleHashes: [],
415
+ extraScriptHashes: [],
383
416
  propagators: /* @__PURE__ */ new Set()
384
- }
417
+ },
418
+ shouldInjectCspMetaTags: !!manifest.csp,
419
+ cspAlgorithm: manifest.csp?.algorithm ?? "SHA-256",
420
+ // The following arrays must be cloned, otherwise they become mutable across routes.
421
+ scriptHashes: manifest.csp?.scriptHashes ? [...manifest.csp.scriptHashes] : [],
422
+ scriptResources: manifest.csp?.scriptResources ? [...manifest.csp.scriptResources] : [],
423
+ styleHashes: manifest.csp?.styleHashes ? [...manifest.csp.styleHashes] : [],
424
+ styleResources: manifest.csp?.styleResources ? [...manifest.csp.styleResources] : [],
425
+ directives: manifest.csp?.directives ? [...manifest.csp.directives] : [],
426
+ isStrictDynamic: manifest.csp?.isStrictDynamic ?? false
385
427
  };
386
428
  return result;
387
429
  }
@@ -494,6 +536,36 @@ class RenderContext {
494
536
  url,
495
537
  get originPathname() {
496
538
  return getOriginPathname(renderContext.request);
539
+ },
540
+ insertDirective(payload) {
541
+ if (!pipeline.manifest.csp) {
542
+ throw new AstroError(CspNotEnabled);
543
+ }
544
+ renderContext.result?.directives.push(payload);
545
+ },
546
+ insertScriptResource(resource) {
547
+ if (!pipeline.manifest.csp) {
548
+ throw new AstroError(CspNotEnabled);
549
+ }
550
+ renderContext.result?.scriptResources.push(resource);
551
+ },
552
+ insertStyleResource(resource) {
553
+ if (!pipeline.manifest.csp) {
554
+ throw new AstroError(CspNotEnabled);
555
+ }
556
+ renderContext.result?.styleResources.push(resource);
557
+ },
558
+ insertStyleHash(hash) {
559
+ if (!pipeline.manifest.csp) {
560
+ throw new AstroError(CspNotEnabled);
561
+ }
562
+ renderContext.result?.styleHashes.push(hash);
563
+ },
564
+ insertScriptHash(hash) {
565
+ if (!!pipeline.manifest.csp === false) {
566
+ throw new AstroError(CspNotEnabled);
567
+ }
568
+ renderContext.result?.scriptHashes.push(hash);
497
569
  }
498
570
  };
499
571
  }