perf(registratura): lightweight API mode strips base64 attachments from list
ROOT CAUSE: RegistryEntry stores file attachments as base64 strings in JSON.
A single 5MB PDF becomes ~6.7MB of base64. With 6 entries, the exportAll()
endpoint was sending 30-60MB of JSON on every page load taking 2+ minutes.
Fix: Added ?lightweight=true parameter to /api/storage GET endpoint.
When enabled, stripHeavyFields() recursively removes large 'data' and
'fileData' string fields (>1KB) from JSON values, replacing with '__stripped__'.
Changes:
- /api/storage route.ts: stripHeavyFields() + lightweight query param
- StorageService.export(): accepts { lightweight?: boolean } option
- DatabaseStorageAdapter.export(): passes lightweight flag to API
- LocalStorageAdapter.export(): accepts option (no-op, localStorage is fast)
- useStorage.exportAll(): passes options through
- registry-service.ts: getAllEntries() uses lightweight=true by default
- registry-service.ts: new getFullEntry() loads single entry with full data
- use-registry.ts: exports loadFullEntry() for on-demand full loading
- registratura-module.tsx: handleEdit/handleNavigateEntry load full entry
Result: List loading transfers ~100KB instead of 30-60MB. Editing loads
full data for a single entry on demand (~5-10MB for one entry vs all).
This commit is contained in:
@@ -8,18 +8,20 @@ export interface RegistryStorage {
|
||||
set<T>(key: string, value: T): Promise<void>;
|
||||
delete(key: string): Promise<void>;
|
||||
list(): Promise<string[]>;
|
||||
exportAll(): Promise<Record<string, unknown>>;
|
||||
exportAll(options?: {
|
||||
lightweight?: boolean;
|
||||
}): Promise<Record<string, unknown>>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load all registry entries in a SINGLE request.
|
||||
* Uses exportAll() which fetches namespace data in one HTTP call,
|
||||
* avoiding the N+1 pattern (list keys → get each one individually).
|
||||
* Load all registry entries in a SINGLE lightweight request.
|
||||
* Uses exportAll({ lightweight: true }) which strips base64 attachment data
|
||||
* server-side, reducing payload from potentially 30-60MB to <100KB.
|
||||
*/
|
||||
export async function getAllEntries(
|
||||
storage: RegistryStorage,
|
||||
): Promise<RegistryEntry[]> {
|
||||
const all = await storage.exportAll();
|
||||
const all = await storage.exportAll({ lightweight: true });
|
||||
const entries: RegistryEntry[] = [];
|
||||
for (const [key, value] of Object.entries(all)) {
|
||||
if (key.startsWith(STORAGE_PREFIX) && value) {
|
||||
@@ -30,6 +32,16 @@ export async function getAllEntries(
|
||||
return entries;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a single full entry (with attachment data) for editing.
|
||||
*/
|
||||
export async function getFullEntry(
|
||||
storage: RegistryStorage,
|
||||
id: string,
|
||||
): Promise<RegistryEntry | null> {
|
||||
return storage.get<RegistryEntry>(`${STORAGE_PREFIX}${id}`);
|
||||
}
|
||||
|
||||
export async function saveEntry(
|
||||
storage: RegistryStorage,
|
||||
entry: RegistryEntry,
|
||||
|
||||
Reference in New Issue
Block a user