@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,193 @@
1
+ /**
2
+ * Universal caching utility that works in both local and production environments
3
+ *
4
+ * - Local development: Uses node-cache (in-memory)
5
+ * - Production (Vercel): Uses Vercel KV
6
+ *
7
+ * Environment-based cache selection:
8
+ * 1. Explicit override: CACHE_TYPE=local or CACHE_TYPE=kv
9
+ * 2. Auto-detect: KV_REST_API_URL or KV_URL present → Uses Vercel KV
10
+ * 3. Fallback: Uses local node-cache
11
+ *
12
+ * Example usage:
13
+ * ```typescript
14
+ * import { CacheUtils } from '@/utils/cache';
15
+ *
16
+ * // Get from cache
17
+ * const cached = await CacheUtils.get<MyType>('my-key', { logHit: true });
18
+ *
19
+ * // Set with TTL
20
+ * await CacheUtils.set('my-key', data, 3600, { log: true }); // 1 hour TTL
21
+ *
22
+ * // Delete
23
+ * await CacheUtils.del('my-key', { log: true });
24
+ * ```
25
+ */
26
+
27
+ import NodeCache from 'node-cache';
28
+ import { kv } from '@vercel/kv';
29
+
30
+ /**
31
+ * Cache environment configuration
32
+ */
33
+ const CACHE_CONFIG = {
34
+ // Environment variables that indicate KV should be used
35
+ KV_INDICATORS: ['KV_REST_API_URL', 'KV_URL'] as const,
36
+
37
+ // Allow explicit override via CACHE_TYPE env var
38
+ CACHE_TYPE: process.env.CACHE_TYPE as 'local' | 'kv' | undefined,
39
+ } as const;
40
+
41
+ /**
42
+ * Determine cache type based on environment variables
43
+ */
44
+ function getCacheType(): 'local' | 'kv' {
45
+ // Explicit override takes precedence
46
+ if (CACHE_CONFIG.CACHE_TYPE === 'local') {
47
+ return 'local';
48
+ }
49
+
50
+ if (CACHE_CONFIG.CACHE_TYPE === 'kv') {
51
+ return 'kv';
52
+ }
53
+
54
+ // Auto-detect based on KV environment variables
55
+ const hasKVConfig = CACHE_CONFIG.KV_INDICATORS.some(
56
+ (envVar) => !!process.env[envVar]
57
+ );
58
+
59
+ return hasKVConfig ? 'kv' : 'local';
60
+ }
61
+
62
+ // Determine cache type at module load time
63
+ const cacheType = getCacheType();
64
+
65
+ // Initialize cache backends based on environment
66
+ let localCache: NodeCache | null = null;
67
+
68
+ if (cacheType === 'kv') {
69
+ console.log('[Cache] Using Vercel KV cache');
70
+ } else {
71
+ console.log('[Cache] Using local node-cache');
72
+ localCache = new NodeCache({
73
+ stdTTL: 60 * 60 * 24, // Default 24 hours TTL
74
+ checkperiod: 60 * 10, // Check for expired keys every 10 minutes
75
+ useClones: false, // Better performance, but be careful with object mutations
76
+ });
77
+ }
78
+
79
+ /**
80
+ * Universal cache utility functions
81
+ */
82
+ export class CacheUtils {
83
+ /**
84
+ * Get a value from cache with optional logging
85
+ */
86
+ static async get<T = unknown>(
87
+ key: string,
88
+ options?: { logHit?: boolean }
89
+ ): Promise<T | null> {
90
+ try {
91
+ let value: T | undefined;
92
+
93
+ if (cacheType === 'kv') {
94
+ value = await kv.get(key) as T | undefined;
95
+ } else {
96
+ value = localCache?.get<T>(key);
97
+ }
98
+
99
+ // Fix: Only return null for missing keys (undefined), not for falsy values
100
+ const result = value !== undefined ? value : null;
101
+
102
+ if (options?.logHit) {
103
+ if (result !== null) {
104
+ console.log(`[Cache] HIT: ${key}`);
105
+ } else {
106
+ console.log(`[Cache] MISS: ${key}`);
107
+ }
108
+ }
109
+
110
+ return result;
111
+ } catch (error) {
112
+ console.warn(`[Cache] Get error for key "${key}":`, error);
113
+ return null;
114
+ }
115
+ }
116
+
117
+ /**
118
+ * Set a value in cache with TTL and logging
119
+ */
120
+ static async set<T = unknown>(
121
+ key: string,
122
+ value: T,
123
+ ttlSeconds?: number,
124
+ options?: { log?: boolean }
125
+ ): Promise<void> {
126
+ try {
127
+ if (cacheType === 'kv') {
128
+ if (ttlSeconds) {
129
+ await kv.set(key, value, { ex: ttlSeconds });
130
+ } else {
131
+ await kv.set(key, value);
132
+ }
133
+ } else {
134
+ const ttl = ttlSeconds || 60 * 60 * 24; // Default to 24 hours
135
+ localCache?.set(key, value, ttl);
136
+ }
137
+
138
+ if (options?.log) {
139
+ const ttlInfo = ttlSeconds ? ` (TTL: ${ttlSeconds}s)` : '';
140
+ console.log(`[Cache] SET: ${key}${ttlInfo}`);
141
+ }
142
+ } catch (error) {
143
+ console.warn(`[Cache] Set error for key "${key}":`, error);
144
+ }
145
+ }
146
+
147
+ /**
148
+ * Delete a key from cache
149
+ */
150
+ static async del(key: string, options?: { log?: boolean }): Promise<void> {
151
+ try {
152
+ if (cacheType === 'kv') {
153
+ await kv.del(key);
154
+ } else {
155
+ localCache?.del(key);
156
+ }
157
+
158
+ if (options?.log) {
159
+ console.log(`[Cache] DEL: ${key}`);
160
+ }
161
+ } catch (error) {
162
+ console.warn(`[Cache] Delete error for key "${key}":`, error);
163
+ }
164
+ }
165
+
166
+ /**
167
+ * Clear all cache entries (use with caution!)
168
+ */
169
+ static async clear(): Promise<void> {
170
+ try {
171
+ if (cacheType === 'kv') {
172
+ await kv.flushdb();
173
+ } else {
174
+ localCache?.flushAll();
175
+ }
176
+ console.log('[Cache] Cleared all entries');
177
+ } catch (error) {
178
+ console.warn('[Cache] Clear error:', error);
179
+ }
180
+ }
181
+
182
+ /**
183
+ * Get current cache type for debugging/monitoring
184
+ */
185
+ static getCacheType(): 'local' | 'kv' {
186
+ return cacheType;
187
+ }
188
+ }
189
+
190
+ // Legacy exports for backward compatibility
191
+ export const cache = CacheUtils;
192
+ export { cacheType };
193
+ export default CacheUtils;
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Configuration Module Exports
3
+ */
4
+
5
+ export {
6
+ docsConfigSchema,
7
+ parseDocsConfig,
8
+ safeParseDocsConfig,
9
+ getDefaultDocsConfig,
10
+ type DocsConfig,
11
+ type NavigationTab,
12
+ type NavigationGroup,
13
+ type NavLink,
14
+ type Anchor,
15
+ type ColorConfig,
16
+ type LogoConfig,
17
+ type ApiConfig,
18
+ } from './schema'
19
+
20
+ export {
21
+ loadDocsConfig,
22
+ safeLoadDocsConfig,
23
+ clearConfigCache,
24
+ hasDocsConfig,
25
+ getContentDir,
26
+ resolvePagePath,
27
+ loadPageContent,
28
+ listMdxFiles,
29
+ } from './loader'
@@ -0,0 +1,142 @@
1
+ import { readFileSync, existsSync, readdirSync } from 'fs'
2
+ import { join } from 'path'
3
+ import { parseDocsConfig, type DocsConfig } from './schema'
4
+
5
+ /**
6
+ * Configuration Loader
7
+ *
8
+ * Utilities for loading and caching docs.json configuration
9
+ * Uses synchronous fs operations for compatibility with Next.js Turbopack
10
+ */
11
+
12
+ // Cache for loaded configuration
13
+ let configCache: DocsConfig | null = null
14
+ let configCachePath: string | null = null
15
+
16
+ /**
17
+ * Load docs.json configuration from a directory
18
+ */
19
+ export function loadDocsConfig(docsDir: string): DocsConfig {
20
+ const configFilePath = join(docsDir, 'docs.json')
21
+
22
+ // Return cached config if path matches
23
+ if (configCache && configCachePath === configFilePath) {
24
+ return configCache
25
+ }
26
+
27
+ try {
28
+ if (!existsSync(configFilePath)) {
29
+ throw new Error(`docs.json not found at ${configFilePath}`)
30
+ }
31
+
32
+ const configContent = readFileSync(configFilePath, 'utf-8')
33
+ const rawConfig = JSON.parse(configContent)
34
+ const config = parseDocsConfig(rawConfig)
35
+
36
+ // Cache the result
37
+ configCache = config
38
+ configCachePath = configFilePath
39
+
40
+ return config
41
+ } catch (error) {
42
+ if (error instanceof Error) {
43
+ throw new Error(`Failed to load docs.json: ${error.message}`)
44
+ }
45
+ throw error
46
+ }
47
+ }
48
+
49
+ /**
50
+ * Load configuration without throwing (returns null on failure)
51
+ */
52
+ export function safeLoadDocsConfig(docsDir: string): DocsConfig | null {
53
+ try {
54
+ return loadDocsConfig(docsDir)
55
+ } catch {
56
+ return null
57
+ }
58
+ }
59
+
60
+ /**
61
+ * Clear the configuration cache
62
+ */
63
+ export function clearConfigCache(): void {
64
+ configCache = null
65
+ configCachePath = null
66
+ }
67
+
68
+ /**
69
+ * Check if a docs.json file exists in a directory
70
+ */
71
+ export function hasDocsConfig(docsDir: string): boolean {
72
+ return existsSync(join(docsDir, 'docs.json'))
73
+ }
74
+
75
+ /**
76
+ * Get the content directory path from configuration
77
+ */
78
+ export function getContentDir(docsDir: string): string {
79
+ return docsDir
80
+ }
81
+
82
+ /**
83
+ * Resolve a page path to a file path
84
+ */
85
+ export function resolvePagePath(
86
+ docsDir: string,
87
+ pagePath: string
88
+ ): string | null {
89
+ const contentDir = getContentDir(docsDir)
90
+ const extensions = ['.mdx', '.md']
91
+
92
+ // Try different extensions
93
+ for (const ext of extensions) {
94
+ const filePath = join(contentDir, `${pagePath}${ext}`)
95
+ if (existsSync(filePath)) {
96
+ return filePath
97
+ }
98
+ }
99
+
100
+ // Try as directory with index file
101
+ for (const ext of extensions) {
102
+ const indexPath = join(contentDir, pagePath, `index${ext}`)
103
+ if (existsSync(indexPath)) {
104
+ return indexPath
105
+ }
106
+ }
107
+
108
+ return null
109
+ }
110
+
111
+ /**
112
+ * Load page content from a resolved path
113
+ */
114
+ export function loadPageContent(filePath: string): string {
115
+ return readFileSync(filePath, 'utf-8')
116
+ }
117
+
118
+ /**
119
+ * List all MDX files in a directory recursively
120
+ */
121
+ export function listMdxFiles(dir: string): string[] {
122
+ const files: string[] = []
123
+
124
+ function walk(currentDir: string) {
125
+ const entries = readdirSync(currentDir, { withFileTypes: true })
126
+
127
+ for (const entry of entries) {
128
+ const fullPath = join(currentDir, entry.name)
129
+
130
+ if (entry.isDirectory()) {
131
+ if (!entry.name.startsWith('.') && entry.name !== 'node_modules') {
132
+ walk(fullPath)
133
+ }
134
+ } else if (entry.isFile() && (entry.name.endsWith('.mdx') || entry.name.endsWith('.md'))) {
135
+ files.push(fullPath)
136
+ }
137
+ }
138
+ }
139
+
140
+ walk(dir)
141
+ return files
142
+ }
@@ -0,0 +1,298 @@
1
+ import { z } from 'zod'
2
+
3
+ /**
4
+ * Documentation Configuration Schema (docs.json)
5
+ *
6
+ * Mintlify-compatible configuration schema for documentation sites.
7
+ */
8
+
9
+ // ============================================================================
10
+ // Navigation Schemas
11
+ // ============================================================================
12
+
13
+ const anchorSchema = z.object({
14
+ anchor: z.string(),
15
+ href: z.string(),
16
+ icon: z.string().optional(),
17
+ })
18
+
19
+ const navLinkSchema = z.object({
20
+ label: z.string(),
21
+ href: z.string(),
22
+ })
23
+
24
+ // Page can be a string or a nested group
25
+ const pageRefSchema: z.ZodType<string | { group: string; pages: (string | object)[] }> = z.lazy(() =>
26
+ z.union([
27
+ z.string(), // Page path like "quickstart" or "guides/intro"
28
+ z.object({ // Nested group
29
+ group: z.string(),
30
+ pages: z.array(z.union([z.string(), z.lazy(() => pageRefSchema)])),
31
+ }),
32
+ ])
33
+ )
34
+
35
+ const groupSchema = z.object({
36
+ group: z.string(),
37
+ pages: z.array(pageRefSchema),
38
+ icon: z.string().optional(),
39
+ })
40
+
41
+ // OpenAPI version schema
42
+ const openapiVersionSchema = z.object({
43
+ version: z.string(),
44
+ spec: z.string(),
45
+ default: z.boolean().optional(),
46
+ })
47
+
48
+ // Different tab types
49
+ const docsTabSchema = z.object({
50
+ tab: z.string(),
51
+ type: z.literal('docs').optional(),
52
+ groups: z.array(groupSchema),
53
+ })
54
+
55
+ const openapiTabSchema = z.object({
56
+ tab: z.string(),
57
+ type: z.literal('openapi'),
58
+ path: z.string().optional(),
59
+ versions: z.array(openapiVersionSchema).optional(),
60
+ spec: z.string().optional(),
61
+ })
62
+
63
+ const changelogTabSchema = z.object({
64
+ tab: z.string(),
65
+ type: z.literal('changelog'),
66
+ path: z.string().optional(),
67
+ })
68
+
69
+ const tabSchema = z.union([docsTabSchema, openapiTabSchema, changelogTabSchema])
70
+
71
+ const navigationSchema = z.object({
72
+ tabs: z.array(tabSchema).optional(),
73
+ groups: z.array(groupSchema).optional(), // For single-tab sites
74
+ global: z.object({
75
+ anchors: z.array(anchorSchema).optional(),
76
+ }).optional(),
77
+ })
78
+
79
+ // ============================================================================
80
+ // Theme & Branding Schemas
81
+ // ============================================================================
82
+
83
+ const colorSchema = z.object({
84
+ primary: z.string(),
85
+ light: z.string().optional(),
86
+ dark: z.string().optional(),
87
+ background: z.object({
88
+ light: z.string().optional(),
89
+ dark: z.string().optional(),
90
+ }).optional(),
91
+ })
92
+
93
+ const logoSchema = z.object({
94
+ light: z.string(),
95
+ dark: z.string(),
96
+ href: z.string().optional(),
97
+ })
98
+
99
+ const faviconSchema = z.string()
100
+
101
+ // ============================================================================
102
+ // Navbar Schema
103
+ // ============================================================================
104
+
105
+ const navbarPrimarySchema = z.object({
106
+ type: z.enum(['button', 'github', 'link']),
107
+ label: z.string().optional(),
108
+ href: z.string(),
109
+ })
110
+
111
+ const navbarSchema = z.object({
112
+ links: z.array(navLinkSchema).optional(),
113
+ primary: navbarPrimarySchema.optional(),
114
+ })
115
+
116
+ // ============================================================================
117
+ // Footer Schema
118
+ // ============================================================================
119
+
120
+ const footerLinkSchema = z.object({
121
+ label: z.string(),
122
+ href: z.string(),
123
+ })
124
+
125
+ const footerGroupSchema = z.object({
126
+ title: z.string(),
127
+ links: z.array(footerLinkSchema),
128
+ })
129
+
130
+ const footerSchema = z.object({
131
+ socials: z.record(z.string(), z.string()).optional(),
132
+ links: z.array(footerGroupSchema).optional(),
133
+ })
134
+
135
+ // ============================================================================
136
+ // API Configuration Schema
137
+ // ============================================================================
138
+
139
+ const apiAuthSchema = z.object({
140
+ method: z.enum(['bearer', 'basic', 'api-key', 'none']),
141
+ name: z.string().optional(),
142
+ })
143
+
144
+ const apiPlaygroundSchema = z.object({
145
+ mode: z.enum(['show', 'simple', 'hide']).optional(),
146
+ })
147
+
148
+ const apiConfigSchema = z.object({
149
+ baseUrl: z.string().optional(),
150
+ auth: apiAuthSchema.optional(),
151
+ playground: apiPlaygroundSchema.optional(),
152
+ })
153
+
154
+ // ============================================================================
155
+ // SEO Schema
156
+ // ============================================================================
157
+
158
+ const seoSchema = z.object({
159
+ indexHiddenPages: z.boolean().optional(),
160
+ titleTemplate: z.string().optional(),
161
+ })
162
+
163
+ // ============================================================================
164
+ // Integrations Schema
165
+ // ============================================================================
166
+
167
+ const analyticsSchema = z.object({
168
+ posthog: z.object({ apiKey: z.string() }).optional(),
169
+ googleAnalytics: z.object({ measurementId: z.string() }).optional(),
170
+ plausible: z.object({ domain: z.string() }).optional(),
171
+ })
172
+
173
+ const integrationsSchema = z.object({
174
+ analytics: analyticsSchema.optional(),
175
+ })
176
+
177
+ // ============================================================================
178
+ // Contextual Menu Schema
179
+ // ============================================================================
180
+
181
+ const contextualOptionsEnum = z.enum([
182
+ 'copy',
183
+ 'view',
184
+ 'chatgpt',
185
+ 'claude',
186
+ 'perplexity',
187
+ 'mcp',
188
+ 'cursor',
189
+ 'vscode',
190
+ ])
191
+
192
+ const contextualSchema = z.object({
193
+ options: z.array(contextualOptionsEnum).optional(),
194
+ })
195
+
196
+ // ============================================================================
197
+ // Main Configuration Schema
198
+ // ============================================================================
199
+
200
+ export const docsConfigSchema = z.object({
201
+ // Schema reference (optional)
202
+ $schema: z.string().optional(),
203
+
204
+ // Core identity
205
+ name: z.string(),
206
+
207
+ // Theme
208
+ theme: z.enum(['default', 'mint', 'quill', 'venus']).optional(),
209
+ colors: colorSchema.optional(),
210
+
211
+ // Branding
212
+ favicon: faviconSchema.optional(),
213
+ logo: logoSchema.optional(),
214
+
215
+ // Navigation
216
+ navigation: navigationSchema,
217
+
218
+ // Navbar
219
+ navbar: navbarSchema.optional(),
220
+
221
+ // Footer
222
+ footer: footerSchema.optional(),
223
+
224
+ // API Configuration
225
+ api: apiConfigSchema.optional(),
226
+ openapi: z.union([z.string(), z.array(z.string())]).optional(),
227
+
228
+ // SEO
229
+ seo: seoSchema.optional(),
230
+
231
+ // Integrations
232
+ integrations: integrationsSchema.optional(),
233
+
234
+ // Contextual menu
235
+ contextual: contextualSchema.optional(),
236
+
237
+ // Topbar style
238
+ topbar: z.object({
239
+ style: z.enum(['default', 'gradient']).optional(),
240
+ }).optional(),
241
+
242
+ // Versioning
243
+ versions: z.array(z.string()).optional(),
244
+ })
245
+
246
+ // ============================================================================
247
+ // Types
248
+ // ============================================================================
249
+
250
+ export type DocsConfig = z.infer<typeof docsConfigSchema>
251
+ export type NavigationTab = z.infer<typeof tabSchema>
252
+ export type NavigationGroup = z.infer<typeof groupSchema>
253
+ export type NavLink = z.infer<typeof navLinkSchema>
254
+ export type Anchor = z.infer<typeof anchorSchema>
255
+ export type ColorConfig = z.infer<typeof colorSchema>
256
+ export type LogoConfig = z.infer<typeof logoSchema>
257
+ export type ApiConfig = z.infer<typeof apiConfigSchema>
258
+
259
+ // ============================================================================
260
+ // Validation Functions
261
+ // ============================================================================
262
+
263
+ /**
264
+ * Parse and validate docs configuration
265
+ */
266
+ export function parseDocsConfig(data: unknown): DocsConfig {
267
+ const result = docsConfigSchema.safeParse(data)
268
+
269
+ if (!result.success) {
270
+ const issues = result.error.issues || []
271
+ const errors = issues.map((e) =>
272
+ `${e.path.map(String).join('.')}: ${e.message}`
273
+ ).join('\n')
274
+ throw new Error(`Invalid docs.json configuration:\n${errors}`)
275
+ }
276
+
277
+ return result.data
278
+ }
279
+
280
+ /**
281
+ * Safe parse that returns null on failure
282
+ */
283
+ export function safeParseDocsConfig(data: unknown): DocsConfig | null {
284
+ const result = docsConfigSchema.safeParse(data)
285
+ return result.success ? result.data : null
286
+ }
287
+
288
+ /**
289
+ * Get default configuration
290
+ */
291
+ export function getDefaultDocsConfig(): Partial<DocsConfig> {
292
+ return {
293
+ theme: 'default',
294
+ navigation: {
295
+ groups: [],
296
+ },
297
+ }
298
+ }
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Documentation Library Exports
3
+ */
4
+
5
+ // MDX
6
+ export * from './mdx'
7
+
8
+ // Configuration
9
+ export * from './config'
10
+
11
+ // Navigation
12
+ export * from './navigation'