mirror of
https://github.com/stack-auth/stack.git
synced 2026-06-19 21:00:40 +08:00
Some checks failed
all-good: Did all the other checks pass? / all-good (push) Has been cancelled
Ensure Prisma migrations are in sync with the schema / check_prisma_migrations (22.x) (push) Has been cancelled
DB migration compat / Check if migrations changed (push) Has been cancelled
Docker Server Build and Push / Docker Build and Push Server (push) Has been cancelled
Docker Server Build and Run / docker (push) Has been cancelled
Runs E2E API Tests (Local Emulator) / E2E Tests (Local Emulator, Node ${{ matrix.node-version }}) (22.x) (push) Has been cancelled
Runs E2E API Tests / E2E Tests (Node ${{ matrix.node-version }}, Freestyle ${{ matrix.freestyle-mode }}) (mock, 22.x) (push) Has been cancelled
Runs E2E API Tests / E2E Tests (Node ${{ matrix.node-version }}, Freestyle ${{ matrix.freestyle-mode }}) (prod, 22.x) (push) Has been cancelled
Runs E2E API Tests with custom port prefix / build (22.x) (push) Has been cancelled
Runs E2E Fallback Tests / E2E Fallback Tests (Node ${{ matrix.node-version }}) (22.x) (push) Has been cancelled
Lint & build / lint_and_build (24) (push) Has been cancelled
TOC Generator / TOC Generator (push) Has been cancelled
DB migration compat / Back-compat — Current branch migrations with ${{ needs.check-migrations-changed.outputs.base_branch }} branch code (push) Has been cancelled
DB migration compat / Forward-compat — Current branch code with ${{ needs.check-migrations-changed.outputs.base_branch }} branch migrations (push) Has been cancelled
DB migration compat / No migration changes (skipped) (push) Has been cancelled
77 lines
2.6 KiB
TypeScript
77 lines
2.6 KiB
TypeScript
import { trackVisit } from '2027-track';
|
|
import { runAsynchronously } from '@hexclave/shared/dist/utils/promises';
|
|
import { NextFetchEvent, NextRequest, NextResponse } from 'next/server';
|
|
|
|
export default function middleware(request: NextRequest, event: NextFetchEvent) {
|
|
const { pathname } = request.nextUrl;
|
|
|
|
// Track AI agent visits
|
|
const trackPromise = trackVisit({
|
|
host: request.headers.get('host') ?? request.nextUrl.host,
|
|
path: pathname,
|
|
userAgent: request.headers.get('user-agent') ?? '',
|
|
accept: request.headers.get('accept') ?? '',
|
|
country: request.headers.get('x-vercel-ip-country') ?? undefined,
|
|
});
|
|
runAsynchronously(trackPromise);
|
|
event.waitUntil(trackPromise);
|
|
|
|
// Redirect old concepts paths to new apps paths
|
|
const movedToApps = [
|
|
'api-keys',
|
|
'emails',
|
|
'oauth',
|
|
'orgs-and-teams',
|
|
'permissions',
|
|
'webhooks',
|
|
];
|
|
|
|
if (pathname.startsWith('/docs/concepts/')) {
|
|
const pageName = pathname.replace('/docs/concepts/', '');
|
|
if (movedToApps.includes(pageName)) {
|
|
const url = request.nextUrl.clone();
|
|
url.pathname = `/docs/apps/${pageName}`;
|
|
return NextResponse.redirect(url, 301); // 301 = permanent redirect
|
|
}
|
|
}
|
|
|
|
// Only apply to docs and api pages (not already .mdx requests)
|
|
// Match /docs, /docs/, /docs/... and /api, /api/, /api/...
|
|
const isDocsPath = pathname === '/docs' || pathname.startsWith('/docs/');
|
|
const isApiPath = pathname === '/api' || pathname.startsWith('/api/');
|
|
|
|
if ((isDocsPath || isApiPath) && !pathname.endsWith('.mdx')) {
|
|
const acceptHeader = request.headers.get('accept') ?? '';
|
|
|
|
// Parse Accept header by splitting on commas to properly handle MIME type ordering
|
|
const acceptTypes = acceptHeader.split(',').map((t: string) => t.trim().split(';')[0]);
|
|
|
|
// Find the index of each MIME type in the Accept header
|
|
const plainIndex = acceptTypes.findIndex(
|
|
(t: string) => t === 'text/plain' || t === 'text/markdown'
|
|
);
|
|
const htmlIndex = acceptTypes.findIndex((t: string) => t === 'text/html');
|
|
|
|
// Prefer markdown if text/plain or text/markdown appears before text/html (or text/html doesn't exist)
|
|
const prefersMarkdown = plainIndex !== -1 && (htmlIndex === -1 || plainIndex < htmlIndex);
|
|
|
|
if (prefersMarkdown) {
|
|
// Rewrite to the LLM markdown endpoint
|
|
const url = request.nextUrl.clone();
|
|
url.pathname = `/llms.mdx${pathname.replace(/^\/(docs|api)/, '')}`;
|
|
|
|
// Preserve query parameters (platform, framework, etc.)
|
|
return NextResponse.rewrite(url);
|
|
}
|
|
}
|
|
|
|
return NextResponse.next();
|
|
}
|
|
|
|
export const config = {
|
|
matcher: [
|
|
'/docs/:path*',
|
|
'/api/:path*',
|
|
],
|
|
};
|