11import { AbortController } from '@shopify/cli-kit/node/abort'
22import { outputDebug , outputContent , outputToken , outputWarn } from '@shopify/cli-kit/node/output'
33import Server from 'http-proxy'
4+ import { useConcurrentOutputContext } from '@shopify/cli-kit/node/ui/components'
45import * as http from 'http'
56import * as https from 'https'
7+ import { Writable } from 'stream'
68
79export interface LocalhostCert {
810 key : string
@@ -14,18 +16,19 @@ export async function getProxyingWebServer(
1416 rules : { [ key : string ] : string } ,
1517 abortSignal : AbortController [ 'signal' ] ,
1618 localhostCert ?: LocalhostCert ,
19+ stdout ?: Writable ,
1720) {
1821 // Lazy-importing it because it's CJS and we don't want it
1922 // to block the loading of the ESM module graph.
2023 const { default : httpProxy } = await import ( 'http-proxy' )
2124 const proxy = httpProxy . createProxy ( )
2225
23- const requestListener = getProxyServerRequestListener ( rules , proxy )
26+ const requestListener = getProxyServerRequestListener ( rules , proxy , stdout )
2427
2528 const server = localhostCert ? https . createServer ( localhostCert , requestListener ) : http . createServer ( requestListener )
2629
2730 // Capture websocket requests and forward them to the proxy
28- server . on ( 'upgrade' , getProxyServerWebsocketUpgradeListener ( rules , proxy ) )
31+ server . on ( 'upgrade' , getProxyServerWebsocketUpgradeListener ( rules , proxy , stdout ) )
2932
3033 abortSignal . addEventListener ( 'abort' , ( ) => {
3134 outputDebug ( 'Closing reverse HTTP proxy' )
@@ -37,12 +40,17 @@ export async function getProxyingWebServer(
3740function getProxyServerWebsocketUpgradeListener (
3841 rules : { [ key : string ] : string } ,
3942 proxy : Server ,
43+ stdout ?: Writable ,
4044) : ( req : http . IncomingMessage , socket : import ( 'stream' ) . Duplex , head : Buffer ) => void {
4145 return function ( req , socket , head ) {
4246 const target = match ( rules , req , true )
4347 if ( target ) {
4448 return proxy . ws ( req , socket , head , { target} , ( err ) => {
45- outputWarn ( `Error forwarding websocket request: ${ err } ` )
49+ useConcurrentOutputContext ( { outputPrefix : 'proxy' , stripAnsi : false } , ( ) => {
50+ const error = err instanceof AggregateError && err . errors . length > 0 ? err . errors [ err . errors . length - 1 ] : err
51+ outputWarn ( `Error forwarding websocket request: ${ error . message } ` , stdout )
52+ outputWarn ( `└ Unreachable target "${ target } " for path: "${ req . url } "` , stdout )
53+ } )
4654 } )
4755 }
4856 socket . destroy ( )
@@ -52,12 +60,17 @@ function getProxyServerWebsocketUpgradeListener(
5260function getProxyServerRequestListener (
5361 rules : { [ key : string ] : string } ,
5462 proxy : Server ,
63+ stdout ?: Writable ,
5564) : http . RequestListener | undefined {
5665 return function ( req , res ) {
5766 const target = match ( rules , req )
5867 if ( target ) {
5968 return proxy . web ( req , res , { target} , ( err ) => {
60- outputWarn ( `Error forwarding web request: ${ err } ` )
69+ useConcurrentOutputContext ( { outputPrefix : 'proxy' , stripAnsi : false } , ( ) => {
70+ const error = err instanceof AggregateError && err . errors . length > 0 ? err . errors [ err . errors . length - 1 ] : err
71+ outputWarn ( `Error forwarding web request: ${ error . message } ` , stdout )
72+ outputWarn ( `└ Unreachable target "${ target } " for path: "${ req . url } "` , stdout )
73+ } )
6174 } )
6275 }
6376
0 commit comments