@publish.os/nextjs 0.0.1-alpha.6 → 0.0.1-alpha.7

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 (220) hide show
  1. package/README.md +3 -5
  2. package/compiler-assets/nextjs/defaults/app/globals.css +6 -0
  3. package/compiler-assets/nextjs/defaults/group/layout.tsx +23 -0
  4. package/compiler-assets/nextjs/defaults/group/leaf.tsx +48 -0
  5. package/compiler-assets/nextjs/defaults/group/page.tsx +50 -0
  6. package/compiler-assets/nextjs/defaults/project/next.config.mjs +45 -0
  7. package/compiler-assets/nextjs/defaults/project/postcss.config.mjs +5 -0
  8. package/compiler-assets/nextjs/defaults/project/tsconfig.json.template +41 -0
  9. package/compiler-assets/nextjs/defaults/root/css/animation.css +90 -0
  10. package/compiler-assets/nextjs/defaults/root/css/components/dialog.css +21 -0
  11. package/compiler-assets/nextjs/defaults/root/css/components/drawer.css +21 -0
  12. package/compiler-assets/nextjs/defaults/root/css/components/menu.css +23 -0
  13. package/compiler-assets/nextjs/defaults/root/css/components/navigation-menu.css +25 -0
  14. package/compiler-assets/nextjs/defaults/root/css/components/popover.css +17 -0
  15. package/compiler-assets/nextjs/defaults/root/css/components/select.css +23 -0
  16. package/compiler-assets/nextjs/defaults/root/css/components/toast.css +19 -0
  17. package/compiler-assets/nextjs/defaults/root/css/components/tooltip.css +15 -0
  18. package/compiler-assets/nextjs/defaults/root/css/layout.css +22 -0
  19. package/compiler-assets/nextjs/defaults/root/css/media.css +81 -0
  20. package/compiler-assets/nextjs/defaults/root/css/radius.css +49 -0
  21. package/compiler-assets/nextjs/defaults/root/css/scrollbar.css +43 -0
  22. package/compiler-assets/nextjs/defaults/root/css/shadow.css +145 -0
  23. package/compiler-assets/nextjs/defaults/root/css/typography.css +607 -0
  24. package/compiler-assets/nextjs/defaults/root/css/zindex.css +39 -0
  25. package/compiler-assets/nextjs/defaults/root/globals.css +191 -0
  26. package/compiler-assets/nextjs/defaults/root/layout.tsx +19 -0
  27. package/compiler-assets/nextjs/defaults/root/page.tsx +61 -0
  28. package/compiler-assets/nextjs/defaults/root/theme.css +50 -0
  29. package/compiler-assets/nextjs/defaults/source/_internal/logger.ts +21 -0
  30. package/compiler-assets/nextjs/shims/generated-group-layout.tsx +19 -0
  31. package/compiler-assets/nextjs/shims/generated-group-page.tsx +18 -0
  32. package/compiler-assets/nextjs/shims/generated-leaf-page.tsx +21 -0
  33. package/compiler-assets/nextjs/shims/global-layout.tsx +134 -0
  34. package/compiler-assets/nextjs/shims/markdown-route.ts +29 -0
  35. package/compiler-assets/nextjs/shims/og-image-route.ts +18 -0
  36. package/compiler-assets/nextjs/shims/powered-by-footer.tsx +40 -0
  37. package/compiler-assets/nextjs/shims/providers.tsx +13 -0
  38. package/compiler-assets/nextjs/shims/proxy.ts +317 -0
  39. package/compiler-assets/nextjs/shims/publish-os-theme-provider.tsx +77 -0
  40. package/compiler-assets/nextjs/shims/root-page.tsx +13 -0
  41. package/compiler-assets/nextjs/shims/theme-defaults.css +177 -0
  42. package/dist/button-CFdx-ohV.d.ts +20 -0
  43. package/dist/cache/tags.js +6 -14
  44. package/dist/compiler.d.ts +100 -0
  45. package/dist/compiler.js +13379 -0
  46. package/dist/config/createNextConfig.d.ts +2 -1
  47. package/dist/config/createNextConfig.js +16 -12
  48. package/dist/icons.d.ts +1 -0
  49. package/dist/icons.js +2 -0
  50. package/dist/index.d.ts +303 -15
  51. package/dist/index.js +30 -1198
  52. package/dist/kernel/components/blocks/AgentActions.d.ts +9 -3
  53. package/dist/kernel/components/blocks/AgentActions.js +114 -200
  54. package/dist/kernel/components/blocks/animated-icon-swap.js +4 -25
  55. package/dist/kernel/components/blocks/color-palette.js +88 -169
  56. package/dist/kernel/components/blocks/design-system-preview.d.ts +38 -6
  57. package/dist/kernel/components/blocks/design-system-preview.js +44 -52
  58. package/dist/kernel/components/blocks/link-playground.js +23 -71
  59. package/dist/kernel/components/blocks/logo-block.js +18 -47
  60. package/dist/kernel/components/blocks/nav-breadcrumb.d.ts +1 -1
  61. package/dist/kernel/components/blocks/nav-breadcrumb.js +28 -42
  62. package/dist/kernel/components/blocks/navbar.d.ts +1 -1
  63. package/dist/kernel/components/blocks/navbar.js +14 -41
  64. package/dist/kernel/components/blocks/navigation-progress-playground.js +56 -149
  65. package/dist/kernel/components/blocks/navigation-progress.js +53 -157
  66. package/dist/kernel/components/blocks/next-prev.d.ts +1 -1
  67. package/dist/kernel/components/blocks/next-prev.js +16 -42
  68. package/dist/kernel/components/blocks/page-list.d.ts +1 -1
  69. package/dist/kernel/components/blocks/page-list.js +11 -16
  70. package/dist/kernel/components/blocks/search.d.ts +13 -2
  71. package/dist/kernel/components/blocks/search.js +116 -247
  72. package/dist/kernel/components/blocks/sidebar-node.d.ts +2 -2
  73. package/dist/kernel/components/blocks/sidebar-node.js +56 -95
  74. package/dist/kernel/components/blocks/sidebar.d.ts +5 -23
  75. package/dist/kernel/components/blocks/sidebar.js +35 -103
  76. package/dist/kernel/components/blocks/theme-toggle.d.ts +7 -3
  77. package/dist/kernel/components/blocks/theme-toggle.js +2 -2
  78. package/dist/kernel/components/blocks/toc.js +42 -178
  79. package/dist/kernel/components/mdx/components/blockquote.js +3 -24
  80. package/dist/kernel/components/mdx/components/callout.d.ts +1 -1
  81. package/dist/kernel/components/mdx/components/callout.js +15 -47
  82. package/dist/kernel/components/mdx/components/code-block.js +2 -2
  83. package/dist/kernel/components/mdx/components/figure-caption.js +6 -24
  84. package/dist/kernel/components/mdx/components/figure.js +9 -36
  85. package/dist/kernel/components/mdx/components/footnotes.js +3 -24
  86. package/dist/kernel/components/mdx/components/heading-copy-link.js +13 -37
  87. package/dist/kernel/components/mdx/components/heading.d.ts +8 -3
  88. package/dist/kernel/components/mdx/components/heading.js +32 -116
  89. package/dist/kernel/components/mdx/components/hr.d.ts +5 -3
  90. package/dist/kernel/components/mdx/components/hr.js +2 -2
  91. package/dist/kernel/components/mdx/components/image-zoom.js +2 -3
  92. package/dist/kernel/components/mdx/components/image.js +22 -62
  93. package/dist/kernel/components/mdx/components/inline-code.js +3 -24
  94. package/dist/kernel/components/mdx/components/kbd.d.ts +9 -4
  95. package/dist/kernel/components/mdx/components/kbd.js +2 -2
  96. package/dist/kernel/components/mdx/components/link.d.ts +1 -2
  97. package/dist/kernel/components/mdx/components/link.js +2 -2
  98. package/dist/kernel/components/mdx/components/paragraph.js +13 -41
  99. package/dist/kernel/components/mdx/components/pre.js +3 -24
  100. package/dist/kernel/components/mdx/components/strikethrough.js +6 -24
  101. package/dist/kernel/components/mdx/components/table.js +2 -2
  102. package/dist/kernel/components/mdx/components/task-list.js +6 -28
  103. package/dist/kernel/components/mdx/components/video-player.js +53 -88
  104. package/dist/kernel/components/mdx/components/video.js +27 -75
  105. package/dist/kernel/components/mdx/error-boundary.d.ts +1 -1
  106. package/dist/kernel/components/mdx/error-boundary.js +12 -15
  107. package/dist/kernel/components/mdx/error-fallback.js +4 -4
  108. package/dist/kernel/components/mdx/mdx.d.ts +68 -11
  109. package/dist/kernel/components/mdx/mdx.js +29 -29
  110. package/dist/kernel/components/mdx/rehype-heading-ids.js +11 -67
  111. package/dist/kernel/components/mdx/types.d.ts +1 -1
  112. package/dist/kernel/components/ui/accordion.js +3 -26
  113. package/dist/kernel/components/ui/breadcrumb-trail.d.ts +23 -7
  114. package/dist/kernel/components/ui/breadcrumb-trail.js +32 -80
  115. package/dist/kernel/components/ui/breadcrumb.d.ts +1 -1
  116. package/dist/kernel/components/ui/breadcrumb.js +20 -54
  117. package/dist/kernel/components/ui/button-group.d.ts +4 -3
  118. package/dist/kernel/components/ui/button-group.js +7 -30
  119. package/dist/kernel/components/ui/button.js +13 -36
  120. package/dist/kernel/components/ui/card.d.ts +2 -2
  121. package/dist/kernel/components/ui/card.js +2 -23
  122. package/dist/kernel/components/ui/dialog.d.ts +9 -9
  123. package/dist/kernel/components/ui/dialog.js +15 -33
  124. package/dist/kernel/components/ui/drawer.d.ts +10 -10
  125. package/dist/kernel/components/ui/drawer.js +15 -33
  126. package/dist/kernel/components/ui/input.js +6 -30
  127. package/dist/kernel/components/ui/kbd.js +10 -31
  128. package/dist/kernel/components/ui/link.d.ts +1 -1
  129. package/dist/kernel/components/ui/link.js +53 -104
  130. package/dist/kernel/components/ui/menu.d.ts +21 -21
  131. package/dist/kernel/components/ui/menu.js +10 -32
  132. package/dist/kernel/components/ui/meta-key.d.ts +9 -4
  133. package/dist/kernel/components/ui/meta-key.js +2 -2
  134. package/dist/kernel/components/ui/navigation-menu.d.ts +14 -14
  135. package/dist/kernel/components/ui/navigation-menu.js +9 -30
  136. package/dist/kernel/components/ui/popover.d.ts +10 -10
  137. package/dist/kernel/components/ui/popover.js +19 -34
  138. package/dist/kernel/components/ui/progress.js +2 -25
  139. package/dist/kernel/components/ui/scroll-area.js +39 -118
  140. package/dist/kernel/components/ui/select.d.ts +15 -15
  141. package/dist/kernel/components/ui/select.js +19 -35
  142. package/dist/kernel/components/ui/separator.js +2 -25
  143. package/dist/kernel/components/ui/table.js +2 -23
  144. package/dist/kernel/components/ui/tabs.js +39 -99
  145. package/dist/kernel/components/ui/tag.d.ts +2 -2
  146. package/dist/kernel/components/ui/tag.js +4 -25
  147. package/dist/kernel/components/ui/text.d.ts +2 -2
  148. package/dist/kernel/components/ui/text.js +3 -25
  149. package/dist/kernel/components/ui/theme-toggle.d.ts +18 -4
  150. package/dist/kernel/components/ui/theme-toggle.js +18 -44
  151. package/dist/kernel/components/ui/toast.d.ts +10 -10
  152. package/dist/kernel/components/ui/toast.js +13 -35
  153. package/dist/kernel/components/ui/tooltip.d.ts +8 -8
  154. package/dist/kernel/components/ui/tooltip.js +8 -29
  155. package/dist/kernel/defaults.registry.d.ts +1 -1
  156. package/dist/kernel/defaults.registry.js +2 -2
  157. package/dist/kernel/framework-icons.d.ts +1 -0
  158. package/dist/kernel/framework-icons.js +39 -0
  159. package/dist/kernel/routes/agent/markdown.js +36 -65
  160. package/dist/kernel/routes/layouts/group.d.ts +1 -1
  161. package/dist/kernel/routes/layouts/group.js +20 -109
  162. package/dist/kernel/routes/metadata/feed.d.ts +1 -2
  163. package/dist/kernel/routes/metadata/feed.js +46 -127
  164. package/dist/kernel/routes/metadata/llms.d.ts +1 -2
  165. package/dist/kernel/routes/metadata/llms.js +40 -120
  166. package/dist/kernel/routes/metadata/og-image.d.ts +10 -0
  167. package/dist/kernel/routes/metadata/og-image.js +264 -198
  168. package/dist/kernel/routes/metadata/robots.d.ts +1 -2
  169. package/dist/kernel/routes/metadata/robots.js +21 -90
  170. package/dist/kernel/routes/metadata/sitemap.d.ts +1 -2
  171. package/dist/kernel/routes/metadata/sitemap.js +36 -102
  172. package/dist/kernel/routes/pages/group.d.ts +1 -1
  173. package/dist/kernel/routes/pages/group.js +42 -137
  174. package/dist/kernel/routes/pages/leaf.d.ts +1 -1
  175. package/dist/kernel/routes/pages/leaf.js +74 -213
  176. package/dist/kernel/routes/pages/root.d.ts +1 -1
  177. package/dist/kernel/routes/pages/root.js +37 -108
  178. package/dist/keyboard-shortcuts.js +69 -141
  179. package/dist/link-CYaCRDb6.d.ts +35 -0
  180. package/dist/resolvers/manifest-resolver.d.ts +3 -3
  181. package/dist/resolvers/manifest-resolver.js +15 -21
  182. package/dist/route-metadata-og-image-BeKKFHg7.d.ts +58 -0
  183. package/dist/search.d.ts +81 -4
  184. package/dist/search.js +124 -195
  185. package/dist/sidebar-types-Bgchdfd6.d.ts +25 -0
  186. package/dist/theme-scope.d.ts +15 -0
  187. package/dist/theme-scope.js +23 -0
  188. package/dist/types-B_b3C0U6.d.ts +63 -0
  189. package/dist/types-CIwwieNw.d.ts +127 -0
  190. package/dist/types-DHBm7-j6.d.ts +57 -0
  191. package/dist/types-sM2g9nW0.d.ts +12 -0
  192. package/dist/types.d.ts +0 -1
  193. package/dist/types.js +1 -1
  194. package/dist/utils/cn.d.ts +5 -9
  195. package/dist/utils/cn.js +13 -7
  196. package/dist/utils/heading-ids.js +20 -47
  197. package/dist/utils/pretty-date.js +7 -13
  198. package/init/seed/minimal/publish.os/assets/logo/publish-dev-logo.dark.png +0 -0
  199. package/init/seed/minimal/publish.os/assets/logo/publish-dev-logo.png +0 -0
  200. package/init/seed/minimal/publish.os/docs/content/get-started.mdx +54 -0
  201. package/init/seed/minimal/publish.os/docs/content/groups.mdx +31 -0
  202. package/init/seed/minimal/publish.os/docs/content/theme.mdx +64 -0
  203. package/init/seed/minimal/publish.os/publish.os.config.json +21 -0
  204. package/init/seed/minimal/publish.os/theme.css +47 -0
  205. package/init/seed/minimal/seed.json +13 -0
  206. package/package.json +469 -35
  207. package/release/{package.json → app/lucide/package.json} +11 -5
  208. package/release/app/lucide/pnpm-lock.yaml.template +2905 -0
  209. package/release/app/lucide/pnpm-workspace.yaml +11 -0
  210. package/release/app/phosphor/package.json +30 -0
  211. package/release/app/phosphor/pnpm-lock.yaml.template +2908 -0
  212. package/release/app/phosphor/pnpm-workspace.yaml +11 -0
  213. package/release/app/tabler/package.json +30 -0
  214. package/release/app/tabler/pnpm-lock.yaml.template +2911 -0
  215. package/release/app/tabler/pnpm-workspace.yaml +11 -0
  216. package/release/compiler/package.json +20 -0
  217. package/release/compiler/pnpm-lock.yaml.template +2432 -0
  218. package/release/compiler/pnpm-workspace.yaml +11 -0
  219. package/release/release.json +29 -5
  220. package/release/runtime-pnpm-lock.yaml +0 -1316
@@ -0,0 +1,317 @@
1
+ import { agentRouteConfig } from "@source/.publishos/agent-route-config.generated";
2
+ import type { NextRequest } from "next/server";
3
+ import { NextResponse } from "next/server";
4
+
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
+ const INTERNAL_MARKDOWN_PREFIX = "/__publishos/md";
8
+ const PUBLIC_FILE_PATTERN = /\.[a-z0-9]{1,12}$/i;
9
+ const TEXT_METHODS = new Set(["GET", "HEAD"]);
10
+
11
+ function debugAgentRoute(
12
+ event: string,
13
+ details: Record<string, string | number | undefined>,
14
+ ) {
15
+ if (
16
+ process.env.NODE_ENV === "production" ||
17
+ process.env.NEXT_PRIVATE_DEBUG_CACHE !== "1"
18
+ ) {
19
+ return;
20
+ }
21
+
22
+ // biome-ignore lint/suspicious/noConsole: proxy debug logs are opt-in diagnostics for request routing.
23
+ console.debug("[publish.os:debug]", "[agent-route]", event, details);
24
+ }
25
+
26
+ function normalizePagePath(pathname: string): string {
27
+ if (pathname === "/") return "/";
28
+ return pathname.replace(/\/+$/, "");
29
+ }
30
+
31
+ function markdownRoutePath(pathname: string): string {
32
+ const normalized = normalizePagePath(pathname);
33
+ const pagePath = normalized.endsWith(".md")
34
+ ? normalized.slice(0, -".md".length)
35
+ : normalized;
36
+ return pagePath === "/"
37
+ ? INTERNAL_MARKDOWN_PREFIX
38
+ : `${INTERNAL_MARKDOWN_PREFIX}${pagePath}`;
39
+ }
40
+
41
+ function markdownAlternatePath(pathname: string): string {
42
+ const normalized = normalizePagePath(pathname);
43
+ if (normalized === "/") {
44
+ return agentRouteConfig.discoveryLinks.sitemap ?? "/sitemap.md";
45
+ }
46
+ return normalized.endsWith(".md") ? normalized : `${normalized}.md`;
47
+ }
48
+
49
+ function markdownNotFoundBody(): string {
50
+ const links = [
51
+ agentRouteConfig.discoveryLinks.home
52
+ ? `> Home: ${agentRouteConfig.discoveryLinks.home}`
53
+ : undefined,
54
+ agentRouteConfig.discoveryLinks.sitemap
55
+ ? `> Sitemap: ${agentRouteConfig.discoveryLinks.sitemap}`
56
+ : undefined,
57
+ agentRouteConfig.discoveryLinks.llms
58
+ ? `> LLMS index: ${agentRouteConfig.discoveryLinks.llms}`
59
+ : undefined,
60
+ ].filter((line): line is string => Boolean(line));
61
+
62
+ return [
63
+ "# Not found",
64
+ "",
65
+ ...links,
66
+ "",
67
+ "The requested Markdown page was not found.",
68
+ "",
69
+ ].join("\n");
70
+ }
71
+
72
+ function explicitAcceptQuality(accept: string, mimeType: string): number {
73
+ if (!accept) return 0;
74
+
75
+ const [targetType, targetSubtype] = mimeType.toLowerCase().split("/");
76
+ let bestQuality = 0;
77
+
78
+ for (const entry of accept.split(",")) {
79
+ const [rawType, ...rawParams] = entry
80
+ .trim()
81
+ .toLowerCase()
82
+ .split(";")
83
+ .map((part) => part.trim());
84
+ if (!rawType) continue;
85
+
86
+ const [type, subtype] = rawType.split("/");
87
+ if (type !== targetType || subtype !== targetSubtype) continue;
88
+
89
+ let quality = 1;
90
+ for (const param of rawParams) {
91
+ const [key, value] = param.split("=").map((part) => part.trim());
92
+ if (key !== "q") continue;
93
+ const parsed = Number.parseFloat(value);
94
+ quality = Number.isFinite(parsed) ? parsed : 0;
95
+ }
96
+
97
+ if (quality > bestQuality) bestQuality = quality;
98
+ }
99
+
100
+ return bestQuality;
101
+ }
102
+
103
+ function wantsMarkdown(request: NextRequest): boolean {
104
+ if (!TEXT_METHODS.has(request.method)) return false;
105
+
106
+ const accept = request.headers.get("accept") ?? "";
107
+ const markdownQuality = agentRouteConfig.markdownAccept
108
+ ? explicitAcceptQuality(accept, "text/markdown")
109
+ : 0;
110
+ const plainQuality = agentRouteConfig.plainTextAccept
111
+ ? explicitAcceptQuality(accept, "text/plain")
112
+ : 0;
113
+ const htmlQuality = explicitAcceptQuality(accept, "text/html");
114
+
115
+ if (markdownQuality > 0 && markdownQuality >= htmlQuality) return true;
116
+ if (plainQuality > 0 && htmlQuality === 0 && markdownQuality === 0) {
117
+ return true;
118
+ }
119
+
120
+ return false;
121
+ }
122
+
123
+ function looksLikeAgent(request: NextRequest): boolean {
124
+ if (!TEXT_METHODS.has(request.method)) return false;
125
+ if (!agentRouteConfig.agentDetection) return false;
126
+ if (explicitAcceptQuality(request.headers.get("accept") ?? "", "text/html")) {
127
+ return false;
128
+ }
129
+ return AGENT_USER_AGENT_PATTERN.test(request.headers.get("user-agent") ?? "");
130
+ }
131
+
132
+ function markdownRequestReason(
133
+ request: NextRequest,
134
+ ): "accept" | "agent" | "extension" | undefined {
135
+ if (!agentRouteConfig.enabled) return undefined;
136
+ if (
137
+ agentRouteConfig.markdownRoutes &&
138
+ request.nextUrl.pathname.endsWith(".md")
139
+ ) {
140
+ return "extension";
141
+ }
142
+ if (wantsMarkdown(request)) return "accept";
143
+ if (looksLikeAgent(request)) return "agent";
144
+ return undefined;
145
+ }
146
+
147
+ function isInternalMarkdownRoute(pathname: string): boolean {
148
+ return (
149
+ pathname === INTERNAL_MARKDOWN_PREFIX ||
150
+ pathname.startsWith(`${INTERNAL_MARKDOWN_PREFIX}/`)
151
+ );
152
+ }
153
+
154
+ function isStaticOrMetadataRoute(pathname: string): boolean {
155
+ if (
156
+ pathname.startsWith("/_next/") ||
157
+ pathname.startsWith("/_publishos/assets/") ||
158
+ pathname.startsWith("/_publishos/favicon/") ||
159
+ pathname.startsWith("/_publishos/logo/") ||
160
+ pathname.startsWith("/_publishos/og/") ||
161
+ pathname.startsWith("/assets/")
162
+ ) {
163
+ return true;
164
+ }
165
+
166
+ if (
167
+ pathname === "/favicon.ico" ||
168
+ pathname === "/apple-touch-icon.png" ||
169
+ pathname === "/apple-touch-icon-precomposed.png" ||
170
+ pathname === "/robots.txt" ||
171
+ pathname === "/sitemap.xml" ||
172
+ pathname === "/sitemap.md" ||
173
+ pathname === "/llms.txt" ||
174
+ pathname === "/llms-full.txt"
175
+ ) {
176
+ return true;
177
+ }
178
+
179
+ return PUBLIC_FILE_PATTERN.test(pathname) && !pathname.endsWith(".md");
180
+ }
181
+
182
+ function rewriteToMarkdown(
183
+ request: NextRequest,
184
+ reason: "accept" | "agent" | "extension",
185
+ ): NextResponse {
186
+ const url = request.nextUrl.clone();
187
+ url.pathname =
188
+ normalizePagePath(url.pathname) === "/"
189
+ ? "/sitemap.md"
190
+ : markdownRoutePath(url.pathname);
191
+
192
+ const requestHeaders = new Headers(request.headers);
193
+ requestHeaders.set("x-publishos-agent-route", "markdown");
194
+
195
+ debugAgentRoute("md", {
196
+ accept: request.headers.get("accept") ?? undefined,
197
+ method: request.method,
198
+ path: request.nextUrl.pathname,
199
+ reason,
200
+ target: url.pathname,
201
+ userAgent: request.headers.get("user-agent") ?? undefined,
202
+ });
203
+
204
+ return NextResponse.rewrite(url, {
205
+ request: {
206
+ headers: requestHeaders,
207
+ },
208
+ });
209
+ }
210
+
211
+ function withDiscoveryHeaders(
212
+ response: NextResponse,
213
+ pathname: string,
214
+ ): NextResponse {
215
+ const markdownUrl = markdownAlternatePath(pathname);
216
+ const links = [
217
+ `<${markdownUrl}>; rel="alternate"; type="text/markdown"`,
218
+ agentRouteConfig.discoveryLinks.llms
219
+ ? `<${agentRouteConfig.discoveryLinks.llms}>; rel="llms-txt"; type="text/plain"`
220
+ : undefined,
221
+ agentRouteConfig.discoveryLinks.sitemap
222
+ ? `<${agentRouteConfig.discoveryLinks.sitemap}>; rel="alternate"; type="text/markdown"; title="Markdown sitemap"`
223
+ : undefined,
224
+ ].filter((link): link is string => Boolean(link));
225
+ response.headers.set("link", links.join(", "));
226
+ response.headers.set("x-publishos-markdown", markdownUrl);
227
+ if (agentRouteConfig.discoveryLinks.llms) {
228
+ response.headers.set(
229
+ "x-publishos-llms",
230
+ agentRouteConfig.discoveryLinks.llms,
231
+ );
232
+ }
233
+ if (agentRouteConfig.discoveryLinks.sitemap) {
234
+ response.headers.set(
235
+ "x-publishos-sitemap",
236
+ agentRouteConfig.discoveryLinks.sitemap,
237
+ );
238
+ }
239
+ response.headers.set("x-publishos-agent-readable", "1");
240
+ return response;
241
+ }
242
+
243
+ export function proxy(request: NextRequest) {
244
+ const { pathname } = request.nextUrl;
245
+
246
+ if (isInternalMarkdownRoute(pathname)) {
247
+ if (request.headers.get("x-publishos-agent-route") === "markdown") {
248
+ return NextResponse.next();
249
+ }
250
+ if (!agentRouteConfig.blockInternalMarkdownRoute) {
251
+ debugAgentRoute("pass", {
252
+ method: request.method,
253
+ path: pathname,
254
+ reason: "allowed-internal",
255
+ });
256
+ return NextResponse.next();
257
+ }
258
+
259
+ debugAgentRoute("md", {
260
+ method: request.method,
261
+ path: pathname,
262
+ reason: "blocked-internal",
263
+ status: 404,
264
+ });
265
+
266
+ return new Response(markdownNotFoundBody(), {
267
+ status: 404,
268
+ headers: {
269
+ "cache-control": "public, max-age=60, s-maxage=300",
270
+ "content-type": "text/markdown; charset=utf-8",
271
+ "x-content-type-options": "nosniff",
272
+ "x-robots-tag": "noindex",
273
+ },
274
+ });
275
+ }
276
+
277
+ if (isStaticOrMetadataRoute(pathname)) {
278
+ debugAgentRoute("pass", {
279
+ method: request.method,
280
+ path: pathname,
281
+ reason: "static-or-metadata",
282
+ });
283
+ return NextResponse.next();
284
+ }
285
+
286
+ const markdownReason = markdownRequestReason(request);
287
+ if (markdownReason) {
288
+ return rewriteToMarkdown(request, markdownReason);
289
+ }
290
+
291
+ if (!agentRouteConfig.enabled || !agentRouteConfig.discoveryHeaders) {
292
+ debugAgentRoute("pass", {
293
+ method: request.method,
294
+ path: pathname,
295
+ reason: agentRouteConfig.enabled
296
+ ? "discovery-disabled"
297
+ : "agent-routes-disabled",
298
+ });
299
+ return NextResponse.next();
300
+ }
301
+
302
+ debugAgentRoute("html", {
303
+ accept: request.headers.get("accept") ?? undefined,
304
+ markdown: markdownAlternatePath(pathname),
305
+ method: request.method,
306
+ path: pathname,
307
+ userAgent: request.headers.get("user-agent") ?? undefined,
308
+ });
309
+
310
+ return withDiscoveryHeaders(NextResponse.next(), pathname);
311
+ }
312
+
313
+ export const config = {
314
+ matcher: [
315
+ "/((?!_next/static|_next/image|_next/webpack-hmr|_publishos/assets|_publishos/favicon|_publishos/logo|_publishos/og|assets).*)",
316
+ ],
317
+ };
@@ -0,0 +1,77 @@
1
+ "use client";
2
+
3
+ import { ThemeScopeProvider } from "@publish.os/nextjs/theme-scope";
4
+ import {
5
+ ROOT_DEFAULT_MODE,
6
+ ROOT_FORCED_MODE,
7
+ routeThemes,
8
+ } from "@source/.theme.generated";
9
+ import { useSelectedLayoutSegments } from "next/navigation";
10
+ import { ThemeProvider as NextThemes } from "next-themes";
11
+ import type { ReactNode } from "react";
12
+
13
+ type ForcedMode = "dark" | "light" | "none";
14
+ type RouteTheme = {
15
+ group: string;
16
+ forcedMode?: ForcedMode;
17
+ };
18
+
19
+ function selectedPathFromSegments(segments: readonly string[]): string {
20
+ const path = segments
21
+ .filter((segment) => segment !== "" && !segment.startsWith("("))
22
+ .join("/");
23
+
24
+ return path ? `/${path}` : "/";
25
+ }
26
+
27
+ function resolveRouteTheme(
28
+ segments: readonly string[],
29
+ ): RouteTheme | undefined {
30
+ const selectedPath = selectedPathFromSegments(segments);
31
+ let match: RouteTheme | undefined;
32
+ let matchLength = 0;
33
+
34
+ const entries = Object.entries(routeThemes) as Array<[string, RouteTheme]>;
35
+ for (const [basePath, routeTheme] of entries) {
36
+ if (selectedPath === basePath || selectedPath.startsWith(`${basePath}/`)) {
37
+ if (basePath.length > matchLength) {
38
+ match = routeTheme;
39
+ matchLength = basePath.length;
40
+ }
41
+ }
42
+ }
43
+
44
+ return match;
45
+ }
46
+
47
+ function effectiveForcedMode(routeTheme: RouteTheme | undefined): ForcedMode {
48
+ if (routeTheme?.forcedMode) return routeTheme.forcedMode;
49
+
50
+ return ROOT_FORCED_MODE ?? "none";
51
+ }
52
+
53
+ export function PublishOSThemeProvider({ children }: { children: ReactNode }) {
54
+ const routeTheme = resolveRouteTheme(useSelectedLayoutSegments());
55
+ const forcedMode = effectiveForcedMode(routeTheme);
56
+ const forcedTheme = forcedMode === "none" ? undefined : forcedMode;
57
+
58
+ return (
59
+ <NextThemes
60
+ attribute="class"
61
+ defaultTheme={ROOT_DEFAULT_MODE}
62
+ disableTransitionOnChange
63
+ enableSystem
64
+ forcedTheme={forcedTheme}
65
+ >
66
+ <ThemeScopeProvider group={routeTheme?.group}>
67
+ <div
68
+ className="contents"
69
+ data-theme-root=""
70
+ data-group={routeTheme?.group ?? ""}
71
+ >
72
+ {children}
73
+ </div>
74
+ </ThemeScopeProvider>
75
+ </NextThemes>
76
+ );
77
+ }
@@ -0,0 +1,13 @@
1
+ import manifest from "@manifest";
2
+ import {
3
+ createRootMetadata,
4
+ createRootPage,
5
+ } from "@publish.os/nextjs/kernel/routes/pages/root";
6
+ import { ogManifest } from "@source/.publishos/og-manifest.generated";
7
+ import RootPage from "@source/page";
8
+ import type { Metadata } from "next";
9
+
10
+ const route = { manifest, ogManifest, RootPage } as const;
11
+
12
+ export default createRootPage(route);
13
+ export const metadata: Metadata = createRootMetadata(route);
@@ -0,0 +1,177 @@
1
+ .PUBLISHOS_THEME_SELECTOR {
2
+ --surface-page: var(--neutral-100);
3
+ --surface-1: var(--neutral-100);
4
+ --surface-2: var(--neutral-200);
5
+ --surface-3: var(--neutral-300);
6
+ --surface-4: var(--neutral-400);
7
+ --surface-hover: var(--surface-3);
8
+ --surface-active: var(--surface-4);
9
+
10
+ --foreground-1: var(--neutral-1200);
11
+ --foreground-2: var(--neutral-1100);
12
+ --foreground-3: var(--neutral-1000);
13
+ --foreground-4: var(--neutral-800);
14
+
15
+ --stroke-1: var(--neutral-800);
16
+ --stroke-2: var(--neutral-700);
17
+ --stroke-3: var(--neutral-500);
18
+ --stroke-4: var(--neutral-400);
19
+ --backdrop: rgb(0 0 0 / 72%);
20
+
21
+ --accent-1: var(--accent);
22
+ --accent-2: color-mix(in oklch, var(--accent) 18%, transparent);
23
+ --accent-3: color-mix(in oklch, var(--accent) 12%, transparent);
24
+ --accent-4: color-mix(in oklch, var(--accent) 6%, transparent);
25
+ /* biome-ignore lint/correctness/noUnknownFunction: CSS Color 5. */
26
+ --accent-foreground: contrast-color(var(--accent-1));
27
+
28
+ --accent-1-foreground: var(--accent-foreground);
29
+ --accent-1-stroke: var(--accent-1);
30
+ --accent-1-hover: oklch(
31
+ from var(--accent-1) calc(l - 0.025) calc(c * 1.02) h
32
+ );
33
+ --accent-1-active: oklch(
34
+ from var(--accent-1) calc(l - 0.055) calc(c * 1.06) h
35
+ );
36
+
37
+ /* biome-ignore lint/correctness/noUnknownFunction: CSS Color 5. */
38
+ --accent-2-foreground: contrast-color(var(--accent-2));
39
+ --accent-2-stroke: color-mix(in oklch, var(--accent-2) 70%, var(--accent));
40
+ --accent-2-hover: color-mix(in oklch, var(--accent-2) 75%, var(--accent));
41
+ --accent-2-active: color-mix(in oklch, var(--accent-2) 60%, var(--accent));
42
+
43
+ /* biome-ignore lint/correctness/noUnknownFunction: CSS Color 5. */
44
+ --accent-3-foreground: contrast-color(var(--accent-3));
45
+ --accent-3-stroke: color-mix(in oklch, var(--accent-3) 55%, var(--accent));
46
+ --accent-3-hover: color-mix(in oklch, var(--accent-3) 75%, var(--accent));
47
+ --accent-3-active: color-mix(in oklch, var(--accent-3) 60%, var(--accent));
48
+
49
+ /* biome-ignore lint/correctness/noUnknownFunction: CSS Color 5. */
50
+ --accent-4-foreground: contrast-color(var(--accent-4));
51
+ --accent-4-stroke: color-mix(in oklch, var(--accent-4) 45%, var(--accent));
52
+ --accent-4-hover: color-mix(in oklch, var(--accent-4) 70%, var(--accent));
53
+ --accent-4-active: color-mix(in oklch, var(--accent-4) 55%, var(--accent));
54
+
55
+ --focus-stroke: var(--accent-3-stroke);
56
+ --selection-surface: var(--accent-2-active);
57
+ --selection-foreground: var(--foreground-1);
58
+ --progress-track-surface: transparent;
59
+ --progress-indicator-surface: var(--accent-1);
60
+ --progress-height: 2px;
61
+ --media-backdrop: var(--backdrop);
62
+ --media-surface: var(--neutral-1200);
63
+ --media-preview-backdrop: color-mix(
64
+ in oklab,
65
+ var(--backdrop) 28%,
66
+ transparent
67
+ );
68
+ --media-preview-backdrop-hover: color-mix(
69
+ in oklab,
70
+ var(--backdrop) 40%,
71
+ transparent
72
+ );
73
+ --media-ambient-surface: color-mix(
74
+ in oklab,
75
+ var(--neutral-100) 8%,
76
+ transparent
77
+ );
78
+ --media-control-surface: color-mix(
79
+ in oklab,
80
+ var(--neutral-1200) 72%,
81
+ transparent
82
+ );
83
+ --media-control-foreground: var(--neutral-100);
84
+ --media-control-stroke: color-mix(
85
+ in oklab,
86
+ var(--neutral-100) 40%,
87
+ transparent
88
+ );
89
+
90
+ --success-100: light-dark(#effaf7, #0d1816);
91
+ --success-200: light-dark(#e2f4ee, #10211e);
92
+ --success-300: light-dark(#c9e9df, #12312c);
93
+ --success-400: light-dark(#a9d9cd, #164238);
94
+ --success-500: light-dark(#83c7ba, #1a5346);
95
+ --success-600: light-dark(#5db3a5, #206655);
96
+ --success-700: light-dark(#399a8d, #297c68);
97
+ --success-800: light-dark(#258b80, #36927a);
98
+ --success-900: light-dark(#1d8178, #50ab91);
99
+ --success-1000: light-dark(#176e66, #65bea1);
100
+ --success-1100: light-dark(#0f5b55, #8bd0b7);
101
+ --success-1200: light-dark(#073f3c, #c4f0df);
102
+
103
+ --warning-100: light-dark(#fffaf0, #1e1507);
104
+ --warning-200: light-dark(#fff3da, #281b07);
105
+ --warning-300: light-dark(#ffe7b5, #392300);
106
+ --warning-400: light-dark(#ffda92, #4b2d00);
107
+ --warning-500: light-dark(#f8c56e, #5d3a00);
108
+ --warning-600: light-dark(#eeb050, #704900);
109
+ --warning-700: light-dark(#dd9f35, #895a00);
110
+ --warning-800: light-dark(#ca8816, #a86c00);
111
+ --warning-900: #ed940f;
112
+ --warning-1000: light-dark(#c97a09, #f5aa35);
113
+ --warning-1100: light-dark(#835000, #ffc978);
114
+ --warning-1200: light-dark(#4d2d00, #ffe9c5);
115
+
116
+ --danger-100: light-dark(#fffcfc, #180e0e);
117
+ --danger-200: light-dark(#fff7f7, #221212);
118
+ --danger-300: light-dark(#feebeb, #410a11);
119
+ --danger-400: light-dark(#ffdcdc, #590010);
120
+ --danger-500: light-dark(#ffcfce, #6c0017);
121
+ --danger-600: light-dark(#fabfbf, #7e0c22);
122
+ --danger-700: light-dark(#f1acac, #991f31);
123
+ --danger-800: light-dark(#e79293, #c62941);
124
+ --danger-900: #ce3247;
125
+ --danger-1000: #be1f3a;
126
+ --danger-1100: light-dark(#ca2d44, #ff8e92);
127
+ --danger-1200: light-dark(#631921, #ffcdcd);
128
+
129
+ --info-100: light-dark(hsl(198 83.3% 97.6%), hsl(200.9 62.2% 7.3%));
130
+ --info-200: light-dark(hsl(195.8 76% 95.1%), hsl(201.3 63.3% 9.6%));
131
+ --info-300: light-dark(hsl(195.9 73.9% 91%), hsl(200 70.6% 13.3%));
132
+ --info-400: light-dark(hsl(195.3 68% 85.3%), hsl(199.4 74.7% 17.1%));
133
+ --info-500: light-dark(hsl(195.6 63.5% 77.5%), hsl(198.5 75.7% 21%));
134
+ --info-600: light-dark(hsl(196.8 61% 67.8%), hsl(197.3 75.2% 25.3%));
135
+ --info-700: light-dark(hsl(198 58% 57.1%), hsl(197.2 75.3% 31.8%));
136
+ --info-800: light-dark(hsl(197.9 64.2% 47.1%), hsl(197 77.1% 37.6%));
137
+ --info-900: hsl(198.8 80.8% 40.8%);
138
+ --info-1000: light-dark(hsl(199.2 85.9% 36.3%), hsl(198 62.1% 50.4%));
139
+ --info-1100: light-dark(hsl(201.7 90.8% 29.8%), hsl(198.8 66.1% 64.1%));
140
+ --info-1200: light-dark(hsl(201.8 100% 19.4%), hsl(197.7 100% 88%));
141
+
142
+ --typography-body-foreground: var(--foreground-2);
143
+ --typography-heading-foreground: var(--foreground-1);
144
+ --typography-lead-foreground: var(--foreground-3);
145
+ --typography-link-foreground: var(--accent-1);
146
+ --typography-strong-foreground: var(--foreground-1);
147
+ --typography-counter-foreground: var(--foreground-4);
148
+ --typography-bullet-foreground: var(--stroke-1);
149
+ --typography-rule-stroke: var(--stroke-4);
150
+ --typography-quote-foreground: var(--foreground-2);
151
+ --typography-quote-stroke: var(--stroke-4);
152
+ --typography-caption-foreground: var(--foreground-4);
153
+ --typography-code-foreground: var(--foreground-1);
154
+ --typography-code-surface: var(--surface-2);
155
+ --typography-code-stroke: var(--stroke-2);
156
+ --typography-variable-foreground: var(--accent-1);
157
+ --typography-pre-foreground: var(--foreground-2);
158
+ --typography-pre-surface: var(--surface-3);
159
+ --typography-pre-stroke: var(--stroke-3);
160
+ --typography-table-heading-stroke: var(--stroke-3);
161
+ --typography-table-cell-stroke: var(--stroke-4);
162
+ --typography-base-size: 1rem;
163
+ --typography-line-height: 1.65;
164
+
165
+ --floating-surface-1: var(--surface-1);
166
+ --floating-surface-2: var(--surface-2);
167
+ --floating-surface-3: var(--surface-3);
168
+ --floating-surface-4: var(--surface-4);
169
+ --floating-foreground-1: var(--foreground-1);
170
+ --floating-foreground-2: var(--foreground-2);
171
+ --floating-foreground-3: var(--foreground-3);
172
+ --floating-foreground-4: var(--foreground-4);
173
+ --floating-stroke-1: var(--stroke-1);
174
+ --floating-stroke-2: var(--stroke-2);
175
+ --floating-stroke-3: var(--stroke-3);
176
+ --floating-stroke-4: var(--stroke-4);
177
+ }
@@ -0,0 +1,20 @@
1
+ import * as class_variance_authority_types from 'class-variance-authority/types';
2
+ import { VariantProps } from 'class-variance-authority';
3
+ import { ReactNode, ButtonHTMLAttributes } from 'react';
4
+
5
+ declare const buttonVariants: (props?: ({
6
+ variant?: "solid" | "soft" | "outline" | "ghost" | null | undefined;
7
+ size?: "xs" | "sm" | "md" | "lg" | "xl" | null | undefined;
8
+ iconOnly?: boolean | null | undefined;
9
+ } & class_variance_authority_types.ClassProp) | undefined) => string;
10
+ type ButtonVariantProps = VariantProps<typeof buttonVariants>;
11
+ type ButtonProps = {
12
+ active?: boolean;
13
+ children?: ReactNode;
14
+ className?: string;
15
+ leftIcon?: ReactNode;
16
+ loading?: boolean;
17
+ rightIcon?: ReactNode;
18
+ } & ButtonVariantProps & Omit<ButtonHTMLAttributes<HTMLButtonElement>, "children" | "className">;
19
+
20
+ export type { ButtonVariantProps as B, ButtonProps as a };
@@ -1,23 +1,15 @@
1
- // src/cache/tags.ts
1
+ // src/cache-tags.ts
2
2
  import { createHash } from "crypto";
3
- var MAX_TAG_LEN = 256;
4
- var MAX_SEGMENT_LEN = 80;
5
- var TAG_PATTERN = /^[a-z0-9:_./-]+$/;
3
+ var MAX_TAG_LEN = 256, MAX_SEGMENT_LEN = 80, TAG_PATTERN = /^[a-z0-9:_./-]+$/;
6
4
  function sha256(value) {
7
5
  return createHash("sha256").update(value).digest("hex").slice(0, 16);
8
6
  }
9
7
  function safeSegment(value) {
10
- const raw = value.trim().toLowerCase() || "root";
11
- const normalized = raw.replace(/\\/g, "/").replace(/\/+/g, "/").replace(/^\//, "").replace(/\/$/, "").replace(/[^a-z0-9:_./-]+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
12
- const segment = normalized || "root";
13
- if (segment.length <= MAX_SEGMENT_LEN) return segment;
14
- return `${segment.slice(0, 48)}.${sha256(segment)}`;
8
+ let segment = (value.trim().toLowerCase() || "root").replace(/\\/g, "/").replace(/\/+/g, "/").replace(/^\//, "").replace(/\/$/, "").replace(/[^a-z0-9:_./-]+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "") || "root";
9
+ return segment.length <= MAX_SEGMENT_LEN ? segment : `${segment.slice(0, 48)}.${sha256(segment)}`;
15
10
  }
16
11
  function assertTag(tag) {
17
- if (tag.length > MAX_TAG_LEN || !TAG_PATTERN.test(tag)) {
18
- return `tag:${sha256(tag)}`;
19
- }
20
- return tag;
12
+ return tag.length > MAX_TAG_LEN || !TAG_PATTERN.test(tag) ? `tag:${sha256(tag)}` : tag;
21
13
  }
22
14
  var tags = {
23
15
  site() {
@@ -30,7 +22,7 @@ var tags = {
30
22
  return assertTag(`group:${safeSegment(group)}`);
31
23
  },
32
24
  page(group, slug) {
33
- const path = Array.isArray(slug) ? slug.join("/") : slug;
25
+ let path = Array.isArray(slug) ? slug.join("/") : slug;
34
26
  return assertTag(`page:${safeSegment(group)}:${safeSegment(path)}`);
35
27
  },
36
28
  manifest(contentHash) {