@stacksjs/buddy 0.70.197 → 0.70.199
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/commands/deploy.d.ts +1 -0
- package/dist/commands/deploy.js +44 -2
- package/package.json +2 -2
|
@@ -84,6 +84,7 @@ export declare function scrubLoopbackSitePortsForFirewall(tsCloudConfig: any): a
|
|
|
84
84
|
* does not provide `config/email.ts`.
|
|
85
85
|
*/
|
|
86
86
|
export declare function hasExplicitEmailConfig(projectRoot?: unknown): boolean;
|
|
87
|
+
export declare function mailServerOwnerFromConfig(config: any): string | undefined;
|
|
87
88
|
/**
|
|
88
89
|
* Everything is MERGE-based so a shared mail server keeps every other tenant's
|
|
89
90
|
* domains, keys, users, and forward rules untouched. Best-effort — a hiccup is
|
package/dist/commands/deploy.js
CHANGED
|
@@ -819,9 +819,23 @@ async function runHetznerDeploy(args) {
|
|
|
819
819
|
if (ok)
|
|
820
820
|
await reconcileConfigDns(onlySite ? { [onlySite]: sites[onlySite] } : sites, log);
|
|
821
821
|
if (ok) {
|
|
822
|
-
const
|
|
822
|
+
const mailOwner = mailServerOwnerFromConfig(emailConfig);
|
|
823
|
+
let mailIp = ip;
|
|
824
|
+
if (mailOwner) {
|
|
825
|
+
const mailBox = await resolveAttachTargetBox(mailOwner, environment);
|
|
826
|
+
if (mailBox?.publicIp) {
|
|
827
|
+
mailIp = mailBox.publicIp;
|
|
828
|
+
log.info(`Mail: reconciling on '${mailOwner}' box '${mailBox.serverName}' (${mailIp})`);
|
|
829
|
+
} else {
|
|
830
|
+
mailIp = void 0;
|
|
831
|
+
log.warn(`Mail: attach target '${mailOwner}' has no reachable '${environment}' box; application deploy remains live`);
|
|
832
|
+
}
|
|
833
|
+
}
|
|
834
|
+
const mailRes = mailIp ? await provisionMailTenant(mailIp, log) : null;
|
|
835
|
+
if (mailOwner && mailIp && mailIp !== ip)
|
|
836
|
+
await cleanupDetachedMailHealth(ip, log);
|
|
823
837
|
if (mailRes)
|
|
824
|
-
await reconcileMailDns(mailRes,
|
|
838
|
+
await reconcileMailDns(mailRes, mailIp, log);
|
|
825
839
|
}
|
|
826
840
|
for (const record of githubDeployments)
|
|
827
841
|
await setGithubDeploymentStatus(record, ok ? "success" : "failure");
|
|
@@ -861,6 +875,34 @@ function resolveMailboxes(mailboxes, domain) {
|
|
|
861
875
|
export function hasExplicitEmailConfig(projectRoot = p.projectPath()) {
|
|
862
876
|
return existsSync(join(projectRoot, "config", "email.ts"));
|
|
863
877
|
}
|
|
878
|
+
export function mailServerOwnerFromConfig(config) {
|
|
879
|
+
const owner = config?.server?.attachTo;
|
|
880
|
+
return typeof owner === "string" && owner.trim() ? owner.trim() : void 0;
|
|
881
|
+
}
|
|
882
|
+
async function cleanupDetachedMailHealth(ip, logger) {
|
|
883
|
+
const { execSync } = await import("node:child_process"), sshArgs = ["-o", "StrictHostKeyChecking=accept-new", "-o", "BatchMode=yes", "-o", "ConnectTimeout=20", `root@${ip}`], script = `set -e
|
|
884
|
+
if systemctl list-unit-files --type=service --no-legend | awk '{print $1}' | grep -qx mail.service; then
|
|
885
|
+
exit 0
|
|
886
|
+
fi
|
|
887
|
+
systemctl disable --now mail-health.timer >/dev/null 2>&1 || true
|
|
888
|
+
systemctl stop mail-health.service >/dev/null 2>&1 || true
|
|
889
|
+
systemctl reset-failed mail-health.service >/dev/null 2>&1 || true
|
|
890
|
+
rm -f /etc/systemd/system/mail-health.service /etc/systemd/system/mail-health.timer
|
|
891
|
+
rm -f /usr/local/sbin/mail-health-check /etc/systemd/system/mail.service.d/reliability.conf
|
|
892
|
+
rmdir /etc/systemd/system/mail.service.d 2>/dev/null || true
|
|
893
|
+
systemctl daemon-reload
|
|
894
|
+
systemctl reset-failed`;
|
|
895
|
+
try {
|
|
896
|
+
execSync(`ssh ${sshArgs.map((a) => `'${a}'`).join(" ")} bash -s`, {
|
|
897
|
+
input: script,
|
|
898
|
+
encoding: "utf8",
|
|
899
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
900
|
+
});
|
|
901
|
+
logger.success("Mail: removed the detached health timer from the application box");
|
|
902
|
+
} catch (err) {
|
|
903
|
+
logger.warn(`Mail: could not remove the detached health timer: ${getErrorMessage(err)}`);
|
|
904
|
+
}
|
|
905
|
+
}
|
|
864
906
|
async function resolveAttachTargetBox(owner, environment) {
|
|
865
907
|
const token = process.env.HCLOUD_TOKEN;
|
|
866
908
|
if (!token)
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@stacksjs/buddy",
|
|
3
3
|
"type": "module",
|
|
4
4
|
"sideEffects": false,
|
|
5
|
-
"version": "0.70.
|
|
5
|
+
"version": "0.70.199",
|
|
6
6
|
"description": "Meet Buddy. The Stacks runtime.",
|
|
7
7
|
"author": "Chris Breuer",
|
|
8
8
|
"contributors": [
|
|
@@ -137,7 +137,7 @@
|
|
|
137
137
|
"@stacksjs/ui": "^0.70.180",
|
|
138
138
|
"@stacksjs/utils": "^0.70.180",
|
|
139
139
|
"@stacksjs/validation": "^0.70.180",
|
|
140
|
-
"@stacksjs/ts-cloud": "^0.7.
|
|
140
|
+
"@stacksjs/ts-cloud": "^0.7.82",
|
|
141
141
|
"ajv": "^8.20.0",
|
|
142
142
|
"ajv-formats": "^3.0.1"
|
|
143
143
|
},
|