@@ -48,7 +48,9 @@ import {
4848 fetchDeveloperGameDetail ,
4949 fetchDeveloperGameResources ,
5050 fetchDeveloperGameSearch ,
51- isTouchGalDeveloperApiConfigured
51+ isTouchGalDeveloperApiConfigured ,
52+ isTouchGalDeveloperApiUsable ,
53+ shouldAttemptTouchGalDeveloperApi
5254} from './developerApi'
5355
5456// Configure logging
@@ -444,7 +446,7 @@ const isLegacySessionUnavailableError = (error: unknown) => {
444446}
445447
446448const shouldReturnDeveloperOnlyEmptyLegacyRead = ( error : unknown ) =>
447- isTouchGalDeveloperApiConfigured ( ) && isLegacySessionUnavailableError ( error )
449+ isTouchGalDeveloperApiUsable ( ) && isLegacySessionUnavailableError ( error )
448450
449451const buildDeveloperOnlyLegacyReadFallback = < T extends Record < string , unknown > > ( fallback : T ) => ( {
450452 ...fallback ,
@@ -453,9 +455,8 @@ const buildDeveloperOnlyLegacyReadFallback = <T extends Record<string, unknown>>
453455} )
454456
455457const getDeveloperModeLegacyRequestConfig = ( ) : TouchGalAxiosRequestConfig =>
456- isTouchGalDeveloperApiConfigured ( )
457- ? { __touchGalSkipChallengeVerification : true }
458- : { }
458+ // Legacy fallbacks should trigger the normal browser verification flow on Cloudflare challenges.
459+ ( { } )
459460
460461const LEGACY_CLOUD_COLLECTION_LOGIN_REQUIRED_MESSAGE =
461462 '云端收藏需要旧站登录;TouchGal Developer API 暂不支持云端收藏写入。'
@@ -2034,12 +2035,7 @@ const fetchLegacyPatchDetail = async (
20342035}
20352036
20362037const fetchLegacyPatchDetailWhenAccessible = async ( uniqueId : string ) => {
2037- if ( ! ( await hasTouchGalClearanceCookie ( ) ) ) {
2038- log . info ( `[API] Skipping legacy detail hydration for ${ uniqueId } ; TouchGal clearance cookie is not available` )
2039- return null
2040- }
2041-
2042- return fetchLegacyPatchDetail ( uniqueId , { skipChallengeVerification : true } )
2038+ return fetchLegacyPatchDetail ( uniqueId )
20432039}
20442040
20452041const cacheFetchedGameDetail = ( uniqueId : string , detail : any ) => {
@@ -2253,16 +2249,45 @@ app.on('window-all-closed', () => {
22532249 }
22542250} )
22552251
2252+ const REDACTED_LOG_VALUE = '[REDACTED]'
2253+ const SENSITIVE_LOG_KEY_PATTERN = / p a s s w o r d | t o k e n | c a p t c h a | c o o k i e | a u t h o r i z a t i o n | a p i [ - _ ] ? k e y | s e c r e t / i
2254+
2255+ const redactForLog = ( value : unknown , seen = new WeakSet < object > ( ) ) : unknown => {
2256+ if ( ! value || typeof value !== 'object' ) return value
2257+
2258+ if ( Array . isArray ( value ) ) {
2259+ return value . map ( ( item ) => redactForLog ( item , seen ) )
2260+ }
2261+
2262+ if ( seen . has ( value ) ) return '[Circular]'
2263+ seen . add ( value )
2264+
2265+ return Object . fromEntries (
2266+ Object . entries ( value as Record < string , unknown > ) . map ( ( [ key , item ] ) => [
2267+ key ,
2268+ SENSITIVE_LOG_KEY_PATTERN . test ( key ) ? REDACTED_LOG_VALUE : redactForLog ( item , seen )
2269+ ] )
2270+ )
2271+ }
2272+
2273+ const redactIpcArgsForLog = ( channel : string , args : unknown [ ] ) => {
2274+ if ( channel === 'tg-login' ) {
2275+ return args . map ( ( ) => REDACTED_LOG_VALUE )
2276+ }
2277+
2278+ return args . map ( ( arg ) => redactForLog ( arg ) )
2279+ }
2280+
22562281// IPC Handlers with Logging
22572282const handleWithLog = ( channel : string , listener : ( ...args : any [ ] ) => any ) => {
22582283 ipcMain . handle ( channel , async ( event , ...args ) => {
2259- log . debug ( `[IPC Request] ${ channel } ` , args )
2284+ log . debug ( `[IPC Request] ${ channel } ` , redactIpcArgsForLog ( channel , args ) )
22602285 try {
22612286 const result = await listener ( event , ...args )
22622287 log . debug ( `[IPC Response] ${ channel } ` , { success : true } )
22632288 return result
22642289 } catch ( error ) {
2265- log . error ( `[IPC Error] ${ channel } ` , error )
2290+ log . error ( `[IPC Error] ${ channel } ` , getSafeErrorMessage ( error ) )
22662291 throw error
22672292 }
22682293 } )
@@ -2476,7 +2501,8 @@ handleWithLog('tg-fetch-resources', async (_event, page: number, limit: number,
24762501 log . warn ( '[API] selectedTags received by tg-fetch-resources; ignoring upstream tag filtering and relying on local advanced pipeline' ) ;
24772502 }
24782503
2479- // Use the standard /galgame (GET) endpoint only.
2504+ // Home feed intentionally keeps the legacy /galgame endpoint first: the
2505+ // Developer API does not currently expose an equivalent general feed.
24802506 // Tag filtering is intentionally NOT delegated upstream because /galgame tagString is unreliable
24812507 // and /search has retrieval semantics that do not match strict local filtering.
24822508 // Advanced Year Logic Translation (Intersection of all constraints)
@@ -2534,7 +2560,7 @@ handleWithLog('tg-fetch-resources', async (_event, page: number, limit: number,
25342560 return normalized
25352561 } catch ( err : any ) {
25362562 log . error ( '[API] GET /galgame error:' , err . response ?. data || err . message ) ;
2537- if ( isTouchGalDeveloperApiConfigured ( ) ) {
2563+ if ( shouldAttemptTouchGalDeveloperApi ( ) ) {
25382564 try {
25392565 const fallback = await fetchDeveloperBrowseFallback ( page , limit , query )
25402566 if ( fallback . list . length > 0 ) {
@@ -2587,7 +2613,7 @@ handleWithLog('tg-search-resources', async (_event, keyword: string, page: numbe
25872613 }
25882614 }
25892615
2590- if ( isTouchGalDeveloperApiConfigured ( ) && ! preferLegacySearch ) {
2616+ if ( shouldAttemptTouchGalDeveloperApi ( ) && ! preferLegacySearch ) {
25912617 try {
25922618 return await fetchFromDeveloperApi ( )
25932619 } catch ( error ) {
@@ -2611,16 +2637,14 @@ handleWithLog('tg-search-resources', async (_event, keyword: string, page: numbe
26112637
26122638 return normalized
26132639 } catch ( error ) {
2614- if ( ! isTouchGalDeveloperApiConfigured ( ) ) {
2615- throw error
2616- }
2617-
26182640 if ( preferLegacySearch ) {
26192641 log . warn ( '[API] Legacy /search failed for optioned search; returning Developer API keyword results:' , getSafeErrorMessage ( error ) )
2620- try {
2621- return await fetchFromDeveloperApi ( true )
2622- } catch ( fallbackError ) {
2623- log . warn ( '[Developer API] Search fallback failed after legacy /search error; trying local cache:' , getSafeErrorMessage ( fallbackError ) )
2642+ if ( shouldAttemptTouchGalDeveloperApi ( ) ) {
2643+ try {
2644+ return await fetchFromDeveloperApi ( true )
2645+ } catch ( fallbackError ) {
2646+ log . warn ( '[Developer API] Search fallback failed after legacy /search error; trying local cache:' , getSafeErrorMessage ( fallbackError ) )
2647+ }
26242648 }
26252649 } else {
26262650 log . warn ( '[API] Legacy /search failed after Developer API search error; trying local cache:' , getSafeErrorMessage ( error ) )
@@ -2642,7 +2666,7 @@ handleWithLog('tg-get-patch-detail', async (_event, uniqueId: string) => {
26422666 }
26432667
26442668 let developerDetail : any | null = null
2645- if ( isTouchGalDeveloperApiConfigured ( ) ) {
2669+ if ( shouldAttemptTouchGalDeveloperApi ( ) ) {
26462670 try {
26472671 developerDetail = await fetchDeveloperGameDetail ( uniqueId )
26482672 } catch ( error ) {
@@ -2790,7 +2814,7 @@ handleWithLog('tg-get-patch-ratings', async (_event, patchId: number, page: numb
27902814} )
27912815
27922816handleWithLog ( 'tg-get-patch-introduction' , async ( _event , uniqueId : string ) => {
2793- if ( isTouchGalDeveloperApiConfigured ( ) ) {
2817+ if ( shouldAttemptTouchGalDeveloperApi ( ) ) {
27942818 try {
27952819 const detail = await fetchDeveloperGameDetail ( uniqueId )
27962820 return buildPatchIntroductionFromDetail ( detail )
@@ -2866,7 +2890,7 @@ handleWithLog('tg-match-folder', async (_event, folderName: string) => {
28662890 }
28672891
28682892 const localMatches = mergeRows ( aliasMatches , results as Array < any > )
2869- if ( localMatches . length > 0 || ! isTouchGalDeveloperApiConfigured ( ) ) {
2893+ if ( localMatches . length > 0 || ! shouldAttemptTouchGalDeveloperApi ( ) ) {
28702894 return localMatches
28712895 }
28722896
@@ -3170,7 +3194,7 @@ handleWithLog('tg-search-tags', async (_event, keyword: string) => {
31703194 if ( query . length === 0 ) return [ ]
31713195
31723196 const cachedSuggestions = buildCachedTagSuggestions ( keyword )
3173- if ( isTouchGalDeveloperApiConfigured ( ) ) {
3197+ if ( shouldAttemptTouchGalDeveloperApi ( ) ) {
31743198 if ( cachedSuggestions . length > 0 ) return cachedSuggestions
31753199
31763200 try {
@@ -3209,7 +3233,7 @@ handleWithLog('tg-get-user-status-self', async () => {
32093233 const response = await API_CLIENT . get ( '/user/status' , getDeveloperModeLegacyRequestConfig ( ) )
32103234 return ensureValidResponse ( response . data )
32113235 } catch ( error ) {
3212- if ( ! isTouchGalDeveloperApiConfigured ( ) ) {
3236+ if ( ! isTouchGalDeveloperApiUsable ( ) ) {
32133237 throw error
32143238 }
32153239 log . warn ( '[API] Legacy /user/status failed; treating TouchGal user session as unavailable:' , getSafeErrorMessage ( error ) )
@@ -3221,6 +3245,7 @@ handleWithLog('tg-get-developer-api-status', async () => {
32213245 if ( ! isTouchGalDeveloperApiConfigured ( ) ) {
32223246 return {
32233247 configured : false ,
3248+ usable : false ,
32243249 isDeveloperApiCredential : true ,
32253250 applicationStatus : 'missing' ,
32263251 dailyLimit : null ,
0 commit comments