Redirects — @sonordev/site-kit/redirects
Sonor-managed 301/302/307/308 redirect rules. Used by createProxy() or standalone.
Usage
Automatically handled when using createProxy():
// proxy.ts
import { createProxy } from '@sonordev/site-kit/proxy'
export default createProxy() // redirects: true by default
// Inlined: an imported `config.matcher` is a build error. See the proxy README.
export const config = {
matcher: [
'/((?!_next/static|_next/image|favicon\\.ico|.*\\.(?:ico|png|jpg|jpeg|gif|webp|svg|woff2?)$).*)',
],
}For standalone use:
import { handleManagedRedirects } from '@sonordev/site-kit/redirects'
export async function middleware(request: NextRequest) {
const redirect = await handleManagedRedirects(request, {})
if (redirect) return redirect
return NextResponse.next()
}API
handleManagedRedirects(request: NextRequest, config: RedirectConfig): Promise<NextResponse | undefined>
fetchRedirectRules(config: RedirectConfig): Promise<RedirectRule[]>
generateNextRedirects(config: RedirectConfig): Promise<Redirect[]> // For next.config.js
clearRedirectCache(): void // Dev helperConfig
interface RedirectConfig {
domain?: string // Resolved from Sonor when using apiKey
apiKey?: string // Project API key
site?: string // Multi-site host, sent as ?site= and cached per host (default: NEXT_PUBLIC_SITE_URL host)
portalApiUrl?: string // Default: https://api.sonor.io
cacheSeconds?: number // Default: 300 (5 minutes)
}Behavior
- Checks in-memory cache first
- Fetches rules from Sonor API if expired
- Matches pathname (exact or trailing-slash variant)
- Preserves query parameters on redirect
- Tracks redirect hit (fire-and-forget)
- Skips static assets and API routes
Types
interface RedirectRule {
from_path: string
to_path: string
redirect_type: '301' | '302' | '307' | '308'
is_enabled: boolean
}