@@ -94,6 +94,39 @@ function fetchInputUrl(fetchMock: ReturnType<typeof vi.fn>, index: number): stri
9494 return input . url ;
9595}
9696
97+ function oversizedJsonResponse ( params : { chunkCount : number ; chunkSize : number } ) : {
98+ response : Response ;
99+ getReadCount : ( ) => number ;
100+ wasCanceled : ( ) => boolean ;
101+ } {
102+ const chunk = new Uint8Array ( params . chunkSize ) ;
103+ let readCount = 0 ;
104+ let canceled = false ;
105+ return {
106+ response : new Response (
107+ new ReadableStream < Uint8Array > ( {
108+ pull ( controller ) {
109+ if ( readCount >= params . chunkCount ) {
110+ controller . close ( ) ;
111+ return ;
112+ }
113+ readCount += 1 ;
114+ controller . enqueue ( chunk ) ;
115+ } ,
116+ cancel ( ) {
117+ canceled = true ;
118+ } ,
119+ } ) ,
120+ {
121+ status : 200 ,
122+ headers : { "Content-Type" : "application/json" } ,
123+ } ,
124+ ) ,
125+ getReadCount : ( ) => readCount ,
126+ wasCanceled : ( ) => canceled ,
127+ } ;
128+ }
129+
97130let ssrfMock : { mockRestore : ( ) => void } | undefined ;
98131
99132describe ( "google video generation provider" , ( ) => {
@@ -486,6 +519,33 @@ describe("google video generation provider", () => {
486519 expect ( result . videos [ 0 ] ?. buffer ) . toEqual ( Buffer . from ( "rest-video" ) ) ;
487520 } ) ;
488521
522+ it ( "bounds successful Google REST operation JSON bodies instead of buffering the whole response" , async ( ) => {
523+ vi . spyOn ( providerAuthRuntime , "resolveApiKeyForProvider" ) . mockResolvedValue ( {
524+ apiKey : "google-key" ,
525+ source : "env" ,
526+ mode : "api-key" ,
527+ } ) ;
528+ generateVideosMock . mockRejectedValue ( Object . assign ( new Error ( "sdk 404" ) , { status : 404 } ) ) ;
529+ const streamed = oversizedJsonResponse ( { chunkCount : 64 , chunkSize : 1024 * 1024 } ) ;
530+ const fetchMock = vi . fn ( async ( ) => streamed . response ) ;
531+ vi . stubGlobal ( "fetch" , fetchMock ) ;
532+
533+ const provider = buildGoogleVideoGenerationProvider ( ) ;
534+ await expect (
535+ provider . generateVideo ( {
536+ provider : "google" ,
537+ model : "veo-3.1-fast-generate-preview" ,
538+ prompt : "A tiny robot watering a windowsill garden" ,
539+ cfg : { } ,
540+ durationSeconds : 3 ,
541+ } ) ,
542+ ) . rejects . toThrow ( "Google video operation response exceeds 16777216 bytes" ) ;
543+
544+ expect ( fetchMock ) . toHaveBeenCalledTimes ( 1 ) ;
545+ expect ( streamed . getReadCount ( ) ) . toBeLessThan ( 64 ) ;
546+ expect ( streamed . wasCanceled ( ) ) . toBe ( true ) ;
547+ } ) ;
548+
489549 it ( "retries transient Google REST poll failures with empty bodies" , async ( ) => {
490550 vi . useFakeTimers ( ) ;
491551 vi . spyOn ( providerAuthRuntime , "resolveApiKeyForProvider" ) . mockResolvedValue ( {
0 commit comments