diff --git a/apps/frontend/src/middleware/project.global.ts b/apps/frontend/src/middleware/project.global.ts
index 27b6da8323..3b11fca38b 100644
--- a/apps/frontend/src/middleware/project.global.ts
+++ b/apps/frontend/src/middleware/project.global.ts
@@ -1,6 +1,7 @@
import { useGeneratedState } from '~/composables/generated'
import { projectQueryOptions } from '~/composables/queries/project'
import { useAppQueryClient } from '~/composables/query-client'
+import { createModrinthClient } from '~/helpers/api.ts'
import { getProjectTypeForUrlShorthand } from '~/helpers/projects.js'
import { useServerModrinthClient } from '~/server/utils/api-client'
@@ -18,9 +19,6 @@ const PROJECT_TYPES = [
]
export default defineNuxtRouteMiddleware(async (to) => {
- // Only run this middleware on the server - it relies on server-only runtime config
- if (import.meta.client) return
-
const routeProjectParam = to.params.project
const projectId = Array.isArray(routeProjectParam) ? routeProjectParam[0] : routeProjectParam
const routeType = Array.isArray(to.params.type) ? to.params.type[0] : to.params.type
@@ -31,10 +29,11 @@ export default defineNuxtRouteMiddleware(async (to) => {
}
const queryClient = useAppQueryClient()
- const authToken = useCookie('auth-token')
- const client = useServerModrinthClient({ authToken: authToken.value || undefined })
+ const client = await getProjectMiddlewareClient()
const tags = useGeneratedState()
+ if (import.meta.client) startLoading()
+
try {
// Fetch v2 and v3 in parallel — cache both for the page's useQuery calls
const [project, projectV3] = await Promise.all([
@@ -48,9 +47,11 @@ export default defineNuxtRouteMiddleware(async (to) => {
// Cache by slug if we looked up by ID (or vice versa)
if (projectId !== project.slug) {
queryClient.setQueryData(['project', 'v2', project.slug], project)
+ queryClient.setQueryData(['project', 'v3', project.slug], projectV3)
}
if (projectId !== project.id) {
queryClient.setQueryData(['project', 'v2', project.id], project)
+ queryClient.setQueryData(['project', 'v3', project.id], projectV3)
}
const projectType = projectV3.minecraft_server != null ? 'server' : project.project_type
@@ -81,5 +82,23 @@ export default defineNuxtRouteMiddleware(async (to) => {
}
} catch {
// Let the page handle 404s and other errors
+ } finally {
+ if (import.meta.client) stopLoading()
}
})
+
+async function getProjectMiddlewareClient() {
+ if (import.meta.server) {
+ const authToken = useCookie('auth-token')
+ return useServerModrinthClient({ authToken: authToken.value || undefined })
+ }
+
+ const auth = await useAuth()
+ const config = useRuntimeConfig()
+
+ return createModrinthClient(auth, {
+ apiBaseUrl: config.public.apiBaseUrl.replace('/v2/', '/'),
+ archonBaseUrl: config.public.pyroBaseUrl.replace('/v2/', '/'),
+ rateLimitKey: config.rateLimitKey,
+ })
+}
diff --git a/apps/frontend/src/pages/[type]/[project].vue b/apps/frontend/src/pages/[type]/[project].vue
index 84215dbcfa..a9eaf9699e 100644
--- a/apps/frontend/src/pages/[type]/[project].vue
+++ b/apps/frontend/src/pages/[type]/[project].vue
@@ -421,6 +421,18 @@