@stacksjs/ts-cloud 0.7.22 → 0.7.24

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 (34) hide show
  1. package/dist/bin/cli.js +259 -258
  2. package/dist/{chunk-kcxxwg3j.js → chunk-5cfcv2s2.js} +50 -21
  3. package/dist/{chunk-js3vrvvn.js → chunk-khfnaap2.js} +1 -1
  4. package/dist/deploy/dashboard-config-module.d.ts +40 -0
  5. package/dist/deploy/dashboard-config-module.test.d.ts +1 -0
  6. package/dist/deploy/index.js +2 -2
  7. package/dist/deploy/management-dashboard.d.ts +10 -7
  8. package/dist/drivers/index.js +1 -1
  9. package/dist/index.js +2 -2
  10. package/dist/ui/index.html +3 -3
  11. package/dist/ui/server/actions.html +3 -3
  12. package/dist/ui/server/backups.html +3 -3
  13. package/dist/ui/server/database.html +3 -3
  14. package/dist/ui/server/deployments.html +3 -3
  15. package/dist/ui/server/firewall.html +3 -3
  16. package/dist/ui/server/logs.html +3 -3
  17. package/dist/ui/server/services.html +3 -3
  18. package/dist/ui/server/sites.html +3 -3
  19. package/dist/ui/server/ssh-keys.html +3 -3
  20. package/dist/ui/server/team.html +3 -3
  21. package/dist/ui/server/terminal.html +3 -3
  22. package/dist/ui/server/workers.html +3 -3
  23. package/dist/ui/serverless/alarms.html +3 -3
  24. package/dist/ui/serverless/assets.html +3 -3
  25. package/dist/ui/serverless/data.html +3 -3
  26. package/dist/ui/serverless/deployments.html +3 -3
  27. package/dist/ui/serverless/functions.html +3 -3
  28. package/dist/ui/serverless/logs.html +3 -3
  29. package/dist/ui/serverless/queues.html +3 -3
  30. package/dist/ui/serverless/scheduler.html +3 -3
  31. package/dist/ui/serverless/secrets.html +3 -3
  32. package/dist/ui/serverless/traces.html +3 -3
  33. package/dist/ui/serverless.html +3 -3
  34. package/package.json +3 -3
@@ -3818,17 +3818,59 @@ function buildLocalArtifactFetch(localPath, siteName) {
3818
3818
  ];
3819
3819
  }
3820
3820
  // src/drivers/shared/compute-deploy.ts
3821
- import { copyFileSync as copyFileSync2 } from "node:fs";
3821
+ import { copyFileSync } from "node:fs";
3822
3822
  import { tmpdir as tmpdir2 } from "node:os";
3823
3823
  import { join as join5 } from "node:path";
3824
3824
 
3825
3825
  // src/deploy/management-dashboard.ts
3826
3826
  import { execSync as execSync2 } from "node:child_process";
3827
3827
  import { randomBytes } from "node:crypto";
3828
- import { chmodSync, copyFileSync, existsSync as existsSync2, mkdirSync, readFileSync as readFileSync3, writeFileSync } from "node:fs";
3828
+ import { chmodSync, existsSync as existsSync2, mkdirSync, readFileSync as readFileSync3, writeFileSync } from "node:fs";
3829
3829
  import { tmpdir } from "node:os";
3830
3830
  import { dirname, isAbsolute, join as join4 } from "node:path";
3831
3831
  import { fileURLToPath } from "node:url";
3832
+
3833
+ // src/deploy/dashboard-config-module.ts
3834
+ function blankValues(record) {
3835
+ if (!record || typeof record !== "object")
3836
+ return record;
3837
+ return Object.fromEntries(Object.keys(record).map((key) => [key, ""]));
3838
+ }
3839
+ function redactForDashboard(config) {
3840
+ const safe = JSON.parse(JSON.stringify(config ?? {}));
3841
+ if (safe.hetzner)
3842
+ delete safe.hetzner.apiToken;
3843
+ delete safe.aws;
3844
+ for (const site of Object.values(safe.sites ?? {})) {
3845
+ if (site?.env)
3846
+ site.env = blankValues(site.env);
3847
+ if (site?.environment)
3848
+ site.environment = blankValues(site.environment);
3849
+ }
3850
+ for (const env2 of Object.values(safe.environments ?? {})) {
3851
+ if (env2?.variables)
3852
+ env2.variables = blankValues(env2.variables);
3853
+ }
3854
+ for (const db of Object.values(safe.infrastructure?.databases ?? {})) {
3855
+ if (db?.password)
3856
+ db.password = "";
3857
+ }
3858
+ return safe;
3859
+ }
3860
+ function serializeDashboardConfig(config) {
3861
+ const safe = redactForDashboard(config);
3862
+ return [
3863
+ "// Generated by ts-cloud for the management dashboard — do not edit.",
3864
+ "//",
3865
+ "// This is the project's resolved cloud config, inlined so it needs no",
3866
+ "// imports on the box. Credentials are deliberately absent.",
3867
+ `export default ${JSON.stringify(safe, null, 2)}`,
3868
+ ""
3869
+ ].join(`
3870
+ `);
3871
+ }
3872
+
3873
+ // src/deploy/management-dashboard.ts
3832
3874
  var MANAGEMENT_DASHBOARD_SITE = "dashboard";
3833
3875
  var DASHBOARD_CREDENTIALS_FILE = join4(".ts-cloud", "dashboard-credentials.json");
3834
3876
  function generatePassword() {
@@ -3865,12 +3907,6 @@ function truthy(v) {
3865
3907
  return v != null && v !== "" && v !== "0" && v.toLowerCase() !== "false";
3866
3908
  }
3867
3909
  var LIVE_STAGE_DIR = join4(".ts-cloud", "dashboard-release");
3868
- var CONFIG_CANDIDATES = [
3869
- ["config", "cloud.ts"],
3870
- ["config", "cloud.js"],
3871
- ["cloud.config.ts"],
3872
- ["cloud.config.js"]
3873
- ];
3874
3910
  function resolveDashboardVersion() {
3875
3911
  const explicit = process.env.TS_CLOUD_UI_VERSION?.trim();
3876
3912
  if (explicit)
@@ -3885,22 +3921,15 @@ function resolveDashboardVersion() {
3885
3921
  }
3886
3922
  return "latest";
3887
3923
  }
3888
- function stageLiveDashboardRoot(cwd, logger) {
3889
- const source = CONFIG_CANDIDATES.map((parts) => join4(cwd, ...parts)).find((file) => existsSync2(file));
3890
- if (!source) {
3891
- logger.warn("Management dashboard: no cloud config found to ship — skipping the live dashboard.");
3924
+ function stageLiveDashboardRoot(config, cwd, logger) {
3925
+ if (!config?.project?.slug) {
3926
+ logger.warn("Management dashboard: the cloud config has no project slug — skipping the live dashboard.");
3892
3927
  return null;
3893
3928
  }
3894
3929
  const stage = join4(cwd, LIVE_STAGE_DIR);
3895
3930
  try {
3896
3931
  mkdirSync(stage, { recursive: true });
3897
- const isStacksLayout = source.endsWith(join4("config", "cloud.ts")) || source.endsWith(join4("config", "cloud.js"));
3898
- if (isStacksLayout) {
3899
- mkdirSync(join4(stage, "config"), { recursive: true });
3900
- copyFileSync(source, join4(stage, "config", source.endsWith(".ts") ? "cloud.ts" : "cloud.js"));
3901
- } else {
3902
- copyFileSync(source, join4(stage, source.endsWith(".ts") ? "cloud.config.ts" : "cloud.config.js"));
3903
- }
3932
+ writeFileSync(join4(stage, "cloud.config.ts"), serializeDashboardConfig(config));
3904
3933
  const pkg = {
3905
3934
  name: "ts-cloud-dashboard",
3906
3935
  private: true,
@@ -3946,7 +3975,7 @@ function ensureManagementDashboard(config, options = {}) {
3946
3975
  const port = Number(process.env.TS_CLOUD_UI_PORT) || undefined;
3947
3976
  const sites = { ...config.sites ?? {} };
3948
3977
  if (!truthy(process.env.TS_CLOUD_UI_STATIC)) {
3949
- const uiRoot = stageLiveDashboardRoot(cwd, logger);
3978
+ const uiRoot = stageLiveDashboardRoot(config, cwd, logger);
3950
3979
  if (!uiRoot)
3951
3980
  return config;
3952
3981
  const resolved2 = resolveManagementDashboardSites(config, environment ?? "production", {
@@ -4729,7 +4758,7 @@ async function deployAllComputeSites(options) {
4729
4758
  }
4730
4759
  try {
4731
4760
  const copy = join5(tmpdir2(), `${slug}-${name}-${sha}.tar.gz`);
4732
- copyFileSync2(dashboardTarball, copy);
4761
+ copyFileSync(dashboardTarball, copy);
4733
4762
  dashboardTarballBySite.set(name, copy);
4734
4763
  } catch {
4735
4764
  dashboardTarballBySite.set(name, dashboardTarball);
@@ -28,7 +28,7 @@ import {
28
28
  resolveSiteKind,
29
29
  resolveUiSource,
30
30
  siteInstallBase
31
- } from "./chunk-kcxxwg3j.js";
31
+ } from "./chunk-5cfcv2s2.js";
32
32
  import {
33
33
  artifactKey,
34
34
  composeServerlessAppTemplate,
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Serialize the resolved cloud config into a self-contained module for the
3
+ * dashboard to read on the box.
4
+ *
5
+ * Copying the project's `cloud.config.ts` verbatim does not work: a real config
6
+ * imports things. Stacks' does
7
+ * `import { servers } from '~/cloud/servers'` and `import { env } from
8
+ * '@stacksjs/env'` — neither the path alias nor the package exists in the
9
+ * dashboard's release dir, so the import would throw and the dashboard would
10
+ * come up describing nothing.
11
+ *
12
+ * The deploy machine has already resolved the config to a plain object, so we
13
+ * ship THAT as a literal. No imports, no aliases, nothing to resolve.
14
+ *
15
+ * Credentials are stripped on the way out (see {@link redactForDashboard}).
16
+ */
17
+ import type { CloudConfig } from '@ts-cloud/core';
18
+ /**
19
+ * Strip everything the dashboard does not need to read.
20
+ *
21
+ * Two rules:
22
+ *
23
+ * 1. **No credentials.** The Hetzner API token is the big one: it controls the
24
+ * whole cloud account (create and destroy any server), and unlike a site's
25
+ * own secrets it is otherwise NOT on the box at all. Putting it in the
26
+ * dashboard's release would turn a dashboard compromise into an account
27
+ * compromise. AWS credentials go for the same reason.
28
+ *
29
+ * 2. **Env keys, not env values.** The dashboard only ever displays which env
30
+ * vars a site defines, never their values — so ship the keys and blank the
31
+ * values. The running site has its own `.env` on the box regardless; there
32
+ * is no reason for a second copy to sit in the dashboard's directory.
33
+ */
34
+ export declare function redactForDashboard(config: CloudConfig): Record<string, any>;
35
+ /**
36
+ * The `cloud.config.ts` module text shipped in the dashboard's release. Reads
37
+ * as a plain literal so bun can import it on the box with nothing installed
38
+ * beyond the ts-cloud package itself.
39
+ */
40
+ export declare function serializeDashboardConfig(config: CloudConfig): string;
@@ -0,0 +1 @@
1
+ export {};
@@ -12,7 +12,7 @@ import {
12
12
  sanitizeCloudConfig,
13
13
  setMaintenance,
14
14
  startLocalDashboardServer
15
- } from "../chunk-js3vrvvn.js";
15
+ } from "../chunk-khfnaap2.js";
16
16
  import {
17
17
  buildAndPushServerlessImage
18
18
  } from "../chunk-5mejsd43.js";
@@ -30,7 +30,7 @@ import {
30
30
  resolveUiSource,
31
31
  siteInstallBase,
32
32
  validateDeploymentConfig
33
- } from "../chunk-kcxxwg3j.js";
33
+ } from "../chunk-5cfcv2s2.js";
34
34
  import"../chunk-0tfwdnmf.js";
35
35
  import"../chunk-93hjhs78.js";
36
36
  import {
@@ -71,15 +71,18 @@ export declare const LIVE_STAGE_DIR: string;
71
71
  */
72
72
  export declare function resolveDashboardVersion(): string;
73
73
  /**
74
- * Stage the live dashboard's release: the project's cloud config (so the box
75
- * can resolve the same sites) plus a `package.json` whose install pulls the CLI
76
- * and UI from npm.
74
+ * Stage the live dashboard's release: the RESOLVED cloud config inlined as a
75
+ * self-contained module, plus a `package.json` whose install pulls the CLI and
76
+ * UI from npm.
77
77
  *
78
- * Returns the staged directory relative to `cwd`, or null when the project has
79
- * no cloud config to ship without one the dashboard on the box would have
80
- * nothing to describe.
78
+ * The config is serialized rather than copied because a real one imports things
79
+ * that do not exist on the box Stacks' does `import { servers } from
80
+ * '~/cloud/servers'` and the import would throw, leaving the dashboard with
81
+ * nothing to describe. Credentials are stripped on the way out.
82
+ *
83
+ * Returns the staged directory relative to `cwd`, or null when staging fails.
81
84
  */
82
- export declare function stageLiveDashboardRoot(cwd: string, logger: EnsureDashboardLogger): string | null;
85
+ export declare function stageLiveDashboardRoot(config: CloudConfig, cwd: string, logger: EnsureDashboardLogger): string | null;
83
86
  /**
84
87
  * Resolve the UI source to ship (STATIC mode only — the live dashboard gets its
85
88
  * UI from the npm package it installs on the box). Prefers the repo's local
@@ -48,7 +48,7 @@ import {
48
48
  waitForCloudInit,
49
49
  waitForSsh,
50
50
  wrapCloudInitUserData
51
- } from "../chunk-kcxxwg3j.js";
51
+ } from "../chunk-5cfcv2s2.js";
52
52
  import"../chunk-0tfwdnmf.js";
53
53
  import"../chunk-93hjhs78.js";
54
54
  import"../chunk-qpj3edwz.js";
package/dist/index.js CHANGED
@@ -55,7 +55,7 @@ import {
55
55
  sanitizeCloudConfig,
56
56
  setMaintenance,
57
57
  startLocalDashboardServer
58
- } from "./chunk-js3vrvvn.js";
58
+ } from "./chunk-khfnaap2.js";
59
59
  import {
60
60
  buildAndPushServerlessImage
61
61
  } from "./chunk-5mejsd43.js";
@@ -105,7 +105,7 @@ import {
105
105
  waitForCloudInit,
106
106
  waitForSsh,
107
107
  wrapCloudInitUserData
108
- } from "./chunk-kcxxwg3j.js";
108
+ } from "./chunk-5cfcv2s2.js";
109
109
  import {
110
110
  ABTestManager,
111
111
  AI,