61 lines
1.6 KiB
TypeScript
61 lines
1.6 KiB
TypeScript
const WILDCARD_HOSTNAMES = new Set(["0.0.0.0", "::", "[::]"]);
|
|
const LOCAL_HOSTNAMES = new Set([...WILDCARD_HOSTNAMES, "localhost"]);
|
|
|
|
function isWildcardHostname(hostname: string) {
|
|
return WILDCARD_HOSTNAMES.has(hostname);
|
|
}
|
|
|
|
function isLocalHostname(hostname: string) {
|
|
return (
|
|
LOCAL_HOSTNAMES.has(hostname) ||
|
|
hostname === "127.0.0.1" ||
|
|
hostname.startsWith("127.")
|
|
);
|
|
}
|
|
|
|
export function resolvePublicAppOrigin(input: {
|
|
configuredUrl?: string;
|
|
authUrl?: string;
|
|
requestUrl?: string;
|
|
production: boolean;
|
|
}) {
|
|
const configured = input.configuredUrl?.trim() || input.authUrl?.trim();
|
|
if (!configured) {
|
|
if (input.production) {
|
|
throw new Error("NEXT_PUBLIC_APP_URL is required in production");
|
|
}
|
|
if (input.requestUrl) {
|
|
const requestOrigin = new URL(input.requestUrl);
|
|
if (!isWildcardHostname(requestOrigin.hostname)) {
|
|
return requestOrigin.origin;
|
|
}
|
|
}
|
|
return "http://localhost:3000";
|
|
}
|
|
|
|
const url = new URL(configured);
|
|
if (isWildcardHostname(url.hostname)) {
|
|
throw new Error(
|
|
`NEXT_PUBLIC_APP_URL resolved to a wildcard bind address (${url.hostname})`,
|
|
);
|
|
}
|
|
if (
|
|
input.production &&
|
|
(url.protocol !== "https:" || isLocalHostname(url.hostname))
|
|
) {
|
|
throw new Error(
|
|
"NEXT_PUBLIC_APP_URL must be a public HTTPS origin in production",
|
|
);
|
|
}
|
|
return url.origin;
|
|
}
|
|
|
|
export function publicAppOrigin(requestUrl?: string) {
|
|
return resolvePublicAppOrigin({
|
|
configuredUrl: process.env.NEXT_PUBLIC_APP_URL,
|
|
authUrl: process.env.BETTER_AUTH_URL,
|
|
requestUrl,
|
|
production: process.env.NODE_ENV === "production",
|
|
});
|
|
}
|