Skip to content

Commit 96795aa

Browse files
committed
Merge branch 'preview'
2 parents f6642ee + fdf7a01 commit 96795aa

File tree

8 files changed

+39
-7
lines changed

8 files changed

+39
-7
lines changed

.vscode/settings.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
{
22
// Enable ESlint flat config support
3-
"eslint.experimental.useFlatConfig": true
3+
"eslint.useFlatConfig": true
44
}

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
- **URL Shortening:** Compress your URLs to their minimal length.
3636
- **Analytics:** Monitor link analytics and gather insightful statistics.
3737
- **Serverless:** Deploy without the need for traditional servers.
38-
- **Customizable Slug:** Support for personalized slugs.
38+
- **Customizable Slug:** Support for personalized slugs and case sensitivity.
3939
- **🪄 AI Slug:** Leverage AI to generate slugs.
4040
- **Link Expiration:** Set expiration dates for your links.
4141

components/dashboard/links/Editor.vue

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,10 +102,12 @@ onMounted(() => {
102102
}
103103
})
104104
105+
const { caseSensitive } = useRuntimeConfig()
106+
105107
async function onSubmit(formData) {
106108
const link = {
107109
url: formData.url,
108-
slug: formData.slug,
110+
slug: caseSensitive ? formData.slug : formData.slug.toLowerCase(),
109111
...(formData.optional || []),
110112
expiration: formData.optional?.expiration ? date2unix(formData.optional?.expiration, 'end') : undefined,
111113
}

components/home/Features.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ const features = ref([
2323
{
2424
title: 'Customizable Slug',
2525
description:
26-
'Support for personalized slugs.',
26+
'Support for personalized slugs and case sensitivity.',
2727
icon: Paintbrush,
2828
},
2929
{

docs/faqs.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,13 @@ Of course. Please set the environment variable `NUXT_HOME_URL` to your blog or o
3232
## 5. Why can't I see statistics after deploying with NuxtHub?
3333

3434
NuxtHub's ANALYTICS points to its dataset, you need to set the `NUXT_DATASET` environment variable to point to the same dataset.
35+
36+
## 6. Why are links always case-insensitive?
37+
38+
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.
39+
40+
However, you can disable this feature by setting the `NUXT_CASE_SENSITIVE` environment variable to `true`.
41+
42+
### What happens when `NUXT_CASE_SENSITIVE` is `true`?
43+
44+
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).

nuxt.config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ export default defineNuxtConfig({
6060
dataset: 'sink',
6161
aiModel: '@cf/meta/llama-3.1-8b-instruct',
6262
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"}`,
63+
caseSensitive: false,
6364
public: {
6465
previewMode: '',
6566
slugDefaultLength: '6',

schemas/link.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,15 @@ import { z } from 'zod'
22
import { customAlphabet } from 'nanoid'
33

44
const { slugRegex } = useAppConfig()
5+
const { caseSensitive } = useRuntimeConfig()
56

67
const slugDefaultLength = +useRuntimeConfig().public.slugDefaultLength
78

8-
export const nanoid = (length: number = slugDefaultLength) => customAlphabet('23456789abcdefghjkmnpqrstuvwxyz', length)
9+
export function nanoid(length: number = slugDefaultLength) {
10+
return caseSensitive
11+
? customAlphabet('23456789abcdefghjkmnpqrstuvwxyzABCDEFGHJKMNPQRSTUVWXYZ', length)
12+
: customAlphabet('23456789abcdefghjkmnpqrstuvwxyz', length)
13+
}
914

1015
export const LinkSchema = z.object({
1116
id: z.string().trim().max(26).default(nanoid(10)),

server/middleware/1.redirect.ts

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,29 @@ import type { LinkSchema } from '@/schemas/link'
55
export default eventHandler(async (event) => {
66
const { pathname: slug } = parsePath(event.path.replace(/^\/|\/$/g, '')) // remove leading and trailing slashes
77
const { slugRegex, reserveSlug } = useAppConfig(event)
8-
const { homeURL, linkCacheTtl, redirectWithQuery } = useRuntimeConfig(event)
8+
const { homeURL, linkCacheTtl, redirectWithQuery, caseSensitive } = useRuntimeConfig(event)
99
const { cloudflare } = event.context
1010

1111
if (event.path === '/' && homeURL)
1212
return sendRedirect(event, homeURL)
1313

1414
if (slug && !reserveSlug.includes(slug) && slugRegex.test(slug) && cloudflare) {
1515
const { KV } = cloudflare.env
16-
const link: z.infer<typeof LinkSchema> | null = await KV.get(`link:${slug}`, { type: 'json', cacheTtl: linkCacheTtl })
16+
17+
let link: z.infer<typeof LinkSchema> | null = null
18+
19+
const getLink = async (key: string) =>
20+
await KV.get(`link:${key}`, { type: 'json', cacheTtl: linkCacheTtl })
21+
22+
link = await getLink(slug)
23+
24+
// fallback to lowercase slug if caseSensitive is false and the slug is not found
25+
const lowerCaseSlug = slug.toLowerCase()
26+
if (!caseSensitive && !link && lowerCaseSlug !== slug) {
27+
console.log('lowerCaseSlug fallback:', `slug:${slug} lowerCaseSlug:${lowerCaseSlug}`)
28+
link = await getLink(lowerCaseSlug)
29+
}
30+
1731
if (link) {
1832
event.context.link = link
1933
try {

0 commit comments

Comments
 (0)