@brainfish-ai/devdoc 0.1.21

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 (268) hide show
  1. package/LICENSE +33 -0
  2. package/README.md +415 -0
  3. package/bin/devdoc.js +13 -0
  4. package/dist/cli/commands/build.d.ts +5 -0
  5. package/dist/cli/commands/build.js +87 -0
  6. package/dist/cli/commands/check.d.ts +1 -0
  7. package/dist/cli/commands/check.js +143 -0
  8. package/dist/cli/commands/create.d.ts +24 -0
  9. package/dist/cli/commands/create.js +387 -0
  10. package/dist/cli/commands/deploy.d.ts +9 -0
  11. package/dist/cli/commands/deploy.js +433 -0
  12. package/dist/cli/commands/dev.d.ts +6 -0
  13. package/dist/cli/commands/dev.js +139 -0
  14. package/dist/cli/commands/init.d.ts +11 -0
  15. package/dist/cli/commands/init.js +238 -0
  16. package/dist/cli/commands/keys.d.ts +12 -0
  17. package/dist/cli/commands/keys.js +165 -0
  18. package/dist/cli/commands/start.d.ts +5 -0
  19. package/dist/cli/commands/start.js +56 -0
  20. package/dist/cli/commands/upload.d.ts +13 -0
  21. package/dist/cli/commands/upload.js +238 -0
  22. package/dist/cli/commands/whoami.d.ts +8 -0
  23. package/dist/cli/commands/whoami.js +91 -0
  24. package/dist/cli/index.d.ts +1 -0
  25. package/dist/cli/index.js +106 -0
  26. package/dist/config/index.d.ts +80 -0
  27. package/dist/config/index.js +133 -0
  28. package/dist/constants.d.ts +9 -0
  29. package/dist/constants.js +13 -0
  30. package/dist/index.d.ts +7 -0
  31. package/dist/index.js +12 -0
  32. package/dist/utils/logger.d.ts +16 -0
  33. package/dist/utils/logger.js +61 -0
  34. package/dist/utils/paths.d.ts +16 -0
  35. package/dist/utils/paths.js +50 -0
  36. package/package.json +51 -0
  37. package/renderer/app/api/assets/[...path]/route.ts +123 -0
  38. package/renderer/app/api/assets/route.ts +124 -0
  39. package/renderer/app/api/assets/upload/route.ts +177 -0
  40. package/renderer/app/api/auth-schemes/route.ts +77 -0
  41. package/renderer/app/api/chat/route.ts +858 -0
  42. package/renderer/app/api/codegen/route.ts +72 -0
  43. package/renderer/app/api/collections/route.ts +1016 -0
  44. package/renderer/app/api/debug/route.ts +53 -0
  45. package/renderer/app/api/deploy/route.ts +234 -0
  46. package/renderer/app/api/device/route.ts +42 -0
  47. package/renderer/app/api/docs/route.ts +187 -0
  48. package/renderer/app/api/keys/regenerate/route.ts +80 -0
  49. package/renderer/app/api/openapi-spec/route.ts +151 -0
  50. package/renderer/app/api/projects/[slug]/route.ts +153 -0
  51. package/renderer/app/api/projects/[slug]/stats/route.ts +96 -0
  52. package/renderer/app/api/projects/register/route.ts +152 -0
  53. package/renderer/app/api/proxy/route.ts +149 -0
  54. package/renderer/app/api/proxy-stream/route.ts +168 -0
  55. package/renderer/app/api/redirects/route.ts +47 -0
  56. package/renderer/app/api/schema/route.ts +65 -0
  57. package/renderer/app/api/subdomains/check/route.ts +172 -0
  58. package/renderer/app/api/suggestions/route.ts +144 -0
  59. package/renderer/app/favicon.ico +0 -0
  60. package/renderer/app/globals.css +1103 -0
  61. package/renderer/app/layout.tsx +47 -0
  62. package/renderer/app/llms-full.txt/route.ts +346 -0
  63. package/renderer/app/llms.txt/route.ts +279 -0
  64. package/renderer/app/page.tsx +14 -0
  65. package/renderer/app/robots.txt/route.ts +84 -0
  66. package/renderer/app/sitemap.xml/route.ts +199 -0
  67. package/renderer/components/docs/index.ts +12 -0
  68. package/renderer/components/docs/mdx/accordion.tsx +169 -0
  69. package/renderer/components/docs/mdx/badge.tsx +132 -0
  70. package/renderer/components/docs/mdx/callouts.tsx +154 -0
  71. package/renderer/components/docs/mdx/cards.tsx +213 -0
  72. package/renderer/components/docs/mdx/changelog.tsx +120 -0
  73. package/renderer/components/docs/mdx/code-block.tsx +186 -0
  74. package/renderer/components/docs/mdx/code-group.tsx +421 -0
  75. package/renderer/components/docs/mdx/file-embeds.tsx +105 -0
  76. package/renderer/components/docs/mdx/frame.tsx +112 -0
  77. package/renderer/components/docs/mdx/highlight.tsx +151 -0
  78. package/renderer/components/docs/mdx/iframe.tsx +134 -0
  79. package/renderer/components/docs/mdx/image.tsx +235 -0
  80. package/renderer/components/docs/mdx/index.ts +204 -0
  81. package/renderer/components/docs/mdx/mermaid.tsx +240 -0
  82. package/renderer/components/docs/mdx/param-field.tsx +200 -0
  83. package/renderer/components/docs/mdx/steps.tsx +113 -0
  84. package/renderer/components/docs/mdx/tabs.tsx +86 -0
  85. package/renderer/components/docs/mdx-renderer.tsx +100 -0
  86. package/renderer/components/docs/navigation/breadcrumbs.tsx +76 -0
  87. package/renderer/components/docs/navigation/index.ts +8 -0
  88. package/renderer/components/docs/navigation/page-nav.tsx +64 -0
  89. package/renderer/components/docs/navigation/sidebar.tsx +515 -0
  90. package/renderer/components/docs/navigation/toc.tsx +113 -0
  91. package/renderer/components/docs/notice.tsx +105 -0
  92. package/renderer/components/docs-header.tsx +274 -0
  93. package/renderer/components/docs-viewer/agent/agent-chat.tsx +2076 -0
  94. package/renderer/components/docs-viewer/agent/cards/debug-context-card.tsx +90 -0
  95. package/renderer/components/docs-viewer/agent/cards/endpoint-context-card.tsx +49 -0
  96. package/renderer/components/docs-viewer/agent/cards/index.tsx +50 -0
  97. package/renderer/components/docs-viewer/agent/cards/response-options-card.tsx +212 -0
  98. package/renderer/components/docs-viewer/agent/cards/types.ts +84 -0
  99. package/renderer/components/docs-viewer/agent/chat-message.tsx +17 -0
  100. package/renderer/components/docs-viewer/agent/index.tsx +6 -0
  101. package/renderer/components/docs-viewer/agent/messages/assistant-message.tsx +119 -0
  102. package/renderer/components/docs-viewer/agent/messages/chat-message.tsx +46 -0
  103. package/renderer/components/docs-viewer/agent/messages/index.ts +17 -0
  104. package/renderer/components/docs-viewer/agent/messages/tool-call-display.tsx +721 -0
  105. package/renderer/components/docs-viewer/agent/messages/types.ts +61 -0
  106. package/renderer/components/docs-viewer/agent/messages/typing-indicator.tsx +24 -0
  107. package/renderer/components/docs-viewer/agent/messages/user-message.tsx +51 -0
  108. package/renderer/components/docs-viewer/code-editor/index.tsx +2 -0
  109. package/renderer/components/docs-viewer/code-editor/notes-mode.tsx +1283 -0
  110. package/renderer/components/docs-viewer/content/changelog-page.tsx +331 -0
  111. package/renderer/components/docs-viewer/content/doc-page.tsx +285 -0
  112. package/renderer/components/docs-viewer/content/documentation-viewer.tsx +17 -0
  113. package/renderer/components/docs-viewer/content/index.tsx +29 -0
  114. package/renderer/components/docs-viewer/content/introduction.tsx +21 -0
  115. package/renderer/components/docs-viewer/content/request-details.tsx +330 -0
  116. package/renderer/components/docs-viewer/content/sections/auth.tsx +69 -0
  117. package/renderer/components/docs-viewer/content/sections/body.tsx +66 -0
  118. package/renderer/components/docs-viewer/content/sections/headers.tsx +43 -0
  119. package/renderer/components/docs-viewer/content/sections/overview.tsx +40 -0
  120. package/renderer/components/docs-viewer/content/sections/parameters.tsx +43 -0
  121. package/renderer/components/docs-viewer/content/sections/responses.tsx +87 -0
  122. package/renderer/components/docs-viewer/global-auth-modal.tsx +352 -0
  123. package/renderer/components/docs-viewer/index.tsx +1466 -0
  124. package/renderer/components/docs-viewer/playground/auth-editor.tsx +280 -0
  125. package/renderer/components/docs-viewer/playground/body-editor.tsx +221 -0
  126. package/renderer/components/docs-viewer/playground/code-editor.tsx +224 -0
  127. package/renderer/components/docs-viewer/playground/code-snippet.tsx +387 -0
  128. package/renderer/components/docs-viewer/playground/graphql-playground.tsx +745 -0
  129. package/renderer/components/docs-viewer/playground/index.tsx +671 -0
  130. package/renderer/components/docs-viewer/playground/key-value-editor.tsx +261 -0
  131. package/renderer/components/docs-viewer/playground/method-selector.tsx +60 -0
  132. package/renderer/components/docs-viewer/playground/request-builder.tsx +179 -0
  133. package/renderer/components/docs-viewer/playground/request-tabs.tsx +237 -0
  134. package/renderer/components/docs-viewer/playground/response-cards/idle-card.tsx +21 -0
  135. package/renderer/components/docs-viewer/playground/response-cards/index.tsx +93 -0
  136. package/renderer/components/docs-viewer/playground/response-cards/loading-card.tsx +16 -0
  137. package/renderer/components/docs-viewer/playground/response-cards/network-error-card.tsx +23 -0
  138. package/renderer/components/docs-viewer/playground/response-cards/response-body-card.tsx +268 -0
  139. package/renderer/components/docs-viewer/playground/response-cards/types.ts +82 -0
  140. package/renderer/components/docs-viewer/playground/response-viewer.tsx +43 -0
  141. package/renderer/components/docs-viewer/search/index.ts +2 -0
  142. package/renderer/components/docs-viewer/search/search-dialog.tsx +331 -0
  143. package/renderer/components/docs-viewer/search/use-search.ts +117 -0
  144. package/renderer/components/docs-viewer/shared/markdown-renderer.tsx +431 -0
  145. package/renderer/components/docs-viewer/shared/method-badge.tsx +41 -0
  146. package/renderer/components/docs-viewer/shared/schema-viewer.tsx +349 -0
  147. package/renderer/components/docs-viewer/sidebar/collection-tree.tsx +239 -0
  148. package/renderer/components/docs-viewer/sidebar/endpoint-options.tsx +316 -0
  149. package/renderer/components/docs-viewer/sidebar/index.tsx +343 -0
  150. package/renderer/components/docs-viewer/sidebar/right-sidebar.tsx +202 -0
  151. package/renderer/components/docs-viewer/sidebar/sidebar-group.tsx +118 -0
  152. package/renderer/components/docs-viewer/sidebar/sidebar-item.tsx +226 -0
  153. package/renderer/components/docs-viewer/sidebar/sidebar-section.tsx +52 -0
  154. package/renderer/components/theme-provider.tsx +11 -0
  155. package/renderer/components/theme-toggle.tsx +76 -0
  156. package/renderer/components/ui/badge.tsx +46 -0
  157. package/renderer/components/ui/button.tsx +59 -0
  158. package/renderer/components/ui/dialog.tsx +118 -0
  159. package/renderer/components/ui/dropdown-menu.tsx +257 -0
  160. package/renderer/components/ui/input.tsx +21 -0
  161. package/renderer/components/ui/label.tsx +24 -0
  162. package/renderer/components/ui/navigation-menu.tsx +168 -0
  163. package/renderer/components/ui/select.tsx +190 -0
  164. package/renderer/components/ui/spinner.tsx +114 -0
  165. package/renderer/components/ui/tabs.tsx +66 -0
  166. package/renderer/components/ui/tooltip.tsx +61 -0
  167. package/renderer/hooks/use-code-copy.ts +88 -0
  168. package/renderer/hooks/use-openapi-title.ts +44 -0
  169. package/renderer/lib/api-docs/agent/index.ts +6 -0
  170. package/renderer/lib/api-docs/agent/indexer.ts +323 -0
  171. package/renderer/lib/api-docs/agent/spec-summary.ts +335 -0
  172. package/renderer/lib/api-docs/agent/types.ts +116 -0
  173. package/renderer/lib/api-docs/auth/auth-context.tsx +225 -0
  174. package/renderer/lib/api-docs/auth/auth-storage.ts +87 -0
  175. package/renderer/lib/api-docs/auth/crypto.ts +89 -0
  176. package/renderer/lib/api-docs/auth/index.ts +4 -0
  177. package/renderer/lib/api-docs/code-editor/db.ts +164 -0
  178. package/renderer/lib/api-docs/code-editor/hooks.ts +266 -0
  179. package/renderer/lib/api-docs/code-editor/index.ts +6 -0
  180. package/renderer/lib/api-docs/code-editor/mode-context.tsx +207 -0
  181. package/renderer/lib/api-docs/code-editor/types.ts +105 -0
  182. package/renderer/lib/api-docs/codegen/definitions.ts +297 -0
  183. package/renderer/lib/api-docs/codegen/har.ts +251 -0
  184. package/renderer/lib/api-docs/codegen/index.ts +159 -0
  185. package/renderer/lib/api-docs/factories.ts +151 -0
  186. package/renderer/lib/api-docs/index.ts +17 -0
  187. package/renderer/lib/api-docs/mobile-context.tsx +112 -0
  188. package/renderer/lib/api-docs/navigation-context.tsx +88 -0
  189. package/renderer/lib/api-docs/parsers/graphql/README.md +129 -0
  190. package/renderer/lib/api-docs/parsers/graphql/index.ts +91 -0
  191. package/renderer/lib/api-docs/parsers/graphql/parser.ts +491 -0
  192. package/renderer/lib/api-docs/parsers/graphql/transformer.ts +246 -0
  193. package/renderer/lib/api-docs/parsers/graphql/types.ts +283 -0
  194. package/renderer/lib/api-docs/parsers/openapi/README.md +32 -0
  195. package/renderer/lib/api-docs/parsers/openapi/dereferencer.ts +60 -0
  196. package/renderer/lib/api-docs/parsers/openapi/extractors/auth.ts +574 -0
  197. package/renderer/lib/api-docs/parsers/openapi/extractors/body.ts +403 -0
  198. package/renderer/lib/api-docs/parsers/openapi/extractors/index.ts +232 -0
  199. package/renderer/lib/api-docs/parsers/openapi/index.ts +171 -0
  200. package/renderer/lib/api-docs/parsers/openapi/transformer.ts +277 -0
  201. package/renderer/lib/api-docs/parsers/openapi/validator.ts +31 -0
  202. package/renderer/lib/api-docs/playground/context.tsx +107 -0
  203. package/renderer/lib/api-docs/playground/navigation-context.tsx +124 -0
  204. package/renderer/lib/api-docs/playground/request-builder.ts +223 -0
  205. package/renderer/lib/api-docs/playground/request-runner.ts +282 -0
  206. package/renderer/lib/api-docs/playground/types.ts +35 -0
  207. package/renderer/lib/api-docs/types.ts +269 -0
  208. package/renderer/lib/api-docs/utils.ts +311 -0
  209. package/renderer/lib/cache.ts +193 -0
  210. package/renderer/lib/docs/config/index.ts +29 -0
  211. package/renderer/lib/docs/config/loader.ts +142 -0
  212. package/renderer/lib/docs/config/schema.ts +298 -0
  213. package/renderer/lib/docs/index.ts +12 -0
  214. package/renderer/lib/docs/mdx/compiler.ts +176 -0
  215. package/renderer/lib/docs/mdx/frontmatter.ts +80 -0
  216. package/renderer/lib/docs/mdx/index.ts +26 -0
  217. package/renderer/lib/docs/navigation/generator.ts +348 -0
  218. package/renderer/lib/docs/navigation/index.ts +12 -0
  219. package/renderer/lib/docs/navigation/types.ts +123 -0
  220. package/renderer/lib/docs-navigation-context.tsx +80 -0
  221. package/renderer/lib/multi-tenant/context.ts +105 -0
  222. package/renderer/lib/storage/blob.ts +845 -0
  223. package/renderer/lib/utils.ts +6 -0
  224. package/renderer/next.config.ts +76 -0
  225. package/renderer/package.json +66 -0
  226. package/renderer/postcss.config.mjs +5 -0
  227. package/renderer/public/assets/images/screenshot.png +0 -0
  228. package/renderer/public/assets/logo/dark.svg +9 -0
  229. package/renderer/public/assets/logo/light.svg +9 -0
  230. package/renderer/public/assets/logo.svg +9 -0
  231. package/renderer/public/file.svg +1 -0
  232. package/renderer/public/globe.svg +1 -0
  233. package/renderer/public/icon.png +0 -0
  234. package/renderer/public/logo.svg +9 -0
  235. package/renderer/public/window.svg +1 -0
  236. package/renderer/tsconfig.json +28 -0
  237. package/templates/basic/README.md +139 -0
  238. package/templates/basic/assets/favicon.svg +4 -0
  239. package/templates/basic/assets/logo.svg +9 -0
  240. package/templates/basic/docs.json +47 -0
  241. package/templates/basic/guides/configuration.mdx +149 -0
  242. package/templates/basic/guides/overview.mdx +96 -0
  243. package/templates/basic/index.mdx +39 -0
  244. package/templates/basic/package.json +14 -0
  245. package/templates/basic/quickstart.mdx +92 -0
  246. package/templates/basic/vercel.json +6 -0
  247. package/templates/graphql/README.md +139 -0
  248. package/templates/graphql/api-reference/schema.graphql +305 -0
  249. package/templates/graphql/assets/favicon.svg +4 -0
  250. package/templates/graphql/assets/logo.svg +9 -0
  251. package/templates/graphql/docs.json +54 -0
  252. package/templates/graphql/guides/configuration.mdx +149 -0
  253. package/templates/graphql/guides/overview.mdx +96 -0
  254. package/templates/graphql/index.mdx +39 -0
  255. package/templates/graphql/package.json +14 -0
  256. package/templates/graphql/quickstart.mdx +92 -0
  257. package/templates/graphql/vercel.json +6 -0
  258. package/templates/openapi/README.md +139 -0
  259. package/templates/openapi/api-reference/openapi.json +419 -0
  260. package/templates/openapi/assets/favicon.svg +4 -0
  261. package/templates/openapi/assets/logo.svg +9 -0
  262. package/templates/openapi/docs.json +61 -0
  263. package/templates/openapi/guides/configuration.mdx +149 -0
  264. package/templates/openapi/guides/overview.mdx +96 -0
  265. package/templates/openapi/index.mdx +39 -0
  266. package/templates/openapi/package.json +14 -0
  267. package/templates/openapi/quickstart.mdx +92 -0
  268. package/templates/openapi/vercel.json +6 -0
@@ -0,0 +1,80 @@
1
+ export interface DocsConfig {
2
+ name?: string;
3
+ logo?: string | {
4
+ light?: string;
5
+ dark?: string;
6
+ };
7
+ favicon?: string;
8
+ colors?: {
9
+ primary?: string;
10
+ accent?: string;
11
+ };
12
+ navigation?: Navigation | NavigationGroup[];
13
+ tabs?: Tab[];
14
+ footer?: {
15
+ links?: Array<{
16
+ name: string;
17
+ url: string;
18
+ }>;
19
+ };
20
+ notice?: {
21
+ content?: string;
22
+ dismissible?: boolean;
23
+ background?: string;
24
+ };
25
+ redirects?: Array<{
26
+ source: string;
27
+ destination: string;
28
+ }>;
29
+ }
30
+ export interface Navigation {
31
+ tabs?: NavigationTab[];
32
+ global?: {
33
+ anchors?: Array<{
34
+ anchor: string;
35
+ href: string;
36
+ icon?: string;
37
+ }>;
38
+ };
39
+ }
40
+ export interface NavigationTab {
41
+ tab: string;
42
+ type: 'docs' | 'openapi' | 'changelog';
43
+ path?: string;
44
+ groups?: NavigationGroup[];
45
+ versions?: Array<{
46
+ version: string;
47
+ spec: string;
48
+ default?: boolean;
49
+ }>;
50
+ }
51
+ export interface NavigationGroup {
52
+ group: string;
53
+ icon?: string;
54
+ pages: Array<string | {
55
+ page?: string;
56
+ group?: string;
57
+ pages?: string[];
58
+ title?: string;
59
+ }>;
60
+ }
61
+ export interface Tab {
62
+ name: string;
63
+ url: string;
64
+ openapi?: string;
65
+ }
66
+ /**
67
+ * Load docs.json configuration from project root
68
+ */
69
+ export declare function loadConfig(projectRoot: string): Promise<DocsConfig>;
70
+ /**
71
+ * Validate docs.json configuration
72
+ */
73
+ export declare function validateConfig(config: DocsConfig): {
74
+ valid: boolean;
75
+ errors: string[];
76
+ };
77
+ /**
78
+ * Get the content directory from config or default
79
+ */
80
+ export declare function getContentDir(config: DocsConfig, projectRoot: string): string;
@@ -0,0 +1,133 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.loadConfig = loadConfig;
7
+ exports.validateConfig = validateConfig;
8
+ exports.getContentDir = getContentDir;
9
+ const path_1 = __importDefault(require("path"));
10
+ const fs_extra_1 = __importDefault(require("fs-extra"));
11
+ /**
12
+ * Load docs.json configuration from project root
13
+ */
14
+ async function loadConfig(projectRoot) {
15
+ const configPath = path_1.default.join(projectRoot, 'docs.json');
16
+ if (!fs_extra_1.default.existsSync(configPath)) {
17
+ throw new Error(`docs.json not found at ${configPath}`);
18
+ }
19
+ const content = await fs_extra_1.default.readFile(configPath, 'utf-8');
20
+ try {
21
+ return JSON.parse(content);
22
+ }
23
+ catch (error) {
24
+ throw new Error(`Invalid JSON in docs.json: ${error.message}`);
25
+ }
26
+ }
27
+ /**
28
+ * Validate docs.json configuration
29
+ */
30
+ function validateConfig(config) {
31
+ const errors = [];
32
+ // Check required fields
33
+ if (!config.name) {
34
+ errors.push('Missing required field: name');
35
+ }
36
+ // Validate navigation - support both old array format and new object format
37
+ if (config.navigation) {
38
+ if (Array.isArray(config.navigation)) {
39
+ // Old format: navigation is an array of groups
40
+ config.navigation.forEach((group, index) => {
41
+ if (!group.group) {
42
+ errors.push(`navigation[${index}]: missing group name`);
43
+ }
44
+ if (!group.pages || !Array.isArray(group.pages)) {
45
+ errors.push(`navigation[${index}]: pages must be an array`);
46
+ }
47
+ });
48
+ }
49
+ else if (typeof config.navigation === 'object') {
50
+ // New format: navigation is an object with tabs
51
+ const nav = config.navigation;
52
+ if (nav.tabs) {
53
+ if (!Array.isArray(nav.tabs)) {
54
+ errors.push('navigation.tabs must be an array');
55
+ }
56
+ else {
57
+ nav.tabs.forEach((tab, index) => {
58
+ if (!tab.tab) {
59
+ errors.push(`navigation.tabs[${index}]: missing tab name`);
60
+ }
61
+ if (!tab.type) {
62
+ errors.push(`navigation.tabs[${index}]: missing type`);
63
+ }
64
+ });
65
+ }
66
+ }
67
+ }
68
+ }
69
+ // Validate tabs (legacy format)
70
+ if (config.tabs) {
71
+ if (!Array.isArray(config.tabs)) {
72
+ errors.push('tabs must be an array');
73
+ }
74
+ else {
75
+ config.tabs.forEach((tab, index) => {
76
+ if (!tab.name) {
77
+ errors.push(`tabs[${index}]: missing name`);
78
+ }
79
+ if (!tab.url) {
80
+ errors.push(`tabs[${index}]: missing url`);
81
+ }
82
+ });
83
+ }
84
+ }
85
+ // Validate colors
86
+ if (config.colors) {
87
+ if (config.colors.primary && !isValidColor(config.colors.primary)) {
88
+ errors.push('colors.primary must be a valid color (hex, rgb, or named color)');
89
+ }
90
+ if (config.colors.accent && !isValidColor(config.colors.accent)) {
91
+ errors.push('colors.accent must be a valid color (hex, rgb, or named color)');
92
+ }
93
+ }
94
+ return {
95
+ valid: errors.length === 0,
96
+ errors,
97
+ };
98
+ }
99
+ /**
100
+ * Check if a string is a valid color
101
+ */
102
+ function isValidColor(color) {
103
+ // Hex colors
104
+ if (/^#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6})$/.test(color)) {
105
+ return true;
106
+ }
107
+ // RGB/RGBA
108
+ if (/^rgba?\(.+\)$/.test(color)) {
109
+ return true;
110
+ }
111
+ // HSL/HSLA
112
+ if (/^hsla?\(.+\)$/.test(color)) {
113
+ return true;
114
+ }
115
+ // Named colors (basic check)
116
+ const namedColors = [
117
+ 'black', 'white', 'red', 'green', 'blue', 'yellow', 'cyan', 'magenta',
118
+ 'gray', 'grey', 'orange', 'purple', 'pink', 'brown',
119
+ ];
120
+ if (namedColors.includes(color.toLowerCase())) {
121
+ return true;
122
+ }
123
+ return false;
124
+ }
125
+ /**
126
+ * Get the content directory from config or default
127
+ */
128
+ function getContentDir(config, projectRoot) {
129
+ // For now, content is at the project root
130
+ // Could be made configurable in the future
131
+ return projectRoot;
132
+ }
133
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvY29uZmlnL2luZGV4LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7O0FBMERBLGdDQWNDO0FBS0Qsd0NBc0VDO0FBb0NELHNDQUlDO0FBM0xELGdEQUF3QjtBQUN4Qix3REFBMEI7QUFzRDFCOztHQUVHO0FBQ0ksS0FBSyxVQUFVLFVBQVUsQ0FBQyxXQUFtQjtJQUNsRCxNQUFNLFVBQVUsR0FBRyxjQUFJLENBQUMsSUFBSSxDQUFDLFdBQVcsRUFBRSxXQUFXLENBQUMsQ0FBQztJQUV2RCxJQUFJLENBQUMsa0JBQUUsQ0FBQyxVQUFVLENBQUMsVUFBVSxDQUFDLEVBQUUsQ0FBQztRQUMvQixNQUFNLElBQUksS0FBSyxDQUFDLDBCQUEwQixVQUFVLEVBQUUsQ0FBQyxDQUFDO0lBQzFELENBQUM7SUFFRCxNQUFNLE9BQU8sR0FBRyxNQUFNLGtCQUFFLENBQUMsUUFBUSxDQUFDLFVBQVUsRUFBRSxPQUFPLENBQUMsQ0FBQztJQUV2RCxJQUFJLENBQUM7UUFDSCxPQUFPLElBQUksQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUM7SUFDN0IsQ0FBQztJQUFDLE9BQU8sS0FBVSxFQUFFLENBQUM7UUFDcEIsTUFBTSxJQUFJLEtBQUssQ0FBQyw4QkFBOEIsS0FBSyxDQUFDLE9BQU8sRUFBRSxDQUFDLENBQUM7SUFDakUsQ0FBQztBQUNILENBQUM7QUFFRDs7R0FFRztBQUNILFNBQWdCLGNBQWMsQ0FBQyxNQUFrQjtJQUMvQyxNQUFNLE1BQU0sR0FBYSxFQUFFLENBQUM7SUFFNUIsd0JBQXdCO0lBQ3hCLElBQUksQ0FBQyxNQUFNLENBQUMsSUFBSSxFQUFFLENBQUM7UUFDakIsTUFBTSxDQUFDLElBQUksQ0FBQyw4QkFBOEIsQ0FBQyxDQUFDO0lBQzlDLENBQUM7SUFFRCw0RUFBNEU7SUFDNUUsSUFBSSxNQUFNLENBQUMsVUFBVSxFQUFFLENBQUM7UUFDdEIsSUFBSSxLQUFL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QUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHBhdGggZnJvbSAncGF0aCc7XG5pbXBvcnQgZnMgZnJvbSAnZnMtZXh0cmEnO1xuXG5leHBvcnQgaW50ZXJmYWNlIERvY3NDb25maWcge1xuICBuYW1lPzogc3RyaW5nO1xuICBsb2dvPzogc3RyaW5nIHwgeyBsaWdodD86IHN0cmluZzsgZGFyaz86IHN0cmluZyB9O1xuICBmYXZpY29uPzogc3RyaW5nO1xuICBjb2xvcnM/OiB7XG4gICAgcHJpbWFyeT86IHN0cmluZztcbiAgICBhY2NlbnQ/OiBzdHJpbmc7XG4gIH07XG4gIG5hdmlnYXRpb24/OiBOYXZpZ2F0aW9uIHwgTmF2aWdhdGlvbkdyb3VwW107XG4gIHRhYnM/OiBUYWJbXTtcbiAgZm9vdGVyPzoge1xuICAgIGxpbmtzPzogQXJyYXk8eyBuYW1lOiBzdHJpbmc7IHVybDogc3RyaW5nIH0+O1xuICB9O1xuICBub3RpY2U/OiB7XG4gICAgY29udGVudD86IHN0cmluZztcbiAgICBkaXNtaXNzaWJsZT86IGJvb2xlYW47XG4gICAgYmFja2dyb3VuZD86IHN0cmluZztcbiAgfTtcbiAgcmVkaXJlY3RzPzogQXJyYXk8e1xuICAgIHNvdXJjZTogc3RyaW5nO1xuICAgIGRlc3RpbmF0aW9uOiBzdHJpbmc7XG4gIH0+O1xufVxuXG4vLyBOZXcgbmF2aWdhdGlvbiBzdHJ1Y3R1cmUgd2l0aCB0YWJzXG5leHBvcnQgaW50ZXJmYWNlIE5hdmlnYXRpb24ge1xuICB0YWJzPzogTmF2aWdhdGlvblRhYltdO1xuICBnbG9iYWw/OiB7XG4gICAgYW5jaG9ycz86IEFycmF5PHsgYW5jaG9yOiBzdHJpbmc7IGhyZWY6IHN0cmluZzsgaWNvbj86IHN0cmluZyB9PjtcbiAgfTtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBOYXZpZ2F0aW9uVGFiIHtcbiAgdGFiOiBzdHJpbmc7XG4gIHR5cGU6ICdkb2NzJyB8ICdvcGVuYXBpJyB8ICdjaGFuZ2Vsb2cnO1xuICBwYXRoPzogc3RyaW5nO1xuICBncm91cHM/OiBOYXZpZ2F0aW9uR3JvdXBbXTtcbiAgdmVyc2lvbnM/OiBBcnJheTx7IHZlcnNpb246IHN0cmluZzsgc3BlYzogc3RyaW5nOyBkZWZhdWx0PzogYm9vbGVhbiB9Pjtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBOYXZpZ2F0aW9uR3JvdXAge1xuICBncm91cDogc3RyaW5nO1xuICBpY29uPzogc3RyaW5nO1xuICBwYWdlczogQXJyYXk8c3RyaW5nIHwgeyBwYWdlPzogc3RyaW5nOyBncm91cD86IHN0cmluZzsgcGFnZXM/OiBzdHJpbmdbXTsgdGl0bGU/OiBzdHJpbmcgfT47XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgVGFiIHtcbiAgbmFtZTogc3RyaW5nO1xuICB1cmw6IHN0cmluZztcbiAgb3BlbmFwaT86IHN0cmluZztcbn1cblxuLyoqXG4gKiBMb2FkIGRvY3MuanNvbiBjb25maWd1cmF0aW9uIGZyb20gcHJvamVjdCByb290XG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBsb2FkQ29uZmlnKHByb2plY3RSb290OiBzdHJpbmcpOiBQcm9taXNlPERvY3NDb25maWc+IHtcbiAgY29uc3QgY29uZmlnUGF0aCA9IHBhdGguam9pbihwcm9qZWN0Um9vdCwgJ2RvY3MuanNvbicpO1xuICBcbiAgaWYgKCFmcy5leGlzdHNTeW5jKGNvbmZpZ1BhdGgpKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBkb2NzLmpzb24gbm90IGZvdW5kIGF0ICR7Y29uZmlnUGF0aH1gKTtcbiAgfVxuICBcbiAgY29uc3QgY29udGVudCA9IGF3YWl0IGZzLnJlYWRGaWxlKGNvbmZpZ1BhdGgsICd1dGYtOCcpO1xuICBcbiAgdHJ5IHtcbiAgICByZXR1cm4gSlNPTi5wYXJzZShjb250ZW50KTtcbiAgfSBjYXRjaCAoZXJyb3I6IGFueSkge1xuICAgIHRocm93IG5ldyBFcnJvcihgSW52YWxpZCBKU09OIGluIGRvY3MuanNvbjogJHtlcnJvci5tZXNzYWdlfWApO1xuICB9XG59XG5cbi8qKlxuICogVmFsaWRhdGUgZG9jcy5qc29uIGNvbmZpZ3VyYXRpb25cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHZhbGlkYXRlQ29uZmlnKGNvbmZpZzogRG9jc0NvbmZpZyk6IHsgdmFsaWQ6IGJvb2xlYW47IGVycm9yczogc3RyaW5nW10gfSB7XG4gIGNvbnN0IGVycm9yczogc3RyaW5nW10gPSBbXTtcbiAgXG4gIC8vIENoZWNrIHJlcXVpcmVkIGZpZWxkc1xuICBpZiAoIWNvbmZpZy5uYW1lKSB7XG4gICAgZXJyb3JzLnB1c2goJ01pc3NpbmcgcmVxdWlyZWQgZmllbGQ6IG5hbWUnKTtcbiAgfVxuICBcbiAgLy8gVmFsaWRhdGUgbmF2aWdhdGlvbiAtIHN1cHBvcnQgYm90aCBvbGQgYXJyYXkgZm9ybWF0IGFuZCBuZXcgb2JqZWN0IGZvcm1hdFxuICBpZiAoY29uZmlnLm5hdmlnYXRpb24pIHtcbiAgICBpZiAoQXJyYXkuaXNBcnJheShjb25maWcubmF2aWdhdGlvbikpIHtcbiAgICAgIC8vIE9sZCBmb3JtYXQ6IG5hdmlnYXRpb24gaXMgYW4gYXJyYXkgb2YgZ3JvdXBzXG4gICAgICBjb25maWcubmF2aWdhdGlvbi5mb3JFYWNoKChncm91cCwgaW5kZXgpID0+IHtcbiAgICAgICAgaWYgKCFncm91cC5ncm91cCkge1xuICAgICAgICAgIGVycm9ycy5wdXNoKGBuYXZpZ2F0aW9uWyR7aW5kZXh9XTogbWlzc2luZyBncm91cCBuYW1lYCk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKCFncm91cC5wYWdlcyB8fCAhQXJyYXkuaXNBcnJheShncm91cC5wYWdlcykpIHtcbiAgICAgICAgICBlcnJvcnMucHVzaChgbmF2aWdhdGlvblske2luZGV4fV06IHBhZ2VzIG11c3QgYmUgYW4gYXJyYXlgKTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgfSBlbHNlIGlmICh0eXBlb2YgY29uZmlnLm5hdmlnYXRpb24gPT09ICdvYmplY3QnKSB7XG4gICAgICAvLyBOZXcgZm9ybWF0OiBuYXZpZ2F0aW9uIGlzIGFuIG9iamVjdCB3aXRoIHRhYnNcbiAgICAgIGNvbnN0IG5hdiA9IGNvbmZpZy5uYXZpZ2F0aW9uIGFzIE5hdmlnYXRpb247XG4gICAgICBpZiAobmF2LnRhYnMpIHtcbiAgICAgICAgaWYgKCFBcnJheS5pc0FycmF5KG5hdi50YWJzKSkge1xuICAgICAgICAgIGVycm9ycy5wdXNoKCduYXZpZ2F0aW9uLnRhYnMgbXVzdCBiZSBhbiBhcnJheScpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIG5hdi50YWJzLmZvckVhY2goKHRhYiwgaW5kZXgpID0+IHtcbiAgICAgICAgICAgIGlmICghdGFiLnRhYikge1xuICAgICAgICAgICAgICBlcnJvcnMucHVzaChgbmF2aWdhdGlvbi50YWJzWyR7aW5kZXh9XTogbWlzc2luZyB0YWIgbmFtZWApO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKCF0YWIudHlwZSkge1xuICAgICAgICAgICAgICBlcnJvcnMucHVzaChgbmF2aWdhdGlvbi50YWJzWyR7aW5kZXh9XTogbWlzc2luZyB0eXBlYCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gIH1cbiAgXG4gIC8vIFZhbGlkYXRlIHRhYnMgKGxlZ2FjeSBmb3JtYXQpXG4gIGlmIChjb25maWcudGFicykge1xuICAgIGlmICghQXJyYXkuaXNBcnJheShjb25maWcudGFicykpIHtcbiAgICAgIGVycm9ycy5wdXNoKCd0YWJzIG11c3QgYmUgYW4gYXJyYXknKTtcbiAgICB9IGVsc2Uge1xuICAgICAgY29uZmlnLnRhYnMuZm9yRWFjaCgodGFiLCBpbmRleCkgPT4ge1xuICAgICAgICBpZiAoIXRhYi5uYW1lKSB7XG4gICAgICAgICAgZXJyb3JzLnB1c2goYHRhYnNbJHtpbmRleH1dOiBtaXNzaW5nIG5hbWVgKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoIXRhYi51cmwpIHtcbiAgICAgICAgICBlcnJvcnMucHVzaChgdGFic1ske2luZGV4fV06IG1pc3NpbmcgdXJsYCk7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICAgIH1cbiAgfVxuICBcbiAgLy8gVmFsaWRhdGUgY29sb3JzXG4gIGlmIChjb25maWcuY29sb3JzKSB7XG4gICAgaWYgKGNvbmZpZy5jb2xvcnMucHJpbWFyeSAmJiAhaXNWYWxpZENvbG9yKGNvbmZpZy5jb2xvcnMucHJpbWFyeSkpIHtcbiAgICAgIGVycm9ycy5wdXNoKCdjb2xvcnMucHJpbWFyeSBtdXN0IGJlIGEgdmFsaWQgY29sb3IgKGhleCwgcmdiLCBvciBuYW1lZCBjb2xvciknKTtcbiAgICB9XG4gICAgaWYgKGNvbmZpZy5jb2xvcnMuYWNjZW50ICYmICFpc1ZhbGlkQ29sb3IoY29uZmlnLmNvbG9ycy5hY2NlbnQpKSB7XG4gICAgICBlcnJvcnMucHVzaCgnY29sb3JzLmFjY2VudCBtdXN0IGJlIGEgdmFsaWQgY29sb3IgKGhleCwgcmdiLCBvciBuYW1lZCBjb2xvciknKTtcbiAgICB9XG4gIH1cbiAgXG4gIHJldHVybiB7XG4gICAgdmFsaWQ6IGVycm9ycy5sZW5ndGggPT09IDAsXG4gICAgZXJyb3JzLFxuICB9O1xufVxuXG4vKipcbiAqIENoZWNrIGlmIGEgc3RyaW5nIGlzIGEgdmFsaWQgY29sb3JcbiAqL1xuZnVuY3Rpb24gaXNWYWxpZENvbG9yKGNvbG9yOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgLy8gSGV4IGNvbG9yc1xuICBpZiAoL14jKFswLTlBLUZhLWZdezN9fFswLTlBLUZhLWZdezZ9KSQvLnRlc3QoY29sb3IpKSB7XG4gICAgcmV0dXJuIHRydWU7XG4gIH1cbiAgXG4gIC8vIFJHQi9SR0JBXG4gIGlmICgvXnJnYmE/XFwoLitcXCkkLy50ZXN0KGNvbG9yKSkge1xuICAgIHJldHVybiB0cnVlO1xuICB9XG4gIFxuICAvLyBIU0wvSFNMQVxuICBpZiAoL15oc2xhP1xcKC4rXFwpJC8udGVzdChjb2xvcikpIHtcbiAgICByZXR1cm4gdHJ1ZTtcbiAgfVxuICBcbiAgLy8gTmFtZWQgY29sb3JzIChiYXNpYyBjaGVjaylcbiAgY29uc3QgbmFtZWRDb2xvcnMgPSBbXG4gICAgJ2JsYWNrJywgJ3doaXRlJywgJ3JlZCcsICdncmVlbicsICdibHVlJywgJ3llbGxvdycsICdjeWFuJywgJ21hZ2VudGEnLFxuICAgICdncmF5JywgJ2dyZXknLCAnb3JhbmdlJywgJ3B1cnBsZScsICdwaW5rJywgJ2Jyb3duJyxcbiAgXTtcbiAgaWYgKG5hbWVkQ29sb3JzLmluY2x1ZGVzKGNvbG9yLnRvTG93ZXJDYXNlKCkpKSB7XG4gICAgcmV0dXJuIHRydWU7XG4gIH1cbiAgXG4gIHJldHVybiBmYWxzZTtcbn1cblxuLyoqXG4gKiBHZXQgdGhlIGNvbnRlbnQgZGlyZWN0b3J5IGZyb20gY29uZmlnIG9yIGRlZmF1bHRcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldENvbnRlbnREaXIoY29uZmlnOiBEb2NzQ29uZmlnLCBwcm9qZWN0Um9vdDogc3RyaW5nKTogc3RyaW5nIHtcbiAgLy8gRm9yIG5vdywgY29udGVudCBpcyBhdCB0aGUgcHJvamVjdCByb290XG4gIC8vIENvdWxkIGJlIG1hZGUgY29uZmlndXJhYmxlIGluIHRoZSBmdXR1cmVcbiAgcmV0dXJuIHByb2plY3RSb290O1xufVxuIl19
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Default API URL for DevDoc services
3
+ * Used for subdomain checks, project registration, deployment, etc.
4
+ */
5
+ export declare const DEFAULT_API_URL = "https://api.devdoc.sh";
6
+ /**
7
+ * Default domain suffix for deployed documentation sites
8
+ */
9
+ export declare const DOCS_DOMAIN_SUFFIX = ".devdoc.sh";
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DOCS_DOMAIN_SUFFIX = exports.DEFAULT_API_URL = void 0;
4
+ /**
5
+ * Default API URL for DevDoc services
6
+ * Used for subdomain checks, project registration, deployment, etc.
7
+ */
8
+ exports.DEFAULT_API_URL = 'https://api.devdoc.sh';
9
+ /**
10
+ * Default domain suffix for deployed documentation sites
11
+ */
12
+ exports.DOCS_DOMAIN_SUFFIX = '.devdoc.sh';
13
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29uc3RhbnRzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL2NvbnN0YW50cy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQTs7O0dBR0c7QUFDVSxRQUFBLGVBQWUsR0FBRyx1QkFBdUIsQ0FBQTtBQUV0RDs7R0FFRztBQUNVLFFBQUEsa0JBQWtCLEdBQUcsWUFBWSxDQUFBIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBEZWZhdWx0IEFQSSBVUkwgZm9yIERldkRvYyBzZXJ2aWNlc1xuICogVXNlZCBmb3Igc3ViZG9tYWluIGNoZWNrcywgcHJvamVjdCByZWdpc3RyYXRpb24sIGRlcGxveW1lbnQsIGV0Yy5cbiAqL1xuZXhwb3J0IGNvbnN0IERFRkFVTFRfQVBJX1VSTCA9ICdodHRwczovL2FwaS5kZXZkb2Muc2gnXG5cbi8qKlxuICogRGVmYXVsdCBkb21haW4gc3VmZml4IGZvciBkZXBsb3llZCBkb2N1bWVudGF0aW9uIHNpdGVzXG4gKi9cbmV4cG9ydCBjb25zdCBET0NTX0RPTUFJTl9TVUZGSVggPSAnLmRldmRvYy5zaCdcbiJdfQ==
@@ -0,0 +1,7 @@
1
+ /**
2
+ * @brainfish/devdoc
3
+ *
4
+ * Documentation framework for developers
5
+ */
6
+ export { loadConfig, validateConfig } from './config';
7
+ export type { DocsConfig, NavigationGroup, Tab } from './config';
package/dist/index.js ADDED
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ /**
3
+ * @brainfish/devdoc
4
+ *
5
+ * Documentation framework for developers
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.validateConfig = exports.loadConfig = void 0;
9
+ var config_1 = require("./config");
10
+ Object.defineProperty(exports, "loadConfig", { enumerable: true, get: function () { return config_1.loadConfig; } });
11
+ Object.defineProperty(exports, "validateConfig", { enumerable: true, get: function () { return config_1.validateConfig; } });
12
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBOzs7O0dBSUc7OztBQUVILG1DQUFzRDtBQUE3QyxvR0FBQSxVQUFVLE9BQUE7QUFBRSx3R0FBQSxjQUFjLE9BQUEiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEBicmFpbmZpc2gvZGV2ZG9jXG4gKiBcbiAqIERvY3VtZW50YXRpb24gZnJhbWV3b3JrIGZvciBkZXZlbG9wZXJzXG4gKi9cblxuZXhwb3J0IHsgbG9hZENvbmZpZywgdmFsaWRhdGVDb25maWcgfSBmcm9tICcuL2NvbmZpZyc7XG5leHBvcnQgdHlwZSB7IERvY3NDb25maWcsIE5hdmlnYXRpb25Hcm91cCwgVGFiIH0gZnJvbSAnLi9jb25maWcnO1xuIl19
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Simple logger utility for CLI output
3
+ */
4
+ export declare const logger: {
5
+ info(message: string): void;
6
+ success(message: string): void;
7
+ warn(message: string): void;
8
+ error(message: string): void;
9
+ debug(message: string): void;
10
+ log(message: string): void;
11
+ newline(): void;
12
+ cyan(text: string): string;
13
+ green(text: string): string;
14
+ yellow(text: string): string;
15
+ red(text: string): string;
16
+ };
@@ -0,0 +1,61 @@
1
+ "use strict";
2
+ /**
3
+ * Simple logger utility for CLI output
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.logger = void 0;
7
+ const colors = {
8
+ reset: '\x1b[0m',
9
+ red: '\x1b[31m',
10
+ green: '\x1b[32m',
11
+ yellow: '\x1b[33m',
12
+ blue: '\x1b[34m',
13
+ magenta: '\x1b[35m',
14
+ cyan: '\x1b[36m',
15
+ white: '\x1b[37m',
16
+ gray: '\x1b[90m',
17
+ };
18
+ function formatMessage(color, prefix, message) {
19
+ return `${color}${prefix}${colors.reset} ${message}`;
20
+ }
21
+ exports.logger = {
22
+ info(message) {
23
+ console.log(formatMessage(colors.blue, '○', message));
24
+ },
25
+ success(message) {
26
+ console.log(formatMessage(colors.green, '✓', message));
27
+ },
28
+ warn(message) {
29
+ console.log(formatMessage(colors.yellow, '⚠', message));
30
+ },
31
+ error(message) {
32
+ console.error(formatMessage(colors.red, '✗', message));
33
+ },
34
+ debug(message) {
35
+ if (process.env.DEBUG || process.env.DEVDOC_DEBUG) {
36
+ console.log(formatMessage(colors.gray, '⋯', message));
37
+ }
38
+ },
39
+ // Plain log without prefix
40
+ log(message) {
41
+ console.log(message);
42
+ },
43
+ // Empty line
44
+ newline() {
45
+ console.log('');
46
+ },
47
+ // Color helpers for inline formatting
48
+ cyan(text) {
49
+ return `${colors.cyan}${text}${colors.reset}`;
50
+ },
51
+ green(text) {
52
+ return `${colors.green}${text}${colors.reset}`;
53
+ },
54
+ yellow(text) {
55
+ return `${colors.yellow}${text}${colors.reset}`;
56
+ },
57
+ red(text) {
58
+ return `${colors.red}${text}${colors.reset}`;
59
+ },
60
+ };
61
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibG9nZ2VyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3V0aWxzL2xvZ2dlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7O0dBRUc7OztBQUVILE1BQU0sTUFBTSxHQUFHO0lBQ2IsS0FBSyxFQUFFLFNBQVM7SUFDaEIsR0FBRyxFQUFFLFVBQVU7SUFDZixLQUFLLEVBQUUsVUFBVTtJQUNqQixNQUFNLEVBQUUsVUFBVTtJQUNsQixJQUFJLEVBQUUsVUFBVTtJQUNoQixPQUFPLEVBQUUsVUFBVTtJQUNuQixJQUFJLEVBQUUsVUFBVTtJQUNoQixLQUFLLEVBQUUsVUFBVTtJQUNqQixJQUFJLEVBQUUsVUFBVTtDQUNqQixDQUFDO0FBRUYsU0FBUyxhQUFhLENBQUMsS0FBYSxFQUFFLE1BQWMsRUFBRSxPQUFlO0lBQ25FLE9BQU8sR0FBRyxLQUFLLEdBQUcsTUFBTSxHQUFHLE1BQU0sQ0FBQyxLQUFLLElBQUksT0FBTyxFQUFFLENBQUM7QUFDdkQsQ0FBQztBQUVZLFFBQUEsTUFBTSxHQUFHO0lBQ3BCLElBQUksQ0FBQyxPQUFlO1FBQ2xCLE9BQU8sQ0FBQyxHQUFHLENBQUMsYUFBYSxDQUFDLE1BQU0sQ0FBQyxJQUFJLEVBQUUsR0FBRyxFQUFFLE9BQU8sQ0FBQyxDQUFDLENBQUM7SUFDeEQsQ0FBQztJQUVELE9BQU8sQ0FBQyxPQUFlO1FBQ3JCLE9BQU8sQ0FBQyxHQUFHLENBQUMsYUFBYSxDQUFDLE1BQU0sQ0FBQyxLQUFLLEVBQUUsR0FBRyxFQUFFLE9BQU8sQ0FBQyxDQUFDLENBQUM7SUFDekQsQ0FBQztJQUVELElBQUksQ0FBQyxPQUFlO1FBQ2xCLE9BQU8sQ0FBQyxHQUFHLENBQUMsYUFBYSxDQUFDLE1BQU0sQ0FBQyxNQUFNLEVBQUUsR0FBRyxFQUFFLE9BQU8sQ0FBQyxDQUFDLENBQUM7SUFDMUQsQ0FBQztJQUVELEtBQUssQ0FBQyxPQUFlO1FBQ25CLE9BQU8sQ0FBQyxLQUFLLENBQUMsYUFBYSxDQUFDLE1BQU0sQ0FBQyxHQUFHLEVBQUUsR0FBRyxFQUFFLE9BQU8sQ0FBQyxDQUFDLENBQUM7SUFDekQsQ0FBQztJQUVELEtBQUssQ0FBQyxPQUFlO1FBQ25CLElBQUksT0FBTyxDQUFDLEdBQUcsQ0FBQyxLQUFLLElBQUksT0FBTyxDQUFDLEdBQUcsQ0FBQyxZQUFZLEVBQUUsQ0FBQztZQUNsRCxPQUFPLENBQUMsR0FBRyxDQUFDLGFBQWEsQ0FBQyxNQUFNLENBQUMsSUFBSSxFQUFFLEdBQUcsRUFBRSxPQUFPLENBQUMsQ0FBQyxDQUFDO1FBQ3hELENBQUM7SUFDSCxDQUFDO0lBRUQsMkJBQTJCO0lBQzNCLEdBQUcsQ0FBQyxPQUFlO1FBQ2pCLE9BQU8sQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFDLENBQUM7SUFDdkIsQ0FBQztJQUVELGFBQWE7SUFDYixPQUFPO1FBQ0wsT0FBTyxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsQ0FBQztJQUNsQixDQUFDO0lBRUQsc0NBQXNDO0lBQ3RDLElBQUksQ0FBQyxJQUFZO1FBQ2YsT0FBTyxHQUFHLE1BQU0sQ0FBQyxJQUFJLEdBQUcsSUFBSSxHQUFHLE1BQU0sQ0FBQyxLQUFLLEVBQUUsQ0FBQztJQUNoRCxDQUFDO0lBRUQsS0FBSyxDQUFDLElBQVk7UUFDaEIsT0FBTyxHQUFHLE1BQU0sQ0FBQyxLQUFLLEdBQUcsSUFBSSxHQUFHLE1BQU0sQ0FBQyxLQUFLLEVBQUUsQ0FBQztJQUNqRCxDQUFDO0lBRUQsTUFBTSxDQUFDLElBQVk7UUFDakIsT0FBTyxHQUFHLE1BQU0sQ0FBQyxNQUFNLEdBQUcsSUFBSSxHQUFHLE1BQU0sQ0FBQyxLQUFLLEVBQUUsQ0FBQztJQUNsRCxDQUFDO0lBRUQsR0FBRyxDQUFDLElBQVk7UUFDZCxPQUFPLEdBQUcsTUFBTSxDQUFDLEdBQUcsR0FBRyxJQUFJLEdBQUcsTUFBTSxDQUFDLEtBQUssRUFBRSxDQUFDO0lBQy9DLENBQUM7Q0FDRixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBTaW1wbGUgbG9nZ2VyIHV0aWxpdHkgZm9yIENMSSBvdXRwdXRcbiAqL1xuXG5jb25zdCBjb2xvcnMgPSB7XG4gIHJlc2V0OiAnXFx4MWJbMG0nLFxuICByZWQ6ICdcXHgxYlszMW0nLFxuICBncmVlbjogJ1xceDFiWzMybScsXG4gIHllbGxvdzogJ1xceDFiWzMzbScsXG4gIGJsdWU6ICdcXHgxYlszNG0nLFxuICBtYWdlbnRhOiAnXFx4MWJbMzVtJyxcbiAgY3lhbjogJ1xceDFiWzM2bScsXG4gIHdoaXRlOiAnXFx4MWJbMzdtJyxcbiAgZ3JheTogJ1xceDFiWzkwbScsXG59O1xuXG5mdW5jdGlvbiBmb3JtYXRNZXNzYWdlKGNvbG9yOiBzdHJpbmcsIHByZWZpeDogc3RyaW5nLCBtZXNzYWdlOiBzdHJpbmcpOiBzdHJpbmcge1xuICByZXR1cm4gYCR7Y29sb3J9JHtwcmVmaXh9JHtjb2xvcnMucmVzZXR9ICR7bWVzc2FnZX1gO1xufVxuXG5leHBvcnQgY29uc3QgbG9nZ2VyID0ge1xuICBpbmZvKG1lc3NhZ2U6IHN0cmluZyk6IHZvaWQge1xuICAgIGNvbnNvbGUubG9nKGZvcm1hdE1lc3NhZ2UoY29sb3JzLmJsdWUsICfil4snLCBtZXNzYWdlKSk7XG4gIH0sXG5cbiAgc3VjY2VzcyhtZXNzYWdlOiBzdHJpbmcpOiB2b2lkIHtcbiAgICBjb25zb2xlLmxvZyhmb3JtYXRNZXNzYWdlKGNvbG9ycy5ncmVlbiwgJ+KckycsIG1lc3NhZ2UpKTtcbiAgfSxcblxuICB3YXJuKG1lc3NhZ2U6IHN0cmluZyk6IHZvaWQge1xuICAgIGNvbnNvbGUubG9nKGZvcm1hdE1lc3NhZ2UoY29sb3JzLnllbGxvdywgJ+KaoCcsIG1lc3NhZ2UpKTtcbiAgfSxcblxuICBlcnJvcihtZXNzYWdlOiBzdHJpbmcpOiB2b2lkIHtcbiAgICBjb25zb2xlLmVycm9yKGZvcm1hdE1lc3NhZ2UoY29sb3JzLnJlZCwgJ+KclycsIG1lc3NhZ2UpKTtcbiAgfSxcblxuICBkZWJ1ZyhtZXNzYWdlOiBzdHJpbmcpOiB2b2lkIHtcbiAgICBpZiAocHJvY2Vzcy5lbnYuREVCVUcgfHwgcHJvY2Vzcy5lbnYuREVWRE9DX0RFQlVHKSB7XG4gICAgICBjb25zb2xlLmxvZyhmb3JtYXRNZXNzYWdlKGNvbG9ycy5ncmF5LCAn4ouvJywgbWVzc2FnZSkpO1xuICAgIH1cbiAgfSxcblxuICAvLyBQbGFpbiBsb2cgd2l0aG91dCBwcmVmaXhcbiAgbG9nKG1lc3NhZ2U6IHN0cmluZyk6IHZvaWQge1xuICAgIGNvbnNvbGUubG9nKG1lc3NhZ2UpO1xuICB9LFxuXG4gIC8vIEVtcHR5IGxpbmVcbiAgbmV3bGluZSgpOiB2b2lkIHtcbiAgICBjb25zb2xlLmxvZygnJyk7XG4gIH0sXG5cbiAgLy8gQ29sb3IgaGVscGVycyBmb3IgaW5saW5lIGZvcm1hdHRpbmdcbiAgY3lhbih0ZXh0OiBzdHJpbmcpOiBzdHJpbmcge1xuICAgIHJldHVybiBgJHtjb2xvcnMuY3lhbn0ke3RleHR9JHtjb2xvcnMucmVzZXR9YDtcbiAgfSxcblxuICBncmVlbih0ZXh0OiBzdHJpbmcpOiBzdHJpbmcge1xuICAgIHJldHVybiBgJHtjb2xvcnMuZ3JlZW59JHt0ZXh0fSR7Y29sb3JzLnJlc2V0fWA7XG4gIH0sXG5cbiAgeWVsbG93KHRleHQ6IHN0cmluZyk6IHN0cmluZyB7XG4gICAgcmV0dXJuIGAke2NvbG9ycy55ZWxsb3d9JHt0ZXh0fSR7Y29sb3JzLnJlc2V0fWA7XG4gIH0sXG5cbiAgcmVkKHRleHQ6IHN0cmluZyk6IHN0cmluZyB7XG4gICAgcmV0dXJuIGAke2NvbG9ycy5yZWR9JHt0ZXh0fSR7Y29sb3JzLnJlc2V0fWA7XG4gIH0sXG59O1xuIl19
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Get the renderer directory
3
+ *
4
+ * The renderer is bundled with the package at:
5
+ * - Development: packages/devdoc/renderer (built by scripts/build.js)
6
+ * - Published: node_modules/@brainfish/devdoc/renderer
7
+ */
8
+ export declare function getRendererDir(): string | null;
9
+ /**
10
+ * Check if we're running in development mode (from source)
11
+ */
12
+ export declare function isDevelopment(): boolean;
13
+ /**
14
+ * Get the package root directory
15
+ */
16
+ export declare function getPackageRoot(): string;
@@ -0,0 +1,50 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.getRendererDir = getRendererDir;
7
+ exports.isDevelopment = isDevelopment;
8
+ exports.getPackageRoot = getPackageRoot;
9
+ const path_1 = __importDefault(require("path"));
10
+ const fs_extra_1 = __importDefault(require("fs-extra"));
11
+ /**
12
+ * Get the renderer directory
13
+ *
14
+ * The renderer is bundled with the package at:
15
+ * - Development: packages/devdoc/renderer (built by scripts/build.js)
16
+ * - Published: node_modules/@brainfish/devdoc/renderer
17
+ */
18
+ function getRendererDir() {
19
+ // __dirname is dist/utils when compiled
20
+ const distDir = __dirname;
21
+ const packageRoot = path_1.default.resolve(distDir, '../..');
22
+ // Check for bundled renderer
23
+ const rendererDir = path_1.default.join(packageRoot, 'renderer');
24
+ if (fs_extra_1.default.existsSync(rendererDir) && fs_extra_1.default.existsSync(path_1.default.join(rendererDir, 'package.json'))) {
25
+ return rendererDir;
26
+ }
27
+ // Development fallback: look for the main app
28
+ // When developing locally, the renderer might not be built yet
29
+ const devAppDir = path_1.default.resolve(packageRoot, '../..');
30
+ if (fs_extra_1.default.existsSync(path_1.default.join(devAppDir, 'app')) && fs_extra_1.default.existsSync(path_1.default.join(devAppDir, 'package.json'))) {
31
+ return devAppDir;
32
+ }
33
+ return null;
34
+ }
35
+ /**
36
+ * Check if we're running in development mode (from source)
37
+ */
38
+ function isDevelopment() {
39
+ const packageRoot = path_1.default.resolve(__dirname, '../..');
40
+ const rendererDir = path_1.default.join(packageRoot, 'renderer');
41
+ // If bundled renderer doesn't exist, we're in dev mode
42
+ return !fs_extra_1.default.existsSync(rendererDir);
43
+ }
44
+ /**
45
+ * Get the package root directory
46
+ */
47
+ function getPackageRoot() {
48
+ return path_1.default.resolve(__dirname, '../..');
49
+ }
50
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGF0aHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvdXRpbHMvcGF0aHMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7QUFVQSx3Q0FtQkM7QUFLRCxzQ0FNQztBQUtELHdDQUVDO0FBL0NELGdEQUF3QjtBQUN4Qix3REFBMEI7QUFFMUI7Ozs7OztHQU1HO0FBQ0gsU0FBZ0IsY0FBYztJQUM1Qix3Q0FBd0M7SUFDeEMsTUFBTSxPQUFPLEdBQUcsU0FBUyxDQUFDO0lBQzFCLE1BQU0sV0FBVyxHQUFHLGNBQUksQ0FBQyxPQUFPLENBQUMsT0FBTyxFQUFFLE9BQU8sQ0FBQyxDQUFDO0lBRW5ELDZCQUE2QjtJQUM3QixNQUFNLFdBQVcsR0FBRyxjQUFJLENBQUMsSUFBSSxDQUFDLFdBQVcsRUFBRSxVQUFVLENBQUMsQ0FBQztJQUN2RCxJQUFJLGtCQUFFLENBQUMsVUFBVSxDQUFDLFdBQVcsQ0FBQyxJQUFJLGtCQUFFLENBQUMsVUFBVSxDQUFDLGNBQUksQ0FBQyxJQUFJLENBQUMsV0FBVyxFQUFFLGNBQWMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztRQUN4RixPQUFPLFdBQVcsQ0FBQztJQUNyQixDQUFDO0lBRUQsOENBQThDO0lBQzlDLCtEQUErRDtJQUMvRCxNQUFNLFNBQVMsR0FBRyxjQUFJLENBQUMsT0FBTyxDQUFDLFdBQVcsRUFBRSxPQUFPLENBQUMsQ0FBQztJQUNyRCxJQUFJLGtCQUFFLENBQUMsVUFBVSxDQUFDLGNBQUksQ0FBQyxJQUFJLENBQUMsU0FBUyxFQUFFLEtBQUssQ0FBQyxDQUFDLElBQUksa0JBQUUsQ0FBQyxVQUFVLENBQUMsY0FBSSxDQUFDLElBQUksQ0FBQyxTQUFTLEVBQUUsY0FBYyxDQUFDLENBQUMsRUFBRSxDQUFDO1FBQ3RHLE9BQU8sU0FBUyxDQUFDO0lBQ25CLENBQUM7SUFFRCxPQUFPLElBQUksQ0FBQztBQUNkLENBQUM7QUFFRDs7R0FFRztBQUNILFNBQWdCLGFBQWE7SUFDM0IsTUFBTSxXQUFXLEdBQUcsY0FBSSxDQUFDLE9BQU8sQ0FBQyxTQUFTLEVBQUUsT0FBTyxDQUFDLENBQUM7SUFDckQsTUFBTSxXQUFXLEdBQUcsY0FBSSxDQUFDLElBQUksQ0FBQyxXQUFXLEVBQUUsVUFBVSxDQUFDLENBQUM7SUFFdkQsdURBQXVEO0lBQ3ZELE9BQU8sQ0FBQyxrQkFBRSxDQUFDLFVBQVUsQ0FBQyxXQUFXLENBQUMsQ0FBQztBQUNyQyxDQUFDO0FBRUQ7O0dBRUc7QUFDSCxTQUFnQixjQUFjO0lBQzVCLE9BQU8sY0FBSSxDQUFDLE9BQU8sQ0FBQyxTQUFTLEVBQUUsT0FBTyxDQUFDLENBQUM7QUFDMUMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBwYXRoIGZyb20gJ3BhdGgnO1xuaW1wb3J0IGZzIGZyb20gJ2ZzLWV4dHJhJztcblxuLyoqXG4gKiBHZXQgdGhlIHJlbmRlcmVyIGRpcmVjdG9yeVxuICogXG4gKiBUaGUgcmVuZGVyZXIgaXMgYnVuZGxlZCB3aXRoIHRoZSBwYWNrYWdlIGF0OlxuICogLSBEZXZlbG9wbWVudDogcGFja2FnZXMvZGV2ZG9jL3JlbmRlcmVyIChidWlsdCBieSBzY3JpcHRzL2J1aWxkLmpzKVxuICogLSBQdWJsaXNoZWQ6IG5vZGVfbW9kdWxlcy9AYnJhaW5maXNoL2RldmRvYy9yZW5kZXJlclxuICovXG5leHBvcnQgZnVuY3Rpb24gZ2V0UmVuZGVyZXJEaXIoKTogc3RyaW5nIHwgbnVsbCB7XG4gIC8vIF9fZGlybmFtZSBpcyBkaXN0L3V0aWxzIHdoZW4gY29tcGlsZWRcbiAgY29uc3QgZGlzdERpciA9IF9fZGlybmFtZTtcbiAgY29uc3QgcGFja2FnZVJvb3QgPSBwYXRoLnJlc29sdmUoZGlzdERpciwgJy4uLy4uJyk7XG4gIFxuICAvLyBDaGVjayBmb3IgYnVuZGxlZCByZW5kZXJlclxuICBjb25zdCByZW5kZXJlckRpciA9IHBhdGguam9pbihwYWNrYWdlUm9vdCwgJ3JlbmRlcmVyJyk7XG4gIGlmIChmcy5leGlzdHNTeW5jKHJlbmRlcmVyRGlyKSAmJiBmcy5leGlzdHNTeW5jKHBhdGguam9pbihyZW5kZXJlckRpciwgJ3BhY2thZ2UuanNvbicpKSkge1xuICAgIHJldHVybiByZW5kZXJlckRpcjtcbiAgfVxuICBcbiAgLy8gRGV2ZWxvcG1lbnQgZmFsbGJhY2s6IGxvb2sgZm9yIHRoZSBtYWluIGFwcFxuICAvLyBXaGVuIGRldmVsb3BpbmcgbG9jYWxseSwgdGhlIHJlbmRlcmVyIG1pZ2h0IG5vdCBiZSBidWlsdCB5ZXRcbiAgY29uc3QgZGV2QXBwRGlyID0gcGF0aC5yZXNvbHZlKHBhY2thZ2VSb290LCAnLi4vLi4nKTtcbiAgaWYgKGZzLmV4aXN0c1N5bmMocGF0aC5qb2luKGRldkFwcERpciwgJ2FwcCcpKSAmJiBmcy5leGlzdHNTeW5jKHBhdGguam9pbihkZXZBcHBEaXIsICdwYWNrYWdlLmpzb24nKSkpIHtcbiAgICByZXR1cm4gZGV2QXBwRGlyO1xuICB9XG4gIFxuICByZXR1cm4gbnVsbDtcbn1cblxuLyoqXG4gKiBDaGVjayBpZiB3ZSdyZSBydW5uaW5nIGluIGRldmVsb3BtZW50IG1vZGUgKGZyb20gc291cmNlKVxuICovXG5leHBvcnQgZnVuY3Rpb24gaXNEZXZlbG9wbWVudCgpOiBib29sZWFuIHtcbiAgY29uc3QgcGFja2FnZVJvb3QgPSBwYXRoLnJlc29sdmUoX19kaXJuYW1lLCAnLi4vLi4nKTtcbiAgY29uc3QgcmVuZGVyZXJEaXIgPSBwYXRoLmpvaW4ocGFja2FnZVJvb3QsICdyZW5kZXJlcicpO1xuICBcbiAgLy8gSWYgYnVuZGxlZCByZW5kZXJlciBkb2Vzbid0IGV4aXN0LCB3ZSdyZSBpbiBkZXYgbW9kZVxuICByZXR1cm4gIWZzLmV4aXN0c1N5bmMocmVuZGVyZXJEaXIpO1xufVxuXG4vKipcbiAqIEdldCB0aGUgcGFja2FnZSByb290IGRpcmVjdG9yeVxuICovXG5leHBvcnQgZnVuY3Rpb24gZ2V0UGFja2FnZVJvb3QoKTogc3RyaW5nIHtcbiAgcmV0dXJuIHBhdGgucmVzb2x2ZShfX2Rpcm5hbWUsICcuLi8uLicpO1xufVxuIl19
package/package.json ADDED
@@ -0,0 +1,51 @@
1
+ {
2
+ "name": "@brainfish-ai/devdoc",
3
+ "version": "0.1.21",
4
+ "description": "Documentation framework for developers. Write docs in MDX, preview locally, deploy to Brainfish.",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "bin": {
8
+ "devdoc": "./bin/devdoc.js"
9
+ },
10
+ "scripts": {
11
+ "build:cli": "tsc",
12
+ "build:bundle": "node scripts/build.js",
13
+ "build": "npm run build:cli",
14
+ "dev": "tsc --watch",
15
+ "test:dev": "npm run build:cli && cd ../../devdoc-docs && node ../../packages/devdoc/bin/devdoc.js dev",
16
+ "test:check": "npm run build:cli && cd ../../devdoc-docs && node ../../packages/devdoc/bin/devdoc.js check",
17
+ "prepublishOnly": "npm run build:bundle"
18
+ },
19
+ "keywords": [
20
+ "documentation",
21
+ "docs",
22
+ "mdx",
23
+ "api-docs",
24
+ "developer-docs",
25
+ "cli"
26
+ ],
27
+ "author": "Brainfish",
28
+ "license": "AGPL-3.0",
29
+ "engines": {
30
+ "node": ">=18.0.0"
31
+ },
32
+ "dependencies": {
33
+ "commander": "^12.0.0",
34
+ "fs-extra": "^11.2.0"
35
+ },
36
+ "devDependencies": {
37
+ "@types/node": "^20.0.0",
38
+ "@types/fs-extra": "^11.0.4",
39
+ "typescript": "^5.0.0"
40
+ },
41
+ "files": [
42
+ "bin",
43
+ "dist",
44
+ "renderer",
45
+ "templates"
46
+ ],
47
+ "repository": {
48
+ "type": "git",
49
+ "url": "https://github.com/brainfish/devdoc"
50
+ }
51
+ }
@@ -0,0 +1,123 @@
1
+ import { NextRequest, NextResponse } from 'next/server'
2
+ import { head } from '@vercel/blob'
3
+ import path from 'path'
4
+ import fs from 'fs'
5
+
6
+ // Check if we're in local development mode
7
+ const IS_LOCAL_DEV = !process.env.BLOB_READ_WRITE_TOKEN
8
+ const LOCAL_STORAGE_DIR = path.join(process.cwd(), '.devdoc-storage')
9
+
10
+ /**
11
+ * Asset proxy - serves uploaded assets for multi-tenant docs
12
+ *
13
+ * GET /api/assets/[slug]/[...path]
14
+ *
15
+ * This allows MDX files to reference assets as:
16
+ * ![logo](/api/assets/my-project/logo.png)
17
+ *
18
+ * Or with the middleware rewrite, simply:
19
+ * ![logo](/logo.png) -> rewrites to /api/assets/[slug]/logo.png
20
+ */
21
+ export async function GET(
22
+ request: NextRequest,
23
+ { params }: { params: Promise<{ path: string[] }> }
24
+ ) {
25
+ try {
26
+ const { path: pathSegments } = await params
27
+
28
+ if (!pathSegments || pathSegments.length < 2) {
29
+ return NextResponse.json(
30
+ { error: 'Invalid asset path' },
31
+ { status: 400 }
32
+ )
33
+ }
34
+
35
+ // First segment is the project slug, rest is the asset path
36
+ const [slug, ...assetPath] = pathSegments
37
+ const fileName = assetPath.join('/')
38
+
39
+ if (!slug || !fileName) {
40
+ return NextResponse.json(
41
+ { error: 'Missing slug or file path' },
42
+ { status: 400 }
43
+ )
44
+ }
45
+
46
+ // Build blob path
47
+ const blobPath = `projects/${slug}/assets/${fileName}`
48
+
49
+ if (IS_LOCAL_DEV) {
50
+ // Local development - serve from filesystem
51
+ const filePath = path.join(LOCAL_STORAGE_DIR, 'projects', slug, 'assets', fileName)
52
+
53
+ if (!fs.existsSync(filePath)) {
54
+ return NextResponse.json(
55
+ { error: 'Asset not found' },
56
+ { status: 404 }
57
+ )
58
+ }
59
+
60
+ const fileBuffer = fs.readFileSync(filePath)
61
+ const contentType = getContentType(fileName)
62
+
63
+ return new NextResponse(fileBuffer, {
64
+ status: 200,
65
+ headers: {
66
+ 'Content-Type': contentType,
67
+ 'Cache-Control': 'public, max-age=31536000, immutable',
68
+ },
69
+ })
70
+ }
71
+
72
+ // Production - fetch from Vercel Blob
73
+ const blobInfo = await head(blobPath).catch(() => null)
74
+
75
+ if (!blobInfo) {
76
+ return NextResponse.json(
77
+ { error: 'Asset not found' },
78
+ { status: 404 }
79
+ )
80
+ }
81
+
82
+ // Redirect to the blob URL (more efficient than proxying)
83
+ return NextResponse.redirect(blobInfo.url, {
84
+ status: 302,
85
+ headers: {
86
+ 'Cache-Control': 'public, max-age=31536000, immutable',
87
+ },
88
+ })
89
+
90
+ } catch (error) {
91
+ console.error('[Asset Proxy] Error:', error)
92
+ return NextResponse.json(
93
+ { error: 'Failed to serve asset' },
94
+ { status: 500 }
95
+ )
96
+ }
97
+ }
98
+
99
+ /**
100
+ * Get content type from file extension
101
+ */
102
+ function getContentType(fileName: string): string {
103
+ const ext = fileName.split('.').pop()?.toLowerCase()
104
+ const types: Record<string, string> = {
105
+ 'jpg': 'image/jpeg',
106
+ 'jpeg': 'image/jpeg',
107
+ 'png': 'image/png',
108
+ 'gif': 'image/gif',
109
+ 'webp': 'image/webp',
110
+ 'svg': 'image/svg+xml',
111
+ 'ico': 'image/x-icon',
112
+ 'pdf': 'application/pdf',
113
+ 'mp4': 'video/mp4',
114
+ 'webm': 'video/webm',
115
+ 'mp3': 'audio/mpeg',
116
+ 'wav': 'audio/wav',
117
+ 'woff': 'font/woff',
118
+ 'woff2': 'font/woff2',
119
+ 'ttf': 'font/ttf',
120
+ 'otf': 'font/otf',
121
+ }
122
+ return types[ext || ''] || 'application/octet-stream'
123
+ }