@@ -7,8 +7,10 @@ import { createHash, randomUUID } from 'node:crypto';
77import { PDFDocument } from 'pdf-lib' ;
88import {
99 FileSafe ,
10+ InvalidAttachmentReceived ,
1011 PDFAnalysed ,
1112 validateFileSafe ,
13+ validateInvalidAttachmentReceived ,
1214 validatePDFAnalysed ,
1315} from 'digital-letters-events' ;
1416import { EventPublisher , Logger , getS3ObjectBufferFromUri } from 'utils' ;
@@ -81,6 +83,33 @@ function generateUpdatedEvent(event: FileSafe, pdfInfo: PdfInfo): PDFAnalysed {
8183 } ;
8284}
8385
86+ function generateInvalidAttachmentEvent (
87+ event : FileSafe ,
88+ ) : InvalidAttachmentReceived {
89+ const eventTime = new Date ( ) . toISOString ( ) ;
90+
91+ const {
92+ data : { messageReference, senderId } ,
93+ } = event ;
94+
95+ return {
96+ ...event ,
97+ id : randomUUID ( ) ,
98+ time : eventTime ,
99+ recordedtime : eventTime ,
100+ dataschema :
101+ 'https://notify.nhs.uk/cloudevents/schemas/digital-letters/2025-10-draft/data/digital-letters-print-invalid-attachment-received-data.schema.json' ,
102+ type : 'uk.nhs.notify.digital.letters.print.invalid.attachment.received.v1' ,
103+ // NOTE: CCM-13892 Generate event digital letters source property from scratch
104+ source : '/nhs/england/notify/production/primary/digitalletters/print' ,
105+ data : {
106+ senderId,
107+ messageReference,
108+ reasonCode : 'DL_CLIV_002' ,
109+ } ,
110+ } ;
111+ }
112+
84113async function analysePdf ( pdf : Buffer ) : Promise < PdfInfo > {
85114 const doc = await PDFDocument . load ( pdf ) ;
86115 const pageCount = doc . getPageCount ( ) ;
@@ -97,7 +126,7 @@ export const createHandler = ({
97126 const receivedItemCount = sqsEvent . Records . length ;
98127 const batchItemFailures : SQSBatchItemFailure [ ] = [ ] ;
99128 const validatedRecords : ValidatedRecord [ ] = [ ] ;
100- const validEvents : PDFAnalysed [ ] = [ ] ;
129+ const validEvents : ( PDFAnalysed | InvalidAttachmentReceived ) [ ] = [ ] ;
101130
102131 logger . info ( `Received SQS Event of ${ receivedItemCount } record(s)` ) ;
103132
@@ -120,16 +149,47 @@ export const createHandler = ({
120149 const pdfInfo = await analysePdf ( pdfBuffer ) ;
121150 validEvents . push ( generateUpdatedEvent ( event , pdfInfo ) ) ;
122151 } catch ( error : any ) {
123- logger . warn ( {
124- err : error . message ,
125- description : 'Failed processing message' ,
126- } ) ;
127- batchItemFailures . push ( { itemIdentifier : validatedRecord . messageId } ) ;
152+ const isPdfParsingError =
153+ error . message ?. includes ( 'PDF' ) ||
154+ error . message ?. includes ( 'parse' ) ||
155+ error . message ?. includes ( 'Invalid' ) ||
156+ error . name === 'PDFParsingError' ;
157+
158+ if ( isPdfParsingError ) {
159+ const invalidAttachmentEvent = generateInvalidAttachmentEvent (
160+ validatedRecord . event ,
161+ ) ;
162+ validEvents . push ( invalidAttachmentEvent ) ;
163+ logger . warn ( {
164+ messageReference : validatedRecord . event . data . messageReference ,
165+ reasonCode : 'DL_CLIV_002' ,
166+ description : 'Failed to analyze PDF - invalid attachment format' ,
167+ } ) ;
168+ } else {
169+ logger . warn ( {
170+ err : error . message ,
171+ description : 'Failed processing message' ,
172+ } ) ;
173+ batchItemFailures . push ( {
174+ itemIdentifier : validatedRecord . messageId ,
175+ } ) ;
176+ }
128177 }
129178 } ) ,
130179 ) ;
131180
132- await eventPublisher . sendEvents ( validEvents , validatePDFAnalysed ) ;
181+ await eventPublisher . sendEvents ( validEvents , ( event ) => {
182+ if ( event . type . includes ( 'pdf.analysed' ) ) {
183+ return validatePDFAnalysed ( event as PDFAnalysed , logger ) ;
184+ }
185+ if ( event . type . includes ( 'invalid.attachment.received' ) ) {
186+ return validateInvalidAttachmentReceived (
187+ event as InvalidAttachmentReceived ,
188+ logger ,
189+ ) ;
190+ }
191+ throw new Error ( `Unknown event type: ${ event . type } ` ) ;
192+ } ) ;
133193
134194 const processedItemCount = receivedItemCount - batchItemFailures . length ;
135195 logger . info (
0 commit comments