@kurly-growth/growthman 0.1.12 → 0.1.14

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 (287) hide show
  1. package/CLAUDE.md +58 -0
  2. package/app/globals.css +125 -0
  3. package/app/layout.tsx +36 -0
  4. package/app/page.tsx +213 -0
  5. package/bin/cli.js +41 -4
  6. package/components/api-test-dialog.tsx +222 -0
  7. package/components/endpoint-edit-dialog.tsx +181 -0
  8. package/components/endpoint-table.tsx +147 -0
  9. package/components/openapi-upload-dialog.tsx +213 -0
  10. package/components/ui/button.tsx +62 -0
  11. package/components/ui/checkbox.tsx +32 -0
  12. package/components/ui/dialog.tsx +143 -0
  13. package/components/ui/input.tsx +21 -0
  14. package/components/ui/label.tsx +24 -0
  15. package/components/ui/sonner.tsx +37 -0
  16. package/components/ui/table.tsx +116 -0
  17. package/components/ui/textarea.tsx +18 -0
  18. package/components.json +22 -0
  19. package/next-env.d.ts +6 -0
  20. package/package.json +10 -19
  21. package/pnpm-workspace.yaml +4 -0
  22. package/postcss.config.mjs +7 -0
  23. package/prisma/prisma/dev.db +0 -0
  24. package/.next/BUILD_ID +0 -1
  25. package/.next/app-path-routes-manifest.json +0 -12
  26. package/.next/build/chunks/[root-of-the-server]__51225daf._.js +0 -206
  27. package/.next/build/chunks/[root-of-the-server]__51225daf._.js.map +0 -8
  28. package/.next/build/chunks/[root-of-the-server]__974941ed._.js +0 -500
  29. package/.next/build/chunks/[root-of-the-server]__974941ed._.js.map +0 -11
  30. package/.next/build/chunks/[turbopack-node]_transforms_postcss_ts_6920245c._.js +0 -13
  31. package/.next/build/chunks/[turbopack-node]_transforms_postcss_ts_6920245c._.js.map +0 -5
  32. package/.next/build/chunks/[turbopack]_runtime.js +0 -795
  33. package/.next/build/chunks/[turbopack]_runtime.js.map +0 -10
  34. package/.next/build/chunks/node_modules_fe693df6._.js +0 -6758
  35. package/.next/build/chunks/node_modules_fe693df6._.js.map +0 -47
  36. package/.next/build/package.json +0 -1
  37. package/.next/build/postcss.js +0 -6
  38. package/.next/build/postcss.js.map +0 -5
  39. package/.next/build-manifest.json +0 -19
  40. package/.next/diagnostics/build-diagnostics.json +0 -6
  41. package/.next/diagnostics/framework.json +0 -1
  42. package/.next/export-marker.json +0 -6
  43. package/.next/fallback-build-manifest.json +0 -12
  44. package/.next/images-manifest.json +0 -66
  45. package/.next/next-minimal-server.js.nft.json +0 -1
  46. package/.next/next-server.js.nft.json +0 -1
  47. package/.next/package.json +0 -1
  48. package/.next/prerender-manifest.json +0 -114
  49. package/.next/required-server-files.js +0 -163
  50. package/.next/required-server-files.json +0 -163
  51. package/.next/routes-manifest.json +0 -109
  52. package/.next/server/app/_global-error/page/app-paths-manifest.json +0 -3
  53. package/.next/server/app/_global-error/page/build-manifest.json +0 -16
  54. package/.next/server/app/_global-error/page/next-font-manifest.json +0 -6
  55. package/.next/server/app/_global-error/page/react-loadable-manifest.json +0 -1
  56. package/.next/server/app/_global-error/page/server-reference-manifest.json +0 -4
  57. package/.next/server/app/_global-error/page.js +0 -11
  58. package/.next/server/app/_global-error/page.js.map +0 -5
  59. package/.next/server/app/_global-error/page.js.nft.json +0 -1
  60. package/.next/server/app/_global-error/page_client-reference-manifest.js +0 -2
  61. package/.next/server/app/_global-error.html +0 -2
  62. package/.next/server/app/_global-error.meta +0 -15
  63. package/.next/server/app/_global-error.rsc +0 -13
  64. package/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +0 -5
  65. package/.next/server/app/_global-error.segments/_full.segment.rsc +0 -13
  66. package/.next/server/app/_global-error.segments/_head.segment.rsc +0 -6
  67. package/.next/server/app/_global-error.segments/_index.segment.rsc +0 -4
  68. package/.next/server/app/_global-error.segments/_tree.segment.rsc +0 -1
  69. package/.next/server/app/_not-found/page/app-paths-manifest.json +0 -3
  70. package/.next/server/app/_not-found/page/build-manifest.json +0 -16
  71. package/.next/server/app/_not-found/page/next-font-manifest.json +0 -11
  72. package/.next/server/app/_not-found/page/react-loadable-manifest.json +0 -1
  73. package/.next/server/app/_not-found/page/server-reference-manifest.json +0 -4
  74. package/.next/server/app/_not-found/page.js +0 -14
  75. package/.next/server/app/_not-found/page.js.map +0 -5
  76. package/.next/server/app/_not-found/page.js.nft.json +0 -1
  77. package/.next/server/app/_not-found/page_client-reference-manifest.js +0 -2
  78. package/.next/server/app/_not-found.html +0 -1
  79. package/.next/server/app/_not-found.meta +0 -16
  80. package/.next/server/app/_not-found.rsc +0 -15
  81. package/.next/server/app/_not-found.segments/_full.segment.rsc +0 -15
  82. package/.next/server/app/_not-found.segments/_head.segment.rsc +0 -6
  83. package/.next/server/app/_not-found.segments/_index.segment.rsc +0 -6
  84. package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +0 -5
  85. package/.next/server/app/_not-found.segments/_not-found.segment.rsc +0 -4
  86. package/.next/server/app/_not-found.segments/_tree.segment.rsc +0 -2
  87. package/.next/server/app/api/endpoints/[id]/route/app-paths-manifest.json +0 -3
  88. package/.next/server/app/api/endpoints/[id]/route/build-manifest.json +0 -11
  89. package/.next/server/app/api/endpoints/[id]/route/server-reference-manifest.json +0 -4
  90. package/.next/server/app/api/endpoints/[id]/route.js +0 -7
  91. package/.next/server/app/api/endpoints/[id]/route.js.map +0 -5
  92. package/.next/server/app/api/endpoints/[id]/route.js.nft.json +0 -1
  93. package/.next/server/app/api/endpoints/[id]/route_client-reference-manifest.js +0 -2
  94. package/.next/server/app/api/endpoints/bulk/route/app-paths-manifest.json +0 -3
  95. package/.next/server/app/api/endpoints/bulk/route/build-manifest.json +0 -11
  96. package/.next/server/app/api/endpoints/bulk/route/server-reference-manifest.json +0 -4
  97. package/.next/server/app/api/endpoints/bulk/route.js +0 -7
  98. package/.next/server/app/api/endpoints/bulk/route.js.map +0 -5
  99. package/.next/server/app/api/endpoints/bulk/route.js.nft.json +0 -1
  100. package/.next/server/app/api/endpoints/bulk/route_client-reference-manifest.js +0 -2
  101. package/.next/server/app/api/endpoints/import/route/app-paths-manifest.json +0 -3
  102. package/.next/server/app/api/endpoints/import/route/build-manifest.json +0 -11
  103. package/.next/server/app/api/endpoints/import/route/server-reference-manifest.json +0 -4
  104. package/.next/server/app/api/endpoints/import/route.js +0 -7
  105. package/.next/server/app/api/endpoints/import/route.js.map +0 -5
  106. package/.next/server/app/api/endpoints/import/route.js.nft.json +0 -1
  107. package/.next/server/app/api/endpoints/import/route_client-reference-manifest.js +0 -2
  108. package/.next/server/app/api/endpoints/route/app-paths-manifest.json +0 -3
  109. package/.next/server/app/api/endpoints/route/build-manifest.json +0 -11
  110. package/.next/server/app/api/endpoints/route/server-reference-manifest.json +0 -4
  111. package/.next/server/app/api/endpoints/route.js +0 -7
  112. package/.next/server/app/api/endpoints/route.js.map +0 -5
  113. package/.next/server/app/api/endpoints/route.js.nft.json +0 -1
  114. package/.next/server/app/api/endpoints/route_client-reference-manifest.js +0 -2
  115. package/.next/server/app/api/endpoints/sync/route/app-paths-manifest.json +0 -3
  116. package/.next/server/app/api/endpoints/sync/route/build-manifest.json +0 -11
  117. package/.next/server/app/api/endpoints/sync/route/server-reference-manifest.json +0 -4
  118. package/.next/server/app/api/endpoints/sync/route.js +0 -7
  119. package/.next/server/app/api/endpoints/sync/route.js.map +0 -5
  120. package/.next/server/app/api/endpoints/sync/route.js.nft.json +0 -1
  121. package/.next/server/app/api/endpoints/sync/route_client-reference-manifest.js +0 -2
  122. package/.next/server/app/api/mock/[...slug]/route/app-paths-manifest.json +0 -3
  123. package/.next/server/app/api/mock/[...slug]/route/build-manifest.json +0 -11
  124. package/.next/server/app/api/mock/[...slug]/route/server-reference-manifest.json +0 -4
  125. package/.next/server/app/api/mock/[...slug]/route.js +0 -8
  126. package/.next/server/app/api/mock/[...slug]/route.js.map +0 -5
  127. package/.next/server/app/api/mock/[...slug]/route.js.nft.json +0 -1
  128. package/.next/server/app/api/mock/[...slug]/route_client-reference-manifest.js +0 -2
  129. package/.next/server/app/favicon.ico/route/app-paths-manifest.json +0 -3
  130. package/.next/server/app/favicon.ico/route/build-manifest.json +0 -11
  131. package/.next/server/app/favicon.ico/route.js +0 -7
  132. package/.next/server/app/favicon.ico/route.js.map +0 -5
  133. package/.next/server/app/favicon.ico/route.js.nft.json +0 -1
  134. package/.next/server/app/favicon.ico.meta +0 -1
  135. package/.next/server/app/index.html +0 -1
  136. package/.next/server/app/index.meta +0 -14
  137. package/.next/server/app/index.rsc +0 -21
  138. package/.next/server/app/index.segments/__PAGE__.segment.rsc +0 -9
  139. package/.next/server/app/index.segments/_full.segment.rsc +0 -21
  140. package/.next/server/app/index.segments/_head.segment.rsc +0 -6
  141. package/.next/server/app/index.segments/_index.segment.rsc +0 -6
  142. package/.next/server/app/index.segments/_tree.segment.rsc +0 -4
  143. package/.next/server/app/page/app-paths-manifest.json +0 -3
  144. package/.next/server/app/page/build-manifest.json +0 -16
  145. package/.next/server/app/page/next-font-manifest.json +0 -11
  146. package/.next/server/app/page/react-loadable-manifest.json +0 -8
  147. package/.next/server/app/page/server-reference-manifest.json +0 -4
  148. package/.next/server/app/page.js +0 -16
  149. package/.next/server/app/page.js.map +0 -5
  150. package/.next/server/app/page.js.nft.json +0 -1
  151. package/.next/server/app/page_client-reference-manifest.js +0 -2
  152. package/.next/server/app-paths-manifest.json +0 -12
  153. package/.next/server/chunks/1629d_next_dist_esm_build_templates_app-route_498527d5.js +0 -3
  154. package/.next/server/chunks/1629d_next_dist_esm_build_templates_app-route_498527d5.js.map +0 -1
  155. package/.next/server/chunks/[externals]__cf2ccb51._.js +0 -3
  156. package/.next/server/chunks/[externals]__cf2ccb51._.js.map +0 -1
  157. package/.next/server/chunks/[externals]_next_dist_8dbe5856._.js +0 -3
  158. package/.next/server/chunks/[externals]_next_dist_8dbe5856._.js.map +0 -1
  159. package/.next/server/chunks/[root-of-the-server]__3534fecc._.js +0 -3
  160. package/.next/server/chunks/[root-of-the-server]__3534fecc._.js.map +0 -1
  161. package/.next/server/chunks/[root-of-the-server]__461ea613._.js +0 -21
  162. package/.next/server/chunks/[root-of-the-server]__461ea613._.js.map +0 -1
  163. package/.next/server/chunks/[root-of-the-server]__4929acb0._.js +0 -129
  164. package/.next/server/chunks/[root-of-the-server]__4929acb0._.js.map +0 -1
  165. package/.next/server/chunks/[root-of-the-server]__909218aa._.js +0 -3
  166. package/.next/server/chunks/[root-of-the-server]__909218aa._.js.map +0 -1
  167. package/.next/server/chunks/[root-of-the-server]__a6c01a13._.js +0 -3
  168. package/.next/server/chunks/[root-of-the-server]__a6c01a13._.js.map +0 -1
  169. package/.next/server/chunks/[root-of-the-server]__db1127cf._.js +0 -3
  170. package/.next/server/chunks/[root-of-the-server]__db1127cf._.js.map +0 -1
  171. package/.next/server/chunks/[root-of-the-server]__e46f3e25._.js +0 -3
  172. package/.next/server/chunks/[root-of-the-server]__e46f3e25._.js.map +0 -1
  173. package/.next/server/chunks/[turbopack]_runtime.js +0 -795
  174. package/.next/server/chunks/[turbopack]_runtime.js.map +0 -10
  175. package/.next/server/chunks/_next-internal_server_app_api_endpoints_[id]_route_actions_b91cfc4c.js +0 -3
  176. package/.next/server/chunks/_next-internal_server_app_api_endpoints_[id]_route_actions_b91cfc4c.js.map +0 -1
  177. package/.next/server/chunks/_next-internal_server_app_api_endpoints_bulk_route_actions_560cc6cd.js +0 -3
  178. package/.next/server/chunks/_next-internal_server_app_api_endpoints_bulk_route_actions_560cc6cd.js.map +0 -1
  179. package/.next/server/chunks/_next-internal_server_app_api_endpoints_import_route_actions_f2444950.js +0 -3
  180. package/.next/server/chunks/_next-internal_server_app_api_endpoints_import_route_actions_f2444950.js.map +0 -1
  181. package/.next/server/chunks/_next-internal_server_app_api_endpoints_route_actions_49d8ad56.js +0 -3
  182. package/.next/server/chunks/_next-internal_server_app_api_endpoints_route_actions_49d8ad56.js.map +0 -1
  183. package/.next/server/chunks/_next-internal_server_app_api_endpoints_sync_route_actions_0f446550.js +0 -3
  184. package/.next/server/chunks/_next-internal_server_app_api_endpoints_sync_route_actions_0f446550.js.map +0 -1
  185. package/.next/server/chunks/_next-internal_server_app_api_mock_[___slug]_route_actions_be875f77.js +0 -3
  186. package/.next/server/chunks/_next-internal_server_app_api_mock_[___slug]_route_actions_be875f77.js.map +0 -1
  187. package/.next/server/chunks/_next-internal_server_app_favicon_ico_route_actions_353150a5.js +0 -3
  188. package/.next/server/chunks/_next-internal_server_app_favicon_ico_route_actions_353150a5.js.map +0 -1
  189. package/.next/server/chunks/node_modules__pnpm_a61fb769._.js +0 -3
  190. package/.next/server/chunks/node_modules__pnpm_a61fb769._.js.map +0 -1
  191. package/.next/server/chunks/ssr/1629d_next_dist_1a21bde7._.js +0 -6
  192. package/.next/server/chunks/ssr/1629d_next_dist_1a21bde7._.js.map +0 -1
  193. package/.next/server/chunks/ssr/1629d_next_dist_8dc31fba._.js +0 -3
  194. package/.next/server/chunks/ssr/1629d_next_dist_8dc31fba._.js.map +0 -1
  195. package/.next/server/chunks/ssr/1629d_next_dist_client_components_b01b33e4._.js +0 -3
  196. package/.next/server/chunks/ssr/1629d_next_dist_client_components_b01b33e4._.js.map +0 -1
  197. package/.next/server/chunks/ssr/1629d_next_dist_client_components_builtin_forbidden_4cab2078.js +0 -3
  198. package/.next/server/chunks/ssr/1629d_next_dist_client_components_builtin_forbidden_4cab2078.js.map +0 -1
  199. package/.next/server/chunks/ssr/1629d_next_dist_client_components_builtin_global-error_0d5cb623.js +0 -3
  200. package/.next/server/chunks/ssr/1629d_next_dist_client_components_builtin_global-error_0d5cb623.js.map +0 -1
  201. package/.next/server/chunks/ssr/1629d_next_dist_client_components_builtin_unauthorized_b8fbdcad.js +0 -3
  202. package/.next/server/chunks/ssr/1629d_next_dist_client_components_builtin_unauthorized_b8fbdcad.js.map +0 -1
  203. package/.next/server/chunks/ssr/1629d_next_dist_d78dee57._.js +0 -4
  204. package/.next/server/chunks/ssr/1629d_next_dist_d78dee57._.js.map +0 -1
  205. package/.next/server/chunks/ssr/1629d_next_dist_esm_build_templates_app-page_d4e9464b.js +0 -4
  206. package/.next/server/chunks/ssr/1629d_next_dist_esm_build_templates_app-page_d4e9464b.js.map +0 -1
  207. package/.next/server/chunks/ssr/67049_lucide-react_dist_esm_createLucideIcon_22fe2e14.js +0 -3
  208. package/.next/server/chunks/ssr/67049_lucide-react_dist_esm_createLucideIcon_22fe2e14.js.map +0 -1
  209. package/.next/server/chunks/ssr/[externals]_next_dist_server_app-render_work-async-storage_external_1f8eeae7.js +0 -3
  210. package/.next/server/chunks/ssr/[externals]_next_dist_server_app-render_work-async-storage_external_1f8eeae7.js.map +0 -1
  211. package/.next/server/chunks/ssr/[root-of-the-server]__14f4396a._.js +0 -10
  212. package/.next/server/chunks/ssr/[root-of-the-server]__14f4396a._.js.map +0 -1
  213. package/.next/server/chunks/ssr/[root-of-the-server]__3064bf15._.js +0 -3
  214. package/.next/server/chunks/ssr/[root-of-the-server]__3064bf15._.js.map +0 -1
  215. package/.next/server/chunks/ssr/[root-of-the-server]__4ff41ba3._.js +0 -4
  216. package/.next/server/chunks/ssr/[root-of-the-server]__4ff41ba3._.js.map +0 -1
  217. package/.next/server/chunks/ssr/[root-of-the-server]__57c5da8e._.js +0 -3
  218. package/.next/server/chunks/ssr/[root-of-the-server]__57c5da8e._.js.map +0 -1
  219. package/.next/server/chunks/ssr/[root-of-the-server]__67653b38._.js +0 -3
  220. package/.next/server/chunks/ssr/[root-of-the-server]__67653b38._.js.map +0 -1
  221. package/.next/server/chunks/ssr/[root-of-the-server]__7d48410d._.js +0 -3
  222. package/.next/server/chunks/ssr/[root-of-the-server]__7d48410d._.js.map +0 -1
  223. package/.next/server/chunks/ssr/[root-of-the-server]__a49eaf36._.js +0 -3
  224. package/.next/server/chunks/ssr/[root-of-the-server]__a49eaf36._.js.map +0 -1
  225. package/.next/server/chunks/ssr/[root-of-the-server]__b0617f51._.js +0 -3
  226. package/.next/server/chunks/ssr/[root-of-the-server]__b0617f51._.js.map +0 -1
  227. package/.next/server/chunks/ssr/[root-of-the-server]__cc026bde._.js +0 -3
  228. package/.next/server/chunks/ssr/[root-of-the-server]__cc026bde._.js.map +0 -1
  229. package/.next/server/chunks/ssr/[root-of-the-server]__d079898e._.js +0 -3
  230. package/.next/server/chunks/ssr/[root-of-the-server]__d079898e._.js.map +0 -1
  231. package/.next/server/chunks/ssr/[root-of-the-server]__d3649e47._.js +0 -3
  232. package/.next/server/chunks/ssr/[root-of-the-server]__d3649e47._.js.map +0 -1
  233. package/.next/server/chunks/ssr/[turbopack]_runtime.js +0 -795
  234. package/.next/server/chunks/ssr/[turbopack]_runtime.js.map +0 -10
  235. package/.next/server/chunks/ssr/_9b6e3dc4._.js +0 -3
  236. package/.next/server/chunks/ssr/_9b6e3dc4._.js.map +0 -1
  237. package/.next/server/chunks/ssr/_a437ac52._.js +0 -7
  238. package/.next/server/chunks/ssr/_a437ac52._.js.map +0 -1
  239. package/.next/server/chunks/ssr/_b62b070d._.js +0 -4
  240. package/.next/server/chunks/ssr/_b62b070d._.js.map +0 -1
  241. package/.next/server/chunks/ssr/_next-internal_server_app__global-error_page_actions_75761787.js +0 -3
  242. package/.next/server/chunks/ssr/_next-internal_server_app__global-error_page_actions_75761787.js.map +0 -1
  243. package/.next/server/chunks/ssr/_next-internal_server_app__not-found_page_actions_554ec2bf.js +0 -3
  244. package/.next/server/chunks/ssr/_next-internal_server_app__not-found_page_actions_554ec2bf.js.map +0 -1
  245. package/.next/server/chunks/ssr/_next-internal_server_app_page_actions_39d4fc33.js +0 -3
  246. package/.next/server/chunks/ssr/_next-internal_server_app_page_actions_39d4fc33.js.map +0 -1
  247. package/.next/server/chunks/ssr/app_b9b1292a._.js +0 -3
  248. package/.next/server/chunks/ssr/app_b9b1292a._.js.map +0 -1
  249. package/.next/server/functions-config-manifest.json +0 -4
  250. package/.next/server/interception-route-rewrite-manifest.js +0 -1
  251. package/.next/server/middleware-build-manifest.js +0 -20
  252. package/.next/server/middleware-manifest.json +0 -6
  253. package/.next/server/next-font-manifest.js +0 -1
  254. package/.next/server/next-font-manifest.json +0 -15
  255. package/.next/server/pages/404.html +0 -1
  256. package/.next/server/pages/500.html +0 -2
  257. package/.next/server/pages-manifest.json +0 -4
  258. package/.next/server/server-reference-manifest.js +0 -1
  259. package/.next/server/server-reference-manifest.json +0 -5
  260. package/.next/static/chunks/16403d658c649f0f.js +0 -1
  261. package/.next/static/chunks/2422cfacfdb28c2c.js +0 -5
  262. package/.next/static/chunks/42572c067be8ea0f.js +0 -1
  263. package/.next/static/chunks/5045da71379799ce.js +0 -1
  264. package/.next/static/chunks/6e04dfc4035d7150.js +0 -5
  265. package/.next/static/chunks/8155485116e3ff24.js +0 -1
  266. package/.next/static/chunks/a66e09a7c2336f67.js +0 -1
  267. package/.next/static/chunks/a6dad97d9634a72d.js +0 -1
  268. package/.next/static/chunks/a6dad97d9634a72d.js.map +0 -1
  269. package/.next/static/chunks/da3f3e4f37f68cee.css +0 -3
  270. package/.next/static/chunks/f1cfb69226717279.js +0 -1
  271. package/.next/static/chunks/turbopack-7027959231bb432a.js +0 -4
  272. package/.next/static/media/4fa387ec64143e14-s.c1fdd6c2.woff2 +0 -0
  273. package/.next/static/media/7178b3e590c64307-s.b97b3418.woff2 +0 -0
  274. package/.next/static/media/797e433ab948586e-s.p.dbea232f.woff2 +0 -0
  275. package/.next/static/media/8a480f0b521d4e75-s.8e0177b5.woff2 +0 -0
  276. package/.next/static/media/bbc41e54d2fcbd21-s.799d8ef8.woff2 +0 -0
  277. package/.next/static/media/caa3a2e1cccd8315-s.p.853070df.woff2 +0 -0
  278. package/.next/static/media/favicon.de6b30f1.ico +0 -0
  279. package/.next/static/tHhig3FrI32oLhNopN5Nj/_buildManifest.js +0 -11
  280. package/.next/static/tHhig3FrI32oLhNopN5Nj/_clientMiddlewareManifest.json +0 -1
  281. package/.next/static/tHhig3FrI32oLhNopN5Nj/_ssgManifest.js +0 -1
  282. package/.next/trace +0 -1
  283. package/.next/trace-build +0 -1
  284. package/.next/turbopack +0 -0
  285. package/.next/types/routes.d.ts +0 -78
  286. package/.next/types/validator.ts +0 -124
  287. /package/{.next/server/app/favicon.ico.body → app/favicon.ico} +0 -0
package/CLAUDE.md ADDED
@@ -0,0 +1,58 @@
1
+ # CLAUDE.md
2
+
3
+ This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4
+
5
+ ## Development Commands
6
+
7
+ ```bash
8
+ pnpm dev # Start dev server (http://localhost:3100)
9
+ pnpm dev:clean # Reset DB with seed data and start dev server
10
+ pnpm build # Build for production
11
+ pnpm lint # Run ESLint
12
+ pnpm db:seed # Seed the database
13
+ pnpm db:reset # Reset database with migrations
14
+ ```
15
+
16
+ ## Architecture Overview
17
+
18
+ This is a **Mock Server Dashboard** - a Next.js 16 application that allows users to create, manage, and serve mock API endpoints stored in PostgreSQL via Prisma.
19
+
20
+ ### Core Concept
21
+
22
+ 1. Users define mock endpoints (path, method, status code, response body) through a web UI
23
+ 2. These endpoints are stored in the `MockEndpoint` table
24
+ 3. Requests to `/api/mock/*` are dynamically matched against stored endpoints using `path-to-regexp`
25
+
26
+ ### Key Components
27
+
28
+ - **`/app/api/mock/[...slug]/route.ts`** - Catch-all route that handles all mock requests. Matches incoming requests against stored endpoints using pattern matching (supports path parameters like `:id`)
29
+
30
+ - **`/app/api/endpoints/`** - CRUD API for managing mock endpoints
31
+ - `route.ts` - GET (list all), POST (create)
32
+ - `[id]/route.ts` - PUT (update), DELETE
33
+ - `import/route.ts` - Bulk import from OpenAPI spec
34
+ - `sync/route.ts` - Sync endpoints with external spec
35
+
36
+ - **`/lib/openapi-parser.ts`** - Parses OpenAPI 3.x specs and generates mock response data based on schema definitions. Handles `$ref`, `allOf`, `oneOf`, `anyOf`, and generates type-appropriate mock values.
37
+
38
+ - **`/components/`** - React components for the dashboard UI
39
+ - `endpoint-table.tsx` - Display list of endpoints
40
+ - `endpoint-edit-dialog.tsx` - Create/edit endpoint with Monaco editor for JSON
41
+ - `openapi-upload-dialog.tsx` - Import endpoints from OpenAPI spec
42
+
43
+ ### Database Schema
44
+
45
+ Single table `MockEndpoint` with unique constraint on `(path, method)`:
46
+ - `path` - Express-style route (e.g., `/v1/users/:id`)
47
+ - `method` - HTTP method
48
+ - `statusCode` - Response status code
49
+ - `responseBody` - JSON response data
50
+
51
+ ### Tech Stack
52
+
53
+ - Next.js 16 (App Router)
54
+ - React 19
55
+ - Prisma with PostgreSQL
56
+ - Tailwind CSS 4
57
+ - Radix UI + shadcn/ui components
58
+ - Monaco Editor for JSON editing
@@ -0,0 +1,125 @@
1
+ @import "tailwindcss";
2
+ @import "tw-animate-css";
3
+
4
+ @custom-variant dark (&:is(.dark *));
5
+
6
+ @theme inline {
7
+ --color-background: var(--background);
8
+ --color-foreground: var(--foreground);
9
+ --font-sans: var(--font-geist-sans);
10
+ --font-mono: var(--font-geist-mono);
11
+ --color-sidebar-ring: var(--sidebar-ring);
12
+ --color-sidebar-border: var(--sidebar-border);
13
+ --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
14
+ --color-sidebar-accent: var(--sidebar-accent);
15
+ --color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
16
+ --color-sidebar-primary: var(--sidebar-primary);
17
+ --color-sidebar-foreground: var(--sidebar-foreground);
18
+ --color-sidebar: var(--sidebar);
19
+ --color-chart-5: var(--chart-5);
20
+ --color-chart-4: var(--chart-4);
21
+ --color-chart-3: var(--chart-3);
22
+ --color-chart-2: var(--chart-2);
23
+ --color-chart-1: var(--chart-1);
24
+ --color-ring: var(--ring);
25
+ --color-input: var(--input);
26
+ --color-border: var(--border);
27
+ --color-destructive: var(--destructive);
28
+ --color-accent-foreground: var(--accent-foreground);
29
+ --color-accent: var(--accent);
30
+ --color-muted-foreground: var(--muted-foreground);
31
+ --color-muted: var(--muted);
32
+ --color-secondary-foreground: var(--secondary-foreground);
33
+ --color-secondary: var(--secondary);
34
+ --color-primary-foreground: var(--primary-foreground);
35
+ --color-primary: var(--primary);
36
+ --color-popover-foreground: var(--popover-foreground);
37
+ --color-popover: var(--popover);
38
+ --color-card-foreground: var(--card-foreground);
39
+ --color-card: var(--card);
40
+ --radius-sm: calc(var(--radius) - 4px);
41
+ --radius-md: calc(var(--radius) - 2px);
42
+ --radius-lg: var(--radius);
43
+ --radius-xl: calc(var(--radius) + 4px);
44
+ --radius-2xl: calc(var(--radius) + 8px);
45
+ --radius-3xl: calc(var(--radius) + 12px);
46
+ --radius-4xl: calc(var(--radius) + 16px);
47
+ }
48
+
49
+ :root {
50
+ --radius: 0.625rem;
51
+ --background: oklch(1 0 0);
52
+ --foreground: oklch(0.145 0 0);
53
+ --card: oklch(1 0 0);
54
+ --card-foreground: oklch(0.145 0 0);
55
+ --popover: oklch(1 0 0);
56
+ --popover-foreground: oklch(0.145 0 0);
57
+ --primary: oklch(0.205 0 0);
58
+ --primary-foreground: oklch(0.985 0 0);
59
+ --secondary: oklch(0.97 0 0);
60
+ --secondary-foreground: oklch(0.205 0 0);
61
+ --muted: oklch(0.97 0 0);
62
+ --muted-foreground: oklch(0.556 0 0);
63
+ --accent: oklch(0.97 0 0);
64
+ --accent-foreground: oklch(0.205 0 0);
65
+ --destructive: oklch(0.577 0.245 27.325);
66
+ --border: oklch(0.922 0 0);
67
+ --input: oklch(0.922 0 0);
68
+ --ring: oklch(0.708 0 0);
69
+ --chart-1: oklch(0.646 0.222 41.116);
70
+ --chart-2: oklch(0.6 0.118 184.704);
71
+ --chart-3: oklch(0.398 0.07 227.392);
72
+ --chart-4: oklch(0.828 0.189 84.429);
73
+ --chart-5: oklch(0.769 0.188 70.08);
74
+ --sidebar: oklch(0.985 0 0);
75
+ --sidebar-foreground: oklch(0.145 0 0);
76
+ --sidebar-primary: oklch(0.205 0 0);
77
+ --sidebar-primary-foreground: oklch(0.985 0 0);
78
+ --sidebar-accent: oklch(0.97 0 0);
79
+ --sidebar-accent-foreground: oklch(0.205 0 0);
80
+ --sidebar-border: oklch(0.922 0 0);
81
+ --sidebar-ring: oklch(0.708 0 0);
82
+ }
83
+
84
+ .dark {
85
+ --background: oklch(0.145 0 0);
86
+ --foreground: oklch(0.985 0 0);
87
+ --card: oklch(0.205 0 0);
88
+ --card-foreground: oklch(0.985 0 0);
89
+ --popover: oklch(0.205 0 0);
90
+ --popover-foreground: oklch(0.985 0 0);
91
+ --primary: oklch(0.922 0 0);
92
+ --primary-foreground: oklch(0.205 0 0);
93
+ --secondary: oklch(0.269 0 0);
94
+ --secondary-foreground: oklch(0.985 0 0);
95
+ --muted: oklch(0.269 0 0);
96
+ --muted-foreground: oklch(0.708 0 0);
97
+ --accent: oklch(0.269 0 0);
98
+ --accent-foreground: oklch(0.985 0 0);
99
+ --destructive: oklch(0.704 0.191 22.216);
100
+ --border: oklch(1 0 0 / 10%);
101
+ --input: oklch(1 0 0 / 15%);
102
+ --ring: oklch(0.556 0 0);
103
+ --chart-1: oklch(0.488 0.243 264.376);
104
+ --chart-2: oklch(0.696 0.17 162.48);
105
+ --chart-3: oklch(0.769 0.188 70.08);
106
+ --chart-4: oklch(0.627 0.265 303.9);
107
+ --chart-5: oklch(0.645 0.246 16.439);
108
+ --sidebar: oklch(0.205 0 0);
109
+ --sidebar-foreground: oklch(0.985 0 0);
110
+ --sidebar-primary: oklch(0.488 0.243 264.376);
111
+ --sidebar-primary-foreground: oklch(0.985 0 0);
112
+ --sidebar-accent: oklch(0.269 0 0);
113
+ --sidebar-accent-foreground: oklch(0.985 0 0);
114
+ --sidebar-border: oklch(1 0 0 / 10%);
115
+ --sidebar-ring: oklch(0.556 0 0);
116
+ }
117
+
118
+ @layer base {
119
+ * {
120
+ @apply border-border outline-ring/50;
121
+ }
122
+ body {
123
+ @apply bg-background text-foreground;
124
+ }
125
+ }
package/app/layout.tsx ADDED
@@ -0,0 +1,36 @@
1
+ import type { Metadata } from "next";
2
+ import { Geist, Geist_Mono } from "next/font/google";
3
+ import { Toaster } from "@/components/ui/sonner";
4
+ import "./globals.css";
5
+
6
+ const geistSans = Geist({
7
+ variable: "--font-geist-sans",
8
+ subsets: ["latin"],
9
+ });
10
+
11
+ const geistMono = Geist_Mono({
12
+ variable: "--font-geist-mono",
13
+ subsets: ["latin"],
14
+ });
15
+
16
+ export const metadata: Metadata = {
17
+ title: "Growthman",
18
+ description: "Local mock API server with UI dashboard",
19
+ };
20
+
21
+ export default function RootLayout({
22
+ children,
23
+ }: Readonly<{
24
+ children: React.ReactNode;
25
+ }>) {
26
+ return (
27
+ <html lang="en">
28
+ <body
29
+ className={`${geistSans.variable} ${geistMono.variable} antialiased`}
30
+ >
31
+ {children}
32
+ <Toaster />
33
+ </body>
34
+ </html>
35
+ );
36
+ }
package/app/page.tsx ADDED
@@ -0,0 +1,213 @@
1
+ 'use client'
2
+
3
+ import { useState, useEffect, useCallback } from 'react'
4
+ import { MockEndpoint } from '@/types/endpoint'
5
+ import { EndpointTable } from '@/components/endpoint-table'
6
+ import { EndpointEditDialog } from '@/components/endpoint-edit-dialog'
7
+ import { OpenAPIUploadDialog } from '@/components/openapi-upload-dialog'
8
+ import { ApiTestDialog } from '@/components/api-test-dialog'
9
+ import { Button } from '@/components/ui/button'
10
+ import { toast } from 'sonner'
11
+
12
+ export default function Home() {
13
+ const [endpoints, setEndpoints] = useState<MockEndpoint[]>([])
14
+ const [loading, setLoading] = useState(true)
15
+ const [editDialogOpen, setEditDialogOpen] = useState(false)
16
+ const [uploadDialogOpen, setUploadDialogOpen] = useState(false)
17
+ const [testDialogOpen, setTestDialogOpen] = useState(false)
18
+ const [selectedEndpoint, setSelectedEndpoint] = useState<MockEndpoint | null>(null)
19
+ const [testEndpoint, setTestEndpoint] = useState<MockEndpoint | null>(null)
20
+ const [selectedIds, setSelectedIds] = useState<Set<string>>(new Set())
21
+ const [baseUrl, setBaseUrl] = useState('')
22
+ const [lastModifiedId, setLastModifiedId] = useState<string | null>(null)
23
+
24
+ useEffect(() => {
25
+ setBaseUrl(window.location.origin)
26
+ }, [])
27
+
28
+ const fetchEndpoints = useCallback(async () => {
29
+ try {
30
+ const response = await fetch('/api/endpoints')
31
+ const data = await response.json()
32
+ setEndpoints(data)
33
+ } catch (error) {
34
+ console.error('Failed to fetch endpoints:', error)
35
+ } finally {
36
+ setLoading(false)
37
+ }
38
+ }, [])
39
+
40
+ useEffect(() => {
41
+ fetchEndpoints()
42
+ }, [fetchEndpoints])
43
+
44
+ const handleEdit = (endpoint: MockEndpoint) => {
45
+ setSelectedEndpoint(endpoint)
46
+ setEditDialogOpen(true)
47
+ }
48
+
49
+ const handleCreate = () => {
50
+ setSelectedEndpoint(null)
51
+ setEditDialogOpen(true)
52
+ }
53
+
54
+ const handleTest = (endpoint: MockEndpoint) => {
55
+ setTestEndpoint(endpoint)
56
+ setTestDialogOpen(true)
57
+ }
58
+
59
+ const handleDelete = async (id: string) => {
60
+ if (!confirm('Are you sure you want to delete this endpoint?')) return
61
+
62
+ try {
63
+ const response = await fetch(`/api/endpoints/${id}`, { method: 'DELETE' })
64
+ if (!response.ok) throw new Error('Failed to delete')
65
+ setSelectedIds((prev) => {
66
+ const newSet = new Set(prev)
67
+ newSet.delete(id)
68
+ return newSet
69
+ })
70
+ toast.success('Endpoint deleted successfully')
71
+ fetchEndpoints()
72
+ } catch (error) {
73
+ console.error('Failed to delete endpoint:', error)
74
+ toast.error('Failed to delete endpoint')
75
+ }
76
+ }
77
+
78
+ const handleBulkDelete = async () => {
79
+ if (selectedIds.size === 0) return
80
+ if (!confirm(`Are you sure you want to delete ${selectedIds.size} endpoint(s)?`)) return
81
+
82
+ try {
83
+ const response = await fetch('/api/endpoints/bulk', {
84
+ method: 'DELETE',
85
+ headers: { 'Content-Type': 'application/json' },
86
+ body: JSON.stringify({ ids: Array.from(selectedIds) }),
87
+ })
88
+ if (!response.ok) throw new Error('Failed to delete')
89
+ const count = selectedIds.size
90
+ setSelectedIds(new Set())
91
+ toast.success(`${count} endpoint(s) deleted successfully`)
92
+ fetchEndpoints()
93
+ } catch (error) {
94
+ console.error('Failed to delete endpoints:', error)
95
+ toast.error('Failed to delete endpoints')
96
+ }
97
+ }
98
+
99
+ const handleSave = async (endpoint: Partial<MockEndpoint> & { id?: string }) => {
100
+ try {
101
+ const isUpdate = !!endpoint.id
102
+ const response = isUpdate
103
+ ? await fetch(`/api/endpoints/${endpoint.id}`, {
104
+ method: 'PUT',
105
+ headers: { 'Content-Type': 'application/json' },
106
+ body: JSON.stringify(endpoint),
107
+ })
108
+ : await fetch('/api/endpoints', {
109
+ method: 'POST',
110
+ headers: { 'Content-Type': 'application/json' },
111
+ body: JSON.stringify(endpoint),
112
+ })
113
+
114
+ if (!response.ok) {
115
+ const data = await response.json()
116
+ throw new Error(data.error || 'Failed to save')
117
+ }
118
+
119
+ const savedEndpoint = await response.json()
120
+ setLastModifiedId(savedEndpoint.id)
121
+ toast.success(isUpdate ? 'Endpoint updated successfully' : 'Endpoint created successfully')
122
+ fetchEndpoints()
123
+ } catch (error) {
124
+ console.error('Failed to save endpoint:', error)
125
+ toast.error(error instanceof Error ? error.message : 'Failed to save endpoint')
126
+ }
127
+ }
128
+
129
+ return (
130
+ <div className="min-h-screen bg-gray-50">
131
+ <div className="max-w-7xl mx-auto py-8 px-4 sm:px-6 lg:px-8">
132
+ <div className="flex justify-between items-center mb-8">
133
+ <div>
134
+ <h1 className="text-3xl font-bold text-gray-900">Growthman</h1>
135
+ <p className="mt-1 text-gray-500">
136
+ Manage your mock API endpoints
137
+ </p>
138
+ {baseUrl && (
139
+ <p className="mt-2 text-sm font-mono bg-gray-100 px-3 py-1.5 rounded-md inline-block">
140
+ {baseUrl}/api/mock
141
+ </p>
142
+ )}
143
+ </div>
144
+ <div className="flex gap-3">
145
+ <Button variant="outline" onClick={() => setUploadDialogOpen(true)}>
146
+ Import OpenAPI
147
+ </Button>
148
+ <Button onClick={handleCreate}>
149
+ + New Endpoint
150
+ </Button>
151
+ </div>
152
+ </div>
153
+
154
+ {selectedIds.size > 0 && (
155
+ <div className="mb-4 flex items-center gap-4 p-3 bg-blue-50 border border-blue-200 rounded-lg">
156
+ <span className="text-sm text-blue-800">
157
+ {selectedIds.size} endpoint(s) selected
158
+ </span>
159
+ <Button
160
+ variant="destructive"
161
+ size="sm"
162
+ onClick={handleBulkDelete}
163
+ >
164
+ Delete Selected
165
+ </Button>
166
+ <Button
167
+ variant="ghost"
168
+ size="sm"
169
+ onClick={() => setSelectedIds(new Set())}
170
+ >
171
+ Clear Selection
172
+ </Button>
173
+ </div>
174
+ )}
175
+
176
+ <div className="bg-white shadow rounded-lg">
177
+ {loading ? (
178
+ <div className="p-8 text-center text-gray-500">Loading...</div>
179
+ ) : (
180
+ <EndpointTable
181
+ endpoints={endpoints}
182
+ onEdit={handleEdit}
183
+ onDelete={handleDelete}
184
+ onTest={handleTest}
185
+ selectedIds={selectedIds}
186
+ onSelectionChange={setSelectedIds}
187
+ lastModifiedId={lastModifiedId}
188
+ />
189
+ )}
190
+ </div>
191
+ </div>
192
+
193
+ <EndpointEditDialog
194
+ endpoint={selectedEndpoint}
195
+ open={editDialogOpen}
196
+ onOpenChange={setEditDialogOpen}
197
+ onSave={handleSave}
198
+ />
199
+
200
+ <OpenAPIUploadDialog
201
+ open={uploadDialogOpen}
202
+ onOpenChange={setUploadDialogOpen}
203
+ onImportComplete={fetchEndpoints}
204
+ />
205
+
206
+ <ApiTestDialog
207
+ endpoint={testEndpoint}
208
+ open={testDialogOpen}
209
+ onOpenChange={setTestDialogOpen}
210
+ />
211
+ </div>
212
+ )
213
+ }
package/bin/cli.js CHANGED
@@ -22,11 +22,48 @@ const env = {
22
22
  DATABASE_URL: `file:${dbPath}`,
23
23
  };
24
24
 
25
+ // CLI 바이너리 경로 찾기
26
+ function getBinPath(packageName, binName) {
27
+ try {
28
+ const pkgJsonPath = require.resolve(`${packageName}/package.json`, {
29
+ paths: [packageDir],
30
+ });
31
+ const pkgDir = path.dirname(pkgJsonPath);
32
+ const pkgJson = require(pkgJsonPath);
33
+
34
+ let binRelPath;
35
+ if (typeof pkgJson.bin === 'string') {
36
+ binRelPath = pkgJson.bin;
37
+ } else if (pkgJson.bin && pkgJson.bin[binName]) {
38
+ binRelPath = pkgJson.bin[binName];
39
+ }
40
+
41
+ if (binRelPath) {
42
+ return path.join(pkgDir, binRelPath);
43
+ }
44
+ } catch (e) {
45
+ // fallback to node_modules/.bin
46
+ }
47
+ return path.join(packageDir, 'node_modules', '.bin', binName);
48
+ }
49
+
25
50
  // DB가 없으면 생성
26
51
  if (!fs.existsSync(dbPath)) {
27
52
  console.log('Initializing database...');
28
- const prismaPath = path.join(packageDir, 'node_modules', '.bin', 'prisma');
29
- execSync(`"${prismaPath}" db push`, {
53
+ const prismaPath = getBinPath('prisma', 'prisma');
54
+ execSync(`node "${prismaPath}" db push`, {
55
+ cwd: packageDir,
56
+ stdio: 'inherit',
57
+ env,
58
+ });
59
+ }
60
+
61
+ // .next 폴더가 없으면 빌드
62
+ const nextDir = path.join(packageDir, '.next');
63
+ if (!fs.existsSync(nextDir)) {
64
+ console.log('Building application (first run)...');
65
+ const nextPath = getBinPath('next', 'next');
66
+ execSync(`node "${nextPath}" build`, {
30
67
  cwd: packageDir,
31
68
  stdio: 'inherit',
32
69
  env,
@@ -39,8 +76,8 @@ const url = `http://localhost:${port}`;
39
76
  console.log(`Database: ${dbPath}`);
40
77
  console.log(`Starting mock server at ${url}`);
41
78
 
42
- const nextPath = path.join(packageDir, 'node_modules', '.bin', 'next');
43
- const server = spawn(nextPath, ['start', '-p', String(port)], {
79
+ const nextPath = getBinPath('next', 'next');
80
+ const server = spawn('node', [nextPath, 'start', '-p', String(port)], {
44
81
  cwd: packageDir,
45
82
  stdio: 'inherit',
46
83
  env,