@@ -2,7 +2,12 @@ import type { AnyEventRequest } from '@workflow/world';
22import { encode } from 'cbor-x' ;
33import { MockAgent } from 'undici' ;
44import { describe , expect , it } from 'vitest' ;
5- import { createWorkflowRunEvent , splitEventDataForV4 } from './events.js' ;
5+ import {
6+ createWorkflowRunEvent ,
7+ getWorkflowRunEvents ,
8+ splitEventDataForV4 ,
9+ } from './events.js' ;
10+ import { encodeFrame , V4_FRAME_CONTENT_TYPE } from './frames.js' ;
611
712const ORIGIN = 'https://vercel-workflow.com' ;
813
@@ -344,3 +349,82 @@ describe('createWorkflowRunEvent resolveData', () => {
344349 agent . assertNoPendingInterceptors ( ) ;
345350 } ) ;
346351} ) ;
352+
353+ describe ( 'getWorkflowRunEvents remoteRefBehavior mapping' , ( ) => {
354+ // A v4 LIST response: one run_created frame (with payload body) + sentinel.
355+ function listResponse ( body : Uint8Array ) : Buffer {
356+ return Buffer . concat ( [
357+ encodeFrame (
358+ {
359+ eventId : 'evnt_1' ,
360+ runId : 'wrun_1' ,
361+ eventType : 'run_created' ,
362+ createdAt : '2026-06-10T00:00:00.000Z' ,
363+ eventData : {
364+ input : { _type : 'RemoteRef' , _ref : 's3rf:wrun_1/input' } ,
365+ workflowName : 'wf' ,
366+ } ,
367+ } ,
368+ body
369+ ) ,
370+ encodeFrame ( { _end : 1 } , new Uint8Array ( 0 ) ) ,
371+ ] ) ;
372+ }
373+
374+ it ( "sends remoteRefBehavior=lazy for resolveData 'none' and strips any returned body" , async ( ) => {
375+ const agent = mockAgent ( ) ;
376+ // The interceptor only matches when the request carries
377+ // ?remoteRefBehavior=lazy — so a missing/wrong param fails the request.
378+ // The reply still includes payload bytes, simulating a backend that
379+ // predates the flag: the adapter must strip them regardless.
380+ agent
381+ . get ( ORIGIN )
382+ . intercept ( {
383+ path : '/api/v4/runs/wrun_1/events' ,
384+ method : 'GET' ,
385+ query : { remoteRefBehavior : 'lazy' } ,
386+ } )
387+ . reply ( 200 , listResponse ( new TextEncoder ( ) . encode ( '"payload"' ) ) , {
388+ headers : { 'content-type' : V4_FRAME_CONTENT_TYPE } ,
389+ } ) ;
390+
391+ const result = await getWorkflowRunEvents (
392+ { runId : 'wrun_1' , resolveData : 'none' } ,
393+ { token : 'test-token' , dispatcher : agent }
394+ ) ;
395+
396+ const eventData = (
397+ result . data [ 0 ] as { eventData ?: Record < string , unknown > }
398+ ) . eventData ;
399+ expect ( eventData ?. input ) . toBeUndefined ( ) ;
400+ expect ( eventData ?. workflowName ) . toBe ( 'wf' ) ;
401+ agent . assertNoPendingInterceptors ( ) ;
402+ } ) ;
403+
404+ it ( 'sends remoteRefBehavior=resolve by default and splices the body bytes' , async ( ) => {
405+ const agent = mockAgent ( ) ;
406+ const body = new TextEncoder ( ) . encode ( '"payload"' ) ;
407+ agent
408+ . get ( ORIGIN )
409+ . intercept ( {
410+ path : '/api/v4/runs/wrun_1/events' ,
411+ method : 'GET' ,
412+ query : { remoteRefBehavior : 'resolve' } ,
413+ } )
414+ . reply ( 200 , listResponse ( body ) , {
415+ headers : { 'content-type' : V4_FRAME_CONTENT_TYPE } ,
416+ } ) ;
417+
418+ // No resolveData → defaults to 'all' → resolve.
419+ const result = await getWorkflowRunEvents (
420+ { runId : 'wrun_1' } ,
421+ { token : 'test-token' , dispatcher : agent }
422+ ) ;
423+
424+ const eventData = (
425+ result . data [ 0 ] as { eventData ?: Record < string , unknown > }
426+ ) . eventData ;
427+ expect ( eventData ?. input ) . toEqual ( body ) ;
428+ agent . assertNoPendingInterceptors ( ) ;
429+ } ) ;
430+ } ) ;
0 commit comments