@publish.os/nextjs 0.0.1-alpha.90 → 0.0.1-alpha.92
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/compiler-assets/nextjs/defaults/group/index.tsx +16 -11
- package/compiler-assets/nextjs/defaults/group/layout.tsx +6 -6
- package/compiler-assets/nextjs/defaults/group/page.tsx +36 -26
- package/compiler-assets/nextjs/defaults/project/next.config.mjs +21 -11
- package/compiler-assets/nextjs/defaults/project/tsconfig.json.template +10 -0
- package/compiler-assets/nextjs/defaults/root/css/components/code-block.css +18 -0
- package/compiler-assets/nextjs/defaults/root/index.tsx +16 -11
- package/compiler-assets/nextjs/defaults/root/layout.tsx +7 -3
- package/compiler-assets/nextjs/shims/agent-user-agents.ts +65 -0
- package/compiler-assets/nextjs/shims/document.tsx +46 -0
- package/compiler-assets/nextjs/shims/generated-leaf-page.tsx +5 -0
- package/compiler-assets/nextjs/shims/global-layout.tsx +8 -42
- package/compiler-assets/nextjs/shims/global-not-found.tsx +69 -0
- package/compiler-assets/nextjs/shims/markdown-route.ts +2 -0
- package/compiler-assets/nextjs/shims/metadata-icons.tsx +39 -0
- package/compiler-assets/nextjs/shims/not-found-content.tsx +53 -0
- package/compiler-assets/nextjs/shims/not-found-navigation.tsx +60 -0
- package/compiler-assets/nextjs/shims/proxy.ts +254 -86
- package/compiler-assets/nextjs/shims/site-fenced-code-block.tsx +2 -6
- package/compiler-assets/nextjs/shims/site-mdx-components.tsx +28 -16
- package/compiler-assets/nextjs/shims/site-mdx.tsx +6 -1
- package/dist/{build-operation-2JAYBSKF.js → build-operation-CJDUL4OW.js} +29 -23
- package/dist/{button-c3WGnxIj.d.ts → button-D6Xp2HBm.d.ts} +4 -4
- package/dist/capture-local-source-WGGDIUU2.js +258 -0
- package/dist/chunk-22RSSUNV.js +13 -0
- package/dist/chunk-3T4HVDSC.js +426 -0
- package/dist/{chunk-WKTEO6RS.js → chunk-4BC2L2KA.js} +46 -12
- package/dist/{chunk-WDY4IK6Z.js → chunk-5J3YUNRY.js} +3 -10
- package/dist/chunk-5KAD7W53.js +248 -0
- package/dist/{chunk-DWA3ZRGW.js → chunk-6C65KV7O.js} +2 -2
- package/dist/{chunk-GGKFQ3MA.js → chunk-6D2E6UMD.js} +144 -70
- package/dist/{chunk-7OGTPSKI.js → chunk-7NY22B5U.js} +8 -3
- package/dist/chunk-DX7PXFCM.js +2519 -0
- package/dist/{chunk-726GV2NF.js → chunk-DZ3VWEV5.js} +950 -632
- package/dist/chunk-EFO6AWXN.js +19 -0
- package/dist/chunk-IL4RJOKI.js +186 -0
- package/dist/{chunk-H6XILMZX.js → chunk-NHSLTARU.js} +2588 -1493
- package/dist/{chunk-DLDFHU7Y.js → chunk-NNBJZPFM.js} +4 -2
- package/dist/{chunk-VO2I7MTM.js → chunk-SBMDONTV.js} +10 -7
- package/dist/{chunk-YLTOLYWM.js → chunk-WL75GQ5M.js} +6 -18
- package/dist/compiler.d.ts +15 -2
- package/dist/compiler.js +111 -23
- package/dist/components/blocks/agent-actions.d.ts +81 -0
- package/dist/components/blocks/agent-actions.js +563 -0
- package/dist/components/blocks/toc.d.ts +43 -0
- package/dist/components/blocks/toc.js +136 -0
- package/dist/components/ui/button.d.ts +4 -0
- package/dist/components/ui/button.js +94 -0
- package/dist/compose-44GJSMXD.js +16 -0
- package/dist/config/createNextConfig.js +19 -3
- package/dist/{dev-operation-TZDVJCN7.js → dev-operation-WNECBHZ5.js} +134 -84
- package/dist/{framework-selection-X4U6Y6QC.js → framework-selection-ZVO323PK.js} +3 -2
- package/dist/ide-support-TG74L4FF.js +16 -0
- package/dist/index.d.ts +151 -95
- package/dist/index.js +25 -0
- package/dist/jsx-dev-runtime.d.ts +6 -0
- package/dist/jsx-dev-runtime.js +100 -0
- package/dist/jsx-runtime.d.ts +7 -0
- package/dist/jsx-runtime.js +97 -0
- package/dist/kernel/components/blocks/AgentActions.d.ts +37 -8
- package/dist/kernel/components/blocks/AgentActions.js +384 -174
- package/dist/kernel/components/blocks/agent-actions.d.ts +4 -0
- package/dist/kernel/components/blocks/agent-actions.js +563 -0
- package/dist/kernel/components/blocks/animated-icon-swap.d.ts +2 -2
- package/dist/kernel/components/blocks/animated-icon-swap.js +1 -1
- package/dist/kernel/components/blocks/color-palette.d.ts +2 -2
- package/dist/kernel/components/blocks/color-palette.js +4 -4
- package/dist/kernel/components/blocks/logo-block.d.ts +2 -2
- package/dist/kernel/components/blocks/logo-block.js +1 -1
- package/dist/kernel/components/blocks/nav-breadcrumb.d.ts +6 -5
- package/dist/kernel/components/blocks/nav-breadcrumb.js +21 -15
- package/dist/kernel/components/blocks/navbar.d.ts +5 -4
- package/dist/kernel/components/blocks/navbar.js +79 -59
- package/dist/kernel/components/blocks/navigation-progress.d.ts +2 -2
- package/dist/kernel/components/blocks/navigation-progress.js +2 -2
- package/dist/kernel/components/blocks/next-prev.d.ts +4 -4
- package/dist/kernel/components/blocks/next-prev.js +30 -7
- package/dist/kernel/components/blocks/page-list.d.ts +4 -4
- package/dist/kernel/components/blocks/page-list.js +32 -9
- package/dist/kernel/components/blocks/search.d.ts +9 -15
- package/dist/kernel/components/blocks/search.js +16 -17
- package/dist/kernel/components/blocks/sidebar-node.d.ts +3 -5
- package/dist/kernel/components/blocks/sidebar-node.js +13 -3
- package/dist/kernel/components/blocks/sidebar.d.ts +6 -7
- package/dist/kernel/components/blocks/sidebar.js +137 -28
- package/dist/kernel/components/blocks/theme-toggle.d.ts +3 -4
- package/dist/kernel/components/blocks/theme-toggle.js +5 -5
- package/dist/kernel/components/blocks/toc-client.d.ts +40 -0
- package/dist/kernel/components/blocks/toc-client.js +495 -0
- package/dist/kernel/components/blocks/toc.d.ts +20 -2
- package/dist/kernel/components/blocks/toc.js +121 -179
- package/dist/kernel/components/mdx/components/blockquote.d.ts +2 -2
- package/dist/kernel/components/mdx/components/blockquote.js +1 -1
- package/dist/kernel/components/mdx/components/callout.d.ts +3 -3
- package/dist/kernel/components/mdx/components/callout.js +1 -1
- package/dist/kernel/components/mdx/components/code-block.d.ts +2 -2
- package/dist/kernel/components/mdx/components/code-block.js +2 -2
- package/dist/kernel/components/mdx/components/copy-code-button.d.ts +2 -2
- package/dist/kernel/components/mdx/components/copy-code-button.js +5 -4
- package/dist/kernel/components/mdx/components/figure-caption.d.ts +3 -3
- package/dist/kernel/components/mdx/components/figure-caption.js +3 -2
- package/dist/kernel/components/mdx/components/figure.d.ts +8 -4
- package/dist/kernel/components/mdx/components/figure.js +23 -13
- package/dist/kernel/components/mdx/components/footnotes.d.ts +2 -2
- package/dist/kernel/components/mdx/components/footnotes.js +1 -1
- package/dist/kernel/components/mdx/components/heading-copy-link.d.ts +2 -2
- package/dist/kernel/components/mdx/components/heading-copy-link.js +1 -1
- package/dist/kernel/components/mdx/components/heading.d.ts +2 -2
- package/dist/kernel/components/mdx/components/heading.js +6 -3
- package/dist/kernel/components/mdx/components/hr.d.ts +4 -4
- package/dist/kernel/components/mdx/components/hr.js +2 -2
- package/dist/kernel/components/mdx/components/image-zoom.d.ts +3 -3
- package/dist/kernel/components/mdx/components/image-zoom.js +4 -3
- package/dist/kernel/components/mdx/components/image.d.ts +2 -2
- package/dist/kernel/components/mdx/components/image.js +22 -17
- package/dist/kernel/components/mdx/components/inline-code.d.ts +2 -2
- package/dist/kernel/components/mdx/components/inline-code.js +1 -1
- package/dist/kernel/components/mdx/components/kbd.d.ts +3 -3
- package/dist/kernel/components/mdx/components/kbd.js +2 -2
- package/dist/kernel/components/mdx/components/link.d.ts +6 -6
- package/dist/kernel/components/mdx/components/link.js +2 -2
- package/dist/kernel/components/mdx/components/paragraph.d.ts +2 -2
- package/dist/kernel/components/mdx/components/paragraph.js +1 -1
- package/dist/kernel/components/mdx/components/strikethrough.d.ts +2 -2
- package/dist/kernel/components/mdx/components/strikethrough.js +1 -1
- package/dist/kernel/components/mdx/components/table.d.ts +7 -7
- package/dist/kernel/components/mdx/components/table.js +2 -2
- package/dist/kernel/components/mdx/components/task-list.d.ts +3 -3
- package/dist/kernel/components/mdx/components/task-list.js +1 -1
- package/dist/kernel/components/mdx/components/video-player.d.ts +8 -4
- package/dist/kernel/components/mdx/components/video-player.js +6 -2
- package/dist/kernel/components/mdx/components/video.d.ts +5 -4
- package/dist/kernel/components/mdx/components/video.js +7 -5
- package/dist/kernel/components/mdx/error-boundary.d.ts +3 -4
- package/dist/kernel/components/mdx/error-boundary.js +2 -2
- package/dist/kernel/components/mdx/error-fallback.d.ts +2 -2
- package/dist/kernel/components/mdx/error-fallback.js +1 -1
- package/dist/kernel/components/mdx/mdx.d.ts +57 -16
- package/dist/kernel/components/mdx/mdx.js +232 -35
- package/dist/kernel/components/mdx/rehype-heading-ids.d.ts +1 -0
- package/dist/kernel/components/mdx/rehype-heading-ids.js +5 -3
- package/dist/kernel/components/mdx/types.d.ts +1 -1
- package/dist/kernel/components/next-image.d.ts +12 -0
- package/dist/kernel/components/next-image.js +61 -0
- package/dist/kernel/components/ui/accordion.d.ts +7 -7
- package/dist/kernel/components/ui/accordion.js +1 -1
- package/dist/kernel/components/ui/breadcrumb-trail.d.ts +3 -4
- package/dist/kernel/components/ui/breadcrumb-trail.js +2 -2
- package/dist/kernel/components/ui/breadcrumb.d.ts +14 -14
- package/dist/kernel/components/ui/breadcrumb.js +4 -4
- package/dist/kernel/components/ui/button-group.d.ts +6 -6
- package/dist/kernel/components/ui/button-group.js +3 -3
- package/dist/kernel/components/ui/button.d.ts +59 -7
- package/dist/kernel/components/ui/button.js +43 -39
- package/dist/kernel/components/ui/card.d.ts +7 -7
- package/dist/kernel/components/ui/card.js +1 -1
- package/dist/kernel/components/ui/dialog.d.ts +10 -10
- package/dist/kernel/components/ui/dialog.js +1 -1
- package/dist/kernel/components/ui/drawer.d.ts +12 -12
- package/dist/kernel/components/ui/drawer.js +1 -1
- package/dist/kernel/components/ui/input.d.ts +2 -2
- package/dist/kernel/components/ui/input.js +1 -1
- package/dist/kernel/components/ui/kbd.d.ts +4 -4
- package/dist/kernel/components/ui/kbd.js +1 -1
- package/dist/kernel/components/ui/link.d.ts +11 -5
- package/dist/kernel/components/ui/link.js +2 -2
- package/dist/kernel/components/ui/menu.d.ts +22 -22
- package/dist/kernel/components/ui/menu.js +1 -1
- package/dist/kernel/components/ui/mod-key.d.ts +2 -3
- package/dist/kernel/components/ui/mod-key.js +2 -2
- package/dist/kernel/components/ui/navigation-menu.d.ts +15 -15
- package/dist/kernel/components/ui/navigation-menu.js +1 -1
- package/dist/kernel/components/ui/popover.d.ts +11 -11
- package/dist/kernel/components/ui/popover.js +1 -1
- package/dist/kernel/components/ui/progress.d.ts +7 -7
- package/dist/kernel/components/ui/progress.js +1 -1
- package/dist/kernel/components/ui/scroll-area.d.ts +9 -10
- package/dist/kernel/components/ui/scroll-area.js +1 -1
- package/dist/kernel/components/ui/select.d.ts +16 -16
- package/dist/kernel/components/ui/select.js +1 -1
- package/dist/kernel/components/ui/separator.d.ts +3 -3
- package/dist/kernel/components/ui/separator.js +1 -1
- package/dist/kernel/components/ui/table.d.ts +7 -7
- package/dist/kernel/components/ui/table.js +1 -1
- package/dist/kernel/components/ui/tabs.d.ts +12 -12
- package/dist/kernel/components/ui/tabs.js +1 -1
- package/dist/kernel/components/ui/tag.d.ts +3 -3
- package/dist/kernel/components/ui/tag.js +1 -1
- package/dist/kernel/components/ui/text.d.ts +4 -4
- package/dist/kernel/components/ui/text.js +1 -1
- package/dist/kernel/components/ui/toast.d.ts +11 -11
- package/dist/kernel/components/ui/toast.js +1 -1
- package/dist/kernel/components/ui/tooltip.d.ts +9 -9
- package/dist/kernel/components/ui/tooltip.js +1 -1
- package/dist/kernel/defaults.registry.d.ts +4 -17
- package/dist/kernel/defaults.registry.js +4 -19
- package/dist/kernel/routes/agent/markdown.d.ts +7 -0
- package/dist/kernel/routes/agent/markdown.js +229 -54
- package/dist/kernel/routes/layouts/group.d.ts +1 -1
- package/dist/kernel/routes/layouts/group.js +5 -7
- package/dist/kernel/routes/metadata/feed.d.ts +1 -2
- package/dist/kernel/routes/metadata/feed.js +119 -88
- package/dist/kernel/routes/metadata/llms.d.ts +3 -23
- package/dist/kernel/routes/metadata/llms.js +2 -103
- package/dist/kernel/routes/metadata/og-image.js +1 -1
- package/dist/kernel/routes/metadata/robots.d.ts +5 -3
- package/dist/kernel/routes/metadata/robots.js +4 -25
- package/dist/kernel/routes/metadata/sitemap.d.ts +36 -3
- package/dist/kernel/routes/metadata/sitemap.js +277 -49
- package/dist/kernel/routes/not-found.d.ts +34 -0
- package/dist/kernel/routes/not-found.js +213 -0
- package/dist/kernel/routes/pages/group.d.ts +5 -5
- package/dist/kernel/routes/pages/group.js +11 -5
- package/dist/kernel/routes/pages/leaf.d.ts +38 -6
- package/dist/kernel/routes/pages/leaf.js +21 -12
- package/dist/kernel/routes/pages/root.d.ts +5 -5
- package/dist/kernel/routes/pages/root.js +21 -6
- package/dist/keyboard-shortcuts.d.ts +2 -2
- package/dist/keyboard-shortcuts.js +1 -1
- package/dist/manifest-types-CcVPH_jh.d.ts +83 -0
- package/dist/resolvers/manifest-resolver.d.ts +2 -2
- package/dist/resolvers/manifest-resolver.js +65 -35
- package/dist/route-metadata-og-image-BeKKFHg7.d.ts +58 -0
- package/dist/search.d.ts +2 -9
- package/dist/search.js +9 -16
- package/dist/sidebar-types-CMrMM0Nj.d.ts +105 -0
- package/dist/theme-scope.d.ts +2 -2
- package/dist/theme-scope.js +1 -1
- package/dist/types-BbqmOzLC.d.ts +168 -0
- package/dist/types-TjH1ek0X.d.ts +22 -0
- package/dist/types-sM2g9nW0.d.ts +12 -0
- package/dist/types.d.ts +117 -91
- package/dist/utils/heading-ids.js +30 -11
- package/dist/utils/toc-selection.d.ts +7 -0
- package/dist/utils/toc-selection.js +14 -0
- package/dist/validate-local-source-EN2GW4FR.js +16 -0
- package/dist/validate-publish-os-source-OEWQDB7B.js +14 -0
- package/init/seed/minimal/publish.os/assets/blog/hello-world.svg +13 -0
- package/init/seed/minimal/publish.os/assets/favicon.dark.svg +13 -0
- package/init/seed/minimal/publish.os/assets/favicon.svg +13 -0
- package/init/seed/minimal/publish.os/blog/content/hello-world.mdx +48 -0
- package/init/seed/minimal/publish.os/blog/content/series-a.mdx +11 -0
- package/init/seed/minimal/publish.os/blog/index.tsx +85 -0
- package/init/seed/minimal/publish.os/blog/layout.tsx +13 -0
- package/init/seed/minimal/publish.os/blog/page.tsx +91 -0
- package/init/seed/minimal/publish.os/components/blog/copy-link.tsx +64 -0
- package/init/seed/minimal/publish.os/components/blog/frontmatter.ts +41 -0
- package/init/seed/minimal/publish.os/docs/content/get-started.mdx +2 -3
- package/init/seed/minimal/publish.os/docs/content/groups.mdx +5 -6
- package/init/seed/minimal/publish.os/publish.os.config.json +17 -2
- package/init/seed/minimal/publish.os/theme.css +3 -3
- package/init/seed/minimal/seed.json +12 -4
- package/init/seed/scratch/publish.os/docs/content/get-started.mdx +1 -1
- package/init/seed/scratch/publish.os/publish.os.config.json +1 -1
- package/package.json +48 -23
- package/release/app/phosphor/package.json +4 -4
- package/release/app/phosphor/pnpm-lock.yaml.template +123 -184
- package/release/compiler/package.json +5 -3
- package/release/compiler/pnpm-lock.yaml.template +153 -183
- package/release/release.json +6 -6
- package/dist/button-CtzUJB8u.d.ts +0 -11
- package/dist/chunk-535TM4A5.js +0 -1455
- package/dist/chunk-B2V22WRT.js +0 -297
- package/dist/chunk-NECL5IBJ.js +0 -318
- package/dist/chunk-SVYGXXYR.js +0 -36
- package/dist/chunk-UF6ATARM.js +0 -1100
- package/dist/compose-NN23UJGC.js +0 -13
- package/dist/ide-support-ZNW7ODFY.js +0 -15
- package/dist/kernel/components/blocks/design-system-preview.d.ts +0 -61
- package/dist/kernel/components/blocks/design-system-preview.js +0 -667
- package/dist/kernel/components/blocks/link-playground.d.ts +0 -5
- package/dist/kernel/components/blocks/link-playground.js +0 -744
- package/dist/kernel/components/blocks/navigation-progress-playground.d.ts +0 -5
- package/dist/kernel/components/blocks/navigation-progress-playground.js +0 -629
- package/dist/kernel/components/ui/theme-toggle.d.ts +0 -24
- package/dist/kernel/components/ui/theme-toggle.js +0 -53
- package/dist/sidebar-types-DKpR27II.d.ts +0 -25
- package/dist/types-BzkZty3r.d.ts +0 -147
- package/dist/types-CJWRG05y.d.ts +0 -76
- package/dist/types-CUtrppxt.d.ts +0 -69
- package/dist/validate-local-source-XRL2Y7XE.js +0 -14
- package/dist/validate-publish-os-source-DAPZ4QGE.js +0 -12
- package/init/seed/minimal/publish.os/assets/favicon/favicon.dark.png +0 -0
- package/init/seed/minimal/publish.os/assets/favicon/favicon.png +0 -0
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { faviconsAndLogos } from "@source/.publishos/favicons-and-logos.generated";
|
|
2
|
+
import type { Metadata } from "next";
|
|
3
|
+
|
|
4
|
+
type GeneratedMetadataIcons = {
|
|
5
|
+
icon?: readonly {
|
|
6
|
+
media?: string;
|
|
7
|
+
sizes?: string;
|
|
8
|
+
type?: string;
|
|
9
|
+
url: string;
|
|
10
|
+
}[];
|
|
11
|
+
apple?: readonly {
|
|
12
|
+
sizes?: string;
|
|
13
|
+
type?: string;
|
|
14
|
+
url: string;
|
|
15
|
+
}[];
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const generated = faviconsAndLogos.metadataIcons as GeneratedMetadataIcons;
|
|
19
|
+
|
|
20
|
+
export const metadataIcons = Object.keys(generated).length
|
|
21
|
+
? ({
|
|
22
|
+
...(generated.icon ? { icon: [...generated.icon] } : {}),
|
|
23
|
+
...(generated.apple ? { apple: [...generated.apple] } : {}),
|
|
24
|
+
} satisfies Metadata["icons"])
|
|
25
|
+
: undefined;
|
|
26
|
+
|
|
27
|
+
/** Global errors bypass Next's layout metadata but use the same resolved icons. */
|
|
28
|
+
export function MetadataIcons() {
|
|
29
|
+
return (
|
|
30
|
+
<>
|
|
31
|
+
{metadataIcons?.icon?.map(({ url, ...attributes }) => (
|
|
32
|
+
<link href={url} key={url} rel="icon" {...attributes} />
|
|
33
|
+
))}
|
|
34
|
+
{metadataIcons?.apple?.map(({ url, ...attributes }) => (
|
|
35
|
+
<link href={url} key={url} rel="apple-touch-icon" {...attributes} />
|
|
36
|
+
))}
|
|
37
|
+
</>
|
|
38
|
+
);
|
|
39
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { Link } from "@components/ui/link";
|
|
2
|
+
import type { NotFoundScope } from "@publish.os/nextjs/kernel/routes/not-found";
|
|
3
|
+
|
|
4
|
+
export default function NotFoundContent({ scope }: { scope: NotFoundScope }) {
|
|
5
|
+
const sections = [
|
|
6
|
+
{ title: "Recommendations", links: scope.recommendations },
|
|
7
|
+
{ title: "For crawlers and agents", links: scope.indexes },
|
|
8
|
+
];
|
|
9
|
+
return (
|
|
10
|
+
<section
|
|
11
|
+
className="mx-auto flex w-full max-w-xl flex-1 flex-col items-center justify-center px-6 py-16 font-main sm:px-8 sm:py-24"
|
|
12
|
+
data-publishos-not-found={scope.id}
|
|
13
|
+
>
|
|
14
|
+
<h1 className="text-center font-mono text-8xl leading-none font-medium tracking-tight text-foreground-1 sm:text-9xl">
|
|
15
|
+
404<span className="sr-only"> — Page not found</span>
|
|
16
|
+
</h1>
|
|
17
|
+
<p className="mt-6 max-w-md text-center text-sm leading-6 text-pretty text-foreground-3">
|
|
18
|
+
This page does not exist. Please check the URL and try again.
|
|
19
|
+
</p>
|
|
20
|
+
<div className="mt-10 w-full space-y-8">
|
|
21
|
+
{sections.map(({ title, links }) =>
|
|
22
|
+
links.length ? (
|
|
23
|
+
<section aria-label={title} key={title}>
|
|
24
|
+
<h2 className="text-xs font-medium text-foreground-3">{title}</h2>
|
|
25
|
+
<ul className="mt-2 space-y-0">
|
|
26
|
+
{links.map((link) => (
|
|
27
|
+
<li className="flex items-baseline gap-3" key={link.href}>
|
|
28
|
+
<span
|
|
29
|
+
aria-hidden="true"
|
|
30
|
+
className="shrink-0 text-sm text-foreground-3"
|
|
31
|
+
>
|
|
32
|
+
-
|
|
33
|
+
</span>
|
|
34
|
+
<Link
|
|
35
|
+
className="inline-flex min-h-10 min-w-0 max-w-full items-center py-1 text-start wrap-anywhere"
|
|
36
|
+
href={link.href}
|
|
37
|
+
prefetch={false}
|
|
38
|
+
size="sm"
|
|
39
|
+
target="_self"
|
|
40
|
+
variant="link.inline"
|
|
41
|
+
>
|
|
42
|
+
{link.title}
|
|
43
|
+
</Link>
|
|
44
|
+
</li>
|
|
45
|
+
))}
|
|
46
|
+
</ul>
|
|
47
|
+
</section>
|
|
48
|
+
) : null,
|
|
49
|
+
)}
|
|
50
|
+
</div>
|
|
51
|
+
</section>
|
|
52
|
+
);
|
|
53
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import type { MouseEvent, ReactNode } from "react";
|
|
4
|
+
|
|
5
|
+
/** Next's routing-level error document has no app-router tree to navigate from. */
|
|
6
|
+
export default function NotFoundNavigation({
|
|
7
|
+
children,
|
|
8
|
+
}: {
|
|
9
|
+
children: ReactNode;
|
|
10
|
+
}) {
|
|
11
|
+
function navigate(event: MouseEvent<HTMLDivElement>) {
|
|
12
|
+
if (
|
|
13
|
+
event.defaultPrevented ||
|
|
14
|
+
event.button !== 0 ||
|
|
15
|
+
event.altKey ||
|
|
16
|
+
event.ctrlKey ||
|
|
17
|
+
event.metaKey ||
|
|
18
|
+
event.shiftKey
|
|
19
|
+
)
|
|
20
|
+
return;
|
|
21
|
+
|
|
22
|
+
const target = event.target as Node;
|
|
23
|
+
const element =
|
|
24
|
+
target.nodeType === 1 ? (target as Element) : target.parentElement;
|
|
25
|
+
const link = element?.closest<HTMLAnchorElement>("a[href]");
|
|
26
|
+
const view = event.currentTarget.ownerDocument.defaultView;
|
|
27
|
+
if (
|
|
28
|
+
!link ||
|
|
29
|
+
!view ||
|
|
30
|
+
link.hasAttribute("download") ||
|
|
31
|
+
(link.target && link.target !== "_self")
|
|
32
|
+
)
|
|
33
|
+
return;
|
|
34
|
+
|
|
35
|
+
let destination: URL;
|
|
36
|
+
try {
|
|
37
|
+
destination = new URL(link.href, view.location.href);
|
|
38
|
+
} catch {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
if (
|
|
42
|
+
!["http:", "https:"].includes(destination.protocol) ||
|
|
43
|
+
destination.origin !== view.location.origin ||
|
|
44
|
+
(destination.pathname === view.location.pathname &&
|
|
45
|
+
destination.search === view.location.search &&
|
|
46
|
+
destination.hash)
|
|
47
|
+
)
|
|
48
|
+
return;
|
|
49
|
+
|
|
50
|
+
event.preventDefault();
|
|
51
|
+
event.stopPropagation();
|
|
52
|
+
view.location.assign(destination.href);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return (
|
|
56
|
+
<div className="contents" onClickCapture={navigate}>
|
|
57
|
+
{children}
|
|
58
|
+
</div>
|
|
59
|
+
);
|
|
60
|
+
}
|
|
@@ -1,14 +1,19 @@
|
|
|
1
|
+
import { isMarkdownClient } from "@app/agent-user-agents";
|
|
2
|
+
import {
|
|
3
|
+
createNotFoundTextResponse,
|
|
4
|
+
resolveNotFoundScope,
|
|
5
|
+
} from "@publish.os/nextjs/kernel/routes/not-found";
|
|
1
6
|
import { agentRouteConfig } from "@source/.publishos/agent-route-config.generated";
|
|
2
7
|
import type { NextRequest } from "next/server";
|
|
3
8
|
import { NextResponse } from "next/server";
|
|
4
9
|
|
|
5
|
-
const AGENT_USER_AGENT_PATTERN =
|
|
6
|
-
/\b(?:axios|got|node-fetch|undici|curl|wget|python-requests|httpx|aiohttp|claude-code|claudebot|claude|cursor|chatgpt|openai|perplexity|anthropic-ai)\b/i;
|
|
7
10
|
const INTERNAL_MARKDOWN_PREFIX = "/__publishos/md";
|
|
8
11
|
const FRAMEWORK_PREFIX = "__PUBLISHOS_FRAMEWORK_PREFIX__";
|
|
9
|
-
const PUBLIC_FILE_PATTERN = /\.[a-z0-9]{1,12}$/i;
|
|
10
12
|
const TEXT_METHODS = new Set(["GET", "HEAD"]);
|
|
11
13
|
const PUBLIC_PATHS = new Set<string>(agentRouteConfig.publicPaths);
|
|
14
|
+
const MARKDOWN_PATHS = new Set<string>(agentRouteConfig.markdownPaths);
|
|
15
|
+
const OUTPUT_PATHS = new Set<string>(agentRouteConfig.outputPaths);
|
|
16
|
+
const NOT_FOUND_SCOPE_HEADER = "x-publishos-not-found-scope";
|
|
12
17
|
|
|
13
18
|
function debugAgentRoute(
|
|
14
19
|
event: string,
|
|
@@ -30,11 +35,15 @@ function normalizePagePath(pathname: string): string {
|
|
|
30
35
|
return pathname.replace(/\/+$/, "");
|
|
31
36
|
}
|
|
32
37
|
|
|
33
|
-
function markdownRoutePath(
|
|
38
|
+
function markdownRoutePath(
|
|
39
|
+
pathname: string,
|
|
40
|
+
reason: "accept" | "extension",
|
|
41
|
+
): string {
|
|
34
42
|
const normalized = normalizePagePath(pathname);
|
|
35
|
-
const pagePath =
|
|
36
|
-
|
|
37
|
-
|
|
43
|
+
const pagePath =
|
|
44
|
+
reason === "extension" && normalized.endsWith(".md")
|
|
45
|
+
? normalized.slice(0, -".md".length)
|
|
46
|
+
: normalized;
|
|
38
47
|
return pagePath === "/"
|
|
39
48
|
? INTERNAL_MARKDOWN_PREFIX
|
|
40
49
|
: `${INTERNAL_MARKDOWN_PREFIX}${pagePath}`;
|
|
@@ -45,36 +54,21 @@ function markdownAlternatePath(pathname: string): string {
|
|
|
45
54
|
if (normalized === "/") {
|
|
46
55
|
return agentRouteConfig.discoveryLinks.sitemap ?? "/sitemap.md";
|
|
47
56
|
}
|
|
48
|
-
return
|
|
57
|
+
return `${normalized}.md`;
|
|
49
58
|
}
|
|
50
59
|
|
|
51
|
-
function
|
|
52
|
-
|
|
53
|
-
agentRouteConfig.discoveryLinks.
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
agentRouteConfig.discoveryLinks.sitemap
|
|
57
|
-
? `> Sitemap: ${agentRouteConfig.discoveryLinks.sitemap}`
|
|
58
|
-
: undefined,
|
|
59
|
-
agentRouteConfig.discoveryLinks.llms
|
|
60
|
-
? `> LLMS index: ${agentRouteConfig.discoveryLinks.llms}`
|
|
61
|
-
: undefined,
|
|
62
|
-
].filter((line): line is string => Boolean(line));
|
|
63
|
-
|
|
64
|
-
return [
|
|
65
|
-
"# Not found",
|
|
66
|
-
"",
|
|
67
|
-
...links,
|
|
68
|
-
"",
|
|
69
|
-
"The requested Markdown page was not found.",
|
|
70
|
-
"",
|
|
71
|
-
].join("\n");
|
|
60
|
+
function rootMarkdownSitemapPath(requestUrl: URL): string {
|
|
61
|
+
return new URL(
|
|
62
|
+
agentRouteConfig.discoveryLinks.sitemap ?? "/sitemap.md",
|
|
63
|
+
requestUrl,
|
|
64
|
+
).pathname;
|
|
72
65
|
}
|
|
73
66
|
|
|
74
67
|
function explicitAcceptQuality(accept: string, mimeType: string): number {
|
|
75
|
-
if (!accept) return
|
|
68
|
+
if (!accept.trim()) return 1;
|
|
76
69
|
|
|
77
70
|
const [targetType, targetSubtype] = mimeType.toLowerCase().split("/");
|
|
71
|
+
let bestSpecificity = -1;
|
|
78
72
|
let bestQuality = 0;
|
|
79
73
|
|
|
80
74
|
for (const entry of accept.split(",")) {
|
|
@@ -86,63 +80,131 @@ function explicitAcceptQuality(accept: string, mimeType: string): number {
|
|
|
86
80
|
if (!rawType) continue;
|
|
87
81
|
|
|
88
82
|
const [type, subtype] = rawType.split("/");
|
|
89
|
-
|
|
83
|
+
const specificity =
|
|
84
|
+
type === targetType && subtype === targetSubtype
|
|
85
|
+
? 2
|
|
86
|
+
: type === targetType && subtype === "*"
|
|
87
|
+
? 1
|
|
88
|
+
: type === "*" && subtype === "*"
|
|
89
|
+
? 0
|
|
90
|
+
: -1;
|
|
91
|
+
if (specificity < 0) continue;
|
|
90
92
|
|
|
91
93
|
let quality = 1;
|
|
92
94
|
for (const param of rawParams) {
|
|
93
95
|
const [key, value] = param.split("=").map((part) => part.trim());
|
|
94
96
|
if (key !== "q") continue;
|
|
95
|
-
const parsed = Number
|
|
96
|
-
quality =
|
|
97
|
+
const parsed = Number(value);
|
|
98
|
+
quality =
|
|
99
|
+
Number.isFinite(parsed) && parsed >= 0 && parsed <= 1 ? parsed : 0;
|
|
97
100
|
}
|
|
98
101
|
|
|
99
|
-
if (
|
|
102
|
+
if (specificity > bestSpecificity) {
|
|
103
|
+
bestSpecificity = specificity;
|
|
104
|
+
bestQuality = quality;
|
|
105
|
+
} else if (specificity === bestSpecificity) {
|
|
106
|
+
bestQuality = Math.max(bestQuality, quality);
|
|
107
|
+
}
|
|
100
108
|
}
|
|
101
109
|
|
|
102
110
|
return bestQuality;
|
|
103
111
|
}
|
|
104
112
|
|
|
105
|
-
function
|
|
113
|
+
function negotiatedTextType(
|
|
114
|
+
request: NextRequest,
|
|
115
|
+
): "text/markdown; charset=utf-8" | "text/html; charset=utf-8" | undefined {
|
|
116
|
+
const accept = request.headers.get("accept") ?? "";
|
|
117
|
+
const markdownQuality = agentRouteConfig.markdownAccept
|
|
118
|
+
? explicitAcceptQuality(accept, "text/markdown")
|
|
119
|
+
: 0;
|
|
120
|
+
const htmlQuality = explicitAcceptQuality(accept, "text/html");
|
|
121
|
+
|
|
122
|
+
if (markdownQuality === 0 && htmlQuality === 0) return undefined;
|
|
123
|
+
if (markdownQuality > htmlQuality) return "text/markdown; charset=utf-8";
|
|
124
|
+
if (markdownQuality < htmlQuality) return "text/html; charset=utf-8";
|
|
125
|
+
if (looksLikeAgent(request)) return "text/markdown; charset=utf-8";
|
|
126
|
+
return htmlQuality > 0 && markdownQuality > 0
|
|
127
|
+
? "text/html; charset=utf-8"
|
|
128
|
+
: undefined;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function negotiatedPlainNotFound(request: NextRequest): boolean {
|
|
106
132
|
if (!TEXT_METHODS.has(request.method)) return false;
|
|
107
133
|
|
|
108
134
|
const accept = request.headers.get("accept") ?? "";
|
|
135
|
+
const plainQuality = explicitAcceptQuality(accept, "text/plain");
|
|
109
136
|
const markdownQuality = agentRouteConfig.markdownAccept
|
|
110
137
|
? explicitAcceptQuality(accept, "text/markdown")
|
|
111
138
|
: 0;
|
|
112
|
-
const plainQuality = agentRouteConfig.plainTextAccept
|
|
113
|
-
? explicitAcceptQuality(accept, "text/plain")
|
|
114
|
-
: 0;
|
|
115
139
|
const htmlQuality = explicitAcceptQuality(accept, "text/html");
|
|
116
140
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
return true;
|
|
120
|
-
}
|
|
141
|
+
return plainQuality > Math.max(markdownQuality, htmlQuality);
|
|
142
|
+
}
|
|
121
143
|
|
|
122
|
-
|
|
144
|
+
function removeDisabledDiscoveryHeaders(response: Response): Response {
|
|
145
|
+
if (!agentRouteConfig.enabled || !agentRouteConfig.discoveryHeaders) {
|
|
146
|
+
for (const name of ["link", "x-publishos-llms", "x-publishos-sitemap"])
|
|
147
|
+
response.headers.delete(name);
|
|
148
|
+
}
|
|
149
|
+
return response;
|
|
123
150
|
}
|
|
124
151
|
|
|
125
152
|
function looksLikeAgent(request: NextRequest): boolean {
|
|
126
153
|
if (!TEXT_METHODS.has(request.method)) return false;
|
|
127
154
|
if (!agentRouteConfig.agentDetection) return false;
|
|
128
|
-
|
|
129
|
-
|
|
155
|
+
return isMarkdownClient(request.headers.get("user-agent") ?? "");
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function mergeVary(response: Response, values: string[]): void {
|
|
159
|
+
const existing = (response.headers.get("vary") ?? "")
|
|
160
|
+
.split(",")
|
|
161
|
+
.map((value) => value.trim())
|
|
162
|
+
.filter(Boolean);
|
|
163
|
+
if (existing.some((value) => value === "*")) return;
|
|
164
|
+
const merged = [...existing];
|
|
165
|
+
for (const value of values) {
|
|
166
|
+
if (!merged.some((item) => item.toLowerCase() === value.toLowerCase()))
|
|
167
|
+
merged.push(value);
|
|
130
168
|
}
|
|
131
|
-
|
|
169
|
+
if (merged.length) response.headers.set("vary", merged.join(", "));
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function negotiationVary(): string[] {
|
|
173
|
+
if (!agentRouteConfig.enabled || !agentRouteConfig.markdownAccept) return [];
|
|
174
|
+
return ["Accept", ...(agentRouteConfig.agentDetection ? ["User-Agent"] : [])];
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
function isNextNavigationRequest(request: NextRequest): boolean {
|
|
178
|
+
return [
|
|
179
|
+
"rsc",
|
|
180
|
+
"next-router-prefetch",
|
|
181
|
+
"next-router-state-tree",
|
|
182
|
+
"next-router-segment-prefetch",
|
|
183
|
+
].some((name) => request.headers.has(name));
|
|
132
184
|
}
|
|
133
185
|
|
|
134
186
|
function markdownRequestReason(
|
|
135
187
|
request: NextRequest,
|
|
136
|
-
): "accept" | "
|
|
188
|
+
): "accept" | "extension" | undefined {
|
|
137
189
|
if (!agentRouteConfig.enabled) return undefined;
|
|
190
|
+
if (!TEXT_METHODS.has(request.method) || isNextNavigationRequest(request))
|
|
191
|
+
return undefined;
|
|
138
192
|
if (
|
|
139
193
|
agentRouteConfig.markdownRoutes &&
|
|
140
194
|
request.nextUrl.pathname.endsWith(".md")
|
|
141
195
|
) {
|
|
142
|
-
|
|
196
|
+
let decoded: string;
|
|
197
|
+
try {
|
|
198
|
+
decoded = normalizePagePath(
|
|
199
|
+
decodeURIComponent(request.nextUrl.pathname),
|
|
200
|
+
).normalize("NFC");
|
|
201
|
+
} catch {
|
|
202
|
+
decoded = request.nextUrl.pathname;
|
|
203
|
+
}
|
|
204
|
+
if (!PUBLIC_PATHS.has(decoded)) return "extension";
|
|
143
205
|
}
|
|
144
|
-
|
|
145
|
-
if (
|
|
206
|
+
const selectedType = negotiatedTextType(request);
|
|
207
|
+
if (selectedType === "text/markdown; charset=utf-8") return "accept";
|
|
146
208
|
return undefined;
|
|
147
209
|
}
|
|
148
210
|
|
|
@@ -154,6 +216,7 @@ function isInternalMarkdownRoute(pathname: string): boolean {
|
|
|
154
216
|
}
|
|
155
217
|
|
|
156
218
|
function isStaticOrMetadataRoute(pathname: string): boolean {
|
|
219
|
+
if (OUTPUT_PATHS.has(normalizePagePath(pathname))) return true;
|
|
157
220
|
if (
|
|
158
221
|
pathname === FRAMEWORK_PREFIX ||
|
|
159
222
|
pathname.startsWith(`${FRAMEWORK_PREFIX}/`) ||
|
|
@@ -175,21 +238,29 @@ function isStaticOrMetadataRoute(pathname: string): boolean {
|
|
|
175
238
|
return true;
|
|
176
239
|
}
|
|
177
240
|
|
|
178
|
-
return
|
|
241
|
+
return false;
|
|
179
242
|
}
|
|
180
243
|
|
|
181
|
-
function rewriteToMarkdown(
|
|
182
|
-
request
|
|
183
|
-
reason
|
|
184
|
-
|
|
185
|
-
|
|
244
|
+
function rewriteToMarkdown({
|
|
245
|
+
request,
|
|
246
|
+
reason,
|
|
247
|
+
requestHeaders,
|
|
248
|
+
}: {
|
|
249
|
+
request: NextRequest;
|
|
250
|
+
reason: "accept" | "extension";
|
|
251
|
+
requestHeaders: Headers;
|
|
252
|
+
}): NextResponse {
|
|
253
|
+
const url = new URL(request.url);
|
|
186
254
|
url.pathname =
|
|
187
255
|
normalizePagePath(url.pathname) === "/"
|
|
188
|
-
?
|
|
189
|
-
: markdownRoutePath(url.pathname);
|
|
256
|
+
? rootMarkdownSitemapPath(url)
|
|
257
|
+
: markdownRoutePath(url.pathname, reason);
|
|
258
|
+
const revision = request.nextUrl.searchParams.get("publishos_revision");
|
|
259
|
+
url.search = "";
|
|
260
|
+
url.hash = "";
|
|
261
|
+
if (revision) url.searchParams.set("publishos_revision", revision);
|
|
190
262
|
|
|
191
|
-
|
|
192
|
-
requestHeaders.set("x-publishos-agent-route", "markdown");
|
|
263
|
+
requestHeaders.set("accept", "text/markdown");
|
|
193
264
|
|
|
194
265
|
debugAgentRoute("md", {
|
|
195
266
|
accept: request.headers.get("accept") ?? undefined,
|
|
@@ -200,20 +271,25 @@ function rewriteToMarkdown(
|
|
|
200
271
|
userAgent: request.headers.get("user-agent") ?? undefined,
|
|
201
272
|
});
|
|
202
273
|
|
|
203
|
-
|
|
274
|
+
const response = NextResponse.rewrite(url, {
|
|
204
275
|
request: {
|
|
205
276
|
headers: requestHeaders,
|
|
206
277
|
},
|
|
207
278
|
});
|
|
279
|
+
if (reason !== "extension") mergeVary(response, negotiationVary());
|
|
280
|
+
return response;
|
|
208
281
|
}
|
|
209
282
|
|
|
210
283
|
function withDiscoveryHeaders(
|
|
211
284
|
response: NextResponse,
|
|
212
285
|
pathname: string,
|
|
213
286
|
): NextResponse {
|
|
287
|
+
mergeVary(response, negotiationVary());
|
|
214
288
|
const markdownUrl = markdownAlternatePath(pathname);
|
|
215
289
|
const links = [
|
|
216
|
-
|
|
290
|
+
agentRouteConfig.markdownRoutes
|
|
291
|
+
? `<${markdownUrl}>; rel="alternate"; type="text/markdown"`
|
|
292
|
+
: undefined,
|
|
217
293
|
agentRouteConfig.discoveryLinks.llms
|
|
218
294
|
? `<${agentRouteConfig.discoveryLinks.llms}>; rel="llms-txt"; type="text/plain"`
|
|
219
295
|
: undefined,
|
|
@@ -221,8 +297,9 @@ function withDiscoveryHeaders(
|
|
|
221
297
|
? `<${agentRouteConfig.discoveryLinks.sitemap}>; rel="alternate"; type="text/markdown"; title="Markdown sitemap"`
|
|
222
298
|
: undefined,
|
|
223
299
|
].filter((link): link is string => Boolean(link));
|
|
224
|
-
response.headers.set("link", links.join(", "));
|
|
225
|
-
|
|
300
|
+
if (links.length) response.headers.set("link", links.join(", "));
|
|
301
|
+
if (agentRouteConfig.markdownRoutes)
|
|
302
|
+
response.headers.set("x-publishos-markdown", markdownUrl);
|
|
226
303
|
if (agentRouteConfig.discoveryLinks.llms) {
|
|
227
304
|
response.headers.set(
|
|
228
305
|
"x-publishos-llms",
|
|
@@ -241,20 +318,28 @@ function withDiscoveryHeaders(
|
|
|
241
318
|
|
|
242
319
|
export function proxy(request: NextRequest) {
|
|
243
320
|
const { pathname } = request.nextUrl;
|
|
321
|
+
const requestHeaders = new Headers(request.headers);
|
|
322
|
+
requestHeaders.delete(NOT_FOUND_SCOPE_HEADER);
|
|
323
|
+
requestHeaders.delete("x-publishos-agent-route");
|
|
244
324
|
|
|
245
|
-
if (pathname === "/_not-found")
|
|
325
|
+
if (pathname === "/_not-found") {
|
|
326
|
+
requestHeaders.set(NOT_FOUND_SCOPE_HEADER, "none");
|
|
327
|
+
const response = NextResponse.next({
|
|
328
|
+
request: { headers: requestHeaders },
|
|
329
|
+
});
|
|
330
|
+
response.headers.set("x-robots-tag", "noindex");
|
|
331
|
+
response.headers.set("vary", "Accept, User-Agent");
|
|
332
|
+
return response;
|
|
333
|
+
}
|
|
246
334
|
|
|
247
335
|
if (isInternalMarkdownRoute(pathname)) {
|
|
248
|
-
if (request.headers.get("x-publishos-agent-route") === "markdown") {
|
|
249
|
-
return NextResponse.next();
|
|
250
|
-
}
|
|
251
336
|
if (!agentRouteConfig.blockInternalMarkdownRoute) {
|
|
252
337
|
debugAgentRoute("pass", {
|
|
253
338
|
method: request.method,
|
|
254
339
|
path: pathname,
|
|
255
340
|
reason: "allowed-internal",
|
|
256
341
|
});
|
|
257
|
-
return NextResponse.next();
|
|
342
|
+
return NextResponse.next({ request: { headers: requestHeaders } });
|
|
258
343
|
}
|
|
259
344
|
|
|
260
345
|
debugAgentRoute("md", {
|
|
@@ -264,15 +349,7 @@ export function proxy(request: NextRequest) {
|
|
|
264
349
|
status: 404,
|
|
265
350
|
});
|
|
266
351
|
|
|
267
|
-
return
|
|
268
|
-
status: 404,
|
|
269
|
-
headers: {
|
|
270
|
-
"cache-control": "public, max-age=60, s-maxage=300",
|
|
271
|
-
"content-type": "text/markdown; charset=utf-8",
|
|
272
|
-
"x-content-type-options": "nosniff",
|
|
273
|
-
"x-robots-tag": "noindex",
|
|
274
|
-
},
|
|
275
|
-
});
|
|
352
|
+
return createNotFoundTextResponse({ method: request.method });
|
|
276
353
|
}
|
|
277
354
|
|
|
278
355
|
if (isStaticOrMetadataRoute(pathname)) {
|
|
@@ -281,25 +358,109 @@ export function proxy(request: NextRequest) {
|
|
|
281
358
|
path: pathname,
|
|
282
359
|
reason: "static-or-metadata",
|
|
283
360
|
});
|
|
284
|
-
return NextResponse.next();
|
|
361
|
+
return NextResponse.next({ request: { headers: requestHeaders } });
|
|
285
362
|
}
|
|
286
363
|
|
|
287
364
|
const markdownReason = markdownRequestReason(request);
|
|
288
365
|
if (markdownReason) {
|
|
289
|
-
|
|
366
|
+
let htmlPath: string | undefined;
|
|
367
|
+
try {
|
|
368
|
+
const decoded = normalizePagePath(decodeURIComponent(pathname)).normalize(
|
|
369
|
+
"NFC",
|
|
370
|
+
);
|
|
371
|
+
htmlPath =
|
|
372
|
+
markdownReason === "extension" && decoded.endsWith(".md")
|
|
373
|
+
? decoded.slice(0, -3) || "/"
|
|
374
|
+
: decoded;
|
|
375
|
+
} catch {
|
|
376
|
+
htmlPath = undefined;
|
|
377
|
+
}
|
|
378
|
+
const scope = resolveNotFoundScope({
|
|
379
|
+
scopes: agentRouteConfig.notFoundScopes,
|
|
380
|
+
pathname,
|
|
381
|
+
});
|
|
382
|
+
const hasArtifact =
|
|
383
|
+
htmlPath === "/"
|
|
384
|
+
? OUTPUT_PATHS.has(rootMarkdownSitemapPath(new URL(request.url)))
|
|
385
|
+
: htmlPath !== undefined && MARKDOWN_PATHS.has(htmlPath);
|
|
386
|
+
if (!scope || !hasArtifact) {
|
|
387
|
+
const response = createNotFoundTextResponse({
|
|
388
|
+
scope,
|
|
389
|
+
pathname,
|
|
390
|
+
method: request.method,
|
|
391
|
+
contentType:
|
|
392
|
+
markdownReason === "accept" ? negotiatedTextType(request) : undefined,
|
|
393
|
+
vary: markdownReason !== "extension",
|
|
394
|
+
});
|
|
395
|
+
return removeDisabledDiscoveryHeaders(response);
|
|
396
|
+
}
|
|
397
|
+
return rewriteToMarkdown({
|
|
398
|
+
request,
|
|
399
|
+
reason: markdownReason,
|
|
400
|
+
requestHeaders,
|
|
401
|
+
});
|
|
290
402
|
}
|
|
291
403
|
|
|
292
404
|
let pagePath: string;
|
|
293
405
|
try {
|
|
294
|
-
pagePath = normalizePagePath(decodeURIComponent(pathname));
|
|
406
|
+
pagePath = normalizePagePath(decodeURIComponent(pathname)).normalize("NFC");
|
|
295
407
|
} catch {
|
|
296
408
|
pagePath = pathname;
|
|
297
409
|
}
|
|
298
410
|
if (!PUBLIC_PATHS.has(pagePath)) {
|
|
299
|
-
//
|
|
300
|
-
const
|
|
411
|
+
// Select Next's error route before an unknown catch-all can stream.
|
|
412
|
+
const scope = resolveNotFoundScope({
|
|
413
|
+
scopes: agentRouteConfig.notFoundScopes,
|
|
414
|
+
pathname,
|
|
415
|
+
});
|
|
416
|
+
if (negotiatedPlainNotFound(request)) {
|
|
417
|
+
return removeDisabledDiscoveryHeaders(
|
|
418
|
+
createNotFoundTextResponse({
|
|
419
|
+
scope,
|
|
420
|
+
pathname,
|
|
421
|
+
method: request.method,
|
|
422
|
+
contentType: "text/plain; charset=utf-8",
|
|
423
|
+
vary: true,
|
|
424
|
+
}),
|
|
425
|
+
);
|
|
426
|
+
}
|
|
427
|
+
requestHeaders.set(NOT_FOUND_SCOPE_HEADER, scope?.id ?? "none");
|
|
428
|
+
const url = new URL(request.url);
|
|
301
429
|
url.pathname = "/_not-found";
|
|
302
|
-
|
|
430
|
+
url.search = "";
|
|
431
|
+
url.hash = "";
|
|
432
|
+
const response = NextResponse.rewrite(url, {
|
|
433
|
+
status: 404,
|
|
434
|
+
request: { headers: requestHeaders },
|
|
435
|
+
});
|
|
436
|
+
const recoveryHeaders = createNotFoundTextResponse({
|
|
437
|
+
scope,
|
|
438
|
+
pathname,
|
|
439
|
+
method: request.method,
|
|
440
|
+
vary: true,
|
|
441
|
+
}).headers;
|
|
442
|
+
for (const name of [
|
|
443
|
+
"x-robots-tag",
|
|
444
|
+
"vary",
|
|
445
|
+
...(agentRouteConfig.enabled && agentRouteConfig.discoveryHeaders
|
|
446
|
+
? ["link", "x-publishos-llms", "x-publishos-sitemap"]
|
|
447
|
+
: []),
|
|
448
|
+
]) {
|
|
449
|
+
const value = recoveryHeaders.get(name);
|
|
450
|
+
if (value) response.headers.set(name, value);
|
|
451
|
+
}
|
|
452
|
+
return response;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
if (
|
|
456
|
+
agentRouteConfig.enabled &&
|
|
457
|
+
TEXT_METHODS.has(request.method) &&
|
|
458
|
+
!isNextNavigationRequest(request) &&
|
|
459
|
+
!negotiatedTextType(request)
|
|
460
|
+
) {
|
|
461
|
+
const response = new NextResponse(null, { status: 406 });
|
|
462
|
+
mergeVary(response, negotiationVary());
|
|
463
|
+
return response;
|
|
303
464
|
}
|
|
304
465
|
|
|
305
466
|
if (!agentRouteConfig.enabled || !agentRouteConfig.discoveryHeaders) {
|
|
@@ -310,7 +471,11 @@ export function proxy(request: NextRequest) {
|
|
|
310
471
|
? "discovery-disabled"
|
|
311
472
|
: "agent-routes-disabled",
|
|
312
473
|
});
|
|
313
|
-
|
|
474
|
+
const response = NextResponse.next({
|
|
475
|
+
request: { headers: requestHeaders },
|
|
476
|
+
});
|
|
477
|
+
mergeVary(response, negotiationVary());
|
|
478
|
+
return response;
|
|
314
479
|
}
|
|
315
480
|
|
|
316
481
|
debugAgentRoute("html", {
|
|
@@ -321,7 +486,10 @@ export function proxy(request: NextRequest) {
|
|
|
321
486
|
userAgent: request.headers.get("user-agent") ?? undefined,
|
|
322
487
|
});
|
|
323
488
|
|
|
324
|
-
return withDiscoveryHeaders(
|
|
489
|
+
return withDiscoveryHeaders(
|
|
490
|
+
NextResponse.next({ request: { headers: requestHeaders } }),
|
|
491
|
+
pathname,
|
|
492
|
+
);
|
|
325
493
|
}
|
|
326
494
|
|
|
327
495
|
export const config = {
|
|
@@ -1,9 +1,5 @@
|
|
|
1
1
|
import { CodeBlock } from "@components/mdx/code-block";
|
|
2
|
-
import {
|
|
3
|
-
type ComponentPropsWithoutRef,
|
|
4
|
-
isValidElement,
|
|
5
|
-
type ReactNode,
|
|
6
|
-
} from "react";
|
|
2
|
+
import { type HTMLAttributes, isValidElement, type ReactNode } from "react";
|
|
7
3
|
|
|
8
4
|
type CodeChildProps = {
|
|
9
5
|
children?: ReactNode;
|
|
@@ -15,7 +11,7 @@ export function FencedCodeBlock({
|
|
|
15
11
|
children,
|
|
16
12
|
title,
|
|
17
13
|
...props
|
|
18
|
-
}:
|
|
14
|
+
}: HTMLAttributes<HTMLElement>) {
|
|
19
15
|
const codeElement = isValidElement<CodeChildProps>(children)
|
|
20
16
|
? children
|
|
21
17
|
: null;
|