@@ -14,11 +14,57 @@ Error.prototype.toString = function () {
1414/** Server-Timing header key to signal that the SFAPI proxy is enabled */
1515const HYDROGEN_SFAPI_PROXY_KEY = '_sfapi_proxy' ;
1616
17+ let hasWarnedAboutStorefront = false ;
18+
19+ function warnOnce ( message : string ) {
20+ if ( ! hasWarnedAboutStorefront ) {
21+ hasWarnedAboutStorefront = true ;
22+ console . warn ( message ) ;
23+ }
24+ }
25+
26+ function buildServerTimingHeader ( values : Record < string , string | undefined > ) {
27+ return Object . entries ( values )
28+ . map ( ( [ key , value ] ) => ( value ? `${ key } ;desc=${ value } ` : undefined ) )
29+ . filter ( Boolean )
30+ . join ( ', ' ) ;
31+ }
32+
33+ function appendServerTimingHeader (
34+ response : { headers : Headers } ,
35+ values : string | Record < string , string | undefined > ,
36+ ) {
37+ const header =
38+ typeof values === 'string' ? values : buildServerTimingHeader ( values ) ;
39+
40+ if ( header ) {
41+ response . headers . append ( 'Server-Timing' , header ) ;
42+ }
43+ }
44+
1745type CreateRequestHandlerOptions < Context = unknown > = {
46+ /** Remix's server build */
1847 build : ServerBuild ;
48+ /** Remix's mode */
1949 mode ?: string ;
20- poweredByHeader ?: boolean ;
50+ /**
51+ * Function to provide the load context for each request.
52+ * It must contain Hydrogen's storefront client instance
53+ * for other Hydrogen utilities to work properly.
54+ */
2155 getLoadContext ?: ( request : Request ) => Promise < Context > | Context ;
56+ /**
57+ * Whether to include the `powered-by` header in responses
58+ * @default true
59+ */
60+ poweredByHeader ?: boolean ;
61+ /**
62+ * Collect tracking information from subrequests such as cookies
63+ * and forward them to the browser. Disable this if you are not
64+ * using Hydrogen's built-in analytics.
65+ * @default true
66+ */
67+ collectTrackingInformation ?: boolean ;
2268 /**
2369 * Whether to proxy standard routes such as `/api/.../graphql.json` (Storefront API).
2470 * You can disable this if you are handling these routes yourself. Ensure that
@@ -33,6 +79,7 @@ export function createRequestHandler<Context = unknown>({
3379 mode,
3480 poweredByHeader = true ,
3581 getLoadContext,
82+ collectTrackingInformation = true ,
3683 proxyStorefrontApiRequests = true ,
3784} : CreateRequestHandlerOptions < Context > ) {
3885 const handleRequest = createRemixRequestHandler ( build , mode ) ;
@@ -71,11 +118,20 @@ export function createRequestHandler<Context = unknown>({
71118 context as { storefront ?: StorefrontForProxy } | undefined
72119 ) ?. storefront ;
73120
74- // Proxy Storefront API requests
75- if ( proxyStorefrontApiRequests && storefront ?. isStorefrontApiUrl ( request ) ) {
76- const response = await storefront . forward ( request ) ;
77- appendPoweredByHeader ?.( response ) ;
78- return response ;
121+ if ( proxyStorefrontApiRequests ) {
122+ if ( ! storefront ) {
123+ // TODO: this should throw error in future major version
124+ warnOnce (
125+ '[h2:createRequestHandler] Storefront instance is required to proxy standard routes.' ,
126+ ) ;
127+ }
128+
129+ // Proxy Storefront API requests
130+ if ( storefront ?. isStorefrontApiUrl ( request ) ) {
131+ const response = await storefront . forward ( request ) ;
132+ appendPoweredByHeader ?.( response ) ;
133+ return response ;
134+ }
79135 }
80136
81137 if ( process . env . NODE_ENV === 'development' && context ) {
@@ -89,12 +145,12 @@ export function createRequestHandler<Context = unknown>({
89145
90146 const response = await handleRequest ( request , context ) ;
91147
92- appendPoweredByHeader ?.( response ) ;
93-
94- // Collect tracking headers from storefront subrequests
95- if ( proxyStorefrontApiRequests && storefront ) {
96- storefront . setCollectedSubrequestHeaders ( response ) ;
148+ if ( storefront && proxyStorefrontApiRequests ) {
149+ if ( collectTrackingInformation ) {
150+ storefront . setCollectedSubrequestHeaders ( response ) ;
151+ }
97152
153+ // TODO: assume SFAPI proxy is available in future major version
98154 // Signal that SFAPI proxy is enabled for document requests.
99155 // Note: sec-fetch-dest is automatically added by modern browsers,
100156 // but we also check the Accept header for other clients.
@@ -103,13 +159,12 @@ export function createRequestHandler<Context = unknown>({
103159 ( fetchDest && fetchDest === 'document' ) ||
104160 request . headers . get ( 'accept' ) ?. includes ( 'text/html' )
105161 ) {
106- response . headers . append (
107- 'Server-Timing' ,
108- `${ HYDROGEN_SFAPI_PROXY_KEY } ;desc=1` ,
109- ) ;
162+ appendServerTimingHeader ( response , { [ HYDROGEN_SFAPI_PROXY_KEY ] : '1' } ) ;
110163 }
111164 }
112165
166+ appendPoweredByHeader ?.( response ) ;
167+
113168 if ( process . env . NODE_ENV === 'development' ) {
114169 globalThis . __H2O_LOG_EVENT ?.( {
115170 eventType : 'request' ,
0 commit comments