diff --git a/src/coordinators/avatarCoordinator.js b/src/coordinators/avatarCoordinator.js index 5cc5c232..318f5605 100644 --- a/src/coordinators/avatarCoordinator.js +++ b/src/coordinators/avatarCoordinator.js @@ -13,7 +13,7 @@ import { storeAvatarImage } from '../shared/utils'; import { avatarRequest, miscRequest, queryRequest } from '../api'; -import { AppDebug } from '../services/appConfig'; +import { logWebRequest } from '../services/appConfig'; import { database } from '../services/database'; import { patchAvatarFromEvent } from '../queries'; import { processBulk } from '../services/request'; @@ -295,9 +295,7 @@ export async function lookupAvatars(type, search) { } }); const json = JSON.parse(response.data); - if (AppDebug.debugWebRequests) { - console.log(url, json, response); - } + logWebRequest('[EXTERNAL GET]', url, `(${response.status})`, json); if (response.status === 200 && typeof json === 'object') { json.forEach((avatar) => { if (!avatars.has(avatar.Id)) { @@ -386,9 +384,7 @@ async function lookupAvatarByFileId(providerUrl, fileId) { } }); const json = JSON.parse(response.data); - if (AppDebug.debugWebRequests) { - console.log(url, json, response); - } + logWebRequest('[EXTERNAL GET]', url, `(${response.status})`, json); if (response.status === 200 && typeof json === 'object') { const ref = { authorId: '', @@ -436,9 +432,7 @@ async function lookupAvatarsByAuthor(providerUrl, authorId) { } }); const json = JSON.parse(response.data); - if (AppDebug.debugWebRequests) { - console.log(url, json, response); - } + logWebRequest('[EXTERNAL GET]', url, `(${response.status})`, json); if (response.status === 200 && typeof json === 'object') { json.forEach((avatar) => { const ref = { diff --git a/src/coordinators/gameLogCoordinator.js b/src/coordinators/gameLogCoordinator.js index eb95c295..561e337e 100644 --- a/src/coordinators/gameLogCoordinator.js +++ b/src/coordinators/gameLogCoordinator.js @@ -12,7 +12,7 @@ import { replaceBioSymbols } from '../shared/utils'; import { i18n } from '../plugins/i18n'; -import { AppDebug } from '../services/appConfig'; +import { AppDebug, logWebRequest } from '../services/appConfig'; import { database } from '../services/database'; import { runLastLocationResetFlow, @@ -334,9 +334,7 @@ export function addGameLogEntry(gameLog, location) { vrcxStore.processScreenshot(gameLog.screenshotPath); break; case 'api-request': - if (AppDebug.debugWebRequests) { - console.log('API Request:', gameLog.url); - } + logWebRequest('[GAMELOG API]', gameLog.url); if (advancedSettingsStore.saveInstanceEmoji) { const inv = parseInventoryFromUrl(gameLog.url); if (inv) { diff --git a/src/queries/entityCache.js b/src/queries/entityCache.js index aab3dca2..52dc4933 100644 --- a/src/queries/entityCache.js +++ b/src/queries/entityCache.js @@ -1,3 +1,4 @@ +import { AppDebug, logWebRequest, withQueryLog } from '../services/appConfig'; import { queryClient } from './client'; import { queryKeys } from './keys'; import { toQueryOptions } from './policies'; @@ -151,10 +152,16 @@ export async function fetchWithEntityPolicy({ queryKey, policy, queryFn }) { const data = await queryClient.fetchQuery({ queryKey, - queryFn, + queryFn: () => withQueryLog(queryFn), ...toQueryOptions(policy) }); + if (isFresh) { + logWebRequest('[QUERY CACHE HIT]', queryKey, data); + } else { + logWebRequest('[QUERY FETCH]', queryKey, data); + } + return { data, cache: isFresh diff --git a/src/services/appConfig.js b/src/services/appConfig.js index 7641e6c8..e5fa71fa 100644 --- a/src/services/appConfig.js +++ b/src/services/appConfig.js @@ -26,4 +26,40 @@ window.$debug = AppDebug; window.utils = utils; window.dayjs = dayjs; +/** + * @param {string} tag + * @param {string|unknown[]} target + * @param {...any} rest + */ +export function logWebRequest(tag, target, ...rest) { + if (!AppDebug.debugWebRequests) return; + console.log(tag, target, ...rest); +} + +let _queryLogDepth = 0; + +/** + * Wraps an async fn so that any API request made inside + * will NOT emit the default [API …] debug log (the query + * layer prints its own log instead). + * @template T + * @param {() => Promise} fn + * @returns {Promise} + */ +export async function withQueryLog(fn) { + _queryLogDepth++; + try { + return await fn(); + } finally { + _queryLogDepth--; + } +} + +/** + * @returns {boolean} true when inside a withQueryLog callback + */ +export function isApiLogSuppressed() { + return _queryLogDepth > 0; +} + export { AppDebug }; diff --git a/src/services/request.js b/src/services/request.js index a5c4b975..7dc87346 100644 --- a/src/services/request.js +++ b/src/services/request.js @@ -8,7 +8,7 @@ import { useUserStore } from '../stores'; import { getCurrentUser } from '../coordinators/userCoordinator'; -import { AppDebug } from './appConfig.js'; +import { AppDebug, isApiLogSuppressed, logWebRequest } from './appConfig.js'; import { escapeTag } from '../shared/utils'; import { i18n } from '../plugins/i18n'; import { statusCodes } from '../shared/constants/api.js'; @@ -139,11 +139,17 @@ export function request(endpoint, options) { throw `API request blocked while logged out: ${endpoint}`; } const parsed = parseResponse(response); - if (AppDebug.debugWebRequests) { + if (!isApiLogSuppressed()) { + const tag = `[API ${init.method}]`; if (!parsed.data) { - console.log(init, 'no data', parsed); + logWebRequest(tag, endpoint, `(${parsed.status}) no data`); } else { - console.log(init, 'parsed data', parsed.data); + logWebRequest( + tag, + endpoint, + `(${parsed.status})`, + parsed.data + ); } } if (parsed.hasApiError) { diff --git a/src/stores/settings/advanced.js b/src/stores/settings/advanced.js index 5f4c992a..fb6596d5 100644 --- a/src/stores/settings/advanced.js +++ b/src/stores/settings/advanced.js @@ -3,7 +3,7 @@ import { defineStore } from 'pinia'; import { toast } from 'vue-sonner'; import { useI18n } from 'vue-i18n'; -import { AppDebug } from '../../services/appConfig'; +import { logWebRequest } from '../../services/appConfig'; import { database } from '../../services/database'; import { languageCodes } from '../../localization'; import { useGameStore } from '../game'; @@ -464,9 +464,12 @@ export const useAdvancedSettingsStore = defineStore('AdvancedSettings', () => { } const data = JSON.parse(response.data); - if (AppDebug.debugWebRequests) { - console.log(modelsURL, data, response); - } + logWebRequest( + '[EXTERNAL GET]', + modelsURL, + `(${response.status})`, + data + ); if (data.data && Array.isArray(data.data)) { return data.data @@ -703,9 +706,7 @@ export const useAdvancedSettingsStore = defineStore('AdvancedSettings', () => { } }); const json = JSON.parse(response.data); - if (AppDebug.debugWebRequests) { - console.log(url, json, response); - } + logWebRequest('[EXTERNAL GET]', url, `(${response.status})`, json); if (response.status === 200) { data = json; } else { @@ -753,9 +754,12 @@ export const useAdvancedSettingsStore = defineStore('AdvancedSettings', () => { ); } const data = JSON.parse(response.data); - if (AppDebug.debugWebRequests) { - console.log(url, data, response); - } + logWebRequest( + '[EXTERNAL POST]', + url, + `(${response.status})`, + data + ); return data.data.translations[0].translatedText; } catch (err) { toast.error(`Translation failed: ${err.message}`); @@ -817,9 +821,12 @@ export const useAdvancedSettingsStore = defineStore('AdvancedSettings', () => { } const data = JSON.parse(response.data); - if (AppDebug.debugWebRequests) { - console.log(endpoint, data, response); - } + logWebRequest( + '[EXTERNAL POST]', + endpoint, + `(${response.status})`, + data + ); const translated = data?.choices?.[0]?.message?.content; return typeof translated === 'string' ? translated.trim() : null; diff --git a/src/stores/vrcxUpdater.js b/src/stores/vrcxUpdater.js index cf34046f..5e0a46c6 100644 --- a/src/stores/vrcxUpdater.js +++ b/src/stores/vrcxUpdater.js @@ -3,7 +3,7 @@ import { defineStore } from 'pinia'; import { toast } from 'vue-sonner'; import { useI18n } from 'vue-i18n'; -import { AppDebug } from '../services/appConfig'; +import { logWebRequest } from '../services/appConfig'; import { branches } from '../shared/constants'; import { changeLogRemoveLinks } from '../shared/utils'; @@ -222,9 +222,7 @@ export const useVRCXUpdaterStore = defineStore('VRCXUpdater', () => { return; } pendingVRCXUpdate.value = false; - if (AppDebug.debugWebRequests) { - console.log(url, json, response); - } + logWebRequest('[EXTERNAL GET]', url, `(${response.status})`, json); if (json === Object(json) && json.name && json.published_at) { changeLogDialog.value.buildName = json.name; changeLogDialog.value.changeLog = changeLogRemoveLinks(json.body); @@ -309,9 +307,7 @@ export const useVRCXUpdaterStore = defineStore('VRCXUpdater', () => { ); return; } - if (AppDebug.debugWebRequests) { - console.log(url, json, response); - } + logWebRequest('[EXTERNAL GET]', url, `(${response.status})`, json); const releases = []; if (typeof json !== 'object' || json.message) { toast.error(