@@ -3,8 +3,8 @@ import { isWordPressRuntimeFile } from "./wordpress-runtime-corpus.js"
33
44export const WORDPRESS_RUNTIME_ARTIFACT_SCHEMA = "wp-codebox/wordpress-runtime-artifact/v1"
55export const WORDPRESS_RUNTIME_MAX_FILES = 2_000
6- export const WORDPRESS_RUNTIME_MAX_UNCOMPRESSED_BYTES = 32 * 1024 * 1024
7- export const WORDPRESS_RUNTIME_MAX_ARCHIVE_BYTES = 32 * 1024 * 1024
6+ export const WORDPRESS_RUNTIME_MAX_UNCOMPRESSED_BYTES = 24 * 1024 * 1024
7+ export const WORDPRESS_RUNTIME_MAX_ARCHIVE_BYTES = 8 * 1024 * 1024
88export const WORDPRESS_RUNTIME_MAX_FILE_BYTES = 8 * 1024 * 1024
99
1010export interface WordPressRuntimeArtifactManifest {
@@ -46,14 +46,16 @@ export async function materializeWordPressRuntimeArtifact(php: RuntimeMemfs, buc
4646 validateWordPressRuntimeArtifactManifest ( manifest )
4747 const object = await bucket . get ( manifest . key )
4848 if ( ! object ) throw new Error ( `WordPress runtime artifact is unavailable: ${ manifest . key } ` )
49+ if ( object . size > WORDPRESS_RUNTIME_MAX_ARCHIVE_BYTES ) throw new Error ( "WordPress runtime artifact archive exceeds its size budget." )
4950 if ( object . size !== manifest . archive . size ) throw new Error ( "WordPress runtime artifact size does not match its manifest." )
5051
51- const [ hashBody , zipBody ] = object . body . tee ( )
52- const archiveHash = sha256ReadableStream ( hashBody )
52+ // The archive and expanded corpus caps leave most of the 128 MiB isolate for PHP-WASM and runtime overhead.
53+ const archiveBytes = new Uint8Array ( await object . arrayBuffer ( ) )
54+ if ( await sha256Hex ( archiveBytes ) !== manifest . archive . sha256 ) throw new Error ( "WordPress runtime artifact archive hash does not match its manifest." )
5355 const expected = new Map ( manifest . files . map ( ( file ) => [ file . path , file ] ) )
5456 let materializedFiles = 0
5557 let materializedBytes = 0
56- for await ( const entry of decodeZip ( zipBody ) ) {
58+ for await ( const entry of decodeZip ( new Blob ( [ archiveBytes ] ) . stream ( ) ) ) {
5759 const file = expected . get ( entry . name )
5860 if ( ! file ) throw new Error ( `WordPress runtime artifact contains an unexpected file: ${ entry . name } ` )
5961 const bytes = new Uint8Array ( await entry . arrayBuffer ( ) )
@@ -66,7 +68,6 @@ export async function materializeWordPressRuntimeArtifact(php: RuntimeMemfs, buc
6668 php . writeFile ( destination , bytes )
6769 expected . delete ( entry . name )
6870 }
69- if ( await archiveHash !== manifest . archive . sha256 ) throw new Error ( "WordPress runtime artifact archive hash does not match its manifest." )
7071 if ( expected . size ) throw new Error ( "WordPress runtime artifact is missing manifest files." )
7172 return { materializedFiles, materializedBytes }
7273}
@@ -75,23 +76,6 @@ function isSafeRuntimePath(path: string): boolean {
7576 return path . startsWith ( "wordpress/" ) && ! path . includes ( "\\" ) && ! path . split ( "/" ) . some ( ( segment ) => ! segment || segment === "." || segment === ".." )
7677}
7778
78- async function sha256ReadableStream ( stream : ReadableStream ) : Promise < string > {
79- const chunks : Uint8Array [ ] = [ ]
80- let size = 0
81- for await ( const chunk of stream as AsyncIterable < Uint8Array > ) {
82- size += chunk . byteLength
83- if ( size > WORDPRESS_RUNTIME_MAX_ARCHIVE_BYTES ) throw new Error ( "WordPress runtime artifact archive exceeds its size budget." )
84- chunks . push ( chunk )
85- }
86- const bytes = new Uint8Array ( size )
87- let offset = 0
88- for ( const chunk of chunks ) {
89- bytes . set ( chunk , offset )
90- offset += chunk . byteLength
91- }
92- return sha256Hex ( bytes )
93- }
94-
9579async function sha256Hex ( bytes : Uint8Array ) : Promise < string > {
9680 const digest = await crypto . subtle . digest ( "SHA-256" , Uint8Array . from ( bytes ) . buffer )
9781 return Array . from ( new Uint8Array ( digest ) , ( byte ) => byte . toString ( 16 ) . padStart ( 2 , "0" ) ) . join ( "" )
0 commit comments