@@ -51,8 +51,9 @@ app.post("/api/webhook/:userPath", (req: Request, res: Response) => {
5151 }
5252 }
5353
54- // Event Grid sends an array of events in the body
55- const events = Array . isArray ( req . body ) ? req . body : [ req . body ] ;
54+ // Event Grid usually sends an array, but some proxies or transports may send a single
55+ // object. Normalize to an array for easier handling.
56+ const events = Array . isArray ( req . body ) ? req . body : req . body ? [ req . body ] : [ ] ;
5657
5758 // Save last request for diagnostics
5859 try {
@@ -69,26 +70,51 @@ app.post("/api/webhook/:userPath", (req: Request, res: Response) => {
6970 // ignore
7071 }
7172
72- // Azure Event Grid subscription validation can arrive in two common shapes:
73- // 1) Standard validation event: an array with eventType === 'Microsoft.EventGrid.SubscriptionValidationEvent'
74- // 2) A special header 'aeg-event-type: SubscriptionValidation' with the events array
75- // Handle both cases robustly.
76- const validationEvent = events . find ( ( e : any ) => e && ( e . eventType === 'Microsoft.EventGrid.SubscriptionValidationEvent' || e . eventType === 'Microsoft.EventGridSubscriptionValidationEvent' ) ) ;
73+ // Helper: extract validation code from an event object in a forgiving way.
74+ const extractValidationCode = ( ev : any ) : string | undefined => {
75+ if ( ! ev ) return undefined ;
76+ // Common places: ev.data.validationCode (case variants)
77+ const data = ev . data || ev . Data || ev . DATA || ev ;
78+ if ( data && typeof data === 'object' ) {
79+ for ( const key of Object . keys ( data ) ) {
80+ if ( key . toLowerCase ( ) === 'validationcode' && data [ key ] ) return String ( data [ key ] ) ;
81+ }
82+ }
83+ // Some transports may put the code at the top-level
84+ for ( const key of Object . keys ( ev ) ) {
85+ if ( key . toLowerCase ( ) === 'validationcode' && ev [ key ] ) return String ( ev [ key ] ) ;
86+ }
87+ return undefined ;
88+ } ;
89+
90+ // Event Grid subscription validation can arrive as:
91+ // - an event in the array with eventType matching expected strings
92+ // - header-based flows where 'aeg-event-type' tells us it's a validation attempt
93+ // Try to find any validation code in the incoming payloads.
94+ const validationEvent = events . find ( ( e : any ) => {
95+ if ( ! e ) return false ;
96+ const et = ( e . eventType || e . EventType || '' ) . toString ( ) ;
97+ return (
98+ et === 'Microsoft.EventGrid.SubscriptionValidationEvent' ||
99+ et === 'Microsoft.EventGridSubscriptionValidationEvent' ||
100+ et === 'Microsoft.EventGrid.SubscriptionValidation' ||
101+ et . toLowerCase ( ) . includes ( 'subscriptionvalidation' )
102+ ) ;
103+ } ) ;
104+
77105 if ( validationEvent ) {
78- const data = validationEvent . data || { } ;
79- console . log ( `EventGrid subscription validation for ${ userPath } :` , data ) ;
80- return res . status ( 200 ) . json ( { validationResponse : data . validationCode } ) ;
106+ const code = extractValidationCode ( validationEvent ) || ( validationEvent . data && validationEvent . data . validationCode ) || undefined ;
107+ console . log ( `EventGrid subscription validation (event) for ${ userPath } :` , validationEvent ?. data || validationEvent , '=> code=' , code ) ;
108+ if ( code ) return res . status ( 200 ) . json ( { validationResponse : code } ) ;
81109 }
82110
83- // Also handle the header-based SubscriptionValidation flow
111+ // Also handle the header-based SubscriptionValidation flow: check aeg header and try first event
84112 const aegHeader = ( req . header ( 'aeg-event-type' ) || '' ) . toString ( ) ;
85- if ( aegHeader === 'SubscriptionValidation' && Array . isArray ( events ) && events . length > 0 ) {
113+ if ( aegHeader && aegHeader . toLowerCase ( ) . includes ( 'subscriptionvalidation' ) && events . length > 0 ) {
86114 const maybe = events [ 0 ] as any ;
87- const code = maybe && maybe . data && ( maybe . data . validationCode || maybe . data . validationcode || maybe . data . ValidationCode ) ;
88- if ( code ) {
89- console . log ( `EventGrid header-based validation for ${ userPath } :` , code ) ;
90- return res . status ( 200 ) . json ( { validationResponse : code } ) ;
91- }
115+ const code = extractValidationCode ( maybe ) ;
116+ console . log ( `EventGrid header-based validation for ${ userPath } : aeg=${ aegHeader } =>` , maybe , '=> code=' , code ) ;
117+ if ( code ) return res . status ( 200 ) . json ( { validationResponse : code } ) ;
92118 }
93119
94120 // Normal events: log and ack
0 commit comments