@geekmidas/cli 0.42.0 → 0.44.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 CHANGED
@@ -1109,6 +1109,227 @@ const logger = createTelescopeLogger(telescope, new ConsoleLogger());
1109
1109
 
1110
1110
  See the [@geekmidas/telescope documentation](../telescope/README.md) for more details.
1111
1111
 
1112
+ ## Workspace Configuration
1113
+
1114
+ For fullstack monorepo projects with multiple apps, use `defineWorkspace` instead of `defineConfig`:
1115
+
1116
+ ```typescript
1117
+ // gkm.config.ts (at workspace root)
1118
+ import { defineWorkspace } from '@geekmidas/cli/config';
1119
+
1120
+ export default defineWorkspace({
1121
+ name: 'my-project',
1122
+ apps: {
1123
+ api: {
1124
+ type: 'backend',
1125
+ path: 'apps/api',
1126
+ port: 3000,
1127
+ routes: './src/endpoints/**/*.ts',
1128
+ envParser: './src/config/env#envParser',
1129
+ logger: './src/config/logger#logger',
1130
+ telescope: {
1131
+ enabled: true,
1132
+ path: '/__telescope',
1133
+ },
1134
+ openapi: {
1135
+ enabled: true,
1136
+ },
1137
+ },
1138
+ auth: {
1139
+ type: 'backend',
1140
+ path: 'apps/auth',
1141
+ port: 3002,
1142
+ entry: './src/index.ts', // Entry-based app (no routes)
1143
+ envParser: './src/config/env#envParser',
1144
+ logger: './src/config/logger#logger',
1145
+ },
1146
+ web: {
1147
+ type: 'frontend',
1148
+ framework: 'nextjs',
1149
+ path: 'apps/web',
1150
+ port: 3001,
1151
+ dependencies: ['api', 'auth'],
1152
+ client: {
1153
+ output: './src/api',
1154
+ },
1155
+ },
1156
+ },
1157
+ shared: {
1158
+ packages: ['packages/*'],
1159
+ models: {
1160
+ path: 'packages/models',
1161
+ schema: 'zod',
1162
+ },
1163
+ },
1164
+ services: {
1165
+ db: true,
1166
+ cache: true,
1167
+ mail: true,
1168
+ },
1169
+ deploy: {
1170
+ default: 'dokploy',
1171
+ },
1172
+ });
1173
+ ```
1174
+
1175
+ ### App Types
1176
+
1177
+ #### Routes-Based Backend Apps
1178
+
1179
+ Standard API apps using endpoint discovery:
1180
+
1181
+ ```typescript
1182
+ api: {
1183
+ type: 'backend',
1184
+ path: 'apps/api',
1185
+ port: 3000,
1186
+ routes: './src/endpoints/**/*.ts', // Glob pattern for endpoints
1187
+ envParser: './src/config/env#envParser',
1188
+ logger: './src/config/logger#logger',
1189
+ }
1190
+ ```
1191
+
1192
+ These apps use `gkm build --provider server` internally to generate a Hono server from discovered endpoints.
1193
+
1194
+ #### Entry-Based Backend Apps
1195
+
1196
+ Apps with a custom entry point (like authentication services using better-auth):
1197
+
1198
+ ```typescript
1199
+ auth: {
1200
+ type: 'backend',
1201
+ path: 'apps/auth',
1202
+ port: 3002,
1203
+ entry: './src/index.ts', // Direct entry point
1204
+ envParser: './src/config/env#envParser',
1205
+ logger: './src/config/logger#logger',
1206
+ }
1207
+ ```
1208
+
1209
+ Entry-based apps are bundled directly with esbuild into a standalone file. All dependencies are bundled, producing a single `index.mjs` file that runs without `node_modules`.
1210
+
1211
+ Example entry point for an auth service:
1212
+
1213
+ ```typescript
1214
+ // apps/auth/src/index.ts
1215
+ import { Hono } from 'hono';
1216
+ import { serve } from '@hono/node-server';
1217
+ import { auth } from './auth.js';
1218
+
1219
+ const app = new Hono();
1220
+
1221
+ app.get('/health', (c) => c.json({ status: 'ok' }));
1222
+ app.on(['POST', 'GET'], '/api/auth/*', (c) => auth.handler(c.req.raw));
1223
+
1224
+ serve({ fetch: app.fetch, port: 3002 });
1225
+ ```
1226
+
1227
+ #### Frontend Apps
1228
+
1229
+ Next.js or other frontend frameworks:
1230
+
1231
+ ```typescript
1232
+ web: {
1233
+ type: 'frontend',
1234
+ framework: 'nextjs',
1235
+ path: 'apps/web',
1236
+ port: 3001,
1237
+ dependencies: ['api', 'auth'], // Apps this depends on
1238
+ client: {
1239
+ output: './src/api', // Where to generate API client
1240
+ },
1241
+ }
1242
+ ```
1243
+
1244
+ ### Workspace Docker Generation
1245
+
1246
+ When running `gkm docker` in a workspace, the CLI generates optimized Dockerfiles for each app:
1247
+
1248
+ ```bash
1249
+ gkm docker
1250
+ ```
1251
+
1252
+ **Generated files:**
1253
+ - `.gkm/docker/Dockerfile.api` - Routes-based backend (uses `gkm build`)
1254
+ - `.gkm/docker/Dockerfile.auth` - Entry-based backend (uses esbuild bundling)
1255
+ - `.gkm/docker/Dockerfile.web` - Next.js standalone output
1256
+ - `.gkm/docker/docker-compose.yml` - Full stack with all apps and services
1257
+ - `.dockerignore` - Optimized ignore patterns
1258
+
1259
+ **Dockerfile types by app:**
1260
+
1261
+ | App Type | Build Method | Output |
1262
+ |----------|--------------|--------|
1263
+ | `routes` backend | `gkm build --provider server` | `.gkm/server/dist/server.mjs` |
1264
+ | `entry` backend | `esbuild --bundle --packages=bundle` | `dist/index.mjs` |
1265
+ | `nextjs` frontend | `next build` (standalone) | `.next/standalone` |
1266
+
1267
+ **Entry-based bundling:**
1268
+
1269
+ Entry-based apps use esbuild with full dependency bundling:
1270
+
1271
+ ```bash
1272
+ npx esbuild ./src/index.ts \
1273
+ --bundle \
1274
+ --platform=node \
1275
+ --target=node22 \
1276
+ --format=esm \
1277
+ --outfile=dist/index.mjs \
1278
+ --packages=bundle \
1279
+ --banner:js='import { createRequire } from "module"; const require = createRequire(import.meta.url);'
1280
+ ```
1281
+
1282
+ The `--packages=bundle` flag bundles all dependencies (unlike tsdown's default behavior). The banner adds CommonJS compatibility for packages that use `require()` internally.
1283
+
1284
+ ### Workspace Interface
1285
+
1286
+ ```typescript
1287
+ interface WorkspaceConfig {
1288
+ name: string;
1289
+ apps: Record<string, AppConfig>;
1290
+ shared?: {
1291
+ packages?: string[];
1292
+ models?: {
1293
+ path: string;
1294
+ schema: 'zod' | 'valibot';
1295
+ };
1296
+ };
1297
+ services?: {
1298
+ db?: boolean;
1299
+ cache?: boolean;
1300
+ mail?: boolean;
1301
+ };
1302
+ deploy?: {
1303
+ default?: 'dokploy' | 'docker';
1304
+ };
1305
+ }
1306
+
1307
+ interface BackendAppConfig {
1308
+ type: 'backend';
1309
+ path: string;
1310
+ port: number;
1311
+ routes?: string; // Glob pattern for routes-based apps
1312
+ entry?: string; // Entry file for entry-based apps
1313
+ envParser: string;
1314
+ logger: string;
1315
+ telescope?: TelescopeConfig;
1316
+ openapi?: { enabled: boolean };
1317
+ }
1318
+
1319
+ interface FrontendAppConfig {
1320
+ type: 'frontend';
1321
+ framework: 'nextjs';
1322
+ path: string;
1323
+ port: number;
1324
+ dependencies?: string[]; // Other apps this depends on
1325
+ client?: {
1326
+ output: string; // Where to generate typed API client
1327
+ };
1328
+ }
1329
+
1330
+ type AppConfig = BackendAppConfig | FrontendAppConfig;
1331
+ ```
1332
+
1112
1333
  ## Providers
1113
1334
 
1114
1335
  ### AWS API Gateway v1
package/dist/index.cjs CHANGED
@@ -29,7 +29,7 @@ const node_module = require_chunk.__toESM(require("node:module"));
29
29
 
30
30
  //#region package.json
31
31
  var name = "@geekmidas/cli";
32
- var version = "0.41.0";
32
+ var version = "0.44.0";
33
33
  var description = "CLI tools for building Lambda handlers, server applications, and generating OpenAPI specs";
34
34
  var private$1 = false;
35
35
  var type = "module";
@@ -1625,7 +1625,8 @@ async function prepareEntryCredentials(options) {
1625
1625
  credentials.PORT = String(resolvedPort);
1626
1626
  const secretsDir = (0, node_path.join)(secretsRoot, ".gkm");
1627
1627
  await (0, node_fs_promises.mkdir)(secretsDir, { recursive: true });
1628
- const secretsJsonPath = (0, node_path.join)(secretsDir, "dev-secrets.json");
1628
+ const secretsFileName = appName ? `dev-secrets-${appName}.json` : "dev-secrets.json";
1629
+ const secretsJsonPath = (0, node_path.join)(secretsDir, secretsFileName);
1629
1630
  await (0, node_fs_promises.writeFile)(secretsJsonPath, JSON.stringify(credentials, null, 2));
1630
1631
  return {
1631
1632
  credentials,
@@ -3224,7 +3225,7 @@ CMD ["node", "server.mjs"]
3224
3225
  }
3225
3226
  /**
3226
3227
  * Generate a Dockerfile for apps with a custom entry point.
3227
- * Uses tsdown to bundle the entry point into dist/index.mjs.
3228
+ * Uses esbuild to bundle the entry point into dist/index.mjs with all dependencies.
3228
3229
  * This is used for apps that don't use gkm routes (e.g., Better Auth servers).
3229
3230
  * @internal Exported for testing
3230
3231
  */
@@ -3287,17 +3288,22 @@ RUN if [ -n "$GKM_ENCRYPTED_CREDENTIALS" ]; then \
3287
3288
  echo "$GKM_CREDENTIALS_IV" > ${appPath}/.gkm/credentials.iv; \
3288
3289
  fi
3289
3290
 
3290
- # Bundle entry point with tsdown (outputs to dist/index.mjs)
3291
+ # Bundle entry point with esbuild (outputs to dist/index.mjs)
3292
+ # Creates a fully standalone bundle with all dependencies included
3291
3293
  # Use define to embed credentials if present
3292
3294
  RUN cd ${appPath} && \
3293
3295
  if [ -f .gkm/credentials.enc ]; then \
3294
3296
  CREDS=$(cat .gkm/credentials.enc) && \
3295
3297
  IV=$(cat .gkm/credentials.iv) && \
3296
- npx tsdown ${entry} --outDir dist --format esm \
3297
- --define __GKM_ENCRYPTED_CREDENTIALS__="'\\"$CREDS\\"'" \
3298
- --define __GKM_CREDENTIALS_IV__="'\\"$IV\\"'"; \
3298
+ npx esbuild ${entry} --bundle --platform=node --target=node22 --format=esm \
3299
+ --outfile=dist/index.mjs --packages=bundle \
3300
+ --banner:js='import { createRequire } from "module"; const require = createRequire(import.meta.url);' \
3301
+ --define:__GKM_ENCRYPTED_CREDENTIALS__="'\\"$CREDS\\"'" \
3302
+ --define:__GKM_CREDENTIALS_IV__="'\\"$IV\\"'"; \
3299
3303
  else \
3300
- npx tsdown ${entry} --outDir dist --format esm; \
3304
+ npx esbuild ${entry} --bundle --platform=node --target=node22 --format=esm \
3305
+ --outfile=dist/index.mjs --packages=bundle \
3306
+ --banner:js='import { createRequire } from "module"; const require = createRequire(import.meta.url);'; \
3301
3307
  fi
3302
3308
 
3303
3309
  # Stage 4: Production
@@ -6244,6 +6250,7 @@ export default defineWorkspace({
6244
6250
  type: 'backend',
6245
6251
  path: 'apps/auth',
6246
6252
  port: 3002,
6253
+ entry: './src/index.ts',
6247
6254
  envParser: './src/config/env#envParser',
6248
6255
  logger: './src/config/logger#logger',
6249
6256
  },
@@ -6557,12 +6564,14 @@ const minimalTemplate = {
6557
6564
  "@geekmidas/schema": GEEKMIDAS_VERSIONS["@geekmidas/schema"],
6558
6565
  "@hono/node-server": "~1.14.1",
6559
6566
  hono: "~4.8.2",
6560
- pino: "~9.6.0"
6567
+ pino: "~9.6.0",
6568
+ zod: "~4.1.0"
6561
6569
  },
6562
6570
  devDependencies: {
6563
6571
  "@biomejs/biome": "~2.3.0",
6564
6572
  "@geekmidas/cli": GEEKMIDAS_VERSIONS["@geekmidas/cli"],
6565
6573
  "@types/node": "~22.0.0",
6574
+ esbuild: "~0.27.0",
6566
6575
  tsx: "~4.20.0",
6567
6576
  turbo: "~2.3.0",
6568
6577
  typescript: "~5.8.2",