Skip to content

Commit 9f187ac

Browse files
committed
feat: support proxy
1 parent 02fdff7 commit 9f187ac

File tree

9 files changed

+112
-64
lines changed

9 files changed

+112
-64
lines changed

modules/hub/index.ts

+40-3
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,60 @@ import { defu } from 'defu'
44
import { randomUUID } from 'uncrypto'
55
import { mkdir, writeFile, readFile } from 'node:fs/promises'
66
import { findWorkspaceDir } from 'pkg-types'
7+
import { readUser } from 'rc9'
8+
import { $fetch } from 'ofetch'
9+
import { joinURL } from 'ufo'
710

811
export default defineNuxtModule({
912
meta: {
1013
name: 'hub'
1114
},
12-
async setup (_options, nuxt) {
15+
async setup (options, nuxt) {
1316
const rootDir = nuxt.options.rootDir
1417
const { resolve } = createResolver(import.meta.url)
1518

19+
// Waiting for https://github.com/unjs/c12/pull/139
20+
// Then adding the c12 dependency to the project to 1.8.1
21+
options = defu(options, {
22+
...readUser('.nuxtrc').hub,
23+
})
24+
25+
const runtimeConfig = nuxt.options.runtimeConfig
26+
const hub = runtimeConfig.hub = defu(runtimeConfig.hub, options, {
27+
url: process.env.NUXT_HUB_URL || 'https://hub.nuxt.com',
28+
projectId: process.env.NUXT_HUB_PROJECT_ID || '',
29+
projectUrl: process.env.NUXT_HUB_PROJECT_URL || '',
30+
projectSecretKey: process.env.NUXT_HUB_PROJECT_SECRET_KEY || '',
31+
userToken: process.env.NUXT_HUB_USER_TOKEN || '',
32+
})
33+
if (/^\d+$/.test(String(hub.projectId))) {
34+
const project = await $fetch(`/api/projects/${hub.projectId}`, {
35+
baseURL: hub.url,
36+
headers: {
37+
authorization: `Bearer ${hub.userToken}`
38+
}
39+
}).catch(() => {
40+
logger.warn('Failed to fetch NuxtHub linked project, make sure to run `nuxthub link` again.')
41+
return null
42+
})
43+
if (project) {
44+
const adminUrl = joinURL(hub.url, project.teamSlug, project.slug)
45+
logger.info(`Connected to NuxtHub project \`${adminUrl}\``)
46+
hub.projectUrl = project.url
47+
if (!hub.projectUrl) {
48+
logger.warn(`NuxtHub project \`${project.slug}\` is not deployed yet, make sure to deploy it using \`nuxthub deploy\` or add the deployed URL to the project settings.`)
49+
}
50+
}
51+
}
52+
1653
// Production mode
1754
if (!nuxt.options.dev) {
1855
return
1956
}
2057

21-
if (process.env.NUXT_HUB_PROJECT_URL) {
58+
if (hub.projectUrl) {
2259
// TODO: check on hub.nuxt.com if the project is connected
23-
logger.info(`Using remote hub from \`${process.env.NUXT_HUB_PROJECT_URL}\``)
60+
logger.info(`Using remote hub from \`${hub.projectUrl}\``)
2461
return
2562
} else {
2663
logger.info('Using local hub from bindings')

package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
"license": "PROPRIETARY",
2020
"scripts": {
2121
"dev:prepare": "nuxt prepare _demo",
22-
"dev": "nuxi dev _demo",
22+
"dev": "PORT=4000 nuxi dev _demo",
2323
"build": "nuxi build --preset cloudflare_pages _demo",
2424
"preview": "nuxt preview _demo",
2525
"lint": "eslint .",
@@ -44,6 +44,7 @@
4444
"pathe": "^1.1.2",
4545
"pkg-types": "^1.0.3",
4646
"rc9": "^2.1.1",
47+
"ufo": "^1.4.0",
4748
"uncrypto": "^0.1.3",
4849
"wrangler": "^3.28.3",
4950
"zod": "^3.22.4"

pnpm-lock.yaml

+14-39
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

server/middleware/1.hub-auth.ts

+41-12
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,46 @@
1+
import { $fetch } from 'ofetch'
2+
13
export default eventHandler(async (event) => {
2-
if (/^\/api\/_hub\//.test(event.path) === false || import.meta.dev) {
4+
// Skip if not a hub request
5+
if (/^\/api\/_hub\//.test(event.path) === false) {
6+
return
7+
}
8+
// Skip if in development
9+
if (import.meta.dev) {
310
return
411
}
12+
const hub = useRuntimeConfig().hub
13+
const secretKey = (getHeader(event, 'authorization') || '').split(' ')[1]
14+
if (!secretKey) {
15+
console.log('throw')
16+
throw createError({
17+
statusCode: 403,
18+
message: 'Missing Authorization header'
19+
})
20+
}
21+
22+
// Self-hosted NuxtHub project, user has to set a secret key to access the proxy
23+
if (hub.projectSecretKey && secretKey !== hub.projectSecretKey) {
24+
throw createError({
25+
statusCode: 401,
26+
message: 'Invalid secret key'
27+
})
28+
}
29+
30+
// Hosted on NuxtHub
31+
if (/^\d+$/.test(hub.projectId as string)) {
32+
// Here the secretKey is a user token
33+
await $fetch(`/api/projects/${hub.projectId}`, {
34+
baseURL: hub.url,
35+
method: 'HEAD',
36+
headers: {
37+
authorization: `Bearer ${secretKey}`
38+
}
39+
})
40+
}
541

6-
// Authorize the request
7-
// console.log('Authorizing the request to hub.nuxt.com...')
8-
// Format Authorization: Bearer <secretKey>
9-
// const [, secretKey] = (getHeader(event, 'authorization') || '').split(' ')
10-
// await $fetch('https://hub.nuxt.com/api/authorize', {
11-
// method: 'HEAD',
12-
// headers: {
13-
// 'x-project-id': process.env.NUXT_HUB_PROJECT_ID || '',
14-
// authorization: `Bearer ${secretKey}`
15-
// }
16-
// })
42+
throw createError({
43+
statusCode: 401,
44+
message: 'Missing NUXT_HUB_PROJECT_SECRET_KEY'
45+
})
1746
})

server/utils/analytics.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,9 @@ function _useDataset() {
2020
}
2121

2222
export function useAnalytics() {
23-
if (import.meta.dev && process.env.NUXT_HUB_PROJECT_URL) {
24-
return useProxyAnalytics(process.env.NUXT_HUB_PROJECT_URL, process.env.NUXT_HUB_PROJECT_SECRET_KEY)
23+
const hub = useRuntimeConfig().hub
24+
if (import.meta.dev && hub.projectUrl) {
25+
return useProxyAnalytics(hub.projectUrl, hub.projectSecretKey || hub.userToken)
2526
}
2627
const dataset = _useDataset()
2728

server/utils/blob.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,9 @@ function _useBucket() {
2727
}
2828

2929
export function useBlob() {
30-
if (import.meta.dev && process.env.NUXT_HUB_PROJECT_URL) {
31-
return useProxyBlob(process.env.NUXT_HUB_PROJECT_URL, process.env.NUXT_HUB_PROJECT_SECRET_KEY)
30+
const hub = useRuntimeConfig().hub
31+
if (import.meta.dev && hub.projectUrl) {
32+
return useProxyBlob(hub.projectUrl, hub.projectSecretKey || hub.userToken)
3233
}
3334
const bucket = _useBucket()
3435

server/utils/database.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,9 @@ export function useDatabase() {
99
if (_db) {
1010
return _db
1111
}
12-
if (import.meta.dev && process.env.NUXT_HUB_PROJECT_URL) {
13-
_db = useProxyDatabase(process.env.NUXT_HUB_PROJECT_URL, process.env.NUXT_HUB_PROJECT_SECRET_KEY)
12+
const hub = useRuntimeConfig().hub
13+
if (import.meta.dev && hub.projectUrl) {
14+
_db = useProxyDatabase(hub.projectUrl, hub.projectSecretKey || hub.userToken)
1415
return _db
1516
}
1617
// @ts-ignore

server/utils/hooks.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ export interface HubHooks {
88
export const hubHooks = createHooks<HubHooks>()
99

1010
export function onHubReady (cb: HubHooks['bindings:ready']) {
11-
if (import.meta.dev && !process.env.NUXT_HUB_PROJECT_URL) {
11+
const hub = useRuntimeConfig().hub
12+
if (import.meta.dev && !hub.projectUrl) {
1213
return hubHooks.hookOnce('bindings:ready', cb)
1314
}
1415
cb()

server/utils/kv.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,11 @@ export function useKV() {
1010
if (_kv) {
1111
return _kv
1212
}
13-
if (import.meta.dev && process.env.NUXT_HUB_PROJECT_URL) {
14-
return useProxyKV(process.env.NUXT_HUB_PROJECT_URL, process.env.NUXT_HUB_PROJECT_SECRET_KEY)
13+
const hub = useRuntimeConfig().hub
14+
if (import.meta.dev && hub.projectUrl) {
15+
return useProxyKV(hub.projectUrl, hub.projectSecretKey || hub.userToken)
1516
}
17+
// @ts-ignore
1618
const binding = process.env.KV || globalThis.__env__?.KV || globalThis.KV
1719
if (binding) {
1820
_kv = createStorage({

0 commit comments

Comments
 (0)