@@ -30,9 +30,7 @@ interface SentryRequestCallbackData {
3030}
3131
3232interface EventCallbackListener {
33- callback : ( data : string ) => void ;
34- /** Timestamp when this listener was registered. Only events after this time should be sent. */
35- registeredAt : number ;
33+ ( data : string ) : void ;
3634}
3735
3836type SentryResponseStatusCode = number ;
@@ -93,16 +91,10 @@ export async function startProxyServer(
9391 const callback : OnRequest =
9492 onRequest ||
9593 ( async ( eventCallbackListeners , proxyRequest , proxyRequestBody , eventBuffer ) => {
96- const eventTimestamp = getTimestamp ( ) ;
97- eventBuffer . push ( { data : proxyRequestBody , timestamp : eventTimestamp } ) ;
94+ eventBuffer . push ( { data : proxyRequestBody , timestamp : getTimestamp ( ) } ) ;
9895
99- // Send to listeners that registered BEFORE or AT THE SAME TIME as this event.
100- // Use >= for live events because they're guaranteed to be new (not stale).
101- // The strict > is only needed for buffered events which might be from before.
10296 eventCallbackListeners . forEach ( listener => {
103- if ( eventTimestamp >= listener . registeredAt ) {
104- listener . callback ( proxyRequestBody ) ;
105- }
97+ listener ( proxyRequestBody ) ;
10698 } ) ;
10799
108100 return [ 200 , '{}' , { } ] ;
@@ -134,38 +126,26 @@ export async function startProxyServer(
134126 eventCallbackResponse . statusCode = 200 ;
135127 eventCallbackResponse . setHeader ( 'connection' , 'keep-alive' ) ;
136128
137- // CRITICAL: Use the SERVER's current time when the listener is actually registered,
138- // NOT the client timestamp from the query param. Due to network latency, events may
139- // have been buffered between when the client generated its timestamp and when the
140- // HTTP request reached this server. Using server time ensures we only get events
141- // that arrived AFTER the listener was actually registered on the server.
142- const listenerTimestamp = getTimestamp ( ) ;
129+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
130+ const searchParams = new URL ( eventCallbackRequest . url ! , 'http://justsomerandombasesothattheurlisparseable.com/' )
131+ . searchParams ;
132+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
133+ const listenerTimestamp = Number ( searchParams . get ( 'timestamp' ) ! ) ;
143134
144- const callbackListener : EventCallbackListener = {
145- callback : ( data : string ) : void => {
146- eventCallbackResponse . write ( data . concat ( '\n' ) , 'utf8' ) ;
147- } ,
148- registeredAt : listenerTimestamp ,
135+ const callbackListener = ( data : string ) : void => {
136+ eventCallbackResponse . write ( data . concat ( '\n' ) , 'utf8' ) ;
149137 } ;
150138
151139 eventCallbackListeners . add ( callbackListener ) ;
152140
153- // Prune old events from the buffer that are definitely stale (strictly older than this listener).
154- // Use strict < to match the live event behavior (>= at line 103) - same-ms events are kept.
155- // This prevents memory buildup and ensures old events can never leak to future listeners.
156- while ( eventBuffer . length > 0 ) {
157- const firstEvent = eventBuffer [ 0 ] ;
158- if ( firstEvent && firstEvent . timestamp < listenerTimestamp ) {
159- eventBuffer . shift ( ) ;
160- } else {
161- break ;
162- }
163- }
164-
165- // Send any remaining buffered events (those that arrived after this listener was registered,
166- // which can happen due to race conditions with HTTP request processing).
141+ // Use strict inequality to prevent stale events from previous tests leaking through.
142+ // If a previous test's event was buffered at the same millisecond as this listener started,
143+ // we want to exclude it. New events arriving after the listener is registered go through
144+ // the callback directly (not the buffer), so they're not affected by this filter.
167145 eventBuffer . forEach ( bufferedEvent => {
168- callbackListener . callback ( bufferedEvent . data ) ;
146+ if ( bufferedEvent . timestamp > listenerTimestamp ) {
147+ callbackListener ( bufferedEvent . data ) ;
148+ }
169149 } ) ;
170150
171151 eventCallbackRequest . on ( 'close' , ( ) => {
@@ -214,16 +194,10 @@ export async function startEventProxyServer(options: EventProxyServerOptions): P
214194
215195 const dataString = Buffer . from ( JSON . stringify ( data ) ) . toString ( 'base64' ) ;
216196
217- const eventTimestamp = getTimestamp ( ) ;
218- eventBuffer . push ( { data : dataString , timestamp : eventTimestamp } ) ;
197+ eventBuffer . push ( { data : dataString , timestamp : getTimestamp ( ) } ) ;
219198
220- // Send to listeners that registered BEFORE or AT THE SAME TIME as this event.
221- // Use >= for live events because they're guaranteed to be new (not stale).
222- // The strict > is only needed for buffered events which might be from before.
223199 eventCallbackListeners . forEach ( listener => {
224- if ( eventTimestamp >= listener . registeredAt ) {
225- listener . callback ( dataString ) ;
226- }
200+ listener ( dataString ) ;
227201 } ) ;
228202
229203 if ( options . envelopeDumpPath ) {
0 commit comments