export const DEFAULT_ROW_LIMIT = 100 export const MAX_ROW_LIMIT = 1000 export const clampLimit = ( requested: number | undefined, fallback = DEFAULT_ROW_LIMIT, max = MAX_ROW_LIMIT ): number => { if (requested === undefined) { return fallback } return Math.max(1, Math.min(Math.trunc(requested), max)) } export const truncateRows = (rows: T[], limit: number): { rows: T[]; truncated: boolean } => rows.length > limit ? { rows: rows.slice(0, limit), truncated: true } : { rows, truncated: false } // Slice a string to at most `maxBytes` UTF-8 bytes without splitting a // multi-byte sequence (back off to a code-point boundary). export const sliceUtf8 = (s: string, maxBytes: number): string => { const buf = Buffer.from(s, 'utf8') if (buf.length <= maxBytes) { return s } let end = maxBytes while (end > 0 && (buf[end] & 0xc0) === 0x80) { end -= 1 } return buf.subarray(0, end).toString('utf8') } // Serialize `value` to JSON and, if it exceeds `maxBytes` (UTF-8), return a // truncated marker object whose own serialization stays within `maxBytes`. export const truncateJsonBudget = ( value: unknown, maxBytes: number ): { body: unknown; truncated: boolean } => { const text = JSON.stringify(value) if (text === undefined) { return { body: value, truncated: false } } const bytes = Buffer.byteLength(text, 'utf8') if (bytes <= maxBytes) { return { body: value, truncated: false } } const RESERVE = 256 const preview = sliceUtf8(text, Math.max(0, maxBytes - RESERVE)) return { body: { _truncated: true, _originalBytes: bytes, _maxBytes: maxBytes, preview }, truncated: true } }