@@ -19,7 +19,7 @@ import {
1919} from "../../services/sentry" ;
2020import { executeSearch } from "../../search/execute" ;
2121import type { BillingMetadata } from "../../services/billing/types" ;
22- import { getSearchZDR } from "../../lib/zdr-helpers" ;
22+ import { getSearchForcedKind , getSearchZDR } from "../../lib/zdr-helpers" ;
2323
2424export async function searchController (
2525 req : RequestWithAuth < { } , SearchResponse , SearchRequest > ,
@@ -30,28 +30,23 @@ export async function searchController(
3030 const controllerStartTime = new Date ( ) . getTime ( ) ;
3131
3232 const jobId = uuidv7 ( ) ;
33+ const searchZDRMode = getSearchZDR ( req . acuc ?. flags ) ;
34+ const teamForcedKind = getSearchForcedKind ( req . acuc ?. flags ) ;
3335 let logger = _logger . child ( {
3436 jobId,
3537 teamId : req . auth . team_id ,
3638 module : "api/v2" ,
3739 method : "searchController" ,
38- zeroDataRetention : getSearchZDR ( req . acuc ?. flags ) === "forced" ,
40+ zeroDataRetention : teamForcedKind !== null ,
41+ teamForcedKind,
3942 } ) ;
4043
41- if ( getSearchZDR ( req . acuc ?. flags ) === "forced" ) {
42- return res . status ( 400 ) . json ( {
43- success : false ,
44- error :
45- "Your team has zero data retention enabled. This is not supported on search. Please contact support@firecrawl.com to unblock this feature." ,
46- } ) ;
47- }
48-
4944 const middlewareTime = controllerStartTime - middlewareStartTime ;
5045 const isSearchPreview =
5146 config . SEARCH_PREVIEW_TOKEN !== undefined &&
5247 config . SEARCH_PREVIEW_TOKEN === req . body . __searchPreviewToken ;
5348
54- let zeroDataRetention = false ;
49+ let zeroDataRetention = teamForcedKind !== null ;
5550
5651 try {
5752 req . body = searchRequestSchema . parse ( req . body ) ;
@@ -84,16 +79,25 @@ export async function searchController(
8479 origin : req . body . origin ,
8580 } ) ;
8681
82+ // Inject the team-forced enterprise mode so downstream billing,
83+ // upstream routing, and ZDR cleanup all see it.
84+ if ( teamForcedKind ) {
85+ const existing = req . body . enterprise ?? [ ] ;
86+ if ( ! existing . includes ( teamForcedKind ) ) {
87+ req . body . enterprise = [ ...existing , teamForcedKind ] ;
88+ }
89+ }
90+
8791 const isZDR = req . body . enterprise ?. includes ( "zdr" ) ;
8892 const isAnon = req . body . enterprise ?. includes ( "anon" ) ;
8993 const isZDROrAnon = isZDR || isAnon ;
9094 zeroDataRetention = isZDROrAnon ?? false ;
91- applyZdrScope ( isZDROrAnon ?? false ) ;
95+ logger = logger . child ( { zeroDataRetention } ) ;
96+ applyZdrScope ( zeroDataRetention ) ;
9297
9398 // Verify the team has searchZDR enabled before allowing enterprise ZDR/anon
94- if ( isZDROrAnon ) {
95- const searchMode = getSearchZDR ( req . acuc ?. flags ) ;
96- if ( searchMode !== "allowed" && searchMode !== "forced" ) {
99+ if ( isZDROrAnon && ! teamForcedKind ) {
100+ if ( searchZDRMode !== "allowed" ) {
97101 return res . status ( 403 ) . json ( {
98102 success : false ,
99103 error :
@@ -111,7 +115,7 @@ export async function searchController(
111115 origin : req . body . origin ?? "api" ,
112116 integration : req . body . integration ,
113117 target_hint : req . body . query ,
114- zeroDataRetention : isZDROrAnon ?? false ,
118+ zeroDataRetention,
115119 api_key_id : req . acuc ?. api_key_id ?? null ,
116120 } ) ;
117121 }
@@ -142,7 +146,7 @@ export async function searchController(
142146 jobId,
143147 apiVersion : "v2" ,
144148 bypassBilling : ! shouldBill ,
145- zeroDataRetention : isZDROrAnon ,
149+ zeroDataRetention,
146150 billing,
147151 agentIndexOnly : ( req as any ) . agentIndexOnly ?? false ,
148152 } ,
@@ -180,7 +184,7 @@ export async function searchController(
180184 team_id : req . auth . team_id ,
181185 options : req . body ,
182186 credits_cost : shouldBill ? result . searchCredits : 0 ,
183- zeroDataRetention : isZDROrAnon ?? false ,
187+ zeroDataRetention,
184188 } ,
185189 false ,
186190 ) ;
0 commit comments