@@ -39,9 +39,24 @@ export default class SentryEventWorker extends Worker {
3939
4040 const [ headers , items ] = envelope ;
4141
42+ if ( items . length === 0 ) {
43+ this . logger . warn ( 'Received envelope with no items' ) ;
44+ return ;
45+ }
46+
47+ let processedCount = 0 ;
48+ let skippedCount = 0 ;
49+
4250 for ( const item of items ) {
43- await this . handleEnvelopeItem ( headers , item , event . projectId ) ;
51+ const result = await this . handleEnvelopeItem ( headers , item , event . projectId ) ;
52+ if ( result === 'processed' ) {
53+ processedCount ++ ;
54+ } else if ( result === 'skipped' ) {
55+ skippedCount ++ ;
56+ }
4457 }
58+
59+ this . logger . verbose ( `Processed ${ processedCount } events, skipped ${ skippedCount } non-event items from envelope` ) ;
4560 } catch ( error ) {
4661 this . logger . error ( `Error handling Sentry event task:` , error ) ;
4762 this . logger . info ( '👇 Here is the problematic event:' ) ;
@@ -99,8 +114,9 @@ export default class SentryEventWorker extends Worker {
99114 * @param envelopeHeaders - The whole envelope headers
100115 * @param item - Sentry item
101116 * @param projectId - Sentry project ID
117+ * @returns 'processed' if event was sent, 'skipped' if non-event item, throws error on failure
102118 */
103- private async handleEnvelopeItem ( envelopeHeaders : Envelope [ 0 ] , item : EnvelopeItem , projectId : string ) : Promise < void > {
119+ private async handleEnvelopeItem ( envelopeHeaders : Envelope [ 0 ] , item : EnvelopeItem , projectId : string ) : Promise < 'processed' | 'skipped' > {
104120 try {
105121 const [ itemHeader , itemPayload ] = item ;
106122
@@ -112,7 +128,8 @@ export default class SentryEventWorker extends Worker {
112128 * Skip non-event items
113129 */
114130 if ( itemHeader . type !== 'event' ) {
115- return ;
131+ this . logger . info ( `Skipping non-event item of type: ${ itemHeader . type } ` ) ;
132+ return 'skipped' ;
116133 }
117134 const payloadHasSDK = typeof itemPayload === 'object' && 'sdk' in itemPayload ;
118135
@@ -121,18 +138,53 @@ export default class SentryEventWorker extends Worker {
121138 */
122139 const sentryJsSDK = [ 'browser' , 'react' , 'vue' , 'angular' , 'capacirtor' , 'electron' ] ;
123140
124- const isJsSDK = payloadHasSDK && sentryJsSDK . includes ( itemPayload . sdk . name ) ;
141+ /**
142+ * Safely check if SDK name exists and is in the list
143+ * SDK name can be either a simple name like "react" or a full name like "sentry.javascript.react"
144+ */
145+ const sdkName = payloadHasSDK && itemPayload . sdk && typeof itemPayload . sdk === 'object' && 'name' in itemPayload . sdk
146+ ? itemPayload . sdk . name
147+ : undefined ;
148+
149+ /**
150+ * Check if SDK is a JavaScript-related SDK
151+ * Supports both simple names (e.g., "react") and full names (e.g., "sentry.javascript.react")
152+ */
153+ const isJsSDK = sdkName !== undefined && typeof sdkName === 'string' && (
154+ /**
155+ * Exact match for simple SDK names (e.g., "react", "browser")
156+ */
157+ sentryJsSDK . includes ( sdkName ) ||
158+ /**
159+ * Check if SDK name contains one of the JS SDK names
160+ * Examples:
161+ * - "sentry.javascript.react" matches "react"
162+ * - "sentry.javascript.browser" matches "browser"
163+ * - "@sentry/react" matches "react"
164+ */
165+ sentryJsSDK . some ( ( jsSDK ) => sdkName . includes ( jsSDK ) )
166+ ) ;
125167
126168 const hawkEvent = this . transformToHawkFormat ( envelopeHeaders as EventEnvelope [ 0 ] , item as EventItem , projectId , isJsSDK ) ;
127169
128170 /**
129- * If we have release attached to the event
171+ * Send task to appropriate worker and check if it was successfully queued
130172 */
131- if ( isJsSDK ) {
132- await this . addTask ( WorkerNames . JAVASCRIPT , hawkEvent as JavaScriptEventWorkerTask ) ;
133- } else {
134- await this . addTask ( WorkerNames . DEFAULT , hawkEvent as DefaultEventWorkerTask ) ;
173+ const workerName = isJsSDK ? WorkerNames . JAVASCRIPT : WorkerNames . DEFAULT ;
174+ const taskSent = await this . addTask ( workerName , hawkEvent as JavaScriptEventWorkerTask | DefaultEventWorkerTask ) ;
175+
176+ if ( ! taskSent ) {
177+ /**
178+ * If addTask returns false, the message was not queued (queue full or channel closed)
179+ */
180+ const error = new Error ( `Failed to queue event to ${ workerName } worker. Queue may be full or channel closed.` ) ;
181+ this . logger . error ( error . message ) ;
182+ this . logger . info ( '👇 Here is the event that failed to queue:' ) ;
183+ this . logger . json ( hawkEvent ) ;
184+ throw error ;
135185 }
186+
187+ return 'processed' ;
136188 } catch ( error ) {
137189 this . logger . error ( 'Error handling envelope item:' , error ) ;
138190 this . logger . info ( '👇 Here is the problematic item:' ) ;
@@ -162,7 +214,14 @@ export default class SentryEventWorker extends Worker {
162214 * convert sent_at from ISO 8601 to Unix timestamp
163215 */
164216 const msInSecond = 1000 ;
165- const sentAtUnix = Math . floor ( new Date ( sent_at ) . getTime ( ) / msInSecond ) ;
217+ const sentAtDate = new Date ( sent_at ) ;
218+ const sentAtTime = sentAtDate . getTime ( ) ;
219+
220+ if ( isNaN ( sentAtTime ) ) {
221+ throw new Error ( `Invalid sent_at timestamp: ${ sent_at } ` ) ;
222+ }
223+
224+ const sentAtUnix = Math . floor ( sentAtTime / msInSecond ) ;
166225 /* eslint-enable @typescript-eslint/naming-convention */
167226
168227 // eslint-disable-next-line @typescript-eslint/no-unused-vars, no-unused-vars
@@ -175,9 +234,18 @@ export default class SentryEventWorker extends Worker {
175234 * We need to decode it to JSON
176235 */
177236 if ( eventPayload instanceof Uint8Array ) {
178- const textDecoder = new TextDecoder ( ) ;
237+ try {
238+ const textDecoder = new TextDecoder ( ) ;
239+ const decoded = textDecoder . decode ( eventPayload as Uint8Array ) ;
179240
180- eventPayload = JSON . parse ( textDecoder . decode ( eventPayload as Uint8Array ) ) ;
241+ try {
242+ eventPayload = JSON . parse ( decoded ) ;
243+ } catch ( parseError ) {
244+ throw new Error ( `Failed to parse event payload JSON: ${ parseError instanceof Error ? parseError . message : String ( parseError ) } ` ) ;
245+ }
246+ } catch ( decodeError ) {
247+ throw new Error ( `Failed to decode Uint8Array event payload: ${ decodeError instanceof Error ? decodeError . message : String ( decodeError ) } ` ) ;
248+ }
181249 }
182250
183251 const title = composeTitle ( eventPayload ) ;
0 commit comments