@@ -2554,6 +2554,7 @@ async function configureDiscordSmoke(params) {
25542554export async function readBoundedCrossOsResponseText (
25552555 response : Response ,
25562556 maxChars = CROSS_OS_FETCH_BODY_MAX_CHARS ,
2557+ options : { signal ?: AbortSignal | null } = { } ,
25572558) : Promise < string > {
25582559 if ( ! response . body ) {
25592560 return "" ;
@@ -2563,10 +2564,11 @@ export async function readBoundedCrossOsResponseText(
25632564 const decoder = new TextDecoder ( ) ;
25642565 let text = "" ;
25652566 let truncated = false ;
2567+ let aborted = false ;
25662568
25672569 try {
25682570 while ( text . length <= maxChars ) {
2569- const { done, value } = await reader . read ( ) ;
2571+ const { done, value } = await readCrossOsResponseChunk ( reader , options . signal ) ;
25702572 if ( done ) {
25712573 text += decoder . decode ( ) ;
25722574 break ;
@@ -2579,8 +2581,11 @@ export async function readBoundedCrossOsResponseText(
25792581 break ;
25802582 }
25812583 }
2584+ } catch ( error ) {
2585+ aborted = options . signal ?. aborted === true ;
2586+ throw error ;
25822587 } finally {
2583- if ( truncated ) {
2588+ if ( truncated || aborted ) {
25842589 await reader . cancel ( ) . catch ( ( ) => undefined ) ;
25852590 } else {
25862591 reader . releaseLock ( ) ;
@@ -2590,6 +2595,36 @@ export async function readBoundedCrossOsResponseText(
25902595 return truncated ? `${ text } \n[truncated]` : text ;
25912596}
25922597
2598+ function readCrossOsResponseChunk (
2599+ reader : ReadableStreamDefaultReader < Uint8Array > ,
2600+ signal ?: AbortSignal | null ,
2601+ ) : Promise < ReadableStreamReadResult < Uint8Array >> {
2602+ if ( ! signal ) {
2603+ return reader . read ( ) ;
2604+ }
2605+ if ( signal . aborted ) {
2606+ throw crossOsAbortReason ( signal ) ;
2607+ }
2608+ return new Promise ( ( resolveRead , rejectRead ) => {
2609+ const onAbort = ( ) => rejectRead ( crossOsAbortReason ( signal ) ) ;
2610+ signal . addEventListener ( "abort" , onAbort , { once : true } ) ;
2611+ reader
2612+ . read ( )
2613+ . then ( resolveRead , rejectRead )
2614+ . finally ( ( ) => {
2615+ signal . removeEventListener ( "abort" , onAbort ) ;
2616+ } ) ;
2617+ } ) ;
2618+ }
2619+
2620+ function crossOsAbortReason ( signal : AbortSignal ) : Error {
2621+ const reason = signal . reason ;
2622+ if ( reason instanceof Error ) {
2623+ return reason ;
2624+ }
2625+ return new Error ( typeof reason === "string" ? reason : "The operation was aborted." ) ;
2626+ }
2627+
25932628export function dashboardHtmlMarkerStatus ( html : string ) : {
25942629 app: boolean ;
25952630 ready: boolean ;
@@ -2647,11 +2682,12 @@ async function waitForDiscordMessage(params) {
26472682 let response ;
26482683 let text ;
26492684 try {
2685+ const init = buildDiscordFetchInit ( params . token ) ;
26502686 response = await fetch (
26512687 `https://discord.com/api/v10/channels/${ params . channelId } /messages?limit=20` ,
2652- buildDiscordFetchInit ( params . token ) ,
2688+ init ,
26532689 ) ;
2654- text = await readBoundedCrossOsResponseText ( response ) ;
2690+ text = await readBoundedCrossOsResponseText ( response , undefined , { signal : init . signal } ) ;
26552691 } catch {
26562692 await sleep ( 2_000 ) ;
26572693 continue ;
@@ -2680,20 +2716,21 @@ export function buildDiscordFetchInit(token, init = {}) {
26802716}
26812717
26822718async function postDiscordMessage ( params ) {
2719+ const init = buildDiscordFetchInit ( params . token , {
2720+ method : "POST" ,
2721+ headers : {
2722+ "Content-Type" : "application/json" ,
2723+ } ,
2724+ body : JSON . stringify ( {
2725+ content : params . content ,
2726+ flags : 4096 ,
2727+ } ) ,
2728+ } ) ;
26832729 const response = await fetch (
26842730 `https://discord.com/api/v10/channels/${ params . channelId } /messages` ,
2685- buildDiscordFetchInit ( params . token , {
2686- method : "POST" ,
2687- headers : {
2688- "Content-Type" : "application/json" ,
2689- } ,
2690- body : JSON . stringify ( {
2691- content : params . content ,
2692- flags : 4096 ,
2693- } ) ,
2694- } ) ,
2731+ init ,
26952732 ) ;
2696- const text = await readBoundedCrossOsResponseText ( response ) ;
2733+ const text = await readBoundedCrossOsResponseText ( response , undefined , { signal : init . signal } ) ;
26972734 if ( ! response . ok ) {
26982735 throw new Error ( `Failed to post Discord smoke message: ${ text } ` ) ;
26992736 }
@@ -3525,10 +3562,11 @@ async function runDashboardSmoke(params) {
35253562 attempt += 1 ;
35263563 logStream . write ( `${ new Date ( ) . toISOString ( ) } attempt=${ attempt } url=${ dashboardUrl } \n` ) ;
35273564 try {
3565+ const signal = AbortSignal . timeout ( CROSS_OS_DASHBOARD_FETCH_TIMEOUT_MS ) ;
35283566 const response = await fetch ( dashboardUrl , {
3529- signal : AbortSignal . timeout ( CROSS_OS_DASHBOARD_FETCH_TIMEOUT_MS ) ,
3567+ signal,
35303568 } ) ;
3531- const html = await readBoundedCrossOsResponseText ( response ) ;
3569+ const html = await readBoundedCrossOsResponseText ( response , undefined , { signal } ) ;
35323570 const markers = dashboardHtmlMarkerStatus ( html ) ;
35333571 const assetUrls = resolveDashboardAssetUrls ( dashboardUrl , html ) ;
35343572 if ( response . ok && markers . ready ) {
0 commit comments