@@ -84,7 +84,6 @@ const ConversationPageSchema = z
8484 . passthrough ( )
8585 . optional ( ) ,
8686 _links : LinksSchema ,
87- page : z . object ( { totalElements : z . number ( ) . optional ( ) } ) . passthrough ( ) . optional ( ) ,
8887 } )
8988 . passthrough ( )
9089
@@ -219,7 +218,9 @@ function conversationChangeMarker(conversation: HelpScoutConversation): string {
219218 conversation . preview ?? '' ,
220219 conversation . mailboxId ?? '' ,
221220 conversation . assignee ?. id ?? '' ,
221+ conversation . assignee ? personName ( conversation . assignee ) : '' ,
222222 conversation . primaryCustomer ?. email ?? '' ,
223+ conversation . primaryCustomer ? personName ( conversation . primaryCustomer ) : '' ,
223224 ( conversation . tags ?? [ ] )
224225 . map ( ( tag ) => tag . tag ?? '' )
225226 . sort ( compareStrings )
@@ -335,8 +336,6 @@ export const helpScoutConnector: ConnectorConfig = {
335336 const seen = new Set < number > ( )
336337 const documents : ExternalDocument [ ] = [ ]
337338 let capped = false
338- let firstTotal : number | undefined
339- let lastTotal : number | undefined
340339 const maxPages = Math . ceil ( maxConversations / CONVERSATIONS_PER_PAGE ) + 5
341340
342341 for ( let page = 1 ; ; page ++ ) {
@@ -351,8 +350,6 @@ export const helpScoutConnector: ConnectorConfig = {
351350 const data = ConversationPageSchema . parse (
352351 await helpScoutGet ( '/conversations' , accessToken , query )
353352 )
354- lastTotal = data . page ?. totalElements
355- if ( page === 1 ) firstTotal = lastTotal
356353 for ( const conversation of data . _embedded ?. conversations ?? [ ] ) {
357354 if ( seen . has ( conversation . id ) || ! isIndexedConversation ( conversation ) ) continue
358355 if ( documents . length >= maxConversations ) {
@@ -369,25 +366,21 @@ export const helpScoutConnector: ConnectorConfig = {
369366 }
370367 }
371368
372- /**
373- * Pages are numbered, so a conversation that leaves the filtered set mid-scan shifts later
374- * ones up a page and one can be skipped. A changed total means that may have happened, so
375- * this listing must not drive deletion.
376- */
377- const totalChanged = firstTotal !== undefined && lastTotal !== firstTotal
378- if ( syncContext ) {
379- if ( capped ) syncContext . listingCapped = true
380- if ( totalChanged ) syncContext . reconciliationUnsafe = true
381- }
369+ if ( capped && syncContext ) syncContext . listingCapped = true
382370 if ( capped ) {
383- logger . warn (
384- 'Help Scout listing truncated by Max Conversations; skipping deletion reconciliation' ,
385- { count : documents . length , maxConversations }
386- )
371+ logger . warn ( 'Help Scout listing truncated by Max Conversations' , {
372+ count : documents . length ,
373+ maxConversations,
374+ } )
387375 } else {
388- logger . info ( 'Listed Help Scout conversations' , { count : documents . length , totalChanged } )
376+ logger . info ( 'Listed Help Scout conversations' , { count : documents . length } )
389377 }
390- return { documents, hasMore : false }
378+ /**
379+ * Pages are numbered, so a conversation that leaves the filtered set mid-scan shifts later
380+ * ones up a page and one can be skipped even when the total stays the same. Absence from
381+ * this listing is therefore never treated as a deletion.
382+ */
383+ return { documents, hasMore : false , reconciliationSafe : false }
391384 } ,
392385
393386 getDocument : async (
@@ -402,7 +395,9 @@ export const helpScoutConnector: ConnectorConfig = {
402395 await helpScoutGet ( `/conversations/${ externalId } ` , accessToken )
403396 )
404397 // A merged conversation redirects to the conversation it was merged into.
405- if ( conversation . state === 'deleted' || String ( conversation . id ) !== externalId ) return null
398+ if ( ! isIndexedConversation ( conversation ) || String ( conversation . id ) !== externalId ) {
399+ return null
400+ }
406401 const threads = ( await listThreads ( externalId , accessToken ) ) . filter ( ( thread ) =>
407402 isIndexedThread ( thread , includeNotes )
408403 )
0 commit comments