diff --git a/packages/astro/src/container/index.ts b/packages/astro/src/container/index.ts
index b570dd8531c5..acacdf22b8d3 100644
--- a/packages/astro/src/container/index.ts
+++ b/packages/astro/src/container/index.ts
@@ -164,7 +164,7 @@ function createManifest(
clientScriptHashes: manifest?.clientScriptHashes ?? [],
clientStyleHashes: manifest?.clientStyleHashes ?? [],
shouldInjectCspMetaTags: manifest?.shouldInjectCspMetaTags ?? false,
- astroIslandHashes: manifest?.astroIslandHashes ?? [],
+ astroIslandHashes: manifest?.astroIslandHashes ?? {},
};
}
diff --git a/packages/astro/src/core/app/types.ts b/packages/astro/src/core/app/types.ts
index 6c60ea2dcd62..62211ea1f937 100644
--- a/packages/astro/src/core/app/types.ts
+++ b/packages/astro/src/core/app/types.ts
@@ -92,7 +92,7 @@ export type SSRManifest = {
* When enabled, Astro tracks the hashes of script and styles, and eventually it will render the `` tag
*/
shouldInjectCspMetaTags: boolean;
- astroIslandHashes: string[];
+ astroIslandHashes: Record;
};
export type SSRActions = {
diff --git a/packages/astro/src/core/astro-islands-hashes.ts b/packages/astro/src/core/astro-islands-hashes.ts
index 9581e3b6456d..56f4ad6fbffe 100644
--- a/packages/astro/src/core/astro-islands-hashes.ts
+++ b/packages/astro/src/core/astro-islands-hashes.ts
@@ -1,11 +1,10 @@
// This file is code-generated, please don't change it manually
-export const ASTRO_ISLAND_HASHES = [
- "GI/D8grziRZwfj/Mqmn+dcgU/i8sylHSR/IfobqcUT4=",
- "HDWxd14AUw8OvjrhhRRyyZFHCGnzxXGDrg59Qi8ayhc=",
- "XN6a2Vn8uvpBr/WhdYPdK0jVeCzlcOD2XYaP10veV4Y=",
- "ZR0ZAU8UNTzLmo/ApeWH0y1mVLT+XtFkvZ5nw32W8jI=",
- "cSNmhdbFlyTDRozeu9HPjo+B2S4QAeMp0RO41PqgAcA=",
- "mH3H4wSoDVWMXJKrmeBKYJQMdAZQ3dArB2N66JomkzI=",
- "mH3H4wSoDVWMXJKrmeBKYJQMdAZQ3dArB2N66JomkzI=",
- "s81ZcLcyAa7P/Jh5M5hUxYthTGwW+iZY3e6aHrQ8H9E="
-];
\ No newline at end of file
+export const ASTRO_ISLAND_HASHES = {
+ "astro-island": "p9VbHs/ClkQc+x63XdUjvCAgeWxA4ZGvpebJtMn9jbs=",
+ "idle": "BF0290pkb3jxQsE7z00xR8Imp8X34FLC88L0lkMnrGw=",
+ "load": "QzWFZi+FLIx23tnm9SBU4aEgx4x8DsuASP07mfqol/c=",
+ "media": "0chmwFk0zaA528yFfGV7J9ppIpdfTPPULncDF3WG7Zs=",
+ "only": "eIXWvAmxkr251LJZkjniEK5LcPF3NkapbJepohwYRIc=",
+ "visible": "Q2BPg90ZMplYY+FSdApNErhpWafg2hcRRbndmvxuL/Q=",
+ "astro-island-styles": "s81ZcLcyAa7P/Jh5M5hUxYthTGwW+iZY3e6aHrQ8H9E="
+};
\ No newline at end of file
diff --git a/packages/astro/src/core/base-pipeline.ts b/packages/astro/src/core/base-pipeline.ts
index bbaf7da6cda3..7e3174a48c46 100644
--- a/packages/astro/src/core/base-pipeline.ts
+++ b/packages/astro/src/core/base-pipeline.ts
@@ -20,6 +20,7 @@ import { NOOP_MIDDLEWARE_FN } from './middleware/noop-middleware.js';
import { sequence } from './middleware/sequence.js';
import { RouteCache } from './render/route-cache.js';
import { createDefaultRoutes } from './routing/default.js';
+import { createCSPMiddleware } from './csp/middleware.js';
/**
* The `Pipeline` represents the static parts of rendering that do not change between requests.
@@ -112,11 +113,16 @@ export abstract class Pipeline {
else if (this.middleware) {
const middlewareInstance = await this.middleware();
const onRequest = middlewareInstance.onRequest ?? NOOP_MIDDLEWARE_FN;
+ const internalMiddlewares = [onRequest];
if (this.manifest.checkOrigin) {
- this.resolvedMiddleware = sequence(createOriginCheckMiddleware(), onRequest);
- } else {
- this.resolvedMiddleware = onRequest;
+ // this middleware must be placed at the beginning because it needs to block incoming requests
+ internalMiddlewares.unshift(createOriginCheckMiddleware());
}
+ if (this.manifest.shouldInjectCspMetaTags) {
+ // this middleware must be placed at the end because it needs to inject the CSP headers
+ internalMiddlewares.push(createCSPMiddleware());
+ }
+ this.resolvedMiddleware = sequence(...internalMiddlewares);
return this.resolvedMiddleware;
} else {
this.resolvedMiddleware = NOOP_MIDDLEWARE_FN;
diff --git a/packages/astro/src/core/csp/common.ts b/packages/astro/src/core/csp/common.ts
index 97d63c271ddf..74c7c2f67652 100644
--- a/packages/astro/src/core/csp/common.ts
+++ b/packages/astro/src/core/csp/common.ts
@@ -12,9 +12,7 @@ export function trackStyleHashes(internals: BuildInternals): string[] {
for (const [_, page] of internals.pagesByViteID.entries()) {
for (const style of page.styles) {
if (style.sheet.type === 'inline') {
- clientStyleHashes.push(
- crypto.createHash('sha256').update(style.sheet.content).digest('base64'),
- );
+ clientStyleHashes.push(generateHash(style.sheet.content));
}
}
}
@@ -26,15 +24,19 @@ export function trackScriptHashes(internals: BuildInternals, settings: AstroSett
const clientScriptHashes: string[] = [];
for (const script of internals.inlinedScripts.values()) {
- clientScriptHashes.push(crypto.createHash('sha256').update(script).digest('base64'));
+ clientScriptHashes.push(generateHash(script));
}
for (const script of settings.scripts) {
const { content, stage } = script;
if (stage === 'head-inline' || stage === 'before-hydration') {
- clientScriptHashes.push(crypto.createHash('sha256').update(content).digest('base64'));
+ clientScriptHashes.push(generateHash(content));
}
}
return clientScriptHashes;
}
+
+function generateHash(content: string): string {
+ return crypto.createHash('sha256').update(content).digest('base64');
+}
diff --git a/packages/astro/src/core/csp/middleware.ts b/packages/astro/src/core/csp/middleware.ts
new file mode 100644
index 000000000000..f05a8443b75f
--- /dev/null
+++ b/packages/astro/src/core/csp/middleware.ts
@@ -0,0 +1,11 @@
+import type { MiddlewareHandler } from '../../types/public/index.js';
+
+export function createCSPMiddleware(): MiddlewareHandler {
+ return async (_, next) => {
+ const response = await next();
+
+ // Do something with the response
+
+ return response;
+ };
+}
diff --git a/packages/astro/src/core/render-context.ts b/packages/astro/src/core/render-context.ts
index b877b4c859fe..81610f42635a 100644
--- a/packages/astro/src/core/render-context.ts
+++ b/packages/astro/src/core/render-context.ts
@@ -465,6 +465,7 @@ export class RenderContext {
shouldInjectCspMetaTags: manifest.shouldInjectCspMetaTags,
clientScriptHashes: manifest.clientScriptHashes,
clientStyleHashes: manifest.clientStyleHashes,
+ astroIslandHashes: manifest.astroIslandHashes,
};
return result;
diff --git a/packages/astro/src/runtime/server/render/common.ts b/packages/astro/src/runtime/server/render/common.ts
index 90d0c1e5756a..de70c6127e82 100644
--- a/packages/astro/src/runtime/server/render/common.ts
+++ b/packages/astro/src/runtime/server/render/common.ts
@@ -3,7 +3,6 @@ import type { SSRResult } from '../../../types/public/internal.js';
import type { HTMLBytes, HTMLString } from '../escape.js';
import { markHTMLString } from '../escape.js';
import {
- type PrescriptType,
determineIfNeedsHydrationScript,
determinesIfNeedsDirectiveScript,
getPrescripts,
@@ -65,13 +64,11 @@ function stringifyChunk(
let needsDirectiveScript =
hydration && determinesIfNeedsDirectiveScript(result, hydration.directive);
- let prescriptType: PrescriptType = needsHydrationScript
- ? 'both'
- : needsDirectiveScript
- ? 'directive'
- : null;
- if (prescriptType) {
- let prescripts = getPrescripts(result, prescriptType, hydration.directive);
+ if (needsHydrationScript) {
+ let prescripts = getPrescripts(result, 'both', hydration.directive);
+ return markHTMLString(prescripts);
+ } else if (needsDirectiveScript) {
+ let prescripts = getPrescripts(result, 'directive', hydration.directive);
return markHTMLString(prescripts);
} else {
return '';
diff --git a/packages/astro/src/runtime/server/render/csp.ts b/packages/astro/src/runtime/server/render/csp.ts
new file mode 100644
index 000000000000..143bf0746b9a
--- /dev/null
+++ b/packages/astro/src/runtime/server/render/csp.ts
@@ -0,0 +1,28 @@
+import type { SSRResult } from '../../../types/public/index.js';
+
+export function renderCspContent(result: SSRResult): string {
+ const finalScriptHashes = new Set();
+ const finalStyleHashes = new Set();
+
+ for (const scriptHash of result.clientScriptHashes) {
+ finalScriptHashes.add(`'sha256-${scriptHash}'`);
+ }
+
+ for (const styleHash of result.clientStyleHashes) {
+ finalStyleHashes.add(`'sha256-${styleHash}'`);
+ }
+
+ if (result.renderers.length > 0) {
+ for (const [ name, hash ] of Object.entries(result.astroIslandHashes)) {
+ if (name === 'astro-island-styles') {
+ finalStyleHashes.add(`'sha256-${hash}'`);
+ } else {
+ finalScriptHashes.add(`'sha256-${hash}'`);
+ }
+ }
+ }
+
+ const scriptSrc = `style-src 'self' ${Array.from(finalStyleHashes).join(' ')};`;
+ const styleSrc = `script-src 'self' ${Array.from(finalScriptHashes).join(' ')};`;
+ return `${scriptSrc} ${styleSrc}`;
+}
diff --git a/packages/astro/src/runtime/server/render/head.ts b/packages/astro/src/runtime/server/render/head.ts
index bc7a70f9b965..7989cb7acb5d 100644
--- a/packages/astro/src/runtime/server/render/head.ts
+++ b/packages/astro/src/runtime/server/render/head.ts
@@ -3,6 +3,7 @@ import { markHTMLString } from '../escape.js';
import type { MaybeRenderHeadInstruction, RenderHeadInstruction } from './instruction.js';
import { createRenderInstruction } from './instruction.js';
import { renderElement } from './util.js';
+import { renderCspContent } from './csp.js';
// Filter out duplicate elements in our set
const uniqueElements = (item: any, index: number, all: any[]) => {
@@ -51,26 +52,19 @@ export function renderAllHeadContent(result: SSRResult) {
}
}
- const hashes = [];
-
if (result.shouldInjectCspMetaTags) {
- for (const scriptHash of [...result.clientScriptHashes, ...result.clientStyleHashes]) {
- hashes.push(
- renderElement(
- 'meta',
- {
- props: {
- 'http-equiv': 'content-security-policy',
- content: scriptHash,
- },
- children: '',
- },
- false,
- ),
- );
- }
+ content += renderElement(
+ 'meta',
+ {
+ props: {
+ 'http-equiv': 'content-security-policy',
+ content: renderCspContent(result),
+ },
+ children: '',
+ },
+ false,
+ );
}
- content += hashes.join('\n');
return markHTMLString(content);
}
diff --git a/packages/astro/src/runtime/server/scripts.ts b/packages/astro/src/runtime/server/scripts.ts
index 4756a0adb510..e77947de9168 100644
--- a/packages/astro/src/runtime/server/scripts.ts
+++ b/packages/astro/src/runtime/server/scripts.ts
@@ -18,7 +18,7 @@ export function determinesIfNeedsDirectiveScript(result: SSRResult, directive: s
return true;
}
-export type PrescriptType = null | 'both' | 'directive';
+export type PrescriptType = 'both' | 'directive';
function getDirectiveScriptText(result: SSRResult, directive: string): string {
const clientDirectives = result.clientDirectives;
@@ -31,8 +31,8 @@ function getDirectiveScriptText(result: SSRResult, directive: string): string {
export function getPrescripts(result: SSRResult, type: PrescriptType, directive: string): string {
// Note that this is a classic script, not a module script.
- // This is so that it executes immediate, and when the browser encounters
- // an astro-island element the callbacks will fire immediately, causing the JS
+ // This is so that it executes immediately, and when the browser encounters
+ // an astro-island element, the callbacks will fire immediately, causing the JS
// deps to be loaded immediately.
switch (type) {
case 'both':
@@ -41,8 +41,5 @@ export function getPrescripts(result: SSRResult, type: PrescriptType, directive:
}`;
case 'directive':
return ``;
- case null:
- break;
}
- return '';
}
diff --git a/packages/astro/src/types/public/config.ts b/packages/astro/src/types/public/config.ts
index 39178cf7ae8c..c8393f577906 100644
--- a/packages/astro/src/types/public/config.ts
+++ b/packages/astro/src/types/public/config.ts
@@ -2229,12 +2229,11 @@ export interface ViteUserConfig extends OriginalViteUserConfig {
*/
headingIdCompat?: boolean;
-
/**
- *
+ *
*/
// TODO: add docs once we are reaching the end
- csp?: boolean,
+ csp?: boolean;
/**
* @name experimental.preserveScriptOrder
diff --git a/packages/astro/src/types/public/internal.ts b/packages/astro/src/types/public/internal.ts
index cb29517a2970..50d202389a5d 100644
--- a/packages/astro/src/types/public/internal.ts
+++ b/packages/astro/src/types/public/internal.ts
@@ -7,6 +7,7 @@ import type { Params } from './common.js';
import type { AstroConfig, RedirectConfig } from './config.js';
import type { AstroGlobal, AstroGlobalPartial } from './context.js';
import type { AstroRenderer } from './integrations.js';
+import type { SSRManifest } from '../../core/app/types.js';
export type { SSRManifest } from '../../core/app/types.js';
@@ -250,8 +251,9 @@ export interface SSRResult {
* Whether Astro should inject the CSP tag into the head of the component.
*/
shouldInjectCspMetaTags: boolean;
- clientScriptHashes: string[];
- clientStyleHashes: string[];
+ clientScriptHashes: SSRManifest['clientScriptHashes'];
+ clientStyleHashes: SSRManifest['clientStyleHashes'];
+ astroIslandHashes: SSRManifest['astroIslandHashes'];
}
/**
diff --git a/packages/astro/test/csp.test.js b/packages/astro/test/csp.test.js
index 23ae039a305d..fc5703c0a016 100644
--- a/packages/astro/test/csp.test.js
+++ b/packages/astro/test/csp.test.js
@@ -31,10 +31,32 @@ describe('CSP', () => {
const response = await app.render(request);
const $ = cheerio.load(await response.text());
+ const meta = $('meta[http-equiv="Content-Security-Policy"]');
for (const hash of manifest.clientStyleHashes) {
- let meta = $('meta[http-equiv="Content-Security-Policy"][content="' + hash + '"]');
- assert.equal(meta.length, 1, `Should have a CSP meta tag for ${hash}`);
+ assert.match(
+ meta.attr('content'),
+ new RegExp(`'sha256-${hash}'`),
+ `Should have a CSP meta tag for ${hash}`,
+ );
}
+
+ let [, astroStyleHash] = Object.entries(manifest.astroIslandHashes).find(
+ ([name, _]) => name === 'astro-island-styles',
+ );
+ astroStyleHash = `sha256-${astroStyleHash}`;
+
+ let [, astroIsland] = Object.entries(manifest.astroIslandHashes).find(([name, _]) => name === 'astro-island');
+ astroIsland = `sha256-${astroIsland}`;
+
+ assert.ok(
+ meta.attr('content').includes(astroStyleHash),
+ `Should have a CSP meta tag for ${astroStyleHash}`,
+ );
+
+ assert.ok(
+ meta.attr('content').includes(astroIsland),
+ `Should have a CSP meta tag for ${astroIsland}`,
+ );
} else {
assert.fail('Should have the manifest');
}
diff --git a/packages/astro/test/fixtures/csp/astro.config.mjs b/packages/astro/test/fixtures/csp/astro.config.mjs
index 7184336cde47..9ea073c7d5f6 100644
--- a/packages/astro/test/fixtures/csp/astro.config.mjs
+++ b/packages/astro/test/fixtures/csp/astro.config.mjs
@@ -1,8 +1,12 @@
import { defineConfig } from 'astro/config';
+import react from '@astrojs/react';
export default defineConfig({
experimental: {
csp: true,
- }
+ },
+ integrations: [
+ react()
+ ],
});
diff --git a/packages/astro/test/fixtures/csp/package.json b/packages/astro/test/fixtures/csp/package.json
index 60390ccd8f87..4965f2c6fe5d 100644
--- a/packages/astro/test/fixtures/csp/package.json
+++ b/packages/astro/test/fixtures/csp/package.json
@@ -3,6 +3,9 @@
"version": "0.0.0",
"private": true,
"dependencies": {
- "astro": "workspace:*"
+ "astro": "workspace:*",
+ "@astrojs/react": "workspace:*",
+ "react": "^19.1.0",
+ "react-dom": "^19.1.0"
}
}
diff --git a/packages/astro/test/fixtures/csp/src/components/Text.jsx b/packages/astro/test/fixtures/csp/src/components/Text.jsx
new file mode 100644
index 000000000000..5317786a7d94
--- /dev/null
+++ b/packages/astro/test/fixtures/csp/src/components/Text.jsx
@@ -0,0 +1,5 @@
+
+
+export function Text() {
+ return "Text"
+}
diff --git a/packages/astro/test/fixtures/csp/src/pages/react.astro b/packages/astro/test/fixtures/csp/src/pages/react.astro
new file mode 100644
index 000000000000..934af5df38f6
--- /dev/null
+++ b/packages/astro/test/fixtures/csp/src/pages/react.astro
@@ -0,0 +1,18 @@
+---
+import {Text} from "../components/Text.jsx"
+---
+
+
+
+
+
+
+ Index
+
+
+
+ React
+
+
+
+
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index a63ebed7a8d1..13f5bf53479e 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -2789,9 +2789,18 @@ importers:
packages/astro/test/fixtures/csp:
dependencies:
+ '@astrojs/react':
+ specifier: workspace:*
+ version: link:../../../../integrations/react
astro:
specifier: workspace:*
version: link:../../..
+ react:
+ specifier: ^19.1.0
+ version: 19.1.0
+ react-dom:
+ specifier: ^19.1.0
+ version: 19.1.0(react@19.1.0)
packages/astro/test/fixtures/csrf-check-origin:
dependencies:
@@ -4322,7 +4331,7 @@ importers:
version: 1.0.2
drizzle-orm:
specifier: ^0.31.2
- version: 0.31.4(@cloudflare/workers-types@4.20250327.0)(@libsql/client@0.15.2)(@types/react@18.3.20)(react@19.0.0)
+ version: 0.31.4(@cloudflare/workers-types@4.20250327.0)(@libsql/client@0.15.2)(@types/react@18.3.20)(react@19.1.0)
github-slugger:
specifier: ^2.0.0
version: 2.0.0
@@ -4774,7 +4783,7 @@ importers:
version: link:../../astro-prism
'@markdoc/markdoc':
specifier: ^0.5.1
- version: 0.5.1(@types/react@18.3.20)(react@19.0.0)
+ version: 0.5.1(@types/react@18.3.20)(react@19.1.0)
esbuild:
specifier: ^0.25.0
version: 0.25.0
@@ -5688,7 +5697,7 @@ importers:
version: link:../../internal-helpers
'@vercel/analytics':
specifier: ^1.5.0
- version: 1.5.0(react@19.0.0)(svelte@5.28.2)(vue@3.5.13(typescript@5.8.3))
+ version: 1.5.0(react@19.1.0)(svelte@5.28.2)(vue@3.5.13(typescript@5.8.3))
'@vercel/edge':
specifier: ^1.2.1
version: 1.2.1
@@ -11067,6 +11076,11 @@ packages:
peerDependencies:
react: ^19.0.0
+ react-dom@19.1.0:
+ resolution: {integrity: sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==}
+ peerDependencies:
+ react: ^19.1.0
+
react-refresh@0.17.0:
resolution: {integrity: sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==}
engines: {node: '>=0.10.0'}
@@ -11079,6 +11093,10 @@ packages:
resolution: {integrity: sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ==}
engines: {node: '>=0.10.0'}
+ react@19.1.0:
+ resolution: {integrity: sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==}
+ engines: {node: '>=0.10.0'}
+
read-yaml-file@1.1.0:
resolution: {integrity: sha512-VIMnQi/Z4HT2Fxuwg5KrY174U1VdUIASQVWXXyqtNRtxSr9IYkn1rsI6Tb6HsrHCmB7gVpNwX6JxPTHcH6IoTA==}
engines: {node: '>=6'}
@@ -11295,6 +11313,9 @@ packages:
scheduler@0.25.0:
resolution: {integrity: sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA==}
+ scheduler@0.26.0:
+ resolution: {integrity: sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==}
+
scslre@0.3.0:
resolution: {integrity: sha512-3A6sD0WYP7+QrjbfNA2FN3FsOaGGFoekCVgTyypy53gPxhbkCIjtO6YWgdrfM+n/8sI8JeXZOIxsHjMTNxQ4nQ==}
engines: {node: ^14.0.0 || >=16.0.0}
@@ -13717,12 +13738,12 @@ snapshots:
- encoding
- supports-color
- '@markdoc/markdoc@0.5.1(@types/react@18.3.20)(react@19.0.0)':
+ '@markdoc/markdoc@0.5.1(@types/react@18.3.20)(react@19.1.0)':
optionalDependencies:
'@types/linkify-it': 3.0.5
'@types/markdown-it': 12.2.3
'@types/react': 18.3.20
- react: 19.0.0
+ react: 19.1.0
'@mdx-js/mdx@3.1.0(acorn@8.14.1)':
dependencies:
@@ -14375,9 +14396,9 @@ snapshots:
'@ungap/structured-clone@1.2.0': {}
- '@vercel/analytics@1.5.0(react@19.0.0)(svelte@5.28.2)(vue@3.5.13(typescript@5.8.3))':
+ '@vercel/analytics@1.5.0(react@19.1.0)(svelte@5.28.2)(vue@3.5.13(typescript@5.8.3))':
optionalDependencies:
- react: 19.0.0
+ react: 19.1.0
svelte: 5.28.2
vue: 3.5.13(typescript@5.8.3)
@@ -15292,12 +15313,12 @@ snapshots:
dotenv@8.6.0: {}
- drizzle-orm@0.31.4(@cloudflare/workers-types@4.20250327.0)(@libsql/client@0.15.2)(@types/react@18.3.20)(react@19.0.0):
+ drizzle-orm@0.31.4(@cloudflare/workers-types@4.20250327.0)(@libsql/client@0.15.2)(@types/react@18.3.20)(react@19.1.0):
optionalDependencies:
'@cloudflare/workers-types': 4.20250327.0
'@libsql/client': 0.15.2
'@types/react': 18.3.20
- react: 19.0.0
+ react: 19.1.0
dset@3.1.4: {}
@@ -17693,6 +17714,11 @@ snapshots:
react: 19.0.0
scheduler: 0.25.0
+ react-dom@19.1.0(react@19.1.0):
+ dependencies:
+ react: 19.1.0
+ scheduler: 0.26.0
+
react-refresh@0.17.0: {}
react@18.3.1:
@@ -17701,6 +17727,8 @@ snapshots:
react@19.0.0: {}
+ react@19.1.0: {}
+
read-yaml-file@1.1.0:
dependencies:
graceful-fs: 4.2.11
@@ -18041,6 +18069,8 @@ snapshots:
scheduler@0.25.0: {}
+ scheduler@0.26.0: {}
+
scslre@0.3.0:
dependencies:
'@eslint-community/regexpp': 4.12.1
diff --git a/scripts/cmd/prebuild.js b/scripts/cmd/prebuild.js
index 1ee505500308..4b26aa529bd5 100644
--- a/scripts/cmd/prebuild.js
+++ b/scripts/cmd/prebuild.js
@@ -43,7 +43,7 @@ export default async function prebuild(...args) {
return outURL;
}
- const hashes = [];
+ const hashes = new Map();
async function prebuildFile(filepath) {
let tscode = await fs.promises.readFile(filepath, 'utf-8');
@@ -115,7 +115,8 @@ export default \`${generatedCode}\`;`;
const url = getPrebuildURL(filepath, result.dev);
await fs.promises.writeFile(url, mod, 'utf-8');
const hash = crypto.createHash('sha256').update(code).digest('base64');
- hashes.push(hash);
+ const basename = path.basename(filepath);
+ hashes.set(basename.slice(0, basename.indexOf('.')), hash);
}
}
for (const entrypoint of entryPoints) {
@@ -127,13 +128,14 @@ export default \`${generatedCode}\`;`;
'utf-8',
);
const styleContent = fileContent.match(ASTRO_ISLAND_STYLE_REGEX)[1];
- hashes.push(crypto.createHash('sha256').update(styleContent).digest('base64'));
- hashes.sort();
- const entries = hashes.map((hash) => `"${hash}"`);
+ hashes.set(
+ 'astro-island-styles',
+ crypto.createHash('sha256').update(styleContent).digest('base64'),
+ );
+
+ const entries = JSON.stringify(Object.fromEntries(hashes.entries()), null, 2);
const content = `// This file is code-generated, please don't change it manually
-export const ASTRO_ISLAND_HASHES = [
- ${entries.join(',\n ')}
-];`;
+export const ASTRO_ISLAND_HASHES = ${entries};`;
await fs.promises.writeFile(
path.join(
fileURLToPath(import.meta.url),