Files
bitvid/js/services/walletSyncService.js
thePR0M3TH3ANandClaude Opus 4.8 023f37f08f [sync] Unify NWC + Storage sync onto one shared implementation (step 1: backend)
walletSyncService and storageSyncService were near-identical copies (the "two
sync systems"). Extract the shared machinery into createEncryptedSyncItem() —
per-pubkey enable flags, conflict-checked push, cheap remote-exists check,
enable/disable/pull — so each service is now a thin config differing only in
d-tag, kind, availability, and buildPayload/applyPayload. Public surface
(isAvailable/isEnabled/hasRemote/push/pull/enable/disable + the *_DTAG export)
preserved; both dedicated suites pass (8).

Next (step 2): shared confirm dialog + consistent notifications + seamless
auto-sync in the two profile controllers (the user-facing UX unification).

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-01 15:49:42 -04:00

60 lines
2.1 KiB
JavaScript

// Opt-in encrypted cross-login sync for the NWC WALLET connection (todo #15).
// Mirrors storageSyncService but for the wallet settings managed by
// NwcSettingsService.
//
// HIGHEST SENSITIVITY: the NWC URI is a bearer SPENDING secret. Anyone who can
// decrypt this note (i.e. anyone who controls the user's Nostr key) can spend
// from the connected wallet. The UI MUST gate enabling this behind an explicit
// confirmation. Off by default; never log the decrypted URI.
//
// NwcSettingsService is a per-app instance (not a singleton), so this is a
// factory — the caller injects the live service.
import { encryptedSync as defaultEncryptedSync } from "../nostr/encryptedSyncFacade.js";
import { createEncryptedSyncItem } from "./encryptedSyncItem.js";
export const WALLET_SYNC_DTAG = "bitvid:nwc";
const SYNC_KIND = "wallet";
export function createWalletSyncService({
encryptedSync = defaultEncryptedSync,
nwcSettings,
} = {}) {
const item = createEncryptedSyncItem({
id: SYNC_KIND,
dtag: WALLET_SYNC_DTAG,
encryptedSync,
logLabel: "walletSync",
available: () => Boolean(nwcSettings),
// Minimal syncable payload from current wallet settings. null => nothing to
// sync (no wallet connected).
buildPayload: () => {
const settings = nwcSettings?.getActiveNwcSettings?.() || {};
const nwcUri = typeof settings.nwcUri === "string" ? settings.nwcUri.trim() : "";
if (!nwcUri) {
return null;
}
const payload = { nwcUri };
if (settings.defaultZap !== undefined) {
payload.defaultZap = settings.defaultZap;
}
return payload;
},
applyPayload: async (pubkey, payload) => {
const nwcUri = typeof payload.nwcUri === "string" ? payload.nwcUri.trim() : "";
if (!nwcUri) {
return { imported: false, error: "empty-payload" };
}
const partial = { nwcUri };
if (payload.defaultZap !== undefined) {
partial.defaultZap = payload.defaultZap;
}
await nwcSettings.updateActiveNwcSettings(partial);
},
});
return { WALLET_SYNC_DTAG, ...item };
}
export default createWalletSyncService;