@geekmidas/cli 10.0.0-alpha.62 → 10.0.0-alpha.64
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/README.md +2 -0
- package/dist/{HostingerProvider-DyD1Hin8.cjs → HostingerProvider-Bx2lHHvu.cjs} +3 -3
- package/dist/{HostingerProvider-DyD1Hin8.cjs.map → HostingerProvider-Bx2lHHvu.cjs.map} +1 -1
- package/dist/{HostingerProvider-B92qH4dC.mjs → HostingerProvider-Cd4aS5Kj.mjs} +2 -2
- package/dist/{HostingerProvider-B92qH4dC.mjs.map → HostingerProvider-Cd4aS5Kj.mjs.map} +1 -1
- package/dist/{LegacyStateStore-UHJEBLdn.cjs → LegacyStateStore-C2abV49N.cjs} +2 -2
- package/dist/{LegacyStateStore-UHJEBLdn.cjs.map → LegacyStateStore-C2abV49N.cjs.map} +1 -1
- package/dist/{LegacyStateStore-A8d2GdT7.mjs → LegacyStateStore-DIgkGaUP.mjs} +2 -2
- package/dist/{LegacyStateStore-A8d2GdT7.mjs.map → LegacyStateStore-DIgkGaUP.mjs.map} +1 -1
- package/dist/{LocalStateStore-B51rnfgn.mjs → LocalStateStore-Cy1ZBW7U.mjs} +2 -2
- package/dist/{LocalStateStore-B51rnfgn.mjs.map → LocalStateStore-Cy1ZBW7U.mjs.map} +1 -1
- package/dist/{LocalStateStore-COW3Ldwa.cjs → LocalStateStore-DiJqKyPy.cjs} +2 -2
- package/dist/{LocalStateStore-COW3Ldwa.cjs.map → LocalStateStore-DiJqKyPy.cjs.map} +1 -1
- package/dist/{OpenApiTsGenerator-BSrgw7B0.cjs → OpenApiTsGenerator-BWuDRHe9.cjs} +2 -2
- package/dist/{OpenApiTsGenerator-BSrgw7B0.cjs.map → OpenApiTsGenerator-BWuDRHe9.cjs.map} +1 -1
- package/dist/{OpenApiTsGenerator-q5B0z8Xg.mjs → OpenApiTsGenerator-C6v-IeHt.mjs} +2 -2
- package/dist/{OpenApiTsGenerator-q5B0z8Xg.mjs.map → OpenApiTsGenerator-C6v-IeHt.mjs.map} +1 -1
- package/dist/{S3StateStore-CJewPhgz.mjs → S3StateStore-D3x6ivBL.mjs} +2 -2
- package/dist/{S3StateStore-CJewPhgz.mjs.map → S3StateStore-D3x6ivBL.mjs.map} +1 -1
- package/dist/{S3StateStore-WUJGdRNL.cjs → S3StateStore-Ds0V1Lgm.cjs} +2 -2
- package/dist/{S3StateStore-WUJGdRNL.cjs.map → S3StateStore-Ds0V1Lgm.cjs.map} +1 -1
- package/dist/{SSMStateStore-Zejt42V8.cjs → SSMStateStore-CLipvx47.cjs} +2 -2
- package/dist/{SSMStateStore-Zejt42V8.cjs.map → SSMStateStore-CLipvx47.cjs.map} +1 -1
- package/dist/{SSMStateStore-iK5UKp9d.mjs → SSMStateStore-DfF174xQ.mjs} +2 -2
- package/dist/{SSMStateStore-iK5UKp9d.mjs.map → SSMStateStore-DfF174xQ.mjs.map} +1 -1
- package/dist/{bundler-CfH9frOS.cjs → bundler-C8uJf324.cjs} +4 -4
- package/dist/{bundler-CfH9frOS.cjs.map → bundler-C8uJf324.cjs.map} +1 -1
- package/dist/{bundler-DN5r4x5b.mjs → bundler-DYgm9xsd.mjs} +3 -3
- package/dist/{bundler-DN5r4x5b.mjs.map → bundler-DYgm9xsd.mjs.map} +1 -1
- package/dist/{cli-DYwxmfsW.mjs → cli-Bogz-zEj.mjs} +5 -4
- package/dist/{cli-DYwxmfsW.mjs.map → cli-Bogz-zEj.mjs.map} +1 -1
- package/dist/{cli-DOAUp80L.cjs → cli-D3jofJ6j.cjs} +7 -6
- package/dist/{cli-DOAUp80L.cjs.map → cli-D3jofJ6j.cjs.map} +1 -1
- package/dist/config-Be-4_I6H.d.cts +256 -0
- package/dist/config-Be-4_I6H.d.cts.map +1 -0
- package/dist/config-DqNRiQOp.d.mts +256 -0
- package/dist/config-DqNRiQOp.d.mts.map +1 -0
- package/dist/config.cjs +416 -13
- package/dist/config.cjs.map +1 -0
- package/dist/config.d.cts +4 -211
- package/dist/config.d.mts +4 -211
- package/dist/config.mjs +402 -3
- package/dist/config.mjs.map +1 -0
- package/dist/credentials-B70vmLcm.cjs +125 -0
- package/dist/credentials-B70vmLcm.cjs.map +1 -0
- package/dist/credentials-s0wMeZBU.mjs +108 -0
- package/dist/credentials-s0wMeZBU.mjs.map +1 -0
- package/dist/{define-CHBIEc5j.mjs → define-CYs0PEfZ.mjs} +2 -3
- package/dist/define-CYs0PEfZ.mjs.map +1 -0
- package/dist/{define-Cv_QvDrg.cjs → define-zUsP72ym.cjs} +2 -3
- package/dist/define-zUsP72ym.cjs.map +1 -0
- package/dist/deploy/public.cjs +166 -14
- package/dist/deploy/public.cjs.map +1 -0
- package/dist/deploy/public.d.cts +224 -3
- package/dist/deploy/public.d.cts.map +1 -1
- package/dist/deploy/public.d.mts +224 -3
- package/dist/deploy/public.d.mts.map +1 -1
- package/dist/deploy/public.mjs +141 -10
- package/dist/deploy/public.mjs.map +1 -0
- package/dist/deploy/sniffer-envparser-worker.cjs +54 -0
- package/dist/deploy/sniffer-envparser-worker.cjs.map +1 -0
- package/dist/deploy/sniffer-envparser-worker.d.cts +1 -0
- package/dist/deploy/sniffer-envparser-worker.d.mts +1 -0
- package/dist/deploy/sniffer-envparser-worker.mjs +55 -0
- package/dist/deploy/sniffer-envparser-worker.mjs.map +1 -0
- package/dist/{deploy-DSaCYvcO.cjs → deploy-55rJkdKz.cjs} +17 -14
- package/dist/{deploy-DSaCYvcO.cjs.map → deploy-55rJkdKz.cjs.map} +1 -1
- package/dist/{deploy-Cg9fae7a.mjs → deploy-Dc2LBJaK.mjs} +13 -10
- package/dist/deploy-Dc2LBJaK.mjs.map +1 -0
- package/dist/{deploy-B7jvUORo.mjs → deploy-ZRXIPp1c.mjs} +11 -8
- package/dist/{deploy-B7jvUORo.mjs.map → deploy-ZRXIPp1c.mjs.map} +1 -1
- package/dist/{deploy-D8Qr-Xto.cjs → deploy-yUcR2OlW.cjs} +15 -12
- package/dist/deploy-yUcR2OlW.cjs.map +1 -0
- package/dist/derive-B4vDpzgP.mjs +150 -0
- package/dist/derive-B4vDpzgP.mjs.map +1 -0
- package/dist/derive-DAbo49sm.cjs +161 -0
- package/dist/derive-DAbo49sm.cjs.map +1 -0
- package/dist/discover-B6yPpvRV.d.mts +99 -0
- package/dist/discover-B6yPpvRV.d.mts.map +1 -0
- package/dist/discover-B_IkPukx.d.cts +99 -0
- package/dist/discover-B_IkPukx.d.cts.map +1 -0
- package/dist/{discover-Bc-4eA_p.cjs → discover-DHdECueV.cjs} +280 -1
- package/dist/discover-DHdECueV.cjs.map +1 -0
- package/dist/{discover-FrYvzkeC.mjs → discover-LMrqsWSU.mjs} +246 -3
- package/dist/discover-LMrqsWSU.mjs.map +1 -0
- package/dist/{dokploy-CD9PY-3D.mjs → dokploy-CepdXuMl.mjs} +3 -3
- package/dist/{dokploy-CD9PY-3D.mjs.map → dokploy-CepdXuMl.mjs.map} +1 -1
- package/dist/{dokploy-Ey2foJLv.cjs → dokploy-D1d37rvM.cjs} +3 -3
- package/dist/{dokploy-Ey2foJLv.cjs.map → dokploy-D1d37rvM.cjs.map} +1 -1
- package/dist/{encryption-ChBk3hTj.cjs → encryption-C9X98u2F.cjs} +5 -5
- package/dist/{encryption-ChBk3hTj.cjs.map → encryption-C9X98u2F.cjs.map} +1 -1
- package/dist/{encryption-CVwvGbsL.mjs → encryption-CKHjMpCr.mjs} +5 -5
- package/dist/{encryption-CVwvGbsL.mjs.map → encryption-CKHjMpCr.mjs.map} +1 -1
- package/dist/fakes-C9RiT6XG.mjs.map +1 -1
- package/dist/fakes-zW-jNAbQ.cjs.map +1 -1
- package/dist/{github-BCB3_LBX.mjs → github-D-byNI7T.mjs} +4 -4
- package/dist/{github-BCB3_LBX.mjs.map → github-D-byNI7T.mjs.map} +1 -1
- package/dist/{github-OUgPDlqg.cjs → github-Dd3tMa1u.cjs} +4 -4
- package/dist/{github-OUgPDlqg.cjs.map → github-Dd3tMa1u.cjs.map} +1 -1
- package/dist/{index-BtXDZQuF.d.cts → index-CJ2qsSpp.d.mts} +2 -2
- package/dist/{index-BtXDZQuF.d.cts.map → index-CJ2qsSpp.d.mts.map} +1 -1
- package/dist/{index-DrKzpHl-.d.mts → index-CfE9Y885.d.cts} +2 -2
- package/dist/{index-DrKzpHl-.d.mts.map → index-CfE9Y885.d.cts.map} +1 -1
- package/dist/index.cjs +111 -239
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +82 -210
- package/dist/index.mjs.map +1 -1
- package/dist/local-C7wnrcYK.cjs +586 -0
- package/dist/local-C7wnrcYK.cjs.map +1 -0
- package/dist/local-Cd8ZYQG3.mjs +473 -0
- package/dist/local-Cd8ZYQG3.mjs.map +1 -0
- package/dist/{migrate-BoHMqdCu.mjs → migrate-B4gngTLe.mjs} +6 -6
- package/dist/{migrate-BoHMqdCu.mjs.map → migrate-B4gngTLe.mjs.map} +1 -1
- package/dist/{migrate-dnaFMvOm.cjs → migrate-tx9-P9uz.cjs} +6 -6
- package/dist/{migrate-dnaFMvOm.cjs.map → migrate-tx9-P9uz.cjs.map} +1 -1
- package/dist/openapi.cjs +3 -3
- package/dist/openapi.d.cts +1 -1
- package/dist/openapi.d.mts +1 -1
- package/dist/openapi.mjs +3 -3
- package/dist/{ready-DQIy21W5.mjs → ready-bQfu9GES.mjs} +3 -3
- package/dist/{ready-DQIy21W5.mjs.map → ready-bQfu9GES.mjs.map} +1 -1
- package/dist/{ready-XlNx-Gbo.cjs → ready-brEhh68f.cjs} +3 -3
- package/dist/{ready-XlNx-Gbo.cjs.map → ready-brEhh68f.cjs.map} +1 -1
- package/dist/reconcile/public.cjs +1 -1
- package/dist/reconcile/public.d.cts +4 -77
- package/dist/reconcile/public.d.cts.map +1 -1
- package/dist/reconcile/public.d.mts +4 -77
- package/dist/reconcile/public.d.mts.map +1 -1
- package/dist/reconcile/public.mjs +1 -1
- package/dist/{resolve-wbv66HjD.cjs → resolve-BXsNQjMR.cjs} +9 -6
- package/dist/resolve-BXsNQjMR.cjs.map +1 -0
- package/dist/{resolve-CFCIkm7m.mjs → resolve-DZ2IJ0qY.mjs} +9 -6
- package/dist/resolve-DZ2IJ0qY.mjs.map +1 -0
- package/dist/{runtime-CMwtq0AL.cjs → runtime-BGNDrHzh.cjs} +2 -2
- package/dist/{runtime-CMwtq0AL.cjs.map → runtime-BGNDrHzh.cjs.map} +1 -1
- package/dist/{runtime-Dn_n-29S.d.cts → runtime-CJEYK4Gz.d.mts} +2 -2
- package/dist/{runtime-CXPlkZzs.d.mts.map → runtime-CJEYK4Gz.d.mts.map} +1 -1
- package/dist/{runtime-CXPlkZzs.d.mts → runtime-Cjq1jlVX.d.cts} +2 -2
- package/dist/{runtime-Dn_n-29S.d.cts.map → runtime-Cjq1jlVX.d.cts.map} +1 -1
- package/dist/{runtime-DbakJS8u.mjs → runtime-Cmn-FeYO.mjs} +2 -2
- package/dist/{runtime-DbakJS8u.mjs.map → runtime-Cmn-FeYO.mjs.map} +1 -1
- package/dist/sandbox/config-worker.cjs +43 -0
- package/dist/sandbox/config-worker.cjs.map +1 -0
- package/dist/sandbox/config-worker.d.cts +1 -0
- package/dist/sandbox/config-worker.d.mts +1 -0
- package/dist/sandbox/config-worker.mjs +44 -0
- package/dist/sandbox/config-worker.mjs.map +1 -0
- package/dist/sandbox/discover-worker.cjs +44 -0
- package/dist/sandbox/discover-worker.cjs.map +1 -0
- package/dist/sandbox/discover-worker.d.cts +1 -0
- package/dist/sandbox/discover-worker.d.mts +1 -0
- package/dist/sandbox/discover-worker.mjs +45 -0
- package/dist/sandbox/discover-worker.mjs.map +1 -0
- package/dist/sandbox-CL--ZDui.cjs +164 -0
- package/dist/sandbox-CL--ZDui.cjs.map +1 -0
- package/dist/sandbox-Dm247NGx.mjs +117 -0
- package/dist/sandbox-Dm247NGx.mjs.map +1 -0
- package/dist/sandbox-M8UnLhXE.d.cts +126 -0
- package/dist/sandbox-M8UnLhXE.d.cts.map +1 -0
- package/dist/sandbox-M8UnLhXE.d.mts +126 -0
- package/dist/sandbox-M8UnLhXE.d.mts.map +1 -0
- package/dist/{workspace-BFe57es7.mjs → schemas-Ckm_aBnF.cjs} +71 -982
- package/dist/schemas-Ckm_aBnF.cjs.map +1 -0
- package/dist/{workspace-B6zQO6RY.cjs → schemas-D2LCF689.mjs} +2 -1168
- package/dist/schemas-D2LCF689.mjs.map +1 -0
- package/dist/{sniffer-DHE2Nafd.mjs → sniffer-49KPbDgq.mjs} +131 -444
- package/dist/sniffer-49KPbDgq.mjs.map +1 -0
- package/dist/{sniffer-BsfPa-GA.cjs → sniffer-ByhbEW5A.cjs} +145 -512
- package/dist/sniffer-ByhbEW5A.cjs.map +1 -0
- package/dist/sst-BdALKEas.cjs +453 -0
- package/dist/sst-BdALKEas.cjs.map +1 -0
- package/dist/sst-Cper040I.mjs +430 -0
- package/dist/sst-Cper040I.mjs.map +1 -0
- package/dist/{store-BS8A7NcA.mjs → store-BaaonhkJ.mjs} +2 -2
- package/dist/{store-BS8A7NcA.mjs.map → store-BaaonhkJ.mjs.map} +1 -1
- package/dist/{store-KvNQwYaB.cjs → store-D_2ByRtW.cjs} +4 -4
- package/dist/{store-KvNQwYaB.cjs.map → store-D_2ByRtW.cjs.map} +1 -1
- package/dist/target/public.cjs +3 -3
- package/dist/target/public.d.cts +3 -3
- package/dist/target/public.d.mts +3 -3
- package/dist/target/public.mjs +3 -3
- package/dist/{terminal-6oL0vANs.cjs → terminal-Bdv--jhY.cjs} +16 -111
- package/dist/terminal-Bdv--jhY.cjs.map +1 -0
- package/dist/{terminal-ByZNjuig.mjs → terminal-D7Ntz6WE.mjs} +13 -90
- package/dist/terminal-D7Ntz6WE.mjs.map +1 -0
- package/dist/{types-DIA7Li-J.d.cts → types-B_bEQvb9.d.mts} +42 -7
- package/dist/types-B_bEQvb9.d.mts.map +1 -0
- package/dist/{types-CfLKGfC_.d.mts → types-DkrDOMxw.d.cts} +43 -6
- package/dist/types-DkrDOMxw.d.cts.map +1 -0
- package/dist/utils-D2Nk1Nv2.cjs +205 -0
- package/dist/utils-D2Nk1Nv2.cjs.map +1 -0
- package/dist/utils-D_fxUqvU.mjs +156 -0
- package/dist/utils-D_fxUqvU.mjs.map +1 -0
- package/dist/vitest.cjs +2 -2
- package/dist/vitest.mjs +2 -2
- package/dist/workerRuntime-BXfhbe13.cjs +108 -0
- package/dist/workerRuntime-BXfhbe13.cjs.map +1 -0
- package/dist/workerRuntime-CsOyBRx2.mjs +79 -0
- package/dist/workerRuntime-CsOyBRx2.mjs.map +1 -0
- package/dist/workspace/index.cjs +1 -1
- package/dist/workspace/index.d.cts +2 -2
- package/dist/workspace/index.d.mts +2 -2
- package/dist/workspace/index.mjs +1 -1
- package/dist/workspace-BwgWJK7h.cjs +1196 -0
- package/dist/workspace-BwgWJK7h.cjs.map +1 -0
- package/dist/workspace-Bwit4q9O.mjs +1024 -0
- package/dist/workspace-Bwit4q9O.mjs.map +1 -0
- package/package.json +13 -13
- package/dist/config-BYh9S0cZ.cjs +0 -534
- package/dist/config-BYh9S0cZ.cjs.map +0 -1
- package/dist/config-Bf4-bROQ.mjs +0 -457
- package/dist/config-Bf4-bROQ.mjs.map +0 -1
- package/dist/config.d.cts.map +0 -1
- package/dist/config.d.mts.map +0 -1
- package/dist/define-CHBIEc5j.mjs.map +0 -1
- package/dist/define-Cv_QvDrg.cjs.map +0 -1
- package/dist/deploy-Cg9fae7a.mjs.map +0 -1
- package/dist/deploy-D8Qr-Xto.cjs.map +0 -1
- package/dist/discover-Bc-4eA_p.cjs.map +0 -1
- package/dist/discover-FrYvzkeC.mjs.map +0 -1
- package/dist/home-DOzBaWaL.cjs +0 -33
- package/dist/home-DOzBaWaL.cjs.map +0 -1
- package/dist/home-GI7pJl1M.mjs +0 -22
- package/dist/home-GI7pJl1M.mjs.map +0 -1
- package/dist/resolve-CFCIkm7m.mjs.map +0 -1
- package/dist/resolve-wbv66HjD.cjs.map +0 -1
- package/dist/sniffer-BsfPa-GA.cjs.map +0 -1
- package/dist/sniffer-DHE2Nafd.mjs.map +0 -1
- package/dist/terminal-6oL0vANs.cjs.map +0 -1
- package/dist/terminal-ByZNjuig.mjs.map +0 -1
- package/dist/types-CfLKGfC_.d.mts.map +0 -1
- package/dist/types-DIA7Li-J.d.cts.map +0 -1
- package/dist/workspace-B6zQO6RY.cjs.map +0 -1
- package/dist/workspace-BFe57es7.mjs.map +0 -1
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
const
|
|
2
|
-
const require_discover = require("./discover-
|
|
3
|
-
const
|
|
4
|
-
const require_workspace = require("./workspace-
|
|
5
|
-
const
|
|
1
|
+
const require_local = require("./local-C7wnrcYK.cjs");
|
|
2
|
+
const require_discover = require("./discover-DHdECueV.cjs");
|
|
3
|
+
const require_sandbox = require("./sandbox-CL--ZDui.cjs");
|
|
4
|
+
const require_workspace = require("./workspace-BwgWJK7h.cjs");
|
|
5
|
+
const require_config = require("./config.cjs");
|
|
6
|
+
const require_credentials = require("./credentials-B70vmLcm.cjs");
|
|
7
|
+
const require_terminal = require("./terminal-Bdv--jhY.cjs");
|
|
6
8
|
let node_path = require("node:path");
|
|
7
9
|
//#region src/deploy/deploy.ts
|
|
8
10
|
/**
|
|
@@ -79,9 +81,9 @@ function deploy(input) {
|
|
|
79
81
|
};
|
|
80
82
|
const ctx = {
|
|
81
83
|
emit,
|
|
82
|
-
credentials: input.credentials ??
|
|
84
|
+
credentials: input.credentials ?? require_credentials.storedCredentials({ home: input.home ?? require_local.gkmHome() }),
|
|
83
85
|
dryRun: input.dryRun ?? false,
|
|
84
|
-
home: input.home ??
|
|
86
|
+
home: input.home ?? require_local.gkmHome(),
|
|
85
87
|
redactor,
|
|
86
88
|
...input.signal ? { signal: input.signal } : {},
|
|
87
89
|
...input.childOutput ? { childOutput: input.childOutput } : {},
|
|
@@ -94,12 +96,13 @@ function deploy(input) {
|
|
|
94
96
|
}), async () => {
|
|
95
97
|
try {
|
|
96
98
|
input.signal?.throwIfAborted();
|
|
97
|
-
const
|
|
99
|
+
const sandbox = input.sandbox ?? new require_local.LocalSandbox({ root: require_config.findWorkspaceRoot((0, node_path.resolve)(input.cwd)) });
|
|
100
|
+
const deployed = await require_sandbox.withSandbox(sandbox, () => require_terminal.runDeploy(() => load(input, sandbox), {
|
|
98
101
|
stage: input.stage,
|
|
99
102
|
...input.target ? { target: input.target } : {},
|
|
100
103
|
...input.tag ? { tag: input.tag } : {},
|
|
101
104
|
...input.apps ? { apps: input.apps } : {}
|
|
102
|
-
}, ctx);
|
|
105
|
+
}, ctx));
|
|
103
106
|
emit({
|
|
104
107
|
type: "deploy.finished",
|
|
105
108
|
result: deployed
|
|
@@ -122,8 +125,8 @@ function deploy(input) {
|
|
|
122
125
|
};
|
|
123
126
|
}
|
|
124
127
|
/** The workspace at `input.cwd`, refusing a stage it does not deploy. */
|
|
125
|
-
async function load(input) {
|
|
126
|
-
const { workspace } = await require_config.loadWorkspaceConfig((0, node_path.resolve)(input.cwd));
|
|
128
|
+
async function load(input, sandbox) {
|
|
129
|
+
const { workspace } = await require_config.loadWorkspaceConfig((0, node_path.resolve)(input.cwd), { sandbox });
|
|
127
130
|
require_workspace.assertDeployedStage(workspace.stages, input.stage);
|
|
128
131
|
return workspace;
|
|
129
132
|
}
|
|
@@ -135,4 +138,4 @@ Object.defineProperty(exports, "deploy", {
|
|
|
135
138
|
}
|
|
136
139
|
});
|
|
137
140
|
|
|
138
|
-
//# sourceMappingURL=deploy-
|
|
141
|
+
//# sourceMappingURL=deploy-yUcR2OlW.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deploy-yUcR2OlW.cjs","names":["Redactor","storedCredentials","gkmHome","withOutput","LocalSandbox","findWorkspaceRoot","resolve","withSandbox","runDeploy","eventError","loadWorkspaceConfig"],"sources":["../src/deploy/deploy.ts"],"sourcesContent":["/**\n * `deploy()`: a deploy as a library call.\n *\n * `gkm deploy` could only be driven from an interactive terminal: it prompted\n * for what it lacked and exited the process on failure, worked out of\n * `process.cwd()`, and reported progress by printing. Here the caller says\n * where the project is, hands over the credentials and a signal, and gets back\n * a run — events to iterate while it goes, and a structured result at the end.\n * Nothing below this asks a person anything or ends the process; `gkm deploy`\n * is a thin wrapper that does both.\n */\n\nimport { resolve } from 'node:path';\nimport { findWorkspaceRoot, loadWorkspaceConfig } from '../config';\nimport { gkmHome } from '../home';\nimport { type OutputLevel, withOutput } from '../output';\nimport { LocalSandbox } from '../sandbox/local';\nimport { type Sandbox, withSandbox } from '../sandbox/sandbox';\nimport { Redactor } from '../target/secrets';\nimport type { AnyDeployTarget } from '../target/types';\nimport { assertDeployedStage } from '../workspace/stages.js';\nimport type { NormalizedWorkspace } from '../workspace/types.js';\nimport { type CredentialProvider, storedCredentials } from './credentials';\nimport { type DeployEvent, eventError } from './events';\nimport { type DeployContext, runDeploy } from './orchestrate';\nimport type { DeployResult } from './types';\n\n/**\n * Where a run's progress lines go, besides its events. `@geekmidas/logger`'s\n * `Logger` is one.\n */\nexport interface DeployLogger {\n\tinfo(message: string): void;\n\twarn(message: string): void;\n\terror?(message: string): void;\n}\n\nexport interface DeployInput {\n\t/**\n\t * The project to deploy: the directory holding `gkm.config.ts`, or any\n\t * directory inside it. Never assumed to be `process.cwd()`.\n\t */\n\tcwd: string;\n\t/** The stage to deploy — one of the config's deployed stages. */\n\tstage: string;\n\t/**\n\t * The target to deploy through, by name. Defaults to `deploy.default`,\n\t * else `dokploy`.\n\t */\n\ttarget?: string;\n\t/**\n\t * The host's own targets, by name. Consulted before the built-ins and the\n\t * config's `deploy.targets`, so a host can deploy through an\n\t * implementation of its own — `{ dokploy: myDokploy }` included.\n\t */\n\ttargets?: Record<string, AnyDeployTarget>;\n\t/** The image tag. Defaults to `<stage>-<timestamp>`. */\n\ttag?: string;\n\t/** Deploy only these apps (in dependency order). Defaults to all. */\n\tapps?: string[];\n\t/**\n\t * Look everything up and report what would happen — as `resource.planned`\n\t * events — without taking the lock, writing state, generating secrets,\n\t * changing Dokploy or building and pushing images.\n\t */\n\tdryRun?: boolean;\n\t/**\n\t * Where credentials come from. Defaults to the environment, then the\n\t * logins `gkm login` stored. A credential no provider has stops the run\n\t * with `MissingCredential`; nothing prompts.\n\t */\n\tcredentials?: CredentialProvider;\n\t/** Receives each progress line as it is written. Defaults to none. */\n\tlogger?: DeployLogger;\n\t/**\n\t * Stops the run: in-flight Dokploy requests and docker children are\n\t * cancelled, the stage's lock is released, and `result` rejects with the\n\t * signal's reason.\n\t */\n\tsignal?: AbortSignal;\n\t/**\n\t * The CLI's home: stage keys and stored logins. Defaults to `GKM_HOME`,\n\t * else `~/.gkm`.\n\t */\n\thome?: string;\n\t/**\n\t * Where docker's own output goes: the host's terminal (`inherit`, the\n\t * default), its stderr, or nowhere.\n\t */\n\tchildOutput?: 'inherit' | 'stderr' | 'ignore';\n\t/**\n\t * Where the project's own code runs: loading `gkm.config.ts`, discovering\n\t * its constructs, sniffing each app's environment. Defaults to a\n\t * `LocalSandbox` on the project — a child process here with an\n\t * allowlisted environment, for a project the host trusts.\n\t *\n\t * A host deploying repositories it does not trust passes one that\n\t * isolates — a container per build — and the config then reaches the\n\t * deploy only as data. Credentials never enter a sandbox: they go from\n\t * `credentials` to the steps that provision, push and release.\n\t */\n\tsandbox?: Sandbox;\n}\n\n/** A deploy in progress. */\nexport interface DeployRun extends AsyncIterable<DeployEvent> {\n\t/**\n\t * What the deploy did, once it is done. Rejects with the error that\n\t * stopped it — `MissingCredential`, `StateLocked`, `ProjectNotOwned`, … —\n\t * after a `deploy.failed` event carrying the same.\n\t */\n\treadonly result: Promise<DeployResult>;\n}\n\n/**\n * Every event a run emits, kept so that each iteration — however late it\n * starts — sees the run from its first event to its last.\n */\nclass EventLog {\n\tprivate readonly events: DeployEvent[] = [];\n\tprivate closed = false;\n\tprivate waiting: (() => void)[] = [];\n\n\tpush(event: DeployEvent): void {\n\t\tthis.events.push(event);\n\t\tthis.wake();\n\t}\n\n\tclose(): void {\n\t\tthis.closed = true;\n\t\tthis.wake();\n\t}\n\n\tprivate wake(): void {\n\t\tconst waiting = this.waiting;\n\t\tthis.waiting = [];\n\t\tfor (const resume of waiting) resume();\n\t}\n\n\tasync *iterate(): AsyncGenerator<DeployEvent> {\n\t\tlet next = 0;\n\t\twhile (true) {\n\t\t\tif (next < this.events.length) {\n\t\t\t\tyield this.events[next++]!;\n\t\t\t} else if (this.closed) {\n\t\t\t\treturn;\n\t\t\t} else {\n\t\t\t\tawait new Promise<void>((resume) => this.waiting.push(resume));\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunction forward(\n\tlogger: DeployLogger | undefined,\n\tlevel: OutputLevel,\n\tmessage: string,\n): void {\n\tif (!logger) return;\n\tif (level === 'info') logger.info(message);\n\telse if (level === 'error' && logger.error) logger.error(message);\n\telse logger.warn(message);\n}\n\n/**\n * Deploy a project's stage.\n *\n * ```ts\n * import { deploy } from '@geekmidas/cli/deploy';\n *\n * const run = deploy({ cwd: '/srv/checkouts/shop', stage: 'production' });\n * for await (const event of run) {\n * if (event.type === 'app.deployed') console.log(event.app, event.url);\n * }\n * const result = await run.result;\n * ```\n *\n * The run starts at once; iterating it is optional, and an iteration started\n * late still sees every event from the first.\n */\nexport function deploy(input: DeployInput): DeployRun {\n\tconst log = new EventLog();\n\t// Every secret the run reads is masked in every line it reports — in the\n\t// events and in what the logger is handed.\n\tconst redactor = new Redactor();\n\tconst emit = (event: DeployEvent) => {\n\t\tconst masked =\n\t\t\tevent.type === 'log'\n\t\t\t\t? { ...event, message: redactor.redact(event.message) }\n\t\t\t\t: event;\n\t\tlog.push(masked);\n\t\tif (masked.type === 'log') {\n\t\t\tforward(input.logger, masked.level, masked.message);\n\t\t}\n\t};\n\n\tconst ctx: DeployContext = {\n\t\temit,\n\t\tcredentials:\n\t\t\tinput.credentials ?? storedCredentials({ home: input.home ?? gkmHome() }),\n\t\tdryRun: input.dryRun ?? false,\n\t\thome: input.home ?? gkmHome(),\n\t\tredactor,\n\t\t...(input.signal ? { signal: input.signal } : {}),\n\t\t...(input.childOutput ? { childOutput: input.childOutput } : {}),\n\t\t...(input.targets ? { targets: input.targets } : {}),\n\t};\n\n\t// Every line anything in the run writes through `output` — the deploy's\n\t// own, the Dockerfile generator's, discovery's warnings — becomes an event\n\t// of this run, and of no other.\n\tconst result = withOutput(\n\t\t(level, message) => emit({ type: 'log', level, message }),\n\t\tasync () => {\n\t\t\ttry {\n\t\t\t\tinput.signal?.throwIfAborted();\n\t\t\t\tconst sandbox =\n\t\t\t\t\tinput.sandbox ??\n\t\t\t\t\tnew LocalSandbox({ root: findWorkspaceRoot(resolve(input.cwd)) });\n\t\t\t\t// Every step of the run that executes the project's code — the\n\t\t\t\t// engine's own discoveries and sniffs included — runs in it.\n\t\t\t\tconst deployed = await withSandbox(sandbox, () =>\n\t\t\t\t\trunDeploy(\n\t\t\t\t\t\t() => load(input, sandbox),\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tstage: input.stage,\n\t\t\t\t\t\t\t...(input.target ? { target: input.target } : {}),\n\t\t\t\t\t\t\t...(input.tag ? { tag: input.tag } : {}),\n\t\t\t\t\t\t\t...(input.apps ? { apps: input.apps } : {}),\n\t\t\t\t\t\t},\n\t\t\t\t\t\tctx,\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t\temit({ type: 'deploy.finished', result: deployed });\n\t\t\t\treturn deployed;\n\t\t\t} catch (error) {\n\t\t\t\temit({ type: 'deploy.failed', error: eventError(error) });\n\t\t\t\tthrow error;\n\t\t\t} finally {\n\t\t\t\tlog.close();\n\t\t\t}\n\t\t},\n\t);\n\n\t// A caller that only iterates still learns of the failure from the\n\t// `deploy.failed` event; the rejection must not also crash its process as\n\t// unhandled. Awaiting `result` still rejects.\n\tresult.catch(() => {});\n\n\treturn {\n\t\tresult,\n\t\t[Symbol.asyncIterator]: () => log.iterate(),\n\t};\n}\n\n/** The workspace at `input.cwd`, refusing a stage it does not deploy. */\nasync function load(\n\tinput: DeployInput,\n\tsandbox: Sandbox,\n): Promise<NormalizedWorkspace> {\n\tconst { workspace } = await loadWorkspaceConfig(resolve(input.cwd), {\n\t\tsandbox,\n\t});\n\n\t// Before anything is provisioned: a typo'd stage would otherwise create a\n\t// whole second environment under the wrong name.\n\tassertDeployedStage(workspace.stages, input.stage);\n\treturn workspace;\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { kebabCase } from "@geekmidas/manifest";
|
|
2
|
+
//#region src/workspace/derive.ts
|
|
3
|
+
/**
|
|
4
|
+
* The apps a manifest implies.
|
|
5
|
+
*
|
|
6
|
+
* `gkm.config.ts` used to carry an `apps` block naming every app: its type, its
|
|
7
|
+
* path, its port, its framework, which other apps it depended on. Every one of
|
|
8
|
+
* those facts was already declared. A `StaticSite('Web', { path: 'apps/web' })`
|
|
9
|
+
* and an `apps.web = { type: 'web', path: 'apps/web', framework: 'vite',
|
|
10
|
+
* dependencies: ['api'] }` are the same statement written twice, and only one of
|
|
11
|
+
* them was checked against anything — so the copy in config was free to drift,
|
|
12
|
+
* and a surface config had no entry for simply never deployed.
|
|
13
|
+
*
|
|
14
|
+
* So the list comes from the graph. A `site` is an app, and so is every
|
|
15
|
+
* `rest-api` — one surface, one container, at the `path` it declared.
|
|
16
|
+
*
|
|
17
|
+
* What config still supplies is what no graph can answer: the backends a cache
|
|
18
|
+
* and a mailer resolve to, the deploy endpoint, the stage's domain.
|
|
19
|
+
*/
|
|
20
|
+
/** Which frontend framework builds each site variant. */
|
|
21
|
+
const FRAMEWORKS = {
|
|
22
|
+
static: "vite",
|
|
23
|
+
next: "nextjs",
|
|
24
|
+
tanstack: "tanstack-start"
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* The app key a construct id becomes.
|
|
28
|
+
*
|
|
29
|
+
* The same kebab form every physical name is built from, so `Api` is `api` in
|
|
30
|
+
* the config, `production-kitchen-sink-api` on Dokploy, and `API_URL` in an
|
|
31
|
+
* environment — one id, three renderings, no second list.
|
|
32
|
+
*/
|
|
33
|
+
function appKey(id) {
|
|
34
|
+
return kebabCase(id);
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* The app serving a surface: its own, always.
|
|
38
|
+
*
|
|
39
|
+
* Every surface gets a container. There is no arrangement in which one runs
|
|
40
|
+
* inside another — two surfaces in a process share a filesystem, an
|
|
41
|
+
* environment, and every credential either was granted, so an auth server
|
|
42
|
+
* beside an API is one bug in the API away from being read by it.
|
|
43
|
+
*/
|
|
44
|
+
function hostOf(manifest, id) {
|
|
45
|
+
const declaration = manifest[id];
|
|
46
|
+
if (!declaration || declaration.kind !== "rest-api") return void 0;
|
|
47
|
+
return id;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Local ports, assigned so that adding a site does not renumber the others.
|
|
51
|
+
*
|
|
52
|
+
* Backends first, then the site holding the base domain, then the rest
|
|
53
|
+
* alphabetically. The ordering is arbitrary but it is *fixed*, which is the
|
|
54
|
+
* property that matters: a port that moves when an unrelated app is added is a
|
|
55
|
+
* port nobody can put in a bookmark. A construct that names its own port keeps
|
|
56
|
+
* it, and is skipped here.
|
|
57
|
+
*/
|
|
58
|
+
function assignPorts(apps) {
|
|
59
|
+
const rank = (name, app) => [
|
|
60
|
+
app.type === "backend" ? 0 : app.type === "web" ? 1 : 2,
|
|
61
|
+
app.root ? 0 : 1,
|
|
62
|
+
name
|
|
63
|
+
];
|
|
64
|
+
const ordered = Object.entries(apps).sort(([aName, a], [bName, b]) => {
|
|
65
|
+
const [at, ar, an] = rank(aName, a);
|
|
66
|
+
const [bt, br, bn] = rank(bName, b);
|
|
67
|
+
return at - bt || ar - br || an.localeCompare(bn);
|
|
68
|
+
});
|
|
69
|
+
const taken = new Set(ordered.map(([, app]) => app.port).filter((p) => !!p));
|
|
70
|
+
let next = 3e3;
|
|
71
|
+
for (const [, app] of ordered) {
|
|
72
|
+
if (app.port) continue;
|
|
73
|
+
while (taken.has(next)) next += 1;
|
|
74
|
+
app.port = next;
|
|
75
|
+
taken.add(next);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Whichever site holds the base domain.
|
|
80
|
+
*
|
|
81
|
+
* The convention first — a site named `web` — because it is one people already
|
|
82
|
+
* rely on. Then an explicit `root: true`. A project with one site needs neither.
|
|
83
|
+
*/
|
|
84
|
+
function markRoot(apps) {
|
|
85
|
+
const sites = Object.entries(apps).filter(([, a]) => a.type === "web");
|
|
86
|
+
if (sites.length === 0) return;
|
|
87
|
+
if (sites.some(([, a]) => a.root)) return;
|
|
88
|
+
const chosen = sites.find(([name]) => name === "web") ?? (sites.length === 1 ? sites[0] : void 0);
|
|
89
|
+
if (chosen) chosen[1].root = true;
|
|
90
|
+
}
|
|
91
|
+
function derivedApps(manifest, workspace) {
|
|
92
|
+
const apps = {};
|
|
93
|
+
const defaultTarget = workspace.deploy?.default ?? "dokploy";
|
|
94
|
+
for (const [id, declaration] of Object.entries(manifest)) {
|
|
95
|
+
if (declaration.kind !== "site" && declaration.kind !== "mobile-app" && declaration.kind !== "rest-api") continue;
|
|
96
|
+
const spec = declaration.kind === "site" || declaration.kind === "mobile-app" ? declaration.app : {
|
|
97
|
+
path: declaration.path,
|
|
98
|
+
...declaration.telescope ? { telescope: true } : {}
|
|
99
|
+
};
|
|
100
|
+
const name = appKey(id);
|
|
101
|
+
const configured = workspace.apps[name];
|
|
102
|
+
apps[name] = {
|
|
103
|
+
...configured,
|
|
104
|
+
type: declaration.kind === "site" ? "web" : declaration.kind === "mobile-app" ? "mobile" : "backend",
|
|
105
|
+
path: spec.path,
|
|
106
|
+
port: spec.port ?? configured?.port ?? 0,
|
|
107
|
+
...(declaration.kind === "rest-api" || declaration.kind === "site") && declaration.subdomain ? { subdomain: declaration.subdomain } : {},
|
|
108
|
+
dependencies: [],
|
|
109
|
+
resolvedDeployTarget: configured?.resolvedDeployTarget ?? defaultTarget,
|
|
110
|
+
...declaration.kind === "site" ? {
|
|
111
|
+
framework: configured?.framework ?? FRAMEWORKS[declaration.variant],
|
|
112
|
+
...declaration.root ? { root: true } : {},
|
|
113
|
+
...spec.config ? { config: spec.config } : {}
|
|
114
|
+
} : {},
|
|
115
|
+
...declaration.kind === "mobile-app" ? {
|
|
116
|
+
framework: configured?.framework ?? declaration.variant,
|
|
117
|
+
...spec.config ? { config: spec.config } : {}
|
|
118
|
+
} : {},
|
|
119
|
+
...spec.telescope !== void 0 ? { telescope: spec.telescope } : {},
|
|
120
|
+
...spec.openapi !== void 0 ? { openapi: spec.openapi } : {},
|
|
121
|
+
...spec.runtime !== void 0 ? { runtime: spec.runtime } : {},
|
|
122
|
+
...spec.env !== void 0 ? { env: spec.env } : {},
|
|
123
|
+
...spec.entry !== void 0 ? { entry: spec.entry } : {},
|
|
124
|
+
...configured?.domain ? { domain: configured.domain } : {}
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
for (const [id, declaration] of Object.entries(manifest)) {
|
|
128
|
+
if (declaration.kind !== "site" && declaration.kind !== "mobile-app" && declaration.kind !== "rest-api") continue;
|
|
129
|
+
const app = apps[appKey(id)];
|
|
130
|
+
if (!app) continue;
|
|
131
|
+
const edges = declaration.kind === "rest-api" ? declaration.calls ?? [] : declaration.dependencies ?? [];
|
|
132
|
+
const names = /* @__PURE__ */ new Set();
|
|
133
|
+
for (const edge of edges) {
|
|
134
|
+
if (edge.kind !== "rest-api") continue;
|
|
135
|
+
const host = hostOf(manifest, edge.target);
|
|
136
|
+
if (!host) continue;
|
|
137
|
+
const key = appKey(host);
|
|
138
|
+
if (key !== appKey(id) && apps[key]) names.add(key);
|
|
139
|
+
}
|
|
140
|
+
app.dependencies = [...names].sort();
|
|
141
|
+
}
|
|
142
|
+
markRoot(apps);
|
|
143
|
+
assignPorts(apps);
|
|
144
|
+
for (const [name, app] of Object.entries(workspace.apps)) if (!apps[name]) apps[name] = app;
|
|
145
|
+
return apps;
|
|
146
|
+
}
|
|
147
|
+
//#endregion
|
|
148
|
+
export { derivedApps as n, appKey as t };
|
|
149
|
+
|
|
150
|
+
//# sourceMappingURL=derive-B4vDpzgP.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"derive-B4vDpzgP.mjs","names":[],"sources":["../src/workspace/derive.ts"],"sourcesContent":["/**\n * The apps a manifest implies.\n *\n * `gkm.config.ts` used to carry an `apps` block naming every app: its type, its\n * path, its port, its framework, which other apps it depended on. Every one of\n * those facts was already declared. A `StaticSite('Web', { path: 'apps/web' })`\n * and an `apps.web = { type: 'web', path: 'apps/web', framework: 'vite',\n * dependencies: ['api'] }` are the same statement written twice, and only one of\n * them was checked against anything — so the copy in config was free to drift,\n * and a surface config had no entry for simply never deployed.\n *\n * So the list comes from the graph. A `site` is an app, and so is every\n * `rest-api` — one surface, one container, at the `path` it declared.\n *\n * What config still supplies is what no graph can answer: the backends a cache\n * and a mailer resolve to, the deploy endpoint, the stage's domain.\n */\n\nimport {\n\ttype AppSpec,\n\ttype ConstructManifest,\n\tkebabCase,\n} from '@geekmidas/manifest';\nimport type {\n\tAppDomainConfig,\n\tDeployTargetName,\n\tFramework,\n\tNormalizedAppConfig,\n\tNormalizedWorkspace,\n} from './types.js';\n\n/** Which frontend framework builds each site variant. */\nconst FRAMEWORKS: Record<string, Framework> = {\n\tstatic: 'vite',\n\tnext: 'nextjs',\n\ttanstack: 'tanstack-start',\n};\n\n/**\n * The app key a construct id becomes.\n *\n * The same kebab form every physical name is built from, so `Api` is `api` in\n * the config, `production-kitchen-sink-api` on Dokploy, and `API_URL` in an\n * environment — one id, three renderings, no second list.\n */\nexport function appKey(id: string): string {\n\treturn kebabCase(id);\n}\n\n/**\n * The app serving a surface: its own, always.\n *\n * Every surface gets a container. There is no arrangement in which one runs\n * inside another — two surfaces in a process share a filesystem, an\n * environment, and every credential either was granted, so an auth server\n * beside an API is one bug in the API away from being read by it.\n */\nexport function hostOf(\n\tmanifest: ConstructManifest,\n\tid: string,\n): string | undefined {\n\tconst declaration = manifest[id];\n\tif (!declaration || declaration.kind !== 'rest-api') return undefined;\n\n\treturn id;\n}\n\n/**\n * Local ports, assigned so that adding a site does not renumber the others.\n *\n * Backends first, then the site holding the base domain, then the rest\n * alphabetically. The ordering is arbitrary but it is *fixed*, which is the\n * property that matters: a port that moves when an unrelated app is added is a\n * port nobody can put in a bookmark. A construct that names its own port keeps\n * it, and is skipped here.\n */\nfunction assignPorts(apps: Record<string, NormalizedAppConfig>): void {\n\tconst rank = (\n\t\tname: string,\n\t\tapp: NormalizedAppConfig,\n\t): [number, number, string] => [\n\t\tapp.type === 'backend' ? 0 : app.type === 'web' ? 1 : 2,\n\t\tapp.root ? 0 : 1,\n\t\tname,\n\t];\n\n\tconst ordered = Object.entries(apps).sort(([aName, a], [bName, b]) => {\n\t\tconst [at, ar, an] = rank(aName, a);\n\t\tconst [bt, br, bn] = rank(bName, b);\n\t\treturn at - bt || ar - br || an.localeCompare(bn);\n\t});\n\n\tconst taken = new Set(\n\t\tordered.map(([, app]) => app.port).filter((p): p is number => !!p),\n\t);\n\n\tlet next = 3000;\n\tfor (const [, app] of ordered) {\n\t\tif (app.port) continue;\n\t\twhile (taken.has(next)) next += 1;\n\t\tapp.port = next;\n\t\ttaken.add(next);\n\t}\n}\n\n/**\n * Whichever site holds the base domain.\n *\n * The convention first — a site named `web` — because it is one people already\n * rely on. Then an explicit `root: true`. A project with one site needs neither.\n */\nfunction markRoot(apps: Record<string, NormalizedAppConfig>): void {\n\tconst sites = Object.entries(apps).filter(([, a]) => a.type === 'web');\n\tif (sites.length === 0) return;\n\tif (sites.some(([, a]) => a.root)) return;\n\n\tconst chosen =\n\t\tsites.find(([name]) => name === 'web') ??\n\t\t(sites.length === 1 ? sites[0] : undefined);\n\tif (chosen) chosen[1].root = true;\n}\n\nexport function derivedApps(\n\tmanifest: ConstructManifest,\n\tworkspace: NormalizedWorkspace,\n): Record<string, NormalizedAppConfig> {\n\tconst apps: Record<string, NormalizedAppConfig> = {};\n\tconst defaultTarget: DeployTargetName =\n\t\tworkspace.deploy?.default ?? 'dokploy';\n\n\tfor (const [id, declaration] of Object.entries(manifest)) {\n\t\t// Three kinds are apps: a site, a mobile app and an HTTP surface. A worker\n\t\t// is not one — it names the process that runs a cron or a subscriber, and\n\t\t// that process is the app's server, which already exists. Everything else\n\t\t// is a resource one of them uses.\n\t\tif (\n\t\t\tdeclaration.kind !== 'site' &&\n\t\t\tdeclaration.kind !== 'mobile-app' &&\n\t\t\tdeclaration.kind !== 'rest-api'\n\t\t)\n\t\t\tcontinue;\n\n\t\t// No opt-in to be had. Each says where it lives.\n\t\tconst spec: AppSpec =\n\t\t\tdeclaration.kind === 'site' || declaration.kind === 'mobile-app'\n\t\t\t\t? declaration.app\n\t\t\t\t: {\n\t\t\t\t\t\tpath: declaration.path,\n\t\t\t\t\t\t...(declaration.telescope ? { telescope: true } : {}),\n\t\t\t\t\t};\n\n\t\tconst name = appKey(id);\n\t\t// A config entry of the same name still wins, so a workspace can override\n\t\t// one field without restating the app. Nothing in this repo needs to.\n\t\tconst configured = workspace.apps[name];\n\n\t\tapps[name] = {\n\t\t\t...configured,\n\t\t\ttype:\n\t\t\t\tdeclaration.kind === 'site'\n\t\t\t\t\t? 'web'\n\t\t\t\t\t: declaration.kind === 'mobile-app'\n\t\t\t\t\t\t? 'mobile'\n\t\t\t\t\t\t: 'backend',\n\t\t\tpath: spec.path,\n\t\t\tport: spec.port ?? configured?.port ?? 0,\n\t\t\t// The label it answers on, under a stage's domain and locally alike.\n\t\t\t...((declaration.kind === 'rest-api' || declaration.kind === 'site') &&\n\t\t\tdeclaration.subdomain\n\t\t\t\t? { subdomain: declaration.subdomain }\n\t\t\t\t: {}),\n\t\t\tdependencies: [],\n\t\t\tresolvedDeployTarget: configured?.resolvedDeployTarget ?? defaultTarget,\n\t\t\t...(declaration.kind === 'site'\n\t\t\t\t? {\n\t\t\t\t\t\tframework: configured?.framework ?? FRAMEWORKS[declaration.variant],\n\t\t\t\t\t\t...(declaration.root ? { root: true } : {}),\n\t\t\t\t\t\t...(spec.config ? { config: spec.config } : {}),\n\t\t\t\t\t}\n\t\t\t\t: {}),\n\t\t\t...(declaration.kind === 'mobile-app'\n\t\t\t\t? {\n\t\t\t\t\t\tframework: configured?.framework ?? declaration.variant,\n\t\t\t\t\t\t...(spec.config ? { config: spec.config } : {}),\n\t\t\t\t\t}\n\t\t\t\t: {}),\n\t\t\t// One glob fans out to the six the build reads, because each generator\n\t\t\t// already inspects every export and keeps what it recognises. A\n\t\t\t// per-kind field still wins where one was given.\n\t\t\t...(spec.telescope !== undefined ? { telescope: spec.telescope } : {}),\n\t\t\t...(spec.openapi !== undefined ? { openapi: spec.openapi } : {}),\n\t\t\t...(spec.runtime !== undefined ? { runtime: spec.runtime } : {}),\n\t\t\t...(spec.env !== undefined ? { env: spec.env } : {}),\n\t\t\t...(spec.entry !== undefined ? { entry: spec.entry } : {}),\n\t\t\t...(configured?.domain\n\t\t\t\t? { domain: configured.domain as AppDomainConfig }\n\t\t\t\t: {}),\n\t\t} as NormalizedAppConfig;\n\t}\n\n\t// Build order, from the edges rather than from a hand-kept list. A site that\n\t// depends on a surface depends on the app that serves it — which for a\n\t// mounted auth server is its host, not a container that does not exist.\n\tfor (const [id, declaration] of Object.entries(manifest)) {\n\t\tif (\n\t\t\tdeclaration.kind !== 'site' &&\n\t\t\tdeclaration.kind !== 'mobile-app' &&\n\t\t\tdeclaration.kind !== 'rest-api'\n\t\t)\n\t\t\tcontinue;\n\n\t\tconst app = apps[appKey(id)];\n\t\tif (!app) continue;\n\n\t\t// A site names its edges `dependencies`; a surface names them `calls`.\n\t\tconst edges =\n\t\t\tdeclaration.kind === 'rest-api'\n\t\t\t\t? (declaration.calls ?? [])\n\t\t\t\t: (declaration.dependencies ?? []);\n\n\t\tconst names = new Set<string>();\n\t\tfor (const edge of edges) {\n\t\t\tif (edge.kind !== 'rest-api') continue;\n\t\t\tconst host = hostOf(manifest, edge.target);\n\t\t\tif (!host) continue;\n\t\t\tconst key = appKey(host);\n\t\t\tif (key !== appKey(id) && apps[key]) names.add(key);\n\t\t}\n\n\t\tapp.dependencies = [...names].sort();\n\t}\n\n\tmarkRoot(apps);\n\tassignPorts(apps);\n\n\t// Apps config declared that the graph knows nothing about — a `type: 'mobile'`\n\t// entry, or a hand-run process. Kept rather than dropped: config is still the\n\t// escape hatch for what nothing declares.\n\tfor (const [name, app] of Object.entries(workspace.apps)) {\n\t\tif (!apps[name]) apps[name] = app;\n\t}\n\n\treturn apps;\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
let _geekmidas_manifest = require("@geekmidas/manifest");
|
|
2
|
+
//#region src/workspace/derive.ts
|
|
3
|
+
/**
|
|
4
|
+
* The apps a manifest implies.
|
|
5
|
+
*
|
|
6
|
+
* `gkm.config.ts` used to carry an `apps` block naming every app: its type, its
|
|
7
|
+
* path, its port, its framework, which other apps it depended on. Every one of
|
|
8
|
+
* those facts was already declared. A `StaticSite('Web', { path: 'apps/web' })`
|
|
9
|
+
* and an `apps.web = { type: 'web', path: 'apps/web', framework: 'vite',
|
|
10
|
+
* dependencies: ['api'] }` are the same statement written twice, and only one of
|
|
11
|
+
* them was checked against anything — so the copy in config was free to drift,
|
|
12
|
+
* and a surface config had no entry for simply never deployed.
|
|
13
|
+
*
|
|
14
|
+
* So the list comes from the graph. A `site` is an app, and so is every
|
|
15
|
+
* `rest-api` — one surface, one container, at the `path` it declared.
|
|
16
|
+
*
|
|
17
|
+
* What config still supplies is what no graph can answer: the backends a cache
|
|
18
|
+
* and a mailer resolve to, the deploy endpoint, the stage's domain.
|
|
19
|
+
*/
|
|
20
|
+
/** Which frontend framework builds each site variant. */
|
|
21
|
+
const FRAMEWORKS = {
|
|
22
|
+
static: "vite",
|
|
23
|
+
next: "nextjs",
|
|
24
|
+
tanstack: "tanstack-start"
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* The app key a construct id becomes.
|
|
28
|
+
*
|
|
29
|
+
* The same kebab form every physical name is built from, so `Api` is `api` in
|
|
30
|
+
* the config, `production-kitchen-sink-api` on Dokploy, and `API_URL` in an
|
|
31
|
+
* environment — one id, three renderings, no second list.
|
|
32
|
+
*/
|
|
33
|
+
function appKey(id) {
|
|
34
|
+
return (0, _geekmidas_manifest.kebabCase)(id);
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* The app serving a surface: its own, always.
|
|
38
|
+
*
|
|
39
|
+
* Every surface gets a container. There is no arrangement in which one runs
|
|
40
|
+
* inside another — two surfaces in a process share a filesystem, an
|
|
41
|
+
* environment, and every credential either was granted, so an auth server
|
|
42
|
+
* beside an API is one bug in the API away from being read by it.
|
|
43
|
+
*/
|
|
44
|
+
function hostOf(manifest, id) {
|
|
45
|
+
const declaration = manifest[id];
|
|
46
|
+
if (!declaration || declaration.kind !== "rest-api") return void 0;
|
|
47
|
+
return id;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Local ports, assigned so that adding a site does not renumber the others.
|
|
51
|
+
*
|
|
52
|
+
* Backends first, then the site holding the base domain, then the rest
|
|
53
|
+
* alphabetically. The ordering is arbitrary but it is *fixed*, which is the
|
|
54
|
+
* property that matters: a port that moves when an unrelated app is added is a
|
|
55
|
+
* port nobody can put in a bookmark. A construct that names its own port keeps
|
|
56
|
+
* it, and is skipped here.
|
|
57
|
+
*/
|
|
58
|
+
function assignPorts(apps) {
|
|
59
|
+
const rank = (name, app) => [
|
|
60
|
+
app.type === "backend" ? 0 : app.type === "web" ? 1 : 2,
|
|
61
|
+
app.root ? 0 : 1,
|
|
62
|
+
name
|
|
63
|
+
];
|
|
64
|
+
const ordered = Object.entries(apps).sort(([aName, a], [bName, b]) => {
|
|
65
|
+
const [at, ar, an] = rank(aName, a);
|
|
66
|
+
const [bt, br, bn] = rank(bName, b);
|
|
67
|
+
return at - bt || ar - br || an.localeCompare(bn);
|
|
68
|
+
});
|
|
69
|
+
const taken = new Set(ordered.map(([, app]) => app.port).filter((p) => !!p));
|
|
70
|
+
let next = 3e3;
|
|
71
|
+
for (const [, app] of ordered) {
|
|
72
|
+
if (app.port) continue;
|
|
73
|
+
while (taken.has(next)) next += 1;
|
|
74
|
+
app.port = next;
|
|
75
|
+
taken.add(next);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Whichever site holds the base domain.
|
|
80
|
+
*
|
|
81
|
+
* The convention first — a site named `web` — because it is one people already
|
|
82
|
+
* rely on. Then an explicit `root: true`. A project with one site needs neither.
|
|
83
|
+
*/
|
|
84
|
+
function markRoot(apps) {
|
|
85
|
+
const sites = Object.entries(apps).filter(([, a]) => a.type === "web");
|
|
86
|
+
if (sites.length === 0) return;
|
|
87
|
+
if (sites.some(([, a]) => a.root)) return;
|
|
88
|
+
const chosen = sites.find(([name]) => name === "web") ?? (sites.length === 1 ? sites[0] : void 0);
|
|
89
|
+
if (chosen) chosen[1].root = true;
|
|
90
|
+
}
|
|
91
|
+
function derivedApps(manifest, workspace) {
|
|
92
|
+
const apps = {};
|
|
93
|
+
const defaultTarget = workspace.deploy?.default ?? "dokploy";
|
|
94
|
+
for (const [id, declaration] of Object.entries(manifest)) {
|
|
95
|
+
if (declaration.kind !== "site" && declaration.kind !== "mobile-app" && declaration.kind !== "rest-api") continue;
|
|
96
|
+
const spec = declaration.kind === "site" || declaration.kind === "mobile-app" ? declaration.app : {
|
|
97
|
+
path: declaration.path,
|
|
98
|
+
...declaration.telescope ? { telescope: true } : {}
|
|
99
|
+
};
|
|
100
|
+
const name = appKey(id);
|
|
101
|
+
const configured = workspace.apps[name];
|
|
102
|
+
apps[name] = {
|
|
103
|
+
...configured,
|
|
104
|
+
type: declaration.kind === "site" ? "web" : declaration.kind === "mobile-app" ? "mobile" : "backend",
|
|
105
|
+
path: spec.path,
|
|
106
|
+
port: spec.port ?? configured?.port ?? 0,
|
|
107
|
+
...(declaration.kind === "rest-api" || declaration.kind === "site") && declaration.subdomain ? { subdomain: declaration.subdomain } : {},
|
|
108
|
+
dependencies: [],
|
|
109
|
+
resolvedDeployTarget: configured?.resolvedDeployTarget ?? defaultTarget,
|
|
110
|
+
...declaration.kind === "site" ? {
|
|
111
|
+
framework: configured?.framework ?? FRAMEWORKS[declaration.variant],
|
|
112
|
+
...declaration.root ? { root: true } : {},
|
|
113
|
+
...spec.config ? { config: spec.config } : {}
|
|
114
|
+
} : {},
|
|
115
|
+
...declaration.kind === "mobile-app" ? {
|
|
116
|
+
framework: configured?.framework ?? declaration.variant,
|
|
117
|
+
...spec.config ? { config: spec.config } : {}
|
|
118
|
+
} : {},
|
|
119
|
+
...spec.telescope !== void 0 ? { telescope: spec.telescope } : {},
|
|
120
|
+
...spec.openapi !== void 0 ? { openapi: spec.openapi } : {},
|
|
121
|
+
...spec.runtime !== void 0 ? { runtime: spec.runtime } : {},
|
|
122
|
+
...spec.env !== void 0 ? { env: spec.env } : {},
|
|
123
|
+
...spec.entry !== void 0 ? { entry: spec.entry } : {},
|
|
124
|
+
...configured?.domain ? { domain: configured.domain } : {}
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
for (const [id, declaration] of Object.entries(manifest)) {
|
|
128
|
+
if (declaration.kind !== "site" && declaration.kind !== "mobile-app" && declaration.kind !== "rest-api") continue;
|
|
129
|
+
const app = apps[appKey(id)];
|
|
130
|
+
if (!app) continue;
|
|
131
|
+
const edges = declaration.kind === "rest-api" ? declaration.calls ?? [] : declaration.dependencies ?? [];
|
|
132
|
+
const names = /* @__PURE__ */ new Set();
|
|
133
|
+
for (const edge of edges) {
|
|
134
|
+
if (edge.kind !== "rest-api") continue;
|
|
135
|
+
const host = hostOf(manifest, edge.target);
|
|
136
|
+
if (!host) continue;
|
|
137
|
+
const key = appKey(host);
|
|
138
|
+
if (key !== appKey(id) && apps[key]) names.add(key);
|
|
139
|
+
}
|
|
140
|
+
app.dependencies = [...names].sort();
|
|
141
|
+
}
|
|
142
|
+
markRoot(apps);
|
|
143
|
+
assignPorts(apps);
|
|
144
|
+
for (const [name, app] of Object.entries(workspace.apps)) if (!apps[name]) apps[name] = app;
|
|
145
|
+
return apps;
|
|
146
|
+
}
|
|
147
|
+
//#endregion
|
|
148
|
+
Object.defineProperty(exports, "appKey", {
|
|
149
|
+
enumerable: true,
|
|
150
|
+
get: function() {
|
|
151
|
+
return appKey;
|
|
152
|
+
}
|
|
153
|
+
});
|
|
154
|
+
Object.defineProperty(exports, "derivedApps", {
|
|
155
|
+
enumerable: true,
|
|
156
|
+
get: function() {
|
|
157
|
+
return derivedApps;
|
|
158
|
+
}
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
//# sourceMappingURL=derive-DAbo49sm.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"derive-DAbo49sm.cjs","names":["kebabCase"],"sources":["../src/workspace/derive.ts"],"sourcesContent":["/**\n * The apps a manifest implies.\n *\n * `gkm.config.ts` used to carry an `apps` block naming every app: its type, its\n * path, its port, its framework, which other apps it depended on. Every one of\n * those facts was already declared. A `StaticSite('Web', { path: 'apps/web' })`\n * and an `apps.web = { type: 'web', path: 'apps/web', framework: 'vite',\n * dependencies: ['api'] }` are the same statement written twice, and only one of\n * them was checked against anything — so the copy in config was free to drift,\n * and a surface config had no entry for simply never deployed.\n *\n * So the list comes from the graph. A `site` is an app, and so is every\n * `rest-api` — one surface, one container, at the `path` it declared.\n *\n * What config still supplies is what no graph can answer: the backends a cache\n * and a mailer resolve to, the deploy endpoint, the stage's domain.\n */\n\nimport {\n\ttype AppSpec,\n\ttype ConstructManifest,\n\tkebabCase,\n} from '@geekmidas/manifest';\nimport type {\n\tAppDomainConfig,\n\tDeployTargetName,\n\tFramework,\n\tNormalizedAppConfig,\n\tNormalizedWorkspace,\n} from './types.js';\n\n/** Which frontend framework builds each site variant. */\nconst FRAMEWORKS: Record<string, Framework> = {\n\tstatic: 'vite',\n\tnext: 'nextjs',\n\ttanstack: 'tanstack-start',\n};\n\n/**\n * The app key a construct id becomes.\n *\n * The same kebab form every physical name is built from, so `Api` is `api` in\n * the config, `production-kitchen-sink-api` on Dokploy, and `API_URL` in an\n * environment — one id, three renderings, no second list.\n */\nexport function appKey(id: string): string {\n\treturn kebabCase(id);\n}\n\n/**\n * The app serving a surface: its own, always.\n *\n * Every surface gets a container. There is no arrangement in which one runs\n * inside another — two surfaces in a process share a filesystem, an\n * environment, and every credential either was granted, so an auth server\n * beside an API is one bug in the API away from being read by it.\n */\nexport function hostOf(\n\tmanifest: ConstructManifest,\n\tid: string,\n): string | undefined {\n\tconst declaration = manifest[id];\n\tif (!declaration || declaration.kind !== 'rest-api') return undefined;\n\n\treturn id;\n}\n\n/**\n * Local ports, assigned so that adding a site does not renumber the others.\n *\n * Backends first, then the site holding the base domain, then the rest\n * alphabetically. The ordering is arbitrary but it is *fixed*, which is the\n * property that matters: a port that moves when an unrelated app is added is a\n * port nobody can put in a bookmark. A construct that names its own port keeps\n * it, and is skipped here.\n */\nfunction assignPorts(apps: Record<string, NormalizedAppConfig>): void {\n\tconst rank = (\n\t\tname: string,\n\t\tapp: NormalizedAppConfig,\n\t): [number, number, string] => [\n\t\tapp.type === 'backend' ? 0 : app.type === 'web' ? 1 : 2,\n\t\tapp.root ? 0 : 1,\n\t\tname,\n\t];\n\n\tconst ordered = Object.entries(apps).sort(([aName, a], [bName, b]) => {\n\t\tconst [at, ar, an] = rank(aName, a);\n\t\tconst [bt, br, bn] = rank(bName, b);\n\t\treturn at - bt || ar - br || an.localeCompare(bn);\n\t});\n\n\tconst taken = new Set(\n\t\tordered.map(([, app]) => app.port).filter((p): p is number => !!p),\n\t);\n\n\tlet next = 3000;\n\tfor (const [, app] of ordered) {\n\t\tif (app.port) continue;\n\t\twhile (taken.has(next)) next += 1;\n\t\tapp.port = next;\n\t\ttaken.add(next);\n\t}\n}\n\n/**\n * Whichever site holds the base domain.\n *\n * The convention first — a site named `web` — because it is one people already\n * rely on. Then an explicit `root: true`. A project with one site needs neither.\n */\nfunction markRoot(apps: Record<string, NormalizedAppConfig>): void {\n\tconst sites = Object.entries(apps).filter(([, a]) => a.type === 'web');\n\tif (sites.length === 0) return;\n\tif (sites.some(([, a]) => a.root)) return;\n\n\tconst chosen =\n\t\tsites.find(([name]) => name === 'web') ??\n\t\t(sites.length === 1 ? sites[0] : undefined);\n\tif (chosen) chosen[1].root = true;\n}\n\nexport function derivedApps(\n\tmanifest: ConstructManifest,\n\tworkspace: NormalizedWorkspace,\n): Record<string, NormalizedAppConfig> {\n\tconst apps: Record<string, NormalizedAppConfig> = {};\n\tconst defaultTarget: DeployTargetName =\n\t\tworkspace.deploy?.default ?? 'dokploy';\n\n\tfor (const [id, declaration] of Object.entries(manifest)) {\n\t\t// Three kinds are apps: a site, a mobile app and an HTTP surface. A worker\n\t\t// is not one — it names the process that runs a cron or a subscriber, and\n\t\t// that process is the app's server, which already exists. Everything else\n\t\t// is a resource one of them uses.\n\t\tif (\n\t\t\tdeclaration.kind !== 'site' &&\n\t\t\tdeclaration.kind !== 'mobile-app' &&\n\t\t\tdeclaration.kind !== 'rest-api'\n\t\t)\n\t\t\tcontinue;\n\n\t\t// No opt-in to be had. Each says where it lives.\n\t\tconst spec: AppSpec =\n\t\t\tdeclaration.kind === 'site' || declaration.kind === 'mobile-app'\n\t\t\t\t? declaration.app\n\t\t\t\t: {\n\t\t\t\t\t\tpath: declaration.path,\n\t\t\t\t\t\t...(declaration.telescope ? { telescope: true } : {}),\n\t\t\t\t\t};\n\n\t\tconst name = appKey(id);\n\t\t// A config entry of the same name still wins, so a workspace can override\n\t\t// one field without restating the app. Nothing in this repo needs to.\n\t\tconst configured = workspace.apps[name];\n\n\t\tapps[name] = {\n\t\t\t...configured,\n\t\t\ttype:\n\t\t\t\tdeclaration.kind === 'site'\n\t\t\t\t\t? 'web'\n\t\t\t\t\t: declaration.kind === 'mobile-app'\n\t\t\t\t\t\t? 'mobile'\n\t\t\t\t\t\t: 'backend',\n\t\t\tpath: spec.path,\n\t\t\tport: spec.port ?? configured?.port ?? 0,\n\t\t\t// The label it answers on, under a stage's domain and locally alike.\n\t\t\t...((declaration.kind === 'rest-api' || declaration.kind === 'site') &&\n\t\t\tdeclaration.subdomain\n\t\t\t\t? { subdomain: declaration.subdomain }\n\t\t\t\t: {}),\n\t\t\tdependencies: [],\n\t\t\tresolvedDeployTarget: configured?.resolvedDeployTarget ?? defaultTarget,\n\t\t\t...(declaration.kind === 'site'\n\t\t\t\t? {\n\t\t\t\t\t\tframework: configured?.framework ?? FRAMEWORKS[declaration.variant],\n\t\t\t\t\t\t...(declaration.root ? { root: true } : {}),\n\t\t\t\t\t\t...(spec.config ? { config: spec.config } : {}),\n\t\t\t\t\t}\n\t\t\t\t: {}),\n\t\t\t...(declaration.kind === 'mobile-app'\n\t\t\t\t? {\n\t\t\t\t\t\tframework: configured?.framework ?? declaration.variant,\n\t\t\t\t\t\t...(spec.config ? { config: spec.config } : {}),\n\t\t\t\t\t}\n\t\t\t\t: {}),\n\t\t\t// One glob fans out to the six the build reads, because each generator\n\t\t\t// already inspects every export and keeps what it recognises. A\n\t\t\t// per-kind field still wins where one was given.\n\t\t\t...(spec.telescope !== undefined ? { telescope: spec.telescope } : {}),\n\t\t\t...(spec.openapi !== undefined ? { openapi: spec.openapi } : {}),\n\t\t\t...(spec.runtime !== undefined ? { runtime: spec.runtime } : {}),\n\t\t\t...(spec.env !== undefined ? { env: spec.env } : {}),\n\t\t\t...(spec.entry !== undefined ? { entry: spec.entry } : {}),\n\t\t\t...(configured?.domain\n\t\t\t\t? { domain: configured.domain as AppDomainConfig }\n\t\t\t\t: {}),\n\t\t} as NormalizedAppConfig;\n\t}\n\n\t// Build order, from the edges rather than from a hand-kept list. A site that\n\t// depends on a surface depends on the app that serves it — which for a\n\t// mounted auth server is its host, not a container that does not exist.\n\tfor (const [id, declaration] of Object.entries(manifest)) {\n\t\tif (\n\t\t\tdeclaration.kind !== 'site' &&\n\t\t\tdeclaration.kind !== 'mobile-app' &&\n\t\t\tdeclaration.kind !== 'rest-api'\n\t\t)\n\t\t\tcontinue;\n\n\t\tconst app = apps[appKey(id)];\n\t\tif (!app) continue;\n\n\t\t// A site names its edges `dependencies`; a surface names them `calls`.\n\t\tconst edges =\n\t\t\tdeclaration.kind === 'rest-api'\n\t\t\t\t? (declaration.calls ?? [])\n\t\t\t\t: (declaration.dependencies ?? []);\n\n\t\tconst names = new Set<string>();\n\t\tfor (const edge of edges) {\n\t\t\tif (edge.kind !== 'rest-api') continue;\n\t\t\tconst host = hostOf(manifest, edge.target);\n\t\t\tif (!host) continue;\n\t\t\tconst key = appKey(host);\n\t\t\tif (key !== appKey(id) && apps[key]) names.add(key);\n\t\t}\n\n\t\tapp.dependencies = [...names].sort();\n\t}\n\n\tmarkRoot(apps);\n\tassignPorts(apps);\n\n\t// Apps config declared that the graph knows nothing about — a `type: 'mobile'`\n\t// entry, or a hand-run process. Kept rather than dropped: config is still the\n\t// escape hatch for what nothing declares.\n\tfor (const [name, app] of Object.entries(workspace.apps)) {\n\t\tif (!apps[name]) apps[name] = app;\n\t}\n\n\treturn apps;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAgCA,MAAM,aAAwC;CAC7C,QAAQ;CACR,MAAM;CACN,UAAU;AACX;;;;;;;;AASA,SAAgB,OAAO,IAAoB;CAC1C,QAAA,GAAOA,oBAAAA,UAAAA,CAAU,EAAE;AACpB;;;;;;;;;AAUA,SAAgB,OACf,UACA,IACqB;CACrB,MAAM,cAAc,SAAS;CAC7B,IAAI,CAAC,eAAe,YAAY,SAAS,YAAY,OAAO,KAAA;CAE5D,OAAO;AACR;;;;;;;;;;AAWA,SAAS,YAAY,MAAiD;CACrE,MAAM,QACL,MACA,QAC8B;EAC9B,IAAI,SAAS,YAAY,IAAI,IAAI,SAAS,QAAQ,IAAI;EACtD,IAAI,OAAO,IAAI;EACf;CACD;CAEA,MAAM,UAAU,OAAO,QAAQ,IAAI,CAAC,CAAC,MAAM,CAAC,OAAO,IAAI,CAAC,OAAO,OAAO;EACrE,MAAM,CAAC,IAAI,IAAI,MAAM,KAAK,OAAO,CAAC;EAClC,MAAM,CAAC,IAAI,IAAI,MAAM,KAAK,OAAO,CAAC;EAClC,OAAO,KAAK,MAAM,KAAK,MAAM,GAAG,cAAc,EAAE;CACjD,CAAC;CAED,MAAM,QAAQ,IAAI,IACjB,QAAQ,KAAK,GAAG,SAAS,IAAI,IAAI,CAAC,CAAC,QAAQ,MAAmB,CAAC,CAAC,CAAC,CAClE;CAEA,IAAI,OAAO;CACX,KAAK,MAAM,GAAG,QAAQ,SAAS;EAC9B,IAAI,IAAI,MAAM;EACd,OAAO,MAAM,IAAI,IAAI,GAAG,QAAQ;EAChC,IAAI,OAAO;EACX,MAAM,IAAI,IAAI;CACf;AACD;;;;;;;AAQA,SAAS,SAAS,MAAiD;CAClE,MAAM,QAAQ,OAAO,QAAQ,IAAI,CAAC,CAAC,QAAQ,GAAG,OAAO,EAAE,SAAS,KAAK;CACrE,IAAI,MAAM,WAAW,GAAG;CACxB,IAAI,MAAM,MAAM,GAAG,OAAO,EAAE,IAAI,GAAG;CAEnC,MAAM,SACL,MAAM,MAAM,CAAC,UAAU,SAAS,KAAK,MACpC,MAAM,WAAW,IAAI,MAAM,KAAK,KAAA;CAClC,IAAI,QAAQ,OAAO,EAAE,CAAC,OAAO;AAC9B;AAEA,SAAgB,YACf,UACA,WACsC;CACtC,MAAM,OAA4C,CAAC;CACnD,MAAM,gBACL,UAAU,QAAQ,WAAW;CAE9B,KAAK,MAAM,CAAC,IAAI,gBAAgB,OAAO,QAAQ,QAAQ,GAAG;EAKzD,IACC,YAAY,SAAS,UACrB,YAAY,SAAS,gBACrB,YAAY,SAAS,YAErB;EAGD,MAAM,OACL,YAAY,SAAS,UAAU,YAAY,SAAS,eACjD,YAAY,MACZ;GACA,MAAM,YAAY;GAClB,GAAI,YAAY,YAAY,EAAE,WAAW,KAAK,IAAI,CAAC;EACpD;EAEH,MAAM,OAAO,OAAO,EAAE;EAGtB,MAAM,aAAa,UAAU,KAAK;EAElC,KAAK,QAAQ;GACZ,GAAG;GACH,MACC,YAAY,SAAS,SAClB,QACA,YAAY,SAAS,eACpB,WACA;GACL,MAAM,KAAK;GACX,MAAM,KAAK,QAAQ,YAAY,QAAQ;GAEvC,IAAK,YAAY,SAAS,cAAc,YAAY,SAAS,WAC7D,YAAY,YACT,EAAE,WAAW,YAAY,UAAU,IACnC,CAAC;GACJ,cAAc,CAAC;GACf,sBAAsB,YAAY,wBAAwB;GAC1D,GAAI,YAAY,SAAS,SACtB;IACA,WAAW,YAAY,aAAa,WAAW,YAAY;IAC3D,GAAI,YAAY,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACzC,GAAI,KAAK,SAAS,EAAE,QAAQ,KAAK,OAAO,IAAI,CAAC;GAC9C,IACC,CAAC;GACJ,GAAI,YAAY,SAAS,eACtB;IACA,WAAW,YAAY,aAAa,YAAY;IAChD,GAAI,KAAK,SAAS,EAAE,QAAQ,KAAK,OAAO,IAAI,CAAC;GAC9C,IACC,CAAC;GAIJ,GAAI,KAAK,cAAc,KAAA,IAAY,EAAE,WAAW,KAAK,UAAU,IAAI,CAAC;GACpE,GAAI,KAAK,YAAY,KAAA,IAAY,EAAE,SAAS,KAAK,QAAQ,IAAI,CAAC;GAC9D,GAAI,KAAK,YAAY,KAAA,IAAY,EAAE,SAAS,KAAK,QAAQ,IAAI,CAAC;GAC9D,GAAI,KAAK,QAAQ,KAAA,IAAY,EAAE,KAAK,KAAK,IAAI,IAAI,CAAC;GAClD,GAAI,KAAK,UAAU,KAAA,IAAY,EAAE,OAAO,KAAK,MAAM,IAAI,CAAC;GACxD,GAAI,YAAY,SACb,EAAE,QAAQ,WAAW,OAA0B,IAC/C,CAAC;EACL;CACD;CAKA,KAAK,MAAM,CAAC,IAAI,gBAAgB,OAAO,QAAQ,QAAQ,GAAG;EACzD,IACC,YAAY,SAAS,UACrB,YAAY,SAAS,gBACrB,YAAY,SAAS,YAErB;EAED,MAAM,MAAM,KAAK,OAAO,EAAE;EAC1B,IAAI,CAAC,KAAK;EAGV,MAAM,QACL,YAAY,SAAS,aACjB,YAAY,SAAS,CAAC,IACtB,YAAY,gBAAgB,CAAC;EAElC,MAAM,wBAAQ,IAAI,IAAY;EAC9B,KAAK,MAAM,QAAQ,OAAO;GACzB,IAAI,KAAK,SAAS,YAAY;GAC9B,MAAM,OAAO,OAAO,UAAU,KAAK,MAAM;GACzC,IAAI,CAAC,MAAM;GACX,MAAM,MAAM,OAAO,IAAI;GACvB,IAAI,QAAQ,OAAO,EAAE,KAAK,KAAK,MAAM,MAAM,IAAI,GAAG;EACnD;EAEA,IAAI,eAAe,CAAC,GAAG,KAAK,CAAC,CAAC,KAAK;CACpC;CAEA,SAAS,IAAI;CACb,YAAY,IAAI;CAKhB,KAAK,MAAM,CAAC,MAAM,QAAQ,OAAO,QAAQ,UAAU,IAAI,GACtD,IAAI,CAAC,KAAK,OAAO,KAAK,QAAQ;CAG/B,OAAO;AACR"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { n as Sandbox } from "./sandbox-M8UnLhXE.mjs";
|
|
2
|
+
import { ConstructManifest, Declaration } from "@geekmidas/manifest";
|
|
3
|
+
//#region src/reconcile/discover.d.ts
|
|
4
|
+
/** The construct face discovery needs: an id, and the ability to declare. */
|
|
5
|
+
interface Declarable {
|
|
6
|
+
id: string;
|
|
7
|
+
declare(): Declaration[];
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Whether a module export is a construct.
|
|
11
|
+
*
|
|
12
|
+
* Deliberately loose about what else it carries — a construct that also has a
|
|
13
|
+
* `service` is still a construct, and requiring one would exclude the kinds that
|
|
14
|
+
* own no address.
|
|
15
|
+
*/
|
|
16
|
+
declare function isDeclarable(value: unknown): value is Declarable;
|
|
17
|
+
interface DiscoverOptions {
|
|
18
|
+
/** The glob(s) to search. One pattern, not one per kind. */
|
|
19
|
+
patterns: string | readonly string[];
|
|
20
|
+
cwd?: string;
|
|
21
|
+
/**
|
|
22
|
+
* Re-import changed modules, for the dev watcher.
|
|
23
|
+
*
|
|
24
|
+
* A single glob makes discovery more central, not less: a new construct file
|
|
25
|
+
* has to be picked up on `add`, not only on `change`.
|
|
26
|
+
*/
|
|
27
|
+
bustCache?: boolean;
|
|
28
|
+
/**
|
|
29
|
+
* Filled in with where each construct was found, when provided.
|
|
30
|
+
*
|
|
31
|
+
* Discovery is the only thing that knows: it globbed the files and imported
|
|
32
|
+
* them. Everything downstream that needs to *write* an import — the build,
|
|
33
|
+
* generating a server entry that reads a surface's logger — would otherwise
|
|
34
|
+
* have to be told the path in config, which is the string this removes.
|
|
35
|
+
*
|
|
36
|
+
* An out-parameter rather than a second return value so that every existing
|
|
37
|
+
* caller, which wants the manifest and nothing else, is unchanged.
|
|
38
|
+
*/
|
|
39
|
+
sources?: Record<string, ConstructSource>;
|
|
40
|
+
/**
|
|
41
|
+
* Filled in, when provided, with the ids each owner's runnables declared an
|
|
42
|
+
* edge to — keyed by the surface an endpoint was built from, or the worker
|
|
43
|
+
* a cron or subscriber was.
|
|
44
|
+
*
|
|
45
|
+
* A runnable is not a declaration: a surface's endpoints are found by the
|
|
46
|
+
* glob, not listed by the surface, so its node says `endpoints: []` until a
|
|
47
|
+
* build folds the routes in. Anything deciding what an app's process reaches
|
|
48
|
+
* — which keys its container is given — needs those edges before any build,
|
|
49
|
+
* and discovery is already importing the files they are in.
|
|
50
|
+
*/
|
|
51
|
+
runnables?: Record<string, string[]>;
|
|
52
|
+
/**
|
|
53
|
+
* Import the construct modules in this sandbox rather than in this
|
|
54
|
+
* process. Defaults to the run's own (`withSandbox`), so a deploy's every
|
|
55
|
+
* discovery — the engine's included — happens there; with neither, they
|
|
56
|
+
* are imported here, as before.
|
|
57
|
+
*/
|
|
58
|
+
sandbox?: Sandbox;
|
|
59
|
+
}
|
|
60
|
+
/** Importing a construct module, or declaring one, threw in the sandbox. */
|
|
61
|
+
declare class ConstructDiscoveryFailed extends Error {
|
|
62
|
+
readonly errorName: string;
|
|
63
|
+
readonly detail: string;
|
|
64
|
+
constructor(errorName: string, detail: string);
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* The constructs' declarations hold something that is not data, and the
|
|
68
|
+
* sandbox they were discovered in hands the deploy nothing but data.
|
|
69
|
+
*/
|
|
70
|
+
declare class ConstructsNotSerializable extends Error {
|
|
71
|
+
readonly paths: readonly string[];
|
|
72
|
+
constructor(paths: readonly string[]);
|
|
73
|
+
}
|
|
74
|
+
/** Where a construct was declared, and under what name. */
|
|
75
|
+
interface ConstructSource {
|
|
76
|
+
/** Absolute path to the module that exported it. */
|
|
77
|
+
file: string;
|
|
78
|
+
/** The name it was exported as — what an import statement has to say. */
|
|
79
|
+
exportName: string;
|
|
80
|
+
/**
|
|
81
|
+
* The exported construct itself.
|
|
82
|
+
*
|
|
83
|
+
* What a declaration cannot say — whether it serves itself — the object can
|
|
84
|
+
* be asked, and discovery already imported it.
|
|
85
|
+
*/
|
|
86
|
+
construct: unknown;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Build the construct manifest for a project.
|
|
90
|
+
*
|
|
91
|
+
* Runs the manifest's own validation before returning, so an app is wrong here
|
|
92
|
+
* — where the error names a file — rather than at deploy.
|
|
93
|
+
*
|
|
94
|
+
* @throws {DuplicateConstruct} when two exports claim one id.
|
|
95
|
+
*/
|
|
96
|
+
declare function discover(options: DiscoverOptions): Promise<ConstructManifest>;
|
|
97
|
+
//#endregion
|
|
98
|
+
export { isDeclarable as a, discover as i, ConstructsNotSerializable as n, DiscoverOptions as r, ConstructDiscoveryFailed as t };
|
|
99
|
+
//# sourceMappingURL=discover-B6yPpvRV.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discover-B6yPpvRV.d.mts","names":[],"sources":["../src/reconcile/discover.ts"],"mappings":";;;;UAkCU;EACT;EACA,WAAW;;;;;;;;;iBAUI,aAAa,iBAAiB,SAAS;UAYtC;;EAEhB;EACA;;;;;;;EAOA;;;;;;;;;;;;EAYA,UAAU,eAAe;;;;;;;;;;;;EAYzB,YAAY;;;;;;;EAOZ,UAAU;;;cA6FE,iCAAiC;WAEnC;WACA;EAFV,YACU,mBACA;;;;;;cAWE,kCAAkC;WACzB;EAArB,YAAqB;;;UAYL;;EAEhB;;EAEA;;;;;;;EAOA;;;;;;;;;;iBAWqB,SACrB,SAAS,kBACP,QAAQ"}
|