url-sanitizer 4.2.0 → 4.2.2

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.
package/README.md CHANGED
@@ -427,17 +427,17 @@ Unpredictable AI outputs introduce unique security risks, and `url-sanitizer` is
427
427
 
428
428
  ### Defending Against Complex & Obfuscated Payloads
429
429
  LLMs can generate highly complex, nested, or Base64-encoded `data:` URLs — either through prompt injection, RAG data poisoning, or simply reproducing obfuscated code from their training data.
430
- Because `url-sanitizer` performs **Deep Data URL Inspection** — decoding the payload, purifying the inner HTML/SVG tree via DOMPurify, and re-encoding it — it physically neutralizes hidden XSS vectors, ensuring that AI-generated data URLs are safe to render.
430
+ Because `url-sanitizer` performs **Deep Data URL Inspection** — decoding the payload, purifying the inner HTML/SVG tree via DOMPurify, and re-encoding it — it effectively neutralizes hidden XSS vectors, ensuring that AI-generated data URLs are safe to render.
431
431
 
432
432
  ### Neutralizing Hallucinated Schemes
433
433
  LLMs generate URLs based on statistical linguistic patterns rather than factual databases.
434
434
  As a result, they frequently hallucinate plausible-looking but non-existent or hazardous URI schemes (e.g., `ai-agent://`, `host-settings:`).
435
- By operating on a **Secure by Default** whitelist approach, `url-sanitizer` automatically denies any unrecognized or unregistered protocols.
436
- This strict blocking prevents hallucinated schemes from inadvertently triggering application-specific or OS-level protocol hijacking.
435
+ By operating on a whitelist approach, `url-sanitizer` automatically denies any unrecognized or unregistered protocols.
436
+ This strict blocking prevents non-existent or hallucinated schemes from inadvertently triggering application-specific or OS-level protocol hijacking.
437
437
 
438
438
  ## Performance
439
439
 
440
- Execution times were measured using [mitata](https://github.com/evanwashere/mitata) on Node.js[cite: 9].
440
+ Execution times were measured using [mitata](https://github.com/evanwashere/mitata) on Node.js.
441
441
 
442
442
  ### Benchmark Results
443
443
 
@@ -1,4 +1,4 @@
1
- var re=Object.freeze(["addHook","removeHook","removeAllHooks","setConfig"]),U=[],S=new Proxy({},{get(s,e){let t=globalThis.DOMPurify||globalThis.window?.DOMPurify;if(t){if(U.length){for(let{prop:a,args:n}of U)typeof t[a]=="function"&&t[a](...n);U.length=0}let r=t[e];return typeof r=="function"?r.bind(t):r}return(...r)=>{if(re.includes(e))return U.push({prop:e,args:r}),s;throw new Error("DOMPurify is not available. Ensure DOMPurify is exposed globally (e.g., window.DOMPurify).")}}});var R=s=>Object.prototype.toString.call(s).slice(8,-1),m=s=>typeof s=="string"||s instanceof String;var k=["aaa","aaas","about","acap","acct","acd","acr","adiumxtra","adt","afp","afs","agtp","aim","amss","android","appdata","apt","ar","ari","ark","at","attachment","aw","barion","beshare","bitcoin","bitcoincash","bl","blob","bluetooth","bolo","brid","browserext","cabal","caip","calculator","callto","cap","cast","casts","chrome","chrome-extension","cid","coap","coaps","com-eventbrite-attendee","content","content-type","crid","cstr","cttps","cvs","dab","dat","data","dav","dhttp","diaspora","dict","did","dilithium3","dis","dlna-playcontainer","dlna-playsingle","dnp","dns","dntp","doi","donau","dpp","drm","dtmi","dtn","dvb","dvx","dweb","ed2k","eid","elsi","embedded","ens","esim","ethereum","example","ez","facetime","feed","feedready","fido","file","finger","first-run-pen-experience","fish","fm","ftp","fuchsia-pkg","geo","gg","git","gitoid","gizmoproject","go","gopher","graph","gtalk","h323","ham","hcap","hcp","hs20","http","https","hxxp","hxxps","hydrazone","hyper","i0","iax","ibi","ibi-","icap","icon","ilstring","im","imap","info","iotdisco","ipfs","ipn","ipns","ipp","ipps","irc","irc6","ircs","iris","iris.beep","iris.lwz","iris.xpc","iris.xpcs","isostore","itms","jabber","jar","jms","keyparc","lastfm","lbry","ldap","ldaps","leaptofrogans","lid","linkid","lorawan","lpa","lvlt","machineProvisioningProgressReporter","magnet","mailto","maps","market","matrix","mdoc","mdoc-openid4vp","message","microsoft.windows.camera","microsoft.windows.camera.multipicker","microsoft.windows.camera.picker","mid","mms","mongodb","moz","moz-extension","mqtt","mqtts","ms-access","ms-appinstaller","ms-browser-extension","ms-calculator","ms-drive-to","ms-enrollment","ms-excel","ms-eyecontrolspeech","ms-gamebarservices","ms-gamingoverlay","ms-getoffice","ms-help","ms-infopath","ms-inputapp","ms-launchremotedesktop","ms-lockscreencomponent-config","ms-media-stream-id","ms-meetnow","ms-mixedrealitycapture","ms-mobileplans","ms-newsandinterests","ms-officeapp","ms-people","ms-personacard","ms-powerpoint","ms-project","ms-publisher","ms-recall","ms-remotedesktop","ms-remotedesktop-launch","ms-restoretabcompanion","ms-screenclip","ms-screensketch","ms-search","ms-search-repair","ms-secondary-screen-controller","ms-secondary-screen-setup","ms-settings","ms-settings-airplanemode","ms-settings-bluetooth","ms-settings-camera","ms-settings-cellular","ms-settings-cloudstorage","ms-settings-connectabledevices","ms-settings-displays-topology","ms-settings-emailandaccounts","ms-settings-language","ms-settings-location","ms-settings-lock","ms-settings-nfctransactions","ms-settings-notifications","ms-settings-power","ms-settings-privacy","ms-settings-proximity","ms-settings-screenrotation","ms-settings-wifi","ms-settings-workplace","ms-spd","ms-stickers","ms-sttoverlay","ms-transit-to","ms-useractivityset","ms-uup","ms-virtualtouchpad","ms-visio","ms-walk-to","ms-whiteboard","ms-whiteboard-cmd","ms-widgetboard","ms-widgets","ms-word","msnim","msrp","msrps","mss","mt","mtqp","mtrust","mumble","mupdate","musik","mvn","mvrp","mvrps","news","nfs","ni","nih","nntp","nostr","notes","npamp","num","ocf","oid","onenote","onenote-cmd","opaquelocktoken","openid","openpgp4fpr","otpauth","palm","paparazzi","payto","pkcs11","platform","pop","pres","proxy","psyc","pttp","pwid","qb","query","quic-transport","redis","rediss","reload","res","resource","rmi","rsync","rtmfp","rtmp","rtsp","rtsps","rtspu","sarif","secondlife","secret-token","service","session","sftp","sgn","shc","shelter","sieve","simpleledger","simplex","sip","sips","skype","smb","smp","sms","smtp","snmp","soap.beep","soap.beeps","soldat","spacify","spiffe","spotify","ssb","ssh","sss","starknet","steam","stun","stuns","submit","svn","swh","swid","swidpath","tag","taler","teamspeak","teapot","teapots","tel","teliaeid","telnet","tftp","things","thismessage","tip","tn3270","tool","tttps","turn","turns","tv","udp","unreal","upn","urn","ust","ut2004","uuaid","uuid-in-package","v-event","vemmi","ventrilo","ves","view-source","vnc","vscode","vscode-insiders","vsls","w3","wasm","wasm-js","wcr","web3","webcal","wifi","ws","wss","wtai","wyciwyg","xcompute","xcon","xcon-userid","xfire","xftp","xmlrpc.beep","xmlrpc.beeps","xmpp","xrcp","xri","ymsgr","z39.50r","z39.50s","ztdnaid"];var D=/(?:#|%23)$/,G=/^(?:application\/(?:[\w.-]+\+)?xml|image\/svg\+xml|text\/(?:html|xml))(?:\s*;\s*|$)/i;var B=/&#(x0*[\dA-F]{1,2}|0*\d{1,3});?/gi,j=/^((?:[^#%]|%(?!23))*)(?:\?|%3F)$/i,A=/^[a-z][\da-z+.-]*$/,F=/^(?:web\+[a-z]+|ext\+[a-z][\da-z.-]*)$/,w=/^(?:java|vb)script$/i,z=/^(?:(?:java|vb)script|blob)$/i,v=/["'<>]|%(?:22|27|3C|3E)|&(?:apos|lt|gt|quot|#0*(?:34|39|60|62)|#x0*(?:22|27|3C|3E));/i,H=/^%[\dA-F]{2}$/i,I=/&(?=[#a-z0-9])(?![a-z0-9]+=)/i,X=/(?:%[\dA-F]{2})+/gi,V=/^(?:\/{2,}|\\|[a-z][a-z\d+\-.]*:[^/])/i;var Y=[9,10,13,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255];var P=new Set(Y),_=new Map([[128,8364],[130,8218],[131,402],[132,8222],[133,8230],[134,8224],[135,8225],[136,710],[137,8240],[138,352],[139,8249],[140,338],[142,381],[145,8216],[146,8217],[147,8220],[148,8221],[149,8226],[150,8211],[151,8212],[152,732],[153,8482],[154,353],[155,8250],[156,339],[158,382],[159,376]]),ce=()=>{let s=new Map;for(let e=0;e<256;e++)!P.has(e)&&!_.has(e)&&s.set(e,`\\x${e.toString(16).padStart(2,"0").toUpperCase()}`);return s},L=ce();var[b,pe,de,me,fe,ue]=["&","#","<",">",'"',"'"].map(s=>`%${s.charCodeAt(0).toString(16).toUpperCase()}`),he={[b]:`${b}amp;`,[de]:`${b}lt;`,[me]:`${b}gt;`,[fe]:`${b}quot;`,[ue]:`${b}${pe}39;`},Ye=Array.from({length:256},(s,e)=>`%${e.toString(16).padStart(2,"0").toUpperCase()}`),Q=globalThis.process?.versions?.node!==void 0,ge=new RegExp(`[${[...L.values()].join("")}]`),ye=new RegExp(`[${[...L.values()].join("")}]`,"g"),qe=new TextEncoder,Re=new TextDecoder("utf-8",{fatal:!0}),C=class{#e=new Set(k);get(){return[...this.#e]}has(e){return this.#e.has(e)}verify(e,t=this.#e){if(!m(e))return!1;let r=e.normalize("NFKC"),a=URL.parse(r);if(!a)return!1;let n=a.protocol.replace(/:$/,""),i=n.split("+");return i.some(o=>w.test(o))?!1:F.test(n)||i.every(o=>t.has(o))}};var K=s=>{if(!m(s))return s;let e=H.test(s)?s.toUpperCase():s;return he[e]??s},W=s=>{if(!m(s))throw new TypeError(`Expected String but got ${R(s)}.`);let e=s.replace(/\s/g,""),t;try{t=atob(e)}catch{throw new Error(`Invalid base64 data: ${s}`)}let r;if(Q&&globalThis.Buffer)r=globalThis.Buffer.from(t,"latin1");else{let a=t.length;r=new Uint8Array(a);for(let n=0;n<a;n++)r[n]=t.charCodeAt(n)}try{let a=Re.decode(r);return ge.test(a)?e:a}catch{return e}},xe=(s,e)=>{let t=/x/i.test(e[0])?parseInt(e.substring(1),16):parseInt(e,10);if(Number.isInteger(t)){if(P.has(t))return String.fromCharCode(t);if(_.has(t)){let r=_.get(t);return String.fromCodePoint(r)}else if(L.has(t))return""}return s},Z=s=>m(s)?s.replace(D,"").replace(j,"$1"):s,J=(s,e=0)=>{if(!m(s))throw new TypeError(`Expected String but got ${R(s)}.`);if(!Number.isInteger(e))throw new TypeError(`Expected Number but got ${R(e)}.`);let t;try{t=decodeURIComponent(s)}catch{t=s.replace(X,a=>{try{return decodeURIComponent(a)}catch{return a}})}t=t.replace(ye,"");let r=0;for(;r+e<=16;r++){let a=t;if(t=t.replace(/&amp;/gi,"&").replace(B,xe),t===a)break}if(r+e>16&&/&#/.test(t))throw new Error("Character references nested too deeply.");return t},be=async s=>{let e=s.type?`${s.type};base64`:"base64",t=await s.arrayBuffer(),r=globalThis.Buffer.from(t).toString("base64");return`data:${e},${r}`},Ee=s=>new Promise((e,t)=>{let r=new globalThis.FileReader;r.addEventListener("error",()=>t(r.error)),r.addEventListener("abort",()=>e(null)),r.addEventListener("load",()=>e(r.result)),r.readAsDataURL(s)}),we=async s=>{let e=s.type?`${s.type};base64`:"base64",t=await s.arrayBuffer(),r=new Uint8Array(t),a=[];for(let n=0;n<r.length;n+=8192)a.push(String.fromCharCode(...r.subarray(n,n+8192)));return`data:${e},${btoa(a.join(""))}`},ee=async(s,e=16777216)=>{if(Number.isInteger(s?.size)){if(Number.isInteger(e)&&s.size>e){let t=`Blob size (${s.size} bytes) exceeds max (${e} bytes).`;throw new DOMException(t,"NotReadableError")}}else return null;return Q&&globalThis.Buffer?be(s):globalThis.FileReader?Ee(s):we(s)};var Ue=Object.freeze(["href","origin","protocol","username","password","host","hostname","port","pathname","search","hash"]),Se=Object.freeze({RETURN_DOM:!1,RETURN_DOM_FRAGMENT:!1,RETURN_TRUSTED_TYPE:!1}),h=(s,e,t)=>{s&&console.warn(`[URLSanitizer Debug] ${e}`,t)},N=class s extends C{#e;static#t=null;static#s=null;static#n(e,t){if(!t.attrValue||!/^\s*data:/i.test(t.attrValue))return;let r=s.#t,a=s.#s;if(!r||!a)return;let n=URL.parse(t.attrValue);if(n&&n.protocol==="data:"){let i=t.attrValue;if(a.recurse||(a.recurse=new Set),a.recurse.has(i)){let c=`Circular Data URL detected and skipped: ${i}`;h(a.debug,c),t.attrValue="";return}a.nest++,a.recurse.add(i);try{let c=r.#a(i,{allow:["data"],deny:[],only:[],allowRelative:!1},a);t.attrValue=c||""}finally{a.nest--,a.recurse.delete(i)}}}static{S.setConfig(Se),S.addHook("uponSanitizeAttribute",s.#n)}constructor(){super(),this.#e=new Set(super.get())}#r(e,t,r,a,n){if(z.test(e))return!1;if(e.split("+").some(o=>w.test(o))||!A.test(e)){let o=`Failed to add scheme '${e}' in '${t}' list.`;return h(n.debug,o),!1}return a.set(e,!0),r.add(e),!0}#i(e,t){let r=e;try{r=decodeURIComponent(e)}catch{}let a=s.#t,n=s.#s;s.#t=this,s.#s=t;let i;try{i=t.domPurify.sanitize(r)}finally{s.#t=a,s.#s=n}i=Z(i);try{return encodeURI(i)}catch{return i}}#a(e,t,r){if(r.nest>16)throw new Error("Data URLs nested too deeply.");let{allowedSchemes:a,restrictScheme:n,schemeMap:i}=this.#o(t,r),{isDataUrl:c,isRelative:o,isVerified:l,scheme:d,schemeParts:p,urlObj:f,urlToSanitize:u}=this.#c(e,t.allowRelative,a,r);return!l||!this.#l(d,p,n,i,o)?null:c?this.#p(f,d,r):this.#d(u)}#o({allow:e,deny:t,only:r},a){let n=this.#e,i=!1,c=new Map(a.schemeMap);if(r.length){n=new Set;for(let o of r)m(o)&&this.#r(o.trim(),"only",n,c,a)&&!i&&(i=!0)}else{if(e.length){n=new Set(this.#e);for(let o of e)m(o)&&this.#r(o.trim(),"allow",n,c,a)}if(t.length)for(let o of t)m(o)&&(o=o.trim(),o&&c.set(o,!1))}return{allowedSchemes:n,restrictScheme:i,schemeMap:c}}#c(e,t,r,a){let n=super.verify(e,r),i=!1,c="";if(!n&&t&&!V.test(e)){let p=e.normalize("NFKC"),f=URL.parse(e,"http://dummy.local"),u=URL.parse(p,"http://dummy.local");f&&u?f.protocol==="http:"&&f.hostname==="dummy.local"&&u.protocol==="http:"&&(n=!0,i=!0,c=`${f.pathname}${f.search}${f.hash}`):h(a.debug,"Failed to parse relative URL.")}if(!n)return{isVerified:!1};if(i)return{isRelative:i,isVerified:n,isDataUrl:!1,scheme:"",schemeParts:[],urlToSanitize:c};let o=URL.parse(e),l=o.protocol.replace(/:$/,"").normalize("NFKC"),d=l.split("+");return{isRelative:i,isVerified:n,scheme:l,schemeParts:d,urlObj:o,isDataUrl:d.includes("data"),urlToSanitize:o.href}}#l(e,t,r,a,n){if(n)return!0;if(r)return t.every(i=>a.get(i));for(let[i,c]of a.entries())if(!(c||e!==i&&t.every(l=>l!==i)))return!1;return!0}#p(e,t,r){let[a,...n]=e.pathname.split(","),i=`${n.join(",")}${e.search}${e.hash}`,c=a.split(";"),o=c[c.length-1]==="base64",l=i;if(o)try{l=W(i)}catch(d){return h(r.debug,"Failed to parse base64 data.",d),null}try{let p=J(l).trim().normalize("NFKC"),u=URL.parse(p,"http://dummy.local");if(!u)return h(r.debug,"Failed to parse inner data URL protocol."),null;if(u.protocol.replace(/:$/,"").split("+").some(x=>z.test(x)))return null}catch(d){return h(r.debug,"Failed to parse inner data URL protocol.",d),null}return(!a||G.test(a))&&(l=this.#i(l,r)),l?(o&&l!==i&&c.pop(),`${t}:${c.join(";")},${l}`):null}#d(e){let t=e;if(v.test(t)){let{index:r}=v.exec(t);t=t.substring(0,r).replace(/[?&]$/,"")}if(I.test(t)){let{index:r}=I.exec(t);t=t.substring(0,r).replace(/[?&]$/,"")}return t}sanitize(e,t){if(!e||!m(e))return null;let r=Number.isInteger(t?.maxLength)&&t.maxLength?t.maxLength:0;if(r&&e.length>r){let c=`URL length ${e.length} exceeds maxLength ${r}.`;throw new RangeError(c)}if(!(t&&(Array.isArray(t.deny)&&t.deny.length>0||Array.isArray(t.only)&&t.only.length>0||t.allowRelative))&&(e.startsWith("https://")||e.startsWith("http://"))&&!v.test(e)&&!e.includes("data:")){let c=URL.parse(e);return c?c.href.replace(/%26/g,K):(h(t?.debug,"Failed to parse URL."),null)}let n={allow:Array.isArray(t?.allow)?t.allow:[],deny:Array.isArray(t?.deny)?t.deny:[],only:Array.isArray(t?.only)?t.only:[],allowRelative:!!t?.allowRelative},i={debug:!!t?.debug,domPurify:S,nest:0,recurse:null,schemeMap:new Map([["blob",!1],["data",!1],["file",!1],["javascript",!1],["vbscript",!1]])};return this.#a(e,n,i)}inspect(e,t){if(!m(e))throw new TypeError(`Expected String but got ${R(e)}.`);let r={input:e,valid:!1},a,n=null,i=Number.isInteger(t?.maxLength)&&t.maxLength?t.maxLength:0,c=e.length;if(i&&c>i)n=`URL length ${c} exceeds maxLength ${i}.`;else if(this.verify(e)){let{protocol:o}=new URL(e);if(o==="blob:")a=e;else try{a=this.sanitize(e,t??{allow:["data"]}),a||(n="Sanitization failed (blocked by allowed schemes or rules).")}catch(l){n=l.message}}else n="Invalid URI syntax or scheme is not registered.";if(a){let o=new URL(a),{pathname:l,protocol:d}=o,f=d.replace(/:$/,"").split("+").includes("data");if(r.valid=!0,f){let[u,...E]=l.split(","),O=`${E.join(",")}${o.search}${o.hash}`,x=u.split(";"),M=x[x.length-1]==="base64";M&&x.pop(),r.data={mime:x.join(";"),base64:M,data:O}}else r.data=null;for(let u of Ue){let E=o[u];m(E)&&(r[u]=E)}}else r.valid=!1,n&&(r.reason=n);return r}get(){return[...this.#e]}has(e){return this.#e.has(e)}add(e){if(m(e))e=e.trim();else throw new TypeError(`Expected String but got ${R(e)}.`);if(e.split("+").some(a=>w.test(a))||!A.test(e))throw new Error(`Invalid scheme: ${e}`);return this.#e.add(e),[...this.#e]}remove(e){return this.#e.delete(e)}reset(){this.#e=new Set(super.get())}verify(e,t=this.#e){return super.verify(e,t)}};var y=new N,ve=async(s,e={allow:[],deny:[],only:[],allowRelative:!1,debug:!1,revokeObjectURL:!1,maxBlobSize:16777216})=>{let t=!!e?.debug,r=Number.isInteger(e?.maxBlobSize)&&e.maxBlobSize>0?e.maxBlobSize:16777216,a;if(s&&m(s)){let n,i=URL.parse(s);if(i?n=i.protocol.replace(/:$/,""):h(t,`Invalid URL input format: ${s}`),n==="blob"){let{allow:c,deny:o,only:l}=e;if(Array.isArray(c)&&c.includes("blob")&&!(Array.isArray(o)&&o.includes("blob"))||Array.isArray(l)&&l.includes("blob")){let d;try{d=await fetch(s).then(p=>p.blob()).then(p=>ee(p,r))}catch(p){let f=`Failed to fetch and convert blob URL: ${s}`;h(t,f,p)}if(d){let p={...e};Array.isArray(e.only)?p.only=e.only.includes("data")?e.only:[...e.only,"data"]:Array.isArray(e.allow)&&(p.allow=e.allow.includes("data")?e.allow:[...e.allow,"data"],Array.isArray(e.deny)&&(p.deny=e.deny.filter(f=>f!=="data"))),a=y.sanitize(d,p)}}e?.revokeObjectURL&&URL.revokeObjectURL(s)}else(n||e.allowRelative)&&(a=y.sanitize(s,e))}return a||null},_e=(s,e={allow:[],deny:[],only:[],allowRelative:!1,debug:!1,revokeObjectURL:!1})=>{let t=!!e?.debug,r;if(s&&m(s)){let a,n=URL.parse(s);if(n?a=n.protocol.replace(/:$/,""):h(t,`Invalid URL input format: ${s}`),a==="blob")return e?.revokeObjectURL&&URL.revokeObjectURL(s),null;(a||e.allowRelative)&&(r=y.sanitize(s,e))}return r||null},te=async s=>y.inspect(s),Le=async s=>te(s),se=s=>y.inspect(s),Te=s=>se(s),Ce=async s=>y.verify(s),$e=s=>y.verify(s),Ae=y;export{Ae as default,te as inspectURL,se as inspectURLSync,Ce as isURI,$e as isURISync,Le as parseURL,Te as parseURLSync,ve as sanitizeURL,_e as sanitizeURLSync};
1
+ var re=Object.freeze(["addHook","removeHook","removeAllHooks","setConfig"]),U=[],S=new Proxy({},{get(s,e){let t=globalThis.DOMPurify||globalThis.window?.DOMPurify;if(t){if(U.length){for(let{prop:a,args:n}of U)typeof t[a]=="function"&&t[a](...n);U.length=0}let r=t[e];return typeof r=="function"?r.bind(t):r}return(...r)=>{if(re.includes(e))return U.push({prop:e,args:r}),s;throw new Error("DOMPurify is not available. Ensure DOMPurify is exposed globally (e.g., window.DOMPurify).")}}});var R=s=>Object.prototype.toString.call(s).slice(8,-1),p=s=>typeof s=="string"||s instanceof String;var k=["aaa","aaas","about","acap","acct","acd","acr","adiumxtra","adt","afp","afs","agtp","aim","amss","android","appdata","apt","ar","ari","ark","at","attachment","aw","barion","beshare","bitcoin","bitcoincash","bl","blob","bluetooth","bolo","brid","browserext","cabal","caip","calculator","callto","cap","cast","casts","chrome","chrome-extension","cid","coap","coaps","com-eventbrite-attendee","content","content-type","crid","cstr","cttps","cvs","dab","dat","data","dav","dhttp","diaspora","dict","did","dilithium3","dis","dlna-playcontainer","dlna-playsingle","dnp","dns","dntp","doi","donau","dpp","drm","dtmi","dtn","dvb","dvx","dweb","ed2k","eid","elsi","embedded","ens","esim","ethereum","example","ez","facetime","feed","feedready","fido","file","finger","first-run-pen-experience","fish","fm","ftp","fuchsia-pkg","geo","gg","git","gitoid","gizmoproject","go","gopher","graph","gtalk","h323","ham","hcap","hcp","hs20","http","https","hxxp","hxxps","hydrazone","hyper","i0","iax","ibi","ibi-","icap","icon","ilstring","im","imap","info","iotdisco","ipfs","ipn","ipns","ipp","ipps","irc","irc6","ircs","iris","iris.beep","iris.lwz","iris.xpc","iris.xpcs","isostore","itms","jabber","jar","jms","keyparc","lastfm","lbry","ldap","ldaps","leaptofrogans","lid","linkid","lorawan","lpa","lvlt","machineProvisioningProgressReporter","magnet","mailto","maps","market","matrix","mdoc","mdoc-openid4vp","message","microsoft.windows.camera","microsoft.windows.camera.multipicker","microsoft.windows.camera.picker","mid","mms","mongodb","moz","moz-extension","mqtt","mqtts","ms-access","ms-appinstaller","ms-browser-extension","ms-calculator","ms-drive-to","ms-enrollment","ms-excel","ms-eyecontrolspeech","ms-gamebarservices","ms-gamingoverlay","ms-getoffice","ms-help","ms-infopath","ms-inputapp","ms-launchremotedesktop","ms-lockscreencomponent-config","ms-media-stream-id","ms-meetnow","ms-mixedrealitycapture","ms-mobileplans","ms-newsandinterests","ms-officeapp","ms-people","ms-personacard","ms-powerpoint","ms-project","ms-publisher","ms-recall","ms-remotedesktop","ms-remotedesktop-launch","ms-restoretabcompanion","ms-screenclip","ms-screensketch","ms-search","ms-search-repair","ms-secondary-screen-controller","ms-secondary-screen-setup","ms-settings","ms-settings-airplanemode","ms-settings-bluetooth","ms-settings-camera","ms-settings-cellular","ms-settings-cloudstorage","ms-settings-connectabledevices","ms-settings-displays-topology","ms-settings-emailandaccounts","ms-settings-language","ms-settings-location","ms-settings-lock","ms-settings-nfctransactions","ms-settings-notifications","ms-settings-power","ms-settings-privacy","ms-settings-proximity","ms-settings-screenrotation","ms-settings-wifi","ms-settings-workplace","ms-spd","ms-stickers","ms-sttoverlay","ms-transit-to","ms-useractivityset","ms-uup","ms-virtualtouchpad","ms-visio","ms-walk-to","ms-whiteboard","ms-whiteboard-cmd","ms-widgetboard","ms-widgets","ms-word","msnim","msrp","msrps","mss","mt","mtqp","mtrust","mumble","mupdate","musik","mvn","mvrp","mvrps","news","nfs","ni","nih","nntp","nostr","notes","npamp","num","ocf","oid","onenote","onenote-cmd","opaquelocktoken","openid","openpgp4fpr","otpauth","palm","paparazzi","payto","pkcs11","platform","pop","pres","proxy","psyc","pttp","pwid","qb","query","quic-transport","redis","rediss","reload","res","resource","rmi","rsync","rtmfp","rtmp","rtsp","rtsps","rtspu","sarif","secondlife","secret-token","service","session","sftp","sgn","shc","shelter","sieve","simpleledger","simplex","sip","sips","skype","smb","smp","sms","smtp","snmp","soap.beep","soap.beeps","soldat","spacify","spiffe","spotify","ssb","ssh","sss","starknet","steam","stun","stuns","submit","svn","swh","swid","swidpath","tag","taler","teamspeak","teapot","teapots","tel","teliaeid","telnet","tftp","things","thismessage","tip","tn3270","tool","tttps","turn","turns","tv","udp","unreal","upn","urn","ust","ut2004","uuaid","uuid-in-package","v-event","vemmi","ventrilo","ves","view-source","vnc","vscode","vscode-insiders","vsls","w3","wasm","wasm-js","wcr","web3","webcal","wifi","ws","wss","wtai","wyciwyg","xcompute","xcon","xcon-userid","xfire","xftp","xmlrpc.beep","xmlrpc.beeps","xmpp","xrcp","xri","ymsgr","z39.50r","z39.50s","ztdnaid"];var D=/(?:#|%23)$/,G=/^(?:application\/(?:[\w.-]+\+)?xml|image\/svg\+xml|text\/(?:html|xml))(?:\s*;\s*|$)/i;var B=/&#(x0*[\dA-F]{1,2}|0*\d{1,3});?/gi,j=/^((?:[^#%]|%(?!23))*)(?:\?|%3F)$/i,A=/^[a-z][\da-z+.-]*$/,F=/^(?:web\+[a-z]+|ext\+[a-z][\da-z.-]*)$/,w=/^(?:java|vb)script$/i,z=/^(?:(?:java|vb)script|blob)$/i,v=/["'<>]|%(?:22|27|3C|3E)|&(?:apos|lt|gt|quot|#0*(?:34|39|60|62)|#x0*(?:22|27|3C|3E));/i,H=/^%[\dA-F]{2}$/i,I=/&(?=[#a-z0-9])(?![a-z0-9]+=)/i,X=/(?:%[\dA-F]{2})+/gi,V=/^(?:\/{2,}|\\|[a-z][a-z\d+\-.]*:[^/])/i;var Y=[9,10,13,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255];var P=new Set(Y),L=new Map([[128,8364],[130,8218],[131,402],[132,8222],[133,8230],[134,8224],[135,8225],[136,710],[137,8240],[138,352],[139,8249],[140,338],[142,381],[145,8216],[146,8217],[147,8220],[148,8221],[149,8226],[150,8211],[151,8212],[152,732],[153,8482],[154,353],[155,8250],[156,339],[158,382],[159,376]]),ce=()=>{let s=new Map;for(let e=0;e<256;e++)!P.has(e)&&!L.has(e)&&s.set(e,`\\x${e.toString(16).padStart(2,"0").toUpperCase()}`);return s},_=ce();var[b,pe,me,de,fe,ue]=["&","#","<",">",'"',"'"].map(s=>`%${s.charCodeAt(0).toString(16).toUpperCase()}`),he={[b]:`${b}amp;`,[me]:`${b}lt;`,[de]:`${b}gt;`,[fe]:`${b}quot;`,[ue]:`${b}${pe}39;`},Ye=Array.from({length:256},(s,e)=>`%${e.toString(16).padStart(2,"0").toUpperCase()}`),Q=globalThis.process?.versions?.node!==void 0,ge=new RegExp(`[${[..._.values()].join("")}]`),ye=new RegExp(`[${[..._.values()].join("")}]`,"g"),qe=new TextEncoder,Re=new TextDecoder("utf-8",{fatal:!0}),T=class{#e=new Set(k);get(){return[...this.#e]}has(e){return p(e)?this.#e.has(e.trim().toLowerCase()):!1}verify(e,t=this.#e){if(!p(e))return!1;let r=e.normalize("NFKC"),a=URL.parse(r);if(!a)return!1;let n=a.protocol.replace(/:$/,""),o=n.split("+");return o.some(i=>w.test(i))?!1:F.test(n)||o.every(i=>t.has(i))}};var K=s=>{if(!p(s))return s;let e=H.test(s)?s.toUpperCase():s;return he[e]??s},W=s=>{if(!p(s))throw new TypeError(`Expected String but got ${R(s)}.`);let e=s.replace(/\s/g,""),t;try{t=atob(e)}catch{throw new Error(`Invalid base64 data: ${s}`)}let r;if(Q&&globalThis.Buffer)r=globalThis.Buffer.from(t,"latin1");else{let a=t.length;r=new Uint8Array(a);for(let n=0;n<a;n++)r[n]=t.charCodeAt(n)}try{let a=Re.decode(r);return ge.test(a)?e:a}catch{return e}},xe=(s,e)=>{let t=/x/i.test(e[0])?parseInt(e.substring(1),16):parseInt(e,10);if(Number.isInteger(t)){if(P.has(t))return String.fromCharCode(t);if(L.has(t)){let r=L.get(t);return String.fromCodePoint(r)}else if(_.has(t))return""}return s},Z=s=>p(s)?s.replace(D,"").replace(j,"$1"):s,J=(s,e=0)=>{if(!p(s))throw new TypeError(`Expected String but got ${R(s)}.`);if(!Number.isInteger(e))throw new TypeError(`Expected Number but got ${R(e)}.`);let t;try{t=decodeURIComponent(s)}catch{t=s.replace(X,a=>{try{return decodeURIComponent(a)}catch{return a}})}t=t.replace(ye,"");let r=0;for(;r+e<=16;r++){let a=t;if(t=t.replace(/&amp;/gi,"&").replace(B,xe),t===a)break}if(r+e>16&&/&#/.test(t))throw new Error("Character references nested too deeply.");return t},be=async s=>{let e=s.type?`${s.type};base64`:"base64",t=await s.arrayBuffer(),r=globalThis.Buffer.from(t).toString("base64");return`data:${e},${r}`},Ee=s=>new Promise((e,t)=>{let r=new globalThis.FileReader;r.addEventListener("error",()=>t(r.error)),r.addEventListener("abort",()=>e(null)),r.addEventListener("load",()=>e(r.result)),r.readAsDataURL(s)}),we=async s=>{let e=s.type?`${s.type};base64`:"base64",t=await s.arrayBuffer(),r=new Uint8Array(t),a=[];for(let n=0;n<r.length;n+=8192)a.push(String.fromCharCode(...r.subarray(n,n+8192)));return`data:${e},${btoa(a.join(""))}`},ee=async(s,e=16777216)=>{if(Number.isInteger(s?.size)){if(Number.isInteger(e)&&s.size>e){let t=`Blob size (${s.size} bytes) exceeds max (${e} bytes).`;throw new DOMException(t,"NotReadableError")}}else return null;return Q&&globalThis.Buffer?be(s):globalThis.FileReader?Ee(s):we(s)};var Ue=Object.freeze(["href","origin","protocol","username","password","host","hostname","port","pathname","search","hash"]),Se=Object.freeze({RETURN_DOM:!1,RETURN_DOM_FRAGMENT:!1,RETURN_TRUSTED_TYPE:!1}),h=(s,e,t)=>{s&&console.warn(`[URLSanitizer Debug] ${e}`,t)},N=class s extends T{#e;static#t=null;static#s=null;static#n(e,t){if(!t.attrValue||!/^\s*data:/i.test(t.attrValue))return;let r=s.#t,a=s.#s;if(!r||!a)return;let n=URL.parse(t.attrValue);if(n&&n.protocol==="data:"){let o=t.attrValue;if(a.recurse||(a.recurse=new Set),a.recurse.has(o)){let c=`Circular Data URL detected and skipped: ${o}`;h(a.debug,c),t.attrValue="";return}a.nest++,a.recurse.add(o);try{let c=r.#a(o,{allow:["data"],deny:[],only:[],allowRelative:!1},a);t.attrValue=c||""}finally{a.nest--,a.recurse.delete(o)}}}static{S.setConfig(Se),S.addHook("uponSanitizeAttribute",s.#n)}constructor(){super(),this.#e=new Set(super.get())}#r(e,t,r,a,n){if(z.test(e))return!1;if(e.split("+").some(i=>w.test(i))||!A.test(e)){let i=`Failed to add scheme '${e}' in '${t}' list.`;return h(n.debug,i),!1}return a.set(e,!0),r.add(e),!0}#o(e,t){let r=e;try{r=decodeURIComponent(e)}catch{}let a=s.#t,n=s.#s;s.#t=this,s.#s=t;let o;try{o=t.domPurify.sanitize(r)}finally{s.#t=a,s.#s=n}o=Z(o);try{return encodeURI(o)}catch{return o}}#a(e,t,r){if(r.nest>16)throw new Error("Data URLs nested too deeply.");let{allowedSchemes:a,restrictScheme:n,schemeMap:o}=this.#i(t,r),{isDataUrl:c,isRelative:i,isVerified:l,scheme:d,schemeParts:m,urlObj:f,urlToSanitize:u}=this.#c(e,t.allowRelative,a,r);return!l||!this.#l(d,m,n,o,i)?null:c?this.#p(f,d,r):this.#m(u)}#i({allow:e,deny:t,only:r},a){let n=this.#e,o=!1,c=new Map(a.schemeMap);if(r.length){n=new Set;for(let i of r)p(i)&&this.#r(i.trim(),"only",n,c,a)&&!o&&(o=!0)}else{if(e.length){n=new Set(this.#e);for(let i of e)p(i)&&this.#r(i.trim(),"allow",n,c,a)}if(t.length)for(let i of t)p(i)&&(i=i.trim(),i&&c.set(i,!1))}return{allowedSchemes:n,restrictScheme:o,schemeMap:c}}#c(e,t,r,a){let n=super.verify(e,r),o=!1,c="";if(!n&&t&&!V.test(e)){let m=e.normalize("NFKC"),f=URL.parse(e,"http://dummy.local"),u=URL.parse(m,"http://dummy.local");f&&u?f.protocol==="http:"&&f.hostname==="dummy.local"&&u.protocol==="http:"&&(n=!0,o=!0,c=`${f.pathname}${f.search}${f.hash}`):h(a.debug,"Failed to parse relative URL.")}if(!n)return{isVerified:!1};if(o)return{isRelative:o,isVerified:n,isDataUrl:!1,scheme:"",schemeParts:[],urlToSanitize:c};let i=URL.parse(e),l=i.protocol.replace(/:$/,"").normalize("NFKC"),d=l.split("+");return{isRelative:o,isVerified:n,scheme:l,schemeParts:d,urlObj:i,isDataUrl:d.includes("data"),urlToSanitize:i.href}}#l(e,t,r,a,n){if(n)return!0;if(r)return t.every(o=>a.get(o));for(let[o,c]of a.entries())if(!(c||e!==o&&t.every(l=>l!==o)))return!1;return!0}#p(e,t,r){let[a,...n]=e.pathname.split(","),o=`${n.join(",")}${e.search}${e.hash}`,c=a.split(";"),i=c[c.length-1]==="base64",l=o;if(i)try{l=W(o)}catch(d){return h(r.debug,"Failed to parse base64 data.",d),null}try{let m=J(l).trim().normalize("NFKC"),u=URL.parse(m,"http://dummy.local");if(!u)return h(r.debug,"Failed to parse inner data URL protocol."),null;if(u.protocol.replace(/:$/,"").split("+").some(x=>z.test(x)))return null}catch(d){return h(r.debug,"Failed to parse inner data URL protocol.",d),null}return(!a||G.test(a))&&(l=this.#o(l,r)),l?(i&&l!==o&&c.pop(),`${t}:${c.join(";")},${l}`):null}#m(e){let t=e;if(v.test(t)){let{index:r}=v.exec(t);t=t.substring(0,r).replace(/[?&]$/,"")}if(I.test(t)){let{index:r}=I.exec(t);t=t.substring(0,r).replace(/[?&]$/,"")}return t}sanitize(e,t){if(!e||!p(e))return null;let r=Number.isInteger(t?.maxLength)&&t.maxLength?t.maxLength:0;if(r&&e.length>r){let c=`URL length ${e.length} exceeds maxLength ${r}.`;throw new RangeError(c)}if(!(t&&(Array.isArray(t.deny)&&t.deny.length>0||Array.isArray(t.only)&&t.only.length>0||t.allowRelative))&&(e.startsWith("https://")||e.startsWith("http://"))&&!v.test(e)&&!e.includes("data:")){let c=URL.parse(e);return c?c.href.replace(/%26/g,K):(h(t?.debug,"Failed to parse URL."),null)}let n={allow:Array.isArray(t?.allow)?t.allow:[],deny:Array.isArray(t?.deny)?t.deny:[],only:Array.isArray(t?.only)?t.only:[],allowRelative:!!t?.allowRelative},o={debug:!!t?.debug,domPurify:S,nest:0,recurse:null,schemeMap:new Map([["blob",!1],["data",!1],["file",!1],["javascript",!1],["vbscript",!1]])};return this.#a(e,n,o)}inspect(e,t){if(!p(e))throw new TypeError(`Expected String but got ${R(e)}.`);let r={input:e,valid:!1},a,n=null,o=Number.isInteger(t?.maxLength)&&t.maxLength?t.maxLength:0,c=e.length;if(o&&c>o)n=`URL length ${c} exceeds maxLength ${o}.`;else if(this.verify(e)){let{protocol:i}=new URL(e);if(i==="blob:")a=e;else try{a=this.sanitize(e,t??{allow:["data"]}),a||(n="Sanitization failed (blocked by allowed schemes or rules).")}catch(l){n=l.message}}else n="Invalid URI syntax or scheme is not registered.";if(a){let i=new URL(a),{pathname:l,protocol:d}=i,f=d.replace(/:$/,"").split("+").includes("data");if(r.valid=!0,f){let[u,...E]=l.split(","),O=`${E.join(",")}${i.search}${i.hash}`,x=u.split(";"),M=x[x.length-1]==="base64";M&&x.pop(),r.data={mime:x.join(";"),base64:M,data:O}}else r.data=null;for(let u of Ue){let E=i[u];p(E)&&(r[u]=E)}}else r.valid=!1,n&&(r.reason=n);return r}get(){return[...this.#e]}has(e){return p(e)?this.#e.has(e.trim().toLowerCase()):!1}add(e){let t;if(p(e))t=e.trim().toLowerCase();else throw new TypeError(`Expected String but got ${R(e)}.`);if(t.split("+").some(n=>w.test(n))||!A.test(t))throw new Error(`Invalid scheme: ${e}`);return this.#e.add(t),[...this.#e]}remove(e){return p(e)?this.#e.delete(e.trim().toLowerCase()):!1}reset(){this.#e=new Set(super.get())}verify(e,t=this.#e){return super.verify(e,t)}};var y=new N,ve=async(s,e={allow:[],deny:[],only:[],allowRelative:!1,debug:!1,revokeObjectURL:!1,maxBlobSize:16777216})=>{let t=!!e?.debug,r=Number.isInteger(e?.maxBlobSize)&&e.maxBlobSize>0?e.maxBlobSize:16777216,a;if(s&&p(s)){let n,o=URL.parse(s);if(o?n=o.protocol.replace(/:$/,""):h(t,`Invalid URL input format: ${s}`),n==="blob"){let{allow:c,deny:i,only:l}=e;if(Array.isArray(c)&&c.includes("blob")&&!(Array.isArray(i)&&i.includes("blob"))||Array.isArray(l)&&l.includes("blob")){let d;try{d=await fetch(s).then(m=>m.blob()).then(m=>ee(m,r))}catch(m){let f=`Failed to fetch and convert blob URL: ${s}`;h(t,f,m)}if(d){let m={...e};Array.isArray(e.only)?m.only=e.only.includes("data")?e.only:[...e.only,"data"]:Array.isArray(e.allow)&&(m.allow=e.allow.includes("data")?e.allow:[...e.allow,"data"],Array.isArray(e.deny)&&(m.deny=e.deny.filter(f=>f!=="data"))),a=y.sanitize(d,m)}}e?.revokeObjectURL&&URL.revokeObjectURL(s)}else(n||e.allowRelative)&&(a=y.sanitize(s,e))}return a||null},Le=(s,e={allow:[],deny:[],only:[],allowRelative:!1,debug:!1,revokeObjectURL:!1})=>{let t=!!e?.debug,r;if(s&&p(s)){let a,n=URL.parse(s);if(n?a=n.protocol.replace(/:$/,""):h(t,`Invalid URL input format: ${s}`),a==="blob")return e?.revokeObjectURL&&URL.revokeObjectURL(s),null;(a||e.allowRelative)&&(r=y.sanitize(s,e))}return r||null},te=async s=>y.inspect(s),_e=async s=>te(s),se=s=>y.inspect(s),Ce=s=>se(s),Te=async s=>y.verify(s),$e=s=>y.verify(s),Ae=y;export{Ae as default,te as inspectURL,se as inspectURLSync,Te as isURI,$e as isURISync,_e as parseURL,Ce as parseURLSync,ve as sanitizeURL,Le as sanitizeURLSync};
2
2
  /*!
3
3
  * URL Sanitizer
4
4
  *
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../bundle_wo_dompurify/mjs/dompurify.js", "../bundle_wo_dompurify/mjs/common.js", "../bundle_wo_dompurify/lib/iana/uri-schemes.json", "../bundle_wo_dompurify/mjs/regexp.js", "../bundle_wo_dompurify/lib/file/text-chars.json", "../bundle_wo_dompurify/mjs/text-chars.js", "../bundle_wo_dompurify/mjs/uri-util.js", "../bundle_wo_dompurify/mjs/sanitizer.js"],
4
- "sourcesContent": ["/**\n * dompurify.js (for wo-dompurify build)\n */\n\n/* constants */\nconst PROPERTIES = Object.freeze([\n 'addHook',\n 'removeHook',\n 'removeAllHooks',\n 'setConfig'\n]);\n\nconst hookQueue = [];\nexport const domPurify = new Proxy({}, {\n get(target, prop) {\n const purifier = globalThis.DOMPurify || globalThis.window?.DOMPurify;\n if (purifier) {\n if (hookQueue.length) {\n for (const { prop: p, args } of hookQueue) {\n if (typeof purifier[p] === 'function') {\n purifier[p](...args);\n }\n }\n hookQueue.length = 0;\n }\n const value = purifier[prop];\n return typeof value === 'function' ? value.bind(purifier) : value;\n }\n return (...args) => {\n if (PROPERTIES.includes(prop)) {\n hookQueue.push({ prop, args });\n return target;\n }\n throw new Error('DOMPurify is not available. Ensure DOMPurify is exposed globally (e.g., window.DOMPurify).');\n };\n }\n});\n", "/**\n * common.js\n */\n\n/* shared */\nimport { TYPE_FROM, TYPE_TO } from './constant.js';\n\n/**\n * Gets the type of the given object.\n * Returns the object class name (e.g., \"String\", \"Array\", \"Null\", \"Undefined\").\n * @param {unknown} o - The object to check.\n * @returns {string} The specific type of the object.\n */\nexport const getType = o =>\n Object.prototype.toString.call(o).slice(TYPE_FROM, TYPE_TO);\n\n/**\n * Checks if the given value is a string.\n * @param {unknown} o - The value to check.\n * @returns {boolean} True if the value is a string, false otherwise.\n */\nexport const isString = o => typeof o === 'string' || o instanceof String;\n", "[\"aaa\",\"aaas\",\"about\",\"acap\",\"acct\",\"acd\",\"acr\",\"adiumxtra\",\"adt\",\"afp\",\"afs\",\"agtp\",\"aim\",\"amss\",\"android\",\"appdata\",\"apt\",\"ar\",\"ari\",\"ark\",\"at\",\"attachment\",\"aw\",\"barion\",\"beshare\",\"bitcoin\",\"bitcoincash\",\"bl\",\"blob\",\"bluetooth\",\"bolo\",\"brid\",\"browserext\",\"cabal\",\"caip\",\"calculator\",\"callto\",\"cap\",\"cast\",\"casts\",\"chrome\",\"chrome-extension\",\"cid\",\"coap\",\"coaps\",\"com-eventbrite-attendee\",\"content\",\"content-type\",\"crid\",\"cstr\",\"cttps\",\"cvs\",\"dab\",\"dat\",\"data\",\"dav\",\"dhttp\",\"diaspora\",\"dict\",\"did\",\"dilithium3\",\"dis\",\"dlna-playcontainer\",\"dlna-playsingle\",\"dnp\",\"dns\",\"dntp\",\"doi\",\"donau\",\"dpp\",\"drm\",\"dtmi\",\"dtn\",\"dvb\",\"dvx\",\"dweb\",\"ed2k\",\"eid\",\"elsi\",\"embedded\",\"ens\",\"esim\",\"ethereum\",\"example\",\"ez\",\"facetime\",\"feed\",\"feedready\",\"fido\",\"file\",\"finger\",\"first-run-pen-experience\",\"fish\",\"fm\",\"ftp\",\"fuchsia-pkg\",\"geo\",\"gg\",\"git\",\"gitoid\",\"gizmoproject\",\"go\",\"gopher\",\"graph\",\"gtalk\",\"h323\",\"ham\",\"hcap\",\"hcp\",\"hs20\",\"http\",\"https\",\"hxxp\",\"hxxps\",\"hydrazone\",\"hyper\",\"i0\",\"iax\",\"ibi\",\"ibi-\",\"icap\",\"icon\",\"ilstring\",\"im\",\"imap\",\"info\",\"iotdisco\",\"ipfs\",\"ipn\",\"ipns\",\"ipp\",\"ipps\",\"irc\",\"irc6\",\"ircs\",\"iris\",\"iris.beep\",\"iris.lwz\",\"iris.xpc\",\"iris.xpcs\",\"isostore\",\"itms\",\"jabber\",\"jar\",\"jms\",\"keyparc\",\"lastfm\",\"lbry\",\"ldap\",\"ldaps\",\"leaptofrogans\",\"lid\",\"linkid\",\"lorawan\",\"lpa\",\"lvlt\",\"machineProvisioningProgressReporter\",\"magnet\",\"mailto\",\"maps\",\"market\",\"matrix\",\"mdoc\",\"mdoc-openid4vp\",\"message\",\"microsoft.windows.camera\",\"microsoft.windows.camera.multipicker\",\"microsoft.windows.camera.picker\",\"mid\",\"mms\",\"mongodb\",\"moz\",\"moz-extension\",\"mqtt\",\"mqtts\",\"ms-access\",\"ms-appinstaller\",\"ms-browser-extension\",\"ms-calculator\",\"ms-drive-to\",\"ms-enrollment\",\"ms-excel\",\"ms-eyecontrolspeech\",\"ms-gamebarservices\",\"ms-gamingoverlay\",\"ms-getoffice\",\"ms-help\",\"ms-infopath\",\"ms-inputapp\",\"ms-launchremotedesktop\",\"ms-lockscreencomponent-config\",\"ms-media-stream-id\",\"ms-meetnow\",\"ms-mixedrealitycapture\",\"ms-mobileplans\",\"ms-newsandinterests\",\"ms-officeapp\",\"ms-people\",\"ms-personacard\",\"ms-powerpoint\",\"ms-project\",\"ms-publisher\",\"ms-recall\",\"ms-remotedesktop\",\"ms-remotedesktop-launch\",\"ms-restoretabcompanion\",\"ms-screenclip\",\"ms-screensketch\",\"ms-search\",\"ms-search-repair\",\"ms-secondary-screen-controller\",\"ms-secondary-screen-setup\",\"ms-settings\",\"ms-settings-airplanemode\",\"ms-settings-bluetooth\",\"ms-settings-camera\",\"ms-settings-cellular\",\"ms-settings-cloudstorage\",\"ms-settings-connectabledevices\",\"ms-settings-displays-topology\",\"ms-settings-emailandaccounts\",\"ms-settings-language\",\"ms-settings-location\",\"ms-settings-lock\",\"ms-settings-nfctransactions\",\"ms-settings-notifications\",\"ms-settings-power\",\"ms-settings-privacy\",\"ms-settings-proximity\",\"ms-settings-screenrotation\",\"ms-settings-wifi\",\"ms-settings-workplace\",\"ms-spd\",\"ms-stickers\",\"ms-sttoverlay\",\"ms-transit-to\",\"ms-useractivityset\",\"ms-uup\",\"ms-virtualtouchpad\",\"ms-visio\",\"ms-walk-to\",\"ms-whiteboard\",\"ms-whiteboard-cmd\",\"ms-widgetboard\",\"ms-widgets\",\"ms-word\",\"msnim\",\"msrp\",\"msrps\",\"mss\",\"mt\",\"mtqp\",\"mtrust\",\"mumble\",\"mupdate\",\"musik\",\"mvn\",\"mvrp\",\"mvrps\",\"news\",\"nfs\",\"ni\",\"nih\",\"nntp\",\"nostr\",\"notes\",\"npamp\",\"num\",\"ocf\",\"oid\",\"onenote\",\"onenote-cmd\",\"opaquelocktoken\",\"openid\",\"openpgp4fpr\",\"otpauth\",\"palm\",\"paparazzi\",\"payto\",\"pkcs11\",\"platform\",\"pop\",\"pres\",\"proxy\",\"psyc\",\"pttp\",\"pwid\",\"qb\",\"query\",\"quic-transport\",\"redis\",\"rediss\",\"reload\",\"res\",\"resource\",\"rmi\",\"rsync\",\"rtmfp\",\"rtmp\",\"rtsp\",\"rtsps\",\"rtspu\",\"sarif\",\"secondlife\",\"secret-token\",\"service\",\"session\",\"sftp\",\"sgn\",\"shc\",\"shelter\",\"sieve\",\"simpleledger\",\"simplex\",\"sip\",\"sips\",\"skype\",\"smb\",\"smp\",\"sms\",\"smtp\",\"snmp\",\"soap.beep\",\"soap.beeps\",\"soldat\",\"spacify\",\"spiffe\",\"spotify\",\"ssb\",\"ssh\",\"sss\",\"starknet\",\"steam\",\"stun\",\"stuns\",\"submit\",\"svn\",\"swh\",\"swid\",\"swidpath\",\"tag\",\"taler\",\"teamspeak\",\"teapot\",\"teapots\",\"tel\",\"teliaeid\",\"telnet\",\"tftp\",\"things\",\"thismessage\",\"tip\",\"tn3270\",\"tool\",\"tttps\",\"turn\",\"turns\",\"tv\",\"udp\",\"unreal\",\"upn\",\"urn\",\"ust\",\"ut2004\",\"uuaid\",\"uuid-in-package\",\"v-event\",\"vemmi\",\"ventrilo\",\"ves\",\"view-source\",\"vnc\",\"vscode\",\"vscode-insiders\",\"vsls\",\"w3\",\"wasm\",\"wasm-js\",\"wcr\",\"web3\",\"webcal\",\"wifi\",\"ws\",\"wss\",\"wtai\",\"wyciwyg\",\"xcompute\",\"xcon\",\"xcon-userid\",\"xfire\",\"xftp\",\"xmlrpc.beep\",\"xmlrpc.beeps\",\"xmpp\",\"xrcp\",\"xri\",\"ymsgr\",\"z39.50r\",\"z39.50s\",\"ztdnaid\"]\n", "/**\n * regexp.js\n */\n\n/**\n * Matches and captures the charset parameter in a media type string.\n * @type {RegExp}\n */\nexport const REG_CHARSET = /^charset\\s*=\\s*([\"']?)(?<name>[\\w:-]+)\\1$/;\n\n/**\n * Matches a trailing empty fragment identifier (#).\n * @type {RegExp}\n */\nexport const REG_HASH = /(?:#|%23)$/;\n\n/**\n * Matches MIME types that contain DOM-parsable content (HTML, XML, SVG).\n * @type {RegExp}\n */\nexport const REG_MIME_DOM =\n /^(?:application\\/(?:[\\w.-]+\\+)?xml|image\\/svg\\+xml|text\\/(?:html|xml))(?:\\s*;\\s*|$)/i;\n\n/**\n * Matches general text MIME types.\n * @type {RegExp}\n */\nexport const REG_MIME_TEXT = /^text\\/[\\w#&.;-]+/;\n\n/**\n * Matches numeric character reference.\n * @type {RegExp}\n */\nexport const REG_NUM_REF = /&#(x0*[\\dA-F]{1,2}|0*\\d{1,3});?/gi;\n\n/**\n * Matches a trailing empty query string (?), ensuring it is not part of a hash.\n * @type {RegExp}\n */\nexport const REG_QUERY = /^((?:[^#%]|%(?!23))*)(?:\\?|%3F)$/i;\n\n/**\n * Validates a string against standard IANA URI scheme syntax.\n * @type {RegExp}\n */\nexport const REG_SCHEME = /^[a-z][\\da-z+.-]*$/;\n\n/**\n * Matches web custom schemes (`web+`) or application-specific schemes (`ext+`).\n * - `web+` schemes comply with the HTML Standard.\n * - `ext+` schemes comply with RFC 3986 but disallow `+` in the suffix.\n * @type {RegExp}\n */\nexport const REG_SCHEME_EXT = /^(?:web\\+[a-z]+|ext\\+[a-z][\\da-z.-]*)$/;\n\n/**\n * Matches executable script schemes (javascript or vbscript).\n * @type {RegExp}\n */\nexport const REG_SCRIPT = /^(?:java|vb)script$/i;\n\n/**\n * Matches script-executing or data-fetching schemes.\n * @type {RegExp}\n */\nexport const REG_SCRIPT_BLOB = /^(?:(?:java|vb)script|blob)$/i;\n\n/**\n * Matches HTML tags, quotes, and their encoded or character reference variants.\n * @type {RegExp}\n */\nexport const REG_TAG_QUOT =\n /[\"'<>]|%(?:22|27|3C|3E)|&(?:apos|lt|gt|quot|#0*(?:34|39|60|62)|#x0*(?:22|27|3C|3E));/i;\n\n/**\n * Matches a percent-encoded character (%XX).\n * @type {RegExp}\n */\nexport const REG_URL_ENC = /^%[\\dA-F]{2}$/i;\n\n/**\n * Matches an ampersand-encoded character (&foo).\n * @type {RegExp}\n */\nexport const REG_AMP_ENC = /&(?=[#a-z0-9])(?![a-z0-9]+=)/i;\n\n/**\n * Match one or more consecutive URL percent-encoded sequences (%20, %E3%81%82).\n * @type {RegExp}\n */\nexport const REG_PCT_ENC = /(?:%[\\dA-F]{2})+/gi;\n\n/**\n * Validates relative URLs and flags invalid patterns.\n * @type {RegExp}\n */\nexport const REG_VERIFY_RELATIVE = /^(?:\\/{2,}|\\\\|[a-z][a-z\\d+\\-.]*:[^/])/i;\n", "[9,10,13,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255]\n", "/**\n * text-chars.js\n */\n\n/* shared */\nimport textChars from '../lib/file/text-chars.json' with { type: 'json' };\nimport { HEX } from './constant.js';\n\n/**\n * A set of valid text character codes.\n * @type {Set<number>}\n */\nexport const TEXT_CHAR_CODES = new Set(textChars);\n\n/**\n * A mapping of Windows-1252 specific character codes to their corresponding Unicode code points.\n * @type {Map<number, number>}\n */\nexport const WINDOWS1252_TO_UNICODE = new Map([\n [128, 0x20ac],\n [130, 0x201a],\n [131, 0x0192],\n [132, 0x201e],\n [133, 0x2026],\n [134, 0x2020],\n [135, 0x2021],\n [136, 0x02c6],\n [137, 0x2030],\n [138, 0x0160],\n [139, 0x2039],\n [140, 0x0152],\n [142, 0x017d],\n [145, 0x2018],\n [146, 0x2019],\n [147, 0x201c],\n [148, 0x201d],\n [149, 0x2022],\n [150, 0x2013],\n [151, 0x2014],\n [152, 0x02dc],\n [153, 0x2122],\n [154, 0x0161],\n [155, 0x203a],\n [156, 0x0153],\n [158, 0x017e],\n [159, 0x0178]\n]);\n\n/**\n * Generates control character codes in hex.\n * @private\n * @returns {Map<number, string>} Generated control char codes.\n */\nconst generateCtrlCharCodes = () => {\n const charCodes = new Map();\n for (let i = 0; i < HEX * HEX; i++) {\n if (!TEXT_CHAR_CODES.has(i) && !WINDOWS1252_TO_UNICODE.has(i)) {\n charCodes.set(i, `\\\\x${i.toString(HEX).padStart(2, '0').toUpperCase()}`);\n }\n }\n return charCodes;\n};\n\n/**\n * A mapping of control character codes to their hexadecimal escape strings.\n * @type {Map<number, string>}\n */\nexport const CTRL_CHAR_CODES = generateCtrlCharCodes();\n", "/**\n * uri-util.js\n */\n\n/* shared */\nimport uriSchemes from '../lib/iana/uri-schemes.json' with { type: 'json' };\nimport { getType, isString } from './common.js';\n\n/* constants */\nimport { CHUNK_SIZE, DECI, HEX, MAX_BLOB_SIZE, MAX_NEST } from './constant.js';\nimport {\n REG_HASH,\n REG_NUM_REF,\n REG_PCT_ENC,\n REG_QUERY,\n REG_SCHEME_EXT,\n REG_SCRIPT,\n REG_URL_ENC\n} from './regexp.js';\nimport {\n CTRL_CHAR_CODES,\n TEXT_CHAR_CODES,\n WINDOWS1252_TO_UNICODE\n} from './text-chars.js';\nconst [ENC_AMP, ENC_NUM, ENC_LT, ENC_GT, ENC_QUOT, ENC_APOS] = [\n '&',\n '#',\n '<',\n '>',\n '\"',\n \"'\"\n].map(ch => `%${ch.charCodeAt(0).toString(HEX).toUpperCase()}`);\nconst ESCAPE_MAP = {\n [ENC_AMP]: `${ENC_AMP}amp;`,\n [ENC_LT]: `${ENC_AMP}lt;`,\n [ENC_GT]: `${ENC_AMP}gt;`,\n [ENC_QUOT]: `${ENC_AMP}quot;`,\n [ENC_APOS]: `${ENC_AMP}${ENC_NUM}39;`\n};\nconst HEX_TABLE = Array.from(\n { length: HEX * HEX },\n (_, i) => `%${i.toString(HEX).padStart(2, '0').toUpperCase()}`\n);\nconst IS_NODE = globalThis.process?.versions?.node !== undefined;\nconst REG_BINARY = new RegExp(`[${[...CTRL_CHAR_CODES.values()].join('')}]`);\nconst REG_CTRL_CHARS = new RegExp(\n `[${[...CTRL_CHAR_CODES.values()].join('')}]`,\n 'g'\n);\n\n/* encoder / decoder */\nconst encoder = new TextEncoder();\nconst decoder = new TextDecoder('utf-8', { fatal: true });\n\n/**\n * URI schemes\n */\nexport class URISchemes {\n /* private fields */\n #schemes = new Set(uriSchemes);\n\n /**\n * Gets the list of registered URI schemes.\n * @see {@link https://www.iana.org/assignments/uri-schemes/uri-schemes.xhtml}\n * - Historical schemes are omitted.\n * - The 'moz-extension' scheme is added by default.\n * @returns {string[]} An array of registered schemes.\n */\n get() {\n return [...this.#schemes];\n }\n\n /**\n * Checks if the specified scheme is currently registered.\n * @param {string} scheme - The target scheme.\n * @returns {boolean} True if the scheme is registered.\n */\n has(scheme) {\n return this.#schemes.has(scheme);\n }\n\n /**\n * Verifies if the given URI is valid and its scheme is allowed.\n * @param {string} uri - The URI string to verify.\n * @param {Set<string>} [schemes] - The set of allowed schemes.\n * @returns {boolean} True if the URI is syntactically valid and permitted.\n */\n verify(uri, schemes = this.#schemes) {\n if (!isString(uri)) {\n return false;\n }\n const normalizedUri = uri.normalize('NFKC');\n const parsedUrl = URL.parse(normalizedUri);\n if (!parsedUrl) {\n return false;\n }\n const scheme = parsedUrl.protocol.replace(/:$/, '');\n const parts = scheme.split('+');\n const isScript = parts.some(s => REG_SCRIPT.test(s));\n if (isScript) {\n return false;\n }\n return REG_SCHEME_EXT.test(scheme) || parts.every(s => schemes.has(s));\n }\n}\n\n/**\n * Gets the URL-encoded representation of a given string.\n * @param {string} str - The target string.\n * @returns {string} The URL-encoded string.\n */\nexport const getURLEncodedString = str => {\n if (!isString(str)) {\n throw new TypeError(`Expected String but got ${getType(str)}.`);\n }\n const bytes = encoder.encode(str);\n let encoded = '';\n for (let i = 0; i < bytes.length; i++) {\n encoded += HEX_TABLE[bytes[i]];\n }\n return encoded;\n};\n\n/**\n * Escapes URL-encoded HTML special characters.\n * @param {string} ch - A URL-encoded (percent-encoded) character.\n * @returns {string} The escaped HTML special character, or the given character.\n */\n\nexport const escapeURLEncodedHTMLChars = ch => {\n if (!isString(ch)) {\n return ch;\n }\n const target = REG_URL_ENC.test(ch) ? ch.toUpperCase() : ch;\n return ESCAPE_MAP[target] ?? ch;\n};\n\n/**\n * Parses base64-encoded data.\n * @param {string} data - The base64-encoded string.\n * @returns {string} The parsed text, or the original base64 if binary.\n */\nexport const parseBase64 = data => {\n if (!isString(data)) {\n throw new TypeError(`Expected String but got ${getType(data)}.`);\n }\n const cleanData = data.replace(/\\s/g, '');\n let binStr;\n try {\n binStr = atob(cleanData);\n } catch {\n throw new Error(`Invalid base64 data: ${data}`);\n }\n let bytes;\n if (IS_NODE && globalThis.Buffer) {\n // Use 'latin1' to correctly map the binary string directly to bytes.\n // @see https://nodejs.org/docs/latest/api/buffer.html#buffers-and-character-encodings\n bytes = globalThis.Buffer.from(binStr, 'latin1');\n } else {\n const len = binStr.length;\n bytes = new Uint8Array(len);\n for (let i = 0; i < len; i++) {\n bytes[i] = binStr.charCodeAt(i);\n }\n }\n try {\n const text = decoder.decode(bytes);\n if (REG_BINARY.test(text)) {\n return cleanData;\n }\n return text;\n } catch {\n return cleanData;\n }\n};\n\n/**\n * Replaces URL-encoded numeric character references.\n * @param {string} match - The matched substring.\n * @param {string} value - The captured numeric value.\n * @returns {string} The resolved character or the original match.\n */\nexport const replaceNumCharRef = (match, value) => {\n const num = /x/i.test(value[0])\n ? parseInt(value.substring(1), HEX)\n : parseInt(value, DECI);\n if (Number.isInteger(num)) {\n if (TEXT_CHAR_CODES.has(num)) {\n return String.fromCharCode(num);\n } else if (WINDOWS1252_TO_UNICODE.has(num)) {\n const codePoint = WINDOWS1252_TO_UNICODE.get(num);\n return String.fromCodePoint(codePoint);\n } else if (CTRL_CHAR_CODES.has(num)) {\n return '';\n }\n }\n return match;\n};\n\n/**\n * Removes a trailing empty hash and an empty query string from a URL.\n * @param {string} url - The target URL string to be cleaned.\n * @returns {string} The cleaned URL string or the original input.\n */\nexport const trimTrailingEmptyQueryAndHash = url => {\n if (!isString(url)) {\n return url;\n }\n return url.replace(REG_HASH, '').replace(REG_QUERY, '$1');\n};\n\n/**\n * Parses URL-encoded numeric character references in the range 0x00 to 0xFF.\n * @param {string} str - The target string to parse.\n * @param {number} [nest] - The current nesting depth for recursive parsing.\n * @returns {string} The decoded and parsed string.\n */\nexport const parseURLEncodedNumCharRef = (str, nest = 0) => {\n if (!isString(str)) {\n throw new TypeError(`Expected String but got ${getType(str)}.`);\n }\n if (!Number.isInteger(nest)) {\n throw new TypeError(`Expected Number but got ${getType(nest)}.`);\n }\n let res;\n try {\n res = decodeURIComponent(str);\n } catch {\n // Fallback: decode only valid multi-byte %XX sequences.\n res = str.replace(REG_PCT_ENC, match => {\n try {\n return decodeURIComponent(match);\n } catch {\n return match;\n }\n });\n }\n res = res.replace(REG_CTRL_CHARS, '');\n let depth = 0;\n for (; depth + nest <= MAX_NEST; depth++) {\n const previousRes = res;\n // Decode '&amp;' before decoding numeric references.\n res = res.replace(/&amp;/gi, '&').replace(REG_NUM_REF, replaceNumCharRef);\n if (res === previousRes) {\n break;\n }\n }\n if (depth + nest > MAX_NEST && /&#/.test(res)) {\n throw new Error('Character references nested too deeply.');\n }\n return res;\n};\n\n/**\n * Converts Blob to data URL from Buffer.\n * @private\n * @param {Blob} blob - The target Blob object.\n * @returns {Promise<string|null>} A promise resolving to the data URL, or null.\n */\nconst convertFromBuffer = async blob => {\n const mimeStr = blob.type ? `${blob.type};base64` : 'base64';\n const buffer = await blob.arrayBuffer();\n const base64 = globalThis.Buffer.from(buffer).toString('base64');\n return `data:${mimeStr},${base64}`;\n};\n\n/**\n * Converts Blob to data URL from FileReader.\n * @private\n * @param {Blob} blob - The target Blob object.\n * @returns {Promise<string|null>} A promise resolving to the data URL, or null.\n */\nconst convertFromFileReader = blob =>\n new Promise((resolve, reject) => {\n const reader = new globalThis.FileReader();\n reader.addEventListener('error', () => reject(reader.error));\n reader.addEventListener('abort', () => resolve(null));\n reader.addEventListener('load', () => resolve(reader.result));\n reader.readAsDataURL(blob);\n });\n\n/**\n * Converts Blob to data URL from btoa.\n * @private\n * @param {Blob} blob - The target Blob object.\n * @returns {Promise<string|null>} A promise resolving to the data URL, or null.\n */\nconst convertFromBtoa = async blob => {\n const mimeStr = blob.type ? `${blob.type};base64` : 'base64';\n const buffer = await blob.arrayBuffer();\n const uint8arr = new Uint8Array(buffer);\n const chunks = [];\n for (let i = 0; i < uint8arr.length; i += CHUNK_SIZE) {\n chunks.push(String.fromCharCode(...uint8arr.subarray(i, i + CHUNK_SIZE)));\n }\n return `data:${mimeStr},${btoa(chunks.join(''))}`;\n};\n\n/**\n * Converts a Blob to a data URL.\n * @param {Blob} blob - The target Blob object.\n * @param {number} [maxSize] - The maximum allowed blob size.\n * @returns {Promise<string|null>} A promise resolving to the data URL, or null.\n */\nexport const convertBlobToDataURL = async (blob, maxSize = MAX_BLOB_SIZE) => {\n if (!Number.isInteger(blob?.size)) {\n return null;\n } else if (Number.isInteger(maxSize) && blob.size > maxSize) {\n const msg = `Blob size (${blob.size} bytes) exceeds max (${maxSize} bytes).`;\n throw new DOMException(msg, 'NotReadableError');\n }\n if (IS_NODE && globalThis.Buffer) {\n return convertFromBuffer(blob);\n } else if (globalThis.FileReader) {\n return convertFromFileReader(blob);\n }\n return convertFromBtoa(blob);\n};\n", "/**\n * sanitizer.js\n */\n\n/* shared */\nimport { domPurify } from './dompurify.js';\nimport { getType, isString } from './common.js';\nimport {\n URISchemes,\n convertBlobToDataURL,\n escapeURLEncodedHTMLChars,\n parseBase64,\n parseURLEncodedNumCharRef,\n trimTrailingEmptyQueryAndHash\n} from './uri-util.js';\n\n/* constants */\nimport { MAX_BLOB_SIZE, MAX_NEST } from './constant.js';\nimport {\n REG_AMP_ENC,\n REG_MIME_DOM,\n REG_SCHEME,\n REG_SCRIPT,\n REG_SCRIPT_BLOB,\n REG_TAG_QUOT,\n REG_VERIFY_RELATIVE\n} from './regexp.js';\nconst URL_PROPS = Object.freeze([\n 'href',\n 'origin',\n 'protocol',\n 'username',\n 'password',\n 'host',\n 'hostname',\n 'port',\n 'pathname',\n 'search',\n 'hash'\n]);\nconst INTERNAL_PURIFY_CONFIG = Object.freeze({\n RETURN_DOM: false,\n RETURN_DOM_FRAGMENT: false,\n RETURN_TRUSTED_TYPE: false\n});\n\n/* typedef */\n/**\n * The parsed result of a data URL.\n * @typedef {object} InspectedDataURL\n * @property {string} mime - The MIME type of the data.\n * @property {boolean} base64 - Indicates whether the data is base64-encoded.\n * @property {string} data - The actual data part of the data URL.\n */\n\n/**\n * The result of an inspected URL, extending the standard URL API.\n * The properties except for input and valid are omitted for invalid URLs.\n * @typedef {object} InspectedURLResult\n * @property {string} input - The original URL input.\n * @property {boolean} valid - Indicates whether the URI is valid.\n * @property {string} [reason] - The reason why the URL is invalid.\n * @property {InspectedDataURL | null} [data] - The parsed result of a data URL. Null if not a data URL.\n * @property {string} [href] - The sanitized URL input.\n * @property {string} [origin] - The scheme, domain, and port.\n * @property {string} [protocol] - The protocol scheme.\n * @property {string} [username] - The specified username.\n * @property {string} [password] - The specified password.\n * @property {string} [host] - The domain and port.\n * @property {string} [hostname] - The domain.\n * @property {string} [port] - The port number.\n * @property {string} [pathname] - The path.\n * @property {string} [search] - The query string.\n * @property {string} [hash] - The fragment identifier.\n */\n\n/**\n * Internal debug logger.\n * @param {boolean} isDebug - Flag to enable or disable debug output.\n * @param {string} message - The message to output.\n * @param {Error} [error] - The caught error object, if any.\n * @returns {void}\n */\nexport const logDebug = (isDebug, message, error) => {\n if (isDebug) {\n console.warn(`[URLSanitizer Debug] ${message}`, error);\n }\n};\n\n/**\n * URL sanitizer\n */\nclass URLSanitizer extends URISchemes {\n /* private fields */\n #allowedSchemes;\n\n /**\n * NOTE: Global Context Pattern for DOMPurify Hooks\n * - DOMPurify hooks (e.g., 'uponSanitizeAttribute') are registered globally\n * and do not accept custom arguments (like `this` or `ctx`).\n * To pass the current sanitization context into the hook, we temporarily\n * store it in static fields (#currentInstance and #currentCtx).\n * - This is entirely safe and immune to race conditions because JavaScript\n * runs on a single thread and DOMPurify's sanitize() is synchronous.\n * The context is safely restored via try/finally block in #purify() even\n * during recursive calls.\n */\n /** @type {URLSanitizer | null} */\n static #currentInstance = null;\n static #currentCtx = null;\n\n /**\n * DOMPurify 'uponSanitizeAttribute' hook callback.\n * @private\n * @static\n * @param {Node} node - The DOM node being sanitized.\n * @param {object} evt - The event object containing attribute details.\n */\n static #uponSanitizeAttribute(node, evt) {\n if (!evt.attrValue || !/^\\s*data:/i.test(evt.attrValue)) {\n return;\n }\n /** @type {URLSanitizer | null} */\n const sanitizer = URLSanitizer.#currentInstance;\n const ctx = URLSanitizer.#currentCtx;\n if (!sanitizer || !ctx) {\n return;\n }\n const urlObj = URL.parse(evt.attrValue);\n if (!urlObj) {\n return;\n }\n if (urlObj.protocol === 'data:') {\n const originalUrl = evt.attrValue;\n if (!ctx.recurse) {\n ctx.recurse = new Set();\n }\n if (ctx.recurse.has(originalUrl)) {\n const msg = `Circular Data URL detected and skipped: ${originalUrl}`;\n logDebug(ctx.debug, msg);\n evt.attrValue = '';\n return;\n }\n ctx.nest++;\n ctx.recurse.add(originalUrl);\n try {\n const sanitized = sanitizer.#process(\n originalUrl,\n {\n allow: ['data'],\n deny: [],\n only: [],\n allowRelative: false\n },\n ctx\n );\n evt.attrValue = sanitized || '';\n } finally {\n ctx.nest--;\n ctx.recurse.delete(originalUrl);\n }\n }\n }\n\n static {\n domPurify.setConfig(INTERNAL_PURIFY_CONFIG);\n domPurify.addHook(\n 'uponSanitizeAttribute',\n URLSanitizer.#uponSanitizeAttribute\n );\n }\n\n constructor() {\n super();\n this.#allowedSchemes = new Set(super.get());\n }\n\n /**\n * Helper method to register schemes for the 'allow' or 'only' options.\n * @private\n * @param {string} item - The scheme to register.\n * @param {string} listName - The name of the target option list.\n * @param {Set<string>} allowedSchemes - The local set of allowed schemes.\n * @param {Map<string, boolean>} schemeMap - The local map of schemes.\n * @param {object} ctx - The context for state management.\n * @returns {boolean} True if the scheme is successfully registered.\n */\n #registerScheme(item, listName, allowedSchemes, schemeMap, ctx) {\n if (REG_SCRIPT_BLOB.test(item)) {\n return false;\n }\n const schemeParts = item.split('+');\n const isScript = schemeParts.some(s => REG_SCRIPT.test(s));\n if (isScript || !REG_SCHEME.test(item)) {\n const msg = `Failed to add scheme '${item}' in '${listName}' list.`;\n logDebug(ctx.debug, msg);\n return false;\n }\n schemeMap.set(item, true);\n allowedSchemes.add(item);\n return true;\n }\n\n /**\n * Purifies a URL-encoded DOM string to prevent XSS.\n * @private\n * @param {string} dom - The URL-encoded DOM string.\n * @param {object} ctx - The context for state management.\n * @returns {string} The purified DOM string.\n */\n #purify(dom, ctx) {\n let decodedDom = dom;\n try {\n decodedDom = decodeURIComponent(dom);\n } catch {\n // fall through\n }\n const prevInstance = URLSanitizer.#currentInstance;\n const prevCtx = URLSanitizer.#currentCtx;\n URLSanitizer.#currentInstance = this;\n URLSanitizer.#currentCtx = ctx;\n let purifiedDom;\n try {\n purifiedDom = ctx.domPurify.sanitize(decodedDom);\n } finally {\n URLSanitizer.#currentInstance = prevInstance;\n URLSanitizer.#currentCtx = prevCtx;\n }\n purifiedDom = trimTrailingEmptyQueryAndHash(purifiedDom);\n try {\n return encodeURI(purifiedDom);\n } catch {\n return purifiedDom;\n }\n }\n\n /**\n * Internal recursive method for sanitization.\n * @private\n * @param {string} url - The URL string to sanitize.\n * @param {object} rules - Normalized sanitization rules.\n * @param {object} ctx - Internal context for state.\n * @returns {string|null} The sanitized URL, or null.\n */\n #process(url, rules, ctx) {\n if (ctx.nest > MAX_NEST) {\n throw new Error('Data URLs nested too deeply.');\n }\n // Resolve allowed/denied schemes\n const { allowedSchemes, restrictScheme, schemeMap } =\n this.#resolveSchemeRules(rules, ctx);\n // Parse and verify the URL\n const {\n isDataUrl,\n isRelative,\n isVerified,\n scheme,\n schemeParts,\n urlObj,\n urlToSanitize\n } = this.#parseAndVerifyURL(url, rules.allowRelative, allowedSchemes, ctx);\n if (!isVerified) {\n return null;\n }\n // Check if the scheme is allowed\n if (\n !this.#isSchemeAllowed(\n scheme,\n schemeParts,\n restrictScheme,\n schemeMap,\n isRelative\n )\n ) {\n return null;\n }\n // Sanitize based on URL type\n if (isDataUrl) {\n return this.#sanitizeDataURL(urlObj, scheme, ctx);\n }\n return this.#sanitizeStandardURL(urlToSanitize);\n }\n\n /**\n * Resolves allow, deny, and only rules into mappings.\n * @private\n * @param {object} rules - The sanitization rules.\n * @param {string[]} rules.allow - Allowed schemes.\n * @param {string[]} rules.deny - Denied schemes.\n * @param {string[]} rules.only - Exclusively allowed schemes.\n * @param {object} ctx - Context for state management.\n * @returns {object} Resolved scheme objects and flags.\n */\n #resolveSchemeRules({ allow, deny, only }, ctx) {\n let allowedSchemes = this.#allowedSchemes;\n let restrictScheme = false;\n const schemeMap = new Map(ctx.schemeMap);\n if (only.length) {\n allowedSchemes = new Set();\n for (const item of only) {\n if (isString(item)) {\n const registered = this.#registerScheme(\n item.trim(),\n 'only',\n allowedSchemes,\n schemeMap,\n ctx\n );\n if (registered && !restrictScheme) {\n restrictScheme = true;\n }\n }\n }\n } else {\n if (allow.length) {\n allowedSchemes = new Set(this.#allowedSchemes);\n for (const item of allow) {\n if (isString(item)) {\n this.#registerScheme(\n item.trim(),\n 'allow',\n allowedSchemes,\n schemeMap,\n ctx\n );\n }\n }\n }\n if (deny.length) {\n for (let item of deny) {\n if (isString(item)) {\n item = item.trim();\n if (item) {\n schemeMap.set(item, false);\n }\n }\n }\n }\n }\n return { allowedSchemes, restrictScheme, schemeMap };\n }\n\n /**\n * Parses and verifies absolute and relative URLs.\n * @private\n * @param {string} url - The URL to parse.\n * @param {boolean} allowRelative - If relative URLs are OK.\n * @param {Set<string>} allowedSchemes - Permitted schemes.\n * @param {object} ctx - Context for logging and state.\n * @returns {object} Parsed URL properties and flags.\n */\n #parseAndVerifyURL(url, allowRelative, allowedSchemes, ctx) {\n let isVerified = super.verify(url, allowedSchemes);\n let isRelative = false;\n let relativeParsedPath = '';\n // Handle Relative URLs\n if (!isVerified && allowRelative && !REG_VERIFY_RELATIVE.test(url)) {\n const normUrl = url.normalize('NFKC');\n const dummyUrl = URL.parse(url, 'http://dummy.local');\n const dummyUrlNormalized = URL.parse(normUrl, 'http://dummy.local');\n if (dummyUrl && dummyUrlNormalized) {\n if (\n dummyUrl.protocol === 'http:' &&\n dummyUrl.hostname === 'dummy.local' &&\n dummyUrlNormalized.protocol === 'http:'\n ) {\n isVerified = true;\n isRelative = true;\n relativeParsedPath = `${dummyUrl.pathname}${dummyUrl.search}${dummyUrl.hash}`;\n }\n } else {\n logDebug(ctx.debug, 'Failed to parse relative URL.');\n }\n }\n if (!isVerified) {\n return { isVerified: false };\n }\n // Extract parts if verified\n if (isRelative) {\n return {\n isRelative,\n isVerified,\n isDataUrl: false,\n scheme: '',\n schemeParts: [],\n urlToSanitize: relativeParsedPath\n };\n }\n const urlObj = URL.parse(url);\n const scheme = urlObj.protocol.replace(/:$/, '').normalize('NFKC');\n const schemeParts = scheme.split('+');\n return {\n isRelative,\n isVerified,\n scheme,\n schemeParts,\n urlObj,\n isDataUrl: schemeParts.includes('data'),\n urlToSanitize: urlObj.href\n };\n }\n\n /**\n * Evaluates if the extracted scheme is permitted.\n * @private\n * @param {string} scheme - The normalized URL scheme.\n * @param {string[]} schemeParts - Parts of the split scheme.\n * @param {boolean} restrictScheme - If rules strictly limit.\n * @param {Map<string, boolean>} schemeMap - Scheme rules map.\n * @param {boolean} isRelative - If the URL is relative.\n * @returns {boolean} True if the scheme is allowed.\n */\n #isSchemeAllowed(scheme, schemeParts, restrictScheme, schemeMap, isRelative) {\n if (isRelative) {\n return true;\n }\n if (restrictScheme) {\n return schemeParts.every(s => schemeMap.get(s));\n }\n for (const [key, value] of schemeMap.entries()) {\n const bool =\n value || (scheme !== key && schemeParts.every(s => s !== key));\n if (!bool) {\n return false;\n }\n }\n return true;\n }\n\n /**\n * Decodes, verifies inner protocols, and purifies data URLs.\n * @private\n * @param {object} urlObj - The URL object.\n * @param {string} scheme - The URL scheme.\n * @param {object} ctx - Context for DOMPurify sanitization.\n * @returns {string|null} Sanitized data URL or null.\n */\n #sanitizeDataURL(urlObj, scheme, ctx) {\n const [mediaType, ...dataParts] = urlObj.pathname.split(',');\n const data = `${dataParts.join(',')}${urlObj.search}${urlObj.hash}`;\n const mediaTypes = mediaType.split(';');\n const isBase64 = mediaTypes[mediaTypes.length - 1] === 'base64';\n let parsedData = data;\n if (isBase64) {\n try {\n parsedData = parseBase64(data);\n } catch (e) {\n logDebug(ctx.debug, 'Failed to parse base64 data.', e);\n return null;\n }\n }\n try {\n const decodedData = parseURLEncodedNumCharRef(parsedData).trim();\n const normalizedData = decodedData.normalize('NFKC');\n const dummy = 'http://dummy.local';\n const parsedUrl = URL.parse(normalizedData, dummy);\n if (!parsedUrl) {\n logDebug(ctx.debug, 'Failed to parse inner data URL protocol.');\n return null;\n }\n const dataScheme = parsedUrl.protocol;\n const dataSchemeParts = dataScheme.replace(/:$/, '').split('+');\n if (dataSchemeParts.some(s => REG_SCRIPT_BLOB.test(s))) {\n return null;\n }\n } catch (e) {\n logDebug(ctx.debug, 'Failed to parse inner data URL protocol.', e);\n return null;\n }\n if (!mediaType || REG_MIME_DOM.test(mediaType)) {\n parsedData = this.#purify(parsedData, ctx);\n }\n if (parsedData) {\n if (isBase64 && parsedData !== data) {\n mediaTypes.pop();\n }\n return `${scheme}:${mediaTypes.join(';')},${parsedData}`;\n }\n return null;\n }\n\n /**\n * Applies regex cleanups to standard non-data URLs.\n * Strips out trailing queries or problematic characters.\n * @private\n * @param {string} urlToSanitize - The absolute/relative URL.\n * @returns {string|null} Cleaned URL string or null.\n */\n #sanitizeStandardURL(urlToSanitize) {\n let sanitized = urlToSanitize;\n if (REG_TAG_QUOT.test(sanitized)) {\n const { index } = REG_TAG_QUOT.exec(sanitized);\n sanitized = sanitized.substring(0, index).replace(/[?&]$/, '');\n }\n if (REG_AMP_ENC.test(sanitized)) {\n const { index } = REG_AMP_ENC.exec(sanitized);\n sanitized = sanitized.substring(0, index).replace(/[?&]$/, '');\n }\n return sanitized;\n }\n\n /**\n * Sanitizes the given URL.\n * @param {string} url - The URL string to sanitize.\n * @param {object} [opt] - Sanitization options.\n * @param {string[]} [opt.allow] - An array of schemes to allow.\n * @param {string[]} [opt.deny] - An array of schemes to deny.\n * @param {string[]} [opt.only] - An array of specific schemes to allow.\n * @param {boolean} [opt.allowRelative] - Flag to safely allow relative URLs.\n * @param {boolean} [opt.debug] - Flag to enable debug mode.\n * @param {number} [opt.maxBlobSize] - The maximum allowed blob size in bytes.\n * @param {number} [opt.maxLength] - The maximum allowed URL length.\n * @returns {string|null} The sanitized URL, or null.\n */\n sanitize(url, opt) {\n if (!url || !isString(url)) {\n return null;\n }\n const maxLength =\n Number.isInteger(opt?.maxLength) && opt.maxLength ? opt.maxLength : 0;\n if (maxLength && url.length > maxLength) {\n const msg = `URL length ${url.length} exceeds maxLength ${maxLength}.`;\n throw new RangeError(msg);\n }\n const hasRestrictiveRules =\n opt &&\n ((Array.isArray(opt.deny) && opt.deny.length > 0) ||\n (Array.isArray(opt.only) && opt.only.length > 0) ||\n opt.allowRelative);\n if (\n !hasRestrictiveRules &&\n (url.startsWith('https://') || url.startsWith('http://')) &&\n !REG_TAG_QUOT.test(url) &&\n !url.includes('data:')\n ) {\n const parsedUrl = URL.parse(url);\n if (parsedUrl) {\n return parsedUrl.href.replace(/%26/g, escapeURLEncodedHTMLChars);\n } else {\n logDebug(opt?.debug, `Failed to parse URL.`);\n return null;\n }\n }\n const rules = {\n allow: Array.isArray(opt?.allow) ? opt.allow : [],\n deny: Array.isArray(opt?.deny) ? opt.deny : [],\n only: Array.isArray(opt?.only) ? opt.only : [],\n allowRelative: !!opt?.allowRelative\n };\n const ctx = {\n debug: !!opt?.debug,\n domPurify,\n nest: 0,\n recurse: null,\n schemeMap: new Map([\n ['blob', false],\n ['data', false],\n ['file', false],\n ['javascript', false],\n ['vbscript', false]\n ])\n };\n return this.#process(url, rules, ctx);\n }\n\n /**\n * Inspects, parses, and sanitizes the given URL.\n * NOTE: blob URLs are simply parsed, but neither decoded nor sanitized.\n * @param {string} url - The URL string to parse.\n * @param {object} [opt] - Sanitization options.\n * @returns {InspectedURLResult} The result of an inspected URL.\n */\n inspect(url, opt) {\n if (!isString(url)) {\n throw new TypeError(`Expected String but got ${getType(url)}.`);\n }\n const inspectedURL = {\n input: url,\n valid: false\n };\n let sanitizedUrl;\n let invalidReason = null;\n const maxLength =\n Number.isInteger(opt?.maxLength) && opt.maxLength ? opt.maxLength : 0;\n const urlLength = url.length;\n if (maxLength && urlLength > maxLength) {\n invalidReason = `URL length ${urlLength} exceeds maxLength ${maxLength}.`;\n } else if (this.verify(url)) {\n const { protocol } = new URL(url);\n if (protocol === 'blob:') {\n sanitizedUrl = url;\n } else {\n try {\n sanitizedUrl = this.sanitize(url, opt ?? { allow: ['data'] });\n if (!sanitizedUrl) {\n invalidReason =\n 'Sanitization failed (blocked by allowed schemes or rules).';\n }\n } catch (e) {\n invalidReason = e.message;\n }\n }\n } else {\n invalidReason = 'Invalid URI syntax or scheme is not registered.';\n }\n if (sanitizedUrl) {\n const urlObj = new URL(sanitizedUrl);\n const { pathname, protocol } = urlObj;\n const schemeParts = protocol.replace(/:$/, '').split('+');\n const isDataUrl = schemeParts.includes('data');\n inspectedURL.valid = true;\n if (isDataUrl) {\n const [mediaType, ...dataParts] = pathname.split(',');\n const data = `${dataParts.join(',')}${urlObj.search}${urlObj.hash}`;\n const mediaTypes = mediaType.split(';');\n const isBase64 = mediaTypes[mediaTypes.length - 1] === 'base64';\n if (isBase64) {\n mediaTypes.pop();\n }\n inspectedURL.data = {\n mime: mediaTypes.join(';'),\n base64: isBase64,\n data\n };\n } else {\n inspectedURL.data = null;\n }\n for (const key of URL_PROPS) {\n const value = urlObj[key];\n if (isString(value)) {\n inspectedURL[key] = value;\n }\n }\n } else {\n inspectedURL.valid = false;\n if (invalidReason) {\n inspectedURL.reason = invalidReason;\n }\n }\n return inspectedURL;\n }\n\n /**\n * Gets the list of registered URI schemes.\n * @returns {string[]} An array of registered schemes.\n */\n get() {\n return [...this.#allowedSchemes];\n }\n\n /**\n * Checks if the specified scheme is currently registered.\n * @param {string} scheme - The target scheme.\n * @returns {boolean} True if the scheme is registered.\n */\n has(scheme) {\n return this.#allowedSchemes.has(scheme);\n }\n\n /**\n * Adds a new scheme to the allowed list.\n * @param {string} scheme - The scheme to add.\n * @returns {string[]} The updated array of registered schemes.\n */\n add(scheme) {\n if (isString(scheme)) {\n scheme = scheme.trim();\n } else {\n throw new TypeError(`Expected String but got ${getType(scheme)}.`);\n }\n const schemeParts = scheme.split('+');\n const isScript = schemeParts.some(s => REG_SCRIPT.test(s));\n if (isScript || !REG_SCHEME.test(scheme)) {\n throw new Error(`Invalid scheme: ${scheme}`);\n }\n this.#allowedSchemes.add(scheme);\n return [...this.#allowedSchemes];\n }\n\n /**\n * Removes a scheme from the allowed list.\n * @param {string} scheme - The scheme to remove.\n * @returns {boolean} True if the scheme was successfully removed.\n */\n remove(scheme) {\n return this.#allowedSchemes.delete(scheme);\n }\n\n /**\n * Resets the registered schemes back to the default initial list.\n * @returns {void}\n */\n reset() {\n this.#allowedSchemes = new Set(super.get());\n }\n\n /**\n * Verifies if the given URI is valid and its scheme is allowed.\n * @param {string} uri - The URI string to verify.\n * @param {Set<string>} [schemes] - The set of allowed schemes.\n * @returns {boolean} True if the URI is syntactically valid and permitted.\n */\n verify(uri, schemes = this.#allowedSchemes) {\n return super.verify(uri, schemes);\n }\n}\nexport { URLSanitizer };\n\n/* instance */\nconst urlSanitizer = new URLSanitizer();\n\n/**\n * Asynchronously sanitizes the given URL.\n * NOTE: `blob`, `data`, and `file` schemes must be explicitly allowed.\n * Given a `blob` URL, it securely converts and returns a sanitized `data` URL.\n * @param {string} url - URL\n * @param {object} [opt] - options\n * @param {string[]} [opt.allow] - The array of schemes to allow.\n * @param {string[]} [opt.deny] - The array of schemes to deny.\n * @param {string[]} [opt.only] - The array of specific schemes to allow.\n * @param {boolean} [opt.allowRelative] - Allow relative URLs.\n * @param {boolean} [opt.debug] - Enable debug mode.\n * @param {boolean} [opt.revokeObjectURL] - Revokes the blob URL after sanitization.\n * @param {number} [opt.maxBlobSize] - The maximum allowed blob size in bytes.\n * @param {number} [opt.maxLength] - The maximum allowed URL length\n * @returns {Promise<string|null>} A promise resolving to the sanitized URL, or null.\n */\nexport const sanitizeURL = async (\n url,\n opt = {\n allow: [],\n deny: [],\n only: [],\n allowRelative: false,\n debug: false,\n revokeObjectURL: false,\n maxBlobSize: MAX_BLOB_SIZE\n }\n) => {\n const isDebug = !!opt?.debug;\n const maxBlobSize =\n Number.isInteger(opt?.maxBlobSize) && opt.maxBlobSize > 0\n ? opt.maxBlobSize\n : MAX_BLOB_SIZE;\n let res;\n if (url && isString(url)) {\n let scheme;\n const parsedUrl = URL.parse(url);\n if (parsedUrl) {\n scheme = parsedUrl.protocol.replace(/:$/, '');\n } else {\n logDebug(isDebug, `Invalid URL input format: ${url}`);\n }\n if (scheme === 'blob') {\n const { allow, deny, only } = opt;\n if (\n (Array.isArray(allow) &&\n allow.includes('blob') &&\n !(Array.isArray(deny) && deny.includes('blob'))) ||\n (Array.isArray(only) && only.includes('blob'))\n ) {\n let data;\n try {\n data = await fetch(url)\n .then(r => r.blob())\n .then(b => convertBlobToDataURL(b, maxBlobSize));\n } catch (e) {\n const msg = `Failed to fetch and convert blob URL: ${url}`;\n logDebug(isDebug, msg, e);\n }\n if (data) {\n const options = { ...opt };\n if (Array.isArray(opt.only)) {\n options.only = opt.only.includes('data')\n ? opt.only\n : [...opt.only, 'data'];\n } else if (Array.isArray(opt.allow)) {\n options.allow = opt.allow.includes('data')\n ? opt.allow\n : [...opt.allow, 'data'];\n if (Array.isArray(opt.deny)) {\n options.deny = opt.deny.filter(scheme => scheme !== 'data');\n }\n }\n res = urlSanitizer.sanitize(data, options);\n }\n }\n if (opt?.revokeObjectURL) {\n URL.revokeObjectURL(url);\n }\n } else if (scheme || opt.allowRelative) {\n res = urlSanitizer.sanitize(url, opt);\n }\n }\n return res || null;\n};\n\n/**\n * Synchronously sanitizes the given URL.\n * NOTE: `data` and `file` schemes must be explicitly allowed.\n * The `blob` scheme is not supported and will return `null`.\n * @param {string} url - URL\n * @param {object} [opt] - options\n * @param {string[]} [opt.allow] - The array of schemes to allow.\n * @param {string[]} [opt.deny] - The array of schemes to deny.\n * @param {string[]} [opt.only] - The array of specific schemes to allow.\n * @param {boolean} [opt.allowRelative] - Allow relative URLs.\n * @param {boolean} [opt.debug] - Enable debug mode.\n * @param {boolean} [opt.revokeObjectURL] - Revokes the blob URL.\n * @param {number} [opt.maxLength] - The maximum allowed URL length.\n * @returns {string|null} The sanitized URL, or null if denied.\n */\nexport const sanitizeURLSync = (\n url,\n opt = {\n allow: [],\n deny: [],\n only: [],\n allowRelative: false,\n debug: false,\n revokeObjectURL: false\n }\n) => {\n const isDebug = !!opt?.debug;\n let res;\n if (url && isString(url)) {\n let scheme;\n const parsedUrl = URL.parse(url);\n if (parsedUrl) {\n scheme = parsedUrl.protocol.replace(/:$/, '');\n } else {\n logDebug(isDebug, `Invalid URL input format: ${url}`);\n }\n if (scheme === 'blob') {\n if (opt?.revokeObjectURL) {\n URL.revokeObjectURL(url);\n }\n return null;\n } else if (scheme || opt.allowRelative) {\n res = urlSanitizer.sanitize(url, opt);\n }\n }\n return res || null;\n};\n\n/**\n * Inspects, parses, and sanitizes the given URL asynchronously.\n * @param {string} url - The URL string to inspect.\n * @returns {Promise<InspectedURLResult>} A promise resolving to the inspected URL result.\n */\nexport const inspectURL = async url => {\n const res = urlSanitizer.inspect(url);\n return res;\n};\n\n/**\n * @deprecated Use {@link inspectURL} instead.\n * @param {string} url - The URL string to inspect.\n * @returns {Promise<InspectedURLResult>} A promise resolving to the inspected URL result.\n */\nexport const parseURL = async url => inspectURL(url);\n\n/**\n * Inspects, parses, and sanitizes the given URL synchronously.\n * @param {string} url - The URL string to inspect.\n * @returns {InspectedURLResult} The inspected URL result.\n */\nexport const inspectURLSync = url => urlSanitizer.inspect(url);\n\n/**\n * @deprecated Use {@link inspectURLSync} instead.\n * @param {string} url - The URL string to inspect.\n * @returns {InspectedURLResult} The inspected URL result.\n */\nexport const parseURLSync = url => inspectURLSync(url);\n\n/**\n * Asynchronously checks if the given string is a valid URI and is registered.\n * @param {string} uri - The URI string to verify.\n * @returns {Promise<boolean>} True if valid and registered, false otherwise.\n */\nexport const isURI = async uri => {\n const res = urlSanitizer.verify(uri);\n return res;\n};\n\n/**\n * Synchronously checks if the given string is a valid URI and is registered.\n * @param {string} uri - The URI string to verify.\n * @returns {boolean} True if valid and registered, false otherwise.\n */\nexport const isURISync = uri => urlSanitizer.verify(uri);\n\n/* export instance */\nexport default urlSanitizer;\n"],
5
- "mappings": "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",
6
- "names": ["PROPERTIES", "hookQueue", "domPurify", "target", "prop", "purifier", "p", "args", "value", "getType", "o", "isString", "uri_schemes_default", "REG_HASH", "REG_MIME_DOM", "REG_NUM_REF", "REG_QUERY", "REG_SCHEME", "REG_SCHEME_EXT", "REG_SCRIPT", "REG_SCRIPT_BLOB", "REG_TAG_QUOT", "REG_URL_ENC", "REG_AMP_ENC", "REG_PCT_ENC", "REG_VERIFY_RELATIVE", "text_chars_default", "TEXT_CHAR_CODES", "text_chars_default", "WINDOWS1252_TO_UNICODE", "generateCtrlCharCodes", "charCodes", "i", "CTRL_CHAR_CODES", "ENC_AMP", "ENC_NUM", "ENC_LT", "ENC_GT", "ENC_QUOT", "ENC_APOS", "ch", "ESCAPE_MAP", "HEX_TABLE", "_", "i", "IS_NODE", "REG_BINARY", "CTRL_CHAR_CODES", "REG_CTRL_CHARS", "encoder", "decoder", "URISchemes", "#schemes", "uri_schemes_default", "scheme", "uri", "schemes", "isString", "normalizedUri", "parsedUrl", "parts", "s", "REG_SCRIPT", "REG_SCHEME_EXT", "escapeURLEncodedHTMLChars", "ch", "isString", "target", "REG_URL_ENC", "ESCAPE_MAP", "parseBase64", "data", "getType", "cleanData", "binStr", "bytes", "IS_NODE", "len", "i", "text", "decoder", "REG_BINARY", "replaceNumCharRef", "match", "value", "num", "TEXT_CHAR_CODES", "WINDOWS1252_TO_UNICODE", "codePoint", "CTRL_CHAR_CODES", "trimTrailingEmptyQueryAndHash", "url", "REG_HASH", "REG_QUERY", "parseURLEncodedNumCharRef", "str", "nest", "res", "REG_PCT_ENC", "REG_CTRL_CHARS", "depth", "previousRes", "REG_NUM_REF", "convertFromBuffer", "blob", "mimeStr", "buffer", "base64", "convertFromFileReader", "resolve", "reject", "reader", "convertFromBtoa", "uint8arr", "chunks", "convertBlobToDataURL", "maxSize", "msg", "URL_PROPS", "INTERNAL_PURIFY_CONFIG", "logDebug", "isDebug", "message", "error", "URLSanitizer", "_URLSanitizer", "URISchemes", "#allowedSchemes", "#currentInstance", "#currentCtx", "#uponSanitizeAttribute", "node", "evt", "sanitizer", "ctx", "urlObj", "originalUrl", "msg", "sanitized", "#process", "domPurify", "#registerScheme", "item", "listName", "allowedSchemes", "schemeMap", "REG_SCRIPT_BLOB", "s", "REG_SCRIPT", "REG_SCHEME", "#purify", "dom", "decodedDom", "prevInstance", "prevCtx", "purifiedDom", "trimTrailingEmptyQueryAndHash", "url", "rules", "restrictScheme", "#resolveSchemeRules", "isDataUrl", "isRelative", "isVerified", "scheme", "schemeParts", "urlToSanitize", "#parseAndVerifyURL", "#isSchemeAllowed", "#sanitizeDataURL", "#sanitizeStandardURL", "allow", "deny", "only", "isString", "allowRelative", "relativeParsedPath", "REG_VERIFY_RELATIVE", "normUrl", "dummyUrl", "dummyUrlNormalized", "key", "value", "mediaType", "dataParts", "data", "mediaTypes", "isBase64", "parsedData", "parseBase64", "e", "normalizedData", "parseURLEncodedNumCharRef", "parsedUrl", "REG_MIME_DOM", "REG_TAG_QUOT", "index", "REG_AMP_ENC", "opt", "maxLength", "escapeURLEncodedHTMLChars", "getType", "inspectedURL", "sanitizedUrl", "invalidReason", "urlLength", "protocol", "pathname", "uri", "schemes", "urlSanitizer", "URLSanitizer", "sanitizeURL", "url", "opt", "isDebug", "maxBlobSize", "res", "isString", "scheme", "parsedUrl", "logDebug", "allow", "deny", "only", "data", "r", "b", "convertBlobToDataURL", "e", "msg", "options", "sanitizeURLSync", "inspectURL", "parseURL", "inspectURLSync", "parseURLSync", "isURI", "uri", "isURISync", "sanitizer_default"]
4
+ "sourcesContent": ["/**\n * dompurify.js (for wo-dompurify build)\n */\n\n/* constants */\nconst PROPERTIES = Object.freeze([\n 'addHook',\n 'removeHook',\n 'removeAllHooks',\n 'setConfig'\n]);\n\nconst hookQueue = [];\nexport const domPurify = new Proxy({}, {\n get(target, prop) {\n const purifier = globalThis.DOMPurify || globalThis.window?.DOMPurify;\n if (purifier) {\n if (hookQueue.length) {\n for (const { prop: p, args } of hookQueue) {\n if (typeof purifier[p] === 'function') {\n purifier[p](...args);\n }\n }\n hookQueue.length = 0;\n }\n const value = purifier[prop];\n return typeof value === 'function' ? value.bind(purifier) : value;\n }\n return (...args) => {\n if (PROPERTIES.includes(prop)) {\n hookQueue.push({ prop, args });\n return target;\n }\n throw new Error('DOMPurify is not available. Ensure DOMPurify is exposed globally (e.g., window.DOMPurify).');\n };\n }\n});\n", "/**\n * common.js\n */\n\n/* shared */\nimport { TYPE_FROM, TYPE_TO } from './constant.js';\n\n/**\n * Gets the type of the given object.\n * Returns the object class name (e.g., \"String\", \"Array\", \"Null\", \"Undefined\").\n * @param {unknown} o - The object to check.\n * @returns {string} The specific type of the object.\n */\nexport const getType = o =>\n Object.prototype.toString.call(o).slice(TYPE_FROM, TYPE_TO);\n\n/**\n * Checks if the given value is a string.\n * @param {unknown} o - The value to check.\n * @returns {boolean} True if the value is a string, false otherwise.\n */\nexport const isString = o => typeof o === 'string' || o instanceof String;\n", "[\"aaa\",\"aaas\",\"about\",\"acap\",\"acct\",\"acd\",\"acr\",\"adiumxtra\",\"adt\",\"afp\",\"afs\",\"agtp\",\"aim\",\"amss\",\"android\",\"appdata\",\"apt\",\"ar\",\"ari\",\"ark\",\"at\",\"attachment\",\"aw\",\"barion\",\"beshare\",\"bitcoin\",\"bitcoincash\",\"bl\",\"blob\",\"bluetooth\",\"bolo\",\"brid\",\"browserext\",\"cabal\",\"caip\",\"calculator\",\"callto\",\"cap\",\"cast\",\"casts\",\"chrome\",\"chrome-extension\",\"cid\",\"coap\",\"coaps\",\"com-eventbrite-attendee\",\"content\",\"content-type\",\"crid\",\"cstr\",\"cttps\",\"cvs\",\"dab\",\"dat\",\"data\",\"dav\",\"dhttp\",\"diaspora\",\"dict\",\"did\",\"dilithium3\",\"dis\",\"dlna-playcontainer\",\"dlna-playsingle\",\"dnp\",\"dns\",\"dntp\",\"doi\",\"donau\",\"dpp\",\"drm\",\"dtmi\",\"dtn\",\"dvb\",\"dvx\",\"dweb\",\"ed2k\",\"eid\",\"elsi\",\"embedded\",\"ens\",\"esim\",\"ethereum\",\"example\",\"ez\",\"facetime\",\"feed\",\"feedready\",\"fido\",\"file\",\"finger\",\"first-run-pen-experience\",\"fish\",\"fm\",\"ftp\",\"fuchsia-pkg\",\"geo\",\"gg\",\"git\",\"gitoid\",\"gizmoproject\",\"go\",\"gopher\",\"graph\",\"gtalk\",\"h323\",\"ham\",\"hcap\",\"hcp\",\"hs20\",\"http\",\"https\",\"hxxp\",\"hxxps\",\"hydrazone\",\"hyper\",\"i0\",\"iax\",\"ibi\",\"ibi-\",\"icap\",\"icon\",\"ilstring\",\"im\",\"imap\",\"info\",\"iotdisco\",\"ipfs\",\"ipn\",\"ipns\",\"ipp\",\"ipps\",\"irc\",\"irc6\",\"ircs\",\"iris\",\"iris.beep\",\"iris.lwz\",\"iris.xpc\",\"iris.xpcs\",\"isostore\",\"itms\",\"jabber\",\"jar\",\"jms\",\"keyparc\",\"lastfm\",\"lbry\",\"ldap\",\"ldaps\",\"leaptofrogans\",\"lid\",\"linkid\",\"lorawan\",\"lpa\",\"lvlt\",\"machineProvisioningProgressReporter\",\"magnet\",\"mailto\",\"maps\",\"market\",\"matrix\",\"mdoc\",\"mdoc-openid4vp\",\"message\",\"microsoft.windows.camera\",\"microsoft.windows.camera.multipicker\",\"microsoft.windows.camera.picker\",\"mid\",\"mms\",\"mongodb\",\"moz\",\"moz-extension\",\"mqtt\",\"mqtts\",\"ms-access\",\"ms-appinstaller\",\"ms-browser-extension\",\"ms-calculator\",\"ms-drive-to\",\"ms-enrollment\",\"ms-excel\",\"ms-eyecontrolspeech\",\"ms-gamebarservices\",\"ms-gamingoverlay\",\"ms-getoffice\",\"ms-help\",\"ms-infopath\",\"ms-inputapp\",\"ms-launchremotedesktop\",\"ms-lockscreencomponent-config\",\"ms-media-stream-id\",\"ms-meetnow\",\"ms-mixedrealitycapture\",\"ms-mobileplans\",\"ms-newsandinterests\",\"ms-officeapp\",\"ms-people\",\"ms-personacard\",\"ms-powerpoint\",\"ms-project\",\"ms-publisher\",\"ms-recall\",\"ms-remotedesktop\",\"ms-remotedesktop-launch\",\"ms-restoretabcompanion\",\"ms-screenclip\",\"ms-screensketch\",\"ms-search\",\"ms-search-repair\",\"ms-secondary-screen-controller\",\"ms-secondary-screen-setup\",\"ms-settings\",\"ms-settings-airplanemode\",\"ms-settings-bluetooth\",\"ms-settings-camera\",\"ms-settings-cellular\",\"ms-settings-cloudstorage\",\"ms-settings-connectabledevices\",\"ms-settings-displays-topology\",\"ms-settings-emailandaccounts\",\"ms-settings-language\",\"ms-settings-location\",\"ms-settings-lock\",\"ms-settings-nfctransactions\",\"ms-settings-notifications\",\"ms-settings-power\",\"ms-settings-privacy\",\"ms-settings-proximity\",\"ms-settings-screenrotation\",\"ms-settings-wifi\",\"ms-settings-workplace\",\"ms-spd\",\"ms-stickers\",\"ms-sttoverlay\",\"ms-transit-to\",\"ms-useractivityset\",\"ms-uup\",\"ms-virtualtouchpad\",\"ms-visio\",\"ms-walk-to\",\"ms-whiteboard\",\"ms-whiteboard-cmd\",\"ms-widgetboard\",\"ms-widgets\",\"ms-word\",\"msnim\",\"msrp\",\"msrps\",\"mss\",\"mt\",\"mtqp\",\"mtrust\",\"mumble\",\"mupdate\",\"musik\",\"mvn\",\"mvrp\",\"mvrps\",\"news\",\"nfs\",\"ni\",\"nih\",\"nntp\",\"nostr\",\"notes\",\"npamp\",\"num\",\"ocf\",\"oid\",\"onenote\",\"onenote-cmd\",\"opaquelocktoken\",\"openid\",\"openpgp4fpr\",\"otpauth\",\"palm\",\"paparazzi\",\"payto\",\"pkcs11\",\"platform\",\"pop\",\"pres\",\"proxy\",\"psyc\",\"pttp\",\"pwid\",\"qb\",\"query\",\"quic-transport\",\"redis\",\"rediss\",\"reload\",\"res\",\"resource\",\"rmi\",\"rsync\",\"rtmfp\",\"rtmp\",\"rtsp\",\"rtsps\",\"rtspu\",\"sarif\",\"secondlife\",\"secret-token\",\"service\",\"session\",\"sftp\",\"sgn\",\"shc\",\"shelter\",\"sieve\",\"simpleledger\",\"simplex\",\"sip\",\"sips\",\"skype\",\"smb\",\"smp\",\"sms\",\"smtp\",\"snmp\",\"soap.beep\",\"soap.beeps\",\"soldat\",\"spacify\",\"spiffe\",\"spotify\",\"ssb\",\"ssh\",\"sss\",\"starknet\",\"steam\",\"stun\",\"stuns\",\"submit\",\"svn\",\"swh\",\"swid\",\"swidpath\",\"tag\",\"taler\",\"teamspeak\",\"teapot\",\"teapots\",\"tel\",\"teliaeid\",\"telnet\",\"tftp\",\"things\",\"thismessage\",\"tip\",\"tn3270\",\"tool\",\"tttps\",\"turn\",\"turns\",\"tv\",\"udp\",\"unreal\",\"upn\",\"urn\",\"ust\",\"ut2004\",\"uuaid\",\"uuid-in-package\",\"v-event\",\"vemmi\",\"ventrilo\",\"ves\",\"view-source\",\"vnc\",\"vscode\",\"vscode-insiders\",\"vsls\",\"w3\",\"wasm\",\"wasm-js\",\"wcr\",\"web3\",\"webcal\",\"wifi\",\"ws\",\"wss\",\"wtai\",\"wyciwyg\",\"xcompute\",\"xcon\",\"xcon-userid\",\"xfire\",\"xftp\",\"xmlrpc.beep\",\"xmlrpc.beeps\",\"xmpp\",\"xrcp\",\"xri\",\"ymsgr\",\"z39.50r\",\"z39.50s\",\"ztdnaid\"]\n", "/**\n * regexp.js\n */\n\n/**\n * Matches and captures the charset parameter in a media type string.\n * @type {RegExp}\n */\nexport const REG_CHARSET = /^charset\\s*=\\s*([\"']?)(?<name>[\\w:-]+)\\1$/;\n\n/**\n * Matches a trailing empty fragment identifier (#).\n * @type {RegExp}\n */\nexport const REG_HASH = /(?:#|%23)$/;\n\n/**\n * Matches MIME types that contain DOM-parsable content (HTML, XML, SVG).\n * @type {RegExp}\n */\nexport const REG_MIME_DOM =\n /^(?:application\\/(?:[\\w.-]+\\+)?xml|image\\/svg\\+xml|text\\/(?:html|xml))(?:\\s*;\\s*|$)/i;\n\n/**\n * Matches general text MIME types.\n * @type {RegExp}\n */\nexport const REG_MIME_TEXT = /^text\\/[\\w#&.;-]+/;\n\n/**\n * Matches numeric character reference.\n * @type {RegExp}\n */\nexport const REG_NUM_REF = /&#(x0*[\\dA-F]{1,2}|0*\\d{1,3});?/gi;\n\n/**\n * Matches a trailing empty query string (?), ensuring it is not part of a hash.\n * @type {RegExp}\n */\nexport const REG_QUERY = /^((?:[^#%]|%(?!23))*)(?:\\?|%3F)$/i;\n\n/**\n * Validates a string against standard IANA URI scheme syntax.\n * @type {RegExp}\n */\nexport const REG_SCHEME = /^[a-z][\\da-z+.-]*$/;\n\n/**\n * Matches web custom schemes (`web+`) or application-specific schemes (`ext+`).\n * - `web+` schemes comply with the HTML Standard.\n * - `ext+` schemes comply with RFC 3986 but disallow `+` in the suffix.\n * @type {RegExp}\n */\nexport const REG_SCHEME_EXT = /^(?:web\\+[a-z]+|ext\\+[a-z][\\da-z.-]*)$/;\n\n/**\n * Matches executable script schemes (javascript or vbscript).\n * @type {RegExp}\n */\nexport const REG_SCRIPT = /^(?:java|vb)script$/i;\n\n/**\n * Matches script-executing or data-fetching schemes.\n * @type {RegExp}\n */\nexport const REG_SCRIPT_BLOB = /^(?:(?:java|vb)script|blob)$/i;\n\n/**\n * Matches HTML tags, quotes, and their encoded or character reference variants.\n * @type {RegExp}\n */\nexport const REG_TAG_QUOT =\n /[\"'<>]|%(?:22|27|3C|3E)|&(?:apos|lt|gt|quot|#0*(?:34|39|60|62)|#x0*(?:22|27|3C|3E));/i;\n\n/**\n * Matches a percent-encoded character (%XX).\n * @type {RegExp}\n */\nexport const REG_URL_ENC = /^%[\\dA-F]{2}$/i;\n\n/**\n * Matches an ampersand-encoded character (&foo).\n * @type {RegExp}\n */\nexport const REG_AMP_ENC = /&(?=[#a-z0-9])(?![a-z0-9]+=)/i;\n\n/**\n * Match one or more consecutive URL percent-encoded sequences (%20, %E3%81%82).\n * @type {RegExp}\n */\nexport const REG_PCT_ENC = /(?:%[\\dA-F]{2})+/gi;\n\n/**\n * Validates relative URLs and flags invalid patterns.\n * @type {RegExp}\n */\nexport const REG_VERIFY_RELATIVE = /^(?:\\/{2,}|\\\\|[a-z][a-z\\d+\\-.]*:[^/])/i;\n", "[9,10,13,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255]\n", "/**\n * text-chars.js\n */\n\n/* shared */\nimport textChars from '../lib/file/text-chars.json' with { type: 'json' };\nimport { HEX } from './constant.js';\n\n/**\n * A set of valid text character codes.\n * @type {Set<number>}\n */\nexport const TEXT_CHAR_CODES = new Set(textChars);\n\n/**\n * A mapping of Windows-1252 specific character codes to their corresponding Unicode code points.\n * @type {Map<number, number>}\n */\nexport const WINDOWS1252_TO_UNICODE = new Map([\n [128, 0x20ac],\n [130, 0x201a],\n [131, 0x0192],\n [132, 0x201e],\n [133, 0x2026],\n [134, 0x2020],\n [135, 0x2021],\n [136, 0x02c6],\n [137, 0x2030],\n [138, 0x0160],\n [139, 0x2039],\n [140, 0x0152],\n [142, 0x017d],\n [145, 0x2018],\n [146, 0x2019],\n [147, 0x201c],\n [148, 0x201d],\n [149, 0x2022],\n [150, 0x2013],\n [151, 0x2014],\n [152, 0x02dc],\n [153, 0x2122],\n [154, 0x0161],\n [155, 0x203a],\n [156, 0x0153],\n [158, 0x017e],\n [159, 0x0178]\n]);\n\n/**\n * Generates control character codes in hex.\n * @private\n * @returns {Map<number, string>} Generated control char codes.\n */\nconst generateCtrlCharCodes = () => {\n const charCodes = new Map();\n for (let i = 0; i < HEX * HEX; i++) {\n if (!TEXT_CHAR_CODES.has(i) && !WINDOWS1252_TO_UNICODE.has(i)) {\n charCodes.set(i, `\\\\x${i.toString(HEX).padStart(2, '0').toUpperCase()}`);\n }\n }\n return charCodes;\n};\n\n/**\n * A mapping of control character codes to their hexadecimal escape strings.\n * @type {Map<number, string>}\n */\nexport const CTRL_CHAR_CODES = generateCtrlCharCodes();\n", "/**\n * uri-util.js\n */\n\n/* shared */\nimport uriSchemes from '../lib/iana/uri-schemes.json' with { type: 'json' };\nimport { getType, isString } from './common.js';\n\n/* constants */\nimport { CHUNK_SIZE, DECI, HEX, MAX_BLOB_SIZE, MAX_NEST } from './constant.js';\nimport {\n REG_HASH,\n REG_NUM_REF,\n REG_PCT_ENC,\n REG_QUERY,\n REG_SCHEME_EXT,\n REG_SCRIPT,\n REG_URL_ENC\n} from './regexp.js';\nimport {\n CTRL_CHAR_CODES,\n TEXT_CHAR_CODES,\n WINDOWS1252_TO_UNICODE\n} from './text-chars.js';\nconst [ENC_AMP, ENC_NUM, ENC_LT, ENC_GT, ENC_QUOT, ENC_APOS] = [\n '&',\n '#',\n '<',\n '>',\n '\"',\n \"'\"\n].map(ch => `%${ch.charCodeAt(0).toString(HEX).toUpperCase()}`);\nconst ESCAPE_MAP = {\n [ENC_AMP]: `${ENC_AMP}amp;`,\n [ENC_LT]: `${ENC_AMP}lt;`,\n [ENC_GT]: `${ENC_AMP}gt;`,\n [ENC_QUOT]: `${ENC_AMP}quot;`,\n [ENC_APOS]: `${ENC_AMP}${ENC_NUM}39;`\n};\nconst HEX_TABLE = Array.from(\n { length: HEX * HEX },\n (_, i) => `%${i.toString(HEX).padStart(2, '0').toUpperCase()}`\n);\nconst IS_NODE = globalThis.process?.versions?.node !== undefined;\nconst REG_BINARY = new RegExp(`[${[...CTRL_CHAR_CODES.values()].join('')}]`);\nconst REG_CTRL_CHARS = new RegExp(\n `[${[...CTRL_CHAR_CODES.values()].join('')}]`,\n 'g'\n);\n\n/* encoder / decoder */\nconst encoder = new TextEncoder();\nconst decoder = new TextDecoder('utf-8', { fatal: true });\n\n/**\n * URI schemes\n */\nexport class URISchemes {\n /* private fields */\n #schemes = new Set(uriSchemes);\n\n /**\n * Gets the list of registered URI schemes.\n * @see {@link https://www.iana.org/assignments/uri-schemes/uri-schemes.xhtml}\n * - Historical schemes are omitted.\n * - The 'moz-extension' scheme is added by default.\n * @returns {string[]} An array of registered schemes.\n */\n get() {\n return [...this.#schemes];\n }\n\n /**\n * Checks if the specified scheme is currently registered.\n * @param {string} scheme - The target scheme.\n * @returns {boolean} True if the scheme is registered.\n */\n has(scheme) {\n if (!isString(scheme)) {\n return false;\n }\n return this.#schemes.has(scheme.trim().toLowerCase());\n }\n\n /**\n * Verifies if the given URI is valid and its scheme is allowed.\n * @param {string} uri - The URI string to verify.\n * @param {Set<string>} [schemes] - The set of allowed schemes.\n * @returns {boolean} True if the URI is syntactically valid and permitted.\n */\n verify(uri, schemes = this.#schemes) {\n if (!isString(uri)) {\n return false;\n }\n const normalizedUri = uri.normalize('NFKC');\n const parsedUrl = URL.parse(normalizedUri);\n if (!parsedUrl) {\n return false;\n }\n const scheme = parsedUrl.protocol.replace(/:$/, '');\n const parts = scheme.split('+');\n const isScript = parts.some(s => REG_SCRIPT.test(s));\n if (isScript) {\n return false;\n }\n return REG_SCHEME_EXT.test(scheme) || parts.every(s => schemes.has(s));\n }\n}\n\n/**\n * Gets the URL-encoded representation of a given string.\n * @param {string} str - The target string.\n * @returns {string} The URL-encoded string.\n */\nexport const getURLEncodedString = str => {\n if (!isString(str)) {\n throw new TypeError(`Expected String but got ${getType(str)}.`);\n }\n const bytes = encoder.encode(str);\n let encoded = '';\n for (let i = 0; i < bytes.length; i++) {\n encoded += HEX_TABLE[bytes[i]];\n }\n return encoded;\n};\n\n/**\n * Escapes URL-encoded HTML special characters.\n * @param {string} ch - A URL-encoded (percent-encoded) character.\n * @returns {string} The escaped HTML special character, or the given character.\n */\n\nexport const escapeURLEncodedHTMLChars = ch => {\n if (!isString(ch)) {\n return ch;\n }\n const target = REG_URL_ENC.test(ch) ? ch.toUpperCase() : ch;\n return ESCAPE_MAP[target] ?? ch;\n};\n\n/**\n * Parses base64-encoded data.\n * @param {string} data - The base64-encoded string.\n * @returns {string} The parsed text, or the original base64 if binary.\n */\nexport const parseBase64 = data => {\n if (!isString(data)) {\n throw new TypeError(`Expected String but got ${getType(data)}.`);\n }\n const cleanData = data.replace(/\\s/g, '');\n let binStr;\n try {\n binStr = atob(cleanData);\n } catch {\n throw new Error(`Invalid base64 data: ${data}`);\n }\n let bytes;\n if (IS_NODE && globalThis.Buffer) {\n // Use 'latin1' to correctly map the binary string directly to bytes.\n // @see https://nodejs.org/docs/latest/api/buffer.html#buffers-and-character-encodings\n bytes = globalThis.Buffer.from(binStr, 'latin1');\n } else {\n const len = binStr.length;\n bytes = new Uint8Array(len);\n for (let i = 0; i < len; i++) {\n bytes[i] = binStr.charCodeAt(i);\n }\n }\n try {\n const text = decoder.decode(bytes);\n if (REG_BINARY.test(text)) {\n return cleanData;\n }\n return text;\n } catch {\n return cleanData;\n }\n};\n\n/**\n * Replaces URL-encoded numeric character references.\n * @param {string} match - The matched substring.\n * @param {string} value - The captured numeric value.\n * @returns {string} The resolved character or the original match.\n */\nexport const replaceNumCharRef = (match, value) => {\n const num = /x/i.test(value[0])\n ? parseInt(value.substring(1), HEX)\n : parseInt(value, DECI);\n if (Number.isInteger(num)) {\n if (TEXT_CHAR_CODES.has(num)) {\n return String.fromCharCode(num);\n } else if (WINDOWS1252_TO_UNICODE.has(num)) {\n const codePoint = WINDOWS1252_TO_UNICODE.get(num);\n return String.fromCodePoint(codePoint);\n } else if (CTRL_CHAR_CODES.has(num)) {\n return '';\n }\n }\n return match;\n};\n\n/**\n * Removes a trailing empty hash and an empty query string from a URL.\n * @param {string} url - The target URL string to be cleaned.\n * @returns {string} The cleaned URL string or the original input.\n */\nexport const trimTrailingEmptyQueryAndHash = url => {\n if (!isString(url)) {\n return url;\n }\n return url.replace(REG_HASH, '').replace(REG_QUERY, '$1');\n};\n\n/**\n * Parses URL-encoded numeric character references in the range 0x00 to 0xFF.\n * @param {string} str - The target string to parse.\n * @param {number} [nest] - The current nesting depth for recursive parsing.\n * @returns {string} The decoded and parsed string.\n */\nexport const parseURLEncodedNumCharRef = (str, nest = 0) => {\n if (!isString(str)) {\n throw new TypeError(`Expected String but got ${getType(str)}.`);\n }\n if (!Number.isInteger(nest)) {\n throw new TypeError(`Expected Number but got ${getType(nest)}.`);\n }\n let res;\n try {\n res = decodeURIComponent(str);\n } catch {\n // Fallback: decode only valid multi-byte %XX sequences.\n res = str.replace(REG_PCT_ENC, match => {\n try {\n return decodeURIComponent(match);\n } catch {\n return match;\n }\n });\n }\n res = res.replace(REG_CTRL_CHARS, '');\n let depth = 0;\n for (; depth + nest <= MAX_NEST; depth++) {\n const previousRes = res;\n // Decode '&amp;' before decoding numeric references.\n res = res.replace(/&amp;/gi, '&').replace(REG_NUM_REF, replaceNumCharRef);\n if (res === previousRes) {\n break;\n }\n }\n if (depth + nest > MAX_NEST && /&#/.test(res)) {\n throw new Error('Character references nested too deeply.');\n }\n return res;\n};\n\n/**\n * Converts Blob to data URL from Buffer.\n * @private\n * @param {Blob} blob - The target Blob object.\n * @returns {Promise<string|null>} A promise resolving to the data URL, or null.\n */\nconst convertFromBuffer = async blob => {\n const mimeStr = blob.type ? `${blob.type};base64` : 'base64';\n const buffer = await blob.arrayBuffer();\n const base64 = globalThis.Buffer.from(buffer).toString('base64');\n return `data:${mimeStr},${base64}`;\n};\n\n/**\n * Converts Blob to data URL from FileReader.\n * @private\n * @param {Blob} blob - The target Blob object.\n * @returns {Promise<string|null>} A promise resolving to the data URL, or null.\n */\nconst convertFromFileReader = blob =>\n new Promise((resolve, reject) => {\n const reader = new globalThis.FileReader();\n reader.addEventListener('error', () => reject(reader.error));\n reader.addEventListener('abort', () => resolve(null));\n reader.addEventListener('load', () => resolve(reader.result));\n reader.readAsDataURL(blob);\n });\n\n/**\n * Converts Blob to data URL from btoa.\n * @private\n * @param {Blob} blob - The target Blob object.\n * @returns {Promise<string|null>} A promise resolving to the data URL, or null.\n */\nconst convertFromBtoa = async blob => {\n const mimeStr = blob.type ? `${blob.type};base64` : 'base64';\n const buffer = await blob.arrayBuffer();\n const uint8arr = new Uint8Array(buffer);\n const chunks = [];\n for (let i = 0; i < uint8arr.length; i += CHUNK_SIZE) {\n chunks.push(String.fromCharCode(...uint8arr.subarray(i, i + CHUNK_SIZE)));\n }\n return `data:${mimeStr},${btoa(chunks.join(''))}`;\n};\n\n/**\n * Converts a Blob to a data URL.\n * @param {Blob} blob - The target Blob object.\n * @param {number} [maxSize] - The maximum allowed blob size.\n * @returns {Promise<string|null>} A promise resolving to the data URL, or null.\n */\nexport const convertBlobToDataURL = async (blob, maxSize = MAX_BLOB_SIZE) => {\n if (!Number.isInteger(blob?.size)) {\n return null;\n } else if (Number.isInteger(maxSize) && blob.size > maxSize) {\n const msg = `Blob size (${blob.size} bytes) exceeds max (${maxSize} bytes).`;\n throw new DOMException(msg, 'NotReadableError');\n }\n if (IS_NODE && globalThis.Buffer) {\n return convertFromBuffer(blob);\n } else if (globalThis.FileReader) {\n return convertFromFileReader(blob);\n }\n return convertFromBtoa(blob);\n};\n", "/**\n * sanitizer.js\n */\n\n/* shared */\nimport { domPurify } from './dompurify.js';\nimport { getType, isString } from './common.js';\nimport {\n URISchemes,\n convertBlobToDataURL,\n escapeURLEncodedHTMLChars,\n parseBase64,\n parseURLEncodedNumCharRef,\n trimTrailingEmptyQueryAndHash\n} from './uri-util.js';\n\n/* constants */\nimport { MAX_BLOB_SIZE, MAX_NEST } from './constant.js';\nimport {\n REG_AMP_ENC,\n REG_MIME_DOM,\n REG_SCHEME,\n REG_SCRIPT,\n REG_SCRIPT_BLOB,\n REG_TAG_QUOT,\n REG_VERIFY_RELATIVE\n} from './regexp.js';\nconst URL_PROPS = Object.freeze([\n 'href',\n 'origin',\n 'protocol',\n 'username',\n 'password',\n 'host',\n 'hostname',\n 'port',\n 'pathname',\n 'search',\n 'hash'\n]);\nconst INTERNAL_PURIFY_CONFIG = Object.freeze({\n RETURN_DOM: false,\n RETURN_DOM_FRAGMENT: false,\n RETURN_TRUSTED_TYPE: false\n});\n\n/* typedef */\n/**\n * The parsed result of a data URL.\n * @typedef {object} InspectedDataURL\n * @property {string} mime - The MIME type of the data.\n * @property {boolean} base64 - Indicates whether the data is base64-encoded.\n * @property {string} data - The actual data part of the data URL.\n */\n\n/**\n * The result of an inspected URL, extending the standard URL API.\n * The properties except for input and valid are omitted for invalid URLs.\n * @typedef {object} InspectedURLResult\n * @property {string} input - The original URL input.\n * @property {boolean} valid - Indicates whether the URI is valid.\n * @property {string} [reason] - The reason why the URL is invalid.\n * @property {InspectedDataURL | null} [data] - The parsed result of a data URL. Null if not a data URL.\n * @property {string} [href] - The sanitized URL input.\n * @property {string} [origin] - The scheme, domain, and port.\n * @property {string} [protocol] - The protocol scheme.\n * @property {string} [username] - The specified username.\n * @property {string} [password] - The specified password.\n * @property {string} [host] - The domain and port.\n * @property {string} [hostname] - The domain.\n * @property {string} [port] - The port number.\n * @property {string} [pathname] - The path.\n * @property {string} [search] - The query string.\n * @property {string} [hash] - The fragment identifier.\n */\n\n/**\n * Internal debug logger.\n * @param {boolean} isDebug - Flag to enable or disable debug output.\n * @param {string} message - The message to output.\n * @param {Error} [error] - The caught error object, if any.\n * @returns {void}\n */\nexport const logDebug = (isDebug, message, error) => {\n if (isDebug) {\n console.warn(`[URLSanitizer Debug] ${message}`, error);\n }\n};\n\n/**\n * URL sanitizer\n */\nclass URLSanitizer extends URISchemes {\n /* private fields */\n #allowedSchemes;\n\n /**\n * NOTE: Global Context Pattern for DOMPurify Hooks\n * - DOMPurify hooks (e.g., 'uponSanitizeAttribute') are registered globally\n * and do not accept custom arguments (like `this` or `ctx`).\n * To pass the current sanitization context into the hook, we temporarily\n * store it in static fields (#currentInstance and #currentCtx).\n * - This is entirely safe and immune to race conditions because JavaScript\n * runs on a single thread and DOMPurify's sanitize() is synchronous.\n * The context is safely restored via try/finally block in #purify() even\n * during recursive calls.\n */\n /** @type {URLSanitizer | null} */\n static #currentInstance = null;\n static #currentCtx = null;\n\n /**\n * DOMPurify 'uponSanitizeAttribute' hook callback.\n * @private\n * @static\n * @param {Node} node - The DOM node being sanitized.\n * @param {object} evt - The event object containing attribute details.\n */\n static #uponSanitizeAttribute(node, evt) {\n if (!evt.attrValue || !/^\\s*data:/i.test(evt.attrValue)) {\n return;\n }\n /** @type {URLSanitizer | null} */\n const sanitizer = URLSanitizer.#currentInstance;\n const ctx = URLSanitizer.#currentCtx;\n if (!sanitizer || !ctx) {\n return;\n }\n const urlObj = URL.parse(evt.attrValue);\n if (!urlObj) {\n return;\n }\n if (urlObj.protocol === 'data:') {\n const originalUrl = evt.attrValue;\n if (!ctx.recurse) {\n ctx.recurse = new Set();\n }\n if (ctx.recurse.has(originalUrl)) {\n const msg = `Circular Data URL detected and skipped: ${originalUrl}`;\n logDebug(ctx.debug, msg);\n evt.attrValue = '';\n return;\n }\n ctx.nest++;\n ctx.recurse.add(originalUrl);\n try {\n const sanitized = sanitizer.#process(\n originalUrl,\n {\n allow: ['data'],\n deny: [],\n only: [],\n allowRelative: false\n },\n ctx\n );\n evt.attrValue = sanitized || '';\n } finally {\n ctx.nest--;\n ctx.recurse.delete(originalUrl);\n }\n }\n }\n\n static {\n domPurify.setConfig(INTERNAL_PURIFY_CONFIG);\n domPurify.addHook(\n 'uponSanitizeAttribute',\n URLSanitizer.#uponSanitizeAttribute\n );\n }\n\n constructor() {\n super();\n this.#allowedSchemes = new Set(super.get());\n }\n\n /**\n * Helper method to register schemes for the 'allow' or 'only' options.\n * @private\n * @param {string} item - The scheme to register.\n * @param {string} listName - The name of the target option list.\n * @param {Set<string>} allowedSchemes - The local set of allowed schemes.\n * @param {Map<string, boolean>} schemeMap - The local map of schemes.\n * @param {object} ctx - The context for state management.\n * @returns {boolean} True if the scheme is successfully registered.\n */\n #registerScheme(item, listName, allowedSchemes, schemeMap, ctx) {\n if (REG_SCRIPT_BLOB.test(item)) {\n return false;\n }\n const schemeParts = item.split('+');\n const isScript = schemeParts.some(s => REG_SCRIPT.test(s));\n if (isScript || !REG_SCHEME.test(item)) {\n const msg = `Failed to add scheme '${item}' in '${listName}' list.`;\n logDebug(ctx.debug, msg);\n return false;\n }\n schemeMap.set(item, true);\n allowedSchemes.add(item);\n return true;\n }\n\n /**\n * Purifies a URL-encoded DOM string to prevent XSS.\n * @private\n * @param {string} dom - The URL-encoded DOM string.\n * @param {object} ctx - The context for state management.\n * @returns {string} The purified DOM string.\n */\n #purify(dom, ctx) {\n let decodedDom = dom;\n try {\n decodedDom = decodeURIComponent(dom);\n } catch {\n // fall through\n }\n const prevInstance = URLSanitizer.#currentInstance;\n const prevCtx = URLSanitizer.#currentCtx;\n URLSanitizer.#currentInstance = this;\n URLSanitizer.#currentCtx = ctx;\n let purifiedDom;\n try {\n purifiedDom = ctx.domPurify.sanitize(decodedDom);\n } finally {\n URLSanitizer.#currentInstance = prevInstance;\n URLSanitizer.#currentCtx = prevCtx;\n }\n purifiedDom = trimTrailingEmptyQueryAndHash(purifiedDom);\n try {\n return encodeURI(purifiedDom);\n } catch {\n return purifiedDom;\n }\n }\n\n /**\n * Internal recursive method for sanitization.\n * @private\n * @param {string} url - The URL string to sanitize.\n * @param {object} rules - Normalized sanitization rules.\n * @param {object} ctx - Internal context for state.\n * @returns {string|null} The sanitized URL, or null.\n */\n #process(url, rules, ctx) {\n if (ctx.nest > MAX_NEST) {\n throw new Error('Data URLs nested too deeply.');\n }\n // Resolve allowed/denied schemes\n const { allowedSchemes, restrictScheme, schemeMap } =\n this.#resolveSchemeRules(rules, ctx);\n // Parse and verify the URL\n const {\n isDataUrl,\n isRelative,\n isVerified,\n scheme,\n schemeParts,\n urlObj,\n urlToSanitize\n } = this.#parseAndVerifyURL(url, rules.allowRelative, allowedSchemes, ctx);\n if (!isVerified) {\n return null;\n }\n // Check if the scheme is allowed\n if (\n !this.#isSchemeAllowed(\n scheme,\n schemeParts,\n restrictScheme,\n schemeMap,\n isRelative\n )\n ) {\n return null;\n }\n // Sanitize based on URL type\n if (isDataUrl) {\n return this.#sanitizeDataURL(urlObj, scheme, ctx);\n }\n return this.#sanitizeStandardURL(urlToSanitize);\n }\n\n /**\n * Resolves allow, deny, and only rules into mappings.\n * @private\n * @param {object} rules - The sanitization rules.\n * @param {string[]} rules.allow - Allowed schemes.\n * @param {string[]} rules.deny - Denied schemes.\n * @param {string[]} rules.only - Exclusively allowed schemes.\n * @param {object} ctx - Context for state management.\n * @returns {object} Resolved scheme objects and flags.\n */\n #resolveSchemeRules({ allow, deny, only }, ctx) {\n let allowedSchemes = this.#allowedSchemes;\n let restrictScheme = false;\n const schemeMap = new Map(ctx.schemeMap);\n if (only.length) {\n allowedSchemes = new Set();\n for (const item of only) {\n if (isString(item)) {\n const registered = this.#registerScheme(\n item.trim(),\n 'only',\n allowedSchemes,\n schemeMap,\n ctx\n );\n if (registered && !restrictScheme) {\n restrictScheme = true;\n }\n }\n }\n } else {\n if (allow.length) {\n allowedSchemes = new Set(this.#allowedSchemes);\n for (const item of allow) {\n if (isString(item)) {\n this.#registerScheme(\n item.trim(),\n 'allow',\n allowedSchemes,\n schemeMap,\n ctx\n );\n }\n }\n }\n if (deny.length) {\n for (let item of deny) {\n if (isString(item)) {\n item = item.trim();\n if (item) {\n schemeMap.set(item, false);\n }\n }\n }\n }\n }\n return { allowedSchemes, restrictScheme, schemeMap };\n }\n\n /**\n * Parses and verifies absolute and relative URLs.\n * @private\n * @param {string} url - The URL to parse.\n * @param {boolean} allowRelative - If relative URLs are OK.\n * @param {Set<string>} allowedSchemes - Permitted schemes.\n * @param {object} ctx - Context for logging and state.\n * @returns {object} Parsed URL properties and flags.\n */\n #parseAndVerifyURL(url, allowRelative, allowedSchemes, ctx) {\n let isVerified = super.verify(url, allowedSchemes);\n let isRelative = false;\n let relativeParsedPath = '';\n // Handle Relative URLs\n if (!isVerified && allowRelative && !REG_VERIFY_RELATIVE.test(url)) {\n const normUrl = url.normalize('NFKC');\n const dummyUrl = URL.parse(url, 'http://dummy.local');\n const dummyUrlNormalized = URL.parse(normUrl, 'http://dummy.local');\n if (dummyUrl && dummyUrlNormalized) {\n if (\n dummyUrl.protocol === 'http:' &&\n dummyUrl.hostname === 'dummy.local' &&\n dummyUrlNormalized.protocol === 'http:'\n ) {\n isVerified = true;\n isRelative = true;\n relativeParsedPath = `${dummyUrl.pathname}${dummyUrl.search}${dummyUrl.hash}`;\n }\n } else {\n logDebug(ctx.debug, 'Failed to parse relative URL.');\n }\n }\n if (!isVerified) {\n return { isVerified: false };\n }\n // Extract parts if verified\n if (isRelative) {\n return {\n isRelative,\n isVerified,\n isDataUrl: false,\n scheme: '',\n schemeParts: [],\n urlToSanitize: relativeParsedPath\n };\n }\n const urlObj = URL.parse(url);\n const scheme = urlObj.protocol.replace(/:$/, '').normalize('NFKC');\n const schemeParts = scheme.split('+');\n return {\n isRelative,\n isVerified,\n scheme,\n schemeParts,\n urlObj,\n isDataUrl: schemeParts.includes('data'),\n urlToSanitize: urlObj.href\n };\n }\n\n /**\n * Evaluates if the extracted scheme is permitted.\n * @private\n * @param {string} scheme - The normalized URL scheme.\n * @param {string[]} schemeParts - Parts of the split scheme.\n * @param {boolean} restrictScheme - If rules strictly limit.\n * @param {Map<string, boolean>} schemeMap - Scheme rules map.\n * @param {boolean} isRelative - If the URL is relative.\n * @returns {boolean} True if the scheme is allowed.\n */\n #isSchemeAllowed(scheme, schemeParts, restrictScheme, schemeMap, isRelative) {\n if (isRelative) {\n return true;\n }\n if (restrictScheme) {\n return schemeParts.every(s => schemeMap.get(s));\n }\n for (const [key, value] of schemeMap.entries()) {\n const bool =\n value || (scheme !== key && schemeParts.every(s => s !== key));\n if (!bool) {\n return false;\n }\n }\n return true;\n }\n\n /**\n * Decodes, verifies inner protocols, and purifies data URLs.\n * @private\n * @param {object} urlObj - The URL object.\n * @param {string} scheme - The URL scheme.\n * @param {object} ctx - Context for DOMPurify sanitization.\n * @returns {string|null} Sanitized data URL or null.\n */\n #sanitizeDataURL(urlObj, scheme, ctx) {\n const [mediaType, ...dataParts] = urlObj.pathname.split(',');\n const data = `${dataParts.join(',')}${urlObj.search}${urlObj.hash}`;\n const mediaTypes = mediaType.split(';');\n const isBase64 = mediaTypes[mediaTypes.length - 1] === 'base64';\n let parsedData = data;\n if (isBase64) {\n try {\n parsedData = parseBase64(data);\n } catch (e) {\n logDebug(ctx.debug, 'Failed to parse base64 data.', e);\n return null;\n }\n }\n try {\n const decodedData = parseURLEncodedNumCharRef(parsedData).trim();\n const normalizedData = decodedData.normalize('NFKC');\n const dummy = 'http://dummy.local';\n const parsedUrl = URL.parse(normalizedData, dummy);\n if (!parsedUrl) {\n logDebug(ctx.debug, 'Failed to parse inner data URL protocol.');\n return null;\n }\n const dataScheme = parsedUrl.protocol;\n const dataSchemeParts = dataScheme.replace(/:$/, '').split('+');\n if (dataSchemeParts.some(s => REG_SCRIPT_BLOB.test(s))) {\n return null;\n }\n } catch (e) {\n logDebug(ctx.debug, 'Failed to parse inner data URL protocol.', e);\n return null;\n }\n if (!mediaType || REG_MIME_DOM.test(mediaType)) {\n parsedData = this.#purify(parsedData, ctx);\n }\n if (parsedData) {\n if (isBase64 && parsedData !== data) {\n mediaTypes.pop();\n }\n return `${scheme}:${mediaTypes.join(';')},${parsedData}`;\n }\n return null;\n }\n\n /**\n * Applies regex cleanups to standard non-data URLs.\n * Strips out trailing queries or problematic characters.\n * @private\n * @param {string} urlToSanitize - The absolute/relative URL.\n * @returns {string|null} Cleaned URL string or null.\n */\n #sanitizeStandardURL(urlToSanitize) {\n let sanitized = urlToSanitize;\n if (REG_TAG_QUOT.test(sanitized)) {\n const { index } = REG_TAG_QUOT.exec(sanitized);\n sanitized = sanitized.substring(0, index).replace(/[?&]$/, '');\n }\n if (REG_AMP_ENC.test(sanitized)) {\n const { index } = REG_AMP_ENC.exec(sanitized);\n sanitized = sanitized.substring(0, index).replace(/[?&]$/, '');\n }\n return sanitized;\n }\n\n /**\n * Sanitizes the given URL.\n * @param {string} url - The URL string to sanitize.\n * @param {object} [opt] - Sanitization options.\n * @param {string[]} [opt.allow] - An array of schemes to allow.\n * @param {string[]} [opt.deny] - An array of schemes to deny.\n * @param {string[]} [opt.only] - An array of specific schemes to allow.\n * @param {boolean} [opt.allowRelative] - Flag to safely allow relative URLs.\n * @param {boolean} [opt.debug] - Flag to enable debug mode.\n * @param {number} [opt.maxBlobSize] - The maximum allowed blob size in bytes.\n * @param {number} [opt.maxLength] - The maximum allowed URL length.\n * @returns {string|null} The sanitized URL, or null.\n */\n sanitize(url, opt) {\n if (!url || !isString(url)) {\n return null;\n }\n const maxLength =\n Number.isInteger(opt?.maxLength) && opt.maxLength ? opt.maxLength : 0;\n if (maxLength && url.length > maxLength) {\n const msg = `URL length ${url.length} exceeds maxLength ${maxLength}.`;\n throw new RangeError(msg);\n }\n const hasRestrictiveRules =\n opt &&\n ((Array.isArray(opt.deny) && opt.deny.length > 0) ||\n (Array.isArray(opt.only) && opt.only.length > 0) ||\n opt.allowRelative);\n if (\n !hasRestrictiveRules &&\n (url.startsWith('https://') || url.startsWith('http://')) &&\n !REG_TAG_QUOT.test(url) &&\n !url.includes('data:')\n ) {\n const parsedUrl = URL.parse(url);\n if (parsedUrl) {\n return parsedUrl.href.replace(/%26/g, escapeURLEncodedHTMLChars);\n } else {\n logDebug(opt?.debug, `Failed to parse URL.`);\n return null;\n }\n }\n const rules = {\n allow: Array.isArray(opt?.allow) ? opt.allow : [],\n deny: Array.isArray(opt?.deny) ? opt.deny : [],\n only: Array.isArray(opt?.only) ? opt.only : [],\n allowRelative: !!opt?.allowRelative\n };\n const ctx = {\n debug: !!opt?.debug,\n domPurify,\n nest: 0,\n recurse: null,\n schemeMap: new Map([\n ['blob', false],\n ['data', false],\n ['file', false],\n ['javascript', false],\n ['vbscript', false]\n ])\n };\n return this.#process(url, rules, ctx);\n }\n\n /**\n * Inspects, parses, and sanitizes the given URL.\n * NOTE: blob URLs are simply parsed, but neither decoded nor sanitized.\n * @param {string} url - The URL string to parse.\n * @param {object} [opt] - Sanitization options.\n * @returns {InspectedURLResult} The result of an inspected URL.\n */\n inspect(url, opt) {\n if (!isString(url)) {\n throw new TypeError(`Expected String but got ${getType(url)}.`);\n }\n const inspectedURL = {\n input: url,\n valid: false\n };\n let sanitizedUrl;\n let invalidReason = null;\n const maxLength =\n Number.isInteger(opt?.maxLength) && opt.maxLength ? opt.maxLength : 0;\n const urlLength = url.length;\n if (maxLength && urlLength > maxLength) {\n invalidReason = `URL length ${urlLength} exceeds maxLength ${maxLength}.`;\n } else if (this.verify(url)) {\n const { protocol } = new URL(url);\n if (protocol === 'blob:') {\n sanitizedUrl = url;\n } else {\n try {\n sanitizedUrl = this.sanitize(url, opt ?? { allow: ['data'] });\n if (!sanitizedUrl) {\n invalidReason =\n 'Sanitization failed (blocked by allowed schemes or rules).';\n }\n } catch (e) {\n invalidReason = e.message;\n }\n }\n } else {\n invalidReason = 'Invalid URI syntax or scheme is not registered.';\n }\n if (sanitizedUrl) {\n const urlObj = new URL(sanitizedUrl);\n const { pathname, protocol } = urlObj;\n const schemeParts = protocol.replace(/:$/, '').split('+');\n const isDataUrl = schemeParts.includes('data');\n inspectedURL.valid = true;\n if (isDataUrl) {\n const [mediaType, ...dataParts] = pathname.split(',');\n const data = `${dataParts.join(',')}${urlObj.search}${urlObj.hash}`;\n const mediaTypes = mediaType.split(';');\n const isBase64 = mediaTypes[mediaTypes.length - 1] === 'base64';\n if (isBase64) {\n mediaTypes.pop();\n }\n inspectedURL.data = {\n mime: mediaTypes.join(';'),\n base64: isBase64,\n data\n };\n } else {\n inspectedURL.data = null;\n }\n for (const key of URL_PROPS) {\n const value = urlObj[key];\n if (isString(value)) {\n inspectedURL[key] = value;\n }\n }\n } else {\n inspectedURL.valid = false;\n if (invalidReason) {\n inspectedURL.reason = invalidReason;\n }\n }\n return inspectedURL;\n }\n\n /**\n * Gets the list of registered URI schemes.\n * @returns {string[]} An array of registered schemes.\n */\n get() {\n return [...this.#allowedSchemes];\n }\n\n /**\n * Checks if the specified scheme is currently registered.\n * @param {string} scheme - The target scheme.\n * @returns {boolean} True if the scheme is registered.\n */\n has(scheme) {\n if (!isString(scheme)) {\n return false;\n }\n return this.#allowedSchemes.has(scheme.trim().toLowerCase());\n }\n\n /**\n * Adds a new scheme to the allowed list.\n * @param {string} scheme - The scheme to add.\n * @returns {string[]} The updated array of registered schemes.\n */\n add(scheme) {\n let loweredScheme;\n if (isString(scheme)) {\n loweredScheme = scheme.trim().toLowerCase();\n } else {\n throw new TypeError(`Expected String but got ${getType(scheme)}.`);\n }\n const schemeParts = loweredScheme.split('+');\n const isScript = schemeParts.some(s => REG_SCRIPT.test(s));\n if (isScript || !REG_SCHEME.test(loweredScheme)) {\n throw new Error(`Invalid scheme: ${scheme}`);\n }\n this.#allowedSchemes.add(loweredScheme);\n return [...this.#allowedSchemes];\n }\n\n /**\n * Removes a scheme from the allowed list.\n * @param {string} scheme - The scheme to remove.\n * @returns {boolean} True if the scheme was successfully removed.\n */\n remove(scheme) {\n if (!isString(scheme)) {\n return false;\n }\n return this.#allowedSchemes.delete(scheme.trim().toLowerCase());\n }\n\n /**\n * Resets the registered schemes back to the default initial list.\n * @returns {void}\n */\n reset() {\n this.#allowedSchemes = new Set(super.get());\n }\n\n /**\n * Verifies if the given URI is valid and its scheme is allowed.\n * @param {string} uri - The URI string to verify.\n * @param {Set<string>} [schemes] - The set of allowed schemes.\n * @returns {boolean} True if the URI is syntactically valid and permitted.\n */\n verify(uri, schemes = this.#allowedSchemes) {\n return super.verify(uri, schemes);\n }\n}\nexport { URLSanitizer };\n\n/* instance */\nconst urlSanitizer = new URLSanitizer();\n\n/**\n * Asynchronously sanitizes the given URL.\n * NOTE: `blob`, `data`, and `file` schemes must be explicitly allowed.\n * Given a `blob` URL, it securely converts and returns a sanitized `data` URL.\n * @param {string} url - URL\n * @param {object} [opt] - options\n * @param {string[]} [opt.allow] - The array of schemes to allow.\n * @param {string[]} [opt.deny] - The array of schemes to deny.\n * @param {string[]} [opt.only] - The array of specific schemes to allow.\n * @param {boolean} [opt.allowRelative] - Allow relative URLs.\n * @param {boolean} [opt.debug] - Enable debug mode.\n * @param {boolean} [opt.revokeObjectURL] - Revokes the blob URL after sanitization.\n * @param {number} [opt.maxBlobSize] - The maximum allowed blob size in bytes.\n * @param {number} [opt.maxLength] - The maximum allowed URL length\n * @returns {Promise<string|null>} A promise resolving to the sanitized URL, or null.\n */\nexport const sanitizeURL = async (\n url,\n opt = {\n allow: [],\n deny: [],\n only: [],\n allowRelative: false,\n debug: false,\n revokeObjectURL: false,\n maxBlobSize: MAX_BLOB_SIZE\n }\n) => {\n const isDebug = !!opt?.debug;\n const maxBlobSize =\n Number.isInteger(opt?.maxBlobSize) && opt.maxBlobSize > 0\n ? opt.maxBlobSize\n : MAX_BLOB_SIZE;\n let res;\n if (url && isString(url)) {\n let scheme;\n const parsedUrl = URL.parse(url);\n if (parsedUrl) {\n scheme = parsedUrl.protocol.replace(/:$/, '');\n } else {\n logDebug(isDebug, `Invalid URL input format: ${url}`);\n }\n if (scheme === 'blob') {\n const { allow, deny, only } = opt;\n if (\n (Array.isArray(allow) &&\n allow.includes('blob') &&\n !(Array.isArray(deny) && deny.includes('blob'))) ||\n (Array.isArray(only) && only.includes('blob'))\n ) {\n let data;\n try {\n data = await fetch(url)\n .then(r => r.blob())\n .then(b => convertBlobToDataURL(b, maxBlobSize));\n } catch (e) {\n const msg = `Failed to fetch and convert blob URL: ${url}`;\n logDebug(isDebug, msg, e);\n }\n if (data) {\n const options = { ...opt };\n if (Array.isArray(opt.only)) {\n options.only = opt.only.includes('data')\n ? opt.only\n : [...opt.only, 'data'];\n } else if (Array.isArray(opt.allow)) {\n options.allow = opt.allow.includes('data')\n ? opt.allow\n : [...opt.allow, 'data'];\n if (Array.isArray(opt.deny)) {\n options.deny = opt.deny.filter(scheme => scheme !== 'data');\n }\n }\n res = urlSanitizer.sanitize(data, options);\n }\n }\n if (opt?.revokeObjectURL) {\n URL.revokeObjectURL(url);\n }\n } else if (scheme || opt.allowRelative) {\n res = urlSanitizer.sanitize(url, opt);\n }\n }\n return res || null;\n};\n\n/**\n * Synchronously sanitizes the given URL.\n * NOTE: `data` and `file` schemes must be explicitly allowed.\n * The `blob` scheme is not supported and will return `null`.\n * @param {string} url - URL\n * @param {object} [opt] - options\n * @param {string[]} [opt.allow] - The array of schemes to allow.\n * @param {string[]} [opt.deny] - The array of schemes to deny.\n * @param {string[]} [opt.only] - The array of specific schemes to allow.\n * @param {boolean} [opt.allowRelative] - Allow relative URLs.\n * @param {boolean} [opt.debug] - Enable debug mode.\n * @param {boolean} [opt.revokeObjectURL] - Revokes the blob URL.\n * @param {number} [opt.maxLength] - The maximum allowed URL length.\n * @returns {string|null} The sanitized URL, or null if denied.\n */\nexport const sanitizeURLSync = (\n url,\n opt = {\n allow: [],\n deny: [],\n only: [],\n allowRelative: false,\n debug: false,\n revokeObjectURL: false\n }\n) => {\n const isDebug = !!opt?.debug;\n let res;\n if (url && isString(url)) {\n let scheme;\n const parsedUrl = URL.parse(url);\n if (parsedUrl) {\n scheme = parsedUrl.protocol.replace(/:$/, '');\n } else {\n logDebug(isDebug, `Invalid URL input format: ${url}`);\n }\n if (scheme === 'blob') {\n if (opt?.revokeObjectURL) {\n URL.revokeObjectURL(url);\n }\n return null;\n } else if (scheme || opt.allowRelative) {\n res = urlSanitizer.sanitize(url, opt);\n }\n }\n return res || null;\n};\n\n/**\n * Inspects, parses, and sanitizes the given URL asynchronously.\n * @param {string} url - The URL string to inspect.\n * @returns {Promise<InspectedURLResult>} A promise resolving to the inspected URL result.\n */\nexport const inspectURL = async url => {\n const res = urlSanitizer.inspect(url);\n return res;\n};\n\n/**\n * @deprecated Use {@link inspectURL} instead.\n * @param {string} url - The URL string to inspect.\n * @returns {Promise<InspectedURLResult>} A promise resolving to the inspected URL result.\n */\nexport const parseURL = async url => inspectURL(url);\n\n/**\n * Inspects, parses, and sanitizes the given URL synchronously.\n * @param {string} url - The URL string to inspect.\n * @returns {InspectedURLResult} The inspected URL result.\n */\nexport const inspectURLSync = url => urlSanitizer.inspect(url);\n\n/**\n * @deprecated Use {@link inspectURLSync} instead.\n * @param {string} url - The URL string to inspect.\n * @returns {InspectedURLResult} The inspected URL result.\n */\nexport const parseURLSync = url => inspectURLSync(url);\n\n/**\n * Asynchronously checks if the given string is a valid URI and is registered.\n * @param {string} uri - The URI string to verify.\n * @returns {Promise<boolean>} True if valid and registered, false otherwise.\n */\nexport const isURI = async uri => {\n const res = urlSanitizer.verify(uri);\n return res;\n};\n\n/**\n * Synchronously checks if the given string is a valid URI and is registered.\n * @param {string} uri - The URI string to verify.\n * @returns {boolean} True if valid and registered, false otherwise.\n */\nexport const isURISync = uri => urlSanitizer.verify(uri);\n\n/* export instance */\nexport default urlSanitizer;\n"],
5
+ "mappings": "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",
6
+ "names": ["PROPERTIES", "hookQueue", "domPurify", "target", "prop", "purifier", "p", "args", "value", "getType", "o", "isString", "uri_schemes_default", "REG_HASH", "REG_MIME_DOM", "REG_NUM_REF", "REG_QUERY", "REG_SCHEME", "REG_SCHEME_EXT", "REG_SCRIPT", "REG_SCRIPT_BLOB", "REG_TAG_QUOT", "REG_URL_ENC", "REG_AMP_ENC", "REG_PCT_ENC", "REG_VERIFY_RELATIVE", "text_chars_default", "TEXT_CHAR_CODES", "text_chars_default", "WINDOWS1252_TO_UNICODE", "generateCtrlCharCodes", "charCodes", "i", "CTRL_CHAR_CODES", "ENC_AMP", "ENC_NUM", "ENC_LT", "ENC_GT", "ENC_QUOT", "ENC_APOS", "ch", "ESCAPE_MAP", "HEX_TABLE", "_", "i", "IS_NODE", "REG_BINARY", "CTRL_CHAR_CODES", "REG_CTRL_CHARS", "encoder", "decoder", "URISchemes", "#schemes", "uri_schemes_default", "scheme", "isString", "uri", "schemes", "normalizedUri", "parsedUrl", "parts", "s", "REG_SCRIPT", "REG_SCHEME_EXT", "escapeURLEncodedHTMLChars", "ch", "isString", "target", "REG_URL_ENC", "ESCAPE_MAP", "parseBase64", "data", "getType", "cleanData", "binStr", "bytes", "IS_NODE", "len", "i", "text", "decoder", "REG_BINARY", "replaceNumCharRef", "match", "value", "num", "TEXT_CHAR_CODES", "WINDOWS1252_TO_UNICODE", "codePoint", "CTRL_CHAR_CODES", "trimTrailingEmptyQueryAndHash", "url", "REG_HASH", "REG_QUERY", "parseURLEncodedNumCharRef", "str", "nest", "res", "REG_PCT_ENC", "REG_CTRL_CHARS", "depth", "previousRes", "REG_NUM_REF", "convertFromBuffer", "blob", "mimeStr", "buffer", "base64", "convertFromFileReader", "resolve", "reject", "reader", "convertFromBtoa", "uint8arr", "chunks", "convertBlobToDataURL", "maxSize", "msg", "URL_PROPS", "INTERNAL_PURIFY_CONFIG", "logDebug", "isDebug", "message", "error", "URLSanitizer", "_URLSanitizer", "URISchemes", "#allowedSchemes", "#currentInstance", "#currentCtx", "#uponSanitizeAttribute", "node", "evt", "sanitizer", "ctx", "urlObj", "originalUrl", "msg", "sanitized", "#process", "domPurify", "#registerScheme", "item", "listName", "allowedSchemes", "schemeMap", "REG_SCRIPT_BLOB", "s", "REG_SCRIPT", "REG_SCHEME", "#purify", "dom", "decodedDom", "prevInstance", "prevCtx", "purifiedDom", "trimTrailingEmptyQueryAndHash", "url", "rules", "restrictScheme", "#resolveSchemeRules", "isDataUrl", "isRelative", "isVerified", "scheme", "schemeParts", "urlToSanitize", "#parseAndVerifyURL", "#isSchemeAllowed", "#sanitizeDataURL", "#sanitizeStandardURL", "allow", "deny", "only", "isString", "allowRelative", "relativeParsedPath", "REG_VERIFY_RELATIVE", "normUrl", "dummyUrl", "dummyUrlNormalized", "key", "value", "mediaType", "dataParts", "data", "mediaTypes", "isBase64", "parsedData", "parseBase64", "e", "normalizedData", "parseURLEncodedNumCharRef", "parsedUrl", "REG_MIME_DOM", "REG_TAG_QUOT", "index", "REG_AMP_ENC", "opt", "maxLength", "escapeURLEncodedHTMLChars", "getType", "inspectedURL", "sanitizedUrl", "invalidReason", "urlLength", "protocol", "pathname", "loweredScheme", "uri", "schemes", "urlSanitizer", "URLSanitizer", "sanitizeURL", "url", "opt", "isDebug", "maxBlobSize", "res", "isString", "scheme", "parsedUrl", "logDebug", "allow", "deny", "only", "data", "r", "b", "convertBlobToDataURL", "e", "msg", "options", "sanitizeURLSync", "inspectURL", "parseURL", "inspectURLSync", "parseURLSync", "isURI", "uri", "isURISync", "sanitizer_default"]
7
7
  }