@geekmidas/cli 10.0.0-alpha.81 → 10.0.0-alpha.83

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 (148) hide show
  1. package/dist/{EndpointGenerator-DftalLYg.mjs → EndpointGenerator-DtnIGafh.mjs} +71 -8
  2. package/dist/EndpointGenerator-DtnIGafh.mjs.map +1 -0
  3. package/dist/{EndpointGenerator-CP6sBvQV.cjs → EndpointGenerator-cKlnllIu.cjs} +88 -7
  4. package/dist/EndpointGenerator-cKlnllIu.cjs.map +1 -0
  5. package/dist/{LegacyStateStore-Ceq7A_75.mjs → LegacyStateStore-DFO3aJgs.mjs} +2 -2
  6. package/dist/{LegacyStateStore-Ceq7A_75.mjs.map → LegacyStateStore-DFO3aJgs.mjs.map} +1 -1
  7. package/dist/{LegacyStateStore-Z-EKUGSX.cjs → LegacyStateStore-iUWVxrXU.cjs} +2 -2
  8. package/dist/{LegacyStateStore-Z-EKUGSX.cjs.map → LegacyStateStore-iUWVxrXU.cjs.map} +1 -1
  9. package/dist/{LocalStateStore-Bocb8dmZ.cjs → LocalStateStore-BsFHdSeA.cjs} +2 -2
  10. package/dist/{LocalStateStore-Bocb8dmZ.cjs.map → LocalStateStore-BsFHdSeA.cjs.map} +1 -1
  11. package/dist/{LocalStateStore-C72bwpG2.mjs → LocalStateStore-DIfuh0Z1.mjs} +2 -2
  12. package/dist/{LocalStateStore-C72bwpG2.mjs.map → LocalStateStore-DIfuh0Z1.mjs.map} +1 -1
  13. package/dist/{OpenApiTsGenerator-nu1r1NgB.mjs → OpenApiTsGenerator-ByRPMbBN.mjs} +34 -7
  14. package/dist/OpenApiTsGenerator-ByRPMbBN.mjs.map +1 -0
  15. package/dist/{OpenApiTsGenerator-CKBCckKz.cjs → OpenApiTsGenerator-CdUM6Hvv.cjs} +34 -7
  16. package/dist/OpenApiTsGenerator-CdUM6Hvv.cjs.map +1 -0
  17. package/dist/{S3StateStore-C9upSW5o.mjs → S3StateStore-DR2f78Dj.mjs} +2 -2
  18. package/dist/{S3StateStore-C9upSW5o.mjs.map → S3StateStore-DR2f78Dj.mjs.map} +1 -1
  19. package/dist/{S3StateStore-35YfcdL_.cjs → S3StateStore-ytvpIiv8.cjs} +2 -2
  20. package/dist/{S3StateStore-35YfcdL_.cjs.map → S3StateStore-ytvpIiv8.cjs.map} +1 -1
  21. package/dist/{SSMStateStore-dOmFO6g1.mjs → SSMStateStore-BZ3XL0Mr.mjs} +2 -2
  22. package/dist/{SSMStateStore-dOmFO6g1.mjs.map → SSMStateStore-BZ3XL0Mr.mjs.map} +1 -1
  23. package/dist/{SSMStateStore-W-Ps22AQ.cjs → SSMStateStore-C1JruCD9.cjs} +2 -2
  24. package/dist/{SSMStateStore-W-Ps22AQ.cjs.map → SSMStateStore-C1JruCD9.cjs.map} +1 -1
  25. package/dist/{SubscriberGenerator-CajwOa5W.cjs → SubscriberGenerator-CYriX5BV.cjs} +2 -2
  26. package/dist/{SubscriberGenerator-CajwOa5W.cjs.map → SubscriberGenerator-CYriX5BV.cjs.map} +1 -1
  27. package/dist/{SubscriberGenerator-5looQ3gB.mjs → SubscriberGenerator-DQZeGkDW.mjs} +2 -2
  28. package/dist/{SubscriberGenerator-5looQ3gB.mjs.map → SubscriberGenerator-DQZeGkDW.mjs.map} +1 -1
  29. package/dist/{add-DF9IHQov.cjs → add-Bwddb4KD.cjs} +3 -3
  30. package/dist/{add-DF9IHQov.cjs.map → add-Bwddb4KD.cjs.map} +1 -1
  31. package/dist/{add-Bn1bqt0c.mjs → add-DkBEZ5_s.mjs} +3 -3
  32. package/dist/{add-Bn1bqt0c.mjs.map → add-DkBEZ5_s.mjs.map} +1 -1
  33. package/dist/{bundler-Ba_LoFXI.mjs → bundler-B8TGsunu.mjs} +5 -5
  34. package/dist/{bundler-Ba_LoFXI.mjs.map → bundler-B8TGsunu.mjs.map} +1 -1
  35. package/dist/{bundler-DeIVbloM.cjs → bundler-BkH1kPEX.cjs} +5 -5
  36. package/dist/{bundler-DeIVbloM.cjs.map → bundler-BkH1kPEX.cjs.map} +1 -1
  37. package/dist/{cli-CznHL-4-.mjs → cli-BgDd4cZB.mjs} +3 -3
  38. package/dist/{cli-CznHL-4-.mjs.map → cli-BgDd4cZB.mjs.map} +1 -1
  39. package/dist/{cli-BB1KOkfo.cjs → cli-DO7DQqCq.cjs} +3 -3
  40. package/dist/{cli-BB1KOkfo.cjs.map → cli-DO7DQqCq.cjs.map} +1 -1
  41. package/dist/{compose-BxIsChn5.mjs → compose-BPJ9bUKp.mjs} +5 -5
  42. package/dist/{compose-BxIsChn5.mjs.map → compose-BPJ9bUKp.mjs.map} +1 -1
  43. package/dist/{compose-76ho0pUg.cjs → compose-CGyxYe-h.cjs} +5 -5
  44. package/dist/{compose-76ho0pUg.cjs.map → compose-CGyxYe-h.cjs.map} +1 -1
  45. package/dist/{config-L_6NivCp.d.mts → config-BBFiH4qk.d.mts} +2 -2
  46. package/dist/{config-L_6NivCp.d.mts.map → config-BBFiH4qk.d.mts.map} +1 -1
  47. package/dist/{config-Mr4rcXFC.d.cts → config-DMdzdO5u.d.cts} +2 -2
  48. package/dist/{config-Mr4rcXFC.d.cts.map → config-DMdzdO5u.d.cts.map} +1 -1
  49. package/dist/config.cjs +1 -1
  50. package/dist/config.d.cts +2 -2
  51. package/dist/config.d.mts +2 -2
  52. package/dist/config.mjs +1 -1
  53. package/dist/deploy/public.cjs +6 -6
  54. package/dist/deploy/public.d.cts +1 -1
  55. package/dist/deploy/public.d.cts.map +1 -1
  56. package/dist/deploy/public.d.mts +1 -1
  57. package/dist/deploy/public.d.mts.map +1 -1
  58. package/dist/deploy/public.mjs +6 -6
  59. package/dist/{deploy-BRUx9hiA.mjs → deploy-0XpZDYAr.mjs} +5 -5
  60. package/dist/{deploy-BRUx9hiA.mjs.map → deploy-0XpZDYAr.mjs.map} +1 -1
  61. package/dist/{deploy-DuHRWNeJ.cjs → deploy-BlZx6J5x.cjs} +5 -5
  62. package/dist/{deploy-DuHRWNeJ.cjs.map → deploy-BlZx6J5x.cjs.map} +1 -1
  63. package/dist/{dokploy-BTO37Co8.mjs → dokploy-Crh4uDmP.mjs} +2 -2
  64. package/dist/{dokploy-BTO37Co8.mjs.map → dokploy-Crh4uDmP.mjs.map} +1 -1
  65. package/dist/{dokploy-Q4iYDmls.cjs → dokploy-rjXmkuwH.cjs} +2 -2
  66. package/dist/{dokploy-Q4iYDmls.cjs.map → dokploy-rjXmkuwH.cjs.map} +1 -1
  67. package/dist/{drivers-Ch1rJitn.mjs → drivers-B4RP2B2O.mjs} +2 -2
  68. package/dist/{drivers-Ch1rJitn.mjs.map → drivers-B4RP2B2O.mjs.map} +1 -1
  69. package/dist/{drivers-BdvtCKc7.cjs → drivers-CJx76mcb.cjs} +2 -2
  70. package/dist/{drivers-BdvtCKc7.cjs.map → drivers-CJx76mcb.cjs.map} +1 -1
  71. package/dist/{encryption-BESGvjHD.mjs → encryption-0eo9aY_H.mjs} +3 -3
  72. package/dist/{encryption-BESGvjHD.mjs.map → encryption-0eo9aY_H.mjs.map} +1 -1
  73. package/dist/{encryption-9YA5ThNl.cjs → encryption-CxTfRx4h.cjs} +3 -3
  74. package/dist/{encryption-9YA5ThNl.cjs.map → encryption-CxTfRx4h.cjs.map} +1 -1
  75. package/dist/{engine-U0xzB5i4.cjs → engine-CMzSebbs.cjs} +4 -4
  76. package/dist/{engine-U0xzB5i4.cjs.map → engine-CMzSebbs.cjs.map} +1 -1
  77. package/dist/{engine-CHij99aX.mjs → engine-DxWswfXe.mjs} +4 -4
  78. package/dist/{engine-CHij99aX.mjs.map → engine-DxWswfXe.mjs.map} +1 -1
  79. package/dist/{github-BM-Y9M2G.cjs → github-Dukt5cJe.cjs} +3 -3
  80. package/dist/{github-BM-Y9M2G.cjs.map → github-Dukt5cJe.cjs.map} +1 -1
  81. package/dist/{github-2OSRBf9G.mjs → github-HOfOpFI_.mjs} +3 -3
  82. package/dist/{github-2OSRBf9G.mjs.map → github-HOfOpFI_.mjs.map} +1 -1
  83. package/dist/{index-DTEPwLml.d.cts → index-DFrbhRwg.d.cts} +6 -2
  84. package/dist/{index-C0UmP_lg.d.mts.map → index-DFrbhRwg.d.cts.map} +1 -1
  85. package/dist/{index-C0UmP_lg.d.mts → index-Wuqpf316.d.mts} +6 -2
  86. package/dist/{index-DTEPwLml.d.cts.map → index-Wuqpf316.d.mts.map} +1 -1
  87. package/dist/index.cjs +437 -117
  88. package/dist/index.cjs.map +1 -1
  89. package/dist/index.mjs +437 -117
  90. package/dist/index.mjs.map +1 -1
  91. package/dist/{migrate-KwZsJFce.mjs → migrate-1dGEzuJ-.mjs} +3 -3
  92. package/dist/{migrate-KwZsJFce.mjs.map → migrate-1dGEzuJ-.mjs.map} +1 -1
  93. package/dist/{migrate-C440QQvZ.cjs → migrate-Bemd4tkz.cjs} +3 -3
  94. package/dist/{migrate-C440QQvZ.cjs.map → migrate-Bemd4tkz.cjs.map} +1 -1
  95. package/dist/{migrate-BlYiMA23.cjs → migrate-BgPWVnAZ.cjs} +3 -3
  96. package/dist/{migrate-BlYiMA23.cjs.map → migrate-BgPWVnAZ.cjs.map} +1 -1
  97. package/dist/{migrate-3oLefufw.mjs → migrate-C14NNbFx.mjs} +3 -3
  98. package/dist/{migrate-3oLefufw.mjs.map → migrate-C14NNbFx.mjs.map} +1 -1
  99. package/dist/openapi.cjs +17 -12
  100. package/dist/openapi.cjs.map +1 -1
  101. package/dist/openapi.d.cts +28 -0
  102. package/dist/openapi.d.cts.map +1 -1
  103. package/dist/openapi.d.mts +28 -0
  104. package/dist/openapi.d.mts.map +1 -1
  105. package/dist/openapi.mjs +17 -13
  106. package/dist/openapi.mjs.map +1 -1
  107. package/dist/{ready-BB9xS4S9.cjs → ready-4kx2pAhm.cjs} +5 -5
  108. package/dist/{ready-BB9xS4S9.cjs.map → ready-4kx2pAhm.cjs.map} +1 -1
  109. package/dist/{ready-ZZoNskrr.mjs → ready-DhZbZtFw.mjs} +5 -5
  110. package/dist/{ready-ZZoNskrr.mjs.map → ready-DhZbZtFw.mjs.map} +1 -1
  111. package/dist/{resolve-CBrJTyDO.cjs → resolve-DCTcD823.cjs} +3 -3
  112. package/dist/{resolve-CBrJTyDO.cjs.map → resolve-DCTcD823.cjs.map} +1 -1
  113. package/dist/{resolve-BPIDcuQ3.mjs → resolve-y1PkSZrF.mjs} +3 -3
  114. package/dist/{resolve-BPIDcuQ3.mjs.map → resolve-y1PkSZrF.mjs.map} +1 -1
  115. package/dist/{rollback-P09wRaW4.cjs → rollback-BVQFDjxr.cjs} +5 -5
  116. package/dist/{rollback-P09wRaW4.cjs.map → rollback-BVQFDjxr.cjs.map} +1 -1
  117. package/dist/{rollback-B7uQKHEk.mjs → rollback-CwVhG_xa.mjs} +5 -5
  118. package/dist/{rollback-B7uQKHEk.mjs.map → rollback-CwVhG_xa.mjs.map} +1 -1
  119. package/dist/{seeds-B4PiO_48.mjs → seeds-BoKQ74Od.mjs} +15 -6
  120. package/dist/seeds-BoKQ74Od.mjs.map +1 -0
  121. package/dist/{seeds-BjHiy9tW.cjs → seeds-Ccju3zGl.cjs} +15 -6
  122. package/dist/{seeds-BjHiy9tW.cjs.map → seeds-Ccju3zGl.cjs.map} +1 -1
  123. package/dist/{sniffer-ByWtH28i.mjs → sniffer-6oYI-MpT.mjs} +6 -6
  124. package/dist/{sniffer-ByWtH28i.mjs.map → sniffer-6oYI-MpT.mjs.map} +1 -1
  125. package/dist/{sniffer-BjG-1mlD.cjs → sniffer-DeyYI9Iv.cjs} +6 -6
  126. package/dist/{sniffer-BjG-1mlD.cjs.map → sniffer-DeyYI9Iv.cjs.map} +1 -1
  127. package/dist/stages-CHF9RFog.mjs +174 -0
  128. package/dist/stages-CHF9RFog.mjs.map +1 -0
  129. package/dist/stages-CwrYVX9u.cjs +174 -0
  130. package/dist/stages-CwrYVX9u.cjs.map +1 -0
  131. package/dist/target/public.cjs +1 -1
  132. package/dist/target/public.mjs +1 -1
  133. package/dist/vitest.cjs +1 -1
  134. package/dist/vitest.mjs +1 -1
  135. package/dist/workspace/index.cjs +2 -1
  136. package/dist/workspace/index.d.cts +2 -2
  137. package/dist/workspace/index.d.mts +2 -2
  138. package/dist/workspace/index.mjs +2 -2
  139. package/dist/{workspace-Bp8FEkF-.cjs → workspace-4i6Jwsoa.cjs} +22 -2
  140. package/dist/{workspace-Bp8FEkF-.cjs.map → workspace-4i6Jwsoa.cjs.map} +1 -1
  141. package/dist/{workspace-BBdqmkch.mjs → workspace-DD9mtPy8.mjs} +11 -3
  142. package/dist/{workspace-BBdqmkch.mjs.map → workspace-DD9mtPy8.mjs.map} +1 -1
  143. package/package.json +15 -15
  144. package/dist/EndpointGenerator-CP6sBvQV.cjs.map +0 -1
  145. package/dist/EndpointGenerator-DftalLYg.mjs.map +0 -1
  146. package/dist/OpenApiTsGenerator-CKBCckKz.cjs.map +0 -1
  147. package/dist/OpenApiTsGenerator-nu1r1NgB.mjs.map +0 -1
  148. package/dist/seeds-B4PiO_48.mjs.map +0 -1
package/dist/index.cjs CHANGED
@@ -5,22 +5,22 @@ const require_run = require("./run-fVZ-rLnc.cjs");
5
5
  const require_credentials = require("./credentials-BVs7mrtw.cjs");
6
6
  const require_discover = require("./discover-D1It5r_h.cjs");
7
7
  const require_derive = require("./derive-DAbo49sm.cjs");
8
- const require_workspace = require("./workspace-Bp8FEkF-.cjs");
8
+ const require_workspace = require("./workspace-4i6Jwsoa.cjs");
9
9
  const require_config = require("./config.cjs");
10
- const require_seeds = require("./seeds-BjHiy9tW.cjs");
11
- const require_EndpointGenerator = require("./EndpointGenerator-CP6sBvQV.cjs");
10
+ const require_seeds = require("./seeds-Ccju3zGl.cjs");
11
+ const require_EndpointGenerator = require("./EndpointGenerator-cKlnllIu.cjs");
12
12
  const require_openapi = require("./openapi.cjs");
13
- const require_SubscriberGenerator = require("./SubscriberGenerator-CajwOa5W.cjs");
13
+ const require_SubscriberGenerator = require("./SubscriberGenerator-CYriX5BV.cjs");
14
14
  const require_appPorts = require("./appPorts-Cu79hJF6.cjs");
15
- const require_drivers = require("./drivers-BdvtCKc7.cjs");
15
+ const require_drivers = require("./drivers-CJx76mcb.cjs");
16
16
  const require_emit = require("./emit-Dmc1nvdS.cjs");
17
- const require_sniffer = require("./sniffer-BjG-1mlD.cjs");
18
- const require_deploy = require("./deploy-DuHRWNeJ.cjs");
19
- const require_compose = require("./compose-76ho0pUg.cjs");
17
+ const require_sniffer = require("./sniffer-DeyYI9Iv.cjs");
18
+ const require_deploy = require("./deploy-BlZx6J5x.cjs");
19
+ const require_compose = require("./compose-CGyxYe-h.cjs");
20
20
  const require_credentialSchemas = require("./credentialSchemas-DCR4Wd1W.cjs");
21
- const require_LocalStateStore = require("./LocalStateStore-Bocb8dmZ.cjs");
21
+ const require_LocalStateStore = require("./LocalStateStore-BsFHdSeA.cjs");
22
22
  const require_utils = require("./utils-D2Nk1Nv2.cjs");
23
- const require_ready = require("./ready-BB9xS4S9.cjs");
23
+ const require_ready = require("./ready-4kx2pAhm.cjs");
24
24
  let node_path = require("node:path");
25
25
  let commander = require("commander");
26
26
  let node_process = require("node:process");
@@ -53,7 +53,7 @@ crypto = require_rolldown_runtime.__toESM(crypto, 1);
53
53
  let _geekmidas_constructs_functions = require("@geekmidas/constructs/functions");
54
54
  let _geekmidas_constructs_topic = require("@geekmidas/constructs/topic");
55
55
  //#region package.json
56
- var version = "10.0.0-alpha.81";
56
+ var version = "10.0.0-alpha.83";
57
57
  //#endregion
58
58
  //#region src/prompt.ts
59
59
  /**
@@ -136,7 +136,7 @@ const logger$8 = console;
136
136
  * Validate Dokploy token by making a test API call
137
137
  */
138
138
  async function validateDokployToken(endpoint, token) {
139
- const { DokployApi } = await Promise.resolve().then(() => require("./sniffer-BjG-1mlD.cjs")).then((n) => n.dokploy_api_exports);
139
+ const { DokployApi } = await Promise.resolve().then(() => require("./sniffer-DeyYI9Iv.cjs")).then((n) => n.dokploy_api_exports);
140
140
  return new DokployApi({
141
141
  baseUrl: endpoint,
142
142
  token
@@ -2217,9 +2217,9 @@ async function workspaceDevCommand(configured, options) {
2217
2217
  for (const { id, port } of fakes) logger$5.log(`🎭 ${id} fake: http://localhost:${port}`);
2218
2218
  logger$5.log(options.migrate || options.seed ? "🗄️ Migrating the databases" : "🗄️ Checking for pending migrations");
2219
2219
  if (options.migrate || options.seed) {
2220
- const { prepareDevDatabases } = await Promise.resolve().then(() => require("./migrate-BlYiMA23.cjs"));
2220
+ const { prepareDevDatabases } = await Promise.resolve().then(() => require("./migrate-BgPWVnAZ.cjs"));
2221
2221
  await prepareDevDatabases(workspace, reconciled.env, { seed: !!options.seed });
2222
- } else await Promise.resolve().then(() => require("./migrate-BlYiMA23.cjs")).then(({ reportPendingMigrations }) => reportPendingMigrations(workspace, reconciled.env)).catch((error) => {
2222
+ } else await Promise.resolve().then(() => require("./migrate-BgPWVnAZ.cjs")).then(({ reportPendingMigrations }) => reportPendingMigrations(workspace, reconciled.env)).catch((error) => {
2223
2223
  logger$5.log(`⚠️ Could not check for pending migrations: ${error instanceof Error ? error.message : String(error)}`);
2224
2224
  });
2225
2225
  const appUrls = {};
@@ -3227,7 +3227,7 @@ async function buildApp(input) {
3227
3227
  if (production?.bundle && !input.skipBundle) {
3228
3228
  const outputDir = (0, node_path.join)(appRoot, ".gkm", "server");
3229
3229
  const entryPoint = await writeSurfaceServer(outputDir, production);
3230
- const { bundleServer } = await Promise.resolve().then(() => require("./bundler-DeIVbloM.cjs"));
3230
+ const { bundleServer } = await Promise.resolve().then(() => require("./bundler-BkH1kPEX.cjs"));
3231
3231
  await bundleServer({
3232
3232
  entryPoint,
3233
3233
  outputDir: (0, node_path.join)(outputDir, "dist"),
@@ -3351,7 +3351,7 @@ async function buildWorkers(input) {
3351
3351
  });
3352
3352
  logger$4.log(`Generated worker ${worker.id}: ${crons.length} crons, ${queues.length} queues, ${subscribers.length} subscribers`);
3353
3353
  if (!input.bundle) continue;
3354
- const { bundleServer } = await Promise.resolve().then(() => require("./bundler-DeIVbloM.cjs"));
3354
+ const { bundleServer } = await Promise.resolve().then(() => require("./bundler-BkH1kPEX.cjs"));
3355
3355
  const outfile = require_seeds.workerBundleName(worker.id);
3356
3356
  await bundleServer({
3357
3357
  entryPoint,
@@ -3421,7 +3421,7 @@ async function buildForTarget(target, context, appRoot, workspaceRoot, endpointG
3421
3421
  let masterKey;
3422
3422
  if (context.production?.bundle && !skipBundle) {
3423
3423
  logger$4.log(`\n📦 Bundling production server...`);
3424
- const { bundleServer } = await Promise.resolve().then(() => require("./bundler-DeIVbloM.cjs"));
3424
+ const { bundleServer } = await Promise.resolve().then(() => require("./bundler-BkH1kPEX.cjs"));
3425
3425
  const allConstructs = [
3426
3426
  ...endpoints.map((e) => e.construct),
3427
3427
  ...functions.map((f) => f.construct),
@@ -5108,12 +5108,12 @@ const PNPM_VERSION = "pnpm@10.13.1";
5108
5108
  const BIOME_SCHEMA = `https://biomejs.dev/schemas/${DEPENDENCY_VERSIONS["@biomejs/biome"].replace(/^[~^]/, "")}/schema.json`;
5109
5109
  //#endregion
5110
5110
  //#region src/init/versions.ts
5111
- const require$1 = (0, node_module.createRequire)(require("url").pathToFileURL(__filename).href);
5111
+ const require$2 = (0, node_module.createRequire)(require("url").pathToFileURL(__filename).href);
5112
5112
  function loadPackageJson() {
5113
5113
  try {
5114
- return require$1("../package.json");
5114
+ return require$2("../package.json");
5115
5115
  } catch {
5116
- return require$1("../../package.json");
5116
+ return require$2("../../package.json");
5117
5117
  }
5118
5118
  }
5119
5119
  /**
@@ -5123,25 +5123,25 @@ function loadPackageJson() {
5123
5123
  * Run: pnpm --filter @geekmidas/cli sync-versions
5124
5124
  */
5125
5125
  const GEEKMIDAS_VERSIONS = {
5126
- "@geekmidas/audit": "~10.0.0-alpha.81",
5127
- "@geekmidas/auth": "~10.0.0-alpha.81",
5128
- "@geekmidas/cache": "~10.0.0-alpha.81",
5129
- "@geekmidas/client": "~10.0.0-alpha.81",
5130
- "@geekmidas/cloud": "~10.0.0-alpha.81",
5131
- "@geekmidas/constructs": "~10.0.0-alpha.81",
5132
- "@geekmidas/db": "~10.0.0-alpha.81",
5133
- "@geekmidas/emailkit": "~10.0.0-alpha.81",
5134
- "@geekmidas/envkit": "~10.0.0-alpha.81",
5135
- "@geekmidas/errors": "~10.0.0-alpha.81",
5136
- "@geekmidas/events": "~10.0.0-alpha.81",
5137
- "@geekmidas/logger": "~10.0.0-alpha.81",
5138
- "@geekmidas/manifest": "~10.0.0-alpha.81",
5139
- "@geekmidas/rate-limit": "~10.0.0-alpha.81",
5140
- "@geekmidas/schema": "~10.0.0-alpha.81",
5141
- "@geekmidas/services": "~10.0.0-alpha.81",
5142
- "@geekmidas/storage": "~10.0.0-alpha.81",
5143
- "@geekmidas/telescope": "~10.0.0-alpha.81",
5144
- "@geekmidas/testkit": "~10.0.0-alpha.81",
5126
+ "@geekmidas/audit": "~10.0.0-alpha.83",
5127
+ "@geekmidas/auth": "~10.0.0-alpha.83",
5128
+ "@geekmidas/cache": "~10.0.0-alpha.83",
5129
+ "@geekmidas/client": "~10.0.0-alpha.83",
5130
+ "@geekmidas/cloud": "~10.0.0-alpha.83",
5131
+ "@geekmidas/constructs": "~10.0.0-alpha.83",
5132
+ "@geekmidas/db": "~10.0.0-alpha.83",
5133
+ "@geekmidas/emailkit": "~10.0.0-alpha.83",
5134
+ "@geekmidas/envkit": "~10.0.0-alpha.83",
5135
+ "@geekmidas/errors": "~10.0.0-alpha.83",
5136
+ "@geekmidas/events": "~10.0.0-alpha.83",
5137
+ "@geekmidas/logger": "~10.0.0-alpha.83",
5138
+ "@geekmidas/manifest": "~10.0.0-alpha.83",
5139
+ "@geekmidas/rate-limit": "~10.0.0-alpha.83",
5140
+ "@geekmidas/schema": "~10.0.0-alpha.83",
5141
+ "@geekmidas/services": "~10.0.0-alpha.83",
5142
+ "@geekmidas/storage": "~10.0.0-alpha.83",
5143
+ "@geekmidas/telescope": "~10.0.0-alpha.83",
5144
+ "@geekmidas/testkit": "~10.0.0-alpha.83",
5145
5145
  "@geekmidas/cli": `~${loadPackageJson().version}`
5146
5146
  };
5147
5147
  //#endregion
@@ -5514,6 +5514,38 @@ coverage/
5514
5514
  return files;
5515
5515
  }
5516
5516
  //#endregion
5517
+ //#region src/init/stagesAction.ts
5518
+ /**
5519
+ * How a scaffolded workflow names the `stages` action.
5520
+ *
5521
+ * A published CLI pins it to the commit it was released from: the release
5522
+ * build is given that commit as `GKM_RELEASE_COMMIT`, which the build writes
5523
+ * into the bundle (`define` in tsdown.config.ts). The action at that commit is
5524
+ * the one released beside this CLI, and a commit SHA cannot be moved under a
5525
+ * project the way a branch or a tag can.
5526
+ *
5527
+ * A CLI built anywhere else — a checkout, a local build — knows no released
5528
+ * commit, and names `main`.
5529
+ */
5530
+ const require$1 = (0, node_module.createRequire)(require("url").pathToFileURL(__filename).href);
5531
+ function cliVersion() {
5532
+ try {
5533
+ return require$1("../package.json").version;
5534
+ } catch {
5535
+ return require$1("../../package.json").version;
5536
+ }
5537
+ }
5538
+ /** The action, as a workflow's `uses:` names it before the `@`. */
5539
+ const STAGES_ACTION = "geekmidas/toolbox/actions/stages";
5540
+ const COMMIT = /^[0-9a-f]{40}$/;
5541
+ /**
5542
+ * The `uses:` value for the stages action, with a comment saying which CLI
5543
+ * release the pinned commit is.
5544
+ */
5545
+ function stagesActionUses(commit = "4dee60bc593ffdfbaa59bbf8d8fe9e3e64f23d41", version = cliVersion()) {
5546
+ return commit && COMMIT.test(commit) ? `${STAGES_ACTION}@${commit} # @geekmidas/cli ${version}` : `${STAGES_ACTION}@main # pin to a commit SHA: see the action's README`;
5547
+ }
5548
+ //#endregion
5517
5549
  //#region src/init/generators/github.ts
5518
5550
  /**
5519
5551
  * The GitHub workflows a scaffold ships with.
@@ -5523,11 +5555,14 @@ coverage/
5523
5555
  * release, labelled from their titles.
5524
5556
  * - `deploy.yml` — when a deploy target was picked: a push to main deploys the
5525
5557
  * stages that are not protected, publishing the drafted release deploys the
5526
- * protected ones.
5558
+ * protected ones, and a manual run deploys the one stage it names.
5527
5559
  *
5528
- * The deploy workflow names no stage. It reads `stages` from gkm.config.ts at
5529
- * run time, so the config stays the one place stages are declared and a
5530
- * workflow cannot fall out of step with it.
5560
+ * The deploy workflow names no stage. Its first job runs the
5561
+ * `geekmidas/toolbox/actions/stages` action, which asks the project's own
5562
+ * `gkm stages --github-output` which stages the run builds and deploys — so
5563
+ * the config stays the one place stages are declared, the rules for each event
5564
+ * are tested code in the CLI, and a workflow cannot fall out of step with
5565
+ * either.
5531
5566
  */
5532
5567
  /** How each package manager is set up, installs, and runs a script. */
5533
5568
  const TOOLING = {
@@ -5713,46 +5748,21 @@ template: |
5713
5748
  **Full Changelog**: https://github.com/$OWNER/$REPOSITORY/compare/$PREVIOUS_TAG...v$RESOLVED_VERSION
5714
5749
  `;
5715
5750
  }
5716
- function deploy(options) {
5717
- const pm = tooling(options);
5718
- const sst = options.deployTarget === "sst";
5719
- const credentials = sst ? `
5720
- # An IAM role GitHub assumes through OIDC — no long-lived AWS keys. Set
5721
- # AWS_ROLE_ARN as a variable on each environment.
5722
- - uses: aws-actions/configure-aws-credentials@v4
5723
- with:
5724
- role-to-assume: \${{ vars.AWS_ROLE_ARN }}
5725
- aws-region: ${options.region}
5726
- ` : "";
5727
- const keyDir = `~/.gkm/keys/${require_seeds.projectKey({ name: options.name })}`;
5728
- const stageSecrets = sst ? credentials : `
5729
- # The stage's secrets are kept in the encrypted .gkm/secrets/<stage>.json,
5730
- # and each environment holds its key as GKM_SECRETS_KEY. .gkm/ is
5731
- # gitignored, so a checkout has the key but not the file: set
5732
- # secrets.store in gkm.config.ts to a store CI can reach before deploying
5733
- # from here.
5734
- # Owner-only, as the CLI writes its own keys. The stage reaches the shell
5735
- # as a variable, never pasted into the script: on a manual run it is
5736
- # whatever was typed.
5737
- - name: Stage secrets key
5738
- run: |
5739
- mkdir -p -m 700 ${keyDir}
5740
- (umask 077 && printf '%s' "$KEY" > ${keyDir}/"$STAGE".key)
5741
- env:
5742
- KEY: \${{ secrets.GKM_SECRETS_KEY }}
5743
- STAGE: \${{ matrix.stage }}
5744
- `;
5745
- const deployEnv = sst ? "" : `
5746
- DOKPLOY_API_TOKEN: \${{ secrets.DOKPLOY_API_TOKEN }}
5747
- DOKPLOY_ENDPOINT: \${{ vars.DOKPLOY_ENDPOINT }}`;
5751
+ /**
5752
+ * What every deploy workflow starts with: its triggers, and the `stages` job,
5753
+ * which asks the project's own gkm (through the stages action) which stages
5754
+ * this run builds and deploys. Nothing in a workflow names a stage.
5755
+ */
5756
+ function deployHeader(build) {
5748
5757
  return `name: Deploy
5749
5758
 
5750
5759
  # Which stages exist, and which are protected, is read from \`stages\` in
5751
- # gkm.config.ts — nothing here names one:
5760
+ # gkm.config.ts by the project's own gkm, through the stages action — nothing
5761
+ # here names one:
5752
5762
  #
5753
- # push to main every deployed stage that is not protected
5763
+ # push to main ${build ? "builds every deployed stage, deploys those not protected" : "every deployed stage that is not protected"}
5754
5764
  # release published the protected stages (publish the drafted release)
5755
- # run workflow the one stage you name
5765
+ # run workflow the one stage you name, at the ref you name
5756
5766
  on:
5757
5767
  push:
5758
5768
  branches: [main]
@@ -5763,17 +5773,27 @@ on:
5763
5773
  stage:
5764
5774
  description: A deployed stage from gkm.config.ts
5765
5775
  required: true
5776
+ type: string
5777
+ ref:
5778
+ description: The commit, tag or branch to deploy (default the latest on main)
5779
+ required: false
5780
+ type: string
5766
5781
 
5767
5782
  permissions:
5768
5783
  contents: read
5769
- id-token: write
5770
-
5771
- jobs:
5772
- stages:
5784
+ `;
5785
+ }
5786
+ function stagesJob(options) {
5787
+ const pm = tooling(options);
5788
+ return ` stages:
5773
5789
  name: Pick stages
5774
5790
  runs-on: ubuntu-latest
5775
5791
  outputs:
5776
- stages: \${{ steps.pick.outputs.stages }}
5792
+ build: \${{ steps.stages.outputs.build }}
5793
+ deploy: \${{ steps.stages.outputs.deploy }}
5794
+ has-build: \${{ steps.stages.outputs.has-build }}
5795
+ has-deploy: \${{ steps.stages.outputs.has-deploy }}
5796
+ aws-region: \${{ steps.stages.outputs.aws-region }}
5777
5797
  steps:
5778
5798
  - uses: actions/checkout@v4
5779
5799
 
@@ -5781,44 +5801,286 @@ ${pm.setup}
5781
5801
  - name: Install
5782
5802
  run: ${pm.install}
5783
5803
 
5804
+ # Runs \`gkm stages --github-output\`: the rules for each event are the
5805
+ # installed CLI's, and a manual run naming a stage gkm.config.ts does not
5806
+ # deploy fails here.
5784
5807
  - name: Read stages from gkm.config.ts
5785
- id: pick
5808
+ id: stages
5809
+ uses: ${stagesActionUses()}
5810
+ with:
5811
+ stage: \${{ inputs.stage }}
5812
+ `;
5813
+ }
5814
+ /**
5815
+ * The registry login a compose build pushes with: GitHub's own token on
5816
+ * ghcr.io, otherwise a username variable and a password secret.
5817
+ */
5818
+ function registryLogin(registry) {
5819
+ const host = registry.split("/")[0];
5820
+ const ghcr = host === "ghcr.io";
5821
+ return ` - uses: docker/login-action@v3
5822
+ with:
5823
+ registry: ${host}
5824
+ username: ${ghcr ? "${{ github.actor }}" : "${{ vars.REGISTRY_USERNAME }}"}
5825
+ password: ${ghcr ? "${{ secrets.GITHUB_TOKEN }}" : "${{ secrets.REGISTRY_PASSWORD }}"}
5826
+ `;
5827
+ }
5828
+ /**
5829
+ * The compose deploy: images are built and pushed by the runner, where the
5830
+ * code is, and pulled by the server, where the stage runs.
5831
+ *
5832
+ * - `build` (on a push): every deployed stage's images, tagged with the
5833
+ * commit, and their digests kept as the artifact `digests-<stage>`.
5834
+ * - `deploy`: the commit the event names — a release's tag, a manual run's
5835
+ * `ref` — then that commit's push build, whose digests pin each image. Over
5836
+ * SSH, with a pinned host key, the server checks the commit out and runs
5837
+ * `gkm compose` on exactly those images.
5838
+ */
5839
+ function composeDeploy(options) {
5840
+ const pm = tooling(options);
5841
+ const registry = options.registry ?? "";
5842
+ return `${deployHeader(true)}
5843
+ jobs:
5844
+ ${stagesJob(options)}
5845
+ build:
5846
+ name: Build \${{ matrix.stage }}
5847
+ needs: stages
5848
+ if: needs.stages.outputs.has-build == 'true'
5849
+ runs-on: ubuntu-latest
5850
+ strategy:
5851
+ fail-fast: false
5852
+ matrix:
5853
+ stage: \${{ fromJSON(needs.stages.outputs.build) }}
5854
+ # One GitHub environment per stage: its secrets, variables and approvals.
5855
+ environment: \${{ matrix.stage }}
5856
+ permissions:
5857
+ contents: read
5858
+ packages: write
5859
+ id-token: write
5860
+ steps:
5861
+ - uses: actions/checkout@v4
5862
+
5863
+ ${pm.setup}
5864
+ - name: Install
5865
+ run: ${pm.install}
5866
+
5867
+ ${registryLogin(registry)}
5868
+ # A site's public URLs are built into it, so the build reads the stage's
5869
+ # secrets store. With secrets.store on SSM or Secrets Manager the job
5870
+ # assumes the stage's role (AWS_ROLE_ARN, set by gkm deploy:github);
5871
+ # with the default 'file' store there is no role to assume.
5872
+ - name: Assume the stage's AWS role
5873
+ if: needs.stages.outputs.aws-region != ''
5874
+ uses: aws-actions/configure-aws-credentials@v4
5875
+ with:
5876
+ role-to-assume: \${{ vars.AWS_ROLE_ARN }}
5877
+ aws-region: \${{ needs.stages.outputs.aws-region }}
5878
+
5879
+ # Builds and pushes every image the stage runs, tagged with the commit,
5880
+ # and starts nothing.
5881
+ - name: Build and push
5882
+ run: ${pm.exec} gkm compose --stage "$STAGE" --build --push --tag "$SHA" --digests-file digests.json
5883
+ env:
5884
+ STAGE: \${{ matrix.stage }}
5885
+ SHA: \${{ github.sha }}
5886
+
5887
+ # What each tag pointed at when it was pushed. A deploy runs these
5888
+ # digests, so a tag moved since cannot change what is released.
5889
+ - uses: actions/upload-artifact@v4
5890
+ with:
5891
+ name: digests-\${{ matrix.stage }}
5892
+ path: digests.json
5893
+ retention-days: 90
5894
+
5895
+ deploy:
5896
+ name: Deploy \${{ matrix.stage }}
5897
+ needs: [stages, build]
5898
+ # The build is skipped on a release or a manual run: deploy then anyway,
5899
+ # but never after a failed build.
5900
+ if: \${{ !cancelled() && !failure() && needs.stages.outputs.has-deploy == 'true' }}
5901
+ runs-on: ubuntu-latest
5902
+ strategy:
5903
+ fail-fast: false
5904
+ matrix:
5905
+ stage: \${{ fromJSON(needs.stages.outputs.deploy) }}
5906
+ environment: \${{ matrix.stage }}
5907
+ concurrency:
5908
+ group: deploy-\${{ matrix.stage }}
5909
+ cancel-in-progress: false
5910
+ permissions:
5911
+ contents: read
5912
+ actions: read
5913
+ steps:
5914
+ # A release deploys its tag's commit, never its target_commitish — the
5915
+ # branch it was drafted against, which has moved on since.
5916
+ - name: Resolve the commit
5917
+ id: commit
5918
+ run: |
5919
+ case "$EVENT" in
5920
+ release) ref="tags/$TAG" ;;
5921
+ workflow_dispatch) ref="\${REF:-$SHA}" ;;
5922
+ *) ref="$SHA" ;;
5923
+ esac
5924
+ sha=$(gh api "repos/$REPO/commits/$ref" --jq .sha)
5925
+ echo "Deploying $sha"
5926
+ echo "sha=$sha" >> "$GITHUB_OUTPUT"
5927
+ env:
5928
+ GH_TOKEN: \${{ github.token }}
5929
+ REPO: \${{ github.repository }}
5930
+ EVENT: \${{ github.event_name }}
5931
+ TAG: \${{ github.event.release.tag_name }}
5932
+ REF: \${{ inputs.ref }}
5933
+ SHA: \${{ github.sha }}
5934
+
5935
+ # The push run of this workflow that built the commit for this stage:
5936
+ # this run on a push, the newest one with the stage's digests otherwise.
5937
+ - name: Find the commit's push build
5938
+ id: build
5786
5939
  run: |
5787
- ${pm.exec} tsx -e "
5788
- import config from './gkm.config.ts';
5789
- const { deployed, protected: kept = [] } = config.stages;
5790
- const event = process.env.EVENT;
5791
- if (event === 'workflow_dispatch' && !deployed.includes(process.env.STAGE)) {
5792
- console.error('Not a deployed stage: ' + process.env.STAGE + ' (deployed: ' + deployed.join(', ') + ')');
5793
- process.exit(1);
5794
- }
5795
- const stages =
5796
- event === 'workflow_dispatch' ? [process.env.STAGE]
5797
- : event === 'release' ? kept
5798
- : deployed.filter((stage) => !kept.includes(stage));
5799
- console.log('stages=' + JSON.stringify(stages));
5800
- " >> "$GITHUB_OUTPUT"
5940
+ if [ "$EVENT" = push ]; then
5941
+ echo "run-id=$RUN_ID" >> "$GITHUB_OUTPUT"
5942
+ exit 0
5943
+ fi
5944
+ workflow=\${WORKFLOW_REF%%@*}
5945
+ workflow=\${workflow##*/}
5946
+ for id in $(gh run list --repo "$REPO" --workflow "$workflow" --event push --commit "$SHA" --limit 20 --json databaseId --jq '.[].databaseId'); do
5947
+ found=$(gh api "repos/$REPO/actions/runs/$id/artifacts?name=$ARTIFACT" --jq '[.artifacts[] | select(.expired | not)] | length')
5948
+ if [ "$found" -gt 0 ]; then
5949
+ echo "run-id=$id" >> "$GITHUB_OUTPUT"
5950
+ exit 0
5951
+ fi
5952
+ done
5953
+ echo "run-id=" >> "$GITHUB_OUTPUT"
5801
5954
  env:
5955
+ GH_TOKEN: \${{ github.token }}
5956
+ REPO: \${{ github.repository }}
5802
5957
  EVENT: \${{ github.event_name }}
5803
- STAGE: \${{ inputs.stage }}
5958
+ RUN_ID: \${{ github.run_id }}
5959
+ WORKFLOW_REF: \${{ github.workflow_ref }}
5960
+ SHA: \${{ steps.commit.outputs.sha }}
5961
+ ARTIFACT: digests-\${{ matrix.stage }}
5962
+
5963
+ - name: Download digests-\${{ matrix.stage }}
5964
+ if: steps.build.outputs.run-id != ''
5965
+ uses: actions/download-artifact@v4
5966
+ with:
5967
+ name: digests-\${{ matrix.stage }}
5968
+ run-id: \${{ steps.build.outputs.run-id }}
5969
+ github-token: \${{ github.token }}
5804
5970
 
5971
+ - name: No digests — deploying by tag
5972
+ if: steps.build.outputs.run-id == ''
5973
+ run: |
5974
+ echo "::warning title=$STAGE deploys by tag, not digest::No push build of $SHA kept digests-$STAGE (never built, or older than 90 days). The server runs whatever the tag $SHA points at in the registry now, which anyone who can push there could have replaced."
5975
+ env:
5976
+ STAGE: \${{ matrix.stage }}
5977
+ SHA: \${{ steps.commit.outputs.sha }}
5978
+
5979
+ # Each environment holds DEPLOY_SSH_KEY (secret) and DEPLOY_KNOWN_HOSTS,
5980
+ # DEPLOY_HOST, DEPLOY_USER and DEPLOY_PATH (variables): the server's
5981
+ # host key is pinned, never accepted on first sight. DEPLOY_PATH is a
5982
+ # clone of this repository, with a docker login to ${registry.split("/")[0]}
5983
+ # and the stage's secrets.
5984
+ #
5985
+ # Every value reaches the server as an argument to a quoted heredoc —
5986
+ # nothing is pasted into the script.
5987
+ - name: Deploy on the server
5988
+ run: |
5989
+ mkdir -p ~/.ssh && chmod 700 ~/.ssh
5990
+ (umask 077 && printf '%s\\n' "$SSH_KEY" > ~/.ssh/deploy_key)
5991
+ printf '%s\\n' "$KNOWN_HOSTS" > ~/.ssh/known_hosts
5992
+ digests=""
5993
+ if [ -f digests.json ]; then digests=$(base64 -w0 < digests.json); fi
5994
+ ssh -i ~/.ssh/deploy_key -o IdentitiesOnly=yes -o StrictHostKeyChecking=yes \\
5995
+ "$DEPLOY_USER@$DEPLOY_HOST" \\
5996
+ "bash -s -- $(printf '%q ' "$STAGE" "$SHA" "$DEPLOY_PATH" "$digests")" <<'REMOTE'
5997
+ set -euo pipefail
5998
+ stage=$1 sha=$2 dir=$3 digests=$4
5999
+ cd "$dir"
6000
+ git fetch --quiet origin
6001
+ git checkout --quiet --detach "$sha"
6002
+ ${pm.install}
6003
+ args=(--stage "$stage" --tag "$sha")
6004
+ if [ -n "$digests" ]; then
6005
+ mkdir -p .gkm
6006
+ printf '%s' "$digests" | base64 -d > ".gkm/digests-$stage.json"
6007
+ args+=(--digests-file ".gkm/digests-$stage.json")
6008
+ fi
6009
+ ${pm.exec} gkm compose "\${args[@]}"
6010
+ REMOTE
6011
+ env:
6012
+ SSH_KEY: \${{ secrets.DEPLOY_SSH_KEY }}
6013
+ KNOWN_HOSTS: \${{ vars.DEPLOY_KNOWN_HOSTS }}
6014
+ DEPLOY_HOST: \${{ vars.DEPLOY_HOST }}
6015
+ DEPLOY_USER: \${{ vars.DEPLOY_USER }}
6016
+ DEPLOY_PATH: \${{ vars.DEPLOY_PATH }}
6017
+ STAGE: \${{ matrix.stage }}
6018
+ SHA: \${{ steps.commit.outputs.sha }}
6019
+ `;
6020
+ }
6021
+ /**
6022
+ * Dokploy and SST: `gkm deploy` builds, releases and health-checks a stage in
6023
+ * one step, from a checkout, so there is no separate build job — the stages
6024
+ * job's `deploy` list is the matrix, and `build` goes unused.
6025
+ */
6026
+ function targetDeploy(options) {
6027
+ const pm = tooling(options);
6028
+ const sst = options.deployTarget === "sst";
6029
+ const credentials = sst ? `
6030
+ # An IAM role GitHub assumes through OIDC — no long-lived AWS keys. Set
6031
+ # AWS_ROLE_ARN as a variable on each environment.
6032
+ - uses: aws-actions/configure-aws-credentials@v4
6033
+ with:
6034
+ role-to-assume: \${{ vars.AWS_ROLE_ARN }}
6035
+ aws-region: ${options.region}
6036
+ ` : "";
6037
+ const keyDir = `~/.gkm/keys/${require_seeds.projectKey({ name: options.name })}`;
6038
+ const stageSecrets = sst ? credentials : `
6039
+ # The stage's secrets are kept in the encrypted .gkm/secrets/<stage>.json,
6040
+ # and each environment holds its key as GKM_SECRETS_KEY. .gkm/ is
6041
+ # gitignored, so a checkout has the key but not the file: set
6042
+ # secrets.store in gkm.config.ts to a store CI can reach before deploying
6043
+ # from here.
6044
+ # Owner-only, as the CLI writes its own keys. The stage reaches the shell
6045
+ # as a variable, never pasted into the script: on a manual run it is
6046
+ # whatever was typed.
6047
+ - name: Stage secrets key
6048
+ run: |
6049
+ mkdir -p ${keyDir} && chmod 700 ${keyDir}
6050
+ (umask 077 && printf '%s' "$KEY" > ${keyDir}/"$STAGE".key)
6051
+ env:
6052
+ KEY: \${{ secrets.GKM_SECRETS_KEY }}
6053
+ STAGE: \${{ matrix.stage }}
6054
+ `;
6055
+ const deployEnv = sst ? "" : `
6056
+ DOKPLOY_API_TOKEN: \${{ secrets.DOKPLOY_API_TOKEN }}
6057
+ DOKPLOY_ENDPOINT: \${{ vars.DOKPLOY_ENDPOINT }}`;
6058
+ return `${deployHeader(false)}
6059
+ jobs:
6060
+ ${stagesJob(options)}
5805
6061
  deploy:
5806
6062
  name: Deploy \${{ matrix.stage }}
5807
6063
  needs: stages
5808
- if: needs.stages.outputs.stages != '[]'
6064
+ if: needs.stages.outputs.has-deploy == 'true'
5809
6065
  runs-on: ubuntu-latest
5810
6066
  strategy:
5811
6067
  fail-fast: false
5812
6068
  matrix:
5813
- stage: \${{ fromJSON(needs.stages.outputs.stages) }}
6069
+ stage: \${{ fromJSON(needs.stages.outputs.deploy) }}
5814
6070
  # One GitHub environment per stage: its secrets and variables, and any
5815
6071
  # approval rule you put on a protected one.
5816
6072
  environment: \${{ matrix.stage }}
5817
6073
  concurrency:
5818
6074
  group: deploy-\${{ matrix.stage }}
5819
6075
  cancel-in-progress: false
6076
+ permissions:
6077
+ contents: read${sst ? "\n id-token: write" : ""}
5820
6078
  steps:
6079
+ # The event's own commit — a release's tag, the push — or the ref a
6080
+ # manual run names.
5821
6081
  - uses: actions/checkout@v4
6082
+ with:
6083
+ ref: \${{ inputs.ref }}
5822
6084
 
5823
6085
  ${pm.setup}
5824
6086
  - name: Install
@@ -5832,6 +6094,9 @@ ${stageSecrets}
5832
6094
  STAGE: \${{ matrix.stage }}${deployEnv}
5833
6095
  `;
5834
6096
  }
6097
+ function deploy(options) {
6098
+ return options.deployTarget === "compose" ? composeDeploy(options) : targetDeploy(options);
6099
+ }
5835
6100
  function generateGithubFiles(options) {
5836
6101
  const files = [
5837
6102
  {
@@ -6672,6 +6937,11 @@ export type ListUsersResponse = z.infer<typeof ListUsersResponseSchema>;
6672
6937
  const perStage = (options, command) => Object.fromEntries(options.stages.deployed.map((stage) => [`deploy:${stage}`, command(stage)]));
6673
6938
  function deployPackage(options) {
6674
6939
  switch (options.deployTarget) {
6940
+ case "compose": return {
6941
+ scripts: perStage(options, (stage) => `gkm compose --stage ${stage}`),
6942
+ dependencies: {},
6943
+ devDependencies: {}
6944
+ };
6675
6945
  case "dokploy": return {
6676
6946
  scripts: perStage(options, (stage) => `gkm deploy --stage ${stage}`),
6677
6947
  dependencies: {},
@@ -7181,6 +7451,13 @@ ${workspaceConstructsGlobs(options.routesStructure, (0, node_path.dirname)(optio
7181
7451
  * `gkm build` builds for, and which backends a cache or a broker resolves to.
7182
7452
  */
7183
7453
  function deployBlock(options) {
7454
+ if (options.deployTarget === "compose") return `
7455
+ // \`gkm compose --stage <stage>\` runs a stage as one Docker Compose stack on
7456
+ // the machine it runs on. CI builds every image and pushes it here; the
7457
+ // server pulls exactly those. On ghcr.io the owner is the repository's —
7458
+ // the user or organisation whose packages the workflow's token can write.
7459
+ deploy: { default: 'compose', registry: '${options.registry}' },
7460
+ `;
7184
7461
  if (options.deployTarget !== "sst") return "";
7185
7462
  return `
7186
7463
  // \`gkm deploy\` runs \`sst deploy\` on the manifest \`gkm build\` writes to
@@ -9757,6 +10034,11 @@ const deployTargetChoices = [
9757
10034
  value: "dokploy",
9758
10035
  description: "Deploy to Dokploy (Docker-based hosting)"
9759
10036
  },
10037
+ {
10038
+ title: "Server (Docker Compose)",
10039
+ value: "compose",
10040
+ description: "One Docker Compose stack per stage on your own server; CI builds the images"
10041
+ },
9760
10042
  {
9761
10043
  title: "AWS (SST)",
9762
10044
  value: "sst",
@@ -9894,6 +10176,13 @@ async function initCommand(projectName, options = {}) {
9894
10176
  message: "AWS region (e.g. eu-west-1):",
9895
10177
  validate: (value) => AWS_REGION.test(value.trim()) || "An AWS region, like eu-west-1"
9896
10178
  },
10179
+ {
10180
+ type: (_prev, values) => !options.yes && !options.registry && (options.deploy ?? values.deployTarget) === "compose" ? "text" : null,
10181
+ name: "registry",
10182
+ message: "Container registry CI pushes to (e.g. ghcr.io/<your GitHub owner>):",
10183
+ initial: (_prev, values) => defaultRegistry(projectName || options.name || values.name),
10184
+ validate: (value) => value.trim().length > 0 || "A registry, like ghcr.io/acme"
10185
+ },
9897
10186
  {
9898
10187
  type: options.yes || options.stages ? null : "text",
9899
10188
  name: "deployedStages",
@@ -9995,6 +10284,7 @@ async function initCommand(projectName, options = {}) {
9995
10284
  packageManager: pkgManager,
9996
10285
  deployTarget,
9997
10286
  stages: resolveStages(options, answers),
10287
+ ...deployTarget === "compose" ? { registry: options.registry ?? answers.registry?.trim() ?? defaultRegistry(name) } : {},
9998
10288
  ...deployTarget === "sst" ? { region: options.region ?? (options.yes ? "eu-west-1" : answers.region?.trim()) } : {},
9999
10289
  constructs,
10000
10290
  frontendFramework
@@ -10166,6 +10456,13 @@ function printNextSteps(projectName, options, pkgManager) {
10166
10456
  for (const stage of deployed) console.log(` ${require_utils.getRunCommand(pkgManager, `deploy:${stage}`)}`);
10167
10457
  console.log("");
10168
10458
  }
10459
+ if (options.deployTarget === "compose") {
10460
+ console.log("🚀 Deployment (Docker Compose, on your server):");
10461
+ console.log(` Images are pushed to ${options.registry}; .github/workflows/deploy.yml builds them`);
10462
+ console.log(" and runs gkm compose on the server over SSH. See the comments in it for the");
10463
+ console.log(" environment variables and secrets each stage needs.");
10464
+ console.log("");
10465
+ }
10169
10466
  if (options.deployTarget === "sst") {
10170
10467
  console.log("🚀 Deployment (AWS, through SST):");
10171
10468
  for (const stage of deployed) console.log(` ${require_utils.getRunCommand(pkgManager, `deploy:${stage}`)} # gkm deploy: build, sst deploy, health checks`);
@@ -10205,6 +10502,14 @@ var UnknownDeployTarget = class extends Error {
10205
10502
  this.name = "UnknownDeployTarget";
10206
10503
  }
10207
10504
  };
10505
+ /**
10506
+ * Where a compose deploy's images go when nobody said: GitHub's registry,
10507
+ * under an owner named after the project. The generated config says to change
10508
+ * it to the repository's owner, whose packages the workflow's token can write.
10509
+ */
10510
+ function defaultRegistry(name) {
10511
+ return `ghcr.io/${(name ?? "my-org").toLowerCase()}`;
10512
+ }
10208
10513
  /** `--region` that is not shaped like one, e.g. `europe` for `eu-west-1`. */
10209
10514
  var NotAnAwsRegion = class extends Error {
10210
10515
  region;
@@ -10909,7 +11214,7 @@ function testDatabases(reconciled) {
10909
11214
  * starts without the reference data the app needs.
10910
11215
  */
10911
11216
  async function migrateTestStage(workspace, env) {
10912
- const { migrateAndSeed } = await Promise.resolve().then(() => require("./migrate-BlYiMA23.cjs"));
11217
+ const { migrateAndSeed } = await Promise.resolve().then(() => require("./migrate-BgPWVnAZ.cjs"));
10913
11218
  const { discover } = await Promise.resolve().then(() => require("./discover-D1It5r_h.cjs")).then((n) => n.discover_exports);
10914
11219
  const sources = {};
10915
11220
  const manifest = await discover({
@@ -11245,7 +11550,7 @@ const program = new commander.Command();
11245
11550
  program.name("gkm").description("GeekMidas backend framework CLI").version(version).option("--cwd <path>", "Change working directory").option("--debug", "Enable debug mode (verbose errors with stack traces)").hook("preAction", () => {
11246
11551
  if (program.opts().debug);
11247
11552
  });
11248
- program.command("init").description("Scaffold a new project").argument("[name]", "Project name").option("--template <template>", "Project template (minimal, api, serverless, worker)").option("--skip-install", "Skip dependency installation", false).option("-y, --yes", "Skip prompts, use defaults", false).option("--monorepo", "Setup as monorepo with packages/models", false).option("--api-path <path>", "API app path in monorepo (default: apps/api)").option("--pm <manager>", "Package manager (pnpm, npm, yarn, bun)").option("--deploy <target>", "Where it deploys (dokploy, sst, none)").option("--region <region>", "AWS region for an SST deploy (e.g. eu-west-1)").option("--stages <names>", "Deployed stages, comma-separated (e.g. staging,prod)").option("--protected-stage <name>", "Which deployed stage is production").option("--local-stage <name>", "What gkm dev runs as (e.g. dev)").action(async (name, options) => {
11553
+ program.command("init").description("Scaffold a new project").argument("[name]", "Project name").option("--template <template>", "Project template (minimal, api, serverless, worker)").option("--skip-install", "Skip dependency installation", false).option("-y, --yes", "Skip prompts, use defaults", false).option("--monorepo", "Setup as monorepo with packages/models", false).option("--api-path <path>", "API app path in monorepo (default: apps/api)").option("--pm <manager>", "Package manager (pnpm, npm, yarn, bun)").option("--deploy <target>", "Where it deploys (dokploy, compose, sst, none)").option("--region <region>", "AWS region for an SST deploy (e.g. eu-west-1)").option("--registry <registry>", "Container registry for a compose deploy (e.g. ghcr.io/acme)").option("--stages <names>", "Deployed stages, comma-separated (e.g. staging,prod)").option("--protected-stage <name>", "Which deployed stage is production").option("--local-stage <name>", "What gkm dev runs as (e.g. dev)").action(async (name, options) => {
11249
11554
  try {
11250
11555
  const globalOptions = program.opts();
11251
11556
  if (globalOptions.cwd) process.chdir(globalOptions.cwd);
@@ -11353,7 +11658,7 @@ program.command("migrate").description("Apply each database construct's migratio
11353
11658
  try {
11354
11659
  const globalOptions = program.opts();
11355
11660
  if (globalOptions.cwd) process.chdir(globalOptions.cwd);
11356
- const { migrateCommand } = await Promise.resolve().then(() => require("./migrate-BlYiMA23.cjs"));
11661
+ const { migrateCommand } = await Promise.resolve().then(() => require("./migrate-BgPWVnAZ.cjs"));
11357
11662
  await migrateCommand({
11358
11663
  ...options,
11359
11664
  ...construct ? { construct } : {}
@@ -11367,7 +11672,7 @@ program.command("seed").description("Migrate, then run each database construct's
11367
11672
  try {
11368
11673
  const globalOptions = program.opts();
11369
11674
  if (globalOptions.cwd) process.chdir(globalOptions.cwd);
11370
- const { seedCommand } = await Promise.resolve().then(() => require("./migrate-BlYiMA23.cjs"));
11675
+ const { seedCommand } = await Promise.resolve().then(() => require("./migrate-BgPWVnAZ.cjs"));
11371
11676
  await seedCommand({
11372
11677
  ...options,
11373
11678
  ...construct ? { construct } : {}
@@ -11381,7 +11686,7 @@ program.command("migration").description("Write a construct's next migration: an
11381
11686
  try {
11382
11687
  const globalOptions = program.opts();
11383
11688
  if (globalOptions.cwd) process.chdir(globalOptions.cwd);
11384
- const { migrationCommand } = await Promise.resolve().then(() => require("./migrate-BlYiMA23.cjs"));
11689
+ const { migrationCommand } = await Promise.resolve().then(() => require("./migrate-BgPWVnAZ.cjs"));
11385
11690
  await migrationCommand({
11386
11691
  construct,
11387
11692
  ...name ? { name } : {}
@@ -11406,11 +11711,15 @@ program.command("api").description("Manage REST API endpoints").action(() => {
11406
11711
  if (globalOptions.cwd) process.chdir(globalOptions.cwd);
11407
11712
  process.stdout.write("REST API management - coming soon\n");
11408
11713
  });
11409
- program.command("openapi").description("Generate OpenAPI specification from endpoints").option("--app <name>", "Workspace mode: generate for a single named backend app").action(async (options) => {
11714
+ program.command("openapi").description("Generate OpenAPI specification from endpoints").option("--app <name>", "Workspace mode: generate for a single named backend app").option("--telemetry [sampleRate]", "Generated clients send W3C trace context to their API by default, at the stage's sample rate (0-1, default 1)").action(async (options) => {
11410
11715
  try {
11411
11716
  const globalOptions = program.opts();
11412
11717
  if (globalOptions.cwd) process.chdir(globalOptions.cwd);
11413
- await require_openapi.openapiCommand({ app: options.app });
11718
+ const telemetry = require_EndpointGenerator.parseTelemetryFlag(options.telemetry);
11719
+ await require_openapi.openapiCommand({
11720
+ app: options.app,
11721
+ ...telemetry !== void 0 ? { telemetry } : {}
11722
+ });
11414
11723
  } catch (error) {
11415
11724
  console.error(formatError(error));
11416
11725
  process.exit(1);
@@ -11485,7 +11794,7 @@ program.command("secrets:add").description("Build the keys a stage must be given
11485
11794
  try {
11486
11795
  const globalOptions = program.opts();
11487
11796
  if (globalOptions.cwd) process.chdir(globalOptions.cwd);
11488
- const { secretsAddCommand } = await Promise.resolve().then(() => require("./add-DF9IHQov.cjs"));
11797
+ const { secretsAddCommand } = await Promise.resolve().then(() => require("./add-Bwddb4KD.cjs"));
11489
11798
  await secretsAddCommand(options);
11490
11799
  } catch (error) {
11491
11800
  console.error(formatError(error));
@@ -11496,7 +11805,7 @@ program.command("encryption:rotate").description("Add a new current key to an En
11496
11805
  try {
11497
11806
  const globalOptions = program.opts();
11498
11807
  if (globalOptions.cwd) process.chdir(globalOptions.cwd);
11499
- const { encryptionRotateCommand } = await Promise.resolve().then(() => require("./encryption-9YA5ThNl.cjs"));
11808
+ const { encryptionRotateCommand } = await Promise.resolve().then(() => require("./encryption-CxTfRx4h.cjs"));
11500
11809
  await encryptionRotateCommand(construct, options);
11501
11810
  } catch (error) {
11502
11811
  console.error(formatError(error));
@@ -11507,7 +11816,7 @@ program.command("encryption:retire").description("Remove an old key from an Encr
11507
11816
  try {
11508
11817
  const globalOptions = program.opts();
11509
11818
  if (globalOptions.cwd) process.chdir(globalOptions.cwd);
11510
- const { encryptionRetireCommand } = await Promise.resolve().then(() => require("./encryption-9YA5ThNl.cjs"));
11819
+ const { encryptionRetireCommand } = await Promise.resolve().then(() => require("./encryption-CxTfRx4h.cjs"));
11511
11820
  await encryptionRetireCommand(construct, key, options);
11512
11821
  } catch (error) {
11513
11822
  console.error(formatError(error));
@@ -11550,7 +11859,7 @@ program.command("secrets:reconcile").description("Backfill missing custom secret
11550
11859
  if (globalOptions.cwd) process.chdir(globalOptions.cwd);
11551
11860
  const { loadWorkspaceConfig } = await Promise.resolve().then(() => require("./config.cjs"));
11552
11861
  const { reconcileMissingSecrets } = await Promise.resolve().then(() => require("./reconcile-CuCQBa5-.cjs"));
11553
- const { secretsStoreFor } = await Promise.resolve().then(() => require("./seeds-BjHiy9tW.cjs")).then((n) => n.store_exports);
11862
+ const { secretsStoreFor } = await Promise.resolve().then(() => require("./seeds-Ccju3zGl.cjs")).then((n) => n.store_exports);
11554
11863
  const { workspace } = await loadWorkspaceConfig();
11555
11864
  const stage = options.stage ?? workspace.stages.local;
11556
11865
  const store = await secretsStoreFor(workspace, stage);
@@ -11559,7 +11868,7 @@ program.command("secrets:reconcile").description("Backfill missing custom secret
11559
11868
  console.error(`No secrets found for stage "${stage}". Run "gkm secrets:init --stage ${stage}" first.`);
11560
11869
  process.exit(1);
11561
11870
  }
11562
- const { derivedContainers } = await Promise.resolve().then(() => require("./seeds-BjHiy9tW.cjs")).then((n) => n.workspace_exports);
11871
+ const { derivedContainers } = await Promise.resolve().then(() => require("./seeds-Ccju3zGl.cjs")).then((n) => n.workspace_exports);
11563
11872
  const result = reconcileMissingSecrets(secrets, workspace, await derivedContainers(workspace, stage));
11564
11873
  if (!result) {
11565
11874
  console.log(`\n✓ Secrets for stage "${stage}" are up-to-date`);
@@ -11577,7 +11886,7 @@ program.command("secrets:migrate").description("Copy a deployed stage's secrets
11577
11886
  try {
11578
11887
  const globalOptions = program.opts();
11579
11888
  if (globalOptions.cwd) process.chdir(globalOptions.cwd);
11580
- const { secretsMigrateCommand } = await Promise.resolve().then(() => require("./migrate-C440QQvZ.cjs"));
11889
+ const { secretsMigrateCommand } = await Promise.resolve().then(() => require("./migrate-Bemd4tkz.cjs"));
11581
11890
  await secretsMigrateCommand(options);
11582
11891
  } catch (error) {
11583
11892
  console.error(formatError(error));
@@ -11585,7 +11894,7 @@ program.command("secrets:migrate").description("Copy a deployed stage's secrets
11585
11894
  }
11586
11895
  });
11587
11896
  program.command("deploy").description("Deploy a stage through its target").option("--target <name>", "Deploy target: dokploy, compose, sst, or one named in deploy.targets (default: deploy.default)").option("--provider <provider>", "[DEPRECATED] Use --target instead").requiredOption("--stage <stage>", "Deployment stage (e.g., production, staging)").option("--tag <tag>", "Image tag (default: stage-timestamp; compose: the commit). Compose pulls a given tag").option("--skip-push", "Skip pushing image to registry").option("--skip-build", "Skip build step (use existing build)").option("--json", "Write events as JSON lines instead of progress; never prompts").option("--dry-run", "Show what would be created or reused; change, build and push nothing").option("--atomic", "If the release fails, roll back every app it released, not only the failed ones").option("--allow-dev-services <list>", "Server targets: run MinIO and/or Mailpit (minio,mailpit) for mail and buckets the stage's secrets don't configure. Not production-grade").action(async (options) => {
11588
- const { deployCli } = await Promise.resolve().then(() => require("./cli-BB1KOkfo.cjs"));
11897
+ const { deployCli } = await Promise.resolve().then(() => require("./cli-DO7DQqCq.cjs"));
11589
11898
  const globalOptions = program.opts();
11590
11899
  const code = await deployCli({
11591
11900
  cwd: (0, node_path.resolve)(globalOptions.cwd ?? process.cwd()),
@@ -11602,7 +11911,7 @@ program.command("deploy").description("Deploy a stage through its target").optio
11602
11911
  });
11603
11912
  program.command("deploy:rollback").description("Put a stage's app back on its previous release (Dokploy): one app with --app, every app with --atomic").requiredOption("--stage <stage>", "A deployed stage").option("--app <app>", "The app to roll back").option("--atomic", "Roll back every app that has an earlier release").action(async (options) => {
11604
11913
  try {
11605
- const { rollbackStage } = await Promise.resolve().then(() => require("./rollback-P09wRaW4.cjs")).then((n) => n.rollback_exports);
11914
+ const { rollbackStage } = await Promise.resolve().then(() => require("./rollback-BVQFDjxr.cjs")).then((n) => n.rollback_exports);
11606
11915
  const { terminalCredentials } = await Promise.resolve().then(() => require("./terminal-BL5E0xbR.cjs"));
11607
11916
  const globalOptions = program.opts();
11608
11917
  await rollbackStage({
@@ -11638,13 +11947,24 @@ program.command("deploy:github").description("Let GitHub Actions deploy a stage:
11638
11947
  try {
11639
11948
  const globalOptions = program.opts();
11640
11949
  if (globalOptions.cwd) process.chdir(globalOptions.cwd);
11641
- const { deployGithubCommand } = await Promise.resolve().then(() => require("./github-BM-Y9M2G.cjs"));
11950
+ const { deployGithubCommand } = await Promise.resolve().then(() => require("./github-Dukt5cJe.cjs"));
11642
11951
  await deployGithubCommand(options);
11643
11952
  } catch (error) {
11644
11953
  console.error(formatError(error));
11645
11954
  process.exit(1);
11646
11955
  }
11647
11956
  });
11957
+ program.command("stages").description("The workspace's stages from gkm.config.ts: local, deployed and protected").option("--json", "Print them as JSON").option("--github-output", "Write the stages, and which this workflow run builds and deploys, to $GITHUB_OUTPUT").option("--event <name>", "The event to plan for (default: $GITHUB_EVENT_NAME)").option("--stage <stage>", "The stage a workflow_dispatch deploys").action(async (options) => {
11958
+ try {
11959
+ const globalOptions = program.opts();
11960
+ if (globalOptions.cwd) process.chdir(globalOptions.cwd);
11961
+ const { stagesCommand } = await Promise.resolve().then(() => require("./stages-CwrYVX9u.cjs"));
11962
+ await stagesCommand(options);
11963
+ } catch (error) {
11964
+ console.error(formatError(error));
11965
+ process.exit(1);
11966
+ }
11967
+ });
11648
11968
  program.command("deploy:list").description("List Dokploy resources (projects, registries)").option("--endpoint <url>", "Dokploy server URL (uses stored credentials if logged in)").option("--projects", "List projects").option("--registries", "List registries").action(async (options) => {
11649
11969
  try {
11650
11970
  const globalOptions = program.opts();