import { useGeneratedState } from '~/composables/generated' import { projectQueryOptions } from '~/composables/queries/project' import { useAppQueryClient } from '~/composables/query-client' import { getProjectTypeForUrlShorthand } from '~/helpers/projects.js' import { useServerModrinthClient } from '~/server/utils/api-client' // All valid project type URL segments const PROJECT_TYPES = [ 'project', 'mod', 'plugin', 'datapack', 'shader', 'resourcepack', 'modpack', 'server', 'minecraft_java_server', ] export default defineNuxtRouteMiddleware(async (to) => { // Only run this middleware on the server - it relies on server-only runtime config if (import.meta.client) return // Only handle project routes if (!to.params.id || !PROJECT_TYPES.includes(to.params.type as string)) { return } const queryClient = useAppQueryClient() const authToken = useCookie('auth-token') const client = useServerModrinthClient({ authToken: authToken.value || undefined }) const tags = useGeneratedState() const projectId = to.params.id as string try { // Fetch v2 project for redirect check AND cache it for the page // Using fetchQuery ensures the page's useQuery gets this cached result const project = await queryClient.fetchQuery(projectQueryOptions.v2(projectId, client)) const projectV3 = await queryClient.fetchQuery(projectQueryOptions.v3(projectId, client)) // Let page handle 404 if (!project) return // Cache by slug if we looked up by ID (or vice versa) if (projectId !== project.slug) { queryClient.setQueryData(['project', 'v2', project.slug], project) } if (projectId !== project.id) { queryClient.setQueryData(['project', 'v2', project.id], project) } const projectType = projectV3.minecraft_server != null ? 'server' : project.project_type // Determine the correct URL type const correctType = getProjectTypeForUrlShorthand(projectType, project.loaders, tags.value) // Preserve the rest of the path (subpages like /versions, /settings, etc.) const pathParts = to.path.split('/') pathParts.splice(0, 3) // Remove '', type, and id const remainder = pathParts.filter((x) => x).join('/') // Build the canonical path const canonicalPath = `/${correctType}/${project.slug}${remainder ? `/${remainder}` : ''}` // Only redirect if the path actually changed if (to.path !== canonicalPath) { return navigateTo( { path: canonicalPath, query: to.query, hash: to.hash, }, { redirectCode: 301, replace: true, }, ) } } catch { // Let the page handle 404s and other errors } })