mirror of
https://github.com/getpaseo/paseo.git
synced 2026-08-15 04:42:45 +00:00
feat: stream files as binary frames over WebSocket (#659)
Replace base64-in-JSON file transfers with binary WebSocket frames to
unblock the JS thread when assistant markdown messages contain images.
Receive cost (JSON.parse over multi-MB base64) and persist cost (base64
re-encode to disk) both removed.
- Split daemon-client `exploreFileSystem` into `listDirectory` + `readFile`;
`readFile` returns `{ bytes, mime, size, modifiedAt }`. Encoding stays
private to the seam.
- New `packages/server/src/shared/binary-frames/` module hosts terminal
frames (moved from `terminal-stream-protocol.ts`) and new file-transfer
opcodes (`FileBegin` / `FileChunk` / `FileEnd`) with request-id correlation.
- Add optional `acceptBinary` to `FileExplorerRequestSchema`. New daemons
emit binary frames when set; legacy JSON path remains for old clients.
Compat fallback lives only inside `readFile`.
- New `persistAttachmentFromBytes` writes bytes directly: native via
`expo-file-system` `File.write(Uint8Array)`, web via Blob -> IndexedDB,
desktop via new `write_attachment_bytes` IPC. `persistAttachmentFromBase64`
removed.
This commit is contained in:
@@ -90,6 +90,37 @@ export async function writeAttachmentBase64(input: {
|
||||
};
|
||||
}
|
||||
|
||||
function normalizeBytes(value: unknown): Uint8Array {
|
||||
if (value instanceof Uint8Array) {
|
||||
return value;
|
||||
}
|
||||
if (value instanceof ArrayBuffer) {
|
||||
return new Uint8Array(value);
|
||||
}
|
||||
if (Array.isArray(value)) {
|
||||
return Uint8Array.from(value);
|
||||
}
|
||||
throw new Error("Attachment byte payload is required.");
|
||||
}
|
||||
|
||||
export async function writeAttachmentBytes(input: {
|
||||
attachmentId?: unknown;
|
||||
bytes?: unknown;
|
||||
extension?: unknown;
|
||||
}): Promise<AttachmentFileResult> {
|
||||
const bytes = normalizeBytes(input.bytes);
|
||||
const targetPath = await buildManagedAttachmentPath({
|
||||
attachmentId: input.attachmentId,
|
||||
extension: input.extension,
|
||||
});
|
||||
await writeFile(targetPath, bytes);
|
||||
const fileInfo = await stat(targetPath);
|
||||
return {
|
||||
path: targetPath,
|
||||
byteSize: fileInfo.size,
|
||||
};
|
||||
}
|
||||
|
||||
export async function copyAttachmentFileToManagedStorage(input: {
|
||||
attachmentId?: unknown;
|
||||
sourcePath?: unknown;
|
||||
|
||||
Reference in New Issue
Block a user