feat: improve handling of deployment env vars

These are now defined in Netlify UI for dedicated environments (test, stage, production):

AUTH_URL
NEXTAUTH_URL
PUBLIC_URL

Code now falls back to incoming request host. Mainly used for
deployment previews which do not have Akamai in front, meaning
we do not need the above workaround as incoming request host
matches the actual public facing host. When Akamai is in front,
we lose the public facing host in Netlify's routing layer as they
internally use `x-forwarded-for` and we can't claim it for our usage.
This commit is contained in:
Michael Zetterberg
2024-10-14 20:43:53 +02:00
parent 3a3491c534
commit 4a846540c3
26 changed files with 72 additions and 485 deletions

4
.env
View File

@@ -1,4 +0,0 @@
# See update-dotenv.mjs
AUTH_URL="REPLACE-ON-NETLIFY-BUILD"
NEXTAUTH_URL="REPLACE-ON-NETLIFY-BUILD"
PUBLIC_URL="REPLACED-ON-NETLIFY-BUILD"

View File

@@ -4,6 +4,7 @@ import { AuthError } from "next-auth"
import { Lang } from "@/constants/languages"
import { env } from "@/env/server"
import { internalServerError } from "@/server/errors/next"
import { getPublicURL } from "@/server/utils"
import { signOut } from "@/auth"
@@ -11,6 +12,8 @@ export async function GET(
request: NextRequest,
context: { params: { lang: Lang } }
) {
const publicURL = getPublicURL(request)
let redirectTo: string = ""
const returnUrl = request.headers.get("x-returnurl")
@@ -39,7 +42,7 @@ export async function GET(
// Make relative URL to absolute URL
if (redirectTo.startsWith("/")) {
console.log(`[logout] make redirectTo absolute, from ${redirectTo}`)
redirectTo = new URL(redirectTo, env.PUBLIC_URL).href
redirectTo = new URL(redirectTo, publicURL).href
console.log(`[logout] make redirectTo absolute, to ${redirectTo}`)
}

View File

@@ -4,6 +4,7 @@ import { AuthError } from "next-auth"
import { Lang } from "@/constants/languages"
import { env } from "@/env/server"
import { internalServerError } from "@/server/errors/next"
import { getPublicURL } from "@/server/utils"
import { signIn } from "@/auth"
@@ -11,9 +12,7 @@ export async function GET(
request: NextRequest,
context: { params: { lang: Lang } }
) {
if (!env.PUBLIC_URL) {
throw internalServerError("No value for env.PUBLIC_URL")
}
const publicURL = getPublicURL(request)
let redirectHeaders: Headers | undefined = undefined
let redirectTo: string
@@ -54,7 +53,7 @@ export async function GET(
// Make relative URL to absolute URL
if (redirectTo.startsWith("/")) {
console.log(`[login] make redirectTo absolute, from ${redirectTo}`)
redirectTo = new URL(redirectTo, env.PUBLIC_URL).href
redirectTo = new URL(redirectTo, publicURL).href
console.log(`[login] make redirectTo absolute, to ${redirectTo}`)
}
@@ -131,7 +130,7 @@ export async function GET(
* because user might choose to do Email link login.
* */
// The `for_origin` param is used to make Curity email login functionality working.
for_origin: env.PUBLIC_URL,
for_origin: publicURL,
// This is new param set for differentiate between the Magic link login of New web and current web
version: "2",
}

View File

@@ -5,6 +5,7 @@ import { Lang } from "@/constants/languages"
import { login } from "@/constants/routes/handleAuth"
import { env } from "@/env/server"
import { badRequest, internalServerError } from "@/server/errors/next"
import { getPublicURL } from "@/server/utils"
import { signIn } from "@/auth"
@@ -12,9 +13,7 @@ export async function GET(
request: NextRequest,
context: { params: { lang: Lang } }
) {
if (!env.PUBLIC_URL) {
throw internalServerError("No value for env.PUBLIC_URL")
}
const publicURL = getPublicURL(request)
const loginKey = request.nextUrl.searchParams.get("loginKey")
if (!loginKey) {
@@ -44,7 +43,7 @@ export async function GET(
console.log(
`[verifymagiclink] make redirectTo absolute, from ${redirectTo}`
)
redirectTo = new URL(redirectTo, env.PUBLIC_URL).href
redirectTo = new URL(redirectTo, publicURL).href
console.log(`[verifymagiclink] make redirectTo absolute, to ${redirectTo}`)
}
@@ -69,7 +68,7 @@ export async function GET(
ui_locales: context.params.lang,
scope: ["openid", "profile"].join(" "),
loginKey: loginKey,
for_origin: env.PUBLIC_URL,
for_origin: publicURL,
acr_values: "abc",
version: "2",
}

View File

@@ -4,14 +4,17 @@ import { env } from "process"
import { Lang } from "@/constants/languages"
import { profile } from "@/constants/routes/myPages"
import { serverClient } from "@/lib/trpc/server"
import { getPublicURL } from "@/server/utils"
export async function GET(
request: NextRequest,
{ params }: { params: { lang: string } }
) {
const publicURL = getPublicURL(request)
console.log(`[add-card] callback started`)
const lang = params.lang as Lang
const returnUrl = new URL(`${env.PUBLIC_URL}/${profile[lang ?? Lang.en]}`)
const returnUrl = new URL(`${publicURL}/${profile[lang ?? Lang.en]}`)
try {
const searchParams = request.nextUrl.searchParams

View File

@@ -1,38 +0,0 @@
import { NextResponse } from "next/server"
import { env } from "@/env/server"
import type { NextRequest } from "next/server"
export async function GET(request: NextRequest) {
const e = process.env
console.log({ process_env: process.env })
const urlVar = "PUBLIC_URL"
const nextAuthUrlVar = "NEXTAUTH_URL"
const nextAuthUrlVar2 = "AUTH_URL"
const envTestVar = "ENVTEST"
const values = {
env_url: env.PUBLIC_URL,
static_url: process.env.PUBLIC_URL,
dynamic_url: e[urlVar],
env_envtest: env.ENVTEST,
static_envtest: process.env.ENVTEST,
dynamic_envtest: e[envTestVar],
env_nextauth: env.NEXTAUTH_URL,
static_nextauth: process.env.NEXTAUTH_URL,
dynamic_nextauth: e[nextAuthUrlVar],
env_nextauth2: env.AUTH_URL,
static_nextauth2: process.env.AUTH_URL,
dynamic_nextauth2: e[nextAuthUrlVar2],
}
console.log(values)
return NextResponse.json(values)
}
export const dynamic = "force-dynamic"
export const runtime = "edge"

View File

@@ -1,39 +0,0 @@
import { config } from "dotenv"
import { NextResponse } from "next/server"
import { env } from "@/env/server"
import type { NextRequest } from "next/server"
config({ path: "./.env" })
export async function GET(request: NextRequest) {
const e = process.env
console.log({ process_env: process.env })
const urlVar = "PUBLIC_URL"
const nextAuthUrlVar = "NEXTAUTH_URL"
const nextAuthUrlVar2 = "AUTH_URL"
const envTestVar = "ENVTEST"
const values = {
env_url: env.PUBLIC_URL,
static_url: process.env.PUBLIC_URL,
dynamic_url: e[urlVar],
env_envtest: env.ENVTEST,
static_envtest: process.env.ENVTEST,
dynamic_envtest: e[envTestVar],
env_nextauth: env.NEXTAUTH_URL,
static_nextauth: process.env.NEXTAUTH_URL,
dynamic_nextauth: e[nextAuthUrlVar],
env_nextauth2: env.AUTH_URL,
static_nextauth2: process.env.AUTH_URL,
dynamic_nextauth2: e[nextAuthUrlVar2],
}
console.log(values)
return NextResponse.json(values)
}
export const dynamic = "force-dynamic"

View File

@@ -1,38 +0,0 @@
import "dotenv/config"
import { NextResponse } from "next/server"
import { env } from "@/env/server"
import type { NextRequest } from "next/server"
export async function GET(request: NextRequest) {
const e = process.env
console.log({ process_env: process.env })
const urlVar = "PUBLC_URL"
const nextAuthUrlVar = "NEXTAUTH_URL"
const nextAuthUrlVar2 = "AUTH_URL"
const envTestVar = "ENVTEST"
const values = {
env_url: env.PUBLIC_URL,
static_url: process.env.PUBLIC_URL,
dynamic_url: e[urlVar],
env_envtest: env.ENVTEST,
static_envtest: process.env.ENVTEST,
dynamic_envtest: e[envTestVar],
env_nextauth: env.NEXTAUTH_URL,
static_nextauth: process.env.NEXTAUTH_URL,
dynamic_nextauth: e[nextAuthUrlVar],
env_nextauth2: env.AUTH_URL,
static_nextauth2: process.env.AUTH_URL,
dynamic_nextauth2: e[nextAuthUrlVar2],
}
console.log(values)
return NextResponse.json(values)
}
export const dynamic = "force-dynamic"

View File

@@ -1,39 +0,0 @@
import { config } from "dotenv"
import { NextResponse } from "next/server"
import { env } from "@/env/server"
import type { NextRequest } from "next/server"
config({ debug: true, override: true })
export async function GET(request: NextRequest) {
const e = process.env
console.log({ process_env: process.env })
const urlVar = "PUBLC_URL"
const nextAuthUrlVar = "NEXTAUTH_URL"
const nextAuthUrlVar2 = "AUTH_URL"
const envTestVar = "ENVTEST"
const values = {
env_url: env.PUBLIC_URL,
static_url: process.env.PUBLIC_URL,
dynamic_url: e[urlVar],
env_envtest: env.ENVTEST,
static_envtest: process.env.ENVTEST,
dynamic_envtest: e[envTestVar],
env_nextauth: env.NEXTAUTH_URL,
static_nextauth: process.env.NEXTAUTH_URL,
dynamic_nextauth: e[nextAuthUrlVar],
env_nextauth2: env.AUTH_URL,
static_nextauth2: process.env.AUTH_URL,
dynamic_nextauth2: e[nextAuthUrlVar2],
}
console.log(values)
return NextResponse.json(values)
}
export const dynamic = "force-dynamic"

View File

@@ -1,36 +0,0 @@
import { NextResponse } from "next/server"
import { env } from "@/env/server"
import type { NextRequest } from "next/server"
export async function GET(request: NextRequest) {
const e = process.env
console.log({ process_env: process.env })
const urlVar = "PUBLIC_URL"
const nextAuthUrlVar = "NEXTAUTH_URL"
const nextAuthUrlVar2 = "AUTH_URL"
const envTestVar = "ENVTEST"
const values = {
env_url: env.PUBLIC_URL,
static_url: process.env.PUBLIC_URL,
dynamic_url: e[urlVar],
env_envtest: env.ENVTEST,
static_envtest: process.env.ENVTEST,
dynamic_envtest: e[envTestVar],
env_nextauth: env.NEXTAUTH_URL,
static_nextauth: process.env.NEXTAUTH_URL,
dynamic_nextauth: e[nextAuthUrlVar],
env_nextauth2: env.AUTH_URL,
static_nextauth2: process.env.AUTH_URL,
dynamic_nextauth2: e[nextAuthUrlVar2],
}
console.log(values)
return NextResponse.json(values)
}
export const dynamic = "force-dynamic"

View File

@@ -1,37 +0,0 @@
import { config } from "dotenv"
import { NextResponse } from "next/server"
import { env } from "@/env/server"
import type { NextRequest } from "next/server"
config({ path: "./.env" })
export async function GET(request: NextRequest) {
const e = process.env
console.log({ process_env: process.env })
const urlVar = "PUBLIC_URL"
const nextAuthUrlVar = "NEXTAUTH_URL"
const nextAuthUrlVar2 = "AUTH_URL"
const envTestVar = "ENVTEST"
const values = {
env_url: env.PUBLIC_URL,
static_url: process.env.PUBLIC_URL,
dynamic_url: e[urlVar],
env_envtest: env.ENVTEST,
static_envtest: process.env.ENVTEST,
dynamic_envtest: e[envTestVar],
env_nextauth: env.NEXTAUTH_URL,
static_nextauth: process.env.NEXTAUTH_URL,
dynamic_nextauth: e[nextAuthUrlVar],
env_nextauth2: env.AUTH_URL,
static_nextauth2: process.env.AUTH_URL,
dynamic_nextauth2: e[nextAuthUrlVar2],
}
console.log(values)
return NextResponse.json(values)
}

View File

@@ -1,36 +0,0 @@
import "dotenv/config"
import { NextResponse } from "next/server"
import { env } from "@/env/server"
import type { NextRequest } from "next/server"
export async function GET(request: NextRequest) {
const e = process.env
console.log({ process_env: process.env })
const urlVar = "PUBLIC_URL"
const nextAuthUrlVar = "NEXTAUTH_URL"
const nextAuthUrlVar2 = "AUTH_URL"
const envTestVar = "ENVTEST"
const values = {
env_url: env.PUBLIC_URL,
static_url: process.env.PUBLIC_URL,
dynamic_url: e[urlVar],
env_envtest: env.ENVTEST,
static_envtest: process.env.ENVTEST,
dynamic_envtest: e[envTestVar],
env_nextauth: env.NEXTAUTH_URL,
static_nextauth: process.env.NEXTAUTH_URL,
dynamic_nextauth: e[nextAuthUrlVar],
env_nextauth2: env.AUTH_URL,
static_nextauth2: process.env.AUTH_URL,
dynamic_nextauth2: e[nextAuthUrlVar2],
}
console.log(values)
return NextResponse.json(values)
}

View File

@@ -1,37 +0,0 @@
import { config } from "dotenv"
import { NextResponse } from "next/server"
import { env } from "@/env/server"
import type { NextRequest } from "next/server"
config({ debug: true, override: true })
export async function GET(request: NextRequest) {
const e = process.env
console.log({ process_env: process.env })
const urlVar = "PUBLIC_URL"
const nextAuthUrlVar = "NEXTAUTH_URL"
const nextAuthUrlVar2 = "AUTH_URL"
const envTestVar = "ENVTEST"
const values = {
env_url: env.PUBLIC_URL,
static_url: process.env.PUBLIC_URL,
dynamic_url: e[urlVar],
env_envtest: env.ENVTEST,
static_envtest: process.env.ENVTEST,
dynamic_envtest: e[envTestVar],
env_nextauth: env.NEXTAUTH_URL,
static_nextauth: process.env.NEXTAUTH_URL,
dynamic_nextauth: e[nextAuthUrlVar],
env_nextauth2: env.AUTH_URL,
static_nextauth2: process.env.AUTH_URL,
dynamic_nextauth2: e[nextAuthUrlVar2],
}
console.log(values)
return NextResponse.json(values)
}

View File

@@ -1,34 +0,0 @@
import { NextResponse } from "next/server"
import { env } from "@/env/server"
import type { NextRequest } from "next/server"
export async function GET(request: NextRequest) {
const e = process.env
console.log({ process_env: process.env })
const urlVar = "PUBLIC_URL"
const nextAuthUrlVar = "NEXTAUTH_URL"
const nextAuthUrlVar2 = "AUTH_URL"
const envTestVar = "ENVTEST"
const values = {
env_url: env.PUBLIC_URL,
static_url: process.env.PUBLIC_URL,
dynamic_url: e[urlVar],
env_envtest: env.ENVTEST,
static_envtest: process.env.ENVTEST,
dynamic_envtest: e[envTestVar],
env_nextauth: env.NEXTAUTH_URL,
static_nextauth: process.env.NEXTAUTH_URL,
dynamic_nextauth: e[nextAuthUrlVar],
env_nextauth2: env.AUTH_URL,
static_nextauth2: process.env.AUTH_URL,
dynamic_nextauth2: e[nextAuthUrlVar2],
}
console.log(values)
return NextResponse.json(values)
}

View File

@@ -6,20 +6,21 @@ import {
bookingConfirmation,
payment,
} from "@/constants/routes/hotelReservation"
import { getPublicURL } from "@/server/utils"
export async function GET(
request: NextRequest,
{ params }: { params: { lang: string; status: string } }
): Promise<NextResponse> {
const publicURL = getPublicURL(request)
console.log(`[payment-callback] callback started`)
const lang = params.lang as Lang
const status = params.status
const returnUrl = new URL(`${env.PUBLIC_URL}/${payment[lang]}`)
const returnUrl = new URL(`${publicURL}/${payment[lang]}`)
if (status === "success") {
const confirmationUrl = new URL(
`${env.PUBLIC_URL}/${bookingConfirmation[lang]}`
)
const confirmationUrl = new URL(`${publicURL}/${bookingConfirmation[lang]}`)
console.log(`[payment-callback] redirecting to: ${confirmationUrl}`)
return NextResponse.redirect(confirmationUrl)
}

View File

@@ -109,6 +109,7 @@ const curityProvider = {
} satisfies OIDCConfig<User>
export const config = {
basePath: "/api/web/auth",
debug: env.NEXTAUTH_DEBUG,
providers: [curityProvider],
redirectProxyUrl: env.NEXTAUTH_REDIRECT_PROXY_URL,
@@ -233,4 +234,4 @@ export const {
auth,
signIn,
signOut,
} = NextAuth(config)
} = NextAuth(config)

6
env/server.ts vendored
View File

@@ -37,15 +37,15 @@ export const env = createEnv({
.default("false"),
NEXTAUTH_REDIRECT_PROXY_URL: z.string().optional(),
NEXTAUTH_SECRET: z.string(),
NEXTAUTH_URL: z.string().optional(),
AUTH_URL: z.string().optional(),
NEXTAUTH_URL: z.string().default(""),
AUTH_URL: z.string().default(""),
NODE_ENV: z.enum(["development", "test", "production"]),
PRINT_QUERY: z
.string()
.refine((s) => s === "true" || s === "false")
.transform((s) => s === "true")
.default("false"),
PUBLIC_URL: z.string().optional(),
PUBLIC_URL: z.string().default(""),
REVALIDATE_SECRET: z.string(),
SALESFORCE_PREFERENCE_BASE_URL: z.string(),
SEAMLESS_LOGIN_DA: z.string(),

View File

@@ -2,8 +2,7 @@ import { NextResponse } from "next/server"
import { authRequired, mfaRequired } from "@/constants/routes/authRequired"
import { login } from "@/constants/routes/handleAuth"
import { env } from "@/env/server"
import { internalServerError } from "@/server/errors/next"
import { getPublicNextURL } from "@/server/utils"
import { auth } from "@/auth"
import { findLang } from "@/utils/languages"
@@ -44,14 +43,7 @@ export const middleware = auth(async (request) => {
const isLoggedIn = !!request.auth
const hasError = request.auth?.error
if (!env.PUBLIC_URL) {
throw internalServerError("Missing value for env.PUBLIC_URL")
}
const publicUrl = new URL(env.PUBLIC_URL)
const nextUrlPublic = nextUrl.clone()
nextUrlPublic.host = publicUrl.host
nextUrlPublic.hostname = publicUrl.hostname
const nextUrlPublic = getPublicNextURL(request)
/**
* Function to validate MFA from token data

View File

@@ -2,6 +2,7 @@ import { NextResponse } from "next/server"
import { env } from "@/env/server"
import { badRequest, internalServerError } from "@/server/errors/next"
import { getPublicURL } from "@/server/utils"
import { findLang } from "@/utils/languages"
@@ -16,10 +17,7 @@ export const middleware: NextMiddleware = (request) => {
}
const lang = findLang(request.nextUrl.pathname)!
if (!env.PUBLIC_URL) {
throw internalServerError("No value for env.PUBLIC_URL")
}
const redirectTo = env.PUBLIC_URL
const redirectTo = getPublicURL(request)
const headers = new Headers(request.headers)
headers.set("x-returnurl", redirectTo)

View File

@@ -8,6 +8,7 @@ import {
} from "@/constants/routes/myPages"
import { env } from "@/env/server"
import { internalServerError, notFound } from "@/server/errors/next"
import { getPublicNextURL } from "@/server/utils"
import { findLang } from "@/utils/languages"
@@ -23,17 +24,9 @@ export const middleware: NextMiddleware = async (request) => {
const myPagesRoot = myPages[lang]
if (nextUrl.pathname === myPagesRoot) {
if (!env.PUBLIC_URL) {
throw internalServerError("Missing value for env.PUBLIC_URL")
}
const publicUrl = new URL(env.PUBLIC_URL)
const nextUrlClone = nextUrl.clone()
nextUrlClone.host = publicUrl.host
nextUrlClone.hostname = publicUrl.hostname
const nextUrlPublic = getPublicNextURL(request)
const overviewUrl = overview[lang]
const redirectUrl = new URL(overviewUrl, nextUrlClone)
const redirectUrl = new URL(overviewUrl, nextUrlPublic)
console.log(`[myPages] redirecting to: ${redirectUrl}`)
return NextResponse.redirect(redirectUrl)
}

View File

@@ -1,7 +1,5 @@
import { stringify } from "querystring"
import { Lang } from "@/constants/languages"
import { env } from "@/env/server"
import { getPublicNextURL } from "@/server/utils"
import { resolve as resolveEntry } from "@/utils/entry"
import { findLang } from "@/utils/languages"
@@ -11,18 +9,7 @@ import type { NextRequest } from "next/server"
export function getDefaultRequestHeaders(request: NextRequest) {
const lang = findLang(request.nextUrl.pathname)!
let nextUrl
if (env.PUBLIC_URL) {
const publicUrl = new URL(env.PUBLIC_URL)
const nextUrlPublic = request.nextUrl.clone()
nextUrlPublic.host = publicUrl.host
nextUrlPublic.hostname = publicUrl.hostname
nextUrl = nextUrlPublic
} else {
nextUrl = request.nextUrl
}
const nextUrlPublic = getPublicNextURL(request)
const headers = new Headers(request.headers)
headers.set("x-lang", lang)
headers.set(
@@ -31,7 +18,7 @@ export function getDefaultRequestHeaders(request: NextRequest) {
request.nextUrl.pathname.replace(`/${lang}`, "").replace(`/webview`, "")
)
)
headers.set("x-url", removeTrailingSlash(nextUrl.href))
headers.set("x-url", removeTrailingSlash(nextUrlPublic.href))
return headers
}

View File

@@ -30,6 +30,3 @@ package = "@netlify/plugin-nextjs"
[images]
remote_images = ["https://imagevault-stage.scandichotels.com.*", "https://imagevault.scandichotels.com.*"]
[functions]
included_files = ["./.env"]

View File

@@ -4,7 +4,7 @@
"private": true,
"type": "module",
"scripts": {
"prebuild": "npm run update-dotenv && npm run lint && npm run test:unit",
"prebuild": "npm run lint && npm run test:unit",
"build": "next build",
"predev": "rm -rf .next",
"dev": "PORT=3000 NEXT_PUBLIC_PORT=3000 next dev",
@@ -20,7 +20,6 @@
"test:e2e:headless": "start-server-and-test test:setup http://127.0.0.1:3000/en/sponsoring \"cypress run --e2e\"",
"test:setup": "npm run build && npm run start",
"preinstall": "export $(cat .env.local | grep -v '^#' | xargs)",
"update-dotenv": "node update-dotenv.mjs",
"test:unit": "jest",
"test:unit:watch": "jest --watch"
},

View File

@@ -1,4 +1,5 @@
import { metrics } from "@opentelemetry/api"
import { Lang } from "@/constants/languages"
import { env } from "@/env/server"
import * as api from "@/lib/api"
@@ -9,7 +10,9 @@ import type { FriendTransaction, Stay } from "./output"
const meter = metrics.getMeter("trpc.user")
const getProfileCounter = meter.createCounter("trpc.user.profile")
const getProfileSuccessCounter = meter.createCounter("trpc.user.profile-success")
const getProfileSuccessCounter = meter.createCounter(
"trpc.user.profile-success"
)
const getProfileFailCounter = meter.createCounter("trpc.user.profile-fail")
async function updateStaysBookingUrl(
@@ -41,7 +44,7 @@ async function updateStaysBookingUrl(
// Temporary Url, domain and lang support for current web
const bookingUrl = new URL(
"/hotelreservation/my-booking",
env.PUBLIC_URL ?? ""
env.PUBLIC_URL || "https://www.scandichotels.com" // fallback to production for ephemeral envs (like deploy previews)
)
switch (lang) {
case Lang.sv:
@@ -83,10 +86,7 @@ async function updateStaysBookingUrl(
}
getProfileSuccessCounter.add(1)
console.info(
"api.user.profile updatebookingurl success",
JSON.stringify({})
)
console.info("api.user.profile updatebookingurl success", JSON.stringify({}))
return data.map((d) => {
const originalString =
@@ -98,10 +98,7 @@ async function updateStaysBookingUrl(
bookingUrl.searchParams.set("RefId", encryptedBookingValue)
} else {
bookingUrl.searchParams.set("lastName", apiJson.data.attributes.lastName)
bookingUrl.searchParams.set(
"bookingId",
d.attributes.confirmationNumber
)
bookingUrl.searchParams.set("bookingId", d.attributes.confirmationNumber)
}
return {
...d,
@@ -113,4 +110,4 @@ async function updateStaysBookingUrl(
})
}
export { updateStaysBookingUrl }
export { updateStaysBookingUrl }

View File

@@ -1,6 +1,9 @@
import { z } from "zod"
import { Lang } from "@/constants/languages"
import { env } from "@/env/server"
import type { NextRequest } from "next/server"
export const langInput = z.object({
lang: z.nativeEnum(Lang),
@@ -33,3 +36,27 @@ export function toLang(lang: string): Lang | undefined {
const lowerCaseLang = lang.toLowerCase()
return Object.values(Lang).find((l) => l === lowerCaseLang)
}
export function getPublicURL(request: NextRequest) {
if (env.PUBLIC_URL) {
return env.PUBLIC_URL
}
const host = request.nextUrl.host
const proto = request.nextUrl.protocol
return `${proto}//${host}`
}
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
}

View File

@@ -1,71 +0,0 @@
/**
* Build time environment variables are not available in Netlify functions at
* runtime. The official workaround is to create an artifact and include that
* in the bundled functions so that the function can load/read it at runtime.
* In other words, during the build fill the .env file with the environment
* variables needed and then instruct Netlify to include the .env file together
* with the bundled function.
*
* This works but has two things to consider:
*
* 1. Any environment variable created in the Netlify UI will be considered
* defined. Even if the variable is set to "empty" in the Netlify UI it is
* still an empty string and therefore defined.
*
* 2. Next.js uses @next/env to automatically read the .env
* file into the process environment. @next/env does NOT override any
* defined variables, empty strings are also considered defined. So for
* @next/env to automatically pick up the .env file in the bundled functions
* we need to make sure that none of the variables in the .env file are
* defined in the Netlify UI. @next/env does not have any "override=true"
* option, like dotenv package. So rather than introduce dotenv and manually
* use it in *every* function, we can delegate to @next/env if we keep the
* environment variables in Netlify UI in check.
*
* We only run this on Netlify build.
*
* We define PUBLIC_URL and use that because we are behind Akamai reverse proxy.
* For the stable environments (test, stage, production) these are defined. For
* any other environment (branch deploys and deploy previews) we use the
* predefined Netlify environment variable DEPLOY_PRIME_URL.
*
* Both AUTH_URL and NEXTAUTH_URL is set to point to the PUBLIC_URL.
* We set both as a precaution as next-auth v5 is transitioning to AUTH_* but we
* have seen several occurences in the auth.js codebase that are not using both.
*/
import fs from "node:fs"
if (process.env.NETLIFY) {
const PUBLIC_URLS = {
production: "https://www.scandichotels.com",
stage: "https://stage.scandichotels.com",
test: "https://test2.scandichotels.com",
}
let PUBLIC_URL
if (PUBLIC_URLS[process.env.CONTEXT]) {
PUBLIC_URL = PUBLIC_URLS[process.env.CONTEXT]
} else if (PUBLIC_URLS[process.env.BRANCH]) {
PUBLIC_URL = PUBLIC_URLS[process.env.BRANCH]
} else {
PUBLIC_URL = process.env.DEPLOY_PRIME_URL
}
const AUTH_URL = `${PUBLIC_URL}/api/web/auth`
const NEXTAUTH_URL = AUTH_URL
const replaceMap = {
AUTH_URL,
NEXTAUTH_URL,
PUBLIC_URL,
}
let contents = fs.readFileSync("./.env", { encoding: "utf-8" })
for (const [key, value] of Object.entries(replaceMap)) {
contents = contents.replace(new RegExp(`${key}=.*`), `${key}="${value}"`)
}
fs.writeFileSync("./.env", contents, { encoding: "utf-8" })
}