@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.
Files changed (146) hide show
  1. package/README.md +525 -0
  2. package/dist/bundler-B1qy9b-j.cjs +112 -0
  3. package/dist/bundler-B1qy9b-j.cjs.map +1 -0
  4. package/dist/bundler-DskIqW2t.mjs +111 -0
  5. package/dist/bundler-DskIqW2t.mjs.map +1 -0
  6. package/dist/{config-C9aXOHBe.cjs → config-AmInkU7k.cjs} +8 -8
  7. package/dist/config-AmInkU7k.cjs.map +1 -0
  8. package/dist/{config-BrkUalUh.mjs → config-DYULeEv8.mjs} +3 -3
  9. package/dist/config-DYULeEv8.mjs.map +1 -0
  10. package/dist/config.cjs +1 -1
  11. package/dist/config.d.cts +1 -1
  12. package/dist/config.d.mts +1 -1
  13. package/dist/config.mjs +1 -1
  14. package/dist/encryption-C8H-38Yy.mjs +42 -0
  15. package/dist/encryption-C8H-38Yy.mjs.map +1 -0
  16. package/dist/encryption-Dyf_r1h-.cjs +44 -0
  17. package/dist/encryption-Dyf_r1h-.cjs.map +1 -0
  18. package/dist/index.cjs +2123 -179
  19. package/dist/index.cjs.map +1 -1
  20. package/dist/index.mjs +2141 -192
  21. package/dist/index.mjs.map +1 -1
  22. package/dist/{openapi-CZLI4QTr.mjs → openapi-BfFlOBCG.mjs} +801 -38
  23. package/dist/openapi-BfFlOBCG.mjs.map +1 -0
  24. package/dist/{openapi-BeHLKcwP.cjs → openapi-Bt_1FDpT.cjs} +794 -31
  25. package/dist/openapi-Bt_1FDpT.cjs.map +1 -0
  26. package/dist/{openapi-react-query-o5iMi8tz.cjs → openapi-react-query-B-sNWHFU.cjs} +5 -5
  27. package/dist/openapi-react-query-B-sNWHFU.cjs.map +1 -0
  28. package/dist/{openapi-react-query-CcciaVu5.mjs → openapi-react-query-B6XTeGqS.mjs} +5 -5
  29. package/dist/openapi-react-query-B6XTeGqS.mjs.map +1 -0
  30. package/dist/openapi-react-query.cjs +1 -1
  31. package/dist/openapi-react-query.d.cts.map +1 -1
  32. package/dist/openapi-react-query.d.mts.map +1 -1
  33. package/dist/openapi-react-query.mjs +1 -1
  34. package/dist/openapi.cjs +2 -2
  35. package/dist/openapi.d.cts +1 -1
  36. package/dist/openapi.d.cts.map +1 -1
  37. package/dist/openapi.d.mts +1 -1
  38. package/dist/openapi.d.mts.map +1 -1
  39. package/dist/openapi.mjs +2 -2
  40. package/dist/storage-BOOpAF8N.cjs +5 -0
  41. package/dist/storage-Bj1E26lU.cjs +187 -0
  42. package/dist/storage-Bj1E26lU.cjs.map +1 -0
  43. package/dist/storage-kSxTjkNb.mjs +133 -0
  44. package/dist/storage-kSxTjkNb.mjs.map +1 -0
  45. package/dist/storage-tgZSUnKl.mjs +3 -0
  46. package/dist/{types-b-vwGpqc.d.cts → types-BR0M2v_c.d.mts} +100 -1
  47. package/dist/types-BR0M2v_c.d.mts.map +1 -0
  48. package/dist/{types-DXgiA1sF.d.mts → types-BhkZc-vm.d.cts} +100 -1
  49. package/dist/types-BhkZc-vm.d.cts.map +1 -0
  50. package/examples/cron-example.ts +27 -27
  51. package/examples/env.ts +27 -27
  52. package/examples/function-example.ts +31 -31
  53. package/examples/gkm.config.json +20 -20
  54. package/examples/gkm.config.ts +8 -8
  55. package/examples/gkm.minimal.config.json +5 -5
  56. package/examples/gkm.production.config.json +25 -25
  57. package/examples/logger.ts +2 -2
  58. package/package.json +6 -6
  59. package/src/__tests__/EndpointGenerator.hooks.spec.ts +191 -191
  60. package/src/__tests__/config.spec.ts +55 -55
  61. package/src/__tests__/loadEnvFiles.spec.ts +93 -93
  62. package/src/__tests__/normalizeHooksConfig.spec.ts +58 -58
  63. package/src/__tests__/openapi-react-query.spec.ts +497 -497
  64. package/src/__tests__/openapi.spec.ts +428 -428
  65. package/src/__tests__/test-helpers.ts +76 -76
  66. package/src/auth/__tests__/credentials.spec.ts +204 -0
  67. package/src/auth/__tests__/index.spec.ts +168 -0
  68. package/src/auth/credentials.ts +187 -0
  69. package/src/auth/index.ts +226 -0
  70. package/src/build/__tests__/bundler.spec.ts +444 -0
  71. package/src/build/__tests__/index-new.spec.ts +474 -474
  72. package/src/build/__tests__/manifests.spec.ts +333 -333
  73. package/src/build/bundler.ts +210 -0
  74. package/src/build/endpoint-analyzer.ts +236 -0
  75. package/src/build/handler-templates.ts +1253 -0
  76. package/src/build/index.ts +260 -179
  77. package/src/build/manifests.ts +52 -52
  78. package/src/build/providerResolver.ts +145 -145
  79. package/src/build/types.ts +64 -43
  80. package/src/config.ts +39 -39
  81. package/src/deploy/__tests__/docker.spec.ts +111 -0
  82. package/src/deploy/__tests__/dokploy.spec.ts +245 -0
  83. package/src/deploy/__tests__/init.spec.ts +662 -0
  84. package/src/deploy/docker.ts +128 -0
  85. package/src/deploy/dokploy.ts +204 -0
  86. package/src/deploy/index.ts +136 -0
  87. package/src/deploy/init.ts +484 -0
  88. package/src/deploy/types.ts +48 -0
  89. package/src/dev/__tests__/index.spec.ts +266 -266
  90. package/src/dev/index.ts +647 -601
  91. package/src/docker/__tests__/compose.spec.ts +531 -0
  92. package/src/docker/__tests__/templates.spec.ts +280 -0
  93. package/src/docker/compose.ts +273 -0
  94. package/src/docker/index.ts +230 -0
  95. package/src/docker/templates.ts +446 -0
  96. package/src/generators/CronGenerator.ts +72 -72
  97. package/src/generators/EndpointGenerator.ts +699 -398
  98. package/src/generators/FunctionGenerator.ts +84 -84
  99. package/src/generators/Generator.ts +72 -72
  100. package/src/generators/OpenApiTsGenerator.ts +577 -577
  101. package/src/generators/SubscriberGenerator.ts +124 -124
  102. package/src/generators/__tests__/CronGenerator.spec.ts +433 -433
  103. package/src/generators/__tests__/EndpointGenerator.spec.ts +532 -382
  104. package/src/generators/__tests__/FunctionGenerator.spec.ts +244 -244
  105. package/src/generators/__tests__/SubscriberGenerator.spec.ts +397 -382
  106. package/src/generators/index.ts +4 -4
  107. package/src/index.ts +623 -201
  108. package/src/init/__tests__/generators.spec.ts +334 -334
  109. package/src/init/__tests__/init.spec.ts +332 -332
  110. package/src/init/__tests__/utils.spec.ts +89 -89
  111. package/src/init/generators/config.ts +175 -175
  112. package/src/init/generators/docker.ts +41 -41
  113. package/src/init/generators/env.ts +72 -72
  114. package/src/init/generators/index.ts +1 -1
  115. package/src/init/generators/models.ts +64 -64
  116. package/src/init/generators/monorepo.ts +161 -161
  117. package/src/init/generators/package.ts +71 -71
  118. package/src/init/generators/source.ts +6 -6
  119. package/src/init/index.ts +203 -208
  120. package/src/init/templates/api.ts +115 -115
  121. package/src/init/templates/index.ts +75 -75
  122. package/src/init/templates/minimal.ts +98 -98
  123. package/src/init/templates/serverless.ts +89 -89
  124. package/src/init/templates/worker.ts +98 -98
  125. package/src/init/utils.ts +54 -56
  126. package/src/openapi-react-query.ts +194 -194
  127. package/src/openapi.ts +63 -63
  128. package/src/secrets/__tests__/encryption.spec.ts +226 -0
  129. package/src/secrets/__tests__/generator.spec.ts +319 -0
  130. package/src/secrets/__tests__/index.spec.ts +91 -0
  131. package/src/secrets/__tests__/storage.spec.ts +611 -0
  132. package/src/secrets/encryption.ts +91 -0
  133. package/src/secrets/generator.ts +164 -0
  134. package/src/secrets/index.ts +383 -0
  135. package/src/secrets/storage.ts +192 -0
  136. package/src/secrets/types.ts +53 -0
  137. package/src/types.ts +295 -176
  138. package/tsdown.config.ts +11 -8
  139. package/dist/config-BrkUalUh.mjs.map +0 -1
  140. package/dist/config-C9aXOHBe.cjs.map +0 -1
  141. package/dist/openapi-BeHLKcwP.cjs.map +0 -1
  142. package/dist/openapi-CZLI4QTr.mjs.map +0 -1
  143. package/dist/openapi-react-query-CcciaVu5.mjs.map +0 -1
  144. package/dist/openapi-react-query-o5iMi8tz.cjs.map +0 -1
  145. package/dist/types-DXgiA1sF.d.mts.map +0 -1
  146. package/dist/types-b-vwGpqc.d.cts.map +0 -1
@@ -0,0 +1,192 @@
1
+ import { existsSync } from 'node:fs';
2
+ import { mkdir, readFile, writeFile } from 'node:fs/promises';
3
+ import { join } from 'node:path';
4
+ import type { EmbeddableSecrets, StageSecrets } from './types';
5
+
6
+ /** Default secrets directory relative to project root */
7
+ const SECRETS_DIR = '.gkm/secrets';
8
+
9
+ /**
10
+ * Get the secrets directory path.
11
+ */
12
+ export function getSecretsDir(cwd = process.cwd()): string {
13
+ return join(cwd, SECRETS_DIR);
14
+ }
15
+
16
+ /**
17
+ * Get the secrets file path for a stage.
18
+ */
19
+ export function getSecretsPath(stage: string, cwd = process.cwd()): string {
20
+ return join(getSecretsDir(cwd), `${stage}.json`);
21
+ }
22
+
23
+ /**
24
+ * Check if secrets exist for a stage.
25
+ */
26
+ export function secretsExist(stage: string, cwd = process.cwd()): boolean {
27
+ return existsSync(getSecretsPath(stage, cwd));
28
+ }
29
+
30
+ /**
31
+ * Read secrets for a stage.
32
+ * @returns StageSecrets or null if not found
33
+ */
34
+ export async function readStageSecrets(
35
+ stage: string,
36
+ cwd = process.cwd(),
37
+ ): Promise<StageSecrets | null> {
38
+ const path = getSecretsPath(stage, cwd);
39
+
40
+ if (!existsSync(path)) {
41
+ return null;
42
+ }
43
+
44
+ const content = await readFile(path, 'utf-8');
45
+ return JSON.parse(content) as StageSecrets;
46
+ }
47
+
48
+ /**
49
+ * Write secrets for a stage.
50
+ */
51
+ export async function writeStageSecrets(
52
+ secrets: StageSecrets,
53
+ cwd = process.cwd(),
54
+ ): Promise<void> {
55
+ const dir = getSecretsDir(cwd);
56
+ const path = getSecretsPath(secrets.stage, cwd);
57
+
58
+ // Ensure directory exists
59
+ await mkdir(dir, { recursive: true });
60
+
61
+ // Write with pretty formatting
62
+ await writeFile(path, JSON.stringify(secrets, null, 2), 'utf-8');
63
+ }
64
+
65
+ /**
66
+ * Convert StageSecrets to embeddable format (flat key-value pairs).
67
+ * This is what gets encrypted and embedded in the bundle.
68
+ */
69
+ export function toEmbeddableSecrets(secrets: StageSecrets): EmbeddableSecrets {
70
+ return {
71
+ ...secrets.urls,
72
+ ...secrets.custom,
73
+ // Also include individual service credentials if needed
74
+ ...(secrets.services.postgres && {
75
+ POSTGRES_USER: secrets.services.postgres.username,
76
+ POSTGRES_PASSWORD: secrets.services.postgres.password,
77
+ POSTGRES_DB: secrets.services.postgres.database ?? 'app',
78
+ POSTGRES_HOST: secrets.services.postgres.host,
79
+ POSTGRES_PORT: String(secrets.services.postgres.port),
80
+ }),
81
+ ...(secrets.services.redis && {
82
+ REDIS_PASSWORD: secrets.services.redis.password,
83
+ REDIS_HOST: secrets.services.redis.host,
84
+ REDIS_PORT: String(secrets.services.redis.port),
85
+ }),
86
+ ...(secrets.services.rabbitmq && {
87
+ RABBITMQ_USER: secrets.services.rabbitmq.username,
88
+ RABBITMQ_PASSWORD: secrets.services.rabbitmq.password,
89
+ RABBITMQ_HOST: secrets.services.rabbitmq.host,
90
+ RABBITMQ_PORT: String(secrets.services.rabbitmq.port),
91
+ RABBITMQ_VHOST: secrets.services.rabbitmq.vhost ?? '/',
92
+ }),
93
+ };
94
+ }
95
+
96
+ /**
97
+ * Update a custom secret in the secrets file.
98
+ */
99
+ export async function setCustomSecret(
100
+ stage: string,
101
+ key: string,
102
+ value: string,
103
+ cwd = process.cwd(),
104
+ ): Promise<StageSecrets> {
105
+ const secrets = await readStageSecrets(stage, cwd);
106
+
107
+ if (!secrets) {
108
+ throw new Error(
109
+ `Secrets not found for stage "${stage}". Run "gkm secrets:init --stage ${stage}" first.`,
110
+ );
111
+ }
112
+
113
+ const updated: StageSecrets = {
114
+ ...secrets,
115
+ updatedAt: new Date().toISOString(),
116
+ custom: {
117
+ ...secrets.custom,
118
+ [key]: value,
119
+ },
120
+ };
121
+
122
+ await writeStageSecrets(updated, cwd);
123
+ return updated;
124
+ }
125
+
126
+ /**
127
+ * Mask a password for display (show first 4 and last 2 chars).
128
+ */
129
+ export function maskPassword(password: string): string {
130
+ if (password.length <= 8) {
131
+ return '********';
132
+ }
133
+ return `${password.slice(0, 4)}${'*'.repeat(password.length - 6)}${password.slice(-2)}`;
134
+ }
135
+
136
+ /**
137
+ * Result of environment variable validation.
138
+ */
139
+ export interface EnvValidationResult {
140
+ /** Whether all required environment variables are present */
141
+ valid: boolean;
142
+ /** List of missing environment variable names */
143
+ missing: string[];
144
+ /** List of environment variables that are provided */
145
+ provided: string[];
146
+ /** List of environment variables that were required */
147
+ required: string[];
148
+ }
149
+
150
+ /**
151
+ * Validate that all required environment variables are present in secrets.
152
+ *
153
+ * @param requiredVars - Array of environment variable names required by the application
154
+ * @param secrets - Stage secrets to validate against
155
+ * @returns Validation result with missing and provided variables
156
+ *
157
+ * @example
158
+ * ```typescript
159
+ * const required = ['DATABASE_URL', 'API_KEY', 'JWT_SECRET'];
160
+ * const secrets = await readStageSecrets('production');
161
+ * const result = validateEnvironmentVariables(required, secrets);
162
+ *
163
+ * if (!result.valid) {
164
+ * console.error(`Missing environment variables: ${result.missing.join(', ')}`);
165
+ * }
166
+ * ```
167
+ */
168
+ export function validateEnvironmentVariables(
169
+ requiredVars: string[],
170
+ secrets: StageSecrets,
171
+ ): EnvValidationResult {
172
+ const embeddable = toEmbeddableSecrets(secrets);
173
+ const availableVars = new Set(Object.keys(embeddable));
174
+
175
+ const missing: string[] = [];
176
+ const provided: string[] = [];
177
+
178
+ for (const varName of requiredVars) {
179
+ if (availableVars.has(varName)) {
180
+ provided.push(varName);
181
+ } else {
182
+ missing.push(varName);
183
+ }
184
+ }
185
+
186
+ return {
187
+ valid: missing.length === 0,
188
+ missing: missing.sort(),
189
+ provided: provided.sort(),
190
+ required: [...requiredVars].sort(),
191
+ };
192
+ }
@@ -0,0 +1,53 @@
1
+ import type { ComposeServiceName } from '../types';
2
+
3
+ /** Credentials for a specific service */
4
+ export interface ServiceCredentials {
5
+ host: string;
6
+ port: number;
7
+ username: string;
8
+ password: string;
9
+ /** Database name (for postgres) */
10
+ database?: string;
11
+ /** Virtual host (for rabbitmq) */
12
+ vhost?: string;
13
+ }
14
+
15
+ /** Stage secrets configuration */
16
+ export interface StageSecrets {
17
+ /** Stage name (e.g., 'production', 'staging') */
18
+ stage: string;
19
+ /** ISO timestamp when secrets were created */
20
+ createdAt: string;
21
+ /** ISO timestamp when secrets were last updated */
22
+ updatedAt: string;
23
+ /** Service-specific credentials */
24
+ services: {
25
+ postgres?: ServiceCredentials;
26
+ redis?: ServiceCredentials;
27
+ rabbitmq?: ServiceCredentials;
28
+ };
29
+ /** Generated connection URLs */
30
+ urls: {
31
+ DATABASE_URL?: string;
32
+ REDIS_URL?: string;
33
+ RABBITMQ_URL?: string;
34
+ };
35
+ /** Custom user-defined secrets */
36
+ custom: Record<string, string>;
37
+ }
38
+
39
+ /** Encrypted payload for build-time injection */
40
+ export interface EncryptedPayload {
41
+ /** Base64 encoded encrypted data (ciphertext + auth tag) */
42
+ encrypted: string;
43
+ /** Hex encoded IV */
44
+ iv: string;
45
+ /** Hex encoded ephemeral master key (for deployment) */
46
+ masterKey: string;
47
+ }
48
+
49
+ /** Secrets that get encrypted and embedded in the bundle */
50
+ export type EmbeddableSecrets = Record<string, string>;
51
+
52
+ /** Services that support automatic credential generation */
53
+ export type SecretServiceName = ComposeServiceName;