mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-10-27 16:02:26 +00:00
328 lines
9.5 KiB
JavaScript
328 lines
9.5 KiB
JavaScript
import {
|
|
loadNwcSettings,
|
|
saveNwcSettings,
|
|
clearNwcSettings,
|
|
createDefaultNwcSettings,
|
|
} from "../nwcSettings.js";
|
|
import { MAX_WALLET_DEFAULT_ZAP } from "../config.js";
|
|
import { devLogger, userLogger } from "../utils/logger.js";
|
|
import createProfileSettingsStore from "../state/profileSettingsStore.js";
|
|
|
|
const NWC_URI_SCHEME = "nostr+walletconnect://";
|
|
|
|
function isFunction(value) {
|
|
return typeof value === "function";
|
|
}
|
|
|
|
export default class NwcSettingsService {
|
|
constructor({
|
|
normalizeHexPubkey,
|
|
getActivePubkey,
|
|
payments = null,
|
|
logger = { dev: devLogger, user: userLogger },
|
|
notifyError,
|
|
maxWalletDefaultZap = MAX_WALLET_DEFAULT_ZAP,
|
|
loadSettings = loadNwcSettings,
|
|
saveSettings = saveNwcSettings,
|
|
clearSettings = clearNwcSettings,
|
|
createDefaultSettings = createDefaultNwcSettings,
|
|
} = {}) {
|
|
this.normalizeHexPubkey = isFunction(normalizeHexPubkey)
|
|
? normalizeHexPubkey
|
|
: (value) => (typeof value === "string" ? value.trim() : null);
|
|
this.getActivePubkey = isFunction(getActivePubkey)
|
|
? getActivePubkey
|
|
: () => null;
|
|
this.payments = payments || null;
|
|
const devChannel = logger?.dev && typeof logger.dev.warn === "function" ? logger.dev : devLogger;
|
|
const userChannel = logger?.user && typeof logger.user.warn === "function" ? logger.user : userLogger;
|
|
this.logger = { dev: devChannel, user: userChannel };
|
|
this.notifyError = isFunction(notifyError) ? notifyError : null;
|
|
this.maxWalletDefaultZap =
|
|
Number.isFinite(maxWalletDefaultZap) && maxWalletDefaultZap > 0
|
|
? maxWalletDefaultZap
|
|
: MAX_WALLET_DEFAULT_ZAP;
|
|
this.loadSettings = isFunction(loadSettings)
|
|
? loadSettings
|
|
: loadNwcSettings;
|
|
this.saveSettings = isFunction(saveSettings)
|
|
? saveSettings
|
|
: saveNwcSettings;
|
|
this.clearSettings = isFunction(clearSettings)
|
|
? clearSettings
|
|
: clearNwcSettings;
|
|
this.createDefaultSettings = isFunction(createDefaultSettings)
|
|
? createDefaultSettings
|
|
: () => createDefaultNwcSettings();
|
|
this.cache = createProfileSettingsStore({
|
|
clone: (value) => this.cloneSettings(value),
|
|
logger: this.logger.dev,
|
|
});
|
|
}
|
|
|
|
cloneSettings(settings) {
|
|
if (!settings || typeof settings !== "object") {
|
|
return this.createDefaultNwcSettings();
|
|
}
|
|
return { ...settings };
|
|
}
|
|
|
|
setPayments(payments) {
|
|
this.payments = payments || null;
|
|
}
|
|
|
|
setActivePubkeyGetter(fn) {
|
|
if (isFunction(fn)) {
|
|
this.getActivePubkey = fn;
|
|
}
|
|
}
|
|
|
|
clearCache() {
|
|
this.cache.clear();
|
|
}
|
|
|
|
getNormalizedPubkey(pubkey) {
|
|
try {
|
|
return this.normalizeHexPubkey(pubkey);
|
|
} catch (error) {
|
|
if (isFunction(this.logger.user?.warn)) {
|
|
this.logger.user.warn("[nwcSettings] Failed to normalize pubkey:", error);
|
|
}
|
|
return null;
|
|
}
|
|
}
|
|
|
|
async hydrateNwcSettingsForPubkey(pubkey) {
|
|
const normalized = this.getNormalizedPubkey(pubkey);
|
|
if (!normalized) {
|
|
return this.createDefaultNwcSettings();
|
|
}
|
|
|
|
try {
|
|
const settings = await this.loadSettings(normalized);
|
|
const record =
|
|
settings && typeof settings === "object"
|
|
? { ...settings }
|
|
: this.createDefaultNwcSettings();
|
|
this.cache.set(normalized, record);
|
|
const cached = this.cache.get(normalized);
|
|
return cached || this.createDefaultNwcSettings();
|
|
} catch (error) {
|
|
if (isFunction(this.logger.user?.warn)) {
|
|
this.logger.user.warn(
|
|
`[nwcSettings] Failed to load settings for ${normalized}:`,
|
|
error,
|
|
);
|
|
}
|
|
const fallback = this.createDefaultNwcSettings();
|
|
this.cache.set(normalized, fallback);
|
|
const cached = this.cache.get(normalized);
|
|
return cached || this.createDefaultNwcSettings();
|
|
}
|
|
}
|
|
|
|
getActiveNwcSettings() {
|
|
const normalized = this.getNormalizedPubkey(this.getActivePubkey());
|
|
if (!normalized) {
|
|
return this.createDefaultNwcSettings();
|
|
}
|
|
const cached = this.cache.get(normalized);
|
|
return cached ? cached : this.createDefaultNwcSettings();
|
|
}
|
|
|
|
createDefaultNwcSettings() {
|
|
return this.createDefaultSettings();
|
|
}
|
|
|
|
hasActiveWalletConnection() {
|
|
const settings = this.getActiveNwcSettings();
|
|
const candidate =
|
|
typeof settings?.nwcUri === "string" ? settings.nwcUri.trim() : "";
|
|
return candidate.length > 0;
|
|
}
|
|
|
|
validateWalletUri(uri, { requireValue = false } = {}) {
|
|
const value = typeof uri === "string" ? uri.trim() : "";
|
|
|
|
if (!value) {
|
|
if (requireValue) {
|
|
return {
|
|
valid: false,
|
|
sanitized: "",
|
|
message: "Enter a wallet connect URI before continuing.",
|
|
};
|
|
}
|
|
return { valid: true, sanitized: "" };
|
|
}
|
|
|
|
if (!value.toLowerCase().startsWith(NWC_URI_SCHEME)) {
|
|
return {
|
|
valid: false,
|
|
sanitized: value,
|
|
message: `Wallet URI must start with ${NWC_URI_SCHEME}.`,
|
|
};
|
|
}
|
|
|
|
return { valid: true, sanitized: value };
|
|
}
|
|
|
|
async updateActiveNwcSettings(partial = {}) {
|
|
const normalized = this.getNormalizedPubkey(this.getActivePubkey());
|
|
if (!normalized) {
|
|
if (isFunction(this.logger.user?.warn)) {
|
|
this.logger.user.warn(
|
|
"[nwcSettings] Cannot update settings without an active pubkey.",
|
|
);
|
|
}
|
|
return this.createDefaultNwcSettings();
|
|
}
|
|
|
|
try {
|
|
const updated = await this.saveSettings(normalized, partial);
|
|
const record =
|
|
updated && typeof updated === "object"
|
|
? { ...updated }
|
|
: this.createDefaultNwcSettings();
|
|
this.cache.set(normalized, record);
|
|
const cached = this.cache.get(normalized);
|
|
return cached || this.createDefaultNwcSettings();
|
|
} catch (error) {
|
|
if (isFunction(this.logger.user?.warn)) {
|
|
this.logger.user.warn(
|
|
`[nwcSettings] Failed to save settings for ${normalized}:`,
|
|
error,
|
|
);
|
|
}
|
|
return this.getActiveNwcSettings();
|
|
}
|
|
}
|
|
|
|
async handleProfileWalletPersist({
|
|
nwcUri,
|
|
defaultZap,
|
|
lastChecked,
|
|
} = {}) {
|
|
const partial = {};
|
|
if (nwcUri !== undefined) {
|
|
partial.nwcUri = nwcUri;
|
|
}
|
|
if (defaultZap !== undefined) {
|
|
partial.defaultZap = defaultZap;
|
|
}
|
|
if (lastChecked !== undefined) {
|
|
partial.lastChecked = lastChecked;
|
|
}
|
|
|
|
if (!Object.keys(partial).length) {
|
|
return this.getActiveNwcSettings();
|
|
}
|
|
|
|
return this.updateActiveNwcSettings(partial);
|
|
}
|
|
|
|
async ensureWallet({ nwcUri, defaultZap } = {}) {
|
|
const activeSettings = this.getActiveNwcSettings();
|
|
const candidateUri =
|
|
typeof nwcUri === "string" && nwcUri.trim()
|
|
? nwcUri.trim()
|
|
: activeSettings.nwcUri || "";
|
|
const { valid, sanitized, message } = this.validateWalletUri(candidateUri, {
|
|
requireValue: true,
|
|
});
|
|
if (!valid) {
|
|
throw new Error(message || "Invalid wallet URI provided.");
|
|
}
|
|
|
|
const merged = {
|
|
...activeSettings,
|
|
nwcUri: sanitized,
|
|
};
|
|
|
|
if (typeof defaultZap === "number" && Number.isFinite(defaultZap)) {
|
|
const rounded = Math.max(0, Math.round(defaultZap));
|
|
merged.defaultZap = Math.min(this.maxWalletDefaultZap, rounded);
|
|
} else if (defaultZap === null) {
|
|
merged.defaultZap = null;
|
|
}
|
|
|
|
if (this.payments && isFunction(this.payments.ensureWallet)) {
|
|
return this.payments.ensureWallet({ settings: merged });
|
|
}
|
|
|
|
if (isFunction(this.logger.dev?.warn)) {
|
|
this.logger.dev.warn(
|
|
"[wallet] Falling back to stub ensureWallet implementation. Returning settings without performing a connection test.",
|
|
);
|
|
}
|
|
return merged;
|
|
}
|
|
|
|
async clearStoredNwcSettings(pubkey, { silent = false } = {}) {
|
|
const normalized = this.getNormalizedPubkey(pubkey);
|
|
if (!normalized) {
|
|
return false;
|
|
}
|
|
|
|
try {
|
|
await this.clearSettings(normalized);
|
|
} catch (error) {
|
|
if (isFunction(this.logger.user?.warn)) {
|
|
this.logger.user.warn(
|
|
`[nwcSettings] Failed to clear settings for ${normalized}:`,
|
|
error,
|
|
);
|
|
}
|
|
if (!silent && this.notifyError) {
|
|
this.notifyError("Failed to clear wallet settings for this account.");
|
|
}
|
|
try {
|
|
await this.saveSettings(normalized, this.createDefaultNwcSettings());
|
|
} catch (persistError) {
|
|
if (isFunction(this.logger.user?.warn)) {
|
|
this.logger.user.warn(
|
|
`[nwcSettings] Failed to overwrite settings for ${normalized}:`,
|
|
persistError,
|
|
);
|
|
}
|
|
}
|
|
this.cache.delete(normalized);
|
|
return false;
|
|
}
|
|
|
|
this.cache.delete(normalized);
|
|
return true;
|
|
}
|
|
|
|
async onLogin({ pubkey, previousPubkey, identityChanged } = {}) {
|
|
if (identityChanged) {
|
|
this.onIdentityChanged();
|
|
}
|
|
|
|
const normalizedActive = this.getNormalizedPubkey(
|
|
pubkey !== undefined ? pubkey : this.getActivePubkey(),
|
|
);
|
|
|
|
if (normalizedActive) {
|
|
await this.hydrateNwcSettingsForPubkey(normalizedActive);
|
|
}
|
|
|
|
return this.getActiveNwcSettings();
|
|
}
|
|
|
|
async onLogout({ pubkey, previousPubkey } = {}) {
|
|
const normalizedPrevious = this.getNormalizedPubkey(
|
|
previousPubkey !== undefined ? previousPubkey : pubkey,
|
|
);
|
|
if (normalizedPrevious) {
|
|
this.cache.delete(normalizedPrevious);
|
|
}
|
|
return this.createDefaultNwcSettings();
|
|
}
|
|
|
|
onIdentityChanged() {
|
|
// Intentionally preserve cached settings so profile switches retain
|
|
// per-account configuration. Explicit cache clearing remains
|
|
// available via `clearCache()` when required by callers.
|
|
}
|
|
}
|