@stacksjs/ts-cloud 0.7.62 → 0.7.64

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.
Files changed (76) hide show
  1. package/dist/bin/cli.js +1556 -1284
  2. package/dist/{chunk-vx2yva1a.js → chunk-0z7ry8fm.js} +897 -93
  3. package/dist/{chunk-zvk0f89t.js → chunk-28vh1h91.js} +1 -1
  4. package/dist/{chunk-ff77qy0c.js → chunk-3c6pp063.js} +519 -143
  5. package/dist/{chunk-tq46tnxv.js → chunk-ecsyc3p0.js} +4 -1
  6. package/dist/{chunk-rxhqny6z.js → chunk-zcvdzvmz.js} +2 -2
  7. package/dist/deploy/dashboard-data-server.d.ts +27 -1
  8. package/dist/deploy/index.js +4 -4
  9. package/dist/deploy/telemetry-collection.d.ts +2 -0
  10. package/dist/drivers/hetzner/client.d.ts +84 -2
  11. package/dist/drivers/hetzner/host-optimization.d.ts +33 -0
  12. package/dist/drivers/hetzner/monitoring.d.ts +46 -0
  13. package/dist/drivers/hetzner/resize-remote.d.ts +38 -0
  14. package/dist/drivers/hetzner/resize-state.d.ts +24 -0
  15. package/dist/drivers/hetzner/resize.d.ts +86 -0
  16. package/dist/drivers/index.d.ts +8 -0
  17. package/dist/drivers/index.js +35 -3
  18. package/dist/drivers/shared/compute-deploy.d.ts +15 -0
  19. package/dist/drivers/shared/releases.d.ts +11 -0
  20. package/dist/drivers/shared/ufw.d.ts +4 -2
  21. package/dist/index.js +4 -4
  22. package/dist/ui/access-denied.html +2 -2
  23. package/dist/ui/account/automation.html +3 -3
  24. package/dist/ui/account/security.html +2 -2
  25. package/dist/ui/applications/compose.html +4 -4
  26. package/dist/ui/applications/new.html +2 -2
  27. package/dist/ui/data/backups.html +4 -4
  28. package/dist/ui/data/services.html +4 -4
  29. package/dist/ui/data/volumes.html +4 -4
  30. package/dist/ui/index.html +12 -7
  31. package/dist/ui/integrations.html +2 -2
  32. package/dist/ui/operations/alerts.html +4 -4
  33. package/dist/ui/operations/configuration.html +4 -4
  34. package/dist/ui/operations/jobs.html +4 -4
  35. package/dist/ui/operations/maintenance.html +3 -3
  36. package/dist/ui/operations/observability.html +13 -7
  37. package/dist/ui/operations/previews.html +4 -4
  38. package/dist/ui/operations/queue.html +4 -4
  39. package/dist/ui/operations/regions.html +4 -4
  40. package/dist/ui/operations/releases.html +4 -4
  41. package/dist/ui/operations/workloads.html +3 -3
  42. package/dist/ui/security.html +2 -2
  43. package/dist/ui/server/actions.html +4 -4
  44. package/dist/ui/server/activity.html +2 -2
  45. package/dist/ui/server/capacity.html +4 -4
  46. package/dist/ui/server/database.html +3 -3
  47. package/dist/ui/server/deployments.html +4 -4
  48. package/dist/ui/server/diagnostics.html +2 -2
  49. package/dist/ui/server/firewall.html +4 -4
  50. package/dist/ui/server/fleet.html +4 -4
  51. package/dist/ui/server/logs.html +4 -4
  52. package/dist/ui/server/metrics.html +203 -3
  53. package/dist/ui/server/security.html +2 -2
  54. package/dist/ui/server/services.html +2 -2
  55. package/dist/ui/server/sites.html +102 -6
  56. package/dist/ui/server/ssh-keys.html +4 -4
  57. package/dist/ui/server/team.html +4 -4
  58. package/dist/ui/server/terminal.html +2 -2
  59. package/dist/ui/serverless/alarms.html +3 -3
  60. package/dist/ui/serverless/assets.html +2 -2
  61. package/dist/ui/serverless/cost.html +2 -2
  62. package/dist/ui/serverless/data.html +4 -4
  63. package/dist/ui/serverless/deployments.html +2 -2
  64. package/dist/ui/serverless/firewall.html +2 -2
  65. package/dist/ui/serverless/functions.html +4 -4
  66. package/dist/ui/serverless/logs.html +3 -3
  67. package/dist/ui/serverless/metrics.html +2 -2
  68. package/dist/ui/serverless/queues.html +4 -4
  69. package/dist/ui/serverless/secrets.html +4 -4
  70. package/dist/ui/serverless/traces.html +4 -4
  71. package/dist/ui/serverless.html +4 -4
  72. package/dist/ui-src/pages/index.stx +12 -10
  73. package/dist/ui-src/pages/operations/observability.stx +6 -4
  74. package/dist/ui-src/pages/server/metrics.stx +262 -106
  75. package/dist/ui-src/pages/server/sites.stx +98 -6
  76. package/package.json +3 -3
@@ -21928,7 +21928,7 @@ function dashboardHostFor(domain, ownedDomains) {
21928
21928
  function collectDomains(config, environment) {
21929
21929
  const candidates = [];
21930
21930
  const dnsDomain = config.infrastructure?.dns?.domain;
21931
- if (dnsDomain)
21931
+ if (dnsDomain && !config.cloud?.attachTo)
21932
21932
  candidates.push(dnsDomain);
21933
21933
  if (environment && config.environments?.[environment]?.domain)
21934
21934
  candidates.push(config.environments[environment].domain);
@@ -21997,6 +21997,9 @@ function resolveManagementDashboardSites(config, environment, opts) {
21997
21997
  preStart: ["bun install --production --no-save"],
21998
21998
  start: `bun ${DASHBOARD_ENTRY} dashboard:serve --box --host 127.0.0.1 --port ${port}`,
21999
21999
  port,
22000
+ env: {
22001
+ TS_CLOUD_DASHBOARD_TELEMETRY: config.cloud?.attachTo ? "0" : "1"
22002
+ },
22000
22003
  zeroDowntime: false,
22001
22004
  sharedPaths: [DASHBOARD_STATE_DIR],
22002
22005
  healthCheck: { path: "/login" },
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  buildAndPushServerlessImage
3
- } from "./chunk-zvk0f89t.js";
3
+ } from "./chunk-28vh1h91.js";
4
4
  import"./chunk-50jpda9q.js";
5
- import"./chunk-tq46tnxv.js";
5
+ import"./chunk-ecsyc3p0.js";
6
6
  import"./chunk-zqtpg06c.js";
7
7
  import"./chunk-v0bahtg2.js";
8
8
  export {
@@ -12,9 +12,33 @@ interface ProbedService {
12
12
  enabled?: string;
13
13
  since?: string;
14
14
  }
15
+ export interface DiscoveredSite {
16
+ name: string;
17
+ project: string;
18
+ route: string;
19
+ href: string;
20
+ domain: string;
21
+ path: string;
22
+ kind: 'app' | 'static' | 'redirect';
23
+ runtime: string;
24
+ deploy: string;
25
+ tls: 'https';
26
+ root: string;
27
+ branch: string;
28
+ status: 'live' | 'degraded' | 'failed';
29
+ managedBy?: 'owner' | 'attached';
30
+ httpStatus: number;
31
+ responseMs: number;
32
+ tlsDaysRemaining?: number;
33
+ checkedAt: string;
34
+ release?: string;
35
+ deployedAt?: string;
36
+ }
15
37
  export declare function parseBlock(output: string): Record<string, string> & {
16
38
  services: ProbedService[];
39
+ discoveredSites: DiscoveredSite[];
17
40
  };
41
+ export declare function mergeDiscoveredSites(configured: Array<Record<string, any>>, discovered: DiscoveredSite[], ownerSlug: string): Array<Record<string, any>>;
18
42
  interface ServerLogSource {
19
43
  /** journalctl `-u` pattern (a unit name or a glob like `acme-web-queue-*`). */
20
44
  pattern: string;
@@ -32,5 +56,7 @@ export declare function parseServerLogs(output: string): Array<Record<string, an
32
56
  export declare function parseServerSecurity(output: string): Record<string, any>;
33
57
  export declare function parseDeployHistory(output: string, sites?: Record<string, any>): Array<Record<string, any>>;
34
58
  export declare function resolveConfigOnlyServerDashboardData(config: CloudConfig, environment: EnvironmentType): Record<string, any>;
35
- export declare function resolveServerDashboardData(config: CloudConfig, environment: EnvironmentType): Promise<Record<string, any> | null>;
59
+ export declare function resolveServerDashboardData(config: CloudConfig, environment: EnvironmentType, options?: {
60
+ telemetryOnly?: boolean;
61
+ }): Promise<Record<string, any> | null>;
36
62
  export {};
@@ -32,7 +32,7 @@ import {
32
32
  synchronizeDashboardUsers,
33
33
  trackDashboardOperation,
34
34
  verifyStaticApiOrigin
35
- } from "../chunk-ff77qy0c.js";
35
+ } from "../chunk-3c6pp063.js";
36
36
  import {
37
37
  deleteStaticSite,
38
38
  deployStaticSite,
@@ -46,7 +46,7 @@ import {
46
46
  } from "../chunk-gcsv7g83.js";
47
47
  import {
48
48
  buildAndPushServerlessImage
49
- } from "../chunk-zvk0f89t.js";
49
+ } from "../chunk-28vh1h91.js";
50
50
  import"../chunk-ybcz6sxc.js";
51
51
  import"../chunk-01d86gt1.js";
52
52
  import"../chunk-50jpda9q.js";
@@ -65,8 +65,8 @@ import {
65
65
  shipsARelease,
66
66
  siteInstallBase,
67
67
  validateDeploymentConfig
68
- } from "../chunk-vx2yva1a.js";
69
- import"../chunk-tq46tnxv.js";
68
+ } from "../chunk-0z7ry8fm.js";
69
+ import"../chunk-ecsyc3p0.js";
70
70
  import"../chunk-703nkybg.js";
71
71
  import"../chunk-4cjrg98a.js";
72
72
  import"../chunk-hpv68b4a.js";
@@ -29,6 +29,8 @@ export interface TelemetryCollectionContext {
29
29
  config: CloudConfig;
30
30
  environment: EnvironmentType;
31
31
  force?: boolean;
32
+ /** Collect host and site metrics without expensive runtime logs or inventory. */
33
+ lightweight?: boolean;
32
34
  }
33
35
  export declare function telemetryRecordsFromLog(input: {
34
36
  projectId: string;
@@ -10,6 +10,54 @@ export interface HetznerApiErrorBody {
10
10
  details?: unknown;
11
11
  };
12
12
  }
13
+ export declare class HetznerApiError extends Error {
14
+ readonly status: number;
15
+ readonly code?: string | undefined;
16
+ readonly details?: unknown;
17
+ constructor(message: string, status: number, code?: string | undefined, details?: unknown);
18
+ }
19
+ export declare class HetznerActionError extends Error {
20
+ readonly action: HetznerAction;
21
+ constructor(message: string, action: HetznerAction);
22
+ }
23
+ export interface HetznerServerTypeLocation {
24
+ id: number;
25
+ name: string;
26
+ available: boolean;
27
+ recommended: boolean;
28
+ deprecation?: unknown;
29
+ }
30
+ export interface HetznerServerTypePrice {
31
+ location: string;
32
+ price_hourly: {
33
+ net: string;
34
+ gross: string;
35
+ };
36
+ price_monthly: {
37
+ net: string;
38
+ gross: string;
39
+ };
40
+ included_traffic?: number;
41
+ price_per_tb_traffic?: {
42
+ net: string;
43
+ gross: string;
44
+ };
45
+ }
46
+ export interface HetznerServerType {
47
+ id?: number;
48
+ name: string;
49
+ architecture?: string;
50
+ cores?: number;
51
+ cpu_type?: string;
52
+ category?: string;
53
+ deprecated?: boolean;
54
+ description?: string;
55
+ disk?: number;
56
+ memory?: number;
57
+ prices?: HetznerServerTypePrice[];
58
+ storage_type?: string;
59
+ locations?: HetznerServerTypeLocation[];
60
+ }
13
61
  export interface HetznerServer {
14
62
  id: number;
15
63
  name: string;
@@ -26,15 +74,24 @@ export interface HetznerServer {
26
74
  ip: string;
27
75
  }>;
28
76
  labels?: Record<string, string>;
29
- server_type: {
77
+ server_type: HetznerServerType;
78
+ /** Current API shape. */
79
+ location?: {
80
+ id?: number;
30
81
  name: string;
82
+ description?: string;
83
+ city?: string;
84
+ country?: string;
31
85
  };
32
- datacenter: {
86
+ /** Legacy API shape retained for compatibility with recorded fixtures. */
87
+ datacenter?: {
33
88
  name: string;
34
89
  location: {
35
90
  name: string;
36
91
  };
37
92
  };
93
+ primary_disk_size?: number;
94
+ locked?: boolean;
38
95
  }
39
96
  export interface HetznerFirewall {
40
97
  id: number;
@@ -65,6 +122,15 @@ export interface HetznerAction {
65
122
  message: string;
66
123
  };
67
124
  }
125
+ export type HetznerServerMetricType = 'cpu' | 'disk' | 'network';
126
+ export interface HetznerServerMetrics {
127
+ start: string;
128
+ end: string;
129
+ step: number;
130
+ time_series: Record<string, {
131
+ values: Array<[number, string]>;
132
+ }>;
133
+ }
68
134
  export interface CreateServerOptions {
69
135
  name: string;
70
136
  serverType: string;
@@ -154,6 +220,14 @@ export declare class HetznerClient {
154
220
  private requestAll;
155
221
  listServers(): Promise<HetznerServer[]>;
156
222
  getServer(id: number): Promise<HetznerServer>;
223
+ getServerMetrics(id: number, options: {
224
+ types: HetznerServerMetricType[];
225
+ start: Date;
226
+ end: Date;
227
+ step?: number;
228
+ }): Promise<HetznerServerMetrics>;
229
+ listServerTypes(name?: string): Promise<HetznerServerType[]>;
230
+ getServerType(name: string): Promise<HetznerServerType | null>;
157
231
  createServer(options: CreateServerOptions): Promise<{
158
232
  server: HetznerServer;
159
233
  action: HetznerAction;
@@ -183,6 +257,10 @@ export declare class HetznerClient {
183
257
  }>): Promise<HetznerAction[]>;
184
258
  listSshKeys(): Promise<HetznerSshKey[]>;
185
259
  createSshKey(options: CreateSshKeyOptions): Promise<HetznerSshKey>;
260
+ getAction(actionId: number): Promise<HetznerAction>;
261
+ shutdownServer(serverId: number): Promise<HetznerAction>;
262
+ powerOnServer(serverId: number): Promise<HetznerAction>;
263
+ changeServerType(serverId: number, serverType: string, upgradeDisk: boolean): Promise<HetznerAction>;
186
264
  waitForAction(actionId: number, options?: {
187
265
  pollIntervalMs?: number;
188
266
  maxWaitMs?: number;
@@ -191,6 +269,10 @@ export declare class HetznerClient {
191
269
  pollIntervalMs?: number;
192
270
  maxWaitMs?: number;
193
271
  }): Promise<HetznerServer>;
272
+ waitForServerStatus(serverId: number, status: string, options?: {
273
+ pollIntervalMs?: number;
274
+ maxWaitMs?: number;
275
+ }): Promise<HetznerServer>;
194
276
  }
195
277
  /**
196
278
  * The Hetzner API token, or a clear error when none is configured.
@@ -0,0 +1,33 @@
1
+ import type { CloudConfig } from '@ts-cloud/core';
2
+ import type { RemoteExecOptions } from '../shared/remote-exec';
3
+ export interface HetznerHostOptimizationPlan {
4
+ firewallPorts: number[];
5
+ monitoring: boolean;
6
+ autoUpdates: boolean;
7
+ swapGb: number;
8
+ sshPasswordAuthentication: false;
9
+ journalMaxUse: string;
10
+ journalRetention: string;
11
+ }
12
+ export interface HetznerHostOptimizationReport {
13
+ firewallActive: boolean;
14
+ firewallPorts: number[];
15
+ passwordAuthentication: boolean;
16
+ rootPasswordLogin: boolean;
17
+ fail2banActive: boolean;
18
+ unattendedUpgradesActive: boolean;
19
+ metricsTimerActive: boolean;
20
+ metricsSnapshotFresh: boolean;
21
+ swapBytes: number;
22
+ journalBytes: number;
23
+ failedUnits: string[];
24
+ publicTcpPorts: number[];
25
+ }
26
+ export interface HetznerHostOptimizationOptions extends RemoteExecOptions {
27
+ host: string;
28
+ }
29
+ export declare function resolveHetznerHostOptimizationPlan(config: CloudConfig): HetznerHostOptimizationPlan;
30
+ export declare function buildHetznerHostOptimizationScript(config: CloudConfig): string[];
31
+ export declare function applyHetznerHostOptimization(config: CloudConfig, options: HetznerHostOptimizationOptions): Promise<void>;
32
+ export declare function collectHetznerHostOptimizationReport(options: HetznerHostOptimizationOptions): Promise<HetznerHostOptimizationReport>;
33
+ export declare function verifyHetznerHostOptimization(plan: HetznerHostOptimizationPlan, report: HetznerHostOptimizationReport): string[];
@@ -0,0 +1,46 @@
1
+ import type { HetznerClient, HetznerServerMetrics } from './client';
2
+ import type { RemoteExecOptions } from '../shared/remote-exec';
3
+ export interface HetznerHostHistoryPoint {
4
+ timestamp: string;
5
+ cpuUsedPercent: number;
6
+ cpuUserPercent: number;
7
+ cpuSystemPercent: number;
8
+ cpuIowaitPercent: number;
9
+ memoryUsedPercent: number;
10
+ memoryUsedBytes: number;
11
+ memoryAvailableBytes: number;
12
+ swapUsedPercent: number;
13
+ swapUsedBytes: number;
14
+ }
15
+ export interface HetznerProviderMetricPoint {
16
+ timestamp: string;
17
+ value: number;
18
+ }
19
+ export interface HetznerServerMonitoring {
20
+ from: string;
21
+ to: string;
22
+ cores: number;
23
+ host: HetznerHostHistoryPoint[];
24
+ provider: Record<string, HetznerProviderMetricPoint[]>;
25
+ summary: {
26
+ cpuAveragePercent: number | null;
27
+ cpuPeakPercent: number | null;
28
+ memoryAveragePercent: number | null;
29
+ memoryPeakPercent: number | null;
30
+ memoryMinimumAvailableBytes: number | null;
31
+ swapPeakPercent: number | null;
32
+ };
33
+ }
34
+ export declare function parseSadfHostHistory(raw: string, from: Date, to: Date): HetznerHostHistoryPoint[];
35
+ export declare function providerMetricSeries(metrics: HetznerServerMetrics): Record<string, HetznerProviderMetricPoint[]>;
36
+ export declare function collectHetznerServerMonitoring(options: {
37
+ client: HetznerClient;
38
+ serverId: number;
39
+ cores: number;
40
+ from: Date;
41
+ to: Date;
42
+ step?: number;
43
+ remote: RemoteExecOptions & {
44
+ host: string;
45
+ };
46
+ }): Promise<HetznerServerMonitoring>;
@@ -0,0 +1,38 @@
1
+ import type { RemoteExecOptions } from '../shared/remote-exec';
2
+ import type { HetznerServerType } from './client';
3
+ import type { HetznerResizeVerification } from './resize';
4
+ export interface HetznerRouteProbe {
5
+ domain: string;
6
+ ok: boolean;
7
+ status?: number;
8
+ error?: string;
9
+ }
10
+ export interface HetznerResizeManifest {
11
+ capturedAt: string;
12
+ hostname: string;
13
+ cpuCores: number;
14
+ memoryBytes: number;
15
+ rootSource: string;
16
+ rootFsType: string;
17
+ rootDiskBytes: number;
18
+ rootFilesystemBytes: number;
19
+ failedUnits: string[];
20
+ runningServices: string[];
21
+ releaseLinks: string[];
22
+ routeFragments: string[];
23
+ routeIds: string[];
24
+ routeDomains: string[];
25
+ persistentData: string[];
26
+ dataCatalog: string[];
27
+ routeProbes: HetznerRouteProbe[];
28
+ }
29
+ export interface HetznerRemoteResizeOptions extends RemoteExecOptions {
30
+ host: string;
31
+ sshTimeoutMs?: number;
32
+ routeTimeoutMs?: number;
33
+ }
34
+ export declare function collectHetznerResizeManifest(options: HetznerRemoteResizeOptions): Promise<HetznerResizeManifest>;
35
+ export declare function prepareHetznerResize(options: HetznerRemoteResizeOptions): Promise<HetznerResizeManifest>;
36
+ export declare function verifyHetznerResize(options: HetznerRemoteResizeOptions, target: HetznerServerType, before?: HetznerResizeManifest, context?: {
37
+ recovered: boolean;
38
+ }): Promise<HetznerResizeVerification>;
@@ -0,0 +1,24 @@
1
+ import type { HetznerResizePhase } from './resize';
2
+ import type { HetznerResizeManifest } from './resize-remote';
3
+ export interface HetznerResizeCheckpoint {
4
+ schemaVersion: 1;
5
+ operationId: string;
6
+ stackName: string;
7
+ serverId: number;
8
+ serverName: string;
9
+ sourceType: string;
10
+ targetType: string;
11
+ upgradeDisk: boolean;
12
+ phase: HetznerResizePhase;
13
+ status: 'running' | 'waiting-capacity' | 'completed' | 'recovered' | 'failed';
14
+ attempts: number;
15
+ startedAt: string;
16
+ updatedAt: string;
17
+ manifest?: HetznerResizeManifest;
18
+ lastError?: string;
19
+ }
20
+ export declare function resizeCheckpointPath(stackName: string): string;
21
+ export declare function resizeLockPath(stackName: string): string;
22
+ export declare function readResizeCheckpoint(stackName: string): Promise<HetznerResizeCheckpoint | null>;
23
+ export declare function writeResizeCheckpoint(checkpoint: HetznerResizeCheckpoint): Promise<void>;
24
+ export declare function acquireResizeLock(stackName: string, staleAfterMs?: number): Promise<() => Promise<void>>;
@@ -0,0 +1,86 @@
1
+ import type { HetznerAction, HetznerClient, HetznerServer, HetznerServerType } from './client';
2
+ export type HetznerResizePhase = 'planning' | 'waiting-capacity' | 'preflight' | 'shutting-down' | 'resizing' | 'powering-on' | 'verifying' | 'recovering' | 'complete';
3
+ export interface HetznerResizePlan {
4
+ serverId: number;
5
+ serverName: string;
6
+ location: string;
7
+ currentType: HetznerServerType;
8
+ targetType: HetznerServerType;
9
+ capacityAvailable: boolean;
10
+ alreadyComplete: boolean;
11
+ upgradeDisk: boolean;
12
+ }
13
+ export interface HetznerResizeVerification {
14
+ ok: boolean;
15
+ checks?: Record<string, boolean | number | string>;
16
+ failures?: string[];
17
+ }
18
+ export interface HetznerResizeHooks<TManifest = unknown> {
19
+ preflight?: (server: HetznerServer, target: HetznerServerType) => Promise<TManifest> | TManifest;
20
+ afterBoot?: (server: HetznerServer, target: HetznerServerType, manifest: TManifest | undefined, context: {
21
+ recovered: boolean;
22
+ }) => Promise<HetznerResizeVerification> | HetznerResizeVerification;
23
+ onPhase?: (phase: HetznerResizePhase, detail?: Record<string, unknown>) => Promise<void> | void;
24
+ }
25
+ export interface HetznerResizeClient {
26
+ getServer(id: number): Promise<HetznerServer>;
27
+ getServerType(name: string): Promise<HetznerServerType | null>;
28
+ shutdownServer(id: number): Promise<HetznerAction>;
29
+ powerOnServer(id: number): Promise<HetznerAction>;
30
+ changeServerType(id: number, serverType: string, upgradeDisk: boolean): Promise<HetznerAction>;
31
+ waitForAction(actionId: number, options?: {
32
+ pollIntervalMs?: number;
33
+ maxWaitMs?: number;
34
+ }): Promise<HetznerAction>;
35
+ waitForServerRunning(serverId: number, options?: {
36
+ pollIntervalMs?: number;
37
+ maxWaitMs?: number;
38
+ }): Promise<HetznerServer>;
39
+ waitForServerStatus(serverId: number, status: string, options?: {
40
+ pollIntervalMs?: number;
41
+ maxWaitMs?: number;
42
+ }): Promise<HetznerServer>;
43
+ }
44
+ export interface ExecuteHetznerResizeOptions<TManifest = unknown> {
45
+ client: HetznerResizeClient;
46
+ serverId: number;
47
+ targetType: string;
48
+ upgradeDisk?: boolean;
49
+ /** Continue a recorded resize after the process stopped with the server off. */
50
+ resumeFromOff?: boolean;
51
+ /** Manifest restored from a durable checkpoint when resuming. */
52
+ manifest?: TManifest;
53
+ /** Ignore the best-effort stock flag and ask the placement API anyway. */
54
+ attemptUnavailable?: boolean;
55
+ hooks?: HetznerResizeHooks<TManifest>;
56
+ actionPollIntervalMs?: number;
57
+ actionTimeoutMs?: number;
58
+ serverPollIntervalMs?: number;
59
+ serverTimeoutMs?: number;
60
+ }
61
+ export type HetznerResizeResult<TManifest = unknown> = {
62
+ status: 'waiting-capacity';
63
+ plan: HetznerResizePlan;
64
+ } | {
65
+ status: 'already-complete';
66
+ plan: HetznerResizePlan;
67
+ verification?: HetznerResizeVerification;
68
+ } | {
69
+ status: 'completed';
70
+ plan: HetznerResizePlan;
71
+ server: HetznerServer;
72
+ manifest?: TManifest;
73
+ verification?: HetznerResizeVerification;
74
+ } | {
75
+ status: 'recovered';
76
+ plan: HetznerResizePlan;
77
+ server: HetznerServer;
78
+ manifest?: TManifest;
79
+ verification?: HetznerResizeVerification;
80
+ retryable: boolean;
81
+ error: string;
82
+ };
83
+ export declare function planHetznerServerResize(client: Pick<HetznerResizeClient, 'getServer' | 'getServerType'>, serverId: number, targetTypeName: string, upgradeDisk?: boolean): Promise<HetznerResizePlan>;
84
+ export declare function isHetznerCapacityError(error: unknown): boolean;
85
+ export declare function executeHetznerServerResize<TManifest = unknown>(options: ExecuteHetznerResizeOptions<TManifest>): Promise<HetznerResizeResult<TManifest>>;
86
+ export type HetznerResizeClientInstance = Pick<HetznerClient, 'getServer' | 'getServerType' | 'shutdownServer' | 'powerOnServer' | 'changeServerType' | 'waitForAction' | 'waitForServerRunning' | 'waitForServerStatus'>;
@@ -3,6 +3,14 @@ export { AwsDriver } from './aws/driver';
3
3
  export { HetznerDriver } from './hetzner/driver';
4
4
  export { isBoxMode, LocalBoxDriver } from './local-box/driver';
5
5
  export { HetznerClient, normalizeSshPublicKey, resolveHetznerApiToken } from './hetzner/client';
6
+ export { executeHetznerServerResize, isHetznerCapacityError, planHetznerServerResize, } from './hetzner/resize';
7
+ export type { ExecuteHetznerResizeOptions, HetznerResizeHooks, HetznerResizePhase, HetznerResizePlan, HetznerResizeResult, HetznerResizeVerification, } from './hetzner/resize';
8
+ export { collectHetznerResizeManifest, prepareHetznerResize, verifyHetznerResize, } from './hetzner/resize-remote';
9
+ export type { HetznerRemoteResizeOptions, HetznerResizeManifest, HetznerRouteProbe, } from './hetzner/resize-remote';
10
+ export { applyHetznerHostOptimization, buildHetznerHostOptimizationScript, collectHetznerHostOptimizationReport, resolveHetznerHostOptimizationPlan, verifyHetznerHostOptimization, } from './hetzner/host-optimization';
11
+ export type { HetznerHostOptimizationOptions, HetznerHostOptimizationPlan, HetznerHostOptimizationReport, } from './hetzner/host-optimization';
12
+ export { acquireResizeLock, readResizeCheckpoint, resizeCheckpointPath, resizeLockPath, writeResizeCheckpoint, } from './hetzner/resize-state';
13
+ export type { HetznerResizeCheckpoint } from './hetzner/resize-state';
6
14
  export { generateUbuntuAppCloudInit, wrapCloudInitUserData } from './hetzner/cloud-init';
7
15
  export { ensureFirewall, ensureServer, ensureSshKey, serverPublicIpv4 } from './hetzner/provision';
8
16
  export type { EnsuredResource, EnsuredServer, EnsureFirewallOptions, EnsureServerOptions, EnsureSshKeyOptions, } from './hetzner/provision';
@@ -14,9 +14,12 @@ import {
14
14
  RPX_LAUNCHER_PATH,
15
15
  RPX_SERVICE_NAME,
16
16
  UBUNTU_2404_AMI_PARAM,
17
+ acquireResizeLock,
18
+ applyHetznerHostOptimization,
17
19
  buildAwsArtifactFetch,
18
20
  buildBoxUserData,
19
21
  buildCloudFrontOriginConfig,
22
+ buildHetznerHostOptimizationScript,
20
23
  buildHostCleanupScript,
21
24
  buildLocalArtifactFetch,
22
25
  buildRpxConfig,
@@ -28,6 +31,8 @@ import {
28
31
  buildStaticSiteDeployScript,
29
32
  buildUbuntuBootstrapScript,
30
33
  cloudDrivers,
34
+ collectHetznerHostOptimizationReport,
35
+ collectHetznerResizeManifest,
31
36
  createBoxProvisioner,
32
37
  createCloudDriver,
33
38
  deployAllComputeSites,
@@ -36,47 +41,69 @@ import {
36
41
  ensureFirewall,
37
42
  ensureServer,
38
43
  ensureSshKey,
44
+ executeHetznerServerResize,
39
45
  isBoxMode,
46
+ isHetznerCapacityError,
40
47
  normalizeRoutePath,
41
48
  normalizeSshPublicKey,
49
+ planHetznerServerResize,
50
+ prepareHetznerResize,
51
+ readResizeCheckpoint,
42
52
  releaseTarballTmpPath,
43
53
  reloadRpxGateway,
44
54
  renderRpxLauncher,
45
55
  renewRpxCertificates,
56
+ resizeCheckpointPath,
57
+ resizeLockPath,
46
58
  resolveExecStart,
47
59
  resolveHetznerApiToken,
60
+ resolveHetznerHostOptimizationPlan,
48
61
  scpUpload,
49
62
  serverPublicIpv4,
50
63
  sshExec,
51
64
  sshExecOrThrow,
65
+ verifyHetznerHostOptimization,
66
+ verifyHetznerResize,
52
67
  waitForCloudInit,
53
68
  waitForSsh,
54
- wrapCloudInitUserData
55
- } from "../chunk-vx2yva1a.js";
56
- import"../chunk-tq46tnxv.js";
69
+ wrapCloudInitUserData,
70
+ writeResizeCheckpoint
71
+ } from "../chunk-0z7ry8fm.js";
72
+ import"../chunk-ecsyc3p0.js";
57
73
  import"../chunk-703nkybg.js";
58
74
  import"../chunk-4cjrg98a.js";
59
75
  import"../chunk-wj3s95p9.js";
60
76
  import"../chunk-zqtpg06c.js";
61
77
  import"../chunk-v0bahtg2.js";
62
78
  export {
79
+ writeResizeCheckpoint,
63
80
  wrapCloudInitUserData,
64
81
  waitForSsh,
65
82
  waitForCloudInit,
83
+ verifyHetznerResize,
84
+ verifyHetznerHostOptimization,
66
85
  sshExecOrThrow,
67
86
  sshExec,
68
87
  serverPublicIpv4,
69
88
  scpUpload,
89
+ resolveHetznerHostOptimizationPlan,
70
90
  resolveHetznerApiToken,
71
91
  resolveExecStart,
92
+ resizeLockPath,
93
+ resizeCheckpointPath,
72
94
  renewRpxCertificates,
73
95
  renderRpxLauncher,
74
96
  reloadRpxGateway,
75
97
  releaseTarballTmpPath,
98
+ readResizeCheckpoint,
99
+ prepareHetznerResize,
100
+ planHetznerServerResize,
76
101
  normalizeSshPublicKey,
77
102
  normalizeRoutePath,
103
+ isHetznerCapacityError,
78
104
  isBoxMode,
79
105
  buildUbuntuBootstrapScript as generateUbuntuAppCloudInit,
106
+ executeHetznerServerResize,
80
107
  ensureSshKey,
81
108
  ensureServer,
82
109
  ensureFirewall,
@@ -85,6 +112,8 @@ export {
85
112
  deployAllComputeSites,
86
113
  createCloudDriver,
87
114
  createBoxProvisioner,
115
+ collectHetznerResizeManifest,
116
+ collectHetznerHostOptimizationReport,
88
117
  cloudDrivers,
89
118
  buildStaticSiteDeployScript,
90
119
  buildSshArgs,
@@ -95,9 +124,12 @@ export {
95
124
  buildRpxConfig,
96
125
  buildLocalArtifactFetch,
97
126
  buildHostCleanupScript,
127
+ buildHetznerHostOptimizationScript,
98
128
  buildCloudFrontOriginConfig,
99
129
  buildBoxUserData,
100
130
  buildAwsArtifactFetch,
131
+ applyHetznerHostOptimization,
132
+ acquireResizeLock,
101
133
  UBUNTU_2404_AMI_PARAM,
102
134
  RPX_SERVICE_NAME,
103
135
  RPX_LAUNCHER_PATH,
@@ -20,6 +20,13 @@ export interface DeployAllSitesOptions {
20
20
  logger?: ComputeDeployLogger;
21
21
  /** Project root used to resolve/build the management dashboard UI. Defaults to `process.cwd()`. */
22
22
  cwd?: string;
23
+ /**
24
+ * Auto-inject the management dashboard when the caller has not already
25
+ * prepared it. Framework integrations that inject before provisioning must
26
+ * disable this for narrowed single-site deploys, otherwise the dashboard is
27
+ * unexpectedly added back to the narrowed site set.
28
+ */
29
+ managementDashboard?: boolean;
23
30
  /**
24
31
  * The FULL site model for regenerating the rpx gateway, distinct from `config`
25
32
  * which may be narrowed to a single site for a partial deploy. The rpx gateway
@@ -28,6 +35,14 @@ export interface DeployAllSitesOptions {
28
35
  */
29
36
  rpxConfig?: CloudConfig;
30
37
  }
38
+ /**
39
+ * Reconcile only the auto-managed dashboard units for one project. Dashboard
40
+ * host derivation can legitimately change when ownership metadata is fixed;
41
+ * without this bounded cleanup, the superseded unit remains enabled forever
42
+ * and can keep crash-looping on its old port. Release data and shared dashboard
43
+ * state stay on disk for recovery.
44
+ */
45
+ export declare function buildManagementDashboardServiceReconciliationScript(slug: string, desiredSiteNames: string[]): string[];
31
46
  /**
32
47
  * Deploy every site that targets the compute server — both dynamic apps
33
48
  * (`server` + `start`, run as systemd services) and static sites (`server`
@@ -70,6 +70,17 @@ export declare function buildDeployLock(paths: ReleasePaths, waitSeconds?: numbe
70
70
  * two renames, which is atomic enough that no request lands mid-swap.
71
71
  */
72
72
  export declare function buildResetReleaseDir(paths: ReleasePaths): string[];
73
+ /**
74
+ * Remove a half-built release if the deploy fails before it went live.
75
+ *
76
+ * The check has to run *when the trap fires*, not when it is armed. A deploy
77
+ * arms this at the top and activates the release much later, so a value
78
+ * computed up front says "not live" for the rest of the script — and a failure
79
+ * in any step after activation would then delete the release the site had just
80
+ * started serving. Both paths are resolved at that moment for the reason in
81
+ * {@link buildIsReleaseLive}.
82
+ */
83
+ export declare function buildStrandedReleaseTrap(paths: ReleasePaths): string;
73
84
  /**
74
85
  * Set `TS_CLOUD_IS_LIVE` to "yes" when `current` resolves to this release.
75
86
  *
@@ -11,7 +11,9 @@ import type { ComputeFirewallConfig } from '@ts-cloud/core';
11
11
  /** Ports always allowed so SSH deploys + web traffic are never locked out. */
12
12
  export declare const UFW_BASE_PORTS: readonly number[];
13
13
  /**
14
- * Build the UFW provisioning commands. Idempotent: `ufw allow` is a no-op when
15
- * a rule already exists, and `--force enable` is safe to re-run.
14
+ * Build the UFW provisioning commands. The ts-cloud declaration owns the host
15
+ * firewall, so every reconciliation resets stale/manual rules before applying
16
+ * the exact desired set. This prevents a removed app port from remaining
17
+ * publicly reachable forever.
16
18
  */
17
19
  export declare function buildUfwScript(firewall?: ComputeFirewallConfig): string[];