relight-cli 0.1.0 → 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 (45) hide show
  1. package/README.md +77 -34
  2. package/package.json +12 -4
  3. package/src/cli.js +350 -1
  4. package/src/commands/apps.js +128 -0
  5. package/src/commands/auth.js +13 -4
  6. package/src/commands/config.js +282 -0
  7. package/src/commands/cost.js +593 -0
  8. package/src/commands/db.js +775 -0
  9. package/src/commands/deploy.js +264 -0
  10. package/src/commands/doctor.js +69 -13
  11. package/src/commands/domains.js +223 -0
  12. package/src/commands/logs.js +111 -0
  13. package/src/commands/open.js +42 -0
  14. package/src/commands/ps.js +121 -0
  15. package/src/commands/scale.js +132 -0
  16. package/src/commands/service.js +227 -0
  17. package/src/lib/clouds/aws.js +309 -35
  18. package/src/lib/clouds/cf.js +401 -2
  19. package/src/lib/clouds/gcp.js +255 -4
  20. package/src/lib/clouds/neon.js +147 -0
  21. package/src/lib/clouds/slicervm.js +139 -0
  22. package/src/lib/config.js +200 -2
  23. package/src/lib/docker.js +34 -0
  24. package/src/lib/link.js +31 -5
  25. package/src/lib/providers/aws/app.js +481 -0
  26. package/src/lib/providers/aws/db.js +504 -0
  27. package/src/lib/providers/aws/dns.js +232 -0
  28. package/src/lib/providers/aws/registry.js +59 -0
  29. package/src/lib/providers/cf/app.js +596 -0
  30. package/src/lib/providers/cf/bundle.js +70 -0
  31. package/src/lib/providers/cf/db.js +181 -0
  32. package/src/lib/providers/cf/dns.js +148 -0
  33. package/src/lib/providers/cf/registry.js +17 -0
  34. package/src/lib/providers/gcp/app.js +429 -0
  35. package/src/lib/providers/gcp/db.js +372 -0
  36. package/src/lib/providers/gcp/dns.js +166 -0
  37. package/src/lib/providers/gcp/registry.js +30 -0
  38. package/src/lib/providers/neon/db.js +306 -0
  39. package/src/lib/providers/resolve.js +79 -0
  40. package/src/lib/providers/slicervm/app.js +396 -0
  41. package/src/lib/providers/slicervm/db.js +33 -0
  42. package/src/lib/providers/slicervm/dns.js +58 -0
  43. package/src/lib/providers/slicervm/registry.js +7 -0
  44. package/worker-template/package.json +10 -0
  45. package/worker-template/src/index.js +260 -0
package/src/lib/config.js CHANGED
@@ -15,18 +15,51 @@ export var CLOUD_NAMES = {
15
15
 
16
16
  export var CLOUD_IDS = Object.keys(CLOUD_NAMES);
17
17
 
18
+ export var SERVICE_TYPES = {
19
+ slicervm: { layer: "compute", name: "SlicerVM" },
20
+ neon: { layer: "db", name: "Neon" },
21
+ };
22
+
18
23
  export function getConfig() {
19
24
  if (!existsSync(CONFIG_PATH)) {
20
25
  console.error("Not authenticated. Run `relight auth` first.");
21
26
  process.exit(1);
22
27
  }
23
- return JSON.parse(readFileSync(CONFIG_PATH, "utf-8"));
28
+ var config = JSON.parse(readFileSync(CONFIG_PATH, "utf-8"));
29
+ return migrateSlicervm(config);
30
+ }
31
+
32
+ function migrateSlicervm(config) {
33
+ if (config.clouds && config.clouds.slicervm) {
34
+ if (!config.services) config.services = {};
35
+ if (!config.services.slicervm) {
36
+ var old = config.clouds.slicervm;
37
+ config.services.slicervm = {
38
+ layer: "compute",
39
+ type: "slicervm",
40
+ ...old,
41
+ };
42
+ }
43
+ delete config.clouds.slicervm;
44
+ if (config.default_cloud === "slicervm") {
45
+ delete config.default_cloud;
46
+ }
47
+ saveConfig(config);
48
+ }
49
+ // Migrate old "addons" key to "services"
50
+ if (config.addons && !config.services) {
51
+ config.services = config.addons;
52
+ delete config.addons;
53
+ saveConfig(config);
54
+ }
55
+ return config;
24
56
  }
25
57
 
26
58
  export function tryGetConfig() {
27
59
  if (!existsSync(CONFIG_PATH)) return null;
28
60
  try {
29
- return JSON.parse(readFileSync(CONFIG_PATH, "utf-8"));
61
+ var config = JSON.parse(readFileSync(CONFIG_PATH, "utf-8"));
62
+ return migrateSlicervm(config);
30
63
  } catch {
31
64
  return null;
32
65
  }
@@ -56,3 +89,168 @@ export function getAuthenticatedClouds() {
56
89
  (id) => config.clouds[id] && Object.keys(config.clouds[id]).length > 0
57
90
  );
58
91
  }
92
+
93
+ export function getDefaultCloud() {
94
+ var config = tryGetConfig();
95
+ if (!config) return null;
96
+ return config.default_cloud || null;
97
+ }
98
+
99
+ export function resolveCloudConfig(cloudId) {
100
+ var config = getConfig();
101
+ var cloud = config.clouds && config.clouds[cloudId];
102
+ if (!cloud) {
103
+ console.error(
104
+ `Not authenticated with ${CLOUD_NAMES[cloudId] || cloudId}. Run \`relight auth --cloud ${cloudId}\` first.`
105
+ );
106
+ process.exit(1);
107
+ }
108
+
109
+ // Return a normalized config object that providers can use
110
+ if (cloudId === "cf") {
111
+ return { accountId: cloud.accountId, apiToken: cloud.token };
112
+ }
113
+ if (cloudId === "gcp") {
114
+ return { clientEmail: cloud.clientEmail, privateKey: cloud.privateKey, project: cloud.project };
115
+ }
116
+ if (cloudId === "aws") {
117
+ return { accessKeyId: cloud.accessKeyId, secretAccessKey: cloud.secretAccessKey, region: cloud.region };
118
+ }
119
+ return cloud;
120
+ }
121
+
122
+ export function getServiceConfig(name) {
123
+ var config = getConfig();
124
+ var service = config.services && config.services[name];
125
+ if (!service) {
126
+ console.error(
127
+ `Service '${name}' not found. Run \`relight service add\` to register it.`
128
+ );
129
+ process.exit(1);
130
+ }
131
+ return service;
132
+ }
133
+
134
+ export function tryGetServiceConfig(name) {
135
+ var config = tryGetConfig();
136
+ if (!config || !config.services) return null;
137
+ return config.services[name] || null;
138
+ }
139
+
140
+ export function getRegisteredServices() {
141
+ var config = tryGetConfig();
142
+ if (!config || !config.services) return [];
143
+ return Object.entries(config.services).map(([name, service]) => ({
144
+ name,
145
+ ...service,
146
+ }));
147
+ }
148
+
149
+ export function saveServiceConfig(name, data) {
150
+ var config = tryGetConfig() || { clouds: {} };
151
+ if (!config.services) config.services = {};
152
+ config.services[name] = data;
153
+ saveConfig(config);
154
+ }
155
+
156
+ export function removeServiceConfig(name) {
157
+ var config = tryGetConfig();
158
+ if (!config || !config.services) return;
159
+ delete config.services[name];
160
+ saveConfig(config);
161
+ }
162
+
163
+ export function getCloudMeta(cloudId, key) {
164
+ var config = tryGetConfig();
165
+ if (!config || !config.clouds || !config.clouds[cloudId]) return undefined;
166
+ var meta = config.clouds[cloudId]._meta;
167
+ if (!meta) return undefined;
168
+ return key ? meta[key] : meta;
169
+ }
170
+
171
+ export function setCloudMeta(cloudId, key, value) {
172
+ var config = getConfig();
173
+ if (!config.clouds[cloudId]._meta) config.clouds[cloudId]._meta = {};
174
+ if (value === undefined) {
175
+ delete config.clouds[cloudId]._meta[key];
176
+ if (Object.keys(config.clouds[cloudId]._meta).length === 0) {
177
+ delete config.clouds[cloudId]._meta;
178
+ }
179
+ } else {
180
+ config.clouds[cloudId]._meta[key] = value;
181
+ }
182
+ saveConfig(config);
183
+ }
184
+
185
+ export function getServiceMeta(serviceName, key) {
186
+ var config = tryGetConfig();
187
+ if (!config || !config.services || !config.services[serviceName]) return undefined;
188
+ var meta = config.services[serviceName]._meta;
189
+ if (!meta) return undefined;
190
+ return key ? meta[key] : meta;
191
+ }
192
+
193
+ export function setServiceMeta(serviceName, key, value) {
194
+ var config = getConfig();
195
+ if (!config.services || !config.services[serviceName]) {
196
+ throw new Error(`Service '${serviceName}' not found.`);
197
+ }
198
+ if (!config.services[serviceName]._meta) config.services[serviceName]._meta = {};
199
+ if (value === undefined) {
200
+ delete config.services[serviceName]._meta[key];
201
+ if (Object.keys(config.services[serviceName]._meta).length === 0) {
202
+ delete config.services[serviceName]._meta;
203
+ }
204
+ } else {
205
+ config.services[serviceName]._meta[key] = value;
206
+ }
207
+ saveConfig(config);
208
+ }
209
+
210
+ // --- Database registry ---
211
+
212
+ export function getDatabaseConfig(name) {
213
+ var config = tryGetConfig();
214
+ if (!config || !config.databases) return null;
215
+ return config.databases[name] || null;
216
+ }
217
+
218
+ export function saveDatabaseConfig(name, data) {
219
+ var config = tryGetConfig() || { clouds: {} };
220
+ if (!config.databases) config.databases = {};
221
+ config.databases[name] = data;
222
+ saveConfig(config);
223
+ }
224
+
225
+ export function removeDatabaseConfig(name) {
226
+ var config = tryGetConfig();
227
+ if (!config || !config.databases) return;
228
+ delete config.databases[name];
229
+ saveConfig(config);
230
+ }
231
+
232
+ export function listDatabases() {
233
+ var config = tryGetConfig();
234
+ if (!config || !config.databases) return [];
235
+ return Object.entries(config.databases).map(([name, data]) => ({
236
+ name,
237
+ ...data,
238
+ }));
239
+ }
240
+
241
+ export function normalizeServiceConfig(service) {
242
+ if (service.type === "slicervm") {
243
+ var cfg = { hostGroup: service.hostGroup, baseDomain: service.baseDomain };
244
+ if (service.socketPath) {
245
+ cfg.socketPath = service.socketPath;
246
+ } else {
247
+ cfg.apiUrl = service.apiUrl;
248
+ cfg.apiToken = service.token;
249
+ }
250
+ return cfg;
251
+ }
252
+ if (service.type === "neon") {
253
+ return { apiKey: service.apiKey };
254
+ }
255
+ return service;
256
+ }
@@ -0,0 +1,34 @@
1
+ import { execSync } from "child_process";
2
+
3
+ function ensureDocker() {
4
+ try {
5
+ execSync("docker version", { stdio: "pipe" });
6
+ } catch {
7
+ console.error("Docker is not running. Install and start Docker first.");
8
+ process.exit(1);
9
+ }
10
+ }
11
+
12
+ export function dockerBuild(contextPath, tag, opts = {}) {
13
+ ensureDocker();
14
+ var platform = opts.platform || "linux/amd64";
15
+ execSync(
16
+ `docker build --platform ${platform} --provenance=false -t ${tag} ${contextPath}`,
17
+ { stdio: "pipe" }
18
+ );
19
+ }
20
+
21
+ export function dockerTag(source, target) {
22
+ execSync(`docker tag ${source} ${target}`, { stdio: "pipe" });
23
+ }
24
+
25
+ export function dockerPush(tag) {
26
+ execSync(`docker push ${tag}`, { stdio: "pipe" });
27
+ }
28
+
29
+ export function dockerLogin(registry, username, password) {
30
+ execSync(
31
+ `docker login --password-stdin --username ${username} ${registry}`,
32
+ { input: password, stdio: "pipe" }
33
+ );
34
+ }
package/src/lib/link.js CHANGED
@@ -1,19 +1,30 @@
1
1
  import { readFileSync, writeFileSync, unlinkSync } from "fs";
2
+ import YAML from "yaml";
2
3
  import { fatal, fmt } from "./output.js";
3
4
 
4
- var LINK_FILE = ".relight";
5
+ var LINK_FILE = ".relight.yaml";
5
6
 
6
7
  export function readLink() {
7
8
  try {
8
- var data = JSON.parse(readFileSync(LINK_FILE, "utf-8"));
9
- return data;
9
+ var raw = readFileSync(LINK_FILE, "utf-8");
10
+ // Support both YAML and legacy JSON
11
+ return YAML.parse(raw);
10
12
  } catch {
11
13
  return null;
12
14
  }
13
15
  }
14
16
 
15
- export function linkApp(name, cloud) {
16
- writeFileSync(LINK_FILE, JSON.stringify({ app: name, cloud }) + "\n");
17
+ export function linkApp(name, cloud, dns, db, compute) {
18
+ var data = { app: name };
19
+ if (compute) {
20
+ data.compute = compute;
21
+ }
22
+ if (cloud) {
23
+ data.cloud = cloud;
24
+ }
25
+ if (dns && dns !== cloud) data.dns = dns;
26
+ if (db && db !== cloud) data.db = db;
27
+ writeFileSync(LINK_FILE, YAML.stringify(data));
17
28
  }
18
29
 
19
30
  export function unlinkApp() {
@@ -38,3 +49,18 @@ export function resolveCloud(cloud) {
38
49
  if (linked && linked.cloud) return linked.cloud;
39
50
  return null;
40
51
  }
52
+
53
+ export function resolveDns() {
54
+ var linked = readLink();
55
+ return linked?.dns || null;
56
+ }
57
+
58
+ export function resolveDb() {
59
+ var linked = readLink();
60
+ return linked?.db || null;
61
+ }
62
+
63
+ export function resolveCompute() {
64
+ var linked = readLink();
65
+ return linked?.compute || null;
66
+ }