Merge branch 'worker'
This commit is contained in:
commit
7e62455c62
22 changed files with 4976 additions and 5413 deletions
|
|
@ -1 +1 @@
|
||||||
20.11.0
|
22.15.1
|
||||||
49
README.md
49
README.md
|
|
@ -74,7 +74,7 @@ Site Token: SinkCool
|
||||||
- **Framework**: [Nuxt](https://nuxt.com/)
|
- **Framework**: [Nuxt](https://nuxt.com/)
|
||||||
- **Database**: [Cloudflare Workers KV](https://developers.cloudflare.com/kv/)
|
- **Database**: [Cloudflare Workers KV](https://developers.cloudflare.com/kv/)
|
||||||
- **Analytics Engine**: [Cloudflare Workers Analytics Engine](https://developers.cloudflare.com/analytics/)
|
- **Analytics Engine**: [Cloudflare Workers Analytics Engine](https://developers.cloudflare.com/analytics/)
|
||||||
- **UI Components**: [Shadcn-vue](https://www.shadcn-vue.com/)
|
- **UI Components**: [shadcn-vue](https://www.shadcn-vue.com/)
|
||||||
- **Styling:** [Tailwind CSS](https://tailwindcss.com/)
|
- **Styling:** [Tailwind CSS](https://tailwindcss.com/)
|
||||||
- **Deployment**: [Cloudflare](https://www.cloudflare.com/)
|
- **Deployment**: [Cloudflare](https://www.cloudflare.com/)
|
||||||
|
|
||||||
|
|
@ -94,31 +94,12 @@ We welcome your contributions and PRs.
|
||||||
- [ ] Analytics Enhancements (Support for merging filter conditions)
|
- [ ] Analytics Enhancements (Support for merging filter conditions)
|
||||||
- [ ] Dashboard Performance Optimization (Infinite loading)
|
- [ ] Dashboard Performance Optimization (Infinite loading)
|
||||||
- [ ] Units Test
|
- [ ] Units Test
|
||||||
- [ ] Support for Other Deployment Platforms
|
|
||||||
|
|
||||||
## 🏗️ Deployment
|
## 🏗️ Deployment
|
||||||
|
|
||||||
> Video tutorial: [Watch here](https://www.youtube.com/watch?v=MkU23U2VE9E)
|
> Video tutorial: [Watch here](https://www.youtube.com/watch?v=MkU23U2VE9E)
|
||||||
|
|
||||||
1. [Fork](https://github.com/ccbikai/Sink/fork) the repository to your GitHub account.
|
We currently support deployment to [Cloudflare Workers](./docs/deployment/workers.md) (recommended) and [Cloudflare Pages](./docs/deployment/pages.md).
|
||||||
2. Create a project in [Cloudflare Pages](https://developers.cloudflare.com/pages/).
|
|
||||||
3. Select the `Sink` repository and choose the `Nuxt.js` preset.
|
|
||||||
4. Configure the following environment variables:
|
|
||||||
- `NUXT_SITE_TOKEN`: Must be longer than **8** characters. This token grants access to your dashboard.
|
|
||||||
- `NUXT_CF_ACCOUNT_ID`: Locate your [account ID](https://developers.cloudflare.com/fundamentals/setup/find-account-and-zone-ids/).
|
|
||||||
- `NUXT_CF_API_TOKEN`: Create a [Cloudflare API token](https://developers.cloudflare.com/fundamentals/api/get-started/create-token/) with at least `Account.Account Analytics` permissions. [See reference.](https://developers.cloudflare.com/analytics/analytics-engine/sql-api/#authentication)
|
|
||||||
|
|
||||||
5. Save and deploy the project.
|
|
||||||
6. Cancel the deployment, then navigate to **Settings** -> **Bindings** -> **Add**:
|
|
||||||
- **KV Namespace**: Bind the variable name `KV` to a [KV namespace](https://developers.cloudflare.com/kv/) (create a new one under **Storage & Databases** -> **KV**).
|
|
||||||
- **Workers AI** (_Optional_): Bind the variable name `AI` to the Workers AI Catalog.
|
|
||||||
- **Analytics Engine**:
|
|
||||||
- In **Workers & Pages**, go to **Account details** on the right side, find `Analytics Engine`, and click `Set up` to enable the free version.
|
|
||||||
- Return to **Settings** -> **Bindings** -> **Add** and select **Analytics engine**.
|
|
||||||
- Bind the variable name `ANALYTICS` to the `sink` dataset.
|
|
||||||
|
|
||||||
7. Redeploy the project.
|
|
||||||
8. Update code, refer to the official GitHub documentation [Syncing a fork branch from the web UI](https://docs.github.com/pull-requests/collaborating-with-pull-requests/working-with-forks/syncing-a-fork#syncing-a-fork-branch-from-the-web-ui).
|
|
||||||
|
|
||||||
## ⚒️ Configuration
|
## ⚒️ Configuration
|
||||||
|
|
||||||
|
|
@ -128,6 +109,32 @@ We welcome your contributions and PRs.
|
||||||
|
|
||||||
[API Docs](./docs/api.md)
|
[API Docs](./docs/api.md)
|
||||||
|
|
||||||
|
## 🧰 MCP
|
||||||
|
|
||||||
|
We currently do not support native MCP Server, but we have OpenAPI documentation, and you can use the following method to support MCP.
|
||||||
|
|
||||||
|
> Replace the domain name in `OPENAPI_SPEC_URL` with your own domain name.
|
||||||
|
>
|
||||||
|
> The `API_KEY` is the same as the `NUXT_SITE_TOKEN` in the environment variables.
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"mcpServers": {
|
||||||
|
"sink": {
|
||||||
|
"command": "uvx",
|
||||||
|
"args": [
|
||||||
|
"mcp-openapi-proxy"
|
||||||
|
],
|
||||||
|
"env": {
|
||||||
|
"OPENAPI_SPEC_URL": "https://sink.cool/_docs/openapi.json",
|
||||||
|
"API_KEY": "SinkCool",
|
||||||
|
"TOOL_WHITELIST": "/api/link/create"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## 🙋🏻 FAQs
|
## 🙋🏻 FAQs
|
||||||
|
|
||||||
[FAQs](./docs/faqs.md)
|
[FAQs](./docs/faqs.md)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ChartTooltip } from '@/components/ui/chart'
|
|
||||||
import { VisSingleContainer, VisTopoJSONMap, VisTopoJSONMapSelectors } from '@unovis/vue'
|
import { VisSingleContainer, VisTopoJSONMap, VisTopoJSONMapSelectors } from '@unovis/vue'
|
||||||
|
import { ChartTooltip } from '@/components/ui/chart'
|
||||||
|
|
||||||
const id = inject('id')
|
const id = inject('id')
|
||||||
const time = inject('time')
|
const time = inject('time')
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { DependencyType } from '@/components/ui/auto-form/interface'
|
|
||||||
import { LinkSchema, nanoid } from '@@/schemas/link'
|
import { LinkSchema, nanoid } from '@@/schemas/link'
|
||||||
import { toTypedSchema } from '@vee-validate/zod'
|
import { toTypedSchema } from '@vee-validate/zod'
|
||||||
import { Shuffle, Sparkles } from 'lucide-vue-next'
|
import { Shuffle, Sparkles } from 'lucide-vue-next'
|
||||||
import { useForm } from 'vee-validate'
|
import { useForm } from 'vee-validate'
|
||||||
import { toast } from 'vue-sonner'
|
import { toast } from 'vue-sonner'
|
||||||
import { z } from 'zod'
|
import { z } from 'zod'
|
||||||
|
import { DependencyType } from '@/components/ui/auto-form/interface'
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
link: {
|
link: {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import heroImg from '@/assets/images/hero.svg?raw'
|
|
||||||
import { AreaChart } from 'lucide-vue-next'
|
import { AreaChart } from 'lucide-vue-next'
|
||||||
import { GitHubIcon } from 'vue3-simple-icons'
|
import { GitHubIcon } from 'vue3-simple-icons'
|
||||||
|
import heroImg from '@/assets/images/hero.svg?raw'
|
||||||
|
|
||||||
const { title, description, github } = useAppConfig()
|
const { title, description, github } = useAppConfig()
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { cn } from '@/lib/utils'
|
|
||||||
import { computed, onMounted, ref, useSlots } from 'vue'
|
import { computed, onMounted, ref, useSlots } from 'vue'
|
||||||
|
import { cn } from '@/lib/utils'
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
class?: string
|
class?: string
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import { type ClassValue, clsx } from 'clsx'
|
import type { ClassValue } from 'clsx'
|
||||||
|
import { clsx } from 'clsx'
|
||||||
import { twMerge } from 'tailwind-merge'
|
import { twMerge } from 'tailwind-merge'
|
||||||
|
|
||||||
export function cn(...inputs: ClassValue[]) {
|
export function cn(...inputs: ClassValue[]) {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import { type DateValue, fromAbsolute, toCalendarDate } from '@internationalized/date'
|
import type { DateValue } from '@internationalized/date'
|
||||||
|
import { fromAbsolute, toCalendarDate } from '@internationalized/date'
|
||||||
|
|
||||||
export function getTimeZone() {
|
export function getTimeZone() {
|
||||||
if (typeof Intl === 'undefined')
|
if (typeof Intl === 'undefined')
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,9 @@
|
||||||
},
|
},
|
||||||
"aliases": {
|
"aliases": {
|
||||||
"components": "@/components",
|
"components": "@/components",
|
||||||
"utils": "@/utils"
|
"utils": "@/utils",
|
||||||
|
"ui": "@/components/ui",
|
||||||
|
"lib": "@/lib",
|
||||||
|
"composables": "@/composables"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
23
docs/deployment/pages.md
Normal file
23
docs/deployment/pages.md
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
# Deployment on Cloudflare Pages
|
||||||
|
|
||||||
|
1. [Fork](https://github.com/ccbikai/Sink/fork) the repository to your GitHub account.
|
||||||
|
2. Create a project in [Cloudflare Pages](https://developers.cloudflare.com/pages/).
|
||||||
|
3. Select the `Sink` repository and choose the `Nuxt.js` preset.
|
||||||
|
4. Configure the following environment variables:
|
||||||
|
- `NUXT_SITE_TOKEN`: Must be at least **8** characters long. This token grants access to your dashboard.
|
||||||
|
- `NUXT_CF_ACCOUNT_ID`: Find your [account ID](https://developers.cloudflare.com/fundamentals/setup/find-account-and-zone-ids/).
|
||||||
|
- `NUXT_CF_API_TOKEN`: Create a [Cloudflare API token](https://developers.cloudflare.com/fundamentals/api/get-started/create-token/) with at least `Account.Account Analytics` permission. [See reference.](https://developers.cloudflare.com/analytics/analytics-engine/sql-api/#authentication)
|
||||||
|
|
||||||
|
5. Save and deploy the project.
|
||||||
|
6. Cancel the deployment, then go to **Settings** -> **Bindings** -> **Add**:
|
||||||
|
- **KV Namespace**: Bind the variable name `KV` to a [KV namespace](https://developers.cloudflare.com/kv/) (create a new one under **Storage & Databases** -> **KV**).
|
||||||
|
- **Workers AI** (_Optional_): Bind the variable name `AI` to the Workers AI Catalog.
|
||||||
|
- **Analytics Engine**:
|
||||||
|
- In **Workers & Pages**, go to **Account details** in the right panel, locate `Analytics Engine`, and click `Set up` to enable the free tier.
|
||||||
|
- Return to **Settings** -> **Bindings** -> **Add** and select **Analytics engine**.
|
||||||
|
- Bind the variable name `ANALYTICS` to the `sink` dataset.
|
||||||
|
|
||||||
|
7. Add Compatibility flags
|
||||||
|
- Go to **Settings** -> **Runtime** -> **Compatibility flags** and set the following flags `nodejs_compat`.
|
||||||
|
8. Redeploy the project.
|
||||||
|
9. To update code, refer to the official GitHub documentation [Syncing a fork branch from the web UI](https://docs.github.com/pull-requests/collaborating-with-pull-requests/working-with-forks/syncing-a-fork#syncing-a-fork-branch-from-the-web-ui).
|
||||||
19
docs/deployment/workers.md
Normal file
19
docs/deployment/workers.md
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
# Deployment on Cloudflare Workers
|
||||||
|
|
||||||
|
1. [Fork](https://github.com/ccbikai/Sink/fork) the repository to your GitHub account.
|
||||||
|
2. Create a [KV namespace](https://developers.cloudflare.com/kv/) (under **Storage & Databases** -> **KV**), and copy the namespace ID.
|
||||||
|
3. Update the `kv_namespaces` ID in `wrangler.jsonc` with your own namespace ID.
|
||||||
|
4. Create a project in [Cloudflare Workers](https://developers.cloudflare.com/workers/).
|
||||||
|
5. Select the `Sink` repository and use the following build and deploy commands:
|
||||||
|
- **Build command**: `pnpm run build` or `npm run build`
|
||||||
|
- **Deploy command**: `npx wrangler deploy`
|
||||||
|
|
||||||
|
6. Save and deploy the project.
|
||||||
|
7. After deployment, go to **Settings** -> **Variables and Secrets** -> **Add**, and configure the following environment variables:
|
||||||
|
- `NUXT_SITE_TOKEN`: Must be at least **8** characters long. This token grants access to your dashboard.
|
||||||
|
- `NUXT_CF_ACCOUNT_ID`: Find your [account ID](https://developers.cloudflare.com/fundamentals/setup/find-account-and-zone-ids/).
|
||||||
|
- `NUXT_CF_API_TOKEN`: Create a [Cloudflare API token](https://developers.cloudflare.com/fundamentals/api/get-started/create-token/) with at least `Account.Account Analytics` permission. [See reference.](https://developers.cloudflare.com/analytics/analytics-engine/sql-api/#authentication)
|
||||||
|
|
||||||
|
8. Enable Analytics Engine. In **Workers & Pages**, go to **Account details** in the right panel, locate **Analytics Engine**, and click **Set up** to enable the free tier.
|
||||||
|
9. Redeploy the project.
|
||||||
|
10. To update your code, refer to the official GitHub documentation: [Syncing a fork branch from the web UI](https://docs.github.com/pull-requests/collaborating-with-pull-requests/working-with-forks/syncing-a-fork-branch-from-the-web-ui).
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
|
import { provider } from 'std-env'
|
||||||
import { currentLocales } from './i18n/i18n'
|
import { currentLocales } from './i18n/i18n'
|
||||||
|
|
||||||
// https://nuxt.com/docs/api/configuration/nuxt-config
|
// https://nuxt.com/docs/api/configuration/nuxt-config
|
||||||
export default defineNuxtConfig({
|
export default defineNuxtConfig({
|
||||||
|
|
||||||
modules: [
|
modules: [
|
||||||
'@nuxthub/core',
|
'@nuxthub/core',
|
||||||
'shadcn-nuxt',
|
'shadcn-nuxt',
|
||||||
|
|
@ -56,13 +56,35 @@ export default defineNuxtConfig({
|
||||||
compatibilityVersion: 4,
|
compatibilityVersion: 4,
|
||||||
},
|
},
|
||||||
|
|
||||||
compatibilityDate: '2024-07-08',
|
experimental: {
|
||||||
|
enforceModuleCompatibility: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
compatibilityDate: {
|
||||||
|
cloudflare: '2025-05-08',
|
||||||
|
},
|
||||||
|
|
||||||
nitro: {
|
nitro: {
|
||||||
experimental: {
|
experimental: {
|
||||||
// Enable Server API documentation within NuxtHub
|
|
||||||
openAPI: true,
|
openAPI: true,
|
||||||
},
|
},
|
||||||
|
timing: true,
|
||||||
|
openAPI: {
|
||||||
|
production: 'runtime',
|
||||||
|
meta: {
|
||||||
|
title: 'Sink API',
|
||||||
|
description: 'A Simple / Speedy / Secure Link Shortener with Analytics, 100% run on Cloudflare.',
|
||||||
|
},
|
||||||
|
route: '/_docs/openapi.json',
|
||||||
|
ui: {
|
||||||
|
scalar: {
|
||||||
|
route: '/_docs/scalar',
|
||||||
|
},
|
||||||
|
swagger: {
|
||||||
|
route: '/_docs/swagger',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
hub: {
|
hub: {
|
||||||
|
|
@ -72,6 +94,7 @@ export default defineNuxtConfig({
|
||||||
cache: false,
|
cache: false,
|
||||||
database: false,
|
database: false,
|
||||||
kv: true,
|
kv: true,
|
||||||
|
workers: provider !== 'cloudflare_pages',
|
||||||
},
|
},
|
||||||
|
|
||||||
eslint: {
|
eslint: {
|
||||||
|
|
|
||||||
62
package.json
62
package.json
|
|
@ -3,13 +3,13 @@
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"version": "0.1.12",
|
"version": "0.1.12",
|
||||||
"private": true,
|
"private": true,
|
||||||
"packageManager": "pnpm@9.15.1",
|
"packageManager": "pnpm@10.11.0",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=20.11"
|
"node": ">=20.11"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "nuxt dev",
|
"dev": "nuxt dev",
|
||||||
"build": "nuxt build",
|
"build": "NODE_OPTIONS=--max-old-space-size=8192 nuxt build",
|
||||||
"build:map": "node scripts/build-map.js",
|
"build:map": "node scripts/build-map.js",
|
||||||
"build:colo": "node scripts/build-colo.js",
|
"build:colo": "node scripts/build-colo.js",
|
||||||
"preview": "wrangler pages dev dist",
|
"preview": "wrangler pages dev dist",
|
||||||
|
|
@ -23,52 +23,52 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@intlify/message-compiler": "^11.1.3",
|
"@intlify/message-compiler": "^11.1.3",
|
||||||
"@number-flow/vue": "^0.3.3",
|
"@number-flow/vue": "^0.4.7",
|
||||||
"@unovis/ts": "^1.5.0",
|
"@unovis/ts": "^1.5.1",
|
||||||
"@unovis/vue": "^1.5.0",
|
"@unovis/vue": "^1.5.1",
|
||||||
"@vee-validate/zod": "^4.15.0",
|
"@vee-validate/zod": "^4.15.0",
|
||||||
"@vueuse/core": "^12.2.0",
|
"@vueuse/core": "^13.2.0",
|
||||||
"@vueuse/motion": "^3.0.3",
|
"@vueuse/motion": "^3.0.3",
|
||||||
"d3-scale": "^4.0.2",
|
"d3-scale": "^4.0.2",
|
||||||
"d3-scale-chromatic": "^3.1.0",
|
"d3-scale-chromatic": "^3.1.0",
|
||||||
"fuse.js": "^7.0.0",
|
"fuse.js": "^7.1.0",
|
||||||
"globe.gl": "^2.41.4",
|
"globe.gl": "^2.41.4",
|
||||||
"intl-parse-accept-language": "^1.0.0",
|
"intl-parse-accept-language": "^1.0.0",
|
||||||
"lodash-es": "^4.17.21",
|
"lodash-es": "^4.17.21",
|
||||||
"lucide-vue-next": "^0.469.0",
|
"lucide-vue-next": "^0.511.0",
|
||||||
"mysql-bricks": "^1.1.2",
|
"mysql-bricks": "^2.0.0",
|
||||||
"nanoid": "^5.0.9",
|
"nanoid": "^5.1.5",
|
||||||
"pluralize": "^8.0.0",
|
"pluralize": "^8.0.0",
|
||||||
"qr-code-styling": "1.6.0-rc.1",
|
"qr-code-styling": "^1.9.2",
|
||||||
"radix-vue": "^1.9.11",
|
"radix-vue": "^1.9.17",
|
||||||
"ua-parser-js": "^2.0.3",
|
"ua-parser-js": "^2.0.3",
|
||||||
"vaul-vue": "^0.3.0",
|
"vaul-vue": "^0.4.1",
|
||||||
"vee-validate": "^4.15.0",
|
"vee-validate": "^4.15.0",
|
||||||
"virtua": "^0.39.2",
|
"virtua": "^0.41.2",
|
||||||
"vue-sonner": "^1.3.0",
|
"vue-sonner": "^2.0.0",
|
||||||
"vue3-simple-icons": "^13.2.0",
|
"vue3-simple-icons": "^13.2.0",
|
||||||
"zod": "^3.24.1"
|
"zod": "^3.25.20"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@antfu/eslint-config": "^3.12.1",
|
"@antfu/eslint-config": "^4.13.2",
|
||||||
"@nuxt/eslint": "^0.7.4",
|
"@nuxt/eslint": "^1.4.1",
|
||||||
"@nuxt/eslint-config": "^0.7.4",
|
"@nuxt/eslint-config": "^1.4.1",
|
||||||
"@nuxthub/core": "0.7.11",
|
"@nuxthub/core": "^0.8.27",
|
||||||
"@nuxtjs/color-mode": "^3.5.2",
|
"@nuxtjs/color-mode": "^3.5.2",
|
||||||
"@nuxtjs/i18n": "^9.0.0",
|
"@nuxtjs/i18n": "^9.5.4",
|
||||||
"@nuxtjs/tailwindcss": "^6.12.2",
|
"@nuxtjs/tailwindcss": "^6.14.0",
|
||||||
"@vueuse/integrations": "^12.2.0",
|
"@vueuse/integrations": "^13.2.0",
|
||||||
"class-variance-authority": "^0.7.1",
|
"class-variance-authority": "^0.7.1",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"eslint": "^9.17.0",
|
"eslint": "^9.27.0",
|
||||||
"lint-staged": "^15.2.11",
|
"lint-staged": "^16.0.0",
|
||||||
"nuxt": "~3.13.2",
|
"nuxt": "^3.17.4",
|
||||||
"shadcn-nuxt": "^0.11.3",
|
"shadcn-nuxt": "^2.1.0",
|
||||||
"simple-git-hooks": "^2.11.1",
|
"simple-git-hooks": "^2.13.0",
|
||||||
"tailwind-merge": "^2.6.0",
|
"tailwind-merge": "^3.3.0",
|
||||||
"tailwindcss-animate": "^1.0.7",
|
"tailwindcss-animate": "^1.0.7",
|
||||||
"vue-tsc": "^2.2.0",
|
"vue-tsc": "^2.2.10",
|
||||||
"wrangler": "^3.99.0"
|
"wrangler": "^4.16.1"
|
||||||
},
|
},
|
||||||
"simple-git-hooks": {
|
"simple-git-hooks": {
|
||||||
"pre-commit": "npm run lint-staged"
|
"pre-commit": "npm run lint-staged"
|
||||||
|
|
|
||||||
10089
pnpm-lock.yaml
10089
pnpm-lock.yaml
File diff suppressed because it is too large
Load diff
7
pnpm-workspace.yaml
Normal file
7
pnpm-workspace.yaml
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
onlyBuiltDependencies:
|
||||||
|
- esbuild
|
||||||
|
- sharp
|
||||||
|
- simple-git-hooks
|
||||||
|
- unrs-resolver
|
||||||
|
- vue-demi
|
||||||
|
- workerd
|
||||||
|
|
@ -1,5 +1,29 @@
|
||||||
import { LinkSchema } from '@@/schemas/link'
|
import { LinkSchema } from '@@/schemas/link'
|
||||||
|
|
||||||
|
defineRouteMeta({
|
||||||
|
openAPI: {
|
||||||
|
description: 'Create a new short link',
|
||||||
|
requestBody: {
|
||||||
|
required: true,
|
||||||
|
content: {
|
||||||
|
'application/json': {
|
||||||
|
// Need: https://github.com/nitrojs/nitro/issues/2974
|
||||||
|
schema: {
|
||||||
|
type: 'object',
|
||||||
|
required: ['url'],
|
||||||
|
properties: {
|
||||||
|
url: {
|
||||||
|
type: 'string',
|
||||||
|
description: 'The URL to shorten',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
export default eventHandler(async (event) => {
|
export default eventHandler(async (event) => {
|
||||||
const link = await readValidatedBody(event, LinkSchema.parse)
|
const link = await readValidatedBody(event, LinkSchema.parse)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,14 @@
|
||||||
|
defineRouteMeta({
|
||||||
|
openAPI: {
|
||||||
|
description: 'Get the location of the user',
|
||||||
|
responses: {
|
||||||
|
200: {
|
||||||
|
description: 'The location of the user',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
export default eventHandler((event) => {
|
export default eventHandler((event) => {
|
||||||
const { request: { cf } } = event.context.cloudflare
|
const { request: { cf } } = event.context.cloudflare
|
||||||
return {
|
return {
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,17 @@
|
||||||
|
defineRouteMeta({
|
||||||
|
openAPI: {
|
||||||
|
description: 'Verify the site token',
|
||||||
|
responses: {
|
||||||
|
200: {
|
||||||
|
description: 'The site token is valid',
|
||||||
|
},
|
||||||
|
default: {
|
||||||
|
description: 'The site token is invalid',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
export default eventHandler(() => {
|
export default eventHandler(() => {
|
||||||
return {
|
return {
|
||||||
name: 'Sink',
|
name: 'Sink',
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
export default eventHandler((event) => {
|
export default eventHandler((event) => {
|
||||||
const token = getHeader(event, 'Authorization')?.replace('Bearer ', '')
|
const token = getHeader(event, 'Authorization')?.replace(/^Bearer\s+/, '')
|
||||||
if (event.path.startsWith('/api/') && !event.path.startsWith('/api/_') && token !== useRuntimeConfig(event).siteToken) {
|
if (event.path.startsWith('/api/') && !event.path.startsWith('/api/_') && token !== useRuntimeConfig(event).siteToken) {
|
||||||
throw createError({
|
throw createError({
|
||||||
status: 401,
|
status: 401,
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
import type { H3Event } from 'h3'
|
import type { H3Event } from 'h3'
|
||||||
import { getFlag } from '@/utils/flag'
|
|
||||||
import { parseAcceptLanguage } from 'intl-parse-accept-language'
|
import { parseAcceptLanguage } from 'intl-parse-accept-language'
|
||||||
import { UAParser } from 'ua-parser-js'
|
import { UAParser } from 'ua-parser-js'
|
||||||
import {
|
import {
|
||||||
|
|
@ -13,6 +12,7 @@ import {
|
||||||
Vehicles,
|
Vehicles,
|
||||||
} from 'ua-parser-js/extensions'
|
} from 'ua-parser-js/extensions'
|
||||||
import { parseURL } from 'ufo'
|
import { parseURL } from 'ufo'
|
||||||
|
import { getFlag } from '@/utils/flag'
|
||||||
|
|
||||||
function toBlobNumber(blob: string) {
|
function toBlobNumber(blob: string) {
|
||||||
return +blob.replace(/\D/g, '')
|
return +blob.replace(/\D/g, '')
|
||||||
|
|
|
||||||
30
wrangler.jsonc
Normal file
30
wrangler.jsonc
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
{
|
||||||
|
"$schema": "node_modules/wrangler/config-schema.json",
|
||||||
|
"name": "sink",
|
||||||
|
"main": "dist/server/index.mjs",
|
||||||
|
"assets": {
|
||||||
|
"binding": "ASSETS",
|
||||||
|
"directory": "dist/public"
|
||||||
|
},
|
||||||
|
"compatibility_date": "2025-05-08",
|
||||||
|
"compatibility_flags": [
|
||||||
|
"nodejs_compat"
|
||||||
|
],
|
||||||
|
"keep_vars": true,
|
||||||
|
"upload_source_maps": true,
|
||||||
|
"ai": {
|
||||||
|
"binding": "AI"
|
||||||
|
},
|
||||||
|
"analytics_engine_datasets": [
|
||||||
|
{
|
||||||
|
"binding": "ANALYTICS",
|
||||||
|
"dataset": "sink"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"kv_namespaces": [
|
||||||
|
{
|
||||||
|
"binding": "KV",
|
||||||
|
"id": "ef93d42dc4b34969bab404d2e80f8dd3" // IMPORTANT: Change this to your KV namespace ID
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
upload_source_maps = true
|
|
||||||
|
|
||||||
[dev]
|
|
||||||
port = 3000
|
|
||||||
|
|
||||||
[ai]
|
|
||||||
binding = "AI"
|
|
||||||
Loading…
Reference in a new issue