fix: Bug - Sending files between users doesn't really work (chunk-time size re-gate)

Remove the leftover MAX_AUTO_SAVE_SIZE_BYTES guard from handleFileChunk's
in-memory path. The request gate (canReceiveAttachment) already admits 10-50 MB
generic files for in-memory receive on stores without disk streaming (browser),
but the chunk handler silently dropped every chunk of such files: no ack was
sent, the sender's waitForAck timed out, and the receiver's GUI never changed.
Receive admission is now decided once, at request time.

Adds a two-browser regression e2e that sends an 11 MB generic file and asserts
Request -> progress -> Download.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-07-13 18:48:30 +02:00
co-authored by Cursor
parent 497033aff0
commit 590e487250
5 changed files with 161 additions and 7 deletions
@@ -629,6 +629,36 @@ describe('AttachmentTransferService', () => {
expect(webrtc.sendToPeer).not.toHaveBeenCalled();
});
it('assembles generic files above the auto-save cap in memory when the store cannot stream but can persist them', async () => {
// Browser receiver: no disk streaming, persistable up to 50 MB. The request
// gate admits a 20 MB file for in-memory receive, so the chunk handler must
// accept its chunks instead of dropping them with a file-too-large error.
attachmentStorage.canStreamToDisk.mockReturnValue(false);
attachmentStorage.canPersistSize.mockImplementation((bytes: number) => bytes <= 50 * 1024 * 1024);
const service = createService();
const attachment = registerIncomingGenericFile(20 * 1024 * 1024);
service.handleFileChunk(chunkPayload(0, 2, [
1,
2,
3
]));
expect(attachment.requestError).toBeUndefined();
expect(attachment.receivedBytes).toBe(3);
service.handleFileChunk(chunkPayload(1, 2, [
4,
5,
6
]));
await vi.waitFor(() => expect(attachment.available).toBe(true));
expect(attachment.objectUrl).toMatch(/^blob:/);
});
it('assembles browser-sized generic files in memory when streaming is unavailable', async () => {
attachmentStorage.canStreamToDisk.mockReturnValue(false);
attachmentStorage.canPersistSize.mockImplementation((bytes: number) => bytes <= 50 * 1024 * 1024);
@@ -425,12 +425,11 @@ export class AttachmentTransferService {
return;
}
if (attachment.size > MAX_AUTO_SAVE_SIZE_BYTES) {
attachment.requestError = this.appI18n.instant(ATTACHMENT_FILE_TOO_LARGE_KEY);
this.runtimeStore.touch();
return;
}
// Reaching here means canReceiveAttachment passed and disk streaming is not
// used, so the in-memory path is the agreed receive strategy - including
// above-auto-save-cap files on stores that cannot stream but can persist
// them (browser). A stricter size guard here would silently drop chunks the
// request gate already admitted.
const decodedBytes = this.transport.decodeBase64(data);
const assemblyKey = `${messageId}:${fileId}`;
const requestKey = this.buildRequestKey(messageId, fileId);