@brainfish-ai/devdoc 0.1.42 → 0.1.44

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (398) hide show
  1. package/dist/cli/commands/create.js +2 -2
  2. package/dist/cli/commands/dev.js +19 -10
  3. package/package.json +3 -2
  4. package/renderer/app/api/assets/[...path]/route.js +108 -0
  5. package/renderer/app/api/assets/route.js +114 -0
  6. package/renderer/app/api/assets/upload/route.js +163 -0
  7. package/renderer/app/api/auth-schemes/route.js +58 -0
  8. package/renderer/app/api/chat/route.js +759 -0
  9. package/renderer/app/api/codegen/route.js +52 -0
  10. package/renderer/app/api/collections/route.js +706 -0
  11. package/renderer/app/api/debug/route.js +47 -0
  12. package/renderer/app/api/deploy/route.js +199 -0
  13. package/renderer/app/api/device/route.js +36 -0
  14. package/renderer/app/api/docs/route.js +205 -0
  15. package/renderer/app/api/domains/add/route.js +121 -0
  16. package/renderer/app/api/domains/lookup/route.js +43 -0
  17. package/renderer/app/api/domains/remove/route.js +89 -0
  18. package/renderer/app/api/domains/status/route.js +140 -0
  19. package/renderer/app/api/domains/verify/route.js +168 -0
  20. package/renderer/app/api/keys/regenerate/route.js +71 -0
  21. package/renderer/app/api/local-assets/[...path]/route.js +108 -0
  22. package/renderer/app/api/openapi-spec/route.js +73 -0
  23. package/renderer/app/api/projects/[slug]/route.js +129 -0
  24. package/renderer/app/api/projects/[slug]/stats/route.js +80 -0
  25. package/renderer/app/api/projects/register/route.js +176 -0
  26. package/renderer/app/api/proxy/route.js +139 -0
  27. package/renderer/app/api/proxy-stream/route.js +156 -0
  28. package/renderer/app/api/redirects/route.js +35 -0
  29. package/renderer/app/api/schema/route.js +85 -0
  30. package/renderer/app/api/subdomains/check/route.js +158 -0
  31. package/renderer/app/api/suggestions/route.js +195 -0
  32. package/renderer/app/globals.css +69 -0
  33. package/renderer/app/layout.js +47 -0
  34. package/renderer/app/llms-full.txt/route.js +266 -0
  35. package/renderer/app/llms.txt/route.js +228 -0
  36. package/renderer/app/page.js +12 -0
  37. package/renderer/app/robots.txt/route.js +66 -0
  38. package/renderer/app/sitemap.xml/route.js +155 -0
  39. package/renderer/components/docs/index.js +8 -0
  40. package/renderer/components/docs/mdx/accordion.js +113 -0
  41. package/renderer/components/docs/mdx/badge.js +72 -0
  42. package/renderer/components/docs/mdx/callouts.js +137 -0
  43. package/renderer/components/docs/mdx/cards.js +175 -0
  44. package/renderer/components/docs/mdx/changelog.js +100 -0
  45. package/renderer/components/docs/mdx/code-block.js +147 -0
  46. package/renderer/components/docs/mdx/code-group.js +287 -0
  47. package/renderer/components/docs/mdx/file-embeds.js +82 -0
  48. package/renderer/components/docs/mdx/frame.js +59 -0
  49. package/renderer/components/docs/mdx/highlight.js +90 -0
  50. package/renderer/components/docs/mdx/iframe.js +69 -0
  51. package/renderer/components/docs/mdx/image.js +135 -0
  52. package/renderer/components/docs/mdx/index.js +134 -0
  53. package/renderer/components/docs/mdx/landing.js +317 -0
  54. package/renderer/components/docs/mdx/mermaid.js +212 -0
  55. package/renderer/components/docs/mdx/param-field.js +112 -0
  56. package/renderer/components/docs/mdx/steps.js +74 -0
  57. package/renderer/components/docs/mdx/tabs.js +50 -0
  58. package/renderer/components/docs/mdx-renderer.js +77 -0
  59. package/renderer/components/docs/navigation/breadcrumbs.js +64 -0
  60. package/renderer/components/docs/navigation/index.js +6 -0
  61. package/renderer/components/docs/navigation/page-nav.js +57 -0
  62. package/renderer/components/docs/navigation/sidebar.js +375 -0
  63. package/renderer/components/docs/navigation/toc.js +89 -0
  64. package/renderer/components/docs/notice.js +77 -0
  65. package/renderer/components/docs-header.js +202 -0
  66. package/renderer/components/docs-viewer/agent/agent-chat.js +1831 -0
  67. package/renderer/components/docs-viewer/agent/agent-popup-button.js +99 -0
  68. package/renderer/components/docs-viewer/agent/cards/debug-context-card.js +107 -0
  69. package/renderer/components/docs-viewer/agent/cards/endpoint-context-card.js +57 -0
  70. package/renderer/components/docs-viewer/agent/cards/index.js +45 -0
  71. package/renderer/components/docs-viewer/agent/cards/response-options-card.js +154 -0
  72. package/renderer/components/docs-viewer/agent/cards/types.js +22 -0
  73. package/renderer/components/docs-viewer/agent/chat-message.js +2 -0
  74. package/renderer/components/docs-viewer/agent/index.js +7 -0
  75. package/renderer/components/docs-viewer/agent/messages/assistant-message.js +108 -0
  76. package/renderer/components/docs-viewer/agent/messages/chat-message.js +34 -0
  77. package/renderer/components/docs-viewer/agent/messages/index.js +6 -0
  78. package/renderer/components/docs-viewer/agent/messages/tool-call-display.js +1065 -0
  79. package/renderer/components/docs-viewer/agent/messages/types.js +2 -0
  80. package/renderer/components/docs-viewer/agent/messages/typing-indicator.js +26 -0
  81. package/renderer/components/docs-viewer/agent/messages/user-message.js +37 -0
  82. package/renderer/components/docs-viewer/code-editor/{index.tsx → index.js} +1 -1
  83. package/renderer/components/docs-viewer/code-editor/notes-mode.js +1338 -0
  84. package/renderer/components/docs-viewer/content/changelog-page.js +297 -0
  85. package/renderer/components/docs-viewer/content/content-router.js +182 -0
  86. package/renderer/components/docs-viewer/content/doc-page.js +290 -0
  87. package/renderer/components/docs-viewer/content/documentation-viewer.js +14 -0
  88. package/renderer/components/docs-viewer/content/index.js +31 -0
  89. package/renderer/components/docs-viewer/content/not-found-page.js +300 -0
  90. package/renderer/components/docs-viewer/content/request-details.js +528 -0
  91. package/renderer/components/docs-viewer/content/sections/auth.js +108 -0
  92. package/renderer/components/docs-viewer/content/sections/body.js +80 -0
  93. package/renderer/components/docs-viewer/content/sections/headers.js +64 -0
  94. package/renderer/components/docs-viewer/content/sections/overview.js +56 -0
  95. package/renderer/components/docs-viewer/content/sections/parameters.js +64 -0
  96. package/renderer/components/docs-viewer/content/sections/responses.js +91 -0
  97. package/renderer/components/docs-viewer/global-auth-modal.js +427 -0
  98. package/renderer/components/docs-viewer/index.js +1448 -0
  99. package/renderer/components/docs-viewer/playground/auth-editor.js +418 -0
  100. package/renderer/components/docs-viewer/playground/body-editor.js +240 -0
  101. package/renderer/components/docs-viewer/playground/code-editor.js +135 -0
  102. package/renderer/components/docs-viewer/playground/code-snippet.js +393 -0
  103. package/renderer/components/docs-viewer/playground/graphql-playground.js +936 -0
  104. package/renderer/components/docs-viewer/playground/index.js +682 -0
  105. package/renderer/components/docs-viewer/playground/key-value-editor.js +317 -0
  106. package/renderer/components/docs-viewer/playground/method-selector.js +65 -0
  107. package/renderer/components/docs-viewer/playground/request-builder.js +181 -0
  108. package/renderer/components/docs-viewer/playground/request-tabs.js +240 -0
  109. package/renderer/components/docs-viewer/playground/response-cards/idle-card.js +42 -0
  110. package/renderer/components/docs-viewer/playground/response-cards/index.js +72 -0
  111. package/renderer/components/docs-viewer/playground/response-cards/loading-card.js +24 -0
  112. package/renderer/components/docs-viewer/playground/response-cards/network-error-card.js +28 -0
  113. package/renderer/components/docs-viewer/playground/response-cards/response-body-card.js +308 -0
  114. package/renderer/components/docs-viewer/playground/response-cards/types.js +9 -0
  115. package/renderer/components/docs-viewer/playground/response-viewer.js +18 -0
  116. package/renderer/components/docs-viewer/search/index.js +2 -0
  117. package/renderer/components/docs-viewer/search/search-dialog.js +367 -0
  118. package/renderer/components/docs-viewer/search/use-search.js +89 -0
  119. package/renderer/components/docs-viewer/shared/markdown-renderer.js +423 -0
  120. package/renderer/components/docs-viewer/shared/method-badge.js +23 -0
  121. package/renderer/components/docs-viewer/shared/schema-viewer.js +321 -0
  122. package/renderer/components/docs-viewer/sidebar/collection-tree.js +222 -0
  123. package/renderer/components/docs-viewer/sidebar/endpoint-options.js +512 -0
  124. package/renderer/components/docs-viewer/sidebar/index.js +196 -0
  125. package/renderer/components/docs-viewer/sidebar/right-sidebar.js +159 -0
  126. package/renderer/components/docs-viewer/sidebar/sidebar-group.js +87 -0
  127. package/renderer/components/docs-viewer/sidebar/sidebar-item.js +172 -0
  128. package/renderer/components/docs-viewer/sidebar/sidebar-section.js +31 -0
  129. package/renderer/components/theme-provider.js +10 -0
  130. package/renderer/components/theme-toggle.js +86 -0
  131. package/renderer/components/ui/badge.js +29 -0
  132. package/renderer/components/ui/button.js +40 -0
  133. package/renderer/components/ui/dialog.js +50 -0
  134. package/renderer/components/ui/dropdown-menu.js +143 -0
  135. package/renderer/components/ui/input.js +12 -0
  136. package/renderer/components/ui/label.js +13 -0
  137. package/renderer/components/ui/navigation-menu.js +83 -0
  138. package/renderer/components/ui/select.js +116 -0
  139. package/renderer/components/ui/spinner.js +92 -0
  140. package/renderer/components/ui/tabs.js +34 -0
  141. package/renderer/components/ui/tooltip.js +43 -0
  142. package/renderer/hooks/use-code-copy.js +76 -0
  143. package/renderer/hooks/use-openapi-title.js +33 -0
  144. package/renderer/hooks/use-route-state.js +159 -0
  145. package/renderer/lib/api-docs/agent/index.js +4 -0
  146. package/renderer/lib/api-docs/agent/indexer.js +254 -0
  147. package/renderer/lib/api-docs/agent/spec-summary.js +227 -0
  148. package/renderer/lib/api-docs/agent/types.js +5 -0
  149. package/renderer/lib/api-docs/agent/use-suggestions.js +97 -0
  150. package/renderer/lib/api-docs/auth/auth-context.js +157 -0
  151. package/renderer/lib/api-docs/auth/auth-storage.js +66 -0
  152. package/renderer/lib/api-docs/auth/crypto.js +64 -0
  153. package/renderer/lib/api-docs/auth/index.js +3 -0
  154. package/renderer/lib/api-docs/code-editor/db.js +145 -0
  155. package/renderer/lib/api-docs/code-editor/hooks.js +254 -0
  156. package/renderer/lib/api-docs/code-editor/{index.ts → index.js} +3 -4
  157. package/renderer/lib/api-docs/code-editor/mode-context.js +126 -0
  158. package/renderer/lib/api-docs/code-editor/types.js +53 -0
  159. package/renderer/lib/api-docs/codegen/definitions.js +258 -0
  160. package/renderer/lib/api-docs/codegen/har.js +171 -0
  161. package/renderer/lib/api-docs/codegen/index.js +118 -0
  162. package/renderer/lib/api-docs/factories.js +136 -0
  163. package/renderer/lib/api-docs/{index.ts → index.js} +5 -10
  164. package/renderer/lib/api-docs/mobile-context.js +116 -0
  165. package/renderer/lib/api-docs/navigation-context.js +62 -0
  166. package/renderer/lib/api-docs/parsers/graphql/index.js +50 -0
  167. package/renderer/lib/api-docs/parsers/graphql/parser.js +350 -0
  168. package/renderer/lib/api-docs/parsers/graphql/transformer.js +215 -0
  169. package/renderer/lib/api-docs/parsers/graphql/types.js +46 -0
  170. package/renderer/lib/api-docs/parsers/openapi/dereferencer.js +43 -0
  171. package/renderer/lib/api-docs/parsers/openapi/extractors/auth.js +486 -0
  172. package/renderer/lib/api-docs/parsers/openapi/extractors/body.js +295 -0
  173. package/renderer/lib/api-docs/parsers/openapi/extractors/index.js +132 -0
  174. package/renderer/lib/api-docs/parsers/openapi/index.js +127 -0
  175. package/renderer/lib/api-docs/parsers/openapi/transformer.js +192 -0
  176. package/renderer/lib/api-docs/parsers/openapi/validator.js +24 -0
  177. package/renderer/lib/api-docs/playground/context.js +65 -0
  178. package/renderer/lib/api-docs/playground/navigation-context.js +74 -0
  179. package/renderer/lib/api-docs/playground/request-builder.js +163 -0
  180. package/renderer/lib/api-docs/playground/request-runner.js +224 -0
  181. package/renderer/lib/api-docs/playground/types.js +5 -0
  182. package/renderer/lib/api-docs/types.js +23 -0
  183. package/renderer/lib/api-docs/utils.js +212 -0
  184. package/renderer/lib/cache.js +157 -0
  185. package/renderer/lib/docs/config/domain-schema.js +161 -0
  186. package/renderer/lib/docs/config/environment.js +38 -0
  187. package/renderer/lib/docs/config/index.js +6 -0
  188. package/renderer/lib/docs/config/loader.js +113 -0
  189. package/renderer/lib/docs/config/schema.js +281 -0
  190. package/renderer/lib/docs/index.js +8 -0
  191. package/renderer/lib/docs/mdx/compiler.js +131 -0
  192. package/renderer/lib/docs/mdx/frontmatter.js +73 -0
  193. package/renderer/lib/docs/mdx/index.js +10 -0
  194. package/renderer/lib/docs/mdx/remark-mermaid.js +63 -0
  195. package/renderer/lib/docs/navigation/generator.js +269 -0
  196. package/renderer/lib/docs/navigation/index.js +3 -0
  197. package/renderer/lib/docs/navigation/types.js +11 -0
  198. package/renderer/lib/docs-navigation-context.js +40 -0
  199. package/renderer/lib/docs-navigation.js +140 -0
  200. package/renderer/lib/multi-tenant/context.js +80 -0
  201. package/renderer/lib/storage/blob.js +767 -0
  202. package/renderer/lib/utils/icons.js +30 -0
  203. package/renderer/lib/utils.js +5 -0
  204. package/renderer/next.config.js +62 -0
  205. package/renderer/package.json +1 -0
  206. package/renderer/tsconfig.json +23 -5
  207. package/renderer/app/api/assets/[...path]/route.ts +0 -123
  208. package/renderer/app/api/assets/route.ts +0 -124
  209. package/renderer/app/api/assets/upload/route.ts +0 -177
  210. package/renderer/app/api/auth-schemes/route.ts +0 -77
  211. package/renderer/app/api/chat/route.ts +0 -858
  212. package/renderer/app/api/codegen/route.ts +0 -72
  213. package/renderer/app/api/collections/route.ts +0 -1002
  214. package/renderer/app/api/debug/route.ts +0 -53
  215. package/renderer/app/api/deploy/route.ts +0 -234
  216. package/renderer/app/api/device/route.ts +0 -42
  217. package/renderer/app/api/docs/route.ts +0 -201
  218. package/renderer/app/api/domains/add/route.ts +0 -132
  219. package/renderer/app/api/domains/lookup/route.ts +0 -43
  220. package/renderer/app/api/domains/remove/route.ts +0 -100
  221. package/renderer/app/api/domains/status/route.ts +0 -158
  222. package/renderer/app/api/domains/verify/route.ts +0 -181
  223. package/renderer/app/api/keys/regenerate/route.ts +0 -80
  224. package/renderer/app/api/local-assets/[...path]/route.ts +0 -122
  225. package/renderer/app/api/openapi-spec/route.ts +0 -151
  226. package/renderer/app/api/projects/[slug]/route.ts +0 -153
  227. package/renderer/app/api/projects/[slug]/stats/route.ts +0 -96
  228. package/renderer/app/api/projects/register/route.ts +0 -152
  229. package/renderer/app/api/proxy/route.ts +0 -149
  230. package/renderer/app/api/proxy-stream/route.ts +0 -168
  231. package/renderer/app/api/redirects/route.ts +0 -47
  232. package/renderer/app/api/schema/route.ts +0 -73
  233. package/renderer/app/api/subdomains/check/route.ts +0 -172
  234. package/renderer/app/api/suggestions/route.ts +0 -144
  235. package/renderer/app/layout.tsx +0 -54
  236. package/renderer/app/llms-full.txt/route.ts +0 -346
  237. package/renderer/app/llms.txt/route.ts +0 -279
  238. package/renderer/app/page.tsx +0 -14
  239. package/renderer/app/robots.txt/route.ts +0 -84
  240. package/renderer/app/sitemap.xml/route.ts +0 -199
  241. package/renderer/components/docs/index.ts +0 -12
  242. package/renderer/components/docs/mdx/accordion.tsx +0 -169
  243. package/renderer/components/docs/mdx/badge.tsx +0 -132
  244. package/renderer/components/docs/mdx/callouts.tsx +0 -154
  245. package/renderer/components/docs/mdx/cards.tsx +0 -241
  246. package/renderer/components/docs/mdx/changelog.tsx +0 -120
  247. package/renderer/components/docs/mdx/code-block.tsx +0 -186
  248. package/renderer/components/docs/mdx/code-group.tsx +0 -421
  249. package/renderer/components/docs/mdx/file-embeds.tsx +0 -105
  250. package/renderer/components/docs/mdx/frame.tsx +0 -112
  251. package/renderer/components/docs/mdx/highlight.tsx +0 -151
  252. package/renderer/components/docs/mdx/iframe.tsx +0 -134
  253. package/renderer/components/docs/mdx/image.tsx +0 -235
  254. package/renderer/components/docs/mdx/index.ts +0 -237
  255. package/renderer/components/docs/mdx/landing.tsx +0 -684
  256. package/renderer/components/docs/mdx/mermaid.tsx +0 -240
  257. package/renderer/components/docs/mdx/param-field.tsx +0 -200
  258. package/renderer/components/docs/mdx/steps.tsx +0 -113
  259. package/renderer/components/docs/mdx/tabs.tsx +0 -86
  260. package/renderer/components/docs/mdx-renderer.tsx +0 -100
  261. package/renderer/components/docs/navigation/breadcrumbs.tsx +0 -76
  262. package/renderer/components/docs/navigation/index.ts +0 -8
  263. package/renderer/components/docs/navigation/page-nav.tsx +0 -64
  264. package/renderer/components/docs/navigation/sidebar.tsx +0 -515
  265. package/renderer/components/docs/navigation/toc.tsx +0 -113
  266. package/renderer/components/docs/notice.tsx +0 -105
  267. package/renderer/components/docs-header.tsx +0 -278
  268. package/renderer/components/docs-viewer/agent/agent-chat.tsx +0 -2076
  269. package/renderer/components/docs-viewer/agent/cards/debug-context-card.tsx +0 -90
  270. package/renderer/components/docs-viewer/agent/cards/endpoint-context-card.tsx +0 -49
  271. package/renderer/components/docs-viewer/agent/cards/index.tsx +0 -50
  272. package/renderer/components/docs-viewer/agent/cards/response-options-card.tsx +0 -212
  273. package/renderer/components/docs-viewer/agent/cards/types.ts +0 -84
  274. package/renderer/components/docs-viewer/agent/chat-message.tsx +0 -17
  275. package/renderer/components/docs-viewer/agent/index.tsx +0 -6
  276. package/renderer/components/docs-viewer/agent/messages/assistant-message.tsx +0 -119
  277. package/renderer/components/docs-viewer/agent/messages/chat-message.tsx +0 -46
  278. package/renderer/components/docs-viewer/agent/messages/index.ts +0 -17
  279. package/renderer/components/docs-viewer/agent/messages/tool-call-display.tsx +0 -721
  280. package/renderer/components/docs-viewer/agent/messages/types.ts +0 -61
  281. package/renderer/components/docs-viewer/agent/messages/typing-indicator.tsx +0 -24
  282. package/renderer/components/docs-viewer/agent/messages/user-message.tsx +0 -51
  283. package/renderer/components/docs-viewer/code-editor/notes-mode.tsx +0 -1283
  284. package/renderer/components/docs-viewer/content/changelog-page.tsx +0 -331
  285. package/renderer/components/docs-viewer/content/doc-page.tsx +0 -367
  286. package/renderer/components/docs-viewer/content/documentation-viewer.tsx +0 -17
  287. package/renderer/components/docs-viewer/content/index.tsx +0 -29
  288. package/renderer/components/docs-viewer/content/not-found-page.tsx +0 -330
  289. package/renderer/components/docs-viewer/content/request-details.tsx +0 -330
  290. package/renderer/components/docs-viewer/content/sections/auth.tsx +0 -69
  291. package/renderer/components/docs-viewer/content/sections/body.tsx +0 -66
  292. package/renderer/components/docs-viewer/content/sections/headers.tsx +0 -43
  293. package/renderer/components/docs-viewer/content/sections/overview.tsx +0 -40
  294. package/renderer/components/docs-viewer/content/sections/parameters.tsx +0 -43
  295. package/renderer/components/docs-viewer/content/sections/responses.tsx +0 -87
  296. package/renderer/components/docs-viewer/global-auth-modal.tsx +0 -352
  297. package/renderer/components/docs-viewer/index.tsx +0 -1670
  298. package/renderer/components/docs-viewer/playground/auth-editor.tsx +0 -280
  299. package/renderer/components/docs-viewer/playground/body-editor.tsx +0 -221
  300. package/renderer/components/docs-viewer/playground/code-editor.tsx +0 -224
  301. package/renderer/components/docs-viewer/playground/code-snippet.tsx +0 -387
  302. package/renderer/components/docs-viewer/playground/graphql-playground.tsx +0 -745
  303. package/renderer/components/docs-viewer/playground/index.tsx +0 -671
  304. package/renderer/components/docs-viewer/playground/key-value-editor.tsx +0 -261
  305. package/renderer/components/docs-viewer/playground/method-selector.tsx +0 -60
  306. package/renderer/components/docs-viewer/playground/request-builder.tsx +0 -179
  307. package/renderer/components/docs-viewer/playground/request-tabs.tsx +0 -237
  308. package/renderer/components/docs-viewer/playground/response-cards/idle-card.tsx +0 -21
  309. package/renderer/components/docs-viewer/playground/response-cards/index.tsx +0 -93
  310. package/renderer/components/docs-viewer/playground/response-cards/loading-card.tsx +0 -16
  311. package/renderer/components/docs-viewer/playground/response-cards/network-error-card.tsx +0 -23
  312. package/renderer/components/docs-viewer/playground/response-cards/response-body-card.tsx +0 -268
  313. package/renderer/components/docs-viewer/playground/response-cards/types.ts +0 -82
  314. package/renderer/components/docs-viewer/playground/response-viewer.tsx +0 -43
  315. package/renderer/components/docs-viewer/search/index.ts +0 -2
  316. package/renderer/components/docs-viewer/search/search-dialog.tsx +0 -331
  317. package/renderer/components/docs-viewer/search/use-search.ts +0 -117
  318. package/renderer/components/docs-viewer/shared/markdown-renderer.tsx +0 -431
  319. package/renderer/components/docs-viewer/shared/method-badge.tsx +0 -41
  320. package/renderer/components/docs-viewer/shared/schema-viewer.tsx +0 -349
  321. package/renderer/components/docs-viewer/sidebar/collection-tree.tsx +0 -259
  322. package/renderer/components/docs-viewer/sidebar/endpoint-options.tsx +0 -316
  323. package/renderer/components/docs-viewer/sidebar/index.tsx +0 -282
  324. package/renderer/components/docs-viewer/sidebar/right-sidebar.tsx +0 -202
  325. package/renderer/components/docs-viewer/sidebar/sidebar-group.tsx +0 -118
  326. package/renderer/components/docs-viewer/sidebar/sidebar-item.tsx +0 -212
  327. package/renderer/components/docs-viewer/sidebar/sidebar-section.tsx +0 -38
  328. package/renderer/components/theme-provider.tsx +0 -11
  329. package/renderer/components/theme-toggle.tsx +0 -76
  330. package/renderer/components/ui/badge.tsx +0 -46
  331. package/renderer/components/ui/button.tsx +0 -59
  332. package/renderer/components/ui/dialog.tsx +0 -118
  333. package/renderer/components/ui/dropdown-menu.tsx +0 -257
  334. package/renderer/components/ui/input.tsx +0 -21
  335. package/renderer/components/ui/label.tsx +0 -24
  336. package/renderer/components/ui/navigation-menu.tsx +0 -168
  337. package/renderer/components/ui/select.tsx +0 -190
  338. package/renderer/components/ui/spinner.tsx +0 -114
  339. package/renderer/components/ui/tabs.tsx +0 -66
  340. package/renderer/components/ui/tooltip.tsx +0 -61
  341. package/renderer/hooks/use-code-copy.ts +0 -88
  342. package/renderer/hooks/use-openapi-title.ts +0 -44
  343. package/renderer/lib/api-docs/agent/index.ts +0 -6
  344. package/renderer/lib/api-docs/agent/indexer.ts +0 -323
  345. package/renderer/lib/api-docs/agent/spec-summary.ts +0 -335
  346. package/renderer/lib/api-docs/agent/types.ts +0 -116
  347. package/renderer/lib/api-docs/auth/auth-context.tsx +0 -225
  348. package/renderer/lib/api-docs/auth/auth-storage.ts +0 -87
  349. package/renderer/lib/api-docs/auth/crypto.ts +0 -89
  350. package/renderer/lib/api-docs/auth/index.ts +0 -4
  351. package/renderer/lib/api-docs/code-editor/db.ts +0 -164
  352. package/renderer/lib/api-docs/code-editor/hooks.ts +0 -266
  353. package/renderer/lib/api-docs/code-editor/mode-context.tsx +0 -207
  354. package/renderer/lib/api-docs/code-editor/types.ts +0 -105
  355. package/renderer/lib/api-docs/codegen/definitions.ts +0 -297
  356. package/renderer/lib/api-docs/codegen/har.ts +0 -251
  357. package/renderer/lib/api-docs/codegen/index.ts +0 -159
  358. package/renderer/lib/api-docs/factories.ts +0 -170
  359. package/renderer/lib/api-docs/mobile-context.tsx +0 -112
  360. package/renderer/lib/api-docs/navigation-context.tsx +0 -88
  361. package/renderer/lib/api-docs/parsers/graphql/README.md +0 -129
  362. package/renderer/lib/api-docs/parsers/graphql/index.ts +0 -91
  363. package/renderer/lib/api-docs/parsers/graphql/parser.ts +0 -491
  364. package/renderer/lib/api-docs/parsers/graphql/transformer.ts +0 -246
  365. package/renderer/lib/api-docs/parsers/graphql/types.ts +0 -283
  366. package/renderer/lib/api-docs/parsers/openapi/README.md +0 -32
  367. package/renderer/lib/api-docs/parsers/openapi/dereferencer.ts +0 -60
  368. package/renderer/lib/api-docs/parsers/openapi/extractors/auth.ts +0 -574
  369. package/renderer/lib/api-docs/parsers/openapi/extractors/body.ts +0 -403
  370. package/renderer/lib/api-docs/parsers/openapi/extractors/index.ts +0 -232
  371. package/renderer/lib/api-docs/parsers/openapi/index.ts +0 -171
  372. package/renderer/lib/api-docs/parsers/openapi/transformer.ts +0 -278
  373. package/renderer/lib/api-docs/parsers/openapi/validator.ts +0 -31
  374. package/renderer/lib/api-docs/playground/context.tsx +0 -107
  375. package/renderer/lib/api-docs/playground/navigation-context.tsx +0 -124
  376. package/renderer/lib/api-docs/playground/request-builder.ts +0 -223
  377. package/renderer/lib/api-docs/playground/request-runner.ts +0 -282
  378. package/renderer/lib/api-docs/playground/types.ts +0 -35
  379. package/renderer/lib/api-docs/types.ts +0 -269
  380. package/renderer/lib/api-docs/utils.ts +0 -311
  381. package/renderer/lib/cache.ts +0 -193
  382. package/renderer/lib/docs/config/domain-schema.ts +0 -260
  383. package/renderer/lib/docs/config/index.ts +0 -43
  384. package/renderer/lib/docs/config/loader.ts +0 -142
  385. package/renderer/lib/docs/config/schema.ts +0 -308
  386. package/renderer/lib/docs/index.ts +0 -12
  387. package/renderer/lib/docs/mdx/compiler.ts +0 -176
  388. package/renderer/lib/docs/mdx/frontmatter.ts +0 -91
  389. package/renderer/lib/docs/mdx/index.ts +0 -26
  390. package/renderer/lib/docs/navigation/generator.ts +0 -348
  391. package/renderer/lib/docs/navigation/index.ts +0 -12
  392. package/renderer/lib/docs/navigation/types.ts +0 -123
  393. package/renderer/lib/docs-navigation-context.tsx +0 -80
  394. package/renderer/lib/multi-tenant/context.ts +0 -105
  395. package/renderer/lib/storage/blob.ts +0 -1083
  396. package/renderer/lib/utils/icons.ts +0 -48
  397. package/renderer/lib/utils.ts +0 -6
  398. package/renderer/next.config.ts +0 -76
@@ -0,0 +1,47 @@
1
+ import { NextResponse } from 'next/server';
2
+ import { headers } from 'next/headers';
3
+ import { getProjectContent, projectExists } from '@/lib/storage/blob';
4
+ /**
5
+ * Debug endpoint to check multi-tenant routing
6
+ *
7
+ * GET /api/debug?slug=acme-api-docs-i2rjwv
8
+ */ export async function GET(request) {
9
+ const headersList = await headers();
10
+ const { searchParams } = new URL(request.url);
11
+ const testSlug = searchParams.get('slug');
12
+ // Collect all headers
13
+ const allHeaders = {};
14
+ headersList.forEach((value, key)=>{
15
+ allHeaders[key] = value;
16
+ });
17
+ // Check for project header
18
+ const projectSlug = headersList.get('x-devdoc-project');
19
+ // Test Blob storage if slug provided
20
+ let blobTest = null;
21
+ if (testSlug) {
22
+ try {
23
+ const exists = await projectExists(testSlug);
24
+ const content = exists ? await getProjectContent(testSlug) : null;
25
+ blobTest = {
26
+ slug: testSlug,
27
+ exists,
28
+ hasContent: !!content,
29
+ filesCount: content?.files?.length || 0,
30
+ projectName: content?.name || null
31
+ };
32
+ } catch (error) {
33
+ blobTest = {
34
+ slug: testSlug,
35
+ error: String(error)
36
+ };
37
+ }
38
+ }
39
+ return NextResponse.json({
40
+ timestamp: new Date().toISOString(),
41
+ host: headersList.get('host'),
42
+ projectSlug,
43
+ hasBlobToken: !!process.env.BLOB_READ_WRITE_TOKEN,
44
+ blobTest,
45
+ headers: allHeaders
46
+ });
47
+ }
@@ -0,0 +1,199 @@
1
+ import { NextResponse } from 'next/server';
2
+ import { storeProjectContent, updateProjectContent, projectExists, generateProjectSlug, generateApiKey, storeProjectApiKey, validateApiKey } from '@/lib/storage/blob';
3
+ import { getProjectUrl, isValidSlug } from '@/lib/multi-tenant/context';
4
+ /**
5
+ * Deploy API - receives content from CLI and stores in Vercel Blob
6
+ *
7
+ * POST /api/deploy
8
+ * Headers:
9
+ * Authorization: Bearer <api_key> // Required for updates
10
+ * Body: {
11
+ * name: string, // Project name from docs.json
12
+ * slug?: string, // Optional: existing slug for updates
13
+ * docsJson: object, // The docs.json configuration
14
+ * files: Array<{ // MDX and other content files
15
+ * path: string,
16
+ * content: string
17
+ * }>
18
+ * }
19
+ */ export async function POST(request) {
20
+ try {
21
+ const body = await request.json();
22
+ // Validate request body
23
+ const { name, slug: existingSlug, docsJson, files } = body;
24
+ if (!name || typeof name !== 'string') {
25
+ return NextResponse.json({
26
+ error: 'Missing or invalid project name'
27
+ }, {
28
+ status: 400
29
+ });
30
+ }
31
+ if (!docsJson || typeof docsJson !== 'object') {
32
+ return NextResponse.json({
33
+ error: 'Missing or invalid docs.json configuration'
34
+ }, {
35
+ status: 400
36
+ });
37
+ }
38
+ if (!files || !Array.isArray(files)) {
39
+ return NextResponse.json({
40
+ error: 'Missing or invalid files array'
41
+ }, {
42
+ status: 400
43
+ });
44
+ }
45
+ // Validate files structure
46
+ const validFiles = [];
47
+ for (const file of files){
48
+ if (!file.path || typeof file.path !== 'string') {
49
+ return NextResponse.json({
50
+ error: `Invalid file entry: missing path`
51
+ }, {
52
+ status: 400
53
+ });
54
+ }
55
+ if (typeof file.content !== 'string') {
56
+ return NextResponse.json({
57
+ error: `Invalid file entry for ${file.path}: content must be a string`
58
+ }, {
59
+ status: 400
60
+ });
61
+ }
62
+ validFiles.push({
63
+ path: file.path,
64
+ content: file.content
65
+ });
66
+ }
67
+ let slug;
68
+ let isUpdate = false;
69
+ let apiKey = null;
70
+ // Check if this is an update to an existing project
71
+ if (existingSlug) {
72
+ if (!isValidSlug(existingSlug)) {
73
+ return NextResponse.json({
74
+ error: 'Invalid project slug format'
75
+ }, {
76
+ status: 400
77
+ });
78
+ }
79
+ const exists = await projectExists(existingSlug);
80
+ if (!exists) {
81
+ return NextResponse.json({
82
+ error: `Project with slug "${existingSlug}" not found`
83
+ }, {
84
+ status: 404
85
+ });
86
+ }
87
+ // For updates, validate API key
88
+ const authHeader = request.headers.get('Authorization');
89
+ const providedKey = authHeader?.replace('Bearer ', '') || body.apiKey;
90
+ if (!providedKey) {
91
+ return NextResponse.json({
92
+ error: 'API key required for project updates. Provide via Authorization header or apiKey field.'
93
+ }, {
94
+ status: 401
95
+ });
96
+ }
97
+ const validatedSlug = await validateApiKey(providedKey);
98
+ if (validatedSlug !== existingSlug) {
99
+ return NextResponse.json({
100
+ error: 'Invalid API key for this project'
101
+ }, {
102
+ status: 403
103
+ });
104
+ }
105
+ slug = existingSlug;
106
+ isUpdate = true;
107
+ } else {
108
+ // Generate a new unique slug
109
+ slug = generateProjectSlug(name);
110
+ // Ensure it doesn't already exist (very unlikely but possible)
111
+ let attempts = 0;
112
+ while(await projectExists(slug) && attempts < 5){
113
+ slug = generateProjectSlug(name);
114
+ attempts++;
115
+ }
116
+ if (attempts >= 5) {
117
+ return NextResponse.json({
118
+ error: 'Failed to generate unique project slug'
119
+ }, {
120
+ status: 500
121
+ });
122
+ }
123
+ // Generate API key for new project
124
+ apiKey = generateApiKey();
125
+ }
126
+ // Store or update content
127
+ let result;
128
+ if (isUpdate) {
129
+ result = await updateProjectContent(slug, docsJson, validFiles);
130
+ } else {
131
+ result = await storeProjectContent(slug, name, docsJson, validFiles);
132
+ // Store the API key for new projects
133
+ if (apiKey) {
134
+ await storeProjectApiKey(slug, apiKey);
135
+ }
136
+ }
137
+ // Build response
138
+ const projectUrl = getProjectUrl(slug);
139
+ // For new projects, include the API key in response
140
+ const response = {
141
+ success: true,
142
+ slug,
143
+ url: projectUrl,
144
+ blobUrl: result.url,
145
+ isUpdate,
146
+ filesCount: validFiles.length
147
+ };
148
+ if (apiKey) {
149
+ response.apiKey = apiKey;
150
+ }
151
+ return NextResponse.json(response);
152
+ } catch (error) {
153
+ console.error('[Deploy API] Error:', error);
154
+ const message = error instanceof Error ? error.message : String(error);
155
+ // Provide clearer error messages for common issues
156
+ let userMessage = 'Deployment failed';
157
+ if (message.includes('blob already exists')) {
158
+ userMessage = 'Storage conflict - please try again';
159
+ } else if (message.includes('network') || message.includes('fetch')) {
160
+ userMessage = 'Network error connecting to storage';
161
+ } else if (message.includes('unauthorized') || message.includes('401')) {
162
+ userMessage = 'Authentication failed';
163
+ }
164
+ return NextResponse.json({
165
+ error: userMessage,
166
+ details: message
167
+ }, {
168
+ status: 500
169
+ });
170
+ }
171
+ }
172
+ /**
173
+ * GET /api/deploy - Check deployment status or get project info
174
+ */ export async function GET(request) {
175
+ const { searchParams } = new URL(request.url);
176
+ const slug = searchParams.get('slug');
177
+ if (!slug) {
178
+ return NextResponse.json({
179
+ error: 'Missing slug parameter'
180
+ }, {
181
+ status: 400
182
+ });
183
+ }
184
+ const exists = await projectExists(slug);
185
+ if (!exists) {
186
+ return NextResponse.json({
187
+ exists: false,
188
+ slug
189
+ }, {
190
+ status: 404
191
+ });
192
+ }
193
+ const projectUrl = getProjectUrl(slug);
194
+ return NextResponse.json({
195
+ exists: true,
196
+ slug,
197
+ url: projectUrl
198
+ });
199
+ }
@@ -0,0 +1,36 @@
1
+ import { NextResponse } from 'next/server';
2
+ import { cookies } from 'next/headers';
3
+ const DEVICE_COOKIE_NAME = 'bf_device_id';
4
+ const COOKIE_MAX_AGE = 60 * 60 * 24 * 365 // 1 year
5
+ ;
6
+ /**
7
+ * Generate a unique device ID
8
+ * Uses crypto.randomUUID for secure random generation
9
+ */ function generateDeviceId() {
10
+ return crypto.randomUUID();
11
+ }
12
+ /**
13
+ * GET /api/device
14
+ * Returns or creates a unique device ID for the client
15
+ * The device ID is stored in an httpOnly cookie for security
16
+ */ export async function GET() {
17
+ const cookieStore = await cookies();
18
+ let deviceId = cookieStore.get(DEVICE_COOKIE_NAME)?.value;
19
+ // Generate new device ID if not exists
20
+ if (!deviceId) {
21
+ deviceId = generateDeviceId();
22
+ }
23
+ // Create response with device ID
24
+ const response = NextResponse.json({
25
+ deviceId
26
+ });
27
+ // Set/refresh the httpOnly cookie
28
+ response.cookies.set(DEVICE_COOKIE_NAME, deviceId, {
29
+ httpOnly: true,
30
+ secure: process.env.NODE_ENV === 'production',
31
+ sameSite: 'strict',
32
+ maxAge: COOKIE_MAX_AGE,
33
+ path: '/'
34
+ });
35
+ return response;
36
+ }
@@ -0,0 +1,205 @@
1
+ import { NextResponse } from 'next/server';
2
+ import { readFileSync, existsSync } from 'fs';
3
+ import { join, isAbsolute } from 'path';
4
+ import matter from 'gray-matter';
5
+ import { serialize } from 'next-mdx-remote/serialize';
6
+ import remarkGfm from 'remark-gfm';
7
+ import rehypeSlug from 'rehype-slug';
8
+ // Note: rehype-pretty-code is dynamically imported to handle serverless environments
9
+ // where shiki may not be fully available
10
+ import { getProjectFile } from '@/lib/storage/blob';
11
+ const STARTER_PATH = process.env.STARTER_PATH || 'devdoc-docs';
12
+ // Helper to get content root - supports both relative and absolute paths
13
+ function getContentRoot() {
14
+ if (isAbsolute(STARTER_PATH)) {
15
+ return STARTER_PATH;
16
+ }
17
+ return join(process.cwd(), STARTER_PATH);
18
+ }
19
+ // Shiki theme options for syntax highlighting
20
+ const prettyCodeOptions = {
21
+ theme: 'github-dark',
22
+ keepBackground: true,
23
+ defaultLang: 'plaintext'
24
+ };
25
+ export async function GET(request) {
26
+ const searchParams = request.nextUrl.searchParams;
27
+ const slug = searchParams.get('slug');
28
+ const is404Request = searchParams.get('is404') === 'true';
29
+ if (!slug) {
30
+ return NextResponse.json({
31
+ error: 'Missing slug parameter'
32
+ }, {
33
+ status: 400
34
+ });
35
+ }
36
+ // Check for multi-tenant mode (project slug from middleware)
37
+ const projectSlug = request.headers.get('x-devdoc-project');
38
+ // If multi-tenant, fetch from Blob Storage
39
+ if (projectSlug && !projectSlug.startsWith('custom:')) {
40
+ return handleMultiTenantDocs(projectSlug, slug, is404Request);
41
+ }
42
+ try {
43
+ const starterDir = getContentRoot();
44
+ // Try .mdx then .md
45
+ let fullPath = join(starterDir, `${slug}.mdx`);
46
+ if (!existsSync(fullPath)) {
47
+ fullPath = join(starterDir, `${slug}.md`);
48
+ }
49
+ if (!existsSync(fullPath)) {
50
+ // For 404 page requests, return 404 status (not a server error)
51
+ // The client will handle showing the default 404 if custom doesn't exist
52
+ return NextResponse.json({
53
+ error: 'Page not found'
54
+ }, {
55
+ status: 404
56
+ });
57
+ }
58
+ const fileContent = readFileSync(fullPath, 'utf-8');
59
+ const { data: frontmatter, content } = matter(fileContent);
60
+ // Serialize MDX for client-side rendering
61
+ // Note: rehype-pretty-code is dynamically imported to handle cases where shiki
62
+ // may not be available in serverless environments
63
+ let mdxSource;
64
+ try {
65
+ // Try with syntax highlighting first
66
+ const rehypePrettyCodeModule = await import('rehype-pretty-code');
67
+ const rehypePrettyCode = rehypePrettyCodeModule.default;
68
+ mdxSource = await serialize(content, {
69
+ mdxOptions: {
70
+ remarkPlugins: [
71
+ remarkGfm
72
+ ],
73
+ rehypePlugins: [
74
+ rehypeSlug,
75
+ [
76
+ rehypePrettyCode,
77
+ prettyCodeOptions
78
+ ]
79
+ ]
80
+ },
81
+ parseFrontmatter: false
82
+ });
83
+ } catch (syntaxError) {
84
+ // Fallback: serialize without syntax highlighting if shiki is unavailable
85
+ console.warn('[Docs API] Syntax highlighting unavailable, using fallback:', syntaxError);
86
+ mdxSource = await serialize(content, {
87
+ mdxOptions: {
88
+ remarkPlugins: [
89
+ remarkGfm
90
+ ],
91
+ rehypePlugins: [
92
+ rehypeSlug
93
+ ]
94
+ },
95
+ parseFrontmatter: false
96
+ });
97
+ }
98
+ return NextResponse.json({
99
+ slug,
100
+ frontmatter: {
101
+ title: frontmatter.title || slug,
102
+ description: frontmatter.description,
103
+ icon: frontmatter.icon,
104
+ // Page mode and layout options
105
+ mode: frontmatter.mode || 'default',
106
+ hideHeader: frontmatter.hideHeader || false,
107
+ fullWidth: frontmatter.fullWidth || false,
108
+ background: frontmatter.background
109
+ },
110
+ mdxSource,
111
+ rawContent: content
112
+ });
113
+ } catch (error) {
114
+ console.error('[Docs API] Error loading page:', error);
115
+ return NextResponse.json({
116
+ error: 'Failed to load page',
117
+ details: error instanceof Error ? error.message : String(error)
118
+ }, {
119
+ status: 500
120
+ });
121
+ }
122
+ }
123
+ /**
124
+ * Handle multi-tenant docs request - fetch from Blob Storage
125
+ */ async function handleMultiTenantDocs(projectSlug, slug, is404Request = false) {
126
+ try {
127
+ // Try .mdx then .md
128
+ let fileContent = await getProjectFile(projectSlug, `${slug}.mdx`);
129
+ if (!fileContent) {
130
+ fileContent = await getProjectFile(projectSlug, `${slug}.md`);
131
+ }
132
+ if (!fileContent) {
133
+ // For 404 page requests, return 404 status
134
+ return NextResponse.json({
135
+ error: 'Page not found'
136
+ }, {
137
+ status: 404
138
+ });
139
+ }
140
+ const { data: frontmatter, content } = matter(fileContent);
141
+ // Serialize MDX for client-side rendering
142
+ // Note: rehype-pretty-code is dynamically imported to handle cases where shiki
143
+ // may not be available in serverless environments
144
+ let mdxSource;
145
+ try {
146
+ // Try with syntax highlighting first
147
+ const rehypePrettyCodeModule = await import('rehype-pretty-code');
148
+ const rehypePrettyCode = rehypePrettyCodeModule.default;
149
+ mdxSource = await serialize(content, {
150
+ mdxOptions: {
151
+ remarkPlugins: [
152
+ remarkGfm
153
+ ],
154
+ rehypePlugins: [
155
+ rehypeSlug,
156
+ [
157
+ rehypePrettyCode,
158
+ prettyCodeOptions
159
+ ]
160
+ ]
161
+ },
162
+ parseFrontmatter: false
163
+ });
164
+ } catch (syntaxError) {
165
+ // Fallback: serialize without syntax highlighting if shiki is unavailable
166
+ console.warn('[Docs API] Multi-tenant syntax highlighting unavailable:', syntaxError);
167
+ mdxSource = await serialize(content, {
168
+ mdxOptions: {
169
+ remarkPlugins: [
170
+ remarkGfm
171
+ ],
172
+ rehypePlugins: [
173
+ rehypeSlug
174
+ ]
175
+ },
176
+ parseFrontmatter: false
177
+ });
178
+ }
179
+ return NextResponse.json({
180
+ slug,
181
+ frontmatter: {
182
+ title: frontmatter.title || slug,
183
+ description: frontmatter.description,
184
+ icon: frontmatter.icon,
185
+ // Page mode and layout options
186
+ mode: frontmatter.mode || 'default',
187
+ hideHeader: frontmatter.hideHeader || false,
188
+ fullWidth: frontmatter.fullWidth || false,
189
+ background: frontmatter.background
190
+ },
191
+ mdxSource,
192
+ rawContent: content,
193
+ isMultiTenant: true,
194
+ projectSlug
195
+ });
196
+ } catch (error) {
197
+ console.error('[Docs API] Multi-tenant error:', error);
198
+ return NextResponse.json({
199
+ error: 'Failed to load page',
200
+ details: error instanceof Error ? error.message : String(error)
201
+ }, {
202
+ status: 500
203
+ });
204
+ }
205
+ }
@@ -0,0 +1,121 @@
1
+ import { NextResponse } from 'next/server';
2
+ import { validateApiKey, addCustomDomain, isCustomDomainRegistered } from '@/lib/storage/blob';
3
+ import { isValidDomain, normalizeDomain, getDnsInstructions } from '@/lib/docs/config';
4
+ /**
5
+ * POST /api/domains/add
6
+ *
7
+ * Add a custom domain to a project.
8
+ * Each project can have ONE custom domain (free).
9
+ *
10
+ * Headers:
11
+ * Authorization: Bearer <api_key>
12
+ *
13
+ * Body:
14
+ * { customDomain: "docs.example.com" }
15
+ *
16
+ * Response:
17
+ * {
18
+ * success: true,
19
+ * domain: "docs.example.com",
20
+ * status: "pending",
21
+ * verification: {
22
+ * cname: { name: "docs", value: "cname.devdoc-dns.com" },
23
+ * txt: { name: "_devdoc-verify.docs.example.com", value: "devdoc-verify=xxx" }
24
+ * }
25
+ * }
26
+ */ export async function POST(request) {
27
+ try {
28
+ // Validate API key
29
+ const authHeader = request.headers.get('Authorization');
30
+ const apiKey = authHeader?.replace('Bearer ', '');
31
+ if (!apiKey) {
32
+ return NextResponse.json({
33
+ error: 'API key required. Provide via Authorization header.'
34
+ }, {
35
+ status: 401
36
+ });
37
+ }
38
+ const projectSlug = await validateApiKey(apiKey);
39
+ if (!projectSlug) {
40
+ return NextResponse.json({
41
+ error: 'Invalid API key'
42
+ }, {
43
+ status: 403
44
+ });
45
+ }
46
+ // Parse request body
47
+ const body = await request.json();
48
+ const { customDomain: rawDomain } = body;
49
+ if (!rawDomain || typeof rawDomain !== 'string') {
50
+ return NextResponse.json({
51
+ error: 'Missing customDomain in request body'
52
+ }, {
53
+ status: 400
54
+ });
55
+ }
56
+ // Normalize and validate domain
57
+ const customDomain = normalizeDomain(rawDomain);
58
+ const validation = isValidDomain(customDomain);
59
+ if (!validation.valid) {
60
+ return NextResponse.json({
61
+ error: validation.error
62
+ }, {
63
+ status: 400
64
+ });
65
+ }
66
+ // Check if domain is already registered
67
+ const isRegistered = await isCustomDomainRegistered(customDomain);
68
+ if (isRegistered) {
69
+ return NextResponse.json({
70
+ error: `Domain ${customDomain} is already registered to another project.`
71
+ }, {
72
+ status: 409
73
+ });
74
+ }
75
+ // Add the custom domain
76
+ const result = await addCustomDomain(projectSlug, customDomain);
77
+ if (!result.success) {
78
+ return NextResponse.json({
79
+ error: result.error
80
+ }, {
81
+ status: 400
82
+ });
83
+ }
84
+ // Get DNS instructions
85
+ const dnsInstructions = getDnsInstructions(customDomain);
86
+ // Add verification token to TXT record
87
+ dnsInstructions.txt.value = result.entry.verificationToken || '';
88
+ return NextResponse.json({
89
+ success: true,
90
+ domain: customDomain,
91
+ projectSlug,
92
+ status: result.entry.status,
93
+ verification: {
94
+ cname: dnsInstructions.cname,
95
+ txt: dnsInstructions.txt
96
+ },
97
+ instructions: [
98
+ 'Add the following DNS records to your domain:',
99
+ '',
100
+ `1. CNAME Record:`,
101
+ ` Name: ${dnsInstructions.cname.name}`,
102
+ ` Value: ${dnsInstructions.cname.value}`,
103
+ '',
104
+ `2. TXT Record (for verification):`,
105
+ ` Name: ${dnsInstructions.txt.name}`,
106
+ ` Value: ${dnsInstructions.txt.value}`,
107
+ '',
108
+ 'After adding DNS records, run "devdoc domain verify" to verify.'
109
+ ]
110
+ });
111
+ } catch (error) {
112
+ console.error('[Domains API] Error adding domain:', error);
113
+ const message = error instanceof Error ? error.message : String(error);
114
+ return NextResponse.json({
115
+ error: 'Failed to add domain',
116
+ details: message
117
+ }, {
118
+ status: 500
119
+ });
120
+ }
121
+ }
@@ -0,0 +1,43 @@
1
+ import { NextResponse } from 'next/server';
2
+ import { lookupCustomDomain } from '@/lib/storage/blob';
3
+ /**
4
+ * GET /api/domains/lookup
5
+ *
6
+ * Internal API for middleware to look up custom domains.
7
+ * Returns the project slug for an active custom domain.
8
+ *
9
+ * Query:
10
+ * ?domain=docs.example.com
11
+ *
12
+ * Response:
13
+ * { found: true, projectSlug: "my-project" }
14
+ * or
15
+ * { found: false }
16
+ */ export async function GET(request) {
17
+ try {
18
+ const { searchParams } = new URL(request.url);
19
+ const domain = searchParams.get('domain');
20
+ if (!domain) {
21
+ return NextResponse.json({
22
+ found: false,
23
+ error: 'Missing domain parameter'
24
+ });
25
+ }
26
+ const entry = await lookupCustomDomain(domain);
27
+ if (entry) {
28
+ return NextResponse.json({
29
+ found: true,
30
+ projectSlug: entry.projectSlug,
31
+ status: entry.status
32
+ });
33
+ }
34
+ return NextResponse.json({
35
+ found: false
36
+ });
37
+ } catch (error) {
38
+ console.error('[Domains Lookup] Error:', error);
39
+ return NextResponse.json({
40
+ found: false
41
+ });
42
+ }
43
+ }