feat: add support for app url variables (#915)
* feat: add support for app url variables * fix: test not working * fix: format issue
This commit is contained in:
@@ -5,8 +5,9 @@
|
||||
"type": "module",
|
||||
"exports": {
|
||||
".": "./index.ts",
|
||||
"./types": "./src/types.ts",
|
||||
"./server": "./src/server.ts",
|
||||
"./types": "./src/types.ts"
|
||||
"./client": "./src/client.ts"
|
||||
},
|
||||
"typesVersions": {
|
||||
"*": {
|
||||
@@ -24,8 +25,9 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"dayjs": "^1.11.12",
|
||||
"next": "^14.2.5",
|
||||
"react": "^18.3.1",
|
||||
"next": "^14.2.5"
|
||||
"tldts": "^6.1.37"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@homarr/eslint-config": "workspace:^0.2.0",
|
||||
|
||||
23
packages/common/src/app-url/base.ts
Normal file
23
packages/common/src/app-url/base.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import * as tldts from "tldts";
|
||||
|
||||
const safeParseTldts = (url: string) => {
|
||||
try {
|
||||
return tldts.parse(url);
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
export const parseAppHrefWithVariables = <TInput extends string | null>(url: TInput, currentHref: string): TInput => {
|
||||
if (!url || url.length === 0) return url;
|
||||
|
||||
const tldtsResult = safeParseTldts(currentHref);
|
||||
|
||||
const urlObject = new URL(currentHref);
|
||||
|
||||
return url
|
||||
.replaceAll("[homarr_base]", `${urlObject.protocol}//${urlObject.hostname}`)
|
||||
.replaceAll("[homarr_hostname]", tldtsResult?.hostname ?? "")
|
||||
.replaceAll("[homarr_domain]", tldtsResult?.domain ?? "")
|
||||
.replaceAll("[homarr_protocol]", urlObject.protocol.replace(":", "")) as TInput;
|
||||
};
|
||||
5
packages/common/src/app-url/client.ts
Normal file
5
packages/common/src/app-url/client.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
import { parseAppHrefWithVariables } from "./base";
|
||||
|
||||
export const parseAppHrefWithVariablesClient = <TInput extends string | null>(url: TInput): TInput => {
|
||||
return parseAppHrefWithVariables(url, window.location.href);
|
||||
};
|
||||
8
packages/common/src/app-url/server.ts
Normal file
8
packages/common/src/app-url/server.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import { headers } from "next/headers";
|
||||
|
||||
import { extractBaseUrlFromHeaders } from "../url";
|
||||
import { parseAppHrefWithVariables } from "./base";
|
||||
|
||||
export const parseAppHrefWithVariablesServer = <TInput extends string | null>(url: TInput): TInput => {
|
||||
return parseAppHrefWithVariables(url, extractBaseUrlFromHeaders(headers()));
|
||||
};
|
||||
1
packages/common/src/client.ts
Normal file
1
packages/common/src/client.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from "./app-url/client";
|
||||
@@ -1 +1,2 @@
|
||||
export * from "./app-url/server";
|
||||
export * from "./security";
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import type { ReadonlyHeaders } from "next/dist/server/web/spec-extension/adapters/headers";
|
||||
|
||||
export const appendPath = (url: URL | string, path: string) => {
|
||||
const newUrl = new URL(url);
|
||||
newUrl.pathname = removeTrailingSlash(newUrl.pathname) + path;
|
||||
@@ -7,3 +9,16 @@ export const appendPath = (url: URL | string, path: string) => {
|
||||
const removeTrailingSlash = (path: string) => {
|
||||
return path.at(-1) === "/" ? path.substring(0, path.length - 1) : path;
|
||||
};
|
||||
|
||||
export const extractBaseUrlFromHeaders = (headers: ReadonlyHeaders): `${string}://${string}` => {
|
||||
let protocol = headers.get("x-forwarded-proto") ?? "http";
|
||||
|
||||
// @see https://support.glitch.com/t/x-forwarded-proto-contains-multiple-protocols/17219
|
||||
if (protocol.includes(",")) {
|
||||
protocol = protocol.includes("https") ? "https" : "http";
|
||||
}
|
||||
|
||||
const host = headers.get("x-forwarded-host") ?? headers.get("host");
|
||||
|
||||
return `${protocol}://${host}`;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user