@geekmidas/cli 0.3.0 → 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.
- package/README.md +488 -71
- package/dist/{EndpointGenerator-C73wNoih.cjs → EndpointGenerator-BxNCkus4.cjs} +60 -6
- package/dist/EndpointGenerator-BxNCkus4.cjs.map +1 -0
- package/dist/{EndpointGenerator-CWh18d92.mjs → EndpointGenerator-CzDhG7Or.mjs} +60 -6
- package/dist/EndpointGenerator-CzDhG7Or.mjs.map +1 -0
- package/dist/OpenApiTsGenerator-NBNEoaeO.cjs +501 -0
- package/dist/OpenApiTsGenerator-NBNEoaeO.cjs.map +1 -0
- package/dist/OpenApiTsGenerator-q3aWNkuM.mjs +495 -0
- package/dist/OpenApiTsGenerator-q3aWNkuM.mjs.map +1 -0
- package/dist/build/index.cjs +3 -3
- package/dist/build/index.mjs +3 -3
- package/dist/{build-CBYBPZpC.cjs → build-CWtHnJMQ.cjs} +3 -3
- package/dist/{build-CBYBPZpC.cjs.map → build-CWtHnJMQ.cjs.map} +1 -1
- package/dist/{build-C6uEGRj8.mjs → build-DyDgu_D1.mjs} +3 -3
- package/dist/{build-C6uEGRj8.mjs.map → build-DyDgu_D1.mjs.map} +1 -1
- package/dist/{config-U-mdW-7Y.mjs → config-AFmFKmU0.mjs} +3 -3
- package/dist/config-AFmFKmU0.mjs.map +1 -0
- package/dist/{config-D1EpSGk6.cjs → config-BVIJpAsa.cjs} +3 -3
- package/dist/config-BVIJpAsa.cjs.map +1 -0
- package/dist/config.cjs +1 -1
- package/dist/config.mjs +1 -1
- package/dist/dev/index.cjs +5 -4
- package/dist/dev/index.mjs +4 -4
- package/dist/{dev-DbtyToc7.cjs → dev-CgDYC4o8.cjs} +95 -31
- package/dist/dev-CgDYC4o8.cjs.map +1 -0
- package/dist/{dev-DnGYXuMn.mjs → dev-CpA8AQPX.mjs} +90 -32
- package/dist/dev-CpA8AQPX.mjs.map +1 -0
- package/dist/generators/EndpointGenerator.cjs +1 -1
- package/dist/generators/EndpointGenerator.mjs +1 -1
- package/dist/generators/OpenApiTsGenerator.cjs +3 -0
- package/dist/generators/OpenApiTsGenerator.mjs +3 -0
- package/dist/generators/index.cjs +1 -1
- package/dist/generators/index.mjs +1 -1
- package/dist/index.cjs +15 -9
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +15 -9
- package/dist/index.mjs.map +1 -1
- package/dist/openapi-DRTRGhTt.mjs +50 -0
- package/dist/openapi-DRTRGhTt.mjs.map +1 -0
- package/dist/openapi-DhK4b0lB.cjs +56 -0
- package/dist/openapi-DhK4b0lB.cjs.map +1 -0
- package/dist/openapi.cjs +4 -3
- package/dist/openapi.mjs +4 -3
- package/docs/OPENAPI_TYPESCRIPT_DESIGN.md +408 -0
- package/package.json +10 -3
- package/src/__tests__/openapi.spec.ts +78 -63
- package/src/build/types.ts +13 -2
- package/src/config.ts +4 -2
- package/src/dev/__tests__/index.spec.ts +98 -1
- package/src/dev/index.ts +152 -25
- package/src/generators/EndpointGenerator.ts +69 -5
- package/src/generators/OpenApiTsGenerator.ts +798 -0
- package/src/index.ts +6 -3
- package/src/openapi.ts +36 -15
- package/src/types.ts +23 -0
- package/dist/EndpointGenerator-C73wNoih.cjs.map +0 -1
- package/dist/EndpointGenerator-CWh18d92.mjs.map +0 -1
- package/dist/config-D1EpSGk6.cjs.map +0 -1
- package/dist/config-U-mdW-7Y.mjs.map +0 -1
- package/dist/dev-DbtyToc7.cjs.map +0 -1
- package/dist/dev-DnGYXuMn.mjs.map +0 -1
- package/dist/openapi-BTHbPrxS.mjs +0 -36
- package/dist/openapi-BTHbPrxS.mjs.map +0 -1
- package/dist/openapi-CewcfoRH.cjs +0 -42
- package/dist/openapi-CewcfoRH.cjs.map +0 -1
package/README.md
CHANGED
|
@@ -5,6 +5,8 @@ A powerful CLI tool for building and managing TypeScript-based backend APIs with
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
7
7
|
- **Multi-Provider Support**: Generate handlers for AWS Lambda (API Gateway v1/v2) and server applications
|
|
8
|
+
- **Development Server**: Hot-reload development server with file watching
|
|
9
|
+
- **Telescope Integration**: Laravel-style debugging dashboard for inspecting requests, logs, and exceptions
|
|
8
10
|
- **OpenAPI Generation**: Auto-generate OpenAPI 3.0 specifications from your endpoints
|
|
9
11
|
- **Type-Safe Configuration**: Configuration with TypeScript support and validation
|
|
10
12
|
- **Endpoint Auto-Discovery**: Automatically find and load endpoints from your codebase
|
|
@@ -51,6 +53,12 @@ const config: GkmConfig = {
|
|
|
51
53
|
|
|
52
54
|
// Logger configuration
|
|
53
55
|
logger: './src/logger.ts#logger',
|
|
56
|
+
|
|
57
|
+
// Optional: Telescope debugging dashboard (enabled by default in dev)
|
|
58
|
+
telescope: {
|
|
59
|
+
enabled: true,
|
|
60
|
+
path: '/__telescope',
|
|
61
|
+
},
|
|
54
62
|
};
|
|
55
63
|
|
|
56
64
|
export default config;
|
|
@@ -166,8 +174,8 @@ npx gkm build --provider aws-apigatewayv1
|
|
|
166
174
|
# Generate server application
|
|
167
175
|
npx gkm build --provider server
|
|
168
176
|
|
|
169
|
-
# Generate OpenAPI
|
|
170
|
-
npx gkm openapi --output api
|
|
177
|
+
# Generate OpenAPI TypeScript module
|
|
178
|
+
npx gkm openapi --output src/api.ts
|
|
171
179
|
```
|
|
172
180
|
|
|
173
181
|
## CLI Commands
|
|
@@ -197,19 +205,141 @@ gkm build --provider server
|
|
|
197
205
|
|
|
198
206
|
### `gkm openapi`
|
|
199
207
|
|
|
200
|
-
Generate OpenAPI
|
|
208
|
+
Generate OpenAPI TypeScript module from your endpoints. This is the recommended approach as it provides full type safety and a ready-to-use API client.
|
|
201
209
|
|
|
202
210
|
```bash
|
|
203
211
|
gkm openapi [options]
|
|
204
212
|
```
|
|
205
213
|
|
|
206
214
|
**Options:**
|
|
207
|
-
- `--output <path>`: Output file path (default: `openapi.
|
|
215
|
+
- `--output <path>`: Output file path (default: `openapi.ts`)
|
|
216
|
+
- `--json`: Generate legacy JSON format instead of TypeScript module
|
|
217
|
+
|
|
218
|
+
**Example:**
|
|
219
|
+
```bash
|
|
220
|
+
# Generate TypeScript module (recommended)
|
|
221
|
+
gkm openapi --output src/api.ts
|
|
222
|
+
|
|
223
|
+
# Generate legacy JSON format
|
|
224
|
+
gkm openapi --output docs/api.json --json
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
#### Generated TypeScript Module
|
|
228
|
+
|
|
229
|
+
The generated TypeScript module includes:
|
|
230
|
+
|
|
231
|
+
```typescript
|
|
232
|
+
// src/api.ts (auto-generated)
|
|
233
|
+
|
|
234
|
+
// Security schemes defined in your endpoints
|
|
235
|
+
export const securitySchemes = {
|
|
236
|
+
jwt: { type: 'http', scheme: 'bearer', bearerFormat: 'JWT' },
|
|
237
|
+
apiKey: { type: 'apiKey', in: 'header', name: 'X-API-Key' },
|
|
238
|
+
} as const;
|
|
239
|
+
|
|
240
|
+
export type SecuritySchemeId = 'jwt' | 'apiKey';
|
|
241
|
+
|
|
242
|
+
// Endpoint-to-auth mapping
|
|
243
|
+
export const endpointAuth = {
|
|
244
|
+
'GET /users': 'jwt',
|
|
245
|
+
'POST /users': 'jwt',
|
|
246
|
+
'GET /health': null,
|
|
247
|
+
} as const;
|
|
248
|
+
|
|
249
|
+
// TypeScript interfaces for request/response types
|
|
250
|
+
export interface GetUsersOutput {
|
|
251
|
+
id: string;
|
|
252
|
+
name: string;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// OpenAPI paths interface
|
|
256
|
+
export interface paths {
|
|
257
|
+
'/users': {
|
|
258
|
+
get: {
|
|
259
|
+
responses: {
|
|
260
|
+
200: { content: { 'application/json': GetUsersOutput[] } };
|
|
261
|
+
};
|
|
262
|
+
};
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// Ready-to-use API client factory
|
|
267
|
+
export function createApi(options: CreateApiOptions) {
|
|
268
|
+
// ... implementation
|
|
269
|
+
}
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
#### Using the Generated Client
|
|
273
|
+
|
|
274
|
+
```typescript
|
|
275
|
+
import { createApi } from './api';
|
|
276
|
+
|
|
277
|
+
const api = createApi({
|
|
278
|
+
baseURL: 'https://api.example.com',
|
|
279
|
+
authStrategies: {
|
|
280
|
+
jwt: {
|
|
281
|
+
type: 'bearer',
|
|
282
|
+
tokenProvider: async () => localStorage.getItem('token'),
|
|
283
|
+
},
|
|
284
|
+
},
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
// Imperative fetching
|
|
288
|
+
const users = await api('GET /users');
|
|
289
|
+
|
|
290
|
+
// React Query hooks
|
|
291
|
+
const { data } = api.useQuery('GET /users');
|
|
292
|
+
const mutation = api.useMutation('POST /users');
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
### `gkm dev`
|
|
296
|
+
|
|
297
|
+
Start a development server with hot-reload and optional Telescope debugging dashboard.
|
|
298
|
+
|
|
299
|
+
```bash
|
|
300
|
+
gkm dev [options]
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
**Options:**
|
|
304
|
+
- `--port <port>`: Server port (default: `3000`)
|
|
305
|
+
|
|
306
|
+
**Features:**
|
|
307
|
+
- Hot-reload on file changes (endpoints, functions, crons, subscribers)
|
|
308
|
+
- Automatic port switching if requested port is in use
|
|
309
|
+
- Telescope debugging dashboard (enabled by default)
|
|
310
|
+
- Real-time WebSocket updates in Telescope
|
|
208
311
|
|
|
209
312
|
**Example:**
|
|
210
313
|
```bash
|
|
211
|
-
#
|
|
212
|
-
gkm
|
|
314
|
+
# Start development server on port 3000
|
|
315
|
+
gkm dev
|
|
316
|
+
|
|
317
|
+
# Start on custom port
|
|
318
|
+
gkm dev --port 8080
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
**Output:**
|
|
322
|
+
```
|
|
323
|
+
🚀 Starting development server...
|
|
324
|
+
Loading routes from: ./src/endpoints/**/*.ts
|
|
325
|
+
Loading subscribers from: ./src/subscribers/**/*.ts
|
|
326
|
+
Using envParser: ./src/config/env
|
|
327
|
+
🔭 Telescope enabled at /__telescope
|
|
328
|
+
Generated server with 5 endpoints
|
|
329
|
+
|
|
330
|
+
✨ Starting server on port 3000...
|
|
331
|
+
🔌 Telescope real-time updates enabled
|
|
332
|
+
|
|
333
|
+
🎉 Server running at http://localhost:3000
|
|
334
|
+
🔭 Telescope available at http://localhost:3000/__telescope
|
|
335
|
+
👀 Watching for changes in: src/endpoints/**/*.ts, src/subscribers/**/*.ts
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
When files change, the server automatically rebuilds and restarts:
|
|
339
|
+
```
|
|
340
|
+
📝 File changed: src/endpoints/users.ts
|
|
341
|
+
🔄 Rebuilding...
|
|
342
|
+
✅ Rebuild complete, restarting server...
|
|
213
343
|
```
|
|
214
344
|
|
|
215
345
|
### Future Commands
|
|
@@ -231,6 +361,20 @@ interface GkmConfig {
|
|
|
231
361
|
routes: string | string[]; // Glob patterns for endpoint files
|
|
232
362
|
envParser: string; // Path to environment parser
|
|
233
363
|
logger: string; // Path to logger configuration
|
|
364
|
+
functions?: string | string[]; // Glob patterns for function files
|
|
365
|
+
crons?: string | string[]; // Glob patterns for cron files
|
|
366
|
+
subscribers?: string | string[];// Glob patterns for subscriber files
|
|
367
|
+
runtime?: 'node' | 'bun'; // Runtime environment (default: 'node')
|
|
368
|
+
telescope?: boolean | TelescopeConfig; // Telescope debugging config
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
interface TelescopeConfig {
|
|
372
|
+
enabled?: boolean; // Enable/disable (default: true in dev)
|
|
373
|
+
path?: string; // Dashboard path (default: '/__telescope')
|
|
374
|
+
ignore?: string[]; // URL patterns to ignore
|
|
375
|
+
recordBody?: boolean; // Record request/response bodies (default: true)
|
|
376
|
+
maxEntries?: number; // Max entries to keep (default: 1000)
|
|
377
|
+
websocket?: boolean; // Enable real-time updates (default: true)
|
|
234
378
|
}
|
|
235
379
|
```
|
|
236
380
|
|
|
@@ -282,6 +426,65 @@ logger: './src/logger.ts#logger'
|
|
|
282
426
|
logger: './src/utils.ts#appLogger'
|
|
283
427
|
```
|
|
284
428
|
|
|
429
|
+
#### `telescope`
|
|
430
|
+
|
|
431
|
+
Configuration for the Telescope debugging dashboard. Telescope is enabled by default when using `gkm dev`.
|
|
432
|
+
|
|
433
|
+
```typescript
|
|
434
|
+
// Disable telescope
|
|
435
|
+
telescope: false
|
|
436
|
+
|
|
437
|
+
// Enable with defaults
|
|
438
|
+
telescope: true
|
|
439
|
+
|
|
440
|
+
// Custom configuration
|
|
441
|
+
telescope: {
|
|
442
|
+
enabled: true,
|
|
443
|
+
path: '/__telescope',
|
|
444
|
+
ignore: ['/health', '/metrics'],
|
|
445
|
+
recordBody: true,
|
|
446
|
+
maxEntries: 1000,
|
|
447
|
+
websocket: true,
|
|
448
|
+
}
|
|
449
|
+
```
|
|
450
|
+
|
|
451
|
+
**Options:**
|
|
452
|
+
|
|
453
|
+
| Option | Type | Default | Description |
|
|
454
|
+
|--------|------|---------|-------------|
|
|
455
|
+
| `enabled` | `boolean` | `true` | Enable/disable Telescope |
|
|
456
|
+
| `path` | `string` | `/__telescope` | Dashboard URL path |
|
|
457
|
+
| `ignore` | `string[]` | `[]` | URL patterns to exclude from recording |
|
|
458
|
+
| `recordBody` | `boolean` | `true` | Record request/response bodies |
|
|
459
|
+
| `maxEntries` | `number` | `1000` | Maximum entries per type to keep |
|
|
460
|
+
| `websocket` | `boolean` | `true` | Enable real-time WebSocket updates |
|
|
461
|
+
|
|
462
|
+
**Logger Integration:**
|
|
463
|
+
|
|
464
|
+
Telescope automatically captures logs when using `gkm dev`. To manually integrate with your logger:
|
|
465
|
+
|
|
466
|
+
```typescript
|
|
467
|
+
// Pino Transport
|
|
468
|
+
import pino from 'pino';
|
|
469
|
+
import { createPinoDestination } from '@geekmidas/telescope/logger/pino';
|
|
470
|
+
|
|
471
|
+
const logger = pino(
|
|
472
|
+
{ level: 'debug' },
|
|
473
|
+
pino.multistream([
|
|
474
|
+
{ stream: process.stdout },
|
|
475
|
+
{ stream: createPinoDestination({ telescope }) }
|
|
476
|
+
])
|
|
477
|
+
);
|
|
478
|
+
|
|
479
|
+
// ConsoleLogger wrapper
|
|
480
|
+
import { createTelescopeLogger } from '@geekmidas/telescope/logger/console';
|
|
481
|
+
import { ConsoleLogger } from '@geekmidas/logger/console';
|
|
482
|
+
|
|
483
|
+
const logger = createTelescopeLogger(telescope, new ConsoleLogger());
|
|
484
|
+
```
|
|
485
|
+
|
|
486
|
+
See the [@geekmidas/telescope documentation](../telescope/README.md) for more details.
|
|
487
|
+
|
|
285
488
|
## Providers
|
|
286
489
|
|
|
287
490
|
### AWS API Gateway v1
|
|
@@ -366,95 +569,193 @@ The CLI generates files in the `.gkm/<provider>` directory:
|
|
|
366
569
|
├── aws-apigatewayv1/
|
|
367
570
|
│ ├── getUsers.ts # Individual Lambda handler
|
|
368
571
|
│ ├── createUser.ts # Individual Lambda handler
|
|
369
|
-
│ └── manifest.json # Build manifest
|
|
370
572
|
├── server/
|
|
371
573
|
│ ├── app.ts # Server application
|
|
372
|
-
│
|
|
574
|
+
│ ├── endpoints.ts # Endpoint exports
|
|
575
|
+
├── manifest/
|
|
576
|
+
│ ├── aws.ts # AWS manifest with types
|
|
577
|
+
│ └── server.ts # Server manifest with types
|
|
373
578
|
└── openapi.json # OpenAPI specification
|
|
374
579
|
```
|
|
375
580
|
|
|
376
581
|
### Build Manifest
|
|
377
582
|
|
|
378
|
-
|
|
583
|
+
The CLI generates TypeScript manifests with full type information in the `.gkm/manifest/` directory. These manifests export both the data and derived types for type-safe usage.
|
|
379
584
|
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
585
|
+
#### AWS Manifest (`.gkm/manifest/aws.ts`)
|
|
586
|
+
|
|
587
|
+
```typescript
|
|
588
|
+
export const manifest = {
|
|
589
|
+
routes: [
|
|
383
590
|
{
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
591
|
+
path: '/users',
|
|
592
|
+
method: 'GET',
|
|
593
|
+
handler: '.gkm/aws-apigatewayv1/getUsers.handler',
|
|
594
|
+
authorizer: 'jwt',
|
|
387
595
|
},
|
|
388
596
|
{
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
597
|
+
path: '/users',
|
|
598
|
+
method: 'POST',
|
|
599
|
+
handler: '.gkm/aws-apigatewayv1/createUser.handler',
|
|
600
|
+
authorizer: 'jwt',
|
|
601
|
+
},
|
|
393
602
|
],
|
|
394
|
-
|
|
603
|
+
functions: [
|
|
395
604
|
{
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
}
|
|
605
|
+
name: 'processData',
|
|
606
|
+
handler: '.gkm/aws-lambda/functions/processData.handler',
|
|
607
|
+
timeout: 60,
|
|
608
|
+
memorySize: 256,
|
|
609
|
+
},
|
|
401
610
|
],
|
|
402
|
-
|
|
611
|
+
crons: [
|
|
403
612
|
{
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
}
|
|
410
|
-
]
|
|
613
|
+
name: 'dailyCleanup',
|
|
614
|
+
handler: '.gkm/aws-lambda/crons/dailyCleanup.handler',
|
|
615
|
+
schedule: 'rate(1 day)',
|
|
616
|
+
timeout: 300,
|
|
617
|
+
memorySize: 512,
|
|
618
|
+
},
|
|
619
|
+
],
|
|
620
|
+
subscribers: [],
|
|
621
|
+
} as const;
|
|
622
|
+
|
|
623
|
+
// Derived types
|
|
624
|
+
export type Route = (typeof manifest.routes)[number];
|
|
625
|
+
export type Function = (typeof manifest.functions)[number];
|
|
626
|
+
export type Cron = (typeof manifest.crons)[number];
|
|
627
|
+
export type Subscriber = (typeof manifest.subscribers)[number];
|
|
628
|
+
|
|
629
|
+
// Useful union types
|
|
630
|
+
export type Authorizer = Route['authorizer'];
|
|
631
|
+
export type HttpMethod = Route['method'];
|
|
632
|
+
export type RoutePath = Route['path'];
|
|
633
|
+
```
|
|
634
|
+
|
|
635
|
+
#### Server Manifest (`.gkm/manifest/server.ts`)
|
|
636
|
+
|
|
637
|
+
```typescript
|
|
638
|
+
export const manifest = {
|
|
639
|
+
app: {
|
|
640
|
+
handler: '.gkm/server/app.ts',
|
|
641
|
+
endpoints: '.gkm/server/endpoints.ts',
|
|
642
|
+
},
|
|
643
|
+
routes: [
|
|
644
|
+
{ path: '/users', method: 'GET', authorizer: 'jwt' },
|
|
645
|
+
{ path: '/users', method: 'POST', authorizer: 'jwt' },
|
|
646
|
+
],
|
|
647
|
+
subscribers: [
|
|
648
|
+
{ name: 'orderHandler', subscribedEvents: ['order.created'] },
|
|
649
|
+
],
|
|
650
|
+
} as const;
|
|
651
|
+
|
|
652
|
+
// Derived types
|
|
653
|
+
export type Route = (typeof manifest.routes)[number];
|
|
654
|
+
export type Subscriber = (typeof manifest.subscribers)[number];
|
|
655
|
+
|
|
656
|
+
// Useful union types
|
|
657
|
+
export type Authorizer = Route['authorizer'];
|
|
658
|
+
export type HttpMethod = Route['method'];
|
|
659
|
+
export type RoutePath = Route['path'];
|
|
660
|
+
```
|
|
661
|
+
|
|
662
|
+
#### Using Manifest Types
|
|
663
|
+
|
|
664
|
+
Import the manifest types for type-safe infrastructure configuration:
|
|
665
|
+
|
|
666
|
+
```typescript
|
|
667
|
+
import { manifest, type Route, type Authorizer } from './.gkm/manifest/aws';
|
|
668
|
+
|
|
669
|
+
// Type-safe route iteration
|
|
670
|
+
for (const route of manifest.routes) {
|
|
671
|
+
console.log(`${route.method} ${route.path} -> ${route.handler}`);
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
// Use union types for validation
|
|
675
|
+
function isValidMethod(method: string): method is HttpMethod {
|
|
676
|
+
return manifest.routes.some((r) => r.method === method);
|
|
411
677
|
}
|
|
678
|
+
|
|
679
|
+
// Access authorizer names
|
|
680
|
+
const authorizers = new Set(manifest.routes.map((r) => r.authorizer));
|
|
412
681
|
```
|
|
413
682
|
|
|
414
683
|
## OpenAPI Generation
|
|
415
684
|
|
|
416
|
-
The CLI
|
|
685
|
+
The CLI generates a TypeScript module with full type safety and a ready-to-use API client:
|
|
417
686
|
|
|
418
687
|
```bash
|
|
419
|
-
gkm openapi --output api
|
|
688
|
+
gkm openapi --output src/api.ts
|
|
420
689
|
```
|
|
421
690
|
|
|
422
|
-
**Generated
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
691
|
+
**Generated TypeScript Module:**
|
|
692
|
+
|
|
693
|
+
The generated module exports:
|
|
694
|
+
|
|
695
|
+
| Export | Description |
|
|
696
|
+
|--------|-------------|
|
|
697
|
+
| `securitySchemes` | OpenAPI security scheme definitions |
|
|
698
|
+
| `SecuritySchemeId` | Union type of security scheme names |
|
|
699
|
+
| `endpointAuth` | Map of endpoints to their auth requirements |
|
|
700
|
+
| `paths` | TypeScript interface for OpenAPI paths |
|
|
701
|
+
| `createApi()` | Factory function to create typed API client |
|
|
702
|
+
|
|
703
|
+
**Example Generated Output:**
|
|
704
|
+
|
|
705
|
+
```typescript
|
|
706
|
+
// Security schemes from your endpoint authorizers
|
|
707
|
+
export const securitySchemes = {
|
|
708
|
+
jwt: {
|
|
709
|
+
type: 'http',
|
|
710
|
+
scheme: 'bearer',
|
|
711
|
+
bearerFormat: 'JWT',
|
|
430
712
|
},
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
}
|
|
454
|
-
}
|
|
455
|
-
}
|
|
456
|
-
}
|
|
713
|
+
} as const;
|
|
714
|
+
|
|
715
|
+
export type SecuritySchemeId = 'jwt';
|
|
716
|
+
|
|
717
|
+
// Which endpoints require which auth
|
|
718
|
+
export const endpointAuth = {
|
|
719
|
+
'GET /users': 'jwt',
|
|
720
|
+
'POST /users': 'jwt',
|
|
721
|
+
'GET /health': null, // Public endpoint
|
|
722
|
+
} as const;
|
|
723
|
+
|
|
724
|
+
// Type-safe paths interface
|
|
725
|
+
export interface paths {
|
|
726
|
+
'/users': {
|
|
727
|
+
get: {
|
|
728
|
+
responses: {
|
|
729
|
+
200: { content: { 'application/json': GetUsersOutput[] } };
|
|
730
|
+
};
|
|
731
|
+
};
|
|
732
|
+
post: {
|
|
733
|
+
requestBody: { content: { 'application/json': CreateUserInput } };
|
|
734
|
+
responses: {
|
|
735
|
+
201: { content: { 'application/json': GetUsersOutput } };
|
|
736
|
+
};
|
|
737
|
+
};
|
|
738
|
+
};
|
|
457
739
|
}
|
|
740
|
+
|
|
741
|
+
// Factory to create API client
|
|
742
|
+
export interface CreateApiOptions {
|
|
743
|
+
baseURL: string;
|
|
744
|
+
authStrategies: Record<SecuritySchemeId, AuthStrategy>;
|
|
745
|
+
queryClient?: QueryClient;
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
export function createApi(options: CreateApiOptions) {
|
|
749
|
+
// Returns callable fetcher with React Query hooks
|
|
750
|
+
}
|
|
751
|
+
```
|
|
752
|
+
|
|
753
|
+
### Legacy JSON Output
|
|
754
|
+
|
|
755
|
+
For compatibility with other tools, you can still generate JSON:
|
|
756
|
+
|
|
757
|
+
```bash
|
|
758
|
+
gkm openapi --output api-docs.json --json
|
|
458
759
|
```
|
|
459
760
|
|
|
460
761
|
## Deployment Examples
|
|
@@ -556,6 +857,97 @@ export const envParser = new EnvironmentParser(process.env)
|
|
|
556
857
|
.parse();
|
|
557
858
|
```
|
|
558
859
|
|
|
860
|
+
### Authentication Integration
|
|
861
|
+
|
|
862
|
+
Integrate `@geekmidas/auth` for JWT/OIDC authentication in your endpoints:
|
|
863
|
+
|
|
864
|
+
```typescript
|
|
865
|
+
// src/env.ts
|
|
866
|
+
import { EnvironmentParser } from '@geekmidas/envkit';
|
|
867
|
+
|
|
868
|
+
export const envParser = new EnvironmentParser(process.env)
|
|
869
|
+
.create((get) => ({
|
|
870
|
+
auth: {
|
|
871
|
+
jwtSecret: get('JWT_SECRET').string(),
|
|
872
|
+
jwtIssuer: get('JWT_ISSUER').string().optional(),
|
|
873
|
+
jwtAudience: get('JWT_AUDIENCE').string().optional(),
|
|
874
|
+
},
|
|
875
|
+
}))
|
|
876
|
+
.parse();
|
|
877
|
+
```
|
|
878
|
+
|
|
879
|
+
#### With Hono Middleware (Server Provider)
|
|
880
|
+
|
|
881
|
+
```typescript
|
|
882
|
+
// src/routes/protected.ts
|
|
883
|
+
import { e } from '@geekmidas/constructs/endpoints';
|
|
884
|
+
import { JwtMiddleware } from '@geekmidas/auth/hono/jwt';
|
|
885
|
+
import { envParser } from '../env.js';
|
|
886
|
+
|
|
887
|
+
const jwt = new JwtMiddleware({
|
|
888
|
+
config: {
|
|
889
|
+
secret: envParser.auth.jwtSecret,
|
|
890
|
+
issuer: envParser.auth.jwtIssuer,
|
|
891
|
+
audience: envParser.auth.jwtAudience,
|
|
892
|
+
},
|
|
893
|
+
});
|
|
894
|
+
|
|
895
|
+
// Apply middleware to Hono app
|
|
896
|
+
app.use('/api/*', jwt.handler());
|
|
897
|
+
app.use('/public/*', jwt.optional());
|
|
898
|
+
```
|
|
899
|
+
|
|
900
|
+
#### With Lambda Authorizers (AWS Provider)
|
|
901
|
+
|
|
902
|
+
```typescript
|
|
903
|
+
// src/authorizers/jwt.ts
|
|
904
|
+
import { JwtAuthorizer } from '@geekmidas/auth/lambda/jwt';
|
|
905
|
+
import { envParser } from '../env.js';
|
|
906
|
+
|
|
907
|
+
const authorizer = new JwtAuthorizer({
|
|
908
|
+
config: {
|
|
909
|
+
secret: envParser.auth.jwtSecret,
|
|
910
|
+
issuer: envParser.auth.jwtIssuer,
|
|
911
|
+
},
|
|
912
|
+
getContext: (claims) => ({
|
|
913
|
+
userId: claims.sub!,
|
|
914
|
+
}),
|
|
915
|
+
});
|
|
916
|
+
|
|
917
|
+
export const handler = authorizer.requestHandler();
|
|
918
|
+
```
|
|
919
|
+
|
|
920
|
+
#### With OIDC (Auth0, Cognito, etc.)
|
|
921
|
+
|
|
922
|
+
```typescript
|
|
923
|
+
// src/env.ts
|
|
924
|
+
export const envParser = new EnvironmentParser(process.env)
|
|
925
|
+
.create((get) => ({
|
|
926
|
+
oidc: {
|
|
927
|
+
issuer: get('OIDC_ISSUER').string().url(),
|
|
928
|
+
audience: get('OIDC_AUDIENCE').string(),
|
|
929
|
+
},
|
|
930
|
+
}))
|
|
931
|
+
.parse();
|
|
932
|
+
|
|
933
|
+
// src/authorizers/oidc.ts
|
|
934
|
+
import { OidcAuthorizer } from '@geekmidas/auth/lambda/oidc';
|
|
935
|
+
import { envParser } from '../env.js';
|
|
936
|
+
|
|
937
|
+
const authorizer = new OidcAuthorizer({
|
|
938
|
+
config: {
|
|
939
|
+
issuer: envParser.oidc.issuer,
|
|
940
|
+
audience: envParser.oidc.audience,
|
|
941
|
+
},
|
|
942
|
+
getContext: (claims) => ({
|
|
943
|
+
userId: claims.sub!,
|
|
944
|
+
email: claims.email,
|
|
945
|
+
}),
|
|
946
|
+
});
|
|
947
|
+
|
|
948
|
+
export const handler = authorizer.requestHandler();
|
|
949
|
+
```
|
|
950
|
+
|
|
559
951
|
### Custom Logger Configuration
|
|
560
952
|
|
|
561
953
|
Set up structured logging with different levels:
|
|
@@ -635,11 +1027,12 @@ Error: OpenAPI generation failed: Invalid endpoint schema
|
|
|
635
1027
|
```json
|
|
636
1028
|
{
|
|
637
1029
|
"scripts": {
|
|
1030
|
+
"dev": "gkm dev",
|
|
1031
|
+
"dev:port": "gkm dev --port 8080",
|
|
638
1032
|
"build": "gkm build",
|
|
639
1033
|
"build:lambda": "gkm build --provider aws-apigatewayv1",
|
|
640
1034
|
"build:server": "gkm build --provider server",
|
|
641
|
-
"docs": "gkm openapi --output
|
|
642
|
-
"dev": "npm run build:server && node server.js"
|
|
1035
|
+
"docs": "gkm openapi --output src/api.ts"
|
|
643
1036
|
}
|
|
644
1037
|
}
|
|
645
1038
|
```
|
|
@@ -734,11 +1127,29 @@ DEBUG=gkm:* npx gkm build
|
|
|
734
1127
|
// Provider options
|
|
735
1128
|
type Provider = 'server' | 'aws-apigatewayv1' | 'aws-apigatewayv2';
|
|
736
1129
|
|
|
1130
|
+
// Runtime options
|
|
1131
|
+
type Runtime = 'node' | 'bun';
|
|
1132
|
+
|
|
737
1133
|
// Configuration interface
|
|
738
1134
|
interface GkmConfig {
|
|
739
1135
|
routes: string | string[];
|
|
740
1136
|
envParser: string;
|
|
741
1137
|
logger: string;
|
|
1138
|
+
functions?: string | string[];
|
|
1139
|
+
crons?: string | string[];
|
|
1140
|
+
subscribers?: string | string[];
|
|
1141
|
+
runtime?: Runtime;
|
|
1142
|
+
telescope?: boolean | TelescopeConfig;
|
|
1143
|
+
}
|
|
1144
|
+
|
|
1145
|
+
// Telescope configuration
|
|
1146
|
+
interface TelescopeConfig {
|
|
1147
|
+
enabled?: boolean;
|
|
1148
|
+
path?: string;
|
|
1149
|
+
ignore?: string[];
|
|
1150
|
+
recordBody?: boolean;
|
|
1151
|
+
maxEntries?: number;
|
|
1152
|
+
websocket?: boolean;
|
|
742
1153
|
}
|
|
743
1154
|
|
|
744
1155
|
// Build options
|
|
@@ -746,6 +1157,12 @@ interface BuildOptions {
|
|
|
746
1157
|
provider: Provider;
|
|
747
1158
|
}
|
|
748
1159
|
|
|
1160
|
+
// Dev options
|
|
1161
|
+
interface DevOptions {
|
|
1162
|
+
port?: number;
|
|
1163
|
+
enableOpenApi?: boolean;
|
|
1164
|
+
}
|
|
1165
|
+
|
|
749
1166
|
// Route information
|
|
750
1167
|
interface RouteInfo {
|
|
751
1168
|
path: string;
|