@geekmidas/cli 10.0.0-alpha.26 → 10.0.0-alpha.28

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 (74) hide show
  1. package/dist/{HostingerProvider-BY26bWwB.mjs → HostingerProvider-Btxpto71.mjs} +2 -2
  2. package/dist/{HostingerProvider-BY26bWwB.mjs.map → HostingerProvider-Btxpto71.mjs.map} +1 -1
  3. package/dist/{bundler-mwH7WOb1.mjs → bundler-D5RcGmVM.mjs} +2 -2
  4. package/dist/{bundler-mwH7WOb1.mjs.map → bundler-D5RcGmVM.mjs.map} +1 -1
  5. package/dist/{config-Dn9DW2Fz.cjs → config-BTFLHfRb.cjs} +25 -4
  6. package/dist/{config-Dn9DW2Fz.cjs.map → config-BTFLHfRb.cjs.map} +1 -1
  7. package/dist/{config-DBGpRTUy.mjs → config-Dqxa-_Ge.mjs} +20 -5
  8. package/dist/{config-DBGpRTUy.mjs.map → config-Dqxa-_Ge.mjs.map} +1 -1
  9. package/dist/config.cjs +3 -2
  10. package/dist/config.d.cts +12 -1
  11. package/dist/config.d.cts.map +1 -1
  12. package/dist/config.d.mts +12 -1
  13. package/dist/config.d.mts.map +1 -1
  14. package/dist/config.mjs +3 -3
  15. package/dist/deploy/sniffer-loader.cjs +1 -1
  16. package/dist/{discover-B_HtYJCr.cjs → discover-BTh87DOO.cjs} +24 -2
  17. package/dist/{discover-B_HtYJCr.cjs.map → discover-BTh87DOO.cjs.map} +1 -1
  18. package/dist/{discover-0fhCbnk0.mjs → discover-CXGlQHm1.mjs} +24 -2
  19. package/dist/{discover-0fhCbnk0.mjs.map → discover-CXGlQHm1.mjs.map} +1 -1
  20. package/dist/{github-D58lt7RR.cjs → github-BUCXEl2v.cjs} +6 -6
  21. package/dist/{github-D58lt7RR.cjs.map → github-BUCXEl2v.cjs.map} +1 -1
  22. package/dist/{github-D5SBlOx5.mjs → github-zkzu-ka2.mjs} +4 -4
  23. package/dist/{github-D5SBlOx5.mjs.map → github-zkzu-ka2.mjs.map} +1 -1
  24. package/dist/{index-RCUizGxL.d.cts → index-BPN7kghQ.d.cts} +2 -12
  25. package/dist/{index-B4H4XF7A.d.mts.map → index-BPN7kghQ.d.cts.map} +1 -1
  26. package/dist/{index-B4H4XF7A.d.mts → index-BqWKWRm0.d.mts} +2 -12
  27. package/dist/{index-RCUizGxL.d.cts.map → index-BqWKWRm0.d.mts.map} +1 -1
  28. package/dist/index.cjs +805 -790
  29. package/dist/index.cjs.map +1 -1
  30. package/dist/index.mjs +754 -741
  31. package/dist/index.mjs.map +1 -1
  32. package/dist/{openapi-DHQlstv6.mjs → openapi-D-Lk5Hr5.mjs} +3 -3
  33. package/dist/{openapi-DHQlstv6.mjs.map → openapi-D-Lk5Hr5.mjs.map} +1 -1
  34. package/dist/{openapi-BAKQLho-.cjs → openapi-K4H5tHzA.cjs} +3 -3
  35. package/dist/{openapi-BAKQLho-.cjs.map → openapi-K4H5tHzA.cjs.map} +1 -1
  36. package/dist/openapi.cjs +1 -1
  37. package/dist/openapi.mjs +1 -1
  38. package/dist/reconcile/public.cjs +1 -1
  39. package/dist/reconcile/public.d.cts +12 -0
  40. package/dist/reconcile/public.d.cts.map +1 -1
  41. package/dist/reconcile/public.d.mts +12 -0
  42. package/dist/reconcile/public.d.mts.map +1 -1
  43. package/dist/reconcile/public.mjs +1 -1
  44. package/dist/{generator-LfZU7NlU.mjs → reconcile-DhbCvh4K.mjs} +111 -2
  45. package/dist/reconcile-DhbCvh4K.mjs.map +1 -0
  46. package/dist/{generator-Wdfp0jCS.cjs → reconcile-szmJw_Sb.cjs} +130 -3
  47. package/dist/reconcile-szmJw_Sb.cjs.map +1 -0
  48. package/dist/workspace/index.cjs +1 -2
  49. package/dist/workspace/index.d.cts +2 -2
  50. package/dist/workspace/index.d.mts +2 -2
  51. package/dist/workspace/index.mjs +2 -2
  52. package/dist/{workspace-CRD9YinV.cjs → workspace-Bav3TVrP.cjs} +47 -78
  53. package/dist/workspace-Bav3TVrP.cjs.map +1 -0
  54. package/dist/{credentials-fQSAe4Nb.cjs → workspace-Cv48QwPK.cjs} +347 -516
  55. package/dist/workspace-Cv48QwPK.cjs.map +1 -0
  56. package/dist/{workspace-Bu3xNCej.mjs → workspace-T4IVGSoB.mjs} +48 -73
  57. package/dist/workspace-T4IVGSoB.mjs.map +1 -0
  58. package/dist/{credentials-DI9kJcaP.mjs → workspace-cBobQVoA.mjs} +349 -500
  59. package/dist/workspace-cBobQVoA.mjs.map +1 -0
  60. package/package.json +14 -14
  61. package/dist/credentials-DI9kJcaP.mjs.map +0 -1
  62. package/dist/credentials-fQSAe4Nb.cjs.map +0 -1
  63. package/dist/generator-LfZU7NlU.mjs.map +0 -1
  64. package/dist/generator-Wdfp0jCS.cjs.map +0 -1
  65. package/dist/reconcile-gb1lz1Dk.mjs +0 -113
  66. package/dist/reconcile-gb1lz1Dk.mjs.map +0 -1
  67. package/dist/reconcile-hx_vBvux.cjs +0 -136
  68. package/dist/reconcile-hx_vBvux.cjs.map +0 -1
  69. package/dist/transfer-CAJs_vhu.mjs +0 -122
  70. package/dist/transfer-CAJs_vhu.mjs.map +0 -1
  71. package/dist/transfer-D2qLFXsw.cjs +0 -151
  72. package/dist/transfer-D2qLFXsw.cjs.map +0 -1
  73. package/dist/workspace-Bu3xNCej.mjs.map +0 -1
  74. package/dist/workspace-CRD9YinV.cjs.map +0 -1
package/dist/index.cjs CHANGED
@@ -1,16 +1,14 @@
1
1
  #!/usr/bin/env -S npx tsx
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
3
  const require_rolldown_runtime = require("./rolldown-runtime-C0BPl7ul.cjs");
4
- const require_discover = require("./discover-B_HtYJCr.cjs");
5
- const require_config = require("./config-Dn9DW2Fz.cjs");
6
- const require_workspace = require("./workspace-CRD9YinV.cjs");
7
- const require_credentials = require("./credentials-fQSAe4Nb.cjs");
8
- const require_generator = require("./generator-Wdfp0jCS.cjs");
4
+ const require_discover = require("./discover-BTh87DOO.cjs");
5
+ const require_config = require("./config-BTFLHfRb.cjs");
6
+ const require_workspace = require("./workspace-Bav3TVrP.cjs");
9
7
  const require_storage = require("./storage-DgypfSD6.cjs");
10
- const require_openapi = require("./openapi-BAKQLho-.cjs");
8
+ const require_workspace$1 = require("./workspace-Cv48QwPK.cjs");
9
+ const require_openapi = require("./openapi-K4H5tHzA.cjs");
11
10
  const require_emit = require("./emit-BdoPFjZf.cjs");
12
- const require_reconcile = require("./reconcile-hx_vBvux.cjs");
13
- const require_transfer = require("./transfer-D2qLFXsw.cjs");
11
+ const require_reconcile = require("./reconcile-szmJw_Sb.cjs");
14
12
  let commander = require("commander");
15
13
  let node_process = require("node:process");
16
14
  let node_readline_promises = require("node:readline/promises");
@@ -23,28 +21,28 @@ let node_child_process = require("node:child_process");
23
21
  let _geekmidas_manifest = require("@geekmidas/manifest");
24
22
  let fast_glob = require("fast-glob");
25
23
  fast_glob = require_rolldown_runtime.__toESM(fast_glob, 1);
24
+ let node_module = require("node:module");
26
25
  let chokidar = require("chokidar");
27
26
  chokidar = require_rolldown_runtime.__toESM(chokidar, 1);
28
- let yaml = require("yaml");
29
27
  let node_crypto = require("node:crypto");
28
+ let node_url = require("node:url");
30
29
  let _geekmidas_db_pg_roles = require("@geekmidas/db/pg/roles");
31
30
  let pg = require("pg");
31
+ let yaml = require("yaml");
32
32
  let node_util = require("node:util");
33
33
  let _geekmidas_cache_postgres = require("@geekmidas/cache/postgres");
34
- let node_url = require("node:url");
34
+ let prompts = require("prompts");
35
+ prompts = require_rolldown_runtime.__toESM(prompts, 1);
35
36
  let _geekmidas_constructs_crons = require("@geekmidas/constructs/crons");
36
37
  let _geekmidas_constructs_functions = require("@geekmidas/constructs/functions");
37
38
  let _geekmidas_constructs_queue = require("@geekmidas/constructs/queue");
38
39
  let _geekmidas_constructs_subscribers = require("@geekmidas/constructs/subscribers");
39
40
  let _geekmidas_constructs_topic = require("@geekmidas/constructs/topic");
40
41
  let node_dns_promises = require("node:dns/promises");
41
- let node_module = require("node:module");
42
- let prompts = require("prompts");
43
- prompts = require_rolldown_runtime.__toESM(prompts, 1);
44
42
  let _geekmidas_envkit = require("@geekmidas/envkit");
45
43
  let _geekmidas_services = require("@geekmidas/services");
46
44
  //#region package.json
47
- var version = "10.0.0-alpha.26";
45
+ var version = "10.0.0-alpha.28";
48
46
  //#endregion
49
47
  //#region src/auth/credentials.ts
50
48
  /**
@@ -411,8 +409,182 @@ function normalizeRoutes(routes) {
411
409
  return Array.isArray(routes) ? routes : [routes];
412
410
  }
413
411
  //#endregion
414
- //#region src/exec/index.ts
412
+ //#region src/trust/index.ts
413
+ /**
414
+ * Installing the local edge's certificate authority into the OS trust store.
415
+ *
416
+ * `NODE_EXTRA_CA_CERTS` covers everything gkm starts — the dev server, the test
417
+ * suite, anything under `gkm exec` — because reconcile injects it. A browser
418
+ * reads none of that: it asks the operating system, so until the root is in the
419
+ * system store a local `https://` address is "not secure", which is true and
420
+ * unhelpful.
421
+ *
422
+ * A separate command rather than part of `gkm setup`, for one reason: this
423
+ * needs `sudo`, and a setup that silently escalates on every run is a worse
424
+ * trade than one that tells you what to type. Caddy's own `caddy trust` draws
425
+ * the line in the same place.
426
+ */
415
427
  const logger$12 = console;
428
+ const run = (0, node_util.promisify)(node_child_process.execFile);
429
+ /**
430
+ * How each platform is told about a new authority.
431
+ *
432
+ * Separate rather than shelled through one script because the failure modes
433
+ * differ and the message should name the real one: macOS refuses without an
434
+ * admin password, Debian needs the file in a specific directory before its
435
+ * updater will look at it.
436
+ */
437
+ function installation(platform, certificate) {
438
+ if (platform === "darwin") return {
439
+ describe: "the System keychain",
440
+ steps: [["sudo", [
441
+ "security",
442
+ "add-trusted-cert",
443
+ "-d",
444
+ "-r",
445
+ "trustRoot",
446
+ "-k",
447
+ "/Library/Keychains/System.keychain",
448
+ certificate
449
+ ]]]
450
+ };
451
+ if (platform === "linux") {
452
+ const debian = (0, node_fs.existsSync)("/usr/local/share/ca-certificates");
453
+ return {
454
+ describe: debian ? "the system CA bundle" : "the system trust anchors",
455
+ steps: debian ? [["sudo", [
456
+ "cp",
457
+ certificate,
458
+ "/usr/local/share/ca-certificates/gkm-local-ca.crt"
459
+ ]], ["sudo", ["update-ca-certificates"]]] : [["sudo", [
460
+ "cp",
461
+ certificate,
462
+ "/etc/pki/ca-trust/source/anchors/gkm-local-ca.crt"
463
+ ]], ["sudo", ["update-ca-trust"]]]
464
+ };
465
+ }
466
+ throw new UnsupportedPlatform(platform, certificate);
467
+ }
468
+ /**
469
+ * Trust the certificate authority this project's edge issues from.
470
+ *
471
+ * Idempotent in effect: installing a root that is already trusted replaces the
472
+ * same entry, so running it twice is not an error.
473
+ */
474
+ async function trustCommand(options = {}) {
475
+ const { workspace } = await require_config.loadWorkspaceConfig();
476
+ const certificate = (0, node_path.join)(workspace.root, require_workspace$1.LOCAL_CA_PATH);
477
+ if (!(0, node_fs.existsSync)(certificate)) throw new NoLocalAuthority(certificate);
478
+ const { describe, steps } = installation(process.platform, certificate);
479
+ logger$12.log(`\n🔐 Trusting the local authority in ${describe}`);
480
+ logger$12.log(` ${certificate}\n`);
481
+ if (options.dryRun) {
482
+ for (const [command, args] of steps) logger$12.log(` ${command} ${args.join(" ")}`);
483
+ return;
484
+ }
485
+ logger$12.log(" This needs an admin password.\n");
486
+ for (const [command, args] of steps) await run(command, args, { stdio: "inherit" });
487
+ logger$12.log("\n✅ Local https addresses are trusted. Restart your browser.\n");
488
+ }
489
+ /**
490
+ * Trust the authority if this machine lacks it and its owner agrees.
491
+ *
492
+ * A machine's answer, not the project's: whether a laptop installs a root
493
+ * certificate is its owner's call, so the decision is `--yes`, then what this
494
+ * machine previously answered, then a prompt. Never a silent `sudo` — that is
495
+ * the one thing a setup command should not do on somebody's behalf.
496
+ *
497
+ * Silent and free when the machine already trusts it, which is what makes it
498
+ * acceptable to call on every `gkm setup`.
499
+ */
500
+ async function ensureTrusted(root, url, options = {}) {
501
+ if (await isTrusted(url)) return;
502
+ if (!options.assumeYes) {
503
+ if (!process.stdin.isTTY) {
504
+ logger$12.log(" Local https addresses are not trusted here. Run \"gkm trust\", or \"gkm setup --yes\".");
505
+ return;
506
+ }
507
+ if (await declined(root)) return;
508
+ const { install } = await (0, prompts.default)({
509
+ type: "confirm",
510
+ name: "install",
511
+ message: "Trust this project's local certificate authority, so a browser accepts its https addresses? (needs sudo)",
512
+ initial: false
513
+ });
514
+ if (!install) {
515
+ await recordDeclined(root);
516
+ logger$12.log(" Skipped. Run \"gkm trust\" later.");
517
+ return;
518
+ }
519
+ }
520
+ await trustCommand();
521
+ }
522
+ /** Where a declined answer is remembered, so setup asks once and not again. */
523
+ const TRUST_STATE = ".gkm/trust.json";
524
+ async function declined(root) {
525
+ try {
526
+ const raw = await (0, node_fs_promises.readFile)((0, node_path.join)(root, TRUST_STATE), "utf-8");
527
+ return JSON.parse(raw).declined === true;
528
+ } catch {
529
+ return false;
530
+ }
531
+ }
532
+ async function recordDeclined(root) {
533
+ const path = (0, node_path.join)(root, TRUST_STATE);
534
+ await (0, node_fs_promises.mkdir)((0, node_path.dirname)(path), { recursive: true });
535
+ await (0, node_fs_promises.writeFile)(path, `${JSON.stringify({ declined: true }, null, 2)}\n`);
536
+ }
537
+ /**
538
+ * Whether this machine already trusts the local authority.
539
+ *
540
+ * Asked by connecting rather than by reading a keychain: what matters is
541
+ * whether a client with no special configuration verifies the edge, and that is
542
+ * one platform-neutral question instead of three platform-specific ones. It is
543
+ * also the exact thing a browser is about to do.
544
+ *
545
+ * A child process, because `NODE_EXTRA_CA_CERTS` is read once at startup and
546
+ * this process almost certainly has it set — asking in-process would answer
547
+ * "yes" for everyone.
548
+ */
549
+ async function isTrusted(url) {
550
+ const { NODE_EXTRA_CA_CERTS: _ignored, ...env } = process.env;
551
+ try {
552
+ await run(process.execPath, [
553
+ "--use-system-ca",
554
+ "-e",
555
+ `fetch(${JSON.stringify(url)}).then(()=>0,()=>process.exit(1))`
556
+ ], {
557
+ env,
558
+ timeout: 15e3
559
+ });
560
+ return true;
561
+ } catch {
562
+ return false;
563
+ }
564
+ }
565
+ /** The edge has not run, so there is no authority to trust yet. */
566
+ var NoLocalAuthority = class extends Error {
567
+ path;
568
+ constructor(path) {
569
+ super(`No local certificate authority at ${path}. It is generated the first time the edge starts, so run "gkm setup" (or "gkm dev") once — and if this project declares no file server, nothing needs one.`);
570
+ this.path = path;
571
+ this.name = "NoLocalAuthority";
572
+ }
573
+ };
574
+ /** A platform with no trust store this knows how to write to. */
575
+ var UnsupportedPlatform = class extends Error {
576
+ platform;
577
+ certificate;
578
+ constructor(platform, certificate) {
579
+ super(`gkm does not know how to install a certificate authority on ${platform}. The root is at ${certificate} — add it to the trust store by hand, or point a client at it with NODE_EXTRA_CA_CERTS.`);
580
+ this.platform = platform;
581
+ this.certificate = certificate;
582
+ this.name = "UnsupportedPlatform";
583
+ }
584
+ };
585
+ //#endregion
586
+ //#region src/exec/index.ts
587
+ const logger$11 = console;
416
588
  /** `gkm exec` was given nothing to run. */
417
589
  var NoCommandSpecified = class extends Error {
418
590
  constructor() {
@@ -434,21 +606,18 @@ var NoCommandSpecified = class extends Error {
434
606
  async function execCommand(commandArgs, options = {}) {
435
607
  const cwd = options.cwd ?? process.cwd();
436
608
  if (!commandArgs[0]) throw new NoCommandSpecified();
437
- const defaultEnv = require_credentials.loadEnvFiles(".env");
438
- if (defaultEnv.loaded.length > 0) logger$12.log(`📦 Loaded env: ${defaultEnv.loaded.join(", ")}`);
439
- const { credentials, secretsJsonPath, appName } = await require_credentials.prepareEntryCredentials({
440
- cwd,
441
- resolveDockerPorts: "readonly"
442
- });
443
- if (appName) logger$12.log(`📦 App: ${appName}`);
609
+ const defaultEnv = require_workspace$1.loadEnvFiles(".env");
610
+ if (defaultEnv.loaded.length > 0) logger$11.log(`📦 Loaded env: ${defaultEnv.loaded.join(", ")}`);
611
+ const { credentials, secretsJsonPath, appName } = await require_workspace$1.prepareEntryCredentials({ cwd });
612
+ if (appName) logger$11.log(`📦 App: ${appName}`);
444
613
  const secretCount = Object.keys(credentials).filter((k) => k !== "PORT").length;
445
- if (secretCount > 0) logger$12.log(`🔐 Loaded ${secretCount} secret(s)`);
614
+ if (secretCount > 0) logger$11.log(`🔐 Loaded ${secretCount} secret(s)`);
446
615
  const preloadDir = (0, node_path.join)(cwd, ".gkm");
447
616
  await (0, node_fs_promises.mkdir)(preloadDir, { recursive: true });
448
617
  const preloadPath = (0, node_path.join)(preloadDir, "credentials-preload.mjs");
449
- await require_credentials.createCredentialsPreload(preloadPath, secretsJsonPath);
618
+ await require_workspace$1.createCredentialsPreload(preloadPath, secretsJsonPath);
450
619
  const [cmd, ...args] = commandArgs;
451
- logger$12.log(`🚀 Running: ${[cmd, ...args].join(" ")}`);
620
+ logger$11.log(`🚀 Running: ${[cmd, ...args].join(" ")}`);
452
621
  const nodeOptions = [(process.env.NODE_OPTIONS ?? "").replace(/--import[= ]\S+/g, "").trim(), `--import=${preloadPath}`].filter(Boolean).join(" ");
453
622
  const child = (0, node_child_process.spawn)(cmd, args, {
454
623
  cwd,
@@ -462,7 +631,7 @@ async function execCommand(commandArgs, options = {}) {
462
631
  const exitCode = await new Promise((resolve) => {
463
632
  child.on("close", (code) => resolve(code ?? 0));
464
633
  child.on("error", (error) => {
465
- logger$12.error(`Failed to run command: ${error.message}`);
634
+ logger$11.error(`Failed to run command: ${error.message}`);
466
635
  resolve(1);
467
636
  });
468
637
  });
@@ -470,7 +639,7 @@ async function execCommand(commandArgs, options = {}) {
470
639
  }
471
640
  //#endregion
472
641
  //#region src/dev/index.ts
473
- const logger$11 = console;
642
+ const logger$10 = console;
474
643
  /**
475
644
  * Normalize telescope configuration
476
645
  * @internal Exported for testing
@@ -563,8 +732,8 @@ function getProductionConfigFromGkm(config) {
563
732
  }
564
733
  async function devCommand(options) {
565
734
  if (options.entry) return entryDevCommand(options);
566
- const defaultEnv = require_credentials.loadEnvFiles(".env");
567
- if (defaultEnv.loaded.length > 0) logger$11.log(`📦 Loaded env: ${defaultEnv.loaded.join(", ")}`);
735
+ const defaultEnv = require_workspace$1.loadEnvFiles(".env");
736
+ if (defaultEnv.loaded.length > 0) logger$10.log(`📦 Loaded env: ${defaultEnv.loaded.join(", ")}`);
568
737
  const appName = require_config.getAppNameFromCwd();
569
738
  let config;
570
739
  let appRoot = process.cwd();
@@ -580,9 +749,8 @@ async function devCommand(options) {
580
749
  workspaceAppName = appConfig.appName;
581
750
  workspaceAppPort = appConfig.app.port;
582
751
  workspace = appConfig.workspace;
583
- logger$11.log(`📦 Running app: ${appConfig.appName} on port ${workspaceAppPort}`);
584
752
  if (appConfig.app.entry) {
585
- logger$11.log(`📄 Using entry point: ${appConfig.app.entry}`);
753
+ logger$10.log(`📄 Using entry point: ${appConfig.app.entry}`);
586
754
  return entryDevCommand({
587
755
  ...options,
588
756
  entry: appConfig.app.entry,
@@ -592,73 +760,54 @@ async function devCommand(options) {
592
760
  }
593
761
  } catch {
594
762
  const loadedConfig = await require_config.loadWorkspaceConfig();
595
- if (loadedConfig.type === "workspace") {
596
- logger$11.log("📦 Detected workspace configuration");
597
- return workspaceDevCommand(loadedConfig.workspace, options);
598
- }
763
+ if (loadedConfig.type === "workspace") return workspaceDevCommand(loadedConfig.workspace, options);
599
764
  config = loadedConfig.raw;
765
+ workspace = loadedConfig.workspace;
600
766
  }
601
767
  else {
602
768
  const loadedConfig = await require_config.loadWorkspaceConfig();
603
- if (loadedConfig.type === "workspace") {
604
- logger$11.log("📦 Detected workspace configuration");
605
- return workspaceDevCommand(loadedConfig.workspace, options);
606
- }
769
+ if (loadedConfig.type === "workspace") return workspaceDevCommand(loadedConfig.workspace, options);
607
770
  config = loadedConfig.raw;
608
771
  workspace = loadedConfig.workspace;
609
772
  }
610
773
  if (config.env) {
611
- const { loaded, missing } = require_credentials.loadEnvFiles(config.env, appRoot);
612
- if (loaded.length > 0) logger$11.log(`📦 Loaded env: ${loaded.join(", ")}`);
613
- if (missing.length > 0) logger$11.warn(`⚠️ Missing env files: ${missing.join(", ")}`);
774
+ const { loaded, missing } = require_workspace$1.loadEnvFiles(config.env, appRoot);
775
+ if (loaded.length > 0) logger$10.log(`📦 Loaded env: ${loaded.join(", ")}`);
776
+ if (missing.length > 0) logger$10.warn(`⚠️ Missing env files: ${missing.join(", ")}`);
614
777
  }
615
778
  const resolved = resolveProviders(config, { provider: "server" });
616
- logger$11.log("🚀 Starting development server...");
617
- logger$11.log(`Loading constructs from: ${config.constructs}`);
618
779
  const telescope = normalizeTelescopeConfig(config.telescope);
619
- if (telescope) logger$11.log(`🔭 Telescope enabled at ${telescope.path}`);
620
780
  const studio = normalizeStudioConfig(config.studio);
621
- if (studio) logger$11.log(`🗄️ Studio enabled at ${studio.path}`);
622
781
  const hooks = normalizeHooksConfig(config.hooks, appRoot);
623
- if (hooks) logger$11.log(`🪝 Server hooks enabled from ${config.hooks?.server}`);
624
782
  const enableOpenApi = require_openapi.resolveOpenApiConfig(config).enabled || resolved.enableOpenApi;
625
- if (enableOpenApi) logger$11.log(`📄 OpenAPI output: ${require_openapi.OPENAPI_OUTPUT_PATH}`);
626
- const build = (bustCache = false) => buildApp({
783
+ const build = (bustCache = false) => quietly(() => buildApp({
627
784
  config,
628
785
  workspaceRoot: workspace?.root ?? secretsRoot,
629
786
  appRoot,
630
787
  providers: ["server"],
631
788
  enableOpenApi,
632
- cacheBackend: require_credentials.cacheBackendFor(require_credentials.providerOf(workspace ?? config)),
789
+ cacheBackend: require_workspace$1.cacheBackendFor(require_workspace$1.providerOf(workspace ?? config)),
633
790
  telescope,
634
791
  studio,
635
792
  hooks,
636
793
  skipBundle: true,
637
794
  bustCache,
638
795
  serveEmpty: true
639
- });
796
+ }));
640
797
  const initial = await build();
641
798
  const runtime = config.runtime ?? "node";
642
799
  let secretsJsonPath;
643
- const appSecrets = await require_credentials.loadSecretsForApp(secretsRoot, config.stages.local, workspaceAppName);
644
- if (workspace && require_credentials.usesConstructs(workspace)) {
645
- const reconciled = await require_credentials.reconcileWorkspace(workspace, { stage: workspace.stages.local });
800
+ let publicUrl;
801
+ const appSecrets = await require_workspace$1.loadSecretsForApp(secretsRoot, config.stages.local, workspaceAppName);
802
+ if (workspace) {
803
+ const reconciled = await require_workspace$1.reconcileWorkspace(workspace, { stage: workspace.stages.local });
646
804
  if (reconciled.changed && reconciled.plan.containers.length > 0) {
647
- logger$11.log(`🐳 Services: ${reconciled.plan.containers.join(", ")}`);
648
- for (const [container, address] of Object.entries(reconciled.addresses)) logger$11.log(` ${container}: ${address}`);
805
+ logger$10.log(`🐳 Services: ${reconciled.plan.containers.join(", ")}`);
806
+ for (const [container, address] of Object.entries(reconciled.addresses)) logger$10.log(` ${container}: ${address}`);
649
807
  }
650
808
  Object.assign(appSecrets, reconciled.env);
651
- } else {
652
- const resolvedPorts = await require_credentials.resolveServicePorts(secretsRoot);
653
- if (Object.keys(resolvedPorts.ports).length > 0) {
654
- const rewritten = require_credentials.rewriteUrlsWithPorts(appSecrets, resolvedPorts);
655
- Object.assign(appSecrets, rewritten);
656
- logger$11.log(`🔌 Applied ${Object.keys(resolvedPorts.ports).length} port mapping(s)`);
657
- }
658
- }
659
- if (workspace && workspaceAppName) {
660
- const depEnv = require_workspace.getDependencyEnvVars(workspace, workspaceAppName);
661
- for (const [key, value] of Object.entries(depEnv)) appSecrets[key] ??= value;
809
+ const own = reconciled.plan.resources.find((r) => (r.kind === "rest-api" || r.kind === "site") && require_config.appKey(r.id) === workspaceAppName);
810
+ publicUrl = own ? reconciled.env[own.envKey] : void 0;
662
811
  }
663
812
  if (Object.keys(appSecrets).length > 0) {
664
813
  const secretsDir = (0, node_path.join)(secretsRoot, ".gkm");
@@ -666,13 +815,13 @@ async function devCommand(options) {
666
815
  const secretsFileName = workspaceAppName ? `dev-secrets-${workspaceAppName}.json` : "dev-secrets.json";
667
816
  secretsJsonPath = (0, node_path.join)(secretsDir, secretsFileName);
668
817
  await (0, node_fs_promises.writeFile)(secretsJsonPath, JSON.stringify(appSecrets, null, 2));
669
- logger$11.log(`🔐 Loaded ${Object.keys(appSecrets).length} secret(s)`);
670
818
  }
671
819
  const devServer = new DevServer(resolved.providers[0], options.port ?? workspaceAppPort ?? 3e3, options.portExplicit ?? workspaceAppPort !== void 0, enableOpenApi, telescope, studio, runtime, appRoot, secretsJsonPath, initial.selfServing !== void 0);
820
+ devServer.label = workspaceAppName ?? "server";
821
+ devServer.publicUrl = publicUrl;
672
822
  await devServer.start();
673
823
  const hooksFile = (config.hooks?.server?.split("#"))?.[0];
674
824
  const normalizedPatterns = [config.constructs, ...hooksFile ? [hooksFile.endsWith(".ts") ? hooksFile : `${hooksFile}.ts`] : []].flat().filter((p) => typeof p === "string").map((p) => p.startsWith("./") ? p.slice(2) : p);
675
- logger$11.log(`👀 Watching for changes in: ${normalizedPatterns.join(", ")}`);
676
825
  const resolvedFiles = await (0, fast_glob.default)(normalizedPatterns, {
677
826
  cwd: appRoot,
678
827
  absolute: false,
@@ -681,34 +830,28 @@ async function devCommand(options) {
681
830
  const dirsToWatch = [...new Set(resolvedFiles.map((f) => {
682
831
  return f.split("/").slice(0, -1).join("/");
683
832
  }))];
684
- logger$11.log(`📁 Found ${resolvedFiles.length} files in ${dirsToWatch.length} directories`);
685
833
  const watcher = chokidar.default.watch([...resolvedFiles, ...dirsToWatch], {
686
834
  ignored: /(^|[/\\])\../,
687
835
  persistent: true,
688
836
  ignoreInitial: true,
689
837
  cwd: appRoot
690
838
  });
691
- watcher.on("ready", () => {
692
- logger$11.log("🔍 File watcher ready");
693
- });
694
839
  watcher.on("error", (error) => {
695
- logger$11.error("❌ Watcher error:", error);
840
+ logger$10.error("❌ Watcher error:", error);
696
841
  });
697
842
  let rebuildTimeout = null;
698
843
  watcher.on("change", async (path) => {
699
- logger$11.log(`📝 File changed: ${path}`);
844
+ logger$10.log(`🔄 ${path} changed — rebuilding`);
700
845
  if (rebuildTimeout) clearTimeout(rebuildTimeout);
701
846
  rebuildTimeout = setTimeout(async () => {
702
847
  try {
703
- logger$11.log("🔄 Rebuilding...");
704
848
  const rebuilt = await build(true);
705
- logger$11.log("✅ Rebuild complete, restarting server...");
706
849
  devServer.selfServing = rebuilt.selfServing !== void 0;
707
850
  await devServer.restart();
708
851
  } catch (error) {
709
852
  const err = error;
710
- logger$11.error(`❌ Rebuild failed: ${err.message}`);
711
- if (err.stack) logger$11.error(err.stack);
853
+ logger$10.error(`❌ Rebuild failed: ${err.message}`);
854
+ if (err.stack) logger$10.error(err.stack);
712
855
  }
713
856
  }, 300);
714
857
  });
@@ -716,9 +859,9 @@ async function devCommand(options) {
716
859
  const shutdown = () => {
717
860
  if (isShuttingDown) return;
718
861
  isShuttingDown = true;
719
- logger$11.log("\n🛑 Shutting down...");
862
+ logger$10.log("\n🛑 Shutting down...");
720
863
  Promise.all([watcher.close(), devServer.stop()]).catch((err) => {
721
- logger$11.error("Error during shutdown:", err);
864
+ logger$10.error("Error during shutdown:", err);
722
865
  }).finally(() => {
723
866
  process.exit(0);
724
867
  });
@@ -727,19 +870,6 @@ async function devCommand(options) {
727
870
  process.on("SIGTERM", shutdown);
728
871
  }
729
872
  /**
730
- * Generate all dependency environment variables for all apps.
731
- * Returns a flat object with all {APP_NAME}_URL variables.
732
- * @internal Exported for testing
733
- */
734
- function generateAllDependencyEnvVars(workspace, urlPrefix = "http://localhost") {
735
- const env = {};
736
- for (const appName of Object.keys(workspace.apps)) {
737
- const appEnv = require_workspace.getDependencyEnvVars(workspace, appName, urlPrefix);
738
- Object.assign(env, appEnv);
739
- }
740
- return env;
741
- }
742
- /**
743
873
  * Check for port conflicts across all apps.
744
874
  * Returns list of conflicts if any ports are duplicated.
745
875
  * @internal Exported for testing
@@ -917,12 +1047,8 @@ async function loadDevSecrets(workspace) {
917
1047
  const stage = workspace.stages.local;
918
1048
  if (require_storage.secretsExist(stage, workspace.root)) {
919
1049
  const secrets = await require_storage.readStageSecrets(stage, workspace.root);
920
- if (secrets) {
921
- logger$11.log(`🔐 Loading secrets from stage: ${stage}`);
922
- return require_storage.toEmbeddableSecrets(secrets);
923
- }
1050
+ if (secrets) return require_storage.toEmbeddableSecrets(secrets);
924
1051
  }
925
- logger$11.warn(`⚠️ Secrets enabled but no "${stage}" secrets found. Run "gkm setup" to initialize the local stage`);
926
1052
  return {};
927
1053
  }
928
1054
  /**
@@ -936,66 +1062,43 @@ async function loadDevSecrets(workspace) {
936
1062
  */
937
1063
  async function workspaceDevCommand(workspace, options) {
938
1064
  const appCount = Object.keys(workspace.apps).length;
939
- const backendApps = Object.entries(workspace.apps).filter(([_, app]) => app.type === "backend");
940
1065
  const frontendApps = Object.entries(workspace.apps).filter(([_, app]) => app.type === "web");
941
- const mobileApps = Object.entries(workspace.apps).filter(([_, app]) => app.type === "mobile");
942
- logger$11.log(`\n🚀 Starting workspace: ${workspace.name}`);
943
- const counts = [`${backendApps.length} backend`, `${frontendApps.length} web`];
944
- if (mobileApps.length > 0) counts.push(`${mobileApps.length} mobile`);
945
- logger$11.log(` ${counts.join(", ")} app(s)`);
946
1066
  const conflicts = checkPortConflicts(workspace);
947
1067
  if (conflicts.length > 0) {
948
- for (const conflict of conflicts) logger$11.error(`❌ Port conflict: Apps "${conflict.app1}" and "${conflict.app2}" both use port ${conflict.port}`);
1068
+ for (const conflict of conflicts) logger$10.error(`❌ Port conflict: Apps "${conflict.app1}" and "${conflict.app2}" both use port ${conflict.port}`);
949
1069
  throw new Error("Port conflicts detected. Please assign unique ports to each app.");
950
1070
  }
951
1071
  if (frontendApps.length > 0) {
952
- logger$11.log("\n🔍 Validating frontend apps...");
953
1072
  const validationResults = await validateFrontendApps(workspace);
954
1073
  let hasErrors = false;
955
1074
  for (const result of validationResults) {
956
1075
  if (!result.valid) {
957
1076
  hasErrors = true;
958
- logger$11.error(`\n❌ Frontend app "${result.appName}" validation failed:`);
959
- for (const error of result.errors) logger$11.error(` • ${error}`);
1077
+ logger$10.error(`\n❌ Frontend app "${result.appName}" validation failed:`);
1078
+ for (const error of result.errors) logger$10.error(` • ${error}`);
960
1079
  }
961
- for (const warning of result.warnings) logger$11.warn(` ⚠️ ${result.appName}: ${warning}`);
1080
+ for (const warning of result.warnings) logger$10.warn(` ⚠️ ${result.appName}: ${warning}`);
962
1081
  }
963
1082
  if (hasErrors) throw new Error("Frontend app validation failed. Fix the issues above and try again.");
964
- logger$11.log("✅ Frontend apps validated");
965
1083
  }
966
1084
  const rawSecrets = await loadDevSecrets(workspace);
967
- let secretsEnv;
1085
+ const reconciled = await require_workspace$1.reconcileWorkspace(workspace, { stage: workspace.stages.local });
1086
+ if (reconciled.changed && reconciled.plan.containers.length > 0) {
1087
+ logger$10.log(`🐳 Services: ${reconciled.plan.containers.join(", ")}`);
1088
+ for (const [container, address] of Object.entries(reconciled.addresses)) logger$10.log(` ${container}: ${address}`);
1089
+ }
1090
+ const secretsEnv = {
1091
+ ...rawSecrets,
1092
+ ...reconciled.env
1093
+ };
968
1094
  const appUrls = {};
969
- if (require_credentials.usesConstructs(workspace)) {
970
- const reconciled = await require_credentials.reconcileWorkspace(workspace, { stage: workspace.stages.local });
971
- if (reconciled.changed && reconciled.plan.containers.length > 0) {
972
- logger$11.log(`🐳 Services: ${reconciled.plan.containers.join(", ")}`);
973
- for (const [container, address] of Object.entries(reconciled.addresses)) logger$11.log(` ${container}: ${address}`);
974
- }
975
- secretsEnv = {
976
- ...rawSecrets,
977
- ...reconciled.env
978
- };
979
- for (const resource of reconciled.plan.resources) {
980
- if (resource.kind !== "rest-api" && resource.kind !== "site") continue;
981
- const address = reconciled.env[resource.envKey];
982
- if (address) appUrls[resource.id] = address;
983
- }
984
- } else {
985
- const resolvedPorts = await require_credentials.resolveServicePorts(workspace.root);
986
- await require_credentials.startWorkspaceServices(workspace, resolvedPorts.dockerEnv, rawSecrets);
987
- secretsEnv = require_credentials.rewriteUrlsWithPorts(rawSecrets, resolvedPorts);
988
- }
989
- if (Object.keys(secretsEnv).length > 0) logger$11.log(` Loaded ${Object.keys(secretsEnv).length} secret(s)`);
990
- if (Object.keys(appUrls).length > 0) {
991
- logger$11.log("🔒 App URLs:");
992
- for (const [id, address] of Object.entries(appUrls)) logger$11.log(` ${id}: ${address}`);
993
- }
994
- const dependencyEnv = Object.fromEntries(Object.entries(generateAllDependencyEnvVars(workspace)).filter(([key]) => secretsEnv[key] === void 0));
995
- if (Object.keys(dependencyEnv).length > 0) {
996
- logger$11.log("📡 Dependency URLs:");
997
- for (const [key, value] of Object.entries(dependencyEnv)) logger$11.log(` ${key}=${value}`);
1095
+ for (const resource of reconciled.plan.resources) {
1096
+ if (resource.kind !== "rest-api" && resource.kind !== "site") continue;
1097
+ const address = reconciled.env[resource.envKey];
1098
+ if (address) appUrls[resource.id] = address;
998
1099
  }
1100
+ const firstUrl = Object.values(appUrls).find((url) => url.startsWith("https://"));
1101
+ if (firstUrl) await ensureTrusted(workspace.root, firstUrl);
999
1102
  let turboFilter = [];
1000
1103
  if (options.app) {
1001
1104
  if (!workspace.apps[options.app]) {
@@ -1003,25 +1106,23 @@ async function workspaceDevCommand(workspace, options) {
1003
1106
  throw new Error(`App "${options.app}" not found. Available apps: ${appNames}`);
1004
1107
  }
1005
1108
  turboFilter = ["--filter", appPackageName(workspace, options.app) ?? options.app];
1006
- logger$11.log(`\n🎯 Running single app: ${options.app}`);
1007
- } else if (options.filter) {
1008
- turboFilter = ["--filter", options.filter];
1009
- logger$11.log(`\n🔍 Using filter: ${options.filter}`);
1010
- } else {
1109
+ } else if (options.filter) turboFilter = ["--filter", options.filter];
1110
+ else {
1011
1111
  const { filters, unpackaged } = turboFilters(workspace);
1012
1112
  turboFilter = filters.flatMap((name) => ["--filter", name]);
1013
- if (unpackaged.length > 0) logger$11.warn(`⚠️ No package.json with a name for: ${unpackaged.join(", ")} — turbo cannot run ${unpackaged.length === 1 ? "it" : "them"}.`);
1014
- logger$11.log(`\n🎯 Running all ${appCount} apps`);
1113
+ if (unpackaged.length > 0) logger$10.warn(`⚠️ No package.json with a name for: ${unpackaged.join(", ")} — turbo cannot run ${unpackaged.length === 1 ? "it" : "them"}.`);
1015
1114
  }
1016
1115
  const buildOrder = require_workspace.getAppBuildOrder(workspace);
1017
- logger$11.log("\n📋 Apps (in dependency order):");
1116
+ const width = Math.max(...buildOrder.map((name) => name.length));
1117
+ logger$10.log(`\n${workspace.name}: ${appCount} app(s)`);
1018
1118
  for (const appName of buildOrder) {
1019
1119
  const app = workspace.apps[appName];
1020
1120
  if (!app) continue;
1021
- const deps = app.dependencies.length > 0 ? ` (depends on: ${app.dependencies.join(", ")})` : "";
1022
- const icon = app.type === "backend" ? "🔧" : app.type === "mobile" ? "📱" : "🌐";
1023
- logger$11.log(` ${icon} ${appName} → http://localhost:${app.port}${deps}`);
1121
+ const local = `http://localhost:${app.port}`;
1122
+ const url = Object.entries(appUrls).find(([id]) => require_config.appKey(id) === appName)?.[1];
1123
+ logger$10.log(` ${appName.padEnd(width)} ${url ? `${url} -> ${local}` : local}`);
1024
1124
  }
1125
+ logger$10.log("");
1025
1126
  const configFiles = [
1026
1127
  "gkm.config.ts",
1027
1128
  "gkm.config.js",
@@ -1038,7 +1139,6 @@ async function workspaceDevCommand(workspace, options) {
1038
1139
  const turboEnv = {
1039
1140
  ...process.env,
1040
1141
  ...secretsEnv,
1041
- ...dependencyEnv,
1042
1142
  NODE_ENV: "development",
1043
1143
  ...configPath ? { GKM_CONFIG_PATH: configPath } : {}
1044
1144
  };
@@ -1046,14 +1146,13 @@ async function workspaceDevCommand(workspace, options) {
1046
1146
  const held = [];
1047
1147
  for (const appName of scoped) {
1048
1148
  const port = workspace.apps[appName]?.port;
1049
- if (port && !await require_credentials.isPortAvailable(port)) held.push({
1149
+ if (port && !await require_workspace$1.isPortAvailable(port)) held.push({
1050
1150
  app: appName,
1051
1151
  port,
1052
1152
  holder: listenerOn(port)
1053
1153
  });
1054
1154
  }
1055
1155
  if (held.length > 0) throw new WorkspacePortsInUse(held);
1056
- logger$11.log("\n🏃 Starting turbo run dev...\n");
1057
1156
  const turboProcess = (0, node_child_process.spawn)("pnpm", [
1058
1157
  "turbo",
1059
1158
  "run",
@@ -1069,7 +1168,7 @@ async function workspaceDevCommand(workspace, options) {
1069
1168
  const shutdown = () => {
1070
1169
  if (isShuttingDown) return;
1071
1170
  isShuttingDown = true;
1072
- logger$11.log("\n🛑 Shutting down workspace...");
1171
+ logger$10.log("\n🛑 Shutting down workspace...");
1073
1172
  const pid = turboProcess.pid;
1074
1173
  if (pid) try {
1075
1174
  process.kill(-pid, "SIGTERM");
@@ -1093,7 +1192,7 @@ async function workspaceDevCommand(workspace, options) {
1093
1192
  process.on("SIGTERM", shutdown);
1094
1193
  return new Promise((resolve, reject) => {
1095
1194
  turboProcess.on("error", (error) => {
1096
- logger$11.error("❌ Turbo error:", error);
1195
+ logger$10.error("❌ Turbo error:", error);
1097
1196
  reject(error);
1098
1197
  });
1099
1198
  turboProcess.on("exit", (code) => {
@@ -1111,23 +1210,23 @@ async function entryDevCommand(options) {
1111
1210
  if (!entry) throw new Error("--entry requires a file path");
1112
1211
  const entryPath = (0, node_path.resolve)(process.cwd(), entry);
1113
1212
  if (!(0, node_fs.existsSync)(entryPath)) throw new Error(`Entry file not found: ${entryPath}`);
1114
- const defaultEnv = require_credentials.loadEnvFiles(".env");
1115
- if (defaultEnv.loaded.length > 0) logger$11.log(`📦 Loaded env: ${defaultEnv.loaded.join(", ")}`);
1116
- const { credentials, resolvedPort, secretsJsonPath, appName } = await require_credentials.prepareEntryCredentials({ explicitPort: options.portExplicit ? options.port : void 0 });
1117
- if (appName) logger$11.log(`📦 App: ${appName} (port ${resolvedPort})`);
1118
- logger$11.log(`🚀 Starting entry file: ${entry} on port ${resolvedPort}`);
1119
- if (Object.keys(credentials).length > 1) logger$11.log(`🔐 Loaded ${Object.keys(credentials).length - 1} secret(s) + PORT`);
1213
+ const defaultEnv = require_workspace$1.loadEnvFiles(".env");
1214
+ if (defaultEnv.loaded.length > 0) logger$10.log(`📦 Loaded env: ${defaultEnv.loaded.join(", ")}`);
1215
+ const { credentials, resolvedPort, secretsJsonPath, appName } = await require_workspace$1.prepareEntryCredentials({ explicitPort: options.portExplicit ? options.port : void 0 });
1216
+ if (appName) logger$10.log(`📦 App: ${appName} (port ${resolvedPort})`);
1217
+ logger$10.log(`🚀 Starting entry file: ${entry} on port ${resolvedPort}`);
1218
+ if (Object.keys(credentials).length > 1) logger$10.log(`🔐 Loaded ${Object.keys(credentials).length - 1} secret(s) + PORT`);
1120
1219
  const wrapperDir = (0, node_path.join)(process.cwd(), ".gkm");
1121
1220
  await (0, node_fs_promises.mkdir)(wrapperDir, { recursive: true });
1122
1221
  const wrapperPath = (0, node_path.join)(wrapperDir, "entry-wrapper.ts");
1123
- await require_credentials.createEntryWrapper(wrapperPath, entryPath, secretsJsonPath);
1222
+ await require_workspace$1.createEntryWrapper(wrapperPath, entryPath, secretsJsonPath);
1124
1223
  const runner = new EntryRunner(wrapperPath, entryPath, watch, resolvedPort);
1125
1224
  await runner.start();
1126
1225
  let isShuttingDown = false;
1127
1226
  const shutdown = () => {
1128
1227
  if (isShuttingDown) return;
1129
1228
  isShuttingDown = true;
1130
- logger$11.log("\n🛑 Shutting down...");
1229
+ logger$10.log("\n🛑 Shutting down...");
1131
1230
  runner.stop();
1132
1231
  process.exit(0);
1133
1232
  };
@@ -1163,14 +1262,14 @@ var EntryRunner = class {
1163
1262
  });
1164
1263
  let restartTimeout = null;
1165
1264
  this.watcher.on("change", (path) => {
1166
- logger$11.log(`📝 File changed: ${path}`);
1265
+ logger$10.log(`📝 File changed: ${path}`);
1167
1266
  if (restartTimeout) clearTimeout(restartTimeout);
1168
1267
  restartTimeout = setTimeout(async () => {
1169
- logger$11.log("🔄 Restarting...");
1268
+ logger$10.log("🔄 Restarting...");
1170
1269
  await this.restart();
1171
1270
  }, 300);
1172
1271
  });
1173
- logger$11.log(`👀 Watching for changes in: ${watchDir}`);
1272
+ logger$10.log(`👀 Watching for changes in: ${watchDir}`);
1174
1273
  }
1175
1274
  }
1176
1275
  async runProcess() {
@@ -1178,24 +1277,24 @@ var EntryRunner = class {
1178
1277
  ...process.env,
1179
1278
  PORT: String(this.port)
1180
1279
  };
1181
- this.childProcess = (0, node_child_process.spawn)("npx", ["tsx", this.wrapperPath], {
1280
+ this.childProcess = (0, node_child_process.spawn)(...tsxCommand((0, node_path.dirname)(this.wrapperPath), [this.wrapperPath]), {
1182
1281
  stdio: "inherit",
1183
1282
  env,
1184
1283
  detached: true
1185
1284
  });
1186
1285
  this.isRunning = true;
1187
1286
  this.childProcess.on("error", (error) => {
1188
- logger$11.error("❌ Process error:", error);
1287
+ logger$10.error("❌ Process error:", error);
1189
1288
  });
1190
1289
  this.childProcess.on("exit", (code) => {
1191
- if (code !== null && code !== 0 && code !== 143) logger$11.error(`❌ Process exited with code ${code}`);
1290
+ if (code !== null && code !== 0 && code !== 143) logger$10.error(`❌ Process exited with code ${code}`);
1192
1291
  this.isRunning = false;
1193
1292
  });
1194
1293
  await new Promise((resolve) => setTimeout(resolve, 500));
1195
1294
  if (this.isRunning) {
1196
- logger$11.log("");
1197
- logger$11.log(` \x1b[32m✓ Ready\x1b[0m at \x1b[36mhttp://localhost:${this.port}\x1b[0m`);
1198
- logger$11.log("");
1295
+ logger$10.log("");
1296
+ logger$10.log(` \x1b[32m✓ Ready\x1b[0m at \x1b[36mhttp://localhost:${this.port}\x1b[0m`);
1297
+ logger$10.log("");
1199
1298
  }
1200
1299
  }
1201
1300
  async restart() {
@@ -1281,7 +1380,6 @@ ${credentialsInjection}${parentWatch}const port = process.argv.includes('--port'
1281
1380
  const { app } = await import('${appImportPath}');
1282
1381
 
1283
1382
  ${serveCode.replace(/^ {4}/gm, "")}
1284
- console.log(\`Server started on port \${port}\`);
1285
1383
  `;
1286
1384
  return `#!/usr/bin/env node
1287
1385
  /**
@@ -1310,6 +1408,31 @@ start({
1310
1408
  });
1311
1409
  `;
1312
1410
  }
1411
+ /** Run `fn` with `console.log` muted — warnings and errors still print. */
1412
+ async function quietly(fn) {
1413
+ const log = console.log;
1414
+ console.log = () => {};
1415
+ try {
1416
+ return await fn();
1417
+ } finally {
1418
+ console.log = log;
1419
+ }
1420
+ }
1421
+ /**
1422
+ * How to run a TypeScript entry with the app's own tsx.
1423
+ *
1424
+ * Straight through node rather than `npx tsx`: npx reads the developer's npm
1425
+ * config on every start and warned about each key it did not recognise — nine
1426
+ * lines per app, per restart, about nothing gkm does.
1427
+ */
1428
+ function tsxCommand(appRoot, args) {
1429
+ try {
1430
+ const cli = (0, node_module.createRequire)((0, node_path.join)(appRoot, "package.json")).resolve("tsx/cli");
1431
+ return [process.execPath, [cli, ...args]];
1432
+ } catch {
1433
+ return ["npx", ["tsx", ...args]];
1434
+ }
1435
+ }
1313
1436
  /** A port this app must serve on is held by something else. */
1314
1437
  var DevPortInUse = class extends Error {
1315
1438
  port;
@@ -1376,25 +1499,30 @@ var DevServer = class {
1376
1499
  this.selfServing = selfServing;
1377
1500
  this.actualPort = requestedPort;
1378
1501
  }
1502
+ /** What the ready line calls this app. */
1503
+ label = "server";
1504
+ /**
1505
+ * Where the app is reached — its HTTPS address behind the edge, when it has
1506
+ * one. The local port is only what the edge forwards to.
1507
+ */
1508
+ publicUrl;
1379
1509
  async start() {
1380
1510
  this.startTime = Date.now();
1381
1511
  if (this.isRunning) await this.stop();
1382
1512
  if (this.portExplicit) {
1383
- if (!await require_credentials.isPortAvailable(this.requestedPort)) throw new DevPortInUse(this.requestedPort, listenerOn(this.requestedPort));
1513
+ if (!await require_workspace$1.isPortAvailable(this.requestedPort)) throw new DevPortInUse(this.requestedPort, listenerOn(this.requestedPort));
1384
1514
  this.actualPort = this.requestedPort;
1385
1515
  } else {
1386
- this.actualPort = await require_credentials.findAvailablePort(this.requestedPort);
1387
- if (this.actualPort !== this.requestedPort) logger$11.log(`ℹ️ Port ${this.requestedPort} was in use, using port ${this.actualPort} instead`);
1516
+ this.actualPort = await require_workspace$1.findAvailablePort(this.requestedPort);
1517
+ if (this.actualPort !== this.requestedPort) logger$10.log(`ℹ️ Port ${this.requestedPort} was in use, using port ${this.actualPort} instead`);
1388
1518
  }
1389
1519
  const serverEntryPath = (0, node_path.join)(this.appRoot, ".gkm", this.provider, "server.ts");
1390
1520
  await this.createServerEntry();
1391
- logger$11.log(`\n⏳ Starting server...`);
1392
- this.serverProcess = (0, node_child_process.spawn)("npx", [
1393
- "tsx",
1521
+ this.serverProcess = (0, node_child_process.spawn)(...tsxCommand(this.appRoot, [
1394
1522
  serverEntryPath,
1395
1523
  "--port",
1396
1524
  this.actualPort.toString()
1397
- ], {
1525
+ ]), {
1398
1526
  stdio: "inherit",
1399
1527
  env: {
1400
1528
  ...process.env,
@@ -1405,29 +1533,24 @@ var DevServer = class {
1405
1533
  });
1406
1534
  this.isRunning = true;
1407
1535
  this.serverProcess.on("error", (error) => {
1408
- logger$11.error("❌ Server error:", error);
1536
+ logger$10.error("❌ Server error:", error);
1409
1537
  });
1410
1538
  this.serverProcess.on("exit", (code, signal) => {
1411
- if (code !== null && code !== 0 && signal !== "SIGTERM") logger$11.error(`❌ Server exited with code ${code}`);
1539
+ if (code !== null && code !== 0 && signal !== "SIGTERM") logger$10.error(`❌ Server exited with code ${code}`);
1412
1540
  this.isRunning = false;
1413
1541
  });
1414
1542
  await new Promise((resolve) => setTimeout(resolve, 1e3));
1415
1543
  if (this.isRunning) {
1416
- const base = `http://localhost:${this.actualPort}`;
1417
- const lines = [` Local: ${base}`];
1418
- if (this.enableOpenApi) lines.push(` API Docs: ${base}/__docs`);
1419
- if (this.telescope) lines.push(` Telescope: ${base}${this.telescope.path}`);
1420
- if (this.studio) lines.push(` Studio: ${base}${this.studio.path}`);
1421
- const maxLen = Math.max(...lines.map((l) => l.length));
1422
- const pad = (s) => s.padEnd(maxLen);
1423
- const border = "─".repeat(maxLen + 2);
1424
- logger$11.log("");
1425
- logger$11.log(` \x1b[32m✓ Ready\x1b[0m in ${((Date.now() - this.startTime) / 1e3).toFixed(1)}s`);
1426
- logger$11.log("");
1427
- logger$11.log(` ┌${border}┐`);
1428
- for (const line of lines) logger$11.log(` │ ${pad(line)} │`);
1429
- logger$11.log(` └${border}┘`);
1430
- logger$11.log("");
1544
+ const local = `http://localhost:${this.actualPort}`;
1545
+ const address = this.publicUrl ? `${this.publicUrl} -> ${local}` : local;
1546
+ const seconds = ((Date.now() - this.startTime) / 1e3).toFixed(1);
1547
+ logger$10.log(`\x1b[32m✓\x1b[0m ${this.label} ready in ${seconds}s ${address}`);
1548
+ const tools = this.selfServing ? [] : [
1549
+ ...this.enableOpenApi ? ["docs /__docs"] : [],
1550
+ ...this.telescope ? [`telescope ${this.telescope.path}`] : [],
1551
+ ...this.studio ? [`studio ${this.studio.path}`] : []
1552
+ ];
1553
+ if (tools.length > 0) logger$10.log(` ${tools.join(" · ")}`);
1431
1554
  }
1432
1555
  }
1433
1556
  async stop() {
@@ -1456,7 +1579,7 @@ var DevServer = class {
1456
1579
  await this.stop();
1457
1580
  let attempts = 0;
1458
1581
  while (attempts < 30) {
1459
- if (await require_credentials.isPortAvailable(portToReuse)) break;
1582
+ if (await require_workspace$1.isPortAvailable(portToReuse)) break;
1460
1583
  await new Promise((resolve) => setTimeout(resolve, 100));
1461
1584
  attempts++;
1462
1585
  }
@@ -2242,7 +2365,7 @@ var TopicGenerator = class extends require_discover.ConstructGenerator {
2242
2365
  };
2243
2366
  //#endregion
2244
2367
  //#region src/build/manifests.ts
2245
- const logger$10 = console;
2368
+ const logger$9 = console;
2246
2369
  function isPartitioned(field) {
2247
2370
  return !Array.isArray(field);
2248
2371
  }
@@ -2339,8 +2462,8 @@ export type RoutePath = Route['path'];
2339
2462
  `;
2340
2463
  const manifestPath = (0, node_path.join)(manifestDir, "aws.ts");
2341
2464
  await (0, node_fs_promises.writeFile)(manifestPath, content);
2342
- logger$10.log(`Generated AWS manifest with ${countItems(awsRoutes)} routes, ${countItems(functions)} functions, ${countItems(crons)} crons, ${countItems(subscribers)} subscribers, ${countItems(queues)} queues, ${countItems(topics)} topics`);
2343
- logger$10.log(`Manifest: ${(0, node_path.relative)(process.cwd(), manifestPath)}`);
2465
+ 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`);
2466
+ logger$9.log(`Manifest: ${(0, node_path.relative)(process.cwd(), manifestPath)}`);
2344
2467
  }
2345
2468
  async function generateServerManifest(outputDir, appInfo, routes, subscribers, queues = [], topics = [], constructs = {}, backends = {}) {
2346
2469
  const manifestDir = (0, node_path.join)(outputDir, "manifest");
@@ -2395,8 +2518,8 @@ export type RoutePath = Route['path'];
2395
2518
  `;
2396
2519
  const manifestPath = (0, node_path.join)(manifestDir, "server.ts");
2397
2520
  await (0, node_fs_promises.writeFile)(manifestPath, content);
2398
- logger$10.log(`Generated server manifest with ${countItems(serverRoutes)} routes, ${countItems(serverSubscribers)} subscribers, ${countItems(serverQueues)} queues, ${countItems(serverTopics)} topics`);
2399
- logger$10.log(`Manifest: ${(0, node_path.relative)(process.cwd(), manifestPath)}`);
2521
+ logger$9.log(`Generated server manifest with ${countItems(serverRoutes)} routes, ${countItems(serverSubscribers)} subscribers, ${countItems(serverQueues)} queues, ${countItems(serverTopics)} topics`);
2522
+ logger$9.log(`Manifest: ${(0, node_path.relative)(process.cwd(), manifestPath)}`);
2400
2523
  }
2401
2524
  /**
2402
2525
  * Filter out 'ALL' method routes from a manifest field (flat or partitioned).
@@ -2601,7 +2724,7 @@ export default app;
2601
2724
  }
2602
2725
  //#endregion
2603
2726
  //#region src/build/index.ts
2604
- const logger$9 = console;
2727
+ const logger$8 = console;
2605
2728
  /**
2606
2729
  * What a build run at the workspace root reads.
2607
2730
  *
@@ -2626,24 +2749,24 @@ async function buildCommand(options) {
2626
2749
  const isAtWorkspaceRoot = cwd === workspaceRoot;
2627
2750
  const someAppIsElsewhere = Object.values(loadedConfig.workspace.apps).some((app) => (0, node_path.resolve)(workspaceRoot, app.path) !== workspaceRoot);
2628
2751
  if (isAtWorkspaceRoot && someAppIsElsewhere) {
2629
- logger$9.log("📦 Detected workspace configuration");
2752
+ logger$8.log("📦 Detected workspace configuration");
2630
2753
  return workspaceBuildCommand(loadedConfig.workspace, options);
2631
2754
  }
2632
2755
  }
2633
2756
  const config = loadedConfig.type !== "workspace" ? await require_config.loadConfig() : (0, node_path.resolve)(process.cwd()) === (0, node_path.resolve)(loadedConfig.workspace.root) ? rootGkmConfig(loadedConfig.workspace) : (await require_config.loadAppConfig()).gkmConfig;
2634
2757
  const resolved = resolveProviders(config, options);
2635
- const cacheBackend = require_credentials.cacheBackendFor(require_credentials.providerOf(loadedConfig.workspace));
2758
+ const cacheBackend = require_workspace$1.cacheBackendFor(require_workspace$1.providerOf(loadedConfig.workspace));
2636
2759
  const productionConfigFromGkm = getProductionConfigFromGkm(config);
2637
2760
  const production = normalizeProductionConfig(options.production ?? false, productionConfigFromGkm);
2638
- if (production) logger$9.log(`🏭 Building for PRODUCTION`);
2639
- logger$9.log(`Building with providers: ${resolved.providers.join(", ")}`);
2640
- logger$9.log(`Loading constructs from: ${formatRoutes(config.constructs)}`);
2761
+ if (production) logger$8.log(`🏭 Building for PRODUCTION`);
2762
+ logger$8.log(`Building with providers: ${resolved.providers.join(", ")}`);
2763
+ logger$8.log(`Loading constructs from: ${formatRoutes(config.constructs)}`);
2641
2764
  const telescope = production ? void 0 : normalizeTelescopeConfig(config.telescope);
2642
- if (telescope) logger$9.log(`🔭 Telescope enabled at ${telescope.path}`);
2765
+ if (telescope) logger$8.log(`🔭 Telescope enabled at ${telescope.path}`);
2643
2766
  const studio = production ? void 0 : normalizeStudioConfig(config.studio);
2644
- if (studio) logger$9.log(`🗄️ Studio enabled at ${studio.path}`);
2767
+ if (studio) logger$8.log(`🗄️ Studio enabled at ${studio.path}`);
2645
2768
  const hooks = normalizeHooksConfig(config.hooks);
2646
- if (hooks) logger$9.log(`🪝 Server hooks enabled`);
2769
+ if (hooks) logger$8.log(`🪝 Server hooks enabled`);
2647
2770
  return buildApp({
2648
2771
  config,
2649
2772
  workspaceRoot: loadedConfig.workspace.root,
@@ -2686,7 +2809,7 @@ async function buildApp(input) {
2686
2809
  });
2687
2810
  if (selfServing) {
2688
2811
  await writeSurfaceEntry((0, node_path.join)(appRoot, ".gkm", "server"), selfServing.source);
2689
- logger$9.log(`Generated a server for ${selfServing.id} from its own declaration`);
2812
+ logger$8.log(`Generated a server for ${selfServing.id} from its own declaration`);
2690
2813
  return { selfServing: selfServing.id };
2691
2814
  }
2692
2815
  const derived = ownersContext({
@@ -2726,14 +2849,14 @@ async function buildApp(input) {
2726
2849
  topicGenerator.load(code, appRoot, bustCache)
2727
2850
  ]);
2728
2851
  const allEndpoints = servedBy(loadedEndpoints, derived.surface);
2729
- logger$9.log(`Found ${allEndpoints.length} endpoints`);
2730
- logger$9.log(`Found ${allFunctions.length} functions`);
2731
- logger$9.log(`Found ${allCrons.length} crons`);
2732
- logger$9.log(`Found ${allSubscribers.length} subscribers`);
2733
- logger$9.log(`Found ${allQueues.length} queues`);
2734
- logger$9.log(`Found ${allTopics.length} topics`);
2852
+ logger$8.log(`Found ${allEndpoints.length} endpoints`);
2853
+ logger$8.log(`Found ${allFunctions.length} functions`);
2854
+ logger$8.log(`Found ${allCrons.length} crons`);
2855
+ logger$8.log(`Found ${allSubscribers.length} subscribers`);
2856
+ logger$8.log(`Found ${allQueues.length} queues`);
2857
+ logger$8.log(`Found ${allTopics.length} topics`);
2735
2858
  if (!input.serveEmpty && allEndpoints.length === 0 && allFunctions.length === 0 && allCrons.length === 0 && allSubscribers.length === 0 && allQueues.length === 0 && allTopics.length === 0) {
2736
- logger$9.log("No endpoints, functions, crons, subscribers, queues, or topics found to process");
2859
+ logger$8.log("No endpoints, functions, crons, subscribers, queues, or topics found to process");
2737
2860
  return {};
2738
2861
  }
2739
2862
  const rootOutputDir = (0, node_path.join)(appRoot, ".gkm");
@@ -2750,7 +2873,7 @@ async function buildForProvider(provider, context, appRoot, discovered, endpoint
2750
2873
  const rootOutputDir = (0, node_path.join)(appRoot, ".gkm");
2751
2874
  const outputDir = (0, node_path.join)(rootOutputDir, provider);
2752
2875
  await (0, node_fs_promises.mkdir)(outputDir, { recursive: true });
2753
- logger$9.log(`\nGenerating handlers for provider: ${provider}`);
2876
+ logger$8.log(`\nGenerating handlers for provider: ${provider}`);
2754
2877
  const [routes, functionInfos, cronInfos, subscriberInfos, queueInfos, topicInfos] = await Promise.all([
2755
2878
  endpointGenerator.build(context, endpoints, outputDir, {
2756
2879
  provider,
@@ -2762,7 +2885,7 @@ async function buildForProvider(provider, context, appRoot, discovered, endpoint
2762
2885
  queueGenerator.build(context, queues, outputDir, { provider }),
2763
2886
  topicGenerator.build(context, topics, outputDir, { provider })
2764
2887
  ]);
2765
- logger$9.log(`Generated ${routes.length} routes, ${functionInfos.length} functions, ${cronInfos.length} crons, ${subscriberInfos.length} subscribers, ${queueInfos.length} queues, ${topicInfos.length} topics for ${provider}`);
2888
+ logger$8.log(`Generated ${routes.length} routes, ${functionInfos.length} functions, ${cronInfos.length} crons, ${subscriberInfos.length} subscribers, ${queueInfos.length} queues, ${topicInfos.length} topics for ${provider}`);
2766
2889
  const manifestRoutes = assembleManifestField(routes, endpoints);
2767
2890
  const manifestFunctions = assembleManifestField(functionInfos, functions);
2768
2891
  const manifestCrons = assembleManifestField(cronInfos, crons);
@@ -2782,7 +2905,7 @@ async function buildForProvider(provider, context, appRoot, discovered, endpoint
2782
2905
  }, serverRouteField, manifestSubscribers, manifestQueues, manifestTopics);
2783
2906
  let masterKey;
2784
2907
  if (context.production?.bundle && !skipBundle) {
2785
- logger$9.log(`\n📦 Bundling production server...`);
2908
+ logger$8.log(`\n📦 Bundling production server...`);
2786
2909
  const { bundleServer } = await Promise.resolve().then(() => require("./bundler-mjqGAvu1.cjs"));
2787
2910
  const allConstructs = [
2788
2911
  ...endpoints.map((e) => e.construct),
@@ -2800,10 +2923,10 @@ async function buildForProvider(provider, context, appRoot, discovered, endpoint
2800
2923
  stage,
2801
2924
  constructs: allConstructs
2802
2925
  })).masterKey;
2803
- logger$9.log(`✅ Bundle complete: .gkm/server/dist/server.mjs`);
2926
+ logger$8.log(`✅ Bundle complete: .gkm/server/dist/server.mjs`);
2804
2927
  if (masterKey) {
2805
- logger$9.log(`\n🔐 Secrets encrypted for deployment`);
2806
- logger$9.log(` Deploy with: GKM_MASTER_KEY=${masterKey}`);
2928
+ logger$8.log(`\n🔐 Secrets encrypted for deployment`);
2929
+ logger$8.log(` Deploy with: GKM_MASTER_KEY=${masterKey}`);
2807
2930
  }
2808
2931
  }
2809
2932
  return { masterKey };
@@ -2890,19 +3013,19 @@ async function workspaceBuildCommand(workspace, options) {
2890
3013
  const apps = Object.entries(workspace.apps);
2891
3014
  const backendApps = apps.filter(([, app]) => app.type === "backend");
2892
3015
  const frontendApps = apps.filter(([, app]) => app.type === "web");
2893
- logger$9.log(`\n🏗️ Building workspace: ${workspace.name}`);
2894
- logger$9.log(` Backend apps: ${backendApps.map(([name]) => name).join(", ") || "none"}`);
2895
- logger$9.log(` Frontend apps: ${frontendApps.map(([name]) => name).join(", ") || "none"}`);
2896
- if (options.production) logger$9.log(` 🏭 Production mode enabled`);
3016
+ logger$8.log(`\n🏗️ Building workspace: ${workspace.name}`);
3017
+ logger$8.log(` Backend apps: ${backendApps.map(([name]) => name).join(", ") || "none"}`);
3018
+ logger$8.log(` Frontend apps: ${frontendApps.map(([name]) => name).join(", ") || "none"}`);
3019
+ if (options.production) logger$8.log(` 🏭 Production mode enabled`);
2897
3020
  const buildOrder = require_workspace.getAppBuildOrder(workspace);
2898
- logger$9.log(` Build order: ${buildOrder.join(" → ")}`);
3021
+ logger$8.log(` Build order: ${buildOrder.join(" → ")}`);
2899
3022
  const pm = detectPackageManager$2();
2900
- logger$9.log(`\n📦 Using ${pm} with Turbo for parallel builds...\n`);
3023
+ logger$8.log(`\n📦 Using ${pm} with Turbo for parallel builds...\n`);
2901
3024
  try {
2902
3025
  const { filters, unpackaged } = turboFilters(workspace);
2903
3026
  if (unpackaged.length > 0) throw new Error(`No package.json for workspace app(s): ${unpackaged.join(", ")}. Each app needs one — turbo builds packages, and gkm reads the name back to know which app it is building.`);
2904
3027
  const turboCommand = getTurboCommand(pm, filters);
2905
- logger$9.log(`Running: ${turboCommand}`);
3028
+ logger$8.log(`Running: ${turboCommand}`);
2906
3029
  await new Promise((resolve, reject) => {
2907
3030
  const child = (0, node_child_process.spawn)(turboCommand, {
2908
3031
  shell: true,
@@ -2930,15 +3053,15 @@ async function workspaceBuildCommand(workspace, options) {
2930
3053
  outputPath
2931
3054
  });
2932
3055
  }
2933
- logger$9.log(`\n✅ Workspace build complete!`);
2934
- logger$9.log(`\n📋 Build Summary:`);
3056
+ logger$8.log(`\n✅ Workspace build complete!`);
3057
+ logger$8.log(`\n📋 Build Summary:`);
2935
3058
  for (const result of results) {
2936
3059
  const icon = result.type === "backend" ? "⚙️" : result.type === "mobile" ? "📱" : "🌐";
2937
- logger$9.log(` ${icon} ${result.appName}: ${result.outputPath || "built"}`);
3060
+ logger$8.log(` ${icon} ${result.appName}: ${result.outputPath || "built"}`);
2938
3061
  }
2939
3062
  } catch (error) {
2940
3063
  const errorMessage = error instanceof Error ? error.message : "Build failed";
2941
- logger$9.log(`\n❌ Build failed: ${errorMessage}`);
3064
+ logger$8.log(`\n❌ Build failed: ${errorMessage}`);
2942
3065
  for (const [appName, app] of apps) results.push({
2943
3066
  appName,
2944
3067
  type: app.type,
@@ -3066,7 +3189,7 @@ const PROVISIONERS = {
3066
3189
  */
3067
3190
  database: async (declaration, context) => {
3068
3191
  if (declaration.kind !== "database") throw new WrongKind(declaration.kind);
3069
- const name = require_credentials.resourceName(declaration.id, declaration.kind, context.stage);
3192
+ const name = require_workspace$1.resourceName(declaration.id, declaration.kind, context.stage);
3070
3193
  const { postgres } = await context.api.findOrCreatePostgres(serviceName({
3071
3194
  stage: context.stage,
3072
3195
  app: context.project
@@ -3102,7 +3225,7 @@ const PROVISIONERS = {
3102
3225
  if (declaration.kind !== "database-schema") throw new WrongKind(declaration.kind);
3103
3226
  const parent = context.provisioned[declaration.of];
3104
3227
  if (!parent) throw new UnresolvedParent(declaration.id, declaration.of);
3105
- const runtime = require_credentials.resourceName(declaration.id, declaration.kind, context.stage);
3228
+ const runtime = require_workspace$1.resourceName(declaration.id, declaration.kind, context.stage);
3106
3229
  const owner = (0, _geekmidas_db_pg_roles.ownerRole)(runtime);
3107
3230
  const reads = readsFrom(context.manifest, declaration.id);
3108
3231
  const parentUrl = new URL(parent.provides[(0, _geekmidas_manifest.provideKey)(declaration.of, "url")] ?? "");
@@ -3204,7 +3327,7 @@ const PROVISIONERS = {
3204
3327
  stage: context.stage,
3205
3328
  app: context.project
3206
3329
  }, declaration.id);
3207
- const bucket = require_credentials.resourceName(declaration.id, declaration.kind, context.stage);
3330
+ const bucket = require_workspace$1.resourceName(declaration.id, declaration.kind, context.stage);
3208
3331
  const user = `${bucket}-root`;
3209
3332
  const password = derivedPassword(context, `objects:${declaration.id}`);
3210
3333
  const { compose } = await context.api.findOrCreateCompose(service, context.projectId, context.environmentId, minioCompose({
@@ -3572,10 +3695,6 @@ var UnprovisionableBucket = class extends Error {
3572
3695
  */
3573
3696
  /**
3574
3697
  * Provision everything the workspace declares, and return what it resolved.
3575
- *
3576
- * Nothing happens for a project that has not adopted the model: `usesConstructs`
3577
- * is the same hard switch reconcile reads, so an existing deploy is untouched
3578
- * until it declares something.
3579
3698
  */
3580
3699
  async function provisionDeclared(options) {
3581
3700
  const { workspace } = options;
@@ -3585,9 +3704,8 @@ async function provisionDeclared(options) {
3585
3704
  provisioned: {},
3586
3705
  clusters: {}
3587
3706
  };
3588
- if (!require_credentials.usesConstructs(workspace)) return empty;
3589
3707
  const manifest = options.manifest ?? await require_discover.discover({
3590
- patterns: require_credentials.constructGlobs(workspace),
3708
+ patterns: require_workspace$1.constructGlobs(workspace),
3591
3709
  cwd: workspace.root
3592
3710
  });
3593
3711
  if (Object.keys(manifest).length === 0) return empty;
@@ -3599,9 +3717,9 @@ async function provisionDeclared(options) {
3599
3717
  environmentId: options.environmentId,
3600
3718
  stage: options.stage,
3601
3719
  project: workspace.name,
3602
- cache: require_credentials.cacheBackendFor(require_credentials.providerOf(workspace)),
3603
- events: require_credentials.eventsBackendFor(require_credentials.providerOf(workspace)),
3604
- storage: require_credentials.storageBackendFor(require_credentials.providerOf(workspace)),
3720
+ cache: require_workspace$1.cacheBackendFor(require_workspace$1.providerOf(workspace)),
3721
+ events: require_workspace$1.eventsBackendFor(require_workspace$1.providerOf(workspace)),
3722
+ storage: require_workspace$1.storageBackendFor(require_workspace$1.providerOf(workspace)),
3605
3723
  addresses: surfaceAddresses(workspace, manifest, options.appUrls),
3606
3724
  ...options.secrets ? { secrets: options.secrets } : {},
3607
3725
  deferred: [],
@@ -3638,7 +3756,7 @@ async function provisionDeclared(options) {
3638
3756
  * run again.
3639
3757
  */
3640
3758
  async function applyDeclared(client, statements) {
3641
- return (await require_credentials.applyPostgres(client, statements)).filter((entry) => entry.created).length;
3759
+ return (await require_workspace$1.applyPostgres(client, statements)).filter((entry) => entry.created).length;
3642
3760
  }
3643
3761
  /**
3644
3762
  * The provisioning order, with queues and topics moved to the end.
@@ -3827,7 +3945,7 @@ async function createDnsProvider(options) {
3827
3945
  *
3828
3946
  * Handles automatic DNS record creation for deployed applications.
3829
3947
  */
3830
- const logger$8 = console;
3948
+ const logger$7 = console;
3831
3949
  /**
3832
3950
  * Check if DNS config is legacy format (single domain with `domain` property)
3833
3951
  */
@@ -3864,7 +3982,7 @@ function groupHostnamesByDomain(appHostnames, dnsConfig) {
3864
3982
  for (const [appName, hostname] of appHostnames) {
3865
3983
  const rootDomain = findRootDomain(hostname, dnsConfig);
3866
3984
  if (!rootDomain) {
3867
- logger$8.log(` ⚠ No DNS config found for hostname: ${hostname}`);
3985
+ logger$7.log(` ⚠ No DNS config found for hostname: ${hostname}`);
3868
3986
  continue;
3869
3987
  }
3870
3988
  if (!grouped.has(rootDomain)) grouped.set(rootDomain, /* @__PURE__ */ new Map());
@@ -3914,10 +4032,10 @@ function generateRequiredRecords(appHostnames, rootDomain, serverIp) {
3914
4032
  * Print DNS records table
3915
4033
  */
3916
4034
  function printDnsRecordsTable(records, rootDomain) {
3917
- logger$8.log(`\n 📋 DNS Records for ${rootDomain}:`);
3918
- logger$8.log(" ┌─────────────────────────────────────┬──────┬─────────────────┬────────┐");
3919
- logger$8.log(" │ Subdomain │ Type │ Value │ Status │");
3920
- logger$8.log(" ├─────────────────────────────────────┼──────┼─────────────────┼────────┤");
4035
+ logger$7.log(`\n 📋 DNS Records for ${rootDomain}:`);
4036
+ logger$7.log(" ┌─────────────────────────────────────┬──────┬─────────────────┬────────┐");
4037
+ logger$7.log(" │ Subdomain │ Type │ Value │ Status │");
4038
+ logger$7.log(" ├─────────────────────────────────────┼──────┼─────────────────┼────────┤");
3921
4039
  for (const record of records) {
3922
4040
  const subdomain = record.subdomain.padEnd(35);
3923
4041
  const type = record.type.padEnd(4);
@@ -3927,18 +4045,18 @@ function printDnsRecordsTable(records, rootDomain) {
3927
4045
  else if (record.created) status = "✓ new";
3928
4046
  else if (record.existed) status = "✓";
3929
4047
  else status = "?";
3930
- logger$8.log(` │ ${subdomain} │ ${type} │ ${value} │ ${status.padEnd(6)} │`);
4048
+ logger$7.log(` │ ${subdomain} │ ${type} │ ${value} │ ${status.padEnd(6)} │`);
3931
4049
  }
3932
- logger$8.log(" └─────────────────────────────────────┴──────┴─────────────────┴────────┘");
4050
+ logger$7.log(" └─────────────────────────────────────┴──────┴─────────────────┴────────┘");
3933
4051
  }
3934
4052
  /**
3935
4053
  * Print DNS records in a simple format for manual setup
3936
4054
  */
3937
4055
  function printDnsRecordsSimple(records, rootDomain) {
3938
- logger$8.log("\n 📋 Required DNS Records:");
3939
- logger$8.log(` Add these A records to your DNS provider (${rootDomain}):\n`);
3940
- for (const record of records) logger$8.log(` ${record.subdomain} → ${record.value} (A record)`);
3941
- logger$8.log("");
4056
+ logger$7.log("\n 📋 Required DNS Records:");
4057
+ logger$7.log(` Add these A records to your DNS provider (${rootDomain}):\n`);
4058
+ for (const record of records) logger$7.log(` ${record.subdomain} → ${record.value} (A record)`);
4059
+ logger$7.log("");
3942
4060
  }
3943
4061
  /**
3944
4062
  * Create DNS records for a single domain using its configured provider
@@ -3950,7 +4068,7 @@ async function createDnsRecordsForDomain(records, rootDomain, providerConfig) {
3950
4068
  provider = await createDnsProvider({ config: providerConfig });
3951
4069
  } catch (error) {
3952
4070
  const message = error instanceof Error ? error.message : "Unknown error";
3953
- logger$8.log(` ⚠ Failed to create DNS provider for ${rootDomain}: ${message}`);
4071
+ logger$7.log(` ⚠ Failed to create DNS provider for ${rootDomain}: ${message}`);
3954
4072
  return records.map((r) => ({
3955
4073
  ...r,
3956
4074
  error: message
@@ -4004,7 +4122,7 @@ async function createDnsRecordsForDomain(records, rootDomain, providerConfig) {
4004
4122
  }
4005
4123
  } catch (error) {
4006
4124
  const message = error instanceof Error ? error.message : "Unknown error";
4007
- logger$8.log(` ⚠ Failed to create DNS records for ${rootDomain}: ${message}`);
4125
+ logger$7.log(` ⚠ Failed to create DNS records for ${rootDomain}: ${message}`);
4008
4126
  return records.map((r) => ({
4009
4127
  hostname: r.hostname,
4010
4128
  subdomain: r.subdomain,
@@ -4031,20 +4149,20 @@ async function createDnsRecordsForDomain(records, rootDomain, providerConfig) {
4031
4149
  async function orchestrateDns(appHostnames, dnsConfig, dokployEndpoint, state) {
4032
4150
  if (!dnsConfig) return null;
4033
4151
  const normalizedConfig = normalizeDnsConfig(dnsConfig);
4034
- logger$8.log("\n🌐 Setting up DNS records...");
4152
+ logger$7.log("\n🌐 Setting up DNS records...");
4035
4153
  let serverIp;
4036
4154
  try {
4037
4155
  const endpointUrl = new URL(dokployEndpoint);
4038
4156
  serverIp = await resolveHostnameToIp(endpointUrl.hostname);
4039
- logger$8.log(` Server IP: ${serverIp} (from ${endpointUrl.hostname})`);
4157
+ logger$7.log(` Server IP: ${serverIp} (from ${endpointUrl.hostname})`);
4040
4158
  } catch (error) {
4041
4159
  const message = error instanceof Error ? error.message : "Unknown error";
4042
- logger$8.log(` ⚠ Failed to resolve server IP: ${message}`);
4160
+ logger$7.log(` ⚠ Failed to resolve server IP: ${message}`);
4043
4161
  return null;
4044
4162
  }
4045
4163
  const groupedHostnames = groupHostnamesByDomain(appHostnames, normalizedConfig);
4046
4164
  if (groupedHostnames.size === 0) {
4047
- logger$8.log(" No DNS records needed (no hostnames match configured domains)");
4165
+ logger$7.log(" No DNS records needed (no hostnames match configured domains)");
4048
4166
  return {
4049
4167
  records: [],
4050
4168
  success: true,
@@ -4056,22 +4174,22 @@ async function orchestrateDns(appHostnames, dnsConfig, dokployEndpoint, state) {
4056
4174
  for (const [rootDomain, domainHostnames] of groupedHostnames) {
4057
4175
  const providerConfig = normalizedConfig[rootDomain];
4058
4176
  if (!providerConfig) {
4059
- logger$8.log(` ⚠ No provider config for ${rootDomain}`);
4177
+ logger$7.log(` ⚠ No provider config for ${rootDomain}`);
4060
4178
  continue;
4061
4179
  }
4062
4180
  const providerName = typeof providerConfig.provider === "string" ? providerConfig.provider : "custom";
4063
4181
  const requiredRecords = generateRequiredRecords(domainHostnames, rootDomain, serverIp);
4064
4182
  if (requiredRecords.length === 0) continue;
4065
- logger$8.log(` Creating DNS records for ${rootDomain} (${providerName})...`);
4183
+ logger$7.log(` Creating DNS records for ${rootDomain} (${providerName})...`);
4066
4184
  const domainRecords = await createDnsRecordsForDomain(requiredRecords, rootDomain, providerConfig);
4067
4185
  allRecords.push(...domainRecords);
4068
4186
  const created = domainRecords.filter((r) => r.created).length;
4069
4187
  const existed = domainRecords.filter((r) => r.existed).length;
4070
4188
  const failed = domainRecords.filter((r) => r.error).length;
4071
- if (created > 0) logger$8.log(` ✓ Created ${created} DNS record(s) for ${rootDomain}`);
4072
- if (existed > 0) logger$8.log(` ✓ ${existed} record(s) already exist for ${rootDomain}`);
4189
+ if (created > 0) logger$7.log(` ✓ Created ${created} DNS record(s) for ${rootDomain}`);
4190
+ if (existed > 0) logger$7.log(` ✓ ${existed} record(s) already exist for ${rootDomain}`);
4073
4191
  if (failed > 0) {
4074
- logger$8.log(` ⚠ ${failed} record(s) failed for ${rootDomain}`);
4192
+ logger$7.log(` ⚠ ${failed} record(s) failed for ${rootDomain}`);
4075
4193
  hasFailures = true;
4076
4194
  }
4077
4195
  if (state) {
@@ -4108,10 +4226,10 @@ async function orchestrateDns(appHostnames, dnsConfig, dokployEndpoint, state) {
4108
4226
  */
4109
4227
  async function verifyDnsRecords(appHostnames, serverIp, state) {
4110
4228
  const results = [];
4111
- logger$8.log("\n🔍 Verifying DNS records...");
4229
+ logger$7.log("\n🔍 Verifying DNS records...");
4112
4230
  for (const [appName, hostname] of appHostnames) {
4113
4231
  if (isDnsVerified(state, hostname, serverIp)) {
4114
- logger$8.log(` ✓ ${hostname} (previously verified)`);
4232
+ logger$7.log(` ✓ ${hostname} (previously verified)`);
4115
4233
  results.push({
4116
4234
  hostname,
4117
4235
  appName,
@@ -4125,7 +4243,7 @@ async function verifyDnsRecords(appHostnames, serverIp, state) {
4125
4243
  const resolvedIp = await resolveHostnameToIp(hostname);
4126
4244
  if (resolvedIp === serverIp) {
4127
4245
  setDnsVerification(state, hostname, serverIp);
4128
- logger$8.log(` ✓ ${hostname} → ${resolvedIp}`);
4246
+ logger$7.log(` ✓ ${hostname} → ${resolvedIp}`);
4129
4247
  results.push({
4130
4248
  hostname,
4131
4249
  appName,
@@ -4134,7 +4252,7 @@ async function verifyDnsRecords(appHostnames, serverIp, state) {
4134
4252
  expectedIp: serverIp
4135
4253
  });
4136
4254
  } else {
4137
- logger$8.log(` ⚠ ${hostname} resolves to ${resolvedIp}, expected ${serverIp}`);
4255
+ logger$7.log(` ⚠ ${hostname} resolves to ${resolvedIp}, expected ${serverIp}`);
4138
4256
  results.push({
4139
4257
  hostname,
4140
4258
  appName,
@@ -4145,7 +4263,7 @@ async function verifyDnsRecords(appHostnames, serverIp, state) {
4145
4263
  }
4146
4264
  } catch (error) {
4147
4265
  const message = error instanceof Error ? error.message : "Unknown error";
4148
- logger$8.log(` ⚠ ${hostname} DNS not propagated (${message})`);
4266
+ logger$7.log(` ⚠ ${hostname} DNS not propagated (${message})`);
4149
4267
  results.push({
4150
4268
  hostname,
4151
4269
  appName,
@@ -4159,9 +4277,9 @@ async function verifyDnsRecords(appHostnames, serverIp, state) {
4159
4277
  const skipped = results.filter((r) => r.skipped).length;
4160
4278
  const pending = results.filter((r) => !r.verified).length;
4161
4279
  if (pending > 0) {
4162
- logger$8.log(`\n ${verified} verified, ${pending} pending propagation`);
4163
- logger$8.log(" DNS changes may take 5-30 minutes to propagate");
4164
- } else if (skipped > 0) logger$8.log(` ${verified} verified (${skipped} from cache)`);
4280
+ logger$7.log(`\n ${verified} verified, ${pending} pending propagation`);
4281
+ logger$7.log(" DNS changes may take 5-30 minutes to propagate");
4282
+ } else if (skipped > 0) logger$7.log(` ${verified} verified (${skipped} from cache)`);
4165
4283
  return results;
4166
4284
  }
4167
4285
  //#endregion
@@ -4194,43 +4312,19 @@ function resolveHost(appName, app, stage, dokployConfig, isMainFrontend) {
4194
4312
  return `${appName}.${baseDomain}`;
4195
4313
  }
4196
4314
  /**
4197
- * Which site the base domain points at.
4198
- *
4199
- * Three rules, in order, and the last one is the point:
4200
- *
4201
- * 1. **One site** — it is the root. Unambiguous, so nothing has to be said.
4202
- * 2. **Named `web`** — the convention wins, because people already rely on it.
4203
- * 3. **Declared `root: true`** — the site says so itself.
4204
- *
4205
- * Anything else throws. It used to take the *first* `type: 'web'` it iterated,
4206
- * and that object is built from the manifest, which is built in glob traversal
4207
- * order — so two sites with neither named `web` meant renaming a file could
4208
- * move the production root domain, silently. The same shape as
4209
- * `CacheIsAmbiguous`: unambiguous with one and arbitrary with two, so two is an
4210
- * error rather than a coin toss.
4315
+ * Whether this app is the site the base domain points at — see `rootSite`,
4316
+ * which the local edge asks too.
4211
4317
  *
4212
4318
  * @throws {AmbiguousRootSite} when several sites could be the root and none says it is
4213
4319
  */
4214
4320
  function isMainFrontendApp(appName, app, allApps) {
4215
4321
  if (app.type !== "web") return false;
4216
- const sites = Object.entries(allApps).filter(([, a]) => a.type === "web");
4217
- if (sites.length === 1) return true;
4218
- if (sites.filter(([name]) => name === "web").length > 0) return appName === "web";
4219
- const declared = sites.filter(([, a]) => a.root === true);
4220
- if (declared.length === 1) return declared[0][0] === appName;
4221
- throw new AmbiguousRootSite(sites.map(([name]) => name), declared.length > 1);
4222
- }
4223
- /** Several sites could hold the base domain, and none of them says it does. */
4224
- var AmbiguousRootSite = class extends Error {
4225
- sites;
4226
- tooMany;
4227
- constructor(sites, tooMany = false) {
4228
- super(tooMany ? `More than one site declares \`root: true\` — ${sites.join(", ")}. The base domain points at one of them.` : `${sites.length} sites and nothing says which holds the base domain: ${sites.join(", ")}. Name one of them \`web\`, or declare \`root: true\` on the one the base domain points at. It used to be whichever the glob reached first, which is not a thing to decide a production hostname.`);
4229
- this.sites = sites;
4230
- this.tooMany = tooMany;
4231
- this.name = "AmbiguousRootSite";
4232
- }
4233
- };
4322
+ const sites = Object.entries(allApps).filter(([, a]) => a.type === "web").map(([name, a]) => ({
4323
+ name,
4324
+ root: a.root
4325
+ }));
4326
+ return require_workspace$1.rootSite(sites) === appName;
4327
+ }
4234
4328
  /**
4235
4329
  * Get public URL arg names from app dependencies.
4236
4330
  *
@@ -5093,7 +5187,7 @@ CMD ["nginx", "-g", "daemon off;"]
5093
5187
  }
5094
5188
  //#endregion
5095
5189
  //#region src/docker/index.ts
5096
- const logger$7 = console;
5190
+ const logger$6 = console;
5097
5191
  /**
5098
5192
  * Docker command implementation
5099
5193
  * Generates Dockerfile, docker-compose.yml, and related files
@@ -5104,7 +5198,7 @@ const logger$7 = console;
5104
5198
  async function dockerCommand(options) {
5105
5199
  const loadedConfig = await require_config.loadWorkspaceConfig();
5106
5200
  if (loadedConfig.type === "workspace") {
5107
- logger$7.log("📦 Detected workspace configuration");
5201
+ logger$6.log("📦 Detected workspace configuration");
5108
5202
  return workspaceDockerCommand(loadedConfig.workspace);
5109
5203
  }
5110
5204
  const config = await require_config.loadConfig();
@@ -5124,7 +5218,7 @@ async function dockerCommand(options) {
5124
5218
  if (inMonorepo && !useSlim) {
5125
5219
  if (hasTurbo) {
5126
5220
  useTurbo = true;
5127
- logger$7.log(" Detected monorepo with turbo.json - using turbo prune");
5221
+ logger$6.log(" Detected monorepo with turbo.json - using turbo prune");
5128
5222
  } 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");
5129
5223
  }
5130
5224
  let turboPackage = options.turboPackage ?? dockerConfig.imageName;
@@ -5132,7 +5226,7 @@ async function dockerCommand(options) {
5132
5226
  const pkg = require(`${process.cwd()}/package.json`);
5133
5227
  if (pkg.name) {
5134
5228
  turboPackage = pkg.name;
5135
- logger$7.log(` Turbo package: ${turboPackage}`);
5229
+ logger$6.log(` Turbo package: ${turboPackage}`);
5136
5230
  }
5137
5231
  } catch {}
5138
5232
  const templateOptions = {
@@ -5149,16 +5243,16 @@ async function dockerCommand(options) {
5149
5243
  const dockerMode = useSlim ? "slim" : useTurbo ? "turbo" : "multi-stage";
5150
5244
  const dockerfilePath = (0, node_path.join)(dockerDir, "Dockerfile");
5151
5245
  await (0, node_fs_promises.writeFile)(dockerfilePath, dockerfile);
5152
- logger$7.log(`Generated: .gkm/docker/Dockerfile (${dockerMode}, ${packageManager})`);
5246
+ logger$6.log(`Generated: .gkm/docker/Dockerfile (${dockerMode}, ${packageManager})`);
5153
5247
  const composePath = await writeConstructsCompose(loadedConfig.workspace);
5154
5248
  const dockerignore = generateDockerignore();
5155
5249
  const dockerignorePath = (0, node_path.join)(process.cwd(), ".dockerignore");
5156
5250
  await (0, node_fs_promises.writeFile)(dockerignorePath, dockerignore);
5157
- logger$7.log("Generated: .dockerignore (project root)");
5251
+ logger$6.log("Generated: .dockerignore (project root)");
5158
5252
  const entrypoint = generateDockerEntrypoint();
5159
5253
  const entrypointPath = (0, node_path.join)(dockerDir, "docker-entrypoint.sh");
5160
5254
  await (0, node_fs_promises.writeFile)(entrypointPath, entrypoint);
5161
- logger$7.log("Generated: .gkm/docker/docker-entrypoint.sh");
5255
+ logger$6.log("Generated: .gkm/docker/docker-entrypoint.sh");
5162
5256
  const result = {
5163
5257
  dockerfile: dockerfilePath,
5164
5258
  dockerCompose: composePath,
@@ -5177,13 +5271,13 @@ async function dockerCommand(options) {
5177
5271
  function ensureLockfile(cwd) {
5178
5272
  const lockfilePath = findLockfilePath(cwd);
5179
5273
  if (!lockfilePath) {
5180
- logger$7.warn("\n⚠️ No lockfile found. Docker build may fail or use stale dependencies.");
5274
+ logger$6.warn("\n⚠️ No lockfile found. Docker build may fail or use stale dependencies.");
5181
5275
  return null;
5182
5276
  }
5183
5277
  const lockfileName = (0, node_path.basename)(lockfilePath);
5184
5278
  const localLockfile = (0, node_path.join)(cwd, lockfileName);
5185
5279
  if (lockfilePath === localLockfile) return null;
5186
- logger$7.log(` Copying ${lockfileName} from monorepo root...`);
5280
+ logger$6.log(` Copying ${lockfileName} from monorepo root...`);
5187
5281
  (0, node_fs.copyFileSync)(lockfilePath, localLockfile);
5188
5282
  return () => {
5189
5283
  try {
@@ -5199,7 +5293,7 @@ async function buildDockerImage(imageName, options) {
5199
5293
  const tag = options.tag ?? "latest";
5200
5294
  const registry = options.registry;
5201
5295
  const fullImageName = registry ? `${registry}/${imageName}:${tag}` : `${imageName}:${tag}`;
5202
- logger$7.log(`\n🐳 Building Docker image: ${fullImageName}`);
5296
+ logger$6.log(`\n🐳 Building Docker image: ${fullImageName}`);
5203
5297
  const cwd = process.cwd();
5204
5298
  const cleanup = ensureLockfile(cwd);
5205
5299
  try {
@@ -5211,7 +5305,7 @@ async function buildDockerImage(imageName, options) {
5211
5305
  DOCKER_BUILDKIT: "1"
5212
5306
  }
5213
5307
  });
5214
- logger$7.log(`✅ Docker image built: ${fullImageName}`);
5308
+ logger$6.log(`✅ Docker image built: ${fullImageName}`);
5215
5309
  } catch (error) {
5216
5310
  throw new Error(`Failed to build Docker image: ${error instanceof Error ? error.message : "Unknown error"}`);
5217
5311
  } finally {
@@ -5226,13 +5320,13 @@ async function pushDockerImage(imageName, options) {
5226
5320
  const registry = options.registry;
5227
5321
  if (!registry) throw new Error("Registry is required to push Docker image. Use --registry or configure docker.registry in gkm.config.ts");
5228
5322
  const fullImageName = `${registry}/${imageName}:${tag}`;
5229
- logger$7.log(`\n🚀 Pushing Docker image: ${fullImageName}`);
5323
+ logger$6.log(`\n🚀 Pushing Docker image: ${fullImageName}`);
5230
5324
  try {
5231
5325
  (0, node_child_process.execSync)(`docker push ${fullImageName}`, {
5232
5326
  cwd: process.cwd(),
5233
5327
  stdio: "inherit"
5234
5328
  });
5235
- logger$7.log(`✅ Docker image pushed: ${fullImageName}`);
5329
+ logger$6.log(`✅ Docker image pushed: ${fullImageName}`);
5236
5330
  } catch (error) {
5237
5331
  throw new Error(`Failed to push Docker image: ${error instanceof Error ? error.message : "Unknown error"}`);
5238
5332
  }
@@ -5257,21 +5351,21 @@ function getAppPackageName(appPath) {
5257
5351
  async function workspaceDockerCommand(workspace) {
5258
5352
  const results = [];
5259
5353
  const apps = Object.entries(workspace.apps);
5260
- logger$7.log(`\n🐳 Generating Dockerfiles for workspace: ${workspace.name}`);
5354
+ logger$6.log(`\n🐳 Generating Dockerfiles for workspace: ${workspace.name}`);
5261
5355
  const dockerDir = (0, node_path.join)(workspace.root, ".gkm", "docker");
5262
5356
  await (0, node_fs_promises.mkdir)(dockerDir, { recursive: true });
5263
5357
  const packageManager = detectPackageManager$1(workspace.root);
5264
- logger$7.log(` Package manager: ${packageManager}`);
5358
+ logger$6.log(` Package manager: ${packageManager}`);
5265
5359
  for (const [appName, app] of apps) {
5266
5360
  if (app.type === "mobile") {
5267
- logger$7.log(`\n 📱 Skipping Docker for ${appName} (mobile app — deploy via framework toolchain)`);
5361
+ logger$6.log(`\n 📱 Skipping Docker for ${appName} (mobile app — deploy via framework toolchain)`);
5268
5362
  continue;
5269
5363
  }
5270
5364
  const appPath = app.path;
5271
5365
  const turboPackage = getAppPackageName((0, node_path.join)(workspace.root, appPath)) ?? appName;
5272
5366
  const imageName = appName;
5273
5367
  const buildType = !!app.entry ? "entry" : app.type;
5274
- logger$7.log(`\n 📄 Generating Dockerfile for ${appName} (${buildType})`);
5368
+ logger$6.log(`\n 📄 Generating Dockerfile for ${appName} (${buildType})`);
5275
5369
  let dockerfile;
5276
5370
  if (app.type === "web") {
5277
5371
  const publicUrlArgs = getPublicUrlArgNames(app);
@@ -5315,7 +5409,7 @@ async function workspaceDockerCommand(workspace) {
5315
5409
  });
5316
5410
  const dockerfilePath = (0, node_path.join)(dockerDir, `Dockerfile.${appName}`);
5317
5411
  await (0, node_fs_promises.writeFile)(dockerfilePath, dockerfile);
5318
- logger$7.log(` Generated: .gkm/docker/Dockerfile.${appName}`);
5412
+ logger$6.log(` Generated: .gkm/docker/Dockerfile.${appName}`);
5319
5413
  results.push({
5320
5414
  appName,
5321
5415
  type: app.type,
@@ -5326,13 +5420,13 @@ async function workspaceDockerCommand(workspace) {
5326
5420
  const dockerignore = generateDockerignore();
5327
5421
  const dockerignorePath = (0, node_path.join)(workspace.root, ".dockerignore");
5328
5422
  await (0, node_fs_promises.writeFile)(dockerignorePath, dockerignore);
5329
- logger$7.log(`\n Generated: .dockerignore (workspace root)`);
5423
+ logger$6.log(`\n Generated: .dockerignore (workspace root)`);
5330
5424
  const composePath = await writeConstructsCompose(workspace);
5331
- logger$7.log(`\n✅ Generated ${results.length} Dockerfile(s) + ${require_credentials.COMPOSE_PATH}`);
5332
- logger$7.log("\n📋 Build commands:");
5425
+ logger$6.log(`\n✅ Generated ${results.length} Dockerfile(s) + ${require_workspace$1.COMPOSE_PATH}`);
5426
+ logger$6.log("\n📋 Build commands:");
5333
5427
  for (const result of results) {
5334
5428
  const icon = result.type === "backend" ? "⚙️" : result.type === "mobile" ? "📱" : "🌐";
5335
- logger$7.log(` ${icon} docker build -f .gkm/docker/Dockerfile.${result.appName} -t ${result.imageName} .`);
5429
+ logger$6.log(` ${icon} docker build -f .gkm/docker/Dockerfile.${result.appName} -t ${result.imageName} .`);
5336
5430
  }
5337
5431
  printRunInstructions(workspace);
5338
5432
  return {
@@ -5349,22 +5443,22 @@ async function workspaceDockerCommand(workspace) {
5349
5443
  * describes and what `gkm dev` runs cannot disagree. Nothing is started.
5350
5444
  */
5351
5445
  async function writeConstructsCompose(workspace) {
5352
- await require_credentials.reconcileWorkspace(workspace, {
5446
+ await require_workspace$1.reconcileWorkspace(workspace, {
5353
5447
  stage: workspace.stages.local,
5354
5448
  start: false
5355
5449
  });
5356
- logger$7.log(` Generated: ${require_credentials.COMPOSE_PATH} (project root)`);
5357
- return (0, node_path.join)(workspace.root, require_credentials.COMPOSE_PATH);
5450
+ logger$6.log(` Generated: ${require_workspace$1.COMPOSE_PATH} (project root)`);
5451
+ return (0, node_path.join)(workspace.root, require_workspace$1.COMPOSE_PATH);
5358
5452
  }
5359
5453
  function printRunInstructions(workspace) {
5360
5454
  const project = (0, node_fs.existsSync)((0, node_path.join)(workspace.root, "docker-compose.yml")) ? " -f docker-compose.yml" : "";
5361
- logger$7.log("\n📋 Run everything (the apps sit behind the \"apps\" profile):");
5362
- logger$7.log(" gkm setup # starts the containers and creates what they hold");
5363
- logger$7.log(` docker compose -f ${require_credentials.COMPOSE_PATH}${project} --profile apps up --build`);
5455
+ logger$6.log("\n📋 Run everything (the apps sit behind the \"apps\" profile):");
5456
+ logger$6.log(" gkm setup # starts the containers and creates what they hold");
5457
+ logger$6.log(` docker compose -f ${require_workspace$1.COMPOSE_PATH}${project} --profile apps up --build`);
5364
5458
  }
5365
5459
  //#endregion
5366
5460
  //#region src/deploy/docker.ts
5367
- const logger$6 = console;
5461
+ const logger$5 = console;
5368
5462
  /**
5369
5463
  * Get the full image reference
5370
5464
  */
@@ -5379,9 +5473,9 @@ function getImageRef(registry, imageName, tag) {
5379
5473
  * @param buildArgs - Build arguments to pass to docker build
5380
5474
  */
5381
5475
  async function buildImage(imageRef, _appName, buildArgs) {
5382
- logger$6.log(`\n🔨 Building Docker image: ${imageRef}`);
5476
+ logger$5.log(`\n🔨 Building Docker image: ${imageRef}`);
5383
5477
  const cwd = process.cwd();
5384
- logger$6.log(" Generating Dockerfile for the pre-built bundle...");
5478
+ logger$5.log(" Generating Dockerfile for the pre-built bundle...");
5385
5479
  await dockerCommand({ slim: true });
5386
5480
  const dockerfilePath = (0, node_path.join)(cwd, ".gkm", "docker", "Dockerfile");
5387
5481
  const buildCwd = cwd;
@@ -5403,7 +5497,7 @@ async function buildImage(imageRef, _appName, buildArgs) {
5403
5497
  DOCKER_BUILDKIT: "1"
5404
5498
  }
5405
5499
  });
5406
- logger$6.log(`✅ Image built: ${imageRef}`);
5500
+ logger$5.log(`✅ Image built: ${imageRef}`);
5407
5501
  } catch (error) {
5408
5502
  throw new Error(`Failed to build Docker image: ${error instanceof Error ? error.message : "Unknown error"}`);
5409
5503
  }
@@ -5412,13 +5506,13 @@ async function buildImage(imageRef, _appName, buildArgs) {
5412
5506
  * Push Docker image to registry
5413
5507
  */
5414
5508
  async function pushImage(imageRef) {
5415
- logger$6.log(`\n☁️ Pushing image: ${imageRef}`);
5509
+ logger$5.log(`\n☁️ Pushing image: ${imageRef}`);
5416
5510
  try {
5417
5511
  (0, node_child_process.execSync)(`docker push ${imageRef}`, {
5418
5512
  cwd: process.cwd(),
5419
5513
  stdio: "inherit"
5420
5514
  });
5421
- logger$6.log(`✅ Image pushed: ${imageRef}`);
5515
+ logger$5.log(`✅ Image pushed: ${imageRef}`);
5422
5516
  } catch (error) {
5423
5517
  throw new Error(`Failed to push Docker image: ${error instanceof Error ? error.message : "Unknown error"}`);
5424
5518
  }
@@ -5432,18 +5526,18 @@ async function deployDocker(options) {
5432
5526
  const imageRef = getImageRef(config.registry, imageName, tag);
5433
5527
  await buildImage(imageRef, config.appName, buildArgs);
5434
5528
  if (!skipPush) {
5435
- if (!config.registry) logger$6.warn("\n⚠️ No registry configured. Use --skip-push or configure docker.registry in gkm.config.ts");
5529
+ if (!config.registry) logger$5.warn("\n⚠️ No registry configured. Use --skip-push or configure docker.registry in gkm.config.ts");
5436
5530
  else await pushImage(imageRef);
5437
5531
  }
5438
- logger$6.log("\n✅ Docker deployment ready!");
5439
- logger$6.log(`\n📋 Deployment details:`);
5440
- logger$6.log(` Image: ${imageRef}`);
5441
- logger$6.log(` Stage: ${stage}`);
5532
+ logger$5.log("\n✅ Docker deployment ready!");
5533
+ logger$5.log(`\n📋 Deployment details:`);
5534
+ logger$5.log(` Image: ${imageRef}`);
5535
+ logger$5.log(` Stage: ${stage}`);
5442
5536
  if (masterKey) {
5443
- logger$6.log(`\n🔐 Deploy with this environment variable:`);
5444
- logger$6.log(` GKM_MASTER_KEY=${masterKey}`);
5445
- logger$6.log("\n Example docker run:");
5446
- logger$6.log(` docker run -e GKM_MASTER_KEY=${masterKey} ${imageRef}`);
5537
+ logger$5.log(`\n🔐 Deploy with this environment variable:`);
5538
+ logger$5.log(` GKM_MASTER_KEY=${masterKey}`);
5539
+ logger$5.log("\n Example docker run:");
5540
+ logger$5.log(` docker run -e GKM_MASTER_KEY=${masterKey} ${imageRef}`);
5447
5541
  }
5448
5542
  return {
5449
5543
  imageRef,
@@ -6822,7 +6916,7 @@ async function sniffAllApps(apps, workspacePath, options = {}) {
6822
6916
  *
6823
6917
  * @module deploy
6824
6918
  */
6825
- const logger$5 = console;
6919
+ const logger$4 = console;
6826
6920
  /**
6827
6921
  * Prompt for input
6828
6922
  */
@@ -6896,7 +6990,7 @@ async function waitForPostgres(host, port, user, password, database, maxRetries
6896
6990
  return;
6897
6991
  } catch {
6898
6992
  if (i < maxRetries - 1) {
6899
- logger$5.log(` Waiting for Postgres... (${i + 1}/${maxRetries})`);
6993
+ logger$4.log(` Waiting for Postgres... (${i + 1}/${maxRetries})`);
6900
6994
  await new Promise((r) => setTimeout(r, retryIntervalMs));
6901
6995
  }
6902
6996
  }
@@ -6939,10 +7033,10 @@ async function applyDeclaredStatements(api, postgres, serverHostname, statements
6939
7033
  break;
6940
7034
  } catch (error) {
6941
7035
  if (!(error instanceof Error ? error.message : String(error)).includes("already in use")) throw error;
6942
- logger$5.log(` Port ${candidate} is taken; trying another...`);
7036
+ logger$4.log(` Port ${candidate} is taken; trying another...`);
6943
7037
  }
6944
7038
  if (externalPort === void 0) throw new Error(`Could not publish a port for ${postgres.appName}. In use on this server: ${[...taken].sort((a, b) => a - b).join(", ") || "none reported"}. The role DDL needs to reach the cluster from here.`);
6945
- logger$5.log(` Publishing ${postgres.appName} on ${externalPort}...`);
7039
+ logger$4.log(` Publishing ${postgres.appName} on ${externalPort}...`);
6946
7040
  }
6947
7041
  await api.deployPostgres(postgres.postgresId);
6948
7042
  await waitForPostgres(serverHostname, externalPort, postgres.databaseUser, postgres.databasePassword, postgres.databaseName);
@@ -6966,7 +7060,7 @@ async function applyDeclaredStatements(api, postgres, serverHostname, statements
6966
7060
  const unpublish = async () => {
6967
7061
  if (!opened) return;
6968
7062
  await api.savePostgresExternalPort(postgres.postgresId, null).then(() => api.deployPostgres(postgres.postgresId)).catch(() => {
6969
- logger$5.log(` ⚠ Could not close external port ${externalPort} on ${postgres.appName} — close it in Dokploy.`);
7063
+ logger$4.log(` ⚠ Could not close external port ${externalPort} on ${postgres.appName} — close it in Dokploy.`);
6970
7064
  });
6971
7065
  };
6972
7066
  let lastError;
@@ -6977,7 +7071,7 @@ async function applyDeclaredStatements(api, postgres, serverHostname, statements
6977
7071
  lastError = error;
6978
7072
  if (attempt === 3) break;
6979
7073
  const message = error instanceof Error ? error.message : String(error);
6980
- logger$5.log(` ⏳ Cluster still settling (${message}); retrying (${attempt}/2)...`);
7074
+ logger$4.log(` ⏳ Cluster still settling (${message}); retrying (${attempt}/2)...`);
6981
7075
  await new Promise((resolve) => setTimeout(resolve, 1e4));
6982
7076
  await waitForPostgres(serverHostname, externalPort, postgres.databaseUser, postgres.databasePassword, postgres.databaseName).catch(() => {});
6983
7077
  }
@@ -7043,7 +7137,7 @@ function requiredOf(requirements) {
7043
7137
  async function workspaceDeployCommand(configured, options) {
7044
7138
  const { provider, stage, tag, apps: selectedApps } = options;
7045
7139
  const manifest = await require_discover.discover({
7046
- patterns: require_credentials.constructGlobs(configured),
7140
+ patterns: require_workspace$1.constructGlobs(configured),
7047
7141
  cwd: configured.root
7048
7142
  });
7049
7143
  const units = deployUnits(manifest, configured);
@@ -7052,91 +7146,91 @@ async function workspaceDeployCommand(configured, options) {
7052
7146
  apps: units
7053
7147
  } : configured;
7054
7148
  if (provider !== "dokploy") throw new Error(`Workspace deployment only supports Dokploy. Got: ${provider}`);
7055
- logger$5.log(`\n🚀 Deploying workspace "${workspace.name}" to Dokploy...`);
7056
- logger$5.log(` Stage: ${stage}`);
7149
+ logger$4.log(`\n🚀 Deploying workspace "${workspace.name}" to Dokploy...`);
7150
+ logger$4.log(` Stage: ${stage}`);
7057
7151
  const imageTag = tag ?? generateTag(stage);
7058
- logger$5.log(` Tag: ${imageTag}`);
7152
+ logger$4.log(` Tag: ${imageTag}`);
7059
7153
  const buildOrder = require_workspace.getAppBuildOrder(workspace);
7060
7154
  let appsToDeployNames = buildOrder;
7061
7155
  if (selectedApps && selectedApps.length > 0) {
7062
7156
  const invalidApps = selectedApps.filter((name) => !workspace.apps[name]);
7063
7157
  if (invalidApps.length > 0) throw new Error(`Unknown apps: ${invalidApps.join(", ")}\nAvailable apps: ${Object.keys(workspace.apps).join(", ")}`);
7064
7158
  appsToDeployNames = buildOrder.filter((name) => selectedApps.includes(name));
7065
- logger$5.log(` Deploying apps: ${appsToDeployNames.join(", ")}`);
7066
- } else logger$5.log(` Deploying all apps: ${appsToDeployNames.join(", ")}`);
7159
+ logger$4.log(` Deploying apps: ${appsToDeployNames.join(", ")}`);
7160
+ } else logger$4.log(` Deploying all apps: ${appsToDeployNames.join(", ")}`);
7067
7161
  const dokployApps = appsToDeployNames.filter((name) => {
7068
7162
  const target = workspace.apps[name].resolvedDeployTarget;
7069
7163
  if (!require_workspace.isDeployTargetSupported(target)) {
7070
- logger$5.log(` ⚠️ Skipping ${name}: ${require_workspace.getDeployTargetError(target, name)}`);
7164
+ logger$4.log(` ⚠️ Skipping ${name}: ${require_workspace.getDeployTargetError(target, name)}`);
7071
7165
  return false;
7072
7166
  }
7073
7167
  return true;
7074
7168
  });
7075
7169
  if (dokployApps.length === 0) throw new Error("No apps to deploy. All selected apps have unsupported deploy targets.");
7076
7170
  appsToDeployNames = dokployApps;
7077
- logger$5.log("\n🔐 Loading secrets and analyzing environment requirements...");
7171
+ logger$4.log("\n🔐 Loading secrets and analyzing environment requirements...");
7078
7172
  const stageSecrets = await require_storage.readStageSecrets(stage, workspace.root);
7079
7173
  if (!stageSecrets) {
7080
- logger$5.log(` ⚠️ No secrets found for stage "${stage}"`);
7081
- logger$5.log(` Run "gkm secrets:init --stage ${stage}" to create secrets`);
7174
+ logger$4.log(` ⚠️ No secrets found for stage "${stage}"`);
7175
+ logger$4.log(` Run "gkm secrets:init --stage ${stage}" to create secrets`);
7082
7176
  }
7083
7177
  const sniffedApps = await sniffAllApps(workspace.apps, workspace.root);
7084
7178
  const encryptedSecrets = stageSecrets ? prepareSecretsForAllApps(stageSecrets, sniffedApps) : /* @__PURE__ */ new Map();
7085
7179
  if (stageSecrets) {
7086
7180
  const report = generateSecretsReport(encryptedSecrets, sniffedApps);
7087
- if (report.appsWithSecrets.length > 0) logger$5.log(` ✓ Encrypted secrets for: ${report.appsWithSecrets.join(", ")}`);
7088
- if (report.appsWithMissingSecrets.length > 0) for (const { appName, missing } of report.appsWithMissingSecrets) logger$5.log(` ⚠️ ${appName}: Missing secrets: ${missing.join(", ")}`);
7181
+ if (report.appsWithSecrets.length > 0) logger$4.log(` ✓ Encrypted secrets for: ${report.appsWithSecrets.join(", ")}`);
7182
+ if (report.appsWithMissingSecrets.length > 0) for (const { appName, missing } of report.appsWithMissingSecrets) logger$4.log(` ⚠️ ${appName}: Missing secrets: ${missing.join(", ")}`);
7089
7183
  }
7090
7184
  let creds = await getDokployCredentials();
7091
7185
  if (!creds) {
7092
- logger$5.log("\n📋 Dokploy credentials not found. Let's set them up.");
7186
+ logger$4.log("\n📋 Dokploy credentials not found. Let's set them up.");
7093
7187
  const normalizedEndpoint = (await prompt("Dokploy URL (e.g., https://dokploy.example.com): ")).replace(/\/$/, "");
7094
7188
  try {
7095
7189
  new URL(normalizedEndpoint);
7096
7190
  } catch {
7097
7191
  throw new Error("Invalid URL format");
7098
7192
  }
7099
- logger$5.log(`\nGenerate a token at: ${normalizedEndpoint}/settings/profile\n`);
7193
+ logger$4.log(`\nGenerate a token at: ${normalizedEndpoint}/settings/profile\n`);
7100
7194
  const token = await prompt("API Token: ", true);
7101
- logger$5.log("\nValidating credentials...");
7195
+ logger$4.log("\nValidating credentials...");
7102
7196
  if (!await validateDokployToken(normalizedEndpoint, token)) throw new Error("Invalid credentials. Please check your token.");
7103
7197
  await storeDokployCredentials(token, normalizedEndpoint);
7104
7198
  creds = {
7105
7199
  token,
7106
7200
  endpoint: normalizedEndpoint
7107
7201
  };
7108
- logger$5.log("✓ Credentials saved");
7202
+ logger$4.log("✓ Credentials saved");
7109
7203
  }
7110
7204
  const api = new DokployApi({
7111
7205
  baseUrl: creds.endpoint,
7112
7206
  token: creds.token
7113
7207
  });
7114
- logger$5.log("\n📁 Setting up Dokploy project...");
7208
+ logger$4.log("\n📁 Setting up Dokploy project...");
7115
7209
  const projectName = workspace.name;
7116
7210
  let project = (await api.listProjects()).find((p) => p.name.toLowerCase() === projectName.toLowerCase());
7117
7211
  let environmentId;
7118
7212
  if (project) {
7119
- logger$5.log(` Found existing project: ${project.name}`);
7213
+ logger$4.log(` Found existing project: ${project.name}`);
7120
7214
  const matchingEnv = ((await api.getProject(project.projectId)).environments ?? []).find((e) => e.name.toLowerCase() === stage.toLowerCase());
7121
7215
  if (matchingEnv) {
7122
7216
  environmentId = matchingEnv.environmentId;
7123
- logger$5.log(` Using environment: ${matchingEnv.name}`);
7217
+ logger$4.log(` Using environment: ${matchingEnv.name}`);
7124
7218
  } else {
7125
- logger$5.log(` Creating "${stage}" environment...`);
7219
+ logger$4.log(` Creating "${stage}" environment...`);
7126
7220
  environmentId = (await api.createEnvironment(project.projectId, stage)).environmentId;
7127
- logger$5.log(` ✓ Created environment: ${stage}`);
7221
+ logger$4.log(` ✓ Created environment: ${stage}`);
7128
7222
  }
7129
7223
  } else {
7130
- logger$5.log(` Creating project: ${projectName}`);
7224
+ logger$4.log(` Creating project: ${projectName}`);
7131
7225
  const result = await api.createProject(projectName);
7132
7226
  project = result.project;
7133
7227
  if (result.environment.name.toLowerCase() !== stage.toLowerCase()) {
7134
- logger$5.log(` Creating "${stage}" environment...`);
7228
+ logger$4.log(` Creating "${stage}" environment...`);
7135
7229
  environmentId = (await api.createEnvironment(project.projectId, stage)).environmentId;
7136
7230
  } else environmentId = result.environment.environmentId;
7137
- logger$5.log(` ✓ Created project: ${project.projectId}`);
7231
+ logger$4.log(` ✓ Created project: ${project.projectId}`);
7138
7232
  }
7139
- logger$5.log("\n📋 Loading deploy state...");
7233
+ logger$4.log("\n📋 Loading deploy state...");
7140
7234
  const stateProvider = await createStateProvider({
7141
7235
  config: workspace.state,
7142
7236
  workspaceRoot: workspace.root,
@@ -7144,27 +7238,27 @@ async function workspaceDeployCommand(configured, options) {
7144
7238
  });
7145
7239
  let state = await stateProvider.read(stage);
7146
7240
  if (state) {
7147
- logger$5.log(` Found existing state for stage "${stage}"`);
7241
+ logger$4.log(` Found existing state for stage "${stage}"`);
7148
7242
  if (state.projectId !== project.projectId) {
7149
- logger$5.log(` ⚠ Project ID changed, updating state`);
7243
+ logger$4.log(` ⚠ Project ID changed, updating state`);
7150
7244
  state.projectId = project.projectId;
7151
7245
  }
7152
7246
  if (state.environmentId !== environmentId) {
7153
- logger$5.log(` ⚠ Environment ID changed, updating state`);
7247
+ logger$4.log(` ⚠ Environment ID changed, updating state`);
7154
7248
  state.environmentId = environmentId;
7155
7249
  }
7156
7250
  } else {
7157
- logger$5.log(` Creating new state for stage "${stage}"`);
7251
+ logger$4.log(` Creating new state for stage "${stage}"`);
7158
7252
  state = createEmptyState(stage, project.projectId, environmentId);
7159
7253
  }
7160
- logger$5.log("\n🐳 Checking registry...");
7254
+ logger$4.log("\n🐳 Checking registry...");
7161
7255
  let registryId = await getDokployRegistryId();
7162
7256
  const registry = workspace.deploy.dokploy?.registry;
7163
7257
  if (registryId) try {
7164
7258
  const reg = await api.getRegistry(registryId);
7165
- logger$5.log(` Using registry: ${reg.registryName}`);
7259
+ logger$4.log(` Using registry: ${reg.registryName}`);
7166
7260
  } catch {
7167
- logger$5.log(" ⚠ Stored registry not found, clearing...");
7261
+ logger$4.log(" ⚠ Stored registry not found, clearing...");
7168
7262
  registryId = void 0;
7169
7263
  await storeDokployRegistryId("");
7170
7264
  }
@@ -7173,26 +7267,26 @@ async function workspaceDeployCommand(configured, options) {
7173
7267
  if (registries.length > 0) {
7174
7268
  registryId = registries[0].registryId;
7175
7269
  await storeDokployRegistryId(registryId);
7176
- logger$5.log(` Using registry: ${registries[0].registryName}`);
7270
+ logger$4.log(` Using registry: ${registries[0].registryName}`);
7177
7271
  } else if (registry) {
7178
- logger$5.log(" No registries found in Dokploy. Let's create one.");
7179
- logger$5.log(` Registry URL: ${registry}`);
7272
+ logger$4.log(" No registries found in Dokploy. Let's create one.");
7273
+ logger$4.log(` Registry URL: ${registry}`);
7180
7274
  const username = await prompt("Registry username: ");
7181
7275
  const password = await prompt("Registry password/token: ", true);
7182
7276
  registryId = (await api.createRegistry("Default Registry", registry, username, password)).registryId;
7183
7277
  await storeDokployRegistryId(registryId);
7184
- logger$5.log(` ✓ Registry created: ${registryId}`);
7185
- } else logger$5.log(" ⚠ No registry configured. Set deploy.dokploy.registry in workspace config");
7278
+ logger$4.log(` ✓ Registry created: ${registryId}`);
7279
+ } else logger$4.log(" ⚠ No registry configured. Set deploy.dokploy.registry in workspace config");
7186
7280
  }
7187
7281
  const skippedMobileApps = appsToDeployNames.filter((name) => workspace.apps[name].type === "mobile");
7188
- if (skippedMobileApps.length > 0) logger$5.log(`\n📱 Skipping ${skippedMobileApps.length} mobile app(s) — deploy via framework toolchain: ${skippedMobileApps.join(", ")}`);
7282
+ if (skippedMobileApps.length > 0) logger$4.log(`\n📱 Skipping ${skippedMobileApps.length} mobile app(s) — deploy via framework toolchain: ${skippedMobileApps.join(", ")}`);
7189
7283
  const backendApps = appsToDeployNames.filter((name) => workspace.apps[name].type === "backend");
7190
7284
  const frontendApps = appsToDeployNames.filter((name) => workspace.apps[name].type === "web");
7191
7285
  const dokployConfig = workspace.deploy.dokploy;
7192
7286
  let declaredEnv = {};
7193
7287
  let declaredClusters = {};
7194
7288
  {
7195
- logger$5.log("\n📦 Provisioning declared constructs...");
7289
+ logger$4.log("\n📦 Provisioning declared constructs...");
7196
7290
  const appUrls = {};
7197
7291
  for (const appName of backendApps) {
7198
7292
  const app = workspace.apps[appName];
@@ -7210,20 +7304,20 @@ async function workspaceDeployCommand(configured, options) {
7210
7304
  });
7211
7305
  declaredEnv = declared.env;
7212
7306
  declaredClusters = declared.clusters;
7213
- if (Object.keys(declaredEnv).length > 0) logger$5.log(` 🔌 Resolved ${Object.keys(declaredEnv).length} declared URL(s)`);
7307
+ if (Object.keys(declaredEnv).length > 0) logger$4.log(` 🔌 Resolved ${Object.keys(declaredEnv).length} declared URL(s)`);
7214
7308
  if (declared.statements.length > 0) {
7215
7309
  const serverHostname = getServerHostname(creds.endpoint);
7216
7310
  for (const [databaseName, cluster] of Object.entries(declared.clusters)) {
7217
7311
  const statements = declared.statements.filter((statement) => statement.database === databaseName);
7218
7312
  if (statements.length === 0) continue;
7219
7313
  const created = await applyDeclaredStatements(api, cluster, serverHostname, statements);
7220
- logger$5.log(` 🗄️ ${databaseName}: applied ${statements.length} statement(s), ${created} new`);
7314
+ logger$4.log(` 🗄️ ${databaseName}: applied ${statements.length} statement(s), ${created} new`);
7221
7315
  }
7222
7316
  }
7223
7317
  }
7224
7318
  const backupCluster = Object.values(declaredClusters)[0];
7225
7319
  if (workspace.deploy?.backups && backupCluster) {
7226
- logger$5.log("\n💾 Provisioning backup destination...");
7320
+ logger$4.log("\n💾 Provisioning backup destination...");
7227
7321
  const { provisionBackupDestination } = await Promise.resolve().then(() => require("./backup-provisioner-BmhIO_Yr.cjs"));
7228
7322
  const backupState = await provisionBackupDestination({
7229
7323
  api,
@@ -7232,13 +7326,13 @@ async function workspaceDeployCommand(configured, options) {
7232
7326
  stage,
7233
7327
  config: workspace.deploy.backups,
7234
7328
  existingState: getBackupState(state),
7235
- logger: logger$5
7329
+ logger: logger$4
7236
7330
  });
7237
7331
  setBackupState(state, backupState);
7238
7332
  if (!backupState.postgresBackupId) {
7239
7333
  const backupSchedule = workspace.deploy.backups.schedule ?? "0 2 * * *";
7240
7334
  const backupRetention = workspace.deploy.backups.retention ?? 30;
7241
- logger$5.log(" Creating postgres backup schedule...");
7335
+ logger$4.log(" Creating postgres backup schedule...");
7242
7336
  const backup = await api.createPostgresBackup({
7243
7337
  schedule: backupSchedule,
7244
7338
  prefix: `${stage}/postgres`,
@@ -7249,8 +7343,8 @@ async function workspaceDeployCommand(configured, options) {
7249
7343
  keepLatestCount: backupRetention
7250
7344
  });
7251
7345
  setPostgresBackupId(state, backup.backupId);
7252
- logger$5.log(` ✓ Postgres backup schedule created (${backupSchedule})`);
7253
- } else logger$5.log(" ✓ Using existing postgres backup schedule");
7346
+ logger$4.log(` ✓ Postgres backup schedule created (${backupSchedule})`);
7347
+ } else logger$4.log(" ✓ Using existing postgres backup schedule");
7254
7348
  }
7255
7349
  const publicUrls = {};
7256
7350
  const results = [];
@@ -7263,25 +7357,25 @@ async function workspaceDeployCommand(configured, options) {
7263
7357
  frontendUrls.push(`https://${hostname}`);
7264
7358
  }
7265
7359
  if (backendApps.length > 0) {
7266
- logger$5.log("\n📦 PHASE 1: Deploying backend applications...");
7360
+ logger$4.log("\n📦 PHASE 1: Deploying backend applications...");
7267
7361
  for (const appName of backendApps) {
7268
7362
  const app = workspace.apps[appName];
7269
- logger$5.log(`\n ⚙️ Deploying ${appName}...`);
7363
+ logger$4.log(`\n ⚙️ Deploying ${appName}...`);
7270
7364
  try {
7271
7365
  const dokployAppName = applicationName(stage, workspace.name, appName);
7272
7366
  let application = null;
7273
7367
  const cachedAppId = getApplicationId(state, appName);
7274
7368
  if (cachedAppId) {
7275
- logger$5.log(` Using cached ID: ${cachedAppId}`);
7369
+ logger$4.log(` Using cached ID: ${cachedAppId}`);
7276
7370
  application = await api.getApplication(cachedAppId);
7277
- if (application) logger$5.log(` ✓ Application found: ${application.applicationId}`);
7278
- else logger$5.log(` ⚠ Cached ID invalid, will create new`);
7371
+ if (application) logger$4.log(` ✓ Application found: ${application.applicationId}`);
7372
+ else logger$4.log(` ⚠ Cached ID invalid, will create new`);
7279
7373
  }
7280
7374
  if (!application) {
7281
7375
  const result = await api.findOrCreateApplication(dokployAppName, project.projectId, environmentId);
7282
7376
  application = result.application;
7283
- if (result.created) logger$5.log(` Created application: ${application.applicationId}`);
7284
- else logger$5.log(` Found existing application: ${application.applicationId}`);
7377
+ if (result.created) logger$4.log(` Created application: ${application.applicationId}`);
7378
+ else logger$4.log(` Found existing application: ${application.applicationId}`);
7285
7379
  }
7286
7380
  setApplicationId(state, appName, application.applicationId);
7287
7381
  const appSecrets = encryptedSecrets.get(appName);
@@ -7289,11 +7383,11 @@ async function workspaceDeployCommand(configured, options) {
7289
7383
  if (appSecrets && appSecrets.secretCount > 0) {
7290
7384
  buildArgs.push(`GKM_ENCRYPTED_CREDENTIALS=${appSecrets.payload.encrypted}`);
7291
7385
  buildArgs.push(`GKM_CREDENTIALS_IV=${appSecrets.payload.iv}`);
7292
- logger$5.log(` Encrypted ${appSecrets.secretCount} secrets`);
7386
+ logger$4.log(` Encrypted ${appSecrets.secretCount} secrets`);
7293
7387
  }
7294
7388
  const imageName = `${workspace.name}-${appName}`;
7295
7389
  const imageRef = registry ? `${registry}/${imageName}:${imageTag}` : `${imageName}:${imageTag}`;
7296
- logger$5.log(` Building Docker image: ${imageRef}`);
7390
+ logger$4.log(` Building Docker image: ${imageRef}`);
7297
7391
  await deployDocker({
7298
7392
  stage,
7299
7393
  tag: imageTag,
@@ -7334,17 +7428,17 @@ async function workspaceDeployCommand(configured, options) {
7334
7428
  ...declaredEnv
7335
7429
  };
7336
7430
  const envVars = Object.entries(withDeclared).map(([key, value]) => `${key}=${value}`);
7337
- if (Object.keys(withDeclared).length > 0) logger$5.log(` Resolved ${Object.keys(withDeclared).length} env vars: ${Object.keys(withDeclared).sort().join(", ")}`);
7431
+ if (Object.keys(withDeclared).length > 0) logger$4.log(` Resolved ${Object.keys(withDeclared).length} env vars: ${Object.keys(withDeclared).sort().join(", ")}`);
7338
7432
  await api.saveDockerProvider(application.applicationId, imageRef, { registryId });
7339
7433
  await api.saveApplicationEnv(application.applicationId, envVars.join("\n"));
7340
- logger$5.log(` Deploying to Dokploy...`);
7434
+ logger$4.log(` Deploying to Dokploy...`);
7341
7435
  await api.deployApplication(application.applicationId);
7342
7436
  const existingDomain = (await api.getDomainsByApplicationId(application.applicationId)).find((d) => d.host === backendHost);
7343
7437
  if (existingDomain) {
7344
7438
  appHostnames.set(appName, backendHost);
7345
7439
  appDomainIds.set(appName, existingDomain.domainId);
7346
7440
  publicUrls[appName] = `https://${backendHost}`;
7347
- logger$5.log(` ✓ Domain: https://${backendHost} (existing)`);
7441
+ logger$4.log(` ✓ Domain: https://${backendHost} (existing)`);
7348
7442
  } else try {
7349
7443
  const domain = await api.createDomain({
7350
7444
  host: backendHost,
@@ -7356,10 +7450,10 @@ async function workspaceDeployCommand(configured, options) {
7356
7450
  appHostnames.set(appName, backendHost);
7357
7451
  appDomainIds.set(appName, domain.domainId);
7358
7452
  publicUrls[appName] = `https://${backendHost}`;
7359
- logger$5.log(` ✓ Domain: https://${backendHost} (created)`);
7453
+ logger$4.log(` ✓ Domain: https://${backendHost} (created)`);
7360
7454
  } catch (domainError) {
7361
7455
  const message = domainError instanceof Error ? domainError.message : "Unknown error";
7362
- logger$5.log(` ⚠ Domain creation failed: ${message}`);
7456
+ logger$4.log(` ⚠ Domain creation failed: ${message}`);
7363
7457
  appHostnames.set(appName, backendHost);
7364
7458
  publicUrls[appName] = `https://${backendHost}`;
7365
7459
  }
@@ -7370,10 +7464,10 @@ async function workspaceDeployCommand(configured, options) {
7370
7464
  applicationId: application.applicationId,
7371
7465
  imageRef
7372
7466
  });
7373
- logger$5.log(` ✓ ${appName} deployed successfully`);
7467
+ logger$4.log(` ✓ ${appName} deployed successfully`);
7374
7468
  } catch (error) {
7375
7469
  const message = error instanceof Error ? error.message : "Unknown error";
7376
- logger$5.log(` ✗ Failed to deploy ${appName}: ${message}`);
7470
+ logger$4.log(` ✗ Failed to deploy ${appName}: ${message}`);
7377
7471
  results.push({
7378
7472
  appName,
7379
7473
  type: app.type,
@@ -7385,25 +7479,25 @@ async function workspaceDeployCommand(configured, options) {
7385
7479
  }
7386
7480
  }
7387
7481
  if (frontendApps.length > 0) {
7388
- logger$5.log("\n🌐 PHASE 2: Deploying frontend applications...");
7482
+ logger$4.log("\n🌐 PHASE 2: Deploying frontend applications...");
7389
7483
  for (const appName of frontendApps) {
7390
7484
  const app = workspace.apps[appName];
7391
- logger$5.log(`\n 🌐 Deploying ${appName}...`);
7485
+ logger$4.log(`\n 🌐 Deploying ${appName}...`);
7392
7486
  try {
7393
7487
  const dokployAppName = applicationName(stage, workspace.name, appName);
7394
7488
  let application = null;
7395
7489
  const cachedAppId = getApplicationId(state, appName);
7396
7490
  if (cachedAppId) {
7397
- logger$5.log(` Using cached ID: ${cachedAppId}`);
7491
+ logger$4.log(` Using cached ID: ${cachedAppId}`);
7398
7492
  application = await api.getApplication(cachedAppId);
7399
- if (application) logger$5.log(` ✓ Application found: ${application.applicationId}`);
7400
- else logger$5.log(` ⚠ Cached ID invalid, will create new`);
7493
+ if (application) logger$4.log(` ✓ Application found: ${application.applicationId}`);
7494
+ else logger$4.log(` ⚠ Cached ID invalid, will create new`);
7401
7495
  }
7402
7496
  if (!application) {
7403
7497
  const result = await api.findOrCreateApplication(dokployAppName, project.projectId, environmentId);
7404
7498
  application = result.application;
7405
- if (result.created) logger$5.log(` Created application: ${application.applicationId}`);
7406
- else logger$5.log(` Found existing application: ${application.applicationId}`);
7499
+ if (result.created) logger$4.log(` Created application: ${application.applicationId}`);
7500
+ else logger$4.log(` Found existing application: ${application.applicationId}`);
7407
7501
  }
7408
7502
  setApplicationId(state, appName, application.applicationId);
7409
7503
  const dependencyUrls = {};
@@ -7423,7 +7517,7 @@ async function workspaceDeployCommand(configured, options) {
7423
7517
  };
7424
7518
  const { valid, missing, resolved } = validateEnvVars(requiredOf(sniffedApps.get(appName)), envContext);
7425
7519
  if (!valid) throw new Error(formatMissingVarsError(appName, missing, stage));
7426
- if (Object.keys(resolved).length > 0) logger$5.log(` Resolved ${Object.keys(resolved).length} env vars: ${Object.keys(resolved).join(", ")}`);
7520
+ if (Object.keys(resolved).length > 0) logger$4.log(` Resolved ${Object.keys(resolved).length} env vars: ${Object.keys(resolved).join(", ")}`);
7427
7521
  const publicPrefix = require_workspace.getPublicEnvPrefix(app.framework);
7428
7522
  const buildArgs = [];
7429
7523
  const publicUrlArgNames = [];
@@ -7433,10 +7527,10 @@ async function workspaceDeployCommand(configured, options) {
7433
7527
  publicUrlArgNames.push(key);
7434
7528
  }
7435
7529
  }
7436
- if (buildArgs.length > 0) logger$5.log(` Build args: ${publicUrlArgNames.join(", ")}`);
7530
+ if (buildArgs.length > 0) logger$4.log(` Build args: ${publicUrlArgNames.join(", ")}`);
7437
7531
  const imageName = `${workspace.name}-${appName}`;
7438
7532
  const imageRef = registry ? `${registry}/${imageName}:${imageTag}` : `${imageName}:${imageTag}`;
7439
- logger$5.log(` Building Docker image: ${imageRef}`);
7533
+ logger$4.log(` Building Docker image: ${imageRef}`);
7440
7534
  await deployDocker({
7441
7535
  stage,
7442
7536
  tag: imageTag,
@@ -7457,14 +7551,14 @@ async function workspaceDeployCommand(configured, options) {
7457
7551
  for (const [key, value] of Object.entries(resolved)) envVars.push(`${key}=${value}`);
7458
7552
  await api.saveDockerProvider(application.applicationId, imageRef, { registryId });
7459
7553
  await api.saveApplicationEnv(application.applicationId, envVars.join("\n"));
7460
- logger$5.log(` Deploying to Dokploy...`);
7554
+ logger$4.log(` Deploying to Dokploy...`);
7461
7555
  await api.deployApplication(application.applicationId);
7462
7556
  const existingFrontendDomain = (await api.getDomainsByApplicationId(application.applicationId)).find((d) => d.host === frontendHost);
7463
7557
  if (existingFrontendDomain) {
7464
7558
  appHostnames.set(appName, frontendHost);
7465
7559
  appDomainIds.set(appName, existingFrontendDomain.domainId);
7466
7560
  publicUrls[appName] = `https://${frontendHost}`;
7467
- logger$5.log(` ✓ Domain: https://${frontendHost} (existing)`);
7561
+ logger$4.log(` ✓ Domain: https://${frontendHost} (existing)`);
7468
7562
  } else try {
7469
7563
  const domain = await api.createDomain({
7470
7564
  host: frontendHost,
@@ -7476,10 +7570,10 @@ async function workspaceDeployCommand(configured, options) {
7476
7570
  appHostnames.set(appName, frontendHost);
7477
7571
  appDomainIds.set(appName, domain.domainId);
7478
7572
  publicUrls[appName] = `https://${frontendHost}`;
7479
- logger$5.log(` ✓ Domain: https://${frontendHost} (created)`);
7573
+ logger$4.log(` ✓ Domain: https://${frontendHost} (created)`);
7480
7574
  } catch (domainError) {
7481
7575
  const message = domainError instanceof Error ? domainError.message : "Unknown error";
7482
- logger$5.log(` ⚠ Domain creation failed: ${message}`);
7576
+ logger$4.log(` ⚠ Domain creation failed: ${message}`);
7483
7577
  appHostnames.set(appName, frontendHost);
7484
7578
  publicUrls[appName] = `https://${frontendHost}`;
7485
7579
  }
@@ -7490,10 +7584,10 @@ async function workspaceDeployCommand(configured, options) {
7490
7584
  applicationId: application.applicationId,
7491
7585
  imageRef
7492
7586
  });
7493
- logger$5.log(` ✓ ${appName} deployed successfully`);
7587
+ logger$4.log(` ✓ ${appName} deployed successfully`);
7494
7588
  } catch (error) {
7495
7589
  const message = error instanceof Error ? error.message : "Unknown error";
7496
- logger$5.log(` ✗ Failed to deploy ${appName}: ${message}`);
7590
+ logger$4.log(` ✗ Failed to deploy ${appName}: ${message}`);
7497
7591
  results.push({
7498
7592
  appName,
7499
7593
  type: app.type,
@@ -7503,9 +7597,9 @@ async function workspaceDeployCommand(configured, options) {
7503
7597
  }
7504
7598
  }
7505
7599
  }
7506
- logger$5.log("\n📋 Saving deploy state...");
7600
+ logger$4.log("\n📋 Saving deploy state...");
7507
7601
  await stateProvider.write(stage, state);
7508
- logger$5.log(" ✓ State saved");
7602
+ logger$4.log(" ✓ State saved");
7509
7603
  const dnsConfig = workspace.deploy.dns;
7510
7604
  if (dnsConfig && appHostnames.size > 0) {
7511
7605
  const dnsResult = await orchestrateDns(appHostnames, dnsConfig, creds.endpoint);
@@ -7514,27 +7608,27 @@ async function workspaceDeployCommand(configured, options) {
7514
7608
  await stateProvider.write(stage, state);
7515
7609
  }
7516
7610
  if (dnsResult?.success && appHostnames.size > 0) {
7517
- logger$5.log("\n🔒 Validating domains for SSL certificates...");
7611
+ logger$4.log("\n🔒 Validating domains for SSL certificates...");
7518
7612
  for (const [appName, hostname] of appHostnames) try {
7519
7613
  const result = await api.validateDomain(hostname);
7520
- if (result.isValid) logger$5.log(` ✓ ${appName}: ${hostname} → ${result.resolvedIp}`);
7521
- else logger$5.log(` ⚠ ${appName}: ${hostname} not valid`);
7614
+ if (result.isValid) logger$4.log(` ✓ ${appName}: ${hostname} → ${result.resolvedIp}`);
7615
+ else logger$4.log(` ⚠ ${appName}: ${hostname} not valid`);
7522
7616
  } catch (validationError) {
7523
7617
  const message = validationError instanceof Error ? validationError.message : "Unknown error";
7524
- logger$5.log(` ⚠ ${appName}: validation failed - ${message}`);
7618
+ logger$4.log(` ⚠ ${appName}: validation failed - ${message}`);
7525
7619
  }
7526
7620
  }
7527
7621
  }
7528
7622
  const successCount = results.filter((r) => r.success).length;
7529
7623
  const failedCount = results.filter((r) => !r.success).length;
7530
- logger$5.log(`\n${"─".repeat(50)}`);
7531
- logger$5.log(`\n✅ Workspace deployment complete!`);
7532
- logger$5.log(` Project: ${project.projectId}`);
7533
- logger$5.log(` Successful: ${successCount}`);
7534
- if (failedCount > 0) logger$5.log(` Failed: ${failedCount}`);
7624
+ logger$4.log(`\n${"─".repeat(50)}`);
7625
+ logger$4.log(`\n✅ Workspace deployment complete!`);
7626
+ logger$4.log(` Project: ${project.projectId}`);
7627
+ logger$4.log(` Successful: ${successCount}`);
7628
+ if (failedCount > 0) logger$4.log(` Failed: ${failedCount}`);
7535
7629
  if (Object.keys(publicUrls).length > 0) {
7536
- logger$5.log("\n 📡 Deployed URLs:");
7537
- for (const [name, url] of Object.entries(publicUrls)) logger$5.log(` ${name}: ${url}`);
7630
+ logger$4.log("\n 📡 Deployed URLs:");
7631
+ for (const [name, url] of Object.entries(publicUrls)) logger$4.log(` ${name}: ${url}`);
7538
7632
  }
7539
7633
  return {
7540
7634
  apps: results,
@@ -7553,7 +7647,7 @@ async function deployCommand(options) {
7553
7647
  }
7554
7648
  //#endregion
7555
7649
  //#region src/deploy/init.ts
7556
- const logger$4 = console;
7650
+ const logger$3 = console;
7557
7651
  /**
7558
7652
  * Get the Dokploy API token from stored credentials or environment
7559
7653
  */
@@ -7599,28 +7693,28 @@ function unsafeToRewrite(content) {
7599
7693
  async function updateConfig(config, cwd = process.cwd()) {
7600
7694
  const configPath = (0, node_path.join)(cwd, "gkm.config.ts");
7601
7695
  if (!(0, node_fs.existsSync)(configPath)) {
7602
- logger$4.warn("\n gkm.config.ts not found. Add this configuration manually:\n");
7603
- logger$4.log(` providers: {`);
7604
- logger$4.log(` dokploy: {`);
7605
- logger$4.log(` endpoint: '${config.endpoint}',`);
7606
- logger$4.log(` projectId: '${config.projectId}',`);
7607
- logger$4.log(` applicationId: '${config.applicationId}',`);
7608
- logger$4.log(` },`);
7609
- logger$4.log(` },`);
7696
+ logger$3.warn("\n gkm.config.ts not found. Add this configuration manually:\n");
7697
+ logger$3.log(` providers: {`);
7698
+ logger$3.log(` dokploy: {`);
7699
+ logger$3.log(` endpoint: '${config.endpoint}',`);
7700
+ logger$3.log(` projectId: '${config.projectId}',`);
7701
+ logger$3.log(` applicationId: '${config.applicationId}',`);
7702
+ logger$3.log(` },`);
7703
+ logger$3.log(` },`);
7610
7704
  return;
7611
7705
  }
7612
7706
  const content = await (0, node_fs_promises.readFile)(configPath, "utf-8");
7613
7707
  if (unsafeToRewrite(content)) {
7614
- logger$4.warn("\n gkm.config.ts holds a dokploy block this cannot safely rewrite —\n it contains an expression or a nested object. Leaving it alone.");
7615
- logger$4.log(`\n Discovered, if you want them written down:`);
7616
- logger$4.log(` projectId: '${config.projectId}'`);
7617
- logger$4.log(` applicationId: '${config.applicationId}'`);
7618
- if (config.registryId) logger$4.log(` registryId: '${config.registryId}'`);
7708
+ logger$3.warn("\n gkm.config.ts holds a dokploy block this cannot safely rewrite —\n it contains an expression or a nested object. Leaving it alone.");
7709
+ logger$3.log(`\n Discovered, if you want them written down:`);
7710
+ logger$3.log(` projectId: '${config.projectId}'`);
7711
+ logger$3.log(` applicationId: '${config.applicationId}'`);
7712
+ if (config.registryId) logger$3.log(` registryId: '${config.registryId}'`);
7619
7713
  return;
7620
7714
  }
7621
7715
  if (content.includes("dokploy:") && content.includes("applicationId:")) {
7622
- logger$4.log("\n Dokploy config already exists in gkm.config.ts");
7623
- logger$4.log(" Updating with new values...");
7716
+ logger$3.log("\n Dokploy config already exists in gkm.config.ts");
7717
+ logger$3.log(" Updating with new values...");
7624
7718
  }
7625
7719
  const registryLine = config.registryId ? `\n\t\t\tregistryId: '${config.registryId}',` : "";
7626
7720
  const dokployConfigStr = `dokploy: {
@@ -7638,7 +7732,7 @@ async function updateConfig(config, cwd = process.cwd()) {
7638
7732
  },
7639
7733
  });`);
7640
7734
  await (0, node_fs_promises.writeFile)(configPath, newContent);
7641
- logger$4.log("\n ✓ Updated gkm.config.ts with Dokploy configuration");
7735
+ logger$3.log("\n ✓ Updated gkm.config.ts with Dokploy configuration");
7642
7736
  }
7643
7737
  /**
7644
7738
  * Initialize Dokploy deployment configuration
@@ -7647,22 +7741,22 @@ async function deployInitCommand(options) {
7647
7741
  const { projectName, appName, projectId: existingProjectId, registryId } = options;
7648
7742
  const endpoint = await getEndpoint(options.endpoint);
7649
7743
  const api = await createApi(endpoint);
7650
- logger$4.log(`\n🚀 Initializing Dokploy deployment...`);
7651
- logger$4.log(` Endpoint: ${endpoint}`);
7744
+ logger$3.log(`\n🚀 Initializing Dokploy deployment...`);
7745
+ logger$3.log(` Endpoint: ${endpoint}`);
7652
7746
  let projectId;
7653
7747
  if (existingProjectId) {
7654
7748
  projectId = existingProjectId;
7655
- logger$4.log(`\n📁 Using existing project: ${projectId}`);
7749
+ logger$3.log(`\n📁 Using existing project: ${projectId}`);
7656
7750
  } else {
7657
- logger$4.log(`\n📁 Looking for project: ${projectName}`);
7751
+ logger$3.log(`\n📁 Looking for project: ${projectName}`);
7658
7752
  const existingProject = (await api.listProjects()).find((p) => p.name.toLowerCase() === projectName.toLowerCase());
7659
7753
  if (existingProject) {
7660
7754
  projectId = existingProject.projectId;
7661
- logger$4.log(` Found existing project: ${projectId}`);
7755
+ logger$3.log(` Found existing project: ${projectId}`);
7662
7756
  } else {
7663
- logger$4.log(` Creating new project...`);
7757
+ logger$3.log(` Creating new project...`);
7664
7758
  projectId = (await api.createProject(projectName)).project.projectId;
7665
- logger$4.log(` ✓ Created project: ${projectId}`);
7759
+ logger$3.log(` ✓ Created project: ${projectId}`);
7666
7760
  }
7667
7761
  }
7668
7762
  const project = await api.getProject(projectId);
@@ -7670,22 +7764,22 @@ async function deployInitCommand(options) {
7670
7764
  const firstEnv = project.environments?.[0];
7671
7765
  if (firstEnv) environmentId = firstEnv.environmentId;
7672
7766
  else {
7673
- logger$4.log(` Creating production environment...`);
7767
+ logger$3.log(` Creating production environment...`);
7674
7768
  environmentId = (await api.createEnvironment(projectId, "production")).environmentId;
7675
7769
  }
7676
- logger$4.log(`\n📦 Creating application: ${appName}`);
7770
+ logger$3.log(`\n📦 Creating application: ${appName}`);
7677
7771
  const application = await api.createApplication(appName, projectId, environmentId);
7678
- logger$4.log(` ✓ Created application: ${application.applicationId}`);
7772
+ logger$3.log(` ✓ Created application: ${application.applicationId}`);
7679
7773
  if (registryId) {
7680
- logger$4.log(`\n🔧 Configuring registry: ${registryId}`);
7774
+ logger$3.log(`\n🔧 Configuring registry: ${registryId}`);
7681
7775
  await api.updateApplication(application.applicationId, { registryId });
7682
- logger$4.log(` ✓ Registry configured`);
7776
+ logger$3.log(` ✓ Registry configured`);
7683
7777
  } else try {
7684
7778
  const registries = await api.listRegistries();
7685
7779
  if (registries.length > 0) {
7686
- logger$4.log(`\n📋 Available registries:`);
7687
- for (const reg of registries) logger$4.log(` - ${reg.registryName}: ${reg.registryUrl} (${reg.registryId})`);
7688
- logger$4.log(`\n To use a registry, run with --registry-id <id>`);
7780
+ logger$3.log(`\n📋 Available registries:`);
7781
+ for (const reg of registries) logger$3.log(` - ${reg.registryName}: ${reg.registryUrl} (${reg.registryId})`);
7782
+ logger$3.log(`\n To use a registry, run with --registry-id <id>`);
7689
7783
  }
7690
7784
  } catch {}
7691
7785
  const config = {
@@ -7694,14 +7788,14 @@ async function deployInitCommand(options) {
7694
7788
  applicationId: application.applicationId
7695
7789
  };
7696
7790
  await updateConfig(config);
7697
- logger$4.log(`\n✅ Dokploy deployment initialized!`);
7698
- logger$4.log(`\n📋 Configuration:`);
7699
- logger$4.log(` Project ID: ${projectId}`);
7700
- logger$4.log(` Application ID: ${application.applicationId}`);
7701
- logger$4.log(`\n🔗 View in Dokploy: ${endpoint}/project/${projectId}`);
7702
- logger$4.log(`\n📝 Next steps:`);
7703
- logger$4.log(` 1. Initialize secrets: gkm secrets:init --stage production`);
7704
- logger$4.log(` 2. Deploy: gkm deploy --provider dokploy --stage production`);
7791
+ logger$3.log(`\n✅ Dokploy deployment initialized!`);
7792
+ logger$3.log(`\n📋 Configuration:`);
7793
+ logger$3.log(` Project ID: ${projectId}`);
7794
+ logger$3.log(` Application ID: ${application.applicationId}`);
7795
+ logger$3.log(`\n🔗 View in Dokploy: ${endpoint}/project/${projectId}`);
7796
+ logger$3.log(`\n📝 Next steps:`);
7797
+ logger$3.log(` 1. Initialize secrets: gkm secrets:init --stage production`);
7798
+ logger$3.log(` 2. Deploy: gkm deploy --provider dokploy --stage production`);
7705
7799
  return config;
7706
7800
  }
7707
7801
  /**
@@ -7712,31 +7806,31 @@ async function deployListCommand(options) {
7712
7806
  const api = await createApi(endpoint);
7713
7807
  const { resource } = options;
7714
7808
  if (resource === "projects") {
7715
- logger$4.log(`\n📁 Projects in ${endpoint}:`);
7809
+ logger$3.log(`\n📁 Projects in ${endpoint}:`);
7716
7810
  const projects = await api.listProjects();
7717
7811
  if (projects.length === 0) {
7718
- logger$4.log(" No projects found");
7812
+ logger$3.log(" No projects found");
7719
7813
  return;
7720
7814
  }
7721
7815
  for (const project of projects) {
7722
- logger$4.log(`\n ${project.name} (${project.projectId})`);
7723
- if (project.description) logger$4.log(` ${project.description}`);
7816
+ logger$3.log(`\n ${project.name} (${project.projectId})`);
7817
+ if (project.description) logger$3.log(` ${project.description}`);
7724
7818
  }
7725
7819
  } else if (resource === "registries") {
7726
- logger$4.log(`\n🐳 Registries in ${endpoint}:`);
7820
+ logger$3.log(`\n🐳 Registries in ${endpoint}:`);
7727
7821
  const registries = await api.listRegistries();
7728
7822
  if (registries.length === 0) {
7729
- logger$4.log(" No registries configured");
7730
- logger$4.log(" Run \"gkm registry:setup\" to configure a registry");
7823
+ logger$3.log(" No registries configured");
7824
+ logger$3.log(" Run \"gkm registry:setup\" to configure a registry");
7731
7825
  return;
7732
7826
  }
7733
7827
  const storedRegistryId = await getDokployRegistryId();
7734
7828
  for (const registry of registries) {
7735
7829
  const marker = registry.registryId === storedRegistryId ? " (default)" : "";
7736
- logger$4.log(`\n ${registry.registryName}${marker} (${registry.registryId})`);
7737
- logger$4.log(` URL: ${registry.registryUrl}`);
7738
- logger$4.log(` Username: ${registry.username}`);
7739
- if (registry.imagePrefix) logger$4.log(` Prefix: ${registry.imagePrefix}`);
7830
+ logger$3.log(`\n ${registry.registryName}${marker} (${registry.registryId})`);
7831
+ logger$3.log(` URL: ${registry.registryUrl}`);
7832
+ logger$3.log(` Username: ${registry.username}`);
7833
+ if (registry.imagePrefix) logger$3.log(` Prefix: ${registry.imagePrefix}`);
7740
7834
  }
7741
7835
  }
7742
7836
  }
@@ -8597,26 +8691,26 @@ function loadPackageJson() {
8597
8691
  * Run: pnpm --filter @geekmidas/cli sync-versions
8598
8692
  */
8599
8693
  const GEEKMIDAS_VERSIONS = {
8600
- "@geekmidas/audit": "~10.0.0-alpha.26",
8601
- "@geekmidas/auth": "~10.0.0-alpha.26",
8602
- "@geekmidas/cache": "~10.0.0-alpha.26",
8603
- "@geekmidas/client": "~10.0.0-alpha.26",
8604
- "@geekmidas/cloud": "~10.0.0-alpha.26",
8605
- "@geekmidas/constructs": "~10.0.0-alpha.26",
8606
- "@geekmidas/db": "~10.0.0-alpha.26",
8607
- "@geekmidas/emailkit": "~10.0.0-alpha.26",
8608
- "@geekmidas/envkit": "~10.0.0-alpha.26",
8609
- "@geekmidas/errors": "~10.0.0-alpha.26",
8610
- "@geekmidas/events": "~10.0.0-alpha.26",
8611
- "@geekmidas/logger": "~10.0.0-alpha.26",
8612
- "@geekmidas/manifest": "~10.0.0-alpha.26",
8613
- "@geekmidas/rate-limit": "~10.0.0-alpha.26",
8614
- "@geekmidas/schema": "~10.0.0-alpha.26",
8615
- "@geekmidas/services": "~10.0.0-alpha.26",
8616
- "@geekmidas/storage": "~10.0.0-alpha.26",
8617
- "@geekmidas/studio": "~10.0.0-alpha.26",
8618
- "@geekmidas/telescope": "~10.0.0-alpha.26",
8619
- "@geekmidas/testkit": "~10.0.0-alpha.26",
8694
+ "@geekmidas/audit": "~10.0.0-alpha.28",
8695
+ "@geekmidas/auth": "~10.0.0-alpha.28",
8696
+ "@geekmidas/cache": "~10.0.0-alpha.28",
8697
+ "@geekmidas/client": "~10.0.0-alpha.28",
8698
+ "@geekmidas/cloud": "~10.0.0-alpha.28",
8699
+ "@geekmidas/constructs": "~10.0.0-alpha.28",
8700
+ "@geekmidas/db": "~10.0.0-alpha.28",
8701
+ "@geekmidas/emailkit": "~10.0.0-alpha.28",
8702
+ "@geekmidas/envkit": "~10.0.0-alpha.28",
8703
+ "@geekmidas/errors": "~10.0.0-alpha.28",
8704
+ "@geekmidas/events": "~10.0.0-alpha.28",
8705
+ "@geekmidas/logger": "~10.0.0-alpha.28",
8706
+ "@geekmidas/manifest": "~10.0.0-alpha.28",
8707
+ "@geekmidas/rate-limit": "~10.0.0-alpha.28",
8708
+ "@geekmidas/schema": "~10.0.0-alpha.28",
8709
+ "@geekmidas/services": "~10.0.0-alpha.28",
8710
+ "@geekmidas/storage": "~10.0.0-alpha.28",
8711
+ "@geekmidas/studio": "~10.0.0-alpha.28",
8712
+ "@geekmidas/telescope": "~10.0.0-alpha.28",
8713
+ "@geekmidas/testkit": "~10.0.0-alpha.28",
8620
8714
  "@geekmidas/cli": `~${loadPackageJson().version}`
8621
8715
  };
8622
8716
  //#endregion
@@ -14531,7 +14625,7 @@ async function initCommand(projectName, options = {}) {
14531
14625
  }
14532
14626
  console.log("🔐 Initializing encrypted secrets...\n");
14533
14627
  const local = templateOptions.stages.local;
14534
- const devSecrets = require_generator.createStageSecrets(local, [], { projectName: name });
14628
+ const devSecrets = require_reconcile.createStageSecrets(local, [], { projectName: name });
14535
14629
  const customSecrets = {
14536
14630
  PORT: "3000",
14537
14631
  LOG_LEVEL: "debug",
@@ -14695,7 +14789,7 @@ var NotAnAwsRegion = class extends Error {
14695
14789
  };
14696
14790
  //#endregion
14697
14791
  //#region src/secrets/index.ts
14698
- const logger$3 = console;
14792
+ const logger$2 = console;
14699
14793
  /**
14700
14794
  * Initialize secrets for a stage.
14701
14795
  * Generates secure random passwords for configured services.
@@ -14703,7 +14797,7 @@ const logger$3 = console;
14703
14797
  async function secretsInitCommand(options) {
14704
14798
  const { stage, force } = options;
14705
14799
  if (!force && require_storage.secretsExist(stage)) {
14706
- logger$3.error(`Secrets already exist for stage "${stage}". Use --force to overwrite.`);
14800
+ logger$2.error(`Secrets already exist for stage "${stage}". Use --force to overwrite.`);
14707
14801
  process.exit(1);
14708
14802
  }
14709
14803
  let projectName;
@@ -14713,21 +14807,21 @@ async function secretsInitCommand(options) {
14713
14807
  projectName = loaded.workspace.name;
14714
14808
  if (Object.keys(loaded.workspace.apps).length > 1) {
14715
14809
  workspaceSecrets = require_reconcile.generateFullstackCustomSecrets(loaded.workspace);
14716
- logger$3.log(" Detected workspace mode — generating per-app secrets");
14810
+ logger$2.log(" Detected workspace mode — generating per-app secrets");
14717
14811
  }
14718
14812
  } catch {}
14719
- const secrets = require_generator.createStageSecrets(stage, [], { projectName });
14813
+ const secrets = require_reconcile.createStageSecrets(stage, [], { projectName });
14720
14814
  if (workspaceSecrets) secrets.custom = workspaceSecrets;
14721
14815
  await require_storage.writeStageSecrets(secrets);
14722
- logger$3.log(`\n✓ Secrets initialized for stage "${stage}"`);
14723
- logger$3.log(` Location: .gkm/secrets/${stage}.json`);
14724
- if (secrets.urls.DATABASE_URL) logger$3.log(`\n DATABASE_URL: ${maskUrl(secrets.urls.DATABASE_URL)}`);
14725
- if (secrets.urls.REDIS_URL) logger$3.log(` REDIS_URL: ${maskUrl(secrets.urls.REDIS_URL)}`);
14726
- if (secrets.urls.RABBITMQ_URL) logger$3.log(` RABBITMQ_URL: ${maskUrl(secrets.urls.RABBITMQ_URL)}`);
14727
- if (secrets.urls.STORAGE_ENDPOINT) logger$3.log(` STORAGE_ENDPOINT: ${secrets.urls.STORAGE_ENDPOINT}`);
14728
- if (Object.keys(secrets.custom).length > 0) logger$3.log(`\n Custom secrets: ${Object.keys(secrets.custom).length}`);
14729
- logger$3.log(`\n Use "gkm secrets:show --stage ${stage}" to view secrets`);
14730
- logger$3.log(" Use \"gkm secrets:set <KEY> <VALUE> --stage " + stage + "\" to add custom secrets");
14816
+ logger$2.log(`\n✓ Secrets initialized for stage "${stage}"`);
14817
+ logger$2.log(` Location: .gkm/secrets/${stage}.json`);
14818
+ if (secrets.urls.DATABASE_URL) logger$2.log(`\n DATABASE_URL: ${maskUrl(secrets.urls.DATABASE_URL)}`);
14819
+ if (secrets.urls.REDIS_URL) logger$2.log(` REDIS_URL: ${maskUrl(secrets.urls.REDIS_URL)}`);
14820
+ if (secrets.urls.RABBITMQ_URL) logger$2.log(` RABBITMQ_URL: ${maskUrl(secrets.urls.RABBITMQ_URL)}`);
14821
+ if (secrets.urls.STORAGE_ENDPOINT) logger$2.log(` STORAGE_ENDPOINT: ${secrets.urls.STORAGE_ENDPOINT}`);
14822
+ if (Object.keys(secrets.custom).length > 0) logger$2.log(`\n Custom secrets: ${Object.keys(secrets.custom).length}`);
14823
+ logger$2.log(`\n Use "gkm secrets:show --stage ${stage}" to view secrets`);
14824
+ logger$2.log(" Use \"gkm secrets:set <KEY> <VALUE> --stage " + stage + "\" to add custom secrets");
14731
14825
  }
14732
14826
  /**
14733
14827
  * Read all data from stdin.
@@ -14746,21 +14840,21 @@ async function secretsSetCommand(key, value, options) {
14746
14840
  let secretValue = value;
14747
14841
  if (!secretValue) {
14748
14842
  if (process.stdin.isTTY) {
14749
- logger$3.error("No value provided. Use: gkm secrets:set KEY VALUE --stage <stage>");
14750
- logger$3.error("Or pipe from stdin: echo \"value\" | gkm secrets:set KEY --stage <stage>");
14843
+ logger$2.error("No value provided. Use: gkm secrets:set KEY VALUE --stage <stage>");
14844
+ logger$2.error("Or pipe from stdin: echo \"value\" | gkm secrets:set KEY --stage <stage>");
14751
14845
  process.exit(1);
14752
14846
  }
14753
14847
  secretValue = await readStdin();
14754
14848
  if (!secretValue) {
14755
- logger$3.error("No value received from stdin");
14849
+ logger$2.error("No value received from stdin");
14756
14850
  process.exit(1);
14757
14851
  }
14758
14852
  }
14759
14853
  try {
14760
14854
  await require_storage.setCustomSecret(stage, key, secretValue);
14761
- logger$3.log(`\n✓ Secret "${key}" set for stage "${stage}"`);
14855
+ logger$2.log(`\n✓ Secret "${key}" set for stage "${stage}"`);
14762
14856
  } catch (error) {
14763
- logger$3.error(error instanceof Error ? error.message : "Failed to set secret");
14857
+ logger$2.error(error instanceof Error ? error.message : "Failed to set secret");
14764
14858
  process.exit(1);
14765
14859
  }
14766
14860
  }
@@ -14771,33 +14865,33 @@ async function secretsShowCommand(options) {
14771
14865
  const { stage, reveal } = options;
14772
14866
  const secrets = await require_storage.readStageSecrets(stage);
14773
14867
  if (!secrets) {
14774
- logger$3.error(`No secrets found for stage "${stage}". Run "gkm secrets:init --stage ${stage}" first.`);
14868
+ logger$2.error(`No secrets found for stage "${stage}". Run "gkm secrets:init --stage ${stage}" first.`);
14775
14869
  process.exit(1);
14776
14870
  }
14777
- logger$3.log(`\nSecrets for stage "${stage}":`);
14778
- logger$3.log(` Created: ${secrets.createdAt}`);
14779
- logger$3.log(` Updated: ${secrets.updatedAt}`);
14780
- logger$3.log("\nService Credentials:");
14871
+ logger$2.log(`\nSecrets for stage "${stage}":`);
14872
+ logger$2.log(` Created: ${secrets.createdAt}`);
14873
+ logger$2.log(` Updated: ${secrets.updatedAt}`);
14874
+ logger$2.log("\nService Credentials:");
14781
14875
  for (const [service, creds] of Object.entries(secrets.services)) if (creds) {
14782
- logger$3.log(`\n ${service}:`);
14783
- logger$3.log(` host: ${creds.host}`);
14784
- logger$3.log(` port: ${creds.port}`);
14785
- logger$3.log(` username: ${creds.username}`);
14786
- logger$3.log(` password: ${reveal ? creds.password : require_storage.maskPassword(creds.password)}`);
14787
- if (creds.database) logger$3.log(` database: ${creds.database}`);
14788
- if (creds.vhost) logger$3.log(` vhost: ${creds.vhost}`);
14789
- if (creds.bucket) logger$3.log(` bucket: ${creds.bucket}`);
14790
- }
14791
- logger$3.log("\nConnection URLs:");
14792
- if (secrets.urls.DATABASE_URL) logger$3.log(` DATABASE_URL: ${reveal ? secrets.urls.DATABASE_URL : maskUrl(secrets.urls.DATABASE_URL)}`);
14793
- if (secrets.urls.REDIS_URL) logger$3.log(` REDIS_URL: ${reveal ? secrets.urls.REDIS_URL : maskUrl(secrets.urls.REDIS_URL)}`);
14794
- if (secrets.urls.RABBITMQ_URL) logger$3.log(` RABBITMQ_URL: ${reveal ? secrets.urls.RABBITMQ_URL : maskUrl(secrets.urls.RABBITMQ_URL)}`);
14795
- if (secrets.urls.STORAGE_ENDPOINT) logger$3.log(` STORAGE_ENDPOINT: ${secrets.urls.STORAGE_ENDPOINT}`);
14876
+ logger$2.log(`\n ${service}:`);
14877
+ logger$2.log(` host: ${creds.host}`);
14878
+ logger$2.log(` port: ${creds.port}`);
14879
+ logger$2.log(` username: ${creds.username}`);
14880
+ logger$2.log(` password: ${reveal ? creds.password : require_storage.maskPassword(creds.password)}`);
14881
+ if (creds.database) logger$2.log(` database: ${creds.database}`);
14882
+ if (creds.vhost) logger$2.log(` vhost: ${creds.vhost}`);
14883
+ if (creds.bucket) logger$2.log(` bucket: ${creds.bucket}`);
14884
+ }
14885
+ logger$2.log("\nConnection URLs:");
14886
+ if (secrets.urls.DATABASE_URL) logger$2.log(` DATABASE_URL: ${reveal ? secrets.urls.DATABASE_URL : maskUrl(secrets.urls.DATABASE_URL)}`);
14887
+ if (secrets.urls.REDIS_URL) logger$2.log(` REDIS_URL: ${reveal ? secrets.urls.REDIS_URL : maskUrl(secrets.urls.REDIS_URL)}`);
14888
+ if (secrets.urls.RABBITMQ_URL) logger$2.log(` RABBITMQ_URL: ${reveal ? secrets.urls.RABBITMQ_URL : maskUrl(secrets.urls.RABBITMQ_URL)}`);
14889
+ if (secrets.urls.STORAGE_ENDPOINT) logger$2.log(` STORAGE_ENDPOINT: ${secrets.urls.STORAGE_ENDPOINT}`);
14796
14890
  if (Object.keys(secrets.custom).length > 0) {
14797
- logger$3.log("\nCustom Secrets:");
14798
- for (const [key, value] of Object.entries(secrets.custom)) logger$3.log(` ${key}: ${reveal ? value : require_storage.maskPassword(value)}`);
14891
+ logger$2.log("\nCustom Secrets:");
14892
+ for (const [key, value] of Object.entries(secrets.custom)) logger$2.log(` ${key}: ${reveal ? value : require_storage.maskPassword(value)}`);
14799
14893
  }
14800
- if (!reveal) logger$3.log("\nUse --reveal to show actual values");
14894
+ if (!reveal) logger$2.log("\nUse --reveal to show actual values");
14801
14895
  }
14802
14896
  /**
14803
14897
  * Rotate passwords for services.
@@ -14806,25 +14900,25 @@ async function secretsRotateCommand(options) {
14806
14900
  const { stage, service } = options;
14807
14901
  const secrets = await require_storage.readStageSecrets(stage);
14808
14902
  if (!secrets) {
14809
- logger$3.error(`No secrets found for stage "${stage}". Run "gkm secrets:init --stage ${stage}" first.`);
14903
+ logger$2.error(`No secrets found for stage "${stage}". Run "gkm secrets:init --stage ${stage}" first.`);
14810
14904
  process.exit(1);
14811
14905
  }
14812
14906
  if (service) {
14813
14907
  if (!secrets.services[service]) {
14814
- logger$3.error(`Service "${service}" not configured in stage "${stage}"`);
14908
+ logger$2.error(`Service "${service}" not configured in stage "${stage}"`);
14815
14909
  process.exit(1);
14816
14910
  }
14817
- const updated = require_generator.rotateServicePassword(secrets, service);
14911
+ const updated = require_reconcile.rotateServicePassword(secrets, service);
14818
14912
  await require_storage.writeStageSecrets(updated);
14819
- logger$3.log(`\n✓ Password rotated for ${service} in stage "${stage}"`);
14913
+ logger$2.log(`\n✓ Password rotated for ${service} in stage "${stage}"`);
14820
14914
  } else {
14821
14915
  let updated = secrets;
14822
14916
  const services = Object.keys(secrets.services);
14823
- for (const svc of services) updated = require_generator.rotateServicePassword(updated, svc);
14917
+ for (const svc of services) updated = require_reconcile.rotateServicePassword(updated, svc);
14824
14918
  await require_storage.writeStageSecrets(updated);
14825
- logger$3.log(`\n✓ Passwords rotated for all services in stage "${stage}": ${services.join(", ")}`);
14919
+ logger$2.log(`\n✓ Passwords rotated for all services in stage "${stage}": ${services.join(", ")}`);
14826
14920
  }
14827
- logger$3.log(`\nUse "gkm secrets:show --stage ${stage}" to view new values`);
14921
+ logger$2.log(`\nUse "gkm secrets:show --stage ${stage}" to view new values`);
14828
14922
  }
14829
14923
  /**
14830
14924
  * Import secrets from a JSON file.
@@ -14832,7 +14926,7 @@ async function secretsRotateCommand(options) {
14832
14926
  async function secretsImportCommand(file, options) {
14833
14927
  const { stage, merge = true } = options;
14834
14928
  if (!(0, node_fs.existsSync)(file)) {
14835
- logger$3.error(`File not found: ${file}`);
14929
+ logger$2.error(`File not found: ${file}`);
14836
14930
  process.exit(1);
14837
14931
  }
14838
14932
  let importedSecrets;
@@ -14842,12 +14936,12 @@ async function secretsImportCommand(file, options) {
14842
14936
  if (typeof importedSecrets !== "object" || importedSecrets === null) throw new Error("JSON must be an object");
14843
14937
  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}`);
14844
14938
  } catch (error) {
14845
- logger$3.error(`Failed to parse JSON file: ${error instanceof Error ? error.message : "Invalid JSON"}`);
14939
+ logger$2.error(`Failed to parse JSON file: ${error instanceof Error ? error.message : "Invalid JSON"}`);
14846
14940
  process.exit(1);
14847
14941
  }
14848
14942
  const secrets = await require_storage.readStageSecrets(stage);
14849
14943
  if (!secrets) {
14850
- logger$3.error(`No secrets found for stage "${stage}". Run "gkm secrets:init --stage ${stage}" first.`);
14944
+ logger$2.error(`No secrets found for stage "${stage}". Run "gkm secrets:init --stage ${stage}" first.`);
14851
14945
  process.exit(1);
14852
14946
  }
14853
14947
  const updatedCustom = merge ? {
@@ -14862,10 +14956,10 @@ async function secretsImportCommand(file, options) {
14862
14956
  await require_storage.writeStageSecrets(updated);
14863
14957
  const importedCount = Object.keys(importedSecrets).length;
14864
14958
  const totalCount = Object.keys(updatedCustom).length;
14865
- logger$3.log(`\n✓ Imported ${importedCount} secrets for stage "${stage}"`);
14866
- if (merge && totalCount > importedCount) logger$3.log(` Total custom secrets: ${totalCount}`);
14867
- logger$3.log("\n Imported keys:");
14868
- for (const key of Object.keys(importedSecrets)) logger$3.log(` - ${key}`);
14959
+ logger$2.log(`\n✓ Imported ${importedCount} secrets for stage "${stage}"`);
14960
+ if (merge && totalCount > importedCount) logger$2.log(` Total custom secrets: ${totalCount}`);
14961
+ logger$2.log("\n Imported keys:");
14962
+ for (const key of Object.keys(importedSecrets)) logger$2.log(` - ${key}`);
14869
14963
  }
14870
14964
  /**
14871
14965
  * Mask password in a URL for display.
@@ -14880,175 +14974,120 @@ function maskUrl(url) {
14880
14974
  }
14881
14975
  }
14882
14976
  //#endregion
14883
- //#region src/trust/index.ts
14884
- /**
14885
- * Installing the local edge's certificate authority into the OS trust store.
14886
- *
14887
- * `NODE_EXTRA_CA_CERTS` covers everything gkm starts — the dev server, the test
14888
- * suite, anything under `gkm exec` — because reconcile injects it. A browser
14889
- * reads none of that: it asks the operating system, so until the root is in the
14890
- * system store a local `https://` address is "not secure", which is true and
14891
- * unhelpful.
14892
- *
14893
- * A separate command rather than part of `gkm setup`, for one reason: this
14894
- * needs `sudo`, and a setup that silently escalates on every run is a worse
14895
- * trade than one that tells you what to type. Caddy's own `caddy trust` draws
14896
- * the line in the same place.
14897
- */
14898
- const logger$2 = console;
14899
- const run = (0, node_util.promisify)(node_child_process.execFile);
14900
- /**
14901
- * How each platform is told about a new authority.
14902
- *
14903
- * Separate rather than shelled through one script because the failure modes
14904
- * differ and the message should name the real one: macOS refuses without an
14905
- * admin password, Debian needs the file in a specific directory before its
14906
- * updater will look at it.
14907
- */
14908
- function installation(platform, certificate) {
14909
- if (platform === "darwin") return {
14910
- describe: "the System keychain",
14911
- steps: [["sudo", [
14912
- "security",
14913
- "add-trusted-cert",
14914
- "-d",
14915
- "-r",
14916
- "trustRoot",
14917
- "-k",
14918
- "/Library/Keychains/System.keychain",
14919
- certificate
14920
- ]]]
14921
- };
14922
- if (platform === "linux") {
14923
- const debian = (0, node_fs.existsSync)("/usr/local/share/ca-certificates");
14924
- return {
14925
- describe: debian ? "the system CA bundle" : "the system trust anchors",
14926
- steps: debian ? [["sudo", [
14927
- "cp",
14928
- certificate,
14929
- "/usr/local/share/ca-certificates/gkm-local-ca.crt"
14930
- ]], ["sudo", ["update-ca-certificates"]]] : [["sudo", [
14931
- "cp",
14932
- certificate,
14933
- "/etc/pki/ca-trust/source/anchors/gkm-local-ca.crt"
14934
- ]], ["sudo", ["update-ca-trust"]]]
14935
- };
14977
+ //#region src/secrets/store.ts
14978
+ /** The encrypted file under `.gkm/secrets/`, and its key under `~/.gkm/`. */
14979
+ var FileSecretsStore = class {
14980
+ root;
14981
+ constructor(root) {
14982
+ this.root = root;
14936
14983
  }
14937
- throw new UnsupportedPlatform(platform, certificate);
14938
- }
14939
- /**
14940
- * Trust the certificate authority this project's edge issues from.
14941
- *
14942
- * Idempotent in effect: installing a root that is already trusted replaces the
14943
- * same entry, so running it twice is not an error.
14944
- */
14945
- async function trustCommand(options = {}) {
14946
- const { workspace } = await require_config.loadWorkspaceConfig();
14947
- const certificate = (0, node_path.join)(workspace.root, require_credentials.LOCAL_CA_PATH);
14948
- if (!(0, node_fs.existsSync)(certificate)) throw new NoLocalAuthority(certificate);
14949
- const { describe, steps } = installation(process.platform, certificate);
14950
- logger$2.log(`\n🔐 Trusting the local authority in ${describe}`);
14951
- logger$2.log(` ${certificate}\n`);
14952
- if (options.dryRun) {
14953
- for (const [command, args] of steps) logger$2.log(` ${command} ${args.join(" ")}`);
14954
- return;
14984
+ pull(stage) {
14985
+ return require_storage.readStageSecrets(stage, this.root);
14955
14986
  }
14956
- logger$2.log(" This needs an admin password.\n");
14957
- for (const [command, args] of steps) await run(command, args, { stdio: "inherit" });
14958
- logger$2.log("\n✅ Local https addresses are trusted. Restart your browser.\n");
14959
- }
14987
+ push(_stage, secrets) {
14988
+ return require_storage.writeStageSecrets(secrets, this.root);
14989
+ }
14990
+ };
14960
14991
  /**
14961
- * Trust the authority if this machine lacks it and its owner agrees.
14992
+ * The store a stage's secrets live in.
14962
14993
  *
14963
- * A machine's answer, not the project's: whether a laptop installs a root
14964
- * certificate is its owner's call, so the decision is `--yes`, then what this
14965
- * machine previously answered, then a prompt. Never a silent `sudo` — that is
14966
- * the one thing a setup command should not do on somebody's behalf.
14967
- *
14968
- * Silent and free when the machine already trusts it, which is what makes it
14969
- * acceptable to call on every `gkm setup`.
14970
- */
14971
- async function ensureTrusted(root, url, options = {}) {
14972
- if (await isTrusted(url)) return;
14973
- if (!options.assumeYes) {
14974
- if (!process.stdin.isTTY) {
14975
- logger$2.log(" Local https addresses are not trusted here. Run \"gkm trust\", or \"gkm setup --yes\".");
14976
- return;
14977
- }
14978
- if (await declined(root)) return;
14979
- const { install } = await (0, prompts.default)({
14980
- type: "confirm",
14981
- name: "install",
14982
- message: "Trust this project's local certificate authority, so a browser accepts its https addresses? (needs sudo)",
14983
- initial: false
14984
- });
14985
- if (!install) {
14986
- await recordDeclined(root);
14987
- logger$2.log(" Skipped. Run \"gkm trust\" later.");
14988
- return;
14989
- }
14990
- }
14991
- await trustCommand();
14992
- }
14993
- /** Where a declined answer is remembered, so setup asks once and not again. */
14994
- const TRUST_STATE = ".gkm/trust.json";
14995
- async function declined(root) {
14996
- try {
14997
- const raw = await (0, node_fs_promises.readFile)((0, node_path.join)(root, TRUST_STATE), "utf-8");
14998
- return JSON.parse(raw).declined === true;
14999
- } catch {
15000
- return false;
15001
- }
14994
+ * The local stage is always the file: its secrets belong to the machine
14995
+ * running `gkm dev`. A deployed stage uses `secrets.store`.
14996
+ */
14997
+ async function secretsStoreFor(workspace, stage, options = {}) {
14998
+ const configured = workspace.secrets.store ?? "file";
14999
+ if (stage === workspace.stages.local || configured === "file") return new FileSecretsStore(workspace.root);
15000
+ if (configured.provider !== "ssm") return configured.provider;
15001
+ const { SsmSecretsStore } = await Promise.resolve().then(() => require("./ssm-FxeSAt35.cjs"));
15002
+ return new SsmSecretsStore({
15003
+ project: workspace.name,
15004
+ region: configured.region,
15005
+ ...options.profile ? { profile: options.profile } : {}
15006
+ });
15002
15007
  }
15003
- async function recordDeclined(root) {
15004
- const path = (0, node_path.join)(root, TRUST_STATE);
15005
- await (0, node_fs_promises.mkdir)((0, node_path.dirname)(path), { recursive: true });
15006
- await (0, node_fs_promises.writeFile)(path, `${JSON.stringify({ declined: true }, null, 2)}\n`);
15008
+ /** Whether a stage's secrets live somewhere other than this machine. */
15009
+ function isRemoteStore(workspace, stage) {
15010
+ const configured = workspace.secrets.store ?? "file";
15011
+ return stage !== workspace.stages.local && configured !== "file";
15007
15012
  }
15013
+ //#endregion
15014
+ //#region src/secrets/transfer.ts
15008
15015
  /**
15009
- * Whether this machine already trusts the local authority.
15016
+ * Moving a deployed stage's secrets between this machine and its store.
15010
15017
  *
15011
- * Asked by connecting rather than by reading a keychain: what matters is
15012
- * whether a client with no special configuration verifies the edge, and that is
15013
- * one platform-neutral question instead of three platform-specific ones. It is
15014
- * also the exact thing a browser is about to do.
15015
- *
15016
- * A child process, because `NODE_EXTRA_CA_CERTS` is read once at startup and
15017
- * this process almost certainly has it set — asking in-process would answer
15018
- * "yes" for everyone.
15019
- */
15020
- async function isTrusted(url) {
15021
- const { NODE_EXTRA_CA_CERTS: _ignored, ...env } = process.env;
15022
- try {
15023
- await run(process.execPath, ["-e", `fetch(${JSON.stringify(url)}).then(()=>0,()=>process.exit(1))`], {
15024
- env,
15025
- timeout: 15e3
15026
- });
15027
- return true;
15028
- } catch {
15029
- return false;
15018
+ * `push` sends the encrypted local copy to the stage's store; `pull` brings it
15019
+ * back and writes the local copy a deploy reads — generating a key for it if
15020
+ * the machine has none, which is what a fresh CI runner needs. Both reconcile
15021
+ * the keys the workspace now derives, so a store never lags a new construct.
15022
+ */
15023
+ var transfer_exports = /* @__PURE__ */ require_rolldown_runtime.__exportAll({
15024
+ NoLocalSecrets: () => NoLocalSecrets,
15025
+ NoRemoteSecretsStore: () => NoRemoteSecretsStore,
15026
+ NoStoredSecrets: () => NoStoredSecrets,
15027
+ pullStageSecrets: () => pullStageSecrets,
15028
+ pushStageSecrets: () => pushStageSecrets
15029
+ });
15030
+ /** A push or pull for a stage with nowhere to push or pull from. */
15031
+ var NoRemoteSecretsStore = class extends Error {
15032
+ stage;
15033
+ constructor(stage) {
15034
+ super(`Stage "${stage}" keeps its secrets in the local file, so there is nothing to push or pull. Set secrets.store in gkm.config.ts (e.g. { provider: 'ssm', region: 'eu-west-1' }) for deployed stages.`);
15035
+ this.stage = stage;
15036
+ this.name = "NoRemoteSecretsStore";
15030
15037
  }
15031
- }
15032
- /** The edge has not run, so there is no authority to trust yet. */
15033
- var NoLocalAuthority = class extends Error {
15034
- path;
15035
- constructor(path) {
15036
- super(`No local certificate authority at ${path}. It is generated the first time the edge starts, so run "gkm setup" (or "gkm dev") once — and if this project declares no file server, nothing needs one.`);
15037
- this.path = path;
15038
- this.name = "NoLocalAuthority";
15038
+ };
15039
+ /** A push for a stage whose secrets this machine does not have. */
15040
+ var NoLocalSecrets = class extends Error {
15041
+ stage;
15042
+ constructor(stage) {
15043
+ super(`No secrets for stage "${stage}" on this machine. Run gkm secrets:init --stage ${stage} first.`);
15044
+ this.stage = stage;
15045
+ this.name = "NoLocalSecrets";
15039
15046
  }
15040
15047
  };
15041
- /** A platform with no trust store this knows how to write to. */
15042
- var UnsupportedPlatform = class extends Error {
15043
- platform;
15044
- certificate;
15045
- constructor(platform, certificate) {
15046
- super(`gkm does not know how to install a certificate authority on ${platform}. The root is at ${certificate} — add it to the trust store by hand, or point a client at it with NODE_EXTRA_CA_CERTS.`);
15047
- this.platform = platform;
15048
- this.certificate = certificate;
15049
- this.name = "UnsupportedPlatform";
15048
+ /** A pull for a stage the store holds nothing for. */
15049
+ var NoStoredSecrets = class extends Error {
15050
+ stage;
15051
+ constructor(stage) {
15052
+ super(`The store holds no secrets for stage "${stage}". Push them first: gkm secrets:push --stage ${stage}.`);
15053
+ this.stage = stage;
15054
+ this.name = "NoStoredSecrets";
15050
15055
  }
15051
15056
  };
15057
+ async function reconcile(secrets, workspace, stage) {
15058
+ const { derivedContainers } = await Promise.resolve().then(() => require("./workspace-Cv48QwPK.cjs")).then((n) => n.workspace_exports);
15059
+ const result = require_reconcile.reconcileMissingSecrets(secrets, workspace, await derivedContainers(workspace, stage));
15060
+ return result ? {
15061
+ secrets: result.secrets,
15062
+ addedKeys: result.addedKeys
15063
+ } : {
15064
+ secrets,
15065
+ addedKeys: []
15066
+ };
15067
+ }
15068
+ function remoteOnly(workspace, stage) {
15069
+ require_workspace.assertDeployedStage(workspace.stages, stage);
15070
+ if (!isRemoteStore(workspace, stage)) throw new NoRemoteSecretsStore(stage);
15071
+ }
15072
+ /** Send this machine's secrets for a deployed stage to its store. */
15073
+ async function pushStageSecrets(workspace, stage, options = {}) {
15074
+ remoteOnly(workspace, stage);
15075
+ const local = await require_storage.readStageSecrets(stage, workspace.root);
15076
+ if (!local) throw new NoLocalSecrets(stage);
15077
+ const result = await reconcile(local, workspace, stage);
15078
+ if (result.addedKeys.length) await require_storage.writeStageSecrets(result.secrets, workspace.root);
15079
+ await (await secretsStoreFor(workspace, stage, options)).push(stage, result.secrets);
15080
+ return result;
15081
+ }
15082
+ /** Bring a deployed stage's secrets from its store into the local copy. */
15083
+ async function pullStageSecrets(workspace, stage, options = {}) {
15084
+ remoteOnly(workspace, stage);
15085
+ const stored = await (await secretsStoreFor(workspace, stage, options)).pull(stage);
15086
+ if (!stored) throw new NoStoredSecrets(stage);
15087
+ const result = await reconcile(stored, workspace, stage);
15088
+ await require_storage.writeStageSecrets(result.secrets, workspace.root);
15089
+ return result;
15090
+ }
15052
15091
  //#endregion
15053
15092
  //#region src/setup/index.ts
15054
15093
  var setup_exports = /* @__PURE__ */ require_rolldown_runtime.__exportAll({
@@ -15087,7 +15126,7 @@ async function setupCommand(options = {}) {
15087
15126
  logger$1.error("❌ Failed to resolve secrets. Exiting.");
15088
15127
  process.exit(1);
15089
15128
  }
15090
- const containers = await require_credentials.derivedContainers(workspace, stage);
15129
+ const containers = await require_workspace$1.derivedContainers(workspace, stage);
15091
15130
  if (isMultiApp && containers.includes("postgres")) {
15092
15131
  await require_reconcile.writeDockerEnvFromSecrets(secrets, workspace.root);
15093
15132
  logger$1.log("📄 Generated docker/.env with database passwords");
@@ -15106,7 +15145,7 @@ async function setupCommand(options = {}) {
15106
15145
  * free and quiet.
15107
15146
  */
15108
15147
  async function reconcileLocal(workspace, stage, options) {
15109
- const result = await require_credentials.reconcileWorkspace(workspace, { stage });
15148
+ const result = await require_workspace$1.reconcileWorkspace(workspace, { stage });
15110
15149
  if (result.plan.containers.length === 0) {
15111
15150
  logger$1.log("🐳 No containers declared");
15112
15151
  return;
@@ -15117,8 +15156,7 @@ async function reconcileLocal(workspace, stage, options) {
15117
15156
  }
15118
15157
  logger$1.log(`🐳 Services: ${result.plan.containers.join(", ")}`);
15119
15158
  for (const [container, address] of Object.entries(result.addresses)) logger$1.log(` ${container}: ${address}`);
15120
- const served = result.plan.resources.find((r) => r.kind === "file-server");
15121
- const url = served ? result.env[served.envKey] : void 0;
15159
+ const url = result.plan.resources.filter((r) => r.kind === "rest-api" || r.kind === "site" || r.kind === "file-server").map((r) => result.env[r.envKey]).find((address) => address?.startsWith("https://"));
15122
15160
  if (url) await ensureTrusted(workspace.root, url, { ...options.yes ? { assumeYes: true } : {} });
15123
15161
  }
15124
15162
  /**
@@ -15138,19 +15176,19 @@ async function resolveSecrets(stage, workspace, options) {
15138
15176
  logger$1.log("🔐 Using existing local secrets");
15139
15177
  const secrets = await require_storage.readStageSecrets(stage, workspace.root);
15140
15178
  if (secrets) {
15141
- const reconciled = reconcileSecrets(secrets, workspace, await require_credentials.derivedContainers(workspace, stage));
15179
+ const reconciled = reconcileSecrets(secrets, workspace, await require_workspace$1.derivedContainers(workspace, stage));
15142
15180
  if (reconciled) await require_storage.writeStageSecrets(reconciled, workspace.root);
15143
15181
  return reconciled ?? secrets;
15144
15182
  }
15145
15183
  }
15146
- if (require_transfer.isRemoteStore(workspace, stage)) {
15184
+ if (isRemoteStore(workspace, stage)) {
15147
15185
  logger$1.log("☁️ Checking the secrets store...");
15148
15186
  try {
15149
- const { secrets } = await require_transfer.pullStageSecrets(workspace, stage);
15187
+ const { secrets } = await pullStageSecrets(workspace, stage);
15150
15188
  logger$1.log("✅ Pulled secrets from the store");
15151
15189
  return secrets;
15152
15190
  } catch (error) {
15153
- if (error instanceof require_transfer.NoStoredSecrets) logger$1.log(" The store holds none yet");
15191
+ if (error instanceof NoStoredSecrets) logger$1.log(" The store holds none yet");
15154
15192
  else logger$1.warn(`⚠️ Could not pull from the store: ${error.message}`);
15155
15193
  }
15156
15194
  }
@@ -15186,7 +15224,7 @@ function reconcileSecrets(secrets, workspace, containers = []) {
15186
15224
  let changed = false;
15187
15225
  let result = { ...secrets };
15188
15226
  for (const name of credentialedServices(containers)) if (!result.services[name]) {
15189
- const creds = require_generator.generateServiceCredentials(name);
15227
+ const creds = require_reconcile.generateServiceCredentials(name);
15190
15228
  if (name === "minio") {
15191
15229
  creds.bucket = workspace.name;
15192
15230
  creds.username = workspace.name;
@@ -15198,7 +15236,7 @@ function reconcileSecrets(secrets, workspace, containers = []) {
15198
15236
  [name]: creds
15199
15237
  }
15200
15238
  };
15201
- result.urls = require_generator.generateConnectionUrls(result.services, result.eventsBackend);
15239
+ result.urls = require_reconcile.generateConnectionUrls(result.services, result.eventsBackend);
15202
15240
  logger$1.log(` 🔄 Adding missing service credentials: ${name}`);
15203
15241
  changed = true;
15204
15242
  }
@@ -15211,12 +15249,12 @@ function reconcileSecrets(secrets, workspace, containers = []) {
15211
15249
  host: result.services.postgres.host,
15212
15250
  port: result.services.postgres.port,
15213
15251
  username: "pgboss",
15214
- password: require_generator.generateSecurePassword(),
15252
+ password: require_reconcile.generateSecurePassword(),
15215
15253
  database: result.services.postgres.database ?? "app"
15216
15254
  }
15217
15255
  }
15218
15256
  };
15219
- result.urls = require_generator.generateConnectionUrls(result.services, result.eventsBackend);
15257
+ result.urls = require_reconcile.generateConnectionUrls(result.services, result.eventsBackend);
15220
15258
  logger$1.log(" 🔄 Adding missing service credentials: pgboss");
15221
15259
  changed = true;
15222
15260
  }
@@ -15251,7 +15289,7 @@ function reconcileSecrets(secrets, workspace, containers = []) {
15251
15289
  */
15252
15290
  function createFreshWorkspaceSecrets(stage, workspace, containers = []) {
15253
15291
  const serviceNames = credentialedServices(containers);
15254
- const secrets = require_generator.createStageSecrets(stage, serviceNames, { projectName: workspace.name });
15292
+ const secrets = require_reconcile.createStageSecrets(stage, serviceNames, { projectName: workspace.name });
15255
15293
  if (Object.keys(workspace.apps).length > 1) secrets.custom = require_reconcile.generateFullstackCustomSecrets(workspace, containers);
15256
15294
  else secrets.custom = {
15257
15295
  PORT: "3000",
@@ -15273,7 +15311,7 @@ function createFreshWorkspaceSecrets(stage, workspace, containers = []) {
15273
15311
  async function ensureStageSecrets(stage, cwd = process.cwd()) {
15274
15312
  const { workspace } = await require_config.loadWorkspaceConfig(cwd);
15275
15313
  if (require_storage.secretsExist(stage, workspace.root)) return false;
15276
- const secrets = createFreshWorkspaceSecrets(stage, workspace, await require_credentials.derivedContainers(workspace, stage));
15314
+ const secrets = createFreshWorkspaceSecrets(stage, workspace, await require_workspace$1.derivedContainers(workspace, stage));
15277
15315
  await require_storage.writeStageSecrets(secrets, workspace.root);
15278
15316
  return true;
15279
15317
  }
@@ -15281,10 +15319,10 @@ async function ensureStageSecrets(stage, cwd = process.cwd()) {
15281
15319
  * Generate fresh secrets for the workspace.
15282
15320
  */
15283
15321
  async function generateFreshSecrets(stage, workspace, options) {
15284
- const secrets = createFreshWorkspaceSecrets(stage, workspace, await require_credentials.derivedContainers(workspace, stage));
15322
+ const secrets = createFreshWorkspaceSecrets(stage, workspace, await require_workspace$1.derivedContainers(workspace, stage));
15285
15323
  await require_storage.writeStageSecrets(secrets, workspace.root);
15286
15324
  logger$1.log(` Secrets written to .gkm/secrets/${stage}.json`);
15287
- if (require_transfer.isRemoteStore(workspace, stage) && !options.yes) {
15325
+ if (isRemoteStore(workspace, stage) && !options.yes) {
15288
15326
  const { shouldPush } = await (0, prompts.default)({
15289
15327
  type: "confirm",
15290
15328
  name: "shouldPush",
@@ -15292,7 +15330,7 @@ async function generateFreshSecrets(stage, workspace, options) {
15292
15330
  initial: true
15293
15331
  });
15294
15332
  if (shouldPush) try {
15295
- await require_transfer.pushStageSecrets(workspace, stage);
15333
+ await pushStageSecrets(workspace, stage);
15296
15334
  logger$1.log("☁️ Secrets pushed to the store");
15297
15335
  } catch (error) {
15298
15336
  logger$1.warn(`⚠️ Could not push to the store: ${error.message}`);
@@ -15556,13 +15594,12 @@ async function testCommand(options = {}) {
15556
15594
  const { ensureStageSecrets } = await Promise.resolve().then(() => setup_exports);
15557
15595
  if (await ensureStageSecrets(stage, cwd)) console.log(` 🔐 Generated fresh ${stage} secrets (auto-setup)`);
15558
15596
  }
15559
- const defaultEnv = require_credentials.loadEnvFiles(".env");
15597
+ const defaultEnv = require_workspace$1.loadEnvFiles(".env");
15560
15598
  if (defaultEnv.loaded.length > 0) console.log(` 📦 Loaded env: ${defaultEnv.loaded.join(", ")}`);
15561
- const result = await require_credentials.prepareEntryCredentials({
15599
+ const result = await require_workspace$1.prepareEntryCredentials({
15562
15600
  stage,
15563
15601
  startDocker: !options.prepare,
15564
15602
  secretsFileName: "test-secrets.json",
15565
- resolveDockerPorts: "full",
15566
15603
  reconcileStage: "test"
15567
15604
  });
15568
15605
  let finalCredentials = { ...result.credentials };
@@ -15576,18 +15613,17 @@ async function testCommand(options = {}) {
15576
15613
  console.log(` 🔍 Sniffed ${sniffed.requiredEnvVars.length} required env var(s)` + (result.declaredKeys.length > 0 ? `, kept ${result.declaredKeys.length} declared` : ""));
15577
15614
  }
15578
15615
  }
15579
- finalCredentials = rewriteDatabaseUrlForTests(finalCredentials);
15580
15616
  console.log("");
15581
15617
  await (0, node_fs_promises.writeFile)(result.secretsJsonPath, JSON.stringify(finalCredentials, null, 2));
15582
15618
  const gkmDir = (0, node_path.join)(cwd, ".gkm");
15583
15619
  const preloadPath = (0, node_path.join)(gkmDir, "test-credentials-preload.ts");
15584
- await require_credentials.createCredentialsPreload(preloadPath, result.secretsJsonPath);
15620
+ await require_workspace$1.createCredentialsPreload(preloadPath, result.secretsJsonPath);
15585
15621
  const workspace = await require_config.loadWorkspaceConfig(cwd).then((loaded) => loaded.workspace).catch(() => void 0);
15586
- const manifestPath = workspace && require_credentials.usesConstructs(workspace) ? await writeTestHarness({
15622
+ const manifestPath = workspace ? await writeTestHarness({
15587
15623
  root: workspace.root,
15588
15624
  targets: [workspace.root, ...Object.values(workspace.apps).map((app) => (0, node_path.isAbsolute)(app.path) ? app.path : (0, node_path.join)(workspace.root, app.path))],
15589
- patterns: require_credentials.constructGlobs(workspace),
15590
- cacheBackend: require_credentials.backendsOf(workspace).cache,
15625
+ patterns: require_workspace$1.constructGlobs(workspace),
15626
+ cacheBackend: require_workspace$1.backendsOf(workspace).cache,
15591
15627
  stage: require_workspace.TEST_STAGE,
15592
15628
  env: finalCredentials
15593
15629
  }) : void 0;
@@ -15627,29 +15663,6 @@ async function testCommand(options = {}) {
15627
15663
  });
15628
15664
  });
15629
15665
  }
15630
- const TEST_DB_SUFFIX = "_test";
15631
- /**
15632
- * Rewrite DATABASE_URL to point to a separate test database.
15633
- * Appends `_test` to the database name (e.g., `app` -> `app_test`).
15634
- * @internal Exported for testing
15635
- */
15636
- function rewriteDatabaseUrlForTests(env) {
15637
- const result = { ...env };
15638
- for (const key of Object.keys(result)) {
15639
- if (!key.includes("DATABASE_URL")) continue;
15640
- const value = result[key];
15641
- try {
15642
- const url = new URL(value);
15643
- const dbName = url.pathname.slice(1);
15644
- if (dbName && !dbName.endsWith(TEST_DB_SUFFIX)) {
15645
- url.pathname = `/${dbName}${TEST_DB_SUFFIX}`;
15646
- result[key] = url.toString();
15647
- console.log(` 🧪 ${key}: using test database "${dbName}${TEST_DB_SUFFIX}"`);
15648
- }
15649
- } catch {}
15650
- }
15651
- return result;
15652
- }
15653
15666
  /** `gkm test` outside a project that declares stages, with none named. */
15654
15667
  var NoStageToTest = class extends Error {
15655
15668
  constructor() {
@@ -16190,7 +16203,7 @@ program.command("secrets:push").description("Send a deployed stage's secrets to
16190
16203
  const globalOptions = program.opts();
16191
16204
  if (globalOptions.cwd) process.chdir(globalOptions.cwd);
16192
16205
  const { loadWorkspaceConfig } = await Promise.resolve().then(() => require("./config.cjs"));
16193
- const { pushStageSecrets } = await Promise.resolve().then(() => require("./transfer-D2qLFXsw.cjs")).then((n) => n.transfer_exports);
16206
+ const { pushStageSecrets } = await Promise.resolve().then(() => transfer_exports);
16194
16207
  const { workspace } = await loadWorkspaceConfig();
16195
16208
  const { addedKeys } = await pushStageSecrets(workspace, options.stage, { profile: options.profile });
16196
16209
  for (const key of addedKeys) console.log(` + ${key} (reconciled)`);
@@ -16205,7 +16218,7 @@ program.command("secrets:pull").description("Bring a deployed stage's secrets fr
16205
16218
  const globalOptions = program.opts();
16206
16219
  if (globalOptions.cwd) process.chdir(globalOptions.cwd);
16207
16220
  const { loadWorkspaceConfig } = await Promise.resolve().then(() => require("./config.cjs"));
16208
- const { pullStageSecrets } = await Promise.resolve().then(() => require("./transfer-D2qLFXsw.cjs")).then((n) => n.transfer_exports);
16221
+ const { pullStageSecrets } = await Promise.resolve().then(() => transfer_exports);
16209
16222
  const { workspace } = await loadWorkspaceConfig();
16210
16223
  const { addedKeys } = await pullStageSecrets(workspace, options.stage, { profile: options.profile });
16211
16224
  for (const key of addedKeys) console.log(` + ${key} (reconciled)`);
@@ -16220,7 +16233,7 @@ program.command("secrets:reconcile").description("Backfill missing custom secret
16220
16233
  const globalOptions = program.opts();
16221
16234
  if (globalOptions.cwd) process.chdir(globalOptions.cwd);
16222
16235
  const { loadWorkspaceConfig } = await Promise.resolve().then(() => require("./config.cjs"));
16223
- const { reconcileMissingSecrets } = await Promise.resolve().then(() => require("./reconcile-hx_vBvux.cjs")).then((n) => n.reconcile_exports);
16236
+ const { reconcileMissingSecrets } = await Promise.resolve().then(() => require("./reconcile-szmJw_Sb.cjs")).then((n) => n.reconcile_exports);
16224
16237
  const { readStageSecrets, writeStageSecrets } = await Promise.resolve().then(() => require("./storage-DgypfSD6.cjs")).then((n) => n.storage_exports);
16225
16238
  const { workspace } = await loadWorkspaceConfig();
16226
16239
  const stage = options.stage ?? workspace.stages.local;
@@ -16229,7 +16242,7 @@ program.command("secrets:reconcile").description("Backfill missing custom secret
16229
16242
  console.error(`No secrets found for stage "${stage}". Run "gkm secrets:init --stage ${stage}" first.`);
16230
16243
  process.exit(1);
16231
16244
  }
16232
- const { derivedContainers } = await Promise.resolve().then(() => require("./credentials-fQSAe4Nb.cjs")).then((n) => n.workspace_exports);
16245
+ const { derivedContainers } = await Promise.resolve().then(() => require("./workspace-Cv48QwPK.cjs")).then((n) => n.workspace_exports);
16233
16246
  const result = reconcileMissingSecrets(secrets, workspace, await derivedContainers(workspace, stage));
16234
16247
  if (!result) {
16235
16248
  console.log(`\n✓ Secrets for stage "${stage}" are up-to-date`);
@@ -16288,7 +16301,7 @@ program.command("deploy:github").description("Let GitHub Actions deploy a stage:
16288
16301
  try {
16289
16302
  const globalOptions = program.opts();
16290
16303
  if (globalOptions.cwd) process.chdir(globalOptions.cwd);
16291
- const { deployGithubCommand } = await Promise.resolve().then(() => require("./github-D58lt7RR.cjs"));
16304
+ const { deployGithubCommand } = await Promise.resolve().then(() => require("./github-BUCXEl2v.cjs"));
16292
16305
  await deployGithubCommand(options);
16293
16306
  } catch (error) {
16294
16307
  console.error(formatError(error));
@@ -16420,5 +16433,7 @@ Object.defineProperty(exports, "encryption_exports", {
16420
16433
  }
16421
16434
  });
16422
16435
  exports.getHostingerToken = getHostingerToken;
16436
+ exports.isRemoteStore = isRemoteStore;
16437
+ exports.pushStageSecrets = pushStageSecrets;
16423
16438
 
16424
16439
  //# sourceMappingURL=index.cjs.map