Loading files
This file is pinned to the selected release. Download the original to open it in your design tool.
af2971ee9This file is pinned to the selected release. Download the original to open it in your design tool.
import type { IncomingMessage, ServerResponse } from 'node:http'
import { CommandBarError, type CommandBarService } from './commandBar.js'
import { isTrustedLocal } from './localSocket.js'
/** Shared by the daemon and the isolated experiment server. Returns false for other routes. */
export async function handleCommandBarHttp(
req: IncomingMessage, res: ServerResponse, service?: Pick<CommandBarService, 'status' | 'decide'>,
): Promise<boolean> {
const path = (req.url ?? '').split('?')[0]
if (path !== '/api/command-bar/status' && path !== '/api/command-bar/resolve') return false
const json = (status: number, body: unknown) => {
if (res.destroyed) return
res.writeHead(status, { 'Content-Type': 'application/json', 'Cache-Control': 'no-store' })
res.end(JSON.stringify(body))
}
const fail = (status: number, code: string, message: string) => json(status, { success: false, error: { code, message } })
const peer = req.socket.remoteAddress
const loopback = isTrustedLocal(req) || peer === '127.0.0.1' || peer === '::1' || peer === '::ffff:127.0.0.1'
if (req.headers['x-adapter-local'] !== '1' || !loopback || req.headers.origin) {
fail(403, 'FORBIDDEN', 'Native local client required.'); return true
}
if (!service) { fail(503, 'UNAVAILABLE', 'Start the command bar experiment server or updated daemon.'); return true }
const isStatus = path.endsWith('/status')
if (req.method !== (isStatus ? 'GET' : 'POST')) { fail(405, 'METHOD', 'Unsupported method.'); return true }
const abort = new AbortController()
let uploadTimer: ReturnType<typeof setTimeout> | undefined
const onClose = () => { if (!res.writableEnded) abort.abort() }
res.on('close', onClose)
try {
let body: unknown
if (!isStatus) {
const chunks: Buffer[] = []
let length = 0
// Bound upload time and bytes too; an incomplete body must not keep a request alive forever.
uploadTimer = setTimeout(() => req.destroy(), 10_000)
for await (const chunk of req.iterator({ destroyOnReturn: false })) {
length += Buffer.byteLength(chunk)
if (length > 128_000) { fail(413, 'INVALID_REQUEST', 'Command context is too large.'); req.resume(); return true }
chunks.push(Buffer.from(chunk))
}
clearTimeout(uploadTimer)
try { body = JSON.parse(Buffer.concat(chunks).toString('utf8')) }
catch { fail(400, 'INVALID_REQUEST', 'Invalid command request.'); return true }
}
const data = isStatus ? await service.status() : await service.decide(body, abort.signal)
json(200, { success: true, data })
} catch (error) {
if (error instanceof CommandBarError) fail(error.status, error.code, error.message)
else fail(502, 'UNAVAILABLE', 'Command bar unavailable.')
} finally { clearTimeout(uploadTimer); res.off('close', onClose) }
return true
}