11import { describe , it , expect , vi , beforeEach , afterEach } from 'vitest' ;
2- import { attachDevToolsBridge , nodeToSdkData } from './bridge.js' ;
2+ import { attachDaVinciBridge , nodeToSdkData } from './davinci- bridge.js' ;
33import { DEVTOOLS_EVENT_NAME } from './emit.js' ;
44import type { AuthEvent } from '@wolfcola/devtools-types' ;
55
@@ -100,13 +100,22 @@ describe('nodeToSdkData', () => {
100100 const result = nodeToSdkData ( { status : 'continue' , cache : null } as never , undefined ) ;
101101 expect ( result . requestId ) . toBeUndefined ( ) ;
102102 } ) ;
103+
104+ it ( 'passes responseBody through to the result' , ( ) => {
105+ const body = { access_token : 'tok-abc' , token_type : 'Bearer' } ;
106+ const result = nodeToSdkData ( { status : 'success' } , 'continue' , body ) ;
107+ expect ( result . responseBody ) . toBe ( body ) ;
108+ } ) ;
103109} ) ;
104110
105111// ---------------------------------------------------------------------------
106112// Mock client factory
107113// ---------------------------------------------------------------------------
108114
109- function makeClient ( initialNode : Record < string , unknown > ) {
115+ function makeClient (
116+ initialNode : Record < string , unknown > ,
117+ cache ?: { getCache : ( key : string ) => unknown } ,
118+ ) {
110119 let listener : ( ( ) => void ) | null = null ;
111120 let node = initialNode ;
112121 return {
@@ -117,6 +126,7 @@ function makeClient(initialNode: Record<string, unknown>) {
117126 } ;
118127 } ) ,
119128 getNode : vi . fn ( ( ) => node ) ,
129+ cache,
120130 /** Test helper: update internal node and fire the subscribed listener. */
121131 trigger : ( newNode : Record < string , unknown > ) => {
122132 node = newNode ;
@@ -140,7 +150,7 @@ function captureDevtoolsEvents(): { events: CustomEvent<AuthEvent>[]; stop: () =
140150// Tests
141151// ---------------------------------------------------------------------------
142152
143- describe ( 'attachDevToolsBridge ' , ( ) => {
153+ describe ( 'attachDaVinciBridge ' , ( ) => {
144154 beforeEach ( ( ) => {
145155 // Simulate extension presence for all tests except the no-op test.
146156 ( window as unknown as Record < string , unknown > ) [ '__PING_DEVTOOLS_EXTENSION__' ] = true ;
@@ -154,7 +164,7 @@ describe('attachDevToolsBridge', () => {
154164
155165 it ( 'returns a BridgeHandle with a detach function' , ( ) => {
156166 const client = makeClient ( { status : 'start' } ) ;
157- const handle = attachDevToolsBridge ( client ) ;
167+ const handle = attachDaVinciBridge ( client ) ;
158168
159169 expect ( handle ) . toHaveProperty ( 'detach' ) ;
160170 expect ( typeof handle . detach ) . toBe ( 'function' ) ;
@@ -166,7 +176,7 @@ describe('attachDevToolsBridge', () => {
166176 const client = makeClient ( { status : 'start' } ) ;
167177 const { events, stop } = captureDevtoolsEvents ( ) ;
168178
169- const handle = attachDevToolsBridge ( client ) ;
179+ const handle = attachDaVinciBridge ( client ) ;
170180
171181 // Trigger a status transition.
172182 client . trigger ( { status : 'continue' } ) ;
@@ -202,7 +212,7 @@ describe('attachDevToolsBridge', () => {
202212 const client = makeClient ( { status : 'start' } ) ;
203213 const { events, stop } = captureDevtoolsEvents ( ) ;
204214
205- const handle = attachDevToolsBridge ( client ) ;
215+ const handle = attachDaVinciBridge ( client ) ;
206216 client . trigger ( continueNode ) ;
207217
208218 handle . detach ( ) ;
@@ -228,7 +238,7 @@ describe('attachDevToolsBridge', () => {
228238 const client = makeClient ( { status : 'start' } ) ;
229239 const { events, stop } = captureDevtoolsEvents ( ) ;
230240
231- const handle = attachDevToolsBridge ( client ) ;
241+ const handle = attachDaVinciBridge ( client ) ;
232242
233243 // First trigger sets previousStatus = 'start'.
234244 client . trigger ( { status : 'start' } ) ;
@@ -249,7 +259,7 @@ describe('attachDevToolsBridge', () => {
249259 const client = makeClient ( { status : 'start' } ) ;
250260 const { events, stop } = captureDevtoolsEvents ( ) ;
251261
252- const handle = attachDevToolsBridge ( client ) ;
262+ const handle = attachDaVinciBridge ( client ) ;
253263
254264 // Verify subscribe was wired up.
255265 expect ( client . subscribe ) . toHaveBeenCalledTimes ( 1 ) ;
@@ -268,7 +278,7 @@ describe('attachDevToolsBridge', () => {
268278 const client = makeClient ( { status : 'start' } ) ;
269279 const { events, stop } = captureDevtoolsEvents ( ) ;
270280
271- const handle = attachDevToolsBridge ( client , {
281+ const handle = attachDaVinciBridge ( client , {
272282 clientId : 'my-app' ,
273283 redirectUri : 'https://app.example.com/callback' ,
274284 } ) ;
@@ -293,7 +303,7 @@ describe('attachDevToolsBridge', () => {
293303 const client = makeClient ( { status : 'start' } ) ;
294304 const { events, stop } = captureDevtoolsEvents ( ) ;
295305
296- const handle = attachDevToolsBridge ( client , { clientId : 'my-app' } ) ;
306+ const handle = attachDaVinciBridge ( client , { clientId : 'my-app' } ) ;
297307
298308 client . trigger ( { status : 'continue' } ) ;
299309 client . trigger ( { status : 'success' } ) ;
@@ -309,7 +319,7 @@ describe('attachDevToolsBridge', () => {
309319 const client = makeClient ( { status : 'start' } ) ;
310320 const { events, stop } = captureDevtoolsEvents ( ) ;
311321
312- const handle = attachDevToolsBridge ( client ) ;
322+ const handle = attachDaVinciBridge ( client ) ;
313323
314324 client . trigger ( { status : 'continue' } ) ;
315325
@@ -327,7 +337,7 @@ describe('attachDevToolsBridge', () => {
327337 const client = makeClient ( { status : 'start' } ) ;
328338 const { events, stop } = captureDevtoolsEvents ( ) ;
329339
330- const handle = attachDevToolsBridge ( client ) ;
340+ const handle = attachDaVinciBridge ( client ) ;
331341
332342 // subscribe is called (the bridge still subscribes), but no events should be dispatched.
333343 expect ( client . subscribe ) . toHaveBeenCalledTimes ( 1 ) ;
@@ -346,7 +356,7 @@ describe('attachDevToolsBridge', () => {
346356 const client = makeClient ( { status : 'start' } ) ;
347357 const { events, stop } = captureDevtoolsEvents ( ) ;
348358
349- const handle = attachDevToolsBridge ( client , { clientId : 'my-app' } ) ;
359+ const handle = attachDaVinciBridge ( client , { clientId : 'my-app' } ) ;
350360 client . trigger ( { status : 'continue' } ) ;
351361
352362 handle . detach ( ) ;
@@ -360,7 +370,7 @@ describe('attachDevToolsBridge', () => {
360370 } ) ;
361371} ) ;
362372
363- describe ( 'attachDevToolsBridge session tracking' , ( ) => {
373+ describe ( 'attachDaVinciBridge session tracking' , ( ) => {
364374 beforeEach ( ( ) => {
365375 ( window as unknown as Record < string , unknown > ) [ '__PING_DEVTOOLS_EXTENSION__' ] = true ;
366376 localStorage . clear ( ) ;
@@ -380,7 +390,7 @@ describe('attachDevToolsBridge session tracking', () => {
380390 const client = makeClient ( { status : 'start' } ) ;
381391 const { events, stop } = captureDevtoolsEvents ( ) ;
382392
383- const handle = attachDevToolsBridge ( client ) ;
393+ const handle = attachDaVinciBridge ( client ) ;
384394
385395 // Trigger a node transition, then mutate storage in the same tick
386396 client . trigger ( { status : 'continue' } ) ;
@@ -410,7 +420,7 @@ describe('attachDevToolsBridge session tracking', () => {
410420 const client = makeClient ( { status : 'start' } ) ;
411421 const { events, stop } = captureDevtoolsEvents ( ) ;
412422
413- const handle = attachDevToolsBridge ( client ) ;
423+ const handle = attachDaVinciBridge ( client ) ;
414424 client . trigger ( { status : 'continue' } ) ;
415425
416426 await new Promise ( ( r ) => setTimeout ( r , 10 ) ) ;
@@ -423,4 +433,118 @@ describe('attachDevToolsBridge session tracking', () => {
423433 ) ;
424434 expect ( sessionEvents ) . toHaveLength ( 0 ) ;
425435 } ) ;
436+
437+ it ( 'emits session:cookie event when document.cookie changes after a node transition' , async ( ) => {
438+ const client = makeClient ( { status : 'start' } ) ;
439+ const { events, stop } = captureDevtoolsEvents ( ) ;
440+
441+ const handle = attachDaVinciBridge ( client ) ;
442+
443+ client . trigger ( { status : 'continue' } ) ;
444+ // Mutate cookie after the transition in the same tick
445+ document . cookie = 'sid=new-session-id' ;
446+
447+ await new Promise ( ( r ) => setTimeout ( r , 10 ) ) ;
448+
449+ handle . detach ( ) ;
450+ stop ( ) ;
451+
452+ const cookieEvents = events . filter ( ( e ) => e . detail . type === 'session:cookie' ) ;
453+ expect ( cookieEvents ) . toHaveLength ( 1 ) ;
454+ const data = cookieEvents [ 0 ] . detail . data as {
455+ _tag : string ;
456+ key : string ;
457+ before ?: string ;
458+ after ?: string ;
459+ } ;
460+ expect ( data . _tag ) . toBe ( 'session' ) ;
461+ expect ( data . key ) . toBe ( 'document.cookie' ) ;
462+ expect ( data . before ) . toBeUndefined ( ) ;
463+ expect ( data . after ) . toBe ( 'sid=new-session-id' ) ;
464+ } ) ;
465+
466+ it ( 'emits separate session:storage events for multiple keys changing at once' , async ( ) => {
467+ const client = makeClient ( { status : 'start' } ) ;
468+ const { events, stop } = captureDevtoolsEvents ( ) ;
469+
470+ // Pre-populate a key that will be removed
471+ localStorage . setItem ( 'old-key' , 'old-value' ) ;
472+
473+ const handle = attachDaVinciBridge ( client ) ;
474+
475+ // First transition to capture the initial snapshot (which includes old-key)
476+ client . trigger ( { status : 'continue' } ) ;
477+ await new Promise ( ( r ) => setTimeout ( r , 10 ) ) ;
478+
479+ // Now mutate multiple keys and trigger another transition
480+ localStorage . setItem ( 'new-key' , 'new-value' ) ;
481+ localStorage . setItem ( 'old-key' , 'changed-value' ) ;
482+ localStorage . setItem ( 'another-key' , 'another-value' ) ;
483+
484+ client . trigger ( { status : 'success' } ) ;
485+ await new Promise ( ( r ) => setTimeout ( r , 10 ) ) ;
486+
487+ handle . detach ( ) ;
488+ stop ( ) ;
489+
490+ const storageEvents = events . filter ( ( e ) => e . detail . type === 'session:storage' ) ;
491+ const changedKeys = storageEvents . map (
492+ ( e ) => ( e . detail . data as { key : string } ) . key ,
493+ ) ;
494+
495+ expect ( changedKeys ) . toContain ( 'new-key' ) ;
496+ expect ( changedKeys ) . toContain ( 'old-key' ) ;
497+ expect ( changedKeys ) . toContain ( 'another-key' ) ;
498+ expect ( storageEvents ) . toHaveLength ( 3 ) ;
499+ } ) ;
500+ } ) ;
501+
502+ describe ( 'attachDaVinciBridge cache passthrough' , ( ) => {
503+ beforeEach ( ( ) => {
504+ ( window as unknown as Record < string , unknown > ) [ '__PING_DEVTOOLS_EXTENSION__' ] = true ;
505+ } ) ;
506+
507+ afterEach ( async ( ) => {
508+ delete ( window as unknown as Record < string , unknown > ) [ '__PING_DEVTOOLS_EXTENSION__' ] ;
509+ await new Promise ( ( r ) => setTimeout ( r , 10 ) ) ;
510+ } ) ;
511+
512+ it ( 'passes cached response body through to the emitted SdkData' , ( ) => {
513+ const cachedResponse = { access_token : 'tok-xyz' , token_type : 'Bearer' } ;
514+ const cache = { getCache : vi . fn ( ( ) => cachedResponse ) } ;
515+ const client = makeClient ( { status : 'start' } , cache ) ;
516+ const { events, stop } = captureDevtoolsEvents ( ) ;
517+
518+ const handle = attachDaVinciBridge ( client ) ;
519+ client . trigger ( {
520+ status : 'continue' ,
521+ cache : { key : 'req-42' } ,
522+ server : { interactionId : 'iid-1' } ,
523+ } ) ;
524+
525+ handle . detach ( ) ;
526+ stop ( ) ;
527+
528+ expect ( cache . getCache ) . toHaveBeenCalledWith ( 'req-42' ) ;
529+ expect ( events ) . toHaveLength ( 1 ) ;
530+ const data = events [ 0 ] . detail . data as { responseBody ?: unknown } ;
531+ expect ( data . responseBody ) . toBe ( cachedResponse ) ;
532+ } ) ;
533+
534+ it ( 'does not call getCache when node has no cache key' , ( ) => {
535+ const cache = { getCache : vi . fn ( ) } ;
536+ const client = makeClient ( { status : 'start' } , cache ) ;
537+ const { events, stop } = captureDevtoolsEvents ( ) ;
538+
539+ const handle = attachDaVinciBridge ( client ) ;
540+ client . trigger ( { status : 'continue' } ) ;
541+
542+ handle . detach ( ) ;
543+ stop ( ) ;
544+
545+ expect ( cache . getCache ) . not . toHaveBeenCalled ( ) ;
546+ expect ( events ) . toHaveLength ( 1 ) ;
547+ const data = events [ 0 ] . detail . data as { responseBody ?: unknown } ;
548+ expect ( data . responseBody ) . toBeUndefined ( ) ;
549+ } ) ;
426550} ) ;
0 commit comments