@zitadel/cli 0.1.0-alpha.0 → 0.1.0-alpha.1
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 +131 -12
- package/SKILLS.md +18 -3
- package/dist/commands/apply.mjs +3 -2
- package/dist/commands/apply.mjs.map +1 -1
- package/dist/commands/doctor.mjs +123 -13
- package/dist/commands/doctor.mjs.map +1 -1
- package/dist/commands/eject.mjs +3 -2
- package/dist/commands/eject.mjs.map +1 -1
- package/dist/commands/logs.mjs +50 -0
- package/dist/commands/logs.mjs.map +1 -0
- package/dist/commands/plan.mjs +3 -2
- package/dist/commands/plan.mjs.map +1 -1
- package/dist/commands/reset.mjs +63 -0
- package/dist/commands/reset.mjs.map +1 -0
- package/dist/commands/setup.mjs +5 -3
- package/dist/commands/setup.mjs.map +1 -1
- package/dist/commands/start.mjs +132 -0
- package/dist/commands/start.mjs.map +1 -0
- package/dist/commands/status.mjs +68 -27
- package/dist/commands/status.mjs.map +1 -1
- package/dist/commands/stop.mjs +44 -0
- package/dist/commands/stop.mjs.map +1 -0
- package/dist/docker-C0aVpJqm.mjs +209 -0
- package/dist/docker-C0aVpJqm.mjs.map +1 -0
- package/dist/{project-C3pSfbao.mjs → oclif-DSPO9Sck.mjs} +216 -91
- package/dist/oclif-DSPO9Sck.mjs.map +1 -0
- package/dist/{orca-COsUnVoz.mjs → orca-DOxshV9n.mjs} +6 -3
- package/dist/{orca-COsUnVoz.mjs.map → orca-DOxshV9n.mjs.map} +1 -1
- package/dist/project-Dwb9WVAT.mjs +87 -0
- package/dist/project-Dwb9WVAT.mjs.map +1 -0
- package/dist/{sync-Cuyh-X1J.mjs → sync-DmtTYNmq.mjs} +3 -3
- package/dist/{sync-Cuyh-X1J.mjs.map → sync-DmtTYNmq.mjs.map} +1 -1
- package/oclif.manifest.json +351 -3
- package/package.json +1 -1
- package/dist/project-C3pSfbao.mjs.map +0 -1
package/dist/commands/status.mjs
CHANGED
|
@@ -1,46 +1,87 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { _ as readRuntimeMetadata, b as runtimeSummary, m as localContainerName, t as BaseCommand, u as checkLocalServerHealth } from "../oclif-DSPO9Sck.mjs";
|
|
2
|
+
import { a as readZitadelConfig, n as hasZitadelSecret, o as readZitadelSecret, r as readDevelopmentIssuer, t as hasZitadelConfig } from "../project-Dwb9WVAT.mjs";
|
|
3
|
+
import { s as inspectContainer } from "../docker-C0aVpJqm.mjs";
|
|
2
4
|
//#region src/commands/status.ts
|
|
3
5
|
/**
|
|
4
|
-
* `zitadel status` — summarize the local project state.
|
|
6
|
+
* `zitadel status` — summarize the local server and project state.
|
|
5
7
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* run on partial or broken setups.
|
|
8
|
+
* This is intentionally informational: a missing `zitadel.json`, stopped
|
|
9
|
+
* local server, or orphaned config should be visible without making `status`
|
|
10
|
+
* itself fail.
|
|
10
11
|
*/
|
|
11
12
|
var Status = class Status extends BaseCommand {
|
|
12
|
-
static description = "Summarize the local project state.";
|
|
13
|
+
static description = "Summarize the local Zitadel server and project state.";
|
|
13
14
|
async run() {
|
|
14
15
|
const { flags } = await this.parse(Status);
|
|
15
|
-
await
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
status: "skipped",
|
|
20
|
-
reason: "orphaned-config",
|
|
21
|
-
data: {
|
|
22
|
-
project_id: typeof config.project === "string" ? config.project : void 0,
|
|
23
|
-
lifecycle: "orphaned-config",
|
|
24
|
-
message: "zitadel.json exists but .zitadel/secret is missing."
|
|
25
|
-
},
|
|
26
|
-
nextCommands: ["zitadel setup --force", "zitadel doctor --fix"]
|
|
16
|
+
const runtime = await readRuntimeMetadata(flags.cwd ? String(flags.cwd) : process.cwd());
|
|
17
|
+
if (flags.server === "local") await this.toMeta(flags, {
|
|
18
|
+
resolveServer: false,
|
|
19
|
+
source: runtime?.server_url ?? "http://localhost:8080"
|
|
27
20
|
});
|
|
28
|
-
|
|
21
|
+
else await this.toMeta(flags);
|
|
22
|
+
const { cwd } = this.meta;
|
|
23
|
+
const containerName = runtime?.container_name ?? localContainerName(cwd);
|
|
24
|
+
let docker;
|
|
25
|
+
let dockerError;
|
|
26
|
+
try {
|
|
27
|
+
docker = await inspectContainer(containerName);
|
|
28
|
+
} catch (error) {
|
|
29
|
+
dockerError = error instanceof Error ? error.message : String(error);
|
|
30
|
+
}
|
|
31
|
+
const healthy = runtime ? await checkLocalServerHealth(runtime.server_url) : false;
|
|
32
|
+
const serverLifecycle = runtime ? docker?.running && healthy ? "running" : docker?.exists ? "unhealthy" : "stopped" : "missing";
|
|
33
|
+
const project = await projectStatus(cwd);
|
|
34
|
+
const nextCommands = nextCommandsFor(serverLifecycle, project.lifecycle);
|
|
29
35
|
return this.emit({
|
|
30
36
|
status: "ok",
|
|
31
37
|
data: {
|
|
32
|
-
title: "Zitadel
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
38
|
+
title: "Zitadel status.",
|
|
39
|
+
server: {
|
|
40
|
+
lifecycle: serverLifecycle,
|
|
41
|
+
runtime: runtimeSummary(runtime),
|
|
42
|
+
docker: {
|
|
43
|
+
available: dockerError === void 0,
|
|
44
|
+
error: dockerError,
|
|
45
|
+
container_exists: docker?.exists ?? false,
|
|
46
|
+
container_running: docker?.running ?? false
|
|
47
|
+
},
|
|
48
|
+
health: {
|
|
49
|
+
healthy,
|
|
50
|
+
url: runtime?.server_url
|
|
51
|
+
}
|
|
36
52
|
},
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
next_commands: ["zitadel doctor", "zitadel apply"]
|
|
53
|
+
project,
|
|
54
|
+
next_commands: nextCommands
|
|
40
55
|
}
|
|
41
56
|
});
|
|
42
57
|
}
|
|
43
58
|
};
|
|
59
|
+
async function projectStatus(cwd) {
|
|
60
|
+
if (!await hasZitadelConfig(cwd)) return {
|
|
61
|
+
lifecycle: "not-configured",
|
|
62
|
+
message: "zitadel.json has not been created yet."
|
|
63
|
+
};
|
|
64
|
+
const config = await readZitadelConfig(cwd);
|
|
65
|
+
if (!await hasZitadelSecret(cwd)) return {
|
|
66
|
+
lifecycle: "orphaned-config",
|
|
67
|
+
project_id: typeof config.project === "string" ? config.project : void 0,
|
|
68
|
+
message: "zitadel.json exists but .zitadel/secret is missing."
|
|
69
|
+
};
|
|
70
|
+
const secret = await readZitadelSecret(cwd);
|
|
71
|
+
return {
|
|
72
|
+
lifecycle: "configured",
|
|
73
|
+
project_id: String(config.project ?? secret.project_id ?? ""),
|
|
74
|
+
issuer: readDevelopmentIssuer(config)
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
function nextCommandsFor(serverLifecycle, projectLifecycle) {
|
|
78
|
+
const commands = [];
|
|
79
|
+
if (serverLifecycle !== "running") commands.push("zitadel start");
|
|
80
|
+
if (projectLifecycle === "not-configured") commands.push("zitadel setup --framework next --server local");
|
|
81
|
+
else if (projectLifecycle === "orphaned-config") commands.push("zitadel setup --force", "zitadel doctor --fix");
|
|
82
|
+
else commands.push("zitadel doctor", "zitadel apply");
|
|
83
|
+
return commands;
|
|
84
|
+
}
|
|
44
85
|
//#endregion
|
|
45
86
|
export { Status as default };
|
|
46
87
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"status.mjs","names":[],"sources":["../../src/commands/status.ts"],"sourcesContent":["import { BaseCommand, type JsonEnvelope } from \"../lib/oclif\";\nimport {\n hasZitadelSecret,\n readDevelopmentIssuer,\n readZitadelConfig,\n readZitadelSecret,\n} from \"../lib/project\";\n\n/**\n * `zitadel status` — summarize the local project state.\n *\n *
|
|
1
|
+
{"version":3,"file":"status.mjs","names":[],"sources":["../../src/commands/status.ts"],"sourcesContent":["import { BaseCommand, type JsonEnvelope } from \"../lib/oclif\";\nimport { inspectContainer } from \"../lib/local-server/docker\";\nimport {\n DEFAULT_LOCAL_SERVER_URL,\n checkLocalServerHealth,\n localContainerName,\n readRuntimeMetadata,\n runtimeSummary,\n} from \"../lib/local-server/runtime\";\nimport {\n hasZitadelConfig,\n hasZitadelSecret,\n readDevelopmentIssuer,\n readZitadelConfig,\n readZitadelSecret,\n} from \"../lib/project\";\n\n/**\n * `zitadel status` — summarize the local server and project state.\n *\n * This is intentionally informational: a missing `zitadel.json`, stopped\n * local server, or orphaned config should be visible without making `status`\n * itself fail.\n */\nexport default class Status extends BaseCommand {\n static override description = \"Summarize the local Zitadel server and project state.\";\n\n async run(): Promise<JsonEnvelope> {\n const { flags } = await this.parse(Status);\n const runtime = await readRuntimeMetadata(flags.cwd ? String(flags.cwd) : process.cwd());\n if (flags.server === \"local\") {\n await this.toMeta(flags, {\n resolveServer: false,\n source: runtime?.server_url ?? DEFAULT_LOCAL_SERVER_URL,\n });\n } else {\n await this.toMeta(flags);\n }\n const { cwd } = this.meta;\n\n const containerName = runtime?.container_name ?? localContainerName(cwd);\n let docker: Awaited<ReturnType<typeof inspectContainer>> | undefined;\n let dockerError: string | undefined;\n try {\n docker = await inspectContainer(containerName);\n } catch (error) {\n dockerError = error instanceof Error ? error.message : String(error);\n }\n const healthy = runtime ? await checkLocalServerHealth(runtime.server_url) : false;\n const serverLifecycle = runtime\n ? docker?.running && healthy\n ? \"running\"\n : docker?.exists\n ? \"unhealthy\"\n : \"stopped\"\n : \"missing\";\n\n const project = await projectStatus(cwd);\n const nextCommands = nextCommandsFor(serverLifecycle, project.lifecycle);\n\n return this.emit({\n status: \"ok\",\n data: {\n title: \"Zitadel status.\",\n server: {\n lifecycle: serverLifecycle,\n runtime: runtimeSummary(runtime),\n docker: {\n available: dockerError === undefined,\n error: dockerError,\n container_exists: docker?.exists ?? false,\n container_running: docker?.running ?? false,\n },\n health: {\n healthy,\n url: runtime?.server_url,\n },\n },\n project,\n next_commands: nextCommands,\n },\n });\n }\n}\n\ntype ProjectStatus =\n | {\n lifecycle: \"not-configured\";\n message: string;\n }\n | {\n lifecycle: \"orphaned-config\";\n project_id?: string;\n message: string;\n }\n | {\n lifecycle: \"configured\";\n project_id: string;\n issuer?: string;\n };\n\nasync function projectStatus(cwd: string): Promise<ProjectStatus> {\n if (!(await hasZitadelConfig(cwd))) {\n return {\n lifecycle: \"not-configured\",\n message: \"zitadel.json has not been created yet.\",\n };\n }\n\n const config = await readZitadelConfig(cwd);\n if (!(await hasZitadelSecret(cwd))) {\n return {\n lifecycle: \"orphaned-config\",\n project_id: typeof config.project === \"string\" ? config.project : undefined,\n message: \"zitadel.json exists but .zitadel/secret is missing.\",\n };\n }\n\n const secret = await readZitadelSecret(cwd);\n return {\n lifecycle: \"configured\",\n project_id: String(config.project ?? secret.project_id ?? \"\"),\n issuer: readDevelopmentIssuer(config),\n };\n}\n\nfunction nextCommandsFor(serverLifecycle: string, projectLifecycle: ProjectStatus[\"lifecycle\"]): string[] {\n const commands: string[] = [];\n if (serverLifecycle !== \"running\") {\n commands.push(\"zitadel start\");\n }\n if (projectLifecycle === \"not-configured\") {\n commands.push(\"zitadel setup --framework next --server local\");\n } else if (projectLifecycle === \"orphaned-config\") {\n commands.push(\"zitadel setup --force\", \"zitadel doctor --fix\");\n } else {\n commands.push(\"zitadel doctor\", \"zitadel apply\");\n }\n return commands;\n}\n"],"mappings":";;;;;;;;;;;AAwBA,IAAqB,SAArB,MAAqB,eAAe,YAAY;CAC9C,OAAgB,cAAc;CAE9B,MAAM,MAA6B;EACjC,MAAM,EAAE,UAAU,MAAM,KAAK,MAAM,OAAO;EAC1C,MAAM,UAAU,MAAM,oBAAoB,MAAM,MAAM,OAAO,MAAM,IAAI,GAAG,QAAQ,KAAK,CAAC;AACxF,MAAI,MAAM,WAAW,QACnB,OAAM,KAAK,OAAO,OAAO;GACvB,eAAe;GACf,QAAQ,SAAS,cAAA;GAClB,CAAC;MAEF,OAAM,KAAK,OAAO,MAAM;EAE1B,MAAM,EAAE,QAAQ,KAAK;EAErB,MAAM,gBAAgB,SAAS,kBAAkB,mBAAmB,IAAI;EACxE,IAAI;EACJ,IAAI;AACJ,MAAI;AACF,YAAS,MAAM,iBAAiB,cAAc;WACvC,OAAO;AACd,iBAAc,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;;EAEtE,MAAM,UAAU,UAAU,MAAM,uBAAuB,QAAQ,WAAW,GAAG;EAC7E,MAAM,kBAAkB,UACpB,QAAQ,WAAW,UACjB,YACA,QAAQ,SACN,cACA,YACJ;EAEJ,MAAM,UAAU,MAAM,cAAc,IAAI;EACxC,MAAM,eAAe,gBAAgB,iBAAiB,QAAQ,UAAU;AAExE,SAAO,KAAK,KAAK;GACf,QAAQ;GACR,MAAM;IACJ,OAAO;IACP,QAAQ;KACN,WAAW;KACX,SAAS,eAAe,QAAQ;KAChC,QAAQ;MACN,WAAW,gBAAgB,KAAA;MAC3B,OAAO;MACP,kBAAkB,QAAQ,UAAU;MACpC,mBAAmB,QAAQ,WAAW;MACvC;KACD,QAAQ;MACN;MACA,KAAK,SAAS;MACf;KACF;IACD;IACA,eAAe;IAChB;GACF,CAAC;;;AAoBN,eAAe,cAAc,KAAqC;AAChE,KAAI,CAAE,MAAM,iBAAiB,IAAI,CAC/B,QAAO;EACL,WAAW;EACX,SAAS;EACV;CAGH,MAAM,SAAS,MAAM,kBAAkB,IAAI;AAC3C,KAAI,CAAE,MAAM,iBAAiB,IAAI,CAC/B,QAAO;EACL,WAAW;EACX,YAAY,OAAO,OAAO,YAAY,WAAW,OAAO,UAAU,KAAA;EAClE,SAAS;EACV;CAGH,MAAM,SAAS,MAAM,kBAAkB,IAAI;AAC3C,QAAO;EACL,WAAW;EACX,YAAY,OAAO,OAAO,WAAW,OAAO,cAAc,GAAG;EAC7D,QAAQ,sBAAsB,OAAO;EACtC;;AAGH,SAAS,gBAAgB,iBAAyB,kBAAwD;CACxG,MAAM,WAAqB,EAAE;AAC7B,KAAI,oBAAoB,UACtB,UAAS,KAAK,gBAAgB;AAEhC,KAAI,qBAAqB,iBACvB,UAAS,KAAK,gDAAgD;UACrD,qBAAqB,kBAC9B,UAAS,KAAK,yBAAyB,uBAAuB;KAE9D,UAAS,KAAK,kBAAkB,gBAAgB;AAElD,QAAO"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { _ as readRuntimeMetadata, m as localContainerName, t as BaseCommand } from "../oclif-DSPO9Sck.mjs";
|
|
2
|
+
import { u as stopAndRemoveContainer } from "../docker-C0aVpJqm.mjs";
|
|
3
|
+
//#region src/commands/stop.ts
|
|
4
|
+
var Stop = class Stop extends BaseCommand {
|
|
5
|
+
static description = "Stop the local Zitadel server.";
|
|
6
|
+
async run() {
|
|
7
|
+
const { flags } = await this.parse(Stop);
|
|
8
|
+
const runtime = await readRuntimeMetadata(flags.cwd ? String(flags.cwd) : process.cwd());
|
|
9
|
+
await this.toMeta(flags, {
|
|
10
|
+
resolveServer: false,
|
|
11
|
+
source: runtime?.server_url ?? "http://localhost:8080"
|
|
12
|
+
});
|
|
13
|
+
const containerName = runtime?.container_name ?? localContainerName(this.meta.cwd);
|
|
14
|
+
if (this.meta.dryRun) return this.emit({
|
|
15
|
+
status: "ok",
|
|
16
|
+
data: {
|
|
17
|
+
title: "Local Zitadel server stop plan.",
|
|
18
|
+
runtime: {
|
|
19
|
+
container_name: containerName,
|
|
20
|
+
data_preserved: true,
|
|
21
|
+
data_dir: runtime?.data_dir
|
|
22
|
+
},
|
|
23
|
+
next_commands: ["zitadel stop"]
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
await stopAndRemoveContainer(containerName);
|
|
27
|
+
return this.emit({
|
|
28
|
+
status: "ok",
|
|
29
|
+
data: {
|
|
30
|
+
title: "Local Zitadel server stopped.",
|
|
31
|
+
runtime: {
|
|
32
|
+
container_name: containerName,
|
|
33
|
+
data_preserved: true,
|
|
34
|
+
data_dir: runtime?.data_dir
|
|
35
|
+
},
|
|
36
|
+
next_commands: ["zitadel start", "zitadel reset --force"]
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
//#endregion
|
|
42
|
+
export { Stop as default };
|
|
43
|
+
|
|
44
|
+
//# sourceMappingURL=stop.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stop.mjs","names":[],"sources":["../../src/commands/stop.ts"],"sourcesContent":["import { BaseCommand, type JsonEnvelope } from \"../lib/oclif\";\nimport { stopAndRemoveContainer } from \"../lib/local-server/docker\";\nimport {\n DEFAULT_LOCAL_SERVER_URL,\n localContainerName,\n readRuntimeMetadata,\n} from \"../lib/local-server/runtime\";\n\nexport default class Stop extends BaseCommand {\n static override description = \"Stop the local Zitadel server.\";\n\n async run(): Promise<JsonEnvelope> {\n const { flags } = await this.parse(Stop);\n const runtime = await readRuntimeMetadata(flags.cwd ? String(flags.cwd) : process.cwd());\n await this.toMeta(flags, {\n resolveServer: false,\n source: runtime?.server_url ?? DEFAULT_LOCAL_SERVER_URL,\n });\n\n const containerName = runtime?.container_name ?? localContainerName(this.meta.cwd);\n if (this.meta.dryRun) {\n return this.emit({\n status: \"ok\",\n data: {\n title: \"Local Zitadel server stop plan.\",\n runtime: {\n container_name: containerName,\n data_preserved: true,\n data_dir: runtime?.data_dir,\n },\n next_commands: [\"zitadel stop\"],\n },\n });\n }\n\n await stopAndRemoveContainer(containerName);\n\n return this.emit({\n status: \"ok\",\n data: {\n title: \"Local Zitadel server stopped.\",\n runtime: {\n container_name: containerName,\n data_preserved: true,\n data_dir: runtime?.data_dir,\n },\n next_commands: [\"zitadel start\", \"zitadel reset --force\"],\n },\n });\n }\n}\n"],"mappings":";;;AAQA,IAAqB,OAArB,MAAqB,aAAa,YAAY;CAC5C,OAAgB,cAAc;CAE9B,MAAM,MAA6B;EACjC,MAAM,EAAE,UAAU,MAAM,KAAK,MAAM,KAAK;EACxC,MAAM,UAAU,MAAM,oBAAoB,MAAM,MAAM,OAAO,MAAM,IAAI,GAAG,QAAQ,KAAK,CAAC;AACxF,QAAM,KAAK,OAAO,OAAO;GACvB,eAAe;GACf,QAAQ,SAAS,cAAA;GAClB,CAAC;EAEF,MAAM,gBAAgB,SAAS,kBAAkB,mBAAmB,KAAK,KAAK,IAAI;AAClF,MAAI,KAAK,KAAK,OACZ,QAAO,KAAK,KAAK;GACf,QAAQ;GACR,MAAM;IACJ,OAAO;IACP,SAAS;KACP,gBAAgB;KAChB,gBAAgB;KAChB,UAAU,SAAS;KACpB;IACD,eAAe,CAAC,eAAe;IAChC;GACF,CAAC;AAGJ,QAAM,uBAAuB,cAAc;AAE3C,SAAO,KAAK,KAAK;GACf,QAAQ;GACR,MAAM;IACJ,OAAO;IACP,SAAS;KACP,gBAAgB;KAChB,gBAAgB;KAChB,UAAU,SAAS;KACpB;IACD,eAAe,CAAC,iBAAiB,wBAAwB;IAC1D;GACF,CAAC"}
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
import { T as ZitadelError, a as CONTAINER_HTTP_PORT, i as CONTAINER_DATA_DIR } from "./oclif-DSPO9Sck.mjs";
|
|
2
|
+
import { spawn } from "node:child_process";
|
|
3
|
+
//#region src/lib/local-server/docker.ts
|
|
4
|
+
function dockerRunArgs(spec) {
|
|
5
|
+
const args = [
|
|
6
|
+
"run",
|
|
7
|
+
"--detach",
|
|
8
|
+
"--name",
|
|
9
|
+
spec.containerName,
|
|
10
|
+
"--publish",
|
|
11
|
+
`127.0.0.1:${spec.port}:${CONTAINER_HTTP_PORT}`,
|
|
12
|
+
"--volume",
|
|
13
|
+
`${spec.dataDir}:${CONTAINER_DATA_DIR}`,
|
|
14
|
+
"--env",
|
|
15
|
+
`NEXTGEN_SERVER_ADDRESS=:${CONTAINER_HTTP_PORT}`,
|
|
16
|
+
"--env",
|
|
17
|
+
`NEXTGEN_SERVER_DATA_DIR=${CONTAINER_DATA_DIR}`
|
|
18
|
+
];
|
|
19
|
+
if (spec.identity) args.push("--volume", `${spec.identity.passwdFile}:/etc/passwd:ro`, "--volume", `${spec.identity.groupFile}:/etc/group:ro`, "--user", `${spec.identity.uid}:${spec.identity.gid}`);
|
|
20
|
+
args.push(spec.image);
|
|
21
|
+
return args;
|
|
22
|
+
}
|
|
23
|
+
async function runDocker(args) {
|
|
24
|
+
return new Promise((resolve, reject) => {
|
|
25
|
+
const child = spawn("docker", args, {
|
|
26
|
+
stdio: [
|
|
27
|
+
"ignore",
|
|
28
|
+
"pipe",
|
|
29
|
+
"pipe"
|
|
30
|
+
],
|
|
31
|
+
env: process.env
|
|
32
|
+
});
|
|
33
|
+
let stdout = "";
|
|
34
|
+
let stderr = "";
|
|
35
|
+
child.stdout?.setEncoding("utf8");
|
|
36
|
+
child.stderr?.setEncoding("utf8");
|
|
37
|
+
child.stdout?.on("data", (chunk) => {
|
|
38
|
+
stdout += chunk;
|
|
39
|
+
});
|
|
40
|
+
child.stderr?.on("data", (chunk) => {
|
|
41
|
+
stderr += chunk;
|
|
42
|
+
});
|
|
43
|
+
child.on("error", reject);
|
|
44
|
+
child.on("close", (code) => {
|
|
45
|
+
resolve({
|
|
46
|
+
status: code ?? 1,
|
|
47
|
+
stdout,
|
|
48
|
+
stderr
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
async function streamDocker(args) {
|
|
54
|
+
await new Promise((resolve, reject) => {
|
|
55
|
+
const child = spawn("docker", args, {
|
|
56
|
+
stdio: "inherit",
|
|
57
|
+
env: process.env
|
|
58
|
+
});
|
|
59
|
+
child.on("error", reject);
|
|
60
|
+
child.on("close", (code) => {
|
|
61
|
+
if (code === 0) resolve();
|
|
62
|
+
else reject(/* @__PURE__ */ new Error(`docker ${args.join(" ")} exited with status ${code ?? 1}`));
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
async function dockerAvailable() {
|
|
67
|
+
return runDocker([
|
|
68
|
+
"version",
|
|
69
|
+
"--format",
|
|
70
|
+
"{{.Server.Version}}"
|
|
71
|
+
]);
|
|
72
|
+
}
|
|
73
|
+
async function pullImage(image) {
|
|
74
|
+
await requireDocker([
|
|
75
|
+
"pull",
|
|
76
|
+
"--quiet",
|
|
77
|
+
image
|
|
78
|
+
], `Pull Docker image ${image}`);
|
|
79
|
+
}
|
|
80
|
+
async function imageExists(image) {
|
|
81
|
+
let result;
|
|
82
|
+
const args = [
|
|
83
|
+
"image",
|
|
84
|
+
"inspect",
|
|
85
|
+
image
|
|
86
|
+
];
|
|
87
|
+
try {
|
|
88
|
+
result = await runDocker(args);
|
|
89
|
+
} catch (error) {
|
|
90
|
+
throw dockerError(`Inspect Docker image ${image}`, args, error);
|
|
91
|
+
}
|
|
92
|
+
return result.status === 0;
|
|
93
|
+
}
|
|
94
|
+
async function imageAvailable(image) {
|
|
95
|
+
if (await imageExists(image)) return "local";
|
|
96
|
+
const args = [
|
|
97
|
+
"manifest",
|
|
98
|
+
"inspect",
|
|
99
|
+
image
|
|
100
|
+
];
|
|
101
|
+
let result;
|
|
102
|
+
try {
|
|
103
|
+
result = await runDocker(args);
|
|
104
|
+
} catch (error) {
|
|
105
|
+
throw dockerError(`Inspect Docker image ${image}`, args, error);
|
|
106
|
+
}
|
|
107
|
+
if (result.status === 0) return "remote";
|
|
108
|
+
throw dockerError(`Inspect Docker image ${image}`, args, result);
|
|
109
|
+
}
|
|
110
|
+
async function ensureImage(image) {
|
|
111
|
+
if (await imageExists(image)) return "local";
|
|
112
|
+
await pullImage(image);
|
|
113
|
+
return "pulled";
|
|
114
|
+
}
|
|
115
|
+
async function inspectContainer(containerName) {
|
|
116
|
+
const result = await runDocker([
|
|
117
|
+
"inspect",
|
|
118
|
+
"--format",
|
|
119
|
+
"{{.Id}} {{.State.Running}}",
|
|
120
|
+
containerName
|
|
121
|
+
]);
|
|
122
|
+
if (result.status !== 0) return {
|
|
123
|
+
exists: false,
|
|
124
|
+
running: false
|
|
125
|
+
};
|
|
126
|
+
const [id, running] = result.stdout.trim().split(/\s+/);
|
|
127
|
+
return {
|
|
128
|
+
exists: true,
|
|
129
|
+
running: running === "true",
|
|
130
|
+
id
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
async function startContainer(spec) {
|
|
134
|
+
return (await requireDocker(dockerRunArgs(spec), "Start local Zitadel container")).stdout.trim();
|
|
135
|
+
}
|
|
136
|
+
async function stopAndRemoveContainer(containerName) {
|
|
137
|
+
const inspect = await inspectContainer(containerName);
|
|
138
|
+
if (!inspect.exists) return;
|
|
139
|
+
if (inspect.running) await requireDocker(["stop", containerName], `Stop ${containerName}`);
|
|
140
|
+
await requireDocker(["rm", containerName], `Remove ${containerName}`);
|
|
141
|
+
}
|
|
142
|
+
async function containerLogs(containerName, tail) {
|
|
143
|
+
return (await requireDocker([
|
|
144
|
+
"logs",
|
|
145
|
+
"--tail",
|
|
146
|
+
String(tail),
|
|
147
|
+
containerName
|
|
148
|
+
], "Read logs")).stdout;
|
|
149
|
+
}
|
|
150
|
+
async function followContainerLogs(containerName, tail) {
|
|
151
|
+
await streamDocker([
|
|
152
|
+
"logs",
|
|
153
|
+
"--tail",
|
|
154
|
+
String(tail),
|
|
155
|
+
"--follow",
|
|
156
|
+
containerName
|
|
157
|
+
]);
|
|
158
|
+
}
|
|
159
|
+
function currentUser() {
|
|
160
|
+
const getuid = process.getuid;
|
|
161
|
+
const getgid = process.getgid;
|
|
162
|
+
if (typeof getuid !== "function") return {};
|
|
163
|
+
const uid = getuid();
|
|
164
|
+
return {
|
|
165
|
+
uid,
|
|
166
|
+
gid: typeof getgid === "function" ? getgid() : uid
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
function metadataFromStart(input) {
|
|
170
|
+
return {
|
|
171
|
+
schema_version: 1,
|
|
172
|
+
container_name: input.containerName,
|
|
173
|
+
container_id: input.containerId,
|
|
174
|
+
image: input.image,
|
|
175
|
+
port: input.port,
|
|
176
|
+
server_url: input.serverUrl,
|
|
177
|
+
data_dir: input.cwdDataDir,
|
|
178
|
+
created_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
179
|
+
cli_version: input.cliVersion
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
async function requireDocker(args, action) {
|
|
183
|
+
let result;
|
|
184
|
+
try {
|
|
185
|
+
result = await runDocker(args);
|
|
186
|
+
} catch (error) {
|
|
187
|
+
throw dockerError(action, args, error);
|
|
188
|
+
}
|
|
189
|
+
if (result.status !== 0) throw dockerError(action, args, result);
|
|
190
|
+
return result;
|
|
191
|
+
}
|
|
192
|
+
function dockerError(action, args, cause) {
|
|
193
|
+
const details = cause && typeof cause === "object" && "stderr" in cause ? {
|
|
194
|
+
command: ["docker", ...args],
|
|
195
|
+
stderr: String(cause.stderr)
|
|
196
|
+
} : {
|
|
197
|
+
command: ["docker", ...args],
|
|
198
|
+
cause
|
|
199
|
+
};
|
|
200
|
+
return new ZitadelError("E_VALIDATION", `${action} failed`, {
|
|
201
|
+
hint: "Check that Docker is installed, running, and reachable from this shell.",
|
|
202
|
+
nextCommands: ["zitadel doctor"],
|
|
203
|
+
details
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
//#endregion
|
|
207
|
+
export { followContainerLogs as a, metadataFromStart as c, ensureImage as i, startContainer as l, currentUser as n, imageAvailable as o, dockerAvailable as r, inspectContainer as s, containerLogs as t, stopAndRemoveContainer as u };
|
|
208
|
+
|
|
209
|
+
//# sourceMappingURL=docker-C0aVpJqm.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"docker-C0aVpJqm.mjs","names":[],"sources":["../src/lib/local-server/docker.ts"],"sourcesContent":["import { spawn } from \"node:child_process\";\n\nimport { ZitadelError } from \"../errors\";\nimport {\n CONTAINER_DATA_DIR,\n CONTAINER_HTTP_PORT,\n type ContainerIdentity,\n type RuntimeMetadata,\n} from \"./runtime\";\n\nexport type DockerResult = {\n status: number;\n stdout: string;\n stderr: string;\n};\n\nexport type DockerRunSpec = {\n containerName: string;\n image: string;\n port: number;\n dataDir: string;\n identity?: ContainerIdentity;\n};\n\nexport function dockerRunArgs(spec: DockerRunSpec): string[] {\n const args = [\n \"run\",\n \"--detach\",\n \"--name\",\n spec.containerName,\n \"--publish\",\n `127.0.0.1:${spec.port}:${CONTAINER_HTTP_PORT}`,\n \"--volume\",\n `${spec.dataDir}:${CONTAINER_DATA_DIR}`,\n \"--env\",\n `NEXTGEN_SERVER_ADDRESS=:${CONTAINER_HTTP_PORT}`,\n \"--env\",\n `NEXTGEN_SERVER_DATA_DIR=${CONTAINER_DATA_DIR}`,\n ];\n\n if (spec.identity) {\n args.push(\n \"--volume\",\n `${spec.identity.passwdFile}:/etc/passwd:ro`,\n \"--volume\",\n `${spec.identity.groupFile}:/etc/group:ro`,\n \"--user\",\n `${spec.identity.uid}:${spec.identity.gid}`,\n );\n }\n\n args.push(spec.image);\n return args;\n}\n\nexport async function runDocker(args: string[]): Promise<DockerResult> {\n return new Promise((resolve, reject) => {\n const child = spawn(\"docker\", args, {\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n env: process.env,\n });\n let stdout = \"\";\n let stderr = \"\";\n child.stdout?.setEncoding(\"utf8\");\n child.stderr?.setEncoding(\"utf8\");\n child.stdout?.on(\"data\", (chunk: string) => {\n stdout += chunk;\n });\n child.stderr?.on(\"data\", (chunk: string) => {\n stderr += chunk;\n });\n child.on(\"error\", reject);\n child.on(\"close\", (code) => {\n resolve({ status: code ?? 1, stdout, stderr });\n });\n });\n}\n\nexport async function streamDocker(args: string[]): Promise<void> {\n await new Promise<void>((resolve, reject) => {\n const child = spawn(\"docker\", args, {\n stdio: \"inherit\",\n env: process.env,\n });\n child.on(\"error\", reject);\n child.on(\"close\", (code) => {\n if (code === 0) {\n resolve();\n } else {\n reject(new Error(`docker ${args.join(\" \")} exited with status ${code ?? 1}`));\n }\n });\n });\n}\n\nexport async function dockerAvailable(): Promise<DockerResult> {\n return runDocker([\"version\", \"--format\", \"{{.Server.Version}}\"]);\n}\n\nexport async function pullImage(image: string): Promise<void> {\n await requireDocker([\"pull\", \"--quiet\", image], `Pull Docker image ${image}`);\n}\n\nexport async function imageExists(image: string): Promise<boolean> {\n let result: DockerResult;\n const args = [\"image\", \"inspect\", image];\n try {\n result = await runDocker(args);\n } catch (error) {\n throw dockerError(`Inspect Docker image ${image}`, args, error);\n }\n return result.status === 0;\n}\n\nexport async function imageAvailable(image: string): Promise<\"local\" | \"remote\"> {\n if (await imageExists(image)) {\n return \"local\";\n }\n\n const args = [\"manifest\", \"inspect\", image];\n let result: DockerResult;\n try {\n result = await runDocker(args);\n } catch (error) {\n throw dockerError(`Inspect Docker image ${image}`, args, error);\n }\n if (result.status === 0) {\n return \"remote\";\n }\n throw dockerError(`Inspect Docker image ${image}`, args, result);\n}\n\nexport async function ensureImage(image: string): Promise<\"local\" | \"pulled\"> {\n if (await imageExists(image)) {\n return \"local\";\n }\n await pullImage(image);\n return \"pulled\";\n}\n\nexport async function inspectContainer(containerName: string): Promise<{\n exists: boolean;\n running: boolean;\n id?: string;\n}> {\n const result = await runDocker([\n \"inspect\",\n \"--format\",\n \"{{.Id}} {{.State.Running}}\",\n containerName,\n ]);\n if (result.status !== 0) {\n return { exists: false, running: false };\n }\n const [id, running] = result.stdout.trim().split(/\\s+/);\n return { exists: true, running: running === \"true\", id };\n}\n\nexport async function startContainer(spec: DockerRunSpec): Promise<string> {\n const args = dockerRunArgs(spec);\n const result = await requireDocker(args, \"Start local Zitadel container\");\n return result.stdout.trim();\n}\n\nexport async function stopAndRemoveContainer(containerName: string): Promise<void> {\n const inspect = await inspectContainer(containerName);\n if (!inspect.exists) {\n return;\n }\n if (inspect.running) {\n await requireDocker([\"stop\", containerName], `Stop ${containerName}`);\n }\n await requireDocker([\"rm\", containerName], `Remove ${containerName}`);\n}\n\nexport async function containerLogs(containerName: string, tail: number): Promise<string> {\n const result = await requireDocker([\"logs\", \"--tail\", String(tail), containerName], \"Read logs\");\n return result.stdout;\n}\n\nexport async function followContainerLogs(containerName: string, tail: number): Promise<void> {\n await streamDocker([\"logs\", \"--tail\", String(tail), \"--follow\", containerName]);\n}\n\nexport function currentUser(): { uid?: number; gid?: number } {\n const getuid = process.getuid;\n const getgid = process.getgid;\n if (typeof getuid !== \"function\") {\n return {};\n }\n const uid = getuid();\n const gid = typeof getgid === \"function\" ? getgid() : uid;\n return { uid, gid };\n}\n\nexport function metadataFromStart(input: {\n cwdDataDir: string;\n cliVersion: string;\n containerName: string;\n containerId: string;\n image: string;\n port: number;\n serverUrl: string;\n}): RuntimeMetadata {\n return {\n schema_version: 1,\n container_name: input.containerName,\n container_id: input.containerId,\n image: input.image,\n port: input.port,\n server_url: input.serverUrl,\n data_dir: input.cwdDataDir,\n created_at: new Date().toISOString(),\n cli_version: input.cliVersion,\n };\n}\n\nexport async function requireDocker(args: string[], action: string): Promise<DockerResult> {\n let result: DockerResult;\n try {\n result = await runDocker(args);\n } catch (error) {\n throw dockerError(action, args, error);\n }\n if (result.status !== 0) {\n throw dockerError(action, args, result);\n }\n return result;\n}\n\nfunction dockerError(action: string, args: string[], cause: unknown): ZitadelError {\n const details =\n cause && typeof cause === \"object\" && \"stderr\" in cause\n ? { command: [\"docker\", ...args], stderr: String((cause as { stderr?: unknown }).stderr) }\n : { command: [\"docker\", ...args], cause };\n return new ZitadelError(\"E_VALIDATION\", `${action} failed`, {\n hint: \"Check that Docker is installed, running, and reachable from this shell.\",\n nextCommands: [\"zitadel doctor\"],\n details,\n });\n}\n"],"mappings":";;;AAwBA,SAAgB,cAAc,MAA+B;CAC3D,MAAM,OAAO;EACX;EACA;EACA;EACA,KAAK;EACL;EACA,aAAa,KAAK,KAAK,GAAG;EAC1B;EACA,GAAG,KAAK,QAAQ,GAAG;EACnB;EACA,2BAA2B;EAC3B;EACA,2BAA2B;EAC5B;AAED,KAAI,KAAK,SACP,MAAK,KACH,YACA,GAAG,KAAK,SAAS,WAAW,kBAC5B,YACA,GAAG,KAAK,SAAS,UAAU,iBAC3B,UACA,GAAG,KAAK,SAAS,IAAI,GAAG,KAAK,SAAS,MACvC;AAGH,MAAK,KAAK,KAAK,MAAM;AACrB,QAAO;;AAGT,eAAsB,UAAU,MAAuC;AACrE,QAAO,IAAI,SAAS,SAAS,WAAW;EACtC,MAAM,QAAQ,MAAM,UAAU,MAAM;GAClC,OAAO;IAAC;IAAU;IAAQ;IAAO;GACjC,KAAK,QAAQ;GACd,CAAC;EACF,IAAI,SAAS;EACb,IAAI,SAAS;AACb,QAAM,QAAQ,YAAY,OAAO;AACjC,QAAM,QAAQ,YAAY,OAAO;AACjC,QAAM,QAAQ,GAAG,SAAS,UAAkB;AAC1C,aAAU;IACV;AACF,QAAM,QAAQ,GAAG,SAAS,UAAkB;AAC1C,aAAU;IACV;AACF,QAAM,GAAG,SAAS,OAAO;AACzB,QAAM,GAAG,UAAU,SAAS;AAC1B,WAAQ;IAAE,QAAQ,QAAQ;IAAG;IAAQ;IAAQ,CAAC;IAC9C;GACF;;AAGJ,eAAsB,aAAa,MAA+B;AAChE,OAAM,IAAI,SAAe,SAAS,WAAW;EAC3C,MAAM,QAAQ,MAAM,UAAU,MAAM;GAClC,OAAO;GACP,KAAK,QAAQ;GACd,CAAC;AACF,QAAM,GAAG,SAAS,OAAO;AACzB,QAAM,GAAG,UAAU,SAAS;AAC1B,OAAI,SAAS,EACX,UAAS;OAET,wBAAO,IAAI,MAAM,UAAU,KAAK,KAAK,IAAI,CAAC,sBAAsB,QAAQ,IAAI,CAAC;IAE/E;GACF;;AAGJ,eAAsB,kBAAyC;AAC7D,QAAO,UAAU;EAAC;EAAW;EAAY;EAAsB,CAAC;;AAGlE,eAAsB,UAAU,OAA8B;AAC5D,OAAM,cAAc;EAAC;EAAQ;EAAW;EAAM,EAAE,qBAAqB,QAAQ;;AAG/E,eAAsB,YAAY,OAAiC;CACjE,IAAI;CACJ,MAAM,OAAO;EAAC;EAAS;EAAW;EAAM;AACxC,KAAI;AACF,WAAS,MAAM,UAAU,KAAK;UACvB,OAAO;AACd,QAAM,YAAY,wBAAwB,SAAS,MAAM,MAAM;;AAEjE,QAAO,OAAO,WAAW;;AAG3B,eAAsB,eAAe,OAA4C;AAC/E,KAAI,MAAM,YAAY,MAAM,CAC1B,QAAO;CAGT,MAAM,OAAO;EAAC;EAAY;EAAW;EAAM;CAC3C,IAAI;AACJ,KAAI;AACF,WAAS,MAAM,UAAU,KAAK;UACvB,OAAO;AACd,QAAM,YAAY,wBAAwB,SAAS,MAAM,MAAM;;AAEjE,KAAI,OAAO,WAAW,EACpB,QAAO;AAET,OAAM,YAAY,wBAAwB,SAAS,MAAM,OAAO;;AAGlE,eAAsB,YAAY,OAA4C;AAC5E,KAAI,MAAM,YAAY,MAAM,CAC1B,QAAO;AAET,OAAM,UAAU,MAAM;AACtB,QAAO;;AAGT,eAAsB,iBAAiB,eAIpC;CACD,MAAM,SAAS,MAAM,UAAU;EAC7B;EACA;EACA;EACA;EACD,CAAC;AACF,KAAI,OAAO,WAAW,EACpB,QAAO;EAAE,QAAQ;EAAO,SAAS;EAAO;CAE1C,MAAM,CAAC,IAAI,WAAW,OAAO,OAAO,MAAM,CAAC,MAAM,MAAM;AACvD,QAAO;EAAE,QAAQ;EAAM,SAAS,YAAY;EAAQ;EAAI;;AAG1D,eAAsB,eAAe,MAAsC;AAGzE,SAAO,MADc,cADR,cAAc,KACY,EAAE,gCAAgC,EAC3D,OAAO,MAAM;;AAG7B,eAAsB,uBAAuB,eAAsC;CACjF,MAAM,UAAU,MAAM,iBAAiB,cAAc;AACrD,KAAI,CAAC,QAAQ,OACX;AAEF,KAAI,QAAQ,QACV,OAAM,cAAc,CAAC,QAAQ,cAAc,EAAE,QAAQ,gBAAgB;AAEvE,OAAM,cAAc,CAAC,MAAM,cAAc,EAAE,UAAU,gBAAgB;;AAGvE,eAAsB,cAAc,eAAuB,MAA+B;AAExF,SAAO,MADc,cAAc;EAAC;EAAQ;EAAU,OAAO,KAAK;EAAE;EAAc,EAAE,YAAY,EAClF;;AAGhB,eAAsB,oBAAoB,eAAuB,MAA6B;AAC5F,OAAM,aAAa;EAAC;EAAQ;EAAU,OAAO,KAAK;EAAE;EAAY;EAAc,CAAC;;AAGjF,SAAgB,cAA8C;CAC5D,MAAM,SAAS,QAAQ;CACvB,MAAM,SAAS,QAAQ;AACvB,KAAI,OAAO,WAAW,WACpB,QAAO,EAAE;CAEX,MAAM,MAAM,QAAQ;AAEpB,QAAO;EAAE;EAAK,KADF,OAAO,WAAW,aAAa,QAAQ,GAAG;EACnC;;AAGrB,SAAgB,kBAAkB,OAQd;AAClB,QAAO;EACL,gBAAgB;EAChB,gBAAgB,MAAM;EACtB,cAAc,MAAM;EACpB,OAAO,MAAM;EACb,MAAM,MAAM;EACZ,YAAY,MAAM;EAClB,UAAU,MAAM;EAChB,6BAAY,IAAI,MAAM,EAAC,aAAa;EACpC,aAAa,MAAM;EACpB;;AAGH,eAAsB,cAAc,MAAgB,QAAuC;CACzF,IAAI;AACJ,KAAI;AACF,WAAS,MAAM,UAAU,KAAK;UACvB,OAAO;AACd,QAAM,YAAY,QAAQ,MAAM,MAAM;;AAExC,KAAI,OAAO,WAAW,EACpB,OAAM,YAAY,QAAQ,MAAM,OAAO;AAEzC,QAAO;;AAGT,SAAS,YAAY,QAAgB,MAAgB,OAA8B;CACjF,MAAM,UACJ,SAAS,OAAO,UAAU,YAAY,YAAY,QAC9C;EAAE,SAAS,CAAC,UAAU,GAAG,KAAK;EAAE,QAAQ,OAAQ,MAA+B,OAAO;EAAE,GACxF;EAAE,SAAS,CAAC,UAAU,GAAG,KAAK;EAAE;EAAO;AAC7C,QAAO,IAAI,aAAa,gBAAgB,GAAG,OAAO,UAAU;EAC1D,MAAM;EACN,cAAc,CAAC,iBAAiB;EAChC;EACD,CAAC"}
|