@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.
Files changed (284) hide show
  1. package/compiler-assets/nextjs/defaults/group/index.tsx +16 -11
  2. package/compiler-assets/nextjs/defaults/group/layout.tsx +6 -6
  3. package/compiler-assets/nextjs/defaults/group/page.tsx +36 -26
  4. package/compiler-assets/nextjs/defaults/project/next.config.mjs +21 -11
  5. package/compiler-assets/nextjs/defaults/project/tsconfig.json.template +10 -0
  6. package/compiler-assets/nextjs/defaults/root/css/components/code-block.css +18 -0
  7. package/compiler-assets/nextjs/defaults/root/index.tsx +16 -11
  8. package/compiler-assets/nextjs/defaults/root/layout.tsx +7 -3
  9. package/compiler-assets/nextjs/shims/agent-user-agents.ts +65 -0
  10. package/compiler-assets/nextjs/shims/document.tsx +46 -0
  11. package/compiler-assets/nextjs/shims/generated-leaf-page.tsx +5 -0
  12. package/compiler-assets/nextjs/shims/global-layout.tsx +8 -42
  13. package/compiler-assets/nextjs/shims/global-not-found.tsx +69 -0
  14. package/compiler-assets/nextjs/shims/markdown-route.ts +2 -0
  15. package/compiler-assets/nextjs/shims/metadata-icons.tsx +39 -0
  16. package/compiler-assets/nextjs/shims/not-found-content.tsx +53 -0
  17. package/compiler-assets/nextjs/shims/not-found-navigation.tsx +60 -0
  18. package/compiler-assets/nextjs/shims/proxy.ts +254 -86
  19. package/compiler-assets/nextjs/shims/site-fenced-code-block.tsx +2 -6
  20. package/compiler-assets/nextjs/shims/site-mdx-components.tsx +28 -16
  21. package/compiler-assets/nextjs/shims/site-mdx.tsx +6 -1
  22. package/dist/{build-operation-2JAYBSKF.js → build-operation-CJDUL4OW.js} +29 -23
  23. package/dist/{button-c3WGnxIj.d.ts → button-D6Xp2HBm.d.ts} +4 -4
  24. package/dist/capture-local-source-WGGDIUU2.js +258 -0
  25. package/dist/chunk-22RSSUNV.js +13 -0
  26. package/dist/chunk-3T4HVDSC.js +426 -0
  27. package/dist/{chunk-WKTEO6RS.js → chunk-4BC2L2KA.js} +46 -12
  28. package/dist/{chunk-WDY4IK6Z.js → chunk-5J3YUNRY.js} +3 -10
  29. package/dist/chunk-5KAD7W53.js +248 -0
  30. package/dist/{chunk-DWA3ZRGW.js → chunk-6C65KV7O.js} +2 -2
  31. package/dist/{chunk-GGKFQ3MA.js → chunk-6D2E6UMD.js} +144 -70
  32. package/dist/{chunk-7OGTPSKI.js → chunk-7NY22B5U.js} +8 -3
  33. package/dist/chunk-DX7PXFCM.js +2519 -0
  34. package/dist/{chunk-726GV2NF.js → chunk-DZ3VWEV5.js} +950 -632
  35. package/dist/chunk-EFO6AWXN.js +19 -0
  36. package/dist/chunk-IL4RJOKI.js +186 -0
  37. package/dist/{chunk-H6XILMZX.js → chunk-NHSLTARU.js} +2588 -1493
  38. package/dist/{chunk-DLDFHU7Y.js → chunk-NNBJZPFM.js} +4 -2
  39. package/dist/{chunk-VO2I7MTM.js → chunk-SBMDONTV.js} +10 -7
  40. package/dist/{chunk-YLTOLYWM.js → chunk-WL75GQ5M.js} +6 -18
  41. package/dist/compiler.d.ts +15 -2
  42. package/dist/compiler.js +111 -23
  43. package/dist/components/blocks/agent-actions.d.ts +81 -0
  44. package/dist/components/blocks/agent-actions.js +563 -0
  45. package/dist/components/blocks/toc.d.ts +43 -0
  46. package/dist/components/blocks/toc.js +136 -0
  47. package/dist/components/ui/button.d.ts +4 -0
  48. package/dist/components/ui/button.js +94 -0
  49. package/dist/compose-44GJSMXD.js +16 -0
  50. package/dist/config/createNextConfig.js +19 -3
  51. package/dist/{dev-operation-TZDVJCN7.js → dev-operation-WNECBHZ5.js} +134 -84
  52. package/dist/{framework-selection-X4U6Y6QC.js → framework-selection-ZVO323PK.js} +3 -2
  53. package/dist/ide-support-TG74L4FF.js +16 -0
  54. package/dist/index.d.ts +151 -95
  55. package/dist/index.js +25 -0
  56. package/dist/jsx-dev-runtime.d.ts +6 -0
  57. package/dist/jsx-dev-runtime.js +100 -0
  58. package/dist/jsx-runtime.d.ts +7 -0
  59. package/dist/jsx-runtime.js +97 -0
  60. package/dist/kernel/components/blocks/AgentActions.d.ts +37 -8
  61. package/dist/kernel/components/blocks/AgentActions.js +384 -174
  62. package/dist/kernel/components/blocks/agent-actions.d.ts +4 -0
  63. package/dist/kernel/components/blocks/agent-actions.js +563 -0
  64. package/dist/kernel/components/blocks/animated-icon-swap.d.ts +2 -2
  65. package/dist/kernel/components/blocks/animated-icon-swap.js +1 -1
  66. package/dist/kernel/components/blocks/color-palette.d.ts +2 -2
  67. package/dist/kernel/components/blocks/color-palette.js +4 -4
  68. package/dist/kernel/components/blocks/logo-block.d.ts +2 -2
  69. package/dist/kernel/components/blocks/logo-block.js +1 -1
  70. package/dist/kernel/components/blocks/nav-breadcrumb.d.ts +6 -5
  71. package/dist/kernel/components/blocks/nav-breadcrumb.js +21 -15
  72. package/dist/kernel/components/blocks/navbar.d.ts +5 -4
  73. package/dist/kernel/components/blocks/navbar.js +79 -59
  74. package/dist/kernel/components/blocks/navigation-progress.d.ts +2 -2
  75. package/dist/kernel/components/blocks/navigation-progress.js +2 -2
  76. package/dist/kernel/components/blocks/next-prev.d.ts +4 -4
  77. package/dist/kernel/components/blocks/next-prev.js +30 -7
  78. package/dist/kernel/components/blocks/page-list.d.ts +4 -4
  79. package/dist/kernel/components/blocks/page-list.js +32 -9
  80. package/dist/kernel/components/blocks/search.d.ts +9 -15
  81. package/dist/kernel/components/blocks/search.js +16 -17
  82. package/dist/kernel/components/blocks/sidebar-node.d.ts +3 -5
  83. package/dist/kernel/components/blocks/sidebar-node.js +13 -3
  84. package/dist/kernel/components/blocks/sidebar.d.ts +6 -7
  85. package/dist/kernel/components/blocks/sidebar.js +137 -28
  86. package/dist/kernel/components/blocks/theme-toggle.d.ts +3 -4
  87. package/dist/kernel/components/blocks/theme-toggle.js +5 -5
  88. package/dist/kernel/components/blocks/toc-client.d.ts +40 -0
  89. package/dist/kernel/components/blocks/toc-client.js +495 -0
  90. package/dist/kernel/components/blocks/toc.d.ts +20 -2
  91. package/dist/kernel/components/blocks/toc.js +121 -179
  92. package/dist/kernel/components/mdx/components/blockquote.d.ts +2 -2
  93. package/dist/kernel/components/mdx/components/blockquote.js +1 -1
  94. package/dist/kernel/components/mdx/components/callout.d.ts +3 -3
  95. package/dist/kernel/components/mdx/components/callout.js +1 -1
  96. package/dist/kernel/components/mdx/components/code-block.d.ts +2 -2
  97. package/dist/kernel/components/mdx/components/code-block.js +2 -2
  98. package/dist/kernel/components/mdx/components/copy-code-button.d.ts +2 -2
  99. package/dist/kernel/components/mdx/components/copy-code-button.js +5 -4
  100. package/dist/kernel/components/mdx/components/figure-caption.d.ts +3 -3
  101. package/dist/kernel/components/mdx/components/figure-caption.js +3 -2
  102. package/dist/kernel/components/mdx/components/figure.d.ts +8 -4
  103. package/dist/kernel/components/mdx/components/figure.js +23 -13
  104. package/dist/kernel/components/mdx/components/footnotes.d.ts +2 -2
  105. package/dist/kernel/components/mdx/components/footnotes.js +1 -1
  106. package/dist/kernel/components/mdx/components/heading-copy-link.d.ts +2 -2
  107. package/dist/kernel/components/mdx/components/heading-copy-link.js +1 -1
  108. package/dist/kernel/components/mdx/components/heading.d.ts +2 -2
  109. package/dist/kernel/components/mdx/components/heading.js +6 -3
  110. package/dist/kernel/components/mdx/components/hr.d.ts +4 -4
  111. package/dist/kernel/components/mdx/components/hr.js +2 -2
  112. package/dist/kernel/components/mdx/components/image-zoom.d.ts +3 -3
  113. package/dist/kernel/components/mdx/components/image-zoom.js +4 -3
  114. package/dist/kernel/components/mdx/components/image.d.ts +2 -2
  115. package/dist/kernel/components/mdx/components/image.js +22 -17
  116. package/dist/kernel/components/mdx/components/inline-code.d.ts +2 -2
  117. package/dist/kernel/components/mdx/components/inline-code.js +1 -1
  118. package/dist/kernel/components/mdx/components/kbd.d.ts +3 -3
  119. package/dist/kernel/components/mdx/components/kbd.js +2 -2
  120. package/dist/kernel/components/mdx/components/link.d.ts +6 -6
  121. package/dist/kernel/components/mdx/components/link.js +2 -2
  122. package/dist/kernel/components/mdx/components/paragraph.d.ts +2 -2
  123. package/dist/kernel/components/mdx/components/paragraph.js +1 -1
  124. package/dist/kernel/components/mdx/components/strikethrough.d.ts +2 -2
  125. package/dist/kernel/components/mdx/components/strikethrough.js +1 -1
  126. package/dist/kernel/components/mdx/components/table.d.ts +7 -7
  127. package/dist/kernel/components/mdx/components/table.js +2 -2
  128. package/dist/kernel/components/mdx/components/task-list.d.ts +3 -3
  129. package/dist/kernel/components/mdx/components/task-list.js +1 -1
  130. package/dist/kernel/components/mdx/components/video-player.d.ts +8 -4
  131. package/dist/kernel/components/mdx/components/video-player.js +6 -2
  132. package/dist/kernel/components/mdx/components/video.d.ts +5 -4
  133. package/dist/kernel/components/mdx/components/video.js +7 -5
  134. package/dist/kernel/components/mdx/error-boundary.d.ts +3 -4
  135. package/dist/kernel/components/mdx/error-boundary.js +2 -2
  136. package/dist/kernel/components/mdx/error-fallback.d.ts +2 -2
  137. package/dist/kernel/components/mdx/error-fallback.js +1 -1
  138. package/dist/kernel/components/mdx/mdx.d.ts +57 -16
  139. package/dist/kernel/components/mdx/mdx.js +232 -35
  140. package/dist/kernel/components/mdx/rehype-heading-ids.d.ts +1 -0
  141. package/dist/kernel/components/mdx/rehype-heading-ids.js +5 -3
  142. package/dist/kernel/components/mdx/types.d.ts +1 -1
  143. package/dist/kernel/components/next-image.d.ts +12 -0
  144. package/dist/kernel/components/next-image.js +61 -0
  145. package/dist/kernel/components/ui/accordion.d.ts +7 -7
  146. package/dist/kernel/components/ui/accordion.js +1 -1
  147. package/dist/kernel/components/ui/breadcrumb-trail.d.ts +3 -4
  148. package/dist/kernel/components/ui/breadcrumb-trail.js +2 -2
  149. package/dist/kernel/components/ui/breadcrumb.d.ts +14 -14
  150. package/dist/kernel/components/ui/breadcrumb.js +4 -4
  151. package/dist/kernel/components/ui/button-group.d.ts +6 -6
  152. package/dist/kernel/components/ui/button-group.js +3 -3
  153. package/dist/kernel/components/ui/button.d.ts +59 -7
  154. package/dist/kernel/components/ui/button.js +43 -39
  155. package/dist/kernel/components/ui/card.d.ts +7 -7
  156. package/dist/kernel/components/ui/card.js +1 -1
  157. package/dist/kernel/components/ui/dialog.d.ts +10 -10
  158. package/dist/kernel/components/ui/dialog.js +1 -1
  159. package/dist/kernel/components/ui/drawer.d.ts +12 -12
  160. package/dist/kernel/components/ui/drawer.js +1 -1
  161. package/dist/kernel/components/ui/input.d.ts +2 -2
  162. package/dist/kernel/components/ui/input.js +1 -1
  163. package/dist/kernel/components/ui/kbd.d.ts +4 -4
  164. package/dist/kernel/components/ui/kbd.js +1 -1
  165. package/dist/kernel/components/ui/link.d.ts +11 -5
  166. package/dist/kernel/components/ui/link.js +2 -2
  167. package/dist/kernel/components/ui/menu.d.ts +22 -22
  168. package/dist/kernel/components/ui/menu.js +1 -1
  169. package/dist/kernel/components/ui/mod-key.d.ts +2 -3
  170. package/dist/kernel/components/ui/mod-key.js +2 -2
  171. package/dist/kernel/components/ui/navigation-menu.d.ts +15 -15
  172. package/dist/kernel/components/ui/navigation-menu.js +1 -1
  173. package/dist/kernel/components/ui/popover.d.ts +11 -11
  174. package/dist/kernel/components/ui/popover.js +1 -1
  175. package/dist/kernel/components/ui/progress.d.ts +7 -7
  176. package/dist/kernel/components/ui/progress.js +1 -1
  177. package/dist/kernel/components/ui/scroll-area.d.ts +9 -10
  178. package/dist/kernel/components/ui/scroll-area.js +1 -1
  179. package/dist/kernel/components/ui/select.d.ts +16 -16
  180. package/dist/kernel/components/ui/select.js +1 -1
  181. package/dist/kernel/components/ui/separator.d.ts +3 -3
  182. package/dist/kernel/components/ui/separator.js +1 -1
  183. package/dist/kernel/components/ui/table.d.ts +7 -7
  184. package/dist/kernel/components/ui/table.js +1 -1
  185. package/dist/kernel/components/ui/tabs.d.ts +12 -12
  186. package/dist/kernel/components/ui/tabs.js +1 -1
  187. package/dist/kernel/components/ui/tag.d.ts +3 -3
  188. package/dist/kernel/components/ui/tag.js +1 -1
  189. package/dist/kernel/components/ui/text.d.ts +4 -4
  190. package/dist/kernel/components/ui/text.js +1 -1
  191. package/dist/kernel/components/ui/toast.d.ts +11 -11
  192. package/dist/kernel/components/ui/toast.js +1 -1
  193. package/dist/kernel/components/ui/tooltip.d.ts +9 -9
  194. package/dist/kernel/components/ui/tooltip.js +1 -1
  195. package/dist/kernel/defaults.registry.d.ts +4 -17
  196. package/dist/kernel/defaults.registry.js +4 -19
  197. package/dist/kernel/routes/agent/markdown.d.ts +7 -0
  198. package/dist/kernel/routes/agent/markdown.js +229 -54
  199. package/dist/kernel/routes/layouts/group.d.ts +1 -1
  200. package/dist/kernel/routes/layouts/group.js +5 -7
  201. package/dist/kernel/routes/metadata/feed.d.ts +1 -2
  202. package/dist/kernel/routes/metadata/feed.js +119 -88
  203. package/dist/kernel/routes/metadata/llms.d.ts +3 -23
  204. package/dist/kernel/routes/metadata/llms.js +2 -103
  205. package/dist/kernel/routes/metadata/og-image.js +1 -1
  206. package/dist/kernel/routes/metadata/robots.d.ts +5 -3
  207. package/dist/kernel/routes/metadata/robots.js +4 -25
  208. package/dist/kernel/routes/metadata/sitemap.d.ts +36 -3
  209. package/dist/kernel/routes/metadata/sitemap.js +277 -49
  210. package/dist/kernel/routes/not-found.d.ts +34 -0
  211. package/dist/kernel/routes/not-found.js +213 -0
  212. package/dist/kernel/routes/pages/group.d.ts +5 -5
  213. package/dist/kernel/routes/pages/group.js +11 -5
  214. package/dist/kernel/routes/pages/leaf.d.ts +38 -6
  215. package/dist/kernel/routes/pages/leaf.js +21 -12
  216. package/dist/kernel/routes/pages/root.d.ts +5 -5
  217. package/dist/kernel/routes/pages/root.js +21 -6
  218. package/dist/keyboard-shortcuts.d.ts +2 -2
  219. package/dist/keyboard-shortcuts.js +1 -1
  220. package/dist/manifest-types-CcVPH_jh.d.ts +83 -0
  221. package/dist/resolvers/manifest-resolver.d.ts +2 -2
  222. package/dist/resolvers/manifest-resolver.js +65 -35
  223. package/dist/route-metadata-og-image-BeKKFHg7.d.ts +58 -0
  224. package/dist/search.d.ts +2 -9
  225. package/dist/search.js +9 -16
  226. package/dist/sidebar-types-CMrMM0Nj.d.ts +105 -0
  227. package/dist/theme-scope.d.ts +2 -2
  228. package/dist/theme-scope.js +1 -1
  229. package/dist/types-BbqmOzLC.d.ts +168 -0
  230. package/dist/types-TjH1ek0X.d.ts +22 -0
  231. package/dist/types-sM2g9nW0.d.ts +12 -0
  232. package/dist/types.d.ts +117 -91
  233. package/dist/utils/heading-ids.js +30 -11
  234. package/dist/utils/toc-selection.d.ts +7 -0
  235. package/dist/utils/toc-selection.js +14 -0
  236. package/dist/validate-local-source-EN2GW4FR.js +16 -0
  237. package/dist/validate-publish-os-source-OEWQDB7B.js +14 -0
  238. package/init/seed/minimal/publish.os/assets/blog/hello-world.svg +13 -0
  239. package/init/seed/minimal/publish.os/assets/favicon.dark.svg +13 -0
  240. package/init/seed/minimal/publish.os/assets/favicon.svg +13 -0
  241. package/init/seed/minimal/publish.os/blog/content/hello-world.mdx +48 -0
  242. package/init/seed/minimal/publish.os/blog/content/series-a.mdx +11 -0
  243. package/init/seed/minimal/publish.os/blog/index.tsx +85 -0
  244. package/init/seed/minimal/publish.os/blog/layout.tsx +13 -0
  245. package/init/seed/minimal/publish.os/blog/page.tsx +91 -0
  246. package/init/seed/minimal/publish.os/components/blog/copy-link.tsx +64 -0
  247. package/init/seed/minimal/publish.os/components/blog/frontmatter.ts +41 -0
  248. package/init/seed/minimal/publish.os/docs/content/get-started.mdx +2 -3
  249. package/init/seed/minimal/publish.os/docs/content/groups.mdx +5 -6
  250. package/init/seed/minimal/publish.os/publish.os.config.json +17 -2
  251. package/init/seed/minimal/publish.os/theme.css +3 -3
  252. package/init/seed/minimal/seed.json +12 -4
  253. package/init/seed/scratch/publish.os/docs/content/get-started.mdx +1 -1
  254. package/init/seed/scratch/publish.os/publish.os.config.json +1 -1
  255. package/package.json +48 -23
  256. package/release/app/phosphor/package.json +4 -4
  257. package/release/app/phosphor/pnpm-lock.yaml.template +123 -184
  258. package/release/compiler/package.json +5 -3
  259. package/release/compiler/pnpm-lock.yaml.template +153 -183
  260. package/release/release.json +6 -6
  261. package/dist/button-CtzUJB8u.d.ts +0 -11
  262. package/dist/chunk-535TM4A5.js +0 -1455
  263. package/dist/chunk-B2V22WRT.js +0 -297
  264. package/dist/chunk-NECL5IBJ.js +0 -318
  265. package/dist/chunk-SVYGXXYR.js +0 -36
  266. package/dist/chunk-UF6ATARM.js +0 -1100
  267. package/dist/compose-NN23UJGC.js +0 -13
  268. package/dist/ide-support-ZNW7ODFY.js +0 -15
  269. package/dist/kernel/components/blocks/design-system-preview.d.ts +0 -61
  270. package/dist/kernel/components/blocks/design-system-preview.js +0 -667
  271. package/dist/kernel/components/blocks/link-playground.d.ts +0 -5
  272. package/dist/kernel/components/blocks/link-playground.js +0 -744
  273. package/dist/kernel/components/blocks/navigation-progress-playground.d.ts +0 -5
  274. package/dist/kernel/components/blocks/navigation-progress-playground.js +0 -629
  275. package/dist/kernel/components/ui/theme-toggle.d.ts +0 -24
  276. package/dist/kernel/components/ui/theme-toggle.js +0 -53
  277. package/dist/sidebar-types-DKpR27II.d.ts +0 -25
  278. package/dist/types-BzkZty3r.d.ts +0 -147
  279. package/dist/types-CJWRG05y.d.ts +0 -76
  280. package/dist/types-CUtrppxt.d.ts +0 -69
  281. package/dist/validate-local-source-XRL2Y7XE.js +0 -14
  282. package/dist/validate-publish-os-source-DAPZ4QGE.js +0 -12
  283. package/init/seed/minimal/publish.os/assets/favicon/favicon.dark.png +0 -0
  284. package/init/seed/minimal/publish.os/assets/favicon/favicon.png +0 -0
@@ -1,43 +1,48 @@
1
1
  import { Link } from "@components/ui/link";
2
2
  import type {
3
3
  IndexPageProps,
4
- PageNode,
5
- TreeNode,
4
+ NavigationNode,
5
+ NavigationPageNode,
6
6
  } from "@publish.os/nextjs/types";
7
7
  import { log } from "@source/_internal/logger";
8
8
 
9
- function pageNodes(nodes: TreeNode[]): PageNode[] {
9
+ function pageNodes(nodes: NavigationNode[]): NavigationPageNode[] {
10
10
  return nodes.flatMap((node) => {
11
11
  if (node.type === "page") return [node];
12
- if (node.type === "section" || node.type === "folder") {
12
+ if (
13
+ node.type === "section" ||
14
+ node.type === "folder" ||
15
+ node.type === "group"
16
+ ) {
13
17
  return pageNodes(node.children);
14
18
  }
19
+ if (node.type === "view") return pageNodes(node.items);
15
20
  return [];
16
21
  });
17
22
  }
18
23
 
19
24
  export default function GroupPage(props: IndexPageProps) {
20
25
  log.debug("[default:group-page]", props);
21
- const { node, tree } = props;
22
- const pages = pageNodes(tree);
26
+ const { node, navigation } = props;
27
+ const pages = pageNodes(navigation.items);
23
28
 
24
29
  return (
25
30
  <div className="flex min-h-[calc(100vh-var(--layout-global-nav-height))] min-w-0 items-start justify-center px-6 pb-16 pt-[clamp(5rem,18vh,10rem)] text-foreground-1 lg:px-10 supports-[height:100dvh]:min-h-[calc(100dvh-var(--layout-global-nav-height))] supports-[top:anchor-size(--global-navbar_height)]:min-h-[calc(100vh-anchor-size(--global-navbar_height,3.5rem))] supports-[top:anchor-size(--global-navbar_height)]:supports-[height:100dvh]:min-h-[calc(100dvh-anchor-size(--global-navbar_height,3.5rem))]">
26
31
  <div className="w-full max-w-md">
27
32
  <p className="mb-6 text-sm font-semibold text-foreground-1">
28
- {node.title}
33
+ {node.label}
29
34
  </p>
30
35
  <h1 className="max-w-sm text-balance text-xl font-semibold leading-7 tracking-tight text-foreground-1">
31
36
  Browse the pages in this section.
32
37
  </h1>
33
38
 
34
39
  {pages.length > 0 ? (
35
- <nav aria-label={`${node.title} pages`} className="mt-8">
40
+ <nav aria-label={`${node.label} pages`} className="mt-8">
36
41
  <ul className="flex flex-col gap-2 text-sm">
37
42
  {pages.map((page) => (
38
- <li key={`${page.group}:${page.fileID}`}>
39
- <Link href={page.path} rightIcon="->" size="sm">
40
- {page.title}
43
+ <li key={page.id}>
44
+ <Link href={page.href} rightIcon="->" size="sm">
45
+ {page.label}
41
46
  </Link>
42
47
  </li>
43
48
  ))}
@@ -3,13 +3,17 @@ import type { LayoutProps } from "@publish.os/nextjs/types";
3
3
  import { log } from "@source/_internal/logger";
4
4
 
5
5
  export default function GroupLayout(props: LayoutProps) {
6
- const { children, currentPath, group, node, site, tree } = props;
6
+ const { children, currentPath, group, node, navigation } = props;
7
7
  log.debug("[default:group-layout]", { currentPath, group });
8
8
 
9
9
  return (
10
10
  <section className="mx-auto grid min-h-[calc(100vh-var(--layout-global-nav-height))] w-full max-w-(--layout-site-max-width) grid-cols-1 border-x border-stroke-3 bg-surface-1 md:grid-cols-[var(--layout-sidebar-width)_minmax(0,1fr)] xl:grid-cols-[var(--layout-sidebar-width)_minmax(0,1fr)_var(--layout-toc-width)] supports-[height:100dvh]:min-h-[calc(100dvh-var(--layout-global-nav-height))] supports-[top:anchor-size(--global-navbar_height)]:min-h-[calc(100vh-anchor-size(--global-navbar_height,3.5rem))] supports-[top:anchor-size(--global-navbar_height)]:supports-[height:100dvh]:min-h-[calc(100dvh-anchor-size(--global-navbar_height,3.5rem))]">
11
11
  <aside className="fixed top-(--layout-global-nav-height) z-content hidden h-[calc(100vh-var(--layout-global-nav-height))] min-h-0 border-l border-stroke-3 bg-surface-1 md:left-[max(0px,calc((100%-var(--layout-site-max-width))/2))] md:flex md:w-(--layout-sidebar-width) supports-[height:100dvh]:h-[calc(100dvh-var(--layout-global-nav-height))] supports-[top:anchor-size(--global-navbar_height)]:top-[anchor-size(--global-navbar_height,3.5rem)] supports-[top:anchor-size(--global-navbar_height)]:h-[calc(100vh-anchor-size(--global-navbar_height,3.5rem))] supports-[top:anchor-size(--global-navbar_height)]:supports-[height:100dvh]:h-[calc(100dvh-anchor-size(--global-navbar_height,3.5rem))]">
12
- <Sidebar currentPath={currentPath} title={node.title} tree={tree} />
12
+ <Sidebar
13
+ currentPath={currentPath}
14
+ title={node.label}
15
+ navigation={navigation}
16
+ />
13
17
  </aside>
14
18
  <main
15
19
  className="flex min-h-0 min-w-0 flex-1 scroll-mt-[calc(var(--layout-global-nav-height)+1rem)] flex-col bg-surface-1 md:col-start-2"
@@ -18,10 +22,6 @@ export default function GroupLayout(props: LayoutProps) {
18
22
  >
19
23
  {children}
20
24
  </main>
21
- <aside
22
- aria-label={`${site.name} secondary navigation`}
23
- className="hidden bg-surface-1 xl:block"
24
- />
25
25
  </section>
26
26
  );
27
27
  }
@@ -1,5 +1,6 @@
1
- import { AgentActions } from "@components/blocks/AgentActions";
1
+ import { AgentActions } from "@components/blocks/agent-actions";
2
2
  import { NextPrev } from "@components/blocks/next-prev";
3
+ import { Toc } from "@components/blocks/toc";
3
4
  import { MDX } from "@publish.os/nextjs/mdx";
4
5
  import type { PageProps } from "@publish.os/nextjs/types";
5
6
  import { log } from "@source/_internal/logger";
@@ -7,35 +8,44 @@ import { log } from "@source/_internal/logger";
7
8
  export default async function ContentPage(props: PageProps) {
8
9
  log.debug("[default:content-page]", props);
9
10
  const sourceUrl =
10
- typeof props.page.meta.sourceUrl === "string"
11
- ? props.page.meta.sourceUrl
12
- : typeof props.page.meta.githubUrl === "string"
13
- ? props.page.meta.githubUrl
11
+ typeof props.page.frontmatter.sourceUrl === "string"
12
+ ? props.page.frontmatter.sourceUrl
13
+ : typeof props.page.frontmatter.githubUrl === "string"
14
+ ? props.page.frontmatter.githubUrl
14
15
  : undefined;
15
16
 
16
17
  return (
17
- <div className="flex min-h-[calc(100vh-var(--layout-global-nav-height))] min-w-0 flex-1 flex-col px-6 py-10 text-foreground-1 lg:px-10 supports-[height:100dvh]:min-h-[calc(100dvh-var(--layout-global-nav-height))] supports-[top:anchor-size(--global-navbar_height)]:min-h-[calc(100vh-anchor-size(--global-navbar_height,3.5rem))] supports-[top:anchor-size(--global-navbar_height)]:supports-[height:100dvh]:min-h-[calc(100dvh-anchor-size(--global-navbar_height,3.5rem))]">
18
- <div className="mx-auto flex w-full max-w-(--layout-content-max-width) flex-1 flex-col">
19
- <article className="min-h-0 min-w-0 flex-1">
20
- <h1 className="text-3xl font-semibold tracking-tight text-foreground-1">
21
- {props.page.title}
22
- </h1>
23
- <AgentActions
24
- className="mt-4"
25
- markdown={props.page.body}
26
- pagePath={props.currentPath}
27
- siteUrl={props.site.origin}
28
- sourceUrl={sourceUrl}
18
+ <div className="relative flex min-h-[calc(100vh-var(--layout-global-nav-height))] min-w-0 flex-1 flex-col text-foreground-1 supports-[height:100dvh]:min-h-[calc(100dvh-var(--layout-global-nav-height))] supports-[top:anchor-size(--global-navbar_height)]:min-h-[calc(100vh-anchor-size(--global-navbar_height,3.5rem))] supports-[top:anchor-size(--global-navbar_height)]:supports-[height:100dvh]:min-h-[calc(100dvh-anchor-size(--global-navbar_height,3.5rem))]">
19
+ <Toc
20
+ content={props.page.body}
21
+ desktopClassName="xl:absolute xl:inset-y-0 xl:start-full xl:w-(--layout-toc-width) xl:px-3 xl:py-10"
22
+ desktopListClassName="xl:sticky xl:top-[calc(var(--layout-global-nav-height)_+_1.5rem)] xl:max-h-[calc(100dvh-var(--layout-global-nav-height)-3rem)] xl:overflow-y-auto supports-[top:anchor-size(--global-navbar_height)]:xl:top-[calc(anchor-size(--global-navbar_height,3.5rem)_+_1.5rem)] supports-[top:anchor-size(--global-navbar_height)]:xl:max-h-[calc(100dvh-anchor-size(--global-navbar_height,3.5rem)-3rem)]"
23
+ mobileClassName="sticky top-(--layout-global-nav-height) z-nav supports-[top:anchor-size(--global-navbar_height)]:top-[anchor-size(--global-navbar_height,3.5rem)]"
24
+ mobileQuery="(max-width: 1279px)"
25
+ />
26
+ <div className="flex min-w-0 flex-1 flex-col px-6 py-10 lg:px-10">
27
+ <div className="mx-auto flex w-full max-w-(--layout-content-max-width) flex-1 flex-col">
28
+ <article className="min-h-0 min-w-0 flex-1">
29
+ <h1 className="text-3xl font-semibold tracking-tight text-foreground-1">
30
+ {props.page.frontmatter.title}
31
+ </h1>
32
+ <AgentActions
33
+ className="mt-4"
34
+ markdownRevision={props.markdownRevision}
35
+ pagePath={props.currentPath}
36
+ siteUrl={props.site.origin}
37
+ sourceUrl={sourceUrl}
38
+ />
39
+ <div className="mt-6">
40
+ <MDX page={props.page} />
41
+ </div>
42
+ </article>
43
+ <NextPrev
44
+ className="mt-auto pt-12"
45
+ currentPath={props.currentPath}
46
+ navigation={props.navigation}
29
47
  />
30
- <div className="mt-6">
31
- <MDX page={props.page} />
32
- </div>
33
- </article>
34
- <NextPrev
35
- className="mt-auto pt-12"
36
- currentPath={props.currentPath}
37
- tree={props.tree}
38
- />
48
+ </div>
39
49
  </div>
40
50
  </div>
41
51
  );
@@ -4,37 +4,47 @@ import { dirname } from "node:path";
4
4
  import { fileURLToPath } from "node:url";
5
5
 
6
6
  const projectRoot = dirname(fileURLToPath(import.meta.url));
7
- const ASSET_PREFIX = "__PUBLISHOS_ASSET_PREFIX__";
7
+ const INTERNAL_PREFIX = "__PUBLISHOS_INTERNAL_PREFIX__";
8
+ const SOURCE_ASSET_PREFIX = "__PUBLISHOS_SOURCE_ASSET_PREFIX__";
8
9
  const IMAGE_OPTIMIZER_PATH = "__PUBLISHOS_IMAGE_PATH__";
9
10
  const NEXT_IMAGE_OPTIMIZER_PATH = "__PUBLISHOS_NEXT_IMAGE_PATH__";
10
11
 
11
12
  /** @type {import("next").NextConfig} */
12
13
  export default {
13
- assetPrefix: ASSET_PREFIX,
14
+ env: { PUBLISHOS_SITE_BUILD_TIME: new Date().toISOString() },
15
+ assetPrefix: INTERNAL_PREFIX,
14
16
  cacheComponents: true,
15
- partialPrefetching: false,
17
+ // Preserve loopback origins so internal rewrites do not proxy back into this app.
18
+ skipProxyUrlNormalize: true,
19
+ experimental: { globalNotFound: true },
20
+ partialPrefetching: true,
21
+ // macOS native notifications can delay preview updates. Use Next's fallback.
22
+ watchOptions:
23
+ process.platform === "darwin" ? { pollIntervalMs: 1_000 } : undefined,
16
24
  // Relocating Shiki as an external loses its pnpm-owned dependencies.
17
25
  transpilePackages: ["shiki"],
18
26
  turbopack: {
19
27
  resolveAlias: {
20
28
  "@publish.os/nextjs/mdx": "./source/.publishos/mdx.tsx",
29
+ "next/image": "@publish.os/nextjs/kernel/components/next-image",
30
+ ...__PUBLISHOS_COMPONENT_ALIASES__,
21
31
  },
22
32
  root: projectRoot,
23
33
  },
34
+ webpack(config) {
35
+ config.resolve.alias["next/image"] =
36
+ "@publish.os/nextjs/kernel/components/next-image";
37
+ return config;
38
+ },
24
39
  images: {
25
40
  dangerouslyAllowSVG: false,
26
41
  deviceSizes: [640, 828, 1080, 1200, 1600, 1920, 2560, 3840],
27
42
  formats: ["image/webp"],
28
43
  imageSizes: [32, 48, 64, 96, 128, 256, 384],
29
44
  path: IMAGE_OPTIMIZER_PATH,
30
- localPatterns: [
31
- {
32
- pathname: `${ASSET_PREFIX}/_publishos/assets/**/images/**`,
33
- search: "",
34
- },
35
- { pathname: `${ASSET_PREFIX}/assets/images/**`, search: "" },
36
- ],
37
- minimumCacheTTL: 2678400,
45
+ localPatterns: [{ pathname: `${SOURCE_ASSET_PREFIX}/**` }],
46
+ remotePatterns: [],
47
+ minimumCacheTTL: 0,
38
48
  qualities: [50, 60, 75, 85, 95, 100],
39
49
  },
40
50
  async rewrites() {
@@ -4,6 +4,7 @@
4
4
  "lib": ["dom", "dom.iterable", "esnext"],
5
5
  "module": "esnext",
6
6
  "moduleResolution": "bundler",
7
+ "jsxImportSource": "@publish.os/nextjs",
7
8
  "jsx": "react-jsx",
8
9
  "allowJs": true,
9
10
  "strict": true,
@@ -17,6 +18,15 @@
17
18
  "paths": {
18
19
  "@app/*": ["./app/*"],
19
20
  "@publish.os/nextjs/mdx": ["./source/.publishos/mdx"],
21
+ "@publish.os/nextjs/components/ui/button": [
22
+ "./node_modules/@publish.os/nextjs/dist/kernel/components/ui/button"
23
+ ],
24
+ "@publish.os/nextjs/components/blocks/toc": [
25
+ "./node_modules/@publish.os/nextjs/dist/kernel/components/blocks/toc"
26
+ ],
27
+ "@publish.os/nextjs/components/blocks/agent-actions": [
28
+ "./node_modules/@publish.os/nextjs/dist/kernel/components/blocks/agent-actions"
29
+ ],
20
30
  "@components/*": [
21
31
  "./source/components/*",
22
32
  "./node_modules/@publish.os/nextjs/dist/kernel/components/*"
@@ -0,0 +1,18 @@
1
+ [data-slot="copy-code-button"] {
2
+ transition: opacity 150ms ease-out;
3
+ }
4
+
5
+ @media (hover: hover) and (pointer: fine) and (any-pointer: fine) and (
6
+ any-hover: hover
7
+ ) and (not (any-pointer: coarse)) {
8
+ [data-slot="code-block"]:not(:hover):not(:focus-within)
9
+ [data-slot="copy-code-button"]:not([data-copied="true"]) {
10
+ opacity: 0;
11
+ }
12
+ }
13
+
14
+ @media (prefers-reduced-motion: reduce) {
15
+ [data-slot="copy-code-button"] {
16
+ transition: none;
17
+ }
18
+ }
@@ -1,25 +1,30 @@
1
1
  import { Link } from "@components/ui/link";
2
2
  import type {
3
- LinkNode,
3
+ NavigationGroupNode,
4
+ NavigationLinkNode,
4
5
  RootPageProps,
5
- SectionNode,
6
- TreeNode,
7
6
  } from "@publish.os/nextjs/types";
8
7
  import { log } from "@source/_internal/logger";
9
8
 
10
- type RootNavNode = LinkNode | (SectionNode & { path: string });
9
+ type RootNavNode = NavigationLinkNode | NavigationGroupNode;
11
10
 
12
- function rootNavNodes(nodes: TreeNode[]): RootNavNode[] {
11
+ function rootNavNodes(
12
+ nodes: RootPageProps["navigation"]["items"],
13
+ ): RootNavNode[] {
13
14
  return nodes.filter((node): node is RootNavNode => {
14
15
  if (node.type === "link") return true;
15
- return node.type === "section" && typeof node.path === "string";
16
+ return (
17
+ node.type === "group" &&
18
+ node.presentation === "page" &&
19
+ Boolean(node.href)
20
+ );
16
21
  });
17
22
  }
18
23
 
19
24
  export default function HomePage(props: RootPageProps) {
20
25
  log.debug("[default:root-page]", props);
21
- const { site, tree } = props;
22
- const navNodes = rootNavNodes(tree);
26
+ const { site, navigation } = props;
27
+ const navNodes = rootNavNodes(navigation.items);
23
28
 
24
29
  return (
25
30
  <section className="mx-auto grid min-h-[calc(100vh-var(--layout-global-nav-height))] w-full max-w-(--layout-site-max-width) grid-cols-1 border-x border-stroke-3 bg-surface-1 md:grid-cols-[var(--layout-sidebar-width)_minmax(0,1fr)_var(--layout-toc-width)] supports-[height:100dvh]:min-h-[calc(100dvh-var(--layout-global-nav-height))] supports-[top:anchor-size(--global-navbar_height)]:min-h-[calc(100vh-anchor-size(--global-navbar_height,3.5rem))] supports-[top:anchor-size(--global-navbar_height)]:supports-[height:100dvh]:min-h-[calc(100dvh-anchor-size(--global-navbar_height,3.5rem))]">
@@ -45,11 +50,11 @@ export default function HomePage(props: RootPageProps) {
45
50
  <li key={node.id}>
46
51
  {node.type === "link" ? (
47
52
  <Link href={node.href} rightIcon="->" size="sm">
48
- {node.title}
53
+ {node.label}
49
54
  </Link>
50
55
  ) : (
51
- <Link href={node.path} rightIcon="->" size="sm">
52
- {node.title}
56
+ <Link href={node.href} rightIcon="->" size="sm">
57
+ {node.label}
53
58
  </Link>
54
59
  )}
55
60
  </li>
@@ -4,10 +4,10 @@ import { faviconsAndLogos } from "@source/.publishos/favicons-and-logos.generate
4
4
  import { log } from "@source/_internal/logger";
5
5
 
6
6
  export default function DefaultRootLayout(props: RootLayoutProps) {
7
- const { children, site, tree } = props;
7
+ const { children, site, navigation } = props;
8
8
  log.debug("[default:root-layout]", {
9
9
  site: site.name,
10
- treeItems: tree.length,
10
+ navigationItems: navigation.items.length,
11
11
  });
12
12
 
13
13
  return (
@@ -18,7 +18,11 @@ export default function DefaultRootLayout(props: RootLayoutProps) {
18
18
  >
19
19
  Skip to content
20
20
  </a>
21
- <Navbar logo={faviconsAndLogos.logo} site={site} tree={tree} />
21
+ <Navbar
22
+ logo={faviconsAndLogos.logo}
23
+ site={site}
24
+ navigation={navigation}
25
+ />
22
26
  <div className="flex w-full flex-1 flex-col">{children}</div>
23
27
  </div>
24
28
  );
@@ -0,0 +1,65 @@
1
+ // HTTP User-Agent product names that select Markdown when Accept leaves a tie.
2
+ // Keep crawler names separate from general HTTP clients. A name is a hint, not
3
+ // proof of identity. Check vendor documentation before adding a crawler.
4
+ const AI_CRAWLERS = [
5
+ // https://developers.openai.com/api/docs/bots
6
+ "OAI-SearchBot",
7
+ "GPTBot",
8
+ "ChatGPT-User",
9
+ // https://support.claude.com/en/articles/8896518
10
+ "ClaudeBot",
11
+ "Claude-SearchBot",
12
+ "Claude-User",
13
+ // https://docs.perplexity.ai/docs/resources/perplexity-crawlers
14
+ "PerplexityBot",
15
+ "Perplexity-User",
16
+ // https://developers.google.com/crawling/docs/crawlers-fetchers/google-user-triggered-fetchers
17
+ "Google-Agent",
18
+ "Google-GeminiNotebook",
19
+ // https://developers.google.com/crawling/docs/crawlers-fetchers/google-common-crawlers
20
+ "Google-CloudVertexBot",
21
+ ];
22
+
23
+ // General HTTP clients follow the existing Markdown tie-break policy.
24
+ const HTTP_CLIENTS = [
25
+ "axios",
26
+ "got",
27
+ "node-fetch",
28
+ "undici",
29
+ "curl",
30
+ "wget",
31
+ "python-requests",
32
+ "httpx",
33
+ "aiohttp",
34
+ ];
35
+
36
+ // Other client product names are not verified crawler identities.
37
+ const CLIENT_PRODUCTS = [
38
+ "claude-code",
39
+ "claude",
40
+ "cursor",
41
+ "chatgpt",
42
+ "openai",
43
+ "perplexity",
44
+ "anthropic-ai",
45
+ ];
46
+
47
+ const SUPPORTED_PRODUCTS = new Set(
48
+ [...AI_CRAWLERS, ...HTTP_CLIENTS, ...CLIENT_PRODUCTS].map((name) =>
49
+ name.toLowerCase(),
50
+ ),
51
+ );
52
+
53
+ export function isMarkdownClient(userAgent: string): boolean {
54
+ // Match whole product names, including those inside a compatible comment.
55
+ // A preceding slash is excluded so a URL in a comment is not a product.
56
+ const products = /(?:^|[\s(;])([A-Za-z0-9!#$%&'*+.^_`|~-]+)(?=\/|[\s;)]|$)/g;
57
+ for (
58
+ let product = products.exec(userAgent);
59
+ product;
60
+ product = products.exec(userAgent)
61
+ ) {
62
+ if (SUPPORTED_PRODUCTS.has(product[1].toLowerCase())) return true;
63
+ }
64
+ return false;
65
+ }
@@ -0,0 +1,46 @@
1
+ import { Providers } from "@app/providers";
2
+ import manifest from "@manifest";
3
+ import { preloadRootFonts, rootFontClassName } from "@source/.fonts.generated";
4
+ import RootLayout from "@source/layout";
5
+ import { type ComponentType, Fragment, type ReactNode } from "react";
6
+ import "@source/.fonts.generated.css";
7
+ import "@app/globals.css";
8
+
9
+ /** Shared document and authored shell for successful pages and routing-level 404s. */
10
+ export default function SiteDocument({
11
+ children,
12
+ head,
13
+ beforeShell,
14
+ bodyWrapper: BodyWrapper = Fragment,
15
+ }: {
16
+ children: ReactNode;
17
+ head?: ReactNode;
18
+ beforeShell?: ReactNode;
19
+ bodyWrapper?: ComponentType<{ children: ReactNode }>;
20
+ }) {
21
+ preloadRootFonts();
22
+ return (
23
+ <html className={rootFontClassName} lang="en" suppressHydrationWarning>
24
+ {/* biome-ignore lint/style/noHeadElement: global-not-found owns a full document outside the Next metadata layout tree. */}
25
+ {head ? <head>{head}</head> : null}
26
+ <body className="publish-os-app-root">
27
+ {beforeShell}
28
+ <BodyWrapper>
29
+ <Providers>
30
+ <RootLayout
31
+ site={manifest.site}
32
+ navigation={
33
+ manifest.groups.__root?.navigation ?? {
34
+ rootGroup: "__root",
35
+ items: [],
36
+ }
37
+ }
38
+ >
39
+ {children}
40
+ </RootLayout>
41
+ </Providers>
42
+ </BodyWrapper>
43
+ </body>
44
+ </html>
45
+ );
46
+ }
@@ -5,6 +5,8 @@ import {
5
5
  createLeafPage,
6
6
  createLeafStaticParams,
7
7
  } from "@publish.os/nextjs/kernel/routes/pages/leaf";
8
+ import { agentRouteConfig } from "@source/.publishos/agent-route-config.generated";
9
+ import { markdownArtifactManifest } from "@source/.publishos/markdown-index.generated";
8
10
  import { ogManifest } from "@source/.publishos/og-manifest.generated";
9
11
  import { groupThemes } from "@source/.theme.generated";
10
12
  import Leaf from "@source/__PUBLISHOS_OWNER_KEY__/page";
@@ -13,6 +15,9 @@ import { PoweredByFooter } from "@source/_internal/powered-by-footer.generated";
13
15
  const route = {
14
16
  group: __PUBLISHOS_GROUP_KEY__,
15
17
  manifest,
18
+ markdownArtifactManifest,
19
+ markdownRoutesEnabled:
20
+ agentRouteConfig.enabled && agentRouteConfig.markdownRoutes,
16
21
  ogManifest,
17
22
  Leaf,
18
23
  PoweredByFooter,
@@ -1,12 +1,8 @@
1
+ import SiteDocument from "@app/document";
2
+ import { metadataIcons } from "@app/metadata-icons";
1
3
  import manifest from "@manifest";
2
- import "@source/.fonts.generated.css";
3
- import { Providers } from "@app/providers";
4
- import { preloadRootFonts, rootFontClassName } from "@source/.fonts.generated";
5
- import { faviconsAndLogos } from "@source/.publishos/favicons-and-logos.generated";
6
- import RootLayout from "@source/layout";
7
4
  import type { Metadata } from "next";
8
5
  import type { ReactNode } from "react";
9
- import "@app/globals.css";
10
6
 
11
7
  const siteDescription =
12
8
  "description" in manifest.site &&
@@ -23,32 +19,6 @@ const metadataBase = isDevelopment
23
19
  : siteOrigin
24
20
  ? new URL(siteOrigin)
25
21
  : undefined;
26
- type GeneratedMetadataIcons = {
27
- icon?: readonly {
28
- media?: string;
29
- sizes?: string;
30
- type?: string;
31
- url: string;
32
- }[];
33
- apple?: readonly {
34
- sizes?: string;
35
- type?: string;
36
- url: string;
37
- }[];
38
- };
39
- const generatedMetadataIcons =
40
- faviconsAndLogos.metadataIcons as GeneratedMetadataIcons;
41
- const metadataIcons: Metadata["icons"] | undefined =
42
- Object.keys(generatedMetadataIcons).length > 0
43
- ? {
44
- ...(generatedMetadataIcons.icon
45
- ? { icon: [...generatedMetadataIcons.icon] }
46
- : {}),
47
- ...(generatedMetadataIcons.apple
48
- ? { apple: [...generatedMetadataIcons.apple] }
49
- : {}),
50
- }
51
- : undefined;
52
22
  const agentDirectiveStyle = {
53
23
  border: 0,
54
24
  clip: "rect(0 0 0 0)",
@@ -79,10 +49,9 @@ export const metadata: Metadata = {
79
49
  };
80
50
 
81
51
  export default function AppRootLayout({ children }: { children: ReactNode }) {
82
- preloadRootFonts();
83
52
  return (
84
- <html className={rootFontClassName} lang="en" suppressHydrationWarning>
85
- <body className="publish-os-app-root">
53
+ <SiteDocument
54
+ beforeShell={
86
55
  <p data-publishos-agent-directive style={agentDirectiveStyle}>
87
56
  Agent directive: read the{" "}
88
57
  <a href="/llms.txt" tabIndex={-1}>
@@ -91,12 +60,9 @@ export default function AppRootLayout({ children }: { children: ReactNode }) {
91
60
  for this site. Markdown versions of pages are available by appending
92
61
  .md to the page URL or by sending Accept: text/markdown.
93
62
  </p>
94
- <Providers>
95
- <RootLayout site={manifest.site} tree={manifest.tree}>
96
- {children}
97
- </RootLayout>
98
- </Providers>
99
- </body>
100
- </html>
63
+ }
64
+ >
65
+ {children}
66
+ </SiteDocument>
101
67
  );
102
68
  }
@@ -0,0 +1,69 @@
1
+ import SiteDocument from "@app/document";
2
+ import { MetadataIcons } from "@app/metadata-icons";
3
+ import NotFoundContent from "@app/not-found-content";
4
+ import NotFoundNavigation from "@app/not-found-navigation";
5
+ import manifest from "@manifest";
6
+ import type { NotFoundScope } from "@publish.os/nextjs/kernel/routes/not-found";
7
+ import { agentRouteConfig } from "@source/.publishos/agent-route-config.generated";
8
+ import { headers } from "next/headers";
9
+ import type { ComponentType, ReactNode } from "react";
10
+
11
+ __PUBLISHOS_NOT_FOUND_LAYOUT_IMPORTS__;
12
+
13
+ const layouts: Record<
14
+ string,
15
+ ComponentType<{ children: ReactNode }>
16
+ > = __PUBLISHOS_NOT_FOUND_LAYOUTS__;
17
+ const generic: NotFoundScope = {
18
+ id: "none",
19
+ path: "/",
20
+ htmlPath: "/_not-found",
21
+ recommendations: [],
22
+ indexes: [],
23
+ markdown: "",
24
+ };
25
+
26
+ // Routing-level errors must stay outside successful pages' prerender trees.
27
+ export const instant = false;
28
+
29
+ export default async function GlobalNotFound() {
30
+ const id = (await headers()).get("x-publishos-not-found-scope");
31
+ const scope =
32
+ agentRouteConfig.notFoundScopes.find((entry) => entry.id === id) ?? generic;
33
+ const Layout = layouts[scope.id as keyof typeof layouts];
34
+ const content = <NotFoundContent scope={scope} />;
35
+ return (
36
+ <SiteDocument
37
+ bodyWrapper={NotFoundNavigation}
38
+ head={
39
+ <>
40
+ <title>{`Page not found · ${manifest.site.name}`}</title>
41
+ <meta name="robots" content="noindex" />
42
+ <MetadataIcons />
43
+ {agentRouteConfig.enabled && agentRouteConfig.discoveryHeaders ? (
44
+ <>
45
+ {scope.describedBy ? (
46
+ <link href={scope.describedBy} rel="describedby" />
47
+ ) : null}
48
+ {scope.indexes.map((link) => (
49
+ <link href={link.href} key={link.href} rel="related" />
50
+ ))}
51
+ </>
52
+ ) : null}
53
+ </>
54
+ }
55
+ >
56
+ {Layout ? (
57
+ <Layout>{content}</Layout>
58
+ ) : (
59
+ <main
60
+ className="flex min-h-0 flex-1 flex-col"
61
+ id="main-content"
62
+ tabIndex={-1}
63
+ >
64
+ {content}
65
+ </main>
66
+ )}
67
+ </SiteDocument>
68
+ );
69
+ }
@@ -1,4 +1,5 @@
1
1
  import { createMarkdownRouteHandlers } from "@publish.os/nextjs/kernel/routes/agent/markdown";
2
+ import { agentRouteConfig } from "@source/.publishos/agent-route-config.generated";
2
3
  import {
3
4
  loadMarkdownArtifact,
4
5
  markdownArtifactManifest,
@@ -11,6 +12,7 @@ const handlers = createMarkdownRouteHandlers(
11
12
  },
12
13
  {
13
14
  discoveryLinks: __PUBLISHOS_MARKDOWN_DISCOVERY_LINKS__,
15
+ notFoundScopes: agentRouteConfig.notFoundScopes,
14
16
  },
15
17
  );
16
18