@@ -651,6 +651,117 @@ describe('rsc-mf host modern.server middleware contracts', () => {
651651 await expect ( context . res ?. text ( ) ) . resolves . toBe ( 'query-fallback-hit' ) ;
652652 } ) ;
653653
654+ it ( 'supports absolute manifest fallback asset URLs and merges request query params' , async ( ) => {
655+ const handler = getProxyMiddlewareHandler ( ) ;
656+ const next = jest . fn ( async ( ) : Promise < void > => undefined ) ;
657+ const fetchMock = installFetchMock (
658+ jest
659+ . fn ( )
660+ . mockResolvedValueOnce ( new Response ( 'not-found' , { status : 404 } ) )
661+ . mockResolvedValueOnce (
662+ new Response (
663+ JSON . stringify ( {
664+ exposes : [
665+ {
666+ assets : {
667+ js : {
668+ sync : [
669+ 'http://127.0.0.1:3999/static/js/async/__federation_expose_RemoteClientCounter.7745fe5f0a.js?manifest=1' ,
670+ ] ,
671+ async : [ ] ,
672+ } ,
673+ css : {
674+ sync : [ ] ,
675+ async : [ ] ,
676+ } ,
677+ } ,
678+ } ,
679+ ] ,
680+ } ) ,
681+ {
682+ status : 200 ,
683+ headers : {
684+ 'content-type' : 'application/json' ,
685+ } ,
686+ } ,
687+ ) ,
688+ )
689+ . mockResolvedValueOnce (
690+ new Response ( 'absolute-query-fallback-hit' , {
691+ status : 200 ,
692+ headers : {
693+ 'content-type' : 'application/javascript' ,
694+ } ,
695+ } ) ,
696+ ) ,
697+ ) ;
698+ const context : { req : { url : string } ; res ?: Response } = {
699+ req : {
700+ url : 'http://127.0.0.1:3007/static/js/async/__federation_expose_RemoteClientCounter.js?cache=1' ,
701+ } ,
702+ } ;
703+
704+ await withRemotePort ( '3999' , ( ) => handler ( context , next ) ) ;
705+
706+ expect ( fetchMock ) . toHaveBeenNthCalledWith (
707+ 3 ,
708+ 'http://127.0.0.1:3999/static/js/async/__federation_expose_RemoteClientCounter.7745fe5f0a.js?manifest=1&cache=1' ,
709+ ) ;
710+ expect ( next ) . not . toHaveBeenCalled ( ) ;
711+ await expect ( context . res ?. text ( ) ) . resolves . toBe (
712+ 'absolute-query-fallback-hit' ,
713+ ) ;
714+ } ) ;
715+
716+ it ( 'falls through when manifest fallback asset URL points to another origin' , async ( ) => {
717+ const handler = getProxyMiddlewareHandler ( ) ;
718+ const next = jest . fn ( async ( ) : Promise < void > => undefined ) ;
719+ const fetchMock = installFetchMock (
720+ jest
721+ . fn ( )
722+ . mockResolvedValueOnce ( new Response ( 'not-found' , { status : 404 } ) )
723+ . mockResolvedValueOnce (
724+ new Response (
725+ JSON . stringify ( {
726+ exposes : [
727+ {
728+ assets : {
729+ js : {
730+ sync : [
731+ 'https://cdn.example.com/static/js/async/__federation_expose_RemoteClientCounter.7745fe5f0a.js' ,
732+ ] ,
733+ async : [ ] ,
734+ } ,
735+ css : {
736+ sync : [ ] ,
737+ async : [ ] ,
738+ } ,
739+ } ,
740+ } ,
741+ ] ,
742+ } ) ,
743+ {
744+ status : 200 ,
745+ headers : {
746+ 'content-type' : 'application/json' ,
747+ } ,
748+ } ,
749+ ) ,
750+ ) ,
751+ ) ;
752+ const context : { req : { url : string } ; res ?: Response } = {
753+ req : {
754+ url : 'http://127.0.0.1:3007/static/js/async/__federation_expose_RemoteClientCounter.js' ,
755+ } ,
756+ } ;
757+
758+ await withRemotePort ( '3999' , ( ) => handler ( context , next ) ) ;
759+
760+ expect ( fetchMock ) . toHaveBeenCalledTimes ( 2 ) ;
761+ expect ( next ) . toHaveBeenCalledTimes ( 1 ) ;
762+ expect ( context . res ) . toBeUndefined ( ) ;
763+ } ) ;
764+
654765 it ( 'matches fallback chunks when manifest hash suffix includes non-hex characters' , async ( ) => {
655766 const handler = getProxyMiddlewareHandler ( ) ;
656767 const next = jest . fn ( async ( ) : Promise < void > => undefined ) ;
0 commit comments