@stacksjs/buddy 0.70.222 → 0.70.223
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 +12 -0
- package/dist/commands/deploy.js +26 -5
- package/package.json +2 -2
|
@@ -76,6 +76,12 @@ export declare function loadTsCloudDeployApi(): Promise<typeof import('@stacksjs
|
|
|
76
76
|
* port declaration is left alone.
|
|
77
77
|
*/
|
|
78
78
|
export declare function shouldInjectManagementDashboard(tsCloudConfig: any): boolean;
|
|
79
|
+
/**
|
|
80
|
+
* Read a tenant's existing shared-server pin without requiring provider API
|
|
81
|
+
* credentials. The pin contains only compute metadata and is sufficient for
|
|
82
|
+
* an SSH release to a box that the owner project already provisioned.
|
|
83
|
+
*/
|
|
84
|
+
export declare function resolvePersistedAttachTargetBox(tsCloudConfig: any, environment: string, cwd?: unknown): AttachedComputeBox | null;
|
|
79
85
|
export declare function scrubLoopbackSitePortsForFirewall(tsCloudConfig: any): any;
|
|
80
86
|
/**
|
|
81
87
|
* Mail tenancy is an explicit deployment capability. The merged Stacks config
|
|
@@ -141,6 +147,12 @@ declare const log: {
|
|
|
141
147
|
error: (...args: any[]) => unknown;
|
|
142
148
|
debug: (...args: any[]) => void
|
|
143
149
|
};
|
|
150
|
+
declare interface AttachedComputeBox {
|
|
151
|
+
serverId: number
|
|
152
|
+
serverName: string
|
|
153
|
+
publicIp: string
|
|
154
|
+
publicIpv6?: string
|
|
155
|
+
}
|
|
144
156
|
/** What a mail-tenant reconcile resolved + provisioned, for the DNS step. */
|
|
145
157
|
export declare interface MailTenantResult {
|
|
146
158
|
domain: string
|
package/dist/commands/deploy.js
CHANGED
|
@@ -534,8 +534,8 @@ export function applyEnvironmentToSites(sites, environment, config) {
|
|
|
534
534
|
return out;
|
|
535
535
|
}
|
|
536
536
|
async function deployToHetzner(tsCloudConfig, deployEnv, options) {
|
|
537
|
-
const verbose = options.verbose === !0, environment = deployEnv === "prod" ? "production" : deployEnv;
|
|
538
|
-
if (!
|
|
537
|
+
const verbose = options.verbose === !0, environment = deployEnv === "prod" ? "production" : deployEnv, apiToken = tsCloudConfig.hetzner?.apiToken || process.env.HCLOUD_TOKEN || process.env.HETZNER_API_TOKEN, persistedAttachBox = resolvePersistedAttachTargetBox(tsCloudConfig, environment);
|
|
538
|
+
if (!apiToken && !persistedAttachBox) {
|
|
539
539
|
log.error("No Hetzner API token found. Set HCLOUD_TOKEN in your .env (or hetzner.apiToken in config/cloud.ts).");
|
|
540
540
|
process.exit(ExitCode.FatalError);
|
|
541
541
|
}
|
|
@@ -548,7 +548,7 @@ async function deployToHetzner(tsCloudConfig, deployEnv, options) {
|
|
|
548
548
|
}
|
|
549
549
|
const { createCloudDriver, deployAllComputeSites, ensureManagementDashboard, resolveSiteKind } = await loadTsCloudDeployApi();
|
|
550
550
|
try {
|
|
551
|
-
await runHetznerDeploy({ tsCloudConfig, environment, verbose, docker: options.docker === !0, createCloudDriver, deployAllComputeSites, ensureManagementDashboard, resolveSiteKind, onlySite: options.site || void 0 });
|
|
551
|
+
await runHetznerDeploy({ tsCloudConfig, environment, verbose, docker: options.docker === !0, createCloudDriver, deployAllComputeSites, ensureManagementDashboard, resolveSiteKind, onlySite: options.site || void 0, persistedAttachBox });
|
|
552
552
|
} catch (err) {
|
|
553
553
|
log.error("Hetzner deploy failed:");
|
|
554
554
|
console.error(err instanceof Error ? err.stack || err.message : err);
|
|
@@ -567,6 +567,27 @@ export async function loadTsCloudDeployApi() {
|
|
|
567
567
|
export function shouldInjectManagementDashboard(tsCloudConfig) {
|
|
568
568
|
return !tsCloudConfig.cloud?.attachTo;
|
|
569
569
|
}
|
|
570
|
+
export function resolvePersistedAttachTargetBox(tsCloudConfig, environment, cwd = process.cwd()) {
|
|
571
|
+
const owner = tsCloudConfig.cloud?.attachTo;
|
|
572
|
+
if (!owner)
|
|
573
|
+
return null;
|
|
574
|
+
const stackName = tsCloudConfig.project?.stackName || `${tsCloudConfig.project?.slug || "app"}-${environment}`, statePath = join(cwd, "storage", "cloud", "state", `${stackName}.json`);
|
|
575
|
+
if (!existsSync(statePath))
|
|
576
|
+
return null;
|
|
577
|
+
try {
|
|
578
|
+
const state = JSON.parse(readFileSync(statePath, "utf8"));
|
|
579
|
+
if (state.stackName !== stackName || typeof state.serverId !== "number" || typeof state.publicIp !== "string" || !state.publicIp.trim())
|
|
580
|
+
return null;
|
|
581
|
+
return {
|
|
582
|
+
serverId: state.serverId,
|
|
583
|
+
serverName: typeof state.serverName === "string" && state.serverName ? state.serverName : `${owner}-${environment}-app`,
|
|
584
|
+
publicIp: state.publicIp,
|
|
585
|
+
publicIpv6: typeof state.publicIpv6 === "string" ? state.publicIpv6 : void 0
|
|
586
|
+
};
|
|
587
|
+
} catch {
|
|
588
|
+
return null;
|
|
589
|
+
}
|
|
590
|
+
}
|
|
570
591
|
export function scrubLoopbackSitePortsForFirewall(tsCloudConfig) {
|
|
571
592
|
const sites = tsCloudConfig?.sites;
|
|
572
593
|
if (!sites)
|
|
@@ -665,7 +686,7 @@ async function startGithubDeployments(args) {
|
|
|
665
686
|
return records;
|
|
666
687
|
}
|
|
667
688
|
async function runHetznerDeploy(args) {
|
|
668
|
-
const { tsCloudConfig, environment, verbose, docker, createCloudDriver, deployAllComputeSites, ensureManagementDashboard, resolveSiteKind, onlySite } = args, startTime = performance.now();
|
|
689
|
+
const { tsCloudConfig, environment, verbose, docker, createCloudDriver, deployAllComputeSites, ensureManagementDashboard, resolveSiteKind, onlySite, persistedAttachBox } = args, startTime = performance.now();
|
|
669
690
|
console.log("");
|
|
670
691
|
console.log("\uD83D\uDE80 Deploy \u2192 Hetzner Cloud");
|
|
671
692
|
console.log("");
|
|
@@ -692,7 +713,7 @@ async function runHetznerDeploy(args) {
|
|
|
692
713
|
const attachTo = tsCloudConfig.cloud?.attachTo;
|
|
693
714
|
let ip, ipv6;
|
|
694
715
|
if (attachTo) {
|
|
695
|
-
const box = await resolveAttachTargetBox(attachTo, environment);
|
|
716
|
+
const box = persistedAttachBox ?? await resolveAttachTargetBox(attachTo, environment);
|
|
696
717
|
if (!box?.publicIp) {
|
|
697
718
|
log.error(`Attach target '${attachTo}' has no reachable box for '${environment}'. Is '${attachTo}-${environment}-app' provisioned (by its owner)?`);
|
|
698
719
|
process.exit(ExitCode.FatalError);
|
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.223",
|
|
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.91",
|
|
141
141
|
"ajv": "^8.20.0",
|
|
142
142
|
"ajv-formats": "^3.0.1",
|
|
143
143
|
"ts-pantry": "^0.11.0"
|