@@ -655,6 +655,52 @@ function arrayBufferToBase64(buffer: ArrayBuffer): string {
655655 return btoa ( binary ) ;
656656}
657657
658+ function isObjectUrl ( url : string ) : boolean {
659+ return / ^ ( b l o b | f i l e s y s t e m ) : / i. test ( url . trim ( ) ) ;
660+ }
661+
662+ function loadBlobViaXhr ( url : string ) : Promise < Blob > {
663+ return new Promise ( ( resolve , reject ) => {
664+ const xhr = new XMLHttpRequest ( ) ;
665+ xhr . open ( "GET" , url , true ) ;
666+ xhr . responseType = "blob" ;
667+ xhr . onload = ( ) => {
668+ // Object URLs report status 0 on success; treat that as OK.
669+ if ( xhr . status === 0 || ( xhr . status >= 200 && xhr . status < 300 ) ) {
670+ resolve ( xhr . response as Blob ) ;
671+ } else {
672+ reject ( new Error ( `XHR ${ xhr . status } ` ) ) ;
673+ }
674+ } ;
675+ xhr . onerror = ( ) => reject ( new Error ( "XHR request failed" ) ) ;
676+ xhr . send ( ) ;
677+ } ) ;
678+ }
679+
680+ async function loadAssetBlob ( url : string ) : Promise < Blob > {
681+ // Object URLs (blob:/filesystem:) are same-document; a credentials mode is
682+ // meaningless for them and trips some WebKit builds, so omit it there.
683+ const objectUrl = isObjectUrl ( url ) ;
684+ try {
685+ if ( typeof fetch !== "function" ) {
686+ throw new Error ( "fetch is not available" ) ;
687+ }
688+ const response = await fetch ( url , objectUrl ? undefined : { credentials : "same-origin" } ) ;
689+ if ( ! response . ok ) {
690+ throw new Error ( `HTTP ${ response . status } ` ) ;
691+ }
692+ return await response . blob ( ) ;
693+ } catch ( error ) {
694+ // WebKit/Safari intermittently fails to fetch() object URLs ("Load
695+ // failed"); XMLHttpRequest is the reliable fallback for same-document
696+ // object URLs and is why a textured/atlas export breaks only on Safari.
697+ if ( objectUrl && typeof XMLHttpRequest === "function" ) {
698+ return loadBlobViaXhr ( url ) ;
699+ }
700+ throw error ;
701+ }
702+ }
703+
658704async function inlineAssetUrl ( rawUrl : string , ctx : InlineContext ) : Promise < string > {
659705 if ( isInlineOrLocalReference ( rawUrl ) ) return rawUrl ;
660706
@@ -664,16 +710,7 @@ async function inlineAssetUrl(rawUrl: string, ctx: InlineContext): Promise<strin
664710
665711 const next = ( async ( ) => {
666712 try {
667- if ( typeof fetch !== "function" ) {
668- throw new Error ( "fetch is not available" ) ;
669- }
670-
671- const response = await fetch ( resolvedUrl , { credentials : "same-origin" } ) ;
672- if ( ! response . ok ) {
673- throw new Error ( `HTTP ${ response . status } ` ) ;
674- }
675-
676- const blob = await response . blob ( ) ;
713+ const blob = await loadAssetBlob ( resolvedUrl ) ;
677714 const mime = blob . type || inferMimeType ( resolvedUrl ) ;
678715 const base64 = arrayBufferToBase64 ( await blob . arrayBuffer ( ) ) ;
679716 return `data:${ mime } ;base64,${ base64 } ` ;
0 commit comments