- typed client and useMenu/useMenuApi (SSR, menu:<code>:<locale> key, server and public bases, x-forwarded-for forwarded also on cached renders) - MenuNav and recursive MenuNavItem: WAI disclosure navigation, URL allowlist with a text fallback, rel on _blank, active link and trail, mobile toggle, Esc / focus-out / outside pointer / route change closing - menu tokens and base CSS, README - node tests (link rules, client, server-rendered NavItem) and a playground SSR smoke against a fixture API
29 lines
1.4 KiB
TypeScript
29 lines
1.4 KiB
TypeScript
// The menu API client. On the server it calls the internal base
|
|
// (runtimeConfig.menu.apiBase) and forwards the visitor's x-forwarded-for,
|
|
// plus the address of the peer that reached Nuxt, so the Go rate limiter
|
|
// keeps one bucket per visitor, also on route-cached renders. In the browser
|
|
// it calls the same-origin public base. The base is always runtime config,
|
|
// never request input.
|
|
|
|
import { createMenuClient, type MenuClient, type MenuFetcher } from '../utils/client.ts'
|
|
|
|
export function useMenuApi(): MenuClient {
|
|
const config = useRuntimeConfig()
|
|
|
|
if (import.meta.server) {
|
|
const base = (config.menu as { apiBase: string }).apiBase
|
|
const event = useRequestEvent()
|
|
const recorded = event?.context.menuForwardedFor as string | undefined
|
|
const incoming = useRequestHeaders(['x-forwarded-for'])['x-forwarded-for']
|
|
const peer = event?.node?.req?.socket?.remoteAddress
|
|
const forwarded = recorded || [incoming, peer].filter((v): v is string => typeof v === 'string' && v !== '').join(', ')
|
|
const headers: Record<string, string> = forwarded ? { 'x-forwarded-for': forwarded } : {}
|
|
const fetcher: MenuFetcher = (path, query) => $fetch(path, { baseURL: base, query, headers })
|
|
return createMenuClient(fetcher)
|
|
}
|
|
|
|
const base = (config.public.menu as { apiBase: string }).apiBase
|
|
const fetcher: MenuFetcher = (path, query) => $fetch(path, { baseURL: base, query })
|
|
return createMenuClient(fetcher)
|
|
}
|