@geekmidas/cli 0.13.0 → 0.15.0
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/{bundler-DskIqW2t.mjs → bundler-D7cM_FWw.mjs} +34 -10
- package/dist/bundler-D7cM_FWw.mjs.map +1 -0
- package/dist/{bundler-B1qy9b-j.cjs → bundler-Nuew7Xcn.cjs} +33 -9
- package/dist/bundler-Nuew7Xcn.cjs.map +1 -0
- package/dist/config.d.cts +1 -1
- package/dist/config.d.mts +1 -1
- package/dist/dokploy-api-B7KxOQr3.cjs +3 -0
- package/dist/dokploy-api-C7F9VykY.cjs +317 -0
- package/dist/dokploy-api-C7F9VykY.cjs.map +1 -0
- package/dist/dokploy-api-CaETb2L6.mjs +305 -0
- package/dist/dokploy-api-CaETb2L6.mjs.map +1 -0
- package/dist/dokploy-api-DHvfmWbi.mjs +3 -0
- package/dist/{encryption-Dyf_r1h-.cjs → encryption-D7Efcdi9.cjs} +1 -1
- package/dist/{encryption-Dyf_r1h-.cjs.map → encryption-D7Efcdi9.cjs.map} +1 -1
- package/dist/{encryption-C8H-38Yy.mjs → encryption-h4Nb6W-M.mjs} +1 -1
- package/dist/{encryption-C8H-38Yy.mjs.map → encryption-h4Nb6W-M.mjs.map} +1 -1
- package/dist/index.cjs +1508 -1073
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +1508 -1073
- package/dist/index.mjs.map +1 -1
- package/dist/{openapi-Bt_1FDpT.cjs → openapi-C89hhkZC.cjs} +3 -3
- package/dist/{openapi-Bt_1FDpT.cjs.map → openapi-C89hhkZC.cjs.map} +1 -1
- package/dist/{openapi-BfFlOBCG.mjs → openapi-CZVcfxk-.mjs} +3 -3
- package/dist/{openapi-BfFlOBCG.mjs.map → openapi-CZVcfxk-.mjs.map} +1 -1
- package/dist/{openapi-react-query-B6XTeGqS.mjs → openapi-react-query-CM2_qlW9.mjs} +1 -1
- package/dist/{openapi-react-query-B6XTeGqS.mjs.map → openapi-react-query-CM2_qlW9.mjs.map} +1 -1
- package/dist/{openapi-react-query-B-sNWHFU.cjs → openapi-react-query-iKjfLzff.cjs} +1 -1
- package/dist/{openapi-react-query-B-sNWHFU.cjs.map → openapi-react-query-iKjfLzff.cjs.map} +1 -1
- package/dist/openapi-react-query.cjs +1 -1
- package/dist/openapi-react-query.mjs +1 -1
- package/dist/openapi.cjs +1 -1
- package/dist/openapi.d.cts +1 -1
- package/dist/openapi.d.mts +1 -1
- package/dist/openapi.mjs +1 -1
- package/dist/{storage-kSxTjkNb.mjs → storage-BaOP55oq.mjs} +16 -2
- package/dist/storage-BaOP55oq.mjs.map +1 -0
- package/dist/{storage-Bj1E26lU.cjs → storage-Bn3K9Ccu.cjs} +21 -1
- package/dist/storage-Bn3K9Ccu.cjs.map +1 -0
- package/dist/storage-UfyTn7Zm.cjs +7 -0
- package/dist/storage-nkGIjeXt.mjs +3 -0
- package/dist/{types-BhkZc-vm.d.cts → types-BgaMXsUa.d.cts} +3 -1
- package/dist/{types-BR0M2v_c.d.mts.map → types-BgaMXsUa.d.cts.map} +1 -1
- package/dist/{types-BR0M2v_c.d.mts → types-iFk5ms7y.d.mts} +3 -1
- package/dist/{types-BhkZc-vm.d.cts.map → types-iFk5ms7y.d.mts.map} +1 -1
- package/package.json +4 -4
- package/src/auth/__tests__/credentials.spec.ts +127 -0
- package/src/auth/__tests__/index.spec.ts +69 -0
- package/src/auth/credentials.ts +33 -0
- package/src/auth/index.ts +57 -50
- package/src/build/__tests__/bundler.spec.ts +5 -4
- package/src/build/__tests__/endpoint-analyzer.spec.ts +623 -0
- package/src/build/__tests__/handler-templates.spec.ts +272 -0
- package/src/build/bundler.ts +61 -8
- package/src/build/index.ts +21 -0
- package/src/build/types.ts +6 -0
- package/src/deploy/__tests__/docker.spec.ts +44 -6
- package/src/deploy/__tests__/dokploy-api.spec.ts +698 -0
- package/src/deploy/__tests__/dokploy.spec.ts +196 -6
- package/src/deploy/__tests__/index.spec.ts +401 -0
- package/src/deploy/__tests__/init.spec.ts +147 -16
- package/src/deploy/docker.ts +109 -5
- package/src/deploy/dokploy-api.ts +581 -0
- package/src/deploy/dokploy.ts +66 -93
- package/src/deploy/index.ts +630 -32
- package/src/deploy/init.ts +192 -249
- package/src/deploy/types.ts +24 -2
- package/src/dev/__tests__/index.spec.ts +95 -0
- package/src/docker/__tests__/templates.spec.ts +144 -0
- package/src/docker/index.ts +96 -6
- package/src/docker/templates.ts +114 -27
- package/src/generators/EndpointGenerator.ts +2 -2
- package/src/index.ts +34 -13
- package/src/secrets/storage.ts +15 -0
- package/src/types.ts +2 -0
- package/dist/bundler-B1qy9b-j.cjs.map +0 -1
- package/dist/bundler-DskIqW2t.mjs.map +0 -1
- package/dist/storage-BOOpAF8N.cjs +0 -5
- package/dist/storage-Bj1E26lU.cjs.map +0 -1
- package/dist/storage-kSxTjkNb.mjs.map +0 -1
- package/dist/storage-tgZSUnKl.mjs +0 -3
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { existsSync } from "node:fs";
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import { mkdir, rename, writeFile } from "node:fs/promises";
|
|
4
|
-
import {
|
|
4
|
+
import { spawnSync } from "node:child_process";
|
|
5
5
|
|
|
6
6
|
//#region src/build/bundler.ts
|
|
7
7
|
/**
|
|
@@ -25,8 +25,14 @@ async function collectRequiredEnvVars(constructs) {
|
|
|
25
25
|
* @param options - Bundle configuration options
|
|
26
26
|
* @returns Bundle result with output path and optional master key
|
|
27
27
|
*/
|
|
28
|
+
/** Default env var values for docker compose services */
|
|
29
|
+
const DOCKER_SERVICE_ENV_VARS = {
|
|
30
|
+
postgres: { DATABASE_URL: "postgresql://postgres:postgres@postgres:5432/app" },
|
|
31
|
+
redis: { REDIS_URL: "redis://redis:6379" },
|
|
32
|
+
rabbitmq: { RABBITMQ_URL: "amqp://rabbitmq:5672" }
|
|
33
|
+
};
|
|
28
34
|
async function bundleServer(options) {
|
|
29
|
-
const { entryPoint, outputDir, minify, sourcemap, external, stage, constructs } = options;
|
|
35
|
+
const { entryPoint, outputDir, minify, sourcemap, external, stage, constructs, dockerServices } = options;
|
|
30
36
|
await mkdir(outputDir, { recursive: true });
|
|
31
37
|
const args = [
|
|
32
38
|
"npx",
|
|
@@ -49,10 +55,24 @@ async function bundleServer(options) {
|
|
|
49
55
|
args.push("--external", "node:*");
|
|
50
56
|
let masterKey;
|
|
51
57
|
if (stage) {
|
|
52
|
-
const { readStageSecrets, toEmbeddableSecrets, validateEnvironmentVariables } = await import("./storage-
|
|
53
|
-
const { encryptSecrets, generateDefineOptions } = await import("./encryption-
|
|
54
|
-
|
|
55
|
-
if (!secrets)
|
|
58
|
+
const { readStageSecrets, toEmbeddableSecrets, validateEnvironmentVariables, initStageSecrets, writeStageSecrets } = await import("./storage-nkGIjeXt.mjs");
|
|
59
|
+
const { encryptSecrets, generateDefineOptions } = await import("./encryption-h4Nb6W-M.mjs");
|
|
60
|
+
let secrets = await readStageSecrets(stage);
|
|
61
|
+
if (!secrets) {
|
|
62
|
+
console.log(` Initializing secrets for stage "${stage}"...`);
|
|
63
|
+
secrets = initStageSecrets(stage);
|
|
64
|
+
await writeStageSecrets(secrets);
|
|
65
|
+
console.log(` ✓ Created .gkm/secrets/${stage}.json`);
|
|
66
|
+
}
|
|
67
|
+
if (dockerServices) {
|
|
68
|
+
for (const [service, enabled] of Object.entries(dockerServices)) if (enabled && DOCKER_SERVICE_ENV_VARS[service]) for (const [envVar, defaultValue] of Object.entries(DOCKER_SERVICE_ENV_VARS[service])) {
|
|
69
|
+
const urlKey = envVar;
|
|
70
|
+
if (!secrets.urls[urlKey] && !secrets.custom[envVar]) {
|
|
71
|
+
secrets.urls[urlKey] = defaultValue;
|
|
72
|
+
console.log(` Auto-populated ${envVar} from docker compose`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
56
76
|
if (constructs && constructs.length > 0) {
|
|
57
77
|
console.log(" Analyzing environment variable requirements...");
|
|
58
78
|
const requiredVars = await collectRequiredEnvVars(constructs);
|
|
@@ -83,15 +103,19 @@ async function bundleServer(options) {
|
|
|
83
103
|
const encrypted = encryptSecrets(embeddable);
|
|
84
104
|
masterKey = encrypted.masterKey;
|
|
85
105
|
const defines = generateDefineOptions(encrypted);
|
|
86
|
-
for (const [key, value] of Object.entries(defines)) args.push(
|
|
106
|
+
for (const [key, value] of Object.entries(defines)) args.push(`--env.${key}`, value);
|
|
87
107
|
console.log(` Secrets encrypted for stage "${stage}"`);
|
|
88
108
|
}
|
|
89
109
|
const mjsOutput = join(outputDir, "server.mjs");
|
|
90
110
|
try {
|
|
91
|
-
|
|
111
|
+
const [cmd, ...cmdArgs] = args;
|
|
112
|
+
const result = spawnSync(cmd, cmdArgs, {
|
|
92
113
|
cwd: process.cwd(),
|
|
93
|
-
stdio: "inherit"
|
|
114
|
+
stdio: "inherit",
|
|
115
|
+
shell: process.platform === "win32"
|
|
94
116
|
});
|
|
117
|
+
if (result.error) throw result.error;
|
|
118
|
+
if (result.status !== 0) throw new Error(`tsdown exited with code ${result.status}`);
|
|
95
119
|
const jsOutput = join(outputDir, "server.js");
|
|
96
120
|
if (existsSync(jsOutput)) await rename(jsOutput, mjsOutput);
|
|
97
121
|
const { readFile: readFile$1 } = await import("node:fs/promises");
|
|
@@ -108,4 +132,4 @@ async function bundleServer(options) {
|
|
|
108
132
|
|
|
109
133
|
//#endregion
|
|
110
134
|
export { bundleServer };
|
|
111
|
-
//# sourceMappingURL=bundler-
|
|
135
|
+
//# sourceMappingURL=bundler-D7cM_FWw.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bundler-D7cM_FWw.mjs","names":["constructs: Construct[]","DOCKER_SERVICE_ENV_VARS: Record<string, Record<string, string>>","options: BundleOptions","masterKey: string | undefined"],"sources":["../src/build/bundler.ts"],"sourcesContent":["import { spawnSync } from 'node:child_process';\nimport { existsSync } from 'node:fs';\nimport { mkdir, rename, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport type { Construct } from '@geekmidas/constructs';\n\nexport interface BundleOptions {\n\t/** Entry point file (e.g., .gkm/server/server.ts) */\n\tentryPoint: string;\n\t/** Output directory for bundled files */\n\toutputDir: string;\n\t/** Minify the output (default: true) */\n\tminify: boolean;\n\t/** Generate sourcemaps (default: false) */\n\tsourcemap: boolean;\n\t/** Packages to exclude from bundling */\n\texternal: string[];\n\t/** Stage for secrets injection (optional) */\n\tstage?: string;\n\t/** Constructs to validate environment variables for */\n\tconstructs?: Construct[];\n\t/** Docker compose services configured (for auto-populating env vars) */\n\tdockerServices?: {\n\t\tpostgres?: boolean;\n\t\tredis?: boolean;\n\t\trabbitmq?: boolean;\n\t};\n}\n\nexport interface BundleResult {\n\t/** Path to the bundled output */\n\toutputPath: string;\n\t/** Ephemeral master key for deployment (only if stage was provided) */\n\tmasterKey?: string;\n}\n\n/**\n * Collect all required environment variables from constructs.\n * Uses the SnifferEnvironmentParser to detect which env vars each service needs.\n *\n * @param constructs - Array of constructs to analyze\n * @returns Deduplicated array of required environment variable names\n */\nasync function collectRequiredEnvVars(\n\tconstructs: Construct[],\n): Promise<string[]> {\n\tconst allEnvVars = new Set<string>();\n\n\tfor (const construct of constructs) {\n\t\tconst envVars = await construct.getEnvironment();\n\t\tenvVars.forEach((v) => allEnvVars.add(v));\n\t}\n\n\treturn Array.from(allEnvVars).sort();\n}\n\n/**\n * Bundle the server application using tsdown\n *\n * @param options - Bundle configuration options\n * @returns Bundle result with output path and optional master key\n */\n/** Default env var values for docker compose services */\nconst DOCKER_SERVICE_ENV_VARS: Record<string, Record<string, string>> = {\n\tpostgres: {\n\t\tDATABASE_URL: 'postgresql://postgres:postgres@postgres:5432/app',\n\t},\n\tredis: {\n\t\tREDIS_URL: 'redis://redis:6379',\n\t},\n\trabbitmq: {\n\t\tRABBITMQ_URL: 'amqp://rabbitmq:5672',\n\t},\n};\n\nexport async function bundleServer(\n\toptions: BundleOptions,\n): Promise<BundleResult> {\n\tconst {\n\t\tentryPoint,\n\t\toutputDir,\n\t\tminify,\n\t\tsourcemap,\n\t\texternal,\n\t\tstage,\n\t\tconstructs,\n\t\tdockerServices,\n\t} = options;\n\n\t// Ensure output directory exists\n\tawait mkdir(outputDir, { recursive: true });\n\n\t// Build command-line arguments for tsdown\n\tconst args = [\n\t\t'npx',\n\t\t'tsdown',\n\t\tentryPoint,\n\t\t'--no-config', // Don't use any config file from workspace\n\t\t'--out-dir',\n\t\toutputDir,\n\t\t'--format',\n\t\t'esm',\n\t\t'--platform',\n\t\t'node',\n\t\t'--target',\n\t\t'node22',\n\t\t'--clean',\n\t];\n\n\tif (minify) {\n\t\targs.push('--minify');\n\t}\n\n\tif (sourcemap) {\n\t\targs.push('--sourcemap');\n\t}\n\n\t// Add external packages\n\tfor (const ext of external) {\n\t\targs.push('--external', ext);\n\t}\n\n\t// Always exclude node: builtins\n\targs.push('--external', 'node:*');\n\n\t// Handle secrets injection if stage is provided\n\tlet masterKey: string | undefined;\n\n\tif (stage) {\n\t\tconst {\n\t\t\treadStageSecrets,\n\t\t\ttoEmbeddableSecrets,\n\t\t\tvalidateEnvironmentVariables,\n\t\t\tinitStageSecrets,\n\t\t\twriteStageSecrets,\n\t\t} = await import('../secrets/storage');\n\t\tconst { encryptSecrets, generateDefineOptions } = await import(\n\t\t\t'../secrets/encryption'\n\t\t);\n\n\t\tlet secrets = await readStageSecrets(stage);\n\n\t\tif (!secrets) {\n\t\t\t// Auto-initialize secrets for the stage\n\t\t\tconsole.log(` Initializing secrets for stage \"${stage}\"...`);\n\t\t\tsecrets = initStageSecrets(stage);\n\t\t\tawait writeStageSecrets(secrets);\n\t\t\tconsole.log(` ✓ Created .gkm/secrets/${stage}.json`);\n\t\t}\n\n\t\t// Auto-populate env vars from docker compose services\n\t\tif (dockerServices) {\n\t\t\tfor (const [service, enabled] of Object.entries(dockerServices)) {\n\t\t\t\tif (enabled && DOCKER_SERVICE_ENV_VARS[service]) {\n\t\t\t\t\tfor (const [envVar, defaultValue] of Object.entries(\n\t\t\t\t\t\tDOCKER_SERVICE_ENV_VARS[service],\n\t\t\t\t\t)) {\n\t\t\t\t\t\t// Check if not already in urls or custom\n\t\t\t\t\t\tconst urlKey = envVar as keyof typeof secrets.urls;\n\t\t\t\t\t\tif (!secrets.urls[urlKey] && !secrets.custom[envVar]) {\n\t\t\t\t\t\t\tsecrets.urls[urlKey] = defaultValue;\n\t\t\t\t\t\t\tconsole.log(` Auto-populated ${envVar} from docker compose`);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Validate environment variables if constructs are provided\n\t\tif (constructs && constructs.length > 0) {\n\t\t\tconsole.log(' Analyzing environment variable requirements...');\n\t\t\tconst requiredVars = await collectRequiredEnvVars(constructs);\n\n\t\t\tif (requiredVars.length > 0) {\n\t\t\t\tconst validation = validateEnvironmentVariables(requiredVars, secrets);\n\n\t\t\t\tif (!validation.valid) {\n\t\t\t\t\tconst errorMessage = [\n\t\t\t\t\t\t`Missing environment variables for stage \"${stage}\":`,\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t...validation.missing.map((v) => ` ❌ ${v}`),\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t'To fix this, either:',\n\t\t\t\t\t\t` 1. Add the missing variables to .gkm/secrets/${stage}.json using:`,\n\t\t\t\t\t\t` gkm secrets:set <KEY> <VALUE> --stage ${stage}`,\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t` 2. Or import from a JSON file:`,\n\t\t\t\t\t\t` gkm secrets:import secrets.json --stage ${stage}`,\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t'Required variables:',\n\t\t\t\t\t\t...validation.required.map((v) =>\n\t\t\t\t\t\t\tvalidation.missing.includes(v) ? ` ❌ ${v}` : ` ✓ ${v}`,\n\t\t\t\t\t\t),\n\t\t\t\t\t].join('\\n');\n\n\t\t\t\t\tthrow new Error(errorMessage);\n\t\t\t\t}\n\n\t\t\t\tconsole.log(\n\t\t\t\t\t` ✓ All ${requiredVars.length} required environment variables found`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\t// Convert to embeddable format and encrypt\n\t\tconst embeddable = toEmbeddableSecrets(secrets);\n\t\tconst encrypted = encryptSecrets(embeddable);\n\t\tmasterKey = encrypted.masterKey;\n\n\t\t// Add define options for build-time injection using tsdown's --env.* format\n\t\tconst defines = generateDefineOptions(encrypted);\n\t\tfor (const [key, value] of Object.entries(defines)) {\n\t\t\targs.push(`--env.${key}`, value);\n\t\t}\n\n\t\tconsole.log(` Secrets encrypted for stage \"${stage}\"`);\n\t}\n\n\tconst mjsOutput = join(outputDir, 'server.mjs');\n\n\ttry {\n\t\t// Run tsdown with command-line arguments\n\t\t// Use spawnSync with args array to avoid shell escaping issues with --define values\n\t\t// args is always populated with ['npx', 'tsdown', ...] so cmd is never undefined\n\t\tconst [cmd, ...cmdArgs] = args as [string, ...string[]];\n\t\tconst result = spawnSync(cmd, cmdArgs, {\n\t\t\tcwd: process.cwd(),\n\t\t\tstdio: 'inherit',\n\t\t\tshell: process.platform === 'win32', // Only use shell on Windows for npx resolution\n\t\t});\n\n\t\tif (result.error) {\n\t\t\tthrow result.error;\n\t\t}\n\t\tif (result.status !== 0) {\n\t\t\tthrow new Error(`tsdown exited with code ${result.status}`);\n\t\t}\n\n\t\t// Rename output to .mjs for explicit ESM\n\t\t// tsdown outputs as server.js for ESM format\n\t\tconst jsOutput = join(outputDir, 'server.js');\n\n\t\tif (existsSync(jsOutput)) {\n\t\t\tawait rename(jsOutput, mjsOutput);\n\t\t}\n\n\t\t// Add shebang to the bundled file\n\t\tconst { readFile } = await import('node:fs/promises');\n\t\tconst content = await readFile(mjsOutput, 'utf-8');\n\t\tif (!content.startsWith('#!')) {\n\t\t\tawait writeFile(mjsOutput, `#!/usr/bin/env node\\n${content}`);\n\t\t}\n\t} catch (error) {\n\t\tthrow new Error(\n\t\t\t`Failed to bundle server: ${error instanceof Error ? error.message : 'Unknown error'}`,\n\t\t);\n\t}\n\n\treturn {\n\t\toutputPath: mjsOutput,\n\t\tmasterKey,\n\t};\n}\n"],"mappings":"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"}
|
|
@@ -26,8 +26,14 @@ async function collectRequiredEnvVars(constructs) {
|
|
|
26
26
|
* @param options - Bundle configuration options
|
|
27
27
|
* @returns Bundle result with output path and optional master key
|
|
28
28
|
*/
|
|
29
|
+
/** Default env var values for docker compose services */
|
|
30
|
+
const DOCKER_SERVICE_ENV_VARS = {
|
|
31
|
+
postgres: { DATABASE_URL: "postgresql://postgres:postgres@postgres:5432/app" },
|
|
32
|
+
redis: { REDIS_URL: "redis://redis:6379" },
|
|
33
|
+
rabbitmq: { RABBITMQ_URL: "amqp://rabbitmq:5672" }
|
|
34
|
+
};
|
|
29
35
|
async function bundleServer(options) {
|
|
30
|
-
const { entryPoint, outputDir, minify, sourcemap, external, stage, constructs } = options;
|
|
36
|
+
const { entryPoint, outputDir, minify, sourcemap, external, stage, constructs, dockerServices } = options;
|
|
31
37
|
await (0, node_fs_promises.mkdir)(outputDir, { recursive: true });
|
|
32
38
|
const args = [
|
|
33
39
|
"npx",
|
|
@@ -50,10 +56,24 @@ async function bundleServer(options) {
|
|
|
50
56
|
args.push("--external", "node:*");
|
|
51
57
|
let masterKey;
|
|
52
58
|
if (stage) {
|
|
53
|
-
const { readStageSecrets, toEmbeddableSecrets, validateEnvironmentVariables } = await Promise.resolve().then(() => require("./storage-
|
|
54
|
-
const { encryptSecrets, generateDefineOptions } = await Promise.resolve().then(() => require("./encryption-
|
|
55
|
-
|
|
56
|
-
if (!secrets)
|
|
59
|
+
const { readStageSecrets, toEmbeddableSecrets, validateEnvironmentVariables, initStageSecrets, writeStageSecrets } = await Promise.resolve().then(() => require("./storage-UfyTn7Zm.cjs"));
|
|
60
|
+
const { encryptSecrets, generateDefineOptions } = await Promise.resolve().then(() => require("./encryption-D7Efcdi9.cjs"));
|
|
61
|
+
let secrets = await readStageSecrets(stage);
|
|
62
|
+
if (!secrets) {
|
|
63
|
+
console.log(` Initializing secrets for stage "${stage}"...`);
|
|
64
|
+
secrets = initStageSecrets(stage);
|
|
65
|
+
await writeStageSecrets(secrets);
|
|
66
|
+
console.log(` ✓ Created .gkm/secrets/${stage}.json`);
|
|
67
|
+
}
|
|
68
|
+
if (dockerServices) {
|
|
69
|
+
for (const [service, enabled] of Object.entries(dockerServices)) if (enabled && DOCKER_SERVICE_ENV_VARS[service]) for (const [envVar, defaultValue] of Object.entries(DOCKER_SERVICE_ENV_VARS[service])) {
|
|
70
|
+
const urlKey = envVar;
|
|
71
|
+
if (!secrets.urls[urlKey] && !secrets.custom[envVar]) {
|
|
72
|
+
secrets.urls[urlKey] = defaultValue;
|
|
73
|
+
console.log(` Auto-populated ${envVar} from docker compose`);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
57
77
|
if (constructs && constructs.length > 0) {
|
|
58
78
|
console.log(" Analyzing environment variable requirements...");
|
|
59
79
|
const requiredVars = await collectRequiredEnvVars(constructs);
|
|
@@ -84,15 +104,19 @@ async function bundleServer(options) {
|
|
|
84
104
|
const encrypted = encryptSecrets(embeddable);
|
|
85
105
|
masterKey = encrypted.masterKey;
|
|
86
106
|
const defines = generateDefineOptions(encrypted);
|
|
87
|
-
for (const [key, value] of Object.entries(defines)) args.push(
|
|
107
|
+
for (const [key, value] of Object.entries(defines)) args.push(`--env.${key}`, value);
|
|
88
108
|
console.log(` Secrets encrypted for stage "${stage}"`);
|
|
89
109
|
}
|
|
90
110
|
const mjsOutput = (0, node_path.join)(outputDir, "server.mjs");
|
|
91
111
|
try {
|
|
92
|
-
|
|
112
|
+
const [cmd, ...cmdArgs] = args;
|
|
113
|
+
const result = (0, node_child_process.spawnSync)(cmd, cmdArgs, {
|
|
93
114
|
cwd: process.cwd(),
|
|
94
|
-
stdio: "inherit"
|
|
115
|
+
stdio: "inherit",
|
|
116
|
+
shell: process.platform === "win32"
|
|
95
117
|
});
|
|
118
|
+
if (result.error) throw result.error;
|
|
119
|
+
if (result.status !== 0) throw new Error(`tsdown exited with code ${result.status}`);
|
|
96
120
|
const jsOutput = (0, node_path.join)(outputDir, "server.js");
|
|
97
121
|
if ((0, node_fs.existsSync)(jsOutput)) await (0, node_fs_promises.rename)(jsOutput, mjsOutput);
|
|
98
122
|
const { readFile } = await import("node:fs/promises");
|
|
@@ -109,4 +133,4 @@ async function bundleServer(options) {
|
|
|
109
133
|
|
|
110
134
|
//#endregion
|
|
111
135
|
exports.bundleServer = bundleServer;
|
|
112
|
-
//# sourceMappingURL=bundler-
|
|
136
|
+
//# sourceMappingURL=bundler-Nuew7Xcn.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bundler-Nuew7Xcn.cjs","names":["constructs: Construct[]","DOCKER_SERVICE_ENV_VARS: Record<string, Record<string, string>>","options: BundleOptions","masterKey: string | undefined"],"sources":["../src/build/bundler.ts"],"sourcesContent":["import { spawnSync } from 'node:child_process';\nimport { existsSync } from 'node:fs';\nimport { mkdir, rename, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport type { Construct } from '@geekmidas/constructs';\n\nexport interface BundleOptions {\n\t/** Entry point file (e.g., .gkm/server/server.ts) */\n\tentryPoint: string;\n\t/** Output directory for bundled files */\n\toutputDir: string;\n\t/** Minify the output (default: true) */\n\tminify: boolean;\n\t/** Generate sourcemaps (default: false) */\n\tsourcemap: boolean;\n\t/** Packages to exclude from bundling */\n\texternal: string[];\n\t/** Stage for secrets injection (optional) */\n\tstage?: string;\n\t/** Constructs to validate environment variables for */\n\tconstructs?: Construct[];\n\t/** Docker compose services configured (for auto-populating env vars) */\n\tdockerServices?: {\n\t\tpostgres?: boolean;\n\t\tredis?: boolean;\n\t\trabbitmq?: boolean;\n\t};\n}\n\nexport interface BundleResult {\n\t/** Path to the bundled output */\n\toutputPath: string;\n\t/** Ephemeral master key for deployment (only if stage was provided) */\n\tmasterKey?: string;\n}\n\n/**\n * Collect all required environment variables from constructs.\n * Uses the SnifferEnvironmentParser to detect which env vars each service needs.\n *\n * @param constructs - Array of constructs to analyze\n * @returns Deduplicated array of required environment variable names\n */\nasync function collectRequiredEnvVars(\n\tconstructs: Construct[],\n): Promise<string[]> {\n\tconst allEnvVars = new Set<string>();\n\n\tfor (const construct of constructs) {\n\t\tconst envVars = await construct.getEnvironment();\n\t\tenvVars.forEach((v) => allEnvVars.add(v));\n\t}\n\n\treturn Array.from(allEnvVars).sort();\n}\n\n/**\n * Bundle the server application using tsdown\n *\n * @param options - Bundle configuration options\n * @returns Bundle result with output path and optional master key\n */\n/** Default env var values for docker compose services */\nconst DOCKER_SERVICE_ENV_VARS: Record<string, Record<string, string>> = {\n\tpostgres: {\n\t\tDATABASE_URL: 'postgresql://postgres:postgres@postgres:5432/app',\n\t},\n\tredis: {\n\t\tREDIS_URL: 'redis://redis:6379',\n\t},\n\trabbitmq: {\n\t\tRABBITMQ_URL: 'amqp://rabbitmq:5672',\n\t},\n};\n\nexport async function bundleServer(\n\toptions: BundleOptions,\n): Promise<BundleResult> {\n\tconst {\n\t\tentryPoint,\n\t\toutputDir,\n\t\tminify,\n\t\tsourcemap,\n\t\texternal,\n\t\tstage,\n\t\tconstructs,\n\t\tdockerServices,\n\t} = options;\n\n\t// Ensure output directory exists\n\tawait mkdir(outputDir, { recursive: true });\n\n\t// Build command-line arguments for tsdown\n\tconst args = [\n\t\t'npx',\n\t\t'tsdown',\n\t\tentryPoint,\n\t\t'--no-config', // Don't use any config file from workspace\n\t\t'--out-dir',\n\t\toutputDir,\n\t\t'--format',\n\t\t'esm',\n\t\t'--platform',\n\t\t'node',\n\t\t'--target',\n\t\t'node22',\n\t\t'--clean',\n\t];\n\n\tif (minify) {\n\t\targs.push('--minify');\n\t}\n\n\tif (sourcemap) {\n\t\targs.push('--sourcemap');\n\t}\n\n\t// Add external packages\n\tfor (const ext of external) {\n\t\targs.push('--external', ext);\n\t}\n\n\t// Always exclude node: builtins\n\targs.push('--external', 'node:*');\n\n\t// Handle secrets injection if stage is provided\n\tlet masterKey: string | undefined;\n\n\tif (stage) {\n\t\tconst {\n\t\t\treadStageSecrets,\n\t\t\ttoEmbeddableSecrets,\n\t\t\tvalidateEnvironmentVariables,\n\t\t\tinitStageSecrets,\n\t\t\twriteStageSecrets,\n\t\t} = await import('../secrets/storage');\n\t\tconst { encryptSecrets, generateDefineOptions } = await import(\n\t\t\t'../secrets/encryption'\n\t\t);\n\n\t\tlet secrets = await readStageSecrets(stage);\n\n\t\tif (!secrets) {\n\t\t\t// Auto-initialize secrets for the stage\n\t\t\tconsole.log(` Initializing secrets for stage \"${stage}\"...`);\n\t\t\tsecrets = initStageSecrets(stage);\n\t\t\tawait writeStageSecrets(secrets);\n\t\t\tconsole.log(` ✓ Created .gkm/secrets/${stage}.json`);\n\t\t}\n\n\t\t// Auto-populate env vars from docker compose services\n\t\tif (dockerServices) {\n\t\t\tfor (const [service, enabled] of Object.entries(dockerServices)) {\n\t\t\t\tif (enabled && DOCKER_SERVICE_ENV_VARS[service]) {\n\t\t\t\t\tfor (const [envVar, defaultValue] of Object.entries(\n\t\t\t\t\t\tDOCKER_SERVICE_ENV_VARS[service],\n\t\t\t\t\t)) {\n\t\t\t\t\t\t// Check if not already in urls or custom\n\t\t\t\t\t\tconst urlKey = envVar as keyof typeof secrets.urls;\n\t\t\t\t\t\tif (!secrets.urls[urlKey] && !secrets.custom[envVar]) {\n\t\t\t\t\t\t\tsecrets.urls[urlKey] = defaultValue;\n\t\t\t\t\t\t\tconsole.log(` Auto-populated ${envVar} from docker compose`);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Validate environment variables if constructs are provided\n\t\tif (constructs && constructs.length > 0) {\n\t\t\tconsole.log(' Analyzing environment variable requirements...');\n\t\t\tconst requiredVars = await collectRequiredEnvVars(constructs);\n\n\t\t\tif (requiredVars.length > 0) {\n\t\t\t\tconst validation = validateEnvironmentVariables(requiredVars, secrets);\n\n\t\t\t\tif (!validation.valid) {\n\t\t\t\t\tconst errorMessage = [\n\t\t\t\t\t\t`Missing environment variables for stage \"${stage}\":`,\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t...validation.missing.map((v) => ` ❌ ${v}`),\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t'To fix this, either:',\n\t\t\t\t\t\t` 1. Add the missing variables to .gkm/secrets/${stage}.json using:`,\n\t\t\t\t\t\t` gkm secrets:set <KEY> <VALUE> --stage ${stage}`,\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t` 2. Or import from a JSON file:`,\n\t\t\t\t\t\t` gkm secrets:import secrets.json --stage ${stage}`,\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t'Required variables:',\n\t\t\t\t\t\t...validation.required.map((v) =>\n\t\t\t\t\t\t\tvalidation.missing.includes(v) ? ` ❌ ${v}` : ` ✓ ${v}`,\n\t\t\t\t\t\t),\n\t\t\t\t\t].join('\\n');\n\n\t\t\t\t\tthrow new Error(errorMessage);\n\t\t\t\t}\n\n\t\t\t\tconsole.log(\n\t\t\t\t\t` ✓ All ${requiredVars.length} required environment variables found`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\t// Convert to embeddable format and encrypt\n\t\tconst embeddable = toEmbeddableSecrets(secrets);\n\t\tconst encrypted = encryptSecrets(embeddable);\n\t\tmasterKey = encrypted.masterKey;\n\n\t\t// Add define options for build-time injection using tsdown's --env.* format\n\t\tconst defines = generateDefineOptions(encrypted);\n\t\tfor (const [key, value] of Object.entries(defines)) {\n\t\t\targs.push(`--env.${key}`, value);\n\t\t}\n\n\t\tconsole.log(` Secrets encrypted for stage \"${stage}\"`);\n\t}\n\n\tconst mjsOutput = join(outputDir, 'server.mjs');\n\n\ttry {\n\t\t// Run tsdown with command-line arguments\n\t\t// Use spawnSync with args array to avoid shell escaping issues with --define values\n\t\t// args is always populated with ['npx', 'tsdown', ...] so cmd is never undefined\n\t\tconst [cmd, ...cmdArgs] = args as [string, ...string[]];\n\t\tconst result = spawnSync(cmd, cmdArgs, {\n\t\t\tcwd: process.cwd(),\n\t\t\tstdio: 'inherit',\n\t\t\tshell: process.platform === 'win32', // Only use shell on Windows for npx resolution\n\t\t});\n\n\t\tif (result.error) {\n\t\t\tthrow result.error;\n\t\t}\n\t\tif (result.status !== 0) {\n\t\t\tthrow new Error(`tsdown exited with code ${result.status}`);\n\t\t}\n\n\t\t// Rename output to .mjs for explicit ESM\n\t\t// tsdown outputs as server.js for ESM format\n\t\tconst jsOutput = join(outputDir, 'server.js');\n\n\t\tif (existsSync(jsOutput)) {\n\t\t\tawait rename(jsOutput, mjsOutput);\n\t\t}\n\n\t\t// Add shebang to the bundled file\n\t\tconst { readFile } = await import('node:fs/promises');\n\t\tconst content = await readFile(mjsOutput, 'utf-8');\n\t\tif (!content.startsWith('#!')) {\n\t\t\tawait writeFile(mjsOutput, `#!/usr/bin/env node\\n${content}`);\n\t\t}\n\t} catch (error) {\n\t\tthrow new Error(\n\t\t\t`Failed to bundle server: ${error instanceof Error ? error.message : 'Unknown error'}`,\n\t\t);\n\t}\n\n\treturn {\n\t\toutputPath: mjsOutput,\n\t\tmasterKey,\n\t};\n}\n"],"mappings":"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"}
|
package/dist/config.d.cts
CHANGED
package/dist/config.d.mts
CHANGED
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
|
|
2
|
+
//#region src/deploy/dokploy-api.ts
|
|
3
|
+
var DokployApiError = class extends Error {
|
|
4
|
+
constructor(message, status, statusText, issues) {
|
|
5
|
+
super(message);
|
|
6
|
+
this.status = status;
|
|
7
|
+
this.statusText = statusText;
|
|
8
|
+
this.issues = issues;
|
|
9
|
+
this.name = "DokployApiError";
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Dokploy API client
|
|
14
|
+
*/
|
|
15
|
+
var DokployApi = class {
|
|
16
|
+
baseUrl;
|
|
17
|
+
token;
|
|
18
|
+
constructor(options) {
|
|
19
|
+
this.baseUrl = options.baseUrl.replace(/\/$/, "");
|
|
20
|
+
this.token = options.token;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Make a GET request to the Dokploy API
|
|
24
|
+
*/
|
|
25
|
+
async get(endpoint) {
|
|
26
|
+
return this.request("GET", endpoint);
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Make a POST request to the Dokploy API
|
|
30
|
+
*/
|
|
31
|
+
async post(endpoint, body) {
|
|
32
|
+
return this.request("POST", endpoint, body);
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Make a request to the Dokploy API
|
|
36
|
+
*/
|
|
37
|
+
async request(method, endpoint, body) {
|
|
38
|
+
const url = `${this.baseUrl}/api/${endpoint}`;
|
|
39
|
+
const response = await fetch(url, {
|
|
40
|
+
method,
|
|
41
|
+
headers: {
|
|
42
|
+
"Content-Type": "application/json",
|
|
43
|
+
"x-api-key": this.token
|
|
44
|
+
},
|
|
45
|
+
body: body ? JSON.stringify(body) : void 0
|
|
46
|
+
});
|
|
47
|
+
if (!response.ok) {
|
|
48
|
+
let errorMessage = `Dokploy API error: ${response.status} ${response.statusText}`;
|
|
49
|
+
let issues;
|
|
50
|
+
try {
|
|
51
|
+
const errorBody = await response.json();
|
|
52
|
+
if (errorBody.message) errorMessage = `Dokploy API error: ${errorBody.message}`;
|
|
53
|
+
if (errorBody.issues?.length) {
|
|
54
|
+
issues = errorBody.issues;
|
|
55
|
+
errorMessage += `\n Issues: ${errorBody.issues.map((i) => i.message).join(", ")}`;
|
|
56
|
+
}
|
|
57
|
+
} catch {}
|
|
58
|
+
throw new DokployApiError(errorMessage, response.status, response.statusText, issues);
|
|
59
|
+
}
|
|
60
|
+
const text = await response.text();
|
|
61
|
+
if (!text || text.trim() === "") return void 0;
|
|
62
|
+
return JSON.parse(text);
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Validate the API token by making a test request
|
|
66
|
+
*/
|
|
67
|
+
async validateToken() {
|
|
68
|
+
try {
|
|
69
|
+
await this.get("project.all");
|
|
70
|
+
return true;
|
|
71
|
+
} catch {
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* List all projects
|
|
77
|
+
*/
|
|
78
|
+
async listProjects() {
|
|
79
|
+
return this.get("project.all");
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Get a single project by ID
|
|
83
|
+
*/
|
|
84
|
+
async getProject(projectId) {
|
|
85
|
+
return this.get(`project.one?projectId=${projectId}`);
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Create a new project
|
|
89
|
+
*/
|
|
90
|
+
async createProject(name, description) {
|
|
91
|
+
return this.post("project.create", {
|
|
92
|
+
name,
|
|
93
|
+
description: description ?? `Created by gkm CLI`
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Create an environment in a project
|
|
98
|
+
*/
|
|
99
|
+
async createEnvironment(projectId, name, description) {
|
|
100
|
+
return this.post("environment.create", {
|
|
101
|
+
projectId,
|
|
102
|
+
name,
|
|
103
|
+
description: description ?? `${name} environment`
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Create a new application
|
|
108
|
+
*/
|
|
109
|
+
async createApplication(name, projectId, environmentId) {
|
|
110
|
+
return this.post("application.create", {
|
|
111
|
+
name,
|
|
112
|
+
projectId,
|
|
113
|
+
environmentId,
|
|
114
|
+
appName: name.toLowerCase().replace(/[^a-z0-9-]/g, "-")
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Update an application
|
|
119
|
+
*/
|
|
120
|
+
async updateApplication(applicationId, updates) {
|
|
121
|
+
await this.post("application.update", {
|
|
122
|
+
applicationId,
|
|
123
|
+
...updates
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Save environment variables for an application
|
|
128
|
+
*/
|
|
129
|
+
async saveApplicationEnv(applicationId, env) {
|
|
130
|
+
await this.post("application.saveEnvironment", {
|
|
131
|
+
applicationId,
|
|
132
|
+
env
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Configure application to use Docker provider (pull from registry)
|
|
137
|
+
*
|
|
138
|
+
* For private registries, either:
|
|
139
|
+
* - Use `registryId` if the registry is configured in Dokploy
|
|
140
|
+
* - Or provide `username`, `password`, and `registryUrl` directly
|
|
141
|
+
*/
|
|
142
|
+
async saveDockerProvider(applicationId, dockerImage, options) {
|
|
143
|
+
await this.post("application.saveDockerProvider", {
|
|
144
|
+
applicationId,
|
|
145
|
+
dockerImage,
|
|
146
|
+
...options
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Deploy an application
|
|
151
|
+
*/
|
|
152
|
+
async deployApplication(applicationId) {
|
|
153
|
+
await this.post("application.deploy", { applicationId });
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* List all registries
|
|
157
|
+
*/
|
|
158
|
+
async listRegistries() {
|
|
159
|
+
return this.get("registry.all");
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Create a new registry
|
|
163
|
+
*/
|
|
164
|
+
async createRegistry(registryName, registryUrl, username, password, options) {
|
|
165
|
+
return this.post("registry.create", {
|
|
166
|
+
registryName,
|
|
167
|
+
registryUrl,
|
|
168
|
+
username,
|
|
169
|
+
password,
|
|
170
|
+
imagePrefix: options?.imagePrefix
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Get a registry by ID
|
|
175
|
+
*/
|
|
176
|
+
async getRegistry(registryId) {
|
|
177
|
+
return this.get(`registry.one?registryId=${registryId}`);
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Update a registry
|
|
181
|
+
*/
|
|
182
|
+
async updateRegistry(registryId, updates) {
|
|
183
|
+
await this.post("registry.update", {
|
|
184
|
+
registryId,
|
|
185
|
+
...updates
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Delete a registry
|
|
190
|
+
*/
|
|
191
|
+
async deleteRegistry(registryId) {
|
|
192
|
+
await this.post("registry.remove", { registryId });
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Create a new Postgres database
|
|
196
|
+
*/
|
|
197
|
+
async createPostgres(name, projectId, environmentId, options) {
|
|
198
|
+
return this.post("postgres.create", {
|
|
199
|
+
name,
|
|
200
|
+
projectId,
|
|
201
|
+
environmentId,
|
|
202
|
+
appName: options?.appName ?? name.toLowerCase().replace(/[^a-z0-9-]/g, "-"),
|
|
203
|
+
databaseName: options?.databaseName ?? "app",
|
|
204
|
+
databaseUser: options?.databaseUser ?? "postgres",
|
|
205
|
+
databasePassword: options?.databasePassword,
|
|
206
|
+
dockerImage: options?.dockerImage ?? "postgres:16-alpine",
|
|
207
|
+
description: options?.description ?? `Postgres database for ${name}`
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Get a Postgres database by ID
|
|
212
|
+
*/
|
|
213
|
+
async getPostgres(postgresId) {
|
|
214
|
+
return this.get(`postgres.one?postgresId=${postgresId}`);
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Deploy a Postgres database
|
|
218
|
+
*/
|
|
219
|
+
async deployPostgres(postgresId) {
|
|
220
|
+
await this.post("postgres.deploy", { postgresId });
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Save environment variables for Postgres
|
|
224
|
+
*/
|
|
225
|
+
async savePostgresEnv(postgresId, env) {
|
|
226
|
+
await this.post("postgres.saveEnvironment", {
|
|
227
|
+
postgresId,
|
|
228
|
+
env
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* Set external port for Postgres (for external access)
|
|
233
|
+
*/
|
|
234
|
+
async savePostgresExternalPort(postgresId, externalPort) {
|
|
235
|
+
await this.post("postgres.saveExternalPort", {
|
|
236
|
+
postgresId,
|
|
237
|
+
externalPort
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Update Postgres configuration
|
|
242
|
+
*/
|
|
243
|
+
async updatePostgres(postgresId, updates) {
|
|
244
|
+
await this.post("postgres.update", {
|
|
245
|
+
postgresId,
|
|
246
|
+
...updates
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Create a new Redis instance
|
|
251
|
+
*/
|
|
252
|
+
async createRedis(name, projectId, environmentId, options) {
|
|
253
|
+
return this.post("redis.create", {
|
|
254
|
+
name,
|
|
255
|
+
projectId,
|
|
256
|
+
environmentId,
|
|
257
|
+
appName: options?.appName ?? name.toLowerCase().replace(/[^a-z0-9-]/g, "-"),
|
|
258
|
+
databasePassword: options?.databasePassword,
|
|
259
|
+
dockerImage: options?.dockerImage ?? "redis:7-alpine",
|
|
260
|
+
description: options?.description ?? `Redis instance for ${name}`
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* Get a Redis instance by ID
|
|
265
|
+
*/
|
|
266
|
+
async getRedis(redisId) {
|
|
267
|
+
return this.get(`redis.one?redisId=${redisId}`);
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* Deploy a Redis instance
|
|
271
|
+
*/
|
|
272
|
+
async deployRedis(redisId) {
|
|
273
|
+
await this.post("redis.deploy", { redisId });
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Save environment variables for Redis
|
|
277
|
+
*/
|
|
278
|
+
async saveRedisEnv(redisId, env) {
|
|
279
|
+
await this.post("redis.saveEnvironment", {
|
|
280
|
+
redisId,
|
|
281
|
+
env
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* Set external port for Redis (for external access)
|
|
286
|
+
*/
|
|
287
|
+
async saveRedisExternalPort(redisId, externalPort) {
|
|
288
|
+
await this.post("redis.saveExternalPort", {
|
|
289
|
+
redisId,
|
|
290
|
+
externalPort
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* Update Redis configuration
|
|
295
|
+
*/
|
|
296
|
+
async updateRedis(redisId, updates) {
|
|
297
|
+
await this.post("redis.update", {
|
|
298
|
+
redisId,
|
|
299
|
+
...updates
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
};
|
|
303
|
+
|
|
304
|
+
//#endregion
|
|
305
|
+
Object.defineProperty(exports, 'DokployApi', {
|
|
306
|
+
enumerable: true,
|
|
307
|
+
get: function () {
|
|
308
|
+
return DokployApi;
|
|
309
|
+
}
|
|
310
|
+
});
|
|
311
|
+
Object.defineProperty(exports, 'DokployApiError', {
|
|
312
|
+
enumerable: true,
|
|
313
|
+
get: function () {
|
|
314
|
+
return DokployApiError;
|
|
315
|
+
}
|
|
316
|
+
});
|
|
317
|
+
//# sourceMappingURL=dokploy-api-C7F9VykY.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dokploy-api-C7F9VykY.cjs","names":["message: string","status: number","statusText: string","issues?: Array<{ message: string }>","options: DokployApiOptions","endpoint: string","body?: Record<string, unknown>","method: 'GET' | 'POST' | 'PUT' | 'DELETE'","issues: Array<{ message: string }> | undefined","projectId: string","name: string","description?: string","environmentId: string","applicationId: string","updates: Partial<DokployApplicationUpdate>","env: string","dockerImage: string","options?: {\n\t\t\t/** Registry ID in Dokploy (for pre-configured registries) */\n\t\t\tregistryId?: string;\n\t\t\t/** Registry username (for direct auth) */\n\t\t\tusername?: string;\n\t\t\t/** Registry password (for direct auth) */\n\t\t\tpassword?: string;\n\t\t\t/** Registry URL (for direct auth, e.g., ghcr.io) */\n\t\t\tregistryUrl?: string;\n\t\t}","registryName: string","registryUrl: string","username: string","password: string","options?: {\n\t\t\timagePrefix?: string;\n\t\t}","registryId: string","updates: Partial<{\n\t\t\tregistryName: string;\n\t\t\tregistryUrl: string;\n\t\t\tusername: string;\n\t\t\tpassword: string;\n\t\t\timagePrefix: string;\n\t\t}>","options?: {\n\t\t\tappName?: string;\n\t\t\tdatabaseName?: string;\n\t\t\tdatabaseUser?: string;\n\t\t\tdatabasePassword?: string;\n\t\t\tdockerImage?: string;\n\t\t\tdescription?: string;\n\t\t}","postgresId: string","externalPort: number | null","updates: Partial<DokployPostgresUpdate>","options?: {\n\t\t\tappName?: string;\n\t\t\tdatabasePassword?: string;\n\t\t\tdockerImage?: string;\n\t\t\tdescription?: string;\n\t\t}","redisId: string","updates: Partial<DokployRedisUpdate>"],"sources":["../src/deploy/dokploy-api.ts"],"sourcesContent":["/**\n * Centralized Dokploy API client\n *\n * Handles authentication, error handling, and provides typed methods for all Dokploy API endpoints.\n */\n\nexport interface DokployApiOptions {\n\t/** Dokploy server URL (e.g., https://dokploy.example.com) */\n\tbaseUrl: string;\n\t/** API token for authentication */\n\ttoken: string;\n}\n\nexport interface DokployErrorResponse {\n\tmessage?: string;\n\tissues?: Array<{ message: string }>;\n}\n\nexport class DokployApiError extends Error {\n\tconstructor(\n\t\tmessage: string,\n\t\tpublic status: number,\n\t\tpublic statusText: string,\n\t\tpublic issues?: Array<{ message: string }>,\n\t) {\n\t\tsuper(message);\n\t\tthis.name = 'DokployApiError';\n\t}\n}\n\n/**\n * Dokploy API client\n */\nexport class DokployApi {\n\tprivate baseUrl: string;\n\tprivate token: string;\n\n\tconstructor(options: DokployApiOptions) {\n\t\tthis.baseUrl = options.baseUrl.replace(/\\/$/, ''); // Remove trailing slash\n\t\tthis.token = options.token;\n\t}\n\n\t/**\n\t * Make a GET request to the Dokploy API\n\t */\n\tasync get<T>(endpoint: string): Promise<T> {\n\t\treturn this.request<T>('GET', endpoint);\n\t}\n\n\t/**\n\t * Make a POST request to the Dokploy API\n\t */\n\tasync post<T>(endpoint: string, body?: Record<string, unknown>): Promise<T> {\n\t\treturn this.request<T>('POST', endpoint, body);\n\t}\n\n\t/**\n\t * Make a request to the Dokploy API\n\t */\n\tprivate async request<T>(\n\t\tmethod: 'GET' | 'POST' | 'PUT' | 'DELETE',\n\t\tendpoint: string,\n\t\tbody?: Record<string, unknown>,\n\t): Promise<T> {\n\t\tconst url = `${this.baseUrl}/api/${endpoint}`;\n\n\t\tconst response = await fetch(url, {\n\t\t\tmethod,\n\t\t\theaders: {\n\t\t\t\t'Content-Type': 'application/json',\n\t\t\t\t'x-api-key': this.token,\n\t\t\t},\n\t\t\tbody: body ? JSON.stringify(body) : undefined,\n\t\t});\n\n\t\tif (!response.ok) {\n\t\t\tlet errorMessage = `Dokploy API error: ${response.status} ${response.statusText}`;\n\t\t\tlet issues: Array<{ message: string }> | undefined;\n\n\t\t\ttry {\n\t\t\t\tconst errorBody = (await response.json()) as DokployErrorResponse;\n\t\t\t\tif (errorBody.message) {\n\t\t\t\t\terrorMessage = `Dokploy API error: ${errorBody.message}`;\n\t\t\t\t}\n\t\t\t\tif (errorBody.issues?.length) {\n\t\t\t\t\tissues = errorBody.issues;\n\t\t\t\t\terrorMessage += `\\n Issues: ${errorBody.issues.map((i) => i.message).join(', ')}`;\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\t// Ignore JSON parse errors\n\t\t\t}\n\n\t\t\tthrow new DokployApiError(\n\t\t\t\terrorMessage,\n\t\t\t\tresponse.status,\n\t\t\t\tresponse.statusText,\n\t\t\t\tissues,\n\t\t\t);\n\t\t}\n\n\t\t// Handle empty responses (204 No Content or empty body)\n\t\tconst text = await response.text();\n\t\tif (!text || text.trim() === '') {\n\t\t\treturn undefined as T;\n\t\t}\n\t\treturn JSON.parse(text) as T;\n\t}\n\n\t/**\n\t * Validate the API token by making a test request\n\t */\n\tasync validateToken(): Promise<boolean> {\n\t\ttry {\n\t\t\tawait this.get('project.all');\n\t\t\treturn true;\n\t\t} catch {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t// ============================================\n\t// Project endpoints\n\t// ============================================\n\n\t/**\n\t * List all projects\n\t */\n\tasync listProjects(): Promise<DokployProject[]> {\n\t\treturn this.get<DokployProject[]>('project.all');\n\t}\n\n\t/**\n\t * Get a single project by ID\n\t */\n\tasync getProject(projectId: string): Promise<DokployProjectDetails> {\n\t\treturn this.get<DokployProjectDetails>(\n\t\t\t`project.one?projectId=${projectId}`,\n\t\t);\n\t}\n\n\t/**\n\t * Create a new project\n\t */\n\tasync createProject(\n\t\tname: string,\n\t\tdescription?: string,\n\t): Promise<{ project: DokployProject; environment: DokployEnvironment }> {\n\t\treturn this.post<{\n\t\t\tproject: DokployProject;\n\t\t\tenvironment: DokployEnvironment;\n\t\t}>('project.create', {\n\t\t\tname,\n\t\t\tdescription: description ?? `Created by gkm CLI`,\n\t\t});\n\t}\n\n\t// ============================================\n\t// Environment endpoints\n\t// ============================================\n\n\t/**\n\t * Create an environment in a project\n\t */\n\tasync createEnvironment(\n\t\tprojectId: string,\n\t\tname: string,\n\t\tdescription?: string,\n\t): Promise<DokployEnvironment> {\n\t\treturn this.post<DokployEnvironment>('environment.create', {\n\t\t\tprojectId,\n\t\t\tname,\n\t\t\tdescription: description ?? `${name} environment`,\n\t\t});\n\t}\n\n\t// ============================================\n\t// Application endpoints\n\t// ============================================\n\n\t/**\n\t * Create a new application\n\t */\n\tasync createApplication(\n\t\tname: string,\n\t\tprojectId: string,\n\t\tenvironmentId: string,\n\t): Promise<DokployApplication> {\n\t\treturn this.post<DokployApplication>('application.create', {\n\t\t\tname,\n\t\t\tprojectId,\n\t\t\tenvironmentId,\n\t\t\tappName: name.toLowerCase().replace(/[^a-z0-9-]/g, '-'),\n\t\t});\n\t}\n\n\t/**\n\t * Update an application\n\t */\n\tasync updateApplication(\n\t\tapplicationId: string,\n\t\tupdates: Partial<DokployApplicationUpdate>,\n\t): Promise<void> {\n\t\tawait this.post('application.update', {\n\t\t\tapplicationId,\n\t\t\t...updates,\n\t\t});\n\t}\n\n\t/**\n\t * Save environment variables for an application\n\t */\n\tasync saveApplicationEnv(applicationId: string, env: string): Promise<void> {\n\t\tawait this.post('application.saveEnvironment', {\n\t\t\tapplicationId,\n\t\t\tenv,\n\t\t});\n\t}\n\n\t/**\n\t * Configure application to use Docker provider (pull from registry)\n\t *\n\t * For private registries, either:\n\t * - Use `registryId` if the registry is configured in Dokploy\n\t * - Or provide `username`, `password`, and `registryUrl` directly\n\t */\n\tasync saveDockerProvider(\n\t\tapplicationId: string,\n\t\tdockerImage: string,\n\t\toptions?: {\n\t\t\t/** Registry ID in Dokploy (for pre-configured registries) */\n\t\t\tregistryId?: string;\n\t\t\t/** Registry username (for direct auth) */\n\t\t\tusername?: string;\n\t\t\t/** Registry password (for direct auth) */\n\t\t\tpassword?: string;\n\t\t\t/** Registry URL (for direct auth, e.g., ghcr.io) */\n\t\t\tregistryUrl?: string;\n\t\t},\n\t): Promise<void> {\n\t\tawait this.post('application.saveDockerProvider', {\n\t\t\tapplicationId,\n\t\t\tdockerImage,\n\t\t\t...options,\n\t\t});\n\t}\n\n\t/**\n\t * Deploy an application\n\t */\n\tasync deployApplication(applicationId: string): Promise<void> {\n\t\tawait this.post('application.deploy', { applicationId });\n\t}\n\n\t// ============================================\n\t// Registry endpoints\n\t// ============================================\n\n\t/**\n\t * List all registries\n\t */\n\tasync listRegistries(): Promise<DokployRegistry[]> {\n\t\treturn this.get<DokployRegistry[]>('registry.all');\n\t}\n\n\t/**\n\t * Create a new registry\n\t */\n\tasync createRegistry(\n\t\tregistryName: string,\n\t\tregistryUrl: string,\n\t\tusername: string,\n\t\tpassword: string,\n\t\toptions?: {\n\t\t\timagePrefix?: string;\n\t\t},\n\t): Promise<DokployRegistry> {\n\t\treturn this.post<DokployRegistry>('registry.create', {\n\t\t\tregistryName,\n\t\t\tregistryUrl,\n\t\t\tusername,\n\t\t\tpassword,\n\t\t\timagePrefix: options?.imagePrefix,\n\t\t});\n\t}\n\n\t/**\n\t * Get a registry by ID\n\t */\n\tasync getRegistry(registryId: string): Promise<DokployRegistry> {\n\t\treturn this.get<DokployRegistry>(`registry.one?registryId=${registryId}`);\n\t}\n\n\t/**\n\t * Update a registry\n\t */\n\tasync updateRegistry(\n\t\tregistryId: string,\n\t\tupdates: Partial<{\n\t\t\tregistryName: string;\n\t\t\tregistryUrl: string;\n\t\t\tusername: string;\n\t\t\tpassword: string;\n\t\t\timagePrefix: string;\n\t\t}>,\n\t): Promise<void> {\n\t\tawait this.post('registry.update', { registryId, ...updates });\n\t}\n\n\t/**\n\t * Delete a registry\n\t */\n\tasync deleteRegistry(registryId: string): Promise<void> {\n\t\tawait this.post('registry.remove', { registryId });\n\t}\n\n\t// ============================================\n\t// Postgres endpoints\n\t// ============================================\n\n\t/**\n\t * Create a new Postgres database\n\t */\n\tasync createPostgres(\n\t\tname: string,\n\t\tprojectId: string,\n\t\tenvironmentId: string,\n\t\toptions?: {\n\t\t\tappName?: string;\n\t\t\tdatabaseName?: string;\n\t\t\tdatabaseUser?: string;\n\t\t\tdatabasePassword?: string;\n\t\t\tdockerImage?: string;\n\t\t\tdescription?: string;\n\t\t},\n\t): Promise<DokployPostgres> {\n\t\treturn this.post<DokployPostgres>('postgres.create', {\n\t\t\tname,\n\t\t\tprojectId,\n\t\t\tenvironmentId,\n\t\t\tappName:\n\t\t\t\toptions?.appName ?? name.toLowerCase().replace(/[^a-z0-9-]/g, '-'),\n\t\t\tdatabaseName: options?.databaseName ?? 'app',\n\t\t\tdatabaseUser: options?.databaseUser ?? 'postgres',\n\t\t\tdatabasePassword: options?.databasePassword,\n\t\t\tdockerImage: options?.dockerImage ?? 'postgres:16-alpine',\n\t\t\tdescription: options?.description ?? `Postgres database for ${name}`,\n\t\t});\n\t}\n\n\t/**\n\t * Get a Postgres database by ID\n\t */\n\tasync getPostgres(postgresId: string): Promise<DokployPostgres> {\n\t\treturn this.get<DokployPostgres>(`postgres.one?postgresId=${postgresId}`);\n\t}\n\n\t/**\n\t * Deploy a Postgres database\n\t */\n\tasync deployPostgres(postgresId: string): Promise<void> {\n\t\tawait this.post('postgres.deploy', { postgresId });\n\t}\n\n\t/**\n\t * Save environment variables for Postgres\n\t */\n\tasync savePostgresEnv(postgresId: string, env: string): Promise<void> {\n\t\tawait this.post('postgres.saveEnvironment', { postgresId, env });\n\t}\n\n\t/**\n\t * Set external port for Postgres (for external access)\n\t */\n\tasync savePostgresExternalPort(\n\t\tpostgresId: string,\n\t\texternalPort: number | null,\n\t): Promise<void> {\n\t\tawait this.post('postgres.saveExternalPort', { postgresId, externalPort });\n\t}\n\n\t/**\n\t * Update Postgres configuration\n\t */\n\tasync updatePostgres(\n\t\tpostgresId: string,\n\t\tupdates: Partial<DokployPostgresUpdate>,\n\t): Promise<void> {\n\t\tawait this.post('postgres.update', { postgresId, ...updates });\n\t}\n\n\t// ============================================\n\t// Redis endpoints\n\t// ============================================\n\n\t/**\n\t * Create a new Redis instance\n\t */\n\tasync createRedis(\n\t\tname: string,\n\t\tprojectId: string,\n\t\tenvironmentId: string,\n\t\toptions?: {\n\t\t\tappName?: string;\n\t\t\tdatabasePassword?: string;\n\t\t\tdockerImage?: string;\n\t\t\tdescription?: string;\n\t\t},\n\t): Promise<DokployRedis> {\n\t\treturn this.post<DokployRedis>('redis.create', {\n\t\t\tname,\n\t\t\tprojectId,\n\t\t\tenvironmentId,\n\t\t\tappName:\n\t\t\t\toptions?.appName ?? name.toLowerCase().replace(/[^a-z0-9-]/g, '-'),\n\t\t\tdatabasePassword: options?.databasePassword,\n\t\t\tdockerImage: options?.dockerImage ?? 'redis:7-alpine',\n\t\t\tdescription: options?.description ?? `Redis instance for ${name}`,\n\t\t});\n\t}\n\n\t/**\n\t * Get a Redis instance by ID\n\t */\n\tasync getRedis(redisId: string): Promise<DokployRedis> {\n\t\treturn this.get<DokployRedis>(`redis.one?redisId=${redisId}`);\n\t}\n\n\t/**\n\t * Deploy a Redis instance\n\t */\n\tasync deployRedis(redisId: string): Promise<void> {\n\t\tawait this.post('redis.deploy', { redisId });\n\t}\n\n\t/**\n\t * Save environment variables for Redis\n\t */\n\tasync saveRedisEnv(redisId: string, env: string): Promise<void> {\n\t\tawait this.post('redis.saveEnvironment', { redisId, env });\n\t}\n\n\t/**\n\t * Set external port for Redis (for external access)\n\t */\n\tasync saveRedisExternalPort(\n\t\tredisId: string,\n\t\texternalPort: number | null,\n\t): Promise<void> {\n\t\tawait this.post('redis.saveExternalPort', { redisId, externalPort });\n\t}\n\n\t/**\n\t * Update Redis configuration\n\t */\n\tasync updateRedis(\n\t\tredisId: string,\n\t\tupdates: Partial<DokployRedisUpdate>,\n\t): Promise<void> {\n\t\tawait this.post('redis.update', { redisId, ...updates });\n\t}\n}\n\n// ============================================\n// Type definitions for Dokploy API responses\n// ============================================\n\nexport interface DokployProject {\n\tprojectId: string;\n\tname: string;\n\tdescription: string | null;\n\tcreatedAt?: string;\n\tadminId?: string;\n}\n\nexport interface DokployEnvironment {\n\tenvironmentId: string;\n\tname: string;\n\tdescription: string | null;\n}\n\nexport interface DokployProjectDetails extends DokployProject {\n\tenvironments: DokployEnvironment[];\n}\n\nexport interface DokployApplication {\n\tapplicationId: string;\n\tname: string;\n\tappName: string;\n\tprojectId: string;\n\tenvironmentId?: string;\n}\n\nexport interface DokployApplicationUpdate {\n\tregistryId: string;\n\tdockerImage: string;\n\tsourceType: 'docker';\n}\n\nexport interface DokployRegistry {\n\tregistryId: string;\n\tregistryName: string;\n\tregistryUrl: string;\n\tusername: string;\n\timagePrefix: string | null;\n}\n\nexport interface DokployPostgres {\n\tpostgresId: string;\n\tname: string;\n\tappName: string;\n\tdatabaseName: string;\n\tdatabaseUser: string;\n\tdatabasePassword: string;\n\tdockerImage: string;\n\tdescription: string | null;\n\tprojectId: string;\n\tenvironmentId: string;\n\tapplicationStatus: 'idle' | 'running' | 'done' | 'error';\n\texternalPort: number | null;\n\tcreatedAt?: string;\n}\n\nexport interface DokployPostgresUpdate {\n\tname: string;\n\tappName: string;\n\tdatabaseName: string;\n\tdatabaseUser: string;\n\tdatabasePassword: string;\n\tdockerImage: string;\n\tdescription: string;\n}\n\nexport interface DokployRedis {\n\tredisId: string;\n\tname: string;\n\tappName: string;\n\tdatabasePassword: string;\n\tdockerImage: string;\n\tdescription: string | null;\n\tprojectId: string;\n\tenvironmentId: string;\n\tapplicationStatus: 'idle' | 'running' | 'done' | 'error';\n\texternalPort: number | null;\n\tcreatedAt?: string;\n}\n\nexport interface DokployRedisUpdate {\n\tname: string;\n\tappName: string;\n\tdatabasePassword: string;\n\tdockerImage: string;\n\tdescription: string;\n}\n\n/**\n * Create a Dokploy API client from stored credentials or environment\n */\nexport async function createDokployApi(\n\tendpoint?: string,\n): Promise<DokployApi | null> {\n\tconst { getDokployCredentials } = await import('../auth/credentials');\n\n\t// Try environment variable first\n\tconst envToken = process.env.DOKPLOY_API_TOKEN;\n\tconst envEndpoint = endpoint || process.env.DOKPLOY_ENDPOINT;\n\n\tif (envToken && envEndpoint) {\n\t\treturn new DokployApi({ baseUrl: envEndpoint, token: envToken });\n\t}\n\n\t// Fall back to stored credentials\n\tconst creds = await getDokployCredentials();\n\tif (creds) {\n\t\treturn new DokployApi({\n\t\t\tbaseUrl: endpoint || creds.endpoint,\n\t\t\ttoken: creds.token,\n\t\t});\n\t}\n\n\treturn null;\n}\n"],"mappings":"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"}
|