Add PDF archive store, raw-body IPC and export file helpers
The searchable PDF can be archived content-addressed under the local data dir with its sha256 and layout fingerprint; a different PDF for an archived invoice is refused and reads verify the hash. Export writes go through a raw-body command that remembers the last folder; reveal-in-folder and open fall back to xdg-open / explorer. Adds a Windows-safe export file name builder. Migration M4 adds the archive columns and last export dir.
This commit is contained in:
+1
-8
@@ -10,13 +10,6 @@ import { imageSizeFromDataUri } from "./imageSize";
|
||||
import { getRenderClient, nextRenderJobId } from "./renderClient";
|
||||
import type { BankAccount, Invoice, Settings } from "./types";
|
||||
|
||||
function bytesToBase64(bytes: Uint8Array): string {
|
||||
let bin = "";
|
||||
const step = 0x8000;
|
||||
for (let i = 0; i < bytes.length; i += step) bin += String.fromCharCode(...bytes.subarray(i, i + step));
|
||||
return btoa(bin);
|
||||
}
|
||||
|
||||
/** A logo with no readable size is fitted as if it filled Classic's 170 x 54 box. */
|
||||
const UNKNOWN_LOGO_SIZE = { width: 170, height: 54 };
|
||||
|
||||
@@ -82,7 +75,7 @@ export async function savePdfBytes(bytes: Uint8Array, fileName: string): Promise
|
||||
filters: [{ name: "PDF document", extensions: ["pdf"] }],
|
||||
});
|
||||
if (!path) return null;
|
||||
await api.saveBinaryFile(path, bytesToBase64(bytes));
|
||||
await api.writeExportFile(path, bytes);
|
||||
return path;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user