@@ -1459,8 +1459,14 @@ describe('Bun Serve Integration', () => {
14591459 describe ( 'sessions' , ( ) => {
14601460 type SessionCounts = Omit < AggregationCounts , 'started' > ;
14611461
1462- function setupSessionClient ( options ?: BunOptions ) : { client : SentryCore . Client ; sessions : SessionCounts [ ] } {
1462+ function setupSessionClient ( options ?: BunOptions ) : {
1463+ client : SentryCore . Client ;
1464+ sessions : SessionCounts [ ] ;
1465+ firstSession : Promise < void > ;
1466+ } {
14631467 const sessions : SessionCounts [ ] = [ ] ;
1468+ let resolveFirstSession : ( ) => void ;
1469+ const firstSession = new Promise < void > ( resolve => ( resolveFirstSession = resolve ) ) ;
14641470 setupClient ( {
14651471 release : '1.0.0' ,
14661472 integrations : [ bunServerIntegration ( ) ] ,
@@ -1474,12 +1480,13 @@ describe('Bun Serve Integration', () => {
14741480 . aggregates ) {
14751481 sessions . push ( counts ) ;
14761482 }
1483+ resolveFirstSession ( ) ;
14771484 }
14781485 } ) ;
14791486 return SentryCore . resolvedSyncPromise ( { } ) ;
14801487 } ) ,
14811488 } ) ;
1482- return { client : SentryCore . getClient ( ) ! , sessions } ;
1489+ return { client : SentryCore . getClient ( ) ! , sessions, firstSession } ;
14831490 }
14841491
14851492 test ( 'records an exited session for a successful request' , async ( ) => {
@@ -1533,6 +1540,35 @@ describe('Bun Serve Integration', () => {
15331540 expect ( sessions ) . toEqual ( [ { exited : 0 , errored : 0 , crashed : 1 } ] ) ;
15341541 } ) ;
15351542
1543+ test . each ( [
1544+ [ 'when tracing is enabled' , { } ] ,
1545+ [ 'when tracing is disabled' , { tracesSampleRate : undefined } ] ,
1546+ ] as const ) ( 'records a crashed session when a streamed response source fails %s' , async ( _label , options ) => {
1547+ const { client, sessions } = setupSessionClient ( options ) ;
1548+ let controller : ReadableStreamDefaultController < Uint8Array > ;
1549+ const source = new ReadableStream < Uint8Array > ( {
1550+ start ( value ) {
1551+ controller = value ;
1552+ } ,
1553+ } ) ;
1554+ const server = Bun . serve ( {
1555+ port,
1556+ fetch : ( ) => new Response ( source , { headers : { 'content-type' : 'text/event-stream' } } ) ,
1557+ } ) ;
1558+ try {
1559+ const response = await server . fetch ( new Request ( `http://localhost:${ port } /events` ) ) ;
1560+ const error = new Error ( 'stream interrupted' ) ;
1561+ const text = response . text ( ) ;
1562+ controller ! . error ( error ) ;
1563+ await expect ( text ) . rejects . toBe ( error ) ;
1564+ } finally {
1565+ await server . stop ( true ) ;
1566+ }
1567+ await client . flush ( ) ;
1568+
1569+ expect ( sessions ) . toEqual ( [ { exited : 0 , errored : 0 , crashed : 1 } ] ) ;
1570+ } ) ;
1571+
15361572 test ( 'records sessions for OPTIONS and HEAD requests' , async ( ) => {
15371573 const { client, sessions } = setupSessionClient ( ) ;
15381574 const server = Bun . serve ( { port, fetch : ( ) => new Response ( 'ok' ) } ) ;
@@ -1578,7 +1614,7 @@ describe('Bun Serve Integration', () => {
15781614 } ) ;
15791615
15801616 test ( 'sends the session aggregate after sessionFlushingDelayMS' , async ( ) => {
1581- const { sessions } = setupSessionClient ( {
1617+ const { sessions, firstSession } = setupSessionClient ( {
15821618 integrations : [ bunServerIntegration ( { sessionFlushingDelayMS : 50 } ) ] ,
15831619 } ) ;
15841620 const server = Bun . serve ( { port, fetch : ( ) => new Response ( 'ok' ) } ) ;
@@ -1588,8 +1624,16 @@ describe('Bun Serve Integration', () => {
15881624 await server . stop ( true ) ;
15891625 }
15901626
1591- // No flush here. With the default 60s delay, no session arrives in time.
1592- await new Promise ( resolve => setTimeout ( resolve , 200 ) ) ;
1627+ // No flush here. The timeout only bounds a failure. With the default 60s delay, no session
1628+ // arrives within it.
1629+ let timeoutId : ReturnType < typeof setTimeout > | undefined ;
1630+ const timedOut = new Promise < 'timed out' > ( resolve => {
1631+ timeoutId = setTimeout ( ( ) => resolve ( 'timed out' ) , 2_000 ) ;
1632+ } ) ;
1633+ const result = await Promise . race ( [ firstSession . then ( ( ) => 'sent' as const ) , timedOut ] ) ;
1634+ clearTimeout ( timeoutId ) ;
1635+
1636+ expect ( result ) . toBe ( 'sent' ) ;
15931637 expect ( sessions ) . toEqual ( [ { exited : 1 , errored : 0 , crashed : 0 } ] ) ;
15941638 } ) ;
15951639
0 commit comments