moved landing page to root and moved app to /dashboard

main
TZGyn 1 year ago
parent 7d17b588d9
commit 33d7bf228b
Signed by: TZGyn
GPG Key ID: 122EAF77AE81FD4A

@ -6,30 +6,7 @@ export const handle: Handle = async ({ event, resolve }) => {
const pathname = event.url.pathname const pathname = event.url.pathname
if (pathname.startsWith('/landing')) { if (pathname.startsWith('/dashboard')) {
const response = await resolve(event)
return response
}
const allowedPath = ['/login', '/signup']
if (allowedPath.includes(pathname)) {
if (sessionId) {
redirect(303, '/')
}
event.locals.session = null
const response = await resolve(event)
return response
}
if (pathname.startsWith('/api')) {
const response = await resolve(event)
return response
}
if (!sessionId) { if (!sessionId) {
redirect(303, '/login') redirect(303, '/login')
} }
@ -61,5 +38,22 @@ export const handle: Handle = async ({ event, resolve }) => {
const response = await resolve(event) const response = await resolve(event)
return response
}
const authPaths = ['/login', '/signup']
if (authPaths.includes(pathname)) {
if (sessionId) {
redirect(303, '/dashboard')
}
event.locals.session = null
const response = await resolve(event)
return response
}
const response = await resolve(event)
return response return response
} }

@ -18,7 +18,7 @@
TrashIcon, TrashIcon,
} from 'lucide-svelte' } from 'lucide-svelte'
import DeleteShortenerDialog from './DeleteShortenerDialog.svelte' import DeleteShortenerDialog from './DeleteShortenerDialog.svelte'
import EditLinkPage from '$lib/../routes/(app)/links/[id]/edit/+page.svelte' import EditLinkPage from '$lib/../routes/(app)/dashboard/links/[id]/edit/+page.svelte'
import { goto, preloadData, pushState } from '$app/navigation' import { goto, preloadData, pushState } from '$app/navigation'
import { cn } from '$lib/utils' import { cn } from '$lib/utils'
@ -41,16 +41,16 @@
const getUrl = () => { const getUrl = () => {
if (shortener.projectUuid) { if (shortener.projectUuid) {
return `/projects/${shortener.projectUuid}` return `/dashboard/projects/${shortener.projectUuid}`
} }
return '' return '/dashboard'
} }
let editProjectLinkOpen = false let editProjectLinkOpen = false
let editData: typeof $page.state.editLink let editData: typeof $page.state.editLink
const showEditModal = async (code: string) => { const showEditModal = async (code: string) => {
const href = `/links/${code}/edit` const href = `/dashboard/links/${code}/edit`
const result = await preloadData(href) const result = await preloadData(href)
if (result.type === 'loaded' && result.status === 200) { if (result.type === 'loaded' && result.status === 200) {
@ -70,7 +70,7 @@
const result = await preloadData(href) const result = await preloadData(href)
if (result.type === 'loaded' && result.status === 200) { if (result.type === 'loaded' && result.status === 200) {
if (getUrl().startsWith('/projects')) { if (getUrl().startsWith('/dashboard/projects')) {
pushState(href, { projectLinkQR: result.data }) pushState(href, { projectLinkQR: result.data })
} else { } else {
pushState(href, { linkQR: result.data }) pushState(href, { linkQR: result.data })
@ -113,7 +113,7 @@
</Tooltip.Root> </Tooltip.Root>
<div <div
class="flex items-center gap-2 text-sm text-muted-foreground"> class="text-muted-foreground flex items-center gap-2 text-sm">
<a <a
href={'https://' + shortenerUrl + '/' + shortener.code} href={'https://' + shortenerUrl + '/' + shortener.code}
target="_blank" target="_blank"
@ -131,7 +131,7 @@
<DropdownMenu.Content> <DropdownMenu.Content>
<DropdownMenu.Group> <DropdownMenu.Group>
<a <a
href={`/links/${shortener.code}/edit`} href={`/dashboard/links/${shortener.code}/edit`}
on:click|preventDefault={() => on:click|preventDefault={() =>
showEditModal(shortener.code)}> showEditModal(shortener.code)}>
<DropdownMenu.Item class="flex items-center gap-2"> <DropdownMenu.Item class="flex items-center gap-2">
@ -140,7 +140,7 @@
</a> </a>
<DropdownMenu.Item <DropdownMenu.Item
on:click={() => openDeleteDialog(shortener.code)} on:click={() => openDeleteDialog(shortener.code)}
class="flex items-center gap-2 text-destructive data-[highlighted]:bg-destructive"> class="text-destructive data-[highlighted]:bg-destructive flex items-center gap-2">
<TrashIcon size={16} /> <TrashIcon size={16} />
Delete Delete
</DropdownMenu.Item> </DropdownMenu.Item>
@ -153,8 +153,8 @@
<div class="flex items-center justify-between"> <div class="flex items-center justify-between">
<div class="flex gap-2"> <div class="flex gap-2">
<Button <Button
href={`/links/${shortener.code}`} href={`/dashboard/links/${shortener.code}`}
class="flex h-8 items-center justify-center gap-1 rounded bg-secondary text-sm"> class="bg-secondary flex h-8 items-center justify-center gap-1 rounded text-sm">
<BarChart size={20} /> <BarChart size={20} />
<div> <div>
{shortener.visitorCount} visits {shortener.visitorCount} visits
@ -163,7 +163,7 @@
<a <a
class={cn( class={cn(
buttonVariants({ variant: 'default' }), buttonVariants({ variant: 'default' }),
'flex h-8 items-center justify-center gap-1 rounded bg-secondary text-sm', 'bg-secondary flex h-8 items-center justify-center gap-1 rounded text-sm',
)} )}
href={`${getUrl()}/links/${shortener.code}/qr`} href={`${getUrl()}/links/${shortener.code}/qr`}
on:click|preventDefault={showQRModal}> on:click|preventDefault={showQRModal}>

@ -38,7 +38,7 @@
<DropdownMenu.Separator /> <DropdownMenu.Separator />
<DropdownMenu.Item <DropdownMenu.Item
on:click={() => { on:click={() => {
goto('/settings') goto('/dashboard/settings')
onClick() onClick()
}}> }}>
Settings Settings
@ -61,8 +61,9 @@
</AlertDialog.Description> </AlertDialog.Description>
</AlertDialog.Header> </AlertDialog.Header>
<AlertDialog.Footer> <AlertDialog.Footer>
<AlertDialog.Cancel disabled={isLoading} <AlertDialog.Cancel disabled={isLoading}>
>Cancel</AlertDialog.Cancel> Cancel
</AlertDialog.Cancel>
<Button <Button
on:click={logout} on:click={logout}
class="flex gap-2" class="flex gap-2"

@ -10,38 +10,42 @@
const routes = [ const routes = [
{ {
href: '/', href: '/dashboard',
name: 'Home', name: 'Home',
regex: createRegExp(exactly('/').notBefore(word)), regex: createRegExp(exactly('/dashboard/').notBefore(word)),
icon: Home, icon: Home,
}, },
{ {
href: '/links', href: '/dashboard/links',
name: 'Links', name: 'Links',
regex: createRegExp( regex: createRegExp(
exactly('/links') exactly('/dashboard/links')
.at.lineStart() .at.lineStart()
.or(exactly('/links/').notBefore(word).and(word)), .or(exactly('/dashboard/links/').notBefore(word).and(word)),
), ),
icon: Link, icon: Link,
}, },
{ {
href: '/projects', href: '/dashboard/projects',
name: 'Projects', name: 'Projects',
regex: createRegExp( regex: createRegExp(
exactly('/projects') exactly('/dashboard/projects')
.at.lineStart() .at.lineStart()
.or(exactly('/projects/').notBefore(word).and(word)), .or(
exactly('/dashboard/projects/').notBefore(word).and(word),
),
), ),
icon: Blocks, icon: Blocks,
}, },
{ {
href: '/settings/account', href: '/dashboard/settings/account',
name: 'Settings', name: 'Settings',
regex: createRegExp( regex: createRegExp(
exactly('/settings') exactly('/dashboard/settings')
.at.lineStart() .at.lineStart()
.or(exactly('/settings/').notBefore(word).and(word)), .or(
exactly('/dashboard/settings/').notBefore(word).and(word),
),
), ),
icon: Settings, icon: Settings,
}, },
@ -61,7 +65,7 @@
? 'secondary' ? 'secondary'
: 'ghost'} : 'ghost'}
href={route.href} href={route.href}
class="flex items-center justify-start gap-4 text-base hover:bg-secondary/50"> class="hover:bg-secondary/50 flex items-center justify-start gap-4 text-base">
<svelte:component this={route.icon} class="h-4 w-4" /> <svelte:component this={route.icon} class="h-4 w-4" />
<div class="hidden lg:flex"> <div class="hidden lg:flex">
{route.name} {route.name}

@ -4,7 +4,7 @@ import type { LayoutServerLoad } from './$types'
export const load = (async (event) => { export const load = (async (event) => {
const user = event.locals.user const user = event.locals.user
const breadcrumbs = [{ name: 'Home', path: '/' }] const breadcrumbs = [{ name: 'Home', path: '/dashboard' }]
const page_title = 'Home' const page_title = 'Home'

@ -8,31 +8,31 @@
export let data: PageData export let data: PageData
</script> </script>
<div class="flex flex-col gap-4 py-8 px-10"> <div class="flex flex-col gap-4 px-10 py-8">
<h2 class="text-2xl font-bold tracking-tight">Projects</h2> <h2 class="text-2xl font-bold tracking-tight">Projects</h2>
<Separator class="" /> <Separator class="" />
</div> </div>
<div class="flex flex-wrap gap-2 items-stretch px-6 w-full"> <div class="flex w-full flex-wrap items-stretch gap-2 px-6">
{#each data.projects as project} {#each data.projects as project}
<a href={'/projects/' + project.uuid}> <a href={'/dashboard/projects/' + project.uuid}>
<Card.Root <Card.Root
class="hover:cursor-pointer w-[500px] hover:bg-secondary"> class="hover:bg-secondary w-[500px] hover:cursor-pointer">
<Card.Header> <Card.Header>
<Card.Title class="flex gap-2 items-center"> <Card.Title class="flex items-center gap-2">
{project.name} {project.name}
</Card.Title> </Card.Title>
</Card.Header> </Card.Header>
<Card.Content> <Card.Content>
<div class="flex gap-4 w-full"> <div class="flex w-full gap-4">
<Button <Button
class="flex gap-1 justify-center items-center h-8 text-sm rounded bg-secondary"> class="bg-secondary flex h-8 items-center justify-center gap-1 rounded text-sm">
<ExternalLink size={20} /> <ExternalLink size={20} />
{project.shortener.length} {project.shortener.length}
Shorteners Shorteners
</Button> </Button>
<Button <Button
class="flex gap-1 justify-center items-center h-8 text-sm rounded bg-secondary"> class="bg-secondary flex h-8 items-center justify-center gap-1 rounded text-sm">
<BarChart size={20} /> <BarChart size={20} />
{project.shortener.reduce( {project.shortener.reduce(
(curr, shortener) => shortener.visitor.length + curr, (curr, shortener) => shortener.visitor.length + curr,

@ -3,13 +3,14 @@
import Button from '$lib/components/ui/button/button.svelte' import Button from '$lib/components/ui/button/button.svelte'
</script> </script>
<div class="flex justify-center items-center w-full h-full"> <div class="flex h-full w-full items-center justify-center">
<div class="flex flex-col gap-12 items-center"> <div class="flex flex-col items-center gap-12">
<div class="flex flex-col gap-4 items-center"> <div class="flex flex-col items-center gap-4">
<div class="text-4xl font-bold">404</div> <div class="text-4xl font-bold">404</div>
<div class="text-4xl font-bold">Page Not Found</div> <div class="text-4xl font-bold">Page Not Found</div>
</div> </div>
<Button on:click={() => goto('/landing')} class="w-fit" <Button on:click={() => goto('/dashboard')} class="w-fit">
>Return</Button> Return Home
</Button>
</div> </div>
</div> </div>

@ -5,7 +5,7 @@ export const load = (async (event) => {
const breadcrumbs = [ const breadcrumbs = [
...parentBreadcrumbs, ...parentBreadcrumbs,
{ name: 'Links', path: '/links' }, { name: 'Links', path: '/dashboard/links' },
] ]
const page_title = 'Links' const page_title = 'Links'

@ -67,9 +67,9 @@
}) })
const searchParams = urlParams.toString() const searchParams = urlParams.toString()
if (searchParams) { if (searchParams) {
return '/links?' + searchParams return '/dashboard/links?' + searchParams
} else { } else {
return '/links' return '/dashboard/links'
} }
} }
@ -373,7 +373,7 @@
perPage={data.perPage} perPage={data.perPage}
page={data.page} page={data.page}
total={pagination[0].total} total={pagination[0].total}
path={'/links'} /> path={'/dashboard/links'} />
{/await} {/await}
<Dialog.Root <Dialog.Root

@ -28,7 +28,7 @@ export const load = (async (event) => {
}) })
if (!shortener) { if (!shortener) {
redirect(300, `/links`) redirect(300, `/dashboard/links`)
} }
const projects = await db.query.project.findMany({ const projects = await db.query.project.findMany({

@ -15,7 +15,7 @@ export const load = (async (event) => {
}) })
if (!shortener) { if (!shortener) {
redirect(300, `/links`) redirect(300, `/dashboard/links`)
} }
const settings = await db.query.setting.findFirst({ const settings = await db.query.setting.findFirst({

@ -4,7 +4,7 @@ export const load = (async (event) => {
const { breadcrumbs: parentBreadcrumbs } = await event.parent() const { breadcrumbs: parentBreadcrumbs } = await event.parent()
const breadcrumbs = [ const breadcrumbs = [
...parentBreadcrumbs, ...parentBreadcrumbs,
{ name: 'Projects', path: '/projects' }, { name: 'Projects', path: '/dashboard/projects' },
] ]
const page_title = 'Projects' const page_title = 'Projects'
return { breadcrumbs, page_title } return { breadcrumbs, page_title }

@ -69,9 +69,9 @@
{#if data.projects.length > 0} {#if data.projects.length > 0}
<div class="flex flex-wrap gap-4 overflow-scroll p-4"> <div class="flex flex-wrap gap-4 overflow-scroll p-4">
{#each data.projects as project} {#each data.projects as project}
<a href={'/projects/' + project.uuid}> <a href={'/dashboard/projects/' + project.uuid}>
<Card.Root <Card.Root
class="w-[500px] hover:cursor-pointer hover:bg-secondary"> class="hover:bg-secondary w-[500px] hover:cursor-pointer">
<Card.Header> <Card.Header>
<Card.Title class="flex items-center gap-2"> <Card.Title class="flex items-center gap-2">
{project.name} {project.name}
@ -80,7 +80,7 @@
<Card.Content> <Card.Content>
<div class="flex w-full justify-between"> <div class="flex w-full justify-between">
<Button <Button
class="flex h-8 items-center justify-center gap-1 rounded bg-secondary text-sm"> class="bg-secondary flex h-8 items-center justify-center gap-1 rounded text-sm">
<ExternalLink size={20} /> <ExternalLink size={20} />
{project.shortener.length} {project.shortener.length}
Shorteners Shorteners

@ -40,7 +40,7 @@
let editData: typeof $page.state.editProjectLink let editData: typeof $page.state.editProjectLink
const showEditModal = async (projectUuid: string, code: string) => { const showEditModal = async (projectUuid: string, code: string) => {
const href = `/projects/${projectUuid}/links/${code}/edit` const href = `/dashboard/projects/${projectUuid}/links/${code}/edit`
const result = await preloadData(href) const result = await preloadData(href)
if (result.type === 'loaded' && result.status === 200) { if (result.type === 'loaded' && result.status === 200) {
@ -98,7 +98,7 @@
</Tooltip.Root> </Tooltip.Root>
<div <div
class="flex items-center gap-2 text-sm text-muted-foreground"> class="text-muted-foreground flex items-center gap-2 text-sm">
<a <a
href={'https://' + shortenerUrl + '/' + shortener.code} href={'https://' + shortenerUrl + '/' + shortener.code}
target="_blank" target="_blank"
@ -116,7 +116,7 @@
<DropdownMenu.Content> <DropdownMenu.Content>
<DropdownMenu.Group> <DropdownMenu.Group>
<a <a
href={`/projects/${selected_project.uuid}/links/${shortener.code}/edit`} href={`/dashboard/projects/${selected_project.uuid}/links/${shortener.code}/edit`}
on:click|preventDefault={() => on:click|preventDefault={() =>
showEditModal( showEditModal(
selected_project.uuid || '', selected_project.uuid || '',
@ -128,7 +128,7 @@
</a> </a>
<DropdownMenu.Item <DropdownMenu.Item
on:click={() => openDeleteDialog(shortener.code)} on:click={() => openDeleteDialog(shortener.code)}
class="flex items-center gap-2 text-destructive data-[highlighted]:bg-destructive"> class="text-destructive data-[highlighted]:bg-destructive flex items-center gap-2">
<TrashIcon size={16} /> <TrashIcon size={16} />
Delete Delete
</DropdownMenu.Item> </DropdownMenu.Item>
@ -141,8 +141,8 @@
<div class="flex items-center justify-between"> <div class="flex items-center justify-between">
<div class="flex gap-2"> <div class="flex gap-2">
<Button <Button
href={`/links/${shortener.code}`} href={`/dashboard/links/${shortener.code}`}
class="flex h-8 items-center justify-center gap-1 rounded bg-secondary text-sm"> class="bg-secondary flex h-8 items-center justify-center gap-1 rounded text-sm">
<BarChart size={20} /> <BarChart size={20} />
<div> <div>
{shortener.visitorCount} visits {shortener.visitorCount} visits
@ -151,9 +151,9 @@
<a <a
class={cn( class={cn(
buttonVariants({ variant: 'default' }), buttonVariants({ variant: 'default' }),
'flex h-8 items-center justify-center gap-1 rounded bg-secondary text-sm', 'bg-secondary flex h-8 items-center justify-center gap-1 rounded text-sm',
)} )}
href={`/projects/${selected_project.uuid}/links/${shortener.code}/qr`} href={`/dashboard/projects/${selected_project.uuid}/links/${shortener.code}/qr`}
on:click|preventDefault={showQRModal}> on:click|preventDefault={showQRModal}>
<QrCode size={20} /> <QrCode size={20} />
</a> </a>

@ -12,16 +12,19 @@ export const load = (async (event) => {
}) })
if (!project) { if (!project) {
redirect(300, '/projects') redirect(300, '/dashboard/projects')
} }
const { breadcrumbs: parentBreadcrumbs } = await event.parent() const { breadcrumbs: parentBreadcrumbs } = await event.parent()
const breadcrumbs = [ const breadcrumbs = [
...parentBreadcrumbs, ...parentBreadcrumbs,
{ name: project.name, path: `/projects/${project.uuid}` }, {
name: project.name,
path: `/dashboard/projects/${project.uuid}`,
},
] ]
return { breadcrumbs, project } return { breadcrumbs, project }
} catch (e) { } catch (e) {
redirect(300, '/projects') redirect(300, '/dashboard/projects')
} }
}) satisfies LayoutServerLoad }) satisfies LayoutServerLoad

@ -18,23 +18,17 @@
<ScrollArea orientation="horizontal"> <ScrollArea orientation="horizontal">
<div class="flex items-center gap-4"> <div class="flex items-center gap-4">
<Button <Button
href={`/projects/${data.project.uuid}`} href={`/dashboard/projects/${data.project.uuid}`}
variant={$page.url.pathname === variant={$page.url.pathname ===
`/projects/${data.project.uuid}` `/dashboard/projects/${data.project.uuid}`
? 'secondary' ? 'secondary'
: 'ghost'}> : 'ghost'}>
Shorteners Shorteners
</Button> </Button>
<!-- <Button -->
<!-- href={`/projects/${data.project.uuid}/members`} -->
<!-- variant={$page.url.pathname === -->
<!-- `/projects/${data.project.uuid}/members` -->
<!-- ? 'secondary' -->
<!-- : 'ghost'}>Members</Button> -->
<Button <Button
href={`/projects/${data.project.uuid}/settings`} href={`/dashboard/projects/${data.project.uuid}/settings`}
variant={$page.url.pathname === variant={$page.url.pathname ===
`/projects/${data.project.uuid}/settings` `/dashboard/projects/${data.project.uuid}/settings`
? 'secondary' ? 'secondary'
: 'ghost'}> : 'ghost'}>
Settings Settings

@ -51,9 +51,12 @@
}) })
const searchParams = urlParams.toString() const searchParams = urlParams.toString()
if (searchParams) { if (searchParams) {
return `/projects/${data.selectedProject.uuid}?` + searchParams return (
`/dashboard/projects/${data.selectedProject.uuid}?` +
searchParams
)
} else { } else {
return '/projects/' + data.selectedProject.uuid return '/dashboard/projects/' + data.selectedProject.uuid
} }
} }
@ -216,7 +219,7 @@
perPage={data.perPage} perPage={data.perPage}
page={data.page} page={data.page}
total={pagination[0].total} total={pagination[0].total}
path={'/projects/' + data.selectedProject.uuid} /> path={'/dashboard/projects/' + data.selectedProject.uuid} />
{/await} {/await}
<Dialog.Root <Dialog.Root

@ -30,7 +30,7 @@ export const load = (async (event) => {
}) })
if (!shortener) { if (!shortener) {
redirect(300, `/projects/${selectedProject.id}`) redirect(300, `/dashboard/projects/${selectedProject.id}`)
} }
return { return {

@ -18,7 +18,7 @@ export const load = (async (event) => {
}) })
if (!shortener) { if (!shortener) {
redirect(300, `/projects/${selectedProject.id}`) redirect(300, `/dashboard/projects/${selectedProject.id}`)
} }
return { shortener, project: selectedProject } return { shortener, project: selectedProject }

@ -8,11 +8,11 @@
const items = [ const items = [
{ {
title: 'Account', title: 'Account',
href: '/settings/account', href: '/dashboard/settings/account',
}, },
{ {
title: 'QR', title: 'QR',
href: '/settings/qr', href: '/dashboard/settings/qr',
}, },
] as const ] as const
</script> </script>
@ -28,7 +28,7 @@
variant={$page.url.pathname == item.href variant={$page.url.pathname == item.href
? 'secondary' ? 'secondary'
: 'ghost'} : 'ghost'}
class="justify-start hover:bg-secondary/50"> class="hover:bg-secondary/50 justify-start">
{item.title} {item.title}
</Button> </Button>
{/each} {/each}

@ -5,7 +5,7 @@ export const load = (async (event) => {
const breadcrumbs = [ const breadcrumbs = [
...parentBreadcrumbs, ...parentBreadcrumbs,
{ name: 'Settings', path: '/settings' }, { name: 'Settings', path: '/dashboard/settings' },
] ]
const page_title = 'Settings' const page_title = 'Settings'

@ -2,5 +2,5 @@ import { redirect } from '@sveltejs/kit'
import type { PageServerLoad } from './$types' import type { PageServerLoad } from './$types'
export const load = (async () => { export const load = (async () => {
redirect(300, '/settings/account'); redirect(300, '/dashboard/settings/account')
}) satisfies PageServerLoad }) satisfies PageServerLoad

@ -32,7 +32,7 @@
Kon.sh is completely self-hostable, open source, and free. No Kon.sh is completely self-hostable, open source, and free. No
vendor lock-in, can be hosted using docker/docker compose with vendor lock-in, can be hosted using docker/docker compose with
no limitations. no limitations.
<!-- <a href="/landing/docs" class="text-orange-400 underline"> <!-- <a href="/docs" class="text-orange-400 underline">
Learn More Learn More
</a> --> </a> -->
</p> </p>

@ -2,5 +2,5 @@ import type { PageServerLoad } from './$types'
import { redirect } from '@sveltejs/kit' import { redirect } from '@sveltejs/kit'
export const load = (async () => { export const load = (async () => {
return redirect(300, '/landing') return redirect(300, '/')
}) satisfies PageServerLoad }) satisfies PageServerLoad

@ -9,7 +9,6 @@
<div class="text-4xl font-bold">404</div> <div class="text-4xl font-bold">404</div>
<div class="text-4xl font-bold">Page Not Found</div> <div class="text-4xl font-bold">Page Not Found</div>
</div> </div>
<Button on:click={() => goto('/')} class="w-fit" <Button on:click={() => goto('/')} class="w-fit">Return</Button>
>Return Home</Button>
</div> </div>
</div> </div>

@ -1,5 +1,5 @@
User-agent: * User-agent: *
Disallow: / Allow: /
User-agent: * User-agent: *
Allow: /landing Disallow: /dashboard

@ -19,7 +19,7 @@ const clickLimiter = new LRUCache({
const app = new Elysia().use(cors()).use(rateLimit({ duration: 1000 })) const app = new Elysia().use(cors()).use(rateLimit({ duration: 1000 }))
app.get('/', ({ set }) => (set.redirect = fallback_url + '/landing')) app.get('/', ({ set }) => (set.redirect = fallback_url))
app.get('/invalid', () => 'Invalid Shortener') app.get('/invalid', () => 'Invalid Shortener')
app.get('/robots.txt', () => Bun.file('public/robots.txt')) app.get('/robots.txt', () => Bun.file('public/robots.txt'))

Loading…
Cancel
Save