@stacksjs/ts-cloud 0.5.26 → 0.5.28
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 +1223 -7366
- package/dist/deploy/dashboard-data-server.d.ts +27 -5
- package/dist/deploy/dashboard-database.d.ts +38 -0
- package/dist/deploy/dashboard-database.test.d.ts +1 -0
- package/dist/deploy/dashboard-operations.d.ts +48 -0
- package/dist/deploy/dashboard-operations.test.d.ts +1 -0
- package/dist/deploy/index.d.ts +1 -0
- package/dist/deploy/local-dashboard-server.d.ts +31 -0
- package/dist/deploy/management-dashboard.d.ts +21 -1
- package/dist/deploy/site-config-editor.d.ts +37 -0
- package/dist/deploy/site-target.d.ts +3 -1
- package/dist/deploy/ssh-config-editor.d.ts +22 -0
- package/dist/deploy/ssh-config-editor.test.d.ts +1 -0
- package/dist/drivers/factory.d.ts +4 -0
- package/dist/drivers/index.d.ts +1 -0
- package/dist/drivers/local-box/driver.d.ts +20 -0
- package/dist/drivers/shared/compute-deploy.d.ts +2 -0
- package/dist/drivers/shared/deploy-script.d.ts +28 -12
- package/dist/drivers/shared/rpx-gateway.d.ts +99 -2
- package/dist/index.d.ts +2 -0
- package/dist/index.js +3381 -210
- package/dist/ui/index.html +83 -1
- package/dist/ui/server/actions.html +1193 -0
- package/dist/ui/server/activity.html +1132 -0
- package/dist/ui/server/backups.html +57 -1
- package/dist/ui/server/database.html +1208 -0
- package/dist/ui/server/deployments.html +79 -1
- package/dist/ui/server/diagnostics.html +1132 -0
- package/dist/ui/server/logs.html +1165 -0
- package/dist/ui/server/metrics.html +1 -1
- package/dist/ui/server/security.html +1132 -0
- package/dist/ui/server/services.html +57 -1
- package/dist/ui/server/sites.html +141 -1
- package/dist/ui/server/ssh-keys.html +58 -1
- package/dist/ui/server/workers.html +57 -1
- package/dist/ui/serverless/assets.html +1 -1
- package/dist/ui/serverless/cost.html +1 -1
- package/dist/ui/serverless/data.html +1 -1
- package/dist/ui/serverless/deployments.html +1 -1
- package/dist/ui/serverless/firewall.html +1 -1
- package/dist/ui/serverless/functions.html +1 -1
- package/dist/ui/serverless/logs.html +1165 -0
- package/dist/ui/serverless/metrics.html +1 -1
- package/dist/ui/serverless/queues.html +1 -1
- package/dist/ui/serverless/scheduler.html +1 -1
- package/dist/ui/serverless/secrets.html +1 -1
- package/dist/ui/serverless.html +1 -1
- package/dist/ui-src/package.json +5 -0
- package/dist/ui-src/pages/index.stx +308 -0
- package/dist/ui-src/pages/partials/head.stx +294 -0
- package/dist/ui-src/pages/partials/nav.stx +54 -0
- package/dist/ui-src/pages/partials/op-confirm.stx +7 -0
- package/dist/ui-src/pages/server/actions.stx +60 -0
- package/dist/ui-src/pages/server/activity.stx +55 -0
- package/dist/ui-src/pages/server/backups.stx +91 -0
- package/dist/ui-src/pages/server/database.stx +119 -0
- package/dist/ui-src/pages/server/deployments.stx +106 -0
- package/dist/ui-src/pages/server/diagnostics.stx +88 -0
- package/dist/ui-src/pages/server/logs.stx +84 -0
- package/dist/ui-src/pages/server/metrics.stx +183 -0
- package/dist/ui-src/pages/server/security.stx +127 -0
- package/dist/ui-src/pages/server/services.stx +82 -0
- package/dist/ui-src/pages/server/sites.stx +143 -0
- package/dist/ui-src/pages/server/ssh-keys.stx +93 -0
- package/dist/ui-src/pages/server/workers.stx +99 -0
- package/dist/ui-src/pages/serverless/assets.stx +66 -0
- package/dist/ui-src/pages/serverless/cost.stx +149 -0
- package/dist/ui-src/pages/serverless/data.stx +76 -0
- package/dist/ui-src/pages/serverless/deployments.stx +56 -0
- package/dist/ui-src/pages/serverless/firewall.stx +58 -0
- package/dist/ui-src/pages/serverless/functions.stx +118 -0
- package/dist/ui-src/pages/serverless/logs.stx +84 -0
- package/dist/ui-src/pages/serverless/metrics.stx +76 -0
- package/dist/ui-src/pages/serverless/queues.stx +81 -0
- package/dist/ui-src/pages/serverless/scheduler.stx +60 -0
- package/dist/ui-src/pages/serverless/secrets.stx +55 -0
- package/dist/ui-src/pages/serverless.stx +222 -0
- package/dist/ui-src/src/charts.ts +17333 -0
- package/package.json +3 -3
|
@@ -2,13 +2,35 @@
|
|
|
2
2
|
* Resolve REAL server-dashboard data for a provisioned compute box. Runs a small
|
|
3
3
|
* metrics script over the active driver (SSM/SSH), parses the KEY=VALUE output,
|
|
4
4
|
* and derives sites/SSH/workers from the cloud config. Everything is best-effort:
|
|
5
|
-
* if no box is reachable it returns
|
|
5
|
+
* if no box is reachable it returns config-derived data marked unavailable.
|
|
6
6
|
*/
|
|
7
7
|
import type { CloudConfig, EnvironmentType } from '@ts-cloud/core';
|
|
8
|
+
interface ProbedService {
|
|
9
|
+
name: string;
|
|
10
|
+
status: string;
|
|
11
|
+
memBytes?: number;
|
|
12
|
+
enabled?: string;
|
|
13
|
+
since?: string;
|
|
14
|
+
}
|
|
8
15
|
export declare function parseBlock(output: string): Record<string, string> & {
|
|
9
|
-
services:
|
|
10
|
-
name: string;
|
|
11
|
-
status: string;
|
|
12
|
-
}>;
|
|
16
|
+
services: ProbedService[];
|
|
13
17
|
};
|
|
18
|
+
interface ServerLogSource {
|
|
19
|
+
/** journalctl `-u` pattern (a unit name or a glob like `acme-web-queue-*`). */
|
|
20
|
+
pattern: string;
|
|
21
|
+
/** Clean source label shown + filtered on in the UI. */
|
|
22
|
+
label: string;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Every log source on the box: the web server, each managed service, and per
|
|
26
|
+
* server-app site the app service PLUS its queue workers and daemons (collected
|
|
27
|
+
* via journalctl unit globs so all worker instances are covered, not just the
|
|
28
|
+
* main service). Deduped by label.
|
|
29
|
+
*/
|
|
30
|
+
export declare function serverLogSources(config: CloudConfig): ServerLogSource[];
|
|
31
|
+
export declare function parseServerLogs(output: string): Array<Record<string, any>>;
|
|
32
|
+
export declare function parseServerSecurity(output: string): Record<string, any>;
|
|
33
|
+
export declare function parseDeployHistory(output: string, sites?: Record<string, any>): Array<Record<string, any>>;
|
|
34
|
+
export declare function resolveConfigOnlyServerDashboardData(config: CloudConfig, environment: EnvironmentType): Record<string, any>;
|
|
14
35
|
export declare function resolveServerDashboardData(config: CloudConfig, environment: EnvironmentType): Promise<Record<string, any> | null>;
|
|
36
|
+
export {};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Database & user management for the cockpit: list databases/users and create a
|
|
3
|
+
* database or an app user over the active driver. MySQL/MariaDB run as root via
|
|
4
|
+
* the pantry UNIX socket; Postgres over local TCP — mirroring the provisioning
|
|
5
|
+
* path in {@link import('../drivers/shared/db-provision')}.
|
|
6
|
+
*/
|
|
7
|
+
import type { CloudConfig, EnvironmentType } from '@ts-cloud/core';
|
|
8
|
+
export type DbEngine = 'mysql' | 'mariadb' | 'postgres';
|
|
9
|
+
/** Valid SQL identifier for a database/user name (kept strict for safety). */
|
|
10
|
+
export declare function isValidDbIdentifier(value: string): boolean;
|
|
11
|
+
export declare function resolveDbEngine(config: CloudConfig): DbEngine;
|
|
12
|
+
export declare function buildListScript(engine: DbEngine): string[];
|
|
13
|
+
export declare function buildCreateDatabaseScript(engine: DbEngine, name: string): string[];
|
|
14
|
+
export interface CreateUserInput {
|
|
15
|
+
username: string;
|
|
16
|
+
password: string;
|
|
17
|
+
database?: string;
|
|
18
|
+
access?: 'all' | 'readonly';
|
|
19
|
+
}
|
|
20
|
+
export declare function buildCreateUserScript(engine: DbEngine, input: CreateUserInput): string[];
|
|
21
|
+
export declare function parseDbList(output: string): {
|
|
22
|
+
databases: string[];
|
|
23
|
+
users: string[];
|
|
24
|
+
};
|
|
25
|
+
interface DbRunResult {
|
|
26
|
+
ok: boolean;
|
|
27
|
+
stdout?: string;
|
|
28
|
+
stderr?: string;
|
|
29
|
+
error?: string;
|
|
30
|
+
}
|
|
31
|
+
export declare function listDatabases(config: CloudConfig, environment: EnvironmentType): Promise<DbRunResult & {
|
|
32
|
+
engine: DbEngine;
|
|
33
|
+
databases: string[];
|
|
34
|
+
users: string[];
|
|
35
|
+
}>;
|
|
36
|
+
export declare function createDatabase(config: CloudConfig, environment: EnvironmentType, name: string): Promise<DbRunResult>;
|
|
37
|
+
export declare function createDatabaseUser(config: CloudConfig, environment: EnvironmentType, input: CreateUserInput): Promise<DbRunResult>;
|
|
38
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generalized server operations for the management cockpit: service lifecycle
|
|
3
|
+
* (restart/reload/start/stop/enable/disable), deployment rollback, scheduled
|
|
4
|
+
* backup run + database restore, worker restart, and scheduler run-now.
|
|
5
|
+
*
|
|
6
|
+
* The catalog is derived purely from the cloud config + live server data (so it
|
|
7
|
+
* is trivially unit-testable); the runner dispatches each operation over the
|
|
8
|
+
* active driver (SSH/SSM), reusing the shared compute-ops builders.
|
|
9
|
+
*/
|
|
10
|
+
import type { CloudConfig, EnvironmentType } from '@ts-cloud/core';
|
|
11
|
+
export type OperationGroup = 'service' | 'deploy' | 'backup' | 'worker' | 'scheduler';
|
|
12
|
+
export interface DashboardOperation {
|
|
13
|
+
id: string;
|
|
14
|
+
label: string;
|
|
15
|
+
group: OperationGroup;
|
|
16
|
+
target: string;
|
|
17
|
+
mutates: boolean;
|
|
18
|
+
/** Token the operator must type to run a mutating operation. */
|
|
19
|
+
confirm: string;
|
|
20
|
+
/** Destructive operations rendered with a danger affordance. */
|
|
21
|
+
danger?: boolean;
|
|
22
|
+
}
|
|
23
|
+
export interface DashboardOperationResult {
|
|
24
|
+
operation: string;
|
|
25
|
+
command?: string;
|
|
26
|
+
ok: boolean;
|
|
27
|
+
stdout?: string;
|
|
28
|
+
stderr?: string;
|
|
29
|
+
error?: string;
|
|
30
|
+
}
|
|
31
|
+
/** Guard systemd unit names so an operation id can never inject shell. */
|
|
32
|
+
export declare function isSafeSystemdUnit(value: string): boolean;
|
|
33
|
+
/**
|
|
34
|
+
* Build the full operation catalog from config + live server data. Pure: every
|
|
35
|
+
* operation that appears here is runnable by {@link runDashboardOperation}.
|
|
36
|
+
*/
|
|
37
|
+
export declare function buildDashboardOperations(config: CloudConfig, data: Record<string, any>): DashboardOperation[];
|
|
38
|
+
export declare function resolveDashboardOperation(id: string, config: CloudConfig, data: Record<string, any>): DashboardOperation | undefined;
|
|
39
|
+
/**
|
|
40
|
+
* Run an operation over the active driver. Rollback + DB restore delegate to the
|
|
41
|
+
* shared compute-ops; the rest run a single bounded remote script on the app
|
|
42
|
+
* target. Returns a structured result (never throws on a remote failure).
|
|
43
|
+
*/
|
|
44
|
+
export interface RunOperationOptions {
|
|
45
|
+
/** For rollback: the release id to roll back to (omit for the previous release). */
|
|
46
|
+
to?: string;
|
|
47
|
+
}
|
|
48
|
+
export declare function runDashboardOperation(config: CloudConfig, environment: EnvironmentType, operation: DashboardOperation, options?: RunOperationOptions): Promise<DashboardOperationResult>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/deploy/index.d.ts
CHANGED
|
@@ -9,3 +9,4 @@ export * from './static-site-helper';
|
|
|
9
9
|
export { buildFunctionEnv, type CodeSource, deployServerlessApp, type DeployServerlessOptions, infraEnvFromOutputs, redeployServerlessApp, type ResolvedContext, rollbackServerlessApp, runRemoteCommand, setMaintenance, } from './serverless-app';
|
|
10
10
|
export { buildAndPushServerlessImage, type BuildImageOptions, type BuiltImage, } from './serverless-image';
|
|
11
11
|
export { type DashboardData, resolveDashboardData, } from './dashboard-data';
|
|
12
|
+
export { dashboardActions, resolveDashboardAction, sanitizeCloudConfig, startLocalDashboardServer, type DashboardAction, type LocalDashboardServer, type LocalDashboardServerOptions, } from './local-dashboard-server';
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { CloudConfig, EnvironmentType } from '@ts-cloud/core';
|
|
2
|
+
export interface LocalDashboardServerOptions {
|
|
3
|
+
host?: string;
|
|
4
|
+
port?: number;
|
|
5
|
+
cwd?: string;
|
|
6
|
+
environment?: EnvironmentType;
|
|
7
|
+
cliEntry?: string;
|
|
8
|
+
verbose?: boolean;
|
|
9
|
+
/**
|
|
10
|
+
* Box mode: the dashboard runs ON the provisioned server. Data resolution and
|
|
11
|
+
* operations execute against localhost (the {@link LocalBoxDriver}) instead of
|
|
12
|
+
* reaching out over SSH/SSM.
|
|
13
|
+
*/
|
|
14
|
+
box?: boolean;
|
|
15
|
+
}
|
|
16
|
+
export interface LocalDashboardServer {
|
|
17
|
+
url: string;
|
|
18
|
+
server: ReturnType<typeof Bun.serve>;
|
|
19
|
+
}
|
|
20
|
+
export interface DashboardAction {
|
|
21
|
+
id: string;
|
|
22
|
+
label: string;
|
|
23
|
+
description: string;
|
|
24
|
+
command: string[];
|
|
25
|
+
mutates: boolean;
|
|
26
|
+
confirm?: string;
|
|
27
|
+
}
|
|
28
|
+
export declare function sanitizeCloudConfig(config: CloudConfig): Record<string, any>;
|
|
29
|
+
export declare function dashboardActions(environment: EnvironmentType): DashboardAction[];
|
|
30
|
+
export declare function resolveDashboardAction(id: string, environment: EnvironmentType): DashboardAction | undefined;
|
|
31
|
+
export declare function startLocalDashboardServer(options?: LocalDashboardServerOptions): Promise<LocalDashboardServer>;
|
|
@@ -15,7 +15,9 @@
|
|
|
15
15
|
* - `TS_CLOUD_UI_REALM` browser auth realm
|
|
16
16
|
* - `TS_CLOUD_UI_DISABLE` set truthy to skip auto-deploy
|
|
17
17
|
*/
|
|
18
|
-
import type { CloudConfig } from '@
|
|
18
|
+
import type { CloudConfig } from '@ts-cloud/core';
|
|
19
|
+
/** Site key under which the management dashboard is auto-injected. */
|
|
20
|
+
export declare const MANAGEMENT_DASHBOARD_SITE = "dashboard";
|
|
19
21
|
export interface EnsureDashboardLogger {
|
|
20
22
|
info: (msg: string) => void;
|
|
21
23
|
warn: (msg: string) => void;
|
|
@@ -37,3 +39,21 @@ export declare function ensureManagementDashboard(config: CloudConfig, options?:
|
|
|
37
39
|
cwd?: string;
|
|
38
40
|
logger?: EnsureDashboardLogger;
|
|
39
41
|
}): CloudConfig;
|
|
42
|
+
export interface BuildDashboardArtifactOptions {
|
|
43
|
+
cwd?: string;
|
|
44
|
+
slug: string;
|
|
45
|
+
sha: string;
|
|
46
|
+
logger?: EnsureDashboardLogger;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Build the management-dashboard release tarball from its injected site config:
|
|
50
|
+
* run the UI `build` (when not already built), then package `site.root`. Returns
|
|
51
|
+
* the tarball path, or null when the UI cannot be built/found.
|
|
52
|
+
*
|
|
53
|
+
* Best-effort: the dashboard is auxiliary, so any failure logs and returns null
|
|
54
|
+
* rather than throwing — the surrounding app deploy must never be blocked by it.
|
|
55
|
+
*/
|
|
56
|
+
export declare function buildManagementDashboardArtifact(site: {
|
|
57
|
+
root?: string;
|
|
58
|
+
build?: string | false;
|
|
59
|
+
} | undefined, options: BuildDashboardArtifactOptions): string | null;
|
|
@@ -10,6 +10,43 @@ export interface AddSiteConfigInput {
|
|
|
10
10
|
port?: number;
|
|
11
11
|
type?: string;
|
|
12
12
|
pathRewriteStyle?: 'directory' | 'flat';
|
|
13
|
+
/** Per-site environment variables. */
|
|
14
|
+
env?: Record<string, string>;
|
|
15
|
+
/** TLS: `false` to disable, or `{ provider }` (e.g. letsencrypt). */
|
|
16
|
+
ssl?: boolean | {
|
|
17
|
+
provider?: string;
|
|
18
|
+
};
|
|
13
19
|
}
|
|
14
20
|
export declare function addSiteToCloudConfig(input: AddSiteConfigInput): string;
|
|
21
|
+
export interface RemoveSiteInput {
|
|
22
|
+
configText: string;
|
|
23
|
+
name: string;
|
|
24
|
+
}
|
|
25
|
+
/** Remove a site (its whole `name: { ... }` entry) from the sites block. */
|
|
26
|
+
export declare function removeSiteFromCloudConfig(input: RemoveSiteInput): string;
|
|
27
|
+
export interface UpdateSiteInput extends Omit<AddSiteConfigInput, 'configText'> {
|
|
28
|
+
configText: string;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Replace a site's definition with a regenerated one carrying the merged fields.
|
|
32
|
+
* Implemented as remove + add so it reuses the validated insert path (the site
|
|
33
|
+
* moves to the end of the sites block, which keeps the config valid).
|
|
34
|
+
*/
|
|
35
|
+
export declare function updateSiteInCloudConfig(input: UpdateSiteInput): string;
|
|
36
|
+
/**
|
|
37
|
+
* Set (or insert) a single property on a site, preserving every other field —
|
|
38
|
+
* the safe path for editing `ssl`/`env` on a site that may also carry queues,
|
|
39
|
+
* auth, etc. `valueText` is raw TS (use {@link renderSslValue}/{@link renderEnvValue}).
|
|
40
|
+
*/
|
|
41
|
+
export declare function setSitePropertyInCloudConfig(input: {
|
|
42
|
+
configText: string;
|
|
43
|
+
siteName: string;
|
|
44
|
+
key: string;
|
|
45
|
+
valueText: string;
|
|
46
|
+
}): string;
|
|
47
|
+
export declare function renderSslValue(ssl: boolean | {
|
|
48
|
+
provider?: string;
|
|
49
|
+
}): string;
|
|
50
|
+
export declare function renderStringValue(value: string): string;
|
|
51
|
+
export declare function renderEnvValue(env: Record<string, string>): string;
|
|
15
52
|
export declare function renderSiteSnippet(input: Omit<AddSiteConfigInput, 'configText'>): string;
|
|
@@ -6,8 +6,10 @@ import type { CloudConfig, SiteConfig, SiteDeployTarget } from '@ts-cloud/core';
|
|
|
6
6
|
* - `'server-static'` — `server` + no `start` (has static `root`): a static
|
|
7
7
|
* site built and shipped to `/var/www/<site>` on the box
|
|
8
8
|
* (served by the operator's own proxy, e.g. rpx + tlsx).
|
|
9
|
+
* - `'redirect'` — gateway-only: `redirect` is set. Nothing is shipped;
|
|
10
|
+
* the gateway answers `domain` with an HTTP redirect.
|
|
9
11
|
*/
|
|
10
|
-
export type SiteDeployKind = 'bucket' | 'server-app' | 'server-static' | 'server-php';
|
|
12
|
+
export type SiteDeployKind = 'bucket' | 'server-app' | 'server-static' | 'server-php' | 'redirect';
|
|
11
13
|
/**
|
|
12
14
|
* A PHP/Laravel site: deployed to the compute box via git clone into atomic
|
|
13
15
|
* release directories and served by nginx + php-fpm. Identified by a PHP
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { SshKeyConfig } from '@ts-cloud/core';
|
|
2
|
+
export interface AddSshKeyInput {
|
|
3
|
+
configText: string;
|
|
4
|
+
name: string;
|
|
5
|
+
publicKey: string;
|
|
6
|
+
existingKeys?: SshKeyConfig[];
|
|
7
|
+
}
|
|
8
|
+
export interface RemoveSshKeyInput {
|
|
9
|
+
configText: string;
|
|
10
|
+
name: string;
|
|
11
|
+
existingKeys?: SshKeyConfig[];
|
|
12
|
+
}
|
|
13
|
+
export interface ManagedSshKey {
|
|
14
|
+
name: string;
|
|
15
|
+
publicKey: string;
|
|
16
|
+
type: string;
|
|
17
|
+
fingerprint: string;
|
|
18
|
+
added: string;
|
|
19
|
+
}
|
|
20
|
+
export declare function addSshKeyToCloudConfig(input: AddSshKeyInput): string;
|
|
21
|
+
export declare function removeSshKeyFromCloudConfig(input: RemoveSshKeyInput): string;
|
|
22
|
+
export declare function describeSshKeys(keys?: SshKeyConfig[]): ManagedSshKey[];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -5,6 +5,10 @@ export interface CreateCloudDriverOptions {
|
|
|
5
5
|
}
|
|
6
6
|
/**
|
|
7
7
|
* Create a cloud infrastructure driver from configuration.
|
|
8
|
+
*
|
|
9
|
+
* In box mode (`TS_CLOUD_DASHBOARD_BOX`), every driver resolves to the
|
|
10
|
+
* {@link LocalBoxDriver} so the on-box management dashboard runs its metrics
|
|
11
|
+
* scripts and operations against localhost instead of reaching out over SSH/SSM.
|
|
8
12
|
*/
|
|
9
13
|
export declare function createCloudDriver(options: CreateCloudDriverOptions): CloudDriver;
|
|
10
14
|
/**
|
package/dist/drivers/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export * from './factory';
|
|
2
2
|
export { AwsDriver } from './aws/driver';
|
|
3
3
|
export { HetznerDriver } from './hetzner/driver';
|
|
4
|
+
export { isBoxMode, LocalBoxDriver } from './local-box/driver';
|
|
4
5
|
export { HetznerClient, resolveHetznerApiToken } from './hetzner/client';
|
|
5
6
|
export { generateUbuntuAppCloudInit, wrapCloudInitUserData } from './hetzner/cloud-init';
|
|
6
7
|
export { buildAwsArtifactFetch, buildLocalArtifactFetch, buildSiteDeployScript, buildStaticSiteDeployScript, resolveExecStart, } from './shared/deploy-script';
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { CloudDriver, ComputeStackOutputs, ComputeTarget, FindComputeTargetsOptions, RemoteDeployResult, RunRemoteDeployOptions, UploadReleaseOptions, UploadReleaseResult } from '@ts-cloud/core';
|
|
2
|
+
/**
|
|
3
|
+
* A {@link CloudDriver} that runs every "remote" command on the LOCAL machine.
|
|
4
|
+
*
|
|
5
|
+
* Used when the management dashboard runs ON a provisioned server (box mode):
|
|
6
|
+
* data resolution and operations execute against localhost via `bash` instead of
|
|
7
|
+
* SSH/SSM, so the existing dashboard code path — metrics scripts, service ops,
|
|
8
|
+
* rollbacks — works unchanged on the box itself. The single synthetic target is
|
|
9
|
+
* the box; provisioning/upload methods are inert (the box is already up).
|
|
10
|
+
*/
|
|
11
|
+
export declare class LocalBoxDriver implements CloudDriver {
|
|
12
|
+
readonly name: "hetzner";
|
|
13
|
+
readonly usesCloudFormation = false;
|
|
14
|
+
getComputeOutputs(): Promise<ComputeStackOutputs>;
|
|
15
|
+
uploadRelease(options: UploadReleaseOptions): Promise<UploadReleaseResult>;
|
|
16
|
+
findComputeTargets(_options: FindComputeTargetsOptions): Promise<ComputeTarget[]>;
|
|
17
|
+
runRemoteDeploy(options: RunRemoteDeployOptions): Promise<RemoteDeployResult>;
|
|
18
|
+
}
|
|
19
|
+
/** Truthy-env check shared by the box-mode gate. */
|
|
20
|
+
export declare function isBoxMode(): boolean;
|
|
@@ -18,6 +18,8 @@ export interface DeployAllSitesOptions {
|
|
|
18
18
|
runtime: 'bun' | 'node' | 'deno' | 'php';
|
|
19
19
|
tarballForSite: (siteName: string) => string;
|
|
20
20
|
logger?: ComputeDeployLogger;
|
|
21
|
+
/** Project root used to resolve/build the management dashboard UI. Defaults to `process.cwd()`. */
|
|
22
|
+
cwd?: string;
|
|
21
23
|
}
|
|
22
24
|
/**
|
|
23
25
|
* Deploy every site that targets the compute server — both dynamic apps
|
|
@@ -8,40 +8,56 @@ export interface BuildSiteDeployScriptOptions {
|
|
|
8
8
|
slug: string;
|
|
9
9
|
/** How the remote host obtains the release tarball */
|
|
10
10
|
artifactFetch: string[];
|
|
11
|
+
/** Site base dir holding `releases/`, `shared/`, `current`. Default `/var/www/<site>`. */
|
|
11
12
|
appDir?: string;
|
|
13
|
+
/** Unique id for this release dir (typically the commit sha). */
|
|
14
|
+
releaseId: string;
|
|
12
15
|
execStart: string;
|
|
13
16
|
envEntries: Record<string, string>;
|
|
14
17
|
port?: number;
|
|
18
|
+
/** Past releases to keep for rollback. @default {@link DEFAULT_KEEP_RELEASES} */
|
|
19
|
+
keepReleases?: number;
|
|
15
20
|
/**
|
|
16
|
-
* Commands run inside
|
|
17
|
-
*
|
|
18
|
-
* and/or build steps (e.g.
|
|
19
|
-
* so the
|
|
21
|
+
* Commands run inside the new release dir after extraction + `.env` link,
|
|
22
|
+
* before the `current` symlink is repointed and the service restarted.
|
|
23
|
+
* Typically dependency install and/or build steps (e.g.
|
|
24
|
+
* `bun install --frozen-lockfile`, `bun run build`) so the tarball can omit
|
|
25
|
+
* `node_modules`.
|
|
20
26
|
*/
|
|
21
27
|
preStartCommands?: string[];
|
|
22
28
|
}
|
|
23
29
|
/**
|
|
24
|
-
* Build the remote shell commands that install/refresh a site on a
|
|
30
|
+
* Build the remote shell commands that install/refresh a server-app site on a
|
|
31
|
+
* compute target with a **zero-downtime atomic release** (Envoyer-style): unpack
|
|
32
|
+
* into `releases/<id>`, link the shared `.env`, build, then atomically repoint
|
|
33
|
+
* `current` and restart the systemd service (which runs from `current`). Old
|
|
34
|
+
* releases are pruned for rollback.
|
|
25
35
|
*/
|
|
26
36
|
export declare function buildSiteDeployScript(options: BuildSiteDeployScriptOptions): string[];
|
|
27
37
|
export interface BuildStaticSiteDeployScriptOptions {
|
|
28
38
|
siteName: string;
|
|
29
39
|
/** How the remote host obtains the release tarball */
|
|
30
40
|
artifactFetch: string[];
|
|
31
|
-
/**
|
|
41
|
+
/** Site base dir holding `releases/`, `current`. Default `/var/www/<site>`. */
|
|
32
42
|
appDir?: string;
|
|
43
|
+
/** Unique id for this release dir (typically the commit sha). */
|
|
44
|
+
releaseId: string;
|
|
45
|
+
/** Past releases to keep for rollback. @default {@link DEFAULT_KEEP_RELEASES} */
|
|
46
|
+
keepReleases?: number;
|
|
33
47
|
/**
|
|
34
|
-
* Commands run inside
|
|
35
|
-
* the box itself (`bun install`, `bun run docs:build`) when the
|
|
36
|
-
* source rather than a pre-built site.
|
|
48
|
+
* Commands run inside the new release dir after extraction — e.g. build the
|
|
49
|
+
* docs/blog on the box itself (`bun install`, `bun run docs:build`) when the
|
|
50
|
+
* tarball ships source rather than a pre-built site.
|
|
37
51
|
*/
|
|
38
52
|
preStartCommands?: string[];
|
|
39
53
|
}
|
|
40
54
|
/**
|
|
41
55
|
* Build the remote shell commands that install/refresh a STATIC site on a
|
|
42
|
-
* compute target
|
|
43
|
-
*
|
|
44
|
-
*
|
|
56
|
+
* compute target with a **zero-downtime atomic release** (Envoyer-style). Unlike
|
|
57
|
+
* {@link buildSiteDeployScript}, there is no systemd service: the artifact is
|
|
58
|
+
* unpacked into `releases/<id>` and `current` is repointed atomically, so the
|
|
59
|
+
* docroot is never empty mid-deploy. The gateway serves `<base>/current` (rpx +
|
|
60
|
+
* tlsx), which ts-cloud points at the symlink. Old releases are pruned.
|
|
45
61
|
*/
|
|
46
62
|
export declare function buildStaticSiteDeployScript(options: BuildStaticSiteDeployScriptOptions): string[];
|
|
47
63
|
export declare function buildAwsArtifactFetch(bucket: string, key: string, region: string, siteName: string): string[];
|
|
@@ -17,9 +17,23 @@
|
|
|
17
17
|
* It replaces the old Caddyfile generation — pantry/stacks use rpx (their own
|
|
18
18
|
* tooling), so the gateway is rpx, not Caddy.
|
|
19
19
|
*/
|
|
20
|
-
import type { ComputeProxyConfig, SiteConfig } from '@ts-cloud/core';
|
|
20
|
+
import type { ComputeProxyConfig, SiteConfig, SiteRedirectConfig } from '@ts-cloud/core';
|
|
21
21
|
/** Default directory on the box that holds real per-domain TLS certs. */
|
|
22
22
|
export declare const DEFAULT_RPX_CERTS_DIR = "/etc/rpx/certs";
|
|
23
|
+
/** Default webroot the gateway serves ACME http-01 challenges from on `:80`. */
|
|
24
|
+
export declare const DEFAULT_ACME_WEBROOT = "/var/www/acme-challenge";
|
|
25
|
+
/** A normalized redirect target on an {@link RpxRoute} (see rpx's `redirect`). */
|
|
26
|
+
export interface RpxRedirect {
|
|
27
|
+
to: string;
|
|
28
|
+
status?: 301 | 302 | 307 | 308;
|
|
29
|
+
preservePath?: boolean;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Normalize a site's `redirect` (string shorthand or object) into the minimal
|
|
33
|
+
* {@link RpxRedirect} the gateway config carries. Optional fields are omitted
|
|
34
|
+
* when unset so rpx applies its own defaults (status `301`, path-preserving).
|
|
35
|
+
*/
|
|
36
|
+
export declare function normalizeSiteRedirect(input: string | SiteRedirectConfig): RpxRedirect;
|
|
23
37
|
/** A single rpx proxy route, mapped from one site. */
|
|
24
38
|
export interface RpxRoute {
|
|
25
39
|
/** Public host this route is served under (the site's `domain`). */
|
|
@@ -30,13 +44,36 @@ export interface RpxRoute {
|
|
|
30
44
|
from?: string;
|
|
31
45
|
/** Absolute directory served for a `server-static` route (`/var/www/<name>`). */
|
|
32
46
|
static?: string;
|
|
47
|
+
/**
|
|
48
|
+
* Redirect target for a `redirect` site — the gateway answers `to` (the host)
|
|
49
|
+
* with an HTTP redirect here instead of proxying/serving. The request path +
|
|
50
|
+
* query are appended unless `preservePath` is `false`.
|
|
51
|
+
*/
|
|
52
|
+
redirect?: RpxRedirect;
|
|
33
53
|
/** Strip `.html` and resolve clean URLs (set for static sites). */
|
|
34
54
|
cleanUrls?: boolean;
|
|
35
55
|
/** SPA fallback for static sites. */
|
|
36
56
|
spa?: boolean;
|
|
57
|
+
/**
|
|
58
|
+
* HTTP Basic auth gate for this route (from the site's `auth`). rpx challenges
|
|
59
|
+
* every request to the route until valid credentials are supplied — this is
|
|
60
|
+
* how the management dashboard (and other protected sites) stay private behind
|
|
61
|
+
* rpx, the same way the nginx driver applies htpasswd.
|
|
62
|
+
*/
|
|
63
|
+
auth?: {
|
|
64
|
+
username: string;
|
|
65
|
+
password: string;
|
|
66
|
+
realm?: string;
|
|
67
|
+
};
|
|
37
68
|
/** Stable id used when rpx registers the route. Derived from `to`+`path`. */
|
|
38
69
|
id: string;
|
|
39
70
|
}
|
|
71
|
+
/**
|
|
72
|
+
* Resolve a site's `auth` into the rpx route auth shape, or `undefined` when the
|
|
73
|
+
* site is public. Mirrors the management-dashboard preset: auth applies only when
|
|
74
|
+
* enabled (default) AND a password is present — no password is ever invented.
|
|
75
|
+
*/
|
|
76
|
+
export declare function resolveRouteAuth(site: SiteConfig): RpxRoute['auth'];
|
|
40
77
|
/** The rpx daemon/proxy config produced from a sites model. */
|
|
41
78
|
export interface RpxGatewayConfig {
|
|
42
79
|
/** Multi-proxy route list (host + path keyed). */
|
|
@@ -58,6 +95,13 @@ export interface RpxGatewayConfig {
|
|
|
58
95
|
email?: string;
|
|
59
96
|
certsDir: string;
|
|
60
97
|
};
|
|
98
|
+
/**
|
|
99
|
+
* Directory the gateway serves ACME http-01 challenge tokens from on `:80`
|
|
100
|
+
* before redirecting to HTTPS. Set when ts-cloud manages certs so the renewal
|
|
101
|
+
* cron (`tlsx acme:renew --webroot`) can issue/renew without taking the gateway
|
|
102
|
+
* down to free `:80`. Omitted ⇒ the `:80` server only redirects.
|
|
103
|
+
*/
|
|
104
|
+
acmeChallengeWebroot?: string;
|
|
61
105
|
/** Always `true` — the gateway terminates TLS on the box. */
|
|
62
106
|
https: true;
|
|
63
107
|
/** Never touch `/etc/hosts` on a real server with real DNS. */
|
|
@@ -104,21 +148,74 @@ export declare function buildRpxConfig(sites: Record<string, SiteConfig | undefi
|
|
|
104
148
|
/**
|
|
105
149
|
* Render the rpx gateway config as a self-contained launcher TS module. The
|
|
106
150
|
* systemd unit runs `bun <file>`, which imports `startProxies` from the
|
|
107
|
-
*
|
|
151
|
+
* managed `/opt/rpx-gateway` install and starts the gateway with the generated
|
|
108
152
|
* options. We ship a runnable launcher (not a bare config) because rpx's CLI
|
|
109
153
|
* resolves its own config from its install dir, not an arbitrary path.
|
|
110
154
|
*/
|
|
111
155
|
export declare function renderRpxLauncher(config: RpxGatewayConfig): string;
|
|
112
156
|
/** Default install location for the gateway launcher + config on the box. */
|
|
113
157
|
export declare const RPX_DIR = "/etc/rpx";
|
|
158
|
+
export declare const RPX_INSTALL_DIR = "/opt/rpx-gateway";
|
|
114
159
|
export declare const RPX_LAUNCHER_PATH = "/etc/rpx/gateway.ts";
|
|
115
160
|
export declare const RPX_SERVICE_NAME = "rpx-gateway.service";
|
|
161
|
+
/**
|
|
162
|
+
* Per-app gateway registry. Each project's deploy writes ONLY its own fragment
|
|
163
|
+
* (`<slug>.json`) here; the launcher ({@link renderRpxAssembler}) merges every
|
|
164
|
+
* fragment at startup. So several independent apps share one box's gateway
|
|
165
|
+
* Forge-style — one app's deploy never clobbers another's routes.
|
|
166
|
+
*/
|
|
167
|
+
export declare const RPX_SITES_DIR = "/etc/rpx/sites.d";
|
|
168
|
+
/** A registry fragment: one project's gateway config, tagged with its slug. */
|
|
169
|
+
export type RpxFragment = RpxGatewayConfig & {
|
|
170
|
+
slug: string;
|
|
171
|
+
};
|
|
172
|
+
/**
|
|
173
|
+
* Merge per-app fragments into one gateway config (the runtime equivalent of
|
|
174
|
+
* what {@link renderRpxAssembler} does on the box, exported for testing).
|
|
175
|
+
*
|
|
176
|
+
* Routes are concatenated (deduped by `id`, first writer wins); on-demand
|
|
177
|
+
* suffixes and origin-guard hosts are unioned; the first non-empty email /
|
|
178
|
+
* certsDir / acmeChallengeWebroot / origin-guard header+secret wins. Fragments
|
|
179
|
+
* are applied in the given order (the box sorts them by filename).
|
|
180
|
+
*/
|
|
181
|
+
export declare function mergeRpxFragments(fragments: RpxGatewayConfig[]): RpxGatewayConfig;
|
|
182
|
+
/**
|
|
183
|
+
* Render the stable assembler launcher. Its content is identical for every app
|
|
184
|
+
* and every deploy — it reads all `<slug>.json` fragments from {@link RPX_SITES_DIR}
|
|
185
|
+
* at startup, merges them (same algorithm as {@link mergeRpxFragments}), and
|
|
186
|
+
* starts the gateway. A malformed fragment is skipped, not fatal.
|
|
187
|
+
*/
|
|
188
|
+
export declare function renderRpxAssembler(sitesDir?: string, defaultCertsDir?: string): string;
|
|
116
189
|
export interface BuildRpxProvisionOptions {
|
|
117
190
|
config: RpxGatewayConfig;
|
|
118
191
|
proxy: ComputeProxyConfig;
|
|
192
|
+
/**
|
|
193
|
+
* This project's slug — the registry fragment is written to
|
|
194
|
+
* `<sites.d>/<slug>.json`. So a box can host several independent apps and each
|
|
195
|
+
* deploy only rewrites its own fragment. Defaults to `'app'` for single-app
|
|
196
|
+
* boxes / backward compatibility.
|
|
197
|
+
*/
|
|
198
|
+
slug?: string;
|
|
119
199
|
/** Absolute path to the `bun` binary on the box. @default '/usr/local/bin/bun' */
|
|
120
200
|
bunBin?: string;
|
|
121
201
|
}
|
|
202
|
+
export declare const RPX_CERT_RENEW_SCRIPT = "/etc/rpx/renew-certs.sh";
|
|
203
|
+
export declare const RPX_CERT_RENEW_SERVICE = "rpx-cert-renew.service";
|
|
204
|
+
export declare const RPX_CERT_RENEW_TIMER = "rpx-cert-renew.timer";
|
|
205
|
+
/** The routable FQDNs in a gateway config — each terminates TLS so each needs a cert. */
|
|
206
|
+
export declare function certDomainsForConfig(config: RpxGatewayConfig): string[];
|
|
207
|
+
/**
|
|
208
|
+
* Commands that make ts-cloud manage the gateway's TLS certs end-to-end: install
|
|
209
|
+
* tlsx, issue a Let's Encrypt cert for every routed domain via http-01 (the
|
|
210
|
+
* running gateway serves the challenge from {@link RpxGatewayConfig.acmeChallengeWebroot}
|
|
211
|
+
* on `:80`, so no downtime), and a daily systemd timer that renews anything
|
|
212
|
+
* expiring within 30 days and reloads the gateway only when a cert changed.
|
|
213
|
+
*
|
|
214
|
+
* Returns `[]` (no-op) unless on-demand/managed TLS is enabled and there's at
|
|
215
|
+
* least one routable domain. Must run AFTER the gateway is started so the
|
|
216
|
+
* challenge listener is live.
|
|
217
|
+
*/
|
|
218
|
+
export declare function buildCertManagementCommands(options: BuildRpxProvisionOptions): string[];
|
|
122
219
|
/**
|
|
123
220
|
* Build the idempotent, re-runnable shell commands that install rpx as the
|
|
124
221
|
* gateway, write the generated launcher + ensure the certs dir, install the
|
package/dist/index.d.ts
CHANGED
|
@@ -13,6 +13,8 @@ export { deployStaticSite, deployStaticSiteFull, uploadStaticFiles, invalidateCa
|
|
|
13
13
|
export type { StaticSiteConfig, DeployResult, UploadOptions, ExternalDnsStaticSiteConfig, ExternalDnsDeployResult, DeploySiteConfig, DeploySiteResult, StaticSiteDnsProvider, SiteDeployKind, DeploymentValidationResult, BuildImageOptions, BuiltImage, CodeSource, DeployServerlessOptions, ResolvedContext, } from './deploy';
|
|
14
14
|
export { createCloudDriver, CloudDriverFactory, cloudDrivers, AwsDriver, HetznerDriver, HetznerClient, resolveHetznerApiToken, generateUbuntuAppCloudInit, wrapCloudInitUserData, buildSiteDeployScript, buildStaticSiteDeployScript, resolveExecStart, deployAllComputeSites, deploySiteRelease, } from './drivers';
|
|
15
15
|
export type { CreateCloudDriverOptions } from './drivers/factory';
|
|
16
|
+
export { dashboardActions, resolveDashboardAction, sanitizeCloudConfig, startLocalDashboardServer, } from './deploy/local-dashboard-server';
|
|
17
|
+
export type { DashboardAction, LocalDashboardServer, LocalDashboardServerOptions, } from './deploy/local-dashboard-server';
|
|
16
18
|
export { createDnsProvider, detectDnsProvider, DnsProviderFactory, dnsProviders, PorkbunProvider, GoDaddyProvider, Route53Provider, UnifiedDnsValidator, createPorkbunValidator, createGoDaddyValidator, createRoute53Validator, } from './dns';
|
|
17
19
|
export type { DnsProvider, DnsProviderConfig, DnsRecord, DnsRecordType, DnsRecordResult, CreateRecordResult, DeleteRecordResult, ListRecordsResult, } from './dns';
|
|
18
20
|
export * from '@ts-cloud/core';
|