@geekmidas/cli 0.17.0 → 0.19.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.
Files changed (118) hide show
  1. package/dist/{bundler-C74EKlNa.cjs → bundler-CyHg1v_T.cjs} +3 -3
  2. package/dist/{bundler-C74EKlNa.cjs.map → bundler-CyHg1v_T.cjs.map} +1 -1
  3. package/dist/{bundler-B6z6HEeh.mjs → bundler-DQIuE3Kn.mjs} +3 -3
  4. package/dist/{bundler-B6z6HEeh.mjs.map → bundler-DQIuE3Kn.mjs.map} +1 -1
  5. package/dist/{config-DYULeEv8.mjs → config-BaYqrF3n.mjs} +48 -10
  6. package/dist/config-BaYqrF3n.mjs.map +1 -0
  7. package/dist/{config-AmInkU7k.cjs → config-CxrLu8ia.cjs} +53 -9
  8. package/dist/config-CxrLu8ia.cjs.map +1 -0
  9. package/dist/config.cjs +4 -1
  10. package/dist/config.d.cts +27 -2
  11. package/dist/config.d.cts.map +1 -1
  12. package/dist/config.d.mts +27 -2
  13. package/dist/config.d.mts.map +1 -1
  14. package/dist/config.mjs +3 -2
  15. package/dist/dokploy-api-B0w17y4_.mjs +3 -0
  16. package/dist/{dokploy-api-CaETb2L6.mjs → dokploy-api-B9qR2Yn1.mjs} +1 -1
  17. package/dist/{dokploy-api-CaETb2L6.mjs.map → dokploy-api-B9qR2Yn1.mjs.map} +1 -1
  18. package/dist/dokploy-api-BnGeUqN4.cjs +3 -0
  19. package/dist/{dokploy-api-C7F9VykY.cjs → dokploy-api-C5czOZoc.cjs} +1 -1
  20. package/dist/{dokploy-api-C7F9VykY.cjs.map → dokploy-api-C5czOZoc.cjs.map} +1 -1
  21. package/dist/{encryption-D7Efcdi9.cjs → encryption-BAz0xQ1Q.cjs} +1 -1
  22. package/dist/{encryption-D7Efcdi9.cjs.map → encryption-BAz0xQ1Q.cjs.map} +1 -1
  23. package/dist/{encryption-h4Nb6W-M.mjs → encryption-JtMsiGNp.mjs} +2 -2
  24. package/dist/{encryption-h4Nb6W-M.mjs.map → encryption-JtMsiGNp.mjs.map} +1 -1
  25. package/dist/index-CWN-bgrO.d.mts +495 -0
  26. package/dist/index-CWN-bgrO.d.mts.map +1 -0
  27. package/dist/index-DEWYvYvg.d.cts +495 -0
  28. package/dist/index-DEWYvYvg.d.cts.map +1 -0
  29. package/dist/index.cjs +2644 -564
  30. package/dist/index.cjs.map +1 -1
  31. package/dist/index.mjs +2639 -564
  32. package/dist/index.mjs.map +1 -1
  33. package/dist/{openapi-CZVcfxk-.mjs → openapi-CgqR6Jkw.mjs} +3 -3
  34. package/dist/{openapi-CZVcfxk-.mjs.map → openapi-CgqR6Jkw.mjs.map} +1 -1
  35. package/dist/{openapi-C89hhkZC.cjs → openapi-DfpxS0xv.cjs} +8 -2
  36. package/dist/{openapi-C89hhkZC.cjs.map → openapi-DfpxS0xv.cjs.map} +1 -1
  37. package/dist/{openapi-react-query-CM2_qlW9.mjs → openapi-react-query-5rSortLH.mjs} +1 -1
  38. package/dist/{openapi-react-query-CM2_qlW9.mjs.map → openapi-react-query-5rSortLH.mjs.map} +1 -1
  39. package/dist/{openapi-react-query-iKjfLzff.cjs → openapi-react-query-DvNpdDpM.cjs} +1 -1
  40. package/dist/{openapi-react-query-iKjfLzff.cjs.map → openapi-react-query-DvNpdDpM.cjs.map} +1 -1
  41. package/dist/openapi-react-query.cjs +1 -1
  42. package/dist/openapi-react-query.mjs +1 -1
  43. package/dist/openapi.cjs +3 -2
  44. package/dist/openapi.d.cts +1 -1
  45. package/dist/openapi.d.mts +1 -1
  46. package/dist/openapi.mjs +3 -2
  47. package/dist/{storage-Bn3K9Ccu.cjs → storage-BPRgh3DU.cjs} +136 -5
  48. package/dist/storage-BPRgh3DU.cjs.map +1 -0
  49. package/dist/{storage-nkGIjeXt.mjs → storage-DNj_I11J.mjs} +1 -1
  50. package/dist/storage-Dhst7BhI.mjs +272 -0
  51. package/dist/storage-Dhst7BhI.mjs.map +1 -0
  52. package/dist/{storage-UfyTn7Zm.cjs → storage-fOR8dMu5.cjs} +1 -1
  53. package/dist/{types-iFk5ms7y.d.mts → types-K2uQJ-FO.d.mts} +2 -2
  54. package/dist/{types-BgaMXsUa.d.cts.map → types-K2uQJ-FO.d.mts.map} +1 -1
  55. package/dist/{types-BgaMXsUa.d.cts → types-l53qUmGt.d.cts} +2 -2
  56. package/dist/{types-iFk5ms7y.d.mts.map → types-l53qUmGt.d.cts.map} +1 -1
  57. package/dist/workspace/index.cjs +19 -0
  58. package/dist/workspace/index.d.cts +3 -0
  59. package/dist/workspace/index.d.mts +3 -0
  60. package/dist/workspace/index.mjs +3 -0
  61. package/dist/workspace-CPLEZDZf.mjs +3788 -0
  62. package/dist/workspace-CPLEZDZf.mjs.map +1 -0
  63. package/dist/workspace-iWgBlX6h.cjs +3885 -0
  64. package/dist/workspace-iWgBlX6h.cjs.map +1 -0
  65. package/package.json +9 -4
  66. package/src/build/__tests__/workspace-build.spec.ts +215 -0
  67. package/src/build/index.ts +189 -1
  68. package/src/config.ts +71 -14
  69. package/src/deploy/__tests__/docker.spec.ts +1 -1
  70. package/src/deploy/__tests__/index.spec.ts +305 -1
  71. package/src/deploy/index.ts +426 -4
  72. package/src/deploy/types.ts +32 -0
  73. package/src/dev/__tests__/index.spec.ts +572 -1
  74. package/src/dev/index.ts +582 -2
  75. package/src/docker/__tests__/compose.spec.ts +425 -0
  76. package/src/docker/__tests__/templates.spec.ts +145 -0
  77. package/src/docker/compose.ts +248 -0
  78. package/src/docker/index.ts +159 -3
  79. package/src/docker/templates.ts +223 -4
  80. package/src/index.ts +24 -0
  81. package/src/init/__tests__/generators.spec.ts +17 -24
  82. package/src/init/__tests__/init.spec.ts +157 -5
  83. package/src/init/generators/auth.ts +220 -0
  84. package/src/init/generators/config.ts +61 -4
  85. package/src/init/generators/docker.ts +115 -8
  86. package/src/init/generators/env.ts +7 -127
  87. package/src/init/generators/index.ts +1 -0
  88. package/src/init/generators/models.ts +3 -1
  89. package/src/init/generators/monorepo.ts +154 -10
  90. package/src/init/generators/package.ts +5 -3
  91. package/src/init/generators/web.ts +213 -0
  92. package/src/init/index.ts +290 -58
  93. package/src/init/templates/api.ts +38 -29
  94. package/src/init/templates/index.ts +132 -4
  95. package/src/init/templates/minimal.ts +33 -35
  96. package/src/init/templates/serverless.ts +16 -19
  97. package/src/init/templates/worker.ts +50 -25
  98. package/src/init/versions.ts +47 -0
  99. package/src/secrets/keystore.ts +144 -0
  100. package/src/secrets/storage.ts +109 -6
  101. package/src/test/index.ts +97 -0
  102. package/src/workspace/__tests__/client-generator.spec.ts +357 -0
  103. package/src/workspace/__tests__/index.spec.ts +543 -0
  104. package/src/workspace/__tests__/schema.spec.ts +519 -0
  105. package/src/workspace/__tests__/type-inference.spec.ts +251 -0
  106. package/src/workspace/client-generator.ts +307 -0
  107. package/src/workspace/index.ts +372 -0
  108. package/src/workspace/schema.ts +368 -0
  109. package/src/workspace/types.ts +336 -0
  110. package/tsconfig.tsbuildinfo +1 -0
  111. package/tsdown.config.ts +1 -0
  112. package/dist/config-AmInkU7k.cjs.map +0 -1
  113. package/dist/config-DYULeEv8.mjs.map +0 -1
  114. package/dist/dokploy-api-B7KxOQr3.cjs +0 -3
  115. package/dist/dokploy-api-DHvfmWbi.mjs +0 -3
  116. package/dist/storage-BaOP55oq.mjs +0 -147
  117. package/dist/storage-BaOP55oq.mjs.map +0 -1
  118. package/dist/storage-Bn3K9Ccu.cjs.map +0 -1
@@ -85,8 +85,8 @@ async function bundleServer(options) {
85
85
  args.push("--external", "node:*");
86
86
  let masterKey;
87
87
  if (stage) {
88
- const { readStageSecrets, toEmbeddableSecrets, validateEnvironmentVariables, initStageSecrets, writeStageSecrets } = await Promise.resolve().then(() => require("./storage-UfyTn7Zm.cjs"));
89
- const { encryptSecrets, generateDefineOptions } = await Promise.resolve().then(() => require("./encryption-D7Efcdi9.cjs"));
88
+ const { readStageSecrets, toEmbeddableSecrets, validateEnvironmentVariables, initStageSecrets, writeStageSecrets } = await Promise.resolve().then(() => require("./storage-fOR8dMu5.cjs"));
89
+ const { encryptSecrets, generateDefineOptions } = await Promise.resolve().then(() => require("./encryption-BAz0xQ1Q.cjs"));
90
90
  let secrets = await readStageSecrets(stage);
91
91
  if (!secrets) {
92
92
  console.log(` Initializing secrets for stage "${stage}"...`);
@@ -162,4 +162,4 @@ async function bundleServer(options) {
162
162
 
163
163
  //#endregion
164
164
  exports.bundleServer = bundleServer;
165
- //# sourceMappingURL=bundler-C74EKlNa.cjs.map
165
+ //# sourceMappingURL=bundler-CyHg1v_T.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"bundler-C74EKlNa.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 { execSync, 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\nconst MIN_TSDOWN_VERSION = '0.11.0';\n\n/**\n * Check if tsdown is installed and meets minimum version requirement\n */\nfunction checkTsdownVersion(): void {\n\ttry {\n\t\tconst result = execSync('npx tsdown --version', {\n\t\t\tencoding: 'utf-8',\n\t\t\tstdio: ['pipe', 'pipe', 'pipe'],\n\t\t});\n\t\t// Output format: \"tsdown/0.12.8 darwin-arm64 node-v22.21.1\"\n\t\tconst match = result.match(/tsdown\\/(\\d+\\.\\d+\\.\\d+)/);\n\t\tif (match) {\n\t\t\tconst version = match[1]!;\n\t\t\tconst [major, minor] = version.split('.').map(Number) as [number, number];\n\t\t\tconst [minMajor, minMinor] = MIN_TSDOWN_VERSION.split('.').map(\n\t\t\t\tNumber,\n\t\t\t) as [number, number];\n\n\t\t\tif (major < minMajor || (major === minMajor && minor < minMinor)) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`tsdown version ${version} is too old. Please upgrade to ${MIN_TSDOWN_VERSION} or later:\\n` +\n\t\t\t\t\t\t' npm install -D tsdown@latest\\n' +\n\t\t\t\t\t\t' # or\\n' +\n\t\t\t\t\t\t' pnpm add -D tsdown@latest',\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t} catch (error) {\n\t\tif (error instanceof Error && error.message.includes('too old')) {\n\t\t\tthrow error;\n\t\t}\n\t\tthrow new Error(\n\t\t\t'tsdown is required for bundling. Please install it:\\n' +\n\t\t\t\t' npm install -D tsdown@latest\\n' +\n\t\t\t\t' # or\\n' +\n\t\t\t\t' pnpm add -D tsdown@latest',\n\t\t);\n\t}\n}\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// Check tsdown version first\n\tcheckTsdownVersion();\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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"}
1
+ {"version":3,"file":"bundler-CyHg1v_T.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 { execSync, 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\nconst MIN_TSDOWN_VERSION = '0.11.0';\n\n/**\n * Check if tsdown is installed and meets minimum version requirement\n */\nfunction checkTsdownVersion(): void {\n\ttry {\n\t\tconst result = execSync('npx tsdown --version', {\n\t\t\tencoding: 'utf-8',\n\t\t\tstdio: ['pipe', 'pipe', 'pipe'],\n\t\t});\n\t\t// Output format: \"tsdown/0.12.8 darwin-arm64 node-v22.21.1\"\n\t\tconst match = result.match(/tsdown\\/(\\d+\\.\\d+\\.\\d+)/);\n\t\tif (match) {\n\t\t\tconst version = match[1]!;\n\t\t\tconst [major, minor] = version.split('.').map(Number) as [number, number];\n\t\t\tconst [minMajor, minMinor] = MIN_TSDOWN_VERSION.split('.').map(\n\t\t\t\tNumber,\n\t\t\t) as [number, number];\n\n\t\t\tif (major < minMajor || (major === minMajor && minor < minMinor)) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`tsdown version ${version} is too old. Please upgrade to ${MIN_TSDOWN_VERSION} or later:\\n` +\n\t\t\t\t\t\t' npm install -D tsdown@latest\\n' +\n\t\t\t\t\t\t' # or\\n' +\n\t\t\t\t\t\t' pnpm add -D tsdown@latest',\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t} catch (error) {\n\t\tif (error instanceof Error && error.message.includes('too old')) {\n\t\t\tthrow error;\n\t\t}\n\t\tthrow new Error(\n\t\t\t'tsdown is required for bundling. Please install it:\\n' +\n\t\t\t\t' npm install -D tsdown@latest\\n' +\n\t\t\t\t' # or\\n' +\n\t\t\t\t' pnpm add -D tsdown@latest',\n\t\t);\n\t}\n}\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// Check tsdown version first\n\tcheckTsdownVersion();\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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"}
@@ -84,8 +84,8 @@ async function bundleServer(options) {
84
84
  args.push("--external", "node:*");
85
85
  let masterKey;
86
86
  if (stage) {
87
- const { readStageSecrets, toEmbeddableSecrets, validateEnvironmentVariables, initStageSecrets, writeStageSecrets } = await import("./storage-nkGIjeXt.mjs");
88
- const { encryptSecrets, generateDefineOptions } = await import("./encryption-h4Nb6W-M.mjs");
87
+ const { readStageSecrets, toEmbeddableSecrets, validateEnvironmentVariables, initStageSecrets, writeStageSecrets } = await import("./storage-DNj_I11J.mjs");
88
+ const { encryptSecrets, generateDefineOptions } = await import("./encryption-JtMsiGNp.mjs");
89
89
  let secrets = await readStageSecrets(stage);
90
90
  if (!secrets) {
91
91
  console.log(` Initializing secrets for stage "${stage}"...`);
@@ -161,4 +161,4 @@ async function bundleServer(options) {
161
161
 
162
162
  //#endregion
163
163
  export { bundleServer };
164
- //# sourceMappingURL=bundler-B6z6HEeh.mjs.map
164
+ //# sourceMappingURL=bundler-DQIuE3Kn.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"bundler-B6z6HEeh.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 { execSync, 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\nconst MIN_TSDOWN_VERSION = '0.11.0';\n\n/**\n * Check if tsdown is installed and meets minimum version requirement\n */\nfunction checkTsdownVersion(): void {\n\ttry {\n\t\tconst result = execSync('npx tsdown --version', {\n\t\t\tencoding: 'utf-8',\n\t\t\tstdio: ['pipe', 'pipe', 'pipe'],\n\t\t});\n\t\t// Output format: \"tsdown/0.12.8 darwin-arm64 node-v22.21.1\"\n\t\tconst match = result.match(/tsdown\\/(\\d+\\.\\d+\\.\\d+)/);\n\t\tif (match) {\n\t\t\tconst version = match[1]!;\n\t\t\tconst [major, minor] = version.split('.').map(Number) as [number, number];\n\t\t\tconst [minMajor, minMinor] = MIN_TSDOWN_VERSION.split('.').map(\n\t\t\t\tNumber,\n\t\t\t) as [number, number];\n\n\t\t\tif (major < minMajor || (major === minMajor && minor < minMinor)) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`tsdown version ${version} is too old. Please upgrade to ${MIN_TSDOWN_VERSION} or later:\\n` +\n\t\t\t\t\t\t' npm install -D tsdown@latest\\n' +\n\t\t\t\t\t\t' # or\\n' +\n\t\t\t\t\t\t' pnpm add -D tsdown@latest',\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t} catch (error) {\n\t\tif (error instanceof Error && error.message.includes('too old')) {\n\t\t\tthrow error;\n\t\t}\n\t\tthrow new Error(\n\t\t\t'tsdown is required for bundling. Please install it:\\n' +\n\t\t\t\t' npm install -D tsdown@latest\\n' +\n\t\t\t\t' # or\\n' +\n\t\t\t\t' pnpm add -D tsdown@latest',\n\t\t);\n\t}\n}\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// Check tsdown version first\n\tcheckTsdownVersion();\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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"}
1
+ {"version":3,"file":"bundler-DQIuE3Kn.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 { execSync, 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\nconst MIN_TSDOWN_VERSION = '0.11.0';\n\n/**\n * Check if tsdown is installed and meets minimum version requirement\n */\nfunction checkTsdownVersion(): void {\n\ttry {\n\t\tconst result = execSync('npx tsdown --version', {\n\t\t\tencoding: 'utf-8',\n\t\t\tstdio: ['pipe', 'pipe', 'pipe'],\n\t\t});\n\t\t// Output format: \"tsdown/0.12.8 darwin-arm64 node-v22.21.1\"\n\t\tconst match = result.match(/tsdown\\/(\\d+\\.\\d+\\.\\d+)/);\n\t\tif (match) {\n\t\t\tconst version = match[1]!;\n\t\t\tconst [major, minor] = version.split('.').map(Number) as [number, number];\n\t\t\tconst [minMajor, minMinor] = MIN_TSDOWN_VERSION.split('.').map(\n\t\t\t\tNumber,\n\t\t\t) as [number, number];\n\n\t\t\tif (major < minMajor || (major === minMajor && minor < minMinor)) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`tsdown version ${version} is too old. Please upgrade to ${MIN_TSDOWN_VERSION} or later:\\n` +\n\t\t\t\t\t\t' npm install -D tsdown@latest\\n' +\n\t\t\t\t\t\t' # or\\n' +\n\t\t\t\t\t\t' pnpm add -D tsdown@latest',\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t} catch (error) {\n\t\tif (error instanceof Error && error.message.includes('too old')) {\n\t\t\tthrow error;\n\t\t}\n\t\tthrow new Error(\n\t\t\t'tsdown is required for bundling. Please install it:\\n' +\n\t\t\t\t' npm install -D tsdown@latest\\n' +\n\t\t\t\t' # or\\n' +\n\t\t\t\t' pnpm add -D tsdown@latest',\n\t\t);\n\t}\n}\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// Check tsdown version first\n\tcheckTsdownVersion();\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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"}
@@ -1,3 +1,4 @@
1
+ import { isWorkspaceConfig, processConfig } from "./workspace-CPLEZDZf.mjs";
1
2
  import { existsSync } from "node:fs";
2
3
  import { join } from "node:path";
3
4
 
@@ -49,29 +50,66 @@ function parseModuleConfig(configString, defaultAlias) {
49
50
  importPattern
50
51
  };
51
52
  }
52
- async function loadConfig(cwd = process.cwd()) {
53
+ /**
54
+ * Find and return the path to the config file.
55
+ */
56
+ function findConfigPath(cwd) {
53
57
  const files = [
54
58
  "gkm.config.json",
55
59
  "gkm.config.ts",
56
60
  "gkm.config.js"
57
61
  ];
58
- let configPath = "";
59
62
  for (const file of files) {
60
63
  const path = join(cwd, file);
61
- if (existsSync(path)) {
62
- configPath = path;
63
- break;
64
- }
64
+ if (existsSync(path)) return path;
65
65
  }
66
- if (!configPath) throw new Error("Configuration file not found. Please create gkm.config.json, gkm.config.ts, or gkm.config.js in the project root.");
66
+ throw new Error("Configuration file not found. Please create gkm.config.json, gkm.config.ts, or gkm.config.js in the project root.");
67
+ }
68
+ /**
69
+ * Load raw configuration from file.
70
+ */
71
+ async function loadRawConfig(cwd) {
72
+ const configPath = findConfigPath(cwd);
67
73
  try {
68
74
  const config = await import(configPath);
69
75
  return config.default;
70
76
  } catch (error) {
71
- throw new Error(`Failed to load gkm.config.json: ${error.message}`);
77
+ throw new Error(`Failed to load config: ${error.message}`);
72
78
  }
73
79
  }
80
+ /**
81
+ * Load configuration file (single-app format).
82
+ * For backwards compatibility with existing code.
83
+ *
84
+ * @deprecated Use loadWorkspaceConfig for new code
85
+ */
86
+ async function loadConfig(cwd = process.cwd()) {
87
+ const config = await loadRawConfig(cwd);
88
+ if (isWorkspaceConfig(config)) throw new Error("Workspace configuration detected. Use loadWorkspaceConfig() instead.");
89
+ return config;
90
+ }
91
+ /**
92
+ * Load configuration file and process it as a workspace.
93
+ * Works with both single-app and workspace configurations.
94
+ *
95
+ * Single-app configs are automatically wrapped as a workspace with one app.
96
+ *
97
+ * @example
98
+ * ```ts
99
+ * const { type, workspace } = await loadWorkspaceConfig();
100
+ *
101
+ * if (type === 'workspace') {
102
+ * console.log('Multi-app workspace:', workspace.apps);
103
+ * } else {
104
+ * console.log('Single app wrapped as workspace');
105
+ * }
106
+ * ```
107
+ */
108
+ async function loadWorkspaceConfig(cwd = process.cwd()) {
109
+ const config = await loadRawConfig(cwd);
110
+ return processConfig(config, cwd);
111
+ }
74
112
 
75
113
  //#endregion
76
- export { defineConfig, loadConfig, parseModuleConfig };
77
- //# sourceMappingURL=config-DYULeEv8.mjs.map
114
+ export { defineConfig, loadConfig, loadWorkspaceConfig, parseModuleConfig };
115
+ //# sourceMappingURL=config-BaYqrF3n.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-BaYqrF3n.mjs","names":["config: GkmConfig","configString: string","defaultAlias: string","cwd: string"],"sources":["../src/config.ts"],"sourcesContent":["import { existsSync } from 'node:fs';\nimport { join } from 'node:path';\nimport type { GkmConfig } from './types.js';\nimport {\n\tisWorkspaceConfig,\n\ttype LoadedConfig,\n\tprocessConfig,\n\ttype WorkspaceConfig,\n} from './workspace/index.js';\n\nexport type { GkmConfig } from './types.js';\nexport type { LoadedConfig, WorkspaceConfig } from './workspace/index.js';\nexport { defineWorkspace } from './workspace/index.js';\n/**\n * Define GKM configuration with full TypeScript support.\n * This is an identity function that provides type safety and autocomplete.\n *\n * @example\n * ```ts\n * // gkm.config.ts\n * import { defineConfig } from '@geekmidas/cli/config';\n *\n * export default defineConfig({\n * routes: './src/endpoints/**\\/*.ts',\n * envParser: './src/config/env',\n * logger: './src/config/logger',\n * telescope: true,\n * });\n * ```\n */\nexport function defineConfig(config: GkmConfig): GkmConfig {\n\treturn config;\n}\n\nexport interface ParsedModuleConfig {\n\tpath: string;\n\timportPattern: string;\n}\n\n/**\n * Parse a module config string into path and import pattern.\n *\n * @param configString - Config string in format \"./path/to/module\" or \"./path/to/module#exportName\"\n * @param defaultAlias - The default alias name to use if no export name specified\n * @returns Object with path and import pattern\n *\n * @example\n * parseModuleConfig('./src/config/env', 'envParser')\n * // { path: './src/config/env', importPattern: 'envParser' }\n *\n * parseModuleConfig('./src/config/env#envParser', 'envParser')\n * // { path: './src/config/env', importPattern: '{ envParser }' }\n *\n * parseModuleConfig('./src/config/env#myEnv', 'envParser')\n * // { path: './src/config/env', importPattern: '{ myEnv as envParser }' }\n */\nexport function parseModuleConfig(\n\tconfigString: string,\n\tdefaultAlias: string,\n): ParsedModuleConfig {\n\tconst parts = configString.split('#');\n\tconst path = parts[0] ?? configString;\n\tconst exportName = parts[1];\n\tconst importPattern = !exportName\n\t\t? defaultAlias\n\t\t: exportName === defaultAlias\n\t\t\t? `{ ${defaultAlias} }`\n\t\t\t: `{ ${exportName} as ${defaultAlias} }`;\n\n\treturn { path, importPattern };\n}\n\n/**\n * Find and return the path to the config file.\n */\nfunction findConfigPath(cwd: string): string {\n\tconst files = ['gkm.config.json', 'gkm.config.ts', 'gkm.config.js'];\n\n\tfor (const file of files) {\n\t\tconst path = join(cwd, file);\n\t\tif (existsSync(path)) {\n\t\t\treturn path;\n\t\t}\n\t}\n\n\tthrow new Error(\n\t\t'Configuration file not found. Please create gkm.config.json, gkm.config.ts, or gkm.config.js in the project root.',\n\t);\n}\n\n/**\n * Load raw configuration from file.\n */\nasync function loadRawConfig(\n\tcwd: string,\n): Promise<GkmConfig | WorkspaceConfig> {\n\tconst configPath = findConfigPath(cwd);\n\n\ttry {\n\t\tconst config = await import(configPath);\n\t\treturn config.default;\n\t} catch (error) {\n\t\tthrow new Error(`Failed to load config: ${(error as Error).message}`);\n\t}\n}\n\n/**\n * Load configuration file (single-app format).\n * For backwards compatibility with existing code.\n *\n * @deprecated Use loadWorkspaceConfig for new code\n */\nexport async function loadConfig(\n\tcwd: string = process.cwd(),\n): Promise<GkmConfig> {\n\tconst config = await loadRawConfig(cwd);\n\n\t// If it's a workspace config, throw an error\n\tif (isWorkspaceConfig(config)) {\n\t\tthrow new Error(\n\t\t\t'Workspace configuration detected. Use loadWorkspaceConfig() instead.',\n\t\t);\n\t}\n\n\treturn config;\n}\n\n/**\n * Load configuration file and process it as a workspace.\n * Works with both single-app and workspace configurations.\n *\n * Single-app configs are automatically wrapped as a workspace with one app.\n *\n * @example\n * ```ts\n * const { type, workspace } = await loadWorkspaceConfig();\n *\n * if (type === 'workspace') {\n * console.log('Multi-app workspace:', workspace.apps);\n * } else {\n * console.log('Single app wrapped as workspace');\n * }\n * ```\n */\nexport async function loadWorkspaceConfig(\n\tcwd: string = process.cwd(),\n): Promise<LoadedConfig> {\n\tconst config = await loadRawConfig(cwd);\n\treturn processConfig(config, cwd);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AA8BA,SAAgB,aAAaA,QAA8B;AAC1D,QAAO;AACP;;;;;;;;;;;;;;;;;;AAwBD,SAAgB,kBACfC,cACAC,cACqB;CACrB,MAAM,QAAQ,aAAa,MAAM,IAAI;CACrC,MAAM,OAAO,MAAM,MAAM;CACzB,MAAM,aAAa,MAAM;CACzB,MAAM,iBAAiB,aACpB,eACA,eAAe,gBACb,IAAI,aAAa,OACjB,IAAI,WAAW,MAAM,aAAa;AAEvC,QAAO;EAAE;EAAM;CAAe;AAC9B;;;;AAKD,SAAS,eAAeC,KAAqB;CAC5C,MAAM,QAAQ;EAAC;EAAmB;EAAiB;CAAgB;AAEnE,MAAK,MAAM,QAAQ,OAAO;EACzB,MAAM,OAAO,KAAK,KAAK,KAAK;AAC5B,MAAI,WAAW,KAAK,CACnB,QAAO;CAER;AAED,OAAM,IAAI,MACT;AAED;;;;AAKD,eAAe,cACdA,KACuC;CACvC,MAAM,aAAa,eAAe,IAAI;AAEtC,KAAI;EACH,MAAM,SAAS,MAAM,OAAO;AAC5B,SAAO,OAAO;CACd,SAAQ,OAAO;AACf,QAAM,IAAI,OAAO,yBAA0B,MAAgB,QAAQ;CACnE;AACD;;;;;;;AAQD,eAAsB,WACrBA,MAAc,QAAQ,KAAK,EACN;CACrB,MAAM,SAAS,MAAM,cAAc,IAAI;AAGvC,KAAI,kBAAkB,OAAO,CAC5B,OAAM,IAAI,MACT;AAIF,QAAO;AACP;;;;;;;;;;;;;;;;;;AAmBD,eAAsB,oBACrBA,MAAc,QAAQ,KAAK,EACH;CACxB,MAAM,SAAS,MAAM,cAAc,IAAI;AACvC,QAAO,cAAc,QAAQ,IAAI;AACjC"}
@@ -1,4 +1,5 @@
1
1
  const require_chunk = require('./chunk-CUT6urMc.cjs');
2
+ const require_workspace = require('./workspace-iWgBlX6h.cjs');
2
3
  const node_fs = require_chunk.__toESM(require("node:fs"));
3
4
  const node_path = require_chunk.__toESM(require("node:path"));
4
5
 
@@ -50,28 +51,65 @@ function parseModuleConfig(configString, defaultAlias) {
50
51
  importPattern
51
52
  };
52
53
  }
53
- async function loadConfig(cwd = process.cwd()) {
54
+ /**
55
+ * Find and return the path to the config file.
56
+ */
57
+ function findConfigPath(cwd) {
54
58
  const files = [
55
59
  "gkm.config.json",
56
60
  "gkm.config.ts",
57
61
  "gkm.config.js"
58
62
  ];
59
- let configPath = "";
60
63
  for (const file of files) {
61
64
  const path = (0, node_path.join)(cwd, file);
62
- if ((0, node_fs.existsSync)(path)) {
63
- configPath = path;
64
- break;
65
- }
65
+ if ((0, node_fs.existsSync)(path)) return path;
66
66
  }
67
- if (!configPath) throw new Error("Configuration file not found. Please create gkm.config.json, gkm.config.ts, or gkm.config.js in the project root.");
67
+ throw new Error("Configuration file not found. Please create gkm.config.json, gkm.config.ts, or gkm.config.js in the project root.");
68
+ }
69
+ /**
70
+ * Load raw configuration from file.
71
+ */
72
+ async function loadRawConfig(cwd) {
73
+ const configPath = findConfigPath(cwd);
68
74
  try {
69
75
  const config = await import(configPath);
70
76
  return config.default;
71
77
  } catch (error) {
72
- throw new Error(`Failed to load gkm.config.json: ${error.message}`);
78
+ throw new Error(`Failed to load config: ${error.message}`);
73
79
  }
74
80
  }
81
+ /**
82
+ * Load configuration file (single-app format).
83
+ * For backwards compatibility with existing code.
84
+ *
85
+ * @deprecated Use loadWorkspaceConfig for new code
86
+ */
87
+ async function loadConfig(cwd = process.cwd()) {
88
+ const config = await loadRawConfig(cwd);
89
+ if (require_workspace.isWorkspaceConfig(config)) throw new Error("Workspace configuration detected. Use loadWorkspaceConfig() instead.");
90
+ return config;
91
+ }
92
+ /**
93
+ * Load configuration file and process it as a workspace.
94
+ * Works with both single-app and workspace configurations.
95
+ *
96
+ * Single-app configs are automatically wrapped as a workspace with one app.
97
+ *
98
+ * @example
99
+ * ```ts
100
+ * const { type, workspace } = await loadWorkspaceConfig();
101
+ *
102
+ * if (type === 'workspace') {
103
+ * console.log('Multi-app workspace:', workspace.apps);
104
+ * } else {
105
+ * console.log('Single app wrapped as workspace');
106
+ * }
107
+ * ```
108
+ */
109
+ async function loadWorkspaceConfig(cwd = process.cwd()) {
110
+ const config = await loadRawConfig(cwd);
111
+ return require_workspace.processConfig(config, cwd);
112
+ }
75
113
 
76
114
  //#endregion
77
115
  Object.defineProperty(exports, 'defineConfig', {
@@ -86,10 +124,16 @@ Object.defineProperty(exports, 'loadConfig', {
86
124
  return loadConfig;
87
125
  }
88
126
  });
127
+ Object.defineProperty(exports, 'loadWorkspaceConfig', {
128
+ enumerable: true,
129
+ get: function () {
130
+ return loadWorkspaceConfig;
131
+ }
132
+ });
89
133
  Object.defineProperty(exports, 'parseModuleConfig', {
90
134
  enumerable: true,
91
135
  get: function () {
92
136
  return parseModuleConfig;
93
137
  }
94
138
  });
95
- //# sourceMappingURL=config-AmInkU7k.cjs.map
139
+ //# sourceMappingURL=config-CxrLu8ia.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-CxrLu8ia.cjs","names":["config: GkmConfig","configString: string","defaultAlias: string","cwd: string"],"sources":["../src/config.ts"],"sourcesContent":["import { existsSync } from 'node:fs';\nimport { join } from 'node:path';\nimport type { GkmConfig } from './types.js';\nimport {\n\tisWorkspaceConfig,\n\ttype LoadedConfig,\n\tprocessConfig,\n\ttype WorkspaceConfig,\n} from './workspace/index.js';\n\nexport type { GkmConfig } from './types.js';\nexport type { LoadedConfig, WorkspaceConfig } from './workspace/index.js';\nexport { defineWorkspace } from './workspace/index.js';\n/**\n * Define GKM configuration with full TypeScript support.\n * This is an identity function that provides type safety and autocomplete.\n *\n * @example\n * ```ts\n * // gkm.config.ts\n * import { defineConfig } from '@geekmidas/cli/config';\n *\n * export default defineConfig({\n * routes: './src/endpoints/**\\/*.ts',\n * envParser: './src/config/env',\n * logger: './src/config/logger',\n * telescope: true,\n * });\n * ```\n */\nexport function defineConfig(config: GkmConfig): GkmConfig {\n\treturn config;\n}\n\nexport interface ParsedModuleConfig {\n\tpath: string;\n\timportPattern: string;\n}\n\n/**\n * Parse a module config string into path and import pattern.\n *\n * @param configString - Config string in format \"./path/to/module\" or \"./path/to/module#exportName\"\n * @param defaultAlias - The default alias name to use if no export name specified\n * @returns Object with path and import pattern\n *\n * @example\n * parseModuleConfig('./src/config/env', 'envParser')\n * // { path: './src/config/env', importPattern: 'envParser' }\n *\n * parseModuleConfig('./src/config/env#envParser', 'envParser')\n * // { path: './src/config/env', importPattern: '{ envParser }' }\n *\n * parseModuleConfig('./src/config/env#myEnv', 'envParser')\n * // { path: './src/config/env', importPattern: '{ myEnv as envParser }' }\n */\nexport function parseModuleConfig(\n\tconfigString: string,\n\tdefaultAlias: string,\n): ParsedModuleConfig {\n\tconst parts = configString.split('#');\n\tconst path = parts[0] ?? configString;\n\tconst exportName = parts[1];\n\tconst importPattern = !exportName\n\t\t? defaultAlias\n\t\t: exportName === defaultAlias\n\t\t\t? `{ ${defaultAlias} }`\n\t\t\t: `{ ${exportName} as ${defaultAlias} }`;\n\n\treturn { path, importPattern };\n}\n\n/**\n * Find and return the path to the config file.\n */\nfunction findConfigPath(cwd: string): string {\n\tconst files = ['gkm.config.json', 'gkm.config.ts', 'gkm.config.js'];\n\n\tfor (const file of files) {\n\t\tconst path = join(cwd, file);\n\t\tif (existsSync(path)) {\n\t\t\treturn path;\n\t\t}\n\t}\n\n\tthrow new Error(\n\t\t'Configuration file not found. Please create gkm.config.json, gkm.config.ts, or gkm.config.js in the project root.',\n\t);\n}\n\n/**\n * Load raw configuration from file.\n */\nasync function loadRawConfig(\n\tcwd: string,\n): Promise<GkmConfig | WorkspaceConfig> {\n\tconst configPath = findConfigPath(cwd);\n\n\ttry {\n\t\tconst config = await import(configPath);\n\t\treturn config.default;\n\t} catch (error) {\n\t\tthrow new Error(`Failed to load config: ${(error as Error).message}`);\n\t}\n}\n\n/**\n * Load configuration file (single-app format).\n * For backwards compatibility with existing code.\n *\n * @deprecated Use loadWorkspaceConfig for new code\n */\nexport async function loadConfig(\n\tcwd: string = process.cwd(),\n): Promise<GkmConfig> {\n\tconst config = await loadRawConfig(cwd);\n\n\t// If it's a workspace config, throw an error\n\tif (isWorkspaceConfig(config)) {\n\t\tthrow new Error(\n\t\t\t'Workspace configuration detected. Use loadWorkspaceConfig() instead.',\n\t\t);\n\t}\n\n\treturn config;\n}\n\n/**\n * Load configuration file and process it as a workspace.\n * Works with both single-app and workspace configurations.\n *\n * Single-app configs are automatically wrapped as a workspace with one app.\n *\n * @example\n * ```ts\n * const { type, workspace } = await loadWorkspaceConfig();\n *\n * if (type === 'workspace') {\n * console.log('Multi-app workspace:', workspace.apps);\n * } else {\n * console.log('Single app wrapped as workspace');\n * }\n * ```\n */\nexport async function loadWorkspaceConfig(\n\tcwd: string = process.cwd(),\n): Promise<LoadedConfig> {\n\tconst config = await loadRawConfig(cwd);\n\treturn processConfig(config, cwd);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AA8BA,SAAgB,aAAaA,QAA8B;AAC1D,QAAO;AACP;;;;;;;;;;;;;;;;;;AAwBD,SAAgB,kBACfC,cACAC,cACqB;CACrB,MAAM,QAAQ,aAAa,MAAM,IAAI;CACrC,MAAM,OAAO,MAAM,MAAM;CACzB,MAAM,aAAa,MAAM;CACzB,MAAM,iBAAiB,aACpB,eACA,eAAe,gBACb,IAAI,aAAa,OACjB,IAAI,WAAW,MAAM,aAAa;AAEvC,QAAO;EAAE;EAAM;CAAe;AAC9B;;;;AAKD,SAAS,eAAeC,KAAqB;CAC5C,MAAM,QAAQ;EAAC;EAAmB;EAAiB;CAAgB;AAEnE,MAAK,MAAM,QAAQ,OAAO;EACzB,MAAM,OAAO,oBAAK,KAAK,KAAK;AAC5B,MAAI,wBAAW,KAAK,CACnB,QAAO;CAER;AAED,OAAM,IAAI,MACT;AAED;;;;AAKD,eAAe,cACdA,KACuC;CACvC,MAAM,aAAa,eAAe,IAAI;AAEtC,KAAI;EACH,MAAM,SAAS,MAAM,OAAO;AAC5B,SAAO,OAAO;CACd,SAAQ,OAAO;AACf,QAAM,IAAI,OAAO,yBAA0B,MAAgB,QAAQ;CACnE;AACD;;;;;;;AAQD,eAAsB,WACrBA,MAAc,QAAQ,KAAK,EACN;CACrB,MAAM,SAAS,MAAM,cAAc,IAAI;AAGvC,KAAI,oCAAkB,OAAO,CAC5B,OAAM,IAAI,MACT;AAIF,QAAO;AACP;;;;;;;;;;;;;;;;;;AAmBD,eAAsB,oBACrBA,MAAc,QAAQ,KAAK,EACH;CACxB,MAAM,SAAS,MAAM,cAAc,IAAI;AACvC,QAAO,gCAAc,QAAQ,IAAI;AACjC"}
package/dist/config.cjs CHANGED
@@ -1,5 +1,8 @@
1
- const require_config = require('./config-AmInkU7k.cjs');
1
+ const require_workspace = require('./workspace-iWgBlX6h.cjs');
2
+ const require_config = require('./config-CxrLu8ia.cjs');
2
3
 
3
4
  exports.defineConfig = require_config.defineConfig;
5
+ exports.defineWorkspace = require_workspace.defineWorkspace;
4
6
  exports.loadConfig = require_config.loadConfig;
7
+ exports.loadWorkspaceConfig = require_config.loadWorkspaceConfig;
5
8
  exports.parseModuleConfig = require_config.parseModuleConfig;
package/dist/config.d.cts CHANGED
@@ -1,4 +1,5 @@
1
- import { GkmConfig } from "./types-BgaMXsUa.cjs";
1
+ import { GkmConfig } from "./types-l53qUmGt.cjs";
2
+ import { LoadedConfig, WorkspaceConfig, defineWorkspace } from "./index-DEWYvYvg.cjs";
2
3
 
3
4
  //#region src/config.d.ts
4
5
 
@@ -42,8 +43,32 @@ interface ParsedModuleConfig {
42
43
  * // { path: './src/config/env', importPattern: '{ myEnv as envParser }' }
43
44
  */
44
45
  declare function parseModuleConfig(configString: string, defaultAlias: string): ParsedModuleConfig;
46
+ /**
47
+ * Load configuration file (single-app format).
48
+ * For backwards compatibility with existing code.
49
+ *
50
+ * @deprecated Use loadWorkspaceConfig for new code
51
+ */
45
52
  declare function loadConfig(cwd?: string): Promise<GkmConfig>;
53
+ /**
54
+ * Load configuration file and process it as a workspace.
55
+ * Works with both single-app and workspace configurations.
56
+ *
57
+ * Single-app configs are automatically wrapped as a workspace with one app.
58
+ *
59
+ * @example
60
+ * ```ts
61
+ * const { type, workspace } = await loadWorkspaceConfig();
62
+ *
63
+ * if (type === 'workspace') {
64
+ * console.log('Multi-app workspace:', workspace.apps);
65
+ * } else {
66
+ * console.log('Single app wrapped as workspace');
67
+ * }
68
+ * ```
69
+ */
70
+ declare function loadWorkspaceConfig(cwd?: string): Promise<LoadedConfig>;
46
71
  //# sourceMappingURL=config.d.ts.map
47
72
  //#endregion
48
- export { GkmConfig, ParsedModuleConfig, defineConfig, loadConfig, parseModuleConfig };
73
+ export { GkmConfig, LoadedConfig, ParsedModuleConfig, WorkspaceConfig, defineConfig, defineWorkspace, loadConfig, loadWorkspaceConfig, parseModuleConfig };
49
74
  //# sourceMappingURL=config.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.cts","names":[],"sources":["../src/config.ts"],"sourcesContent":[],"mappings":";;;;;AAsBA;;;;AAA0D;AAI1D;AAsBA;AAgBA;;;;AAEU;;;;;iBA5CM,YAAA,SAAqB,YAAY;UAIhC,kBAAA;;;;;;;;;;;;;;;;;;;;;iBAsBD,iBAAA,8CAGb;iBAamB,UAAA,gBAEnB,QAAQ"}
1
+ {"version":3,"file":"config.d.cts","names":[],"sources":["../src/config.ts"],"sourcesContent":[],"mappings":";;;;;;;;AA8B0D;AAI1D;AAsBA;AAwDA;;;;AAEU;AA8BV;;;;AAEU;;iBApHM,YAAA,SAAqB,YAAY;UAIhC,kBAAA;;;;;;;;;;;;;;;;;;;;;iBAsBD,iBAAA,8CAGb;;;;;;;iBAqDmB,UAAA,gBAEnB,QAAQ;;;;;;;;;;;;;;;;;;iBA8BW,mBAAA,gBAEnB,QAAQ"}
package/dist/config.d.mts CHANGED
@@ -1,4 +1,5 @@
1
- import { GkmConfig } from "./types-iFk5ms7y.mjs";
1
+ import { GkmConfig } from "./types-K2uQJ-FO.mjs";
2
+ import { LoadedConfig, WorkspaceConfig, defineWorkspace } from "./index-CWN-bgrO.mjs";
2
3
 
3
4
  //#region src/config.d.ts
4
5
 
@@ -42,8 +43,32 @@ interface ParsedModuleConfig {
42
43
  * // { path: './src/config/env', importPattern: '{ myEnv as envParser }' }
43
44
  */
44
45
  declare function parseModuleConfig(configString: string, defaultAlias: string): ParsedModuleConfig;
46
+ /**
47
+ * Load configuration file (single-app format).
48
+ * For backwards compatibility with existing code.
49
+ *
50
+ * @deprecated Use loadWorkspaceConfig for new code
51
+ */
45
52
  declare function loadConfig(cwd?: string): Promise<GkmConfig>;
53
+ /**
54
+ * Load configuration file and process it as a workspace.
55
+ * Works with both single-app and workspace configurations.
56
+ *
57
+ * Single-app configs are automatically wrapped as a workspace with one app.
58
+ *
59
+ * @example
60
+ * ```ts
61
+ * const { type, workspace } = await loadWorkspaceConfig();
62
+ *
63
+ * if (type === 'workspace') {
64
+ * console.log('Multi-app workspace:', workspace.apps);
65
+ * } else {
66
+ * console.log('Single app wrapped as workspace');
67
+ * }
68
+ * ```
69
+ */
70
+ declare function loadWorkspaceConfig(cwd?: string): Promise<LoadedConfig>;
46
71
  //# sourceMappingURL=config.d.ts.map
47
72
  //#endregion
48
- export { GkmConfig, ParsedModuleConfig, defineConfig, loadConfig, parseModuleConfig };
73
+ export { GkmConfig, LoadedConfig, ParsedModuleConfig, WorkspaceConfig, defineConfig, defineWorkspace, loadConfig, loadWorkspaceConfig, parseModuleConfig };
49
74
  //# sourceMappingURL=config.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.mts","names":[],"sources":["../src/config.ts"],"sourcesContent":[],"mappings":";;;;;AAsBA;;;;AAA0D;AAI1D;AAsBA;AAgBA;;;;AAEU;;;;;iBA5CM,YAAA,SAAqB,YAAY;UAIhC,kBAAA;;;;;;;;;;;;;;;;;;;;;iBAsBD,iBAAA,8CAGb;iBAamB,UAAA,gBAEnB,QAAQ"}
1
+ {"version":3,"file":"config.d.mts","names":[],"sources":["../src/config.ts"],"sourcesContent":[],"mappings":";;;;;;;;AA8B0D;AAI1D;AAsBA;AAwDA;;;;AAEU;AA8BV;;;;AAEU;;iBApHM,YAAA,SAAqB,YAAY;UAIhC,kBAAA;;;;;;;;;;;;;;;;;;;;;iBAsBD,iBAAA,8CAGb;;;;;;;iBAqDmB,UAAA,gBAEnB,QAAQ;;;;;;;;;;;;;;;;;;iBA8BW,mBAAA,gBAEnB,QAAQ"}
package/dist/config.mjs CHANGED
@@ -1,3 +1,4 @@
1
- import { defineConfig, loadConfig, parseModuleConfig } from "./config-DYULeEv8.mjs";
1
+ import { defineWorkspace } from "./workspace-CPLEZDZf.mjs";
2
+ import { defineConfig, loadConfig, loadWorkspaceConfig, parseModuleConfig } from "./config-BaYqrF3n.mjs";
2
3
 
3
- export { defineConfig, loadConfig, parseModuleConfig };
4
+ export { defineConfig, defineWorkspace, loadConfig, loadWorkspaceConfig, parseModuleConfig };
@@ -0,0 +1,3 @@
1
+ import { DokployApi, DokployApiError } from "./dokploy-api-B9qR2Yn1.mjs";
2
+
3
+ export { DokployApi };
@@ -302,4 +302,4 @@ var DokployApi = class {
302
302
 
303
303
  //#endregion
304
304
  export { DokployApi, DokployApiError };
305
- //# sourceMappingURL=dokploy-api-CaETb2L6.mjs.map
305
+ //# sourceMappingURL=dokploy-api-B9qR2Yn1.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"dokploy-api-CaETb2L6.mjs","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":";AAkBA,IAAa,kBAAb,cAAqC,MAAM;CAC1C,YACCA,SACOC,QACAC,YACAC,QACN;AACD,QAAM,QAAQ;EAJP;EACA;EACA;AAGP,OAAK,OAAO;CACZ;AACD;;;;AAKD,IAAa,aAAb,MAAwB;CACvB,AAAQ;CACR,AAAQ;CAER,YAAYC,SAA4B;AACvC,OAAK,UAAU,QAAQ,QAAQ,QAAQ,OAAO,GAAG;AACjD,OAAK,QAAQ,QAAQ;CACrB;;;;CAKD,MAAM,IAAOC,UAA8B;AAC1C,SAAO,KAAK,QAAW,OAAO,SAAS;CACvC;;;;CAKD,MAAM,KAAQA,UAAkBC,MAA4C;AAC3E,SAAO,KAAK,QAAW,QAAQ,UAAU,KAAK;CAC9C;;;;CAKD,MAAc,QACbC,QACAF,UACAC,MACa;EACb,MAAM,OAAO,EAAE,KAAK,QAAQ,OAAO,SAAS;EAE5C,MAAM,WAAW,MAAM,MAAM,KAAK;GACjC;GACA,SAAS;IACR,gBAAgB;IAChB,aAAa,KAAK;GAClB;GACD,MAAM,OAAO,KAAK,UAAU,KAAK;EACjC,EAAC;AAEF,OAAK,SAAS,IAAI;GACjB,IAAI,gBAAgB,qBAAqB,SAAS,OAAO,GAAG,SAAS,WAAW;GAChF,IAAIE;AAEJ,OAAI;IACH,MAAM,YAAa,MAAM,SAAS,MAAM;AACxC,QAAI,UAAU,QACb,iBAAgB,qBAAqB,UAAU,QAAQ;AAExD,QAAI,UAAU,QAAQ,QAAQ;AAC7B,cAAS,UAAU;AACnB,sBAAiB,cAAc,UAAU,OAAO,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC,KAAK,KAAK,CAAC;IACjF;GACD,QAAO,CAEP;AAED,SAAM,IAAI,gBACT,cACA,SAAS,QACT,SAAS,YACT;EAED;EAGD,MAAM,OAAO,MAAM,SAAS,MAAM;AAClC,OAAK,QAAQ,KAAK,MAAM,KAAK,GAC5B;AAED,SAAO,KAAK,MAAM,KAAK;CACvB;;;;CAKD,MAAM,gBAAkC;AACvC,MAAI;AACH,SAAM,KAAK,IAAI,cAAc;AAC7B,UAAO;EACP,QAAO;AACP,UAAO;EACP;CACD;;;;CASD,MAAM,eAA0C;AAC/C,SAAO,KAAK,IAAsB,cAAc;CAChD;;;;CAKD,MAAM,WAAWC,WAAmD;AACnE,SAAO,KAAK,KACV,wBAAwB,UAAU,EACnC;CACD;;;;CAKD,MAAM,cACLC,MACAC,aACwE;AACxE,SAAO,KAAK,KAGT,kBAAkB;GACpB;GACA,aAAa,gBAAgB;EAC7B,EAAC;CACF;;;;CASD,MAAM,kBACLF,WACAC,MACAC,aAC8B;AAC9B,SAAO,KAAK,KAAyB,sBAAsB;GAC1D;GACA;GACA,aAAa,gBAAgB,EAAE,KAAK;EACpC,EAAC;CACF;;;;CASD,MAAM,kBACLD,MACAD,WACAG,eAC8B;AAC9B,SAAO,KAAK,KAAyB,sBAAsB;GAC1D;GACA;GACA;GACA,SAAS,KAAK,aAAa,CAAC,QAAQ,eAAe,IAAI;EACvD,EAAC;CACF;;;;CAKD,MAAM,kBACLC,eACAC,SACgB;AAChB,QAAM,KAAK,KAAK,sBAAsB;GACrC;GACA,GAAG;EACH,EAAC;CACF;;;;CAKD,MAAM,mBAAmBD,eAAuBE,KAA4B;AAC3E,QAAM,KAAK,KAAK,+BAA+B;GAC9C;GACA;EACA,EAAC;CACF;;;;;;;;CASD,MAAM,mBACLF,eACAG,aACAC,SAUgB;AAChB,QAAM,KAAK,KAAK,kCAAkC;GACjD;GACA;GACA,GAAG;EACH,EAAC;CACF;;;;CAKD,MAAM,kBAAkBJ,eAAsC;AAC7D,QAAM,KAAK,KAAK,sBAAsB,EAAE,cAAe,EAAC;CACxD;;;;CASD,MAAM,iBAA6C;AAClD,SAAO,KAAK,IAAuB,eAAe;CAClD;;;;CAKD,MAAM,eACLK,cACAC,aACAC,UACAC,UACAC,SAG2B;AAC3B,SAAO,KAAK,KAAsB,mBAAmB;GACpD;GACA;GACA;GACA;GACA,aAAa,SAAS;EACtB,EAAC;CACF;;;;CAKD,MAAM,YAAYC,YAA8C;AAC/D,SAAO,KAAK,KAAsB,0BAA0B,WAAW,EAAE;CACzE;;;;CAKD,MAAM,eACLA,YACAC,SAOgB;AAChB,QAAM,KAAK,KAAK,mBAAmB;GAAE;GAAY,GAAG;EAAS,EAAC;CAC9D;;;;CAKD,MAAM,eAAeD,YAAmC;AACvD,QAAM,KAAK,KAAK,mBAAmB,EAAE,WAAY,EAAC;CAClD;;;;CASD,MAAM,eACLb,MACAD,WACAG,eACAa,SAQ2B;AAC3B,SAAO,KAAK,KAAsB,mBAAmB;GACpD;GACA;GACA;GACA,SACC,SAAS,WAAW,KAAK,aAAa,CAAC,QAAQ,eAAe,IAAI;GACnE,cAAc,SAAS,gBAAgB;GACvC,cAAc,SAAS,gBAAgB;GACvC,kBAAkB,SAAS;GAC3B,aAAa,SAAS,eAAe;GACrC,aAAa,SAAS,gBAAgB,wBAAwB,KAAK;EACnE,EAAC;CACF;;;;CAKD,MAAM,YAAYC,YAA8C;AAC/D,SAAO,KAAK,KAAsB,0BAA0B,WAAW,EAAE;CACzE;;;;CAKD,MAAM,eAAeA,YAAmC;AACvD,QAAM,KAAK,KAAK,mBAAmB,EAAE,WAAY,EAAC;CAClD;;;;CAKD,MAAM,gBAAgBA,YAAoBX,KAA4B;AACrE,QAAM,KAAK,KAAK,4BAA4B;GAAE;GAAY;EAAK,EAAC;CAChE;;;;CAKD,MAAM,yBACLW,YACAC,cACgB;AAChB,QAAM,KAAK,KAAK,6BAA6B;GAAE;GAAY;EAAc,EAAC;CAC1E;;;;CAKD,MAAM,eACLD,YACAE,SACgB;AAChB,QAAM,KAAK,KAAK,mBAAmB;GAAE;GAAY,GAAG;EAAS,EAAC;CAC9D;;;;CASD,MAAM,YACLlB,MACAD,WACAG,eACAiB,SAMwB;AACxB,SAAO,KAAK,KAAmB,gBAAgB;GAC9C;GACA;GACA;GACA,SACC,SAAS,WAAW,KAAK,aAAa,CAAC,QAAQ,eAAe,IAAI;GACnE,kBAAkB,SAAS;GAC3B,aAAa,SAAS,eAAe;GACrC,aAAa,SAAS,gBAAgB,qBAAqB,KAAK;EAChE,EAAC;CACF;;;;CAKD,MAAM,SAASC,SAAwC;AACtD,SAAO,KAAK,KAAmB,oBAAoB,QAAQ,EAAE;CAC7D;;;;CAKD,MAAM,YAAYA,SAAgC;AACjD,QAAM,KAAK,KAAK,gBAAgB,EAAE,QAAS,EAAC;CAC5C;;;;CAKD,MAAM,aAAaA,SAAiBf,KAA4B;AAC/D,QAAM,KAAK,KAAK,yBAAyB;GAAE;GAAS;EAAK,EAAC;CAC1D;;;;CAKD,MAAM,sBACLe,SACAH,cACgB;AAChB,QAAM,KAAK,KAAK,0BAA0B;GAAE;GAAS;EAAc,EAAC;CACpE;;;;CAKD,MAAM,YACLG,SACAC,SACgB;AAChB,QAAM,KAAK,KAAK,gBAAgB;GAAE;GAAS,GAAG;EAAS,EAAC;CACxD;AACD"}
1
+ {"version":3,"file":"dokploy-api-B9qR2Yn1.mjs","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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"}
@@ -0,0 +1,3 @@
1
+ const require_dokploy_api = require('./dokploy-api-C5czOZoc.cjs');
2
+
3
+ exports.DokployApi = require_dokploy_api.DokployApi;