@brainfish-ai/devdoc 0.1.41 → 0.1.43

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 (400) hide show
  1. package/ai-agents/.claude/skills/bootstrap-docs/SKILL.md +710 -79
  2. package/ai-agents/.claude/skills/check-docs/SKILL.md +83 -8
  3. package/ai-agents/.claude/skills/create-doc/SKILL.md +267 -55
  4. package/ai-agents/.claude/skills/update-doc/SKILL.md +162 -63
  5. package/ai-agents/.cursor/rules/devdoc-bootstrap.mdc +145 -15
  6. package/ai-agents/.cursor/rules/devdoc-create.mdc +108 -57
  7. package/ai-agents/.cursor/rules/devdoc-update.mdc +93 -70
  8. package/ai-agents/.cursor/rules/devdoc.mdc +21 -0
  9. package/ai-agents/schemas/docs.schema.json +332 -0
  10. package/ai-agents/schemas/theme.schema.json +243 -0
  11. package/dist/cli/commands/create.js +4 -9
  12. package/dist/cli/commands/deploy.js +50 -25
  13. package/dist/cli/commands/dev.js +19 -10
  14. package/package.json +3 -2
  15. package/renderer/app/api/assets/[...path]/route.js +108 -0
  16. package/renderer/app/api/assets/route.js +114 -0
  17. package/renderer/app/api/assets/upload/route.js +163 -0
  18. package/renderer/app/api/auth-schemes/route.js +58 -0
  19. package/renderer/app/api/chat/route.js +759 -0
  20. package/renderer/app/api/codegen/route.js +52 -0
  21. package/renderer/app/api/collections/route.js +675 -0
  22. package/renderer/app/api/debug/route.js +47 -0
  23. package/renderer/app/api/deploy/route.js +199 -0
  24. package/renderer/app/api/device/route.js +36 -0
  25. package/renderer/app/api/docs/route.js +205 -0
  26. package/renderer/app/api/domains/add/route.js +121 -0
  27. package/renderer/app/api/domains/lookup/route.js +43 -0
  28. package/renderer/app/api/domains/remove/route.js +89 -0
  29. package/renderer/app/api/domains/status/route.js +140 -0
  30. package/renderer/app/api/domains/verify/route.js +168 -0
  31. package/renderer/app/api/keys/regenerate/route.js +71 -0
  32. package/renderer/app/api/local-assets/[...path]/route.js +108 -0
  33. package/renderer/app/api/openapi-spec/route.js +73 -0
  34. package/renderer/app/api/projects/[slug]/route.js +129 -0
  35. package/renderer/app/api/projects/[slug]/stats/route.js +80 -0
  36. package/renderer/app/api/projects/register/route.js +176 -0
  37. package/renderer/app/api/proxy/route.js +139 -0
  38. package/renderer/app/api/proxy-stream/route.js +156 -0
  39. package/renderer/app/api/redirects/route.js +35 -0
  40. package/renderer/app/api/schema/route.js +85 -0
  41. package/renderer/app/api/subdomains/check/route.js +158 -0
  42. package/renderer/app/api/suggestions/route.js +175 -0
  43. package/renderer/app/layout.js +47 -0
  44. package/renderer/app/llms-full.txt/route.js +257 -0
  45. package/renderer/app/llms.txt/route.js +219 -0
  46. package/renderer/app/page.js +12 -0
  47. package/renderer/app/robots.txt/route.js +66 -0
  48. package/renderer/app/sitemap.xml/route.js +145 -0
  49. package/renderer/components/docs/index.js +8 -0
  50. package/renderer/components/docs/mdx/accordion.js +113 -0
  51. package/renderer/components/docs/mdx/badge.js +72 -0
  52. package/renderer/components/docs/mdx/callouts.js +137 -0
  53. package/renderer/components/docs/mdx/cards.js +175 -0
  54. package/renderer/components/docs/mdx/changelog.js +100 -0
  55. package/renderer/components/docs/mdx/code-block.js +147 -0
  56. package/renderer/components/docs/mdx/code-group.js +287 -0
  57. package/renderer/components/docs/mdx/file-embeds.js +82 -0
  58. package/renderer/components/docs/mdx/frame.js +59 -0
  59. package/renderer/components/docs/mdx/highlight.js +90 -0
  60. package/renderer/components/docs/mdx/iframe.js +69 -0
  61. package/renderer/components/docs/mdx/image.js +135 -0
  62. package/renderer/components/docs/mdx/index.js +134 -0
  63. package/renderer/components/docs/mdx/landing.js +315 -0
  64. package/renderer/components/docs/mdx/mermaid.js +212 -0
  65. package/renderer/components/docs/mdx/param-field.js +112 -0
  66. package/renderer/components/docs/mdx/steps.js +74 -0
  67. package/renderer/components/docs/mdx/tabs.js +50 -0
  68. package/renderer/components/docs/mdx-renderer.js +77 -0
  69. package/renderer/components/docs/navigation/breadcrumbs.js +64 -0
  70. package/renderer/components/docs/navigation/index.js +6 -0
  71. package/renderer/components/docs/navigation/page-nav.js +57 -0
  72. package/renderer/components/docs/navigation/sidebar.js +375 -0
  73. package/renderer/components/docs/navigation/toc.js +89 -0
  74. package/renderer/components/docs/notice.js +77 -0
  75. package/renderer/components/docs-header.js +202 -0
  76. package/renderer/components/docs-viewer/agent/agent-chat.js +1930 -0
  77. package/renderer/components/docs-viewer/agent/cards/debug-context-card.js +107 -0
  78. package/renderer/components/docs-viewer/agent/cards/endpoint-context-card.js +57 -0
  79. package/renderer/components/docs-viewer/agent/cards/index.js +45 -0
  80. package/renderer/components/docs-viewer/agent/cards/response-options-card.js +154 -0
  81. package/renderer/components/docs-viewer/agent/cards/types.js +22 -0
  82. package/renderer/components/docs-viewer/agent/chat-message.js +2 -0
  83. package/renderer/components/docs-viewer/agent/index.js +4 -0
  84. package/renderer/components/docs-viewer/agent/messages/assistant-message.js +108 -0
  85. package/renderer/components/docs-viewer/agent/messages/chat-message.js +34 -0
  86. package/renderer/components/docs-viewer/agent/messages/index.js +6 -0
  87. package/renderer/components/docs-viewer/agent/messages/tool-call-display.js +1065 -0
  88. package/renderer/components/docs-viewer/agent/messages/types.js +2 -0
  89. package/renderer/components/docs-viewer/agent/messages/typing-indicator.js +26 -0
  90. package/renderer/components/docs-viewer/agent/messages/user-message.js +37 -0
  91. package/renderer/components/docs-viewer/code-editor/{index.tsx → index.js} +1 -1
  92. package/renderer/components/docs-viewer/code-editor/notes-mode.js +1338 -0
  93. package/renderer/components/docs-viewer/content/changelog-page.js +297 -0
  94. package/renderer/components/docs-viewer/content/doc-page.js +264 -0
  95. package/renderer/components/docs-viewer/content/documentation-viewer.js +14 -0
  96. package/renderer/components/docs-viewer/content/index.js +29 -0
  97. package/renderer/components/docs-viewer/content/not-found-page.js +300 -0
  98. package/renderer/components/docs-viewer/content/request-details.js +528 -0
  99. package/renderer/components/docs-viewer/content/sections/auth.js +108 -0
  100. package/renderer/components/docs-viewer/content/sections/body.js +80 -0
  101. package/renderer/components/docs-viewer/content/sections/headers.js +64 -0
  102. package/renderer/components/docs-viewer/content/sections/overview.js +56 -0
  103. package/renderer/components/docs-viewer/content/sections/parameters.js +64 -0
  104. package/renderer/components/docs-viewer/content/sections/responses.js +91 -0
  105. package/renderer/components/docs-viewer/global-auth-modal.js +427 -0
  106. package/renderer/components/docs-viewer/index.js +1552 -0
  107. package/renderer/components/docs-viewer/playground/auth-editor.js +418 -0
  108. package/renderer/components/docs-viewer/playground/body-editor.js +240 -0
  109. package/renderer/components/docs-viewer/playground/code-editor.js +135 -0
  110. package/renderer/components/docs-viewer/playground/code-snippet.js +393 -0
  111. package/renderer/components/docs-viewer/playground/graphql-playground.js +734 -0
  112. package/renderer/components/docs-viewer/playground/index.js +682 -0
  113. package/renderer/components/docs-viewer/playground/key-value-editor.js +317 -0
  114. package/renderer/components/docs-viewer/playground/method-selector.js +65 -0
  115. package/renderer/components/docs-viewer/playground/request-builder.js +181 -0
  116. package/renderer/components/docs-viewer/playground/request-tabs.js +240 -0
  117. package/renderer/components/docs-viewer/playground/response-cards/idle-card.js +42 -0
  118. package/renderer/components/docs-viewer/playground/response-cards/index.js +72 -0
  119. package/renderer/components/docs-viewer/playground/response-cards/loading-card.js +24 -0
  120. package/renderer/components/docs-viewer/playground/response-cards/network-error-card.js +28 -0
  121. package/renderer/components/docs-viewer/playground/response-cards/response-body-card.js +308 -0
  122. package/renderer/components/docs-viewer/playground/response-cards/types.js +9 -0
  123. package/renderer/components/docs-viewer/playground/response-viewer.js +18 -0
  124. package/renderer/components/docs-viewer/search/index.js +2 -0
  125. package/renderer/components/docs-viewer/search/search-dialog.js +367 -0
  126. package/renderer/components/docs-viewer/search/use-search.js +89 -0
  127. package/renderer/components/docs-viewer/shared/markdown-renderer.js +423 -0
  128. package/renderer/components/docs-viewer/shared/method-badge.js +23 -0
  129. package/renderer/components/docs-viewer/shared/schema-viewer.js +321 -0
  130. package/renderer/components/docs-viewer/sidebar/collection-tree.js +222 -0
  131. package/renderer/components/docs-viewer/sidebar/endpoint-options.js +512 -0
  132. package/renderer/components/docs-viewer/sidebar/index.js +196 -0
  133. package/renderer/components/docs-viewer/sidebar/right-sidebar.js +163 -0
  134. package/renderer/components/docs-viewer/sidebar/sidebar-group.js +87 -0
  135. package/renderer/components/docs-viewer/sidebar/sidebar-item.js +172 -0
  136. package/renderer/components/docs-viewer/sidebar/sidebar-section.js +31 -0
  137. package/renderer/components/theme-provider.js +10 -0
  138. package/renderer/components/theme-toggle.js +106 -0
  139. package/renderer/components/ui/badge.js +29 -0
  140. package/renderer/components/ui/button.js +40 -0
  141. package/renderer/components/ui/dialog.js +50 -0
  142. package/renderer/components/ui/dropdown-menu.js +143 -0
  143. package/renderer/components/ui/input.js +12 -0
  144. package/renderer/components/ui/label.js +13 -0
  145. package/renderer/components/ui/navigation-menu.js +83 -0
  146. package/renderer/components/ui/select.js +116 -0
  147. package/renderer/components/ui/spinner.js +92 -0
  148. package/renderer/components/ui/tabs.js +34 -0
  149. package/renderer/components/ui/tooltip.js +43 -0
  150. package/renderer/hooks/use-code-copy.js +76 -0
  151. package/renderer/hooks/use-openapi-title.js +33 -0
  152. package/renderer/lib/api-docs/agent/index.js +4 -0
  153. package/renderer/lib/api-docs/agent/indexer.js +254 -0
  154. package/renderer/lib/api-docs/agent/spec-summary.js +227 -0
  155. package/renderer/lib/api-docs/agent/types.js +5 -0
  156. package/renderer/lib/api-docs/auth/auth-context.js +157 -0
  157. package/renderer/lib/api-docs/auth/auth-storage.js +66 -0
  158. package/renderer/lib/api-docs/auth/crypto.js +64 -0
  159. package/renderer/lib/api-docs/auth/index.js +3 -0
  160. package/renderer/lib/api-docs/code-editor/db.js +145 -0
  161. package/renderer/lib/api-docs/code-editor/hooks.js +254 -0
  162. package/renderer/lib/api-docs/code-editor/{index.ts → index.js} +3 -4
  163. package/renderer/lib/api-docs/code-editor/mode-context.js +154 -0
  164. package/renderer/lib/api-docs/code-editor/types.js +53 -0
  165. package/renderer/lib/api-docs/codegen/definitions.js +258 -0
  166. package/renderer/lib/api-docs/codegen/har.js +171 -0
  167. package/renderer/lib/api-docs/codegen/index.js +118 -0
  168. package/renderer/lib/api-docs/factories.js +136 -0
  169. package/renderer/lib/api-docs/{index.ts → index.js} +5 -10
  170. package/renderer/lib/api-docs/mobile-context.js +79 -0
  171. package/renderer/lib/api-docs/navigation-context.js +62 -0
  172. package/renderer/lib/api-docs/parsers/graphql/index.js +50 -0
  173. package/renderer/lib/api-docs/parsers/graphql/parser.js +350 -0
  174. package/renderer/lib/api-docs/parsers/graphql/transformer.js +215 -0
  175. package/renderer/lib/api-docs/parsers/graphql/types.js +46 -0
  176. package/renderer/lib/api-docs/parsers/openapi/dereferencer.js +43 -0
  177. package/renderer/lib/api-docs/parsers/openapi/extractors/auth.js +486 -0
  178. package/renderer/lib/api-docs/parsers/openapi/extractors/body.js +295 -0
  179. package/renderer/lib/api-docs/parsers/openapi/extractors/index.js +132 -0
  180. package/renderer/lib/api-docs/parsers/openapi/index.js +127 -0
  181. package/renderer/lib/api-docs/parsers/openapi/transformer.js +192 -0
  182. package/renderer/lib/api-docs/parsers/openapi/validator.js +24 -0
  183. package/renderer/lib/api-docs/playground/context.js +65 -0
  184. package/renderer/lib/api-docs/playground/navigation-context.js +74 -0
  185. package/renderer/lib/api-docs/playground/request-builder.js +163 -0
  186. package/renderer/lib/api-docs/playground/request-runner.js +224 -0
  187. package/renderer/lib/api-docs/playground/types.js +5 -0
  188. package/renderer/lib/api-docs/types.js +23 -0
  189. package/renderer/lib/api-docs/utils.js +212 -0
  190. package/renderer/lib/cache.js +157 -0
  191. package/renderer/lib/docs/config/domain-schema.js +161 -0
  192. package/renderer/lib/docs/config/index.js +5 -0
  193. package/renderer/lib/docs/config/loader.js +113 -0
  194. package/renderer/lib/docs/config/schema.js +269 -0
  195. package/renderer/lib/docs/index.js +8 -0
  196. package/renderer/lib/docs/mdx/compiler.js +128 -0
  197. package/renderer/lib/docs/mdx/frontmatter.js +73 -0
  198. package/renderer/lib/docs/mdx/index.js +8 -0
  199. package/renderer/lib/docs/navigation/generator.js +269 -0
  200. package/renderer/lib/docs/navigation/index.js +4 -0
  201. package/renderer/lib/docs/navigation/types.js +9 -0
  202. package/renderer/lib/docs-navigation-context.js +40 -0
  203. package/renderer/lib/multi-tenant/context.js +80 -0
  204. package/renderer/lib/storage/blob.js +767 -0
  205. package/renderer/lib/utils/icons.js +30 -0
  206. package/renderer/lib/utils.js +5 -0
  207. package/renderer/next.config.js +62 -0
  208. package/renderer/tsconfig.json +23 -5
  209. package/renderer/app/api/assets/[...path]/route.ts +0 -123
  210. package/renderer/app/api/assets/route.ts +0 -124
  211. package/renderer/app/api/assets/upload/route.ts +0 -177
  212. package/renderer/app/api/auth-schemes/route.ts +0 -77
  213. package/renderer/app/api/chat/route.ts +0 -858
  214. package/renderer/app/api/codegen/route.ts +0 -72
  215. package/renderer/app/api/collections/route.ts +0 -1002
  216. package/renderer/app/api/debug/route.ts +0 -53
  217. package/renderer/app/api/deploy/route.ts +0 -234
  218. package/renderer/app/api/device/route.ts +0 -42
  219. package/renderer/app/api/docs/route.ts +0 -201
  220. package/renderer/app/api/domains/add/route.ts +0 -132
  221. package/renderer/app/api/domains/lookup/route.ts +0 -43
  222. package/renderer/app/api/domains/remove/route.ts +0 -100
  223. package/renderer/app/api/domains/status/route.ts +0 -158
  224. package/renderer/app/api/domains/verify/route.ts +0 -181
  225. package/renderer/app/api/keys/regenerate/route.ts +0 -80
  226. package/renderer/app/api/local-assets/[...path]/route.ts +0 -122
  227. package/renderer/app/api/openapi-spec/route.ts +0 -151
  228. package/renderer/app/api/projects/[slug]/route.ts +0 -153
  229. package/renderer/app/api/projects/[slug]/stats/route.ts +0 -96
  230. package/renderer/app/api/projects/register/route.ts +0 -152
  231. package/renderer/app/api/proxy/route.ts +0 -149
  232. package/renderer/app/api/proxy-stream/route.ts +0 -168
  233. package/renderer/app/api/redirects/route.ts +0 -47
  234. package/renderer/app/api/schema/route.ts +0 -73
  235. package/renderer/app/api/subdomains/check/route.ts +0 -172
  236. package/renderer/app/api/suggestions/route.ts +0 -144
  237. package/renderer/app/layout.tsx +0 -54
  238. package/renderer/app/llms-full.txt/route.ts +0 -346
  239. package/renderer/app/llms.txt/route.ts +0 -279
  240. package/renderer/app/page.tsx +0 -14
  241. package/renderer/app/robots.txt/route.ts +0 -84
  242. package/renderer/app/sitemap.xml/route.ts +0 -199
  243. package/renderer/components/docs/index.ts +0 -12
  244. package/renderer/components/docs/mdx/accordion.tsx +0 -169
  245. package/renderer/components/docs/mdx/badge.tsx +0 -132
  246. package/renderer/components/docs/mdx/callouts.tsx +0 -154
  247. package/renderer/components/docs/mdx/cards.tsx +0 -241
  248. package/renderer/components/docs/mdx/changelog.tsx +0 -120
  249. package/renderer/components/docs/mdx/code-block.tsx +0 -186
  250. package/renderer/components/docs/mdx/code-group.tsx +0 -421
  251. package/renderer/components/docs/mdx/file-embeds.tsx +0 -105
  252. package/renderer/components/docs/mdx/frame.tsx +0 -112
  253. package/renderer/components/docs/mdx/highlight.tsx +0 -151
  254. package/renderer/components/docs/mdx/iframe.tsx +0 -134
  255. package/renderer/components/docs/mdx/image.tsx +0 -235
  256. package/renderer/components/docs/mdx/index.ts +0 -237
  257. package/renderer/components/docs/mdx/landing.tsx +0 -684
  258. package/renderer/components/docs/mdx/mermaid.tsx +0 -240
  259. package/renderer/components/docs/mdx/param-field.tsx +0 -200
  260. package/renderer/components/docs/mdx/steps.tsx +0 -113
  261. package/renderer/components/docs/mdx/tabs.tsx +0 -86
  262. package/renderer/components/docs/mdx-renderer.tsx +0 -100
  263. package/renderer/components/docs/navigation/breadcrumbs.tsx +0 -76
  264. package/renderer/components/docs/navigation/index.ts +0 -8
  265. package/renderer/components/docs/navigation/page-nav.tsx +0 -64
  266. package/renderer/components/docs/navigation/sidebar.tsx +0 -515
  267. package/renderer/components/docs/navigation/toc.tsx +0 -113
  268. package/renderer/components/docs/notice.tsx +0 -105
  269. package/renderer/components/docs-header.tsx +0 -278
  270. package/renderer/components/docs-viewer/agent/agent-chat.tsx +0 -2076
  271. package/renderer/components/docs-viewer/agent/cards/debug-context-card.tsx +0 -90
  272. package/renderer/components/docs-viewer/agent/cards/endpoint-context-card.tsx +0 -49
  273. package/renderer/components/docs-viewer/agent/cards/index.tsx +0 -50
  274. package/renderer/components/docs-viewer/agent/cards/response-options-card.tsx +0 -212
  275. package/renderer/components/docs-viewer/agent/cards/types.ts +0 -84
  276. package/renderer/components/docs-viewer/agent/chat-message.tsx +0 -17
  277. package/renderer/components/docs-viewer/agent/index.tsx +0 -6
  278. package/renderer/components/docs-viewer/agent/messages/assistant-message.tsx +0 -119
  279. package/renderer/components/docs-viewer/agent/messages/chat-message.tsx +0 -46
  280. package/renderer/components/docs-viewer/agent/messages/index.ts +0 -17
  281. package/renderer/components/docs-viewer/agent/messages/tool-call-display.tsx +0 -721
  282. package/renderer/components/docs-viewer/agent/messages/types.ts +0 -61
  283. package/renderer/components/docs-viewer/agent/messages/typing-indicator.tsx +0 -24
  284. package/renderer/components/docs-viewer/agent/messages/user-message.tsx +0 -51
  285. package/renderer/components/docs-viewer/code-editor/notes-mode.tsx +0 -1283
  286. package/renderer/components/docs-viewer/content/changelog-page.tsx +0 -331
  287. package/renderer/components/docs-viewer/content/doc-page.tsx +0 -367
  288. package/renderer/components/docs-viewer/content/documentation-viewer.tsx +0 -17
  289. package/renderer/components/docs-viewer/content/index.tsx +0 -29
  290. package/renderer/components/docs-viewer/content/not-found-page.tsx +0 -330
  291. package/renderer/components/docs-viewer/content/request-details.tsx +0 -330
  292. package/renderer/components/docs-viewer/content/sections/auth.tsx +0 -69
  293. package/renderer/components/docs-viewer/content/sections/body.tsx +0 -66
  294. package/renderer/components/docs-viewer/content/sections/headers.tsx +0 -43
  295. package/renderer/components/docs-viewer/content/sections/overview.tsx +0 -40
  296. package/renderer/components/docs-viewer/content/sections/parameters.tsx +0 -43
  297. package/renderer/components/docs-viewer/content/sections/responses.tsx +0 -87
  298. package/renderer/components/docs-viewer/global-auth-modal.tsx +0 -352
  299. package/renderer/components/docs-viewer/index.tsx +0 -1662
  300. package/renderer/components/docs-viewer/playground/auth-editor.tsx +0 -280
  301. package/renderer/components/docs-viewer/playground/body-editor.tsx +0 -221
  302. package/renderer/components/docs-viewer/playground/code-editor.tsx +0 -224
  303. package/renderer/components/docs-viewer/playground/code-snippet.tsx +0 -387
  304. package/renderer/components/docs-viewer/playground/graphql-playground.tsx +0 -745
  305. package/renderer/components/docs-viewer/playground/index.tsx +0 -671
  306. package/renderer/components/docs-viewer/playground/key-value-editor.tsx +0 -261
  307. package/renderer/components/docs-viewer/playground/method-selector.tsx +0 -60
  308. package/renderer/components/docs-viewer/playground/request-builder.tsx +0 -179
  309. package/renderer/components/docs-viewer/playground/request-tabs.tsx +0 -237
  310. package/renderer/components/docs-viewer/playground/response-cards/idle-card.tsx +0 -21
  311. package/renderer/components/docs-viewer/playground/response-cards/index.tsx +0 -93
  312. package/renderer/components/docs-viewer/playground/response-cards/loading-card.tsx +0 -16
  313. package/renderer/components/docs-viewer/playground/response-cards/network-error-card.tsx +0 -23
  314. package/renderer/components/docs-viewer/playground/response-cards/response-body-card.tsx +0 -268
  315. package/renderer/components/docs-viewer/playground/response-cards/types.ts +0 -82
  316. package/renderer/components/docs-viewer/playground/response-viewer.tsx +0 -43
  317. package/renderer/components/docs-viewer/search/index.ts +0 -2
  318. package/renderer/components/docs-viewer/search/search-dialog.tsx +0 -331
  319. package/renderer/components/docs-viewer/search/use-search.ts +0 -117
  320. package/renderer/components/docs-viewer/shared/markdown-renderer.tsx +0 -431
  321. package/renderer/components/docs-viewer/shared/method-badge.tsx +0 -41
  322. package/renderer/components/docs-viewer/shared/schema-viewer.tsx +0 -349
  323. package/renderer/components/docs-viewer/sidebar/collection-tree.tsx +0 -259
  324. package/renderer/components/docs-viewer/sidebar/endpoint-options.tsx +0 -316
  325. package/renderer/components/docs-viewer/sidebar/index.tsx +0 -282
  326. package/renderer/components/docs-viewer/sidebar/right-sidebar.tsx +0 -202
  327. package/renderer/components/docs-viewer/sidebar/sidebar-group.tsx +0 -118
  328. package/renderer/components/docs-viewer/sidebar/sidebar-item.tsx +0 -212
  329. package/renderer/components/docs-viewer/sidebar/sidebar-section.tsx +0 -38
  330. package/renderer/components/theme-provider.tsx +0 -11
  331. package/renderer/components/theme-toggle.tsx +0 -76
  332. package/renderer/components/ui/badge.tsx +0 -46
  333. package/renderer/components/ui/button.tsx +0 -59
  334. package/renderer/components/ui/dialog.tsx +0 -118
  335. package/renderer/components/ui/dropdown-menu.tsx +0 -257
  336. package/renderer/components/ui/input.tsx +0 -21
  337. package/renderer/components/ui/label.tsx +0 -24
  338. package/renderer/components/ui/navigation-menu.tsx +0 -168
  339. package/renderer/components/ui/select.tsx +0 -190
  340. package/renderer/components/ui/spinner.tsx +0 -114
  341. package/renderer/components/ui/tabs.tsx +0 -66
  342. package/renderer/components/ui/tooltip.tsx +0 -61
  343. package/renderer/hooks/use-code-copy.ts +0 -88
  344. package/renderer/hooks/use-openapi-title.ts +0 -44
  345. package/renderer/lib/api-docs/agent/index.ts +0 -6
  346. package/renderer/lib/api-docs/agent/indexer.ts +0 -323
  347. package/renderer/lib/api-docs/agent/spec-summary.ts +0 -335
  348. package/renderer/lib/api-docs/agent/types.ts +0 -116
  349. package/renderer/lib/api-docs/auth/auth-context.tsx +0 -225
  350. package/renderer/lib/api-docs/auth/auth-storage.ts +0 -87
  351. package/renderer/lib/api-docs/auth/crypto.ts +0 -89
  352. package/renderer/lib/api-docs/auth/index.ts +0 -4
  353. package/renderer/lib/api-docs/code-editor/db.ts +0 -164
  354. package/renderer/lib/api-docs/code-editor/hooks.ts +0 -266
  355. package/renderer/lib/api-docs/code-editor/mode-context.tsx +0 -207
  356. package/renderer/lib/api-docs/code-editor/types.ts +0 -105
  357. package/renderer/lib/api-docs/codegen/definitions.ts +0 -297
  358. package/renderer/lib/api-docs/codegen/har.ts +0 -251
  359. package/renderer/lib/api-docs/codegen/index.ts +0 -159
  360. package/renderer/lib/api-docs/factories.ts +0 -170
  361. package/renderer/lib/api-docs/mobile-context.tsx +0 -112
  362. package/renderer/lib/api-docs/navigation-context.tsx +0 -88
  363. package/renderer/lib/api-docs/parsers/graphql/README.md +0 -129
  364. package/renderer/lib/api-docs/parsers/graphql/index.ts +0 -91
  365. package/renderer/lib/api-docs/parsers/graphql/parser.ts +0 -491
  366. package/renderer/lib/api-docs/parsers/graphql/transformer.ts +0 -246
  367. package/renderer/lib/api-docs/parsers/graphql/types.ts +0 -283
  368. package/renderer/lib/api-docs/parsers/openapi/README.md +0 -32
  369. package/renderer/lib/api-docs/parsers/openapi/dereferencer.ts +0 -60
  370. package/renderer/lib/api-docs/parsers/openapi/extractors/auth.ts +0 -574
  371. package/renderer/lib/api-docs/parsers/openapi/extractors/body.ts +0 -403
  372. package/renderer/lib/api-docs/parsers/openapi/extractors/index.ts +0 -232
  373. package/renderer/lib/api-docs/parsers/openapi/index.ts +0 -171
  374. package/renderer/lib/api-docs/parsers/openapi/transformer.ts +0 -278
  375. package/renderer/lib/api-docs/parsers/openapi/validator.ts +0 -31
  376. package/renderer/lib/api-docs/playground/context.tsx +0 -107
  377. package/renderer/lib/api-docs/playground/navigation-context.tsx +0 -124
  378. package/renderer/lib/api-docs/playground/request-builder.ts +0 -223
  379. package/renderer/lib/api-docs/playground/request-runner.ts +0 -282
  380. package/renderer/lib/api-docs/playground/types.ts +0 -35
  381. package/renderer/lib/api-docs/types.ts +0 -269
  382. package/renderer/lib/api-docs/utils.ts +0 -311
  383. package/renderer/lib/cache.ts +0 -193
  384. package/renderer/lib/docs/config/domain-schema.ts +0 -260
  385. package/renderer/lib/docs/config/index.ts +0 -43
  386. package/renderer/lib/docs/config/loader.ts +0 -142
  387. package/renderer/lib/docs/config/schema.ts +0 -308
  388. package/renderer/lib/docs/index.ts +0 -12
  389. package/renderer/lib/docs/mdx/compiler.ts +0 -176
  390. package/renderer/lib/docs/mdx/frontmatter.ts +0 -91
  391. package/renderer/lib/docs/mdx/index.ts +0 -26
  392. package/renderer/lib/docs/navigation/generator.ts +0 -348
  393. package/renderer/lib/docs/navigation/index.ts +0 -12
  394. package/renderer/lib/docs/navigation/types.ts +0 -123
  395. package/renderer/lib/docs-navigation-context.tsx +0 -80
  396. package/renderer/lib/multi-tenant/context.ts +0 -105
  397. package/renderer/lib/storage/blob.ts +0 -1083
  398. package/renderer/lib/utils/icons.ts +0 -48
  399. package/renderer/lib/utils.ts +0 -6
  400. package/renderer/next.config.ts +0 -76
@@ -1,1002 +0,0 @@
1
- import { NextResponse } from 'next/server'
2
- import { readFileSync, existsSync, readdirSync } from 'fs'
3
- import { join, basename, isAbsolute } from 'path'
4
- import matter from 'gray-matter'
5
- import { CacheUtils } from '@/lib/cache'
6
- import { importOpenAPISpec } from '@/lib/api-docs/parsers/openapi'
7
- import { importGraphQLSchema, type BrainfishGraphQLCollection } from '@/lib/api-docs/parsers/graphql'
8
- import { generateAPISummary, formatAPISummaryForPrompt } from '@/lib/api-docs/agent/spec-summary'
9
- import { getProjectContent, type ProjectContent } from '@/lib/storage/blob'
10
- import type { OpenAPI } from 'openapi-types'
11
- import type { BrainfishCollection, BrainfishDocGroup, BrainfishDocPage } from '@/lib/api-docs/types'
12
-
13
- // Configuration
14
- const USE_LOCAL_SPEC = process.env.USE_LOCAL_SPEC !== 'false' // Default to true
15
- const STARTER_PATH = process.env.STARTER_PATH || 'devdoc-docs'
16
- const LOCAL_SPEC_PATH = process.env.LOCAL_SPEC_PATH || `${STARTER_PATH}/api-reference/openapi.json`
17
-
18
- // Helper to resolve paths - supports both relative and absolute STARTER_PATH
19
- function resolvePath(...paths: string[]): string {
20
- if (isAbsolute(STARTER_PATH)) {
21
- return join(STARTER_PATH, ...paths)
22
- }
23
- return join(process.cwd(), STARTER_PATH, ...paths)
24
- }
25
-
26
- // Get the content root directory
27
- function getContentRoot(): string {
28
- if (isAbsolute(STARTER_PATH)) {
29
- return STARTER_PATH
30
- }
31
- return join(process.cwd(), STARTER_PATH)
32
- }
33
- const BRAINFISH_API_BASE_URL = process.env.BRAINFISH_API_BASE_URL || 'https://api.brainfish.ai/api'
34
- const BRAINFISH_CATALOG_ID = process.env.BRAINFISH_CATALOG_ID || 'your_catalog_id_here'
35
- const BRAINFISH_JWT_TOKEN = process.env.BRAINFISH_JWT_TOKEN || 'your_jwt_token_here'
36
-
37
- // Debug logging - only in verbose mode
38
- if (process.env.DEVDOC_VERBOSE === 'true') {
39
- console.log('[Collections] Config:', {
40
- useLocalSpec: USE_LOCAL_SPEC,
41
- starterPath: STARTER_PATH,
42
- localSpecPath: LOCAL_SPEC_PATH,
43
- })
44
- }
45
-
46
- // Cache configuration
47
- const CACHE_KEY = USE_LOCAL_SPEC ? `collections-local` : `collections-${BRAINFISH_CATALOG_ID}`
48
- const CACHE_TTL = 60 * 5 // 5 minutes
49
- const FALLBACK_CACHE_KEY = `${CACHE_KEY}-fallback`
50
- const SUMMARY_CACHE_KEY = USE_LOCAL_SPEC ? `api-summary-local` : `api-summary-${BRAINFISH_CATALOG_ID}`
51
- const SUMMARY_CACHE_TTL = 60 * 60 * 24 // 1 day
52
-
53
- interface OpenApiSpec {
54
- openapi: string
55
- info: {
56
- title: string
57
- version: string
58
- description: string
59
- }
60
- paths: Record<string, unknown>
61
- servers?: Array<{
62
- url: string
63
- description: string
64
- }>
65
- }
66
-
67
- // API version configuration
68
- interface ApiVersionConfig {
69
- version: string
70
- spec: string // Path to the OpenAPI spec file
71
- default?: boolean
72
- }
73
-
74
- // GraphQL schema configuration
75
- interface GraphQLSchemaConfig {
76
- name?: string
77
- schema: string // Path to the GraphQL schema file (.graphql or .gql)
78
- endpoint: string // GraphQL endpoint URL
79
- default?: boolean
80
- }
81
-
82
- // Nested group within pages array
83
- interface DocsConfigNestedGroup {
84
- group: string
85
- pages: string[]
86
- }
87
-
88
- // Page can be a string path or a nested group
89
- type DocsConfigPageItem = string | DocsConfigNestedGroup
90
-
91
- interface DocsConfigTab {
92
- tab: string
93
- type?: 'docs' | 'openapi' | 'changelog' | 'graphql'
94
- path?: string // URL path for the tab (e.g., "/api-reference", "/changelog")
95
- versions?: ApiVersionConfig[] // Multiple API versions (for openapi type)
96
- // GraphQL-specific config
97
- schema?: string // Path to single GraphQL schema file
98
- endpoint?: string // GraphQL endpoint URL
99
- schemas?: GraphQLSchemaConfig[] // Multiple GraphQL schemas
100
- groups?: Array<{
101
- group: string
102
- pages: DocsConfigPageItem[]
103
- icon?: string // Phosphor icon name for the group header
104
- }>
105
- }
106
-
107
- interface DocsConfigLogo {
108
- url?: string
109
- alt?: string
110
- width?: number
111
- height?: number
112
- light?: string
113
- dark?: string
114
- }
115
-
116
- interface DocsConfigHeader {
117
- showAskAI?: boolean
118
- showSearch?: boolean
119
- showThemeToggle?: boolean
120
- }
121
-
122
- interface DocsConfigNavbarLink {
123
- label: string
124
- href: string
125
- external?: boolean
126
- }
127
-
128
- interface DocsConfigNavbarPrimary {
129
- label: string
130
- href: string
131
- }
132
-
133
- interface DocsConfigNavbar {
134
- links?: DocsConfigNavbarLink[]
135
- primary?: DocsConfigNavbarPrimary
136
- }
137
-
138
- interface DocsConfigNotice {
139
- content: string
140
- dismissible?: boolean
141
- background?: string
142
- }
143
-
144
- interface DocsConfigRedirect {
145
- source: string
146
- destination: string
147
- }
148
-
149
- interface DocsConfig {
150
- name?: string
151
- favicon?: string
152
- notice?: DocsConfigNotice
153
- redirects?: DocsConfigRedirect[]
154
- navigation?: {
155
- tabs?: DocsConfigTab[]
156
- }
157
- }
158
-
159
- // Theme configuration (from theme.json)
160
- interface ThemeConfig {
161
- logo?: DocsConfigLogo
162
- header?: DocsConfigHeader
163
- navbar?: DocsConfigNavbar
164
- colors?: {
165
- primary?: string
166
- primaryLight?: string
167
- primaryDark?: string
168
- }
169
- typography?: {
170
- fontFamily?: string
171
- fontFamilyMono?: string
172
- baseFontSize?: string
173
- }
174
- defaultTheme?: 'light' | 'dark' | 'system'
175
- customCss?: string
176
- }
177
-
178
- // API version for the response
179
- interface ApiVersion {
180
- version: string
181
- spec: string
182
- default: boolean
183
- }
184
-
185
- // GraphQL schema for the response
186
- interface GraphQLSchemaInfo {
187
- name: string
188
- schema: string
189
- endpoint: string
190
- default: boolean
191
- }
192
-
193
- // Navigation tab type for the response
194
- interface NavigationTab {
195
- id: string
196
- tab: string // Tab name (used for both navigation and page header)
197
- type: 'docs' | 'openapi' | 'changelog' | 'graphql'
198
- path?: string
199
- order: number
200
- versions?: ApiVersion[] // Available API versions (for openapi type)
201
- graphqlSchemas?: GraphQLSchemaInfo[] // Available GraphQL schemas (for graphql type)
202
- }
203
-
204
- // Changelog release type
205
- interface ChangelogRelease {
206
- version: string
207
- date: string
208
- title: string
209
- slug: string
210
- }
211
-
212
- // Load GraphQL schema from local file
213
- function loadGraphQLSchema(schemaPath: string): string | null {
214
- try {
215
- // Resolve the path similar to OpenAPI spec
216
- const relativePath = schemaPath
217
- const fullPath = relativePath.startsWith(STARTER_PATH) || isAbsolute(relativePath)
218
- ? (isAbsolute(relativePath) ? relativePath : resolvePath(relativePath.replace(STARTER_PATH + '/', '')))
219
- : resolvePath(relativePath)
220
-
221
- if (!existsSync(fullPath)) {
222
- return null
223
- }
224
-
225
- const content = readFileSync(fullPath, 'utf-8')
226
- return content
227
- } catch (error) {
228
- console.error('[Collections] Error loading GraphQL schema:', error)
229
- return null
230
- }
231
- }
232
-
233
- // Load OpenAPI spec from local file
234
- function loadLocalSpec(specPath?: string): OpenApiSpec | null {
235
- try {
236
- // Use provided path or default
237
- const relativePath = specPath || LOCAL_SPEC_PATH
238
- // If the path already includes STARTER_PATH prefix, use it; otherwise prepend
239
- const fullPath = relativePath.startsWith(STARTER_PATH) || isAbsolute(relativePath)
240
- ? (isAbsolute(relativePath) ? relativePath : resolvePath(relativePath.replace(STARTER_PATH + '/', '')))
241
- : resolvePath(relativePath)
242
-
243
- if (!existsSync(fullPath)) {
244
- return null
245
- }
246
-
247
- const content = readFileSync(fullPath, 'utf-8')
248
- const spec = JSON.parse(content) as OpenApiSpec
249
-
250
- return spec
251
- } catch (error) {
252
- console.error('[Collections] Error loading local spec:', error)
253
- return null
254
- }
255
- }
256
-
257
- // Load docs.json configuration
258
- function loadDocsConfig(): DocsConfig | null {
259
- try {
260
- const configPath = resolvePath('docs.json')
261
-
262
- if (!existsSync(configPath)) {
263
- return null
264
- }
265
-
266
- const content = readFileSync(configPath, 'utf-8')
267
- return JSON.parse(content) as DocsConfig
268
- } catch (error) {
269
- console.error('[Collections] Error loading docs.json:', error)
270
- return null
271
- }
272
- }
273
-
274
- // Load theme.json configuration
275
- function loadThemeConfig(): ThemeConfig | null {
276
- try {
277
- const configPath = resolvePath('theme.json')
278
-
279
- if (!existsSync(configPath)) {
280
- return null
281
- }
282
-
283
- const content = readFileSync(configPath, 'utf-8')
284
- return JSON.parse(content) as ThemeConfig
285
- } catch (error) {
286
- console.error('[Collections] Error loading theme.json:', error)
287
- return null
288
- }
289
- }
290
-
291
- // Load custom CSS content
292
- function loadCustomCss(cssPath?: string): string | null {
293
- if (!cssPath) return null
294
-
295
- try {
296
- const fullPath = resolvePath(cssPath)
297
-
298
- if (!existsSync(fullPath)) {
299
- return null
300
- }
301
-
302
- return readFileSync(fullPath, 'utf-8')
303
- } catch (error) {
304
- console.error('[Collections] Error loading custom CSS:', error)
305
- return null
306
- }
307
- }
308
-
309
- // Load MDX page metadata
310
- function loadPageMeta(pagePath: string): { title: string; description?: string; icon?: string } | null {
311
- try {
312
- const contentRoot = getContentRoot()
313
-
314
- // Try .mdx then .md
315
- let fullPath = join(contentRoot, `${pagePath}.mdx`)
316
- if (!existsSync(fullPath)) {
317
- fullPath = join(contentRoot, `${pagePath}.md`)
318
- }
319
- if (!existsSync(fullPath)) {
320
- return null
321
- }
322
-
323
- const content = readFileSync(fullPath, 'utf-8')
324
- const { data } = matter(content)
325
-
326
- return {
327
- title: data.title || basename(pagePath),
328
- description: data.description,
329
- icon: data.icon,
330
- }
331
- } catch (error) {
332
- console.error('[Collections] Error loading page meta:', pagePath, error)
333
- return null
334
- }
335
- }
336
-
337
- // Extract navigation tabs from docs.json in order
338
- function buildNavigationTabs(config: DocsConfig): NavigationTab[] {
339
- const tabs: NavigationTab[] = []
340
-
341
- if (!config.navigation?.tabs) {
342
- return tabs
343
- }
344
-
345
- config.navigation.tabs.forEach((tab, index) => {
346
- // Convert tab name to id (e.g., "API Reference" -> "api-reference")
347
- const id = tab.tab.toLowerCase().replace(/\s+/g, '-')
348
-
349
- // Determine the type (default to 'docs' if not specified)
350
- const type = tab.type || 'docs'
351
-
352
- // Build versions array for openapi tabs
353
- let versions: ApiVersion[] | undefined
354
- if (tab.type === 'openapi' && tab.versions && tab.versions.length > 0) {
355
- versions = tab.versions.map(v => ({
356
- version: v.version,
357
- spec: v.spec,
358
- default: v.default || false,
359
- }))
360
- // Ensure at least one default
361
- if (!versions.some(v => v.default)) {
362
- versions[0].default = true
363
- }
364
- }
365
-
366
- // Build graphql schemas array for graphql tabs
367
- let graphqlSchemas: GraphQLSchemaInfo[] | undefined
368
- if (tab.type === 'graphql') {
369
- if (tab.schemas && tab.schemas.length > 0) {
370
- // Multiple schemas
371
- graphqlSchemas = tab.schemas.map(s => ({
372
- name: s.name || 'GraphQL API',
373
- schema: s.schema,
374
- endpoint: s.endpoint,
375
- default: s.default || false,
376
- }))
377
- // Ensure at least one default
378
- if (!graphqlSchemas.some(s => s.default)) {
379
- graphqlSchemas[0].default = true
380
- }
381
- } else if (tab.schema && tab.endpoint) {
382
- // Single schema
383
- graphqlSchemas = [{
384
- name: tab.tab,
385
- schema: tab.schema,
386
- endpoint: tab.endpoint,
387
- default: true,
388
- }]
389
- }
390
- }
391
-
392
- tabs.push({
393
- id,
394
- tab: tab.tab,
395
- type,
396
- path: tab.path,
397
- order: index,
398
- versions,
399
- graphqlSchemas,
400
- })
401
- })
402
-
403
- return tabs
404
- }
405
-
406
- // Build documentation groups from docs.json
407
- function buildDocGroups(config: DocsConfig): BrainfishDocGroup[] {
408
- const groups: BrainfishDocGroup[] = []
409
-
410
- if (!config.navigation?.tabs) {
411
- return groups
412
- }
413
-
414
- // Helper to process a page item (string or nested group)
415
- const processPageItem = (
416
- pageItem: DocsConfigPageItem,
417
- index: number,
418
- parentGroup: string
419
- ): BrainfishDocPage | null => {
420
- // Handle nested group
421
- if (typeof pageItem === 'object' && 'group' in pageItem) {
422
- const nestedGroup = pageItem as DocsConfigNestedGroup
423
- const children: BrainfishDocPage[] = []
424
-
425
- for (let j = 0; j < nestedGroup.pages.length; j++) {
426
- const childPath = nestedGroup.pages[j]
427
- if (typeof childPath === 'string') {
428
- const childMeta = loadPageMeta(childPath)
429
- if (childMeta) {
430
- children.push({
431
- id: `doc-${childPath.replace(/\//g, '-')}`,
432
- slug: childPath,
433
- title: childMeta.title,
434
- description: childMeta.description,
435
- icon: childMeta.icon,
436
- filePath: childPath,
437
- group: nestedGroup.group,
438
- order: j,
439
- })
440
- }
441
- }
442
- }
443
-
444
- if (children.length > 0) {
445
- // Return a group item with children
446
- return {
447
- id: `group-${nestedGroup.group}`.toLowerCase().replace(/\s+/g, '-'),
448
- slug: '', // Groups don't have a slug themselves
449
- title: nestedGroup.group,
450
- filePath: '',
451
- group: parentGroup,
452
- order: index,
453
- isGroup: true,
454
- children,
455
- }
456
- }
457
- return null
458
- }
459
-
460
- // Handle string page path
461
- const pagePath = pageItem as string
462
- const meta = loadPageMeta(pagePath)
463
-
464
- if (meta) {
465
- return {
466
- id: `doc-${pagePath.replace(/\//g, '-')}`,
467
- slug: pagePath,
468
- title: meta.title,
469
- description: meta.description,
470
- icon: meta.icon,
471
- filePath: pagePath,
472
- group: parentGroup,
473
- order: index,
474
- }
475
- }
476
- return null
477
- }
478
-
479
- // Iterate through all tabs and their groups
480
- for (const tab of config.navigation.tabs) {
481
- // Skip tabs without groups (like API Reference with just href)
482
- if (!tab.groups) {
483
- continue
484
- }
485
-
486
- for (const group of tab.groups) {
487
- const pages: BrainfishDocPage[] = []
488
-
489
- for (let i = 0; i < group.pages.length; i++) {
490
- const pageItem = group.pages[i]
491
- const page = processPageItem(pageItem, i, group.group)
492
- if (page) {
493
- pages.push(page)
494
- }
495
- }
496
-
497
- if (pages.length > 0) {
498
- groups.push({
499
- id: `group-${tab.tab}-${group.group}`.toLowerCase().replace(/\s+/g, '-'),
500
- title: group.group,
501
- pages,
502
- order: groups.length,
503
- icon: group.icon,
504
- })
505
- }
506
- }
507
- }
508
-
509
- return groups
510
- }
511
-
512
- // Scan changelog directory for release files
513
- function scanChangelogReleases(): ChangelogRelease[] {
514
- const releases: ChangelogRelease[] = []
515
- const changelogDir = resolvePath('changelog')
516
-
517
- if (!existsSync(changelogDir)) {
518
- return releases
519
- }
520
-
521
- try {
522
- const files = readdirSync(changelogDir)
523
-
524
- for (const file of files) {
525
- // Only process versioned files (v1.0.0.mdx, etc.), skip latest.mdx and index files
526
- if (!file.match(/^v[\d.]+\.mdx?$/)) {
527
- continue
528
- }
529
-
530
- const filePath = join(changelogDir, file)
531
- const content = readFileSync(filePath, 'utf-8')
532
- const { data } = matter(content)
533
-
534
- const version = data.version || file.replace(/\.mdx?$/, '')
535
-
536
- releases.push({
537
- version,
538
- date: data.date || '',
539
- title: data.title || version,
540
- slug: `changelog/${file.replace(/\.mdx?$/, '')}`,
541
- })
542
- }
543
-
544
- // Sort by version (newest first)
545
- releases.sort((a, b) => {
546
- const versionA = a.version.replace(/^v/, '').split('.').map(Number)
547
- const versionB = b.version.replace(/^v/, '').split('.').map(Number)
548
-
549
- for (let i = 0; i < Math.max(versionA.length, versionB.length); i++) {
550
- const numA = versionA[i] || 0
551
- const numB = versionB[i] || 0
552
- if (numA !== numB) return numB - numA
553
- }
554
- return 0
555
- })
556
-
557
- } catch (error) {
558
- console.error('[Collections] Error scanning changelog:', error)
559
- }
560
-
561
- return releases
562
- }
563
-
564
- // Fetch OpenAPI spec from Brainfish API
565
- async function fetchRemoteSpec(): Promise<OpenApiSpec | null> {
566
- const cachedSpec = await CacheUtils.get<OpenApiSpec>(CACHE_KEY)
567
- if (cachedSpec) {
568
- return cachedSpec
569
- }
570
-
571
- try {
572
- const url = `${BRAINFISH_API_BASE_URL}/catalogs.openapi-spec`
573
-
574
- const response = await fetch(url, {
575
- method: 'POST',
576
- headers: {
577
- 'Authorization': `Bearer ${BRAINFISH_JWT_TOKEN}`,
578
- 'Accept': 'application/json',
579
- 'Content-Type': 'application/json',
580
- 'User-Agent': 'Brainfish-API-Docs/1.0',
581
- },
582
- body: JSON.stringify({ catalogId: BRAINFISH_CATALOG_ID }),
583
- cache: 'no-store',
584
- })
585
-
586
- if (!response.ok) {
587
- let errorBody = ''
588
- try {
589
- errorBody = await response.text()
590
- } catch {
591
- // ignore
592
- }
593
- throw new Error(`Failed to fetch: ${response.status} ${response.statusText}${errorBody ? ` - ${errorBody}` : ''}`)
594
- }
595
-
596
- const spec = await response.json() as OpenApiSpec
597
-
598
- await CacheUtils.set(CACHE_KEY, spec, CACHE_TTL)
599
- await CacheUtils.set(FALLBACK_CACHE_KEY, spec, 60 * 60 * 24 * 365)
600
-
601
- return spec
602
- } catch (error) {
603
- console.error('[Collections] Error fetching remote spec:', error)
604
-
605
- const fallbackSpec = await CacheUtils.get<OpenApiSpec>(FALLBACK_CACHE_KEY)
606
- if (fallbackSpec) {
607
- return fallbackSpec
608
- }
609
-
610
- return null
611
- }
612
- }
613
-
614
- // Get OpenAPI spec (local or remote)
615
- async function getOpenApiSpec(specPath?: string): Promise<OpenApiSpec | null> {
616
- if (USE_LOCAL_SPEC) {
617
- const localSpec = loadLocalSpec(specPath)
618
- if (localSpec) {
619
- return localSpec
620
- }
621
- }
622
-
623
- return fetchRemoteSpec()
624
- }
625
-
626
- /**
627
- * Handle multi-tenant request - fetch content from Blob Storage
628
- */
629
- async function handleMultiTenantRequest(projectSlug: string, request: Request): Promise<Response> {
630
- try {
631
- const projectContent = await getProjectContent(projectSlug)
632
-
633
- if (!projectContent) {
634
- return NextResponse.json(
635
- { error: 'Project not found' },
636
- { status: 404 }
637
- )
638
- }
639
-
640
- // Parse docs.json from project content
641
- const docsConfig = JSON.parse(projectContent.docsJson) as DocsConfig
642
-
643
- // Build navigation tabs and doc groups from config
644
- const navigationTabs = buildNavigationTabs(docsConfig)
645
- const docGroups = buildDocGroupsFromBlob(docsConfig, projectContent)
646
-
647
- // For now, return docs-only response (no OpenAPI spec from blob)
648
- return NextResponse.json(
649
- {
650
- id: projectSlug,
651
- name: docsConfig.name || 'Documentation',
652
- description: 'Documentation',
653
- folders: [],
654
- requests: [],
655
- auth: { authType: 'none', authActive: true },
656
- headers: [],
657
- variables: [],
658
- apiSummary: null,
659
- docGroups,
660
- navigationTabs,
661
- changelogReleases: [],
662
- docsName: docsConfig.name || null,
663
- docsFavicon: docsConfig.favicon || null,
664
- docsLogo: null,
665
- docsHeader: null,
666
- docsNavbar: null,
667
- docsColors: null,
668
- defaultTheme: null,
669
- customCss: null,
670
- apiVersions: [],
671
- selectedApiVersion: null,
672
- notice: docsConfig.notice || null,
673
- isMultiTenant: true,
674
- projectSlug,
675
- },
676
- {
677
- headers: {
678
- 'Content-Type': 'application/json',
679
- 'Cache-Control': 'public, max-age=60',
680
- },
681
- }
682
- )
683
- } catch (error) {
684
- console.error('[Collections] Multi-tenant error:', error)
685
- return NextResponse.json(
686
- { error: 'Failed to load project' },
687
- { status: 500 }
688
- )
689
- }
690
- }
691
-
692
- /**
693
- * Build doc groups from Blob storage content
694
- */
695
- function buildDocGroupsFromBlob(config: DocsConfig, content: ProjectContent): BrainfishDocGroup[] {
696
- const groups: BrainfishDocGroup[] = []
697
-
698
- if (!config.navigation?.tabs) {
699
- return groups
700
- }
701
-
702
- // Helper to find file content
703
- const findFileContent = (pagePath: string): { title: string; description?: string; icon?: string } | null => {
704
- const mdxPath = `${pagePath}.mdx`
705
- const mdPath = `${pagePath}.md`
706
-
707
- const file = content.files.find(f => f.path === mdxPath || f.path === mdPath)
708
- if (!file) return null
709
-
710
- try {
711
- const { data } = matter(file.content)
712
- return {
713
- title: data.title || basename(pagePath),
714
- description: data.description,
715
- icon: data.icon,
716
- }
717
- } catch {
718
- return { title: basename(pagePath) }
719
- }
720
- }
721
-
722
- // Process tabs and groups
723
- for (const tab of config.navigation.tabs) {
724
- if (!tab.groups) continue
725
-
726
- for (const group of tab.groups) {
727
- const pages: BrainfishDocPage[] = []
728
-
729
- for (let i = 0; i < group.pages.length; i++) {
730
- const pageItem = group.pages[i]
731
-
732
- if (typeof pageItem === 'string') {
733
- const meta = findFileContent(pageItem)
734
- if (meta) {
735
- pages.push({
736
- id: `doc-${pageItem.replace(/\//g, '-')}`,
737
- slug: pageItem,
738
- title: meta.title,
739
- description: meta.description,
740
- icon: meta.icon,
741
- filePath: pageItem,
742
- group: group.group,
743
- order: i,
744
- })
745
- }
746
- } else if ('group' in pageItem) {
747
- // Nested group
748
- const children: BrainfishDocPage[] = []
749
- for (let j = 0; j < pageItem.pages.length; j++) {
750
- const childPath = pageItem.pages[j]
751
- if (typeof childPath === 'string') {
752
- const childMeta = findFileContent(childPath)
753
- if (childMeta) {
754
- children.push({
755
- id: `doc-${childPath.replace(/\//g, '-')}`,
756
- slug: childPath,
757
- title: childMeta.title,
758
- description: childMeta.description,
759
- icon: childMeta.icon,
760
- filePath: childPath,
761
- group: pageItem.group,
762
- order: j,
763
- })
764
- }
765
- }
766
- }
767
-
768
- if (children.length > 0) {
769
- pages.push({
770
- id: `group-${pageItem.group}`.toLowerCase().replace(/\s+/g, '-'),
771
- slug: '',
772
- title: pageItem.group,
773
- filePath: '',
774
- group: group.group,
775
- order: i,
776
- isGroup: true,
777
- children,
778
- })
779
- }
780
- }
781
- }
782
-
783
- if (pages.length > 0) {
784
- groups.push({
785
- id: `group-${tab.tab}-${group.group}`.toLowerCase().replace(/\s+/g, '-'),
786
- title: group.group,
787
- pages,
788
- order: groups.length,
789
- icon: group.icon,
790
- })
791
- }
792
- }
793
- }
794
-
795
- return groups
796
- }
797
-
798
- // Helper to generate or get cached summary
799
- async function getOrGenerateSummary(collection: BrainfishCollection, specVersion: string): Promise<string> {
800
- const versionedCacheKey = `${SUMMARY_CACHE_KEY}-v${specVersion}`
801
-
802
- const cachedSummary = await CacheUtils.get<string>(versionedCacheKey)
803
- if (cachedSummary) {
804
- return cachedSummary
805
- }
806
-
807
- const summary = generateAPISummary(collection)
808
- const formattedSummary = formatAPISummaryForPrompt(summary)
809
-
810
- await CacheUtils.set(versionedCacheKey, formattedSummary, SUMMARY_CACHE_TTL)
811
-
812
- return formattedSummary
813
- }
814
-
815
- export async function GET(request: Request) {
816
- try {
817
- // Check for multi-tenant mode (project slug from middleware)
818
- const projectSlug = request.headers.get('x-devdoc-project')
819
-
820
- // If multi-tenant, fetch from Blob Storage
821
- if (projectSlug && !projectSlug.startsWith('custom:')) {
822
- return handleMultiTenantRequest(projectSlug, request)
823
- }
824
-
825
- // Parse query params
826
- const { searchParams } = new URL(request.url)
827
- const requestedVersion = searchParams.get('version')
828
-
829
- // Load docs and theme configuration
830
- const docsConfig = loadDocsConfig()
831
- const themeConfig = loadThemeConfig()
832
- const customCss = loadCustomCss(themeConfig?.customCss)
833
- const docGroups = docsConfig ? buildDocGroups(docsConfig) : []
834
- const navigationTabs = docsConfig ? buildNavigationTabs(docsConfig) : []
835
- const changelogReleases = scanChangelogReleases()
836
-
837
- // Find the OpenAPI tab and its versions
838
- const openapiTab = navigationTabs.find(t => t.type === 'openapi')
839
- const apiVersions = openapiTab?.versions || []
840
-
841
- // Determine which spec to load
842
- let specPath: string | undefined
843
- let selectedVersion: string | undefined
844
-
845
- if (apiVersions.length > 0) {
846
- // Find requested version or default
847
- const versionConfig = requestedVersion
848
- ? apiVersions.find(v => v.version === requestedVersion)
849
- : apiVersions.find(v => v.default) || apiVersions[0]
850
-
851
- if (versionConfig) {
852
- specPath = versionConfig.spec
853
- selectedVersion = versionConfig.version
854
- }
855
- }
856
-
857
- // Get OpenAPI spec (with optional path for versioned specs)
858
- const spec = await getOpenApiSpec(specPath)
859
-
860
- // Handle no spec available
861
- if (!spec) {
862
- return NextResponse.json(
863
- {
864
- id: 'empty',
865
- name: docsConfig?.name || 'Documentation',
866
- description: 'Welcome to the documentation.',
867
- folders: [],
868
- requests: [],
869
- auth: { authType: 'none', authActive: true },
870
- headers: [],
871
- variables: [],
872
- apiSummary: null,
873
- docGroups,
874
- navigationTabs,
875
- changelogReleases,
876
- docsName: docsConfig?.name || null,
877
- docsFavicon: docsConfig?.favicon || null,
878
- docsLogo: themeConfig?.logo || null,
879
- docsHeader: themeConfig?.header || null,
880
- docsNavbar: themeConfig?.navbar || null,
881
- docsColors: themeConfig?.colors || null,
882
- defaultTheme: themeConfig?.defaultTheme || null,
883
- customCss: customCss || null,
884
- apiVersions,
885
- selectedApiVersion: selectedVersion,
886
- notice: docsConfig?.notice || null,
887
- },
888
- {
889
- headers: {
890
- 'Content-Type': 'application/json',
891
- 'Cache-Control': 'no-cache, no-store, must-revalidate',
892
- },
893
- }
894
- )
895
- }
896
-
897
- // Check if spec has paths
898
- if (!spec.paths || Object.keys(spec.paths).length === 0) {
899
- return NextResponse.json(
900
- {
901
- id: 'empty',
902
- name: spec.info?.title || docsConfig?.name || 'Documentation',
903
- description: spec.info?.description || 'No endpoints defined.',
904
- folders: [],
905
- requests: [],
906
- auth: { authType: 'none', authActive: true },
907
- headers: [],
908
- variables: [],
909
- apiSummary: null,
910
- docGroups,
911
- navigationTabs,
912
- changelogReleases,
913
- docsName: docsConfig?.name || null,
914
- docsFavicon: docsConfig?.favicon || null,
915
- docsLogo: themeConfig?.logo || null,
916
- docsHeader: themeConfig?.header || null,
917
- docsNavbar: themeConfig?.navbar || null,
918
- docsColors: themeConfig?.colors || null,
919
- defaultTheme: themeConfig?.defaultTheme || null,
920
- customCss: customCss || null,
921
- apiVersions,
922
- selectedApiVersion: selectedVersion,
923
- notice: docsConfig?.notice || null,
924
- },
925
- {
926
- headers: {
927
- 'Content-Type': 'application/json',
928
- 'Cache-Control': 'no-cache, no-store, must-revalidate',
929
- },
930
- }
931
- )
932
- }
933
-
934
- // Convert to BrainfishCollection using our parser
935
- const collections = await importOpenAPISpec(spec as OpenAPI.Document)
936
- const collection = collections[0]
937
-
938
- if (!collection) {
939
- return NextResponse.json(null, {
940
- headers: {
941
- 'Content-Type': 'application/json',
942
- 'Cache-Control': 'no-cache, no-store, must-revalidate',
943
- },
944
- })
945
- }
946
-
947
- // Generate or get cached API summary
948
- const specVersion = spec.info?.version || 'unknown'
949
- const apiSummary = await getOrGenerateSummary(collection, specVersion)
950
-
951
- // Return collection with summary and doc groups
952
- return NextResponse.json(
953
- {
954
- ...collection,
955
- apiSummary,
956
- specVersion,
957
- docGroups,
958
- navigationTabs,
959
- changelogReleases,
960
- docsName: docsConfig?.name || null,
961
- docsFavicon: docsConfig?.favicon || null,
962
- docsLogo: themeConfig?.logo || null,
963
- docsHeader: themeConfig?.header || null,
964
- docsNavbar: themeConfig?.navbar || null,
965
- docsColors: themeConfig?.colors || null,
966
- defaultTheme: themeConfig?.defaultTheme || null,
967
- customCss: customCss || null,
968
- apiVersions,
969
- selectedApiVersion: selectedVersion,
970
- notice: docsConfig?.notice || null,
971
- },
972
- {
973
- headers: {
974
- 'Content-Type': 'application/json',
975
- 'Cache-Control': 'no-cache, no-store, must-revalidate',
976
- },
977
- }
978
- )
979
- } catch (error) {
980
- console.error('[Collections] Unexpected error:', error)
981
-
982
- return NextResponse.json(
983
- {
984
- id: 'error',
985
- name: 'Documentation',
986
- description: 'Failed to load documentation.',
987
- folders: [],
988
- requests: [],
989
- auth: { authType: 'none', authActive: true },
990
- headers: [],
991
- variables: [],
992
- docGroups: [],
993
- },
994
- {
995
- headers: {
996
- 'Content-Type': 'application/json',
997
- 'Cache-Control': 'no-cache, no-store, must-revalidate',
998
- },
999
- }
1000
- )
1001
- }
1002
- }