@geekmidas/cli 1.10.41 → 1.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 (115) hide show
  1. package/CHANGELOG.md +149 -0
  2. package/README.md +14 -0
  3. package/dist/{CachedStateProvider-37pG1HBx.cjs → CachedStateProvider-BdX7klRc.cjs} +1 -1
  4. package/dist/{CachedStateProvider-C8A-cCm5.mjs → CachedStateProvider-CzyFct42.mjs} +1 -1
  5. package/dist/{CachedStateProvider-C8A-cCm5.mjs.map → CachedStateProvider-CzyFct42.mjs.map} +1 -1
  6. package/dist/CachedStateProvider-GcGziXh1.mjs +3 -0
  7. package/dist/{CachedStateProvider-CxsXOKkg.cjs → CachedStateProvider-klLWZXWF.cjs} +1 -1
  8. package/dist/{CachedStateProvider-CxsXOKkg.cjs.map → CachedStateProvider-klLWZXWF.cjs.map} +1 -1
  9. package/dist/{HostingerProvider-ANWchdiK.mjs → HostingerProvider-B2ZYz7Yc.mjs} +1 -1
  10. package/dist/{HostingerProvider-ANWchdiK.mjs.map → HostingerProvider-B2ZYz7Yc.mjs.map} +1 -1
  11. package/dist/{HostingerProvider-5KYmwoK2.cjs → HostingerProvider-CrHfsgz9.cjs} +1 -1
  12. package/dist/{HostingerProvider-5KYmwoK2.cjs.map → HostingerProvider-CrHfsgz9.cjs.map} +1 -1
  13. package/dist/{LocalStateProvider-Dp0KkRcw.mjs → LocalStateProvider-CP49rjzt.mjs} +1 -1
  14. package/dist/{LocalStateProvider-Dp0KkRcw.mjs.map → LocalStateProvider-CP49rjzt.mjs.map} +1 -1
  15. package/dist/{LocalStateProvider-CLifRC0Y.cjs → LocalStateProvider-CalzNfNA.cjs} +1 -1
  16. package/dist/{LocalStateProvider-CLifRC0Y.cjs.map → LocalStateProvider-CalzNfNA.cjs.map} +1 -1
  17. package/dist/{Route53Provider-owQQ4pn6.cjs → Route53Provider-DwgXiLxt.cjs} +1 -1
  18. package/dist/{Route53Provider-owQQ4pn6.cjs.map → Route53Provider-DwgXiLxt.cjs.map} +1 -1
  19. package/dist/{Route53Provider-QoPgcXxn.mjs → Route53Provider-tlgBzrRQ.mjs} +1 -1
  20. package/dist/{Route53Provider-QoPgcXxn.mjs.map → Route53Provider-tlgBzrRQ.mjs.map} +1 -1
  21. package/dist/{SSMStateProvider-CksOTB8M.mjs → SSMStateProvider-BlrTiV5m.mjs} +1 -1
  22. package/dist/{SSMStateProvider-CksOTB8M.mjs.map → SSMStateProvider-BlrTiV5m.mjs.map} +1 -1
  23. package/dist/{SSMStateProvider-CT8tjl9o.cjs → SSMStateProvider-Bt6r8CTL.cjs} +1 -1
  24. package/dist/{SSMStateProvider-CT8tjl9o.cjs.map → SSMStateProvider-Bt6r8CTL.cjs.map} +1 -1
  25. package/dist/{backup-provisioner-C4noe75O.cjs → backup-provisioner-B3HBN-2k.cjs} +1 -1
  26. package/dist/{backup-provisioner-C4noe75O.cjs.map → backup-provisioner-B3HBN-2k.cjs.map} +1 -1
  27. package/dist/{backup-provisioner-BEXoHTuC.mjs → backup-provisioner-Xunq-p_8.mjs} +1 -1
  28. package/dist/{backup-provisioner-BEXoHTuC.mjs.map → backup-provisioner-Xunq-p_8.mjs.map} +1 -1
  29. package/dist/{bundler-c6QvGUBM.mjs → bundler-DkA4qzUD.mjs} +2 -2
  30. package/dist/{bundler-c6QvGUBM.mjs.map → bundler-DkA4qzUD.mjs.map} +1 -1
  31. package/dist/{bundler-BG6P249p.cjs → bundler-Dufq3uvI.cjs} +2 -2
  32. package/dist/{bundler-BG6P249p.cjs.map → bundler-Dufq3uvI.cjs.map} +1 -1
  33. package/dist/config.d.cts +2 -2
  34. package/dist/config.d.mts +2 -2
  35. package/dist/dokploy-api-BPYkG-ZZ.cjs +3 -0
  36. package/dist/dokploy-api-BiSzWM4v.mjs +3 -0
  37. package/dist/{dokploy-api-Dvyq-LsM.cjs → dokploy-api-CqOIKHme.cjs} +1 -1
  38. package/dist/{dokploy-api-Dvyq-LsM.cjs.map → dokploy-api-CqOIKHme.cjs.map} +1 -1
  39. package/dist/{dokploy-api-BIT0683o.mjs → dokploy-api-sfZFlWuE.mjs} +1 -1
  40. package/dist/{dokploy-api-BIT0683o.mjs.map → dokploy-api-sfZFlWuE.mjs.map} +1 -1
  41. package/dist/{encryption-CipsS0KW.cjs → encryption-BVS7Vmzs.cjs} +1 -1
  42. package/dist/encryption-Bd_m4q3g.mjs +3 -0
  43. package/dist/{encryption-DSkIlEZ6.mjs → encryption-CO5Q4Bhf.mjs} +1 -1
  44. package/dist/{encryption-DSkIlEZ6.mjs.map → encryption-CO5Q4Bhf.mjs.map} +1 -1
  45. package/dist/{encryption-DgKS-Dv9.cjs → encryption-MfXAiFTm.cjs} +1 -1
  46. package/dist/{encryption-DgKS-Dv9.cjs.map → encryption-MfXAiFTm.cjs.map} +1 -1
  47. package/dist/{index-BBvGMG_A.d.mts → index-Bw548Bta.d.mts} +2 -2
  48. package/dist/{index-Dz2a7xQU.d.cts.map → index-Bw548Bta.d.mts.map} +1 -1
  49. package/dist/{index-Dz2a7xQU.d.cts → index-DTpkeFb8.d.cts} +2 -2
  50. package/dist/{index-BBvGMG_A.d.mts.map → index-DTpkeFb8.d.cts.map} +1 -1
  51. package/dist/index.cjs +863 -1330
  52. package/dist/index.cjs.map +1 -1
  53. package/dist/index.mjs +990 -1457
  54. package/dist/index.mjs.map +1 -1
  55. package/dist/{openapi-DHp49UJV.cjs → openapi-BzNOC7_i.cjs} +14 -2
  56. package/dist/openapi-BzNOC7_i.cjs.map +1 -0
  57. package/dist/{openapi-DF9GyhyZ.mjs → openapi-Cfwi0fqF.mjs} +14 -2
  58. package/dist/openapi-Cfwi0fqF.mjs.map +1 -0
  59. package/dist/{openapi-react-query-C4UdILaI.mjs → openapi-react-query-C4iIvpPf.mjs} +1 -1
  60. package/dist/{openapi-react-query-C4UdILaI.mjs.map → openapi-react-query-C4iIvpPf.mjs.map} +1 -1
  61. package/dist/{openapi-react-query-DYbBq-WJ.cjs → openapi-react-query-CYWik72n.cjs} +1 -1
  62. package/dist/{openapi-react-query-DYbBq-WJ.cjs.map → openapi-react-query-CYWik72n.cjs.map} +1 -1
  63. package/dist/openapi-react-query.cjs +1 -1
  64. package/dist/openapi-react-query.mjs +1 -1
  65. package/dist/openapi.cjs +1 -1
  66. package/dist/openapi.d.cts +1 -1
  67. package/dist/openapi.d.mts +1 -1
  68. package/dist/openapi.mjs +1 -1
  69. package/dist/{reconcile-CYGmqXvq.mjs → reconcile-B2FoJE0a.mjs} +1 -1
  70. package/dist/{reconcile-CYGmqXvq.mjs.map → reconcile-B2FoJE0a.mjs.map} +1 -1
  71. package/dist/{reconcile-D93YG7G5.cjs → reconcile-BzqKJ2Rt.cjs} +1 -1
  72. package/dist/{reconcile-D93YG7G5.cjs.map → reconcile-BzqKJ2Rt.cjs.map} +1 -1
  73. package/dist/setup-DDXUXzzl.mjs +765 -0
  74. package/dist/setup-DDXUXzzl.mjs.map +1 -0
  75. package/dist/setup-DLwhfyt-.cjs +8 -0
  76. package/dist/setup-Dh-B7YTX.mjs +8 -0
  77. package/dist/setup-WZ-xqAQO.cjs +849 -0
  78. package/dist/setup-WZ-xqAQO.cjs.map +1 -0
  79. package/dist/{sync-COnAugP-.mjs → sync-B5UHXwRM.mjs} +1 -1
  80. package/dist/sync-BLA94rgC.cjs +4 -0
  81. package/dist/{sync-D_NowTkZ.mjs → sync-CSooqRQ8.mjs} +1 -1
  82. package/dist/{sync-D_NowTkZ.mjs.map → sync-CSooqRQ8.mjs.map} +1 -1
  83. package/dist/{sync-DGXXSk2v.cjs → sync-o_CtEbvR.cjs} +1 -1
  84. package/dist/{sync-DGXXSk2v.cjs.map → sync-o_CtEbvR.cjs.map} +1 -1
  85. package/dist/{types-DdHfUbxk.d.cts → types-B3GQUg3k.d.mts} +3 -1
  86. package/dist/{types-DdHfUbxk.d.cts.map → types-B3GQUg3k.d.mts.map} +1 -1
  87. package/dist/{types-OszPdw9m.d.mts → types-BWQDiooe.d.cts} +3 -1
  88. package/dist/{types-OszPdw9m.d.mts.map → types-BWQDiooe.d.cts.map} +1 -1
  89. package/dist/workspace/index.d.cts +2 -2
  90. package/dist/workspace/index.d.mts +2 -2
  91. package/package.json +6 -5
  92. package/src/build/__tests__/index-new.spec.ts +3 -1
  93. package/src/build/__tests__/manifests.spec.ts +2 -2
  94. package/src/build/index.ts +61 -21
  95. package/src/build/manifests.ts +62 -5
  96. package/src/dev/index.ts +25 -11
  97. package/src/generators/EndpointGenerator.ts +14 -2
  98. package/src/generators/QueueGenerator.ts +245 -0
  99. package/src/generators/SubscriberGenerator.ts +5 -0
  100. package/src/generators/TopicGenerator.ts +45 -0
  101. package/src/generators/__tests__/QueueGenerator.spec.ts +141 -0
  102. package/src/generators/index.ts +2 -0
  103. package/src/index.ts +4 -0
  104. package/src/init/versions.ts +6 -6
  105. package/src/setup/__tests__/auto-setup.spec.ts +147 -0
  106. package/src/setup/index.ts +46 -6
  107. package/src/test/index.ts +17 -0
  108. package/src/types.ts +14 -51
  109. package/dist/CachedStateProvider-CC0DyO09.mjs +0 -3
  110. package/dist/dokploy-api-BOx71j6F.cjs +0 -3
  111. package/dist/dokploy-api-BZGk-lkD.mjs +0 -3
  112. package/dist/encryption-Db2zvGqM.mjs +0 -3
  113. package/dist/openapi-DF9GyhyZ.mjs.map +0 -1
  114. package/dist/openapi-DHp49UJV.cjs.map +0 -1
  115. package/dist/sync-D1Pa30oV.cjs +0 -4
package/dist/index.cjs CHANGED
@@ -5,12 +5,13 @@ const require_config = require('./config-DujV8DbR.cjs');
5
5
  const require_credentials = require('./credentials-C8DWtnMY.cjs');
6
6
  const require_fullstack_secrets = require('./fullstack-secrets-BYzi6Hwl.cjs');
7
7
  const require_storage = require('./storage-B1wvztiJ.cjs');
8
- const require_openapi = require('./openapi-DHp49UJV.cjs');
9
- const require_dokploy_api = require('./dokploy-api-Dvyq-LsM.cjs');
10
- const require_encryption = require('./encryption-DgKS-Dv9.cjs');
11
- const require_CachedStateProvider = require('./CachedStateProvider-CxsXOKkg.cjs');
12
- const require_openapi_react_query = require('./openapi-react-query-DYbBq-WJ.cjs');
13
- const require_sync = require('./sync-DGXXSk2v.cjs');
8
+ const require_setup = require('./setup-WZ-xqAQO.cjs');
9
+ const require_openapi = require('./openapi-BzNOC7_i.cjs');
10
+ const require_dokploy_api = require('./dokploy-api-CqOIKHme.cjs');
11
+ const require_encryption = require('./encryption-MfXAiFTm.cjs');
12
+ const require_CachedStateProvider = require('./CachedStateProvider-klLWZXWF.cjs');
13
+ const require_openapi_react_query = require('./openapi-react-query-CYWik72n.cjs');
14
+ require('./sync-o_CtEbvR.cjs');
14
15
  const node_fs = require_chunk.__toESM(require("node:fs"));
15
16
  const node_path = require_chunk.__toESM(require("node:path"));
16
17
  const commander = require_chunk.__toESM(require("commander"));
@@ -20,13 +21,13 @@ const node_fs_promises = require_chunk.__toESM(require("node:fs/promises"));
20
21
  const node_child_process = require_chunk.__toESM(require("node:child_process"));
21
22
  const chokidar = require_chunk.__toESM(require("chokidar"));
22
23
  const fast_glob = require_chunk.__toESM(require("fast-glob"));
23
- const node_net = require_chunk.__toESM(require("node:net"));
24
- const dotenv = require_chunk.__toESM(require("dotenv"));
25
24
  const yaml = require_chunk.__toESM(require("yaml"));
26
25
  const node_crypto = require_chunk.__toESM(require("node:crypto"));
27
26
  const __geekmidas_constructs_crons = require_chunk.__toESM(require("@geekmidas/constructs/crons"));
28
27
  const __geekmidas_constructs_functions = require_chunk.__toESM(require("@geekmidas/constructs/functions"));
28
+ const __geekmidas_constructs_queue = require_chunk.__toESM(require("@geekmidas/constructs/queue"));
29
29
  const __geekmidas_constructs_subscribers = require_chunk.__toESM(require("@geekmidas/constructs/subscribers"));
30
+ const __geekmidas_constructs_topic = require_chunk.__toESM(require("@geekmidas/constructs/topic"));
30
31
  const node_url = require_chunk.__toESM(require("node:url"));
31
32
  const pg = require_chunk.__toESM(require("pg"));
32
33
  const node_dns_promises = require_chunk.__toESM(require("node:dns/promises"));
@@ -35,7 +36,7 @@ const prompts = require_chunk.__toESM(require("prompts"));
35
36
 
36
37
  //#region package.json
37
38
  var name = "@geekmidas/cli";
38
- var version = "1.10.40";
39
+ var version = "1.11.0";
39
40
  var description = "CLI tools for building Lambda handlers, server applications, and generating OpenAPI specs";
40
41
  var private$1 = false;
41
42
  var type = "module";
@@ -115,6 +116,7 @@ var dependencies = {
115
116
  "@geekmidas/envkit": "workspace:~",
116
117
  "@geekmidas/errors": "workspace:~",
117
118
  "@geekmidas/logger": "workspace:~",
119
+ "@geekmidas/manifest": "workspace:*",
118
120
  "@geekmidas/schema": "workspace:~",
119
121
  "chokidar": "~4.0.3",
120
122
  "commander": "^12.1.0",
@@ -158,12 +160,12 @@ var package_default = {
158
160
 
159
161
  //#endregion
160
162
  //#region src/auth/index.ts
161
- const logger$14 = console;
163
+ const logger$12 = console;
162
164
  /**
163
165
  * Validate Dokploy token by making a test API call
164
166
  */
165
167
  async function validateDokployToken(endpoint, token) {
166
- const { DokployApi: DokployApi$1 } = await Promise.resolve().then(() => require("./dokploy-api-BOx71j6F.cjs"));
168
+ const { DokployApi: DokployApi$1 } = await Promise.resolve().then(() => require("./dokploy-api-BPYkG-ZZ.cjs"));
167
169
  const api = new DokployApi$1({
168
170
  baseUrl: endpoint,
169
171
  token
@@ -177,7 +179,7 @@ async function prompt$1(message, hidden = false) {
177
179
  if (!process.stdin.isTTY) throw new Error("Interactive input required. Please provide --token option.");
178
180
  if (hidden) {
179
181
  process.stdout.write(message);
180
- return new Promise((resolve$4, reject) => {
182
+ return new Promise((resolve$3, reject) => {
181
183
  let value = "";
182
184
  const cleanup = () => {
183
185
  process.stdin.setRawMode(false);
@@ -194,7 +196,7 @@ async function prompt$1(message, hidden = false) {
194
196
  if (c === "\n" || c === "\r") {
195
197
  cleanup();
196
198
  process.stdout.write("\n");
197
- resolve$4(value);
199
+ resolve$3(value);
198
200
  } else if (c === "") {
199
201
  cleanup();
200
202
  process.stdout.write("\n");
@@ -226,36 +228,36 @@ async function prompt$1(message, hidden = false) {
226
228
  async function loginCommand(options) {
227
229
  const { service, token: providedToken, endpoint: providedEndpoint } = options;
228
230
  if (service === "dokploy") {
229
- logger$14.log("\n🔐 Logging in to Dokploy...\n");
231
+ logger$12.log("\n🔐 Logging in to Dokploy...\n");
230
232
  let endpoint = providedEndpoint;
231
233
  if (!endpoint) endpoint = await prompt$1("Dokploy URL (e.g., https://dokploy.example.com): ");
232
234
  endpoint = endpoint.replace(/\/$/, "");
233
235
  try {
234
236
  new URL(endpoint);
235
237
  } catch {
236
- logger$14.error("Invalid URL format");
238
+ logger$12.error("Invalid URL format");
237
239
  process.exit(1);
238
240
  }
239
241
  let token = providedToken;
240
242
  if (!token) {
241
- logger$14.log(`\nGenerate a token at: ${endpoint}/settings/profile\n`);
243
+ logger$12.log(`\nGenerate a token at: ${endpoint}/settings/profile\n`);
242
244
  token = await prompt$1("API Token: ", true);
243
245
  }
244
246
  if (!token) {
245
- logger$14.error("Token is required");
247
+ logger$12.error("Token is required");
246
248
  process.exit(1);
247
249
  }
248
- logger$14.log("\nValidating credentials...");
250
+ logger$12.log("\nValidating credentials...");
249
251
  const isValid = await validateDokployToken(endpoint, token);
250
252
  if (!isValid) {
251
- logger$14.error("\n✗ Invalid credentials. Please check your token and try again.");
253
+ logger$12.error("\n✗ Invalid credentials. Please check your token and try again.");
252
254
  process.exit(1);
253
255
  }
254
256
  await require_credentials.storeDokployCredentials(token, endpoint);
255
- logger$14.log("\n✓ Successfully logged in to Dokploy!");
256
- logger$14.log(` Endpoint: ${endpoint}`);
257
- logger$14.log(` Credentials stored in: ${require_credentials.getCredentialsPath()}`);
258
- logger$14.log("\nYou can now use deploy commands without setting DOKPLOY_API_TOKEN.");
257
+ logger$12.log("\n✓ Successfully logged in to Dokploy!");
258
+ logger$12.log(` Endpoint: ${endpoint}`);
259
+ logger$12.log(` Credentials stored in: ${require_credentials.getCredentialsPath()}`);
260
+ logger$12.log("\nYou can now use deploy commands without setting DOKPLOY_API_TOKEN.");
259
261
  }
260
262
  }
261
263
  /**
@@ -265,28 +267,28 @@ async function logoutCommand(options) {
265
267
  const { service = "dokploy" } = options;
266
268
  if (service === "all") {
267
269
  const dokployRemoved = await require_credentials.removeDokployCredentials();
268
- if (dokployRemoved) logger$14.log("\n✓ Logged out from all services");
269
- else logger$14.log("\nNo stored credentials found");
270
+ if (dokployRemoved) logger$12.log("\n✓ Logged out from all services");
271
+ else logger$12.log("\nNo stored credentials found");
270
272
  return;
271
273
  }
272
274
  if (service === "dokploy") {
273
275
  const removed = await require_credentials.removeDokployCredentials();
274
- if (removed) logger$14.log("\n✓ Logged out from Dokploy");
275
- else logger$14.log("\nNo Dokploy credentials found");
276
+ if (removed) logger$12.log("\n✓ Logged out from Dokploy");
277
+ else logger$12.log("\nNo Dokploy credentials found");
276
278
  }
277
279
  }
278
280
  /**
279
281
  * Show current login status
280
282
  */
281
283
  async function whoamiCommand() {
282
- logger$14.log("\n📋 Current credentials:\n");
284
+ logger$12.log("\n📋 Current credentials:\n");
283
285
  const dokploy = await require_credentials.getDokployCredentials();
284
286
  if (dokploy) {
285
- logger$14.log(" Dokploy:");
286
- logger$14.log(` Endpoint: ${dokploy.endpoint}`);
287
- logger$14.log(` Token: ${maskToken(dokploy.token)}`);
288
- } else logger$14.log(" Dokploy: Not logged in");
289
- logger$14.log(`\n Credentials file: ${require_credentials.getCredentialsPath()}`);
287
+ logger$12.log(" Dokploy:");
288
+ logger$12.log(` Endpoint: ${dokploy.endpoint}`);
289
+ logger$12.log(` Token: ${maskToken(dokploy.token)}`);
290
+ } else logger$12.log(" Dokploy: Not logged in");
291
+ logger$12.log(`\n Credentials file: ${require_credentials.getCredentialsPath()}`);
290
292
  }
291
293
  /**
292
294
  * Mask a token for display
@@ -367,477 +369,12 @@ function isEnabled(config) {
367
369
  return config.enabled !== false;
368
370
  }
369
371
 
370
- //#endregion
371
- //#region src/credentials/index.ts
372
- const logger$13 = console;
373
- /**
374
- * Load environment files
375
- * @internal Exported for testing
376
- */
377
- function loadEnvFiles(envConfig, cwd = process.cwd()) {
378
- const loaded = [];
379
- const missing = [];
380
- const envFiles = envConfig ? Array.isArray(envConfig) ? envConfig : [envConfig] : [".env"];
381
- for (const envFile of envFiles) {
382
- const envPath = (0, node_path.resolve)(cwd, envFile);
383
- if ((0, node_fs.existsSync)(envPath)) {
384
- (0, dotenv.config)({
385
- path: envPath,
386
- override: true,
387
- quiet: true
388
- });
389
- loaded.push(envFile);
390
- } else if (envConfig) missing.push(envFile);
391
- }
392
- return {
393
- loaded,
394
- missing
395
- };
396
- }
397
- /**
398
- * Check if a port is available
399
- * @internal Exported for testing
400
- */
401
- async function isPortAvailable(port) {
402
- return new Promise((resolve$4) => {
403
- const server = (0, node_net.createServer)();
404
- server.once("error", (err) => {
405
- if (err.code === "EADDRINUSE") resolve$4(false);
406
- else resolve$4(false);
407
- });
408
- server.once("listening", () => {
409
- server.close();
410
- resolve$4(true);
411
- });
412
- server.listen(port);
413
- });
414
- }
415
- /**
416
- * Find an available port starting from the preferred port
417
- * @internal Exported for testing
418
- */
419
- async function findAvailablePort(preferredPort, maxAttempts = 10) {
420
- for (let i = 0; i < maxAttempts; i++) {
421
- const port = preferredPort + i;
422
- if (await isPortAvailable(port)) return port;
423
- logger$13.log(`⚠️ Port ${port} is in use, trying ${port + 1}...`);
424
- }
425
- throw new Error(`Could not find an available port after trying ${maxAttempts} ports starting from ${preferredPort}`);
426
- }
427
- const PORT_STATE_PATH = ".gkm/ports.json";
428
- /**
429
- * Parse docker-compose.yml and extract all port mappings that use env var interpolation.
430
- * Entries like `'${POSTGRES_HOST_PORT:-5432}:5432'` are captured.
431
- * Fixed port mappings like `'5050:80'` are skipped.
432
- * @internal Exported for testing
433
- */
434
- function parseComposePortMappings(composePath) {
435
- if (!(0, node_fs.existsSync)(composePath)) return [];
436
- const content = (0, node_fs.readFileSync)(composePath, "utf-8");
437
- const compose = (0, yaml.parse)(content);
438
- if (!compose?.services) return [];
439
- const results = [];
440
- for (const [serviceName, serviceConfig] of Object.entries(compose.services)) for (const portMapping of serviceConfig?.ports ?? []) {
441
- const match = String(portMapping).match(/\$\{(\w+):-(\d+)\}:(\d+)/);
442
- if (match?.[1] && match[2] && match[3]) results.push({
443
- service: serviceName,
444
- envVar: match[1],
445
- defaultPort: Number(match[2]),
446
- containerPort: Number(match[3])
447
- });
448
- }
449
- return results;
450
- }
451
- /**
452
- * Load saved port state from .gkm/ports.json.
453
- * @internal Exported for testing
454
- */
455
- async function loadPortState(workspaceRoot) {
456
- try {
457
- const raw = await (0, node_fs_promises.readFile)((0, node_path.join)(workspaceRoot, PORT_STATE_PATH), "utf-8");
458
- return JSON.parse(raw);
459
- } catch {
460
- return {};
461
- }
462
- }
463
- /**
464
- * Save port state to .gkm/ports.json.
465
- * @internal Exported for testing
466
- */
467
- async function savePortState(workspaceRoot, ports) {
468
- const dir = (0, node_path.join)(workspaceRoot, ".gkm");
469
- await (0, node_fs_promises.mkdir)(dir, { recursive: true });
470
- await (0, node_fs_promises.writeFile)((0, node_path.join)(workspaceRoot, PORT_STATE_PATH), `${JSON.stringify(ports, null, 2)}\n`);
471
- }
472
- /**
473
- * Check if a project's own Docker container is running and return its host port.
474
- * Uses `docker compose port` scoped to the project's compose file.
475
- * @internal Exported for testing
476
- */
477
- function getContainerHostPort(workspaceRoot, service, containerPort) {
478
- try {
479
- const result = (0, node_child_process.execSync)(`docker compose port ${service} ${containerPort}`, {
480
- cwd: workspaceRoot,
481
- stdio: "pipe"
482
- }).toString().trim();
483
- const match = result.match(/:(\d+)$/);
484
- return match ? Number(match[1]) : null;
485
- } catch {
486
- return null;
487
- }
488
- }
489
- /**
490
- * Resolve host ports for Docker services by parsing docker-compose.yml.
491
- * Priority: running container → saved state → find available port.
492
- * Persists resolved ports to .gkm/ports.json.
493
- * @internal Exported for testing
494
- */
495
- async function resolveServicePorts(workspaceRoot) {
496
- const composePath = (0, node_path.join)(workspaceRoot, "docker-compose.yml");
497
- const mappings = parseComposePortMappings(composePath);
498
- if (mappings.length === 0) return {
499
- dockerEnv: {},
500
- ports: {},
501
- mappings: []
502
- };
503
- const savedState = await loadPortState(workspaceRoot);
504
- const dockerEnv = {};
505
- const ports = {};
506
- const assignedPorts = /* @__PURE__ */ new Set();
507
- logger$13.log("\n🔌 Resolving service ports...");
508
- for (const mapping of mappings) {
509
- const containerPort = getContainerHostPort(workspaceRoot, mapping.service, mapping.containerPort);
510
- if (containerPort !== null) {
511
- ports[mapping.envVar] = containerPort;
512
- dockerEnv[mapping.envVar] = String(containerPort);
513
- assignedPorts.add(containerPort);
514
- logger$13.log(` 🔄 ${mapping.service}:${mapping.containerPort}: reusing existing container on port ${containerPort}`);
515
- continue;
516
- }
517
- const savedPort = savedState[mapping.envVar];
518
- if (savedPort && !assignedPorts.has(savedPort) && await isPortAvailable(savedPort)) {
519
- ports[mapping.envVar] = savedPort;
520
- dockerEnv[mapping.envVar] = String(savedPort);
521
- assignedPorts.add(savedPort);
522
- logger$13.log(` 💾 ${mapping.service}:${mapping.containerPort}: using saved port ${savedPort}`);
523
- continue;
524
- }
525
- let resolvedPort = await findAvailablePort(mapping.defaultPort);
526
- while (assignedPorts.has(resolvedPort)) resolvedPort = await findAvailablePort(resolvedPort + 1);
527
- ports[mapping.envVar] = resolvedPort;
528
- dockerEnv[mapping.envVar] = String(resolvedPort);
529
- assignedPorts.add(resolvedPort);
530
- if (resolvedPort !== mapping.defaultPort) logger$13.log(` ⚡ ${mapping.service}:${mapping.containerPort}: port ${mapping.defaultPort} occupied, using port ${resolvedPort}`);
531
- else logger$13.log(` ✅ ${mapping.service}:${mapping.containerPort}: using default port ${resolvedPort}`);
532
- }
533
- await savePortState(workspaceRoot, ports);
534
- return {
535
- dockerEnv,
536
- ports,
537
- mappings
538
- };
539
- }
540
- /**
541
- * Replace a port in a URL string.
542
- * Handles both `hostname:port` and `localhost:port` patterns.
543
- * @internal Exported for testing
544
- */
545
- function replacePortInUrl(url, oldPort, newPort) {
546
- if (oldPort === newPort) return url;
547
- let result = url.replace(new RegExp(`:${oldPort}(?=[/?#]|$)`, "g"), `:${newPort}`);
548
- result = result.replace(new RegExp(`%3A${oldPort}(?=[%/?#&]|$)`, "gi"), `%3A${newPort}`);
549
- return result;
550
- }
551
- /**
552
- * Rewrite connection URLs and port vars in secrets with resolved ports.
553
- * Uses the parsed compose mappings to determine which default ports to replace.
554
- * Pure transform — does not modify secrets on disk.
555
- * @internal Exported for testing
556
- */
557
- function rewriteUrlsWithPorts(secrets, resolvedPorts) {
558
- const { ports, mappings } = resolvedPorts;
559
- const result = { ...secrets };
560
- const portReplacements = [];
561
- const serviceNames = /* @__PURE__ */ new Set();
562
- for (const mapping of mappings) {
563
- serviceNames.add(mapping.service);
564
- const resolved = ports[mapping.envVar];
565
- if (resolved !== void 0) portReplacements.push({
566
- defaultPort: mapping.defaultPort,
567
- resolvedPort: resolved
568
- });
569
- }
570
- for (const [key, value] of Object.entries(result)) {
571
- if (!key.endsWith("_HOST")) continue;
572
- if (serviceNames.has(value)) result[key] = "localhost";
573
- }
574
- for (const [key, value] of Object.entries(result)) {
575
- if (!key.endsWith("_PORT")) continue;
576
- for (const { defaultPort, resolvedPort } of portReplacements) if (value === String(defaultPort)) result[key] = String(resolvedPort);
577
- }
578
- for (const [key, value] of Object.entries(result)) {
579
- if (!key.endsWith("_URL") && !key.endsWith("_ENDPOINT") && !key.endsWith("_CONNECTION_STRING") && key !== "DATABASE_URL") continue;
580
- let rewritten = value;
581
- for (const name$1 of serviceNames) rewritten = rewritten.replace(new RegExp(`@${name$1}:`, "g"), "@localhost:");
582
- for (const { defaultPort, resolvedPort } of portReplacements) rewritten = replacePortInUrl(rewritten, defaultPort, resolvedPort);
583
- result[key] = rewritten;
584
- }
585
- return result;
586
- }
587
- /**
588
- * Build the environment variables to pass to `docker compose up`.
589
- * Merges process.env, secrets, and port mappings so that Docker Compose
590
- * can interpolate variables like ${POSTGRES_USER} correctly.
591
- * @internal Exported for testing
592
- */
593
- function buildDockerComposeEnv(secretsEnv, portEnv) {
594
- return {
595
- ...process.env,
596
- ...secretsEnv,
597
- ...portEnv
598
- };
599
- }
600
- /**
601
- * Parse all service names from a docker-compose.yml file.
602
- * @internal Exported for testing
603
- */
604
- function parseComposeServiceNames(composePath) {
605
- if (!(0, node_fs.existsSync)(composePath)) return [];
606
- const content = (0, node_fs.readFileSync)(composePath, "utf-8");
607
- const compose = (0, yaml.parse)(content);
608
- return Object.keys(compose?.services ?? {});
609
- }
610
- /**
611
- * Start docker-compose services for a single-app project (no workspace config).
612
- * Starts all services defined in docker-compose.yml.
613
- */
614
- async function startComposeServices(cwd, portEnv, secretsEnv) {
615
- const composeFile = (0, node_path.join)(cwd, "docker-compose.yml");
616
- if (!(0, node_fs.existsSync)(composeFile)) return;
617
- const servicesToStart = parseComposeServiceNames(composeFile);
618
- if (servicesToStart.length === 0) return;
619
- logger$13.log(`🐳 Starting services: ${servicesToStart.join(", ")}`);
620
- try {
621
- (0, node_child_process.execSync)(`docker compose up -d ${servicesToStart.join(" ")}`, {
622
- cwd,
623
- stdio: "inherit",
624
- env: buildDockerComposeEnv(secretsEnv, portEnv)
625
- });
626
- logger$13.log("✅ Services started");
627
- } catch (error) {
628
- logger$13.error("❌ Failed to start services:", error.message);
629
- throw error;
630
- }
631
- }
632
- /**
633
- * Start docker-compose services for a workspace.
634
- * Discovers all services from docker-compose.yml and starts everything
635
- * except app services (which are managed by turbo).
636
- * @internal Exported for testing
637
- */
638
- async function startWorkspaceServices(workspace, portEnv, secretsEnv) {
639
- const composeFile = (0, node_path.join)(workspace.root, "docker-compose.yml");
640
- if (!(0, node_fs.existsSync)(composeFile)) return;
641
- const allServices = parseComposeServiceNames(composeFile);
642
- const appNames = new Set(Object.keys(workspace.apps));
643
- const servicesToStart = allServices.filter((name$1) => !appNames.has(name$1));
644
- if (servicesToStart.length === 0) return;
645
- logger$13.log(`🐳 Starting services: ${servicesToStart.join(", ")}`);
646
- try {
647
- (0, node_child_process.execSync)(`docker compose up -d ${servicesToStart.join(" ")}`, {
648
- cwd: workspace.root,
649
- stdio: "inherit",
650
- env: buildDockerComposeEnv(secretsEnv, portEnv)
651
- });
652
- logger$13.log("✅ Services started");
653
- } catch (error) {
654
- logger$13.error("❌ Failed to start services:", error.message);
655
- throw error;
656
- }
657
- }
658
- /**
659
- * Load and flatten secrets for an app from encrypted storage.
660
- * For workspace app: maps {APP}_DATABASE_URL → DATABASE_URL.
661
- * @internal Exported for testing
662
- */
663
- async function loadSecretsForApp(secretsRoot, appName, stages = ["dev", "development"]) {
664
- let secrets = {};
665
- for (const stage of stages) if (require_storage.secretsExist(stage, secretsRoot)) {
666
- const stageSecrets = await require_storage.readStageSecrets(stage, secretsRoot);
667
- if (stageSecrets) {
668
- logger$13.log(`🔐 Loading secrets from stage: ${stage}`);
669
- secrets = require_storage.toEmbeddableSecrets(stageSecrets);
670
- break;
671
- }
672
- }
673
- if (Object.keys(secrets).length === 0) return {};
674
- if (!appName) return secrets;
675
- const prefix = appName.toUpperCase();
676
- const mapped = { ...secrets };
677
- const appDbUrl = secrets[`${prefix}_DATABASE_URL`];
678
- if (appDbUrl) mapped.DATABASE_URL = appDbUrl;
679
- return mapped;
680
- }
681
- /**
682
- * Walk up the directory tree to find the root containing .gkm/secrets/.
683
- * @internal Exported for testing
684
- */
685
- function findSecretsRoot(startDir) {
686
- let dir = startDir;
687
- while (dir !== "/") {
688
- if ((0, node_fs.existsSync)((0, node_path.join)(dir, ".gkm", "secrets"))) return dir;
689
- const parent = (0, node_path.dirname)(dir);
690
- if (parent === dir) break;
691
- dir = parent;
692
- }
693
- return startDir;
694
- }
695
- /**
696
- * Generate the credentials injection code snippet.
697
- * This is the common logic used by both entry wrapper and exec preload.
698
- * @internal
699
- */
700
- function generateCredentialsInjection(secretsJsonPath) {
701
- return `import { existsSync, readFileSync } from 'node:fs';
702
-
703
- // Inject dev secrets via globalThis and process.env
704
- // Using globalThis.__gkm_credentials__ avoids CJS/ESM interop issues where
705
- // Object.assign on the Credentials export only mutates one module copy.
706
- const secretsPath = '${secretsJsonPath}';
707
- if (existsSync(secretsPath)) {
708
- const secrets = JSON.parse(readFileSync(secretsPath, 'utf-8'));
709
- globalThis.__gkm_credentials__ = secrets;
710
- Object.assign(process.env, secrets);
711
- }
712
- `;
713
- }
714
- /**
715
- * Create a preload script that injects secrets into Credentials.
716
- * Used by `gkm exec` to inject secrets before running any command.
717
- * @internal Exported for testing
718
- */
719
- async function createCredentialsPreload(preloadPath, secretsJsonPath) {
720
- const content = `/**
721
- * Credentials preload generated by 'gkm exec'
722
- * This file is loaded via NODE_OPTIONS="--import <path>"
723
- */
724
- ${generateCredentialsInjection(secretsJsonPath)}`;
725
- await (0, node_fs_promises.writeFile)(preloadPath, content);
726
- }
727
- /**
728
- * Create a wrapper script that injects secrets before importing the entry file.
729
- * @internal Exported for testing
730
- */
731
- async function createEntryWrapper(wrapperPath, entryPath, secretsJsonPath) {
732
- const credentialsInjection = secretsJsonPath ? `${generateCredentialsInjection(secretsJsonPath)}
733
- ` : "";
734
- const content = `#!/usr/bin/env node
735
- /**
736
- * Entry wrapper generated by 'gkm dev --entry'
737
- */
738
- ${credentialsInjection}// Import and run the user's entry file (dynamic import ensures secrets load first)
739
- await import('${entryPath}');
740
- `;
741
- await (0, node_fs_promises.writeFile)(wrapperPath, content);
742
- }
743
- /**
744
- * Prepare credentials for dev/exec/test modes.
745
- * Loads workspace config, secrets, resolves Docker ports, rewrites URLs,
746
- * injects PORT, dependency URLs, and writes credentials JSON.
747
- *
748
- * @param options.resolveDockerPorts - How to resolve Docker ports:
749
- * - `'full'` (default): probe running containers, saved state, then find available ports. Used by dev/test.
750
- * - `'readonly'`: check running containers and saved state only, never probe for new ports. Used by exec.
751
- * @param options.stages - Secret stages to try, in order. Default: ['dev', 'development'].
752
- * @param options.startDocker - Start Docker Compose services after port resolution. Default: false.
753
- * @param options.secretsFileName - Custom secrets JSON filename. Default: 'dev-secrets-{appName}.json' or 'dev-secrets.json'.
754
- * @internal Exported for testing
755
- */
756
- async function prepareEntryCredentials(options) {
757
- const cwd = options.cwd ?? process.cwd();
758
- const portMode = options.resolveDockerPorts ?? "full";
759
- let workspaceAppPort;
760
- let secretsRoot = cwd;
761
- let appName;
762
- let appInfo;
763
- try {
764
- appInfo = await require_config.loadWorkspaceAppInfo(cwd);
765
- workspaceAppPort = appInfo.app.port;
766
- secretsRoot = appInfo.workspaceRoot;
767
- appName = appInfo.appName;
768
- } catch {
769
- secretsRoot = findSecretsRoot(cwd);
770
- appName = require_config.getAppNameFromCwd(cwd) ?? void 0;
771
- }
772
- const resolvedPort = options.explicitPort ?? workspaceAppPort ?? 3e3;
773
- const credentials = await loadSecretsForApp(secretsRoot, appName, options.stages);
774
- credentials.PORT = String(resolvedPort);
775
- const composePath = (0, node_path.join)(secretsRoot, "docker-compose.yml");
776
- const mappings = parseComposePortMappings(composePath);
777
- if (mappings.length > 0) {
778
- let resolvedPorts;
779
- if (portMode === "full") resolvedPorts = await resolveServicePorts(secretsRoot);
780
- else {
781
- const savedPorts = await loadPortState(secretsRoot);
782
- const ports = {};
783
- for (const mapping of mappings) {
784
- const containerPort = getContainerHostPort(secretsRoot, mapping.service, mapping.containerPort);
785
- if (containerPort !== null) ports[mapping.envVar] = containerPort;
786
- else {
787
- const saved = savedPorts[mapping.envVar];
788
- if (saved !== void 0) ports[mapping.envVar] = saved;
789
- }
790
- }
791
- resolvedPorts = {
792
- dockerEnv: {},
793
- ports,
794
- mappings
795
- };
796
- }
797
- if (options.startDocker) if (appInfo) await startWorkspaceServices(appInfo.workspace, resolvedPorts.dockerEnv, credentials);
798
- else await startComposeServices(secretsRoot, resolvedPorts.dockerEnv, credentials);
799
- if (Object.keys(resolvedPorts.ports).length > 0) {
800
- const rewritten = rewriteUrlsWithPorts(credentials, resolvedPorts);
801
- Object.assign(credentials, rewritten);
802
- logger$13.log(`🔌 Applied ${Object.keys(resolvedPorts.ports).length} port mapping(s)`);
803
- }
804
- }
805
- if (appInfo?.appName) {
806
- const depEnv = require_workspace.getDependencyEnvVars(appInfo.workspace, appInfo.appName);
807
- Object.assign(credentials, depEnv);
808
- }
809
- if (!credentials.EVENT_PUBLISHER_CONNECTION_STRING && !credentials.EVENT_SUBSCRIBER_CONNECTION_STRING && credentials.PGBOSS_DB_USER) {
810
- const pgbossUrl = require_fullstack_secrets.generatePgBossUrl({
811
- username: credentials.PGBOSS_DB_USER,
812
- password: credentials.PGBOSS_DB_PASSWORD ?? "",
813
- host: credentials.POSTGRES_HOST ?? "localhost",
814
- port: Number(credentials.POSTGRES_PORT ?? "5432"),
815
- database: credentials.POSTGRES_DB ?? "app"
816
- });
817
- credentials.EVENT_PUBLISHER_CONNECTION_STRING = pgbossUrl;
818
- credentials.EVENT_SUBSCRIBER_CONNECTION_STRING = pgbossUrl;
819
- }
820
- const secretsDir = (0, node_path.join)(secretsRoot, ".gkm");
821
- await (0, node_fs_promises.mkdir)(secretsDir, { recursive: true });
822
- const secretsFileName = options.secretsFileName ?? (appName ? `dev-secrets-${appName}.json` : "dev-secrets.json");
823
- const secretsJsonPath = (0, node_path.join)(secretsDir, secretsFileName);
824
- await (0, node_fs_promises.writeFile)(secretsJsonPath, JSON.stringify(credentials, null, 2));
825
- return {
826
- credentials,
827
- resolvedPort,
828
- secretsJsonPath,
829
- appName,
830
- secretsRoot,
831
- appInfo
832
- };
833
- }
834
-
835
372
  //#endregion
836
373
  //#region src/generators/CronGenerator.ts
837
374
  var CronGenerator = class extends require_openapi.ConstructGenerator {
838
375
  async build(context, constructs, outputDir, options) {
839
376
  const provider = options?.provider || "aws-lambda";
840
- const logger$15 = console;
377
+ const logger$13 = console;
841
378
  const cronInfos = [];
842
379
  if (constructs.length === 0 || provider !== "aws-lambda") return cronInfos;
843
380
  const cronsDir = (0, node_path.join)(outputDir, "crons");
@@ -852,7 +389,7 @@ var CronGenerator = class extends require_openapi.ConstructGenerator {
852
389
  memorySize: construct.memorySize,
853
390
  environment: await construct.getEnvironment({ markOptional: context.markOptional })
854
391
  });
855
- logger$15.log(`Generated cron handler: ${key}`);
392
+ logger$13.log(`Generated cron handler: ${key}`);
856
393
  }
857
394
  return cronInfos;
858
395
  }
@@ -888,7 +425,7 @@ var FunctionGenerator = class extends require_openapi.ConstructGenerator {
888
425
  }
889
426
  async build(context, constructs, outputDir, options) {
890
427
  const provider = options?.provider || "aws-lambda";
891
- const logger$15 = console;
428
+ const logger$13 = console;
892
429
  const functionInfos = [];
893
430
  if (constructs.length === 0 || provider !== "aws-lambda") return functionInfos;
894
431
  const functionsDir = (0, node_path.join)(outputDir, "functions");
@@ -902,7 +439,7 @@ var FunctionGenerator = class extends require_openapi.ConstructGenerator {
902
439
  memorySize: construct.memorySize,
903
440
  environment: await construct.getEnvironment({ markOptional: context.markOptional })
904
441
  });
905
- logger$15.log(`Generated function handler: ${key}`);
442
+ logger$13.log(`Generated function handler: ${key}`);
906
443
  }
907
444
  return functionInfos;
908
445
  }
@@ -927,6 +464,176 @@ export const handler = adapter.handler;
927
464
  }
928
465
  };
929
466
 
467
+ //#endregion
468
+ //#region src/generators/QueueGenerator.ts
469
+ /**
470
+ * Generates the runtime for `q` queue workers.
471
+ *
472
+ * - **server** (`gkm dev`): a single `queues.ts` exposing `setupQueues()` that
473
+ * runs an in-process pg-boss poller alongside the Hono server — no SQS/Lambda.
474
+ * Each queue subscribes by its **name** on the shared event connection.
475
+ * - **aws-lambda**: one handler file per queue wrapping `AWSLambdaQueue`, backed
476
+ * by an SQS event-source mapping.
477
+ */
478
+ var QueueGenerator = class extends require_openapi.ConstructGenerator {
479
+ isConstruct(value) {
480
+ return __geekmidas_constructs_queue.Queue.isQueue(value);
481
+ }
482
+ async build(context, constructs, outputDir, options) {
483
+ const provider = options?.provider || "aws-lambda";
484
+ const logger$13 = console;
485
+ const queueInfos = [];
486
+ if (provider === "server") {
487
+ await this.generateServerQueuesFile(outputDir, constructs);
488
+ logger$13.log(`Generated server queues file with ${constructs.length} queues (polling mode)`);
489
+ return queueInfos;
490
+ }
491
+ if (constructs.length === 0 || provider !== "aws-lambda") return queueInfos;
492
+ const queuesDir = (0, node_path.join)(outputDir, "queues");
493
+ await (0, node_fs_promises.mkdir)(queuesDir, { recursive: true });
494
+ for (const { key, construct, path } of constructs) {
495
+ const handlerFile = await this.generateQueueHandler(queuesDir, path.relative, key, context);
496
+ queueInfos.push({
497
+ name: construct.name,
498
+ handler: (0, node_path.relative)(process.cwd(), handlerFile).replace(/\.ts$/, ".handler"),
499
+ batchSize: construct.batchSize,
500
+ fifo: construct.fifo,
501
+ timeout: construct.timeout,
502
+ environment: await construct.getEnvironment({ markOptional: context.markOptional })
503
+ });
504
+ logger$13.log(`Generated queue handler: ${key}`);
505
+ }
506
+ return queueInfos;
507
+ }
508
+ async generateQueueHandler(outputDir, sourceFile, exportName, context) {
509
+ const handlerPath = (0, node_path.join)(outputDir, `${exportName}.ts`);
510
+ const importPath = (0, node_path.relative)((0, node_path.dirname)(handlerPath), sourceFile).replace(/\.ts$/, ".js");
511
+ const relativeEnvParserPath = (0, node_path.relative)((0, node_path.dirname)(handlerPath), context.envParserPath);
512
+ const content = `import { AWSLambdaQueue } from '@geekmidas/constructs/aws';
513
+ import { ${exportName} } from '${importPath}';
514
+ import ${context.envParserImportPattern} from '${relativeEnvParserPath}';
515
+
516
+ const adapter = new AWSLambdaQueue(envParser, ${exportName});
517
+
518
+ export const handler = adapter.handler;
519
+ `;
520
+ await (0, node_fs_promises.writeFile)(handlerPath, content);
521
+ return handlerPath;
522
+ }
523
+ async generateServerQueuesFile(outputDir, queues) {
524
+ await (0, node_fs_promises.mkdir)(outputDir, { recursive: true });
525
+ const queuesPath = (0, node_path.join)(outputDir, "queues.ts");
526
+ const importsByFile = /* @__PURE__ */ new Map();
527
+ for (const { path, key } of queues) {
528
+ const importPath = (0, node_path.relative)((0, node_path.dirname)(queuesPath), path.relative).replace(/\.ts$/, ".js");
529
+ if (!importsByFile.has(importPath)) importsByFile.set(importPath, []);
530
+ importsByFile.get(importPath)?.push(key);
531
+ }
532
+ const imports = Array.from(importsByFile.entries()).map(([importPath, exports$2]) => `import { ${exports$2.join(", ")} } from '${importPath}';`).join("\n");
533
+ const allExportNames = queues.map(({ key }) => key);
534
+ const content = `/**
535
+ * Generated queue workers setup
536
+ *
537
+ * ⚠️ WARNING: This is for LOCAL DEVELOPMENT ONLY
538
+ * This runs an in-process pg-boss poller alongside the HTTP server. Each queue
539
+ * subscribes by its name on the shared event connection
540
+ * (EVENT_SUBSCRIBER_CONNECTION_STRING), so producers using
541
+ * <NAME>_PUBLISHER_CONNECTION_STRING (pgboss:// locally) reach it.
542
+ *
543
+ * For production, queues run as AWS Lambda with SQS event-source mappings.
544
+ */
545
+ import type { EnvironmentParser } from '@geekmidas/envkit';
546
+ import type { Logger } from '@geekmidas/logger';
547
+ import { EventConnectionFactory, Subscriber } from '@geekmidas/events';
548
+ import type { EventConnection, EventSubscriber } from '@geekmidas/events';
549
+ import { ServiceDiscovery } from '@geekmidas/services';
550
+ ${imports}
551
+
552
+ const queues = [
553
+ ${allExportNames.join(",\n ")}
554
+ ];
555
+
556
+ const activeSubscribers: EventSubscriber<any>[] = [];
557
+
558
+ export async function setupQueues(
559
+ envParser: EnvironmentParser<any>,
560
+ logger: Logger,
561
+ ): Promise<void> {
562
+ if (queues.length === 0) {
563
+ return;
564
+ }
565
+
566
+ logger.info('Setting up queue workers in polling mode (local development)');
567
+
568
+ const config = envParser.create((get) => ({
569
+ connectionString: get('EVENT_SUBSCRIBER_CONNECTION_STRING').string(),
570
+ })).parse();
571
+
572
+ const serviceDiscovery = ServiceDiscovery.getInstance(envParser);
573
+
574
+ let connection: EventConnection;
575
+ try {
576
+ connection = await EventConnectionFactory.fromConnectionString(config.connectionString);
577
+ const connectionType = new URL(config.connectionString).protocol.replace(':', '');
578
+ logger.info({ connectionType }, 'Created shared event connection for queues');
579
+ } catch (error) {
580
+ logger.error({ error }, 'Failed to create event connection for queues');
581
+ return;
582
+ }
583
+
584
+ for (const queue of queues) {
585
+ try {
586
+ const eventSubscriber = await Subscriber.fromConnection(connection);
587
+
588
+ const services = queue.services.length > 0
589
+ ? await serviceDiscovery.register(queue.services)
590
+ : {};
591
+
592
+ // A queue subscribes to a single "type" — its own name.
593
+ await eventSubscriber.subscribe([queue.name], async (message) => {
594
+ try {
595
+ const validation = await queue.messageSchema['~standard'].validate(message.payload);
596
+ if (validation.issues) {
597
+ logger.error({ issues: validation.issues, queue: queue.name }, 'Queue message failed validation');
598
+ return;
599
+ }
600
+
601
+ await queue.handler({
602
+ messages: [validation.value],
603
+ services: services,
604
+ logger: queue.logger,
605
+ });
606
+
607
+ logger.debug({ queue: queue.name }, 'Successfully processed queue message');
608
+ } catch (error) {
609
+ logger.error({ error, queue: queue.name }, 'Failed to process queue message');
610
+ // Message will become visible again for retry.
611
+ }
612
+ });
613
+
614
+ activeSubscribers.push(eventSubscriber);
615
+ logger.info({ queue: queue.name }, 'Queue worker started polling');
616
+ } catch (error) {
617
+ logger.error({ error, queue: queue.name }, 'Failed to setup queue worker');
618
+ }
619
+ }
620
+
621
+ const shutdown = () => {
622
+ logger.info('Stopping all queue workers');
623
+ for (const _ of activeSubscribers) {
624
+ connection.stop();
625
+ }
626
+ };
627
+
628
+ process.on('SIGTERM', shutdown);
629
+ process.on('SIGINT', shutdown);
630
+ }
631
+ `;
632
+ await (0, node_fs_promises.writeFile)(queuesPath, content);
633
+ return queuesPath;
634
+ }
635
+ };
636
+
930
637
  //#endregion
931
638
  //#region src/generators/SubscriberGenerator.ts
932
639
  var SubscriberGenerator = class extends require_openapi.ConstructGenerator {
@@ -935,11 +642,11 @@ var SubscriberGenerator = class extends require_openapi.ConstructGenerator {
935
642
  }
936
643
  async build(context, constructs, outputDir, options) {
937
644
  const provider = options?.provider || "aws-lambda";
938
- const logger$15 = console;
645
+ const logger$13 = console;
939
646
  const subscriberInfos = [];
940
647
  if (provider === "server") {
941
648
  await this.generateServerSubscribersFile(outputDir, constructs);
942
- logger$15.log(`Generated server subscribers file with ${constructs.length} subscribers (polling mode)`);
649
+ logger$13.log(`Generated server subscribers file with ${constructs.length} subscribers (polling mode)`);
943
650
  return subscriberInfos;
944
651
  }
945
652
  if (constructs.length === 0) return subscriberInfos;
@@ -952,11 +659,15 @@ var SubscriberGenerator = class extends require_openapi.ConstructGenerator {
952
659
  name: key,
953
660
  handler: (0, node_path.relative)(process.cwd(), handlerFile).replace(/\.ts$/, ".handler"),
954
661
  subscribedEvents: construct.subscribedEvents || [],
662
+ ...construct.topicName ? {
663
+ transport: "topic",
664
+ topic: construct.topicName
665
+ } : {},
955
666
  timeout: construct.timeout,
956
667
  memorySize: construct.memorySize,
957
668
  environment: await construct.getEnvironment({ markOptional: context.markOptional })
958
669
  });
959
- logger$15.log(`Generated subscriber handler: ${key}`);
670
+ logger$13.log(`Generated subscriber handler: ${key}`);
960
671
  }
961
672
  return subscriberInfos;
962
673
  }
@@ -1120,9 +831,35 @@ export async function setupSubscribers(
1120
831
  }
1121
832
  };
1122
833
 
834
+ //#endregion
835
+ //#region src/generators/TopicGenerator.ts
836
+ /**
837
+ * Discovers `t` topics into `manifest.topics`. A topic is a *resource*, not a
838
+ * function — it has no handler to generate. Producers reach it via its derived
839
+ * publisher (`topic.publisher`, whose connection string is sniffed onto the
840
+ * producing construct) and subscribers bind via `s.topic(topic)`; this generator
841
+ * only records the topic + its event contract so infra can provision the SNS
842
+ * topic. Identical output for every provider (locally pg-boss routes by event
843
+ * name, so there's nothing to run).
844
+ */
845
+ var TopicGenerator = class extends require_openapi.ConstructGenerator {
846
+ isConstruct(value) {
847
+ return __geekmidas_constructs_topic.Topic.isTopic(value);
848
+ }
849
+ async build(_context, constructs, _outputDir, _options) {
850
+ const logger$13 = console;
851
+ const topicInfos = constructs.map(({ construct }) => ({
852
+ name: construct.name,
853
+ events: construct.eventTypes
854
+ }));
855
+ for (const topic of topicInfos) logger$13.log(`Discovered topic: ${topic.name}`);
856
+ return topicInfos;
857
+ }
858
+ };
859
+
1123
860
  //#endregion
1124
861
  //#region src/exec/index.ts
1125
- const logger$12 = console;
862
+ const logger$11 = console;
1126
863
  /**
1127
864
  * Run a command with secrets injected into Credentials.
1128
865
  * Uses Node's --import flag to preload a script that populates Credentials
@@ -1137,22 +874,22 @@ const logger$12 = console;
1137
874
  async function execCommand(commandArgs, options = {}) {
1138
875
  const cwd = options.cwd ?? process.cwd();
1139
876
  if (commandArgs.length === 0) throw new Error("No command specified. Usage: gkm exec -- <command>");
1140
- const defaultEnv = loadEnvFiles(".env");
1141
- if (defaultEnv.loaded.length > 0) logger$12.log(`📦 Loaded env: ${defaultEnv.loaded.join(", ")}`);
1142
- const { credentials, secretsJsonPath, appName } = await prepareEntryCredentials({
877
+ const defaultEnv = require_setup.loadEnvFiles(".env");
878
+ if (defaultEnv.loaded.length > 0) logger$11.log(`📦 Loaded env: ${defaultEnv.loaded.join(", ")}`);
879
+ const { credentials, secretsJsonPath, appName } = await require_setup.prepareEntryCredentials({
1143
880
  cwd,
1144
881
  resolveDockerPorts: "readonly"
1145
882
  });
1146
- if (appName) logger$12.log(`📦 App: ${appName}`);
883
+ if (appName) logger$11.log(`📦 App: ${appName}`);
1147
884
  const secretCount = Object.keys(credentials).filter((k) => k !== "PORT").length;
1148
- if (secretCount > 0) logger$12.log(`🔐 Loaded ${secretCount} secret(s)`);
885
+ if (secretCount > 0) logger$11.log(`🔐 Loaded ${secretCount} secret(s)`);
1149
886
  const preloadDir = (0, node_path.join)(cwd, ".gkm");
1150
887
  await (0, node_fs_promises.mkdir)(preloadDir, { recursive: true });
1151
888
  const preloadPath = (0, node_path.join)(preloadDir, "credentials-preload.mjs");
1152
- await createCredentialsPreload(preloadPath, secretsJsonPath);
889
+ await require_setup.createCredentialsPreload(preloadPath, secretsJsonPath);
1153
890
  const [cmd, ...args] = commandArgs;
1154
891
  if (!cmd) throw new Error("No command specified");
1155
- logger$12.log(`🚀 Running: ${[cmd, ...args].join(" ")}`);
892
+ logger$11.log(`🚀 Running: ${[cmd, ...args].join(" ")}`);
1156
893
  const existingNodeOptions = (process.env.NODE_OPTIONS ?? "").replace(/--import[= ]\S+/g, "").trim();
1157
894
  const preloadImport = `--import=${preloadPath}`;
1158
895
  const nodeOptions = [existingNodeOptions, preloadImport].filter(Boolean).join(" ");
@@ -1165,11 +902,11 @@ async function execCommand(commandArgs, options = {}) {
1165
902
  NODE_OPTIONS: nodeOptions
1166
903
  }
1167
904
  });
1168
- const exitCode = await new Promise((resolve$4) => {
1169
- child.on("close", (code) => resolve$4(code ?? 0));
905
+ const exitCode = await new Promise((resolve$3) => {
906
+ child.on("close", (code) => resolve$3(code ?? 0));
1170
907
  child.on("error", (error) => {
1171
- logger$12.error(`Failed to run command: ${error.message}`);
1172
- resolve$4(1);
908
+ logger$11.error(`Failed to run command: ${error.message}`);
909
+ resolve$3(1);
1173
910
  });
1174
911
  });
1175
912
  if (exitCode !== 0) process.exit(exitCode);
@@ -1177,7 +914,7 @@ async function execCommand(commandArgs, options = {}) {
1177
914
 
1178
915
  //#endregion
1179
916
  //#region src/dev/index.ts
1180
- const logger$11 = console;
917
+ const logger$10 = console;
1181
918
  /**
1182
919
  * Normalize telescope configuration
1183
920
  * @internal Exported for testing
@@ -1274,8 +1011,8 @@ function getProductionConfigFromGkm(config) {
1274
1011
  }
1275
1012
  async function devCommand(options) {
1276
1013
  if (options.entry) return entryDevCommand(options);
1277
- const defaultEnv = loadEnvFiles(".env");
1278
- if (defaultEnv.loaded.length > 0) logger$11.log(`📦 Loaded env: ${defaultEnv.loaded.join(", ")}`);
1014
+ const defaultEnv = require_setup.loadEnvFiles(".env");
1015
+ if (defaultEnv.loaded.length > 0) logger$10.log(`📦 Loaded env: ${defaultEnv.loaded.join(", ")}`);
1279
1016
  const appName = require_config.getAppNameFromCwd();
1280
1017
  let config;
1281
1018
  let appRoot = process.cwd();
@@ -1291,9 +1028,9 @@ async function devCommand(options) {
1291
1028
  workspaceAppName = appConfig.appName;
1292
1029
  workspaceAppPort = appConfig.app.port;
1293
1030
  workspace = appConfig.workspace;
1294
- logger$11.log(`📦 Running app: ${appConfig.appName} on port ${workspaceAppPort}`);
1031
+ logger$10.log(`📦 Running app: ${appConfig.appName} on port ${workspaceAppPort}`);
1295
1032
  if (appConfig.app.entry) {
1296
- logger$11.log(`📄 Using entry point: ${appConfig.app.entry}`);
1033
+ logger$10.log(`📄 Using entry point: ${appConfig.app.entry}`);
1297
1034
  return entryDevCommand({
1298
1035
  ...options,
1299
1036
  entry: appConfig.app.entry,
@@ -1304,7 +1041,7 @@ async function devCommand(options) {
1304
1041
  } catch {
1305
1042
  const loadedConfig = await require_config.loadWorkspaceConfig();
1306
1043
  if (loadedConfig.type === "workspace") {
1307
- logger$11.log("📦 Detected workspace configuration");
1044
+ logger$10.log("📦 Detected workspace configuration");
1308
1045
  return workspaceDevCommand(loadedConfig.workspace, options);
1309
1046
  }
1310
1047
  config = loadedConfig.raw;
@@ -1312,34 +1049,34 @@ async function devCommand(options) {
1312
1049
  else {
1313
1050
  const loadedConfig = await require_config.loadWorkspaceConfig();
1314
1051
  if (loadedConfig.type === "workspace") {
1315
- logger$11.log("📦 Detected workspace configuration");
1052
+ logger$10.log("📦 Detected workspace configuration");
1316
1053
  return workspaceDevCommand(loadedConfig.workspace, options);
1317
1054
  }
1318
1055
  config = loadedConfig.raw;
1319
1056
  }
1320
1057
  if (config.env) {
1321
- const { loaded, missing } = loadEnvFiles(config.env, appRoot);
1322
- if (loaded.length > 0) logger$11.log(`📦 Loaded env: ${loaded.join(", ")}`);
1323
- if (missing.length > 0) logger$11.warn(`⚠️ Missing env files: ${missing.join(", ")}`);
1058
+ const { loaded, missing } = require_setup.loadEnvFiles(config.env, appRoot);
1059
+ if (loaded.length > 0) logger$10.log(`📦 Loaded env: ${loaded.join(", ")}`);
1060
+ if (missing.length > 0) logger$10.warn(`⚠️ Missing env files: ${missing.join(", ")}`);
1324
1061
  }
1325
1062
  const resolved = resolveProviders(config, { provider: "server" });
1326
- logger$11.log("🚀 Starting development server...");
1327
- logger$11.log(`Loading routes from: ${config.routes}`);
1328
- if (config.functions) logger$11.log(`Loading functions from: ${config.functions}`);
1329
- if (config.crons) logger$11.log(`Loading crons from: ${config.crons}`);
1330
- if (config.subscribers) logger$11.log(`Loading subscribers from: ${config.subscribers}`);
1331
- logger$11.log(`Using envParser: ${config.envParser}`);
1063
+ logger$10.log("🚀 Starting development server...");
1064
+ logger$10.log(`Loading routes from: ${config.routes}`);
1065
+ if (config.functions) logger$10.log(`Loading functions from: ${config.functions}`);
1066
+ if (config.crons) logger$10.log(`Loading crons from: ${config.crons}`);
1067
+ if (config.subscribers) logger$10.log(`Loading subscribers from: ${config.subscribers}`);
1068
+ logger$10.log(`Using envParser: ${config.envParser}`);
1332
1069
  const { path: envParserPath, importPattern: envParserImportPattern } = require_config.parseModuleConfig(config.envParser, "envParser");
1333
1070
  const { path: loggerPath, importPattern: loggerImportPattern } = require_config.parseModuleConfig(config.logger, "logger");
1334
1071
  const telescope = normalizeTelescopeConfig(config.telescope);
1335
- if (telescope) logger$11.log(`🔭 Telescope enabled at ${telescope.path}`);
1072
+ if (telescope) logger$10.log(`🔭 Telescope enabled at ${telescope.path}`);
1336
1073
  const studio = normalizeStudioConfig(config.studio);
1337
- if (studio) logger$11.log(`🗄️ Studio enabled at ${studio.path}`);
1074
+ if (studio) logger$10.log(`🗄️ Studio enabled at ${studio.path}`);
1338
1075
  const hooks = normalizeHooksConfig(config.hooks, appRoot);
1339
- if (hooks) logger$11.log(`🪝 Server hooks enabled from ${config.hooks?.server}`);
1076
+ if (hooks) logger$10.log(`🪝 Server hooks enabled from ${config.hooks?.server}`);
1340
1077
  const openApiConfig = require_openapi.resolveOpenApiConfig(config);
1341
1078
  const enableOpenApi = openApiConfig.enabled || resolved.enableOpenApi;
1342
- if (enableOpenApi) logger$11.log(`📄 OpenAPI output: ${require_openapi.OPENAPI_OUTPUT_PATH}`);
1079
+ if (enableOpenApi) logger$10.log(`📄 OpenAPI output: ${require_openapi.OPENAPI_OUTPUT_PATH}`);
1343
1080
  const buildContext = {
1344
1081
  envParserPath,
1345
1082
  envParserImportPattern,
@@ -1353,12 +1090,12 @@ async function devCommand(options) {
1353
1090
  if (enableOpenApi) await require_openapi.generateOpenApi(config);
1354
1091
  const runtime = config.runtime ?? "node";
1355
1092
  let secretsJsonPath;
1356
- const appSecrets = await loadSecretsForApp(secretsRoot, workspaceAppName);
1357
- const resolvedPorts = await resolveServicePorts(secretsRoot);
1093
+ const appSecrets = await require_setup.loadSecretsForApp(secretsRoot, workspaceAppName);
1094
+ const resolvedPorts = await require_setup.resolveServicePorts(secretsRoot);
1358
1095
  if (Object.keys(resolvedPorts.ports).length > 0) {
1359
- const rewritten = rewriteUrlsWithPorts(appSecrets, resolvedPorts);
1096
+ const rewritten = require_setup.rewriteUrlsWithPorts(appSecrets, resolvedPorts);
1360
1097
  Object.assign(appSecrets, rewritten);
1361
- logger$11.log(`🔌 Applied ${Object.keys(resolvedPorts.ports).length} port mapping(s)`);
1098
+ logger$10.log(`🔌 Applied ${Object.keys(resolvedPorts.ports).length} port mapping(s)`);
1362
1099
  }
1363
1100
  if (workspace && workspaceAppName) {
1364
1101
  const depEnv = require_workspace.getDependencyEnvVars(workspace, workspaceAppName);
@@ -1370,7 +1107,7 @@ async function devCommand(options) {
1370
1107
  const secretsFileName = workspaceAppName ? `dev-secrets-${workspaceAppName}.json` : "dev-secrets.json";
1371
1108
  secretsJsonPath = (0, node_path.join)(secretsDir, secretsFileName);
1372
1109
  await (0, node_fs_promises.writeFile)(secretsJsonPath, JSON.stringify(appSecrets, null, 2));
1373
- logger$11.log(`🔐 Loaded ${Object.keys(appSecrets).length} secret(s)`);
1110
+ logger$10.log(`🔐 Loaded ${Object.keys(appSecrets).length} secret(s)`);
1374
1111
  }
1375
1112
  const devServer = new DevServer(resolved.providers[0], options.port ?? workspaceAppPort ?? 3e3, options.portExplicit ?? false, enableOpenApi, telescope, studio, runtime, appRoot, secretsJsonPath);
1376
1113
  await devServer.start();
@@ -1388,7 +1125,7 @@ async function devCommand(options) {
1388
1125
  ...hooksFile ? [hooksFile.endsWith(".ts") ? hooksFile : `${hooksFile}.ts`] : []
1389
1126
  ].flat().filter((p) => typeof p === "string");
1390
1127
  const normalizedPatterns = watchPatterns.map((p) => p.startsWith("./") ? p.slice(2) : p);
1391
- logger$11.log(`👀 Watching for changes in: ${normalizedPatterns.join(", ")}`);
1128
+ logger$10.log(`👀 Watching for changes in: ${normalizedPatterns.join(", ")}`);
1392
1129
  const resolvedFiles = await (0, fast_glob.default)(normalizedPatterns, {
1393
1130
  cwd: appRoot,
1394
1131
  absolute: false,
@@ -1398,7 +1135,7 @@ async function devCommand(options) {
1398
1135
  const parts = f.split("/");
1399
1136
  return parts.slice(0, -1).join("/");
1400
1137
  }))];
1401
- logger$11.log(`📁 Found ${resolvedFiles.length} files in ${dirsToWatch.length} directories`);
1138
+ logger$10.log(`📁 Found ${resolvedFiles.length} files in ${dirsToWatch.length} directories`);
1402
1139
  const watcher = chokidar.default.watch([...resolvedFiles, ...dirsToWatch], {
1403
1140
  ignored: /(^|[/\\])\../,
1404
1141
  persistent: true,
@@ -1406,29 +1143,29 @@ async function devCommand(options) {
1406
1143
  cwd: appRoot
1407
1144
  });
1408
1145
  watcher.on("ready", () => {
1409
- logger$11.log("🔍 File watcher ready");
1146
+ logger$10.log("🔍 File watcher ready");
1410
1147
  });
1411
1148
  watcher.on("error", (error) => {
1412
- logger$11.error("❌ Watcher error:", error);
1149
+ logger$10.error("❌ Watcher error:", error);
1413
1150
  });
1414
1151
  let rebuildTimeout = null;
1415
1152
  watcher.on("change", async (path) => {
1416
- logger$11.log(`📝 File changed: ${path}`);
1153
+ logger$10.log(`📝 File changed: ${path}`);
1417
1154
  if (rebuildTimeout) clearTimeout(rebuildTimeout);
1418
1155
  rebuildTimeout = setTimeout(async () => {
1419
1156
  try {
1420
- logger$11.log("🔄 Rebuilding...");
1157
+ logger$10.log("🔄 Rebuilding...");
1421
1158
  await buildServer(config, buildContext, resolved.providers[0], enableOpenApi, appRoot, true);
1422
1159
  if (enableOpenApi) await require_openapi.generateOpenApi(config, {
1423
1160
  silent: true,
1424
1161
  bustCache: true
1425
1162
  });
1426
- logger$11.log("✅ Rebuild complete, restarting server...");
1163
+ logger$10.log("✅ Rebuild complete, restarting server...");
1427
1164
  await devServer.restart();
1428
1165
  } catch (error) {
1429
1166
  const err = error;
1430
- logger$11.error(`❌ Rebuild failed: ${err.message}`);
1431
- if (err.stack) logger$11.error(err.stack);
1167
+ logger$10.error(`❌ Rebuild failed: ${err.message}`);
1168
+ if (err.stack) logger$10.error(err.stack);
1432
1169
  }
1433
1170
  }, 300);
1434
1171
  });
@@ -1436,9 +1173,9 @@ async function devCommand(options) {
1436
1173
  const shutdown = () => {
1437
1174
  if (isShuttingDown) return;
1438
1175
  isShuttingDown = true;
1439
- logger$11.log("\n🛑 Shutting down...");
1176
+ logger$10.log("\n🛑 Shutting down...");
1440
1177
  Promise.all([watcher.close(), devServer.stop()]).catch((err) => {
1441
- logger$11.error("Error during shutdown:", err);
1178
+ logger$10.error("Error during shutdown:", err);
1442
1179
  }).finally(() => {
1443
1180
  process.exit(0);
1444
1181
  });
@@ -1637,11 +1374,11 @@ async function loadDevSecrets(workspace) {
1637
1374
  for (const stage of stages) if (require_storage.secretsExist(stage, workspace.root)) {
1638
1375
  const secrets = await require_storage.readStageSecrets(stage, workspace.root);
1639
1376
  if (secrets) {
1640
- logger$11.log(`🔐 Loading secrets from stage: ${stage}`);
1377
+ logger$10.log(`🔐 Loading secrets from stage: ${stage}`);
1641
1378
  return require_storage.toEmbeddableSecrets(secrets);
1642
1379
  }
1643
1380
  }
1644
- logger$11.warn("⚠️ Secrets enabled but no dev/development secrets found. Run \"gkm setup\" to initialize your development environment");
1381
+ logger$10.warn("⚠️ Secrets enabled but no dev/development secrets found. Run \"gkm setup\" to initialize your development environment");
1645
1382
  return {};
1646
1383
  }
1647
1384
  /**
@@ -1658,39 +1395,39 @@ async function workspaceDevCommand(workspace, options) {
1658
1395
  const backendApps = Object.entries(workspace.apps).filter(([_, app]) => app.type === "backend");
1659
1396
  const frontendApps = Object.entries(workspace.apps).filter(([_, app]) => app.type === "web");
1660
1397
  const mobileApps = Object.entries(workspace.apps).filter(([_, app]) => app.type === "mobile");
1661
- logger$11.log(`\n🚀 Starting workspace: ${workspace.name}`);
1398
+ logger$10.log(`\n🚀 Starting workspace: ${workspace.name}`);
1662
1399
  const counts = [`${backendApps.length} backend`, `${frontendApps.length} web`];
1663
1400
  if (mobileApps.length > 0) counts.push(`${mobileApps.length} mobile`);
1664
- logger$11.log(` ${counts.join(", ")} app(s)`);
1401
+ logger$10.log(` ${counts.join(", ")} app(s)`);
1665
1402
  const conflicts = checkPortConflicts(workspace);
1666
1403
  if (conflicts.length > 0) {
1667
- for (const conflict of conflicts) logger$11.error(`❌ Port conflict: Apps "${conflict.app1}" and "${conflict.app2}" both use port ${conflict.port}`);
1404
+ for (const conflict of conflicts) logger$10.error(`❌ Port conflict: Apps "${conflict.app1}" and "${conflict.app2}" both use port ${conflict.port}`);
1668
1405
  throw new Error("Port conflicts detected. Please assign unique ports to each app.");
1669
1406
  }
1670
1407
  if (frontendApps.length > 0) {
1671
- logger$11.log("\n🔍 Validating frontend apps...");
1408
+ logger$10.log("\n🔍 Validating frontend apps...");
1672
1409
  const validationResults = await validateFrontendApps(workspace);
1673
1410
  let hasErrors = false;
1674
1411
  for (const result of validationResults) {
1675
1412
  if (!result.valid) {
1676
1413
  hasErrors = true;
1677
- logger$11.error(`\n❌ Frontend app "${result.appName}" validation failed:`);
1678
- for (const error of result.errors) logger$11.error(` • ${error}`);
1414
+ logger$10.error(`\n❌ Frontend app "${result.appName}" validation failed:`);
1415
+ for (const error of result.errors) logger$10.error(` • ${error}`);
1679
1416
  }
1680
- for (const warning of result.warnings) logger$11.warn(` ⚠️ ${result.appName}: ${warning}`);
1417
+ for (const warning of result.warnings) logger$10.warn(` ⚠️ ${result.appName}: ${warning}`);
1681
1418
  }
1682
1419
  if (hasErrors) throw new Error("Frontend app validation failed. Fix the issues above and try again.");
1683
- logger$11.log("✅ Frontend apps validated");
1420
+ logger$10.log("✅ Frontend apps validated");
1684
1421
  }
1685
- const resolvedPorts = await resolveServicePorts(workspace.root);
1422
+ const resolvedPorts = await require_setup.resolveServicePorts(workspace.root);
1686
1423
  const rawSecrets = await loadDevSecrets(workspace);
1687
- await startWorkspaceServices(workspace, resolvedPorts.dockerEnv, rawSecrets);
1688
- const secretsEnv = rewriteUrlsWithPorts(rawSecrets, resolvedPorts);
1689
- if (Object.keys(secretsEnv).length > 0) logger$11.log(` Loaded ${Object.keys(secretsEnv).length} secret(s)`);
1424
+ await require_setup.startWorkspaceServices(workspace, resolvedPorts.dockerEnv, rawSecrets);
1425
+ const secretsEnv = require_setup.rewriteUrlsWithPorts(rawSecrets, resolvedPorts);
1426
+ if (Object.keys(secretsEnv).length > 0) logger$10.log(` Loaded ${Object.keys(secretsEnv).length} secret(s)`);
1690
1427
  const dependencyEnv = generateAllDependencyEnvVars(workspace);
1691
1428
  if (Object.keys(dependencyEnv).length > 0) {
1692
- logger$11.log("📡 Dependency URLs:");
1693
- for (const [key, value] of Object.entries(dependencyEnv)) logger$11.log(` ${key}=${value}`);
1429
+ logger$10.log("📡 Dependency URLs:");
1430
+ for (const [key, value] of Object.entries(dependencyEnv)) logger$10.log(` ${key}=${value}`);
1694
1431
  }
1695
1432
  let turboFilter = [];
1696
1433
  if (options.app) {
@@ -1699,19 +1436,19 @@ async function workspaceDevCommand(workspace, options) {
1699
1436
  throw new Error(`App "${options.app}" not found. Available apps: ${appNames}`);
1700
1437
  }
1701
1438
  turboFilter = ["--filter", options.app];
1702
- logger$11.log(`\n🎯 Running single app: ${options.app}`);
1439
+ logger$10.log(`\n🎯 Running single app: ${options.app}`);
1703
1440
  } else if (options.filter) {
1704
1441
  turboFilter = ["--filter", options.filter];
1705
- logger$11.log(`\n🔍 Using filter: ${options.filter}`);
1706
- } else logger$11.log(`\n🎯 Running all ${appCount} apps`);
1442
+ logger$10.log(`\n🔍 Using filter: ${options.filter}`);
1443
+ } else logger$10.log(`\n🎯 Running all ${appCount} apps`);
1707
1444
  const buildOrder = require_workspace.getAppBuildOrder(workspace);
1708
- logger$11.log("\n📋 Apps (in dependency order):");
1445
+ logger$10.log("\n📋 Apps (in dependency order):");
1709
1446
  for (const appName of buildOrder) {
1710
1447
  const app = workspace.apps[appName];
1711
1448
  if (!app) continue;
1712
1449
  const deps = app.dependencies.length > 0 ? ` (depends on: ${app.dependencies.join(", ")})` : "";
1713
1450
  const icon = app.type === "backend" ? "🔧" : app.type === "mobile" ? "📱" : "🌐";
1714
- logger$11.log(` ${icon} ${appName} → http://localhost:${app.port}${deps}`);
1451
+ logger$10.log(` ${icon} ${appName} → http://localhost:${app.port}${deps}`);
1715
1452
  }
1716
1453
  const configFiles = [
1717
1454
  "gkm.config.ts",
@@ -1733,7 +1470,7 @@ async function workspaceDevCommand(workspace, options) {
1733
1470
  NODE_ENV: "development",
1734
1471
  ...configPath ? { GKM_CONFIG_PATH: configPath } : {}
1735
1472
  };
1736
- logger$11.log("\n🏃 Starting turbo run dev...\n");
1473
+ logger$10.log("\n🏃 Starting turbo run dev...\n");
1737
1474
  const turboProcess = (0, node_child_process.spawn)("pnpm", [
1738
1475
  "turbo",
1739
1476
  "run",
@@ -1749,7 +1486,7 @@ async function workspaceDevCommand(workspace, options) {
1749
1486
  const shutdown = () => {
1750
1487
  if (isShuttingDown) return;
1751
1488
  isShuttingDown = true;
1752
- logger$11.log("\n🛑 Shutting down workspace...");
1489
+ logger$10.log("\n🛑 Shutting down workspace...");
1753
1490
  const pid = turboProcess.pid;
1754
1491
  if (pid) try {
1755
1492
  process.kill(-pid, "SIGTERM");
@@ -1771,14 +1508,14 @@ async function workspaceDevCommand(workspace, options) {
1771
1508
  };
1772
1509
  process.on("SIGINT", shutdown);
1773
1510
  process.on("SIGTERM", shutdown);
1774
- return new Promise((resolve$4, reject) => {
1511
+ return new Promise((resolve$3, reject) => {
1775
1512
  turboProcess.on("error", (error) => {
1776
- logger$11.error("❌ Turbo error:", error);
1513
+ logger$10.error("❌ Turbo error:", error);
1777
1514
  reject(error);
1778
1515
  });
1779
1516
  turboProcess.on("exit", (code) => {
1780
1517
  if (code !== null && code !== 0) reject(new Error(`Turbo exited with code ${code}`));
1781
- else resolve$4();
1518
+ else resolve$3();
1782
1519
  });
1783
1520
  });
1784
1521
  }
@@ -1787,11 +1524,15 @@ async function buildServer(config, context, provider, enableOpenApi, appRoot = p
1787
1524
  const functionGenerator = new FunctionGenerator();
1788
1525
  const cronGenerator = new CronGenerator();
1789
1526
  const subscriberGenerator = new SubscriberGenerator();
1790
- const [allEndpoints, allFunctions, allCrons, allSubscribers] = await Promise.all([
1527
+ const queueGenerator = new QueueGenerator();
1528
+ const topicGenerator = new TopicGenerator();
1529
+ const [allEndpoints, allFunctions, allCrons, allSubscribers, allQueues, allTopics] = await Promise.all([
1791
1530
  endpointGenerator.load(config.routes, appRoot, bustCache),
1792
1531
  config.functions ? functionGenerator.load(config.functions, appRoot, bustCache) : [],
1793
1532
  config.crons ? cronGenerator.load(config.crons, appRoot, bustCache) : [],
1794
- config.subscribers ? subscriberGenerator.load(config.subscribers, appRoot, bustCache) : []
1533
+ config.subscribers ? subscriberGenerator.load(config.subscribers, appRoot, bustCache) : [],
1534
+ config.queues ? queueGenerator.load(config.queues, appRoot, bustCache) : [],
1535
+ config.topics ? topicGenerator.load(config.topics, appRoot, bustCache) : []
1795
1536
  ]);
1796
1537
  const outputDir = (0, node_path.join)(appRoot, ".gkm", provider);
1797
1538
  await (0, node_fs_promises.mkdir)(outputDir, { recursive: true });
@@ -1802,7 +1543,9 @@ async function buildServer(config, context, provider, enableOpenApi, appRoot = p
1802
1543
  }),
1803
1544
  functionGenerator.build(context, allFunctions, outputDir, { provider }),
1804
1545
  cronGenerator.build(context, allCrons, outputDir, { provider }),
1805
- subscriberGenerator.build(context, allSubscribers, outputDir, { provider })
1546
+ subscriberGenerator.build(context, allSubscribers, outputDir, { provider }),
1547
+ queueGenerator.build(context, allQueues, outputDir, { provider }),
1548
+ topicGenerator.build(context, allTopics, outputDir, { provider })
1806
1549
  ]);
1807
1550
  }
1808
1551
  /**
@@ -1814,23 +1557,23 @@ async function entryDevCommand(options) {
1814
1557
  if (!entry) throw new Error("--entry requires a file path");
1815
1558
  const entryPath = (0, node_path.resolve)(process.cwd(), entry);
1816
1559
  if (!(0, node_fs.existsSync)(entryPath)) throw new Error(`Entry file not found: ${entryPath}`);
1817
- const defaultEnv = loadEnvFiles(".env");
1818
- if (defaultEnv.loaded.length > 0) logger$11.log(`📦 Loaded env: ${defaultEnv.loaded.join(", ")}`);
1819
- const { credentials, resolvedPort, secretsJsonPath, appName } = await prepareEntryCredentials({ explicitPort: options.portExplicit ? options.port : void 0 });
1820
- if (appName) logger$11.log(`📦 App: ${appName} (port ${resolvedPort})`);
1821
- logger$11.log(`🚀 Starting entry file: ${entry} on port ${resolvedPort}`);
1822
- if (Object.keys(credentials).length > 1) logger$11.log(`🔐 Loaded ${Object.keys(credentials).length - 1} secret(s) + PORT`);
1560
+ const defaultEnv = require_setup.loadEnvFiles(".env");
1561
+ if (defaultEnv.loaded.length > 0) logger$10.log(`📦 Loaded env: ${defaultEnv.loaded.join(", ")}`);
1562
+ const { credentials, resolvedPort, secretsJsonPath, appName } = await require_setup.prepareEntryCredentials({ explicitPort: options.portExplicit ? options.port : void 0 });
1563
+ if (appName) logger$10.log(`📦 App: ${appName} (port ${resolvedPort})`);
1564
+ logger$10.log(`🚀 Starting entry file: ${entry} on port ${resolvedPort}`);
1565
+ if (Object.keys(credentials).length > 1) logger$10.log(`🔐 Loaded ${Object.keys(credentials).length - 1} secret(s) + PORT`);
1823
1566
  const wrapperDir = (0, node_path.join)(process.cwd(), ".gkm");
1824
1567
  await (0, node_fs_promises.mkdir)(wrapperDir, { recursive: true });
1825
1568
  const wrapperPath = (0, node_path.join)(wrapperDir, "entry-wrapper.ts");
1826
- await createEntryWrapper(wrapperPath, entryPath, secretsJsonPath);
1569
+ await require_setup.createEntryWrapper(wrapperPath, entryPath, secretsJsonPath);
1827
1570
  const runner = new EntryRunner(wrapperPath, entryPath, watch, resolvedPort);
1828
1571
  await runner.start();
1829
1572
  let isShuttingDown = false;
1830
1573
  const shutdown = () => {
1831
1574
  if (isShuttingDown) return;
1832
1575
  isShuttingDown = true;
1833
- logger$11.log("\n🛑 Shutting down...");
1576
+ logger$10.log("\n🛑 Shutting down...");
1834
1577
  runner.stop();
1835
1578
  process.exit(0);
1836
1579
  };
@@ -1862,14 +1605,14 @@ var EntryRunner = class {
1862
1605
  });
1863
1606
  let restartTimeout = null;
1864
1607
  this.watcher.on("change", (path) => {
1865
- logger$11.log(`📝 File changed: ${path}`);
1608
+ logger$10.log(`📝 File changed: ${path}`);
1866
1609
  if (restartTimeout) clearTimeout(restartTimeout);
1867
1610
  restartTimeout = setTimeout(async () => {
1868
- logger$11.log("🔄 Restarting...");
1611
+ logger$10.log("🔄 Restarting...");
1869
1612
  await this.restart();
1870
1613
  }, 300);
1871
1614
  });
1872
- logger$11.log(`👀 Watching for changes in: ${watchDir}`);
1615
+ logger$10.log(`👀 Watching for changes in: ${watchDir}`);
1873
1616
  }
1874
1617
  }
1875
1618
  async runProcess() {
@@ -1884,22 +1627,22 @@ var EntryRunner = class {
1884
1627
  });
1885
1628
  this.isRunning = true;
1886
1629
  this.childProcess.on("error", (error) => {
1887
- logger$11.error("❌ Process error:", error);
1630
+ logger$10.error("❌ Process error:", error);
1888
1631
  });
1889
1632
  this.childProcess.on("exit", (code) => {
1890
- if (code !== null && code !== 0 && code !== 143) logger$11.error(`❌ Process exited with code ${code}`);
1633
+ if (code !== null && code !== 0 && code !== 143) logger$10.error(`❌ Process exited with code ${code}`);
1891
1634
  this.isRunning = false;
1892
1635
  });
1893
- await new Promise((resolve$4) => setTimeout(resolve$4, 500));
1636
+ await new Promise((resolve$3) => setTimeout(resolve$3, 500));
1894
1637
  if (this.isRunning) {
1895
- logger$11.log("");
1896
- logger$11.log(` \x1b[32m✓ Ready\x1b[0m at \x1b[36mhttp://localhost:${this.port}\x1b[0m`);
1897
- logger$11.log("");
1638
+ logger$10.log("");
1639
+ logger$10.log(` \x1b[32m✓ Ready\x1b[0m at \x1b[36mhttp://localhost:${this.port}\x1b[0m`);
1640
+ logger$10.log("");
1898
1641
  }
1899
1642
  }
1900
1643
  async restart() {
1901
1644
  this.stopProcess();
1902
- await new Promise((resolve$4) => setTimeout(resolve$4, 500));
1645
+ await new Promise((resolve$3) => setTimeout(resolve$3, 500));
1903
1646
  await this.runProcess();
1904
1647
  }
1905
1648
  stop() {
@@ -2003,16 +1746,16 @@ var DevServer = class {
2003
1746
  this.startTime = Date.now();
2004
1747
  if (this.isRunning) await this.stop();
2005
1748
  if (this.portExplicit) {
2006
- const available = await isPortAvailable(this.requestedPort);
1749
+ const available = await require_setup.isPortAvailable(this.requestedPort);
2007
1750
  if (!available) throw new Error(`Port ${this.requestedPort} is already in use. Either stop the process using that port or omit -p/--port to auto-select an available port.`);
2008
1751
  this.actualPort = this.requestedPort;
2009
1752
  } else {
2010
- this.actualPort = await findAvailablePort(this.requestedPort);
2011
- if (this.actualPort !== this.requestedPort) logger$11.log(`ℹ️ Port ${this.requestedPort} was in use, using port ${this.actualPort} instead`);
1753
+ this.actualPort = await require_setup.findAvailablePort(this.requestedPort);
1754
+ if (this.actualPort !== this.requestedPort) logger$10.log(`ℹ️ Port ${this.requestedPort} was in use, using port ${this.actualPort} instead`);
2012
1755
  }
2013
1756
  const serverEntryPath = (0, node_path.join)(this.appRoot, ".gkm", this.provider, "server.ts");
2014
1757
  await this.createServerEntry();
2015
- logger$11.log(`\n⏳ Starting server...`);
1758
+ logger$10.log(`\n⏳ Starting server...`);
2016
1759
  this.serverProcess = (0, node_child_process.spawn)("npx", [
2017
1760
  "tsx",
2018
1761
  serverEntryPath,
@@ -2028,13 +1771,13 @@ var DevServer = class {
2028
1771
  });
2029
1772
  this.isRunning = true;
2030
1773
  this.serverProcess.on("error", (error) => {
2031
- logger$11.error("❌ Server error:", error);
1774
+ logger$10.error("❌ Server error:", error);
2032
1775
  });
2033
1776
  this.serverProcess.on("exit", (code, signal) => {
2034
- if (code !== null && code !== 0 && signal !== "SIGTERM") logger$11.error(`❌ Server exited with code ${code}`);
1777
+ if (code !== null && code !== 0 && signal !== "SIGTERM") logger$10.error(`❌ Server exited with code ${code}`);
2035
1778
  this.isRunning = false;
2036
1779
  });
2037
- await new Promise((resolve$4) => setTimeout(resolve$4, 1e3));
1780
+ await new Promise((resolve$3) => setTimeout(resolve$3, 1e3));
2038
1781
  if (this.isRunning) {
2039
1782
  const base = `http://localhost:${this.actualPort}`;
2040
1783
  const lines = [` Local: ${base}`];
@@ -2044,13 +1787,13 @@ var DevServer = class {
2044
1787
  const maxLen = Math.max(...lines.map((l) => l.length));
2045
1788
  const pad = (s) => s.padEnd(maxLen);
2046
1789
  const border = "─".repeat(maxLen + 2);
2047
- logger$11.log("");
2048
- logger$11.log(` \x1b[32m✓ Ready\x1b[0m in ${((Date.now() - this.startTime) / 1e3).toFixed(1)}s`);
2049
- logger$11.log("");
2050
- logger$11.log(` ┌${border}┐`);
2051
- for (const line of lines) logger$11.log(` │ ${pad(line)} │`);
2052
- logger$11.log(` └${border}┘`);
2053
- logger$11.log("");
1790
+ logger$10.log("");
1791
+ logger$10.log(` \x1b[32m✓ Ready\x1b[0m in ${((Date.now() - this.startTime) / 1e3).toFixed(1)}s`);
1792
+ logger$10.log("");
1793
+ logger$10.log(` ┌${border}┐`);
1794
+ for (const line of lines) logger$10.log(` │ ${pad(line)} │`);
1795
+ logger$10.log(` └${border}┘`);
1796
+ logger$10.log("");
2054
1797
  }
2055
1798
  }
2056
1799
  async stop() {
@@ -2079,8 +1822,8 @@ var DevServer = class {
2079
1822
  await this.stop();
2080
1823
  let attempts = 0;
2081
1824
  while (attempts < 30) {
2082
- if (await isPortAvailable(portToReuse)) break;
2083
- await new Promise((resolve$4) => setTimeout(resolve$4, 100));
1825
+ if (await require_setup.isPortAvailable(portToReuse)) break;
1826
+ await new Promise((resolve$3) => setTimeout(resolve$3, 100));
2084
1827
  attempts++;
2085
1828
  }
2086
1829
  this.requestedPort = portToReuse;
@@ -2100,7 +1843,7 @@ var DevServer = class {
2100
1843
 
2101
1844
  //#endregion
2102
1845
  //#region src/build/manifests.ts
2103
- const logger$10 = console;
1846
+ const logger$9 = console;
2104
1847
  function isPartitioned(field) {
2105
1848
  return !Array.isArray(field);
2106
1849
  }
@@ -2133,7 +1876,7 @@ function generateDerivedType(fieldName, typeName, partitioned) {
2133
1876
  }
2134
1877
  return `export type ${typeName} = (typeof manifest.${fieldName})[number];`;
2135
1878
  }
2136
- async function generateAwsManifest(outputDir, routes, functions, crons, subscribers) {
1879
+ async function generateAwsManifest(outputDir, routes, functions, crons, subscribers, queues = [], topics = []) {
2137
1880
  const manifestDir = (0, node_path.join)(outputDir, "manifest");
2138
1881
  await (0, node_fs_promises.mkdir)(manifestDir, { recursive: true });
2139
1882
  const awsRoutes = filterAllRoutes(routes);
@@ -2141,11 +1884,15 @@ async function generateAwsManifest(outputDir, routes, functions, crons, subscrib
2141
1884
  const functionsPartitioned = isPartitioned(functions);
2142
1885
  const cronsPartitioned = isPartitioned(crons);
2143
1886
  const subscribersPartitioned = isPartitioned(subscribers);
1887
+ const queuesPartitioned = isPartitioned(queues);
1888
+ const topicsPartitioned = isPartitioned(topics);
2144
1889
  const content = `export const manifest = {
2145
1890
  routes: ${serializeField(awsRoutes)},
2146
1891
  functions: ${serializeField(functions)},
2147
1892
  crons: ${serializeField(crons)},
2148
1893
  subscribers: ${serializeField(subscribers)},
1894
+ queues: ${serializeField(queues)},
1895
+ topics: ${serializeField(topics)},
2149
1896
  } as const;
2150
1897
 
2151
1898
  // Derived types
@@ -2153,6 +1900,8 @@ ${generateDerivedType("routes", "Route", routesPartitioned)}
2153
1900
  ${generateDerivedType("functions", "Function", functionsPartitioned)}
2154
1901
  ${generateDerivedType("crons", "Cron", cronsPartitioned)}
2155
1902
  ${generateDerivedType("subscribers", "Subscriber", subscribersPartitioned)}
1903
+ ${generateDerivedType("queues", "Queue", queuesPartitioned)}
1904
+ ${generateDerivedType("topics", "Topic", topicsPartitioned)}
2156
1905
 
2157
1906
  // Useful union types
2158
1907
  export type Authorizer = Route['authorizer'];
@@ -2161,25 +1910,33 @@ export type RoutePath = Route['path'];
2161
1910
  `;
2162
1911
  const manifestPath = (0, node_path.join)(manifestDir, "aws.ts");
2163
1912
  await (0, node_fs_promises.writeFile)(manifestPath, content);
2164
- logger$10.log(`Generated AWS manifest with ${countItems(awsRoutes)} routes, ${countItems(functions)} functions, ${countItems(crons)} crons, ${countItems(subscribers)} subscribers`);
2165
- logger$10.log(`Manifest: ${(0, node_path.relative)(process.cwd(), manifestPath)}`);
1913
+ logger$9.log(`Generated AWS manifest with ${countItems(awsRoutes)} routes, ${countItems(functions)} functions, ${countItems(crons)} crons, ${countItems(subscribers)} subscribers, ${countItems(queues)} queues, ${countItems(topics)} topics`);
1914
+ logger$9.log(`Manifest: ${(0, node_path.relative)(process.cwd(), manifestPath)}`);
2166
1915
  }
2167
- async function generateServerManifest(outputDir, appInfo, routes, subscribers) {
1916
+ async function generateServerManifest(outputDir, appInfo, routes, subscribers, queues = [], topics = []) {
2168
1917
  const manifestDir = (0, node_path.join)(outputDir, "manifest");
2169
1918
  await (0, node_fs_promises.mkdir)(manifestDir, { recursive: true });
2170
1919
  const serverRoutes = mapRouteMetadata(filterAllRoutes(routes));
2171
1920
  const serverSubscribers = mapSubscriberMetadata(subscribers);
1921
+ const serverQueues = mapQueueMetadata(queues);
1922
+ const serverTopics = mapTopicMetadata(topics);
2172
1923
  const routesPartitioned = isPartitioned(serverRoutes);
2173
1924
  const subscribersPartitioned = isPartitioned(serverSubscribers);
1925
+ const queuesPartitioned = isPartitioned(serverQueues);
1926
+ const topicsPartitioned = isPartitioned(serverTopics);
2174
1927
  const content = `export const manifest = {
2175
1928
  app: ${JSON.stringify(appInfo, null, 2)},
2176
1929
  routes: ${serializeField(serverRoutes)},
2177
1930
  subscribers: ${serializeField(serverSubscribers)},
1931
+ queues: ${serializeField(serverQueues)},
1932
+ topics: ${serializeField(serverTopics)},
2178
1933
  } as const;
2179
1934
 
2180
1935
  // Derived types
2181
1936
  ${generateDerivedType("routes", "Route", routesPartitioned)}
2182
1937
  ${generateDerivedType("subscribers", "Subscriber", subscribersPartitioned)}
1938
+ ${generateDerivedType("queues", "Queue", queuesPartitioned)}
1939
+ ${generateDerivedType("topics", "Topic", topicsPartitioned)}
2183
1940
 
2184
1941
  // Useful union types
2185
1942
  export type Authorizer = Route['authorizer'];
@@ -2188,8 +1945,8 @@ export type RoutePath = Route['path'];
2188
1945
  `;
2189
1946
  const manifestPath = (0, node_path.join)(manifestDir, "server.ts");
2190
1947
  await (0, node_fs_promises.writeFile)(manifestPath, content);
2191
- logger$10.log(`Generated server manifest with ${countItems(serverRoutes)} routes, ${countItems(serverSubscribers)} subscribers`);
2192
- logger$10.log(`Manifest: ${(0, node_path.relative)(process.cwd(), manifestPath)}`);
1948
+ logger$9.log(`Generated server manifest with ${countItems(serverRoutes)} routes, ${countItems(serverSubscribers)} subscribers, ${countItems(serverQueues)} queues, ${countItems(serverTopics)} topics`);
1949
+ logger$9.log(`Manifest: ${(0, node_path.relative)(process.cwd(), manifestPath)}`);
2193
1950
  }
2194
1951
  /**
2195
1952
  * Filter out 'ALL' method routes from a manifest field (flat or partitioned).
@@ -2227,6 +1984,23 @@ function mapSubscriberMetadata(subscribers) {
2227
1984
  for (const [partition, partitionSubs] of Object.entries(subscribers)) result[partition] = partitionSubs.map(mapFn);
2228
1985
  return result;
2229
1986
  }
1987
+ function mapQueueMetadata(queues) {
1988
+ const mapFn = (q) => ({ name: q.name });
1989
+ if (Array.isArray(queues)) return queues.map(mapFn);
1990
+ const result = {};
1991
+ for (const [partition, partitionQueues] of Object.entries(queues)) result[partition] = partitionQueues.map(mapFn);
1992
+ return result;
1993
+ }
1994
+ function mapTopicMetadata(topics) {
1995
+ const mapFn = (t) => ({
1996
+ name: t.name,
1997
+ events: t.events
1998
+ });
1999
+ if (Array.isArray(topics)) return topics.map(mapFn);
2000
+ const result = {};
2001
+ for (const [partition, partitionTopics] of Object.entries(topics)) result[partition] = partitionTopics.map(mapFn);
2002
+ return result;
2003
+ }
2230
2004
 
2231
2005
  //#endregion
2232
2006
  //#region src/build/partitions.ts
@@ -2255,7 +2029,7 @@ function groupInfosByPartition(infos, constructs) {
2255
2029
 
2256
2030
  //#endregion
2257
2031
  //#region src/build/index.ts
2258
- const logger$9 = console;
2032
+ const logger$8 = console;
2259
2033
  async function buildCommand(options) {
2260
2034
  const loadedConfig = await require_config.loadWorkspaceConfig();
2261
2035
  if (loadedConfig.type === "workspace") {
@@ -2263,7 +2037,7 @@ async function buildCommand(options) {
2263
2037
  const workspaceRoot = (0, node_path.resolve)(loadedConfig.workspace.root);
2264
2038
  const isAtWorkspaceRoot = cwd === workspaceRoot;
2265
2039
  if (isAtWorkspaceRoot) {
2266
- logger$9.log("📦 Detected workspace configuration");
2040
+ logger$8.log("📦 Detected workspace configuration");
2267
2041
  return workspaceBuildCommand(loadedConfig.workspace, options);
2268
2042
  }
2269
2043
  }
@@ -2271,21 +2045,21 @@ async function buildCommand(options) {
2271
2045
  const resolved = resolveProviders(config, options);
2272
2046
  const productionConfigFromGkm = getProductionConfigFromGkm(config);
2273
2047
  const production = normalizeProductionConfig(options.production ?? false, productionConfigFromGkm);
2274
- if (production) logger$9.log(`🏭 Building for PRODUCTION`);
2275
- logger$9.log(`Building with providers: ${resolved.providers.join(", ")}`);
2276
- logger$9.log(`Loading routes from: ${formatRoutes(config.routes)}`);
2277
- if (config.functions) logger$9.log(`Loading functions from: ${formatRoutes(config.functions)}`);
2278
- if (config.crons) logger$9.log(`Loading crons from: ${formatRoutes(config.crons)}`);
2279
- if (config.subscribers) logger$9.log(`Loading subscribers from: ${formatRoutes(config.subscribers)}`);
2280
- logger$9.log(`Using envParser: ${config.envParser}`);
2048
+ if (production) logger$8.log(`🏭 Building for PRODUCTION`);
2049
+ logger$8.log(`Building with providers: ${resolved.providers.join(", ")}`);
2050
+ logger$8.log(`Loading routes from: ${formatRoutes(config.routes)}`);
2051
+ if (config.functions) logger$8.log(`Loading functions from: ${formatRoutes(config.functions)}`);
2052
+ if (config.crons) logger$8.log(`Loading crons from: ${formatRoutes(config.crons)}`);
2053
+ if (config.subscribers) logger$8.log(`Loading subscribers from: ${formatRoutes(config.subscribers)}`);
2054
+ logger$8.log(`Using envParser: ${config.envParser}`);
2281
2055
  const { path: envParserPath, importPattern: envParserImportPattern } = require_config.parseModuleConfig(config.envParser, "envParser");
2282
2056
  const { path: loggerPath, importPattern: loggerImportPattern } = require_config.parseModuleConfig(config.logger, "logger");
2283
2057
  const telescope = production ? void 0 : normalizeTelescopeConfig(config.telescope);
2284
- if (telescope) logger$9.log(`🔭 Telescope enabled at ${telescope.path}`);
2058
+ if (telescope) logger$8.log(`🔭 Telescope enabled at ${telescope.path}`);
2285
2059
  const studio = production ? void 0 : normalizeStudioConfig(config.studio);
2286
- if (studio) logger$9.log(`🗄️ Studio enabled at ${studio.path}`);
2060
+ if (studio) logger$8.log(`🗄️ Studio enabled at ${studio.path}`);
2287
2061
  const hooks = normalizeHooksConfig(config.hooks);
2288
- if (hooks) logger$9.log(`🪝 Server hooks enabled`);
2062
+ if (hooks) logger$8.log(`🪝 Server hooks enabled`);
2289
2063
  const services = config.docker?.compose?.services;
2290
2064
  const dockerServices = services ? Array.isArray(services) ? {
2291
2065
  postgres: services.includes("postgres"),
@@ -2312,47 +2086,57 @@ async function buildCommand(options) {
2312
2086
  const functionGenerator = new FunctionGenerator();
2313
2087
  const cronGenerator = new CronGenerator();
2314
2088
  const subscriberGenerator = new SubscriberGenerator();
2315
- const [allEndpoints, allFunctions, allCrons, allSubscribers] = await Promise.all([
2089
+ const queueGenerator = new QueueGenerator();
2090
+ const topicGenerator = new TopicGenerator();
2091
+ const [allEndpoints, allFunctions, allCrons, allSubscribers, allQueues, allTopics] = await Promise.all([
2316
2092
  endpointGenerator.load(config.routes),
2317
2093
  config.functions ? functionGenerator.load(config.functions) : [],
2318
2094
  config.crons ? cronGenerator.load(config.crons) : [],
2319
- config.subscribers ? subscriberGenerator.load(config.subscribers) : []
2095
+ config.subscribers ? subscriberGenerator.load(config.subscribers) : [],
2096
+ config.queues ? queueGenerator.load(config.queues) : [],
2097
+ config.topics ? topicGenerator.load(config.topics) : []
2320
2098
  ]);
2321
- logger$9.log(`Found ${allEndpoints.length} endpoints`);
2322
- logger$9.log(`Found ${allFunctions.length} functions`);
2323
- logger$9.log(`Found ${allCrons.length} crons`);
2324
- logger$9.log(`Found ${allSubscribers.length} subscribers`);
2325
- if (allEndpoints.length === 0 && allFunctions.length === 0 && allCrons.length === 0 && allSubscribers.length === 0) {
2326
- logger$9.log("No endpoints, functions, crons, or subscribers found to process");
2099
+ logger$8.log(`Found ${allEndpoints.length} endpoints`);
2100
+ logger$8.log(`Found ${allFunctions.length} functions`);
2101
+ logger$8.log(`Found ${allCrons.length} crons`);
2102
+ logger$8.log(`Found ${allSubscribers.length} subscribers`);
2103
+ logger$8.log(`Found ${allQueues.length} queues`);
2104
+ logger$8.log(`Found ${allTopics.length} topics`);
2105
+ if (allEndpoints.length === 0 && allFunctions.length === 0 && allCrons.length === 0 && allSubscribers.length === 0 && allQueues.length === 0 && allTopics.length === 0) {
2106
+ logger$8.log("No endpoints, functions, crons, subscribers, queues, or topics found to process");
2327
2107
  return {};
2328
2108
  }
2329
2109
  const rootOutputDir = (0, node_path.join)(process.cwd(), ".gkm");
2330
2110
  await (0, node_fs_promises.mkdir)(rootOutputDir, { recursive: true });
2331
2111
  let result = {};
2332
2112
  for (const provider of resolved.providers) {
2333
- const providerResult = await buildForProvider(provider, buildContext, rootOutputDir, endpointGenerator, functionGenerator, cronGenerator, subscriberGenerator, allEndpoints, allFunctions, allCrons, allSubscribers, resolved.enableOpenApi, options.skipBundle ?? false, options.stage);
2113
+ const providerResult = await buildForProvider(provider, buildContext, rootOutputDir, endpointGenerator, functionGenerator, cronGenerator, subscriberGenerator, queueGenerator, topicGenerator, allEndpoints, allFunctions, allCrons, allSubscribers, allQueues, allTopics, resolved.enableOpenApi, options.skipBundle ?? false, options.stage);
2334
2114
  if (providerResult.masterKey) result = providerResult;
2335
2115
  }
2336
2116
  await require_openapi.generateOpenApi(config, { bustCache: true });
2337
2117
  return result;
2338
2118
  }
2339
- async function buildForProvider(provider, context, rootOutputDir, endpointGenerator, functionGenerator, cronGenerator, subscriberGenerator, endpoints, functions, crons, subscribers, enableOpenApi, skipBundle, stage) {
2119
+ async function buildForProvider(provider, context, rootOutputDir, endpointGenerator, functionGenerator, cronGenerator, subscriberGenerator, queueGenerator, topicGenerator, endpoints, functions, crons, subscribers, queues, topics, enableOpenApi, skipBundle, stage) {
2340
2120
  const outputDir = (0, node_path.join)(process.cwd(), ".gkm", provider);
2341
2121
  await (0, node_fs_promises.mkdir)(outputDir, { recursive: true });
2342
- logger$9.log(`\nGenerating handlers for provider: ${provider}`);
2343
- const [routes, functionInfos, cronInfos, subscriberInfos] = await Promise.all([
2122
+ logger$8.log(`\nGenerating handlers for provider: ${provider}`);
2123
+ const [routes, functionInfos, cronInfos, subscriberInfos, queueInfos, topicInfos] = await Promise.all([
2344
2124
  endpointGenerator.build(context, endpoints, outputDir, {
2345
2125
  provider,
2346
2126
  enableOpenApi
2347
2127
  }),
2348
2128
  functionGenerator.build(context, functions, outputDir, { provider }),
2349
2129
  cronGenerator.build(context, crons, outputDir, { provider }),
2350
- subscriberGenerator.build(context, subscribers, outputDir, { provider })
2130
+ subscriberGenerator.build(context, subscribers, outputDir, { provider }),
2131
+ queueGenerator.build(context, queues, outputDir, { provider }),
2132
+ topicGenerator.build(context, topics, outputDir, { provider })
2351
2133
  ]);
2352
- logger$9.log(`Generated ${routes.length} routes, ${functionInfos.length} functions, ${cronInfos.length} crons, ${subscriberInfos.length} subscribers for ${provider}`);
2134
+ logger$8.log(`Generated ${routes.length} routes, ${functionInfos.length} functions, ${cronInfos.length} crons, ${subscriberInfos.length} subscribers, ${queueInfos.length} queues, ${topicInfos.length} topics for ${provider}`);
2353
2135
  const manifestRoutes = assembleManifestField(routes, endpoints);
2354
2136
  const manifestFunctions = assembleManifestField(functionInfos, functions);
2355
2137
  const manifestCrons = assembleManifestField(cronInfos, crons);
2138
+ const manifestQueues = assembleManifestField(queueInfos, queues);
2139
+ const manifestTopics = assembleManifestField(topicInfos, topics);
2356
2140
  const manifestSubscribers = assembleManifestField(subscriberInfos, subscribers);
2357
2141
  if (provider === "server") {
2358
2142
  const routeMetadata = await Promise.all(endpoints.map(async ({ construct }) => ({
@@ -2366,16 +2150,17 @@ async function buildForProvider(provider, context, rootOutputDir, endpointGenera
2366
2150
  handler: (0, node_path.relative)(process.cwd(), (0, node_path.join)(outputDir, "app.ts")),
2367
2151
  endpoints: (0, node_path.relative)(process.cwd(), (0, node_path.join)(outputDir, "endpoints.ts"))
2368
2152
  };
2369
- await generateServerManifest(rootOutputDir, appInfo, serverRouteField, manifestSubscribers);
2153
+ await generateServerManifest(rootOutputDir, appInfo, serverRouteField, manifestSubscribers, manifestQueues, manifestTopics);
2370
2154
  let masterKey;
2371
2155
  if (context.production?.bundle && !skipBundle) {
2372
- logger$9.log(`\n📦 Bundling production server...`);
2373
- const { bundleServer } = await Promise.resolve().then(() => require("./bundler-BG6P249p.cjs"));
2156
+ logger$8.log(`\n📦 Bundling production server...`);
2157
+ const { bundleServer } = await Promise.resolve().then(() => require("./bundler-Dufq3uvI.cjs"));
2374
2158
  const allConstructs = [
2375
2159
  ...endpoints.map((e) => e.construct),
2376
2160
  ...functions.map((f) => f.construct),
2377
2161
  ...crons.map((c) => c.construct),
2378
- ...subscribers.map((s) => s.construct)
2162
+ ...subscribers.map((s) => s.construct),
2163
+ ...queues.map((q) => q.construct)
2379
2164
  ];
2380
2165
  const dockerServices = context.dockerServices;
2381
2166
  const bundleResult = await bundleServer({
@@ -2389,14 +2174,14 @@ async function buildForProvider(provider, context, rootOutputDir, endpointGenera
2389
2174
  dockerServices
2390
2175
  });
2391
2176
  masterKey = bundleResult.masterKey;
2392
- logger$9.log(`✅ Bundle complete: .gkm/server/dist/server.mjs`);
2177
+ logger$8.log(`✅ Bundle complete: .gkm/server/dist/server.mjs`);
2393
2178
  if (masterKey) {
2394
- logger$9.log(`\n🔐 Secrets encrypted for deployment`);
2395
- logger$9.log(` Deploy with: GKM_MASTER_KEY=${masterKey}`);
2179
+ logger$8.log(`\n🔐 Secrets encrypted for deployment`);
2180
+ logger$8.log(` Deploy with: GKM_MASTER_KEY=${masterKey}`);
2396
2181
  }
2397
2182
  }
2398
2183
  return { masterKey };
2399
- } else await generateAwsManifest(rootOutputDir, manifestRoutes, manifestFunctions, manifestCrons, manifestSubscribers);
2184
+ } else await generateAwsManifest(rootOutputDir, manifestRoutes, manifestFunctions, manifestCrons, manifestSubscribers, manifestQueues, manifestTopics);
2400
2185
  return {};
2401
2186
  }
2402
2187
  /**
@@ -2429,18 +2214,18 @@ async function workspaceBuildCommand(workspace, options) {
2429
2214
  const apps = Object.entries(workspace.apps);
2430
2215
  const backendApps = apps.filter(([, app]) => app.type === "backend");
2431
2216
  const frontendApps = apps.filter(([, app]) => app.type === "web");
2432
- logger$9.log(`\n🏗️ Building workspace: ${workspace.name}`);
2433
- logger$9.log(` Backend apps: ${backendApps.map(([name$1]) => name$1).join(", ") || "none"}`);
2434
- logger$9.log(` Frontend apps: ${frontendApps.map(([name$1]) => name$1).join(", ") || "none"}`);
2435
- if (options.production) logger$9.log(` 🏭 Production mode enabled`);
2217
+ logger$8.log(`\n🏗️ Building workspace: ${workspace.name}`);
2218
+ logger$8.log(` Backend apps: ${backendApps.map(([name$1]) => name$1).join(", ") || "none"}`);
2219
+ logger$8.log(` Frontend apps: ${frontendApps.map(([name$1]) => name$1).join(", ") || "none"}`);
2220
+ if (options.production) logger$8.log(` 🏭 Production mode enabled`);
2436
2221
  const buildOrder = require_workspace.getAppBuildOrder(workspace);
2437
- logger$9.log(` Build order: ${buildOrder.join(" → ")}`);
2222
+ logger$8.log(` Build order: ${buildOrder.join(" → ")}`);
2438
2223
  const pm = detectPackageManager$2();
2439
- logger$9.log(`\n📦 Using ${pm} with Turbo for parallel builds...\n`);
2224
+ logger$8.log(`\n📦 Using ${pm} with Turbo for parallel builds...\n`);
2440
2225
  try {
2441
2226
  const turboCommand = getTurboCommand(pm);
2442
- logger$9.log(`Running: ${turboCommand}`);
2443
- await new Promise((resolve$4, reject) => {
2227
+ logger$8.log(`Running: ${turboCommand}`);
2228
+ await new Promise((resolve$3, reject) => {
2444
2229
  const child = (0, node_child_process.spawn)(turboCommand, {
2445
2230
  shell: true,
2446
2231
  cwd: workspace.root,
@@ -2451,7 +2236,7 @@ async function workspaceBuildCommand(workspace, options) {
2451
2236
  }
2452
2237
  });
2453
2238
  child.on("close", (code) => {
2454
- if (code === 0) resolve$4();
2239
+ if (code === 0) resolve$3();
2455
2240
  else reject(new Error(`Turbo build failed with exit code ${code}`));
2456
2241
  });
2457
2242
  child.on("error", (err) => {
@@ -2467,16 +2252,16 @@ async function workspaceBuildCommand(workspace, options) {
2467
2252
  outputPath
2468
2253
  });
2469
2254
  }
2470
- logger$9.log(`\n✅ Workspace build complete!`);
2255
+ logger$8.log(`\n✅ Workspace build complete!`);
2471
2256
  await require_openapi.openapiCommand({ cwd: workspace.root });
2472
- logger$9.log(`\n📋 Build Summary:`);
2257
+ logger$8.log(`\n📋 Build Summary:`);
2473
2258
  for (const result of results) {
2474
2259
  const icon = result.type === "backend" ? "⚙️" : result.type === "mobile" ? "📱" : "🌐";
2475
- logger$9.log(` ${icon} ${result.appName}: ${result.outputPath || "built"}`);
2260
+ logger$8.log(` ${icon} ${result.appName}: ${result.outputPath || "built"}`);
2476
2261
  }
2477
2262
  } catch (error) {
2478
2263
  const errorMessage = error instanceof Error ? error.message : "Build failed";
2479
- logger$9.log(`\n❌ Build failed: ${errorMessage}`);
2264
+ logger$8.log(`\n❌ Build failed: ${errorMessage}`);
2480
2265
  for (const [appName, app] of apps) results.push({
2481
2266
  appName,
2482
2267
  type: app.type,
@@ -2703,11 +2488,11 @@ async function createDnsProvider(options) {
2703
2488
  if (isDnsProvider(config.provider)) return config.provider;
2704
2489
  const provider = config.provider;
2705
2490
  if (provider === "hostinger") {
2706
- const { HostingerProvider } = await Promise.resolve().then(() => require("./HostingerProvider-5KYmwoK2.cjs"));
2491
+ const { HostingerProvider } = await Promise.resolve().then(() => require("./HostingerProvider-CrHfsgz9.cjs"));
2707
2492
  return new HostingerProvider();
2708
2493
  }
2709
2494
  if (provider === "route53") {
2710
- const { Route53Provider } = await Promise.resolve().then(() => require("./Route53Provider-owQQ4pn6.cjs"));
2495
+ const { Route53Provider } = await Promise.resolve().then(() => require("./Route53Provider-DwgXiLxt.cjs"));
2711
2496
  const route53Config = config;
2712
2497
  return new Route53Provider({
2713
2498
  region: route53Config.region,
@@ -2721,7 +2506,7 @@ async function createDnsProvider(options) {
2721
2506
 
2722
2507
  //#endregion
2723
2508
  //#region src/deploy/dns/index.ts
2724
- const logger$8 = console;
2509
+ const logger$7 = console;
2725
2510
  /**
2726
2511
  * Check if DNS config is legacy format (single domain with `domain` property)
2727
2512
  */
@@ -2758,7 +2543,7 @@ function groupHostnamesByDomain(appHostnames, dnsConfig) {
2758
2543
  for (const [appName, hostname] of appHostnames) {
2759
2544
  const rootDomain = findRootDomain(hostname, dnsConfig);
2760
2545
  if (!rootDomain) {
2761
- logger$8.log(` ⚠ No DNS config found for hostname: ${hostname}`);
2546
+ logger$7.log(` ⚠ No DNS config found for hostname: ${hostname}`);
2762
2547
  continue;
2763
2548
  }
2764
2549
  if (!grouped.has(rootDomain)) grouped.set(rootDomain, /* @__PURE__ */ new Map());
@@ -2810,10 +2595,10 @@ function generateRequiredRecords(appHostnames, rootDomain, serverIp) {
2810
2595
  * Print DNS records table
2811
2596
  */
2812
2597
  function printDnsRecordsTable(records, rootDomain) {
2813
- logger$8.log(`\n 📋 DNS Records for ${rootDomain}:`);
2814
- logger$8.log(" ┌─────────────────────────────────────┬──────┬─────────────────┬────────┐");
2815
- logger$8.log(" │ Subdomain │ Type │ Value │ Status │");
2816
- logger$8.log(" ├─────────────────────────────────────┼──────┼─────────────────┼────────┤");
2598
+ logger$7.log(`\n 📋 DNS Records for ${rootDomain}:`);
2599
+ logger$7.log(" ┌─────────────────────────────────────┬──────┬─────────────────┬────────┐");
2600
+ logger$7.log(" │ Subdomain │ Type │ Value │ Status │");
2601
+ logger$7.log(" ├─────────────────────────────────────┼──────┼─────────────────┼────────┤");
2817
2602
  for (const record of records) {
2818
2603
  const subdomain = record.subdomain.padEnd(35);
2819
2604
  const type$1 = record.type.padEnd(4);
@@ -2823,18 +2608,18 @@ function printDnsRecordsTable(records, rootDomain) {
2823
2608
  else if (record.created) status = "✓ new";
2824
2609
  else if (record.existed) status = "✓";
2825
2610
  else status = "?";
2826
- logger$8.log(` │ ${subdomain} │ ${type$1} │ ${value} │ ${status.padEnd(6)} │`);
2611
+ logger$7.log(` │ ${subdomain} │ ${type$1} │ ${value} │ ${status.padEnd(6)} │`);
2827
2612
  }
2828
- logger$8.log(" └─────────────────────────────────────┴──────┴─────────────────┴────────┘");
2613
+ logger$7.log(" └─────────────────────────────────────┴──────┴─────────────────┴────────┘");
2829
2614
  }
2830
2615
  /**
2831
2616
  * Print DNS records in a simple format for manual setup
2832
2617
  */
2833
2618
  function printDnsRecordsSimple(records, rootDomain) {
2834
- logger$8.log("\n 📋 Required DNS Records:");
2835
- logger$8.log(` Add these A records to your DNS provider (${rootDomain}):\n`);
2836
- for (const record of records) logger$8.log(` ${record.subdomain} → ${record.value} (A record)`);
2837
- logger$8.log("");
2619
+ logger$7.log("\n 📋 Required DNS Records:");
2620
+ logger$7.log(` Add these A records to your DNS provider (${rootDomain}):\n`);
2621
+ for (const record of records) logger$7.log(` ${record.subdomain} → ${record.value} (A record)`);
2622
+ logger$7.log("");
2838
2623
  }
2839
2624
  /**
2840
2625
  * Create DNS records for a single domain using its configured provider
@@ -2846,7 +2631,7 @@ async function createDnsRecordsForDomain(records, rootDomain, providerConfig) {
2846
2631
  provider = await createDnsProvider({ config: providerConfig });
2847
2632
  } catch (error) {
2848
2633
  const message = error instanceof Error ? error.message : "Unknown error";
2849
- logger$8.log(` ⚠ Failed to create DNS provider for ${rootDomain}: ${message}`);
2634
+ logger$7.log(` ⚠ Failed to create DNS provider for ${rootDomain}: ${message}`);
2850
2635
  return records.map((r) => ({
2851
2636
  ...r,
2852
2637
  error: message
@@ -2900,7 +2685,7 @@ async function createDnsRecordsForDomain(records, rootDomain, providerConfig) {
2900
2685
  }
2901
2686
  } catch (error) {
2902
2687
  const message = error instanceof Error ? error.message : "Unknown error";
2903
- logger$8.log(` ⚠ Failed to create DNS records for ${rootDomain}: ${message}`);
2688
+ logger$7.log(` ⚠ Failed to create DNS records for ${rootDomain}: ${message}`);
2904
2689
  return records.map((r) => ({
2905
2690
  hostname: r.hostname,
2906
2691
  subdomain: r.subdomain,
@@ -2927,20 +2712,20 @@ async function createDnsRecordsForDomain(records, rootDomain, providerConfig) {
2927
2712
  async function orchestrateDns(appHostnames, dnsConfig, dokployEndpoint, state) {
2928
2713
  if (!dnsConfig) return null;
2929
2714
  const normalizedConfig = normalizeDnsConfig(dnsConfig);
2930
- logger$8.log("\n🌐 Setting up DNS records...");
2715
+ logger$7.log("\n🌐 Setting up DNS records...");
2931
2716
  let serverIp;
2932
2717
  try {
2933
2718
  const endpointUrl = new URL(dokployEndpoint);
2934
2719
  serverIp = await resolveHostnameToIp(endpointUrl.hostname);
2935
- logger$8.log(` Server IP: ${serverIp} (from ${endpointUrl.hostname})`);
2720
+ logger$7.log(` Server IP: ${serverIp} (from ${endpointUrl.hostname})`);
2936
2721
  } catch (error) {
2937
2722
  const message = error instanceof Error ? error.message : "Unknown error";
2938
- logger$8.log(` ⚠ Failed to resolve server IP: ${message}`);
2723
+ logger$7.log(` ⚠ Failed to resolve server IP: ${message}`);
2939
2724
  return null;
2940
2725
  }
2941
2726
  const groupedHostnames = groupHostnamesByDomain(appHostnames, normalizedConfig);
2942
2727
  if (groupedHostnames.size === 0) {
2943
- logger$8.log(" No DNS records needed (no hostnames match configured domains)");
2728
+ logger$7.log(" No DNS records needed (no hostnames match configured domains)");
2944
2729
  return {
2945
2730
  records: [],
2946
2731
  success: true,
@@ -2952,22 +2737,22 @@ async function orchestrateDns(appHostnames, dnsConfig, dokployEndpoint, state) {
2952
2737
  for (const [rootDomain, domainHostnames] of groupedHostnames) {
2953
2738
  const providerConfig = normalizedConfig[rootDomain];
2954
2739
  if (!providerConfig) {
2955
- logger$8.log(` ⚠ No provider config for ${rootDomain}`);
2740
+ logger$7.log(` ⚠ No provider config for ${rootDomain}`);
2956
2741
  continue;
2957
2742
  }
2958
2743
  const providerName = typeof providerConfig.provider === "string" ? providerConfig.provider : "custom";
2959
2744
  const requiredRecords = generateRequiredRecords(domainHostnames, rootDomain, serverIp);
2960
2745
  if (requiredRecords.length === 0) continue;
2961
- logger$8.log(` Creating DNS records for ${rootDomain} (${providerName})...`);
2746
+ logger$7.log(` Creating DNS records for ${rootDomain} (${providerName})...`);
2962
2747
  const domainRecords = await createDnsRecordsForDomain(requiredRecords, rootDomain, providerConfig);
2963
2748
  allRecords.push(...domainRecords);
2964
2749
  const created = domainRecords.filter((r) => r.created).length;
2965
2750
  const existed = domainRecords.filter((r) => r.existed).length;
2966
2751
  const failed = domainRecords.filter((r) => r.error).length;
2967
- if (created > 0) logger$8.log(` ✓ Created ${created} DNS record(s) for ${rootDomain}`);
2968
- if (existed > 0) logger$8.log(` ✓ ${existed} record(s) already exist for ${rootDomain}`);
2752
+ if (created > 0) logger$7.log(` ✓ Created ${created} DNS record(s) for ${rootDomain}`);
2753
+ if (existed > 0) logger$7.log(` ✓ ${existed} record(s) already exist for ${rootDomain}`);
2969
2754
  if (failed > 0) {
2970
- logger$8.log(` ⚠ ${failed} record(s) failed for ${rootDomain}`);
2755
+ logger$7.log(` ⚠ ${failed} record(s) failed for ${rootDomain}`);
2971
2756
  hasFailures = true;
2972
2757
  }
2973
2758
  if (state) {
@@ -3004,10 +2789,10 @@ async function orchestrateDns(appHostnames, dnsConfig, dokployEndpoint, state) {
3004
2789
  */
3005
2790
  async function verifyDnsRecords(appHostnames, serverIp, state) {
3006
2791
  const results = [];
3007
- logger$8.log("\n🔍 Verifying DNS records...");
2792
+ logger$7.log("\n🔍 Verifying DNS records...");
3008
2793
  for (const [appName, hostname] of appHostnames) {
3009
2794
  if (isDnsVerified(state, hostname, serverIp)) {
3010
- logger$8.log(` ✓ ${hostname} (previously verified)`);
2795
+ logger$7.log(` ✓ ${hostname} (previously verified)`);
3011
2796
  results.push({
3012
2797
  hostname,
3013
2798
  appName,
@@ -3021,7 +2806,7 @@ async function verifyDnsRecords(appHostnames, serverIp, state) {
3021
2806
  const resolvedIp = await resolveHostnameToIp(hostname);
3022
2807
  if (resolvedIp === serverIp) {
3023
2808
  setDnsVerification(state, hostname, serverIp);
3024
- logger$8.log(` ✓ ${hostname} → ${resolvedIp}`);
2809
+ logger$7.log(` ✓ ${hostname} → ${resolvedIp}`);
3025
2810
  results.push({
3026
2811
  hostname,
3027
2812
  appName,
@@ -3030,7 +2815,7 @@ async function verifyDnsRecords(appHostnames, serverIp, state) {
3030
2815
  expectedIp: serverIp
3031
2816
  });
3032
2817
  } else {
3033
- logger$8.log(` ⚠ ${hostname} resolves to ${resolvedIp}, expected ${serverIp}`);
2818
+ logger$7.log(` ⚠ ${hostname} resolves to ${resolvedIp}, expected ${serverIp}`);
3034
2819
  results.push({
3035
2820
  hostname,
3036
2821
  appName,
@@ -3041,7 +2826,7 @@ async function verifyDnsRecords(appHostnames, serverIp, state) {
3041
2826
  }
3042
2827
  } catch (error) {
3043
2828
  const message = error instanceof Error ? error.message : "Unknown error";
3044
- logger$8.log(` ⚠ ${hostname} DNS not propagated (${message})`);
2829
+ logger$7.log(` ⚠ ${hostname} DNS not propagated (${message})`);
3045
2830
  results.push({
3046
2831
  hostname,
3047
2832
  appName,
@@ -3055,9 +2840,9 @@ async function verifyDnsRecords(appHostnames, serverIp, state) {
3055
2840
  const skipped = results.filter((r) => r.skipped).length;
3056
2841
  const pending = results.filter((r) => !r.verified).length;
3057
2842
  if (pending > 0) {
3058
- logger$8.log(`\n ${verified} verified, ${pending} pending propagation`);
3059
- logger$8.log(" DNS changes may take 5-30 minutes to propagate");
3060
- } else if (skipped > 0) logger$8.log(` ${verified} verified (${skipped} from cache)`);
2843
+ logger$7.log(`\n ${verified} verified, ${pending} pending propagation`);
2844
+ logger$7.log(" DNS changes may take 5-30 minutes to propagate");
2845
+ } else if (skipped > 0) logger$7.log(` ${verified} verified (${skipped} from cache)`);
3061
2846
  return results;
3062
2847
  }
3063
2848
 
@@ -4528,7 +4313,7 @@ CMD ["nginx", "-g", "daemon off;"]
4528
4313
 
4529
4314
  //#endregion
4530
4315
  //#region src/docker/index.ts
4531
- const logger$7 = console;
4316
+ const logger$6 = console;
4532
4317
  /**
4533
4318
  * Docker command implementation
4534
4319
  * Generates Dockerfile, docker-compose.yml, and related files
@@ -4539,7 +4324,7 @@ const logger$7 = console;
4539
4324
  async function dockerCommand(options) {
4540
4325
  const loadedConfig = await require_config.loadWorkspaceConfig();
4541
4326
  if (loadedConfig.type === "workspace") {
4542
- logger$7.log("📦 Detected workspace configuration");
4327
+ logger$6.log("📦 Detected workspace configuration");
4543
4328
  return workspaceDockerCommand(loadedConfig.workspace, options);
4544
4329
  }
4545
4330
  const config = await require_config.loadConfig();
@@ -4560,14 +4345,14 @@ async function dockerCommand(options) {
4560
4345
  let useTurbo = options.turbo ?? false;
4561
4346
  if (inMonorepo && !useSlim) if (hasTurbo) {
4562
4347
  useTurbo = true;
4563
- logger$7.log(" Detected monorepo with turbo.json - using turbo prune");
4348
+ logger$6.log(" Detected monorepo with turbo.json - using turbo prune");
4564
4349
  } else throw new Error("Monorepo detected but turbo.json not found.\n\nDocker builds in monorepos require Turborepo for proper dependency isolation.\n\nTo fix this:\n 1. Install turbo: pnpm add -Dw turbo\n 2. Create turbo.json in your monorepo root\n 3. Run this command again\n\nSee: https://turbo.build/repo/docs/guides/tools/docker");
4565
4350
  let turboPackage = options.turboPackage ?? dockerConfig.imageName;
4566
4351
  if (useTurbo && !options.turboPackage) try {
4567
4352
  const pkg$1 = require(`${process.cwd()}/package.json`);
4568
4353
  if (pkg$1.name) {
4569
4354
  turboPackage = pkg$1.name;
4570
- logger$7.log(` Turbo package: ${turboPackage}`);
4355
+ logger$6.log(` Turbo package: ${turboPackage}`);
4571
4356
  }
4572
4357
  } catch {}
4573
4358
  const templateOptions = {
@@ -4584,7 +4369,7 @@ async function dockerCommand(options) {
4584
4369
  const dockerMode = useSlim ? "slim" : useTurbo ? "turbo" : "multi-stage";
4585
4370
  const dockerfilePath = (0, node_path.join)(dockerDir, "Dockerfile");
4586
4371
  await (0, node_fs_promises.writeFile)(dockerfilePath, dockerfile);
4587
- logger$7.log(`Generated: .gkm/docker/Dockerfile (${dockerMode}, ${packageManager})`);
4372
+ logger$6.log(`Generated: .gkm/docker/Dockerfile (${dockerMode}, ${packageManager})`);
4588
4373
  const composeOptions = {
4589
4374
  imageName: dockerConfig.imageName,
4590
4375
  registry: options.registry ?? dockerConfig.registry,
@@ -4596,15 +4381,15 @@ async function dockerCommand(options) {
4596
4381
  const dockerCompose = hasServices ? generateDockerCompose(composeOptions) : generateMinimalDockerCompose(composeOptions);
4597
4382
  const composePath = (0, node_path.join)(dockerDir, "docker-compose.yml");
4598
4383
  await (0, node_fs_promises.writeFile)(composePath, dockerCompose);
4599
- logger$7.log("Generated: .gkm/docker/docker-compose.yml");
4384
+ logger$6.log("Generated: .gkm/docker/docker-compose.yml");
4600
4385
  const dockerignore = generateDockerignore();
4601
4386
  const dockerignorePath = (0, node_path.join)(process.cwd(), ".dockerignore");
4602
4387
  await (0, node_fs_promises.writeFile)(dockerignorePath, dockerignore);
4603
- logger$7.log("Generated: .dockerignore (project root)");
4388
+ logger$6.log("Generated: .dockerignore (project root)");
4604
4389
  const entrypoint = generateDockerEntrypoint();
4605
4390
  const entrypointPath = (0, node_path.join)(dockerDir, "docker-entrypoint.sh");
4606
4391
  await (0, node_fs_promises.writeFile)(entrypointPath, entrypoint);
4607
- logger$7.log("Generated: .gkm/docker/docker-entrypoint.sh");
4392
+ logger$6.log("Generated: .gkm/docker/docker-entrypoint.sh");
4608
4393
  const result = {
4609
4394
  dockerfile: dockerfilePath,
4610
4395
  dockerCompose: composePath,
@@ -4623,13 +4408,13 @@ async function dockerCommand(options) {
4623
4408
  function ensureLockfile(cwd) {
4624
4409
  const lockfilePath = findLockfilePath(cwd);
4625
4410
  if (!lockfilePath) {
4626
- logger$7.warn("\n⚠️ No lockfile found. Docker build may fail or use stale dependencies.");
4411
+ logger$6.warn("\n⚠️ No lockfile found. Docker build may fail or use stale dependencies.");
4627
4412
  return null;
4628
4413
  }
4629
4414
  const lockfileName = (0, node_path.basename)(lockfilePath);
4630
4415
  const localLockfile = (0, node_path.join)(cwd, lockfileName);
4631
4416
  if (lockfilePath === localLockfile) return null;
4632
- logger$7.log(` Copying ${lockfileName} from monorepo root...`);
4417
+ logger$6.log(` Copying ${lockfileName} from monorepo root...`);
4633
4418
  (0, node_fs.copyFileSync)(lockfilePath, localLockfile);
4634
4419
  return () => {
4635
4420
  try {
@@ -4645,7 +4430,7 @@ async function buildDockerImage(imageName, options) {
4645
4430
  const tag = options.tag ?? "latest";
4646
4431
  const registry = options.registry;
4647
4432
  const fullImageName = registry ? `${registry}/${imageName}:${tag}` : `${imageName}:${tag}`;
4648
- logger$7.log(`\n🐳 Building Docker image: ${fullImageName}`);
4433
+ logger$6.log(`\n🐳 Building Docker image: ${fullImageName}`);
4649
4434
  const cwd = process.cwd();
4650
4435
  const cleanup = ensureLockfile(cwd);
4651
4436
  try {
@@ -4657,7 +4442,7 @@ async function buildDockerImage(imageName, options) {
4657
4442
  DOCKER_BUILDKIT: "1"
4658
4443
  }
4659
4444
  });
4660
- logger$7.log(`✅ Docker image built: ${fullImageName}`);
4445
+ logger$6.log(`✅ Docker image built: ${fullImageName}`);
4661
4446
  } catch (error) {
4662
4447
  throw new Error(`Failed to build Docker image: ${error instanceof Error ? error.message : "Unknown error"}`);
4663
4448
  } finally {
@@ -4672,13 +4457,13 @@ async function pushDockerImage(imageName, options) {
4672
4457
  const registry = options.registry;
4673
4458
  if (!registry) throw new Error("Registry is required to push Docker image. Use --registry or configure docker.registry in gkm.config.ts");
4674
4459
  const fullImageName = `${registry}/${imageName}:${tag}`;
4675
- logger$7.log(`\n🚀 Pushing Docker image: ${fullImageName}`);
4460
+ logger$6.log(`\n🚀 Pushing Docker image: ${fullImageName}`);
4676
4461
  try {
4677
4462
  (0, node_child_process.execSync)(`docker push ${fullImageName}`, {
4678
4463
  cwd: process.cwd(),
4679
4464
  stdio: "inherit"
4680
4465
  });
4681
- logger$7.log(`✅ Docker image pushed: ${fullImageName}`);
4466
+ logger$6.log(`✅ Docker image pushed: ${fullImageName}`);
4682
4467
  } catch (error) {
4683
4468
  throw new Error(`Failed to push Docker image: ${error instanceof Error ? error.message : "Unknown error"}`);
4684
4469
  }
@@ -4704,14 +4489,14 @@ function getAppPackageName(appPath) {
4704
4489
  async function workspaceDockerCommand(workspace, options) {
4705
4490
  const results = [];
4706
4491
  const apps = Object.entries(workspace.apps);
4707
- logger$7.log(`\n🐳 Generating Dockerfiles for workspace: ${workspace.name}`);
4492
+ logger$6.log(`\n🐳 Generating Dockerfiles for workspace: ${workspace.name}`);
4708
4493
  const dockerDir = (0, node_path.join)(workspace.root, ".gkm", "docker");
4709
4494
  await (0, node_fs_promises.mkdir)(dockerDir, { recursive: true });
4710
4495
  const packageManager = detectPackageManager$1(workspace.root);
4711
- logger$7.log(` Package manager: ${packageManager}`);
4496
+ logger$6.log(` Package manager: ${packageManager}`);
4712
4497
  for (const [appName, app] of apps) {
4713
4498
  if (app.type === "mobile") {
4714
- logger$7.log(`\n 📱 Skipping Docker for ${appName} (mobile app — deploy via framework toolchain)`);
4499
+ logger$6.log(`\n 📱 Skipping Docker for ${appName} (mobile app — deploy via framework toolchain)`);
4715
4500
  continue;
4716
4501
  }
4717
4502
  const appPath = app.path;
@@ -4720,7 +4505,7 @@ async function workspaceDockerCommand(workspace, options) {
4720
4505
  const imageName = appName;
4721
4506
  const hasEntry = !!app.entry;
4722
4507
  const buildType = hasEntry ? "entry" : app.type;
4723
- logger$7.log(`\n 📄 Generating Dockerfile for ${appName} (${buildType})`);
4508
+ logger$6.log(`\n 📄 Generating Dockerfile for ${appName} (${buildType})`);
4724
4509
  let dockerfile;
4725
4510
  if (app.type === "web") {
4726
4511
  const publicUrlArgs = getPublicUrlArgNames(app);
@@ -4764,7 +4549,7 @@ async function workspaceDockerCommand(workspace, options) {
4764
4549
  });
4765
4550
  const dockerfilePath = (0, node_path.join)(dockerDir, `Dockerfile.${appName}`);
4766
4551
  await (0, node_fs_promises.writeFile)(dockerfilePath, dockerfile);
4767
- logger$7.log(` Generated: .gkm/docker/Dockerfile.${appName}`);
4552
+ logger$6.log(` Generated: .gkm/docker/Dockerfile.${appName}`);
4768
4553
  results.push({
4769
4554
  appName,
4770
4555
  type: app.type,
@@ -4775,19 +4560,19 @@ async function workspaceDockerCommand(workspace, options) {
4775
4560
  const dockerignore = generateDockerignore();
4776
4561
  const dockerignorePath = (0, node_path.join)(workspace.root, ".dockerignore");
4777
4562
  await (0, node_fs_promises.writeFile)(dockerignorePath, dockerignore);
4778
- logger$7.log(`\n Generated: .dockerignore (workspace root)`);
4563
+ logger$6.log(`\n Generated: .dockerignore (workspace root)`);
4779
4564
  const dockerCompose = generateWorkspaceCompose(workspace, { registry: options.registry });
4780
4565
  const composePath = (0, node_path.join)(dockerDir, "docker-compose.yml");
4781
4566
  await (0, node_fs_promises.writeFile)(composePath, dockerCompose);
4782
- logger$7.log(` Generated: .gkm/docker/docker-compose.yml`);
4783
- logger$7.log(`\n✅ Generated ${results.length} Dockerfile(s) + docker-compose.yml`);
4784
- logger$7.log("\n📋 Build commands:");
4567
+ logger$6.log(` Generated: .gkm/docker/docker-compose.yml`);
4568
+ logger$6.log(`\n✅ Generated ${results.length} Dockerfile(s) + docker-compose.yml`);
4569
+ logger$6.log("\n📋 Build commands:");
4785
4570
  for (const result of results) {
4786
4571
  const icon = result.type === "backend" ? "⚙️" : result.type === "mobile" ? "📱" : "🌐";
4787
- logger$7.log(` ${icon} docker build -f .gkm/docker/Dockerfile.${result.appName} -t ${result.imageName} .`);
4572
+ logger$6.log(` ${icon} docker build -f .gkm/docker/Dockerfile.${result.appName} -t ${result.imageName} .`);
4788
4573
  }
4789
- logger$7.log("\n📋 Run all services:");
4790
- logger$7.log(" docker compose -f .gkm/docker/docker-compose.yml up --build");
4574
+ logger$6.log("\n📋 Run all services:");
4575
+ logger$6.log(" docker compose -f .gkm/docker/docker-compose.yml up --build");
4791
4576
  return {
4792
4577
  apps: results,
4793
4578
  dockerCompose: composePath,
@@ -4827,7 +4612,7 @@ function getAppNameFromPackageJson() {
4827
4612
  } catch {}
4828
4613
  return void 0;
4829
4614
  }
4830
- const logger$6 = console;
4615
+ const logger$5 = console;
4831
4616
  /**
4832
4617
  * Get the full image reference
4833
4618
  */
@@ -4842,18 +4627,18 @@ function getImageRef(registry, imageName, tag) {
4842
4627
  * @param buildArgs - Build arguments to pass to docker build
4843
4628
  */
4844
4629
  async function buildImage(imageRef, appName, buildArgs) {
4845
- logger$6.log(`\n🔨 Building Docker image: ${imageRef}`);
4630
+ logger$5.log(`\n🔨 Building Docker image: ${imageRef}`);
4846
4631
  const cwd = process.cwd();
4847
4632
  const lockfilePath = findLockfilePath(cwd);
4848
4633
  const lockfileDir = lockfilePath ? (0, node_path.dirname)(lockfilePath) : cwd;
4849
4634
  const inMonorepo = lockfileDir !== cwd;
4850
- if (appName || inMonorepo) logger$6.log(" Generating Dockerfile for monorepo (turbo prune)...");
4851
- else logger$6.log(" Generating Dockerfile...");
4635
+ if (appName || inMonorepo) logger$5.log(" Generating Dockerfile for monorepo (turbo prune)...");
4636
+ else logger$5.log(" Generating Dockerfile...");
4852
4637
  await dockerCommand({});
4853
4638
  const dockerfileSuffix = appName ? `.${appName}` : "";
4854
4639
  const dockerfilePath = `.gkm/docker/Dockerfile${dockerfileSuffix}`;
4855
4640
  const buildCwd = lockfilePath && (inMonorepo || appName) ? lockfileDir : cwd;
4856
- if (buildCwd !== cwd) logger$6.log(` Building from workspace root: ${buildCwd}`);
4641
+ if (buildCwd !== cwd) logger$5.log(` Building from workspace root: ${buildCwd}`);
4857
4642
  const buildArgsString = buildArgs && buildArgs.length > 0 ? buildArgs.map((arg) => `--build-arg "${arg}"`).join(" ") : "";
4858
4643
  try {
4859
4644
  const cmd = [
@@ -4872,7 +4657,7 @@ async function buildImage(imageRef, appName, buildArgs) {
4872
4657
  DOCKER_BUILDKIT: "1"
4873
4658
  }
4874
4659
  });
4875
- logger$6.log(`✅ Image built: ${imageRef}`);
4660
+ logger$5.log(`✅ Image built: ${imageRef}`);
4876
4661
  } catch (error) {
4877
4662
  throw new Error(`Failed to build Docker image: ${error instanceof Error ? error.message : "Unknown error"}`);
4878
4663
  }
@@ -4881,13 +4666,13 @@ async function buildImage(imageRef, appName, buildArgs) {
4881
4666
  * Push Docker image to registry
4882
4667
  */
4883
4668
  async function pushImage(imageRef) {
4884
- logger$6.log(`\n☁️ Pushing image: ${imageRef}`);
4669
+ logger$5.log(`\n☁️ Pushing image: ${imageRef}`);
4885
4670
  try {
4886
4671
  (0, node_child_process.execSync)(`docker push ${imageRef}`, {
4887
4672
  cwd: process.cwd(),
4888
4673
  stdio: "inherit"
4889
4674
  });
4890
- logger$6.log(`✅ Image pushed: ${imageRef}`);
4675
+ logger$5.log(`✅ Image pushed: ${imageRef}`);
4891
4676
  } catch (error) {
4892
4677
  throw new Error(`Failed to push Docker image: ${error instanceof Error ? error.message : "Unknown error"}`);
4893
4678
  }
@@ -4900,17 +4685,17 @@ async function deployDocker(options) {
4900
4685
  const imageName = config.imageName;
4901
4686
  const imageRef = getImageRef(config.registry, imageName, tag);
4902
4687
  await buildImage(imageRef, config.appName, buildArgs);
4903
- if (!skipPush) if (!config.registry) logger$6.warn("\n⚠️ No registry configured. Use --skip-push or configure docker.registry in gkm.config.ts");
4688
+ if (!skipPush) if (!config.registry) logger$5.warn("\n⚠️ No registry configured. Use --skip-push or configure docker.registry in gkm.config.ts");
4904
4689
  else await pushImage(imageRef);
4905
- logger$6.log("\n✅ Docker deployment ready!");
4906
- logger$6.log(`\n📋 Deployment details:`);
4907
- logger$6.log(` Image: ${imageRef}`);
4908
- logger$6.log(` Stage: ${stage}`);
4690
+ logger$5.log("\n✅ Docker deployment ready!");
4691
+ logger$5.log(`\n📋 Deployment details:`);
4692
+ logger$5.log(` Image: ${imageRef}`);
4693
+ logger$5.log(` Stage: ${stage}`);
4909
4694
  if (masterKey) {
4910
- logger$6.log(`\n🔐 Deploy with this environment variable:`);
4911
- logger$6.log(` GKM_MASTER_KEY=${masterKey}`);
4912
- logger$6.log("\n Example docker run:");
4913
- logger$6.log(` docker run -e GKM_MASTER_KEY=${masterKey} ${imageRef}`);
4695
+ logger$5.log(`\n🔐 Deploy with this environment variable:`);
4696
+ logger$5.log(` GKM_MASTER_KEY=${masterKey}`);
4697
+ logger$5.log("\n Example docker run:");
4698
+ logger$5.log(` docker run -e GKM_MASTER_KEY=${masterKey} ${imageRef}`);
4914
4699
  }
4915
4700
  return {
4916
4701
  imageRef,
@@ -4937,7 +4722,7 @@ function resolveDockerConfig(config) {
4937
4722
 
4938
4723
  //#endregion
4939
4724
  //#region src/deploy/dokploy.ts
4940
- const logger$5 = console;
4725
+ const logger$4 = console;
4941
4726
  /**
4942
4727
  * Get the Dokploy API token from stored credentials or environment
4943
4728
  */
@@ -4961,25 +4746,25 @@ async function createApi$1(endpoint) {
4961
4746
  */
4962
4747
  async function deployDokploy(options) {
4963
4748
  const { stage, imageRef, masterKey, config } = options;
4964
- logger$5.log(`\n🎯 Deploying to Dokploy...`);
4965
- logger$5.log(` Endpoint: ${config.endpoint}`);
4966
- logger$5.log(` Application: ${config.applicationId}`);
4749
+ logger$4.log(`\n🎯 Deploying to Dokploy...`);
4750
+ logger$4.log(` Endpoint: ${config.endpoint}`);
4751
+ logger$4.log(` Application: ${config.applicationId}`);
4967
4752
  const api = await createApi$1(config.endpoint);
4968
- logger$5.log(` Configuring Docker image: ${imageRef}`);
4753
+ logger$4.log(` Configuring Docker image: ${imageRef}`);
4969
4754
  const registryOptions = {};
4970
4755
  if (config.registryId) {
4971
4756
  registryOptions.registryId = config.registryId;
4972
- logger$5.log(` Using Dokploy registry: ${config.registryId}`);
4757
+ logger$4.log(` Using Dokploy registry: ${config.registryId}`);
4973
4758
  } else {
4974
4759
  const storedRegistryId = await require_credentials.getDokployRegistryId();
4975
4760
  if (storedRegistryId) {
4976
4761
  registryOptions.registryId = storedRegistryId;
4977
- logger$5.log(` Using stored Dokploy registry: ${storedRegistryId}`);
4762
+ logger$4.log(` Using stored Dokploy registry: ${storedRegistryId}`);
4978
4763
  } else if (config.registryCredentials) {
4979
4764
  registryOptions.username = config.registryCredentials.username;
4980
4765
  registryOptions.password = config.registryCredentials.password;
4981
4766
  registryOptions.registryUrl = config.registryCredentials.registryUrl;
4982
- logger$5.log(` Using registry credentials for: ${config.registryCredentials.registryUrl}`);
4767
+ logger$4.log(` Using registry credentials for: ${config.registryCredentials.registryUrl}`);
4983
4768
  } else {
4984
4769
  const username = process.env.DOCKER_REGISTRY_USERNAME;
4985
4770
  const password = process.env.DOCKER_REGISTRY_PASSWORD;
@@ -4988,31 +4773,31 @@ async function deployDokploy(options) {
4988
4773
  registryOptions.username = username;
4989
4774
  registryOptions.password = password;
4990
4775
  registryOptions.registryUrl = registryUrl;
4991
- logger$5.log(` Using registry credentials from environment`);
4776
+ logger$4.log(` Using registry credentials from environment`);
4992
4777
  }
4993
4778
  }
4994
4779
  }
4995
4780
  await api.saveDockerProvider(config.applicationId, imageRef, registryOptions);
4996
- logger$5.log(" ✓ Docker provider configured");
4781
+ logger$4.log(" ✓ Docker provider configured");
4997
4782
  const envVars = {};
4998
4783
  if (masterKey) envVars.GKM_MASTER_KEY = masterKey;
4999
4784
  if (Object.keys(envVars).length > 0) {
5000
- logger$5.log(" Updating environment variables...");
4785
+ logger$4.log(" Updating environment variables...");
5001
4786
  const envString = Object.entries(envVars).map(([key, value]) => `${key}=${value}`).join("\n");
5002
4787
  await api.saveApplicationEnv(config.applicationId, envString);
5003
- logger$5.log(" ✓ Environment variables updated");
4788
+ logger$4.log(" ✓ Environment variables updated");
5004
4789
  }
5005
- logger$5.log(" Triggering deployment...");
4790
+ logger$4.log(" Triggering deployment...");
5006
4791
  await api.deployApplication(config.applicationId);
5007
- logger$5.log(" ✓ Deployment triggered");
5008
- logger$5.log("\n✅ Dokploy deployment initiated!");
5009
- logger$5.log(`\n📋 Deployment details:`);
5010
- logger$5.log(` Image: ${imageRef}`);
5011
- logger$5.log(` Stage: ${stage}`);
5012
- logger$5.log(` Application ID: ${config.applicationId}`);
5013
- if (masterKey) logger$5.log(`\n🔐 GKM_MASTER_KEY has been set in Dokploy environment`);
4792
+ logger$4.log(" ✓ Deployment triggered");
4793
+ logger$4.log("\n✅ Dokploy deployment initiated!");
4794
+ logger$4.log(`\n📋 Deployment details:`);
4795
+ logger$4.log(` Image: ${imageRef}`);
4796
+ logger$4.log(` Stage: ${stage}`);
4797
+ logger$4.log(` Application ID: ${config.applicationId}`);
4798
+ if (masterKey) logger$4.log(`\n🔐 GKM_MASTER_KEY has been set in Dokploy environment`);
5014
4799
  const deploymentUrl = `${config.endpoint}/project/${config.projectId}`;
5015
- logger$5.log(`\n🔗 View deployment: ${deploymentUrl}`);
4800
+ logger$4.log(`\n🔗 View deployment: ${deploymentUrl}`);
5016
4801
  return {
5017
4802
  imageRef,
5018
4803
  masterKey,
@@ -5129,7 +4914,7 @@ function validateEnvVars(requiredVars, context) {
5129
4914
 
5130
4915
  //#endregion
5131
4916
  //#region src/deploy/init.ts
5132
- const logger$4 = console;
4917
+ const logger$3 = console;
5133
4918
  /**
5134
4919
  * Get the Dokploy API token from stored credentials or environment
5135
4920
  */
@@ -5163,20 +4948,20 @@ async function createApi(endpoint) {
5163
4948
  async function updateConfig(config, cwd = process.cwd()) {
5164
4949
  const configPath = (0, node_path.join)(cwd, "gkm.config.ts");
5165
4950
  if (!(0, node_fs.existsSync)(configPath)) {
5166
- logger$4.warn("\n gkm.config.ts not found. Add this configuration manually:\n");
5167
- logger$4.log(` providers: {`);
5168
- logger$4.log(` dokploy: {`);
5169
- logger$4.log(` endpoint: '${config.endpoint}',`);
5170
- logger$4.log(` projectId: '${config.projectId}',`);
5171
- logger$4.log(` applicationId: '${config.applicationId}',`);
5172
- logger$4.log(` },`);
5173
- logger$4.log(` },`);
4951
+ logger$3.warn("\n gkm.config.ts not found. Add this configuration manually:\n");
4952
+ logger$3.log(` providers: {`);
4953
+ logger$3.log(` dokploy: {`);
4954
+ logger$3.log(` endpoint: '${config.endpoint}',`);
4955
+ logger$3.log(` projectId: '${config.projectId}',`);
4956
+ logger$3.log(` applicationId: '${config.applicationId}',`);
4957
+ logger$3.log(` },`);
4958
+ logger$3.log(` },`);
5174
4959
  return;
5175
4960
  }
5176
4961
  const content = await (0, node_fs_promises.readFile)(configPath, "utf-8");
5177
4962
  if (content.includes("dokploy:") && content.includes("applicationId:")) {
5178
- logger$4.log("\n Dokploy config already exists in gkm.config.ts");
5179
- logger$4.log(" Updating with new values...");
4963
+ logger$3.log("\n Dokploy config already exists in gkm.config.ts");
4964
+ logger$3.log(" Updating with new values...");
5180
4965
  }
5181
4966
  const registryLine = config.registryId ? `\n\t\t\tregistryId: '${config.registryId}',` : "";
5182
4967
  const dokployConfigStr = `dokploy: {
@@ -5193,7 +4978,7 @@ async function updateConfig(config, cwd = process.cwd()) {
5193
4978
  },
5194
4979
  });`);
5195
4980
  await (0, node_fs_promises.writeFile)(configPath, newContent);
5196
- logger$4.log("\n ✓ Updated gkm.config.ts with Dokploy configuration");
4981
+ logger$3.log("\n ✓ Updated gkm.config.ts with Dokploy configuration");
5197
4982
  }
5198
4983
  /**
5199
4984
  * Initialize Dokploy deployment configuration
@@ -5202,24 +4987,24 @@ async function deployInitCommand(options) {
5202
4987
  const { projectName, appName, projectId: existingProjectId, registryId } = options;
5203
4988
  const endpoint = await getEndpoint(options.endpoint);
5204
4989
  const api = await createApi(endpoint);
5205
- logger$4.log(`\n🚀 Initializing Dokploy deployment...`);
5206
- logger$4.log(` Endpoint: ${endpoint}`);
4990
+ logger$3.log(`\n🚀 Initializing Dokploy deployment...`);
4991
+ logger$3.log(` Endpoint: ${endpoint}`);
5207
4992
  let projectId;
5208
4993
  if (existingProjectId) {
5209
4994
  projectId = existingProjectId;
5210
- logger$4.log(`\n📁 Using existing project: ${projectId}`);
4995
+ logger$3.log(`\n📁 Using existing project: ${projectId}`);
5211
4996
  } else {
5212
- logger$4.log(`\n📁 Looking for project: ${projectName}`);
4997
+ logger$3.log(`\n📁 Looking for project: ${projectName}`);
5213
4998
  const projects = await api.listProjects();
5214
4999
  const existingProject = projects.find((p) => p.name.toLowerCase() === projectName.toLowerCase());
5215
5000
  if (existingProject) {
5216
5001
  projectId = existingProject.projectId;
5217
- logger$4.log(` Found existing project: ${projectId}`);
5002
+ logger$3.log(` Found existing project: ${projectId}`);
5218
5003
  } else {
5219
- logger$4.log(` Creating new project...`);
5004
+ logger$3.log(` Creating new project...`);
5220
5005
  const result = await api.createProject(projectName);
5221
5006
  projectId = result.project.projectId;
5222
- logger$4.log(` ✓ Created project: ${projectId}`);
5007
+ logger$3.log(` ✓ Created project: ${projectId}`);
5223
5008
  }
5224
5009
  }
5225
5010
  const project = await api.getProject(projectId);
@@ -5227,23 +5012,23 @@ async function deployInitCommand(options) {
5227
5012
  const firstEnv = project.environments?.[0];
5228
5013
  if (firstEnv) environmentId = firstEnv.environmentId;
5229
5014
  else {
5230
- logger$4.log(` Creating production environment...`);
5015
+ logger$3.log(` Creating production environment...`);
5231
5016
  const env = await api.createEnvironment(projectId, "production");
5232
5017
  environmentId = env.environmentId;
5233
5018
  }
5234
- logger$4.log(`\n📦 Creating application: ${appName}`);
5019
+ logger$3.log(`\n📦 Creating application: ${appName}`);
5235
5020
  const application = await api.createApplication(appName, projectId, environmentId);
5236
- logger$4.log(` ✓ Created application: ${application.applicationId}`);
5021
+ logger$3.log(` ✓ Created application: ${application.applicationId}`);
5237
5022
  if (registryId) {
5238
- logger$4.log(`\n🔧 Configuring registry: ${registryId}`);
5023
+ logger$3.log(`\n🔧 Configuring registry: ${registryId}`);
5239
5024
  await api.updateApplication(application.applicationId, { registryId });
5240
- logger$4.log(` ✓ Registry configured`);
5025
+ logger$3.log(` ✓ Registry configured`);
5241
5026
  } else try {
5242
5027
  const registries = await api.listRegistries();
5243
5028
  if (registries.length > 0) {
5244
- logger$4.log(`\n📋 Available registries:`);
5245
- for (const reg of registries) logger$4.log(` - ${reg.registryName}: ${reg.registryUrl} (${reg.registryId})`);
5246
- logger$4.log(`\n To use a registry, run with --registry-id <id>`);
5029
+ logger$3.log(`\n📋 Available registries:`);
5030
+ for (const reg of registries) logger$3.log(` - ${reg.registryName}: ${reg.registryUrl} (${reg.registryId})`);
5031
+ logger$3.log(`\n To use a registry, run with --registry-id <id>`);
5247
5032
  }
5248
5033
  } catch {}
5249
5034
  const config = {
@@ -5252,14 +5037,14 @@ async function deployInitCommand(options) {
5252
5037
  applicationId: application.applicationId
5253
5038
  };
5254
5039
  await updateConfig(config);
5255
- logger$4.log(`\n✅ Dokploy deployment initialized!`);
5256
- logger$4.log(`\n📋 Configuration:`);
5257
- logger$4.log(` Project ID: ${projectId}`);
5258
- logger$4.log(` Application ID: ${application.applicationId}`);
5259
- logger$4.log(`\n🔗 View in Dokploy: ${endpoint}/project/${projectId}`);
5260
- logger$4.log(`\n📝 Next steps:`);
5261
- logger$4.log(` 1. Initialize secrets: gkm secrets:init --stage production`);
5262
- logger$4.log(` 2. Deploy: gkm deploy --provider dokploy --stage production`);
5040
+ logger$3.log(`\n✅ Dokploy deployment initialized!`);
5041
+ logger$3.log(`\n📋 Configuration:`);
5042
+ logger$3.log(` Project ID: ${projectId}`);
5043
+ logger$3.log(` Application ID: ${application.applicationId}`);
5044
+ logger$3.log(`\n🔗 View in Dokploy: ${endpoint}/project/${projectId}`);
5045
+ logger$3.log(`\n📝 Next steps:`);
5046
+ logger$3.log(` 1. Initialize secrets: gkm secrets:init --stage production`);
5047
+ logger$3.log(` 2. Deploy: gkm deploy --provider dokploy --stage production`);
5263
5048
  return config;
5264
5049
  }
5265
5050
  /**
@@ -5270,32 +5055,32 @@ async function deployListCommand(options) {
5270
5055
  const api = await createApi(endpoint);
5271
5056
  const { resource } = options;
5272
5057
  if (resource === "projects") {
5273
- logger$4.log(`\n📁 Projects in ${endpoint}:`);
5058
+ logger$3.log(`\n📁 Projects in ${endpoint}:`);
5274
5059
  const projects = await api.listProjects();
5275
5060
  if (projects.length === 0) {
5276
- logger$4.log(" No projects found");
5061
+ logger$3.log(" No projects found");
5277
5062
  return;
5278
5063
  }
5279
5064
  for (const project of projects) {
5280
- logger$4.log(`\n ${project.name} (${project.projectId})`);
5281
- if (project.description) logger$4.log(` ${project.description}`);
5065
+ logger$3.log(`\n ${project.name} (${project.projectId})`);
5066
+ if (project.description) logger$3.log(` ${project.description}`);
5282
5067
  }
5283
5068
  } else if (resource === "registries") {
5284
- logger$4.log(`\n🐳 Registries in ${endpoint}:`);
5069
+ logger$3.log(`\n🐳 Registries in ${endpoint}:`);
5285
5070
  const registries = await api.listRegistries();
5286
5071
  if (registries.length === 0) {
5287
- logger$4.log(" No registries configured");
5288
- logger$4.log(" Run \"gkm registry:setup\" to configure a registry");
5072
+ logger$3.log(" No registries configured");
5073
+ logger$3.log(" Run \"gkm registry:setup\" to configure a registry");
5289
5074
  return;
5290
5075
  }
5291
5076
  const storedRegistryId = await require_credentials.getDokployRegistryId();
5292
5077
  for (const registry of registries) {
5293
5078
  const isDefault = registry.registryId === storedRegistryId;
5294
5079
  const marker = isDefault ? " (default)" : "";
5295
- logger$4.log(`\n ${registry.registryName}${marker} (${registry.registryId})`);
5296
- logger$4.log(` URL: ${registry.registryUrl}`);
5297
- logger$4.log(` Username: ${registry.username}`);
5298
- if (registry.imagePrefix) logger$4.log(` Prefix: ${registry.imagePrefix}`);
5080
+ logger$3.log(`\n ${registry.registryName}${marker} (${registry.registryId})`);
5081
+ logger$3.log(` URL: ${registry.registryUrl}`);
5082
+ logger$3.log(` Username: ${registry.username}`);
5083
+ if (registry.imagePrefix) logger$3.log(` Prefix: ${registry.imagePrefix}`);
5299
5084
  }
5300
5085
  }
5301
5086
  }
@@ -5318,20 +5103,20 @@ function isStateProvider(value) {
5318
5103
  async function createStateProvider(options) {
5319
5104
  const { config, workspaceRoot, workspaceName } = options;
5320
5105
  if (!config) {
5321
- const { LocalStateProvider } = await Promise.resolve().then(() => require("./LocalStateProvider-CLifRC0Y.cjs"));
5106
+ const { LocalStateProvider } = await Promise.resolve().then(() => require("./LocalStateProvider-CalzNfNA.cjs"));
5322
5107
  return new LocalStateProvider(workspaceRoot);
5323
5108
  }
5324
5109
  if (isStateProvider(config.provider)) return config.provider;
5325
5110
  const provider = config.provider;
5326
5111
  if (provider === "local") {
5327
- const { LocalStateProvider } = await Promise.resolve().then(() => require("./LocalStateProvider-CLifRC0Y.cjs"));
5112
+ const { LocalStateProvider } = await Promise.resolve().then(() => require("./LocalStateProvider-CalzNfNA.cjs"));
5328
5113
  return new LocalStateProvider(workspaceRoot);
5329
5114
  }
5330
5115
  if (provider === "ssm") {
5331
5116
  if (!workspaceName) throw new Error("Workspace name is required for SSM state provider. Set \"name\" in gkm.config.ts.");
5332
- const { LocalStateProvider } = await Promise.resolve().then(() => require("./LocalStateProvider-CLifRC0Y.cjs"));
5333
- const { SSMStateProvider } = await Promise.resolve().then(() => require("./SSMStateProvider-CT8tjl9o.cjs"));
5334
- const { CachedStateProvider: CachedStateProvider$1 } = await Promise.resolve().then(() => require("./CachedStateProvider-37pG1HBx.cjs"));
5117
+ const { LocalStateProvider } = await Promise.resolve().then(() => require("./LocalStateProvider-CalzNfNA.cjs"));
5118
+ const { SSMStateProvider } = await Promise.resolve().then(() => require("./SSMStateProvider-Bt6r8CTL.cjs"));
5119
+ const { CachedStateProvider: CachedStateProvider$1 } = await Promise.resolve().then(() => require("./CachedStateProvider-BdX7klRc.cjs"));
5335
5120
  const ssmConfig = config;
5336
5121
  const local = new LocalStateProvider(workspaceRoot);
5337
5122
  const ssm = SSMStateProvider.create({
@@ -5791,7 +5576,7 @@ async function sniffAllApps(apps, workspacePath, options = {}) {
5791
5576
 
5792
5577
  //#endregion
5793
5578
  //#region src/deploy/index.ts
5794
- const logger$3 = console;
5579
+ const logger$2 = console;
5795
5580
  /**
5796
5581
  * Prompt for input
5797
5582
  */
@@ -5799,7 +5584,7 @@ async function prompt(message, hidden = false) {
5799
5584
  if (!process.stdin.isTTY) throw new Error("Interactive input required. Please configure manually.");
5800
5585
  if (hidden) {
5801
5586
  process.stdout.write(message);
5802
- return new Promise((resolve$4) => {
5587
+ return new Promise((resolve$3) => {
5803
5588
  let value = "";
5804
5589
  const onData = (char) => {
5805
5590
  const c = char.toString();
@@ -5808,7 +5593,7 @@ async function prompt(message, hidden = false) {
5808
5593
  process.stdin.pause();
5809
5594
  process.stdin.removeListener("data", onData);
5810
5595
  process.stdout.write("\n");
5811
- resolve$4(value);
5596
+ resolve$3(value);
5812
5597
  } else if (c === "") {
5813
5598
  process.stdin.setRawMode(false);
5814
5599
  process.stdin.pause();
@@ -5863,7 +5648,7 @@ async function waitForPostgres(host, port, user, password, database, maxRetries
5863
5648
  return;
5864
5649
  } catch {
5865
5650
  if (i < maxRetries - 1) {
5866
- logger$3.log(` Waiting for Postgres... (${i + 1}/${maxRetries})`);
5651
+ logger$2.log(` Waiting for Postgres... (${i + 1}/${maxRetries})`);
5867
5652
  await new Promise((r) => setTimeout(r, retryIntervalMs));
5868
5653
  }
5869
5654
  }
@@ -5898,12 +5683,12 @@ async function waitForPostgres(host, port, user, password, database, maxRetries
5898
5683
  * ```
5899
5684
  */
5900
5685
  async function initializePostgresUsers(api, postgres, serverHostname, users) {
5901
- logger$3.log("\n🔧 Initializing database users...");
5686
+ logger$2.log("\n🔧 Initializing database users...");
5902
5687
  const externalPort = 5432;
5903
- logger$3.log(` Enabling external port ${externalPort}...`);
5688
+ logger$2.log(` Enabling external port ${externalPort}...`);
5904
5689
  await api.savePostgresExternalPort(postgres.postgresId, externalPort);
5905
5690
  await api.deployPostgres(postgres.postgresId);
5906
- logger$3.log(` Waiting for Postgres to be accessible at ${serverHostname}:${externalPort}...`);
5691
+ logger$2.log(` Waiting for Postgres to be accessible at ${serverHostname}:${externalPort}...`);
5907
5692
  await waitForPostgres(serverHostname, externalPort, postgres.databaseUser, postgres.databasePassword, postgres.databaseName);
5908
5693
  const client = new pg.Client({
5909
5694
  host: serverHostname,
@@ -5916,7 +5701,7 @@ async function initializePostgresUsers(api, postgres, serverHostname, users) {
5916
5701
  await client.connect();
5917
5702
  for (const user of users) {
5918
5703
  const schemaName = user.usePublicSchema ? "public" : user.name;
5919
- logger$3.log(` Creating user "${user.name}" with schema "${schemaName}"...`);
5704
+ logger$2.log(` Creating user "${user.name}" with schema "${schemaName}"...`);
5920
5705
  if (user.usePublicSchema) {
5921
5706
  await client.query(`
5922
5707
  DO $$ BEGIN
@@ -5951,15 +5736,15 @@ async function initializePostgresUsers(api, postgres, serverHostname, users) {
5951
5736
  ALTER DEFAULT PRIVILEGES IN SCHEMA "${schemaName}" GRANT ALL ON TABLES TO "${user.name}";
5952
5737
  `);
5953
5738
  }
5954
- logger$3.log(` ✓ User "${user.name}" configured`);
5739
+ logger$2.log(` ✓ User "${user.name}" configured`);
5955
5740
  }
5956
5741
  } finally {
5957
5742
  await client.end();
5958
5743
  }
5959
- logger$3.log(" Disabling external port...");
5744
+ logger$2.log(" Disabling external port...");
5960
5745
  await api.savePostgresExternalPort(postgres.postgresId, null);
5961
5746
  await api.deployPostgres(postgres.postgresId);
5962
- logger$3.log(" ✓ Database users initialized");
5747
+ logger$2.log(" ✓ Database users initialized");
5963
5748
  }
5964
5749
  /**
5965
5750
  * Get the server hostname from the Dokploy endpoint URL
@@ -5973,24 +5758,24 @@ function getServerHostname(endpoint) {
5973
5758
  * @internal Exported for testing
5974
5759
  */
5975
5760
  async function provisionServices(api, projectId, environmentId, projectName, services, existingServiceIds) {
5976
- logger$3.log(`\n🔍 provisionServices called: services=${JSON.stringify(services)}, envId=${environmentId}`);
5761
+ logger$2.log(`\n🔍 provisionServices called: services=${JSON.stringify(services)}, envId=${environmentId}`);
5977
5762
  if (!services || !environmentId) {
5978
- logger$3.log(" Skipping: no services or no environmentId");
5763
+ logger$2.log(" Skipping: no services or no environmentId");
5979
5764
  return void 0;
5980
5765
  }
5981
5766
  const serviceUrls = {};
5982
5767
  const serviceIds = {};
5983
5768
  if (services.postgres) {
5984
- logger$3.log("\n🐘 Checking PostgreSQL...");
5769
+ logger$2.log("\n🐘 Checking PostgreSQL...");
5985
5770
  const postgresName = "db";
5986
5771
  try {
5987
5772
  let postgres = null;
5988
5773
  let created = false;
5989
5774
  if (existingServiceIds?.postgresId) {
5990
- logger$3.log(` Using cached ID: ${existingServiceIds.postgresId}`);
5775
+ logger$2.log(` Using cached ID: ${existingServiceIds.postgresId}`);
5991
5776
  postgres = await api.getPostgres(existingServiceIds.postgresId);
5992
- if (postgres) logger$3.log(` ✓ PostgreSQL found: ${postgres.postgresId}`);
5993
- else logger$3.log(` ⚠ Cached ID invalid, will create new`);
5777
+ if (postgres) logger$2.log(` ✓ PostgreSQL found: ${postgres.postgresId}`);
5778
+ else logger$2.log(` ⚠ Cached ID invalid, will create new`);
5994
5779
  }
5995
5780
  if (!postgres) {
5996
5781
  const databasePassword = (0, node_crypto.randomBytes)(16).toString("hex");
@@ -6002,10 +5787,10 @@ async function provisionServices(api, projectId, environmentId, projectName, ser
6002
5787
  postgres = result.postgres;
6003
5788
  created = result.created;
6004
5789
  if (created) {
6005
- logger$3.log(` ✓ Created PostgreSQL: ${postgres.postgresId}`);
5790
+ logger$2.log(` ✓ Created PostgreSQL: ${postgres.postgresId}`);
6006
5791
  await api.deployPostgres(postgres.postgresId);
6007
- logger$3.log(" ✓ PostgreSQL deployed");
6008
- } else logger$3.log(` ✓ PostgreSQL already exists: ${postgres.postgresId}`);
5792
+ logger$2.log(" ✓ PostgreSQL deployed");
5793
+ } else logger$2.log(` ✓ PostgreSQL already exists: ${postgres.postgresId}`);
6009
5794
  }
6010
5795
  serviceIds.postgresId = postgres.postgresId;
6011
5796
  serviceUrls.DATABASE_HOST = postgres.appName;
@@ -6014,23 +5799,23 @@ async function provisionServices(api, projectId, environmentId, projectName, ser
6014
5799
  serviceUrls.DATABASE_USER = postgres.databaseUser;
6015
5800
  serviceUrls.DATABASE_PASSWORD = postgres.databasePassword;
6016
5801
  serviceUrls.DATABASE_URL = `postgresql://${postgres.databaseUser}:${postgres.databasePassword}@${postgres.appName}:5432/${postgres.databaseName}`;
6017
- logger$3.log(` ✓ Database credentials configured`);
5802
+ logger$2.log(` ✓ Database credentials configured`);
6018
5803
  } catch (error) {
6019
5804
  const message = error instanceof Error ? error.message : "Unknown error";
6020
- logger$3.log(` ⚠ Failed to provision PostgreSQL: ${message}`);
5805
+ logger$2.log(` ⚠ Failed to provision PostgreSQL: ${message}`);
6021
5806
  }
6022
5807
  }
6023
5808
  if (services.redis) {
6024
- logger$3.log("\n🔴 Checking Redis...");
5809
+ logger$2.log("\n🔴 Checking Redis...");
6025
5810
  const redisName = "cache";
6026
5811
  try {
6027
5812
  let redis = null;
6028
5813
  let created = false;
6029
5814
  if (existingServiceIds?.redisId) {
6030
- logger$3.log(` Using cached ID: ${existingServiceIds.redisId}`);
5815
+ logger$2.log(` Using cached ID: ${existingServiceIds.redisId}`);
6031
5816
  redis = await api.getRedis(existingServiceIds.redisId);
6032
- if (redis) logger$3.log(` ✓ Redis found: ${redis.redisId}`);
6033
- else logger$3.log(` ⚠ Cached ID invalid, will create new`);
5817
+ if (redis) logger$2.log(` ✓ Redis found: ${redis.redisId}`);
5818
+ else logger$2.log(` ⚠ Cached ID invalid, will create new`);
6034
5819
  }
6035
5820
  if (!redis) {
6036
5821
  const { randomBytes: randomBytes$2 } = await import("node:crypto");
@@ -6039,10 +5824,10 @@ async function provisionServices(api, projectId, environmentId, projectName, ser
6039
5824
  redis = result.redis;
6040
5825
  created = result.created;
6041
5826
  if (created) {
6042
- logger$3.log(` ✓ Created Redis: ${redis.redisId}`);
5827
+ logger$2.log(` ✓ Created Redis: ${redis.redisId}`);
6043
5828
  await api.deployRedis(redis.redisId);
6044
- logger$3.log(" ✓ Redis deployed");
6045
- } else logger$3.log(` ✓ Redis already exists: ${redis.redisId}`);
5829
+ logger$2.log(" ✓ Redis deployed");
5830
+ } else logger$2.log(` ✓ Redis already exists: ${redis.redisId}`);
6046
5831
  }
6047
5832
  serviceIds.redisId = redis.redisId;
6048
5833
  serviceUrls.REDIS_HOST = redis.appName;
@@ -6050,10 +5835,10 @@ async function provisionServices(api, projectId, environmentId, projectName, ser
6050
5835
  if (redis.databasePassword) serviceUrls.REDIS_PASSWORD = redis.databasePassword;
6051
5836
  const password = redis.databasePassword ? `:${redis.databasePassword}@` : "";
6052
5837
  serviceUrls.REDIS_URL = `redis://${password}${redis.appName}:6379`;
6053
- logger$3.log(` ✓ Redis credentials configured`);
5838
+ logger$2.log(` ✓ Redis credentials configured`);
6054
5839
  } catch (error) {
6055
5840
  const message = error instanceof Error ? error.message : "Unknown error";
6056
- logger$3.log(` ⚠ Failed to provision Redis: ${message}`);
5841
+ logger$2.log(` ⚠ Failed to provision Redis: ${message}`);
6057
5842
  }
6058
5843
  }
6059
5844
  return Object.keys(serviceUrls).length > 0 ? {
@@ -6065,10 +5850,10 @@ async function provisionServices(api, projectId, environmentId, projectName, ser
6065
5850
  * Ensure Dokploy is fully configured, recovering/creating resources as needed
6066
5851
  */
6067
5852
  async function ensureDokploySetup(config, dockerConfig, stage, services) {
6068
- logger$3.log("\n🔧 Checking Dokploy setup...");
5853
+ logger$2.log("\n🔧 Checking Dokploy setup...");
6069
5854
  let creds = await require_credentials.getDokployCredentials();
6070
5855
  if (!creds) {
6071
- logger$3.log("\n📋 Dokploy credentials not found. Let's set them up.");
5856
+ logger$2.log("\n📋 Dokploy credentials not found. Let's set them up.");
6072
5857
  const endpoint = await prompt("Dokploy URL (e.g., https://dokploy.example.com): ");
6073
5858
  const normalizedEndpoint = endpoint.replace(/\/$/, "");
6074
5859
  try {
@@ -6076,9 +5861,9 @@ async function ensureDokploySetup(config, dockerConfig, stage, services) {
6076
5861
  } catch {
6077
5862
  throw new Error("Invalid URL format");
6078
5863
  }
6079
- logger$3.log(`\nGenerate a token at: ${normalizedEndpoint}/settings/profile\n`);
5864
+ logger$2.log(`\nGenerate a token at: ${normalizedEndpoint}/settings/profile\n`);
6080
5865
  const token = await prompt("API Token: ", true);
6081
- logger$3.log("\nValidating credentials...");
5866
+ logger$2.log("\nValidating credentials...");
6082
5867
  const isValid = await validateDokployToken(normalizedEndpoint, token);
6083
5868
  if (!isValid) throw new Error("Invalid credentials. Please check your token.");
6084
5869
  await require_credentials.storeDokployCredentials(token, normalizedEndpoint);
@@ -6086,7 +5871,7 @@ async function ensureDokploySetup(config, dockerConfig, stage, services) {
6086
5871
  token,
6087
5872
  endpoint: normalizedEndpoint
6088
5873
  };
6089
- logger$3.log("✓ Credentials saved");
5874
+ logger$2.log("✓ Credentials saved");
6090
5875
  }
6091
5876
  const api = new require_dokploy_api.DokployApi({
6092
5877
  baseUrl: creds.endpoint,
@@ -6094,20 +5879,20 @@ async function ensureDokploySetup(config, dockerConfig, stage, services) {
6094
5879
  });
6095
5880
  const existingConfig = config.providers?.dokploy;
6096
5881
  if (existingConfig && typeof existingConfig !== "boolean" && existingConfig.applicationId && existingConfig.projectId) {
6097
- logger$3.log("✓ Dokploy config found in gkm.config.ts");
5882
+ logger$2.log("✓ Dokploy config found in gkm.config.ts");
6098
5883
  try {
6099
5884
  const projectDetails = await api.getProject(existingConfig.projectId);
6100
- logger$3.log("✓ Project verified");
5885
+ logger$2.log("✓ Project verified");
6101
5886
  const storedRegistryId = existingConfig.registryId ?? await require_credentials.getDokployRegistryId();
6102
5887
  const environments = projectDetails.environments ?? [];
6103
5888
  let environment = environments.find((e) => e.name.toLowerCase() === stage.toLowerCase());
6104
5889
  if (!environment) {
6105
- logger$3.log(` Creating "${stage}" environment...`);
5890
+ logger$2.log(` Creating "${stage}" environment...`);
6106
5891
  environment = await api.createEnvironment(existingConfig.projectId, stage);
6107
- logger$3.log(` ✓ Created environment: ${environment.environmentId}`);
5892
+ logger$2.log(` ✓ Created environment: ${environment.environmentId}`);
6108
5893
  }
6109
5894
  const environmentId$1 = environment.environmentId;
6110
- logger$3.log(` Services config: ${JSON.stringify(services)}, envId: ${environmentId$1}`);
5895
+ logger$2.log(` Services config: ${JSON.stringify(services)}, envId: ${environmentId$1}`);
6111
5896
  const provisionResult$1 = await provisionServices(api, existingConfig.projectId, environmentId$1, dockerConfig.appName, services, void 0);
6112
5897
  return {
6113
5898
  config: {
@@ -6120,97 +5905,97 @@ async function ensureDokploySetup(config, dockerConfig, stage, services) {
6120
5905
  serviceUrls: provisionResult$1?.serviceUrls
6121
5906
  };
6122
5907
  } catch {
6123
- logger$3.log("⚠ Project not found, will recover...");
5908
+ logger$2.log("⚠ Project not found, will recover...");
6124
5909
  }
6125
5910
  }
6126
- logger$3.log("\n📁 Looking for project...");
5911
+ logger$2.log("\n📁 Looking for project...");
6127
5912
  const projectName = dockerConfig.projectName;
6128
5913
  const projects = await api.listProjects();
6129
5914
  let project = projects.find((p) => p.name.toLowerCase() === projectName.toLowerCase());
6130
5915
  let environmentId;
6131
5916
  if (project) {
6132
- logger$3.log(` Found existing project: ${project.name} (${project.projectId})`);
5917
+ logger$2.log(` Found existing project: ${project.name} (${project.projectId})`);
6133
5918
  const projectDetails = await api.getProject(project.projectId);
6134
5919
  const environments = projectDetails.environments ?? [];
6135
5920
  const matchingEnv = environments.find((e) => e.name.toLowerCase() === stage.toLowerCase());
6136
5921
  if (matchingEnv) {
6137
5922
  environmentId = matchingEnv.environmentId;
6138
- logger$3.log(` Using environment: ${matchingEnv.name}`);
5923
+ logger$2.log(` Using environment: ${matchingEnv.name}`);
6139
5924
  } else {
6140
- logger$3.log(` Creating "${stage}" environment...`);
5925
+ logger$2.log(` Creating "${stage}" environment...`);
6141
5926
  const env = await api.createEnvironment(project.projectId, stage);
6142
5927
  environmentId = env.environmentId;
6143
- logger$3.log(` ✓ Created environment: ${stage}`);
5928
+ logger$2.log(` ✓ Created environment: ${stage}`);
6144
5929
  }
6145
5930
  } else {
6146
- logger$3.log(` Creating project: ${projectName}`);
5931
+ logger$2.log(` Creating project: ${projectName}`);
6147
5932
  const result = await api.createProject(projectName);
6148
5933
  project = result.project;
6149
5934
  if (result.environment.name.toLowerCase() !== stage.toLowerCase()) {
6150
- logger$3.log(` Creating "${stage}" environment...`);
5935
+ logger$2.log(` Creating "${stage}" environment...`);
6151
5936
  const env = await api.createEnvironment(project.projectId, stage);
6152
5937
  environmentId = env.environmentId;
6153
5938
  } else environmentId = result.environment.environmentId;
6154
- logger$3.log(` ✓ Created project: ${project.projectId}`);
6155
- logger$3.log(` ✓ Using environment: ${stage}`);
5939
+ logger$2.log(` ✓ Created project: ${project.projectId}`);
5940
+ logger$2.log(` ✓ Using environment: ${stage}`);
6156
5941
  }
6157
- logger$3.log("\n📦 Looking for application...");
5942
+ logger$2.log("\n📦 Looking for application...");
6158
5943
  const appName = dockerConfig.appName;
6159
5944
  let applicationId;
6160
5945
  if (existingConfig && typeof existingConfig !== "boolean" && existingConfig.applicationId) {
6161
5946
  applicationId = existingConfig.applicationId;
6162
- logger$3.log(` Using application from config: ${applicationId}`);
5947
+ logger$2.log(` Using application from config: ${applicationId}`);
6163
5948
  } else {
6164
- logger$3.log(` Creating application: ${appName}`);
5949
+ logger$2.log(` Creating application: ${appName}`);
6165
5950
  const app = await api.createApplication(appName, project.projectId, environmentId);
6166
5951
  applicationId = app.applicationId;
6167
- logger$3.log(` ✓ Created application: ${applicationId}`);
5952
+ logger$2.log(` ✓ Created application: ${applicationId}`);
6168
5953
  }
6169
- logger$3.log("\n🐳 Checking registry...");
5954
+ logger$2.log("\n🐳 Checking registry...");
6170
5955
  let registryId = await require_credentials.getDokployRegistryId();
6171
5956
  if (registryId) try {
6172
5957
  const registry = await api.getRegistry(registryId);
6173
- logger$3.log(` Using registry: ${registry.registryName}`);
5958
+ logger$2.log(` Using registry: ${registry.registryName}`);
6174
5959
  } catch {
6175
- logger$3.log(" ⚠ Stored registry not found, clearing...");
5960
+ logger$2.log(" ⚠ Stored registry not found, clearing...");
6176
5961
  registryId = void 0;
6177
5962
  await require_credentials.storeDokployRegistryId("");
6178
5963
  }
6179
5964
  if (!registryId) {
6180
5965
  const registries = await api.listRegistries();
6181
5966
  if (registries.length === 0) if (dockerConfig.registry) {
6182
- logger$3.log(" No registries found in Dokploy. Let's create one.");
6183
- logger$3.log(` Registry URL: ${dockerConfig.registry}`);
5967
+ logger$2.log(" No registries found in Dokploy. Let's create one.");
5968
+ logger$2.log(` Registry URL: ${dockerConfig.registry}`);
6184
5969
  const username = await prompt("Registry username: ");
6185
5970
  const password = await prompt("Registry password/token: ", true);
6186
5971
  const registry = await api.createRegistry("Default Registry", dockerConfig.registry, username, password);
6187
5972
  registryId = registry.registryId;
6188
5973
  await require_credentials.storeDokployRegistryId(registryId);
6189
- logger$3.log(` ✓ Registry created: ${registryId}`);
6190
- } else logger$3.log(" ⚠ No registry configured. Set docker.registry in gkm.config.ts");
5974
+ logger$2.log(` ✓ Registry created: ${registryId}`);
5975
+ } else logger$2.log(" ⚠ No registry configured. Set docker.registry in gkm.config.ts");
6191
5976
  else {
6192
- logger$3.log(" Available registries:");
5977
+ logger$2.log(" Available registries:");
6193
5978
  registries.forEach((reg, i) => {
6194
- logger$3.log(` ${i + 1}. ${reg.registryName} (${reg.registryUrl})`);
5979
+ logger$2.log(` ${i + 1}. ${reg.registryName} (${reg.registryUrl})`);
6195
5980
  });
6196
- if (dockerConfig.registry) logger$3.log(` ${registries.length + 1}. Create new registry`);
5981
+ if (dockerConfig.registry) logger$2.log(` ${registries.length + 1}. Create new registry`);
6197
5982
  const maxOption = dockerConfig.registry ? registries.length + 1 : registries.length;
6198
5983
  const selection = await prompt(` Select registry (1-${maxOption}): `);
6199
5984
  const index = parseInt(selection, 10) - 1;
6200
5985
  if (index >= 0 && index < registries.length) {
6201
5986
  registryId = registries[index].registryId;
6202
5987
  await require_credentials.storeDokployRegistryId(registryId);
6203
- logger$3.log(` ✓ Selected: ${registries[index].registryName}`);
5988
+ logger$2.log(` ✓ Selected: ${registries[index].registryName}`);
6204
5989
  } else if (dockerConfig.registry && index === registries.length) {
6205
- logger$3.log(`\n Creating new registry...`);
6206
- logger$3.log(` Registry URL: ${dockerConfig.registry}`);
5990
+ logger$2.log(`\n Creating new registry...`);
5991
+ logger$2.log(` Registry URL: ${dockerConfig.registry}`);
6207
5992
  const username = await prompt(" Registry username: ");
6208
5993
  const password = await prompt(" Registry password/token: ", true);
6209
5994
  const registry = await api.createRegistry(dockerConfig.registry.replace(/^https?:\/\//, ""), dockerConfig.registry, username, password);
6210
5995
  registryId = registry.registryId;
6211
5996
  await require_credentials.storeDokployRegistryId(registryId);
6212
- logger$3.log(` ✓ Registry created: ${registryId}`);
6213
- } else logger$3.log(" ⚠ Invalid selection, skipping registry setup");
5997
+ logger$2.log(` ✓ Registry created: ${registryId}`);
5998
+ } else logger$2.log(" ⚠ Invalid selection, skipping registry setup");
6214
5999
  }
6215
6000
  }
6216
6001
  const dokployConfig = {
@@ -6220,10 +6005,10 @@ async function ensureDokploySetup(config, dockerConfig, stage, services) {
6220
6005
  registryId: registryId ?? void 0
6221
6006
  };
6222
6007
  await updateConfig(dokployConfig);
6223
- logger$3.log("\n✅ Dokploy setup complete!");
6224
- logger$3.log(` Project: ${project.projectId}`);
6225
- logger$3.log(` Application: ${applicationId}`);
6226
- if (registryId) logger$3.log(` Registry: ${registryId}`);
6008
+ logger$2.log("\n✅ Dokploy setup complete!");
6009
+ logger$2.log(` Project: ${project.projectId}`);
6010
+ logger$2.log(` Application: ${applicationId}`);
6011
+ if (registryId) logger$2.log(` Registry: ${registryId}`);
6227
6012
  const provisionResult = await provisionServices(api, project.projectId, environmentId, dockerConfig.appName, services, void 0);
6228
6013
  return {
6229
6014
  config: dokployConfig,
@@ -6254,45 +6039,45 @@ function generateTag(stage) {
6254
6039
  async function workspaceDeployCommand(workspace, options) {
6255
6040
  const { provider, stage, tag, apps: selectedApps } = options;
6256
6041
  if (provider !== "dokploy") throw new Error(`Workspace deployment only supports Dokploy. Got: ${provider}`);
6257
- logger$3.log(`\n🚀 Deploying workspace "${workspace.name}" to Dokploy...`);
6258
- logger$3.log(` Stage: ${stage}`);
6042
+ logger$2.log(`\n🚀 Deploying workspace "${workspace.name}" to Dokploy...`);
6043
+ logger$2.log(` Stage: ${stage}`);
6259
6044
  const imageTag = tag ?? generateTag(stage);
6260
- logger$3.log(` Tag: ${imageTag}`);
6045
+ logger$2.log(` Tag: ${imageTag}`);
6261
6046
  const buildOrder = require_workspace.getAppBuildOrder(workspace);
6262
6047
  let appsToDeployNames = buildOrder;
6263
6048
  if (selectedApps && selectedApps.length > 0) {
6264
6049
  const invalidApps = selectedApps.filter((name$1) => !workspace.apps[name$1]);
6265
6050
  if (invalidApps.length > 0) throw new Error(`Unknown apps: ${invalidApps.join(", ")}\nAvailable apps: ${Object.keys(workspace.apps).join(", ")}`);
6266
6051
  appsToDeployNames = buildOrder.filter((name$1) => selectedApps.includes(name$1));
6267
- logger$3.log(` Deploying apps: ${appsToDeployNames.join(", ")}`);
6268
- } else logger$3.log(` Deploying all apps: ${appsToDeployNames.join(", ")}`);
6052
+ logger$2.log(` Deploying apps: ${appsToDeployNames.join(", ")}`);
6053
+ } else logger$2.log(` Deploying all apps: ${appsToDeployNames.join(", ")}`);
6269
6054
  const dokployApps = appsToDeployNames.filter((name$1) => {
6270
6055
  const app = workspace.apps[name$1];
6271
6056
  const target = app.resolvedDeployTarget;
6272
6057
  if (!require_workspace.isDeployTargetSupported(target)) {
6273
- logger$3.log(` ⚠️ Skipping ${name$1}: ${require_workspace.getDeployTargetError(target, name$1)}`);
6058
+ logger$2.log(` ⚠️ Skipping ${name$1}: ${require_workspace.getDeployTargetError(target, name$1)}`);
6274
6059
  return false;
6275
6060
  }
6276
6061
  return true;
6277
6062
  });
6278
6063
  if (dokployApps.length === 0) throw new Error("No apps to deploy. All selected apps have unsupported deploy targets.");
6279
6064
  appsToDeployNames = dokployApps;
6280
- logger$3.log("\n🔐 Loading secrets and analyzing environment requirements...");
6065
+ logger$2.log("\n🔐 Loading secrets and analyzing environment requirements...");
6281
6066
  const stageSecrets = await require_storage.readStageSecrets(stage, workspace.root);
6282
6067
  if (!stageSecrets) {
6283
- logger$3.log(` ⚠️ No secrets found for stage "${stage}"`);
6284
- logger$3.log(` Run "gkm secrets:init --stage ${stage}" to create secrets`);
6068
+ logger$2.log(` ⚠️ No secrets found for stage "${stage}"`);
6069
+ logger$2.log(` Run "gkm secrets:init --stage ${stage}" to create secrets`);
6285
6070
  }
6286
6071
  const sniffedApps = await sniffAllApps(workspace.apps, workspace.root);
6287
6072
  const encryptedSecrets = stageSecrets ? prepareSecretsForAllApps(stageSecrets, sniffedApps) : /* @__PURE__ */ new Map();
6288
6073
  if (stageSecrets) {
6289
6074
  const report = generateSecretsReport(encryptedSecrets, sniffedApps);
6290
- if (report.appsWithSecrets.length > 0) logger$3.log(` ✓ Encrypted secrets for: ${report.appsWithSecrets.join(", ")}`);
6291
- if (report.appsWithMissingSecrets.length > 0) for (const { appName, missing } of report.appsWithMissingSecrets) logger$3.log(` ⚠️ ${appName}: Missing secrets: ${missing.join(", ")}`);
6075
+ if (report.appsWithSecrets.length > 0) logger$2.log(` ✓ Encrypted secrets for: ${report.appsWithSecrets.join(", ")}`);
6076
+ if (report.appsWithMissingSecrets.length > 0) for (const { appName, missing } of report.appsWithMissingSecrets) logger$2.log(` ⚠️ ${appName}: Missing secrets: ${missing.join(", ")}`);
6292
6077
  }
6293
6078
  let creds = await require_credentials.getDokployCredentials();
6294
6079
  if (!creds) {
6295
- logger$3.log("\n📋 Dokploy credentials not found. Let's set them up.");
6080
+ logger$2.log("\n📋 Dokploy credentials not found. Let's set them up.");
6296
6081
  const endpoint = await prompt("Dokploy URL (e.g., https://dokploy.example.com): ");
6297
6082
  const normalizedEndpoint = endpoint.replace(/\/$/, "");
6298
6083
  try {
@@ -6300,9 +6085,9 @@ async function workspaceDeployCommand(workspace, options) {
6300
6085
  } catch {
6301
6086
  throw new Error("Invalid URL format");
6302
6087
  }
6303
- logger$3.log(`\nGenerate a token at: ${normalizedEndpoint}/settings/profile\n`);
6088
+ logger$2.log(`\nGenerate a token at: ${normalizedEndpoint}/settings/profile\n`);
6304
6089
  const token = await prompt("API Token: ", true);
6305
- logger$3.log("\nValidating credentials...");
6090
+ logger$2.log("\nValidating credentials...");
6306
6091
  const isValid = await validateDokployToken(normalizedEndpoint, token);
6307
6092
  if (!isValid) throw new Error("Invalid credentials. Please check your token.");
6308
6093
  await require_credentials.storeDokployCredentials(token, normalizedEndpoint);
@@ -6310,43 +6095,43 @@ async function workspaceDeployCommand(workspace, options) {
6310
6095
  token,
6311
6096
  endpoint: normalizedEndpoint
6312
6097
  };
6313
- logger$3.log("✓ Credentials saved");
6098
+ logger$2.log("✓ Credentials saved");
6314
6099
  }
6315
6100
  const api = new require_dokploy_api.DokployApi({
6316
6101
  baseUrl: creds.endpoint,
6317
6102
  token: creds.token
6318
6103
  });
6319
- logger$3.log("\n📁 Setting up Dokploy project...");
6104
+ logger$2.log("\n📁 Setting up Dokploy project...");
6320
6105
  const projectName = workspace.name;
6321
6106
  const projects = await api.listProjects();
6322
6107
  let project = projects.find((p) => p.name.toLowerCase() === projectName.toLowerCase());
6323
6108
  let environmentId;
6324
6109
  if (project) {
6325
- logger$3.log(` Found existing project: ${project.name}`);
6110
+ logger$2.log(` Found existing project: ${project.name}`);
6326
6111
  const projectDetails = await api.getProject(project.projectId);
6327
6112
  const environments = projectDetails.environments ?? [];
6328
6113
  const matchingEnv = environments.find((e) => e.name.toLowerCase() === stage.toLowerCase());
6329
6114
  if (matchingEnv) {
6330
6115
  environmentId = matchingEnv.environmentId;
6331
- logger$3.log(` Using environment: ${matchingEnv.name}`);
6116
+ logger$2.log(` Using environment: ${matchingEnv.name}`);
6332
6117
  } else {
6333
- logger$3.log(` Creating "${stage}" environment...`);
6118
+ logger$2.log(` Creating "${stage}" environment...`);
6334
6119
  const env = await api.createEnvironment(project.projectId, stage);
6335
6120
  environmentId = env.environmentId;
6336
- logger$3.log(` ✓ Created environment: ${stage}`);
6121
+ logger$2.log(` ✓ Created environment: ${stage}`);
6337
6122
  }
6338
6123
  } else {
6339
- logger$3.log(` Creating project: ${projectName}`);
6124
+ logger$2.log(` Creating project: ${projectName}`);
6340
6125
  const result = await api.createProject(projectName);
6341
6126
  project = result.project;
6342
6127
  if (result.environment.name.toLowerCase() !== stage.toLowerCase()) {
6343
- logger$3.log(` Creating "${stage}" environment...`);
6128
+ logger$2.log(` Creating "${stage}" environment...`);
6344
6129
  const env = await api.createEnvironment(project.projectId, stage);
6345
6130
  environmentId = env.environmentId;
6346
6131
  } else environmentId = result.environment.environmentId;
6347
- logger$3.log(` ✓ Created project: ${project.projectId}`);
6132
+ logger$2.log(` ✓ Created project: ${project.projectId}`);
6348
6133
  }
6349
- logger$3.log("\n📋 Loading deploy state...");
6134
+ logger$2.log("\n📋 Loading deploy state...");
6350
6135
  const stateProvider = await createStateProvider({
6351
6136
  config: workspace.state,
6352
6137
  workspaceRoot: workspace.root,
@@ -6354,27 +6139,27 @@ async function workspaceDeployCommand(workspace, options) {
6354
6139
  });
6355
6140
  let state = await stateProvider.read(stage);
6356
6141
  if (state) {
6357
- logger$3.log(` Found existing state for stage "${stage}"`);
6142
+ logger$2.log(` Found existing state for stage "${stage}"`);
6358
6143
  if (state.projectId !== project.projectId) {
6359
- logger$3.log(` ⚠ Project ID changed, updating state`);
6144
+ logger$2.log(` ⚠ Project ID changed, updating state`);
6360
6145
  state.projectId = project.projectId;
6361
6146
  }
6362
6147
  if (state.environmentId !== environmentId) {
6363
- logger$3.log(` ⚠ Environment ID changed, updating state`);
6148
+ logger$2.log(` ⚠ Environment ID changed, updating state`);
6364
6149
  state.environmentId = environmentId;
6365
6150
  }
6366
6151
  } else {
6367
- logger$3.log(` Creating new state for stage "${stage}"`);
6152
+ logger$2.log(` Creating new state for stage "${stage}"`);
6368
6153
  state = createEmptyState(stage, project.projectId, environmentId);
6369
6154
  }
6370
- logger$3.log("\n🐳 Checking registry...");
6155
+ logger$2.log("\n🐳 Checking registry...");
6371
6156
  let registryId = await require_credentials.getDokployRegistryId();
6372
6157
  const registry = workspace.deploy.dokploy?.registry;
6373
6158
  if (registryId) try {
6374
6159
  const reg = await api.getRegistry(registryId);
6375
- logger$3.log(` Using registry: ${reg.registryName}`);
6160
+ logger$2.log(` Using registry: ${reg.registryName}`);
6376
6161
  } catch {
6377
- logger$3.log(" ⚠ Stored registry not found, clearing...");
6162
+ logger$2.log(" ⚠ Stored registry not found, clearing...");
6378
6163
  registryId = void 0;
6379
6164
  await require_credentials.storeDokployRegistryId("");
6380
6165
  }
@@ -6383,17 +6168,17 @@ async function workspaceDeployCommand(workspace, options) {
6383
6168
  if (registries.length > 0) {
6384
6169
  registryId = registries[0].registryId;
6385
6170
  await require_credentials.storeDokployRegistryId(registryId);
6386
- logger$3.log(` Using registry: ${registries[0].registryName}`);
6171
+ logger$2.log(` Using registry: ${registries[0].registryName}`);
6387
6172
  } else if (registry) {
6388
- logger$3.log(" No registries found in Dokploy. Let's create one.");
6389
- logger$3.log(` Registry URL: ${registry}`);
6173
+ logger$2.log(" No registries found in Dokploy. Let's create one.");
6174
+ logger$2.log(` Registry URL: ${registry}`);
6390
6175
  const username = await prompt("Registry username: ");
6391
6176
  const password = await prompt("Registry password/token: ", true);
6392
6177
  const reg = await api.createRegistry("Default Registry", registry, username, password);
6393
6178
  registryId = reg.registryId;
6394
6179
  await require_credentials.storeDokployRegistryId(registryId);
6395
- logger$3.log(` ✓ Registry created: ${registryId}`);
6396
- } else logger$3.log(" ⚠ No registry configured. Set deploy.dokploy.registry in workspace config");
6180
+ logger$2.log(` ✓ Registry created: ${registryId}`);
6181
+ } else logger$2.log(" ⚠ No registry configured. Set deploy.dokploy.registry in workspace config");
6397
6182
  }
6398
6183
  const services = workspace.services;
6399
6184
  const dockerServices = {
@@ -6403,7 +6188,7 @@ async function workspaceDeployCommand(workspace, options) {
6403
6188
  let provisionedPostgres = null;
6404
6189
  let provisionedRedis = null;
6405
6190
  if (dockerServices.postgres || dockerServices.redis) {
6406
- logger$3.log("\n🔧 Provisioning infrastructure services...");
6191
+ logger$2.log("\n🔧 Provisioning infrastructure services...");
6407
6192
  const existingServiceIds = {
6408
6193
  postgresId: getPostgresId(state),
6409
6194
  redisId: getRedisId(state)
@@ -6421,7 +6206,7 @@ async function workspaceDeployCommand(workspace, options) {
6421
6206
  }
6422
6207
  }
6423
6208
  const skippedMobileApps = appsToDeployNames.filter((name$1) => workspace.apps[name$1].type === "mobile");
6424
- if (skippedMobileApps.length > 0) logger$3.log(`\n📱 Skipping ${skippedMobileApps.length} mobile app(s) — deploy via framework toolchain: ${skippedMobileApps.join(", ")}`);
6209
+ if (skippedMobileApps.length > 0) logger$2.log(`\n📱 Skipping ${skippedMobileApps.length} mobile app(s) — deploy via framework toolchain: ${skippedMobileApps.join(", ")}`);
6425
6210
  const backendApps = appsToDeployNames.filter((name$1) => workspace.apps[name$1].type === "backend");
6426
6211
  const frontendApps = appsToDeployNames.filter((name$1) => workspace.apps[name$1].type === "web");
6427
6212
  const perAppDbCredentials = /* @__PURE__ */ new Map();
@@ -6431,13 +6216,13 @@ async function workspaceDeployCommand(workspace, options) {
6431
6216
  return requirements?.requiredEnvVars.includes("DATABASE_URL");
6432
6217
  });
6433
6218
  if (appsNeedingDb.length > 0) {
6434
- logger$3.log(`\n🔐 Setting up per-app database credentials...`);
6435
- logger$3.log(` Apps needing DATABASE_URL: ${appsNeedingDb.join(", ")}`);
6219
+ logger$2.log(`\n🔐 Setting up per-app database credentials...`);
6220
+ logger$2.log(` Apps needing DATABASE_URL: ${appsNeedingDb.join(", ")}`);
6436
6221
  const existingCredentials = getAllAppCredentials(state);
6437
6222
  const usersToCreate = [];
6438
6223
  for (const appName of appsNeedingDb) {
6439
6224
  let credentials = existingCredentials[appName];
6440
- if (credentials) logger$3.log(` ${appName}: Using existing credentials from state`);
6225
+ if (credentials) logger$2.log(` ${appName}: Using existing credentials from state`);
6441
6226
  else {
6442
6227
  const password = (0, node_crypto.randomBytes)(16).toString("hex");
6443
6228
  credentials = {
@@ -6445,7 +6230,7 @@ async function workspaceDeployCommand(workspace, options) {
6445
6230
  dbPassword: password
6446
6231
  };
6447
6232
  setAppCredentials(state, appName, credentials);
6448
- logger$3.log(` ${appName}: Generated new credentials`);
6233
+ logger$2.log(` ${appName}: Generated new credentials`);
6449
6234
  }
6450
6235
  perAppDbCredentials.set(appName, credentials);
6451
6236
  usersToCreate.push({
@@ -6459,8 +6244,8 @@ async function workspaceDeployCommand(workspace, options) {
6459
6244
  }
6460
6245
  }
6461
6246
  if (workspace.deploy?.backups && provisionedPostgres) {
6462
- logger$3.log("\n💾 Provisioning backup destination...");
6463
- const { provisionBackupDestination } = await Promise.resolve().then(() => require("./backup-provisioner-C4noe75O.cjs"));
6247
+ logger$2.log("\n💾 Provisioning backup destination...");
6248
+ const { provisionBackupDestination } = await Promise.resolve().then(() => require("./backup-provisioner-B3HBN-2k.cjs"));
6464
6249
  const backupState = await provisionBackupDestination({
6465
6250
  api,
6466
6251
  projectId: project.projectId,
@@ -6468,13 +6253,13 @@ async function workspaceDeployCommand(workspace, options) {
6468
6253
  stage,
6469
6254
  config: workspace.deploy.backups,
6470
6255
  existingState: getBackupState(state),
6471
- logger: logger$3
6256
+ logger: logger$2
6472
6257
  });
6473
6258
  setBackupState(state, backupState);
6474
6259
  if (!backupState.postgresBackupId) {
6475
6260
  const backupSchedule = workspace.deploy.backups.schedule ?? "0 2 * * *";
6476
6261
  const backupRetention = workspace.deploy.backups.retention ?? 30;
6477
- logger$3.log(" Creating postgres backup schedule...");
6262
+ logger$2.log(" Creating postgres backup schedule...");
6478
6263
  const backup = await api.createPostgresBackup({
6479
6264
  schedule: backupSchedule,
6480
6265
  prefix: `${stage}/postgres`,
@@ -6485,8 +6270,8 @@ async function workspaceDeployCommand(workspace, options) {
6485
6270
  keepLatestCount: backupRetention
6486
6271
  });
6487
6272
  setPostgresBackupId(state, backup.backupId);
6488
- logger$3.log(` ✓ Postgres backup schedule created (${backupSchedule})`);
6489
- } else logger$3.log(" ✓ Using existing postgres backup schedule");
6273
+ logger$2.log(` ✓ Postgres backup schedule created (${backupSchedule})`);
6274
+ } else logger$2.log(" ✓ Using existing postgres backup schedule");
6490
6275
  }
6491
6276
  const publicUrls = {};
6492
6277
  const results = [];
@@ -6501,25 +6286,25 @@ async function workspaceDeployCommand(workspace, options) {
6501
6286
  frontendUrls.push(`https://${hostname}`);
6502
6287
  }
6503
6288
  if (backendApps.length > 0) {
6504
- logger$3.log("\n📦 PHASE 1: Deploying backend applications...");
6289
+ logger$2.log("\n📦 PHASE 1: Deploying backend applications...");
6505
6290
  for (const appName of backendApps) {
6506
6291
  const app = workspace.apps[appName];
6507
- logger$3.log(`\n ⚙️ Deploying ${appName}...`);
6292
+ logger$2.log(`\n ⚙️ Deploying ${appName}...`);
6508
6293
  try {
6509
6294
  const dokployAppName = appName;
6510
6295
  let application = null;
6511
6296
  const cachedAppId = getApplicationId(state, appName);
6512
6297
  if (cachedAppId) {
6513
- logger$3.log(` Using cached ID: ${cachedAppId}`);
6298
+ logger$2.log(` Using cached ID: ${cachedAppId}`);
6514
6299
  application = await api.getApplication(cachedAppId);
6515
- if (application) logger$3.log(` ✓ Application found: ${application.applicationId}`);
6516
- else logger$3.log(` ⚠ Cached ID invalid, will create new`);
6300
+ if (application) logger$2.log(` ✓ Application found: ${application.applicationId}`);
6301
+ else logger$2.log(` ⚠ Cached ID invalid, will create new`);
6517
6302
  }
6518
6303
  if (!application) {
6519
6304
  const result = await api.findOrCreateApplication(dokployAppName, project.projectId, environmentId);
6520
6305
  application = result.application;
6521
- if (result.created) logger$3.log(` Created application: ${application.applicationId}`);
6522
- else logger$3.log(` Found existing application: ${application.applicationId}`);
6306
+ if (result.created) logger$2.log(` Created application: ${application.applicationId}`);
6307
+ else logger$2.log(` Found existing application: ${application.applicationId}`);
6523
6308
  }
6524
6309
  setApplicationId(state, appName, application.applicationId);
6525
6310
  const appSecrets = encryptedSecrets.get(appName);
@@ -6527,11 +6312,11 @@ async function workspaceDeployCommand(workspace, options) {
6527
6312
  if (appSecrets && appSecrets.secretCount > 0) {
6528
6313
  buildArgs.push(`GKM_ENCRYPTED_CREDENTIALS=${appSecrets.payload.encrypted}`);
6529
6314
  buildArgs.push(`GKM_CREDENTIALS_IV=${appSecrets.payload.iv}`);
6530
- logger$3.log(` Encrypted ${appSecrets.secretCount} secrets`);
6315
+ logger$2.log(` Encrypted ${appSecrets.secretCount} secrets`);
6531
6316
  }
6532
6317
  const imageName = `${workspace.name}-${appName}`;
6533
6318
  const imageRef = registry ? `${registry}/${imageName}:${imageTag}` : `${imageName}:${imageTag}`;
6534
- logger$3.log(` Building Docker image: ${imageRef}`);
6319
+ logger$2.log(` Building Docker image: ${imageRef}`);
6535
6320
  await deployDocker({
6536
6321
  stage,
6537
6322
  tag: imageTag,
@@ -6581,10 +6366,10 @@ async function workspaceDeployCommand(workspace, options) {
6581
6366
  const { valid, missing, resolved } = validateEnvVars(requiredVars, envContext);
6582
6367
  if (!valid) throw new Error(formatMissingVarsError(appName, missing, stage));
6583
6368
  const envVars = Object.entries(resolved).map(([key, value]) => `${key}=${value}`);
6584
- if (Object.keys(resolved).length > 0) logger$3.log(` Resolved ${Object.keys(resolved).length} env vars: ${Object.keys(resolved).join(", ")}`);
6369
+ if (Object.keys(resolved).length > 0) logger$2.log(` Resolved ${Object.keys(resolved).length} env vars: ${Object.keys(resolved).join(", ")}`);
6585
6370
  await api.saveDockerProvider(application.applicationId, imageRef, { registryId });
6586
6371
  await api.saveApplicationEnv(application.applicationId, envVars.join("\n"));
6587
- logger$3.log(` Deploying to Dokploy...`);
6372
+ logger$2.log(` Deploying to Dokploy...`);
6588
6373
  await api.deployApplication(application.applicationId);
6589
6374
  const existingDomains = await api.getDomainsByApplicationId(application.applicationId);
6590
6375
  const existingDomain = existingDomains.find((d) => d.host === backendHost);
@@ -6592,7 +6377,7 @@ async function workspaceDeployCommand(workspace, options) {
6592
6377
  appHostnames.set(appName, backendHost);
6593
6378
  appDomainIds.set(appName, existingDomain.domainId);
6594
6379
  publicUrls[appName] = `https://${backendHost}`;
6595
- logger$3.log(` ✓ Domain: https://${backendHost} (existing)`);
6380
+ logger$2.log(` ✓ Domain: https://${backendHost} (existing)`);
6596
6381
  } else try {
6597
6382
  const domain = await api.createDomain({
6598
6383
  host: backendHost,
@@ -6604,10 +6389,10 @@ async function workspaceDeployCommand(workspace, options) {
6604
6389
  appHostnames.set(appName, backendHost);
6605
6390
  appDomainIds.set(appName, domain.domainId);
6606
6391
  publicUrls[appName] = `https://${backendHost}`;
6607
- logger$3.log(` ✓ Domain: https://${backendHost} (created)`);
6392
+ logger$2.log(` ✓ Domain: https://${backendHost} (created)`);
6608
6393
  } catch (domainError) {
6609
6394
  const message = domainError instanceof Error ? domainError.message : "Unknown error";
6610
- logger$3.log(` ⚠ Domain creation failed: ${message}`);
6395
+ logger$2.log(` ⚠ Domain creation failed: ${message}`);
6611
6396
  appHostnames.set(appName, backendHost);
6612
6397
  publicUrls[appName] = `https://${backendHost}`;
6613
6398
  }
@@ -6618,10 +6403,10 @@ async function workspaceDeployCommand(workspace, options) {
6618
6403
  applicationId: application.applicationId,
6619
6404
  imageRef
6620
6405
  });
6621
- logger$3.log(` ✓ ${appName} deployed successfully`);
6406
+ logger$2.log(` ✓ ${appName} deployed successfully`);
6622
6407
  } catch (error) {
6623
6408
  const message = error instanceof Error ? error.message : "Unknown error";
6624
- logger$3.log(` ✗ Failed to deploy ${appName}: ${message}`);
6409
+ logger$2.log(` ✗ Failed to deploy ${appName}: ${message}`);
6625
6410
  results.push({
6626
6411
  appName,
6627
6412
  type: app.type,
@@ -6633,25 +6418,25 @@ async function workspaceDeployCommand(workspace, options) {
6633
6418
  }
6634
6419
  }
6635
6420
  if (frontendApps.length > 0) {
6636
- logger$3.log("\n🌐 PHASE 2: Deploying frontend applications...");
6421
+ logger$2.log("\n🌐 PHASE 2: Deploying frontend applications...");
6637
6422
  for (const appName of frontendApps) {
6638
6423
  const app = workspace.apps[appName];
6639
- logger$3.log(`\n 🌐 Deploying ${appName}...`);
6424
+ logger$2.log(`\n 🌐 Deploying ${appName}...`);
6640
6425
  try {
6641
6426
  const dokployAppName = appName;
6642
6427
  let application = null;
6643
6428
  const cachedAppId = getApplicationId(state, appName);
6644
6429
  if (cachedAppId) {
6645
- logger$3.log(` Using cached ID: ${cachedAppId}`);
6430
+ logger$2.log(` Using cached ID: ${cachedAppId}`);
6646
6431
  application = await api.getApplication(cachedAppId);
6647
- if (application) logger$3.log(` ✓ Application found: ${application.applicationId}`);
6648
- else logger$3.log(` ⚠ Cached ID invalid, will create new`);
6432
+ if (application) logger$2.log(` ✓ Application found: ${application.applicationId}`);
6433
+ else logger$2.log(` ⚠ Cached ID invalid, will create new`);
6649
6434
  }
6650
6435
  if (!application) {
6651
6436
  const result = await api.findOrCreateApplication(dokployAppName, project.projectId, environmentId);
6652
6437
  application = result.application;
6653
- if (result.created) logger$3.log(` Created application: ${application.applicationId}`);
6654
- else logger$3.log(` Found existing application: ${application.applicationId}`);
6438
+ if (result.created) logger$2.log(` Created application: ${application.applicationId}`);
6439
+ else logger$2.log(` Found existing application: ${application.applicationId}`);
6655
6440
  }
6656
6441
  setApplicationId(state, appName, application.applicationId);
6657
6442
  const dependencyUrls = {};
@@ -6673,7 +6458,7 @@ async function workspaceDeployCommand(workspace, options) {
6673
6458
  const sniffedVars = sniffedApps.get(appName)?.requiredEnvVars ?? [];
6674
6459
  const { valid, missing, resolved } = validateEnvVars(sniffedVars, envContext);
6675
6460
  if (!valid) throw new Error(formatMissingVarsError(appName, missing, stage));
6676
- if (Object.keys(resolved).length > 0) logger$3.log(` Resolved ${Object.keys(resolved).length} env vars: ${Object.keys(resolved).join(", ")}`);
6461
+ if (Object.keys(resolved).length > 0) logger$2.log(` Resolved ${Object.keys(resolved).length} env vars: ${Object.keys(resolved).join(", ")}`);
6677
6462
  const publicPrefix = require_workspace.getPublicEnvPrefix(app.framework);
6678
6463
  const buildArgs = [];
6679
6464
  const publicUrlArgNames = [];
@@ -6683,10 +6468,10 @@ async function workspaceDeployCommand(workspace, options) {
6683
6468
  publicUrlArgNames.push(key);
6684
6469
  }
6685
6470
  }
6686
- if (buildArgs.length > 0) logger$3.log(` Build args: ${publicUrlArgNames.join(", ")}`);
6471
+ if (buildArgs.length > 0) logger$2.log(` Build args: ${publicUrlArgNames.join(", ")}`);
6687
6472
  const imageName = `${workspace.name}-${appName}`;
6688
6473
  const imageRef = registry ? `${registry}/${imageName}:${imageTag}` : `${imageName}:${imageTag}`;
6689
- logger$3.log(` Building Docker image: ${imageRef}`);
6474
+ logger$2.log(` Building Docker image: ${imageRef}`);
6690
6475
  await deployDocker({
6691
6476
  stage,
6692
6477
  tag: imageTag,
@@ -6707,7 +6492,7 @@ async function workspaceDeployCommand(workspace, options) {
6707
6492
  for (const [key, value] of Object.entries(resolved)) envVars.push(`${key}=${value}`);
6708
6493
  await api.saveDockerProvider(application.applicationId, imageRef, { registryId });
6709
6494
  await api.saveApplicationEnv(application.applicationId, envVars.join("\n"));
6710
- logger$3.log(` Deploying to Dokploy...`);
6495
+ logger$2.log(` Deploying to Dokploy...`);
6711
6496
  await api.deployApplication(application.applicationId);
6712
6497
  const existingFrontendDomains = await api.getDomainsByApplicationId(application.applicationId);
6713
6498
  const existingFrontendDomain = existingFrontendDomains.find((d) => d.host === frontendHost);
@@ -6715,7 +6500,7 @@ async function workspaceDeployCommand(workspace, options) {
6715
6500
  appHostnames.set(appName, frontendHost);
6716
6501
  appDomainIds.set(appName, existingFrontendDomain.domainId);
6717
6502
  publicUrls[appName] = `https://${frontendHost}`;
6718
- logger$3.log(` ✓ Domain: https://${frontendHost} (existing)`);
6503
+ logger$2.log(` ✓ Domain: https://${frontendHost} (existing)`);
6719
6504
  } else try {
6720
6505
  const domain = await api.createDomain({
6721
6506
  host: frontendHost,
@@ -6727,10 +6512,10 @@ async function workspaceDeployCommand(workspace, options) {
6727
6512
  appHostnames.set(appName, frontendHost);
6728
6513
  appDomainIds.set(appName, domain.domainId);
6729
6514
  publicUrls[appName] = `https://${frontendHost}`;
6730
- logger$3.log(` ✓ Domain: https://${frontendHost} (created)`);
6515
+ logger$2.log(` ✓ Domain: https://${frontendHost} (created)`);
6731
6516
  } catch (domainError) {
6732
6517
  const message = domainError instanceof Error ? domainError.message : "Unknown error";
6733
- logger$3.log(` ⚠ Domain creation failed: ${message}`);
6518
+ logger$2.log(` ⚠ Domain creation failed: ${message}`);
6734
6519
  appHostnames.set(appName, frontendHost);
6735
6520
  publicUrls[appName] = `https://${frontendHost}`;
6736
6521
  }
@@ -6741,10 +6526,10 @@ async function workspaceDeployCommand(workspace, options) {
6741
6526
  applicationId: application.applicationId,
6742
6527
  imageRef
6743
6528
  });
6744
- logger$3.log(` ✓ ${appName} deployed successfully`);
6529
+ logger$2.log(` ✓ ${appName} deployed successfully`);
6745
6530
  } catch (error) {
6746
6531
  const message = error instanceof Error ? error.message : "Unknown error";
6747
- logger$3.log(` ✗ Failed to deploy ${appName}: ${message}`);
6532
+ logger$2.log(` ✗ Failed to deploy ${appName}: ${message}`);
6748
6533
  results.push({
6749
6534
  appName,
6750
6535
  type: app.type,
@@ -6754,9 +6539,9 @@ async function workspaceDeployCommand(workspace, options) {
6754
6539
  }
6755
6540
  }
6756
6541
  }
6757
- logger$3.log("\n📋 Saving deploy state...");
6542
+ logger$2.log("\n📋 Saving deploy state...");
6758
6543
  await stateProvider.write(stage, state);
6759
- logger$3.log(" ✓ State saved");
6544
+ logger$2.log(" ✓ State saved");
6760
6545
  const dnsConfig = workspace.deploy.dns;
6761
6546
  if (dnsConfig && appHostnames.size > 0) {
6762
6547
  const dnsResult = await orchestrateDns(appHostnames, dnsConfig, creds.endpoint);
@@ -6765,27 +6550,27 @@ async function workspaceDeployCommand(workspace, options) {
6765
6550
  await stateProvider.write(stage, state);
6766
6551
  }
6767
6552
  if (dnsResult?.success && appHostnames.size > 0) {
6768
- logger$3.log("\n🔒 Validating domains for SSL certificates...");
6553
+ logger$2.log("\n🔒 Validating domains for SSL certificates...");
6769
6554
  for (const [appName, hostname] of appHostnames) try {
6770
6555
  const result = await api.validateDomain(hostname);
6771
- if (result.isValid) logger$3.log(` ✓ ${appName}: ${hostname} → ${result.resolvedIp}`);
6772
- else logger$3.log(` ⚠ ${appName}: ${hostname} not valid`);
6556
+ if (result.isValid) logger$2.log(` ✓ ${appName}: ${hostname} → ${result.resolvedIp}`);
6557
+ else logger$2.log(` ⚠ ${appName}: ${hostname} not valid`);
6773
6558
  } catch (validationError) {
6774
6559
  const message = validationError instanceof Error ? validationError.message : "Unknown error";
6775
- logger$3.log(` ⚠ ${appName}: validation failed - ${message}`);
6560
+ logger$2.log(` ⚠ ${appName}: validation failed - ${message}`);
6776
6561
  }
6777
6562
  }
6778
6563
  }
6779
6564
  const successCount = results.filter((r) => r.success).length;
6780
6565
  const failedCount = results.filter((r) => !r.success).length;
6781
- logger$3.log(`\n${"─".repeat(50)}`);
6782
- logger$3.log(`\n✅ Workspace deployment complete!`);
6783
- logger$3.log(` Project: ${project.projectId}`);
6784
- logger$3.log(` Successful: ${successCount}`);
6785
- if (failedCount > 0) logger$3.log(` Failed: ${failedCount}`);
6566
+ logger$2.log(`\n${"─".repeat(50)}`);
6567
+ logger$2.log(`\n✅ Workspace deployment complete!`);
6568
+ logger$2.log(` Project: ${project.projectId}`);
6569
+ logger$2.log(` Successful: ${successCount}`);
6570
+ if (failedCount > 0) logger$2.log(` Failed: ${failedCount}`);
6786
6571
  if (Object.keys(publicUrls).length > 0) {
6787
- logger$3.log("\n 📡 Deployed URLs:");
6788
- for (const [name$1, url] of Object.entries(publicUrls)) logger$3.log(` ${name$1}: ${url}`);
6572
+ logger$2.log("\n 📡 Deployed URLs:");
6573
+ for (const [name$1, url] of Object.entries(publicUrls)) logger$2.log(` ${name$1}: ${url}`);
6789
6574
  }
6790
6575
  return {
6791
6576
  apps: results,
@@ -6801,14 +6586,14 @@ async function deployCommand(options) {
6801
6586
  const { provider, stage, tag, skipPush, skipBuild } = options;
6802
6587
  const loadedConfig = await require_config.loadWorkspaceConfig();
6803
6588
  if (loadedConfig.type === "workspace") {
6804
- logger$3.log("📦 Detected workspace configuration");
6589
+ logger$2.log("📦 Detected workspace configuration");
6805
6590
  return workspaceDeployCommand(loadedConfig.workspace, options);
6806
6591
  }
6807
- logger$3.log(`\n🚀 Deploying to ${provider}...`);
6808
- logger$3.log(` Stage: ${stage}`);
6592
+ logger$2.log(`\n🚀 Deploying to ${provider}...`);
6593
+ logger$2.log(` Stage: ${stage}`);
6809
6594
  const config = await require_config.loadConfig();
6810
6595
  const imageTag = tag ?? generateTag(stage);
6811
- logger$3.log(` Tag: ${imageTag}`);
6596
+ logger$2.log(` Tag: ${imageTag}`);
6812
6597
  const dockerConfig = resolveDockerConfig(config);
6813
6598
  const imageName = dockerConfig.imageName;
6814
6599
  const registry = dockerConfig.registry;
@@ -6817,7 +6602,7 @@ async function deployCommand(options) {
6817
6602
  let finalRegistry = registry;
6818
6603
  if (provider === "dokploy") {
6819
6604
  const composeServices = config.docker?.compose?.services;
6820
- logger$3.log(`\n🔍 Docker compose config: ${JSON.stringify(config.docker?.compose)}`);
6605
+ logger$2.log(`\n🔍 Docker compose config: ${JSON.stringify(config.docker?.compose)}`);
6821
6606
  const dockerServices = composeServices ? Array.isArray(composeServices) ? {
6822
6607
  postgres: composeServices.includes("postgres"),
6823
6608
  redis: composeServices.includes("redis"),
@@ -6834,7 +6619,7 @@ async function deployCommand(options) {
6834
6619
  const { readStageSecrets: readStageSecrets$1, writeStageSecrets: writeStageSecrets$1, initStageSecrets } = await Promise.resolve().then(() => require("./storage-DOEtT2Hr.cjs"));
6835
6620
  let secrets = await readStageSecrets$1(stage);
6836
6621
  if (!secrets) {
6837
- logger$3.log(` Creating secrets file for stage "${stage}"...`);
6622
+ logger$2.log(` Creating secrets file for stage "${stage}"...`);
6838
6623
  secrets = initStageSecrets(stage);
6839
6624
  }
6840
6625
  let updated = false;
@@ -6849,12 +6634,12 @@ async function deployCommand(options) {
6849
6634
  const urlKey = key;
6850
6635
  if (!secrets.urls[urlKey]) {
6851
6636
  secrets.urls[urlKey] = value;
6852
- logger$3.log(` Saved ${key} to secrets.urls`);
6637
+ logger$2.log(` Saved ${key} to secrets.urls`);
6853
6638
  updated = true;
6854
6639
  }
6855
6640
  } else if (!secrets.custom[key]) {
6856
6641
  secrets.custom[key] = value;
6857
- logger$3.log(` Saved ${key} to secrets.custom`);
6642
+ logger$2.log(` Saved ${key} to secrets.custom`);
6858
6643
  updated = true;
6859
6644
  }
6860
6645
  }
@@ -6863,14 +6648,14 @@ async function deployCommand(options) {
6863
6648
  }
6864
6649
  let masterKey;
6865
6650
  if (!skipBuild) {
6866
- logger$3.log(`\n📦 Building for production...`);
6651
+ logger$2.log(`\n📦 Building for production...`);
6867
6652
  const buildResult = await buildCommand({
6868
6653
  provider: "server",
6869
6654
  production: true,
6870
6655
  stage
6871
6656
  });
6872
6657
  masterKey = buildResult.masterKey;
6873
- } else logger$3.log(`\n⏭️ Skipping build (--skip-build)`);
6658
+ } else logger$2.log(`\n⏭️ Skipping build (--skip-build)`);
6874
6659
  let result;
6875
6660
  switch (provider) {
6876
6661
  case "docker": {
@@ -6906,8 +6691,8 @@ async function deployCommand(options) {
6906
6691
  break;
6907
6692
  }
6908
6693
  case "aws-lambda": {
6909
- logger$3.log("\n⚠️ AWS Lambda deployment is not yet implemented.");
6910
- logger$3.log(" Use SST or AWS CDK for Lambda deployments.");
6694
+ logger$2.log("\n⚠️ AWS Lambda deployment is not yet implemented.");
6695
+ logger$2.log(" Use SST or AWS CDK for Lambda deployments.");
6911
6696
  result = {
6912
6697
  imageRef,
6913
6698
  masterKey
@@ -6916,7 +6701,7 @@ async function deployCommand(options) {
6916
6701
  }
6917
6702
  default: throw new Error(`Unknown deploy provider: ${provider}\nSupported providers: docker, dokploy, aws-lambda`);
6918
6703
  }
6919
- logger$3.log("\n✅ Deployment complete!");
6704
+ logger$2.log("\n✅ Deployment complete!");
6920
6705
  return result;
6921
6706
  }
6922
6707
 
@@ -7113,22 +6898,22 @@ const GEEKMIDAS_VERSIONS = {
7113
6898
  "@geekmidas/audit": "~2.0.1",
7114
6899
  "@geekmidas/auth": "~2.0.1",
7115
6900
  "@geekmidas/cache": "~1.1.1",
7116
- "@geekmidas/client": "~5.0.0",
6901
+ "@geekmidas/client": "~6.0.0",
7117
6902
  "@geekmidas/cloud": "~1.0.1",
7118
- "@geekmidas/constructs": "~3.1.0",
6903
+ "@geekmidas/constructs": "~4.0.1",
7119
6904
  "@geekmidas/db": "~1.0.2",
7120
6905
  "@geekmidas/emailkit": "~1.0.1",
7121
6906
  "@geekmidas/envkit": "~1.0.7",
7122
6907
  "@geekmidas/errors": "~1.0.1",
7123
6908
  "@geekmidas/events": "~1.1.4",
7124
6909
  "@geekmidas/logger": "~1.0.2",
7125
- "@geekmidas/rate-limit": "~2.0.1",
7126
- "@geekmidas/schema": "~1.0.2",
7127
- "@geekmidas/services": "~1.0.4",
6910
+ "@geekmidas/rate-limit": "~3.0.0",
6911
+ "@geekmidas/schema": "~1.0.3",
6912
+ "@geekmidas/services": "~1.1.1",
7128
6913
  "@geekmidas/storage": "~2.0.3",
7129
6914
  "@geekmidas/studio": "~1.0.1",
7130
6915
  "@geekmidas/telescope": "~1.0.1",
7131
- "@geekmidas/testkit": "~1.0.9",
6916
+ "@geekmidas/testkit": "~2.0.0",
7132
6917
  "@geekmidas/cli": CLI_VERSION
7133
6918
  };
7134
6919
 
@@ -12868,7 +12653,7 @@ function printNextSteps(projectName, options, pkgManager) {
12868
12653
 
12869
12654
  //#endregion
12870
12655
  //#region src/secrets/index.ts
12871
- const logger$2 = console;
12656
+ const logger$1 = console;
12872
12657
  /**
12873
12658
  * Extract service names from compose config.
12874
12659
  */
@@ -12884,12 +12669,12 @@ function getServicesFromConfig(services) {
12884
12669
  async function secretsInitCommand(options) {
12885
12670
  const { stage, force } = options;
12886
12671
  if (!force && require_storage.secretsExist(stage)) {
12887
- logger$2.error(`Secrets already exist for stage "${stage}". Use --force to overwrite.`);
12672
+ logger$1.error(`Secrets already exist for stage "${stage}". Use --force to overwrite.`);
12888
12673
  process.exit(1);
12889
12674
  }
12890
12675
  const config = await require_config.loadConfig();
12891
12676
  const services = getServicesFromConfig(config.docker?.compose?.services);
12892
- if (services.length === 0) logger$2.warn("No services configured in docker.compose.services. Creating secrets with empty services.");
12677
+ if (services.length === 0) logger$1.warn("No services configured in docker.compose.services. Creating secrets with empty services.");
12893
12678
  let projectName;
12894
12679
  let workspaceSecrets;
12895
12680
  try {
@@ -12898,23 +12683,23 @@ async function secretsInitCommand(options) {
12898
12683
  const isMultiApp = Object.keys(loaded.workspace.apps).length > 1;
12899
12684
  if (isMultiApp) {
12900
12685
  workspaceSecrets = require_fullstack_secrets.generateFullstackCustomSecrets(loaded.workspace);
12901
- logger$2.log(" Detected workspace mode — generating per-app secrets");
12686
+ logger$1.log(" Detected workspace mode — generating per-app secrets");
12902
12687
  }
12903
12688
  } catch {}
12904
12689
  const secrets = require_fullstack_secrets.createStageSecrets(stage, services, { projectName });
12905
12690
  if (workspaceSecrets) secrets.custom = workspaceSecrets;
12906
12691
  await require_storage.writeStageSecrets(secrets);
12907
- logger$2.log(`\n✓ Secrets initialized for stage "${stage}"`);
12908
- logger$2.log(` Location: .gkm/secrets/${stage}.json`);
12909
- logger$2.log("\n Generated credentials for:");
12910
- for (const service of services) logger$2.log(` - ${service}`);
12911
- if (secrets.urls.DATABASE_URL) logger$2.log(`\n DATABASE_URL: ${maskUrl(secrets.urls.DATABASE_URL)}`);
12912
- if (secrets.urls.REDIS_URL) logger$2.log(` REDIS_URL: ${maskUrl(secrets.urls.REDIS_URL)}`);
12913
- if (secrets.urls.RABBITMQ_URL) logger$2.log(` RABBITMQ_URL: ${maskUrl(secrets.urls.RABBITMQ_URL)}`);
12914
- if (secrets.urls.STORAGE_ENDPOINT) logger$2.log(` STORAGE_ENDPOINT: ${secrets.urls.STORAGE_ENDPOINT}`);
12915
- if (Object.keys(secrets.custom).length > 0) logger$2.log(`\n Custom secrets: ${Object.keys(secrets.custom).length}`);
12916
- logger$2.log(`\n Use "gkm secrets:show --stage ${stage}" to view secrets`);
12917
- logger$2.log(" Use \"gkm secrets:set <KEY> <VALUE> --stage " + stage + "\" to add custom secrets");
12692
+ logger$1.log(`\n✓ Secrets initialized for stage "${stage}"`);
12693
+ logger$1.log(` Location: .gkm/secrets/${stage}.json`);
12694
+ logger$1.log("\n Generated credentials for:");
12695
+ for (const service of services) logger$1.log(` - ${service}`);
12696
+ if (secrets.urls.DATABASE_URL) logger$1.log(`\n DATABASE_URL: ${maskUrl(secrets.urls.DATABASE_URL)}`);
12697
+ if (secrets.urls.REDIS_URL) logger$1.log(` REDIS_URL: ${maskUrl(secrets.urls.REDIS_URL)}`);
12698
+ if (secrets.urls.RABBITMQ_URL) logger$1.log(` RABBITMQ_URL: ${maskUrl(secrets.urls.RABBITMQ_URL)}`);
12699
+ if (secrets.urls.STORAGE_ENDPOINT) logger$1.log(` STORAGE_ENDPOINT: ${secrets.urls.STORAGE_ENDPOINT}`);
12700
+ if (Object.keys(secrets.custom).length > 0) logger$1.log(`\n Custom secrets: ${Object.keys(secrets.custom).length}`);
12701
+ logger$1.log(`\n Use "gkm secrets:show --stage ${stage}" to view secrets`);
12702
+ logger$1.log(" Use \"gkm secrets:set <KEY> <VALUE> --stage " + stage + "\" to add custom secrets");
12918
12703
  }
12919
12704
  /**
12920
12705
  * Read all data from stdin.
@@ -12933,21 +12718,21 @@ async function secretsSetCommand(key, value, options) {
12933
12718
  let secretValue = value;
12934
12719
  if (!secretValue) {
12935
12720
  if (process.stdin.isTTY) {
12936
- logger$2.error("No value provided. Use: gkm secrets:set KEY VALUE --stage <stage>");
12937
- logger$2.error("Or pipe from stdin: echo \"value\" | gkm secrets:set KEY --stage <stage>");
12721
+ logger$1.error("No value provided. Use: gkm secrets:set KEY VALUE --stage <stage>");
12722
+ logger$1.error("Or pipe from stdin: echo \"value\" | gkm secrets:set KEY --stage <stage>");
12938
12723
  process.exit(1);
12939
12724
  }
12940
12725
  secretValue = await readStdin();
12941
12726
  if (!secretValue) {
12942
- logger$2.error("No value received from stdin");
12727
+ logger$1.error("No value received from stdin");
12943
12728
  process.exit(1);
12944
12729
  }
12945
12730
  }
12946
12731
  try {
12947
12732
  await require_storage.setCustomSecret(stage, key, secretValue);
12948
- logger$2.log(`\n✓ Secret "${key}" set for stage "${stage}"`);
12733
+ logger$1.log(`\n✓ Secret "${key}" set for stage "${stage}"`);
12949
12734
  } catch (error) {
12950
- logger$2.error(error instanceof Error ? error.message : "Failed to set secret");
12735
+ logger$1.error(error instanceof Error ? error.message : "Failed to set secret");
12951
12736
  process.exit(1);
12952
12737
  }
12953
12738
  }
@@ -12958,34 +12743,34 @@ async function secretsShowCommand(options) {
12958
12743
  const { stage, reveal } = options;
12959
12744
  const secrets = await require_storage.readStageSecrets(stage);
12960
12745
  if (!secrets) {
12961
- logger$2.error(`No secrets found for stage "${stage}". Run "gkm secrets:init --stage ${stage}" first.`);
12746
+ logger$1.error(`No secrets found for stage "${stage}". Run "gkm secrets:init --stage ${stage}" first.`);
12962
12747
  process.exit(1);
12963
12748
  }
12964
- logger$2.log(`\nSecrets for stage "${stage}":`);
12965
- logger$2.log(` Created: ${secrets.createdAt}`);
12966
- logger$2.log(` Updated: ${secrets.updatedAt}`);
12967
- logger$2.log("\nService Credentials:");
12749
+ logger$1.log(`\nSecrets for stage "${stage}":`);
12750
+ logger$1.log(` Created: ${secrets.createdAt}`);
12751
+ logger$1.log(` Updated: ${secrets.updatedAt}`);
12752
+ logger$1.log("\nService Credentials:");
12968
12753
  for (const [service, creds] of Object.entries(secrets.services)) if (creds) {
12969
- logger$2.log(`\n ${service}:`);
12970
- logger$2.log(` host: ${creds.host}`);
12971
- logger$2.log(` port: ${creds.port}`);
12972
- logger$2.log(` username: ${creds.username}`);
12973
- logger$2.log(` password: ${reveal ? creds.password : require_storage.maskPassword(creds.password)}`);
12974
- if (creds.database) logger$2.log(` database: ${creds.database}`);
12975
- if (creds.vhost) logger$2.log(` vhost: ${creds.vhost}`);
12976
- if (creds.bucket) logger$2.log(` bucket: ${creds.bucket}`);
12977
- }
12978
- logger$2.log("\nConnection URLs:");
12979
- if (secrets.urls.DATABASE_URL) logger$2.log(` DATABASE_URL: ${reveal ? secrets.urls.DATABASE_URL : maskUrl(secrets.urls.DATABASE_URL)}`);
12980
- if (secrets.urls.REDIS_URL) logger$2.log(` REDIS_URL: ${reveal ? secrets.urls.REDIS_URL : maskUrl(secrets.urls.REDIS_URL)}`);
12981
- if (secrets.urls.RABBITMQ_URL) logger$2.log(` RABBITMQ_URL: ${reveal ? secrets.urls.RABBITMQ_URL : maskUrl(secrets.urls.RABBITMQ_URL)}`);
12982
- if (secrets.urls.STORAGE_ENDPOINT) logger$2.log(` STORAGE_ENDPOINT: ${secrets.urls.STORAGE_ENDPOINT}`);
12754
+ logger$1.log(`\n ${service}:`);
12755
+ logger$1.log(` host: ${creds.host}`);
12756
+ logger$1.log(` port: ${creds.port}`);
12757
+ logger$1.log(` username: ${creds.username}`);
12758
+ logger$1.log(` password: ${reveal ? creds.password : require_storage.maskPassword(creds.password)}`);
12759
+ if (creds.database) logger$1.log(` database: ${creds.database}`);
12760
+ if (creds.vhost) logger$1.log(` vhost: ${creds.vhost}`);
12761
+ if (creds.bucket) logger$1.log(` bucket: ${creds.bucket}`);
12762
+ }
12763
+ logger$1.log("\nConnection URLs:");
12764
+ if (secrets.urls.DATABASE_URL) logger$1.log(` DATABASE_URL: ${reveal ? secrets.urls.DATABASE_URL : maskUrl(secrets.urls.DATABASE_URL)}`);
12765
+ if (secrets.urls.REDIS_URL) logger$1.log(` REDIS_URL: ${reveal ? secrets.urls.REDIS_URL : maskUrl(secrets.urls.REDIS_URL)}`);
12766
+ if (secrets.urls.RABBITMQ_URL) logger$1.log(` RABBITMQ_URL: ${reveal ? secrets.urls.RABBITMQ_URL : maskUrl(secrets.urls.RABBITMQ_URL)}`);
12767
+ if (secrets.urls.STORAGE_ENDPOINT) logger$1.log(` STORAGE_ENDPOINT: ${secrets.urls.STORAGE_ENDPOINT}`);
12983
12768
  const customKeys = Object.keys(secrets.custom);
12984
12769
  if (customKeys.length > 0) {
12985
- logger$2.log("\nCustom Secrets:");
12986
- for (const [key, value] of Object.entries(secrets.custom)) logger$2.log(` ${key}: ${reveal ? value : require_storage.maskPassword(value)}`);
12770
+ logger$1.log("\nCustom Secrets:");
12771
+ for (const [key, value] of Object.entries(secrets.custom)) logger$1.log(` ${key}: ${reveal ? value : require_storage.maskPassword(value)}`);
12987
12772
  }
12988
- if (!reveal) logger$2.log("\nUse --reveal to show actual values");
12773
+ if (!reveal) logger$1.log("\nUse --reveal to show actual values");
12989
12774
  }
12990
12775
  /**
12991
12776
  * Rotate passwords for services.
@@ -12994,25 +12779,25 @@ async function secretsRotateCommand(options) {
12994
12779
  const { stage, service } = options;
12995
12780
  const secrets = await require_storage.readStageSecrets(stage);
12996
12781
  if (!secrets) {
12997
- logger$2.error(`No secrets found for stage "${stage}". Run "gkm secrets:init --stage ${stage}" first.`);
12782
+ logger$1.error(`No secrets found for stage "${stage}". Run "gkm secrets:init --stage ${stage}" first.`);
12998
12783
  process.exit(1);
12999
12784
  }
13000
12785
  if (service) {
13001
12786
  if (!secrets.services[service]) {
13002
- logger$2.error(`Service "${service}" not configured in stage "${stage}"`);
12787
+ logger$1.error(`Service "${service}" not configured in stage "${stage}"`);
13003
12788
  process.exit(1);
13004
12789
  }
13005
12790
  const updated = require_fullstack_secrets.rotateServicePassword(secrets, service);
13006
12791
  await require_storage.writeStageSecrets(updated);
13007
- logger$2.log(`\n✓ Password rotated for ${service} in stage "${stage}"`);
12792
+ logger$1.log(`\n✓ Password rotated for ${service} in stage "${stage}"`);
13008
12793
  } else {
13009
12794
  let updated = secrets;
13010
12795
  const services = Object.keys(secrets.services);
13011
12796
  for (const svc of services) updated = require_fullstack_secrets.rotateServicePassword(updated, svc);
13012
12797
  await require_storage.writeStageSecrets(updated);
13013
- logger$2.log(`\n✓ Passwords rotated for all services in stage "${stage}": ${services.join(", ")}`);
12798
+ logger$1.log(`\n✓ Passwords rotated for all services in stage "${stage}": ${services.join(", ")}`);
13014
12799
  }
13015
- logger$2.log(`\nUse "gkm secrets:show --stage ${stage}" to view new values`);
12800
+ logger$1.log(`\nUse "gkm secrets:show --stage ${stage}" to view new values`);
13016
12801
  }
13017
12802
  /**
13018
12803
  * Import secrets from a JSON file.
@@ -13020,7 +12805,7 @@ async function secretsRotateCommand(options) {
13020
12805
  async function secretsImportCommand(file, options) {
13021
12806
  const { stage, merge = true } = options;
13022
12807
  if (!(0, node_fs.existsSync)(file)) {
13023
- logger$2.error(`File not found: ${file}`);
12808
+ logger$1.error(`File not found: ${file}`);
13024
12809
  process.exit(1);
13025
12810
  }
13026
12811
  let importedSecrets;
@@ -13030,12 +12815,12 @@ async function secretsImportCommand(file, options) {
13030
12815
  if (typeof importedSecrets !== "object" || importedSecrets === null) throw new Error("JSON must be an object");
13031
12816
  for (const [key, value] of Object.entries(importedSecrets)) if (typeof value !== "string") throw new Error(`Value for "${key}" must be a string, got ${typeof value}`);
13032
12817
  } catch (error) {
13033
- logger$2.error(`Failed to parse JSON file: ${error instanceof Error ? error.message : "Invalid JSON"}`);
12818
+ logger$1.error(`Failed to parse JSON file: ${error instanceof Error ? error.message : "Invalid JSON"}`);
13034
12819
  process.exit(1);
13035
12820
  }
13036
12821
  const secrets = await require_storage.readStageSecrets(stage);
13037
12822
  if (!secrets) {
13038
- logger$2.error(`No secrets found for stage "${stage}". Run "gkm secrets:init --stage ${stage}" first.`);
12823
+ logger$1.error(`No secrets found for stage "${stage}". Run "gkm secrets:init --stage ${stage}" first.`);
13039
12824
  process.exit(1);
13040
12825
  }
13041
12826
  const updatedCustom = merge ? {
@@ -13050,10 +12835,10 @@ async function secretsImportCommand(file, options) {
13050
12835
  await require_storage.writeStageSecrets(updated);
13051
12836
  const importedCount = Object.keys(importedSecrets).length;
13052
12837
  const totalCount = Object.keys(updatedCustom).length;
13053
- logger$2.log(`\n✓ Imported ${importedCount} secrets for stage "${stage}"`);
13054
- if (merge && totalCount > importedCount) logger$2.log(` Total custom secrets: ${totalCount}`);
13055
- logger$2.log("\n Imported keys:");
13056
- for (const key of Object.keys(importedSecrets)) logger$2.log(` - ${key}`);
12838
+ logger$1.log(`\n✓ Imported ${importedCount} secrets for stage "${stage}"`);
12839
+ if (merge && totalCount > importedCount) logger$1.log(` Total custom secrets: ${totalCount}`);
12840
+ logger$1.log("\n Imported keys:");
12841
+ for (const key of Object.keys(importedSecrets)) logger$1.log(` - ${key}`);
13057
12842
  }
13058
12843
  /**
13059
12844
  * Mask password in a URL for display.
@@ -13068,264 +12853,6 @@ function maskUrl(url) {
13068
12853
  }
13069
12854
  }
13070
12855
 
13071
- //#endregion
13072
- //#region src/setup/index.ts
13073
- const logger$1 = console;
13074
- /**
13075
- * Setup development environment.
13076
- *
13077
- * Orchestrates:
13078
- * 1. Load workspace config
13079
- * 2. Resolve secrets (local → SSM → generate fresh)
13080
- * 3. Write docker/.env from secrets
13081
- * 4. Start Docker services
13082
- */
13083
- async function setupCommand(options = {}) {
13084
- const stage = options.stage ?? "development";
13085
- logger$1.log("\n🔧 Setting up development environment...\n");
13086
- let loadedConfig;
13087
- try {
13088
- loadedConfig = await require_config.loadWorkspaceConfig();
13089
- } catch {
13090
- logger$1.error("❌ No gkm.config.ts found. Run this command from a workspace root.");
13091
- process.exit(1);
13092
- }
13093
- const { workspace } = loadedConfig;
13094
- const isMultiApp = Object.keys(workspace.apps).length > 1;
13095
- logger$1.log(`📦 Workspace: ${workspace.name}`);
13096
- logger$1.log(`📱 Apps: ${Object.keys(workspace.apps).join(", ")}`);
13097
- logger$1.log(`🔑 Stage: ${stage}\n`);
13098
- const secrets = await resolveSecrets(stage, workspace, options);
13099
- if (!secrets) {
13100
- logger$1.error("❌ Failed to resolve secrets. Exiting.");
13101
- process.exit(1);
13102
- }
13103
- if (isMultiApp && workspace.services.db) {
13104
- await require_fullstack_secrets.writeDockerEnvFromSecrets(secrets, workspace.root);
13105
- logger$1.log("📄 Generated docker/.env with database passwords");
13106
- }
13107
- if (!options.skipDocker) {
13108
- const composeFile = (0, node_path.join)(workspace.root, "docker-compose.yml");
13109
- if ((0, node_fs.existsSync)(composeFile)) {
13110
- logger$1.log("");
13111
- const resolvedPorts = await resolveServicePorts(workspace.root);
13112
- await startWorkspaceServices(workspace, resolvedPorts.dockerEnv);
13113
- } else logger$1.log("⚠️ No docker-compose.yml found. Skipping Docker services.");
13114
- }
13115
- printSummary(workspace, stage);
13116
- }
13117
- /**
13118
- * Resolve secrets with priority:
13119
- * 1. Local secrets exist → use them (preserves manual additions)
13120
- * 2. SSM configured and has secrets → pull and use
13121
- * 3. Neither → generate fresh secrets
13122
- *
13123
- * --force skips checks 1 and 2 and always regenerates.
13124
- */
13125
- async function resolveSecrets(stage, workspace, options) {
13126
- if (options.force) {
13127
- logger$1.log("🔐 Generating fresh secrets (--force)...");
13128
- return generateFreshSecrets(stage, workspace, options);
13129
- }
13130
- if (require_storage.secretsExist(stage, workspace.root)) {
13131
- logger$1.log("🔐 Using existing local secrets");
13132
- const secrets = await require_storage.readStageSecrets(stage, workspace.root);
13133
- if (secrets) {
13134
- const reconciled = reconcileSecrets(secrets, workspace);
13135
- if (reconciled) await require_storage.writeStageSecrets(reconciled, workspace.root);
13136
- return reconciled ?? secrets;
13137
- }
13138
- }
13139
- if (require_sync.isSSMConfigured(workspace)) {
13140
- logger$1.log("☁️ Checking for remote secrets in SSM...");
13141
- try {
13142
- const remoteSecrets = await require_sync.pullSecrets(stage, workspace);
13143
- if (remoteSecrets) {
13144
- logger$1.log("✅ Pulled secrets from SSM");
13145
- await require_storage.writeStageSecrets(remoteSecrets, workspace.root);
13146
- return remoteSecrets;
13147
- }
13148
- logger$1.log(" No remote secrets found");
13149
- } catch (error) {
13150
- logger$1.warn(`⚠️ Failed to pull from SSM: ${error.message}`);
13151
- }
13152
- }
13153
- logger$1.log("🔐 Generating fresh development secrets...");
13154
- return generateFreshSecrets(stage, workspace, options);
13155
- }
13156
- /**
13157
- * Reconcile existing secrets with expected workspace-derived keys.
13158
- * Adds missing keys (e.g. BETTER_AUTH_*) without overwriting existing values.
13159
- * Returns the updated secrets if changes were made, or null if no changes needed.
13160
- * @internal Exported for testing
13161
- */
13162
- function reconcileSecrets(secrets, workspace) {
13163
- let changed = false;
13164
- let result = { ...secrets };
13165
- const serviceMap = [
13166
- {
13167
- key: "db",
13168
- name: "postgres"
13169
- },
13170
- {
13171
- key: "cache",
13172
- name: "redis"
13173
- },
13174
- {
13175
- key: "storage",
13176
- name: "minio"
13177
- },
13178
- {
13179
- key: "mail",
13180
- name: "mailpit"
13181
- }
13182
- ];
13183
- for (const { key, name: name$1 } of serviceMap) if (workspace.services[key] && !result.services[name$1]) {
13184
- const creds = require_fullstack_secrets.generateServiceCredentials(name$1);
13185
- if (name$1 === "minio") {
13186
- creds.bucket = workspace.name;
13187
- creds.username = workspace.name;
13188
- }
13189
- result = {
13190
- ...result,
13191
- services: {
13192
- ...result.services,
13193
- [name$1]: creds
13194
- }
13195
- };
13196
- result.urls = require_fullstack_secrets.generateConnectionUrls(result.services, result.eventsBackend);
13197
- logger$1.log(` 🔄 Adding missing service credentials: ${name$1}`);
13198
- changed = true;
13199
- }
13200
- if (result.services.postgres && !result.services.pgboss) {
13201
- result = {
13202
- ...result,
13203
- services: {
13204
- ...result.services,
13205
- pgboss: {
13206
- host: result.services.postgres.host,
13207
- port: result.services.postgres.port,
13208
- username: "pgboss",
13209
- password: require_fullstack_secrets.generateSecurePassword(),
13210
- database: result.services.postgres.database ?? "app"
13211
- }
13212
- }
13213
- };
13214
- result.urls = require_fullstack_secrets.generateConnectionUrls(result.services, result.eventsBackend);
13215
- logger$1.log(" 🔄 Adding missing service credentials: pgboss");
13216
- changed = true;
13217
- }
13218
- const eventsBackend = workspace.services.events;
13219
- if (eventsBackend && result.eventsBackend !== eventsBackend) {
13220
- result.eventsBackend = eventsBackend;
13221
- if (eventsBackend === "sns" && !result.services.localstack) {
13222
- result = {
13223
- ...result,
13224
- services: {
13225
- ...result.services,
13226
- localstack: require_fullstack_secrets.generateLocalStackCredentials()
13227
- }
13228
- };
13229
- logger$1.log(" 🔄 Adding missing service credentials: localstack");
13230
- changed = true;
13231
- }
13232
- if (eventsBackend === "rabbitmq" && !result.services.rabbitmq) {
13233
- result = {
13234
- ...result,
13235
- services: {
13236
- ...result.services,
13237
- rabbitmq: require_fullstack_secrets.generateServiceCredentials("rabbitmq")
13238
- }
13239
- };
13240
- logger$1.log(" 🔄 Adding missing service credentials: rabbitmq");
13241
- changed = true;
13242
- }
13243
- result.urls = require_fullstack_secrets.generateConnectionUrls(result.services, eventsBackend);
13244
- changed = true;
13245
- }
13246
- const isMultiApp = Object.keys(workspace.apps).length > 1;
13247
- if (isMultiApp) {
13248
- const expected = require_fullstack_secrets.generateFullstackCustomSecrets(workspace);
13249
- const missing = {};
13250
- for (const [key, value] of Object.entries(expected)) if (!(key in result.custom)) missing[key] = value;
13251
- if (Object.keys(missing).length > 0) {
13252
- logger$1.log(` 🔄 Adding missing secrets: ${Object.keys(missing).join(", ")}`);
13253
- result = {
13254
- ...result,
13255
- custom: {
13256
- ...result.custom,
13257
- ...missing
13258
- }
13259
- };
13260
- changed = true;
13261
- }
13262
- }
13263
- if (!changed) return null;
13264
- return {
13265
- ...result,
13266
- updatedAt: (/* @__PURE__ */ new Date()).toISOString()
13267
- };
13268
- }
13269
- /**
13270
- * Generate fresh secrets for the workspace.
13271
- */
13272
- async function generateFreshSecrets(stage, workspace, options) {
13273
- const serviceNames = [];
13274
- if (workspace.services.db) serviceNames.push("postgres");
13275
- if (workspace.services.cache) serviceNames.push("redis");
13276
- if (workspace.services.storage) serviceNames.push("minio");
13277
- if (workspace.services.mail) serviceNames.push("mailpit");
13278
- if (workspace.services.events === "sns") serviceNames.push("localstack");
13279
- if (workspace.services.events === "rabbitmq") serviceNames.push("rabbitmq");
13280
- const secrets = require_fullstack_secrets.createStageSecrets(stage, serviceNames, {
13281
- projectName: workspace.name,
13282
- eventsBackend: workspace.services.events
13283
- });
13284
- const isMultiApp = Object.keys(workspace.apps).length > 1;
13285
- if (isMultiApp) {
13286
- const customSecrets = require_fullstack_secrets.generateFullstackCustomSecrets(workspace);
13287
- secrets.custom = customSecrets;
13288
- } else secrets.custom = {
13289
- NODE_ENV: "development",
13290
- PORT: "3000",
13291
- LOG_LEVEL: "debug",
13292
- JWT_SECRET: `dev-${Date.now()}-${Math.random().toString(36).slice(2)}`
13293
- };
13294
- await require_storage.writeStageSecrets(secrets, workspace.root);
13295
- logger$1.log(` Secrets written to .gkm/secrets/${stage}.json`);
13296
- if (require_sync.isSSMConfigured(workspace) && !options.yes) {
13297
- const { shouldPush } = await (0, prompts.default)({
13298
- type: "confirm",
13299
- name: "shouldPush",
13300
- message: "Push secrets to SSM for team sharing?",
13301
- initial: true
13302
- });
13303
- if (shouldPush) try {
13304
- await require_sync.pushSecrets(stage, workspace);
13305
- logger$1.log("☁️ Secrets pushed to SSM");
13306
- } catch (error) {
13307
- logger$1.warn(`⚠️ Failed to push to SSM: ${error.message}`);
13308
- }
13309
- }
13310
- return secrets;
13311
- }
13312
- /**
13313
- * Print setup summary with next steps.
13314
- */
13315
- function printSummary(workspace, stage) {
13316
- logger$1.log(`\n${"─".repeat(50)}`);
13317
- logger$1.log("\n✅ Development environment ready!\n");
13318
- logger$1.log("📋 Apps:");
13319
- for (const [name$1, app] of Object.entries(workspace.apps)) {
13320
- const icon = app.type === "web" ? "🌐" : app.type === "mobile" ? "📱" : "🔧";
13321
- logger$1.log(` ${icon} ${name$1} → http://localhost:${app.port}`);
13322
- }
13323
- logger$1.log("\n🚀 Next steps:");
13324
- logger$1.log(" gkm dev # Start all apps");
13325
- logger$1.log(` gkm secrets:show --stage ${stage} # View secrets`);
13326
- logger$1.log("");
13327
- }
13328
-
13329
12856
  //#endregion
13330
12857
  //#region src/test/index.ts
13331
12858
  /**
@@ -13336,9 +12863,15 @@ async function testCommand(options = {}) {
13336
12863
  const stage = options.stage ?? "development";
13337
12864
  const cwd = process.cwd();
13338
12865
  console.log(`\n🧪 Running tests with ${stage} environment...\n`);
13339
- const defaultEnv = loadEnvFiles(".env");
12866
+ const autoSetup = options.autoSetup || Boolean(process.env.GKM_AUTO_SETUP);
12867
+ if (autoSetup) {
12868
+ const { ensureStageSecrets } = await Promise.resolve().then(() => require("./setup-DLwhfyt-.cjs"));
12869
+ const generated = await ensureStageSecrets(stage, cwd);
12870
+ if (generated) console.log(` 🔐 Generated fresh ${stage} secrets (auto-setup)`);
12871
+ }
12872
+ const defaultEnv = require_setup.loadEnvFiles(".env");
13340
12873
  if (defaultEnv.loaded.length > 0) console.log(` 📦 Loaded env: ${defaultEnv.loaded.join(", ")}`);
13341
- const result = await prepareEntryCredentials({
12874
+ const result = await require_setup.prepareEntryCredentials({
13342
12875
  stages: [stage],
13343
12876
  startDocker: true,
13344
12877
  secretsFileName: "test-secrets.json",
@@ -13360,7 +12893,7 @@ async function testCommand(options = {}) {
13360
12893
  await (0, node_fs_promises.writeFile)(result.secretsJsonPath, JSON.stringify(finalCredentials, null, 2));
13361
12894
  const gkmDir = (0, node_path.join)(cwd, ".gkm");
13362
12895
  const preloadPath = (0, node_path.join)(gkmDir, "test-credentials-preload.ts");
13363
- await createCredentialsPreload(preloadPath, result.secretsJsonPath);
12896
+ await require_setup.createCredentialsPreload(preloadPath, result.secretsJsonPath);
13364
12897
  const existingNodeOptions = process.env.NODE_OPTIONS ?? "";
13365
12898
  const tsxImport = "--import=tsx";
13366
12899
  const preloadImport = `--import=${preloadPath}`;
@@ -13385,9 +12918,9 @@ async function testCommand(options = {}) {
13385
12918
  NODE_OPTIONS: nodeOptions
13386
12919
  }
13387
12920
  });
13388
- return new Promise((resolve$4, reject) => {
12921
+ return new Promise((resolve$3, reject) => {
13389
12922
  vitestProcess.on("close", (code) => {
13390
- if (code === 0) resolve$4();
12923
+ if (code === 0) resolve$3();
13391
12924
  else reject(new Error(`Tests failed with exit code ${code}`));
13392
12925
  });
13393
12926
  vitestProcess.on("error", (error) => {
@@ -13580,7 +13113,7 @@ program.command("setup").description("Setup development environment (secrets, Do
13580
13113
  try {
13581
13114
  const globalOptions = program.opts();
13582
13115
  if (globalOptions.cwd) process.chdir(globalOptions.cwd);
13583
- await setupCommand(options);
13116
+ await require_setup.setupCommand(options);
13584
13117
  } catch (error) {
13585
13118
  console.error(formatError(error));
13586
13119
  process.exit(1);
@@ -13648,7 +13181,7 @@ program.command("exec").description("Run a command with secrets injected into Cr
13648
13181
  process.exit(1);
13649
13182
  }
13650
13183
  });
13651
- program.command("test").description("Run tests with secrets loaded from environment").option("--stage <stage>", "Stage to load secrets from", "development").option("--run", "Run tests once without watch mode").option("--watch", "Enable watch mode").option("--coverage", "Generate coverage report").option("--ui", "Open Vitest UI").argument("[pattern]", "Pattern to filter tests").action(async (pattern, options) => {
13184
+ program.command("test").description("Run tests with secrets loaded from environment").option("--stage <stage>", "Stage to load secrets from", "development").option("--run", "Run tests once without watch mode").option("--watch", "Enable watch mode").option("--coverage", "Generate coverage report").option("--ui", "Open Vitest UI").option("--auto-setup", "Generate a fresh stage (secrets + key) from the workspace config when none exists (for CI; also via GKM_AUTO_SETUP)").argument("[pattern]", "Pattern to filter tests").action(async (pattern, options) => {
13652
13185
  try {
13653
13186
  const globalOptions = program.opts();
13654
13187
  if (globalOptions.cwd) process.chdir(globalOptions.cwd);
@@ -13790,8 +13323,8 @@ program.command("secrets:push").description("Push secrets to remote provider (SS
13790
13323
  const globalOptions = program.opts();
13791
13324
  if (globalOptions.cwd) process.chdir(globalOptions.cwd);
13792
13325
  const { loadWorkspaceConfig: loadWorkspaceConfig$1 } = await Promise.resolve().then(() => require("./config.cjs"));
13793
- const { pushSecrets: pushSecrets$1 } = await Promise.resolve().then(() => require("./sync-D1Pa30oV.cjs"));
13794
- const { reconcileMissingSecrets } = await Promise.resolve().then(() => require("./reconcile-D93YG7G5.cjs"));
13326
+ const { pushSecrets } = await Promise.resolve().then(() => require("./sync-BLA94rgC.cjs"));
13327
+ const { reconcileMissingSecrets } = await Promise.resolve().then(() => require("./reconcile-BzqKJ2Rt.cjs"));
13795
13328
  const { readStageSecrets: readStageSecrets$1, writeStageSecrets: writeStageSecrets$1 } = await Promise.resolve().then(() => require("./storage-DOEtT2Hr.cjs"));
13796
13329
  const { workspace } = await loadWorkspaceConfig$1();
13797
13330
  const secrets = await readStageSecrets$1(options.stage, workspace.root);
@@ -13803,7 +13336,7 @@ program.command("secrets:push").description("Push secrets to remote provider (SS
13803
13336
  for (const key of result.addedKeys) console.log(` + ${key}`);
13804
13337
  }
13805
13338
  }
13806
- await pushSecrets$1(options.stage, workspace);
13339
+ await pushSecrets(options.stage, workspace);
13807
13340
  console.log(`\n✓ Secrets pushed for stage "${options.stage}"`);
13808
13341
  } catch (error) {
13809
13342
  console.error(formatError(error));
@@ -13815,11 +13348,11 @@ program.command("secrets:pull").description("Pull secrets from remote provider (
13815
13348
  const globalOptions = program.opts();
13816
13349
  if (globalOptions.cwd) process.chdir(globalOptions.cwd);
13817
13350
  const { loadWorkspaceConfig: loadWorkspaceConfig$1 } = await Promise.resolve().then(() => require("./config.cjs"));
13818
- const { pullSecrets: pullSecrets$1 } = await Promise.resolve().then(() => require("./sync-D1Pa30oV.cjs"));
13351
+ const { pullSecrets } = await Promise.resolve().then(() => require("./sync-BLA94rgC.cjs"));
13819
13352
  const { writeStageSecrets: writeStageSecrets$1 } = await Promise.resolve().then(() => require("./storage-DOEtT2Hr.cjs"));
13820
- const { reconcileMissingSecrets } = await Promise.resolve().then(() => require("./reconcile-D93YG7G5.cjs"));
13353
+ const { reconcileMissingSecrets } = await Promise.resolve().then(() => require("./reconcile-BzqKJ2Rt.cjs"));
13821
13354
  const { workspace } = await loadWorkspaceConfig$1();
13822
- let secrets = await pullSecrets$1(options.stage, workspace);
13355
+ let secrets = await pullSecrets(options.stage, workspace);
13823
13356
  if (!secrets) {
13824
13357
  console.error(`No remote secrets found for stage "${options.stage}".`);
13825
13358
  process.exit(1);
@@ -13842,7 +13375,7 @@ program.command("secrets:reconcile").description("Backfill missing custom secret
13842
13375
  const globalOptions = program.opts();
13843
13376
  if (globalOptions.cwd) process.chdir(globalOptions.cwd);
13844
13377
  const { loadWorkspaceConfig: loadWorkspaceConfig$1 } = await Promise.resolve().then(() => require("./config.cjs"));
13845
- const { reconcileMissingSecrets } = await Promise.resolve().then(() => require("./reconcile-D93YG7G5.cjs"));
13378
+ const { reconcileMissingSecrets } = await Promise.resolve().then(() => require("./reconcile-BzqKJ2Rt.cjs"));
13846
13379
  const { readStageSecrets: readStageSecrets$1, writeStageSecrets: writeStageSecrets$1 } = await Promise.resolve().then(() => require("./storage-DOEtT2Hr.cjs"));
13847
13380
  const { workspace } = await loadWorkspaceConfig$1();
13848
13381
  const secrets = await readStageSecrets$1(options.stage, workspace.root);