@@ -6,11 +6,19 @@ import {
66 getSessionState ,
77 requestSession ,
88} from '@/server/free-session/public-api'
9- import { getFreeModeCountryAccess } from '@/server/free-mode-country'
9+ import { getSessionRow as getStoredSessionRow } from '@/server/free-session/store'
10+ import {
11+ FREE_MODE_ALLOWED_COUNTRIES ,
12+ getFreeModeCountryAccess ,
13+ IPINFO_PRIVACY_CACHE_TTL_MS ,
14+ } from '@/server/free-mode-country'
1015import { extractApiKeyFromHeader } from '@/util/auth'
1116
1217import type { FreeModeCountryAccess } from '@/server/free-mode-country'
13- import type { FreeSessionCountryAccessMetadata } from '@/server/free-session/types'
18+ import type {
19+ FreeSessionCountryAccessMetadata ,
20+ InternalSessionRow ,
21+ } from '@/server/free-session/types'
1422import type { SessionDeps } from '@/server/free-session/public-api'
1523import type { GetUserInfoFromApiKeyFn } from '@codebuff/common/types/contracts/database'
1624import type { Logger } from '@codebuff/common/types/contracts/logger'
@@ -57,10 +65,10 @@ function toSessionCountryAccess(
5765async function countryBlockedResponse (
5866 req : NextRequest ,
5967 deps : FreebuffSessionDeps ,
60- ) : Promise <
61- | { response : NextResponse ; countryAccess : FreeModeCountryAccess }
62- | { response : null ; countryAccess : FreeModeCountryAccess }
63- > {
68+ ) : Promise < {
69+ response : NextResponse | null
70+ countryAccess : FreeModeCountryAccess
71+ } > {
6472 const countryAccess = await getCountryAccess ( req , deps )
6573 if ( countryAccess . allowed ) {
6674 return { response : null , countryAccess }
@@ -79,6 +87,32 @@ async function countryBlockedResponse(
7987 }
8088}
8189
90+ function hasRecentAllowedCountryCheck (
91+ row : InternalSessionRow | null ,
92+ now : Date ,
93+ ) : boolean {
94+ if ( ! row ?. country_checked_at || row . country_block_reason !== null ) {
95+ return false
96+ }
97+ if ( ! row . country_code || ! FREE_MODE_ALLOWED_COUNTRIES . has ( row . country_code ) ) {
98+ return false
99+ }
100+ return (
101+ now . getTime ( ) - row . country_checked_at . getTime ( ) <
102+ IPINFO_PRIVACY_CACHE_TTL_MS
103+ )
104+ }
105+
106+ async function shouldSkipGetCountryCheck (
107+ userId : string ,
108+ deps : FreebuffSessionDeps ,
109+ ) : Promise < boolean > {
110+ const getSessionRow = deps . sessionDeps ?. getSessionRow ?? getStoredSessionRow
111+ const row = await getSessionRow ( userId )
112+ const now = deps . sessionDeps ?. now ?.( ) ?? new Date ( )
113+ return hasRecentAllowedCountryCheck ( row , now )
114+ }
115+
82116/** Header the CLI uses to identify which instance is polling. Used by GET to
83117 * detect when another CLI on the same account has rotated the id. */
84118export const FREEBUFF_INSTANCE_HEADER = 'x-freebuff-instance-id'
@@ -220,10 +254,12 @@ export async function getFreebuffSession(
220254 const auth = await resolveUser ( req , deps )
221255 if ( 'error' in auth ) return auth . error
222256
223- const { response : blocked } = await countryBlockedResponse ( req , deps )
224- if ( blocked ) return blocked
225-
226257 try {
258+ if ( ! ( await shouldSkipGetCountryCheck ( auth . userId , deps ) ) ) {
259+ const { response : blocked } = await countryBlockedResponse ( req , deps )
260+ if ( blocked ) return blocked
261+ }
262+
227263 const claimedInstanceId =
228264 req . headers . get ( FREEBUFF_INSTANCE_HEADER ) ?? undefined
229265 const state = await getSessionState ( {
0 commit comments