@geekmidas/cli 0.2.4 → 0.4.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 (82) hide show
  1. package/README.md +488 -71
  2. package/dist/{EndpointGenerator-C73wNoih.cjs → EndpointGenerator-BxNCkus4.cjs} +60 -6
  3. package/dist/EndpointGenerator-BxNCkus4.cjs.map +1 -0
  4. package/dist/{EndpointGenerator-CWh18d92.mjs → EndpointGenerator-CzDhG7Or.mjs} +60 -6
  5. package/dist/EndpointGenerator-CzDhG7Or.mjs.map +1 -0
  6. package/dist/OpenApiTsGenerator-NBNEoaeO.cjs +501 -0
  7. package/dist/OpenApiTsGenerator-NBNEoaeO.cjs.map +1 -0
  8. package/dist/OpenApiTsGenerator-q3aWNkuM.mjs +495 -0
  9. package/dist/OpenApiTsGenerator-q3aWNkuM.mjs.map +1 -0
  10. package/dist/build/index.cjs +4 -4
  11. package/dist/build/index.mjs +4 -4
  12. package/dist/build/manifests.cjs +3 -2
  13. package/dist/build/manifests.mjs +2 -2
  14. package/dist/{build-BVng9MQX.cjs → build-CWtHnJMQ.cjs} +19 -17
  15. package/dist/build-CWtHnJMQ.cjs.map +1 -0
  16. package/dist/{build-BqexeI-W.mjs → build-DyDgu_D1.mjs} +20 -18
  17. package/dist/build-DyDgu_D1.mjs.map +1 -0
  18. package/dist/{config-U-mdW-7Y.mjs → config-AFmFKmU0.mjs} +3 -3
  19. package/dist/config-AFmFKmU0.mjs.map +1 -0
  20. package/dist/{config-D1EpSGk6.cjs → config-BVIJpAsa.cjs} +3 -3
  21. package/dist/config-BVIJpAsa.cjs.map +1 -0
  22. package/dist/config.cjs +1 -1
  23. package/dist/config.mjs +1 -1
  24. package/dist/dev/index.cjs +5 -4
  25. package/dist/dev/index.mjs +4 -4
  26. package/dist/{dev-DbtyToc7.cjs → dev-CgDYC4o8.cjs} +95 -31
  27. package/dist/dev-CgDYC4o8.cjs.map +1 -0
  28. package/dist/{dev-DnGYXuMn.mjs → dev-CpA8AQPX.mjs} +90 -32
  29. package/dist/dev-CpA8AQPX.mjs.map +1 -0
  30. package/dist/generators/EndpointGenerator.cjs +1 -1
  31. package/dist/generators/EndpointGenerator.mjs +1 -1
  32. package/dist/generators/OpenApiTsGenerator.cjs +3 -0
  33. package/dist/generators/OpenApiTsGenerator.mjs +3 -0
  34. package/dist/generators/index.cjs +1 -1
  35. package/dist/generators/index.mjs +1 -1
  36. package/dist/index.cjs +16 -10
  37. package/dist/index.cjs.map +1 -1
  38. package/dist/index.mjs +16 -10
  39. package/dist/index.mjs.map +1 -1
  40. package/dist/manifests-C2eMoMUm.mjs +68 -0
  41. package/dist/manifests-C2eMoMUm.mjs.map +1 -0
  42. package/dist/manifests-CK1VV_pM.cjs +80 -0
  43. package/dist/manifests-CK1VV_pM.cjs.map +1 -0
  44. package/dist/openapi-DRTRGhTt.mjs +50 -0
  45. package/dist/openapi-DRTRGhTt.mjs.map +1 -0
  46. package/dist/openapi-DhK4b0lB.cjs +56 -0
  47. package/dist/openapi-DhK4b0lB.cjs.map +1 -0
  48. package/dist/openapi.cjs +4 -3
  49. package/dist/openapi.mjs +4 -3
  50. package/docs/OPENAPI_TYPESCRIPT_DESIGN.md +408 -0
  51. package/docs/manifest-refactor-design.md +287 -0
  52. package/package.json +10 -3
  53. package/src/__tests__/openapi.spec.ts +78 -63
  54. package/src/build/__tests__/index-new.spec.ts +43 -72
  55. package/src/build/__tests__/manifests.spec.ts +346 -0
  56. package/src/build/index.ts +59 -62
  57. package/src/build/manifests.ts +85 -13
  58. package/src/build/types.ts +13 -2
  59. package/src/config.ts +4 -2
  60. package/src/dev/__tests__/index.spec.ts +98 -1
  61. package/src/dev/index.ts +152 -25
  62. package/src/generators/EndpointGenerator.ts +69 -5
  63. package/src/generators/OpenApiTsGenerator.ts +798 -0
  64. package/src/index.ts +6 -3
  65. package/src/openapi.ts +36 -15
  66. package/src/types.ts +23 -7
  67. package/dist/EndpointGenerator-C73wNoih.cjs.map +0 -1
  68. package/dist/EndpointGenerator-CWh18d92.mjs.map +0 -1
  69. package/dist/build-BVng9MQX.cjs.map +0 -1
  70. package/dist/build-BqexeI-W.mjs.map +0 -1
  71. package/dist/config-D1EpSGk6.cjs.map +0 -1
  72. package/dist/config-U-mdW-7Y.mjs.map +0 -1
  73. package/dist/dev-DbtyToc7.cjs.map +0 -1
  74. package/dist/dev-DnGYXuMn.mjs.map +0 -1
  75. package/dist/manifests-BrJXpHrf.mjs +0 -21
  76. package/dist/manifests-BrJXpHrf.mjs.map +0 -1
  77. package/dist/manifests-D0saShvH.cjs +0 -27
  78. package/dist/manifests-D0saShvH.cjs.map +0 -1
  79. package/dist/openapi-BTHbPrxS.mjs +0 -36
  80. package/dist/openapi-BTHbPrxS.mjs.map +0 -1
  81. package/dist/openapi-CewcfoRH.cjs +0 -42
  82. package/dist/openapi-CewcfoRH.cjs.map +0 -1
@@ -1,6 +1,10 @@
1
1
  import { createServer } from 'node:net';
2
2
  import { describe, expect, it } from 'vitest';
3
- import { findAvailablePort, isPortAvailable } from '../index';
3
+ import {
4
+ findAvailablePort,
5
+ isPortAvailable,
6
+ normalizeTelescopeConfig,
7
+ } from '../index';
4
8
 
5
9
  /**
6
10
  * Helper to occupy a port for testing
@@ -206,3 +210,96 @@ describe('devCommand edge cases', () => {
206
210
  });
207
211
  });
208
212
  });
213
+
214
+ describe('normalizeTelescopeConfig', () => {
215
+ it('should return undefined when config is false', () => {
216
+ const result = normalizeTelescopeConfig(false);
217
+ expect(result).toBeUndefined();
218
+ });
219
+
220
+ it('should return default config when config is true', () => {
221
+ const result = normalizeTelescopeConfig(true);
222
+ expect(result).toEqual({
223
+ enabled: true,
224
+ path: '/__telescope',
225
+ ignore: [],
226
+ recordBody: true,
227
+ maxEntries: 1000,
228
+ websocket: true,
229
+ });
230
+ });
231
+
232
+ it('should return default config when config is undefined', () => {
233
+ const result = normalizeTelescopeConfig(undefined);
234
+ expect(result).toEqual({
235
+ enabled: true,
236
+ path: '/__telescope',
237
+ ignore: [],
238
+ recordBody: true,
239
+ maxEntries: 1000,
240
+ websocket: true,
241
+ });
242
+ });
243
+
244
+ it('should return undefined when config.enabled is false', () => {
245
+ const result = normalizeTelescopeConfig({ enabled: false });
246
+ expect(result).toBeUndefined();
247
+ });
248
+
249
+ it('should merge custom config with defaults', () => {
250
+ const result = normalizeTelescopeConfig({
251
+ path: '/__debug',
252
+ ignore: ['/health', '/metrics'],
253
+ recordBody: false,
254
+ maxEntries: 500,
255
+ });
256
+ expect(result).toEqual({
257
+ enabled: true,
258
+ path: '/__debug',
259
+ ignore: ['/health', '/metrics'],
260
+ recordBody: false,
261
+ maxEntries: 500,
262
+ websocket: true,
263
+ });
264
+ });
265
+
266
+ it('should use defaults for missing config values', () => {
267
+ const result = normalizeTelescopeConfig({
268
+ path: '/__custom',
269
+ });
270
+ expect(result).toEqual({
271
+ enabled: true,
272
+ path: '/__custom',
273
+ ignore: [],
274
+ recordBody: true,
275
+ maxEntries: 1000,
276
+ websocket: true,
277
+ });
278
+ });
279
+
280
+ it('should handle empty object config', () => {
281
+ const result = normalizeTelescopeConfig({});
282
+ expect(result).toEqual({
283
+ enabled: true,
284
+ path: '/__telescope',
285
+ ignore: [],
286
+ recordBody: true,
287
+ maxEntries: 1000,
288
+ websocket: true,
289
+ });
290
+ });
291
+
292
+ it('should allow disabling websocket', () => {
293
+ const result = normalizeTelescopeConfig({
294
+ websocket: false,
295
+ });
296
+ expect(result).toEqual({
297
+ enabled: true,
298
+ path: '/__telescope',
299
+ ignore: [],
300
+ recordBody: true,
301
+ maxEntries: 1000,
302
+ websocket: false,
303
+ });
304
+ });
305
+ });
package/src/dev/index.ts CHANGED
@@ -3,8 +3,9 @@ import { mkdir } from 'node:fs/promises';
3
3
  import { createServer } from 'node:net';
4
4
  import { join } from 'node:path';
5
5
  import chokidar from 'chokidar';
6
+ import fg from 'fast-glob';
6
7
  import { resolveProviders } from '../build/providerResolver';
7
- import type { BuildContext } from '../build/types';
8
+ import type { BuildContext, NormalizedTelescopeConfig } from '../build/types';
8
9
  import { loadConfig } from '../config';
9
10
  import {
10
11
  CronGenerator,
@@ -12,7 +13,12 @@ import {
12
13
  FunctionGenerator,
13
14
  SubscriberGenerator,
14
15
  } from '../generators';
15
- import type { LegacyProvider } from '../types';
16
+ import type {
17
+ GkmConfig,
18
+ LegacyProvider,
19
+ Runtime,
20
+ TelescopeConfig,
21
+ } from '../types';
16
22
 
17
23
  const logger = console;
18
24
 
@@ -62,6 +68,38 @@ export async function findAvailablePort(
62
68
  );
63
69
  }
64
70
 
71
+ /**
72
+ * Normalize telescope configuration
73
+ * @internal Exported for testing
74
+ */
75
+ export function normalizeTelescopeConfig(
76
+ config: GkmConfig['telescope'],
77
+ ): NormalizedTelescopeConfig | undefined {
78
+ if (config === false) {
79
+ return undefined;
80
+ }
81
+
82
+ // Default to enabled in development mode
83
+ const isEnabled =
84
+ config === true || config === undefined || config.enabled !== false;
85
+
86
+ if (!isEnabled) {
87
+ return undefined;
88
+ }
89
+
90
+ const telescopeConfig: TelescopeConfig =
91
+ typeof config === 'object' ? config : {};
92
+
93
+ return {
94
+ enabled: true,
95
+ path: telescopeConfig.path ?? '/__telescope',
96
+ ignore: telescopeConfig.ignore ?? [],
97
+ recordBody: telescopeConfig.recordBody ?? true,
98
+ maxEntries: telescopeConfig.maxEntries ?? 1000,
99
+ websocket: telescopeConfig.websocket ?? true,
100
+ };
101
+ }
102
+
65
103
  export interface DevOptions {
66
104
  port?: number;
67
105
  enableOpenApi?: boolean;
@@ -102,11 +140,18 @@ export async function devCommand(options: DevOptions): Promise<void> {
102
140
  ? '{ logger }'
103
141
  : `{ ${loggerName} as logger }`;
104
142
 
143
+ // Normalize telescope configuration
144
+ const telescope = normalizeTelescopeConfig(config.telescope);
145
+ if (telescope) {
146
+ logger.log(`🔭 Telescope enabled at ${telescope.path}`);
147
+ }
148
+
105
149
  const buildContext: BuildContext = {
106
150
  envParserPath,
107
151
  envParserImportPattern,
108
152
  loggerPath,
109
153
  loggerImportPattern,
154
+ telescope,
110
155
  };
111
156
 
112
157
  // Build initial version
@@ -117,31 +162,70 @@ export async function devCommand(options: DevOptions): Promise<void> {
117
162
  resolved.enableOpenApi,
118
163
  );
119
164
 
165
+ // Determine runtime (default to node)
166
+ const runtime: Runtime = config.runtime ?? 'node';
167
+
120
168
  // Start the dev server
121
169
  const devServer = new DevServer(
122
170
  resolved.providers[0] as LegacyProvider,
123
171
  options.port || 3000,
124
172
  resolved.enableOpenApi,
173
+ telescope,
174
+ runtime,
125
175
  );
126
176
 
127
177
  await devServer.start();
128
178
 
129
179
  // Watch for file changes
180
+ const envParserFile = config.envParser.split('#')[0];
181
+ const loggerFile = config.logger.split('#')[0];
182
+
130
183
  const watchPatterns = [
131
184
  config.routes,
132
185
  ...(config.functions ? [config.functions] : []),
133
186
  ...(config.crons ? [config.crons] : []),
134
187
  ...(config.subscribers ? [config.subscribers] : []),
135
- config.envParser.split('#')[0],
136
- config.logger.split('#')[0],
188
+ // Add .ts extension if not present for config files
189
+ envParserFile.endsWith('.ts') ? envParserFile : `${envParserFile}.ts`,
190
+ loggerFile.endsWith('.ts') ? loggerFile : `${loggerFile}.ts`,
137
191
  ].flat();
138
192
 
139
- logger.log(`👀 Watching for changes in: ${watchPatterns.join(', ')}`);
193
+ // Normalize patterns - remove leading ./ when using cwd option
194
+ const normalizedPatterns = watchPatterns.map((p) =>
195
+ p.startsWith('./') ? p.slice(2) : p,
196
+ );
197
+
198
+ logger.log(`👀 Watching for changes in: ${normalizedPatterns.join(', ')}`);
199
+
200
+ // Resolve glob patterns to actual files (chokidar 4.x doesn't support globs)
201
+ const resolvedFiles = await fg(normalizedPatterns, {
202
+ cwd: process.cwd(),
203
+ absolute: false,
204
+ onlyFiles: true,
205
+ });
206
+
207
+ // Also watch the directories for new files
208
+ const dirsToWatch = [
209
+ ...new Set(resolvedFiles.map((f) => f.split('/').slice(0, -1).join('/'))),
210
+ ];
211
+
212
+ logger.log(
213
+ `📁 Found ${resolvedFiles.length} files in ${dirsToWatch.length} directories`,
214
+ );
140
215
 
141
- const watcher = chokidar.watch(watchPatterns, {
216
+ const watcher = chokidar.watch([...resolvedFiles, ...dirsToWatch], {
142
217
  ignored: /(^|[\/\\])\../, // ignore dotfiles
143
218
  persistent: true,
144
219
  ignoreInitial: true,
220
+ cwd: process.cwd(),
221
+ });
222
+
223
+ watcher.on('ready', () => {
224
+ logger.log('🔍 File watcher ready');
225
+ });
226
+
227
+ watcher.on('error', (error) => {
228
+ logger.error('❌ Watcher error:', error);
145
229
  });
146
230
 
147
231
  let rebuildTimeout: NodeJS.Timeout | null = null;
@@ -229,6 +313,8 @@ class DevServer {
229
313
  private provider: LegacyProvider,
230
314
  private requestedPort: number,
231
315
  private enableOpenApi: boolean,
316
+ private telescope?: NormalizedTelescopeConfig,
317
+ private runtime: Runtime = 'node',
232
318
  ) {
233
319
  this.actualPort = requestedPort;
234
320
  }
@@ -260,12 +346,14 @@ class DevServer {
260
346
  logger.log(`\n✨ Starting server on port ${this.actualPort}...`);
261
347
 
262
348
  // Start the server using tsx (TypeScript execution)
349
+ // Use detached: true so we can kill the entire process tree
263
350
  this.serverProcess = spawn(
264
351
  'npx',
265
352
  ['tsx', serverEntryPath, '--port', this.actualPort.toString()],
266
353
  {
267
354
  stdio: 'inherit',
268
355
  env: { ...process.env, NODE_ENV: 'development' },
356
+ detached: true,
269
357
  },
270
358
  );
271
359
 
@@ -292,19 +380,39 @@ class DevServer {
292
380
  `📚 API Docs available at http://localhost:${this.actualPort}/docs`,
293
381
  );
294
382
  }
383
+ if (this.telescope) {
384
+ logger.log(
385
+ `🔭 Telescope available at http://localhost:${this.actualPort}${this.telescope.path}`,
386
+ );
387
+ }
295
388
  }
296
389
  }
297
390
 
298
391
  async stop(): Promise<void> {
299
392
  if (this.serverProcess && this.isRunning) {
300
- this.serverProcess.kill('SIGTERM');
393
+ const pid = this.serverProcess.pid;
394
+
395
+ // Kill the entire process group (negative PID kills the group)
396
+ if (pid) {
397
+ try {
398
+ process.kill(-pid, 'SIGTERM');
399
+ } catch {
400
+ // Process might already be dead
401
+ }
402
+ }
301
403
 
302
404
  // Wait for process to exit
303
405
  await new Promise<void>((resolve) => {
304
406
  const timeout = setTimeout(() => {
305
- this.serverProcess?.kill('SIGKILL');
407
+ if (pid) {
408
+ try {
409
+ process.kill(-pid, 'SIGKILL');
410
+ } catch {
411
+ // Process might already be dead
412
+ }
413
+ }
306
414
  resolve();
307
- }, 5000);
415
+ }, 3000);
308
416
 
309
417
  this.serverProcess?.on('exit', () => {
310
418
  clearTimeout(timeout);
@@ -318,7 +426,21 @@ class DevServer {
318
426
  }
319
427
 
320
428
  async restart(): Promise<void> {
429
+ const portToReuse = this.actualPort;
321
430
  await this.stop();
431
+
432
+ // Wait for port to be released (up to 3 seconds)
433
+ let attempts = 0;
434
+ while (attempts < 30) {
435
+ if (await isPortAvailable(portToReuse)) {
436
+ break;
437
+ }
438
+ await new Promise((resolve) => setTimeout(resolve, 100));
439
+ attempts++;
440
+ }
441
+
442
+ // Force reuse the same port
443
+ this.requestedPort = portToReuse;
322
444
  await this.start();
323
445
  }
324
446
 
@@ -333,6 +455,24 @@ class DevServer {
333
455
  join(dirname(serverPath), 'app.js'),
334
456
  );
335
457
 
458
+ const serveCode =
459
+ this.runtime === 'bun'
460
+ ? `Bun.serve({
461
+ port,
462
+ fetch: app.fetch,
463
+ });`
464
+ : `const { serve } = await import('@hono/node-server');
465
+ const server = serve({
466
+ fetch: app.fetch,
467
+ port,
468
+ });
469
+ // Inject WebSocket support if available
470
+ const injectWs = (app as any).__injectWebSocket;
471
+ if (injectWs) {
472
+ injectWs(server);
473
+ console.log('🔌 Telescope real-time updates enabled');
474
+ }`;
475
+
336
476
  const content = `#!/usr/bin/env node
337
477
  /**
338
478
  * Development server entry point
@@ -344,27 +484,14 @@ const port = process.argv.includes('--port')
344
484
  ? Number.parseInt(process.argv[process.argv.indexOf('--port') + 1])
345
485
  : 3000;
346
486
 
347
- const { app, start } = createApp(undefined, ${this.enableOpenApi});
487
+ // createApp is async to support optional WebSocket setup
488
+ const { app, start } = await createApp(undefined, ${this.enableOpenApi});
348
489
 
349
490
  // Start the server
350
491
  start({
351
492
  port,
352
493
  serve: async (app, port) => {
353
- // Detect runtime and use appropriate server
354
- if (typeof Bun !== 'undefined') {
355
- // Bun runtime
356
- Bun.serve({
357
- port,
358
- fetch: app.fetch,
359
- });
360
- } else {
361
- // Node.js runtime with @hono/node-server
362
- const { serve } = await import('@hono/node-server');
363
- serve({
364
- fetch: app.fetch,
365
- port,
366
- });
367
- }
494
+ ${serveCode}
368
495
  },
369
496
  }).catch((error) => {
370
497
  console.error('Failed to start server:', error);
@@ -249,7 +249,7 @@ export class EndpointGenerator extends ConstructGenerator<
249
249
  any
250
250
  >
251
251
  >[],
252
- context: BuildContext,
252
+ _context: BuildContext,
253
253
  ): Promise<string> {
254
254
  const endpointsFileName = 'endpoints.ts';
255
255
  const endpointsPath = join(outputDir, endpointsFileName);
@@ -333,6 +333,69 @@ export function setupEndpoints(
333
333
  context.envParserPath,
334
334
  );
335
335
 
336
+ // Generate telescope imports and setup if enabled
337
+ const telescopeEnabled = context.telescope?.enabled;
338
+ const telescopeWebSocketEnabled = context.telescope?.websocket;
339
+ const telescopeImports = telescopeEnabled
340
+ ? `import { Telescope, InMemoryStorage } from '@geekmidas/telescope';
341
+ import { createMiddleware, createUI } from '@geekmidas/telescope/hono';`
342
+ : '';
343
+
344
+ const telescopeWebSocketSetupCode = telescopeWebSocketEnabled
345
+ ? `
346
+ // Setup WebSocket for real-time telescope updates
347
+ try {
348
+ const { createNodeWebSocket } = await import('@hono/node-ws');
349
+ const { injectWebSocket, upgradeWebSocket } = createNodeWebSocket({ app: honoApp });
350
+ // Add WebSocket route directly to main app (sub-app routes don't support WS upgrade)
351
+ honoApp.get('${context.telescope!.path}/ws', upgradeWebSocket(() => ({
352
+ onOpen: (_event: Event, ws: any) => {
353
+ telescope.addWsClient(ws);
354
+ },
355
+ onClose: (_event: Event, ws: any) => {
356
+ telescope.removeWsClient(ws);
357
+ },
358
+ onMessage: (event: MessageEvent, ws: any) => {
359
+ try {
360
+ const data = JSON.parse(event.data);
361
+ if (data.type === 'ping') {
362
+ ws.send(JSON.stringify({ type: 'pong' }));
363
+ }
364
+ } catch {
365
+ // Ignore invalid messages
366
+ }
367
+ },
368
+ })));
369
+ // Store injectWebSocket for server entry to call after serve()
370
+ (honoApp as any).__injectWebSocket = injectWebSocket;
371
+ logger.info('Telescope WebSocket enabled');
372
+ } catch (e) {
373
+ logger.warn({ error: e }, 'WebSocket support not available - install @hono/node-ws for real-time updates');
374
+ }
375
+ `
376
+ : '';
377
+
378
+ const telescopeSetup = telescopeEnabled
379
+ ? `
380
+ // Setup Telescope for debugging/monitoring
381
+ const telescopeStorage = new InMemoryStorage({ maxEntries: ${context.telescope!.maxEntries} });
382
+ const telescope = new Telescope({
383
+ enabled: true,
384
+ path: '${context.telescope!.path}',
385
+ ignorePatterns: ${JSON.stringify(context.telescope!.ignore)},
386
+ recordBody: ${context.telescope!.recordBody},
387
+ storage: telescopeStorage,
388
+ });
389
+ ${telescopeWebSocketSetupCode}
390
+ // Add telescope middleware (before endpoints to capture all requests)
391
+ honoApp.use('*', createMiddleware(telescope));
392
+
393
+ // Mount telescope UI
394
+ const telescopeUI = createUI(telescope);
395
+ honoApp.route('${context.telescope!.path}', telescopeUI);
396
+ `
397
+ : '';
398
+
336
399
  const content = `/**
337
400
  * Generated server application
338
401
  *
@@ -346,6 +409,7 @@ import { setupEndpoints } from './endpoints.js';
346
409
  import { setupSubscribers } from './subscribers.js';
347
410
  import ${context.envParserImportPattern} from '${relativeEnvParserPath}';
348
411
  import ${context.loggerImportPattern} from '${relativeLoggerPath}';
412
+ ${telescopeImports}
349
413
 
350
414
  export interface ServerApp {
351
415
  app: HonoType;
@@ -366,7 +430,7 @@ export interface ServerApp {
366
430
  * // With Bun
367
431
  * import { createApp } from './.gkm/server/app.js';
368
432
  *
369
- * const { app, start } = createApp();
433
+ * const { app, start } = await createApp();
370
434
  *
371
435
  * await start({
372
436
  * port: 3000,
@@ -380,7 +444,7 @@ export interface ServerApp {
380
444
  * import { serve } from '@hono/node-server';
381
445
  * import { createApp } from './.gkm/server/app.js';
382
446
  *
383
- * const { app, start } = createApp();
447
+ * const { app, start } = await createApp();
384
448
  *
385
449
  * await start({
386
450
  * port: 3000,
@@ -389,9 +453,9 @@ export interface ServerApp {
389
453
  * }
390
454
  * });
391
455
  */
392
- export function createApp(app?: HonoType, enableOpenApi: boolean = true): ServerApp {
456
+ export async function createApp(app?: HonoType, enableOpenApi: boolean = true): Promise<ServerApp> {
393
457
  const honoApp = app || new Hono();
394
-
458
+ ${telescopeSetup}
395
459
  // Setup HTTP endpoints
396
460
  setupEndpoints(honoApp, envParser, logger, enableOpenApi);
397
461