@kurly-growth/growthman 0.1.13 → 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 +12 -2
  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/rD3QdLXPN9C3vquucAUu6/_buildManifest.js +0 -11
  280. package/.next/static/rD3QdLXPN9C3vquucAUu6/_clientMiddlewareManifest.json +0 -1
  281. package/.next/static/rD3QdLXPN9C3vquucAUu6/_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
@@ -0,0 +1,181 @@
1
+ 'use client'
2
+
3
+ import { useState, useEffect } from 'react'
4
+ import dynamic from 'next/dynamic'
5
+ import { MockEndpoint } from '@/types/endpoint'
6
+ import {
7
+ Dialog,
8
+ DialogContent,
9
+ DialogHeader,
10
+ DialogTitle,
11
+ DialogFooter,
12
+ } from '@/components/ui/dialog'
13
+ import { Button } from '@/components/ui/button'
14
+ import { Input } from '@/components/ui/input'
15
+ import { Label } from '@/components/ui/label'
16
+
17
+ const MonacoEditor = dynamic(() => import('@monaco-editor/react'), {
18
+ ssr: false,
19
+ loading: () => <div className="h-[400px] bg-gray-100 animate-pulse rounded" />,
20
+ })
21
+
22
+ interface EndpointEditDialogProps {
23
+ endpoint: MockEndpoint | null
24
+ open: boolean
25
+ onOpenChange: (open: boolean) => void
26
+ onSave: (endpoint: Partial<MockEndpoint> & { id?: string }) => void
27
+ }
28
+
29
+ const HTTP_METHODS = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE']
30
+
31
+ export function EndpointEditDialog({
32
+ endpoint,
33
+ open,
34
+ onOpenChange,
35
+ onSave,
36
+ }: EndpointEditDialogProps) {
37
+ const [path, setPath] = useState('')
38
+ const [method, setMethod] = useState('GET')
39
+ const [description, setDescription] = useState('')
40
+ const [statusCode, setStatusCode] = useState(200)
41
+ const [responseBody, setResponseBody] = useState('{}')
42
+ const [jsonError, setJsonError] = useState<string | null>(null)
43
+
44
+ useEffect(() => {
45
+ if (endpoint) {
46
+ setPath(endpoint.path)
47
+ setMethod(endpoint.method)
48
+ setDescription(endpoint.description || '')
49
+ setStatusCode(endpoint.statusCode)
50
+ setResponseBody(JSON.stringify(endpoint.responseBody, null, 2))
51
+ } else {
52
+ setPath('')
53
+ setMethod('GET')
54
+ setDescription('')
55
+ setStatusCode(200)
56
+ setResponseBody('{}')
57
+ }
58
+ setJsonError(null)
59
+ }, [endpoint, open])
60
+
61
+ const handleSave = () => {
62
+ try {
63
+ const parsedBody = JSON.parse(responseBody)
64
+ setJsonError(null)
65
+ onSave({
66
+ id: endpoint?.id,
67
+ path,
68
+ method,
69
+ description: description || null,
70
+ statusCode,
71
+ responseBody: parsedBody,
72
+ })
73
+ onOpenChange(false)
74
+ } catch {
75
+ setJsonError('Invalid JSON format')
76
+ }
77
+ }
78
+
79
+ return (
80
+ <Dialog open={open} onOpenChange={onOpenChange}>
81
+ <DialogContent className="sm:max-w-[70vw] h-[90vh] flex flex-col">
82
+ <DialogHeader>
83
+ <DialogTitle>
84
+ {endpoint ? 'Edit Endpoint' : 'Create New Endpoint'}
85
+ </DialogTitle>
86
+ </DialogHeader>
87
+
88
+ <div className="grid gap-4 py-4 flex-1 overflow-hidden">
89
+ <div className="flex items-center gap-4">
90
+ <Label htmlFor="method" className="w-28 text-right shrink-0">
91
+ Method
92
+ </Label>
93
+ <select
94
+ id="method"
95
+ value={method}
96
+ onChange={(e) => setMethod(e.target.value)}
97
+ className="flex-1 h-10 rounded-md border border-input bg-background px-3 py-2"
98
+ >
99
+ {HTTP_METHODS.map((m) => (
100
+ <option key={m} value={m}>
101
+ {m}
102
+ </option>
103
+ ))}
104
+ </select>
105
+ </div>
106
+
107
+ <div className="flex items-center gap-4">
108
+ <Label htmlFor="path" className="w-28 text-right shrink-0">
109
+ Path
110
+ </Label>
111
+ <Input
112
+ id="path"
113
+ value={path}
114
+ onChange={(e) => setPath(e.target.value)}
115
+ placeholder="/v1/users/:userId"
116
+ className="flex-1"
117
+ />
118
+ </div>
119
+
120
+ <div className="flex items-center gap-4">
121
+ <Label htmlFor="description" className="w-28 text-right shrink-0">
122
+ Description
123
+ </Label>
124
+ <Input
125
+ id="description"
126
+ value={description}
127
+ onChange={(e) => setDescription(e.target.value)}
128
+ placeholder="API description"
129
+ className="flex-1"
130
+ />
131
+ </div>
132
+
133
+ <div className="flex items-center gap-4">
134
+ <Label htmlFor="statusCode" className="w-28 text-right shrink-0">
135
+ Status Code
136
+ </Label>
137
+ <Input
138
+ id="statusCode"
139
+ type="number"
140
+ value={statusCode}
141
+ onChange={(e) => setStatusCode(Number(e.target.value))}
142
+ className="flex-1"
143
+ />
144
+ </div>
145
+
146
+ <div className="flex items-start gap-4">
147
+ <Label className="w-28 text-right shrink-0 pt-2">Response Body</Label>
148
+ <div className="flex-1">
149
+ <div className="border rounded-md overflow-hidden">
150
+ <MonacoEditor
151
+ height="calc(85vh - 320px)"
152
+ language="json"
153
+ theme="vs-dark"
154
+ value={responseBody}
155
+ onChange={(value) => setResponseBody(value || '{}')}
156
+ options={{
157
+ minimap: { enabled: false },
158
+ fontSize: 14,
159
+ formatOnPaste: true,
160
+ automaticLayout: true,
161
+ scrollBeyondLastLine: false,
162
+ }}
163
+ />
164
+ </div>
165
+ {jsonError && (
166
+ <p className="text-red-500 text-sm mt-2">{jsonError}</p>
167
+ )}
168
+ </div>
169
+ </div>
170
+ </div>
171
+
172
+ <DialogFooter className="shrink-0">
173
+ <Button variant="outline" onClick={() => onOpenChange(false)}>
174
+ Cancel
175
+ </Button>
176
+ <Button onClick={handleSave}>Save</Button>
177
+ </DialogFooter>
178
+ </DialogContent>
179
+ </Dialog>
180
+ )
181
+ }
@@ -0,0 +1,147 @@
1
+ 'use client'
2
+
3
+ import { MockEndpoint } from '@/types/endpoint'
4
+ import {
5
+ Table,
6
+ TableBody,
7
+ TableCell,
8
+ TableHead,
9
+ TableHeader,
10
+ TableRow,
11
+ } from '@/components/ui/table'
12
+ import { Button } from '@/components/ui/button'
13
+ import { Checkbox } from '@/components/ui/checkbox'
14
+
15
+ interface EndpointTableProps {
16
+ endpoints: MockEndpoint[]
17
+ onEdit: (endpoint: MockEndpoint) => void
18
+ onDelete: (id: string) => void
19
+ onTest: (endpoint: MockEndpoint) => void
20
+ selectedIds: Set<string>
21
+ onSelectionChange: (ids: Set<string>) => void
22
+ lastModifiedId?: string | null
23
+ }
24
+
25
+ const methodColors: Record<string, string> = {
26
+ GET: 'bg-green-100 text-green-800',
27
+ POST: 'bg-blue-100 text-blue-800',
28
+ PUT: 'bg-yellow-100 text-yellow-800',
29
+ PATCH: 'bg-orange-100 text-orange-800',
30
+ DELETE: 'bg-red-100 text-red-800',
31
+ }
32
+
33
+ export function EndpointTable({
34
+ endpoints,
35
+ onEdit,
36
+ onDelete,
37
+ onTest,
38
+ selectedIds,
39
+ onSelectionChange,
40
+ lastModifiedId,
41
+ }: EndpointTableProps) {
42
+ const allSelected = endpoints.length > 0 && endpoints.every((e) => selectedIds.has(e.id))
43
+ const someSelected = endpoints.some((e) => selectedIds.has(e.id)) && !allSelected
44
+
45
+ const handleSelectAll = (checked: boolean) => {
46
+ if (checked) {
47
+ onSelectionChange(new Set(endpoints.map((e) => e.id)))
48
+ } else {
49
+ onSelectionChange(new Set())
50
+ }
51
+ }
52
+
53
+ const handleSelectOne = (id: string, checked: boolean) => {
54
+ const newSet = new Set(selectedIds)
55
+ if (checked) {
56
+ newSet.add(id)
57
+ } else {
58
+ newSet.delete(id)
59
+ }
60
+ onSelectionChange(newSet)
61
+ }
62
+
63
+ return (
64
+ <Table>
65
+ <TableHeader>
66
+ <TableRow>
67
+ <TableHead className="w-[50px]">
68
+ <Checkbox
69
+ checked={allSelected}
70
+ ref={(el) => {
71
+ if (el) {
72
+ (el as unknown as HTMLInputElement).indeterminate = someSelected
73
+ }
74
+ }}
75
+ onCheckedChange={(checked) => handleSelectAll(checked === true)}
76
+ aria-label="Select all"
77
+ />
78
+ </TableHead>
79
+ <TableHead className="w-[100px]">Method</TableHead>
80
+ <TableHead>Path</TableHead>
81
+ <TableHead>Description</TableHead>
82
+ <TableHead className="w-[200px]">Actions</TableHead>
83
+ </TableRow>
84
+ </TableHeader>
85
+ <TableBody>
86
+ {endpoints.length === 0 ? (
87
+ <TableRow>
88
+ <TableCell colSpan={5} className="text-center text-gray-500">
89
+ No endpoints registered yet
90
+ </TableCell>
91
+ </TableRow>
92
+ ) : (
93
+ endpoints.map((endpoint) => (
94
+ <TableRow
95
+ key={endpoint.id}
96
+ className={lastModifiedId === endpoint.id ? 'bg-yellow-50' : ''}
97
+ >
98
+ <TableCell>
99
+ <Checkbox
100
+ checked={selectedIds.has(endpoint.id)}
101
+ onCheckedChange={(checked) => handleSelectOne(endpoint.id, checked === true)}
102
+ aria-label={`Select ${endpoint.path}`}
103
+ />
104
+ </TableCell>
105
+ <TableCell>
106
+ <span
107
+ className={`px-2 py-1 rounded text-xs font-medium ${methodColors[endpoint.method] || 'bg-gray-100'}`}
108
+ >
109
+ {endpoint.method}
110
+ </span>
111
+ </TableCell>
112
+ <TableCell className="font-mono text-sm">{endpoint.path}</TableCell>
113
+ <TableCell className="text-gray-600">
114
+ {endpoint.description || '-'}
115
+ </TableCell>
116
+ <TableCell>
117
+ <div className="flex gap-2">
118
+ <Button
119
+ variant="secondary"
120
+ size="sm"
121
+ onClick={() => onTest(endpoint)}
122
+ >
123
+ Test
124
+ </Button>
125
+ <Button
126
+ variant="outline"
127
+ size="sm"
128
+ onClick={() => onEdit(endpoint)}
129
+ >
130
+ Edit
131
+ </Button>
132
+ <Button
133
+ variant="destructive"
134
+ size="sm"
135
+ onClick={() => onDelete(endpoint.id)}
136
+ >
137
+ Delete
138
+ </Button>
139
+ </div>
140
+ </TableCell>
141
+ </TableRow>
142
+ ))
143
+ )}
144
+ </TableBody>
145
+ </Table>
146
+ )
147
+ }
@@ -0,0 +1,213 @@
1
+ 'use client'
2
+
3
+ import { useState, useRef } from 'react'
4
+ import {
5
+ Dialog,
6
+ DialogContent,
7
+ DialogHeader,
8
+ DialogTitle,
9
+ DialogFooter,
10
+ } from '@/components/ui/dialog'
11
+ import { Button } from '@/components/ui/button'
12
+ import { Input } from '@/components/ui/input'
13
+ import { Label } from '@/components/ui/label'
14
+ import { toast } from 'sonner'
15
+
16
+ interface OpenAPIUploadDialogProps {
17
+ open: boolean
18
+ onOpenChange: (open: boolean) => void
19
+ onImportComplete: () => void
20
+ }
21
+
22
+ type ImportMode = 'url' | 'file'
23
+
24
+ export function OpenAPIUploadDialog({
25
+ open,
26
+ onOpenChange,
27
+ onImportComplete,
28
+ }: OpenAPIUploadDialogProps) {
29
+ const [mode, setMode] = useState<ImportMode>('url')
30
+ const [url, setUrl] = useState('')
31
+ const [file, setFile] = useState<File | null>(null)
32
+ const [pathPrefix, setPathPrefix] = useState('')
33
+ const [loading, setLoading] = useState(false)
34
+ const [error, setError] = useState<string | null>(null)
35
+ const fileInputRef = useRef<HTMLInputElement>(null)
36
+
37
+ const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
38
+ const selectedFile = e.target.files?.[0]
39
+ if (selectedFile) {
40
+ setFile(selectedFile)
41
+ setError(null)
42
+ }
43
+ }
44
+
45
+ const handleImport = async () => {
46
+ setLoading(true)
47
+ setError(null)
48
+
49
+ try {
50
+ let response: Response
51
+
52
+ if (mode === 'url') {
53
+ if (!url.trim()) {
54
+ throw new Error('Please enter a URL')
55
+ }
56
+ response = await fetch('/api/endpoints/sync', {
57
+ method: 'POST',
58
+ headers: { 'Content-Type': 'application/json' },
59
+ body: JSON.stringify({ url: url.trim(), pathPrefix: pathPrefix.trim() || undefined }),
60
+ })
61
+ } else {
62
+ if (!file) {
63
+ throw new Error('Please select a file')
64
+ }
65
+ const text = await file.text()
66
+ const spec = JSON.parse(text)
67
+ response = await fetch('/api/endpoints/import', {
68
+ method: 'POST',
69
+ headers: { 'Content-Type': 'application/json' },
70
+ body: JSON.stringify({ spec, pathPrefix: pathPrefix.trim() || undefined }),
71
+ })
72
+ }
73
+
74
+ const data = await response.json()
75
+
76
+ if (!response.ok) {
77
+ throw new Error(data.error || 'Import failed')
78
+ }
79
+
80
+ const succeeded = data.succeeded ?? data.created
81
+ const failed = data.failed ?? 0
82
+ if (failed > 0) {
83
+ toast.warning(`Imported ${succeeded} endpoints (${failed} failed)`)
84
+ } else {
85
+ toast.success(`Successfully imported ${succeeded} endpoints`)
86
+ }
87
+ onImportComplete()
88
+ handleClose()
89
+ } catch (err) {
90
+ const message = err instanceof Error ? err.message : 'Import failed'
91
+ setError(message)
92
+ toast.error(message)
93
+ } finally {
94
+ setLoading(false)
95
+ }
96
+ }
97
+
98
+ const handleClose = () => {
99
+ setUrl('')
100
+ setFile(null)
101
+ setPathPrefix('')
102
+ setError(null)
103
+ onOpenChange(false)
104
+ }
105
+
106
+ const canImport = mode === 'url' ? url.trim().length > 0 : file !== null
107
+
108
+ return (
109
+ <Dialog open={open} onOpenChange={handleClose}>
110
+ <DialogContent className="sm:max-w-lg">
111
+ <DialogHeader>
112
+ <DialogTitle>Import OpenAPI Specification</DialogTitle>
113
+ </DialogHeader>
114
+
115
+ <div className="py-4 space-y-4">
116
+ {/* Mode Toggle */}
117
+ <div className="flex gap-2">
118
+ <Button
119
+ type="button"
120
+ variant={mode === 'url' ? 'default' : 'outline'}
121
+ size="sm"
122
+ onClick={() => setMode('url')}
123
+ >
124
+ From URL
125
+ </Button>
126
+ <Button
127
+ type="button"
128
+ variant={mode === 'file' ? 'default' : 'outline'}
129
+ size="sm"
130
+ onClick={() => setMode('file')}
131
+ >
132
+ From File
133
+ </Button>
134
+ </div>
135
+
136
+ {/* URL Input */}
137
+ {mode === 'url' && (
138
+ <div className="space-y-2">
139
+ <Label htmlFor="url">OpenAPI JSON URL</Label>
140
+ <Input
141
+ id="url"
142
+ type="url"
143
+ placeholder="https://api.example.com/api-docs-json"
144
+ value={url}
145
+ onChange={(e) => {
146
+ setUrl(e.target.value)
147
+ setError(null)
148
+ }}
149
+ />
150
+ <p className="text-xs text-gray-500">
151
+ Enter the URL to your OpenAPI/Swagger JSON specification
152
+ </p>
153
+ </div>
154
+ )}
155
+
156
+ {/* File Upload */}
157
+ {mode === 'file' && (
158
+ <div
159
+ className="border-2 border-dashed rounded-lg p-8 text-center cursor-pointer hover:border-gray-400 transition-colors"
160
+ onClick={() => fileInputRef.current?.click()}
161
+ >
162
+ <input
163
+ ref={fileInputRef}
164
+ type="file"
165
+ accept=".json"
166
+ onChange={handleFileChange}
167
+ className="hidden"
168
+ />
169
+ {file ? (
170
+ <p className="text-sm">
171
+ Selected: <span className="font-medium">{file.name}</span>
172
+ </p>
173
+ ) : (
174
+ <p className="text-gray-500">
175
+ Click to select an OpenAPI JSON file
176
+ </p>
177
+ )}
178
+ </div>
179
+ )}
180
+
181
+ {/* Path Prefix */}
182
+ <div className="space-y-2">
183
+ <Label htmlFor="pathPrefix">Path Prefix (optional)</Label>
184
+ <Input
185
+ id="pathPrefix"
186
+ type="text"
187
+ placeholder="/reward"
188
+ value={pathPrefix}
189
+ onChange={(e) => setPathPrefix(e.target.value)}
190
+ />
191
+ <p className="text-xs text-gray-500">
192
+ Prefix to add to all imported paths (e.g., /reward → /reward/v1/users/:id)
193
+ </p>
194
+ </div>
195
+
196
+ {/* Error */}
197
+ {error && (
198
+ <p className="text-red-500 text-sm">{error}</p>
199
+ )}
200
+ </div>
201
+
202
+ <DialogFooter>
203
+ <Button variant="outline" onClick={handleClose}>
204
+ Cancel
205
+ </Button>
206
+ <Button onClick={handleImport} disabled={!canImport || loading}>
207
+ {loading ? 'Importing...' : 'Import'}
208
+ </Button>
209
+ </DialogFooter>
210
+ </DialogContent>
211
+ </Dialog>
212
+ )
213
+ }
@@ -0,0 +1,62 @@
1
+ import * as React from "react"
2
+ import { Slot } from "@radix-ui/react-slot"
3
+ import { cva, type VariantProps } from "class-variance-authority"
4
+
5
+ import { cn } from "@/lib/utils"
6
+
7
+ const buttonVariants = cva(
8
+ "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
9
+ {
10
+ variants: {
11
+ variant: {
12
+ default: "bg-primary text-primary-foreground hover:bg-primary/90",
13
+ destructive:
14
+ "bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
15
+ outline:
16
+ "border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50",
17
+ secondary:
18
+ "bg-secondary text-secondary-foreground hover:bg-secondary/80",
19
+ ghost:
20
+ "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
21
+ link: "text-primary underline-offset-4 hover:underline",
22
+ },
23
+ size: {
24
+ default: "h-9 px-4 py-2 has-[>svg]:px-3",
25
+ sm: "h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5",
26
+ lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
27
+ icon: "size-9",
28
+ "icon-sm": "size-8",
29
+ "icon-lg": "size-10",
30
+ },
31
+ },
32
+ defaultVariants: {
33
+ variant: "default",
34
+ size: "default",
35
+ },
36
+ }
37
+ )
38
+
39
+ function Button({
40
+ className,
41
+ variant = "default",
42
+ size = "default",
43
+ asChild = false,
44
+ ...props
45
+ }: React.ComponentProps<"button"> &
46
+ VariantProps<typeof buttonVariants> & {
47
+ asChild?: boolean
48
+ }) {
49
+ const Comp = asChild ? Slot : "button"
50
+
51
+ return (
52
+ <Comp
53
+ data-slot="button"
54
+ data-variant={variant}
55
+ data-size={size}
56
+ className={cn(buttonVariants({ variant, size, className }))}
57
+ {...props}
58
+ />
59
+ )
60
+ }
61
+
62
+ export { Button, buttonVariants }
@@ -0,0 +1,32 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import * as CheckboxPrimitive from "@radix-ui/react-checkbox"
5
+ import { CheckIcon } from "lucide-react"
6
+
7
+ import { cn } from "@/lib/utils"
8
+
9
+ function Checkbox({
10
+ className,
11
+ ...props
12
+ }: React.ComponentProps<typeof CheckboxPrimitive.Root>) {
13
+ return (
14
+ <CheckboxPrimitive.Root
15
+ data-slot="checkbox"
16
+ className={cn(
17
+ "peer border-input dark:bg-input/30 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground dark:data-[state=checked]:bg-primary data-[state=checked]:border-primary focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive size-4 shrink-0 rounded-[4px] border shadow-xs transition-shadow outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50",
18
+ className
19
+ )}
20
+ {...props}
21
+ >
22
+ <CheckboxPrimitive.Indicator
23
+ data-slot="checkbox-indicator"
24
+ className="grid place-content-center text-current transition-none"
25
+ >
26
+ <CheckIcon className="size-3.5" />
27
+ </CheckboxPrimitive.Indicator>
28
+ </CheckboxPrimitive.Root>
29
+ )
30
+ }
31
+
32
+ export { Checkbox }