@stacksjs/ts-cloud 0.7.110 → 0.7.112

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 (67) hide show
  1. package/dist/aws/index.js +3 -3
  2. package/dist/bin/cli.js +382 -382
  3. package/dist/bin/dashboard-server.js +398 -398
  4. package/dist/{chunk-x6yzgv7y.js → chunk-6a1t7fnq.js} +2 -2
  5. package/dist/{chunk-d3vx2ekv.js → chunk-6xnwshtc.js} +92 -6
  6. package/dist/{chunk-wmz8x3cy.js → chunk-ham2enem.js} +12 -8
  7. package/dist/{chunk-9v2pwxv9.js → chunk-kpeb5rcs.js} +2 -2
  8. package/dist/{chunk-hpv68b4a.js → chunk-nsgqsmrh.js} +1 -1
  9. package/dist/{chunk-wj3s95p9.js → chunk-rds0sy87.js} +3 -2
  10. package/dist/{chunk-k114qwg9.js → chunk-ttz2ra5j.js} +2 -2
  11. package/dist/{chunk-8kh577qh.js → chunk-v0vpamnf.js} +3 -3
  12. package/dist/deploy/index.js +10 -6
  13. package/dist/deploy/site-target.d.ts +20 -3
  14. package/dist/drivers/index.js +2 -2
  15. package/dist/drivers/shared/rpx-gateway.d.ts +3 -1
  16. package/dist/index.d.ts +1 -1
  17. package/dist/index.js +12 -6
  18. package/dist/ui/access-denied.html +2 -2
  19. package/dist/ui/account/automation.html +3 -3
  20. package/dist/ui/account/security.html +2 -2
  21. package/dist/ui/applications/compose.html +4 -4
  22. package/dist/ui/applications/new.html +2 -2
  23. package/dist/ui/data/backups.html +3 -3
  24. package/dist/ui/data/services.html +3 -3
  25. package/dist/ui/data/volumes.html +4 -4
  26. package/dist/ui/index.html +3 -3
  27. package/dist/ui/infrastructure/topology.html +3 -3
  28. package/dist/ui/integrations.html +2 -2
  29. package/dist/ui/operations/alerts.html +3 -3
  30. package/dist/ui/operations/configuration.html +3 -3
  31. package/dist/ui/operations/jobs.html +3 -3
  32. package/dist/ui/operations/maintenance.html +4 -4
  33. package/dist/ui/operations/observability.html +4 -4
  34. package/dist/ui/operations/previews.html +4 -4
  35. package/dist/ui/operations/queue.html +3 -3
  36. package/dist/ui/operations/regions.html +4 -4
  37. package/dist/ui/operations/releases.html +4 -4
  38. package/dist/ui/operations/spend.html +3 -3
  39. package/dist/ui/operations/workloads.html +4 -4
  40. package/dist/ui/security.html +2 -2
  41. package/dist/ui/server/actions.html +4 -4
  42. package/dist/ui/server/activity.html +2 -2
  43. package/dist/ui/server/capacity.html +3 -3
  44. package/dist/ui/server/database.html +4 -4
  45. package/dist/ui/server/deployments.html +4 -4
  46. package/dist/ui/server/firewall.html +4 -4
  47. package/dist/ui/server/fleet.html +4 -4
  48. package/dist/ui/server/logs.html +4 -4
  49. package/dist/ui/server/metrics.html +3 -3
  50. package/dist/ui/server/services.html +2 -2
  51. package/dist/ui/server/sites.html +4 -4
  52. package/dist/ui/server/ssh-keys.html +4 -4
  53. package/dist/ui/server/team.html +4 -4
  54. package/dist/ui/server/terminal.html +2 -2
  55. package/dist/ui/serverless/alarms.html +3 -3
  56. package/dist/ui/serverless/assets.html +2 -2
  57. package/dist/ui/serverless/data.html +4 -4
  58. package/dist/ui/serverless/deployments.html +2 -2
  59. package/dist/ui/serverless/firewall.html +2 -2
  60. package/dist/ui/serverless/functions.html +4 -4
  61. package/dist/ui/serverless/logs.html +4 -4
  62. package/dist/ui/serverless/metrics.html +2 -2
  63. package/dist/ui/serverless/queues.html +4 -4
  64. package/dist/ui/serverless/secrets.html +4 -4
  65. package/dist/ui/serverless/traces.html +4 -4
  66. package/dist/ui/serverless.html +4 -4
  67. package/package.json +3 -3
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  SESClient
3
- } from "./chunk-hpv68b4a.js";
3
+ } from "./chunk-nsgqsmrh.js";
4
4
  import {
5
5
  S3Client,
6
6
  resolveCredentials
7
- } from "./chunk-wj3s95p9.js";
7
+ } from "./chunk-rds0sy87.js";
8
8
  import {
9
9
  AWSClient
10
10
  } from "./chunk-zqtpg06c.js";
@@ -7,7 +7,7 @@ import {
7
7
  } from "./chunk-4cjrg98a.js";
8
8
  import {
9
9
  S3Client
10
- } from "./chunk-wj3s95p9.js";
10
+ } from "./chunk-rds0sy87.js";
11
11
  import {
12
12
  renderWafInstallScript
13
13
  } from "./chunk-va2yd85b.js";
@@ -1287,7 +1287,7 @@ async function sendNotifications(config, event, message, options = {}) {
1287
1287
  }
1288
1288
  async function sendEmailNotification(email, event, message) {
1289
1289
  try {
1290
- const mod = await import("./chunk-k114qwg9.js");
1290
+ const mod = await import("./chunk-ttz2ra5j.js");
1291
1291
  await mod.email.send({
1292
1292
  to: email.to,
1293
1293
  from: email.from,
@@ -1336,6 +1336,16 @@ var PHP_SITE_TYPES = new Set([
1336
1336
  function isPhpSite(site) {
1337
1337
  return site.type != null && PHP_SITE_TYPES.has(site.type);
1338
1338
  }
1339
+ function resolveProxyUpstreams(site) {
1340
+ const raw = site.proxyTo;
1341
+ if (raw == null)
1342
+ return [];
1343
+ const list = Array.isArray(raw) ? raw : [raw];
1344
+ return list.map((entry) => String(entry).trim()).filter((entry) => entry.length > 0);
1345
+ }
1346
+ function hasProxyUpstream(site) {
1347
+ return resolveProxyUpstreams(site).length > 0;
1348
+ }
1339
1349
  function resolveSiteDeployTarget(site) {
1340
1350
  if (site.deploy)
1341
1351
  return site.deploy;
@@ -1348,6 +1358,8 @@ function resolveSiteDeployTarget(site) {
1348
1358
  function resolveSiteKind(site) {
1349
1359
  if (site.redirect)
1350
1360
  return "redirect";
1361
+ if (hasProxyUpstream(site))
1362
+ return "proxy";
1351
1363
  if (isPhpSite(site))
1352
1364
  return "server-php";
1353
1365
  const target = resolveSiteDeployTarget(site);
@@ -1387,10 +1399,34 @@ function validateDeploymentConfig(config) {
1387
1399
  serverOnly.push("start");
1388
1400
  if (site.root)
1389
1401
  serverOnly.push("root");
1402
+ if (site.proxyTo)
1403
+ serverOnly.push("proxyTo");
1390
1404
  if (serverOnly.length > 0)
1391
1405
  warnings.push(`Site '${name}' is a redirect site but also sets ${serverOnly.join(", ")}. These are ignored.`);
1392
1406
  continue;
1393
1407
  }
1408
+ if (kind === "proxy") {
1409
+ if (!site.domain)
1410
+ errors.push(`Site '${name}' is a proxy site but has no \`domain\` to route from.`);
1411
+ if (!computeConfigured) {
1412
+ errors.push(`Site '${name}' is a proxy site but no \`infrastructure.compute\` is configured to host the gateway that forwards it.`);
1413
+ }
1414
+ const ignored = [];
1415
+ if (site.start)
1416
+ ignored.push("start");
1417
+ if (site.root)
1418
+ ignored.push("root");
1419
+ if (typeof site.port === "number")
1420
+ ignored.push("port");
1421
+ if (site.build)
1422
+ ignored.push("build");
1423
+ if (site.preStart && site.preStart.length > 0)
1424
+ ignored.push("preStart");
1425
+ if (ignored.length > 0) {
1426
+ warnings.push(`Site '${name}' sets \`proxyTo\`, so ts-cloud ships and supervises nothing for it. ${ignored.join(", ")} ${ignored.length === 1 ? "is" : "are"} ignored — remove ${ignored.length === 1 ? "it" : "them"}, or drop \`proxyTo\` to let ts-cloud own the service.`);
1427
+ }
1428
+ continue;
1429
+ }
1394
1430
  if (target === "server" && !site.start && !site.root) {
1395
1431
  errors.push(`Site '${name}' sets deploy:'server' but declares neither \`start\` (dynamic app) nor \`root\` (static site to serve). Add one.`);
1396
1432
  continue;
@@ -1441,7 +1477,7 @@ function validateDeploymentConfig(config) {
1441
1477
  }
1442
1478
  function shipsARelease(site) {
1443
1479
  const kind = resolveSiteKind(site);
1444
- return kind !== "bucket" && kind !== "redirect";
1480
+ return kind !== "bucket" && kind !== "redirect" && kind !== "proxy";
1445
1481
  }
1446
1482
 
1447
1483
  // src/drivers/shared/rpx-gateway.ts
@@ -1512,6 +1548,22 @@ function buildRpxConfigInternal(sites, options, appBoxes) {
1512
1548
  domains.add(site.domain);
1513
1549
  continue;
1514
1550
  }
1551
+ if (kind === "proxy") {
1552
+ const upstreams = resolveProxyUpstreams(site);
1553
+ if (upstreams.length === 0)
1554
+ continue;
1555
+ const from = upstreams.length === 1 ? upstreams[0] : upstreams;
1556
+ proxies.push({
1557
+ to: site.domain,
1558
+ path,
1559
+ from,
1560
+ id,
1561
+ ...auth ? { auth } : {},
1562
+ ...Array.isArray(from) && loadBalancer ? { loadBalancer } : {}
1563
+ });
1564
+ domains.add(site.domain);
1565
+ continue;
1566
+ }
1515
1567
  if (kind === "server-app") {
1516
1568
  if (typeof site.port !== "number")
1517
1569
  continue;
@@ -1773,10 +1825,29 @@ function buildCertManagementCommands(options) {
1773
1825
  `EMAIL='${email}'`,
1774
1826
  `TLSX="${tlsxCli}"`,
1775
1827
  `DOMAINS='${csv}'`,
1828
+ "DNS_ATTEMPTS='24'",
1829
+ "DNS_DELAY_SECONDS='5'",
1830
+ "wait_for_dns() {",
1831
+ ' d="$1"',
1832
+ " attempt=1",
1833
+ ' while ! getent ahosts "$d" >/dev/null 2>&1; do',
1834
+ ' if [ "$attempt" -ge "$DNS_ATTEMPTS" ]; then',
1835
+ ' echo "DNS for $d did not become resolvable after $DNS_ATTEMPTS attempts" >&2',
1836
+ " return 1",
1837
+ " fi",
1838
+ ' echo "Waiting for public DNS before ACME: $d (attempt $attempt/$DNS_ATTEMPTS)"',
1839
+ ' sleep "$DNS_DELAY_SECONDS"',
1840
+ " attempt=$((attempt + 1))",
1841
+ " done",
1842
+ "}",
1776
1843
  'before=$(cat "$CERTS"/*.crt 2>/dev/null | sha256sum)',
1777
1844
  `for d in ${spaced}; do`,
1778
1845
  ' if [ ! -s "$CERTS/$d.crt" ]; then',
1779
- ' $TLSX acme:issue -d "$d" --method http-01 --webroot "$WEBROOT" --dir "$CERTS" --prod --email "$EMAIL" || echo "issue $d failed (non-fatal)"',
1846
+ ' if wait_for_dns "$d"; then',
1847
+ ' $TLSX acme:issue -d "$d" --method http-01 --webroot "$WEBROOT" --dir "$CERTS" --prod --email "$EMAIL" || echo "issue $d failed (non-fatal)"',
1848
+ " else",
1849
+ ' echo "issue $d skipped until DNS resolves (non-fatal)"',
1850
+ " fi",
1780
1851
  " # rpx reloads its SNI set when a PEM appears. Complete that reload",
1781
1852
  " # before the next hostname starts http-01, or :80 can disappear in",
1782
1853
  " # the middle of the following challenge on a multi-domain deploy.",
@@ -1877,6 +1948,9 @@ function buildRpxProvisionScript(options) {
1877
1948
  "OOMPolicy=stop",
1878
1949
  "Restart=always",
1879
1950
  "RestartSec=5",
1951
+ "StartLimitIntervalSec=120",
1952
+ "StartLimitBurst=5",
1953
+ `ExecStartPre=/bin/sh -c 'for p in 80 443; do fuser -k -n tcp "$p" 2>/dev/null || true; done; sleep 1'`,
1880
1954
  "LimitNOFILE=1048576",
1881
1955
  "AmbientCapabilities=CAP_NET_BIND_SERVICE",
1882
1956
  "",
@@ -6295,6 +6369,9 @@ var noopLogger2 = {
6295
6369
  step: () => {},
6296
6370
  success: () => {}
6297
6371
  };
6372
+ function shellQuote2(value) {
6373
+ return `'${value.replace(/'/g, `'"'"'`)}'`;
6374
+ }
6298
6375
  async function deploySiteRelease(driver, options, logger = noopLogger2) {
6299
6376
  const { config, environment, siteName, site, slug, sha, runtime, localTarballPath } = options;
6300
6377
  const remoteKey = `releases/${siteName}/${sha}.tar.gz`;
@@ -6667,6 +6744,8 @@ async function deployAllComputeSites(options) {
6667
6744
  }
6668
6745
  if (kind === "redirect")
6669
6746
  return false;
6747
+ if (kind === "proxy")
6748
+ return false;
6670
6749
  return true;
6671
6750
  });
6672
6751
  if (deployable.length === 0)
@@ -6806,6 +6885,9 @@ async function renewRpxCertificates(options) {
6806
6885
  const rpxConfig = buildRpxConfig(routeSource.sites || {}, { proxy, slug: config.project.slug });
6807
6886
  if (rpxConfig.proxies.length === 0)
6808
6887
  return true;
6888
+ const certDomains = certDomainsForConfig(rpxConfig);
6889
+ if (certDomains.length === 0)
6890
+ return true;
6809
6891
  const slug = config.project.slug;
6810
6892
  const stackName = resolveProjectStackName(config, environment);
6811
6893
  let role = "lb";
@@ -6819,9 +6901,13 @@ async function renewRpxCertificates(options) {
6819
6901
  return true;
6820
6902
  }
6821
6903
  logger.step("Issuing rpx TLS certificates after DNS reconciliation...");
6904
+ const certChecks = certDomains.map((domain) => `test -s ${shellQuote2(`${rpxConfig.productionCerts.certsDir}/${domain}.crt`)}`).join(" && ");
6822
6905
  const result = await driver.runRemoteDeploy({
6823
6906
  targets,
6824
- commands: [`systemctl start ${rpxCertRenewServiceName(slug)}`],
6907
+ commands: [
6908
+ `systemctl start ${rpxCertRenewServiceName(slug)}`,
6909
+ certChecks
6910
+ ],
6825
6911
  comment: `ts-cloud rpx TLS issuance ${slug}`,
6826
6912
  tags: {
6827
6913
  Project: slug,
@@ -6924,4 +7010,4 @@ function buildCloudFrontOriginConfig(options) {
6924
7010
  CustomErrorResponses: { Quantity: 0 }
6925
7011
  };
6926
7012
  }
6927
- export { collectServerDnsDomains, removeStaleServerAddressRecords, normalizePublicIpv6, IPV6_EXCLUDED_HOST_LABELS, hostAcceptsIpv6, reconcileAddressRecords, verifyAddressRecord, PANTRY_PROJECT_DIR, buildPantryBootstrapScript, buildVitessProvisionScript, pgAdminCommand, BACKUP_RUNNER_PATH, buildBackupRestoreScript, siteInstallBase, isPhpSite, resolveSiteDeployTarget, resolveSiteKind, validateDeploymentConfig, shipsARelease, DEFAULT_RPX_CERTS_DIR, normalizeRoutePath, deriveRouteId, buildRpxConfig, buildRpxLbConfig, renderRpxLauncher, RPX_DIR, RPX_LAUNCHER_PATH, RPX_SERVICE_NAME, buildRpxProvisionScript, buildRpxFragmentRefreshScript, buildUbuntuBootstrapScript, AwsDriver, resolveHetznerLocation, HetznerClient, resolveHetznerApiToken2 as resolveHetznerApiToken, normalizeSshPublicKey, wrapCloudInitUserData, HetznerDriver, LocalBoxDriver, isBoxMode, createCloudDriver, CloudDriverFactory, cloudDrivers, planHetznerServerResize, isHetznerCapacityError, executeHetznerServerResize, buildSshArgs, sshExec, sshExecOrThrow, scpUpload, waitForSsh, waitForCloudInit, collectHetznerResizeManifest, prepareHetznerResize, verifyHetznerResize, resolveHetznerHostOptimizationPlan, buildHetznerHostOptimizationScript, applyHetznerHostOptimization, collectHetznerHostOptimizationReport, verifyHetznerHostOptimization, resizeCheckpointPath, resizeLockPath, readResizeCheckpoint, writeResizeCheckpoint, acquireResizeLock, ensureSshKey, ensureFirewall, ensureServer, serverPublicIpv4, UBUNTU_2404_AMI_PARAM, buildBoxUserData, HetznerBoxProvisioner, AwsBoxProvisioner, createBoxProvisioner, releasePaths, buildRollbackScript, resolveExecStart, buildSiteDeployScript, buildStaticSiteDeployScript, releaseTarballTmpPath, buildAwsArtifactFetch, buildLocalArtifactFetch, buildHostCleanupScript, MANAGEMENT_DASHBOARD_SITE, dashboardCredentialsFile, resolveDashboardAuth, resolveUiSource, ensureManagementDashboard, buildManagementDashboardArtifact, resolveSiteFramework, deploySiteRelease, deployAllComputeSites, reloadRpxGateway, renewRpxCertificates, MANAGED_CACHE_POLICY_OPTIMIZED, MANAGED_CACHE_POLICY_DISABLED, MANAGED_ORIGIN_REQUEST_POLICY_ALL_VIEWER, buildCloudFrontOriginConfig };
7013
+ export { collectServerDnsDomains, removeStaleServerAddressRecords, normalizePublicIpv6, IPV6_EXCLUDED_HOST_LABELS, hostAcceptsIpv6, reconcileAddressRecords, verifyAddressRecord, PANTRY_PROJECT_DIR, buildPantryBootstrapScript, buildVitessProvisionScript, pgAdminCommand, BACKUP_RUNNER_PATH, buildBackupRestoreScript, siteInstallBase, isPhpSite, resolveProxyUpstreams, hasProxyUpstream, resolveSiteDeployTarget, resolveSiteKind, validateDeploymentConfig, shipsARelease, DEFAULT_RPX_CERTS_DIR, normalizeRoutePath, deriveRouteId, buildRpxConfig, buildRpxLbConfig, renderRpxLauncher, RPX_DIR, RPX_LAUNCHER_PATH, RPX_SERVICE_NAME, buildRpxProvisionScript, buildRpxFragmentRefreshScript, buildUbuntuBootstrapScript, AwsDriver, resolveHetznerLocation, HetznerClient, resolveHetznerApiToken2 as resolveHetznerApiToken, normalizeSshPublicKey, wrapCloudInitUserData, HetznerDriver, LocalBoxDriver, isBoxMode, createCloudDriver, CloudDriverFactory, cloudDrivers, planHetznerServerResize, isHetznerCapacityError, executeHetznerServerResize, buildSshArgs, sshExec, sshExecOrThrow, scpUpload, waitForSsh, waitForCloudInit, collectHetznerResizeManifest, prepareHetznerResize, verifyHetznerResize, resolveHetznerHostOptimizationPlan, buildHetznerHostOptimizationScript, applyHetznerHostOptimization, collectHetznerHostOptimizationReport, verifyHetznerHostOptimization, resizeCheckpointPath, resizeLockPath, readResizeCheckpoint, writeResizeCheckpoint, acquireResizeLock, ensureSshKey, ensureFirewall, ensureServer, serverPublicIpv4, UBUNTU_2404_AMI_PARAM, buildBoxUserData, HetznerBoxProvisioner, AwsBoxProvisioner, createBoxProvisioner, releasePaths, buildRollbackScript, resolveExecStart, buildSiteDeployScript, buildStaticSiteDeployScript, releaseTarballTmpPath, buildAwsArtifactFetch, buildLocalArtifactFetch, buildHostCleanupScript, MANAGEMENT_DASHBOARD_SITE, dashboardCredentialsFile, resolveDashboardAuth, resolveUiSource, ensureManagementDashboard, buildManagementDashboardArtifact, resolveSiteFramework, deploySiteRelease, deployAllComputeSites, reloadRpxGateway, renewRpxCertificates, MANAGED_CACHE_POLICY_OPTIMIZED, MANAGED_CACHE_POLICY_DISABLED, MANAGED_ORIGIN_REQUEST_POLICY_ALL_VIEWER, buildCloudFrontOriginConfig };
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  deployStaticSiteWithExternalDnsFull
3
- } from "./chunk-8kh577qh.js";
3
+ } from "./chunk-v0vpamnf.js";
4
4
  import {
5
5
  box,
6
6
  error,
@@ -22,10 +22,10 @@ import {
22
22
  SQSClient,
23
23
  STSClient,
24
24
  SecretsManagerClient
25
- } from "./chunk-x6yzgv7y.js";
25
+ } from "./chunk-6a1t7fnq.js";
26
26
  import {
27
27
  IAMClient
28
- } from "./chunk-hpv68b4a.js";
28
+ } from "./chunk-nsgqsmrh.js";
29
29
  import {
30
30
  CloudFrontClient
31
31
  } from "./chunk-01d86gt1.js";
@@ -50,7 +50,7 @@ import {
50
50
  resolveSiteKind,
51
51
  resolveUiSource,
52
52
  siteInstallBase
53
- } from "./chunk-d3vx2ekv.js";
53
+ } from "./chunk-6xnwshtc.js";
54
54
  import {
55
55
  SSMClient
56
56
  } from "./chunk-7m60qnc8.js";
@@ -60,7 +60,7 @@ import {
60
60
  import {
61
61
  S3Client,
62
62
  resolveCredentials
63
- } from "./chunk-wj3s95p9.js";
63
+ } from "./chunk-rds0sy87.js";
64
64
  import {
65
65
  AWSClient,
66
66
  buildQueryParams
@@ -10395,7 +10395,7 @@ async function sendAuthenticationEmail(config, message) {
10395
10395
  if (!from)
10396
10396
  return false;
10397
10397
  try {
10398
- const { EmailClient } = await import("./chunk-k114qwg9.js");
10398
+ const { EmailClient } = await import("./chunk-ttz2ra5j.js");
10399
10399
  const email = new EmailClient({ region: config.project.region, defaultFrom: from });
10400
10400
  await email.send(message);
10401
10401
  return true;
@@ -30848,6 +30848,8 @@ function siteKindLabel(name, site) {
30848
30848
  const kind = resolveSiteKind(site);
30849
30849
  if (kind === "redirect")
30850
30850
  return "redirect";
30851
+ if (kind === "proxy")
30852
+ return "proxy";
30851
30853
  const build2 = String(site.build ?? "").toLowerCase();
30852
30854
  const start = String(site.start ?? "").toLowerCase();
30853
30855
  if (name === "main" || start.includes("buddy/src/cli.ts serve"))
@@ -30870,7 +30872,7 @@ function siteKindLabel(name, site) {
30870
30872
  }
30871
30873
  function siteRuntime(site) {
30872
30874
  const kind = resolveSiteKind(site);
30873
- if (kind === "redirect")
30875
+ if (kind === "redirect" || kind === "proxy")
30874
30876
  return "—";
30875
30877
  const command = `${site.start ?? ""} ${site.build ?? ""}`.toLowerCase();
30876
30878
  if (kind === "server-static")
@@ -30885,6 +30887,8 @@ function siteDeployLabel(site) {
30885
30887
  const kind = resolveSiteKind(site);
30886
30888
  if (kind === "redirect")
30887
30889
  return "redirect";
30890
+ if (kind === "proxy")
30891
+ return "proxy";
30888
30892
  if (kind === "server-app")
30889
30893
  return "service";
30890
30894
  if (kind === "server-static")
@@ -36403,7 +36407,7 @@ async function startLocalDashboardServer(options = {}) {
36403
36407
  });
36404
36408
  const notificationRouter = new NotificationRouter(alertStore, {
36405
36409
  emailImpl: async (input) => {
36406
- const { email } = await import("./chunk-k114qwg9.js");
36410
+ const { email } = await import("./chunk-ttz2ra5j.js");
36407
36411
  return email.send(input);
36408
36412
  }
36409
36413
  });
@@ -5,12 +5,12 @@ import {
5
5
  generateStaticSiteTemplate,
6
6
  invalidateCache,
7
7
  uploadStaticFiles
8
- } from "./chunk-8kh577qh.js";
8
+ } from "./chunk-v0vpamnf.js";
9
9
  import"./chunk-01d86gt1.js";
10
10
  import"./chunk-gttvakpv.js";
11
11
  import"./chunk-32e7ya18.js";
12
12
  import"./chunk-4cjrg98a.js";
13
- import"./chunk-wj3s95p9.js";
13
+ import"./chunk-rds0sy87.js";
14
14
  import"./chunk-zqtpg06c.js";
15
15
  import"./chunk-v0bahtg2.js";
16
16
  export {
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-32e7ya18.js";
4
4
  import {
5
5
  S3Client
6
- } from "./chunk-wj3s95p9.js";
6
+ } from "./chunk-rds0sy87.js";
7
7
  import {
8
8
  AWSClient
9
9
  } from "./chunk-zqtpg06c.js";
@@ -1407,7 +1407,8 @@ host:${host}
1407
1407
  queryParams: { uploads: "" },
1408
1408
  headers
1409
1409
  });
1410
- return { UploadId: result?.InitiateMultipartUploadResult?.UploadId };
1410
+ const root = result?.InitiateMultipartUploadResult ?? result;
1411
+ return { UploadId: root?.UploadId };
1411
1412
  }
1412
1413
  async uploadPart(bucket, key, uploadId, partNumber, body) {
1413
1414
  const { accessKeyId, secretAccessKey, sessionToken } = this.getCredentials();
@@ -1504,7 +1505,7 @@ host:${host}
1504
1505
  bucket,
1505
1506
  queryParams: { uploads: "" }
1506
1507
  });
1507
- const uploads = result?.ListMultipartUploadsResult?.Upload;
1508
+ const uploads = (result?.ListMultipartUploadsResult ?? result)?.Upload;
1508
1509
  if (!uploads)
1509
1510
  return [];
1510
1511
  const list = Array.isArray(uploads) ? uploads : [uploads];
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  EmailClient,
3
3
  email
4
- } from "./chunk-hpv68b4a.js";
4
+ } from "./chunk-nsgqsmrh.js";
5
5
  import"./chunk-32e7ya18.js";
6
- import"./chunk-wj3s95p9.js";
6
+ import"./chunk-rds0sy87.js";
7
7
  import"./chunk-zqtpg06c.js";
8
8
  import"./chunk-v0bahtg2.js";
9
9
  export {
@@ -16,7 +16,7 @@ import {
16
16
  } from "./chunk-4cjrg98a.js";
17
17
  import {
18
18
  S3Client
19
- } from "./chunk-wj3s95p9.js";
19
+ } from "./chunk-rds0sy87.js";
20
20
  import {
21
21
  __require
22
22
  } from "./chunk-v0bahtg2.js";
@@ -815,7 +815,7 @@ async function deployStaticSiteWithExternalDnsFull(config) {
815
815
  }
816
816
  }
817
817
  onProgress?.("upload", "Uploading files to S3...");
818
- const { uploadStaticFiles } = await import("./chunk-9v2pwxv9.js");
818
+ const { uploadStaticFiles } = await import("./chunk-kpeb5rcs.js");
819
819
  const uploadResult = await uploadStaticFiles({
820
820
  sourceDir,
821
821
  bucket: infraResult.bucket,
@@ -835,7 +835,7 @@ async function deployStaticSiteWithExternalDnsFull(config) {
835
835
  }
836
836
  if (infraResult.distributionId && uploadResult.uploaded > 0) {
837
837
  onProgress?.("invalidate", "Invalidating CloudFront cache...");
838
- const { invalidateCache } = await import("./chunk-9v2pwxv9.js");
838
+ const { invalidateCache } = await import("./chunk-kpeb5rcs.js");
839
839
  await invalidateCache(infraResult.distributionId);
840
840
  }
841
841
  onProgress?.("complete", "Deployment complete!");
@@ -36,7 +36,7 @@ import {
36
36
  synchronizeDashboardUsers,
37
37
  trackDashboardOperation,
38
38
  verifyStaticApiOrigin
39
- } from "../chunk-wmz8x3cy.js";
39
+ } from "../chunk-ham2enem.js";
40
40
  import {
41
41
  deleteStaticSite,
42
42
  deployStaticSite,
@@ -47,12 +47,12 @@ import {
47
47
  generateStaticSiteTemplate,
48
48
  invalidateCache,
49
49
  uploadStaticFiles
50
- } from "../chunk-8kh577qh.js";
50
+ } from "../chunk-v0vpamnf.js";
51
51
  import {
52
52
  buildAndPushServerlessImage
53
53
  } from "../chunk-wmbep3b5.js";
54
- import"../chunk-x6yzgv7y.js";
55
- import"../chunk-hpv68b4a.js";
54
+ import"../chunk-6a1t7fnq.js";
55
+ import"../chunk-nsgqsmrh.js";
56
56
  import"../chunk-01d86gt1.js";
57
57
  import"../chunk-50jpda9q.js";
58
58
  import"../chunk-he9a874b.js";
@@ -65,12 +65,14 @@ import {
65
65
  collectServerDnsDomains,
66
66
  dashboardCredentialsFile,
67
67
  ensureManagementDashboard,
68
+ hasProxyUpstream,
68
69
  hostAcceptsIpv6,
69
70
  isPhpSite,
70
71
  normalizePublicIpv6,
71
72
  reconcileAddressRecords,
72
73
  removeStaleServerAddressRecords,
73
74
  resolveDashboardAuth,
75
+ resolveProxyUpstreams,
74
76
  resolveSiteDeployTarget,
75
77
  resolveSiteKind,
76
78
  resolveUiSource,
@@ -78,10 +80,10 @@ import {
78
80
  siteInstallBase,
79
81
  validateDeploymentConfig,
80
82
  verifyAddressRecord
81
- } from "../chunk-d3vx2ekv.js";
83
+ } from "../chunk-6xnwshtc.js";
82
84
  import"../chunk-7m60qnc8.js";
83
85
  import"../chunk-4cjrg98a.js";
84
- import"../chunk-wj3s95p9.js";
86
+ import"../chunk-rds0sy87.js";
85
87
  import"../chunk-zqtpg06c.js";
86
88
  import"../chunk-19bs955w.js";
87
89
  import"../chunk-va2yd85b.js";
@@ -106,6 +108,7 @@ export {
106
108
  resolveUiSource,
107
109
  resolveSiteKind,
108
110
  resolveSiteDeployTarget,
111
+ resolveProxyUpstreams,
109
112
  resolveLegacyDashboardRoute,
110
113
  resolveDashboardData,
111
114
  resolveDashboardAuth,
@@ -120,6 +123,7 @@ export {
120
123
  infraEnvFromOutputs,
121
124
  hostAcceptsIpv6,
122
125
  hashContainerContext,
126
+ hasProxyUpstream,
123
127
  generateStaticSiteTemplate,
124
128
  generateExternalDnsStaticSiteTemplate,
125
129
  generateExistingStaticFullStackTemplate,
@@ -1,6 +1,6 @@
1
1
  import type { CloudConfig, SiteConfig, SiteDeployTarget } from '@ts-cloud/core';
2
2
  /**
3
- * The three resolved deployment kinds for a site:
3
+ * The resolved deployment kinds for a site:
4
4
  * - `'bucket'` — upload built `root` to object storage + CDN.
5
5
  * - `'server-app'` — `server` + `start`: dynamic app as a systemd service.
6
6
  * - `'server-static'` — `server` + no `start` (has static `root`): a static
@@ -8,8 +8,12 @@ import type { CloudConfig, SiteConfig, SiteDeployTarget } from '@ts-cloud/core';
8
8
  * (served by the operator's own proxy, e.g. rpx + tlsx).
9
9
  * - `'redirect'` — gateway-only: `redirect` is set. Nothing is shipped;
10
10
  * the gateway answers `domain` with an HTTP redirect.
11
+ * - `'proxy'` — gateway-only: `proxyTo` is set. Nothing is shipped and
12
+ * no unit is managed; the gateway forwards `domain` to an
13
+ * upstream somebody else runs. The domain still joins the
14
+ * gateway's TLS set, which is the point.
11
15
  */
12
- export type SiteDeployKind = 'bucket' | 'server-app' | 'server-static' | 'server-php' | 'redirect';
16
+ export type SiteDeployKind = 'bucket' | 'server-app' | 'server-static' | 'server-php' | 'redirect' | 'proxy';
13
17
  /**
14
18
  * On-disk base directory for a site's atomic release tree
15
19
  * (`<base>/releases/<sha>` + `<base>/current`).
@@ -33,6 +37,17 @@ export declare function siteInstallBase(slug: string, siteName: string): string;
33
37
  * `type` (laravel/php/statamic/wordpress).
34
38
  */
35
39
  export declare function isPhpSite(site: SiteConfig): boolean;
40
+ /**
41
+ * Normalize a proxy-only site's `proxyTo` into the upstream list the gateway
42
+ * routes to, dropping blanks so a stray empty string cannot produce a route
43
+ * pointing at nothing.
44
+ *
45
+ * Returns `[]` when the site declares no usable upstream, which is what
46
+ * {@link hasProxyUpstream} keys off.
47
+ */
48
+ export declare function resolveProxyUpstreams(site: SiteConfig): string[];
49
+ /** Does this site forward to an upstream ts-cloud does not manage? */
50
+ export declare function hasProxyUpstream(site: SiteConfig): boolean;
36
51
  /**
37
52
  * Resolve the explicit-or-inferred {@link SiteDeployTarget} for a site.
38
53
  *
@@ -68,8 +83,10 @@ export declare function validateDeploymentConfig(config: CloudConfig): Deploymen
68
83
  * Does this site produce a release the compute deploy has to build, package and
69
84
  * ship?
70
85
  *
71
- * `false` for the two kinds that ship nothing:
86
+ * `false` for the kinds that ship nothing:
72
87
  * - `bucket` — handled by the S3/CloudFront static-site path instead;
88
+ * - `proxy` — the gateway forwards the domain to a service ts-cloud does not
89
+ * manage, so there is nothing to build, package or restart;
73
90
  * - `redirect` — the gateway answers the domain with a Location header, so
74
91
  * there is no `root` to package. Filtering these BEFORE the packaging loop
75
92
  * matters: that loop reads `site.root` to build a tarball, and a redirect
@@ -68,10 +68,10 @@ import {
68
68
  waitForSsh,
69
69
  wrapCloudInitUserData,
70
70
  writeResizeCheckpoint
71
- } from "../chunk-d3vx2ekv.js";
71
+ } from "../chunk-6xnwshtc.js";
72
72
  import"../chunk-7m60qnc8.js";
73
73
  import"../chunk-4cjrg98a.js";
74
- import"../chunk-wj3s95p9.js";
74
+ import"../chunk-rds0sy87.js";
75
75
  import"../chunk-zqtpg06c.js";
76
76
  import"../chunk-va2yd85b.js";
77
77
  import"../chunk-aa2dkn7b.js";
@@ -2,10 +2,12 @@
2
2
  * Generate the rpx reverse-proxy gateway config + provisioning from the `sites`
3
3
  * model.
4
4
  *
5
- * ts-cloud's per-site deploy model resolves each site to one of three kinds
5
+ * ts-cloud's per-site deploy model resolves each site to a kind
6
6
  * (see {@link import('../../deploy/site-target').resolveSiteKind}):
7
7
  * - `server-app` — a dynamic app running on a port (systemd service);
8
8
  * - `server-static` — a static site shipped to `/var/www/<name>`;
9
+ * - `redirect` — answered here with a Location header, nothing shipped;
10
+ * - `proxy` — forwarded here to an upstream ts-cloud does not manage;
9
11
  * - `bucket` — object storage + CDN (not on the box; ignored here).
10
12
  *
11
13
  * The rpx gateway fronts :80/:443 on the box and routes by host **and path**:
package/dist/index.d.ts CHANGED
@@ -32,7 +32,7 @@ export type { ObjectStorageConfig, ObjectStorageCredentials, ObjectStorageProvid
32
32
  export { keyMatchesFilters, migrateObjectStorage, remapKey } from './object-storage/migrate';
33
33
  export type { MigrateEndpoint, MigrateError, MigrateOptions, MigratePlanItem, MigrateProgress, MigrateResult, MigrateVerification, } from './object-storage/migrate';
34
34
  export * from './ssl';
35
- export { deployStaticSite, deployStaticSiteFull, uploadStaticFiles, invalidateCache, deleteStaticSite, generateStaticSiteTemplate, deployStaticSiteWithExternalDns, deployStaticSiteWithExternalDnsFull, generateExternalDnsStaticSiteTemplate, deploySite, resolveSiteDeployTarget, resolveSiteKind, validateDeploymentConfig, buildAndPushServerlessImage, buildFunctionEnv, deployServerlessApp, infraEnvFromOutputs, redeployServerlessApp, rollbackServerlessApp, runRemoteCommand, setMaintenance, buildManagementDashboardArtifact, dashboardCredentialsFile, ensureManagementDashboard, MANAGEMENT_DASHBOARD_SITE, resolveDashboardAuth, resolveUiSource, } from './deploy';
35
+ export { deployStaticSite, deployStaticSiteFull, uploadStaticFiles, invalidateCache, deleteStaticSite, generateStaticSiteTemplate, deployStaticSiteWithExternalDns, deployStaticSiteWithExternalDnsFull, generateExternalDnsStaticSiteTemplate, deploySite, hasProxyUpstream, resolveProxyUpstreams, resolveSiteDeployTarget, resolveSiteKind, shipsARelease, validateDeploymentConfig, buildAndPushServerlessImage, buildFunctionEnv, deployServerlessApp, infraEnvFromOutputs, redeployServerlessApp, rollbackServerlessApp, runRemoteCommand, setMaintenance, buildManagementDashboardArtifact, dashboardCredentialsFile, ensureManagementDashboard, MANAGEMENT_DASHBOARD_SITE, resolveDashboardAuth, resolveUiSource, } from './deploy';
36
36
  export { collectServerDnsDomains, hostAcceptsIpv6, IPV6_EXCLUDED_HOST_LABELS, normalizePublicIpv6, reconcileAddressRecords, removeStaleServerAddressRecords, verifyAddressRecord, } from './deploy/server-dns';
37
37
  export type { AddressRecordReport } from './deploy/server-dns';
38
38
  export type { EnsureDashboardLogger, ResolvedDashboardAuth, StaticSiteConfig, DeployResult, UploadOptions, ExternalDnsStaticSiteConfig, ExternalDnsDeployResult, DeploySiteConfig, DeploySiteResult, StaticSiteDnsProvider, SiteDeployKind, DeploymentValidationResult, BuildImageOptions, BuiltImage, CodeSource, DeployServerlessOptions, ResolvedContext, } from './deploy';
package/dist/index.js CHANGED
@@ -208,7 +208,7 @@ import {
208
208
  verifyUpdateSignature,
209
209
  webhookEndpoint,
210
210
  zeroCapacity
211
- } from "./chunk-wmz8x3cy.js";
211
+ } from "./chunk-ham2enem.js";
212
212
  import {
213
213
  deleteStaticSite,
214
214
  deployStaticSite,
@@ -219,7 +219,7 @@ import {
219
219
  generateStaticSiteTemplate,
220
220
  invalidateCache,
221
221
  uploadStaticFiles
222
- } from "./chunk-8kh577qh.js";
222
+ } from "./chunk-v0vpamnf.js";
223
223
  import {
224
224
  buildAndPushServerlessImage
225
225
  } from "./chunk-wmbep3b5.js";
@@ -260,12 +260,12 @@ import {
260
260
  providerEndpoint,
261
261
  remapKey,
262
262
  resolveObjectStorage
263
- } from "./chunk-x6yzgv7y.js";
263
+ } from "./chunk-6a1t7fnq.js";
264
264
  import {
265
265
  EmailClient,
266
266
  IAMClient,
267
267
  SESClient
268
- } from "./chunk-hpv68b4a.js";
268
+ } from "./chunk-nsgqsmrh.js";
269
269
  import {
270
270
  CloudFrontClient
271
271
  } from "./chunk-01d86gt1.js";
@@ -316,6 +316,7 @@ import {
316
316
  ensureManagementDashboard,
317
317
  ensureServer,
318
318
  ensureSshKey,
319
+ hasProxyUpstream,
319
320
  hostAcceptsIpv6,
320
321
  normalizePublicIpv6,
321
322
  normalizeSshPublicKey,
@@ -326,11 +327,13 @@ import {
326
327
  resolveDashboardAuth,
327
328
  resolveExecStart,
328
329
  resolveHetznerApiToken,
330
+ resolveProxyUpstreams,
329
331
  resolveSiteDeployTarget,
330
332
  resolveSiteKind,
331
333
  resolveUiSource,
332
334
  scpUpload,
333
335
  serverPublicIpv4,
336
+ shipsARelease,
334
337
  sshExec,
335
338
  sshExecOrThrow,
336
339
  validateDeploymentConfig,
@@ -338,7 +341,7 @@ import {
338
341
  waitForCloudInit,
339
342
  waitForSsh,
340
343
  wrapCloudInitUserData
341
- } from "./chunk-d3vx2ekv.js";
344
+ } from "./chunk-6xnwshtc.js";
342
345
  import {
343
346
  EC2Client,
344
347
  SSMClient
@@ -348,7 +351,7 @@ import {
348
351
  } from "./chunk-4cjrg98a.js";
349
352
  import {
350
353
  S3Client
351
- } from "./chunk-wj3s95p9.js";
354
+ } from "./chunk-rds0sy87.js";
352
355
  import {
353
356
  AWSClient
354
357
  } from "./chunk-zqtpg06c.js";
@@ -5333,6 +5336,7 @@ export {
5333
5336
  signRequest,
5334
5337
  signCloudFrontUrl,
5335
5338
  signCloudFrontCookies,
5339
+ shipsARelease,
5336
5340
  sharedRuntimeLoop,
5337
5341
  sharedRecursionGuard,
5338
5342
  sha256,
@@ -5396,6 +5400,7 @@ export {
5396
5400
  resolveQueues,
5397
5401
  resolveQueuedDeploymentCommand,
5398
5402
  resolveQueueNames,
5403
+ resolveProxyUpstreams,
5399
5404
  resolveProjectStackName,
5400
5405
  resolveObjectStorage,
5401
5406
  resolveManagementDashboardSites,
@@ -5558,6 +5563,7 @@ export {
5558
5563
  hashFile,
5559
5564
  hashDirectory,
5560
5565
  hashBuffer,
5566
+ hasProxyUpstream,
5561
5567
  hasManagementDashboardSite,
5562
5568
  handleSpendRequest,
5563
5569
  guardDutyManager,