Skip to content

Commit ea1faee

Browse files
feat: implement offline synchronization, local IndexedDB storage, and AES-GCM encryption for field data management
1 parent f4c98db commit ea1faee

4 files changed

Lines changed: 33 additions & 5 deletions

File tree

src/hooks/useNodeConfig.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ export function useNodeConfig(getSessionKey: () => CryptoKey, getSalt: () => Uin
2222

2323
for (const [key, value] of Object.entries(rawPayload)) {
2424
if (CONFIG_SCHEMA[key]?.sensitive && value && typeof value === 'object') {
25-
decryptedConfig[key] = await decryptField(value, sessionKey);
25+
decryptedConfig[key] = await decryptField(value as any, sessionKey);
2626
} else {
2727
decryptedConfig[key] = value;
2828
}

src/hooks/useOfflineSync.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import {
88
useRef,
99
useState,
1010
} from "react";
11-
import { flushSyncQueue, getSyncQueueSize } from "@/src/lib/idbClient";
11+
import { flushSyncQueue, getSyncQueueSize } from "@/src/lib/storage/idb";
1212

1313
export type SyncStatus = "idle" | "syncing" | "error";
1414

src/lib/crypto/cryptoEngine.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,9 +70,9 @@ export async function encryptField(plaintext: string, sessionKey: CryptoKey, sal
7070
);
7171

7272
return {
73-
iv: bufferToBase64(iv.buffer),
74-
salt: bufferToBase64(salt.buffer),
75-
ciphertext: bufferToBase64(ciphertextBuffer),
73+
iv: bufferToBase64(iv.buffer as ArrayBuffer),
74+
salt: bufferToBase64(salt.buffer as ArrayBuffer),
75+
ciphertext: bufferToBase64(ciphertextBuffer as ArrayBuffer),
7676
version: 1,
7777
};
7878
}

src/lib/storage/idb.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -361,3 +361,31 @@ export async function flushSyncQueue(): Promise<SyncFlushResult> {
361361

362362
return result;
363363
}
364+
365+
366+
// ── Generic Wrappers for useNodeConfig Hook ──────────────────────────
367+
368+
/**
369+
* Wrapper to match hook signature for saving node configuration
370+
*/
371+
export async function saveToIndexedDB(key: string, data: any): Promise<void> {
372+
// We use the nodeConfigSnapshots store. The key matches the nodeId.
373+
await saveNodeConfigSnapshot({
374+
nodeId: key,
375+
config: data,
376+
version: 1,
377+
snapshotAt: new Date().toISOString()
378+
});
379+
}
380+
381+
/**
382+
* Wrapper to match hook signature for loading node configuration
383+
*/
384+
export async function loadFromIndexedDB(key: string): Promise<any | null> {
385+
const snapshots = await getNodeConfigSnapshots(key);
386+
if (snapshots.length === 0) return null;
387+
388+
// Sort by snapshot date to get the newest one if multiple exist
389+
snapshots.sort((a, b) => new Date(b.snapshotAt).getTime() - new Date(a.snapshotAt).getTime());
390+
return snapshots[0].config;
391+
}

0 commit comments

Comments
 (0)