blodemd 0.0.5 → 0.0.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 (187) hide show
  1. package/README.md +2 -2
  2. package/dev-server/app/[[...slug]]/page.tsx +139 -0
  3. package/dev-server/app/blodemd-dev/invalidate/route.ts +12 -0
  4. package/dev-server/app/blodemd-dev/static/[...path]/route.ts +32 -0
  5. package/dev-server/app/blodemd-dev/version/route.ts +14 -0
  6. package/dev-server/app/blodemd-internal/proxy/route.ts +86 -0
  7. package/dev-server/app/error.tsx +24 -0
  8. package/dev-server/app/favicon.ico +0 -0
  9. package/dev-server/app/globals.css +4 -0
  10. package/dev-server/app/layout.tsx +38 -0
  11. package/dev-server/app/not-found.tsx +18 -0
  12. package/dev-server/app/search/route.ts +17 -0
  13. package/dev-server/components/dev-reload-script.tsx +86 -0
  14. package/dev-server/components/providers.tsx +15 -0
  15. package/dev-server/lib/dev-state.ts +8 -0
  16. package/dev-server/lib/local-content-source.ts +103 -0
  17. package/dev-server/lib/local-runtime.tsx +558 -0
  18. package/dev-server/next-env.d.ts +5 -0
  19. package/dev-server/next.config.js +46 -0
  20. package/dev-server/package.json +57 -0
  21. package/dev-server/postcss.config.mjs +7 -0
  22. package/dev-server/public/glide-variable.woff2 +0 -0
  23. package/dev-server/tsconfig.json +50 -0
  24. package/dist/cli.mjs +311 -86
  25. package/dist/cli.mjs.map +1 -1
  26. package/docs/app/globals.css +457 -0
  27. package/docs/components/api/api-playground.tsx +295 -0
  28. package/docs/components/api/api-reference.tsx +121 -0
  29. package/docs/components/content/collection-index.tsx +114 -0
  30. package/docs/components/docs/contextual-menu.tsx +406 -0
  31. package/docs/components/docs/copy-page-menu.tsx +255 -0
  32. package/docs/components/docs/doc-header.tsx +210 -0
  33. package/docs/components/docs/doc-shell.tsx +313 -0
  34. package/docs/components/docs/doc-sidebar.tsx +211 -0
  35. package/docs/components/docs/doc-toc.tsx +45 -0
  36. package/docs/components/docs/mobile-nav.tsx +205 -0
  37. package/docs/components/icons/doc-icon.tsx +96 -0
  38. package/docs/components/mdx/accordion.tsx +83 -0
  39. package/docs/components/mdx/badge.tsx +79 -0
  40. package/docs/components/mdx/callout.tsx +88 -0
  41. package/docs/components/mdx/card.tsx +110 -0
  42. package/docs/components/mdx/code-block.tsx +75 -0
  43. package/docs/components/mdx/code-group.tsx +94 -0
  44. package/docs/components/mdx/color.tsx +87 -0
  45. package/docs/components/mdx/columns.tsx +25 -0
  46. package/docs/components/mdx/expandable.tsx +45 -0
  47. package/docs/components/mdx/field-layout.tsx +77 -0
  48. package/docs/components/mdx/frame.tsx +23 -0
  49. package/docs/components/mdx/get-text-content.ts +18 -0
  50. package/docs/components/mdx/icon.tsx +12 -0
  51. package/docs/components/mdx/index.tsx +107 -0
  52. package/docs/components/mdx/installer.tsx +20 -0
  53. package/docs/components/mdx/panel.tsx +11 -0
  54. package/docs/components/mdx/param-field.tsx +56 -0
  55. package/docs/components/mdx/preview.tsx +36 -0
  56. package/docs/components/mdx/prompt.tsx +63 -0
  57. package/docs/components/mdx/request-example.tsx +27 -0
  58. package/docs/components/mdx/response-field.tsx +42 -0
  59. package/docs/components/mdx/steps.tsx +92 -0
  60. package/docs/components/mdx/tabs.tsx +88 -0
  61. package/docs/components/mdx/tile.tsx +43 -0
  62. package/docs/components/mdx/tooltip.tsx +71 -0
  63. package/docs/components/mdx/tree.tsx +120 -0
  64. package/docs/components/mdx/type-table.tsx +71 -0
  65. package/docs/components/mdx/update.tsx +44 -0
  66. package/docs/components/mdx/video.tsx +12 -0
  67. package/docs/components/mdx/view.tsx +66 -0
  68. package/docs/components/providers.tsx +15 -0
  69. package/docs/components/ui/breadcrumb.tsx +92 -0
  70. package/docs/components/ui/button.tsx +90 -0
  71. package/docs/components/ui/card.tsx +92 -0
  72. package/docs/components/ui/command.tsx +139 -0
  73. package/docs/components/ui/dialog.tsx +97 -0
  74. package/docs/components/ui/field.tsx +237 -0
  75. package/docs/components/ui/input.tsx +105 -0
  76. package/docs/components/ui/label.tsx +22 -0
  77. package/docs/components/ui/popover.tsx +72 -0
  78. package/docs/components/ui/search.tsx +384 -0
  79. package/docs/components/ui/separator.tsx +26 -0
  80. package/docs/components/ui/sheet.tsx +104 -0
  81. package/docs/components/ui/sidebar.tsx +433 -0
  82. package/docs/components/ui/theme-toggle.tsx +62 -0
  83. package/docs/components/ui/tooltip.tsx +53 -0
  84. package/docs/lib/contextual-options.ts +193 -0
  85. package/docs/lib/docs-collection.ts +22 -0
  86. package/docs/lib/mdx.ts +87 -0
  87. package/docs/lib/navigation.ts +288 -0
  88. package/docs/lib/openapi.ts +158 -0
  89. package/docs/lib/routes.ts +44 -0
  90. package/docs/lib/server-cache.ts +83 -0
  91. package/docs/lib/shiki.ts +40 -0
  92. package/docs/lib/theme.ts +29 -0
  93. package/docs/lib/toc.ts +2 -0
  94. package/docs/lib/utils.ts +5 -0
  95. package/package.json +43 -6
  96. package/packages/@repo/common/dist/index.d.ts +9 -0
  97. package/packages/@repo/common/dist/index.d.ts.map +1 -0
  98. package/packages/@repo/common/dist/index.js +42 -0
  99. package/packages/@repo/common/package.json +34 -0
  100. package/packages/@repo/common/src/index.ts +51 -0
  101. package/packages/@repo/contracts/dist/api-key.d.ts +30 -0
  102. package/packages/@repo/contracts/dist/api-key.d.ts.map +1 -0
  103. package/packages/@repo/contracts/dist/api-key.js +20 -0
  104. package/packages/@repo/contracts/dist/dates.d.ts +4 -0
  105. package/packages/@repo/contracts/dist/dates.d.ts.map +1 -0
  106. package/packages/@repo/contracts/dist/dates.js +2 -0
  107. package/packages/@repo/contracts/dist/deployment.d.ts +71 -0
  108. package/packages/@repo/contracts/dist/deployment.d.ts.map +1 -0
  109. package/packages/@repo/contracts/dist/deployment.js +46 -0
  110. package/packages/@repo/contracts/dist/domain.d.ts +94 -0
  111. package/packages/@repo/contracts/dist/domain.d.ts.map +1 -0
  112. package/packages/@repo/contracts/dist/domain.js +36 -0
  113. package/packages/@repo/contracts/dist/ids.d.ts +14 -0
  114. package/packages/@repo/contracts/dist/ids.d.ts.map +1 -0
  115. package/packages/@repo/contracts/dist/ids.js +10 -0
  116. package/packages/@repo/contracts/dist/index.d.ts +10 -0
  117. package/packages/@repo/contracts/dist/index.d.ts.map +1 -0
  118. package/packages/@repo/contracts/dist/index.js +11 -0
  119. package/packages/@repo/contracts/dist/pagination.d.ts +23 -0
  120. package/packages/@repo/contracts/dist/pagination.d.ts.map +1 -0
  121. package/packages/@repo/contracts/dist/pagination.js +15 -0
  122. package/packages/@repo/contracts/dist/project.d.ts +25 -0
  123. package/packages/@repo/contracts/dist/project.d.ts.map +1 -0
  124. package/packages/@repo/contracts/dist/project.js +23 -0
  125. package/packages/@repo/contracts/dist/tenant.d.ts +111 -0
  126. package/packages/@repo/contracts/dist/tenant.d.ts.map +1 -0
  127. package/packages/@repo/contracts/dist/tenant.js +56 -0
  128. package/packages/@repo/contracts/dist/user.d.ts +9 -0
  129. package/packages/@repo/contracts/dist/user.d.ts.map +1 -0
  130. package/packages/@repo/contracts/dist/user.js +9 -0
  131. package/packages/@repo/contracts/package.json +37 -0
  132. package/packages/@repo/contracts/src/api-key.ts +27 -0
  133. package/packages/@repo/contracts/src/dates.ts +4 -0
  134. package/packages/@repo/contracts/src/deployment.ts +73 -0
  135. package/packages/@repo/contracts/src/domain.ts +51 -0
  136. package/packages/@repo/contracts/src/ids.ts +22 -0
  137. package/packages/@repo/contracts/src/index.ts +11 -0
  138. package/packages/@repo/contracts/src/pagination.ts +21 -0
  139. package/packages/@repo/contracts/src/project.ts +30 -0
  140. package/packages/@repo/contracts/src/tenant.ts +92 -0
  141. package/packages/@repo/contracts/src/user.ts +12 -0
  142. package/packages/@repo/models/dist/docs-config.d.ts +985 -0
  143. package/packages/@repo/models/dist/docs-config.d.ts.map +1 -0
  144. package/packages/@repo/models/dist/docs-config.js +548 -0
  145. package/packages/@repo/models/dist/index.d.ts +3 -0
  146. package/packages/@repo/models/dist/index.d.ts.map +1 -0
  147. package/packages/@repo/models/dist/index.js +3 -0
  148. package/packages/@repo/models/dist/tenant.d.ts +25 -0
  149. package/packages/@repo/models/dist/tenant.d.ts.map +1 -0
  150. package/packages/@repo/models/dist/tenant.js +1 -0
  151. package/packages/@repo/models/package.json +37 -0
  152. package/packages/@repo/models/src/docs-config.ts +648 -0
  153. package/packages/@repo/models/src/index.ts +3 -0
  154. package/packages/@repo/models/src/tenant.ts +29 -0
  155. package/packages/@repo/prebuild/dist/index.d.ts +2 -0
  156. package/packages/@repo/prebuild/dist/index.d.ts.map +1 -0
  157. package/packages/@repo/prebuild/dist/index.js +2 -0
  158. package/packages/@repo/prebuild/dist/openapi.d.ts +43 -0
  159. package/packages/@repo/prebuild/dist/openapi.d.ts.map +1 -0
  160. package/packages/@repo/prebuild/dist/openapi.js +58 -0
  161. package/packages/@repo/prebuild/package.json +39 -0
  162. package/packages/@repo/prebuild/src/index.ts +2 -0
  163. package/packages/@repo/prebuild/src/openapi.ts +116 -0
  164. package/packages/@repo/previewing/dist/blob-source.d.ts +16 -0
  165. package/packages/@repo/previewing/dist/blob-source.d.ts.map +1 -0
  166. package/packages/@repo/previewing/dist/blob-source.js +110 -0
  167. package/packages/@repo/previewing/dist/content-source.d.ts +12 -0
  168. package/packages/@repo/previewing/dist/content-source.d.ts.map +1 -0
  169. package/packages/@repo/previewing/dist/content-source.js +1 -0
  170. package/packages/@repo/previewing/dist/fs-source.d.ts +11 -0
  171. package/packages/@repo/previewing/dist/fs-source.d.ts.map +1 -0
  172. package/packages/@repo/previewing/dist/fs-source.js +72 -0
  173. package/packages/@repo/previewing/dist/index.d.ts +120 -0
  174. package/packages/@repo/previewing/dist/index.d.ts.map +1 -0
  175. package/packages/@repo/previewing/dist/index.js +984 -0
  176. package/packages/@repo/previewing/package.json +41 -0
  177. package/packages/@repo/previewing/src/blob-source.ts +167 -0
  178. package/packages/@repo/previewing/src/content-source.ts +12 -0
  179. package/packages/@repo/previewing/src/fs-source.ts +104 -0
  180. package/packages/@repo/previewing/src/index.ts +1490 -0
  181. package/packages/@repo/validation/dist/index.d.ts +12 -0
  182. package/packages/@repo/validation/dist/index.d.ts.map +1 -0
  183. package/packages/@repo/validation/dist/index.js +30 -0
  184. package/packages/@repo/validation/package.json +37 -0
  185. package/packages/@repo/validation/src/index.ts +59 -0
  186. package/packages/@repo/validation/src/mintlify-docs-schema.json +5016 -0
  187. package/scripts/prepare-package.mjs +39 -0
@@ -0,0 +1,558 @@
1
+ import { createPreviewContentSource } from "@dev/lib/local-content-source";
2
+ import { normalizePath } from "@repo/common";
3
+ import type { PageMode, SiteConfig } from "@repo/models";
4
+ import {
5
+ buildContentIndex,
6
+ buildPageMetadataMap,
7
+ loadContentSource,
8
+ loadSiteConfig,
9
+ } from "@repo/previewing";
10
+ import type {
11
+ ContentIndex,
12
+ ContentSource,
13
+ PageMetadata,
14
+ } from "@repo/previewing";
15
+
16
+ import {
17
+ getDocsCollection,
18
+ getDocsCollectionWithNavigation,
19
+ getDocsNavigation,
20
+ } from "@/lib/docs-collection";
21
+ import { renderMdx } from "@/lib/mdx";
22
+ import {
23
+ buildNavigation,
24
+ buildTabbedNavigation,
25
+ enrichNavWithMetadata,
26
+ findActiveTabIndex,
27
+ findBreadcrumbs,
28
+ flattenNav,
29
+ getVisibleNavigation,
30
+ } from "@/lib/navigation";
31
+ import type { NavEntry, NavPage, NavTab } from "@/lib/navigation";
32
+ import { buildOpenApiRegistry } from "@/lib/openapi";
33
+ import type { OpenApiRegistry } from "@/lib/openapi";
34
+ import { createTimedPromiseCache } from "@/lib/server-cache";
35
+ import { extractToc } from "@/lib/toc";
36
+
37
+ interface SearchItem {
38
+ href?: string;
39
+ path: string;
40
+ title: string;
41
+ }
42
+
43
+ interface ConfigErrorResult {
44
+ configErrors: string[];
45
+ configWarnings: string[];
46
+ }
47
+
48
+ interface RenderedPageData {
49
+ content: Awaited<ReturnType<typeof renderMdx>>["content"];
50
+ frontmatter: Awaited<ReturnType<typeof renderMdx>>["frontmatter"];
51
+ rawContent: string;
52
+ toc: ReturnType<typeof extractToc>;
53
+ }
54
+
55
+ interface PreviewArtifacts {
56
+ anchors: { href: string; label: string }[];
57
+ config: SiteConfig;
58
+ contentIndex: ContentIndex;
59
+ contentSource: ContentSource;
60
+ flatNav: NavPage[];
61
+ pageMetadataMap: Map<string, PageMetadata>;
62
+ registry: OpenApiRegistry;
63
+ searchItems: SearchItem[];
64
+ tabs: NavTab[] | null;
65
+ visibleFlatNav: NavPage[];
66
+ visibleNav: NavEntry[];
67
+ }
68
+
69
+ type PreviewArtifactsResult = ConfigErrorResult | PreviewArtifacts | null;
70
+
71
+ const ARTIFACT_CACHE_TTL_MS = 5 * 60 * 1000;
72
+ const PAGE_RENDER_CACHE_TTL_MS = 5 * 60 * 1000;
73
+ const USE_LOCAL_RUNTIME_CACHE = false;
74
+
75
+ const artifactsCache = createTimedPromiseCache<string, PreviewArtifactsResult>({
76
+ maxEntries: 32,
77
+ ttlMs: ARTIFACT_CACHE_TTL_MS,
78
+ });
79
+
80
+ const renderedPageCache = createTimedPromiseCache<string, RenderedPageData>({
81
+ maxEntries: 512,
82
+ ttlMs: PAGE_RENDER_CACHE_TTL_MS,
83
+ });
84
+
85
+ const ABSOLUTE_URL_REGEX = /^https?:\/\//i;
86
+
87
+ const isConfigErrorResult = (
88
+ value: PreviewArtifactsResult
89
+ ): value is ConfigErrorResult => Boolean(value && "configErrors" in value);
90
+
91
+ const resolveAssetUrl = async (
92
+ source: ContentSource,
93
+ value?: string
94
+ ): Promise<string | undefined> => {
95
+ if (!value || value.startsWith("/") || ABSOLUTE_URL_REGEX.test(value)) {
96
+ return value;
97
+ }
98
+
99
+ const resolved = await source.resolveUrl?.(value);
100
+ return resolved ?? value;
101
+ };
102
+
103
+ const resolveSiteConfigAssets = async (
104
+ config: SiteConfig,
105
+ source: ContentSource
106
+ ): Promise<SiteConfig> => ({
107
+ ...config,
108
+ favicon: await resolveAssetUrl(source, config.favicon),
109
+ fonts: config.fonts
110
+ ? {
111
+ ...config.fonts,
112
+ cssUrl: await resolveAssetUrl(source, config.fonts.cssUrl),
113
+ }
114
+ : config.fonts,
115
+ logo: config.logo
116
+ ? {
117
+ ...config.logo,
118
+ dark: await resolveAssetUrl(source, config.logo.dark),
119
+ light: await resolveAssetUrl(source, config.logo.light),
120
+ }
121
+ : config.logo,
122
+ metadata: config.metadata
123
+ ? {
124
+ ...config.metadata,
125
+ ogImage: await resolveAssetUrl(source, config.metadata.ogImage),
126
+ }
127
+ : config.metadata,
128
+ });
129
+
130
+ const buildSearchItems = ({
131
+ config,
132
+ contentIndex,
133
+ flatNav,
134
+ pageMetadataMap,
135
+ visibleFlatNav,
136
+ }: {
137
+ config: SiteConfig;
138
+ contentIndex: ContentIndex;
139
+ flatNav: NavPage[];
140
+ pageMetadataMap: Map<string, PageMetadata>;
141
+ visibleFlatNav: NavPage[];
142
+ }): SearchItem[] => {
143
+ const indexAll = config.seo?.indexing === "all";
144
+ const searchItems = new Map<string, SearchItem>();
145
+
146
+ const shouldAddSearchItem = (
147
+ entry: (typeof contentIndex.entries)[number]
148
+ ): boolean => {
149
+ const pageMeta = pageMetadataMap.get(entry.slug);
150
+
151
+ if (pageMeta?.hidden || pageMeta?.noindex) {
152
+ return false;
153
+ }
154
+
155
+ if (!indexAll && entry.kind === "entry" && entry.hidden) {
156
+ return false;
157
+ }
158
+
159
+ return true;
160
+ };
161
+
162
+ for (const item of visibleFlatNav) {
163
+ searchItems.set(item.path, {
164
+ href: item.url,
165
+ path: item.path,
166
+ title: item.sidebarTitle ?? item.title,
167
+ });
168
+ }
169
+
170
+ for (const entry of contentIndex.entries) {
171
+ if (!shouldAddSearchItem(entry)) {
172
+ continue;
173
+ }
174
+
175
+ const pageMeta = pageMetadataMap.get(entry.slug);
176
+ searchItems.set(entry.slug, {
177
+ href: pageMeta?.url,
178
+ path: entry.slug,
179
+ title: pageMeta?.sidebarTitle ?? entry.title,
180
+ });
181
+ }
182
+
183
+ if (indexAll) {
184
+ for (const item of flatNav) {
185
+ if (!searchItems.has(item.path)) {
186
+ searchItems.set(item.path, {
187
+ href: item.url,
188
+ path: item.path,
189
+ title: item.sidebarTitle ?? item.title,
190
+ });
191
+ }
192
+ }
193
+ }
194
+
195
+ return [...searchItems.values()];
196
+ };
197
+
198
+ const buildArtifacts = async (): Promise<PreviewArtifactsResult> => {
199
+ const contentSource = createPreviewContentSource();
200
+ const configResult = await loadSiteConfig(contentSource);
201
+
202
+ if (!configResult.ok) {
203
+ return {
204
+ configErrors: configResult.errors,
205
+ configWarnings: [],
206
+ };
207
+ }
208
+
209
+ const rawConfig = configResult.config;
210
+ const docsCollection = getDocsCollection(rawConfig);
211
+ const docsNavigation = getDocsNavigation(rawConfig);
212
+ const docsCollectionWithNavigation =
213
+ getDocsCollectionWithNavigation(rawConfig);
214
+
215
+ const [config, contentIndex, registryResult] = await Promise.all([
216
+ resolveSiteConfigAssets(rawConfig, contentSource),
217
+ buildContentIndex(contentSource, rawConfig),
218
+ buildOpenApiRegistry(docsCollectionWithNavigation, contentSource)
219
+ .then((registry) => ({ ok: true as const, registry }))
220
+ .catch((error: unknown) => ({ error, ok: false as const })),
221
+ ]);
222
+
223
+ if (contentIndex.errors.length) {
224
+ return {
225
+ configErrors: contentIndex.errors,
226
+ configWarnings: configResult.warnings,
227
+ };
228
+ }
229
+
230
+ if (!registryResult.ok) {
231
+ return {
232
+ configErrors: [
233
+ registryResult.error instanceof Error
234
+ ? registryResult.error.message
235
+ : "OpenAPI parsing failed.",
236
+ ],
237
+ configWarnings: configResult.warnings,
238
+ };
239
+ }
240
+
241
+ const pageMetadataMap = buildPageMetadataMap(contentIndex);
242
+ const slugPrefix = docsCollection?.slugPrefix ?? "";
243
+ const rawNav = docsNavigation
244
+ ? buildNavigation(docsNavigation, registryResult.registry, slugPrefix)
245
+ : [];
246
+ const nav = enrichNavWithMetadata(rawNav, pageMetadataMap);
247
+ const visibleNav = getVisibleNavigation(nav);
248
+ const flatNav = flattenNav(nav);
249
+ const visibleFlatNav = flattenNav(visibleNav);
250
+ const rawTabs = buildTabbedNavigation(
251
+ docsNavigation,
252
+ registryResult.registry,
253
+ slugPrefix
254
+ );
255
+ const tabs =
256
+ rawTabs?.map((tab) => ({
257
+ ...tab,
258
+ entries: enrichNavWithMetadata(tab.entries, pageMetadataMap),
259
+ })) ?? null;
260
+
261
+ return {
262
+ anchors: docsNavigation?.global?.anchors ?? [],
263
+ config,
264
+ contentIndex,
265
+ contentSource,
266
+ flatNav,
267
+ pageMetadataMap,
268
+ registry: registryResult.registry,
269
+ searchItems: buildSearchItems({
270
+ config,
271
+ contentIndex,
272
+ flatNav,
273
+ pageMetadataMap,
274
+ visibleFlatNav,
275
+ }),
276
+ tabs,
277
+ visibleFlatNav,
278
+ visibleNav,
279
+ };
280
+ };
281
+
282
+ const getArtifacts = async () =>
283
+ USE_LOCAL_RUNTIME_CACHE
284
+ ? await artifactsCache.getOrCreate("preview", buildArtifacts)
285
+ : await buildArtifacts();
286
+
287
+ const buildRenderedPageData = async ({
288
+ artifacts,
289
+ relativePath,
290
+ useToc,
291
+ }: {
292
+ artifacts: PreviewArtifacts;
293
+ relativePath: string;
294
+ useToc: boolean;
295
+ }): Promise<RenderedPageData> => {
296
+ const rawContent = await loadContentSource(
297
+ artifacts.contentSource,
298
+ relativePath
299
+ );
300
+ const { content, frontmatter } = await renderMdx(rawContent);
301
+
302
+ return {
303
+ content,
304
+ frontmatter,
305
+ rawContent,
306
+ toc: useToc ? extractToc(rawContent) : [],
307
+ };
308
+ };
309
+
310
+ const getRenderedPageData = async ({
311
+ artifacts,
312
+ currentPath,
313
+ relativePath,
314
+ useToc,
315
+ }: {
316
+ artifacts: PreviewArtifacts;
317
+ currentPath: string;
318
+ relativePath: string;
319
+ useToc: boolean;
320
+ }) =>
321
+ USE_LOCAL_RUNTIME_CACHE
322
+ ? await renderedPageCache.getOrCreate(
323
+ currentPath,
324
+ async () =>
325
+ await buildRenderedPageData({
326
+ artifacts,
327
+ relativePath,
328
+ useToc,
329
+ })
330
+ )
331
+ : await buildRenderedPageData({
332
+ artifacts,
333
+ relativePath,
334
+ useToc,
335
+ });
336
+
337
+ const computePrevNext = (
338
+ flatNav: NavPage[],
339
+ currentPath: string
340
+ ): {
341
+ nextPage: { path: string; title: string } | undefined;
342
+ prevPage: { path: string; title: string } | undefined;
343
+ } => {
344
+ const currentIndex = flatNav.findIndex((page) => page.path === currentPath);
345
+
346
+ return {
347
+ nextPage:
348
+ currentIndex !== -1 && currentIndex < flatNav.length - 1
349
+ ? flatNav[currentIndex + 1]
350
+ : undefined,
351
+ prevPage: currentIndex > 0 ? flatNav[currentIndex - 1] : undefined,
352
+ };
353
+ };
354
+
355
+ export const clearLocalRuntimeCaches = () => {
356
+ if (!USE_LOCAL_RUNTIME_CACHE) {
357
+ return;
358
+ }
359
+
360
+ artifactsCache.clear();
361
+ renderedPageCache.clear();
362
+ };
363
+
364
+ export const getSearchItems = async () => {
365
+ const artifacts = await getArtifacts();
366
+
367
+ if (!artifacts || isConfigErrorResult(artifacts)) {
368
+ return [];
369
+ }
370
+
371
+ return artifacts.searchItems;
372
+ };
373
+
374
+ export const getOpenApiProxyContext = async (): Promise<{
375
+ config: SiteConfig;
376
+ registry: OpenApiRegistry;
377
+ } | null> => {
378
+ const artifacts = await getArtifacts();
379
+
380
+ if (!artifacts || isConfigErrorResult(artifacts)) {
381
+ return null;
382
+ }
383
+
384
+ return {
385
+ config: artifacts.config,
386
+ registry: artifacts.registry,
387
+ };
388
+ };
389
+
390
+ // oxlint-disable-next-line eslint/complexity
391
+ export const getDocShellData = async (slugKey: string) => {
392
+ const artifacts = await getArtifacts();
393
+
394
+ if (!artifacts || isConfigErrorResult(artifacts)) {
395
+ return artifacts;
396
+ }
397
+
398
+ const currentPath = normalizePath(slugKey) || "index";
399
+ const activeTabIndex = artifacts.tabs
400
+ ? findActiveTabIndex(artifacts.tabs, currentPath)
401
+ : 0;
402
+ const activeTabNav = artifacts.tabs
403
+ ? getVisibleNavigation(artifacts.tabs[activeTabIndex]?.entries ?? [])
404
+ : null;
405
+ const activeTabFlatNav = activeTabNav ? flattenNav(activeTabNav) : null;
406
+ const effectiveFlatNav = activeTabFlatNav ?? artifacts.visibleFlatNav;
407
+
408
+ const openApiEntry = artifacts.registry.bySlug.get(currentPath);
409
+ if (openApiEntry) {
410
+ const isHidden = artifacts.flatNav.some(
411
+ (page) => page.path === currentPath && page.hidden
412
+ );
413
+
414
+ return {
415
+ activeTabIndex,
416
+ anchors: artifacts.anchors,
417
+ breadcrumbs: findBreadcrumbs(
418
+ activeTabNav ?? artifacts.visibleNav,
419
+ currentPath
420
+ ),
421
+ config: artifacts.config,
422
+ currentPath,
423
+ deprecated: false,
424
+ hidden: isHidden,
425
+ hideFooterPagination: false,
426
+ kind: "openapi" as const,
427
+ mode: undefined as PageMode | undefined,
428
+ nav: activeTabNav ?? artifacts.visibleNav,
429
+ nextPage: computePrevNext(effectiveFlatNav, currentPath).nextPage,
430
+ noindex: false,
431
+ openApiEntry,
432
+ openapiProxyEnabled: artifacts.config.openapiProxy?.enabled ?? false,
433
+ pageDescription: openApiEntry.operation.description,
434
+ pageTitle: openApiEntry.operation.summary ?? openApiEntry.identifier,
435
+ prevPage: computePrevNext(effectiveFlatNav, currentPath).prevPage,
436
+ tabs: artifacts.tabs,
437
+ };
438
+ }
439
+
440
+ const entry = artifacts.contentIndex.bySlug.get(currentPath) ?? null;
441
+ if (!entry) {
442
+ return null;
443
+ }
444
+
445
+ if (entry.kind === "index") {
446
+ const collectionEntries =
447
+ artifacts.contentIndex.byCollection
448
+ .get(entry.collectionId)
449
+ ?.filter(
450
+ (
451
+ collectionEntry
452
+ ): collectionEntry is Extract<
453
+ (typeof artifacts.contentIndex.entries)[number],
454
+ { kind: "entry" }
455
+ > =>
456
+ collectionEntry.kind === "entry" &&
457
+ collectionEntry.hidden !== true &&
458
+ !artifacts.pageMetadataMap.get(collectionEntry.slug)?.hidden &&
459
+ !artifacts.pageMetadataMap.get(collectionEntry.slug)?.noindex
460
+ ) ?? [];
461
+ const showDocsNav = entry.type === "docs";
462
+
463
+ return {
464
+ activeTabIndex,
465
+ anchors: showDocsNav ? artifacts.anchors : [],
466
+ breadcrumbs: [] as { label: string; path: string }[],
467
+ collectionIndex: { entries: collectionEntries },
468
+ config: artifacts.config,
469
+ currentPath,
470
+ deprecated: false,
471
+ hidden: false,
472
+ hideFooterPagination: false,
473
+ kind: "index" as const,
474
+ mode: undefined as PageMode | undefined,
475
+ nav: showDocsNav ? (activeTabNav ?? artifacts.visibleNav) : [],
476
+ nextPage: computePrevNext(effectiveFlatNav, currentPath).nextPage,
477
+ noindex: false,
478
+ pageDescription: entry.description,
479
+ pageTitle: entry.title,
480
+ prevPage: computePrevNext(effectiveFlatNav, currentPath).prevPage,
481
+ tabs: artifacts.tabs,
482
+ };
483
+ }
484
+
485
+ const showDocsNav = entry.type === "docs";
486
+ const breadcrumbs = showDocsNav
487
+ ? findBreadcrumbs(activeTabNav ?? artifacts.visibleNav, currentPath)
488
+ : [];
489
+ const pageMeta = artifacts.pageMetadataMap.get(currentPath);
490
+ const isHiddenByNav = artifacts.flatNav.some(
491
+ (page) => page.path === currentPath && page.hidden
492
+ );
493
+ const useToc =
494
+ entry.type === "docs" && artifacts.config.features?.toc !== false;
495
+
496
+ let rawContent = "";
497
+ let toc: ReturnType<typeof extractToc> = [];
498
+
499
+ try {
500
+ rawContent = await loadContentSource(
501
+ artifacts.contentSource,
502
+ entry.relativePath
503
+ );
504
+
505
+ if (useToc) {
506
+ toc = extractToc(rawContent);
507
+ }
508
+ } catch {
509
+ // The page rendering path handles read failures.
510
+ }
511
+
512
+ return {
513
+ activeTabIndex,
514
+ anchors: showDocsNav ? artifacts.anchors : [],
515
+ breadcrumbs,
516
+ config: artifacts.config,
517
+ currentPath,
518
+ deprecated: pageMeta?.deprecated ?? false,
519
+ hidden: isHiddenByNav || entry.hidden === true,
520
+ hideFooterPagination: pageMeta?.hideFooterPagination ?? false,
521
+ kind: "page" as const,
522
+ mode: pageMeta?.mode,
523
+ nav: showDocsNav ? (activeTabNav ?? artifacts.visibleNav) : [],
524
+ nextPage: computePrevNext(effectiveFlatNav, currentPath).nextPage,
525
+ noindex: pageMeta?.noindex ?? false,
526
+ pageDescription: entry.description,
527
+ pageTitle: entry.title,
528
+ prevPage: computePrevNext(effectiveFlatNav, currentPath).prevPage,
529
+ rawContent,
530
+ tabs: artifacts.tabs,
531
+ toc,
532
+ };
533
+ };
534
+
535
+ export const getDocPageContent = async (slugKey: string) => {
536
+ const artifacts = await getArtifacts();
537
+
538
+ if (!artifacts || isConfigErrorResult(artifacts)) {
539
+ return null;
540
+ }
541
+
542
+ const currentPath = normalizePath(slugKey) || "index";
543
+ const entry = artifacts.contentIndex.bySlug.get(currentPath) ?? null;
544
+
545
+ if (!entry || entry.kind !== "entry") {
546
+ return null;
547
+ }
548
+
549
+ const useToc =
550
+ entry.type === "docs" && artifacts.config.features?.toc !== false;
551
+
552
+ return await getRenderedPageData({
553
+ artifacts,
554
+ currentPath,
555
+ relativePath: entry.relativePath,
556
+ useToc,
557
+ });
558
+ };
@@ -0,0 +1,5 @@
1
+ /// <reference types="next" />
2
+ /// <reference types="next/image-types/global" />
3
+
4
+ // NOTE: This file should not be edited
5
+ // see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
@@ -0,0 +1,46 @@
1
+ import path from "node:path";
2
+
3
+ // When running in standalone mode (npm-installed CLI), the CLI sets this
4
+ // to the directory containing shipped @repo packages.
5
+ const packagesDir = process.env.BLODEMD_PACKAGES_DIR;
6
+
7
+ /** @type {import('next').NextConfig} */
8
+ const nextConfig = {
9
+ allowedDevOrigins: ["127.0.0.1"],
10
+ experimental: {
11
+ optimizePackageImports: [
12
+ "blode-icons-react",
13
+ "radix-ui",
14
+ "@base-ui/react",
15
+ "cmdk",
16
+ "@repo/previewing",
17
+ "@repo/models",
18
+ "@repo/common",
19
+ ],
20
+ },
21
+ images: {
22
+ unoptimized: true,
23
+ },
24
+ transpilePackages: [
25
+ "@repo/common",
26
+ "@repo/contracts",
27
+ "@repo/models",
28
+ "@repo/prebuild",
29
+ "@repo/previewing",
30
+ "@repo/validation",
31
+ ],
32
+ webpack: (config) => {
33
+ if (packagesDir) {
34
+ // In standalone mode, @repo packages live in the CLI's packages/ dir.
35
+ // Add it as a module resolution root so webpack (and transpilePackages)
36
+ // can resolve @repo/common from packages/@repo/common/.
37
+ config.resolve.modules = [
38
+ path.resolve(packagesDir),
39
+ ...(config.resolve.modules || []),
40
+ ];
41
+ }
42
+ return config;
43
+ },
44
+ };
45
+
46
+ export default nextConfig;
@@ -0,0 +1,57 @@
1
+ {
2
+ "name": "dev-server",
3
+ "version": "0.0.0",
4
+ "private": true,
5
+ "type": "module",
6
+ "scripts": {
7
+ "dev": "next dev --webpack",
8
+ "build": "next build",
9
+ "start": "next start",
10
+ "lint": "oxlint .",
11
+ "lint:fix": "oxlint --fix .",
12
+ "format": "oxfmt --write .",
13
+ "format:check": "oxfmt .",
14
+ "check-types": "next typegen && tsc --noEmit"
15
+ },
16
+ "dependencies": {
17
+ "@base-ui/react": "^1.3.0",
18
+ "@mdx-js/mdx": "^3.1.1",
19
+ "@repo/common": "*",
20
+ "@repo/contracts": "*",
21
+ "@repo/models": "*",
22
+ "@repo/prebuild": "*",
23
+ "@repo/previewing": "*",
24
+ "@shikijs/rehype": "^4.0.2",
25
+ "@tailwindcss/postcss": "^4.2.2",
26
+ "blode-icons-react": "^0.3.10",
27
+ "class-variance-authority": "^0.7.1",
28
+ "clsx": "^2.1.1",
29
+ "cmdk": "^1.1.1",
30
+ "geist": "^1.7.0",
31
+ "next": "16.2.1",
32
+ "next-mdx-remote": "^6.0.0",
33
+ "next-themes": "^0.4.6",
34
+ "radix-ui": "^1.4.3",
35
+ "react": "^19.2.0",
36
+ "react-dom": "^19.2.0",
37
+ "rehype-autolink-headings": "^7.1.0",
38
+ "rehype-slug": "^6.0.0",
39
+ "remark-gfm": "^4.0.0",
40
+ "shadcn": "^4.1.1",
41
+ "shiki": "^4.0.2",
42
+ "tailwind-merge": "^3.5.0",
43
+ "tailwindcss": "^4.2.2",
44
+ "tw-animate-css": "^1.4.0"
45
+ },
46
+ "devDependencies": {
47
+ "@repo/typescript-config": "*",
48
+ "@types/mdx": "^2.0.13",
49
+ "@types/node": "^22.19.15",
50
+ "@types/react": "19.2.14",
51
+ "@types/react-dom": "19.2.3",
52
+ "oxfmt": "^0.42.0",
53
+ "oxlint": "^1.57.0",
54
+ "typescript": "6.0.2",
55
+ "ultracite": "^7.3.2"
56
+ }
57
+ }
@@ -0,0 +1,7 @@
1
+ const config = {
2
+ plugins: {
3
+ "@tailwindcss/postcss": {},
4
+ },
5
+ };
6
+
7
+ export default config;