@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,187 @@
1
+ const require_chunk = require('./chunk-CUT6urMc.cjs');
2
+ const node_fs = require_chunk.__toESM(require("node:fs"));
3
+ const node_path = require_chunk.__toESM(require("node:path"));
4
+ const node_fs_promises = require_chunk.__toESM(require("node:fs/promises"));
5
+
6
+ //#region src/secrets/storage.ts
7
+ /** Default secrets directory relative to project root */
8
+ const SECRETS_DIR = ".gkm/secrets";
9
+ /**
10
+ * Get the secrets directory path.
11
+ */
12
+ function getSecretsDir(cwd = process.cwd()) {
13
+ return (0, node_path.join)(cwd, SECRETS_DIR);
14
+ }
15
+ /**
16
+ * Get the secrets file path for a stage.
17
+ */
18
+ function getSecretsPath(stage, cwd = process.cwd()) {
19
+ return (0, node_path.join)(getSecretsDir(cwd), `${stage}.json`);
20
+ }
21
+ /**
22
+ * Check if secrets exist for a stage.
23
+ */
24
+ function secretsExist(stage, cwd = process.cwd()) {
25
+ return (0, node_fs.existsSync)(getSecretsPath(stage, cwd));
26
+ }
27
+ /**
28
+ * Read secrets for a stage.
29
+ * @returns StageSecrets or null if not found
30
+ */
31
+ async function readStageSecrets(stage, cwd = process.cwd()) {
32
+ const path = getSecretsPath(stage, cwd);
33
+ if (!(0, node_fs.existsSync)(path)) return null;
34
+ const content = await (0, node_fs_promises.readFile)(path, "utf-8");
35
+ return JSON.parse(content);
36
+ }
37
+ /**
38
+ * Write secrets for a stage.
39
+ */
40
+ async function writeStageSecrets(secrets, cwd = process.cwd()) {
41
+ const dir = getSecretsDir(cwd);
42
+ const path = getSecretsPath(secrets.stage, cwd);
43
+ await (0, node_fs_promises.mkdir)(dir, { recursive: true });
44
+ await (0, node_fs_promises.writeFile)(path, JSON.stringify(secrets, null, 2), "utf-8");
45
+ }
46
+ /**
47
+ * Convert StageSecrets to embeddable format (flat key-value pairs).
48
+ * This is what gets encrypted and embedded in the bundle.
49
+ */
50
+ function toEmbeddableSecrets(secrets) {
51
+ return {
52
+ ...secrets.urls,
53
+ ...secrets.custom,
54
+ ...secrets.services.postgres && {
55
+ POSTGRES_USER: secrets.services.postgres.username,
56
+ POSTGRES_PASSWORD: secrets.services.postgres.password,
57
+ POSTGRES_DB: secrets.services.postgres.database ?? "app",
58
+ POSTGRES_HOST: secrets.services.postgres.host,
59
+ POSTGRES_PORT: String(secrets.services.postgres.port)
60
+ },
61
+ ...secrets.services.redis && {
62
+ REDIS_PASSWORD: secrets.services.redis.password,
63
+ REDIS_HOST: secrets.services.redis.host,
64
+ REDIS_PORT: String(secrets.services.redis.port)
65
+ },
66
+ ...secrets.services.rabbitmq && {
67
+ RABBITMQ_USER: secrets.services.rabbitmq.username,
68
+ RABBITMQ_PASSWORD: secrets.services.rabbitmq.password,
69
+ RABBITMQ_HOST: secrets.services.rabbitmq.host,
70
+ RABBITMQ_PORT: String(secrets.services.rabbitmq.port),
71
+ RABBITMQ_VHOST: secrets.services.rabbitmq.vhost ?? "/"
72
+ }
73
+ };
74
+ }
75
+ /**
76
+ * Update a custom secret in the secrets file.
77
+ */
78
+ async function setCustomSecret(stage, key, value, cwd = process.cwd()) {
79
+ const secrets = await readStageSecrets(stage, cwd);
80
+ if (!secrets) throw new Error(`Secrets not found for stage "${stage}". Run "gkm secrets:init --stage ${stage}" first.`);
81
+ const updated = {
82
+ ...secrets,
83
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
84
+ custom: {
85
+ ...secrets.custom,
86
+ [key]: value
87
+ }
88
+ };
89
+ await writeStageSecrets(updated, cwd);
90
+ return updated;
91
+ }
92
+ /**
93
+ * Mask a password for display (show first 4 and last 2 chars).
94
+ */
95
+ function maskPassword(password) {
96
+ if (password.length <= 8) return "********";
97
+ return `${password.slice(0, 4)}${"*".repeat(password.length - 6)}${password.slice(-2)}`;
98
+ }
99
+ /**
100
+ * Validate that all required environment variables are present in secrets.
101
+ *
102
+ * @param requiredVars - Array of environment variable names required by the application
103
+ * @param secrets - Stage secrets to validate against
104
+ * @returns Validation result with missing and provided variables
105
+ *
106
+ * @example
107
+ * ```typescript
108
+ * const required = ['DATABASE_URL', 'API_KEY', 'JWT_SECRET'];
109
+ * const secrets = await readStageSecrets('production');
110
+ * const result = validateEnvironmentVariables(required, secrets);
111
+ *
112
+ * if (!result.valid) {
113
+ * console.error(`Missing environment variables: ${result.missing.join(', ')}`);
114
+ * }
115
+ * ```
116
+ */
117
+ function validateEnvironmentVariables(requiredVars, secrets) {
118
+ const embeddable = toEmbeddableSecrets(secrets);
119
+ const availableVars = new Set(Object.keys(embeddable));
120
+ const missing = [];
121
+ const provided = [];
122
+ for (const varName of requiredVars) if (availableVars.has(varName)) provided.push(varName);
123
+ else missing.push(varName);
124
+ return {
125
+ valid: missing.length === 0,
126
+ missing: missing.sort(),
127
+ provided: provided.sort(),
128
+ required: [...requiredVars].sort()
129
+ };
130
+ }
131
+
132
+ //#endregion
133
+ Object.defineProperty(exports, 'getSecretsDir', {
134
+ enumerable: true,
135
+ get: function () {
136
+ return getSecretsDir;
137
+ }
138
+ });
139
+ Object.defineProperty(exports, 'getSecretsPath', {
140
+ enumerable: true,
141
+ get: function () {
142
+ return getSecretsPath;
143
+ }
144
+ });
145
+ Object.defineProperty(exports, 'maskPassword', {
146
+ enumerable: true,
147
+ get: function () {
148
+ return maskPassword;
149
+ }
150
+ });
151
+ Object.defineProperty(exports, 'readStageSecrets', {
152
+ enumerable: true,
153
+ get: function () {
154
+ return readStageSecrets;
155
+ }
156
+ });
157
+ Object.defineProperty(exports, 'secretsExist', {
158
+ enumerable: true,
159
+ get: function () {
160
+ return secretsExist;
161
+ }
162
+ });
163
+ Object.defineProperty(exports, 'setCustomSecret', {
164
+ enumerable: true,
165
+ get: function () {
166
+ return setCustomSecret;
167
+ }
168
+ });
169
+ Object.defineProperty(exports, 'toEmbeddableSecrets', {
170
+ enumerable: true,
171
+ get: function () {
172
+ return toEmbeddableSecrets;
173
+ }
174
+ });
175
+ Object.defineProperty(exports, 'validateEnvironmentVariables', {
176
+ enumerable: true,
177
+ get: function () {
178
+ return validateEnvironmentVariables;
179
+ }
180
+ });
181
+ Object.defineProperty(exports, 'writeStageSecrets', {
182
+ enumerable: true,
183
+ get: function () {
184
+ return writeStageSecrets;
185
+ }
186
+ });
187
+ //# sourceMappingURL=storage-Bj1E26lU.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage-Bj1E26lU.cjs","names":["stage: string","secrets: StageSecrets","key: string","value: string","updated: StageSecrets","password: string","requiredVars: string[]","missing: string[]","provided: string[]"],"sources":["../src/secrets/storage.ts"],"sourcesContent":["import { existsSync } from 'node:fs';\nimport { mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport type { EmbeddableSecrets, StageSecrets } from './types';\n\n/** Default secrets directory relative to project root */\nconst SECRETS_DIR = '.gkm/secrets';\n\n/**\n * Get the secrets directory path.\n */\nexport function getSecretsDir(cwd = process.cwd()): string {\n\treturn join(cwd, SECRETS_DIR);\n}\n\n/**\n * Get the secrets file path for a stage.\n */\nexport function getSecretsPath(stage: string, cwd = process.cwd()): string {\n\treturn join(getSecretsDir(cwd), `${stage}.json`);\n}\n\n/**\n * Check if secrets exist for a stage.\n */\nexport function secretsExist(stage: string, cwd = process.cwd()): boolean {\n\treturn existsSync(getSecretsPath(stage, cwd));\n}\n\n/**\n * Read secrets for a stage.\n * @returns StageSecrets or null if not found\n */\nexport async function readStageSecrets(\n\tstage: string,\n\tcwd = process.cwd(),\n): Promise<StageSecrets | null> {\n\tconst path = getSecretsPath(stage, cwd);\n\n\tif (!existsSync(path)) {\n\t\treturn null;\n\t}\n\n\tconst content = await readFile(path, 'utf-8');\n\treturn JSON.parse(content) as StageSecrets;\n}\n\n/**\n * Write secrets for a stage.\n */\nexport async function writeStageSecrets(\n\tsecrets: StageSecrets,\n\tcwd = process.cwd(),\n): Promise<void> {\n\tconst dir = getSecretsDir(cwd);\n\tconst path = getSecretsPath(secrets.stage, cwd);\n\n\t// Ensure directory exists\n\tawait mkdir(dir, { recursive: true });\n\n\t// Write with pretty formatting\n\tawait writeFile(path, JSON.stringify(secrets, null, 2), 'utf-8');\n}\n\n/**\n * Convert StageSecrets to embeddable format (flat key-value pairs).\n * This is what gets encrypted and embedded in the bundle.\n */\nexport function toEmbeddableSecrets(secrets: StageSecrets): EmbeddableSecrets {\n\treturn {\n\t\t...secrets.urls,\n\t\t...secrets.custom,\n\t\t// Also include individual service credentials if needed\n\t\t...(secrets.services.postgres && {\n\t\t\tPOSTGRES_USER: secrets.services.postgres.username,\n\t\t\tPOSTGRES_PASSWORD: secrets.services.postgres.password,\n\t\t\tPOSTGRES_DB: secrets.services.postgres.database ?? 'app',\n\t\t\tPOSTGRES_HOST: secrets.services.postgres.host,\n\t\t\tPOSTGRES_PORT: String(secrets.services.postgres.port),\n\t\t}),\n\t\t...(secrets.services.redis && {\n\t\t\tREDIS_PASSWORD: secrets.services.redis.password,\n\t\t\tREDIS_HOST: secrets.services.redis.host,\n\t\t\tREDIS_PORT: String(secrets.services.redis.port),\n\t\t}),\n\t\t...(secrets.services.rabbitmq && {\n\t\t\tRABBITMQ_USER: secrets.services.rabbitmq.username,\n\t\t\tRABBITMQ_PASSWORD: secrets.services.rabbitmq.password,\n\t\t\tRABBITMQ_HOST: secrets.services.rabbitmq.host,\n\t\t\tRABBITMQ_PORT: String(secrets.services.rabbitmq.port),\n\t\t\tRABBITMQ_VHOST: secrets.services.rabbitmq.vhost ?? '/',\n\t\t}),\n\t};\n}\n\n/**\n * Update a custom secret in the secrets file.\n */\nexport async function setCustomSecret(\n\tstage: string,\n\tkey: string,\n\tvalue: string,\n\tcwd = process.cwd(),\n): Promise<StageSecrets> {\n\tconst secrets = await readStageSecrets(stage, cwd);\n\n\tif (!secrets) {\n\t\tthrow new Error(\n\t\t\t`Secrets not found for stage \"${stage}\". Run \"gkm secrets:init --stage ${stage}\" first.`,\n\t\t);\n\t}\n\n\tconst updated: StageSecrets = {\n\t\t...secrets,\n\t\tupdatedAt: new Date().toISOString(),\n\t\tcustom: {\n\t\t\t...secrets.custom,\n\t\t\t[key]: value,\n\t\t},\n\t};\n\n\tawait writeStageSecrets(updated, cwd);\n\treturn updated;\n}\n\n/**\n * Mask a password for display (show first 4 and last 2 chars).\n */\nexport function maskPassword(password: string): string {\n\tif (password.length <= 8) {\n\t\treturn '********';\n\t}\n\treturn `${password.slice(0, 4)}${'*'.repeat(password.length - 6)}${password.slice(-2)}`;\n}\n\n/**\n * Result of environment variable validation.\n */\nexport interface EnvValidationResult {\n\t/** Whether all required environment variables are present */\n\tvalid: boolean;\n\t/** List of missing environment variable names */\n\tmissing: string[];\n\t/** List of environment variables that are provided */\n\tprovided: string[];\n\t/** List of environment variables that were required */\n\trequired: string[];\n}\n\n/**\n * Validate that all required environment variables are present in secrets.\n *\n * @param requiredVars - Array of environment variable names required by the application\n * @param secrets - Stage secrets to validate against\n * @returns Validation result with missing and provided variables\n *\n * @example\n * ```typescript\n * const required = ['DATABASE_URL', 'API_KEY', 'JWT_SECRET'];\n * const secrets = await readStageSecrets('production');\n * const result = validateEnvironmentVariables(required, secrets);\n *\n * if (!result.valid) {\n * console.error(`Missing environment variables: ${result.missing.join(', ')}`);\n * }\n * ```\n */\nexport function validateEnvironmentVariables(\n\trequiredVars: string[],\n\tsecrets: StageSecrets,\n): EnvValidationResult {\n\tconst embeddable = toEmbeddableSecrets(secrets);\n\tconst availableVars = new Set(Object.keys(embeddable));\n\n\tconst missing: string[] = [];\n\tconst provided: string[] = [];\n\n\tfor (const varName of requiredVars) {\n\t\tif (availableVars.has(varName)) {\n\t\t\tprovided.push(varName);\n\t\t} else {\n\t\t\tmissing.push(varName);\n\t\t}\n\t}\n\n\treturn {\n\t\tvalid: missing.length === 0,\n\t\tmissing: missing.sort(),\n\t\tprovided: provided.sort(),\n\t\trequired: [...requiredVars].sort(),\n\t};\n}\n"],"mappings":"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"}
@@ -0,0 +1,133 @@
1
+ import { existsSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { mkdir, readFile, writeFile } from "node:fs/promises";
4
+
5
+ //#region src/secrets/storage.ts
6
+ /** Default secrets directory relative to project root */
7
+ const SECRETS_DIR = ".gkm/secrets";
8
+ /**
9
+ * Get the secrets directory path.
10
+ */
11
+ function getSecretsDir(cwd = process.cwd()) {
12
+ return join(cwd, SECRETS_DIR);
13
+ }
14
+ /**
15
+ * Get the secrets file path for a stage.
16
+ */
17
+ function getSecretsPath(stage, cwd = process.cwd()) {
18
+ return join(getSecretsDir(cwd), `${stage}.json`);
19
+ }
20
+ /**
21
+ * Check if secrets exist for a stage.
22
+ */
23
+ function secretsExist(stage, cwd = process.cwd()) {
24
+ return existsSync(getSecretsPath(stage, cwd));
25
+ }
26
+ /**
27
+ * Read secrets for a stage.
28
+ * @returns StageSecrets or null if not found
29
+ */
30
+ async function readStageSecrets(stage, cwd = process.cwd()) {
31
+ const path = getSecretsPath(stage, cwd);
32
+ if (!existsSync(path)) return null;
33
+ const content = await readFile(path, "utf-8");
34
+ return JSON.parse(content);
35
+ }
36
+ /**
37
+ * Write secrets for a stage.
38
+ */
39
+ async function writeStageSecrets(secrets, cwd = process.cwd()) {
40
+ const dir = getSecretsDir(cwd);
41
+ const path = getSecretsPath(secrets.stage, cwd);
42
+ await mkdir(dir, { recursive: true });
43
+ await writeFile(path, JSON.stringify(secrets, null, 2), "utf-8");
44
+ }
45
+ /**
46
+ * Convert StageSecrets to embeddable format (flat key-value pairs).
47
+ * This is what gets encrypted and embedded in the bundle.
48
+ */
49
+ function toEmbeddableSecrets(secrets) {
50
+ return {
51
+ ...secrets.urls,
52
+ ...secrets.custom,
53
+ ...secrets.services.postgres && {
54
+ POSTGRES_USER: secrets.services.postgres.username,
55
+ POSTGRES_PASSWORD: secrets.services.postgres.password,
56
+ POSTGRES_DB: secrets.services.postgres.database ?? "app",
57
+ POSTGRES_HOST: secrets.services.postgres.host,
58
+ POSTGRES_PORT: String(secrets.services.postgres.port)
59
+ },
60
+ ...secrets.services.redis && {
61
+ REDIS_PASSWORD: secrets.services.redis.password,
62
+ REDIS_HOST: secrets.services.redis.host,
63
+ REDIS_PORT: String(secrets.services.redis.port)
64
+ },
65
+ ...secrets.services.rabbitmq && {
66
+ RABBITMQ_USER: secrets.services.rabbitmq.username,
67
+ RABBITMQ_PASSWORD: secrets.services.rabbitmq.password,
68
+ RABBITMQ_HOST: secrets.services.rabbitmq.host,
69
+ RABBITMQ_PORT: String(secrets.services.rabbitmq.port),
70
+ RABBITMQ_VHOST: secrets.services.rabbitmq.vhost ?? "/"
71
+ }
72
+ };
73
+ }
74
+ /**
75
+ * Update a custom secret in the secrets file.
76
+ */
77
+ async function setCustomSecret(stage, key, value, cwd = process.cwd()) {
78
+ const secrets = await readStageSecrets(stage, cwd);
79
+ if (!secrets) throw new Error(`Secrets not found for stage "${stage}". Run "gkm secrets:init --stage ${stage}" first.`);
80
+ const updated = {
81
+ ...secrets,
82
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
83
+ custom: {
84
+ ...secrets.custom,
85
+ [key]: value
86
+ }
87
+ };
88
+ await writeStageSecrets(updated, cwd);
89
+ return updated;
90
+ }
91
+ /**
92
+ * Mask a password for display (show first 4 and last 2 chars).
93
+ */
94
+ function maskPassword(password) {
95
+ if (password.length <= 8) return "********";
96
+ return `${password.slice(0, 4)}${"*".repeat(password.length - 6)}${password.slice(-2)}`;
97
+ }
98
+ /**
99
+ * Validate that all required environment variables are present in secrets.
100
+ *
101
+ * @param requiredVars - Array of environment variable names required by the application
102
+ * @param secrets - Stage secrets to validate against
103
+ * @returns Validation result with missing and provided variables
104
+ *
105
+ * @example
106
+ * ```typescript
107
+ * const required = ['DATABASE_URL', 'API_KEY', 'JWT_SECRET'];
108
+ * const secrets = await readStageSecrets('production');
109
+ * const result = validateEnvironmentVariables(required, secrets);
110
+ *
111
+ * if (!result.valid) {
112
+ * console.error(`Missing environment variables: ${result.missing.join(', ')}`);
113
+ * }
114
+ * ```
115
+ */
116
+ function validateEnvironmentVariables(requiredVars, secrets) {
117
+ const embeddable = toEmbeddableSecrets(secrets);
118
+ const availableVars = new Set(Object.keys(embeddable));
119
+ const missing = [];
120
+ const provided = [];
121
+ for (const varName of requiredVars) if (availableVars.has(varName)) provided.push(varName);
122
+ else missing.push(varName);
123
+ return {
124
+ valid: missing.length === 0,
125
+ missing: missing.sort(),
126
+ provided: provided.sort(),
127
+ required: [...requiredVars].sort()
128
+ };
129
+ }
130
+
131
+ //#endregion
132
+ export { getSecretsDir, getSecretsPath, maskPassword, readStageSecrets, secretsExist, setCustomSecret, toEmbeddableSecrets, validateEnvironmentVariables, writeStageSecrets };
133
+ //# sourceMappingURL=storage-kSxTjkNb.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage-kSxTjkNb.mjs","names":["stage: string","secrets: StageSecrets","key: string","value: string","updated: StageSecrets","password: string","requiredVars: string[]","missing: string[]","provided: string[]"],"sources":["../src/secrets/storage.ts"],"sourcesContent":["import { existsSync } from 'node:fs';\nimport { mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport type { EmbeddableSecrets, StageSecrets } from './types';\n\n/** Default secrets directory relative to project root */\nconst SECRETS_DIR = '.gkm/secrets';\n\n/**\n * Get the secrets directory path.\n */\nexport function getSecretsDir(cwd = process.cwd()): string {\n\treturn join(cwd, SECRETS_DIR);\n}\n\n/**\n * Get the secrets file path for a stage.\n */\nexport function getSecretsPath(stage: string, cwd = process.cwd()): string {\n\treturn join(getSecretsDir(cwd), `${stage}.json`);\n}\n\n/**\n * Check if secrets exist for a stage.\n */\nexport function secretsExist(stage: string, cwd = process.cwd()): boolean {\n\treturn existsSync(getSecretsPath(stage, cwd));\n}\n\n/**\n * Read secrets for a stage.\n * @returns StageSecrets or null if not found\n */\nexport async function readStageSecrets(\n\tstage: string,\n\tcwd = process.cwd(),\n): Promise<StageSecrets | null> {\n\tconst path = getSecretsPath(stage, cwd);\n\n\tif (!existsSync(path)) {\n\t\treturn null;\n\t}\n\n\tconst content = await readFile(path, 'utf-8');\n\treturn JSON.parse(content) as StageSecrets;\n}\n\n/**\n * Write secrets for a stage.\n */\nexport async function writeStageSecrets(\n\tsecrets: StageSecrets,\n\tcwd = process.cwd(),\n): Promise<void> {\n\tconst dir = getSecretsDir(cwd);\n\tconst path = getSecretsPath(secrets.stage, cwd);\n\n\t// Ensure directory exists\n\tawait mkdir(dir, { recursive: true });\n\n\t// Write with pretty formatting\n\tawait writeFile(path, JSON.stringify(secrets, null, 2), 'utf-8');\n}\n\n/**\n * Convert StageSecrets to embeddable format (flat key-value pairs).\n * This is what gets encrypted and embedded in the bundle.\n */\nexport function toEmbeddableSecrets(secrets: StageSecrets): EmbeddableSecrets {\n\treturn {\n\t\t...secrets.urls,\n\t\t...secrets.custom,\n\t\t// Also include individual service credentials if needed\n\t\t...(secrets.services.postgres && {\n\t\t\tPOSTGRES_USER: secrets.services.postgres.username,\n\t\t\tPOSTGRES_PASSWORD: secrets.services.postgres.password,\n\t\t\tPOSTGRES_DB: secrets.services.postgres.database ?? 'app',\n\t\t\tPOSTGRES_HOST: secrets.services.postgres.host,\n\t\t\tPOSTGRES_PORT: String(secrets.services.postgres.port),\n\t\t}),\n\t\t...(secrets.services.redis && {\n\t\t\tREDIS_PASSWORD: secrets.services.redis.password,\n\t\t\tREDIS_HOST: secrets.services.redis.host,\n\t\t\tREDIS_PORT: String(secrets.services.redis.port),\n\t\t}),\n\t\t...(secrets.services.rabbitmq && {\n\t\t\tRABBITMQ_USER: secrets.services.rabbitmq.username,\n\t\t\tRABBITMQ_PASSWORD: secrets.services.rabbitmq.password,\n\t\t\tRABBITMQ_HOST: secrets.services.rabbitmq.host,\n\t\t\tRABBITMQ_PORT: String(secrets.services.rabbitmq.port),\n\t\t\tRABBITMQ_VHOST: secrets.services.rabbitmq.vhost ?? '/',\n\t\t}),\n\t};\n}\n\n/**\n * Update a custom secret in the secrets file.\n */\nexport async function setCustomSecret(\n\tstage: string,\n\tkey: string,\n\tvalue: string,\n\tcwd = process.cwd(),\n): Promise<StageSecrets> {\n\tconst secrets = await readStageSecrets(stage, cwd);\n\n\tif (!secrets) {\n\t\tthrow new Error(\n\t\t\t`Secrets not found for stage \"${stage}\". Run \"gkm secrets:init --stage ${stage}\" first.`,\n\t\t);\n\t}\n\n\tconst updated: StageSecrets = {\n\t\t...secrets,\n\t\tupdatedAt: new Date().toISOString(),\n\t\tcustom: {\n\t\t\t...secrets.custom,\n\t\t\t[key]: value,\n\t\t},\n\t};\n\n\tawait writeStageSecrets(updated, cwd);\n\treturn updated;\n}\n\n/**\n * Mask a password for display (show first 4 and last 2 chars).\n */\nexport function maskPassword(password: string): string {\n\tif (password.length <= 8) {\n\t\treturn '********';\n\t}\n\treturn `${password.slice(0, 4)}${'*'.repeat(password.length - 6)}${password.slice(-2)}`;\n}\n\n/**\n * Result of environment variable validation.\n */\nexport interface EnvValidationResult {\n\t/** Whether all required environment variables are present */\n\tvalid: boolean;\n\t/** List of missing environment variable names */\n\tmissing: string[];\n\t/** List of environment variables that are provided */\n\tprovided: string[];\n\t/** List of environment variables that were required */\n\trequired: string[];\n}\n\n/**\n * Validate that all required environment variables are present in secrets.\n *\n * @param requiredVars - Array of environment variable names required by the application\n * @param secrets - Stage secrets to validate against\n * @returns Validation result with missing and provided variables\n *\n * @example\n * ```typescript\n * const required = ['DATABASE_URL', 'API_KEY', 'JWT_SECRET'];\n * const secrets = await readStageSecrets('production');\n * const result = validateEnvironmentVariables(required, secrets);\n *\n * if (!result.valid) {\n * console.error(`Missing environment variables: ${result.missing.join(', ')}`);\n * }\n * ```\n */\nexport function validateEnvironmentVariables(\n\trequiredVars: string[],\n\tsecrets: StageSecrets,\n): EnvValidationResult {\n\tconst embeddable = toEmbeddableSecrets(secrets);\n\tconst availableVars = new Set(Object.keys(embeddable));\n\n\tconst missing: string[] = [];\n\tconst provided: string[] = [];\n\n\tfor (const varName of requiredVars) {\n\t\tif (availableVars.has(varName)) {\n\t\t\tprovided.push(varName);\n\t\t} else {\n\t\t\tmissing.push(varName);\n\t\t}\n\t}\n\n\treturn {\n\t\tvalid: missing.length === 0,\n\t\tmissing: missing.sort(),\n\t\tprovided: provided.sort(),\n\t\trequired: [...requiredVars].sort(),\n\t};\n}\n"],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { getSecretsDir, getSecretsPath, maskPassword, readStageSecrets, secretsExist, setCustomSecret, toEmbeddableSecrets, validateEnvironmentVariables, writeStageSecrets } from "./storage-kSxTjkNb.mjs";
2
+
3
+ export { readStageSecrets, toEmbeddableSecrets, validateEnvironmentVariables };
@@ -7,9 +7,81 @@ interface ProviderConfig {
7
7
  }
8
8
  interface AWSApiGatewayConfig extends ProviderConfig {}
9
9
  interface AWSLambdaConfig extends ProviderConfig {}
10
+ interface ProductionConfig {
11
+ /** Enable production mode (default: false) */
12
+ enabled?: boolean;
13
+ /** Bundle server into single file (default: true) */
14
+ bundle?: boolean;
15
+ /** Minify bundled output (default: true) */
16
+ minify?: boolean;
17
+ /** Health check endpoint path (default: '/health') */
18
+ healthCheck?: string;
19
+ /** Enable graceful shutdown handling (default: true) */
20
+ gracefulShutdown?: boolean;
21
+ /** Packages to exclude from bundling (default: []) */
22
+ external?: string[];
23
+ /** Include subscribers in production build (default: 'exclude' for serverless) */
24
+ subscribers?: 'include' | 'exclude';
25
+ /** Include OpenAPI spec in production (default: false) */
26
+ openapi?: boolean;
27
+ /**
28
+ * Enable build-time optimized handler generation (default: true)
29
+ * Generates specialized handlers based on endpoint tier:
30
+ * - minimal: Near-raw-Hono performance for simple endpoints
31
+ * - standard: Optimized handlers for auth/services
32
+ * - full: Uses HonoEndpoint.addRoutes for complex endpoints
33
+ */
34
+ optimizedHandlers?: boolean;
35
+ }
36
+ /** Service-specific configuration for docker-compose */
37
+ interface ServiceConfig {
38
+ /**
39
+ * Full Docker image reference (e.g., 'postgis/postgis:16-3.4-alpine').
40
+ * When specified, overrides the default image entirely.
41
+ */
42
+ image?: string;
43
+ /**
44
+ * Docker image version/tag (e.g., '15-alpine' for postgres).
45
+ * Only used when `image` is not specified.
46
+ */
47
+ version?: string;
48
+ }
49
+ /** Supported docker-compose service names */
50
+ type ComposeServiceName = 'postgres' | 'redis' | 'rabbitmq';
51
+ /** Services configuration - can be boolean (use defaults) or object with version */
52
+ type ComposeServicesConfig = { [K in ComposeServiceName]?: boolean | ServiceConfig };
53
+ interface DockerConfig {
54
+ /** Container registry URL (e.g., 'ghcr.io/myorg') */
55
+ registry?: string;
56
+ /** Docker image name (default: derived from package.json name) */
57
+ imageName?: string;
58
+ /** Base Docker image (default: 'node:22-alpine') */
59
+ baseImage?: string;
60
+ /** Container port (default: 3000) */
61
+ port?: number;
62
+ /** docker-compose services to include */
63
+ compose?: {
64
+ /**
65
+ * Services to include in docker-compose.
66
+ * Can be an object with service configs or an array of service names (legacy).
67
+ *
68
+ * @example Object format (recommended)
69
+ * services: {
70
+ * postgres: { version: '15-alpine' },
71
+ * redis: true, // use default version
72
+ * }
73
+ *
74
+ * @example Array format (legacy, uses default versions)
75
+ * services: ['postgres', 'redis']
76
+ */
77
+ services?: ComposeServicesConfig | ComposeServiceName[];
78
+ };
79
+ }
10
80
  interface ServerConfig extends ProviderConfig {
11
81
  enableOpenApi?: boolean;
12
82
  port?: number;
83
+ /** Production build configuration */
84
+ production?: ProductionConfig;
13
85
  }
14
86
  type Runtime = 'node' | 'bun';
15
87
  interface TelescopeConfig {
@@ -73,6 +145,17 @@ interface HooksConfig {
73
145
  */
74
146
  server?: string;
75
147
  }
148
+ /** Dokploy deployment configuration */
149
+ interface DokployProviderConfig {
150
+ /** Dokploy API endpoint (e.g., 'https://dokploy.example.com') */
151
+ endpoint: string;
152
+ /** Project ID in Dokploy */
153
+ projectId: string;
154
+ /** Application ID in Dokploy */
155
+ applicationId: string;
156
+ /** Container registry (overrides docker.registry if set) */
157
+ registry?: string;
158
+ }
76
159
  interface ProvidersConfig {
77
160
  aws?: {
78
161
  apiGateway?: {
@@ -85,6 +168,8 @@ interface ProvidersConfig {
85
168
  };
86
169
  };
87
170
  server?: boolean | ServerConfig;
171
+ /** Dokploy deployment configuration */
172
+ dokploy?: boolean | DokployProviderConfig;
88
173
  }
89
174
  interface GkmConfig {
90
175
  routes: Routes;
@@ -157,7 +242,21 @@ interface GkmConfig {
157
242
  * env: ['.env', '.env.local']
158
243
  */
159
244
  env?: string | string[];
245
+ /**
246
+ * Docker deployment configuration.
247
+ * Used by `gkm docker` and `gkm prepack` commands.
248
+ *
249
+ * @example
250
+ * docker: {
251
+ * registry: 'ghcr.io/myorg',
252
+ * imageName: 'my-api',
253
+ * compose: {
254
+ * services: ['postgres', 'redis']
255
+ * }
256
+ * }
257
+ */
258
+ docker?: DockerConfig;
160
259
  }
161
260
  //#endregion
162
261
  export { GkmConfig, OpenApiConfig };
163
- //# sourceMappingURL=types-b-vwGpqc.d.cts.map
262
+ //# sourceMappingURL=types-BR0M2v_c.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types-BR0M2v_c.d.mts","names":[],"sources":["../src/types.ts"],"sourcesContent":[],"mappings":";;AASiB,KAFL,MAAA,GAEmB,MAAA,GAAA,MAAA,EAAA;AAKd,UALA,cAAA,CAKoB;EAIpB,OAAA,CAAA,EAAA,OAAA;EAIA,SAAA,CAAA,EAAA,MAAA;AA4BjB;AAcY,UAlDK,mBAAA,SAA4B,cAkDf,CAAA,CAG9B;AAAiC,UAjDhB,eAAA,SAAwB,cAiDR,CAAA;AACM,UA9CtB,gBAAA,CA8CsB;EAAa;EAGnC,OAAA,CAAA,EAAA,OAAY;EAAA;EAAA,MAwBhB,CAAA,EAAA,OAAA;EAAqB;EAAqB,MAAA,CAAA,EAAA,OAAA;EAItC;EAAa,WAAA,CAAA,EAAA,MAAA;EAAA;EAIA,gBAJQ,CAAA,EAAA,OAAA;EAAc;EAOxC,QAAA,CAAA,EAAO,MAAA,EAAA;EAEF;EAiBA,WAAA,CAAA,EAAA,SAAY,GAAA,SAAA;EASZ;EAWA,OAAA,CAAA,EAAA,OAAW;EA6BX;AAWjB;;;;;;EAQoC,iBAGhB,CAAA,EAAA,OAAA;;AAEsB;AAGzB,UAvJA,aAAA,CAuJS;EAAA;;;;EAGX,KACA,CAAA,EAAA,MAAA;EAAM;;;;EA+BoB,OAmBpB,CAAA,EAAA,MAAA;;;AA8BC,KA7NV,kBAAA,GA6NU,UAAA,GAAA,OAAA,GAAA,UAAA;;KA1NV,qBAAA,WACL,gCAAgC;UAGtB,YAAA;;;;;;;;;;;;;;;;;;;;;;;;eAwBJ,wBAAwB;;;UAIpB,YAAA,SAAqB;;;;eAIxB;;KAGF,OAAA;UAEK,eAAA;;;;;;;;;;;;;;;;UAiBA,YAAA;;;;;;;;UASA,aAAA;;;;;;;;;;UAWA,WAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;UA6BA,qBAAA;;;;;;;;;;UAWA,eAAA;;;qBAGC;qBACA;;;4BAGO;wBACJ;;;qBAGD;;sBAEC;;UAGJ,SAAA;UACR;cACI;UACJ;gBACM;;;cAGF;;;;;;;;;;UAUJ;;;;;;;;iCAQuB;;;;;;;;;;8BAUH;;;;;;;;;;;;;;;;;;;sBAmBR;;YAEV;;;;;;;;;;;;;;;;;;;;;;;;;;;;WA4BD"}
@@ -7,9 +7,81 @@ interface ProviderConfig {
7
7
  }
8
8
  interface AWSApiGatewayConfig extends ProviderConfig {}
9
9
  interface AWSLambdaConfig extends ProviderConfig {}
10
+ interface ProductionConfig {
11
+ /** Enable production mode (default: false) */
12
+ enabled?: boolean;
13
+ /** Bundle server into single file (default: true) */
14
+ bundle?: boolean;
15
+ /** Minify bundled output (default: true) */
16
+ minify?: boolean;
17
+ /** Health check endpoint path (default: '/health') */
18
+ healthCheck?: string;
19
+ /** Enable graceful shutdown handling (default: true) */
20
+ gracefulShutdown?: boolean;
21
+ /** Packages to exclude from bundling (default: []) */
22
+ external?: string[];
23
+ /** Include subscribers in production build (default: 'exclude' for serverless) */
24
+ subscribers?: 'include' | 'exclude';
25
+ /** Include OpenAPI spec in production (default: false) */
26
+ openapi?: boolean;
27
+ /**
28
+ * Enable build-time optimized handler generation (default: true)
29
+ * Generates specialized handlers based on endpoint tier:
30
+ * - minimal: Near-raw-Hono performance for simple endpoints
31
+ * - standard: Optimized handlers for auth/services
32
+ * - full: Uses HonoEndpoint.addRoutes for complex endpoints
33
+ */
34
+ optimizedHandlers?: boolean;
35
+ }
36
+ /** Service-specific configuration for docker-compose */
37
+ interface ServiceConfig {
38
+ /**
39
+ * Full Docker image reference (e.g., 'postgis/postgis:16-3.4-alpine').
40
+ * When specified, overrides the default image entirely.
41
+ */
42
+ image?: string;
43
+ /**
44
+ * Docker image version/tag (e.g., '15-alpine' for postgres).
45
+ * Only used when `image` is not specified.
46
+ */
47
+ version?: string;
48
+ }
49
+ /** Supported docker-compose service names */
50
+ type ComposeServiceName = 'postgres' | 'redis' | 'rabbitmq';
51
+ /** Services configuration - can be boolean (use defaults) or object with version */
52
+ type ComposeServicesConfig = { [K in ComposeServiceName]?: boolean | ServiceConfig };
53
+ interface DockerConfig {
54
+ /** Container registry URL (e.g., 'ghcr.io/myorg') */
55
+ registry?: string;
56
+ /** Docker image name (default: derived from package.json name) */
57
+ imageName?: string;
58
+ /** Base Docker image (default: 'node:22-alpine') */
59
+ baseImage?: string;
60
+ /** Container port (default: 3000) */
61
+ port?: number;
62
+ /** docker-compose services to include */
63
+ compose?: {
64
+ /**
65
+ * Services to include in docker-compose.
66
+ * Can be an object with service configs or an array of service names (legacy).
67
+ *
68
+ * @example Object format (recommended)
69
+ * services: {
70
+ * postgres: { version: '15-alpine' },
71
+ * redis: true, // use default version
72
+ * }
73
+ *
74
+ * @example Array format (legacy, uses default versions)
75
+ * services: ['postgres', 'redis']
76
+ */
77
+ services?: ComposeServicesConfig | ComposeServiceName[];
78
+ };
79
+ }
10
80
  interface ServerConfig extends ProviderConfig {
11
81
  enableOpenApi?: boolean;
12
82
  port?: number;
83
+ /** Production build configuration */
84
+ production?: ProductionConfig;
13
85
  }
14
86
  type Runtime = 'node' | 'bun';
15
87
  interface TelescopeConfig {
@@ -73,6 +145,17 @@ interface HooksConfig {
73
145
  */
74
146
  server?: string;
75
147
  }
148
+ /** Dokploy deployment configuration */
149
+ interface DokployProviderConfig {
150
+ /** Dokploy API endpoint (e.g., 'https://dokploy.example.com') */
151
+ endpoint: string;
152
+ /** Project ID in Dokploy */
153
+ projectId: string;
154
+ /** Application ID in Dokploy */
155
+ applicationId: string;
156
+ /** Container registry (overrides docker.registry if set) */
157
+ registry?: string;
158
+ }
76
159
  interface ProvidersConfig {
77
160
  aws?: {
78
161
  apiGateway?: {
@@ -85,6 +168,8 @@ interface ProvidersConfig {
85
168
  };
86
169
  };
87
170
  server?: boolean | ServerConfig;
171
+ /** Dokploy deployment configuration */
172
+ dokploy?: boolean | DokployProviderConfig;
88
173
  }
89
174
  interface GkmConfig {
90
175
  routes: Routes;
@@ -157,7 +242,21 @@ interface GkmConfig {
157
242
  * env: ['.env', '.env.local']
158
243
  */
159
244
  env?: string | string[];
245
+ /**
246
+ * Docker deployment configuration.
247
+ * Used by `gkm docker` and `gkm prepack` commands.
248
+ *
249
+ * @example
250
+ * docker: {
251
+ * registry: 'ghcr.io/myorg',
252
+ * imageName: 'my-api',
253
+ * compose: {
254
+ * services: ['postgres', 'redis']
255
+ * }
256
+ * }
257
+ */
258
+ docker?: DockerConfig;
160
259
  }
161
260
  //#endregion
162
261
  export { GkmConfig, OpenApiConfig };
163
- //# sourceMappingURL=types-DXgiA1sF.d.mts.map
262
+ //# sourceMappingURL=types-BhkZc-vm.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types-BhkZc-vm.d.cts","names":[],"sources":["../src/types.ts"],"sourcesContent":[],"mappings":";;AASiB,KAFL,MAAA,GAEmB,MAAA,GAAA,MAAA,EAAA;AAKd,UALA,cAAA,CAKoB;EAIpB,OAAA,CAAA,EAAA,OAAA;EAIA,SAAA,CAAA,EAAA,MAAA;AA4BjB;AAcY,UAlDK,mBAAA,SAA4B,cAkDf,CAAA,CAG9B;AAAiC,UAjDhB,eAAA,SAAwB,cAiDR,CAAA;AACM,UA9CtB,gBAAA,CA8CsB;EAAa;EAGnC,OAAA,CAAA,EAAA,OAAY;EAAA;EAAA,MAwBhB,CAAA,EAAA,OAAA;EAAqB;EAAqB,MAAA,CAAA,EAAA,OAAA;EAItC;EAAa,WAAA,CAAA,EAAA,MAAA;EAAA;EAIA,gBAJQ,CAAA,EAAA,OAAA;EAAc;EAOxC,QAAA,CAAA,EAAO,MAAA,EAAA;EAEF;EAiBA,WAAA,CAAA,EAAA,SAAY,GAAA,SAAA;EASZ;EAWA,OAAA,CAAA,EAAA,OAAW;EA6BX;AAWjB;;;;;;EAQoC,iBAGhB,CAAA,EAAA,OAAA;;AAEsB;AAGzB,UAvJA,aAAA,CAuJS;EAAA;;;;EAGX,KACA,CAAA,EAAA,MAAA;EAAM;;;;EA+BoB,OAmBpB,CAAA,EAAA,MAAA;;;AA8BC,KA7NV,kBAAA,GA6NU,UAAA,GAAA,OAAA,GAAA,UAAA;;KA1NV,qBAAA,WACL,gCAAgC;UAGtB,YAAA;;;;;;;;;;;;;;;;;;;;;;;;eAwBJ,wBAAwB;;;UAIpB,YAAA,SAAqB;;;;eAIxB;;KAGF,OAAA;UAEK,eAAA;;;;;;;;;;;;;;;;UAiBA,YAAA;;;;;;;;UASA,aAAA;;;;;;;;;;UAWA,WAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;UA6BA,qBAAA;;;;;;;;;;UAWA,eAAA;;;qBAGC;qBACA;;;4BAGO;wBACJ;;;qBAGD;;sBAEC;;UAGJ,SAAA;UACR;cACI;UACJ;gBACM;;;cAGF;;;;;;;;;;UAUJ;;;;;;;;iCAQuB;;;;;;;;;;8BAUH;;;;;;;;;;;;;;;;;;;sBAmBR;;YAEV;;;;;;;;;;;;;;;;;;;;;;;;;;;;WA4BD"}