unoverse 0.1.68 → 0.1.69

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.
@@ -11,9 +11,14 @@
11
11
  * their size, counts the plumbing (database users, firewall rules, generated passwords)
12
12
  * rather than listing it, and shouts about anything being destroyed.
13
13
  *
14
- * NOT A COST ORACLE. Prices are DigitalOcean's published monthly rates for the sizes this
15
- * ground uses, so the developer sees an order of magnitude rather than a surprise. They
14
+ * NOT A COST ORACLE. The developer sees an order of magnitude rather than a surprise. Rates
16
15
  * move, so the total is labelled approximate and the real bill is the provider's.
16
+ *
17
+ * THE GROUND PRICES ITSELF. Every ground exposes a `prices` output (its own prices.tf)
18
+ * keyed by the size slugs it actually uses, and this reads that out of the plan. Keeping
19
+ * a table here instead meant one more copy to forget: it still quoted t3-series rates
20
+ * after the AWS ground moved to t4g, so that ground's database and cache priced at zero
21
+ * and nobody could see it. A ground without the output is simply not priced.
17
22
  */
18
23
 
19
24
  const COLOR = !process.env.NO_COLOR;
@@ -24,14 +29,11 @@ const green = paint("32");
24
29
  const red = paint("31");
25
30
  const yellow = paint("33");
26
31
 
27
- /** Monthly USD for the sizes these grounds use. Absent size → no guess. */
28
- const PRICE = {
29
- "s-1vcpu-1gb": 6, "s-1vcpu-2gb": 12, "s-2vcpu-2gb": 18, "s-2vcpu-4gb": 24,
30
- "s-4vcpu-8gb": 48, "s-4vcpu-16gb-amd": 96, "s-8vcpu-16gb": 96,
31
- "db-s-1vcpu-1gb": 15, "db-s-1vcpu-2gb": 30, "db-s-2vcpu-4gb": 60,
32
- lb: 12,
33
- "t3.large": 60, "t3.xlarge": 120, "db.t3.medium": 50, "cache.t3.micro": 12,
34
- };
32
+ /**
33
+ * Monthly USD by size slug, read from the ground's own `prices` output. Empty until the
34
+ * plan is parsed, and empty stays harmless: every lookup misses and nothing is priced.
35
+ */
36
+ let PRICE = {};
35
37
 
36
38
  /** vCPU/RAM read out of a size slug, when it says so. */
37
39
  function spec(size) {
@@ -70,7 +72,7 @@ function describe(r) {
70
72
  case "aws_elasticache_replication_group":
71
73
  return { what: "Redis cache", detail: a.node_type ?? "", price: PRICE[a.node_type] };
72
74
  case "aws_lb":
73
- return { what: "Load balancer", detail: "the public way in", price: 18 };
75
+ return { what: "Load balancer", detail: "the public way in", price: PRICE.alb };
74
76
  case "aws_cognito_user_pool":
75
77
  return { what: "Login (Cognito)", detail: "who may use your universe" };
76
78
  case "aws_acm_certificate":
@@ -101,6 +103,16 @@ process.stdin.on("end", () => {
101
103
  process.exit(2); // caller falls back to raw terraform output
102
104
  }
103
105
 
106
+ // THE GROUND'S OWN NUMBERS, or none. `prices` is an output of infra/<cloud>/prices.tf, so a
107
+ // planned run carries it under output_changes and an applied one under outputs. A
108
+ // ground that does not expose it simply prices nothing: an invented figure is worse
109
+ // than a missing one.
110
+ PRICE =
111
+ plan.output_changes?.prices?.after ??
112
+ plan.planned_values?.outputs?.prices?.value ??
113
+ plan.outputs?.prices?.value ??
114
+ {};
115
+
104
116
  const groups = { create: [], update: [], delete: [], replace: [] };
105
117
  const supporting = { create: 0, update: 0, delete: 0, replace: 0 };
106
118
 
@@ -135,7 +147,12 @@ process.stdin.on("end", () => {
135
147
  out.push("");
136
148
  }
137
149
 
138
- const monthly = Object.values(groups).flat().reduce((sum, d) => sum + (d.price ?? 0), 0);
150
+ // The GROUND's own total when it publishes one (it knows what an adopted database
151
+ // does not cost); otherwise the sum of what is on screen.
152
+ const ground = plan.output_changes?.monthly_estimate?.after ??
153
+ plan.planned_values?.outputs?.monthly_estimate?.value ??
154
+ plan.outputs?.monthly_estimate?.value;
155
+ const monthly = ground ?? Object.values(groups).flat().reduce((sum, d) => sum + (d.price ?? 0), 0);
139
156
  if (monthly) {
140
157
  out.push(` ${bold("Roughly")} ${bold(`$${monthly}/month`)} ${dim("at your provider's current prices, billed by them, not by unoverse")}`);
141
158
  out.push("");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "unoverse",
3
- "version": "0.1.68",
3
+ "version": "0.1.69",
4
4
  "description": "The Unoverse front door — create a Studio project, a universe, or a client app, and launch Studio.",
5
5
  "license": "SEE LICENSE IN README.md",
6
6
  "type": "module",