dockup-cli 1.0.2 → 1.2.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.
package/bin/dockup ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ require('../dist/index.js');
@@ -0,0 +1,432 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target2, all) => {
9
+ for (var name in all)
10
+ __defProp(target2, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target2) => (target2 = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target2, "default", { value: mod, enumerable: true }) : target2,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+ var agent_exports = {};
30
+ __export(agent_exports, {
31
+ deployTrigger: () => deployTrigger,
32
+ deploymentsView: () => deploymentsView,
33
+ envImport: () => envImport,
34
+ envRemove: () => envRemove,
35
+ envSet: () => envSet,
36
+ envView: () => envView,
37
+ info: () => info,
38
+ logsView: () => logsView,
39
+ registryClear: () => registryClear,
40
+ registrySet: () => registrySet,
41
+ resourcesSet: () => resourcesSet,
42
+ resourcesView: () => resourcesView,
43
+ servicesList: () => servicesList,
44
+ statusView: () => statusView
45
+ });
46
+ module.exports = __toCommonJS(agent_exports);
47
+ var import_chalk = __toESM(require("chalk"));
48
+ var fs = __toESM(require("fs"));
49
+ var import_config = require("../lib/config");
50
+ var import_flags = require("../lib/flags");
51
+ var import_output = require("../lib/output");
52
+ var import_target = require("../lib/target");
53
+ var import_api = require("../lib/api");
54
+ function applyJson(opts) {
55
+ (0, import_flags.setJson)(!!opts?.json);
56
+ }
57
+ function requireAuth() {
58
+ if (!(0, import_config.isLoggedIn)()) (0, import_output.fail)("Not logged in. Run `dockup login` first.", { code: "not_logged_in" });
59
+ }
60
+ function target(arg) {
61
+ try {
62
+ return (0, import_target.resolveTarget)(arg);
63
+ } catch (e) {
64
+ return (0, import_output.fail)(e.message, { code: "no_target" });
65
+ }
66
+ }
67
+ function maskEnv(envVariables = []) {
68
+ return envVariables.map((e) => ({
69
+ key: e.key,
70
+ isSecret: !!e.isSecret,
71
+ value: e.isSecret ? null : e.value
72
+ }));
73
+ }
74
+ async function servicesList(opts) {
75
+ applyJson(opts);
76
+ requireAuth();
77
+ try {
78
+ const services = await import_api.api.getAllServices();
79
+ const slim = services.map((s) => ({
80
+ target: s.target,
81
+ name: s.name,
82
+ project: s.projectName,
83
+ status: s.status,
84
+ domain: s.domain || null,
85
+ branch: s.branch,
86
+ deploymentType: s.deploymentType,
87
+ countryCode: s.countryCode || null
88
+ }));
89
+ (0, import_output.emit)({ count: slim.length, services: slim }, () => {
90
+ console.log(import_chalk.default.cyan(`
91
+ ${slim.length} service(s)
92
+ `));
93
+ for (const s of slim) {
94
+ const dot = s.status === "running" ? import_chalk.default.green("\u25CF") : s.status === "error" ? import_chalk.default.red("\u25CF") : import_chalk.default.yellow("\u25CF");
95
+ console.log(` ${dot} ${import_chalk.default.bold(s.target.padEnd(40))} ${import_chalk.default.dim(s.status)}`);
96
+ }
97
+ console.log();
98
+ });
99
+ } catch (e) {
100
+ (0, import_output.fail)(e.message);
101
+ }
102
+ }
103
+ async function info(arg, opts) {
104
+ applyJson(opts);
105
+ requireAuth();
106
+ const t = target(arg);
107
+ try {
108
+ const s = await import_api.api.getServiceStatus(t.projectSlug, t.serviceSlug);
109
+ const data = {
110
+ target: `${t.projectSlug}/${t.serviceSlug}`,
111
+ name: s.name,
112
+ status: s.status,
113
+ deploymentType: s.deploymentType,
114
+ repoUrl: s.repoUrl || null,
115
+ branch: s.branch || null,
116
+ domain: s.domain || null,
117
+ port: s.port ?? null,
118
+ exposedPort: s.exposedPort ?? null,
119
+ autoDeployEnabled: !!s.autoDeployEnabled,
120
+ prPreviewEnabled: !!s.prPreviewEnabled,
121
+ memoryLimit: s.memoryLimit ?? null,
122
+ cpuLimit: s.cpuLimit ?? null,
123
+ lastDeployedAt: s.lastDeployedAt || null,
124
+ lastError: s.lastError || null,
125
+ env: maskEnv(s.envVariables),
126
+ customDomains: (s.customDomains || []).map((d) => ({ domain: d.domain, status: d.status, ssl: !!d.sslEnabled })),
127
+ latestDeployment: (s.deployments || [])[0] || null
128
+ };
129
+ (0, import_output.emit)(data, () => {
130
+ console.log(import_chalk.default.cyan(`
131
+ ${import_chalk.default.bold(data.name)} ${import_chalk.default.dim(data.target)}
132
+ `));
133
+ console.log(` ${import_chalk.default.dim("Status:")} ${data.status}`);
134
+ console.log(` ${import_chalk.default.dim("Repo:")} ${data.repoUrl || "N/A"} @ ${data.branch || "main"}`);
135
+ console.log(` ${import_chalk.default.dim("Domain:")} ${data.domain || "N/A"}`);
136
+ console.log(` ${import_chalk.default.dim("Type:")} ${data.deploymentType}`);
137
+ console.log(` ${import_chalk.default.dim("Auto-deploy:")} ${data.autoDeployEnabled}`);
138
+ console.log(` ${import_chalk.default.dim("Env vars:")} ${data.env.length}`);
139
+ console.log();
140
+ });
141
+ } catch (e) {
142
+ (0, import_output.fail)(e.message);
143
+ }
144
+ }
145
+ async function statusView(arg, opts) {
146
+ applyJson(opts);
147
+ requireAuth();
148
+ const t = target(arg);
149
+ try {
150
+ const s = await import_api.api.getServiceStatus(t.projectSlug, t.serviceSlug);
151
+ const latest = (s.deployments || [])[0] || null;
152
+ const data = {
153
+ target: `${t.projectSlug}/${t.serviceSlug}`,
154
+ status: s.status,
155
+ domain: s.domain || null,
156
+ lastDeployedAt: s.lastDeployedAt || null,
157
+ lastError: s.lastError || null,
158
+ latestDeployment: latest && {
159
+ id: latest.id,
160
+ status: latest.status,
161
+ commitHash: latest.commitHash,
162
+ commitMessage: latest.commitMessage,
163
+ startedAt: latest.startedAt,
164
+ completedAt: latest.completedAt
165
+ }
166
+ };
167
+ (0, import_output.emit)(data, () => {
168
+ console.log(import_chalk.default.cyan(`
169
+ ${import_chalk.default.bold(data.target)}: ${data.status}
170
+ `));
171
+ if (data.domain) console.log(` ${import_chalk.default.dim("URL:")} https://${data.domain}`);
172
+ if (latest) console.log(` ${import_chalk.default.dim("Last deploy:")} ${latest.status} (${(latest.commitHash || "").substring(0, 7)})`);
173
+ console.log();
174
+ });
175
+ } catch (e) {
176
+ (0, import_output.fail)(e.message);
177
+ }
178
+ }
179
+ async function deploymentsView(arg, opts) {
180
+ applyJson(opts);
181
+ requireAuth();
182
+ const t = target(arg);
183
+ const limit = parseInt(opts?.number || "10", 10);
184
+ try {
185
+ const deployments = await import_api.api.getDeployments(t.projectSlug, t.serviceSlug, limit);
186
+ (0, import_output.emit)({ target: `${t.projectSlug}/${t.serviceSlug}`, count: deployments.length, deployments }, () => {
187
+ console.log(import_chalk.default.cyan(`
188
+ Deployment history \u2014 ${t.serviceSlug}
189
+ `));
190
+ for (const d of deployments) {
191
+ const c = d.status === "success" ? import_chalk.default.green : d.status === "failed" ? import_chalk.default.red : import_chalk.default.yellow;
192
+ const when = d.createdAt ? new Date(d.createdAt).toLocaleString() : "";
193
+ console.log(` ${c(d.status.padEnd(9))} ${(d.commitHash || "").substring(0, 7)} ${import_chalk.default.dim(when)} ${d.commitMessage || ""}`);
194
+ }
195
+ console.log();
196
+ });
197
+ } catch (e) {
198
+ (0, import_output.fail)(e.message);
199
+ }
200
+ }
201
+ async function logsView(arg, opts) {
202
+ applyJson(opts);
203
+ requireAuth();
204
+ const t = target(arg);
205
+ const lines = parseInt(opts?.number || "200", 10);
206
+ try {
207
+ if (opts?.build) {
208
+ const res = await import_api.api.getBuildLogs(t.projectSlug, t.serviceSlug);
209
+ (0, import_output.emit)({ target: `${t.projectSlug}/${t.serviceSlug}`, type: "build", deployment: res.deployment, lastError: res.lastError, logs: res.logs }, () => {
210
+ console.log(res.logs);
211
+ });
212
+ } else {
213
+ const res = await import_api.api.getRuntimeLogs(t.projectSlug, t.serviceSlug, lines);
214
+ (0, import_output.emit)({ target: `${t.projectSlug}/${t.serviceSlug}`, type: res.type, logs: res.logs }, () => {
215
+ console.log(res.logs);
216
+ });
217
+ }
218
+ } catch (e) {
219
+ (0, import_output.fail)(e.message);
220
+ }
221
+ }
222
+ async function envView(opts) {
223
+ applyJson(opts);
224
+ requireAuth();
225
+ const t = target(opts?.service);
226
+ try {
227
+ const s = await import_api.api.getServiceStatus(t.projectSlug, t.serviceSlug);
228
+ const env = maskEnv(s.envVariables);
229
+ (0, import_output.emit)({ target: `${t.projectSlug}/${t.serviceSlug}`, count: env.length, env }, () => {
230
+ for (const e of env) console.log(` ${import_chalk.default.green(e.key)}=${e.isSecret ? import_chalk.default.dim("<secret>") : e.value}`);
231
+ });
232
+ } catch (e) {
233
+ (0, import_output.fail)(e.message);
234
+ }
235
+ }
236
+ async function envSet(keyValue, opts) {
237
+ applyJson(opts);
238
+ requireAuth();
239
+ const t = target(opts?.service);
240
+ const eq = keyValue.indexOf("=");
241
+ if (eq === -1) (0, import_output.fail)("Invalid format. Use KEY=value.", { code: "bad_format" });
242
+ const key = keyValue.substring(0, eq);
243
+ const value = keyValue.substring(eq + 1);
244
+ if (!key) (0, import_output.fail)("Key cannot be empty.", { code: "bad_format" });
245
+ try {
246
+ await import_api.api.setEnvVariable(t.projectSlug, t.serviceSlug, key, value, !!opts?.secret);
247
+ (0, import_output.ok)({ target: `${t.projectSlug}/${t.serviceSlug}`, key, secret: !!opts?.secret, hint: "redeploy to apply" }, () => {
248
+ console.log(import_chalk.default.green(`\u2713 set ${key}`) + import_chalk.default.dim(" (redeploy to apply)"));
249
+ });
250
+ } catch (e) {
251
+ (0, import_output.fail)(e.message);
252
+ }
253
+ }
254
+ async function envRemove(key, opts) {
255
+ applyJson(opts);
256
+ requireAuth();
257
+ const t = target(opts?.service);
258
+ try {
259
+ await import_api.api.deleteEnvVariable(t.projectSlug, t.serviceSlug, key);
260
+ (0, import_output.ok)({ target: `${t.projectSlug}/${t.serviceSlug}`, key, removed: true, hint: "redeploy to apply" }, () => {
261
+ console.log(import_chalk.default.green(`\u2713 removed ${key}`) + import_chalk.default.dim(" (redeploy to apply)"));
262
+ });
263
+ } catch (e) {
264
+ (0, import_output.fail)(e.message);
265
+ }
266
+ }
267
+ async function envImport(file, opts) {
268
+ applyJson(opts);
269
+ requireAuth();
270
+ const t = target(opts?.service);
271
+ let content;
272
+ try {
273
+ content = fs.readFileSync(file, "utf-8");
274
+ } catch {
275
+ return (0, import_output.fail)(`Cannot read file: ${file}`, { code: "file_not_found" });
276
+ }
277
+ const entries = [];
278
+ for (const raw of content.split("\n")) {
279
+ const line = raw.trim();
280
+ if (!line || line.startsWith("#")) continue;
281
+ const eq = line.indexOf("=");
282
+ if (eq === -1) continue;
283
+ let value = line.substring(eq + 1).trim();
284
+ if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
285
+ value = value.slice(1, -1);
286
+ }
287
+ entries.push({ key: line.substring(0, eq).trim(), value });
288
+ }
289
+ const done = [];
290
+ try {
291
+ for (const e of entries) {
292
+ await import_api.api.setEnvVariable(t.projectSlug, t.serviceSlug, e.key, e.value, !!opts?.secret);
293
+ done.push(e.key);
294
+ }
295
+ (0, import_output.ok)({ target: `${t.projectSlug}/${t.serviceSlug}`, imported: done.length, keys: done, hint: "redeploy to apply" }, () => {
296
+ console.log(import_chalk.default.green(`\u2713 imported ${done.length} variable(s)`) + import_chalk.default.dim(" (redeploy to apply)"));
297
+ });
298
+ } catch (e) {
299
+ (0, import_output.fail)(e.message, { importedBeforeError: done });
300
+ }
301
+ }
302
+ async function registrySet(arg, opts) {
303
+ applyJson(opts);
304
+ requireAuth();
305
+ const t = target(arg);
306
+ if (!opts?.url || !opts?.user || !opts?.token) {
307
+ return (0, import_output.fail)("--url, --user and --token are required", { code: "bad_args" });
308
+ }
309
+ try {
310
+ await import_api.api.setRegistry(t.projectSlug, t.serviceSlug, opts.url, opts.user, opts.token);
311
+ (0, import_output.ok)({ target: `${t.projectSlug}/${t.serviceSlug}`, registryUrl: opts.url, registryUsername: opts.user, hint: "redeploy to use the private base image" }, () => {
312
+ console.log(import_chalk.default.green(`\u2713 registry credentials saved for ${opts.url}`) + import_chalk.default.dim(" (redeploy to apply)"));
313
+ });
314
+ } catch (e) {
315
+ (0, import_output.fail)(e.message);
316
+ }
317
+ }
318
+ async function registryClear(arg, opts) {
319
+ applyJson(opts);
320
+ requireAuth();
321
+ const t = target(arg);
322
+ try {
323
+ await import_api.api.clearRegistry(t.projectSlug, t.serviceSlug);
324
+ (0, import_output.ok)({ target: `${t.projectSlug}/${t.serviceSlug}`, cleared: true }, () => {
325
+ console.log(import_chalk.default.green("\u2713 registry credentials cleared"));
326
+ });
327
+ } catch (e) {
328
+ (0, import_output.fail)(e.message);
329
+ }
330
+ }
331
+ const CPU_PER_MONTH = 463e-6 * 43200;
332
+ const MEM_PER_GB_PER_MONTH = 231e-6 * 43200;
333
+ const monthlyCost = (cpu, memMB) => Math.round((cpu * CPU_PER_MONTH + memMB / 1024 * MEM_PER_GB_PER_MONTH) * 100) / 100;
334
+ async function resourcesView(arg, opts) {
335
+ applyJson(opts);
336
+ requireAuth();
337
+ const t = target(arg);
338
+ try {
339
+ let memMB, cpu, name, kind;
340
+ if (opts?.db) {
341
+ const d = await import_api.api.getDatabaseDetail(t.projectSlug, t.serviceSlug);
342
+ const s = d.settings || d.database || d;
343
+ memMB = s.memoryLimitMB ?? 1024;
344
+ cpu = s.cpuLimit ?? 1;
345
+ name = d.database?.name || s.name || t.serviceSlug;
346
+ kind = "database";
347
+ } else {
348
+ const s = await import_api.api.getServiceStatus(t.projectSlug, t.serviceSlug);
349
+ memMB = s.memoryLimit ?? 2048;
350
+ cpu = s.cpuLimit ?? 2;
351
+ name = s.name || t.serviceSlug;
352
+ kind = "service";
353
+ }
354
+ const data = {
355
+ target: `${t.projectSlug}/${t.serviceSlug}`,
356
+ kind,
357
+ name,
358
+ cpu,
359
+ memoryMB: memMB,
360
+ estMonthlyUsd: monthlyCost(cpu, memMB),
361
+ limits: { maxCpu: 24, maxMemMB: 24576 }
362
+ };
363
+ (0, import_output.emit)(data, () => {
364
+ console.log(import_chalk.default.cyan(`
365
+ ${import_chalk.default.bold(name)} ${import_chalk.default.dim(data.target)} ${import_chalk.default.dim("(" + kind + ")")}
366
+ `));
367
+ console.log(` ${import_chalk.default.dim("CPU:")} ${cpu} vCPU`);
368
+ console.log(` ${import_chalk.default.dim("RAM:")} ${memMB >= 1024 ? memMB / 1024 + " GB" : memMB + " MB"}`);
369
+ console.log(` ${import_chalk.default.dim("Est.:")} $${data.estMonthlyUsd.toFixed(2)}/mo ${import_chalk.default.dim("+ disk")}`);
370
+ console.log();
371
+ });
372
+ } catch (e) {
373
+ (0, import_output.fail)(e.message);
374
+ }
375
+ }
376
+ async function resourcesSet(arg, opts) {
377
+ applyJson(opts);
378
+ requireAuth();
379
+ const t = target(arg);
380
+ const cpu = opts?.cpu !== void 0 ? parseFloat(opts.cpu) : void 0;
381
+ const mem = opts?.memory !== void 0 ? parseInt(opts.memory, 10) : void 0;
382
+ if (cpu === void 0 && mem === void 0) {
383
+ return (0, import_output.fail)("Provide --cpu <vCPU> and/or --memory <MB>.", { code: "bad_args" });
384
+ }
385
+ if (cpu !== void 0 && (isNaN(cpu) || cpu <= 0)) return (0, import_output.fail)("--cpu must be a positive number (max 24).", { code: "bad_args" });
386
+ if (mem !== void 0 && (isNaN(mem) || mem <= 0)) return (0, import_output.fail)("--memory must be MB (e.g. 4096, max 24576).", { code: "bad_args" });
387
+ try {
388
+ if (opts?.db) {
389
+ const res = await import_api.api.setDatabaseResources(t.projectSlug, t.serviceSlug, mem ?? 1024, cpu ?? 1);
390
+ (0, import_output.ok)({ target: `${t.projectSlug}/${t.serviceSlug}`, kind: "database", memoryMB: res.memoryLimitMB, cpu: res.cpuLimit, applied: res.applied, estMonthlyUsd: monthlyCost(res.cpuLimit, res.memoryLimitMB) }, () => {
391
+ console.log(import_chalk.default.green(`\u2713 ${res.cpuLimit} vCPU / ${res.memoryLimitMB} MB`) + import_chalk.default.dim(` ${res.applied ? "(applied)" : "(start db to apply)"} ~$${monthlyCost(res.cpuLimit, res.memoryLimitMB).toFixed(2)}/mo`));
392
+ });
393
+ } else {
394
+ const res = await import_api.api.setServiceResources(t.projectSlug, t.serviceSlug, mem ?? 2048, cpu ?? 2);
395
+ (0, import_output.ok)({ target: `${t.projectSlug}/${t.serviceSlug}`, kind: "service", memoryMB: res.memoryLimit, cpu: res.cpuLimit, applied: res.applied, estMonthlyUsd: monthlyCost(res.cpuLimit, res.memoryLimit) }, () => {
396
+ console.log(import_chalk.default.green(`\u2713 ${res.cpuLimit} vCPU / ${res.memoryLimit} MB`) + import_chalk.default.dim(` ${res.applied ? "(applied)" : "(redeploy to apply)"} ~$${monthlyCost(res.cpuLimit, res.memoryLimit).toFixed(2)}/mo`));
397
+ });
398
+ }
399
+ } catch (e) {
400
+ (0, import_output.fail)(e.message);
401
+ }
402
+ }
403
+ async function deployTrigger(arg, opts) {
404
+ applyJson(opts);
405
+ requireAuth();
406
+ const t = target(arg);
407
+ try {
408
+ const result = await import_api.api.deploy(t.projectSlug, t.serviceSlug, opts?.branch ? { branch: opts.branch } : void 0);
409
+ (0, import_output.ok)({ target: `${t.projectSlug}/${t.serviceSlug}`, deploymentId: result?.deployment?.id || null, hint: "poll `dockup status` for progress" }, () => {
410
+ console.log(import_chalk.default.green("\u2713 deployment triggered") + import_chalk.default.dim(` (${result?.deployment?.id || "n/a"})`));
411
+ });
412
+ } catch (e) {
413
+ (0, import_output.fail)(e.message);
414
+ }
415
+ }
416
+ // Annotate the CommonJS export names for ESM import in node:
417
+ 0 && (module.exports = {
418
+ deployTrigger,
419
+ deploymentsView,
420
+ envImport,
421
+ envRemove,
422
+ envSet,
423
+ envView,
424
+ info,
425
+ logsView,
426
+ registryClear,
427
+ registrySet,
428
+ resourcesSet,
429
+ resourcesView,
430
+ servicesList,
431
+ statusView
432
+ });