@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.
- package/dist/{bundler-C74EKlNa.cjs → bundler-CyHg1v_T.cjs} +3 -3
- package/dist/{bundler-C74EKlNa.cjs.map → bundler-CyHg1v_T.cjs.map} +1 -1
- package/dist/{bundler-B6z6HEeh.mjs → bundler-DQIuE3Kn.mjs} +3 -3
- package/dist/{bundler-B6z6HEeh.mjs.map → bundler-DQIuE3Kn.mjs.map} +1 -1
- package/dist/{config-DYULeEv8.mjs → config-BaYqrF3n.mjs} +48 -10
- package/dist/config-BaYqrF3n.mjs.map +1 -0
- package/dist/{config-AmInkU7k.cjs → config-CxrLu8ia.cjs} +53 -9
- package/dist/config-CxrLu8ia.cjs.map +1 -0
- package/dist/config.cjs +4 -1
- package/dist/config.d.cts +27 -2
- package/dist/config.d.cts.map +1 -1
- package/dist/config.d.mts +27 -2
- package/dist/config.d.mts.map +1 -1
- package/dist/config.mjs +3 -2
- package/dist/dokploy-api-B0w17y4_.mjs +3 -0
- package/dist/{dokploy-api-CaETb2L6.mjs → dokploy-api-B9qR2Yn1.mjs} +1 -1
- package/dist/{dokploy-api-CaETb2L6.mjs.map → dokploy-api-B9qR2Yn1.mjs.map} +1 -1
- package/dist/dokploy-api-BnGeUqN4.cjs +3 -0
- package/dist/{dokploy-api-C7F9VykY.cjs → dokploy-api-C5czOZoc.cjs} +1 -1
- package/dist/{dokploy-api-C7F9VykY.cjs.map → dokploy-api-C5czOZoc.cjs.map} +1 -1
- package/dist/{encryption-D7Efcdi9.cjs → encryption-BAz0xQ1Q.cjs} +1 -1
- package/dist/{encryption-D7Efcdi9.cjs.map → encryption-BAz0xQ1Q.cjs.map} +1 -1
- package/dist/{encryption-h4Nb6W-M.mjs → encryption-JtMsiGNp.mjs} +2 -2
- package/dist/{encryption-h4Nb6W-M.mjs.map → encryption-JtMsiGNp.mjs.map} +1 -1
- package/dist/index-CWN-bgrO.d.mts +495 -0
- package/dist/index-CWN-bgrO.d.mts.map +1 -0
- package/dist/index-DEWYvYvg.d.cts +495 -0
- package/dist/index-DEWYvYvg.d.cts.map +1 -0
- package/dist/index.cjs +2639 -563
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +2634 -563
- package/dist/index.mjs.map +1 -1
- package/dist/{openapi-CZVcfxk-.mjs → openapi-CgqR6Jkw.mjs} +3 -3
- package/dist/{openapi-CZVcfxk-.mjs.map → openapi-CgqR6Jkw.mjs.map} +1 -1
- package/dist/{openapi-C89hhkZC.cjs → openapi-DfpxS0xv.cjs} +8 -2
- package/dist/{openapi-C89hhkZC.cjs.map → openapi-DfpxS0xv.cjs.map} +1 -1
- package/dist/{openapi-react-query-CM2_qlW9.mjs → openapi-react-query-5rSortLH.mjs} +1 -1
- package/dist/{openapi-react-query-CM2_qlW9.mjs.map → openapi-react-query-5rSortLH.mjs.map} +1 -1
- package/dist/{openapi-react-query-iKjfLzff.cjs → openapi-react-query-DvNpdDpM.cjs} +1 -1
- package/dist/{openapi-react-query-iKjfLzff.cjs.map → openapi-react-query-DvNpdDpM.cjs.map} +1 -1
- package/dist/openapi-react-query.cjs +1 -1
- package/dist/openapi-react-query.mjs +1 -1
- package/dist/openapi.cjs +3 -2
- package/dist/openapi.d.cts +1 -1
- package/dist/openapi.d.mts +1 -1
- package/dist/openapi.mjs +3 -2
- package/dist/{storage-Bn3K9Ccu.cjs → storage-BPRgh3DU.cjs} +136 -5
- package/dist/storage-BPRgh3DU.cjs.map +1 -0
- package/dist/{storage-nkGIjeXt.mjs → storage-DNj_I11J.mjs} +1 -1
- package/dist/storage-Dhst7BhI.mjs +272 -0
- package/dist/storage-Dhst7BhI.mjs.map +1 -0
- package/dist/{storage-UfyTn7Zm.cjs → storage-fOR8dMu5.cjs} +1 -1
- package/dist/{types-iFk5ms7y.d.mts → types-K2uQJ-FO.d.mts} +2 -2
- package/dist/{types-BgaMXsUa.d.cts.map → types-K2uQJ-FO.d.mts.map} +1 -1
- package/dist/{types-BgaMXsUa.d.cts → types-l53qUmGt.d.cts} +2 -2
- package/dist/{types-iFk5ms7y.d.mts.map → types-l53qUmGt.d.cts.map} +1 -1
- package/dist/workspace/index.cjs +19 -0
- package/dist/workspace/index.d.cts +3 -0
- package/dist/workspace/index.d.mts +3 -0
- package/dist/workspace/index.mjs +3 -0
- package/dist/workspace-CPLEZDZf.mjs +3788 -0
- package/dist/workspace-CPLEZDZf.mjs.map +1 -0
- package/dist/workspace-iWgBlX6h.cjs +3885 -0
- package/dist/workspace-iWgBlX6h.cjs.map +1 -0
- package/package.json +8 -3
- package/src/build/__tests__/workspace-build.spec.ts +215 -0
- package/src/build/index.ts +189 -1
- package/src/config.ts +71 -14
- package/src/deploy/__tests__/docker.spec.ts +1 -1
- package/src/deploy/__tests__/index.spec.ts +305 -1
- package/src/deploy/index.ts +426 -4
- package/src/deploy/types.ts +32 -0
- package/src/dev/__tests__/index.spec.ts +572 -1
- package/src/dev/index.ts +582 -2
- package/src/docker/__tests__/compose.spec.ts +425 -0
- package/src/docker/__tests__/templates.spec.ts +145 -0
- package/src/docker/compose.ts +248 -0
- package/src/docker/index.ts +159 -3
- package/src/docker/templates.ts +219 -4
- package/src/index.ts +24 -0
- package/src/init/__tests__/generators.spec.ts +17 -24
- package/src/init/__tests__/init.spec.ts +157 -5
- package/src/init/generators/auth.ts +220 -0
- package/src/init/generators/config.ts +61 -4
- package/src/init/generators/docker.ts +115 -8
- package/src/init/generators/env.ts +7 -127
- package/src/init/generators/index.ts +1 -0
- package/src/init/generators/models.ts +3 -1
- package/src/init/generators/monorepo.ts +154 -10
- package/src/init/generators/package.ts +5 -3
- package/src/init/generators/web.ts +213 -0
- package/src/init/index.ts +290 -58
- package/src/init/templates/api.ts +38 -29
- package/src/init/templates/index.ts +132 -4
- package/src/init/templates/minimal.ts +33 -35
- package/src/init/templates/serverless.ts +16 -19
- package/src/init/templates/worker.ts +50 -25
- package/src/init/versions.ts +47 -0
- package/src/secrets/keystore.ts +144 -0
- package/src/secrets/storage.ts +109 -6
- package/src/test/index.ts +97 -0
- package/src/workspace/__tests__/client-generator.spec.ts +357 -0
- package/src/workspace/__tests__/index.spec.ts +543 -0
- package/src/workspace/__tests__/schema.spec.ts +519 -0
- package/src/workspace/__tests__/type-inference.spec.ts +251 -0
- package/src/workspace/client-generator.ts +307 -0
- package/src/workspace/index.ts +372 -0
- package/src/workspace/schema.ts +368 -0
- package/src/workspace/types.ts +336 -0
- package/tsconfig.tsbuildinfo +1 -1
- package/tsdown.config.ts +1 -0
- package/dist/config-AmInkU7k.cjs.map +0 -1
- package/dist/config-DYULeEv8.mjs.map +0 -1
- package/dist/dokploy-api-B7KxOQr3.cjs +0 -3
- package/dist/dokploy-api-DHvfmWbi.mjs +0 -3
- package/dist/storage-BaOP55oq.mjs +0 -147
- package/dist/storage-BaOP55oq.mjs.map +0 -1
- 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
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
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 (.
|
|
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
|
-
|
|
15
|
+
_template: TemplateConfig,
|
|
13
16
|
): GeneratedFile[] {
|
|
14
|
-
const
|
|
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
|
|
@@ -42,10 +42,12 @@ export function generateModelsPackage(
|
|
|
42
42
|
},
|
|
43
43
|
};
|
|
44
44
|
|
|
45
|
-
// tsconfig.json for models -
|
|
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': '~
|
|
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/
|
|
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
|
-
|
|
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'] =
|
|
25
|
+
dependencies['@geekmidas/telescope'] =
|
|
26
|
+
GEEKMIDAS_VERSIONS['@geekmidas/telescope'];
|
|
25
27
|
}
|
|
26
28
|
|
|
27
29
|
if (studio) {
|
|
28
|
-
dependencies['@geekmidas/studio'] = '
|
|
30
|
+
dependencies['@geekmidas/studio'] = GEEKMIDAS_VERSIONS['@geekmidas/studio'];
|
|
29
31
|
}
|
|
30
32
|
|
|
31
33
|
if (database) {
|
|
32
|
-
dependencies['@geekmidas/db'] = '
|
|
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';
|