diff --git a/src/lib/client/resolver.ts b/src/lib/client/resolver.ts new file mode 100644 index 00000000..a0274e2b --- /dev/null +++ b/src/lib/client/resolver.ts @@ -0,0 +1,33 @@ +// eslint-disable-next-line @typescript-eslint/no-explicit-any +type ResolveFn = (...args: any[]) => string; + +/** + * Wrapper for SvelteKit's resolve function + * @param resolve - The resolve function from $app/paths + * @param path - The route path or route ID (e.g., "/blog/[slug]") or absolute URL + * @param params - Optional parameters for dynamic route segments + * @returns The resolved URL with base path, or the original URL if it's absolute + * + * @example + * ```ts + * // Using a static path + * urlResolve(resolve, "/dashboard-apis/monitor-bar") + * + * // Using a dynamic route with params + * urlResolve(resolve, "/blog/[slug]", { slug: "hello-world" }) + * + * // Using an absolute URL (returns as-is) + * urlResolve(resolve, "https://example.com/api") + * ``` + */ +export default function urlResolve(resolve: ResolveFn, path: string, params?: Record): string { + // If path is an absolute URL, return it as-is + if (path.startsWith("http://") || path.startsWith("https://")) { + return path; + } + + if (params) { + return resolve(path, params); + } + return resolve(path); +} diff --git a/src/lib/components/KenerNav.svelte b/src/lib/components/KenerNav.svelte index 96d03f39..48cd103c 100644 --- a/src/lib/components/KenerNav.svelte +++ b/src/lib/components/KenerNav.svelte @@ -2,6 +2,8 @@ import { page } from "$app/state"; import * as NavigationMenu from "$lib/components/ui/navigation-menu/index.js"; import { navigationMenuTriggerStyle } from "$lib/components/ui/navigation-menu/navigation-menu-trigger.svelte"; + import { resolve } from "$app/paths"; + import urlResolve from "$lib/client/resolver.js"; let { data } = page; const navItems: { name: string; url: string; iconURL: string }[] = data.navItems || []; @@ -13,12 +15,12 @@
{#if logo} - {siteName} + {siteName} {/if} {siteName} @@ -31,14 +33,14 @@ {#snippet child()} {#if item.iconURL} - {item.name} + {item.name} {/if} {item.name} diff --git a/src/lib/components/MonitorBar.svelte b/src/lib/components/MonitorBar.svelte index 202f1983..aa48385c 100644 --- a/src/lib/components/MonitorBar.svelte +++ b/src/lib/components/MonitorBar.svelte @@ -9,6 +9,7 @@ import StatusBarCalendar from "$lib/components/StatusBarCalendar.svelte"; import { selectedTimezone } from "$lib/stores/timezone"; import type { MonitorBarResponse, BarData } from "$lib/server/api-server/monitor-bar/get.js"; + import { resolve } from "$app/paths"; interface Props { tag: string; @@ -52,7 +53,7 @@ try { const endOfDayTodayAtTz = getEndOfDayAtTz($selectedTimezone); const response = await fetch( - `/dashboard-apis/monitor-bar?tag=${encodeURIComponent(tag)}&endOfDayTodayAtTz=${endOfDayTodayAtTz}` + `${resolve("/dashboard-apis/monitor-bar")}?tag=${encodeURIComponent(tag)}&endOfDayTodayAtTz=${endOfDayTodayAtTz}` ); if (!response.ok) { throw new Error("Failed to fetch monitor data"); diff --git a/src/lib/components/nav.svelte b/src/lib/components/nav.svelte deleted file mode 100644 index 52551504..00000000 --- a/src/lib/components/nav.svelte +++ /dev/null @@ -1,119 +0,0 @@ - - -{#if defaultPattern == "pets" && !!randomPet} -
-{:else} -
-{/if} - -
-
- - {#if data.site.logo} - - {/if} - {#if data.site.siteName} - - {data.site.siteName} - - {/if} - -
- {#if data.site.nav} - -
- - - - - - {#each data.site.nav as navItem} - - - {navItem.name} - - - {/each} - - -
- {/if} -
-
-
diff --git a/src/lib/server/resolver.ts b/src/lib/server/resolver.ts new file mode 100644 index 00000000..ca09d934 --- /dev/null +++ b/src/lib/server/resolver.ts @@ -0,0 +1,52 @@ +/** + * Server-side URL resolver that uses KENER_BASE_PATH environment variable + * Works in both SvelteKit and Node scheduler contexts + * + * @param path - The route path (e.g., "/api/monitor") or absolute URL + * @param params - Optional parameters for dynamic route segments (e.g., { slug: "hello" }) + * @returns The resolved URL with base path, or the original URL if it's absolute + * + * @example + * ```ts + * // Using a static path + * serverResolve("/dashboard-apis/monitor-bar") + * // Returns: "/status/dashboard-apis/monitor-bar" (if KENER_BASE_PATH=/status) + * + * // Using dynamic route with params + * serverResolve("/blog/[slug]", { slug: "hello-world" }) + * // Returns: "/status/blog/hello-world" + * + * // Using an absolute URL (returns as-is) + * serverResolve("https://example.com/api") + * // Returns: "https://example.com/api" + * ``` + */ +export function serverResolve(path: string, params?: Record): string { + // If path is an absolute URL, return it as-is + if (path.startsWith("http://") || path.startsWith("https://")) { + return path; + } + + // Get base path from environment variable + const basePath = process.env.KENER_BASE_PATH || ""; + + // Replace route parameters if provided + let resolvedPath = path; + if (params) { + for (const [key, value] of Object.entries(params)) { + resolvedPath = resolvedPath.replace(`[${key}]`, value); + } + } + + // Ensure path starts with / + if (!resolvedPath.startsWith("/")) { + resolvedPath = "/" + resolvedPath; + } + + // Combine base path with resolved path + // Ensure no double slashes + const fullPath = basePath + resolvedPath; + return fullPath.replace(/\/+/g, "/"); +} + +export default serverResolve; diff --git a/src/routes/(account)/account/signin/+page.server.ts b/src/routes/(account)/account/signin/+page.server.ts index 539057f9..02f10352 100644 --- a/src/routes/(account)/account/signin/+page.server.ts +++ b/src/routes/(account)/account/signin/+page.server.ts @@ -1,21 +1,19 @@ import { redirect } from "@sveltejs/kit"; import type { PageServerLoad } from "./$types"; -import dotenv from "dotenv"; import { VerifyToken } from "$lib/server/controllers/controller.js"; import db from "$lib/server/db/db.js"; - -dotenv.config(); +import serverResolve from "$lib/server/resolver.js"; export const load: PageServerLoad = async ({ cookies }) => { const tokenData = cookies.get("kener-user"); if (tokenData) { const tokenUser = await VerifyToken(tokenData); if (!tokenUser) { - throw redirect(302, "/account/logout"); + throw redirect(302, serverResolve("/account/logout")); } const userDB = await db.getUserByEmail(tokenUser.email); if (userDB) { - throw redirect(302, "/manage/app/site-configurations"); + throw redirect(302, serverResolve("/manage/app/site-configurations")); } } diff --git a/src/routes/(kener)/+page.server.ts b/src/routes/(kener)/+page.server.ts index 5a0e9c82..fbb29e42 100644 --- a/src/routes/(kener)/+page.server.ts +++ b/src/routes/(kener)/+page.server.ts @@ -1,11 +1,14 @@ import { error } from "@sveltejs/kit"; import type { PageServerLoad } from "./$types"; import { GetPageDashboardData } from "$lib/server/controllers/dashboardController.js"; +import { resolve } from "$app/paths"; +import { env } from "$env/dynamic/private"; -export const load: PageServerLoad = async ({ url }) => { - const pagePath = url.pathname.substring(1); // Remove leading slash - - const dashboardData = await GetPageDashboardData(pagePath); +export const load: PageServerLoad = async ({ url, params }) => { + const pagePath = url.pathname.replace(/\//g, ""); // Remove all slash if it exists + const base = !!env.KENER_BASE_PATH ? env.KENER_BASE_PATH.substring(1) : ""; // Remove leading slash from base path if it exists + const normalizedPagePath = base && pagePath.startsWith(base) ? pagePath.substring(base.length) : pagePath; + const dashboardData = await GetPageDashboardData(normalizedPagePath); if (!dashboardData) { throw error(404, "Page Not Found"); } diff --git a/src/routes/(kener)/+page.svelte b/src/routes/(kener)/+page.svelte index a645467b..3a8b0d68 100644 --- a/src/routes/(kener)/+page.svelte +++ b/src/routes/(kener)/+page.svelte @@ -1,9 +1,8 @@