fumadocs-core 16.15.2 → 16.15.3

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.
@@ -51,7 +51,7 @@ function buildDocuments(indexes) {
51
51
  locale: page.locale
52
52
  });
53
53
  const nextId = () => `${page.id}-${id++}`;
54
- if (page.description) docs.push({
54
+ if (page.description && !data.contents.some((item) => item.content === page.description)) docs.push({
55
55
  id: nextId(),
56
56
  page_id: page.id,
57
57
  tags,
@@ -4,7 +4,7 @@ import { r as StructureOptions } from "../../remark-structure-CnHwvNZr.js";
4
4
  import { t as RemarkHeadingOptions } from "../../remark-heading-DEIzTkU5.js";
5
5
  import { t as RemarkCodeTabOptions } from "../../remark-code-tab-DE_4bdnu.js";
6
6
  import { t as RemarkNpmOptions } from "../../remark-npm-BbpvkJaT.js";
7
- import "../../index-C-fnVAhi.js";
7
+ import "../../index-BhgPrb5p.js";
8
8
  import { t as ResolvePlugins } from "../../util-BDsqOxh3.js";
9
9
  import { Pluggable } from "unified";
10
10
  import { ProcessorOptions } from "@mdx-js/mdx";
@@ -4,7 +4,7 @@ import { r as StructureOptions } from "../../remark-structure-CnHwvNZr.js";
4
4
  import { t as RemarkHeadingOptions } from "../../remark-heading-DEIzTkU5.js";
5
5
  import { t as RemarkCodeTabOptions } from "../../remark-code-tab-DE_4bdnu.js";
6
6
  import { t as RemarkNpmOptions } from "../../remark-npm-BbpvkJaT.js";
7
- import "../../index-C-fnVAhi.js";
7
+ import "../../index-BhgPrb5p.js";
8
8
  import { t as ResolvePlugins } from "../../util-BDsqOxh3.js";
9
9
  import { ProcessorOptions } from "@mdx-js/mdx";
10
10
  //#region src/content/mdx/preset-runtime.d.ts
@@ -1,7 +1,7 @@
1
1
  import { a as Separator, i as Root, n as Item, r as Node, t as Folder } from "./definitions-D8-KI7Uy.js";
2
2
  import { t as Awaitable } from "./types-D89QoQR-.js";
3
3
  import { i as StructuredData } from "./remark-structure-CnHwvNZr.js";
4
- import "./index-C-fnVAhi.js";
4
+ import "./index-BhgPrb5p.js";
5
5
  import { n as I18nConfig } from "./index-DydiXvgS.js";
6
6
  import "./index-DZN5OrTa.js";
7
7
  import { n as SerializedPageTree } from "./index-CdZGMKDG.js";
@@ -13,4 +13,4 @@ import "./codeblock-utils-CyP8qsYv.js";
13
13
  import "./remark-mdx-files-Buvxc-sa.js";
14
14
  import "./remark-mdx-mermaid-C1bCHHc6.js";
15
15
  import "./remark-feedback-block-BxtINXN-.js";
16
- import "./remark-llms-BF5SHW_O.js";
16
+ import "./remark-llms-DxglVo94.js";
@@ -15,6 +15,6 @@ import { i as parseCodeBlockAttributes, n as CodeBlockTabsOptions, r as generate
15
15
  import { a as remarkMdxFiles, r as RemarkMdxFilesOptions } from "../remark-mdx-files-Buvxc-sa.js";
16
16
  import { n as remarkMdxMermaid, t as RemarkMdxMermaidOptions } from "../remark-mdx-mermaid-C1bCHHc6.js";
17
17
  import { n as RemarkFeedbackBlockOptions, r as remarkFeedbackBlock, t as FeedbackBlockProps } from "../remark-feedback-block-BxtINXN-.js";
18
- import { t as LLMsOptions } from "../remark-llms-BF5SHW_O.js";
19
- import "../index-C-fnVAhi.js";
18
+ import { t as LLMsOptions } from "../remark-llms-DxglVo94.js";
19
+ import "../index-BhgPrb5p.js";
20
20
  export { CodeBlockAttributes, type CodeBlockIcon, CodeBlockTabsOptions, FeedbackBlockProps, type LLMsOptions, RehypeCodeOptions, RehypeTOCItemType, RehypeTocOptions, RemarkAdmonitionOptions, RemarkCodeTabOptions, RemarkDirectiveAdmonitionOptions, RemarkFeedbackBlockOptions, type RemarkGfmOptions, RemarkHeadingOptions, RemarkImageOptions, type RemarkMdxFilesOptions, RemarkMdxMermaidOptions, RemarkNpmOptions, RemarkStepsOptions, Stringifier, StringifyOptions, StructureOptions, StructuredData, defaultStringifier, generateCodeBlockTabs, parseCodeBlockAttributes, rehypeCode, rehypeCodeDefaultOptions, rehypeToc, remarkAdmonition, remarkCodeTab, remarkDirectiveAdmonition, remarkFeedbackBlock, remarkGfm, remarkHeading, remarkImage, remarkMdxFiles, remarkMdxMermaid, remarkNpm, remarkSteps, remarkStructure, remarkStructureDefaultOptions, structure, transformerIcon, transformerTab };
@@ -1,2 +1,2 @@
1
- import { n as placeholder, r as remarkLLMs, t as LLMsOptions } from "../remark-llms-BF5SHW_O.js";
1
+ import { n as placeholder, r as remarkLLMs, t as LLMsOptions } from "../remark-llms-DxglVo94.js";
2
2
  export { LLMsOptions, placeholder, remarkLLMs };
@@ -5,7 +5,8 @@ import { defaultHandlers } from "mdast-util-to-markdown";
5
5
  /**
6
6
  * generate `llms.txt` for markdown.
7
7
  */
8
- function remarkLLMs({ as = "_markdown", headingIds = true, _data = false, mdxAsPlaceholder, ...rest } = {}) {
8
+ function remarkLLMs({ as = "_markdown", headingIds = true, _data = false, mdxAsPlaceholder, output = "string", ...rest } = {}) {
9
+ const jsx = output === "function";
9
10
  const stringifier = defaultStringifier({
10
11
  ...rest,
11
12
  filterElement(node) {
@@ -14,12 +15,14 @@ function remarkLLMs({ as = "_markdown", headingIds = true, _data = false, mdxAsP
14
15
  default: return true;
15
16
  }
16
17
  },
17
- stringify(node, parent, state, info, ctx) {
18
- if (mdxAsPlaceholder) switch (node.type) {
18
+ stringify(node, parent, state, info, collect) {
19
+ if (mdxAsPlaceholder && !collect) switch (node.type) {
19
20
  case "mdxJsxFlowElement":
20
21
  case "mdxJsxTextElement": if (node.name && mdxAsPlaceholder.includes(node.name)) return placeholder(node, parent, state, info);
21
22
  }
22
- return rest.stringify?.(node, parent, state, info, ctx);
23
+ const custom = rest.stringify?.(node, parent, state, info, void 0);
24
+ if (custom) return custom;
25
+ if (collect) return collectJsx(node, state, info, collect);
23
26
  },
24
27
  handlers: {
25
28
  heading(node, _p, state, info) {
@@ -31,6 +34,12 @@ function remarkLLMs({ as = "_markdown", headingIds = true, _data = false, mdxAsP
31
34
  }
32
35
  });
33
36
  return (node, file) => {
37
+ if (jsx) {
38
+ const collect = [];
39
+ const text = stringifier.call(this, node, collect);
40
+ node.children.unshift(jsxToEstree(as, toJsxChunks(text, collect)));
41
+ return;
42
+ }
34
43
  const value = stringifier.call(this, node, void 0);
35
44
  node.children.unshift(toMdxExport(as, value));
36
45
  if (_data) file.data.markdown = value;
@@ -51,5 +60,279 @@ function placeholder(node, _parent, state, info) {
51
60
  attributes
52
61
  })}\0`;
53
62
  }
63
+ /**
64
+ * `stringify` branch for the `function` output: collect the element and return a marker,
65
+ * resolved later by `toJsxChunks()`. Only components (capitalized names) are kept.
66
+ */
67
+ function collectJsx(node, state, info, collect) {
68
+ switch (node.type) {
69
+ case "mdxJsxFlowElement":
70
+ case "mdxJsxTextElement": {
71
+ if (!node.name || !/^[A-Z][\w$]*$/.test(node.name)) return;
72
+ const entry = {
73
+ node,
74
+ children: ""
75
+ };
76
+ const marker = `\0${collect.push(entry) - 1}\0`;
77
+ entry.children = node.type === "mdxJsxTextElement" ? state.containerPhrasing(node, info) : state.containerFlow(node, info);
78
+ return marker;
79
+ }
80
+ }
81
+ }
82
+ const Marker = /\0(\d+)\0/g;
83
+ /**
84
+ * Split stringified Markdown on the markers emitted by `collectJsx()` into
85
+ * alternating text chunks and kept JSX elements, recursively for their children.
86
+ */
87
+ function toJsxChunks(text, collect) {
88
+ const out = [];
89
+ let idx = 0;
90
+ for (const match of text.matchAll(Marker)) {
91
+ if (match.index > idx) out.push(text.slice(idx, match.index));
92
+ const { node, children } = collect[Number(match[1])];
93
+ out.push({
94
+ node,
95
+ children: toJsxChunks(children, collect)
96
+ });
97
+ idx = match.index + match[0].length;
98
+ }
99
+ if (idx < text.length) out.push(text.slice(idx));
100
+ return out;
101
+ }
102
+ /**
103
+ * Generate the component export as an ESM node with estree, for the MDX.js compiler.
104
+ */
105
+ function jsxToEstree(as, chunks) {
106
+ const hasJsx = chunks.some((chunk) => typeof chunk !== "string");
107
+ let value;
108
+ if (chunks.length === 0) value = literal("");
109
+ else if (typeof chunks[0] === "string" && chunks.length === 1) value = literal(chunks[0]);
110
+ else if (chunks.length === 1) value = elementToEstree(chunks[0]);
111
+ else value = {
112
+ type: "JSXFragment",
113
+ openingFragment: { type: "JSXOpeningFragment" },
114
+ closingFragment: { type: "JSXClosingFragment" },
115
+ children: childrenToEstree(chunks)
116
+ };
117
+ const body = [{
118
+ type: "IfStatement",
119
+ test: {
120
+ type: "UnaryExpression",
121
+ operator: "!",
122
+ prefix: true,
123
+ argument: {
124
+ type: "CallExpression",
125
+ callee: {
126
+ type: "Identifier",
127
+ name: "_asMarkdown"
128
+ },
129
+ arguments: [],
130
+ optional: false
131
+ }
132
+ },
133
+ consequent: {
134
+ type: "ReturnStatement",
135
+ argument: literal(null)
136
+ },
137
+ alternate: null
138
+ }];
139
+ if (hasJsx) body.push({
140
+ type: "VariableDeclaration",
141
+ kind: "const",
142
+ declarations: [{
143
+ type: "VariableDeclarator",
144
+ id: {
145
+ type: "Identifier",
146
+ name: "_c"
147
+ },
148
+ init: {
149
+ type: "CallExpression",
150
+ callee: {
151
+ type: "Identifier",
152
+ name: "_jsxComponents"
153
+ },
154
+ arguments: [{
155
+ type: "MemberExpression",
156
+ object: {
157
+ type: "Identifier",
158
+ name: "props"
159
+ },
160
+ property: {
161
+ type: "Identifier",
162
+ name: "components"
163
+ },
164
+ computed: false,
165
+ optional: false
166
+ }],
167
+ optional: false
168
+ }
169
+ }]
170
+ });
171
+ body.push({
172
+ type: "ReturnStatement",
173
+ argument: value
174
+ });
175
+ return {
176
+ type: "mdxjsEsm",
177
+ value: "",
178
+ data: { estree: {
179
+ type: "Program",
180
+ sourceType: "module",
181
+ body: [{
182
+ type: "ImportDeclaration",
183
+ attributes: [],
184
+ specifiers: [{
185
+ type: "ImportSpecifier",
186
+ imported: {
187
+ type: "Identifier",
188
+ name: "asMarkdown"
189
+ },
190
+ local: {
191
+ type: "Identifier",
192
+ name: "_asMarkdown"
193
+ }
194
+ }, ...hasJsx ? [{
195
+ type: "ImportSpecifier",
196
+ imported: {
197
+ type: "Identifier",
198
+ name: "jsxComponents"
199
+ },
200
+ local: {
201
+ type: "Identifier",
202
+ name: "_jsxComponents"
203
+ }
204
+ }] : []],
205
+ source: literal("fumadocs-core/server")
206
+ }, {
207
+ type: "ExportNamedDeclaration",
208
+ attributes: [],
209
+ specifiers: [],
210
+ declaration: {
211
+ type: "FunctionDeclaration",
212
+ id: {
213
+ type: "Identifier",
214
+ name: as
215
+ },
216
+ params: [{
217
+ type: "Identifier",
218
+ name: "props"
219
+ }],
220
+ body: {
221
+ type: "BlockStatement",
222
+ body
223
+ }
224
+ }
225
+ }]
226
+ } }
227
+ };
228
+ }
229
+ function literal(value) {
230
+ return {
231
+ type: "Literal",
232
+ value
233
+ };
234
+ }
235
+ function childrenToEstree(chunks) {
236
+ const out = [];
237
+ for (const chunk of chunks) out.push(typeof chunk === "string" ? {
238
+ type: "JSXExpressionContainer",
239
+ expression: literal(chunk)
240
+ } : elementToEstree(chunk));
241
+ return out;
242
+ }
243
+ function elementToEstree({ node, children }) {
244
+ const attributes = [];
245
+ for (const attr of node.attributes) {
246
+ if (attr.type === "mdxJsxExpressionAttribute") {
247
+ const expression = programExpression(attr.data?.estree);
248
+ if (expression?.type === "ObjectExpression" && expression.properties.length === 1 && expression.properties[0].type === "SpreadElement") attributes.push({
249
+ type: "JSXSpreadAttribute",
250
+ argument: expression.properties[0].argument
251
+ });
252
+ continue;
253
+ }
254
+ let value = null;
255
+ if (typeof attr.value === "string") value = {
256
+ type: "Literal",
257
+ value: attr.value
258
+ };
259
+ else if (attr.value) {
260
+ const expression = programExpression(attr.value.data?.estree);
261
+ if (!expression) continue;
262
+ value = {
263
+ type: "JSXExpressionContainer",
264
+ expression
265
+ };
266
+ }
267
+ attributes.push({
268
+ type: "JSXAttribute",
269
+ name: attr.name.includes(":") ? {
270
+ type: "JSXNamespacedName",
271
+ namespace: {
272
+ type: "JSXIdentifier",
273
+ name: attr.name.slice(0, attr.name.indexOf(":"))
274
+ },
275
+ name: {
276
+ type: "JSXIdentifier",
277
+ name: attr.name.slice(attr.name.indexOf(":") + 1)
278
+ }
279
+ } : {
280
+ type: "JSXIdentifier",
281
+ name: attr.name
282
+ },
283
+ value
284
+ });
285
+ }
286
+ const name = {
287
+ type: "JSXMemberExpression",
288
+ object: {
289
+ type: "JSXIdentifier",
290
+ name: "_c"
291
+ },
292
+ property: {
293
+ type: "JSXIdentifier",
294
+ name: node.name
295
+ }
296
+ };
297
+ const element = {
298
+ type: "JSXElement",
299
+ openingElement: {
300
+ type: "JSXOpeningElement",
301
+ name,
302
+ attributes,
303
+ selfClosing: children.length === 0
304
+ },
305
+ closingElement: children.length === 0 ? null : {
306
+ type: "JSXClosingElement",
307
+ name
308
+ },
309
+ children: childrenToEstree(children)
310
+ };
311
+ if (node.type === "mdxJsxFlowElement") return element;
312
+ return {
313
+ type: "JSXElement",
314
+ openingElement: {
315
+ type: "JSXOpeningElement",
316
+ name: {
317
+ type: "JSXIdentifier",
318
+ name: "span"
319
+ },
320
+ attributes: [],
321
+ selfClosing: false
322
+ },
323
+ closingElement: {
324
+ type: "JSXClosingElement",
325
+ name: {
326
+ type: "JSXIdentifier",
327
+ name: "span"
328
+ }
329
+ },
330
+ children: [element]
331
+ };
332
+ }
333
+ function programExpression(program) {
334
+ const statement = program?.body[0];
335
+ if (statement?.type === "ExpressionStatement") return statement.expression;
336
+ }
54
337
  //#endregion
55
338
  export { placeholder, remarkLLMs };
@@ -40,17 +40,31 @@ interface LLMsOptions extends StringifyOptions {
40
40
  filterElement?: StringifyOptions['filterElement'];
41
41
  /**
42
42
  * Tag names of MDX components to be stringified as `placeholder()`, you can also use `placeholder()` directly in `stringify` callback.
43
+ *
44
+ * Ignored with `output: 'function'`.
43
45
  */
44
46
  mdxAsPlaceholder?: string[];
45
47
  /**
46
- * @private output in file data
48
+ * Form of the export:
49
+ *
50
+ * - `string`: the output Markdown.
51
+ * - `function`: a component: Markdown content is still stringified at compile time, while JSX
52
+ * elements are kept as JSX, receiving their original props and resolving from `props.components`.
53
+ * Render it with `renderToMarkdown` from `fumadocs-core/server`, where a component
54
+ * can call `asMarkdown()` to define its own Markdown form.
55
+ *
56
+ * @default string
57
+ */
58
+ output?: 'function' | 'string';
59
+ /**
60
+ * @private output in file data, unavailable with `output: 'function'`
47
61
  */
48
62
  _data?: boolean;
49
63
  }
50
64
  /**
51
65
  * generate `llms.txt` for markdown.
52
66
  */
53
- declare function remarkLLMs(this: Processor, { as, headingIds, _data, mdxAsPlaceholder, ...rest }?: LLMsOptions): Transformer<Root, Root>;
67
+ declare function remarkLLMs(this: Processor, { as, headingIds, _data, mdxAsPlaceholder, output, ...rest }?: LLMsOptions): Transformer<Root, Root>;
54
68
  /**
55
69
  * Preserve AST data to render the MDX component at runtime, use `renderPlaceholder()` to render the placeholders.
56
70
  */
@@ -1,8 +1,8 @@
1
1
  import { t as Awaitable } from "../types-D89QoQR-.js";
2
2
  import { n as I18nConfig } from "../index-DydiXvgS.js";
3
3
  import "../index-BM36H-xw.js";
4
- import { m as SharedIndex, n as SearchAPI, t as QueryOptions } from "../server-BoDPRfLi.js";
5
- import { b as LoaderOutput, v as LoaderConfig } from "../index-DQWu2opy.js";
4
+ import { m as SharedIndex, n as SearchAPI, t as QueryOptions } from "../server-C8FDQbVc.js";
5
+ import { b as LoaderOutput, v as LoaderConfig } from "../index-19nHQs6M.js";
6
6
  import { DocumentData, DocumentOptions } from "flexsearch";
7
7
  //#region src/search/server/build-doc.d.ts
8
8
  interface SharedDocument {
@@ -1,5 +1,5 @@
1
1
  import { t as createEndpoint } from "../endpoint-MyoBU5IC.js";
2
- import { n as buildBreadcrumbs, r as buildIndexDefault, t as buildDocuments } from "../build-doc-SC7P37WG.js";
2
+ import { n as buildBreadcrumbs, r as buildIndexDefault, t as buildDocuments } from "../build-doc-CX-PNB-q.js";
3
3
  import { n as search, t as createDocument } from "../utils-Bvy3V-fv.js";
4
4
  import Search from "flexsearch";
5
5
  //#region src/search/flexsearch.ts
@@ -1,5 +1,5 @@
1
1
  import { r as SortedResult } from "../index-BM36H-xw.js";
2
- import { n as SearchAPI } from "../server-BoDPRfLi.js";
2
+ import { n as SearchAPI } from "../server-C8FDQbVc.js";
3
3
  import Mixedbread from "@mixedbread/sdk";
4
4
  import { StoreSearchResponse } from "@mixedbread/sdk/resources/stores";
5
5
  //#region src/search/mixedbread.d.ts
@@ -1,5 +1,5 @@
1
1
  import { i as StructuredData } from "../remark-structure-CnHwvNZr.js";
2
- import "../index-C-fnVAhi.js";
2
+ import "../index-BhgPrb5p.js";
3
3
  import { CloudManager } from "@oramacloud/client";
4
4
  //#region src/search/orama-cloud-legacy.d.ts
5
5
  interface SyncOptions {
@@ -1,5 +1,5 @@
1
1
  import { i as StructuredData } from "../remark-structure-CnHwvNZr.js";
2
- import "../index-C-fnVAhi.js";
2
+ import "../index-BhgPrb5p.js";
3
3
  import { OramaCloud } from "@orama/core";
4
4
  //#region src/search/orama-cloud.d.ts
5
5
  interface SyncOptions {
@@ -1,2 +1,2 @@
1
- import { a as AdvancedOptions, c as SimpleOptions, d as createSearchAPI, f as initAdvancedSearch, i as AdvancedIndex, l as createFromSource, n as SearchAPI, o as ExportedData, p as initSimpleSearch, r as SearchServer, s as Index, t as QueryOptions, u as createI18nSearchAPI } from "../server-BoDPRfLi.js";
1
+ import { a as AdvancedOptions, c as SimpleOptions, d as createSearchAPI, f as initAdvancedSearch, i as AdvancedIndex, l as createFromSource, n as SearchAPI, o as ExportedData, p as initSimpleSearch, r as SearchServer, s as Index, t as QueryOptions, u as createI18nSearchAPI } from "../server-C8FDQbVc.js";
2
2
  export { AdvancedIndex, AdvancedOptions, ExportedData, Index, QueryOptions, SearchAPI, SearchServer, SimpleOptions, createFromSource, createI18nSearchAPI, createSearchAPI, initAdvancedSearch, initSimpleSearch };
@@ -1,5 +1,5 @@
1
1
  import { n as defaultReadOptions, t as createEndpoint } from "../endpoint-MyoBU5IC.js";
2
- import { n as buildBreadcrumbs, r as buildIndexDefault, t as buildDocuments } from "../build-doc-SC7P37WG.js";
2
+ import { n as buildBreadcrumbs, r as buildIndexDefault, t as buildDocuments } from "../build-doc-CX-PNB-q.js";
3
3
  import { n as searchSimple, t as searchAdvanced } from "../advanced-Ct13khZr.js";
4
4
  import { create, insertMultipleAsync, save } from "zbsearch";
5
5
  //#region src/search/zbsearch/create-db.ts
@@ -2,7 +2,7 @@ import { t as Awaitable } from "./types-D89QoQR-.js";
2
2
  import { i as StructuredData } from "./remark-structure-CnHwvNZr.js";
3
3
  import { n as I18nConfig } from "./index-DydiXvgS.js";
4
4
  import { r as SortedResult } from "./index-BM36H-xw.js";
5
- import { b as LoaderOutput, v as LoaderConfig } from "./index-DQWu2opy.js";
5
+ import { b as LoaderOutput, v as LoaderConfig } from "./index-19nHQs6M.js";
6
6
  import { Language, RawData, SearchParams, TypedDocument, ZBSearch, create } from "zbsearch";
7
7
  //#region src/search/zbsearch/create-db.d.ts
8
8
  type SimpleDocument = TypedDocument<ZBSearch<typeof simpleSchema>>;
@@ -0,0 +1,13 @@
1
+ import { ElementType, ReactElement } from "react";
2
+ //#region src/server.browser.d.ts
3
+ /**
4
+ * Browser stub: Markdown rendering is server-only, components generated by
5
+ * `remarkLLMs` with `output: 'function'` render `null` in the browser.
6
+ */
7
+ declare function asMarkdown(): boolean;
8
+ declare function jsxComponents(components: Record<string, ElementType> | undefined): Record<string, ElementType>;
9
+ declare function renderToMarkdown(): Promise<string>;
10
+ declare function renderRoute(_element: ReactElement): Promise<string | undefined>;
11
+ declare const md: () => never;
12
+ //#endregion
13
+ export { asMarkdown, jsxComponents, md, renderRoute, renderToMarkdown };
@@ -0,0 +1,22 @@
1
+ //#region src/server.browser.ts
2
+ /**
3
+ * Browser stub: Markdown rendering is server-only, components generated by
4
+ * `remarkLLMs` with `output: 'function'` render `null` in the browser.
5
+ */
6
+ function asMarkdown() {
7
+ return false;
8
+ }
9
+ function jsxComponents(components) {
10
+ return components ?? {};
11
+ }
12
+ async function renderToMarkdown() {
13
+ throw new Error("`renderToMarkdown` is only available on the server.");
14
+ }
15
+ async function renderRoute(_element) {
16
+ throw new Error("`renderRoute` is only available on the server.");
17
+ }
18
+ const md = () => {
19
+ throw new Error("`md` is only available on the server.");
20
+ };
21
+ //#endregion
22
+ export { asMarkdown, jsxComponents, md, renderRoute, renderToMarkdown };
@@ -0,0 +1,42 @@
1
+ import { ElementType, ReactElement, ReactNode } from "react";
2
+ //#region src/server.d.ts
3
+ /**
4
+ * Whether the current component is being rendered into Markdown, calling it opts the component in.
5
+ */
6
+ declare function asMarkdown(): boolean;
7
+ /**
8
+ * Render a React tree into a Markdown document.
9
+ */
10
+ declare function renderToMarkdown(node: ReactNode): Promise<string>;
11
+ /**
12
+ * Render a page element into Markdown, `undefined` when its component doesn't call `asMarkdown()`.
13
+ */
14
+ declare function renderRoute(element: ReactElement): Promise<string | undefined>;
15
+ /**
16
+ * Resolve the MDX components of a generated Markdown component (`remarkLLMs` with `output: 'function'`):
17
+ * a missing component becomes a stub that `renderToMarkdown` serializes as JSX syntax.
18
+ */
19
+ declare function jsxComponents(components: Record<string, ElementType> | undefined): Record<string, ElementType>;
20
+ type MarkdownTag = (strings: TemplateStringsArray, ...values: ReactNode[]) => Promise<string>;
21
+ /**
22
+ * Tagged template for Markdown, interpolated values can be strings, React nodes, promises, or arrays of them.
23
+ *
24
+ * Use `md\`${children}\`` inside a component to stringify its children before manipulating them, the result is not
25
+ * trimmed so block-level output keeps its trailing blank line.
26
+ *
27
+ * Formatters (Prettier, oxfmt) format `md` templates as Markdown and may move the content onto its own indented lines,
28
+ * so a leading empty line, the indentation before the closing backtick and the common indentation are removed.
29
+ */
30
+ declare const md: MarkdownTag & {
31
+ /**
32
+ * Like `md`, but trims the result, prefixes every line (empty lines receive the trimmed prefix, e.g. `>` instead of
33
+ * `> `) and returns it as a block.
34
+ */
35
+ linePrefix: (prefix: string) => MarkdownTag;
36
+ /**
37
+ * Like `md`, but trims the result, indents every non-empty line and returns it as a block.
38
+ */
39
+ indent: (size?: number) => MarkdownTag;
40
+ };
41
+ //#endregion
42
+ export { MarkdownTag, asMarkdown, jsxComponents, md, renderRoute, renderToMarkdown };
package/dist/server.js ADDED
@@ -0,0 +1,398 @@
1
+ import { isValidElement } from "react";
2
+ import { AsyncLocalStorage } from "node:async_hooks";
3
+ //#region src/server.ts
4
+ const ROOT_STATE = {
5
+ pre: false,
6
+ inline: false,
7
+ heading: false
8
+ };
9
+ const CLIENT_REFERENCE = Symbol.for("react.client.reference");
10
+ const REACT_LAZY = Symbol.for("react.lazy");
11
+ const REACT_MEMO = Symbol.for("react.memo");
12
+ const REACT_FORWARD_REF = Symbol.for("react.forward_ref");
13
+ const NOT_OPTED_IN = Symbol();
14
+ const store = new AsyncLocalStorage({ name: "fumadocs:markdown" });
15
+ /**
16
+ * Whether the current component is being rendered into Markdown, calling it opts the component in.
17
+ */
18
+ function asMarkdown() {
19
+ const frame = store.getStore();
20
+ if (!frame) return false;
21
+ frame.optedIn = true;
22
+ return true;
23
+ }
24
+ /**
25
+ * Render a React tree into a Markdown document.
26
+ */
27
+ async function renderToMarkdown(node) {
28
+ return collapse(await walk(node, ROOT_STATE)).trim();
29
+ }
30
+ /**
31
+ * Render a page element into Markdown, `undefined` when its component doesn't call `asMarkdown()`.
32
+ */
33
+ async function renderRoute(element) {
34
+ if (typeof element.type !== "function") return;
35
+ const result = await optIn(element.type, element.props);
36
+ if (result !== NOT_OPTED_IN) return renderToMarkdown(result);
37
+ }
38
+ /**
39
+ * Resolve the MDX components of a generated Markdown component (`remarkLLMs` with `output: 'function'`):
40
+ * a missing component becomes a stub that `renderToMarkdown` serializes as JSX syntax.
41
+ */
42
+ function jsxComponents(components) {
43
+ return new Proxy(components ?? {}, { get(target, key) {
44
+ const value = target[key];
45
+ if (value !== void 0 || typeof key !== "string") return value;
46
+ const stub = () => null;
47
+ stub.displayName = key;
48
+ return stub;
49
+ } });
50
+ }
51
+ /**
52
+ * Tagged template for Markdown, interpolated values can be strings, React nodes, promises, or arrays of them.
53
+ *
54
+ * Use `md\`${children}\`` inside a component to stringify its children before manipulating them, the result is not
55
+ * trimmed so block-level output keeps its trailing blank line.
56
+ *
57
+ * Formatters (Prettier, oxfmt) format `md` templates as Markdown and may move the content onto its own indented lines,
58
+ * so a leading empty line, the indentation before the closing backtick and the common indentation are removed.
59
+ */
60
+ const md = Object.assign(async function md(strings, ...values) {
61
+ const parts = dedent(strings);
62
+ const resolved = await Promise.all(values.map(render));
63
+ let out = parts[0];
64
+ for (let i = 0; i < resolved.length; i++) out += resolved[i] + parts[i + 1];
65
+ return out;
66
+ }, {
67
+ linePrefix(prefix) {
68
+ return async (strings, ...values) => {
69
+ const text = (await md(strings, ...values)).trim();
70
+ return text.length === 0 ? "" : `\n${prefixLines(text, prefix)}\n\n`;
71
+ };
72
+ },
73
+ indent(size = 2) {
74
+ return md.linePrefix(" ".repeat(size));
75
+ }
76
+ });
77
+ /** stands in for interpolations while dedenting, so their lines count as content */
78
+ const PLACEHOLDER = "\0";
79
+ function dedent(strings) {
80
+ const lines = strings.join(PLACEHOLDER).split("\n");
81
+ if (lines.length === 1) return [...strings];
82
+ if (lines[0].trim().length === 0) lines.shift();
83
+ const last = lines[lines.length - 1];
84
+ if (lines.length > 1 && last.length > 0 && last.trim().length === 0) lines.pop();
85
+ let indent = Infinity;
86
+ for (const line of lines) if (line.trim().length > 0) indent = Math.min(indent, /^[ \t]*/.exec(line)[0].length);
87
+ let out = "";
88
+ for (let i = 0; i < lines.length; i++) {
89
+ if (i > 0) out += "\n";
90
+ out += indent === Infinity ? lines[i] : lines[i].slice(Math.min(indent, lines[i].length));
91
+ }
92
+ return out.split(PLACEHOLDER);
93
+ }
94
+ async function render(node) {
95
+ return collapse(await walk(node, ROOT_STATE));
96
+ }
97
+ /**
98
+ * Prefix every line, empty lines receive the trimmed prefix (e.g. `>` instead of `> `).
99
+ */
100
+ function prefixLines(text, prefix) {
101
+ const empty = prefix.trimEnd();
102
+ return text.replace(/^.*$/gm, (line) => line.length === 0 ? empty : prefix + line);
103
+ }
104
+ function collapse(text) {
105
+ return text.replace(/\n{3,}/g, "\n\n");
106
+ }
107
+ /**
108
+ * Render a component in its own frame, `NOT_OPTED_IN` when it never calls `asMarkdown()`.
109
+ *
110
+ * A component that throws before opting in (e.g. it needs a context that only exists on its own route) is treated the
111
+ * same, it has no Markdown form.
112
+ */
113
+ async function optIn(component, props) {
114
+ const frame = { optedIn: false };
115
+ try {
116
+ const result = await store.run(frame, () => component(props));
117
+ return frame.optedIn ? result : NOT_OPTED_IN;
118
+ } catch (e) {
119
+ if (frame.optedIn) throw e;
120
+ return NOT_OPTED_IN;
121
+ }
122
+ }
123
+ async function walk(node, state) {
124
+ if (node === null || node === void 0 || typeof node === "boolean") return "";
125
+ if (typeof node === "string") return node;
126
+ if (typeof node === "number" || typeof node === "bigint") return String(node);
127
+ if (isThenable(node)) return walk(await node, state);
128
+ if (isValidElement(node)) return element(node.type, node.props, state);
129
+ if (typeof node === "object" && Symbol.iterator in node) return (await Promise.all(Array.from(node, (child) => walk(child, state)))).join("");
130
+ return "";
131
+ }
132
+ async function element(type, props, state) {
133
+ if (typeof type === "string") return host(type, props, state);
134
+ if (isClientReference(type)) return jsx(clientReferenceName(type.$$id), props, state);
135
+ if (typeof type === "function") return component(type, props, state);
136
+ if (typeof type === "symbol") return walk(props.children, state);
137
+ if (typeof type === "object" && type !== null) {
138
+ const special = type;
139
+ switch (special.$$typeof) {
140
+ case REACT_LAZY: return element(await resolveLazy(special), props, state);
141
+ case REACT_MEMO: return element(special.type, props, state);
142
+ case REACT_FORWARD_REF: return component(special.render, props, state);
143
+ }
144
+ }
145
+ return "";
146
+ }
147
+ async function component(fn, props, state) {
148
+ const result = await optIn(fn, props);
149
+ if (result === NOT_OPTED_IN) return jsx(componentName(fn), props, state);
150
+ return walk(result, state);
151
+ }
152
+ function componentName(fn) {
153
+ const { displayName, name } = fn;
154
+ return typeof displayName === "string" && displayName ? displayName : name || "Component";
155
+ }
156
+ async function resolveLazy(type) {
157
+ for (;;) try {
158
+ return type._init(type._payload);
159
+ } catch (e) {
160
+ if (!isThenable(e)) throw e;
161
+ await e;
162
+ }
163
+ }
164
+ /**
165
+ * The export name of a client reference, or a PascalCase name from its file for default exports.
166
+ */
167
+ function clientReferenceName(id) {
168
+ if (typeof id !== "string") return "Component";
169
+ try {
170
+ id = decodeURIComponent(id);
171
+ } catch {}
172
+ const hash = id.lastIndexOf("#");
173
+ const exportName = hash === -1 ? "" : id.slice(hash + 1);
174
+ if (exportName && exportName !== "default") return exportName;
175
+ const file = (hash === -1 ? id : id.slice(0, hash)).split(/[\\/]/).pop();
176
+ let name = "";
177
+ for (const part of file.replace(/\.[^.]+$/, "").split(/[^\w$]+/)) if (part) name += part[0].toUpperCase() + part.slice(1);
178
+ return name || "Component";
179
+ }
180
+ const MAX_ATTRIBUTE_LENGTH = 1024;
181
+ const PRESENTATIONAL_PROPS = /* @__PURE__ */ new Set([
182
+ "children",
183
+ "className",
184
+ "style",
185
+ "tabIndex"
186
+ ]);
187
+ /**
188
+ * Serialize a component as JSX syntax, for components without a Markdown form.
189
+ */
190
+ async function jsx(name, props, state) {
191
+ let open = `<${name}`;
192
+ for (const key in props) {
193
+ if (PRESENTATIONAL_PROPS.has(key)) continue;
194
+ const attr = attribute(key, props[key]);
195
+ if (attr !== void 0) open += ` ${attr}`;
196
+ }
197
+ const children = await walk(props.children, state);
198
+ if (state.inline) return children.trim().length === 0 ? `${open} />` : `${open}>${children}</${name}>`;
199
+ const body = children.trim();
200
+ if (body.length === 0) return `\n${open} />\n\n`;
201
+ return `\n${open}>\n${body}\n</${name}>\n\n`;
202
+ }
203
+ function attribute(key, value) {
204
+ if (value === true) return key;
205
+ if (value === false || value === null || value === void 0) return;
206
+ if (typeof value === "string") return value.length > MAX_ATTRIBUTE_LENGTH ? void 0 : `${key}=${JSON.stringify(value)}`;
207
+ if (typeof value === "number" || typeof value === "bigint") return `${key}={${value}}`;
208
+ if (typeof value === "function" || typeof value === "symbol" || isValidElement(value)) return;
209
+ try {
210
+ const json = JSON.stringify(value, (_, v) => isValidElement(v) ? void 0 : v);
211
+ if (json === void 0 || json.length > MAX_ATTRIBUTE_LENGTH) return;
212
+ return `${key}={${json}}`;
213
+ } catch {
214
+ return;
215
+ }
216
+ }
217
+ const INLINE_TAGS = /* @__PURE__ */ new Set([
218
+ "a",
219
+ "abbr",
220
+ "b",
221
+ "cite",
222
+ "code",
223
+ "del",
224
+ "em",
225
+ "i",
226
+ "kbd",
227
+ "label",
228
+ "mark",
229
+ "q",
230
+ "s",
231
+ "small",
232
+ "span",
233
+ "strong",
234
+ "sub",
235
+ "sup",
236
+ "time",
237
+ "u"
238
+ ]);
239
+ const DROP_TAGS = /* @__PURE__ */ new Set([
240
+ "head",
241
+ "link",
242
+ "meta",
243
+ "noscript",
244
+ "script",
245
+ "style",
246
+ "svg",
247
+ "template",
248
+ "title"
249
+ ]);
250
+ async function host(tag, props, state) {
251
+ if (DROP_TAGS.has(tag)) return "";
252
+ if (state.pre) {
253
+ if (tag === "br") return "\n";
254
+ return walk(props.children, state);
255
+ }
256
+ const children = (override) => walk(props.children, {
257
+ ...state,
258
+ ...override
259
+ });
260
+ switch (tag) {
261
+ case "p": {
262
+ const c = (await children({ inline: true })).trim();
263
+ return state.inline ? `${c} ` : `\n${c}\n\n`;
264
+ }
265
+ case "h1":
266
+ case "h2":
267
+ case "h3":
268
+ case "h4":
269
+ case "h5":
270
+ case "h6": {
271
+ const c = (await children({
272
+ inline: true,
273
+ heading: true
274
+ })).trim().replace(/\s*\n\s*/g, " ");
275
+ return `\n${"#".repeat(Number(tag[1]))} ${c}\n\n`;
276
+ }
277
+ case "a": {
278
+ const href = typeof props.href === "string" ? props.href : void 0;
279
+ const c = await children({ inline: true });
280
+ if (!href || state.heading && href.startsWith("#")) return c;
281
+ const text = c.trim();
282
+ return text.length === 0 ? `<${href}>` : `[${text}](${href})`;
283
+ }
284
+ case "strong":
285
+ case "b": return wrap(await children({ inline: true }), "**");
286
+ case "em":
287
+ case "i": return wrap(await children({ inline: true }), "*");
288
+ case "del":
289
+ case "s": return wrap(await children({ inline: true }), "~~");
290
+ case "code":
291
+ case "kbd": {
292
+ const c = await children({ inline: true });
293
+ if (c.includes("\n") && !state.inline) return codeFence(detectLang(props), c);
294
+ return inlineCode(c);
295
+ }
296
+ case "pre": return codeFence(detectLang(props), await children({ pre: true }));
297
+ case "blockquote": return `\n${prefixLines(collapse(await children({ inline: false })).trim(), "> ")}\n\n`;
298
+ case "ul":
299
+ case "ol": {
300
+ const ordered = tag === "ol";
301
+ let index = typeof props.start === "number" ? props.start : 1;
302
+ return `\n${(await Promise.all(flatten(props.children).map((child) => {
303
+ if (!isValidElement(child)) return typeof child === "string" ? child.trim() : "";
304
+ return walk(child, {
305
+ ...state,
306
+ inline: false,
307
+ list: {
308
+ ordered,
309
+ index: index++
310
+ }
311
+ });
312
+ }))).join("")}\n`;
313
+ }
314
+ case "li": {
315
+ const marker = state.list?.ordered ? `${state.list.index}. ` : "- ";
316
+ return `${marker}${prefixLines((await children({ inline: false })).trim().replace(/\n{2,}(?=(?:[-*+] |\d+\. ))/g, "\n"), " ".repeat(marker.length)).slice(marker.length)}\n`;
317
+ }
318
+ case "img": {
319
+ if (typeof props.src !== "string") return "";
320
+ const alt = typeof props.alt === "string" ? props.alt : "";
321
+ return state.inline ? `![${alt}](${props.src})` : `\n![${alt}](${props.src})\n\n`;
322
+ }
323
+ case "hr": return "\n---\n\n";
324
+ case "br": return "\n";
325
+ case "table": {
326
+ const rows = (await children({ inline: false })).replace(/\n\s*\n/g, "\n").trim();
327
+ if (rows.length === 0) return "";
328
+ const end = rows.indexOf("\n");
329
+ const first = end === -1 ? rows : rows.slice(0, end);
330
+ return `\n${first}\n${separatorRow(first)}${end === -1 ? "" : rows.slice(end)}\n\n`;
331
+ }
332
+ case "tr": return `|${await children({ inline: false })}\n`;
333
+ case "th":
334
+ case "td": return ` ${(await children({ inline: true })).trim().replace(/\s*\n\s*/g, " ").replaceAll("|", "\\|")} |`;
335
+ }
336
+ if (INLINE_TAGS.has(tag)) return children({ inline: true });
337
+ const c = (await children({ inline: false })).trim();
338
+ return c.length === 0 ? "" : `\n${c}\n\n`;
339
+ }
340
+ function separatorRow(row) {
341
+ const cells = Math.max(1, (row.match(/(?<!\\)\|/g)?.length ?? 2) - 1);
342
+ return `|${" --- |".repeat(cells)}`;
343
+ }
344
+ function wrap(text, marker) {
345
+ const [, lead, core, trail] = /^(\s*)([\s\S]*?)(\s*)$/.exec(text);
346
+ return core ? `${lead}${marker}${core}${marker}${trail}` : text;
347
+ }
348
+ function codeFence(lang, code) {
349
+ const text = code.replace(/\n$/, "");
350
+ const fence = "`".repeat(Math.max(3, longestRun(text, "`") + 1));
351
+ return `\n${fence}${lang}\n${text}\n${fence}\n\n`;
352
+ }
353
+ function inlineCode(text) {
354
+ const fence = "`".repeat(longestRun(text, "`") + 1);
355
+ const pad = text.startsWith("`") || text.endsWith("`") ? " " : "";
356
+ return `${fence}${pad}${text}${pad}${fence}`;
357
+ }
358
+ function longestRun(text, char) {
359
+ let max = 0;
360
+ let current = 0;
361
+ for (const c of text) {
362
+ current = c === char ? current + 1 : 0;
363
+ if (current > max) max = current;
364
+ }
365
+ return max;
366
+ }
367
+ /** from `data-lang` or a `language-*` class name, of the element or its `<code>` child */
368
+ function detectLang(props) {
369
+ const lang = props["data-lang"] ?? props.lang;
370
+ if (typeof lang === "string" && lang.length > 0) return lang;
371
+ const fromClass = (className) => typeof className === "string" ? /(?:^|\s)(?:language|lang)-([\w+#.-]+)/.exec(className)?.[1] : void 0;
372
+ let out = fromClass(props.className);
373
+ for (const child of flatten(props.children)) {
374
+ if (out) break;
375
+ if (isValidElement(child) && child.type === "code") out = fromClass(child.props.className);
376
+ }
377
+ return out ?? "";
378
+ }
379
+ /**
380
+ * Direct children, flattened through arrays and fragments.
381
+ */
382
+ function flatten(node, out = []) {
383
+ if (node === null || node === void 0 || typeof node === "boolean") return out;
384
+ if (isValidElement(node)) {
385
+ if (typeof node.type === "symbol") flatten(node.props.children, out);
386
+ else out.push(node);
387
+ } else if (typeof node === "object" && Symbol.iterator in node) for (const child of node) flatten(child, out);
388
+ else out.push(node);
389
+ return out;
390
+ }
391
+ function isClientReference(type) {
392
+ return (typeof type === "function" || typeof type === "object" && type !== null) && type.$$typeof === CLIENT_REFERENCE;
393
+ }
394
+ function isThenable(value) {
395
+ return typeof value === "object" && value !== null && typeof value.then === "function";
396
+ }
397
+ //#endregion
398
+ export { asMarkdown, jsxComponents, md, renderRoute, renderToMarkdown };
@@ -1,2 +1,2 @@
1
- import { h as dynamicLoader, m as DynamicLoaderConfig, p as DynamicLoader } from "../index-DQWu2opy.js";
1
+ import { h as dynamicLoader, m as DynamicLoaderConfig, p as DynamicLoader } from "../index-19nHQs6M.js";
2
2
  export { DynamicLoader, DynamicLoaderConfig, dynamicLoader };
@@ -1,2 +1,2 @@
1
- import { B as ContentStoragePageFile, C as Meta, D as loader, E as createGetUrl, F as PageTreeBuilderContext, I as PageTreeOptions, L as PageTreeTransformer, O as types_d_exports, P as PageTreeBuilder, R as ContentStorage, S as LoaderPluginOption, T as ResolvedLoaderConfig, V as FileSystem, _ as InferPageType, a as MetaData, b as LoaderOutput, c as SourceUnion, d as multiple, f as update, g as InferMetaType, h as dynamicLoader, i as DynamicSource, j as getSlugs, l as StaticSource, m as DynamicLoaderConfig, n as llms, o as PageData, p as DynamicLoader, r as path_d_exports, s as Source, t as LLMsConfig, u as VirtualFile, v as LoaderConfig, w as Page, x as LoaderPlugin, y as LoaderOptions, z as ContentStorageMetaFile } from "../index-DQWu2opy.js";
1
+ import { B as ContentStoragePageFile, C as Meta, D as loader, E as createGetUrl, F as PageTreeBuilderContext, I as PageTreeOptions, L as PageTreeTransformer, O as types_d_exports, P as PageTreeBuilder, R as ContentStorage, S as LoaderPluginOption, T as ResolvedLoaderConfig, V as FileSystem, _ as InferPageType, a as MetaData, b as LoaderOutput, c as SourceUnion, d as multiple, f as update, g as InferMetaType, h as dynamicLoader, i as DynamicSource, j as getSlugs, l as StaticSource, m as DynamicLoaderConfig, n as llms, o as PageData, p as DynamicLoader, r as path_d_exports, s as Source, t as LLMsConfig, u as VirtualFile, v as LoaderConfig, w as Page, x as LoaderPlugin, y as LoaderOptions, z as ContentStorageMetaFile } from "../index-19nHQs6M.js";
2
2
  export { type ContentStorage, type ContentStorageMetaFile, type ContentStoragePageFile, type DynamicLoader, type DynamicLoaderConfig, type DynamicSource, FileSystem, InferMetaType, InferPageType, LLMsConfig, LoaderConfig, LoaderOptions, LoaderOutput, LoaderPlugin, LoaderPluginOption, Meta, type MetaData, Page, type PageData, type PageTreeBuilder, type PageTreeBuilderContext, type PageTreeOptions, type PageTreeTransformer, path_d_exports as PathUtils, ResolvedLoaderConfig, type Source, type SourceUnion, type StaticSource, type VirtualFile, type types_d_exports as _Internal, createGetUrl, dynamicLoader, getSlugs, llms, loader, multiple, update };
@@ -1,2 +1,2 @@
1
- import { n as llms, t as LLMsConfig } from "../index-DQWu2opy.js";
1
+ import { n as llms, t as LLMsConfig } from "../index-19nHQs6M.js";
2
2
  export { LLMsConfig, llms };
@@ -1,4 +1,4 @@
1
- import { x as LoaderPlugin } from "../../index-DQWu2opy.js";
1
+ import { x as LoaderPlugin } from "../../index-19nHQs6M.js";
2
2
  import { icons } from "lucide-react";
3
3
  //#region src/source/plugins/lucide-icons.d.ts
4
4
  /**
@@ -1,2 +1,2 @@
1
- import { A as SlugsPluginOptions, M as slugsFromData, N as slugsPlugin, j as getSlugs, k as SlugFn } from "../../index-DQWu2opy.js";
1
+ import { A as SlugsPluginOptions, M as slugsFromData, N as slugsPlugin, j as getSlugs, k as SlugFn } from "../../index-19nHQs6M.js";
2
2
  export { SlugFn, SlugsPluginOptions, getSlugs, slugsFromData, slugsPlugin };
@@ -1,5 +1,5 @@
1
1
  import { a as Separator$1, n as Item$1, t as Folder$1 } from "../../definitions-D8-KI7Uy.js";
2
- import { x as LoaderPlugin } from "../../index-DQWu2opy.js";
2
+ import { x as LoaderPlugin } from "../../index-19nHQs6M.js";
3
3
  import { ReactNode } from "react";
4
4
  //#region src/source/plugins/status-badges.d.ts
5
5
  interface Item extends Item$1 {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fumadocs-core",
3
- "version": "16.15.2",
3
+ "version": "16.15.3",
4
4
  "description": "The React.js library for building a documentation website",
5
5
  "keywords": [
6
6
  "Docs",
@@ -82,6 +82,11 @@
82
82
  "./search/orama-cloud": "./dist/search/orama-cloud.js",
83
83
  "./search/orama-cloud-legacy": "./dist/search/orama-cloud-legacy.js",
84
84
  "./search/server": "./dist/search/server.js",
85
+ "./server": {
86
+ "browser": "./dist/server.browser.js",
87
+ "import": "./dist/server.js"
88
+ },
89
+ "./server.browser": "./dist/server.browser.js",
85
90
  "./source": "./dist/source/index.js",
86
91
  "./source/client": "./dist/source/client/index.js",
87
92
  "./source/dynamic": "./dist/source/dynamic.js",