Files
web/apps/scandic-web/server/utils.ts
Anton Gunnarsson 846fd904a6 Merged in feat/sw-2859-set-up-shared-trpc-package (pull request #2319)
feat(SW-2859): Create trpc package

* Add isEdge, safeTry and dataCache to new common package

* Add eslint and move prettier config

* Clean up tests

* Create trpc package and move initialization

* Move errors and a few procedures

* Move telemetry to common package

* Move tokenManager to common package

* Add Sentry to procedures

* Clean up procedures

* Fix self-referencing imports

* Add exports to packages and lint rule to prevent relative imports

* Add env to trpc package

* Add eslint to trpc package

* Apply lint rules

* Use direct imports from trpc package

* Add lint-staged config to trpc

* Move lang enum to common

* Restructure trpc package folder structure

* Fix lang imports


Approved-by: Linus Flood
2025-06-18 12:14:20 +00:00

133 lines
4.7 KiB
TypeScript

import { NextRequest } from "next/server"
import { z } from "zod"
import { Lang } from "@scandic-hotels/common/constants/language"
import { env } from "@/env/server"
export function isDefined<T>(argument: T | undefined | null): argument is T {
return argument !== undefined && argument !== null
}
export const langInput = z.object({
lang: z.nativeEnum(Lang),
})
/**
* Helper function to convert Lang enum to API lang enum.
*/
export const toApiLang = (lang: Lang): string => {
const result = toApiLangMap[lang]
if (!result) {
throw new Error("Invalid language")
}
return result
}
const toApiLangMap: { [key in Lang]: string } = {
[Lang.en]: "En",
[Lang.sv]: "Sv",
[Lang.no]: "No",
[Lang.fi]: "Fi",
[Lang.da]: "Da",
[Lang.de]: "De",
}
/**
* Helper function to convert lang string to Lang enum.
*/
export function toLang(lang: string): Lang | undefined {
const lowerCaseLang = lang.toLowerCase()
return Object.values(Lang).find((l) => l === lowerCaseLang)
}
/**
* Use this function when you want to create URLs that are public facing, for
* example for redirects or redirectTo query parameters.
* Dedicated environments are behind Akamai (test, stage, production). They have
* env.PUBLIC_URL set.
* All other environment like deploy previews and branch deployments are not
* behind Akamai and therefore do not have env.PUBLIC_URL set.
* We need this approach because Netlify uses x-forwarded-host internally and
* strips it from ever reaching our code.
* TODO: Replace this approach with custom header in Akamai that mirrors the
* value in x-forwarded-host which would not get stripped by Netlify.
* @param request The incoming request.
* @returns NextURL The public facing URL instance for the given request.
*/
export function getPublicNextURL(request: NextRequest) {
if (env.PUBLIC_URL) {
const publicNextURL = request.nextUrl.clone()
// Akamai in front of Netlify for dedicated environments
// require us to rewrite the incoming host and hostname
// to match the public URL used to visit Akamai.
const url = new URL(env.PUBLIC_URL)
publicNextURL.host = url.host
publicNextURL.hostname = url.hostname
return publicNextURL
}
return request.nextUrl
}
/**
* Use this function when you want the public facing URL for the given request.
* Read about the motivation in getPublicNextURL above.
* @see getPublicNextURL
* @param request The incoming request.
* @returns string The public facing origin for the given request.
*/
export function getPublicURL(request: NextRequest) {
if (env.PUBLIC_URL) {
return env.PUBLIC_URL
}
return request.nextUrl.origin
}
/**
* Use this function when you want to create URLs that are internal (behind Akamai),
* for example for rewrites. Mainly used for middleware wrapped in auth().
* The auth() function overrides the origin of the incoming request. It sets it
* to the origin of AUTH_URL/NEXTAUTH_URL. This means we cannot use the augmented
* request from auth() for rewrites, as those will point to auth url origin
* (in front of Akamai) and not the origin of the incoming request (behind Akamai).
* This results in rewrites going over the internet instead of going through the
* internal routing at Netlify.
* For dedicated environments (test, stage and production) we are behind Akamai.
* For those we have set a value for AUTH_URL/NEXTAUTH_URL, they point to the
* PUBLIC_URL. For rewrites we need the internal origin inside Netlify.
* In middleware.ts we copy the incoming origin to a header 'x-sh-origin'. We try
* and use that first, if not present we assume the internal origin is the value
* of the host header, as that is what Netlify used for routing to this deployment.
* @param request The incoming request.
* @returns NextURL The internal request, in Netlify behind Akamai.
*/
export function getInternalNextURL(request: NextRequest) {
const { href, origin } = request.nextUrl
const originHeader = request.headers.get("x-sh-origin")
if (originHeader) {
console.log(`[internalNextUrl] using x-sh-origin header`, {
origin,
originHeader,
newOrigin: href.replace(origin, originHeader),
})
return new NextRequest(href.replace(origin, originHeader), request).nextUrl
}
const hostHeader = request.headers.get("host")
if (hostHeader) {
const inputHostOrigin = `${request.nextUrl.protocol}//${hostHeader}`
console.log(`[internalNextUrl] using host header`, {
origin,
hostHeader,
hostOrigin: inputHostOrigin,
newOrigin: href.replace(origin, inputHostOrigin),
})
const { origin: hostOrigin } = new URL(inputHostOrigin)
return new NextRequest(href.replace(origin, hostOrigin), request).nextUrl
}
console.log(`[internalNextUrl] falling back to incoming request`)
return request.nextUrl
}