@geekmidas/cli 1.10.10 → 1.10.12

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 (66) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/{bundler-Bm3Az_sv.cjs → bundler-DVJkwNMQ.cjs} +2 -2
  3. package/dist/{bundler-Bm3Az_sv.cjs.map → bundler-DVJkwNMQ.cjs.map} +1 -1
  4. package/dist/{bundler-kk_XJTRp.mjs → bundler-Di5Gz9Ou.mjs} +2 -2
  5. package/dist/{bundler-kk_XJTRp.mjs.map → bundler-Di5Gz9Ou.mjs.map} +1 -1
  6. package/dist/config.d.cts +2 -2
  7. package/dist/config.d.mts +2 -2
  8. package/dist/{fullstack-secrets-DmUOfLeX.mjs → fullstack-secrets-BIFFv4UZ.mjs} +18 -3
  9. package/dist/fullstack-secrets-BIFFv4UZ.mjs.map +1 -0
  10. package/dist/{fullstack-secrets-BC9t9wWB.cjs → fullstack-secrets-D9rjTNyx.cjs} +18 -3
  11. package/dist/fullstack-secrets-D9rjTNyx.cjs.map +1 -0
  12. package/dist/{index-BdJZKXCJ.d.cts → index-UCsZ_Vkw.d.cts} +2 -2
  13. package/dist/{index-BdJZKXCJ.d.cts.map → index-UCsZ_Vkw.d.cts.map} +1 -1
  14. package/dist/{index-DB9VbcCD.d.mts → index-gXAGDSGu.d.mts} +2 -2
  15. package/dist/{index-DB9VbcCD.d.mts.map → index-gXAGDSGu.d.mts.map} +1 -1
  16. package/dist/index.cjs +120 -54
  17. package/dist/index.cjs.map +1 -1
  18. package/dist/index.mjs +120 -54
  19. package/dist/index.mjs.map +1 -1
  20. package/dist/openapi-BYxAWwok.cjs.map +1 -1
  21. package/dist/openapi-DenF-okj.mjs.map +1 -1
  22. package/dist/openapi.d.cts +1 -1
  23. package/dist/openapi.d.mts +1 -1
  24. package/dist/{reconcile-C0dsg-Gq.mjs → reconcile-DxTEausy.mjs} +2 -2
  25. package/dist/{reconcile-C0dsg-Gq.mjs.map → reconcile-DxTEausy.mjs.map} +1 -1
  26. package/dist/{reconcile-BZ8j_-0z.cjs → reconcile-LaaJkFlO.cjs} +2 -2
  27. package/dist/{reconcile-BZ8j_-0z.cjs.map → reconcile-LaaJkFlO.cjs.map} +1 -1
  28. package/dist/{storage-Cs13jkJ9.cjs → storage-6GBoLCYF.cjs} +12 -6
  29. package/dist/{storage-B7H2PPCS.mjs.map → storage-6GBoLCYF.cjs.map} +1 -1
  30. package/dist/{storage-C1FNm2EP.mjs → storage-BFqrVsip.mjs} +1 -1
  31. package/dist/{storage-D6BGLgWf.cjs → storage-DCqjCiDn.cjs} +1 -1
  32. package/dist/{storage-B7H2PPCS.mjs → storage-DMf420PP.mjs} +12 -6
  33. package/dist/{storage-Cs13jkJ9.cjs.map → storage-DMf420PP.mjs.map} +1 -1
  34. package/dist/sync-BVNso6AA.cjs +4 -0
  35. package/dist/{sync-oCqELfeA.cjs → sync-DIGGOxCw.cjs} +2 -2
  36. package/dist/{sync-oCqELfeA.cjs.map → sync-DIGGOxCw.cjs.map} +1 -1
  37. package/dist/{sync-CyGe5f1I.mjs → sync-DjD_TeNX.mjs} +1 -1
  38. package/dist/{sync-CzXruMzP.mjs → sync-Do9O7QZ8.mjs} +2 -2
  39. package/dist/{sync-CzXruMzP.mjs.map → sync-Do9O7QZ8.mjs.map} +1 -1
  40. package/dist/{types-DwpLq_fp.d.mts → types-DiV9Mbvc.d.mts} +2 -2
  41. package/dist/{types-D4MLWXSL.d.cts.map → types-DiV9Mbvc.d.mts.map} +1 -1
  42. package/dist/{types-D4MLWXSL.d.cts → types-JvWj5Ckc.d.cts} +2 -2
  43. package/dist/{types-DwpLq_fp.d.mts.map → types-JvWj5Ckc.d.cts.map} +1 -1
  44. package/dist/workspace/index.d.cts +2 -2
  45. package/dist/workspace/index.d.mts +2 -2
  46. package/package.json +2 -2
  47. package/src/dev/index.ts +41 -1
  48. package/src/docker/__tests__/compose.spec.ts +48 -13
  49. package/src/docker/compose.ts +77 -23
  50. package/src/init/__tests__/generators.spec.ts +1 -0
  51. package/src/init/generators/docker.ts +1 -2
  52. package/src/init/index.ts +1 -0
  53. package/src/init/versions.ts +1 -1
  54. package/src/secrets/__tests__/generator.spec.ts +5 -5
  55. package/src/secrets/__tests__/storage.spec.ts +7 -7
  56. package/src/secrets/generator.ts +20 -4
  57. package/src/secrets/index.ts +4 -4
  58. package/src/secrets/storage.ts +11 -5
  59. package/src/secrets/types.ts +4 -1
  60. package/src/setup/__tests__/reconcile-secrets.spec.ts +3 -3
  61. package/src/setup/index.ts +5 -0
  62. package/src/test/index.ts +8 -10
  63. package/src/types.ts +6 -1
  64. package/dist/fullstack-secrets-BC9t9wWB.cjs.map +0 -1
  65. package/dist/fullstack-secrets-DmUOfLeX.mjs.map +0 -1
  66. package/dist/sync-DLlwsrBs.cjs +0 -4
package/dist/index.mjs CHANGED
@@ -4,13 +4,13 @@ import { getAppBuildOrder, getDependencyEnvVars, getDeployTargetError, isDeployT
4
4
  import { getAppNameFromCwd, loadAppConfig, loadConfig, loadWorkspaceAppInfo, loadWorkspaceConfig, parseModuleConfig } from "./config-jsRYHOHU.mjs";
5
5
  import { getCredentialsPath, getDokployCredentials, getDokployRegistryId, getDokployToken, removeDokployCredentials, storeDokployCredentials, storeDokployRegistryId } from "./credentials-s1kLcIzK.mjs";
6
6
  import { ConstructGenerator, EndpointGenerator, OPENAPI_OUTPUT_PATH, copyAllClients, copyClientToFrontends, generateOpenApi, getBackendOpenApiPath, isPartitionedRoutes, normalizeRoutes, openapiCommand, resolveOpenApiConfig } from "./openapi-DenF-okj.mjs";
7
- import { getKeyPath, maskPassword, readStageSecrets, secretsExist, setCustomSecret, toEmbeddableSecrets, writeStageSecrets } from "./storage-B7H2PPCS.mjs";
7
+ import { getKeyPath, maskPassword, readStageSecrets, secretsExist, setCustomSecret, toEmbeddableSecrets, writeStageSecrets } from "./storage-DMf420PP.mjs";
8
8
  import { DokployApi } from "./dokploy-api-2ldYoN3i.mjs";
9
9
  import { encryptSecrets } from "./encryption-BOH5M-f-.mjs";
10
10
  import { CachedStateProvider } from "./CachedStateProvider-BDq5WqSy.mjs";
11
- import { createStageSecrets, generateConnectionUrls, generateDbPassword, generateDbUrl, generateFullstackCustomSecrets, generateServiceCredentials, rotateServicePassword, writeDockerEnvFromSecrets } from "./fullstack-secrets-DmUOfLeX.mjs";
11
+ import { createStageSecrets, generateConnectionUrls, generateDbPassword, generateDbUrl, generateFullstackCustomSecrets, generateServiceCredentials, rotateServicePassword, writeDockerEnvFromSecrets } from "./fullstack-secrets-BIFFv4UZ.mjs";
12
12
  import { generateReactQueryCommand } from "./openapi-react-query-C4UdILaI.mjs";
13
- import { isSSMConfigured, pullSecrets, pushSecrets } from "./sync-CzXruMzP.mjs";
13
+ import { isSSMConfigured, pullSecrets, pushSecrets } from "./sync-Do9O7QZ8.mjs";
14
14
  import { createRequire } from "node:module";
15
15
  import { copyFileSync, existsSync, readFileSync, unlinkSync } from "node:fs";
16
16
  import { basename, dirname, join, parse, relative, resolve } from "node:path";
@@ -35,7 +35,7 @@ import prompts from "prompts";
35
35
 
36
36
  //#region package.json
37
37
  var name = "@geekmidas/cli";
38
- var version = "1.10.9";
38
+ var version = "1.10.11";
39
39
  var description = "CLI tools for building Lambda handlers, server applications, and generating OpenAPI specs";
40
40
  var private$1 = false;
41
41
  var type = "module";
@@ -838,7 +838,7 @@ function rewriteUrlsWithPorts(secrets, resolvedPorts) {
838
838
  for (const { defaultPort, resolvedPort } of portReplacements) if (value === String(defaultPort)) result[key] = String(resolvedPort);
839
839
  }
840
840
  for (const [key, value] of Object.entries(result)) {
841
- if (!key.endsWith("_URL") && key !== "DATABASE_URL") continue;
841
+ if (!key.endsWith("_URL") && !key.endsWith("_ENDPOINT") && key !== "DATABASE_URL") continue;
842
842
  let rewritten = value;
843
843
  for (const name$1 of serviceNames) rewritten = rewritten.replace(new RegExp(`@${name$1}:`, "g"), "@localhost:");
844
844
  for (const { defaultPort, resolvedPort } of portReplacements) rewritten = replacePortInUrl(rewritten, defaultPort, resolvedPort);
@@ -1256,6 +1256,28 @@ function parseComposeServiceNames(composePath) {
1256
1256
  * This ensures manually added services are always started.
1257
1257
  * @internal Exported for testing
1258
1258
  */
1259
+ /**
1260
+ * Start docker-compose services for a single-app project (no workspace config).
1261
+ * Starts all services defined in docker-compose.yml.
1262
+ */
1263
+ async function startComposeServices(cwd, portEnv, secretsEnv) {
1264
+ const composeFile = join(cwd, "docker-compose.yml");
1265
+ if (!existsSync(composeFile)) return;
1266
+ const servicesToStart = parseComposeServiceNames(composeFile);
1267
+ if (servicesToStart.length === 0) return;
1268
+ logger$11.log(`🐳 Starting services: ${servicesToStart.join(", ")}`);
1269
+ try {
1270
+ execSync(`docker compose up -d ${servicesToStart.join(" ")}`, {
1271
+ cwd,
1272
+ stdio: "inherit",
1273
+ env: buildDockerComposeEnv(secretsEnv, portEnv)
1274
+ });
1275
+ logger$11.log("✅ Services started");
1276
+ } catch (error) {
1277
+ logger$11.error("❌ Failed to start services:", error.message);
1278
+ throw error;
1279
+ }
1280
+ }
1259
1281
  async function startWorkspaceServices(workspace, portEnv, secretsEnv) {
1260
1282
  const composeFile = join(workspace.root, "docker-compose.yml");
1261
1283
  if (!existsSync(composeFile)) return;
@@ -2198,7 +2220,7 @@ async function buildForProvider(provider, context, rootOutputDir, endpointGenera
2198
2220
  let masterKey;
2199
2221
  if (context.production?.bundle && !skipBundle) {
2200
2222
  logger$9.log(`\n📦 Bundling production server...`);
2201
- const { bundleServer } = await import("./bundler-kk_XJTRp.mjs");
2223
+ const { bundleServer } = await import("./bundler-Di5Gz9Ou.mjs");
2202
2224
  const allConstructs = [
2203
2225
  ...endpoints.map((e) => e.construct),
2204
2226
  ...functions.map((f) => f.construct),
@@ -2861,14 +2883,16 @@ const DEFAULT_SERVICE_IMAGES = {
2861
2883
  postgres: "postgres",
2862
2884
  redis: "redis",
2863
2885
  rabbitmq: "rabbitmq",
2864
- minio: "minio/minio"
2886
+ minio: "minio/minio",
2887
+ mailpit: "axllent/mailpit"
2865
2888
  };
2866
2889
  /** Default Docker image versions for services */
2867
2890
  const DEFAULT_SERVICE_VERSIONS = {
2868
2891
  postgres: "18-alpine",
2869
2892
  redis: "7-alpine",
2870
2893
  rabbitmq: "3-management-alpine",
2871
- minio: "latest"
2894
+ minio: "latest",
2895
+ mailpit: "latest"
2872
2896
  };
2873
2897
  /** Get the default full image reference for a service */
2874
2898
  function getDefaultImage(serviceName) {
@@ -2922,12 +2946,17 @@ services:
2922
2946
  `;
2923
2947
  if (serviceMap.has("rabbitmq")) yaml += ` - RABBITMQ_URL=\${RABBITMQ_URL:-amqp://rabbitmq:5672}
2924
2948
  `;
2925
- if (serviceMap.has("minio")) yaml += ` - S3_ENDPOINT=\${S3_ENDPOINT:-http://minio:9000}
2926
- - S3_ACCESS_KEY_ID=\${MINIO_ACCESS_KEY:-app}
2927
- - S3_SECRET_ACCESS_KEY=\${MINIO_SECRET_KEY:-app}
2928
- - S3_BUCKET=\${MINIO_BUCKET:-app}
2929
- - S3_REGION=\${S3_REGION:-eu-west-1}
2930
- - S3_FORCE_PATH_STYLE=true
2949
+ if (serviceMap.has("minio")) yaml += ` - STORAGE_ENDPOINT=\${STORAGE_ENDPOINT:-http://minio:9000}
2950
+ - STORAGE_ACCESS_KEY_ID=\${STORAGE_ACCESS_KEY_ID:-${imageName}}
2951
+ - STORAGE_SECRET_ACCESS_KEY=\${STORAGE_SECRET_ACCESS_KEY:-${imageName}}
2952
+ - STORAGE_BUCKET=\${STORAGE_BUCKET:-${imageName}}
2953
+ - STORAGE_REGION=\${STORAGE_REGION:-eu-west-1}
2954
+ - STORAGE_FORCE_PATH_STYLE=true
2955
+ `;
2956
+ if (serviceMap.has("mailpit")) yaml += ` - SMTP_HOST=\${SMTP_HOST:-mailpit}
2957
+ - SMTP_PORT=\${SMTP_PORT:-1025}
2958
+ - SMTP_USER=\${SMTP_USER:-${imageName}}
2959
+ - SMTP_PASS=\${SMTP_PASS:-${imageName}}
2931
2960
  `;
2932
2961
  yaml += ` healthcheck:
2933
2962
  test: ["CMD", "wget", "-q", "--spider", "http://localhost:${port}${healthCheckPath}"]
@@ -3009,12 +3038,13 @@ services:
3009
3038
  container_name: minio
3010
3039
  restart: unless-stopped
3011
3040
  entrypoint: sh
3012
- command: -c 'mkdir -p /data/\${MINIO_BUCKET:-app} && /usr/bin/docker-entrypoint.sh server --console-address ":9001" /data'
3041
+ command: -c 'mkdir -p /data/\${STORAGE_BUCKET:-${imageName}} && /usr/bin/docker-entrypoint.sh server --console-address ":9001" /data'
3013
3042
  environment:
3014
- MINIO_ROOT_USER: \${MINIO_ACCESS_KEY:-app}
3015
- MINIO_ROOT_PASSWORD: \${MINIO_SECRET_KEY:-app}
3043
+ MINIO_ROOT_USER: \${STORAGE_ACCESS_KEY_ID:-${imageName}}
3044
+ MINIO_ROOT_PASSWORD: \${STORAGE_SECRET_ACCESS_KEY:-${imageName}}
3016
3045
  ports:
3017
- - "9001:9001" # Console UI
3046
+ - "\${MINIO_API_PORT:-9000}:9000"
3047
+ - "\${MINIO_CONSOLE_PORT:-9001}:9001"
3018
3048
  volumes:
3019
3049
  - minio_data:/data
3020
3050
  healthcheck:
@@ -3024,6 +3054,25 @@ services:
3024
3054
  retries: 5
3025
3055
  networks:
3026
3056
  - app-network
3057
+ `;
3058
+ const mailpitImage = serviceMap.get("mailpit");
3059
+ if (mailpitImage) yaml += `
3060
+ mailpit:
3061
+ image: ${mailpitImage}
3062
+ container_name: mailpit
3063
+ restart: unless-stopped
3064
+ environment:
3065
+ MP_SMTP_AUTH: \${SMTP_USER:-${imageName}}:\${SMTP_PASS:-${imageName}}
3066
+ ports:
3067
+ - "\${MAILPIT_UI_PORT:-8025}:8025" # Web UI
3068
+ - "\${MAILPIT_SMTP_PORT:-1025}:1025" # SMTP
3069
+ healthcheck:
3070
+ test: ["CMD", "wget", "-q", "--spider", "http://localhost:8025"]
3071
+ interval: 5s
3072
+ timeout: 5s
3073
+ retries: 5
3074
+ networks:
3075
+ - app-network
3027
3076
  `;
3028
3077
  yaml += `
3029
3078
  volumes:
@@ -3102,9 +3151,11 @@ services:
3102
3151
  `;
3103
3152
  for (const [appName, app] of apps) yaml += generateAppService(appName, app, apps, {
3104
3153
  registry,
3154
+ projectName: workspace.name,
3105
3155
  hasPostgres,
3106
3156
  hasRedis,
3107
- hasMinio
3157
+ hasMinio,
3158
+ hasMail
3108
3159
  });
3109
3160
  if (hasPostgres) yaml += `
3110
3161
  postgres:
@@ -3145,9 +3196,16 @@ services:
3145
3196
  image: axllent/mailpit:latest
3146
3197
  container_name: ${workspace.name}-mailpit
3147
3198
  restart: unless-stopped
3199
+ environment:
3200
+ MP_SMTP_AUTH: \${SMTP_USER:-${workspace.name}}:\${SMTP_PASS:-${workspace.name}}
3148
3201
  ports:
3149
- - "8025:8025" # Web UI
3150
- - "1025:1025" # SMTP
3202
+ - "\${MAILPIT_UI_PORT:-8025}:8025" # Web UI
3203
+ - "\${MAILPIT_SMTP_PORT:-1025}:1025" # SMTP
3204
+ healthcheck:
3205
+ test: ["CMD", "wget", "-q", "--spider", "http://localhost:8025"]
3206
+ interval: 5s
3207
+ timeout: 5s
3208
+ retries: 5
3151
3209
  networks:
3152
3210
  - workspace-network
3153
3211
  `;
@@ -3157,12 +3215,13 @@ services:
3157
3215
  container_name: ${workspace.name}-minio
3158
3216
  restart: unless-stopped
3159
3217
  entrypoint: sh
3160
- command: -c 'mkdir -p /data/\${MINIO_BUCKET:-app} && /usr/bin/docker-entrypoint.sh server --console-address ":9001" /data'
3218
+ command: -c 'mkdir -p /data/\${STORAGE_BUCKET:-${workspace.name}} && /usr/bin/docker-entrypoint.sh server --console-address ":9001" /data'
3161
3219
  environment:
3162
- MINIO_ROOT_USER: \${MINIO_ACCESS_KEY:-app}
3163
- MINIO_ROOT_PASSWORD: \${MINIO_SECRET_KEY:-app}
3220
+ MINIO_ROOT_USER: \${STORAGE_ACCESS_KEY_ID:-${workspace.name}}
3221
+ MINIO_ROOT_PASSWORD: \${STORAGE_SECRET_ACCESS_KEY:-${workspace.name}}
3164
3222
  ports:
3165
- - "9001:9001" # Console UI
3223
+ - "\${MINIO_API_PORT:-9000}:9000"
3224
+ - "\${MINIO_CONSOLE_PORT:-9001}:9001"
3166
3225
  volumes:
3167
3226
  - minio_data:/data
3168
3227
  healthcheck:
@@ -3216,7 +3275,7 @@ function getInfraServiceImage(serviceName, config$1) {
3216
3275
  * Generate a service definition for an app.
3217
3276
  */
3218
3277
  function generateAppService(appName, app, allApps, options) {
3219
- const { registry, hasPostgres, hasRedis, hasMinio } = options;
3278
+ const { registry, projectName, hasPostgres, hasRedis, hasMinio, hasMail } = options;
3220
3279
  const imageRef = registry ? `\${REGISTRY:-${registry}}/` : "";
3221
3280
  const healthCheckPath = app.type === "frontend" ? "/" : "/health";
3222
3281
  const healthCheckCmd = app.type === "frontend" ? `["CMD", "wget", "-q", "--spider", "http://localhost:${app.port}/"]` : `["CMD", "wget", "-q", "--spider", "http://localhost:${app.port}${healthCheckPath}"]`;
@@ -3244,12 +3303,17 @@ function generateAppService(appName, app, allApps, options) {
3244
3303
  `;
3245
3304
  if (hasRedis) yaml += ` - REDIS_URL=\${REDIS_URL:-redis://redis:6379}
3246
3305
  `;
3247
- if (hasMinio) yaml += ` - S3_ENDPOINT=\${S3_ENDPOINT:-http://minio:9000}
3248
- - S3_ACCESS_KEY_ID=\${MINIO_ACCESS_KEY:-app}
3249
- - S3_SECRET_ACCESS_KEY=\${MINIO_SECRET_KEY:-app}
3250
- - S3_BUCKET=\${MINIO_BUCKET:-app}
3251
- - S3_REGION=\${S3_REGION:-eu-west-1}
3252
- - S3_FORCE_PATH_STYLE=true
3306
+ if (hasMinio) yaml += ` - STORAGE_ENDPOINT=\${STORAGE_ENDPOINT:-http://minio:9000}
3307
+ - STORAGE_ACCESS_KEY_ID=\${STORAGE_ACCESS_KEY_ID:-${projectName}}
3308
+ - STORAGE_SECRET_ACCESS_KEY=\${STORAGE_SECRET_ACCESS_KEY:-${projectName}}
3309
+ - STORAGE_BUCKET=\${STORAGE_BUCKET:-${projectName}}
3310
+ - STORAGE_REGION=\${STORAGE_REGION:-eu-west-1}
3311
+ - STORAGE_FORCE_PATH_STYLE=true
3312
+ `;
3313
+ if (hasMail) yaml += ` - SMTP_HOST=\${SMTP_HOST:-mailpit}
3314
+ - SMTP_PORT=\${SMTP_PORT:-1025}
3315
+ - SMTP_USER=\${SMTP_USER:-${projectName}}
3316
+ - SMTP_PASS=\${SMTP_PASS:-${projectName}}
3253
3317
  `;
3254
3318
  }
3255
3319
  yaml += ` healthcheck:
@@ -3263,6 +3327,7 @@ function generateAppService(appName, app, allApps, options) {
3263
3327
  if (hasPostgres) dependencies$1.push("postgres");
3264
3328
  if (hasRedis) dependencies$1.push("redis");
3265
3329
  if (hasMinio) dependencies$1.push("minio");
3330
+ if (hasMail) dependencies$1.push("mailpit");
3266
3331
  }
3267
3332
  if (dependencies$1.length > 0) {
3268
3333
  yaml += ` depends_on:
@@ -6307,7 +6372,7 @@ async function deployCommand(options) {
6307
6372
  dokployConfig = setupResult.config;
6308
6373
  finalRegistry = dokployConfig.registry ?? dockerConfig.registry;
6309
6374
  if (setupResult.serviceUrls) {
6310
- const { readStageSecrets: readStageSecrets$1, writeStageSecrets: writeStageSecrets$1, initStageSecrets } = await import("./storage-C1FNm2EP.mjs");
6375
+ const { readStageSecrets: readStageSecrets$1, writeStageSecrets: writeStageSecrets$1, initStageSecrets } = await import("./storage-BFqrVsip.mjs");
6311
6376
  let secrets = await readStageSecrets$1(stage);
6312
6377
  if (!secrets) {
6313
6378
  logger$3.log(` Creating secrets file for stage "${stage}"...`);
@@ -6601,7 +6666,7 @@ const GEEKMIDAS_VERSIONS = {
6601
6666
  "@geekmidas/rate-limit": "~2.0.0",
6602
6667
  "@geekmidas/schema": "~1.0.0",
6603
6668
  "@geekmidas/services": "~1.0.1",
6604
- "@geekmidas/storage": "~2.0.0",
6669
+ "@geekmidas/storage": "~2.0.1",
6605
6670
  "@geekmidas/studio": "~1.0.0",
6606
6671
  "@geekmidas/telescope": "~1.0.0",
6607
6672
  "@geekmidas/testkit": "~1.0.5",
@@ -7157,8 +7222,7 @@ function generateDockerFiles(options, template, dbApps) {
7157
7222
  - '\${MAILPIT_SMTP_HOST_PORT:-1025}:1025'
7158
7223
  - '\${MAILPIT_UI_HOST_PORT:-8025}:8025'
7159
7224
  environment:
7160
- MP_SMTP_AUTH_ACCEPT_ANY: 1
7161
- MP_SMTP_AUTH_ALLOW_INSECURE: 1`);
7225
+ MP_SMTP_AUTH: \${SMTP_USER:-${options.name}}:\${SMTP_PASS:-${options.name}}`);
7162
7226
  let dockerCompose = `# Use "gkm dev" or "gkm test" to start services.
7163
7227
  # Running "docker compose up" directly will not inject secrets or resolve ports.
7164
7228
  services:
@@ -10973,6 +11037,7 @@ async function initCommand(projectName, options = {}) {
10973
11037
  if (services.db) secretServices.push("postgres");
10974
11038
  if (services.cache) secretServices.push("redis");
10975
11039
  if (services.storage) secretServices.push("minio");
11040
+ if (services.mail) secretServices.push("mailpit");
10976
11041
  const devSecrets = createStageSecrets("development", secretServices, { projectName: name$1 });
10977
11042
  const customSecrets = {
10978
11043
  NODE_ENV: "development",
@@ -11131,7 +11196,7 @@ async function secretsInitCommand(options) {
11131
11196
  if (secrets.urls.DATABASE_URL) logger$2.log(`\n DATABASE_URL: ${maskUrl(secrets.urls.DATABASE_URL)}`);
11132
11197
  if (secrets.urls.REDIS_URL) logger$2.log(` REDIS_URL: ${maskUrl(secrets.urls.REDIS_URL)}`);
11133
11198
  if (secrets.urls.RABBITMQ_URL) logger$2.log(` RABBITMQ_URL: ${maskUrl(secrets.urls.RABBITMQ_URL)}`);
11134
- if (secrets.urls.S3_ENDPOINT) logger$2.log(` S3_ENDPOINT: ${secrets.urls.S3_ENDPOINT}`);
11199
+ if (secrets.urls.STORAGE_ENDPOINT) logger$2.log(` STORAGE_ENDPOINT: ${secrets.urls.STORAGE_ENDPOINT}`);
11135
11200
  if (Object.keys(secrets.custom).length > 0) logger$2.log(`\n Custom secrets: ${Object.keys(secrets.custom).length}`);
11136
11201
  logger$2.log(`\n Use "gkm secrets:show --stage ${stage}" to view secrets`);
11137
11202
  logger$2.log(" Use \"gkm secrets:set <KEY> <VALUE> --stage " + stage + "\" to add custom secrets");
@@ -11199,7 +11264,7 @@ async function secretsShowCommand(options) {
11199
11264
  if (secrets.urls.DATABASE_URL) logger$2.log(` DATABASE_URL: ${reveal ? secrets.urls.DATABASE_URL : maskUrl(secrets.urls.DATABASE_URL)}`);
11200
11265
  if (secrets.urls.REDIS_URL) logger$2.log(` REDIS_URL: ${reveal ? secrets.urls.REDIS_URL : maskUrl(secrets.urls.REDIS_URL)}`);
11201
11266
  if (secrets.urls.RABBITMQ_URL) logger$2.log(` RABBITMQ_URL: ${reveal ? secrets.urls.RABBITMQ_URL : maskUrl(secrets.urls.RABBITMQ_URL)}`);
11202
- if (secrets.urls.S3_ENDPOINT) logger$2.log(` S3_ENDPOINT: ${secrets.urls.S3_ENDPOINT}`);
11267
+ if (secrets.urls.STORAGE_ENDPOINT) logger$2.log(` STORAGE_ENDPOINT: ${secrets.urls.STORAGE_ENDPOINT}`);
11203
11268
  const customKeys = Object.keys(secrets.custom);
11204
11269
  if (customKeys.length > 0) {
11205
11270
  logger$2.log("\nCustom Secrets:");
@@ -11398,6 +11463,10 @@ function reconcileSecrets(secrets, workspace) {
11398
11463
  ];
11399
11464
  for (const { key, name: name$1 } of serviceMap) if (workspace.services[key] && !result.services[name$1]) {
11400
11465
  const creds = generateServiceCredentials(name$1);
11466
+ if (name$1 === "minio") {
11467
+ creds.bucket = workspace.name;
11468
+ creds.username = workspace.name;
11469
+ }
11401
11470
  result = {
11402
11471
  ...result,
11403
11472
  services: {
@@ -11537,14 +11606,11 @@ async function testCommand(options = {}) {
11537
11606
  const composePath = join(cwd, "docker-compose.yml");
11538
11607
  const mappings = parseComposePortMappings(composePath);
11539
11608
  if (mappings.length > 0) {
11540
- const ports = await loadPortState(cwd);
11541
- if (Object.keys(ports).length > 0) {
11542
- secretsEnv = rewriteUrlsWithPorts(secretsEnv, {
11543
- dockerEnv: {},
11544
- ports,
11545
- mappings
11546
- });
11547
- console.log(` 🔌 Applied ${Object.keys(ports).length} port mapping(s)`);
11609
+ const resolvedPorts = await resolveServicePorts(cwd);
11610
+ await startComposeServices(cwd, resolvedPorts.dockerEnv, secretsEnv);
11611
+ if (resolvedPorts.mappings.length > 0) {
11612
+ secretsEnv = rewriteUrlsWithPorts(secretsEnv, resolvedPorts);
11613
+ console.log(` 🔌 Applied ${Object.keys(resolvedPorts.ports).length} port mapping(s)`);
11548
11614
  }
11549
11615
  }
11550
11616
  }
@@ -11983,9 +12049,9 @@ program.command("secrets:push").description("Push secrets to remote provider (SS
11983
12049
  const globalOptions = program.opts();
11984
12050
  if (globalOptions.cwd) process.chdir(globalOptions.cwd);
11985
12051
  const { loadWorkspaceConfig: loadWorkspaceConfig$1 } = await import("./config.mjs");
11986
- const { pushSecrets: pushSecrets$1 } = await import("./sync-CyGe5f1I.mjs");
11987
- const { reconcileMissingSecrets } = await import("./reconcile-C0dsg-Gq.mjs");
11988
- const { readStageSecrets: readStageSecrets$1, writeStageSecrets: writeStageSecrets$1 } = await import("./storage-C1FNm2EP.mjs");
12052
+ const { pushSecrets: pushSecrets$1 } = await import("./sync-DjD_TeNX.mjs");
12053
+ const { reconcileMissingSecrets } = await import("./reconcile-DxTEausy.mjs");
12054
+ const { readStageSecrets: readStageSecrets$1, writeStageSecrets: writeStageSecrets$1 } = await import("./storage-BFqrVsip.mjs");
11989
12055
  const { workspace } = await loadWorkspaceConfig$1();
11990
12056
  const secrets = await readStageSecrets$1(options.stage, workspace.root);
11991
12057
  if (secrets) {
@@ -12008,9 +12074,9 @@ program.command("secrets:pull").description("Pull secrets from remote provider (
12008
12074
  const globalOptions = program.opts();
12009
12075
  if (globalOptions.cwd) process.chdir(globalOptions.cwd);
12010
12076
  const { loadWorkspaceConfig: loadWorkspaceConfig$1 } = await import("./config.mjs");
12011
- const { pullSecrets: pullSecrets$1 } = await import("./sync-CyGe5f1I.mjs");
12012
- const { writeStageSecrets: writeStageSecrets$1 } = await import("./storage-C1FNm2EP.mjs");
12013
- const { reconcileMissingSecrets } = await import("./reconcile-C0dsg-Gq.mjs");
12077
+ const { pullSecrets: pullSecrets$1 } = await import("./sync-DjD_TeNX.mjs");
12078
+ const { writeStageSecrets: writeStageSecrets$1 } = await import("./storage-BFqrVsip.mjs");
12079
+ const { reconcileMissingSecrets } = await import("./reconcile-DxTEausy.mjs");
12014
12080
  const { workspace } = await loadWorkspaceConfig$1();
12015
12081
  let secrets = await pullSecrets$1(options.stage, workspace);
12016
12082
  if (!secrets) {
@@ -12035,8 +12101,8 @@ program.command("secrets:reconcile").description("Backfill missing custom secret
12035
12101
  const globalOptions = program.opts();
12036
12102
  if (globalOptions.cwd) process.chdir(globalOptions.cwd);
12037
12103
  const { loadWorkspaceConfig: loadWorkspaceConfig$1 } = await import("./config.mjs");
12038
- const { reconcileMissingSecrets } = await import("./reconcile-C0dsg-Gq.mjs");
12039
- const { readStageSecrets: readStageSecrets$1, writeStageSecrets: writeStageSecrets$1 } = await import("./storage-C1FNm2EP.mjs");
12104
+ const { reconcileMissingSecrets } = await import("./reconcile-DxTEausy.mjs");
12105
+ const { readStageSecrets: readStageSecrets$1, writeStageSecrets: writeStageSecrets$1 } = await import("./storage-BFqrVsip.mjs");
12040
12106
  const { workspace } = await loadWorkspaceConfig$1();
12041
12107
  const secrets = await readStageSecrets$1(options.stage, workspace.root);
12042
12108
  if (!secrets) {