@@ -21,6 +21,7 @@ import {
2121 MonthlyLimitError ,
2222 UserLimitError ,
2323 ModelError ,
24+ RateLimitError ,
2425 FreeUsageLimitError ,
2526 SubscriptionUsageLimitError ,
2627} from "./error"
@@ -35,7 +36,8 @@ import { anthropicHelper } from "./provider/anthropic"
3536import { googleHelper } from "./provider/google"
3637import { openaiHelper } from "./provider/openai"
3738import { oaCompatHelper } from "./provider/openai-compatible"
38- import { createRateLimiter } from "./rateLimiter"
39+ import { createRateLimiter as createIpRateLimiter } from "./ipRateLimiter"
40+ import { createRateLimiter as createKeyRateLimiter } from "./keyRateLimiter"
3941import { createDataDumper } from "./dataDumper"
4042import { createTrialLimiter } from "./trialLimiter"
4143import { createStickyTracker } from "./stickyProviderTracker"
@@ -92,6 +94,8 @@ export async function handler(
9294 const isStream = opts . parseIsStream ( url , body )
9395 const rawIp = input . request . headers . get ( "x-real-ip" ) ?? ""
9496 const ip = rawIp . includes ( ":" ) ? rawIp . split ( ":" ) . slice ( 0 , 4 ) . join ( ":" ) : rawIp
97+ const rawZenApiKey = opts . parseApiKey ( input . request . headers )
98+ const zenApiKey = rawZenApiKey === "public" ? undefined : rawZenApiKey
9599 const sessionId = input . request . headers . get ( "x-opencode-session" ) ?? ""
96100 const requestId = input . request . headers . get ( "x-opencode-request" ) ?? ""
97101 const projectId = input . request . headers . get ( "x-opencode-project" ) ?? ""
@@ -108,17 +112,13 @@ export async function handler(
108112 const dataDumper = createDataDumper ( sessionId , requestId , projectId )
109113 const trialLimiter = createTrialLimiter ( modelInfo . trialProvider , ip )
110114 const trialProviders = await trialLimiter ?. check ( )
111- const rateLimiter = createRateLimiter (
112- modelInfo . id ,
113- modelInfo . allowAnonymous ,
114- modelInfo . rateLimit ,
115- ip ,
116- input . request ,
117- )
115+ const rateLimiter = modelInfo . allowAnonymous
116+ ? createIpRateLimiter ( modelInfo . id , modelInfo . rateLimit , ip , input . request )
117+ : createKeyRateLimiter ( modelInfo . id , zenApiKey , input . request )
118118 await rateLimiter ?. check ( )
119119 const stickyTracker = createStickyTracker ( modelInfo . stickyProvider , sessionId )
120120 const stickyProvider = await stickyTracker ?. get ( )
121- const authInfo = await authenticate ( modelInfo )
121+ const authInfo = await authenticate ( modelInfo , zenApiKey )
122122 const billingSource = validateBilling ( authInfo , modelInfo )
123123 logger . metric ( { source : billingSource } )
124124
@@ -363,7 +363,11 @@ export async function handler(
363363 { status : 401 } ,
364364 )
365365
366- if ( error instanceof FreeUsageLimitError || error instanceof SubscriptionUsageLimitError ) {
366+ if (
367+ error instanceof RateLimitError ||
368+ error instanceof FreeUsageLimitError ||
369+ error instanceof SubscriptionUsageLimitError
370+ ) {
367371 const headers = new Headers ( )
368372 if ( error . retryAfter ) {
369373 headers . set ( "retry-after" , String ( error . retryAfter ) )
@@ -492,9 +496,8 @@ export async function handler(
492496 }
493497 }
494498
495- async function authenticate ( modelInfo : ModelInfo ) {
496- const apiKey = opts . parseApiKey ( input . request . headers )
497- if ( ! apiKey || apiKey === "public" ) {
499+ async function authenticate ( modelInfo : ModelInfo , zenApiKey ?: string ) {
500+ if ( ! zenApiKey ) {
498501 if ( modelInfo . allowAnonymous ) return
499502 throw new AuthError ( t ( "zen.api.error.missingApiKey" ) )
500503 }
@@ -573,7 +576,7 @@ export async function handler(
573576 isNull ( LiteTable . timeDeleted ) ,
574577 ) ,
575578 )
576- . where ( and ( eq ( KeyTable . key , apiKey ) , isNull ( KeyTable . timeDeleted ) ) )
579+ . where ( and ( eq ( KeyTable . key , zenApiKey ) , isNull ( KeyTable . timeDeleted ) ) )
577580 . then ( ( rows ) => rows [ 0 ] ) ,
578581 )
579582
0 commit comments