feat(fs): raise preview size cap for PDFs and images (#1096)
Local IPC bumps to 50MB; SSH relay bumps to 10MB (bounded by the 16MB JSON-RPC frame cap). Text and search paths keep the 5MB cap.
This commit is contained in:
parent
3bf2b31c96
commit
50ebd11003
|
|
@ -45,6 +45,14 @@ import { getSshFilesystemProvider } from '../providers/ssh-filesystem-dispatch'
|
|||
import { getSshGitProvider } from '../providers/ssh-git-dispatch'
|
||||
|
||||
const MAX_FILE_SIZE = 5 * 1024 * 1024 // 5MB
|
||||
// Why: previewable binaries (PDFs, images) are rendered by the viewer as
|
||||
// base64 blobs, not parsed as text — 5MB is tight for real-world PDFs, and
|
||||
// raising this cap only affects binary preview, not text/search paths.
|
||||
// The relay (SSH) uses a smaller 10MB cap because its JSON-RPC frames are
|
||||
// bounded by MAX_MESSAGE_SIZE = 16MB; the local IPC path has no such limit,
|
||||
// so 50MB covers real-world PDFs (specs, datasheets, image-heavy contracts).
|
||||
// See src/relay/fs-handler-utils.ts for the remote-side reasoning.
|
||||
const MAX_PREVIEWABLE_BINARY_SIZE = 50 * 1024 * 1024 // 50MB
|
||||
const DEFAULT_SEARCH_MAX_RESULTS = 2000
|
||||
const MAX_MATCHES_PER_FILE = 100
|
||||
const SEARCH_TIMEOUT_MS = 15000
|
||||
|
|
@ -124,14 +132,15 @@ export function registerFilesystemHandlers(store: Store): void {
|
|||
}
|
||||
const filePath = await resolveAuthorizedPath(args.filePath, store)
|
||||
const stats = await stat(filePath)
|
||||
if (stats.size > MAX_FILE_SIZE) {
|
||||
const mimeType = PREVIEWABLE_BINARY_MIME_TYPES[extname(filePath).toLowerCase()]
|
||||
const sizeLimit = mimeType ? MAX_PREVIEWABLE_BINARY_SIZE : MAX_FILE_SIZE
|
||||
if (stats.size > sizeLimit) {
|
||||
throw new Error(
|
||||
`File too large: ${(stats.size / 1024 / 1024).toFixed(1)}MB exceeds ${MAX_FILE_SIZE / 1024 / 1024}MB limit`
|
||||
`File too large: ${(stats.size / 1024 / 1024).toFixed(1)}MB exceeds ${sizeLimit / 1024 / 1024}MB limit`
|
||||
)
|
||||
}
|
||||
|
||||
const buffer = await readFile(filePath)
|
||||
const mimeType = PREVIEWABLE_BINARY_MIME_TYPES[extname(filePath).toLowerCase()]
|
||||
if (mimeType) {
|
||||
return {
|
||||
content: buffer.toString('base64'),
|
||||
|
|
|
|||
|
|
@ -11,6 +11,20 @@ import { execFile, type ChildProcess } from 'child_process'
|
|||
// ─── Constants ───────────────────────────────────────────────────────
|
||||
|
||||
export const MAX_FILE_SIZE = 5 * 1024 * 1024
|
||||
// Why: previewable binaries (PDFs, images) are rendered by the viewer as
|
||||
// base64 blobs, not parsed as text — 5MB is tight for real-world PDFs, and
|
||||
// raising this cap only affects binary preview, not text/search paths.
|
||||
// Why 10MB (not 50MB like the local main-process cap): the SSH relay ships
|
||||
// every JSON-RPC response in a single framed message capped at
|
||||
// MAX_MESSAGE_SIZE = 16MB (see src/relay/protocol.ts and
|
||||
// src/main/ssh/relay-protocol.ts). A file here is sent as base64 inside JSON,
|
||||
// so 10MB on disk → ~13.3MB base64 → ~13.4MB framed payload, leaving headroom
|
||||
// under the 16MB frame cap. Raising this cap without first landing streaming
|
||||
// reads would cause the encoder to throw "Message too large" and the decoder
|
||||
// to discard oversized frames for borderline files. The proper path to a
|
||||
// higher remote cap is streaming fs.readFile over the relay, not bumping
|
||||
// MAX_MESSAGE_SIZE (which would introduce head-of-line blocking on the mux).
|
||||
export const MAX_PREVIEWABLE_BINARY_SIZE = 10 * 1024 * 1024
|
||||
export const SEARCH_TIMEOUT_MS = 15_000
|
||||
export const MAX_MATCHES_PER_FILE = 100
|
||||
export const DEFAULT_MAX_RESULTS = 2000
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ import type { RelayContext } from './context'
|
|||
import { expandTilde } from './context'
|
||||
import {
|
||||
MAX_FILE_SIZE,
|
||||
MAX_PREVIEWABLE_BINARY_SIZE,
|
||||
DEFAULT_MAX_RESULTS,
|
||||
IMAGE_MIME_TYPES,
|
||||
isBinaryBuffer,
|
||||
|
|
@ -82,14 +83,15 @@ export class FsHandler {
|
|||
const filePath = expandTilde(params.filePath as string)
|
||||
await this.context.validatePathResolved(filePath)
|
||||
const stats = await stat(filePath)
|
||||
if (stats.size > MAX_FILE_SIZE) {
|
||||
const mimeType = IMAGE_MIME_TYPES[extname(filePath).toLowerCase()]
|
||||
const sizeLimit = mimeType ? MAX_PREVIEWABLE_BINARY_SIZE : MAX_FILE_SIZE
|
||||
if (stats.size > sizeLimit) {
|
||||
throw new Error(
|
||||
`File too large: ${(stats.size / 1024 / 1024).toFixed(1)}MB exceeds ${MAX_FILE_SIZE / 1024 / 1024}MB limit`
|
||||
`File too large: ${(stats.size / 1024 / 1024).toFixed(1)}MB exceeds ${sizeLimit / 1024 / 1024}MB limit`
|
||||
)
|
||||
}
|
||||
|
||||
const buffer = await readFile(filePath)
|
||||
const mimeType = IMAGE_MIME_TYPES[extname(filePath).toLowerCase()]
|
||||
if (mimeType) {
|
||||
return { content: buffer.toString('base64'), isBinary: true, isImage: true, mimeType }
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue