diff --git a/js/accessControl.js b/js/accessControl.js index c3a74b54..ce883de2 100644 --- a/js/accessControl.js +++ b/js/accessControl.js @@ -8,6 +8,7 @@ import { ADMIN_WHITELIST_MODE_STORAGE_KEY, } from "./config.js"; import { loadAdminState, persistAdminState } from "./adminListStore.js"; +import { userLogger } from "./utils/logger.js"; function normalizeNpub(value) { return typeof value === "string" ? value.trim() : ""; @@ -126,7 +127,7 @@ class AccessControl { const operation = this._performRefresh(); const tracked = operation.catch((error) => { - console.error("Failed to refresh admin lists:", error); + userLogger.error("Failed to refresh admin lists:", error); throw error; }); this._refreshPromise = tracked; diff --git a/js/adminListStore.js b/js/adminListStore.js index f46ff07f..5d82cffc 100644 --- a/js/adminListStore.js +++ b/js/adminListStore.js @@ -9,6 +9,7 @@ import { } from "./config.js"; import { nostrClient } from "./nostr.js"; import { +import { devLogger, userLogger } from "./utils/logger.js"; buildAdminListEvent, ADMIN_LIST_IDENTIFIERS, } from "./nostrEventSchemas.js"; @@ -150,8 +151,7 @@ function readJsonListFromStorage(key) { const parsed = JSON.parse(raw); return Array.isArray(parsed) ? parsed : null; } catch (error) { - if (isDevMode) { - console.warn(`[adminListStore] Failed to parse legacy list for ${key}:`, error); + devLogger.warn(`[adminListStore] Failed to parse legacy list for ${key:`, error); } return null; } @@ -198,8 +198,7 @@ function clearLegacyStorageFor(listKey) { try { localStorage.removeItem(key); } catch (error) { - if (isDevMode) { - console.warn(`[adminListStore] Failed to clear legacy storage for ${key}:`, error); + devLogger.warn(`[adminListStore] Failed to clear legacy storage for ${key:`, error); } } } @@ -244,9 +243,7 @@ function encodeHexToNpub(hex) { try { return window?.NostrTools?.nip19?.npubEncode(hex) || ""; } catch (error) { - if (isDevMode) { - console.warn("Failed to encode hex pubkey to npub:", error); - } + devLogger.warn("Failed to encode hex pubkey to npub:", error); return ""; } } @@ -333,12 +330,10 @@ async function loadNostrList(identifier) { events = combined; } } catch (error) { - if (isDevMode) { - console.warn( - `[adminListStore] Combined relay fetch failed for ${identifier}:`, - error - ); - } + devLogger.warn( + `[adminListStore] Combined relay fetch failed for ${identifier}:`, + error + ); } if (!events.length) { @@ -348,12 +343,10 @@ async function loadNostrList(identifier) { const result = await nostrClient.pool.list([url], [filter]); return Array.isArray(result) ? result : []; } catch (error) { - if (isDevMode) { - console.warn( - `[adminListStore] Relay fetch failed for ${identifier} on ${url}:`, - error - ); - } + devLogger.warn( + `[adminListStore] Relay fetch failed for ${identifier} on ${url}:`, + error + ); return []; } }) @@ -394,12 +387,10 @@ function buildListEvent(listKey, npubs, actorHex) { try { return decodeNpubToHex(npub); } catch (error) { - if (isDevMode) { - console.warn( - `[adminListStore] Failed to decode npub while publishing ${listKey}:`, - error - ); - } + devLogger.warn( + `[adminListStore] Failed to decode npub while publishing ${listKey}:`, + error + ); return ""; } }).filter((hex) => !!hex)) @@ -412,9 +403,7 @@ function buildListEvent(listKey, npubs, actorHex) { hexPubkeys.push(superHex); } } catch (error) { - if (isDevMode) { - console.warn("Failed to ensure super admin presence:", error); - } + devLogger.warn("Failed to ensure super admin presence:", error); } } @@ -457,12 +446,10 @@ function publishToRelay(url, signedEvent, listKey) { pub.on(eventName, handler); return true; } catch (error) { - if (isDevMode) { - console.warn( - `[adminListStore] Relay publish rejected ${eventName} listener:`, - error - ); - } + devLogger.warn( + `[adminListStore] Relay publish rejected ${eventName} listener:`, + error + ); return false; } }; @@ -500,7 +487,7 @@ function publishToRelay(url, signedEvent, listKey) { finalize(true); }).then((result) => { if (!result.success && isDevMode) { - console.warn( + userLogger.warn( `[adminListStore] Publish failed for ${listKey} on ${result.url}:`, result.error ); @@ -605,7 +592,7 @@ async function persistNostrState(actorNpub, updates = {}) { export async function loadAdminState() { if (ADMIN_LIST_MODE !== "nostr" && isDevMode) { - console.warn( + userLogger.warn( `[adminListStore] ADMIN_LIST_MODE "${ADMIN_LIST_MODE}" is deprecated. Defaulting to remote Nostr lists.` ); } @@ -614,7 +601,7 @@ export async function loadAdminState() { if (!hasAnyEntries(state)) { const legacy = loadLegacyAdminState(); if (legacy && isDevMode) { - console.warn( + userLogger.warn( "[adminListStore] Ignoring legacy admin lists because remote mode is enforced. Publish them to Nostr to retain access.", legacy ); @@ -626,7 +613,7 @@ export async function loadAdminState() { export async function persistAdminState(actorNpub, updates) { if (ADMIN_LIST_MODE !== "nostr" && isDevMode) { - console.warn( + userLogger.warn( `[adminListStore] ADMIN_LIST_MODE "${ADMIN_LIST_MODE}" is deprecated. Remote lists are enforced.` ); } diff --git a/js/analytics.js b/js/analytics.js index bdab3ef8..c4038f95 100644 --- a/js/analytics.js +++ b/js/analytics.js @@ -1,5 +1,6 @@ // js/analytics.js import { ANALYTICS_CONFIG } from "./analyticsConfig.js"; +import { userLogger } from "./utils/logger.js"; const SCRIPT_ATTR = "data-bitvid-analytics"; const SCRIPT_IDENTIFIER = "umami"; @@ -30,7 +31,7 @@ function flushPendingCalls() { try { fn.apply(umami, args); } catch (err) { - console.warn("[analytics] Failed to call", method, err); + userLogger.warn("[analytics] Failed to call", method, err); } } } @@ -103,7 +104,7 @@ function invokeUmami(method, args) { try { umami[method].apply(umami, args); } catch (err) { - console.warn("[analytics] Failed to call", method, err); + userLogger.warn("[analytics] Failed to call", method, err); } return; } diff --git a/js/blog/carousel.js b/js/blog/carousel.js index 0b1f22d4..675f72b5 100644 --- a/js/blog/carousel.js +++ b/js/blog/carousel.js @@ -1,3 +1,4 @@ +import { userLogger } from "../utils/logger.js"; function toArray(value) { if (!value) { return []; @@ -196,7 +197,7 @@ export function destroyCarousel(state) { try { dispose(); } catch (error) { - console.warn('Failed to dispose carousel listener', error); + userLogger.warn('Failed to dispose carousel listener', error); } }); state.cleanup = []; diff --git a/js/blog/index.js b/js/blog/index.js index 0fffd772..b595ab30 100644 --- a/js/blog/index.js +++ b/js/blog/index.js @@ -1,6 +1,7 @@ import { createCarousel, advanceSlide, destroyCarousel } from './carousel.js'; import { mountProgressBar } from './progressBar.js'; import { initZapthreadsEmbed as defaultInitZapthreadsEmbed } from './zapthreadsEmbed.js'; +import { userLogger } from "../utils/logger.js"; const CAROUSEL_AUTOPLAY_INTERVAL = 8000; @@ -499,7 +500,7 @@ function initializeZapthreads({ registerCleanup, isDestroyed, initZapthreadsEmbe try { dispose(); } catch (error) { - console.error('[blog] zapthreads cleanup failed', error); + userLogger.error('[blog] zapthreads cleanup failed', error); } return; } @@ -507,12 +508,12 @@ function initializeZapthreads({ registerCleanup, isDestroyed, initZapthreadsEmbe try { dispose(); } catch (error) { - console.error('[blog] zapthreads cleanup failed', error); + userLogger.error('[blog] zapthreads cleanup failed', error); } }); }) .catch((error) => { - console.error('[blog] failed to initialise zapthreads embed', error); + userLogger.error('[blog] failed to initialise zapthreads embed', error); }); return; } @@ -522,7 +523,7 @@ function initializeZapthreads({ registerCleanup, isDestroyed, initZapthreadsEmbe try { maybeDispose(); } catch (error) { - console.error('[blog] zapthreads cleanup failed', error); + userLogger.error('[blog] zapthreads cleanup failed', error); } return; } @@ -530,12 +531,12 @@ function initializeZapthreads({ registerCleanup, isDestroyed, initZapthreadsEmbe try { maybeDispose(); } catch (error) { - console.error('[blog] zapthreads cleanup failed', error); + userLogger.error('[blog] zapthreads cleanup failed', error); } }); } } catch (error) { - console.error('[blog] failed to start zapthreads embed', error); + userLogger.error('[blog] failed to start zapthreads embed', error); } }); } @@ -555,7 +556,7 @@ function mountBlogApp({ initZapthreadsEmbed = defaultInitZapthreadsEmbed } = {}) try { callback(); } catch (error) { - console.error('[blog] cleanup callback failed', error); + userLogger.error('[blog] cleanup callback failed', error); } return () => {}; } @@ -574,7 +575,7 @@ function mountBlogApp({ initZapthreadsEmbed = defaultInitZapthreadsEmbed } = {}) try { callback(); } catch (error) { - console.error('[blog] cleanup callback failed', error); + userLogger.error('[blog] cleanup callback failed', error); } }); runtime.cleanupCallbacks.clear(); diff --git a/js/blog/zapthreadsEmbed.js b/js/blog/zapthreadsEmbed.js index 47722ace..e8ae9397 100644 --- a/js/blog/zapthreadsEmbed.js +++ b/js/blog/zapthreadsEmbed.js @@ -1,4 +1,5 @@ import { escapeHTML } from '../utils/domUtils.js'; +import { userLogger } from "../utils/logger.js"; /** * Responsibilities mirrored from the legacy DS component that ships inside @@ -492,7 +493,7 @@ export function parseRelayList(relayList = '') { try { relays.push(new URL(trimmed).toString()); } catch (error) { - console.warn('[zapthreads] ignored invalid relay input', trimmed, error); + userLogger.warn('[zapthreads] ignored invalid relay input', trimmed, error); } } @@ -1161,7 +1162,7 @@ export async function initZapthreadsEmbed({ try { callback(); } catch (error) { - console.error('[zapthreads] cleanup failed', error); + userLogger.error('[zapthreads] cleanup failed', error); } }); disposeCallbacks.clear(); @@ -1194,7 +1195,7 @@ export async function initZapthreadsEmbed({ try { currentSubscription.close(); } catch (error) { - console.error('[zapthreads] failed to close subscription', error); + userLogger.error('[zapthreads] failed to close subscription', error); } } currentSubscription = null; @@ -1276,7 +1277,7 @@ export async function initZapthreadsEmbed({ try { callback(); } catch (error) { - console.error('[zapthreads] cleanup failed', error); + userLogger.error('[zapthreads] cleanup failed', error); } }); disposeCallbacks.clear(); diff --git a/js/channelProfile.js b/js/channelProfile.js index 76f15bfc..f2b2ec4f 100644 --- a/js/channelProfile.js +++ b/js/channelProfile.js @@ -41,6 +41,7 @@ import { } from "./payments/lnurl.js"; import { getPlatformLightningAddress } from "./payments/platformAddress.js"; import { +import { userLogger } from "./utils/logger.js"; ensureWallet, sendPayment as sendWalletPayment } from "./payments/nwcClient.js"; @@ -109,7 +110,7 @@ function logZapError(stage, details = {}, error) { ? details.retryAttempt : undefined }; - console.error("[zap] Channel zap failure", summary, error); + userLogger.error("[zap] Channel zap failure", summary, error); } let currentChannelProfileEvent = null; @@ -1289,7 +1290,7 @@ function buildChannelShareUrl() { url.hash = `#view=channel-profile&npub=${currentChannelNpub}`; return url.toString(); } catch (error) { - console.warn("Falling back to basic channel share URL:", error); + userLogger.warn("Falling back to basic channel share URL:", error); const origin = window.location?.origin || ""; const pathname = window.location?.pathname || ""; if (!origin && !pathname) { @@ -1361,7 +1362,7 @@ async function updateChannelMenuState() { try { await accessControl.ensureReady(); } catch (error) { - console.warn("Failed to refresh moderation lists for channel menu:", error); + userLogger.warn("Failed to refresh moderation lists for channel menu:", error); } const canBlacklist = @@ -1431,7 +1432,7 @@ export async function initChannelProfileView() { const hashParams = new URLSearchParams(window.location.hash.slice(1)); const npub = hashParams.get("npub"); if (!npub) { - console.error( + userLogger.error( "No npub found in hash (e.g. #view=channel-profile&npub=...)" ); return; @@ -1456,7 +1457,7 @@ export async function initChannelProfileView() { throw new Error("Invalid npub decoding result."); } } catch (err) { - console.error("Error decoding npub:", err); + userLogger.error("Error decoding npub:", err); return; } @@ -1469,7 +1470,7 @@ export async function initChannelProfileView() { setupChannelMoreMenu(); const initialMenuRefresh = updateChannelMenuState().catch((error) => { - console.error("Failed to prepare channel menu state:", error); + userLogger.error("Failed to prepare channel menu state:", error); }); let subscriptionsTask = null; @@ -1478,7 +1479,7 @@ export async function initChannelProfileView() { subscriptionsTask = subscriptions .loadSubscriptions(app.pubkey) .catch((error) => { - console.error("Failed to load subscriptions for channel view:", error); + userLogger.error("Failed to load subscriptions for channel view:", error); }) .finally(() => { renderSubscribeButton(hexPub); @@ -1495,14 +1496,14 @@ export async function initChannelProfileView() { const profilePromise = loadUserProfile(hexPub) .then(() => updateChannelMenuState()) .catch((error) => { - console.error("Failed to load channel profile:", error); + userLogger.error("Failed to load channel profile:", error); }) .finally(() => { syncChannelShareButtonState(); }); const videosPromise = loadUserVideos(hexPub).catch((error) => { - console.error("Failed to load channel videos:", error); + userLogger.error("Failed to load channel videos:", error); }); const pendingTasks = [profilePromise, videosPromise]; @@ -1609,7 +1610,7 @@ function renderSubscribeButton(channelHex) { if (toggleBtn) { toggleBtn.addEventListener("click", async () => { if (!app?.pubkey) { - console.error("Not logged in => cannot subscribe/unsubscribe."); + userLogger.error("Not logged in => cannot subscribe/unsubscribe."); return; } try { @@ -1621,7 +1622,7 @@ function renderSubscribeButton(channelHex) { // Re-render the button so it toggles state renderSubscribeButton(channelHex); } catch (err) { - console.error("Failed to update subscription:", err); + userLogger.error("Failed to update subscription:", err); } }); } @@ -1905,7 +1906,7 @@ function renderChannelVideosFromList({ description: detail.video?.description }) ).catch((error) => { - console.error("Failed to play channel video via event id:", error); + userLogger.error("Failed to play channel video via event id:", error); if (typeof app?.playVideoWithFallback === "function") { app.playVideoWithFallback({ url: detail.url, @@ -1920,7 +1921,7 @@ function renderChannelVideosFromList({ Promise.resolve( app.playVideoWithFallback({ url: detail.url, magnet: detail.magnet }) ).catch((error) => { - console.error( + userLogger.error( "Failed to start fallback playback for channel video:", error ); @@ -2235,7 +2236,7 @@ async function fetchChannelProfileFromRelays(pubkey) { try { await nostrClient.ensurePool(); } catch (error) { - console.error("Failed to initialize relay pool for channel profile:", error); + userLogger.error("Failed to initialize relay pool for channel profile:", error); return { event: null, profile: {} }; } @@ -2271,7 +2272,7 @@ async function fetchChannelProfileFromRelays(pubkey) { const meta = JSON.parse(newestEvent.content); return { event: newestEvent, profile: meta }; } catch (error) { - console.warn("Failed to parse channel metadata payload:", error); + userLogger.warn("Failed to parse channel metadata payload:", error); return { event: newestEvent, profile: {} }; } } @@ -2343,7 +2344,7 @@ async function loadUserProfile(pubkey) { "" }); } catch (error) { - console.warn( + userLogger.warn( "Failed to persist channel profile metadata to cache:", error ); @@ -2359,7 +2360,7 @@ async function loadUserProfile(pubkey) { }); } catch (error) { if (loadToken === currentProfileLoadToken) { - console.error("Failed to fetch user profile data:", error); + userLogger.error("Failed to fetch user profile data:", error); const lnEl = document.getElementById("channelLightning"); if (lnEl && !currentChannelLightningAddress) { lnEl.textContent = "No lightning address found."; @@ -2416,7 +2417,7 @@ async function loadUserVideos(pubkey) { } const ensureAccessPromise = accessControl.ensureReady().catch((error) => { - console.warn( + userLogger.warn( "Failed to ensure admin lists were loaded before channel fetch:", error ); @@ -2448,7 +2449,7 @@ async function loadUserVideos(pubkey) { events.push(...fallbackEvents); } } catch (error) { - console.error("Relay error (default pool):", error); + userLogger.error("Relay error (default pool):", error); } } else { const relayPromises = relayList.map((url) => @@ -2466,7 +2467,7 @@ async function loadUserVideos(pubkey) { } if (result.reason) { - console.error(`Relay error (${relayUrl}):`, result.reason); + userLogger.error(`Relay error (${relayUrl}):`, result.reason); } }); } @@ -2478,7 +2479,7 @@ async function loadUserVideos(pubkey) { } if (!container) { - console.warn("channelVideoList element not found in DOM."); + userLogger.warn("channelVideoList element not found in DOM."); return; } @@ -2503,7 +2504,7 @@ async function loadUserVideos(pubkey) {
Failed to load videos. Please try again.
`; } - console.error("Error loading user videos:", err); + userLogger.error("Error loading user videos:", err); } finally { await ensureAccessPromise; if (loadToken === currentVideoLoadToken && container) { @@ -2528,7 +2529,7 @@ window.addEventListener("bitvid:access-control-updated", () => { } loadUserVideos(currentChannelHex).catch((error) => { - console.error( + userLogger.error( "Failed to refresh channel videos after admin update:", error ); diff --git a/js/config.js b/js/config.js index 24bd0019..5f4e89a9 100644 --- a/js/config.js +++ b/js/config.js @@ -1,6 +1,7 @@ // js/config.js import { +import { userLogger } from "./utils/logger.js"; IS_DEV_MODE, ADMIN_SUPER_NPUB, ADMIN_DM_IMAGE_URL, @@ -61,7 +62,7 @@ export function getWhitelistMode() { } return raw === "true"; } catch (error) { - console.warn("Failed to read whitelist mode from storage:", error); + userLogger.warn("Failed to read whitelist mode from storage:", error); return DEFAULT_WHITELIST_ENABLED; } } @@ -70,7 +71,7 @@ export function setWhitelistMode(enabled) { try { localStorage.setItem(WHITELIST_MODE_KEY, enabled ? "true" : "false"); } catch (error) { - console.warn("Failed to persist whitelist mode to storage:", error); + userLogger.warn("Failed to persist whitelist mode to storage:", error); } } diff --git a/js/designSystem.js b/js/designSystem.js index 06d7d7d4..ab171cc5 100644 --- a/js/designSystem.js +++ b/js/designSystem.js @@ -1,3 +1,4 @@ +import { userLogger } from "./utils/logger.js"; const NEW_MODE = "new"; const FALLBACK_CONTEXT = Object.freeze({ @@ -87,9 +88,7 @@ export function applyDesignSystemAttributes(root = null) { try { element.setAttribute("data-ds", mode); } catch (error) { - if (typeof console !== "undefined" && console && console.warn) { - console.warn("[design-system] Failed to set data-ds attribute:", error); - } + userLogger.warn("[design-system] Failed to set data-ds attribute:", error); } }); diff --git a/js/dom/cardObserver.js b/js/dom/cardObserver.js index a8507a98..4272ded0 100644 --- a/js/dom/cardObserver.js +++ b/js/dom/cardObserver.js @@ -1,3 +1,4 @@ +import { userLogger } from "../utils/logger.js"; const DEFAULT_CARD_SELECTOR = ".card[data-video-id]"; function defaultIsCardVisible(entry) { @@ -78,7 +79,7 @@ export function createCardObserver(options = {}) { return prepared; } } catch (err) { - console.warn("[cardObserver] prepareEntries failed", err); + userLogger.warn("[cardObserver] prepareEntries failed", err); } } @@ -122,7 +123,7 @@ export function createCardObserver(options = {}) { state: state.customState, })); } catch (err) { - console.warn("[cardObserver] isCardVisible failed", err); + userLogger.warn("[cardObserver] isCardVisible failed", err); visible = false; } @@ -142,7 +143,7 @@ export function createCardObserver(options = {}) { }, }); } catch (err) { - console.warn("[cardObserver] onCardVisible failed", err); + userLogger.warn("[cardObserver] onCardVisible failed", err); } }); } @@ -170,7 +171,7 @@ export function createCardObserver(options = {}) { context: { container }, }); } catch (err) { - console.warn("[cardObserver] onCardRegister failed", err); + userLogger.warn("[cardObserver] onCardRegister failed", err); } } state.observer.observe(card); diff --git a/js/feedEngine/engine.js b/js/feedEngine/engine.js index 95b4cbdd..0652a313 100644 --- a/js/feedEngine/engine.js +++ b/js/feedEngine/engine.js @@ -1,6 +1,7 @@ // js/feedEngine/engine.js import { isPlainObject } from "./utils.js"; +import { userLogger } from "../utils/logger.js"; const DEFAULT_FEED_CONFIG = Object.freeze({ timeWindow: null, @@ -93,7 +94,7 @@ function createExecutionContext(entry, { config, hooks, runtime, logger }) { try { resolvedLogger(`[feed:${entry.name}]`, ...args); } catch (error) { - console.warn(`[feed:${entry.name}] logger threw`, error); + userLogger.warn(`[feed:${entry.name}] logger threw`, error); } }, addWhy: (detail) => { diff --git a/js/gridHealth.js b/js/gridHealth.js index 1dba3761..20ce8d87 100644 --- a/js/gridHealth.js +++ b/js/gridHealth.js @@ -2,6 +2,7 @@ import { createCardObserver } from "./dom/cardObserver.js"; import { infoHashFromMagnet } from "./magnets.js"; import { updateVideoCardSourceVisibility } from "./utils/cardSourceVisibility.js"; import { TorrentClient, torrentClient } from "./webtorrent.js"; +import { userLogger } from "./utils/logger.js"; const badgeUpdateListeners = new Set(); @@ -17,7 +18,7 @@ function notifyBadgeUpdate(payload) { try { listener(payload); } catch (err) { - console.warn("[gridHealth] badge listener failed", err); + userLogger.warn("[gridHealth] badge listener failed", err); } }); } @@ -581,7 +582,7 @@ function handleCardVisible({ card, pendingByCard, priority = 0 }) { setBadge(card, "unhealthy", result); }) .catch((err) => { - console.warn("[gridHealth] probe failed", err); + userLogger.warn("[gridHealth] probe failed", err); pendingByCard.delete(card); if (!card.isConnected) { return; diff --git a/js/healthService.js b/js/healthService.js index de265bab..8e8a0f4b 100644 --- a/js/healthService.js +++ b/js/healthService.js @@ -2,6 +2,7 @@ import PQueue from "https://esm.sh/p-queue@7.4.1"; import { trackerPing } from "./trackerPing.js"; import { infoHashFromMagnet } from "./magnets.js"; import { HEALTH_TTL_MS, CONCURRENCY } from "./trackerConfig.js"; +import { userLogger } from "./utils/logger.js"; const queue = new PQueue({ concurrency: CONCURRENCY }); const cache = new Map(); @@ -72,7 +73,7 @@ export function queueHealthCheck(magnet, onResult) { setHealthCache(infoHash, health); return health; } catch (err) { - console.warn("trackerPing failed", err); + userLogger.warn("trackerPing failed", err); return getDefaultHealth(); } }) diff --git a/js/historyView.js b/js/historyView.js index 3fd47a9b..3b44f425 100644 --- a/js/historyView.js +++ b/js/historyView.js @@ -12,6 +12,7 @@ import { WATCH_HISTORY_BATCH_PAGE_SIZE } from "./config.js"; import { getApplication } from "./applicationContext.js"; +import { userLogger } from "./utils/logger.js"; export const WATCH_HISTORY_EMPTY_COPY = "Your watch history is empty. Watch some videos to populate this list."; @@ -53,7 +54,7 @@ function resolveElement(selector) { try { return document.querySelector(selector); } catch (error) { - console.warn("[historyView] Failed to query selector:", selector, error); + userLogger.warn("[historyView] Failed to query selector:", selector, error); return null; } } @@ -264,7 +265,7 @@ async function defaultRemoveHandler({ } } catch (error) { if (isDevEnv) { - console.warn("[historyView] Failed to update watch history list:", error); + userLogger.warn("[historyView] Failed to update watch history list:", error); } throw error; } @@ -307,7 +308,7 @@ function writePreference(key, value) { storage.setItem(key, value); } catch (error) { if (isDevEnv) { - console.warn("[historyView] Failed to persist preference:", error); + userLogger.warn("[historyView] Failed to persist preference:", error); } } } @@ -732,7 +733,7 @@ export function createWatchHistoryRenderer(config = {}) { unsubscribe(); } catch (error) { if (isDevEnv) { - console.warn( + userLogger.warn( "[historyView] Failed to unsubscribe from watch history event:", error ); @@ -1133,7 +1134,7 @@ export function createWatchHistoryRenderer(config = {}) { return result.trim(); } } catch (error) { - console.warn( + userLogger.warn( "[historyView] Failed to resolve actor via getActor:", error ); @@ -1177,7 +1178,7 @@ export function createWatchHistoryRenderer(config = {}) { watchHistoryService.getLocalMetadata(pointerKeyValue) || null; } catch (error) { if (isDevEnv) { - console.warn( + userLogger.warn( "[historyView] Failed to read stored metadata for pointer:", pointerKeyValue, error @@ -1213,7 +1214,7 @@ export function createWatchHistoryRenderer(config = {}) { }); } catch (error) { if (isDevEnv) { - console.warn( + userLogger.warn( "[historyView] Failed to persist metadata for pointer:", pointerKeyValue, error @@ -1227,7 +1228,7 @@ export function createWatchHistoryRenderer(config = {}) { watchHistoryService.removeLocalMetadata(pointerKeyValue); } catch (error) { if (isDevEnv) { - console.warn( + userLogger.warn( "[historyView] Failed to remove cached metadata for pointer:", pointerKeyValue, error @@ -1268,7 +1269,7 @@ export function createWatchHistoryRenderer(config = {}) { } catch (error) { state.isRendering = false; if (isDevEnv) { - console.warn("[historyView] Failed to hydrate batch:", error); + userLogger.warn("[historyView] Failed to hydrate batch:", error); } return; } @@ -1441,7 +1442,7 @@ export function createWatchHistoryRenderer(config = {}) { watchHistoryService.clearLocalMetadata?.(); } catch (error) { if (isDevEnv) { - console.warn( + userLogger.warn( "[historyView] Failed to clear stored metadata while resetting progress:", error ); @@ -1484,7 +1485,7 @@ export function createWatchHistoryRenderer(config = {}) { const app = getAppInstance(); app?.showError?.("Failed to publish watch history. Try again later."); if (isDevEnv) { - console.warn("[historyView] Republish failed:", error); + userLogger.warn("[historyView] Republish failed:", error); } } }; @@ -1560,7 +1561,7 @@ export function createWatchHistoryRenderer(config = {}) { } } catch (error) { if (isDevEnv) { - console.warn( + userLogger.warn( "[historyView] Failed to set metadata preference:", error ); @@ -1576,7 +1577,7 @@ export function createWatchHistoryRenderer(config = {}) { watchHistoryService.clearLocalMetadata?.(); } catch (error) { if (isDevEnv) { - console.warn( + userLogger.warn( "[historyView] Failed to clear stored metadata after disabling preference:", error ); @@ -1909,7 +1910,7 @@ export function createWatchHistoryRenderer(config = {}) { watchHistoryService.removeLocalMetadata?.(pointerKeyValue); } catch (error) { if (isDevEnv) { - console.warn( + userLogger.warn( "[historyView] Failed to drop cached metadata for pointer:", pointerKeyValue, error @@ -1948,7 +1949,7 @@ export function createWatchHistoryRenderer(config = {}) { app?.showError?.("Failed to remove from history. Reloading list."); } if (isDevEnv) { - console.warn("[historyView] Removal failed:", error); + userLogger.warn("[historyView] Removal failed:", error); } } finally { if (parentDay instanceof HTMLElement) { @@ -1959,7 +1960,7 @@ export function createWatchHistoryRenderer(config = {}) { await this.refresh({ force: true }); } catch (error) { if (isDevEnv) { - console.warn( + userLogger.warn( "[historyView] Failed to refresh watch history after removal:", error ); diff --git a/js/index.js b/js/index.js index 2d8788eb..dbf45644 100644 --- a/js/index.js +++ b/js/index.js @@ -14,6 +14,7 @@ import { refreshThemeControls, } from "./themeController.js"; import { +import { devLogger, userLogger } from "./utils/logger.js"; prepareStaticModal, openStaticModal, closeStaticModal, @@ -53,7 +54,7 @@ function startApplication() { setApplicationReady(startupPromise); startupPromise.catch((error) => { - console.error("Application failed to initialize:", error); + userLogger.error("Application failed to initialize:", error); }); return startupPromise; @@ -149,9 +150,9 @@ async function loadModal(url) { applyDesignSystemAttributes(modalContainer); refreshThemeControls(modalContainer); } - console.log(url, "loaded"); + devLogger.log(url, "loaded"); } catch (err) { - console.error(err); + userLogger.error(err); } } @@ -165,9 +166,9 @@ async function loadSidebar(url, containerId) { applyDesignSystemAttributes(container); refreshThemeControls(container); } - console.log(url, "loaded into", containerId); + devLogger.log(url, "loaded into", containerId); } catch (err) { - console.error(err); + userLogger.error(err); } } @@ -181,9 +182,9 @@ async function loadDisclaimer(url, containerId) { applyDesignSystemAttributes(container); refreshThemeControls(container); } - console.log(url, "disclaimer loaded into", containerId); + devLogger.log(url, "disclaimer loaded into", containerId); } catch (err) { - console.error(err); + userLogger.error(err); } } @@ -197,7 +198,7 @@ async function bootstrapInterface() { loadModal("components/bug-fix-form.html"), ]); - console.log("Modals loaded."); + devLogger.log("Modals loaded."); [ "loginModal", @@ -211,7 +212,7 @@ async function bootstrapInterface() { }); await loadSidebar("components/sidebar.html", "sidebarContainer"); - console.log("Sidebar loaded."); + devLogger.log("Sidebar loaded."); const sidebar = document.getElementById("sidebar"); const collapseToggle = document.getElementById("sidebarCollapseToggle"); @@ -219,7 +220,7 @@ async function bootstrapInterface() { sidebar.setAttribute("data-footer-state", "collapsed"); } if (!collapseToggle) { - console.warn("Sidebar collapse toggle not found; skipping density controls."); + userLogger.warn("Sidebar collapse toggle not found; skipping density controls."); } const mobileMenuBtn = document.getElementById("mobileMenuBtn"); @@ -241,7 +242,7 @@ async function bootstrapInterface() { } return storedValue === "true"; } catch (error) { - console.warn("Unable to read sidebar collapse state from storage:", error); + userLogger.warn("Unable to read sidebar collapse state from storage:", error); return DEFAULT_SIDEBAR_COLLAPSED; } }; @@ -253,7 +254,7 @@ async function bootstrapInterface() { collapsed ? "true" : "false", ); } catch (error) { - console.warn("Unable to persist sidebar collapse state:", error); + userLogger.warn("Unable to persist sidebar collapse state:", error); } }; @@ -469,11 +470,11 @@ async function bootstrapInterface() { sidebarModule.setupSidebarNavigation({ closeSidebar }); } } catch (error) { - console.error("Failed to set up sidebar navigation:", error); + userLogger.error("Failed to set up sidebar navigation:", error); } await loadDisclaimer("components/disclaimer.html", "modalContainer"); - console.log("Disclaimer loaded."); + devLogger.log("Disclaimer loaded."); prepareStaticModal({ id: "disclaimerModal" }); const loginNavBtn = document.getElementById("loginButton"); @@ -538,13 +539,13 @@ async function initializeInterface() { try { await bootstrapInterface(); } catch (error) { - console.error("Failed to bootstrap bitvid interface:", error); + userLogger.error("Failed to bootstrap bitvid interface:", error); } } function onDomReady() { initializeInterface().catch((error) => { - console.error("Unhandled error during bitvid initialization:", error); + userLogger.error("Unhandled error during bitvid initialization:", error); }); } @@ -676,12 +677,12 @@ function handleQueryParams() { } async function handleHashChange() { - console.log("handleHashChange called, current hash =", window.location.hash); + devLogger.log("handleHashChange called, current hash =", window.location.hash); try { await applicationReadyPromise; } catch (error) { - console.warn( + userLogger.warn( "Proceeding with hash handling despite application initialization failure:", error ); @@ -715,6 +716,6 @@ async function handleHashChange() { await initFn(); } } catch (error) { - console.error("Failed to handle hash change:", error); + userLogger.error("Failed to handle hash change:", error); } } diff --git a/js/nostr.js b/js/nostr.js index bc750244..63ad0828 100644 --- a/js/nostr.js +++ b/js/nostr.js @@ -40,6 +40,7 @@ import { assertAnyRelayAccepted, } from "./nostrPublish.js"; import { nostrToolsReady } from "./nostrToolsBootstrap.js"; +import { devLogger, userLogger } from "./utils/logger.js"; /** * The default relay set bitvid bootstraps with before loading a user's @@ -207,7 +208,7 @@ let cachedNostrTools = __nostrToolsBootstrapResult.toolkit || null; const nostrToolsBootstrapFailure = __nostrToolsBootstrapResult.failure || null; if (!cachedNostrTools && nostrToolsBootstrapFailure && isDevMode) { - console.warn( + userLogger.warn( "[nostr] nostr-tools helpers unavailable after bootstrap.", nostrToolsBootstrapFailure ); @@ -239,9 +240,7 @@ async function ensureNostrTools() { const result = await nostrToolsReadySource; rememberNostrTools(result); } catch (error) { - if (isDevMode) { - console.warn("[nostr] Failed to resolve nostr-tools helpers.", error); - } + devLogger.warn("[nostr] Failed to resolve nostr-tools helpers.", error); } if (!cachedNostrTools) { @@ -334,12 +333,10 @@ async function loadIngestLocalViewEvent() { return ingestLocalViewEventRef; } } catch (error) { - if (isDevMode) { - console.warn( - "[nostr] Failed to load view counter ingest helper:", - error - ); - } + devLogger.warn( + "[nostr] Failed to load view counter ingest helper:", + error + ); } return null; } @@ -349,14 +346,14 @@ let errorLogCount = 0; const MAX_ERROR_LOGS = 100; function logErrorOnce(message, eventContent = null) { if (errorLogCount < MAX_ERROR_LOGS) { - console.error(message); + userLogger.error(message); if (eventContent) { - console.log(`Event Content: ${eventContent}`); + devLogger.log(`Event Content: ${eventContent}`); } errorLogCount++; } if (errorLogCount === MAX_ERROR_LOGS) { - console.error( + userLogger.error( "Maximum error log limit reached. Further errors will be suppressed." ); } @@ -446,11 +443,9 @@ async function runNip07WithRetry( Math.round(timeoutMs * retryMultiplier), ); - if (isDevMode) { - console.warn( - `[nostr] ${label} taking longer than ${timeoutMs}ms. Waiting up to ${extendedTimeout}ms for extension response.`, - ); - } + devLogger.warn( + `[nostr] ${label} taking longer than ${timeoutMs}ms. Waiting up to ${extendedTimeout}ms for extension response.`, + ); return withNip07Timeout(getOrStartOperation, { timeoutMs: extendedTimeout, @@ -481,9 +476,7 @@ function withRequestTimeout(promise, timeoutMs, onTimeout, message = "Request ti try { onTimeout(); } catch (cleanupError) { - if (isDevMode) { - console.warn("[nostr] COUNT timeout cleanup failed:", cleanupError); - } + devLogger.warn("[nostr] COUNT timeout cleanup failed:", cleanupError); } } reject(new Error(message)); @@ -1285,9 +1278,7 @@ function cloneNip71Metadata(metadata) { try { return JSON.parse(JSON.stringify(metadata)); } catch (error) { - if (isDevMode) { - console.warn("[nostr] Failed to clone NIP-71 metadata", error); - } + devLogger.warn("[nostr] Failed to clone NIP-71 metadata", error); return { ...metadata }; } } @@ -1629,8 +1620,7 @@ function normalizePointerInput(pointer) { } } } catch (err) { - if (isDevMode) { - console.warn(`[nostr] Failed to decode pointer ${trimmed}:`, err); + devLogger.warn(`[nostr] Failed to decode pointer ${trimmed:`, err); } } } @@ -1748,9 +1738,7 @@ function generateViewEventEntropy() { value.toString(16).padStart(8, "0") ).join(""); } catch (error) { - if (isDevMode) { - console.warn("[nostr] Failed to gather crypto entropy for view event:", error); - } + devLogger.warn("[nostr] Failed to gather crypto entropy for view event:", error); } } @@ -1803,9 +1791,7 @@ function hasRecentViewPublish(scope, bucketIndex) { try { rawValue = localStorage.getItem(storageKey); } catch (error) { - if (isDevMode) { - console.warn("[nostr] Failed to read view guard entry:", error); - } + devLogger.warn("[nostr] Failed to read view guard entry:", error); return false; } @@ -1821,9 +1807,7 @@ function hasRecentViewPublish(scope, bucketIndex) { try { localStorage.removeItem(storageKey); } catch (error) { - if (isDevMode) { - console.warn("[nostr] Failed to clear corrupt view guard entry:", error); - } + devLogger.warn("[nostr] Failed to clear corrupt view guard entry:", error); } return false; } @@ -1832,9 +1816,7 @@ function hasRecentViewPublish(scope, bucketIndex) { try { localStorage.removeItem(storageKey); } catch (error) { - if (isDevMode) { - console.warn("[nostr] Failed to remove expired view guard entry:", error); - } + devLogger.warn("[nostr] Failed to remove expired view guard entry:", error); } return false; } @@ -1872,9 +1854,7 @@ function rememberViewPublish(scope, bucketIndex) { try { localStorage.setItem(storageKey, `${bucketIndex}:${now}`); } catch (error) { - if (isDevMode) { - console.warn("[nostr] Failed to persist view guard entry:", error); - } + devLogger.warn("[nostr] Failed to persist view guard entry:", error); } } @@ -1939,9 +1919,7 @@ function readRebroadcastGuardEntry(scope) { try { rawValue = localStorage.getItem(storageKey); } catch (error) { - if (isDevMode) { - console.warn("[nostr] Failed to read rebroadcast guard entry:", error); - } + devLogger.warn("[nostr] Failed to read rebroadcast guard entry:", error); return null; } @@ -1957,9 +1935,7 @@ function readRebroadcastGuardEntry(scope) { try { localStorage.removeItem(storageKey); } catch (error) { - if (isDevMode) { - console.warn("[nostr] Failed to clear corrupt rebroadcast guard entry:", error); - } + devLogger.warn("[nostr] Failed to clear corrupt rebroadcast guard entry:", error); } return null; } @@ -1968,9 +1944,7 @@ function readRebroadcastGuardEntry(scope) { try { localStorage.removeItem(storageKey); } catch (error) { - if (isDevMode) { - console.warn("[nostr] Failed to remove expired rebroadcast guard entry:", error); - } + devLogger.warn("[nostr] Failed to remove expired rebroadcast guard entry:", error); } return null; } @@ -2015,9 +1989,7 @@ function rememberRebroadcastAttempt(scope, bucketIndex) { try { localStorage.setItem(storageKey, `${bucketIndex}:${now}`); } catch (error) { - if (isDevMode) { - console.warn("[nostr] Failed to persist rebroadcast guard entry:", error); - } + devLogger.warn("[nostr] Failed to persist rebroadcast guard entry:", error); } } @@ -2202,9 +2174,7 @@ function parseWatchHistoryPayload(plaintext) { : 1; return { version, items, snapshot, chunkIndex, totalChunks }; } catch (error) { - if (isDevMode) { - console.warn("[nostr] Failed to parse watch history payload:", error); - } + devLogger.warn("[nostr] Failed to parse watch history payload:", error); return { version: 0, items: [], @@ -2423,9 +2393,7 @@ function sanitizeWatchHistoryMetadata(metadata) { try { return JSON.parse(JSON.stringify(metadata)); } catch (error) { - if (isDevMode) { - console.warn("[nostr] Failed to sanitize watch history metadata:", error); - } + devLogger.warn("[nostr] Failed to sanitize watch history metadata:", error); return {}; } } @@ -2530,9 +2498,7 @@ async function computeWatchHistoryFingerprintForItems(items) { const digest = await window.crypto.subtle.digest("SHA-256", data); return bytesToHex(new Uint8Array(digest)); } catch (error) { - if (isDevMode) { - console.warn("[nostr] Failed to hash watch history fingerprint:", error); - } + devLogger.warn("[nostr] Failed to hash watch history fingerprint:", error); } } @@ -2773,7 +2739,7 @@ function decodeNpubToHex(npub) { } if (isDevMode && warnableNpub) { - console.warn( + userLogger.warn( `[nostr] Failed to decode npub: ${trimmed}`, decodeError || new Error("invalid-npub"), ); @@ -3191,7 +3157,7 @@ export class NostrClient { } catch (error) { lastError = error; if (options && isDevMode) { - console.warn( + userLogger.warn( "[nostr] extension.enable request with explicit permissions failed:", error, ); @@ -3287,9 +3253,7 @@ export class NostrClient { try { raw = localStorage.getItem(SESSION_ACTOR_STORAGE_KEY); } catch (error) { - if (isDevMode) { - console.warn("[nostr] Failed to read session actor from storage:", error); - } + devLogger.warn("[nostr] Failed to read session actor from storage:", error); return null; } @@ -3318,18 +3282,14 @@ export class NostrClient { : Date.now(), }; } catch (error) { - if (isDevMode) { - console.warn("[nostr] Failed to parse stored session actor:", error); - } + devLogger.warn("[nostr] Failed to parse stored session actor:", error); try { localStorage.removeItem(SESSION_ACTOR_STORAGE_KEY); } catch (cleanupError) { - if (isDevMode) { - console.warn( - "[nostr] Failed to clear corrupt session actor entry:", - cleanupError - ); - } + devLogger.warn( + "[nostr] Failed to clear corrupt session actor entry:", + cleanupError + ); } } @@ -3365,9 +3325,7 @@ export class NostrClient { JSON.stringify(payload) ); } catch (error) { - if (isDevMode) { - console.warn("[nostr] Failed to persist session actor:", error); - } + devLogger.warn("[nostr] Failed to persist session actor:", error); } } @@ -3378,29 +3336,23 @@ export class NostrClient { try { localStorage.removeItem(SESSION_ACTOR_STORAGE_KEY); } catch (error) { - if (isDevMode) { - console.warn("[nostr] Failed to clear stored session actor:", error); - } + devLogger.warn("[nostr] Failed to clear stored session actor:", error); } } mintSessionActor() { const tools = getCachedNostrTools(); if (!tools) { - if (isDevMode) { - console.warn("[nostr] Cannot mint session actor without NostrTools."); - } + devLogger.warn("[nostr] Cannot mint session actor without NostrTools."); return null; } const getPublicKey = typeof tools.getPublicKey === "function" ? tools.getPublicKey : null; if (!getPublicKey) { - if (isDevMode) { - console.warn( - "[nostr] Cannot mint session actor: missing getPublicKey helper." - ); - } + devLogger.warn( + "[nostr] Cannot mint session actor: missing getPublicKey helper." + ); return null; } @@ -3416,9 +3368,7 @@ export class NostrClient { .join(""); } } catch (error) { - if (isDevMode) { - console.warn("[nostr] Failed to mint session private key:", error); - } + devLogger.warn("[nostr] Failed to mint session private key:", error); privateKey = ""; } @@ -3435,9 +3385,7 @@ export class NostrClient { try { pubkey = getPublicKey(normalizedPrivateKey); } catch (error) { - if (isDevMode) { - console.warn("[nostr] Failed to derive session pubkey:", error); - } + devLogger.warn("[nostr] Failed to derive session pubkey:", error); return null; } @@ -3540,9 +3488,7 @@ export class NostrClient { return parsed; } } catch (err) { - if (isDevMode) { - console.warn("[nostr] Failed to parse cached events:", err); - } + devLogger.warn("[nostr] Failed to parse cached events:", err); } return null; }; @@ -3563,9 +3509,7 @@ export class NostrClient { try { localStorage.removeItem(LEGACY_EVENTS_STORAGE_KEY); } catch (err) { - if (isDevMode) { - console.warn("[nostr] Failed to remove legacy cache:", err); - } + devLogger.warn("[nostr] Failed to remove legacy cache:", err); } } } @@ -3582,9 +3526,7 @@ export class NostrClient { try { localStorage.removeItem(EVENTS_CACHE_STORAGE_KEY); } catch (err) { - if (isDevMode) { - console.warn("[nostr] Failed to clear expired cache:", err); - } + devLogger.warn("[nostr] Failed to clear expired cache:", err); } return false; } @@ -3680,9 +3622,7 @@ export class NostrClient { try { raw = localStorage.getItem(WATCH_HISTORY_STORAGE_KEY); } catch (error) { - if (isDevMode) { - console.warn("[nostr] Failed to read watch history storage:", error); - } + devLogger.warn("[nostr] Failed to read watch history storage:", error); this.watchHistoryStorage = emptyStorage; return this.watchHistoryStorage; } @@ -3696,9 +3636,7 @@ export class NostrClient { try { parsed = JSON.parse(raw); } catch (error) { - if (isDevMode) { - console.warn("[nostr] Failed to parse watch history storage:", error); - } + devLogger.warn("[nostr] Failed to parse watch history storage:", error); this.watchHistoryStorage = emptyStorage; return this.watchHistoryStorage; } @@ -3755,9 +3693,7 @@ export class NostrClient { try { localStorage.setItem(WATCH_HISTORY_STORAGE_KEY, JSON.stringify(storage)); } catch (error) { - if (isDevMode) { - console.warn("[nostr] Failed to rewrite watch history storage:", error); - } + devLogger.warn("[nostr] Failed to rewrite watch history storage:", error); } } @@ -3828,9 +3764,7 @@ export class NostrClient { try { localStorage.setItem(WATCH_HISTORY_STORAGE_KEY, JSON.stringify(payload)); } catch (error) { - if (isDevMode) { - console.warn("[nostr] Failed to persist watch history entry:", error); - } + devLogger.warn("[nostr] Failed to persist watch history entry:", error); } } @@ -3904,12 +3838,10 @@ export class NostrClient { try { onSchedule({ snapshotId: key, attempt: attempt + 1, delay }); } catch (error) { - if (isDevMode) { - console.warn( - `[nostr] Failed to notify watch history republish schedule for ${key}:`, - error, - ); - } + devLogger.warn( + `[nostr] Failed to notify watch history republish schedule for ${key}:`, + error, + ); } } @@ -3923,18 +3855,14 @@ export class NostrClient { attempt: attempt + 1, onSchedule, }); - } else if (isDevMode) { - console.warn( - `[nostr] Watch history republish aborted for ${key}: max attempts reached.`, - ); - } + } else devLogger.warn( + `[nostr] Watch history republish aborted for ${key}: max attempts reached.`, + ); } else { this.cancelWatchHistoryRepublish(key); } } catch (error) { - if (isDevMode) { - console.warn("[nostr] Watch history republish attempt failed:", error); - } + devLogger.warn("[nostr] Watch history republish attempt failed:", error); if (attempt + 1 <= WATCH_HISTORY_REPUBLISH_MAX_ATTEMPTS) { this.scheduleWatchHistoryRepublish(key, operation, { attempt: attempt + 1, @@ -3979,7 +3907,7 @@ export class NostrClient { const fingerprint = await computeWatchHistoryFingerprintForItems(items); const previous = this.watchHistoryFingerprints.get(actorKey); if (previous && previous !== fingerprint) { - console.info(`[nostr] Watch history fingerprint changed for ${actorKey}.`); + devLogger.info(`[nostr] Watch history fingerprint changed for ${actorKey}.`); } this.watchHistoryFingerprints.set(actorKey, fingerprint); return fingerprint; @@ -4069,9 +3997,7 @@ export class NostrClient { }; })() .catch((error) => { - if (isDevMode) { - console.warn("[nostr] Watch history background refresh failed:", error); - } + devLogger.warn("[nostr] Watch history background refresh failed:", error); throw error; }) .finally(() => { @@ -4151,9 +4077,9 @@ export class NostrClient { ); if (skipped.length) { - console.warn( + userLogger.warn( `[nostr] Watch history snapshot skipped ${skipped.length} oversize entr${ - skipped.length === 1 ? "y" : "ies" + skipped.length === 1 ? "y" : "ies" }.`, ); } @@ -4172,16 +4098,16 @@ export class NostrClient { relays = Array.from(RELAY_URLS); } - console.info( + devLogger.info( "[nostr] Preparing to publish watch history snapshot.", { - actor: actorKey, - snapshotId, - itemCount: canonicalItems.length, - chunkCount: chunks.length, - relaysRequested: relays, - attempt: options.attempt || 0, - source: options.source || "unknown", + actor: actorKey, + snapshotId, + itemCount: canonicalItems.length, + chunkCount: chunks.length, + relaysRequested: relays, + attempt: options.attempt || 0, + source: options.source || "unknown", } ); @@ -4284,14 +4210,14 @@ export class NostrClient { return tag; }); - console.info( + devLogger.info( "[nostr] Publishing watch history chunk.", { - actor: actorKey, - snapshotId, - chunkIndex: index, - chunkSize: chunkItems.length, - relays, + actor: actorKey, + snapshotId, + chunkIndex: index, + chunkSize: chunkItems.length, + relays, } ); @@ -4307,7 +4233,7 @@ export class NostrClient { try { ciphertext = await encryptChunk(plaintext); } catch (error) { - console.warn("[nostr] Failed to encrypt watch history chunk:", error); + userLogger.warn("[nostr] Failed to encrypt watch history chunk:", error); return { ok: false, error: "encryption-failed", retryable: false }; } @@ -4329,7 +4255,7 @@ export class NostrClient { try { signedEvent = await signEvent(event); } catch (error) { - console.warn("[nostr] Failed to sign watch history chunk:", error); + userLogger.warn("[nostr] Failed to sign watch history chunk:", error); return { ok: false, error: "signing-failed", retryable: false }; } @@ -4343,7 +4269,7 @@ export class NostrClient { if (acceptedCount === 0) { anyChunkRejected = true; - console.warn( + userLogger.warn( `[nostr] Watch history chunk ${index} rejected by all relays:`, publishResults, ); @@ -4353,12 +4279,12 @@ export class NostrClient { ? "accepted" : "partially accepted"; if (acceptedCount === relays.length) { - console.info( + devLogger.info( `[nostr] Watch history chunk ${index} accepted by ${acceptedCount}/${relays.length} relay(s).`, ); } else { anyChunkPartial = true; - console.warn( + userLogger.warn( `[nostr] Watch history chunk ${index} ${logMessage} by ${acceptedCount}/${relays.length} relay(s).`, publishResults, ); @@ -4391,16 +4317,16 @@ export class NostrClient { try { signedPointerEvent = await signEvent(pointerEvent); } catch (error) { - console.warn("[nostr] Failed to sign watch history pointer event:", error); + userLogger.warn("[nostr] Failed to sign watch history pointer event:", error); return { ok: false, error: "signing-failed", retryable: false }; } - console.info( + devLogger.info( "[nostr] Publishing watch history pointer event.", { - actor: actorKey, - snapshotId, - relays, + actor: actorKey, + snapshotId, + relays, } ); @@ -4415,16 +4341,16 @@ export class NostrClient { const pointerAccepted = pointerAcceptedCount > 0; if (pointerAcceptedCount === relays.length) { - console.info( + devLogger.info( `[nostr] Watch history pointer accepted by ${pointerAcceptedCount}/${relays.length} relay(s).`, ); } else if (pointerAccepted) { - console.warn( + userLogger.warn( `[nostr] Watch history pointer partially accepted by ${pointerAcceptedCount}/${relays.length} relay(s).`, pointerResults, ); } else { - console.warn( + userLogger.warn( "[nostr] Watch history pointer rejected by all relays:", pointerResults, ); @@ -4488,7 +4414,7 @@ export class NostrClient { result.error = errorCode; } - console.info("[nostr] Watch history snapshot publish result.", { + devLogger.info("[nostr] Watch history snapshot publish result.", { actor: actorKey, snapshotId, success, @@ -4538,12 +4464,12 @@ export class NostrClient { canonicalItems, ); - console.info("[nostr] Updating watch history list.", { + devLogger.info("[nostr] Updating watch history list.", { actor: resolvedActor, incomingItemCount: incomingItems.length, finalItemCount: canonicalItems.length, replace: options.replace === true, - }); + }); const publishResult = await this.publishWatchHistorySnapshot( canonicalItems, @@ -4554,12 +4480,12 @@ export class NostrClient { }, ); - console.info("[nostr] Watch history list publish attempt finished.", { + devLogger.info("[nostr] Watch history list publish attempt finished.", { actor: resolvedActor, snapshotId: publishResult.snapshotId || null, success: !!publishResult.ok, retryable: !!publishResult.retryable, - }); + }); const metadata = sanitizeWatchHistoryMetadata(cachedEntry.metadata); metadata.updatedAt = Date.now(); @@ -4660,10 +4586,10 @@ export class NostrClient { const actorKeyIsHex = /^[0-9a-f]{64}$/.test(actorKey); - console.info("[nostr] Fetching watch history from relays.", { + devLogger.info("[nostr] Fetching watch history from relays.", { actor: resolvedActor, forceRefresh: options.forceRefresh === true, - }); + }); const extension = window?.nostr; @@ -4697,7 +4623,7 @@ export class NostrClient { }; if (!actorKeyIsHex) { - console.warn( + userLogger.warn( `[nostr] Cannot normalize watch history actor key to hex. Aborting relay fetch for ${resolvedActor}.`, ); if ( @@ -4721,11 +4647,11 @@ export class NostrClient { Number.isFinite(existingEntry.savedAt) && now - existingEntry.savedAt < ttl ) { - console.info("[nostr] Using cached watch history entry.", { + devLogger.info("[nostr] Using cached watch history entry.", { actor: resolvedActor, itemCount: Array.isArray(existingEntry.items) ? existingEntry.items.length : 0, cacheAgeMs: now - existingEntry.savedAt, - }); + }); return { pointerEvent: existingEntry.pointerEvent || null, items: existingEntry.items || [], @@ -4734,7 +4660,7 @@ export class NostrClient { } if (!this.pool) { - console.warn("[nostr] Cannot fetch watch history because relay pool is unavailable. Returning cached values."); + userLogger.warn("[nostr] Cannot fetch watch history because relay pool is unavailable. Returning cached values."); return { pointerEvent: existingEntry?.pointerEvent || null, items: existingEntry?.items || [], @@ -4779,9 +4705,7 @@ export class NostrClient { .filter((event) => event && typeof event === "object") : []; } catch (error) { - if (isDevMode) { - console.warn("[nostr] Failed to fetch watch history pointer:", error); - } + devLogger.warn("[nostr] Failed to fetch watch history pointer:", error); } const pointerEvent = pointerEvents.reduce((latest, current) => { @@ -4801,10 +4725,10 @@ export class NostrClient { }, null); if (!pointerEvent) { - console.info( + devLogger.info( "[nostr] No watch history pointer event found on relays. Falling back to storage.", { - actor: resolvedActor, + actor: resolvedActor, } ); return await loadFromStorage(); @@ -4882,9 +4806,7 @@ export class NostrClient { .filter((event) => event && typeof event === "object") : []; } catch (error) { - if (isDevMode) { - console.warn("[nostr] Failed to fetch watch history chunks:", error); - } + devLogger.warn("[nostr] Failed to fetch watch history chunks:", error); } } @@ -4922,10 +4844,10 @@ export class NostrClient { const tools = await ensureNostrTools(); if (tools?.nip04 && typeof tools.nip04.decrypt === "function") { cachedDecryptTools = tools; - console.info("[nostr] Loaded nostr-tools nip04 helpers for watch history decryption."); + devLogger.info("[nostr] Loaded nostr-tools nip04 helpers for watch history decryption."); return cachedDecryptTools; } - console.warn("[nostr] Unable to load nostr-tools nip04 helpers for watch history decryption."); + userLogger.warn("[nostr] Unable to load nostr-tools nip04 helpers for watch history decryption."); return null; }; @@ -4934,80 +4856,80 @@ export class NostrClient { throw new Error("empty-ciphertext"); } const ciphertextPreview = ciphertext.slice(0, 32); - console.info("[nostr] Attempting to decrypt watch history chunk.", { + devLogger.info("[nostr] Attempting to decrypt watch history chunk.", { actorKey, chunkIdentifier: context.chunkIdentifier ?? null, eventId: context.eventId ?? null, ciphertextPreview, ciphertextFormat: "base64 NIP-04 ciphertext", expectedPlaintextFormat: - "JSON string with { version, items, snapshot, chunkIndex, totalChunks }", - }); + "JSON string with { version, items, snapshot, chunkIndex, totalChunks }", + }); const extensionDecrypt = extension && typeof extension?.nip04?.decrypt === "function" && normalizeActorKey(this.pubkey) === actorKey; if (extensionDecrypt) { await this.ensureExtensionPermissions(DEFAULT_NIP07_PERMISSION_METHODS); - console.info( + devLogger.info( "[nostr] Using logged in user's extension key to decrypt watch history chunk.", { - actorKey, - chunkIdentifier: context.chunkIdentifier ?? null, - eventId: context.eventId ?? null, - }, - ); - const plaintext = await extension.nip04.decrypt(actorKey, ciphertext); - console.info("[nostr] Successfully decrypted watch history chunk via extension key.", { actorKey, chunkIdentifier: context.chunkIdentifier ?? null, eventId: context.eventId ?? null, - }); + }, + ); + const plaintext = await extension.nip04.decrypt(actorKey, ciphertext); + devLogger.info("[nostr] Successfully decrypted watch history chunk via extension key.", { + actorKey, + chunkIdentifier: context.chunkIdentifier ?? null, + eventId: context.eventId ?? null, + }); return plaintext; } if (!this.sessionActor || this.sessionActor.pubkey !== actorKey) { - console.info( + devLogger.info( "[nostr] Session actor mismatch while decrypting watch history chunk. Ensuring session actor matches requested key.", { - actorKey, - chunkIdentifier: context.chunkIdentifier ?? null, - eventId: context.eventId ?? null, - currentSessionActor: this.sessionActor?.pubkey ?? null, + actorKey, + chunkIdentifier: context.chunkIdentifier ?? null, + eventId: context.eventId ?? null, + currentSessionActor: this.sessionActor?.pubkey ?? null, }, ); await this.ensureSessionActor(); } if (!this.sessionActor || this.sessionActor.pubkey !== actorKey) { - console.error( + userLogger.error( "[nostr] Watch history decrypt failed: session actor key unavailable after ensure.", { - actorKey, - chunkIdentifier: context.chunkIdentifier ?? null, - eventId: context.eventId ?? null, - currentSessionActor: this.sessionActor?.pubkey ?? null, + actorKey, + chunkIdentifier: context.chunkIdentifier ?? null, + eventId: context.eventId ?? null, + currentSessionActor: this.sessionActor?.pubkey ?? null, }, ); throw new Error("missing-session-key"); } const tools = await ensureDecryptTools(); if (!tools?.nip04 || typeof tools.nip04.decrypt !== "function") { - console.error( + userLogger.error( "[nostr] Watch history decrypt failed: nip04 helpers unavailable.", { - actorKey, - chunkIdentifier: context.chunkIdentifier ?? null, - eventId: context.eventId ?? null, + actorKey, + chunkIdentifier: context.chunkIdentifier ?? null, + eventId: context.eventId ?? null, }, ); throw new Error("nip04-unavailable"); } - console.info( + devLogger.info( "[nostr] Using session actor private key to decrypt watch history chunk.", { - actorKey, - chunkIdentifier: context.chunkIdentifier ?? null, - eventId: context.eventId ?? null, - sessionActor: this.sessionActor?.pubkey ?? null, + actorKey, + chunkIdentifier: context.chunkIdentifier ?? null, + eventId: context.eventId ?? null, + sessionActor: this.sessionActor?.pubkey ?? null, }, ); const plaintext = await tools.nip04.decrypt( @@ -5015,11 +4937,11 @@ export class NostrClient { actorKey, ciphertext, ); - console.info("[nostr] Successfully decrypted watch history chunk via session actor key.", { + devLogger.info("[nostr] Successfully decrypted watch history chunk via session actor key.", { actorKey, chunkIdentifier: context.chunkIdentifier ?? null, eventId: context.eventId ?? null, - }); + }); return plaintext; }; @@ -5042,19 +4964,19 @@ export class NostrClient { eventId: event.id ?? null, }; if (isNip04EncryptedWatchHistoryEvent(event, ciphertext)) { - console.info("[nostr] Watch history chunk is marked as NIP-04 encrypted. Beginning decrypt flow.", { + devLogger.info("[nostr] Watch history chunk is marked as NIP-04 encrypted. Beginning decrypt flow.", { actorKey, ...chunkContext, - }); + }); try { const plaintext = await decryptChunk(ciphertext, chunkContext); - console.info("[nostr] Decrypted watch history chunk. Parsing plaintext payload.", { + devLogger.info("[nostr] Decrypted watch history chunk. Parsing plaintext payload.", { actorKey, ...chunkContext, plaintextPreview: typeof plaintext === "string" ? plaintext.slice(0, 64) : null, expectedPlaintextFormat: - "JSON string with { version, items, snapshot, chunkIndex, totalChunks }", - }); + "JSON string with { version, items, snapshot, chunkIndex, totalChunks }", + }); payload = parseWatchHistoryContentWithFallback( plaintext, fallbackPointers, @@ -5068,30 +4990,30 @@ export class NostrClient { ); } catch (error) { decryptErrors.push(error); - console.error("[nostr] Decrypt failed for watch history chunk. Falling back to pointer items.", { + userLogger.error("[nostr] Decrypt failed for watch history chunk. Falling back to pointer items.", { actorKey, ...chunkContext, error: error?.message || error, ciphertextPreview, fallbackPointerCount: Array.isArray(fallbackPointers) - ? fallbackPointers.length - : 0, + ? fallbackPointers.length + : 0, expectedPlaintextFormat: - "JSON string with { version, items, snapshot, chunkIndex, totalChunks }", - }); + "JSON string with { version, items, snapshot, chunkIndex, totalChunks }", + }); payload = { version: 0, items: fallbackPointers, }; } } else { - console.info("[nostr] Watch history chunk is plaintext. Attempting to parse expected payload format.", { + devLogger.info("[nostr] Watch history chunk is plaintext. Attempting to parse expected payload format.", { actorKey, ...chunkContext, ciphertextPreview, expectedPlaintextFormat: - "JSON string with { version, items, snapshot, chunkIndex, totalChunks }", - }); + "JSON string with { version, items, snapshot, chunkIndex, totalChunks }", + }); payload = parseWatchHistoryContentWithFallback( ciphertext, fallbackPointers, @@ -5110,7 +5032,7 @@ export class NostrClient { } if (decryptErrors.length) { - console.warn( + userLogger.warn( `[nostr] Failed to decrypt ${decryptErrors.length} watch history chunk(s) for ${actorKey}. Using fallback pointers.`, ); } @@ -5162,10 +5084,10 @@ export class NostrClient { return []; } - console.info("[nostr] Resolving watch history for actor.", { + devLogger.info("[nostr] Resolving watch history for actor.", { actor: resolvedActor, forceRefresh: options.forceRefresh === true, - }); + }); const storage = this.getWatchHistoryStorage(); const fallbackItems = Array.isArray(storage.actors?.[actorKey]?.items) @@ -5210,18 +5132,18 @@ export class NostrClient { canonicalItems, ); - console.info("[nostr] Watch history fetch complete.", { + devLogger.info("[nostr] Watch history fetch complete.", { actor: resolvedActor, snapshotId: fetchResult.snapshotId || null, pointerFound: !!fetchResult.pointerEvent, itemCount: canonicalItems.length, - }); + }); - console.info("[nostr] Watch history resolved and cached.", { + devLogger.info("[nostr] Watch history resolved and cached.", { actor: resolvedActor, itemCount: canonicalItems.length, snapshotId: fetchResult.snapshotId || null, - }); + }); const entry = { actor: resolvedActor, @@ -5275,9 +5197,7 @@ export class NostrClient { try { rawResults = await this.pool.list(relayList, filters); } catch (error) { - if (isDevMode) { - console.warn("[nostr] Failed to list video view events:", error); - } + devLogger.warn("[nostr] Failed to list video view events:", error); return []; } @@ -5352,9 +5272,7 @@ export class NostrClient { subscribeVideoViewEvents(pointer, options = {}) { if (!this.pool) { - if (isDevMode) { - console.warn("[nostr] Unable to subscribe to view events: pool missing."); - } + devLogger.warn("[nostr] Unable to subscribe to view events: pool missing."); return () => {}; } @@ -5382,9 +5300,7 @@ export class NostrClient { try { subscription = this.pool.sub(relayList, filters); } catch (error) { - if (isDevMode) { - console.warn("[nostr] Failed to open video view subscription:", error); - } + devLogger.warn("[nostr] Failed to open video view subscription:", error); return () => {}; } @@ -5394,9 +5310,7 @@ export class NostrClient { try { onEvent(event); } catch (error) { - if (isDevMode) { - console.warn("[nostr] Video view event handler threw:", error); - } + devLogger.warn("[nostr] Video view event handler threw:", error); } } }); @@ -5417,12 +5331,10 @@ export class NostrClient { try { originalUnsub(); } catch (error) { - if (isDevMode) { - console.warn( - "[nostr] Failed to unsubscribe from video view events:", - error - ); - } + devLogger.warn( + "[nostr] Failed to unsubscribe from video view events:", + error + ); } } }; @@ -5514,9 +5426,7 @@ export class NostrClient { return { ...result, fallback: false }; } } catch (error) { - if (isDevMode) { - console.warn("[nostr] COUNT view request failed:", error); - } + devLogger.warn("[nostr] COUNT view request failed:", error); } if (signal?.aborted) { @@ -5589,9 +5499,7 @@ export class NostrClient { const guardScope = deriveViewEventPointerScope(pointer); const guardBucket = deriveViewEventBucketIndex(createdAt); if (guardScope && hasRecentViewPublish(guardScope, guardBucket)) { - if (isDevMode) { - console.info("[nostr] Skipping duplicate view publish for scope", guardScope); - } + devLogger.info("[nostr] Skipping duplicate view publish for scope", guardScope); return { ok: true, duplicate: true, @@ -5634,12 +5542,10 @@ export class NostrClient { try { content = JSON.stringify(options.content); } catch (error) { - if (isDevMode) { - console.warn( - "[nostr] Failed to serialize custom view event content:", - error - ); - } + devLogger.warn( + "[nostr] Failed to serialize custom view event content:", + error + ); content = ""; } } @@ -5658,12 +5564,10 @@ export class NostrClient { try { content = JSON.stringify(payload); } catch (error) { - if (isDevMode) { - console.warn( - "[nostr] Failed to serialize default view event content:", - error - ); - } + devLogger.warn( + "[nostr] Failed to serialize default view event content:", + error + ); content = ""; } } @@ -5689,7 +5593,7 @@ export class NostrClient { try { signedEvent = await window.nostr.signEvent(event); } catch (error) { - console.warn("[nostr] Failed to sign view event with extension:", error); + userLogger.warn("[nostr] Failed to sign view event with extension:", error); return { ok: false, error: "signing-failed", details: error }; } } else { @@ -5703,7 +5607,7 @@ export class NostrClient { const privateKey = this.sessionActor.privateKey; signedEvent = signEventWithPrivateKey(event, privateKey); } catch (error) { - console.warn("[nostr] Failed to sign view event with session key:", error); + userLogger.warn("[nostr] Failed to sign view event with session key:", error); return { ok: false, error: "signing-failed", details: error }; } } @@ -5728,12 +5632,12 @@ export class NostrClient { if (guardScope) { rememberViewPublish(guardScope, guardBucket); } - console.info( + devLogger.info( `[nostr] View event accepted by ${acceptedRelays.length} relay(s):`, acceptedRelays.join(", ") ); } else { - console.warn("[nostr] View event rejected by relays:", publishResults); + userLogger.warn("[nostr] View event rejected by relays:", publishResults); } return { @@ -5759,12 +5663,10 @@ export class NostrClient { ingest({ event: view.event, pointer }); } } catch (error) { - if (isDevMode) { - console.warn( - "[nostr] Failed to ingest optimistic view event:", - error - ); - } + devLogger.warn( + "[nostr] Failed to ingest optimistic view event:", + error + ); } } @@ -5775,7 +5677,7 @@ export class NostrClient { * Connect to the configured relays */ async init() { - if (isDevMode) console.log("Connecting to relays..."); + devLogger.log("Connecting to relays..."); this.restoreLocalData(); @@ -5788,11 +5690,10 @@ export class NostrClient { if (successfulRelays.length === 0) { throw new Error("No relays connected"); } - if (isDevMode) { - console.log(`Connected to ${successfulRelays.length} relay(s)`); + devLogger.log(`Connected to ${successfulRelays.length relay(s)`); } } catch (err) { - console.error("Nostr init failed:", err); + userLogger.error("Nostr init failed:", err); throw err; } } @@ -5810,24 +5711,22 @@ export class NostrClient { const SimplePool = resolveSimplePoolConstructor(tools); if (typeof SimplePool !== "function") { - if (isDevMode) { - if (tools && typeof tools === "object") { - const availableKeys = Object.keys(tools).join(", "); - console.warn( - "[nostr] NostrTools helpers did not expose SimplePool. Available keys:", - availableKeys - ); - } else { - console.warn( - "[nostr] NostrTools helpers were unavailable. Check that nostr-tools bundles can load on this domain." - ); - } - if (nostrToolsBootstrapFailure) { - console.warn( - "[nostr] nostr-tools bootstrap failure details:", - nostrToolsBootstrapFailure - ); - } + if (tools && typeof tools === "object") { + const availableKeys = Object.keys(tools).join(", "); + devLogger.warn( + "[nostr] NostrTools helpers did not expose SimplePool. Available keys:", + availableKeys + ); + } else { + userLogger.warn( + "[nostr] NostrTools helpers were unavailable. Check that nostr-tools bundles can load on this domain." + ); + } + if (nostrToolsBootstrapFailure) { + userLogger.warn( + "[nostr] nostr-tools bootstrap failure details:", + nostrToolsBootstrapFailure + ); } const error = new Error( "NostrTools SimplePool is unavailable. Verify that nostr-tools resources can load on this domain." @@ -5896,7 +5795,7 @@ export class NostrClient { try { const extension = window.nostr; if (!extension) { - console.log("No Nostr extension found"); + devLogger.log("No Nostr extension found"); throw new Error( "Please install a Nostr extension (Alby, nos2x, etc.)." ); @@ -5916,9 +5815,7 @@ export class NostrClient { } if (typeof extension.enable === "function") { - if (isDevMode) { - console.log("Requesting permissions from NIP-07 extension..."); - } + devLogger.log("Requesting permissions from NIP-07 extension..."); const requestedPermissionMethods = Array.from( DEFAULT_NIP07_PERMISSION_METHODS, ); @@ -5966,7 +5863,7 @@ export class NostrClient { } catch (error) { enableError = error; if (options && isDevMode) { - console.warn( + userLogger.warn( "[nostr] extension.enable request with explicit permissions failed:", error, ); @@ -6033,12 +5930,10 @@ export class NostrClient { } const npub = npubEncode(pubkey); - if (isDevMode) { - console.log("Got pubkey:", pubkey); - console.log("Converted to npub:", npub); - console.log("Whitelist:", accessControl.getWhitelist()); - console.log("Blacklist:", accessControl.getBlacklist()); - } + devLogger.log("Got pubkey:", pubkey); + devLogger.log("Converted to npub:", npub); + devLogger.log("Whitelist:", accessControl.getWhitelist()); + devLogger.log("Blacklist:", accessControl.getBlacklist()); // Access control if (!accessControl.canAccess(npub)) { if (accessControl.isBlacklisted(npub)) { @@ -6048,12 +5943,10 @@ export class NostrClient { } } this.pubkey = pubkey; - if (isDevMode) { - console.log("Logged in with extension. Pubkey:", this.pubkey); - } + devLogger.log("Logged in with extension. Pubkey:", this.pubkey); return this.pubkey; } catch (err) { - console.error("Login error:", err); + userLogger.error("Login error:", err); throw err; } } @@ -6075,7 +5968,7 @@ export class NostrClient { this.watchHistoryRefreshPromises.clear(); this.watchHistoryLastCreatedAt = 0; this.watchHistoryStorage = null; - if (isDevMode) console.log("User logged out."); + devLogger.log("User logged out."); } async sendDirectMessage(targetNpub, message, actorPubkeyOverride = null) { @@ -6121,12 +6014,10 @@ export class NostrClient { try { actorHex = await extension.getPublicKey(); } catch (error) { - if (isDevMode) { - console.warn( - "[nostr] Failed to fetch actor pubkey from extension:", - error - ); - } + devLogger.warn( + "[nostr] Failed to fetch actor pubkey from extension:", + error + ); } } @@ -6263,7 +6154,7 @@ export class NostrClient { ); signerPubkey = sessionActor.pubkey; } catch (error) { - console.warn("[nostr] Failed to sign event with session key:", error); + userLogger.warn("[nostr] Failed to sign event with session key:", error); throw error; } } @@ -6272,8 +6163,7 @@ export class NostrClient { signerPubkey = signedEvent.pubkey; } - if (isDevMode) { - console.log(`Signed ${devLogLabel} event:`, signedEvent); + devLogger.log(`Signed ${devLogLabel event:`, signedEvent); } let targetRelays = sanitizeRelayList( @@ -6302,7 +6192,8 @@ export class NostrClient { const logLevel = rejectionLogLevel === "warn" ? "warn" : "error"; publishError.relayFailures.forEach( ({ url, error: relayError, reason }) => { - console[logLevel]( + const logFn = logLevel === "warn" ? userLogger.warn : userLogger.error; + logFn( `[nostr] ${logName} rejected by ${url}: ${reason}`, relayError || reason ); @@ -6312,11 +6203,9 @@ export class NostrClient { throw publishError; } - if (isDevMode) { - publishSummary.accepted.forEach(({ url }) => { - console.log(`${logName} published to ${url}`); - }); - } + publishSummary.accepted.forEach(({ url }) => { + devLogger.log(`${logName} published to ${url}`); + }); if (publishSummary.failed.length) { publishSummary.failed.forEach(({ url, error: relayError }) => { @@ -6326,7 +6215,7 @@ export class NostrClient { : relayError ? String(relayError) : "publish failed"; - console.warn( + userLogger.warn( `[nostr] ${logName} not accepted by ${url}: ${reason}`, relayError ); @@ -6349,11 +6238,9 @@ export class NostrClient { // NOTE: Keep the Upload, Edit, and Revert flows synchronized when // updating shared fields. Changes here must be reflected in the modal // controllers and revert helpers so all paths stay in lockstep. - if (isDevMode) { - console.log("Publishing new video with data:", videoData); - if (nip71Metadata) { - console.log("Including NIP-71 metadata:", nip71Metadata); - } + devLogger.log("Publishing new video with data:", videoData); + if (nip71Metadata) { + devLogger.log("Including NIP-71 metadata:", nip71Metadata); } const rawMagnet = typeof videoData.magnet === "string" ? videoData.magnet : ""; @@ -6425,10 +6312,8 @@ export class NostrClient { additionalTags: nip71Tags, }); - if (isDevMode) { - console.log("Publish event with brand-new root:", videoRootId); - console.log("Event content:", event.content); - } + devLogger.log("Publish event with brand-new root:", videoRootId); + devLogger.log("Event content:", event.content); try { const { signedEvent } = await this.signAndPublishEvent(event, { @@ -6467,9 +6352,7 @@ export class NostrClient { content: altText, }); - if (isDevMode) { - console.log("Prepared NIP-94 mirror event:", mirrorEvent); - } + devLogger.log("Prepared NIP-94 mirror event:", mirrorEvent); try { await this.signAndPublishEvent(mirrorEvent, { @@ -6479,23 +6362,17 @@ export class NostrClient { rejectionLogLevel: "warn", }); - if (isDevMode) { - console.log( - "NIP-94 mirror dispatched for hosted URL:", - finalUrl - ); - } + devLogger.log( + "NIP-94 mirror dispatched for hosted URL:", + finalUrl + ); } catch (mirrorError) { - if (isDevMode) { - console.warn( - "[nostr] NIP-94 mirror rejected by all relays:", - mirrorError - ); - } + devLogger.warn( + "[nostr] NIP-94 mirror rejected by all relays:", + mirrorError + ); } - } else if (isDevMode) { - console.log("Skipping NIP-94 mirror: no hosted URL provided."); - } + } else devLogger.log("Skipping NIP-94 mirror: no hosted URL provided."); const hasMetadataObject = nip71Metadata && typeof nip71Metadata === "object"; const metadataWasEdited = @@ -6538,7 +6415,7 @@ export class NostrClient { } ); } catch (nip71Error) { - console.warn( + userLogger.warn( "[nostr] Failed to publish NIP-71 metadata for edit:", nip71Error ); @@ -6547,7 +6424,7 @@ export class NostrClient { return signedEvent; } catch (err) { - if (isDevMode) console.error("Failed to sign/publish:", err); + devLogger.error("Failed to sign/publish:", err); throw err; } } @@ -6564,9 +6441,7 @@ export class NostrClient { const { videoData, nip71Metadata } = extractVideoPublishPayload(videoPayload); if (!nip71Metadata || typeof nip71Metadata !== "object") { - if (isDevMode) { - console.log("[nostr] Skipping NIP-71 publish: metadata missing."); - } + devLogger.log("[nostr] Skipping NIP-71 publish: metadata missing."); return null; } @@ -6592,15 +6467,11 @@ export class NostrClient { }); if (!event) { - if (isDevMode) { - console.warn("[nostr] Skipping NIP-71 publish: builder produced no event."); - } + devLogger.warn("[nostr] Skipping NIP-71 publish: builder produced no event."); return null; } - if (isDevMode) { - console.log("Prepared NIP-71 video event:", event); - } + devLogger.log("Prepared NIP-71 video event:", event); const { signedEvent } = await this.signAndPublishEvent(event, { context: "NIP-71 video", @@ -6776,16 +6647,12 @@ export class NostrClient { additionalTags: nip71Tags, }); - if (isDevMode) { - console.log("Creating edited event with root ID:", oldRootId); - console.log("Event content:", event.content); - } + devLogger.log("Creating edited event with root ID:", oldRootId); + devLogger.log("Event content:", event.content); try { const signedEvent = await window.nostr.signEvent(event); - if (isDevMode) { - console.log("Signed edited event:", signedEvent); - } + devLogger.log("Signed edited event:", signedEvent); const publishResults = await publishEventToRelays( this.pool, @@ -6802,7 +6669,7 @@ export class NostrClient { if (publishError?.relayFailures?.length) { publishError.relayFailures.forEach( ({ url, error: relayError, reason }) => { - console.error( + userLogger.error( `[nostr] Edited video rejected by ${url}: ${reason}`, relayError || reason ); @@ -6812,11 +6679,9 @@ export class NostrClient { throw publishError; } - if (isDevMode) { - publishSummary.accepted.forEach(({ url }) => - console.log(`Edited video published to ${url}`) - ); - } + publishSummary.accepted.forEach(({ url }) => + devLogger.log(`Edited video published to ${url}`) + ); if (publishSummary.failed.length) { publishSummary.failed.forEach(({ url, error: relayError }) => { @@ -6826,7 +6691,7 @@ export class NostrClient { : relayError ? String(relayError) : "publish failed"; - console.warn( + userLogger.warn( `[nostr] Edited video not accepted by ${url}: ${reason}`, relayError ); @@ -6835,7 +6700,7 @@ export class NostrClient { return signedEvent; } catch (err) { - console.error("Edit failed:", err); + userLogger.error("Edit failed:", err); throw err; } } @@ -6885,9 +6750,7 @@ export class NostrClient { try { oldContent = JSON.parse(baseEvent.content || "{}"); } catch (err) { - if (isDevMode) { - console.warn("[nostr] Failed to parse baseEvent.content while reverting:", err); - } + devLogger.warn("[nostr] Failed to parse baseEvent.content while reverting:", err); oldContent = {}; } const oldVersion = oldContent.version ?? 1; @@ -6945,7 +6808,7 @@ export class NostrClient { if (publishError?.relayFailures?.length) { publishError.relayFailures.forEach( ({ url, error: relayError, reason }) => { - console.error( + userLogger.error( `[nostr] Video revert rejected by ${url}: ${reason}`, relayError || reason ); @@ -6955,11 +6818,9 @@ export class NostrClient { throw publishError; } - if (isDevMode) { - publishSummary.accepted.forEach(({ url }) => - console.log(`Revert event published to ${url}`) - ); - } + publishSummary.accepted.forEach(({ url }) => + devLogger.log(`Revert event published to ${url}`) + ); if (publishSummary.failed.length) { publishSummary.failed.forEach(({ url, error: relayError }) => { @@ -6969,7 +6830,7 @@ export class NostrClient { : relayError ? String(relayError) : "publish failed"; - console.warn( + userLogger.warn( `[nostr] Video revert not accepted by ${url}: ${reason}`, relayError ); @@ -7000,7 +6861,7 @@ export class NostrClient { } if (!confirmed) { - console.log("Deletion cancelled by user."); + devLogger.log("Deletion cancelled by user."); return null; // Cancel deletion if user clicks "Cancel" } @@ -7068,9 +6929,7 @@ export class NostrClient { localStorage.setItem(EVENTS_CACHE_STORAGE_KEY, JSON.stringify(payload)); localStorage.removeItem(LEGACY_EVENTS_STORAGE_KEY); } catch (err) { - if (isDevMode) { - console.warn("[nostr] Failed to persist events cache:", err); - } + devLogger.warn("[nostr] Failed to persist events cache:", err); } } @@ -7087,9 +6946,7 @@ export class NostrClient { since: 0, }; - if (isDevMode) { - console.log("[subscribeVideos] Subscribing with filter:", filter); - } + devLogger.log("[subscribeVideos] Subscribing with filter:", filter); const sub = this.pool.sub(this.relays, [filter]); const invalidDuringSub = []; @@ -7143,18 +7000,14 @@ export class NostrClient { this.applyRootCreatedAt(video); }) .catch((error) => { - if (isDevMode) { - console.warn( - "[nostr] Failed to hydrate NIP-71 metadata for live video:", - error - ); - } + devLogger.warn( + "[nostr] Failed to hydrate NIP-71 metadata for live video:", + error + ); }); } } catch (err) { - if (isDevMode) { - console.error("[subscribeVideos] Error processing event:", err); - } + devLogger.error("[subscribeVideos] Error processing event:", err); } } @@ -7191,16 +7044,14 @@ export class NostrClient { // You can still use sub.on("eose") if needed sub.on("eose", () => { if (isDevMode && invalidDuringSub.length > 0) { - console.warn( + userLogger.warn( `[subscribeVideos] found ${invalidDuringSub.length} invalid video notes (with reasons):`, invalidDuringSub ); } - if (isDevMode) { - console.log( - "[subscribeVideos] Reached EOSE for all relays (historical load done)" - ); - } + devLogger.log( + "[subscribeVideos] Reached EOSE for all relays (historical load done)" + ); scheduleFlush(true); }); @@ -7222,7 +7073,7 @@ export class NostrClient { try { return originalUnsub(); } catch (err) { - console.error("[subscribeVideos] Failed to unsub from pool:", err); + userLogger.error("[subscribeVideos] Failed to unsub from pool:", err); return undefined; } }; @@ -7523,8 +7374,7 @@ export class NostrClient { const events = await this.pool.list([url], [filter]); return Array.isArray(events) ? events : []; } catch (error) { - if (isDevMode) { - console.warn(`[nostr] NIP-71 fetch failed on ${url}:`, error); + devLogger.warn(`[nostr] NIP-71 fetch failed on ${url:`, error); } return []; } @@ -7540,9 +7390,7 @@ export class NostrClient { this.processNip71Events(Array.from(deduped.values()), pointerMap); } catch (error) { - if (isDevMode) { - console.warn("[nostr] Failed to fetch NIP-71 metadata:", error); - } + devLogger.warn("[nostr] Failed to fetch NIP-71 metadata:", error); } finally { pointerValues.forEach((pointerValue) => { const info = pointerMap.get(pointerValue); @@ -7664,7 +7512,7 @@ export class NostrClient { // OPTIONAL: Log invalid stats if (invalidNotes.length > 0 && isDevMode) { - console.warn( + userLogger.warn( `Skipped ${invalidNotes.length} invalid video notes:\n`, invalidNotes.map((n) => `${n.id.slice(0, 8)}.. => ${n.reason}`) ); @@ -7677,7 +7525,7 @@ export class NostrClient { activeVideos.forEach((video) => this.applyRootCreatedAt(video)); return activeVideos; } catch (err) { - console.error("fetchVideos error:", err); + userLogger.error("fetchVideos error:", err); return []; } } @@ -7706,9 +7554,7 @@ export class NostrClient { try { await this.ensurePool(); } catch (error) { - if (isDevMode) { - console.warn("fetchRawEventById ensurePool error:", error); - } + devLogger.warn("fetchRawEventById ensurePool error:", error); return null; } @@ -7770,9 +7616,7 @@ export class NostrClient { return remember(evt); } } catch (error) { - if (isDevMode) { - console.warn("fetchRawEventById pool.get error:", error); - } + devLogger.warn("fetchRawEventById pool.get error:", error); } } @@ -7791,9 +7635,7 @@ export class NostrClient { } } } catch (error) { - if (isDevMode) { - console.warn("fetchRawEventById pool.list error:", error); - } + devLogger.warn("fetchRawEventById pool.list error:", error); } } @@ -8007,9 +7849,7 @@ export class NostrClient { const ensured = await this.ensureSessionActor(); actorPubkey = ensured || ""; } catch (error) { - if (isDevMode) { - console.warn("[nostr] Failed to ensure session actor before repost:", error); - } + devLogger.warn("[nostr] Failed to ensure session actor before repost:", error); return { ok: false, error: "missing-actor", details: error }; } } @@ -8022,9 +7862,7 @@ export class NostrClient { try { await this.ensurePool(); } catch (error) { - if (isDevMode) { - console.warn("[nostr] Failed to ensure pool before repost:", error); - } + devLogger.warn("[nostr] Failed to ensure pool before repost:", error); return { ok: false, error: "pool-unavailable", details: error }; } } @@ -8083,9 +7921,7 @@ export class NostrClient { signerPubkey, }; } catch (error) { - if (isDevMode) { - console.warn("[nostr] Repost publish failed:", error); - } + devLogger.warn("[nostr] Repost publish failed:", error); const relayFailure = error && typeof error === "object" && Array.isArray(error.relayFailures); return { @@ -8186,9 +8022,7 @@ export class NostrClient { const ensured = await this.ensureSessionActor(); actorPubkey = ensured || ""; } catch (error) { - if (isDevMode) { - console.warn("[nostr] Failed to ensure session actor before mirror:", error); - } + devLogger.warn("[nostr] Failed to ensure session actor before mirror:", error); return { ok: false, error: "missing-actor", details: error }; } } @@ -8201,9 +8035,7 @@ export class NostrClient { try { await this.ensurePool(); } catch (error) { - if (isDevMode) { - console.warn("[nostr] Failed to ensure pool before mirror:", error); - } + devLogger.warn("[nostr] Failed to ensure pool before mirror:", error); return { ok: false, error: "pool-unavailable", details: error }; } } @@ -8264,9 +8096,7 @@ export class NostrClient { signerPubkey, }; } catch (error) { - if (isDevMode) { - console.warn("[nostr] Mirror publish failed:", error); - } + devLogger.warn("[nostr] Mirror publish failed:", error); const relayFailure = error && typeof error === "object" && Array.isArray(error.relayFailures); return { @@ -8325,9 +8155,7 @@ export class NostrClient { try { await this.ensurePool(); } catch (error) { - if (isDevMode) { - console.warn("[nostr] Failed to ensure pool before rebroadcast:", error); - } + devLogger.warn("[nostr] Failed to ensure pool before rebroadcast:", error); return { ok: false, error: "pool-unavailable", details: error }; } } @@ -8366,9 +8194,7 @@ export class NostrClient { timeoutMs: options.timeoutMs, }); } catch (error) { - if (isDevMode) { - console.warn("[nostr] COUNT request for rebroadcast failed:", error); - } + devLogger.warn("[nostr] COUNT request for rebroadcast failed:", error); } if (countResult?.total && Number(countResult.total) > 0) { @@ -8393,9 +8219,7 @@ export class NostrClient { cooldown: guardScope ? getRebroadcastCooldownState(guardScope) : null, }; } catch (error) { - if (isDevMode) { - console.warn("[nostr] Rebroadcast rejected by relays:", error); - } + devLogger.warn("[nostr] Rebroadcast rejected by relays:", error); return { ok: false, error: "publish-rejected", @@ -8718,8 +8542,7 @@ export class NostrClient { const isUnsupported = error?.code === "count-unsupported"; if (isUnsupported) { this.countUnsupportedRelays.add(url); - } else if (isDevMode) { - console.warn(`[nostr] COUNT request failed on ${url}:`, error); + } else devLogger.warn(`[nostr] COUNT request failed on ${url:`, error); } return { url, ok: false, error, unsupported: isUnsupported }; } @@ -8887,12 +8710,10 @@ export class NostrClient { } } } catch (error) { - if (isDevMode) { - console.warn( - `[nostr] Failed to fetch root event ${normalizedRoot} for history:`, - error - ); - } + devLogger.warn( + `[nostr] Failed to fetch root event ${normalizedRoot} for history:`, + error + ); } }; @@ -8919,8 +8740,7 @@ export class NostrClient { const events = await this.pool.list([url], [filter]); return events || []; } catch (err) { - if (isDevMode) { - console.warn(`[nostr] History fetch failed on ${url}:`, err); + devLogger.warn(`[nostr] History fetch failed on ${url:`, err); } return []; } @@ -8940,15 +8760,11 @@ export class NostrClient { this.allEvents.set(evt.id, parsed); } } catch (err) { - if (isDevMode) { - console.warn("[nostr] Failed to convert historical event:", err); - } + devLogger.warn("[nostr] Failed to convert historical event:", err); } } } catch (err) { - if (isDevMode) { - console.warn("[nostr] hydrateVideoHistory relay fetch error:", err); - } + devLogger.warn("[nostr] hydrateVideoHistory relay fetch error:", err); } localMatches = collectLocalMatches(); diff --git a/js/nostrEventSchemas.js b/js/nostrEventSchemas.js index 3b8053c9..fa0e2460 100644 --- a/js/nostrEventSchemas.js +++ b/js/nostrEventSchemas.js @@ -1,4 +1,5 @@ import { +import { devLogger } from "./utils/logger.js"; ADMIN_LIST_NAMESPACE, isDevMode, WATCH_HISTORY_KIND, @@ -46,12 +47,10 @@ function ensureValidUtf8Content(value) { const stringified = JSON.stringify(value); normalized = typeof stringified === "string" ? stringified : ""; } catch (error) { - if (isDevMode) { - console.warn( - "[nostrEventSchemas] Failed to serialize view event content:", - error - ); - } + devLogger.warn( + "[nostrEventSchemas] Failed to serialize view event content:", + error + ); normalized = ""; } } else { @@ -66,12 +65,10 @@ function ensureValidUtf8Content(value) { try { cachedUtf8Encoder.encode(normalized); } catch (error) { - if (isDevMode) { - console.warn( - "[nostrEventSchemas] Dropping invalid UTF-8 characters from event content", - error - ); - } + devLogger.warn( + "[nostrEventSchemas] Dropping invalid UTF-8 characters from event content", + error + ); const sanitized = Array.from(normalized) .filter((char) => { const code = char.charCodeAt(0); @@ -82,12 +79,10 @@ function ensureValidUtf8Content(value) { cachedUtf8Encoder.encode(sanitized); normalized = sanitized; } catch (encodeError) { - if (isDevMode) { - console.warn( - "[nostrEventSchemas] Failed to normalize view event content; defaulting to empty string", - encodeError - ); - } + devLogger.warn( + "[nostrEventSchemas] Failed to normalize view event content; defaulting to empty string", + encodeError + ); normalized = ""; } } @@ -835,8 +830,7 @@ function resolveAdminNoteType(listKey) { export function buildAdminListEvent(listKey, { pubkey, created_at, hexPubkeys = [] }) { const schema = getNostrEventSchema(resolveAdminNoteType(listKey)); if (!schema) { - if (isDevMode) { - console.warn(`[nostrEventSchemas] Unknown admin list key: ${listKey}`); + devLogger.warn(`[nostrEventSchemas] Unknown admin list key: ${listKey`); } return { kind: 30000, diff --git a/js/nostrPublish.js b/js/nostrPublish.js index 5faa25f3..ab2237de 100644 --- a/js/nostrPublish.js +++ b/js/nostrPublish.js @@ -1,4 +1,5 @@ import { isDevMode } from "./config.js"; +import { devLogger } from "./utils/logger.js"; export const RELAY_PUBLISH_TIMEOUT_MS = 10_000; @@ -88,12 +89,10 @@ export function publishEventToRelay(pool, url, event, options = {}) { pub.on(eventName, handler); return true; } catch (error) { - if (isDevMode) { - console.warn( - `[nostrPublish] Relay publish handle rejected ${eventName} listener:`, - error, - ); - } + devLogger.warn( + `[nostrPublish] Relay publish handle rejected ${eventName} listener:`, + error, + ); return false; } }; diff --git a/js/nostrToolsBootstrap.js b/js/nostrToolsBootstrap.js index 685e8efe..b139d3ad 100644 --- a/js/nostrToolsBootstrap.js +++ b/js/nostrToolsBootstrap.js @@ -1,3 +1,4 @@ +import { devLogger, userLogger } from "./utils/logger.js"; const REMOTE_IMPORT_TIMEOUT = 4500; const LOCAL_IMPORT_TIMEOUT = 2500; const NODE_IMPORT_TIMEOUT = 1500; @@ -416,7 +417,7 @@ export function bootstrapNostrTools() { reason: "Failed to resolve any nostr-tools helpers.", attempts, }; - console.warn("[bitvid] nostr-tools bootstrap failed", failure); + userLogger.warn("[bitvid] nostr-tools bootstrap failed", failure); return failure; } @@ -446,9 +447,9 @@ export function bootstrapNostrTools() { if (resolvedNip04) { canonicalTools.nip04 = resolvedNip04; - console.info("[bitvid] Initialized nostr nip04 helpers."); + devLogger.info("[bitvid] Initialized nostr nip04 helpers."); } else { - console.warn( + userLogger.warn( "[bitvid] NIP-04 helpers unavailable after bootstrap attempts." ); } @@ -507,7 +508,7 @@ export function bootstrapNostrTools() { }, }); } catch (error) { - console.warn("[bitvid] Failed to install NostrTools guard.", error); + userLogger.warn("[bitvid] Failed to install NostrTools guard.", error); } applyActive(existingGlobalTools); diff --git a/js/nwcSettings.js b/js/nwcSettings.js index 5a1697f0..46dbface 100644 --- a/js/nwcSettings.js +++ b/js/nwcSettings.js @@ -1,3 +1,4 @@ +import { userLogger } from "./utils/logger.js"; const DB_NAME = "bitvidSettings"; const DB_VERSION = 1; const STORE_NAME = "kv"; @@ -183,20 +184,20 @@ function emitToast(message, { variant = "error", error } = {}) { }) ); } catch (eventError) { - console.warn("[nwcSettings] Failed to dispatch toast event", eventError); + userLogger.warn("[nwcSettings] Failed to dispatch toast event", eventError); } } } function notifyFailure(message, error) { const text = message || "NWC settings storage error."; - console.warn(`[nwcSettings] ${text}`, error); + userLogger.warn(`[nwcSettings] ${text}`, error); emitToast(text, { variant: "error", error }); } function notifyWarning(message, error) { const text = message || "NWC settings storage warning."; - console.warn(`[nwcSettings] ${text}`, error); + userLogger.warn(`[nwcSettings] ${text}`, error); emitToast(text, { variant: "warning", error }); } diff --git a/js/payments/nwcClient.js b/js/payments/nwcClient.js index 2774b5c3..435c317c 100644 --- a/js/payments/nwcClient.js +++ b/js/payments/nwcClient.js @@ -1,6 +1,7 @@ // js/payments/nwcClient.js import { nostrToolsReady } from "../nostrToolsBootstrap.js"; +import { userLogger } from "../utils/logger.js"; const HEX64_REGEX = /^[0-9a-f]{64}$/i; const URI_SCHEMES = [ @@ -119,7 +120,7 @@ let cachedNostrTools = __nwcNostrToolsBootstrap.toolkit || null; const nostrToolsInitializationFailure = __nwcNostrToolsBootstrap.failure || null; if (!cachedNostrTools && nostrToolsInitializationFailure) { - console.warn( + userLogger.warn( "[nwcClient] nostr-tools helpers unavailable after bootstrap.", nostrToolsInitializationFailure ); @@ -150,7 +151,7 @@ async function ensureNostrTools() { const result = await nostrToolsReadySource; rememberNostrTools(result); } catch (error) { - console.warn("[nwcClient] Failed to resolve nostr-tools helpers.", error); + userLogger.warn("[nwcClient] Failed to resolve nostr-tools helpers.", error); } if (!cachedNostrTools) { rememberNostrTools(readToolkitFromScope()); @@ -200,15 +201,15 @@ function assertNostrTools(methods = []) { const available = Array.isArray(Object.keys(tools)) ? Object.keys(tools) : []; - console.error( + userLogger.error( "[nwcClient] Required NostrTools capability is missing.", { - missingMethod: method, - availableMethods: available, + missingMethod: method, + availableMethods: available, } ); } catch (loggingError) { - console.error( + userLogger.error( "[nwcClient] Failed to enumerate available NostrTools methods.", loggingError ); @@ -454,7 +455,7 @@ function createNip44Encryption(context) { const secretBytes = hexToBytesCompat(context.secretKey); cachedKey = resolved.getConversationKey(secretBytes, context.walletPubkey); } catch (error) { - console.warn("[nwcClient] Failed to derive nip44 conversation key", error); + userLogger.warn("[nwcClient] Failed to derive nip44 conversation key", error); throw error; } } @@ -527,7 +528,7 @@ function settleInfoRequest(result) { try { resolver(result || null); } catch (error) { - console.warn("[nwcClient] Failed to resolve wallet info request", error); + userLogger.warn("[nwcClient] Failed to resolve wallet info request", error); } } } @@ -571,7 +572,7 @@ function requestInfoEvent(context) { try { socket.send(JSON.stringify(["REQ", infoSubscriptionId, filters])); } catch (error) { - console.warn("[nwcClient] Failed to request wallet info event", error); + userLogger.warn("[nwcClient] Failed to request wallet info event", error); settleInfoRequest(null); return Promise.resolve(null); } @@ -619,7 +620,7 @@ async function ensureEncryption(context) { try { infoEvent = await requestInfoEvent(context); } catch (error) { - console.warn("[nwcClient] Failed to load wallet info event", error); + userLogger.warn("[nwcClient] Failed to load wallet info event", error); } if (infoEvent) { context.infoEvent = infoEvent; @@ -735,12 +736,12 @@ function isSocketOpen() { } function handleSocketError(error) { - console.warn("[nwcClient] WebSocket error", error); + userLogger.warn("[nwcClient] WebSocket error", error); closeSocket({ keepState: true }); } function handleSocketClose() { - console.warn("[nwcClient] Wallet connection closed."); + userLogger.warn("[nwcClient] Wallet connection closed."); closeSocket({ keepState: true }); } @@ -782,7 +783,7 @@ async function handleSocketMessage(messageEvent) { try { payload = JSON.parse(messageEvent.data); } catch (error) { - console.warn("[nwcClient] Failed to parse relay message", error); + userLogger.warn("[nwcClient] Failed to parse relay message", error); return; } @@ -815,7 +816,7 @@ async function handleSocketMessage(messageEvent) { finalizePendingRequest(pending); pending.reject(error); } else { - console.warn("[nwcClient] Failed to decrypt wallet response", error); + userLogger.warn("[nwcClient] Failed to decrypt wallet response", error); } return; } @@ -860,7 +861,7 @@ async function handleSocketMessage(messageEvent) { } if (type === "NOTICE" && payload.length >= 2) { - console.warn("[nwcClient] Relay notice:", payload[1]); + userLogger.warn("[nwcClient] Relay notice:", payload[1]); return; } } diff --git a/js/payments/platformAddress.js b/js/payments/platformAddress.js index cb1f35a3..80891965 100644 --- a/js/payments/platformAddress.js +++ b/js/payments/platformAddress.js @@ -4,6 +4,7 @@ import { PLATFORM_LUD16_OVERRIDE, ADMIN_SUPER_NPUB } from "../config.js"; import { nostrClient } from "../nostr.js"; import { setProfileCacheEntry } from "../state/cache.js"; import { nostrToolsReady } from "../nostrToolsBootstrap.js"; +import { userLogger } from "../utils/logger.js"; const HEX64_REGEX = /^[0-9a-f]{64}$/i; const CACHE_TTL_MS = 10 * 60 * 1000; @@ -106,7 +107,7 @@ const nostrToolsInitializationFailure = __platformNostrToolsBootstrap.failure || null; if (!cachedNostrTools && nostrToolsInitializationFailure) { - console.warn( + userLogger.warn( "[platformAddress] nostr-tools helpers unavailable after bootstrap.", nostrToolsInitializationFailure ); @@ -137,7 +138,7 @@ async function ensureNostrTools() { const result = await nostrToolsReadySource; rememberNostrTools(result); } catch (error) { - console.warn( + userLogger.warn( "[platformAddress] Failed to resolve nostr-tools helpers.", error ); @@ -198,7 +199,7 @@ function decodeAdminPubkey() { } } } catch (error) { - console.warn("[platformAddress] Failed to decode ADMIN_SUPER_NPUB", error); + userLogger.warn("[platformAddress] Failed to decode ADMIN_SUPER_NPUB", error); } } @@ -233,7 +234,7 @@ async function fetchAdminMetadata(adminPubkey) { try { pool = await nostrClient.ensurePool(); } catch (error) { - console.warn("[platformAddress] Failed to initialize Nostr pool", error); + userLogger.warn("[platformAddress] Failed to initialize Nostr pool", error); return null; } @@ -245,7 +246,7 @@ async function fetchAdminMetadata(adminPubkey) { ? nostrClient.relays : []; if (relayUrls.length === 0) { - console.warn("[platformAddress] Nostr client is not ready."); + userLogger.warn("[platformAddress] Nostr client is not ready."); return null; } @@ -286,7 +287,7 @@ async function fetchAdminMetadata(adminPubkey) { return lightningAddress || null; } catch (error) { - console.warn("[platformAddress] Failed to fetch admin metadata", error); + userLogger.warn("[platformAddress] Failed to fetch admin metadata", error); return null; } } diff --git a/js/payments/zapSplit.js b/js/payments/zapSplit.js index 05f6d9ce..98f5e643 100644 --- a/js/payments/zapSplit.js +++ b/js/payments/zapSplit.js @@ -11,6 +11,7 @@ import { import { ensureWallet, sendPayment } from "./nwcClient.js"; import { getPlatformLightningAddress } from "./platformAddress.js"; import { +import { userLogger } from "../utils/logger.js"; clampPercent, parsePercentValue, resolvePlatformFeePercent, @@ -124,7 +125,7 @@ let cachedNostrTools = __zapNostrToolsBootstrap.toolkit || null; const nostrToolsInitializationFailure = __zapNostrToolsBootstrap.failure || null; if (!cachedNostrTools && nostrToolsInitializationFailure) { - console.warn( + userLogger.warn( "[zapSplit] nostr-tools helpers unavailable after bootstrap.", nostrToolsInitializationFailure ); @@ -155,7 +156,7 @@ async function ensureNostrTools() { const result = await nostrToolsReadySource; rememberNostrTools(result); } catch (error) { - console.warn("[zapSplit] Failed to resolve nostr-tools helpers.", error); + userLogger.warn("[zapSplit] Failed to resolve nostr-tools helpers.", error); } if (!cachedNostrTools) { rememberNostrTools(readToolkitFromScope()); diff --git a/js/r2-quick.js b/js/r2-quick.js index ff6b3cbf..23c665be 100644 --- a/js/r2-quick.js +++ b/js/r2-quick.js @@ -7,6 +7,7 @@ import { setManagedDomain, } from "./storage/r2-mgmt.js"; import { makeR2Client, multipartUpload } from "./storage/r2-s3.js"; +import { userLogger } from "./utils/logger.js"; const STORAGE_KEY = "bitvid:quickR2Settings"; const STATUS_CLASSNAMES = [ @@ -46,7 +47,7 @@ function loadSavedSettings() { } return parsed; } catch (err) { - console.warn("Failed to read quick R2 settings:", err); + userLogger.warn("Failed to read quick R2 settings:", err); return null; } } @@ -55,7 +56,7 @@ function persistSettings(settings) { try { localStorage.setItem(STORAGE_KEY, JSON.stringify(settings)); } catch (err) { - console.warn("Failed to store quick R2 settings:", err); + userLogger.warn("Failed to store quick R2 settings:", err); } } @@ -63,7 +64,7 @@ function clearSavedSettings() { try { localStorage.removeItem(STORAGE_KEY); } catch (err) { - console.warn("Failed to clear quick R2 settings:", err); + userLogger.warn("Failed to clear quick R2 settings:", err); } } @@ -258,7 +259,7 @@ export function initQuickR2Upload(app) { origins: getCorsOrigins(), }); } catch (corsErr) { - console.warn("Quick R2 CORS update failed:", corsErr); + userLogger.warn("Quick R2 CORS update failed:", corsErr); } } @@ -292,7 +293,7 @@ export function initQuickR2Upload(app) { enabled: false, }); } catch (disableErr) { - console.warn("Quick R2 managed domain disable failed:", disableErr); + userLogger.warn("Quick R2 managed domain disable failed:", disableErr); } } else { setStatus( @@ -302,7 +303,7 @@ export function initQuickR2Upload(app) { ); } } catch (err) { - console.warn("Quick R2 custom domain error:", err); + userLogger.warn("Quick R2 custom domain error:", err); setStatus( elements.status, err?.message @@ -332,7 +333,7 @@ export function initQuickR2Upload(app) { usedManagedFallback = true; } } catch (err) { - console.warn("Quick R2 managed domain enable failed:", err); + userLogger.warn("Quick R2 managed domain enable failed:", err); setStatus( elements.status, err?.message @@ -393,7 +394,7 @@ export function initQuickR2Upload(app) { elements.form.requestSubmit(); } } catch (err) { - console.error("Quick R2 upload failed:", err); + userLogger.error("Quick R2 upload failed:", err); setStatus( elements.status, err?.message ? `Upload failed: ${err.message}` : "Upload failed.", diff --git a/js/r2.js b/js/r2.js index d3b73429..777165f0 100644 --- a/js/r2.js +++ b/js/r2.js @@ -1,3 +1,4 @@ +import { userLogger } from "./utils/logger.js"; const DB_NAME = "bitvidSettings"; const DB_VERSION = 1; const STORE_NAME = "kv"; @@ -104,7 +105,7 @@ export async function loadR2Settings() { }); } } catch (err) { - console.warn("Failed to open IndexedDB for settings, falling back:", err); + userLogger.warn("Failed to open IndexedDB for settings, falling back:", err); } try { @@ -115,7 +116,7 @@ export async function loadR2Settings() { } } } catch (err) { - console.warn("Failed to read fallback settings:", err); + userLogger.warn("Failed to read fallback settings:", err); } return normalizeSettings(null); @@ -128,7 +129,7 @@ export async function saveR2Settings(settings) { try { db = await openSettingsDb(); } catch (err) { - console.warn("Unable to open IndexedDB, continuing with fallback:", err); + userLogger.warn("Unable to open IndexedDB, continuing with fallback:", err); } if (db) { @@ -165,7 +166,7 @@ export async function clearR2Settings() { cleared = true; } } catch (err) { - console.warn("Failed to clear IndexedDB settings:", err); + userLogger.warn("Failed to clear IndexedDB settings:", err); } try { @@ -174,7 +175,7 @@ export async function clearR2Settings() { cleared = true; } } catch (err) { - console.warn("Failed to clear fallback settings:", err); + userLogger.warn("Failed to clear fallback settings:", err); } return cleared; diff --git a/js/relayManager.js b/js/relayManager.js index d40549e2..668e70f8 100644 --- a/js/relayManager.js +++ b/js/relayManager.js @@ -2,6 +2,7 @@ import { isDevMode } from "./config.js"; import { DEFAULT_RELAY_URLS, nostrClient } from "./nostr.js"; import { buildRelayListEvent } from "./nostrEventSchemas.js"; import { +import { devLogger, userLogger } from "./utils/logger.js"; publishEventToRelays, assertAnyRelayAccepted, } from "./nostrPublish.js"; @@ -537,17 +538,13 @@ class RelayPreferencesManager { } else { const reason = outcome.reason; if (reason?.code === "timeout") { - if (isDevMode) { - console.warn( - `[relayManager] Relay ${reason.relay} timed out while loading relay list (${reason.timeoutMs}ms)` - ); - } - } else if (isDevMode) { - console.warn( - `[relayManager] Relay ${reason?.relay || "unknown"} failed while loading relay list:`, - reason + devLogger.warn( + `[relayManager] Relay ${reason.relay} timed out while loading relay list (${reason.timeoutMs}ms)` ); - } + } else devLogger.warn( + `[relayManager] Relay ${reason?.relay || "unknown"} failed while loading relay list:`, + reason + ); } }); @@ -558,9 +555,7 @@ class RelayPreferencesManager { applyEvents(aggregated, { skipIfEmpty: true }); }) .catch((error) => { - if (isDevMode) { - console.warn("[relayManager] Background relay refresh failed", error); - } + devLogger.warn("[relayManager] Background relay refresh failed", error); }); let fastResult = null; @@ -571,14 +566,12 @@ class RelayPreferencesManager { if (error instanceof AggregateError) { error.errors?.forEach((err) => { if (err?.code === "timeout" && isDevMode) { - console.warn( + userLogger.warn( `[relayManager] Relay ${err.relay} timed out while loading relay list (${err.timeoutMs}ms)` ); } }); - } else if (isDevMode) { - console.warn("[relayManager] Fast relay fetch failed", error); - } + } else devLogger.warn("[relayManager] Fast relay fetch failed", error); } } @@ -657,7 +650,7 @@ class RelayPreferencesManager { if (publishError?.relayFailures?.length) { publishError.relayFailures.forEach( ({ url, error: relayError, reason }) => { - console.error( + userLogger.error( `[RelayPreferencesManager] Relay ${url} rejected relay list: ${reason}`, relayError || reason ); @@ -675,7 +668,7 @@ class RelayPreferencesManager { : relayError ? String(relayError) : "publish failed"; - console.warn( + userLogger.warn( `[RelayPreferencesManager] Relay ${url} did not acknowledge relay list: ${reason}`, relayError ); diff --git a/js/services/authService.js b/js/services/authService.js index 76b5a2e1..9ec018e0 100644 --- a/js/services/authService.js +++ b/js/services/authService.js @@ -7,6 +7,7 @@ import { getCurrentUserNpub, } from "../state/appState.js"; import { +import { userLogger } from "../utils/logger.js"; getSavedProfiles, getActiveProfilePubkey, setActiveProfilePubkey, @@ -94,7 +95,7 @@ export default class AuthService { try { this.logger(message, error); } catch (logError) { - console.warn("[AuthService] logger threw", logError); + userLogger.warn("[AuthService] logger threw", logError); } }); } @@ -103,7 +104,7 @@ export default class AuthService { try { this.logger(...args); } catch (error) { - console.warn("[AuthService] logger threw", error); + userLogger.warn("[AuthService] logger threw", error); } } diff --git a/js/services/discussionCountService.js b/js/services/discussionCountService.js index 0673901a..ec29a12e 100644 --- a/js/services/discussionCountService.js +++ b/js/services/discussionCountService.js @@ -1,4 +1,4 @@ -import { isDevMode } from "../config.js"; +import { devLogger } from "../utils/logger.js"; const DEFAULT_MAX_DISCUSSION_COUNT_VIDEOS = 24; const COUNT_UNSUPPORTED_TITLE = "Relay does not support NIP-45 COUNT queries."; @@ -14,10 +14,10 @@ function toPositiveInteger(value, fallback) { export default class DiscussionCountService { constructor({ maxVideos = DEFAULT_MAX_DISCUSSION_COUNT_VIDEOS, - logger = typeof console !== "undefined" ? console : null, + logger = devLogger, } = {}) { this.maxVideos = toPositiveInteger(maxVideos, DEFAULT_MAX_DISCUSSION_COUNT_VIDEOS); - this.logger = logger; + this.logger = logger && typeof logger.warn === "function" ? logger : devLogger; this.videoDiscussionCountCache = new Map(); this.inFlightDiscussionCounts = new Map(); } @@ -104,7 +104,7 @@ export default class DiscussionCountService { return result; }) .catch((error) => { - if (isDevMode && this.logger?.warn) { + if (this.logger?.warn) { this.logger.warn( `[counts] Failed to fetch discussion count for ${video.id}:`, error diff --git a/js/services/nostrService.js b/js/services/nostrService.js index 56299ab7..a7784b40 100644 --- a/js/services/nostrService.js +++ b/js/services/nostrService.js @@ -5,6 +5,7 @@ import { import { accessControl } from "../accessControl.js"; import { ALLOW_NSFW_CONTENT } from "../config.js"; import { +import { userLogger } from "../utils/logger.js"; getVideosMap as getStoredVideosMap, setVideosMap as setStoredVideosMap, getVideoSubscription as getStoredVideoSubscription, @@ -53,7 +54,7 @@ class SimpleEventEmitter { try { this.logger(`nostrService listener for "${eventName}" threw`, error); } catch (logError) { - console.warn("[nostrService] listener logger threw", logError); + userLogger.warn("[nostrService] listener logger threw", logError); } } } @@ -108,7 +109,7 @@ export class NostrService { try { this.logger(message, error); } catch (logError) { - console.warn("[nostrService] logger threw", logError); + userLogger.warn("[nostrService] logger threw", logError); } }); this.videosMap = null; @@ -118,7 +119,7 @@ export class NostrService { try { this.logger(...args); } catch (error) { - console.warn("[nostrService] logger threw", error); + userLogger.warn("[nostrService] logger threw", error); } } @@ -164,7 +165,7 @@ export class NostrService { try { current.unsub(); } catch (error) { - console.warn("[nostrService] Failed to unsubscribe from video feed:", error); + userLogger.warn("[nostrService] Failed to unsubscribe from video feed:", error); } } this.setVideoSubscription(null); @@ -209,7 +210,7 @@ export class NostrService { return false; } } catch (error) { - console.warn("[nostrService] isAuthorBlocked handler threw", error); + userLogger.warn("[nostrService] isAuthorBlocked handler threw", error); } } @@ -223,7 +224,7 @@ export class NostrService { return false; } } catch (error) { - console.warn("[nostrService] access control check failed", error); + userLogger.warn("[nostrService] access control check failed", error); return false; } } @@ -254,7 +255,7 @@ export class NostrService { try { await this.accessControl.ensureReady(); } catch (error) { - console.warn( + userLogger.warn( "[nostrService] Failed to ensure access control lists are ready:", error ); @@ -288,7 +289,7 @@ export class NostrService { try { onVideos(filtered, { reason }); } catch (error) { - console.warn("[nostrService] onVideos handler threw", error); + userLogger.warn("[nostrService] onVideos handler threw", error); } } this.emit("videos:updated", { videos: filtered, reason }); @@ -318,7 +319,7 @@ export class NostrService { this.emit("videos:fetched", { videos: filtered }); return filtered; } catch (error) { - console.error("[nostrService] Failed to fetch videos:", error); + userLogger.error("[nostrService] Failed to fetch videos:", error); return []; } } @@ -362,11 +363,11 @@ export class NostrService { collected.set(video.id, video); this.nostrClient.allEvents.set(video.id, video); } catch (error) { - console.warn("[nostrService] Failed to convert older event", error); + userLogger.warn("[nostrService] Failed to convert older event", error); } } } catch (error) { - console.error("[nostrService] Failed to load older videos:", error); + userLogger.error("[nostrService] Failed to load older videos:", error); return []; } diff --git a/js/services/nwcSettingsService.js b/js/services/nwcSettingsService.js index 27f665c5..e9a55b18 100644 --- a/js/services/nwcSettingsService.js +++ b/js/services/nwcSettingsService.js @@ -5,6 +5,7 @@ import { createDefaultNwcSettings, } from "../nwcSettings.js"; import { MAX_WALLET_DEFAULT_ZAP } from "../config.js"; +import { devLogger, userLogger } from "../utils/logger.js"; const NWC_URI_SCHEME = "nostr+walletconnect://"; @@ -17,7 +18,7 @@ export default class NwcSettingsService { normalizeHexPubkey, getActivePubkey, payments = null, - logger = console, + logger = { dev: devLogger, user: userLogger }, notifyError, maxWalletDefaultZap = MAX_WALLET_DEFAULT_ZAP, loadSettings = loadNwcSettings, @@ -32,7 +33,9 @@ export default class NwcSettingsService { ? getActivePubkey : () => null; this.payments = payments || null; - this.logger = logger || console; + 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 @@ -78,8 +81,8 @@ export default class NwcSettingsService { try { return this.normalizeHexPubkey(pubkey); } catch (error) { - if (this.logger && isFunction(this.logger.warn)) { - this.logger.warn("[nwcSettings] Failed to normalize pubkey:", error); + if (isFunction(this.logger.user?.warn)) { + this.logger.user.warn("[nwcSettings] Failed to normalize pubkey:", error); } return null; } @@ -100,8 +103,8 @@ export default class NwcSettingsService { this.cache.set(normalized, record); return this.cloneSettings(record); } catch (error) { - if (this.logger && isFunction(this.logger.warn)) { - this.logger.warn( + if (isFunction(this.logger.user?.warn)) { + this.logger.user.warn( `[nwcSettings] Failed to load settings for ${normalized}:`, error, ); @@ -160,8 +163,8 @@ export default class NwcSettingsService { async updateActiveNwcSettings(partial = {}) { const normalized = this.getNormalizedPubkey(this.getActivePubkey()); if (!normalized) { - if (this.logger && isFunction(this.logger.warn)) { - this.logger.warn( + if (isFunction(this.logger.user?.warn)) { + this.logger.user.warn( "[nwcSettings] Cannot update settings without an active pubkey.", ); } @@ -177,8 +180,8 @@ export default class NwcSettingsService { this.cache.set(normalized, record); return this.cloneSettings(record); } catch (error) { - if (this.logger && isFunction(this.logger.warn)) { - this.logger.warn( + if (isFunction(this.logger.user?.warn)) { + this.logger.user.warn( `[nwcSettings] Failed to save settings for ${normalized}:`, error, ); @@ -239,8 +242,8 @@ export default class NwcSettingsService { return this.payments.ensureWallet({ settings: merged }); } - if (this.logger && isFunction(this.logger.warn)) { - this.logger.warn( + if (isFunction(this.logger.dev?.warn)) { + this.logger.dev.warn( "[wallet] Falling back to stub ensureWallet implementation. Returning settings without performing a connection test.", ); } @@ -256,8 +259,8 @@ export default class NwcSettingsService { try { await this.clearSettings(normalized); } catch (error) { - if (this.logger && isFunction(this.logger.warn)) { - this.logger.warn( + if (isFunction(this.logger.user?.warn)) { + this.logger.user.warn( `[nwcSettings] Failed to clear settings for ${normalized}:`, error, ); @@ -268,8 +271,8 @@ export default class NwcSettingsService { try { await this.saveSettings(normalized, this.createDefaultNwcSettings()); } catch (persistError) { - if (this.logger && isFunction(this.logger.warn)) { - this.logger.warn( + if (isFunction(this.logger.user?.warn)) { + this.logger.user.warn( `[nwcSettings] Failed to overwrite settings for ${normalized}:`, persistError, ); diff --git a/js/services/playbackService.js b/js/services/playbackService.js index ae7278fc..794acd7e 100644 --- a/js/services/playbackService.js +++ b/js/services/playbackService.js @@ -1,3 +1,4 @@ +import { userLogger } from "../utils/logger.js"; // js/services/playbackService.js class SimpleEventEmitter { @@ -73,7 +74,7 @@ export class PlaybackService { try { this.logger(...args); } catch (err) { - console.warn("[PlaybackService] logger threw", err); + userLogger.warn("[PlaybackService] logger threw", err); } } diff --git a/js/services/r2Service.js b/js/services/r2Service.js index f6518809..48017f8e 100644 --- a/js/services/r2Service.js +++ b/js/services/r2Service.js @@ -21,6 +21,7 @@ import { ensureBucketCors, } from "../storage/r2-s3.js"; import { truncateMiddle } from "../utils/formatters.js"; +import { userLogger } from "../utils/logger.js"; const STATUS_VARIANTS = new Set(["info", "success", "error", "warning"]); @@ -69,7 +70,7 @@ class R2Service { try { handler(detail); } catch (err) { - console.error("[r2Service] Listener error for", event, err); + userLogger.error("[r2Service] Listener error for", event, err); } } } @@ -225,7 +226,7 @@ class R2Service { this.populateCloudflareSettingsInputs(settings); return settings; } catch (err) { - console.error("Failed to load Cloudflare settings:", err); + userLogger.error("Failed to load Cloudflare settings:", err); this.setSettings(createDefaultSettings()); this.populateCloudflareSettingsInputs(this.getSettings()); this.setCloudflareSettingsStatus( @@ -285,7 +286,7 @@ class R2Service { } return true; } catch (err) { - console.error("Failed to save Cloudflare settings:", err); + userLogger.error("Failed to save Cloudflare settings:", err); if (!quiet) { this.setCloudflareSettingsStatus( "Failed to save settings. Check console for details.", @@ -310,7 +311,7 @@ class R2Service { this.setCloudflareSettingsStatus("Settings cleared.", "success"); return true; } catch (err) { - console.error("Failed to clear Cloudflare settings:", err); + userLogger.error("Failed to clear Cloudflare settings:", err); this.setCloudflareSettingsStatus("Failed to clear settings.", "error"); return false; } @@ -338,7 +339,7 @@ class R2Service { try { return deriveShortSubdomain(npub); } catch (err) { - console.warn("Failed to derive short subdomain, falling back:", err); + userLogger.warn("Failed to derive short subdomain, falling back:", err); } const base = String(npub || "user") @@ -382,7 +383,7 @@ class R2Service { origins: corsOrigins, }); } catch (err) { - console.warn("Failed to refresh bucket configuration:", err); + userLogger.warn("Failed to refresh bucket configuration:", err); } } else if (accessKeyId && secretAccessKey && corsOrigins.length > 0) { try { @@ -397,7 +398,7 @@ class R2Service { origins: corsOrigins, }); } catch (err) { - console.warn("Failed to refresh bucket CORS via access keys:", err); + userLogger.warn("Failed to refresh bucket CORS via access keys:", err); } } return { @@ -444,7 +445,7 @@ class R2Service { origins: corsOrigins, }); } catch (corsErr) { - console.warn( + userLogger.warn( "Failed to ensure R2 CORS rules via access keys. Configure the bucket's CORS policy manually if uploads continue to fail.", corsErr ); @@ -485,7 +486,7 @@ class R2Service { origins: corsOrigins, }); } catch (err) { - console.warn("Failed to apply R2 CORS rules:", err); + userLogger.warn("Failed to apply R2 CORS rules:", err); } let publicBaseUrl = entry?.publicBaseUrl || ""; @@ -517,7 +518,7 @@ class R2Service { enabled: false, }); } catch (disableErr) { - console.warn("Failed to disable managed domain:", disableErr); + userLogger.warn("Failed to disable managed domain:", disableErr); } } else { usedManagedFallback = true; @@ -535,10 +536,10 @@ class R2Service { enabled: false, }); } catch (disableErr) { - console.warn("Failed to disable managed domain:", disableErr); + userLogger.warn("Failed to disable managed domain:", disableErr); } } else { - console.warn("Failed to attach custom domain, falling back:", err); + userLogger.warn("Failed to attach custom domain, falling back:", err); usedManagedFallback = true; customDomainStatus = "error"; } @@ -699,7 +700,7 @@ class R2Service { try { bucketResult = await this.ensureBucketConfigForNpub(npub); } catch (err) { - console.error("Failed to prepare R2 bucket:", err); + userLogger.error("Failed to prepare R2 bucket:", err); this.setCloudflareUploadStatus( err?.message ? `Bucket setup failed: ${err.message}` : "Bucket setup failed.", "error" @@ -760,7 +761,7 @@ class R2Service { let publishOutcome = true; if (typeof publishVideoNote !== "function") { - console.warn( + userLogger.warn( "publishVideoNote handler missing; skipping publish step." ); publishOutcome = false; @@ -805,7 +806,7 @@ class R2Service { return publishOutcome; } catch (err) { - console.error("Cloudflare upload failed:", err); + userLogger.error("Cloudflare upload failed:", err); this.setCloudflareUploadStatus( err?.message ? `Upload failed: ${err.message}` : "Upload failed.", "error" diff --git a/js/services/watchHistoryTelemetry.js b/js/services/watchHistoryTelemetry.js index a34e7a35..bd2bad43 100644 --- a/js/services/watchHistoryTelemetry.js +++ b/js/services/watchHistoryTelemetry.js @@ -1,6 +1,7 @@ import { isDevMode } from "../config.js"; import { pointerArrayToKey } from "../utils/pointer.js"; import { +import { devLogger, userLogger } from "../utils/logger.js"; ingestLocalViewEvent as defaultIngestLocalViewEvent, } from "../viewCounter.js"; @@ -108,12 +109,10 @@ export default class WatchHistoryTelemetry { try { this.watchHistoryService?.clearLocalMetadata?.(); } catch (error) { - if (isDevMode) { - console.warn( - "[watchHistoryTelemetry] Failed to clear cached metadata after toggle off:", - error, - ); - } + devLogger.warn( + "[watchHistoryTelemetry] Failed to clear cached metadata after toggle off:", + error, + ); } } }, @@ -122,12 +121,10 @@ export default class WatchHistoryTelemetry { this.watchHistoryPreferenceUnsubscribe = unsubscribe; } } catch (error) { - if (isDevMode) { - console.warn( - "[watchHistoryTelemetry] Failed to subscribe to metadata preference changes:", - error, - ); - } + devLogger.warn( + "[watchHistoryTelemetry] Failed to subscribe to metadata preference changes:", + error, + ); } } @@ -153,12 +150,10 @@ export default class WatchHistoryTelemetry { enabled = this.watchHistoryService.shouldStoreMetadata() !== false; } } catch (error) { - if (isDevMode) { - console.warn( - "[watchHistoryTelemetry] Failed to read metadata settings:", - error, - ); - } + devLogger.warn( + "[watchHistoryTelemetry] Failed to read metadata settings:", + error, + ); enabled = true; } @@ -168,12 +163,10 @@ export default class WatchHistoryTelemetry { try { this.watchHistoryService?.clearLocalMetadata?.(); } catch (error) { - if (isDevMode) { - console.warn( - "[watchHistoryTelemetry] Failed to purge metadata cache while preference disabled:", - error, - ); - } + devLogger.warn( + "[watchHistoryTelemetry] Failed to purge metadata cache while preference disabled:", + error, + ); } } @@ -205,13 +198,11 @@ export default class WatchHistoryTelemetry { try { this.watchHistoryService.setLocalMetadata(pointerInfo.key, metadata); } catch (error) { - if (isDevMode) { - console.warn( - "[watchHistoryTelemetry] Failed to persist local metadata for pointer:", - pointerInfo.key, - error, - ); - } + devLogger.warn( + "[watchHistoryTelemetry] Failed to persist local metadata for pointer:", + pointerInfo.key, + error, + ); } } @@ -227,13 +218,11 @@ export default class WatchHistoryTelemetry { try { this.watchHistoryService.removeLocalMetadata(pointerKey); } catch (error) { - if (isDevMode) { - console.warn( - "[watchHistoryTelemetry] Failed to remove cached metadata for pointer:", - pointerKey, - error, - ); - } + devLogger.warn( + "[watchHistoryTelemetry] Failed to remove cached metadata for pointer:", + pointerKey, + error, + ); } } @@ -277,12 +266,10 @@ export default class WatchHistoryTelemetry { try { state.videoEl.removeEventListener(eventName, handler); } catch (error) { - if (isDevMode) { - console.warn( - `[watchHistoryTelemetry] Failed to detach ${eventName} listener:`, - error, - ); - } + devLogger.warn( + `[watchHistoryTelemetry] Failed to detach ${eventName} listener:`, + error, + ); } } } @@ -423,12 +410,10 @@ export default class WatchHistoryTelemetry { viewResult = { ok: false, error: "view-logging-unavailable" }; } } catch (error) { - if (isDevMode) { - console.warn( - "[watchHistoryTelemetry] Exception while recording video view:", - error, - ); - } + devLogger.warn( + "[watchHistoryTelemetry] Exception while recording video view:", + error, + ); } const viewOk = !!viewResult?.ok; @@ -451,27 +436,23 @@ export default class WatchHistoryTelemetry { pointer: thresholdPointer, }); } catch (error) { - if (isDevMode) { - console.warn( - "[watchHistoryTelemetry] Failed to ingest local view event:", - error, - ); - } + devLogger.warn( + "[watchHistoryTelemetry] Failed to ingest local view event:", + error, + ); } } } else if (isDevMode && viewResult) { - console.warn( + userLogger.warn( "[watchHistoryTelemetry] View event rejected by relays:", viewResult, ); } })().catch((error) => { - if (isDevMode) { - console.warn( - "[watchHistoryTelemetry] Unexpected error while recording video view:", - error, - ); - } + devLogger.warn( + "[watchHistoryTelemetry] Unexpected error while recording video view:", + error, + ); }); }; @@ -581,7 +562,7 @@ export default class WatchHistoryTelemetry { try { this.watchHistoryPreferenceUnsubscribe(); } catch (error) { - console.warn( + userLogger.warn( "[watchHistoryTelemetry] Failed to unsubscribe watch history preference:", error, ); diff --git a/js/state/appState.js b/js/state/appState.js index efde8cd2..ca74016b 100644 --- a/js/state/appState.js +++ b/js/state/appState.js @@ -1,3 +1,4 @@ +import { userLogger } from "../utils/logger.js"; const state = { pubkey: null, currentUserNpub: null, @@ -29,7 +30,7 @@ function notifyKey(key, value, previousValue) { try { callback(value, previousValue, createSnapshot()); } catch (error) { - console.warn(`[appState] subscriber for key "${key}" threw:`, error); + userLogger.warn(`[appState] subscriber for key "${key}" threw:`, error); } } } @@ -40,7 +41,7 @@ function notifyKey(key, value, previousValue) { try { callback(snapshot, { key, value, previousValue }); } catch (error) { - console.warn("[appState] global subscriber threw:", error); + userLogger.warn("[appState] global subscriber threw:", error); } } } @@ -158,7 +159,7 @@ function notifyModal(name, value, previousValue) { try { callback(value, previousValue, createSnapshot()); } catch (error) { - console.warn(`[appState] modal subscriber for "${name}" threw:`, error); + userLogger.warn(`[appState] modal subscriber for "${name}" threw:`, error); } } } diff --git a/js/state/cache.js b/js/state/cache.js index 385083a7..f8bc49f6 100644 --- a/js/state/cache.js +++ b/js/state/cache.js @@ -1,4 +1,5 @@ import { +import { userLogger } from "../utils/logger.js"; readUrlHealthFromStorage, removeUrlHealthFromStorage, writeUrlHealthToStorage, @@ -187,7 +188,7 @@ export function readSavedProfilesPayloadFromStorage() { } return parsed; } catch (error) { - console.warn( + userLogger.warn( "[cache.readSavedProfilesPayloadFromStorage] Failed to parse payload:", error ); @@ -210,12 +211,12 @@ function writeSavedProfilesPayloadToStorage(payload) { error.code === 22 || error.code === 1014); if (isQuotaError) { - console.warn( + userLogger.warn( "[cache.writeSavedProfilesPayloadToStorage] Storage quota exceeded; keeping in-memory copy only.", error ); } else { - console.warn( + userLogger.warn( "[cache.writeSavedProfilesPayloadToStorage] Failed to persist saved profiles:", error ); @@ -232,7 +233,7 @@ export function persistSavedProfiles({ persistActive = true } = {}) { try { localStorage.removeItem(SAVED_PROFILES_STORAGE_KEY); } catch (error) { - console.warn( + userLogger.warn( "[cache.persistSavedProfiles] Failed to remove empty payload:", error ); @@ -349,7 +350,7 @@ export function loadSavedProfilesFromStorage() { needsRewrite = true; } } catch (error) { - console.warn("[cache.loadSavedProfilesFromStorage] Failed to parse payload:", error); + userLogger.warn("[cache.loadSavedProfilesFromStorage] Failed to parse payload:", error); needsRewrite = true; } @@ -493,7 +494,7 @@ export function loadProfileCacheFromStorage() { }); } } catch (error) { - console.warn("[cache.loadProfileCacheFromStorage] Failed to parse payload:", error); + userLogger.warn("[cache.loadProfileCacheFromStorage] Failed to parse payload:", error); } } @@ -532,7 +533,7 @@ export function persistProfileCacheToStorage() { try { localStorage.removeItem(PROFILE_CACHE_STORAGE_KEY); } catch (error) { - console.warn( + userLogger.warn( "[cache.persistProfileCacheToStorage] Failed to clear storage:", error ); @@ -543,7 +544,7 @@ export function persistProfileCacheToStorage() { try { localStorage.setItem(PROFILE_CACHE_STORAGE_KEY, JSON.stringify(payload)); } catch (error) { - console.warn("[cache.persistProfileCacheToStorage] Failed to persist cache:", error); + userLogger.warn("[cache.persistProfileCacheToStorage] Failed to persist cache:", error); } } diff --git a/js/subscriptions.js b/js/subscriptions.js index 3aebace9..f4ce091f 100644 --- a/js/subscriptions.js +++ b/js/subscriptions.js @@ -15,6 +15,7 @@ import { import { getApplication } from "./applicationContext.js"; import { VideoListView } from "./ui/views/VideoListView.js"; import { ALLOW_NSFW_CONTENT } from "./config.js"; +import { devLogger, userLogger } from "./utils/logger.js"; const getApp = () => getApplication(); @@ -40,7 +41,7 @@ class SubscriptionsManager { */ async loadSubscriptions(userPubkey) { if (!userPubkey) { - console.warn("[SubscriptionsManager] No pubkey => cannot load subs."); + userLogger.warn("[SubscriptionsManager] No pubkey => cannot load subs."); return; } try { @@ -59,7 +60,7 @@ class SubscriptionsManager { events.push(...result); } } catch (err) { - console.error(`[SubscriptionsManager] Relay error at ${url}`, err); + userLogger.error(`[SubscriptionsManager] Relay error at ${url}`, err); } } @@ -82,7 +83,7 @@ class SubscriptionsManager { newest.content ); } catch (errDecrypt) { - console.error("[SubscriptionsManager] Decryption failed:", errDecrypt); + userLogger.error("[SubscriptionsManager] Decryption failed:", errDecrypt); this.subscribedPubkeys.clear(); this.subsEventId = null; this.loaded = true; @@ -97,7 +98,7 @@ class SubscriptionsManager { this.loaded = true; } catch (err) { - console.error("[SubscriptionsManager] Failed to load subs:", err); + userLogger.error("[SubscriptionsManager] Failed to load subs:", err); } } @@ -114,18 +115,16 @@ class SubscriptionsManager { throw new Error("No user pubkey => cannot addChannel."); } if (this.subscribedPubkeys.has(channelHex)) { - console.log("Already subscribed to", channelHex); + devLogger.log("Already subscribed to", channelHex); return; } this.subscribedPubkeys.add(channelHex); await this.publishSubscriptionList(userPubkey); this.refreshActiveFeed({ reason: "subscription-update" }).catch((error) => { - if (typeof console !== "undefined") { - console.warn( - "[SubscriptionsManager] Failed to refresh after adding subscription:", - error - ); - } + userLogger.warn( + "[SubscriptionsManager] Failed to refresh after adding subscription:", + error + ); }); } @@ -134,18 +133,16 @@ class SubscriptionsManager { throw new Error("No user pubkey => cannot removeChannel."); } if (!this.subscribedPubkeys.has(channelHex)) { - console.log("Channel not found in subscription list:", channelHex); + devLogger.log("Channel not found in subscription list:", channelHex); return; } this.subscribedPubkeys.delete(channelHex); await this.publishSubscriptionList(userPubkey); this.refreshActiveFeed({ reason: "subscription-update" }).catch((error) => { - if (typeof console !== "undefined") { - console.warn( - "[SubscriptionsManager] Failed to refresh after removing subscription:", - error - ); - } + userLogger.warn( + "[SubscriptionsManager] Failed to refresh after removing subscription:", + error + ); }); } @@ -173,7 +170,7 @@ class SubscriptionsManager { try { cipherText = await window.nostr.nip04.encrypt(userPubkey, plainStr); } catch (err) { - console.error("Encryption failed:", err); + userLogger.error("Encryption failed:", err); throw err; } @@ -187,7 +184,7 @@ class SubscriptionsManager { try { signedEvent = await window.nostr.signEvent(evt); } catch (signErr) { - console.error("Failed to sign subscription list:", signErr); + userLogger.error("Failed to sign subscription list:", signErr); throw signErr; } @@ -206,7 +203,7 @@ class SubscriptionsManager { if (publishError?.relayFailures?.length) { publishError.relayFailures.forEach( ({ url, error: relayError, reason }) => { - console.error( + userLogger.error( `[SubscriptionsManager] Subscription list rejected by ${url}: ${reason}`, relayError || reason ); @@ -224,7 +221,7 @@ class SubscriptionsManager { : relayError ? String(relayError) : "publish failed"; - console.warn( + userLogger.warn( `[SubscriptionsManager] Subscription list not accepted by ${url}: ${reason}`, relayError ); @@ -233,7 +230,7 @@ class SubscriptionsManager { this.subsEventId = signedEvent.id; const acceptedUrls = publishSummary.accepted.map(({ url }) => url); - console.log( + devLogger.log( "Subscription list published, event id:", signedEvent.id, "accepted relays:", @@ -348,7 +345,7 @@ class SubscriptionsManager { this.renderSameGridStyle(result, containerId, { limit, reason }); return result; } catch (error) { - console.error( + userLogger.error( "[SubscriptionsManager] Failed to run subscriptions feed:", error ); @@ -365,7 +362,7 @@ class SubscriptionsManager { try { app.registerSubscriptionsFeed(); } catch (error) { - console.warn( + userLogger.warn( "[SubscriptionsManager] Failed to register subscriptions feed:", error ); @@ -607,7 +604,7 @@ class SubscriptionsManager { magnet: detail.magnet }) ).catch((error) => { - console.error( + userLogger.error( "[SubscriptionsManager] Failed to play by event id:", error ); @@ -617,7 +614,7 @@ class SubscriptionsManager { Promise.resolve( app?.playVideoWithFallback?.({ url: detail.url, magnet: detail.magnet }) ).catch((error) => { - console.error( + userLogger.error( "[SubscriptionsManager] Failed to start playback:", error ); diff --git a/js/themeController.js b/js/themeController.js index 1c32332c..ddca025d 100644 --- a/js/themeController.js +++ b/js/themeController.js @@ -1,3 +1,4 @@ +import { userLogger } from "./utils/logger.js"; const STORAGE_KEY = "bitvid:theme"; const FALLBACK_THEME = "dark"; const VALID_THEMES = new Set(["light", "dark"]); @@ -42,7 +43,7 @@ const readStoredTheme = () => { const stored = window.localStorage.getItem(STORAGE_KEY); return normalizeTheme(stored); } catch (error) { - console.warn("Unable to read stored theme preference:", error); + userLogger.warn("Unable to read stored theme preference:", error); return null; } }; @@ -54,7 +55,7 @@ const persistTheme = (theme) => { try { window.localStorage.setItem(STORAGE_KEY, theme); } catch (error) { - console.warn("Unable to persist theme preference:", error); + userLogger.warn("Unable to persist theme preference:", error); } }; @@ -92,7 +93,7 @@ const updateThemeColorMeta = (theme) => { .trim(); } } catch (error) { - console.warn("Unable to compute theme color token:", error); + userLogger.warn("Unable to compute theme color token:", error); } const fallback = FALLBACK_META_COLORS[theme] || FALLBACK_META_COLORS[FALLBACK_THEME]; @@ -179,7 +180,7 @@ const collectToggleElements = (root = document) => { } }); } catch (error) { - console.warn(`Invalid selector for theme toggle: ${selector}`, error); + userLogger.warn(`Invalid selector for theme toggle: ${selector}`, error); } }); diff --git a/js/ui/components/UploadModal.js b/js/ui/components/UploadModal.js index 8da5f6a1..b0709d83 100644 --- a/js/ui/components/UploadModal.js +++ b/js/ui/components/UploadModal.js @@ -2,6 +2,7 @@ import { createModalAccessibility } from "./modalAccessibility.js"; import { Nip71FormManager } from "./nip71FormManager.js"; +import { userLogger } from "../../utils/logger.js"; export class UploadModal { constructor({ @@ -439,7 +440,7 @@ export class UploadModal { unsubscribe(); } } catch (error) { - console.warn("[UploadModal] Failed to remove R2 listener", error); + userLogger.warn("[UploadModal] Failed to remove R2 listener", error); } }); } @@ -855,7 +856,7 @@ export class UploadModal { await this.refreshCloudflareBucketPreview(); } } catch (error) { - console.error("[UploadModal] Failed to save Cloudflare settings", error); + userLogger.error("[UploadModal] Failed to save Cloudflare settings", error); } } @@ -869,7 +870,7 @@ export class UploadModal { await this.refreshCloudflareBucketPreview(); } } catch (error) { - console.error("[UploadModal] Failed to clear Cloudflare settings", error); + userLogger.error("[UploadModal] Failed to clear Cloudflare settings", error); } } @@ -934,7 +935,7 @@ export class UploadModal { onReset: () => this.resetCloudflareUploadForm() }); } catch (error) { - console.error("[UploadModal] Cloudflare upload failed", error); + userLogger.error("[UploadModal] Cloudflare upload failed", error); } } @@ -953,7 +954,7 @@ export class UploadModal { cleanup(); } } catch (error) { - console.warn("[UploadModal] Failed to remove handler", error); + userLogger.warn("[UploadModal] Failed to remove handler", error); } }); this.cleanupHandlers = []; @@ -966,7 +967,7 @@ export class UploadModal { unsubscribe(); } } catch (error) { - console.warn("[UploadModal] Failed to cleanup R2 listener", error); + userLogger.warn("[UploadModal] Failed to cleanup R2 listener", error); } }); } diff --git a/js/ui/components/VideoCard.js b/js/ui/components/VideoCard.js index 92db634e..f8a528d4 100644 --- a/js/ui/components/VideoCard.js +++ b/js/ui/components/VideoCard.js @@ -3,6 +3,7 @@ import { updateVideoCardSourceVisibility } from "../../utils/cardSourceVisibilit import positionFloatingPanel from "../utils/positionFloatingPanel.js"; import { createFloatingPanelStyles } from "../utils/floatingPanelStyles.js"; import { +import { userLogger } from "../../utils/logger.js"; getPopupOffsetPx, getPopupViewportPaddingPx, } from "../../designSystem/metrics.js"; @@ -1566,8 +1567,8 @@ export class VideoCard { const formatted = this.formatters.formatTimeAgo(normalized); return typeof formatted === "string" ? formatted : ""; } catch (error) { - if (this.window?.console?.warn) { - this.window.console.warn( + if (this.window?.userLogger?.warn) { + this.window.userLogger.warn( "[VideoCard] formatTimeAgo formatter threw", error ); diff --git a/js/ui/components/VideoModal.js b/js/ui/components/VideoModal.js index 1982080a..70a53d97 100644 --- a/js/ui/components/VideoModal.js +++ b/js/ui/components/VideoModal.js @@ -2,6 +2,7 @@ import { createModalAccessibility } from "./modalAccessibility.js"; import positionFloatingPanel from "../utils/positionFloatingPanel.js"; import { createFloatingPanelStyles } from "../utils/floatingPanelStyles.js"; import { applyDesignSystemAttributes } from "../../designSystem.js"; +import { devLogger } from "../../utils/logger.js"; import { getPopupOffsetPx, getPopupViewportPaddingPx, @@ -12,7 +13,7 @@ export class VideoModal { removeTrackingScripts, setGlobalModalState, document: doc, - logger + logger, } = {}) { if (!doc) { throw new Error("VideoModal requires a document reference."); @@ -28,7 +29,14 @@ export class VideoModal { ? removeTrackingScripts : () => {}; this.setGlobalModalState = setGlobalModalState; - this.logger = logger || console; + const providedLogger = logger ?? devLogger; + if (typeof providedLogger === "function") { + this.logger = { log: providedLogger }; + } else if (providedLogger && typeof providedLogger.log === "function") { + this.logger = providedLogger; + } else { + this.logger = devLogger; + } this.eventTarget = new EventTarget(); this.loaded = false; @@ -101,7 +109,7 @@ export class VideoModal { this.logger(message, ...args); return; } - console.log(message, ...args); + devLogger.log(message, ...args); } addEventListener(type, listener, options) { diff --git a/js/ui/components/nip71FormManager.js b/js/ui/components/nip71FormManager.js index 05f6a43f..2d1428e6 100644 --- a/js/ui/components/nip71FormManager.js +++ b/js/ui/components/nip71FormManager.js @@ -1,3 +1,4 @@ +import { userLogger } from "../../utils/logger.js"; // NOTE: Keep the Upload, Edit, and Revert modals in lockstep when updating NIP-71 form features. const REPEATER_KEYS = ["imeta", "text-track", "segment", "t", "p", "r"]; @@ -36,7 +37,7 @@ export class Nip71FormManager { try { store.root.removeEventListener("click", store.handlers.click); } catch (error) { - console.warn("[Nip71FormManager] Failed to detach previous handler", error); + userLogger.warn("[Nip71FormManager] Failed to detach previous handler", error); } } diff --git a/js/ui/moreMenuController.js b/js/ui/moreMenuController.js index c03926f1..d911f493 100644 --- a/js/ui/moreMenuController.js +++ b/js/ui/moreMenuController.js @@ -2,6 +2,7 @@ import { normalizeDesignSystemContext } from "../designSystem.js"; import positionFloatingPanel from "./utils/positionFloatingPanel.js"; import { createFloatingPanelStyles } from "./utils/floatingPanelStyles.js"; import { +import { userLogger } from "../utils/logger.js"; getPopupOffsetPx, getPopupViewportPaddingPx, } from "../designSystem/metrics.js"; @@ -460,7 +461,7 @@ export default class MoreMenuController { await this.clipboard.writeText(valueToCopy); this.callbacks.showSuccess("Channel npub copied to clipboard!"); } catch (error) { - console.error("Failed to copy npub:", error); + userLogger.error("Failed to copy npub:", error); this.callbacks.showError("Failed to copy the npub."); } break; @@ -477,7 +478,7 @@ export default class MoreMenuController { try { await this.accessControl?.ensureReady?.(); } catch (error) { - console.warn( + userLogger.warn( "Failed to refresh moderation state before blacklisting:", error, ); @@ -521,7 +522,7 @@ export default class MoreMenuController { }); } catch (error) { if (this.isDevMode) { - console.warn( + userLogger.warn( "[Subscriptions] Failed to refresh after blacklist update:", error, ); @@ -552,7 +553,7 @@ export default class MoreMenuController { } } } catch (error) { - console.error("Failed to add creator to blacklist:", error); + userLogger.error("Failed to add creator to blacklist:", error); this.callbacks.showError( "Failed to update the blacklist. Please try again.", ); @@ -608,7 +609,7 @@ export default class MoreMenuController { try { this.callbacks.onUserBlocksUpdated(); } catch (error) { - console.warn( + userLogger.warn( "[MoreMenu] Failed to refresh blocked list after update:", error, ); @@ -621,14 +622,14 @@ export default class MoreMenuController { }); } catch (error) { if (this.isDevMode) { - console.warn( + userLogger.warn( "[Subscriptions] Failed to refresh after user block update:", error, ); } } } catch (error) { - console.error("Failed to update personal block list:", error); + userLogger.error("Failed to update personal block list:", error); const message = error?.code === "nip04-missing" ? "Your Nostr extension must support NIP-04 to manage private lists." diff --git a/js/ui/profileModalController.js b/js/ui/profileModalController.js index d904535f..c5d112ed 100644 --- a/js/ui/profileModalController.js +++ b/js/ui/profileModalController.js @@ -6,6 +6,7 @@ import { MAX_WALLET_DEFAULT_ZAP as CONFIG_MAX_WALLET_DEFAULT_ZAP, } from "../config.js"; import { normalizeDesignSystemContext } from "../designSystem.js"; +import { devLogger, userLogger } from "../utils/logger.js"; const noop = () => {}; @@ -940,7 +941,7 @@ export class ProfileModalController { try { this.profileHistoryRenderer = this.createWatchHistoryRenderer(config); } catch (error) { - console.error( + userLogger.error( "[profileModal] Failed to create watch history renderer:", error, ); @@ -1372,7 +1373,7 @@ export class ProfileModalController { try { await this.switchProfile(entry.pubkey, { entry }); } catch (error) { - console.error("Failed to switch profile:", error); + userLogger.error("Failed to switch profile:", error); } finally { button.dataset.loading = "false"; button.setAttribute("aria-busy", "false"); @@ -1427,7 +1428,7 @@ export class ProfileModalController { try { this.profileHistoryRenderer?.pause(); } catch (error) { - console.warn("[profileModal] Failed to pause history renderer:", error); + userLogger.warn("[profileModal] Failed to pause history renderer:", error); } } @@ -1990,7 +1991,7 @@ export class ProfileModalController { } this.populateBlockedList(); } catch (error) { - console.error("Failed to add creator to personal block list:", error); + userLogger.error("Failed to add creator to personal block list:", error); context.error = error; context.reason = error?.code || "service-error"; const message = @@ -2026,7 +2027,7 @@ export class ProfileModalController { } if (!targetHex) { - console.warn("No valid pubkey to remove from block list:", candidate); + userLogger.warn("No valid pubkey to remove from block list:", candidate); return; } @@ -2055,7 +2056,7 @@ export class ProfileModalController { this.populateBlockedList(); } catch (error) { - console.error( + userLogger.error( "Failed to remove creator from personal block list:", error, ); @@ -2111,7 +2112,7 @@ export class ProfileModalController { renderer.resume(); } } catch (error) { - console.error( + userLogger.error( "[profileModal] Failed to populate watch history pane:", error, ); @@ -2769,11 +2770,11 @@ export class ProfileModalController { if (loadError) { if (loadError?.code === "nostr-unavailable") { - console.info("Moderation lists are still syncing with relays."); + devLogger.info("Moderation lists are still syncing with relays."); return; } - console.error("Failed to load admin lists:", loadError); + userLogger.error("Failed to load admin lists:", loadError); this.showStatus(null); this.showError("Unable to load moderation lists. Please try again."); this.clearAdminLists(); @@ -2866,7 +2867,7 @@ export class ProfileModalController { } } catch (error) { preloadError = error; - console.error("Failed to load admin lists before adding moderator:", error); + userLogger.error("Failed to load admin lists before adding moderator:", error); } if (preloadError) { @@ -2970,7 +2971,7 @@ export class ProfileModalController { } } catch (error) { preloadError = error; - console.error("Failed to load admin lists before removing moderator:", error); + userLogger.error("Failed to load admin lists before removing moderator:", error); } if (preloadError) { @@ -3077,7 +3078,7 @@ export class ProfileModalController { } } catch (error) { preloadError = error; - console.error("Failed to load admin lists before updating entries:", error); + userLogger.error("Failed to load admin lists before updating entries:", error); } if (preloadError) { @@ -3162,7 +3163,7 @@ export class ProfileModalController { this.showError(errorMessage); } if (isDevMode && notifyResult?.error) { - console.warn( + userLogger.warn( "[admin] Failed to send list notification DM:", notifyResult, ); @@ -3178,13 +3179,11 @@ export class ProfileModalController { } } catch (error) { context.notificationError = error; - console.error("Failed to send list notification DM:", error); - if (isDevMode) { - console.warn( - "List update succeeded, but DM notification threw an unexpected error.", - error, - ); - } + userLogger.error("Failed to send list notification DM:", error); + devLogger.warn( + "List update succeeded, but DM notification threw an unexpected error.", + error, + ); this.notifyAdminError({ listType, action, @@ -3468,7 +3467,7 @@ export class ProfileModalController { targetHex, }); } catch (refreshError) { - console.warn( + userLogger.warn( "[ProfileModalController] Failed to refresh videos after blocklist mutation:", refreshError, ); @@ -3776,7 +3775,7 @@ export class ProfileModalController { try { await this.refreshAdminPaneState(); } catch (error) { - console.error( + userLogger.error( "Failed to refresh admin pane while opening profile modal:", error, ); @@ -3793,7 +3792,7 @@ export class ProfileModalController { const activeHex = this.normalizeHexPubkey(this.getActivePubkey()); await this.services.userBlocks.ensureLoaded(activeHex); } catch (error) { - console.warn( + userLogger.warn( "Failed to refresh user block list while opening profile modal:", error, ); @@ -3886,7 +3885,7 @@ export class ProfileModalController { this.profileHistoryRenderer.destroy(); } } catch (error) { - console.warn( + userLogger.warn( "[profileModal] Failed to reset watch history renderer on close:", error, ); @@ -3913,7 +3912,7 @@ export class ProfileModalController { try { previous.focus(); } catch (error) { - console.warn( + userLogger.warn( "[profileModal] Failed to restore focus after closing modal:", error, ); @@ -3926,7 +3925,7 @@ export class ProfileModalController { try { this.callbacks.onClose(this); } catch (error) { - console.warn( + userLogger.warn( "[profileModal] onClose callback threw while hiding modal:", error, ); @@ -3950,7 +3949,7 @@ export class ProfileModalController { persistActive: false, }); } catch (error) { - console.warn( + userLogger.warn( "[profileModal] Failed to sync saved profiles during login:", error, ); @@ -3970,7 +3969,7 @@ export class ProfileModalController { try { await this.refreshAdminPaneState(); } catch (error) { - console.warn("Failed to refresh admin pane after login:", error); + userLogger.warn("Failed to refresh admin pane after login:", error); } this.populateBlockedList(); @@ -3984,7 +3983,7 @@ export class ProfileModalController { this.refreshWalletPaneState(); }) .catch((error) => { - console.warn( + userLogger.warn( "[profileModal] Failed to hydrate deferred login data:", error, ); @@ -4004,7 +4003,7 @@ export class ProfileModalController { persistActive: false, }); } catch (error) { - console.warn( + userLogger.warn( "[profileModal] Failed to sync saved profiles during logout:", error, ); @@ -4023,7 +4022,7 @@ export class ProfileModalController { try { await this.refreshAdminPaneState(); } catch (error) { - console.warn("Failed to refresh admin pane after logout:", error); + userLogger.warn("Failed to refresh admin pane after logout:", error); } this.populateBlockedList(); @@ -4041,7 +4040,7 @@ export class ProfileModalController { persistActive: false, }); } catch (error) { - console.warn( + userLogger.warn( "[profileModal] Failed to sync saved profiles after profile update:", error, ); @@ -4066,7 +4065,7 @@ export class ProfileModalController { try { result = this.services.removeSavedProfile(pubkey) || { removed: false }; } catch (error) { - console.error("Failed to remove saved profile:", error); + userLogger.error("Failed to remove saved profile:", error); result = { removed: false, error }; } @@ -4099,7 +4098,7 @@ export class ProfileModalController { try { return await hydrate(normalized); } catch (error) { - console.warn( + userLogger.warn( `[ProfileModalController] Failed to hydrate wallet settings for ${normalized}:`, error, ); @@ -4155,7 +4154,7 @@ export class ProfileModalController { try { return this.services.persistSavedProfiles(...args); } catch (error) { - console.warn( + userLogger.warn( "[ProfileModalController] Persist saved profiles service threw:", error, ); diff --git a/js/ui/views/VideoListView.js b/js/ui/views/VideoListView.js index 4451a0f0..6943dd10 100644 --- a/js/ui/views/VideoListView.js +++ b/js/ui/views/VideoListView.js @@ -4,6 +4,7 @@ import { unsubscribeFromVideoViewCount, } from "../../viewCounter.js"; import { normalizeDesignSystemContext } from "../../designSystem.js"; +import { userLogger } from "../../utils/logger.js"; const EMPTY_VIDEO_LIST_SIGNATURE = "__EMPTY__"; @@ -539,8 +540,8 @@ export class VideoListView { videoCard.updatePostedAt(Math.floor(resolvedPostedAt)); }) .catch((error) => { - if (this.window?.console?.warn) { - this.window.console.warn( + if (this.window?.userLogger?.warn) { + this.window.userLogger.warn( "[VideoListView] Failed to resolve posted timestamp:", error ); @@ -766,7 +767,7 @@ export class VideoListView { try { unsubscribeFromVideoViewCount(entry.pointer, entry.token); } catch (error) { - console.warn( + userLogger.warn( `[viewCount] Failed to unsubscribe from stale pointer ${key}:`, error ); @@ -920,7 +921,7 @@ export class VideoListView { this.viewCountSubscriptions.set(pointerInfo.key, entry); return entry; } catch (error) { - console.warn("[viewCount] Failed to subscribe to view counter:", error); + userLogger.warn("[viewCount] Failed to subscribe to view counter:", error); return null; } } @@ -972,7 +973,7 @@ export class VideoListView { try { unsubscribeFromVideoViewCount(entry.pointer, entry.token); } catch (error) { - console.warn( + userLogger.warn( `[viewCount] Failed to unsubscribe from pointer ${key}:`, error ); diff --git a/js/ui/watchHistoryController.js b/js/ui/watchHistoryController.js index 64bffd20..355e9434 100644 --- a/js/ui/watchHistoryController.js +++ b/js/ui/watchHistoryController.js @@ -4,6 +4,7 @@ import { pointerKey as derivePointerKey, } from "../nostr.js"; import { normalizeDesignSystemContext } from "../designSystem.js"; +import { devLogger } from "../utils/logger.js"; const noop = () => {}; @@ -22,12 +23,10 @@ function safeInvoke(callback, payload) { try { callback(payload); } catch (error) { - if (isDevMode) { - console.warn( - "[watchHistoryController] onStateChange handler failed:", - error, - ); - } + devLogger.warn( + "[watchHistoryController] onStateChange handler failed:", + error, + ); } } @@ -104,12 +103,10 @@ export default class WatchHistoryController { try { return derivePointerKey(normalized) || ""; } catch (error) { - if (isDevMode) { - console.warn( - "[watchHistoryController] Failed to derive pointer key:", - error, - ); - } + devLogger.warn( + "[watchHistoryController] Failed to derive pointer key:", + error, + ); return ""; } } @@ -321,12 +318,10 @@ export default class WatchHistoryController { source: reason, }); } catch (updateError) { - if (isDevMode) { - console.warn( - "[watchHistoryController] Failed to update local watch history list:", - updateError, - ); - } + devLogger.warn( + "[watchHistoryController] Failed to update local watch history list:", + updateError, + ); } this.showSuccess( @@ -355,14 +350,12 @@ export default class WatchHistoryController { try { const result = this.watchHistoryService.snapshot(undefined, { reason }); return Promise.resolve(result).catch((error) => { - if (isDevMode) { - console.warn(`[${context}] Watch history flush failed:`, error); + devLogger.warn(`[${context] Watch history flush failed:`, error); } throw error; }); } catch (error) { - if (isDevMode) { - console.warn(`[${context}] Failed to queue watch history flush:`, error); + devLogger.warn(`[${context] Failed to queue watch history flush:`, error); } return Promise.reject(error); } diff --git a/js/ui/zapController.js b/js/ui/zapController.js index d3b95da6..de87aeb0 100644 --- a/js/ui/zapController.js +++ b/js/ui/zapController.js @@ -19,6 +19,7 @@ import { } from "../payments/lnurl.js"; import { getPlatformLightningAddress } from "../payments/platformAddress.js"; import { +import { devLogger, userLogger } from "../utils/logger.js"; ensureWallet as ensureWalletDefault, sendPayment as sendPaymentDefault, } from "../payments/nwcClient.js"; @@ -118,9 +119,7 @@ export default class ZapController { this.resetFeedback(); this.applyDefaultAmount(); this.preloadLightningMetadata().catch((error) => { - if (isDevMode) { - console.warn("[zap] Preload metadata error:", error); - } + devLogger.warn("[zap] Preload metadata error:", error); }); } @@ -238,7 +237,7 @@ export default class ZapController { Promise.resolve() .then(() => this.requestWalletPane()) .catch((error) => { - console.error("Failed to open wallet pane:", error); + userLogger.error("Failed to open wallet pane:", error); }); } } @@ -312,9 +311,7 @@ export default class ZapController { try { await fetchLightningMetadata(lightningAddress); } catch (error) { - if (isDevMode) { - console.warn("[zap] Failed to preload creator metadata:", error); - } + devLogger.warn("[zap] Failed to preload creator metadata:", error); } } @@ -333,18 +330,14 @@ export default class ZapController { }); setCachedPlatformLightningAddress(platformAddress || ""); } catch (error) { - if (isDevMode) { - console.warn("[zap] Failed to load platform Lightning address:", error); - } + devLogger.warn("[zap] Failed to load platform Lightning address:", error); } } if (platformAddress) { try { await fetchLightningMetadata(platformAddress); } catch (error) { - if (isDevMode) { - console.warn("[zap] Failed to preload platform metadata:", error); - } + devLogger.warn("[zap] Failed to preload platform metadata:", error); } } } @@ -428,7 +421,7 @@ export default class ZapController { ? details.retryAttempt : undefined, }; - console.error("[zap] Modal zap failure", summary, error); + userLogger.error("[zap] Modal zap failure", summary, error); }; const lightningAddress = this.getCurrentVideo()?.lightningAddress || ""; @@ -675,17 +668,17 @@ export default class ZapController { overrideFee, }); } catch (error) { - console.error( + userLogger.error( "[zap] Modal lightning context failed", { - amount, - overrideFee, - commentLength: typeof comment === "string" ? comment.length : undefined, - wallet: { - hasUri: Boolean(settings?.nwcUri), - type: - settings?.type || settings?.name || settings?.client || undefined, - }, + amount, + overrideFee, + commentLength: typeof comment === "string" ? comment.length : undefined, + wallet: { + hasUri: Boolean(settings?.nwcUri), + type: + settings?.type || settings?.name || settings?.client || undefined, + }, }, error ); @@ -720,7 +713,7 @@ export default class ZapController { if (Array.isArray(shareTracker) && shareTracker.length) { error.__zapShareTracker = shareTracker; } - console.error( + userLogger.error( "[zap] splitAndZap failed", { amount, @@ -818,7 +811,7 @@ export default class ZapController { const tracker = Array.isArray(error?.__zapShareTracker) ? error.__zapShareTracker : []; - console.error( + userLogger.error( "[zap] Modal zap retry failed", { shareType: share?.type || "unknown", @@ -908,7 +901,7 @@ export default class ZapController { const tracker = Array.isArray(error?.__zapShareTracker) ? error.__zapShareTracker : []; - console.error( + userLogger.error( "[zap] Modal zap attempt failed", { amount, diff --git a/js/urlHealthObserver.js b/js/urlHealthObserver.js index c3746190..0cce8590 100644 --- a/js/urlHealthObserver.js +++ b/js/urlHealthObserver.js @@ -1,5 +1,6 @@ import { createCardObserver } from "./dom/cardObserver.js"; import { safeDecodeURIComponent } from "./utils/safeDecode.js"; +import { userLogger } from "./utils/logger.js"; const ROOT_MARGIN = "0px"; const THRESHOLD = 0.25; @@ -49,7 +50,7 @@ const urlCardObserver = createCardObserver({ try { state.onCheck({ card, badgeEl, url, eventId }); } catch (err) { - console.warn("[urlHealthObserver] onCheck handler failed", err); + userLogger.warn("[urlHealthObserver] onCheck handler failed", err); } }, }); diff --git a/js/userBlocks.js b/js/userBlocks.js index 2703efdb..ecae8a3b 100644 --- a/js/userBlocks.js +++ b/js/userBlocks.js @@ -2,6 +2,7 @@ import { nostrClient } from "./nostr.js"; import { buildBlockListEvent, BLOCK_LIST_IDENTIFIER } from "./nostrEventSchemas.js"; import { +import { userLogger } from "./utils/logger.js"; publishEventToRelays, assertAnyRelayAccepted, } from "./nostrPublish.js"; @@ -74,7 +75,7 @@ class UserBlockListManager { } if (!window?.nostr?.nip04?.decrypt) { - console.warn( + userLogger.warn( "[UserBlockList] nip04.decrypt is unavailable; treating block list as empty." ); this.reset(); @@ -202,7 +203,7 @@ class UserBlockListManager { try { decrypted = await window.nostr.nip04.decrypt(normalized, newest.content); } catch (err) { - console.error("[UserBlockList] Failed to decrypt block list:", err); + userLogger.error("[UserBlockList] Failed to decrypt block list:", err); this.blockedPubkeys.clear(); return; } @@ -225,7 +226,7 @@ class UserBlockListManager { }); this.blockedPubkeys = new Set(sanitized); } catch (err) { - console.error("[UserBlockList] Failed to parse block list:", err); + userLogger.error("[UserBlockList] Failed to parse block list:", err); this.blockedPubkeys.clear(); } }; @@ -247,12 +248,12 @@ class UserBlockListManager { } else { const reason = outcome.reason; if (reason?.code === "timeout") { - console.warn( + userLogger.warn( `[UserBlockList] Relay ${reason.relay} timed out while loading block list (${reason.timeoutMs}ms)` ); } else { const relay = reason?.relay || reason?.relayUrl; - console.error( + userLogger.error( `[UserBlockList] Relay error at ${relay}:`, reason?.error ?? reason ); @@ -267,7 +268,7 @@ class UserBlockListManager { await applyEvents(aggregated, { skipIfEmpty: true }); }) .catch((error) => { - console.error("[UserBlockList] background block list refresh failed:", error); + userLogger.error("[UserBlockList] background block list refresh failed:", error); }); let fastResult = null; @@ -278,13 +279,13 @@ class UserBlockListManager { if (error instanceof AggregateError) { error.errors?.forEach((err) => { if (err?.code === "timeout") { - console.warn( + userLogger.warn( `[UserBlockList] Relay ${err.relay} timed out while loading block list (${err.timeoutMs}ms)` ); } }); } else { - console.error("[UserBlockList] Fast block list fetch failed:", error); + userLogger.error("[UserBlockList] Fast block list fetch failed:", error); } } } @@ -299,7 +300,7 @@ class UserBlockListManager { this.blockEventId = null; background.catch(() => {}); } catch (error) { - console.error("[UserBlockList] loadBlocks failed:", error); + userLogger.error("[UserBlockList] loadBlocks failed:", error); this.blockedPubkeys.clear(); } finally { this.loaded = true; @@ -431,7 +432,7 @@ class UserBlockListManager { if (publishError?.relayFailures?.length) { publishError.relayFailures.forEach( ({ url, error: relayError, reason }) => { - console.error( + userLogger.error( `[UserBlockList] Block list rejected by ${url}: ${reason}`, relayError || reason ); @@ -449,7 +450,7 @@ class UserBlockListManager { : relayError ? String(relayError) : "publish failed"; - console.warn( + userLogger.warn( `[UserBlockList] Block list not accepted by ${url}: ${reason}`, relayError ); diff --git a/js/utils/storage.js b/js/utils/storage.js index 7bd5766f..0cc3ec56 100644 --- a/js/utils/storage.js +++ b/js/utils/storage.js @@ -1,3 +1,4 @@ +import { userLogger } from "./logger.js"; // js/utils/storage.js const URL_HEALTH_STORAGE_PREFIX = "bitvid:urlHealth:"; @@ -21,7 +22,7 @@ export function readUrlHealthFromStorage(eventId) { return parsed; } } catch (err) { - console.warn(`Failed to parse stored URL health for ${eventId}:`, err); + userLogger.warn(`Failed to parse stored URL health for ${eventId}:`, err); } removeUrlHealthFromStorage(eventId); @@ -39,7 +40,7 @@ export function writeUrlHealthToStorage(eventId, entry) { JSON.stringify(entry) ); } catch (err) { - console.warn(`Failed to persist URL health for ${eventId}:`, err); + userLogger.warn(`Failed to persist URL health for ${eventId}:`, err); } } @@ -51,6 +52,6 @@ export function removeUrlHealthFromStorage(eventId) { try { localStorage.removeItem(getUrlHealthStorageKey(eventId)); } catch (err) { - console.warn(`Failed to remove URL health for ${eventId}:`, err); + userLogger.warn(`Failed to remove URL health for ${eventId}:`, err); } } diff --git a/js/viewCounter.js b/js/viewCounter.js index 42f60af0..406bc766 100644 --- a/js/viewCounter.js +++ b/js/viewCounter.js @@ -17,6 +17,7 @@ import { VIEW_COUNT_DEDUPE_WINDOW_SECONDS, } from "./config.js"; import { +import { userLogger } from "./utils/logger.js"; countVideoViewEvents, listVideoViewEvents, subscribeVideoViewEvents, @@ -164,7 +165,7 @@ function normalizePointer(pointer) { } } } catch (error) { - console.warn("[viewCounter] Failed to decode NIP-19 pointer:", error); + userLogger.warn("[viewCounter] Failed to decode NIP-19 pointer:", error); } } } @@ -279,7 +280,7 @@ function restoreCacheSnapshot() { }); } } catch (error) { - console.warn("[viewCounter] Failed to restore cached view counts:", error); + userLogger.warn("[viewCounter] Failed to restore cached view counts:", error); } } @@ -307,7 +308,7 @@ function persistCacheSnapshot() { }; localStorage.setItem(VIEW_COUNTER_STORAGE_KEY, JSON.stringify(payload)); } catch (error) { - console.warn("[viewCounter] Failed to persist view count cache:", error); + userLogger.warn("[viewCounter] Failed to persist view count cache:", error); } } @@ -376,7 +377,7 @@ function notifyHandlers(key) { try { handler(snapshot); } catch (error) { - console.warn("[viewCounter] View handler threw:", error); + userLogger.warn("[viewCounter] View handler threw:", error); } } } @@ -468,15 +469,15 @@ async function hydratePointer(key, listeners) { try { listResult = await listPromise; } catch (error) { - console.warn("[viewCounter] Failed to hydrate view events via list:", error); + userLogger.warn("[viewCounter] Failed to hydrate view events via list:", error); } try { countResult = await countPromise; } catch (error) { if (error?.name === "AbortError") { - console.warn("[viewCounter] View count hydration aborted:", error); + userLogger.warn("[viewCounter] View count hydration aborted:", error); } else { - console.warn("[viewCounter] Failed to count view events:", error); + userLogger.warn("[viewCounter] Failed to count view events:", error); } } let mutated = false; @@ -549,7 +550,7 @@ function ensureLiveSubscription(key, listeners) { try { unsubscribe(); } catch (error) { - console.warn("[viewCounter] Failed to unsubscribe from view events:", error); + userLogger.warn("[viewCounter] Failed to unsubscribe from view events:", error); } listeners.liveUnsub = null; if (!listeners.hydrationPromise) { @@ -558,7 +559,7 @@ function ensureLiveSubscription(key, listeners) { }; setPointerStatus(key, "live"); } catch (error) { - console.warn("[viewCounter] Failed to open live view subscription:", error); + userLogger.warn("[viewCounter] Failed to open live view subscription:", error); } } @@ -583,7 +584,7 @@ export function subscribeToVideoViewCount(pointerInput, handler, options = {}) { status: state.status, }); } catch (error) { - console.warn("[viewCounter] Initial handler invocation threw:", error); + userLogger.warn("[viewCounter] Initial handler invocation threw:", error); } ensureHydration(key, listeners); ensureLiveSubscription(key, listeners); @@ -617,7 +618,7 @@ export function ingestLocalViewEvent({ event, pointer }) { notifyHandlers(key); } } catch (error) { - console.warn("[viewCounter] Failed to ingest local view event:", error); + userLogger.warn("[viewCounter] Failed to ingest local view event:", error); } } diff --git a/js/viewManager.js b/js/viewManager.js index f9ea486d..94545e60 100644 --- a/js/viewManager.js +++ b/js/viewManager.js @@ -4,6 +4,7 @@ import { subscriptions } from "./subscriptions.js"; import { getApplication } from "./applicationContext.js"; import { ASSET_VERSION } from "../config/asset-version.js"; import { applyDesignSystemAttributes } from "./designSystem.js"; +import { devLogger, userLogger } from "./utils/logger.js"; const TRACKING_SCRIPT_PATTERN = /(?:^|\/)tracking\.js(?:$|\?)/; @@ -55,7 +56,7 @@ export async function loadView(viewUrl) { container.appendChild(newScript); }); } catch (err) { - console.error("View loading error:", err); + userLogger.error("View loading error:", err); const fallbackMarkup = `