@@ -11,6 +11,17 @@ import {
1111 sanitizeIrcTarget ,
1212} from "./protocol.js" ;
1313
14+ function sliceIrcPrivmsgChunk ( text : string , end : number ) : string {
15+ const sliced = sliceUtf16Safe ( text , 0 , end ) ;
16+ if ( sliced || end <= 0 ) {
17+ return sliced ;
18+ }
19+ // A one-unit budget cannot contain an astral code point. Emit that point
20+ // whole so chunking advances without changing one-unit behavior for BMP text.
21+ const firstCodePoint = text . codePointAt ( 0 ) ;
22+ return firstCodePoint !== undefined && firstCodePoint > 0xffff ? text . slice ( 0 , 2 ) : sliced ;
23+ }
24+
1425const IRC_ERROR_CODES = new Set ( [ "432" , "464" , "465" ] ) ;
1526const IRC_NICK_COLLISION_CODES = new Set ( [ "433" , "436" ] ) ;
1627
@@ -108,8 +119,7 @@ export function buildIrcNickServCommands(options?: IrcNickServOptions): string[]
108119
109120export async function connectIrcClient ( options : IrcClientOptions ) : Promise < IrcClient > {
110121 const timeoutMs = options . connectTimeoutMs != null ? options . connectTimeoutMs : 15000 ;
111- // Two UTF-16 code units are the smallest budget that can hold one full code point.
112- const messageChunkMaxChars = Math . max ( 2 , Math . floor ( options . messageChunkMaxChars ?? 350 ) ) ;
122+ const messageChunkMaxChars = Math . max ( 1 , Math . floor ( options . messageChunkMaxChars ?? 350 ) ) ;
113123
114124 if ( ! options . host . trim ( ) ) {
115125 throw new Error ( "IRC host is required" ) ;
@@ -221,7 +231,7 @@ export async function connectIrcClient(options: IrcClientOptions): Promise<IrcCl
221231 if ( splitAt < Math . floor ( messageChunkMaxChars / 2 ) ) {
222232 splitAt = messageChunkMaxChars ;
223233 }
224- chunk = sliceUtf16Safe ( chunk , 0 , splitAt ) . trim ( ) ;
234+ chunk = sliceIrcPrivmsgChunk ( chunk , splitAt ) . trim ( ) ;
225235 }
226236 if ( ! chunk ) {
227237 break ;
0 commit comments