@brainfish-ai/devdoc 0.1.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (268) hide show
  1. package/LICENSE +33 -0
  2. package/README.md +415 -0
  3. package/bin/devdoc.js +13 -0
  4. package/dist/cli/commands/build.d.ts +5 -0
  5. package/dist/cli/commands/build.js +87 -0
  6. package/dist/cli/commands/check.d.ts +1 -0
  7. package/dist/cli/commands/check.js +143 -0
  8. package/dist/cli/commands/create.d.ts +24 -0
  9. package/dist/cli/commands/create.js +387 -0
  10. package/dist/cli/commands/deploy.d.ts +9 -0
  11. package/dist/cli/commands/deploy.js +433 -0
  12. package/dist/cli/commands/dev.d.ts +6 -0
  13. package/dist/cli/commands/dev.js +139 -0
  14. package/dist/cli/commands/init.d.ts +11 -0
  15. package/dist/cli/commands/init.js +238 -0
  16. package/dist/cli/commands/keys.d.ts +12 -0
  17. package/dist/cli/commands/keys.js +165 -0
  18. package/dist/cli/commands/start.d.ts +5 -0
  19. package/dist/cli/commands/start.js +56 -0
  20. package/dist/cli/commands/upload.d.ts +13 -0
  21. package/dist/cli/commands/upload.js +238 -0
  22. package/dist/cli/commands/whoami.d.ts +8 -0
  23. package/dist/cli/commands/whoami.js +91 -0
  24. package/dist/cli/index.d.ts +1 -0
  25. package/dist/cli/index.js +106 -0
  26. package/dist/config/index.d.ts +80 -0
  27. package/dist/config/index.js +133 -0
  28. package/dist/constants.d.ts +9 -0
  29. package/dist/constants.js +13 -0
  30. package/dist/index.d.ts +7 -0
  31. package/dist/index.js +12 -0
  32. package/dist/utils/logger.d.ts +16 -0
  33. package/dist/utils/logger.js +61 -0
  34. package/dist/utils/paths.d.ts +16 -0
  35. package/dist/utils/paths.js +50 -0
  36. package/package.json +51 -0
  37. package/renderer/app/api/assets/[...path]/route.ts +123 -0
  38. package/renderer/app/api/assets/route.ts +124 -0
  39. package/renderer/app/api/assets/upload/route.ts +177 -0
  40. package/renderer/app/api/auth-schemes/route.ts +77 -0
  41. package/renderer/app/api/chat/route.ts +858 -0
  42. package/renderer/app/api/codegen/route.ts +72 -0
  43. package/renderer/app/api/collections/route.ts +1016 -0
  44. package/renderer/app/api/debug/route.ts +53 -0
  45. package/renderer/app/api/deploy/route.ts +234 -0
  46. package/renderer/app/api/device/route.ts +42 -0
  47. package/renderer/app/api/docs/route.ts +187 -0
  48. package/renderer/app/api/keys/regenerate/route.ts +80 -0
  49. package/renderer/app/api/openapi-spec/route.ts +151 -0
  50. package/renderer/app/api/projects/[slug]/route.ts +153 -0
  51. package/renderer/app/api/projects/[slug]/stats/route.ts +96 -0
  52. package/renderer/app/api/projects/register/route.ts +152 -0
  53. package/renderer/app/api/proxy/route.ts +149 -0
  54. package/renderer/app/api/proxy-stream/route.ts +168 -0
  55. package/renderer/app/api/redirects/route.ts +47 -0
  56. package/renderer/app/api/schema/route.ts +65 -0
  57. package/renderer/app/api/subdomains/check/route.ts +172 -0
  58. package/renderer/app/api/suggestions/route.ts +144 -0
  59. package/renderer/app/favicon.ico +0 -0
  60. package/renderer/app/globals.css +1103 -0
  61. package/renderer/app/layout.tsx +47 -0
  62. package/renderer/app/llms-full.txt/route.ts +346 -0
  63. package/renderer/app/llms.txt/route.ts +279 -0
  64. package/renderer/app/page.tsx +14 -0
  65. package/renderer/app/robots.txt/route.ts +84 -0
  66. package/renderer/app/sitemap.xml/route.ts +199 -0
  67. package/renderer/components/docs/index.ts +12 -0
  68. package/renderer/components/docs/mdx/accordion.tsx +169 -0
  69. package/renderer/components/docs/mdx/badge.tsx +132 -0
  70. package/renderer/components/docs/mdx/callouts.tsx +154 -0
  71. package/renderer/components/docs/mdx/cards.tsx +213 -0
  72. package/renderer/components/docs/mdx/changelog.tsx +120 -0
  73. package/renderer/components/docs/mdx/code-block.tsx +186 -0
  74. package/renderer/components/docs/mdx/code-group.tsx +421 -0
  75. package/renderer/components/docs/mdx/file-embeds.tsx +105 -0
  76. package/renderer/components/docs/mdx/frame.tsx +112 -0
  77. package/renderer/components/docs/mdx/highlight.tsx +151 -0
  78. package/renderer/components/docs/mdx/iframe.tsx +134 -0
  79. package/renderer/components/docs/mdx/image.tsx +235 -0
  80. package/renderer/components/docs/mdx/index.ts +204 -0
  81. package/renderer/components/docs/mdx/mermaid.tsx +240 -0
  82. package/renderer/components/docs/mdx/param-field.tsx +200 -0
  83. package/renderer/components/docs/mdx/steps.tsx +113 -0
  84. package/renderer/components/docs/mdx/tabs.tsx +86 -0
  85. package/renderer/components/docs/mdx-renderer.tsx +100 -0
  86. package/renderer/components/docs/navigation/breadcrumbs.tsx +76 -0
  87. package/renderer/components/docs/navigation/index.ts +8 -0
  88. package/renderer/components/docs/navigation/page-nav.tsx +64 -0
  89. package/renderer/components/docs/navigation/sidebar.tsx +515 -0
  90. package/renderer/components/docs/navigation/toc.tsx +113 -0
  91. package/renderer/components/docs/notice.tsx +105 -0
  92. package/renderer/components/docs-header.tsx +274 -0
  93. package/renderer/components/docs-viewer/agent/agent-chat.tsx +2076 -0
  94. package/renderer/components/docs-viewer/agent/cards/debug-context-card.tsx +90 -0
  95. package/renderer/components/docs-viewer/agent/cards/endpoint-context-card.tsx +49 -0
  96. package/renderer/components/docs-viewer/agent/cards/index.tsx +50 -0
  97. package/renderer/components/docs-viewer/agent/cards/response-options-card.tsx +212 -0
  98. package/renderer/components/docs-viewer/agent/cards/types.ts +84 -0
  99. package/renderer/components/docs-viewer/agent/chat-message.tsx +17 -0
  100. package/renderer/components/docs-viewer/agent/index.tsx +6 -0
  101. package/renderer/components/docs-viewer/agent/messages/assistant-message.tsx +119 -0
  102. package/renderer/components/docs-viewer/agent/messages/chat-message.tsx +46 -0
  103. package/renderer/components/docs-viewer/agent/messages/index.ts +17 -0
  104. package/renderer/components/docs-viewer/agent/messages/tool-call-display.tsx +721 -0
  105. package/renderer/components/docs-viewer/agent/messages/types.ts +61 -0
  106. package/renderer/components/docs-viewer/agent/messages/typing-indicator.tsx +24 -0
  107. package/renderer/components/docs-viewer/agent/messages/user-message.tsx +51 -0
  108. package/renderer/components/docs-viewer/code-editor/index.tsx +2 -0
  109. package/renderer/components/docs-viewer/code-editor/notes-mode.tsx +1283 -0
  110. package/renderer/components/docs-viewer/content/changelog-page.tsx +331 -0
  111. package/renderer/components/docs-viewer/content/doc-page.tsx +285 -0
  112. package/renderer/components/docs-viewer/content/documentation-viewer.tsx +17 -0
  113. package/renderer/components/docs-viewer/content/index.tsx +29 -0
  114. package/renderer/components/docs-viewer/content/introduction.tsx +21 -0
  115. package/renderer/components/docs-viewer/content/request-details.tsx +330 -0
  116. package/renderer/components/docs-viewer/content/sections/auth.tsx +69 -0
  117. package/renderer/components/docs-viewer/content/sections/body.tsx +66 -0
  118. package/renderer/components/docs-viewer/content/sections/headers.tsx +43 -0
  119. package/renderer/components/docs-viewer/content/sections/overview.tsx +40 -0
  120. package/renderer/components/docs-viewer/content/sections/parameters.tsx +43 -0
  121. package/renderer/components/docs-viewer/content/sections/responses.tsx +87 -0
  122. package/renderer/components/docs-viewer/global-auth-modal.tsx +352 -0
  123. package/renderer/components/docs-viewer/index.tsx +1466 -0
  124. package/renderer/components/docs-viewer/playground/auth-editor.tsx +280 -0
  125. package/renderer/components/docs-viewer/playground/body-editor.tsx +221 -0
  126. package/renderer/components/docs-viewer/playground/code-editor.tsx +224 -0
  127. package/renderer/components/docs-viewer/playground/code-snippet.tsx +387 -0
  128. package/renderer/components/docs-viewer/playground/graphql-playground.tsx +745 -0
  129. package/renderer/components/docs-viewer/playground/index.tsx +671 -0
  130. package/renderer/components/docs-viewer/playground/key-value-editor.tsx +261 -0
  131. package/renderer/components/docs-viewer/playground/method-selector.tsx +60 -0
  132. package/renderer/components/docs-viewer/playground/request-builder.tsx +179 -0
  133. package/renderer/components/docs-viewer/playground/request-tabs.tsx +237 -0
  134. package/renderer/components/docs-viewer/playground/response-cards/idle-card.tsx +21 -0
  135. package/renderer/components/docs-viewer/playground/response-cards/index.tsx +93 -0
  136. package/renderer/components/docs-viewer/playground/response-cards/loading-card.tsx +16 -0
  137. package/renderer/components/docs-viewer/playground/response-cards/network-error-card.tsx +23 -0
  138. package/renderer/components/docs-viewer/playground/response-cards/response-body-card.tsx +268 -0
  139. package/renderer/components/docs-viewer/playground/response-cards/types.ts +82 -0
  140. package/renderer/components/docs-viewer/playground/response-viewer.tsx +43 -0
  141. package/renderer/components/docs-viewer/search/index.ts +2 -0
  142. package/renderer/components/docs-viewer/search/search-dialog.tsx +331 -0
  143. package/renderer/components/docs-viewer/search/use-search.ts +117 -0
  144. package/renderer/components/docs-viewer/shared/markdown-renderer.tsx +431 -0
  145. package/renderer/components/docs-viewer/shared/method-badge.tsx +41 -0
  146. package/renderer/components/docs-viewer/shared/schema-viewer.tsx +349 -0
  147. package/renderer/components/docs-viewer/sidebar/collection-tree.tsx +239 -0
  148. package/renderer/components/docs-viewer/sidebar/endpoint-options.tsx +316 -0
  149. package/renderer/components/docs-viewer/sidebar/index.tsx +343 -0
  150. package/renderer/components/docs-viewer/sidebar/right-sidebar.tsx +202 -0
  151. package/renderer/components/docs-viewer/sidebar/sidebar-group.tsx +118 -0
  152. package/renderer/components/docs-viewer/sidebar/sidebar-item.tsx +226 -0
  153. package/renderer/components/docs-viewer/sidebar/sidebar-section.tsx +52 -0
  154. package/renderer/components/theme-provider.tsx +11 -0
  155. package/renderer/components/theme-toggle.tsx +76 -0
  156. package/renderer/components/ui/badge.tsx +46 -0
  157. package/renderer/components/ui/button.tsx +59 -0
  158. package/renderer/components/ui/dialog.tsx +118 -0
  159. package/renderer/components/ui/dropdown-menu.tsx +257 -0
  160. package/renderer/components/ui/input.tsx +21 -0
  161. package/renderer/components/ui/label.tsx +24 -0
  162. package/renderer/components/ui/navigation-menu.tsx +168 -0
  163. package/renderer/components/ui/select.tsx +190 -0
  164. package/renderer/components/ui/spinner.tsx +114 -0
  165. package/renderer/components/ui/tabs.tsx +66 -0
  166. package/renderer/components/ui/tooltip.tsx +61 -0
  167. package/renderer/hooks/use-code-copy.ts +88 -0
  168. package/renderer/hooks/use-openapi-title.ts +44 -0
  169. package/renderer/lib/api-docs/agent/index.ts +6 -0
  170. package/renderer/lib/api-docs/agent/indexer.ts +323 -0
  171. package/renderer/lib/api-docs/agent/spec-summary.ts +335 -0
  172. package/renderer/lib/api-docs/agent/types.ts +116 -0
  173. package/renderer/lib/api-docs/auth/auth-context.tsx +225 -0
  174. package/renderer/lib/api-docs/auth/auth-storage.ts +87 -0
  175. package/renderer/lib/api-docs/auth/crypto.ts +89 -0
  176. package/renderer/lib/api-docs/auth/index.ts +4 -0
  177. package/renderer/lib/api-docs/code-editor/db.ts +164 -0
  178. package/renderer/lib/api-docs/code-editor/hooks.ts +266 -0
  179. package/renderer/lib/api-docs/code-editor/index.ts +6 -0
  180. package/renderer/lib/api-docs/code-editor/mode-context.tsx +207 -0
  181. package/renderer/lib/api-docs/code-editor/types.ts +105 -0
  182. package/renderer/lib/api-docs/codegen/definitions.ts +297 -0
  183. package/renderer/lib/api-docs/codegen/har.ts +251 -0
  184. package/renderer/lib/api-docs/codegen/index.ts +159 -0
  185. package/renderer/lib/api-docs/factories.ts +151 -0
  186. package/renderer/lib/api-docs/index.ts +17 -0
  187. package/renderer/lib/api-docs/mobile-context.tsx +112 -0
  188. package/renderer/lib/api-docs/navigation-context.tsx +88 -0
  189. package/renderer/lib/api-docs/parsers/graphql/README.md +129 -0
  190. package/renderer/lib/api-docs/parsers/graphql/index.ts +91 -0
  191. package/renderer/lib/api-docs/parsers/graphql/parser.ts +491 -0
  192. package/renderer/lib/api-docs/parsers/graphql/transformer.ts +246 -0
  193. package/renderer/lib/api-docs/parsers/graphql/types.ts +283 -0
  194. package/renderer/lib/api-docs/parsers/openapi/README.md +32 -0
  195. package/renderer/lib/api-docs/parsers/openapi/dereferencer.ts +60 -0
  196. package/renderer/lib/api-docs/parsers/openapi/extractors/auth.ts +574 -0
  197. package/renderer/lib/api-docs/parsers/openapi/extractors/body.ts +403 -0
  198. package/renderer/lib/api-docs/parsers/openapi/extractors/index.ts +232 -0
  199. package/renderer/lib/api-docs/parsers/openapi/index.ts +171 -0
  200. package/renderer/lib/api-docs/parsers/openapi/transformer.ts +277 -0
  201. package/renderer/lib/api-docs/parsers/openapi/validator.ts +31 -0
  202. package/renderer/lib/api-docs/playground/context.tsx +107 -0
  203. package/renderer/lib/api-docs/playground/navigation-context.tsx +124 -0
  204. package/renderer/lib/api-docs/playground/request-builder.ts +223 -0
  205. package/renderer/lib/api-docs/playground/request-runner.ts +282 -0
  206. package/renderer/lib/api-docs/playground/types.ts +35 -0
  207. package/renderer/lib/api-docs/types.ts +269 -0
  208. package/renderer/lib/api-docs/utils.ts +311 -0
  209. package/renderer/lib/cache.ts +193 -0
  210. package/renderer/lib/docs/config/index.ts +29 -0
  211. package/renderer/lib/docs/config/loader.ts +142 -0
  212. package/renderer/lib/docs/config/schema.ts +298 -0
  213. package/renderer/lib/docs/index.ts +12 -0
  214. package/renderer/lib/docs/mdx/compiler.ts +176 -0
  215. package/renderer/lib/docs/mdx/frontmatter.ts +80 -0
  216. package/renderer/lib/docs/mdx/index.ts +26 -0
  217. package/renderer/lib/docs/navigation/generator.ts +348 -0
  218. package/renderer/lib/docs/navigation/index.ts +12 -0
  219. package/renderer/lib/docs/navigation/types.ts +123 -0
  220. package/renderer/lib/docs-navigation-context.tsx +80 -0
  221. package/renderer/lib/multi-tenant/context.ts +105 -0
  222. package/renderer/lib/storage/blob.ts +845 -0
  223. package/renderer/lib/utils.ts +6 -0
  224. package/renderer/next.config.ts +76 -0
  225. package/renderer/package.json +66 -0
  226. package/renderer/postcss.config.mjs +5 -0
  227. package/renderer/public/assets/images/screenshot.png +0 -0
  228. package/renderer/public/assets/logo/dark.svg +9 -0
  229. package/renderer/public/assets/logo/light.svg +9 -0
  230. package/renderer/public/assets/logo.svg +9 -0
  231. package/renderer/public/file.svg +1 -0
  232. package/renderer/public/globe.svg +1 -0
  233. package/renderer/public/icon.png +0 -0
  234. package/renderer/public/logo.svg +9 -0
  235. package/renderer/public/window.svg +1 -0
  236. package/renderer/tsconfig.json +28 -0
  237. package/templates/basic/README.md +139 -0
  238. package/templates/basic/assets/favicon.svg +4 -0
  239. package/templates/basic/assets/logo.svg +9 -0
  240. package/templates/basic/docs.json +47 -0
  241. package/templates/basic/guides/configuration.mdx +149 -0
  242. package/templates/basic/guides/overview.mdx +96 -0
  243. package/templates/basic/index.mdx +39 -0
  244. package/templates/basic/package.json +14 -0
  245. package/templates/basic/quickstart.mdx +92 -0
  246. package/templates/basic/vercel.json +6 -0
  247. package/templates/graphql/README.md +139 -0
  248. package/templates/graphql/api-reference/schema.graphql +305 -0
  249. package/templates/graphql/assets/favicon.svg +4 -0
  250. package/templates/graphql/assets/logo.svg +9 -0
  251. package/templates/graphql/docs.json +54 -0
  252. package/templates/graphql/guides/configuration.mdx +149 -0
  253. package/templates/graphql/guides/overview.mdx +96 -0
  254. package/templates/graphql/index.mdx +39 -0
  255. package/templates/graphql/package.json +14 -0
  256. package/templates/graphql/quickstart.mdx +92 -0
  257. package/templates/graphql/vercel.json +6 -0
  258. package/templates/openapi/README.md +139 -0
  259. package/templates/openapi/api-reference/openapi.json +419 -0
  260. package/templates/openapi/assets/favicon.svg +4 -0
  261. package/templates/openapi/assets/logo.svg +9 -0
  262. package/templates/openapi/docs.json +61 -0
  263. package/templates/openapi/guides/configuration.mdx +149 -0
  264. package/templates/openapi/guides/overview.mdx +96 -0
  265. package/templates/openapi/index.mdx +39 -0
  266. package/templates/openapi/package.json +14 -0
  267. package/templates/openapi/quickstart.mdx +92 -0
  268. package/templates/openapi/vercel.json +6 -0
@@ -0,0 +1,87 @@
1
+ 'use client'
2
+
3
+ import type { BrainfishRESTRequestResponses } from '@/lib/api-docs/types'
4
+ import { CodeViewer } from '../../playground/code-editor'
5
+
6
+ interface ResponsesSectionProps {
7
+ responses: BrainfishRESTRequestResponses
8
+ }
9
+
10
+ export function ResponsesSection({ responses }: ResponsesSectionProps) {
11
+ const responseEntries = Object.entries(responses)
12
+
13
+ if (responseEntries.length === 0) {
14
+ return null
15
+ }
16
+
17
+ return (
18
+ <section>
19
+ <h2 className="text-2xl font-semibold mb-4">Responses</h2>
20
+ <div className="space-y-4">
21
+ {responseEntries.map(([name, response]) => {
22
+ // Pass raw JSON - CodeViewer will format it
23
+ const bodyContent = response.body
24
+ ? typeof response.body === 'string'
25
+ ? response.body
26
+ : JSON.stringify(response.body)
27
+ : null
28
+
29
+ return (
30
+ <div key={name} className="border rounded-sm overflow-hidden">
31
+ <div className="bg-muted/50 px-4 py-3 border-b">
32
+ <div className="flex items-center gap-3">
33
+ <span
34
+ className={`px-2 py-1 rounded text-xs font-semibold ${
35
+ response.code >= 200 && response.code < 300
36
+ ? 'bg-green-500 text-white'
37
+ : response.code >= 400
38
+ ? 'bg-red-500 text-white'
39
+ : 'bg-gray-500 text-white'
40
+ }`}
41
+ >
42
+ {response.code}
43
+ </span>
44
+ <span className="font-medium">{response.status}</span>
45
+ {name !== response.status && (
46
+ <span className="text-sm text-muted-foreground">({name})</span>
47
+ )}
48
+ </div>
49
+ </div>
50
+
51
+ {response.headers.length > 0 && (
52
+ <div className="px-4 py-3 border-b bg-muted/30">
53
+ <p className="text-sm font-medium mb-2">Headers:</p>
54
+ <div className="space-y-1">
55
+ {response.headers.map((header, index) => (
56
+ <div key={index} className="text-sm">
57
+ <code className="bg-background px-2 py-1 rounded">
58
+ {header.key}
59
+ </code>
60
+ <span className="text-muted-foreground ml-2">{header.value}</span>
61
+ </div>
62
+ ))}
63
+ </div>
64
+ </div>
65
+ )}
66
+
67
+ {bodyContent && (
68
+ <div className="dark-editor">
69
+ <CodeViewer
70
+ value={bodyContent}
71
+ language="json"
72
+ theme="dark"
73
+ height="auto"
74
+ minHeight={100}
75
+ maxHeight={500}
76
+ showBorder={false}
77
+ rounded={false}
78
+ />
79
+ </div>
80
+ )}
81
+ </div>
82
+ )
83
+ })}
84
+ </div>
85
+ </section>
86
+ )
87
+ }
@@ -0,0 +1,352 @@
1
+ 'use client'
2
+
3
+ import { useState, useEffect, useMemo } from 'react'
4
+ import { ShieldCheck, Key, Lock, User, X, Star } from '@phosphor-icons/react'
5
+ import { Button } from '@/components/ui/button'
6
+ import { Input } from '@/components/ui/input'
7
+ import {
8
+ Dialog,
9
+ DialogContent,
10
+ DialogHeader,
11
+ DialogFooter,
12
+ DialogTitle,
13
+ DialogClose,
14
+ } from '@/components/ui/dialog'
15
+ import {
16
+ Select,
17
+ SelectContent,
18
+ SelectItem,
19
+ SelectTrigger,
20
+ SelectValue,
21
+ } from '@/components/ui/select'
22
+ import { useAuth } from '@/lib/api-docs/auth'
23
+ import type { BrainfishRESTAuth } from '@/lib/api-docs/types'
24
+ import { cn } from '@/lib/utils'
25
+
26
+ const BASE_AUTH_TYPES = [
27
+ { value: 'none', label: 'No Auth', icon: ShieldCheck },
28
+ { value: 'basic', label: 'Basic Auth', icon: User },
29
+ { value: 'bearer', label: 'Bearer Token', icon: Key },
30
+ { value: 'api-key', label: 'API Key', icon: Lock },
31
+ ] as const
32
+
33
+ interface GlobalAuthModalProps {
34
+ open: boolean
35
+ onClose: () => void
36
+ }
37
+
38
+ export function GlobalAuthModal({ open, onClose }: GlobalAuthModalProps) {
39
+ const { globalAuth, setGlobalAuth, clearAuth, specSchemes, specDefaultAuth } = useAuth()
40
+
41
+ // Local state for editing
42
+ const [authType, setAuthType] = useState<string>('none')
43
+ const [basicUsername, setBasicUsername] = useState('')
44
+ const [basicPassword, setBasicPassword] = useState('')
45
+ const [bearerToken, setBearerToken] = useState('')
46
+ const [apiKeyName, setApiKeyName] = useState('X-API-Key')
47
+ const [apiKeyValue, setApiKeyValue] = useState('')
48
+ const [apiKeyLocation, setApiKeyLocation] = useState<'HEADERS' | 'QUERY_PARAMS'>('HEADERS')
49
+ const [showPassword, setShowPassword] = useState(false)
50
+
51
+ // Build auth types with spec-recommended first
52
+ const AUTH_TYPES = useMemo(() => {
53
+ // If we have a spec default auth, put it first with a recommended label
54
+ if (specDefaultAuth && specDefaultAuth.authType !== 'none') {
55
+ const specType = specDefaultAuth.authType
56
+ const baseType = BASE_AUTH_TYPES.find(t => t.value === specType)
57
+
58
+ if (baseType) {
59
+ // Get scheme info but use short label
60
+ const scheme = specSchemes.find(s => s.type === specType)
61
+ const label = `${baseType.label} (Recommended)`
62
+ const description = scheme?.description
63
+
64
+ return [
65
+ { ...baseType, label, isRecommended: true, description },
66
+ ...BASE_AUTH_TYPES.filter(t => t.value !== specType).map(t => ({ ...t, isRecommended: false, description: undefined })),
67
+ ]
68
+ }
69
+ }
70
+ return BASE_AUTH_TYPES.map(t => ({ ...t, isRecommended: false, description: undefined }))
71
+ }, [specDefaultAuth, specSchemes])
72
+
73
+ // Sync local state with global auth when modal opens
74
+ useEffect(() => {
75
+ if (open && globalAuth) {
76
+ setAuthType(globalAuth.authType)
77
+
78
+ if (globalAuth.authType === 'basic') {
79
+ setBasicUsername(globalAuth.username)
80
+ setBasicPassword(globalAuth.password)
81
+ } else if (globalAuth.authType === 'bearer') {
82
+ setBearerToken(globalAuth.token)
83
+ } else if (globalAuth.authType === 'api-key') {
84
+ setApiKeyName(globalAuth.key)
85
+ setApiKeyValue(globalAuth.value)
86
+ setApiKeyLocation(globalAuth.addTo)
87
+ }
88
+ } else if (open) {
89
+ // If no global auth set, use spec default as the initial type
90
+ if (specDefaultAuth && specDefaultAuth.authType !== 'none') {
91
+ setAuthType(specDefaultAuth.authType)
92
+
93
+ // Pre-populate fields from spec (like API key name)
94
+ if (specDefaultAuth.authType === 'api-key') {
95
+ setApiKeyName(specDefaultAuth.key || 'X-API-Key')
96
+ setApiKeyLocation(specDefaultAuth.addTo || 'HEADERS')
97
+ setApiKeyValue('') // User needs to enter value
98
+ }
99
+ } else {
100
+ setAuthType('none')
101
+ }
102
+ setBasicUsername('')
103
+ setBasicPassword('')
104
+ setBearerToken('')
105
+ if (!specDefaultAuth || specDefaultAuth.authType !== 'api-key') {
106
+ setApiKeyName('X-API-Key')
107
+ setApiKeyValue('')
108
+ setApiKeyLocation('HEADERS')
109
+ }
110
+ }
111
+ }, [open, globalAuth, specDefaultAuth])
112
+
113
+ const handleSave = () => {
114
+ let auth: BrainfishRESTAuth
115
+
116
+ switch (authType) {
117
+ case 'basic':
118
+ auth = {
119
+ authType: 'basic',
120
+ authActive: true,
121
+ username: basicUsername.trim(),
122
+ password: basicPassword,
123
+ }
124
+ break
125
+ case 'bearer':
126
+ auth = {
127
+ authType: 'bearer',
128
+ authActive: true,
129
+ token: bearerToken.trim(),
130
+ }
131
+ break
132
+ case 'api-key':
133
+ auth = {
134
+ authType: 'api-key',
135
+ authActive: true,
136
+ addTo: apiKeyLocation,
137
+ key: apiKeyName.trim(),
138
+ value: apiKeyValue.trim(),
139
+ }
140
+ break
141
+ default:
142
+ auth = { authType: 'none', authActive: true }
143
+ }
144
+
145
+ setGlobalAuth(auth)
146
+ onClose()
147
+ }
148
+
149
+ const handleClear = () => {
150
+ clearAuth()
151
+ setAuthType('none')
152
+ setBasicUsername('')
153
+ setBasicPassword('')
154
+ setBearerToken('')
155
+ setApiKeyName('X-API-Key')
156
+ setApiKeyValue('')
157
+ onClose()
158
+ }
159
+
160
+ const currentType = AUTH_TYPES.find((t) => t.value === authType) || AUTH_TYPES[0]
161
+ const CurrentIcon = currentType.icon
162
+
163
+ return (
164
+ <Dialog open={open} onOpenChange={(isOpen) => !isOpen && onClose()}>
165
+ <DialogContent>
166
+ <DialogHeader>
167
+ <DialogTitle>Global Authentication</DialogTitle>
168
+ <DialogClose className="text-muted-foreground hover:text-foreground transition-colors p-1 hover:bg-muted rounded">
169
+ <X className="h-4 w-4" />
170
+ </DialogClose>
171
+ </DialogHeader>
172
+
173
+ {/* Content */}
174
+ <div className="p-5 space-y-4">
175
+ {/* Auth Type Selector */}
176
+ <div className="space-y-1.5">
177
+ <label className="text-xs font-medium text-muted-foreground uppercase tracking-wide">Type</label>
178
+ <Select value={authType} onValueChange={setAuthType}>
179
+ <SelectTrigger className="w-full h-9">
180
+ <SelectValue>
181
+ <span className="flex items-center gap-2">
182
+ <CurrentIcon className="h-3.5 w-3.5" weight="bold" />
183
+ <span className="text-sm truncate">{currentType.label}</span>
184
+ {currentType.isRecommended && (
185
+ <Star className="h-3 w-3 text-amber-500 flex-shrink-0" weight="fill" />
186
+ )}
187
+ </span>
188
+ </SelectValue>
189
+ </SelectTrigger>
190
+ <SelectContent>
191
+ {AUTH_TYPES.map((type) => (
192
+ <SelectItem key={type.value} value={type.value}>
193
+ <div className="flex items-center gap-2">
194
+ <type.icon className="h-3.5 w-3.5" weight="bold" />
195
+ <span>{type.label}</span>
196
+ {type.isRecommended && (
197
+ <Star className="h-3 w-3 text-amber-500 ml-1" weight="fill" />
198
+ )}
199
+ </div>
200
+ </SelectItem>
201
+ ))}
202
+ </SelectContent>
203
+ </Select>
204
+ {currentType.description && (
205
+ <p className="text-xs text-muted-foreground mt-1.5 line-clamp-2">
206
+ {currentType.description.split('\n')[0]}
207
+ </p>
208
+ )}
209
+ </div>
210
+
211
+ {/* Auth Type Specific Fields */}
212
+ {authType === 'none' && (
213
+ <div className="flex items-center justify-center py-8 text-center">
214
+ <p className="text-sm text-muted-foreground">
215
+ No authentication will be applied
216
+ </p>
217
+ </div>
218
+ )}
219
+
220
+ {authType === 'basic' && (
221
+ <div className="space-y-3">
222
+ <div className="space-y-1.5">
223
+ <label className="text-xs font-medium text-muted-foreground">Username</label>
224
+ <Input
225
+ type="text"
226
+ value={basicUsername}
227
+ onChange={(e) => setBasicUsername(e.target.value)}
228
+ placeholder="Enter username"
229
+ className="h-9"
230
+ />
231
+ </div>
232
+ <div className="space-y-1.5">
233
+ <label className="text-xs font-medium text-muted-foreground">Password</label>
234
+ <div className="relative">
235
+ <Input
236
+ type={showPassword ? 'text' : 'password'}
237
+ value={basicPassword}
238
+ onChange={(e) => setBasicPassword(e.target.value)}
239
+ placeholder="Enter password"
240
+ className="h-9 pr-14"
241
+ />
242
+ <button
243
+ type="button"
244
+ onClick={() => setShowPassword(!showPassword)}
245
+ className="absolute right-2 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground text-xs px-1.5 py-0.5 rounded hover:bg-muted"
246
+ >
247
+ {showPassword ? 'Hide' : 'Show'}
248
+ </button>
249
+ </div>
250
+ </div>
251
+ </div>
252
+ )}
253
+
254
+ {authType === 'bearer' && (
255
+ <div className="space-y-1.5">
256
+ <label className="text-xs font-medium text-muted-foreground">Token</label>
257
+ <textarea
258
+ value={bearerToken}
259
+ onChange={(e) => setBearerToken(e.target.value)}
260
+ placeholder="Paste your bearer token..."
261
+ className="w-full min-h-[80px] px-3 py-2 rounded-md border border-input bg-background font-mono text-sm resize-none focus:outline-none focus:ring-2 focus:ring-ring placeholder:text-muted-foreground/50"
262
+ />
263
+ </div>
264
+ )}
265
+
266
+ {authType === 'api-key' && (
267
+ <div className="space-y-3">
268
+ {/* Location toggle */}
269
+ <div className="space-y-1.5">
270
+ <label className="text-xs font-medium text-muted-foreground">Add to</label>
271
+ <div className="flex p-0.5 bg-muted rounded-md">
272
+ <button
273
+ type="button"
274
+ onClick={() => setApiKeyLocation('HEADERS')}
275
+ className={cn(
276
+ 'flex-1 px-3 py-1 rounded text-xs font-medium transition-all',
277
+ apiKeyLocation === 'HEADERS'
278
+ ? 'bg-background text-foreground shadow-sm'
279
+ : 'text-muted-foreground hover:text-foreground'
280
+ )}
281
+ >
282
+ Header
283
+ </button>
284
+ <button
285
+ type="button"
286
+ onClick={() => setApiKeyLocation('QUERY_PARAMS')}
287
+ className={cn(
288
+ 'flex-1 px-3 py-1 rounded text-xs font-medium transition-all',
289
+ apiKeyLocation === 'QUERY_PARAMS'
290
+ ? 'bg-background text-foreground shadow-sm'
291
+ : 'text-muted-foreground hover:text-foreground'
292
+ )}
293
+ >
294
+ Query
295
+ </button>
296
+ </div>
297
+ </div>
298
+
299
+ <div className="space-y-1.5">
300
+ <label className="text-xs font-medium text-muted-foreground">Key Name</label>
301
+ <Input
302
+ type="text"
303
+ value={apiKeyName}
304
+ onChange={(e) => setApiKeyName(e.target.value)}
305
+ placeholder="X-API-Key"
306
+ className="font-mono h-9"
307
+ />
308
+ </div>
309
+
310
+ <div className="space-y-1.5">
311
+ <label className="text-xs font-medium text-muted-foreground">Key Value</label>
312
+ <div className="relative">
313
+ <Input
314
+ type={showPassword ? 'text' : 'password'}
315
+ value={apiKeyValue}
316
+ onChange={(e) => setApiKeyValue(e.target.value)}
317
+ placeholder="Enter API key"
318
+ className="font-mono h-9 pr-14"
319
+ />
320
+ <button
321
+ type="button"
322
+ onClick={() => setShowPassword(!showPassword)}
323
+ className="absolute right-2 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground text-xs px-1.5 py-0.5 rounded hover:bg-muted"
324
+ >
325
+ {showPassword ? 'Hide' : 'Show'}
326
+ </button>
327
+ </div>
328
+ </div>
329
+ </div>
330
+ )}
331
+ </div>
332
+
333
+ <DialogFooter>
334
+ <button
335
+ onClick={handleClear}
336
+ className="text-xs text-muted-foreground hover:text-destructive transition-colors"
337
+ >
338
+ Clear
339
+ </button>
340
+ <div className="flex gap-2">
341
+ <Button variant="ghost" size="sm" onClick={onClose} className="h-8 px-3 text-xs">
342
+ Cancel
343
+ </Button>
344
+ <Button size="sm" onClick={handleSave} className="h-8 px-4 text-xs">
345
+ Apply
346
+ </Button>
347
+ </div>
348
+ </DialogFooter>
349
+ </DialogContent>
350
+ </Dialog>
351
+ )
352
+ }