sourcegraph/client/web/dev/utils/get-api-proxy-settings.ts
Valery Bugakov 77541f2c30
web: upgrade react-router to v6 (#47595)
- Closes #33834
- Upgraded react-router to v6
- Migrated the web application to [the data-aware router introduced in
v6.4.0](https://reactrouter.com/en/main/routers/picking-a-router#using-v64-data-apis).
- Migrated `history.block` usages to the `unstable_useBlock` hook
[introduced in
v6.7.0](https://github.com/remix-run/react-router/issues/8139).
- Removed explicit history reference from the `renderWithBrandedContext`
utility used in unit tests.
- Migrated the search-query state observer from `history.listen` to
`useLocation` API.

## Test plan

CI and manually visiting all the pages.
2023-02-21 06:32:51 +00:00

114 lines
4.8 KiB
TypeScript

import { Options, responseInterceptor } from 'http-proxy-middleware'
import { ENVIRONMENT_CONFIG, HTTPS_WEB_SERVER_URL } from './environment-config'
// One of the API routes: "/-/sign-in".
const PROXY_ROUTES = ['/.api', '/search/stream', '/-', '/.auth']
interface GetAPIProxySettingsOptions {
apiURL: string
/**
* If provided, the server will proxy requests to index.html
* and inject the `window.context` defined there into the local template.
*/
getLocalIndexHTML?: (jsContextScript?: string) => string
}
interface ProxySettings extends Options {
proxyRoutes: string[]
}
export function getAPIProxySettings(options: GetAPIProxySettingsOptions): ProxySettings {
const { apiURL, getLocalIndexHTML } = options
return {
// Enable index.html proxy if `getLocalIndexHTML` is provided.
proxyRoutes: [...PROXY_ROUTES, ...(getLocalIndexHTML ? [''] : [])],
target: apiURL,
// Do not SSL certificate.
secure: false,
// Change the origin of the host header to the target URL.
changeOrigin: true,
// Rewrite domain of `set-cookie` headers for all cookies received.
cookieDomainRewrite: '',
// Prevent automatic call of res.end() in `onProxyRes`. It is handled by `responseInterceptor`.
selfHandleResponse: true,
// eslint-disable-next-line @typescript-eslint/no-misused-promises, @typescript-eslint/require-await
onProxyRes: responseInterceptor(async (responseBuffer, proxyRes) => {
// Propagate cookies to enable authentication on the remote server.
if (proxyRes.headers['set-cookie']) {
// Remove `Secure` and `SameSite` from `set-cookie` headers.
const cookies = proxyRes.headers['set-cookie'].map(cookie =>
cookie.replace(/; secure/gi, '').replace(/; samesite=.+/gi, '')
)
proxyRes.headers['set-cookie'] = cookies
}
// Extract remote `window.context` from the HTML response and inject it into
// the index.html generated by `getLocalIndexHTML`.
if (
getLocalIndexHTML &&
// router.go is not up to date with client routes and still serves index.html with 404
(proxyRes.statusCode === 200 || proxyRes.statusCode === 404) &&
proxyRes.headers['content-type'] &&
proxyRes.headers['content-type'].includes('text/html')
) {
const remoteIndexHTML = responseBuffer.toString('utf8')
return getLocalIndexHTML(getRemoteJsContextScript(remoteIndexHTML))
}
return responseBuffer
}),
onProxyReq: proxyRequest => {
// Not really clear why, but the `changeOrigin: true` setting does NOT add the correct
// Origin header to requests sent to k8s.sgdev.org, which e.g. breaks sign in and more. So
// we add it ourselves.
proxyRequest.setHeader('Origin', apiURL)
},
// TODO: share with `client/web/gulpfile.js`
// Avoid crashing on "read ECONNRESET".
onError: () => undefined,
// Don't log proxy errors, these usually just contain
// ECONNRESET errors caused by the browser cancelling
// requests. This should not be needed to actually debug something.
logLevel: 'silent',
onProxyReqWs: (_proxyRequest, _request, socket) =>
socket.on('error', error => console.error('WebSocket proxy error:', error)),
}
}
const jsContextChanges = `
// Changes to remote 'window.context' required for local development.
Object.assign(window.context, {
// Only username/password auth-provider provider is supported with the standalone server.
authProviders: window.context.authProviders.filter(provider => provider.isBuiltin),
// For some reason, the standalone server crashes with legacy extensions enabled.
enableLegacyExtensions: false,
// Sync externalURL with the development environment config.
externalURL: '${HTTPS_WEB_SERVER_URL}',
// Enable local testing of OpenTelemtry endpoints.
openTelemetry: {
endpoint: '${ENVIRONMENT_CONFIG.CLIENT_OTEL_EXPORTER_OTLP_ENDPOINT}',
},
// Do not send errors to Sentry from the development environment.
sentryDSN: null,
siteGQLID: 'TestGQLSiteID',
siteID: 'TestSiteID',
version: 'web-standalone',
})
`
function getRemoteJsContextScript(remoteIndexHTML: string): string {
const remoteJsContextStart = remoteIndexHTML.indexOf('window.context = {')
const remoteJsContextEnd = remoteIndexHTML.indexOf('</script>', remoteJsContextStart)
return remoteIndexHTML.slice(remoteJsContextStart, remoteJsContextEnd) + jsContextChanges
}