const pinger = `
<!doctype html>
<html>
    <head>
        <meta charset="utf-8" />
    </head>
    <body>
        <script type="text/javascript">(function() {
            var interval = setInterval(function() {
                fetch("/download-stream-service-worker/" + Math.random() +
                    Math.random() + Math.random() +
                    "/download-stream-service-worker-ping").then(function(f) {

                    return f.text();

                }).then(function(t) {
                    if (t !== "pong") {
                        console.log(t);
                        clearInterval(interval);
                    }

                }).catch(console.error);
            }, 5000);
        })();
        </script>
    </body>
</html>
` ; interface Stream { buf : Uint8Array ; started : boolean ; ended : boolean ; headers : Record < string , string > ; onstart : ( ) => void ; readyForData : ( ) => void ; dataAvailable : ( ) => void ; timeout : number ; } const streams = Object . create ( null ) ; self . addEventListener ( "message" , async function ( ev ) { if ( ev . data . c !== "port" ) return ; const port = ev . data . p ; port . onmessage = ev => { message ( port , ev ) ; } ; } ) ; async function message ( port , ev ) { const msg = ev . data ; switch ( msg . c ) { case "setup" : port . postMessage ( { c : "ack" , i : msg . i , v : 5 } ) ; return ; case "ping" : port . postMessage ( { c : "pong" , i : msg . i } ) ; return ; case "stream" : stream ( msg ) ; break ; case "wait-start" : await waitStart ( msg ) ; break ; case "data" : case "end" : case "keepalive" : await data ( msg ) ; break ; default : port . postMessage ( { c : "nack" , i : msg . i } ) ; return ; } port . postMessage ( { c : "ack" , i : msg . i } ) ; } /**
 * Set up a stream.
 */ function stream ( msg ) { streams [ msg . u ] = { buf : null , started : false , ended : false , headers : msg . h , onstart : null , readyForData : null , dataAvailable : null , timeout : null } ; } /**
 * Wait for this stream to start.
 */ async function waitStart ( msg ) { const stream = streams [ msg . u ] ; if ( ! stream ) return ; if ( stream . started ) return ; await new Promise < void > ( res => stream . onstart = res ) ; } /**
 * Send some data.
 */ async function data ( msg ) { const stream = streams [ msg . u ] ; if ( stream . timeout ) clearTimeout ( stream . timeout ) ; stream . timeout = setTimeout ( ( ) => { stream . ended = true ; if ( stream . dataAvailable ) stream . dataAvailable ( ) ; } , 30000 ) ; if ( msg . c === "keepalive" ) { return ; } while ( stream . buf ) { await new Promise < void > ( res => stream . readyForData = res ) ; stream . readyForData = null ; } if ( msg . c === "data" ) { stream . buf = msg . b ; } else { stream . ended = true ; } if ( stream . dataAvailable ) stream . dataAvailable ( ) ; } self . addEventListener ( "fetch" , ( ev ) => { const urlF = new URL ( ev . request . url ) ; const url = urlF . pathname ; if ( url . indexOf ( "/download-stream-service-worker/" ) !== 0 ) { return fetch ( url ) ; } if ( url . endsWith ( "/download-stream-service-worker-ping" ) ) { ev . respondWith ( new Response ( "pong" , { status : 200 , headers : { "content-type" : "text/plain" , "cross-origin-embedder-policy" : "require-corp" } } ) ) ; return ; } if ( url . endsWith ( "/download-stream-service-worker-pinger.html" ) ) { ev . respondWith ( new Response ( pinger , { status : 200 , headers : { "content-type" : "text/html" , "cross-origin-embedder-policy" : "require-corp" } } ) ) ; return ; } if ( ! ( url in streams ) ) { ev . respondWith ( new Response ( "404" , { status : 404 } ) ) ; return ; } const stream = streams [ url ] ; stream . started = true ; if ( stream . onstart ) stream . onstart ( ) ; ev . respondWith ( new Response ( new ReadableStream ( { async pull ( controller ) { while ( true ) { if ( stream . buf ) { controller . enqueue ( stream . buf ) ; stream . buf = null ; if ( stream . readyForData ) stream . readyForData ( ) ; break ; } else if ( stream . ended ) { controller . close ( ) ; break ; } else { await new Promise < void > ( res => stream . dataAvailable = res ) ; } } } } ) , { status : 200 , headers : stream . headers } ) ) ; } ) ;