PC2 can now automatically pull and restore a fresh copy of PC1's database on a daily schedule. Config and API key are stored in local JSON files so they survive database restores. - New networkSyncConfigService: file-based config (network-backup-key.json, network-sync-config.json) that persists through DB restores - New networkSyncService: streams live pg_dump from source PC over HTTP and pipes into psql, then reconnects Prisma and applies missing migrations - 6 new endpoints: get/regenerate API key, serve backup stream (key-auth only), get/save sync config, trigger immediate sync - Hourly cron job that fires only when current hour matches configured syncHour - NetworkBackupManager component: shows this machine's key (show/copy/regen) and receiver config (enable toggle, hour picker 0-23, source URL + key, Save + Sync Now, last sync status) - README setup guide for both PCs Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
59 lines
1.5 KiB
TypeScript
59 lines
1.5 KiB
TypeScript
import fs from "fs";
|
|
import path from "path";
|
|
import crypto from "crypto";
|
|
|
|
const KEY_FILE = path.resolve(process.cwd(), "network-backup-key.json");
|
|
const CONFIG_FILE = path.resolve(process.cwd(), "network-sync-config.json");
|
|
|
|
export interface NetworkSyncConfig {
|
|
enabled: boolean;
|
|
syncHour: number;
|
|
sourceUrl: string;
|
|
apiKey: string;
|
|
lastSyncAt: string | null;
|
|
lastSyncStatus: string | null;
|
|
lastSyncError: string | null;
|
|
}
|
|
|
|
export function getOrCreateApiKey(): string {
|
|
if (fs.existsSync(KEY_FILE)) {
|
|
try {
|
|
const data = JSON.parse(fs.readFileSync(KEY_FILE, "utf8"));
|
|
if (data.apiKey) return data.apiKey;
|
|
} catch {}
|
|
}
|
|
const key = crypto.randomUUID();
|
|
fs.writeFileSync(KEY_FILE, JSON.stringify({ apiKey: key }), "utf8");
|
|
return key;
|
|
}
|
|
|
|
export function regenerateApiKey(): string {
|
|
const key = crypto.randomUUID();
|
|
fs.writeFileSync(KEY_FILE, JSON.stringify({ apiKey: key }), "utf8");
|
|
return key;
|
|
}
|
|
|
|
export function readSyncConfig(): NetworkSyncConfig {
|
|
if (fs.existsSync(CONFIG_FILE)) {
|
|
try {
|
|
return JSON.parse(fs.readFileSync(CONFIG_FILE, "utf8"));
|
|
} catch {}
|
|
}
|
|
return {
|
|
enabled: false,
|
|
syncHour: 0,
|
|
sourceUrl: "",
|
|
apiKey: "",
|
|
lastSyncAt: null,
|
|
lastSyncStatus: null,
|
|
lastSyncError: null,
|
|
};
|
|
}
|
|
|
|
export function writeSyncConfig(patch: Partial<NetworkSyncConfig>): NetworkSyncConfig {
|
|
const current = readSyncConfig();
|
|
const updated = { ...current, ...patch };
|
|
fs.writeFileSync(CONFIG_FILE, JSON.stringify(updated, null, 2), "utf8");
|
|
return updated;
|
|
}
|