@geekmidas/cli 0.10.0 → 0.13.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 +525 -0
- package/dist/bundler-B1qy9b-j.cjs +112 -0
- package/dist/bundler-B1qy9b-j.cjs.map +1 -0
- package/dist/bundler-DskIqW2t.mjs +111 -0
- package/dist/bundler-DskIqW2t.mjs.map +1 -0
- package/dist/{config-C9aXOHBe.cjs → config-AmInkU7k.cjs} +8 -8
- package/dist/config-AmInkU7k.cjs.map +1 -0
- package/dist/{config-BrkUalUh.mjs → config-DYULeEv8.mjs} +3 -3
- package/dist/config-DYULeEv8.mjs.map +1 -0
- package/dist/config.cjs +1 -1
- package/dist/config.d.cts +1 -1
- package/dist/config.d.mts +1 -1
- package/dist/config.mjs +1 -1
- package/dist/encryption-C8H-38Yy.mjs +42 -0
- package/dist/encryption-C8H-38Yy.mjs.map +1 -0
- package/dist/encryption-Dyf_r1h-.cjs +44 -0
- package/dist/encryption-Dyf_r1h-.cjs.map +1 -0
- package/dist/index.cjs +2123 -179
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +2141 -192
- package/dist/index.mjs.map +1 -1
- package/dist/{openapi-CZLI4QTr.mjs → openapi-BfFlOBCG.mjs} +801 -38
- package/dist/openapi-BfFlOBCG.mjs.map +1 -0
- package/dist/{openapi-BeHLKcwP.cjs → openapi-Bt_1FDpT.cjs} +794 -31
- package/dist/openapi-Bt_1FDpT.cjs.map +1 -0
- package/dist/{openapi-react-query-o5iMi8tz.cjs → openapi-react-query-B-sNWHFU.cjs} +5 -5
- package/dist/openapi-react-query-B-sNWHFU.cjs.map +1 -0
- package/dist/{openapi-react-query-CcciaVu5.mjs → openapi-react-query-B6XTeGqS.mjs} +5 -5
- package/dist/openapi-react-query-B6XTeGqS.mjs.map +1 -0
- package/dist/openapi-react-query.cjs +1 -1
- package/dist/openapi-react-query.d.cts.map +1 -1
- package/dist/openapi-react-query.d.mts.map +1 -1
- package/dist/openapi-react-query.mjs +1 -1
- package/dist/openapi.cjs +2 -2
- package/dist/openapi.d.cts +1 -1
- package/dist/openapi.d.cts.map +1 -1
- package/dist/openapi.d.mts +1 -1
- package/dist/openapi.d.mts.map +1 -1
- package/dist/openapi.mjs +2 -2
- package/dist/storage-BOOpAF8N.cjs +5 -0
- package/dist/storage-Bj1E26lU.cjs +187 -0
- package/dist/storage-Bj1E26lU.cjs.map +1 -0
- package/dist/storage-kSxTjkNb.mjs +133 -0
- package/dist/storage-kSxTjkNb.mjs.map +1 -0
- package/dist/storage-tgZSUnKl.mjs +3 -0
- package/dist/{types-b-vwGpqc.d.cts → types-BR0M2v_c.d.mts} +100 -1
- package/dist/types-BR0M2v_c.d.mts.map +1 -0
- package/dist/{types-DXgiA1sF.d.mts → types-BhkZc-vm.d.cts} +100 -1
- package/dist/types-BhkZc-vm.d.cts.map +1 -0
- package/examples/cron-example.ts +27 -27
- package/examples/env.ts +27 -27
- package/examples/function-example.ts +31 -31
- package/examples/gkm.config.json +20 -20
- package/examples/gkm.config.ts +8 -8
- package/examples/gkm.minimal.config.json +5 -5
- package/examples/gkm.production.config.json +25 -25
- package/examples/logger.ts +2 -2
- package/package.json +6 -6
- package/src/__tests__/EndpointGenerator.hooks.spec.ts +191 -191
- package/src/__tests__/config.spec.ts +55 -55
- package/src/__tests__/loadEnvFiles.spec.ts +93 -93
- package/src/__tests__/normalizeHooksConfig.spec.ts +58 -58
- package/src/__tests__/openapi-react-query.spec.ts +497 -497
- package/src/__tests__/openapi.spec.ts +428 -428
- package/src/__tests__/test-helpers.ts +76 -76
- package/src/auth/__tests__/credentials.spec.ts +204 -0
- package/src/auth/__tests__/index.spec.ts +168 -0
- package/src/auth/credentials.ts +187 -0
- package/src/auth/index.ts +226 -0
- package/src/build/__tests__/bundler.spec.ts +444 -0
- package/src/build/__tests__/index-new.spec.ts +474 -474
- package/src/build/__tests__/manifests.spec.ts +333 -333
- package/src/build/bundler.ts +210 -0
- package/src/build/endpoint-analyzer.ts +236 -0
- package/src/build/handler-templates.ts +1253 -0
- package/src/build/index.ts +260 -179
- package/src/build/manifests.ts +52 -52
- package/src/build/providerResolver.ts +145 -145
- package/src/build/types.ts +64 -43
- package/src/config.ts +39 -39
- package/src/deploy/__tests__/docker.spec.ts +111 -0
- package/src/deploy/__tests__/dokploy.spec.ts +245 -0
- package/src/deploy/__tests__/init.spec.ts +662 -0
- package/src/deploy/docker.ts +128 -0
- package/src/deploy/dokploy.ts +204 -0
- package/src/deploy/index.ts +136 -0
- package/src/deploy/init.ts +484 -0
- package/src/deploy/types.ts +48 -0
- package/src/dev/__tests__/index.spec.ts +266 -266
- package/src/dev/index.ts +647 -601
- package/src/docker/__tests__/compose.spec.ts +531 -0
- package/src/docker/__tests__/templates.spec.ts +280 -0
- package/src/docker/compose.ts +273 -0
- package/src/docker/index.ts +230 -0
- package/src/docker/templates.ts +446 -0
- package/src/generators/CronGenerator.ts +72 -72
- package/src/generators/EndpointGenerator.ts +699 -398
- package/src/generators/FunctionGenerator.ts +84 -84
- package/src/generators/Generator.ts +72 -72
- package/src/generators/OpenApiTsGenerator.ts +577 -577
- package/src/generators/SubscriberGenerator.ts +124 -124
- package/src/generators/__tests__/CronGenerator.spec.ts +433 -433
- package/src/generators/__tests__/EndpointGenerator.spec.ts +532 -382
- package/src/generators/__tests__/FunctionGenerator.spec.ts +244 -244
- package/src/generators/__tests__/SubscriberGenerator.spec.ts +397 -382
- package/src/generators/index.ts +4 -4
- package/src/index.ts +623 -201
- package/src/init/__tests__/generators.spec.ts +334 -334
- package/src/init/__tests__/init.spec.ts +332 -332
- package/src/init/__tests__/utils.spec.ts +89 -89
- package/src/init/generators/config.ts +175 -175
- package/src/init/generators/docker.ts +41 -41
- package/src/init/generators/env.ts +72 -72
- package/src/init/generators/index.ts +1 -1
- package/src/init/generators/models.ts +64 -64
- package/src/init/generators/monorepo.ts +161 -161
- package/src/init/generators/package.ts +71 -71
- package/src/init/generators/source.ts +6 -6
- package/src/init/index.ts +203 -208
- package/src/init/templates/api.ts +115 -115
- package/src/init/templates/index.ts +75 -75
- package/src/init/templates/minimal.ts +98 -98
- package/src/init/templates/serverless.ts +89 -89
- package/src/init/templates/worker.ts +98 -98
- package/src/init/utils.ts +54 -56
- package/src/openapi-react-query.ts +194 -194
- package/src/openapi.ts +63 -63
- package/src/secrets/__tests__/encryption.spec.ts +226 -0
- package/src/secrets/__tests__/generator.spec.ts +319 -0
- package/src/secrets/__tests__/index.spec.ts +91 -0
- package/src/secrets/__tests__/storage.spec.ts +611 -0
- package/src/secrets/encryption.ts +91 -0
- package/src/secrets/generator.ts +164 -0
- package/src/secrets/index.ts +383 -0
- package/src/secrets/storage.ts +192 -0
- package/src/secrets/types.ts +53 -0
- package/src/types.ts +295 -176
- package/tsdown.config.ts +11 -8
- package/dist/config-BrkUalUh.mjs.map +0 -1
- package/dist/config-C9aXOHBe.cjs.map +0 -1
- package/dist/openapi-BeHLKcwP.cjs.map +0 -1
- package/dist/openapi-CZLI4QTr.mjs.map +0 -1
- package/dist/openapi-react-query-CcciaVu5.mjs.map +0 -1
- package/dist/openapi-react-query-o5iMi8tz.cjs.map +0 -1
- package/dist/types-DXgiA1sF.d.mts.map +0 -1
- package/dist/types-b-vwGpqc.d.cts.map +0 -1
package/src/index.ts
CHANGED
|
@@ -1,215 +1,637 @@
|
|
|
1
1
|
#!/usr/bin/env -S npx tsx
|
|
2
2
|
|
|
3
3
|
import { Command } from 'commander';
|
|
4
|
-
import pkg from '../package.json'
|
|
4
|
+
import pkg from '../package.json';
|
|
5
|
+
import { loginCommand, logoutCommand, whoamiCommand } from './auth';
|
|
5
6
|
import { buildCommand } from './build/index';
|
|
7
|
+
import { type DeployProvider, deployCommand } from './deploy/index';
|
|
8
|
+
import { deployInitCommand, deployListCommand } from './deploy/init';
|
|
6
9
|
import { devCommand } from './dev/index';
|
|
10
|
+
import { type DockerOptions, dockerCommand } from './docker/index';
|
|
7
11
|
import { type InitOptions, initCommand } from './init/index';
|
|
8
12
|
import { openapiCommand } from './openapi';
|
|
9
13
|
import { generateReactQueryCommand } from './openapi-react-query';
|
|
10
|
-
import
|
|
14
|
+
import {
|
|
15
|
+
secretsImportCommand,
|
|
16
|
+
secretsInitCommand,
|
|
17
|
+
secretsRotateCommand,
|
|
18
|
+
secretsSetCommand,
|
|
19
|
+
secretsShowCommand,
|
|
20
|
+
} from './secrets';
|
|
21
|
+
import type { ComposeServiceName, LegacyProvider, MainProvider } from './types';
|
|
11
22
|
|
|
12
23
|
const program = new Command();
|
|
13
24
|
|
|
14
25
|
program
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
program
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
26
|
+
.name('gkm')
|
|
27
|
+
.description('GeekMidas backend framework CLI')
|
|
28
|
+
.version(pkg.version)
|
|
29
|
+
.option('--cwd <path>', 'Change working directory');
|
|
30
|
+
|
|
31
|
+
program
|
|
32
|
+
.command('init')
|
|
33
|
+
.description('Scaffold a new project')
|
|
34
|
+
.argument('[name]', 'Project name')
|
|
35
|
+
.option(
|
|
36
|
+
'--template <template>',
|
|
37
|
+
'Project template (minimal, api, serverless, worker)',
|
|
38
|
+
)
|
|
39
|
+
.option('--skip-install', 'Skip dependency installation', false)
|
|
40
|
+
.option('-y, --yes', 'Skip prompts, use defaults', false)
|
|
41
|
+
.option('--monorepo', 'Setup as monorepo with packages/models', false)
|
|
42
|
+
.option('--api-path <path>', 'API app path in monorepo (default: apps/api)')
|
|
43
|
+
.action(async (name: string | undefined, options: InitOptions) => {
|
|
44
|
+
try {
|
|
45
|
+
const globalOptions = program.opts();
|
|
46
|
+
if (globalOptions.cwd) {
|
|
47
|
+
process.chdir(globalOptions.cwd);
|
|
48
|
+
}
|
|
49
|
+
await initCommand(name, options);
|
|
50
|
+
} catch (_error) {
|
|
51
|
+
process.exit(1);
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
program
|
|
56
|
+
.command('build')
|
|
57
|
+
.description('Build handlers from endpoints, functions, and crons')
|
|
58
|
+
.option(
|
|
59
|
+
'--provider <provider>',
|
|
60
|
+
'Target provider for generated handlers (aws, server)',
|
|
61
|
+
)
|
|
62
|
+
.option(
|
|
63
|
+
'--providers <providers>',
|
|
64
|
+
'[DEPRECATED] Use --provider instead. Target providers for generated handlers (comma-separated)',
|
|
65
|
+
)
|
|
66
|
+
.option(
|
|
67
|
+
'--enable-openapi',
|
|
68
|
+
'Enable OpenAPI documentation generation for server builds',
|
|
69
|
+
)
|
|
70
|
+
.option('--production', 'Build for production (no dev tools, bundled output)')
|
|
71
|
+
.option('--skip-bundle', 'Skip bundling step in production build')
|
|
72
|
+
.option('--stage <stage>', 'Inject encrypted secrets for deployment stage')
|
|
73
|
+
.action(
|
|
74
|
+
async (options: {
|
|
75
|
+
provider?: string;
|
|
76
|
+
providers?: string;
|
|
77
|
+
enableOpenapi?: boolean;
|
|
78
|
+
production?: boolean;
|
|
79
|
+
skipBundle?: boolean;
|
|
80
|
+
stage?: string;
|
|
81
|
+
}) => {
|
|
82
|
+
try {
|
|
83
|
+
const globalOptions = program.opts();
|
|
84
|
+
if (globalOptions.cwd) {
|
|
85
|
+
process.chdir(globalOptions.cwd);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Handle new single provider option
|
|
89
|
+
if (options.provider) {
|
|
90
|
+
if (!['aws', 'server'].includes(options.provider)) {
|
|
91
|
+
process.exit(1);
|
|
92
|
+
}
|
|
93
|
+
await buildCommand({
|
|
94
|
+
provider: options.provider as MainProvider,
|
|
95
|
+
enableOpenApi: options.enableOpenapi || false,
|
|
96
|
+
production: options.production || false,
|
|
97
|
+
skipBundle: options.skipBundle || false,
|
|
98
|
+
stage: options.stage,
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
// Handle legacy providers option
|
|
102
|
+
else if (options.providers) {
|
|
103
|
+
const providerList = [
|
|
104
|
+
...new Set(options.providers.split(',').map((p) => p.trim())),
|
|
105
|
+
] as LegacyProvider[];
|
|
106
|
+
await buildCommand({
|
|
107
|
+
providers: providerList,
|
|
108
|
+
enableOpenApi: options.enableOpenapi || false,
|
|
109
|
+
production: options.production || false,
|
|
110
|
+
skipBundle: options.skipBundle || false,
|
|
111
|
+
stage: options.stage,
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
// Default to config-driven build
|
|
115
|
+
else {
|
|
116
|
+
await buildCommand({
|
|
117
|
+
enableOpenApi: options.enableOpenapi || false,
|
|
118
|
+
production: options.production || false,
|
|
119
|
+
skipBundle: options.skipBundle || false,
|
|
120
|
+
stage: options.stage,
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
} catch (_error) {
|
|
124
|
+
process.exit(1);
|
|
125
|
+
}
|
|
126
|
+
},
|
|
127
|
+
);
|
|
128
|
+
|
|
129
|
+
program
|
|
130
|
+
.command('dev')
|
|
131
|
+
.description('Start development server with automatic reload')
|
|
132
|
+
.option('-p, --port <port>', 'Port to run the development server on')
|
|
133
|
+
.option(
|
|
134
|
+
'--enable-openapi',
|
|
135
|
+
'Enable OpenAPI documentation for development server',
|
|
136
|
+
true,
|
|
137
|
+
)
|
|
138
|
+
.action(async (options: { port?: string; enableOpenapi?: boolean }) => {
|
|
139
|
+
try {
|
|
140
|
+
const globalOptions = program.opts();
|
|
141
|
+
if (globalOptions.cwd) {
|
|
142
|
+
process.chdir(globalOptions.cwd);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
await devCommand({
|
|
146
|
+
port: options.port ? Number.parseInt(options.port, 10) : 3000,
|
|
147
|
+
portExplicit: !!options.port,
|
|
148
|
+
enableOpenApi: options.enableOpenapi ?? true,
|
|
149
|
+
});
|
|
150
|
+
} catch (_error) {
|
|
151
|
+
process.exit(1);
|
|
152
|
+
}
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
program
|
|
156
|
+
.command('cron')
|
|
157
|
+
.description('Manage cron jobs')
|
|
158
|
+
.action(() => {
|
|
159
|
+
const globalOptions = program.opts();
|
|
160
|
+
if (globalOptions.cwd) {
|
|
161
|
+
process.chdir(globalOptions.cwd);
|
|
162
|
+
}
|
|
163
|
+
process.stdout.write('Cron management - coming soon\n');
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
program
|
|
167
|
+
.command('function')
|
|
168
|
+
.description('Manage serverless functions')
|
|
169
|
+
.action(() => {
|
|
170
|
+
const globalOptions = program.opts();
|
|
171
|
+
if (globalOptions.cwd) {
|
|
172
|
+
process.chdir(globalOptions.cwd);
|
|
173
|
+
}
|
|
174
|
+
process.stdout.write('Serverless function management - coming soon\n');
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
program
|
|
178
|
+
.command('api')
|
|
179
|
+
.description('Manage REST API endpoints')
|
|
180
|
+
.action(() => {
|
|
181
|
+
const globalOptions = program.opts();
|
|
182
|
+
if (globalOptions.cwd) {
|
|
183
|
+
process.chdir(globalOptions.cwd);
|
|
184
|
+
}
|
|
185
|
+
process.stdout.write('REST API management - coming soon\n');
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
program
|
|
189
|
+
.command('openapi')
|
|
190
|
+
.description('Generate OpenAPI specification from endpoints')
|
|
191
|
+
.action(async () => {
|
|
192
|
+
try {
|
|
193
|
+
const globalOptions = program.opts();
|
|
194
|
+
if (globalOptions.cwd) {
|
|
195
|
+
process.chdir(globalOptions.cwd);
|
|
196
|
+
}
|
|
197
|
+
await openapiCommand({});
|
|
198
|
+
} catch (_error) {
|
|
199
|
+
process.exit(1);
|
|
200
|
+
}
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
program
|
|
204
|
+
.command('generate:react-query')
|
|
205
|
+
.description('Generate React Query hooks from OpenAPI specification')
|
|
206
|
+
.option('--input <path>', 'Input OpenAPI spec file path', 'openapi.json')
|
|
207
|
+
.option(
|
|
208
|
+
'--output <path>',
|
|
209
|
+
'Output file path for generated hooks',
|
|
210
|
+
'src/api/hooks.ts',
|
|
211
|
+
)
|
|
212
|
+
.option('--name <name>', 'API name prefix for generated code', 'API')
|
|
213
|
+
.action(
|
|
214
|
+
async (options: { input?: string; output?: string; name?: string }) => {
|
|
215
|
+
try {
|
|
216
|
+
const globalOptions = program.opts();
|
|
217
|
+
if (globalOptions.cwd) {
|
|
218
|
+
process.chdir(globalOptions.cwd);
|
|
219
|
+
}
|
|
220
|
+
await generateReactQueryCommand(options);
|
|
221
|
+
} catch (_error) {
|
|
222
|
+
process.exit(1);
|
|
223
|
+
}
|
|
224
|
+
},
|
|
225
|
+
);
|
|
226
|
+
|
|
227
|
+
program
|
|
228
|
+
.command('docker')
|
|
229
|
+
.description('Generate Docker deployment files')
|
|
230
|
+
.option('--build', 'Build Docker image after generating files')
|
|
231
|
+
.option('--push', 'Push image to registry after building')
|
|
232
|
+
.option('--tag <tag>', 'Image tag', 'latest')
|
|
233
|
+
.option('--registry <registry>', 'Container registry URL')
|
|
234
|
+
.option('--slim', 'Use slim Dockerfile (assumes pre-built bundle exists)')
|
|
235
|
+
.option('--turbo', 'Use turbo prune for monorepo optimization')
|
|
236
|
+
.option('--turbo-package <name>', 'Package name for turbo prune')
|
|
237
|
+
.action(async (options: DockerOptions) => {
|
|
238
|
+
try {
|
|
239
|
+
const globalOptions = program.opts();
|
|
240
|
+
if (globalOptions.cwd) {
|
|
241
|
+
process.chdir(globalOptions.cwd);
|
|
242
|
+
}
|
|
243
|
+
await dockerCommand(options);
|
|
244
|
+
} catch (_error) {
|
|
245
|
+
process.exit(1);
|
|
246
|
+
}
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
program
|
|
250
|
+
.command('prepack')
|
|
251
|
+
.description('Generate Docker files for production deployment')
|
|
252
|
+
.option('--build', 'Build Docker image after generating files')
|
|
253
|
+
.option('--push', 'Push image to registry after building')
|
|
254
|
+
.option('--tag <tag>', 'Image tag', 'latest')
|
|
255
|
+
.option('--registry <registry>', 'Container registry URL')
|
|
256
|
+
.option('--slim', 'Build locally first, then use slim Dockerfile')
|
|
257
|
+
.option('--skip-bundle', 'Skip bundling step (only with --slim)')
|
|
258
|
+
.option('--turbo', 'Use turbo prune for monorepo optimization')
|
|
259
|
+
.option('--turbo-package <name>', 'Package name for turbo prune')
|
|
260
|
+
.action(
|
|
261
|
+
async (options: {
|
|
262
|
+
build?: boolean;
|
|
263
|
+
push?: boolean;
|
|
264
|
+
tag?: string;
|
|
265
|
+
registry?: string;
|
|
266
|
+
slim?: boolean;
|
|
267
|
+
skipBundle?: boolean;
|
|
268
|
+
turbo?: boolean;
|
|
269
|
+
turboPackage?: string;
|
|
270
|
+
}) => {
|
|
271
|
+
try {
|
|
272
|
+
const globalOptions = program.opts();
|
|
273
|
+
if (globalOptions.cwd) {
|
|
274
|
+
process.chdir(globalOptions.cwd);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
if (options.slim) {
|
|
278
|
+
await buildCommand({
|
|
279
|
+
provider: 'server',
|
|
280
|
+
production: true,
|
|
281
|
+
skipBundle: options.skipBundle,
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
await dockerCommand({
|
|
285
|
+
build: options.build,
|
|
286
|
+
push: options.push,
|
|
287
|
+
tag: options.tag,
|
|
288
|
+
registry: options.registry,
|
|
289
|
+
slim: options.slim,
|
|
290
|
+
turbo: options.turbo,
|
|
291
|
+
turboPackage: options.turboPackage,
|
|
292
|
+
});
|
|
293
|
+
if (options.slim) {
|
|
294
|
+
} else {
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
if (options.build) {
|
|
298
|
+
const tag = options.tag ?? 'latest';
|
|
299
|
+
const registry = options.registry;
|
|
300
|
+
const _imageRef = registry ? `${registry}/api:${tag}` : `api:${tag}`;
|
|
301
|
+
}
|
|
302
|
+
} catch (_error) {
|
|
303
|
+
process.exit(1);
|
|
304
|
+
}
|
|
305
|
+
},
|
|
306
|
+
);
|
|
307
|
+
|
|
308
|
+
// Secrets management commands
|
|
309
|
+
program
|
|
310
|
+
.command('secrets:init')
|
|
311
|
+
.description('Initialize secrets for a deployment stage')
|
|
312
|
+
.requiredOption('--stage <stage>', 'Stage name (e.g., production, staging)')
|
|
313
|
+
.option('--force', 'Overwrite existing secrets')
|
|
314
|
+
.action(async (options: { stage: string; force?: boolean }) => {
|
|
315
|
+
try {
|
|
316
|
+
const globalOptions = program.opts();
|
|
317
|
+
if (globalOptions.cwd) {
|
|
318
|
+
process.chdir(globalOptions.cwd);
|
|
319
|
+
}
|
|
320
|
+
await secretsInitCommand(options);
|
|
321
|
+
} catch (_error) {
|
|
322
|
+
process.exit(1);
|
|
323
|
+
}
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
program
|
|
327
|
+
.command('secrets:set')
|
|
328
|
+
.description('Set a custom secret for a stage')
|
|
329
|
+
.argument('<key>', 'Secret key (e.g., API_KEY)')
|
|
330
|
+
.argument('[value]', 'Secret value (reads from stdin if omitted)')
|
|
331
|
+
.requiredOption('--stage <stage>', 'Stage name')
|
|
332
|
+
.action(
|
|
333
|
+
async (
|
|
334
|
+
key: string,
|
|
335
|
+
value: string | undefined,
|
|
336
|
+
options: { stage: string },
|
|
337
|
+
) => {
|
|
338
|
+
try {
|
|
339
|
+
const globalOptions = program.opts();
|
|
340
|
+
if (globalOptions.cwd) {
|
|
341
|
+
process.chdir(globalOptions.cwd);
|
|
342
|
+
}
|
|
343
|
+
await secretsSetCommand(key, value, options);
|
|
344
|
+
} catch (_error) {
|
|
345
|
+
process.exit(1);
|
|
346
|
+
}
|
|
347
|
+
},
|
|
348
|
+
);
|
|
349
|
+
|
|
350
|
+
program
|
|
351
|
+
.command('secrets:show')
|
|
352
|
+
.description('Show secrets for a stage')
|
|
353
|
+
.requiredOption('--stage <stage>', 'Stage name')
|
|
354
|
+
.option('--reveal', 'Show actual secret values (not masked)')
|
|
355
|
+
.action(async (options: { stage: string; reveal?: boolean }) => {
|
|
356
|
+
try {
|
|
357
|
+
const globalOptions = program.opts();
|
|
358
|
+
if (globalOptions.cwd) {
|
|
359
|
+
process.chdir(globalOptions.cwd);
|
|
360
|
+
}
|
|
361
|
+
await secretsShowCommand(options);
|
|
362
|
+
} catch (_error) {
|
|
363
|
+
process.exit(1);
|
|
364
|
+
}
|
|
365
|
+
});
|
|
366
|
+
|
|
367
|
+
program
|
|
368
|
+
.command('secrets:rotate')
|
|
369
|
+
.description('Rotate service passwords')
|
|
370
|
+
.requiredOption('--stage <stage>', 'Stage name')
|
|
371
|
+
.option(
|
|
372
|
+
'--service <service>',
|
|
373
|
+
'Specific service to rotate (postgres, redis, rabbitmq)',
|
|
374
|
+
)
|
|
375
|
+
.action(async (options: { stage: string; service?: ComposeServiceName }) => {
|
|
376
|
+
try {
|
|
377
|
+
const globalOptions = program.opts();
|
|
378
|
+
if (globalOptions.cwd) {
|
|
379
|
+
process.chdir(globalOptions.cwd);
|
|
380
|
+
}
|
|
381
|
+
await secretsRotateCommand(options);
|
|
382
|
+
} catch (_error) {
|
|
383
|
+
process.exit(1);
|
|
384
|
+
}
|
|
385
|
+
});
|
|
386
|
+
|
|
387
|
+
program
|
|
388
|
+
.command('secrets:import')
|
|
389
|
+
.description('Import secrets from a JSON file')
|
|
390
|
+
.argument('<file>', 'JSON file path (e.g., secrets.json)')
|
|
391
|
+
.requiredOption('--stage <stage>', 'Stage name')
|
|
392
|
+
.option('--no-merge', 'Replace all custom secrets instead of merging')
|
|
393
|
+
.action(async (file: string, options: { stage: string; merge?: boolean }) => {
|
|
394
|
+
try {
|
|
395
|
+
const globalOptions = program.opts();
|
|
396
|
+
if (globalOptions.cwd) {
|
|
397
|
+
process.chdir(globalOptions.cwd);
|
|
398
|
+
}
|
|
399
|
+
await secretsImportCommand(file, options);
|
|
400
|
+
} catch (_error) {
|
|
401
|
+
process.exit(1);
|
|
402
|
+
}
|
|
403
|
+
});
|
|
404
|
+
|
|
405
|
+
// Deploy command
|
|
406
|
+
program
|
|
407
|
+
.command('deploy')
|
|
408
|
+
.description('Deploy application to a provider')
|
|
409
|
+
.requiredOption(
|
|
410
|
+
'--provider <provider>',
|
|
411
|
+
'Deploy provider (docker, dokploy, aws-lambda)',
|
|
412
|
+
)
|
|
413
|
+
.requiredOption(
|
|
414
|
+
'--stage <stage>',
|
|
415
|
+
'Deployment stage (e.g., production, staging)',
|
|
416
|
+
)
|
|
417
|
+
.option('--tag <tag>', 'Image tag (default: stage-timestamp)')
|
|
418
|
+
.option('--skip-push', 'Skip pushing image to registry')
|
|
419
|
+
.option('--skip-build', 'Skip build step (use existing build)')
|
|
420
|
+
.action(
|
|
421
|
+
async (options: {
|
|
422
|
+
provider: string;
|
|
423
|
+
stage: string;
|
|
424
|
+
tag?: string;
|
|
425
|
+
skipPush?: boolean;
|
|
426
|
+
skipBuild?: boolean;
|
|
427
|
+
}) => {
|
|
428
|
+
try {
|
|
429
|
+
const globalOptions = program.opts();
|
|
430
|
+
if (globalOptions.cwd) {
|
|
431
|
+
process.chdir(globalOptions.cwd);
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
const validProviders = ['docker', 'dokploy', 'aws-lambda'];
|
|
435
|
+
if (!validProviders.includes(options.provider)) {
|
|
436
|
+
console.error(
|
|
437
|
+
`Invalid provider: ${options.provider}\n` +
|
|
438
|
+
`Valid providers: ${validProviders.join(', ')}`,
|
|
439
|
+
);
|
|
440
|
+
process.exit(1);
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
await deployCommand({
|
|
444
|
+
provider: options.provider as DeployProvider,
|
|
445
|
+
stage: options.stage,
|
|
446
|
+
tag: options.tag,
|
|
447
|
+
skipPush: options.skipPush,
|
|
448
|
+
skipBuild: options.skipBuild,
|
|
449
|
+
});
|
|
450
|
+
} catch (_error) {
|
|
451
|
+
process.exit(1);
|
|
452
|
+
}
|
|
453
|
+
},
|
|
454
|
+
);
|
|
455
|
+
|
|
456
|
+
// Deploy init command - Initialize Dokploy project and application
|
|
457
|
+
program
|
|
458
|
+
.command('deploy:init')
|
|
459
|
+
.description('Initialize Dokploy deployment (create project and application)')
|
|
460
|
+
.option(
|
|
461
|
+
'--endpoint <url>',
|
|
462
|
+
'Dokploy server URL (uses stored credentials if logged in)',
|
|
463
|
+
)
|
|
464
|
+
.requiredOption('--project <name>', 'Project name (creates if not exists)')
|
|
465
|
+
.requiredOption('--app <name>', 'Application name')
|
|
466
|
+
.option('--project-id <id>', 'Use existing project ID instead of creating')
|
|
467
|
+
.option('--registry-id <id>', 'Configure registry for the application')
|
|
468
|
+
.action(
|
|
469
|
+
async (options: {
|
|
470
|
+
endpoint?: string;
|
|
471
|
+
project: string;
|
|
472
|
+
app: string;
|
|
473
|
+
projectId?: string;
|
|
474
|
+
registryId?: string;
|
|
475
|
+
}) => {
|
|
476
|
+
try {
|
|
477
|
+
const globalOptions = program.opts();
|
|
478
|
+
if (globalOptions.cwd) {
|
|
479
|
+
process.chdir(globalOptions.cwd);
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
await deployInitCommand({
|
|
483
|
+
endpoint: options.endpoint,
|
|
484
|
+
projectName: options.project,
|
|
485
|
+
appName: options.app,
|
|
486
|
+
projectId: options.projectId,
|
|
487
|
+
registryId: options.registryId,
|
|
488
|
+
});
|
|
489
|
+
} catch (error) {
|
|
490
|
+
console.error(
|
|
491
|
+
error instanceof Error
|
|
492
|
+
? error.message
|
|
493
|
+
: 'Failed to initialize deployment',
|
|
494
|
+
);
|
|
495
|
+
process.exit(1);
|
|
496
|
+
}
|
|
497
|
+
},
|
|
498
|
+
);
|
|
499
|
+
|
|
500
|
+
// Deploy list command - List Dokploy resources
|
|
501
|
+
program
|
|
502
|
+
.command('deploy:list')
|
|
503
|
+
.description('List Dokploy resources (projects, registries)')
|
|
504
|
+
.option(
|
|
505
|
+
'--endpoint <url>',
|
|
506
|
+
'Dokploy server URL (uses stored credentials if logged in)',
|
|
507
|
+
)
|
|
508
|
+
.option('--projects', 'List projects')
|
|
509
|
+
.option('--registries', 'List registries')
|
|
510
|
+
.action(
|
|
511
|
+
async (options: {
|
|
512
|
+
endpoint?: string;
|
|
513
|
+
projects?: boolean;
|
|
514
|
+
registries?: boolean;
|
|
515
|
+
}) => {
|
|
516
|
+
try {
|
|
517
|
+
const globalOptions = program.opts();
|
|
518
|
+
if (globalOptions.cwd) {
|
|
519
|
+
process.chdir(globalOptions.cwd);
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
if (options.projects) {
|
|
523
|
+
await deployListCommand({
|
|
524
|
+
endpoint: options.endpoint,
|
|
525
|
+
resource: 'projects',
|
|
526
|
+
});
|
|
527
|
+
}
|
|
528
|
+
if (options.registries) {
|
|
529
|
+
await deployListCommand({
|
|
530
|
+
endpoint: options.endpoint,
|
|
531
|
+
resource: 'registries',
|
|
532
|
+
});
|
|
533
|
+
}
|
|
534
|
+
if (!options.projects && !options.registries) {
|
|
535
|
+
// Default to listing both
|
|
536
|
+
await deployListCommand({
|
|
537
|
+
endpoint: options.endpoint,
|
|
538
|
+
resource: 'projects',
|
|
539
|
+
});
|
|
540
|
+
await deployListCommand({
|
|
541
|
+
endpoint: options.endpoint,
|
|
542
|
+
resource: 'registries',
|
|
543
|
+
});
|
|
544
|
+
}
|
|
545
|
+
} catch (error) {
|
|
546
|
+
console.error(
|
|
547
|
+
error instanceof Error ? error.message : 'Failed to list resources',
|
|
548
|
+
);
|
|
549
|
+
process.exit(1);
|
|
550
|
+
}
|
|
551
|
+
},
|
|
552
|
+
);
|
|
553
|
+
|
|
554
|
+
// Login command
|
|
555
|
+
program
|
|
556
|
+
.command('login')
|
|
557
|
+
.description('Authenticate with a deployment service')
|
|
558
|
+
.option('--service <service>', 'Service to login to (dokploy)', 'dokploy')
|
|
559
|
+
.option('--token <token>', 'API token (will prompt if not provided)')
|
|
560
|
+
.option('--endpoint <url>', 'Service endpoint URL')
|
|
561
|
+
.action(
|
|
562
|
+
async (options: { service: string; token?: string; endpoint?: string }) => {
|
|
563
|
+
try {
|
|
564
|
+
const globalOptions = program.opts();
|
|
565
|
+
if (globalOptions.cwd) {
|
|
566
|
+
process.chdir(globalOptions.cwd);
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
if (options.service !== 'dokploy') {
|
|
570
|
+
console.error(
|
|
571
|
+
`Unknown service: ${options.service}. Supported: dokploy`,
|
|
572
|
+
);
|
|
573
|
+
process.exit(1);
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
await loginCommand({
|
|
577
|
+
service: options.service as 'dokploy',
|
|
578
|
+
token: options.token,
|
|
579
|
+
endpoint: options.endpoint,
|
|
580
|
+
});
|
|
581
|
+
} catch (error) {
|
|
582
|
+
console.error(
|
|
583
|
+
error instanceof Error ? error.message : 'Failed to login',
|
|
584
|
+
);
|
|
585
|
+
process.exit(1);
|
|
586
|
+
}
|
|
587
|
+
},
|
|
588
|
+
);
|
|
589
|
+
|
|
590
|
+
// Logout command
|
|
591
|
+
program
|
|
592
|
+
.command('logout')
|
|
593
|
+
.description('Remove stored credentials')
|
|
594
|
+
.option(
|
|
595
|
+
'--service <service>',
|
|
596
|
+
'Service to logout from (dokploy, all)',
|
|
597
|
+
'dokploy',
|
|
598
|
+
)
|
|
599
|
+
.action(async (options: { service: string }) => {
|
|
600
|
+
try {
|
|
601
|
+
const globalOptions = program.opts();
|
|
602
|
+
if (globalOptions.cwd) {
|
|
603
|
+
process.chdir(globalOptions.cwd);
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
await logoutCommand({
|
|
607
|
+
service: options.service as 'dokploy' | 'all',
|
|
608
|
+
});
|
|
609
|
+
} catch (error) {
|
|
610
|
+
console.error(
|
|
611
|
+
error instanceof Error ? error.message : 'Failed to logout',
|
|
612
|
+
);
|
|
613
|
+
process.exit(1);
|
|
614
|
+
}
|
|
615
|
+
});
|
|
616
|
+
|
|
617
|
+
// Whoami command
|
|
618
|
+
program
|
|
619
|
+
.command('whoami')
|
|
620
|
+
.description('Show current authentication status')
|
|
621
|
+
.action(async () => {
|
|
622
|
+
try {
|
|
623
|
+
const globalOptions = program.opts();
|
|
624
|
+
if (globalOptions.cwd) {
|
|
625
|
+
process.chdir(globalOptions.cwd);
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
await whoamiCommand();
|
|
629
|
+
} catch (error) {
|
|
630
|
+
console.error(
|
|
631
|
+
error instanceof Error ? error.message : 'Failed to get status',
|
|
632
|
+
);
|
|
633
|
+
process.exit(1);
|
|
634
|
+
}
|
|
635
|
+
});
|
|
214
636
|
|
|
215
637
|
program.parse();
|