blodemd 0.0.15 → 0.2.0

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 (286) hide show
  1. package/README.md +26 -1
  2. package/dist/cli.mjs +217 -217
  3. package/dist/cli.mjs.map +1 -1
  4. package/package.json +3 -36
  5. package/dev-server/app/[[...slug]]/page.tsx +0 -140
  6. package/dev-server/app/blodemd-dev/invalidate/route.ts +0 -12
  7. package/dev-server/app/blodemd-dev/static/[...path]/route.ts +0 -32
  8. package/dev-server/app/blodemd-dev/version/route.ts +0 -14
  9. package/dev-server/app/blodemd-internal/proxy/route.ts +0 -86
  10. package/dev-server/app/error.tsx +0 -24
  11. package/dev-server/app/favicon.ico +0 -0
  12. package/dev-server/app/globals.css +0 -4
  13. package/dev-server/app/layout.tsx +0 -38
  14. package/dev-server/app/not-found.tsx +0 -18
  15. package/dev-server/app/search/route.ts +0 -17
  16. package/dev-server/components/dev-reload-script.tsx +0 -86
  17. package/dev-server/components/providers.tsx +0 -15
  18. package/dev-server/lib/dev-state.ts +0 -8
  19. package/dev-server/lib/local-content-source.ts +0 -103
  20. package/dev-server/lib/local-runtime.tsx +0 -555
  21. package/dev-server/next-env.d.ts +0 -5
  22. package/dev-server/next.config.js +0 -54
  23. package/dev-server/package.json +0 -61
  24. package/dev-server/postcss.config.mjs +0 -7
  25. package/dev-server/public/glide-variable.woff2 +0 -0
  26. package/dev-server/tsconfig.json +0 -50
  27. package/docs/app/globals.css +0 -471
  28. package/docs/components/animate-ui/primitives/buttons/button.tsx +0 -14
  29. package/docs/components/api/api-playground.tsx +0 -467
  30. package/docs/components/api/api-reference.tsx +0 -157
  31. package/docs/components/content/collection-index.tsx +0 -114
  32. package/docs/components/docs/contextual-menu.tsx +0 -495
  33. package/docs/components/docs/copy-page-menu.tsx +0 -364
  34. package/docs/components/docs/doc-header.tsx +0 -223
  35. package/docs/components/docs/doc-shell.tsx +0 -355
  36. package/docs/components/docs/doc-sidebar.tsx +0 -256
  37. package/docs/components/docs/doc-toc.tsx +0 -46
  38. package/docs/components/docs/mobile-nav.tsx +0 -195
  39. package/docs/components/docs/sidebar-active-highlight.tsx +0 -34
  40. package/docs/components/docs/sidebar-scroll-area.tsx +0 -63
  41. package/docs/components/git/repo-picker.tsx +0 -529
  42. package/docs/components/icons/doc-icon.tsx +0 -96
  43. package/docs/components/mdx/accordion.tsx +0 -83
  44. package/docs/components/mdx/agent-instructions.tsx +0 -17
  45. package/docs/components/mdx/badge.tsx +0 -79
  46. package/docs/components/mdx/callout.tsx +0 -88
  47. package/docs/components/mdx/card.tsx +0 -110
  48. package/docs/components/mdx/code-block.tsx +0 -80
  49. package/docs/components/mdx/code-group.tsx +0 -203
  50. package/docs/components/mdx/color.tsx +0 -87
  51. package/docs/components/mdx/columns.tsx +0 -25
  52. package/docs/components/mdx/expandable.tsx +0 -45
  53. package/docs/components/mdx/field-layout.tsx +0 -77
  54. package/docs/components/mdx/frame.tsx +0 -23
  55. package/docs/components/mdx/get-text-content.ts +0 -18
  56. package/docs/components/mdx/icon.tsx +0 -12
  57. package/docs/components/mdx/iframe.tsx +0 -62
  58. package/docs/components/mdx/index.tsx +0 -121
  59. package/docs/components/mdx/installer.tsx +0 -20
  60. package/docs/components/mdx/panel.tsx +0 -11
  61. package/docs/components/mdx/param-field.tsx +0 -56
  62. package/docs/components/mdx/preview.tsx +0 -36
  63. package/docs/components/mdx/prompt.tsx +0 -63
  64. package/docs/components/mdx/request-example.tsx +0 -27
  65. package/docs/components/mdx/response-field.tsx +0 -42
  66. package/docs/components/mdx/steps.tsx +0 -92
  67. package/docs/components/mdx/tabs.tsx +0 -193
  68. package/docs/components/mdx/tile.tsx +0 -43
  69. package/docs/components/mdx/tooltip.tsx +0 -71
  70. package/docs/components/mdx/tree.tsx +0 -120
  71. package/docs/components/mdx/type-table.tsx +0 -71
  72. package/docs/components/mdx/update.tsx +0 -44
  73. package/docs/components/mdx/video.tsx +0 -45
  74. package/docs/components/mdx/view.tsx +0 -66
  75. package/docs/components/posthog-provider.tsx +0 -42
  76. package/docs/components/providers.tsx +0 -15
  77. package/docs/components/tenant-analytics.tsx +0 -49
  78. package/docs/components/third-parties.tsx +0 -32
  79. package/docs/components/ui/badge.tsx +0 -61
  80. package/docs/components/ui/breadcrumb.tsx +0 -112
  81. package/docs/components/ui/button-group.tsx +0 -83
  82. package/docs/components/ui/button.tsx +0 -65
  83. package/docs/components/ui/card.tsx +0 -92
  84. package/docs/components/ui/command.tsx +0 -167
  85. package/docs/components/ui/copy-button.tsx +0 -129
  86. package/docs/components/ui/dialog.tsx +0 -146
  87. package/docs/components/ui/field.tsx +0 -237
  88. package/docs/components/ui/input.tsx +0 -23
  89. package/docs/components/ui/kbd.tsx +0 -98
  90. package/docs/components/ui/label.tsx +0 -22
  91. package/docs/components/ui/morph-icon.tsx +0 -79
  92. package/docs/components/ui/popover.tsx +0 -267
  93. package/docs/components/ui/search-dialog.tsx +0 -431
  94. package/docs/components/ui/search.tsx +0 -101
  95. package/docs/components/ui/separator.tsx +0 -26
  96. package/docs/components/ui/sheet.tsx +0 -133
  97. package/docs/components/ui/sidebar.tsx +0 -758
  98. package/docs/components/ui/skeleton.tsx +0 -11
  99. package/docs/components/ui/switch.tsx +0 -32
  100. package/docs/components/ui/tabs.tsx +0 -138
  101. package/docs/components/ui/theme-toggle.tsx +0 -62
  102. package/docs/components/ui/tooltip.tsx +0 -53
  103. package/docs/components/web-mcp.tsx +0 -115
  104. package/docs/lib/agent-skills.ts +0 -48
  105. package/docs/lib/api-client.ts +0 -72
  106. package/docs/lib/config.ts +0 -6
  107. package/docs/lib/content-root.ts +0 -33
  108. package/docs/lib/content-source.ts +0 -70
  109. package/docs/lib/contextual-options.ts +0 -222
  110. package/docs/lib/dashboard-session.ts +0 -167
  111. package/docs/lib/db.ts +0 -13
  112. package/docs/lib/docs-collection.ts +0 -7
  113. package/docs/lib/docs-runtime.tsx +0 -745
  114. package/docs/lib/edge-config.ts +0 -95
  115. package/docs/lib/env.ts +0 -23
  116. package/docs/lib/etag.ts +0 -22
  117. package/docs/lib/github-install.ts +0 -33
  118. package/docs/lib/llms-full.ts +0 -82
  119. package/docs/lib/marketing-markdown.ts +0 -79
  120. package/docs/lib/marketing-site.ts +0 -31
  121. package/docs/lib/mdx.ts +0 -98
  122. package/docs/lib/navigation.ts +0 -288
  123. package/docs/lib/openapi-proxy.ts +0 -88
  124. package/docs/lib/openapi.ts +0 -158
  125. package/docs/lib/platform-config.ts +0 -6
  126. package/docs/lib/project-authz.ts +0 -46
  127. package/docs/lib/routes.ts +0 -103
  128. package/docs/lib/server-cache.ts +0 -83
  129. package/docs/lib/shiki.ts +0 -44
  130. package/docs/lib/supabase.ts +0 -37
  131. package/docs/lib/tenancy.ts +0 -364
  132. package/docs/lib/tenant-headers.ts +0 -43
  133. package/docs/lib/tenant-static.ts +0 -705
  134. package/docs/lib/tenant-utility-context.ts +0 -62
  135. package/docs/lib/tenants.ts +0 -72
  136. package/docs/lib/theme.ts +0 -29
  137. package/docs/lib/time-ago.ts +0 -24
  138. package/docs/lib/toc.ts +0 -2
  139. package/docs/lib/use-mobile.ts +0 -19
  140. package/docs/lib/use-tab-observer.ts +0 -71
  141. package/docs/lib/utils.ts +0 -5
  142. package/packages/@repo/common/dist/index.d.ts +0 -16
  143. package/packages/@repo/common/dist/index.d.ts.map +0 -1
  144. package/packages/@repo/common/dist/index.js +0 -84
  145. package/packages/@repo/common/package.json +0 -34
  146. package/packages/@repo/common/src/index.ts +0 -101
  147. package/packages/@repo/contracts/dist/analytics.d.ts +0 -21
  148. package/packages/@repo/contracts/dist/analytics.d.ts.map +0 -1
  149. package/packages/@repo/contracts/dist/analytics.js +0 -18
  150. package/packages/@repo/contracts/dist/dates.d.ts +0 -4
  151. package/packages/@repo/contracts/dist/dates.d.ts.map +0 -1
  152. package/packages/@repo/contracts/dist/dates.js +0 -2
  153. package/packages/@repo/contracts/dist/deployment.d.ts +0 -71
  154. package/packages/@repo/contracts/dist/deployment.d.ts.map +0 -1
  155. package/packages/@repo/contracts/dist/deployment.js +0 -46
  156. package/packages/@repo/contracts/dist/domain.d.ts +0 -94
  157. package/packages/@repo/contracts/dist/domain.d.ts.map +0 -1
  158. package/packages/@repo/contracts/dist/domain.js +0 -36
  159. package/packages/@repo/contracts/dist/git.d.ts +0 -28
  160. package/packages/@repo/contracts/dist/git.d.ts.map +0 -1
  161. package/packages/@repo/contracts/dist/git.js +0 -24
  162. package/packages/@repo/contracts/dist/ids.d.ts +0 -14
  163. package/packages/@repo/contracts/dist/ids.d.ts.map +0 -1
  164. package/packages/@repo/contracts/dist/ids.js +0 -11
  165. package/packages/@repo/contracts/dist/index.d.ts +0 -11
  166. package/packages/@repo/contracts/dist/index.d.ts.map +0 -1
  167. package/packages/@repo/contracts/dist/index.js +0 -12
  168. package/packages/@repo/contracts/dist/pagination.d.ts +0 -23
  169. package/packages/@repo/contracts/dist/pagination.d.ts.map +0 -1
  170. package/packages/@repo/contracts/dist/pagination.js +0 -15
  171. package/packages/@repo/contracts/dist/project.d.ts +0 -42
  172. package/packages/@repo/contracts/dist/project.d.ts.map +0 -1
  173. package/packages/@repo/contracts/dist/project.js +0 -25
  174. package/packages/@repo/contracts/dist/tenant.d.ts +0 -147
  175. package/packages/@repo/contracts/dist/tenant.d.ts.map +0 -1
  176. package/packages/@repo/contracts/dist/tenant.js +0 -58
  177. package/packages/@repo/contracts/dist/user.d.ts +0 -9
  178. package/packages/@repo/contracts/dist/user.d.ts.map +0 -1
  179. package/packages/@repo/contracts/dist/user.js +0 -9
  180. package/packages/@repo/contracts/package.json +0 -37
  181. package/packages/@repo/contracts/src/analytics.ts +0 -33
  182. package/packages/@repo/contracts/src/dates.ts +0 -4
  183. package/packages/@repo/contracts/src/deployment.ts +0 -73
  184. package/packages/@repo/contracts/src/domain.ts +0 -51
  185. package/packages/@repo/contracts/src/git.ts +0 -31
  186. package/packages/@repo/contracts/src/ids.ts +0 -23
  187. package/packages/@repo/contracts/src/index.ts +0 -12
  188. package/packages/@repo/contracts/src/pagination.ts +0 -21
  189. package/packages/@repo/contracts/src/project.ts +0 -32
  190. package/packages/@repo/contracts/src/tenant.ts +0 -94
  191. package/packages/@repo/contracts/src/user.ts +0 -12
  192. package/packages/@repo/models/dist/docs-config.d.ts +0 -961
  193. package/packages/@repo/models/dist/docs-config.d.ts.map +0 -1
  194. package/packages/@repo/models/dist/docs-config.js +0 -531
  195. package/packages/@repo/models/dist/index.d.ts +0 -3
  196. package/packages/@repo/models/dist/index.d.ts.map +0 -1
  197. package/packages/@repo/models/dist/index.js +0 -3
  198. package/packages/@repo/models/dist/tenant.d.ts +0 -37
  199. package/packages/@repo/models/dist/tenant.d.ts.map +0 -1
  200. package/packages/@repo/models/dist/tenant.js +0 -1
  201. package/packages/@repo/models/package.json +0 -37
  202. package/packages/@repo/models/src/docs-config.ts +0 -629
  203. package/packages/@repo/models/src/index.ts +0 -3
  204. package/packages/@repo/models/src/tenant.ts +0 -44
  205. package/packages/@repo/prebuild/dist/index.d.ts +0 -2
  206. package/packages/@repo/prebuild/dist/index.d.ts.map +0 -1
  207. package/packages/@repo/prebuild/dist/index.js +0 -2
  208. package/packages/@repo/prebuild/dist/openapi.d.ts +0 -43
  209. package/packages/@repo/prebuild/dist/openapi.d.ts.map +0 -1
  210. package/packages/@repo/prebuild/dist/openapi.js +0 -86
  211. package/packages/@repo/prebuild/package.json +0 -39
  212. package/packages/@repo/prebuild/src/index.ts +0 -2
  213. package/packages/@repo/prebuild/src/openapi.ts +0 -154
  214. package/packages/@repo/previewing/dist/blob-source.d.ts +0 -16
  215. package/packages/@repo/previewing/dist/blob-source.d.ts.map +0 -1
  216. package/packages/@repo/previewing/dist/blob-source.js +0 -128
  217. package/packages/@repo/previewing/dist/config-loader.d.ts +0 -134
  218. package/packages/@repo/previewing/dist/config-loader.d.ts.map +0 -1
  219. package/packages/@repo/previewing/dist/config-loader.js +0 -231
  220. package/packages/@repo/previewing/dist/constants.d.ts +0 -15
  221. package/packages/@repo/previewing/dist/constants.d.ts.map +0 -1
  222. package/packages/@repo/previewing/dist/constants.js +0 -14
  223. package/packages/@repo/previewing/dist/content-index.d.ts +0 -7
  224. package/packages/@repo/previewing/dist/content-index.d.ts.map +0 -1
  225. package/packages/@repo/previewing/dist/content-index.js +0 -291
  226. package/packages/@repo/previewing/dist/content-source.d.ts +0 -12
  227. package/packages/@repo/previewing/dist/content-source.d.ts.map +0 -1
  228. package/packages/@repo/previewing/dist/content-source.js +0 -1
  229. package/packages/@repo/previewing/dist/fs-source.d.ts +0 -11
  230. package/packages/@repo/previewing/dist/fs-source.d.ts.map +0 -1
  231. package/packages/@repo/previewing/dist/fs-source.js +0 -71
  232. package/packages/@repo/previewing/dist/index.d.ts +0 -16
  233. package/packages/@repo/previewing/dist/index.d.ts.map +0 -1
  234. package/packages/@repo/previewing/dist/index.js +0 -13
  235. package/packages/@repo/previewing/dist/markdown/agent-markdown.d.ts +0 -3
  236. package/packages/@repo/previewing/dist/markdown/agent-markdown.d.ts.map +0 -1
  237. package/packages/@repo/previewing/dist/markdown/agent-markdown.js +0 -176
  238. package/packages/@repo/previewing/dist/markdown/format.d.ts +0 -8
  239. package/packages/@repo/previewing/dist/markdown/format.d.ts.map +0 -1
  240. package/packages/@repo/previewing/dist/markdown/format.js +0 -43
  241. package/packages/@repo/previewing/dist/markdown/links.d.ts +0 -3
  242. package/packages/@repo/previewing/dist/markdown/links.d.ts.map +0 -1
  243. package/packages/@repo/previewing/dist/markdown/links.js +0 -31
  244. package/packages/@repo/previewing/dist/openapi-pages.d.ts +0 -7
  245. package/packages/@repo/previewing/dist/openapi-pages.d.ts.map +0 -1
  246. package/packages/@repo/previewing/dist/openapi-pages.js +0 -200
  247. package/packages/@repo/previewing/dist/search-index.d.ts +0 -4
  248. package/packages/@repo/previewing/dist/search-index.d.ts.map +0 -1
  249. package/packages/@repo/previewing/dist/search-index.js +0 -23
  250. package/packages/@repo/previewing/dist/serialization.d.ts +0 -13
  251. package/packages/@repo/previewing/dist/serialization.d.ts.map +0 -1
  252. package/packages/@repo/previewing/dist/serialization.js +0 -108
  253. package/packages/@repo/previewing/dist/toc-index.d.ts +0 -5
  254. package/packages/@repo/previewing/dist/toc-index.d.ts.map +0 -1
  255. package/packages/@repo/previewing/dist/toc-index.js +0 -53
  256. package/packages/@repo/previewing/dist/types.d.ts +0 -92
  257. package/packages/@repo/previewing/dist/types.d.ts.map +0 -1
  258. package/packages/@repo/previewing/dist/types.js +0 -1
  259. package/packages/@repo/previewing/dist/utility-index.d.ts +0 -7
  260. package/packages/@repo/previewing/dist/utility-index.d.ts.map +0 -1
  261. package/packages/@repo/previewing/dist/utility-index.js +0 -201
  262. package/packages/@repo/previewing/package.json +0 -41
  263. package/packages/@repo/previewing/src/blob-source.ts +0 -185
  264. package/packages/@repo/previewing/src/config-loader.ts +0 -316
  265. package/packages/@repo/previewing/src/constants.ts +0 -16
  266. package/packages/@repo/previewing/src/content-index.ts +0 -384
  267. package/packages/@repo/previewing/src/content-source.ts +0 -12
  268. package/packages/@repo/previewing/src/fs-source.ts +0 -103
  269. package/packages/@repo/previewing/src/index.ts +0 -71
  270. package/packages/@repo/previewing/src/markdown/agent-markdown.ts +0 -254
  271. package/packages/@repo/previewing/src/markdown/format.ts +0 -63
  272. package/packages/@repo/previewing/src/markdown/links.ts +0 -46
  273. package/packages/@repo/previewing/src/openapi-pages.ts +0 -319
  274. package/packages/@repo/previewing/src/search-index.ts +0 -38
  275. package/packages/@repo/previewing/src/serialization.ts +0 -191
  276. package/packages/@repo/previewing/src/toc-index.ts +0 -72
  277. package/packages/@repo/previewing/src/types.ts +0 -105
  278. package/packages/@repo/previewing/src/utility-index.ts +0 -304
  279. package/packages/@repo/validation/dist/index.d.ts +0 -12
  280. package/packages/@repo/validation/dist/index.d.ts.map +0 -1
  281. package/packages/@repo/validation/dist/index.js +0 -30
  282. package/packages/@repo/validation/package.json +0 -38
  283. package/packages/@repo/validation/src/blodemd-docs-schema.json +0 -3575
  284. package/packages/@repo/validation/src/index.ts +0 -59
  285. package/scripts/prepare-package.mjs +0 -53
  286. package/scripts/repo-packages.mjs +0 -8
@@ -1,745 +0,0 @@
1
- import { normalizePath } from "@repo/common";
2
- import type { PageMode, Tenant } from "@repo/models";
3
- import {
4
- buildContentIndex,
5
- buildPageMetadataMap,
6
- buildSearchIndex,
7
- buildUtilityIndex,
8
- loadPrebuiltContentIndex,
9
- loadPrebuiltSearchIndex,
10
- loadPrebuiltTocIndex,
11
- loadPrebuiltUtilityIndex,
12
- loadSiteConfig,
13
- } from "@repo/previewing";
14
- import type {
15
- ContentIndex,
16
- ContentSource,
17
- PageMetadata,
18
- SearchIndexItem,
19
- TocItem,
20
- UtilityIndex,
21
- } from "@repo/previewing";
22
- import { cache } from "react";
23
-
24
- import {
25
- getTenantContentSource,
26
- resolveSiteConfigAssets,
27
- } from "@/lib/content-source";
28
- import { contextualOptionsRequirePageContent } from "@/lib/contextual-options";
29
- import {
30
- getDocsCollection,
31
- getDocsCollectionWithNavigation,
32
- getDocsNavigation,
33
- } from "@/lib/docs-collection";
34
- import { renderFromCompiled, renderMdx } from "@/lib/mdx";
35
- import {
36
- buildNavigation,
37
- buildTabbedNavigation,
38
- enrichNavWithMetadata,
39
- findActiveTabIndex,
40
- findBreadcrumbs,
41
- flattenNav,
42
- getVisibleNavigation,
43
- } from "@/lib/navigation";
44
- import type { NavEntry, NavPage, NavTab } from "@/lib/navigation";
45
- import { loadOpenApiRegistry } from "@/lib/openapi";
46
- import type { OpenApiRegistry } from "@/lib/openapi";
47
- import { createTimedPromiseCache } from "@/lib/server-cache";
48
- import { getTenantBySlug } from "@/lib/tenants";
49
- import { extractToc } from "@/lib/toc";
50
-
51
- interface ConfigErrorResult {
52
- configErrors: string[];
53
- configWarnings: string[];
54
- tenant: Tenant;
55
- }
56
-
57
- interface UnpublishedTenantResult {
58
- emptyState: "unpublished";
59
- tenant: Tenant;
60
- }
61
-
62
- interface RenderedPageData {
63
- content: Awaited<ReturnType<typeof renderMdx>>["content"];
64
- frontmatter: Awaited<ReturnType<typeof renderMdx>>["frontmatter"];
65
- rawContent?: string;
66
- toc: ReturnType<typeof extractToc>;
67
- }
68
-
69
- interface TenantArtifacts {
70
- anchors: { label: string; href: string }[];
71
- config: Awaited<ReturnType<typeof resolveSiteConfigAssets>>;
72
- contentIndex: ContentIndex;
73
- contentSource: ContentSource;
74
- flatNav: NavPage[];
75
- pageMetadataMap: Map<string, PageMetadata>;
76
- registry: OpenApiRegistry;
77
- tabs: NavTab[] | null;
78
- tenant: Tenant;
79
- tocBySlug: Map<string, TocItem[]>;
80
- visibleFlatNav: NavPage[];
81
- visibleNav: NavEntry[];
82
- }
83
-
84
- type TenantArtifactsResult =
85
- | ConfigErrorResult
86
- | TenantArtifacts
87
- | UnpublishedTenantResult
88
- | null;
89
-
90
- const ARTIFACT_CACHE_TTL_MS = 30 * 60 * 1000;
91
- const PAGE_RENDER_CACHE_TTL_MS = 4 * 60 * 60 * 1000;
92
-
93
- const artifactsCache = createTimedPromiseCache<string, TenantArtifactsResult>({
94
- maxEntries: 512,
95
- ttlMs: ARTIFACT_CACHE_TTL_MS,
96
- });
97
-
98
- const searchItemsCache = createTimedPromiseCache<string, SearchIndexItem[]>({
99
- maxEntries: 512,
100
- ttlMs: ARTIFACT_CACHE_TTL_MS,
101
- });
102
-
103
- const renderedPageCache = createTimedPromiseCache<string, RenderedPageData>({
104
- maxEntries: 2048,
105
- ttlMs: PAGE_RENDER_CACHE_TTL_MS,
106
- });
107
-
108
- const isConfigErrorResult = (
109
- value: TenantArtifactsResult
110
- ): value is ConfigErrorResult => Boolean(value && "configErrors" in value);
111
-
112
- const isUnpublishedTenantResult = (
113
- value: TenantArtifactsResult
114
- ): value is UnpublishedTenantResult => Boolean(value && "emptyState" in value);
115
-
116
- const getTenantArtifactsCacheKey = (tenant: Tenant) =>
117
- [
118
- tenant.id,
119
- tenant.slug,
120
- tenant.activeDeploymentId ?? "",
121
- tenant.activeDeploymentManifestUrl ?? "",
122
- tenant.docsPath ?? "",
123
- tenant.pathPrefix ?? "",
124
- tenant.primaryDomain,
125
- ].join(":");
126
-
127
- const buildSearchItems = ({
128
- config,
129
- contentIndex,
130
- utilityIndex,
131
- }: {
132
- config: TenantArtifacts["config"];
133
- contentIndex: ContentIndex;
134
- utilityIndex?: UtilityIndex | null;
135
- }) => buildSearchIndex(contentIndex, config, utilityIndex ?? undefined);
136
-
137
- const mergeSearchItems = ({
138
- baseItems,
139
- config,
140
- flatNav,
141
- visibleFlatNav,
142
- }: {
143
- baseItems: SearchIndexItem[];
144
- config: TenantArtifacts["config"];
145
- flatNav: NavPage[];
146
- visibleFlatNav: NavPage[];
147
- }): SearchIndexItem[] => {
148
- const items = new Map<string, SearchIndexItem>(
149
- baseItems.map((item) => [item.path, item])
150
- );
151
-
152
- for (const item of visibleFlatNav) {
153
- items.set(item.path, {
154
- href: item.url,
155
- path: item.path,
156
- title: item.sidebarTitle ?? item.title,
157
- });
158
- }
159
-
160
- if (config.seo?.indexing === "all") {
161
- for (const item of flatNav) {
162
- if (!items.has(item.path)) {
163
- items.set(item.path, {
164
- href: item.url,
165
- path: item.path,
166
- title: item.sidebarTitle ?? item.title,
167
- });
168
- }
169
- }
170
- }
171
-
172
- return [...items.values()];
173
- };
174
-
175
- const getTenantArtifacts = async (tenantSlug: string) => {
176
- const tenant = await getTenantBySlug(tenantSlug);
177
- if (!tenant) {
178
- return null;
179
- }
180
-
181
- const cacheKey = getTenantArtifactsCacheKey(tenant);
182
-
183
- return await artifactsCache.getOrCreate(cacheKey, async () => {
184
- const contentSource = getTenantContentSource(tenant);
185
- const configResult = await loadSiteConfig(contentSource);
186
- if (!configResult.ok) {
187
- if (
188
- !tenant.activeDeploymentManifestUrl &&
189
- configResult.errors.length === 1 &&
190
- configResult.errors[0] === "docs.json not found."
191
- ) {
192
- return {
193
- emptyState: "unpublished" as const,
194
- tenant,
195
- };
196
- }
197
-
198
- return {
199
- configErrors: configResult.errors,
200
- configWarnings: [],
201
- tenant,
202
- };
203
- }
204
-
205
- const rawConfig = configResult.config;
206
- const docsCollection = getDocsCollection(rawConfig);
207
- const docsNavigation = getDocsNavigation(rawConfig);
208
- const docsCollectionWithNavigation =
209
- getDocsCollectionWithNavigation(rawConfig);
210
-
211
- const [config, contentIndex, registryResult, prebuiltTocIndex] =
212
- await Promise.all([
213
- resolveSiteConfigAssets(rawConfig, contentSource),
214
- loadPrebuiltContentIndex(contentSource).then(
215
- async (prebuilt) =>
216
- prebuilt ?? (await buildContentIndex(contentSource, rawConfig))
217
- ),
218
- loadOpenApiRegistry(docsCollectionWithNavigation, contentSource)
219
- .then((registry) => ({ ok: true as const, registry }))
220
- .catch((error: unknown) => ({
221
- error,
222
- ok: false as const,
223
- })),
224
- loadPrebuiltTocIndex(contentSource),
225
- ]);
226
-
227
- if (contentIndex.errors.length) {
228
- return {
229
- configErrors: contentIndex.errors,
230
- configWarnings: configResult.warnings,
231
- tenant,
232
- };
233
- }
234
-
235
- if (!registryResult.ok) {
236
- return {
237
- configErrors: [
238
- registryResult.error instanceof Error
239
- ? registryResult.error.message
240
- : "OpenAPI parsing failed",
241
- ],
242
- configWarnings: configResult.warnings,
243
- tenant,
244
- };
245
- }
246
-
247
- const pageMetadataMap = buildPageMetadataMap(contentIndex);
248
- const slugPrefix = docsCollection?.slugPrefix ?? "";
249
- const rawNav = docsNavigation
250
- ? buildNavigation(docsNavigation, registryResult.registry, slugPrefix)
251
- : [];
252
- const nav = enrichNavWithMetadata(rawNav, pageMetadataMap);
253
- const visibleNav = getVisibleNavigation(nav);
254
- const flatNav = flattenNav(nav);
255
- const visibleFlatNav = flattenNav(visibleNav);
256
- const rawTabs = buildTabbedNavigation(
257
- docsNavigation,
258
- registryResult.registry,
259
- slugPrefix
260
- );
261
- const tabs =
262
- rawTabs?.map((tab) => ({
263
- ...tab,
264
- entries: enrichNavWithMetadata(tab.entries, pageMetadataMap),
265
- })) ?? null;
266
-
267
- return {
268
- anchors: docsNavigation?.global?.anchors ?? [],
269
- config,
270
- contentIndex,
271
- contentSource,
272
- flatNav,
273
- pageMetadataMap,
274
- registry: registryResult.registry,
275
- tabs,
276
- tenant,
277
- tocBySlug: prebuiltTocIndex ?? new Map(),
278
- visibleFlatNav,
279
- visibleNav,
280
- };
281
- });
282
- };
283
-
284
- export interface TenantSidebarData {
285
- anchors: { label: string; href: string }[];
286
- entries: NavEntry[];
287
- }
288
-
289
- export const getTenantSidebarData = cache(
290
- async (
291
- tenantSlug: string,
292
- activeTabIndex: number
293
- ): Promise<TenantSidebarData | null> => {
294
- const artifacts = await getTenantArtifacts(tenantSlug);
295
- if (
296
- !artifacts ||
297
- isConfigErrorResult(artifacts) ||
298
- isUnpublishedTenantResult(artifacts)
299
- ) {
300
- return null;
301
- }
302
-
303
- const tabEntries = artifacts.tabs
304
- ? getVisibleNavigation(artifacts.tabs[activeTabIndex]?.entries ?? [])
305
- : null;
306
-
307
- return {
308
- anchors: artifacts.anchors,
309
- entries: tabEntries ?? artifacts.visibleNav,
310
- };
311
- }
312
- );
313
-
314
- export const getTenantSearchItems = cache(async (tenantSlug: string) => {
315
- const artifacts = await getTenantArtifacts(tenantSlug);
316
- if (
317
- !artifacts ||
318
- isConfigErrorResult(artifacts) ||
319
- isUnpublishedTenantResult(artifacts)
320
- ) {
321
- return null;
322
- }
323
-
324
- const cacheKey = `${getTenantArtifactsCacheKey(artifacts.tenant)}:search`;
325
-
326
- return await searchItemsCache.getOrCreate(cacheKey, async () => {
327
- const prebuiltSearchIndex = await loadPrebuiltSearchIndex(
328
- artifacts.contentSource
329
- );
330
- const utilityIndex = prebuiltSearchIndex
331
- ? null
332
- : ((await loadPrebuiltUtilityIndex(artifacts.contentSource)) ??
333
- (await buildUtilityIndex(
334
- artifacts.contentIndex,
335
- artifacts.contentSource,
336
- artifacts.config
337
- )));
338
-
339
- return mergeSearchItems({
340
- baseItems:
341
- prebuiltSearchIndex ??
342
- buildSearchItems({
343
- config: artifacts.config,
344
- contentIndex: artifacts.contentIndex,
345
- utilityIndex,
346
- }),
347
- config: artifacts.config,
348
- flatNav: artifacts.flatNav,
349
- visibleFlatNav: artifacts.visibleFlatNav,
350
- });
351
- });
352
- });
353
-
354
- const getRenderedPageData = async ({
355
- artifacts,
356
- basePath,
357
- currentPath,
358
- relativePath,
359
- rawContent: preloadedRawContent,
360
- toc: preloadedToc,
361
- useToc,
362
- }: {
363
- artifacts: TenantArtifacts;
364
- basePath?: string;
365
- currentPath: string;
366
- relativePath: string;
367
- rawContent?: string;
368
- toc?: TocItem[];
369
- useToc: boolean;
370
- }) => {
371
- const cacheKey = `${getTenantArtifactsCacheKey(artifacts.tenant)}:${basePath ?? ""}:${currentPath}`;
372
-
373
- return await renderedPageCache.getOrCreate(cacheKey, async () => {
374
- const compiled =
375
- await artifacts.contentSource.readCompiledMdx?.(relativePath);
376
- const rawContent =
377
- preloadedRawContent ??
378
- (compiled
379
- ? undefined
380
- : await artifacts.contentSource.readFile(relativePath));
381
- const rendered = compiled
382
- ? await renderFromCompiled(
383
- compiled.compiledSource,
384
- basePath,
385
- relativePath
386
- )
387
- : await renderMdx(rawContent ?? "", basePath, relativePath);
388
-
389
- return {
390
- content: rendered.content,
391
- frontmatter: rendered.frontmatter,
392
- rawContent,
393
- toc: preloadedToc ?? (useToc && rawContent ? extractToc(rawContent) : []),
394
- };
395
- });
396
- };
397
-
398
- export const clearDocsRuntimeCaches = () => {
399
- artifactsCache.clear();
400
- searchItemsCache.clear();
401
- renderedPageCache.clear();
402
- };
403
-
404
- export const clearDocsRuntimeCachesForTenant = (tenantId: string) => {
405
- artifactsCache.deleteByPrefix(tenantId);
406
- searchItemsCache.deleteByPrefix(tenantId);
407
- renderedPageCache.deleteByPrefix(tenantId);
408
- };
409
-
410
- const computePrevNext = (
411
- flatNav: NavPage[],
412
- currentPath: string
413
- ): {
414
- nextPage: { title: string; path: string } | undefined;
415
- prevPage: { title: string; path: string } | undefined;
416
- } => {
417
- const currentIndex = flatNav.findIndex((p) => p.path === currentPath);
418
- return {
419
- nextPage:
420
- currentIndex !== -1 && currentIndex < flatNav.length - 1
421
- ? flatNav[currentIndex + 1]
422
- : undefined,
423
- prevPage: currentIndex > 0 ? flatNav[currentIndex - 1] : undefined,
424
- };
425
- };
426
-
427
- const META_DESCRIPTION_MIN = 120;
428
- const META_DESCRIPTION_MAX = 160;
429
- const META_FRONTMATTER_RE = /^---\s*\n[\s\S]*?\n---\s*\n?/;
430
-
431
- /**
432
- * Reduce raw MDX/Markdown to a single line of readable prose so it can seed a
433
- * meta description when a page has no (or a too-short) frontmatter description.
434
- */
435
- const markdownToPlainText = (markdown: string): string =>
436
- markdown
437
- .replace(META_FRONTMATTER_RE, "")
438
- .replaceAll(/```[\s\S]*?```/g, " ")
439
- .replaceAll(/~~~[\s\S]*?~~~/g, " ")
440
- .replaceAll(/`[^`]*`/g, " ")
441
- .replaceAll(/!\[[^\]]*\]\([^)]*\)/g, " ")
442
- .replaceAll(/\[([^\]]+)\]\([^)]*\)/g, "$1")
443
- .replaceAll(/<[^>]+>/g, " ")
444
- .replaceAll(/^\s{0,3}#{1,6}\s+/gm, "")
445
- .replaceAll(/^\s{0,3}>\s?/gm, "")
446
- .replaceAll(/^\s{0,3}(?:[-*+]|\d+\.)\s+/gm, "")
447
- .replaceAll(/[*_~]+/g, "")
448
- .replaceAll("|", " ")
449
- .replaceAll(/\s+/g, " ")
450
- .trim();
451
-
452
- const normalizeMetaText = (value?: string) =>
453
- value ? value.replaceAll(/\s+/g, " ").trim() : "";
454
-
455
- const truncateMetaDescription = (text: string, max: number): string => {
456
- if (text.length <= max) {
457
- return text;
458
- }
459
- const slice = text.slice(0, max - 1);
460
- const lastSpace = slice.lastIndexOf(" ");
461
- const trimmed = (lastSpace > max * 0.6 ? slice.slice(0, lastSpace) : slice)
462
- .replace(/[\s.,;:–—-]+$/, "")
463
- .trim();
464
- return `${trimmed}…`;
465
- };
466
-
467
- /**
468
- * Build a 120-160 character meta description from (in order of preference) the
469
- * frontmatter description, the page body, and a site-level fallback. Keeps the
470
- * visible page subtitle untouched while giving crawlers a complete description.
471
- */
472
- const deriveMetaDescription = ({
473
- description,
474
- rawText,
475
- fallback,
476
- }: {
477
- description?: string;
478
- rawText?: string;
479
- fallback?: string;
480
- }): string | undefined => {
481
- const frontmatter = normalizeMetaText(description);
482
- if (frontmatter.length >= META_DESCRIPTION_MIN) {
483
- return truncateMetaDescription(frontmatter, META_DESCRIPTION_MAX);
484
- }
485
-
486
- let combined = frontmatter;
487
- const excerpt = rawText ? markdownToPlainText(rawText) : "";
488
- if (excerpt) {
489
- if (
490
- !frontmatter ||
491
- excerpt.toLowerCase().startsWith(frontmatter.toLowerCase())
492
- ) {
493
- combined = excerpt;
494
- } else if (combined.length < META_DESCRIPTION_MIN) {
495
- combined = `${frontmatter} ${excerpt}`;
496
- }
497
- }
498
-
499
- const fallbackText = normalizeMetaText(fallback);
500
- if (
501
- fallbackText &&
502
- normalizeMetaText(combined).length < META_DESCRIPTION_MIN
503
- ) {
504
- combined = combined ? `${combined} ${fallbackText}` : fallbackText;
505
- }
506
-
507
- combined = normalizeMetaText(combined);
508
- return combined
509
- ? truncateMetaDescription(combined, META_DESCRIPTION_MAX)
510
- : undefined;
511
- };
512
-
513
- const buildMetaDescriptionFallback = (
514
- config: { name?: string; description?: string } | undefined,
515
- title: string | undefined
516
- ): string => {
517
- const name = config?.name ?? "Docs";
518
- const lead = title
519
- ? `${title} — ${name} documentation.`
520
- : `${name} documentation.`;
521
- return config?.description ? `${lead} ${config.description}` : lead;
522
- };
523
-
524
- /**
525
- * Returns shell data (config, nav, title, breadcrumbs) from cached artifacts
526
- * without compiling MDX. Used by the page component to render the shell
527
- * immediately while streaming content.
528
- */
529
- export const getDocShellData = cache(
530
- // oxlint-disable-next-line eslint/complexity
531
- async (tenantSlug: string, slugKey: string) => {
532
- const artifacts = await getTenantArtifacts(tenantSlug);
533
- if (
534
- !artifacts ||
535
- isConfigErrorResult(artifacts) ||
536
- isUnpublishedTenantResult(artifacts)
537
- ) {
538
- return artifacts;
539
- }
540
-
541
- const currentPath = normalizePath(slugKey) || "index";
542
- const activeTabIndex = artifacts.tabs
543
- ? findActiveTabIndex(artifacts.tabs, currentPath)
544
- : 0;
545
- const activeTabNav = artifacts.tabs
546
- ? getVisibleNavigation(artifacts.tabs[activeTabIndex]?.entries ?? [])
547
- : null;
548
- const activeTabFlatNav = activeTabNav ? flattenNav(activeTabNav) : null;
549
- const effectiveFlatNav = activeTabFlatNav ?? artifacts.visibleFlatNav;
550
-
551
- const openApiEntry = artifacts.registry.bySlug.get(currentPath);
552
- if (openApiEntry) {
553
- const isHidden = artifacts.flatNav.some(
554
- (page) => page.path === currentPath && page.hidden
555
- );
556
- return {
557
- activeTabIndex,
558
- anchors: artifacts.anchors,
559
- breadcrumbs: findBreadcrumbs(
560
- activeTabNav ?? artifacts.visibleNav,
561
- currentPath
562
- ),
563
- config: artifacts.config,
564
- currentPath,
565
- deprecated: false,
566
- hidden: isHidden,
567
- hideFooterPagination: false,
568
- kind: "openapi" as const,
569
- metaDescription: deriveMetaDescription({
570
- description: openApiEntry.operation.description,
571
- fallback: buildMetaDescriptionFallback(
572
- artifacts.config,
573
- openApiEntry.operation.summary ?? openApiEntry.identifier
574
- ),
575
- }),
576
- mode: undefined as PageMode | undefined,
577
- nav: activeTabNav ?? artifacts.visibleNav,
578
- nextPage: computePrevNext(effectiveFlatNav, currentPath).nextPage,
579
- noindex: false,
580
- openApiEntry,
581
- openapiProxyEnabled: artifacts.config.openapiProxy?.enabled ?? false,
582
- pageDescription: openApiEntry.operation.description,
583
- pageTitle: openApiEntry.operation.summary ?? openApiEntry.identifier,
584
- prevPage: computePrevNext(effectiveFlatNav, currentPath).prevPage,
585
- tabs: artifacts.tabs,
586
- tenant: artifacts.tenant,
587
- };
588
- }
589
-
590
- const entry = artifacts.contentIndex.bySlug.get(currentPath) ?? null;
591
- if (!entry) {
592
- return null;
593
- }
594
-
595
- if (entry.kind === "index") {
596
- const collectionEntries =
597
- artifacts.contentIndex.byCollection
598
- .get(entry.collectionId)
599
- ?.filter(
600
- (
601
- collectionEntry
602
- ): collectionEntry is Extract<
603
- (typeof artifacts.contentIndex.entries)[number],
604
- { kind: "entry" }
605
- > =>
606
- collectionEntry.kind === "entry" &&
607
- collectionEntry.hidden !== true &&
608
- !artifacts.pageMetadataMap.get(collectionEntry.slug)?.hidden &&
609
- !artifacts.pageMetadataMap.get(collectionEntry.slug)?.noindex
610
- ) ?? [];
611
- const showDocsNav = entry.type === "docs";
612
- return {
613
- activeTabIndex,
614
- anchors: showDocsNav ? artifacts.anchors : [],
615
- breadcrumbs: [] as { label: string; path: string }[],
616
- collectionIndex: { entries: collectionEntries },
617
- config: artifacts.config,
618
- currentPath,
619
- deprecated: false,
620
- hidden: false,
621
- hideFooterPagination: false,
622
- kind: "index" as const,
623
- metaDescription: deriveMetaDescription({
624
- description: entry.description,
625
- fallback: buildMetaDescriptionFallback(artifacts.config, entry.title),
626
- }),
627
- mode: undefined as PageMode | undefined,
628
- nav: showDocsNav ? (activeTabNav ?? artifacts.visibleNav) : [],
629
- nextPage: computePrevNext(effectiveFlatNav, currentPath).nextPage,
630
- noindex: false,
631
- pageDescription: entry.description,
632
- pageTitle: entry.title,
633
- prevPage: computePrevNext(effectiveFlatNav, currentPath).prevPage,
634
- tabs: artifacts.tabs,
635
- tenant: artifacts.tenant,
636
- };
637
- }
638
-
639
- const showDocsNav = entry.type === "docs";
640
- const breadcrumbs = showDocsNav
641
- ? findBreadcrumbs(activeTabNav ?? artifacts.visibleNav, currentPath)
642
- : [];
643
- const pageMeta = artifacts.pageMetadataMap.get(currentPath);
644
- const isHiddenByNav = artifacts.flatNav.some(
645
- (page) => page.path === currentPath && page.hidden
646
- );
647
- const { nextPage, prevPage } = computePrevNext(
648
- effectiveFlatNav,
649
- currentPath
650
- );
651
- const useToc =
652
- entry.type === "docs" && artifacts.config.features?.toc !== false;
653
-
654
- const prebuiltToc = artifacts.tocBySlug.get(currentPath) ?? null;
655
- const needsRawContent = artifacts.config.contextual
656
- ? contextualOptionsRequirePageContent(artifacts.config.contextual.options)
657
- : false;
658
-
659
- // Load the body when we need a TOC, contextual content, or a body excerpt
660
- // to flesh out a short/missing frontmatter description for SEO.
661
- const needsExcerpt = (entry.description ?? "").trim().length < 120;
662
- let rawContent: string | undefined;
663
- let toc: ReturnType<typeof extractToc> = prebuiltToc ?? [];
664
- if ((!prebuiltToc && useToc) || needsRawContent || needsExcerpt) {
665
- try {
666
- rawContent = await artifacts.contentSource.readFile(entry.relativePath);
667
- if (!prebuiltToc && useToc) {
668
- toc = extractToc(rawContent);
669
- }
670
- } catch {
671
- // Content load failure is handled by the content rendering path
672
- }
673
- }
674
-
675
- return {
676
- activeTabIndex,
677
- anchors: showDocsNav ? artifacts.anchors : [],
678
- breadcrumbs,
679
- config: artifacts.config,
680
- currentPath,
681
- deprecated: pageMeta?.deprecated ?? false,
682
- hidden: isHiddenByNav || entry.hidden === true,
683
- hideFooterPagination: pageMeta?.hideFooterPagination ?? false,
684
- kind: "page" as const,
685
- metaDescription: deriveMetaDescription({
686
- description: entry.description,
687
- fallback: buildMetaDescriptionFallback(artifacts.config, entry.title),
688
- rawText: rawContent,
689
- }),
690
- mode: pageMeta?.mode,
691
- nav: showDocsNav ? (activeTabNav ?? artifacts.visibleNav) : [],
692
- nextPage,
693
- noindex: pageMeta?.noindex ?? false,
694
- pageDescription: entry.description,
695
- pageTitle: entry.title,
696
- prevPage,
697
- rawContent,
698
- tabs: artifacts.tabs,
699
- tenant: artifacts.tenant,
700
- toc,
701
- };
702
- }
703
- );
704
-
705
- /**
706
- * Compiles MDX content for a specific page. Uses pre-compiled content
707
- * from deploy when available, otherwise falls back to runtime compilation.
708
- */
709
- export const getDocPageContent = cache(
710
- async (
711
- tenantSlug: string,
712
- slugKey: string,
713
- basePath = "",
714
- rawContent?: string,
715
- toc?: TocItem[]
716
- ) => {
717
- const artifacts = await getTenantArtifacts(tenantSlug);
718
- if (
719
- !artifacts ||
720
- isConfigErrorResult(artifacts) ||
721
- isUnpublishedTenantResult(artifacts)
722
- ) {
723
- return null;
724
- }
725
-
726
- const currentPath = normalizePath(slugKey) || "index";
727
- const entry = artifacts.contentIndex.bySlug.get(currentPath) ?? null;
728
- if (!entry || entry.kind !== "entry") {
729
- return null;
730
- }
731
-
732
- const useToc =
733
- entry.type === "docs" && artifacts.config.features?.toc !== false;
734
-
735
- return await getRenderedPageData({
736
- artifacts,
737
- basePath,
738
- currentPath,
739
- rawContent,
740
- relativePath: entry.relativePath,
741
- toc,
742
- useToc,
743
- });
744
- }
745
- );