@geekmidas/cli 10.0.0-alpha.80 → 10.0.0-alpha.82

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 (105) 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/{OpenApiTsGenerator-nu1r1NgB.mjs → OpenApiTsGenerator-ByRPMbBN.mjs} +34 -7
  6. package/dist/OpenApiTsGenerator-ByRPMbBN.mjs.map +1 -0
  7. package/dist/{OpenApiTsGenerator-CKBCckKz.cjs → OpenApiTsGenerator-CdUM6Hvv.cjs} +34 -7
  8. package/dist/OpenApiTsGenerator-CdUM6Hvv.cjs.map +1 -0
  9. package/dist/{SubscriberGenerator-CajwOa5W.cjs → SubscriberGenerator-CYriX5BV.cjs} +2 -2
  10. package/dist/{SubscriberGenerator-CajwOa5W.cjs.map → SubscriberGenerator-CYriX5BV.cjs.map} +1 -1
  11. package/dist/{SubscriberGenerator-5looQ3gB.mjs → SubscriberGenerator-DQZeGkDW.mjs} +2 -2
  12. package/dist/{SubscriberGenerator-5looQ3gB.mjs.map → SubscriberGenerator-DQZeGkDW.mjs.map} +1 -1
  13. package/dist/{add-DJ0VE-y-.cjs → add-1T3y6E4M.cjs} +2 -2
  14. package/dist/{add-DJ0VE-y-.cjs.map → add-1T3y6E4M.cjs.map} +1 -1
  15. package/dist/{add-CIxT-Iq6.mjs → add-DnYHJOap.mjs} +2 -2
  16. package/dist/{add-CIxT-Iq6.mjs.map → add-DnYHJOap.mjs.map} +1 -1
  17. package/dist/{bundler-D4pl87A5.mjs → bundler-DlKdxCGh.mjs} +3 -3
  18. package/dist/{bundler-D4pl87A5.mjs.map → bundler-DlKdxCGh.mjs.map} +1 -1
  19. package/dist/{bundler-BlbSLFLn.cjs → bundler-YNvLdvlh.cjs} +3 -3
  20. package/dist/{bundler-BlbSLFLn.cjs.map → bundler-YNvLdvlh.cjs.map} +1 -1
  21. package/dist/{cli-BkNZBe_-.cjs → cli-CWee1-wU.cjs} +3 -3
  22. package/dist/{cli-BkNZBe_-.cjs.map → cli-CWee1-wU.cjs.map} +1 -1
  23. package/dist/{cli-7aLfgIGt.mjs → cli-qMszGvDu.mjs} +3 -3
  24. package/dist/{cli-7aLfgIGt.mjs.map → cli-qMszGvDu.mjs.map} +1 -1
  25. package/dist/{compose-n7K8H5j8.mjs → compose-D4sD4Lgr.mjs} +83 -351
  26. package/dist/compose-D4sD4Lgr.mjs.map +1 -0
  27. package/dist/{compose-Bn4OJONR.cjs → compose-qnDyPJNp.cjs} +101 -369
  28. package/dist/compose-qnDyPJNp.cjs.map +1 -0
  29. package/dist/deploy/public.cjs +5 -5
  30. package/dist/deploy/public.d.cts.map +1 -1
  31. package/dist/deploy/public.d.mts.map +1 -1
  32. package/dist/deploy/public.mjs +5 -5
  33. package/dist/{deploy-DK4Y6ev4.mjs → deploy-C00DAKOt.mjs} +3 -3
  34. package/dist/{deploy-DK4Y6ev4.mjs.map → deploy-C00DAKOt.mjs.map} +1 -1
  35. package/dist/{deploy-Ppnh8MHS.cjs → deploy-CXP2fXvK.cjs} +3 -3
  36. package/dist/{deploy-Ppnh8MHS.cjs.map → deploy-CXP2fXvK.cjs.map} +1 -1
  37. package/dist/{dokploy-Bjq05wkw.mjs → dokploy-B3zoCmJb.mjs} +2 -2
  38. package/dist/{dokploy-Bjq05wkw.mjs.map → dokploy-B3zoCmJb.mjs.map} +1 -1
  39. package/dist/{dokploy-CJvdoNc3.cjs → dokploy-BHcSmghb.cjs} +2 -2
  40. package/dist/{dokploy-CJvdoNc3.cjs.map → dokploy-BHcSmghb.cjs.map} +1 -1
  41. package/dist/{drivers-Ch1rJitn.mjs → drivers-B4RP2B2O.mjs} +2 -2
  42. package/dist/{drivers-Ch1rJitn.mjs.map → drivers-B4RP2B2O.mjs.map} +1 -1
  43. package/dist/{drivers-BdvtCKc7.cjs → drivers-CJx76mcb.cjs} +2 -2
  44. package/dist/{drivers-BdvtCKc7.cjs.map → drivers-CJx76mcb.cjs.map} +1 -1
  45. package/dist/{encryption-CAyR6D7B.cjs → encryption-DLin89I_.cjs} +2 -2
  46. package/dist/{encryption-CAyR6D7B.cjs.map → encryption-DLin89I_.cjs.map} +1 -1
  47. package/dist/{encryption-BrsOJFFz.mjs → encryption-DPFljXtM.mjs} +2 -2
  48. package/dist/{encryption-BrsOJFFz.mjs.map → encryption-DPFljXtM.mjs.map} +1 -1
  49. package/dist/{engine-DzBZR5D0.cjs → engine-BS3iX9Mu.cjs} +2 -2
  50. package/dist/{engine-DzBZR5D0.cjs.map → engine-BS3iX9Mu.cjs.map} +1 -1
  51. package/dist/{engine-ba9CvjTo.mjs → engine-CgzgIg-_.mjs} +2 -2
  52. package/dist/{engine-ba9CvjTo.mjs.map → engine-CgzgIg-_.mjs.map} +1 -1
  53. package/dist/{github-BLjU59Ye.cjs → github-D8KVmNRg.cjs} +2 -2
  54. package/dist/{github-BLjU59Ye.cjs.map → github-D8KVmNRg.cjs.map} +1 -1
  55. package/dist/{github-CVdbVlT5.mjs → github-DL4zwJsR.mjs} +2 -2
  56. package/dist/{github-CVdbVlT5.mjs.map → github-DL4zwJsR.mjs.map} +1 -1
  57. package/dist/index.cjs +225 -49
  58. package/dist/index.cjs.map +1 -1
  59. package/dist/index.mjs +226 -50
  60. package/dist/index.mjs.map +1 -1
  61. package/dist/{migrate-iEdyEx4S.cjs → migrate-BdKhIJgT.cjs} +2 -2
  62. package/dist/{migrate-iEdyEx4S.cjs.map → migrate-BdKhIJgT.cjs.map} +1 -1
  63. package/dist/{migrate-DlBgATa-.mjs → migrate-CCejlgU0.mjs} +2 -2
  64. package/dist/{migrate-DlBgATa-.mjs.map → migrate-CCejlgU0.mjs.map} +1 -1
  65. package/dist/{migrate-pfu4aYzX.mjs → migrate-Cd3kcI7o.mjs} +2 -2
  66. package/dist/{migrate-pfu4aYzX.mjs.map → migrate-Cd3kcI7o.mjs.map} +1 -1
  67. package/dist/{migrate-DkB833Jj.cjs → migrate-DIjG8-QR.cjs} +2 -2
  68. package/dist/{migrate-DkB833Jj.cjs.map → migrate-DIjG8-QR.cjs.map} +1 -1
  69. package/dist/openapi.cjs +16 -11
  70. package/dist/openapi.cjs.map +1 -1
  71. package/dist/openapi.d.cts +28 -0
  72. package/dist/openapi.d.cts.map +1 -1
  73. package/dist/openapi.d.mts +28 -0
  74. package/dist/openapi.d.mts.map +1 -1
  75. package/dist/openapi.mjs +16 -12
  76. package/dist/openapi.mjs.map +1 -1
  77. package/dist/{ready-BB9xS4S9.cjs → ready-4kx2pAhm.cjs} +5 -5
  78. package/dist/{ready-BB9xS4S9.cjs.map → ready-4kx2pAhm.cjs.map} +1 -1
  79. package/dist/{ready-ZZoNskrr.mjs → ready-DhZbZtFw.mjs} +5 -5
  80. package/dist/{ready-ZZoNskrr.mjs.map → ready-DhZbZtFw.mjs.map} +1 -1
  81. package/dist/{resolve-4_5N67Fk.cjs → resolve-ApSUK_HB.cjs} +3 -3
  82. package/dist/{resolve-4_5N67Fk.cjs.map → resolve-ApSUK_HB.cjs.map} +1 -1
  83. package/dist/{resolve-CQPn66jr.mjs → resolve-DY9TaVeV.mjs} +3 -3
  84. package/dist/{resolve-CQPn66jr.mjs.map → resolve-DY9TaVeV.mjs.map} +1 -1
  85. package/dist/{rollback-CgYUPLbq.cjs → rollback-CdGhCk1d.cjs} +3 -3
  86. package/dist/{rollback-CgYUPLbq.cjs.map → rollback-CdGhCk1d.cjs.map} +1 -1
  87. package/dist/{rollback-C0cbdsM-.mjs → rollback-DXU6cr7q.mjs} +3 -3
  88. package/dist/{rollback-C0cbdsM-.mjs.map → rollback-DXU6cr7q.mjs.map} +1 -1
  89. package/dist/{seeds-ZljwYV_p.cjs → seeds-BLzrSwEr.cjs} +3889 -2953
  90. package/dist/seeds-BLzrSwEr.cjs.map +1 -0
  91. package/dist/{seeds-BdkFpW0P.mjs → seeds-DbyqaXW4.mjs} +2344 -1528
  92. package/dist/seeds-DbyqaXW4.mjs.map +1 -0
  93. package/dist/target/public.cjs +1 -1
  94. package/dist/target/public.mjs +1 -1
  95. package/dist/vitest.cjs +1 -1
  96. package/dist/vitest.mjs +1 -1
  97. package/package.json +15 -15
  98. package/dist/EndpointGenerator-CP6sBvQV.cjs.map +0 -1
  99. package/dist/EndpointGenerator-DftalLYg.mjs.map +0 -1
  100. package/dist/OpenApiTsGenerator-CKBCckKz.cjs.map +0 -1
  101. package/dist/OpenApiTsGenerator-nu1r1NgB.mjs.map +0 -1
  102. package/dist/compose-Bn4OJONR.cjs.map +0 -1
  103. package/dist/compose-n7K8H5j8.mjs.map +0 -1
  104. package/dist/seeds-BdkFpW0P.mjs.map +0 -1
  105. package/dist/seeds-ZljwYV_p.cjs.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"cli-BkNZBe_-.cjs","names":["targetForProvider","formatError","parseDevServices","deploy","storedCredentials","terminalCredentials"],"sources":["../src/deploy/cli.ts"],"sourcesContent":["/**\n * `gkm deploy`: the terminal around `deploy()`. CLI layer only.\n *\n * Everything that belongs to a person at a terminal lives here and nowhere\n * below it: prompting for a missing login (and storing it), printing progress,\n * and turning the outcome into an exit code. The deploy itself is the same\n * `deploy()` a host calls.\n */\n\nimport { formatError } from '../debug';\nimport { targetForProvider } from '../target/provider';\nimport { storedCredentials } from './credentials';\nimport { deploy } from './deploy';\nimport { type DevService, parseDevServices } from './devServices';\nimport { terminalCredentials } from './terminal';\n\nexport interface DeployCliOptions {\n\t/** The project directory: `--cwd`, else where the command was run. */\n\tcwd: string;\n\t/** `--target`: where to deploy. Defaults to `deploy.default`. */\n\ttarget?: string;\n\t/** `--provider`, deprecated: `dokploy` means `--target dokploy`. */\n\tprovider?: string;\n\tstage: string;\n\ttag?: string;\n\t/**\n\t * Print each event as one JSON object per line on stdout, instead of the\n\t * progress lines. Nothing prompts: a missing credential fails the run.\n\t */\n\tjson?: boolean;\n\t/** Plan only: create, change, build and push nothing. */\n\tdryRun?: boolean;\n\t/** On a failed release, roll back every app, not only the failed ones. */\n\tatomic?: boolean;\n\t/** `--allow-dev-services minio,mailpit`, as typed. */\n\tallowDevServices?: string;\n}\n\n/** Where the command writes. The process's own streams, outside tests. */\nexport interface DeployCliStreams {\n\tstdout: Pick<NodeJS.WriteStream, 'write'>;\n}\n\n/**\n * Run `gkm deploy` and resolve with its exit code: 0 when the run finished,\n * 1 when anything stopped it.\n */\nexport async function deployCli(\n\toptions: DeployCliOptions,\n\tstreams: DeployCliStreams = { stdout: process.stdout },\n): Promise<number> {\n\tlet target = options.target;\n\tif (options.provider !== undefined && target === undefined) {\n\t\ttry {\n\t\t\t// On stderr, so a `--json` run's stdout still carries only events.\n\t\t\ttarget = targetForProvider(options.provider, (message) =>\n\t\t\t\tconsole.warn(message),\n\t\t\t);\n\t\t} catch (error) {\n\t\t\tconsole.error(formatError(error));\n\t\t\treturn 1;\n\t\t}\n\t}\n\n\tlet allowDevServices: DevService[];\n\ttry {\n\t\tallowDevServices = parseDevServices(options.allowDevServices);\n\t} catch (error) {\n\t\tconsole.error(formatError(error));\n\t\treturn 1;\n\t}\n\n\tconst input = {\n\t\tcwd: options.cwd,\n\t\tstage: options.stage,\n\t\t...(target ? { target } : {}),\n\t\t...(options.tag ? { tag: options.tag } : {}),\n\t\t...(options.dryRun ? { dryRun: true } : {}),\n\t\t...(options.atomic ? { atomic: true } : {}),\n\t\t...(allowDevServices.length > 0 ? { allowDevServices } : {}),\n\t};\n\n\tif (options.json) {\n\t\t// stdout carries the events and nothing else: docker's own output goes\n\t\t// to stderr, and nobody is asked anything — a prompt would be written\n\t\t// into the stream a program is parsing.\n\t\tconst run = deploy({\n\t\t\t...input,\n\t\t\tcredentials: storedCredentials(),\n\t\t\tchildOutput: 'stderr',\n\t\t});\n\t\tfor await (const event of run) {\n\t\t\tstreams.stdout.write(`${JSON.stringify(event)}\\n`);\n\t\t}\n\t\treturn run.result.then(\n\t\t\t() => 0,\n\t\t\t(error) => {\n\t\t\t\tconsole.error(formatError(error));\n\t\t\t\treturn 1;\n\t\t\t},\n\t\t);\n\t}\n\n\t// The lines arrive as they are written, rather than as events read back a\n\t// tick later, so they interleave with a prompt exactly as they always did.\n\tconst run = deploy({\n\t\t...input,\n\t\tcredentials: terminalCredentials(storedCredentials()),\n\t\tlogger: {\n\t\t\tinfo: (message) => console.log(message),\n\t\t\twarn: (message) => console.warn(message),\n\t\t\terror: (message) => console.error(message),\n\t\t},\n\t});\n\n\ttry {\n\t\tawait run.result;\n\t\treturn 0;\n\t} catch (error) {\n\t\tconsole.error(formatError(error));\n\t\treturn 1;\n\t}\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AA+CA,eAAsB,UACrB,SACA,UAA4B,EAAE,QAAQ,QAAQ,OAAO,GACnC;CAClB,IAAI,SAAS,QAAQ;CACrB,IAAI,QAAQ,aAAa,KAAA,KAAa,WAAW,KAAA,GAChD,IAAI;EAEH,SAASA,iBAAAA,kBAAkB,QAAQ,WAAW,YAC7C,QAAQ,KAAK,OAAO,CACrB;CACD,SAAS,OAAO;EACf,QAAQ,MAAMC,cAAAA,YAAY,KAAK,CAAC;EAChC,OAAO;CACR;CAGD,IAAI;CACJ,IAAI;EACH,mBAAmBC,cAAAA,iBAAiB,QAAQ,gBAAgB;CAC7D,SAAS,OAAO;EACf,QAAQ,MAAMD,cAAAA,YAAY,KAAK,CAAC;EAChC,OAAO;CACR;CAEA,MAAM,QAAQ;EACb,KAAK,QAAQ;EACb,OAAO,QAAQ;EACf,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;EAC3B,GAAI,QAAQ,MAAM,EAAE,KAAK,QAAQ,IAAI,IAAI,CAAC;EAC1C,GAAI,QAAQ,SAAS,EAAE,QAAQ,KAAK,IAAI,CAAC;EACzC,GAAI,QAAQ,SAAS,EAAE,QAAQ,KAAK,IAAI,CAAC;EACzC,GAAI,iBAAiB,SAAS,IAAI,EAAE,iBAAiB,IAAI,CAAC;CAC3D;CAEA,IAAI,QAAQ,MAAM;EAIjB,MAAM,MAAME,eAAAA,OAAO;GAClB,GAAG;GACH,aAAaC,oBAAAA,kBAAkB;GAC/B,aAAa;EACd,CAAC;EACD,WAAW,MAAM,SAAS,KACzB,QAAQ,OAAO,MAAM,GAAG,KAAK,UAAU,KAAK,EAAE,GAAG;EAElD,OAAO,IAAI,OAAO,WACX,IACL,UAAU;GACV,QAAQ,MAAMH,cAAAA,YAAY,KAAK,CAAC;GAChC,OAAO;EACR,CACD;CACD;CAIA,MAAM,MAAME,eAAAA,OAAO;EAClB,GAAG;EACH,aAAaE,iBAAAA,oBAAoBD,oBAAAA,kBAAkB,CAAC;EACpD,QAAQ;GACP,OAAO,YAAY,QAAQ,IAAI,OAAO;GACtC,OAAO,YAAY,QAAQ,KAAK,OAAO;GACvC,QAAQ,YAAY,QAAQ,MAAM,OAAO;EAC1C;CACD,CAAC;CAED,IAAI;EACH,MAAM,IAAI;EACV,OAAO;CACR,SAAS,OAAO;EACf,QAAQ,MAAMH,cAAAA,YAAY,KAAK,CAAC;EAChC,OAAO;CACR;AACD"}
1
+ {"version":3,"file":"cli-CWee1-wU.cjs","names":["targetForProvider","formatError","parseDevServices","deploy","storedCredentials","terminalCredentials"],"sources":["../src/deploy/cli.ts"],"sourcesContent":["/**\n * `gkm deploy`: the terminal around `deploy()`. CLI layer only.\n *\n * Everything that belongs to a person at a terminal lives here and nowhere\n * below it: prompting for a missing login (and storing it), printing progress,\n * and turning the outcome into an exit code. The deploy itself is the same\n * `deploy()` a host calls.\n */\n\nimport { formatError } from '../debug';\nimport { targetForProvider } from '../target/provider';\nimport { storedCredentials } from './credentials';\nimport { deploy } from './deploy';\nimport { type DevService, parseDevServices } from './devServices';\nimport { terminalCredentials } from './terminal';\n\nexport interface DeployCliOptions {\n\t/** The project directory: `--cwd`, else where the command was run. */\n\tcwd: string;\n\t/** `--target`: where to deploy. Defaults to `deploy.default`. */\n\ttarget?: string;\n\t/** `--provider`, deprecated: `dokploy` means `--target dokploy`. */\n\tprovider?: string;\n\tstage: string;\n\ttag?: string;\n\t/**\n\t * Print each event as one JSON object per line on stdout, instead of the\n\t * progress lines. Nothing prompts: a missing credential fails the run.\n\t */\n\tjson?: boolean;\n\t/** Plan only: create, change, build and push nothing. */\n\tdryRun?: boolean;\n\t/** On a failed release, roll back every app, not only the failed ones. */\n\tatomic?: boolean;\n\t/** `--allow-dev-services minio,mailpit`, as typed. */\n\tallowDevServices?: string;\n}\n\n/** Where the command writes. The process's own streams, outside tests. */\nexport interface DeployCliStreams {\n\tstdout: Pick<NodeJS.WriteStream, 'write'>;\n}\n\n/**\n * Run `gkm deploy` and resolve with its exit code: 0 when the run finished,\n * 1 when anything stopped it.\n */\nexport async function deployCli(\n\toptions: DeployCliOptions,\n\tstreams: DeployCliStreams = { stdout: process.stdout },\n): Promise<number> {\n\tlet target = options.target;\n\tif (options.provider !== undefined && target === undefined) {\n\t\ttry {\n\t\t\t// On stderr, so a `--json` run's stdout still carries only events.\n\t\t\ttarget = targetForProvider(options.provider, (message) =>\n\t\t\t\tconsole.warn(message),\n\t\t\t);\n\t\t} catch (error) {\n\t\t\tconsole.error(formatError(error));\n\t\t\treturn 1;\n\t\t}\n\t}\n\n\tlet allowDevServices: DevService[];\n\ttry {\n\t\tallowDevServices = parseDevServices(options.allowDevServices);\n\t} catch (error) {\n\t\tconsole.error(formatError(error));\n\t\treturn 1;\n\t}\n\n\tconst input = {\n\t\tcwd: options.cwd,\n\t\tstage: options.stage,\n\t\t...(target ? { target } : {}),\n\t\t...(options.tag ? { tag: options.tag } : {}),\n\t\t...(options.dryRun ? { dryRun: true } : {}),\n\t\t...(options.atomic ? { atomic: true } : {}),\n\t\t...(allowDevServices.length > 0 ? { allowDevServices } : {}),\n\t};\n\n\tif (options.json) {\n\t\t// stdout carries the events and nothing else: docker's own output goes\n\t\t// to stderr, and nobody is asked anything — a prompt would be written\n\t\t// into the stream a program is parsing.\n\t\tconst run = deploy({\n\t\t\t...input,\n\t\t\tcredentials: storedCredentials(),\n\t\t\tchildOutput: 'stderr',\n\t\t});\n\t\tfor await (const event of run) {\n\t\t\tstreams.stdout.write(`${JSON.stringify(event)}\\n`);\n\t\t}\n\t\treturn run.result.then(\n\t\t\t() => 0,\n\t\t\t(error) => {\n\t\t\t\tconsole.error(formatError(error));\n\t\t\t\treturn 1;\n\t\t\t},\n\t\t);\n\t}\n\n\t// The lines arrive as they are written, rather than as events read back a\n\t// tick later, so they interleave with a prompt exactly as they always did.\n\tconst run = deploy({\n\t\t...input,\n\t\tcredentials: terminalCredentials(storedCredentials()),\n\t\tlogger: {\n\t\t\tinfo: (message) => console.log(message),\n\t\t\twarn: (message) => console.warn(message),\n\t\t\terror: (message) => console.error(message),\n\t\t},\n\t});\n\n\ttry {\n\t\tawait run.result;\n\t\treturn 0;\n\t} catch (error) {\n\t\tconsole.error(formatError(error));\n\t\treturn 1;\n\t}\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AA+CA,eAAsB,UACrB,SACA,UAA4B,EAAE,QAAQ,QAAQ,OAAO,GACnC;CAClB,IAAI,SAAS,QAAQ;CACrB,IAAI,QAAQ,aAAa,KAAA,KAAa,WAAW,KAAA,GAChD,IAAI;EAEH,SAASA,iBAAAA,kBAAkB,QAAQ,WAAW,YAC7C,QAAQ,KAAK,OAAO,CACrB;CACD,SAAS,OAAO;EACf,QAAQ,MAAMC,cAAAA,YAAY,KAAK,CAAC;EAChC,OAAO;CACR;CAGD,IAAI;CACJ,IAAI;EACH,mBAAmBC,cAAAA,iBAAiB,QAAQ,gBAAgB;CAC7D,SAAS,OAAO;EACf,QAAQ,MAAMD,cAAAA,YAAY,KAAK,CAAC;EAChC,OAAO;CACR;CAEA,MAAM,QAAQ;EACb,KAAK,QAAQ;EACb,OAAO,QAAQ;EACf,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;EAC3B,GAAI,QAAQ,MAAM,EAAE,KAAK,QAAQ,IAAI,IAAI,CAAC;EAC1C,GAAI,QAAQ,SAAS,EAAE,QAAQ,KAAK,IAAI,CAAC;EACzC,GAAI,QAAQ,SAAS,EAAE,QAAQ,KAAK,IAAI,CAAC;EACzC,GAAI,iBAAiB,SAAS,IAAI,EAAE,iBAAiB,IAAI,CAAC;CAC3D;CAEA,IAAI,QAAQ,MAAM;EAIjB,MAAM,MAAME,eAAAA,OAAO;GAClB,GAAG;GACH,aAAaC,oBAAAA,kBAAkB;GAC/B,aAAa;EACd,CAAC;EACD,WAAW,MAAM,SAAS,KACzB,QAAQ,OAAO,MAAM,GAAG,KAAK,UAAU,KAAK,EAAE,GAAG;EAElD,OAAO,IAAI,OAAO,WACX,IACL,UAAU;GACV,QAAQ,MAAMH,cAAAA,YAAY,KAAK,CAAC;GAChC,OAAO;EACR,CACD;CACD;CAIA,MAAM,MAAME,eAAAA,OAAO;EAClB,GAAG;EACH,aAAaE,iBAAAA,oBAAoBD,oBAAAA,kBAAkB,CAAC;EACpD,QAAQ;GACP,OAAO,YAAY,QAAQ,IAAI,OAAO;GACtC,OAAO,YAAY,QAAQ,KAAK,OAAO;GACvC,QAAQ,YAAY,QAAQ,MAAM,OAAO;EAC1C;CACD,CAAC;CAED,IAAI;EACH,MAAM,IAAI;EACV,OAAO;CACR,SAAS,OAAO;EACf,QAAQ,MAAMH,cAAAA,YAAY,KAAK,CAAC;EAChC,OAAO;CACR;AACD"}
@@ -1,6 +1,6 @@
1
1
  import { r as storedCredentials } from "./credentials-pAtB70k3.mjs";
2
- import { V as parseDevServices } from "./seeds-BdkFpW0P.mjs";
3
- import { t as deploy } from "./deploy-DK4Y6ev4.mjs";
2
+ import { F as parseDevServices } from "./seeds-DbyqaXW4.mjs";
3
+ import { t as deploy } from "./deploy-C00DAKOt.mjs";
4
4
  import { i as formatError } from "./index.mjs";
5
5
  import { n as targetForProvider } from "./provider-q4lsYzYG.mjs";
6
6
  import { terminalCredentials } from "./terminal-BdvrmkaC.mjs";
@@ -73,4 +73,4 @@ async function deployCli(options, streams = { stdout: process.stdout }) {
73
73
  //#endregion
74
74
  export { deployCli };
75
75
 
76
- //# sourceMappingURL=cli-7aLfgIGt.mjs.map
76
+ //# sourceMappingURL=cli-qMszGvDu.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"cli-7aLfgIGt.mjs","names":[],"sources":["../src/deploy/cli.ts"],"sourcesContent":["/**\n * `gkm deploy`: the terminal around `deploy()`. CLI layer only.\n *\n * Everything that belongs to a person at a terminal lives here and nowhere\n * below it: prompting for a missing login (and storing it), printing progress,\n * and turning the outcome into an exit code. The deploy itself is the same\n * `deploy()` a host calls.\n */\n\nimport { formatError } from '../debug';\nimport { targetForProvider } from '../target/provider';\nimport { storedCredentials } from './credentials';\nimport { deploy } from './deploy';\nimport { type DevService, parseDevServices } from './devServices';\nimport { terminalCredentials } from './terminal';\n\nexport interface DeployCliOptions {\n\t/** The project directory: `--cwd`, else where the command was run. */\n\tcwd: string;\n\t/** `--target`: where to deploy. Defaults to `deploy.default`. */\n\ttarget?: string;\n\t/** `--provider`, deprecated: `dokploy` means `--target dokploy`. */\n\tprovider?: string;\n\tstage: string;\n\ttag?: string;\n\t/**\n\t * Print each event as one JSON object per line on stdout, instead of the\n\t * progress lines. Nothing prompts: a missing credential fails the run.\n\t */\n\tjson?: boolean;\n\t/** Plan only: create, change, build and push nothing. */\n\tdryRun?: boolean;\n\t/** On a failed release, roll back every app, not only the failed ones. */\n\tatomic?: boolean;\n\t/** `--allow-dev-services minio,mailpit`, as typed. */\n\tallowDevServices?: string;\n}\n\n/** Where the command writes. The process's own streams, outside tests. */\nexport interface DeployCliStreams {\n\tstdout: Pick<NodeJS.WriteStream, 'write'>;\n}\n\n/**\n * Run `gkm deploy` and resolve with its exit code: 0 when the run finished,\n * 1 when anything stopped it.\n */\nexport async function deployCli(\n\toptions: DeployCliOptions,\n\tstreams: DeployCliStreams = { stdout: process.stdout },\n): Promise<number> {\n\tlet target = options.target;\n\tif (options.provider !== undefined && target === undefined) {\n\t\ttry {\n\t\t\t// On stderr, so a `--json` run's stdout still carries only events.\n\t\t\ttarget = targetForProvider(options.provider, (message) =>\n\t\t\t\tconsole.warn(message),\n\t\t\t);\n\t\t} catch (error) {\n\t\t\tconsole.error(formatError(error));\n\t\t\treturn 1;\n\t\t}\n\t}\n\n\tlet allowDevServices: DevService[];\n\ttry {\n\t\tallowDevServices = parseDevServices(options.allowDevServices);\n\t} catch (error) {\n\t\tconsole.error(formatError(error));\n\t\treturn 1;\n\t}\n\n\tconst input = {\n\t\tcwd: options.cwd,\n\t\tstage: options.stage,\n\t\t...(target ? { target } : {}),\n\t\t...(options.tag ? { tag: options.tag } : {}),\n\t\t...(options.dryRun ? { dryRun: true } : {}),\n\t\t...(options.atomic ? { atomic: true } : {}),\n\t\t...(allowDevServices.length > 0 ? { allowDevServices } : {}),\n\t};\n\n\tif (options.json) {\n\t\t// stdout carries the events and nothing else: docker's own output goes\n\t\t// to stderr, and nobody is asked anything — a prompt would be written\n\t\t// into the stream a program is parsing.\n\t\tconst run = deploy({\n\t\t\t...input,\n\t\t\tcredentials: storedCredentials(),\n\t\t\tchildOutput: 'stderr',\n\t\t});\n\t\tfor await (const event of run) {\n\t\t\tstreams.stdout.write(`${JSON.stringify(event)}\\n`);\n\t\t}\n\t\treturn run.result.then(\n\t\t\t() => 0,\n\t\t\t(error) => {\n\t\t\t\tconsole.error(formatError(error));\n\t\t\t\treturn 1;\n\t\t\t},\n\t\t);\n\t}\n\n\t// The lines arrive as they are written, rather than as events read back a\n\t// tick later, so they interleave with a prompt exactly as they always did.\n\tconst run = deploy({\n\t\t...input,\n\t\tcredentials: terminalCredentials(storedCredentials()),\n\t\tlogger: {\n\t\t\tinfo: (message) => console.log(message),\n\t\t\twarn: (message) => console.warn(message),\n\t\t\terror: (message) => console.error(message),\n\t\t},\n\t});\n\n\ttry {\n\t\tawait run.result;\n\t\treturn 0;\n\t} catch (error) {\n\t\tconsole.error(formatError(error));\n\t\treturn 1;\n\t}\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AA+CA,eAAsB,UACrB,SACA,UAA4B,EAAE,QAAQ,QAAQ,OAAO,GACnC;CAClB,IAAI,SAAS,QAAQ;CACrB,IAAI,QAAQ,aAAa,KAAA,KAAa,WAAW,KAAA,GAChD,IAAI;EAEH,SAAS,kBAAkB,QAAQ,WAAW,YAC7C,QAAQ,KAAK,OAAO,CACrB;CACD,SAAS,OAAO;EACf,QAAQ,MAAM,YAAY,KAAK,CAAC;EAChC,OAAO;CACR;CAGD,IAAI;CACJ,IAAI;EACH,mBAAmB,iBAAiB,QAAQ,gBAAgB;CAC7D,SAAS,OAAO;EACf,QAAQ,MAAM,YAAY,KAAK,CAAC;EAChC,OAAO;CACR;CAEA,MAAM,QAAQ;EACb,KAAK,QAAQ;EACb,OAAO,QAAQ;EACf,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;EAC3B,GAAI,QAAQ,MAAM,EAAE,KAAK,QAAQ,IAAI,IAAI,CAAC;EAC1C,GAAI,QAAQ,SAAS,EAAE,QAAQ,KAAK,IAAI,CAAC;EACzC,GAAI,QAAQ,SAAS,EAAE,QAAQ,KAAK,IAAI,CAAC;EACzC,GAAI,iBAAiB,SAAS,IAAI,EAAE,iBAAiB,IAAI,CAAC;CAC3D;CAEA,IAAI,QAAQ,MAAM;EAIjB,MAAM,MAAM,OAAO;GAClB,GAAG;GACH,aAAa,kBAAkB;GAC/B,aAAa;EACd,CAAC;EACD,WAAW,MAAM,SAAS,KACzB,QAAQ,OAAO,MAAM,GAAG,KAAK,UAAU,KAAK,EAAE,GAAG;EAElD,OAAO,IAAI,OAAO,WACX,IACL,UAAU;GACV,QAAQ,MAAM,YAAY,KAAK,CAAC;GAChC,OAAO;EACR,CACD;CACD;CAIA,MAAM,MAAM,OAAO;EAClB,GAAG;EACH,aAAa,oBAAoB,kBAAkB,CAAC;EACpD,QAAQ;GACP,OAAO,YAAY,QAAQ,IAAI,OAAO;GACtC,OAAO,YAAY,QAAQ,KAAK,OAAO;GACvC,QAAQ,YAAY,QAAQ,MAAM,OAAO;EAC1C;CACD,CAAC;CAED,IAAI;EACH,MAAM,IAAI;EACV,OAAO;CACR,SAAS,OAAO;EACf,QAAQ,MAAM,YAAY,KAAK,CAAC;EAChC,OAAO;CACR;AACD"}
1
+ {"version":3,"file":"cli-qMszGvDu.mjs","names":[],"sources":["../src/deploy/cli.ts"],"sourcesContent":["/**\n * `gkm deploy`: the terminal around `deploy()`. CLI layer only.\n *\n * Everything that belongs to a person at a terminal lives here and nowhere\n * below it: prompting for a missing login (and storing it), printing progress,\n * and turning the outcome into an exit code. The deploy itself is the same\n * `deploy()` a host calls.\n */\n\nimport { formatError } from '../debug';\nimport { targetForProvider } from '../target/provider';\nimport { storedCredentials } from './credentials';\nimport { deploy } from './deploy';\nimport { type DevService, parseDevServices } from './devServices';\nimport { terminalCredentials } from './terminal';\n\nexport interface DeployCliOptions {\n\t/** The project directory: `--cwd`, else where the command was run. */\n\tcwd: string;\n\t/** `--target`: where to deploy. Defaults to `deploy.default`. */\n\ttarget?: string;\n\t/** `--provider`, deprecated: `dokploy` means `--target dokploy`. */\n\tprovider?: string;\n\tstage: string;\n\ttag?: string;\n\t/**\n\t * Print each event as one JSON object per line on stdout, instead of the\n\t * progress lines. Nothing prompts: a missing credential fails the run.\n\t */\n\tjson?: boolean;\n\t/** Plan only: create, change, build and push nothing. */\n\tdryRun?: boolean;\n\t/** On a failed release, roll back every app, not only the failed ones. */\n\tatomic?: boolean;\n\t/** `--allow-dev-services minio,mailpit`, as typed. */\n\tallowDevServices?: string;\n}\n\n/** Where the command writes. The process's own streams, outside tests. */\nexport interface DeployCliStreams {\n\tstdout: Pick<NodeJS.WriteStream, 'write'>;\n}\n\n/**\n * Run `gkm deploy` and resolve with its exit code: 0 when the run finished,\n * 1 when anything stopped it.\n */\nexport async function deployCli(\n\toptions: DeployCliOptions,\n\tstreams: DeployCliStreams = { stdout: process.stdout },\n): Promise<number> {\n\tlet target = options.target;\n\tif (options.provider !== undefined && target === undefined) {\n\t\ttry {\n\t\t\t// On stderr, so a `--json` run's stdout still carries only events.\n\t\t\ttarget = targetForProvider(options.provider, (message) =>\n\t\t\t\tconsole.warn(message),\n\t\t\t);\n\t\t} catch (error) {\n\t\t\tconsole.error(formatError(error));\n\t\t\treturn 1;\n\t\t}\n\t}\n\n\tlet allowDevServices: DevService[];\n\ttry {\n\t\tallowDevServices = parseDevServices(options.allowDevServices);\n\t} catch (error) {\n\t\tconsole.error(formatError(error));\n\t\treturn 1;\n\t}\n\n\tconst input = {\n\t\tcwd: options.cwd,\n\t\tstage: options.stage,\n\t\t...(target ? { target } : {}),\n\t\t...(options.tag ? { tag: options.tag } : {}),\n\t\t...(options.dryRun ? { dryRun: true } : {}),\n\t\t...(options.atomic ? { atomic: true } : {}),\n\t\t...(allowDevServices.length > 0 ? { allowDevServices } : {}),\n\t};\n\n\tif (options.json) {\n\t\t// stdout carries the events and nothing else: docker's own output goes\n\t\t// to stderr, and nobody is asked anything — a prompt would be written\n\t\t// into the stream a program is parsing.\n\t\tconst run = deploy({\n\t\t\t...input,\n\t\t\tcredentials: storedCredentials(),\n\t\t\tchildOutput: 'stderr',\n\t\t});\n\t\tfor await (const event of run) {\n\t\t\tstreams.stdout.write(`${JSON.stringify(event)}\\n`);\n\t\t}\n\t\treturn run.result.then(\n\t\t\t() => 0,\n\t\t\t(error) => {\n\t\t\t\tconsole.error(formatError(error));\n\t\t\t\treturn 1;\n\t\t\t},\n\t\t);\n\t}\n\n\t// The lines arrive as they are written, rather than as events read back a\n\t// tick later, so they interleave with a prompt exactly as they always did.\n\tconst run = deploy({\n\t\t...input,\n\t\tcredentials: terminalCredentials(storedCredentials()),\n\t\tlogger: {\n\t\t\tinfo: (message) => console.log(message),\n\t\t\twarn: (message) => console.warn(message),\n\t\t\terror: (message) => console.error(message),\n\t\t},\n\t});\n\n\ttry {\n\t\tawait run.result;\n\t\treturn 0;\n\t} catch (error) {\n\t\tconsole.error(formatError(error));\n\t\treturn 1;\n\t}\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AA+CA,eAAsB,UACrB,SACA,UAA4B,EAAE,QAAQ,QAAQ,OAAO,GACnC;CAClB,IAAI,SAAS,QAAQ;CACrB,IAAI,QAAQ,aAAa,KAAA,KAAa,WAAW,KAAA,GAChD,IAAI;EAEH,SAAS,kBAAkB,QAAQ,WAAW,YAC7C,QAAQ,KAAK,OAAO,CACrB;CACD,SAAS,OAAO;EACf,QAAQ,MAAM,YAAY,KAAK,CAAC;EAChC,OAAO;CACR;CAGD,IAAI;CACJ,IAAI;EACH,mBAAmB,iBAAiB,QAAQ,gBAAgB;CAC7D,SAAS,OAAO;EACf,QAAQ,MAAM,YAAY,KAAK,CAAC;EAChC,OAAO;CACR;CAEA,MAAM,QAAQ;EACb,KAAK,QAAQ;EACb,OAAO,QAAQ;EACf,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;EAC3B,GAAI,QAAQ,MAAM,EAAE,KAAK,QAAQ,IAAI,IAAI,CAAC;EAC1C,GAAI,QAAQ,SAAS,EAAE,QAAQ,KAAK,IAAI,CAAC;EACzC,GAAI,QAAQ,SAAS,EAAE,QAAQ,KAAK,IAAI,CAAC;EACzC,GAAI,iBAAiB,SAAS,IAAI,EAAE,iBAAiB,IAAI,CAAC;CAC3D;CAEA,IAAI,QAAQ,MAAM;EAIjB,MAAM,MAAM,OAAO;GAClB,GAAG;GACH,aAAa,kBAAkB;GAC/B,aAAa;EACd,CAAC;EACD,WAAW,MAAM,SAAS,KACzB,QAAQ,OAAO,MAAM,GAAG,KAAK,UAAU,KAAK,EAAE,GAAG;EAElD,OAAO,IAAI,OAAO,WACX,IACL,UAAU;GACV,QAAQ,MAAM,YAAY,KAAK,CAAC;GAChC,OAAO;EACR,CACD;CACD;CAIA,MAAM,MAAM,OAAO;EAClB,GAAG;EACH,aAAa,oBAAoB,kBAAkB,CAAC;EACpD,QAAQ;GACP,OAAO,YAAY,QAAQ,IAAI,OAAO;GACtC,OAAO,YAAY,QAAQ,KAAK,OAAO;GACvC,QAAQ,YAAY,QAAQ,MAAM,OAAO;EAC1C;CACD,CAAC;CAED,IAAI;EACH,MAAM,IAAI;EACV,OAAO;CACR,SAAS,OAAO;EACf,QAAQ,MAAM,YAAY,KAAK,CAAC;EAChC,OAAO;CACR;AACD"}
@@ -4,9 +4,9 @@ import { r as discover } from "./discover-BPelzeGW.mjs";
4
4
  import { t as appKey } from "./derive-B4vDpzgP.mjs";
5
5
  import { F as LOGS_PORT, I as resolveLogs, M as ComposeTlsFileMissing, N as certificateFor, P as proxyFor } from "./workspace-BBdqmkch.mjs";
6
6
  import { t as defineTarget } from "./define-DR8xGYfL.mjs";
7
- import { $ as constructGlobs, A as isOtlpDestination, Bt as primaryPortKey, C as ensureDockerignore, Ct as hostFor, D as NoDomainForStage, Dt as WORKER_PORT, E as validateImageRef, Et as TURBO_VERSION, G as workerUnits, H as reportDevServices, It as DEFAULT_IMAGES, L as assertExternalServices, O as isMainFrontendApp, R as devServicesUsed, Tt as imageLayout, W as suppliedOnly, _ as DeployJournal, _t as networkEnv, a as createEmptyState, at as applyBuckets, bt as localRolePassword, ct as bucketPolicies, dn as initStageSecrets, ft as composeFor, ht as appEnvKeys, i as assertNoStaleSecrets, j as otelEnv, k as resolveHost, kt as findBuildRoot, l as recordRelease, mt as pgClient, n as reportDatabaseRuns, on as imageRef, ot as applyPolicies, pt as bucketClient, r as reportPlannedSeeds, st as applyPostgres, t as DeploySeedsFailed, ut as postgresStatements, v as withGeneratedSecrets, vt as workerEnvKeys, w as workerDockerfile, wt as composeBuildPaths, x as appDockerfile, xt as planFor, yt as envFor, zt as portKeys } from "./seeds-BdkFpW0P.mjs";
8
- import { i as DEFAULT_EVENTS } from "./SubscriberGenerator-5looQ3gB.mjs";
9
- import { i as installedFrom } from "./drivers-Ch1rJitn.mjs";
7
+ import { $ as postgresSuperuser, $t as EMULATOR_ACCESS_KEY_ID, At as appEnvKeys, Bt as imageLayout, C as workerDockerfile, Dt as ensurePostgresLogin, En as imageRef, Et as LEGACY_LOCAL_LOGIN, Ft as localRolePassword, Ht as WORKER_PORT, I as reportDevServices, It as planFor, M as devServicesUsed, Mt as networkEnv, Nt as workerEnvKeys, Ot as bucketClient, Pt as envFor, Q as loadLocalCredentials, Qt as composeFor, R as suppliedOnly, Rt as hostFor, S as ensureDockerignore, St as bucketPolicies, T as validateImageRef, Vt as TURBO_VERSION, Wt as findBuildRoot, Z as LOCAL_RABBITMQ_USER, _ as DeployJournal, a as createEmptyState, an as primaryPortKey, at as runsRedis, b as appDockerfile, bt as applyPolicies, ct as LOGS_SERVICE, dt as stackLogs, en as DEFAULT_IMAGES, ft as withLogsPassword, gt as otelEnv, ht as resolveHost, i as assertNoStaleSecrets, it as redisService, j as assertExternalServices, jn as initStageSecrets, kt as pgClient, l as recordRelease, lt as logsAccess, mt as isMainFrontendApp, n as reportDatabaseRuns, nt as REDIS_SERVICE, ot as stackRedis, pt as NoDomainForStage, q as constructGlobs, r as reportPlannedSeeds, rn as portKeys, rt as STACK_CACHE, st as withRedisPassword, t as DeploySeedsFailed, tt as withGeneratedSecrets, ut as logsService, wt as postgresStatements, xt as applyPostgres, yt as applyBuckets, z as workerUnits, zt as composeBuildPaths } from "./seeds-DbyqaXW4.mjs";
8
+ import { i as DEFAULT_EVENTS } from "./SubscriberGenerator-DQZeGkDW.mjs";
9
+ import { i as installedFrom } from "./drivers-B4RP2B2O.mjs";
10
10
  import { f as plannedSeeds, o as SeedFailed, p as seedDatabases, u as migrateDatabases } from "./databases-CzszQV0N.mjs";
11
11
  import { n as assertStageCredentials } from "./credentialSchemas-BJqRJNK4.mjs";
12
12
  import { dirname, join } from "node:path";
@@ -15,7 +15,7 @@ import { chmod, copyFile, mkdir, readFile, readdir, rename, rm, writeFile } from
15
15
  import { hostname, userInfo } from "node:os";
16
16
  import { provideKey, provisionOrder, publicEnvFor } from "@geekmidas/manifest";
17
17
  import { spawn } from "node:child_process";
18
- import { createHash, randomBytes } from "node:crypto";
18
+ import { createHash } from "node:crypto";
19
19
  import { stringify } from "yaml";
20
20
  import { request } from "node:https";
21
21
  //#region src/compose/docker.ts
@@ -792,330 +792,6 @@ function pinImages(file, digests, images) {
792
792
  });
793
793
  }
794
794
  //#endregion
795
- //#region src/compose/logs.ts
796
- /**
797
- * The stack's log UI: OpenObserve, run beside the apps when
798
- * `deploy.compose.logs` asks for it, and every backend's OpenTelemetry
799
- * pointed at it.
800
- *
801
- * The production server already exports its traces and pino logs over
802
- * OTLP/HTTP when `OTEL_EXPORTER_OTLP_ENDPOINT` is set. OpenObserve takes OTLP
803
- * at `/api/<org>/v1/{logs,traces}` with HTTP basic auth, so wiring an app is
804
- * two variables: the endpoint, `http://openobserve:5080/api/default`, and
805
- * the header that signs in as the root user.
806
- *
807
- * It is reached, by default, through an SSH tunnel: published on 127.0.0.1
808
- * only, because a port Docker publishes on every interface is opened in the
809
- * firewall by Docker itself, past ufw's rules. Served publicly, it is a host
810
- * on the stack's Caddy that refuses every address not allowed.
811
- *
812
- * Pure: the stack decides it, and the phases print and check it.
813
- */
814
- /**
815
- * The image, pinned. A log store's on-disk format is the thing that must not
816
- * move under a running stack, so a new version is a change to this line.
817
- */
818
- const OPENOBSERVE_IMAGE = "public.ecr.aws/zinclabs/openobserve:v1.0.4";
819
- /** Its compose service name — the host the apps send to. */
820
- const LOGS_SERVICE = "openobserve";
821
- /** The organisation every app's telemetry lands in. */
822
- const LOGS_ORG = "default";
823
- /** The stage secrets that sign in as OpenObserve's root user. */
824
- const LOGS_EMAIL_KEY = "ZO_ROOT_USER_EMAIL";
825
- const LOGS_PASSWORD_KEY = "ZO_ROOT_USER_PASSWORD";
826
- /** The stage sends its telemetry somewhere already, and logs are on too. */
827
- var LogsEndpointConflict = class extends Error {
828
- stage;
829
- keys;
830
- constructor(stage, keys) {
831
- super(`The stage '${stage}' sets ${keys.join(", ")} in its secrets, and deploy.compose.logs also runs OpenObserve for it — each backend can send its telemetry to one place. Either keep your own OTLP backend: remove logs from deploy.compose in gkm.config.ts; or use the bundled OpenObserve: remove ${keys.join(", ")} from the stage's secrets, and every backend is pointed at it.`);
832
- this.stage = stage;
833
- this.keys = keys;
834
- this.name = "LogsEndpointConflict";
835
- }
836
- };
837
- /** A root password OpenObserve would refuse to start with. */
838
- var LogsPasswordWeak = class extends Error {
839
- stage;
840
- constructor(stage) {
841
- super(`The stage '${stage}' sets ${LOGS_PASSWORD_KEY}, and OpenObserve refuses it: a root password must be 8 to 128 characters with a lowercase letter, an uppercase letter, a digit and a symbol. Set another with gkm secrets:set ${LOGS_PASSWORD_KEY} '…' --stage ${stage}, or unset it to have one generated.`);
842
- this.stage = stage;
843
- this.name = "LogsPasswordWeak";
844
- }
845
- };
846
- /** A deployed stage with logs on and no root password generated yet. */
847
- var LogsPasswordMissing = class extends Error {
848
- stage;
849
- constructor(stage) {
850
- super(`The stage '${stage}' runs OpenObserve and has no ${LOGS_PASSWORD_KEY} in its secrets. Run gkm compose --stage ${stage} without --dry-run once to generate it, or set one: gkm secrets:set ${LOGS_PASSWORD_KEY} '…' --stage ${stage}`);
851
- this.stage = stage;
852
- this.name = "LogsPasswordMissing";
853
- }
854
- };
855
- /** Whether OpenObserve accepts `password` for its root user. */
856
- function isStrongLogsPassword(password) {
857
- return password.length >= 8 && password.length <= 128 && /[a-z]/.test(password) && /[A-Z]/.test(password) && /\d/.test(password) && /[^A-Za-z0-9]/.test(password);
858
- }
859
- /**
860
- * A root password: 192 random bits, with a fixed tail so every class
861
- * OpenObserve requires is present whatever the random part drew.
862
- */
863
- function generateLogsPassword() {
864
- return `${randomBytes(24).toString("base64url")}-Zo1`;
865
- }
866
- /**
867
- * The stage's secrets with a generated root password, where it has none.
868
- * Pure, like `withGeneratedSecrets`: the caller keeps the result once the
869
- * run goes ahead.
870
- */
871
- function withLogsPassword(secrets) {
872
- if (secrets.custom?.["ZO_ROOT_USER_PASSWORD"]) return {
873
- secrets,
874
- generated: []
875
- };
876
- return {
877
- secrets: {
878
- ...secrets,
879
- custom: {
880
- ...secrets.custom,
881
- [LOGS_PASSWORD_KEY]: generateLogsPassword()
882
- },
883
- updatedAt: (/* @__PURE__ */ new Date()).toISOString()
884
- },
885
- generated: [LOGS_PASSWORD_KEY]
886
- };
887
- }
888
- /**
889
- * `OTEL_EXPORTER_OTLP_HEADERS` signing in as `email`.
890
- *
891
- * The variable's values are percent-decoded by the SDK (they follow the W3C
892
- * baggage format), so the space after `Basic` is written `%20`. Base64's own
893
- * `+`, `/` and `=` pass through decoding unchanged.
894
- */
895
- function otlpHeaders(email, password) {
896
- return `Authorization=Basic%20${Buffer.from(`${email}:${password}`).toString("base64")}`;
897
- }
898
- /** The stack's OpenObserve for one stage. */
899
- function stackLogs(options) {
900
- const { config, stage, local, custom } = options;
901
- const conflicting = Object.keys(custom).filter(isOtlpDestination).sort();
902
- if (conflicting.length > 0) throw new LogsEndpointConflict(stage, conflicting);
903
- if (!local && !options.domain) throw new NoDomainForStage(stage);
904
- const email = custom["ZO_ROOT_USER_EMAIL"] ?? (local ? "admin@gkm.localhost" : `admin@${options.domain}`);
905
- const set = custom[LOGS_PASSWORD_KEY];
906
- if (!set && !local) throw new LogsPasswordMissing(stage);
907
- const password = set ?? "Geekmidas-1";
908
- if (!isStrongLogsPassword(password)) throw new LogsPasswordWeak(stage);
909
- const host = config.public ? local ? `logs.${options.project}.localhost` : `logs.${options.domain}` : void 0;
910
- const url = host ? `https://${host}${local && options.https !== 443 ? `:${options.https}` : ""}` : `http://localhost:${config.port}`;
911
- return {
912
- ...config,
913
- email,
914
- password,
915
- passwordFromSecrets: Boolean(set),
916
- url,
917
- ...host ? { host } : {},
918
- env: {
919
- [LOGS_EMAIL_KEY]: email,
920
- [LOGS_PASSWORD_KEY]: password,
921
- ZO_DATA_DIR: "/data",
922
- ZO_COMPACT_DATA_RETENTION_DAYS: String(config.retentionDays),
923
- ZO_TELEMETRY: "false"
924
- },
925
- appEnv: {
926
- OTEL_EXPORTER_OTLP_ENDPOINT: `http://${LOGS_SERVICE}:${LOGS_PORT}/api/${LOGS_ORG}`,
927
- OTEL_EXPORTER_OTLP_HEADERS: otlpHeaders(email, password)
928
- }
929
- };
930
- }
931
- /**
932
- * OpenObserve's service. The image has no shell, `wget` or `curl`, so its
933
- * health check is its own binary asking the running server for its status —
934
- * which exits non-zero when nothing answers on its port.
935
- */
936
- function logsService(logs) {
937
- return {
938
- image: OPENOBSERVE_IMAGE,
939
- restart: "unless-stopped",
940
- env_file: [{
941
- path: `./${LOGS_SERVICE}.env`,
942
- format: "raw"
943
- }],
944
- volumes: ["openobserve-data:/data"],
945
- ...logs.public ? {} : { ports: [`127.0.0.1:${logs.port}:${LOGS_PORT}`] },
946
- healthcheck: {
947
- test: [
948
- "CMD",
949
- "/openobserve",
950
- "node",
951
- "status"
952
- ],
953
- interval: "10s",
954
- timeout: "5s",
955
- retries: 12,
956
- start_period: "20s"
957
- }
958
- };
959
- }
960
- /** What `gkm compose` prints once the stack is up: how to open the logs. */
961
- function logsAccess(logs, ctx) {
962
- const login = `login: ${logs.email}, password: ${ctx.local && !logs.passwordFromSecrets ? logs.password : `gkm secrets:show --stage ${ctx.stage} --reveal → ${LOGS_PASSWORD_KEY}`}`;
963
- if (logs.public) return [`📜 Logs (OpenObserve): ${logs.url} (${login})`, ` answered only for ${logs.public.allow.join(", ")}; every other address gets 403`];
964
- return [
965
- `📜 Logs (OpenObserve) on 127.0.0.1:${logs.port} — from your computer:`,
966
- ...ctx.local ? [` on this machine, open http://localhost:${logs.port} directly; from another:`] : [],
967
- ` ssh -N -L ${logs.port}:localhost:${logs.port} ${ctx.user}@${ctx.hostname} (user and host are guesses: this machine's)`,
968
- ` then open http://localhost:${logs.port} (${login})`,
969
- `⚠️ Docker-published ports bypass ufw, so OpenObserve is bound to 127.0.0.1 only — reach it through the tunnel, not by opening the port.`
970
- ];
971
- }
972
- //#endregion
973
- //#region src/compose/redis.ts
974
- /**
975
- * The stack's Redis: what every declared cache lives in when a workspace runs
976
- * as a `gkm compose` stack, on the local stage and on a deployed one alike.
977
- *
978
- * A cache is the one store whose contents can always be rebuilt, so unlike
979
- * Mailpit and MinIO it is a production service, not a dev stand-in: it runs
980
- * for every stage, on the compose network only, with nothing published. It
981
- * is bounded (`maxmemory`, evicting the least recently used key), persisted
982
- * (an append-only file on a named volume, kept by `--down`) and password
983
- * protected — the stage's own password, generated once like its seed.
984
- *
985
- * A stage that sets a cache's URL in its secrets — a managed Redis — keeps
986
- * it, and a stack whose every cache is set that way runs no Redis at all.
987
- *
988
- * Pure: the stack decides it, and the phases keep the password.
989
- */
990
- /**
991
- * Where a stack's caches live: its own Redis, whatever the deploy target's
992
- * default is. A stack is one machine running containers, and a Redis beside
993
- * the apps is cheaper for a cache than a table in the database they share.
994
- */
995
- const STACK_CACHE = "redis";
996
- /** Its compose service name — the host every cache URL points at. */
997
- const REDIS_SERVICE = "redis";
998
- /** The port it answers on, inside the network. */
999
- const REDIS_PORT = 6379;
1000
- /** Reconcile's pin, so `gkm dev` and the stack run one Redis. */
1001
- const REDIS_IMAGE = DEFAULT_IMAGES.redis;
1002
- /**
1003
- * How much it may hold before it evicts. A cache that grows until the box
1004
- * runs out of memory takes the apps with it; 256 MB is a lot of sessions and
1005
- * little of a small server. A project's `docker-compose.<stage>.yml` can
1006
- * replace the command to change it.
1007
- */
1008
- const REDIS_MAXMEMORY = "256mb";
1009
- /** The stage secret holding its password. */
1010
- const REDIS_PASSWORD_KEY = "REDIS_PASSWORD";
1011
- /** Redis's own count of logical databases, before `--databases` raises it. */
1012
- const REDIS_DATABASES = 16;
1013
- /** A deployed stage that runs the stack's Redis and has no password yet. */
1014
- var RedisPasswordMissing = class extends Error {
1015
- stage;
1016
- constructor(stage) {
1017
- super(`The stage '${stage}' runs the stack's Redis and has no ${REDIS_PASSWORD_KEY} in its secrets. Run gkm compose --stage ${stage} without --dry-run once to generate it, or set one: gkm secrets:set ${REDIS_PASSWORD_KEY} '…' --stage ${stage}`);
1018
- this.stage = stage;
1019
- this.name = "RedisPasswordMissing";
1020
- }
1021
- };
1022
- /**
1023
- * Whether a stage's stack runs Redis: a cache is declared and the stage's
1024
- * secrets do not set the URL of every one.
1025
- */
1026
- function runsRedis(manifest, custom) {
1027
- return Object.values(manifest).some((declaration) => declaration?.kind === "cache" && (declaration.provides ?? []).some((key) => custom[key] === void 0));
1028
- }
1029
- /** A password: 256 random bits, URL-safe, so it sits in a URL unescaped. */
1030
- function generateRedisPassword() {
1031
- return randomBytes(32).toString("base64url");
1032
- }
1033
- /**
1034
- * The stage's secrets with a generated Redis password, where it has none.
1035
- * Pure, like `withGeneratedSecrets`: the caller keeps the result once the run
1036
- * goes ahead.
1037
- */
1038
- function withRedisPassword(secrets) {
1039
- if (secrets.custom?.["REDIS_PASSWORD"]) return {
1040
- secrets,
1041
- generated: []
1042
- };
1043
- return {
1044
- secrets: {
1045
- ...secrets,
1046
- custom: {
1047
- ...secrets.custom,
1048
- [REDIS_PASSWORD_KEY]: generateRedisPassword()
1049
- },
1050
- updatedAt: (/* @__PURE__ */ new Date()).toISOString()
1051
- },
1052
- generated: [REDIS_PASSWORD_KEY]
1053
- };
1054
- }
1055
- /**
1056
- * The stack's Redis for one stage, or nothing where no cache needs it.
1057
- *
1058
- * Each cache it holds gets a logical database of its own, by the order of
1059
- * their ids, so two caches never read each other's keys.
1060
- */
1061
- function stackRedis(options) {
1062
- const { plan, stage, local, custom } = options;
1063
- const caches = plan.resources.filter((r) => r.kind === "cache" && custom[r.envKey] === void 0).sort((a, b) => a.id.localeCompare(b.id));
1064
- if (caches.length === 0) return void 0;
1065
- const set = custom[REDIS_PASSWORD_KEY];
1066
- if (!set && !local) throw new RedisPasswordMissing(stage);
1067
- const password = set ?? "geekmidas";
1068
- const auth = encodeURIComponent(password);
1069
- return {
1070
- password,
1071
- passwordFromSecrets: Boolean(set),
1072
- urls: Object.fromEntries(caches.map((cache, index) => [cache.envKey, `redis://:${auth}@${REDIS_SERVICE}:${REDIS_PORT}/${index}`])),
1073
- env: {
1074
- [REDIS_PASSWORD_KEY]: password,
1075
- REDISCLI_AUTH: password
1076
- },
1077
- databases: Math.max(REDIS_DATABASES, caches.length)
1078
- };
1079
- }
1080
- /**
1081
- * Redis's service: bounded, persisted and password protected, on the
1082
- * network alone.
1083
- *
1084
- * The command runs the image's own entrypoint with `redis-server` first, so
1085
- * it still drops to the `redis` user and owns `/data`; the password is read
1086
- * from the env file by the shell (`$$` is compose's escape for `$`), so
1087
- * neither the compose file nor the container's command holds it.
1088
- */
1089
- function redisService(redis) {
1090
- const flags = [
1091
- `--requirepass "$$${REDIS_PASSWORD_KEY}"`,
1092
- `--maxmemory ${REDIS_MAXMEMORY}`,
1093
- "--maxmemory-policy allkeys-lru",
1094
- "--appendonly yes",
1095
- ...redis.databases > REDIS_DATABASES ? [`--databases ${redis.databases}`] : []
1096
- ];
1097
- return {
1098
- image: REDIS_IMAGE,
1099
- restart: "unless-stopped",
1100
- command: [
1101
- "sh",
1102
- "-c",
1103
- `exec docker-entrypoint.sh redis-server ${flags.join(" ")}`
1104
- ],
1105
- env_file: [{
1106
- path: `./${REDIS_SERVICE}.env`,
1107
- format: "raw"
1108
- }],
1109
- volumes: ["redis-data:/data"],
1110
- healthcheck: {
1111
- test: ["CMD-SHELL", "redis-cli ping | grep -q PONG"],
1112
- interval: "5s",
1113
- timeout: "3s",
1114
- retries: 10
1115
- }
1116
- };
1117
- }
1118
- //#endregion
1119
795
  //#region src/compose/caddyfile.ts
1120
796
  /** Where Caddy reads a stage's own certificate, inside its container. */
1121
797
  const CADDY_TLS_DIR = "/etc/caddy/tls";
@@ -1246,6 +922,43 @@ const LOG_ROTATION = {
1246
922
  "max-file": "3"
1247
923
  }
1248
924
  };
925
+ /** The local stage's stack, without the logins `gkm dev` generates. */
926
+ var LocalCredentialsMissing = class extends Error {
927
+ stage;
928
+ constructor(stage) {
929
+ super(`The local stage '${stage}' runs with this machine's generated logins, and none were passed. Load them with loadLocalCredentials(workspace) and pass them as localCredentials.`);
930
+ this.stage = stage;
931
+ this.name = "LocalCredentialsMissing";
932
+ }
933
+ };
934
+ /**
935
+ * A deployed stage's container logins, derived from its seed like its role
936
+ * passwords — so every deploy of the stage computes the same ones, and no one
937
+ * reading the repo can.
938
+ */
939
+ function derivedCredentials(project, plan, seed) {
940
+ const derive = (purpose) => localRolePassword(project, plan, purpose, seed);
941
+ return {
942
+ postgres: {
943
+ user: postgresSuperuser(project),
944
+ password: derive("master")
945
+ },
946
+ minio: {
947
+ user: `${project}-minio`,
948
+ password: derive("minio")
949
+ },
950
+ rabbitmq: {
951
+ user: LOCAL_RABBITMQ_USER,
952
+ password: derive("rabbitmq")
953
+ },
954
+ redis: { password: derive("redis") },
955
+ cacheToken: derive("cache-token"),
956
+ emulator: {
957
+ accessKeyId: EMULATOR_ACCESS_KEY_ID,
958
+ secretAccessKey: derive("emulator")
959
+ }
960
+ };
961
+ }
1249
962
  /** A value only the stage's secrets can hold, and they do not. */
1250
963
  var StageSecretMissing = class extends Error {
1251
964
  app;
@@ -1328,11 +1041,19 @@ function composeStack(input) {
1328
1041
  edge: false
1329
1042
  });
1330
1043
  const byId = new Map(plan.resources.map((r) => [r.id, r]));
1331
- const seed = local ? void 0 : input.secrets?.seed;
1332
- if (!local && !seed) throw new StageSeedMissing(stage);
1044
+ if (local && !input.localCredentials) throw new LocalCredentialsMissing(stage);
1045
+ const seed = local ? input.localCredentials.seed : input.secrets?.seed;
1046
+ if (!seed) throw new StageSeedMissing(stage);
1047
+ const containers = local ? input.localCredentials : derivedCredentials(workspace.name, plan, seed);
1333
1048
  const credential = {
1334
- master: local ? "geekmidas" : localRolePassword(workspace.name, plan, "master", seed),
1335
- ...seed ? { seed } : {}
1049
+ containers: {
1050
+ ...containers,
1051
+ minio: {
1052
+ user: custom.AWS_ACCESS_KEY_ID ?? containers.minio.user,
1053
+ password: custom.AWS_SECRET_ACCESS_KEY ?? containers.minio.password
1054
+ }
1055
+ },
1056
+ seed
1336
1057
  };
1337
1058
  const apps = stackApps(workspace, manifest, plan, {
1338
1059
  local,
@@ -1371,7 +1092,8 @@ function composeStack(input) {
1371
1092
  project: workspace.name,
1372
1093
  ...domain ? { domain } : {},
1373
1094
  custom,
1374
- https
1095
+ https,
1096
+ ...local ? { localLogin: input.localCredentials.logs } : {}
1375
1097
  }) : void 0;
1376
1098
  const services = local ? {
1377
1099
  missing: [],
@@ -1388,14 +1110,14 @@ function composeStack(input) {
1388
1110
  plan,
1389
1111
  stage,
1390
1112
  local,
1391
- custom
1113
+ custom,
1114
+ ...local ? { localPassword: input.localCredentials.redis.password } : {}
1392
1115
  });
1393
1116
  const infra = [...plan.containers.filter((c) => !NOT_RUN[c]).filter((c) => c !== "minio" || services.minio.length > 0).filter((c) => c !== "mailpit" || services.mailpit.length > 0).filter((c) => c !== "redis" || redis !== void 0), ...logsBase ? [LOGS_SERVICE] : []].sort();
1394
1117
  const storage = infra.includes("minio") ? (() => {
1395
1118
  const buckets = services.minio.map((id) => byId.get(id)?.name).filter((name) => Boolean(name)).sort();
1396
1119
  return {
1397
- user: custom.AWS_ACCESS_KEY_ID ?? (local ? "geekmidas" : `${workspace.name}-minio`),
1398
- password: custom.AWS_SECRET_ACCESS_KEY ?? (local ? "geekmidas" : localRolePassword(workspace.name, plan, "minio", seed)),
1120
+ ...credential.containers.minio,
1399
1121
  buckets,
1400
1122
  policies: bucketPolicies(plan).filter((p) => buckets.includes(p.bucket))
1401
1123
  };
@@ -1442,8 +1164,8 @@ function composeStack(input) {
1442
1164
  };
1443
1165
  const derivation = {
1444
1166
  project: workspace.name,
1445
- master: credential.master,
1446
- ...credential.seed ? { seed: credential.seed } : {},
1167
+ credentials: credential.containers,
1168
+ seed: credential.seed,
1447
1169
  ...!local && domain ? { mailFrom: `noreply@${domain}` } : {}
1448
1170
  };
1449
1171
  const outside = networkEnv(plan, {
@@ -1559,7 +1281,7 @@ function composeStack(input) {
1559
1281
  infra,
1560
1282
  apps,
1561
1283
  workers,
1562
- master: credential.master,
1284
+ credentials: credential.containers,
1563
1285
  ...storage ? { storage } : {},
1564
1286
  ...logs ? { logs } : {},
1565
1287
  ...redis ? { redis } : {},
@@ -1747,7 +1469,8 @@ function stackFile(options) {
1747
1469
  containers: [...infra]
1748
1470
  }, {
1749
1471
  project,
1750
- ports: Object.fromEntries(portKeys(infra, plan.fakes).map((key) => [key, 0]))
1472
+ ports: Object.fromEntries(portKeys(infra, plan.fakes).map((key) => [key, 0])),
1473
+ credentials: options.credentials
1751
1474
  });
1752
1475
  const services = {};
1753
1476
  const volumes = {
@@ -1766,13 +1489,7 @@ function stackFile(options) {
1766
1489
  };
1767
1490
  }
1768
1491
  const postgres = services.postgres;
1769
- if (postgres) {
1770
- postgres.environment = {
1771
- ...postgres.environment,
1772
- POSTGRES_PASSWORD: options.master
1773
- };
1774
- postgres.ports = ["127.0.0.1::5432"];
1775
- }
1492
+ if (postgres) postgres.ports = ["127.0.0.1::5432"];
1776
1493
  const minio = services.minio;
1777
1494
  if (minio && options.storage) {
1778
1495
  minio.environment = {
@@ -2064,6 +1781,7 @@ const defaultDeps = {
2064
1781
  revision: gitRevision,
2065
1782
  sql: pgClient,
2066
1783
  buckets: bucketClient,
1784
+ logins: ensurePostgresLogin,
2067
1785
  migrate: migrateDatabases,
2068
1786
  seed: seedDatabases,
2069
1787
  probe: httpsProbe,
@@ -2122,6 +1840,7 @@ async function validateCompose(ctx, deps, options = {}) {
2122
1840
  ...registry ? { registry } : {}
2123
1841
  },
2124
1842
  secrets,
1843
+ ...stage === workspace.stages.local ? { localCredentials: (await loadLocalCredentials(workspace)).credentials } : {},
2125
1844
  allowDevServices: ctx.allowDevServices,
2126
1845
  ports: edgePorts(deps.env),
2127
1846
  ...layout ? { layout } : {},
@@ -2390,10 +2109,20 @@ async function prepareDatabases(ctx, run, deps) {
2390
2109
  const { stack } = run;
2391
2110
  const workspace = ctx.workspace;
2392
2111
  const port = await deps.docker.port(run.ref, "postgres", 5432);
2112
+ const superuser = stack.credential.containers.postgres;
2113
+ const login = await deps.logins({
2114
+ port,
2115
+ login: superuser,
2116
+ legacy: [{
2117
+ user: LEGACY_LOCAL_LOGIN.user,
2118
+ password: superuser.password
2119
+ }, ...stack.local ? [LEGACY_LOCAL_LOGIN] : []]
2120
+ });
2121
+ if (login.notice) ctx.logger.info(login.notice);
2393
2122
  const statements = postgresStatements(stack.plan, workspace.name, stack.credential.seed);
2394
2123
  if (statements.length > 0) {
2395
2124
  ctx.logger.info("🗄️ Creating databases, roles and grants…");
2396
- await applyPostgres(deps.sql(port, stack.credential.master), statements);
2125
+ await applyPostgres(deps.sql(port, login.login), statements);
2397
2126
  }
2398
2127
  const sources = {};
2399
2128
  const manifest = await discover({
@@ -2404,8 +2133,11 @@ async function prepareDatabases(ctx, run, deps) {
2404
2133
  const env = envFor(stack.plan, {
2405
2134
  ports: { [primaryPortKey("postgres")]: port },
2406
2135
  project: workspace.name,
2407
- master: stack.credential.master,
2408
- ...stack.credential.seed ? { seed: stack.credential.seed } : {}
2136
+ credentials: {
2137
+ ...stack.credential.containers,
2138
+ postgres: login.login
2139
+ },
2140
+ seed: stack.credential.seed
2409
2141
  });
2410
2142
  const options = {
2411
2143
  root: workspace.root,
@@ -2856,4 +2588,4 @@ function composeTarget(options = {}) {
2856
2588
  //#endregion
2857
2589
  export { stackOverrideFile as a, parseDigests as c, removeEdgeRoutes as d, EDGE_PROJECT as f, ComposePushNeedsBuild as i, pinnedRef as l, compose_exports as n, composeProject as o, dockerCompose as p, ComposePinNeedsPull as r, stackDir as s, composeTarget as t, edgeDir as u };
2858
2590
 
2859
- //# sourceMappingURL=compose-n7K8H5j8.mjs.map
2591
+ //# sourceMappingURL=compose-D4sD4Lgr.mjs.map