-
Notifications
You must be signed in to change notification settings - Fork 0
feat(agent-markdown): Add navigation to Markdown exports #9
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
a4d4b22
170be0e
4b95d0a
e4aa7d2
cd803df
0e3e6c7
3cc0de0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,37 +2,75 @@ import { defineMiddleware } from "astro:middleware"; | |
| import { isIgnoredPath, toMarkdownPath } from "./path-utils"; | ||
| import { base as siteBase } from "virtual:sentry-starlight-theme/agent-markdown/config"; | ||
|
|
||
| export const onRequest = defineMiddleware((context, next) => { | ||
| export const onRequest = defineMiddleware(async (context, next) => { | ||
| const { pathname, search } = context.url; | ||
| const forceMarkdown = context.url.searchParams.get("format") === "md"; | ||
|
|
||
| if (isMarkdownPath(pathname) || isIgnoredPath(pathname, siteBase)) { | ||
| return next(); | ||
| } | ||
|
|
||
| if (!wantsMarkdown(context.request.headers)) { | ||
| const uaTriggered = | ||
| !forceMarkdown && | ||
| isAIOrDevTool(context.request.headers.get("user-agent") ?? ""); | ||
|
|
||
| if ( | ||
| !forceMarkdown && | ||
| !uaTriggered && | ||
| !acceptsMarkdown(context.request.headers) | ||
| ) { | ||
| return next(); | ||
| } | ||
|
|
||
| const destination = new URL(context.url); | ||
| destination.pathname = toMarkdownPath(pathname, siteBase); | ||
| destination.search = search; | ||
| destination.searchParams.delete("format"); | ||
|
|
||
| const response = await context.rewrite(destination); | ||
|
|
||
| return context.rewrite(destination); | ||
| // When the rewrite was triggered by User-Agent rather than an explicit Accept | ||
| // header or format param, add Vary: User-Agent so caches key on the UA and | ||
| // don't serve Markdown to regular browsers at the same URL. | ||
| if (uaTriggered) { | ||
| response.headers.append("Vary", "User-Agent"); | ||
| } | ||
|
Comment on lines
+35
to
+37
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Bug: When a rewrite is triggered by a User-Agent, the middleware incorrectly appends Suggested FixThe middleware should ensure the final Prompt for AI Agent |
||
|
|
||
| return response; | ||
| }); | ||
|
|
||
| function wantsMarkdown(headers: Headers) { | ||
| function acceptsMarkdown(headers: Headers) { | ||
| const accept = headers.get("accept") ?? ""; | ||
| if (!accept) { | ||
| return false; | ||
| } | ||
|
|
||
| return accept.split(",").some((entry) => { | ||
| const entries = accept.split(",").map((entry) => { | ||
| const [type = "", ...parameters] = entry.trim().toLowerCase().split(";"); | ||
| return { type: type.trim(), q: getAcceptQuality(parameters) }; | ||
| }); | ||
|
|
||
| const mediaType = type.trim(); | ||
| if (mediaType !== "text/markdown" && mediaType !== "text/x-markdown") { | ||
| return false; | ||
| const htmlQuality = entries.find(({ type }) => type === "text/html")?.q ?? 0; | ||
| const markdownQuality = entries.reduce((max, { type, q }) => { | ||
| if ( | ||
| type === "text/markdown" || | ||
| type === "text/plain" || | ||
| type === "text/x-markdown" | ||
| ) { | ||
|
cursor[bot] marked this conversation as resolved.
|
||
| return Math.max(max, q); | ||
| } | ||
| return max; | ||
| }, 0); | ||
|
|
||
| return getAcceptQuality(parameters) > 0; | ||
| }); | ||
| // Only rewrite when a markdown type is explicitly wanted AND outranks text/html. | ||
| // Equal quality defers to HTML since that is the native format for these URLs. | ||
| return markdownQuality > 0 && markdownQuality > htmlQuality; | ||
| } | ||
|
|
||
| function isAIOrDevTool(userAgent: string) { | ||
| return /claude|anthropic|gptbot|chatgpt|openai|cursor|codex|copilot|perplexity|cohere|gemini/i.test( | ||
| userAgent, | ||
| ); | ||
|
Comment on lines
+70
to
+73
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Bug: The User-Agent detection regex is too broad, using simple substring matches for terms like Suggested FixMake the User-Agent matching regex stricter to avoid false positives. Consider using word boundaries (e.g., Prompt for AI Agent |
||
| } | ||
|
|
||
| function isMarkdownPath(pathname: string) { | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.