@geekmidas/cli 10.0.0-alpha.60 → 10.0.0-alpha.62
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/{HostingerProvider-DgzKa_Tj.mjs → HostingerProvider-B92qH4dC.mjs} +2 -2
- package/dist/{HostingerProvider-DgzKa_Tj.mjs.map → HostingerProvider-B92qH4dC.mjs.map} +1 -1
- package/dist/{HostingerProvider-BTZd2u0f.cjs → HostingerProvider-DyD1Hin8.cjs} +2 -2
- package/dist/{HostingerProvider-BTZd2u0f.cjs.map → HostingerProvider-DyD1Hin8.cjs.map} +1 -1
- package/dist/{LegacyStateStore-CToa2hga.mjs → LegacyStateStore-A8d2GdT7.mjs} +2 -2
- package/dist/{LegacyStateStore-CToa2hga.mjs.map → LegacyStateStore-A8d2GdT7.mjs.map} +1 -1
- package/dist/{LegacyStateStore-CidlPT0N.cjs → LegacyStateStore-UHJEBLdn.cjs} +2 -2
- package/dist/{LegacyStateStore-CidlPT0N.cjs.map → LegacyStateStore-UHJEBLdn.cjs.map} +1 -1
- package/dist/{LocalStateStore-BFLiOocU.mjs → LocalStateStore-B51rnfgn.mjs} +2 -2
- package/dist/{LocalStateStore-BFLiOocU.mjs.map → LocalStateStore-B51rnfgn.mjs.map} +1 -1
- package/dist/{LocalStateStore-Dpuqka1N.cjs → LocalStateStore-COW3Ldwa.cjs} +2 -2
- package/dist/{LocalStateStore-Dpuqka1N.cjs.map → LocalStateStore-COW3Ldwa.cjs.map} +1 -1
- package/dist/{OpenApiTsGenerator-BTuUumsV.cjs → OpenApiTsGenerator-BSrgw7B0.cjs} +31 -2
- package/dist/OpenApiTsGenerator-BSrgw7B0.cjs.map +1 -0
- package/dist/{OpenApiTsGenerator-CvVr1Ilz.mjs → OpenApiTsGenerator-q5B0z8Xg.mjs} +31 -2
- package/dist/OpenApiTsGenerator-q5B0z8Xg.mjs.map +1 -0
- package/dist/{S3StateStore-aaGkjcxO.mjs → S3StateStore-CJewPhgz.mjs} +2 -2
- package/dist/{S3StateStore-aaGkjcxO.mjs.map → S3StateStore-CJewPhgz.mjs.map} +1 -1
- package/dist/{S3StateStore-cnm813Xn.cjs → S3StateStore-WUJGdRNL.cjs} +2 -2
- package/dist/{S3StateStore-cnm813Xn.cjs.map → S3StateStore-WUJGdRNL.cjs.map} +1 -1
- package/dist/{SSMStateStore-DwaGprVX.cjs → SSMStateStore-Zejt42V8.cjs} +2 -2
- package/dist/{SSMStateStore-DwaGprVX.cjs.map → SSMStateStore-Zejt42V8.cjs.map} +1 -1
- package/dist/{SSMStateStore-BllaJKGo.mjs → SSMStateStore-iK5UKp9d.mjs} +2 -2
- package/dist/{SSMStateStore-BllaJKGo.mjs.map → SSMStateStore-iK5UKp9d.mjs.map} +1 -1
- package/dist/{bundler-CzXZPSBJ.cjs → bundler-CfH9frOS.cjs} +2 -2
- package/dist/{bundler-CzXZPSBJ.cjs.map → bundler-CfH9frOS.cjs.map} +1 -1
- package/dist/{bundler-DJVR4QlW.mjs → bundler-DN5r4x5b.mjs} +2 -2
- package/dist/{bundler-DJVR4QlW.mjs.map → bundler-DN5r4x5b.mjs.map} +1 -1
- package/dist/{cli-D_qTl20Z.cjs → cli-DOAUp80L.cjs} +12 -16
- package/dist/cli-DOAUp80L.cjs.map +1 -0
- package/dist/{cli-DzR1hpum.mjs → cli-DYwxmfsW.mjs} +10 -14
- package/dist/cli-DYwxmfsW.mjs.map +1 -0
- package/dist/{config-DXnkCEq0.cjs → config-BYh9S0cZ.cjs} +2 -2
- package/dist/config-BYh9S0cZ.cjs.map +1 -0
- package/dist/{config-C5-EEdmr.mjs → config-Bf4-bROQ.mjs} +2 -2
- package/dist/config-Bf4-bROQ.mjs.map +1 -0
- package/dist/config.cjs +2 -2
- package/dist/config.d.cts +2 -2
- package/dist/config.d.mts +2 -2
- package/dist/config.mjs +2 -2
- package/dist/define-CHBIEc5j.mjs +94 -0
- package/dist/define-CHBIEc5j.mjs.map +1 -0
- package/dist/define-Cv_QvDrg.cjs +141 -0
- package/dist/define-Cv_QvDrg.cjs.map +1 -0
- package/dist/deploy/public.cjs +28 -13
- package/dist/deploy/public.d.cts +38 -315
- package/dist/deploy/public.d.cts.map +1 -1
- package/dist/deploy/public.d.mts +38 -315
- package/dist/deploy/public.d.mts.map +1 -1
- package/dist/deploy/public.mjs +8 -3
- package/dist/{deploy-D6Q09OkA.mjs → deploy-B7jvUORo.mjs} +155 -682
- package/dist/deploy-B7jvUORo.mjs.map +1 -0
- package/dist/deploy-Cg9fae7a.mjs +133 -0
- package/dist/deploy-Cg9fae7a.mjs.map +1 -0
- package/dist/deploy-D8Qr-Xto.cjs +138 -0
- package/dist/deploy-D8Qr-Xto.cjs.map +1 -0
- package/dist/{deploy-0fBVeWO-.cjs → deploy-DSaCYvcO.cjs} +182 -727
- package/dist/deploy-DSaCYvcO.cjs.map +1 -0
- package/dist/dokploy-CD9PY-3D.mjs +32 -0
- package/dist/dokploy-CD9PY-3D.mjs.map +1 -0
- package/dist/dokploy-Ey2foJLv.cjs +32 -0
- package/dist/dokploy-Ey2foJLv.cjs.map +1 -0
- package/dist/{encryption-aDA2AzVx.mjs → encryption-CVwvGbsL.mjs} +4 -4
- package/dist/{encryption-aDA2AzVx.mjs.map → encryption-CVwvGbsL.mjs.map} +1 -1
- package/dist/{encryption-CML4UaPi.cjs → encryption-ChBk3hTj.cjs} +4 -4
- package/dist/{encryption-CML4UaPi.cjs.map → encryption-ChBk3hTj.cjs.map} +1 -1
- package/dist/{github-DmCj2u95.mjs → github-BCB3_LBX.mjs} +3 -3
- package/dist/{github-DmCj2u95.mjs.map → github-BCB3_LBX.mjs.map} +1 -1
- package/dist/{github-Cq57poPj.cjs → github-OUgPDlqg.cjs} +3 -3
- package/dist/{github-Cq57poPj.cjs.map → github-OUgPDlqg.cjs.map} +1 -1
- package/dist/{index-UiWCaGzU.d.cts → index-BtXDZQuF.d.cts} +2 -2
- package/dist/{index-Da1-oa9W.d.mts.map → index-BtXDZQuF.d.cts.map} +1 -1
- package/dist/{index-Da1-oa9W.d.mts → index-DrKzpHl-.d.mts} +2 -2
- package/dist/{index-UiWCaGzU.d.cts.map → index-DrKzpHl-.d.mts.map} +1 -1
- package/dist/index.cjs +1728 -146
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +1719 -153
- package/dist/index.mjs.map +1 -1
- package/dist/migrate-BoHMqdCu.mjs +265 -0
- package/dist/migrate-BoHMqdCu.mjs.map +1 -0
- package/dist/migrate-dnaFMvOm.cjs +270 -0
- package/dist/migrate-dnaFMvOm.cjs.map +1 -0
- package/dist/openapi.cjs +2 -2
- package/dist/openapi.d.cts +1 -1
- package/dist/openapi.d.mts +1 -1
- package/dist/openapi.mjs +2 -2
- package/dist/{ready-CIHpnUc5.mjs → ready-DQIy21W5.mjs} +2 -2
- package/dist/{ready-CIHpnUc5.mjs.map → ready-DQIy21W5.mjs.map} +1 -1
- package/dist/{ready-CCLIAkwR.cjs → ready-XlNx-Gbo.cjs} +2 -2
- package/dist/{ready-CCLIAkwR.cjs.map → ready-XlNx-Gbo.cjs.map} +1 -1
- package/dist/reconcile/public.d.cts +1 -1
- package/dist/reconcile/public.d.mts +1 -1
- package/dist/resolve-CFCIkm7m.mjs +170 -0
- package/dist/resolve-CFCIkm7m.mjs.map +1 -0
- package/dist/resolve-wbv66HjD.cjs +217 -0
- package/dist/resolve-wbv66HjD.cjs.map +1 -0
- package/dist/runtime-CMwtq0AL.cjs +163 -0
- package/dist/runtime-CMwtq0AL.cjs.map +1 -0
- package/dist/runtime-CXPlkZzs.d.mts +90 -0
- package/dist/runtime-CXPlkZzs.d.mts.map +1 -0
- package/dist/runtime-DbakJS8u.mjs +134 -0
- package/dist/runtime-DbakJS8u.mjs.map +1 -0
- package/dist/runtime-Dn_n-29S.d.cts +90 -0
- package/dist/runtime-Dn_n-29S.d.cts.map +1 -0
- package/dist/{sniffer-DIv12ncU.cjs → sniffer-BsfPa-GA.cjs} +2581 -2170
- package/dist/sniffer-BsfPa-GA.cjs.map +1 -0
- package/dist/{sniffer-BM8fpCas.mjs → sniffer-DHE2Nafd.mjs} +2428 -2185
- package/dist/sniffer-DHE2Nafd.mjs.map +1 -0
- package/dist/target/public.cjs +15 -0
- package/dist/target/public.d.cts +28 -0
- package/dist/target/public.d.cts.map +1 -0
- package/dist/target/public.d.mts +28 -0
- package/dist/target/public.d.mts.map +1 -0
- package/dist/target/public.mjs +4 -0
- package/dist/terminal-6oL0vANs.cjs +576 -0
- package/dist/terminal-6oL0vANs.cjs.map +1 -0
- package/dist/terminal-ByZNjuig.mjs +517 -0
- package/dist/terminal-ByZNjuig.mjs.map +1 -0
- package/dist/{types-efNLu9xu.d.cts → types-CfLKGfC_.d.mts} +624 -34
- package/dist/types-CfLKGfC_.d.mts.map +1 -0
- package/dist/{types-Bp1mVxG0.d.mts → types-DIA7Li-J.d.cts} +626 -34
- package/dist/types-DIA7Li-J.d.cts.map +1 -0
- package/dist/vitest.cjs +1 -1
- package/dist/vitest.mjs +1 -1
- package/dist/workspace/index.cjs +1 -1
- package/dist/workspace/index.d.cts +3 -3
- package/dist/workspace/index.d.mts +3 -3
- package/dist/workspace/index.mjs +1 -1
- package/dist/{workspace-B64Xk1Mb.cjs → workspace-B6zQO6RY.cjs} +229 -23
- package/dist/workspace-B6zQO6RY.cjs.map +1 -0
- package/dist/{workspace-Bp1xVaOz.mjs → workspace-BFe57es7.mjs} +229 -23
- package/dist/workspace-BFe57es7.mjs.map +1 -0
- package/package.json +23 -13
- package/dist/OpenApiTsGenerator-BTuUumsV.cjs.map +0 -1
- package/dist/OpenApiTsGenerator-CvVr1Ilz.mjs.map +0 -1
- package/dist/cli-D_qTl20Z.cjs.map +0 -1
- package/dist/cli-DzR1hpum.mjs.map +0 -1
- package/dist/config-C5-EEdmr.mjs.map +0 -1
- package/dist/config-DXnkCEq0.cjs.map +0 -1
- package/dist/deploy-0fBVeWO-.cjs.map +0 -1
- package/dist/deploy-D6Q09OkA.mjs.map +0 -1
- package/dist/migrate-BTqIflwc.cjs +0 -743
- package/dist/migrate-BTqIflwc.cjs.map +0 -1
- package/dist/migrate-B_6KofUo.mjs +0 -736
- package/dist/migrate-B_6KofUo.mjs.map +0 -1
- package/dist/sniffer-BM8fpCas.mjs.map +0 -1
- package/dist/sniffer-DIv12ncU.cjs.map +0 -1
- package/dist/types-Bp1mVxG0.d.mts.map +0 -1
- package/dist/types-efNLu9xu.d.cts.map +0 -1
- package/dist/workspace-B64Xk1Mb.cjs.map +0 -1
- package/dist/workspace-Bp1xVaOz.mjs.map +0 -1
|
@@ -1,110 +1,19 @@
|
|
|
1
|
-
import { B as
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { D as assertDeployedStage, a as getAppBuildOrder, b as getDeployTargetError, m as stripPublicPrefix, p as getPublicEnvPrefix, x as isDeployTargetSupported } from "./workspace-Bp1xVaOz.mjs";
|
|
1
|
+
import { A as StateStoreBusy, B as run, C as setDnsRecord, E as setPostgresBackupId, I as withGeneratedSecrets, L as encryptSecrets, M as StateVersionConflict, S as setDeployedImage, T as setGeneratedSecret, V as runOutput, W as constructGlobs, X as applyPostgres, _ as getBackupState, a as DockerBuildFailed, b as setApplicationId, c as dockerCommand, dt as providerOf, ft as storageBackendFor, g as createEmptyState, h as resolveHost, i as DokployApiError, lt as cacheBackendFor, m as isMainFrontendApp, o as DockerPushFailed, p as validateImageRef, r as DokployApi, st as resourceName, t as sniffAllApps, ut as eventsBackendFor, v as getGeneratedSecret, w as setDnsVerification, x as setBackupState, y as isDnsVerified, z as keyFingerprint } from "./sniffer-DHE2Nafd.mjs";
|
|
2
|
+
import { a as output, t as discover } from "./discover-FrYvzkeC.mjs";
|
|
3
|
+
import { f as appKey } from "./config-Bf4-bROQ.mjs";
|
|
4
|
+
import { a as getAppBuildOrder, m as stripPublicPrefix, p as getPublicEnvPrefix } from "./workspace-BFe57es7.mjs";
|
|
6
5
|
import { i as toEmbeddableSecrets, t as initStageSecrets } from "./storage-BzaUxmqe.mjs";
|
|
7
|
-
import { d as imageName, f as imageRef, g as projectName, h as ownershipMarker, l as applicationName, m as markerOf,
|
|
6
|
+
import { d as imageName, f as imageRef, g as projectName, h as ownershipMarker, l as applicationName, m as markerOf, p as isOwnedBy } from "./store-BS8A7NcA.mjs";
|
|
7
|
+
import { c as MissingCredential, o as eventError } from "./terminal-ByZNjuig.mjs";
|
|
8
8
|
import { join, resolve } from "node:path";
|
|
9
9
|
import { chmod, mkdtemp, rm, writeFile } from "node:fs/promises";
|
|
10
10
|
import { tmpdir } from "node:os";
|
|
11
11
|
import { cacheTable, cloudName, cookieDomain, dependentsOf, externalApiUrl, mobileOrigins, provideKey, provisionOrder, schemeBase } from "@geekmidas/manifest";
|
|
12
12
|
import { createHash, randomBytes } from "node:crypto";
|
|
13
|
-
import { generateKeyring } from "@geekmidas/constructs/encryption";
|
|
14
13
|
import { ownerRole, readerRole, roleStatements } from "@geekmidas/db/pg/roles";
|
|
15
14
|
import { Client } from "pg";
|
|
16
15
|
import { cacheTableStatements } from "@geekmidas/cache/postgres";
|
|
17
16
|
import { lookup } from "node:dns/promises";
|
|
18
|
-
//#region src/deploy/credentials.ts
|
|
19
|
-
/**
|
|
20
|
-
* How a deploy gets the credentials it acts with.
|
|
21
|
-
*
|
|
22
|
-
* `deploy()` never prompts and never reads a terminal: it asks a
|
|
23
|
-
* `CredentialProvider` and, when the provider has nothing, stops with
|
|
24
|
-
* `MissingCredential` naming what it needed and how to supply it. Whether to
|
|
25
|
-
* ask a person, read a vault or fail is the caller's decision — `gkm deploy`
|
|
26
|
-
* prompts at a terminal and stores what was typed; a CI job sets the
|
|
27
|
-
* environment; a host passes its own provider.
|
|
28
|
-
*/
|
|
29
|
-
/** How to supply each kind, for the error that says it is missing. */
|
|
30
|
-
const HOW_TO_PROVIDE = {
|
|
31
|
-
dokploy: "Set DOKPLOY_API_TOKEN (and DOKPLOY_ENDPOINT, or deploy.dokploy.endpoint in gkm.config.ts), run `gkm login --provider dokploy`, or pass them through the deploy's CredentialProvider.",
|
|
32
|
-
registry: "Add the registry in Dokploy (Settings → Docker Registry) and set deploy.dokploy.registryId, set DOCKER_REGISTRY_USERNAME and DOCKER_REGISTRY_PASSWORD, or run `gkm deploy` at a terminal to be asked for them."
|
|
33
|
-
};
|
|
34
|
-
/** A deploy needed a credential, and its provider had none. */
|
|
35
|
-
var MissingCredential = class extends Error {
|
|
36
|
-
kind;
|
|
37
|
-
target;
|
|
38
|
-
howToProvide;
|
|
39
|
-
constructor(kind, target, howToProvide = HOW_TO_PROVIDE[kind]) {
|
|
40
|
-
const what = kind === "dokploy" ? `No Dokploy credentials${target ? ` for ${target}` : ""}.` : `Dokploy has no registry for ${target ?? "the configured registry"}, and there are no credentials to create one with.`;
|
|
41
|
-
super(`${what} ${howToProvide}`);
|
|
42
|
-
this.kind = kind;
|
|
43
|
-
this.target = target;
|
|
44
|
-
this.howToProvide = howToProvide;
|
|
45
|
-
this.name = "MissingCredential";
|
|
46
|
-
}
|
|
47
|
-
};
|
|
48
|
-
/** Whatever was asked for, from the first provider that has it. */
|
|
49
|
-
function chainCredentials(...providers) {
|
|
50
|
-
return { async get(request, options) {
|
|
51
|
-
for (const provider of providers) {
|
|
52
|
-
const found = await provider.get(request, options);
|
|
53
|
-
if (found) return found;
|
|
54
|
-
}
|
|
55
|
-
} };
|
|
56
|
-
}
|
|
57
|
-
/**
|
|
58
|
-
* Credentials from the environment, then from what `gkm login` stored. What
|
|
59
|
-
* `deploy()` uses when it is handed no provider.
|
|
60
|
-
*
|
|
61
|
-
* - Dokploy: `DOKPLOY_API_TOKEN` / `DOKPLOY_ENDPOINT`, each falling back to
|
|
62
|
-
* the stored login, and the endpoint finally to `deploy.dokploy.endpoint`.
|
|
63
|
-
* Each half is read on its own: a token is a secret and belongs in the
|
|
64
|
-
* environment, an endpoint is configuration and belongs in the config.
|
|
65
|
-
* - Registry: `DOCKER_REGISTRY_USERNAME` / `DOCKER_REGISTRY_PASSWORD`.
|
|
66
|
-
*/
|
|
67
|
-
function storedCredentials(options = {}) {
|
|
68
|
-
const env = options.env ?? process.env;
|
|
69
|
-
return { async get(asked) {
|
|
70
|
-
const request = asked;
|
|
71
|
-
switch (request.kind) {
|
|
72
|
-
case "dokploy": {
|
|
73
|
-
const stored = (await readCredentials(options.home ? { home: options.home } : void 0)).dokploy;
|
|
74
|
-
const token = env.DOKPLOY_API_TOKEN ?? stored?.token;
|
|
75
|
-
const endpoint = env.DOKPLOY_ENDPOINT ?? stored?.endpoint ?? request.endpoint;
|
|
76
|
-
if (!token || !endpoint) return void 0;
|
|
77
|
-
return {
|
|
78
|
-
endpoint: endpoint.replace(/\/$/, ""),
|
|
79
|
-
token
|
|
80
|
-
};
|
|
81
|
-
}
|
|
82
|
-
case "registry": {
|
|
83
|
-
const username = env.DOCKER_REGISTRY_USERNAME;
|
|
84
|
-
const password = env.DOCKER_REGISTRY_PASSWORD;
|
|
85
|
-
if (!username || !password) return void 0;
|
|
86
|
-
return {
|
|
87
|
-
username,
|
|
88
|
-
password
|
|
89
|
-
};
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
} };
|
|
93
|
-
}
|
|
94
|
-
//#endregion
|
|
95
|
-
//#region src/deploy/events.ts
|
|
96
|
-
/** An error as an event carries it: its name and message, nothing else. */
|
|
97
|
-
function eventError(error) {
|
|
98
|
-
if (error instanceof Error) return {
|
|
99
|
-
name: error.name,
|
|
100
|
-
message: error.message
|
|
101
|
-
};
|
|
102
|
-
return {
|
|
103
|
-
name: "Error",
|
|
104
|
-
message: String(error)
|
|
105
|
-
};
|
|
106
|
-
}
|
|
107
|
-
//#endregion
|
|
108
17
|
//#region src/deploy/fromManifest.ts
|
|
109
18
|
/**
|
|
110
19
|
* The Dokploy target, read off the construct manifest.
|
|
@@ -855,102 +764,6 @@ function surfaceAddresses(manifest, appUrls) {
|
|
|
855
764
|
return addresses;
|
|
856
765
|
}
|
|
857
766
|
//#endregion
|
|
858
|
-
//#region src/deploy/state.ts
|
|
859
|
-
/**
|
|
860
|
-
* Create a new empty state for a stage
|
|
861
|
-
*/
|
|
862
|
-
function createEmptyState(stage, projectId, environmentId) {
|
|
863
|
-
return {
|
|
864
|
-
provider: "dokploy",
|
|
865
|
-
stage,
|
|
866
|
-
projectId,
|
|
867
|
-
environmentId,
|
|
868
|
-
applications: {},
|
|
869
|
-
services: {},
|
|
870
|
-
lastDeployedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
871
|
-
};
|
|
872
|
-
}
|
|
873
|
-
/**
|
|
874
|
-
* Set application ID in state (mutates state)
|
|
875
|
-
*/
|
|
876
|
-
function setApplicationId(state, appName, applicationId) {
|
|
877
|
-
state.applications[appName] = applicationId;
|
|
878
|
-
}
|
|
879
|
-
/**
|
|
880
|
-
* Record the image an app was deployed with (mutates state)
|
|
881
|
-
*/
|
|
882
|
-
function setDeployedImage(state, appName, image) {
|
|
883
|
-
state.images = {
|
|
884
|
-
...state.images,
|
|
885
|
-
[appName]: image
|
|
886
|
-
};
|
|
887
|
-
}
|
|
888
|
-
/**
|
|
889
|
-
* Get a generated secret for an app
|
|
890
|
-
*/
|
|
891
|
-
function getGeneratedSecret(state, appName, secretName) {
|
|
892
|
-
return state?.generatedSecrets?.[appName]?.[secretName];
|
|
893
|
-
}
|
|
894
|
-
/**
|
|
895
|
-
* Set a generated secret for an app (mutates state)
|
|
896
|
-
*/
|
|
897
|
-
function setGeneratedSecret(state, appName, secretName, value) {
|
|
898
|
-
if (!state.generatedSecrets) state.generatedSecrets = {};
|
|
899
|
-
if (!state.generatedSecrets[appName]) state.generatedSecrets[appName] = {};
|
|
900
|
-
state.generatedSecrets[appName][secretName] = value;
|
|
901
|
-
}
|
|
902
|
-
/**
|
|
903
|
-
* Set DNS verification record for a hostname (mutates state)
|
|
904
|
-
*/
|
|
905
|
-
function setDnsVerification(state, hostname, serverIp) {
|
|
906
|
-
if (!state.dnsVerified) state.dnsVerified = {};
|
|
907
|
-
state.dnsVerified[hostname] = {
|
|
908
|
-
serverIp,
|
|
909
|
-
verifiedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
910
|
-
};
|
|
911
|
-
}
|
|
912
|
-
/**
|
|
913
|
-
* Check if a hostname is already verified with the given IP
|
|
914
|
-
*/
|
|
915
|
-
function isDnsVerified(state, hostname, serverIp) {
|
|
916
|
-
return (state?.dnsVerified?.[hostname])?.serverIp === serverIp;
|
|
917
|
-
}
|
|
918
|
-
/**
|
|
919
|
-
* Get the key for a DNS record in state
|
|
920
|
-
*/
|
|
921
|
-
function getDnsRecordKey(name, type) {
|
|
922
|
-
return `${name}:${type}`;
|
|
923
|
-
}
|
|
924
|
-
/**
|
|
925
|
-
* Set a created DNS record in state (mutates state)
|
|
926
|
-
*/
|
|
927
|
-
function setDnsRecord(state, record) {
|
|
928
|
-
if (!state.dnsRecords) state.dnsRecords = {};
|
|
929
|
-
const key = getDnsRecordKey(record.name, record.type);
|
|
930
|
-
state.dnsRecords[key] = {
|
|
931
|
-
...record,
|
|
932
|
-
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
933
|
-
};
|
|
934
|
-
}
|
|
935
|
-
/**
|
|
936
|
-
* Get backup state from state
|
|
937
|
-
*/
|
|
938
|
-
function getBackupState(state) {
|
|
939
|
-
return state?.backups;
|
|
940
|
-
}
|
|
941
|
-
/**
|
|
942
|
-
* Set backup state (mutates state)
|
|
943
|
-
*/
|
|
944
|
-
function setBackupState(state, backupState) {
|
|
945
|
-
state.backups = backupState;
|
|
946
|
-
}
|
|
947
|
-
/**
|
|
948
|
-
* Set postgres backup ID in state (mutates state)
|
|
949
|
-
*/
|
|
950
|
-
function setPostgresBackupId(state, backupId) {
|
|
951
|
-
if (state.backups) state.backups.postgresBackupId = backupId;
|
|
952
|
-
}
|
|
953
|
-
//#endregion
|
|
954
767
|
//#region src/deploy/dns/DnsProvider.ts
|
|
955
768
|
/**
|
|
956
769
|
* Check if value is a DnsProvider implementation.
|
|
@@ -972,7 +785,7 @@ async function createDnsProvider(options) {
|
|
|
972
785
|
if (isDnsProvider(config.provider)) return config.provider;
|
|
973
786
|
const provider = config.provider;
|
|
974
787
|
if (provider === "hostinger") {
|
|
975
|
-
const { HostingerProvider } = await import("./HostingerProvider-
|
|
788
|
+
const { HostingerProvider } = await import("./HostingerProvider-B92qH4dC.mjs");
|
|
976
789
|
return new HostingerProvider();
|
|
977
790
|
}
|
|
978
791
|
if (provider === "route53") {
|
|
@@ -994,7 +807,7 @@ async function createDnsProvider(options) {
|
|
|
994
807
|
*
|
|
995
808
|
* Handles automatic DNS record creation for deployed applications.
|
|
996
809
|
*/
|
|
997
|
-
const logger$
|
|
810
|
+
const logger$2 = output;
|
|
998
811
|
/**
|
|
999
812
|
* Check if DNS config is legacy format (single domain with `domain` property)
|
|
1000
813
|
*/
|
|
@@ -1031,7 +844,7 @@ function groupHostnamesByDomain(appHostnames, dnsConfig) {
|
|
|
1031
844
|
for (const [appName, hostname] of appHostnames) {
|
|
1032
845
|
const rootDomain = findRootDomain(hostname, dnsConfig);
|
|
1033
846
|
if (!rootDomain) {
|
|
1034
|
-
logger$
|
|
847
|
+
logger$2.log(` ⚠ No DNS config found for hostname: ${hostname}`);
|
|
1035
848
|
continue;
|
|
1036
849
|
}
|
|
1037
850
|
if (!grouped.has(rootDomain)) grouped.set(rootDomain, /* @__PURE__ */ new Map());
|
|
@@ -1081,10 +894,10 @@ function generateRequiredRecords(appHostnames, rootDomain, serverIp) {
|
|
|
1081
894
|
* Print DNS records table
|
|
1082
895
|
*/
|
|
1083
896
|
function printDnsRecordsTable(records, rootDomain) {
|
|
1084
|
-
logger$
|
|
1085
|
-
logger$
|
|
1086
|
-
logger$
|
|
1087
|
-
logger$
|
|
897
|
+
logger$2.log(`\n 📋 DNS Records for ${rootDomain}:`);
|
|
898
|
+
logger$2.log(" ┌─────────────────────────────────────┬──────┬─────────────────┬────────┐");
|
|
899
|
+
logger$2.log(" │ Subdomain │ Type │ Value │ Status │");
|
|
900
|
+
logger$2.log(" ├─────────────────────────────────────┼──────┼─────────────────┼────────┤");
|
|
1088
901
|
for (const record of records) {
|
|
1089
902
|
const subdomain = record.subdomain.padEnd(35);
|
|
1090
903
|
const type = record.type.padEnd(4);
|
|
@@ -1094,18 +907,18 @@ function printDnsRecordsTable(records, rootDomain) {
|
|
|
1094
907
|
else if (record.created) status = "✓ new";
|
|
1095
908
|
else if (record.existed) status = "✓";
|
|
1096
909
|
else status = "?";
|
|
1097
|
-
logger$
|
|
910
|
+
logger$2.log(` │ ${subdomain} │ ${type} │ ${value} │ ${status.padEnd(6)} │`);
|
|
1098
911
|
}
|
|
1099
|
-
logger$
|
|
912
|
+
logger$2.log(" └─────────────────────────────────────┴──────┴─────────────────┴────────┘");
|
|
1100
913
|
}
|
|
1101
914
|
/**
|
|
1102
915
|
* Print DNS records in a simple format for manual setup
|
|
1103
916
|
*/
|
|
1104
917
|
function printDnsRecordsSimple(records, rootDomain) {
|
|
1105
|
-
logger$
|
|
1106
|
-
logger$
|
|
1107
|
-
for (const record of records) logger$
|
|
1108
|
-
logger$
|
|
918
|
+
logger$2.log("\n 📋 Required DNS Records:");
|
|
919
|
+
logger$2.log(` Add these A records to your DNS provider (${rootDomain}):\n`);
|
|
920
|
+
for (const record of records) logger$2.log(` ${record.subdomain} → ${record.value} (A record)`);
|
|
921
|
+
logger$2.log("");
|
|
1109
922
|
}
|
|
1110
923
|
/**
|
|
1111
924
|
* Create DNS records for a single domain using its configured provider
|
|
@@ -1117,7 +930,7 @@ async function createDnsRecordsForDomain(records, rootDomain, providerConfig) {
|
|
|
1117
930
|
provider = await createDnsProvider({ config: providerConfig });
|
|
1118
931
|
} catch (error) {
|
|
1119
932
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
1120
|
-
logger$
|
|
933
|
+
logger$2.log(` ⚠ Failed to create DNS provider for ${rootDomain}: ${message}`);
|
|
1121
934
|
return records.map((r) => ({
|
|
1122
935
|
...r,
|
|
1123
936
|
error: message
|
|
@@ -1171,7 +984,7 @@ async function createDnsRecordsForDomain(records, rootDomain, providerConfig) {
|
|
|
1171
984
|
}
|
|
1172
985
|
} catch (error) {
|
|
1173
986
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
1174
|
-
logger$
|
|
987
|
+
logger$2.log(` ⚠ Failed to create DNS records for ${rootDomain}: ${message}`);
|
|
1175
988
|
return records.map((r) => ({
|
|
1176
989
|
hostname: r.hostname,
|
|
1177
990
|
subdomain: r.subdomain,
|
|
@@ -1198,20 +1011,20 @@ async function createDnsRecordsForDomain(records, rootDomain, providerConfig) {
|
|
|
1198
1011
|
async function orchestrateDns(appHostnames, dnsConfig, dokployEndpoint, state) {
|
|
1199
1012
|
if (!dnsConfig) return null;
|
|
1200
1013
|
const normalizedConfig = normalizeDnsConfig(dnsConfig);
|
|
1201
|
-
logger$
|
|
1014
|
+
logger$2.log("\n🌐 Setting up DNS records...");
|
|
1202
1015
|
let serverIp;
|
|
1203
1016
|
try {
|
|
1204
1017
|
const endpointUrl = new URL(dokployEndpoint);
|
|
1205
1018
|
serverIp = await resolveHostnameToIp(endpointUrl.hostname);
|
|
1206
|
-
logger$
|
|
1019
|
+
logger$2.log(` Server IP: ${serverIp} (from ${endpointUrl.hostname})`);
|
|
1207
1020
|
} catch (error) {
|
|
1208
1021
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
1209
|
-
logger$
|
|
1022
|
+
logger$2.log(` ⚠ Failed to resolve server IP: ${message}`);
|
|
1210
1023
|
return null;
|
|
1211
1024
|
}
|
|
1212
1025
|
const groupedHostnames = groupHostnamesByDomain(appHostnames, normalizedConfig);
|
|
1213
1026
|
if (groupedHostnames.size === 0) {
|
|
1214
|
-
logger$
|
|
1027
|
+
logger$2.log(" No DNS records needed (no hostnames match configured domains)");
|
|
1215
1028
|
return {
|
|
1216
1029
|
records: [],
|
|
1217
1030
|
success: true,
|
|
@@ -1223,22 +1036,22 @@ async function orchestrateDns(appHostnames, dnsConfig, dokployEndpoint, state) {
|
|
|
1223
1036
|
for (const [rootDomain, domainHostnames] of groupedHostnames) {
|
|
1224
1037
|
const providerConfig = normalizedConfig[rootDomain];
|
|
1225
1038
|
if (!providerConfig) {
|
|
1226
|
-
logger$
|
|
1039
|
+
logger$2.log(` ⚠ No provider config for ${rootDomain}`);
|
|
1227
1040
|
continue;
|
|
1228
1041
|
}
|
|
1229
1042
|
const providerName = typeof providerConfig.provider === "string" ? providerConfig.provider : "custom";
|
|
1230
1043
|
const requiredRecords = generateRequiredRecords(domainHostnames, rootDomain, serverIp);
|
|
1231
1044
|
if (requiredRecords.length === 0) continue;
|
|
1232
|
-
logger$
|
|
1045
|
+
logger$2.log(` Creating DNS records for ${rootDomain} (${providerName})...`);
|
|
1233
1046
|
const domainRecords = await createDnsRecordsForDomain(requiredRecords, rootDomain, providerConfig);
|
|
1234
1047
|
allRecords.push(...domainRecords);
|
|
1235
1048
|
const created = domainRecords.filter((r) => r.created).length;
|
|
1236
1049
|
const existed = domainRecords.filter((r) => r.existed).length;
|
|
1237
1050
|
const failed = domainRecords.filter((r) => r.error).length;
|
|
1238
|
-
if (created > 0) logger$
|
|
1239
|
-
if (existed > 0) logger$
|
|
1051
|
+
if (created > 0) logger$2.log(` ✓ Created ${created} DNS record(s) for ${rootDomain}`);
|
|
1052
|
+
if (existed > 0) logger$2.log(` ✓ ${existed} record(s) already exist for ${rootDomain}`);
|
|
1240
1053
|
if (failed > 0) {
|
|
1241
|
-
logger$
|
|
1054
|
+
logger$2.log(` ⚠ ${failed} record(s) failed for ${rootDomain}`);
|
|
1242
1055
|
hasFailures = true;
|
|
1243
1056
|
}
|
|
1244
1057
|
if (state) {
|
|
@@ -1275,10 +1088,10 @@ async function orchestrateDns(appHostnames, dnsConfig, dokployEndpoint, state) {
|
|
|
1275
1088
|
*/
|
|
1276
1089
|
async function verifyDnsRecords(appHostnames, serverIp, state) {
|
|
1277
1090
|
const results = [];
|
|
1278
|
-
logger$
|
|
1091
|
+
logger$2.log("\n🔍 Verifying DNS records...");
|
|
1279
1092
|
for (const [appName, hostname] of appHostnames) {
|
|
1280
1093
|
if (isDnsVerified(state, hostname, serverIp)) {
|
|
1281
|
-
logger$
|
|
1094
|
+
logger$2.log(` ✓ ${hostname} (previously verified)`);
|
|
1282
1095
|
results.push({
|
|
1283
1096
|
hostname,
|
|
1284
1097
|
appName,
|
|
@@ -1292,7 +1105,7 @@ async function verifyDnsRecords(appHostnames, serverIp, state) {
|
|
|
1292
1105
|
const resolvedIp = await resolveHostnameToIp(hostname);
|
|
1293
1106
|
if (resolvedIp === serverIp) {
|
|
1294
1107
|
setDnsVerification(state, hostname, serverIp);
|
|
1295
|
-
logger$
|
|
1108
|
+
logger$2.log(` ✓ ${hostname} → ${resolvedIp}`);
|
|
1296
1109
|
results.push({
|
|
1297
1110
|
hostname,
|
|
1298
1111
|
appName,
|
|
@@ -1301,7 +1114,7 @@ async function verifyDnsRecords(appHostnames, serverIp, state) {
|
|
|
1301
1114
|
expectedIp: serverIp
|
|
1302
1115
|
});
|
|
1303
1116
|
} else {
|
|
1304
|
-
logger$
|
|
1117
|
+
logger$2.log(` ⚠ ${hostname} resolves to ${resolvedIp}, expected ${serverIp}`);
|
|
1305
1118
|
results.push({
|
|
1306
1119
|
hostname,
|
|
1307
1120
|
appName,
|
|
@@ -1312,7 +1125,7 @@ async function verifyDnsRecords(appHostnames, serverIp, state) {
|
|
|
1312
1125
|
}
|
|
1313
1126
|
} catch (error) {
|
|
1314
1127
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
1315
|
-
logger$
|
|
1128
|
+
logger$2.log(` ⚠ ${hostname} DNS not propagated (${message})`);
|
|
1316
1129
|
results.push({
|
|
1317
1130
|
hostname,
|
|
1318
1131
|
appName,
|
|
@@ -1326,14 +1139,14 @@ async function verifyDnsRecords(appHostnames, serverIp, state) {
|
|
|
1326
1139
|
const skipped = results.filter((r) => r.skipped).length;
|
|
1327
1140
|
const pending = results.filter((r) => !r.verified).length;
|
|
1328
1141
|
if (pending > 0) {
|
|
1329
|
-
logger$
|
|
1330
|
-
logger$
|
|
1331
|
-
} else if (skipped > 0) logger$
|
|
1142
|
+
logger$2.log(`\n ${verified} verified, ${pending} pending propagation`);
|
|
1143
|
+
logger$2.log(" DNS changes may take 5-30 minutes to propagate");
|
|
1144
|
+
} else if (skipped > 0) logger$2.log(` ${verified} verified (${skipped} from cache)`);
|
|
1332
1145
|
return results;
|
|
1333
1146
|
}
|
|
1334
1147
|
//#endregion
|
|
1335
1148
|
//#region src/deploy/docker.ts
|
|
1336
|
-
const logger$
|
|
1149
|
+
const logger$1 = output;
|
|
1337
1150
|
/**
|
|
1338
1151
|
* The id the Dockerfile templates mount the encrypted credentials under:
|
|
1339
1152
|
* `RUN --mount=type=secret,id=gkm_credentials`.
|
|
@@ -1396,8 +1209,8 @@ async function writeCredentialsFile(credentials) {
|
|
|
1396
1209
|
* @param credentials - Encrypted credentials, passed as a build secret
|
|
1397
1210
|
*/
|
|
1398
1211
|
async function buildImage(imageRef, buildArgs, credentials, { cwd, signal, stdio }) {
|
|
1399
|
-
logger$
|
|
1400
|
-
logger$
|
|
1212
|
+
logger$1.log(`\n🔨 Building Docker image: ${imageRef}`);
|
|
1213
|
+
logger$1.log(" Generating Dockerfile for the pre-built bundle...");
|
|
1401
1214
|
await dockerCommand({
|
|
1402
1215
|
slim: true,
|
|
1403
1216
|
cwd
|
|
@@ -1419,7 +1232,7 @@ async function buildImage(imageRef, buildArgs, credentials, { cwd, signal, stdio
|
|
|
1419
1232
|
...signal ? { signal } : {},
|
|
1420
1233
|
...stdio ? { stdio } : {}
|
|
1421
1234
|
});
|
|
1422
|
-
logger$
|
|
1235
|
+
logger$1.log(`✅ Image built: ${imageRef}`);
|
|
1423
1236
|
} catch (error) {
|
|
1424
1237
|
throw new DockerBuildFailed(imageRef, error);
|
|
1425
1238
|
} finally {
|
|
@@ -1430,14 +1243,14 @@ async function buildImage(imageRef, buildArgs, credentials, { cwd, signal, stdio
|
|
|
1430
1243
|
* Push Docker image to registry
|
|
1431
1244
|
*/
|
|
1432
1245
|
async function pushImage(imageRef, { cwd, signal, stdio }) {
|
|
1433
|
-
logger$
|
|
1246
|
+
logger$1.log(`\n☁️ Pushing image: ${imageRef}`);
|
|
1434
1247
|
try {
|
|
1435
1248
|
await run("docker", ["push", imageRef], {
|
|
1436
1249
|
cwd,
|
|
1437
1250
|
...signal ? { signal } : {},
|
|
1438
1251
|
...stdio ? { stdio } : {}
|
|
1439
1252
|
});
|
|
1440
|
-
logger$
|
|
1253
|
+
logger$1.log(`✅ Image pushed: ${imageRef}`);
|
|
1441
1254
|
} catch (error) {
|
|
1442
1255
|
throw new DockerPushFailed(imageRef, error);
|
|
1443
1256
|
}
|
|
@@ -1487,17 +1300,17 @@ async function deployDocker(options) {
|
|
|
1487
1300
|
await buildImage(imageRef, buildArgs, credentials, docker);
|
|
1488
1301
|
let digest;
|
|
1489
1302
|
if (!skipPush) {
|
|
1490
|
-
if (!config.registry) logger$
|
|
1303
|
+
if (!config.registry) logger$1.warn("\n⚠️ No registry configured. Use --skip-push or configure docker.registry in gkm.config.ts");
|
|
1491
1304
|
else {
|
|
1492
1305
|
await pushImage(imageRef, docker);
|
|
1493
1306
|
digest = await pushedDigest(imageRef, docker);
|
|
1494
1307
|
}
|
|
1495
1308
|
}
|
|
1496
|
-
logger$
|
|
1497
|
-
logger$
|
|
1498
|
-
logger$
|
|
1499
|
-
logger$
|
|
1500
|
-
if (masterKey) logger$
|
|
1309
|
+
logger$1.log("\n✅ Docker deployment ready!");
|
|
1310
|
+
logger$1.log(`\n📋 Deployment details:`);
|
|
1311
|
+
logger$1.log(` Image: ${imageRef}`);
|
|
1312
|
+
logger$1.log(` Stage: ${stage}`);
|
|
1313
|
+
if (masterKey) logger$1.log(`\n🔐 Run the container with GKM_MASTER_KEY set to the key with fingerprint ${keyFingerprint(masterKey)}.`);
|
|
1501
1314
|
return {
|
|
1502
1315
|
imageRef,
|
|
1503
1316
|
...digest ? { digest } : {},
|
|
@@ -1591,57 +1404,6 @@ function validateEnvVars(requiredVars, context) {
|
|
|
1591
1404
|
};
|
|
1592
1405
|
}
|
|
1593
1406
|
//#endregion
|
|
1594
|
-
//#region src/deploy/generated.ts
|
|
1595
|
-
/**
|
|
1596
|
-
* The values a deployed stage generates once and keeps: what nothing can
|
|
1597
|
-
* provision and nobody else issues.
|
|
1598
|
-
*
|
|
1599
|
-
* - **A seed**, which salts every password a deploy derives — a database's
|
|
1600
|
-
* master and roles, a bucket's root user. Derived from repo facts alone
|
|
1601
|
-
* (project, stage, construct id), those passwords were computable by anyone
|
|
1602
|
-
* who could read the repo.
|
|
1603
|
-
* - **Each `secret` construct's value** — an auth server's signing secret —
|
|
1604
|
-
* random, rather than derived.
|
|
1605
|
-
* - **Each `encryption` construct's keyring** — one random key and an index
|
|
1606
|
-
* key. Later keys are added by `gkm encryption:rotate`, never by a deploy.
|
|
1607
|
-
*
|
|
1608
|
-
* Both are generated on the first deploy that needs them and written to the
|
|
1609
|
-
* stage's store, so every later deploy reads the same values: sessions survive
|
|
1610
|
-
* a redeploy, and a role's password does not move. A value set by hand with
|
|
1611
|
-
* `gkm secrets:set` is kept, never replaced.
|
|
1612
|
-
*/
|
|
1613
|
-
/**
|
|
1614
|
-
* The stage's secrets with its seed and every declared `secret`'s value
|
|
1615
|
-
* present, generating what is missing. Pure: the caller writes the result
|
|
1616
|
-
* back to the stage's store when `generated` is not empty.
|
|
1617
|
-
*/
|
|
1618
|
-
function withGeneratedSecrets(secrets, manifest) {
|
|
1619
|
-
const generated = [];
|
|
1620
|
-
const custom = { ...secrets.custom };
|
|
1621
|
-
for (const declaration of Object.values(manifest)) {
|
|
1622
|
-
if (declaration?.kind !== "secret" && declaration?.kind !== "encryption") continue;
|
|
1623
|
-
const key = declaration.provides?.[0];
|
|
1624
|
-
if (!key || custom[key]) continue;
|
|
1625
|
-
custom[key] = declaration.kind === "encryption" ? generateKeyring() : random();
|
|
1626
|
-
generated.push(key);
|
|
1627
|
-
}
|
|
1628
|
-
const seed = secrets.seed ?? random();
|
|
1629
|
-
if (!secrets.seed) generated.push("seed");
|
|
1630
|
-
return {
|
|
1631
|
-
secrets: generated.length ? {
|
|
1632
|
-
...secrets,
|
|
1633
|
-
seed,
|
|
1634
|
-
custom,
|
|
1635
|
-
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1636
|
-
} : secrets,
|
|
1637
|
-
generated
|
|
1638
|
-
};
|
|
1639
|
-
}
|
|
1640
|
-
/** 256 bits, URL-safe. */
|
|
1641
|
-
function random() {
|
|
1642
|
-
return randomBytes(32).toString("base64url");
|
|
1643
|
-
}
|
|
1644
|
-
//#endregion
|
|
1645
1407
|
//#region src/deploy/journal.ts
|
|
1646
1408
|
var DeployJournal = class DeployJournal {
|
|
1647
1409
|
store;
|
|
@@ -2059,83 +1821,6 @@ function generateSecretsReport(encryptedApps, sniffedApps) {
|
|
|
2059
1821
|
};
|
|
2060
1822
|
}
|
|
2061
1823
|
//#endregion
|
|
2062
|
-
//#region src/deploy/terminal.ts
|
|
2063
|
-
/**
|
|
2064
|
-
* The credentials `gkm deploy` can ask a person for. CLI layer only.
|
|
2065
|
-
*
|
|
2066
|
-
* `deploy()` asks its `CredentialProvider` and stops with `MissingCredential`
|
|
2067
|
-
* when the answer is nothing. At a terminal, `gkm deploy` would rather ask:
|
|
2068
|
-
* this provider reads the environment and the stored login first, and only
|
|
2069
|
-
* when both are empty prompts — and stores a Dokploy login it validated, so
|
|
2070
|
-
* the next deploy does not ask again. With no terminal it answers nothing, and
|
|
2071
|
-
* the deploy says what was missing instead of waiting on a prompt nobody sees.
|
|
2072
|
-
*/
|
|
2073
|
-
const logger$1 = output;
|
|
2074
|
-
/** What answers a deploy prompt without a terminal. */
|
|
2075
|
-
const INSTEAD = "Please configure manually.";
|
|
2076
|
-
/** The Dokploy URL typed at the prompt is not a URL. */
|
|
2077
|
-
var DokployEndpointInvalid = class extends Error {
|
|
2078
|
-
endpoint;
|
|
2079
|
-
constructor(endpoint) {
|
|
2080
|
-
super("Invalid URL format");
|
|
2081
|
-
this.endpoint = endpoint;
|
|
2082
|
-
this.name = "DokployEndpointInvalid";
|
|
2083
|
-
}
|
|
2084
|
-
};
|
|
2085
|
-
/** Dokploy refused the token typed at the prompt; nothing was stored. */
|
|
2086
|
-
var DokployTokenRejected = class extends Error {
|
|
2087
|
-
endpoint;
|
|
2088
|
-
constructor(endpoint) {
|
|
2089
|
-
super("Invalid credentials. Please check your token.");
|
|
2090
|
-
this.endpoint = endpoint;
|
|
2091
|
-
this.name = "DokployTokenRejected";
|
|
2092
|
-
}
|
|
2093
|
-
};
|
|
2094
|
-
/** Asks the person at the terminal for what nothing else supplied. */
|
|
2095
|
-
function asking() {
|
|
2096
|
-
return { async get(asked) {
|
|
2097
|
-
if (!canPrompt()) return void 0;
|
|
2098
|
-
const request = asked;
|
|
2099
|
-
if (request.kind === "dokploy") {
|
|
2100
|
-
logger$1.log("\n📋 Dokploy credentials not found. Let's set them up.");
|
|
2101
|
-
const endpoint = (await prompt("Dokploy URL (e.g., https://dokploy.example.com): ", { instead: INSTEAD })).replace(/\/$/, "");
|
|
2102
|
-
try {
|
|
2103
|
-
new URL(endpoint);
|
|
2104
|
-
} catch {
|
|
2105
|
-
throw new DokployEndpointInvalid(endpoint);
|
|
2106
|
-
}
|
|
2107
|
-
logger$1.log(`\nGenerate a token at: ${endpoint}/settings/profile\n`);
|
|
2108
|
-
const token = await prompt("API Token: ", {
|
|
2109
|
-
hidden: true,
|
|
2110
|
-
instead: INSTEAD
|
|
2111
|
-
});
|
|
2112
|
-
logger$1.log("\nValidating credentials...");
|
|
2113
|
-
if (!await validateDokployToken(endpoint, token)) throw new DokployTokenRejected(endpoint);
|
|
2114
|
-
await storeDokployCredentials(token, endpoint);
|
|
2115
|
-
logger$1.log("✓ Credentials saved");
|
|
2116
|
-
return {
|
|
2117
|
-
endpoint,
|
|
2118
|
-
token
|
|
2119
|
-
};
|
|
2120
|
-
}
|
|
2121
|
-
logger$1.log(` Dokploy has no registry for ${request.url}. Let's create one.`);
|
|
2122
|
-
return {
|
|
2123
|
-
username: await prompt("Registry username: ", { instead: INSTEAD }),
|
|
2124
|
-
password: await prompt("Registry password/token: ", {
|
|
2125
|
-
hidden: true,
|
|
2126
|
-
instead: INSTEAD
|
|
2127
|
-
})
|
|
2128
|
-
};
|
|
2129
|
-
} };
|
|
2130
|
-
}
|
|
2131
|
-
/**
|
|
2132
|
-
* The environment, then the stored login, then — at a terminal — the person
|
|
2133
|
-
* running the command.
|
|
2134
|
-
*/
|
|
2135
|
-
function terminalCredentials(base = storedCredentials()) {
|
|
2136
|
-
return chainCredentials(base, asking());
|
|
2137
|
-
}
|
|
2138
|
-
//#endregion
|
|
2139
1824
|
//#region src/deploy/index.ts
|
|
2140
1825
|
/**
|
|
2141
1826
|
* Deploy Module
|
|
@@ -2336,22 +2021,6 @@ function getServerHostname(endpoint) {
|
|
|
2336
2021
|
return new URL(endpoint).hostname;
|
|
2337
2022
|
}
|
|
2338
2023
|
/**
|
|
2339
|
-
* Generate image tag from stage and timestamp
|
|
2340
|
-
*/
|
|
2341
|
-
function generateTag(stage) {
|
|
2342
|
-
return `${stage}-${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").slice(0, 19)}`;
|
|
2343
|
-
}
|
|
2344
|
-
/**
|
|
2345
|
-
* The things this deploy creates a container for.
|
|
2346
|
-
*
|
|
2347
|
-
* A deploy unit is a *declaration*, not a config entry — and since that is now
|
|
2348
|
-
* true of every app, not just the ones being deployed, this is the workspace's
|
|
2349
|
-
* own derivation under the name the deploy phases call it by.
|
|
2350
|
-
*/
|
|
2351
|
-
function deployUnits(manifest, workspace) {
|
|
2352
|
-
return derivedApps(manifest, workspace);
|
|
2353
|
-
}
|
|
2354
|
-
/**
|
|
2355
2024
|
* The variables an app cannot start without.
|
|
2356
2025
|
*
|
|
2357
2026
|
* The sniffer reports every key it saw in `requiredEnvVars` and says which of
|
|
@@ -2369,26 +2038,6 @@ function requiredOf(requirements) {
|
|
|
2369
2038
|
const optional = new Set(requirements.optionalEnvVars);
|
|
2370
2039
|
return requirements.requiredEnvVars.map((name) => name.endsWith("?") ? name.slice(0, -1) : name).filter((name) => !optional.has(name));
|
|
2371
2040
|
}
|
|
2372
|
-
/** Apps were asked for by name that the workspace does not have. */
|
|
2373
|
-
var UnknownDeployApps = class extends Error {
|
|
2374
|
-
apps;
|
|
2375
|
-
available;
|
|
2376
|
-
constructor(apps, available) {
|
|
2377
|
-
super(`Unknown apps: ${apps.join(", ")}\nAvailable apps: ${available.join(", ")}`);
|
|
2378
|
-
this.apps = apps;
|
|
2379
|
-
this.available = available;
|
|
2380
|
-
this.name = "UnknownDeployApps";
|
|
2381
|
-
}
|
|
2382
|
-
};
|
|
2383
|
-
/** Every app asked for deploys somewhere other than Dokploy. */
|
|
2384
|
-
var NoDeployableApps = class extends Error {
|
|
2385
|
-
stage;
|
|
2386
|
-
constructor(stage) {
|
|
2387
|
-
super("No apps to deploy. All selected apps have unsupported deploy targets.");
|
|
2388
|
-
this.stage = stage;
|
|
2389
|
-
this.name = "NoDeployableApps";
|
|
2390
|
-
}
|
|
2391
|
-
};
|
|
2392
2041
|
/** A backend failed, so the run stopped before deploying anything after it. */
|
|
2393
2042
|
var BackendDeployFailed = class extends Error {
|
|
2394
2043
|
app;
|
|
@@ -2411,23 +2060,24 @@ var MissingEnvVars = class extends Error {
|
|
|
2411
2060
|
this.name = "MissingEnvVars";
|
|
2412
2061
|
}
|
|
2413
2062
|
};
|
|
2414
|
-
/** Workspace deploys go to Dokploy; another provider was asked for. */
|
|
2415
|
-
var DeployProviderUnsupported = class extends Error {
|
|
2416
|
-
provider;
|
|
2417
|
-
constructor(provider) {
|
|
2418
|
-
super(`Workspace deployment only supports Dokploy. Got: ${provider}`);
|
|
2419
|
-
this.provider = provider;
|
|
2420
|
-
this.name = "DeployProviderUnsupported";
|
|
2421
|
-
}
|
|
2422
|
-
};
|
|
2423
2063
|
/** How `resolveProject` found a project, in the journal's words. */
|
|
2424
2064
|
const PROJECT_VIA = {
|
|
2425
2065
|
state: "recorded",
|
|
2426
2066
|
marker: "found",
|
|
2427
2067
|
created: "created"
|
|
2428
2068
|
};
|
|
2069
|
+
/** `childOutput` as `spawn` reads it, where it is not the default. */
|
|
2070
|
+
const CHILD_STDIO = {
|
|
2071
|
+
stderr: [
|
|
2072
|
+
"ignore",
|
|
2073
|
+
2,
|
|
2074
|
+
2
|
|
2075
|
+
],
|
|
2076
|
+
ignore: "ignore"
|
|
2077
|
+
};
|
|
2429
2078
|
/**
|
|
2430
|
-
* Deploy every app in a workspace to Dokploy
|
|
2079
|
+
* Deploy every app in a workspace to Dokploy: the engine under the built-in
|
|
2080
|
+
* `dokploy` target.
|
|
2431
2081
|
*
|
|
2432
2082
|
* Two-phase orchestration:
|
|
2433
2083
|
* - PHASE 1: Deploy backend apps (with encrypted secrets)
|
|
@@ -2438,119 +2088,60 @@ const PROJECT_VIA = {
|
|
|
2438
2088
|
* - Only GKM_MASTER_KEY is injected as Dokploy env var
|
|
2439
2089
|
* - Frontend apps get public URLs baked in at build time (no secrets)
|
|
2440
2090
|
*
|
|
2441
|
-
* The
|
|
2442
|
-
*
|
|
2443
|
-
* `ctx.emit` and to `output`, and every failure is thrown.
|
|
2091
|
+
* The run around it — the target, the apps, the lock, the phase events — is
|
|
2092
|
+
* `runDeploy`'s. This says what it is doing and checks what Dokploy needs.
|
|
2444
2093
|
*
|
|
2445
2094
|
* @internal
|
|
2446
2095
|
*/
|
|
2447
|
-
async function
|
|
2448
|
-
const { stage,
|
|
2449
|
-
ctx
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
cwd: configured.root
|
|
2457
|
-
});
|
|
2458
|
-
const units = deployUnits(manifest, configured);
|
|
2459
|
-
const workspace = Object.keys(units).length > 0 ? {
|
|
2460
|
-
...configured,
|
|
2461
|
-
apps: units
|
|
2462
|
-
} : configured;
|
|
2463
|
-
const identity = deployIdentity(workspace, stage);
|
|
2096
|
+
async function validateDokploy(phase) {
|
|
2097
|
+
const { workspace, stage, identity, tag: imageTag } = phase;
|
|
2098
|
+
const ctx = {
|
|
2099
|
+
emit: phase.emit,
|
|
2100
|
+
credentials: phase.credentials,
|
|
2101
|
+
signal: phase.signal,
|
|
2102
|
+
dryRun: phase.dryRun,
|
|
2103
|
+
...phase.childOutput !== "inherit" ? { stdio: CHILD_STDIO[phase.childOutput] } : {}
|
|
2104
|
+
};
|
|
2464
2105
|
logger.log(`\n🚀 Deploying workspace "${workspace.name}" to Dokploy...`);
|
|
2465
2106
|
logger.log(` Stage: ${stage}`);
|
|
2466
|
-
const imageTag = tag ?? generateTag(stage);
|
|
2467
2107
|
logger.log(` Tag: ${imageTag}`);
|
|
2468
|
-
const
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
logger.log(` Deploying apps: ${appsToDeployNames.join(", ")}`);
|
|
2475
|
-
} else logger.log(` Deploying all apps: ${appsToDeployNames.join(", ")}`);
|
|
2476
|
-
const skipped = [];
|
|
2477
|
-
const skip = (app, reason) => {
|
|
2478
|
-
skipped.push({
|
|
2479
|
-
app,
|
|
2480
|
-
reason
|
|
2481
|
-
});
|
|
2482
|
-
ctx.emit({
|
|
2483
|
-
type: "app.skipped",
|
|
2484
|
-
app,
|
|
2485
|
-
reason
|
|
2486
|
-
});
|
|
2487
|
-
};
|
|
2488
|
-
const dokployApps = appsToDeployNames.filter((name) => {
|
|
2489
|
-
const target = workspace.apps[name].resolvedDeployTarget;
|
|
2490
|
-
if (target === "sst") {
|
|
2491
|
-
const reason = `it deploys with SST — run \`gkm build && sst deploy --stage ${stage}\``;
|
|
2492
|
-
logger.log(` ⚠️ Skipping ${name}: ${reason}`);
|
|
2493
|
-
skip(name, reason);
|
|
2494
|
-
return false;
|
|
2495
|
-
}
|
|
2496
|
-
if (!isDeployTargetSupported(target)) {
|
|
2497
|
-
const reason = getDeployTargetError(target, name);
|
|
2498
|
-
logger.log(` ⚠️ Skipping ${name}: ${reason}`);
|
|
2499
|
-
skip(name, reason);
|
|
2500
|
-
return false;
|
|
2501
|
-
}
|
|
2502
|
-
return true;
|
|
2503
|
-
});
|
|
2504
|
-
if (dokployApps.length === 0) throw new NoDeployableApps(stage);
|
|
2505
|
-
appsToDeployNames = dokployApps;
|
|
2506
|
-
for (const name of appsToDeployNames) if (workspace.apps[name].type === "mobile") skip(name, MOBILE_SKIP_REASON);
|
|
2507
|
-
ctx.emit({
|
|
2508
|
-
type: "deploy.started",
|
|
2509
|
-
stage,
|
|
2510
|
-
identity: identity.key,
|
|
2511
|
-
tag: imageTag,
|
|
2512
|
-
apps: appsToDeployNames.filter((name) => workspace.apps[name].type !== "mobile"),
|
|
2513
|
-
dryRun: ctx.dryRun
|
|
2514
|
-
});
|
|
2515
|
-
const store = await createStateStore({
|
|
2516
|
-
config: workspace.state,
|
|
2517
|
-
workspaceRoot: workspace.root,
|
|
2518
|
-
workspaceName: workspace.name
|
|
2519
|
-
});
|
|
2108
|
+
const askedFor = /* @__PURE__ */ new Set([...phase.apps, ...phase.skipped.map((skipped) => skipped.app)]);
|
|
2109
|
+
const asked = getAppBuildOrder(workspace).filter((name) => askedFor.has(name));
|
|
2110
|
+
logger.log(asked.length === Object.keys(workspace.apps).length ? ` Deploying all apps: ${asked.join(", ")}` : ` Deploying apps: ${asked.join(", ")}`);
|
|
2111
|
+
for (const { app, reason } of phase.skipped) logger.log(` ⚠️ Skipping ${app}: ${reason}`);
|
|
2112
|
+
const appsToDeployNames = [...phase.apps];
|
|
2113
|
+
for (const name of appsToDeployNames) if (workspace.apps[name].type === "mobile") phase.skip(name, MOBILE_SKIP_REASON);
|
|
2520
2114
|
const run = {
|
|
2521
2115
|
workspace,
|
|
2522
|
-
manifest,
|
|
2116
|
+
manifest: phase.manifest,
|
|
2523
2117
|
stage,
|
|
2524
2118
|
imageTag,
|
|
2525
2119
|
appsToDeployNames,
|
|
2526
2120
|
identity,
|
|
2527
|
-
store,
|
|
2528
|
-
skipped,
|
|
2121
|
+
store: phase.state,
|
|
2122
|
+
skipped: phase.skipped,
|
|
2123
|
+
secrets: phase.secrets,
|
|
2529
2124
|
ctx
|
|
2530
2125
|
};
|
|
2531
|
-
|
|
2532
|
-
|
|
2533
|
-
|
|
2534
|
-
|
|
2535
|
-
} finally {
|
|
2536
|
-
await lock.release();
|
|
2537
|
-
}
|
|
2126
|
+
return {
|
|
2127
|
+
...run,
|
|
2128
|
+
preflight: await preflight(run)
|
|
2129
|
+
};
|
|
2538
2130
|
}
|
|
2539
2131
|
/**
|
|
2540
2132
|
* The stage's secrets and every app's environment requirements. A dry run
|
|
2541
2133
|
* reads the secrets and generates nothing into the store.
|
|
2542
2134
|
*/
|
|
2543
|
-
async function preflight({ workspace, manifest, stage, ctx }) {
|
|
2135
|
+
async function preflight({ workspace, manifest, stage, secrets: secretsStore, ctx }) {
|
|
2544
2136
|
logger.log("\n🔐 Loading secrets and analyzing environment requirements...");
|
|
2545
|
-
const
|
|
2546
|
-
const stored = await secretsStore.read(stage);
|
|
2137
|
+
const stored = await secretsStore.read();
|
|
2547
2138
|
if (!stored) logger.log(` ⚠️ No secrets found for stage "${stage}"; starting them`);
|
|
2548
2139
|
const { secrets: stageSecrets, generated } = withGeneratedSecrets(stored ?? initStageSecrets(stage), manifest);
|
|
2549
2140
|
if (generated.length > 0) {
|
|
2550
|
-
if (ctx.dryRun) logger.log(` 🔑 Would generate for "${stage}" (${secretsStore.
|
|
2141
|
+
if (ctx.dryRun) logger.log(` 🔑 Would generate for "${stage}" (${secretsStore.store}): ${generated.join(", ")}`);
|
|
2551
2142
|
else {
|
|
2552
|
-
await secretsStore.write(
|
|
2553
|
-
logger.log(` 🔑 Generated for "${stage}" (${secretsStore.
|
|
2143
|
+
await secretsStore.write(stageSecrets);
|
|
2144
|
+
logger.log(` 🔑 Generated for "${stage}" (${secretsStore.store}): ${generated.join(", ")}`);
|
|
2554
2145
|
}
|
|
2555
2146
|
}
|
|
2556
2147
|
const sniffedApps = await sniffAllApps(workspace.apps, workspace.root);
|
|
@@ -2566,14 +2157,14 @@ async function preflight({ workspace, manifest, stage, ctx }) {
|
|
|
2566
2157
|
encryptedSecrets
|
|
2567
2158
|
};
|
|
2568
2159
|
}
|
|
2569
|
-
/**
|
|
2570
|
-
|
|
2571
|
-
|
|
2572
|
-
|
|
2573
|
-
|
|
2574
|
-
|
|
2575
|
-
|
|
2576
|
-
}
|
|
2160
|
+
/**
|
|
2161
|
+
* The project, environment and registry, then what the manifest declares.
|
|
2162
|
+
* Each is looked up — by the id the stage's state recorded, else by name —
|
|
2163
|
+
* before it is created, so a run stopped part way is finished by the next.
|
|
2164
|
+
*/
|
|
2165
|
+
async function provisionDokploy(run) {
|
|
2166
|
+
const { workspace, manifest, stage, appsToDeployNames, identity, store, ctx } = run;
|
|
2167
|
+
const { stageSecrets } = run.preflight;
|
|
2577
2168
|
const changes = [];
|
|
2578
2169
|
const applied = (change, via) => {
|
|
2579
2170
|
changes.push(change);
|
|
@@ -2583,11 +2174,6 @@ async function deployLocked(run) {
|
|
|
2583
2174
|
via
|
|
2584
2175
|
});
|
|
2585
2176
|
};
|
|
2586
|
-
ctx.signal?.throwIfAborted();
|
|
2587
|
-
ctx.emit({
|
|
2588
|
-
type: "phase.started",
|
|
2589
|
-
phase: "provision"
|
|
2590
|
-
});
|
|
2591
2177
|
const { api, endpoint } = await dokployApi(workspace, ctx);
|
|
2592
2178
|
logger.log("\n📋 Loading deploy state...");
|
|
2593
2179
|
const journal = await DeployJournal.open(store, stage, () => createEmptyState(stage, "", ""));
|
|
@@ -2730,7 +2316,7 @@ async function deployLocked(run) {
|
|
|
2730
2316
|
const backupSchedule = workspace.deploy.backups.schedule ?? "0 2 * * *";
|
|
2731
2317
|
const backupRetention = workspace.deploy.backups.retention ?? 30;
|
|
2732
2318
|
logger.log(" Creating postgres backup schedule...");
|
|
2733
|
-
|
|
2319
|
+
const backup = await api.createPostgresBackup({
|
|
2734
2320
|
schedule: backupSchedule,
|
|
2735
2321
|
prefix: `${stage}/postgres`,
|
|
2736
2322
|
destinationId: backupState.destinationId,
|
|
@@ -2738,14 +2324,39 @@ async function deployLocked(run) {
|
|
|
2738
2324
|
postgresId: backupCluster.postgresId,
|
|
2739
2325
|
enabled: true,
|
|
2740
2326
|
keepLatestCount: backupRetention
|
|
2741
|
-
})
|
|
2327
|
+
});
|
|
2328
|
+
setPostgresBackupId(state, backup.backupId);
|
|
2742
2329
|
logger.log(` ✓ Postgres backup schedule created (${backupSchedule})`);
|
|
2743
2330
|
} else logger.log(" ✓ Using existing postgres backup schedule");
|
|
2744
2331
|
}
|
|
2745
|
-
|
|
2746
|
-
|
|
2747
|
-
|
|
2748
|
-
|
|
2332
|
+
run.provisioned = {
|
|
2333
|
+
api,
|
|
2334
|
+
endpoint,
|
|
2335
|
+
journal,
|
|
2336
|
+
state,
|
|
2337
|
+
projectId: project.projectId,
|
|
2338
|
+
environmentId,
|
|
2339
|
+
registry,
|
|
2340
|
+
registryId,
|
|
2341
|
+
declaredEnv,
|
|
2342
|
+
changes,
|
|
2343
|
+
applied
|
|
2344
|
+
};
|
|
2345
|
+
}
|
|
2346
|
+
/**
|
|
2347
|
+
* Each app's image built and pushed, its application configured and
|
|
2348
|
+
* deployed, and its domain attached: backends first, each failure stopping
|
|
2349
|
+
* the run; then sites, whose build args are the backends' public URLs.
|
|
2350
|
+
*
|
|
2351
|
+
* Building is here rather than in a `build` phase of its own because an
|
|
2352
|
+
* image is built beside its application — a site's build args are resolved
|
|
2353
|
+
* per app, against the backends released before it.
|
|
2354
|
+
*/
|
|
2355
|
+
async function releaseDokploy(run) {
|
|
2356
|
+
const { workspace, stage, imageTag, appsToDeployNames, identity, ctx } = run;
|
|
2357
|
+
const { stageSecrets, sniffedApps, encryptedSecrets } = run.preflight;
|
|
2358
|
+
const { api, journal, state, environmentId, registry, registryId, declaredEnv, changes, applied } = run.provisioned;
|
|
2359
|
+
const project = { projectId: run.provisioned.projectId };
|
|
2749
2360
|
const backendApps = appsToDeployNames.filter((name) => workspace.apps[name].type === "backend");
|
|
2750
2361
|
const frontendApps = appsToDeployNames.filter((name) => workspace.apps[name].type === "web");
|
|
2751
2362
|
const publicUrls = {};
|
|
@@ -2806,11 +2417,6 @@ async function deployLocked(run) {
|
|
|
2806
2417
|
};
|
|
2807
2418
|
const frontendUrls = [];
|
|
2808
2419
|
for (const appName of frontendApps) frontendUrls.push(`https://${hostOf(workspace, appName, stage)}`);
|
|
2809
|
-
ctx.signal?.throwIfAborted();
|
|
2810
|
-
ctx.emit({
|
|
2811
|
-
type: "phase.started",
|
|
2812
|
-
phase: "release"
|
|
2813
|
-
});
|
|
2814
2420
|
if (backendApps.length > 0) {
|
|
2815
2421
|
logger.log("\n📦 PHASE 1: Deploying backend applications...");
|
|
2816
2422
|
for (const appName of backendApps) {
|
|
@@ -2976,15 +2582,17 @@ async function deployLocked(run) {
|
|
|
2976
2582
|
logger.log("\n📋 Saving deploy state...");
|
|
2977
2583
|
await journal.save();
|
|
2978
2584
|
logger.log(" ✓ State saved");
|
|
2979
|
-
|
|
2980
|
-
|
|
2981
|
-
|
|
2982
|
-
|
|
2983
|
-
|
|
2984
|
-
|
|
2985
|
-
|
|
2986
|
-
|
|
2987
|
-
}
|
|
2585
|
+
run.released = {
|
|
2586
|
+
results,
|
|
2587
|
+
publicUrls,
|
|
2588
|
+
appHostnames
|
|
2589
|
+
};
|
|
2590
|
+
}
|
|
2591
|
+
/** DNS records for each released app, and Dokploy's validation of each domain. */
|
|
2592
|
+
async function verifyDokploy(run) {
|
|
2593
|
+
const { workspace } = run;
|
|
2594
|
+
const { api, endpoint, journal, state } = run.provisioned;
|
|
2595
|
+
const { appHostnames } = run.released;
|
|
2988
2596
|
const dnsConfig = workspace.deploy.dns;
|
|
2989
2597
|
if (dnsConfig && appHostnames.size > 0) {
|
|
2990
2598
|
const dnsResult = await orchestrateDns(appHostnames, dnsConfig, endpoint);
|
|
@@ -3004,10 +2612,14 @@ async function deployLocked(run) {
|
|
|
3004
2612
|
}
|
|
3005
2613
|
}
|
|
3006
2614
|
}
|
|
3007
|
-
|
|
3008
|
-
|
|
3009
|
-
|
|
3010
|
-
|
|
2615
|
+
}
|
|
2616
|
+
/** What the run did, printed as the summary it always ended with. */
|
|
2617
|
+
function dokployResult(run) {
|
|
2618
|
+
if (run.result) return run.result;
|
|
2619
|
+
const { stage, identity, imageTag } = run;
|
|
2620
|
+
const { projectId, environmentId, changes } = run.provisioned;
|
|
2621
|
+
const { results, publicUrls } = run.released;
|
|
2622
|
+
const project = { projectId };
|
|
3011
2623
|
const successCount = results.filter((r) => r.success).length;
|
|
3012
2624
|
const failedCount = results.filter((r) => !r.success).length;
|
|
3013
2625
|
logger.log(`\n${"─".repeat(50)}`);
|
|
@@ -3029,7 +2641,7 @@ async function deployLocked(run) {
|
|
|
3029
2641
|
identity: identity.key,
|
|
3030
2642
|
tag: imageTag,
|
|
3031
2643
|
dryRun: false,
|
|
3032
|
-
skipped: run.skipped,
|
|
2644
|
+
skipped: [...run.skipped],
|
|
3033
2645
|
urls: publicUrls,
|
|
3034
2646
|
changes
|
|
3035
2647
|
};
|
|
@@ -3150,19 +2762,9 @@ function hostOf(workspace, appName, stage) {
|
|
|
3150
2762
|
* else: no lock, no state written, no secret generated, no Dokploy resource
|
|
3151
2763
|
* created or changed, no image built or pushed.
|
|
3152
2764
|
*/
|
|
3153
|
-
async function
|
|
2765
|
+
async function planDokploy(run) {
|
|
3154
2766
|
const { workspace, manifest, stage, imageTag, appsToDeployNames, identity } = run;
|
|
3155
2767
|
const { ctx } = run;
|
|
3156
|
-
await preflight(run);
|
|
3157
|
-
ctx.emit({
|
|
3158
|
-
type: "phase.finished",
|
|
3159
|
-
phase: "validate"
|
|
3160
|
-
});
|
|
3161
|
-
ctx.signal?.throwIfAborted();
|
|
3162
|
-
ctx.emit({
|
|
3163
|
-
type: "phase.started",
|
|
3164
|
-
phase: "plan"
|
|
3165
|
-
});
|
|
3166
2768
|
logger.log("\n🔎 Dry run: nothing will be created, changed, built or pushed.");
|
|
3167
2769
|
const changes = [];
|
|
3168
2770
|
const plan = (change, detail) => {
|
|
@@ -3277,11 +2879,7 @@ async function planDeploy(run) {
|
|
|
3277
2879
|
}
|
|
3278
2880
|
const creates = changes.filter((c) => c.action !== "reuse").length;
|
|
3279
2881
|
logger.log(`\n✅ Dry run complete: ${creates} to create or build, ${changes.length - creates} to reuse.`);
|
|
3280
|
-
|
|
3281
|
-
type: "phase.finished",
|
|
3282
|
-
phase: "plan"
|
|
3283
|
-
});
|
|
3284
|
-
return {
|
|
2882
|
+
run.result = {
|
|
3285
2883
|
apps,
|
|
3286
2884
|
projectId: project?.projectId ?? "",
|
|
3287
2885
|
environmentId: environment?.environmentId ?? "",
|
|
@@ -3291,7 +2889,7 @@ async function planDeploy(run) {
|
|
|
3291
2889
|
identity: identity.key,
|
|
3292
2890
|
tag: imageTag,
|
|
3293
2891
|
dryRun: true,
|
|
3294
|
-
skipped: run.skipped,
|
|
2892
|
+
skipped: [...run.skipped],
|
|
3295
2893
|
urls,
|
|
3296
2894
|
changes
|
|
3297
2895
|
};
|
|
@@ -3299,131 +2897,6 @@ async function planDeploy(run) {
|
|
|
3299
2897
|
/** Why a mobile app is left out of a Dokploy deploy. */
|
|
3300
2898
|
const MOBILE_SKIP_REASON = "deploys via its framework toolchain";
|
|
3301
2899
|
//#endregion
|
|
3302
|
-
|
|
3303
|
-
/**
|
|
3304
|
-
* `deploy()`: a deploy as a library call.
|
|
3305
|
-
*
|
|
3306
|
-
* `gkm deploy` could only be driven from an interactive terminal: it prompted
|
|
3307
|
-
* for what it lacked and exited the process on failure, worked out of
|
|
3308
|
-
* `process.cwd()`, and reported progress by printing. Here the caller says
|
|
3309
|
-
* where the project is, hands over the credentials and a signal, and gets back
|
|
3310
|
-
* a run — events to iterate while it goes, and a structured result at the end.
|
|
3311
|
-
* Nothing below this asks a person anything or ends the process; `gkm deploy`
|
|
3312
|
-
* is a thin wrapper that does both.
|
|
3313
|
-
*/
|
|
3314
|
-
/**
|
|
3315
|
-
* Every event a run emits, kept so that each iteration — however late it
|
|
3316
|
-
* starts — sees the run from its first event to its last.
|
|
3317
|
-
*/
|
|
3318
|
-
var EventLog = class {
|
|
3319
|
-
events = [];
|
|
3320
|
-
closed = false;
|
|
3321
|
-
waiting = [];
|
|
3322
|
-
push(event) {
|
|
3323
|
-
this.events.push(event);
|
|
3324
|
-
this.wake();
|
|
3325
|
-
}
|
|
3326
|
-
close() {
|
|
3327
|
-
this.closed = true;
|
|
3328
|
-
this.wake();
|
|
3329
|
-
}
|
|
3330
|
-
wake() {
|
|
3331
|
-
const waiting = this.waiting;
|
|
3332
|
-
this.waiting = [];
|
|
3333
|
-
for (const resume of waiting) resume();
|
|
3334
|
-
}
|
|
3335
|
-
async *iterate() {
|
|
3336
|
-
let next = 0;
|
|
3337
|
-
while (true) if (next < this.events.length) yield this.events[next++];
|
|
3338
|
-
else if (this.closed) return;
|
|
3339
|
-
else await new Promise((resume) => this.waiting.push(resume));
|
|
3340
|
-
}
|
|
3341
|
-
};
|
|
3342
|
-
/** `childOutput` as `spawn` reads it, where it is not the default. */
|
|
3343
|
-
const CHILD_STDIO = {
|
|
3344
|
-
stderr: [
|
|
3345
|
-
"ignore",
|
|
3346
|
-
2,
|
|
3347
|
-
2
|
|
3348
|
-
],
|
|
3349
|
-
ignore: "ignore"
|
|
3350
|
-
};
|
|
3351
|
-
function forward(logger, level, message) {
|
|
3352
|
-
if (!logger) return;
|
|
3353
|
-
if (level === "info") logger.info(message);
|
|
3354
|
-
else if (level === "error" && logger.error) logger.error(message);
|
|
3355
|
-
else logger.warn(message);
|
|
3356
|
-
}
|
|
3357
|
-
/**
|
|
3358
|
-
* Deploy a project's stage.
|
|
3359
|
-
*
|
|
3360
|
-
* ```ts
|
|
3361
|
-
* import { deploy } from '@geekmidas/cli/deploy';
|
|
3362
|
-
*
|
|
3363
|
-
* const run = deploy({ cwd: '/srv/checkouts/shop', stage: 'production' });
|
|
3364
|
-
* for await (const event of run) {
|
|
3365
|
-
* if (event.type === 'app.deployed') console.log(event.app, event.url);
|
|
3366
|
-
* }
|
|
3367
|
-
* const result = await run.result;
|
|
3368
|
-
* ```
|
|
3369
|
-
*
|
|
3370
|
-
* The run starts at once; iterating it is optional, and an iteration started
|
|
3371
|
-
* late still sees every event from the first.
|
|
3372
|
-
*/
|
|
3373
|
-
function deploy(input) {
|
|
3374
|
-
const log = new EventLog();
|
|
3375
|
-
const emit = (event) => {
|
|
3376
|
-
log.push(event);
|
|
3377
|
-
if (event.type === "log") forward(input.logger, event.level, event.message);
|
|
3378
|
-
};
|
|
3379
|
-
const ctx = {
|
|
3380
|
-
emit,
|
|
3381
|
-
credentials: input.credentials ?? storedCredentials({ home: input.home ?? gkmHome() }),
|
|
3382
|
-
dryRun: input.dryRun ?? false,
|
|
3383
|
-
home: input.home ?? gkmHome(),
|
|
3384
|
-
...input.signal ? { signal: input.signal } : {},
|
|
3385
|
-
...input.childOutput && input.childOutput !== "inherit" ? { stdio: CHILD_STDIO[input.childOutput] } : {}
|
|
3386
|
-
};
|
|
3387
|
-
const result = withOutput((level, message) => emit({
|
|
3388
|
-
type: "log",
|
|
3389
|
-
level,
|
|
3390
|
-
message
|
|
3391
|
-
}), async () => {
|
|
3392
|
-
try {
|
|
3393
|
-
input.signal?.throwIfAborted();
|
|
3394
|
-
const deployed = await runDeploy(() => load(input), {
|
|
3395
|
-
stage: input.stage,
|
|
3396
|
-
...input.tag ? { tag: input.tag } : {},
|
|
3397
|
-
...input.apps ? { apps: input.apps } : {}
|
|
3398
|
-
}, ctx);
|
|
3399
|
-
emit({
|
|
3400
|
-
type: "deploy.finished",
|
|
3401
|
-
result: deployed
|
|
3402
|
-
});
|
|
3403
|
-
return deployed;
|
|
3404
|
-
} catch (error) {
|
|
3405
|
-
emit({
|
|
3406
|
-
type: "deploy.failed",
|
|
3407
|
-
error: eventError(error)
|
|
3408
|
-
});
|
|
3409
|
-
throw error;
|
|
3410
|
-
} finally {
|
|
3411
|
-
log.close();
|
|
3412
|
-
}
|
|
3413
|
-
});
|
|
3414
|
-
result.catch(() => {});
|
|
3415
|
-
return {
|
|
3416
|
-
result,
|
|
3417
|
-
[Symbol.asyncIterator]: () => log.iterate()
|
|
3418
|
-
};
|
|
3419
|
-
}
|
|
3420
|
-
/** The workspace at `input.cwd`, refusing a stage it does not deploy. */
|
|
3421
|
-
async function load(input) {
|
|
3422
|
-
const { workspace } = await loadWorkspaceConfig(resolve(input.cwd));
|
|
3423
|
-
assertDeployedStage(workspace.stages, input.stage);
|
|
3424
|
-
return workspace;
|
|
3425
|
-
}
|
|
3426
|
-
//#endregion
|
|
3427
|
-
export { NoDeployableApps as a, RegistryAmbiguous as c, ProjectNotOwned as d, MissingCredential as f, MissingEnvVars as i, RegistryNotConfigured as l, storedCredentials as m, BackendDeployFailed as n, UnknownDeployApps as o, chainCredentials as p, DeployProviderUnsupported as r, terminalCredentials as s, deploy as t, RegistryNotFound as u };
|
|
2900
|
+
export { provisionDokploy as a, verifyDokploy as c, RegistryNotFound as d, ProjectNotOwned as f, planDokploy as i, RegistryAmbiguous as l, MissingEnvVars as n, releaseDokploy as o, dokployResult as r, validateDokploy as s, BackendDeployFailed as t, RegistryNotConfigured as u };
|
|
3428
2901
|
|
|
3429
|
-
//# sourceMappingURL=deploy-
|
|
2902
|
+
//# sourceMappingURL=deploy-B7jvUORo.mjs.map
|