Files
openchamber/packages/vscode/src/bridge-localfs-proxy-runtime.ts
T
Bohdan Triapitsyn a45376d585 perf: migrate chat rendering to virtua (#1651)
* refactor: migrate chat history virtualization to virtua

* refactor: render loaded chat history directly

* refactor: finish virtua migration

* perf: defer tool body rendering

* perf: queue deferred tool body mounts

* perf: quiet and defer markdown file probes

* perf: defer markdown code highlighting

* perf: stabilize markdown plugin lists

* perf: defer mermaid markdown rendering

* perf: delay markdown file reference annotation

* perf: attach markdown table listeners on demand

* perf: trim markdown render overhead
2026-06-15 03:29:40 +03:00

148 lines
4.7 KiB
TypeScript

import * as fs from 'fs';
import { getFsMimeType, normalizeFsPath, resolveFileReadPath, type FsReadPathResolution } from './bridge-fs-helpers-runtime';
type ApiProxyResponsePayload = {
status: number;
headers: Record<string, string>;
bodyBase64: string;
};
export const base64EncodeUtf8 = (text: string) => Buffer.from(text, 'utf8').toString('base64');
export const collectHeaders = (headers: Headers): Record<string, string> => {
const result: Record<string, string> = {};
headers.forEach((value, key) => {
result[key] = value;
});
return result;
};
export const buildUnavailableApiResponse = (): ApiProxyResponsePayload => {
const body = JSON.stringify({ error: 'OpenCode API unavailable' });
return {
status: 503,
headers: { 'content-type': 'application/json' },
bodyBase64: base64EncodeUtf8(body),
};
};
export const sanitizeForwardHeaders = (input: Record<string, string> | undefined): Record<string, string> => {
const headers: Record<string, string> = { ...(input || {}) };
delete headers['content-length'];
delete headers['host'];
delete headers['connection'];
return headers;
};
const buildProxyJsonError = (status: number, error: string): ApiProxyResponsePayload => ({
status,
headers: { 'content-type': 'application/json' },
bodyBase64: base64EncodeUtf8(JSON.stringify({ error })),
});
const normalizeFsProxyPath = (pathname: string): '/api/fs/stat' | '/api/fs/read' | '/api/fs/raw' | null => {
if (pathname === '/api/fs/stat' || pathname === '/fs/stat') return '/api/fs/stat';
if (pathname === '/api/fs/read' || pathname === '/fs/read') return '/api/fs/read';
if (pathname === '/api/fs/raw' || pathname === '/fs/raw') return '/api/fs/raw';
return null;
};
export const tryHandleLocalFsProxy = async (method: string, requestPath: string): Promise<ApiProxyResponsePayload | null> => {
let parsed: URL;
try {
parsed = new URL(requestPath, 'https://openchamber.local');
} catch {
return buildProxyJsonError(400, 'Invalid request path');
}
const fsProxyPath = normalizeFsProxyPath(parsed.pathname);
if (!fsProxyPath) {
return null;
}
if (method !== 'GET' && method !== 'HEAD') {
return buildProxyJsonError(405, 'Method not allowed');
}
const targetPath = parsed.searchParams.get('path') || '';
const optional = parsed.searchParams.get('optional') === 'true';
const resolution: FsReadPathResolution = await resolveFileReadPath(targetPath);
if (!resolution.ok) {
if (fsProxyPath === '/api/fs/stat' && optional && resolution.status === 404) {
return {
status: 200,
headers: {
'content-type': 'application/json',
'cache-control': 'no-store',
},
bodyBase64: base64EncodeUtf8(JSON.stringify({ path: targetPath, exists: false })),
};
}
return buildProxyJsonError(resolution.status, resolution.error);
}
try {
const stats = await fs.promises.stat(resolution.resolvedPath);
if (!stats.isFile()) {
return buildProxyJsonError(400, 'Specified path is not a file');
}
if (fsProxyPath === '/api/fs/stat') {
return {
status: 200,
headers: {
'content-type': 'application/json',
'cache-control': 'no-store',
},
bodyBase64: base64EncodeUtf8(JSON.stringify({
path: normalizeFsPath(resolution.resolvedPath),
isFile: true,
size: stats.size,
mtimeMs: stats.mtimeMs,
})),
};
}
if (fsProxyPath === '/api/fs/read') {
const content = await fs.promises.readFile(resolution.resolvedPath, 'utf8');
return {
status: 200,
headers: {
'content-type': 'text/plain; charset=utf-8',
'cache-control': 'no-store',
},
bodyBase64: base64EncodeUtf8(content),
};
}
const raw = await fs.promises.readFile(resolution.resolvedPath);
return {
status: 200,
headers: {
'content-type': getFsMimeType(resolution.resolvedPath),
'cache-control': 'no-store',
},
bodyBase64: Buffer.from(raw).toString('base64'),
};
} catch (error) {
const err = error as NodeJS.ErrnoException;
if (err?.code === 'ENOENT') {
if (fsProxyPath === '/api/fs/stat' && optional) {
return {
status: 200,
headers: {
'content-type': 'application/json',
'cache-control': 'no-store',
},
bodyBase64: base64EncodeUtf8(JSON.stringify({ path: targetPath, exists: false })),
};
}
return buildProxyJsonError(404, 'File not found');
}
if (fsProxyPath === '/api/fs/stat') {
return buildProxyJsonError(500, 'Unable to stat file');
}
return buildProxyJsonError(500, 'Unable to read file');
}
};