@geekmidas/cli 1.0.2 → 1.2.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/CHANGELOG.md +12 -0
- package/dist/{SSMStateProvider-C4wp4AZe.mjs → SSMStateProvider-BjCi_58g.mjs} +16 -7
- package/dist/SSMStateProvider-BjCi_58g.mjs.map +1 -0
- package/dist/{SSMStateProvider-BxAPU99a.cjs → SSMStateProvider-D79o_JjM.cjs} +16 -7
- package/dist/SSMStateProvider-D79o_JjM.cjs.map +1 -0
- package/dist/{config-C6awcFBx.mjs → config-BQ4a36Rq.mjs} +2 -2
- package/dist/{config-C6awcFBx.mjs.map → config-BQ4a36Rq.mjs.map} +1 -1
- package/dist/{config-BGeJsW1r.cjs → config-Bayob8pB.cjs} +2 -2
- package/dist/{config-BGeJsW1r.cjs.map → config-Bayob8pB.cjs.map} +1 -1
- package/dist/config.cjs +2 -2
- package/dist/config.d.cts +1 -1
- package/dist/config.d.mts +1 -1
- package/dist/config.mjs +2 -2
- package/dist/{index-KFEbMIRa.d.mts → index-Bi9vGQJy.d.mts} +61 -13
- package/dist/index-Bi9vGQJy.d.mts.map +1 -0
- package/dist/{index-B5rGIc4g.d.cts → index-CufAAnge.d.cts} +61 -13
- package/dist/index-CufAAnge.d.cts.map +1 -0
- package/dist/index.cjs +14 -9
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +14 -9
- package/dist/index.mjs.map +1 -1
- package/dist/{openapi-D1KXv2Ml.cjs → openapi-BZP8jkI4.cjs} +2 -2
- package/dist/{openapi-D1KXv2Ml.cjs.map → openapi-BZP8jkI4.cjs.map} +1 -1
- package/dist/{openapi-BMFmLnX6.mjs → openapi-DrbBWq0s.mjs} +2 -2
- package/dist/{openapi-BMFmLnX6.mjs.map → openapi-DrbBWq0s.mjs.map} +1 -1
- package/dist/openapi.cjs +3 -3
- package/dist/openapi.mjs +3 -3
- package/dist/workspace/index.cjs +2 -1
- package/dist/workspace/index.d.cts +2 -2
- package/dist/workspace/index.d.mts +2 -2
- package/dist/workspace/index.mjs +2 -2
- package/dist/{workspace-BFRUOOrh.cjs → workspace-BMJE18LV.cjs} +46 -6
- package/dist/workspace-BMJE18LV.cjs.map +1 -0
- package/dist/{workspace-DAxG3_H2.mjs → workspace-CASoZOjs.mjs} +41 -7
- package/dist/workspace-CASoZOjs.mjs.map +1 -0
- package/package.json +4 -4
- package/src/deploy/SSMStateProvider.ts +20 -7
- package/src/deploy/StateProvider.ts +1 -1
- package/src/deploy/__tests__/CachedStateProvider.spec.ts +7 -0
- package/src/deploy/__tests__/LocalStateProvider.spec.ts +4 -0
- package/src/deploy/__tests__/SSMStateProvider.spec.ts +20 -8
- package/src/deploy/__tests__/dns-verification.spec.ts +1 -1
- package/src/deploy/__tests__/env-resolver.spec.ts +9 -9
- package/src/deploy/__tests__/state-e2e.spec.ts +387 -0
- package/src/deploy/__tests__/state.spec.ts +53 -29
- package/src/deploy/index.ts +6 -1
- package/src/deploy/state.ts +4 -0
- package/src/init/__tests__/init.spec.ts +10 -1
- package/src/init/versions.ts +1 -1
- package/src/secrets/__tests__/storage.spec.ts +6 -2
- package/src/workspace/__tests__/index.spec.ts +129 -0
- package/src/workspace/index.ts +44 -0
- package/src/workspace/schema.ts +17 -6
- package/src/workspace/types.ts +26 -9
- package/dist/SSMStateProvider-BxAPU99a.cjs.map +0 -1
- package/dist/SSMStateProvider-C4wp4AZe.mjs.map +0 -1
- package/dist/index-B5rGIc4g.d.cts.map +0 -1
- package/dist/index-KFEbMIRa.d.mts.map +0 -1
- package/dist/workspace-BFRUOOrh.cjs.map +0 -1
- package/dist/workspace-DAxG3_H2.mjs.map +0 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@geekmidas/cli",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "CLI tools for building Lambda handlers, server applications, and generating OpenAPI specs",
|
|
5
5
|
"private": false,
|
|
6
6
|
"type": "module",
|
|
@@ -56,8 +56,8 @@
|
|
|
56
56
|
"@geekmidas/constructs": "~1.0.0",
|
|
57
57
|
"@geekmidas/envkit": "~1.0.0",
|
|
58
58
|
"@geekmidas/errors": "~1.0.0",
|
|
59
|
-
"@geekmidas/
|
|
60
|
-
"@geekmidas/
|
|
59
|
+
"@geekmidas/schema": "~1.0.0",
|
|
60
|
+
"@geekmidas/logger": "~1.0.0"
|
|
61
61
|
},
|
|
62
62
|
"devDependencies": {
|
|
63
63
|
"@types/lodash.kebabcase": "^4.1.9",
|
|
@@ -67,7 +67,7 @@
|
|
|
67
67
|
"typescript": "^5.8.2",
|
|
68
68
|
"vitest": "^3.2.4",
|
|
69
69
|
"zod": "~4.1.13",
|
|
70
|
-
"@geekmidas/testkit": "1.0.
|
|
70
|
+
"@geekmidas/testkit": "1.0.1"
|
|
71
71
|
},
|
|
72
72
|
"peerDependencies": {
|
|
73
73
|
"@geekmidas/telescope": "~1.0.0"
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
ParameterNotFound,
|
|
13
13
|
PutParameterCommand,
|
|
14
14
|
SSMClient,
|
|
15
|
+
type SSMClientConfig,
|
|
15
16
|
} from '@aws-sdk/client-ssm';
|
|
16
17
|
import type { AwsRegion, StateProvider } from './StateProvider';
|
|
17
18
|
import type { DokployStageState } from './state';
|
|
@@ -19,8 +20,12 @@ import type { DokployStageState } from './state';
|
|
|
19
20
|
export interface SSMStateProviderOptions {
|
|
20
21
|
/** Workspace name (used in parameter path) */
|
|
21
22
|
workspaceName: string;
|
|
22
|
-
/** AWS region
|
|
23
|
-
region
|
|
23
|
+
/** AWS region */
|
|
24
|
+
region?: AwsRegion;
|
|
25
|
+
/** AWS credentials (optional - uses default credential chain if not provided) */
|
|
26
|
+
credentials?: SSMClientConfig['credentials'];
|
|
27
|
+
/** Custom endpoint (for LocalStack or other S3-compatible services) */
|
|
28
|
+
endpoint?: string;
|
|
24
29
|
}
|
|
25
30
|
|
|
26
31
|
/**
|
|
@@ -30,14 +35,22 @@ export interface SSMStateProviderOptions {
|
|
|
30
35
|
* Parameter path: /gkm/{workspaceName}/{stage}/state
|
|
31
36
|
*/
|
|
32
37
|
export class SSMStateProvider implements StateProvider {
|
|
33
|
-
|
|
34
|
-
|
|
38
|
+
constructor(
|
|
39
|
+
readonly workspaceName: string,
|
|
40
|
+
private readonly client: SSMClient,
|
|
41
|
+
) {}
|
|
35
42
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
43
|
+
/**
|
|
44
|
+
* Create an SSMStateProvider with a new SSMClient.
|
|
45
|
+
*/
|
|
46
|
+
static create(options: SSMStateProviderOptions): SSMStateProvider {
|
|
47
|
+
const client = new SSMClient({
|
|
39
48
|
region: options.region,
|
|
49
|
+
credentials: options.credentials,
|
|
50
|
+
endpoint: options.endpoint,
|
|
40
51
|
});
|
|
52
|
+
|
|
53
|
+
return new SSMStateProvider(options.workspaceName, client);
|
|
41
54
|
}
|
|
42
55
|
|
|
43
56
|
/**
|
|
@@ -158,7 +158,7 @@ export async function createStateProvider(
|
|
|
158
158
|
const { CachedStateProvider } = await import('./CachedStateProvider');
|
|
159
159
|
|
|
160
160
|
const local = new LocalStateProvider(workspaceRoot);
|
|
161
|
-
const ssm =
|
|
161
|
+
const ssm = SSMStateProvider.create({
|
|
162
162
|
workspaceName,
|
|
163
163
|
region: (config as SSMStateConfig).region,
|
|
164
164
|
});
|
|
@@ -36,6 +36,7 @@ describe('CachedStateProvider', () => {
|
|
|
36
36
|
const state: DokployStageState = {
|
|
37
37
|
provider: 'dokploy',
|
|
38
38
|
stage: 'production',
|
|
39
|
+
projectId: 'proj_test',
|
|
39
40
|
environmentId: 'env_123',
|
|
40
41
|
applications: { api: 'local_app' },
|
|
41
42
|
services: {},
|
|
@@ -58,6 +59,7 @@ describe('CachedStateProvider', () => {
|
|
|
58
59
|
const state: DokployStageState = {
|
|
59
60
|
provider: 'dokploy',
|
|
60
61
|
stage: 'production',
|
|
62
|
+
projectId: 'proj_test',
|
|
61
63
|
environmentId: 'env_123',
|
|
62
64
|
applications: { api: 'remote_app' },
|
|
63
65
|
services: {},
|
|
@@ -96,6 +98,7 @@ describe('CachedStateProvider', () => {
|
|
|
96
98
|
const state: DokployStageState = {
|
|
97
99
|
provider: 'dokploy',
|
|
98
100
|
stage: 'production',
|
|
101
|
+
projectId: 'proj_test',
|
|
99
102
|
environmentId: 'env_123',
|
|
100
103
|
applications: { api: 'app_123' },
|
|
101
104
|
services: {},
|
|
@@ -120,6 +123,7 @@ describe('CachedStateProvider', () => {
|
|
|
120
123
|
const remoteState: DokployStageState = {
|
|
121
124
|
provider: 'dokploy',
|
|
122
125
|
stage: 'production',
|
|
126
|
+
projectId: 'proj_test',
|
|
123
127
|
environmentId: 'env_123',
|
|
124
128
|
applications: { api: 'remote_app' },
|
|
125
129
|
services: {},
|
|
@@ -155,6 +159,7 @@ describe('CachedStateProvider', () => {
|
|
|
155
159
|
const localState: DokployStageState = {
|
|
156
160
|
provider: 'dokploy',
|
|
157
161
|
stage: 'production',
|
|
162
|
+
projectId: 'proj_test',
|
|
158
163
|
environmentId: 'env_123',
|
|
159
164
|
applications: { api: 'local_app' },
|
|
160
165
|
services: {},
|
|
@@ -190,6 +195,7 @@ describe('CachedStateProvider', () => {
|
|
|
190
195
|
const localState: DokployStageState = {
|
|
191
196
|
provider: 'dokploy',
|
|
192
197
|
stage: 'production',
|
|
198
|
+
projectId: 'proj_test',
|
|
193
199
|
environmentId: 'env_123',
|
|
194
200
|
applications: { api: 'local_app' },
|
|
195
201
|
services: {},
|
|
@@ -198,6 +204,7 @@ describe('CachedStateProvider', () => {
|
|
|
198
204
|
const remoteState: DokployStageState = {
|
|
199
205
|
provider: 'dokploy',
|
|
200
206
|
stage: 'production',
|
|
207
|
+
projectId: 'proj_test',
|
|
201
208
|
environmentId: 'env_123',
|
|
202
209
|
applications: { api: 'remote_app' },
|
|
203
210
|
services: {},
|
|
@@ -29,6 +29,7 @@ describe('LocalStateProvider', () => {
|
|
|
29
29
|
const stateData: DokployStageState = {
|
|
30
30
|
provider: 'dokploy',
|
|
31
31
|
stage: 'production',
|
|
32
|
+
projectId: 'proj_test',
|
|
32
33
|
environmentId: 'env_123',
|
|
33
34
|
applications: { api: 'app_123' },
|
|
34
35
|
services: { postgresId: 'pg_123' },
|
|
@@ -62,6 +63,7 @@ describe('LocalStateProvider', () => {
|
|
|
62
63
|
const state: DokployStageState = {
|
|
63
64
|
provider: 'dokploy',
|
|
64
65
|
stage: 'staging',
|
|
66
|
+
projectId: 'proj_test',
|
|
65
67
|
environmentId: 'env_456',
|
|
66
68
|
applications: {},
|
|
67
69
|
services: {},
|
|
@@ -81,6 +83,7 @@ describe('LocalStateProvider', () => {
|
|
|
81
83
|
const state: DokployStageState = {
|
|
82
84
|
provider: 'dokploy',
|
|
83
85
|
stage: 'staging',
|
|
86
|
+
projectId: 'proj_test',
|
|
84
87
|
environmentId: 'env_456',
|
|
85
88
|
applications: {},
|
|
86
89
|
services: {},
|
|
@@ -98,6 +101,7 @@ describe('LocalStateProvider', () => {
|
|
|
98
101
|
const state: DokployStageState = {
|
|
99
102
|
provider: 'dokploy',
|
|
100
103
|
stage: 'production',
|
|
104
|
+
projectId: 'proj_test',
|
|
101
105
|
environmentId: 'env_123',
|
|
102
106
|
applications: { api: 'app_123', web: 'app_456' },
|
|
103
107
|
services: { postgresId: 'pg_123', redisId: 'redis_123' },
|
|
@@ -44,14 +44,8 @@ describe('SSMStateProvider', () => {
|
|
|
44
44
|
},
|
|
45
45
|
});
|
|
46
46
|
|
|
47
|
-
provider
|
|
48
|
-
|
|
49
|
-
region: 'us-east-1',
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
// Override the client's endpoint for localstack
|
|
53
|
-
// @ts-expect-error - accessing private property for testing
|
|
54
|
-
provider.client = client;
|
|
47
|
+
// Create provider with injected client
|
|
48
|
+
provider = new SSMStateProvider(workspaceName, client);
|
|
55
49
|
});
|
|
56
50
|
|
|
57
51
|
afterEach(async () => {
|
|
@@ -70,6 +64,19 @@ describe('SSMStateProvider', () => {
|
|
|
70
64
|
client.destroy();
|
|
71
65
|
});
|
|
72
66
|
|
|
67
|
+
describe('static create', () => {
|
|
68
|
+
it('should create provider with options', () => {
|
|
69
|
+
const provider = SSMStateProvider.create({
|
|
70
|
+
workspaceName: 'my-workspace',
|
|
71
|
+
region: 'us-west-2',
|
|
72
|
+
endpoint: LOCALSTACK_ENDPOINT,
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
expect(provider).toBeInstanceOf(SSMStateProvider);
|
|
76
|
+
expect(provider.workspaceName).toBe('my-workspace');
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
|
|
73
80
|
describe('read', () => {
|
|
74
81
|
it('should return null when parameter does not exist', async () => {
|
|
75
82
|
const state = await provider.read('nonexistent-stage');
|
|
@@ -80,6 +87,7 @@ describe('SSMStateProvider', () => {
|
|
|
80
87
|
const stateData: DokployStageState = {
|
|
81
88
|
provider: 'dokploy',
|
|
82
89
|
stage: testStage,
|
|
90
|
+
projectId: 'proj_test',
|
|
83
91
|
environmentId: 'env_123',
|
|
84
92
|
applications: { api: 'app_123' },
|
|
85
93
|
services: { postgresId: 'pg_123' },
|
|
@@ -105,6 +113,7 @@ describe('SSMStateProvider', () => {
|
|
|
105
113
|
const state: DokployStageState = {
|
|
106
114
|
provider: 'dokploy',
|
|
107
115
|
stage: testStage,
|
|
116
|
+
projectId: 'proj_test',
|
|
108
117
|
environmentId: 'env_123',
|
|
109
118
|
applications: { api: 'app_123' },
|
|
110
119
|
services: {},
|
|
@@ -128,6 +137,7 @@ describe('SSMStateProvider', () => {
|
|
|
128
137
|
const state1: DokployStageState = {
|
|
129
138
|
provider: 'dokploy',
|
|
130
139
|
stage: testStage,
|
|
140
|
+
projectId: 'proj_test',
|
|
131
141
|
environmentId: 'env_123',
|
|
132
142
|
applications: { api: 'app_old' },
|
|
133
143
|
services: {},
|
|
@@ -137,6 +147,7 @@ describe('SSMStateProvider', () => {
|
|
|
137
147
|
const state2: DokployStageState = {
|
|
138
148
|
provider: 'dokploy',
|
|
139
149
|
stage: testStage,
|
|
150
|
+
projectId: 'proj_test',
|
|
140
151
|
environmentId: 'env_123',
|
|
141
152
|
applications: { api: 'app_new' },
|
|
142
153
|
services: {},
|
|
@@ -161,6 +172,7 @@ describe('SSMStateProvider', () => {
|
|
|
161
172
|
const state: DokployStageState = {
|
|
162
173
|
provider: 'dokploy',
|
|
163
174
|
stage: testStage,
|
|
175
|
+
projectId: 'proj_test',
|
|
164
176
|
environmentId: 'env_123',
|
|
165
177
|
applications: {},
|
|
166
178
|
services: {},
|
|
@@ -53,7 +53,7 @@ describe('generateSecret', () => {
|
|
|
53
53
|
describe('getOrGenerateSecret', () => {
|
|
54
54
|
it('should return existing secret if already stored', () => {
|
|
55
55
|
const state: DokployStageState = {
|
|
56
|
-
...createEmptyState('production', 'env-123'),
|
|
56
|
+
...createEmptyState('production', 'proj_test', 'env-123'),
|
|
57
57
|
generatedSecrets: {
|
|
58
58
|
api: { BETTER_AUTH_SECRET: 'existing-secret-123' },
|
|
59
59
|
},
|
|
@@ -64,7 +64,7 @@ describe('getOrGenerateSecret', () => {
|
|
|
64
64
|
});
|
|
65
65
|
|
|
66
66
|
it('should generate and store new secret if not exists', () => {
|
|
67
|
-
const state = createEmptyState('production', 'env-123');
|
|
67
|
+
const state = createEmptyState('production', 'proj_test', 'env-123');
|
|
68
68
|
|
|
69
69
|
const result = getOrGenerateSecret(state, 'api', 'BETTER_AUTH_SECRET');
|
|
70
70
|
|
|
@@ -73,7 +73,7 @@ describe('getOrGenerateSecret', () => {
|
|
|
73
73
|
});
|
|
74
74
|
|
|
75
75
|
it('should generate different secrets for different apps', () => {
|
|
76
|
-
const state = createEmptyState('production', 'env-123');
|
|
76
|
+
const state = createEmptyState('production', 'proj_test', 'env-123');
|
|
77
77
|
|
|
78
78
|
const apiSecret = getOrGenerateSecret(state, 'api', 'BETTER_AUTH_SECRET');
|
|
79
79
|
const authSecret = getOrGenerateSecret(state, 'auth', 'BETTER_AUTH_SECRET');
|
|
@@ -84,7 +84,7 @@ describe('getOrGenerateSecret', () => {
|
|
|
84
84
|
});
|
|
85
85
|
|
|
86
86
|
it('should generate different secrets for different secret names', () => {
|
|
87
|
-
const state = createEmptyState('production', 'env-123');
|
|
87
|
+
const state = createEmptyState('production', 'proj_test', 'env-123');
|
|
88
88
|
|
|
89
89
|
const secret1 = getOrGenerateSecret(state, 'api', 'SECRET_ONE');
|
|
90
90
|
const secret2 = getOrGenerateSecret(state, 'api', 'SECRET_TWO');
|
|
@@ -93,7 +93,7 @@ describe('getOrGenerateSecret', () => {
|
|
|
93
93
|
});
|
|
94
94
|
|
|
95
95
|
it('should return same secret on subsequent calls', () => {
|
|
96
|
-
const state = createEmptyState('production', 'env-123');
|
|
96
|
+
const state = createEmptyState('production', 'proj_test', 'env-123');
|
|
97
97
|
|
|
98
98
|
const first = getOrGenerateSecret(state, 'api', 'BETTER_AUTH_SECRET');
|
|
99
99
|
const second = getOrGenerateSecret(state, 'api', 'BETTER_AUTH_SECRET');
|
|
@@ -181,7 +181,7 @@ describe('resolveEnvVar', () => {
|
|
|
181
181
|
app: createApp(),
|
|
182
182
|
appName: 'api',
|
|
183
183
|
stage: 'production',
|
|
184
|
-
state: createEmptyState('production', 'env-123'),
|
|
184
|
+
state: createEmptyState('production', 'proj_test', 'env-123'),
|
|
185
185
|
appHostname: 'api.example.com',
|
|
186
186
|
frontendUrls: [],
|
|
187
187
|
...overrides,
|
|
@@ -253,7 +253,7 @@ describe('resolveEnvVar', () => {
|
|
|
253
253
|
});
|
|
254
254
|
|
|
255
255
|
it('should resolve BETTER_AUTH_SECRET by generating and storing secret', () => {
|
|
256
|
-
const state = createEmptyState('production', 'env-123');
|
|
256
|
+
const state = createEmptyState('production', 'proj_test', 'env-123');
|
|
257
257
|
const context = createContext({ state, appName: 'auth' });
|
|
258
258
|
|
|
259
259
|
const secret = resolveEnvVar('BETTER_AUTH_SECRET', context);
|
|
@@ -362,7 +362,7 @@ describe('resolveEnvVars', () => {
|
|
|
362
362
|
},
|
|
363
363
|
appName: 'api',
|
|
364
364
|
stage: 'production',
|
|
365
|
-
state: createEmptyState('production', 'env-123'),
|
|
365
|
+
state: createEmptyState('production', 'proj_test', 'env-123'),
|
|
366
366
|
appHostname: 'api.example.com',
|
|
367
367
|
frontendUrls: ['https://web.example.com'],
|
|
368
368
|
...overrides,
|
|
@@ -449,7 +449,7 @@ describe('validateEnvVars', () => {
|
|
|
449
449
|
},
|
|
450
450
|
appName: 'api',
|
|
451
451
|
stage: 'production',
|
|
452
|
-
state: createEmptyState('production', 'env-123'),
|
|
452
|
+
state: createEmptyState('production', 'proj_test', 'env-123'),
|
|
453
453
|
appHostname: 'api.example.com',
|
|
454
454
|
frontendUrls: [],
|
|
455
455
|
...overrides,
|