Improve attachment memory safety, downloads, and high-memory alert UX.
Queue Release Build / prepare (push) Successful in 20s
Deploy Web Apps / deploy (push) Successful in 9m2s
Queue Release Build / build-windows (push) Successful in 28m8s
Queue Release Build / build-linux (push) Successful in 47m26s
Queue Release Build / build-android (push) Successful in 19m52s
Queue Release Build / finalize (push) Successful in 4m42s
Queue Release Build / prepare (push) Successful in 20s
Deploy Web Apps / deploy (push) Successful in 9m2s
Queue Release Build / build-windows (push) Successful in 28m8s
Queue Release Build / build-linux (push) Successful in 47m26s
Queue Release Build / build-android (push) Successful in 19m52s
Queue Release Build / finalize (push) Successful in 4m42s
Stream large receives to disk with chunk acks to cap renderer RAM, evict off-screen display blobs, and route exports through a disk-aware download service. Fix the high-memory dialog (backdrop dismiss, copy, log actions), allow diagnostics paths in the path jail, and restore persisted image hydration after reload. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+58
-1
@@ -99,7 +99,17 @@ describe('AttachmentPersistenceService', () => {
|
||||
});
|
||||
|
||||
it('hydrates blob URLs on demand for a single attachment', async () => {
|
||||
const service = createService();
|
||||
const injector = Injector.create({
|
||||
providers: [
|
||||
AttachmentPersistenceService,
|
||||
AttachmentRuntimeStore,
|
||||
{ provide: DatabaseService, useValue: database },
|
||||
{ provide: AttachmentStorageService, useValue: attachmentStorage },
|
||||
{ provide: Store, useValue: { select: () => of('room-1') } }
|
||||
]
|
||||
});
|
||||
const service = runInInjectionContext(injector, () => injector.get(AttachmentPersistenceService));
|
||||
const runtimeStore = injector.get(AttachmentRuntimeStore);
|
||||
|
||||
await service.initFromDatabase();
|
||||
|
||||
@@ -113,10 +123,12 @@ describe('AttachmentPersistenceService', () => {
|
||||
savedPath: '/appdata/photo.png',
|
||||
available: false
|
||||
};
|
||||
const versionBefore = runtimeStore.updated();
|
||||
|
||||
await expect(service.ensureInlineDisplayObjectUrl(attachment)).resolves.toBe(true);
|
||||
expect(attachment.available).toBe(true);
|
||||
expect(attachment.objectUrl).toMatch(/^blob:/);
|
||||
expect(runtimeStore.updated()).toBeGreaterThan(versionBefore);
|
||||
expect(attachmentStorage.getFileSize).toHaveBeenCalledWith('/appdata/photo.png');
|
||||
expect(attachmentStorage.readFileChunk).toHaveBeenCalled();
|
||||
expect(attachmentStorage.readFile).not.toHaveBeenCalled();
|
||||
@@ -206,4 +218,49 @@ describe('AttachmentPersistenceService', () => {
|
||||
expect(attachmentStorage.readFileChunk).not.toHaveBeenCalled();
|
||||
expect(database.saveAttachment).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('restores host metadata without hydrating media blobs when display hydration is disabled', async () => {
|
||||
const service = createService();
|
||||
const attachment = {
|
||||
id: 'att-1',
|
||||
messageId: 'msg-1',
|
||||
filename: 'photo.png',
|
||||
size: 3,
|
||||
mime: 'image/png',
|
||||
isImage: true,
|
||||
savedPath: '/appdata/photo.png',
|
||||
available: false
|
||||
};
|
||||
|
||||
await expect(service.tryRestoreAttachmentHostOnly(attachment)).resolves.toBe(true);
|
||||
|
||||
expect(attachment.savedPath).toBe('/appdata/photo.png');
|
||||
expect(attachment.objectUrl).toBeUndefined();
|
||||
expect(attachment.available).toBe(false);
|
||||
expect(attachmentStorage.readFileChunk).not.toHaveBeenCalled();
|
||||
expect(attachmentStorage.readFile).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('revokes display blobs while keeping disk paths for later rehydration', () => {
|
||||
const service = createService();
|
||||
const attachment = {
|
||||
id: 'att-1',
|
||||
messageId: 'msg-1',
|
||||
filename: 'photo.png',
|
||||
size: 3,
|
||||
mime: 'image/png',
|
||||
isImage: true,
|
||||
savedPath: '/appdata/photo.png',
|
||||
available: true,
|
||||
objectUrl: 'blob:http://localhost/abc'
|
||||
};
|
||||
const revokeSpy = vi.spyOn(URL, 'revokeObjectURL').mockImplementation(() => undefined);
|
||||
|
||||
expect(service.revokeAttachmentDisplayBlob(attachment)).toBe(true);
|
||||
expect(attachment.objectUrl).toBeUndefined();
|
||||
expect(attachment.savedPath).toBe('/appdata/photo.png');
|
||||
expect(revokeSpy).toHaveBeenCalledWith('blob:http://localhost/abc');
|
||||
|
||||
revokeSpy.mockRestore();
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user