Skip to content

Commit 2cdfae3

Browse files
jahoomaclaude
andcommitted
Add dev-only env to force Freebuff limited mode
Set FREEBUFF_DEV_FORCE_LIMITED=true on localhost to make free-mode country resolution return allowed=false, so the limited tier UX can be exercised without a real geo block. Honored only when NEXT_PUBLIC_CB_ENVIRONMENT === 'dev'; cache lookups are bypassed for forced-limited requests so toggling the flag takes effect immediately. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 793de91 commit 2cdfae3

5 files changed

Lines changed: 36 additions & 1 deletion

File tree

packages/internal/src/env-schema.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,14 @@ export const serverEnvSchema = clientEnvSchema.extend({
6969
.int()
7070
.positive()
7171
.default(60 * 60 * 1000),
72+
73+
// Dev-only override: when 'true', force free-mode requests to the 'limited'
74+
// access tier so the limited UX (single DeepSeek Flash model) can be
75+
// exercised on localhost. Ignored unless NEXT_PUBLIC_CB_ENVIRONMENT === 'dev'.
76+
FREEBUFF_DEV_FORCE_LIMITED: z
77+
.enum(['true', 'false'])
78+
.default('false')
79+
.transform((v) => v === 'true'),
7280
})
7381
export const serverEnvVars = serverEnvSchema.keyof().options
7482
export type ServerEnvVar = (typeof serverEnvVars)[number]
@@ -131,4 +139,5 @@ export const serverProcessEnv: ServerInput = {
131139
// Freebuff waiting room
132140
FREEBUFF_WAITING_ROOM_ENABLED: process.env.FREEBUFF_WAITING_ROOM_ENABLED,
133141
FREEBUFF_SESSION_LENGTH_MS: process.env.FREEBUFF_SESSION_LENGTH_MS,
142+
FREEBUFF_DEV_FORCE_LIMITED: process.env.FREEBUFF_DEV_FORCE_LIMITED,
134143
}

web/src/app/api/v1/chat/completions/_post.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,9 @@ export async function postChatCompletions(params: {
332332
ipinfoToken: env.IPINFO_TOKEN,
333333
ipHashSecret: env.NEXTAUTH_SECRET,
334334
allowLocalhost: env.NEXT_PUBLIC_CB_ENVIRONMENT === 'dev',
335+
forceLimited:
336+
env.NEXT_PUBLIC_CB_ENVIRONMENT === 'dev' &&
337+
env.FREEBUFF_DEV_FORCE_LIMITED,
335338
})
336339
freebuffAccessTier = getFreeModeAccessTier(countryAccess)
337340

web/src/app/api/v1/freebuff/session/_handlers.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ async function getCountryAccess(
3737
ipinfoToken: env.IPINFO_TOKEN,
3838
ipHashSecret: env.NEXTAUTH_SECRET,
3939
allowLocalhost: env.NEXT_PUBLIC_CB_ENVIRONMENT === 'dev',
40+
forceLimited:
41+
env.NEXT_PUBLIC_CB_ENVIRONMENT === 'dev' &&
42+
env.FREEBUFF_DEV_FORCE_LIMITED,
4043
},
4144
})
4245
)

web/src/server/free-mode-country-access-cache.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ export async function getCachedFreeModeCountryAccess(params: {
146146
const clientIp = extractClientIp(req)
147147
const clientIpHash = hashClientIp(clientIp, options.ipHashSecret)
148148

149-
if (clientIpHash) {
149+
if (clientIpHash && !options.forceLimited) {
150150
try {
151151
const cached = await cacheStore.get({
152152
userId,

web/src/server/free-mode-country.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,12 @@ export type FreeModeCountryAccessOptions = {
7373
ipinfoToken: string
7474
ipHashSecret?: string
7575
allowLocalhost?: boolean
76+
/** Dev-only escape hatch: when true (and `allowLocalhost` is also true),
77+
* the localhost bypass returns `allowed: false` so callers exercise the
78+
* limited Freebuff tier instead of full. Cache writes/reads are skipped
79+
* for these requests (clientIpHash is nulled) so flipping the flag takes
80+
* effect on the next request without manual cache eviction. */
81+
forceLimited?: boolean
7682
}
7783

7884
const LOCALHOST_IPS = new Set(['::1', '::ffff:127.0.0.1'])
@@ -216,6 +222,20 @@ export async function getFreeModeCountryAccess(
216222
!cfCountry &&
217223
(!clientIp || isLocalhostIp(clientIp))
218224
) {
225+
if (options.forceLimited) {
226+
return {
227+
allowed: false,
228+
countryCode: 'US',
229+
blockReason: 'country_not_allowed',
230+
cfCountry: null,
231+
geoipCountry: null,
232+
ipPrivacy: { signals: [] },
233+
hasClientIp: Boolean(clientIp),
234+
// Null hash skips the country-access cache so toggling the env var
235+
// takes effect immediately without evicting prior allowed=true rows.
236+
clientIpHash: null,
237+
}
238+
}
219239
return {
220240
allowed: true,
221241
countryCode: 'US',

0 commit comments

Comments
 (0)