@geekmidas/cli 0.3.0 → 0.5.0

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 (309) hide show
  1. package/README.md +488 -71
  2. package/dist/CronGenerator-BPTqNYOR.d.cts +14 -0
  3. package/dist/{CronGenerator-Bh26MaNA.mjs → CronGenerator-CCRYptuT.mjs} +2 -2
  4. package/dist/{CronGenerator-Bh26MaNA.mjs.map → CronGenerator-CCRYptuT.mjs.map} +1 -1
  5. package/dist/{CronGenerator-C6MF8rlG.cjs → CronGenerator-D4TWXQbh.cjs} +2 -2
  6. package/dist/{CronGenerator-C6MF8rlG.cjs.map → CronGenerator-D4TWXQbh.cjs.map} +1 -1
  7. package/dist/CronGenerator-YAj59JUd.d.mts +14 -0
  8. package/dist/EndpointGenerator-ChAD1INz.d.cts +19 -0
  9. package/dist/EndpointGenerator-Cj3O1U8-.d.mts +19 -0
  10. package/dist/{EndpointGenerator-CWh18d92.mjs → EndpointGenerator-DGivkPLT.mjs} +77 -7
  11. package/dist/EndpointGenerator-DGivkPLT.mjs.map +1 -0
  12. package/dist/{EndpointGenerator-C73wNoih.cjs → EndpointGenerator-npWEDoK2.cjs} +77 -7
  13. package/dist/EndpointGenerator-npWEDoK2.cjs.map +1 -0
  14. package/dist/FunctionGenerator-429-9NER.d.cts +14 -0
  15. package/dist/FunctionGenerator-BQ4ehoID.d.mts +14 -0
  16. package/dist/{FunctionGenerator-BNE_GC7N.mjs → FunctionGenerator-CVk0h8tO.mjs} +2 -2
  17. package/dist/{FunctionGenerator-BNE_GC7N.mjs.map → FunctionGenerator-CVk0h8tO.mjs.map} +1 -1
  18. package/dist/{FunctionGenerator-FgZUTd8L.cjs → FunctionGenerator-DYTnyr4c.cjs} +2 -2
  19. package/dist/{FunctionGenerator-FgZUTd8L.cjs.map → FunctionGenerator-DYTnyr4c.cjs.map} +1 -1
  20. package/dist/Generator-BjHK_qce.d.mts +27 -0
  21. package/dist/{Generator-UanJW0_V.mjs → Generator-CDt4pB3W.mjs} +1 -1
  22. package/dist/{Generator-UanJW0_V.mjs.map → Generator-CDt4pB3W.mjs.map} +1 -1
  23. package/dist/{Generator-CDoEXCDg.cjs → Generator-CLVplqm2.cjs} +1 -1
  24. package/dist/{Generator-CDoEXCDg.cjs.map → Generator-CLVplqm2.cjs.map} +1 -1
  25. package/dist/Generator-DxQMCQp7.d.cts +27 -0
  26. package/dist/OpenApiTsGenerator-Be-sKGTT.cjs +501 -0
  27. package/dist/OpenApiTsGenerator-Be-sKGTT.cjs.map +1 -0
  28. package/dist/OpenApiTsGenerator-C4mHHaku.mjs +495 -0
  29. package/dist/OpenApiTsGenerator-C4mHHaku.mjs.map +1 -0
  30. package/dist/SubscriberGenerator-7uX42xyG.d.mts +15 -0
  31. package/dist/{SubscriberGenerator-Dnlj_1FK.mjs → SubscriberGenerator-DABaJXML.mjs} +2 -2
  32. package/dist/{SubscriberGenerator-Dnlj_1FK.mjs.map → SubscriberGenerator-DABaJXML.mjs.map} +1 -1
  33. package/dist/{SubscriberGenerator-Bd-a7aiw.cjs → SubscriberGenerator-D_zpNGFr.cjs} +2 -2
  34. package/dist/{SubscriberGenerator-Bd-a7aiw.cjs.map → SubscriberGenerator-D_zpNGFr.cjs.map} +1 -1
  35. package/dist/SubscriberGenerator-Dtb3HS4i.d.cts +15 -0
  36. package/dist/api-B3SCEHPf.cjs +190 -0
  37. package/dist/api-B3SCEHPf.cjs.map +1 -0
  38. package/dist/api-BKIN0s0S.mjs +184 -0
  39. package/dist/api-BKIN0s0S.mjs.map +1 -0
  40. package/dist/build/index.cjs +11 -10
  41. package/dist/build/index.d.cts +7 -0
  42. package/dist/build/index.d.mts +7 -0
  43. package/dist/build/index.mjs +11 -10
  44. package/dist/build/manifests.cjs +1 -1
  45. package/dist/build/manifests.d.cts +13 -0
  46. package/dist/build/manifests.d.mts +13 -0
  47. package/dist/build/manifests.mjs +1 -1
  48. package/dist/build/providerResolver.cjs +1 -1
  49. package/dist/build/providerResolver.d.cts +23 -0
  50. package/dist/build/providerResolver.d.mts +23 -0
  51. package/dist/build/providerResolver.mjs +1 -1
  52. package/dist/build/types.d.cts +3 -0
  53. package/dist/build/types.d.mts +3 -0
  54. package/dist/{build-C6uEGRj8.mjs → build-B8C_qHir.mjs} +15 -13
  55. package/dist/build-B8C_qHir.mjs.map +1 -0
  56. package/dist/{build-CBYBPZpC.cjs → build-D0Wr49bf.cjs} +15 -13
  57. package/dist/build-D0Wr49bf.cjs.map +1 -0
  58. package/dist/config-Ba-Gbpbc.d.cts +11 -0
  59. package/dist/config-Bq72aj8e.mjs +75 -0
  60. package/dist/config-Bq72aj8e.mjs.map +1 -0
  61. package/dist/config-CFls09Ey.cjs +93 -0
  62. package/dist/config-CFls09Ey.cjs.map +1 -0
  63. package/dist/config-CLEDqKO3.cjs +157 -0
  64. package/dist/config-CLEDqKO3.cjs.map +1 -0
  65. package/dist/config-DBsmMDhf.d.mts +11 -0
  66. package/dist/config-Dp8RonV_.mjs +151 -0
  67. package/dist/config-Dp8RonV_.mjs.map +1 -0
  68. package/dist/config.cjs +4 -2
  69. package/dist/config.d.cts +48 -0
  70. package/dist/config.d.mts +48 -0
  71. package/dist/config.mjs +2 -2
  72. package/dist/dev/index.cjs +12 -10
  73. package/dist/dev/index.d.cts +36 -0
  74. package/dist/dev/index.d.mts +36 -0
  75. package/dist/dev/index.mjs +10 -10
  76. package/dist/dev-B734w3L1.mjs +343 -0
  77. package/dist/dev-B734w3L1.mjs.map +1 -0
  78. package/dist/{dev-DbtyToc7.cjs → dev-DHqYn8k4.cjs} +161 -47
  79. package/dist/dev-DHqYn8k4.cjs.map +1 -0
  80. package/dist/docker-5d8Yh5_X.cjs +119 -0
  81. package/dist/docker-5d8Yh5_X.cjs.map +1 -0
  82. package/dist/docker-DlUqdFle.mjs +113 -0
  83. package/dist/docker-DlUqdFle.mjs.map +1 -0
  84. package/dist/env-B-OKjgI4.cjs +144 -0
  85. package/dist/env-B-OKjgI4.cjs.map +1 -0
  86. package/dist/env-HfuJRlg5.d.cts +11 -0
  87. package/dist/env-nd-iQPYM.d.mts +11 -0
  88. package/dist/env-tv1HlZlw.mjs +138 -0
  89. package/dist/env-tv1HlZlw.mjs.map +1 -0
  90. package/dist/generators/CronGenerator.cjs +2 -2
  91. package/dist/generators/CronGenerator.d.cts +5 -0
  92. package/dist/generators/CronGenerator.d.mts +5 -0
  93. package/dist/generators/CronGenerator.mjs +2 -2
  94. package/dist/generators/EndpointGenerator.cjs +2 -2
  95. package/dist/generators/EndpointGenerator.d.cts +5 -0
  96. package/dist/generators/EndpointGenerator.d.mts +5 -0
  97. package/dist/generators/EndpointGenerator.mjs +2 -2
  98. package/dist/generators/FunctionGenerator.cjs +2 -2
  99. package/dist/generators/FunctionGenerator.d.cts +5 -0
  100. package/dist/generators/FunctionGenerator.d.mts +5 -0
  101. package/dist/generators/FunctionGenerator.mjs +2 -2
  102. package/dist/generators/Generator.cjs +1 -1
  103. package/dist/generators/Generator.d.cts +4 -0
  104. package/dist/generators/Generator.d.mts +4 -0
  105. package/dist/generators/Generator.mjs +1 -1
  106. package/dist/generators/OpenApiTsGenerator.cjs +3 -0
  107. package/dist/generators/OpenApiTsGenerator.d.cts +44 -0
  108. package/dist/generators/OpenApiTsGenerator.d.mts +44 -0
  109. package/dist/generators/OpenApiTsGenerator.mjs +3 -0
  110. package/dist/generators/SubscriberGenerator.cjs +2 -2
  111. package/dist/generators/SubscriberGenerator.d.cts +5 -0
  112. package/dist/generators/SubscriberGenerator.d.mts +5 -0
  113. package/dist/generators/SubscriberGenerator.mjs +2 -2
  114. package/dist/generators/index.cjs +6 -6
  115. package/dist/generators/index.d.cts +8 -0
  116. package/dist/generators/index.d.mts +8 -0
  117. package/dist/generators/index.mjs +6 -6
  118. package/dist/index-C523No_B.d.mts +64 -0
  119. package/dist/index-DrzN4xkQ.d.cts +64 -0
  120. package/dist/index.cjs +56 -18
  121. package/dist/index.cjs.map +1 -1
  122. package/dist/index.d.cts +1 -0
  123. package/dist/index.d.mts +1 -0
  124. package/dist/index.mjs +56 -18
  125. package/dist/index.mjs.map +1 -1
  126. package/dist/init/generators/config.cjs +3 -0
  127. package/dist/init/generators/config.d.cts +3 -0
  128. package/dist/init/generators/config.d.mts +3 -0
  129. package/dist/init/generators/config.mjs +3 -0
  130. package/dist/init/generators/docker.cjs +3 -0
  131. package/dist/init/generators/docker.d.cts +11 -0
  132. package/dist/init/generators/docker.d.mts +11 -0
  133. package/dist/init/generators/docker.mjs +3 -0
  134. package/dist/init/generators/env.cjs +3 -0
  135. package/dist/init/generators/env.d.cts +3 -0
  136. package/dist/init/generators/env.d.mts +3 -0
  137. package/dist/init/generators/env.mjs +3 -0
  138. package/dist/init/generators/index.cjs +9 -0
  139. package/dist/init/generators/index.d.cts +6 -0
  140. package/dist/init/generators/index.d.mts +6 -0
  141. package/dist/init/generators/index.mjs +6 -0
  142. package/dist/init/generators/models.cjs +3 -0
  143. package/dist/init/generators/models.d.cts +11 -0
  144. package/dist/init/generators/models.d.mts +11 -0
  145. package/dist/init/generators/models.mjs +3 -0
  146. package/dist/init/generators/monorepo.cjs +3 -0
  147. package/dist/init/generators/monorepo.d.cts +11 -0
  148. package/dist/init/generators/monorepo.d.mts +11 -0
  149. package/dist/init/generators/monorepo.mjs +3 -0
  150. package/dist/init/generators/package.cjs +3 -0
  151. package/dist/init/generators/package.d.cts +3 -0
  152. package/dist/init/generators/package.d.mts +3 -0
  153. package/dist/init/generators/package.mjs +3 -0
  154. package/dist/init/generators/source.cjs +3 -0
  155. package/dist/init/generators/source.d.cts +3 -0
  156. package/dist/init/generators/source.d.mts +3 -0
  157. package/dist/init/generators/source.mjs +3 -0
  158. package/dist/init/index.cjs +16 -0
  159. package/dist/init/index.d.cts +17 -0
  160. package/dist/init/index.d.mts +17 -0
  161. package/dist/init/index.mjs +16 -0
  162. package/dist/init/templates/api.cjs +3 -0
  163. package/dist/init/templates/api.d.cts +7 -0
  164. package/dist/init/templates/api.d.mts +7 -0
  165. package/dist/init/templates/api.mjs +3 -0
  166. package/dist/init/templates/index.cjs +10 -0
  167. package/dist/init/templates/index.d.cts +2 -0
  168. package/dist/init/templates/index.d.mts +2 -0
  169. package/dist/init/templates/index.mjs +7 -0
  170. package/dist/init/templates/minimal.cjs +3 -0
  171. package/dist/init/templates/minimal.d.cts +7 -0
  172. package/dist/init/templates/minimal.d.mts +7 -0
  173. package/dist/init/templates/minimal.mjs +3 -0
  174. package/dist/init/templates/serverless.cjs +3 -0
  175. package/dist/init/templates/serverless.d.cts +7 -0
  176. package/dist/init/templates/serverless.d.mts +7 -0
  177. package/dist/init/templates/serverless.mjs +3 -0
  178. package/dist/init/templates/worker.cjs +3 -0
  179. package/dist/init/templates/worker.d.cts +7 -0
  180. package/dist/init/templates/worker.d.mts +7 -0
  181. package/dist/init/templates/worker.mjs +3 -0
  182. package/dist/init/utils.cjs +7 -0
  183. package/dist/init/utils.d.cts +25 -0
  184. package/dist/init/utils.d.mts +25 -0
  185. package/dist/init/utils.mjs +3 -0
  186. package/dist/init-CtOnZn3G.mjs +145 -0
  187. package/dist/init-CtOnZn3G.mjs.map +1 -0
  188. package/dist/init-qLFsWR-R.cjs +151 -0
  189. package/dist/init-qLFsWR-R.cjs.map +1 -0
  190. package/dist/{manifests-C2eMoMUm.mjs → manifests-DIA_2QYd.mjs} +1 -1
  191. package/dist/{manifests-C2eMoMUm.mjs.map → manifests-DIA_2QYd.mjs.map} +1 -1
  192. package/dist/{manifests-CK1VV_pM.cjs → manifests-VJ9-2JpW.cjs} +1 -1
  193. package/dist/{manifests-CK1VV_pM.cjs.map → manifests-VJ9-2JpW.cjs.map} +1 -1
  194. package/dist/minimal-Bdhhpp7v.cjs +93 -0
  195. package/dist/minimal-Bdhhpp7v.cjs.map +1 -0
  196. package/dist/minimal-C4GsE45s.mjs +87 -0
  197. package/dist/minimal-C4GsE45s.mjs.map +1 -0
  198. package/dist/models-DyNwdOcz.cjs +121 -0
  199. package/dist/models-DyNwdOcz.cjs.map +1 -0
  200. package/dist/models-cvNg6Oea.mjs +115 -0
  201. package/dist/models-cvNg6Oea.mjs.map +1 -0
  202. package/dist/monorepo-Cknwzj5C.mjs +184 -0
  203. package/dist/monorepo-Cknwzj5C.mjs.map +1 -0
  204. package/dist/monorepo-sEK8gW59.cjs +190 -0
  205. package/dist/monorepo-sEK8gW59.cjs.map +1 -0
  206. package/dist/openapi-BQWPWyNB.cjs +56 -0
  207. package/dist/openapi-BQWPWyNB.cjs.map +1 -0
  208. package/dist/openapi-DBX8cJJ8.mjs +50 -0
  209. package/dist/openapi-DBX8cJJ8.mjs.map +1 -0
  210. package/dist/{openapi-react-query-D9Z7lh0p.cjs → openapi-react-query-DxHjXQvg.cjs} +1 -1
  211. package/dist/{openapi-react-query-D9Z7lh0p.cjs.map → openapi-react-query-DxHjXQvg.cjs.map} +1 -1
  212. package/dist/{openapi-react-query-MEBlYIM1.mjs → openapi-react-query-o7Mp1Jd5.mjs} +1 -1
  213. package/dist/{openapi-react-query-MEBlYIM1.mjs.map → openapi-react-query-o7Mp1Jd5.mjs.map} +1 -1
  214. package/dist/openapi-react-query.cjs +1 -1
  215. package/dist/openapi-react-query.d.cts +11 -0
  216. package/dist/openapi-react-query.d.mts +11 -0
  217. package/dist/openapi-react-query.mjs +1 -1
  218. package/dist/openapi.cjs +5 -4
  219. package/dist/openapi.d.cts +11 -0
  220. package/dist/openapi.d.mts +11 -0
  221. package/dist/openapi.mjs +5 -4
  222. package/dist/package-C7WhWU8m.d.mts +11 -0
  223. package/dist/package-CIfmeuSW.mjs +51 -0
  224. package/dist/package-CIfmeuSW.mjs.map +1 -0
  225. package/dist/package-DvWEMz6z.d.cts +11 -0
  226. package/dist/package-PP-o1nvq.cjs +57 -0
  227. package/dist/package-PP-o1nvq.cjs.map +1 -0
  228. package/dist/{providerResolver-B_TjNF0_.mjs → providerResolver-DEVKngbC.mjs} +1 -1
  229. package/dist/{providerResolver-B_TjNF0_.mjs.map → providerResolver-DEVKngbC.mjs.map} +1 -1
  230. package/dist/{providerResolver-DgvzNfP4.cjs → providerResolver-DOTbN9jo.cjs} +1 -1
  231. package/dist/{providerResolver-DgvzNfP4.cjs.map → providerResolver-DOTbN9jo.cjs.map} +1 -1
  232. package/dist/serverless-DkHBF2vC.mjs +108 -0
  233. package/dist/serverless-DkHBF2vC.mjs.map +1 -0
  234. package/dist/serverless-Yav3GRVz.cjs +114 -0
  235. package/dist/serverless-Yav3GRVz.cjs.map +1 -0
  236. package/dist/source-D6v2BnKT.d.mts +11 -0
  237. package/dist/source-D8fK9qRo.d.cts +11 -0
  238. package/dist/source-DT5Xhiob.cjs +17 -0
  239. package/dist/source-DT5Xhiob.cjs.map +1 -0
  240. package/dist/source-DnaH_MLA.mjs +11 -0
  241. package/dist/source-DnaH_MLA.mjs.map +1 -0
  242. package/dist/templates-CBFUwpBy.mjs +64 -0
  243. package/dist/templates-CBFUwpBy.mjs.map +1 -0
  244. package/dist/templates-DM_rtYYW.cjs +87 -0
  245. package/dist/templates-DM_rtYYW.cjs.map +1 -0
  246. package/dist/types-C4KITv-y.d.mts +51 -0
  247. package/dist/types-Cxl8-uwV.d.mts +129 -0
  248. package/dist/types-DB99_qIy.d.cts +129 -0
  249. package/dist/types-DLFN49M3.d.cts +51 -0
  250. package/dist/types.d.cts +2 -0
  251. package/dist/types.d.mts +2 -0
  252. package/dist/utils-BX3F4fT8.cjs +99 -0
  253. package/dist/utils-BX3F4fT8.cjs.map +1 -0
  254. package/dist/utils-C31-SWHP.mjs +69 -0
  255. package/dist/utils-C31-SWHP.mjs.map +1 -0
  256. package/dist/worker--8O5a3Hv.cjs +150 -0
  257. package/dist/worker--8O5a3Hv.cjs.map +1 -0
  258. package/dist/worker-Jme7uOOJ.mjs +144 -0
  259. package/dist/worker-Jme7uOOJ.mjs.map +1 -0
  260. package/docs/OPENAPI_TYPESCRIPT_DESIGN.md +408 -0
  261. package/package.json +19 -4
  262. package/src/__tests__/loadEnvFiles.spec.ts +131 -0
  263. package/src/__tests__/openapi.spec.ts +78 -63
  264. package/src/build/index.ts +14 -16
  265. package/src/build/types.ts +18 -2
  266. package/src/config.ts +61 -2
  267. package/src/dev/__tests__/index.spec.ts +98 -1
  268. package/src/dev/index.ts +229 -42
  269. package/src/generators/EndpointGenerator.ts +98 -5
  270. package/src/generators/OpenApiTsGenerator.ts +798 -0
  271. package/src/index.ts +32 -3
  272. package/src/init/__tests__/generators.spec.ts +366 -0
  273. package/src/init/__tests__/init.spec.ts +341 -0
  274. package/src/init/__tests__/utils.spec.ts +104 -0
  275. package/src/init/generators/config.ts +192 -0
  276. package/src/init/generators/docker.ts +134 -0
  277. package/src/init/generators/env.ts +182 -0
  278. package/src/init/generators/index.ts +4 -0
  279. package/src/init/generators/models.ts +129 -0
  280. package/src/init/generators/monorepo.ts +211 -0
  281. package/src/init/generators/package.ts +81 -0
  282. package/src/init/generators/source.ts +15 -0
  283. package/src/init/index.ts +206 -0
  284. package/src/init/templates/api.ts +218 -0
  285. package/src/init/templates/index.ts +108 -0
  286. package/src/init/templates/minimal.ts +102 -0
  287. package/src/init/templates/serverless.ts +129 -0
  288. package/src/init/templates/worker.ts +169 -0
  289. package/src/init/utils.ts +98 -0
  290. package/src/openapi.ts +36 -15
  291. package/src/types.ts +43 -0
  292. package/tsdown.config.ts +1 -1
  293. package/dist/EndpointGenerator-C73wNoih.cjs.map +0 -1
  294. package/dist/EndpointGenerator-CWh18d92.mjs.map +0 -1
  295. package/dist/build-C6uEGRj8.mjs.map +0 -1
  296. package/dist/build-CBYBPZpC.cjs.map +0 -1
  297. package/dist/config-D1EpSGk6.cjs +0 -36
  298. package/dist/config-D1EpSGk6.cjs.map +0 -1
  299. package/dist/config-U-mdW-7Y.mjs +0 -30
  300. package/dist/config-U-mdW-7Y.mjs.map +0 -1
  301. package/dist/dev-DbtyToc7.cjs.map +0 -1
  302. package/dist/dev-DnGYXuMn.mjs +0 -241
  303. package/dist/dev-DnGYXuMn.mjs.map +0 -1
  304. package/dist/openapi-BTHbPrxS.mjs +0 -36
  305. package/dist/openapi-BTHbPrxS.mjs.map +0 -1
  306. package/dist/openapi-CewcfoRH.cjs +0 -42
  307. package/dist/openapi-CewcfoRH.cjs.map +0 -1
  308. /package/dist/{generators-CEKtVh81.cjs → generators-3IemvCLk.cjs} +0 -0
  309. /package/dist/{generators-CsLujGXs.mjs → generators-FNpdfN6J.mjs} +0 -0
@@ -22,9 +22,8 @@ describe('OpenAPI Generation', () => {
22
22
  vi.restoreAllMocks();
23
23
  });
24
24
 
25
- describe('openapiCommand', () => {
26
- it('should generate OpenAPI spec for endpoints', async () => {
27
- // Create endpoint file
25
+ describe('openapiCommand - TypeScript output (default)', () => {
26
+ it('should generate TypeScript module by default', async () => {
28
27
  await createMockEndpointFile(
29
28
  tempDir,
30
29
  'getUser.ts',
@@ -33,7 +32,6 @@ describe('OpenAPI Generation', () => {
33
32
  'GET',
34
33
  );
35
34
 
36
- // Create config file
37
35
  await createTestFile(
38
36
  tempDir,
39
37
  'gkm.config.json',
@@ -42,56 +40,58 @@ describe('OpenAPI Generation', () => {
42
40
  }),
43
41
  );
44
42
 
45
- const outputPath = join(tempDir, 'openapi.json');
46
-
47
- // Mock process.cwd
48
- vi.spyOn(process, 'cwd').mockReturnValue(tempDir);
43
+ const outputPath = join(tempDir, 'openapi.ts');
49
44
 
50
- await openapiCommand({ output: outputPath });
45
+ await openapiCommand({ output: outputPath, cwd: tempDir });
51
46
 
52
- // Verify file was created
53
47
  expect(existsSync(outputPath)).toBe(true);
54
48
 
55
- // Verify content
56
49
  const content = await readFile(outputPath, 'utf-8');
57
- const spec = JSON.parse(content);
58
50
 
59
- expect(spec).toHaveProperty('openapi');
60
- expect(spec).toHaveProperty('info');
61
- expect(spec.info.title).toBe('API Documentation');
62
- expect(spec).toHaveProperty('paths');
63
- expect(Object.keys(spec.paths).length).toBeGreaterThan(0);
51
+ expect(content).toContain('// Auto-generated by @geekmidas/cli');
52
+ expect(content).toContain('export const securitySchemes');
53
+ expect(content).toContain('export const endpointAuth');
54
+ expect(content).toContain('export interface paths');
64
55
  });
65
56
 
66
- it('should handle no endpoints found', async () => {
67
- // Create config with no matching files
57
+ it('should include endpoint auth map', async () => {
58
+ await createMockEndpointFile(
59
+ tempDir,
60
+ 'getUser.ts',
61
+ 'getUser',
62
+ '/users/:id',
63
+ 'GET',
64
+ );
65
+
68
66
  await createTestFile(
69
67
  tempDir,
70
68
  'gkm.config.json',
71
69
  JSON.stringify({
72
- routes: [`${tempDir}/nonexistent/**/*.ts`],
70
+ routes: [`${tempDir}/**/*.ts`],
73
71
  }),
74
72
  );
75
73
 
76
- vi.spyOn(process, 'cwd').mockReturnValue(tempDir);
77
- const consoleSpy = vi.spyOn(console, 'log');
74
+ const outputPath = join(tempDir, 'openapi.ts');
78
75
 
79
- await openapiCommand({ output: join(tempDir, 'openapi.json') });
76
+ await openapiCommand({ output: outputPath, cwd: tempDir });
80
77
 
81
- expect(consoleSpy).toHaveBeenCalledWith('No valid endpoints found');
78
+ const content = await readFile(outputPath, 'utf-8');
79
+
80
+ expect(content).toContain('endpointAuth');
81
+ expect(content).toContain("'GET /users/{id}'");
82
82
  });
83
+ });
83
84
 
84
- it('should use default output path when not specified', async () => {
85
- // Create endpoint file
85
+ describe('openapiCommand - JSON output (legacy)', () => {
86
+ it('should generate JSON OpenAPI spec with --json flag', async () => {
86
87
  await createMockEndpointFile(
87
88
  tempDir,
88
- 'endpoint.ts',
89
- 'testEndpoint',
90
- '/test',
89
+ 'getUser.ts',
90
+ 'getUser',
91
+ '/users/:id',
91
92
  'GET',
92
93
  );
93
94
 
94
- // Create config
95
95
  await createTestFile(
96
96
  tempDir,
97
97
  'gkm.config.json',
@@ -100,16 +100,43 @@ describe('OpenAPI Generation', () => {
100
100
  }),
101
101
  );
102
102
 
103
- vi.spyOn(process, 'cwd').mockReturnValue(tempDir);
103
+ const outputPath = join(tempDir, 'openapi.json');
104
+
105
+ await openapiCommand({ output: outputPath, json: true, cwd: tempDir });
106
+
107
+ expect(existsSync(outputPath)).toBe(true);
108
+
109
+ const content = await readFile(outputPath, 'utf-8');
110
+ const spec = JSON.parse(content);
111
+
112
+ expect(spec).toHaveProperty('openapi');
113
+ expect(spec).toHaveProperty('info');
114
+ expect(spec.info.title).toBe('API Documentation');
115
+ expect(spec).toHaveProperty('paths');
116
+ expect(Object.keys(spec.paths).length).toBeGreaterThan(0);
117
+ });
118
+
119
+ it('should handle no endpoints found', async () => {
120
+ await createTestFile(
121
+ tempDir,
122
+ 'gkm.config.json',
123
+ JSON.stringify({
124
+ routes: [`${tempDir}/nonexistent/**/*.ts`],
125
+ }),
126
+ );
127
+
128
+ const consoleSpy = vi.spyOn(console, 'log');
104
129
 
105
- await openapiCommand();
130
+ await openapiCommand({
131
+ output: join(tempDir, 'openapi.json'),
132
+ json: true,
133
+ cwd: tempDir,
134
+ });
106
135
 
107
- // Should create openapi.json in current directory
108
- expect(existsSync(join(tempDir, 'openapi.json'))).toBe(true);
136
+ expect(consoleSpy).toHaveBeenCalledWith('No valid endpoints found');
109
137
  });
110
138
 
111
139
  it('should generate spec with multiple endpoints', async () => {
112
- // Create multiple endpoint files
113
140
  await createMockEndpointFile(
114
141
  tempDir,
115
142
  'getUsers.ts',
@@ -132,7 +159,6 @@ describe('OpenAPI Generation', () => {
132
159
  'DELETE',
133
160
  );
134
161
 
135
- // Create config
136
162
  await createTestFile(
137
163
  tempDir,
138
164
  'gkm.config.json',
@@ -142,19 +168,16 @@ describe('OpenAPI Generation', () => {
142
168
  );
143
169
 
144
170
  const outputPath = join(tempDir, 'openapi.json');
145
- vi.spyOn(process, 'cwd').mockReturnValue(tempDir);
146
171
 
147
- await openapiCommand({ output: outputPath });
172
+ await openapiCommand({ output: outputPath, json: true, cwd: tempDir });
148
173
 
149
174
  const content = await readFile(outputPath, 'utf-8');
150
175
  const spec = JSON.parse(content);
151
176
 
152
- // Should have multiple paths
153
177
  expect(Object.keys(spec.paths).length).toBeGreaterThanOrEqual(1);
154
178
  });
155
179
 
156
180
  it('should create output directory if it does not exist', async () => {
157
- // Create endpoint file
158
181
  await createMockEndpointFile(
159
182
  tempDir,
160
183
  'endpoint.ts',
@@ -163,7 +186,6 @@ describe('OpenAPI Generation', () => {
163
186
  'GET',
164
187
  );
165
188
 
166
- // Create config
167
189
  await createTestFile(
168
190
  tempDir,
169
191
  'gkm.config.json',
@@ -173,15 +195,13 @@ describe('OpenAPI Generation', () => {
173
195
  );
174
196
 
175
197
  const outputPath = join(tempDir, 'nested', 'dir', 'openapi.json');
176
- vi.spyOn(process, 'cwd').mockReturnValue(tempDir);
177
198
 
178
- await openapiCommand({ output: outputPath });
199
+ await openapiCommand({ output: outputPath, json: true, cwd: tempDir });
179
200
 
180
201
  expect(existsSync(outputPath)).toBe(true);
181
202
  });
182
203
 
183
204
  it('should include API metadata in spec', async () => {
184
- // Create endpoint
185
205
  await createMockEndpointFile(
186
206
  tempDir,
187
207
  'endpoint.ts',
@@ -190,7 +210,6 @@ describe('OpenAPI Generation', () => {
190
210
  'GET',
191
211
  );
192
212
 
193
- // Create config
194
213
  await createTestFile(
195
214
  tempDir,
196
215
  'gkm.config.json',
@@ -200,9 +219,8 @@ describe('OpenAPI Generation', () => {
200
219
  );
201
220
 
202
221
  const outputPath = join(tempDir, 'openapi.json');
203
- vi.spyOn(process, 'cwd').mockReturnValue(tempDir);
204
222
 
205
- await openapiCommand({ output: outputPath });
223
+ await openapiCommand({ output: outputPath, json: true, cwd: tempDir });
206
224
 
207
225
  const content = await readFile(outputPath, 'utf-8');
208
226
  const spec = JSON.parse(content);
@@ -214,7 +232,7 @@ describe('OpenAPI Generation', () => {
214
232
  });
215
233
  });
216
234
 
217
- it('should log generation success', async () => {
235
+ it('should log generation success for JSON', async () => {
218
236
  // Create endpoint
219
237
  await createMockEndpointFile(
220
238
  tempDir,
@@ -234,13 +252,12 @@ describe('OpenAPI Generation', () => {
234
252
  );
235
253
 
236
254
  const outputPath = join(tempDir, 'openapi.json');
237
- vi.spyOn(process, 'cwd').mockReturnValue(tempDir);
238
255
  const consoleSpy = vi.spyOn(console, 'log');
239
256
 
240
- await openapiCommand({ output: outputPath });
257
+ await openapiCommand({ output: outputPath, json: true, cwd: tempDir });
241
258
 
242
259
  expect(consoleSpy).toHaveBeenCalledWith(
243
- expect.stringContaining('OpenAPI spec generated'),
260
+ expect.stringContaining('OpenAPI JSON spec generated'),
244
261
  );
245
262
  expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining('Found'));
246
263
  expect(consoleSpy).toHaveBeenCalledWith(
@@ -250,11 +267,9 @@ describe('OpenAPI Generation', () => {
250
267
 
251
268
  it('should throw error when config loading fails', async () => {
252
269
  // No config file created
253
- vi.spyOn(process, 'cwd').mockReturnValue(tempDir);
254
-
255
- await expect(openapiCommand()).rejects.toThrow(
256
- /OpenAPI generation failed/,
257
- );
270
+ await expect(
271
+ openapiCommand({ json: true, cwd: tempDir }),
272
+ ).rejects.toThrow(/OpenAPI generation failed/);
258
273
  });
259
274
 
260
275
  it('should throw error for invalid TypeScript files', async () => {
@@ -274,11 +289,13 @@ describe('OpenAPI Generation', () => {
274
289
  }),
275
290
  );
276
291
 
277
- vi.spyOn(process, 'cwd').mockReturnValue(tempDir);
278
-
279
292
  // Should throw error for syntax errors
280
293
  await expect(
281
- openapiCommand({ output: join(tempDir, 'openapi.json') }),
294
+ openapiCommand({
295
+ output: join(tempDir, 'openapi.json'),
296
+ json: true,
297
+ cwd: tempDir,
298
+ }),
282
299
  ).rejects.toThrow(/OpenAPI generation failed/);
283
300
  });
284
301
 
@@ -302,9 +319,8 @@ describe('OpenAPI Generation', () => {
302
319
  );
303
320
 
304
321
  const outputPath = join(tempDir, 'openapi.json');
305
- vi.spyOn(process, 'cwd').mockReturnValue(tempDir);
306
322
 
307
- await openapiCommand({ output: outputPath });
323
+ await openapiCommand({ output: outputPath, json: true, cwd: tempDir });
308
324
 
309
325
  const content = await readFile(outputPath, 'utf-8');
310
326
 
@@ -348,9 +364,8 @@ export const complexEndpoint = e
348
364
  );
349
365
 
350
366
  const outputPath = join(tempDir, 'openapi.json');
351
- vi.spyOn(process, 'cwd').mockReturnValue(tempDir);
352
367
 
353
- await openapiCommand({ output: outputPath });
368
+ await openapiCommand({ output: outputPath, json: true, cwd: tempDir });
354
369
 
355
370
  const content = await readFile(outputPath, 'utf-8');
356
371
  const spec = JSON.parse(content);
@@ -4,7 +4,8 @@ import type { Cron } from '@geekmidas/constructs/crons';
4
4
  import type { Endpoint } from '@geekmidas/constructs/endpoints';
5
5
  import type { Function } from '@geekmidas/constructs/functions';
6
6
  import type { Subscriber } from '@geekmidas/constructs/subscribers';
7
- import { loadConfig } from '../config';
7
+ import { loadConfig, parseModuleConfig } from '../config';
8
+ import { normalizeTelescopeConfig } from '../dev';
8
9
  import {
9
10
  CronGenerator,
10
11
  EndpointGenerator,
@@ -42,27 +43,24 @@ export async function buildCommand(options: BuildOptions): Promise<void> {
42
43
  }
43
44
  logger.log(`Using envParser: ${config.envParser}`);
44
45
 
45
- // Parse envParser configuration
46
- const [envParserPath, envParserName] = config.envParser.split('#');
47
- const envParserImportPattern = !envParserName
48
- ? 'envParser'
49
- : envParserName === 'envParser'
50
- ? '{ envParser }'
51
- : `{ ${envParserName} as envParser }`;
52
-
53
- // Parse logger configuration
54
- const [loggerPath, loggerName] = config.logger.split('#');
55
- const loggerImportPattern = !loggerName
56
- ? 'logger'
57
- : loggerName === 'logger'
58
- ? '{ logger }'
59
- : `{ ${loggerName} as logger }`;
46
+ // Parse envParser and logger configuration
47
+ const { path: envParserPath, importPattern: envParserImportPattern } =
48
+ parseModuleConfig(config.envParser, 'envParser');
49
+ const { path: loggerPath, importPattern: loggerImportPattern } =
50
+ parseModuleConfig(config.logger, 'logger');
51
+
52
+ // Normalize telescope configuration
53
+ const telescope = normalizeTelescopeConfig(config.telescope);
54
+ if (telescope) {
55
+ logger.log(`🔭 Telescope enabled at ${telescope.path}`);
56
+ }
60
57
 
61
58
  const buildContext: BuildContext = {
62
59
  envParserPath,
63
60
  envParserImportPattern,
64
61
  loggerPath,
65
62
  loggerImportPattern,
63
+ telescope,
66
64
  };
67
65
 
68
66
  // Initialize generators
@@ -1,5 +1,6 @@
1
- import type { Cron, Function } from '@geekmidas/constructs';
2
- import type { Endpoint } from '@geekmidas/constructs';
1
+ import type { Cron } from '@geekmidas/constructs/crons';
2
+ import type { Endpoint } from '@geekmidas/constructs/endpoints';
3
+ import type { Function } from '@geekmidas/constructs/functions';
3
4
 
4
5
  import type { CronInfo, FunctionInfo, RouteInfo } from '../types';
5
6
 
@@ -23,11 +24,26 @@ export interface ProcessedCron {
23
24
  schedule?: string;
24
25
  }
25
26
 
27
+ export interface NormalizedTelescopeConfig {
28
+ enabled: boolean;
29
+ /** Path to user's telescope module (if provided) */
30
+ telescopePath?: string;
31
+ /** Import pattern for telescope (e.g., '{ telescope }' or 'telescope') */
32
+ telescopeImportPattern?: string;
33
+ /** UI path for telescope dashboard */
34
+ path: string;
35
+ ignore: string[];
36
+ recordBody: boolean;
37
+ maxEntries: number;
38
+ websocket: boolean;
39
+ }
40
+
26
41
  export interface BuildContext {
27
42
  envParserPath: string;
28
43
  envParserImportPattern: string;
29
44
  loggerPath: string;
30
45
  loggerImportPattern: string;
46
+ telescope?: NormalizedTelescopeConfig;
31
47
  }
32
48
 
33
49
  export interface ProviderBuildResult {
package/src/config.ts CHANGED
@@ -2,12 +2,71 @@ import { existsSync } from 'fs';
2
2
  import { join } from 'path';
3
3
  import type { GkmConfig } from './types.ts';
4
4
 
5
- export async function loadConfig(): Promise<GkmConfig> {
5
+ /**
6
+ * Define GKM configuration with full TypeScript support.
7
+ * This is an identity function that provides type safety and autocomplete.
8
+ *
9
+ * @example
10
+ * ```ts
11
+ * // gkm.config.ts
12
+ * import { defineConfig } from '@geekmidas/cli/config';
13
+ *
14
+ * export default defineConfig({
15
+ * routes: './src/endpoints/**\/*.ts',
16
+ * envParser: './src/config/env',
17
+ * logger: './src/config/logger',
18
+ * telescope: true,
19
+ * });
20
+ * ```
21
+ */
22
+ export function defineConfig(config: GkmConfig): GkmConfig {
23
+ return config;
24
+ }
25
+
26
+ export interface ParsedModuleConfig {
27
+ path: string;
28
+ importPattern: string;
29
+ }
30
+
31
+ /**
32
+ * Parse a module config string into path and import pattern.
33
+ *
34
+ * @param configString - Config string in format "./path/to/module" or "./path/to/module#exportName"
35
+ * @param defaultAlias - The default alias name to use if no export name specified
36
+ * @returns Object with path and import pattern
37
+ *
38
+ * @example
39
+ * parseModuleConfig('./src/config/env', 'envParser')
40
+ * // { path: './src/config/env', importPattern: 'envParser' }
41
+ *
42
+ * parseModuleConfig('./src/config/env#envParser', 'envParser')
43
+ * // { path: './src/config/env', importPattern: '{ envParser }' }
44
+ *
45
+ * parseModuleConfig('./src/config/env#myEnv', 'envParser')
46
+ * // { path: './src/config/env', importPattern: '{ myEnv as envParser }' }
47
+ */
48
+ export function parseModuleConfig(
49
+ configString: string,
50
+ defaultAlias: string,
51
+ ): ParsedModuleConfig {
52
+ const [path, exportName] = configString.split('#');
53
+ const importPattern = !exportName
54
+ ? defaultAlias
55
+ : exportName === defaultAlias
56
+ ? `{ ${defaultAlias} }`
57
+ : `{ ${exportName} as ${defaultAlias} }`;
58
+
59
+ return { path, importPattern };
60
+ }
61
+
62
+ export async function loadConfig(
63
+ cwd: string = process.cwd(),
64
+ ): Promise<GkmConfig> {
6
65
  const files = ['gkm.config.json', 'gkm.config.ts', 'gkm.config.js'];
7
66
  let configPath = '';
8
67
 
9
68
  for (const file of files) {
10
- const path = join(process.cwd(), file);
69
+ const path = join(cwd, file);
11
70
  if (existsSync(path)) {
12
71
  configPath = path;
13
72
  break;
@@ -1,6 +1,10 @@
1
1
  import { createServer } from 'node:net';
2
2
  import { describe, expect, it } from 'vitest';
3
- import { findAvailablePort, isPortAvailable } from '../index';
3
+ import {
4
+ findAvailablePort,
5
+ isPortAvailable,
6
+ normalizeTelescopeConfig,
7
+ } from '../index';
4
8
 
5
9
  /**
6
10
  * Helper to occupy a port for testing
@@ -206,3 +210,96 @@ describe('devCommand edge cases', () => {
206
210
  });
207
211
  });
208
212
  });
213
+
214
+ describe('normalizeTelescopeConfig', () => {
215
+ it('should return undefined when config is false', () => {
216
+ const result = normalizeTelescopeConfig(false);
217
+ expect(result).toBeUndefined();
218
+ });
219
+
220
+ it('should return default config when config is true', () => {
221
+ const result = normalizeTelescopeConfig(true);
222
+ expect(result).toEqual({
223
+ enabled: true,
224
+ path: '/__telescope',
225
+ ignore: [],
226
+ recordBody: true,
227
+ maxEntries: 1000,
228
+ websocket: true,
229
+ });
230
+ });
231
+
232
+ it('should return default config when config is undefined', () => {
233
+ const result = normalizeTelescopeConfig(undefined);
234
+ expect(result).toEqual({
235
+ enabled: true,
236
+ path: '/__telescope',
237
+ ignore: [],
238
+ recordBody: true,
239
+ maxEntries: 1000,
240
+ websocket: true,
241
+ });
242
+ });
243
+
244
+ it('should return undefined when config.enabled is false', () => {
245
+ const result = normalizeTelescopeConfig({ enabled: false });
246
+ expect(result).toBeUndefined();
247
+ });
248
+
249
+ it('should merge custom config with defaults', () => {
250
+ const result = normalizeTelescopeConfig({
251
+ path: '/__debug',
252
+ ignore: ['/health', '/metrics'],
253
+ recordBody: false,
254
+ maxEntries: 500,
255
+ });
256
+ expect(result).toEqual({
257
+ enabled: true,
258
+ path: '/__debug',
259
+ ignore: ['/health', '/metrics'],
260
+ recordBody: false,
261
+ maxEntries: 500,
262
+ websocket: true,
263
+ });
264
+ });
265
+
266
+ it('should use defaults for missing config values', () => {
267
+ const result = normalizeTelescopeConfig({
268
+ path: '/__custom',
269
+ });
270
+ expect(result).toEqual({
271
+ enabled: true,
272
+ path: '/__custom',
273
+ ignore: [],
274
+ recordBody: true,
275
+ maxEntries: 1000,
276
+ websocket: true,
277
+ });
278
+ });
279
+
280
+ it('should handle empty object config', () => {
281
+ const result = normalizeTelescopeConfig({});
282
+ expect(result).toEqual({
283
+ enabled: true,
284
+ path: '/__telescope',
285
+ ignore: [],
286
+ recordBody: true,
287
+ maxEntries: 1000,
288
+ websocket: true,
289
+ });
290
+ });
291
+
292
+ it('should allow disabling websocket', () => {
293
+ const result = normalizeTelescopeConfig({
294
+ websocket: false,
295
+ });
296
+ expect(result).toEqual({
297
+ enabled: true,
298
+ path: '/__telescope',
299
+ ignore: [],
300
+ recordBody: true,
301
+ maxEntries: 1000,
302
+ websocket: false,
303
+ });
304
+ });
305
+ });