@frost1994/agentic-core 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.md +32 -0
- package/dist/client.cjs +6 -0
- package/dist/client.cjs.map +1 -0
- package/dist/client.d.ts +149 -0
- package/dist/client.js +6 -0
- package/dist/client.js.map +1 -0
- package/dist/index-CesPelb5.js +619 -0
- package/dist/index-CesPelb5.js.map +1 -0
- package/dist/index-DHqclwK8.cjs +618 -0
- package/dist/index-DHqclwK8.cjs.map +1 -0
- package/dist/index.cjs +605 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +904 -0
- package/dist/index.js +606 -0
- package/dist/index.js.map +1 -0
- package/dist/protocol.cjs +2 -0
- package/dist/protocol.cjs.map +1 -0
- package/dist/protocol.d.ts +298 -0
- package/dist/protocol.js +2 -0
- package/dist/protocol.js.map +1 -0
- package/package.json +64 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-DHqclwK8.cjs","sources":["../src/errors/index.ts","../src/utils/index.ts","../src/client/sql-guard.ts","../src/client/index.ts"],"sourcesContent":["/**\r\n * Error system for AI Assistant Core\r\n *\r\n * All error codes with retriability classification.\r\n */\r\n\r\nexport const ErrorCodes = {\r\n NETWORK: 'NETWORK',\r\n TIMEOUT: 'TIMEOUT',\r\n AUTH: 'AUTH',\r\n FORBIDDEN: 'FORBIDDEN',\r\n RATE_LIMIT: 'RATE_LIMIT',\r\n MODEL_UNAVAILABLE: 'MODEL_UNAVAILABLE',\r\n TOOL_FAILED: 'TOOL_FAILED',\r\n SQL_FORBIDDEN: 'SQL_FORBIDDEN',\r\n SQL_SENSITIVE: 'SQL_SENSITIVE',\r\n PARSE: 'PARSE',\r\n ABORTED: 'ABORTED',\r\n UNKNOWN: 'UNKNOWN',\r\n} as const\r\n\r\nexport type ErrorCode = keyof typeof ErrorCodes\r\n\r\n/**\r\n * Map of error codes to their default retriability.\r\n * Retriable errors: transient network / server issues.\r\n * Non-retriable errors: auth, permission, parse, user-cancel.\r\n */\r\nconst DEFAULT_RETRIABILITY: Record<ErrorCode, boolean> = {\r\n NETWORK: true,\r\n TIMEOUT: true,\r\n AUTH: false,\r\n FORBIDDEN: false,\r\n RATE_LIMIT: true,\r\n MODEL_UNAVAILABLE: true,\r\n TOOL_FAILED: false,\r\n SQL_FORBIDDEN: false,\r\n SQL_SENSITIVE: false,\r\n PARSE: false,\r\n ABORTED: false,\r\n UNKNOWN: false,\r\n}\r\n\r\nexport interface AiAssistantError extends Error {\r\n code: ErrorCode\r\n retriable: boolean\r\n details?: unknown\r\n}\r\n\r\n/**\r\n * Create a typed AI Assistant error.\r\n *\r\n * @param code — error code from ErrorCodes\r\n * @param message — human-readable message\r\n * @param retriable — override default retriability (optional)\r\n * @param details — extra context for debugging\r\n */\r\nexport function createError(\r\n code: ErrorCode,\r\n message: string,\r\n retriable?: boolean,\r\n details?: unknown\r\n): AiAssistantError {\r\n const error = new Error(message) as AiAssistantError\r\n error.code = code\r\n error.retriable = retriable ?? DEFAULT_RETRIABILITY[code] ?? false\r\n error.details = details\r\n return error\r\n}\r\n\r\n/**\r\n * Check whether an error is retriable.\r\n */\r\nexport function isRetriable(error: unknown): boolean {\r\n if (error instanceof Error && 'retriable' in error) {\r\n return Boolean((error as AiAssistantError).retriable)\r\n }\r\n return false\r\n}\r\n\r\n/**\r\n * Check whether an error represents a user abort.\r\n */\r\nexport function isAborted(error: unknown): boolean {\r\n if (error instanceof Error && 'code' in error) {\r\n return (error as AiAssistantError).code === 'ABORTED'\r\n }\r\n return false\r\n}\r\n","/**\r\n * Utility functions for AI Assistant Core\r\n *\r\n * Pure TypeScript — no framework dependencies.\r\n */\r\n\r\n/** Generate a short unique id with an optional prefix. */\r\nexport function generateId(prefix: string = ''): string {\r\n return `${prefix}${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 7)}`\r\n}\r\n\r\n/** Promise-based sleep. */\r\nexport function delay(ms: number): Promise<void> {\r\n return new Promise(resolve => setTimeout(resolve, ms))\r\n}\r\n\r\n/** Clamp a number between min and max (inclusive). */\r\nexport function clamp(value: number, min: number, max: number): number {\r\n return Math.min(Math.max(value, min), max)\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Type guards\r\n// ---------------------------------------------------------------------------\r\n\r\nexport function isObject(value: unknown): value is Record<string, unknown> {\r\n return value !== null && typeof value === 'object' && !Array.isArray(value)\r\n}\r\n\r\nexport function isArray<T = unknown>(value: unknown): value is T[] {\r\n return Array.isArray(value)\r\n}\r\n\r\nexport function isString(value: unknown): value is string {\r\n return typeof value === 'string'\r\n}\r\n\r\nexport function isNumber(value: unknown): value is number {\r\n return typeof value === 'number' && !Number.isNaN(value)\r\n}\r\n\r\nexport function isFunction(value: unknown): value is (...args: unknown[]) => unknown {\r\n return typeof value === 'function'\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Debounce / Throttle\r\n// ---------------------------------------------------------------------------\r\n\r\nexport interface DebouncedFunction<T extends (...args: unknown[]) => unknown> {\r\n (...args: Parameters<T>): ReturnType<T> | undefined\r\n cancel: () => void\r\n flush: () => ReturnType<T> | undefined\r\n}\r\n\r\nexport function debounce<T extends (...args: unknown[]) => unknown>(\r\n fn: T,\r\n waitMs: number,\r\n immediate: boolean = false\r\n): DebouncedFunction<T> {\r\n let timeoutId: ReturnType<typeof setTimeout> | null = null\r\n let lastArgs: Parameters<T> | null = null\r\n let lastResult: ReturnType<T> | undefined\r\n\r\n const invoke = (): ReturnType<T> | undefined => {\r\n timeoutId = null\r\n if (lastArgs) {\r\n lastResult = fn(...lastArgs) as ReturnType<T>\r\n lastArgs = null\r\n }\r\n return lastResult\r\n }\r\n\r\n const debounced = (...args: Parameters<T>): ReturnType<T> | undefined => {\r\n lastArgs = args\r\n if (timeoutId) clearTimeout(timeoutId)\r\n if (immediate && !timeoutId) {\r\n lastResult = fn(...args) as ReturnType<T>\r\n timeoutId = setTimeout(() => { timeoutId = null }, waitMs)\r\n return lastResult\r\n }\r\n timeoutId = setTimeout(invoke, waitMs)\r\n return undefined\r\n }\r\n\r\n debounced.cancel = () => {\r\n if (timeoutId) {\r\n clearTimeout(timeoutId)\r\n timeoutId = null\r\n }\r\n lastArgs = null\r\n }\r\n\r\n debounced.flush = () => {\r\n if (timeoutId) {\r\n clearTimeout(timeoutId)\r\n return invoke()\r\n }\r\n return lastResult\r\n }\r\n\r\n return debounced as DebouncedFunction<T>\r\n}\r\n\r\nexport interface ThrottledFunction<T extends (...args: unknown[]) => unknown> {\r\n (...args: Parameters<T>): ReturnType<T> | undefined\r\n cancel: () => void\r\n}\r\n\r\nexport function throttle<T extends (...args: unknown[]) => unknown>(\r\n fn: T,\r\n waitMs: number,\r\n options: { leading?: boolean; trailing?: boolean } = {}\r\n): ThrottledFunction<T> {\r\n const { leading = true, trailing = true } = options\r\n let timeoutId: ReturnType<typeof setTimeout> | null = null\r\n let lastArgs: Parameters<T> | null = null\r\n let lastResult: ReturnType<T> | undefined\r\n let lastCallTime = 0\r\n\r\n const invoke = (): void => {\r\n timeoutId = null\r\n if (lastArgs && trailing) {\r\n lastResult = fn(...lastArgs) as ReturnType<T>\r\n lastArgs = null\r\n lastCallTime = Date.now()\r\n }\r\n }\r\n\r\n const throttled = (...args: Parameters<T>): ReturnType<T> | undefined => {\r\n const now = Date.now()\r\n const remaining = waitMs - (now - lastCallTime)\r\n lastArgs = args\r\n\r\n if (remaining <= 0 || remaining > waitMs) {\r\n if (timeoutId) {\r\n clearTimeout(timeoutId)\r\n timeoutId = null\r\n }\r\n if (leading) {\r\n lastResult = fn(...args) as ReturnType<T>\r\n lastCallTime = now\r\n } else {\r\n lastCallTime = now\r\n if (trailing) {\r\n timeoutId = setTimeout(invoke, waitMs)\r\n }\r\n }\r\n return lastResult\r\n }\r\n\r\n if (!timeoutId && trailing) {\r\n timeoutId = setTimeout(invoke, remaining)\r\n }\r\n return lastResult\r\n }\r\n\r\n throttled.cancel = () => {\r\n if (timeoutId) {\r\n clearTimeout(timeoutId)\r\n timeoutId = null\r\n }\r\n lastArgs = null\r\n lastCallTime = 0\r\n }\r\n\r\n return throttled as ThrottledFunction<T>\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Deep clone\r\n// ---------------------------------------------------------------------------\r\n\r\nexport function deepClone<T>(value: T): T {\r\n if (value === null || typeof value !== 'object') return value\r\n if (value instanceof Date) return new Date(value.getTime()) as unknown as T\r\n if (value instanceof RegExp) return new RegExp(value.source, value.flags) as unknown as T\r\n if (Array.isArray(value)) {\r\n return value.map(item => deepClone(item)) as unknown as T\r\n }\r\n const cloned = {} as Record<string, unknown>\r\n for (const key of Object.keys(value as Record<string, unknown>)) {\r\n cloned[key] = deepClone((value as Record<string, unknown>)[key])\r\n }\r\n return cloned as T\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Date / Duration formatting\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Format a Date or timestamp to locale string. */\r\nexport function formatDate(\r\n input: Date | number | string,\r\n options?: Intl.DateTimeFormatOptions\r\n): string {\r\n const d = input instanceof Date ? input : new Date(input)\r\n if (Number.isNaN(d.getTime())) return String(input)\r\n return d.toLocaleString('zh-CN', {\r\n year: 'numeric',\r\n month: '2-digit',\r\n day: '2-digit',\r\n hour: '2-digit',\r\n minute: '2-digit',\r\n second: '2-digit',\r\n ...options,\r\n })\r\n}\r\n\r\n/** Format a duration in milliseconds to human-readable string. */\r\nexport function formatDuration(ms: number): string {\r\n if (ms < 0) ms = 0\r\n const seconds = Math.floor(ms / 1000)\r\n const minutes = Math.floor(seconds / 60)\r\n const hours = Math.floor(minutes / 60)\r\n\r\n if (hours > 0) {\r\n return `${hours}h ${minutes % 60}m ${seconds % 60}s`\r\n }\r\n if (minutes > 0) {\r\n return `${minutes}m ${seconds % 60}s`\r\n }\r\n if (seconds > 0) {\r\n return `${seconds}s`\r\n }\r\n return `${ms}ms`\r\n}\r\n","/**\r\n * SQL Guard — client-side SQL validation for AI Assistant Core\r\n *\r\n * Detects dangerous patterns before sending SQL to the backend.\r\n * This is a **defence-in-depth** layer; the backend must also enforce\r\n * read-only constraints and parameterised queries.\r\n */\r\n\r\nexport interface SqlGuardResult {\r\n /** Whether the SQL passes all checks */\r\n allowed: boolean\r\n /** Human-readable reason when blocked */\r\n reason?: string\r\n /** Sanitised SQL (if applicable) */\r\n sanitizedSql?: string\r\n}\r\n\r\nexport interface SqlGuardOptions {\r\n /** Table names that are off-limits */\r\n sensitiveTables?: string[]\r\n /** Allowed SQL operations (default: ['SELECT']) */\r\n allowedOperations?: string[]\r\n /** Whether to reject SQL containing comments */\r\n rejectComments?: boolean\r\n /** Whether to reject UNION / stacked queries */\r\n rejectUnion?: boolean\r\n /** Whether this guard represents a read-only DB account */\r\n readOnlyAccount?: boolean\r\n}\r\n\r\nexport class SqlGuard {\r\n private readonly sensitiveTables: string[]\r\n private readonly allowedOperations: string[]\r\n private readonly rejectComments: boolean\r\n private readonly rejectUnion: boolean\r\n private readonly readOnlyAccount: boolean\r\n\r\n constructor(options: SqlGuardOptions = {}) {\r\n this.sensitiveTables = options.sensitiveTables ?? []\r\n this.allowedOperations = options.allowedOperations ?? ['SELECT']\r\n this.rejectComments = options.rejectComments ?? true\r\n this.rejectUnion = options.rejectUnion ?? true\r\n this.readOnlyAccount = options.readOnlyAccount ?? true\r\n }\r\n\r\n /**\r\n * Validate a SQL string against all guard rules.\r\n *\r\n * Checks (in order):\r\n * 1. Read-only account enforcement\r\n * 2. Comment detection (SQL injection vector)\r\n * 3. UNION / stacked query detection\r\n * 4. Operation type whitelist\r\n * 5. Sensitive table access\r\n */\r\n validate(sql: string): SqlGuardResult {\r\n const normalized = sql.trim()\r\n if (!normalized) {\r\n return { allowed: false, reason: 'SQL is empty' }\r\n }\r\n\r\n const upper = normalized.toUpperCase()\r\n\r\n // 1. Read-only account\r\n if (this.readOnlyAccount) {\r\n const writeOps = ['INSERT', 'UPDATE', 'DELETE', 'DROP', 'ALTER', 'CREATE', 'TRUNCATE', 'REPLACE', 'MERGE']\r\n for (const op of writeOps) {\r\n if (this._hasWord(upper, op)) {\r\n return {\r\n allowed: false,\r\n reason: `Write operation \"${op}\" is forbidden in read-only mode`,\r\n }\r\n }\r\n }\r\n }\r\n\r\n // 2. Comment detection\r\n if (this.rejectComments) {\r\n if (normalized.includes('--') || normalized.includes('/*') || normalized.includes('*/')) {\r\n return {\r\n allowed: false,\r\n reason: 'SQL comments are not allowed (injection risk)',\r\n }\r\n }\r\n }\r\n\r\n // 3. UNION / stacked query detection\r\n if (this.rejectUnion) {\r\n if (this._hasWord(upper, 'UNION')) {\r\n return {\r\n allowed: false,\r\n reason: 'UNION queries are not allowed',\r\n }\r\n }\r\n // Detect stacked queries (semicolon outside string literals)\r\n const semicolonCount = this._countSemicolonsOutsideStrings(normalized)\r\n if (semicolonCount > 1) {\r\n return {\r\n allowed: false,\r\n reason: 'Stacked / multiple queries are not allowed',\r\n }\r\n }\r\n }\r\n\r\n // 4. Operation whitelist\r\n const detectedOp = this._detectOperation(upper)\r\n if (detectedOp && !this.allowedOperations.includes(detectedOp)) {\r\n return {\r\n allowed: false,\r\n reason: `SQL operation \"${detectedOp}\" is not in the allowed list: [${this.allowedOperations.join(', ')}]`,\r\n }\r\n }\r\n\r\n // 5. Sensitive table detection\r\n for (const table of this.sensitiveTables) {\r\n const tablePattern = new RegExp(`\\\\b${this._escapeRegex(table)}\\\\b`, 'i')\r\n if (tablePattern.test(normalized)) {\r\n return {\r\n allowed: false,\r\n reason: `Access to sensitive table \"${table}\" is forbidden`,\r\n }\r\n }\r\n }\r\n\r\n return { allowed: true, sanitizedSql: normalized }\r\n }\r\n\r\n /** Quick check: does the SQL contain any forbidden pattern? */\r\n isSafe(sql: string): boolean {\r\n return this.validate(sql).allowed\r\n }\r\n\r\n // -------------------------------------------------------------------------\r\n // Private helpers\r\n // -------------------------------------------------------------------------\r\n\r\n /** Check if a whole word exists in the text. */\r\n private _hasWord(text: string, word: string): boolean {\r\n const re = new RegExp(`\\\\b${word}\\\\b`)\r\n return re.test(text)\r\n }\r\n\r\n /** Detect the primary SQL operation (first keyword). */\r\n private _detectOperation(sql: string): string | null {\r\n const match = sql.match(/^\\\\s*(\\\\w+)/)\r\n return match ? match[1].toUpperCase() : null\r\n }\r\n\r\n /** Count semicolons that are outside quoted string literals. */\r\n private _countSemicolonsOutsideStrings(sql: string): number {\r\n let count = 0\r\n let inString = false\r\n let stringChar: string | null = null\r\n let escaped = false\r\n\r\n for (let i = 0; i < sql.length; i++) {\r\n const ch = sql[i]\r\n\r\n if (escaped) {\r\n escaped = false\r\n continue\r\n }\r\n\r\n if (ch === '\\\\') {\r\n escaped = true\r\n continue\r\n }\r\n\r\n if (!inString) {\r\n if (ch === \"'\" || ch === '\"') {\r\n inString = true\r\n stringChar = ch\r\n } else if (ch === ';') {\r\n count++\r\n }\r\n } else {\r\n if (ch === stringChar) {\r\n inString = false\r\n stringChar = null\r\n }\r\n }\r\n }\r\n\r\n return count\r\n }\r\n\r\n private _escapeRegex(str: string): string {\r\n return str.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\r\n }\r\n}\r\n","/**\n * SSE Client for AI Assistant Core\n *\n * Uses fetch + ReadableStream (not EventSource) to support:\n * - POST requests with custom headers\n * - AbortController cancellation\n * - Custom event parsing and heartbeat handling\n * - Sequence-based ack / resume protocol\n * - Exponential backoff reconnection\n */\n\nimport { createError } from '../errors'\nimport { clamp } from '../utils'\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport type SseConnectionStatus =\n | 'idle'\n | 'connecting'\n | 'streaming'\n | 'reconnecting'\n | 'closed'\n | 'error'\n\nexport interface SseClientOptions {\n /** Target URL */\n url: string\n /** POST body */\n body: unknown\n /** Request headers */\n headers: Record<string, string>\n /** Abort signal for cancellation */\n signal?: AbortSignal\n /** Called for every parsed stream event */\n onEvent?: (event: unknown) => void\n /** Called on unrecoverable errors */\n onError?: (error: Error) => void\n /** Called when connection status changes */\n onStatusChange?: (status: SseConnectionStatus) => void\n /** Heartbeat timeout in ms (default 15000) */\n heartbeatMs?: number\n /** Request timeout in ms (default 90000) */\n timeoutMs?: number\n /** Reconnect config */\n reconnect?: {\n max: number\n baseMs: number\n maxMs?: number\n resetOnSuccessMs?: number\n }\n /** Last acknowledged sequence number (for resume) */\n lastSeq?: number\n /**\n * Resume hook, consulted ONLY when re-establishing a dropped stream (i.e. on a\n * reconnect attempt, never the initial connect). Returns the additive body\n * fields that let the backend replay from where the client left off —\n * typically `{ conversationId, messageId, lastSeq }`. These are merged over the\n * base body so the same `/chat/stream` endpoint serves both fresh sends and\n * resumes (the 14-endpoint contract stays frozen). Any `lastSeq` returned here\n * takes precedence over the client's internally tracked seq.\n */\n resume?: () => Record<string, unknown> | undefined\n}\n\ninterface ReconnectState {\n attempt: number\n timer: ReturnType<typeof setTimeout> | null\n}\n\n// ---------------------------------------------------------------------------\n// SseClient\n// ---------------------------------------------------------------------------\n\nexport class SseClient {\n private reader: ReadableStreamDefaultReader<Uint8Array> | null = null\n private abortCtrl: AbortController | null = null\n private heartbeatTimer: ReturnType<typeof setTimeout> | null = null\n private timeoutTimer: ReturnType<typeof setTimeout> | null = null\n private reconnect: ReconnectState = { attempt: 0, timer: null }\n private lastSeq = 0\n private buffer = ''\n private status: SseConnectionStatus = 'idle'\n private options: SseClientOptions | null = null\n private destroyed = false\n\n /** Current connection status */\n get connectionStatus(): SseConnectionStatus {\n return this.status\n }\n\n /** Current reconnect attempt count */\n get reconnectAttempt(): number {\n return this.reconnect.attempt\n }\n\n /** Last acknowledged sequence number */\n get currentSeq(): number {\n return this.lastSeq\n }\n\n // -------------------------------------------------------------------------\n // Lifecycle\n // -------------------------------------------------------------------------\n\n async start(options: SseClientOptions): Promise<void> {\n if (this.destroyed) {\n throw createError('UNKNOWN', 'SseClient has been destroyed', false)\n }\n\n this.options = options\n this.lastSeq = options.lastSeq ?? 0\n this._setStatus('connecting')\n await this._connect()\n }\n\n /** Abort the current connection (does not destroy). */\n abort(): void {\n this._clearTimers()\n this._cancelReader()\n this._setStatus('closed')\n }\n\n /** Permanently destroy — no further connections allowed. */\n destroy(): void {\n this.destroyed = true\n this.abort()\n this._clearReconnectTimer()\n }\n\n // -------------------------------------------------------------------------\n // Connection\n // -------------------------------------------------------------------------\n\n private async _connect(): Promise<void> {\n const opts = this.options\n if (!opts || this.destroyed) return\n\n this._clearReconnectTimer()\n\n // Build abort controller (merge external signal)\n this.abortCtrl = new AbortController()\n if (opts.signal) {\n const onAbort = () => this.abortCtrl?.abort()\n if (opts.signal.aborted) {\n onAbort()\n return\n }\n opts.signal.addEventListener('abort', onAbort, { once: true })\n }\n\n // Timeout guard\n const timeoutMs = opts.timeoutMs ?? 90000\n this.timeoutTimer = setTimeout(() => {\n this._handleError(createError('TIMEOUT', `Request timed out after ${timeoutMs}ms`, true))\n }, timeoutMs)\n\n // `reconnect.attempt` is incremented before a reconnect is scheduled, so a\n // value > 0 here means this `_connect` is re-establishing a dropped stream.\n const isReconnect = this.reconnect.attempt > 0\n // Additive resume fields (conversationId / messageId / authoritative lastSeq)\n // are sent ONLY on reconnect so a fresh send's body is untouched.\n const resumeFields = isReconnect ? (opts.resume?.() ?? {}) : {}\n const resumeSeq =\n typeof resumeFields.lastSeq === 'number' ? (resumeFields.lastSeq as number) : this.lastSeq\n\n try {\n const res = await fetch(opts.url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Accept: 'text/event-stream',\n ...opts.headers,\n },\n body: JSON.stringify({\n ...(typeof opts.body === 'object' && opts.body !== null ? opts.body : {}),\n ...resumeFields,\n lastSeq: resumeSeq,\n }),\n signal: this.abortCtrl.signal,\n })\n\n if (!res.ok) {\n const status = res.status\n if (status === 401 || status === 403) {\n throw createError('AUTH', `Authentication failed (${status})`, false)\n }\n if (status === 429) {\n throw createError('RATE_LIMIT', 'Rate limit exceeded', true)\n }\n throw createError('NETWORK', `HTTP ${status}: ${res.statusText}`, status >= 500)\n }\n\n if (!res.body) {\n throw createError('NETWORK', 'Response body is empty', true)\n }\n\n this._setStatus('streaming')\n this._resetReconnect()\n this._startHeartbeat(opts.heartbeatMs ?? 15000)\n\n this.reader = res.body.getReader()\n const decoder = new TextDecoder()\n\n while (true) {\n const { done, value } = await this.reader.read()\n if (done) break\n this._processChunk(decoder.decode(value, { stream: true }))\n }\n\n // Stream ended gracefully\n this._setStatus('closed')\n } catch (err) {\n if (this.destroyed) return\n\n if (err instanceof Error && err.name === 'AbortError') {\n this._setStatus('closed')\n return\n }\n\n this._handleError(err instanceof Error ? err : new Error(String(err)))\n } finally {\n this._clearTimers()\n this._cancelReader()\n }\n }\n\n // -------------------------------------------------------------------------\n // Stream parsing\n // -------------------------------------------------------------------------\n\n private _processChunk(chunk: string): void {\n this.buffer += chunk\n const lines = this.buffer.split('\\n')\n // Keep the last partial line in the buffer\n this.buffer = lines.pop() ?? ''\n\n for (const line of lines) {\n this._processLine(line)\n }\n }\n\n private _processLine(line: string): void {\n const trimmed = line.trim()\n\n // Empty line — event boundary (SSE spec)\n if (!trimmed) return\n\n // Heartbeat / comment line (starts with ':')\n if (trimmed.startsWith(':')) {\n this._handleHeartbeat()\n return\n }\n\n // Data line (starts with 'data:')\n if (trimmed.startsWith('data:')) {\n const payload = trimmed.slice(5).trim()\n if (!payload) return\n this._parseEvent(payload)\n return\n }\n\n // Ignore other SSE fields (event:, id:, retry:) for simplicity\n }\n\n private _parseEvent(payload: string): void {\n try {\n const event = JSON.parse(payload) as Record<string, unknown>\n\n // Sequence tracking\n if (typeof event.seq === 'number') {\n this.lastSeq = event.seq\n }\n\n // Heartbeat event\n if (event.type === 'heartbeat') {\n this._handleHeartbeat()\n return\n }\n\n this.options?.onEvent?.(event)\n } catch (err) {\n this.options?.onError?.(\n createError('PARSE', `Failed to parse SSE payload: ${payload.slice(0, 200)}`, false, err)\n )\n }\n }\n\n // -------------------------------------------------------------------------\n // Heartbeat\n // -------------------------------------------------------------------------\n\n private _startHeartbeat(ms: number): void {\n this._clearHeartbeat()\n this.heartbeatTimer = setTimeout(() => {\n this._handleError(createError('TIMEOUT', 'Heartbeat timeout — no data received', true))\n }, ms * 2) // allow 2x interval before treating as timeout\n }\n\n private _handleHeartbeat(): void {\n this._startHeartbeat(this.options?.heartbeatMs ?? 15000)\n this.options?.onEvent?.({ type: 'heartbeat', ts: Date.now() })\n }\n\n // -------------------------------------------------------------------------\n // Error & Reconnect\n // -------------------------------------------------------------------------\n\n private _handleError(error: Error): void {\n this._setStatus('error')\n this.options?.onError?.(error)\n\n const cfg = this.options?.reconnect\n if (!cfg) return\n\n if (this.reconnect.attempt >= cfg.max) {\n this._setStatus('error')\n this.options?.onError?.(\n createError('NETWORK', `Max reconnect attempts (${cfg.max}) exceeded`, false)\n )\n return\n }\n\n this._scheduleReconnect(cfg)\n }\n\n private _scheduleReconnect(cfg: NonNullable<SseClientOptions['reconnect']>): void {\n this._setStatus('reconnecting')\n\n const base = cfg.baseMs ?? 1000\n const maxMs = cfg.maxMs ?? 30000\n // Exponential backoff: 1s, 2s, 4s, 8s, 16s, 30s, 30s, 30s...\n const delayMs = clamp(base * 2 ** this.reconnect.attempt, base, maxMs)\n // Add jitter (±25%) to prevent thundering herd\n const jitter = delayMs * 0.25 * (Math.random() * 2 - 1)\n const finalDelay = Math.max(0, Math.floor(delayMs + jitter))\n\n this.reconnect.attempt++\n this.reconnect.timer = setTimeout(() => {\n if (!this.destroyed) {\n this._connect()\n }\n }, finalDelay)\n }\n\n private _resetReconnect(): void {\n this.reconnect.attempt = 0\n this._clearReconnectTimer()\n }\n\n // -------------------------------------------------------------------------\n // Helpers\n // -------------------------------------------------------------------------\n\n private _setStatus(next: SseConnectionStatus): void {\n if (this.status === next) return\n this.status = next\n this.options?.onStatusChange?.(next)\n }\n\n private _cancelReader(): void {\n if (this.reader) {\n this.reader.cancel().catch(() => {\n /* ignore */\n })\n this.reader = null\n }\n if (this.abortCtrl) {\n try {\n this.abortCtrl.abort()\n } catch {\n /* ignore */\n }\n this.abortCtrl = null\n }\n }\n\n private _clearTimers(): void {\n if (this.timeoutTimer) {\n clearTimeout(this.timeoutTimer)\n this.timeoutTimer = null\n }\n this._clearHeartbeat()\n }\n\n private _clearHeartbeat(): void {\n if (this.heartbeatTimer) {\n clearTimeout(this.heartbeatTimer)\n this.heartbeatTimer = null\n }\n }\n\n private _clearReconnectTimer(): void {\n if (this.reconnect.timer) {\n clearTimeout(this.reconnect.timer)\n this.reconnect.timer = null\n }\n }\n}\n\nexport * from './sql-guard'\n"],"names":["_a"],"mappings":"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"}
|