@envsync-cloud/deploy 0.20.12 → 0.21.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 (3) hide show
  1. package/dist/cli.js +30 -23
  2. package/dist/index.js +30 -23
  3. package/package.json +2 -2
package/dist/cli.js CHANGED
@@ -37,13 +37,11 @@ var deployConfigSchema = z.object({
37
37
  services: z.object({
38
38
  stack_name: z.string().default("envsync"),
39
39
  api_port: z.number().int().positive().default(4e3),
40
- management_api_port: z.number().int().positive().default(4001),
41
40
  public_http_port: z.number().int().positive().default(80),
42
41
  public_https_port: z.number().int().positive().default(443)
43
42
  }).default({}),
44
43
  images: z.object({
45
44
  api: z.string().default("ghcr.io/envsync-cloud/envsync-api:stable"),
46
- management_api: z.string().default("ghcr.io/envsync-cloud/envsync-management-api:stable"),
47
45
  web: z.string().default("ghcr.io/envsync-cloud/envsync-web-oss-static:stable"),
48
46
  enterprise_web: z.string().default("ghcr.io/envsync-cloud/envsync-web-static:stable"),
49
47
  landing: z.string().default("ghcr.io/envsync-cloud/envsync-landing-static:stable"),
@@ -383,7 +381,6 @@ function buildRuntimeEnv2(config, generated, options) {
383
381
  ENVSYNC_STACK_NAME: config.services.stack_name,
384
382
  DB_AUTO_MIGRATE: "false",
385
383
  PORT: `${config.services.api_port}`,
386
- MANAGEMENT_API_PORT: `${config.services.management_api_port}`,
387
384
  DATABASE_HOST: "postgres",
388
385
  DATABASE_PORT: "5432",
389
386
  DATABASE_USER: "postgres",
@@ -427,7 +424,13 @@ function buildRuntimeEnv2(config, generated, options) {
427
424
  OPENFGA_MODEL_ID: generated.openfga.model_id,
428
425
  OPENFGA_DB_PASSWORD: generated.secrets.openfga_db_password,
429
426
  API_URL: publicHttpsUrl(config, hosts.api),
427
+ SAML_SESSION_SECRET: generated.secrets.saml_session_secret,
430
428
  MANAGEMENT_API_URL: oss ? "" : publicHttpsUrl(config, hosts.api, "/api/v1/manage"),
429
+ KEYCLOAK_ACCESS_TOKEN_LIFESPAN_SECONDS: "3600",
430
+ KEYCLOAK_SSO_SESSION_IDLE_TIMEOUT_SECONDS: "604800",
431
+ KEYCLOAK_SSO_SESSION_MAX_LIFESPAN_SECONDS: "604800",
432
+ KEYCLOAK_CLIENT_SESSION_IDLE_TIMEOUT_SECONDS: "604800",
433
+ KEYCLOAK_CLIENT_SESSION_MAX_LIFESPAN_SECONDS: "604800",
431
434
  CLICKSTACK_OPERATOR_EMAIL: generated.clickstack.operator_email,
432
435
  CLICKSTACK_OPERATOR_PASSWORD: generated.clickstack.operator_password,
433
436
  CLICKSTACK_ACCESS_KEY: generated.clickstack.access_key,
@@ -466,12 +469,22 @@ function renderKeycloakRealm(config, runtimeEnv) {
466
469
  const webOrigins = publicHttpsOriginVariants(config, hosts.app);
467
470
  const apiRedirectUris = publicHttpsUrlVariants(config, hosts.api, "/api/access/api/callback");
468
471
  const apiOrigins = publicHttpsOriginVariants(config, hosts.api);
472
+ const accessTokenLifespan = Number(runtimeEnv.KEYCLOAK_ACCESS_TOKEN_LIFESPAN_SECONDS || "3600");
473
+ const ssoSessionIdleTimeout = Number(runtimeEnv.KEYCLOAK_SSO_SESSION_IDLE_TIMEOUT_SECONDS || "604800");
474
+ const ssoSessionMaxLifespan = Number(runtimeEnv.KEYCLOAK_SSO_SESSION_MAX_LIFESPAN_SECONDS || "604800");
475
+ const clientSessionIdleTimeout = Number(runtimeEnv.KEYCLOAK_CLIENT_SESSION_IDLE_TIMEOUT_SECONDS || "604800");
476
+ const clientSessionMaxLifespan = Number(runtimeEnv.KEYCLOAK_CLIENT_SESSION_MAX_LIFESPAN_SECONDS || "604800");
469
477
  return JSON.stringify(
470
478
  {
471
479
  realm: config.auth.keycloak_realm,
472
480
  enabled: true,
473
481
  loginTheme: "envsync",
474
482
  emailTheme: "envsync",
483
+ accessTokenLifespan,
484
+ ssoSessionIdleTimeout,
485
+ ssoSessionMaxLifespan,
486
+ clientSessionIdleTimeout,
487
+ clientSessionMaxLifespan,
475
488
  clients: [
476
489
  {
477
490
  clientId: config.auth.web_client_id,
@@ -1021,7 +1034,7 @@ ${includeRuntimeInfra ? `
1021
1034
  image: ${config.images.keycloak}
1022
1035
  entrypoint: ["/bin/sh", "-lc"]
1023
1036
  command:
1024
- - /opt/keycloak/bin/kc.sh import --dir /opt/keycloak/data/import --override true && exec /opt/keycloak/bin/kc.sh start --optimized
1037
+ - /opt/keycloak/bin/kc.sh import --dir /opt/keycloak/data/import --override false && exec /opt/keycloak/bin/kc.sh start --optimized
1025
1038
  environment:
1026
1039
  ${renderEnvList({
1027
1040
  KC_DB: "postgres",
@@ -1581,8 +1594,6 @@ var DEFAULT_ENTERPRISE_LICENSE_SERVER_URL = "https://license.envsync.cloud";
1581
1594
  var MANAGED_VERSIONED_IMAGE_PREFIXES = {
1582
1595
  api: "ghcr.io/envsync-cloud/envsync-api:",
1583
1596
  api_enterprise: "ghcr.io/envsync-cloud/envsync-api-enterprise:",
1584
- // Retired second process — kept so old deploy.yaml image strings still parse as "managed".
1585
- management_api: "ghcr.io/envsync-cloud/envsync-management-api:",
1586
1597
  keycloak: "envsync-keycloak:",
1587
1598
  web: "ghcr.io/envsync-cloud/envsync-web-static:",
1588
1599
  web_oss: "ghcr.io/envsync-cloud/envsync-web-oss-static:",
@@ -2203,7 +2214,6 @@ function buildOperatorOverview() {
2203
2214
  const bootstrapComplete = hasCompleteBootstrapState(generated) && generated.bootstrap.completed_at.length > 0;
2204
2215
  const api = apiHealth(services, config.services.stack_name);
2205
2216
  const web = serviceHealth(services, `${config.services.stack_name}_web_nginx`);
2206
- const landing = serviceHealth(services, `${config.services.stack_name}_landing_nginx`);
2207
2217
  statusLines.push(`Configured: ${chalk.green("yes")}`);
2208
2218
  statusLines.push(`Pinned release: ${chalk.cyan(config.release.version)}`);
2209
2219
  statusLines.push(`Stack: ${stackRunning ? chalk.green(config.services.stack_name) : chalk.yellow("not running")}`);
@@ -2211,7 +2221,7 @@ function buildOperatorOverview() {
2211
2221
  statusLines.push(`Active API slot: ${chalk.cyan(generated.deployment.active_slot)}`);
2212
2222
  statusLines.push(`API: ${api === "healthy" ? chalk.green(api) : api === "missing" ? chalk.red(api) : chalk.yellow(api)}`);
2213
2223
  statusLines.push(`Web: ${web === "healthy" ? chalk.green(web) : web === "missing" ? chalk.red(web) : chalk.yellow(web)}`);
2214
- statusLines.push(`Landing: ${landing === "healthy" ? chalk.green(landing) : landing === "missing" ? chalk.red(landing) : chalk.yellow(landing)}`);
2224
+ statusLines.push(`Landing: ${chalk.dim("omitted")}`);
2215
2225
  if (!bootstrapComplete) {
2216
2226
  return {
2217
2227
  statusLines,
@@ -2221,7 +2231,7 @@ function buildOperatorOverview() {
2221
2231
  ]
2222
2232
  };
2223
2233
  }
2224
- if (api !== "healthy" || web !== "healthy" || landing !== "healthy") {
2234
+ if (api !== "healthy" || web !== "healthy") {
2225
2235
  return {
2226
2236
  statusLines,
2227
2237
  nextSteps: [
@@ -2290,8 +2300,6 @@ function versionedImages(version, edition = "enterprise") {
2290
2300
  const api = edition === "oss" ? `ghcr.io/envsync-cloud/envsync-api:${version}` : `ghcr.io/envsync-cloud/envsync-api-enterprise:${version}`;
2291
2301
  return {
2292
2302
  api,
2293
- // Deprecated field: kept for older deploy.yaml keys; unused by stack render.
2294
- management_api: api,
2295
2303
  keycloak: `envsync-keycloak:${version}`,
2296
2304
  web,
2297
2305
  landing: `ghcr.io/envsync-cloud/envsync-landing-static:${version}`
@@ -2377,7 +2385,6 @@ function normalizeConfig(raw) {
2377
2385
  },
2378
2386
  images: {
2379
2387
  api: !raw.images?.api || isManagedVersionedImage(raw.images.api, "api") ? derivedImages.api : raw.images.api,
2380
- management_api: !raw.images?.management_api || isManagedVersionedImage(raw.images.management_api, "management_api") ? derivedImages.management_api : raw.images.management_api,
2381
2388
  keycloak: !raw.images?.keycloak || isManagedVersionedImage(raw.images.keycloak, "keycloak") ? derivedImages.keycloak : raw.images.keycloak,
2382
2389
  web: !raw.images?.web || isManagedVersionedImage(raw.images.web, "web") ? derivedImages.web : raw.images.web,
2383
2390
  landing: !raw.images?.landing || isManagedVersionedImage(raw.images.landing, "landing") ? derivedImages.landing : raw.images.landing,
@@ -2388,7 +2395,6 @@ function normalizeConfig(raw) {
2388
2395
  services: {
2389
2396
  stack_name: stackName,
2390
2397
  api_port: requireDefined(raw.services?.api_port, "services.api_port"),
2391
- management_api_port: raw.services?.management_api_port ?? 4001,
2392
2398
  public_http_port: raw.services?.public_http_port ?? 80,
2393
2399
  public_https_port: raw.services?.public_https_port ?? 443,
2394
2400
  clickstack_ui_port: requireDefined(raw.services?.clickstack_ui_port, "services.clickstack_ui_port"),
@@ -2489,7 +2495,8 @@ function emptyGeneratedState() {
2489
2495
  openfga_db_password: "",
2490
2496
  minikms_root_key: "",
2491
2497
  minikms_session_signing_key: "",
2492
- minikms_db_password: ""
2498
+ minikms_db_password: "",
2499
+ saml_session_secret: ""
2493
2500
  },
2494
2501
  bootstrap: {
2495
2502
  completed_at: ""
@@ -2526,7 +2533,8 @@ function normalizeGeneratedState(raw) {
2526
2533
  openfga_db_password: raw?.secrets?.openfga_db_password ?? defaults.secrets.openfga_db_password,
2527
2534
  minikms_root_key: raw?.secrets?.minikms_root_key ?? defaults.secrets.minikms_root_key,
2528
2535
  minikms_session_signing_key: raw?.secrets?.minikms_session_signing_key ?? defaults.secrets.minikms_session_signing_key,
2529
- minikms_db_password: raw?.secrets?.minikms_db_password ?? defaults.secrets.minikms_db_password
2536
+ minikms_db_password: raw?.secrets?.minikms_db_password ?? defaults.secrets.minikms_db_password,
2537
+ saml_session_secret: raw?.secrets?.saml_session_secret ?? defaults.secrets.saml_session_secret
2530
2538
  },
2531
2539
  bootstrap: {
2532
2540
  completed_at: raw?.bootstrap?.completed_at ?? defaults.bootstrap.completed_at
@@ -2577,7 +2585,8 @@ function mergeGeneratedState(env, generated) {
2577
2585
  openfga_db_password: env.OPENFGA_DB_PASSWORD ?? normalized.secrets.openfga_db_password,
2578
2586
  minikms_root_key: env.MINIKMS_ROOT_KEY ?? normalized.secrets.minikms_root_key,
2579
2587
  minikms_session_signing_key: env.MINIKMS_SESSION_SIGNING_KEY ?? normalized.secrets.minikms_session_signing_key,
2580
- minikms_db_password: env.MINIKMS_DB_PASSWORD ?? normalized.secrets.minikms_db_password
2588
+ minikms_db_password: env.MINIKMS_DB_PASSWORD ?? normalized.secrets.minikms_db_password,
2589
+ saml_session_secret: env.SAML_SESSION_SECRET ?? normalized.secrets.saml_session_secret
2581
2590
  },
2582
2591
  bootstrap: normalized.bootstrap
2583
2592
  });
@@ -2606,7 +2615,8 @@ function ensureGeneratedRuntimeState(config, generated) {
2606
2615
  openfga_db_password: generated.secrets.openfga_db_password || randomSecret(),
2607
2616
  minikms_root_key: generated.secrets.minikms_root_key || randomBytes2(32).toString("hex"),
2608
2617
  minikms_session_signing_key: generated.secrets.minikms_session_signing_key || generateMinikmsSessionSigningKey(),
2609
- minikms_db_password: generated.secrets.minikms_db_password || randomSecret()
2618
+ minikms_db_password: generated.secrets.minikms_db_password || randomSecret(),
2619
+ saml_session_secret: generated.secrets.saml_session_secret || randomBytes2(32).toString("hex")
2610
2620
  },
2611
2621
  bootstrap: generated.bootstrap
2612
2622
  });
@@ -3977,7 +3987,6 @@ async function cmdSetup() {
3977
3987
  domain: { root_domain: rootDomain, acme_email: acmeEmail },
3978
3988
  images: {
3979
3989
  api: releaseImages.api,
3980
- management_api: releaseImages.management_api,
3981
3990
  keycloak: releaseImages.keycloak,
3982
3991
  web: releaseImages.web,
3983
3992
  landing: releaseImages.landing,
@@ -3988,7 +3997,6 @@ async function cmdSetup() {
3988
3997
  services: {
3989
3998
  stack_name: "envsync",
3990
3999
  api_port: 4e3,
3991
- management_api_port: 4001,
3992
4000
  public_http_port: 80,
3993
4001
  public_https_port: 443,
3994
4002
  clickstack_ui_port: 8080,
@@ -4387,7 +4395,6 @@ ${rollbackError instanceof Error ? rollbackError.message : String(rollbackError)
4387
4395
  { label: "openfga", getHealth: (services) => serviceHealth(services, `${config.services.stack_name}_openfga`) },
4388
4396
  { label: "minikms", getHealth: (services) => serviceHealth(services, `${config.services.stack_name}_minikms`) },
4389
4397
  { label: "clickstack", getHealth: (services) => serviceHealth(services, `${config.services.stack_name}_clickstack`) },
4390
- ...isOssConfig2(config) ? [] : [{ label: "landing", getHealth: (services) => serviceHealth(services, `${config.services.stack_name}_landing_nginx`) }],
4391
4398
  { label: "web", getHealth: (services) => serviceHealth(services, `${config.services.stack_name}_web_nginx`) },
4392
4399
  { label: "api", getHealth: (services) => apiHealth(services, config.services.stack_name) }
4393
4400
  ]);
@@ -4430,7 +4437,7 @@ async function cmdPromote(target) {
4430
4437
  }
4431
4438
  });
4432
4439
  writeDeployArtifacts(config, promotedState);
4433
- if (exists2(releaseAssetDir("web", promotedState.deployment.slots[targetSlot].release_version)) && exists2(releaseAssetDir("landing", promotedState.deployment.slots[targetSlot].release_version))) {
4440
+ if (exists2(releaseAssetDir("web", promotedState.deployment.slots[targetSlot].release_version))) {
4434
4441
  activateFrontendReleaseForState(config, promotedState);
4435
4442
  } else {
4436
4443
  logWarn(`Missing staged frontend assets for release ${promotedState.deployment.slots[targetSlot].release_version}; leaving current frontend assets unchanged.`);
@@ -4461,7 +4468,7 @@ async function cmdRollback() {
4461
4468
  }
4462
4469
  });
4463
4470
  writeDeployArtifacts(config, rollbackState);
4464
- if (exists2(releaseAssetDir("web", rollbackState.deployment.slots[rollbackState.deployment.active_slot].release_version)) && exists2(releaseAssetDir("landing", rollbackState.deployment.slots[rollbackState.deployment.active_slot].release_version))) {
4471
+ if (exists2(releaseAssetDir("web", rollbackState.deployment.slots[rollbackState.deployment.active_slot].release_version))) {
4465
4472
  activateFrontendReleaseForState(config, rollbackState);
4466
4473
  } else {
4467
4474
  logWarn(`Missing staged frontend assets for release ${rollbackState.deployment.slots[rollbackState.deployment.active_slot].release_version}; leaving current frontend assets unchanged.`);
@@ -4557,7 +4564,7 @@ async function cmdHealth(asJson) {
4557
4564
  }
4558
4565
  },
4559
4566
  web: serviceHealth(services, `${stackName}_web_nginx`),
4560
- landing: serviceHealth(services, `${stackName}_landing_nginx`)
4567
+ landing: "omitted"
4561
4568
  },
4562
4569
  database: {
4563
4570
  api: databaseHealth
package/dist/index.js CHANGED
@@ -243,13 +243,11 @@ var init_src = __esm({
243
243
  services: z.object({
244
244
  stack_name: z.string().default("envsync"),
245
245
  api_port: z.number().int().positive().default(4e3),
246
- management_api_port: z.number().int().positive().default(4001),
247
246
  public_http_port: z.number().int().positive().default(80),
248
247
  public_https_port: z.number().int().positive().default(443)
249
248
  }).default({}),
250
249
  images: z.object({
251
250
  api: z.string().default("ghcr.io/envsync-cloud/envsync-api:stable"),
252
- management_api: z.string().default("ghcr.io/envsync-cloud/envsync-management-api:stable"),
253
251
  web: z.string().default("ghcr.io/envsync-cloud/envsync-web-oss-static:stable"),
254
252
  enterprise_web: z.string().default("ghcr.io/envsync-cloud/envsync-web-static:stable"),
255
253
  landing: z.string().default("ghcr.io/envsync-cloud/envsync-landing-static:stable"),
@@ -384,7 +382,6 @@ function buildRuntimeEnv2(config, generated, options) {
384
382
  ENVSYNC_STACK_NAME: config.services.stack_name,
385
383
  DB_AUTO_MIGRATE: "false",
386
384
  PORT: `${config.services.api_port}`,
387
- MANAGEMENT_API_PORT: `${config.services.management_api_port}`,
388
385
  DATABASE_HOST: "postgres",
389
386
  DATABASE_PORT: "5432",
390
387
  DATABASE_USER: "postgres",
@@ -428,7 +425,13 @@ function buildRuntimeEnv2(config, generated, options) {
428
425
  OPENFGA_MODEL_ID: generated.openfga.model_id,
429
426
  OPENFGA_DB_PASSWORD: generated.secrets.openfga_db_password,
430
427
  API_URL: publicHttpsUrl(config, hosts.api),
428
+ SAML_SESSION_SECRET: generated.secrets.saml_session_secret,
431
429
  MANAGEMENT_API_URL: oss ? "" : publicHttpsUrl(config, hosts.api, "/api/v1/manage"),
430
+ KEYCLOAK_ACCESS_TOKEN_LIFESPAN_SECONDS: "3600",
431
+ KEYCLOAK_SSO_SESSION_IDLE_TIMEOUT_SECONDS: "604800",
432
+ KEYCLOAK_SSO_SESSION_MAX_LIFESPAN_SECONDS: "604800",
433
+ KEYCLOAK_CLIENT_SESSION_IDLE_TIMEOUT_SECONDS: "604800",
434
+ KEYCLOAK_CLIENT_SESSION_MAX_LIFESPAN_SECONDS: "604800",
432
435
  CLICKSTACK_OPERATOR_EMAIL: generated.clickstack.operator_email,
433
436
  CLICKSTACK_OPERATOR_PASSWORD: generated.clickstack.operator_password,
434
437
  CLICKSTACK_ACCESS_KEY: generated.clickstack.access_key,
@@ -467,12 +470,22 @@ function renderKeycloakRealm(config, runtimeEnv) {
467
470
  const webOrigins = publicHttpsOriginVariants(config, hosts.app);
468
471
  const apiRedirectUris = publicHttpsUrlVariants(config, hosts.api, "/api/access/api/callback");
469
472
  const apiOrigins = publicHttpsOriginVariants(config, hosts.api);
473
+ const accessTokenLifespan = Number(runtimeEnv.KEYCLOAK_ACCESS_TOKEN_LIFESPAN_SECONDS || "3600");
474
+ const ssoSessionIdleTimeout = Number(runtimeEnv.KEYCLOAK_SSO_SESSION_IDLE_TIMEOUT_SECONDS || "604800");
475
+ const ssoSessionMaxLifespan = Number(runtimeEnv.KEYCLOAK_SSO_SESSION_MAX_LIFESPAN_SECONDS || "604800");
476
+ const clientSessionIdleTimeout = Number(runtimeEnv.KEYCLOAK_CLIENT_SESSION_IDLE_TIMEOUT_SECONDS || "604800");
477
+ const clientSessionMaxLifespan = Number(runtimeEnv.KEYCLOAK_CLIENT_SESSION_MAX_LIFESPAN_SECONDS || "604800");
470
478
  return JSON.stringify(
471
479
  {
472
480
  realm: config.auth.keycloak_realm,
473
481
  enabled: true,
474
482
  loginTheme: "envsync",
475
483
  emailTheme: "envsync",
484
+ accessTokenLifespan,
485
+ ssoSessionIdleTimeout,
486
+ ssoSessionMaxLifespan,
487
+ clientSessionIdleTimeout,
488
+ clientSessionMaxLifespan,
476
489
  clients: [
477
490
  {
478
491
  clientId: config.auth.web_client_id,
@@ -1018,7 +1031,7 @@ ${includeRuntimeInfra ? `
1018
1031
  image: ${config.images.keycloak}
1019
1032
  entrypoint: ["/bin/sh", "-lc"]
1020
1033
  command:
1021
- - /opt/keycloak/bin/kc.sh import --dir /opt/keycloak/data/import --override true && exec /opt/keycloak/bin/kc.sh start --optimized
1034
+ - /opt/keycloak/bin/kc.sh import --dir /opt/keycloak/data/import --override false && exec /opt/keycloak/bin/kc.sh start --optimized
1022
1035
  environment:
1023
1036
  ${renderEnvList({
1024
1037
  KC_DB: "postgres",
@@ -2064,7 +2077,6 @@ function buildOperatorOverview() {
2064
2077
  const bootstrapComplete = hasCompleteBootstrapState(generated) && generated.bootstrap.completed_at.length > 0;
2065
2078
  const api = apiHealth(services, config.services.stack_name);
2066
2079
  const web = serviceHealth(services, `${config.services.stack_name}_web_nginx`);
2067
- const landing = serviceHealth(services, `${config.services.stack_name}_landing_nginx`);
2068
2080
  statusLines.push(`Configured: ${chalk.green("yes")}`);
2069
2081
  statusLines.push(`Pinned release: ${chalk.cyan(config.release.version)}`);
2070
2082
  statusLines.push(`Stack: ${stackRunning ? chalk.green(config.services.stack_name) : chalk.yellow("not running")}`);
@@ -2072,7 +2084,7 @@ function buildOperatorOverview() {
2072
2084
  statusLines.push(`Active API slot: ${chalk.cyan(generated.deployment.active_slot)}`);
2073
2085
  statusLines.push(`API: ${api === "healthy" ? chalk.green(api) : api === "missing" ? chalk.red(api) : chalk.yellow(api)}`);
2074
2086
  statusLines.push(`Web: ${web === "healthy" ? chalk.green(web) : web === "missing" ? chalk.red(web) : chalk.yellow(web)}`);
2075
- statusLines.push(`Landing: ${landing === "healthy" ? chalk.green(landing) : landing === "missing" ? chalk.red(landing) : chalk.yellow(landing)}`);
2087
+ statusLines.push(`Landing: ${chalk.dim("omitted")}`);
2076
2088
  if (!bootstrapComplete) {
2077
2089
  return {
2078
2090
  statusLines,
@@ -2082,7 +2094,7 @@ function buildOperatorOverview() {
2082
2094
  ]
2083
2095
  };
2084
2096
  }
2085
- if (api !== "healthy" || web !== "healthy" || landing !== "healthy") {
2097
+ if (api !== "healthy" || web !== "healthy") {
2086
2098
  return {
2087
2099
  statusLines,
2088
2100
  nextSteps: [
@@ -2151,8 +2163,6 @@ function versionedImages(version, edition = "enterprise") {
2151
2163
  const api = edition === "oss" ? `ghcr.io/envsync-cloud/envsync-api:${version}` : `ghcr.io/envsync-cloud/envsync-api-enterprise:${version}`;
2152
2164
  return {
2153
2165
  api,
2154
- // Deprecated field: kept for older deploy.yaml keys; unused by stack render.
2155
- management_api: api,
2156
2166
  keycloak: `envsync-keycloak:${version}`,
2157
2167
  web,
2158
2168
  landing: `ghcr.io/envsync-cloud/envsync-landing-static:${version}`
@@ -2238,7 +2248,6 @@ function normalizeConfig(raw) {
2238
2248
  },
2239
2249
  images: {
2240
2250
  api: !raw.images?.api || isManagedVersionedImage(raw.images.api, "api") ? derivedImages.api : raw.images.api,
2241
- management_api: !raw.images?.management_api || isManagedVersionedImage(raw.images.management_api, "management_api") ? derivedImages.management_api : raw.images.management_api,
2242
2251
  keycloak: !raw.images?.keycloak || isManagedVersionedImage(raw.images.keycloak, "keycloak") ? derivedImages.keycloak : raw.images.keycloak,
2243
2252
  web: !raw.images?.web || isManagedVersionedImage(raw.images.web, "web") ? derivedImages.web : raw.images.web,
2244
2253
  landing: !raw.images?.landing || isManagedVersionedImage(raw.images.landing, "landing") ? derivedImages.landing : raw.images.landing,
@@ -2249,7 +2258,6 @@ function normalizeConfig(raw) {
2249
2258
  services: {
2250
2259
  stack_name: stackName,
2251
2260
  api_port: requireDefined(raw.services?.api_port, "services.api_port"),
2252
- management_api_port: raw.services?.management_api_port ?? 4001,
2253
2261
  public_http_port: raw.services?.public_http_port ?? 80,
2254
2262
  public_https_port: raw.services?.public_https_port ?? 443,
2255
2263
  clickstack_ui_port: requireDefined(raw.services?.clickstack_ui_port, "services.clickstack_ui_port"),
@@ -2350,7 +2358,8 @@ function emptyGeneratedState() {
2350
2358
  openfga_db_password: "",
2351
2359
  minikms_root_key: "",
2352
2360
  minikms_session_signing_key: "",
2353
- minikms_db_password: ""
2361
+ minikms_db_password: "",
2362
+ saml_session_secret: ""
2354
2363
  },
2355
2364
  bootstrap: {
2356
2365
  completed_at: ""
@@ -2387,7 +2396,8 @@ function normalizeGeneratedState(raw) {
2387
2396
  openfga_db_password: raw?.secrets?.openfga_db_password ?? defaults.secrets.openfga_db_password,
2388
2397
  minikms_root_key: raw?.secrets?.minikms_root_key ?? defaults.secrets.minikms_root_key,
2389
2398
  minikms_session_signing_key: raw?.secrets?.minikms_session_signing_key ?? defaults.secrets.minikms_session_signing_key,
2390
- minikms_db_password: raw?.secrets?.minikms_db_password ?? defaults.secrets.minikms_db_password
2399
+ minikms_db_password: raw?.secrets?.minikms_db_password ?? defaults.secrets.minikms_db_password,
2400
+ saml_session_secret: raw?.secrets?.saml_session_secret ?? defaults.secrets.saml_session_secret
2391
2401
  },
2392
2402
  bootstrap: {
2393
2403
  completed_at: raw?.bootstrap?.completed_at ?? defaults.bootstrap.completed_at
@@ -2438,7 +2448,8 @@ function mergeGeneratedState(env, generated) {
2438
2448
  openfga_db_password: env.OPENFGA_DB_PASSWORD ?? normalized.secrets.openfga_db_password,
2439
2449
  minikms_root_key: env.MINIKMS_ROOT_KEY ?? normalized.secrets.minikms_root_key,
2440
2450
  minikms_session_signing_key: env.MINIKMS_SESSION_SIGNING_KEY ?? normalized.secrets.minikms_session_signing_key,
2441
- minikms_db_password: env.MINIKMS_DB_PASSWORD ?? normalized.secrets.minikms_db_password
2451
+ minikms_db_password: env.MINIKMS_DB_PASSWORD ?? normalized.secrets.minikms_db_password,
2452
+ saml_session_secret: env.SAML_SESSION_SECRET ?? normalized.secrets.saml_session_secret
2442
2453
  },
2443
2454
  bootstrap: normalized.bootstrap
2444
2455
  });
@@ -2467,7 +2478,8 @@ function ensureGeneratedRuntimeState(config, generated) {
2467
2478
  openfga_db_password: generated.secrets.openfga_db_password || randomSecret(),
2468
2479
  minikms_root_key: generated.secrets.minikms_root_key || randomBytes2(32).toString("hex"),
2469
2480
  minikms_session_signing_key: generated.secrets.minikms_session_signing_key || generateMinikmsSessionSigningKey(),
2470
- minikms_db_password: generated.secrets.minikms_db_password || randomSecret()
2481
+ minikms_db_password: generated.secrets.minikms_db_password || randomSecret(),
2482
+ saml_session_secret: generated.secrets.saml_session_secret || randomBytes2(32).toString("hex")
2471
2483
  },
2472
2484
  bootstrap: generated.bootstrap
2473
2485
  });
@@ -3833,7 +3845,6 @@ async function cmdSetup() {
3833
3845
  domain: { root_domain: rootDomain, acme_email: acmeEmail },
3834
3846
  images: {
3835
3847
  api: releaseImages.api,
3836
- management_api: releaseImages.management_api,
3837
3848
  keycloak: releaseImages.keycloak,
3838
3849
  web: releaseImages.web,
3839
3850
  landing: releaseImages.landing,
@@ -3844,7 +3855,6 @@ async function cmdSetup() {
3844
3855
  services: {
3845
3856
  stack_name: "envsync",
3846
3857
  api_port: 4e3,
3847
- management_api_port: 4001,
3848
3858
  public_http_port: 80,
3849
3859
  public_https_port: 443,
3850
3860
  clickstack_ui_port: 8080,
@@ -4243,7 +4253,6 @@ ${rollbackError instanceof Error ? rollbackError.message : String(rollbackError)
4243
4253
  { label: "openfga", getHealth: (services) => serviceHealth(services, `${config.services.stack_name}_openfga`) },
4244
4254
  { label: "minikms", getHealth: (services) => serviceHealth(services, `${config.services.stack_name}_minikms`) },
4245
4255
  { label: "clickstack", getHealth: (services) => serviceHealth(services, `${config.services.stack_name}_clickstack`) },
4246
- ...isOssConfig2(config) ? [] : [{ label: "landing", getHealth: (services) => serviceHealth(services, `${config.services.stack_name}_landing_nginx`) }],
4247
4256
  { label: "web", getHealth: (services) => serviceHealth(services, `${config.services.stack_name}_web_nginx`) },
4248
4257
  { label: "api", getHealth: (services) => apiHealth(services, config.services.stack_name) }
4249
4258
  ]);
@@ -4286,7 +4295,7 @@ async function cmdPromote(target) {
4286
4295
  }
4287
4296
  });
4288
4297
  writeDeployArtifacts(config, promotedState);
4289
- if (exists2(releaseAssetDir("web", promotedState.deployment.slots[targetSlot].release_version)) && exists2(releaseAssetDir("landing", promotedState.deployment.slots[targetSlot].release_version))) {
4298
+ if (exists2(releaseAssetDir("web", promotedState.deployment.slots[targetSlot].release_version))) {
4290
4299
  activateFrontendReleaseForState(config, promotedState);
4291
4300
  } else {
4292
4301
  logWarn(`Missing staged frontend assets for release ${promotedState.deployment.slots[targetSlot].release_version}; leaving current frontend assets unchanged.`);
@@ -4317,7 +4326,7 @@ async function cmdRollback() {
4317
4326
  }
4318
4327
  });
4319
4328
  writeDeployArtifacts(config, rollbackState);
4320
- if (exists2(releaseAssetDir("web", rollbackState.deployment.slots[rollbackState.deployment.active_slot].release_version)) && exists2(releaseAssetDir("landing", rollbackState.deployment.slots[rollbackState.deployment.active_slot].release_version))) {
4329
+ if (exists2(releaseAssetDir("web", rollbackState.deployment.slots[rollbackState.deployment.active_slot].release_version))) {
4321
4330
  activateFrontendReleaseForState(config, rollbackState);
4322
4331
  } else {
4323
4332
  logWarn(`Missing staged frontend assets for release ${rollbackState.deployment.slots[rollbackState.deployment.active_slot].release_version}; leaving current frontend assets unchanged.`);
@@ -4413,7 +4422,7 @@ async function cmdHealth(asJson) {
4413
4422
  }
4414
4423
  },
4415
4424
  web: serviceHealth(services, `${stackName}_web_nginx`),
4416
- landing: serviceHealth(services, `${stackName}_landing_nginx`)
4425
+ landing: "omitted"
4417
4426
  },
4418
4427
  database: {
4419
4428
  api: databaseHealth
@@ -5338,8 +5347,6 @@ var init_cli = __esm({
5338
5347
  MANAGED_VERSIONED_IMAGE_PREFIXES = {
5339
5348
  api: "ghcr.io/envsync-cloud/envsync-api:",
5340
5349
  api_enterprise: "ghcr.io/envsync-cloud/envsync-api-enterprise:",
5341
- // Retired second process — kept so old deploy.yaml image strings still parse as "managed".
5342
- management_api: "ghcr.io/envsync-cloud/envsync-management-api:",
5343
5350
  keycloak: "envsync-keycloak:",
5344
5351
  web: "ghcr.io/envsync-cloud/envsync-web-static:",
5345
5352
  web_oss: "ghcr.io/envsync-cloud/envsync-web-oss-static:",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@envsync-cloud/deploy",
3
- "version": "0.20.12",
3
+ "version": "0.21.0",
4
4
  "description": "OSS CLI for self-hosted EnvSync deployment on Docker Swarm",
5
5
  "type": "module",
6
6
  "bin": {
@@ -46,7 +46,7 @@
46
46
  "zod": "^3.25.76"
47
47
  },
48
48
  "devDependencies": {
49
- "@envsync-cloud/deploy-core": "0.20.12",
49
+ "@envsync-cloud/deploy-core": "0.21.0",
50
50
  "tsup": "^8.5.0",
51
51
  "typescript": "^5.9.2"
52
52
  },