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