@geekmidas/cli 0.9.0 → 0.12.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-DRXCw_YR.mjs +70 -0
  3. package/dist/bundler-DRXCw_YR.mjs.map +1 -0
  4. package/dist/bundler-WsEvH_b2.cjs +71 -0
  5. package/dist/bundler-WsEvH_b2.cjs.map +1 -0
  6. package/dist/{config-CFls09Ey.cjs → config-AmInkU7k.cjs} +10 -8
  7. package/dist/config-AmInkU7k.cjs.map +1 -0
  8. package/dist/{config-Bq72aj8e.mjs → config-DYULeEv8.mjs} +6 -4
  9. package/dist/config-DYULeEv8.mjs.map +1 -0
  10. package/dist/config.cjs +1 -1
  11. package/dist/config.d.cts +2 -1
  12. package/dist/config.d.cts.map +1 -0
  13. package/dist/config.d.mts +2 -1
  14. package/dist/config.d.mts.map +1 -0
  15. package/dist/config.mjs +1 -1
  16. package/dist/encryption-C8H-38Yy.mjs +42 -0
  17. package/dist/encryption-C8H-38Yy.mjs.map +1 -0
  18. package/dist/encryption-Dyf_r1h-.cjs +44 -0
  19. package/dist/encryption-Dyf_r1h-.cjs.map +1 -0
  20. package/dist/index.cjs +2125 -184
  21. package/dist/index.cjs.map +1 -1
  22. package/dist/index.mjs +2143 -197
  23. package/dist/index.mjs.map +1 -1
  24. package/dist/{openapi--vOy9mo4.mjs → openapi-BfFlOBCG.mjs} +812 -49
  25. package/dist/openapi-BfFlOBCG.mjs.map +1 -0
  26. package/dist/{openapi-CHhTPief.cjs → openapi-Bt_1FDpT.cjs} +805 -42
  27. package/dist/openapi-Bt_1FDpT.cjs.map +1 -0
  28. package/dist/{openapi-react-query-o5iMi8tz.cjs → openapi-react-query-B-sNWHFU.cjs} +5 -5
  29. package/dist/openapi-react-query-B-sNWHFU.cjs.map +1 -0
  30. package/dist/{openapi-react-query-CcciaVu5.mjs → openapi-react-query-B6XTeGqS.mjs} +5 -5
  31. package/dist/openapi-react-query-B6XTeGqS.mjs.map +1 -0
  32. package/dist/openapi-react-query.cjs +1 -1
  33. package/dist/openapi-react-query.d.cts.map +1 -0
  34. package/dist/openapi-react-query.d.mts.map +1 -0
  35. package/dist/openapi-react-query.mjs +1 -1
  36. package/dist/openapi.cjs +2 -2
  37. package/dist/openapi.d.cts +1 -1
  38. package/dist/openapi.d.cts.map +1 -0
  39. package/dist/openapi.d.mts +1 -1
  40. package/dist/openapi.d.mts.map +1 -0
  41. package/dist/openapi.mjs +2 -2
  42. package/dist/storage-BUYQJgz7.cjs +4 -0
  43. package/dist/storage-BXoJvmv2.cjs +149 -0
  44. package/dist/storage-BXoJvmv2.cjs.map +1 -0
  45. package/dist/storage-C9PU_30f.mjs +101 -0
  46. package/dist/storage-C9PU_30f.mjs.map +1 -0
  47. package/dist/storage-DLJAYxzJ.mjs +3 -0
  48. package/dist/{types-b-vwGpqc.d.cts → types-BR0M2v_c.d.mts} +100 -1
  49. package/dist/types-BR0M2v_c.d.mts.map +1 -0
  50. package/dist/{types-DXgiA1sF.d.mts → types-BhkZc-vm.d.cts} +100 -1
  51. package/dist/types-BhkZc-vm.d.cts.map +1 -0
  52. package/examples/cron-example.ts +27 -27
  53. package/examples/env.ts +27 -27
  54. package/examples/function-example.ts +31 -31
  55. package/examples/gkm.config.json +20 -20
  56. package/examples/gkm.config.ts +8 -8
  57. package/examples/gkm.minimal.config.json +5 -5
  58. package/examples/gkm.production.config.json +25 -25
  59. package/examples/logger.ts +2 -2
  60. package/package.json +6 -6
  61. package/src/__tests__/EndpointGenerator.hooks.spec.ts +191 -191
  62. package/src/__tests__/config.spec.ts +55 -55
  63. package/src/__tests__/loadEnvFiles.spec.ts +93 -93
  64. package/src/__tests__/normalizeHooksConfig.spec.ts +58 -58
  65. package/src/__tests__/openapi-react-query.spec.ts +497 -497
  66. package/src/__tests__/openapi.spec.ts +428 -428
  67. package/src/__tests__/test-helpers.ts +77 -76
  68. package/src/auth/__tests__/credentials.spec.ts +204 -0
  69. package/src/auth/__tests__/index.spec.ts +168 -0
  70. package/src/auth/credentials.ts +187 -0
  71. package/src/auth/index.ts +226 -0
  72. package/src/build/__tests__/index-new.spec.ts +474 -474
  73. package/src/build/__tests__/manifests.spec.ts +333 -333
  74. package/src/build/bundler.ts +141 -0
  75. package/src/build/endpoint-analyzer.ts +236 -0
  76. package/src/build/handler-templates.ts +1253 -0
  77. package/src/build/index.ts +250 -179
  78. package/src/build/manifests.ts +52 -52
  79. package/src/build/providerResolver.ts +145 -145
  80. package/src/build/types.ts +64 -43
  81. package/src/config.ts +39 -37
  82. package/src/deploy/__tests__/docker.spec.ts +111 -0
  83. package/src/deploy/__tests__/dokploy.spec.ts +245 -0
  84. package/src/deploy/__tests__/init.spec.ts +662 -0
  85. package/src/deploy/docker.ts +128 -0
  86. package/src/deploy/dokploy.ts +204 -0
  87. package/src/deploy/index.ts +136 -0
  88. package/src/deploy/init.ts +484 -0
  89. package/src/deploy/types.ts +48 -0
  90. package/src/dev/__tests__/index.spec.ts +266 -266
  91. package/src/dev/index.ts +647 -593
  92. package/src/docker/__tests__/compose.spec.ts +531 -0
  93. package/src/docker/__tests__/templates.spec.ts +280 -0
  94. package/src/docker/compose.ts +273 -0
  95. package/src/docker/index.ts +230 -0
  96. package/src/docker/templates.ts +446 -0
  97. package/src/generators/CronGenerator.ts +72 -72
  98. package/src/generators/EndpointGenerator.ts +699 -398
  99. package/src/generators/FunctionGenerator.ts +84 -84
  100. package/src/generators/Generator.ts +72 -72
  101. package/src/generators/OpenApiTsGenerator.ts +589 -589
  102. package/src/generators/SubscriberGenerator.ts +124 -124
  103. package/src/generators/__tests__/CronGenerator.spec.ts +433 -433
  104. package/src/generators/__tests__/EndpointGenerator.spec.ts +532 -382
  105. package/src/generators/__tests__/FunctionGenerator.spec.ts +244 -244
  106. package/src/generators/__tests__/SubscriberGenerator.spec.ts +397 -382
  107. package/src/generators/index.ts +4 -4
  108. package/src/index.ts +628 -206
  109. package/src/init/__tests__/generators.spec.ts +334 -334
  110. package/src/init/__tests__/init.spec.ts +332 -332
  111. package/src/init/__tests__/utils.spec.ts +89 -89
  112. package/src/init/generators/config.ts +175 -175
  113. package/src/init/generators/docker.ts +41 -41
  114. package/src/init/generators/env.ts +72 -72
  115. package/src/init/generators/index.ts +1 -1
  116. package/src/init/generators/models.ts +64 -64
  117. package/src/init/generators/monorepo.ts +161 -161
  118. package/src/init/generators/package.ts +71 -71
  119. package/src/init/generators/source.ts +6 -6
  120. package/src/init/index.ts +203 -208
  121. package/src/init/templates/api.ts +115 -115
  122. package/src/init/templates/index.ts +75 -75
  123. package/src/init/templates/minimal.ts +98 -98
  124. package/src/init/templates/serverless.ts +89 -89
  125. package/src/init/templates/worker.ts +98 -98
  126. package/src/init/utils.ts +54 -56
  127. package/src/openapi-react-query.ts +194 -194
  128. package/src/openapi.ts +63 -63
  129. package/src/secrets/__tests__/encryption.spec.ts +226 -0
  130. package/src/secrets/__tests__/generator.spec.ts +319 -0
  131. package/src/secrets/__tests__/index.spec.ts +91 -0
  132. package/src/secrets/__tests__/storage.spec.ts +403 -0
  133. package/src/secrets/encryption.ts +91 -0
  134. package/src/secrets/generator.ts +164 -0
  135. package/src/secrets/index.ts +383 -0
  136. package/src/secrets/storage.ts +134 -0
  137. package/src/secrets/types.ts +53 -0
  138. package/src/types.ts +295 -176
  139. package/tsconfig.json +9 -0
  140. package/tsdown.config.ts +11 -8
  141. package/dist/config-Bq72aj8e.mjs.map +0 -1
  142. package/dist/config-CFls09Ey.cjs.map +0 -1
  143. package/dist/openapi--vOy9mo4.mjs.map +0 -1
  144. package/dist/openapi-CHhTPief.cjs.map +0 -1
  145. package/dist/openapi-react-query-CcciaVu5.mjs.map +0 -1
  146. package/dist/openapi-react-query-o5iMi8tz.cjs.map +0 -1
@@ -0,0 +1,149 @@
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
+ //#endregion
101
+ Object.defineProperty(exports, 'getSecretsDir', {
102
+ enumerable: true,
103
+ get: function () {
104
+ return getSecretsDir;
105
+ }
106
+ });
107
+ Object.defineProperty(exports, 'getSecretsPath', {
108
+ enumerable: true,
109
+ get: function () {
110
+ return getSecretsPath;
111
+ }
112
+ });
113
+ Object.defineProperty(exports, 'maskPassword', {
114
+ enumerable: true,
115
+ get: function () {
116
+ return maskPassword;
117
+ }
118
+ });
119
+ Object.defineProperty(exports, 'readStageSecrets', {
120
+ enumerable: true,
121
+ get: function () {
122
+ return readStageSecrets;
123
+ }
124
+ });
125
+ Object.defineProperty(exports, 'secretsExist', {
126
+ enumerable: true,
127
+ get: function () {
128
+ return secretsExist;
129
+ }
130
+ });
131
+ Object.defineProperty(exports, 'setCustomSecret', {
132
+ enumerable: true,
133
+ get: function () {
134
+ return setCustomSecret;
135
+ }
136
+ });
137
+ Object.defineProperty(exports, 'toEmbeddableSecrets', {
138
+ enumerable: true,
139
+ get: function () {
140
+ return toEmbeddableSecrets;
141
+ }
142
+ });
143
+ Object.defineProperty(exports, 'writeStageSecrets', {
144
+ enumerable: true,
145
+ get: function () {
146
+ return writeStageSecrets;
147
+ }
148
+ });
149
+ //# sourceMappingURL=storage-BXoJvmv2.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage-BXoJvmv2.cjs","names":["stage: string","secrets: StageSecrets","key: string","value: string","updated: StageSecrets","password: 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"],"mappings":";;;;;;;AAMA,MAAM,cAAc;;;;AAKpB,SAAgB,cAAc,MAAM,QAAQ,KAAK,EAAU;AAC1D,QAAO,oBAAK,KAAK,YAAY;AAC7B;;;;AAKD,SAAgB,eAAeA,OAAe,MAAM,QAAQ,KAAK,EAAU;AAC1E,QAAO,oBAAK,cAAc,IAAI,GAAG,EAAE,MAAM,OAAO;AAChD;;;;AAKD,SAAgB,aAAaA,OAAe,MAAM,QAAQ,KAAK,EAAW;AACzE,QAAO,wBAAW,eAAe,OAAO,IAAI,CAAC;AAC7C;;;;;AAMD,eAAsB,iBACrBA,OACA,MAAM,QAAQ,KAAK,EACY;CAC/B,MAAM,OAAO,eAAe,OAAO,IAAI;AAEvC,MAAK,wBAAW,KAAK,CACpB,QAAO;CAGR,MAAM,UAAU,MAAM,+BAAS,MAAM,QAAQ;AAC7C,QAAO,KAAK,MAAM,QAAQ;AAC1B;;;;AAKD,eAAsB,kBACrBC,SACA,MAAM,QAAQ,KAAK,EACH;CAChB,MAAM,MAAM,cAAc,IAAI;CAC9B,MAAM,OAAO,eAAe,QAAQ,OAAO,IAAI;AAG/C,OAAM,4BAAM,KAAK,EAAE,WAAW,KAAM,EAAC;AAGrC,OAAM,gCAAU,MAAM,KAAK,UAAU,SAAS,MAAM,EAAE,EAAE,QAAQ;AAChE;;;;;AAMD,SAAgB,oBAAoBA,SAA0C;AAC7E,QAAO;EACN,GAAG,QAAQ;EACX,GAAG,QAAQ;EAEX,GAAI,QAAQ,SAAS,YAAY;GAChC,eAAe,QAAQ,SAAS,SAAS;GACzC,mBAAmB,QAAQ,SAAS,SAAS;GAC7C,aAAa,QAAQ,SAAS,SAAS,YAAY;GACnD,eAAe,QAAQ,SAAS,SAAS;GACzC,eAAe,OAAO,QAAQ,SAAS,SAAS,KAAK;EACrD;EACD,GAAI,QAAQ,SAAS,SAAS;GAC7B,gBAAgB,QAAQ,SAAS,MAAM;GACvC,YAAY,QAAQ,SAAS,MAAM;GACnC,YAAY,OAAO,QAAQ,SAAS,MAAM,KAAK;EAC/C;EACD,GAAI,QAAQ,SAAS,YAAY;GAChC,eAAe,QAAQ,SAAS,SAAS;GACzC,mBAAmB,QAAQ,SAAS,SAAS;GAC7C,eAAe,QAAQ,SAAS,SAAS;GACzC,eAAe,OAAO,QAAQ,SAAS,SAAS,KAAK;GACrD,gBAAgB,QAAQ,SAAS,SAAS,SAAS;EACnD;CACD;AACD;;;;AAKD,eAAsB,gBACrBD,OACAE,KACAC,OACA,MAAM,QAAQ,KAAK,EACK;CACxB,MAAM,UAAU,MAAM,iBAAiB,OAAO,IAAI;AAElD,MAAK,QACJ,OAAM,IAAI,OACR,+BAA+B,MAAM,mCAAmC,MAAM;CAIjF,MAAMC,UAAwB;EAC7B,GAAG;EACH,WAAW,qBAAI,QAAO,aAAa;EACnC,QAAQ;GACP,GAAG,QAAQ;IACV,MAAM;EACP;CACD;AAED,OAAM,kBAAkB,SAAS,IAAI;AACrC,QAAO;AACP;;;;AAKD,SAAgB,aAAaC,UAA0B;AACtD,KAAI,SAAS,UAAU,EACtB,QAAO;AAER,SAAQ,EAAE,SAAS,MAAM,GAAG,EAAE,CAAC,EAAE,IAAI,OAAO,SAAS,SAAS,EAAE,CAAC,EAAE,SAAS,MAAM,GAAG,CAAC;AACtF"}
@@ -0,0 +1,101 @@
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
+ //#endregion
100
+ export { getSecretsDir, getSecretsPath, maskPassword, readStageSecrets, secretsExist, setCustomSecret, toEmbeddableSecrets, writeStageSecrets };
101
+ //# sourceMappingURL=storage-C9PU_30f.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage-C9PU_30f.mjs","names":["stage: string","secrets: StageSecrets","key: string","value: string","updated: StageSecrets","password: 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"],"mappings":";;;;;;AAMA,MAAM,cAAc;;;;AAKpB,SAAgB,cAAc,MAAM,QAAQ,KAAK,EAAU;AAC1D,QAAO,KAAK,KAAK,YAAY;AAC7B;;;;AAKD,SAAgB,eAAeA,OAAe,MAAM,QAAQ,KAAK,EAAU;AAC1E,QAAO,KAAK,cAAc,IAAI,GAAG,EAAE,MAAM,OAAO;AAChD;;;;AAKD,SAAgB,aAAaA,OAAe,MAAM,QAAQ,KAAK,EAAW;AACzE,QAAO,WAAW,eAAe,OAAO,IAAI,CAAC;AAC7C;;;;;AAMD,eAAsB,iBACrBA,OACA,MAAM,QAAQ,KAAK,EACY;CAC/B,MAAM,OAAO,eAAe,OAAO,IAAI;AAEvC,MAAK,WAAW,KAAK,CACpB,QAAO;CAGR,MAAM,UAAU,MAAM,SAAS,MAAM,QAAQ;AAC7C,QAAO,KAAK,MAAM,QAAQ;AAC1B;;;;AAKD,eAAsB,kBACrBC,SACA,MAAM,QAAQ,KAAK,EACH;CAChB,MAAM,MAAM,cAAc,IAAI;CAC9B,MAAM,OAAO,eAAe,QAAQ,OAAO,IAAI;AAG/C,OAAM,MAAM,KAAK,EAAE,WAAW,KAAM,EAAC;AAGrC,OAAM,UAAU,MAAM,KAAK,UAAU,SAAS,MAAM,EAAE,EAAE,QAAQ;AAChE;;;;;AAMD,SAAgB,oBAAoBA,SAA0C;AAC7E,QAAO;EACN,GAAG,QAAQ;EACX,GAAG,QAAQ;EAEX,GAAI,QAAQ,SAAS,YAAY;GAChC,eAAe,QAAQ,SAAS,SAAS;GACzC,mBAAmB,QAAQ,SAAS,SAAS;GAC7C,aAAa,QAAQ,SAAS,SAAS,YAAY;GACnD,eAAe,QAAQ,SAAS,SAAS;GACzC,eAAe,OAAO,QAAQ,SAAS,SAAS,KAAK;EACrD;EACD,GAAI,QAAQ,SAAS,SAAS;GAC7B,gBAAgB,QAAQ,SAAS,MAAM;GACvC,YAAY,QAAQ,SAAS,MAAM;GACnC,YAAY,OAAO,QAAQ,SAAS,MAAM,KAAK;EAC/C;EACD,GAAI,QAAQ,SAAS,YAAY;GAChC,eAAe,QAAQ,SAAS,SAAS;GACzC,mBAAmB,QAAQ,SAAS,SAAS;GAC7C,eAAe,QAAQ,SAAS,SAAS;GACzC,eAAe,OAAO,QAAQ,SAAS,SAAS,KAAK;GACrD,gBAAgB,QAAQ,SAAS,SAAS,SAAS;EACnD;CACD;AACD;;;;AAKD,eAAsB,gBACrBD,OACAE,KACAC,OACA,MAAM,QAAQ,KAAK,EACK;CACxB,MAAM,UAAU,MAAM,iBAAiB,OAAO,IAAI;AAElD,MAAK,QACJ,OAAM,IAAI,OACR,+BAA+B,MAAM,mCAAmC,MAAM;CAIjF,MAAMC,UAAwB;EAC7B,GAAG;EACH,WAAW,qBAAI,QAAO,aAAa;EACnC,QAAQ;GACP,GAAG,QAAQ;IACV,MAAM;EACP;CACD;AAED,OAAM,kBAAkB,SAAS,IAAI;AACrC,QAAO;AACP;;;;AAKD,SAAgB,aAAaC,UAA0B;AACtD,KAAI,SAAS,UAAU,EACtB,QAAO;AAER,SAAQ,EAAE,SAAS,MAAM,GAAG,EAAE,CAAC,EAAE,IAAI,OAAO,SAAS,SAAS,EAAE,CAAC,EAAE,SAAS,MAAM,GAAG,CAAC;AACtF"}
@@ -0,0 +1,3 @@
1
+ import { getSecretsDir, getSecretsPath, maskPassword, readStageSecrets, secretsExist, setCustomSecret, toEmbeddableSecrets, writeStageSecrets } from "./storage-C9PU_30f.mjs";
2
+
3
+ export { readStageSecrets, toEmbeddableSecrets };
@@ -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"}
@@ -4,42 +4,42 @@ import { cron } from '@geekmidas/constructs/crons';
4
4
  * Example cron that generates a daily report at 9 AM UTC
5
5
  */
6
6
  export const dailyReport = cron
7
- .schedule('cron(0 9 * * ? *)')
8
- .timeout(600000) // 10 minutes
9
- .handle(async ({ services, logger }) => {
10
- logger.info('Generating daily report');
7
+ .schedule('cron(0 9 * * ? *)')
8
+ .timeout(600000) // 10 minutes
9
+ .handle(async ({ services, logger }) => {
10
+ logger.info('Generating daily report');
11
11
 
12
- const reportDate = new Date().toISOString().split('T')[0];
12
+ const reportDate = new Date().toISOString().split('T')[0];
13
13
 
14
- // Generate report logic here
15
- const reportData = {
16
- date: reportDate,
17
- totalOrders: 150,
18
- totalRevenue: 12500.0,
19
- topProducts: [
20
- { id: 'prod-1', name: 'Widget A', sales: 45 },
21
- { id: 'prod-2', name: 'Widget B', sales: 32 },
22
- ],
23
- };
14
+ // Generate report logic here
15
+ const reportData = {
16
+ date: reportDate,
17
+ totalOrders: 150,
18
+ totalRevenue: 12500.0,
19
+ topProducts: [
20
+ { id: 'prod-1', name: 'Widget A', sales: 45 },
21
+ { id: 'prod-2', name: 'Widget B', sales: 32 },
22
+ ],
23
+ };
24
24
 
25
- logger.info('Daily report generated', reportData);
25
+ logger.info('Daily report generated', reportData);
26
26
 
27
- return reportData;
28
- });
27
+ return reportData;
28
+ });
29
29
 
30
30
  /**
31
31
  * Example cron that runs every hour
32
32
  */
33
33
  export const hourlyCleanup = cron
34
- .schedule('rate(1 hour)')
35
- .timeout(300000) // 5 minutes
36
- .handle(async ({ services, logger }) => {
37
- logger.info('Running hourly cleanup');
34
+ .schedule('rate(1 hour)')
35
+ .timeout(300000) // 5 minutes
36
+ .handle(async ({ services, logger }) => {
37
+ logger.info('Running hourly cleanup');
38
38
 
39
- // Cleanup logic here
40
- const itemsCleaned = 42;
39
+ // Cleanup logic here
40
+ const itemsCleaned = 42;
41
41
 
42
- logger.info(`Cleaned ${itemsCleaned} items`);
42
+ logger.info(`Cleaned ${itemsCleaned} items`);
43
43
 
44
- return { itemsCleaned };
45
- });
44
+ return { itemsCleaned };
45
+ });