@geekmidas/cli 0.6.2 → 0.7.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 (271) hide show
  1. package/dist/config.d.cts +1 -1
  2. package/dist/config.d.mts +1 -1
  3. package/dist/index.cjs +2561 -34
  4. package/dist/index.cjs.map +1 -1
  5. package/dist/index.mjs +2556 -29
  6. package/dist/index.mjs.map +1 -1
  7. package/dist/openapi-Mwy2_R4W.mjs +957 -0
  8. package/dist/openapi-Mwy2_R4W.mjs.map +1 -0
  9. package/dist/{openapi-react-query-_-B3s8v_.mjs → openapi-react-query-CcciaVu5.mjs} +1 -1
  10. package/dist/{openapi-react-query-_-B3s8v_.mjs.map → openapi-react-query-CcciaVu5.mjs.map} +1 -1
  11. package/dist/{openapi-react-query-Cp-w8_05.cjs → openapi-react-query-o5iMi8tz.cjs} +1 -1
  12. package/dist/{openapi-react-query-Cp-w8_05.cjs.map → openapi-react-query-o5iMi8tz.cjs.map} +1 -1
  13. package/dist/openapi-react-query.cjs +1 -1
  14. package/dist/openapi-react-query.mjs +1 -1
  15. package/dist/openapi-tAIbJJU_.cjs +993 -0
  16. package/dist/openapi-tAIbJJU_.cjs.map +1 -0
  17. package/dist/openapi.cjs +1 -4
  18. package/dist/openapi.d.cts +1 -1
  19. package/dist/openapi.d.mts +1 -1
  20. package/dist/openapi.mjs +1 -4
  21. package/dist/{types-Bi7VzDUZ.d.mts → types-B3TXoj7v.d.mts} +21 -53
  22. package/dist/{types-KmjzMgu8.d.cts → types-C0hwnSjm.d.cts} +21 -53
  23. package/package.json +5 -5
  24. package/src/build/types.ts +13 -0
  25. package/src/dev/index.ts +71 -8
  26. package/src/generators/EndpointGenerator.ts +46 -5
  27. package/src/generators/__tests__/EndpointGenerator.spec.ts +1 -1
  28. package/src/init/generators/config.ts +6 -1
  29. package/src/init/generators/package.ts +5 -1
  30. package/src/init/index.ts +9 -1
  31. package/src/init/templates/api.ts +31 -0
  32. package/src/init/templates/index.ts +1 -0
  33. package/src/init/templates/minimal.ts +83 -0
  34. package/src/types.ts +19 -0
  35. package/tsdown.config.ts +6 -0
  36. package/dist/CronGenerator-CCRYptuT.mjs +0 -55
  37. package/dist/CronGenerator-CCRYptuT.mjs.map +0 -1
  38. package/dist/CronGenerator-D4TWXQbh.cjs +0 -61
  39. package/dist/CronGenerator-D4TWXQbh.cjs.map +0 -1
  40. package/dist/CronGenerator-DWS3CCZt.d.cts +0 -14
  41. package/dist/CronGenerator-DZjdkEjI.d.mts +0 -14
  42. package/dist/EndpointGenerator-DGivkPLT.mjs +0 -335
  43. package/dist/EndpointGenerator-DGivkPLT.mjs.map +0 -1
  44. package/dist/EndpointGenerator-Dh7kMtuL.d.mts +0 -19
  45. package/dist/EndpointGenerator-npWEDoK2.cjs +0 -341
  46. package/dist/EndpointGenerator-npWEDoK2.cjs.map +0 -1
  47. package/dist/EndpointGenerator-zBsie_7s.d.cts +0 -19
  48. package/dist/FunctionGenerator-BmDHo27U.d.mts +0 -14
  49. package/dist/FunctionGenerator-CVk0h8tO.mjs +0 -54
  50. package/dist/FunctionGenerator-CVk0h8tO.mjs.map +0 -1
  51. package/dist/FunctionGenerator-DXjXBxUd.d.cts +0 -14
  52. package/dist/FunctionGenerator-DYTnyr4c.cjs +0 -60
  53. package/dist/FunctionGenerator-DYTnyr4c.cjs.map +0 -1
  54. package/dist/Generator-BGY-2dgI.d.cts +0 -27
  55. package/dist/Generator-CDt4pB3W.mjs +0 -41
  56. package/dist/Generator-CDt4pB3W.mjs.map +0 -1
  57. package/dist/Generator-CLVplqm2.cjs +0 -47
  58. package/dist/Generator-CLVplqm2.cjs.map +0 -1
  59. package/dist/Generator-yi9DH5TN.d.mts +0 -27
  60. package/dist/OpenApiTsGenerator-BVS4pOH7.mjs +0 -495
  61. package/dist/OpenApiTsGenerator-BVS4pOH7.mjs.map +0 -1
  62. package/dist/OpenApiTsGenerator-gPIIyppX.cjs +0 -501
  63. package/dist/OpenApiTsGenerator-gPIIyppX.cjs.map +0 -1
  64. package/dist/SubscriberGenerator-Bb-z3Kvx.d.cts +0 -15
  65. package/dist/SubscriberGenerator-CwsXqCpS.d.mts +0 -15
  66. package/dist/SubscriberGenerator-DABaJXML.mjs +0 -200
  67. package/dist/SubscriberGenerator-DABaJXML.mjs.map +0 -1
  68. package/dist/SubscriberGenerator-D_zpNGFr.cjs +0 -206
  69. package/dist/SubscriberGenerator-D_zpNGFr.cjs.map +0 -1
  70. package/dist/api-Bp5TIl1R.mjs +0 -167
  71. package/dist/api-Bp5TIl1R.mjs.map +0 -1
  72. package/dist/api-D4W9-tdZ.cjs +0 -173
  73. package/dist/api-D4W9-tdZ.cjs.map +0 -1
  74. package/dist/build/index.cjs +0 -15
  75. package/dist/build/index.d.cts +0 -7
  76. package/dist/build/index.d.mts +0 -7
  77. package/dist/build/index.mjs +0 -15
  78. package/dist/build/manifests.cjs +0 -4
  79. package/dist/build/manifests.d.cts +0 -13
  80. package/dist/build/manifests.d.mts +0 -13
  81. package/dist/build/manifests.mjs +0 -3
  82. package/dist/build/providerResolver.cjs +0 -5
  83. package/dist/build/providerResolver.d.cts +0 -23
  84. package/dist/build/providerResolver.d.mts +0 -23
  85. package/dist/build/providerResolver.mjs +0 -3
  86. package/dist/build/types.cjs +0 -0
  87. package/dist/build/types.d.cts +0 -3
  88. package/dist/build/types.d.mts +0 -3
  89. package/dist/build/types.mjs +0 -0
  90. package/dist/build-Cu6Mi0Lf.mjs +0 -87
  91. package/dist/build-Cu6Mi0Lf.mjs.map +0 -1
  92. package/dist/build-wmt8ZcmA.cjs +0 -93
  93. package/dist/build-wmt8ZcmA.cjs.map +0 -1
  94. package/dist/config-BP1IZynR.cjs +0 -168
  95. package/dist/config-BP1IZynR.cjs.map +0 -1
  96. package/dist/config-CIzRhm_D.d.mts +0 -11
  97. package/dist/config-CvehIYsb.d.cts +0 -11
  98. package/dist/config-UCK12Lrr.mjs +0 -162
  99. package/dist/config-UCK12Lrr.mjs.map +0 -1
  100. package/dist/dev/index.cjs +0 -17
  101. package/dist/dev/index.d.cts +0 -36
  102. package/dist/dev/index.d.mts +0 -36
  103. package/dist/dev/index.mjs +0 -13
  104. package/dist/dev-BBPWSllq.mjs +0 -348
  105. package/dist/dev-BBPWSllq.mjs.map +0 -1
  106. package/dist/dev-C2lCgE53.cjs +0 -378
  107. package/dist/dev-C2lCgE53.cjs.map +0 -1
  108. package/dist/docker-2-ipZDOJ.cjs +0 -119
  109. package/dist/docker-2-ipZDOJ.cjs.map +0 -1
  110. package/dist/docker-31GNwU3F.mjs +0 -113
  111. package/dist/docker-31GNwU3F.mjs.map +0 -1
  112. package/dist/env-CQ3hXAAW.d.mts +0 -11
  113. package/dist/env-CS0jvg7k.cjs +0 -144
  114. package/dist/env-CS0jvg7k.cjs.map +0 -1
  115. package/dist/env-D4YFgMqo.d.cts +0 -11
  116. package/dist/env-DEeVOvVu.mjs +0 -138
  117. package/dist/env-DEeVOvVu.mjs.map +0 -1
  118. package/dist/generators/CronGenerator.cjs +0 -4
  119. package/dist/generators/CronGenerator.d.cts +0 -5
  120. package/dist/generators/CronGenerator.d.mts +0 -5
  121. package/dist/generators/CronGenerator.mjs +0 -4
  122. package/dist/generators/EndpointGenerator.cjs +0 -4
  123. package/dist/generators/EndpointGenerator.d.cts +0 -5
  124. package/dist/generators/EndpointGenerator.d.mts +0 -5
  125. package/dist/generators/EndpointGenerator.mjs +0 -4
  126. package/dist/generators/FunctionGenerator.cjs +0 -4
  127. package/dist/generators/FunctionGenerator.d.cts +0 -5
  128. package/dist/generators/FunctionGenerator.d.mts +0 -5
  129. package/dist/generators/FunctionGenerator.mjs +0 -4
  130. package/dist/generators/Generator.cjs +0 -3
  131. package/dist/generators/Generator.d.cts +0 -4
  132. package/dist/generators/Generator.d.mts +0 -4
  133. package/dist/generators/Generator.mjs +0 -3
  134. package/dist/generators/OpenApiTsGenerator.cjs +0 -3
  135. package/dist/generators/OpenApiTsGenerator.d.cts +0 -44
  136. package/dist/generators/OpenApiTsGenerator.d.mts +0 -44
  137. package/dist/generators/OpenApiTsGenerator.mjs +0 -3
  138. package/dist/generators/SubscriberGenerator.cjs +0 -4
  139. package/dist/generators/SubscriberGenerator.d.cts +0 -5
  140. package/dist/generators/SubscriberGenerator.d.mts +0 -5
  141. package/dist/generators/SubscriberGenerator.mjs +0 -4
  142. package/dist/generators/index.cjs +0 -12
  143. package/dist/generators/index.d.cts +0 -8
  144. package/dist/generators/index.d.mts +0 -8
  145. package/dist/generators/index.mjs +0 -8
  146. package/dist/generators-3IemvCLk.cjs +0 -0
  147. package/dist/generators-FNpdfN6J.mjs +0 -0
  148. package/dist/index-DG6xNQMH.d.cts +0 -81
  149. package/dist/index-DZgrOOOW.d.mts +0 -81
  150. package/dist/init/generators/config.cjs +0 -3
  151. package/dist/init/generators/config.d.cts +0 -3
  152. package/dist/init/generators/config.d.mts +0 -3
  153. package/dist/init/generators/config.mjs +0 -3
  154. package/dist/init/generators/docker.cjs +0 -3
  155. package/dist/init/generators/docker.d.cts +0 -11
  156. package/dist/init/generators/docker.d.mts +0 -11
  157. package/dist/init/generators/docker.mjs +0 -3
  158. package/dist/init/generators/env.cjs +0 -3
  159. package/dist/init/generators/env.d.cts +0 -3
  160. package/dist/init/generators/env.d.mts +0 -3
  161. package/dist/init/generators/env.mjs +0 -3
  162. package/dist/init/generators/index.cjs +0 -14
  163. package/dist/init/generators/index.d.cts +0 -6
  164. package/dist/init/generators/index.d.mts +0 -6
  165. package/dist/init/generators/index.mjs +0 -11
  166. package/dist/init/generators/models.cjs +0 -3
  167. package/dist/init/generators/models.d.cts +0 -11
  168. package/dist/init/generators/models.d.mts +0 -11
  169. package/dist/init/generators/models.mjs +0 -3
  170. package/dist/init/generators/monorepo.cjs +0 -3
  171. package/dist/init/generators/monorepo.d.cts +0 -11
  172. package/dist/init/generators/monorepo.d.mts +0 -11
  173. package/dist/init/generators/monorepo.mjs +0 -3
  174. package/dist/init/generators/package.cjs +0 -8
  175. package/dist/init/generators/package.d.cts +0 -3
  176. package/dist/init/generators/package.d.mts +0 -3
  177. package/dist/init/generators/package.mjs +0 -8
  178. package/dist/init/generators/source.cjs +0 -3
  179. package/dist/init/generators/source.d.cts +0 -3
  180. package/dist/init/generators/source.d.mts +0 -3
  181. package/dist/init/generators/source.mjs +0 -3
  182. package/dist/init/index.cjs +0 -16
  183. package/dist/init/index.d.cts +0 -17
  184. package/dist/init/index.d.mts +0 -17
  185. package/dist/init/index.mjs +0 -16
  186. package/dist/init/templates/api.cjs +0 -3
  187. package/dist/init/templates/api.d.cts +0 -7
  188. package/dist/init/templates/api.d.mts +0 -7
  189. package/dist/init/templates/api.mjs +0 -3
  190. package/dist/init/templates/index.cjs +0 -12
  191. package/dist/init/templates/index.d.cts +0 -2
  192. package/dist/init/templates/index.d.mts +0 -2
  193. package/dist/init/templates/index.mjs +0 -7
  194. package/dist/init/templates/minimal.cjs +0 -3
  195. package/dist/init/templates/minimal.d.cts +0 -7
  196. package/dist/init/templates/minimal.d.mts +0 -7
  197. package/dist/init/templates/minimal.mjs +0 -3
  198. package/dist/init/templates/serverless.cjs +0 -3
  199. package/dist/init/templates/serverless.d.cts +0 -7
  200. package/dist/init/templates/serverless.d.mts +0 -7
  201. package/dist/init/templates/serverless.mjs +0 -3
  202. package/dist/init/templates/worker.cjs +0 -3
  203. package/dist/init/templates/worker.d.cts +0 -7
  204. package/dist/init/templates/worker.d.mts +0 -7
  205. package/dist/init/templates/worker.mjs +0 -3
  206. package/dist/init/utils.cjs +0 -7
  207. package/dist/init/utils.d.cts +0 -25
  208. package/dist/init/utils.d.mts +0 -25
  209. package/dist/init/utils.mjs +0 -3
  210. package/dist/init-BMA7xi8r.mjs +0 -161
  211. package/dist/init-BMA7xi8r.mjs.map +0 -1
  212. package/dist/init-D-7WEk-b.cjs +0 -167
  213. package/dist/init-D-7WEk-b.cjs.map +0 -1
  214. package/dist/manifests-BNKG6AXf.mjs +0 -68
  215. package/dist/manifests-BNKG6AXf.mjs.map +0 -1
  216. package/dist/manifests-D13Ej8AE.cjs +0 -80
  217. package/dist/manifests-D13Ej8AE.cjs.map +0 -1
  218. package/dist/minimal-BkyASH_C.mjs +0 -93
  219. package/dist/minimal-BkyASH_C.mjs.map +0 -1
  220. package/dist/minimal-CSFggzdH.cjs +0 -99
  221. package/dist/minimal-CSFggzdH.cjs.map +0 -1
  222. package/dist/models-BWlDfviw.mjs +0 -115
  223. package/dist/models-BWlDfviw.mjs.map +0 -1
  224. package/dist/models-BapGSoHC.cjs +0 -121
  225. package/dist/models-BapGSoHC.cjs.map +0 -1
  226. package/dist/monorepo-BBOWhkcd.mjs +0 -184
  227. package/dist/monorepo-BBOWhkcd.mjs.map +0 -1
  228. package/dist/monorepo-CFtxHeDh.cjs +0 -190
  229. package/dist/monorepo-CFtxHeDh.cjs.map +0 -1
  230. package/dist/openapi-DA9RkPJl.mjs +0 -74
  231. package/dist/openapi-DA9RkPJl.mjs.map +0 -1
  232. package/dist/openapi-DZH6RQHk.cjs +0 -98
  233. package/dist/openapi-DZH6RQHk.cjs.map +0 -1
  234. package/dist/package-6h-7QfJZ.d.cts +0 -11
  235. package/dist/package-BCe_KvGv.d.mts +0 -11
  236. package/dist/package-C3If80n1.mjs +0 -57
  237. package/dist/package-C3If80n1.mjs.map +0 -1
  238. package/dist/package-Dk8IMBOB.cjs +0 -62
  239. package/dist/package-Dk8IMBOB.cjs.map +0 -1
  240. package/dist/providerResolver-DEVKngbC.mjs +0 -96
  241. package/dist/providerResolver-DEVKngbC.mjs.map +0 -1
  242. package/dist/providerResolver-DOTbN9jo.cjs +0 -114
  243. package/dist/providerResolver-DOTbN9jo.cjs.map +0 -1
  244. package/dist/serverless-AGOS-l3G.cjs +0 -119
  245. package/dist/serverless-AGOS-l3G.cjs.map +0 -1
  246. package/dist/serverless-D5HjJByU.mjs +0 -113
  247. package/dist/serverless-D5HjJByU.mjs.map +0 -1
  248. package/dist/source-C1cyfHcF.cjs +0 -17
  249. package/dist/source-C1cyfHcF.cjs.map +0 -1
  250. package/dist/source-C3LiNUV9.d.mts +0 -11
  251. package/dist/source-CkQHBpwu.mjs +0 -11
  252. package/dist/source-CkQHBpwu.mjs.map +0 -1
  253. package/dist/source-Dtcjbokc.d.cts +0 -11
  254. package/dist/templates-C0EMmhwb.mjs +0 -88
  255. package/dist/templates-C0EMmhwb.mjs.map +0 -1
  256. package/dist/templates-CbgQ9dw0.cjs +0 -123
  257. package/dist/templates-CbgQ9dw0.cjs.map +0 -1
  258. package/dist/types-D2xYkOal.d.mts +0 -51
  259. package/dist/types-DA-r8HWZ.d.cts +0 -51
  260. package/dist/types.cjs +0 -0
  261. package/dist/types.d.cts +0 -2
  262. package/dist/types.d.mts +0 -2
  263. package/dist/types.mjs +0 -0
  264. package/dist/utils-CKEzCxc1.mjs +0 -69
  265. package/dist/utils-CKEzCxc1.mjs.map +0 -1
  266. package/dist/utils-DSdN2MTt.cjs +0 -99
  267. package/dist/utils-DSdN2MTt.cjs.map +0 -1
  268. package/dist/worker-CGhlqNH-.cjs +0 -156
  269. package/dist/worker-CGhlqNH-.cjs.map +0 -1
  270. package/dist/worker-CiP420As.mjs +0 -150
  271. package/dist/worker-CiP420As.mjs.map +0 -1
@@ -0,0 +1,993 @@
1
+ const require_chunk = require('./chunk-CUT6urMc.cjs');
2
+ const require_config = require('./config-CFls09Ey.cjs');
3
+ const path = require_chunk.__toESM(require("path"));
4
+ const node_fs_promises = require_chunk.__toESM(require("node:fs/promises"));
5
+ const node_path = require_chunk.__toESM(require("node:path"));
6
+ const fast_glob = require_chunk.__toESM(require("fast-glob"));
7
+ const lodash_kebabcase = require_chunk.__toESM(require("lodash.kebabcase"));
8
+ const __geekmidas_constructs_endpoints = require_chunk.__toESM(require("@geekmidas/constructs/endpoints"));
9
+ const __geekmidas_schema_conversion = require_chunk.__toESM(require("@geekmidas/schema/conversion"));
10
+
11
+ //#region src/generators/Generator.ts
12
+ var ConstructGenerator = class {
13
+ static async build(context, outputDir, generator, patterns, options) {
14
+ const constructs = await generator.load(patterns);
15
+ return generator.build(context, constructs, outputDir, options);
16
+ }
17
+ async load(patterns, cwd = process.cwd()) {
18
+ const logger = console;
19
+ const globPatterns = Array.isArray(patterns) ? patterns : patterns ? [patterns] : [];
20
+ const files = fast_glob.default.stream(globPatterns, {
21
+ cwd,
22
+ absolute: true
23
+ });
24
+ const constructs = [];
25
+ for await (const f of files) try {
26
+ const file = f.toString();
27
+ const module$1 = await import(file);
28
+ for (const [key, construct] of Object.entries(module$1)) if (this.isConstruct(construct)) constructs.push({
29
+ key,
30
+ name: (0, lodash_kebabcase.default)(key),
31
+ construct,
32
+ path: {
33
+ absolute: file,
34
+ relative: (0, path.relative)(process.cwd(), file)
35
+ }
36
+ });
37
+ } catch (error) {
38
+ logger.warn(`Failed to load ${f}:`, error.message);
39
+ throw new Error("Failed to load constructs. Please check the logs for details.");
40
+ }
41
+ return constructs;
42
+ }
43
+ };
44
+
45
+ //#endregion
46
+ //#region src/generators/EndpointGenerator.ts
47
+ var EndpointGenerator = class extends ConstructGenerator {
48
+ isConstruct(value) {
49
+ return __geekmidas_constructs_endpoints.Endpoint.isEndpoint(value);
50
+ }
51
+ async build(context, constructs, outputDir, options) {
52
+ const provider = options?.provider || "aws-apigatewayv2";
53
+ const enableOpenApi = options?.enableOpenApi || false;
54
+ const logger = console;
55
+ const routes = [];
56
+ if (constructs.length === 0) return routes;
57
+ if (provider === "server") {
58
+ await this.generateEndpointsFile(outputDir, constructs, context);
59
+ const appFile = await this.generateAppFile(outputDir, context);
60
+ routes.push({
61
+ path: "*",
62
+ method: "ALL",
63
+ handler: (0, node_path.relative)(process.cwd(), appFile),
64
+ authorizer: "none"
65
+ });
66
+ logger.log(`Generated server with ${constructs.length} endpoints${enableOpenApi ? " (OpenAPI enabled)" : ""}`);
67
+ } else if (provider === "aws-lambda") {
68
+ const routesDir = (0, node_path.join)(outputDir, "routes");
69
+ await (0, node_fs_promises.mkdir)(routesDir, { recursive: true });
70
+ for (const { key, construct, path: path$1 } of constructs) {
71
+ const handlerFile = await this.generateHandlerFile(routesDir, path$1.relative, key, "aws-apigatewayv2", construct, context);
72
+ const routeInfo = {
73
+ path: construct._path,
74
+ method: construct.method,
75
+ handler: (0, node_path.relative)(process.cwd(), handlerFile).replace(/\.ts$/, ".handler"),
76
+ timeout: construct.timeout,
77
+ memorySize: construct.memorySize,
78
+ environment: await construct.getEnvironment(),
79
+ authorizer: construct.authorizer?.name ?? "none"
80
+ };
81
+ routes.push(routeInfo);
82
+ logger.log(`Generated handler for ${routeInfo.method} ${routeInfo.path}`);
83
+ }
84
+ } else for (const { key, construct, path: path$1 } of constructs) {
85
+ const handlerFile = await this.generateHandlerFile(outputDir, path$1.relative, key, provider, construct, context);
86
+ const routeInfo = {
87
+ path: construct._path,
88
+ method: construct.method,
89
+ handler: (0, node_path.relative)(process.cwd(), handlerFile).replace(/\.ts$/, ".handler"),
90
+ timeout: construct.timeout,
91
+ memorySize: construct.memorySize,
92
+ environment: await construct.getEnvironment(),
93
+ authorizer: construct.authorizer?.name ?? "none"
94
+ };
95
+ routes.push(routeInfo);
96
+ logger.log(`Generated handler for ${routeInfo.method} ${routeInfo.path}`);
97
+ }
98
+ return routes;
99
+ }
100
+ async generateHandlerFile(outputDir, sourceFile, exportName, provider, _endpoint, context) {
101
+ const handlerFileName = `${exportName}.ts`;
102
+ const handlerPath = (0, node_path.join)(outputDir, handlerFileName);
103
+ const relativePath = (0, node_path.relative)((0, node_path.dirname)(handlerPath), sourceFile);
104
+ const importPath = relativePath.replace(/\.ts$/, ".js");
105
+ const relativeEnvParserPath = (0, node_path.relative)((0, node_path.dirname)(handlerPath), context.envParserPath);
106
+ let content;
107
+ switch (provider) {
108
+ case "aws-apigatewayv1":
109
+ content = this.generateAWSApiGatewayV1Handler(importPath, exportName, relativeEnvParserPath, context.envParserImportPattern);
110
+ break;
111
+ case "aws-apigatewayv2":
112
+ content = this.generateAWSApiGatewayV2Handler(importPath, exportName, relativeEnvParserPath, context.envParserImportPattern);
113
+ break;
114
+ case "server":
115
+ content = this.generateServerHandler(importPath, exportName);
116
+ break;
117
+ default: throw new Error(`Unsupported provider: ${provider}`);
118
+ }
119
+ await (0, node_fs_promises.writeFile)(handlerPath, content);
120
+ return handlerPath;
121
+ }
122
+ async generateEndpointsFile(outputDir, endpoints, _context) {
123
+ const endpointsFileName = "endpoints.ts";
124
+ const endpointsPath = (0, node_path.join)(outputDir, endpointsFileName);
125
+ const importsByFile = /* @__PURE__ */ new Map();
126
+ for (const { path: path$1, key } of endpoints) {
127
+ const relativePath = (0, node_path.relative)((0, node_path.dirname)(endpointsPath), path$1.relative);
128
+ const importPath = relativePath.replace(/\.ts$/, ".js");
129
+ if (!importsByFile.has(importPath)) importsByFile.set(importPath, []);
130
+ importsByFile.get(importPath).push(key);
131
+ }
132
+ const imports = Array.from(importsByFile.entries()).map(([importPath, exports$1]) => `import { ${exports$1.join(", ")} } from '${importPath}';`).join("\n");
133
+ const allExportNames = endpoints.map(({ key }) => key);
134
+ const content = `import type { EnvironmentParser } from '@geekmidas/envkit';
135
+ import type { Logger } from '@geekmidas/logger';
136
+ import { HonoEndpoint } from '@geekmidas/constructs/hono';
137
+ import { Endpoint } from '@geekmidas/constructs/endpoints';
138
+ import { ServiceDiscovery } from '@geekmidas/services';
139
+ import type { Hono } from 'hono';
140
+ ${imports}
141
+
142
+ const endpoints: Endpoint<any, any, any, any, any, any, any, any, any, any, any, any, any, any>[] = [
143
+ ${allExportNames.join(",\n ")}
144
+ ];
145
+
146
+ export async function setupEndpoints(
147
+ app: Hono,
148
+ envParser: EnvironmentParser<any>,
149
+ logger: Logger,
150
+ enableOpenApi: boolean = true,
151
+ ): Promise<void> {
152
+ const serviceDiscovery = ServiceDiscovery.getInstance(
153
+ logger,
154
+ envParser
155
+ );
156
+
157
+ // Configure OpenAPI options based on enableOpenApi flag
158
+ const openApiOptions: any = enableOpenApi ? {
159
+ docsPath: '/__docs',
160
+ openApiOptions: {
161
+ title: 'API Documentation',
162
+ version: '1.0.0',
163
+ description: 'Generated API documentation'
164
+ }
165
+ } : { docsPath: false };
166
+
167
+ HonoEndpoint.addRoutes(endpoints, serviceDiscovery, app, openApiOptions);
168
+
169
+ // Add Swagger UI if OpenAPI is enabled
170
+ if (enableOpenApi) {
171
+ try {
172
+ const { swaggerUI } = await import('@hono/swagger-ui');
173
+ app.get('/__docs/ui', swaggerUI({ url: '/__docs' }));
174
+ } catch {
175
+ // @hono/swagger-ui not installed, skip Swagger UI
176
+ }
177
+ }
178
+ }
179
+ `;
180
+ await (0, node_fs_promises.writeFile)(endpointsPath, content);
181
+ return endpointsPath;
182
+ }
183
+ async generateAppFile(outputDir, context) {
184
+ const appFileName = "app.ts";
185
+ const appPath = (0, node_path.join)(outputDir, appFileName);
186
+ const relativeLoggerPath = (0, node_path.relative)((0, node_path.dirname)(appPath), context.loggerPath);
187
+ const relativeEnvParserPath = (0, node_path.relative)((0, node_path.dirname)(appPath), context.envParserPath);
188
+ const telescopeEnabled = context.telescope?.enabled;
189
+ const telescopeWebSocketEnabled = context.telescope?.websocket;
190
+ const usesExternalTelescope = !!context.telescope?.telescopePath;
191
+ const studioEnabled = context.studio?.enabled;
192
+ const usesExternalStudio = !!context.studio?.studioPath;
193
+ let telescopeImports = "";
194
+ if (telescopeEnabled) if (usesExternalTelescope) {
195
+ const relativeTelescopePath = (0, node_path.relative)((0, node_path.dirname)(appPath), context.telescope.telescopePath);
196
+ telescopeImports = `import ${context.telescope.telescopeImportPattern} from '${relativeTelescopePath}';
197
+ import { createMiddleware, createUI } from '@geekmidas/telescope/hono';`;
198
+ } else telescopeImports = `import { Telescope, InMemoryStorage } from '@geekmidas/telescope';
199
+ import { createMiddleware, createUI } from '@geekmidas/telescope/hono';`;
200
+ let studioImports = "";
201
+ if (studioEnabled) if (usesExternalStudio) {
202
+ const relativeStudioPath = (0, node_path.relative)((0, node_path.dirname)(appPath), context.studio.studioPath);
203
+ studioImports = `import ${context.studio.studioImportPattern} from '${relativeStudioPath}';
204
+ import { createStudioApp } from '@geekmidas/studio/server/hono';`;
205
+ } else studioImports = `// Studio requires a configured instance - use studio config path
206
+ // import { createStudioApp } from '@geekmidas/studio/server/hono';`;
207
+ const telescopeWebSocketSetupCode = telescopeWebSocketEnabled ? `
208
+ // Setup WebSocket for real-time telescope updates
209
+ try {
210
+ const { createNodeWebSocket } = await import('@hono/node-ws');
211
+ const { injectWebSocket, upgradeWebSocket } = createNodeWebSocket({ app: honoApp });
212
+ // Add WebSocket route directly to main app (sub-app routes don't support WS upgrade)
213
+ honoApp.get('${context.telescope.path}/ws', upgradeWebSocket(() => ({
214
+ onOpen: (_event: Event, ws: any) => {
215
+ telescope.addWsClient(ws);
216
+ },
217
+ onClose: (_event: Event, ws: any) => {
218
+ telescope.removeWsClient(ws);
219
+ },
220
+ onMessage: (event: MessageEvent, ws: any) => {
221
+ try {
222
+ const data = JSON.parse(event.data);
223
+ if (data.type === 'ping') {
224
+ ws.send(JSON.stringify({ type: 'pong' }));
225
+ }
226
+ } catch {
227
+ // Ignore invalid messages
228
+ }
229
+ },
230
+ })));
231
+ // Store injectWebSocket for server entry to call after serve()
232
+ (honoApp as any).__injectWebSocket = injectWebSocket;
233
+ logger.info('Telescope WebSocket enabled');
234
+ } catch (e) {
235
+ logger.warn({ error: e }, 'WebSocket support not available - install @hono/node-ws for real-time updates');
236
+ }
237
+ ` : "";
238
+ let telescopeSetup = "";
239
+ if (telescopeEnabled) if (usesExternalTelescope) telescopeSetup = `
240
+ ${telescopeWebSocketSetupCode}
241
+ // Add telescope middleware (before endpoints to capture all requests)
242
+ honoApp.use('*', createMiddleware(telescope));
243
+
244
+ // Mount telescope UI
245
+ const telescopeUI = createUI(telescope);
246
+ honoApp.route('${context.telescope.path}', telescopeUI);
247
+ `;
248
+ else telescopeSetup = `
249
+ // Setup Telescope for debugging/monitoring
250
+ const telescopeStorage = new InMemoryStorage({ maxEntries: ${context.telescope.maxEntries} });
251
+ const telescope = new Telescope({
252
+ enabled: true,
253
+ path: '${context.telescope.path}',
254
+ ignorePatterns: ${JSON.stringify(context.telescope.ignore)},
255
+ recordBody: ${context.telescope.recordBody},
256
+ storage: telescopeStorage,
257
+ });
258
+ ${telescopeWebSocketSetupCode}
259
+ // Add telescope middleware (before endpoints to capture all requests)
260
+ honoApp.use('*', createMiddleware(telescope));
261
+
262
+ // Mount telescope UI
263
+ const telescopeUI = createUI(telescope);
264
+ honoApp.route('${context.telescope.path}', telescopeUI);
265
+ `;
266
+ let studioSetup = "";
267
+ if (studioEnabled && usesExternalStudio) studioSetup = `
268
+ // Mount Studio data browser UI
269
+ const studioApp = createStudioApp(studio);
270
+ honoApp.route('${context.studio.path}', studioApp);
271
+ `;
272
+ const content = `/**
273
+ * Generated server application
274
+ *
275
+ * ⚠️ WARNING: This is for LOCAL DEVELOPMENT ONLY
276
+ * The subscriber polling mechanism is not production-ready.
277
+ * For production, use AWS Lambda with SQS/SNS event sources.
278
+ */
279
+ import { Hono } from 'hono';
280
+ import type { Hono as HonoType } from 'hono';
281
+ import { setupEndpoints } from './endpoints.js';
282
+ import { setupSubscribers } from './subscribers.js';
283
+ import ${context.envParserImportPattern} from '${relativeEnvParserPath}';
284
+ import ${context.loggerImportPattern} from '${relativeLoggerPath}';
285
+ ${telescopeImports}
286
+ ${studioImports}
287
+
288
+ export interface ServerApp {
289
+ app: HonoType;
290
+ start: (options?: {
291
+ port?: number;
292
+ serve: (app: HonoType, port: number) => void | Promise<void>;
293
+ }) => Promise<void>;
294
+ }
295
+
296
+ /**
297
+ * Create and configure the Hono application
298
+ *
299
+ * @param app - Optional Hono app instance to configure (creates new one if not provided)
300
+ * @param enableOpenApi - Enable OpenAPI documentation (default: true)
301
+ * @returns Server app with configured Hono app and start function
302
+ *
303
+ * @example
304
+ * // With Bun
305
+ * import { createApp } from './.gkm/server/app.js';
306
+ *
307
+ * const { app, start } = await createApp();
308
+ *
309
+ * await start({
310
+ * port: 3000,
311
+ * serve: (app, port) => {
312
+ * Bun.serve({ port, fetch: app.fetch });
313
+ * }
314
+ * });
315
+ *
316
+ * @example
317
+ * // With Node.js (using @hono/node-server)
318
+ * import { serve } from '@hono/node-server';
319
+ * import { createApp } from './.gkm/server/app.js';
320
+ *
321
+ * const { app, start } = await createApp();
322
+ *
323
+ * await start({
324
+ * port: 3000,
325
+ * serve: (app, port) => {
326
+ * serve({ fetch: app.fetch, port });
327
+ * }
328
+ * });
329
+ */
330
+ export async function createApp(app?: HonoType, enableOpenApi: boolean = true): Promise<ServerApp> {
331
+ const honoApp = app || new Hono();
332
+ ${telescopeSetup}${studioSetup}
333
+ // Setup HTTP endpoints
334
+ await setupEndpoints(honoApp, envParser, logger, enableOpenApi);
335
+
336
+ return {
337
+ app: honoApp,
338
+ async start(options) {
339
+ if (!options?.serve) {
340
+ throw new Error(
341
+ 'serve function is required. Pass a serve function for your runtime:\\n' +
342
+ ' - Bun: (app, port) => Bun.serve({ port, fetch: app.fetch })\\n' +
343
+ ' - Node: (app, port) => serve({ fetch: app.fetch, port })'
344
+ );
345
+ }
346
+
347
+ const port = options.port ?? 3000;
348
+
349
+ // Start subscribers in background (non-blocking, local development only)
350
+ await setupSubscribers(envParser, logger).catch((error) => {
351
+ logger.error({ error }, 'Failed to start subscribers');
352
+ });
353
+
354
+ logger.info({ port }, 'Starting server');
355
+
356
+ // Start HTTP server using provided serve function
357
+ await options.serve(honoApp, port);
358
+
359
+ logger.info({ port }, 'Server started');
360
+ }
361
+ };
362
+ }
363
+
364
+ // Default export for convenience
365
+ export default createApp;
366
+ `;
367
+ await (0, node_fs_promises.writeFile)(appPath, content);
368
+ return appPath;
369
+ }
370
+ generateAWSApiGatewayV1Handler(importPath, exportName, envParserPath, envParserImportPattern) {
371
+ return `import { AmazonApiGatewayV1Endpoint } from '@geekmidas/constructs/aws';
372
+ import { ${exportName} } from '${importPath}';
373
+ import ${envParserImportPattern} from '${envParserPath}';
374
+
375
+ const adapter = new AmazonApiGatewayV1Endpoint(envParser, ${exportName});
376
+
377
+ export const handler = adapter.handler;
378
+ `;
379
+ }
380
+ generateAWSApiGatewayV2Handler(importPath, exportName, envParserPath, envParserImportPattern) {
381
+ return `import { AmazonApiGatewayV2Endpoint } from '@geekmidas/constructs/aws';
382
+ import { ${exportName} } from '${importPath}';
383
+ import ${envParserImportPattern} from '${envParserPath}';
384
+
385
+ const adapter = new AmazonApiGatewayV2Endpoint(envParser, ${exportName});
386
+
387
+ export const handler = adapter.handler;
388
+ `;
389
+ }
390
+ generateServerHandler(importPath, exportName) {
391
+ return `import { ${exportName} } from '${importPath}';
392
+
393
+ // Server handler - implement based on your server framework
394
+ export const handler = ${exportName};
395
+ `;
396
+ }
397
+ };
398
+
399
+ //#endregion
400
+ //#region src/generators/OpenApiTsGenerator.ts
401
+ /**
402
+ * Generates TypeScript OpenAPI module from endpoints.
403
+ * Outputs:
404
+ * - securitySchemes: typed security scheme definitions
405
+ * - endpointAuth: runtime map of endpoints to auth requirements
406
+ * - paths: TypeScript interface for type-safe fetcher
407
+ * - schema interfaces: reusable TypeScript types from Zod/Valibot schemas
408
+ */
409
+ var OpenApiTsGenerator = class {
410
+ async generate(endpoints, options = {}) {
411
+ const { title = "API", version = "1.0.0", description } = options;
412
+ const endpointInfos = await this.extractEndpointInfos(endpoints);
413
+ const securitySchemes = this.collectSecuritySchemes(endpointInfos);
414
+ const endpointAuth = this.buildEndpointAuthMap(endpointInfos);
415
+ const schemaInterfaces = await this.generateSchemaInterfaces(endpointInfos);
416
+ const pathsInterface = await this.generatePathsInterface(endpointInfos);
417
+ return this.buildModule({
418
+ title,
419
+ version,
420
+ description,
421
+ securitySchemes,
422
+ endpointAuth,
423
+ schemaInterfaces,
424
+ pathsInterface
425
+ });
426
+ }
427
+ async extractEndpointInfos(endpoints) {
428
+ return endpoints.map((ep) => {
429
+ const route = ep.route.replace(/:(\w+)/g, "{$1}");
430
+ const method = ep.method.toUpperCase();
431
+ const securityScheme = ep.authorizer?.securityScheme;
432
+ return {
433
+ endpoint: `${method} ${route}`,
434
+ route,
435
+ method,
436
+ authorizerName: ep.authorizer?.name ?? null,
437
+ authorizerType: ep.authorizer?.type ?? null,
438
+ securityScheme: securityScheme ?? null,
439
+ input: ep.input,
440
+ output: ep.outputSchema,
441
+ description: ep.description,
442
+ tags: ep.tags,
443
+ operationId: ep.operationId
444
+ };
445
+ });
446
+ }
447
+ collectSecuritySchemes(endpointInfos) {
448
+ const schemes = /* @__PURE__ */ new Map();
449
+ for (const info of endpointInfos) if (info.authorizerName && !schemes.has(info.authorizerName)) {
450
+ const scheme = info.securityScheme ?? (info.authorizerType ? this.mapAuthorizerToSecurityScheme(info.authorizerType, info.authorizerName) : null);
451
+ if (scheme) schemes.set(info.authorizerName, {
452
+ name: info.authorizerName,
453
+ type: scheme.type,
454
+ scheme
455
+ });
456
+ }
457
+ return Array.from(schemes.values());
458
+ }
459
+ mapAuthorizerToSecurityScheme(type, _name) {
460
+ switch (type.toLowerCase()) {
461
+ case "jwt":
462
+ case "bearer": return {
463
+ type: "http",
464
+ scheme: "bearer",
465
+ bearerFormat: "JWT"
466
+ };
467
+ case "iam":
468
+ case "aws-sigv4":
469
+ case "sigv4": return {
470
+ type: "apiKey",
471
+ in: "header",
472
+ name: "Authorization",
473
+ "x-amazon-apigateway-authtype": "awsSigv4"
474
+ };
475
+ case "apikey":
476
+ case "api-key": return {
477
+ type: "apiKey",
478
+ in: "header",
479
+ name: "X-API-Key"
480
+ };
481
+ case "oauth2": return {
482
+ type: "oauth2",
483
+ flows: {}
484
+ };
485
+ case "oidc":
486
+ case "openidconnect": return {
487
+ type: "openIdConnect",
488
+ openIdConnectUrl: ""
489
+ };
490
+ default: return {
491
+ type: "http",
492
+ scheme: "bearer"
493
+ };
494
+ }
495
+ }
496
+ buildEndpointAuthMap(endpointInfos) {
497
+ const authMap = {};
498
+ for (const info of endpointInfos) authMap[info.endpoint] = info.authorizerName;
499
+ return authMap;
500
+ }
501
+ async generateSchemaInterfaces(endpointInfos) {
502
+ const interfaces = [];
503
+ const generatedNames = /* @__PURE__ */ new Set();
504
+ const collectedDefs = /* @__PURE__ */ new Map();
505
+ for (const info of endpointInfos) {
506
+ const baseName = this.getSchemaBaseName(info);
507
+ if (info.input?.body) {
508
+ const name = await this.getSchemaName(info.input.body, `${baseName}Input`);
509
+ if (!generatedNames.has(name)) {
510
+ const schema = await this.schemaToInterfaceWithDefs(info.input.body, name, collectedDefs);
511
+ if (schema) {
512
+ interfaces.push(schema);
513
+ generatedNames.add(name);
514
+ }
515
+ }
516
+ }
517
+ if (info.input?.params) {
518
+ const name = await this.getSchemaName(info.input.params, `${baseName}Params`);
519
+ if (!generatedNames.has(name)) {
520
+ const schema = await this.schemaToInterfaceWithDefs(info.input.params, name, collectedDefs);
521
+ if (schema) {
522
+ interfaces.push(schema);
523
+ generatedNames.add(name);
524
+ }
525
+ }
526
+ }
527
+ if (info.input?.query) {
528
+ const name = await this.getSchemaName(info.input.query, `${baseName}Query`);
529
+ if (!generatedNames.has(name)) {
530
+ const schema = await this.schemaToInterfaceWithDefs(info.input.query, name, collectedDefs);
531
+ if (schema) {
532
+ interfaces.push(schema);
533
+ generatedNames.add(name);
534
+ }
535
+ }
536
+ }
537
+ if (info.output) {
538
+ const name = await this.getSchemaName(info.output, `${baseName}Output`);
539
+ if (!generatedNames.has(name)) {
540
+ const schema = await this.schemaToInterfaceWithDefs(info.output, name, collectedDefs);
541
+ if (schema) {
542
+ interfaces.push(schema);
543
+ generatedNames.add(name);
544
+ }
545
+ }
546
+ }
547
+ }
548
+ for (const [defName, defSchema] of collectedDefs) if (!generatedNames.has(defName)) {
549
+ const interfaceStr = this.jsonSchemaToInterface(defSchema, defName);
550
+ interfaces.push(interfaceStr);
551
+ generatedNames.add(defName);
552
+ }
553
+ return interfaces.join("\n\n");
554
+ }
555
+ /**
556
+ * Get the name for a schema, using metadata `id` if available,
557
+ * otherwise falling back to the provided default name.
558
+ */
559
+ async getSchemaName(schema, defaultName) {
560
+ try {
561
+ const metadata = await (0, __geekmidas_schema_conversion.getSchemaMetadata)(schema);
562
+ if (metadata?.id) return this.pascalCase(metadata.id);
563
+ } catch {}
564
+ return defaultName;
565
+ }
566
+ getSchemaBaseName(info) {
567
+ if (info.operationId) return this.pascalCase(info.operationId);
568
+ const routeParts = info.route.replace(/[{}]/g, "").split("/").filter(Boolean).map((part) => this.pascalCase(part));
569
+ return `${this.pascalCase(info.method.toLowerCase())}${routeParts.join("")}`;
570
+ }
571
+ pascalCase(str) {
572
+ return str.replace(/[-_](.)/g, (_, c) => c.toUpperCase()).replace(/^./, (c) => c.toUpperCase());
573
+ }
574
+ /**
575
+ * Convert schema to interface while collecting $defs for nested schemas
576
+ * with .meta({ id: 'X' }).
577
+ */
578
+ async schemaToInterfaceWithDefs(schema, name, collectedDefs) {
579
+ try {
580
+ const vendor = schema["~standard"]?.vendor;
581
+ if (!vendor || !(vendor in __geekmidas_schema_conversion.StandardSchemaJsonSchema)) return null;
582
+ const toJsonSchema = __geekmidas_schema_conversion.StandardSchemaJsonSchema[vendor];
583
+ const jsonSchema = await toJsonSchema(schema);
584
+ if (!jsonSchema) return null;
585
+ if (jsonSchema.$defs && typeof jsonSchema.$defs === "object") {
586
+ for (const [defName, defSchema] of Object.entries(jsonSchema.$defs)) if (!collectedDefs.has(defName)) {
587
+ const { id,...schemaWithoutId } = defSchema;
588
+ collectedDefs.set(defName, schemaWithoutId);
589
+ }
590
+ }
591
+ const { $defs,...schemaWithoutDefs } = jsonSchema;
592
+ return this.jsonSchemaToInterface(schemaWithoutDefs, name);
593
+ } catch {
594
+ return null;
595
+ }
596
+ }
597
+ jsonSchemaToInterface(schema, name) {
598
+ if (schema.type !== "object" || !schema.properties) {
599
+ const typeStr = this.jsonSchemaTypeToTs(schema);
600
+ return `export type ${name} = ${typeStr};`;
601
+ }
602
+ const props = [];
603
+ const required = new Set(schema.required || []);
604
+ for (const [propName, propSchema] of Object.entries(schema.properties)) {
605
+ const isRequired = required.has(propName);
606
+ const typeStr = this.jsonSchemaTypeToTs(propSchema);
607
+ const optionalMark = isRequired ? "" : "?";
608
+ props.push(` ${propName}${optionalMark}: ${typeStr};`);
609
+ }
610
+ return `export interface ${name} {\n${props.join("\n")}\n}`;
611
+ }
612
+ jsonSchemaTypeToTs(schema) {
613
+ if (!schema) return "unknown";
614
+ if (schema.$ref) {
615
+ const refName = schema.$ref.split("/").pop() || "unknown";
616
+ return refName;
617
+ }
618
+ if (schema.anyOf) return schema.anyOf.map((s) => this.jsonSchemaTypeToTs(s)).join(" | ");
619
+ if (schema.oneOf) return schema.oneOf.map((s) => this.jsonSchemaTypeToTs(s)).join(" | ");
620
+ if (schema.allOf) return schema.allOf.map((s) => this.jsonSchemaTypeToTs(s)).join(" & ");
621
+ switch (schema.type) {
622
+ case "string":
623
+ if (schema.enum) return schema.enum.map((e) => `'${e}'`).join(" | ");
624
+ return "string";
625
+ case "number":
626
+ case "integer": return "number";
627
+ case "boolean": return "boolean";
628
+ case "null": return "null";
629
+ case "array":
630
+ if (schema.items) return `Array<${this.jsonSchemaTypeToTs(schema.items)}>`;
631
+ return "Array<unknown>";
632
+ case "object":
633
+ if (schema.properties) {
634
+ const props = [];
635
+ const required = new Set(schema.required || []);
636
+ for (const [propName, propSchema] of Object.entries(schema.properties)) {
637
+ const isRequired = required.has(propName);
638
+ const typeStr = this.jsonSchemaTypeToTs(propSchema);
639
+ const optionalMark = isRequired ? "" : "?";
640
+ props.push(`${propName}${optionalMark}: ${typeStr}`);
641
+ }
642
+ return `{ ${props.join("; ")} }`;
643
+ }
644
+ if (schema.additionalProperties) {
645
+ const valueType = this.jsonSchemaTypeToTs(schema.additionalProperties);
646
+ return `Record<string, ${valueType}>`;
647
+ }
648
+ return "Record<string, unknown>";
649
+ default: return "unknown";
650
+ }
651
+ }
652
+ async generatePathsInterface(endpointInfos) {
653
+ const pathGroups = /* @__PURE__ */ new Map();
654
+ for (const info of endpointInfos) {
655
+ const existing = pathGroups.get(info.route) || [];
656
+ existing.push(info);
657
+ pathGroups.set(info.route, existing);
658
+ }
659
+ const pathEntries = [];
660
+ for (const [route, infos] of pathGroups) {
661
+ const methodEntries = [];
662
+ for (const info of infos) {
663
+ const methodDef = await this.generateMethodDefinition(info);
664
+ methodEntries.push(` ${info.method.toLowerCase()}: ${methodDef};`);
665
+ }
666
+ const firstWithParams = infos.find((i) => i.input?.params);
667
+ let paramsEntry = "";
668
+ if (firstWithParams?.input?.params) {
669
+ const paramsName = await this.getSchemaName(firstWithParams.input.params, `${this.getSchemaBaseName(firstWithParams)}Params`);
670
+ paramsEntry = `\n parameters: {\n path: ${paramsName};\n };`;
671
+ }
672
+ pathEntries.push(` '${route}': {${paramsEntry}\n${methodEntries.join("\n")}\n };`);
673
+ }
674
+ return `export interface paths {\n${pathEntries.join("\n")}\n}`;
675
+ }
676
+ async generateMethodDefinition(info) {
677
+ const parts = [];
678
+ const baseName = this.getSchemaBaseName(info);
679
+ if (info.input?.body) {
680
+ const bodyName = await this.getSchemaName(info.input.body, `${baseName}Input`);
681
+ parts.push(`requestBody: {
682
+ content: {
683
+ 'application/json': ${bodyName};
684
+ };
685
+ }`);
686
+ }
687
+ if (info.input?.query) {
688
+ const queryName = await this.getSchemaName(info.input.query, `${baseName}Query`);
689
+ parts.push(`parameters: {
690
+ query: ${queryName};
691
+ }`);
692
+ }
693
+ const outputName = info.output ? await this.getSchemaName(info.output, `${baseName}Output`) : "unknown";
694
+ parts.push(`responses: {
695
+ 200: {
696
+ content: {
697
+ 'application/json': ${outputName};
698
+ };
699
+ };
700
+ }`);
701
+ return `{\n ${parts.join(";\n ")};\n }`;
702
+ }
703
+ buildModule(params) {
704
+ const { title, version, description, securitySchemes, endpointAuth, schemaInterfaces, pathsInterface } = params;
705
+ const securitySchemesObj = securitySchemes.reduce((acc, s) => {
706
+ acc[s.name] = s.scheme;
707
+ return acc;
708
+ }, {});
709
+ const schemeNames = securitySchemes.map((s) => `'${s.name}'`).join(" | ");
710
+ const hasSecuritySchemes = schemeNames.length > 0;
711
+ const createApiSection = hasSecuritySchemes ? `
712
+ // ============================================================
713
+ // API Client Factory
714
+ // ============================================================
715
+
716
+ import {
717
+ createAuthAwareFetcher,
718
+ type AuthStrategy,
719
+ } from '@geekmidas/client/auth-fetcher';
720
+ import { createEndpointHooks } from '@geekmidas/client/endpoint-hooks';
721
+ import type { QueryClient } from '@tanstack/react-query';
722
+
723
+ /**
724
+ * Options for creating the API client.
725
+ */
726
+ export interface CreateApiOptions {
727
+ /** Base URL for all API requests (required) */
728
+ baseURL: string;
729
+ /** Auth strategies for each security scheme used in this API */
730
+ authStrategies: Record<SecuritySchemeId, AuthStrategy>;
731
+ /** Optional React Query client instance */
732
+ queryClient?: QueryClient;
733
+ /** Optional request interceptor */
734
+ onRequest?: (config: RequestInit) => RequestInit | Promise<RequestInit>;
735
+ }
736
+
737
+ /**
738
+ * Create a type-safe API client with authentication and React Query hooks.
739
+ *
740
+ * @example
741
+ * \`\`\`typescript
742
+ * const api = createApi({
743
+ * baseURL: 'https://api.example.com',
744
+ * authStrategies: {
745
+ * jwt: { type: 'bearer', tokenProvider },
746
+ * },
747
+ * });
748
+ *
749
+ * // Imperative fetch
750
+ * const user = await api('GET /users/{id}', { params: { id: '123' } });
751
+ *
752
+ * // React Query hooks
753
+ * const { data } = api.useQuery('GET /users/{id}', { params: { id: '123' } });
754
+ * const mutation = api.useMutation('POST /users');
755
+ * \`\`\`
756
+ */
757
+ export function createApi(options: CreateApiOptions) {
758
+ const fetcher = createAuthAwareFetcher<paths, typeof endpointAuth, typeof securitySchemes>({
759
+ baseURL: options.baseURL,
760
+ endpointAuth,
761
+ securitySchemes,
762
+ authStrategies: options.authStrategies,
763
+ onRequest: options.onRequest,
764
+ });
765
+
766
+ const hooks = createEndpointHooks<paths>(fetcher, { queryClient: options.queryClient });
767
+
768
+ return Object.assign(fetcher, hooks);
769
+ }
770
+ ` : `
771
+ // ============================================================
772
+ // API Client Factory
773
+ // ============================================================
774
+
775
+ import { TypedFetcher, type FetcherOptions } from '@geekmidas/client/fetcher';
776
+ import { createEndpointHooks } from '@geekmidas/client/endpoint-hooks';
777
+ import type { QueryClient } from '@tanstack/react-query';
778
+
779
+ /**
780
+ * Options for creating the API client.
781
+ */
782
+ export interface CreateApiOptions extends Omit<FetcherOptions, 'baseURL'> {
783
+ /** Base URL for all API requests (required) */
784
+ baseURL: string;
785
+ /** Optional React Query client instance */
786
+ queryClient?: QueryClient;
787
+ }
788
+
789
+ /**
790
+ * Create a type-safe API client with React Query hooks.
791
+ *
792
+ * @example
793
+ * \`\`\`typescript
794
+ * const api = createApi({
795
+ * baseURL: 'https://api.example.com',
796
+ * });
797
+ *
798
+ * // Imperative fetch
799
+ * const data = await api('GET /health');
800
+ *
801
+ * // React Query hooks
802
+ * const { data } = api.useQuery('GET /health');
803
+ * \`\`\`
804
+ */
805
+ export function createApi(options: CreateApiOptions) {
806
+ const { queryClient, ...fetcherOptions } = options;
807
+ const fetcher = new TypedFetcher<paths>(fetcherOptions);
808
+
809
+ const hooks = createEndpointHooks<paths>(fetcher.request.bind(fetcher), { queryClient });
810
+
811
+ return Object.assign(fetcher.request.bind(fetcher), hooks);
812
+ }
813
+ `;
814
+ return `// Auto-generated by @geekmidas/cli - DO NOT EDIT
815
+ // Generated: ${(/* @__PURE__ */ new Date()).toISOString()}
816
+
817
+ // ============================================================
818
+ // Security Scheme Type
819
+ // ============================================================
820
+
821
+ interface SecuritySchemeObject {
822
+ type: 'apiKey' | 'http' | 'mutualTLS' | 'oauth2' | 'openIdConnect';
823
+ description?: string;
824
+ name?: string;
825
+ in?: 'query' | 'header' | 'cookie';
826
+ scheme?: string;
827
+ bearerFormat?: string;
828
+ flows?: Record<string, unknown>;
829
+ openIdConnectUrl?: string;
830
+ [key: string]: unknown;
831
+ }
832
+
833
+ // ============================================================
834
+ // API Info
835
+ // ============================================================
836
+
837
+ export const apiInfo = {
838
+ title: '${title}',
839
+ version: '${version}',${description ? `\n description: '${description.replace(/'/g, "\\'")}',` : ""}
840
+ } as const;
841
+
842
+ // ============================================================
843
+ // Security Schemes
844
+ // ============================================================
845
+
846
+ /**
847
+ * Available security schemes for this API.
848
+ * Maps authorizer names to OpenAPI security scheme definitions.
849
+ */
850
+ export const securitySchemes = ${JSON.stringify(securitySchemesObj, null, 2).replace(/"([a-zA-Z_$][a-zA-Z0-9_$]*)":/g, "$1:")} as const satisfies Record<string, SecuritySchemeObject>;
851
+
852
+ export type SecuritySchemeId = ${schemeNames || "never"};
853
+
854
+ // ============================================================
855
+ // Endpoint Authentication Map
856
+ // ============================================================
857
+
858
+ /**
859
+ * Runtime map of endpoints to their required authentication scheme.
860
+ * \`null\` indicates a public endpoint (no auth required).
861
+ */
862
+ export const endpointAuth = ${JSON.stringify(endpointAuth, null, 2).replace(/"([^"]+)":/g, "'$1':")} as const satisfies Record<string, SecuritySchemeId | null>;
863
+
864
+ export type EndpointString = keyof typeof endpointAuth;
865
+
866
+ export type AuthenticatedEndpoint = {
867
+ [K in EndpointString]: typeof endpointAuth[K] extends null ? never : K;
868
+ }[EndpointString];
869
+
870
+ export type PublicEndpoint = {
871
+ [K in EndpointString]: typeof endpointAuth[K] extends null ? K : never;
872
+ }[EndpointString];
873
+
874
+ // ============================================================
875
+ // Schema Definitions
876
+ // ============================================================
877
+
878
+ ${schemaInterfaces}
879
+
880
+ // ============================================================
881
+ // OpenAPI Paths
882
+ // ============================================================
883
+
884
+ ${pathsInterface}
885
+ ${createApiSection}
886
+ `;
887
+ }
888
+ };
889
+
890
+ //#endregion
891
+ //#region src/openapi.ts
892
+ /**
893
+ * Fixed output path for generated OpenAPI client (not configurable)
894
+ */
895
+ const OPENAPI_OUTPUT_PATH = "./.gkm/openapi.ts";
896
+ /**
897
+ * Resolve OpenAPI config from GkmConfig
898
+ */
899
+ function resolveOpenApiConfig(config) {
900
+ if (config.openapi === false) return { enabled: false };
901
+ if (config.openapi === true || config.openapi === void 0) return {
902
+ enabled: config.openapi === true,
903
+ title: "API Documentation",
904
+ version: "1.0.0",
905
+ description: "Auto-generated API documentation from endpoints"
906
+ };
907
+ return {
908
+ enabled: config.openapi.enabled !== false,
909
+ title: config.openapi.title || "API Documentation",
910
+ version: config.openapi.version || "1.0.0",
911
+ description: config.openapi.description || "Auto-generated API documentation from endpoints"
912
+ };
913
+ }
914
+ /**
915
+ * Generate OpenAPI spec from endpoints
916
+ * @returns Object with output path and endpoint count, or null if disabled
917
+ */
918
+ async function generateOpenApi(config, options = {}) {
919
+ const logger = options.silent ? { log: () => {} } : console;
920
+ const openApiConfig = resolveOpenApiConfig(config);
921
+ if (!openApiConfig.enabled) return null;
922
+ const endpointGenerator = new EndpointGenerator();
923
+ const loadedEndpoints = await endpointGenerator.load(config.routes);
924
+ if (loadedEndpoints.length === 0) {
925
+ logger.log("No valid endpoints found for OpenAPI generation");
926
+ return null;
927
+ }
928
+ const endpoints = loadedEndpoints.map(({ construct }) => construct);
929
+ const outputPath = (0, node_path.join)(process.cwd(), OPENAPI_OUTPUT_PATH);
930
+ await (0, node_fs_promises.mkdir)((0, node_path.dirname)(outputPath), { recursive: true });
931
+ const tsGenerator = new OpenApiTsGenerator();
932
+ const tsContent = await tsGenerator.generate(endpoints, {
933
+ title: openApiConfig.title,
934
+ version: openApiConfig.version,
935
+ description: openApiConfig.description
936
+ });
937
+ await (0, node_fs_promises.writeFile)(outputPath, tsContent);
938
+ logger.log(`📄 OpenAPI client generated: ${OPENAPI_OUTPUT_PATH}`);
939
+ return {
940
+ outputPath,
941
+ endpointCount: loadedEndpoints.length
942
+ };
943
+ }
944
+ async function openapiCommand(options = {}) {
945
+ const logger = console;
946
+ try {
947
+ const config = await require_config.loadConfig(options.cwd);
948
+ if (!config.openapi) config.openapi = { enabled: true };
949
+ const result = await generateOpenApi(config);
950
+ if (result) logger.log(`Found ${result.endpointCount} endpoints`);
951
+ } catch (error) {
952
+ throw new Error(`OpenAPI generation failed: ${error.message}`);
953
+ }
954
+ }
955
+
956
+ //#endregion
957
+ Object.defineProperty(exports, 'ConstructGenerator', {
958
+ enumerable: true,
959
+ get: function () {
960
+ return ConstructGenerator;
961
+ }
962
+ });
963
+ Object.defineProperty(exports, 'EndpointGenerator', {
964
+ enumerable: true,
965
+ get: function () {
966
+ return EndpointGenerator;
967
+ }
968
+ });
969
+ Object.defineProperty(exports, 'OPENAPI_OUTPUT_PATH', {
970
+ enumerable: true,
971
+ get: function () {
972
+ return OPENAPI_OUTPUT_PATH;
973
+ }
974
+ });
975
+ Object.defineProperty(exports, 'generateOpenApi', {
976
+ enumerable: true,
977
+ get: function () {
978
+ return generateOpenApi;
979
+ }
980
+ });
981
+ Object.defineProperty(exports, 'openapiCommand', {
982
+ enumerable: true,
983
+ get: function () {
984
+ return openapiCommand;
985
+ }
986
+ });
987
+ Object.defineProperty(exports, 'resolveOpenApiConfig', {
988
+ enumerable: true,
989
+ get: function () {
990
+ return resolveOpenApiConfig;
991
+ }
992
+ });
993
+ //# sourceMappingURL=openapi-tAIbJJU_.cjs.map