From 326939feee2f608f99e6efa2c6a594e079ca6d5e Mon Sep 17 00:00:00 2001 From: ZL Asica <40444637+ZL-Asica@users.noreply.github.com> Date: Mon, 2 Dec 2024 20:01:49 -0600 Subject: [PATCH 1/5] feat: add config to switch case sensitivities --- components/dashboard/links/Editor.vue | 4 +++- nuxt.config.ts | 1 + schemas/link.ts | 7 ++++++- server/middleware/1.redirect.ts | 8 ++++++-- 4 files changed, 16 insertions(+), 4 deletions(-) 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 { From cd7e3022d576eb9834e32e07957d93c780ad7167 Mon Sep 17 00:00:00 2001 From: ZL Asica <40444637+ZL-Asica@users.noreply.github.com> Date: Mon, 2 Dec 2024 20:02:59 -0600 Subject: [PATCH 2/5] chore: fix wrong key in vscode setting For eslint version > 9 no need to add .experimental --- .vscode/settings.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 898ec90..68d55ed 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,4 +1,4 @@ { // Enable ESlint flat config support - "eslint.experimental.useFlatConfig": true + "eslint.useFlatConfig": true } From e51e912972e5e6fec82c7f68c32cb37a99f346ef Mon Sep 17 00:00:00 2001 From: ZL Asica <40444637+ZL-Asica@users.noreply.github.com> Date: Mon, 2 Dec 2024 20:22:45 -0600 Subject: [PATCH 3/5] doc: update docs to reflect the new feature. --- README.md | 1 + docs/faqs.md | 10 ++++++++++ 2 files changed, 11 insertions(+) diff --git a/README.md b/README.md index 14424b8..82860a3 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,7 @@ - **Customizable Slug:** Support for personalized slugs. - **🪄 AI Slug:** Leverage AI to generate slugs. - **Link Expiration:** Set expiration dates for your links. +- **Switch between case sensitivity:** Toggle between case sensitivity for slugs. ## 🪧 Demo diff --git a/docs/faqs.md b/docs/faqs.md index aa6cde5..159536b 100644 --- a/docs/faqs.md +++ b/docs/faqs.md @@ -32,3 +32,13 @@ Of course. Please set the environment variable `NUXT_HOME_URL` to your blog or o ## 5. Why can't I see statistics after deploying with NuxtHub? NuxtHub's ANALYTICS points to its dataset, you need to set the `NUXT_DATASET` environment variable to point to the same dataset. + +## 6. Why are links always case-insensitive? + +This is a feature of Sink. By default, we automatically convert all links to lowercase to avoid case-sensitive issues and improve usability. This ensures users don’t encounter errors due to accidental capitalization differences. + +However, you can disable this feature by setting the `NUXT_CASE_SENSITIVE` environment variable to `true`. + +### What happens when `NUXT_CASE_SENSITIVE` is `true`? + +Newly generated links will be case-sensitive, treating `MyLink` and `mylink` as distinct. Randomly generated slugs will include both uppercase and lowercase characters, offering a larger pool of unique combinations (but not user-friendly that why we default to non-case-sensitive). From 902fc1bef5a6dee5f78ec045c496b57dbc752157 Mon Sep 17 00:00:00 2001 From: ZL Asica <40444637+ZL-Asica@users.noreply.github.com> Date: Fri, 6 Dec 2024 10:19:40 -0600 Subject: [PATCH 4/5] fix: forward compability for case sensitive --- server/middleware/1.redirect.ts | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/server/middleware/1.redirect.ts b/server/middleware/1.redirect.ts index 99ea21f..a8de17a 100644 --- a/server/middleware/1.redirect.ts +++ b/server/middleware/1.redirect.ts @@ -13,10 +13,16 @@ 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:${caseSensitive ? slug : slug.toLowerCase()}`, - { type: 'json', cacheTtl: linkCacheTtl }, - ) + + let link: z.infer | null = null + + const getLink = async (key: string) => + await KV.get(`link:${key}`, { type: 'json', cacheTtl: linkCacheTtl }) + + link = await getLink(slug) + if (!caseSensitive && !link) { + link = await getLink(slug.toLowerCase()) + } if (link) { event.context.link = link From 899323faf6be0696d5dbe03ed9ff65dda14d092d Mon Sep 17 00:00:00 2001 From: ZL Asica <40444637+ZL-Asica@users.noreply.github.com> Date: Fri, 6 Dec 2024 15:11:07 -0600 Subject: [PATCH 5/5] chore: pre-check if slug is same before and after lowercase. --- server/middleware/1.redirect.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/server/middleware/1.redirect.ts b/server/middleware/1.redirect.ts index a8de17a..1c3ce80 100644 --- a/server/middleware/1.redirect.ts +++ b/server/middleware/1.redirect.ts @@ -20,8 +20,9 @@ export default eventHandler(async (event) => { await KV.get(`link:${key}`, { type: 'json', cacheTtl: linkCacheTtl }) link = await getLink(slug) - if (!caseSensitive && !link) { - link = await getLink(slug.toLowerCase()) + const lowercaseSlug = slug.toLowerCase() + if (!caseSensitive && !link && lowercaseSlug !== slug) { + link = await getLink(lowercaseSlug) } if (link) {