@geekmidas/cli 10.0.0-alpha.69 → 10.0.0-alpha.71

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 (148) hide show
  1. package/dist/{LegacyStateStore-LS_uTO8D.cjs → LegacyStateStore-Dd5IwiyC.cjs} +2 -2
  2. package/dist/{LegacyStateStore-LS_uTO8D.cjs.map → LegacyStateStore-Dd5IwiyC.cjs.map} +1 -1
  3. package/dist/{LegacyStateStore-BE1Et8RS.mjs → LegacyStateStore-NSHEinQi.mjs} +2 -2
  4. package/dist/{LegacyStateStore-BE1Et8RS.mjs.map → LegacyStateStore-NSHEinQi.mjs.map} +1 -1
  5. package/dist/{LocalStateStore-CV6phNMZ.cjs → LocalStateStore-DTylG4T4.cjs} +2 -2
  6. package/dist/{LocalStateStore-CV6phNMZ.cjs.map → LocalStateStore-DTylG4T4.cjs.map} +1 -1
  7. package/dist/{LocalStateStore-DAnFc708.mjs → LocalStateStore-DUoG2wA_.mjs} +2 -2
  8. package/dist/{LocalStateStore-DAnFc708.mjs.map → LocalStateStore-DUoG2wA_.mjs.map} +1 -1
  9. package/dist/{OpenApiTsGenerator-CSaXs-dB.mjs → OpenApiTsGenerator-Bhr_XWWN.mjs} +57 -638
  10. package/dist/OpenApiTsGenerator-Bhr_XWWN.mjs.map +1 -0
  11. package/dist/{OpenApiTsGenerator-CxB8mqXz.cjs → OpenApiTsGenerator-DZZwHdDC.cjs} +57 -638
  12. package/dist/OpenApiTsGenerator-DZZwHdDC.cjs.map +1 -0
  13. package/dist/{S3StateStore-dA34LAYm.cjs → S3StateStore-D7hrU-sy.cjs} +2 -2
  14. package/dist/{S3StateStore-dA34LAYm.cjs.map → S3StateStore-D7hrU-sy.cjs.map} +1 -1
  15. package/dist/{S3StateStore-8kJEGnTh.mjs → S3StateStore-Dxob3PNA.mjs} +2 -2
  16. package/dist/{S3StateStore-8kJEGnTh.mjs.map → S3StateStore-Dxob3PNA.mjs.map} +1 -1
  17. package/dist/{SSMStateStore-DBzlfc-S.cjs → SSMStateStore-DGIKJ4NN.cjs} +2 -2
  18. package/dist/{SSMStateStore-DBzlfc-S.cjs.map → SSMStateStore-DGIKJ4NN.cjs.map} +1 -1
  19. package/dist/{SSMStateStore-Dkdw-fPL.mjs → SSMStateStore-Dvl4A8Up.mjs} +2 -2
  20. package/dist/{SSMStateStore-Dkdw-fPL.mjs.map → SSMStateStore-Dvl4A8Up.mjs.map} +1 -1
  21. package/dist/{add-CoIr2wgv.cjs → add-DeC2Kyyv.cjs} +3 -3
  22. package/dist/{add-CoIr2wgv.cjs.map → add-DeC2Kyyv.cjs.map} +1 -1
  23. package/dist/{add-Dzk23476.mjs → add-XTLU19_E.mjs} +3 -3
  24. package/dist/{add-Dzk23476.mjs.map → add-XTLU19_E.mjs.map} +1 -1
  25. package/dist/{bundler-CSR2nM4m.cjs → bundler-CEaR6Dpb.cjs} +6 -6
  26. package/dist/bundler-CEaR6Dpb.cjs.map +1 -0
  27. package/dist/{bundler-Cn0JF5G0.mjs → bundler-CNTVLCCA.mjs} +6 -6
  28. package/dist/bundler-CNTVLCCA.mjs.map +1 -0
  29. package/dist/{cli-ij8Lwlww.mjs → cli-D1arS0p1.mjs} +3 -3
  30. package/dist/{cli-ij8Lwlww.mjs.map → cli-D1arS0p1.mjs.map} +1 -1
  31. package/dist/{cli-IoM2-x48.cjs → cli-MMgBrHx7.cjs} +3 -3
  32. package/dist/{cli-IoM2-x48.cjs.map → cli-MMgBrHx7.cjs.map} +1 -1
  33. package/dist/{compose-DfIioFX0.cjs → compose-B-MME-4C.cjs} +358 -16
  34. package/dist/compose-B-MME-4C.cjs.map +1 -0
  35. package/dist/{compose-CZtinmtw.mjs → compose-T3hnnjKZ.mjs} +353 -17
  36. package/dist/compose-T3hnnjKZ.mjs.map +1 -0
  37. package/dist/{config-CxEp_g7j.d.mts → config-BN6iXvyR.d.mts} +3 -3
  38. package/dist/{config-BnA0kPTY.d.cts.map → config-BN6iXvyR.d.mts.map} +1 -1
  39. package/dist/{config-BnA0kPTY.d.cts → config-j9zBKaEG.d.cts} +3 -3
  40. package/dist/{config-CxEp_g7j.d.mts.map → config-j9zBKaEG.d.cts.map} +1 -1
  41. package/dist/config.cjs +1 -1
  42. package/dist/config.d.cts +3 -3
  43. package/dist/config.d.mts +3 -3
  44. package/dist/config.mjs +1 -1
  45. package/dist/deploy/public.cjs +6 -6
  46. package/dist/deploy/public.d.cts +3 -3
  47. package/dist/deploy/public.d.cts.map +1 -1
  48. package/dist/deploy/public.d.mts +3 -3
  49. package/dist/deploy/public.d.mts.map +1 -1
  50. package/dist/deploy/public.mjs +6 -6
  51. package/dist/{deploy-Dpz9raPM.cjs → deploy-CZE0m6jd.cjs} +5 -5
  52. package/dist/{deploy-Dpz9raPM.cjs.map → deploy-CZE0m6jd.cjs.map} +1 -1
  53. package/dist/{deploy-BzqbkJ3o.mjs → deploy-ClC53rc6.mjs} +5 -5
  54. package/dist/{deploy-BzqbkJ3o.mjs.map → deploy-ClC53rc6.mjs.map} +1 -1
  55. package/dist/{dokploy-DkwcORbv.mjs → dokploy-D1UwQKm3.mjs} +2 -2
  56. package/dist/{dokploy-DkwcORbv.mjs.map → dokploy-D1UwQKm3.mjs.map} +1 -1
  57. package/dist/{dokploy-B6O-J1fb.cjs → dokploy-lwmH05zr.cjs} +2 -2
  58. package/dist/{dokploy-B6O-J1fb.cjs.map → dokploy-lwmH05zr.cjs.map} +1 -1
  59. package/dist/{encryption-C8Ic5t0C.cjs → encryption-D05sNwED.cjs} +3 -3
  60. package/dist/{encryption-C8Ic5t0C.cjs.map → encryption-D05sNwED.cjs.map} +1 -1
  61. package/dist/{encryption-7m1mKcRy.mjs → encryption-DcrxWl1s.mjs} +3 -3
  62. package/dist/{encryption-7m1mKcRy.mjs.map → encryption-DcrxWl1s.mjs.map} +1 -1
  63. package/dist/{engine-BR9qlS7A.cjs → engine-Cry1vwMz.cjs} +6 -5
  64. package/dist/engine-Cry1vwMz.cjs.map +1 -0
  65. package/dist/{engine-62Kl70Pj.mjs → engine-DmQS3XHX.mjs} +6 -5
  66. package/dist/{engine-62Kl70Pj.mjs.map → engine-DmQS3XHX.mjs.map} +1 -1
  67. package/dist/{github-CmGIZjhu.cjs → github-BchWoiVx.cjs} +3 -3
  68. package/dist/{github-CmGIZjhu.cjs.map → github-BchWoiVx.cjs.map} +1 -1
  69. package/dist/{github-DtymyOcH.mjs → github-CqYOP8cI.mjs} +3 -3
  70. package/dist/{github-DtymyOcH.mjs.map → github-CqYOP8cI.mjs.map} +1 -1
  71. package/dist/{index-CkX89m6S.d.mts → index-Bk3NY6DN.d.cts} +2 -2
  72. package/dist/{index-CkX89m6S.d.mts.map → index-Bk3NY6DN.d.cts.map} +1 -1
  73. package/dist/{index-EvZBkycu.d.cts → index-DvoxuTqR.d.mts} +2 -2
  74. package/dist/{index-EvZBkycu.d.cts.map → index-DvoxuTqR.d.mts.map} +1 -1
  75. package/dist/index.cjs +53 -52
  76. package/dist/index.cjs.map +1 -1
  77. package/dist/index.mjs +53 -52
  78. package/dist/index.mjs.map +1 -1
  79. package/dist/{migrate-CEzq6DjL.mjs → migrate-guck0NJK.mjs} +3 -3
  80. package/dist/{migrate-CEzq6DjL.mjs.map → migrate-guck0NJK.mjs.map} +1 -1
  81. package/dist/{migrate-CYC-hBOU.cjs → migrate-qKeGYq21.cjs} +3 -3
  82. package/dist/{migrate-CYC-hBOU.cjs.map → migrate-qKeGYq21.cjs.map} +1 -1
  83. package/dist/openapi.cjs +1 -1
  84. package/dist/openapi.d.cts +1 -1
  85. package/dist/openapi.d.mts +1 -1
  86. package/dist/openapi.mjs +1 -1
  87. package/dist/{ready-QGgjmcuN.cjs → ready-Dp6arkI4.cjs} +5 -5
  88. package/dist/ready-Dp6arkI4.cjs.map +1 -0
  89. package/dist/{ready-DeYaSoNN.mjs → ready-xpoX11uu.mjs} +5 -5
  90. package/dist/ready-xpoX11uu.mjs.map +1 -0
  91. package/dist/reconcile/public.d.cts +1 -1
  92. package/dist/reconcile/public.d.mts +1 -1
  93. package/dist/{resolve-Dn5wGf1r.mjs → resolve-BsXEXAUz.mjs} +3 -3
  94. package/dist/{resolve-Dn5wGf1r.mjs.map → resolve-BsXEXAUz.mjs.map} +1 -1
  95. package/dist/{resolve-BDsMffvz.cjs → resolve-wEjEvbJ5.cjs} +3 -3
  96. package/dist/{resolve-BDsMffvz.cjs.map → resolve-wEjEvbJ5.cjs.map} +1 -1
  97. package/dist/{rollback-DDfaqv7P.mjs → rollback-Bk91csFg.mjs} +5 -5
  98. package/dist/{rollback-DDfaqv7P.mjs.map → rollback-Bk91csFg.mjs.map} +1 -1
  99. package/dist/{rollback-5XHaBDxW.cjs → rollback-DmcU-efZ.cjs} +5 -5
  100. package/dist/{rollback-5XHaBDxW.cjs.map → rollback-DmcU-efZ.cjs.map} +1 -1
  101. package/dist/{runtime-B3jNgeP-.d.mts → runtime-CYAO4iZG.d.cts} +2 -2
  102. package/dist/{runtime-B3jNgeP-.d.mts.map → runtime-CYAO4iZG.d.cts.map} +1 -1
  103. package/dist/{runtime-DWThEP-r.d.cts → runtime-DHJhe4QI.d.mts} +2 -2
  104. package/dist/{runtime-DWThEP-r.d.cts.map → runtime-DHJhe4QI.d.mts.map} +1 -1
  105. package/dist/{sniffer-Bc0nNBDF.cjs → sniffer-DpHpFZBD.cjs} +6 -6
  106. package/dist/sniffer-DpHpFZBD.cjs.map +1 -0
  107. package/dist/{sniffer-DMqi2b1q.mjs → sniffer-vAXsU_4G.mjs} +6 -6
  108. package/dist/sniffer-vAXsU_4G.mjs.map +1 -0
  109. package/dist/{state-DClnPZt5.mjs → state-BJFherj1.mjs} +60 -5
  110. package/dist/state-BJFherj1.mjs.map +1 -0
  111. package/dist/{state-8RgXeX5Y.cjs → state-CCuTJNRH.cjs} +71 -4
  112. package/dist/state-CCuTJNRH.cjs.map +1 -0
  113. package/dist/target/public.cjs +1 -1
  114. package/dist/target/public.d.cts +2 -2
  115. package/dist/target/public.d.mts +2 -2
  116. package/dist/target/public.mjs +1 -1
  117. package/dist/{types-CZdCxUCK.d.cts → types-BD1jgA85.d.cts} +70 -2
  118. package/dist/types-BD1jgA85.d.cts.map +1 -0
  119. package/dist/{types-Da0E3Qv7.d.mts → types-DkG5WW8l.d.mts} +70 -2
  120. package/dist/types-DkG5WW8l.d.mts.map +1 -0
  121. package/dist/vitest.cjs +1 -1
  122. package/dist/vitest.mjs +1 -1
  123. package/dist/workspace/index.cjs +1 -1
  124. package/dist/workspace/index.d.cts +3 -3
  125. package/dist/workspace/index.d.mts +3 -3
  126. package/dist/workspace/index.mjs +1 -1
  127. package/dist/{workspace-B2UK_rVP.mjs → workspace-C7NqCsQF.mjs} +104 -2
  128. package/dist/workspace-C7NqCsQF.mjs.map +1 -0
  129. package/dist/{workspace-8NuAjaXJ.cjs → workspace-vdrcRI-m.cjs} +115 -1
  130. package/dist/workspace-vdrcRI-m.cjs.map +1 -0
  131. package/package.json +15 -15
  132. package/dist/OpenApiTsGenerator-CSaXs-dB.mjs.map +0 -1
  133. package/dist/OpenApiTsGenerator-CxB8mqXz.cjs.map +0 -1
  134. package/dist/bundler-CSR2nM4m.cjs.map +0 -1
  135. package/dist/bundler-Cn0JF5G0.mjs.map +0 -1
  136. package/dist/compose-CZtinmtw.mjs.map +0 -1
  137. package/dist/compose-DfIioFX0.cjs.map +0 -1
  138. package/dist/engine-BR9qlS7A.cjs.map +0 -1
  139. package/dist/ready-DeYaSoNN.mjs.map +0 -1
  140. package/dist/ready-QGgjmcuN.cjs.map +0 -1
  141. package/dist/sniffer-Bc0nNBDF.cjs.map +0 -1
  142. package/dist/sniffer-DMqi2b1q.mjs.map +0 -1
  143. package/dist/state-8RgXeX5Y.cjs.map +0 -1
  144. package/dist/state-DClnPZt5.mjs.map +0 -1
  145. package/dist/types-CZdCxUCK.d.cts.map +0 -1
  146. package/dist/types-Da0E3Qv7.d.mts.map +0 -1
  147. package/dist/workspace-8NuAjaXJ.cjs.map +0 -1
  148. package/dist/workspace-B2UK_rVP.mjs.map +0 -1
@@ -4,579 +4,6 @@ import { existsSync, realpathSync } from "node:fs";
4
4
  import { mkdir, writeFile } from "node:fs/promises";
5
5
  import { Endpoint } from "@geekmidas/constructs/endpoints";
6
6
  import { StandardSchemaJsonSchema, getRegisteredZodJsonSchemas, getSchemaMetadata } from "@geekmidas/schema/conversion";
7
- //#region src/build/endpoint-analyzer.ts
8
- /**
9
- * Analyze an endpoint to extract its features
10
- */
11
- function analyzeEndpointFeatures(endpoint) {
12
- return {
13
- hasAuth: !!endpoint.authorizer || endpoint.hasSession === true,
14
- hasServices: endpoint.services.length > 0,
15
- hasDatabase: !!endpoint.databaseService,
16
- hasBodyValidation: !!endpoint.input?.body,
17
- hasQueryValidation: !!endpoint.input?.query,
18
- hasParamValidation: !!endpoint.input?.params,
19
- hasAudits: (endpoint.audits?.length ?? 0) > 0,
20
- hasEvents: (endpoint.events?.length ?? 0) > 0,
21
- hasRateLimit: !!endpoint.rateLimit,
22
- hasRls: !!endpoint.rlsConfig && !endpoint.rlsBypass,
23
- hasOutputValidation: !!endpoint.outputSchema
24
- };
25
- }
26
- /**
27
- * Determine the optimization tier for an endpoint based on its features
28
- */
29
- function determineEndpointTier(features) {
30
- const { hasAuth, hasServices, hasDatabase, hasAudits, hasEvents, hasRateLimit, hasRls } = features;
31
- if (!hasAuth && !hasServices && !hasDatabase && !hasAudits && !hasEvents && !hasRateLimit && !hasRls) return "minimal";
32
- if (hasAudits || hasRls || hasRateLimit) return "full";
33
- return "standard";
34
- }
35
- /**
36
- * Perform complete analysis of an endpoint
37
- */
38
- function analyzeEndpoint(endpoint, exportName) {
39
- const features = analyzeEndpointFeatures(endpoint);
40
- const tier = determineEndpointTier(features);
41
- return {
42
- route: endpoint.route,
43
- method: endpoint.method,
44
- exportName,
45
- features,
46
- tier,
47
- serviceNames: endpoint.services.map((s) => s.serviceName),
48
- databaseServiceName: endpoint.databaseService?.serviceName
49
- };
50
- }
51
- /**
52
- * Generate a summary of endpoint analysis for logging
53
- */
54
- function summarizeAnalysis(analyses) {
55
- const byTier = {
56
- minimal: 0,
57
- standard: 0,
58
- full: 0
59
- };
60
- const byFeature = {
61
- hasAuth: 0,
62
- hasServices: 0,
63
- hasDatabase: 0,
64
- hasBodyValidation: 0,
65
- hasQueryValidation: 0,
66
- hasParamValidation: 0,
67
- hasAudits: 0,
68
- hasEvents: 0,
69
- hasRateLimit: 0,
70
- hasRls: 0,
71
- hasOutputValidation: 0
72
- };
73
- for (const analysis of analyses) {
74
- byTier[analysis.tier]++;
75
- for (const [feature, enabled] of Object.entries(analysis.features)) if (enabled) byFeature[feature]++;
76
- }
77
- return {
78
- total: analyses.length,
79
- byTier,
80
- byFeature
81
- };
82
- }
83
- //#endregion
84
- //#region src/build/handler-templates.ts
85
- /**
86
- * Generate validator references for an endpoint
87
- */
88
- function generateValidators(exportName, features) {
89
- const validators = [];
90
- if (features.hasBodyValidation) validators.push(`validateBody(${exportName})`);
91
- if (features.hasQueryValidation) validators.push(`validateQuery(${exportName})`);
92
- if (features.hasParamValidation) validators.push(`validateParams(${exportName})`);
93
- return validators.length > 0 ? `\n ${validators.join(",\n ")},` : "";
94
- }
95
- /**
96
- * Generate a minimal handler (near-raw-Hono performance)
97
- *
98
- * Used for: Health checks, public endpoints with no services
99
- */
100
- function generateMinimalHandler(analysis) {
101
- const { exportName, features } = analysis;
102
- const method = analysis.method.toLowerCase();
103
- const validators = generateValidators(exportName, features);
104
- if (!(validators.length > 0) && !features.hasOutputValidation) return `
105
- // Minimal handler: ${analysis.route} (${analysis.method})
106
- app.${method}('${analysis.route}', async (c) => {
107
- const result = await ${exportName}.handler(
108
- {
109
- services: {},
110
- logger,
111
- body: undefined,
112
- query: undefined,
113
- params: undefined,
114
- session: undefined,
115
- header: Endpoint.createHeaders(c.req.header()),
116
- cookie: Endpoint.createCookies(c.req.header().cookie),
117
- auditor: undefined,
118
- db: undefined,
119
- } as any,
120
- { getMetadata: () => ({}) } as any,
121
- );
122
- return c.json(result, ${exportName}.status as any);
123
- });`;
124
- return `
125
- // Minimal handler with validation: ${analysis.route} (${analysis.method})
126
- app.${method}('${analysis.route}',${validators}
127
- async (c) => {
128
- const result = await ${exportName}.handler(
129
- {
130
- services: {},
131
- logger,
132
- body: ${features.hasBodyValidation ? "(c.req.valid as any)('json')" : "undefined"},
133
- query: ${features.hasQueryValidation ? "(c.req.valid as any)('query')" : "undefined"},
134
- params: ${features.hasParamValidation ? "(c.req.valid as any)('param')" : "undefined"},
135
- session: undefined,
136
- header: Endpoint.createHeaders(c.req.header()),
137
- cookie: Endpoint.createCookies(c.req.header().cookie),
138
- auditor: undefined,
139
- db: undefined,
140
- } as any,
141
- { getMetadata: () => ({}) } as any,
142
- );
143
- ${features.hasOutputValidation ? `const output = await ${exportName}.parseOutput(result);
144
- return c.json(output, ${exportName}.status as any);` : `return c.json(result, ${exportName}.status as any);`}
145
- }
146
- );`;
147
- }
148
- /**
149
- * Generate a standard handler (auth and/or services)
150
- *
151
- * Used for: Authenticated endpoints, endpoints with services
152
- */
153
- function generateStandardHandler(analysis) {
154
- const { exportName, features } = analysis;
155
- const method = analysis.method.toLowerCase();
156
- const validators = generateValidators(exportName, features);
157
- let serviceResolution = "";
158
- if (features.hasServices || features.hasDatabase) serviceResolution = `
159
- const services = await serviceDiscovery.register(${exportName}.services);
160
- ${features.hasDatabase ? `const db = ${exportName}.databaseService
161
- ? (await serviceDiscovery.register([${exportName}.databaseService]) as any)[${exportName}.databaseService.serviceName]
162
- : undefined;` : "const db = undefined;"}`;
163
- else serviceResolution = `
164
- const services = {};
165
- const db = undefined;`;
166
- let authCode = "";
167
- if (features.hasAuth) authCode = `
168
- // Authentication
169
- const session = await ${exportName}.getSession({
170
- services,
171
- logger,
172
- header,
173
- cookie,
174
- ...(db !== undefined && { db }),
175
- } as any);
176
-
177
- const isAuthorized = await ${exportName}.authorize({
178
- header,
179
- cookie,
180
- services,
181
- logger,
182
- session,
183
- } as any);
184
-
185
- if (!isAuthorized) {
186
- return c.json({ error: 'Unauthorized' }, 401);
187
- }`;
188
- let eventCode = "";
189
- if (features.hasEvents) eventCode = `
190
- // Publish events on success
191
- if (Endpoint.isSuccessStatus(${exportName}.status)) {
192
- await (publishConstructEvents as any)(
193
- ${exportName},
194
- result,
195
- serviceDiscovery,
196
- logger,
197
- );
198
- }`;
199
- return `
200
- // Standard handler: ${analysis.route} (${analysis.method})
201
- app.${method}('${analysis.route}',${validators}
202
- async (c) => {
203
- const headerValues = c.req.header();
204
- const header = Endpoint.createHeaders(headerValues);
205
- const cookie = Endpoint.createCookies(headerValues.cookie);
206
- ${serviceResolution}
207
- ${authCode}
208
-
209
- const responseBuilder = new ResponseBuilder();
210
- const result = await ${exportName}.handler(
211
- {
212
- services,
213
- logger,
214
- body: ${features.hasBodyValidation ? "(c.req.valid as any)('json')" : "undefined"},
215
- query: ${features.hasQueryValidation ? "(c.req.valid as any)('query')" : "undefined"},
216
- params: ${features.hasParamValidation ? "(c.req.valid as any)('param')" : "undefined"},
217
- session: ${features.hasAuth ? "session" : "undefined"},
218
- header,
219
- cookie,
220
- auditor: undefined,
221
- db,
222
- } as any,
223
- responseBuilder,
224
- );
225
-
226
- let data = result;
227
- let metadata = responseBuilder.getMetadata();
228
-
229
- if (Endpoint.hasMetadata(result)) {
230
- data = result.data;
231
- metadata = result.metadata;
232
- }
233
-
234
- ${features.hasOutputValidation ? `const output = ${exportName}.outputSchema
235
- ? await ${exportName}.parseOutput(data)
236
- : data;` : "const output = data;"}
237
- ${eventCode}
238
-
239
- const status = (metadata.status ?? ${exportName}.status) as any;
240
- return c.json(output, status);
241
- }
242
- );`;
243
- }
244
- /**
245
- * Generate validators.ts - Shared validator middleware factories
246
- */
247
- function generateValidatorsFile(analyses) {
248
- const needsBody = analyses.some((a) => a.features.hasBodyValidation);
249
- const needsQuery = analyses.some((a) => a.features.hasQueryValidation);
250
- const needsParams = analyses.some((a) => a.features.hasParamValidation);
251
- if (!needsBody && !needsQuery && !needsParams) return `// No validators needed for this build\nexport {};\n`;
252
- const exports = [];
253
- const factories = [];
254
- if (needsBody) {
255
- exports.push("validateBody");
256
- factories.push(`
257
- export const validateBody = (endpoint: any) =>
258
- validator('json', async (value, c) => {
259
- if (!endpoint.input?.body) return undefined;
260
- const parsed = await Endpoint.validate(endpoint.input.body, value);
261
- if (parsed.issues) return c.json(parsed.issues, 422);
262
- return parsed.value;
263
- });`);
264
- }
265
- if (needsQuery) {
266
- exports.push("validateQuery");
267
- factories.push(`
268
- export const validateQuery = (endpoint: any) =>
269
- validator('query', async (_, c) => {
270
- if (!endpoint.input?.query) return undefined;
271
- const rawQuery = Object.fromEntries(new URL(c.req.url).searchParams);
272
- const parsed = await Endpoint.validate(endpoint.input.query, rawQuery);
273
- if (parsed.issues) return c.json(parsed.issues, 422);
274
- return parsed.value;
275
- });`);
276
- }
277
- if (needsParams) {
278
- exports.push("validateParams");
279
- factories.push(`
280
- export const validateParams = (endpoint: any) =>
281
- validator('param', async (params, c) => {
282
- if (!endpoint.input?.params) return undefined;
283
- const parsed = await Endpoint.validate(endpoint.input.params, params);
284
- if (parsed.issues) return c.json(parsed.issues, 422);
285
- return parsed.value;
286
- });`);
287
- }
288
- return `/**
289
- * Generated validator middleware factories
290
- * Shared across all endpoint tiers that need validation
291
- */
292
- import { validator } from 'hono/validator';
293
- import { Endpoint } from '@geekmidas/constructs/endpoints';
294
- ${factories.join("\n")}
295
- `;
296
- }
297
- /**
298
- * Generate a standalone minimal endpoint file
299
- */
300
- function generateMinimalEndpointFile(analysis, endpointImport) {
301
- const { exportName, features } = analysis;
302
- const validatorImport = features.hasBodyValidation || features.hasQueryValidation || features.hasParamValidation ? generateValidatorImportsForEndpoint(analysis) : "";
303
- const handler = generateMinimalHandler(analysis);
304
- return `/**
305
- * Minimal endpoint: ${analysis.route} (${analysis.method})
306
- * Near-raw-Hono performance
307
- */
308
- import type { Hono } from 'hono';
309
- import type { Logger } from '@geekmidas/logger';
310
- import { Endpoint } from '@geekmidas/constructs/endpoints';
311
- ${validatorImport}
312
- import { ${exportName} } from '${endpointImport.importPath}';
313
-
314
- export function setup${capitalize(exportName)}(
315
- app: Hono,
316
- logger: Logger,
317
- ): void {
318
- ${handler}
319
- }
320
- `;
321
- }
322
- /**
323
- * Generate a standalone standard endpoint file
324
- */
325
- function generateStandardEndpointFile(analysis, endpointImport) {
326
- const { exportName, features } = analysis;
327
- const validatorImport = features.hasBodyValidation || features.hasQueryValidation || features.hasParamValidation ? generateValidatorImportsForEndpoint(analysis) : "";
328
- const eventsImport = features.hasEvents ? `import { publishConstructEvents } from '@geekmidas/constructs/endpoints';` : "";
329
- const handler = generateStandardHandler(analysis);
330
- return `/**
331
- * Standard endpoint: ${analysis.route} (${analysis.method})
332
- * Auth and/or services enabled
333
- */
334
- import type { Hono } from 'hono';
335
- import type { Logger } from '@geekmidas/logger';
336
- import type { ServiceDiscovery } from '@geekmidas/services';
337
- import { Endpoint, ResponseBuilder } from '@geekmidas/constructs/endpoints';
338
- ${eventsImport}
339
- ${validatorImport}
340
- import { ${exportName} } from '${endpointImport.importPath}';
341
-
342
- export function setup${capitalize(exportName)}(
343
- app: Hono,
344
- serviceDiscovery: ServiceDiscovery<any, any>,
345
- logger: Logger,
346
- ): void {
347
- ${handler}
348
- }
349
- `;
350
- }
351
- /**
352
- * Generate a standalone full endpoint file
353
- */
354
- function generateFullEndpointFile(analysis, endpointImport) {
355
- const { exportName } = analysis;
356
- return `/**
357
- * Full endpoint: ${analysis.route} (${analysis.method})
358
- * Complex features: audits, RLS, rate limiting
359
- */
360
- import type { Hono } from 'hono';
361
- import type { ServiceDiscovery } from '@geekmidas/services';
362
- import { HonoEndpoint } from '@geekmidas/constructs/hono';
363
- import { ${exportName} } from '${endpointImport.importPath}';
364
-
365
- export function setup${capitalize(exportName)}(
366
- app: Hono,
367
- serviceDiscovery: ServiceDiscovery<any, any>,
368
- openApiOptions: any,
369
- ): void {
370
- HonoEndpoint.addRoutes([${exportName}] as any, serviceDiscovery, app, openApiOptions);
371
- }
372
- `;
373
- }
374
- /**
375
- * Generate tier index file that imports and calls all endpoint setup functions
376
- */
377
- function generateTierIndexFile(tier, analyses) {
378
- const tierEndpoints = analyses.filter((a) => a.tier === tier);
379
- if (tierEndpoints.length === 0) {
380
- if (tier === "minimal") return `// No minimal-tier endpoints in this build
381
- import type { Hono } from 'hono';
382
- import type { Logger } from '@geekmidas/logger';
383
-
384
- export function setupMinimalEndpoints(
385
- _app: Hono,
386
- _logger: Logger,
387
- ): void {
388
- // No minimal endpoints
389
- }
390
- `;
391
- if (tier === "standard") return `// No standard-tier endpoints in this build
392
- import type { Hono } from 'hono';
393
- import type { Logger } from '@geekmidas/logger';
394
- import type { ServiceDiscovery } from '@geekmidas/services';
395
-
396
- export function setupStandardEndpoints(
397
- _app: Hono,
398
- _serviceDiscovery: ServiceDiscovery<any, any>,
399
- _logger: Logger,
400
- ): void {
401
- // No standard endpoints
402
- }
403
- `;
404
- return `// No full-tier endpoints in this build
405
- import type { Hono } from 'hono';
406
- import type { ServiceDiscovery } from '@geekmidas/services';
407
-
408
- export function setupFullEndpoints(
409
- _app: Hono,
410
- _serviceDiscovery: ServiceDiscovery<any, any>,
411
- _enableOpenApi: boolean,
412
- ): void {
413
- // No full endpoints
414
- }
415
- `;
416
- }
417
- const imports = tierEndpoints.map((a) => `import { setup${capitalize(a.exportName)} } from './${a.exportName}.js';`).join("\n");
418
- if (tier === "minimal") {
419
- const calls = tierEndpoints.map((a) => ` setup${capitalize(a.exportName)}(app, logger);`).join("\n");
420
- return `/**
421
- * Minimal-tier endpoint index (${tierEndpoints.length} endpoints)
422
- * Near-raw-Hono performance
423
- */
424
- import type { Hono } from 'hono';
425
- import type { Logger } from '@geekmidas/logger';
426
- ${imports}
427
-
428
- export function setupMinimalEndpoints(
429
- app: Hono,
430
- logger: Logger,
431
- ): void {
432
- ${calls}
433
- }
434
- `;
435
- }
436
- if (tier === "standard") {
437
- const calls = tierEndpoints.map((a) => ` setup${capitalize(a.exportName)}(app, serviceDiscovery, logger);`).join("\n");
438
- return `/**
439
- * Standard-tier endpoint index (${tierEndpoints.length} endpoints)
440
- * Auth and/or services enabled
441
- */
442
- import type { Hono } from 'hono';
443
- import type { Logger } from '@geekmidas/logger';
444
- import type { ServiceDiscovery } from '@geekmidas/services';
445
- ${imports}
446
-
447
- export function setupStandardEndpoints(
448
- app: Hono,
449
- serviceDiscovery: ServiceDiscovery<any, any>,
450
- logger: Logger,
451
- ): void {
452
- ${calls}
453
- }
454
- `;
455
- }
456
- const calls = tierEndpoints.map((a) => ` setup${capitalize(a.exportName)}(app, serviceDiscovery, openApiOptions);`).join("\n");
457
- return `/**
458
- * Full-tier endpoint index (${tierEndpoints.length} endpoints)
459
- * Complex features: audits, RLS, rate limiting
460
- */
461
- import type { Hono } from 'hono';
462
- import type { ServiceDiscovery } from '@geekmidas/services';
463
- ${imports}
464
-
465
- export function setupFullEndpoints(
466
- app: Hono,
467
- serviceDiscovery: ServiceDiscovery<any, any>,
468
- enableOpenApi: boolean,
469
- ): void {
470
- const openApiOptions: any = enableOpenApi ? {
471
- docsPath: '/__docs',
472
- openApiOptions: {
473
- title: 'API Documentation',
474
- version: '1.0.0',
475
- description: 'Generated API documentation'
476
- }
477
- } : { docsPath: false };
478
-
479
- ${calls}
480
- }
481
- `;
482
- }
483
- /**
484
- * Generate validator imports for a single endpoint
485
- */
486
- function generateValidatorImportsForEndpoint(analysis) {
487
- const imports = [];
488
- if (analysis.features.hasBodyValidation) imports.push("validateBody");
489
- if (analysis.features.hasQueryValidation) imports.push("validateQuery");
490
- if (analysis.features.hasParamValidation) imports.push("validateParams");
491
- if (imports.length === 0) return "";
492
- return `import { ${imports.join(", ")} } from '../validators.js';`;
493
- }
494
- /**
495
- * Capitalize first letter
496
- */
497
- function capitalize(str) {
498
- return str.charAt(0).toUpperCase() + str.slice(1);
499
- }
500
- /**
501
- * Generate all endpoint files with nested folder structure (per-endpoint files)
502
- */
503
- function generateEndpointFilesNested(analyses, endpointImports) {
504
- const files = {
505
- "validators.ts": generateValidatorsFile(analyses),
506
- "minimal/index.ts": generateTierIndexFile("minimal", analyses),
507
- "standard/index.ts": generateTierIndexFile("standard", analyses),
508
- "full/index.ts": generateTierIndexFile("full", analyses),
509
- "index.ts": generateNestedIndexFile(analyses)
510
- };
511
- for (const analysis of analyses) {
512
- const endpointImport = endpointImports.find((i) => i.exportName === analysis.exportName);
513
- if (!endpointImport) continue;
514
- const fileName = `${analysis.tier}/${analysis.exportName}.ts`;
515
- switch (analysis.tier) {
516
- case "minimal":
517
- files[fileName] = generateMinimalEndpointFile(analysis, endpointImport);
518
- break;
519
- case "standard":
520
- files[fileName] = generateStandardEndpointFile(analysis, endpointImport);
521
- break;
522
- case "full": files[fileName] = generateFullEndpointFile(analysis, endpointImport);
523
- }
524
- }
525
- return files;
526
- }
527
- /**
528
- * Generate index.ts for nested structure
529
- */
530
- function generateNestedIndexFile(analyses) {
531
- const minimalCount = analyses.filter((a) => a.tier === "minimal").length;
532
- const standardCount = analyses.filter((a) => a.tier === "standard").length;
533
- const fullCount = analyses.filter((a) => a.tier === "full").length;
534
- return `/**
535
- * Generated optimized endpoints
536
- *
537
- * Build-time optimization tiers:
538
- * - minimal: ${minimalCount} endpoints (near-raw-Hono)
539
- * - standard: ${standardCount} endpoints (auth/services)
540
- * - full: ${fullCount} endpoints (audits/rls/rate-limit)
541
- */
542
- import type { EnvironmentParser } from '@geekmidas/envkit';
543
- import type { Logger } from '@geekmidas/logger';
544
- import type { Hono } from 'hono';
545
- import { ServiceDiscovery } from '@geekmidas/services';
546
- import { setupMinimalEndpoints } from './minimal/index.js';
547
- import { setupStandardEndpoints } from './standard/index.js';
548
- import { setupFullEndpoints } from './full/index.js';
549
-
550
- export async function setupEndpoints(
551
- app: Hono,
552
- envParser: EnvironmentParser<any>,
553
- logger: Logger,
554
- enableOpenApi: boolean = false,
555
- ): Promise<void> {
556
- const serviceDiscovery = ServiceDiscovery.getInstance(envParser);
557
-
558
- // Minimal handlers (${minimalCount} endpoints) - near-raw-Hono performance
559
- setupMinimalEndpoints(app, logger);
560
-
561
- // Standard handlers (${standardCount} endpoints) - auth/services
562
- setupStandardEndpoints(app, serviceDiscovery, logger);
563
-
564
- // Full handlers (${fullCount} endpoints) - audits/rls/rate-limit
565
- setupFullEndpoints(app, serviceDiscovery, enableOpenApi);
566
-
567
- // Add Swagger UI if OpenAPI is enabled
568
- if (enableOpenApi) {
569
- try {
570
- const { swaggerUI } = await import('@hono/swagger-ui');
571
- app.get('/__docs/ui', swaggerUI({ url: '/__docs' }));
572
- } catch {
573
- // @hono/swagger-ui not installed, skip Swagger UI
574
- }
575
- }
576
- }
577
- `;
578
- }
579
- //#endregion
580
7
  //#region src/generators/telemetry.ts
581
8
  /**
582
9
  * Every package `@geekmidas/telescope/instrumentation` loads at runtime.
@@ -641,6 +68,13 @@ const HEADER = `/**
641
68
  * configure the rest.
642
69
  */
643
70
 
71
+ import type { MiddlewareHandler } from 'hono';
72
+
73
+ /** Requests whose spans would only be noise: health checks, by default. */
74
+ export interface StartTelemetryOptions {
75
+ ignorePaths?: string[];
76
+ }
77
+
644
78
  /** Telemetry was asked for and cannot start. The server runs without it. */
645
79
  export class TelemetryUnavailable extends Error {
646
80
  constructor(readonly reason: string, options?: { cause?: unknown }) {
@@ -654,7 +88,9 @@ export class TelemetryUnavailable extends Error {
654
88
  `;
655
89
  /**
656
90
  * The entry's `telemetry.ts`: a `startTelemetry()` the server awaits before it
657
- * imports the app, so the libraries the app loads are instrumented.
91
+ * imports the app, so the libraries the app loads are instrumented. It returns
92
+ * the Hono middleware that traces each request, or undefined when telemetry is
93
+ * off — the server mounts it ahead of every route.
658
94
  *
659
95
  * Failing to start telemetry warns (a named `TelemetryUnavailable`, through
660
96
  * `process.emitWarning`) and never stops the server: an outage in observability
@@ -662,25 +98,32 @@ export class TelemetryUnavailable extends Error {
662
98
  */
663
99
  function generateTelemetryModule(telemetry) {
664
100
  if (!telemetry?.available) return `${HEADER}
665
- export async function startTelemetry(): Promise<void> {
666
- if (!process.env.OTEL_EXPORTER_OTLP_ENDPOINT) return;
101
+ export async function startTelemetry(
102
+ _options: StartTelemetryOptions = {},
103
+ ): Promise<MiddlewareHandler | undefined> {
104
+ if (!process.env.OTEL_EXPORTER_OTLP_ENDPOINT) return undefined;
667
105
 
668
106
  process.emitWarning(
669
107
  new TelemetryUnavailable(
670
108
  'this server was built without @geekmidas/telescope and the @opentelemetry packages it needs. Add them to the app and rebuild.',
671
109
  ),
672
110
  );
111
+ return undefined;
673
112
  }
674
113
  `;
675
114
  const options = [
676
115
  `serviceName: ${JSON.stringify(telemetry.serviceName)},`,
677
116
  ...telemetry.serviceNamespace ? [`serviceNamespace: ${JSON.stringify(telemetry.serviceNamespace)},`] : [],
678
117
  "deploymentEnvironment: process.env.STAGE,",
679
- "handleSignals: false,"
118
+ "handleSignals: false,",
119
+ "instrumentPino: false,",
120
+ "incomingHttpSpans: false,"
680
121
  ];
681
122
  return `${HEADER}
682
- export async function startTelemetry(): Promise<void> {
683
- if (!process.env.OTEL_EXPORTER_OTLP_ENDPOINT) return;
123
+ export async function startTelemetry(
124
+ options: StartTelemetryOptions = {},
125
+ ): Promise<MiddlewareHandler | undefined> {
126
+ if (!process.env.OTEL_EXPORTER_OTLP_ENDPOINT) return undefined;
684
127
 
685
128
  let instrumentation;
686
129
  try {
@@ -692,7 +135,7 @@ export async function startTelemetry(): Promise<void> {
692
135
  { cause },
693
136
  ),
694
137
  );
695
- return;
138
+ return undefined;
696
139
  }
697
140
 
698
141
  instrumentation.setupTelemetry({
@@ -709,6 +152,13 @@ export async function startTelemetry(): Promise<void> {
709
152
  });
710
153
  });
711
154
  }
155
+
156
+ // A SERVER span per request, opened by the app itself rather than by
157
+ // hooking node:http: \`GET /users/:id\`, continuing an incoming traceparent,
158
+ // with the handler — its logs, fetches and queries — running inside it.
159
+ return instrumentation.honoTelemetryMiddleware({
160
+ ignorePaths: options.ignorePaths,
161
+ });
712
162
  }
713
163
  `;
714
164
  }
@@ -811,7 +261,7 @@ var EndpointGenerator = class extends ConstructGenerator {
811
261
  const routes = [];
812
262
  if (constructs.length === 0) return routes;
813
263
  if (target === "server") {
814
- await this.generateEndpointsFile(outputDir, constructs, context);
264
+ await this.generateEndpointsFile(outputDir, constructs);
815
265
  const appFile = await this.generateAppFile(outputDir, context);
816
266
  routes.push({
817
267
  path: "*",
@@ -847,7 +297,7 @@ var EndpointGenerator = class extends ConstructGenerator {
847
297
  await writeFile(handlerPath, this.generateAWSApiGatewayV2Handler(importPath, exportName, context.storageDrivers));
848
298
  return handlerPath;
849
299
  }
850
- async generateEndpointsFile(outputDir, endpoints, context) {
300
+ async generateEndpointsFile(outputDir, endpoints) {
851
301
  const endpointsPath = join(outputDir, "endpoints.ts");
852
302
  const importsByFile = /* @__PURE__ */ new Map();
853
303
  for (const { path, key } of endpoints) {
@@ -855,19 +305,16 @@ var EndpointGenerator = class extends ConstructGenerator {
855
305
  if (!importsByFile.has(importPath)) importsByFile.set(importPath, []);
856
306
  importsByFile.get(importPath)?.push(key);
857
307
  }
858
- const endpointImports = Array.from(importsByFile.entries()).map(([importPath, exports]) => `import { ${exports.join(", ")} } from '${importPath}';`).join("\n");
859
- const allExportNames = endpoints.map(({ key }) => key);
860
- if (context.production?.enabled && context.production.optimizedHandlers) return this.generateOptimizedEndpointsFile(endpointsPath, endpoints, endpointImports, allExportNames);
861
308
  const content = `import type { EnvironmentParser } from '@geekmidas/envkit';
862
309
  import type { Logger } from '@geekmidas/logger';
863
310
  import { HonoEndpoint } from '@geekmidas/constructs/hono';
864
311
  import { Endpoint } from '@geekmidas/constructs/endpoints';
865
312
  import { ServiceDiscovery } from '@geekmidas/services';
866
313
  import type { Hono } from 'hono';
867
- ${endpointImports}
314
+ ${Array.from(importsByFile.entries()).map(([importPath, exports]) => `import { ${exports.join(", ")} } from '${importPath}';`).join("\n")}
868
315
 
869
316
  export const endpoints: Endpoint<any, any, any, any, any, any, any, any, any, any, any, any>[] = [
870
- ${allExportNames.join(",\n ")}
317
+ ${endpoints.map(({ key }) => key).join(",\n ")}
871
318
  ];
872
319
 
873
320
  export async function setupEndpoints(
@@ -904,41 +351,6 @@ export async function setupEndpoints(
904
351
  await writeFile(endpointsPath, content);
905
352
  return endpointsPath;
906
353
  }
907
- /**
908
- * Generate optimized endpoints files with nested folder structure (per-endpoint files)
909
- */
910
- async generateOptimizedEndpointsFile(endpointsPath, endpoints, _endpointImports, _allExportNames) {
911
- const logger = console;
912
- const outputDir = dirname(endpointsPath);
913
- const endpointsDir = join(outputDir, "endpoints");
914
- await mkdir(join(endpointsDir, "minimal"), { recursive: true });
915
- await mkdir(join(endpointsDir, "standard"), { recursive: true });
916
- await mkdir(join(endpointsDir, "full"), { recursive: true });
917
- const analyses = endpoints.map(({ key, construct }) => analyzeEndpoint(construct, key));
918
- const endpointImports = endpoints.map(({ key, path }) => {
919
- const tierDir = join(endpointsDir, "standard");
920
- return {
921
- exportName: key,
922
- importPath: relative(tierDir, path.relative).replace(/\.ts$/, ".js")
923
- };
924
- });
925
- const summary = summarizeAnalysis(analyses);
926
- logger.log(`\n📊 Endpoint Analysis:`);
927
- logger.log(` Total: ${summary.total} endpoints`);
928
- logger.log(` - Minimal (near-raw-Hono): ${summary.byTier.minimal} endpoints`);
929
- logger.log(` - Standard (auth/services): ${summary.byTier.standard} endpoints`);
930
- logger.log(` - Full (audits/rls/rate-limit): ${summary.byTier.full} endpoints`);
931
- const files = generateEndpointFilesNested(analyses, endpointImports);
932
- for (const [filename, content] of Object.entries(files)) {
933
- const filePath = join(endpointsDir, filename);
934
- await mkdir(dirname(filePath), { recursive: true });
935
- await writeFile(filePath, content);
936
- }
937
- const endpointFiles = Object.keys(files).filter((f) => !f.endsWith("index.ts") && !f.endsWith("validators.ts")).length;
938
- const indexFiles = Object.keys(files).filter((f) => f.endsWith("index.ts")).length;
939
- logger.log(` Generated ${endpointFiles} endpoint files + ${indexFiles} index files + validators.ts`);
940
- return join(endpointsDir, "index.ts");
941
- }
942
354
  async generateAppFile(outputDir, context) {
943
355
  if (context.production?.enabled) return this.generateProductionAppFile(outputDir, context);
944
356
  const appPath = join(outputDir, "app.ts");
@@ -1009,7 +421,7 @@ import { ${databaseApi.database.exportName} as __introspectedDb } from '${import
1009
421
  (honoApp as any).__injectWebSocket = injectWebSocket;
1010
422
  logger.info('Telescope WebSocket enabled');
1011
423
  } catch (e) {
1012
- logger.warn({ error: e }, 'WebSocket support not available - install @hono/node-ws for real-time updates');
424
+ logger.warn({ err: e }, 'WebSocket support not available - install @hono/node-ws for real-time updates');
1013
425
  }
1014
426
  ` : "";
1015
427
  let telescopeSetup = "";
@@ -1158,19 +570,19 @@ ${afterSetupCall}
1158
570
  // Mount pushed subscribers' routes and start polled ones. What comes
1159
571
  // back subscribes the routes, once the server can answer them.
1160
572
  const subscribeForPush = await setupSubscribers(honoApp, envParser, logger).catch((error) => {
1161
- logger.error({ error }, 'Failed to start subscribers');
573
+ logger.error({ err: error }, 'Failed to start subscribers');
1162
574
  return async (_port: number) => {};
1163
575
  });
1164
576
 
1165
577
  // Start queue workers in background (non-blocking, local development only)
1166
578
  await setupQueues(envParser, logger).catch((error) => {
1167
- logger.error({ error }, 'Failed to start queue workers');
579
+ logger.error({ err: error }, 'Failed to start queue workers');
1168
580
  });
1169
581
 
1170
582
  // Schedule this app's crons. Caught like the others: a scheduler that
1171
583
  // cannot start is not a reason for the HTTP server not to.
1172
584
  await setupCrons(envParser, logger).catch((error) => {
1173
- logger.error({ error }, 'Failed to schedule crons');
585
+ logger.error({ err: error }, 'Failed to schedule crons');
1174
586
  });
1175
587
 
1176
588
  logger.info({ port }, 'Starting server');
@@ -1246,19 +658,19 @@ export const handler = adapter.handler;
1246
658
  // Mount pushed subscribers' routes and start polled ones. What comes
1247
659
  // back subscribes the routes, once the server can answer them.
1248
660
  const subscribeForPush = await setupSubscribers(honoApp, envParser, logger).catch((error) => {
1249
- logger.error({ error }, 'Failed to start subscribers');
661
+ logger.error({ err: error }, 'Failed to start subscribers');
1250
662
  return async (_port: number) => {};
1251
663
  });
1252
664
 
1253
665
  // Start queue workers in background
1254
666
  await setupQueues(envParser, logger).catch((error) => {
1255
- logger.error({ error }, 'Failed to start queue workers');
667
+ logger.error({ err: error }, 'Failed to start queue workers');
1256
668
  });
1257
669
 
1258
670
  // Schedule this app's crons. Caught like the others: a scheduler that
1259
671
  // cannot start is not a reason for the HTTP server not to.
1260
672
  await setupCrons(envParser, logger).catch((error) => {
1261
- logger.error({ error }, 'Failed to schedule crons');
673
+ logger.error({ err: error }, 'Failed to schedule crons');
1262
674
  });
1263
675
  ` : "";
1264
676
  const subscriberImport = includeSubscribers ? `import { setupSubscribers } from './subscribers.js';
@@ -1286,14 +698,13 @@ import { setupCrons } from './crons.js';` : "";
1286
698
  if (typeof close === 'function') close.call(server, () => resolve());
1287
699
  else resolve();
1288
700
  });
1289
- await runShutdownHooks((error) => logger.error({ error }, 'Shutdown hook failed'));
701
+ await runShutdownHooks((error) => logger.error({ err: error }, 'Shutdown hook failed'));
1290
702
  process.exit(0);
1291
703
  };
1292
704
 
1293
705
  process.on('SIGTERM', shutdown);
1294
706
  process.on('SIGINT', shutdown);
1295
707
  ` : "";
1296
- const endpointsImportPath = production.optimizedHandlers ? "./endpoints/index.js" : "./endpoints.js";
1297
708
  const content = `/**
1298
709
  * Generated production server application
1299
710
  *
@@ -1305,7 +716,7 @@ import { setupCrons } from './crons.js';` : "";
1305
716
  */
1306
717
  import { Hono } from 'hono';
1307
718
  import type { Hono as HonoType } from 'hono';
1308
- ${enableGracefulShutdown ? "import { runShutdownHooks } from '@geekmidas/constructs';\n" : ""}import { setupEndpoints } from '${endpointsImportPath}';
719
+ ${enableGracefulShutdown ? "import { runShutdownHooks } from '@geekmidas/constructs';\n" : ""}import { setupEndpoints } from './endpoints.js';
1309
720
  ${subscriberImport}
1310
721
  ${runtime.imports}
1311
722
  ${runtime.bindings}
@@ -1362,7 +773,7 @@ export async function createApp(app?: HonoType): Promise<ServerApp> {
1362
773
  http.statusCode as 500,
1363
774
  );
1364
775
  }
1365
- logger.error({ error }, 'Unhandled error');
776
+ logger.error({ err: error }, 'Unhandled error');
1366
777
  return c.json({ message: 'Internal Server Error' }, 500);
1367
778
  });
1368
779
  ${cors.setup}${beforeSetupCall}
@@ -1407,28 +818,36 @@ export default createApp;
1407
818
  async generateProductionServerEntry(outputDir, context) {
1408
819
  const serverPath = join(outputDir, "server.ts");
1409
820
  await writeFile(join(outputDir, "telemetry.ts"), generateTelemetryModule(context.telemetry));
1410
- await writeFile(serverPath, `#!/usr/bin/env node
821
+ const content = `#!/usr/bin/env node
1411
822
  /**
1412
823
  * Production server entry point
1413
824
  * Generated by 'gkm build --production'
1414
825
  */
1415
826
  import { serve } from '@hono/node-server';
827
+ import { Hono } from 'hono';
1416
828
  import { startTelemetry } from './telemetry.js';
1417
829
 
1418
830
  // Before the app is imported, so the libraries it loads are instrumented.
1419
- await startTelemetry();
831
+ const requestSpans = await startTelemetry({
832
+ ignorePaths: [${JSON.stringify(context.production?.healthCheck ?? "/health")}, '/ready'],
833
+ });
1420
834
 
1421
835
  const { createApp } = await import('./app.js');
1422
836
 
1423
837
  const port = Number(process.env.PORT) || 3000;
1424
838
 
1425
- const { start } = await createApp();
839
+ // The span middleware goes on before any route, so every request runs in it.
840
+ const app = new Hono();
841
+ if (requestSpans) app.use('*', requestSpans);
842
+
843
+ const { start } = await createApp(app);
1426
844
 
1427
845
  await start({
1428
846
  port,
1429
847
  serve: (app, port) => serve({ fetch: app.fetch, port }),
1430
848
  });
1431
- `);
849
+ `;
850
+ await writeFile(serverPath, content);
1432
851
  }
1433
852
  };
1434
853
  //#endregion
@@ -1939,4 +1358,4 @@ function unknownType(name) {
1939
1358
  //#endregion
1940
1359
  export { telemetryFor as i, EndpointGenerator as n, runtimeFor as r, OpenApiTsGenerator as t };
1941
1360
 
1942
- //# sourceMappingURL=OpenApiTsGenerator-CSaXs-dB.mjs.map
1361
+ //# sourceMappingURL=OpenApiTsGenerator-Bhr_XWWN.mjs.map