@brainfish-ai/devdoc 0.1.44 → 0.1.45

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brainfish-ai/devdoc",
3
- "version": "0.1.44",
3
+ "version": "0.1.45",
4
4
  "description": "Documentation framework for developers. Write docs in MDX, preview locally, deploy to Brainfish.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -8,6 +8,7 @@ import rehypeSlug from 'rehype-slug';
8
8
  // Note: rehype-pretty-code is dynamically imported to handle serverless environments
9
9
  // where shiki may not be fully available
10
10
  import { getProjectFile } from '@/lib/storage/blob';
11
+ import { remarkMermaid } from '@/lib/docs/mdx/remark-mermaid';
11
12
  const STARTER_PATH = process.env.STARTER_PATH || 'devdoc-docs';
12
13
  // Helper to get content root - supports both relative and absolute paths
13
14
  function getContentRoot() {
@@ -68,7 +69,8 @@ export async function GET(request) {
68
69
  mdxSource = await serialize(content, {
69
70
  mdxOptions: {
70
71
  remarkPlugins: [
71
- remarkGfm
72
+ remarkGfm,
73
+ remarkMermaid
72
74
  ],
73
75
  rehypePlugins: [
74
76
  rehypeSlug,
@@ -86,7 +88,8 @@ export async function GET(request) {
86
88
  mdxSource = await serialize(content, {
87
89
  mdxOptions: {
88
90
  remarkPlugins: [
89
- remarkGfm
91
+ remarkGfm,
92
+ remarkMermaid
90
93
  ],
91
94
  rehypePlugins: [
92
95
  rehypeSlug
@@ -149,7 +152,8 @@ export async function GET(request) {
149
152
  mdxSource = await serialize(content, {
150
153
  mdxOptions: {
151
154
  remarkPlugins: [
152
- remarkGfm
155
+ remarkGfm,
156
+ remarkMermaid
153
157
  ],
154
158
  rehypePlugins: [
155
159
  rehypeSlug,
@@ -167,7 +171,8 @@ export async function GET(request) {
167
171
  mdxSource = await serialize(content, {
168
172
  mdxOptions: {
169
173
  remarkPlugins: [
170
- remarkGfm
174
+ remarkGfm,
175
+ remarkMermaid
171
176
  ],
172
177
  rehypePlugins: [
173
178
  rehypeSlug
@@ -6,6 +6,7 @@ import { MDXRemote } from 'next-mdx-remote';
6
6
  import { useDocsNavigation } from '@/lib/docs-navigation-context';
7
7
  import { useCodeCopy } from '@/hooks/use-code-copy';
8
8
  import { NotFoundPage } from './not-found-page';
9
+ import { MDXErrorBoundary } from './mdx-error-boundary';
9
10
  // Custom Link component for MDX - uses docs navigation context
10
11
  function MdxLink({ href, children, ...props }) {
11
12
  const docsNav = useDocsNavigation();
@@ -213,29 +214,65 @@ export function DocPage({ slug, onSearch }) {
213
214
  const showHeader = !hideHeader && !isCustomMode;
214
215
  // Custom mode: Full-width layout for landing pages
215
216
  if (isCustomMode) {
216
- return /*#__PURE__*/ _jsx("div", {
217
- ref: contentRef,
218
- className: "docs-page docs-page-custom docs-content w-full min-h-full",
219
- style: {
220
- background: background || 'var(--background)',
221
- // Ensure the content fills the entire viewport width within the content area
222
- marginLeft: 0,
223
- marginRight: 0
224
- },
217
+ return /*#__PURE__*/ _jsx(MDXErrorBoundary, {
218
+ slug: slug,
225
219
  children: /*#__PURE__*/ _jsx("div", {
226
- className: "docs-custom-content [&>*]:w-full",
227
- children: /*#__PURE__*/ _jsx(MDXRemote, {
228
- ...pageData.mdxSource,
229
- components: mdxComponents
220
+ ref: contentRef,
221
+ className: "docs-page docs-page-custom docs-content w-full min-h-full",
222
+ style: {
223
+ background: background || 'var(--background)',
224
+ // Ensure the content fills the entire viewport width within the content area
225
+ marginLeft: 0,
226
+ marginRight: 0
227
+ },
228
+ children: /*#__PURE__*/ _jsx("div", {
229
+ className: "docs-custom-content [&>*]:w-full",
230
+ children: /*#__PURE__*/ _jsx(MDXRemote, {
231
+ ...pageData.mdxSource,
232
+ components: mdxComponents
233
+ })
230
234
  })
231
235
  })
232
236
  });
233
237
  }
234
238
  // Wide mode: No prose wrapper (for landing pages with custom components)
235
239
  if (isWideMode) {
236
- return /*#__PURE__*/ _jsxs("div", {
240
+ return /*#__PURE__*/ _jsx(MDXErrorBoundary, {
241
+ slug: slug,
242
+ children: /*#__PURE__*/ _jsxs("div", {
243
+ ref: contentRef,
244
+ className: "docs-page docs-content max-w-6xl mx-auto px-4 py-6 sm:px-8 sm:py-8",
245
+ children: [
246
+ showHeader && /*#__PURE__*/ _jsxs("div", {
247
+ className: "docs-page-header mb-6",
248
+ children: [
249
+ /*#__PURE__*/ _jsx("h1", {
250
+ className: "docs-content-title text-2xl sm:text-3xl font-bold mb-2 text-foreground",
251
+ children: pageData.frontmatter.title
252
+ }),
253
+ pageData.frontmatter.description && /*#__PURE__*/ _jsx("p", {
254
+ className: "docs-content-description text-lg text-muted-foreground",
255
+ children: pageData.frontmatter.description
256
+ })
257
+ ]
258
+ }),
259
+ /*#__PURE__*/ _jsx("div", {
260
+ className: "docs-wide-content",
261
+ children: /*#__PURE__*/ _jsx(MDXRemote, {
262
+ ...pageData.mdxSource,
263
+ components: mdxComponents
264
+ })
265
+ })
266
+ ]
267
+ })
268
+ });
269
+ }
270
+ // Default mode: Standard documentation layout with prose
271
+ return /*#__PURE__*/ _jsx(MDXErrorBoundary, {
272
+ slug: slug,
273
+ children: /*#__PURE__*/ _jsxs("div", {
237
274
  ref: contentRef,
238
- className: "docs-page docs-content max-w-6xl mx-auto px-4 py-6 sm:px-8 sm:py-8",
275
+ className: "docs-page docs-content max-w-4xl mx-auto px-4 py-6 sm:px-8 sm:py-8",
239
276
  children: [
240
277
  showHeader && /*#__PURE__*/ _jsxs("div", {
241
278
  className: "docs-page-header mb-6",
@@ -251,40 +288,13 @@ export function DocPage({ slug, onSearch }) {
251
288
  ]
252
289
  }),
253
290
  /*#__PURE__*/ _jsx("div", {
254
- className: "docs-wide-content",
291
+ className: "docs-prose prose prose-sm max-w-none prose-headings:text-foreground prose-p:text-muted-foreground prose-strong:text-foreground prose-code:text-foreground prose-pre:bg-muted prose-code:bg-muted prose-code:px-1 prose-code:py-0.5 prose-code:rounded prose-pre:overflow-x-auto prose-table:w-full prose-th:text-left prose-th:p-3 prose-th:bg-muted prose-td:p-3 prose-td:border-b prose-td:border-border",
255
292
  children: /*#__PURE__*/ _jsx(MDXRemote, {
256
293
  ...pageData.mdxSource,
257
294
  components: mdxComponents
258
295
  })
259
296
  })
260
297
  ]
261
- });
262
- }
263
- // Default mode: Standard documentation layout with prose
264
- return /*#__PURE__*/ _jsxs("div", {
265
- ref: contentRef,
266
- className: "docs-page docs-content max-w-4xl mx-auto px-4 py-6 sm:px-8 sm:py-8",
267
- children: [
268
- showHeader && /*#__PURE__*/ _jsxs("div", {
269
- className: "docs-page-header mb-6",
270
- children: [
271
- /*#__PURE__*/ _jsx("h1", {
272
- className: "docs-content-title text-2xl sm:text-3xl font-bold mb-2 text-foreground",
273
- children: pageData.frontmatter.title
274
- }),
275
- pageData.frontmatter.description && /*#__PURE__*/ _jsx("p", {
276
- className: "docs-content-description text-lg text-muted-foreground",
277
- children: pageData.frontmatter.description
278
- })
279
- ]
280
- }),
281
- /*#__PURE__*/ _jsx("div", {
282
- className: "docs-prose prose prose-sm max-w-none prose-headings:text-foreground prose-p:text-muted-foreground prose-strong:text-foreground prose-code:text-foreground prose-pre:bg-muted prose-code:bg-muted prose-code:px-1 prose-code:py-0.5 prose-code:rounded prose-pre:overflow-x-auto prose-table:w-full prose-th:text-left prose-th:p-3 prose-th:bg-muted prose-td:p-3 prose-td:border-b prose-td:border-border",
283
- children: /*#__PURE__*/ _jsx(MDXRemote, {
284
- ...pageData.mdxSource,
285
- components: mdxComponents
286
- })
287
- })
288
- ]
298
+ })
289
299
  });
290
300
  }
@@ -0,0 +1,184 @@
1
+ 'use client';
2
+ function _define_property(obj, key, value) {
3
+ if (key in obj) {
4
+ Object.defineProperty(obj, key, {
5
+ value: value,
6
+ enumerable: true,
7
+ configurable: true,
8
+ writable: true
9
+ });
10
+ } else {
11
+ obj[key] = value;
12
+ }
13
+ return obj;
14
+ }
15
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
16
+ import { Component } from 'react';
17
+ import { Warning, ArrowClockwise, Code, FileText } from '@phosphor-icons/react';
18
+ /**
19
+ * Error boundary for MDX content rendering.
20
+ * Catches rendering errors and displays helpful guidance.
21
+ */ export class MDXErrorBoundary extends Component {
22
+ static getDerivedStateFromError(error) {
23
+ return {
24
+ hasError: true,
25
+ error
26
+ };
27
+ }
28
+ componentDidCatch(error, errorInfo) {
29
+ console.error('[MDX Rendering Error]', error, errorInfo);
30
+ }
31
+ render() {
32
+ if (this.state.hasError) {
33
+ const errorMessage = this.state.error?.message || 'Unknown error';
34
+ const suggestions = getErrorSuggestions(errorMessage);
35
+ return /*#__PURE__*/ _jsx("div", {
36
+ className: "docs-page docs-page-error w-full min-h-[200px] max-w-4xl mx-auto px-4 py-6 sm:px-8 sm:py-8",
37
+ children: /*#__PURE__*/ _jsxs("div", {
38
+ className: "rounded-lg border border-amber-200 dark:border-amber-800 bg-amber-50 dark:bg-amber-950/50 p-6",
39
+ children: [
40
+ /*#__PURE__*/ _jsxs("div", {
41
+ className: "flex items-start gap-3 mb-4",
42
+ children: [
43
+ /*#__PURE__*/ _jsx(Warning, {
44
+ className: "h-6 w-6 text-amber-600 dark:text-amber-400 flex-shrink-0 mt-0.5",
45
+ weight: "fill"
46
+ }),
47
+ /*#__PURE__*/ _jsxs("div", {
48
+ children: [
49
+ /*#__PURE__*/ _jsx("h2", {
50
+ className: "text-lg font-semibold text-amber-900 dark:text-amber-100",
51
+ children: "Unable to render this page"
52
+ }),
53
+ /*#__PURE__*/ _jsx("p", {
54
+ className: "text-sm text-amber-700 dark:text-amber-300 mt-1",
55
+ children: "There's a syntax error in the MDX content that prevented rendering."
56
+ })
57
+ ]
58
+ })
59
+ ]
60
+ }),
61
+ /*#__PURE__*/ _jsxs("div", {
62
+ className: "bg-amber-100 dark:bg-amber-900/50 rounded-md p-3 mb-4",
63
+ children: [
64
+ /*#__PURE__*/ _jsx("p", {
65
+ className: "text-xs font-medium text-amber-800 dark:text-amber-200 mb-1",
66
+ children: "Error message:"
67
+ }),
68
+ /*#__PURE__*/ _jsx("code", {
69
+ className: "text-sm text-amber-900 dark:text-amber-100 break-all",
70
+ children: errorMessage
71
+ })
72
+ ]
73
+ }),
74
+ /*#__PURE__*/ _jsxs("div", {
75
+ className: "space-y-3",
76
+ children: [
77
+ /*#__PURE__*/ _jsx("p", {
78
+ className: "text-sm font-medium text-amber-800 dark:text-amber-200",
79
+ children: "Common causes and fixes:"
80
+ }),
81
+ /*#__PURE__*/ _jsx("ul", {
82
+ className: "space-y-2",
83
+ children: suggestions.map((suggestion, index)=>/*#__PURE__*/ _jsxs("li", {
84
+ className: "flex items-start gap-2 text-sm text-amber-700 dark:text-amber-300",
85
+ children: [
86
+ /*#__PURE__*/ _jsx(suggestion.icon, {
87
+ className: "h-4 w-4 flex-shrink-0 mt-0.5",
88
+ weight: "bold"
89
+ }),
90
+ /*#__PURE__*/ _jsxs("div", {
91
+ children: [
92
+ /*#__PURE__*/ _jsxs("span", {
93
+ className: "font-medium",
94
+ children: [
95
+ suggestion.title,
96
+ ":"
97
+ ]
98
+ }),
99
+ ' ',
100
+ suggestion.description
101
+ ]
102
+ })
103
+ ]
104
+ }, index))
105
+ })
106
+ ]
107
+ }),
108
+ /*#__PURE__*/ _jsxs("button", {
109
+ onClick: this.handleRetry,
110
+ className: "mt-6 inline-flex items-center gap-2 px-4 py-2 text-sm font-medium rounded-md bg-amber-200 dark:bg-amber-800 text-amber-900 dark:text-amber-100 hover:bg-amber-300 dark:hover:bg-amber-700 transition-colors",
111
+ children: [
112
+ /*#__PURE__*/ _jsx(ArrowClockwise, {
113
+ className: "h-4 w-4",
114
+ weight: "bold"
115
+ }),
116
+ "Try again"
117
+ ]
118
+ })
119
+ ]
120
+ })
121
+ });
122
+ }
123
+ return this.props.children;
124
+ }
125
+ constructor(props){
126
+ super(props), _define_property(this, "handleRetry", ()=>{
127
+ this.setState({
128
+ hasError: false,
129
+ error: null
130
+ });
131
+ });
132
+ this.state = {
133
+ hasError: false,
134
+ error: null
135
+ };
136
+ }
137
+ }
138
+ /**
139
+ * Get context-aware error suggestions based on the error message
140
+ */ function getErrorSuggestions(errorMessage) {
141
+ const suggestions = [];
142
+ // Check for common MDX errors
143
+ if (errorMessage.includes('Unexpected') || errorMessage.includes('Expected')) {
144
+ suggestions.push({
145
+ icon: Code,
146
+ title: 'JSX Syntax',
147
+ description: 'Check for unclosed tags, missing quotes in attributes, or invalid JSX expressions. All tags must be properly closed (e.g., <Image /> not <Image>).'
148
+ });
149
+ }
150
+ if (errorMessage.includes('is not defined') || errorMessage.includes('is not a function')) {
151
+ suggestions.push({
152
+ icon: Code,
153
+ title: 'Unknown Component',
154
+ description: 'A component used in this page may not be available. Check that all component names are spelled correctly and are supported.'
155
+ });
156
+ }
157
+ if (errorMessage.includes('mermaid') || errorMessage.includes('Mermaid')) {
158
+ suggestions.push({
159
+ icon: Code,
160
+ title: 'Mermaid Syntax',
161
+ description: 'Check your Mermaid diagram syntax. Ensure proper indentation and valid diagram type (flowchart, sequenceDiagram, etc.).'
162
+ });
163
+ }
164
+ if (errorMessage.includes('frontmatter') || errorMessage.includes('yaml')) {
165
+ suggestions.push({
166
+ icon: FileText,
167
+ title: 'Frontmatter Format',
168
+ description: 'Ensure frontmatter is valid YAML between --- markers at the top of the file.'
169
+ });
170
+ }
171
+ // Always add generic suggestions
172
+ suggestions.push({
173
+ icon: Code,
174
+ title: 'Curly Braces',
175
+ description: 'In MDX, curly braces {} are for JavaScript expressions. Use {"{"} and {"}"} to display literal braces.'
176
+ });
177
+ suggestions.push({
178
+ icon: FileText,
179
+ title: 'Special Characters',
180
+ description: 'Characters like <, >, and & may need to be escaped or wrapped in JSX expressions.'
181
+ });
182
+ return suggestions.slice(0, 4) // Limit to 4 suggestions
183
+ ;
184
+ }