@stacksjs/ts-cloud 0.2.23 → 0.2.25

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.
@@ -2,10 +2,10 @@ import type { CloudConfig, SiteConfig, SiteDeployTarget } from '@ts-cloud/core';
2
2
  /**
3
3
  * The three resolved deployment kinds for a site:
4
4
  * - `'bucket'` — upload built `root` to object storage + CDN.
5
- * - `'server-app'` — `server` + `start`: dynamic app as a systemd service
6
- * behind the Caddy reverse proxy.
5
+ * - `'server-app'` — `server` + `start`: dynamic app as a systemd service.
7
6
  * - `'server-static'` — `server` + no `start` (has static `root`): a static
8
- * site built and served on the box via Caddy `file_server`.
7
+ * site built and shipped to `/var/www/<site>` on the box
8
+ * (served by the operator's own proxy, e.g. rpx + tlsx).
9
9
  */
10
10
  export type SiteDeployKind = 'bucket' | 'server-app' | 'server-static';
11
11
  /**
@@ -9,6 +9,13 @@ export interface UbuntuBootstrapOptions {
9
9
  systemPackages?: string[];
10
10
  database?: 'sqlite' | 'mysql' | 'postgres';
11
11
  caddyfile?: string;
12
+ /**
13
+ * Shell commands that install + start the rpx reverse-proxy gateway, built by
14
+ * {@link import('../shared/rpx-gateway').buildRpxProvisionScript}. Appended
15
+ * after the runtime is installed so `bun add -g @stacksjs/rpx` works. Mutually
16
+ * exclusive with `caddyfile` (the box runs one gateway).
17
+ */
18
+ rpxProvision?: string[];
12
19
  }
13
20
  export declare function generateUbuntuAppCloudInit(options?: UbuntuBootstrapOptions): string;
14
21
  /**
@@ -67,8 +67,9 @@ export declare class HetznerDriver implements CloudDriver {
67
67
  */
68
68
  private ensureFirewall;
69
69
  /**
70
- * Collect the upstream app ports that must be reachable when no reverse proxy
71
- * is fronting traffic (raw-port deploys). Drops 80/443 (handled separately).
70
+ * Collect the upstream app ports that must be reachable on the box. ts-cloud
71
+ * does not front traffic with its own proxy, so each site's app port is
72
+ * opened directly. Drops 80/443 (always handled by the firewall base rules).
72
73
  */
73
74
  private collectUpstreamPorts;
74
75
  private sleep;
@@ -81,8 +82,8 @@ export declare class HetznerDriver implements CloudDriver {
81
82
  private waitForSshReady;
82
83
  /**
83
84
  * Block until cloud-init finishes (`cloud-init status --wait`). cloud-init is
84
- * what installs the runtime + Caddy; deploying before it completes leaves the
85
- * release pointing at a half-provisioned box (missing `bun`, no Caddy).
85
+ * what installs the runtime; deploying before it completes leaves the
86
+ * release pointing at a half-provisioned box (missing `bun`).
86
87
  */
87
88
  private waitForCloudInit;
88
89
  private outputsFromState;
@@ -3,6 +3,7 @@ export { AwsDriver } from './aws/driver';
3
3
  export { HetznerDriver } from './hetzner/driver';
4
4
  export { HetznerClient, resolveHetznerApiToken } from './hetzner/client';
5
5
  export { generateUbuntuAppCloudInit, wrapCloudInitUserData } from './hetzner/cloud-init';
6
- export { buildCaddyfile, buildCaddyfileFromProxy, isOnDemandDomain, proxyConfigFromSites, resolveCaddyfile, staticSiteServerRoot, } from './shared/caddyfile';
7
6
  export { buildAwsArtifactFetch, buildLocalArtifactFetch, buildSiteDeployScript, buildStaticSiteDeployScript, resolveExecStart, } from './shared/deploy-script';
8
- export { deployAllComputeSites, deploySiteRelease } from './shared/compute-deploy';
7
+ export { deployAllComputeSites, deploySiteRelease, reloadRpxGateway } from './shared/compute-deploy';
8
+ export { buildRpxConfig, buildRpxProvisionScript, deriveRouteId, normalizeRoutePath, renderRpxLauncher, DEFAULT_RPX_CERTS_DIR, RPX_DIR, RPX_LAUNCHER_PATH, RPX_SERVICE_NAME, } from './shared/rpx-gateway';
9
+ export type { BuildRpxConfigOptions, BuildRpxProvisionOptions, RpxGatewayConfig, RpxRoute, } from './shared/rpx-gateway';
@@ -22,6 +22,13 @@ export interface DeployAllSitesOptions {
22
22
  /**
23
23
  * Deploy every site that targets the compute server — both dynamic apps
24
24
  * (`server` + `start`, run as systemd services) and static sites (`server`
25
- * without `start`, served by Caddy `file_server`). Bucket sites are skipped.
25
+ * without `start`, shipped to `/var/www/<site>`). Bucket sites are skipped.
26
26
  */
27
27
  export declare function deployAllComputeSites(options: DeployAllSitesOptions): Promise<boolean>;
28
+ /**
29
+ * Regenerate the rpx gateway config from the sites model and (re)start the
30
+ * gateway on the compute targets. No-op (returns `true`) unless
31
+ * `compute.proxy.engine === 'rpx'`. Re-runnable: the provision script writes the
32
+ * launcher + unit and `systemctl restart`s, which reloads the new routes.
33
+ */
34
+ export declare function reloadRpxGateway(options: DeployAllSitesOptions): Promise<boolean>;
@@ -31,7 +31,7 @@ export interface BuildStaticSiteDeployScriptOptions {
31
31
  siteName: string;
32
32
  /** How the remote host obtains the release tarball */
33
33
  artifactFetch: string[];
34
- /** Target directory served by Caddy `file_server`. Default `/var/www/<site>`. */
34
+ /** Target directory the static site is shipped to. Default `/var/www/<site>`. */
35
35
  appDir?: string;
36
36
  /**
37
37
  * Commands run inside `appDir` after extraction — e.g. build the docs/blog on
@@ -43,8 +43,8 @@ export interface BuildStaticSiteDeployScriptOptions {
43
43
  /**
44
44
  * Build the remote shell commands that install/refresh a STATIC site on a
45
45
  * compute target. Unlike {@link buildSiteDeployScript}, there is no systemd
46
- * service — the extracted files are served directly by Caddy `file_server`
47
- * (Caddy is reloaded separately when the Caddyfile changes).
46
+ * service — the extracted files are shipped to `/var/www/<site>` and served by
47
+ * the operator's own proxy (e.g. rpx + tlsx), which ts-cloud does not manage.
48
48
  */
49
49
  export declare function buildStaticSiteDeployScript(options: BuildStaticSiteDeployScriptOptions): string[];
50
50
  export declare function buildAwsArtifactFetch(bucket: string, key: string, region: string, siteName: string): string[];
@@ -0,0 +1,122 @@
1
+ /**
2
+ * Generate the rpx reverse-proxy gateway config + provisioning from the `sites`
3
+ * model.
4
+ *
5
+ * ts-cloud's per-site deploy model resolves each site to one of three kinds
6
+ * (see {@link import('../../deploy/site-target').resolveSiteKind}):
7
+ * - `server-app` — a dynamic app running on a port (systemd service);
8
+ * - `server-static` — a static site shipped to `/var/www/<name>`;
9
+ * - `bucket` — object storage + CDN (not on the box; ignored here).
10
+ *
11
+ * The rpx gateway fronts :80/:443 on the box and routes by host **and path**:
12
+ * several sites can share one `domain` on different `path`s (e.g.
13
+ * `stacksjs.com/api/*` → app on :3000, `stacksjs.com/docs*` → `/var/www/docs`,
14
+ * `stacksjs.com/` → `/var/www/public`). This module maps the sites model to the
15
+ * rpx `proxies` array so `buddy deploy` can ship the config + wire the gateway.
16
+ *
17
+ * It replaces the old Caddyfile generation — pantry/stacks use rpx (their own
18
+ * tooling), so the gateway is rpx, not Caddy.
19
+ */
20
+ import type { ComputeProxyConfig, SiteConfig } from '@ts-cloud/core';
21
+ /** Default directory on the box that holds real per-domain TLS certs. */
22
+ export declare const DEFAULT_RPX_CERTS_DIR = "/etc/rpx/certs";
23
+ /** A single rpx proxy route, mapped from one site. */
24
+ export interface RpxRoute {
25
+ /** Public host this route is served under (the site's `domain`). */
26
+ to: string;
27
+ /** Path prefix within the host this route owns (e.g. `/api`). Omitted = `/`. */
28
+ path?: string;
29
+ /** Upstream `host:port` for a `server-app` route. */
30
+ from?: string;
31
+ /** Absolute directory served for a `server-static` route (`/var/www/<name>`). */
32
+ static?: string;
33
+ /** Strip `.html` and resolve clean URLs (set for static sites). */
34
+ cleanUrls?: boolean;
35
+ /** SPA fallback for static sites. */
36
+ spa?: boolean;
37
+ /** Stable id used when rpx registers the route. Derived from `to`+`path`. */
38
+ id: string;
39
+ }
40
+ /** The rpx daemon/proxy config produced from a sites model. */
41
+ export interface RpxGatewayConfig {
42
+ /** Multi-proxy route list (host + path keyed). */
43
+ proxies: RpxRoute[];
44
+ /**
45
+ * Production per-domain SNI certs: rpx serves a real PEM per server name from
46
+ * this directory (`<domain>.crt` / `<domain>.key`).
47
+ */
48
+ productionCerts: {
49
+ certsDir: string;
50
+ };
51
+ /**
52
+ * On-demand TLS (opt-in): lazily issue a real cert for an approved host the
53
+ * first time it's needed. The site domains form the allowlist.
54
+ */
55
+ onDemandTls?: {
56
+ enabled: true;
57
+ allowedSuffixes: string[];
58
+ email?: string;
59
+ certsDir: string;
60
+ };
61
+ /** Always `true` — the gateway terminates TLS on the box. */
62
+ https: true;
63
+ /** Never touch `/etc/hosts` on a real server with real DNS. */
64
+ hostsManagement: false;
65
+ /** Don't remove certs/hosts on exit. */
66
+ cleanup: {
67
+ hosts: false;
68
+ certs: false;
69
+ };
70
+ }
71
+ export interface BuildRpxConfigOptions {
72
+ /** Proxy config from `infrastructure.compute.proxy`. */
73
+ proxy: ComputeProxyConfig;
74
+ /** Directory static sites are shipped to. @default '/var/www' */
75
+ wwwRoot?: string;
76
+ }
77
+ /**
78
+ * Normalize a path prefix to a leading-slash, no-trailing-slash form, or
79
+ * `undefined` for the host default. Mirrors rpx's `normalizePathPrefix`.
80
+ */
81
+ export declare function normalizeRoutePath(path: string | undefined): string | undefined;
82
+ /** Derive a stable, filesystem/registry-safe id from a host (+ optional path). */
83
+ export declare function deriveRouteId(to: string, path?: string): string;
84
+ /**
85
+ * Map the sites model to an rpx gateway config. Each non-bucket site with a
86
+ * `domain` becomes a route:
87
+ * - `server-app` → `{ to: domain, path, from: 'localhost:<port>' }`
88
+ * - `server-static` → `{ to: domain, path, static: '<wwwRoot>/<name>' }`
89
+ *
90
+ * Routes are grouped by domain so rpx's path-based routing can serve an app +
91
+ * several static dirs under one host. Bucket sites and sites without a `domain`
92
+ * (or a `server-app` without a `port`) are skipped.
93
+ */
94
+ export declare function buildRpxConfig(sites: Record<string, SiteConfig | undefined>, options: BuildRpxConfigOptions): RpxGatewayConfig;
95
+ /**
96
+ * Render the rpx gateway config as a self-contained launcher TS module. The
97
+ * systemd unit runs `bun <file>`, which imports `startProxies` from the
98
+ * globally-installed `@stacksjs/rpx` and starts the gateway with the generated
99
+ * options. We ship a runnable launcher (not a bare config) because rpx's CLI
100
+ * resolves its own config from its install dir, not an arbitrary path.
101
+ */
102
+ export declare function renderRpxLauncher(config: RpxGatewayConfig): string;
103
+ /** Default install location for the gateway launcher + config on the box. */
104
+ export declare const RPX_DIR = "/etc/rpx";
105
+ export declare const RPX_LAUNCHER_PATH = "/etc/rpx/gateway.ts";
106
+ export declare const RPX_SERVICE_NAME = "rpx-gateway.service";
107
+ export interface BuildRpxProvisionOptions {
108
+ config: RpxGatewayConfig;
109
+ proxy: ComputeProxyConfig;
110
+ /** Absolute path to the `bun` binary on the box. @default '/usr/local/bin/bun' */
111
+ bunBin?: string;
112
+ }
113
+ /**
114
+ * Build the idempotent, re-runnable shell commands that install rpx as the
115
+ * gateway, write the generated launcher + ensure the certs dir, install the
116
+ * systemd unit, and enable + (re)start it on :80/:443.
117
+ *
118
+ * Safe to run at first boot (cloud-init) and again on every deploy — the unit
119
+ * write + `systemctl restart` reloads the regenerated routes so new
120
+ * server-app/server-static sites appear in the gateway automatically.
121
+ */
122
+ export declare function buildRpxProvisionScript(options: BuildRpxProvisionOptions): string[];
package/dist/index.d.ts CHANGED
@@ -11,7 +11,7 @@ export type { MigrateEndpoint, MigrateError, MigrateOptions, MigratePlanItem, Mi
11
11
  export * from './ssl';
12
12
  export { deployStaticSite, deployStaticSiteFull, uploadStaticFiles, invalidateCache, deleteStaticSite, generateStaticSiteTemplate, deployStaticSiteWithExternalDns, deployStaticSiteWithExternalDnsFull, generateExternalDnsStaticSiteTemplate, deploySite, resolveSiteDeployTarget, resolveSiteKind, validateDeploymentConfig, } from './deploy';
13
13
  export type { StaticSiteConfig, DeployResult, UploadOptions, ExternalDnsStaticSiteConfig, ExternalDnsDeployResult, DeploySiteConfig, DeploySiteResult, StaticSiteDnsProvider, SiteDeployKind, DeploymentValidationResult, } from './deploy';
14
- export { createCloudDriver, CloudDriverFactory, cloudDrivers, AwsDriver, HetznerDriver, HetznerClient, resolveHetznerApiToken, generateUbuntuAppCloudInit, wrapCloudInitUserData, buildCaddyfile, buildCaddyfileFromProxy, isOnDemandDomain, proxyConfigFromSites, resolveCaddyfile, staticSiteServerRoot, buildSiteDeployScript, buildStaticSiteDeployScript, resolveExecStart, deployAllComputeSites, deploySiteRelease, } from './drivers';
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
16
  export { createDnsProvider, detectDnsProvider, DnsProviderFactory, dnsProviders, PorkbunProvider, GoDaddyProvider, Route53Provider, UnifiedDnsValidator, createPorkbunValidator, createGoDaddyValidator, createRoute53Validator, } from './dns';
17
17
  export type { DnsProvider, DnsProviderConfig, DnsRecord, DnsRecordType, DnsRecordResult, CreateRecordResult, DeleteRecordResult, ListRecordsResult, } from './dns';