@stacksjs/ts-cloud 0.2.26 → 0.3.0

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 (38) hide show
  1. package/dist/aws/ec2.d.ts +23 -0
  2. package/dist/aws/lambda.d.ts +17 -2
  3. package/dist/bin/cli.js +1012 -914
  4. package/dist/deploy/serverless-app.d.ts +53 -0
  5. package/dist/deploy/serverless-app.test.d.ts +1 -0
  6. package/dist/deploy/serverless-image.d.ts +32 -0
  7. package/dist/deploy/site-target.d.ts +7 -1
  8. package/dist/drivers/aws/driver.d.ts +21 -0
  9. package/dist/drivers/aws/provision.d.ts +41 -0
  10. package/dist/drivers/hetzner/client.d.ts +46 -0
  11. package/dist/drivers/hetzner/cloud-init.d.ts +7 -18
  12. package/dist/drivers/hetzner/driver.d.ts +24 -0
  13. package/dist/drivers/hetzner/state.d.ts +8 -2
  14. package/dist/drivers/shared/backups.d.ts +28 -0
  15. package/dist/drivers/shared/certbot.d.ts +38 -0
  16. package/dist/drivers/shared/compute-deploy.d.ts +1 -1
  17. package/dist/drivers/shared/compute-provision.d.ts +29 -0
  18. package/dist/drivers/shared/db-provision.d.ts +34 -0
  19. package/dist/drivers/shared/deploy-script.d.ts +0 -3
  20. package/dist/drivers/shared/env-file.d.ts +12 -0
  21. package/dist/drivers/shared/fleet.d.ts +34 -0
  22. package/dist/drivers/shared/git-deploy.d.ts +36 -0
  23. package/dist/drivers/shared/image-recipe.d.ts +40 -0
  24. package/dist/drivers/shared/laravel-deploy.d.ts +42 -0
  25. package/dist/drivers/shared/laravel-services.d.ts +36 -0
  26. package/dist/drivers/shared/maintenance.d.ts +10 -0
  27. package/dist/drivers/shared/monitoring.d.ts +15 -0
  28. package/dist/drivers/shared/nginx-vhost.d.ts +88 -0
  29. package/dist/drivers/shared/notifications.d.ts +40 -0
  30. package/dist/drivers/shared/package-manager.d.ts +84 -0
  31. package/dist/drivers/shared/php-provision.d.ts +36 -0
  32. package/dist/drivers/shared/releases.d.ts +52 -0
  33. package/dist/drivers/shared/ssh-keys.d.ts +21 -0
  34. package/dist/drivers/shared/ubuntu-bootstrap.d.ts +54 -0
  35. package/dist/drivers/shared/ufw.d.ts +17 -0
  36. package/dist/index.js +38356 -35292
  37. package/dist/security/pre-deploy-scanner.d.ts +12 -0
  38. package/package.json +3 -3
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Assemble the remote deploy script for a Forge-style PHP/Laravel site: a
3
+ * git-clone-on-server, zero-downtime atomic-release deploy.
4
+ *
5
+ * The deploy script is a list of steps run in order on the box. Three Forge
6
+ * macros expand to the release machinery:
7
+ * $CREATE_RELEASE — clone the repo into a new release dir, link shared
8
+ * paths, and `cd` into it (subsequent steps run there).
9
+ * $ACTIVATE_RELEASE — flip the `current` symlink atomically, prune old
10
+ * releases, and reload php-fpm so opcache sees new code.
11
+ * $RESTART_QUEUES — gracefully restart Laravel queue workers / Horizon.
12
+ *
13
+ * Everything between $CREATE_RELEASE and $ACTIVATE_RELEASE runs inside the new
14
+ * (not-yet-live) release, so a failure leaves the previous release serving —
15
+ * the Envoyer zero-downtime guarantee.
16
+ */
17
+ import type { SiteConfig } from '@ts-cloud/core';
18
+ export declare const MACRO_CREATE_RELEASE = "$CREATE_RELEASE";
19
+ export declare const MACRO_ACTIVATE_RELEASE = "$ACTIVATE_RELEASE";
20
+ export declare const MACRO_RESTART_QUEUES = "$RESTART_QUEUES";
21
+ /**
22
+ * Default deploy script (with macros) for a site type. Overridden by
23
+ * {@link SiteConfig.deployScript}.
24
+ */
25
+ export declare function defaultDeployScriptFor(type: NonNullable<SiteConfig['type']>): string[];
26
+ export interface LaravelDeployOptions {
27
+ siteName: string;
28
+ site: SiteConfig;
29
+ /** Unique release identifier (timestamp or sha) → `releases/<id>`. */
30
+ releaseId: string;
31
+ /** Site base dir. @default `/var/www/<siteName>` */
32
+ appBase?: string;
33
+ /** Exact commit to deploy (else the branch tip). */
34
+ commit?: string;
35
+ /** PHP version selecting the `phpX.Y` binary. @default `site.phpVersion` ?? '8.3' */
36
+ defaultPhpVersion?: string;
37
+ }
38
+ /**
39
+ * Build the full remote shell script for a PHP/Laravel git deploy, expanding the
40
+ * release macros. Requires `site.repository` to be set.
41
+ */
42
+ export declare function buildLaravelDeployScript(options: LaravelDeployOptions): string[];
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Generate the per-site runtime services for a Forge-style PHP box: queue
3
+ * workers / Horizon (systemd), the Laravel scheduler (cron), and arbitrary
4
+ * daemons (systemd). Reconciled on every deploy so units track the config —
5
+ * units no longer in the config are stopped and removed.
6
+ *
7
+ * Unit naming (so a site's units can be globbed for pruning):
8
+ * <slug>-<site>-queue-<i>.service
9
+ * <slug>-<site>-daemon-<slug-of-name>.service
10
+ * Scheduler cron lives at /etc/cron.d/<slug>-<site>-scheduler.
11
+ *
12
+ * ExecStart commands target `<base>/current/...` (the active-release symlink),
13
+ * so workers/daemons always run the live code; `queue:restart` (run by the
14
+ * deploy's $RESTART_QUEUES macro) cycles them onto the new release.
15
+ */
16
+ import type { DaemonConfig, SiteConfig } from '@ts-cloud/core';
17
+ export interface SiteServicesOptions {
18
+ slug: string;
19
+ siteName: string;
20
+ site: SiteConfig;
21
+ /** PHP version selecting the `phpX.Y` binary. @default '8.3' */
22
+ phpVersion?: string;
23
+ /** Site base dir. @default `/var/www/<siteName>` */
24
+ appBase?: string;
25
+ }
26
+ export declare function queueUnitName(slug: string, siteName: string, index: number): string;
27
+ export declare function daemonUnitName(slug: string, siteName: string, daemon: DaemonConfig, index: number): string;
28
+ /** Path of the scheduler cron file for a site. */
29
+ export declare function schedulerCronPath(slug: string, siteName: string): string;
30
+ /**
31
+ * Build the full reconcile script: (re)write desired queue/daemon units +
32
+ * scheduler cron, prune stale units for this site, and reload systemd.
33
+ */
34
+ export declare function buildSiteServicesScript(options: SiteServicesOptions): string[];
35
+ /** Whether a site declares any runtime services (avoids emitting an empty reconcile). */
36
+ export declare function siteHasServices(site: SiteConfig): boolean;
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Automatic unattended security/system updates, mirroring Forge's scheduled
3
+ * maintenance. Installs `unattended-upgrades` and enables the daily APT
4
+ * auto-update timers so security patches land without manual intervention.
5
+ */
6
+ /**
7
+ * Build the commands that enable automatic security updates. Idempotent.
8
+ * Returns `[]` when disabled.
9
+ */
10
+ export declare function buildAutoUpdatesScript(enabled?: boolean): string[];
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Lightweight server monitoring, mirroring Forge's basic server metrics.
3
+ *
4
+ * Dependency-free: a small shell collector reads load average, memory, and
5
+ * disk usage and writes a JSON snapshot to `/var/lib/ts-cloud/metrics.json`
6
+ * every minute via a systemd timer. The ts-cloud UI (and any operator tooling)
7
+ * can read that file for at-a-glance server health.
8
+ */
9
+ /** Where the metrics snapshot is written. */
10
+ export declare const METRICS_PATH = "/var/lib/ts-cloud/metrics.json";
11
+ /**
12
+ * Build the commands that install the metrics collector + systemd timer.
13
+ * Idempotent. Returns `[]` when disabled.
14
+ */
15
+ export declare function buildMonitoringScript(enabled?: boolean): string[];
@@ -0,0 +1,88 @@
1
+ /**
2
+ * Generate an nginx server block (vhost) for a Forge-style site and the shell
3
+ * commands that install it.
4
+ *
5
+ * Site `type` drives the template:
6
+ * - `laravel` / `statamic` / `wordpress` — `public/` web root, `index.php`,
7
+ * `try_files … /index.php?$query_string`, and a `fastcgi_pass` to the site's
8
+ * php-fpm socket (see {@link import('./php-provision').phpFpmSocketPath}).
9
+ * - `php` — generic PHP app behind php-fpm, web root at the release root.
10
+ * - `static` — plain files, `try_files … =404`.
11
+ * - `spa` — SPA fallback to `/index.html`.
12
+ *
13
+ * The block listens on :80 only; TLS (the `:443` block + redirect) is layered
14
+ * on by certbot in the SSL step, so this stays stable across cert renewals.
15
+ */
16
+ import type { SiteConfig } from '@ts-cloud/core';
17
+ export type NginxSiteType = NonNullable<SiteConfig['type']>;
18
+ export interface NginxVhostOptions {
19
+ /** Site key — names the config file (`/etc/nginx/sites-available/<siteName>`). */
20
+ siteName: string;
21
+ /** Primary hostname (`server_name`). */
22
+ domain: string;
23
+ /** Additional hostnames added to `server_name`. */
24
+ aliases?: string[];
25
+ /** Site type — selects the template. @default 'laravel' */
26
+ type?: NginxSiteType;
27
+ /**
28
+ * Directory the vhost serves from. For zero-downtime sites this is the
29
+ * `current` symlink (`/var/www/<site>/current`); the web root appends
30
+ * {@link webDirectory}.
31
+ */
32
+ appDir: string;
33
+ /** Web root relative to {@link appDir}. Defaults per type (see {@link defaultWebDirectory}). */
34
+ webDirectory?: string;
35
+ /** PHP version selecting the php-fpm socket. @default '8.3' */
36
+ phpVersion?: string;
37
+ /** `from path` → `to URL` 301 redirects. */
38
+ redirects?: Record<string, string>;
39
+ /**
40
+ * Serve TLS directly from this vhost using operator-provided certs. When set,
41
+ * the :80 block becomes an HTTPS redirect and a :443 `ssl` block serves the
42
+ * site. Used for the `custom` SSL provider; for Let's Encrypt, certbot
43
+ * rewrites the :80 block itself (leave this unset).
44
+ */
45
+ ssl?: {
46
+ certPath: string;
47
+ keyPath: string;
48
+ };
49
+ /**
50
+ * HTTP Basic auth (htpasswd). When set, the vhost requires auth and the
51
+ * generated script writes the htpasswd file. The `realm` is shown in the
52
+ * browser prompt.
53
+ */
54
+ auth?: {
55
+ username: string;
56
+ password: string;
57
+ realm?: string;
58
+ };
59
+ }
60
+ /** Path of the htpasswd file for a site. */
61
+ export declare function htpasswdPath(siteName: string): string;
62
+ /** Whether a site type is served by php-fpm. */
63
+ export declare function isPhpSiteType(type: NginxSiteType): boolean;
64
+ /** Default web root (relative to the release dir) for a site type. */
65
+ export declare function defaultWebDirectory(type: NginxSiteType): string;
66
+ /**
67
+ * Build the nginx server block text for a site. With `options.ssl`, emits a
68
+ * :80 → HTTPS redirect plus a :443 `ssl` block (the `custom` cert path);
69
+ * otherwise a single :80 block (certbot upgrades it for Let's Encrypt).
70
+ */
71
+ export declare function buildNginxVhost(options: NginxVhostOptions): string;
72
+ /**
73
+ * Build the shell commands that write the vhost, enable it, validate the nginx
74
+ * config, and reload. Re-runnable (overwrites the config + refreshes the symlink).
75
+ */
76
+ export declare function buildNginxVhostScript(options: NginxVhostOptions): string[];
77
+ /** Wrapper that runs the pantry-installed nginx binary inside pantry's env. */
78
+ export declare const NGINX_WRAPPER = "/usr/local/bin/ts-cloud-nginx";
79
+ /**
80
+ * Set up ts-cloud-managed nginx on top of the pantry-installed nginx binary:
81
+ * a wrapper that runs nginx within `pantry env` (so it + its shared libs
82
+ * resolve), a full `/etc/nginx/nginx.conf` that `include`s the per-site vhosts,
83
+ * and a systemd unit on :80/:443. Replaces apt's nginx service (pantry's own
84
+ * nginx service serves a minimal :8080 default and isn't started here).
85
+ *
86
+ * Run once at provision time, after the nginx binary is installed.
87
+ */
88
+ export declare function buildNginxServiceScript(projectDir?: string): string[];
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Send deploy / SSL / health-check / backup notifications to the configured
3
+ * channels (Slack, Discord, Telegram, email, generic webhook), mirroring
4
+ * Forge's notification system.
5
+ *
6
+ * Two surfaces:
7
+ * - {@link sendNotifications} — called from the TS deploy orchestrator for
8
+ * deploy success/failure (and other events ts-cloud drives locally).
9
+ * - {@link buildNotifierScript} — generates an on-box `ts-cloud-notify`
10
+ * helper that cron-driven events (certbot renewal, backups) can call.
11
+ */
12
+ import type { NotifyEvent, NotificationsConfig } from '@ts-cloud/core';
13
+ /** Fetch implementation (injectable for tests). */
14
+ export type FetchLike = (input: string, init?: {
15
+ method?: string;
16
+ headers?: Record<string, string>;
17
+ body?: string;
18
+ }) => Promise<{
19
+ ok: boolean;
20
+ status: number;
21
+ }>;
22
+ export interface SendNotificationsOptions {
23
+ /** Override the fetch implementation (default: global `fetch`). */
24
+ fetchImpl?: FetchLike;
25
+ }
26
+ /**
27
+ * Send `message` for `event` to every configured + subscribed channel. Errors
28
+ * on individual channels are swallowed (a flaky webhook must not fail a deploy);
29
+ * returns the list of channels that were attempted.
30
+ */
31
+ export declare function sendNotifications(config: NotificationsConfig | undefined, event: NotifyEvent, message: string, options?: SendNotificationsOptions): Promise<string[]>;
32
+ /** Resolve the effective notifications config for a site (site overrides project). */
33
+ export declare function resolveNotifications(project: NotificationsConfig | undefined, site: NotificationsConfig | undefined): NotificationsConfig | undefined;
34
+ /**
35
+ * Generate an on-box `ts-cloud-notify` script that POSTs `$1` (a message) to
36
+ * the webhook channels. Used by cron-driven hooks (certbot renew, backups) so
37
+ * server-side events also reach Slack/Discord/etc. Returns `[]` when no
38
+ * webhook-style channel is configured.
39
+ */
40
+ export declare function buildNotifierScript(config: NotificationsConfig | undefined): string[];
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Pantry-based package manager for provisioned servers.
3
+ *
4
+ * Every server dependency ts-cloud installs — PHP, nginx, Composer, the
5
+ * databases/caches/search engines, and the language runtimes — comes from the
6
+ * pantry registry (`registry.pantry.dev`, Hetzner-backed object storage) via
7
+ * the `pantry` CLI instead of apt/ppa/curl installers. Long-running services
8
+ * are managed by pantry's own systemd integration, which runs in **system
9
+ * scope** when provisioning as root (units under `/etc/systemd/system`, started
10
+ * at boot) — see `PANTRY_SERVICE_SCOPE` in pantry's service controller.
11
+ *
12
+ * This module is the single chokepoint for "install package X" / "run service
13
+ * Y" so the Hetzner and AWS bootstrap paths share one implementation. It only
14
+ * emits shell command lines (the convention used across `drivers/shared`); the
15
+ * caller splices them into the Ubuntu cloud-init / SSM bootstrap.
16
+ */
17
+ /**
18
+ * Pantry package domains for the dependencies ts-cloud provisions. Domains
19
+ * (not aliases) are used because aliases aren't guaranteed in every released
20
+ * pantry binary. The recipes live in pantry's `src/packages/*` (e.g. `php.net`
21
+ * is a source build carrying the full Laravel extension matrix).
22
+ */
23
+ export declare const PANTRY_PACKAGES: {
24
+ readonly php: "php.net";
25
+ readonly nginx: "nginx.org";
26
+ readonly composer: "getcomposer.org";
27
+ readonly mysql: "mysql.com";
28
+ readonly mariadb: "mariadb.org";
29
+ readonly postgres: "postgresql.org";
30
+ readonly redis: "redis.io";
31
+ readonly memcached: "memcached.org";
32
+ readonly meilisearch: "meilisearch.com";
33
+ readonly git: "git-scm.com";
34
+ readonly certbot: "certbot.eff.org";
35
+ readonly bun: "bun.sh";
36
+ readonly node: "nodejs.org";
37
+ readonly deno: "deno.land";
38
+ };
39
+ /** Logical package key (`'php'`, `'nginx'`, …). */
40
+ export type PantryPackageKey = keyof typeof PANTRY_PACKAGES;
41
+ /** A fully-qualified pantry package domain (`'php.net'`, `'nginx.org'`, …). */
42
+ export type PantryPackageDomain = (typeof PANTRY_PACKAGES)[PantryPackageKey];
43
+ /** A package to install: a known domain, optionally pinned with `@<version>`. */
44
+ export type PantrySpec = PantryPackageDomain | `${PantryPackageDomain}@${string}`;
45
+ /** Where the `pantry` binary itself is installed (on PATH for all later steps). */
46
+ export declare const PANTRY_INSTALL_DIR = "/usr/local/bin";
47
+ /**
48
+ * Server-side pantry project root. `pantry install` is project-scoped — it
49
+ * writes packages under `<root>/pantry/` and exposes their binaries via
50
+ * `<root>/pantry/.bin`. Provisioning installs everything into this one fixed
51
+ * project so the env (and thus PATH) is stable across deploy/systemd steps.
52
+ */
53
+ export declare const PANTRY_PROJECT_DIR = "/opt/pantry";
54
+ export interface PantryBootstrapOptions {
55
+ /** Pin the pantry CLI version (e.g. `'0.9.39'`). @default latest release */
56
+ version?: string;
57
+ }
58
+ /**
59
+ * Bootstrap the `pantry` CLI on a fresh server (idempotent — skips when already
60
+ * present). Installs to {@link PANTRY_INSTALL_DIR} and selects system-scope
61
+ * service management so `pantry enable/start` provisions boot-time systemd
62
+ * units rather than the per-user units that can't run headlessly.
63
+ */
64
+ export declare function buildPantryBootstrapScript(options?: PantryBootstrapOptions): string[];
65
+ /**
66
+ * Shell snippet that puts the project's pantry-installed binaries (php,
67
+ * composer, …) on PATH for a deploy step. `pantry env` is project-scoped, so it
68
+ * is evaluated from {@link PANTRY_PROJECT_DIR}. Returns a single line to
69
+ * `eval`/source before invoking those binaries.
70
+ */
71
+ export declare function pantryEnvActivation(): string;
72
+ /**
73
+ * Install one or more pantry packages in a single resolve pass. Accepts known
74
+ * domains (optionally `domain@version`). Returns `[]` for an empty list.
75
+ */
76
+ export declare function buildPantryInstallScript(specs: readonly PantrySpec[]): string[];
77
+ /**
78
+ * Enable (start on boot) and start pantry-managed services now. Service names
79
+ * are pantry's own (`'php-fpm'`, `'nginx'`, `'mysql'`, `'redis'`, …), not the
80
+ * package domains.
81
+ */
82
+ export declare function buildPantryServiceScript(services: readonly string[]): string[];
83
+ /** Resolve a logical key (or an explicit domain) to its package domain. */
84
+ export declare function pantryDomain(pkg: PantryPackageKey | PantryPackageDomain): PantryPackageDomain;
@@ -0,0 +1,36 @@
1
+ /**
2
+ * The baseline Laravel PHP extensions. pantry's `php.net` is a single source
3
+ * build that already bundles these, so unlike apt there are no per-extension
4
+ * packages to install — this list documents the expectation and is asserted
5
+ * against `php -m` in tests.
6
+ */
7
+ export declare const LARAVEL_PHP_EXTENSIONS: readonly string[];
8
+ export interface PhpProvisionOptions {
9
+ /** PHP versions to install (first is the default). pantry runs one php-fpm. @default ['8.3'] */
10
+ versions?: string[];
11
+ /** Default PHP version. @default first of `versions` */
12
+ default?: string;
13
+ /** Extra extensions — informational; pantry's php build is fixed. */
14
+ extensions?: string[];
15
+ /** Install the nginx binary (the vhost/service is wired separately). @default true */
16
+ installNginx?: boolean;
17
+ /** Install Composer. @default true */
18
+ installComposer?: boolean;
19
+ }
20
+ /** PHP-FPM listen address for nginx `fastcgi_pass` (pantry's php-fpm is TCP). */
21
+ export declare const PHP_FPM_LISTEN = "127.0.0.1:9074";
22
+ /**
23
+ * php-fpm `fastcgi_pass` target. The `version` arg is accepted for API
24
+ * compatibility with the old per-version unix sockets; pantry runs a single
25
+ * php-fpm on {@link PHP_FPM_LISTEN}.
26
+ */
27
+ export declare function phpFpmSocketPath(_version?: string): string;
28
+ /** Resolve the default PHP version from the requested set. */
29
+ export declare function resolveDefaultPhpVersion(options?: PhpProvisionOptions): string;
30
+ /**
31
+ * Build the shell command lines that install PHP-FPM + Composer (+ the nginx
32
+ * binary) via pantry and start php-fpm as a system service. Assumes the pantry
33
+ * CLI is already bootstrapped (see
34
+ * {@link import('./package-manager').buildPantryBootstrapScript}).
35
+ */
36
+ export declare function buildPhpProvisionScript(options?: PhpProvisionOptions): string[];
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Zero-downtime atomic release management for Forge-style git deploys.
3
+ *
4
+ * Directory layout under a site's base (`/var/www/<site>`):
5
+ * releases/<id>/ one checkout per deploy
6
+ * shared/ files persisted across releases (storage, .env, …)
7
+ * current -> symlink to the active release
8
+ *
9
+ * A deploy clones into `releases/<id>`, symlinks the shared paths in, runs the
10
+ * deploy script, then atomically repoints `current`. Old releases are pruned
11
+ * to a retention count for rollback. These map to Forge's deploy macros:
12
+ * $CREATE_RELEASE → {@link buildEnsureReleaseLayout} + git clone + {@link buildLinkSharedPaths}
13
+ * $ACTIVATE_RELEASE → {@link buildActivateRelease} (+ {@link buildPruneReleases})
14
+ */
15
+ /** Paths that are always shared across releases (Forge shares `.env` implicitly). */
16
+ export declare const DEFAULT_SHARED_PATHS: readonly string[];
17
+ /** Default number of past releases to retain for rollback. */
18
+ export declare const DEFAULT_KEEP_RELEASES = 4;
19
+ export interface ReleasePaths {
20
+ /** Site base directory (`/var/www/<site>`). */
21
+ base: string;
22
+ /** Releases parent (`<base>/releases`). */
23
+ releases: string;
24
+ /** Shared parent (`<base>/shared`). */
25
+ shared: string;
26
+ /** Active-release symlink (`<base>/current`). */
27
+ current: string;
28
+ /** This deploy's release dir (`<base>/releases/<id>`). */
29
+ release: string;
30
+ }
31
+ /** Resolve the standard release layout paths for a site + release id. */
32
+ export declare function releasePaths(base: string, releaseId: string): ReleasePaths;
33
+ /**
34
+ * Ensure the releases/ and shared/ skeleton exist, including the Laravel
35
+ * `storage` tree and an empty shared `.env` so symlinks never dangle.
36
+ */
37
+ export declare function buildEnsureReleaseLayout(paths: ReleasePaths, sharedPaths?: readonly string[]): string[];
38
+ /**
39
+ * Symlink every shared path from `shared/` into the freshly checked-out release,
40
+ * replacing whatever the checkout shipped (e.g. the repo's empty `storage`).
41
+ */
42
+ export declare function buildLinkSharedPaths(paths: ReleasePaths, sharedPaths?: readonly string[]): string[];
43
+ /**
44
+ * Atomically repoint `current` at the new release. Writes a temp symlink and
45
+ * `mv -T`s it over `current` so there is no window where `current` is missing.
46
+ */
47
+ export declare function buildActivateRelease(paths: ReleasePaths): string[];
48
+ /**
49
+ * Remove all but the newest `keep` releases (by mtime). `current` always points
50
+ * at the newest, so it is never pruned.
51
+ */
52
+ export declare function buildPruneReleases(paths: ReleasePaths, keep?: number): string[];
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Declaratively manage operator SSH keys in the box's `authorized_keys`.
3
+ *
4
+ * Keys are written inside a ts-cloud-managed block (delimited by marker
5
+ * comments) so the set can be reconciled on every provision/deploy without
6
+ * disturbing keys added out-of-band: the whole block is rewritten from the
7
+ * config each time. Adding an SSH key is therefore "add an entry + redeploy".
8
+ */
9
+ import type { SshKeyConfig } from '@ts-cloud/core';
10
+ /** Default authorized_keys path (root deploy user). */
11
+ export declare const DEFAULT_AUTHORIZED_KEYS = "/root/.ssh/authorized_keys";
12
+ export interface AuthorizedKeysOptions {
13
+ /** authorized_keys file to manage. @default '/root/.ssh/authorized_keys' */
14
+ path?: string;
15
+ }
16
+ /**
17
+ * Build the commands that reconcile the managed key block in authorized_keys.
18
+ * Strips any previous ts-cloud block, then appends the current set. Returns `[]`
19
+ * when there are no keys to manage.
20
+ */
21
+ export declare function buildAuthorizedKeysScript(keys?: SshKeyConfig[], options?: AuthorizedKeysOptions): string[];
@@ -0,0 +1,54 @@
1
+ /**
2
+ * The canonical Ubuntu provisioning recipe for a ts-cloud compute box.
3
+ *
4
+ * This single bash builder is used in three places so there is exactly one
5
+ * source of truth (and zero per-provider divergence):
6
+ * - **cold boot** — Hetzner cloud-init / AWS EC2 UserData run it on first boot.
7
+ * - **image bake** — the golden-image pipeline runs it to pre-install the
8
+ * stack, then snapshots the box into a Hetzner snapshot / AWS AMI.
9
+ * - **baked boot** — when a box boots from a pre-provisioned image, pass
10
+ * `baked: true` to skip the install-heavy steps (apt/runtime/php/services)
11
+ * that are already in the image, keeping only cheap per-boot setup.
12
+ *
13
+ * Targets Ubuntu (apt) — Forge's platform — on every provider, so the apt
14
+ * provisioning, nginx vhosts, php-fpm sockets, and deploy scripts are identical
15
+ * for Hetzner and AWS.
16
+ */
17
+ export interface UbuntuBootstrapOptions {
18
+ runtime?: 'bun' | 'node' | 'deno' | 'php';
19
+ runtimeVersion?: string;
20
+ systemPackages?: string[];
21
+ database?: 'sqlite' | 'mysql' | 'postgres';
22
+ /**
23
+ * Shell commands that install PHP-FPM + nginx + Composer, built by
24
+ * {@link import('./php-provision').buildPhpProvisionScript}. Spliced
25
+ * after the base packages so Laravel/PHP sites have their runtime ready
26
+ * before any deploy. Used when `runtime === 'php'` (or `compute.php` is set).
27
+ */
28
+ phpProvision?: string[];
29
+ /**
30
+ * Shell commands that install on-box services (database engine, redis,
31
+ * memcached, meilisearch) and create the app database + user, built by
32
+ * {@link import('./db-provision')}. Spliced after the PHP provision.
33
+ */
34
+ servicesProvision?: string[];
35
+ caddyfile?: string;
36
+ /**
37
+ * Shell commands that install + start the rpx reverse-proxy gateway, built by
38
+ * {@link import('./rpx-gateway').buildRpxProvisionScript}. Appended
39
+ * after the runtime is installed so `bun add -g @stacksjs/rpx` works. Mutually
40
+ * exclusive with `caddyfile` (the box runs one gateway).
41
+ */
42
+ rpxProvision?: string[];
43
+ /**
44
+ * The box boots from a pre-provisioned (golden) image that already has the
45
+ * runtime + PHP + services + base packages installed. Skip those install
46
+ * steps — only do the cheap per-boot setup (dirs, gateway config). Makes
47
+ * boot near-instant. @default false
48
+ */
49
+ baked?: boolean;
50
+ }
51
+ /**
52
+ * Build the Ubuntu provisioning bash script (with `#!/bin/bash` shebang).
53
+ */
54
+ export declare function buildUbuntuBootstrapScript(options?: UbuntuBootstrapOptions): string;
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Host firewall (UFW) provisioning, mirroring Forge's per-server firewall.
3
+ *
4
+ * Defaults to deny-incoming / allow-outgoing, with SSH (OpenSSH), HTTP (80),
5
+ * and HTTPS (443) always open so deploys and web traffic keep working, plus
6
+ * any extra ports the config lists (e.g. a Reverb/websocket port). On Hetzner
7
+ * this is layered on top of the cloud firewall; on a bare box it's the primary
8
+ * line of defence.
9
+ */
10
+ import type { ComputeFirewallConfig } from '@ts-cloud/core';
11
+ /** Ports always allowed so SSH deploys + web traffic are never locked out. */
12
+ export declare const UFW_BASE_PORTS: readonly number[];
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.
16
+ */
17
+ export declare function buildUfwScript(firewall?: ComputeFirewallConfig): string[];