@geekmidas/cli 0.18.0 → 0.19.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 (118) hide show
  1. package/dist/{bundler-C74EKlNa.cjs → bundler-CyHg1v_T.cjs} +3 -3
  2. package/dist/{bundler-C74EKlNa.cjs.map → bundler-CyHg1v_T.cjs.map} +1 -1
  3. package/dist/{bundler-B6z6HEeh.mjs → bundler-DQIuE3Kn.mjs} +3 -3
  4. package/dist/{bundler-B6z6HEeh.mjs.map → bundler-DQIuE3Kn.mjs.map} +1 -1
  5. package/dist/{config-DYULeEv8.mjs → config-BaYqrF3n.mjs} +48 -10
  6. package/dist/config-BaYqrF3n.mjs.map +1 -0
  7. package/dist/{config-AmInkU7k.cjs → config-CxrLu8ia.cjs} +53 -9
  8. package/dist/config-CxrLu8ia.cjs.map +1 -0
  9. package/dist/config.cjs +4 -1
  10. package/dist/config.d.cts +27 -2
  11. package/dist/config.d.cts.map +1 -1
  12. package/dist/config.d.mts +27 -2
  13. package/dist/config.d.mts.map +1 -1
  14. package/dist/config.mjs +3 -2
  15. package/dist/dokploy-api-B0w17y4_.mjs +3 -0
  16. package/dist/{dokploy-api-CaETb2L6.mjs → dokploy-api-B9qR2Yn1.mjs} +1 -1
  17. package/dist/{dokploy-api-CaETb2L6.mjs.map → dokploy-api-B9qR2Yn1.mjs.map} +1 -1
  18. package/dist/dokploy-api-BnGeUqN4.cjs +3 -0
  19. package/dist/{dokploy-api-C7F9VykY.cjs → dokploy-api-C5czOZoc.cjs} +1 -1
  20. package/dist/{dokploy-api-C7F9VykY.cjs.map → dokploy-api-C5czOZoc.cjs.map} +1 -1
  21. package/dist/{encryption-D7Efcdi9.cjs → encryption-BAz0xQ1Q.cjs} +1 -1
  22. package/dist/{encryption-D7Efcdi9.cjs.map → encryption-BAz0xQ1Q.cjs.map} +1 -1
  23. package/dist/{encryption-h4Nb6W-M.mjs → encryption-JtMsiGNp.mjs} +2 -2
  24. package/dist/{encryption-h4Nb6W-M.mjs.map → encryption-JtMsiGNp.mjs.map} +1 -1
  25. package/dist/index-CWN-bgrO.d.mts +495 -0
  26. package/dist/index-CWN-bgrO.d.mts.map +1 -0
  27. package/dist/index-DEWYvYvg.d.cts +495 -0
  28. package/dist/index-DEWYvYvg.d.cts.map +1 -0
  29. package/dist/index.cjs +2639 -563
  30. package/dist/index.cjs.map +1 -1
  31. package/dist/index.mjs +2634 -563
  32. package/dist/index.mjs.map +1 -1
  33. package/dist/{openapi-CZVcfxk-.mjs → openapi-CgqR6Jkw.mjs} +3 -3
  34. package/dist/{openapi-CZVcfxk-.mjs.map → openapi-CgqR6Jkw.mjs.map} +1 -1
  35. package/dist/{openapi-C89hhkZC.cjs → openapi-DfpxS0xv.cjs} +8 -2
  36. package/dist/{openapi-C89hhkZC.cjs.map → openapi-DfpxS0xv.cjs.map} +1 -1
  37. package/dist/{openapi-react-query-CM2_qlW9.mjs → openapi-react-query-5rSortLH.mjs} +1 -1
  38. package/dist/{openapi-react-query-CM2_qlW9.mjs.map → openapi-react-query-5rSortLH.mjs.map} +1 -1
  39. package/dist/{openapi-react-query-iKjfLzff.cjs → openapi-react-query-DvNpdDpM.cjs} +1 -1
  40. package/dist/{openapi-react-query-iKjfLzff.cjs.map → openapi-react-query-DvNpdDpM.cjs.map} +1 -1
  41. package/dist/openapi-react-query.cjs +1 -1
  42. package/dist/openapi-react-query.mjs +1 -1
  43. package/dist/openapi.cjs +3 -2
  44. package/dist/openapi.d.cts +1 -1
  45. package/dist/openapi.d.mts +1 -1
  46. package/dist/openapi.mjs +3 -2
  47. package/dist/{storage-Bn3K9Ccu.cjs → storage-BPRgh3DU.cjs} +136 -5
  48. package/dist/storage-BPRgh3DU.cjs.map +1 -0
  49. package/dist/{storage-nkGIjeXt.mjs → storage-DNj_I11J.mjs} +1 -1
  50. package/dist/storage-Dhst7BhI.mjs +272 -0
  51. package/dist/storage-Dhst7BhI.mjs.map +1 -0
  52. package/dist/{storage-UfyTn7Zm.cjs → storage-fOR8dMu5.cjs} +1 -1
  53. package/dist/{types-iFk5ms7y.d.mts → types-K2uQJ-FO.d.mts} +2 -2
  54. package/dist/{types-BgaMXsUa.d.cts.map → types-K2uQJ-FO.d.mts.map} +1 -1
  55. package/dist/{types-BgaMXsUa.d.cts → types-l53qUmGt.d.cts} +2 -2
  56. package/dist/{types-iFk5ms7y.d.mts.map → types-l53qUmGt.d.cts.map} +1 -1
  57. package/dist/workspace/index.cjs +19 -0
  58. package/dist/workspace/index.d.cts +3 -0
  59. package/dist/workspace/index.d.mts +3 -0
  60. package/dist/workspace/index.mjs +3 -0
  61. package/dist/workspace-CPLEZDZf.mjs +3788 -0
  62. package/dist/workspace-CPLEZDZf.mjs.map +1 -0
  63. package/dist/workspace-iWgBlX6h.cjs +3885 -0
  64. package/dist/workspace-iWgBlX6h.cjs.map +1 -0
  65. package/package.json +8 -3
  66. package/src/build/__tests__/workspace-build.spec.ts +215 -0
  67. package/src/build/index.ts +189 -1
  68. package/src/config.ts +71 -14
  69. package/src/deploy/__tests__/docker.spec.ts +1 -1
  70. package/src/deploy/__tests__/index.spec.ts +305 -1
  71. package/src/deploy/index.ts +426 -4
  72. package/src/deploy/types.ts +32 -0
  73. package/src/dev/__tests__/index.spec.ts +572 -1
  74. package/src/dev/index.ts +582 -2
  75. package/src/docker/__tests__/compose.spec.ts +425 -0
  76. package/src/docker/__tests__/templates.spec.ts +145 -0
  77. package/src/docker/compose.ts +248 -0
  78. package/src/docker/index.ts +159 -3
  79. package/src/docker/templates.ts +219 -4
  80. package/src/index.ts +24 -0
  81. package/src/init/__tests__/generators.spec.ts +17 -24
  82. package/src/init/__tests__/init.spec.ts +157 -5
  83. package/src/init/generators/auth.ts +220 -0
  84. package/src/init/generators/config.ts +61 -4
  85. package/src/init/generators/docker.ts +115 -8
  86. package/src/init/generators/env.ts +7 -127
  87. package/src/init/generators/index.ts +1 -0
  88. package/src/init/generators/models.ts +3 -1
  89. package/src/init/generators/monorepo.ts +154 -10
  90. package/src/init/generators/package.ts +5 -3
  91. package/src/init/generators/web.ts +213 -0
  92. package/src/init/index.ts +290 -58
  93. package/src/init/templates/api.ts +38 -29
  94. package/src/init/templates/index.ts +132 -4
  95. package/src/init/templates/minimal.ts +33 -35
  96. package/src/init/templates/serverless.ts +16 -19
  97. package/src/init/templates/worker.ts +50 -25
  98. package/src/init/versions.ts +47 -0
  99. package/src/secrets/keystore.ts +144 -0
  100. package/src/secrets/storage.ts +109 -6
  101. package/src/test/index.ts +97 -0
  102. package/src/workspace/__tests__/client-generator.spec.ts +357 -0
  103. package/src/workspace/__tests__/index.spec.ts +543 -0
  104. package/src/workspace/__tests__/schema.spec.ts +519 -0
  105. package/src/workspace/__tests__/type-inference.spec.ts +251 -0
  106. package/src/workspace/client-generator.ts +307 -0
  107. package/src/workspace/index.ts +372 -0
  108. package/src/workspace/schema.ts +368 -0
  109. package/src/workspace/types.ts +336 -0
  110. package/tsconfig.tsbuildinfo +1 -1
  111. package/tsdown.config.ts +1 -0
  112. package/dist/config-AmInkU7k.cjs.map +0 -1
  113. package/dist/config-DYULeEv8.mjs.map +0 -1
  114. package/dist/dokploy-api-B7KxOQr3.cjs +0 -3
  115. package/dist/dokploy-api-DHvfmWbi.mjs +0 -3
  116. package/dist/storage-BaOP55oq.mjs +0 -147
  117. package/dist/storage-BaOP55oq.mjs.map +0 -1
  118. package/dist/storage-Bn3K9Ccu.cjs.map +0 -1
@@ -4,26 +4,47 @@ import type {
4
4
  TemplateOptions,
5
5
  } from '../templates/index.js';
6
6
 
7
+ export interface DatabaseAppConfig {
8
+ name: string;
9
+ password: string;
10
+ }
11
+
7
12
  /**
8
13
  * Generate docker-compose.yml based on template and options
9
14
  */
10
15
  export function generateDockerFiles(
11
16
  options: TemplateOptions,
12
17
  template: TemplateConfig,
18
+ dbApps?: DatabaseAppConfig[],
13
19
  ): GeneratedFile[] {
14
20
  const { database } = options;
15
21
  const isServerless = template.name === 'serverless';
16
22
  const hasWorker = template.name === 'worker';
23
+ const isFullstack = options.template === 'fullstack';
17
24
 
18
25
  const services: string[] = [];
19
26
  const volumes: string[] = [];
27
+ const files: GeneratedFile[] = [];
20
28
 
21
29
  // PostgreSQL database
22
30
  if (database) {
31
+ const initVolume =
32
+ isFullstack && dbApps?.length
33
+ ? `
34
+ - ./docker/postgres/init.sh:/docker-entrypoint-initdb.d/init.sh:ro`
35
+ : '';
36
+
37
+ const envFile =
38
+ isFullstack && dbApps?.length
39
+ ? `
40
+ env_file:
41
+ - ./docker/.env`
42
+ : '';
43
+
23
44
  services.push(` postgres:
24
45
  image: postgres:16-alpine
25
46
  container_name: ${options.name}-postgres
26
- restart: unless-stopped
47
+ restart: unless-stopped${envFile}
27
48
  environment:
28
49
  POSTGRES_USER: postgres
29
50
  POSTGRES_PASSWORD: postgres
@@ -31,13 +52,27 @@ export function generateDockerFiles(
31
52
  ports:
32
53
  - '5432:5432'
33
54
  volumes:
34
- - postgres_data:/var/lib/postgresql/data
55
+ - postgres_data:/var/lib/postgresql/data${initVolume}
35
56
  healthcheck:
36
57
  test: ['CMD-SHELL', 'pg_isready -U postgres']
37
58
  interval: 5s
38
59
  timeout: 5s
39
60
  retries: 5`);
40
61
  volumes.push(' postgres_data:');
62
+
63
+ // Generate PostgreSQL init script and .env for fullstack template
64
+ if (isFullstack && dbApps?.length) {
65
+ files.push({
66
+ path: 'docker/postgres/init.sh',
67
+ content: generatePostgresInitScript(dbApps),
68
+ });
69
+
70
+ // Generate .env file for docker-compose (contains db passwords)
71
+ files.push({
72
+ path: 'docker/.env',
73
+ content: generateDockerEnv(dbApps),
74
+ });
75
+ }
41
76
  }
42
77
 
43
78
  // Redis - different setup for serverless vs standard
@@ -125,10 +160,82 @@ ${volumes.join('\n')}
125
160
  `;
126
161
  }
127
162
 
128
- return [
129
- {
130
- path: 'docker-compose.yml',
131
- content: dockerCompose,
132
- },
133
- ];
163
+ // Add docker-compose.yml to files
164
+ files.push({
165
+ path: 'docker-compose.yml',
166
+ content: dockerCompose,
167
+ });
168
+
169
+ return files;
170
+ }
171
+
172
+ /**
173
+ * Generate .env file for docker-compose with database passwords
174
+ */
175
+ function generateDockerEnv(apps: DatabaseAppConfig[]): string {
176
+ const envVars = apps.map((app) => {
177
+ const envVar = `${app.name.toUpperCase()}_DB_PASSWORD`;
178
+ return `${envVar}=${app.password}`;
179
+ });
180
+
181
+ return `# Auto-generated docker environment file
182
+ # Contains database passwords for docker-compose postgres init
183
+ # This file is gitignored - do not commit to version control
184
+ ${envVars.join('\n')}
185
+ `;
186
+ }
187
+
188
+ /**
189
+ * Generate PostgreSQL init shell script that creates per-app users with separate schemas
190
+ * Uses environment variables for passwords (more secure than hardcoded values)
191
+ * - api user: uses public schema
192
+ * - auth user: uses auth schema with search_path=auth
193
+ */
194
+ function generatePostgresInitScript(apps: DatabaseAppConfig[]): string {
195
+ const userCreations = apps.map((app) => {
196
+ const userName = app.name.replace(/-/g, '_');
197
+ const envVar = `${app.name.toUpperCase()}_DB_PASSWORD`;
198
+ const isApi = app.name === 'api';
199
+ const schemaName = isApi ? 'public' : userName;
200
+
201
+ if (isApi) {
202
+ // API user uses public schema
203
+ return `
204
+ # Create ${app.name} user (uses public schema)
205
+ echo "Creating user ${userName}..."
206
+ psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<-EOSQL
207
+ CREATE USER ${userName} WITH PASSWORD '$${envVar}';
208
+ GRANT ALL ON SCHEMA public TO ${userName};
209
+ ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON TABLES TO ${userName};
210
+ ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON SEQUENCES TO ${userName};
211
+ EOSQL
212
+ `;
213
+ }
214
+ // Other users get their own schema with search_path
215
+ return `
216
+ # Create ${app.name} user with dedicated schema
217
+ echo "Creating user ${userName} with schema ${schemaName}..."
218
+ psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<-EOSQL
219
+ CREATE USER ${userName} WITH PASSWORD '$${envVar}';
220
+ CREATE SCHEMA ${schemaName} AUTHORIZATION ${userName};
221
+ ALTER USER ${userName} SET search_path TO ${schemaName};
222
+ GRANT USAGE ON SCHEMA ${schemaName} TO ${userName};
223
+ GRANT ALL ON ALL TABLES IN SCHEMA ${schemaName} TO ${userName};
224
+ GRANT ALL ON ALL SEQUENCES IN SCHEMA ${schemaName} TO ${userName};
225
+ ALTER DEFAULT PRIVILEGES IN SCHEMA ${schemaName} GRANT ALL ON TABLES TO ${userName};
226
+ ALTER DEFAULT PRIVILEGES IN SCHEMA ${schemaName} GRANT ALL ON SEQUENCES TO ${userName};
227
+ EOSQL
228
+ `;
229
+ });
230
+
231
+ return `#!/bin/bash
232
+ set -e
233
+
234
+ # Auto-generated PostgreSQL init script
235
+ # Creates per-app users with separate schemas in a single database
236
+ # - api: uses public schema
237
+ # - auth: uses auth schema (search_path=auth)
238
+ ${userCreations.join('\n')}
239
+ echo "Database initialization complete!"
240
+ `;
134
241
  }
@@ -5,136 +5,16 @@ import type {
5
5
  } from '../templates/index.js';
6
6
 
7
7
  /**
8
- * Generate environment files (.env, .env.example, .env.development, .env.test, .gitignore)
8
+ * Generate environment-related files (.gitignore only).
9
+ * Note: .env files are no longer generated. Use `gkm secrets:init` to initialize
10
+ * encrypted secrets stored in `.gkm/secrets/{stage}.json` with keys stored at
11
+ * `~/.gkm/{project-name}/{stage}.key`.
9
12
  */
10
13
  export function generateEnvFiles(
11
14
  options: TemplateOptions,
12
- template: TemplateConfig,
15
+ _template: TemplateConfig,
13
16
  ): GeneratedFile[] {
14
- const { database } = options;
15
- const isServerless = template.name === 'serverless';
16
- const hasWorker = template.name === 'worker';
17
-
18
- // Build base env content
19
- let baseEnv = `# Application
20
- NODE_ENV=development
21
- PORT=3000
22
- LOG_LEVEL=info
23
- `;
24
-
25
- if (isServerless) {
26
- baseEnv = `# AWS
27
- STAGE=dev
28
- AWS_REGION=us-east-1
29
- LOG_LEVEL=info
30
- `;
31
- }
32
-
33
- if (database) {
34
- baseEnv += `
35
- # Database
36
- DATABASE_URL=postgresql://user:password@localhost:5432/mydb
37
- `;
38
- }
39
-
40
- if (hasWorker) {
41
- baseEnv += `
42
- # Message Queue
43
- RABBITMQ_URL=amqp://localhost:5672
44
- `;
45
- }
46
-
47
- baseEnv += `
48
- # Authentication
49
- JWT_SECRET=your-secret-key-change-in-production
50
- `;
51
-
52
- // Development env
53
- let devEnv = `# Development Environment
54
- NODE_ENV=development
55
- PORT=3000
56
- LOG_LEVEL=debug
57
- `;
58
-
59
- if (isServerless) {
60
- devEnv = `# Development Environment
61
- STAGE=dev
62
- AWS_REGION=us-east-1
63
- LOG_LEVEL=debug
64
- `;
65
- }
66
-
67
- if (database) {
68
- devEnv += `
69
- # Database
70
- DATABASE_URL=postgresql://postgres:postgres@localhost:5432/mydb_dev
71
- `;
72
- }
73
-
74
- if (hasWorker) {
75
- devEnv += `
76
- # Message Queue
77
- RABBITMQ_URL=amqp://localhost:5672
78
- `;
79
- }
80
-
81
- devEnv += `
82
- # Authentication
83
- JWT_SECRET=dev-secret-not-for-production
84
- `;
85
-
86
- // Test env
87
- let testEnv = `# Test Environment
88
- NODE_ENV=test
89
- PORT=3001
90
- LOG_LEVEL=error
91
- `;
92
-
93
- if (isServerless) {
94
- testEnv = `# Test Environment
95
- STAGE=test
96
- AWS_REGION=us-east-1
97
- LOG_LEVEL=error
98
- `;
99
- }
100
-
101
- if (database) {
102
- testEnv += `
103
- # Database
104
- DATABASE_URL=postgresql://postgres:postgres@localhost:5432/mydb_test
105
- `;
106
- }
107
-
108
- if (hasWorker) {
109
- testEnv += `
110
- # Message Queue
111
- RABBITMQ_URL=amqp://localhost:5672
112
- `;
113
- }
114
-
115
- testEnv += `
116
- # Authentication
117
- JWT_SECRET=test-secret-not-for-production
118
- `;
119
-
120
- const files: GeneratedFile[] = [
121
- {
122
- path: '.env.example',
123
- content: baseEnv,
124
- },
125
- {
126
- path: '.env',
127
- content: baseEnv,
128
- },
129
- {
130
- path: '.env.development',
131
- content: devEnv,
132
- },
133
- {
134
- path: '.env.test',
135
- content: testEnv,
136
- },
137
- ];
17
+ const files: GeneratedFile[] = [];
138
18
 
139
19
  // Only add .gitignore for non-monorepo (monorepo has it at root)
140
20
  if (!options.monorepo) {
@@ -145,7 +25,7 @@ node_modules/
145
25
  dist/
146
26
  .gkm/
147
27
 
148
- # Environment
28
+ # Environment (legacy - use gkm secrets instead)
149
29
  .env
150
30
  .env.local
151
31
  .env.*.local
@@ -1,3 +1,4 @@
1
+ export { generateAuthAppFiles } from './auth.js';
1
2
  export { generateConfigFiles } from './config.js';
2
3
  export { generateEnvFiles } from './env.js';
3
4
  export { generatePackageJson } from './package.js';
@@ -42,10 +42,12 @@ export function generateModelsPackage(
42
42
  },
43
43
  };
44
44
 
45
- // tsconfig.json for models - extends root
45
+ // tsconfig.json for models - library package that builds to dist
46
46
  const tsConfig = {
47
47
  extends: '../../tsconfig.json',
48
48
  compilerOptions: {
49
+ declaration: true,
50
+ declarationMap: true,
49
51
  outDir: './dist',
50
52
  rootDir: './src',
51
53
  },
@@ -3,6 +3,7 @@ import type {
3
3
  TemplateConfig,
4
4
  TemplateOptions,
5
5
  } from '../templates/index.js';
6
+ import { GEEKMIDAS_VERSIONS } from '../versions.js';
6
7
 
7
8
  /**
8
9
  * Generate monorepo root files (pnpm-workspace.yaml, root package.json, etc.)
@@ -15,24 +16,31 @@ export function generateMonorepoFiles(
15
16
  return [];
16
17
  }
17
18
 
19
+ const isFullstack = options.template === 'fullstack';
20
+
18
21
  // Root package.json for monorepo
19
22
  const rootPackageJson = {
20
23
  name: options.name,
21
24
  version: '0.0.1',
22
25
  private: true,
23
26
  type: 'module',
27
+ packageManager: 'pnpm@10.13.1',
24
28
  scripts: {
25
- dev: 'turbo dev',
26
- build: 'turbo build',
27
- test: 'turbo test',
28
- 'test:once': 'turbo test:once',
29
+ dev: isFullstack ? 'gkm dev' : 'turbo dev',
30
+ build: isFullstack ? 'gkm build' : 'turbo build',
31
+ test: isFullstack ? 'gkm test' : 'turbo test',
32
+ 'test:once': isFullstack ? 'gkm test --run' : 'turbo test:once',
29
33
  typecheck: 'turbo typecheck',
30
34
  lint: 'biome lint .',
31
35
  fmt: 'biome format . --write',
32
36
  'fmt:check': 'biome format .',
37
+ ...(options.deployTarget === 'dokploy'
38
+ ? { deploy: 'gkm deploy --provider dokploy --stage production' }
39
+ : {}),
33
40
  },
34
41
  devDependencies: {
35
- '@biomejs/biome': '~1.9.4',
42
+ '@biomejs/biome': '~2.3.0',
43
+ '@geekmidas/cli': GEEKMIDAS_VERSIONS['@geekmidas/cli'],
36
44
  turbo: '~2.3.0',
37
45
  typescript: '~5.8.2',
38
46
  vitest: '~4.0.0',
@@ -50,7 +58,7 @@ export function generateMonorepoFiles(
50
58
 
51
59
  // Root biome.json
52
60
  const biomeConfig = {
53
- $schema: 'https://biomejs.dev/schemas/1.9.4/schema.json',
61
+ $schema: 'https://biomejs.dev/schemas/2.3.0/schema.json',
54
62
  vcs: {
55
63
  enabled: true,
56
64
  clientKind: 'git',
@@ -136,6 +144,7 @@ dist/
136
144
  .env
137
145
  .env.local
138
146
  .env.*.local
147
+ docker/.env
139
148
 
140
149
  # IDE
141
150
  .idea/
@@ -164,6 +173,7 @@ coverage/
164
173
  `;
165
174
 
166
175
  // Root tsconfig.json - base config for all packages
176
+ // Using turbo typecheck to run tsc --noEmit in each app/package
167
177
  const tsConfig = {
168
178
  compilerOptions: {
169
179
  target: 'ES2022',
@@ -175,14 +185,29 @@ coverage/
175
185
  skipLibCheck: true,
176
186
  forceConsistentCasingInFileNames: true,
177
187
  resolveJsonModule: true,
178
- declaration: true,
179
- declarationMap: true,
180
- composite: true,
181
188
  },
182
189
  exclude: ['node_modules', 'dist'],
183
190
  };
184
191
 
185
- return [
192
+ // Vitest config for workspace
193
+ const vitestConfig = `import { defineConfig } from 'vitest/config';
194
+
195
+ export default defineConfig({
196
+ test: {
197
+ globals: true,
198
+ environment: 'node',
199
+ include: ['apps/**/*.{test,spec}.ts', 'packages/**/*.{test,spec}.ts'],
200
+ exclude: ['**/node_modules/**', '**/dist/**'],
201
+ coverage: {
202
+ provider: 'v8',
203
+ reporter: ['text', 'json', 'html'],
204
+ exclude: ['**/node_modules/**', '**/dist/**', '**/*.d.ts'],
205
+ },
206
+ },
207
+ });
208
+ `;
209
+
210
+ const files: GeneratedFile[] = [
186
211
  {
187
212
  path: 'package.json',
188
213
  content: `${JSON.stringify(rootPackageJson, null, 2)}\n`,
@@ -203,9 +228,128 @@ coverage/
203
228
  path: 'turbo.json',
204
229
  content: `${JSON.stringify(turboConfig, null, 2)}\n`,
205
230
  },
231
+ {
232
+ path: 'vitest.config.ts',
233
+ content: vitestConfig,
234
+ },
206
235
  {
207
236
  path: '.gitignore',
208
237
  content: gitignore,
209
238
  },
210
239
  ];
240
+
241
+ // Add workspace config for fullstack template
242
+ if (isFullstack) {
243
+ files.push({
244
+ path: 'gkm.config.ts',
245
+ content: generateWorkspaceConfig(options),
246
+ });
247
+ }
248
+
249
+ return files;
250
+ }
251
+
252
+ /**
253
+ * Generate gkm.config.ts with defineWorkspace for fullstack template
254
+ */
255
+ function generateWorkspaceConfig(options: TemplateOptions): string {
256
+ const { telescope, services, deployTarget, routesStructure } = options;
257
+
258
+ // Get routes glob pattern
259
+ const getRoutesGlob = (): string => {
260
+ switch (routesStructure) {
261
+ case 'centralized-endpoints':
262
+ return './src/endpoints/**/*.ts';
263
+ case 'centralized-routes':
264
+ return './src/routes/**/*.ts';
265
+ case 'domain-based':
266
+ return './src/**/routes/*.ts';
267
+ }
268
+ };
269
+
270
+ let config = `import { defineWorkspace } from '@geekmidas/cli/config';
271
+
272
+ export default defineWorkspace({
273
+ name: '${options.name}',
274
+ apps: {
275
+ api: {
276
+ type: 'backend',
277
+ path: 'apps/api',
278
+ port: 3000,
279
+ routes: '${getRoutesGlob()}',
280
+ envParser: './src/config/env#envParser',
281
+ logger: './src/config/logger#logger',`;
282
+
283
+ if (telescope) {
284
+ config += `
285
+ telescope: {
286
+ enabled: true,
287
+ path: '/__telescope',
288
+ },`;
289
+ }
290
+
291
+ config += `
292
+ openapi: {
293
+ enabled: true,
294
+ },
295
+ },
296
+ auth: {
297
+ type: 'backend',
298
+ path: 'apps/auth',
299
+ port: 3002,
300
+ envParser: './src/config/env#envParser',
301
+ logger: './src/config/logger#logger',
302
+ },
303
+ web: {
304
+ type: 'frontend',
305
+ framework: 'nextjs',
306
+ path: 'apps/web',
307
+ port: 3001,
308
+ dependencies: ['api', 'auth'],
309
+ client: {
310
+ output: './src/api',
311
+ },
312
+ },
313
+ },
314
+ shared: {
315
+ packages: ['packages/*'],
316
+ models: {
317
+ path: 'packages/models',
318
+ schema: 'zod',
319
+ },
320
+ },`;
321
+
322
+ // Add services if any are selected
323
+ if (services.db || services.cache || services.mail) {
324
+ config += `
325
+ services: {`;
326
+ if (services.db) {
327
+ config += `
328
+ db: true,`;
329
+ }
330
+ if (services.cache) {
331
+ config += `
332
+ cache: true,`;
333
+ }
334
+ if (services.mail) {
335
+ config += `
336
+ mail: true,`;
337
+ }
338
+ config += `
339
+ },`;
340
+ }
341
+
342
+ // Add deploy config if dokploy is selected
343
+ if (deployTarget === 'dokploy') {
344
+ config += `
345
+ deploy: {
346
+ default: 'dokploy',
347
+ },`;
348
+ }
349
+
350
+ config += `
351
+ });
352
+ `;
353
+
354
+ return config;
211
355
  }
@@ -4,6 +4,7 @@ import {
4
4
  type TemplateConfig,
5
5
  type TemplateOptions,
6
6
  } from '../templates/index.js';
7
+ import { GEEKMIDAS_VERSIONS } from '../versions.js';
7
8
 
8
9
  /**
9
10
  * Generate package.json with dependencies based on template and options
@@ -21,15 +22,16 @@ export function generatePackageJson(
21
22
 
22
23
  // Add optional dependencies based on user choices
23
24
  if (telescope) {
24
- dependencies['@geekmidas/telescope'] = 'workspace:*';
25
+ dependencies['@geekmidas/telescope'] =
26
+ GEEKMIDAS_VERSIONS['@geekmidas/telescope'];
25
27
  }
26
28
 
27
29
  if (studio) {
28
- dependencies['@geekmidas/studio'] = 'workspace:*';
30
+ dependencies['@geekmidas/studio'] = GEEKMIDAS_VERSIONS['@geekmidas/studio'];
29
31
  }
30
32
 
31
33
  if (database) {
32
- dependencies['@geekmidas/db'] = 'workspace:*';
34
+ dependencies['@geekmidas/db'] = GEEKMIDAS_VERSIONS['@geekmidas/db'];
33
35
  dependencies.kysely = '~0.28.2';
34
36
  dependencies.pg = '~8.16.0';
35
37
  devDependencies['@types/pg'] = '~8.15.0';