@@ -10,6 +10,7 @@ const log = getServiceLogger()
1010// Slack message size limit (keeping it conservative at 30KB)
1111const MAX_MESSAGE_SIZE = 30 * 1024 // 30KB in bytes
1212const MAX_BLOCKS = 50
13+ const MAX_SECTION_TEXT = 2900 // Slack hard limit is 3000 chars per section block
1314
1415interface SlackBlock {
1516 type : string
@@ -25,32 +26,52 @@ interface SlackBlock {
2526}
2627
2728/**
28- * Build content blocks from either a simple string or an array of sections
29+ * Split text into section blocks, respecting Slack's 3000 char per-section limit.
30+ * Splits at line boundaries where possible; hard-truncates individual lines that
31+ * are themselves longer than the limit.
32+ */
33+ function splitIntoSectionBlocks ( text : string ) : SlackBlock [ ] {
34+ const blocks : SlackBlock [ ] = [ ]
35+ const lines = text . split ( '\n' )
36+ let current = ''
37+
38+ for ( let line of lines ) {
39+ // Hard-truncate a single line that exceeds the limit on its own
40+ if ( line . length > MAX_SECTION_TEXT ) {
41+ line = `${ line . slice ( 0 , MAX_SECTION_TEXT - 1 ) } …`
42+ }
43+
44+ const candidate = current ? `${ current } \n${ line } ` : line
45+ if ( candidate . length > MAX_SECTION_TEXT && current ) {
46+ blocks . push ( { type : 'section' , text : { type : 'mrkdwn' , text : current } } )
47+ current = line
48+ } else {
49+ current = candidate
50+ }
51+ }
52+
53+ if ( current ) {
54+ blocks . push ( { type : 'section' , text : { type : 'mrkdwn' , text : current } } )
55+ }
56+
57+ return blocks
58+ }
59+
60+ /**
61+ * Build content blocks from either a simple string or an array of sections.
62+ * Splits text that exceeds Slack's 3000 char per-section limit at line boundaries.
2963 */
3064function buildContentBlocks ( content : string | SlackMessageSection [ ] ) : SlackBlock [ ] {
3165 if ( typeof content === 'string' ) {
32- // Simple string content - single section
33- return [
34- {
35- type : 'section' ,
36- text : {
37- type : 'mrkdwn' ,
38- text : content ,
39- } ,
40- } ,
41- ]
66+ return splitIntoSectionBlocks ( content )
4267 }
4368
44- // Multiple sections - create a block for each section
4569 const blocks : SlackBlock [ ] = [ ]
4670 for ( const section of content ) {
47- blocks . push ( {
48- type : 'section' ,
49- text : {
50- type : 'mrkdwn' ,
51- text : `*${ section . title } *\n${ section . text } ` ,
52- } ,
53- } )
71+ const fullText = `*${ section . title } *\n${ section . text } `
72+ for ( const block of splitIntoSectionBlocks ( fullText ) ) {
73+ blocks . push ( block )
74+ }
5475 }
5576 return blocks
5677}
0 commit comments