@stacksjs/ts-cloud 0.4.2 → 0.5.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.
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Auto-deploy of the ts-cloud management dashboard (the `@ts-cloud/ui` stx app)
3
+ * on every server provision/deploy.
4
+ *
5
+ * Resolves the UI directory (the repo's local `ui/`, else the prebuilt UI that
6
+ * ships inside the installed package at `dist/ui`), derives a `dashboard.<apex>`
7
+ * host, and injects it into `config.sites` as a server-static site. It is served
8
+ * behind htpasswd ONLY when `TS_CLOUD_UI_PASSWORD` is set; when it is not, the
9
+ * dashboard is served without auth (no password is invented).
10
+ *
11
+ * Env:
12
+ * - `TS_CLOUD_UI_PASSWORD` htpasswd password (unset ⇒ no auth)
13
+ * - `TS_CLOUD_UI_USERNAME` htpasswd user (default `admin`)
14
+ * - `TS_CLOUD_UI_DOMAIN` explicit dashboard host (else `dashboard.<apex>`)
15
+ * - `TS_CLOUD_UI_REALM` browser auth realm
16
+ * - `TS_CLOUD_UI_DISABLE` set truthy to skip auto-deploy
17
+ */
18
+ import type { CloudConfig } from '@stacksjs/ts-cloud';
19
+ export interface EnsureDashboardLogger {
20
+ info: (msg: string) => void;
21
+ warn: (msg: string) => void;
22
+ }
23
+ /**
24
+ * Resolve the UI source to ship. Prefers the repo's local `ui/` (built on the
25
+ * deploy machine), then the prebuilt UI bundled in the installed package.
26
+ * Returns `{ uiRoot, build }` or null when no UI is available.
27
+ */
28
+ export declare function resolveUiSource(cwd: string): {
29
+ uiRoot: string;
30
+ build: string | false;
31
+ } | null;
32
+ /**
33
+ * Inject the management dashboard into `config.sites` for a server deploy.
34
+ * Mutates and returns `config`. Idempotent and safe to call on every deploy.
35
+ */
36
+ export declare function ensureManagementDashboard(config: CloudConfig, options?: {
37
+ cwd?: string;
38
+ logger?: EnsureDashboardLogger;
39
+ }): CloudConfig;
package/dist/index.js CHANGED
@@ -7654,6 +7654,56 @@ function createDashboardSite(options) {
7654
7654
  }
7655
7655
  };
7656
7656
  }
7657
+ function apexOf(domain) {
7658
+ const parts = domain.split(".").filter(Boolean);
7659
+ return parts.length <= 2 ? domain : parts.slice(-2).join(".");
7660
+ }
7661
+ function resolveDashboardDomain(config6, environment, explicit) {
7662
+ if (explicit)
7663
+ return explicit;
7664
+ const candidates = [];
7665
+ for (const site of Object.values(config6.sites ?? {})) {
7666
+ const d = site?.domain;
7667
+ if (typeof d === "string")
7668
+ candidates.push(d);
7669
+ else if (Array.isArray(d))
7670
+ candidates.push(...d.filter((x) => typeof x === "string"));
7671
+ }
7672
+ if (environment && config6.environments?.[environment]?.domain)
7673
+ candidates.push(config6.environments[environment].domain);
7674
+ const dnsDomain = config6.infrastructure?.dns?.domain;
7675
+ if (dnsDomain)
7676
+ candidates.push(dnsDomain);
7677
+ const base = candidates.find((d) => d && !d.startsWith("dashboard."));
7678
+ if (!base)
7679
+ return null;
7680
+ return `dashboard.${apexOf(base)}`;
7681
+ }
7682
+ function hasManagementDashboardSite(config6) {
7683
+ return Object.entries(config6.sites ?? {}).some(([name, site]) => {
7684
+ if (!site)
7685
+ return false;
7686
+ const root = site.root ?? "";
7687
+ return name === "dashboard" || root === "ui/dist" || root.endsWith("/ui/dist") || root.endsWith("/dist/ui");
7688
+ });
7689
+ }
7690
+ function resolveManagementDashboardSite(config6, environment, opts) {
7691
+ if (hasManagementDashboardSite(config6))
7692
+ return null;
7693
+ const domain = resolveDashboardDomain(config6, environment, opts.domain);
7694
+ if (!domain)
7695
+ return null;
7696
+ const site = {
7697
+ root: opts.uiRoot,
7698
+ deploy: "server",
7699
+ type: "static",
7700
+ domain,
7701
+ ssl: { provider: "letsencrypt" },
7702
+ ...opts.build === false || opts.build === undefined ? {} : { build: opts.build },
7703
+ ...opts.password ? { auth: { username: opts.username || "admin", password: opts.password, realm: opts.realm } } : {}
7704
+ };
7705
+ return { name: "dashboard", site };
7706
+ }
7657
7707
  function deepMerge5(target, source) {
7658
7708
  const result = { ...target };
7659
7709
  for (const key in source) {
@@ -83450,15 +83500,18 @@ function buildDatabaseSetupScript(database, services = {}) {
83450
83500
  "TS_CLOUD_PG_EOF"
83451
83501
  ];
83452
83502
  }
83503
+ const sock = useMariadb ? "/var/lib/pantry/mariadb/mariadbd.sock" : "/var/lib/pantry/mysql/mysqld.sock";
83453
83504
  const ident = (v) => v.replace(/`/g, "``");
83454
83505
  const lit = (v) => v.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
83455
83506
  return [
83456
83507
  pantryEnvActivation(),
83457
- "for i in $(seq 1 30); do mysqladmin -h 127.0.0.1 -P 3306 -u root ping 2>/dev/null | grep -q alive && break; sleep 2; done",
83458
- "mysql -h 127.0.0.1 -P 3306 -u root <<'TS_CLOUD_SQL_EOF'",
83508
+ `for i in $(seq 1 30); do mysqladmin --socket=${sock} -u root ping 2>/dev/null | grep -q alive && break; sleep 2; done`,
83509
+ `mysql --socket=${sock} -u root <<'TS_CLOUD_SQL_EOF'`,
83459
83510
  `CREATE DATABASE IF NOT EXISTS \`${ident(name)}\` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;`,
83460
83511
  `CREATE USER IF NOT EXISTS '${lit(user)}'@'%' IDENTIFIED BY '${lit(pass)}';`,
83512
+ `CREATE USER IF NOT EXISTS '${lit(user)}'@'localhost' IDENTIFIED BY '${lit(pass)}';`,
83461
83513
  `GRANT ALL PRIVILEGES ON \`${ident(name)}\`.* TO '${lit(user)}'@'%';`,
83514
+ `GRANT ALL PRIVILEGES ON \`${ident(name)}\`.* TO '${lit(user)}'@'localhost';`,
83462
83515
  "FLUSH PRIVILEGES;",
83463
83516
  "TS_CLOUD_SQL_EOF"
83464
83517
  ];
@@ -86275,9 +86328,11 @@ export {
86275
86328
  resolveQueueNames,
86276
86329
  resolveProjectStackName,
86277
86330
  resolveObjectStorage,
86331
+ resolveManagementDashboardSite,
86278
86332
  resolveHetznerApiToken,
86279
86333
  resolveExecStart,
86280
86334
  resolveDeployBucketName,
86335
+ resolveDashboardDomain,
86281
86336
  resolveCredentials,
86282
86337
  resolveCloudProvider,
86283
86338
  resolveApp,
@@ -86340,6 +86395,7 @@ export {
86340
86395
  hashFile,
86341
86396
  hashDirectory,
86342
86397
  hashBuffer,
86398
+ hasManagementDashboardSite,
86343
86399
  guardDutyManager,
86344
86400
  globalResourceManager,
86345
86401
  getTimestamp,
@@ -0,0 +1,22 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Page Not Found</title>
7
+ <style>
8
+ body { font-family: system-ui, sans-serif; display: flex; align-items: center; justify-content: center; min-height: 100vh; margin: 0; }
9
+ .container { text-align: center; }
10
+ h1 { font-size: 6rem; margin: 0; color: #333; }
11
+ p { color: #666; }
12
+ a { color: #0066cc; }
13
+ </style>
14
+ </head>
15
+ <body>
16
+ <div class="container">
17
+ <h1>404</h1>
18
+ <p>Page not found</p>
19
+ <a href="/">Go home</a>
20
+ </div>
21
+ </body>
22
+ </html>