@stacksjs/ts-cloud 0.7.49 → 0.7.51
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 +444 -444
- package/dist/{chunk-kshwaj48.js → chunk-b17vf1g1.js} +1 -1
- package/dist/{chunk-9359j1an.js → chunk-d5vqwj8s.js} +78 -4
- package/dist/deploy/index.js +2 -2
- package/dist/drivers/hetzner/driver.d.ts +8 -0
- package/dist/drivers/index.d.ts +1 -1
- package/dist/drivers/index.js +3 -1
- package/dist/drivers/shared/compute-deploy.d.ts +7 -0
- package/dist/drivers/shared/rpx-gateway.d.ts +1 -0
- package/dist/index.js +2 -2
- package/dist/ui/index.html +3 -3
- package/dist/ui/server/actions.html +3 -3
- package/dist/ui/server/backups.html +3 -3
- package/dist/ui/server/database.html +3 -3
- package/dist/ui/server/deployments.html +3 -3
- package/dist/ui/server/firewall.html +3 -3
- package/dist/ui/server/logs.html +3 -3
- package/dist/ui/server/services.html +3 -3
- package/dist/ui/server/sites.html +3 -3
- package/dist/ui/server/ssh-keys.html +3 -3
- package/dist/ui/server/team.html +3 -3
- package/dist/ui/server/terminal.html +3 -3
- package/dist/ui/server/workers.html +3 -3
- package/dist/ui/serverless/alarms.html +3 -3
- package/dist/ui/serverless/assets.html +3 -3
- package/dist/ui/serverless/data.html +3 -3
- package/dist/ui/serverless/deployments.html +3 -3
- package/dist/ui/serverless/functions.html +3 -3
- package/dist/ui/serverless/logs.html +3 -3
- package/dist/ui/serverless/queues.html +3 -3
- package/dist/ui/serverless/scheduler.html +3 -3
- package/dist/ui/serverless/secrets.html +3 -3
- package/dist/ui/serverless/traces.html +3 -3
- package/dist/ui/serverless.html +3 -3
- package/package.json +3 -3
|
@@ -915,6 +915,10 @@ function writeFileHeredoc(path, content, delimiter, mode = "0644") {
|
|
|
915
915
|
`chmod ${mode} ${path}`
|
|
916
916
|
];
|
|
917
917
|
}
|
|
918
|
+
function rpxCertRenewServiceName(slug) {
|
|
919
|
+
const safeSlug = (slug || "app").replace(/[^a-z0-9._-]+/gi, "-");
|
|
920
|
+
return `rpx-cert-renew-${safeSlug}.service`;
|
|
921
|
+
}
|
|
918
922
|
function certDomainsForConfig(config) {
|
|
919
923
|
const seen = new Set;
|
|
920
924
|
for (const r of config.proxies) {
|
|
@@ -940,7 +944,7 @@ function buildCertManagementCommands(options) {
|
|
|
940
944
|
const spaced = domains.join(" ");
|
|
941
945
|
const slug = (options.slug || "app").replace(/[^a-z0-9._-]+/gi, "-");
|
|
942
946
|
const renewScriptPath = `${RPX_DIR}/renew-certs-${slug}.sh`;
|
|
943
|
-
const renewServiceName =
|
|
947
|
+
const renewServiceName = rpxCertRenewServiceName(slug);
|
|
944
948
|
const renewTimerName = `rpx-cert-renew-${slug}.timer`;
|
|
945
949
|
const renewScript = [
|
|
946
950
|
"#!/bin/sh",
|
|
@@ -2447,6 +2451,9 @@ class HetznerDriver {
|
|
|
2447
2451
|
if (!compute) {
|
|
2448
2452
|
throw new Error("infrastructure.compute is required to provision Hetzner compute");
|
|
2449
2453
|
}
|
|
2454
|
+
if (config.cloud?.attachTo) {
|
|
2455
|
+
return this.attachToComputeInfrastructure(config.cloud.attachTo, config, environment);
|
|
2456
|
+
}
|
|
2450
2457
|
const stackName = resolveProjectStackName(config, environment);
|
|
2451
2458
|
const serverName = `${slug}-${environment}-app`;
|
|
2452
2459
|
const phpBox = compute.runtime === "php" || !!compute.php;
|
|
@@ -3022,9 +3029,9 @@ class HetznerDriver {
|
|
|
3022
3029
|
const exact = servers.filter((server) => matchesTsCloudLabels(server.labels, options.slug, options.environment, role));
|
|
3023
3030
|
if (exact.length > 0)
|
|
3024
3031
|
return exact.map(toTarget);
|
|
3025
|
-
if (role === "app") {
|
|
3032
|
+
if (role === "app" || role === "lb" || role === "services") {
|
|
3026
3033
|
const state = await readDriverState(options.stackName ?? `${options.slug}-${options.environment}`);
|
|
3027
|
-
const pinnedIds = [state?.serverId, ...state?.appServerIds ?? []].filter((id) => typeof id === "number");
|
|
3034
|
+
const pinnedIds = [...new Set(role === "app" ? [state?.serverId, ...state?.appServerIds ?? []] : role === "lb" ? [state?.lbServerId] : [state?.servicesServerId])].filter((id) => typeof id === "number");
|
|
3028
3035
|
if (pinnedIds.length > 0) {
|
|
3029
3036
|
const pinned = [];
|
|
3030
3037
|
for (const id of pinnedIds) {
|
|
@@ -3043,6 +3050,34 @@ class HetznerDriver {
|
|
|
3043
3050
|
}
|
|
3044
3051
|
return [];
|
|
3045
3052
|
}
|
|
3053
|
+
async attachToComputeInfrastructure(ownerSlug, config, environment) {
|
|
3054
|
+
const servers = await this.client.listServers();
|
|
3055
|
+
const running = (role) => servers.filter((server) => server.status !== "off" && matchesTsCloudLabels(server.labels, ownerSlug, environment, role));
|
|
3056
|
+
const appServers = running("app");
|
|
3057
|
+
if (appServers.length === 0) {
|
|
3058
|
+
throw new Error(`Cannot attach '${config.project.slug}' to '${ownerSlug}': no running Hetzner app server is labeled for ${ownerSlug}/${environment}. Deploy the owner project first.`);
|
|
3059
|
+
}
|
|
3060
|
+
const lbServer = running("lb")[0];
|
|
3061
|
+
const servicesServer = running("services")[0];
|
|
3062
|
+
const primaryApp = appServers[0];
|
|
3063
|
+
const publicGateway = lbServer ?? primaryApp;
|
|
3064
|
+
const stackName = resolveProjectStackName(config, environment);
|
|
3065
|
+
const state = {
|
|
3066
|
+
provider: "hetzner",
|
|
3067
|
+
stackName,
|
|
3068
|
+
serverId: primaryApp.id,
|
|
3069
|
+
serverName: primaryApp.name,
|
|
3070
|
+
appServerIds: appServers.map((server) => server.id),
|
|
3071
|
+
lbServerId: lbServer?.id,
|
|
3072
|
+
servicesServerId: servicesServer?.id,
|
|
3073
|
+
servicesPrivateIp: servicesServer?.private_net?.[0]?.ip,
|
|
3074
|
+
publicIp: publicGateway.public_net.ipv4?.ip,
|
|
3075
|
+
deployStoragePath: "/var/ts-cloud/staging",
|
|
3076
|
+
sshUser: this.sshUser
|
|
3077
|
+
};
|
|
3078
|
+
await writeDriverState(stackName, state);
|
|
3079
|
+
return this.outputsFromState(state);
|
|
3080
|
+
}
|
|
3046
3081
|
async runRemoteDeploy(options) {
|
|
3047
3082
|
if (options.targets.length === 0) {
|
|
3048
3083
|
return { success: false, instanceCount: 0, perInstance: [], error: "No targets provided" };
|
|
@@ -5090,6 +5125,45 @@ async function reloadRpxGateway(options) {
|
|
|
5090
5125
|
logger.success(`rpx gateway reloaded on ${result.instanceCount} target(s)`);
|
|
5091
5126
|
return true;
|
|
5092
5127
|
}
|
|
5128
|
+
async function renewRpxCertificates(options) {
|
|
5129
|
+
const { config, environment, driver, logger = noopLogger2 } = options;
|
|
5130
|
+
const routeSource = options.rpxConfig ?? config;
|
|
5131
|
+
const proxy = routeSource.infrastructure?.compute?.proxy ?? config.infrastructure?.compute?.proxy;
|
|
5132
|
+
if (proxy?.engine !== "rpx" || !proxy.onDemandTls)
|
|
5133
|
+
return true;
|
|
5134
|
+
const rpxConfig = buildRpxConfig(routeSource.sites || {}, { proxy, slug: config.project.slug });
|
|
5135
|
+
if (rpxConfig.proxies.length === 0)
|
|
5136
|
+
return true;
|
|
5137
|
+
const slug = config.project.slug;
|
|
5138
|
+
const stackName = resolveProjectStackName(config, environment);
|
|
5139
|
+
let role = "lb";
|
|
5140
|
+
let targets = await driver.findComputeTargets({ slug, environment, role, stackName });
|
|
5141
|
+
if (targets.length === 0) {
|
|
5142
|
+
role = "app";
|
|
5143
|
+
targets = await driver.findComputeTargets({ slug, environment, role, stackName });
|
|
5144
|
+
}
|
|
5145
|
+
if (targets.length === 0) {
|
|
5146
|
+
logger.warn("rpx TLS: no gateway targets found - skipping certificate issuance.");
|
|
5147
|
+
return true;
|
|
5148
|
+
}
|
|
5149
|
+
logger.step("Issuing rpx TLS certificates after DNS reconciliation...");
|
|
5150
|
+
const result = await driver.runRemoteDeploy({
|
|
5151
|
+
targets,
|
|
5152
|
+
commands: [`systemctl start ${rpxCertRenewServiceName(slug)}`],
|
|
5153
|
+
comment: `ts-cloud rpx TLS issuance ${slug}`,
|
|
5154
|
+
tags: {
|
|
5155
|
+
Project: slug,
|
|
5156
|
+
Environment: environment,
|
|
5157
|
+
Role: role
|
|
5158
|
+
}
|
|
5159
|
+
});
|
|
5160
|
+
if (!result.success) {
|
|
5161
|
+
logger.error(`rpx TLS issuance failed: ${result.error || "unknown error"}`);
|
|
5162
|
+
return false;
|
|
5163
|
+
}
|
|
5164
|
+
logger.success(`rpx TLS certificates reconciled on ${result.instanceCount} gateway target(s)`);
|
|
5165
|
+
return true;
|
|
5166
|
+
}
|
|
5093
5167
|
// src/drivers/shared/cloudfront-origin.ts
|
|
5094
5168
|
var MANAGED_CACHE_POLICY_OPTIMIZED = "658327ea-f89d-4fab-a63d-7e88639e58f6";
|
|
5095
5169
|
var MANAGED_CACHE_POLICY_DISABLED = "4135ea2d-6df8-44a3-9df3-4b5a84be39ad";
|
|
@@ -5172,4 +5246,4 @@ function buildCloudFrontOriginConfig(options) {
|
|
|
5172
5246
|
CustomErrorResponses: { Quantity: 0 }
|
|
5173
5247
|
};
|
|
5174
5248
|
}
|
|
5175
|
-
export { siteInstallBase, isPhpSite, resolveSiteDeployTarget, resolveSiteKind, validateDeploymentConfig, PANTRY_PROJECT_DIR, pgAdminCommand, DEFAULT_RPX_CERTS_DIR, normalizeRoutePath, deriveRouteId, buildRpxConfig, buildRpxLbConfig, renderRpxLauncher, RPX_DIR, RPX_LAUNCHER_PATH, RPX_SERVICE_NAME, buildRpxProvisionScript, buildRpxFragmentRefreshScript, BACKUP_RUNNER_PATH, buildBackupRestoreScript, buildUbuntuBootstrapScript, AwsDriver, resolveHetznerLocation, HetznerClient, resolveHetznerApiToken2 as resolveHetznerApiToken, normalizeSshPublicKey, wrapCloudInitUserData, HetznerDriver, LocalBoxDriver, isBoxMode, createCloudDriver, CloudDriverFactory, cloudDrivers, ensureSshKey, ensureFirewall, ensureServer, serverPublicIpv4, buildSshArgs, sshExec, sshExecOrThrow, scpUpload, waitForSsh, waitForCloudInit, UBUNTU_2404_AMI_PARAM, buildBoxUserData, HetznerBoxProvisioner, AwsBoxProvisioner, createBoxProvisioner, releasePaths, buildRollbackScript, resolveExecStart, buildSiteDeployScript, buildStaticSiteDeployScript, releaseTarballTmpPath, buildAwsArtifactFetch, buildLocalArtifactFetch, buildHostCleanupScript, MANAGEMENT_DASHBOARD_SITE, DASHBOARD_CREDENTIALS_FILE, resolveDashboardAuth, resolveUiSource, ensureManagementDashboard, buildManagementDashboardArtifact, resolveSiteFramework, deploySiteRelease, deployAllComputeSites, reloadRpxGateway, MANAGED_CACHE_POLICY_OPTIMIZED, MANAGED_CACHE_POLICY_DISABLED, MANAGED_ORIGIN_REQUEST_POLICY_ALL_VIEWER, buildCloudFrontOriginConfig };
|
|
5249
|
+
export { siteInstallBase, isPhpSite, resolveSiteDeployTarget, resolveSiteKind, validateDeploymentConfig, PANTRY_PROJECT_DIR, pgAdminCommand, DEFAULT_RPX_CERTS_DIR, normalizeRoutePath, deriveRouteId, buildRpxConfig, buildRpxLbConfig, renderRpxLauncher, RPX_DIR, RPX_LAUNCHER_PATH, RPX_SERVICE_NAME, buildRpxProvisionScript, buildRpxFragmentRefreshScript, BACKUP_RUNNER_PATH, buildBackupRestoreScript, buildUbuntuBootstrapScript, AwsDriver, resolveHetznerLocation, HetznerClient, resolveHetznerApiToken2 as resolveHetznerApiToken, normalizeSshPublicKey, wrapCloudInitUserData, HetznerDriver, LocalBoxDriver, isBoxMode, createCloudDriver, CloudDriverFactory, cloudDrivers, ensureSshKey, ensureFirewall, ensureServer, serverPublicIpv4, buildSshArgs, sshExec, sshExecOrThrow, scpUpload, waitForSsh, waitForCloudInit, UBUNTU_2404_AMI_PARAM, buildBoxUserData, HetznerBoxProvisioner, AwsBoxProvisioner, createBoxProvisioner, releasePaths, buildRollbackScript, resolveExecStart, buildSiteDeployScript, buildStaticSiteDeployScript, releaseTarballTmpPath, buildAwsArtifactFetch, buildLocalArtifactFetch, buildHostCleanupScript, MANAGEMENT_DASHBOARD_SITE, DASHBOARD_CREDENTIALS_FILE, 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
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
sanitizeCloudConfig,
|
|
15
15
|
setMaintenance,
|
|
16
16
|
startLocalDashboardServer
|
|
17
|
-
} from "../chunk-
|
|
17
|
+
} from "../chunk-b17vf1g1.js";
|
|
18
18
|
import {
|
|
19
19
|
buildAndPushServerlessImage
|
|
20
20
|
} from "../chunk-f29w04w5.js";
|
|
@@ -32,7 +32,7 @@ import {
|
|
|
32
32
|
resolveUiSource,
|
|
33
33
|
siteInstallBase,
|
|
34
34
|
validateDeploymentConfig
|
|
35
|
-
} from "../chunk-
|
|
35
|
+
} from "../chunk-d5vqwj8s.js";
|
|
36
36
|
import"../chunk-r16e02bc.js";
|
|
37
37
|
import"../chunk-93hjhs78.js";
|
|
38
38
|
import {
|
|
@@ -83,6 +83,14 @@ export declare class HetznerDriver implements CloudDriver {
|
|
|
83
83
|
getComputeOutputs(options: ProvisionComputeOptions): Promise<ComputeStackOutputs>;
|
|
84
84
|
uploadRelease(options: UploadReleaseOptions): Promise<UploadReleaseResult>;
|
|
85
85
|
findComputeTargets(options: FindComputeTargetsOptions): Promise<ComputeTarget[]>;
|
|
86
|
+
/**
|
|
87
|
+
* Attach this project to compute owned by another ts-cloud project.
|
|
88
|
+
*
|
|
89
|
+
* The owner's Hetzner labels are the source of truth. We write a tenant-local
|
|
90
|
+
* state pin so all later deploy operations resolve the same app/LB targets,
|
|
91
|
+
* even when several unrelated managed boxes exist in the Hetzner project.
|
|
92
|
+
*/
|
|
93
|
+
private attachToComputeInfrastructure;
|
|
86
94
|
runRemoteDeploy(options: RunRemoteDeployOptions): Promise<RemoteDeployResult>;
|
|
87
95
|
/**
|
|
88
96
|
* Ensure the local SSH public key is registered in the Hetzner project and
|
package/dist/drivers/index.d.ts
CHANGED
|
@@ -11,7 +11,7 @@ export type { RemoteExecOptions, RemoteExecResult, WaitOptions } from './shared/
|
|
|
11
11
|
export { AwsBoxProvisioner, buildBoxUserData, createBoxProvisioner, HetznerBoxProvisioner, UBUNTU_2404_AMI_PARAM, } from './shared/box-provision';
|
|
12
12
|
export type { AwsBoxProvisionerOptions, BoxPort, BoxProviderName, BoxProvisioner, BoxSpec, CreateBoxProvisionerOptions, ProvisionedBox, } from './shared/box-provision';
|
|
13
13
|
export { buildAwsArtifactFetch, buildHostCleanupScript, buildLocalArtifactFetch, buildSiteDeployScript, buildStaticSiteDeployScript, releaseTarballTmpPath, resolveExecStart, } from './shared/deploy-script';
|
|
14
|
-
export { deployAllComputeSites, deploySiteRelease, reloadRpxGateway } from './shared/compute-deploy';
|
|
14
|
+
export { deployAllComputeSites, deploySiteRelease, reloadRpxGateway, renewRpxCertificates } from './shared/compute-deploy';
|
|
15
15
|
export { buildRpxConfig, buildRpxFragmentRefreshScript, buildRpxLbConfig, buildRpxProvisionScript, deriveRouteId, normalizeRoutePath, renderRpxLauncher, DEFAULT_RPX_CERTS_DIR, RPX_DIR, RPX_LAUNCHER_PATH, RPX_SERVICE_NAME, } from './shared/rpx-gateway';
|
|
16
16
|
export type { BuildRpxConfigOptions, BuildRpxFragmentRefreshOptions, BuildRpxProvisionOptions, RpxGatewayConfig, RpxLbAppBox, RpxRoute, } from './shared/rpx-gateway';
|
|
17
17
|
export { buildCloudFrontOriginConfig, MANAGED_CACHE_POLICY_DISABLED, MANAGED_CACHE_POLICY_OPTIMIZED, MANAGED_ORIGIN_REQUEST_POLICY_ALL_VIEWER, } from './shared/cloudfront-origin';
|
package/dist/drivers/index.js
CHANGED
|
@@ -42,6 +42,7 @@ import {
|
|
|
42
42
|
releaseTarballTmpPath,
|
|
43
43
|
reloadRpxGateway,
|
|
44
44
|
renderRpxLauncher,
|
|
45
|
+
renewRpxCertificates,
|
|
45
46
|
resolveExecStart,
|
|
46
47
|
resolveHetznerApiToken,
|
|
47
48
|
scpUpload,
|
|
@@ -51,7 +52,7 @@ import {
|
|
|
51
52
|
waitForCloudInit,
|
|
52
53
|
waitForSsh,
|
|
53
54
|
wrapCloudInitUserData
|
|
54
|
-
} from "../chunk-
|
|
55
|
+
} from "../chunk-d5vqwj8s.js";
|
|
55
56
|
import"../chunk-r16e02bc.js";
|
|
56
57
|
import"../chunk-93hjhs78.js";
|
|
57
58
|
import"../chunk-qpj3edwz.js";
|
|
@@ -68,6 +69,7 @@ export {
|
|
|
68
69
|
scpUpload,
|
|
69
70
|
resolveHetznerApiToken,
|
|
70
71
|
resolveExecStart,
|
|
72
|
+
renewRpxCertificates,
|
|
71
73
|
renderRpxLauncher,
|
|
72
74
|
reloadRpxGateway,
|
|
73
75
|
releaseTarballTmpPath,
|
|
@@ -47,3 +47,10 @@ export declare function deployAllComputeSites(options: DeployAllSitesOptions): P
|
|
|
47
47
|
* launcher + unit and `systemctl restart`s, reloading the new routes.
|
|
48
48
|
*/
|
|
49
49
|
export declare function reloadRpxGateway(options: DeployAllSitesOptions): Promise<boolean>;
|
|
50
|
+
/**
|
|
51
|
+
* Request the first production certificates after DNS has been reconciled.
|
|
52
|
+
* Provisioning installs the per-project renewal unit, but ACME HTTP-01 cannot
|
|
53
|
+
* succeed until the domain points at the new box. This deliberately runs after
|
|
54
|
+
* DNS and targets the same gateway box selected by reloadRpxGateway.
|
|
55
|
+
*/
|
|
56
|
+
export declare function renewRpxCertificates(options: Pick<DeployAllSitesOptions, 'config' | 'environment' | 'driver' | 'logger' | 'rpxConfig'>): Promise<boolean>;
|
|
@@ -273,6 +273,7 @@ export interface BuildRpxProvisionOptions {
|
|
|
273
273
|
export declare const RPX_CERT_RENEW_SCRIPT = "/etc/rpx/renew-certs.sh";
|
|
274
274
|
export declare const RPX_CERT_RENEW_SERVICE = "rpx-cert-renew.service";
|
|
275
275
|
export declare const RPX_CERT_RENEW_TIMER = "rpx-cert-renew.timer";
|
|
276
|
+
export declare function rpxCertRenewServiceName(slug: string): string;
|
|
276
277
|
/** The routable FQDNs in a gateway config — each terminates TLS so each needs a cert. */
|
|
277
278
|
export declare function certDomainsForConfig(config: RpxGatewayConfig): string[];
|
|
278
279
|
/**
|
package/dist/index.js
CHANGED
|
@@ -57,7 +57,7 @@ import {
|
|
|
57
57
|
sanitizeCloudConfig,
|
|
58
58
|
setMaintenance,
|
|
59
59
|
startLocalDashboardServer
|
|
60
|
-
} from "./chunk-
|
|
60
|
+
} from "./chunk-b17vf1g1.js";
|
|
61
61
|
import {
|
|
62
62
|
buildAndPushServerlessImage
|
|
63
63
|
} from "./chunk-f29w04w5.js";
|
|
@@ -108,7 +108,7 @@ import {
|
|
|
108
108
|
waitForCloudInit,
|
|
109
109
|
waitForSsh,
|
|
110
110
|
wrapCloudInitUserData
|
|
111
|
-
} from "./chunk-
|
|
111
|
+
} from "./chunk-d5vqwj8s.js";
|
|
112
112
|
import {
|
|
113
113
|
ABTestManager,
|
|
114
114
|
AI,
|