diff --git a/components/dashboard/links/Editor.vue b/components/dashboard/links/Editor.vue index 4f7fb3b..d4eeddd 100644 --- a/components/dashboard/links/Editor.vue +++ b/components/dashboard/links/Editor.vue @@ -102,10 +102,12 @@ onMounted(() => { } }) +const { caseSensitive } = useRuntimeConfig() + async function onSubmit(formData) { const link = { url: formData.url, - slug: formData.slug, + slug: caseSensitive ? formData.slug : formData.slug.toLowerCase(), ...(formData.optional || []), expiration: formData.optional?.expiration ? date2unix(formData.optional?.expiration, 'end') : undefined, } diff --git a/nuxt.config.ts b/nuxt.config.ts index 049414a..30beb15 100644 --- a/nuxt.config.ts +++ b/nuxt.config.ts @@ -60,6 +60,7 @@ export default defineNuxtConfig({ dataset: 'sink', aiModel: '@cf/meta/llama-3.1-8b-instruct', aiPrompt: `You are a URL shortening assistant, please shorten the URL provided by the user into a SLUG. The SLUG information must come from the URL itself, do not make any assumptions. A SLUG is human-readable and should not exceed three words and can be validated using regular expressions {slugRegex} . Only the best one is returned, the format must be JSON reference {"slug": "example-slug"}`, + caseSensitive: false, public: { previewMode: '', slugDefaultLength: '6', diff --git a/schemas/link.ts b/schemas/link.ts index fe74492..763c650 100644 --- a/schemas/link.ts +++ b/schemas/link.ts @@ -2,10 +2,15 @@ import { z } from 'zod' import { customAlphabet } from 'nanoid' const { slugRegex } = useAppConfig() +const { caseSensitive } = useRuntimeConfig() const slugDefaultLength = +useRuntimeConfig().public.slugDefaultLength -export const nanoid = (length: number = slugDefaultLength) => customAlphabet('23456789abcdefghjkmnpqrstuvwxyz', length) +export function nanoid(length: number = slugDefaultLength) { + return caseSensitive + ? customAlphabet('23456789abcdefghjkmnpqrstuvwxyzABCDEFGHJKMNPQRSTUVWXYZ', length) + : customAlphabet('23456789abcdefghjkmnpqrstuvwxyz', length) +} export const LinkSchema = z.object({ id: z.string().trim().max(26).default(nanoid(10)), diff --git a/server/middleware/1.redirect.ts b/server/middleware/1.redirect.ts index 297098d..99ea21f 100644 --- a/server/middleware/1.redirect.ts +++ b/server/middleware/1.redirect.ts @@ -5,7 +5,7 @@ import type { LinkSchema } from '@/schemas/link' export default eventHandler(async (event) => { const { pathname: slug } = parsePath(event.path.replace(/^\/|\/$/g, '')) // remove leading and trailing slashes const { slugRegex, reserveSlug } = useAppConfig(event) - const { homeURL, linkCacheTtl, redirectWithQuery } = useRuntimeConfig(event) + const { homeURL, linkCacheTtl, redirectWithQuery, caseSensitive } = useRuntimeConfig(event) const { cloudflare } = event.context if (event.path === '/' && homeURL) @@ -13,7 +13,11 @@ export default eventHandler(async (event) => { if (slug && !reserveSlug.includes(slug) && slugRegex.test(slug) && cloudflare) { const { KV } = cloudflare.env - const link: z.infer | null = await KV.get(`link:${slug}`, { type: 'json', cacheTtl: linkCacheTtl }) + const link: z.infer | null = await KV.get( + `link:${caseSensitive ? slug : slug.toLowerCase()}`, + { type: 'json', cacheTtl: linkCacheTtl }, + ) + if (link) { event.context.link = link try {