@stacksjs/ts-cloud 0.2.23 → 0.2.25
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.
- package/dist/bin/cli.js +668 -682
- package/dist/deploy/site-target.d.ts +3 -3
- package/dist/drivers/hetzner/cloud-init.d.ts +7 -0
- package/dist/drivers/hetzner/driver.d.ts +5 -4
- package/dist/drivers/index.d.ts +3 -2
- package/dist/drivers/shared/compute-deploy.d.ts +8 -1
- package/dist/drivers/shared/deploy-script.d.ts +3 -3
- package/dist/drivers/shared/rpx-gateway.d.ts +122 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +182 -213
- package/package.json +3 -3
- package/dist/drivers/shared/caddyfile.d.ts +0 -46
package/dist/index.js
CHANGED
|
@@ -81449,204 +81449,6 @@ import { homedir as homedir7 } from "node:os";
|
|
|
81449
81449
|
import { join as join13 } from "node:path";
|
|
81450
81450
|
import { execSync } from "node:child_process";
|
|
81451
81451
|
|
|
81452
|
-
// src/drivers/shared/caddyfile.ts
|
|
81453
|
-
function isOnDemandDomain(domain) {
|
|
81454
|
-
return domain === "*" || domain.includes("*");
|
|
81455
|
-
}
|
|
81456
|
-
function isStaticApp(app) {
|
|
81457
|
-
return typeof app.root === "string" && app.root.length > 0;
|
|
81458
|
-
}
|
|
81459
|
-
function isProxyApp(app) {
|
|
81460
|
-
return typeof app.port === "number";
|
|
81461
|
-
}
|
|
81462
|
-
function staticSiteServerRoot(name) {
|
|
81463
|
-
return `/var/www/${name}`;
|
|
81464
|
-
}
|
|
81465
|
-
function normalizeOnDemandTls(onDemandTls) {
|
|
81466
|
-
if (!onDemandTls)
|
|
81467
|
-
return;
|
|
81468
|
-
if (onDemandTls === true)
|
|
81469
|
-
return {};
|
|
81470
|
-
return onDemandTls;
|
|
81471
|
-
}
|
|
81472
|
-
function wrapInHandle(body, path, indent) {
|
|
81473
|
-
const inner = body.split(`
|
|
81474
|
-
`).map((line) => ` ${line}`).join(`
|
|
81475
|
-
`);
|
|
81476
|
-
return `${indent}handle ${path} {
|
|
81477
|
-
${inner}
|
|
81478
|
-
${indent}}`;
|
|
81479
|
-
}
|
|
81480
|
-
function renderUpstreamBlock(app, indent) {
|
|
81481
|
-
const host = app.upstreamHost || "localhost";
|
|
81482
|
-
const upstream = `${host}:${app.port}`;
|
|
81483
|
-
const directives = app.reverseProxyDirectives ?? [];
|
|
81484
|
-
const proxyLine = directives.length === 0 ? `${indent}reverse_proxy ${upstream}` : [
|
|
81485
|
-
`${indent}reverse_proxy ${upstream} {`,
|
|
81486
|
-
...directives.map((d) => `${indent} ${d}`),
|
|
81487
|
-
`${indent}}`
|
|
81488
|
-
].join(`
|
|
81489
|
-
`);
|
|
81490
|
-
const isCatchAll = !app.path || app.path === "/";
|
|
81491
|
-
if (isCatchAll)
|
|
81492
|
-
return proxyLine;
|
|
81493
|
-
return wrapInHandle(proxyLine, app.path, indent);
|
|
81494
|
-
}
|
|
81495
|
-
function renderStaticBlock(app, indent) {
|
|
81496
|
-
const root = app.root;
|
|
81497
|
-
const lines = [`${indent}root * ${root}`];
|
|
81498
|
-
if (app.cache?.enabled) {
|
|
81499
|
-
const maxAge = app.cache.maxAge ?? 3600;
|
|
81500
|
-
lines.push(`${indent}header Cache-Control "public, max-age=${maxAge}"`);
|
|
81501
|
-
}
|
|
81502
|
-
if (app.spa) {
|
|
81503
|
-
lines.push(`${indent}try_files {path} /index.html`);
|
|
81504
|
-
} else if (app.pathRewriteStyle === "flat") {
|
|
81505
|
-
lines.push(`${indent}try_files {path} {path}.html {path}/index.html`);
|
|
81506
|
-
} else {
|
|
81507
|
-
lines.push(`${indent}try_files {path} {path}/index.html {path}.html`);
|
|
81508
|
-
}
|
|
81509
|
-
lines.push(`${indent}file_server`);
|
|
81510
|
-
const body = lines.join(`
|
|
81511
|
-
`);
|
|
81512
|
-
const isCatchAll = !app.path || app.path === "/";
|
|
81513
|
-
if (isCatchAll)
|
|
81514
|
-
return body;
|
|
81515
|
-
return wrapInHandle(body, app.path, indent);
|
|
81516
|
-
}
|
|
81517
|
-
function renderAppBlock(app, indent) {
|
|
81518
|
-
return isStaticApp(app) ? renderStaticBlock(app, indent) : renderUpstreamBlock(app, indent);
|
|
81519
|
-
}
|
|
81520
|
-
function groupAppsByDomains(apps) {
|
|
81521
|
-
const groups = new Map;
|
|
81522
|
-
for (const app of apps) {
|
|
81523
|
-
const domains = [...app.domains].filter(Boolean);
|
|
81524
|
-
if (domains.length === 0)
|
|
81525
|
-
continue;
|
|
81526
|
-
const key = [...domains].sort().join(" ");
|
|
81527
|
-
const group = groups.get(key) ?? { domains, apps: [] };
|
|
81528
|
-
group.apps.push(app);
|
|
81529
|
-
groups.set(key, group);
|
|
81530
|
-
}
|
|
81531
|
-
return [...groups.values()];
|
|
81532
|
-
}
|
|
81533
|
-
function sortAppsByPath(apps) {
|
|
81534
|
-
return [...apps].sort((a, b) => {
|
|
81535
|
-
const aCatchAll = !a.path || a.path === "/";
|
|
81536
|
-
const bCatchAll = !b.path || b.path === "/";
|
|
81537
|
-
if (aCatchAll && !bCatchAll)
|
|
81538
|
-
return 1;
|
|
81539
|
-
if (!aCatchAll && bCatchAll)
|
|
81540
|
-
return -1;
|
|
81541
|
-
return (b.path?.length ?? 0) - (a.path?.length ?? 0);
|
|
81542
|
-
});
|
|
81543
|
-
}
|
|
81544
|
-
function buildCaddyfileFromProxy(proxy) {
|
|
81545
|
-
if (proxy.raw && proxy.raw.trim())
|
|
81546
|
-
return proxy.raw.trim();
|
|
81547
|
-
const apps = (proxy.apps ?? []).filter((app) => app.domains.length > 0 && (isProxyApp(app) || isStaticApp(app)));
|
|
81548
|
-
if (apps.length === 0)
|
|
81549
|
-
return;
|
|
81550
|
-
const onDemand = normalizeOnDemandTls(proxy.onDemandTls);
|
|
81551
|
-
const hasOnDemandDomain = apps.some((app) => app.domains.some(isOnDemandDomain));
|
|
81552
|
-
const globalLines = [];
|
|
81553
|
-
if (proxy.email)
|
|
81554
|
-
globalLines.push(`email ${proxy.email}`);
|
|
81555
|
-
if (proxy.staging)
|
|
81556
|
-
globalLines.push("acme_ca https://acme-staging-v02.api.letsencrypt.org/directory");
|
|
81557
|
-
if (onDemand) {
|
|
81558
|
-
if (onDemand.ask || onDemand.interval || onDemand.burst != null) {
|
|
81559
|
-
const inner = [];
|
|
81560
|
-
if (onDemand.ask)
|
|
81561
|
-
inner.push(` ask ${onDemand.ask}`);
|
|
81562
|
-
if (onDemand.interval || onDemand.burst != null) {
|
|
81563
|
-
const rl = [];
|
|
81564
|
-
if (onDemand.interval)
|
|
81565
|
-
rl.push(` interval ${onDemand.interval}`);
|
|
81566
|
-
if (onDemand.burst != null)
|
|
81567
|
-
rl.push(` burst ${onDemand.burst}`);
|
|
81568
|
-
inner.push(` rate_limit {
|
|
81569
|
-
${rl.join(`
|
|
81570
|
-
`)}
|
|
81571
|
-
}`);
|
|
81572
|
-
}
|
|
81573
|
-
globalLines.push(`on_demand_tls {
|
|
81574
|
-
${inner.join(`
|
|
81575
|
-
`)}
|
|
81576
|
-
}`);
|
|
81577
|
-
} else {
|
|
81578
|
-
globalLines.push(`on_demand_tls {
|
|
81579
|
-
}`);
|
|
81580
|
-
}
|
|
81581
|
-
}
|
|
81582
|
-
for (const directive of proxy.globalDirectives ?? [])
|
|
81583
|
-
globalLines.push(directive);
|
|
81584
|
-
const blocks = [];
|
|
81585
|
-
if (globalLines.length > 0)
|
|
81586
|
-
blocks.push(`{
|
|
81587
|
-
${globalLines.map((line) => ` ${line}`).join(`
|
|
81588
|
-
`)}
|
|
81589
|
-
}`);
|
|
81590
|
-
for (const group of groupAppsByDomains(apps)) {
|
|
81591
|
-
const sorted = sortAppsByPath(group.apps);
|
|
81592
|
-
const body = sorted.map((app) => renderAppBlock(app, " ")).join(`
|
|
81593
|
-
`);
|
|
81594
|
-
const needsOnDemand = onDemand && group.domains.some(isOnDemandDomain);
|
|
81595
|
-
const tlsBlock = needsOnDemand ? `
|
|
81596
|
-
tls {
|
|
81597
|
-
on_demand
|
|
81598
|
-
}` : "";
|
|
81599
|
-
blocks.push(`${group.domains.join(", ")} {
|
|
81600
|
-
${body}${tlsBlock}
|
|
81601
|
-
}`);
|
|
81602
|
-
}
|
|
81603
|
-
if (hasOnDemandDomain && !onDemand) {
|
|
81604
|
-
blocks.unshift(`# WARNING: wildcard/catch-all domain present but on_demand_tls is not enabled.
|
|
81605
|
-
` + "# Caddy cannot provision TLS for these hosts. Set compute.proxy.onDemandTls.");
|
|
81606
|
-
}
|
|
81607
|
-
return blocks.join(`
|
|
81608
|
-
|
|
81609
|
-
`);
|
|
81610
|
-
}
|
|
81611
|
-
function proxyConfigFromSites(sites) {
|
|
81612
|
-
const apps = [];
|
|
81613
|
-
for (const [name, site] of Object.entries(sites)) {
|
|
81614
|
-
if (typeof site.domain !== "string" || !site.domain)
|
|
81615
|
-
continue;
|
|
81616
|
-
if (typeof site.port === "number" && site.deploy !== "bucket") {
|
|
81617
|
-
apps.push({
|
|
81618
|
-
name,
|
|
81619
|
-
domains: [site.domain],
|
|
81620
|
-
port: site.port,
|
|
81621
|
-
path: site.path
|
|
81622
|
-
});
|
|
81623
|
-
} else if (resolveSiteKind(site) === "server-static") {
|
|
81624
|
-
apps.push({
|
|
81625
|
-
name,
|
|
81626
|
-
domains: [site.domain],
|
|
81627
|
-
root: staticSiteServerRoot(name),
|
|
81628
|
-
path: site.path,
|
|
81629
|
-
spa: site.spa,
|
|
81630
|
-
pathRewriteStyle: site.pathRewriteStyle,
|
|
81631
|
-
cache: site.cache
|
|
81632
|
-
});
|
|
81633
|
-
}
|
|
81634
|
-
}
|
|
81635
|
-
return { apps };
|
|
81636
|
-
}
|
|
81637
|
-
function resolveCaddyfile(sites, proxy) {
|
|
81638
|
-
if (proxy) {
|
|
81639
|
-
if (proxy.raw && proxy.raw.trim())
|
|
81640
|
-
return proxy.raw.trim();
|
|
81641
|
-
const resolved = proxy.apps && proxy.apps.length > 0 ? proxy : { ...proxy, apps: proxyConfigFromSites(sites).apps };
|
|
81642
|
-
return buildCaddyfileFromProxy(resolved);
|
|
81643
|
-
}
|
|
81644
|
-
return buildCaddyfileFromProxy(proxyConfigFromSites(sites));
|
|
81645
|
-
}
|
|
81646
|
-
function buildCaddyfile(sites) {
|
|
81647
|
-
return buildCaddyfileFromProxy(proxyConfigFromSites(sites));
|
|
81648
|
-
}
|
|
81649
|
-
|
|
81650
81452
|
// src/drivers/hetzner/client.ts
|
|
81651
81453
|
var DEFAULT_API_URL = "https://api.hetzner.cloud/v1";
|
|
81652
81454
|
|
|
@@ -81798,7 +81600,8 @@ function generateUbuntuAppCloudInit(options = {}) {
|
|
|
81798
81600
|
runtimeVersion = "latest",
|
|
81799
81601
|
systemPackages = [],
|
|
81800
81602
|
database,
|
|
81801
|
-
caddyfile
|
|
81603
|
+
caddyfile,
|
|
81604
|
+
rpxProvision
|
|
81802
81605
|
} = options;
|
|
81803
81606
|
const packages = new Set(systemPackages);
|
|
81804
81607
|
if (database === "sqlite")
|
|
@@ -81890,6 +81693,13 @@ CADDY_CONFIG_EOF
|
|
|
81890
81693
|
systemctl daemon-reload
|
|
81891
81694
|
systemctl enable caddy
|
|
81892
81695
|
systemctl start caddy
|
|
81696
|
+
`;
|
|
81697
|
+
}
|
|
81698
|
+
if (rpxProvision && rpxProvision.length > 0) {
|
|
81699
|
+
const body = rpxProvision[0] === "set -euo pipefail" ? rpxProvision.slice(1) : rpxProvision;
|
|
81700
|
+
script += `
|
|
81701
|
+
${body.join(`
|
|
81702
|
+
`)}
|
|
81893
81703
|
`;
|
|
81894
81704
|
}
|
|
81895
81705
|
script += `
|
|
@@ -81914,6 +81724,129 @@ runcmd:
|
|
|
81914
81724
|
`;
|
|
81915
81725
|
}
|
|
81916
81726
|
|
|
81727
|
+
// src/drivers/shared/rpx-gateway.ts
|
|
81728
|
+
var DEFAULT_RPX_CERTS_DIR = "/etc/rpx/certs";
|
|
81729
|
+
function normalizeRoutePath(path) {
|
|
81730
|
+
if (!path || path === "/")
|
|
81731
|
+
return;
|
|
81732
|
+
let p = `/${path}`.replace(/\/+/g, "/").replace(/\/+$/, "");
|
|
81733
|
+
if (!p.startsWith("/"))
|
|
81734
|
+
p = `/${p}`;
|
|
81735
|
+
return p === "" || p === "/" ? undefined : p;
|
|
81736
|
+
}
|
|
81737
|
+
function deriveRouteId(to, path) {
|
|
81738
|
+
const base = path ? `${to}${path}` : to;
|
|
81739
|
+
const cleaned = base.replace(/[^a-zA-Z0-9._-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 128);
|
|
81740
|
+
return cleaned.length > 0 ? cleaned : "rpx";
|
|
81741
|
+
}
|
|
81742
|
+
function buildRpxConfig(sites, options) {
|
|
81743
|
+
const wwwRoot = (options.wwwRoot ?? "/var/www").replace(/\/+$/, "");
|
|
81744
|
+
const certsDir = options.proxy.certsDir ?? DEFAULT_RPX_CERTS_DIR;
|
|
81745
|
+
const proxies = [];
|
|
81746
|
+
const domains = new Set;
|
|
81747
|
+
for (const [name, site] of Object.entries(sites)) {
|
|
81748
|
+
if (!site || !site.domain)
|
|
81749
|
+
continue;
|
|
81750
|
+
const kind = resolveSiteKind(site);
|
|
81751
|
+
if (kind === "bucket")
|
|
81752
|
+
continue;
|
|
81753
|
+
const path = normalizeRoutePath(site.path);
|
|
81754
|
+
const id = deriveRouteId(site.domain, path);
|
|
81755
|
+
if (kind === "server-app") {
|
|
81756
|
+
if (typeof site.port !== "number")
|
|
81757
|
+
continue;
|
|
81758
|
+
proxies.push({ to: site.domain, path, from: `localhost:${site.port}`, id });
|
|
81759
|
+
} else {
|
|
81760
|
+
proxies.push({
|
|
81761
|
+
to: site.domain,
|
|
81762
|
+
path,
|
|
81763
|
+
static: `${wwwRoot}/${name}`,
|
|
81764
|
+
cleanUrls: site.pathRewriteStyle !== "flat",
|
|
81765
|
+
spa: site.spa ?? false,
|
|
81766
|
+
id
|
|
81767
|
+
});
|
|
81768
|
+
}
|
|
81769
|
+
domains.add(site.domain);
|
|
81770
|
+
}
|
|
81771
|
+
proxies.sort((a, b) => {
|
|
81772
|
+
if (a.to !== b.to)
|
|
81773
|
+
return a.to.localeCompare(b.to);
|
|
81774
|
+
return (b.path?.length ?? 0) - (a.path?.length ?? 0);
|
|
81775
|
+
});
|
|
81776
|
+
const config6 = {
|
|
81777
|
+
proxies,
|
|
81778
|
+
productionCerts: { certsDir },
|
|
81779
|
+
https: true,
|
|
81780
|
+
hostsManagement: false,
|
|
81781
|
+
cleanup: { hosts: false, certs: false }
|
|
81782
|
+
};
|
|
81783
|
+
if (options.proxy.onDemandTls && domains.size > 0) {
|
|
81784
|
+
config6.onDemandTls = {
|
|
81785
|
+
enabled: true,
|
|
81786
|
+
allowedSuffixes: [...domains],
|
|
81787
|
+
email: options.proxy.onDemandTlsEmail,
|
|
81788
|
+
certsDir
|
|
81789
|
+
};
|
|
81790
|
+
}
|
|
81791
|
+
return config6;
|
|
81792
|
+
}
|
|
81793
|
+
function renderRpxLauncher(config6) {
|
|
81794
|
+
const json = JSON.stringify(config6, null, 2);
|
|
81795
|
+
return `// Generated by ts-cloud — rpx reverse-proxy gateway.
|
|
81796
|
+
// Routes are derived from the \`sites\` model on every \`buddy deploy\`.
|
|
81797
|
+
import { startProxies } from '@stacksjs/rpx'
|
|
81798
|
+
|
|
81799
|
+
const config = ${json} as const
|
|
81800
|
+
|
|
81801
|
+
await startProxies(config as any)
|
|
81802
|
+
`;
|
|
81803
|
+
}
|
|
81804
|
+
var RPX_DIR = "/etc/rpx";
|
|
81805
|
+
var RPX_LAUNCHER_PATH = "/etc/rpx/gateway.ts";
|
|
81806
|
+
var RPX_SERVICE_NAME = "rpx-gateway.service";
|
|
81807
|
+
function writeFileHeredoc(path, content, delimiter) {
|
|
81808
|
+
return [
|
|
81809
|
+
`cat > ${path} <<'${delimiter}'`,
|
|
81810
|
+
content,
|
|
81811
|
+
delimiter
|
|
81812
|
+
];
|
|
81813
|
+
}
|
|
81814
|
+
function buildRpxProvisionScript(options) {
|
|
81815
|
+
const { config: config6, proxy } = options;
|
|
81816
|
+
const bunBin = options.bunBin ?? "/usr/local/bin/bun";
|
|
81817
|
+
const version2 = proxy.version ?? "latest";
|
|
81818
|
+
const certsDir = config6.productionCerts.certsDir;
|
|
81819
|
+
const launcher = renderRpxLauncher(config6);
|
|
81820
|
+
return [
|
|
81821
|
+
"set -euo pipefail",
|
|
81822
|
+
`mkdir -p ${RPX_DIR} ${certsDir}`,
|
|
81823
|
+
`${bunBin} add -g @stacksjs/rpx@${version2}`,
|
|
81824
|
+
...writeFileHeredoc(RPX_LAUNCHER_PATH, launcher, "TS_CLOUD_RPX_EOF"),
|
|
81825
|
+
...writeFileHeredoc(`/etc/systemd/system/${RPX_SERVICE_NAME}`, [
|
|
81826
|
+
"[Unit]",
|
|
81827
|
+
"Description=rpx reverse-proxy gateway (managed by ts-cloud)",
|
|
81828
|
+
"After=network.target network-online.target",
|
|
81829
|
+
"Wants=network-online.target",
|
|
81830
|
+
"",
|
|
81831
|
+
"[Service]",
|
|
81832
|
+
"Type=simple",
|
|
81833
|
+
`ExecStart=${bunBin} ${RPX_LAUNCHER_PATH}`,
|
|
81834
|
+
`Environment=BUN_INSTALL=/root/.bun`,
|
|
81835
|
+
"Restart=always",
|
|
81836
|
+
"RestartSec=5",
|
|
81837
|
+
"LimitNOFILE=1048576",
|
|
81838
|
+
"AmbientCapabilities=CAP_NET_BIND_SERVICE",
|
|
81839
|
+
"",
|
|
81840
|
+
"[Install]",
|
|
81841
|
+
"WantedBy=multi-user.target"
|
|
81842
|
+
].join(`
|
|
81843
|
+
`), "TS_CLOUD_RPX_UNIT_EOF"),
|
|
81844
|
+
"systemctl daemon-reload",
|
|
81845
|
+
`systemctl enable ${RPX_SERVICE_NAME}`,
|
|
81846
|
+
`systemctl restart ${RPX_SERVICE_NAME}`
|
|
81847
|
+
];
|
|
81848
|
+
}
|
|
81849
|
+
|
|
81917
81850
|
// src/drivers/hetzner/firewall-rules.ts
|
|
81918
81851
|
function buildHetznerFirewallRules(config6) {
|
|
81919
81852
|
const openPorts = new Set([80, 443, ...config6.sitePorts]);
|
|
@@ -82049,14 +81982,18 @@ class HetznerDriver {
|
|
|
82049
81982
|
return this.outputsFromState(rehydrated, alreadyRunning);
|
|
82050
81983
|
}
|
|
82051
81984
|
const sites = config6.sites || {};
|
|
82052
|
-
const
|
|
82053
|
-
const
|
|
81985
|
+
const sitePorts = this.collectUpstreamPorts(sites);
|
|
81986
|
+
const rpxProvision = compute.proxy?.engine === "rpx" ? buildRpxProvisionScript({
|
|
81987
|
+
proxy: compute.proxy,
|
|
81988
|
+
config: buildRpxConfig(sites, { proxy: compute.proxy }),
|
|
81989
|
+
bunBin: compute.runtime === "node" || compute.runtime === "deno" ? undefined : "/usr/local/bin/bun"
|
|
81990
|
+
}) : undefined;
|
|
82054
81991
|
const bootstrap = generateUbuntuAppCloudInit({
|
|
82055
81992
|
runtime: compute.runtime || "bun",
|
|
82056
81993
|
runtimeVersion: compute.runtimeVersion || "latest",
|
|
82057
81994
|
systemPackages: compute.systemPackages,
|
|
82058
81995
|
database: config6.infrastructure?.database,
|
|
82059
|
-
|
|
81996
|
+
rpxProvision
|
|
82060
81997
|
});
|
|
82061
81998
|
const userData = wrapCloudInitUserData(bootstrap);
|
|
82062
81999
|
const serverType = resolveHetznerServerType(compute.size);
|
|
@@ -82222,12 +82159,8 @@ class HetznerDriver {
|
|
|
82222
82159
|
const { firewall } = await this.client.createFirewall({ name, labels, rules });
|
|
82223
82160
|
return { firewall };
|
|
82224
82161
|
}
|
|
82225
|
-
collectUpstreamPorts(sites
|
|
82162
|
+
collectUpstreamPorts(sites) {
|
|
82226
82163
|
const ports = new Set;
|
|
82227
|
-
for (const app of proxy?.apps ?? []) {
|
|
82228
|
-
if (typeof app.port === "number")
|
|
82229
|
-
ports.add(app.port);
|
|
82230
|
-
}
|
|
82231
82164
|
for (const site of Object.values(sites)) {
|
|
82232
82165
|
if (typeof site.port === "number")
|
|
82233
82166
|
ports.add(site.port);
|
|
@@ -82548,6 +82481,48 @@ async function deployAllComputeSites(options) {
|
|
|
82548
82481
|
}
|
|
82549
82482
|
}
|
|
82550
82483
|
}
|
|
82484
|
+
const reloaded = await reloadRpxGateway(options);
|
|
82485
|
+
if (!reloaded)
|
|
82486
|
+
return false;
|
|
82487
|
+
return true;
|
|
82488
|
+
}
|
|
82489
|
+
async function reloadRpxGateway(options) {
|
|
82490
|
+
const { config: config6, environment, driver, logger: logger4 = noopLogger } = options;
|
|
82491
|
+
const proxy = config6.infrastructure?.compute?.proxy;
|
|
82492
|
+
if (proxy?.engine !== "rpx")
|
|
82493
|
+
return true;
|
|
82494
|
+
const sites = config6.sites || {};
|
|
82495
|
+
const rpxConfig = buildRpxConfig(sites, { proxy });
|
|
82496
|
+
if (rpxConfig.proxies.length === 0) {
|
|
82497
|
+
logger4.warn("rpx gateway: no server sites with a domain to route — skipping gateway reload.");
|
|
82498
|
+
return true;
|
|
82499
|
+
}
|
|
82500
|
+
const targets = await driver.findComputeTargets({
|
|
82501
|
+
slug: config6.project.slug,
|
|
82502
|
+
environment,
|
|
82503
|
+
role: "app"
|
|
82504
|
+
});
|
|
82505
|
+
if (targets.length === 0) {
|
|
82506
|
+
logger4.warn("rpx gateway: no compute targets found — skipping gateway reload.");
|
|
82507
|
+
return true;
|
|
82508
|
+
}
|
|
82509
|
+
logger4.step(`Reloading rpx gateway with ${rpxConfig.proxies.length} route(s)...`);
|
|
82510
|
+
const script = buildRpxProvisionScript({ proxy, config: rpxConfig });
|
|
82511
|
+
const result = await driver.runRemoteDeploy({
|
|
82512
|
+
targets,
|
|
82513
|
+
commands: script,
|
|
82514
|
+
comment: `ts-cloud rpx gateway reload ${config6.project.slug}`,
|
|
82515
|
+
tags: {
|
|
82516
|
+
Project: config6.project.slug,
|
|
82517
|
+
Environment: environment,
|
|
82518
|
+
Role: "app"
|
|
82519
|
+
}
|
|
82520
|
+
});
|
|
82521
|
+
if (!result.success) {
|
|
82522
|
+
logger4.error(`rpx gateway reload failed: ${result.error || "unknown error"}`);
|
|
82523
|
+
return false;
|
|
82524
|
+
}
|
|
82525
|
+
logger4.success(`rpx gateway reloaded on ${result.instanceCount} target(s)`);
|
|
82551
82526
|
return true;
|
|
82552
82527
|
}
|
|
82553
82528
|
// src/index.ts
|
|
@@ -82581,7 +82556,6 @@ export {
|
|
|
82581
82556
|
suggestFlags,
|
|
82582
82557
|
suggestCommand,
|
|
82583
82558
|
storageAdvancedManager,
|
|
82584
|
-
staticSiteServerRoot,
|
|
82585
82559
|
staticSiteManager,
|
|
82586
82560
|
stackDependencyManager,
|
|
82587
82561
|
signRequestAsync,
|
|
@@ -82613,14 +82587,12 @@ export {
|
|
|
82613
82587
|
resolveDeployBucketName,
|
|
82614
82588
|
resolveCredentials,
|
|
82615
82589
|
resolveCloudProvider,
|
|
82616
|
-
resolveCaddyfile,
|
|
82617
82590
|
requiresReplacement,
|
|
82618
82591
|
replicaManager,
|
|
82619
82592
|
remapKey,
|
|
82620
82593
|
regionPairManager,
|
|
82621
82594
|
quickHash,
|
|
82622
82595
|
queueManagementManager,
|
|
82623
|
-
proxyConfigFromSites,
|
|
82624
82596
|
providerEndpoint,
|
|
82625
82597
|
progressiveDeploymentManager,
|
|
82626
82598
|
processInChunks,
|
|
@@ -82655,7 +82627,6 @@ export {
|
|
|
82655
82627
|
keyMatchesFilters,
|
|
82656
82628
|
isWebCryptoAvailable,
|
|
82657
82629
|
isValidRegion,
|
|
82658
|
-
isOnDemandDomain,
|
|
82659
82630
|
isNodeCryptoAvailable,
|
|
82660
82631
|
isLocalDevelopment,
|
|
82661
82632
|
isLikelyTypo,
|
|
@@ -82808,8 +82779,6 @@ export {
|
|
|
82808
82779
|
buildSiteDeployScript,
|
|
82809
82780
|
buildOptimizationManager,
|
|
82810
82781
|
buildCloudFormationTemplate,
|
|
82811
|
-
buildCaddyfileFromProxy,
|
|
82812
|
-
buildCaddyfile,
|
|
82813
82782
|
bounceComplaintHandler,
|
|
82814
82783
|
blueGreenManager,
|
|
82815
82784
|
batchProcessingManager,
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stacksjs/ts-cloud",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.2.
|
|
4
|
+
"version": "0.2.25",
|
|
5
5
|
"description": "A lightweight, performant infrastructure-as-code library and CLI for deploying both server-based (EC2) and serverless applications.",
|
|
6
6
|
"author": "Chris Breuer <chris@stacksjs.com>",
|
|
7
7
|
"license": "MIT",
|
|
@@ -89,8 +89,8 @@
|
|
|
89
89
|
"test": "bun test"
|
|
90
90
|
},
|
|
91
91
|
"dependencies": {
|
|
92
|
-
"@ts-cloud/aws-types": "0.2.
|
|
93
|
-
"@ts-cloud/core": "0.2.
|
|
92
|
+
"@ts-cloud/aws-types": "0.2.25",
|
|
93
|
+
"@ts-cloud/core": "0.2.25",
|
|
94
94
|
"@stacksjs/ts-xml": "^0.1.0"
|
|
95
95
|
},
|
|
96
96
|
"devDependencies": {
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
import type { CaddyAppConfig, CaddyProxyConfig, SiteConfig } from '@ts-cloud/core';
|
|
2
|
-
/** A domain is "on-demand" (needs lazy TLS) if it's a wildcard or bare catch-all. */
|
|
3
|
-
export declare function isOnDemandDomain(domain: string): boolean;
|
|
4
|
-
/**
|
|
5
|
-
* The on-server install path a static site's `root` is shipped to. Mirrors the
|
|
6
|
-
* release layout used by the systemd app deploy (`/var/www/<name>`), so a box
|
|
7
|
-
* can host both proxied apps and file-served static sites side by side.
|
|
8
|
-
*/
|
|
9
|
-
export declare function staticSiteServerRoot(name: string): string;
|
|
10
|
-
/**
|
|
11
|
-
* Build a complete Caddyfile from a typed {@link CaddyProxyConfig}.
|
|
12
|
-
*
|
|
13
|
-
* Produces:
|
|
14
|
-
* - a global options block (ACME email, on-demand TLS `ask`, staging CA, extras);
|
|
15
|
-
* - one site block per unique domain set, each performing host-based routing to
|
|
16
|
-
* its upstream app(s);
|
|
17
|
-
* - `tls { on_demand }` inside any block whose domains are wildcards/catch-all.
|
|
18
|
-
*
|
|
19
|
-
* Returns `undefined` when there's nothing to route (no apps, no raw).
|
|
20
|
-
*/
|
|
21
|
-
export declare function buildCaddyfileFromProxy(proxy: CaddyProxyConfig): string | undefined;
|
|
22
|
-
/**
|
|
23
|
-
* Derive a {@link CaddyProxyConfig} from the legacy `sites` map: every site
|
|
24
|
-
* that declares a `domain` + `port` becomes a Caddy app. Keeps single-app /
|
|
25
|
-
* sites-driven deploys working without an explicit `compute.proxy` block.
|
|
26
|
-
*/
|
|
27
|
-
export declare function proxyConfigFromSites(sites: Record<string, SiteConfig>): CaddyProxyConfig & {
|
|
28
|
-
apps: CaddyAppConfig[];
|
|
29
|
-
};
|
|
30
|
-
/**
|
|
31
|
-
* Resolve the final Caddyfile for a deploy. Prefers the typed `compute.proxy`
|
|
32
|
-
* config (merging in `sites`-derived apps when `proxy.apps` is omitted), and
|
|
33
|
-
* falls back to deriving everything from `sites`.
|
|
34
|
-
*
|
|
35
|
-
* Returns `undefined` when there's nothing to route.
|
|
36
|
-
*/
|
|
37
|
-
export declare function resolveCaddyfile(sites: Record<string, SiteConfig>, proxy?: CaddyProxyConfig): string | undefined;
|
|
38
|
-
/**
|
|
39
|
-
* Build a Caddyfile from site configs. Sites sharing a domain are grouped;
|
|
40
|
-
* explicit paths are ordered before catch-all routes.
|
|
41
|
-
*
|
|
42
|
-
* @deprecated Prefer {@link resolveCaddyfile} / {@link buildCaddyfileFromProxy},
|
|
43
|
-
* which support multi-app host routing and on-demand TLS. Retained for
|
|
44
|
-
* backward compatibility.
|
|
45
|
-
*/
|
|
46
|
-
export declare function buildCaddyfile(sites: Record<string, SiteConfig>): string | undefined;
|