@stacksjs/ts-cloud 0.7.85 → 0.7.86
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/aws/ec2.d.ts +13 -0
- package/dist/aws/index.js +1 -1
- package/dist/bin/cli.js +510 -510
- package/dist/{chunk-qbj74thz.js → chunk-4erbrg3e.js} +2 -2
- package/dist/{chunk-703nkybg.js → chunk-7m60qnc8.js} +10 -0
- package/dist/{chunk-gx4288t5.js → chunk-ztbn47we.js} +102 -58
- package/dist/deploy/index.js +15 -7
- package/dist/deploy/server-dns.d.ts +66 -7
- package/dist/drivers/index.js +2 -2
- package/dist/index.d.ts +2 -1
- package/dist/index.js +13 -5
- package/dist/ui/access-denied.html +2 -2
- package/dist/ui/account/automation.html +3 -3
- package/dist/ui/account/security.html +2 -2
- package/dist/ui/applications/compose.html +4 -4
- package/dist/ui/applications/new.html +2 -2
- package/dist/ui/data/backups.html +4 -4
- package/dist/ui/data/services.html +4 -4
- package/dist/ui/data/volumes.html +4 -4
- package/dist/ui/index.html +4 -4
- package/dist/ui/operations/alerts.html +3 -3
- package/dist/ui/operations/configuration.html +3 -3
- package/dist/ui/operations/jobs.html +3 -3
- package/dist/ui/operations/maintenance.html +3 -3
- package/dist/ui/operations/observability.html +4 -4
- package/dist/ui/operations/previews.html +4 -4
- package/dist/ui/operations/queue.html +4 -4
- package/dist/ui/operations/regions.html +4 -4
- package/dist/ui/operations/releases.html +4 -4
- package/dist/ui/operations/workloads.html +4 -4
- package/dist/ui/security.html +2 -2
- package/dist/ui/server/actions.html +4 -4
- package/dist/ui/server/activity.html +2 -2
- package/dist/ui/server/capacity.html +4 -4
- package/dist/ui/server/database.html +4 -4
- package/dist/ui/server/deployments.html +4 -4
- package/dist/ui/server/firewall.html +4 -4
- package/dist/ui/server/fleet.html +4 -4
- package/dist/ui/server/logs.html +4 -4
- package/dist/ui/server/metrics.html +4 -4
- package/dist/ui/server/services.html +2 -2
- package/dist/ui/server/sites.html +4 -4
- package/dist/ui/server/ssh-keys.html +4 -4
- package/dist/ui/server/team.html +4 -4
- package/dist/ui/serverless/alarms.html +4 -4
- package/dist/ui/serverless/assets.html +2 -2
- package/dist/ui/serverless/data.html +4 -4
- package/dist/ui/serverless/deployments.html +2 -2
- package/dist/ui/serverless/firewall.html +2 -2
- package/dist/ui/serverless/functions.html +4 -4
- package/dist/ui/serverless/logs.html +4 -4
- package/dist/ui/serverless/metrics.html +2 -2
- package/dist/ui/serverless/queues.html +4 -4
- package/dist/ui/serverless/secrets.html +4 -4
- package/dist/ui/serverless/traces.html +4 -4
- package/dist/ui/serverless.html +3 -3
- package/package.json +3 -3
|
@@ -45,7 +45,7 @@ import {
|
|
|
45
45
|
resolveSiteKind,
|
|
46
46
|
resolveUiSource,
|
|
47
47
|
siteInstallBase
|
|
48
|
-
} from "./chunk-
|
|
48
|
+
} from "./chunk-ztbn47we.js";
|
|
49
49
|
import {
|
|
50
50
|
artifactKey,
|
|
51
51
|
buildCloudFormationTemplate,
|
|
@@ -70,7 +70,7 @@ import {
|
|
|
70
70
|
} from "./chunk-1qjyqrc5.js";
|
|
71
71
|
import {
|
|
72
72
|
SSMClient
|
|
73
|
-
} from "./chunk-
|
|
73
|
+
} from "./chunk-7m60qnc8.js";
|
|
74
74
|
import {
|
|
75
75
|
CloudFormationClient
|
|
76
76
|
} from "./chunk-4cjrg98a.js";
|
|
@@ -1087,6 +1087,15 @@ class EC2Client {
|
|
|
1087
1087
|
return [];
|
|
1088
1088
|
return Array.isArray(item) ? item : [item];
|
|
1089
1089
|
}
|
|
1090
|
+
parseFirstIpv6Address(item) {
|
|
1091
|
+
for (const eni of this.parseArray(item)) {
|
|
1092
|
+
for (const entry of this.parseArray(eni?.ipv6AddressesSet?.item)) {
|
|
1093
|
+
if (entry?.ipv6Address)
|
|
1094
|
+
return entry.ipv6Address;
|
|
1095
|
+
}
|
|
1096
|
+
}
|
|
1097
|
+
return;
|
|
1098
|
+
}
|
|
1090
1099
|
parseTags(item) {
|
|
1091
1100
|
return this.parseArray(item).map((t) => ({
|
|
1092
1101
|
Key: t.key,
|
|
@@ -1110,6 +1119,7 @@ class EC2Client {
|
|
|
1110
1119
|
} : undefined,
|
|
1111
1120
|
PrivateIpAddress: i.privateIpAddress,
|
|
1112
1121
|
PublicIpAddress: i.ipAddress,
|
|
1122
|
+
Ipv6Address: this.parseFirstIpv6Address(i.networkInterfaceSet?.item),
|
|
1113
1123
|
SubnetId: i.subnetId,
|
|
1114
1124
|
VpcId: i.vpcId,
|
|
1115
1125
|
SecurityGroups: this.parseArray(i.groupSet?.item).map((g) => ({
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
import {
|
|
13
13
|
EC2Client,
|
|
14
14
|
SSMClient
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-7m60qnc8.js";
|
|
16
16
|
import {
|
|
17
17
|
CloudFormationClient
|
|
18
18
|
} from "./chunk-4cjrg98a.js";
|
|
@@ -27,6 +27,98 @@ import {
|
|
|
27
27
|
import { readFileSync } from "node:fs";
|
|
28
28
|
import { join } from "node:path";
|
|
29
29
|
|
|
30
|
+
// src/deploy/server-dns.ts
|
|
31
|
+
function collectServerDnsDomains(sites = {}) {
|
|
32
|
+
const domains = new Set;
|
|
33
|
+
for (const site of Object.values(sites)) {
|
|
34
|
+
if (!site.domain)
|
|
35
|
+
continue;
|
|
36
|
+
if (site.redirect || site.deploy === "server" || site.start)
|
|
37
|
+
domains.add(site.domain);
|
|
38
|
+
}
|
|
39
|
+
return domains;
|
|
40
|
+
}
|
|
41
|
+
function normalizeName(name) {
|
|
42
|
+
return name.replace(/\.$/, "").toLowerCase();
|
|
43
|
+
}
|
|
44
|
+
function matchesHostname(record, zone, hostname) {
|
|
45
|
+
const recordName = normalizeName(record.name);
|
|
46
|
+
const normalizedZone = normalizeName(zone);
|
|
47
|
+
const normalizedHostname = normalizeName(hostname);
|
|
48
|
+
const relativeName = normalizedHostname === normalizedZone ? "@" : normalizedHostname.endsWith(`.${normalizedZone}`) ? normalizedHostname.slice(0, -(normalizedZone.length + 1)) : normalizedHostname;
|
|
49
|
+
return recordName === normalizedHostname || recordName === relativeName || relativeName === "@" && (recordName === "" || recordName === normalizedZone);
|
|
50
|
+
}
|
|
51
|
+
async function removeStaleServerAddressRecords(provider, zone, hostname, desiredAddress, recordType = "A") {
|
|
52
|
+
const listed = await provider.listRecords(zone);
|
|
53
|
+
if (!listed.success)
|
|
54
|
+
return [`could not list ${recordType} records: ${listed.message || "unknown provider error"}`];
|
|
55
|
+
const matching = listed.records.filter((record) => record.type === recordType && matchesHostname(record, zone, hostname));
|
|
56
|
+
const desiredIndex = matching.findIndex((record) => record.content === desiredAddress);
|
|
57
|
+
if (matching.length <= 1 || desiredIndex === -1)
|
|
58
|
+
return [];
|
|
59
|
+
const warnings = [];
|
|
60
|
+
for (const [index, record] of matching.entries()) {
|
|
61
|
+
if (index === desiredIndex)
|
|
62
|
+
continue;
|
|
63
|
+
const result = await provider.deleteRecord(zone, record);
|
|
64
|
+
if (!result.success)
|
|
65
|
+
warnings.push(`could not remove stale ${record.name} ${recordType} ${record.content}: ${result.message || "unknown provider error"}`);
|
|
66
|
+
}
|
|
67
|
+
return warnings;
|
|
68
|
+
}
|
|
69
|
+
function normalizePublicIpv6(reported) {
|
|
70
|
+
if (!reported)
|
|
71
|
+
return;
|
|
72
|
+
const trimmed = reported.trim();
|
|
73
|
+
if (!trimmed)
|
|
74
|
+
return;
|
|
75
|
+
if (!trimmed.includes("/"))
|
|
76
|
+
return trimmed;
|
|
77
|
+
const [block] = trimmed.split("/");
|
|
78
|
+
if (!block.endsWith("::"))
|
|
79
|
+
return block || undefined;
|
|
80
|
+
return `${block}1`;
|
|
81
|
+
}
|
|
82
|
+
var IPV6_EXCLUDED_HOST_LABELS = new Set(["mail", "smtp", "imap", "mx"]);
|
|
83
|
+
function hostAcceptsIpv6(fqdn) {
|
|
84
|
+
return !IPV6_EXCLUDED_HOST_LABELS.has(fqdn.split(".")[0] ?? "");
|
|
85
|
+
}
|
|
86
|
+
async function reconcileAddressRecords(options) {
|
|
87
|
+
const { provider, zone, fqdn, ipv4, ipv6, ttl = 600 } = options;
|
|
88
|
+
const report = { published: [], warnings: [] };
|
|
89
|
+
const families = [{ type: "A", content: ipv4 }];
|
|
90
|
+
if (ipv6 && hostAcceptsIpv6(fqdn))
|
|
91
|
+
families.push({ type: "AAAA", content: ipv6 });
|
|
92
|
+
for (const { type, content } of families) {
|
|
93
|
+
const result = await provider.upsertRecord(zone, { name: fqdn, type, content, ttl });
|
|
94
|
+
if (result?.success === false) {
|
|
95
|
+
report.warnings.push(`${fqdn} → ${content} failed: ${result.error || result.message || "unknown error"}`);
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
report.warnings.push(...(await removeStaleServerAddressRecords(provider, zone, fqdn, content, type)).map((warning) => `${fqdn} cleanup: ${warning}`));
|
|
99
|
+
if (await verifyAddressRecord(provider, zone, fqdn, content, type))
|
|
100
|
+
report.published.push({ fqdn, type, content });
|
|
101
|
+
else
|
|
102
|
+
report.warnings.push(`${fqdn} → ${content} reported success at ${provider.name} but no matching ${type} record exists — create it manually: ${type} ${fqdn} → ${content}`);
|
|
103
|
+
}
|
|
104
|
+
return report;
|
|
105
|
+
}
|
|
106
|
+
async function verifyAddressRecord(provider, zone, fqdn, content, recordType) {
|
|
107
|
+
try {
|
|
108
|
+
if (typeof provider?.listRecords !== "function")
|
|
109
|
+
return true;
|
|
110
|
+
const listed = await provider.listRecords(zone);
|
|
111
|
+
if (!listed?.success || !Array.isArray(listed.records))
|
|
112
|
+
return true;
|
|
113
|
+
return listed.records.some((record) => {
|
|
114
|
+
const name = typeof record?.name === "string" ? record.name.replace(/\.$/, "") : "";
|
|
115
|
+
return record?.type === recordType && name === fqdn && record?.content === content;
|
|
116
|
+
});
|
|
117
|
+
} catch {
|
|
118
|
+
return true;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
30
122
|
// src/drivers/shared/package-manager.ts
|
|
31
123
|
var PANTRY_PACKAGES = {
|
|
32
124
|
php: "php.net",
|
|
@@ -1752,6 +1844,7 @@ class AwsDriver {
|
|
|
1752
1844
|
return {
|
|
1753
1845
|
appInstanceId: first.id,
|
|
1754
1846
|
appPublicIp: first.publicIp,
|
|
1847
|
+
appPublicIpv6: first.publicIpv6,
|
|
1755
1848
|
sshUser: "ubuntu",
|
|
1756
1849
|
deployStoragePath: "/var/ts-cloud/staging"
|
|
1757
1850
|
};
|
|
@@ -1834,6 +1927,7 @@ class AwsDriver {
|
|
|
1834
1927
|
return {
|
|
1835
1928
|
appInstanceId: instanceId,
|
|
1836
1929
|
appPublicIp: running.PublicIpAddress,
|
|
1930
|
+
appPublicIpv6: normalizePublicIpv6(running.Ipv6Address),
|
|
1837
1931
|
sshUser: "ubuntu",
|
|
1838
1932
|
deployStoragePath: "/var/ts-cloud/staging"
|
|
1839
1933
|
};
|
|
@@ -1892,6 +1986,7 @@ class AwsDriver {
|
|
|
1892
1986
|
return {
|
|
1893
1987
|
appInstanceId: first?.id,
|
|
1894
1988
|
appPublicIp: first?.publicIp,
|
|
1989
|
+
appPublicIpv6: first?.publicIpv6,
|
|
1895
1990
|
sshUser: "ubuntu",
|
|
1896
1991
|
deployStoragePath: "/var/ts-cloud/staging"
|
|
1897
1992
|
};
|
|
@@ -1961,6 +2056,7 @@ class AwsDriver {
|
|
|
1961
2056
|
id: instance.InstanceId,
|
|
1962
2057
|
name: nameTag,
|
|
1963
2058
|
publicIp: instance.PublicIpAddress,
|
|
2059
|
+
publicIpv6: normalizePublicIpv6(instance.Ipv6Address),
|
|
1964
2060
|
privateIp: instance.PrivateIpAddress,
|
|
1965
2061
|
status: instance.State?.Name
|
|
1966
2062
|
});
|
|
@@ -2045,59 +2141,6 @@ import { execSync } from "node:child_process";
|
|
|
2045
2141
|
import { randomUUID } from "node:crypto";
|
|
2046
2142
|
import { existsSync, readFileSync as readFileSync2 } from "node:fs";
|
|
2047
2143
|
|
|
2048
|
-
// src/deploy/server-dns.ts
|
|
2049
|
-
function collectServerDnsDomains(sites = {}) {
|
|
2050
|
-
const domains = new Set;
|
|
2051
|
-
for (const site of Object.values(sites)) {
|
|
2052
|
-
if (!site.domain)
|
|
2053
|
-
continue;
|
|
2054
|
-
if (site.redirect || site.deploy === "server" || site.start)
|
|
2055
|
-
domains.add(site.domain);
|
|
2056
|
-
}
|
|
2057
|
-
return domains;
|
|
2058
|
-
}
|
|
2059
|
-
function normalizeName(name) {
|
|
2060
|
-
return name.replace(/\.$/, "").toLowerCase();
|
|
2061
|
-
}
|
|
2062
|
-
function matchesHostname(record, zone, hostname) {
|
|
2063
|
-
const recordName = normalizeName(record.name);
|
|
2064
|
-
const normalizedZone = normalizeName(zone);
|
|
2065
|
-
const normalizedHostname = normalizeName(hostname);
|
|
2066
|
-
const relativeName = normalizedHostname === normalizedZone ? "@" : normalizedHostname.endsWith(`.${normalizedZone}`) ? normalizedHostname.slice(0, -(normalizedZone.length + 1)) : normalizedHostname;
|
|
2067
|
-
return recordName === normalizedHostname || recordName === relativeName || relativeName === "@" && (recordName === "" || recordName === normalizedZone);
|
|
2068
|
-
}
|
|
2069
|
-
async function removeStaleServerAddressRecords(provider, zone, hostname, desiredAddress, recordType = "A") {
|
|
2070
|
-
const listed = await provider.listRecords(zone);
|
|
2071
|
-
if (!listed.success)
|
|
2072
|
-
return [`could not list ${recordType} records: ${listed.message || "unknown provider error"}`];
|
|
2073
|
-
const matching = listed.records.filter((record) => record.type === recordType && matchesHostname(record, zone, hostname));
|
|
2074
|
-
const desiredIndex = matching.findIndex((record) => record.content === desiredAddress);
|
|
2075
|
-
if (matching.length <= 1 || desiredIndex === -1)
|
|
2076
|
-
return [];
|
|
2077
|
-
const warnings = [];
|
|
2078
|
-
for (const [index, record] of matching.entries()) {
|
|
2079
|
-
if (index === desiredIndex)
|
|
2080
|
-
continue;
|
|
2081
|
-
const result = await provider.deleteRecord(zone, record);
|
|
2082
|
-
if (!result.success)
|
|
2083
|
-
warnings.push(`could not remove stale ${record.name} ${recordType} ${record.content}: ${result.message || "unknown provider error"}`);
|
|
2084
|
-
}
|
|
2085
|
-
return warnings;
|
|
2086
|
-
}
|
|
2087
|
-
function hetznerBoxIpv6(reported) {
|
|
2088
|
-
if (!reported)
|
|
2089
|
-
return;
|
|
2090
|
-
const trimmed = reported.trim();
|
|
2091
|
-
if (!trimmed)
|
|
2092
|
-
return;
|
|
2093
|
-
if (!trimmed.includes("/"))
|
|
2094
|
-
return trimmed;
|
|
2095
|
-
const [block] = trimmed.split("/");
|
|
2096
|
-
if (!block.endsWith("::"))
|
|
2097
|
-
return block || undefined;
|
|
2098
|
-
return `${block}1`;
|
|
2099
|
-
}
|
|
2100
|
-
|
|
2101
2144
|
// src/drivers/shared/fleet.ts
|
|
2102
2145
|
function resolveFleetTopology(compute = {}) {
|
|
2103
2146
|
const appServers = Math.max(1, compute.appServers ?? compute.instances ?? 1);
|
|
@@ -2666,7 +2709,7 @@ class HetznerDriver {
|
|
|
2666
2709
|
serverId: alreadyRunning.id,
|
|
2667
2710
|
serverName: alreadyRunning.name,
|
|
2668
2711
|
publicIp: alreadyRunning.public_net.ipv4?.ip,
|
|
2669
|
-
publicIpv6:
|
|
2712
|
+
publicIpv6: normalizePublicIpv6(alreadyRunning.public_net.ipv6?.ip),
|
|
2670
2713
|
deployStoragePath: "/var/ts-cloud/staging",
|
|
2671
2714
|
sshUser: this.sshUser
|
|
2672
2715
|
};
|
|
@@ -2714,7 +2757,7 @@ class HetznerDriver {
|
|
|
2714
2757
|
serverName: running.name,
|
|
2715
2758
|
firewallId: firewall.id,
|
|
2716
2759
|
publicIp: running.public_net.ipv4?.ip,
|
|
2717
|
-
publicIpv6:
|
|
2760
|
+
publicIpv6: normalizePublicIpv6(running.public_net.ipv6?.ip),
|
|
2718
2761
|
deployStoragePath: "/var/ts-cloud/staging",
|
|
2719
2762
|
sshUser: this.sshUser
|
|
2720
2763
|
};
|
|
@@ -3216,6 +3259,7 @@ class HetznerDriver {
|
|
|
3216
3259
|
id: String(server.id),
|
|
3217
3260
|
name: server.name,
|
|
3218
3261
|
publicIp: server.public_net.ipv4?.ip,
|
|
3262
|
+
publicIpv6: normalizePublicIpv6(server.public_net.ipv6?.ip),
|
|
3219
3263
|
privateIp: server.private_net?.[0]?.ip,
|
|
3220
3264
|
status: server.status
|
|
3221
3265
|
});
|
|
@@ -3428,7 +3472,7 @@ ${out}`);
|
|
|
3428
3472
|
deployStoragePath: state.deployStoragePath || "/var/ts-cloud/staging",
|
|
3429
3473
|
appInstanceId: state.serverId ? String(state.serverId) : undefined,
|
|
3430
3474
|
appPublicIp: server?.public_net.ipv4?.ip || state.publicIp,
|
|
3431
|
-
appPublicIpv6:
|
|
3475
|
+
appPublicIpv6: normalizePublicIpv6(server?.public_net.ipv6?.ip) || state.publicIpv6,
|
|
3432
3476
|
sshUser: state.sshUser || this.sshUser,
|
|
3433
3477
|
servicesPrivateIp: state.servicesPrivateIp
|
|
3434
3478
|
};
|
|
@@ -6254,4 +6298,4 @@ function buildCloudFrontOriginConfig(options) {
|
|
|
6254
6298
|
CustomErrorResponses: { Quantity: 0 }
|
|
6255
6299
|
};
|
|
6256
6300
|
}
|
|
6257
|
-
export { PANTRY_PROJECT_DIR, 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,
|
|
6301
|
+
export { collectServerDnsDomains, removeStaleServerAddressRecords, normalizePublicIpv6, IPV6_EXCLUDED_HOST_LABELS, hostAcceptsIpv6, reconcileAddressRecords, verifyAddressRecord, PANTRY_PROJECT_DIR, 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 };
|
package/dist/deploy/index.js
CHANGED
|
@@ -30,7 +30,7 @@ import {
|
|
|
30
30
|
synchronizeDashboardUsers,
|
|
31
31
|
trackDashboardOperation,
|
|
32
32
|
verifyStaticApiOrigin
|
|
33
|
-
} from "../chunk-
|
|
33
|
+
} from "../chunk-4erbrg3e.js";
|
|
34
34
|
import {
|
|
35
35
|
deleteStaticSite,
|
|
36
36
|
deployStaticSite,
|
|
@@ -51,13 +51,16 @@ import"../chunk-50jpda9q.js";
|
|
|
51
51
|
import"../chunk-he9a874b.js";
|
|
52
52
|
import"../chunk-gttvakpv.js";
|
|
53
53
|
import {
|
|
54
|
+
IPV6_EXCLUDED_HOST_LABELS,
|
|
54
55
|
MANAGEMENT_DASHBOARD_SITE,
|
|
55
56
|
buildManagementDashboardArtifact,
|
|
56
57
|
collectServerDnsDomains,
|
|
57
58
|
dashboardCredentialsFile,
|
|
58
59
|
ensureManagementDashboard,
|
|
59
|
-
|
|
60
|
+
hostAcceptsIpv6,
|
|
60
61
|
isPhpSite,
|
|
62
|
+
normalizePublicIpv6,
|
|
63
|
+
reconcileAddressRecords,
|
|
61
64
|
removeStaleServerAddressRecords,
|
|
62
65
|
resolveDashboardAuth,
|
|
63
66
|
resolveSiteDeployTarget,
|
|
@@ -65,10 +68,11 @@ import {
|
|
|
65
68
|
resolveUiSource,
|
|
66
69
|
shipsARelease,
|
|
67
70
|
siteInstallBase,
|
|
68
|
-
validateDeploymentConfig
|
|
69
|
-
|
|
71
|
+
validateDeploymentConfig,
|
|
72
|
+
verifyAddressRecord
|
|
73
|
+
} from "../chunk-ztbn47we.js";
|
|
70
74
|
import"../chunk-1qjyqrc5.js";
|
|
71
|
-
import"../chunk-
|
|
75
|
+
import"../chunk-7m60qnc8.js";
|
|
72
76
|
import"../chunk-4cjrg98a.js";
|
|
73
77
|
import"../chunk-hpv68b4a.js";
|
|
74
78
|
import"../chunk-32e7ya18.js";
|
|
@@ -77,6 +81,7 @@ import"../chunk-zqtpg06c.js";
|
|
|
77
81
|
import"../chunk-v0bahtg2.js";
|
|
78
82
|
export {
|
|
79
83
|
verifyStaticApiOrigin,
|
|
84
|
+
verifyAddressRecord,
|
|
80
85
|
validateDeploymentConfig,
|
|
81
86
|
uploadStaticFiles,
|
|
82
87
|
trackDashboardOperation,
|
|
@@ -98,11 +103,13 @@ export {
|
|
|
98
103
|
resolveDashboardAction,
|
|
99
104
|
removeStaleServerAddressRecords,
|
|
100
105
|
redeployServerlessApp,
|
|
106
|
+
reconcileAddressRecords,
|
|
107
|
+
normalizePublicIpv6,
|
|
101
108
|
isPhpSite,
|
|
102
109
|
invalidateCache,
|
|
103
110
|
initializeDashboardControlPlane,
|
|
104
111
|
infraEnvFromOutputs,
|
|
105
|
-
|
|
112
|
+
hostAcceptsIpv6,
|
|
106
113
|
hashContainerContext,
|
|
107
114
|
generateStaticSiteTemplate,
|
|
108
115
|
generateExternalDnsStaticSiteTemplate,
|
|
@@ -131,5 +138,6 @@ export {
|
|
|
131
138
|
buildFunctionEnv,
|
|
132
139
|
buildAndPushServerlessImage,
|
|
133
140
|
buildAndPushContainerImage,
|
|
134
|
-
MANAGEMENT_DASHBOARD_SITE
|
|
141
|
+
MANAGEMENT_DASHBOARD_SITE,
|
|
142
|
+
IPV6_EXCLUDED_HOST_LABELS
|
|
135
143
|
};
|
|
@@ -19,13 +19,72 @@ export declare function collectServerDnsDomains(sites?: Record<string, ServerSit
|
|
|
19
19
|
*/
|
|
20
20
|
export declare function removeStaleServerAddressRecords(provider: DnsProvider, zone: string, hostname: string, desiredAddress: string, recordType?: 'A' | 'AAAA'): Promise<string[]>;
|
|
21
21
|
/**
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
* the address. Publishing the block verbatim as an AAAA record yields a host
|
|
25
|
-
* nothing answers on, so turn it into the address the box actually holds.
|
|
22
|
+
* Turn whatever a provider reports as a box's IPv6 into an address an AAAA
|
|
23
|
+
* record can point at.
|
|
26
24
|
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
25
|
+
* Providers disagree on what "the server's IPv6" means. Hetzner hands out a
|
|
26
|
+
* routed /64 and reports the block (`2a01:4f8:c014:6186::/64`) while the
|
|
27
|
+
* interface actually holds `::1` inside it; AWS reports a plain address per
|
|
28
|
+
* network interface. Publishing a block verbatim gives an AAAA record nothing
|
|
29
|
+
* answers on, which is the kind of failure that only shows up for the fraction
|
|
30
|
+
* of visitors whose network prefers IPv6 — so every driver runs its value
|
|
31
|
+
* through here rather than reinventing the narrowing.
|
|
32
|
+
*
|
|
33
|
+
* A plain address passes through unchanged.
|
|
34
|
+
*/
|
|
35
|
+
export declare function normalizePublicIpv6(reported: string | undefined | null): string | undefined;
|
|
36
|
+
/**
|
|
37
|
+
* Hostname labels that must stay IPv4-only.
|
|
38
|
+
*
|
|
39
|
+
* A box typically runs its mail server on IPv4 alone, and its IPv6 address
|
|
40
|
+
* usually has no PTR — both of which make an AAAA on a mail host actively
|
|
41
|
+
* harmful: senders try the v6 address first, find nothing listening (or get
|
|
42
|
+
* rejected for the missing reverse record) and defer the message. Web traffic
|
|
43
|
+
* has no such constraint, so the exclusion is per-host rather than per-zone.
|
|
44
|
+
*/
|
|
45
|
+
export declare const IPV6_EXCLUDED_HOST_LABELS: ReadonlySet<string>;
|
|
46
|
+
/** Whether `fqdn` should get an AAAA record pointing at the box. */
|
|
47
|
+
export declare function hostAcceptsIpv6(fqdn: string): boolean;
|
|
48
|
+
export interface AddressRecordReport {
|
|
49
|
+
/** Records confirmed present at the provider after the write. */
|
|
50
|
+
published: Array<{
|
|
51
|
+
fqdn: string;
|
|
52
|
+
type: 'A' | 'AAAA';
|
|
53
|
+
content: string;
|
|
54
|
+
}>;
|
|
55
|
+
/** Anything the caller should surface: failed writes, unverified writes, stale-record cleanup problems. */
|
|
56
|
+
warnings: string[];
|
|
57
|
+
}
|
|
58
|
+
interface ReconcileAddressRecordsOptions {
|
|
59
|
+
provider: DnsProvider;
|
|
60
|
+
zone: string;
|
|
61
|
+
fqdn: string;
|
|
62
|
+
ipv4: string;
|
|
63
|
+
/** Omit when the box has no public IPv6; the AAAA pass is then skipped entirely. */
|
|
64
|
+
ipv6?: string;
|
|
65
|
+
ttl?: number;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Point one hostname at a box on every address family the box actually has.
|
|
69
|
+
*
|
|
70
|
+
* Shared by every driver and by the framework's deploy command so the rules
|
|
71
|
+
* live in one place: upsert, then remove the *other* records of that family for
|
|
72
|
+
* the same hostname (a leftover address round-robins traffic to a dead host —
|
|
73
|
+
* and a stale AAAA is the worse of the two, because dual-stack clients prefer
|
|
74
|
+
* IPv6), then verify against the provider rather than trusting the write.
|
|
75
|
+
*/
|
|
76
|
+
export declare function reconcileAddressRecords(options: ReconcileAddressRecordsOptions): Promise<AddressRecordReport>;
|
|
77
|
+
/**
|
|
78
|
+
* Best-effort post-write check that the record exists at the provider.
|
|
79
|
+
*
|
|
80
|
+
* Returns true when the provider offers no list API or the listing itself
|
|
81
|
+
* fails: verification must never turn a possibly-good write into a false
|
|
82
|
+
* alarm. It exists to catch phantom successes — an upsert that reported OK
|
|
83
|
+
* while editing the wrong record — at providers that can list their zone.
|
|
84
|
+
*
|
|
85
|
+
* The listing is deliberately untyped. Typed listings map to endpoints like
|
|
86
|
+
* Porkbun's retrieveByNameType, whose subdomain-less form returns apex records
|
|
87
|
+
* only, which made verification blind to every non-apex record.
|
|
29
88
|
*/
|
|
30
|
-
export declare function
|
|
89
|
+
export declare function verifyAddressRecord(provider: DnsProvider, zone: string, fqdn: string, content: string, recordType: 'A' | 'AAAA'): Promise<boolean>;
|
|
31
90
|
export {};
|
package/dist/drivers/index.js
CHANGED
|
@@ -68,9 +68,9 @@ import {
|
|
|
68
68
|
waitForSsh,
|
|
69
69
|
wrapCloudInitUserData,
|
|
70
70
|
writeResizeCheckpoint
|
|
71
|
-
} from "../chunk-
|
|
71
|
+
} from "../chunk-ztbn47we.js";
|
|
72
72
|
import"../chunk-1qjyqrc5.js";
|
|
73
|
-
import"../chunk-
|
|
73
|
+
import"../chunk-7m60qnc8.js";
|
|
74
74
|
import"../chunk-4cjrg98a.js";
|
|
75
75
|
import"../chunk-wj3s95p9.js";
|
|
76
76
|
import"../chunk-zqtpg06c.js";
|
package/dist/index.d.ts
CHANGED
|
@@ -30,7 +30,8 @@ export { keyMatchesFilters, migrateObjectStorage, remapKey } from './object-stor
|
|
|
30
30
|
export type { MigrateEndpoint, MigrateError, MigrateOptions, MigratePlanItem, MigrateProgress, MigrateResult, MigrateVerification, } from './object-storage/migrate';
|
|
31
31
|
export * from './ssl';
|
|
32
32
|
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';
|
|
33
|
-
export { collectServerDnsDomains,
|
|
33
|
+
export { collectServerDnsDomains, hostAcceptsIpv6, IPV6_EXCLUDED_HOST_LABELS, normalizePublicIpv6, reconcileAddressRecords, removeStaleServerAddressRecords, verifyAddressRecord, } from './deploy/server-dns';
|
|
34
|
+
export type { AddressRecordReport } from './deploy/server-dns';
|
|
34
35
|
export type { EnsureDashboardLogger, ResolvedDashboardAuth, StaticSiteConfig, DeployResult, UploadOptions, ExternalDnsStaticSiteConfig, ExternalDnsDeployResult, DeploySiteConfig, DeploySiteResult, StaticSiteDnsProvider, SiteDeployKind, DeploymentValidationResult, BuildImageOptions, BuiltImage, CodeSource, DeployServerlessOptions, ResolvedContext, } from './deploy';
|
|
35
36
|
export { createCloudDriver, CloudDriverFactory, cloudDrivers, AwsDriver, HetznerDriver, HetznerClient, resolveHetznerApiToken, normalizeSshPublicKey, ensureFirewall, ensureServer, ensureSshKey, serverPublicIpv4, sshExec, sshExecOrThrow, scpUpload, waitForSsh, waitForCloudInit, buildSshArgs, generateUbuntuAppCloudInit, wrapCloudInitUserData, buildHostCleanupScript, buildSiteDeployScript, buildStaticSiteDeployScript, resolveExecStart, deployAllComputeSites, deploySiteRelease, } from './drivers';
|
|
36
37
|
export type { CreateCloudDriverOptions } from './drivers/factory';
|
package/dist/index.js
CHANGED
|
@@ -283,7 +283,7 @@ import {
|
|
|
283
283
|
volumeCapabilities,
|
|
284
284
|
webhookEndpoint,
|
|
285
285
|
zeroCapacity
|
|
286
|
-
} from "./chunk-
|
|
286
|
+
} from "./chunk-4erbrg3e.js";
|
|
287
287
|
import {
|
|
288
288
|
deleteStaticSite,
|
|
289
289
|
deployStaticSite,
|
|
@@ -365,6 +365,7 @@ import {
|
|
|
365
365
|
CloudDriverFactory,
|
|
366
366
|
HetznerClient,
|
|
367
367
|
HetznerDriver,
|
|
368
|
+
IPV6_EXCLUDED_HOST_LABELS,
|
|
368
369
|
MANAGEMENT_DASHBOARD_SITE,
|
|
369
370
|
buildHostCleanupScript,
|
|
370
371
|
buildManagementDashboardArtifact,
|
|
@@ -382,8 +383,10 @@ import {
|
|
|
382
383
|
ensureManagementDashboard,
|
|
383
384
|
ensureServer,
|
|
384
385
|
ensureSshKey,
|
|
385
|
-
|
|
386
|
+
hostAcceptsIpv6,
|
|
387
|
+
normalizePublicIpv6,
|
|
386
388
|
normalizeSshPublicKey,
|
|
389
|
+
reconcileAddressRecords,
|
|
387
390
|
removeStaleServerAddressRecords,
|
|
388
391
|
resolveDashboardAuth,
|
|
389
392
|
resolveExecStart,
|
|
@@ -396,10 +399,11 @@ import {
|
|
|
396
399
|
sshExec,
|
|
397
400
|
sshExecOrThrow,
|
|
398
401
|
validateDeploymentConfig,
|
|
402
|
+
verifyAddressRecord,
|
|
399
403
|
waitForCloudInit,
|
|
400
404
|
waitForSsh,
|
|
401
405
|
wrapCloudInitUserData
|
|
402
|
-
} from "./chunk-
|
|
406
|
+
} from "./chunk-ztbn47we.js";
|
|
403
407
|
import {
|
|
404
408
|
ABTestManager,
|
|
405
409
|
AI,
|
|
@@ -817,7 +821,7 @@ import {
|
|
|
817
821
|
import {
|
|
818
822
|
EC2Client,
|
|
819
823
|
SSMClient
|
|
820
|
-
} from "./chunk-
|
|
824
|
+
} from "./chunk-7m60qnc8.js";
|
|
821
825
|
import {
|
|
822
826
|
CloudFormationClient
|
|
823
827
|
} from "./chunk-4cjrg98a.js";
|
|
@@ -5125,6 +5129,7 @@ export {
|
|
|
5125
5129
|
verifyTotp,
|
|
5126
5130
|
verifyMediaAccessToken,
|
|
5127
5131
|
verifyArtifactSignature,
|
|
5132
|
+
verifyAddressRecord,
|
|
5128
5133
|
validateTemplateSize,
|
|
5129
5134
|
validateTemplate,
|
|
5130
5135
|
validateResourceLimits,
|
|
@@ -5266,6 +5271,7 @@ export {
|
|
|
5266
5271
|
recordDashboardHostPosture,
|
|
5267
5272
|
reconcileSourceWebhook,
|
|
5268
5273
|
reconcileJobObservation,
|
|
5274
|
+
reconcileAddressRecords,
|
|
5269
5275
|
quickHash,
|
|
5270
5276
|
queueManagementManager,
|
|
5271
5277
|
publicKeyFingerprint,
|
|
@@ -5302,6 +5308,7 @@ export {
|
|
|
5302
5308
|
normalizeSourceEvent,
|
|
5303
5309
|
normalizeScheduleExpression,
|
|
5304
5310
|
normalizeRuntimeStatus,
|
|
5311
|
+
normalizePublicIpv6,
|
|
5305
5312
|
nextScheduleRuns,
|
|
5306
5313
|
networkSecurityManager,
|
|
5307
5314
|
needsRenewal,
|
|
@@ -5346,7 +5353,7 @@ export {
|
|
|
5346
5353
|
infraEnvFromOutputs,
|
|
5347
5354
|
imageScanningManager,
|
|
5348
5355
|
hotp,
|
|
5349
|
-
|
|
5356
|
+
hostAcceptsIpv6,
|
|
5350
5357
|
healthCheckManager,
|
|
5351
5358
|
hashString,
|
|
5352
5359
|
hashManifest,
|
|
@@ -5775,6 +5782,7 @@ export {
|
|
|
5775
5782
|
InvalidOperationTransitionError,
|
|
5776
5783
|
InfrastructureGenerator,
|
|
5777
5784
|
ImageScanningManager,
|
|
5785
|
+
IPV6_EXCLUDED_HOST_LABELS,
|
|
5778
5786
|
IAMClient,
|
|
5779
5787
|
HetznerDriver,
|
|
5780
5788
|
HetznerClient,
|