@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.
- package/dist/{EndpointGenerator-DftalLYg.mjs → EndpointGenerator-DtnIGafh.mjs} +71 -8
- package/dist/EndpointGenerator-DtnIGafh.mjs.map +1 -0
- package/dist/{EndpointGenerator-CP6sBvQV.cjs → EndpointGenerator-cKlnllIu.cjs} +88 -7
- package/dist/EndpointGenerator-cKlnllIu.cjs.map +1 -0
- package/dist/{OpenApiTsGenerator-nu1r1NgB.mjs → OpenApiTsGenerator-ByRPMbBN.mjs} +34 -7
- package/dist/OpenApiTsGenerator-ByRPMbBN.mjs.map +1 -0
- package/dist/{OpenApiTsGenerator-CKBCckKz.cjs → OpenApiTsGenerator-CdUM6Hvv.cjs} +34 -7
- package/dist/OpenApiTsGenerator-CdUM6Hvv.cjs.map +1 -0
- package/dist/{SubscriberGenerator-CajwOa5W.cjs → SubscriberGenerator-CYriX5BV.cjs} +2 -2
- package/dist/{SubscriberGenerator-CajwOa5W.cjs.map → SubscriberGenerator-CYriX5BV.cjs.map} +1 -1
- package/dist/{SubscriberGenerator-5looQ3gB.mjs → SubscriberGenerator-DQZeGkDW.mjs} +2 -2
- package/dist/{SubscriberGenerator-5looQ3gB.mjs.map → SubscriberGenerator-DQZeGkDW.mjs.map} +1 -1
- package/dist/{add-DJ0VE-y-.cjs → add-1T3y6E4M.cjs} +2 -2
- package/dist/{add-DJ0VE-y-.cjs.map → add-1T3y6E4M.cjs.map} +1 -1
- package/dist/{add-CIxT-Iq6.mjs → add-DnYHJOap.mjs} +2 -2
- package/dist/{add-CIxT-Iq6.mjs.map → add-DnYHJOap.mjs.map} +1 -1
- package/dist/{bundler-D4pl87A5.mjs → bundler-DlKdxCGh.mjs} +3 -3
- package/dist/{bundler-D4pl87A5.mjs.map → bundler-DlKdxCGh.mjs.map} +1 -1
- package/dist/{bundler-BlbSLFLn.cjs → bundler-YNvLdvlh.cjs} +3 -3
- package/dist/{bundler-BlbSLFLn.cjs.map → bundler-YNvLdvlh.cjs.map} +1 -1
- package/dist/{cli-BkNZBe_-.cjs → cli-CWee1-wU.cjs} +3 -3
- package/dist/{cli-BkNZBe_-.cjs.map → cli-CWee1-wU.cjs.map} +1 -1
- package/dist/{cli-7aLfgIGt.mjs → cli-qMszGvDu.mjs} +3 -3
- package/dist/{cli-7aLfgIGt.mjs.map → cli-qMszGvDu.mjs.map} +1 -1
- package/dist/{compose-n7K8H5j8.mjs → compose-D4sD4Lgr.mjs} +83 -351
- package/dist/compose-D4sD4Lgr.mjs.map +1 -0
- package/dist/{compose-Bn4OJONR.cjs → compose-qnDyPJNp.cjs} +101 -369
- package/dist/compose-qnDyPJNp.cjs.map +1 -0
- package/dist/deploy/public.cjs +5 -5
- package/dist/deploy/public.d.cts.map +1 -1
- package/dist/deploy/public.d.mts.map +1 -1
- package/dist/deploy/public.mjs +5 -5
- package/dist/{deploy-DK4Y6ev4.mjs → deploy-C00DAKOt.mjs} +3 -3
- package/dist/{deploy-DK4Y6ev4.mjs.map → deploy-C00DAKOt.mjs.map} +1 -1
- package/dist/{deploy-Ppnh8MHS.cjs → deploy-CXP2fXvK.cjs} +3 -3
- package/dist/{deploy-Ppnh8MHS.cjs.map → deploy-CXP2fXvK.cjs.map} +1 -1
- package/dist/{dokploy-Bjq05wkw.mjs → dokploy-B3zoCmJb.mjs} +2 -2
- package/dist/{dokploy-Bjq05wkw.mjs.map → dokploy-B3zoCmJb.mjs.map} +1 -1
- package/dist/{dokploy-CJvdoNc3.cjs → dokploy-BHcSmghb.cjs} +2 -2
- package/dist/{dokploy-CJvdoNc3.cjs.map → dokploy-BHcSmghb.cjs.map} +1 -1
- package/dist/{drivers-Ch1rJitn.mjs → drivers-B4RP2B2O.mjs} +2 -2
- package/dist/{drivers-Ch1rJitn.mjs.map → drivers-B4RP2B2O.mjs.map} +1 -1
- package/dist/{drivers-BdvtCKc7.cjs → drivers-CJx76mcb.cjs} +2 -2
- package/dist/{drivers-BdvtCKc7.cjs.map → drivers-CJx76mcb.cjs.map} +1 -1
- package/dist/{encryption-CAyR6D7B.cjs → encryption-DLin89I_.cjs} +2 -2
- package/dist/{encryption-CAyR6D7B.cjs.map → encryption-DLin89I_.cjs.map} +1 -1
- package/dist/{encryption-BrsOJFFz.mjs → encryption-DPFljXtM.mjs} +2 -2
- package/dist/{encryption-BrsOJFFz.mjs.map → encryption-DPFljXtM.mjs.map} +1 -1
- package/dist/{engine-DzBZR5D0.cjs → engine-BS3iX9Mu.cjs} +2 -2
- package/dist/{engine-DzBZR5D0.cjs.map → engine-BS3iX9Mu.cjs.map} +1 -1
- package/dist/{engine-ba9CvjTo.mjs → engine-CgzgIg-_.mjs} +2 -2
- package/dist/{engine-ba9CvjTo.mjs.map → engine-CgzgIg-_.mjs.map} +1 -1
- package/dist/{github-BLjU59Ye.cjs → github-D8KVmNRg.cjs} +2 -2
- package/dist/{github-BLjU59Ye.cjs.map → github-D8KVmNRg.cjs.map} +1 -1
- package/dist/{github-CVdbVlT5.mjs → github-DL4zwJsR.mjs} +2 -2
- package/dist/{github-CVdbVlT5.mjs.map → github-DL4zwJsR.mjs.map} +1 -1
- package/dist/index.cjs +225 -49
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +226 -50
- package/dist/index.mjs.map +1 -1
- package/dist/{migrate-iEdyEx4S.cjs → migrate-BdKhIJgT.cjs} +2 -2
- package/dist/{migrate-iEdyEx4S.cjs.map → migrate-BdKhIJgT.cjs.map} +1 -1
- package/dist/{migrate-DlBgATa-.mjs → migrate-CCejlgU0.mjs} +2 -2
- package/dist/{migrate-DlBgATa-.mjs.map → migrate-CCejlgU0.mjs.map} +1 -1
- package/dist/{migrate-pfu4aYzX.mjs → migrate-Cd3kcI7o.mjs} +2 -2
- package/dist/{migrate-pfu4aYzX.mjs.map → migrate-Cd3kcI7o.mjs.map} +1 -1
- package/dist/{migrate-DkB833Jj.cjs → migrate-DIjG8-QR.cjs} +2 -2
- package/dist/{migrate-DkB833Jj.cjs.map → migrate-DIjG8-QR.cjs.map} +1 -1
- package/dist/openapi.cjs +16 -11
- package/dist/openapi.cjs.map +1 -1
- package/dist/openapi.d.cts +28 -0
- package/dist/openapi.d.cts.map +1 -1
- package/dist/openapi.d.mts +28 -0
- package/dist/openapi.d.mts.map +1 -1
- package/dist/openapi.mjs +16 -12
- package/dist/openapi.mjs.map +1 -1
- package/dist/{ready-BB9xS4S9.cjs → ready-4kx2pAhm.cjs} +5 -5
- package/dist/{ready-BB9xS4S9.cjs.map → ready-4kx2pAhm.cjs.map} +1 -1
- package/dist/{ready-ZZoNskrr.mjs → ready-DhZbZtFw.mjs} +5 -5
- package/dist/{ready-ZZoNskrr.mjs.map → ready-DhZbZtFw.mjs.map} +1 -1
- package/dist/{resolve-4_5N67Fk.cjs → resolve-ApSUK_HB.cjs} +3 -3
- package/dist/{resolve-4_5N67Fk.cjs.map → resolve-ApSUK_HB.cjs.map} +1 -1
- package/dist/{resolve-CQPn66jr.mjs → resolve-DY9TaVeV.mjs} +3 -3
- package/dist/{resolve-CQPn66jr.mjs.map → resolve-DY9TaVeV.mjs.map} +1 -1
- package/dist/{rollback-CgYUPLbq.cjs → rollback-CdGhCk1d.cjs} +3 -3
- package/dist/{rollback-CgYUPLbq.cjs.map → rollback-CdGhCk1d.cjs.map} +1 -1
- package/dist/{rollback-C0cbdsM-.mjs → rollback-DXU6cr7q.mjs} +3 -3
- package/dist/{rollback-C0cbdsM-.mjs.map → rollback-DXU6cr7q.mjs.map} +1 -1
- package/dist/{seeds-ZljwYV_p.cjs → seeds-BLzrSwEr.cjs} +3889 -2953
- package/dist/seeds-BLzrSwEr.cjs.map +1 -0
- package/dist/{seeds-BdkFpW0P.mjs → seeds-DbyqaXW4.mjs} +2344 -1528
- package/dist/seeds-DbyqaXW4.mjs.map +1 -0
- package/dist/target/public.cjs +1 -1
- package/dist/target/public.mjs +1 -1
- package/dist/vitest.cjs +1 -1
- package/dist/vitest.mjs +1 -1
- package/package.json +15 -15
- package/dist/EndpointGenerator-CP6sBvQV.cjs.map +0 -1
- package/dist/EndpointGenerator-DftalLYg.mjs.map +0 -1
- package/dist/OpenApiTsGenerator-CKBCckKz.cjs.map +0 -1
- package/dist/OpenApiTsGenerator-nu1r1NgB.mjs.map +0 -1
- package/dist/compose-Bn4OJONR.cjs.map +0 -1
- package/dist/compose-n7K8H5j8.mjs.map +0 -1
- package/dist/seeds-BdkFpW0P.mjs.map +0 -1
- package/dist/seeds-ZljwYV_p.cjs.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli-
|
|
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 {
|
|
3
|
-
import { t as deploy } from "./deploy-
|
|
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-
|
|
76
|
+
//# sourceMappingURL=cli-qMszGvDu.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli-
|
|
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
|
|
8
|
-
import { i as DEFAULT_EVENTS } from "./SubscriberGenerator-
|
|
9
|
-
import { i as installedFrom } from "./drivers-
|
|
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
|
|
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
|
-
|
|
1332
|
-
|
|
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
|
-
|
|
1335
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1446
|
-
|
|
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
|
-
|
|
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,
|
|
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
|
-
|
|
2408
|
-
|
|
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-
|
|
2591
|
+
//# sourceMappingURL=compose-D4sD4Lgr.mjs.map
|