@humain/terminal 0.0.3-beta.0 → 0.0.3-beta.2
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/CHANGELOG.md +13 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +4 -3
- package/dist/config.js.map +1 -1
- package/dist/humain/mcp-adapter/vendor/CHANGELOG.md +13 -0
- package/dist/humain/mcp-adapter/vendor/README.md +4 -1
- package/dist/humain/mcp-adapter/vendor/agent-dir.ts +12 -4
- package/dist/humain/mcp-adapter/vendor/cli.js +25 -4
- package/dist/humain/mcp-adapter/vendor/config.ts +4 -4
- package/dist/humain/mcp-adapter/vendor/direct-tools.ts +18 -15
- package/dist/humain/mcp-adapter/vendor/index.bundle.mjs +416 -60
- package/dist/humain/mcp-adapter/vendor/mcp-setup-panel.ts +2 -1
- package/dist/humain/mcp-adapter/vendor/metadata-cache.ts +18 -8
- package/dist/humain/mcp-adapter/vendor/package.json +177 -176
- package/dist/humain/mcp-adapter/vendor/request-headers-command.ts +336 -0
- package/dist/humain/mcp-adapter/vendor/server-manager.ts +5 -0
- package/dist/humain/mcp-adapter/vendor/tool-metadata.ts +38 -18
- package/dist/humain/mcp-adapter/vendor/types.ts +93 -10
- package/dist/humain/web-access/vendor/auth-fetch.d.ts +13 -0
- package/dist/humain/web-access/vendor/auth-fetch.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/auth-fetch.js +134 -0
- package/dist/humain/web-access/vendor/auth-fetch.js.map +1 -0
- package/dist/humain/web-access/vendor/chrome-cookies.d.ts +13 -0
- package/dist/humain/web-access/vendor/chrome-cookies.d.ts.map +1 -1
- package/dist/humain/web-access/vendor/chrome-cookies.js +106 -22
- package/dist/humain/web-access/vendor/chrome-cookies.js.map +1 -1
- package/dist/humain/web-access/vendor/curator-page.d.ts +1 -0
- package/dist/humain/web-access/vendor/curator-page.d.ts.map +1 -1
- package/dist/humain/web-access/vendor/curator-page.js +3 -1
- package/dist/humain/web-access/vendor/curator-page.js.map +1 -1
- package/dist/humain/web-access/vendor/curator-server.d.ts +1 -0
- package/dist/humain/web-access/vendor/curator-server.d.ts.map +1 -1
- package/dist/humain/web-access/vendor/curator-server.js +2 -0
- package/dist/humain/web-access/vendor/curator-server.js.map +1 -1
- package/dist/humain/web-access/vendor/extract.d.ts +2 -0
- package/dist/humain/web-access/vendor/extract.d.ts.map +1 -1
- package/dist/humain/web-access/vendor/extract.js +79 -17
- package/dist/humain/web-access/vendor/extract.js.map +1 -1
- package/dist/humain/web-access/vendor/fetch-params.d.ts +2 -0
- package/dist/humain/web-access/vendor/fetch-params.d.ts.map +1 -1
- package/dist/humain/web-access/vendor/fetch-params.js +17 -3
- package/dist/humain/web-access/vendor/fetch-params.js.map +1 -1
- package/dist/humain/web-access/vendor/firecrawl.d.ts +7 -0
- package/dist/humain/web-access/vendor/firecrawl.d.ts.map +1 -1
- package/dist/humain/web-access/vendor/firecrawl.js +141 -10
- package/dist/humain/web-access/vendor/firecrawl.js.map +1 -1
- package/dist/humain/web-access/vendor/gemini-search.d.ts +2 -2
- package/dist/humain/web-access/vendor/gemini-search.d.ts.map +1 -1
- package/dist/humain/web-access/vendor/gemini-search.js +22 -4
- package/dist/humain/web-access/vendor/gemini-search.js.map +1 -1
- package/dist/humain/web-access/vendor/index.d.ts.map +1 -1
- package/dist/humain/web-access/vendor/index.js +122 -48
- package/dist/humain/web-access/vendor/index.js.map +1 -1
- package/dist/humain/web-access/vendor/summary-review.d.ts +3 -1
- package/dist/humain/web-access/vendor/summary-review.d.ts.map +1 -1
- package/dist/humain/web-access/vendor/summary-review.js +6 -3
- package/dist/humain/web-access/vendor/summary-review.js.map +1 -1
- package/dist/humain/web-access/vendor/youtube-extract.d.ts.map +1 -1
- package/dist/humain/web-access/vendor/youtube-extract.js +2 -2
- package/dist/humain/web-access/vendor/youtube-extract.js.map +1 -1
- package/dist/utils/clipboard-image.d.ts.map +1 -1
- package/dist/utils/clipboard-image.js +2 -0
- package/dist/utils/clipboard-image.js.map +1 -1
- package/npm-shrinkwrap.json +7 -7
- package/package.json +6 -6
- package/src/humain/mcp-adapter/UPSTREAM.md +1 -1
- package/src/humain/mcp-adapter/upstream.json +3 -3
- package/src/humain/mcp-adapter/vendor/CHANGELOG.md +13 -0
- package/src/humain/web-access/UPSTREAM.md +1 -1
- package/src/humain/web-access/upstream.json +4 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"curator-server.d.ts","sourceRoot":"","sources":["../../../../src/humain/web-access/vendor/curator-server.ts"],"names":[],"mappings":"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","sourcesContent":["import http, { type IncomingMessage, type ServerResponse } from \"node:http\";\nimport { generateCuratorPage } from \"./curator-page.ts\";\nimport type { SummaryMeta } from \"./summary-review.ts\";\nimport { resolveCuratorNetworkConfig } from \"./utils.ts\";\n\nconst STALE_THRESHOLD_MS = 30000;\nconst WATCHDOG_INTERVAL_MS = 1000;\nconst MAX_BODY_SIZE = 64 * 1024;\n\ntype ServerState = \"SEARCHING\" | \"RESULT_SELECTION\" | \"COMPLETED\";\ntype CuratorResultEventData = IndexedCuratorSearchEntry & { slotIndex?: number };\ntype CuratorSearchErrorEventData = { queryIndex: number; query: string; error: string; provider?: string; slotIndex?: number };\ntype CuratorStoredEvent =\n\t| { event: \"result\"; data: CuratorResultEventData }\n\t| { event: \"search-error\"; data: CuratorSearchErrorEventData };\n\nexport interface CuratorServerOptions {\n\tqueries: string[];\n\tsessionToken: string;\n\ttimeout: number;\n\tavailableProviders: { all: boolean; openai: boolean; brave: boolean; parallel: boolean; tinyfish: boolean; search1api: boolean; searchinfinity: boolean; querit: boolean; tavily: boolean; jina: boolean; serpdive: boolean; kagi: boolean; bocha: boolean; ollama: boolean; searxng: boolean; duckduckgo: boolean; perplexity: boolean; exa: boolean; gemini: boolean; anysearch: boolean; xai: boolean; brightdata: boolean; serpbase: boolean };\n\tdefaultProvider: string;\n\tsearchProvider: string;\n\tsummaryModels: Array<{ value: string; label: string }>;\n\tdefaultSummaryModel: string | null;\n}\n\nexport interface CuratorSearchEntry {\n\tanswer: string;\n\tresults: Array<{ title: string; url: string; domain: string; snippet?: string }>;\n\tprovider: string;\n\terror?: string;\n}\n\nexport interface IndexedCuratorSearchEntry extends CuratorSearchEntry {\n\tqueryIndex: number;\n\tquery: string;\n}\n\nexport interface CuratorServerCallbacks {\n\tonSubmit: (payload: { selectedQueryIndices: number[]; summary?: string; summaryMeta?: SummaryMeta; rawResults?: boolean }) => void;\n\tonCancel: (reason: \"user\" | \"timeout\" | \"stale\") => void;\n\tonProviderChange: (provider: string) => void;\n\tonAddSearch: (query: string, provider?: string) => Promise<CuratorSearchEntry[]>;\n\tonAddSearchResults: (entries: IndexedCuratorSearchEntry[]) => void;\n\tonSummarize: (\n\t\tselectedQueryIndices: number[],\n\t\tsignal: AbortSignal,\n\t\tmodel?: string,\n\t\tfeedback?: string,\n\t) => Promise<{ summary: string; meta: SummaryMeta }>;\n\tonRewriteQuery: (query: string, signal: AbortSignal) => Promise<string>;\n}\n\nexport interface CuratorServerHandle {\n\tserver: http.Server;\n\turl: string;\n\tclose: () => void;\n\tpushResult: (queryIndex: number, data: CuratorSearchEntry & { query?: string; slotIndex?: number }) => void;\n\tpushError: (queryIndex: number, error: string, provider?: string, meta?: { query?: string; slotIndex?: number }) => void;\n\tsearchesDone: () => void;\n\t/** Reports browser connection state so a cancelled search can surface WHY it\n\t * went stale (e.g. the browser never connected). */\n\tgetConnectionState: () => { browserConnected: boolean; lastHeartbeatAgeMs: number };\n}\n\nfunction sendJson(res: ServerResponse, status: number, payload: unknown): void {\n\tres.writeHead(status, {\n\t\t\"Content-Type\": \"application/json\",\n\t\t\"Cache-Control\": \"no-store\",\n\t});\n\tres.end(JSON.stringify(payload));\n}\n\nfunction parseJSONBody(req: IncomingMessage): Promise<unknown> {\n\treturn new Promise((resolve, reject) => {\n\t\tlet body = \"\";\n\t\tlet size = 0;\n\t\treq.on(\"data\", (chunk: Buffer) => {\n\t\t\tsize += chunk.length;\n\t\t\tif (size > MAX_BODY_SIZE) {\n\t\t\t\treq.destroy();\n\t\t\t\treject(new Error(\"Request body too large\"));\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tbody += chunk.toString();\n\t\t});\n\t\treq.on(\"end\", () => {\n\t\t\ttry {\n\t\t\t\tresolve(JSON.parse(body));\n\t\t\t} catch (err) {\n\t\t\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\t\t\treject(new Error(`Invalid JSON: ${message}`));\n\t\t\t}\n\t\t});\n\t\treq.on(\"error\", reject);\n\t});\n}\n\nasync function parseBodyOrSend(req: IncomingMessage, res: ServerResponse): Promise<unknown | null> {\n\ttry {\n\t\treturn await parseJSONBody(req);\n\t} catch (err) {\n\t\tconst message = err instanceof Error ? err.message : \"Invalid body\";\n\t\tconst status = message === \"Request body too large\" ? 413 : 400;\n\t\tsendJson(res, status, { ok: false, error: message });\n\t\treturn null;\n\t}\n}\n\nfunction normalizeSelectedIndices(\n\tvalue: unknown,\n\toptions: { allowEmpty: boolean; maxExclusive: number },\n): { ok: true; indices: number[] } | { ok: false; error: string } {\n\tif (!Array.isArray(value)) {\n\t\treturn { ok: false, error: \"Invalid selection\" };\n\t}\n\n\tif (!options.allowEmpty && value.length === 0) {\n\t\treturn { ok: false, error: \"Invalid selection\" };\n\t}\n\n\tconst normalized: number[] = [];\n\tconst seen = new Set<number>();\n\tfor (const item of value) {\n\t\tif (typeof item !== \"number\" || !Number.isInteger(item) || item < 0) {\n\t\t\treturn { ok: false, error: \"Invalid selection\" };\n\t\t}\n\t\tif (item >= options.maxExclusive) {\n\t\t\treturn { ok: false, error: \"Invalid selection\" };\n\t\t}\n\t\tif (seen.has(item)) {\n\t\t\tcontinue;\n\t\t}\n\t\tseen.add(item);\n\t\tnormalized.push(item);\n\t}\n\n\tif (!options.allowEmpty && normalized.length === 0) {\n\t\treturn { ok: false, error: \"Invalid selection\" };\n\t}\n\n\treturn { ok: true, indices: normalized };\n}\n\nfunction normalizeSummaryMeta(value: unknown): SummaryMeta | null {\n\tif (!value || typeof value !== \"object\") return null;\n\tconst meta = value as Record<string, unknown>;\n\n\tconst model = meta.model === null\n\t\t? null\n\t\t: typeof meta.model === \"string\"\n\t\t\t? meta.model\n\t\t\t: undefined;\n\tif (model === undefined) return null;\n\n\tconst durationMs = meta.durationMs;\n\tif (typeof durationMs !== \"number\" || !Number.isFinite(durationMs) || durationMs < 0) return null;\n\n\tconst tokenEstimate = meta.tokenEstimate;\n\tif (typeof tokenEstimate !== \"number\" || !Number.isFinite(tokenEstimate) || tokenEstimate < 0) return null;\n\n\tconst fallbackUsed = meta.fallbackUsed;\n\tif (typeof fallbackUsed !== \"boolean\") return null;\n\n\tconst fallbackReason = typeof meta.fallbackReason === \"string\" ? meta.fallbackReason : undefined;\n\tif (meta.fallbackReason !== undefined && fallbackReason === undefined) return null;\n\n\tconst phase = meta.phase === \"summary-model\" || meta.phase === \"deterministic-fallback\"\n\t\t? meta.phase\n\t\t: undefined;\n\tif (meta.phase !== undefined && phase === undefined) return null;\n\tif (phase === \"deterministic-fallback\" && fallbackUsed !== true) return null;\n\tif (phase === \"summary-model\" && fallbackUsed !== false) return null;\n\n\tconst edited = typeof meta.edited === \"boolean\" ? meta.edited : undefined;\n\tif (meta.edited !== undefined && edited === undefined) return null;\n\n\treturn {\n\t\tmodel,\n\t\tdurationMs,\n\t\ttokenEstimate,\n\t\tfallbackUsed,\n\t\t...(fallbackReason !== undefined ? { fallbackReason } : {}),\n\t\t...(phase !== undefined ? { phase } : {}),\n\t\t...(edited !== undefined ? { edited } : {}),\n\t};\n}\n\nexport function startCuratorServer(\n\toptions: CuratorServerOptions,\n\tcallbacks: CuratorServerCallbacks,\n): Promise<CuratorServerHandle> {\n\tconst {\n\t\tqueries,\n\t\tsessionToken,\n\t\ttimeout,\n\t\tavailableProviders,\n\t\tdefaultProvider,\n\t\tsearchProvider,\n\t\tsummaryModels,\n\t\tdefaultSummaryModel,\n\t} = options;\n\tlet browserConnected = false;\n\tlet lastHeartbeatAt = Date.now();\n\tlet stateChangedAt = Date.now();\n\tlet clientIdleMs: number | null = null;\n\tlet clientTimeoutSeconds = timeout;\n\tlet completed = false;\n\tlet watchdog: NodeJS.Timeout | null = null;\n\tlet state: ServerState = \"SEARCHING\";\n\tlet sseResponse: ServerResponse | null = null;\n\tconst streamedEventsByResultIndex = new Map<number, CuratorStoredEvent>();\n\tlet searchStreamDone = queries.length === 0;\n\tlet nextQueryIndex = queries.length;\n\tlet summarizeAbortController: AbortController | null = null;\n\tlet summarizeRequestSeq = 0;\n\n\tlet sseKeepalive: NodeJS.Timeout | null = null;\n\n\tconst abortInFlightSummarize = (): void => {\n\t\tif (!summarizeAbortController) return;\n\t\tsummarizeAbortController.abort();\n\t\tsummarizeAbortController = null;\n\t};\n\n\tconst markCompleted = (): boolean => {\n\t\tif (completed) return false;\n\t\tcompleted = true;\n\t\tstate = \"COMPLETED\";\n\t\tstateChangedAt = Date.now();\n\t\tif (watchdog) {\n\t\t\tclearInterval(watchdog);\n\t\t\twatchdog = null;\n\t\t}\n\t\tif (sseKeepalive) {\n\t\t\tclearInterval(sseKeepalive);\n\t\t\tsseKeepalive = null;\n\t\t}\n\t\tabortInFlightSummarize();\n\t\tif (sseResponse) {\n\t\t\ttry { sseResponse.end(); } catch {}\n\t\t\tsseResponse = null;\n\t\t}\n\t\treturn true;\n\t};\n\n\tconst touchHeartbeat = (): void => {\n\t\tlastHeartbeatAt = Date.now();\n\t\tbrowserConnected = true;\n\t};\n\n\tconst getEffectiveTimeoutMs = (): number => Math.max(1000, Math.floor(clientTimeoutSeconds) * 1000);\n\n\tconst shouldTimeoutFromClientIdle = (): boolean => (\n\t\tstate === \"RESULT_SELECTION\" &&\n\t\tclientIdleMs !== null &&\n\t\tclientIdleMs >= getEffectiveTimeoutMs()\n\t);\n\n\tfunction validateToken(body: unknown, res: ServerResponse): boolean {\n\t\tif (!body || typeof body !== \"object\") {\n\t\t\tsendJson(res, 400, { ok: false, error: \"Invalid body\" });\n\t\t\treturn false;\n\t\t}\n\t\tif ((body as { token?: string }).token !== sessionToken) {\n\t\t\tsendJson(res, 403, { ok: false, error: \"Invalid session\" });\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t}\n\n\tfunction isAvailableProvider(provider: string): boolean {\n\t\tif (provider === \"all\") return availableProviders.all;\n\t\tif (provider === \"openai\") return availableProviders.openai;\n\t\tif (provider === \"brave\") return availableProviders.brave;\n\t\tif (provider === \"parallel\") return availableProviders.parallel;\n\t\tif (provider === \"tinyfish\") return availableProviders.tinyfish;\n\t\tif (provider === \"search1api\") return availableProviders.search1api;\n\t\tif (provider === \"searchinfinity\") return availableProviders.searchinfinity;\n\t\tif (provider === \"querit\") return availableProviders.querit;\n\t\tif (provider === \"tavily\") return availableProviders.tavily;\n\t\tif (provider === \"jina\") return availableProviders.jina;\n\t\tif (provider === \"serpdive\") return availableProviders.serpdive;\n\t\tif (provider === \"kagi\") return availableProviders.kagi;\n\t\tif (provider === \"bocha\") return availableProviders.bocha;\n\t\tif (provider === \"ollama\") return availableProviders.ollama;\n\t\tif (provider === \"searxng\") return availableProviders.searxng;\n\t\tif (provider === \"duckduckgo\") return availableProviders.duckduckgo;\n\t\tif (provider === \"perplexity\") return availableProviders.perplexity;\n\t\tif (provider === \"exa\") return availableProviders.exa;\n\t\tif (provider === \"gemini\") return availableProviders.gemini;\n\t\tif (provider === \"anysearch\") return availableProviders.anysearch;\n\t\tif (provider === \"xai\") return availableProviders.xai;\n\t\tif (provider === \"brightdata\") return availableProviders.brightdata;\n\t\tif (provider === \"serpbase\") return availableProviders.serpbase;\n\t\treturn false;\n\t}\n\n\tfunction writeSSE(res: ServerResponse, event: string, data: unknown): boolean {\n\t\tconst payload = `event: ${event}\\ndata: ${JSON.stringify(data)}\\n\\n`;\n\t\ttry {\n\t\t\tres.write(payload);\n\t\t\treturn true;\n\t\t} catch {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tfunction sendSSE(event: string, data: unknown): void {\n\t\tconst res = sseResponse;\n\t\tif (res && !res.writableEnded && res.socket && !res.socket.destroyed && writeSSE(res, event, data)) return;\n\t\tif (sseResponse === res) sseResponse = null;\n\t}\n\n\tfunction retainStreamedEvent(event: CuratorStoredEvent): void {\n\t\tstreamedEventsByResultIndex.set(event.data.queryIndex, event);\n\t}\n\n\tfunction getStreamedEvents(): CuratorStoredEvent[] {\n\t\treturn [...streamedEventsByResultIndex.values()];\n\t}\n\n\tfunction replaySSE(res: ServerResponse): void {\n\t\tfor (const item of getStreamedEvents()) {\n\t\t\tif (!writeSSE(res, item.event, item.data)) return;\n\t\t}\n\t\tif (searchStreamDone) writeSSE(res, \"done\", {});\n\t}\n\n\tconst pageHtml = generateCuratorPage(\n\t\tqueries,\n\t\tsessionToken,\n\t\ttimeout,\n\t\tavailableProviders,\n\t\tdefaultProvider,\n\t\tsearchProvider,\n\t\tsummaryModels,\n\t\tdefaultSummaryModel,\n\t);\n\n\tconst server = http.createServer(async (req, res) => {\n\t\ttry {\n\t\t\tconst method = req.method || \"GET\";\n\t\t\tconst url = new URL(req.url || \"/\", `http://${req.headers.host || \"127.0.0.1\"}`);\n\n\t\t\tif (method === \"GET\" && url.pathname === \"/\") {\n\t\t\t\tconst token = url.searchParams.get(\"session\");\n\t\t\t\tif (token !== sessionToken) {\n\t\t\t\t\tres.writeHead(403, { \"Content-Type\": \"text/plain\" });\n\t\t\t\t\tres.end(\"Invalid session\");\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\ttouchHeartbeat();\n\t\t\t\tres.writeHead(200, {\n\t\t\t\t\t\"Content-Type\": \"text/html; charset=utf-8\",\n\t\t\t\t\t\"Cache-Control\": \"no-store\",\n\t\t\t\t});\n\t\t\t\tres.end(pageHtml);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (method === \"GET\" && url.pathname === \"/events\") {\n\t\t\t\tconst token = url.searchParams.get(\"session\");\n\t\t\t\tif (token !== sessionToken) {\n\t\t\t\t\tres.writeHead(403, { \"Content-Type\": \"text/plain\" });\n\t\t\t\t\tres.end(\"Invalid session\");\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (state === \"COMPLETED\") {\n\t\t\t\t\tsendJson(res, 409, { ok: false, error: \"No events available\" });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (sseResponse) {\n\t\t\t\t\ttry { sseResponse.end(); } catch {}\n\t\t\t\t}\n\t\t\t\tres.writeHead(200, {\n\t\t\t\t\t\"Content-Type\": \"text/event-stream\",\n\t\t\t\t\t\"Cache-Control\": \"no-cache\",\n\t\t\t\t\tConnection: \"keep-alive\",\n\t\t\t\t\t\"X-Accel-Buffering\": \"no\",\n\t\t\t\t});\n\t\t\t\tres.flushHeaders();\n\t\t\t\tif (res.socket) res.socket.setNoDelay(true);\n\t\t\t\tsseResponse = res;\n\t\t\t\treplaySSE(res);\n\t\t\t\tif (sseKeepalive) clearInterval(sseKeepalive);\n\t\t\t\tsseKeepalive = setInterval(() => {\n\t\t\t\t\tif (sseResponse) {\n\t\t\t\t\t\ttry { sseResponse.write(\":keepalive\\n\\n\"); } catch {}\n\t\t\t\t\t}\n\t\t\t\t}, 15000);\n\t\t\t\treq.on(\"close\", () => {\n\t\t\t\t\tif (sseResponse === res) sseResponse = null;\n\t\t\t\t});\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (method === \"GET\" && url.pathname === \"/state\") {\n\t\t\t\tconst token = url.searchParams.get(\"session\");\n\t\t\t\tif (token !== sessionToken) {\n\t\t\t\t\tsendJson(res, 403, { ok: false, error: \"Invalid session\" });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\ttouchHeartbeat();\n\t\t\t\tsendJson(res, 200, { ok: true, events: getStreamedEvents(), done: searchStreamDone });\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (method === \"POST\" && url.pathname === \"/heartbeat\") {\n\t\t\t\tconst body = await parseBodyOrSend(req, res);\n\t\t\t\tif (!body) return;\n\t\t\t\tif (!validateToken(body, res)) return;\n\t\t\t\ttouchHeartbeat();\n\t\t\t\tconst heartbeat = body as { idleMs?: unknown; timeoutSec?: unknown };\n\t\t\t\tif (typeof heartbeat.timeoutSec === \"number\" && Number.isFinite(heartbeat.timeoutSec) && heartbeat.timeoutSec > 0) {\n\t\t\t\t\tclientTimeoutSeconds = Math.min(600, Math.floor(heartbeat.timeoutSec));\n\t\t\t\t}\n\t\t\t\tif (typeof heartbeat.idleMs === \"number\" && Number.isFinite(heartbeat.idleMs) && heartbeat.idleMs >= 0) {\n\t\t\t\t\tclientIdleMs = Math.floor(heartbeat.idleMs);\n\t\t\t\t}\n\t\t\t\tconst timedOut = shouldTimeoutFromClientIdle();\n\t\t\t\tsendJson(res, 200, { ok: true });\n\t\t\t\tif (timedOut && markCompleted()) {\n\t\t\t\t\tsetImmediate(() => callbacks.onCancel(\"timeout\"));\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (method === \"POST\" && url.pathname === \"/provider\") {\n\t\t\t\tconst body = await parseBodyOrSend(req, res);\n\t\t\t\tif (!body) return;\n\t\t\t\tif (!validateToken(body, res)) return;\n\t\t\t\tconst { provider } = body as { provider?: string };\n\t\t\t\tif (typeof provider !== \"string\" || provider.length === 0) {\n\t\t\t\t\tsendJson(res, 400, { ok: false, error: \"Invalid provider\" });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (!isAvailableProvider(provider)) {\n\t\t\t\t\tsendJson(res, 400, { ok: false, error: `Provider unavailable: ${provider}` });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tsetImmediate(() => callbacks.onProviderChange(provider));\n\t\t\t\tsendJson(res, 200, { ok: true });\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (method === \"POST\" && url.pathname === \"/search\") {\n\t\t\t\tconst body = await parseBodyOrSend(req, res);\n\t\t\t\tif (!body) return;\n\t\t\t\tif (!validateToken(body, res)) return;\n\t\t\t\tif (state === \"COMPLETED\") {\n\t\t\t\t\tsendJson(res, 409, { ok: false, error: \"Session closed\" });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst { query, provider } = body as { query?: string; provider?: string };\n\t\t\t\tif (typeof query !== \"string\" || query.trim().length === 0) {\n\t\t\t\t\tsendJson(res, 400, { ok: false, error: \"Invalid query\" });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (provider !== undefined) {\n\t\t\t\t\tif (typeof provider !== \"string\" || provider.length === 0) {\n\t\t\t\t\t\tsendJson(res, 400, { ok: false, error: \"Invalid provider\" });\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tif (!isAvailableProvider(provider)) {\n\t\t\t\t\t\tsendJson(res, 400, { ok: false, error: `Provider unavailable: ${provider}` });\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tconst qi = nextQueryIndex++;\n\t\t\t\tconst trimmedQuery = query.trim();\n\t\t\t\ttouchHeartbeat();\n\t\t\t\ttry {\n\t\t\t\t\tconst results = await callbacks.onAddSearch(trimmedQuery, provider);\n\t\t\t\t\tif (results.length === 0) throw new Error(\"Search returned no provider results\");\n\t\t\t\t\tconst entries = results.map((result, index): IndexedCuratorSearchEntry => ({\n\t\t\t\t\t\t...result,\n\t\t\t\t\t\tqueryIndex: index === 0 ? qi : nextQueryIndex++,\n\t\t\t\t\t\tquery: trimmedQuery,\n\t\t\t\t\t}));\n\t\t\t\t\tcallbacks.onAddSearchResults(entries);\n\t\t\t\t\tsendJson(res, 200, { ok: true, ...entries[0], entries });\n\t\t\t\t} catch (err) {\n\t\t\t\t\tconst message = err instanceof Error ? err.message : \"Search failed\";\n\t\t\t\t\tconst entry: IndexedCuratorSearchEntry = {\n\t\t\t\t\t\tqueryIndex: qi,\n\t\t\t\t\t\tquery: trimmedQuery,\n\t\t\t\t\t\tanswer: \"\",\n\t\t\t\t\t\tresults: [],\n\t\t\t\t\t\terror: message,\n\t\t\t\t\t\tprovider: typeof provider === \"string\" && provider.length > 0 ? provider : defaultProvider,\n\t\t\t\t\t};\n\t\t\t\t\tcallbacks.onAddSearchResults([entry]);\n\t\t\t\t\tsendJson(res, 200, { ok: true, ...entry, entries: [entry] });\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (method === \"POST\" && url.pathname === \"/summarize\") {\n\t\t\t\tconst body = await parseBodyOrSend(req, res);\n\t\t\t\tif (!body) return;\n\t\t\t\tif (!validateToken(body, res)) return;\n\t\t\t\tif (state === \"COMPLETED\") {\n\t\t\t\t\tsendJson(res, 409, { ok: false, error: \"Session closed\" });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst parsed = normalizeSelectedIndices((body as { selected?: unknown }).selected, {\n\t\t\t\t\tallowEmpty: false,\n\t\t\t\t\tmaxExclusive: nextQueryIndex,\n\t\t\t\t});\n\t\t\t\tif (\"error\" in parsed) {\n\t\t\t\t\tsendJson(res, 400, { ok: false, error: parsed.error });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tlet model: string | undefined;\n\t\t\t\tconst bodyModel = (body as { model?: unknown }).model;\n\t\t\t\tif (bodyModel !== undefined) {\n\t\t\t\t\tif (typeof bodyModel !== \"string\") {\n\t\t\t\t\t\tsendJson(res, 400, { ok: false, error: \"Invalid model\" });\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tconst trimmedModel = bodyModel.trim();\n\t\t\t\t\tmodel = trimmedModel.length > 0 ? trimmedModel : undefined;\n\t\t\t\t}\n\n\t\t\t\tconst bodyFeedback = (body as { feedback?: unknown }).feedback;\n\t\t\t\tconst feedback = typeof bodyFeedback === \"string\" && bodyFeedback.trim().length > 0\n\t\t\t\t\t? bodyFeedback.trim()\n\t\t\t\t\t: undefined;\n\n\t\t\t\tabortInFlightSummarize();\n\t\t\t\tconst controller = new AbortController();\n\t\t\t\tsummarizeAbortController = controller;\n\t\t\t\tconst requestId = ++summarizeRequestSeq;\n\n\t\t\t\ttry {\n\t\t\t\t\tconst result = await callbacks.onSummarize(parsed.indices, controller.signal, model, feedback);\n\t\t\t\t\tif (requestId !== summarizeRequestSeq || completed) {\n\t\t\t\t\t\tsendJson(res, 409, { ok: false, error: \"Summarize request superseded\" });\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tsendJson(res, 200, {\n\t\t\t\t\t\tok: true,\n\t\t\t\t\t\tsummary: result.summary,\n\t\t\t\t\t\tmeta: result.meta,\n\t\t\t\t\t});\n\t\t\t\t} catch (err) {\n\t\t\t\t\tconst message = err instanceof Error ? err.message : \"Summary generation failed\";\n\t\t\t\t\tconst status = controller.signal.aborted ? 409 : 500;\n\t\t\t\t\tsendJson(res, status, { ok: false, error: message });\n\t\t\t\t} finally {\n\t\t\t\t\tif (summarizeAbortController === controller) {\n\t\t\t\t\t\tsummarizeAbortController = null;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (method === \"POST\" && url.pathname === \"/rewrite\") {\n\t\t\t\tconst body = await parseBodyOrSend(req, res);\n\t\t\t\tif (!body) return;\n\t\t\t\tif (!validateToken(body, res)) return;\n\t\t\t\tif (state === \"COMPLETED\") {\n\t\t\t\t\tsendJson(res, 409, { ok: false, error: \"Session closed\" });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst { query } = body as { query?: unknown };\n\t\t\t\tif (typeof query !== \"string\" || query.trim().length === 0) {\n\t\t\t\t\tsendJson(res, 400, { ok: false, error: \"Invalid query\" });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst controller = new AbortController();\n\t\t\t\treq.on(\"close\", () => controller.abort());\n\t\t\t\ttouchHeartbeat();\n\t\t\t\ttry {\n\t\t\t\t\tconst rewritten = await callbacks.onRewriteQuery(query.trim(), controller.signal);\n\t\t\t\t\tsendJson(res, 200, { ok: true, query: rewritten });\n\t\t\t\t} catch (err) {\n\t\t\t\t\tconst message = err instanceof Error ? err.message : \"Rewrite failed\";\n\t\t\t\t\tconst status = controller.signal.aborted ? 409 : 500;\n\t\t\t\t\tsendJson(res, status, { ok: false, error: message });\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (method === \"POST\" && url.pathname === \"/submit\") {\n\t\t\t\tconst body = await parseBodyOrSend(req, res);\n\t\t\t\tif (!body) return;\n\t\t\t\tif (!validateToken(body, res)) return;\n\n\t\t\t\tconst parsed = normalizeSelectedIndices((body as { selected?: unknown }).selected, {\n\t\t\t\t\tallowEmpty: true,\n\t\t\t\t\tmaxExclusive: nextQueryIndex,\n\t\t\t\t});\n\t\t\t\tif (\"error\" in parsed) {\n\t\t\t\t\tsendJson(res, 400, { ok: false, error: parsed.error });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tlet summary: string | undefined;\n\t\t\t\tconst bodySummary = (body as { summary?: unknown }).summary;\n\t\t\t\tif (bodySummary !== undefined) {\n\t\t\t\t\tif (typeof bodySummary !== \"string\") {\n\t\t\t\t\t\tsendJson(res, 400, { ok: false, error: \"Invalid summary\" });\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tconst trimmedSummary = bodySummary.trim();\n\t\t\t\t\tsummary = trimmedSummary.length > 0 ? trimmedSummary : undefined;\n\t\t\t\t}\n\n\t\t\t\tlet summaryMeta: SummaryMeta | undefined;\n\t\t\t\tconst bodySummaryMeta = (body as { summaryMeta?: unknown }).summaryMeta;\n\t\t\t\tif (bodySummaryMeta !== undefined) {\n\t\t\t\t\tconst parsedSummaryMeta = normalizeSummaryMeta(bodySummaryMeta);\n\t\t\t\t\tif (!parsedSummaryMeta) {\n\t\t\t\t\t\tsendJson(res, 400, { ok: false, error: \"Invalid summaryMeta\" });\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tsummaryMeta = parsedSummaryMeta;\n\t\t\t\t}\n\n\t\t\t\tif (state !== \"SEARCHING\" && state !== \"RESULT_SELECTION\") {\n\t\t\t\t\tsendJson(res, 409, { ok: false, error: \"Cannot submit in current state\" });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (!markCompleted()) {\n\t\t\t\t\tsendJson(res, 409, { ok: false, error: \"Session closed\" });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst rawResults = (body as { rawResults?: unknown }).rawResults === true;\n\t\t\t\tsendJson(res, 200, { ok: true });\n\t\t\t\tsetImmediate(() => callbacks.onSubmit({\n\t\t\t\t\tselectedQueryIndices: parsed.indices,\n\t\t\t\t\t...(summary !== undefined ? { summary } : {}),\n\t\t\t\t\t...(summaryMeta !== undefined ? { summaryMeta } : {}),\n\t\t\t\t\trawResults,\n\t\t\t\t}));\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (method === \"POST\" && url.pathname === \"/cancel\") {\n\t\t\t\tconst body = await parseBodyOrSend(req, res);\n\t\t\t\tif (!body) return;\n\t\t\t\tif (!validateToken(body, res)) return;\n\t\t\t\tif (!markCompleted()) {\n\t\t\t\t\tsendJson(res, 200, { ok: true });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst { reason } = body as { reason?: string };\n\t\t\t\tsendJson(res, 200, { ok: true });\n\t\t\t\tconst cancelReason = reason === \"timeout\" ? \"timeout\" : \"user\";\n\t\t\t\tsetImmediate(() => callbacks.onCancel(cancelReason));\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tres.writeHead(404, { \"Content-Type\": \"text/plain\" });\n\t\t\tres.end(\"Not found\");\n\t\t} catch (err) {\n\t\t\tconst message = err instanceof Error ? err.message : \"Server error\";\n\t\t\tsendJson(res, 500, { ok: false, error: message });\n\t\t}\n\t});\n\n\treturn new Promise((resolve, reject) => {\n\t\tconst onError = (err: Error) => {\n\t\t\treject(new Error(`Curator server failed to start: ${err.message}`));\n\t\t};\n\n\t\tconst networkConfig = resolveCuratorNetworkConfig();\n\n\t\tserver.once(\"error\", onError);\n\t\tserver.listen(0, networkConfig.bind, () => {\n\t\t\tserver.off(\"error\", onError);\n\t\t\tconst addr = server.address();\n\t\t\tif (!addr || typeof addr === \"string\") {\n\t\t\t\treject(new Error(\"Curator server: invalid address\"));\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst url = `http://${networkConfig.host}:${addr.port}/?session=${sessionToken}`;\n\n\t\t\twatchdog = setInterval(() => {\n\t\t\t\tif (completed) return;\n\t\t\t\tif (!browserConnected) {\n\t\t\t\t\tconst noBrowserTimeoutMs = Math.max(5000, getEffectiveTimeoutMs());\n\t\t\t\t\tif (state !== \"RESULT_SELECTION\") return;\n\t\t\t\t\tif (Date.now() - stateChangedAt <= noBrowserTimeoutMs) return;\n\t\t\t\t\tif (!markCompleted()) return;\n\t\t\t\t\tsetImmediate(() => callbacks.onCancel(\"timeout\"));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (shouldTimeoutFromClientIdle()) {\n\t\t\t\t\tif (!markCompleted()) return;\n\t\t\t\t\tsetImmediate(() => callbacks.onCancel(\"timeout\"));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (Date.now() - lastHeartbeatAt <= STALE_THRESHOLD_MS) return;\n\t\t\t\tconst staleReason = state === \"RESULT_SELECTION\" ? \"timeout\" : \"stale\";\n\t\t\t\tif (!markCompleted()) return;\n\t\t\t\tsetImmediate(() => callbacks.onCancel(staleReason));\n\t\t\t}, WATCHDOG_INTERVAL_MS);\n\n\t\t\tresolve({\n\t\t\t\tserver,\n\t\t\t\turl,\n\t\t\t\tclose: () => {\n\t\t\t\t\tconst wasOpen = markCompleted();\n\t\t\t\t\ttry { server.close(); } catch {}\n\t\t\t\t\tif (wasOpen) {\n\t\t\t\t\t\tsetImmediate(() => callbacks.onCancel(\"stale\"));\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tpushResult: (queryIndex, data) => {\n\t\t\t\t\tif (completed) return;\n\t\t\t\t\tnextQueryIndex = Math.max(nextQueryIndex, queryIndex + 1);\n\t\t\t\t\tconst eventData: CuratorResultEventData = { ...data, queryIndex, query: data.query ?? queries[queryIndex] ?? \"\" };\n\t\t\t\t\tretainStreamedEvent({ event: \"result\", data: eventData });\n\t\t\t\t\tsendSSE(\"result\", eventData);\n\t\t\t\t},\n\t\t\t\tpushError: (queryIndex, error, provider, meta) => {\n\t\t\t\t\tif (completed) return;\n\t\t\t\t\tnextQueryIndex = Math.max(nextQueryIndex, queryIndex + 1);\n\t\t\t\t\tconst eventData: CuratorSearchErrorEventData = { queryIndex, query: meta?.query ?? queries[queryIndex] ?? \"\", error, provider, slotIndex: meta?.slotIndex };\n\t\t\t\t\tretainStreamedEvent({ event: \"search-error\", data: eventData });\n\t\t\t\t\tsendSSE(\"search-error\", eventData);\n\t\t\t\t},\n\t\t\t\tsearchesDone: () => {\n\t\t\t\t\tif (completed) return;\n\t\t\t\t\tsearchStreamDone = true;\n\t\t\t\t\tsendSSE(\"done\", {});\n\t\t\t\t\tstate = \"RESULT_SELECTION\";\n\t\t\t\t\tstateChangedAt = Date.now();\n\t\t\t\t},\n\t\t\t\tgetConnectionState: () => ({\n\t\t\t\t\tbrowserConnected,\n\t\t\t\t\tlastHeartbeatAgeMs: Date.now() - lastHeartbeatAt,\n\t\t\t\t}),\n\t\t\t});\n\t\t});\n\t});\n}\n"]}
|
|
1
|
+
{"version":3,"file":"curator-server.d.ts","sourceRoot":"","sources":["../../../../src/humain/web-access/vendor/curator-server.ts"],"names":[],"mappings":"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","sourcesContent":["import http, { type IncomingMessage, type ServerResponse } from \"node:http\";\nimport { generateCuratorPage } from \"./curator-page.ts\";\nimport type { SummaryMeta } from \"./summary-review.ts\";\nimport { resolveCuratorNetworkConfig } from \"./utils.ts\";\n\nconst STALE_THRESHOLD_MS = 30000;\nconst WATCHDOG_INTERVAL_MS = 1000;\nconst MAX_BODY_SIZE = 64 * 1024;\n\ntype ServerState = \"SEARCHING\" | \"RESULT_SELECTION\" | \"COMPLETED\";\ntype CuratorResultEventData = IndexedCuratorSearchEntry & { slotIndex?: number };\ntype CuratorSearchErrorEventData = { queryIndex: number; query: string; error: string; provider?: string; slotIndex?: number };\ntype CuratorStoredEvent =\n\t| { event: \"result\"; data: CuratorResultEventData }\n\t| { event: \"search-error\"; data: CuratorSearchErrorEventData };\n\nexport interface CuratorServerOptions {\n\tqueries: string[];\n\tsessionToken: string;\n\ttimeout: number;\n\tavailableProviders: { all: boolean; openai: boolean; brave: boolean; parallel: boolean; tinyfish: boolean; search1api: boolean; searchinfinity: boolean; querit: boolean; tavily: boolean; firecrawl: boolean; jina: boolean; serpdive: boolean; kagi: boolean; bocha: boolean; ollama: boolean; searxng: boolean; duckduckgo: boolean; perplexity: boolean; exa: boolean; gemini: boolean; anysearch: boolean; xai: boolean; brightdata: boolean; serpbase: boolean };\n\tdefaultProvider: string;\n\tsearchProvider: string;\n\tsummaryModels: Array<{ value: string; label: string }>;\n\tdefaultSummaryModel: string | null;\n}\n\nexport interface CuratorSearchEntry {\n\tanswer: string;\n\tresults: Array<{ title: string; url: string; domain: string; snippet?: string }>;\n\tprovider: string;\n\terror?: string;\n}\n\nexport interface IndexedCuratorSearchEntry extends CuratorSearchEntry {\n\tqueryIndex: number;\n\tquery: string;\n}\n\nexport interface CuratorServerCallbacks {\n\tonSubmit: (payload: { selectedQueryIndices: number[]; summary?: string; summaryMeta?: SummaryMeta; rawResults?: boolean }) => void;\n\tonCancel: (reason: \"user\" | \"timeout\" | \"stale\") => void;\n\tonProviderChange: (provider: string) => void;\n\tonAddSearch: (query: string, provider?: string) => Promise<CuratorSearchEntry[]>;\n\tonAddSearchResults: (entries: IndexedCuratorSearchEntry[]) => void;\n\tonSummarize: (\n\t\tselectedQueryIndices: number[],\n\t\tsignal: AbortSignal,\n\t\tmodel?: string,\n\t\tfeedback?: string,\n\t) => Promise<{ summary: string; meta: SummaryMeta }>;\n\tonRewriteQuery: (query: string, signal: AbortSignal) => Promise<string>;\n}\n\nexport interface CuratorServerHandle {\n\tserver: http.Server;\n\turl: string;\n\tclose: () => void;\n\tpushResult: (queryIndex: number, data: CuratorSearchEntry & { query?: string; slotIndex?: number }) => void;\n\tpushError: (queryIndex: number, error: string, provider?: string, meta?: { query?: string; slotIndex?: number }) => void;\n\tsearchesDone: () => void;\n\t/** Reports browser connection state so a cancelled search can surface WHY it\n\t * went stale (e.g. the browser never connected). */\n\tgetConnectionState: () => { browserConnected: boolean; lastHeartbeatAgeMs: number };\n}\n\nfunction sendJson(res: ServerResponse, status: number, payload: unknown): void {\n\tres.writeHead(status, {\n\t\t\"Content-Type\": \"application/json\",\n\t\t\"Cache-Control\": \"no-store\",\n\t});\n\tres.end(JSON.stringify(payload));\n}\n\nfunction parseJSONBody(req: IncomingMessage): Promise<unknown> {\n\treturn new Promise((resolve, reject) => {\n\t\tlet body = \"\";\n\t\tlet size = 0;\n\t\treq.on(\"data\", (chunk: Buffer) => {\n\t\t\tsize += chunk.length;\n\t\t\tif (size > MAX_BODY_SIZE) {\n\t\t\t\treq.destroy();\n\t\t\t\treject(new Error(\"Request body too large\"));\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tbody += chunk.toString();\n\t\t});\n\t\treq.on(\"end\", () => {\n\t\t\ttry {\n\t\t\t\tresolve(JSON.parse(body));\n\t\t\t} catch (err) {\n\t\t\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\t\t\treject(new Error(`Invalid JSON: ${message}`));\n\t\t\t}\n\t\t});\n\t\treq.on(\"error\", reject);\n\t});\n}\n\nasync function parseBodyOrSend(req: IncomingMessage, res: ServerResponse): Promise<unknown | null> {\n\ttry {\n\t\treturn await parseJSONBody(req);\n\t} catch (err) {\n\t\tconst message = err instanceof Error ? err.message : \"Invalid body\";\n\t\tconst status = message === \"Request body too large\" ? 413 : 400;\n\t\tsendJson(res, status, { ok: false, error: message });\n\t\treturn null;\n\t}\n}\n\nfunction normalizeSelectedIndices(\n\tvalue: unknown,\n\toptions: { allowEmpty: boolean; maxExclusive: number },\n): { ok: true; indices: number[] } | { ok: false; error: string } {\n\tif (!Array.isArray(value)) {\n\t\treturn { ok: false, error: \"Invalid selection\" };\n\t}\n\n\tif (!options.allowEmpty && value.length === 0) {\n\t\treturn { ok: false, error: \"Invalid selection\" };\n\t}\n\n\tconst normalized: number[] = [];\n\tconst seen = new Set<number>();\n\tfor (const item of value) {\n\t\tif (typeof item !== \"number\" || !Number.isInteger(item) || item < 0) {\n\t\t\treturn { ok: false, error: \"Invalid selection\" };\n\t\t}\n\t\tif (item >= options.maxExclusive) {\n\t\t\treturn { ok: false, error: \"Invalid selection\" };\n\t\t}\n\t\tif (seen.has(item)) {\n\t\t\tcontinue;\n\t\t}\n\t\tseen.add(item);\n\t\tnormalized.push(item);\n\t}\n\n\tif (!options.allowEmpty && normalized.length === 0) {\n\t\treturn { ok: false, error: \"Invalid selection\" };\n\t}\n\n\treturn { ok: true, indices: normalized };\n}\n\nfunction normalizeSummaryMeta(value: unknown): SummaryMeta | null {\n\tif (!value || typeof value !== \"object\") return null;\n\tconst meta = value as Record<string, unknown>;\n\n\tconst model = meta.model === null\n\t\t? null\n\t\t: typeof meta.model === \"string\"\n\t\t\t? meta.model\n\t\t\t: undefined;\n\tif (model === undefined) return null;\n\n\tconst durationMs = meta.durationMs;\n\tif (typeof durationMs !== \"number\" || !Number.isFinite(durationMs) || durationMs < 0) return null;\n\n\tconst tokenEstimate = meta.tokenEstimate;\n\tif (typeof tokenEstimate !== \"number\" || !Number.isFinite(tokenEstimate) || tokenEstimate < 0) return null;\n\n\tconst fallbackUsed = meta.fallbackUsed;\n\tif (typeof fallbackUsed !== \"boolean\") return null;\n\n\tconst fallbackReason = typeof meta.fallbackReason === \"string\" ? meta.fallbackReason : undefined;\n\tif (meta.fallbackReason !== undefined && fallbackReason === undefined) return null;\n\n\tconst phase = meta.phase === \"summary-model\" || meta.phase === \"deterministic-fallback\"\n\t\t? meta.phase\n\t\t: undefined;\n\tif (meta.phase !== undefined && phase === undefined) return null;\n\tif (phase === \"deterministic-fallback\" && fallbackUsed !== true) return null;\n\tif (phase === \"summary-model\" && fallbackUsed !== false) return null;\n\n\tconst edited = typeof meta.edited === \"boolean\" ? meta.edited : undefined;\n\tif (meta.edited !== undefined && edited === undefined) return null;\n\n\treturn {\n\t\tmodel,\n\t\tdurationMs,\n\t\ttokenEstimate,\n\t\tfallbackUsed,\n\t\t...(fallbackReason !== undefined ? { fallbackReason } : {}),\n\t\t...(phase !== undefined ? { phase } : {}),\n\t\t...(edited !== undefined ? { edited } : {}),\n\t};\n}\n\nexport function startCuratorServer(\n\toptions: CuratorServerOptions,\n\tcallbacks: CuratorServerCallbacks,\n): Promise<CuratorServerHandle> {\n\tconst {\n\t\tqueries,\n\t\tsessionToken,\n\t\ttimeout,\n\t\tavailableProviders,\n\t\tdefaultProvider,\n\t\tsearchProvider,\n\t\tsummaryModels,\n\t\tdefaultSummaryModel,\n\t} = options;\n\tlet browserConnected = false;\n\tlet lastHeartbeatAt = Date.now();\n\tlet stateChangedAt = Date.now();\n\tlet clientIdleMs: number | null = null;\n\tlet clientTimeoutSeconds = timeout;\n\tlet completed = false;\n\tlet watchdog: NodeJS.Timeout | null = null;\n\tlet state: ServerState = \"SEARCHING\";\n\tlet sseResponse: ServerResponse | null = null;\n\tconst streamedEventsByResultIndex = new Map<number, CuratorStoredEvent>();\n\tlet searchStreamDone = queries.length === 0;\n\tlet nextQueryIndex = queries.length;\n\tlet summarizeAbortController: AbortController | null = null;\n\tlet summarizeRequestSeq = 0;\n\n\tlet sseKeepalive: NodeJS.Timeout | null = null;\n\n\tconst abortInFlightSummarize = (): void => {\n\t\tif (!summarizeAbortController) return;\n\t\tsummarizeAbortController.abort();\n\t\tsummarizeAbortController = null;\n\t};\n\n\tconst markCompleted = (): boolean => {\n\t\tif (completed) return false;\n\t\tcompleted = true;\n\t\tstate = \"COMPLETED\";\n\t\tstateChangedAt = Date.now();\n\t\tif (watchdog) {\n\t\t\tclearInterval(watchdog);\n\t\t\twatchdog = null;\n\t\t}\n\t\tif (sseKeepalive) {\n\t\t\tclearInterval(sseKeepalive);\n\t\t\tsseKeepalive = null;\n\t\t}\n\t\tabortInFlightSummarize();\n\t\tif (sseResponse) {\n\t\t\ttry { sseResponse.end(); } catch {}\n\t\t\tsseResponse = null;\n\t\t}\n\t\treturn true;\n\t};\n\n\tconst touchHeartbeat = (): void => {\n\t\tlastHeartbeatAt = Date.now();\n\t\tbrowserConnected = true;\n\t};\n\n\tconst getEffectiveTimeoutMs = (): number => Math.max(1000, Math.floor(clientTimeoutSeconds) * 1000);\n\n\tconst shouldTimeoutFromClientIdle = (): boolean => (\n\t\tstate === \"RESULT_SELECTION\" &&\n\t\tclientIdleMs !== null &&\n\t\tclientIdleMs >= getEffectiveTimeoutMs()\n\t);\n\n\tfunction validateToken(body: unknown, res: ServerResponse): boolean {\n\t\tif (!body || typeof body !== \"object\") {\n\t\t\tsendJson(res, 400, { ok: false, error: \"Invalid body\" });\n\t\t\treturn false;\n\t\t}\n\t\tif ((body as { token?: string }).token !== sessionToken) {\n\t\t\tsendJson(res, 403, { ok: false, error: \"Invalid session\" });\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t}\n\n\tfunction isAvailableProvider(provider: string): boolean {\n\t\tif (provider === \"all\") return availableProviders.all;\n\t\tif (provider === \"openai\") return availableProviders.openai;\n\t\tif (provider === \"brave\") return availableProviders.brave;\n\t\tif (provider === \"parallel\") return availableProviders.parallel;\n\t\tif (provider === \"tinyfish\") return availableProviders.tinyfish;\n\t\tif (provider === \"search1api\") return availableProviders.search1api;\n\t\tif (provider === \"searchinfinity\") return availableProviders.searchinfinity;\n\t\tif (provider === \"querit\") return availableProviders.querit;\n\t\tif (provider === \"tavily\") return availableProviders.tavily;\n\t\tif (provider === \"firecrawl\") return availableProviders.firecrawl;\n\t\tif (provider === \"jina\") return availableProviders.jina;\n\t\tif (provider === \"serpdive\") return availableProviders.serpdive;\n\t\tif (provider === \"kagi\") return availableProviders.kagi;\n\t\tif (provider === \"bocha\") return availableProviders.bocha;\n\t\tif (provider === \"ollama\") return availableProviders.ollama;\n\t\tif (provider === \"searxng\") return availableProviders.searxng;\n\t\tif (provider === \"duckduckgo\") return availableProviders.duckduckgo;\n\t\tif (provider === \"perplexity\") return availableProviders.perplexity;\n\t\tif (provider === \"exa\") return availableProviders.exa;\n\t\tif (provider === \"gemini\") return availableProviders.gemini;\n\t\tif (provider === \"anysearch\") return availableProviders.anysearch;\n\t\tif (provider === \"xai\") return availableProviders.xai;\n\t\tif (provider === \"brightdata\") return availableProviders.brightdata;\n\t\tif (provider === \"serpbase\") return availableProviders.serpbase;\n\t\treturn false;\n\t}\n\n\tfunction writeSSE(res: ServerResponse, event: string, data: unknown): boolean {\n\t\tconst payload = `event: ${event}\\ndata: ${JSON.stringify(data)}\\n\\n`;\n\t\ttry {\n\t\t\tres.write(payload);\n\t\t\treturn true;\n\t\t} catch {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tfunction sendSSE(event: string, data: unknown): void {\n\t\tconst res = sseResponse;\n\t\tif (res && !res.writableEnded && res.socket && !res.socket.destroyed && writeSSE(res, event, data)) return;\n\t\tif (sseResponse === res) sseResponse = null;\n\t}\n\n\tfunction retainStreamedEvent(event: CuratorStoredEvent): void {\n\t\tstreamedEventsByResultIndex.set(event.data.queryIndex, event);\n\t}\n\n\tfunction getStreamedEvents(): CuratorStoredEvent[] {\n\t\treturn [...streamedEventsByResultIndex.values()];\n\t}\n\n\tfunction replaySSE(res: ServerResponse): void {\n\t\tfor (const item of getStreamedEvents()) {\n\t\t\tif (!writeSSE(res, item.event, item.data)) return;\n\t\t}\n\t\tif (searchStreamDone) writeSSE(res, \"done\", {});\n\t}\n\n\tconst pageHtml = generateCuratorPage(\n\t\tqueries,\n\t\tsessionToken,\n\t\ttimeout,\n\t\tavailableProviders,\n\t\tdefaultProvider,\n\t\tsearchProvider,\n\t\tsummaryModels,\n\t\tdefaultSummaryModel,\n\t);\n\n\tconst server = http.createServer(async (req, res) => {\n\t\ttry {\n\t\t\tconst method = req.method || \"GET\";\n\t\t\tconst url = new URL(req.url || \"/\", `http://${req.headers.host || \"127.0.0.1\"}`);\n\n\t\t\tif (method === \"GET\" && url.pathname === \"/\") {\n\t\t\t\tconst token = url.searchParams.get(\"session\");\n\t\t\t\tif (token !== sessionToken) {\n\t\t\t\t\tres.writeHead(403, { \"Content-Type\": \"text/plain\" });\n\t\t\t\t\tres.end(\"Invalid session\");\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\ttouchHeartbeat();\n\t\t\t\tres.writeHead(200, {\n\t\t\t\t\t\"Content-Type\": \"text/html; charset=utf-8\",\n\t\t\t\t\t\"Cache-Control\": \"no-store\",\n\t\t\t\t});\n\t\t\t\tres.end(pageHtml);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (method === \"GET\" && url.pathname === \"/events\") {\n\t\t\t\tconst token = url.searchParams.get(\"session\");\n\t\t\t\tif (token !== sessionToken) {\n\t\t\t\t\tres.writeHead(403, { \"Content-Type\": \"text/plain\" });\n\t\t\t\t\tres.end(\"Invalid session\");\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (state === \"COMPLETED\") {\n\t\t\t\t\tsendJson(res, 409, { ok: false, error: \"No events available\" });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (sseResponse) {\n\t\t\t\t\ttry { sseResponse.end(); } catch {}\n\t\t\t\t}\n\t\t\t\tres.writeHead(200, {\n\t\t\t\t\t\"Content-Type\": \"text/event-stream\",\n\t\t\t\t\t\"Cache-Control\": \"no-cache\",\n\t\t\t\t\tConnection: \"keep-alive\",\n\t\t\t\t\t\"X-Accel-Buffering\": \"no\",\n\t\t\t\t});\n\t\t\t\tres.flushHeaders();\n\t\t\t\tif (res.socket) res.socket.setNoDelay(true);\n\t\t\t\tsseResponse = res;\n\t\t\t\treplaySSE(res);\n\t\t\t\tif (sseKeepalive) clearInterval(sseKeepalive);\n\t\t\t\tsseKeepalive = setInterval(() => {\n\t\t\t\t\tif (sseResponse) {\n\t\t\t\t\t\ttry { sseResponse.write(\":keepalive\\n\\n\"); } catch {}\n\t\t\t\t\t}\n\t\t\t\t}, 15000);\n\t\t\t\treq.on(\"close\", () => {\n\t\t\t\t\tif (sseResponse === res) sseResponse = null;\n\t\t\t\t});\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (method === \"GET\" && url.pathname === \"/state\") {\n\t\t\t\tconst token = url.searchParams.get(\"session\");\n\t\t\t\tif (token !== sessionToken) {\n\t\t\t\t\tsendJson(res, 403, { ok: false, error: \"Invalid session\" });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\ttouchHeartbeat();\n\t\t\t\tsendJson(res, 200, { ok: true, events: getStreamedEvents(), done: searchStreamDone });\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (method === \"POST\" && url.pathname === \"/heartbeat\") {\n\t\t\t\tconst body = await parseBodyOrSend(req, res);\n\t\t\t\tif (!body) return;\n\t\t\t\tif (!validateToken(body, res)) return;\n\t\t\t\ttouchHeartbeat();\n\t\t\t\tconst heartbeat = body as { idleMs?: unknown; timeoutSec?: unknown };\n\t\t\t\tif (typeof heartbeat.timeoutSec === \"number\" && Number.isFinite(heartbeat.timeoutSec) && heartbeat.timeoutSec > 0) {\n\t\t\t\t\tclientTimeoutSeconds = Math.min(600, Math.floor(heartbeat.timeoutSec));\n\t\t\t\t}\n\t\t\t\tif (typeof heartbeat.idleMs === \"number\" && Number.isFinite(heartbeat.idleMs) && heartbeat.idleMs >= 0) {\n\t\t\t\t\tclientIdleMs = Math.floor(heartbeat.idleMs);\n\t\t\t\t}\n\t\t\t\tconst timedOut = shouldTimeoutFromClientIdle();\n\t\t\t\tsendJson(res, 200, { ok: true });\n\t\t\t\tif (timedOut && markCompleted()) {\n\t\t\t\t\tsetImmediate(() => callbacks.onCancel(\"timeout\"));\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (method === \"POST\" && url.pathname === \"/provider\") {\n\t\t\t\tconst body = await parseBodyOrSend(req, res);\n\t\t\t\tif (!body) return;\n\t\t\t\tif (!validateToken(body, res)) return;\n\t\t\t\tconst { provider } = body as { provider?: string };\n\t\t\t\tif (typeof provider !== \"string\" || provider.length === 0) {\n\t\t\t\t\tsendJson(res, 400, { ok: false, error: \"Invalid provider\" });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (!isAvailableProvider(provider)) {\n\t\t\t\t\tsendJson(res, 400, { ok: false, error: `Provider unavailable: ${provider}` });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tsetImmediate(() => callbacks.onProviderChange(provider));\n\t\t\t\tsendJson(res, 200, { ok: true });\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (method === \"POST\" && url.pathname === \"/search\") {\n\t\t\t\tconst body = await parseBodyOrSend(req, res);\n\t\t\t\tif (!body) return;\n\t\t\t\tif (!validateToken(body, res)) return;\n\t\t\t\tif (state === \"COMPLETED\") {\n\t\t\t\t\tsendJson(res, 409, { ok: false, error: \"Session closed\" });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst { query, provider } = body as { query?: string; provider?: string };\n\t\t\t\tif (typeof query !== \"string\" || query.trim().length === 0) {\n\t\t\t\t\tsendJson(res, 400, { ok: false, error: \"Invalid query\" });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (provider !== undefined) {\n\t\t\t\t\tif (typeof provider !== \"string\" || provider.length === 0) {\n\t\t\t\t\t\tsendJson(res, 400, { ok: false, error: \"Invalid provider\" });\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tif (!isAvailableProvider(provider)) {\n\t\t\t\t\t\tsendJson(res, 400, { ok: false, error: `Provider unavailable: ${provider}` });\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tconst qi = nextQueryIndex++;\n\t\t\t\tconst trimmedQuery = query.trim();\n\t\t\t\ttouchHeartbeat();\n\t\t\t\ttry {\n\t\t\t\t\tconst results = await callbacks.onAddSearch(trimmedQuery, provider);\n\t\t\t\t\tif (results.length === 0) throw new Error(\"Search returned no provider results\");\n\t\t\t\t\tconst entries = results.map((result, index): IndexedCuratorSearchEntry => ({\n\t\t\t\t\t\t...result,\n\t\t\t\t\t\tqueryIndex: index === 0 ? qi : nextQueryIndex++,\n\t\t\t\t\t\tquery: trimmedQuery,\n\t\t\t\t\t}));\n\t\t\t\t\tcallbacks.onAddSearchResults(entries);\n\t\t\t\t\tsendJson(res, 200, { ok: true, ...entries[0], entries });\n\t\t\t\t} catch (err) {\n\t\t\t\t\tconst message = err instanceof Error ? err.message : \"Search failed\";\n\t\t\t\t\tconst entry: IndexedCuratorSearchEntry = {\n\t\t\t\t\t\tqueryIndex: qi,\n\t\t\t\t\t\tquery: trimmedQuery,\n\t\t\t\t\t\tanswer: \"\",\n\t\t\t\t\t\tresults: [],\n\t\t\t\t\t\terror: message,\n\t\t\t\t\t\tprovider: typeof provider === \"string\" && provider.length > 0 ? provider : defaultProvider,\n\t\t\t\t\t};\n\t\t\t\t\tcallbacks.onAddSearchResults([entry]);\n\t\t\t\t\tsendJson(res, 200, { ok: true, ...entry, entries: [entry] });\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (method === \"POST\" && url.pathname === \"/summarize\") {\n\t\t\t\tconst body = await parseBodyOrSend(req, res);\n\t\t\t\tif (!body) return;\n\t\t\t\tif (!validateToken(body, res)) return;\n\t\t\t\tif (state === \"COMPLETED\") {\n\t\t\t\t\tsendJson(res, 409, { ok: false, error: \"Session closed\" });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst parsed = normalizeSelectedIndices((body as { selected?: unknown }).selected, {\n\t\t\t\t\tallowEmpty: false,\n\t\t\t\t\tmaxExclusive: nextQueryIndex,\n\t\t\t\t});\n\t\t\t\tif (\"error\" in parsed) {\n\t\t\t\t\tsendJson(res, 400, { ok: false, error: parsed.error });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tlet model: string | undefined;\n\t\t\t\tconst bodyModel = (body as { model?: unknown }).model;\n\t\t\t\tif (bodyModel !== undefined) {\n\t\t\t\t\tif (typeof bodyModel !== \"string\") {\n\t\t\t\t\t\tsendJson(res, 400, { ok: false, error: \"Invalid model\" });\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tconst trimmedModel = bodyModel.trim();\n\t\t\t\t\tmodel = trimmedModel.length > 0 ? trimmedModel : undefined;\n\t\t\t\t}\n\n\t\t\t\tconst bodyFeedback = (body as { feedback?: unknown }).feedback;\n\t\t\t\tconst feedback = typeof bodyFeedback === \"string\" && bodyFeedback.trim().length > 0\n\t\t\t\t\t? bodyFeedback.trim()\n\t\t\t\t\t: undefined;\n\n\t\t\t\tabortInFlightSummarize();\n\t\t\t\tconst controller = new AbortController();\n\t\t\t\tsummarizeAbortController = controller;\n\t\t\t\tconst requestId = ++summarizeRequestSeq;\n\n\t\t\t\ttry {\n\t\t\t\t\tconst result = await callbacks.onSummarize(parsed.indices, controller.signal, model, feedback);\n\t\t\t\t\tif (requestId !== summarizeRequestSeq || completed) {\n\t\t\t\t\t\tsendJson(res, 409, { ok: false, error: \"Summarize request superseded\" });\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tsendJson(res, 200, {\n\t\t\t\t\t\tok: true,\n\t\t\t\t\t\tsummary: result.summary,\n\t\t\t\t\t\tmeta: result.meta,\n\t\t\t\t\t});\n\t\t\t\t} catch (err) {\n\t\t\t\t\tconst message = err instanceof Error ? err.message : \"Summary generation failed\";\n\t\t\t\t\tconst status = controller.signal.aborted ? 409 : 500;\n\t\t\t\t\tsendJson(res, status, { ok: false, error: message });\n\t\t\t\t} finally {\n\t\t\t\t\tif (summarizeAbortController === controller) {\n\t\t\t\t\t\tsummarizeAbortController = null;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (method === \"POST\" && url.pathname === \"/rewrite\") {\n\t\t\t\tconst body = await parseBodyOrSend(req, res);\n\t\t\t\tif (!body) return;\n\t\t\t\tif (!validateToken(body, res)) return;\n\t\t\t\tif (state === \"COMPLETED\") {\n\t\t\t\t\tsendJson(res, 409, { ok: false, error: \"Session closed\" });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst { query } = body as { query?: unknown };\n\t\t\t\tif (typeof query !== \"string\" || query.trim().length === 0) {\n\t\t\t\t\tsendJson(res, 400, { ok: false, error: \"Invalid query\" });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst controller = new AbortController();\n\t\t\t\treq.on(\"close\", () => controller.abort());\n\t\t\t\ttouchHeartbeat();\n\t\t\t\ttry {\n\t\t\t\t\tconst rewritten = await callbacks.onRewriteQuery(query.trim(), controller.signal);\n\t\t\t\t\tsendJson(res, 200, { ok: true, query: rewritten });\n\t\t\t\t} catch (err) {\n\t\t\t\t\tconst message = err instanceof Error ? err.message : \"Rewrite failed\";\n\t\t\t\t\tconst status = controller.signal.aborted ? 409 : 500;\n\t\t\t\t\tsendJson(res, status, { ok: false, error: message });\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (method === \"POST\" && url.pathname === \"/submit\") {\n\t\t\t\tconst body = await parseBodyOrSend(req, res);\n\t\t\t\tif (!body) return;\n\t\t\t\tif (!validateToken(body, res)) return;\n\n\t\t\t\tconst parsed = normalizeSelectedIndices((body as { selected?: unknown }).selected, {\n\t\t\t\t\tallowEmpty: true,\n\t\t\t\t\tmaxExclusive: nextQueryIndex,\n\t\t\t\t});\n\t\t\t\tif (\"error\" in parsed) {\n\t\t\t\t\tsendJson(res, 400, { ok: false, error: parsed.error });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tlet summary: string | undefined;\n\t\t\t\tconst bodySummary = (body as { summary?: unknown }).summary;\n\t\t\t\tif (bodySummary !== undefined) {\n\t\t\t\t\tif (typeof bodySummary !== \"string\") {\n\t\t\t\t\t\tsendJson(res, 400, { ok: false, error: \"Invalid summary\" });\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tconst trimmedSummary = bodySummary.trim();\n\t\t\t\t\tsummary = trimmedSummary.length > 0 ? trimmedSummary : undefined;\n\t\t\t\t}\n\n\t\t\t\tlet summaryMeta: SummaryMeta | undefined;\n\t\t\t\tconst bodySummaryMeta = (body as { summaryMeta?: unknown }).summaryMeta;\n\t\t\t\tif (bodySummaryMeta !== undefined) {\n\t\t\t\t\tconst parsedSummaryMeta = normalizeSummaryMeta(bodySummaryMeta);\n\t\t\t\t\tif (!parsedSummaryMeta) {\n\t\t\t\t\t\tsendJson(res, 400, { ok: false, error: \"Invalid summaryMeta\" });\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tsummaryMeta = parsedSummaryMeta;\n\t\t\t\t}\n\n\t\t\t\tif (state !== \"SEARCHING\" && state !== \"RESULT_SELECTION\") {\n\t\t\t\t\tsendJson(res, 409, { ok: false, error: \"Cannot submit in current state\" });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (!markCompleted()) {\n\t\t\t\t\tsendJson(res, 409, { ok: false, error: \"Session closed\" });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst rawResults = (body as { rawResults?: unknown }).rawResults === true;\n\t\t\t\tsendJson(res, 200, { ok: true });\n\t\t\t\tsetImmediate(() => callbacks.onSubmit({\n\t\t\t\t\tselectedQueryIndices: parsed.indices,\n\t\t\t\t\t...(summary !== undefined ? { summary } : {}),\n\t\t\t\t\t...(summaryMeta !== undefined ? { summaryMeta } : {}),\n\t\t\t\t\trawResults,\n\t\t\t\t}));\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (method === \"POST\" && url.pathname === \"/cancel\") {\n\t\t\t\tconst body = await parseBodyOrSend(req, res);\n\t\t\t\tif (!body) return;\n\t\t\t\tif (!validateToken(body, res)) return;\n\t\t\t\tif (!markCompleted()) {\n\t\t\t\t\tsendJson(res, 200, { ok: true });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst { reason } = body as { reason?: string };\n\t\t\t\tsendJson(res, 200, { ok: true });\n\t\t\t\tconst cancelReason = reason === \"timeout\" ? \"timeout\" : \"user\";\n\t\t\t\tsetImmediate(() => callbacks.onCancel(cancelReason));\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tres.writeHead(404, { \"Content-Type\": \"text/plain\" });\n\t\t\tres.end(\"Not found\");\n\t\t} catch (err) {\n\t\t\tconst message = err instanceof Error ? err.message : \"Server error\";\n\t\t\tsendJson(res, 500, { ok: false, error: message });\n\t\t}\n\t});\n\n\treturn new Promise((resolve, reject) => {\n\t\tconst onError = (err: Error) => {\n\t\t\treject(new Error(`Curator server failed to start: ${err.message}`));\n\t\t};\n\n\t\tconst networkConfig = resolveCuratorNetworkConfig();\n\n\t\tserver.once(\"error\", onError);\n\t\tserver.listen(0, networkConfig.bind, () => {\n\t\t\tserver.off(\"error\", onError);\n\t\t\tconst addr = server.address();\n\t\t\tif (!addr || typeof addr === \"string\") {\n\t\t\t\treject(new Error(\"Curator server: invalid address\"));\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst url = `http://${networkConfig.host}:${addr.port}/?session=${sessionToken}`;\n\n\t\t\twatchdog = setInterval(() => {\n\t\t\t\tif (completed) return;\n\t\t\t\tif (!browserConnected) {\n\t\t\t\t\tconst noBrowserTimeoutMs = Math.max(5000, getEffectiveTimeoutMs());\n\t\t\t\t\tif (state !== \"RESULT_SELECTION\") return;\n\t\t\t\t\tif (Date.now() - stateChangedAt <= noBrowserTimeoutMs) return;\n\t\t\t\t\tif (!markCompleted()) return;\n\t\t\t\t\tsetImmediate(() => callbacks.onCancel(\"timeout\"));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (shouldTimeoutFromClientIdle()) {\n\t\t\t\t\tif (!markCompleted()) return;\n\t\t\t\t\tsetImmediate(() => callbacks.onCancel(\"timeout\"));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (Date.now() - lastHeartbeatAt <= STALE_THRESHOLD_MS) return;\n\t\t\t\tconst staleReason = state === \"RESULT_SELECTION\" ? \"timeout\" : \"stale\";\n\t\t\t\tif (!markCompleted()) return;\n\t\t\t\tsetImmediate(() => callbacks.onCancel(staleReason));\n\t\t\t}, WATCHDOG_INTERVAL_MS);\n\n\t\t\tresolve({\n\t\t\t\tserver,\n\t\t\t\turl,\n\t\t\t\tclose: () => {\n\t\t\t\t\tconst wasOpen = markCompleted();\n\t\t\t\t\ttry { server.close(); } catch {}\n\t\t\t\t\tif (wasOpen) {\n\t\t\t\t\t\tsetImmediate(() => callbacks.onCancel(\"stale\"));\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tpushResult: (queryIndex, data) => {\n\t\t\t\t\tif (completed) return;\n\t\t\t\t\tnextQueryIndex = Math.max(nextQueryIndex, queryIndex + 1);\n\t\t\t\t\tconst eventData: CuratorResultEventData = { ...data, queryIndex, query: data.query ?? queries[queryIndex] ?? \"\" };\n\t\t\t\t\tretainStreamedEvent({ event: \"result\", data: eventData });\n\t\t\t\t\tsendSSE(\"result\", eventData);\n\t\t\t\t},\n\t\t\t\tpushError: (queryIndex, error, provider, meta) => {\n\t\t\t\t\tif (completed) return;\n\t\t\t\t\tnextQueryIndex = Math.max(nextQueryIndex, queryIndex + 1);\n\t\t\t\t\tconst eventData: CuratorSearchErrorEventData = { queryIndex, query: meta?.query ?? queries[queryIndex] ?? \"\", error, provider, slotIndex: meta?.slotIndex };\n\t\t\t\t\tretainStreamedEvent({ event: \"search-error\", data: eventData });\n\t\t\t\t\tsendSSE(\"search-error\", eventData);\n\t\t\t\t},\n\t\t\t\tsearchesDone: () => {\n\t\t\t\t\tif (completed) return;\n\t\t\t\t\tsearchStreamDone = true;\n\t\t\t\t\tsendSSE(\"done\", {});\n\t\t\t\t\tstate = \"RESULT_SELECTION\";\n\t\t\t\t\tstateChangedAt = Date.now();\n\t\t\t\t},\n\t\t\t\tgetConnectionState: () => ({\n\t\t\t\t\tbrowserConnected,\n\t\t\t\t\tlastHeartbeatAgeMs: Date.now() - lastHeartbeatAt,\n\t\t\t\t}),\n\t\t\t});\n\t\t});\n\t});\n}\n"]}
|
|
@@ -204,6 +204,8 @@ export function startCuratorServer(options, callbacks) {
|
|
|
204
204
|
return availableProviders.querit;
|
|
205
205
|
if (provider === "tavily")
|
|
206
206
|
return availableProviders.tavily;
|
|
207
|
+
if (provider === "firecrawl")
|
|
208
|
+
return availableProviders.firecrawl;
|
|
207
209
|
if (provider === "jina")
|
|
208
210
|
return availableProviders.jina;
|
|
209
211
|
if (provider === "serpdive")
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"curator-server.js","sourceRoot":"","sources":["../../../../src/humain/web-access/vendor/curator-server.ts"],"names":[],"mappings":"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","sourcesContent":["import http, { type IncomingMessage, type ServerResponse } from \"node:http\";\nimport { generateCuratorPage } from \"./curator-page.ts\";\nimport type { SummaryMeta } from \"./summary-review.ts\";\nimport { resolveCuratorNetworkConfig } from \"./utils.ts\";\n\nconst STALE_THRESHOLD_MS = 30000;\nconst WATCHDOG_INTERVAL_MS = 1000;\nconst MAX_BODY_SIZE = 64 * 1024;\n\ntype ServerState = \"SEARCHING\" | \"RESULT_SELECTION\" | \"COMPLETED\";\ntype CuratorResultEventData = IndexedCuratorSearchEntry & { slotIndex?: number };\ntype CuratorSearchErrorEventData = { queryIndex: number; query: string; error: string; provider?: string; slotIndex?: number };\ntype CuratorStoredEvent =\n\t| { event: \"result\"; data: CuratorResultEventData }\n\t| { event: \"search-error\"; data: CuratorSearchErrorEventData };\n\nexport interface CuratorServerOptions {\n\tqueries: string[];\n\tsessionToken: string;\n\ttimeout: number;\n\tavailableProviders: { all: boolean; openai: boolean; brave: boolean; parallel: boolean; tinyfish: boolean; search1api: boolean; searchinfinity: boolean; querit: boolean; tavily: boolean; jina: boolean; serpdive: boolean; kagi: boolean; bocha: boolean; ollama: boolean; searxng: boolean; duckduckgo: boolean; perplexity: boolean; exa: boolean; gemini: boolean; anysearch: boolean; xai: boolean; brightdata: boolean; serpbase: boolean };\n\tdefaultProvider: string;\n\tsearchProvider: string;\n\tsummaryModels: Array<{ value: string; label: string }>;\n\tdefaultSummaryModel: string | null;\n}\n\nexport interface CuratorSearchEntry {\n\tanswer: string;\n\tresults: Array<{ title: string; url: string; domain: string; snippet?: string }>;\n\tprovider: string;\n\terror?: string;\n}\n\nexport interface IndexedCuratorSearchEntry extends CuratorSearchEntry {\n\tqueryIndex: number;\n\tquery: string;\n}\n\nexport interface CuratorServerCallbacks {\n\tonSubmit: (payload: { selectedQueryIndices: number[]; summary?: string; summaryMeta?: SummaryMeta; rawResults?: boolean }) => void;\n\tonCancel: (reason: \"user\" | \"timeout\" | \"stale\") => void;\n\tonProviderChange: (provider: string) => void;\n\tonAddSearch: (query: string, provider?: string) => Promise<CuratorSearchEntry[]>;\n\tonAddSearchResults: (entries: IndexedCuratorSearchEntry[]) => void;\n\tonSummarize: (\n\t\tselectedQueryIndices: number[],\n\t\tsignal: AbortSignal,\n\t\tmodel?: string,\n\t\tfeedback?: string,\n\t) => Promise<{ summary: string; meta: SummaryMeta }>;\n\tonRewriteQuery: (query: string, signal: AbortSignal) => Promise<string>;\n}\n\nexport interface CuratorServerHandle {\n\tserver: http.Server;\n\turl: string;\n\tclose: () => void;\n\tpushResult: (queryIndex: number, data: CuratorSearchEntry & { query?: string; slotIndex?: number }) => void;\n\tpushError: (queryIndex: number, error: string, provider?: string, meta?: { query?: string; slotIndex?: number }) => void;\n\tsearchesDone: () => void;\n\t/** Reports browser connection state so a cancelled search can surface WHY it\n\t * went stale (e.g. the browser never connected). */\n\tgetConnectionState: () => { browserConnected: boolean; lastHeartbeatAgeMs: number };\n}\n\nfunction sendJson(res: ServerResponse, status: number, payload: unknown): void {\n\tres.writeHead(status, {\n\t\t\"Content-Type\": \"application/json\",\n\t\t\"Cache-Control\": \"no-store\",\n\t});\n\tres.end(JSON.stringify(payload));\n}\n\nfunction parseJSONBody(req: IncomingMessage): Promise<unknown> {\n\treturn new Promise((resolve, reject) => {\n\t\tlet body = \"\";\n\t\tlet size = 0;\n\t\treq.on(\"data\", (chunk: Buffer) => {\n\t\t\tsize += chunk.length;\n\t\t\tif (size > MAX_BODY_SIZE) {\n\t\t\t\treq.destroy();\n\t\t\t\treject(new Error(\"Request body too large\"));\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tbody += chunk.toString();\n\t\t});\n\t\treq.on(\"end\", () => {\n\t\t\ttry {\n\t\t\t\tresolve(JSON.parse(body));\n\t\t\t} catch (err) {\n\t\t\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\t\t\treject(new Error(`Invalid JSON: ${message}`));\n\t\t\t}\n\t\t});\n\t\treq.on(\"error\", reject);\n\t});\n}\n\nasync function parseBodyOrSend(req: IncomingMessage, res: ServerResponse): Promise<unknown | null> {\n\ttry {\n\t\treturn await parseJSONBody(req);\n\t} catch (err) {\n\t\tconst message = err instanceof Error ? err.message : \"Invalid body\";\n\t\tconst status = message === \"Request body too large\" ? 413 : 400;\n\t\tsendJson(res, status, { ok: false, error: message });\n\t\treturn null;\n\t}\n}\n\nfunction normalizeSelectedIndices(\n\tvalue: unknown,\n\toptions: { allowEmpty: boolean; maxExclusive: number },\n): { ok: true; indices: number[] } | { ok: false; error: string } {\n\tif (!Array.isArray(value)) {\n\t\treturn { ok: false, error: \"Invalid selection\" };\n\t}\n\n\tif (!options.allowEmpty && value.length === 0) {\n\t\treturn { ok: false, error: \"Invalid selection\" };\n\t}\n\n\tconst normalized: number[] = [];\n\tconst seen = new Set<number>();\n\tfor (const item of value) {\n\t\tif (typeof item !== \"number\" || !Number.isInteger(item) || item < 0) {\n\t\t\treturn { ok: false, error: \"Invalid selection\" };\n\t\t}\n\t\tif (item >= options.maxExclusive) {\n\t\t\treturn { ok: false, error: \"Invalid selection\" };\n\t\t}\n\t\tif (seen.has(item)) {\n\t\t\tcontinue;\n\t\t}\n\t\tseen.add(item);\n\t\tnormalized.push(item);\n\t}\n\n\tif (!options.allowEmpty && normalized.length === 0) {\n\t\treturn { ok: false, error: \"Invalid selection\" };\n\t}\n\n\treturn { ok: true, indices: normalized };\n}\n\nfunction normalizeSummaryMeta(value: unknown): SummaryMeta | null {\n\tif (!value || typeof value !== \"object\") return null;\n\tconst meta = value as Record<string, unknown>;\n\n\tconst model = meta.model === null\n\t\t? null\n\t\t: typeof meta.model === \"string\"\n\t\t\t? meta.model\n\t\t\t: undefined;\n\tif (model === undefined) return null;\n\n\tconst durationMs = meta.durationMs;\n\tif (typeof durationMs !== \"number\" || !Number.isFinite(durationMs) || durationMs < 0) return null;\n\n\tconst tokenEstimate = meta.tokenEstimate;\n\tif (typeof tokenEstimate !== \"number\" || !Number.isFinite(tokenEstimate) || tokenEstimate < 0) return null;\n\n\tconst fallbackUsed = meta.fallbackUsed;\n\tif (typeof fallbackUsed !== \"boolean\") return null;\n\n\tconst fallbackReason = typeof meta.fallbackReason === \"string\" ? meta.fallbackReason : undefined;\n\tif (meta.fallbackReason !== undefined && fallbackReason === undefined) return null;\n\n\tconst phase = meta.phase === \"summary-model\" || meta.phase === \"deterministic-fallback\"\n\t\t? meta.phase\n\t\t: undefined;\n\tif (meta.phase !== undefined && phase === undefined) return null;\n\tif (phase === \"deterministic-fallback\" && fallbackUsed !== true) return null;\n\tif (phase === \"summary-model\" && fallbackUsed !== false) return null;\n\n\tconst edited = typeof meta.edited === \"boolean\" ? meta.edited : undefined;\n\tif (meta.edited !== undefined && edited === undefined) return null;\n\n\treturn {\n\t\tmodel,\n\t\tdurationMs,\n\t\ttokenEstimate,\n\t\tfallbackUsed,\n\t\t...(fallbackReason !== undefined ? { fallbackReason } : {}),\n\t\t...(phase !== undefined ? { phase } : {}),\n\t\t...(edited !== undefined ? { edited } : {}),\n\t};\n}\n\nexport function startCuratorServer(\n\toptions: CuratorServerOptions,\n\tcallbacks: CuratorServerCallbacks,\n): Promise<CuratorServerHandle> {\n\tconst {\n\t\tqueries,\n\t\tsessionToken,\n\t\ttimeout,\n\t\tavailableProviders,\n\t\tdefaultProvider,\n\t\tsearchProvider,\n\t\tsummaryModels,\n\t\tdefaultSummaryModel,\n\t} = options;\n\tlet browserConnected = false;\n\tlet lastHeartbeatAt = Date.now();\n\tlet stateChangedAt = Date.now();\n\tlet clientIdleMs: number | null = null;\n\tlet clientTimeoutSeconds = timeout;\n\tlet completed = false;\n\tlet watchdog: NodeJS.Timeout | null = null;\n\tlet state: ServerState = \"SEARCHING\";\n\tlet sseResponse: ServerResponse | null = null;\n\tconst streamedEventsByResultIndex = new Map<number, CuratorStoredEvent>();\n\tlet searchStreamDone = queries.length === 0;\n\tlet nextQueryIndex = queries.length;\n\tlet summarizeAbortController: AbortController | null = null;\n\tlet summarizeRequestSeq = 0;\n\n\tlet sseKeepalive: NodeJS.Timeout | null = null;\n\n\tconst abortInFlightSummarize = (): void => {\n\t\tif (!summarizeAbortController) return;\n\t\tsummarizeAbortController.abort();\n\t\tsummarizeAbortController = null;\n\t};\n\n\tconst markCompleted = (): boolean => {\n\t\tif (completed) return false;\n\t\tcompleted = true;\n\t\tstate = \"COMPLETED\";\n\t\tstateChangedAt = Date.now();\n\t\tif (watchdog) {\n\t\t\tclearInterval(watchdog);\n\t\t\twatchdog = null;\n\t\t}\n\t\tif (sseKeepalive) {\n\t\t\tclearInterval(sseKeepalive);\n\t\t\tsseKeepalive = null;\n\t\t}\n\t\tabortInFlightSummarize();\n\t\tif (sseResponse) {\n\t\t\ttry { sseResponse.end(); } catch {}\n\t\t\tsseResponse = null;\n\t\t}\n\t\treturn true;\n\t};\n\n\tconst touchHeartbeat = (): void => {\n\t\tlastHeartbeatAt = Date.now();\n\t\tbrowserConnected = true;\n\t};\n\n\tconst getEffectiveTimeoutMs = (): number => Math.max(1000, Math.floor(clientTimeoutSeconds) * 1000);\n\n\tconst shouldTimeoutFromClientIdle = (): boolean => (\n\t\tstate === \"RESULT_SELECTION\" &&\n\t\tclientIdleMs !== null &&\n\t\tclientIdleMs >= getEffectiveTimeoutMs()\n\t);\n\n\tfunction validateToken(body: unknown, res: ServerResponse): boolean {\n\t\tif (!body || typeof body !== \"object\") {\n\t\t\tsendJson(res, 400, { ok: false, error: \"Invalid body\" });\n\t\t\treturn false;\n\t\t}\n\t\tif ((body as { token?: string }).token !== sessionToken) {\n\t\t\tsendJson(res, 403, { ok: false, error: \"Invalid session\" });\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t}\n\n\tfunction isAvailableProvider(provider: string): boolean {\n\t\tif (provider === \"all\") return availableProviders.all;\n\t\tif (provider === \"openai\") return availableProviders.openai;\n\t\tif (provider === \"brave\") return availableProviders.brave;\n\t\tif (provider === \"parallel\") return availableProviders.parallel;\n\t\tif (provider === \"tinyfish\") return availableProviders.tinyfish;\n\t\tif (provider === \"search1api\") return availableProviders.search1api;\n\t\tif (provider === \"searchinfinity\") return availableProviders.searchinfinity;\n\t\tif (provider === \"querit\") return availableProviders.querit;\n\t\tif (provider === \"tavily\") return availableProviders.tavily;\n\t\tif (provider === \"jina\") return availableProviders.jina;\n\t\tif (provider === \"serpdive\") return availableProviders.serpdive;\n\t\tif (provider === \"kagi\") return availableProviders.kagi;\n\t\tif (provider === \"bocha\") return availableProviders.bocha;\n\t\tif (provider === \"ollama\") return availableProviders.ollama;\n\t\tif (provider === \"searxng\") return availableProviders.searxng;\n\t\tif (provider === \"duckduckgo\") return availableProviders.duckduckgo;\n\t\tif (provider === \"perplexity\") return availableProviders.perplexity;\n\t\tif (provider === \"exa\") return availableProviders.exa;\n\t\tif (provider === \"gemini\") return availableProviders.gemini;\n\t\tif (provider === \"anysearch\") return availableProviders.anysearch;\n\t\tif (provider === \"xai\") return availableProviders.xai;\n\t\tif (provider === \"brightdata\") return availableProviders.brightdata;\n\t\tif (provider === \"serpbase\") return availableProviders.serpbase;\n\t\treturn false;\n\t}\n\n\tfunction writeSSE(res: ServerResponse, event: string, data: unknown): boolean {\n\t\tconst payload = `event: ${event}\\ndata: ${JSON.stringify(data)}\\n\\n`;\n\t\ttry {\n\t\t\tres.write(payload);\n\t\t\treturn true;\n\t\t} catch {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tfunction sendSSE(event: string, data: unknown): void {\n\t\tconst res = sseResponse;\n\t\tif (res && !res.writableEnded && res.socket && !res.socket.destroyed && writeSSE(res, event, data)) return;\n\t\tif (sseResponse === res) sseResponse = null;\n\t}\n\n\tfunction retainStreamedEvent(event: CuratorStoredEvent): void {\n\t\tstreamedEventsByResultIndex.set(event.data.queryIndex, event);\n\t}\n\n\tfunction getStreamedEvents(): CuratorStoredEvent[] {\n\t\treturn [...streamedEventsByResultIndex.values()];\n\t}\n\n\tfunction replaySSE(res: ServerResponse): void {\n\t\tfor (const item of getStreamedEvents()) {\n\t\t\tif (!writeSSE(res, item.event, item.data)) return;\n\t\t}\n\t\tif (searchStreamDone) writeSSE(res, \"done\", {});\n\t}\n\n\tconst pageHtml = generateCuratorPage(\n\t\tqueries,\n\t\tsessionToken,\n\t\ttimeout,\n\t\tavailableProviders,\n\t\tdefaultProvider,\n\t\tsearchProvider,\n\t\tsummaryModels,\n\t\tdefaultSummaryModel,\n\t);\n\n\tconst server = http.createServer(async (req, res) => {\n\t\ttry {\n\t\t\tconst method = req.method || \"GET\";\n\t\t\tconst url = new URL(req.url || \"/\", `http://${req.headers.host || \"127.0.0.1\"}`);\n\n\t\t\tif (method === \"GET\" && url.pathname === \"/\") {\n\t\t\t\tconst token = url.searchParams.get(\"session\");\n\t\t\t\tif (token !== sessionToken) {\n\t\t\t\t\tres.writeHead(403, { \"Content-Type\": \"text/plain\" });\n\t\t\t\t\tres.end(\"Invalid session\");\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\ttouchHeartbeat();\n\t\t\t\tres.writeHead(200, {\n\t\t\t\t\t\"Content-Type\": \"text/html; charset=utf-8\",\n\t\t\t\t\t\"Cache-Control\": \"no-store\",\n\t\t\t\t});\n\t\t\t\tres.end(pageHtml);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (method === \"GET\" && url.pathname === \"/events\") {\n\t\t\t\tconst token = url.searchParams.get(\"session\");\n\t\t\t\tif (token !== sessionToken) {\n\t\t\t\t\tres.writeHead(403, { \"Content-Type\": \"text/plain\" });\n\t\t\t\t\tres.end(\"Invalid session\");\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (state === \"COMPLETED\") {\n\t\t\t\t\tsendJson(res, 409, { ok: false, error: \"No events available\" });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (sseResponse) {\n\t\t\t\t\ttry { sseResponse.end(); } catch {}\n\t\t\t\t}\n\t\t\t\tres.writeHead(200, {\n\t\t\t\t\t\"Content-Type\": \"text/event-stream\",\n\t\t\t\t\t\"Cache-Control\": \"no-cache\",\n\t\t\t\t\tConnection: \"keep-alive\",\n\t\t\t\t\t\"X-Accel-Buffering\": \"no\",\n\t\t\t\t});\n\t\t\t\tres.flushHeaders();\n\t\t\t\tif (res.socket) res.socket.setNoDelay(true);\n\t\t\t\tsseResponse = res;\n\t\t\t\treplaySSE(res);\n\t\t\t\tif (sseKeepalive) clearInterval(sseKeepalive);\n\t\t\t\tsseKeepalive = setInterval(() => {\n\t\t\t\t\tif (sseResponse) {\n\t\t\t\t\t\ttry { sseResponse.write(\":keepalive\\n\\n\"); } catch {}\n\t\t\t\t\t}\n\t\t\t\t}, 15000);\n\t\t\t\treq.on(\"close\", () => {\n\t\t\t\t\tif (sseResponse === res) sseResponse = null;\n\t\t\t\t});\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (method === \"GET\" && url.pathname === \"/state\") {\n\t\t\t\tconst token = url.searchParams.get(\"session\");\n\t\t\t\tif (token !== sessionToken) {\n\t\t\t\t\tsendJson(res, 403, { ok: false, error: \"Invalid session\" });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\ttouchHeartbeat();\n\t\t\t\tsendJson(res, 200, { ok: true, events: getStreamedEvents(), done: searchStreamDone });\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (method === \"POST\" && url.pathname === \"/heartbeat\") {\n\t\t\t\tconst body = await parseBodyOrSend(req, res);\n\t\t\t\tif (!body) return;\n\t\t\t\tif (!validateToken(body, res)) return;\n\t\t\t\ttouchHeartbeat();\n\t\t\t\tconst heartbeat = body as { idleMs?: unknown; timeoutSec?: unknown };\n\t\t\t\tif (typeof heartbeat.timeoutSec === \"number\" && Number.isFinite(heartbeat.timeoutSec) && heartbeat.timeoutSec > 0) {\n\t\t\t\t\tclientTimeoutSeconds = Math.min(600, Math.floor(heartbeat.timeoutSec));\n\t\t\t\t}\n\t\t\t\tif (typeof heartbeat.idleMs === \"number\" && Number.isFinite(heartbeat.idleMs) && heartbeat.idleMs >= 0) {\n\t\t\t\t\tclientIdleMs = Math.floor(heartbeat.idleMs);\n\t\t\t\t}\n\t\t\t\tconst timedOut = shouldTimeoutFromClientIdle();\n\t\t\t\tsendJson(res, 200, { ok: true });\n\t\t\t\tif (timedOut && markCompleted()) {\n\t\t\t\t\tsetImmediate(() => callbacks.onCancel(\"timeout\"));\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (method === \"POST\" && url.pathname === \"/provider\") {\n\t\t\t\tconst body = await parseBodyOrSend(req, res);\n\t\t\t\tif (!body) return;\n\t\t\t\tif (!validateToken(body, res)) return;\n\t\t\t\tconst { provider } = body as { provider?: string };\n\t\t\t\tif (typeof provider !== \"string\" || provider.length === 0) {\n\t\t\t\t\tsendJson(res, 400, { ok: false, error: \"Invalid provider\" });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (!isAvailableProvider(provider)) {\n\t\t\t\t\tsendJson(res, 400, { ok: false, error: `Provider unavailable: ${provider}` });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tsetImmediate(() => callbacks.onProviderChange(provider));\n\t\t\t\tsendJson(res, 200, { ok: true });\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (method === \"POST\" && url.pathname === \"/search\") {\n\t\t\t\tconst body = await parseBodyOrSend(req, res);\n\t\t\t\tif (!body) return;\n\t\t\t\tif (!validateToken(body, res)) return;\n\t\t\t\tif (state === \"COMPLETED\") {\n\t\t\t\t\tsendJson(res, 409, { ok: false, error: \"Session closed\" });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst { query, provider } = body as { query?: string; provider?: string };\n\t\t\t\tif (typeof query !== \"string\" || query.trim().length === 0) {\n\t\t\t\t\tsendJson(res, 400, { ok: false, error: \"Invalid query\" });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (provider !== undefined) {\n\t\t\t\t\tif (typeof provider !== \"string\" || provider.length === 0) {\n\t\t\t\t\t\tsendJson(res, 400, { ok: false, error: \"Invalid provider\" });\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tif (!isAvailableProvider(provider)) {\n\t\t\t\t\t\tsendJson(res, 400, { ok: false, error: `Provider unavailable: ${provider}` });\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tconst qi = nextQueryIndex++;\n\t\t\t\tconst trimmedQuery = query.trim();\n\t\t\t\ttouchHeartbeat();\n\t\t\t\ttry {\n\t\t\t\t\tconst results = await callbacks.onAddSearch(trimmedQuery, provider);\n\t\t\t\t\tif (results.length === 0) throw new Error(\"Search returned no provider results\");\n\t\t\t\t\tconst entries = results.map((result, index): IndexedCuratorSearchEntry => ({\n\t\t\t\t\t\t...result,\n\t\t\t\t\t\tqueryIndex: index === 0 ? qi : nextQueryIndex++,\n\t\t\t\t\t\tquery: trimmedQuery,\n\t\t\t\t\t}));\n\t\t\t\t\tcallbacks.onAddSearchResults(entries);\n\t\t\t\t\tsendJson(res, 200, { ok: true, ...entries[0], entries });\n\t\t\t\t} catch (err) {\n\t\t\t\t\tconst message = err instanceof Error ? err.message : \"Search failed\";\n\t\t\t\t\tconst entry: IndexedCuratorSearchEntry = {\n\t\t\t\t\t\tqueryIndex: qi,\n\t\t\t\t\t\tquery: trimmedQuery,\n\t\t\t\t\t\tanswer: \"\",\n\t\t\t\t\t\tresults: [],\n\t\t\t\t\t\terror: message,\n\t\t\t\t\t\tprovider: typeof provider === \"string\" && provider.length > 0 ? provider : defaultProvider,\n\t\t\t\t\t};\n\t\t\t\t\tcallbacks.onAddSearchResults([entry]);\n\t\t\t\t\tsendJson(res, 200, { ok: true, ...entry, entries: [entry] });\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (method === \"POST\" && url.pathname === \"/summarize\") {\n\t\t\t\tconst body = await parseBodyOrSend(req, res);\n\t\t\t\tif (!body) return;\n\t\t\t\tif (!validateToken(body, res)) return;\n\t\t\t\tif (state === \"COMPLETED\") {\n\t\t\t\t\tsendJson(res, 409, { ok: false, error: \"Session closed\" });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst parsed = normalizeSelectedIndices((body as { selected?: unknown }).selected, {\n\t\t\t\t\tallowEmpty: false,\n\t\t\t\t\tmaxExclusive: nextQueryIndex,\n\t\t\t\t});\n\t\t\t\tif (\"error\" in parsed) {\n\t\t\t\t\tsendJson(res, 400, { ok: false, error: parsed.error });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tlet model: string | undefined;\n\t\t\t\tconst bodyModel = (body as { model?: unknown }).model;\n\t\t\t\tif (bodyModel !== undefined) {\n\t\t\t\t\tif (typeof bodyModel !== \"string\") {\n\t\t\t\t\t\tsendJson(res, 400, { ok: false, error: \"Invalid model\" });\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tconst trimmedModel = bodyModel.trim();\n\t\t\t\t\tmodel = trimmedModel.length > 0 ? trimmedModel : undefined;\n\t\t\t\t}\n\n\t\t\t\tconst bodyFeedback = (body as { feedback?: unknown }).feedback;\n\t\t\t\tconst feedback = typeof bodyFeedback === \"string\" && bodyFeedback.trim().length > 0\n\t\t\t\t\t? bodyFeedback.trim()\n\t\t\t\t\t: undefined;\n\n\t\t\t\tabortInFlightSummarize();\n\t\t\t\tconst controller = new AbortController();\n\t\t\t\tsummarizeAbortController = controller;\n\t\t\t\tconst requestId = ++summarizeRequestSeq;\n\n\t\t\t\ttry {\n\t\t\t\t\tconst result = await callbacks.onSummarize(parsed.indices, controller.signal, model, feedback);\n\t\t\t\t\tif (requestId !== summarizeRequestSeq || completed) {\n\t\t\t\t\t\tsendJson(res, 409, { ok: false, error: \"Summarize request superseded\" });\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tsendJson(res, 200, {\n\t\t\t\t\t\tok: true,\n\t\t\t\t\t\tsummary: result.summary,\n\t\t\t\t\t\tmeta: result.meta,\n\t\t\t\t\t});\n\t\t\t\t} catch (err) {\n\t\t\t\t\tconst message = err instanceof Error ? err.message : \"Summary generation failed\";\n\t\t\t\t\tconst status = controller.signal.aborted ? 409 : 500;\n\t\t\t\t\tsendJson(res, status, { ok: false, error: message });\n\t\t\t\t} finally {\n\t\t\t\t\tif (summarizeAbortController === controller) {\n\t\t\t\t\t\tsummarizeAbortController = null;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (method === \"POST\" && url.pathname === \"/rewrite\") {\n\t\t\t\tconst body = await parseBodyOrSend(req, res);\n\t\t\t\tif (!body) return;\n\t\t\t\tif (!validateToken(body, res)) return;\n\t\t\t\tif (state === \"COMPLETED\") {\n\t\t\t\t\tsendJson(res, 409, { ok: false, error: \"Session closed\" });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst { query } = body as { query?: unknown };\n\t\t\t\tif (typeof query !== \"string\" || query.trim().length === 0) {\n\t\t\t\t\tsendJson(res, 400, { ok: false, error: \"Invalid query\" });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst controller = new AbortController();\n\t\t\t\treq.on(\"close\", () => controller.abort());\n\t\t\t\ttouchHeartbeat();\n\t\t\t\ttry {\n\t\t\t\t\tconst rewritten = await callbacks.onRewriteQuery(query.trim(), controller.signal);\n\t\t\t\t\tsendJson(res, 200, { ok: true, query: rewritten });\n\t\t\t\t} catch (err) {\n\t\t\t\t\tconst message = err instanceof Error ? err.message : \"Rewrite failed\";\n\t\t\t\t\tconst status = controller.signal.aborted ? 409 : 500;\n\t\t\t\t\tsendJson(res, status, { ok: false, error: message });\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (method === \"POST\" && url.pathname === \"/submit\") {\n\t\t\t\tconst body = await parseBodyOrSend(req, res);\n\t\t\t\tif (!body) return;\n\t\t\t\tif (!validateToken(body, res)) return;\n\n\t\t\t\tconst parsed = normalizeSelectedIndices((body as { selected?: unknown }).selected, {\n\t\t\t\t\tallowEmpty: true,\n\t\t\t\t\tmaxExclusive: nextQueryIndex,\n\t\t\t\t});\n\t\t\t\tif (\"error\" in parsed) {\n\t\t\t\t\tsendJson(res, 400, { ok: false, error: parsed.error });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tlet summary: string | undefined;\n\t\t\t\tconst bodySummary = (body as { summary?: unknown }).summary;\n\t\t\t\tif (bodySummary !== undefined) {\n\t\t\t\t\tif (typeof bodySummary !== \"string\") {\n\t\t\t\t\t\tsendJson(res, 400, { ok: false, error: \"Invalid summary\" });\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tconst trimmedSummary = bodySummary.trim();\n\t\t\t\t\tsummary = trimmedSummary.length > 0 ? trimmedSummary : undefined;\n\t\t\t\t}\n\n\t\t\t\tlet summaryMeta: SummaryMeta | undefined;\n\t\t\t\tconst bodySummaryMeta = (body as { summaryMeta?: unknown }).summaryMeta;\n\t\t\t\tif (bodySummaryMeta !== undefined) {\n\t\t\t\t\tconst parsedSummaryMeta = normalizeSummaryMeta(bodySummaryMeta);\n\t\t\t\t\tif (!parsedSummaryMeta) {\n\t\t\t\t\t\tsendJson(res, 400, { ok: false, error: \"Invalid summaryMeta\" });\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tsummaryMeta = parsedSummaryMeta;\n\t\t\t\t}\n\n\t\t\t\tif (state !== \"SEARCHING\" && state !== \"RESULT_SELECTION\") {\n\t\t\t\t\tsendJson(res, 409, { ok: false, error: \"Cannot submit in current state\" });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (!markCompleted()) {\n\t\t\t\t\tsendJson(res, 409, { ok: false, error: \"Session closed\" });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst rawResults = (body as { rawResults?: unknown }).rawResults === true;\n\t\t\t\tsendJson(res, 200, { ok: true });\n\t\t\t\tsetImmediate(() => callbacks.onSubmit({\n\t\t\t\t\tselectedQueryIndices: parsed.indices,\n\t\t\t\t\t...(summary !== undefined ? { summary } : {}),\n\t\t\t\t\t...(summaryMeta !== undefined ? { summaryMeta } : {}),\n\t\t\t\t\trawResults,\n\t\t\t\t}));\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (method === \"POST\" && url.pathname === \"/cancel\") {\n\t\t\t\tconst body = await parseBodyOrSend(req, res);\n\t\t\t\tif (!body) return;\n\t\t\t\tif (!validateToken(body, res)) return;\n\t\t\t\tif (!markCompleted()) {\n\t\t\t\t\tsendJson(res, 200, { ok: true });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst { reason } = body as { reason?: string };\n\t\t\t\tsendJson(res, 200, { ok: true });\n\t\t\t\tconst cancelReason = reason === \"timeout\" ? \"timeout\" : \"user\";\n\t\t\t\tsetImmediate(() => callbacks.onCancel(cancelReason));\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tres.writeHead(404, { \"Content-Type\": \"text/plain\" });\n\t\t\tres.end(\"Not found\");\n\t\t} catch (err) {\n\t\t\tconst message = err instanceof Error ? err.message : \"Server error\";\n\t\t\tsendJson(res, 500, { ok: false, error: message });\n\t\t}\n\t});\n\n\treturn new Promise((resolve, reject) => {\n\t\tconst onError = (err: Error) => {\n\t\t\treject(new Error(`Curator server failed to start: ${err.message}`));\n\t\t};\n\n\t\tconst networkConfig = resolveCuratorNetworkConfig();\n\n\t\tserver.once(\"error\", onError);\n\t\tserver.listen(0, networkConfig.bind, () => {\n\t\t\tserver.off(\"error\", onError);\n\t\t\tconst addr = server.address();\n\t\t\tif (!addr || typeof addr === \"string\") {\n\t\t\t\treject(new Error(\"Curator server: invalid address\"));\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst url = `http://${networkConfig.host}:${addr.port}/?session=${sessionToken}`;\n\n\t\t\twatchdog = setInterval(() => {\n\t\t\t\tif (completed) return;\n\t\t\t\tif (!browserConnected) {\n\t\t\t\t\tconst noBrowserTimeoutMs = Math.max(5000, getEffectiveTimeoutMs());\n\t\t\t\t\tif (state !== \"RESULT_SELECTION\") return;\n\t\t\t\t\tif (Date.now() - stateChangedAt <= noBrowserTimeoutMs) return;\n\t\t\t\t\tif (!markCompleted()) return;\n\t\t\t\t\tsetImmediate(() => callbacks.onCancel(\"timeout\"));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (shouldTimeoutFromClientIdle()) {\n\t\t\t\t\tif (!markCompleted()) return;\n\t\t\t\t\tsetImmediate(() => callbacks.onCancel(\"timeout\"));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (Date.now() - lastHeartbeatAt <= STALE_THRESHOLD_MS) return;\n\t\t\t\tconst staleReason = state === \"RESULT_SELECTION\" ? \"timeout\" : \"stale\";\n\t\t\t\tif (!markCompleted()) return;\n\t\t\t\tsetImmediate(() => callbacks.onCancel(staleReason));\n\t\t\t}, WATCHDOG_INTERVAL_MS);\n\n\t\t\tresolve({\n\t\t\t\tserver,\n\t\t\t\turl,\n\t\t\t\tclose: () => {\n\t\t\t\t\tconst wasOpen = markCompleted();\n\t\t\t\t\ttry { server.close(); } catch {}\n\t\t\t\t\tif (wasOpen) {\n\t\t\t\t\t\tsetImmediate(() => callbacks.onCancel(\"stale\"));\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tpushResult: (queryIndex, data) => {\n\t\t\t\t\tif (completed) return;\n\t\t\t\t\tnextQueryIndex = Math.max(nextQueryIndex, queryIndex + 1);\n\t\t\t\t\tconst eventData: CuratorResultEventData = { ...data, queryIndex, query: data.query ?? queries[queryIndex] ?? \"\" };\n\t\t\t\t\tretainStreamedEvent({ event: \"result\", data: eventData });\n\t\t\t\t\tsendSSE(\"result\", eventData);\n\t\t\t\t},\n\t\t\t\tpushError: (queryIndex, error, provider, meta) => {\n\t\t\t\t\tif (completed) return;\n\t\t\t\t\tnextQueryIndex = Math.max(nextQueryIndex, queryIndex + 1);\n\t\t\t\t\tconst eventData: CuratorSearchErrorEventData = { queryIndex, query: meta?.query ?? queries[queryIndex] ?? \"\", error, provider, slotIndex: meta?.slotIndex };\n\t\t\t\t\tretainStreamedEvent({ event: \"search-error\", data: eventData });\n\t\t\t\t\tsendSSE(\"search-error\", eventData);\n\t\t\t\t},\n\t\t\t\tsearchesDone: () => {\n\t\t\t\t\tif (completed) return;\n\t\t\t\t\tsearchStreamDone = true;\n\t\t\t\t\tsendSSE(\"done\", {});\n\t\t\t\t\tstate = \"RESULT_SELECTION\";\n\t\t\t\t\tstateChangedAt = Date.now();\n\t\t\t\t},\n\t\t\t\tgetConnectionState: () => ({\n\t\t\t\t\tbrowserConnected,\n\t\t\t\t\tlastHeartbeatAgeMs: Date.now() - lastHeartbeatAt,\n\t\t\t\t}),\n\t\t\t});\n\t\t});\n\t});\n}\n"]}
|
|
1
|
+
{"version":3,"file":"curator-server.js","sourceRoot":"","sources":["../../../../src/humain/web-access/vendor/curator-server.ts"],"names":[],"mappings":"AAAA,OAAO,IAAmD,MAAM,WAAW,CAAC;AAC5E,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAExD,OAAO,EAAE,2BAA2B,EAAE,MAAM,YAAY,CAAC;AAEzD,MAAM,kBAAkB,GAAG,KAAK,CAAC;AACjC,MAAM,oBAAoB,GAAG,IAAI,CAAC;AAClC,MAAM,aAAa,GAAG,EAAE,GAAG,IAAI,CAAC;AA2DhC,SAAS,QAAQ,CAAC,GAAmB,EAAE,MAAc,EAAE,OAAgB,EAAQ;IAC9E,GAAG,CAAC,SAAS,CAAC,MAAM,EAAE;QACrB,cAAc,EAAE,kBAAkB;QAClC,eAAe,EAAE,UAAU;KAC3B,CAAC,CAAC;IACH,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC;AAAA,CACjC;AAED,SAAS,aAAa,CAAC,GAAoB,EAAoB;IAC9D,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,CAAC;QACvC,IAAI,IAAI,GAAG,EAAE,CAAC;QACd,IAAI,IAAI,GAAG,CAAC,CAAC;QACb,GAAG,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE,CAAC;YACjC,IAAI,IAAI,KAAK,CAAC,MAAM,CAAC;YACrB,IAAI,IAAI,GAAG,aAAa,EAAE,CAAC;gBAC1B,GAAG,CAAC,OAAO,EAAE,CAAC;gBACd,MAAM,CAAC,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC,CAAC;gBAC5C,OAAO;YACR,CAAC;YACD,IAAI,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;QAAA,CACzB,CAAC,CAAC;QACH,GAAG,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,CAAC;YACnB,IAAI,CAAC;gBACJ,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;YAC3B,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACd,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;gBACjE,MAAM,CAAC,IAAI,KAAK,CAAC,iBAAiB,OAAO,EAAE,CAAC,CAAC,CAAC;YAC/C,CAAC;QAAA,CACD,CAAC,CAAC;QACH,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAAA,CACxB,CAAC,CAAC;AAAA,CACH;AAED,KAAK,UAAU,eAAe,CAAC,GAAoB,EAAE,GAAmB,EAA2B;IAClG,IAAI,CAAC;QACJ,OAAO,MAAM,aAAa,CAAC,GAAG,CAAC,CAAC;IACjC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACd,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,cAAc,CAAC;QACpE,MAAM,MAAM,GAAG,OAAO,KAAK,wBAAwB,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;QAChE,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC;QACrD,OAAO,IAAI,CAAC;IACb,CAAC;AAAA,CACD;AAED,SAAS,wBAAwB,CAChC,KAAc,EACd,OAAsD,EACW;IACjE,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QAC3B,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,mBAAmB,EAAE,CAAC;IAClD,CAAC;IAED,IAAI,CAAC,OAAO,CAAC,UAAU,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC/C,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,mBAAmB,EAAE,CAAC;IAClD,CAAC;IAED,MAAM,UAAU,GAAa,EAAE,CAAC;IAChC,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QAC1B,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,IAAI,GAAG,CAAC,EAAE,CAAC;YACrE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,mBAAmB,EAAE,CAAC;QAClD,CAAC;QACD,IAAI,IAAI,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;YAClC,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,mBAAmB,EAAE,CAAC;QAClD,CAAC;QACD,IAAI,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YACpB,SAAS;QACV,CAAC;QACD,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACf,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACvB,CAAC;IAED,IAAI,CAAC,OAAO,CAAC,UAAU,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACpD,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,mBAAmB,EAAE,CAAC;IAClD,CAAC;IAED,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,UAAU,EAAE,CAAC;AAAA,CACzC;AAED,SAAS,oBAAoB,CAAC,KAAc,EAAsB;IACjE,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC;IACrD,MAAM,IAAI,GAAG,KAAgC,CAAC;IAE9C,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,KAAK,IAAI;QAChC,CAAC,CAAC,IAAI;QACN,CAAC,CAAC,OAAO,IAAI,CAAC,KAAK,KAAK,QAAQ;YAC/B,CAAC,CAAC,IAAI,CAAC,KAAK;YACZ,CAAC,CAAC,SAAS,CAAC;IACd,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,IAAI,CAAC;IAErC,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC;IACnC,IAAI,OAAO,UAAU,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,UAAU,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IAElG,MAAM,aAAa,GAAG,IAAI,CAAC,aAAa,CAAC;IACzC,IAAI,OAAO,aAAa,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,aAAa,CAAC,IAAI,aAAa,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IAE3G,MAAM,YAAY,GAAG,IAAI,CAAC,YAAY,CAAC;IACvC,IAAI,OAAO,YAAY,KAAK,SAAS;QAAE,OAAO,IAAI,CAAC;IAEnD,MAAM,cAAc,GAAG,OAAO,IAAI,CAAC,cAAc,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,SAAS,CAAC;IACjG,IAAI,IAAI,CAAC,cAAc,KAAK,SAAS,IAAI,cAAc,KAAK,SAAS;QAAE,OAAO,IAAI,CAAC;IAEnF,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,KAAK,eAAe,IAAI,IAAI,CAAC,KAAK,KAAK,wBAAwB;QACtF,CAAC,CAAC,IAAI,CAAC,KAAK;QACZ,CAAC,CAAC,SAAS,CAAC;IACb,IAAI,IAAI,CAAC,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,IAAI,CAAC;IACjE,IAAI,KAAK,KAAK,wBAAwB,IAAI,YAAY,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAC7E,IAAI,KAAK,KAAK,eAAe,IAAI,YAAY,KAAK,KAAK;QAAE,OAAO,IAAI,CAAC;IAErE,MAAM,MAAM,GAAG,OAAO,IAAI,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC;IAC1E,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS,IAAI,MAAM,KAAK,SAAS;QAAE,OAAO,IAAI,CAAC;IAEnE,OAAO;QACN,KAAK;QACL,UAAU;QACV,aAAa;QACb,YAAY;QACZ,GAAG,CAAC,cAAc,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC3D,GAAG,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACzC,GAAG,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC3C,CAAC;AAAA,CACF;AAED,MAAM,UAAU,kBAAkB,CACjC,OAA6B,EAC7B,SAAiC,EACF;IAC/B,MAAM,EACL,OAAO,EACP,YAAY,EACZ,OAAO,EACP,kBAAkB,EAClB,eAAe,EACf,cAAc,EACd,aAAa,EACb,mBAAmB,GACnB,GAAG,OAAO,CAAC;IACZ,IAAI,gBAAgB,GAAG,KAAK,CAAC;IAC7B,IAAI,eAAe,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACjC,IAAI,cAAc,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAChC,IAAI,YAAY,GAAkB,IAAI,CAAC;IACvC,IAAI,oBAAoB,GAAG,OAAO,CAAC;IACnC,IAAI,SAAS,GAAG,KAAK,CAAC;IACtB,IAAI,QAAQ,GAA0B,IAAI,CAAC;IAC3C,IAAI,KAAK,GAAgB,WAAW,CAAC;IACrC,IAAI,WAAW,GAA0B,IAAI,CAAC;IAC9C,MAAM,2BAA2B,GAAG,IAAI,GAAG,EAA8B,CAAC;IAC1E,IAAI,gBAAgB,GAAG,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC;IAC5C,IAAI,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC;IACpC,IAAI,wBAAwB,GAA2B,IAAI,CAAC;IAC5D,IAAI,mBAAmB,GAAG,CAAC,CAAC;IAE5B,IAAI,YAAY,GAA0B,IAAI,CAAC;IAE/C,MAAM,sBAAsB,GAAG,GAAS,EAAE,CAAC;QAC1C,IAAI,CAAC,wBAAwB;YAAE,OAAO;QACtC,wBAAwB,CAAC,KAAK,EAAE,CAAC;QACjC,wBAAwB,GAAG,IAAI,CAAC;IAAA,CAChC,CAAC;IAEF,MAAM,aAAa,GAAG,GAAY,EAAE,CAAC;QACpC,IAAI,SAAS;YAAE,OAAO,KAAK,CAAC;QAC5B,SAAS,GAAG,IAAI,CAAC;QACjB,KAAK,GAAG,WAAW,CAAC;QACpB,cAAc,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC5B,IAAI,QAAQ,EAAE,CAAC;YACd,aAAa,CAAC,QAAQ,CAAC,CAAC;YACxB,QAAQ,GAAG,IAAI,CAAC;QACjB,CAAC;QACD,IAAI,YAAY,EAAE,CAAC;YAClB,aAAa,CAAC,YAAY,CAAC,CAAC;YAC5B,YAAY,GAAG,IAAI,CAAC;QACrB,CAAC;QACD,sBAAsB,EAAE,CAAC;QACzB,IAAI,WAAW,EAAE,CAAC;YACjB,IAAI,CAAC;gBAAC,WAAW,CAAC,GAAG,EAAE,CAAC;YAAC,CAAC;YAAC,MAAM,CAAC,CAAA,CAAC;YACnC,WAAW,GAAG,IAAI,CAAC;QACpB,CAAC;QACD,OAAO,IAAI,CAAC;IAAA,CACZ,CAAC;IAEF,MAAM,cAAc,GAAG,GAAS,EAAE,CAAC;QAClC,eAAe,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC7B,gBAAgB,GAAG,IAAI,CAAC;IAAA,CACxB,CAAC;IAEF,MAAM,qBAAqB,GAAG,GAAW,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,oBAAoB,CAAC,GAAG,IAAI,CAAC,CAAC;IAEpG,MAAM,2BAA2B,GAAG,GAAY,EAAE,CAAC,CAClD,KAAK,KAAK,kBAAkB;QAC5B,YAAY,KAAK,IAAI;QACrB,YAAY,IAAI,qBAAqB,EAAE,CACvC,CAAC;IAEF,SAAS,aAAa,CAAC,IAAa,EAAE,GAAmB,EAAW;QACnE,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;YACvC,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,cAAc,EAAE,CAAC,CAAC;YACzD,OAAO,KAAK,CAAC;QACd,CAAC;QACD,IAAK,IAA2B,CAAC,KAAK,KAAK,YAAY,EAAE,CAAC;YACzD,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,iBAAiB,EAAE,CAAC,CAAC;YAC5D,OAAO,KAAK,CAAC;QACd,CAAC;QACD,OAAO,IAAI,CAAC;IAAA,CACZ;IAED,SAAS,mBAAmB,CAAC,QAAgB,EAAW;QACvD,IAAI,QAAQ,KAAK,KAAK;YAAE,OAAO,kBAAkB,CAAC,GAAG,CAAC;QACtD,IAAI,QAAQ,KAAK,QAAQ;YAAE,OAAO,kBAAkB,CAAC,MAAM,CAAC;QAC5D,IAAI,QAAQ,KAAK,OAAO;YAAE,OAAO,kBAAkB,CAAC,KAAK,CAAC;QAC1D,IAAI,QAAQ,KAAK,UAAU;YAAE,OAAO,kBAAkB,CAAC,QAAQ,CAAC;QAChE,IAAI,QAAQ,KAAK,UAAU;YAAE,OAAO,kBAAkB,CAAC,QAAQ,CAAC;QAChE,IAAI,QAAQ,KAAK,YAAY;YAAE,OAAO,kBAAkB,CAAC,UAAU,CAAC;QACpE,IAAI,QAAQ,KAAK,gBAAgB;YAAE,OAAO,kBAAkB,CAAC,cAAc,CAAC;QAC5E,IAAI,QAAQ,KAAK,QAAQ;YAAE,OAAO,kBAAkB,CAAC,MAAM,CAAC;QAC5D,IAAI,QAAQ,KAAK,QAAQ;YAAE,OAAO,kBAAkB,CAAC,MAAM,CAAC;QAC5D,IAAI,QAAQ,KAAK,WAAW;YAAE,OAAO,kBAAkB,CAAC,SAAS,CAAC;QAClE,IAAI,QAAQ,KAAK,MAAM;YAAE,OAAO,kBAAkB,CAAC,IAAI,CAAC;QACxD,IAAI,QAAQ,KAAK,UAAU;YAAE,OAAO,kBAAkB,CAAC,QAAQ,CAAC;QAChE,IAAI,QAAQ,KAAK,MAAM;YAAE,OAAO,kBAAkB,CAAC,IAAI,CAAC;QACxD,IAAI,QAAQ,KAAK,OAAO;YAAE,OAAO,kBAAkB,CAAC,KAAK,CAAC;QAC1D,IAAI,QAAQ,KAAK,QAAQ;YAAE,OAAO,kBAAkB,CAAC,MAAM,CAAC;QAC5D,IAAI,QAAQ,KAAK,SAAS;YAAE,OAAO,kBAAkB,CAAC,OAAO,CAAC;QAC9D,IAAI,QAAQ,KAAK,YAAY;YAAE,OAAO,kBAAkB,CAAC,UAAU,CAAC;QACpE,IAAI,QAAQ,KAAK,YAAY;YAAE,OAAO,kBAAkB,CAAC,UAAU,CAAC;QACpE,IAAI,QAAQ,KAAK,KAAK;YAAE,OAAO,kBAAkB,CAAC,GAAG,CAAC;QACtD,IAAI,QAAQ,KAAK,QAAQ;YAAE,OAAO,kBAAkB,CAAC,MAAM,CAAC;QAC5D,IAAI,QAAQ,KAAK,WAAW;YAAE,OAAO,kBAAkB,CAAC,SAAS,CAAC;QAClE,IAAI,QAAQ,KAAK,KAAK;YAAE,OAAO,kBAAkB,CAAC,GAAG,CAAC;QACtD,IAAI,QAAQ,KAAK,YAAY;YAAE,OAAO,kBAAkB,CAAC,UAAU,CAAC;QACpE,IAAI,QAAQ,KAAK,UAAU;YAAE,OAAO,kBAAkB,CAAC,QAAQ,CAAC;QAChE,OAAO,KAAK,CAAC;IAAA,CACb;IAED,SAAS,QAAQ,CAAC,GAAmB,EAAE,KAAa,EAAE,IAAa,EAAW;QAC7E,MAAM,OAAO,GAAG,UAAU,KAAK,WAAW,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC;QACrE,IAAI,CAAC;YACJ,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YACnB,OAAO,IAAI,CAAC;QACb,CAAC;QAAC,MAAM,CAAC;YACR,OAAO,KAAK,CAAC;QACd,CAAC;IAAA,CACD;IAED,SAAS,OAAO,CAAC,KAAa,EAAE,IAAa,EAAQ;QACpD,MAAM,GAAG,GAAG,WAAW,CAAC;QACxB,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,aAAa,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,IAAI,QAAQ,CAAC,GAAG,EAAE,KAAK,EAAE,IAAI,CAAC;YAAE,OAAO;QAC3G,IAAI,WAAW,KAAK,GAAG;YAAE,WAAW,GAAG,IAAI,CAAC;IAAA,CAC5C;IAED,SAAS,mBAAmB,CAAC,KAAyB,EAAQ;QAC7D,2BAA2B,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;IAAA,CAC9D;IAED,SAAS,iBAAiB,GAAyB;QAClD,OAAO,CAAC,GAAG,2BAA2B,CAAC,MAAM,EAAE,CAAC,CAAC;IAAA,CACjD;IAED,SAAS,SAAS,CAAC,GAAmB,EAAQ;QAC7C,KAAK,MAAM,IAAI,IAAI,iBAAiB,EAAE,EAAE,CAAC;YACxC,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,IAAI,CAAC;gBAAE,OAAO;QACnD,CAAC;QACD,IAAI,gBAAgB;YAAE,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC;IAAA,CAChD;IAED,MAAM,QAAQ,GAAG,mBAAmB,CACnC,OAAO,EACP,YAAY,EACZ,OAAO,EACP,kBAAkB,EAClB,eAAe,EACf,cAAc,EACd,aAAa,EACb,mBAAmB,CACnB,CAAC;IAEF,MAAM,MAAM,GAAG,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,CAAC;QACpD,IAAI,CAAC;YACJ,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,IAAI,KAAK,CAAC;YACnC,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,IAAI,GAAG,EAAE,UAAU,GAAG,CAAC,OAAO,CAAC,IAAI,IAAI,WAAW,EAAE,CAAC,CAAC;YAEjF,IAAI,MAAM,KAAK,KAAK,IAAI,GAAG,CAAC,QAAQ,KAAK,GAAG,EAAE,CAAC;gBAC9C,MAAM,KAAK,GAAG,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;gBAC9C,IAAI,KAAK,KAAK,YAAY,EAAE,CAAC;oBAC5B,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,YAAY,EAAE,CAAC,CAAC;oBACrD,GAAG,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;oBAC3B,OAAO;gBACR,CAAC;gBACD,cAAc,EAAE,CAAC;gBACjB,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE;oBAClB,cAAc,EAAE,0BAA0B;oBAC1C,eAAe,EAAE,UAAU;iBAC3B,CAAC,CAAC;gBACH,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;gBAClB,OAAO;YACR,CAAC;YAED,IAAI,MAAM,KAAK,KAAK,IAAI,GAAG,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;gBACpD,MAAM,KAAK,GAAG,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;gBAC9C,IAAI,KAAK,KAAK,YAAY,EAAE,CAAC;oBAC5B,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,YAAY,EAAE,CAAC,CAAC;oBACrD,GAAG,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;oBAC3B,OAAO;gBACR,CAAC;gBACD,IAAI,KAAK,KAAK,WAAW,EAAE,CAAC;oBAC3B,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,qBAAqB,EAAE,CAAC,CAAC;oBAChE,OAAO;gBACR,CAAC;gBACD,IAAI,WAAW,EAAE,CAAC;oBACjB,IAAI,CAAC;wBAAC,WAAW,CAAC,GAAG,EAAE,CAAC;oBAAC,CAAC;oBAAC,MAAM,CAAC,CAAA,CAAC;gBACpC,CAAC;gBACD,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE;oBAClB,cAAc,EAAE,mBAAmB;oBACnC,eAAe,EAAE,UAAU;oBAC3B,UAAU,EAAE,YAAY;oBACxB,mBAAmB,EAAE,IAAI;iBACzB,CAAC,CAAC;gBACH,GAAG,CAAC,YAAY,EAAE,CAAC;gBACnB,IAAI,GAAG,CAAC,MAAM;oBAAE,GAAG,CAAC,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;gBAC5C,WAAW,GAAG,GAAG,CAAC;gBAClB,SAAS,CAAC,GAAG,CAAC,CAAC;gBACf,IAAI,YAAY;oBAAE,aAAa,CAAC,YAAY,CAAC,CAAC;gBAC9C,YAAY,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;oBAChC,IAAI,WAAW,EAAE,CAAC;wBACjB,IAAI,CAAC;4BAAC,WAAW,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC;wBAAC,CAAC;wBAAC,MAAM,CAAC,CAAA,CAAC;oBACtD,CAAC;gBAAA,CACD,EAAE,KAAK,CAAC,CAAC;gBACV,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC;oBACrB,IAAI,WAAW,KAAK,GAAG;wBAAE,WAAW,GAAG,IAAI,CAAC;gBAAA,CAC5C,CAAC,CAAC;gBACH,OAAO;YACR,CAAC;YAED,IAAI,MAAM,KAAK,KAAK,IAAI,GAAG,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;gBACnD,MAAM,KAAK,GAAG,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;gBAC9C,IAAI,KAAK,KAAK,YAAY,EAAE,CAAC;oBAC5B,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,iBAAiB,EAAE,CAAC,CAAC;oBAC5D,OAAO;gBACR,CAAC;gBACD,cAAc,EAAE,CAAC;gBACjB,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,iBAAiB,EAAE,EAAE,IAAI,EAAE,gBAAgB,EAAE,CAAC,CAAC;gBACtF,OAAO;YACR,CAAC;YAED,IAAI,MAAM,KAAK,MAAM,IAAI,GAAG,CAAC,QAAQ,KAAK,YAAY,EAAE,CAAC;gBACxD,MAAM,IAAI,GAAG,MAAM,eAAe,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;gBAC7C,IAAI,CAAC,IAAI;oBAAE,OAAO;gBAClB,IAAI,CAAC,aAAa,CAAC,IAAI,EAAE,GAAG,CAAC;oBAAE,OAAO;gBACtC,cAAc,EAAE,CAAC;gBACjB,MAAM,SAAS,GAAG,IAAkD,CAAC;gBACrE,IAAI,OAAO,SAAS,CAAC,UAAU,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,UAAU,CAAC,IAAI,SAAS,CAAC,UAAU,GAAG,CAAC,EAAE,CAAC;oBACnH,oBAAoB,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC;gBACxE,CAAC;gBACD,IAAI,OAAO,SAAS,CAAC,MAAM,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,SAAS,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC;oBACxG,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;gBAC7C,CAAC;gBACD,MAAM,QAAQ,GAAG,2BAA2B,EAAE,CAAC;gBAC/C,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;gBACjC,IAAI,QAAQ,IAAI,aAAa,EAAE,EAAE,CAAC;oBACjC,YAAY,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC;gBACnD,CAAC;gBACD,OAAO;YACR,CAAC;YAED,IAAI,MAAM,KAAK,MAAM,IAAI,GAAG,CAAC,QAAQ,KAAK,WAAW,EAAE,CAAC;gBACvD,MAAM,IAAI,GAAG,MAAM,eAAe,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;gBAC7C,IAAI,CAAC,IAAI;oBAAE,OAAO;gBAClB,IAAI,CAAC,aAAa,CAAC,IAAI,EAAE,GAAG,CAAC;oBAAE,OAAO;gBACtC,MAAM,EAAE,QAAQ,EAAE,GAAG,IAA6B,CAAC;gBACnD,IAAI,OAAO,QAAQ,KAAK,QAAQ,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;oBAC3D,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,kBAAkB,EAAE,CAAC,CAAC;oBAC7D,OAAO;gBACR,CAAC;gBACD,IAAI,CAAC,mBAAmB,CAAC,QAAQ,CAAC,EAAE,CAAC;oBACpC,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,yBAAyB,QAAQ,EAAE,EAAE,CAAC,CAAC;oBAC9E,OAAO;gBACR,CAAC;gBACD,YAAY,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,gBAAgB,CAAC,QAAQ,CAAC,CAAC,CAAC;gBACzD,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;gBACjC,OAAO;YACR,CAAC;YAED,IAAI,MAAM,KAAK,MAAM,IAAI,GAAG,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;gBACrD,MAAM,IAAI,GAAG,MAAM,eAAe,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;gBAC7C,IAAI,CAAC,IAAI;oBAAE,OAAO;gBAClB,IAAI,CAAC,aAAa,CAAC,IAAI,EAAE,GAAG,CAAC;oBAAE,OAAO;gBACtC,IAAI,KAAK,KAAK,WAAW,EAAE,CAAC;oBAC3B,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,gBAAgB,EAAE,CAAC,CAAC;oBAC3D,OAAO;gBACR,CAAC;gBACD,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,IAA6C,CAAC;gBAC1E,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;oBAC5D,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,eAAe,EAAE,CAAC,CAAC;oBAC1D,OAAO;gBACR,CAAC;gBACD,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;oBAC5B,IAAI,OAAO,QAAQ,KAAK,QAAQ,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;wBAC3D,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,kBAAkB,EAAE,CAAC,CAAC;wBAC7D,OAAO;oBACR,CAAC;oBACD,IAAI,CAAC,mBAAmB,CAAC,QAAQ,CAAC,EAAE,CAAC;wBACpC,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,yBAAyB,QAAQ,EAAE,EAAE,CAAC,CAAC;wBAC9E,OAAO;oBACR,CAAC;gBACF,CAAC;gBACD,MAAM,EAAE,GAAG,cAAc,EAAE,CAAC;gBAC5B,MAAM,YAAY,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;gBAClC,cAAc,EAAE,CAAC;gBACjB,IAAI,CAAC;oBACJ,MAAM,OAAO,GAAG,MAAM,SAAS,CAAC,WAAW,CAAC,YAAY,EAAE,QAAQ,CAAC,CAAC;oBACpE,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;wBAAE,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAC;oBACjF,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,KAAK,EAA6B,EAAE,CAAC,CAAC;wBAC1E,GAAG,MAAM;wBACT,UAAU,EAAE,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,cAAc,EAAE;wBAC/C,KAAK,EAAE,YAAY;qBACnB,CAAC,CAAC,CAAC;oBACJ,SAAS,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC;oBACtC,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC;gBAC1D,CAAC;gBAAC,OAAO,GAAG,EAAE,CAAC;oBACd,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC;oBACrE,MAAM,KAAK,GAA8B;wBACxC,UAAU,EAAE,EAAE;wBACd,KAAK,EAAE,YAAY;wBACnB,MAAM,EAAE,EAAE;wBACV,OAAO,EAAE,EAAE;wBACX,KAAK,EAAE,OAAO;wBACd,QAAQ,EAAE,OAAO,QAAQ,KAAK,QAAQ,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,eAAe;qBAC1F,CAAC;oBACF,SAAS,CAAC,kBAAkB,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;oBACtC,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,GAAG,KAAK,EAAE,OAAO,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;gBAC9D,CAAC;gBACD,OAAO;YACR,CAAC;YAED,IAAI,MAAM,KAAK,MAAM,IAAI,GAAG,CAAC,QAAQ,KAAK,YAAY,EAAE,CAAC;gBACxD,MAAM,IAAI,GAAG,MAAM,eAAe,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;gBAC7C,IAAI,CAAC,IAAI;oBAAE,OAAO;gBAClB,IAAI,CAAC,aAAa,CAAC,IAAI,EAAE,GAAG,CAAC;oBAAE,OAAO;gBACtC,IAAI,KAAK,KAAK,WAAW,EAAE,CAAC;oBAC3B,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,gBAAgB,EAAE,CAAC,CAAC;oBAC3D,OAAO;gBACR,CAAC;gBAED,MAAM,MAAM,GAAG,wBAAwB,CAAE,IAA+B,CAAC,QAAQ,EAAE;oBAClF,UAAU,EAAE,KAAK;oBACjB,YAAY,EAAE,cAAc;iBAC5B,CAAC,CAAC;gBACH,IAAI,OAAO,IAAI,MAAM,EAAE,CAAC;oBACvB,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC;oBACvD,OAAO;gBACR,CAAC;gBAED,IAAI,KAAyB,CAAC;gBAC9B,MAAM,SAAS,GAAI,IAA4B,CAAC,KAAK,CAAC;gBACtD,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;oBAC7B,IAAI,OAAO,SAAS,KAAK,QAAQ,EAAE,CAAC;wBACnC,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,eAAe,EAAE,CAAC,CAAC;wBAC1D,OAAO;oBACR,CAAC;oBACD,MAAM,YAAY,GAAG,SAAS,CAAC,IAAI,EAAE,CAAC;oBACtC,KAAK,GAAG,YAAY,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,SAAS,CAAC;gBAC5D,CAAC;gBAED,MAAM,YAAY,GAAI,IAA+B,CAAC,QAAQ,CAAC;gBAC/D,MAAM,QAAQ,GAAG,OAAO,YAAY,KAAK,QAAQ,IAAI,YAAY,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC;oBAClF,CAAC,CAAC,YAAY,CAAC,IAAI,EAAE;oBACrB,CAAC,CAAC,SAAS,CAAC;gBAEb,sBAAsB,EAAE,CAAC;gBACzB,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;gBACzC,wBAAwB,GAAG,UAAU,CAAC;gBACtC,MAAM,SAAS,GAAG,EAAE,mBAAmB,CAAC;gBAExC,IAAI,CAAC;oBACJ,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,WAAW,CAAC,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,MAAM,EAAE,KAAK,EAAE,QAAQ,CAAC,CAAC;oBAC/F,IAAI,SAAS,KAAK,mBAAmB,IAAI,SAAS,EAAE,CAAC;wBACpD,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,8BAA8B,EAAE,CAAC,CAAC;wBACzE,OAAO;oBACR,CAAC;oBACD,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE;wBAClB,EAAE,EAAE,IAAI;wBACR,OAAO,EAAE,MAAM,CAAC,OAAO;wBACvB,IAAI,EAAE,MAAM,CAAC,IAAI;qBACjB,CAAC,CAAC;gBACJ,CAAC;gBAAC,OAAO,GAAG,EAAE,CAAC;oBACd,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,2BAA2B,CAAC;oBACjF,MAAM,MAAM,GAAG,UAAU,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;oBACrD,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC;gBACtD,CAAC;wBAAS,CAAC;oBACV,IAAI,wBAAwB,KAAK,UAAU,EAAE,CAAC;wBAC7C,wBAAwB,GAAG,IAAI,CAAC;oBACjC,CAAC;gBACF,CAAC;gBACD,OAAO;YACR,CAAC;YAED,IAAI,MAAM,KAAK,MAAM,IAAI,GAAG,CAAC,QAAQ,KAAK,UAAU,EAAE,CAAC;gBACtD,MAAM,IAAI,GAAG,MAAM,eAAe,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;gBAC7C,IAAI,CAAC,IAAI;oBAAE,OAAO;gBAClB,IAAI,CAAC,aAAa,CAAC,IAAI,EAAE,GAAG,CAAC;oBAAE,OAAO;gBACtC,IAAI,KAAK,KAAK,WAAW,EAAE,CAAC;oBAC3B,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,gBAAgB,EAAE,CAAC,CAAC;oBAC3D,OAAO;gBACR,CAAC;gBACD,MAAM,EAAE,KAAK,EAAE,GAAG,IAA2B,CAAC;gBAC9C,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;oBAC5D,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,eAAe,EAAE,CAAC,CAAC;oBAC1D,OAAO;gBACR,CAAC;gBACD,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;gBACzC,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC,CAAC;gBAC1C,cAAc,EAAE,CAAC;gBACjB,IAAI,CAAC;oBACJ,MAAM,SAAS,GAAG,MAAM,SAAS,CAAC,cAAc,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC;oBAClF,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC;gBACpD,CAAC;gBAAC,OAAO,GAAG,EAAE,CAAC;oBACd,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,gBAAgB,CAAC;oBACtE,MAAM,MAAM,GAAG,UAAU,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;oBACrD,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC;gBACtD,CAAC;gBACD,OAAO;YACR,CAAC;YAED,IAAI,MAAM,KAAK,MAAM,IAAI,GAAG,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;gBACrD,MAAM,IAAI,GAAG,MAAM,eAAe,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;gBAC7C,IAAI,CAAC,IAAI;oBAAE,OAAO;gBAClB,IAAI,CAAC,aAAa,CAAC,IAAI,EAAE,GAAG,CAAC;oBAAE,OAAO;gBAEtC,MAAM,MAAM,GAAG,wBAAwB,CAAE,IAA+B,CAAC,QAAQ,EAAE;oBAClF,UAAU,EAAE,IAAI;oBAChB,YAAY,EAAE,cAAc;iBAC5B,CAAC,CAAC;gBACH,IAAI,OAAO,IAAI,MAAM,EAAE,CAAC;oBACvB,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC;oBACvD,OAAO;gBACR,CAAC;gBAED,IAAI,OAA2B,CAAC;gBAChC,MAAM,WAAW,GAAI,IAA8B,CAAC,OAAO,CAAC;gBAC5D,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;oBAC/B,IAAI,OAAO,WAAW,KAAK,QAAQ,EAAE,CAAC;wBACrC,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,iBAAiB,EAAE,CAAC,CAAC;wBAC5D,OAAO;oBACR,CAAC;oBACD,MAAM,cAAc,GAAG,WAAW,CAAC,IAAI,EAAE,CAAC;oBAC1C,OAAO,GAAG,cAAc,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,SAAS,CAAC;gBAClE,CAAC;gBAED,IAAI,WAAoC,CAAC;gBACzC,MAAM,eAAe,GAAI,IAAkC,CAAC,WAAW,CAAC;gBACxE,IAAI,eAAe,KAAK,SAAS,EAAE,CAAC;oBACnC,MAAM,iBAAiB,GAAG,oBAAoB,CAAC,eAAe,CAAC,CAAC;oBAChE,IAAI,CAAC,iBAAiB,EAAE,CAAC;wBACxB,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,qBAAqB,EAAE,CAAC,CAAC;wBAChE,OAAO;oBACR,CAAC;oBACD,WAAW,GAAG,iBAAiB,CAAC;gBACjC,CAAC;gBAED,IAAI,KAAK,KAAK,WAAW,IAAI,KAAK,KAAK,kBAAkB,EAAE,CAAC;oBAC3D,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,gCAAgC,EAAE,CAAC,CAAC;oBAC3E,OAAO;gBACR,CAAC;gBACD,IAAI,CAAC,aAAa,EAAE,EAAE,CAAC;oBACtB,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,gBAAgB,EAAE,CAAC,CAAC;oBAC3D,OAAO;gBACR,CAAC;gBACD,MAAM,UAAU,GAAI,IAAiC,CAAC,UAAU,KAAK,IAAI,CAAC;gBAC1E,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;gBACjC,YAAY,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,QAAQ,CAAC;oBACrC,oBAAoB,EAAE,MAAM,CAAC,OAAO;oBACpC,GAAG,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;oBAC7C,GAAG,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;oBACrD,UAAU;iBACV,CAAC,CAAC,CAAC;gBACJ,OAAO;YACR,CAAC;YAED,IAAI,MAAM,KAAK,MAAM,IAAI,GAAG,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;gBACrD,MAAM,IAAI,GAAG,MAAM,eAAe,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;gBAC7C,IAAI,CAAC,IAAI;oBAAE,OAAO;gBAClB,IAAI,CAAC,aAAa,CAAC,IAAI,EAAE,GAAG,CAAC;oBAAE,OAAO;gBACtC,IAAI,CAAC,aAAa,EAAE,EAAE,CAAC;oBACtB,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;oBACjC,OAAO;gBACR,CAAC;gBACD,MAAM,EAAE,MAAM,EAAE,GAAG,IAA2B,CAAC;gBAC/C,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;gBACjC,MAAM,YAAY,GAAG,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC;gBAC/D,YAAY,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC;gBACrD,OAAO;YACR,CAAC;YAED,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,YAAY,EAAE,CAAC,CAAC;YACrD,GAAG,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;QACtB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACd,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,cAAc,CAAC;YACpE,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC;QACnD,CAAC;IAAA,CACD,CAAC,CAAC;IAEH,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,CAAC;QACvC,MAAM,OAAO,GAAG,CAAC,GAAU,EAAE,EAAE,CAAC;YAC/B,MAAM,CAAC,IAAI,KAAK,CAAC,mCAAmC,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;QAAA,CACpE,CAAC;QAEF,MAAM,aAAa,GAAG,2BAA2B,EAAE,CAAC;QAEpD,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QAC9B,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,aAAa,CAAC,IAAI,EAAE,GAAG,EAAE,CAAC;YAC1C,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;YAC7B,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,EAAE,CAAC;YAC9B,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;gBACvC,MAAM,CAAC,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAC,CAAC;gBACrD,OAAO;YACR,CAAC;YACD,MAAM,GAAG,GAAG,UAAU,aAAa,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,aAAa,YAAY,EAAE,CAAC;YAEjF,QAAQ,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;gBAC5B,IAAI,SAAS;oBAAE,OAAO;gBACtB,IAAI,CAAC,gBAAgB,EAAE,CAAC;oBACvB,MAAM,kBAAkB,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,qBAAqB,EAAE,CAAC,CAAC;oBACnE,IAAI,KAAK,KAAK,kBAAkB;wBAAE,OAAO;oBACzC,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,cAAc,IAAI,kBAAkB;wBAAE,OAAO;oBAC9D,IAAI,CAAC,aAAa,EAAE;wBAAE,OAAO;oBAC7B,YAAY,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC;oBAClD,OAAO;gBACR,CAAC;gBACD,IAAI,2BAA2B,EAAE,EAAE,CAAC;oBACnC,IAAI,CAAC,aAAa,EAAE;wBAAE,OAAO;oBAC7B,YAAY,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC;oBAClD,OAAO;gBACR,CAAC;gBACD,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,eAAe,IAAI,kBAAkB;oBAAE,OAAO;gBAC/D,MAAM,WAAW,GAAG,KAAK,KAAK,kBAAkB,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC;gBACvE,IAAI,CAAC,aAAa,EAAE;oBAAE,OAAO;gBAC7B,YAAY,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,CAAC;YAAA,CACpD,EAAE,oBAAoB,CAAC,CAAC;YAEzB,OAAO,CAAC;gBACP,MAAM;gBACN,GAAG;gBACH,KAAK,EAAE,GAAG,EAAE,CAAC;oBACZ,MAAM,OAAO,GAAG,aAAa,EAAE,CAAC;oBAChC,IAAI,CAAC;wBAAC,MAAM,CAAC,KAAK,EAAE,CAAC;oBAAC,CAAC;oBAAC,MAAM,CAAC,CAAA,CAAC;oBAChC,IAAI,OAAO,EAAE,CAAC;wBACb,YAAY,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;oBACjD,CAAC;gBAAA,CACD;gBACD,UAAU,EAAE,CAAC,UAAU,EAAE,IAAI,EAAE,EAAE,CAAC;oBACjC,IAAI,SAAS;wBAAE,OAAO;oBACtB,cAAc,GAAG,IAAI,CAAC,GAAG,CAAC,cAAc,EAAE,UAAU,GAAG,CAAC,CAAC,CAAC;oBAC1D,MAAM,SAAS,GAA2B,EAAE,GAAG,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,IAAI,OAAO,CAAC,UAAU,CAAC,IAAI,EAAE,EAAE,CAAC;oBAClH,mBAAmB,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC;oBAC1D,OAAO,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;gBAAA,CAC7B;gBACD,SAAS,EAAE,CAAC,UAAU,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,CAAC;oBACjD,IAAI,SAAS;wBAAE,OAAO;oBACtB,cAAc,GAAG,IAAI,CAAC,GAAG,CAAC,cAAc,EAAE,UAAU,GAAG,CAAC,CAAC,CAAC;oBAC1D,MAAM,SAAS,GAAgC,EAAE,UAAU,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,IAAI,OAAO,CAAC,UAAU,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;oBAC5J,mBAAmB,CAAC,EAAE,KAAK,EAAE,cAAc,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC;oBAChE,OAAO,CAAC,cAAc,EAAE,SAAS,CAAC,CAAC;gBAAA,CACnC;gBACD,YAAY,EAAE,GAAG,EAAE,CAAC;oBACnB,IAAI,SAAS;wBAAE,OAAO;oBACtB,gBAAgB,GAAG,IAAI,CAAC;oBACxB,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;oBACpB,KAAK,GAAG,kBAAkB,CAAC;oBAC3B,cAAc,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;gBAAA,CAC5B;gBACD,kBAAkB,EAAE,GAAG,EAAE,CAAC,CAAC;oBAC1B,gBAAgB;oBAChB,kBAAkB,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,eAAe;iBAChD,CAAC;aACF,CAAC,CAAC;QAAA,CACH,CAAC,CAAC;IAAA,CACH,CAAC,CAAC;AAAA,CACH","sourcesContent":["import http, { type IncomingMessage, type ServerResponse } from \"node:http\";\nimport { generateCuratorPage } from \"./curator-page.ts\";\nimport type { SummaryMeta } from \"./summary-review.ts\";\nimport { resolveCuratorNetworkConfig } from \"./utils.ts\";\n\nconst STALE_THRESHOLD_MS = 30000;\nconst WATCHDOG_INTERVAL_MS = 1000;\nconst MAX_BODY_SIZE = 64 * 1024;\n\ntype ServerState = \"SEARCHING\" | \"RESULT_SELECTION\" | \"COMPLETED\";\ntype CuratorResultEventData = IndexedCuratorSearchEntry & { slotIndex?: number };\ntype CuratorSearchErrorEventData = { queryIndex: number; query: string; error: string; provider?: string; slotIndex?: number };\ntype CuratorStoredEvent =\n\t| { event: \"result\"; data: CuratorResultEventData }\n\t| { event: \"search-error\"; data: CuratorSearchErrorEventData };\n\nexport interface CuratorServerOptions {\n\tqueries: string[];\n\tsessionToken: string;\n\ttimeout: number;\n\tavailableProviders: { all: boolean; openai: boolean; brave: boolean; parallel: boolean; tinyfish: boolean; search1api: boolean; searchinfinity: boolean; querit: boolean; tavily: boolean; firecrawl: boolean; jina: boolean; serpdive: boolean; kagi: boolean; bocha: boolean; ollama: boolean; searxng: boolean; duckduckgo: boolean; perplexity: boolean; exa: boolean; gemini: boolean; anysearch: boolean; xai: boolean; brightdata: boolean; serpbase: boolean };\n\tdefaultProvider: string;\n\tsearchProvider: string;\n\tsummaryModels: Array<{ value: string; label: string }>;\n\tdefaultSummaryModel: string | null;\n}\n\nexport interface CuratorSearchEntry {\n\tanswer: string;\n\tresults: Array<{ title: string; url: string; domain: string; snippet?: string }>;\n\tprovider: string;\n\terror?: string;\n}\n\nexport interface IndexedCuratorSearchEntry extends CuratorSearchEntry {\n\tqueryIndex: number;\n\tquery: string;\n}\n\nexport interface CuratorServerCallbacks {\n\tonSubmit: (payload: { selectedQueryIndices: number[]; summary?: string; summaryMeta?: SummaryMeta; rawResults?: boolean }) => void;\n\tonCancel: (reason: \"user\" | \"timeout\" | \"stale\") => void;\n\tonProviderChange: (provider: string) => void;\n\tonAddSearch: (query: string, provider?: string) => Promise<CuratorSearchEntry[]>;\n\tonAddSearchResults: (entries: IndexedCuratorSearchEntry[]) => void;\n\tonSummarize: (\n\t\tselectedQueryIndices: number[],\n\t\tsignal: AbortSignal,\n\t\tmodel?: string,\n\t\tfeedback?: string,\n\t) => Promise<{ summary: string; meta: SummaryMeta }>;\n\tonRewriteQuery: (query: string, signal: AbortSignal) => Promise<string>;\n}\n\nexport interface CuratorServerHandle {\n\tserver: http.Server;\n\turl: string;\n\tclose: () => void;\n\tpushResult: (queryIndex: number, data: CuratorSearchEntry & { query?: string; slotIndex?: number }) => void;\n\tpushError: (queryIndex: number, error: string, provider?: string, meta?: { query?: string; slotIndex?: number }) => void;\n\tsearchesDone: () => void;\n\t/** Reports browser connection state so a cancelled search can surface WHY it\n\t * went stale (e.g. the browser never connected). */\n\tgetConnectionState: () => { browserConnected: boolean; lastHeartbeatAgeMs: number };\n}\n\nfunction sendJson(res: ServerResponse, status: number, payload: unknown): void {\n\tres.writeHead(status, {\n\t\t\"Content-Type\": \"application/json\",\n\t\t\"Cache-Control\": \"no-store\",\n\t});\n\tres.end(JSON.stringify(payload));\n}\n\nfunction parseJSONBody(req: IncomingMessage): Promise<unknown> {\n\treturn new Promise((resolve, reject) => {\n\t\tlet body = \"\";\n\t\tlet size = 0;\n\t\treq.on(\"data\", (chunk: Buffer) => {\n\t\t\tsize += chunk.length;\n\t\t\tif (size > MAX_BODY_SIZE) {\n\t\t\t\treq.destroy();\n\t\t\t\treject(new Error(\"Request body too large\"));\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tbody += chunk.toString();\n\t\t});\n\t\treq.on(\"end\", () => {\n\t\t\ttry {\n\t\t\t\tresolve(JSON.parse(body));\n\t\t\t} catch (err) {\n\t\t\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\t\t\treject(new Error(`Invalid JSON: ${message}`));\n\t\t\t}\n\t\t});\n\t\treq.on(\"error\", reject);\n\t});\n}\n\nasync function parseBodyOrSend(req: IncomingMessage, res: ServerResponse): Promise<unknown | null> {\n\ttry {\n\t\treturn await parseJSONBody(req);\n\t} catch (err) {\n\t\tconst message = err instanceof Error ? err.message : \"Invalid body\";\n\t\tconst status = message === \"Request body too large\" ? 413 : 400;\n\t\tsendJson(res, status, { ok: false, error: message });\n\t\treturn null;\n\t}\n}\n\nfunction normalizeSelectedIndices(\n\tvalue: unknown,\n\toptions: { allowEmpty: boolean; maxExclusive: number },\n): { ok: true; indices: number[] } | { ok: false; error: string } {\n\tif (!Array.isArray(value)) {\n\t\treturn { ok: false, error: \"Invalid selection\" };\n\t}\n\n\tif (!options.allowEmpty && value.length === 0) {\n\t\treturn { ok: false, error: \"Invalid selection\" };\n\t}\n\n\tconst normalized: number[] = [];\n\tconst seen = new Set<number>();\n\tfor (const item of value) {\n\t\tif (typeof item !== \"number\" || !Number.isInteger(item) || item < 0) {\n\t\t\treturn { ok: false, error: \"Invalid selection\" };\n\t\t}\n\t\tif (item >= options.maxExclusive) {\n\t\t\treturn { ok: false, error: \"Invalid selection\" };\n\t\t}\n\t\tif (seen.has(item)) {\n\t\t\tcontinue;\n\t\t}\n\t\tseen.add(item);\n\t\tnormalized.push(item);\n\t}\n\n\tif (!options.allowEmpty && normalized.length === 0) {\n\t\treturn { ok: false, error: \"Invalid selection\" };\n\t}\n\n\treturn { ok: true, indices: normalized };\n}\n\nfunction normalizeSummaryMeta(value: unknown): SummaryMeta | null {\n\tif (!value || typeof value !== \"object\") return null;\n\tconst meta = value as Record<string, unknown>;\n\n\tconst model = meta.model === null\n\t\t? null\n\t\t: typeof meta.model === \"string\"\n\t\t\t? meta.model\n\t\t\t: undefined;\n\tif (model === undefined) return null;\n\n\tconst durationMs = meta.durationMs;\n\tif (typeof durationMs !== \"number\" || !Number.isFinite(durationMs) || durationMs < 0) return null;\n\n\tconst tokenEstimate = meta.tokenEstimate;\n\tif (typeof tokenEstimate !== \"number\" || !Number.isFinite(tokenEstimate) || tokenEstimate < 0) return null;\n\n\tconst fallbackUsed = meta.fallbackUsed;\n\tif (typeof fallbackUsed !== \"boolean\") return null;\n\n\tconst fallbackReason = typeof meta.fallbackReason === \"string\" ? meta.fallbackReason : undefined;\n\tif (meta.fallbackReason !== undefined && fallbackReason === undefined) return null;\n\n\tconst phase = meta.phase === \"summary-model\" || meta.phase === \"deterministic-fallback\"\n\t\t? meta.phase\n\t\t: undefined;\n\tif (meta.phase !== undefined && phase === undefined) return null;\n\tif (phase === \"deterministic-fallback\" && fallbackUsed !== true) return null;\n\tif (phase === \"summary-model\" && fallbackUsed !== false) return null;\n\n\tconst edited = typeof meta.edited === \"boolean\" ? meta.edited : undefined;\n\tif (meta.edited !== undefined && edited === undefined) return null;\n\n\treturn {\n\t\tmodel,\n\t\tdurationMs,\n\t\ttokenEstimate,\n\t\tfallbackUsed,\n\t\t...(fallbackReason !== undefined ? { fallbackReason } : {}),\n\t\t...(phase !== undefined ? { phase } : {}),\n\t\t...(edited !== undefined ? { edited } : {}),\n\t};\n}\n\nexport function startCuratorServer(\n\toptions: CuratorServerOptions,\n\tcallbacks: CuratorServerCallbacks,\n): Promise<CuratorServerHandle> {\n\tconst {\n\t\tqueries,\n\t\tsessionToken,\n\t\ttimeout,\n\t\tavailableProviders,\n\t\tdefaultProvider,\n\t\tsearchProvider,\n\t\tsummaryModels,\n\t\tdefaultSummaryModel,\n\t} = options;\n\tlet browserConnected = false;\n\tlet lastHeartbeatAt = Date.now();\n\tlet stateChangedAt = Date.now();\n\tlet clientIdleMs: number | null = null;\n\tlet clientTimeoutSeconds = timeout;\n\tlet completed = false;\n\tlet watchdog: NodeJS.Timeout | null = null;\n\tlet state: ServerState = \"SEARCHING\";\n\tlet sseResponse: ServerResponse | null = null;\n\tconst streamedEventsByResultIndex = new Map<number, CuratorStoredEvent>();\n\tlet searchStreamDone = queries.length === 0;\n\tlet nextQueryIndex = queries.length;\n\tlet summarizeAbortController: AbortController | null = null;\n\tlet summarizeRequestSeq = 0;\n\n\tlet sseKeepalive: NodeJS.Timeout | null = null;\n\n\tconst abortInFlightSummarize = (): void => {\n\t\tif (!summarizeAbortController) return;\n\t\tsummarizeAbortController.abort();\n\t\tsummarizeAbortController = null;\n\t};\n\n\tconst markCompleted = (): boolean => {\n\t\tif (completed) return false;\n\t\tcompleted = true;\n\t\tstate = \"COMPLETED\";\n\t\tstateChangedAt = Date.now();\n\t\tif (watchdog) {\n\t\t\tclearInterval(watchdog);\n\t\t\twatchdog = null;\n\t\t}\n\t\tif (sseKeepalive) {\n\t\t\tclearInterval(sseKeepalive);\n\t\t\tsseKeepalive = null;\n\t\t}\n\t\tabortInFlightSummarize();\n\t\tif (sseResponse) {\n\t\t\ttry { sseResponse.end(); } catch {}\n\t\t\tsseResponse = null;\n\t\t}\n\t\treturn true;\n\t};\n\n\tconst touchHeartbeat = (): void => {\n\t\tlastHeartbeatAt = Date.now();\n\t\tbrowserConnected = true;\n\t};\n\n\tconst getEffectiveTimeoutMs = (): number => Math.max(1000, Math.floor(clientTimeoutSeconds) * 1000);\n\n\tconst shouldTimeoutFromClientIdle = (): boolean => (\n\t\tstate === \"RESULT_SELECTION\" &&\n\t\tclientIdleMs !== null &&\n\t\tclientIdleMs >= getEffectiveTimeoutMs()\n\t);\n\n\tfunction validateToken(body: unknown, res: ServerResponse): boolean {\n\t\tif (!body || typeof body !== \"object\") {\n\t\t\tsendJson(res, 400, { ok: false, error: \"Invalid body\" });\n\t\t\treturn false;\n\t\t}\n\t\tif ((body as { token?: string }).token !== sessionToken) {\n\t\t\tsendJson(res, 403, { ok: false, error: \"Invalid session\" });\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t}\n\n\tfunction isAvailableProvider(provider: string): boolean {\n\t\tif (provider === \"all\") return availableProviders.all;\n\t\tif (provider === \"openai\") return availableProviders.openai;\n\t\tif (provider === \"brave\") return availableProviders.brave;\n\t\tif (provider === \"parallel\") return availableProviders.parallel;\n\t\tif (provider === \"tinyfish\") return availableProviders.tinyfish;\n\t\tif (provider === \"search1api\") return availableProviders.search1api;\n\t\tif (provider === \"searchinfinity\") return availableProviders.searchinfinity;\n\t\tif (provider === \"querit\") return availableProviders.querit;\n\t\tif (provider === \"tavily\") return availableProviders.tavily;\n\t\tif (provider === \"firecrawl\") return availableProviders.firecrawl;\n\t\tif (provider === \"jina\") return availableProviders.jina;\n\t\tif (provider === \"serpdive\") return availableProviders.serpdive;\n\t\tif (provider === \"kagi\") return availableProviders.kagi;\n\t\tif (provider === \"bocha\") return availableProviders.bocha;\n\t\tif (provider === \"ollama\") return availableProviders.ollama;\n\t\tif (provider === \"searxng\") return availableProviders.searxng;\n\t\tif (provider === \"duckduckgo\") return availableProviders.duckduckgo;\n\t\tif (provider === \"perplexity\") return availableProviders.perplexity;\n\t\tif (provider === \"exa\") return availableProviders.exa;\n\t\tif (provider === \"gemini\") return availableProviders.gemini;\n\t\tif (provider === \"anysearch\") return availableProviders.anysearch;\n\t\tif (provider === \"xai\") return availableProviders.xai;\n\t\tif (provider === \"brightdata\") return availableProviders.brightdata;\n\t\tif (provider === \"serpbase\") return availableProviders.serpbase;\n\t\treturn false;\n\t}\n\n\tfunction writeSSE(res: ServerResponse, event: string, data: unknown): boolean {\n\t\tconst payload = `event: ${event}\\ndata: ${JSON.stringify(data)}\\n\\n`;\n\t\ttry {\n\t\t\tres.write(payload);\n\t\t\treturn true;\n\t\t} catch {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tfunction sendSSE(event: string, data: unknown): void {\n\t\tconst res = sseResponse;\n\t\tif (res && !res.writableEnded && res.socket && !res.socket.destroyed && writeSSE(res, event, data)) return;\n\t\tif (sseResponse === res) sseResponse = null;\n\t}\n\n\tfunction retainStreamedEvent(event: CuratorStoredEvent): void {\n\t\tstreamedEventsByResultIndex.set(event.data.queryIndex, event);\n\t}\n\n\tfunction getStreamedEvents(): CuratorStoredEvent[] {\n\t\treturn [...streamedEventsByResultIndex.values()];\n\t}\n\n\tfunction replaySSE(res: ServerResponse): void {\n\t\tfor (const item of getStreamedEvents()) {\n\t\t\tif (!writeSSE(res, item.event, item.data)) return;\n\t\t}\n\t\tif (searchStreamDone) writeSSE(res, \"done\", {});\n\t}\n\n\tconst pageHtml = generateCuratorPage(\n\t\tqueries,\n\t\tsessionToken,\n\t\ttimeout,\n\t\tavailableProviders,\n\t\tdefaultProvider,\n\t\tsearchProvider,\n\t\tsummaryModels,\n\t\tdefaultSummaryModel,\n\t);\n\n\tconst server = http.createServer(async (req, res) => {\n\t\ttry {\n\t\t\tconst method = req.method || \"GET\";\n\t\t\tconst url = new URL(req.url || \"/\", `http://${req.headers.host || \"127.0.0.1\"}`);\n\n\t\t\tif (method === \"GET\" && url.pathname === \"/\") {\n\t\t\t\tconst token = url.searchParams.get(\"session\");\n\t\t\t\tif (token !== sessionToken) {\n\t\t\t\t\tres.writeHead(403, { \"Content-Type\": \"text/plain\" });\n\t\t\t\t\tres.end(\"Invalid session\");\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\ttouchHeartbeat();\n\t\t\t\tres.writeHead(200, {\n\t\t\t\t\t\"Content-Type\": \"text/html; charset=utf-8\",\n\t\t\t\t\t\"Cache-Control\": \"no-store\",\n\t\t\t\t});\n\t\t\t\tres.end(pageHtml);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (method === \"GET\" && url.pathname === \"/events\") {\n\t\t\t\tconst token = url.searchParams.get(\"session\");\n\t\t\t\tif (token !== sessionToken) {\n\t\t\t\t\tres.writeHead(403, { \"Content-Type\": \"text/plain\" });\n\t\t\t\t\tres.end(\"Invalid session\");\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (state === \"COMPLETED\") {\n\t\t\t\t\tsendJson(res, 409, { ok: false, error: \"No events available\" });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (sseResponse) {\n\t\t\t\t\ttry { sseResponse.end(); } catch {}\n\t\t\t\t}\n\t\t\t\tres.writeHead(200, {\n\t\t\t\t\t\"Content-Type\": \"text/event-stream\",\n\t\t\t\t\t\"Cache-Control\": \"no-cache\",\n\t\t\t\t\tConnection: \"keep-alive\",\n\t\t\t\t\t\"X-Accel-Buffering\": \"no\",\n\t\t\t\t});\n\t\t\t\tres.flushHeaders();\n\t\t\t\tif (res.socket) res.socket.setNoDelay(true);\n\t\t\t\tsseResponse = res;\n\t\t\t\treplaySSE(res);\n\t\t\t\tif (sseKeepalive) clearInterval(sseKeepalive);\n\t\t\t\tsseKeepalive = setInterval(() => {\n\t\t\t\t\tif (sseResponse) {\n\t\t\t\t\t\ttry { sseResponse.write(\":keepalive\\n\\n\"); } catch {}\n\t\t\t\t\t}\n\t\t\t\t}, 15000);\n\t\t\t\treq.on(\"close\", () => {\n\t\t\t\t\tif (sseResponse === res) sseResponse = null;\n\t\t\t\t});\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (method === \"GET\" && url.pathname === \"/state\") {\n\t\t\t\tconst token = url.searchParams.get(\"session\");\n\t\t\t\tif (token !== sessionToken) {\n\t\t\t\t\tsendJson(res, 403, { ok: false, error: \"Invalid session\" });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\ttouchHeartbeat();\n\t\t\t\tsendJson(res, 200, { ok: true, events: getStreamedEvents(), done: searchStreamDone });\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (method === \"POST\" && url.pathname === \"/heartbeat\") {\n\t\t\t\tconst body = await parseBodyOrSend(req, res);\n\t\t\t\tif (!body) return;\n\t\t\t\tif (!validateToken(body, res)) return;\n\t\t\t\ttouchHeartbeat();\n\t\t\t\tconst heartbeat = body as { idleMs?: unknown; timeoutSec?: unknown };\n\t\t\t\tif (typeof heartbeat.timeoutSec === \"number\" && Number.isFinite(heartbeat.timeoutSec) && heartbeat.timeoutSec > 0) {\n\t\t\t\t\tclientTimeoutSeconds = Math.min(600, Math.floor(heartbeat.timeoutSec));\n\t\t\t\t}\n\t\t\t\tif (typeof heartbeat.idleMs === \"number\" && Number.isFinite(heartbeat.idleMs) && heartbeat.idleMs >= 0) {\n\t\t\t\t\tclientIdleMs = Math.floor(heartbeat.idleMs);\n\t\t\t\t}\n\t\t\t\tconst timedOut = shouldTimeoutFromClientIdle();\n\t\t\t\tsendJson(res, 200, { ok: true });\n\t\t\t\tif (timedOut && markCompleted()) {\n\t\t\t\t\tsetImmediate(() => callbacks.onCancel(\"timeout\"));\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (method === \"POST\" && url.pathname === \"/provider\") {\n\t\t\t\tconst body = await parseBodyOrSend(req, res);\n\t\t\t\tif (!body) return;\n\t\t\t\tif (!validateToken(body, res)) return;\n\t\t\t\tconst { provider } = body as { provider?: string };\n\t\t\t\tif (typeof provider !== \"string\" || provider.length === 0) {\n\t\t\t\t\tsendJson(res, 400, { ok: false, error: \"Invalid provider\" });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (!isAvailableProvider(provider)) {\n\t\t\t\t\tsendJson(res, 400, { ok: false, error: `Provider unavailable: ${provider}` });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tsetImmediate(() => callbacks.onProviderChange(provider));\n\t\t\t\tsendJson(res, 200, { ok: true });\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (method === \"POST\" && url.pathname === \"/search\") {\n\t\t\t\tconst body = await parseBodyOrSend(req, res);\n\t\t\t\tif (!body) return;\n\t\t\t\tif (!validateToken(body, res)) return;\n\t\t\t\tif (state === \"COMPLETED\") {\n\t\t\t\t\tsendJson(res, 409, { ok: false, error: \"Session closed\" });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst { query, provider } = body as { query?: string; provider?: string };\n\t\t\t\tif (typeof query !== \"string\" || query.trim().length === 0) {\n\t\t\t\t\tsendJson(res, 400, { ok: false, error: \"Invalid query\" });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (provider !== undefined) {\n\t\t\t\t\tif (typeof provider !== \"string\" || provider.length === 0) {\n\t\t\t\t\t\tsendJson(res, 400, { ok: false, error: \"Invalid provider\" });\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tif (!isAvailableProvider(provider)) {\n\t\t\t\t\t\tsendJson(res, 400, { ok: false, error: `Provider unavailable: ${provider}` });\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tconst qi = nextQueryIndex++;\n\t\t\t\tconst trimmedQuery = query.trim();\n\t\t\t\ttouchHeartbeat();\n\t\t\t\ttry {\n\t\t\t\t\tconst results = await callbacks.onAddSearch(trimmedQuery, provider);\n\t\t\t\t\tif (results.length === 0) throw new Error(\"Search returned no provider results\");\n\t\t\t\t\tconst entries = results.map((result, index): IndexedCuratorSearchEntry => ({\n\t\t\t\t\t\t...result,\n\t\t\t\t\t\tqueryIndex: index === 0 ? qi : nextQueryIndex++,\n\t\t\t\t\t\tquery: trimmedQuery,\n\t\t\t\t\t}));\n\t\t\t\t\tcallbacks.onAddSearchResults(entries);\n\t\t\t\t\tsendJson(res, 200, { ok: true, ...entries[0], entries });\n\t\t\t\t} catch (err) {\n\t\t\t\t\tconst message = err instanceof Error ? err.message : \"Search failed\";\n\t\t\t\t\tconst entry: IndexedCuratorSearchEntry = {\n\t\t\t\t\t\tqueryIndex: qi,\n\t\t\t\t\t\tquery: trimmedQuery,\n\t\t\t\t\t\tanswer: \"\",\n\t\t\t\t\t\tresults: [],\n\t\t\t\t\t\terror: message,\n\t\t\t\t\t\tprovider: typeof provider === \"string\" && provider.length > 0 ? provider : defaultProvider,\n\t\t\t\t\t};\n\t\t\t\t\tcallbacks.onAddSearchResults([entry]);\n\t\t\t\t\tsendJson(res, 200, { ok: true, ...entry, entries: [entry] });\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (method === \"POST\" && url.pathname === \"/summarize\") {\n\t\t\t\tconst body = await parseBodyOrSend(req, res);\n\t\t\t\tif (!body) return;\n\t\t\t\tif (!validateToken(body, res)) return;\n\t\t\t\tif (state === \"COMPLETED\") {\n\t\t\t\t\tsendJson(res, 409, { ok: false, error: \"Session closed\" });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst parsed = normalizeSelectedIndices((body as { selected?: unknown }).selected, {\n\t\t\t\t\tallowEmpty: false,\n\t\t\t\t\tmaxExclusive: nextQueryIndex,\n\t\t\t\t});\n\t\t\t\tif (\"error\" in parsed) {\n\t\t\t\t\tsendJson(res, 400, { ok: false, error: parsed.error });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tlet model: string | undefined;\n\t\t\t\tconst bodyModel = (body as { model?: unknown }).model;\n\t\t\t\tif (bodyModel !== undefined) {\n\t\t\t\t\tif (typeof bodyModel !== \"string\") {\n\t\t\t\t\t\tsendJson(res, 400, { ok: false, error: \"Invalid model\" });\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tconst trimmedModel = bodyModel.trim();\n\t\t\t\t\tmodel = trimmedModel.length > 0 ? trimmedModel : undefined;\n\t\t\t\t}\n\n\t\t\t\tconst bodyFeedback = (body as { feedback?: unknown }).feedback;\n\t\t\t\tconst feedback = typeof bodyFeedback === \"string\" && bodyFeedback.trim().length > 0\n\t\t\t\t\t? bodyFeedback.trim()\n\t\t\t\t\t: undefined;\n\n\t\t\t\tabortInFlightSummarize();\n\t\t\t\tconst controller = new AbortController();\n\t\t\t\tsummarizeAbortController = controller;\n\t\t\t\tconst requestId = ++summarizeRequestSeq;\n\n\t\t\t\ttry {\n\t\t\t\t\tconst result = await callbacks.onSummarize(parsed.indices, controller.signal, model, feedback);\n\t\t\t\t\tif (requestId !== summarizeRequestSeq || completed) {\n\t\t\t\t\t\tsendJson(res, 409, { ok: false, error: \"Summarize request superseded\" });\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tsendJson(res, 200, {\n\t\t\t\t\t\tok: true,\n\t\t\t\t\t\tsummary: result.summary,\n\t\t\t\t\t\tmeta: result.meta,\n\t\t\t\t\t});\n\t\t\t\t} catch (err) {\n\t\t\t\t\tconst message = err instanceof Error ? err.message : \"Summary generation failed\";\n\t\t\t\t\tconst status = controller.signal.aborted ? 409 : 500;\n\t\t\t\t\tsendJson(res, status, { ok: false, error: message });\n\t\t\t\t} finally {\n\t\t\t\t\tif (summarizeAbortController === controller) {\n\t\t\t\t\t\tsummarizeAbortController = null;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (method === \"POST\" && url.pathname === \"/rewrite\") {\n\t\t\t\tconst body = await parseBodyOrSend(req, res);\n\t\t\t\tif (!body) return;\n\t\t\t\tif (!validateToken(body, res)) return;\n\t\t\t\tif (state === \"COMPLETED\") {\n\t\t\t\t\tsendJson(res, 409, { ok: false, error: \"Session closed\" });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst { query } = body as { query?: unknown };\n\t\t\t\tif (typeof query !== \"string\" || query.trim().length === 0) {\n\t\t\t\t\tsendJson(res, 400, { ok: false, error: \"Invalid query\" });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst controller = new AbortController();\n\t\t\t\treq.on(\"close\", () => controller.abort());\n\t\t\t\ttouchHeartbeat();\n\t\t\t\ttry {\n\t\t\t\t\tconst rewritten = await callbacks.onRewriteQuery(query.trim(), controller.signal);\n\t\t\t\t\tsendJson(res, 200, { ok: true, query: rewritten });\n\t\t\t\t} catch (err) {\n\t\t\t\t\tconst message = err instanceof Error ? err.message : \"Rewrite failed\";\n\t\t\t\t\tconst status = controller.signal.aborted ? 409 : 500;\n\t\t\t\t\tsendJson(res, status, { ok: false, error: message });\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (method === \"POST\" && url.pathname === \"/submit\") {\n\t\t\t\tconst body = await parseBodyOrSend(req, res);\n\t\t\t\tif (!body) return;\n\t\t\t\tif (!validateToken(body, res)) return;\n\n\t\t\t\tconst parsed = normalizeSelectedIndices((body as { selected?: unknown }).selected, {\n\t\t\t\t\tallowEmpty: true,\n\t\t\t\t\tmaxExclusive: nextQueryIndex,\n\t\t\t\t});\n\t\t\t\tif (\"error\" in parsed) {\n\t\t\t\t\tsendJson(res, 400, { ok: false, error: parsed.error });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tlet summary: string | undefined;\n\t\t\t\tconst bodySummary = (body as { summary?: unknown }).summary;\n\t\t\t\tif (bodySummary !== undefined) {\n\t\t\t\t\tif (typeof bodySummary !== \"string\") {\n\t\t\t\t\t\tsendJson(res, 400, { ok: false, error: \"Invalid summary\" });\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tconst trimmedSummary = bodySummary.trim();\n\t\t\t\t\tsummary = trimmedSummary.length > 0 ? trimmedSummary : undefined;\n\t\t\t\t}\n\n\t\t\t\tlet summaryMeta: SummaryMeta | undefined;\n\t\t\t\tconst bodySummaryMeta = (body as { summaryMeta?: unknown }).summaryMeta;\n\t\t\t\tif (bodySummaryMeta !== undefined) {\n\t\t\t\t\tconst parsedSummaryMeta = normalizeSummaryMeta(bodySummaryMeta);\n\t\t\t\t\tif (!parsedSummaryMeta) {\n\t\t\t\t\t\tsendJson(res, 400, { ok: false, error: \"Invalid summaryMeta\" });\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tsummaryMeta = parsedSummaryMeta;\n\t\t\t\t}\n\n\t\t\t\tif (state !== \"SEARCHING\" && state !== \"RESULT_SELECTION\") {\n\t\t\t\t\tsendJson(res, 409, { ok: false, error: \"Cannot submit in current state\" });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (!markCompleted()) {\n\t\t\t\t\tsendJson(res, 409, { ok: false, error: \"Session closed\" });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst rawResults = (body as { rawResults?: unknown }).rawResults === true;\n\t\t\t\tsendJson(res, 200, { ok: true });\n\t\t\t\tsetImmediate(() => callbacks.onSubmit({\n\t\t\t\t\tselectedQueryIndices: parsed.indices,\n\t\t\t\t\t...(summary !== undefined ? { summary } : {}),\n\t\t\t\t\t...(summaryMeta !== undefined ? { summaryMeta } : {}),\n\t\t\t\t\trawResults,\n\t\t\t\t}));\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (method === \"POST\" && url.pathname === \"/cancel\") {\n\t\t\t\tconst body = await parseBodyOrSend(req, res);\n\t\t\t\tif (!body) return;\n\t\t\t\tif (!validateToken(body, res)) return;\n\t\t\t\tif (!markCompleted()) {\n\t\t\t\t\tsendJson(res, 200, { ok: true });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst { reason } = body as { reason?: string };\n\t\t\t\tsendJson(res, 200, { ok: true });\n\t\t\t\tconst cancelReason = reason === \"timeout\" ? \"timeout\" : \"user\";\n\t\t\t\tsetImmediate(() => callbacks.onCancel(cancelReason));\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tres.writeHead(404, { \"Content-Type\": \"text/plain\" });\n\t\t\tres.end(\"Not found\");\n\t\t} catch (err) {\n\t\t\tconst message = err instanceof Error ? err.message : \"Server error\";\n\t\t\tsendJson(res, 500, { ok: false, error: message });\n\t\t}\n\t});\n\n\treturn new Promise((resolve, reject) => {\n\t\tconst onError = (err: Error) => {\n\t\t\treject(new Error(`Curator server failed to start: ${err.message}`));\n\t\t};\n\n\t\tconst networkConfig = resolveCuratorNetworkConfig();\n\n\t\tserver.once(\"error\", onError);\n\t\tserver.listen(0, networkConfig.bind, () => {\n\t\t\tserver.off(\"error\", onError);\n\t\t\tconst addr = server.address();\n\t\t\tif (!addr || typeof addr === \"string\") {\n\t\t\t\treject(new Error(\"Curator server: invalid address\"));\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst url = `http://${networkConfig.host}:${addr.port}/?session=${sessionToken}`;\n\n\t\t\twatchdog = setInterval(() => {\n\t\t\t\tif (completed) return;\n\t\t\t\tif (!browserConnected) {\n\t\t\t\t\tconst noBrowserTimeoutMs = Math.max(5000, getEffectiveTimeoutMs());\n\t\t\t\t\tif (state !== \"RESULT_SELECTION\") return;\n\t\t\t\t\tif (Date.now() - stateChangedAt <= noBrowserTimeoutMs) return;\n\t\t\t\t\tif (!markCompleted()) return;\n\t\t\t\t\tsetImmediate(() => callbacks.onCancel(\"timeout\"));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (shouldTimeoutFromClientIdle()) {\n\t\t\t\t\tif (!markCompleted()) return;\n\t\t\t\t\tsetImmediate(() => callbacks.onCancel(\"timeout\"));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (Date.now() - lastHeartbeatAt <= STALE_THRESHOLD_MS) return;\n\t\t\t\tconst staleReason = state === \"RESULT_SELECTION\" ? \"timeout\" : \"stale\";\n\t\t\t\tif (!markCompleted()) return;\n\t\t\t\tsetImmediate(() => callbacks.onCancel(staleReason));\n\t\t\t}, WATCHDOG_INTERVAL_MS);\n\n\t\t\tresolve({\n\t\t\t\tserver,\n\t\t\t\turl,\n\t\t\t\tclose: () => {\n\t\t\t\t\tconst wasOpen = markCompleted();\n\t\t\t\t\ttry { server.close(); } catch {}\n\t\t\t\t\tif (wasOpen) {\n\t\t\t\t\t\tsetImmediate(() => callbacks.onCancel(\"stale\"));\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tpushResult: (queryIndex, data) => {\n\t\t\t\t\tif (completed) return;\n\t\t\t\t\tnextQueryIndex = Math.max(nextQueryIndex, queryIndex + 1);\n\t\t\t\t\tconst eventData: CuratorResultEventData = { ...data, queryIndex, query: data.query ?? queries[queryIndex] ?? \"\" };\n\t\t\t\t\tretainStreamedEvent({ event: \"result\", data: eventData });\n\t\t\t\t\tsendSSE(\"result\", eventData);\n\t\t\t\t},\n\t\t\t\tpushError: (queryIndex, error, provider, meta) => {\n\t\t\t\t\tif (completed) return;\n\t\t\t\t\tnextQueryIndex = Math.max(nextQueryIndex, queryIndex + 1);\n\t\t\t\t\tconst eventData: CuratorSearchErrorEventData = { queryIndex, query: meta?.query ?? queries[queryIndex] ?? \"\", error, provider, slotIndex: meta?.slotIndex };\n\t\t\t\t\tretainStreamedEvent({ event: \"search-error\", data: eventData });\n\t\t\t\t\tsendSSE(\"search-error\", eventData);\n\t\t\t\t},\n\t\t\t\tsearchesDone: () => {\n\t\t\t\t\tif (completed) return;\n\t\t\t\t\tsearchStreamDone = true;\n\t\t\t\t\tsendSSE(\"done\", {});\n\t\t\t\t\tstate = \"RESULT_SELECTION\";\n\t\t\t\t\tstateChangedAt = Date.now();\n\t\t\t\t},\n\t\t\t\tgetConnectionState: () => ({\n\t\t\t\t\tbrowserConnected,\n\t\t\t\t\tlastHeartbeatAgeMs: Date.now() - lastHeartbeatAt,\n\t\t\t\t}),\n\t\t\t});\n\t\t});\n\t});\n}\n"]}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type Lookup } from "./ssrf-protection.ts";
|
|
2
|
+
import { type AuthFetchProfile } from "./auth-fetch.ts";
|
|
2
3
|
export { loadSsrfConfig } from "./ssrf-protection.ts";
|
|
3
4
|
export declare function loadSsrfAllowRanges(): string[];
|
|
4
5
|
export interface VideoFrame {
|
|
@@ -36,6 +37,7 @@ export interface ExtractOptions {
|
|
|
36
37
|
model?: string;
|
|
37
38
|
mode?: "readable" | "raw" | "answer";
|
|
38
39
|
answerModel?: string;
|
|
40
|
+
authFetchProfile?: AuthFetchProfile;
|
|
39
41
|
/** Custom DNS resolver used for SSRF validation. Primarily a test seam. */
|
|
40
42
|
lookup?: Lookup;
|
|
41
43
|
}
|