@geekmidas/cli 0.4.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 (298) hide show
  1. package/dist/CronGenerator-BPTqNYOR.d.cts +14 -0
  2. package/dist/{CronGenerator-Bh26MaNA.mjs → CronGenerator-CCRYptuT.mjs} +2 -2
  3. package/dist/{CronGenerator-Bh26MaNA.mjs.map → CronGenerator-CCRYptuT.mjs.map} +1 -1
  4. package/dist/{CronGenerator-C6MF8rlG.cjs → CronGenerator-D4TWXQbh.cjs} +2 -2
  5. package/dist/{CronGenerator-C6MF8rlG.cjs.map → CronGenerator-D4TWXQbh.cjs.map} +1 -1
  6. package/dist/CronGenerator-YAj59JUd.d.mts +14 -0
  7. package/dist/EndpointGenerator-ChAD1INz.d.cts +19 -0
  8. package/dist/EndpointGenerator-Cj3O1U8-.d.mts +19 -0
  9. package/dist/{EndpointGenerator-CzDhG7Or.mjs → EndpointGenerator-DGivkPLT.mjs} +22 -6
  10. package/dist/EndpointGenerator-DGivkPLT.mjs.map +1 -0
  11. package/dist/{EndpointGenerator-BxNCkus4.cjs → EndpointGenerator-npWEDoK2.cjs} +22 -6
  12. package/dist/EndpointGenerator-npWEDoK2.cjs.map +1 -0
  13. package/dist/FunctionGenerator-429-9NER.d.cts +14 -0
  14. package/dist/FunctionGenerator-BQ4ehoID.d.mts +14 -0
  15. package/dist/{FunctionGenerator-BNE_GC7N.mjs → FunctionGenerator-CVk0h8tO.mjs} +2 -2
  16. package/dist/{FunctionGenerator-BNE_GC7N.mjs.map → FunctionGenerator-CVk0h8tO.mjs.map} +1 -1
  17. package/dist/{FunctionGenerator-FgZUTd8L.cjs → FunctionGenerator-DYTnyr4c.cjs} +2 -2
  18. package/dist/{FunctionGenerator-FgZUTd8L.cjs.map → FunctionGenerator-DYTnyr4c.cjs.map} +1 -1
  19. package/dist/Generator-BjHK_qce.d.mts +27 -0
  20. package/dist/{Generator-UanJW0_V.mjs → Generator-CDt4pB3W.mjs} +1 -1
  21. package/dist/{Generator-UanJW0_V.mjs.map → Generator-CDt4pB3W.mjs.map} +1 -1
  22. package/dist/{Generator-CDoEXCDg.cjs → Generator-CLVplqm2.cjs} +1 -1
  23. package/dist/{Generator-CDoEXCDg.cjs.map → Generator-CLVplqm2.cjs.map} +1 -1
  24. package/dist/Generator-DxQMCQp7.d.cts +27 -0
  25. package/dist/{OpenApiTsGenerator-NBNEoaeO.cjs → OpenApiTsGenerator-Be-sKGTT.cjs} +1 -1
  26. package/dist/{OpenApiTsGenerator-NBNEoaeO.cjs.map → OpenApiTsGenerator-Be-sKGTT.cjs.map} +1 -1
  27. package/dist/{OpenApiTsGenerator-q3aWNkuM.mjs → OpenApiTsGenerator-C4mHHaku.mjs} +1 -1
  28. package/dist/{OpenApiTsGenerator-q3aWNkuM.mjs.map → OpenApiTsGenerator-C4mHHaku.mjs.map} +1 -1
  29. package/dist/SubscriberGenerator-7uX42xyG.d.mts +15 -0
  30. package/dist/{SubscriberGenerator-Dnlj_1FK.mjs → SubscriberGenerator-DABaJXML.mjs} +2 -2
  31. package/dist/{SubscriberGenerator-Dnlj_1FK.mjs.map → SubscriberGenerator-DABaJXML.mjs.map} +1 -1
  32. package/dist/{SubscriberGenerator-Bd-a7aiw.cjs → SubscriberGenerator-D_zpNGFr.cjs} +2 -2
  33. package/dist/{SubscriberGenerator-Bd-a7aiw.cjs.map → SubscriberGenerator-D_zpNGFr.cjs.map} +1 -1
  34. package/dist/SubscriberGenerator-Dtb3HS4i.d.cts +15 -0
  35. package/dist/api-B3SCEHPf.cjs +190 -0
  36. package/dist/api-B3SCEHPf.cjs.map +1 -0
  37. package/dist/api-BKIN0s0S.mjs +184 -0
  38. package/dist/api-BKIN0s0S.mjs.map +1 -0
  39. package/dist/build/index.cjs +11 -10
  40. package/dist/build/index.d.cts +7 -0
  41. package/dist/build/index.d.mts +7 -0
  42. package/dist/build/index.mjs +11 -10
  43. package/dist/build/manifests.cjs +1 -1
  44. package/dist/build/manifests.d.cts +13 -0
  45. package/dist/build/manifests.d.mts +13 -0
  46. package/dist/build/manifests.mjs +1 -1
  47. package/dist/build/providerResolver.cjs +1 -1
  48. package/dist/build/providerResolver.d.cts +23 -0
  49. package/dist/build/providerResolver.d.mts +23 -0
  50. package/dist/build/providerResolver.mjs +1 -1
  51. package/dist/build/types.d.cts +3 -0
  52. package/dist/build/types.d.mts +3 -0
  53. package/dist/{build-DyDgu_D1.mjs → build-B8C_qHir.mjs} +15 -13
  54. package/dist/build-B8C_qHir.mjs.map +1 -0
  55. package/dist/{build-CWtHnJMQ.cjs → build-D0Wr49bf.cjs} +15 -13
  56. package/dist/build-D0Wr49bf.cjs.map +1 -0
  57. package/dist/config-Ba-Gbpbc.d.cts +11 -0
  58. package/dist/config-Bq72aj8e.mjs +75 -0
  59. package/dist/config-Bq72aj8e.mjs.map +1 -0
  60. package/dist/config-CFls09Ey.cjs +93 -0
  61. package/dist/config-CFls09Ey.cjs.map +1 -0
  62. package/dist/config-CLEDqKO3.cjs +157 -0
  63. package/dist/config-CLEDqKO3.cjs.map +1 -0
  64. package/dist/config-DBsmMDhf.d.mts +11 -0
  65. package/dist/config-Dp8RonV_.mjs +151 -0
  66. package/dist/config-Dp8RonV_.mjs.map +1 -0
  67. package/dist/config.cjs +4 -2
  68. package/dist/config.d.cts +48 -0
  69. package/dist/config.d.mts +48 -0
  70. package/dist/config.mjs +2 -2
  71. package/dist/dev/index.cjs +10 -9
  72. package/dist/dev/index.d.cts +36 -0
  73. package/dist/dev/index.d.mts +36 -0
  74. package/dist/dev/index.mjs +10 -10
  75. package/dist/{dev-CpA8AQPX.mjs → dev-B734w3L1.mjs} +93 -49
  76. package/dist/dev-B734w3L1.mjs.map +1 -0
  77. package/dist/{dev-CgDYC4o8.cjs → dev-DHqYn8k4.cjs} +71 -21
  78. package/dist/dev-DHqYn8k4.cjs.map +1 -0
  79. package/dist/docker-5d8Yh5_X.cjs +119 -0
  80. package/dist/docker-5d8Yh5_X.cjs.map +1 -0
  81. package/dist/docker-DlUqdFle.mjs +113 -0
  82. package/dist/docker-DlUqdFle.mjs.map +1 -0
  83. package/dist/env-B-OKjgI4.cjs +144 -0
  84. package/dist/env-B-OKjgI4.cjs.map +1 -0
  85. package/dist/env-HfuJRlg5.d.cts +11 -0
  86. package/dist/env-nd-iQPYM.d.mts +11 -0
  87. package/dist/env-tv1HlZlw.mjs +138 -0
  88. package/dist/env-tv1HlZlw.mjs.map +1 -0
  89. package/dist/generators/CronGenerator.cjs +2 -2
  90. package/dist/generators/CronGenerator.d.cts +5 -0
  91. package/dist/generators/CronGenerator.d.mts +5 -0
  92. package/dist/generators/CronGenerator.mjs +2 -2
  93. package/dist/generators/EndpointGenerator.cjs +2 -2
  94. package/dist/generators/EndpointGenerator.d.cts +5 -0
  95. package/dist/generators/EndpointGenerator.d.mts +5 -0
  96. package/dist/generators/EndpointGenerator.mjs +2 -2
  97. package/dist/generators/FunctionGenerator.cjs +2 -2
  98. package/dist/generators/FunctionGenerator.d.cts +5 -0
  99. package/dist/generators/FunctionGenerator.d.mts +5 -0
  100. package/dist/generators/FunctionGenerator.mjs +2 -2
  101. package/dist/generators/Generator.cjs +1 -1
  102. package/dist/generators/Generator.d.cts +4 -0
  103. package/dist/generators/Generator.d.mts +4 -0
  104. package/dist/generators/Generator.mjs +1 -1
  105. package/dist/generators/OpenApiTsGenerator.cjs +1 -1
  106. package/dist/generators/OpenApiTsGenerator.d.cts +44 -0
  107. package/dist/generators/OpenApiTsGenerator.d.mts +44 -0
  108. package/dist/generators/OpenApiTsGenerator.mjs +1 -1
  109. package/dist/generators/SubscriberGenerator.cjs +2 -2
  110. package/dist/generators/SubscriberGenerator.d.cts +5 -0
  111. package/dist/generators/SubscriberGenerator.d.mts +5 -0
  112. package/dist/generators/SubscriberGenerator.mjs +2 -2
  113. package/dist/generators/index.cjs +6 -6
  114. package/dist/generators/index.d.cts +8 -0
  115. package/dist/generators/index.d.mts +8 -0
  116. package/dist/generators/index.mjs +6 -6
  117. package/dist/index-C523No_B.d.mts +64 -0
  118. package/dist/index-DrzN4xkQ.d.cts +64 -0
  119. package/dist/index.cjs +48 -16
  120. package/dist/index.cjs.map +1 -1
  121. package/dist/index.d.cts +1 -0
  122. package/dist/index.d.mts +1 -0
  123. package/dist/index.mjs +48 -16
  124. package/dist/index.mjs.map +1 -1
  125. package/dist/init/generators/config.cjs +3 -0
  126. package/dist/init/generators/config.d.cts +3 -0
  127. package/dist/init/generators/config.d.mts +3 -0
  128. package/dist/init/generators/config.mjs +3 -0
  129. package/dist/init/generators/docker.cjs +3 -0
  130. package/dist/init/generators/docker.d.cts +11 -0
  131. package/dist/init/generators/docker.d.mts +11 -0
  132. package/dist/init/generators/docker.mjs +3 -0
  133. package/dist/init/generators/env.cjs +3 -0
  134. package/dist/init/generators/env.d.cts +3 -0
  135. package/dist/init/generators/env.d.mts +3 -0
  136. package/dist/init/generators/env.mjs +3 -0
  137. package/dist/init/generators/index.cjs +9 -0
  138. package/dist/init/generators/index.d.cts +6 -0
  139. package/dist/init/generators/index.d.mts +6 -0
  140. package/dist/init/generators/index.mjs +6 -0
  141. package/dist/init/generators/models.cjs +3 -0
  142. package/dist/init/generators/models.d.cts +11 -0
  143. package/dist/init/generators/models.d.mts +11 -0
  144. package/dist/init/generators/models.mjs +3 -0
  145. package/dist/init/generators/monorepo.cjs +3 -0
  146. package/dist/init/generators/monorepo.d.cts +11 -0
  147. package/dist/init/generators/monorepo.d.mts +11 -0
  148. package/dist/init/generators/monorepo.mjs +3 -0
  149. package/dist/init/generators/package.cjs +3 -0
  150. package/dist/init/generators/package.d.cts +3 -0
  151. package/dist/init/generators/package.d.mts +3 -0
  152. package/dist/init/generators/package.mjs +3 -0
  153. package/dist/init/generators/source.cjs +3 -0
  154. package/dist/init/generators/source.d.cts +3 -0
  155. package/dist/init/generators/source.d.mts +3 -0
  156. package/dist/init/generators/source.mjs +3 -0
  157. package/dist/init/index.cjs +16 -0
  158. package/dist/init/index.d.cts +17 -0
  159. package/dist/init/index.d.mts +17 -0
  160. package/dist/init/index.mjs +16 -0
  161. package/dist/init/templates/api.cjs +3 -0
  162. package/dist/init/templates/api.d.cts +7 -0
  163. package/dist/init/templates/api.d.mts +7 -0
  164. package/dist/init/templates/api.mjs +3 -0
  165. package/dist/init/templates/index.cjs +10 -0
  166. package/dist/init/templates/index.d.cts +2 -0
  167. package/dist/init/templates/index.d.mts +2 -0
  168. package/dist/init/templates/index.mjs +7 -0
  169. package/dist/init/templates/minimal.cjs +3 -0
  170. package/dist/init/templates/minimal.d.cts +7 -0
  171. package/dist/init/templates/minimal.d.mts +7 -0
  172. package/dist/init/templates/minimal.mjs +3 -0
  173. package/dist/init/templates/serverless.cjs +3 -0
  174. package/dist/init/templates/serverless.d.cts +7 -0
  175. package/dist/init/templates/serverless.d.mts +7 -0
  176. package/dist/init/templates/serverless.mjs +3 -0
  177. package/dist/init/templates/worker.cjs +3 -0
  178. package/dist/init/templates/worker.d.cts +7 -0
  179. package/dist/init/templates/worker.d.mts +7 -0
  180. package/dist/init/templates/worker.mjs +3 -0
  181. package/dist/init/utils.cjs +7 -0
  182. package/dist/init/utils.d.cts +25 -0
  183. package/dist/init/utils.d.mts +25 -0
  184. package/dist/init/utils.mjs +3 -0
  185. package/dist/init-CtOnZn3G.mjs +145 -0
  186. package/dist/init-CtOnZn3G.mjs.map +1 -0
  187. package/dist/init-qLFsWR-R.cjs +151 -0
  188. package/dist/init-qLFsWR-R.cjs.map +1 -0
  189. package/dist/{manifests-C2eMoMUm.mjs → manifests-DIA_2QYd.mjs} +1 -1
  190. package/dist/{manifests-C2eMoMUm.mjs.map → manifests-DIA_2QYd.mjs.map} +1 -1
  191. package/dist/{manifests-CK1VV_pM.cjs → manifests-VJ9-2JpW.cjs} +1 -1
  192. package/dist/{manifests-CK1VV_pM.cjs.map → manifests-VJ9-2JpW.cjs.map} +1 -1
  193. package/dist/minimal-Bdhhpp7v.cjs +93 -0
  194. package/dist/minimal-Bdhhpp7v.cjs.map +1 -0
  195. package/dist/minimal-C4GsE45s.mjs +87 -0
  196. package/dist/minimal-C4GsE45s.mjs.map +1 -0
  197. package/dist/models-DyNwdOcz.cjs +121 -0
  198. package/dist/models-DyNwdOcz.cjs.map +1 -0
  199. package/dist/models-cvNg6Oea.mjs +115 -0
  200. package/dist/models-cvNg6Oea.mjs.map +1 -0
  201. package/dist/monorepo-Cknwzj5C.mjs +184 -0
  202. package/dist/monorepo-Cknwzj5C.mjs.map +1 -0
  203. package/dist/monorepo-sEK8gW59.cjs +190 -0
  204. package/dist/monorepo-sEK8gW59.cjs.map +1 -0
  205. package/dist/{openapi-DhK4b0lB.cjs → openapi-BQWPWyNB.cjs} +4 -4
  206. package/dist/{openapi-DhK4b0lB.cjs.map → openapi-BQWPWyNB.cjs.map} +1 -1
  207. package/dist/{openapi-DRTRGhTt.mjs → openapi-DBX8cJJ8.mjs} +4 -4
  208. package/dist/{openapi-DRTRGhTt.mjs.map → openapi-DBX8cJJ8.mjs.map} +1 -1
  209. package/dist/{openapi-react-query-D9Z7lh0p.cjs → openapi-react-query-DxHjXQvg.cjs} +1 -1
  210. package/dist/{openapi-react-query-D9Z7lh0p.cjs.map → openapi-react-query-DxHjXQvg.cjs.map} +1 -1
  211. package/dist/{openapi-react-query-MEBlYIM1.mjs → openapi-react-query-o7Mp1Jd5.mjs} +1 -1
  212. package/dist/{openapi-react-query-MEBlYIM1.mjs.map → openapi-react-query-o7Mp1Jd5.mjs.map} +1 -1
  213. package/dist/openapi-react-query.cjs +1 -1
  214. package/dist/openapi-react-query.d.cts +11 -0
  215. package/dist/openapi-react-query.d.mts +11 -0
  216. package/dist/openapi-react-query.mjs +1 -1
  217. package/dist/openapi.cjs +5 -5
  218. package/dist/openapi.d.cts +11 -0
  219. package/dist/openapi.d.mts +11 -0
  220. package/dist/openapi.mjs +5 -5
  221. package/dist/package-C7WhWU8m.d.mts +11 -0
  222. package/dist/package-CIfmeuSW.mjs +51 -0
  223. package/dist/package-CIfmeuSW.mjs.map +1 -0
  224. package/dist/package-DvWEMz6z.d.cts +11 -0
  225. package/dist/package-PP-o1nvq.cjs +57 -0
  226. package/dist/package-PP-o1nvq.cjs.map +1 -0
  227. package/dist/{providerResolver-B_TjNF0_.mjs → providerResolver-DEVKngbC.mjs} +1 -1
  228. package/dist/{providerResolver-B_TjNF0_.mjs.map → providerResolver-DEVKngbC.mjs.map} +1 -1
  229. package/dist/{providerResolver-DgvzNfP4.cjs → providerResolver-DOTbN9jo.cjs} +1 -1
  230. package/dist/{providerResolver-DgvzNfP4.cjs.map → providerResolver-DOTbN9jo.cjs.map} +1 -1
  231. package/dist/serverless-DkHBF2vC.mjs +108 -0
  232. package/dist/serverless-DkHBF2vC.mjs.map +1 -0
  233. package/dist/serverless-Yav3GRVz.cjs +114 -0
  234. package/dist/serverless-Yav3GRVz.cjs.map +1 -0
  235. package/dist/source-D6v2BnKT.d.mts +11 -0
  236. package/dist/source-D8fK9qRo.d.cts +11 -0
  237. package/dist/source-DT5Xhiob.cjs +17 -0
  238. package/dist/source-DT5Xhiob.cjs.map +1 -0
  239. package/dist/source-DnaH_MLA.mjs +11 -0
  240. package/dist/source-DnaH_MLA.mjs.map +1 -0
  241. package/dist/templates-CBFUwpBy.mjs +64 -0
  242. package/dist/templates-CBFUwpBy.mjs.map +1 -0
  243. package/dist/templates-DM_rtYYW.cjs +87 -0
  244. package/dist/templates-DM_rtYYW.cjs.map +1 -0
  245. package/dist/types-C4KITv-y.d.mts +51 -0
  246. package/dist/types-Cxl8-uwV.d.mts +129 -0
  247. package/dist/types-DB99_qIy.d.cts +129 -0
  248. package/dist/types-DLFN49M3.d.cts +51 -0
  249. package/dist/types.d.cts +2 -0
  250. package/dist/types.d.mts +2 -0
  251. package/dist/utils-BX3F4fT8.cjs +99 -0
  252. package/dist/utils-BX3F4fT8.cjs.map +1 -0
  253. package/dist/utils-C31-SWHP.mjs +69 -0
  254. package/dist/utils-C31-SWHP.mjs.map +1 -0
  255. package/dist/worker--8O5a3Hv.cjs +150 -0
  256. package/dist/worker--8O5a3Hv.cjs.map +1 -0
  257. package/dist/worker-Jme7uOOJ.mjs +144 -0
  258. package/dist/worker-Jme7uOOJ.mjs.map +1 -0
  259. package/package.json +11 -3
  260. package/src/__tests__/loadEnvFiles.spec.ts +131 -0
  261. package/src/build/index.ts +14 -16
  262. package/src/build/types.ts +5 -0
  263. package/src/config.ts +57 -0
  264. package/src/dev/index.ts +77 -17
  265. package/src/generators/EndpointGenerator.ts +37 -8
  266. package/src/index.ts +26 -0
  267. package/src/init/__tests__/generators.spec.ts +366 -0
  268. package/src/init/__tests__/init.spec.ts +341 -0
  269. package/src/init/__tests__/utils.spec.ts +104 -0
  270. package/src/init/generators/config.ts +192 -0
  271. package/src/init/generators/docker.ts +134 -0
  272. package/src/init/generators/env.ts +182 -0
  273. package/src/init/generators/index.ts +4 -0
  274. package/src/init/generators/models.ts +129 -0
  275. package/src/init/generators/monorepo.ts +211 -0
  276. package/src/init/generators/package.ts +81 -0
  277. package/src/init/generators/source.ts +15 -0
  278. package/src/init/index.ts +206 -0
  279. package/src/init/templates/api.ts +218 -0
  280. package/src/init/templates/index.ts +108 -0
  281. package/src/init/templates/minimal.ts +102 -0
  282. package/src/init/templates/serverless.ts +129 -0
  283. package/src/init/templates/worker.ts +169 -0
  284. package/src/init/utils.ts +98 -0
  285. package/src/types.ts +22 -2
  286. package/tsdown.config.ts +1 -1
  287. package/dist/EndpointGenerator-BxNCkus4.cjs.map +0 -1
  288. package/dist/EndpointGenerator-CzDhG7Or.mjs.map +0 -1
  289. package/dist/build-CWtHnJMQ.cjs.map +0 -1
  290. package/dist/build-DyDgu_D1.mjs.map +0 -1
  291. package/dist/config-AFmFKmU0.mjs +0 -30
  292. package/dist/config-AFmFKmU0.mjs.map +0 -1
  293. package/dist/config-BVIJpAsa.cjs +0 -36
  294. package/dist/config-BVIJpAsa.cjs.map +0 -1
  295. package/dist/dev-CgDYC4o8.cjs.map +0 -1
  296. package/dist/dev-CpA8AQPX.mjs.map +0 -1
  297. /package/dist/{generators-CEKtVh81.cjs → generators-3IemvCLk.cjs} +0 -0
  298. /package/dist/{generators-CsLujGXs.mjs → generators-FNpdfN6J.mjs} +0 -0
@@ -0,0 +1,150 @@
1
+
2
+ //#region src/init/templates/worker.ts
3
+ const workerTemplate = {
4
+ name: "worker",
5
+ description: "Background job processing",
6
+ dependencies: {
7
+ "@geekmidas/constructs": "workspace:*",
8
+ "@geekmidas/envkit": "workspace:*",
9
+ "@geekmidas/logger": "workspace:*",
10
+ "@geekmidas/events": "workspace:*",
11
+ hono: "~4.8.2",
12
+ pino: "~9.6.0"
13
+ },
14
+ devDependencies: {
15
+ "@biomejs/biome": "~1.9.4",
16
+ "@geekmidas/cli": "workspace:*",
17
+ "@types/node": "~22.0.0",
18
+ tsx: "~4.20.0",
19
+ turbo: "~2.3.0",
20
+ typescript: "~5.8.2",
21
+ vitest: "~4.0.0"
22
+ },
23
+ scripts: {
24
+ dev: "gkm dev",
25
+ build: "gkm build",
26
+ test: "vitest",
27
+ "test:once": "vitest run",
28
+ typecheck: "tsc --noEmit",
29
+ lint: "biome lint .",
30
+ fmt: "biome format . --write",
31
+ "fmt:check": "biome format ."
32
+ },
33
+ files: (options) => {
34
+ const files = [
35
+ {
36
+ path: "src/config/env.ts",
37
+ content: `import { EnvironmentParser } from '@geekmidas/envkit';
38
+
39
+ export const envParser = new EnvironmentParser(process.env);
40
+
41
+ export const config = envParser
42
+ .create((get) => ({
43
+ port: get('PORT').string().transform(Number).default(3000),
44
+ nodeEnv: get('NODE_ENV').string().default('development'),
45
+ rabbitmq: {
46
+ url: get('RABBITMQ_URL').string().default('amqp://localhost:5672'),
47
+ },${options.database ? `
48
+ database: {
49
+ url: get('DATABASE_URL').string().default('postgresql://localhost:5432/mydb'),
50
+ },` : ""}
51
+ }))
52
+ .parse();
53
+ `
54
+ },
55
+ {
56
+ path: "src/config/logger.ts",
57
+ content: `import { PinoLogger } from '@geekmidas/logger/pino';
58
+
59
+ export const logger = new PinoLogger({
60
+ app: '${options.name}',
61
+ level: process.env.LOG_LEVEL || 'info',
62
+ });
63
+ `
64
+ },
65
+ {
66
+ path: "src/endpoints/health.ts",
67
+ content: `import { e } from '@geekmidas/constructs/endpoints';
68
+
69
+ export default e
70
+ .get('/health')
71
+ .handle(async () => ({
72
+ status: 'ok',
73
+ timestamp: new Date().toISOString(),
74
+ }));
75
+ `
76
+ },
77
+ {
78
+ path: "src/events/types.ts",
79
+ content: `import type { PublishableMessage } from '@geekmidas/events';
80
+
81
+ // Define your event types here
82
+ export type AppEvents =
83
+ | PublishableMessage<'user.created', { userId: string; email: string }>
84
+ | PublishableMessage<'user.updated', { userId: string; changes: Record<string, unknown> }>
85
+ | PublishableMessage<'order.placed', { orderId: string; userId: string; total: number }>;
86
+ `
87
+ },
88
+ {
89
+ path: "src/subscribers/user-events.ts",
90
+ content: `import { s } from '@geekmidas/constructs/subscribers';
91
+ import type { AppEvents } from '../events/types.js';
92
+
93
+ export default s<AppEvents>()
94
+ .events(['user.created', 'user.updated'])
95
+ .handle(async ({ event, logger }) => {
96
+ logger.info({ type: event.type, payload: event.payload }, 'Processing user event');
97
+
98
+ switch (event.type) {
99
+ case 'user.created':
100
+ // Handle user creation
101
+ logger.info({ userId: event.payload.userId }, 'New user created');
102
+ break;
103
+ case 'user.updated':
104
+ // Handle user update
105
+ logger.info({ userId: event.payload.userId }, 'User updated');
106
+ break;
107
+ }
108
+ });
109
+ `
110
+ },
111
+ {
112
+ path: "src/crons/cleanup.ts",
113
+ content: `import { cron } from '@geekmidas/constructs/crons';
114
+
115
+ // Run every day at midnight
116
+ export default cron('0 0 * * *')
117
+ .handle(async ({ logger }) => {
118
+ logger.info('Running cleanup job');
119
+
120
+ // Add your cleanup logic here
121
+ // e.g., delete old sessions, clean up temp files, etc.
122
+
123
+ logger.info('Cleanup job completed');
124
+ });
125
+ `
126
+ }
127
+ ];
128
+ if (options.telescope) files.push({
129
+ path: "src/config/telescope.ts",
130
+ content: `import { Telescope } from '@geekmidas/telescope';
131
+ import { InMemoryStorage } from '@geekmidas/telescope/storage/memory';
132
+
133
+ export const telescope = new Telescope({
134
+ storage: new InMemoryStorage({ maxEntries: 100 }),
135
+ enabled: process.env.NODE_ENV === 'development',
136
+ });
137
+ `
138
+ });
139
+ return files;
140
+ }
141
+ };
142
+
143
+ //#endregion
144
+ Object.defineProperty(exports, 'workerTemplate', {
145
+ enumerable: true,
146
+ get: function () {
147
+ return workerTemplate;
148
+ }
149
+ });
150
+ //# sourceMappingURL=worker--8O5a3Hv.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worker--8O5a3Hv.cjs","names":["workerTemplate: TemplateConfig","options: TemplateOptions","files: GeneratedFile[]"],"sources":["../src/init/templates/worker.ts"],"sourcesContent":["import type {\n GeneratedFile,\n TemplateConfig,\n TemplateOptions,\n} from './index.js';\n\nexport const workerTemplate: TemplateConfig = {\n name: 'worker',\n description: 'Background job processing',\n\n dependencies: {\n '@geekmidas/constructs': 'workspace:*',\n '@geekmidas/envkit': 'workspace:*',\n '@geekmidas/logger': 'workspace:*',\n '@geekmidas/events': 'workspace:*',\n hono: '~4.8.2',\n pino: '~9.6.0',\n },\n\n devDependencies: {\n '@biomejs/biome': '~1.9.4',\n '@geekmidas/cli': 'workspace:*',\n '@types/node': '~22.0.0',\n tsx: '~4.20.0',\n turbo: '~2.3.0',\n typescript: '~5.8.2',\n vitest: '~4.0.0',\n },\n\n scripts: {\n dev: 'gkm dev',\n build: 'gkm build',\n test: 'vitest',\n 'test:once': 'vitest run',\n typecheck: 'tsc --noEmit',\n lint: 'biome lint .',\n fmt: 'biome format . --write',\n 'fmt:check': 'biome format .',\n },\n\n files: (options: TemplateOptions): GeneratedFile[] => {\n const files: GeneratedFile[] = [\n // src/config/env.ts\n {\n path: 'src/config/env.ts',\n content: `import { EnvironmentParser } from '@geekmidas/envkit';\n\nexport const envParser = new EnvironmentParser(process.env);\n\nexport const config = envParser\n .create((get) => ({\n port: get('PORT').string().transform(Number).default(3000),\n nodeEnv: get('NODE_ENV').string().default('development'),\n rabbitmq: {\n url: get('RABBITMQ_URL').string().default('amqp://localhost:5672'),\n },${\n options.database\n ? `\n database: {\n url: get('DATABASE_URL').string().default('postgresql://localhost:5432/mydb'),\n },`\n : ''\n }\n }))\n .parse();\n`,\n },\n\n // src/config/logger.ts - using pino\n {\n path: 'src/config/logger.ts',\n content: `import { PinoLogger } from '@geekmidas/logger/pino';\n\nexport const logger = new PinoLogger({\n app: '${options.name}',\n level: process.env.LOG_LEVEL || 'info',\n});\n`,\n },\n\n // src/endpoints/health.ts\n {\n path: 'src/endpoints/health.ts',\n content: `import { e } from '@geekmidas/constructs/endpoints';\n\nexport default e\n .get('/health')\n .handle(async () => ({\n status: 'ok',\n timestamp: new Date().toISOString(),\n }));\n`,\n },\n\n // src/events/types.ts\n {\n path: 'src/events/types.ts',\n content: `import type { PublishableMessage } from '@geekmidas/events';\n\n// Define your event types here\nexport type AppEvents =\n | PublishableMessage<'user.created', { userId: string; email: string }>\n | PublishableMessage<'user.updated', { userId: string; changes: Record<string, unknown> }>\n | PublishableMessage<'order.placed', { orderId: string; userId: string; total: number }>;\n`,\n },\n\n // src/subscribers/user-events.ts\n {\n path: 'src/subscribers/user-events.ts',\n content: `import { s } from '@geekmidas/constructs/subscribers';\nimport type { AppEvents } from '../events/types.js';\n\nexport default s<AppEvents>()\n .events(['user.created', 'user.updated'])\n .handle(async ({ event, logger }) => {\n logger.info({ type: event.type, payload: event.payload }, 'Processing user event');\n\n switch (event.type) {\n case 'user.created':\n // Handle user creation\n logger.info({ userId: event.payload.userId }, 'New user created');\n break;\n case 'user.updated':\n // Handle user update\n logger.info({ userId: event.payload.userId }, 'User updated');\n break;\n }\n });\n`,\n },\n\n // src/crons/cleanup.ts\n {\n path: 'src/crons/cleanup.ts',\n content: `import { cron } from '@geekmidas/constructs/crons';\n\n// Run every day at midnight\nexport default cron('0 0 * * *')\n .handle(async ({ logger }) => {\n logger.info('Running cleanup job');\n\n // Add your cleanup logic here\n // e.g., delete old sessions, clean up temp files, etc.\n\n logger.info('Cleanup job completed');\n });\n`,\n },\n ];\n\n // Add Telescope config if enabled\n if (options.telescope) {\n files.push({\n path: 'src/config/telescope.ts',\n content: `import { Telescope } from '@geekmidas/telescope';\nimport { InMemoryStorage } from '@geekmidas/telescope/storage/memory';\n\nexport const telescope = new Telescope({\n storage: new InMemoryStorage({ maxEntries: 100 }),\n enabled: process.env.NODE_ENV === 'development',\n});\n`,\n });\n }\n\n return files;\n },\n};\n"],"mappings":";;AAMA,MAAaA,iBAAiC;CAC5C,MAAM;CACN,aAAa;CAEb,cAAc;EACZ,yBAAyB;EACzB,qBAAqB;EACrB,qBAAqB;EACrB,qBAAqB;EACrB,MAAM;EACN,MAAM;CACP;CAED,iBAAiB;EACf,kBAAkB;EAClB,kBAAkB;EAClB,eAAe;EACf,KAAK;EACL,OAAO;EACP,YAAY;EACZ,QAAQ;CACT;CAED,SAAS;EACP,KAAK;EACL,OAAO;EACP,MAAM;EACN,aAAa;EACb,WAAW;EACX,MAAM;EACN,KAAK;EACL,aAAa;CACd;CAED,OAAO,CAACC,YAA8C;EACpD,MAAMC,QAAyB;GAE7B;IACE,MAAM;IACN,UAAU;;;;;;;;;;QAWZ,QAAQ,YACH;;;UAID,GACL;;;;GAIE;GAGD;IACE,MAAM;IACN,UAAU;;;UAGR,QAAQ,KAAK;;;;GAIhB;GAGD;IACE,MAAM;IACN,UAAU;;;;;;;;;GASX;GAGD;IACE,MAAM;IACN,UAAU;;;;;;;;GAQX;GAGD;IACE,MAAM;IACN,UAAU;;;;;;;;;;;;;;;;;;;;GAoBX;GAGD;IACE,MAAM;IACN,UAAU;;;;;;;;;;;;;GAaX;EACF;AAGD,MAAI,QAAQ,UACV,OAAM,KAAK;GACT,MAAM;GACN,UAAU;;;;;;;;EAQX,EAAC;AAGJ,SAAO;CACR;AACF"}
@@ -0,0 +1,144 @@
1
+ //#region src/init/templates/worker.ts
2
+ const workerTemplate = {
3
+ name: "worker",
4
+ description: "Background job processing",
5
+ dependencies: {
6
+ "@geekmidas/constructs": "workspace:*",
7
+ "@geekmidas/envkit": "workspace:*",
8
+ "@geekmidas/logger": "workspace:*",
9
+ "@geekmidas/events": "workspace:*",
10
+ hono: "~4.8.2",
11
+ pino: "~9.6.0"
12
+ },
13
+ devDependencies: {
14
+ "@biomejs/biome": "~1.9.4",
15
+ "@geekmidas/cli": "workspace:*",
16
+ "@types/node": "~22.0.0",
17
+ tsx: "~4.20.0",
18
+ turbo: "~2.3.0",
19
+ typescript: "~5.8.2",
20
+ vitest: "~4.0.0"
21
+ },
22
+ scripts: {
23
+ dev: "gkm dev",
24
+ build: "gkm build",
25
+ test: "vitest",
26
+ "test:once": "vitest run",
27
+ typecheck: "tsc --noEmit",
28
+ lint: "biome lint .",
29
+ fmt: "biome format . --write",
30
+ "fmt:check": "biome format ."
31
+ },
32
+ files: (options) => {
33
+ const files = [
34
+ {
35
+ path: "src/config/env.ts",
36
+ content: `import { EnvironmentParser } from '@geekmidas/envkit';
37
+
38
+ export const envParser = new EnvironmentParser(process.env);
39
+
40
+ export const config = envParser
41
+ .create((get) => ({
42
+ port: get('PORT').string().transform(Number).default(3000),
43
+ nodeEnv: get('NODE_ENV').string().default('development'),
44
+ rabbitmq: {
45
+ url: get('RABBITMQ_URL').string().default('amqp://localhost:5672'),
46
+ },${options.database ? `
47
+ database: {
48
+ url: get('DATABASE_URL').string().default('postgresql://localhost:5432/mydb'),
49
+ },` : ""}
50
+ }))
51
+ .parse();
52
+ `
53
+ },
54
+ {
55
+ path: "src/config/logger.ts",
56
+ content: `import { PinoLogger } from '@geekmidas/logger/pino';
57
+
58
+ export const logger = new PinoLogger({
59
+ app: '${options.name}',
60
+ level: process.env.LOG_LEVEL || 'info',
61
+ });
62
+ `
63
+ },
64
+ {
65
+ path: "src/endpoints/health.ts",
66
+ content: `import { e } from '@geekmidas/constructs/endpoints';
67
+
68
+ export default e
69
+ .get('/health')
70
+ .handle(async () => ({
71
+ status: 'ok',
72
+ timestamp: new Date().toISOString(),
73
+ }));
74
+ `
75
+ },
76
+ {
77
+ path: "src/events/types.ts",
78
+ content: `import type { PublishableMessage } from '@geekmidas/events';
79
+
80
+ // Define your event types here
81
+ export type AppEvents =
82
+ | PublishableMessage<'user.created', { userId: string; email: string }>
83
+ | PublishableMessage<'user.updated', { userId: string; changes: Record<string, unknown> }>
84
+ | PublishableMessage<'order.placed', { orderId: string; userId: string; total: number }>;
85
+ `
86
+ },
87
+ {
88
+ path: "src/subscribers/user-events.ts",
89
+ content: `import { s } from '@geekmidas/constructs/subscribers';
90
+ import type { AppEvents } from '../events/types.js';
91
+
92
+ export default s<AppEvents>()
93
+ .events(['user.created', 'user.updated'])
94
+ .handle(async ({ event, logger }) => {
95
+ logger.info({ type: event.type, payload: event.payload }, 'Processing user event');
96
+
97
+ switch (event.type) {
98
+ case 'user.created':
99
+ // Handle user creation
100
+ logger.info({ userId: event.payload.userId }, 'New user created');
101
+ break;
102
+ case 'user.updated':
103
+ // Handle user update
104
+ logger.info({ userId: event.payload.userId }, 'User updated');
105
+ break;
106
+ }
107
+ });
108
+ `
109
+ },
110
+ {
111
+ path: "src/crons/cleanup.ts",
112
+ content: `import { cron } from '@geekmidas/constructs/crons';
113
+
114
+ // Run every day at midnight
115
+ export default cron('0 0 * * *')
116
+ .handle(async ({ logger }) => {
117
+ logger.info('Running cleanup job');
118
+
119
+ // Add your cleanup logic here
120
+ // e.g., delete old sessions, clean up temp files, etc.
121
+
122
+ logger.info('Cleanup job completed');
123
+ });
124
+ `
125
+ }
126
+ ];
127
+ if (options.telescope) files.push({
128
+ path: "src/config/telescope.ts",
129
+ content: `import { Telescope } from '@geekmidas/telescope';
130
+ import { InMemoryStorage } from '@geekmidas/telescope/storage/memory';
131
+
132
+ export const telescope = new Telescope({
133
+ storage: new InMemoryStorage({ maxEntries: 100 }),
134
+ enabled: process.env.NODE_ENV === 'development',
135
+ });
136
+ `
137
+ });
138
+ return files;
139
+ }
140
+ };
141
+
142
+ //#endregion
143
+ export { workerTemplate };
144
+ //# sourceMappingURL=worker-Jme7uOOJ.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worker-Jme7uOOJ.mjs","names":["workerTemplate: TemplateConfig","options: TemplateOptions","files: GeneratedFile[]"],"sources":["../src/init/templates/worker.ts"],"sourcesContent":["import type {\n GeneratedFile,\n TemplateConfig,\n TemplateOptions,\n} from './index.js';\n\nexport const workerTemplate: TemplateConfig = {\n name: 'worker',\n description: 'Background job processing',\n\n dependencies: {\n '@geekmidas/constructs': 'workspace:*',\n '@geekmidas/envkit': 'workspace:*',\n '@geekmidas/logger': 'workspace:*',\n '@geekmidas/events': 'workspace:*',\n hono: '~4.8.2',\n pino: '~9.6.0',\n },\n\n devDependencies: {\n '@biomejs/biome': '~1.9.4',\n '@geekmidas/cli': 'workspace:*',\n '@types/node': '~22.0.0',\n tsx: '~4.20.0',\n turbo: '~2.3.0',\n typescript: '~5.8.2',\n vitest: '~4.0.0',\n },\n\n scripts: {\n dev: 'gkm dev',\n build: 'gkm build',\n test: 'vitest',\n 'test:once': 'vitest run',\n typecheck: 'tsc --noEmit',\n lint: 'biome lint .',\n fmt: 'biome format . --write',\n 'fmt:check': 'biome format .',\n },\n\n files: (options: TemplateOptions): GeneratedFile[] => {\n const files: GeneratedFile[] = [\n // src/config/env.ts\n {\n path: 'src/config/env.ts',\n content: `import { EnvironmentParser } from '@geekmidas/envkit';\n\nexport const envParser = new EnvironmentParser(process.env);\n\nexport const config = envParser\n .create((get) => ({\n port: get('PORT').string().transform(Number).default(3000),\n nodeEnv: get('NODE_ENV').string().default('development'),\n rabbitmq: {\n url: get('RABBITMQ_URL').string().default('amqp://localhost:5672'),\n },${\n options.database\n ? `\n database: {\n url: get('DATABASE_URL').string().default('postgresql://localhost:5432/mydb'),\n },`\n : ''\n }\n }))\n .parse();\n`,\n },\n\n // src/config/logger.ts - using pino\n {\n path: 'src/config/logger.ts',\n content: `import { PinoLogger } from '@geekmidas/logger/pino';\n\nexport const logger = new PinoLogger({\n app: '${options.name}',\n level: process.env.LOG_LEVEL || 'info',\n});\n`,\n },\n\n // src/endpoints/health.ts\n {\n path: 'src/endpoints/health.ts',\n content: `import { e } from '@geekmidas/constructs/endpoints';\n\nexport default e\n .get('/health')\n .handle(async () => ({\n status: 'ok',\n timestamp: new Date().toISOString(),\n }));\n`,\n },\n\n // src/events/types.ts\n {\n path: 'src/events/types.ts',\n content: `import type { PublishableMessage } from '@geekmidas/events';\n\n// Define your event types here\nexport type AppEvents =\n | PublishableMessage<'user.created', { userId: string; email: string }>\n | PublishableMessage<'user.updated', { userId: string; changes: Record<string, unknown> }>\n | PublishableMessage<'order.placed', { orderId: string; userId: string; total: number }>;\n`,\n },\n\n // src/subscribers/user-events.ts\n {\n path: 'src/subscribers/user-events.ts',\n content: `import { s } from '@geekmidas/constructs/subscribers';\nimport type { AppEvents } from '../events/types.js';\n\nexport default s<AppEvents>()\n .events(['user.created', 'user.updated'])\n .handle(async ({ event, logger }) => {\n logger.info({ type: event.type, payload: event.payload }, 'Processing user event');\n\n switch (event.type) {\n case 'user.created':\n // Handle user creation\n logger.info({ userId: event.payload.userId }, 'New user created');\n break;\n case 'user.updated':\n // Handle user update\n logger.info({ userId: event.payload.userId }, 'User updated');\n break;\n }\n });\n`,\n },\n\n // src/crons/cleanup.ts\n {\n path: 'src/crons/cleanup.ts',\n content: `import { cron } from '@geekmidas/constructs/crons';\n\n// Run every day at midnight\nexport default cron('0 0 * * *')\n .handle(async ({ logger }) => {\n logger.info('Running cleanup job');\n\n // Add your cleanup logic here\n // e.g., delete old sessions, clean up temp files, etc.\n\n logger.info('Cleanup job completed');\n });\n`,\n },\n ];\n\n // Add Telescope config if enabled\n if (options.telescope) {\n files.push({\n path: 'src/config/telescope.ts',\n content: `import { Telescope } from '@geekmidas/telescope';\nimport { InMemoryStorage } from '@geekmidas/telescope/storage/memory';\n\nexport const telescope = new Telescope({\n storage: new InMemoryStorage({ maxEntries: 100 }),\n enabled: process.env.NODE_ENV === 'development',\n});\n`,\n });\n }\n\n return files;\n },\n};\n"],"mappings":";AAMA,MAAaA,iBAAiC;CAC5C,MAAM;CACN,aAAa;CAEb,cAAc;EACZ,yBAAyB;EACzB,qBAAqB;EACrB,qBAAqB;EACrB,qBAAqB;EACrB,MAAM;EACN,MAAM;CACP;CAED,iBAAiB;EACf,kBAAkB;EAClB,kBAAkB;EAClB,eAAe;EACf,KAAK;EACL,OAAO;EACP,YAAY;EACZ,QAAQ;CACT;CAED,SAAS;EACP,KAAK;EACL,OAAO;EACP,MAAM;EACN,aAAa;EACb,WAAW;EACX,MAAM;EACN,KAAK;EACL,aAAa;CACd;CAED,OAAO,CAACC,YAA8C;EACpD,MAAMC,QAAyB;GAE7B;IACE,MAAM;IACN,UAAU;;;;;;;;;;QAWZ,QAAQ,YACH;;;UAID,GACL;;;;GAIE;GAGD;IACE,MAAM;IACN,UAAU;;;UAGR,QAAQ,KAAK;;;;GAIhB;GAGD;IACE,MAAM;IACN,UAAU;;;;;;;;;GASX;GAGD;IACE,MAAM;IACN,UAAU;;;;;;;;GAQX;GAGD;IACE,MAAM;IACN,UAAU;;;;;;;;;;;;;;;;;;;;GAoBX;GAGD;IACE,MAAM;IACN,UAAU;;;;;;;;;;;;;GAaX;EACF;AAGD,MAAI,QAAQ,UACV,OAAM,KAAK;GACT,MAAM;GACN,UAAU;;;;;;;;EAQX,EAAC;AAGJ,SAAO;CACR;AACF"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@geekmidas/cli",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "description": "CLI tools for building Lambda handlers, server applications, and generating OpenAPI specs",
5
5
  "private": false,
6
6
  "type": "module",
@@ -10,6 +10,11 @@
10
10
  "import": "./dist/index.mjs",
11
11
  "require": "./dist/index.cjs"
12
12
  },
13
+ "./config": {
14
+ "types": "./dist/config.d.ts",
15
+ "import": "./dist/config.mjs",
16
+ "require": "./dist/config.cjs"
17
+ },
13
18
  "./openapi": {
14
19
  "types": "./dist/openapi.d.ts",
15
20
  "import": "./dist/openapi.mjs",
@@ -32,20 +37,23 @@
32
37
  "@apidevtools/swagger-parser": "^10.1.0",
33
38
  "chokidar": "~4.0.3",
34
39
  "commander": "^12.1.0",
40
+ "dotenv": "~17.2.3",
35
41
  "fast-glob": "^3.3.2",
36
42
  "lodash.kebabcase": "^4.1.1",
37
- "openapi-typescript": "^7.4.2"
43
+ "openapi-typescript": "^7.4.2",
44
+ "prompts": "~2.4.2"
38
45
  },
39
46
  "devDependencies": {
40
47
  "@types/lodash.kebabcase": "^4.1.9",
41
48
  "@types/node": "~24.9.1",
49
+ "@types/prompts": "~2.4.9",
42
50
  "typescript": "^5.8.2",
43
51
  "vitest": "^3.2.4",
44
52
  "zod": "~4.1.13",
45
53
  "@geekmidas/testkit": "0.0.17"
46
54
  },
47
55
  "peerDependencies": {
48
- "@geekmidas/constructs": "~0.1.0",
56
+ "@geekmidas/constructs": "~0.2.0",
49
57
  "@geekmidas/envkit": "~0.1.0",
50
58
  "@geekmidas/logger": "~0.0.1",
51
59
  "@geekmidas/telescope": "~0.0.1",
@@ -0,0 +1,131 @@
1
+ import { existsSync, mkdirSync, rmSync, writeFileSync } from 'node:fs';
2
+ import { tmpdir } from 'node:os';
3
+ import { join } from 'node:path';
4
+ import { afterEach, beforeEach, describe, expect, it } from 'vitest';
5
+ import { loadEnvFiles } from '../dev';
6
+
7
+ describe('loadEnvFiles', () => {
8
+ let testDir: string;
9
+ const originalEnv = { ...process.env };
10
+
11
+ beforeEach(() => {
12
+ // Create a temporary test directory
13
+ testDir = join(tmpdir(), `gkm-test-${Date.now()}`);
14
+ mkdirSync(testDir, { recursive: true });
15
+
16
+ // Reset process.env to original state
17
+ process.env = { ...originalEnv };
18
+ });
19
+
20
+ afterEach(() => {
21
+ // Clean up test directory
22
+ if (existsSync(testDir)) {
23
+ rmSync(testDir, { recursive: true, force: true });
24
+ }
25
+
26
+ // Reset process.env
27
+ process.env = originalEnv;
28
+ });
29
+
30
+ it('should load a single .env file', () => {
31
+ writeFileSync(join(testDir, '.env'), 'TEST_VAR=hello\nANOTHER_VAR=world');
32
+
33
+ const { loaded, missing } = loadEnvFiles('.env', testDir);
34
+
35
+ expect(loaded).toEqual(['.env']);
36
+ expect(missing).toEqual([]);
37
+ expect(process.env.TEST_VAR).toBe('hello');
38
+ expect(process.env.ANOTHER_VAR).toBe('world');
39
+ });
40
+
41
+ it('should load multiple env files in order', () => {
42
+ writeFileSync(join(testDir, '.env'), 'VAR1=base\nVAR2=base');
43
+ writeFileSync(join(testDir, '.env.local'), 'VAR2=local\nVAR3=local');
44
+
45
+ const { loaded, missing } = loadEnvFiles(['.env', '.env.local'], testDir);
46
+
47
+ expect(loaded).toEqual(['.env', '.env.local']);
48
+ expect(missing).toEqual([]);
49
+ expect(process.env.VAR1).toBe('base');
50
+ expect(process.env.VAR2).toBe('local'); // Overridden by .env.local
51
+ expect(process.env.VAR3).toBe('local');
52
+ });
53
+
54
+ it('should report missing files when explicitly configured', () => {
55
+ writeFileSync(join(testDir, '.env'), 'VAR=value');
56
+
57
+ const { loaded, missing } = loadEnvFiles(
58
+ ['.env', '.env.local', '.env.missing'],
59
+ testDir,
60
+ );
61
+
62
+ expect(loaded).toEqual(['.env']);
63
+ expect(missing).toEqual(['.env.local', '.env.missing']);
64
+ expect(process.env.VAR).toBe('value');
65
+ });
66
+
67
+ it('should not report missing .env when using default', () => {
68
+ // No .env file exists
69
+ const { loaded, missing } = loadEnvFiles(undefined, testDir);
70
+
71
+ expect(loaded).toEqual([]);
72
+ expect(missing).toEqual([]);
73
+ });
74
+
75
+ it('should handle undefined config with default .env', () => {
76
+ writeFileSync(join(testDir, '.env'), 'DEFAULT_VAR=default');
77
+
78
+ const { loaded, missing } = loadEnvFiles(undefined, testDir);
79
+
80
+ expect(loaded).toEqual(['.env']);
81
+ expect(missing).toEqual([]);
82
+ expect(process.env.DEFAULT_VAR).toBe('default');
83
+ });
84
+
85
+ it('should handle string config as single file', () => {
86
+ writeFileSync(join(testDir, '.env.production'), 'PROD_VAR=production');
87
+
88
+ const { loaded, missing } = loadEnvFiles('.env.production', testDir);
89
+
90
+ expect(loaded).toEqual(['.env.production']);
91
+ expect(missing).toEqual([]);
92
+ expect(process.env.PROD_VAR).toBe('production');
93
+ });
94
+
95
+ it('should override earlier files with later files', () => {
96
+ writeFileSync(join(testDir, '.env'), 'SHARED=first\nONLY_FIRST=yes');
97
+ writeFileSync(join(testDir, '.env.local'), 'SHARED=second');
98
+ writeFileSync(join(testDir, '.env.dev'), 'SHARED=third\nONLY_DEV=yes');
99
+
100
+ const { loaded } = loadEnvFiles(
101
+ ['.env', '.env.local', '.env.dev'],
102
+ testDir,
103
+ );
104
+
105
+ expect(loaded).toEqual(['.env', '.env.local', '.env.dev']);
106
+ expect(process.env.SHARED).toBe('third');
107
+ expect(process.env.ONLY_FIRST).toBe('yes');
108
+ expect(process.env.ONLY_DEV).toBe('yes');
109
+ });
110
+
111
+ it('should handle empty env files', () => {
112
+ writeFileSync(join(testDir, '.env'), '');
113
+
114
+ const { loaded, missing } = loadEnvFiles('.env', testDir);
115
+
116
+ expect(loaded).toEqual(['.env']);
117
+ expect(missing).toEqual([]);
118
+ });
119
+
120
+ it('should handle env files with comments', () => {
121
+ writeFileSync(
122
+ join(testDir, '.env'),
123
+ '# This is a comment\nVAR=value\n# Another comment',
124
+ );
125
+
126
+ const { loaded } = loadEnvFiles('.env', testDir);
127
+
128
+ expect(loaded).toEqual(['.env']);
129
+ expect(process.env.VAR).toBe('value');
130
+ });
131
+ });
@@ -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
@@ -26,6 +26,11 @@ export interface ProcessedCron {
26
26
 
27
27
  export interface NormalizedTelescopeConfig {
28
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 */
29
34
  path: string;
30
35
  ignore: string[];
31
36
  recordBody: boolean;
package/src/config.ts CHANGED
@@ -2,6 +2,63 @@ import { existsSync } from 'fs';
2
2
  import { join } from 'path';
3
3
  import type { GkmConfig } from './types.ts';
4
4
 
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
+
5
62
  export async function loadConfig(
6
63
  cwd: string = process.cwd(),
7
64
  ): Promise<GkmConfig> {