@envsync-cloud/deploy 0.20.2 → 0.20.4

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 +42 -12
  2. package/dist/index.js +42 -12
  3. package/package.json +4 -3
package/dist/cli.js CHANGED
@@ -361,6 +361,7 @@ function buildRuntimeEnv2(config, generated, options) {
361
361
  ENVSYNC_EDITION: oss ? "oss" : "enterprise",
362
362
  // Self-host product install — never multi-tenant SaaS mode (program plan Phase 1).
363
363
  ENVSYNC_DEPLOYMENT_MODE: "selfhosted",
364
+ SKIP_ROOT_ENV: "1",
364
365
  ENVSYNC_MANAGEMENT_ENABLED: oss ? "false" : "true",
365
366
  // Landing is Hosted-only; self-host does not ship marketing/signup surface.
366
367
  ENVSYNC_LANDING_ENABLED: "false",
@@ -1144,6 +1145,12 @@ ${renderEnvList({
1144
1145
  })}
1145
1146
  ${apiLicenseVolume}
1146
1147
  networks: [envsync]
1148
+ healthcheck:
1149
+ test: ["CMD", "bun", "-e", "fetch('http://127.0.0.1:4000/health').then((r)=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))"]
1150
+ interval: 10s
1151
+ timeout: 5s
1152
+ retries: 8
1153
+ start_period: 45s
1147
1154
  deploy:
1148
1155
  replicas: ${slotHasApiDeployment(deployment.slots.blue) ? 1 : 0}
1149
1156
 
@@ -1157,6 +1164,12 @@ ${renderEnvList({
1157
1164
  })}
1158
1165
  ${apiLicenseVolume}
1159
1166
  networks: [envsync]
1167
+ healthcheck:
1168
+ test: ["CMD", "bun", "-e", "fetch('http://127.0.0.1:4000/health').then((r)=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))"]
1169
+ interval: 10s
1170
+ timeout: 5s
1171
+ retries: 8
1172
+ start_period: 45s
1160
1173
  deploy:
1161
1174
  replicas: ${slotHasApiDeployment(deployment.slots.green) ? 1 : 0}` : ""}${netutilsService}${vpnResult?.serviceBlock ?? ""}
1162
1175
 
@@ -2883,7 +2896,7 @@ function createApiDbUpgradeBackup(config, fromVersion, toVersion) {
2883
2896
  "postgres:17",
2884
2897
  "sh",
2885
2898
  "-lc",
2886
- `pg_dump -h ${config.services.stack_name}_postgres -U postgres -d envsync -Fc -f /backup/${fileName}`
2899
+ `pg_dump -h postgres -U postgres -d envsync -Fc -f /backup/${fileName}`
2887
2900
  ]);
2888
2901
  logSuccess(`API DB upgrade snapshot created at ${hostPath}`);
2889
2902
  return hostPath;
@@ -2907,7 +2920,7 @@ function restoreApiDbUpgradeBackup(config, backupPath) {
2907
2920
  "postgres:17",
2908
2921
  "sh",
2909
2922
  "-lc",
2910
- `pg_restore --clean --if-exists --no-owner --no-privileges -h ${config.services.stack_name}_postgres -U postgres -d envsync /backup/${fileName}`
2923
+ `pg_restore --clean --if-exists --no-owner --no-privileges -h postgres -U postgres -d envsync /backup/${fileName}`
2911
2924
  ]);
2912
2925
  logSuccess(`API DB upgrade snapshot restored from ${backupPath}`);
2913
2926
  }
@@ -3275,6 +3288,7 @@ function runApiMigrationJsonCommand(config, image, args) {
3275
3288
  executedMigrations: []
3276
3289
  };
3277
3290
  }
3291
+ const migrateCli = args.map((arg) => JSON.stringify(arg)).join(" ");
3278
3292
  const output = run(
3279
3293
  "docker",
3280
3294
  [
@@ -3287,11 +3301,14 @@ function runApiMigrationJsonCommand(config, image, args) {
3287
3301
  "-e",
3288
3302
  "SKIP_ROOT_ENV=1",
3289
3303
  image,
3290
- "bun",
3291
- "run",
3292
- "scripts/migrate.ts",
3293
- ...args,
3294
- "--json"
3304
+ "sh",
3305
+ "-lc",
3306
+ [
3307
+ "if [ -d /app/packages/envsync-api ]; then cd /app/packages/envsync-api; fi",
3308
+ `if [ -f scripts/migrate.enterprise.ts ]; then exec bun run scripts/migrate.enterprise.ts ${migrateCli} --json`,
3309
+ `elif [ -f scripts/migrate.ts ]; then exec bun run scripts/migrate.ts ${migrateCli} --json`,
3310
+ "else echo 'Migration CLI missing from API image (expected scripts/migrate.ts)' >&2; exit 1; fi"
3311
+ ].join("; ")
3295
3312
  ],
3296
3313
  { quiet: true }
3297
3314
  );
@@ -3630,7 +3647,15 @@ function waitForApiSlotHealthy(config, slot, timeoutSeconds = 180) {
3630
3647
  sleepSeconds(3);
3631
3648
  }
3632
3649
  const services = listStackServices(config);
3633
- throw new Error(`Timed out waiting for API ${slot} slot to become healthy: ${serviceHealth(services, serviceName)}`);
3650
+ const ps = tryRun("docker", ["service", "ps", serviceName, "--no-trunc", "--format", "{{.CurrentState}} {{.Error}}"], {
3651
+ quiet: true
3652
+ });
3653
+ const logs = tryRun("docker", ["service", "logs", "--tail", "80", serviceName], { quiet: true });
3654
+ throw new Error(
3655
+ `Timed out waiting for API ${slot} slot to become healthy: ${serviceHealth(services, serviceName)}
3656
+ ${ps}
3657
+ ${logs}`
3658
+ );
3634
3659
  }
3635
3660
  function waitForHealthyServices(config, checks, timeoutSeconds = 180) {
3636
3661
  if (currentOptions.dryRun) {
@@ -4188,8 +4213,8 @@ async function cmdDeploy() {
4188
4213
  logSection("Deploy");
4189
4214
  const { config, generated } = loadState();
4190
4215
  logReleaseContext(config);
4191
- if (!isOssConfig2(config)) {
4192
- ensureEnterpriseLicenseFilesReadable();
4216
+ if (!isOssConfig2(config) && !currentOptions.dryRun) {
4217
+ await ensureEnterpriseCertificateBundle(config);
4193
4218
  }
4194
4219
  assertSwarmManager();
4195
4220
  assertBootstrapState(generated);
@@ -4255,7 +4280,12 @@ async function cmdDeploy() {
4255
4280
  const rollbackTarget = preUpgradeHead ?? "zero";
4256
4281
  try {
4257
4282
  logWarn(`Candidate deploy failed after migration. Rolling schema back to ${rollbackTarget}.`);
4258
- runApiMigrationJsonCommand(config, config.images.api, ["rollback_to", rollbackTarget]);
4283
+ try {
4284
+ runApiMigrationJsonCommand(config, config.images.api, ["rollback_to", rollbackTarget]);
4285
+ } catch {
4286
+ logWarn(`Rollback with ${config.images.api} failed; retrying with ${activeImageBeforeUpgrade}.`);
4287
+ runApiMigrationJsonCommand(config, activeImageBeforeUpgrade, ["rollback_to", rollbackTarget]);
4288
+ }
4259
4289
  } catch (rollbackError) {
4260
4290
  if (!snapshotPath) {
4261
4291
  throw new Error(
@@ -4564,7 +4594,7 @@ async function cmdUpgrade(targetVersion) {
4564
4594
  };
4565
4595
  logReleaseContext(config);
4566
4596
  if (!isOssConfig2(config) && !currentOptions.dryRun) {
4567
- ensureEnterpriseLicenseFilesReadable();
4597
+ await ensureEnterpriseCertificateBundle(config);
4568
4598
  }
4569
4599
  config.images = {
4570
4600
  ...config.images,
package/dist/index.js CHANGED
@@ -362,6 +362,7 @@ function buildRuntimeEnv2(config, generated, options) {
362
362
  ENVSYNC_EDITION: oss ? "oss" : "enterprise",
363
363
  // Self-host product install — never multi-tenant SaaS mode (program plan Phase 1).
364
364
  ENVSYNC_DEPLOYMENT_MODE: "selfhosted",
365
+ SKIP_ROOT_ENV: "1",
365
366
  ENVSYNC_MANAGEMENT_ENABLED: oss ? "false" : "true",
366
367
  // Landing is Hosted-only; self-host does not ship marketing/signup surface.
367
368
  ENVSYNC_LANDING_ENABLED: "false",
@@ -1141,6 +1142,12 @@ ${renderEnvList({
1141
1142
  })}
1142
1143
  ${apiLicenseVolume}
1143
1144
  networks: [envsync]
1145
+ healthcheck:
1146
+ test: ["CMD", "bun", "-e", "fetch('http://127.0.0.1:4000/health').then((r)=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))"]
1147
+ interval: 10s
1148
+ timeout: 5s
1149
+ retries: 8
1150
+ start_period: 45s
1144
1151
  deploy:
1145
1152
  replicas: ${slotHasApiDeployment(deployment.slots.blue) ? 1 : 0}
1146
1153
 
@@ -1154,6 +1161,12 @@ ${renderEnvList({
1154
1161
  })}
1155
1162
  ${apiLicenseVolume}
1156
1163
  networks: [envsync]
1164
+ healthcheck:
1165
+ test: ["CMD", "bun", "-e", "fetch('http://127.0.0.1:4000/health').then((r)=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))"]
1166
+ interval: 10s
1167
+ timeout: 5s
1168
+ retries: 8
1169
+ start_period: 45s
1157
1170
  deploy:
1158
1171
  replicas: ${slotHasApiDeployment(deployment.slots.green) ? 1 : 0}` : ""}${netutilsService}${vpnResult?.serviceBlock ?? ""}
1159
1172
 
@@ -2745,7 +2758,7 @@ function createApiDbUpgradeBackup(config, fromVersion, toVersion) {
2745
2758
  "postgres:17",
2746
2759
  "sh",
2747
2760
  "-lc",
2748
- `pg_dump -h ${config.services.stack_name}_postgres -U postgres -d envsync -Fc -f /backup/${fileName}`
2761
+ `pg_dump -h postgres -U postgres -d envsync -Fc -f /backup/${fileName}`
2749
2762
  ]);
2750
2763
  logSuccess(`API DB upgrade snapshot created at ${hostPath}`);
2751
2764
  return hostPath;
@@ -2769,7 +2782,7 @@ function restoreApiDbUpgradeBackup(config, backupPath) {
2769
2782
  "postgres:17",
2770
2783
  "sh",
2771
2784
  "-lc",
2772
- `pg_restore --clean --if-exists --no-owner --no-privileges -h ${config.services.stack_name}_postgres -U postgres -d envsync /backup/${fileName}`
2785
+ `pg_restore --clean --if-exists --no-owner --no-privileges -h postgres -U postgres -d envsync /backup/${fileName}`
2773
2786
  ]);
2774
2787
  logSuccess(`API DB upgrade snapshot restored from ${backupPath}`);
2775
2788
  }
@@ -3137,6 +3150,7 @@ function runApiMigrationJsonCommand(config, image, args) {
3137
3150
  executedMigrations: []
3138
3151
  };
3139
3152
  }
3153
+ const migrateCli = args.map((arg) => JSON.stringify(arg)).join(" ");
3140
3154
  const output = run(
3141
3155
  "docker",
3142
3156
  [
@@ -3149,11 +3163,14 @@ function runApiMigrationJsonCommand(config, image, args) {
3149
3163
  "-e",
3150
3164
  "SKIP_ROOT_ENV=1",
3151
3165
  image,
3152
- "bun",
3153
- "run",
3154
- "scripts/migrate.ts",
3155
- ...args,
3156
- "--json"
3166
+ "sh",
3167
+ "-lc",
3168
+ [
3169
+ "if [ -d /app/packages/envsync-api ]; then cd /app/packages/envsync-api; fi",
3170
+ `if [ -f scripts/migrate.enterprise.ts ]; then exec bun run scripts/migrate.enterprise.ts ${migrateCli} --json`,
3171
+ `elif [ -f scripts/migrate.ts ]; then exec bun run scripts/migrate.ts ${migrateCli} --json`,
3172
+ "else echo 'Migration CLI missing from API image (expected scripts/migrate.ts)' >&2; exit 1; fi"
3173
+ ].join("; ")
3157
3174
  ],
3158
3175
  { quiet: true }
3159
3176
  );
@@ -3492,7 +3509,15 @@ function waitForApiSlotHealthy(config, slot, timeoutSeconds = 180) {
3492
3509
  sleepSeconds(3);
3493
3510
  }
3494
3511
  const services = listStackServices(config);
3495
- throw new Error(`Timed out waiting for API ${slot} slot to become healthy: ${serviceHealth(services, serviceName)}`);
3512
+ const ps = tryRun("docker", ["service", "ps", serviceName, "--no-trunc", "--format", "{{.CurrentState}} {{.Error}}"], {
3513
+ quiet: true
3514
+ });
3515
+ const logs = tryRun("docker", ["service", "logs", "--tail", "80", serviceName], { quiet: true });
3516
+ throw new Error(
3517
+ `Timed out waiting for API ${slot} slot to become healthy: ${serviceHealth(services, serviceName)}
3518
+ ${ps}
3519
+ ${logs}`
3520
+ );
3496
3521
  }
3497
3522
  function waitForHealthyServices(config, checks, timeoutSeconds = 180) {
3498
3523
  if (currentOptions.dryRun) {
@@ -4050,8 +4075,8 @@ async function cmdDeploy() {
4050
4075
  logSection("Deploy");
4051
4076
  const { config, generated } = loadState();
4052
4077
  logReleaseContext(config);
4053
- if (!isOssConfig2(config)) {
4054
- ensureEnterpriseLicenseFilesReadable();
4078
+ if (!isOssConfig2(config) && !currentOptions.dryRun) {
4079
+ await ensureEnterpriseCertificateBundle(config);
4055
4080
  }
4056
4081
  assertSwarmManager();
4057
4082
  assertBootstrapState(generated);
@@ -4117,7 +4142,12 @@ async function cmdDeploy() {
4117
4142
  const rollbackTarget = preUpgradeHead ?? "zero";
4118
4143
  try {
4119
4144
  logWarn(`Candidate deploy failed after migration. Rolling schema back to ${rollbackTarget}.`);
4120
- runApiMigrationJsonCommand(config, config.images.api, ["rollback_to", rollbackTarget]);
4145
+ try {
4146
+ runApiMigrationJsonCommand(config, config.images.api, ["rollback_to", rollbackTarget]);
4147
+ } catch {
4148
+ logWarn(`Rollback with ${config.images.api} failed; retrying with ${activeImageBeforeUpgrade}.`);
4149
+ runApiMigrationJsonCommand(config, activeImageBeforeUpgrade, ["rollback_to", rollbackTarget]);
4150
+ }
4121
4151
  } catch (rollbackError) {
4122
4152
  if (!snapshotPath) {
4123
4153
  throw new Error(
@@ -4426,7 +4456,7 @@ async function cmdUpgrade(targetVersion) {
4426
4456
  };
4427
4457
  logReleaseContext(config);
4428
4458
  if (!isOssConfig2(config) && !currentOptions.dryRun) {
4429
- ensureEnterpriseLicenseFilesReadable();
4459
+ await ensureEnterpriseCertificateBundle(config);
4430
4460
  }
4431
4461
  config.images = {
4432
4462
  ...config.images,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@envsync-cloud/deploy",
3
- "version": "0.20.2",
3
+ "version": "0.20.4",
4
4
  "description": "OSS CLI for self-hosted EnvSync deployment on Docker Swarm",
5
5
  "type": "module",
6
6
  "bin": {
@@ -42,10 +42,11 @@
42
42
  ],
43
43
  "dependencies": {
44
44
  "chalk": "^5.6.2",
45
- "yaml": "^1.10.2"
45
+ "yaml": "^1.10.2",
46
+ "zod": "^3.25.76"
46
47
  },
47
48
  "devDependencies": {
48
- "@envsync-cloud/deploy-core": "0.20.2",
49
+ "@envsync-cloud/deploy-core": "0.20.4",
49
50
  "tsup": "^8.5.0",
50
51
  "typescript": "^5.9.2"
51
52
  },