@brainfish-ai/devdoc 0.1.42 → 0.1.44

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 (398) hide show
  1. package/dist/cli/commands/create.js +2 -2
  2. package/dist/cli/commands/dev.js +19 -10
  3. package/package.json +3 -2
  4. package/renderer/app/api/assets/[...path]/route.js +108 -0
  5. package/renderer/app/api/assets/route.js +114 -0
  6. package/renderer/app/api/assets/upload/route.js +163 -0
  7. package/renderer/app/api/auth-schemes/route.js +58 -0
  8. package/renderer/app/api/chat/route.js +759 -0
  9. package/renderer/app/api/codegen/route.js +52 -0
  10. package/renderer/app/api/collections/route.js +706 -0
  11. package/renderer/app/api/debug/route.js +47 -0
  12. package/renderer/app/api/deploy/route.js +199 -0
  13. package/renderer/app/api/device/route.js +36 -0
  14. package/renderer/app/api/docs/route.js +205 -0
  15. package/renderer/app/api/domains/add/route.js +121 -0
  16. package/renderer/app/api/domains/lookup/route.js +43 -0
  17. package/renderer/app/api/domains/remove/route.js +89 -0
  18. package/renderer/app/api/domains/status/route.js +140 -0
  19. package/renderer/app/api/domains/verify/route.js +168 -0
  20. package/renderer/app/api/keys/regenerate/route.js +71 -0
  21. package/renderer/app/api/local-assets/[...path]/route.js +108 -0
  22. package/renderer/app/api/openapi-spec/route.js +73 -0
  23. package/renderer/app/api/projects/[slug]/route.js +129 -0
  24. package/renderer/app/api/projects/[slug]/stats/route.js +80 -0
  25. package/renderer/app/api/projects/register/route.js +176 -0
  26. package/renderer/app/api/proxy/route.js +139 -0
  27. package/renderer/app/api/proxy-stream/route.js +156 -0
  28. package/renderer/app/api/redirects/route.js +35 -0
  29. package/renderer/app/api/schema/route.js +85 -0
  30. package/renderer/app/api/subdomains/check/route.js +158 -0
  31. package/renderer/app/api/suggestions/route.js +195 -0
  32. package/renderer/app/globals.css +69 -0
  33. package/renderer/app/layout.js +47 -0
  34. package/renderer/app/llms-full.txt/route.js +266 -0
  35. package/renderer/app/llms.txt/route.js +228 -0
  36. package/renderer/app/page.js +12 -0
  37. package/renderer/app/robots.txt/route.js +66 -0
  38. package/renderer/app/sitemap.xml/route.js +155 -0
  39. package/renderer/components/docs/index.js +8 -0
  40. package/renderer/components/docs/mdx/accordion.js +113 -0
  41. package/renderer/components/docs/mdx/badge.js +72 -0
  42. package/renderer/components/docs/mdx/callouts.js +137 -0
  43. package/renderer/components/docs/mdx/cards.js +175 -0
  44. package/renderer/components/docs/mdx/changelog.js +100 -0
  45. package/renderer/components/docs/mdx/code-block.js +147 -0
  46. package/renderer/components/docs/mdx/code-group.js +287 -0
  47. package/renderer/components/docs/mdx/file-embeds.js +82 -0
  48. package/renderer/components/docs/mdx/frame.js +59 -0
  49. package/renderer/components/docs/mdx/highlight.js +90 -0
  50. package/renderer/components/docs/mdx/iframe.js +69 -0
  51. package/renderer/components/docs/mdx/image.js +135 -0
  52. package/renderer/components/docs/mdx/index.js +134 -0
  53. package/renderer/components/docs/mdx/landing.js +317 -0
  54. package/renderer/components/docs/mdx/mermaid.js +212 -0
  55. package/renderer/components/docs/mdx/param-field.js +112 -0
  56. package/renderer/components/docs/mdx/steps.js +74 -0
  57. package/renderer/components/docs/mdx/tabs.js +50 -0
  58. package/renderer/components/docs/mdx-renderer.js +77 -0
  59. package/renderer/components/docs/navigation/breadcrumbs.js +64 -0
  60. package/renderer/components/docs/navigation/index.js +6 -0
  61. package/renderer/components/docs/navigation/page-nav.js +57 -0
  62. package/renderer/components/docs/navigation/sidebar.js +375 -0
  63. package/renderer/components/docs/navigation/toc.js +89 -0
  64. package/renderer/components/docs/notice.js +77 -0
  65. package/renderer/components/docs-header.js +202 -0
  66. package/renderer/components/docs-viewer/agent/agent-chat.js +1831 -0
  67. package/renderer/components/docs-viewer/agent/agent-popup-button.js +99 -0
  68. package/renderer/components/docs-viewer/agent/cards/debug-context-card.js +107 -0
  69. package/renderer/components/docs-viewer/agent/cards/endpoint-context-card.js +57 -0
  70. package/renderer/components/docs-viewer/agent/cards/index.js +45 -0
  71. package/renderer/components/docs-viewer/agent/cards/response-options-card.js +154 -0
  72. package/renderer/components/docs-viewer/agent/cards/types.js +22 -0
  73. package/renderer/components/docs-viewer/agent/chat-message.js +2 -0
  74. package/renderer/components/docs-viewer/agent/index.js +7 -0
  75. package/renderer/components/docs-viewer/agent/messages/assistant-message.js +108 -0
  76. package/renderer/components/docs-viewer/agent/messages/chat-message.js +34 -0
  77. package/renderer/components/docs-viewer/agent/messages/index.js +6 -0
  78. package/renderer/components/docs-viewer/agent/messages/tool-call-display.js +1065 -0
  79. package/renderer/components/docs-viewer/agent/messages/types.js +2 -0
  80. package/renderer/components/docs-viewer/agent/messages/typing-indicator.js +26 -0
  81. package/renderer/components/docs-viewer/agent/messages/user-message.js +37 -0
  82. package/renderer/components/docs-viewer/code-editor/{index.tsx → index.js} +1 -1
  83. package/renderer/components/docs-viewer/code-editor/notes-mode.js +1338 -0
  84. package/renderer/components/docs-viewer/content/changelog-page.js +297 -0
  85. package/renderer/components/docs-viewer/content/content-router.js +182 -0
  86. package/renderer/components/docs-viewer/content/doc-page.js +290 -0
  87. package/renderer/components/docs-viewer/content/documentation-viewer.js +14 -0
  88. package/renderer/components/docs-viewer/content/index.js +31 -0
  89. package/renderer/components/docs-viewer/content/not-found-page.js +300 -0
  90. package/renderer/components/docs-viewer/content/request-details.js +528 -0
  91. package/renderer/components/docs-viewer/content/sections/auth.js +108 -0
  92. package/renderer/components/docs-viewer/content/sections/body.js +80 -0
  93. package/renderer/components/docs-viewer/content/sections/headers.js +64 -0
  94. package/renderer/components/docs-viewer/content/sections/overview.js +56 -0
  95. package/renderer/components/docs-viewer/content/sections/parameters.js +64 -0
  96. package/renderer/components/docs-viewer/content/sections/responses.js +91 -0
  97. package/renderer/components/docs-viewer/global-auth-modal.js +427 -0
  98. package/renderer/components/docs-viewer/index.js +1448 -0
  99. package/renderer/components/docs-viewer/playground/auth-editor.js +418 -0
  100. package/renderer/components/docs-viewer/playground/body-editor.js +240 -0
  101. package/renderer/components/docs-viewer/playground/code-editor.js +135 -0
  102. package/renderer/components/docs-viewer/playground/code-snippet.js +393 -0
  103. package/renderer/components/docs-viewer/playground/graphql-playground.js +936 -0
  104. package/renderer/components/docs-viewer/playground/index.js +682 -0
  105. package/renderer/components/docs-viewer/playground/key-value-editor.js +317 -0
  106. package/renderer/components/docs-viewer/playground/method-selector.js +65 -0
  107. package/renderer/components/docs-viewer/playground/request-builder.js +181 -0
  108. package/renderer/components/docs-viewer/playground/request-tabs.js +240 -0
  109. package/renderer/components/docs-viewer/playground/response-cards/idle-card.js +42 -0
  110. package/renderer/components/docs-viewer/playground/response-cards/index.js +72 -0
  111. package/renderer/components/docs-viewer/playground/response-cards/loading-card.js +24 -0
  112. package/renderer/components/docs-viewer/playground/response-cards/network-error-card.js +28 -0
  113. package/renderer/components/docs-viewer/playground/response-cards/response-body-card.js +308 -0
  114. package/renderer/components/docs-viewer/playground/response-cards/types.js +9 -0
  115. package/renderer/components/docs-viewer/playground/response-viewer.js +18 -0
  116. package/renderer/components/docs-viewer/search/index.js +2 -0
  117. package/renderer/components/docs-viewer/search/search-dialog.js +367 -0
  118. package/renderer/components/docs-viewer/search/use-search.js +89 -0
  119. package/renderer/components/docs-viewer/shared/markdown-renderer.js +423 -0
  120. package/renderer/components/docs-viewer/shared/method-badge.js +23 -0
  121. package/renderer/components/docs-viewer/shared/schema-viewer.js +321 -0
  122. package/renderer/components/docs-viewer/sidebar/collection-tree.js +222 -0
  123. package/renderer/components/docs-viewer/sidebar/endpoint-options.js +512 -0
  124. package/renderer/components/docs-viewer/sidebar/index.js +196 -0
  125. package/renderer/components/docs-viewer/sidebar/right-sidebar.js +159 -0
  126. package/renderer/components/docs-viewer/sidebar/sidebar-group.js +87 -0
  127. package/renderer/components/docs-viewer/sidebar/sidebar-item.js +172 -0
  128. package/renderer/components/docs-viewer/sidebar/sidebar-section.js +31 -0
  129. package/renderer/components/theme-provider.js +10 -0
  130. package/renderer/components/theme-toggle.js +86 -0
  131. package/renderer/components/ui/badge.js +29 -0
  132. package/renderer/components/ui/button.js +40 -0
  133. package/renderer/components/ui/dialog.js +50 -0
  134. package/renderer/components/ui/dropdown-menu.js +143 -0
  135. package/renderer/components/ui/input.js +12 -0
  136. package/renderer/components/ui/label.js +13 -0
  137. package/renderer/components/ui/navigation-menu.js +83 -0
  138. package/renderer/components/ui/select.js +116 -0
  139. package/renderer/components/ui/spinner.js +92 -0
  140. package/renderer/components/ui/tabs.js +34 -0
  141. package/renderer/components/ui/tooltip.js +43 -0
  142. package/renderer/hooks/use-code-copy.js +76 -0
  143. package/renderer/hooks/use-openapi-title.js +33 -0
  144. package/renderer/hooks/use-route-state.js +159 -0
  145. package/renderer/lib/api-docs/agent/index.js +4 -0
  146. package/renderer/lib/api-docs/agent/indexer.js +254 -0
  147. package/renderer/lib/api-docs/agent/spec-summary.js +227 -0
  148. package/renderer/lib/api-docs/agent/types.js +5 -0
  149. package/renderer/lib/api-docs/agent/use-suggestions.js +97 -0
  150. package/renderer/lib/api-docs/auth/auth-context.js +157 -0
  151. package/renderer/lib/api-docs/auth/auth-storage.js +66 -0
  152. package/renderer/lib/api-docs/auth/crypto.js +64 -0
  153. package/renderer/lib/api-docs/auth/index.js +3 -0
  154. package/renderer/lib/api-docs/code-editor/db.js +145 -0
  155. package/renderer/lib/api-docs/code-editor/hooks.js +254 -0
  156. package/renderer/lib/api-docs/code-editor/{index.ts → index.js} +3 -4
  157. package/renderer/lib/api-docs/code-editor/mode-context.js +126 -0
  158. package/renderer/lib/api-docs/code-editor/types.js +53 -0
  159. package/renderer/lib/api-docs/codegen/definitions.js +258 -0
  160. package/renderer/lib/api-docs/codegen/har.js +171 -0
  161. package/renderer/lib/api-docs/codegen/index.js +118 -0
  162. package/renderer/lib/api-docs/factories.js +136 -0
  163. package/renderer/lib/api-docs/{index.ts → index.js} +5 -10
  164. package/renderer/lib/api-docs/mobile-context.js +116 -0
  165. package/renderer/lib/api-docs/navigation-context.js +62 -0
  166. package/renderer/lib/api-docs/parsers/graphql/index.js +50 -0
  167. package/renderer/lib/api-docs/parsers/graphql/parser.js +350 -0
  168. package/renderer/lib/api-docs/parsers/graphql/transformer.js +215 -0
  169. package/renderer/lib/api-docs/parsers/graphql/types.js +46 -0
  170. package/renderer/lib/api-docs/parsers/openapi/dereferencer.js +43 -0
  171. package/renderer/lib/api-docs/parsers/openapi/extractors/auth.js +486 -0
  172. package/renderer/lib/api-docs/parsers/openapi/extractors/body.js +295 -0
  173. package/renderer/lib/api-docs/parsers/openapi/extractors/index.js +132 -0
  174. package/renderer/lib/api-docs/parsers/openapi/index.js +127 -0
  175. package/renderer/lib/api-docs/parsers/openapi/transformer.js +192 -0
  176. package/renderer/lib/api-docs/parsers/openapi/validator.js +24 -0
  177. package/renderer/lib/api-docs/playground/context.js +65 -0
  178. package/renderer/lib/api-docs/playground/navigation-context.js +74 -0
  179. package/renderer/lib/api-docs/playground/request-builder.js +163 -0
  180. package/renderer/lib/api-docs/playground/request-runner.js +224 -0
  181. package/renderer/lib/api-docs/playground/types.js +5 -0
  182. package/renderer/lib/api-docs/types.js +23 -0
  183. package/renderer/lib/api-docs/utils.js +212 -0
  184. package/renderer/lib/cache.js +157 -0
  185. package/renderer/lib/docs/config/domain-schema.js +161 -0
  186. package/renderer/lib/docs/config/environment.js +38 -0
  187. package/renderer/lib/docs/config/index.js +6 -0
  188. package/renderer/lib/docs/config/loader.js +113 -0
  189. package/renderer/lib/docs/config/schema.js +281 -0
  190. package/renderer/lib/docs/index.js +8 -0
  191. package/renderer/lib/docs/mdx/compiler.js +131 -0
  192. package/renderer/lib/docs/mdx/frontmatter.js +73 -0
  193. package/renderer/lib/docs/mdx/index.js +10 -0
  194. package/renderer/lib/docs/mdx/remark-mermaid.js +63 -0
  195. package/renderer/lib/docs/navigation/generator.js +269 -0
  196. package/renderer/lib/docs/navigation/index.js +3 -0
  197. package/renderer/lib/docs/navigation/types.js +11 -0
  198. package/renderer/lib/docs-navigation-context.js +40 -0
  199. package/renderer/lib/docs-navigation.js +140 -0
  200. package/renderer/lib/multi-tenant/context.js +80 -0
  201. package/renderer/lib/storage/blob.js +767 -0
  202. package/renderer/lib/utils/icons.js +30 -0
  203. package/renderer/lib/utils.js +5 -0
  204. package/renderer/next.config.js +62 -0
  205. package/renderer/package.json +1 -0
  206. package/renderer/tsconfig.json +23 -5
  207. package/renderer/app/api/assets/[...path]/route.ts +0 -123
  208. package/renderer/app/api/assets/route.ts +0 -124
  209. package/renderer/app/api/assets/upload/route.ts +0 -177
  210. package/renderer/app/api/auth-schemes/route.ts +0 -77
  211. package/renderer/app/api/chat/route.ts +0 -858
  212. package/renderer/app/api/codegen/route.ts +0 -72
  213. package/renderer/app/api/collections/route.ts +0 -1002
  214. package/renderer/app/api/debug/route.ts +0 -53
  215. package/renderer/app/api/deploy/route.ts +0 -234
  216. package/renderer/app/api/device/route.ts +0 -42
  217. package/renderer/app/api/docs/route.ts +0 -201
  218. package/renderer/app/api/domains/add/route.ts +0 -132
  219. package/renderer/app/api/domains/lookup/route.ts +0 -43
  220. package/renderer/app/api/domains/remove/route.ts +0 -100
  221. package/renderer/app/api/domains/status/route.ts +0 -158
  222. package/renderer/app/api/domains/verify/route.ts +0 -181
  223. package/renderer/app/api/keys/regenerate/route.ts +0 -80
  224. package/renderer/app/api/local-assets/[...path]/route.ts +0 -122
  225. package/renderer/app/api/openapi-spec/route.ts +0 -151
  226. package/renderer/app/api/projects/[slug]/route.ts +0 -153
  227. package/renderer/app/api/projects/[slug]/stats/route.ts +0 -96
  228. package/renderer/app/api/projects/register/route.ts +0 -152
  229. package/renderer/app/api/proxy/route.ts +0 -149
  230. package/renderer/app/api/proxy-stream/route.ts +0 -168
  231. package/renderer/app/api/redirects/route.ts +0 -47
  232. package/renderer/app/api/schema/route.ts +0 -73
  233. package/renderer/app/api/subdomains/check/route.ts +0 -172
  234. package/renderer/app/api/suggestions/route.ts +0 -144
  235. package/renderer/app/layout.tsx +0 -54
  236. package/renderer/app/llms-full.txt/route.ts +0 -346
  237. package/renderer/app/llms.txt/route.ts +0 -279
  238. package/renderer/app/page.tsx +0 -14
  239. package/renderer/app/robots.txt/route.ts +0 -84
  240. package/renderer/app/sitemap.xml/route.ts +0 -199
  241. package/renderer/components/docs/index.ts +0 -12
  242. package/renderer/components/docs/mdx/accordion.tsx +0 -169
  243. package/renderer/components/docs/mdx/badge.tsx +0 -132
  244. package/renderer/components/docs/mdx/callouts.tsx +0 -154
  245. package/renderer/components/docs/mdx/cards.tsx +0 -241
  246. package/renderer/components/docs/mdx/changelog.tsx +0 -120
  247. package/renderer/components/docs/mdx/code-block.tsx +0 -186
  248. package/renderer/components/docs/mdx/code-group.tsx +0 -421
  249. package/renderer/components/docs/mdx/file-embeds.tsx +0 -105
  250. package/renderer/components/docs/mdx/frame.tsx +0 -112
  251. package/renderer/components/docs/mdx/highlight.tsx +0 -151
  252. package/renderer/components/docs/mdx/iframe.tsx +0 -134
  253. package/renderer/components/docs/mdx/image.tsx +0 -235
  254. package/renderer/components/docs/mdx/index.ts +0 -237
  255. package/renderer/components/docs/mdx/landing.tsx +0 -684
  256. package/renderer/components/docs/mdx/mermaid.tsx +0 -240
  257. package/renderer/components/docs/mdx/param-field.tsx +0 -200
  258. package/renderer/components/docs/mdx/steps.tsx +0 -113
  259. package/renderer/components/docs/mdx/tabs.tsx +0 -86
  260. package/renderer/components/docs/mdx-renderer.tsx +0 -100
  261. package/renderer/components/docs/navigation/breadcrumbs.tsx +0 -76
  262. package/renderer/components/docs/navigation/index.ts +0 -8
  263. package/renderer/components/docs/navigation/page-nav.tsx +0 -64
  264. package/renderer/components/docs/navigation/sidebar.tsx +0 -515
  265. package/renderer/components/docs/navigation/toc.tsx +0 -113
  266. package/renderer/components/docs/notice.tsx +0 -105
  267. package/renderer/components/docs-header.tsx +0 -278
  268. package/renderer/components/docs-viewer/agent/agent-chat.tsx +0 -2076
  269. package/renderer/components/docs-viewer/agent/cards/debug-context-card.tsx +0 -90
  270. package/renderer/components/docs-viewer/agent/cards/endpoint-context-card.tsx +0 -49
  271. package/renderer/components/docs-viewer/agent/cards/index.tsx +0 -50
  272. package/renderer/components/docs-viewer/agent/cards/response-options-card.tsx +0 -212
  273. package/renderer/components/docs-viewer/agent/cards/types.ts +0 -84
  274. package/renderer/components/docs-viewer/agent/chat-message.tsx +0 -17
  275. package/renderer/components/docs-viewer/agent/index.tsx +0 -6
  276. package/renderer/components/docs-viewer/agent/messages/assistant-message.tsx +0 -119
  277. package/renderer/components/docs-viewer/agent/messages/chat-message.tsx +0 -46
  278. package/renderer/components/docs-viewer/agent/messages/index.ts +0 -17
  279. package/renderer/components/docs-viewer/agent/messages/tool-call-display.tsx +0 -721
  280. package/renderer/components/docs-viewer/agent/messages/types.ts +0 -61
  281. package/renderer/components/docs-viewer/agent/messages/typing-indicator.tsx +0 -24
  282. package/renderer/components/docs-viewer/agent/messages/user-message.tsx +0 -51
  283. package/renderer/components/docs-viewer/code-editor/notes-mode.tsx +0 -1283
  284. package/renderer/components/docs-viewer/content/changelog-page.tsx +0 -331
  285. package/renderer/components/docs-viewer/content/doc-page.tsx +0 -367
  286. package/renderer/components/docs-viewer/content/documentation-viewer.tsx +0 -17
  287. package/renderer/components/docs-viewer/content/index.tsx +0 -29
  288. package/renderer/components/docs-viewer/content/not-found-page.tsx +0 -330
  289. package/renderer/components/docs-viewer/content/request-details.tsx +0 -330
  290. package/renderer/components/docs-viewer/content/sections/auth.tsx +0 -69
  291. package/renderer/components/docs-viewer/content/sections/body.tsx +0 -66
  292. package/renderer/components/docs-viewer/content/sections/headers.tsx +0 -43
  293. package/renderer/components/docs-viewer/content/sections/overview.tsx +0 -40
  294. package/renderer/components/docs-viewer/content/sections/parameters.tsx +0 -43
  295. package/renderer/components/docs-viewer/content/sections/responses.tsx +0 -87
  296. package/renderer/components/docs-viewer/global-auth-modal.tsx +0 -352
  297. package/renderer/components/docs-viewer/index.tsx +0 -1670
  298. package/renderer/components/docs-viewer/playground/auth-editor.tsx +0 -280
  299. package/renderer/components/docs-viewer/playground/body-editor.tsx +0 -221
  300. package/renderer/components/docs-viewer/playground/code-editor.tsx +0 -224
  301. package/renderer/components/docs-viewer/playground/code-snippet.tsx +0 -387
  302. package/renderer/components/docs-viewer/playground/graphql-playground.tsx +0 -745
  303. package/renderer/components/docs-viewer/playground/index.tsx +0 -671
  304. package/renderer/components/docs-viewer/playground/key-value-editor.tsx +0 -261
  305. package/renderer/components/docs-viewer/playground/method-selector.tsx +0 -60
  306. package/renderer/components/docs-viewer/playground/request-builder.tsx +0 -179
  307. package/renderer/components/docs-viewer/playground/request-tabs.tsx +0 -237
  308. package/renderer/components/docs-viewer/playground/response-cards/idle-card.tsx +0 -21
  309. package/renderer/components/docs-viewer/playground/response-cards/index.tsx +0 -93
  310. package/renderer/components/docs-viewer/playground/response-cards/loading-card.tsx +0 -16
  311. package/renderer/components/docs-viewer/playground/response-cards/network-error-card.tsx +0 -23
  312. package/renderer/components/docs-viewer/playground/response-cards/response-body-card.tsx +0 -268
  313. package/renderer/components/docs-viewer/playground/response-cards/types.ts +0 -82
  314. package/renderer/components/docs-viewer/playground/response-viewer.tsx +0 -43
  315. package/renderer/components/docs-viewer/search/index.ts +0 -2
  316. package/renderer/components/docs-viewer/search/search-dialog.tsx +0 -331
  317. package/renderer/components/docs-viewer/search/use-search.ts +0 -117
  318. package/renderer/components/docs-viewer/shared/markdown-renderer.tsx +0 -431
  319. package/renderer/components/docs-viewer/shared/method-badge.tsx +0 -41
  320. package/renderer/components/docs-viewer/shared/schema-viewer.tsx +0 -349
  321. package/renderer/components/docs-viewer/sidebar/collection-tree.tsx +0 -259
  322. package/renderer/components/docs-viewer/sidebar/endpoint-options.tsx +0 -316
  323. package/renderer/components/docs-viewer/sidebar/index.tsx +0 -282
  324. package/renderer/components/docs-viewer/sidebar/right-sidebar.tsx +0 -202
  325. package/renderer/components/docs-viewer/sidebar/sidebar-group.tsx +0 -118
  326. package/renderer/components/docs-viewer/sidebar/sidebar-item.tsx +0 -212
  327. package/renderer/components/docs-viewer/sidebar/sidebar-section.tsx +0 -38
  328. package/renderer/components/theme-provider.tsx +0 -11
  329. package/renderer/components/theme-toggle.tsx +0 -76
  330. package/renderer/components/ui/badge.tsx +0 -46
  331. package/renderer/components/ui/button.tsx +0 -59
  332. package/renderer/components/ui/dialog.tsx +0 -118
  333. package/renderer/components/ui/dropdown-menu.tsx +0 -257
  334. package/renderer/components/ui/input.tsx +0 -21
  335. package/renderer/components/ui/label.tsx +0 -24
  336. package/renderer/components/ui/navigation-menu.tsx +0 -168
  337. package/renderer/components/ui/select.tsx +0 -190
  338. package/renderer/components/ui/spinner.tsx +0 -114
  339. package/renderer/components/ui/tabs.tsx +0 -66
  340. package/renderer/components/ui/tooltip.tsx +0 -61
  341. package/renderer/hooks/use-code-copy.ts +0 -88
  342. package/renderer/hooks/use-openapi-title.ts +0 -44
  343. package/renderer/lib/api-docs/agent/index.ts +0 -6
  344. package/renderer/lib/api-docs/agent/indexer.ts +0 -323
  345. package/renderer/lib/api-docs/agent/spec-summary.ts +0 -335
  346. package/renderer/lib/api-docs/agent/types.ts +0 -116
  347. package/renderer/lib/api-docs/auth/auth-context.tsx +0 -225
  348. package/renderer/lib/api-docs/auth/auth-storage.ts +0 -87
  349. package/renderer/lib/api-docs/auth/crypto.ts +0 -89
  350. package/renderer/lib/api-docs/auth/index.ts +0 -4
  351. package/renderer/lib/api-docs/code-editor/db.ts +0 -164
  352. package/renderer/lib/api-docs/code-editor/hooks.ts +0 -266
  353. package/renderer/lib/api-docs/code-editor/mode-context.tsx +0 -207
  354. package/renderer/lib/api-docs/code-editor/types.ts +0 -105
  355. package/renderer/lib/api-docs/codegen/definitions.ts +0 -297
  356. package/renderer/lib/api-docs/codegen/har.ts +0 -251
  357. package/renderer/lib/api-docs/codegen/index.ts +0 -159
  358. package/renderer/lib/api-docs/factories.ts +0 -170
  359. package/renderer/lib/api-docs/mobile-context.tsx +0 -112
  360. package/renderer/lib/api-docs/navigation-context.tsx +0 -88
  361. package/renderer/lib/api-docs/parsers/graphql/README.md +0 -129
  362. package/renderer/lib/api-docs/parsers/graphql/index.ts +0 -91
  363. package/renderer/lib/api-docs/parsers/graphql/parser.ts +0 -491
  364. package/renderer/lib/api-docs/parsers/graphql/transformer.ts +0 -246
  365. package/renderer/lib/api-docs/parsers/graphql/types.ts +0 -283
  366. package/renderer/lib/api-docs/parsers/openapi/README.md +0 -32
  367. package/renderer/lib/api-docs/parsers/openapi/dereferencer.ts +0 -60
  368. package/renderer/lib/api-docs/parsers/openapi/extractors/auth.ts +0 -574
  369. package/renderer/lib/api-docs/parsers/openapi/extractors/body.ts +0 -403
  370. package/renderer/lib/api-docs/parsers/openapi/extractors/index.ts +0 -232
  371. package/renderer/lib/api-docs/parsers/openapi/index.ts +0 -171
  372. package/renderer/lib/api-docs/parsers/openapi/transformer.ts +0 -278
  373. package/renderer/lib/api-docs/parsers/openapi/validator.ts +0 -31
  374. package/renderer/lib/api-docs/playground/context.tsx +0 -107
  375. package/renderer/lib/api-docs/playground/navigation-context.tsx +0 -124
  376. package/renderer/lib/api-docs/playground/request-builder.ts +0 -223
  377. package/renderer/lib/api-docs/playground/request-runner.ts +0 -282
  378. package/renderer/lib/api-docs/playground/types.ts +0 -35
  379. package/renderer/lib/api-docs/types.ts +0 -269
  380. package/renderer/lib/api-docs/utils.ts +0 -311
  381. package/renderer/lib/cache.ts +0 -193
  382. package/renderer/lib/docs/config/domain-schema.ts +0 -260
  383. package/renderer/lib/docs/config/index.ts +0 -43
  384. package/renderer/lib/docs/config/loader.ts +0 -142
  385. package/renderer/lib/docs/config/schema.ts +0 -308
  386. package/renderer/lib/docs/index.ts +0 -12
  387. package/renderer/lib/docs/mdx/compiler.ts +0 -176
  388. package/renderer/lib/docs/mdx/frontmatter.ts +0 -91
  389. package/renderer/lib/docs/mdx/index.ts +0 -26
  390. package/renderer/lib/docs/navigation/generator.ts +0 -348
  391. package/renderer/lib/docs/navigation/index.ts +0 -12
  392. package/renderer/lib/docs/navigation/types.ts +0 -123
  393. package/renderer/lib/docs-navigation-context.tsx +0 -80
  394. package/renderer/lib/multi-tenant/context.ts +0 -105
  395. package/renderer/lib/storage/blob.ts +0 -1083
  396. package/renderer/lib/utils/icons.ts +0 -48
  397. package/renderer/lib/utils.ts +0 -6
  398. package/renderer/next.config.ts +0 -76
@@ -0,0 +1,1448 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useEffect, useState, useCallback, useRef, useMemo } from 'react';
4
+ import { Spinner } from '@phosphor-icons/react';
5
+ import { DocsSidebar } from './sidebar';
6
+ import { NotFoundPage } from './content/not-found-page';
7
+ import { ApiPlayground } from './playground';
8
+ import { RightSidebar } from './sidebar/right-sidebar';
9
+ import { RequestDetails } from './content/request-details';
10
+ import { DocPage } from './content/doc-page';
11
+ import { ChangelogPage } from './content/changelog-page';
12
+ import { GraphQLPlayground } from './playground/graphql-playground';
13
+ import { makeBrainfishCollection } from '@/lib/api-docs/factories';
14
+ import { buildSchema, isNonNullType, isListType } from 'graphql';
15
+ import { GlobalAuthModal } from './global-auth-modal';
16
+ import { AuthProvider } from '@/lib/api-docs/auth';
17
+ import { PlaygroundProvider, usePlaygroundPrefill } from '@/lib/api-docs/playground/context';
18
+ import { PlaygroundNavigationProvider, usePlaygroundNavigation } from '@/lib/api-docs/playground/navigation-context';
19
+ import { NavigationProvider } from '@/lib/api-docs/navigation-context';
20
+ import { ModeProvider, useModeContext } from '@/lib/api-docs/code-editor';
21
+ import { NotesMode } from './code-editor';
22
+ import { DocsHeader } from '@/components/docs-header';
23
+ import { Notice } from '../docs/notice';
24
+ import { DocsNavigationProvider } from '@/lib/docs-navigation-context';
25
+ import { Button } from '@/components/ui/button';
26
+ import { Code, TestTube, Book } from '@phosphor-icons/react';
27
+ import { cn } from '@/lib/utils';
28
+ import { SearchDialog, useSearch } from './search';
29
+ import { useTheme } from 'next-themes';
30
+ import { useRouteState } from '@/hooks/use-route-state';
31
+ import { navigateToPage, navigateToEndpoint, navigateToSection, navigateToTab } from '@/lib/docs-navigation';
32
+ import { useMobile } from '@/lib/api-docs/mobile-context';
33
+ import { AgentPopupButton } from './agent/agent-popup-button';
34
+ import { buildEndpointIndex } from '@/lib/api-docs/agent/indexer';
35
+ // Helper to convert GraphQL type to string representation
36
+ function graphqlTypeToString(type) {
37
+ if (isNonNullType(type)) {
38
+ return `${graphqlTypeToString(type.ofType)}!`;
39
+ }
40
+ if (isListType(type)) {
41
+ return `[${graphqlTypeToString(type.ofType)}]`;
42
+ }
43
+ // Named type
44
+ return type.name || 'Unknown';
45
+ }
46
+ // Parse GraphQL schema using buildSchema (for SDL)
47
+ function parseGraphQLSchema(schemaSDL) {
48
+ const operations = [];
49
+ try {
50
+ const schema = buildSchema(schemaSDL);
51
+ // Get root operation types
52
+ const rootTypes = [
53
+ {
54
+ type: schema.getQueryType(),
55
+ operationType: 'query'
56
+ },
57
+ {
58
+ type: schema.getMutationType(),
59
+ operationType: 'mutation'
60
+ },
61
+ {
62
+ type: schema.getSubscriptionType(),
63
+ operationType: 'subscription'
64
+ }
65
+ ];
66
+ for (const { type: rootType, operationType } of rootTypes){
67
+ if (!rootType) continue;
68
+ const fields = rootType.getFields();
69
+ for (const [fieldName, field] of Object.entries(fields)){
70
+ // Skip internal fields
71
+ if (fieldName.startsWith('_')) continue;
72
+ const returnType = graphqlTypeToString(field.type);
73
+ const query = generateGraphQLQueryFromField(operationType, fieldName, field.args, returnType, schema);
74
+ const exampleVariables = generateGraphQLVariablesFromArgs(field.args, schema);
75
+ operations.push({
76
+ id: `${operationType}-${fieldName}`,
77
+ name: fieldName,
78
+ description: field.description || null,
79
+ operationType,
80
+ query,
81
+ exampleVariables
82
+ });
83
+ }
84
+ }
85
+ } catch (err) {
86
+ console.error('[GraphQL Parser] Failed to parse schema:', err);
87
+ }
88
+ return operations;
89
+ }
90
+ // Get default fields for a type from schema
91
+ function getDefaultFieldsForType(typeName, schema) {
92
+ const type = schema.getType(typeName);
93
+ if (!type || !('getFields' in type)) return [];
94
+ const fields = type.getFields();
95
+ const fieldNames = Object.keys(fields);
96
+ // Priority order for default fields
97
+ const priorityFields = [
98
+ 'code',
99
+ 'id',
100
+ 'name',
101
+ 'title',
102
+ 'slug'
103
+ ];
104
+ const selectedFields = [];
105
+ // First, add priority fields if they exist
106
+ for (const pf of priorityFields){
107
+ if (fieldNames.includes(pf)) {
108
+ selectedFields.push(pf);
109
+ if (selectedFields.length >= 3) break;
110
+ }
111
+ }
112
+ // If we don't have enough, add other scalar fields
113
+ if (selectedFields.length < 3) {
114
+ for (const [fname, fdef] of Object.entries(fields)){
115
+ if (selectedFields.includes(fname)) continue;
116
+ const ftype = graphqlTypeToString(fdef.type).replace(/[\[\]!]/g, '').trim();
117
+ if ([
118
+ 'String',
119
+ 'Int',
120
+ 'Float',
121
+ 'Boolean',
122
+ 'ID'
123
+ ].includes(ftype)) {
124
+ selectedFields.push(fname);
125
+ if (selectedFields.length >= 3) break;
126
+ }
127
+ }
128
+ }
129
+ return selectedFields.length > 0 ? selectedFields : [
130
+ '__typename'
131
+ ];
132
+ }
133
+ // Generate example GraphQL query from schema field
134
+ function generateGraphQLQueryFromField(operationType, name, args, returnType, schema) {
135
+ let query = `${operationType} ${name.charAt(0).toUpperCase() + name.slice(1)}`;
136
+ if (args.length > 0) {
137
+ const varDefs = args.map((arg)=>`$${arg.name}: ${graphqlTypeToString(arg.type)}`).join(', ');
138
+ query += `(${varDefs})`;
139
+ }
140
+ query += ` {\n ${name}`;
141
+ if (args.length > 0) {
142
+ const argPairs = args.map((arg)=>`${arg.name}: $${arg.name}`).join(', ');
143
+ query += `(${argPairs})`;
144
+ }
145
+ const baseType = returnType.replace(/[\[\]!]/g, '').trim();
146
+ if ([
147
+ 'String',
148
+ 'Int',
149
+ 'Float',
150
+ 'Boolean',
151
+ 'ID'
152
+ ].includes(baseType)) {
153
+ query += '\n}';
154
+ } else {
155
+ // Get actual fields from the schema for this type
156
+ const defaultFields = getDefaultFieldsForType(baseType, schema);
157
+ const fieldsStr = defaultFields.map((f)=>` ${f}`).join('\n');
158
+ query += ` {\n${fieldsStr}\n }\n}`;
159
+ }
160
+ return query;
161
+ }
162
+ // Generate example value for a GraphQL type
163
+ function generateExampleValue(type, schema, depth = 0) {
164
+ // Prevent infinite recursion
165
+ if (depth > 3) return null;
166
+ // Unwrap NonNull
167
+ if (isNonNullType(type)) {
168
+ return generateExampleValue(type.ofType, schema, depth);
169
+ }
170
+ // Handle List types - return array with one example element
171
+ if (isListType(type)) {
172
+ const itemValue = generateExampleValue(type.ofType, schema, depth);
173
+ return itemValue !== null ? [
174
+ itemValue
175
+ ] : [];
176
+ }
177
+ // Get the named type
178
+ const typeName = type.name;
179
+ if (!typeName) return null;
180
+ // Built-in scalar types
181
+ switch(typeName){
182
+ case 'String':
183
+ return 'example';
184
+ case 'Int':
185
+ return 10;
186
+ case 'Float':
187
+ return 1.5;
188
+ case 'Boolean':
189
+ return true;
190
+ case 'ID':
191
+ return 'example-id';
192
+ // Common custom scalars
193
+ case 'DateTime':
194
+ return new Date().toISOString();
195
+ case 'Date':
196
+ return new Date().toISOString().split('T')[0];
197
+ case 'Time':
198
+ return '12:00:00';
199
+ case 'JSON':
200
+ return {};
201
+ case 'JSONObject':
202
+ return {};
203
+ case 'URL':
204
+ return 'https://example.com';
205
+ case 'URI':
206
+ return 'https://example.com';
207
+ case 'Email':
208
+ return 'user@example.com';
209
+ case 'EmailAddress':
210
+ return 'user@example.com';
211
+ case 'UUID':
212
+ return '550e8400-e29b-41d4-a716-446655440000';
213
+ case 'BigInt':
214
+ return '9007199254740991';
215
+ case 'Long':
216
+ return 9007199254740991;
217
+ }
218
+ // Check if it's an enum type
219
+ const schemaType = schema.getType(typeName);
220
+ if (schemaType && 'getValues' in schemaType) {
221
+ const enumType = schemaType;
222
+ const values = enumType.getValues();
223
+ if (values.length > 0) {
224
+ return values[0].name // Return first enum value
225
+ ;
226
+ }
227
+ }
228
+ // Check if it's an input object type
229
+ if (schemaType && 'getFields' in schemaType) {
230
+ const inputType = schemaType;
231
+ const fields = inputType.getFields();
232
+ const result = {};
233
+ // Only include required fields to keep examples concise
234
+ for (const [fieldName, field] of Object.entries(fields)){
235
+ if (isNonNullType(field.type)) {
236
+ // Use default value if available, otherwise generate
237
+ if (field.defaultValue !== undefined) {
238
+ result[fieldName] = field.defaultValue;
239
+ } else {
240
+ result[fieldName] = generateExampleValue(field.type, schema, depth + 1);
241
+ }
242
+ }
243
+ }
244
+ // If no required fields, include first optional field
245
+ if (Object.keys(result).length === 0) {
246
+ const firstField = Object.entries(fields)[0];
247
+ if (firstField) {
248
+ const [fname, fdef] = firstField;
249
+ // Use default value if available
250
+ if (fdef.defaultValue !== undefined) {
251
+ result[fname] = fdef.defaultValue;
252
+ } else {
253
+ result[fname] = generateExampleValue(fdef.type, schema, depth + 1);
254
+ }
255
+ }
256
+ }
257
+ return result;
258
+ }
259
+ // Unknown type - return null
260
+ return null;
261
+ }
262
+ // Generate example variables from GraphQL arguments
263
+ function generateGraphQLVariablesFromArgs(args, schema) {
264
+ const variables = {};
265
+ for (const arg of args){
266
+ // First, check if the argument has a default value in the schema
267
+ if (arg.defaultValue !== undefined) {
268
+ variables[arg.name] = arg.defaultValue;
269
+ } else {
270
+ // Generate example value for arguments without defaults
271
+ const value = generateExampleValue(arg.type, schema, 0);
272
+ if (value !== null) {
273
+ variables[arg.name] = value;
274
+ }
275
+ }
276
+ }
277
+ return variables;
278
+ }
279
+ // Convert GraphQL operations to BrainfishCollection for sidebar
280
+ function convertGraphQLToCollection(operations, endpoint) {
281
+ const queries = operations.filter((op)=>op.operationType === 'query');
282
+ const mutations = operations.filter((op)=>op.operationType === 'mutation');
283
+ const subscriptions = operations.filter((op)=>op.operationType === 'subscription');
284
+ const toRequest = (op)=>({
285
+ id: op.id,
286
+ name: op.name,
287
+ description: op.description || '',
288
+ method: 'POST',
289
+ endpoint,
290
+ params: [],
291
+ headers: [],
292
+ auth: {
293
+ authType: 'none',
294
+ authActive: false
295
+ },
296
+ body: {
297
+ contentType: 'application/json',
298
+ body: JSON.stringify({
299
+ query: op.query,
300
+ variables: op.exampleVariables
301
+ }, null, 2)
302
+ },
303
+ requestVariables: [],
304
+ responses: {},
305
+ tags: [
306
+ op.operationType
307
+ ]
308
+ });
309
+ const folders = [];
310
+ if (queries.length > 0) {
311
+ folders.push(makeBrainfishCollection({
312
+ name: 'Queries',
313
+ description: 'GraphQL Query operations',
314
+ requests: queries.map(toRequest),
315
+ folders: [],
316
+ variables: [],
317
+ auth: {
318
+ authType: 'none',
319
+ authActive: false
320
+ },
321
+ headers: []
322
+ }));
323
+ }
324
+ if (mutations.length > 0) {
325
+ folders.push(makeBrainfishCollection({
326
+ name: 'Mutations',
327
+ description: 'GraphQL Mutation operations',
328
+ requests: mutations.map(toRequest),
329
+ folders: [],
330
+ variables: [],
331
+ auth: {
332
+ authType: 'none',
333
+ authActive: false
334
+ },
335
+ headers: []
336
+ }));
337
+ }
338
+ if (subscriptions.length > 0) {
339
+ folders.push(makeBrainfishCollection({
340
+ name: 'Subscriptions',
341
+ description: 'GraphQL Subscription operations',
342
+ requests: subscriptions.map(toRequest),
343
+ folders: [],
344
+ variables: [],
345
+ auth: {
346
+ authType: 'none',
347
+ authActive: false
348
+ },
349
+ headers: []
350
+ }));
351
+ }
352
+ return makeBrainfishCollection({
353
+ name: 'GraphQL API',
354
+ description: 'GraphQL operations',
355
+ folders,
356
+ requests: [],
357
+ variables: [],
358
+ auth: {
359
+ authType: 'none',
360
+ authActive: false
361
+ },
362
+ headers: []
363
+ });
364
+ }
365
+ // Helper to find request by ID in collection
366
+ function findRequestById(collection, id) {
367
+ // Check direct requests
368
+ const found = collection.requests.find((r)=>r.id === id);
369
+ if (found) return found;
370
+ // Check folders recursively
371
+ for (const folder of collection.folders){
372
+ const request = findRequestById(folder, id);
373
+ if (request) return request;
374
+ }
375
+ return null;
376
+ }
377
+ // Helper to get the first endpoint from collection
378
+ function getFirstEndpoint(collection) {
379
+ // Check direct requests first
380
+ if (collection.requests.length > 0) {
381
+ return collection.requests[0];
382
+ }
383
+ // Check folders recursively
384
+ for (const folder of collection.folders){
385
+ const firstInFolder = getFirstEndpoint(folder);
386
+ if (firstInFolder) return firstInFolder;
387
+ }
388
+ return null;
389
+ }
390
+ // Helper to check if a doc group belongs to a specific tab
391
+ // Group IDs are formatted as: group-{tab-id}-{group-name}
392
+ function isGroupForTab(groupId, tabId) {
393
+ // Check if the group ID starts with "group-{tabId}-"
394
+ const prefix = `group-${tabId}-`;
395
+ return groupId.startsWith(prefix);
396
+ }
397
+ // Helper to check if a tab has doc groups (MDX pages)
398
+ function hasDocGroupsForTab(docGroups, tabId) {
399
+ if (!docGroups || docGroups.length === 0) return false;
400
+ // Check if any doc group belongs to this tab and has pages
401
+ return docGroups.some((g)=>isGroupForTab(g.id, tabId) && g.pages.length > 0);
402
+ }
403
+ // Helper to get the first page from doc groups for a tab
404
+ function getFirstDocPageForTab(docGroups, tabId) {
405
+ if (!docGroups || docGroups.length === 0) return null;
406
+ const tabDocGroup = docGroups.find((g)=>isGroupForTab(g.id, tabId) && g.pages.length > 0);
407
+ return tabDocGroup?.pages[0]?.slug || null;
408
+ }
409
+ function DocsContent() {
410
+ const [collection, setCollection] = useState(null);
411
+ const [selectedApiVersion, setSelectedApiVersion] = useState(null);
412
+ const [loading, setLoading] = useState(true);
413
+ const [isVersionLoading, setIsVersionLoading] = useState(false) // For version switch only
414
+ ;
415
+ const [error, setError] = useState(null);
416
+ const [showAuthModal, setShowAuthModal] = useState(false);
417
+ // URL-based route state - single source of truth for selection
418
+ const routeState = useRouteState();
419
+ // Derive active tab from URL (with default fallback)
420
+ const activeTab = routeState.tab || 'api-reference';
421
+ // Derive selected doc page from URL
422
+ const selectedDocPage = routeState.contentType === 'page' ? routeState.contentId : null;
423
+ // Derive selected doc section from URL
424
+ const selectedDocSection = routeState.contentType === 'section' ? routeState.contentId : null;
425
+ // Derive selected request from URL by looking up in collection
426
+ const selectedRequest = useMemo(()=>{
427
+ if (routeState.contentType !== 'endpoint' || !routeState.contentId || !collection) {
428
+ return null;
429
+ }
430
+ return findRequestById(collection, routeState.contentId);
431
+ }, [
432
+ routeState.contentType,
433
+ routeState.contentId,
434
+ collection
435
+ ]);
436
+ // Derive not found slug from URL when endpoint doesn't exist
437
+ const notFoundSlug = useMemo(()=>{
438
+ if (routeState.contentType === 'endpoint' && routeState.contentId && collection) {
439
+ const request = findRequestById(collection, routeState.contentId);
440
+ if (!request) {
441
+ return `endpoint/${routeState.contentId}`;
442
+ }
443
+ }
444
+ return null;
445
+ }, [
446
+ routeState.contentType,
447
+ routeState.contentId,
448
+ collection
449
+ ]);
450
+ // Prefill context for agent
451
+ const { setPrefill } = usePlaygroundPrefill();
452
+ // Playground navigation context for tab navigation
453
+ const { navigateAndHighlight, resetNavigation } = usePlaygroundNavigation();
454
+ // Mode context for switching modes
455
+ const { switchToDocs } = useModeContext();
456
+ // Ref for the scrollable content area
457
+ const contentRef = useRef(null);
458
+ // Track if initial navigation has been done (prevents re-navigation on effect re-runs)
459
+ const hasInitialNavigated = useRef(false);
460
+ // Handle selecting a request - just navigates to URL
461
+ const handleSelectRequest = useCallback((request)=>{
462
+ navigateToEndpoint(activeTab, request.id);
463
+ // Reset tab navigation so the new endpoint can determine its default tab
464
+ resetNavigation();
465
+ // Switch to Docs mode to show endpoint documentation first
466
+ switchToDocs();
467
+ }, [
468
+ activeTab,
469
+ resetNavigation,
470
+ switchToDocs
471
+ ]);
472
+ // Handle selecting a documentation section (scroll to heading)
473
+ const handleSelectDocumentation = useCallback((headingId)=>{
474
+ const isIntro = headingId === 'introduction';
475
+ if (isIntro) {
476
+ // Scroll to top
477
+ navigateToTab(activeTab);
478
+ setTimeout(()=>{
479
+ contentRef.current?.scrollTo({
480
+ top: 0,
481
+ behavior: 'smooth'
482
+ });
483
+ }, 50);
484
+ } else {
485
+ // Navigate to section and scroll
486
+ navigateToSection(activeTab, headingId);
487
+ setTimeout(()=>{
488
+ const element = document.getElementById(headingId);
489
+ if (element) {
490
+ element.scrollIntoView({
491
+ behavior: 'smooth',
492
+ block: 'start'
493
+ });
494
+ }
495
+ }, 50);
496
+ }
497
+ // Switch to Docs mode when selecting documentation
498
+ switchToDocs();
499
+ }, [
500
+ activeTab,
501
+ switchToDocs
502
+ ]);
503
+ // Handle selecting a doc page
504
+ const handleSelectDocPage = useCallback((slug)=>{
505
+ // Find which tab this doc page belongs to
506
+ let targetTab = activeTab;
507
+ let releaseSlug = null;
508
+ let sectionId = null;
509
+ // Parse section from slug (e.g., "essentials/markdown#headings" -> slug: "essentials/markdown", section: "headings")
510
+ let pageSlug = slug;
511
+ if (slug.includes('#')) {
512
+ const [pagePart, sectionPart] = slug.split('#');
513
+ pageSlug = pagePart;
514
+ sectionId = sectionPart;
515
+ }
516
+ // Special handling for changelog pages
517
+ if (pageSlug.startsWith('changelog/') || pageSlug === 'changelog') {
518
+ // Find the changelog tab
519
+ const changelogTab = collection?.navigationTabs?.find((t)=>t.type === 'changelog');
520
+ if (changelogTab) {
521
+ targetTab = changelogTab.id;
522
+ }
523
+ // Extract the release slug for scrolling (e.g., "changelog/v1.2.0" -> "v1.2.0")
524
+ if (pageSlug.startsWith('changelog/')) {
525
+ releaseSlug = pageSlug.replace('changelog/', '');
526
+ }
527
+ } else if (collection?.docGroups) {
528
+ for (const group of collection.docGroups){
529
+ const hasPage = (pages)=>{
530
+ for (const page of pages){
531
+ if (page.slug === pageSlug) return true;
532
+ if (page.children && hasPage(page.children)) return true;
533
+ }
534
+ return false;
535
+ };
536
+ if (hasPage(group.pages)) {
537
+ // Extract tab from group ID (e.g., "group-guides-getting-started" -> "guides")
538
+ const tabPart = group.id.replace('group-', '').split('-')[0];
539
+ // Find the actual tab ID that matches
540
+ const matchingTab = collection.navigationTabs?.find((t)=>t.id === tabPart || t.id.startsWith(tabPart));
541
+ if (matchingTab) {
542
+ targetTab = matchingTab.id;
543
+ }
544
+ break;
545
+ }
546
+ }
547
+ }
548
+ // Navigate to the page via URL
549
+ navigateToPage(targetTab, pageSlug);
550
+ switchToDocs();
551
+ // Scroll to specific release if navigating to a changelog entry
552
+ if (releaseSlug) {
553
+ // Wait for the changelog page to render, then scroll to the release
554
+ setTimeout(()=>{
555
+ const releaseElement = document.getElementById(`release-${releaseSlug}`);
556
+ if (releaseElement) {
557
+ releaseElement.scrollIntoView({
558
+ behavior: 'smooth',
559
+ block: 'start'
560
+ });
561
+ }
562
+ }, 600);
563
+ } else if (sectionId) {
564
+ // Scroll to section within the page after it renders
565
+ setTimeout(()=>{
566
+ const sectionElement = document.getElementById(sectionId);
567
+ if (sectionElement) {
568
+ sectionElement.scrollIntoView({
569
+ behavior: 'smooth',
570
+ block: 'start'
571
+ });
572
+ }
573
+ }, 300);
574
+ } else {
575
+ // Scroll to top of content when navigating to a new page
576
+ setTimeout(()=>{
577
+ contentRef.current?.scrollTo({
578
+ top: 0,
579
+ behavior: 'smooth'
580
+ });
581
+ }, 50);
582
+ }
583
+ }, [
584
+ switchToDocs,
585
+ collection,
586
+ activeTab
587
+ ]);
588
+ // Handle API version change
589
+ const handleApiVersionChange = useCallback((version)=>{
590
+ if (version !== selectedApiVersion) {
591
+ setSelectedApiVersion(version);
592
+ // Navigate to tab only (clears selection) when switching versions
593
+ navigateToTab(activeTab);
594
+ }
595
+ }, [
596
+ selectedApiVersion,
597
+ activeTab
598
+ ]);
599
+ // Handle tab change from header
600
+ const handleTabChange = useCallback((tabId)=>{
601
+ // Reset mode to docs when switching tabs (exit sandbox/api-client mode)
602
+ switchToDocs();
603
+ // Find the tab config to check its type
604
+ const tabConfig = collection?.navigationTabs?.find((t)=>t.id === tabId);
605
+ const isApiTab = tabConfig?.type === 'openapi' || tabConfig?.type === 'graphql' || tabId === 'api-reference';
606
+ if (tabId === 'changelog') {
607
+ // Switch to Changelog tab
608
+ navigateToTab(tabId);
609
+ } else if (isApiTab) {
610
+ // API Reference or GraphQL tab
611
+ // Check if there are doc groups for this tab (MDX pages)
612
+ const hasGroups = hasDocGroupsForTab(collection?.docGroups, tabId);
613
+ if (hasGroups) {
614
+ // Has doc groups - select the first page from groups
615
+ const firstPage = getFirstDocPageForTab(collection?.docGroups, tabId);
616
+ if (firstPage) {
617
+ navigateToPage(tabId, firstPage);
618
+ switchToDocs();
619
+ } else {
620
+ // No pages in groups - auto-select first endpoint
621
+ const firstEndpoint = collection ? getFirstEndpoint(collection) : null;
622
+ if (firstEndpoint) {
623
+ navigateToEndpoint(tabId, firstEndpoint.id);
624
+ } else {
625
+ navigateToTab(tabId);
626
+ }
627
+ }
628
+ } else {
629
+ // No doc groups - auto-select first endpoint
630
+ const firstEndpoint = collection ? getFirstEndpoint(collection) : null;
631
+ if (firstEndpoint) {
632
+ navigateToEndpoint(tabId, firstEndpoint.id);
633
+ } else {
634
+ navigateToTab(tabId);
635
+ }
636
+ }
637
+ } else {
638
+ // Switch to a doc group tab - find and select the first page in that tab
639
+ // Find the first doc group for this tab and select its first page
640
+ if (collection?.docGroups) {
641
+ const tabDocGroup = collection.docGroups.find((g)=>isGroupForTab(g.id, tabId));
642
+ if (tabDocGroup && tabDocGroup.pages.length > 0) {
643
+ const firstPage = tabDocGroup.pages[0];
644
+ navigateToPage(tabId, firstPage.slug);
645
+ switchToDocs();
646
+ } else {
647
+ navigateToTab(tabId);
648
+ }
649
+ }
650
+ }
651
+ }, [
652
+ collection,
653
+ switchToDocs
654
+ ]);
655
+ // Handler for agent navigation
656
+ const handleAgentNavigate = useCallback((endpointId)=>{
657
+ if (!collection) return;
658
+ const request = findRequestById(collection, endpointId);
659
+ if (request) {
660
+ // Navigate to the endpoint in api-reference tab
661
+ navigateToEndpoint('api-reference', endpointId);
662
+ // Reset tab navigation so the new endpoint can determine its default tab
663
+ resetNavigation();
664
+ }
665
+ }, [
666
+ collection,
667
+ resetNavigation
668
+ ]);
669
+ // Handler for agent prefilling parameters
670
+ const handleAgentPrefill = useCallback((data)=>{
671
+ console.log('[Agent] Prefill requested:', data);
672
+ setPrefill(data);
673
+ }, [
674
+ setPrefill
675
+ ]);
676
+ // State for debug context - used to trigger agent debugging
677
+ const [debugContext, setDebugContext] = useState(null);
678
+ // Handler for debug requests from playground
679
+ const handleDebugRequest = useCallback((context)=>{
680
+ setDebugContext(context);
681
+ }, []);
682
+ // Clear debug context after it's been used
683
+ const clearDebugContext = useCallback(()=>{
684
+ setDebugContext(null);
685
+ }, []);
686
+ // State for explain context - used to trigger agent explanation
687
+ const [explainContext, setExplainContext] = useState(null);
688
+ // Handler for explain requests from playground
689
+ const handleExplainRequest = useCallback((context)=>{
690
+ setExplainContext(context);
691
+ }, []);
692
+ // Clear explain context after it's been used
693
+ const clearExplainContext = useCallback(()=>{
694
+ setExplainContext(null);
695
+ }, []);
696
+ // Note: Browser back/forward is now handled by useRouteState hook automatically
697
+ // Dynamically set favicon from docs.json config
698
+ useEffect(()=>{
699
+ if (!collection?.docsFavicon) return;
700
+ const faviconPath = collection.docsFavicon;
701
+ // Update or create link elements for favicon
702
+ const updateFaviconLink = (rel, href)=>{
703
+ let link = document.querySelector(`link[rel="${rel}"]`);
704
+ if (!link) {
705
+ link = document.createElement('link');
706
+ link.rel = rel;
707
+ document.head.appendChild(link);
708
+ }
709
+ link.href = href;
710
+ };
711
+ // Determine the type based on file extension
712
+ const ext = faviconPath.split('.').pop()?.toLowerCase();
713
+ const type = ext === 'svg' ? 'image/svg+xml' : ext === 'png' ? 'image/png' : ext === 'ico' ? 'image/x-icon' : 'image/png';
714
+ // Update the favicon link with type
715
+ let iconLink = document.querySelector('link[rel="icon"]');
716
+ if (!iconLink) {
717
+ iconLink = document.createElement('link');
718
+ iconLink.rel = 'icon';
719
+ document.head.appendChild(iconLink);
720
+ }
721
+ iconLink.type = type;
722
+ iconLink.href = faviconPath;
723
+ // Also update shortcut icon and apple-touch-icon
724
+ updateFaviconLink('shortcut icon', faviconPath);
725
+ updateFaviconLink('apple-touch-icon', faviconPath);
726
+ }, [
727
+ collection?.docsFavicon
728
+ ]);
729
+ useEffect(()=>{
730
+ async function fetchCollection() {
731
+ try {
732
+ // Only show full loading on initial load
733
+ const isInitialLoad = !collection;
734
+ if (isInitialLoad) {
735
+ setLoading(true);
736
+ } else {
737
+ setIsVersionLoading(true);
738
+ }
739
+ setError(null);
740
+ // Build URL with version param if selected
741
+ const url = selectedApiVersion ? `/api/collections?version=${encodeURIComponent(selectedApiVersion)}` : '/api/collections';
742
+ const response = await fetch(url);
743
+ if (!response.ok) {
744
+ throw new Error(`Failed to fetch collection: ${response.status}`);
745
+ }
746
+ const data = await response.json();
747
+ setCollection(data);
748
+ // Set initial API version if not already set
749
+ if (!selectedApiVersion && data?.selectedApiVersion) {
750
+ setSelectedApiVersion(data.selectedApiVersion);
751
+ }
752
+ // Only run initial navigation logic on first load
753
+ if (isInitialLoad && !hasInitialNavigated.current) {
754
+ hasInitialNavigated.current = true;
755
+ // Helper: Navigate to first content for a given tab
756
+ const navigateToFirstContent = (tabId)=>{
757
+ const tabConfig = data.navigationTabs?.find((t)=>t.id === tabId);
758
+ const isApiTab = tabConfig?.type === 'openapi' || tabConfig?.type === 'graphql' || tabId === 'api-reference';
759
+ // Try doc pages first, then endpoints
760
+ const firstPage = isApiTab ? getFirstDocPageForTab(data.docGroups, tabId) : data.docGroups?.find((g)=>isGroupForTab(g.id, tabId))?.pages[0]?.slug;
761
+ if (firstPage) {
762
+ navigateToPage(tabId, firstPage);
763
+ return;
764
+ }
765
+ // Fall back to first endpoint for API tabs
766
+ if (isApiTab) {
767
+ const firstEndpoint = getFirstEndpoint(data);
768
+ if (firstEndpoint) {
769
+ navigateToEndpoint(tabId, firstEndpoint.id);
770
+ return;
771
+ }
772
+ }
773
+ // No content found, just navigate to tab
774
+ navigateToTab(tabId);
775
+ };
776
+ // Get default tab (first tab in config)
777
+ let defaultTabId = 'api-reference';
778
+ if (data?.navigationTabs?.length > 0) {
779
+ const sortedTabs = [
780
+ ...data.navigationTabs
781
+ ].sort((a, b)=>a.order - b.order);
782
+ defaultTabId = sortedTabs[0].id;
783
+ }
784
+ // Handle initial navigation after collection loads
785
+ setTimeout(()=>{
786
+ const hash = window.location.hash.slice(1);
787
+ const isTabOnly = hash && !hash.includes('/');
788
+ if (!hash) {
789
+ // No hash - navigate to first content of default tab
790
+ navigateToFirstContent(defaultTabId);
791
+ } else if (isTabOnly) {
792
+ // Just a tab name (e.g., #guides) - navigate to first content
793
+ navigateToFirstContent(hash);
794
+ }
795
+ // View mode (docs/playground/notes) is derived from URL by ModeProvider
796
+ }, 0);
797
+ }
798
+ // Version changes are handled by handleApiVersionChange callback
799
+ } catch (err) {
800
+ console.error('Error fetching collection:', err);
801
+ setError(err instanceof Error ? err.message : 'Failed to load API documentation');
802
+ } finally{
803
+ setLoading(false);
804
+ setIsVersionLoading(false);
805
+ }
806
+ }
807
+ fetchCollection();
808
+ // eslint-disable-next-line react-hooks/exhaustive-deps
809
+ }, [
810
+ selectedApiVersion
811
+ ]);
812
+ // Only show full-page loading on initial load
813
+ if (loading && !collection) {
814
+ return /*#__PURE__*/ _jsx("div", {
815
+ className: "flex items-center justify-center h-screen",
816
+ children: /*#__PURE__*/ _jsxs("div", {
817
+ className: "text-center",
818
+ children: [
819
+ /*#__PURE__*/ _jsx(Spinner, {
820
+ size: 32,
821
+ className: "text-muted-foreground animate-spin mx-auto mb-3"
822
+ }),
823
+ /*#__PURE__*/ _jsx("p", {
824
+ className: "text-sm text-muted-foreground",
825
+ children: "Loading API documentation..."
826
+ })
827
+ ]
828
+ })
829
+ });
830
+ }
831
+ if (error) {
832
+ return /*#__PURE__*/ _jsx("div", {
833
+ className: "flex items-center justify-center h-screen",
834
+ children: /*#__PURE__*/ _jsxs("div", {
835
+ className: "text-center",
836
+ children: [
837
+ /*#__PURE__*/ _jsx("p", {
838
+ className: "text-destructive text-lg mb-2",
839
+ children: "Error loading documentation"
840
+ }),
841
+ /*#__PURE__*/ _jsx("p", {
842
+ className: "text-muted-foreground",
843
+ children: error
844
+ })
845
+ ]
846
+ })
847
+ });
848
+ }
849
+ if (!collection) {
850
+ return /*#__PURE__*/ _jsx("div", {
851
+ className: "flex items-center justify-center h-screen",
852
+ children: /*#__PURE__*/ _jsxs("div", {
853
+ className: "text-center max-w-md",
854
+ children: [
855
+ /*#__PURE__*/ _jsx("p", {
856
+ className: "text-muted-foreground mb-2",
857
+ children: "No API documentation available"
858
+ }),
859
+ /*#__PURE__*/ _jsx("p", {
860
+ className: "text-sm text-muted-foreground",
861
+ children: "Please configure your Brainfish API credentials in your environment variables."
862
+ })
863
+ ]
864
+ })
865
+ });
866
+ }
867
+ // Only show "configure credentials" if there are no endpoints AND no doc groups
868
+ // Multi-tenant docs may have only doc groups without API endpoints
869
+ const hasDocGroups = collection.docGroups && collection.docGroups.length > 0;
870
+ const hasEndpoints = collection.requests.length > 0 || collection.folders.length > 0;
871
+ if (!hasEndpoints && !hasDocGroups) {
872
+ return /*#__PURE__*/ _jsx("div", {
873
+ className: "flex items-center justify-center h-screen",
874
+ children: /*#__PURE__*/ _jsxs("div", {
875
+ className: "text-center max-w-lg p-8",
876
+ children: [
877
+ /*#__PURE__*/ _jsx("h2", {
878
+ className: "text-2xl font-semibold mb-2",
879
+ children: collection.name || 'Documentation'
880
+ }),
881
+ /*#__PURE__*/ _jsx("p", {
882
+ className: "text-muted-foreground mb-6",
883
+ children: collection.description || 'No documentation content available yet.'
884
+ }),
885
+ /*#__PURE__*/ _jsxs("div", {
886
+ className: "bg-muted/50 rounded-lg p-5 text-left text-sm space-y-4",
887
+ children: [
888
+ /*#__PURE__*/ _jsx("p", {
889
+ className: "font-medium",
890
+ children: "Get started with DevDoc:"
891
+ }),
892
+ /*#__PURE__*/ _jsxs("div", {
893
+ className: "space-y-3",
894
+ children: [
895
+ /*#__PURE__*/ _jsxs("div", {
896
+ children: [
897
+ /*#__PURE__*/ _jsx("p", {
898
+ className: "text-muted-foreground text-xs mb-1",
899
+ children: "Create a new project"
900
+ }),
901
+ /*#__PURE__*/ _jsx("code", {
902
+ className: "block bg-background px-3 py-2 rounded-md font-mono text-xs",
903
+ children: "npx create-devdoc-doc my-docs"
904
+ })
905
+ ]
906
+ }),
907
+ /*#__PURE__*/ _jsxs("div", {
908
+ children: [
909
+ /*#__PURE__*/ _jsx("p", {
910
+ className: "text-muted-foreground text-xs mb-1",
911
+ children: "Start local development"
912
+ }),
913
+ /*#__PURE__*/ _jsx("code", {
914
+ className: "block bg-background px-3 py-2 rounded-md font-mono text-xs",
915
+ children: "npx devdoc dev"
916
+ })
917
+ ]
918
+ }),
919
+ /*#__PURE__*/ _jsxs("div", {
920
+ children: [
921
+ /*#__PURE__*/ _jsx("p", {
922
+ className: "text-muted-foreground text-xs mb-1",
923
+ children: "Deploy to production"
924
+ }),
925
+ /*#__PURE__*/ _jsx("code", {
926
+ className: "block bg-background px-3 py-2 rounded-md font-mono text-xs",
927
+ children: "npx devdoc deploy"
928
+ })
929
+ ]
930
+ })
931
+ ]
932
+ }),
933
+ /*#__PURE__*/ _jsxs("a", {
934
+ href: "https://devdoc.sh",
935
+ target: "_blank",
936
+ rel: "noopener noreferrer",
937
+ className: "inline-flex items-center gap-1.5 text-primary hover:underline text-sm font-medium",
938
+ children: [
939
+ "Learn more at devdoc.sh",
940
+ /*#__PURE__*/ _jsx("svg", {
941
+ className: "h-3.5 w-3.5",
942
+ fill: "none",
943
+ viewBox: "0 0 24 24",
944
+ stroke: "currentColor",
945
+ strokeWidth: 2,
946
+ children: /*#__PURE__*/ _jsx("path", {
947
+ strokeLinecap: "round",
948
+ strokeLinejoin: "round",
949
+ d: "M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"
950
+ })
951
+ })
952
+ ]
953
+ })
954
+ ]
955
+ })
956
+ ]
957
+ })
958
+ });
959
+ }
960
+ return /*#__PURE__*/ _jsx(NavigationProvider, {
961
+ collection: collection,
962
+ onSelectRequest: handleSelectRequest,
963
+ children: /*#__PURE__*/ _jsx(DocsWithMode, {
964
+ collection: collection,
965
+ selectedRequest: selectedRequest,
966
+ selectedDocSection: selectedDocSection,
967
+ selectedDocPage: selectedDocPage,
968
+ activeTab: activeTab,
969
+ onTabChange: handleTabChange,
970
+ contentRef: contentRef,
971
+ showAuthModal: showAuthModal,
972
+ setShowAuthModal: setShowAuthModal,
973
+ handleSelectRequest: handleSelectRequest,
974
+ handleSelectDocumentation: handleSelectDocumentation,
975
+ handleSelectDocPage: handleSelectDocPage,
976
+ handleDebugRequest: handleDebugRequest,
977
+ handleExplainRequest: handleExplainRequest,
978
+ handleAgentNavigate: handleAgentNavigate,
979
+ handleAgentPrefill: handleAgentPrefill,
980
+ debugContext: debugContext,
981
+ clearDebugContext: clearDebugContext,
982
+ explainContext: explainContext,
983
+ clearExplainContext: clearExplainContext,
984
+ navigateAndHighlight: navigateAndHighlight,
985
+ selectedApiVersion: selectedApiVersion,
986
+ handleApiVersionChange: handleApiVersionChange,
987
+ isVersionLoading: isVersionLoading,
988
+ notFoundSlug: notFoundSlug
989
+ })
990
+ });
991
+ }
992
+ // Mode toggle tabs - switches between Docs, API Client, and Notes
993
+ function ModeToggleTabs({ hasEndpoint }) {
994
+ const { mode, switchToDocs, switchToApiClient, switchToNotes } = useModeContext();
995
+ return /*#__PURE__*/ _jsxs("div", {
996
+ className: "flex items-center gap-1 p-1 rounded-lg bg-muted/50 shrink-0",
997
+ children: [
998
+ /*#__PURE__*/ _jsxs(Button, {
999
+ variant: mode === 'docs' ? 'secondary' : 'ghost',
1000
+ size: "sm",
1001
+ onClick: ()=>switchToDocs(),
1002
+ className: cn("text-xs h-7 px-2 sm:px-3 gap-1.5", mode === 'docs' ? 'bg-background shadow-sm' : 'text-muted-foreground hover:text-foreground'),
1003
+ children: [
1004
+ /*#__PURE__*/ _jsx(Book, {
1005
+ className: "h-3.5 w-3.5",
1006
+ weight: "bold"
1007
+ }),
1008
+ /*#__PURE__*/ _jsx("span", {
1009
+ className: "hidden xs:inline",
1010
+ children: "Docs"
1011
+ })
1012
+ ]
1013
+ }),
1014
+ hasEndpoint && /*#__PURE__*/ _jsxs(Button, {
1015
+ variant: mode === 'api_client' ? 'secondary' : 'ghost',
1016
+ size: "sm",
1017
+ onClick: ()=>switchToApiClient(),
1018
+ className: cn("text-xs h-7 px-2 sm:px-3 gap-1.5", mode === 'api_client' ? 'bg-background shadow-sm' : 'text-muted-foreground hover:text-foreground'),
1019
+ children: [
1020
+ /*#__PURE__*/ _jsx(TestTube, {
1021
+ className: "h-3.5 w-3.5",
1022
+ weight: "bold"
1023
+ }),
1024
+ /*#__PURE__*/ _jsx("span", {
1025
+ className: "hidden xs:inline",
1026
+ children: "API Client"
1027
+ })
1028
+ ]
1029
+ }),
1030
+ /*#__PURE__*/ _jsxs(Button, {
1031
+ variant: mode === 'notes' ? 'secondary' : 'ghost',
1032
+ size: "sm",
1033
+ onClick: ()=>switchToNotes(),
1034
+ className: cn("text-xs h-7 px-2 sm:px-3 gap-1.5", mode === 'notes' ? 'bg-background shadow-sm' : 'text-muted-foreground hover:text-foreground'),
1035
+ children: [
1036
+ /*#__PURE__*/ _jsx(Code, {
1037
+ className: "h-3.5 w-3.5",
1038
+ weight: "bold"
1039
+ }),
1040
+ /*#__PURE__*/ _jsx("span", {
1041
+ className: "hidden xs:inline",
1042
+ children: "Sandbox"
1043
+ })
1044
+ ]
1045
+ })
1046
+ ]
1047
+ });
1048
+ }
1049
+ function DocsWithMode({ collection, selectedRequest, selectedDocSection, selectedDocPage, activeTab, onTabChange, contentRef, showAuthModal, setShowAuthModal, handleSelectRequest, handleSelectDocumentation, handleSelectDocPage, handleDebugRequest, handleExplainRequest, handleAgentNavigate, handleAgentPrefill, debugContext, clearDebugContext, explainContext, clearExplainContext, navigateAndHighlight, selectedApiVersion, handleApiVersionChange, isVersionLoading, notFoundSlug }) {
1050
+ const { mode, switchToDocs } = useModeContext();
1051
+ const { setTheme } = useTheme();
1052
+ // Agent panel state - controls popup button and push animation
1053
+ const { isRightSidebarOpen, openRightSidebar } = useMobile();
1054
+ // Build endpoint index for suggestions (memoized)
1055
+ const endpointIndex = useMemo(()=>buildEndpointIndex(collection), [
1056
+ collection
1057
+ ]);
1058
+ // GraphQL state
1059
+ const [graphqlOperations, setGraphqlOperations] = useState([]);
1060
+ const [graphqlCollection, setGraphqlCollection] = useState(null);
1061
+ const [graphqlSchemaSDL, setGraphqlSchemaSDL] = useState(undefined);
1062
+ // Use route state for URL-based selection
1063
+ const routeState = useRouteState();
1064
+ // Derive selected GraphQL operation from URL
1065
+ const selectedGraphQLOperation = useMemo(()=>{
1066
+ if (routeState.contentType !== 'endpoint' || !routeState.contentId) {
1067
+ return null;
1068
+ }
1069
+ return graphqlOperations.find((op)=>op.id === routeState.contentId) || null;
1070
+ }, [
1071
+ routeState.contentType,
1072
+ routeState.contentId,
1073
+ graphqlOperations
1074
+ ]);
1075
+ // Get API spec URL from environment or collection
1076
+ const apiSpecUrl = process.env.NEXT_PUBLIC_OPENAPI_URL || collection.name || 'default';
1077
+ // Check if there are endpoints
1078
+ const hasEndpoints = collection.folders.length > 0 || collection.requests.length > 0;
1079
+ // Search functionality
1080
+ const { isOpen: searchOpen, setIsOpen: setSearchOpen, openSearch, searchItems } = useSearch({
1081
+ requests: collection.requests,
1082
+ folders: collection.folders,
1083
+ docGroups: collection.docGroups
1084
+ });
1085
+ // Handle search item selection - use URL hash navigation
1086
+ const handleSearchSelect = useCallback((item)=>{
1087
+ if (item.type === 'endpoint') {
1088
+ // Navigate to endpoint via hash - format: #api-reference/endpoint/{id}
1089
+ window.location.hash = `api-reference/endpoint/${item.id}`;
1090
+ } else if (item.type === 'doc') {
1091
+ // Navigate to doc page via hash - the href already has the correct format
1092
+ // Extract tab and path from href (e.g., #guides/page/quickstart)
1093
+ const hashPath = item.href.replace('#', '');
1094
+ window.location.hash = hashPath;
1095
+ }
1096
+ }, []);
1097
+ // Wrap agent navigate to switch to Docs mode and navigate to endpoint
1098
+ const handleAgentNavigateWithModeSwitch = useCallback((endpointId)=>{
1099
+ // handleAgentNavigate navigates via URL
1100
+ handleAgentNavigate(endpointId);
1101
+ }, [
1102
+ handleAgentNavigate
1103
+ ]);
1104
+ // Get the current content title for header
1105
+ // Find the active tab's config
1106
+ const activeTabConfig = collection.navigationTabs?.find((t)=>t.id === activeTab);
1107
+ const activeTabType = activeTabConfig?.type || 'docs';
1108
+ // Filter doc groups for sidebar based on active tab
1109
+ // Group IDs are like "group-guides-getting-started", tab IDs are like "guides"
1110
+ // Filter doc groups for sidebar based on active tab
1111
+ // Group IDs are formatted as: group-{tab-id}-{group-name}
1112
+ const filteredDocGroups = collection.docGroups?.filter((g)=>isGroupForTab(g.id, activeTab)) || [];
1113
+ // Show endpoints in sidebar only when OpenAPI tab is active
1114
+ const showEndpoints = activeTabType === 'openapi';
1115
+ // Show changelog when changelog tab is active
1116
+ const showChangelog = activeTabType === 'changelog';
1117
+ // Show GraphQL playground when graphql tab is active
1118
+ const showGraphQL = activeTabType === 'graphql';
1119
+ const activeGraphQLSchemas = activeTabConfig?.graphqlSchemas || [];
1120
+ // Get the first schema path for stable dependency
1121
+ const schemaPath = activeGraphQLSchemas[0]?.schema;
1122
+ const schemaEndpoint = activeGraphQLSchemas[0]?.endpoint;
1123
+ // Load GraphQL operations when graphql tab is active
1124
+ useEffect(()=>{
1125
+ if (!showGraphQL || !schemaPath) {
1126
+ setGraphqlOperations([]);
1127
+ setGraphqlCollection(null);
1128
+ setGraphqlSchemaSDL(undefined);
1129
+ return;
1130
+ }
1131
+ // Load and parse GraphQL schema
1132
+ const loadGraphQLSchema = async ()=>{
1133
+ try {
1134
+ console.log('[DocsViewer] Loading GraphQL schema from:', schemaPath);
1135
+ const response = await fetch(`/api/schema?path=${encodeURIComponent(schemaPath)}`);
1136
+ if (!response.ok) {
1137
+ console.error('[DocsViewer] Failed to fetch schema:', response.status);
1138
+ return;
1139
+ }
1140
+ const schemaContent = await response.text();
1141
+ console.log('[DocsViewer] Schema loaded, length:', schemaContent.length);
1142
+ setGraphqlSchemaSDL(schemaContent); // Store schema SDL for autocomplete
1143
+ const operations = parseGraphQLSchema(schemaContent);
1144
+ console.log('[DocsViewer] Parsed operations:', operations.length);
1145
+ setGraphqlOperations(operations);
1146
+ // Convert to BrainfishCollection for sidebar
1147
+ const gqlCollection = convertGraphQLToCollection(operations, schemaEndpoint || '');
1148
+ setGraphqlCollection(gqlCollection);
1149
+ } catch (err) {
1150
+ console.error('[DocsViewer] Failed to load GraphQL schema:', err);
1151
+ }
1152
+ };
1153
+ loadGraphQLSchema();
1154
+ }, [
1155
+ showGraphQL,
1156
+ schemaPath,
1157
+ schemaEndpoint
1158
+ ]);
1159
+ // Auto-navigate to first GraphQL operation when none selected and no doc pages
1160
+ useEffect(()=>{
1161
+ if (!showGraphQL || graphqlOperations.length === 0) {
1162
+ return;
1163
+ }
1164
+ // If there's already content selected (page or endpoint), don't auto-navigate
1165
+ if (routeState.contentType) {
1166
+ return;
1167
+ }
1168
+ // Check if there are doc groups for this tab
1169
+ const hasGroups = hasDocGroupsForTab(collection?.docGroups, activeTab);
1170
+ if (!hasGroups) {
1171
+ // No doc groups - auto-navigate to first GraphQL operation
1172
+ const firstOperation = graphqlOperations[0];
1173
+ navigateToEndpoint(activeTab, firstOperation.id);
1174
+ }
1175
+ }, [
1176
+ showGraphQL,
1177
+ graphqlOperations,
1178
+ activeTab,
1179
+ collection?.docGroups,
1180
+ routeState.contentType
1181
+ ]);
1182
+ // Handle GraphQL operation selection from sidebar - just navigates via URL
1183
+ const handleSelectGraphQLOperation = useCallback((request)=>{
1184
+ navigateToEndpoint(activeTab, request.id);
1185
+ switchToDocs();
1186
+ }, [
1187
+ activeTab,
1188
+ switchToDocs
1189
+ ]);
1190
+ // Inject custom CSS and color variables
1191
+ useEffect(()=>{
1192
+ // Create or update style element for custom CSS
1193
+ let styleEl = document.getElementById('docs-custom-css');
1194
+ if (!styleEl) {
1195
+ styleEl = document.createElement('style');
1196
+ styleEl.id = 'docs-custom-css';
1197
+ document.head.appendChild(styleEl);
1198
+ }
1199
+ // Build CSS with color variables
1200
+ let cssContent = '';
1201
+ // Add color variables if provided
1202
+ // We set both --docs-primary (for custom CSS) and --primary (for Tailwind's bg-primary class)
1203
+ if (collection.docsColors) {
1204
+ const colors = collection.docsColors;
1205
+ cssContent += `:root {\n`;
1206
+ if (colors.primary) {
1207
+ cssContent += ` --docs-primary: ${colors.primary};\n`;
1208
+ cssContent += ` --primary: ${colors.primary};\n`;
1209
+ }
1210
+ if (colors.primaryLight) cssContent += ` --docs-primary-light: ${colors.primaryLight};\n`;
1211
+ if (colors.primaryDark) cssContent += ` --docs-primary-dark: ${colors.primaryDark};\n`;
1212
+ cssContent += `}\n`;
1213
+ // Also set for dark mode
1214
+ cssContent += `.dark {\n`;
1215
+ if (colors.primary) cssContent += ` --primary: ${colors.primary};\n`;
1216
+ cssContent += `}\n\n`;
1217
+ }
1218
+ // Add custom CSS if provided
1219
+ if (collection.customCss) {
1220
+ cssContent += collection.customCss;
1221
+ }
1222
+ styleEl.textContent = cssContent;
1223
+ return ()=>{
1224
+ // Cleanup on unmount
1225
+ const el = document.getElementById('docs-custom-css');
1226
+ if (el) el.remove();
1227
+ };
1228
+ }, [
1229
+ collection.customCss,
1230
+ collection.docsColors
1231
+ ]);
1232
+ // Apply default theme from theme.json on initial load
1233
+ // Use a ref to track if we've already applied the default theme
1234
+ const hasAppliedDefaultTheme = useRef(false);
1235
+ useEffect(()=>{
1236
+ if (collection?.defaultTheme && !hasAppliedDefaultTheme.current) {
1237
+ setTheme(collection.defaultTheme);
1238
+ hasAppliedDefaultTheme.current = true;
1239
+ }
1240
+ }, [
1241
+ collection?.defaultTheme,
1242
+ setTheme
1243
+ ]);
1244
+ return /*#__PURE__*/ _jsxs("div", {
1245
+ className: "docs-viewer-root flex flex-col h-screen overflow-hidden",
1246
+ children: [
1247
+ collection.notice && /*#__PURE__*/ _jsx(Notice, {
1248
+ config: collection.notice,
1249
+ storageKey: "docs-notice"
1250
+ }),
1251
+ /*#__PURE__*/ _jsx(SearchDialog, {
1252
+ open: searchOpen,
1253
+ onOpenChange: setSearchOpen,
1254
+ items: searchItems,
1255
+ onSelect: handleSearchSelect
1256
+ }),
1257
+ /*#__PURE__*/ _jsx(DocsHeader, {
1258
+ docGroups: collection.docGroups,
1259
+ navigationTabs: collection.navigationTabs,
1260
+ activeTab: activeTab,
1261
+ onTabChange: onTabChange,
1262
+ hasEndpoints: hasEndpoints,
1263
+ docsName: collection.docsName,
1264
+ docsLogo: collection.docsLogo,
1265
+ onSearchClick: openSearch,
1266
+ docsHeader: collection.docsHeader,
1267
+ docsNavbar: collection.docsNavbar
1268
+ }),
1269
+ /*#__PURE__*/ _jsxs("div", {
1270
+ className: cn("docs-layout flex flex-1 overflow-hidden relative z-0 min-h-0", "transition-[margin] duration-300 ease-in-out", // Push content left when agent panel is open (only on larger screens)
1271
+ isRightSidebarOpen && "lg:mr-96"),
1272
+ children: [
1273
+ !showChangelog && /*#__PURE__*/ _jsx(DocsSidebar, {
1274
+ collection: {
1275
+ ...collection,
1276
+ // Show GraphQL operations when GraphQL tab is active, else show REST endpoints
1277
+ folders: showGraphQL && graphqlCollection ? graphqlCollection.folders : showEndpoints ? collection.folders : [],
1278
+ requests: showGraphQL && graphqlCollection ? graphqlCollection.requests : showEndpoints ? collection.requests : [],
1279
+ // Only show filtered doc groups
1280
+ docGroups: filteredDocGroups
1281
+ },
1282
+ selectedRequest: showGraphQL ? selectedGraphQLOperation ? {
1283
+ id: selectedGraphQLOperation.id
1284
+ } : null : selectedRequest,
1285
+ selectedDocSection: selectedDocSection,
1286
+ selectedDocPage: selectedDocPage,
1287
+ activeTab: activeTab,
1288
+ onSelectRequest: showGraphQL ? handleSelectGraphQLOperation : handleSelectRequest,
1289
+ onSelectDocumentation: handleSelectDocumentation,
1290
+ onSelectDocPage: handleSelectDocPage,
1291
+ apiVersions: collection.apiVersions,
1292
+ selectedApiVersion: selectedApiVersion,
1293
+ onApiVersionChange: handleApiVersionChange,
1294
+ isVersionLoading: isVersionLoading
1295
+ }),
1296
+ /*#__PURE__*/ _jsxs("div", {
1297
+ className: "docs-main flex-1 flex flex-col overflow-hidden",
1298
+ style: {
1299
+ minWidth: 0,
1300
+ flexBasis: 0,
1301
+ flexGrow: 1
1302
+ },
1303
+ children: [
1304
+ /*#__PURE__*/ _jsx("div", {
1305
+ className: "docs-main-header flex items-center justify-end px-3 sm:px-4 h-[41px] border-b border-border bg-muted/30 flex-shrink-0",
1306
+ children: /*#__PURE__*/ _jsx(ModeToggleTabs, {
1307
+ hasEndpoint: !!selectedRequest
1308
+ })
1309
+ }),
1310
+ mode === 'docs' ? /*#__PURE__*/ _jsx(DocsNavigationProvider, {
1311
+ onNavigateToPage: handleSelectDocPage,
1312
+ onSwitchTab: onTabChange,
1313
+ activeTab: activeTab,
1314
+ children: /*#__PURE__*/ _jsx("div", {
1315
+ ref: contentRef,
1316
+ className: cn("docs-content-area flex-1 bg-background min-w-0", showChangelog || showGraphQL && selectedGraphQLOperation && !selectedDocPage ? "overflow-hidden flex flex-col" : "overflow-y-auto scroll-smooth"),
1317
+ children: showGraphQL && selectedGraphQLOperation && !selectedDocPage ? /*#__PURE__*/ _jsx("div", {
1318
+ className: "flex-1 flex flex-col h-full",
1319
+ children: /*#__PURE__*/ _jsx(GraphQLPlayground, {
1320
+ endpoint: activeGraphQLSchemas[0]?.endpoint || '',
1321
+ defaultQuery: selectedGraphQLOperation?.query,
1322
+ operations: graphqlOperations,
1323
+ selectedOperationId: selectedGraphQLOperation?.id,
1324
+ hideExplorer: true,
1325
+ headers: {},
1326
+ theme: "dark",
1327
+ schemaSDL: graphqlSchemaSDL
1328
+ })
1329
+ }) : showChangelog ? /*#__PURE__*/ _jsx(ChangelogPage, {
1330
+ releases: collection.changelogReleases || [],
1331
+ tabName: activeTabConfig?.tab
1332
+ }) : selectedRequest ? /*#__PURE__*/ _jsx(RequestDetails, {
1333
+ request: selectedRequest
1334
+ }) : selectedDocPage ? /*#__PURE__*/ _jsx(DocPage, {
1335
+ slug: selectedDocPage,
1336
+ onSearch: openSearch
1337
+ }) : notFoundSlug ? /*#__PURE__*/ _jsx(NotFoundPage, {
1338
+ slug: notFoundSlug,
1339
+ onSearch: openSearch
1340
+ }) : /*#__PURE__*/ _jsx("div", {
1341
+ className: "flex-1 flex items-center justify-center bg-background",
1342
+ children: /*#__PURE__*/ _jsxs("div", {
1343
+ className: "text-center text-muted-foreground",
1344
+ children: [
1345
+ /*#__PURE__*/ _jsx(Book, {
1346
+ className: "h-12 w-12 mx-auto mb-3 opacity-40"
1347
+ }),
1348
+ /*#__PURE__*/ _jsx("p", {
1349
+ className: "text-sm",
1350
+ children: "Select an endpoint from the sidebar"
1351
+ })
1352
+ ]
1353
+ })
1354
+ })
1355
+ })
1356
+ }) : mode === 'notes' ? /*#__PURE__*/ _jsx("div", {
1357
+ className: "flex-1 flex flex-col min-h-0 overflow-hidden",
1358
+ children: /*#__PURE__*/ _jsx(NotesMode, {
1359
+ apiSpecUrl: apiSpecUrl,
1360
+ apiName: collection.name
1361
+ })
1362
+ }) : selectedRequest ? /*#__PURE__*/ _jsx("div", {
1363
+ className: "flex-1 flex flex-col min-h-0 overflow-hidden",
1364
+ children: /*#__PURE__*/ _jsx(ApiPlayground, {
1365
+ request: selectedRequest,
1366
+ onDebugRequest: handleDebugRequest,
1367
+ onExplainRequest: handleExplainRequest
1368
+ })
1369
+ }) : /*#__PURE__*/ _jsx("div", {
1370
+ className: "flex-1 flex items-center justify-center bg-background",
1371
+ children: /*#__PURE__*/ _jsxs("div", {
1372
+ className: "text-center text-muted-foreground",
1373
+ children: [
1374
+ /*#__PURE__*/ _jsx(TestTube, {
1375
+ className: "h-12 w-12 mx-auto mb-3 opacity-40"
1376
+ }),
1377
+ /*#__PURE__*/ _jsx("p", {
1378
+ className: "text-sm",
1379
+ children: "Select an endpoint from the sidebar to test"
1380
+ })
1381
+ ]
1382
+ })
1383
+ })
1384
+ ]
1385
+ }),
1386
+ /*#__PURE__*/ _jsx(RightSidebar, {
1387
+ request: selectedRequest,
1388
+ collection: collection,
1389
+ apiSummary: collection.apiSummary,
1390
+ onNavigateToEndpoint: handleAgentNavigateWithModeSwitch,
1391
+ onPrefillParameters: handleAgentPrefill,
1392
+ debugContext: debugContext,
1393
+ onClearDebugContext: clearDebugContext,
1394
+ explainContext: explainContext,
1395
+ onClearExplainContext: clearExplainContext,
1396
+ onOpenGlobalAuth: ()=>setShowAuthModal(true),
1397
+ onNavigateToAuthTab: ()=>{
1398
+ navigateAndHighlight('auth', {
1399
+ type: 'auth'
1400
+ }, true);
1401
+ },
1402
+ onNavigateToParamsTab: ()=>{
1403
+ navigateAndHighlight('params', {
1404
+ type: 'param'
1405
+ }, true);
1406
+ },
1407
+ onNavigateToBodyTab: ()=>{
1408
+ navigateAndHighlight('body', {
1409
+ type: 'body'
1410
+ }, true);
1411
+ },
1412
+ onNavigateToHeadersTab: ()=>{
1413
+ navigateAndHighlight('headers', {
1414
+ type: 'header'
1415
+ }, true);
1416
+ },
1417
+ onNavigateToDocSection: handleSelectDocumentation,
1418
+ onNavigateToDocPage: handleSelectDocPage
1419
+ })
1420
+ ]
1421
+ }),
1422
+ /*#__PURE__*/ _jsx(GlobalAuthModal, {
1423
+ open: showAuthModal,
1424
+ onClose: ()=>setShowAuthModal(false)
1425
+ }),
1426
+ !isRightSidebarOpen && /*#__PURE__*/ _jsx(AgentPopupButton, {
1427
+ onClick: openRightSidebar,
1428
+ currentEndpoint: selectedRequest ? {
1429
+ id: selectedRequest.id,
1430
+ name: selectedRequest.name
1431
+ } : null,
1432
+ endpointIndex: endpointIndex
1433
+ })
1434
+ ]
1435
+ });
1436
+ }
1437
+ // Wrapper component with providers
1438
+ export function Docs() {
1439
+ return /*#__PURE__*/ _jsx(AuthProvider, {
1440
+ children: /*#__PURE__*/ _jsx(ModeProvider, {
1441
+ children: /*#__PURE__*/ _jsx(PlaygroundProvider, {
1442
+ children: /*#__PURE__*/ _jsx(PlaygroundNavigationProvider, {
1443
+ children: /*#__PURE__*/ _jsx(DocsContent, {})
1444
+ })
1445
+ })
1446
+ })
1447
+ });
1448
+ }