Skip to content

Commit 463af42

Browse files
mathix420claude
andcommitted
refactor: migrate from NuxtHub to Cloudflare Workers
Replace NuxtHub with direct Cloudflare Workers deployment using the cloudflare-module Nitro preset, a wrangler.toml config, and a useKV helper that reads the KV binding from the event context. Also resolve logo and macLogo to absolute URLs so install commands fetch them correctly when site config URL is unset. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 3c77944 commit 463af42

11 files changed

Lines changed: 80 additions & 43 deletions

File tree

.github/workflows/deploy.yml

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
name: Deploy to Cloudflare Workers
2+
3+
on:
4+
push:
5+
branches: [master]
6+
workflow_dispatch:
7+
8+
jobs:
9+
deploy:
10+
name: Build and deploy
11+
runs-on: ubuntu-latest
12+
permissions:
13+
contents: read
14+
15+
steps:
16+
- uses: actions/checkout@v4
17+
18+
- name: Install Bun
19+
uses: oven-sh/setup-bun@v2
20+
with:
21+
bun-version: latest
22+
23+
- name: Install dependencies
24+
run: bun install --frozen-lockfile
25+
26+
- name: Build Nuxt (cloudflare-module)
27+
run: bun run build
28+
29+
- name: Deploy with Wrangler
30+
uses: cloudflare/wrangler-action@v3
31+
with:
32+
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
33+
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
34+
command: deploy

.github/workflows/nuxthub.yml

Lines changed: 0 additions & 29 deletions
This file was deleted.

app/pages/app/[slug].vue

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ if (!app.value || error.value) {
1010
});
1111
}
1212
13-
const websiteBaseURL = useSiteConfig().url;
13+
const websiteBaseURL = useSiteConfig().url || "https://ftwa.mathix.dev";
1414
const fullImageURL = `${websiteBaseURL}${app.value.screenshot}`;
1515
1616
useSeoMeta({
@@ -44,11 +44,11 @@ const config = computed(() => [
4444
},
4545
{
4646
key: "Logo",
47-
value: app.value?.logo,
47+
value: app.value?.logo ? `${websiteBaseURL}${app.value.logo}` : "-",
4848
},
4949
{
5050
key: "Mac Logo",
51-
value: app.value?.macLogo || "-",
51+
value: app.value?.macLogo ? `${websiteBaseURL}${app.value.macLogo}` : "-",
5252
},
5353
{
5454
key: "Tags",

bun.lockb

-1.86 KB
Binary file not shown.

nuxt.config.ts

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ export default defineNuxtConfig({
44

55
modules: [
66
"@nuxt/ui",
7-
"@nuxthub/core",
87
"@nuxtjs/device",
98
"@nuxthq/studio",
109
],
@@ -48,16 +47,13 @@ export default defineNuxtConfig({
4847
compatibilityDate: "2024-10-08",
4948

5049
nitro: {
50+
preset: "cloudflare-module",
5151
prerender: {
5252
routes: ["/"],
5353
crawlLinks: true,
5454
},
5555
},
5656

57-
hub: {
58-
kv: true,
59-
},
60-
6157
eslint: {
6258
config: {
6359
stylistic: {

package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
"@nuxt/devtools": "latest",
2222
"@nuxt/ui": "^2.20.0",
2323
"@nuxthq/studio": "2.2.1",
24-
"@nuxthub/core": "^0.8.8",
2524
"@nuxtjs/device": "^3.2.4",
2625
"@types/web-app-manifest": "^1.0.8",
2726
"nuxt": "^3.14.1592",

server/api/submit.post.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,11 @@ export default defineEventHandler(async (event) => {
1010

1111
// Checking for collisions is probably overkilled here (129M IDs before 1% chance of collision)
1212
// Worst case scenario is that we overwrite an existing unverified website just before someone will paste the link, the user will install the wrong app.
13-
await hubKV().set(`unverified-website:${uid}`, {
14-
...website,
15-
id: uid,
16-
}, { ttl: 60 * 60 * 24 });
13+
await useKV(event).put(
14+
`unverified-website:${uid}`,
15+
JSON.stringify({ ...website, id: uid }),
16+
{ expirationTtl: 60 * 60 * 24 },
17+
);
1718

1819
return { uid };
1920
});

server/routes/u/[uid].get.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ export default defineEventHandler(async (event) => {
1515
return "echo '\nERROR: Target unsupported (yet).'";
1616
}
1717

18-
const website = await hubKV().get<WebsiteType>(`unverified-website:${uid}`);
18+
const website = await useKV(event).get<WebsiteType>(`unverified-website:${uid}`, "json");
1919

2020
if (!website) {
2121
return `echo '\nERROR: Website not found.'

server/routes/v/[uid].get.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,5 +26,12 @@ export default defineEventHandler(async (event) => {
2626
echo 'NOTE: Unverified links (starting with /u/) expires after 24 hours.'`;
2727
}
2828

29+
const siteUrl = useSiteConfig(event).url || "https://ftwa.mathix.dev";
30+
const toAbsolute = (url?: string) =>
31+
url && url.startsWith("/") ? `${siteUrl}${url}` : url;
32+
33+
website.logo = toAbsolute(website.logo)!;
34+
if (website.macLogo) website.macLogo = toAbsolute(website.macLogo);
35+
2936
return templates[target.os]({ website, target });
3037
});

server/utils/kv.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/// <reference types="@cloudflare/workers-types" />
2+
import type { H3Event } from "h3";
3+
4+
export function useKV(event: H3Event): KVNamespace {
5+
const kv = event.context.cloudflare?.env?.KV as KVNamespace | undefined;
6+
if (!kv) {
7+
throw createError({
8+
statusCode: 500,
9+
statusMessage: "KV binding 'KV' is not available in this environment.",
10+
});
11+
}
12+
return kv;
13+
}

0 commit comments

Comments
 (0)