@stacksjs/ts-cloud 0.7.82 → 0.7.84

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 (56) hide show
  1. package/dist/bin/cli.js +640 -622
  2. package/dist/{chunk-900rezgt.js → chunk-838t87x3.js} +14 -6
  3. package/dist/{chunk-hq03wq2p.js → chunk-8m38yfba.js} +66 -33
  4. package/dist/deploy/index.js +2 -2
  5. package/dist/deploy/local-dashboard-server.d.ts +1 -0
  6. package/dist/drivers/index.js +1 -1
  7. package/dist/drivers/shared/rpx-gateway.d.ts +1 -0
  8. package/dist/index.js +2 -2
  9. package/dist/ui/access-denied.html +2 -2
  10. package/dist/ui/account/automation.html +3 -3
  11. package/dist/ui/account/security.html +2 -2
  12. package/dist/ui/applications/compose.html +4 -4
  13. package/dist/ui/data/backups.html +3 -3
  14. package/dist/ui/data/services.html +4 -4
  15. package/dist/ui/data/volumes.html +4 -4
  16. package/dist/ui/index.html +4 -4
  17. package/dist/ui/integrations.html +2 -2
  18. package/dist/ui/operations/alerts.html +3 -3
  19. package/dist/ui/operations/configuration.html +4 -4
  20. package/dist/ui/operations/jobs.html +4 -4
  21. package/dist/ui/operations/maintenance.html +4 -4
  22. package/dist/ui/operations/observability.html +3 -3
  23. package/dist/ui/operations/previews.html +4 -4
  24. package/dist/ui/operations/queue.html +3 -3
  25. package/dist/ui/operations/regions.html +4 -4
  26. package/dist/ui/operations/releases.html +4 -4
  27. package/dist/ui/operations/workloads.html +3 -3
  28. package/dist/ui/security.html +2 -2
  29. package/dist/ui/server/actions.html +3 -3
  30. package/dist/ui/server/activity.html +2 -2
  31. package/dist/ui/server/capacity.html +4 -4
  32. package/dist/ui/server/database.html +3 -3
  33. package/dist/ui/server/deployments.html +4 -4
  34. package/dist/ui/server/diagnostics.html +2 -2
  35. package/dist/ui/server/firewall.html +3 -3
  36. package/dist/ui/server/fleet.html +3 -3
  37. package/dist/ui/server/logs.html +4 -4
  38. package/dist/ui/server/metrics.html +4 -4
  39. package/dist/ui/server/services.html +2 -2
  40. package/dist/ui/server/sites.html +4 -4
  41. package/dist/ui/server/ssh-keys.html +3 -3
  42. package/dist/ui/server/team.html +4 -4
  43. package/dist/ui/server/terminal.html +2 -2
  44. package/dist/ui/serverless/alarms.html +4 -4
  45. package/dist/ui/serverless/assets.html +2 -2
  46. package/dist/ui/serverless/cost.html +2 -2
  47. package/dist/ui/serverless/data.html +4 -4
  48. package/dist/ui/serverless/deployments.html +2 -2
  49. package/dist/ui/serverless/functions.html +4 -4
  50. package/dist/ui/serverless/logs.html +4 -4
  51. package/dist/ui/serverless/metrics.html +2 -2
  52. package/dist/ui/serverless/queues.html +4 -4
  53. package/dist/ui/serverless/secrets.html +4 -4
  54. package/dist/ui/serverless/traces.html +4 -4
  55. package/dist/ui/serverless.html +4 -4
  56. package/package.json +3 -3
@@ -399,10 +399,9 @@ function buildMonitoringScript(monitoring = true) {
399
399
  "set -uo pipefail",
400
400
  `LOAD=$(cut -d' ' -f1 /proc/loadavg)`,
401
401
  "CPUS=$(nproc)",
402
- `MEM_TOTAL=$(free -m | awk '/^Mem:/{print $2}')`,
403
- `MEM_USED=$(free -m | awk '/^Mem:/{print $3}')`,
404
- `SWAP_TOTAL=$(free -m | awk '/^Swap:/{print $2}')`,
405
- `SWAP_USED=$(free -m | awk '/^Swap:/{print $3}')`,
402
+ `read MEM_TOTAL MEM_USED SWAP_TOTAL SWAP_USED <<EOF
403
+ $(free -m | awk '/^Mem:/{total=$2; used=$3} /^Swap:/{print total, used, $2, $3}')
404
+ EOF`,
406
405
  `DISK_PCT=$(df -P / | awk 'NR==2{gsub("%","",$5); print $5}')`,
407
406
  `UPTIME_SEC=$(cut -d' ' -f1 /proc/uptime | cut -d. -f1)`,
408
407
  `RX_BYTES=$(awk -F'[: ]+' 'NR>2 && $2!="lo"{rx+=$3} END{print rx+0}' /proc/net/dev)`,
@@ -1112,7 +1111,7 @@ function buildRpxConfigInternal(sites, options, appBoxes) {
1112
1111
  });
1113
1112
  const config = {
1114
1113
  proxies,
1115
- productionCerts: { certsDir },
1114
+ productionCerts: { certsDir, certsDirServerNames: [...domains] },
1116
1115
  https: true,
1117
1116
  hostsManagement: false,
1118
1117
  cleanup: { hosts: false, certs: false }
@@ -1221,7 +1220,13 @@ for (const f of files) {
1221
1220
  }
1222
1221
  const config = {
1223
1222
  proxies,
1224
- productionCerts: { certsDir },
1223
+ productionCerts: {
1224
+ certsDir,
1225
+ // A shared host's cert directory also contains mail and retired-site PEMs.
1226
+ // Keep those files on disk for their owners, but do not turn them into live
1227
+ // OpenSSL SNI contexts when no current route can select them.
1228
+ certsDirServerNames: [...new Set(proxies.map(p => p.to).filter(Boolean))],
1229
+ },
1225
1230
  https: true,
1226
1231
  hostsManagement: false,
1227
1232
  cleanup: { hosts: false, certs: false },
@@ -1390,7 +1395,10 @@ function buildRpxProvisionScript(options) {
1390
1395
  `), "TS_CLOUD_RPX_UNIT_EOF"),
1391
1396
  "systemctl daemon-reload",
1392
1397
  "systemctl disable --now bun-gateway.service 2>/dev/null || true",
1398
+ "systemctl disable --now bun-gateway-renew.timer bun-gateway-renew.service 2>/dev/null || true",
1399
+ "rm -f /etc/systemd/system/bun-gateway-renew.timer /etc/systemd/system/bun-gateway-renew.service",
1393
1400
  "systemctl disable --now ts-cloud-nginx.service 2>/dev/null || true",
1401
+ `for timer in /etc/systemd/system/rpx-cert-renew-*.timer; do [ -e "$timer" ] || continue; unit="$(basename "$timer")"; tenant="\${unit#rpx-cert-renew-}"; tenant="\${tenant%.timer}"; [ -f "${RPX_SITES_DIR}/$tenant.json" ] && continue; systemctl disable --now "$unit" 2>/dev/null || true; rm -f "$timer" "/etc/systemd/system/rpx-cert-renew-$tenant.service" "${RPX_DIR}/renew-certs-$tenant.sh"; done`,
1394
1402
  `systemctl enable ${RPX_SERVICE_NAME}`,
1395
1403
  `systemctl restart ${RPX_SERVICE_NAME}`,
1396
1404
  ...buildCertManagementCommands(options)
@@ -45,7 +45,7 @@ import {
45
45
  resolveSiteKind,
46
46
  resolveUiSource,
47
47
  siteInstallBase
48
- } from "./chunk-900rezgt.js";
48
+ } from "./chunk-838t87x3.js";
49
49
  import {
50
50
  artifactKey,
51
51
  buildCloudFormationTemplate,
@@ -38547,28 +38547,34 @@ for (const route of routes) console.log('DISCOVERED_SITE=' + Buffer.from(JSON.st
38547
38547
  const serviceOutput = Bun.spawnSync([
38548
38548
  'systemctl', 'list-units', '--type=service', '--state=running', '--no-legend', '--plain',
38549
38549
  ]).stdout.toString()
38550
- for (const line of serviceOutput.split('\n')) {
38551
- const unit = line.trim().split(/\s+/)[0]
38552
- if (!unit) continue
38553
- const properties = Bun.spawnSync([
38550
+ const runningUnits = serviceOutput
38551
+ .split('\n')
38552
+ .map(line => line.trim().split(/\s+/)[0])
38553
+ .filter(Boolean)
38554
+ if (runningUnits.length > 0) {
38555
+ const propertiesOutput = Bun.spawnSync([
38554
38556
  'systemctl',
38555
38557
  'show',
38556
- unit,
38557
- '--property=WorkingDirectory,ExecStart,MemoryCurrent,UnitFileState,ActiveEnterTimestamp',
38558
+ ...runningUnits,
38559
+ '--property=Id,WorkingDirectory,ExecStart,MemoryCurrent,UnitFileState,ActiveEnterTimestamp',
38558
38560
  ]).stdout.toString()
38559
- const values = Object.fromEntries(properties.split('\n').filter(Boolean).map(value => {
38560
- const separator = value.indexOf('=')
38561
- return separator < 0 ? [value, ''] : [value.slice(0, separator), value.slice(separator + 1)]
38562
- }))
38563
- if (!/^\/var\/www\/|^\/opt\/ts-cloud\//.test(values.WorkingDirectory || '') && !/\/var\/www\/|\/opt\/ts-cloud\//.test(values.ExecStart || '')) continue
38564
- console.log([
38565
- 'SVC',
38566
- unit,
38567
- 'active',
38568
- values.MemoryCurrent || '0',
38569
- values.UnitFileState || '-',
38570
- values.ActiveEnterTimestamp || '-',
38571
- ].join('='))
38561
+ for (const properties of propertiesOutput.split(/\n\n+/)) {
38562
+ const values = Object.fromEntries(properties.split('\n').filter(Boolean).map(value => {
38563
+ const separator = value.indexOf('=')
38564
+ return separator < 0 ? [value, ''] : [value.slice(0, separator), value.slice(separator + 1)]
38565
+ }))
38566
+ const unit = values.Id
38567
+ if (!unit) continue
38568
+ if (!/^\/var\/www\/|^\/opt\/ts-cloud\//.test(values.WorkingDirectory || '') && !/\/var\/www\/|\/opt\/ts-cloud\//.test(values.ExecStart || '')) continue
38569
+ console.log([
38570
+ 'SVC',
38571
+ unit,
38572
+ 'active',
38573
+ values.MemoryCurrent || '0',
38574
+ values.UnitFileState || '-',
38575
+ values.ActiveEnterTimestamp || '-',
38576
+ ].join('='))
38577
+ }
38572
38578
  }
38573
38579
  `;
38574
38580
  return `echo '${Buffer.from(source).toString("base64")}' | base64 -d | bun -`;
@@ -38588,15 +38594,21 @@ EOF`,
38588
38594
  `echo "LOAD=$(cut -d' ' -f1 /proc/loadavg 2>/dev/null || echo 0)"`,
38589
38595
  `echo "LOAD5=$(cut -d' ' -f2 /proc/loadavg 2>/dev/null || echo 0)"`,
38590
38596
  `echo "LOAD15=$(cut -d' ' -f3 /proc/loadavg 2>/dev/null || echo 0)"`,
38591
- `echo "MEMTOTAL=$(free -m 2>/dev/null | awk '/^Mem:/{print $2}')"`,
38592
- `echo "MEMUSED=$(free -m 2>/dev/null | awk '/^Mem:/{print $3}')"`,
38593
- `echo "MEMAVAILABLE=$(free -m 2>/dev/null | awk '/^Mem:/{print $7}')"`,
38594
- `echo "MEMCACHE=$(free -m 2>/dev/null | awk '/^Mem:/{print $6}')"`,
38595
- `echo "SWAPTOTAL=$(free -m 2>/dev/null | awk '/^Swap:/{print $2}')"`,
38596
- `echo "SWAPUSED=$(free -m 2>/dev/null | awk '/^Swap:/{print $3}')"`,
38597
- `echo "DISKPCT=$(df -P / 2>/dev/null | awk 'NR==2{gsub("%","",$5);print $5}')"`,
38598
- `echo "DISKUSEDG=$(df -BG / 2>/dev/null | awk 'NR==2{gsub("G","",$3);print $3}')"`,
38599
- `echo "DISKTOTG=$(df -BG / 2>/dev/null | awk 'NR==2{gsub("G","",$2);print $2}')"`,
38597
+ `read MEMTOTAL MEMUSED MEMAVAILABLE MEMCACHE SWAPTOTAL SWAPUSED <<EOF
38598
+ $(free -m 2>/dev/null | awk '/^Mem:/{total=$2; used=$3; available=$7; cache=$6} /^Swap:/{print total, used, available, cache, $2, $3}')
38599
+ EOF`,
38600
+ 'echo "MEMTOTAL=${MEMTOTAL:-0}"',
38601
+ 'echo "MEMUSED=${MEMUSED:-0}"',
38602
+ 'echo "MEMAVAILABLE=${MEMAVAILABLE:-0}"',
38603
+ 'echo "MEMCACHE=${MEMCACHE:-0}"',
38604
+ 'echo "SWAPTOTAL=${SWAPTOTAL:-0}"',
38605
+ 'echo "SWAPUSED=${SWAPUSED:-0}"',
38606
+ `read DISKTOTG DISKUSEDG DISKPCT <<EOF
38607
+ $(df -BG -P / 2>/dev/null | awk 'NR==2{gsub("G","",$2); gsub("G","",$3); gsub("%","",$5); print $2, $3, $5}')
38608
+ EOF`,
38609
+ 'echo "DISKPCT=${DISKPCT:-0}"',
38610
+ 'echo "DISKUSEDG=${DISKUSEDG:-0}"',
38611
+ 'echo "DISKTOTG=${DISKTOTG:-0}"',
38600
38612
  `echo "INODEPCT=$(df -Pi / 2>/dev/null | awk 'NR==2{gsub("%","",$5);print $5}')"`,
38601
38613
  `echo "NETRX=$(awk -F'[: ]+' 'NR>2 && $2!="lo"{sum+=$3} END{print sum+0}' /proc/net/dev 2>/dev/null)"`,
38602
38614
  `echo "NETTX=$(awk -F'[: ]+' 'NR>2 && $2!="lo"{sum+=$11} END{print sum+0}' /proc/net/dev 2>/dev/null)"`,
@@ -43144,7 +43156,7 @@ function authorizationScope(body) {
43144
43156
  const id2 = String(body.scopeId ?? "").trim();
43145
43157
  return id2 ? { type, id: id2 } : undefined;
43146
43158
  }
43147
- async function resolveLiveDashboardData(config6, environment2) {
43159
+ async function resolveLiveDashboardData(config6, environment2, options = {}) {
43148
43160
  const mode = resolveDeploymentMode(config6);
43149
43161
  const meta = {
43150
43162
  mode,
@@ -43153,12 +43165,24 @@ async function resolveLiveDashboardData(config6, environment2) {
43153
43165
  project: { name: config6.project.name, slug: config6.project.slug, region: config6.project.region }
43154
43166
  };
43155
43167
  try {
43156
- const data = mode === "serverless" ? await resolveDashboardData(config6, environment2) : await resolveServerDashboardData(config6, environment2);
43168
+ const data = mode === "serverless" ? await resolveDashboardData(config6, environment2) : await resolveServerDashboardData(config6, environment2, {
43169
+ includeSiteHealth: options.includeSiteHealth
43170
+ });
43157
43171
  return { ...data ?? {}, ...meta };
43158
43172
  } catch {
43159
43173
  return { ...meta };
43160
43174
  }
43161
43175
  }
43176
+ function preserveDashboardSiteSnapshot(previous, next) {
43177
+ if (!previous)
43178
+ return next;
43179
+ return {
43180
+ ...next,
43181
+ ...Array.isArray(previous.sites) ? { sites: previous.sites } : {},
43182
+ ...Array.isArray(previous.sitesDetail) ? { sitesDetail: previous.sitesDetail } : {},
43183
+ ...Array.isArray(previous.siteHealth) ? { siteHealth: previous.siteHealth } : {}
43184
+ };
43185
+ }
43162
43186
  function resolveUiSourceDir(cwd) {
43163
43187
  const candidates = [
43164
43188
  join13(cwd, "packages", "ui"),
@@ -43512,8 +43536,13 @@ async function startLocalDashboardServer(options = {}) {
43512
43536
  const initialData = await resolveLiveDashboardData(config6, defaultEnvironment);
43513
43537
  const latestDataByEnvironment = new Map([[defaultEnvironment, initialData]]);
43514
43538
  const latestDataRefreshedAtByEnvironment = new Map([[defaultEnvironment, Date.now()]]);
43539
+ const latestSiteHealthRefreshedAtByEnvironment = new Map([
43540
+ [defaultEnvironment, Date.now()]
43541
+ ]);
43515
43542
  const liveDataRefreshesByEnvironment = new Map;
43516
43543
  const dashboardDataMinimumRefreshMs = Math.min(5 * 60000, Math.max(5000, Number(process.env.TS_CLOUD_DASHBOARD_REFRESH_MS) || 30000));
43544
+ const dashboardSiteHealthMinimumRefreshMs = Math.min(30 * 60000, Math.max(60000, Number(process.env.TS_CLOUD_DASHBOARD_SITE_REFRESH_MS) || 5 * 60000));
43545
+ const computeDashboard = resolveDeploymentMode(config6) !== "serverless";
43517
43546
  const refreshLatestDashboardData = (environment2) => {
43518
43547
  const previous = latestDataByEnvironment.get(environment2);
43519
43548
  if (previous && !dashboardDataRefreshDue(latestDataRefreshedAtByEnvironment.get(environment2), Date.now(), dashboardDataMinimumRefreshMs))
@@ -43521,10 +43550,14 @@ async function startLocalDashboardServer(options = {}) {
43521
43550
  const running = liveDataRefreshesByEnvironment.get(environment2);
43522
43551
  if (running)
43523
43552
  return running;
43524
- const refresh = resolveLiveDashboardData(config6, environment2).then((data) => {
43553
+ const includeSiteHealth = !computeDashboard || dashboardDataRefreshDue(latestSiteHealthRefreshedAtByEnvironment.get(environment2), Date.now(), dashboardSiteHealthMinimumRefreshMs);
43554
+ const refresh = resolveLiveDashboardData(config6, environment2, { includeSiteHealth }).then((refreshedData) => {
43525
43555
  const previous2 = latestDataByEnvironment.get(environment2);
43556
+ const data = includeSiteHealth ? refreshedData : preserveDashboardSiteSnapshot(previous2, refreshedData);
43526
43557
  latestDataByEnvironment.set(environment2, data);
43527
43558
  latestDataRefreshedAtByEnvironment.set(environment2, Date.now());
43559
+ if (includeSiteHealth)
43560
+ latestSiteHealthRefreshedAtByEnvironment.set(environment2, Date.now());
43528
43561
  if (previous2?._serverReachable !== data._serverReachable || previous2?._metricsStatus !== data._metricsStatus || (previous2?.sitesDetail?.length ?? 0) !== (data.sitesDetail?.length ?? 0))
43529
43562
  clearUiCache();
43530
43563
  return data;
@@ -43537,7 +43570,7 @@ async function startLocalDashboardServer(options = {}) {
43537
43570
  const backgroundTelemetryEnabled = options.box && telemetryPreference !== "0" && (telemetryPreference === "1" || !config6.cloud?.attachTo);
43538
43571
  if (backgroundTelemetryEnabled) {
43539
43572
  let telemetryCollectionRunning = false;
43540
- let nextSiteHealthCollectionAt = 0;
43573
+ let nextSiteHealthCollectionAt = Date.now() + 5 * 60000;
43541
43574
  const collectHostHistory = async () => {
43542
43575
  if (telemetryCollectionRunning)
43543
43576
  return;
@@ -32,7 +32,7 @@ import {
32
32
  synchronizeDashboardUsers,
33
33
  trackDashboardOperation,
34
34
  verifyStaticApiOrigin
35
- } from "../chunk-hq03wq2p.js";
35
+ } from "../chunk-8m38yfba.js";
36
36
  import {
37
37
  deleteStaticSite,
38
38
  deployStaticSite,
@@ -65,7 +65,7 @@ import {
65
65
  shipsARelease,
66
66
  siteInstallBase,
67
67
  validateDeploymentConfig
68
- } from "../chunk-900rezgt.js";
68
+ } from "../chunk-838t87x3.js";
69
69
  import"../chunk-1qjyqrc5.js";
70
70
  import"../chunk-703nkybg.js";
71
71
  import"../chunk-4cjrg98a.js";
@@ -48,6 +48,7 @@ export declare function resolveDashboardEnvironment(available: readonly string[]
48
48
  export declare function dashboardDataRefreshDue(lastRefreshedAt: number | undefined, now: number, minimumIntervalMs: number): boolean;
49
49
  /** Reject browser cross-site mutations while retaining header-light CLI access. */
50
50
  export declare function isTrustedMutationRequest(req: Request): boolean;
51
+ export declare function preserveDashboardSiteSnapshot(previous: Record<string, any> | undefined, next: Record<string, any>): Record<string, any>;
51
52
  export declare function sanitizeCloudConfig(config: CloudConfig): Record<string, any>;
52
53
  export declare function dashboardActions(environment: EnvironmentType): DashboardAction[];
53
54
  export declare function resolveDashboardAction(id: string, environment: EnvironmentType): DashboardAction | undefined;
@@ -68,7 +68,7 @@ import {
68
68
  waitForSsh,
69
69
  wrapCloudInitUserData,
70
70
  writeResizeCheckpoint
71
- } from "../chunk-900rezgt.js";
71
+ } from "../chunk-838t87x3.js";
72
72
  import"../chunk-1qjyqrc5.js";
73
73
  import"../chunk-703nkybg.js";
74
74
  import"../chunk-4cjrg98a.js";
@@ -108,6 +108,7 @@ export interface RpxGatewayConfig {
108
108
  */
109
109
  productionCerts: {
110
110
  certsDir: string;
111
+ certsDirServerNames?: string[];
111
112
  };
112
113
  /**
113
114
  * On-demand TLS (opt-in): lazily issue a real cert for an approved host the
package/dist/index.js CHANGED
@@ -285,7 +285,7 @@ import {
285
285
  volumeCapabilities,
286
286
  webhookEndpoint,
287
287
  zeroCapacity
288
- } from "./chunk-hq03wq2p.js";
288
+ } from "./chunk-8m38yfba.js";
289
289
  import {
290
290
  deleteStaticSite,
291
291
  deployStaticSite,
@@ -398,7 +398,7 @@ import {
398
398
  waitForCloudInit,
399
399
  waitForSsh,
400
400
  wrapCloudInitUserData
401
- } from "./chunk-900rezgt.js";
401
+ } from "./chunk-838t87x3.js";
402
402
  import {
403
403
  ABTestManager,
404
404
  AI,