clever-tools 3.14.0 → 4.0.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 (93) hide show
  1. package/README.md +130 -37
  2. package/bin/clever.js +1427 -718
  3. package/package.json +61 -77
  4. package/src/clever-client/auth-bridge.js +9 -12
  5. package/src/clever-client/ng.js +1 -1
  6. package/src/clever-client/operators.js +7 -7
  7. package/src/command-options.js +6 -6
  8. package/src/command-promise-handler.js +6 -6
  9. package/src/commands/accesslogs.js +38 -29
  10. package/src/commands/activity.js +62 -40
  11. package/src/commands/addon.js +65 -69
  12. package/src/commands/applications.js +33 -31
  13. package/src/commands/cancel-deploy.js +7 -7
  14. package/src/commands/config.js +9 -7
  15. package/src/commands/console.js +3 -3
  16. package/src/commands/create.js +32 -31
  17. package/src/commands/curl.js +14 -36
  18. package/src/commands/database.js +10 -30
  19. package/src/commands/delete.js +8 -8
  20. package/src/commands/deploy.js +60 -46
  21. package/src/commands/diag.js +27 -25
  22. package/src/commands/domain.js +89 -91
  23. package/src/commands/drain.js +26 -14
  24. package/src/commands/emails.js +24 -28
  25. package/src/commands/env.js +18 -18
  26. package/src/commands/features.js +12 -18
  27. package/src/commands/keycloak.js +11 -11
  28. package/src/commands/kv.js +13 -13
  29. package/src/commands/link.js +9 -8
  30. package/src/commands/login.js +19 -27
  31. package/src/commands/logout.js +1 -1
  32. package/src/commands/logs.js +20 -12
  33. package/src/commands/makeDefault.js +5 -5
  34. package/src/commands/matomo.js +7 -7
  35. package/src/commands/metabase.js +9 -9
  36. package/src/commands/ng.js +32 -32
  37. package/src/commands/notify-email.js +11 -15
  38. package/src/commands/open.js +1 -1
  39. package/src/commands/otoroshi.js +11 -11
  40. package/src/commands/profile.js +8 -8
  41. package/src/commands/published-config.js +11 -11
  42. package/src/commands/restart.js +15 -8
  43. package/src/commands/scale.js +25 -16
  44. package/src/commands/service.js +18 -9
  45. package/src/commands/ssh-keys.js +25 -29
  46. package/src/commands/ssh.js +1 -2
  47. package/src/commands/status.js +31 -22
  48. package/src/commands/stop.js +3 -3
  49. package/src/commands/tcp-redirs.js +27 -26
  50. package/src/commands/tokens.js +44 -43
  51. package/src/commands/unlink.js +7 -5
  52. package/src/commands/version.js +2 -4
  53. package/src/commands/webhooks.js +8 -10
  54. package/src/experimental-features.js +7 -5
  55. package/src/format-table.js +46 -15
  56. package/src/initial-setup.js +2 -32
  57. package/src/initial-update-notifier.js +18 -0
  58. package/src/lib/has-param.js +16 -0
  59. package/src/lib/ng-print.js +21 -24
  60. package/src/lib/operator-commands.js +58 -53
  61. package/src/lib/prompts.js +5 -5
  62. package/src/lib/slugify.js +1 -1
  63. package/src/logger.js +24 -22
  64. package/src/models/activity.js +3 -3
  65. package/src/models/addon.js +52 -53
  66. package/src/models/app_configuration.js +34 -32
  67. package/src/models/application.js +90 -77
  68. package/src/models/application_configuration.js +19 -27
  69. package/src/models/configuration.js +30 -32
  70. package/src/models/deployments.js +9 -19
  71. package/src/models/domain.js +10 -9
  72. package/src/models/drain.js +16 -15
  73. package/src/models/exit-strategy-option.js +15 -5
  74. package/src/models/fs-utils.js +4 -3
  75. package/src/models/git.js +26 -32
  76. package/src/models/ids-resolver.js +37 -41
  77. package/src/models/isomorphic-http-with-agent.js +3 -3
  78. package/src/models/json-array.js +5 -6
  79. package/src/models/log-v4.js +44 -52
  80. package/src/models/log.js +40 -45
  81. package/src/models/namespaces.js +4 -4
  82. package/src/models/ng-resources.js +49 -39
  83. package/src/models/ng.js +41 -40
  84. package/src/models/node-dns-resolver.js +3 -3
  85. package/src/models/notification.js +7 -10
  86. package/src/models/operator.js +8 -10
  87. package/src/models/organisation.js +5 -8
  88. package/src/models/send-to-api.js +18 -11
  89. package/src/models/user.js +6 -5
  90. package/src/models/utils.js +5 -8
  91. package/src/models/variables.js +18 -20
  92. package/src/parsers.js +34 -34
  93. package/src/load-package-json.cjs +0 -5
@@ -1,23 +1,19 @@
1
- import os from 'node:os';
2
-
3
1
  import { releaseInfo as getLinuxInfos } from 'linux-release-info';
4
- import colors from 'colors/safe.js';
5
-
2
+ import os from 'node:os';
3
+ import { styleText } from 'node:util';
4
+ import pkg from '../../package.json' with { type: 'json' };
6
5
  import { Logger } from '../logger.js';
7
- import { getPackageJson } from '../load-package-json.cjs';
8
- import * as User from '../models/user.js';
9
6
  import { conf, loadOAuthConf } from '../models/configuration.js';
7
+ import * as User from '../models/user.js';
10
8
 
11
- const pkg = getPackageJson();
12
-
13
- export async function diag (params) {
9
+ export async function diag(params) {
14
10
  const { format } = params.options;
15
11
 
16
12
  /** @type {string} */
17
13
  const userId = await User.getCurrentId().catch(() => null);
18
14
  const authDetails = await loadOAuthConf();
19
15
 
20
- function getAuthState () {
16
+ function getAuthState() {
21
17
  if (authDetails.token == null) {
22
18
  return 'not connected';
23
19
  }
@@ -31,6 +27,7 @@ export async function diag (params) {
31
27
 
32
28
  const formattedDiag = {
33
29
  version: pkg.version,
30
+ commitId: pkg.commitId,
34
31
  nodeVersion: process.version,
35
32
  platform: os.platform(),
36
33
  release: os.release(),
@@ -59,35 +56,40 @@ export async function diag (params) {
59
56
  }
60
57
  case 'human':
61
58
  default: {
62
- Logger.println('clever-tools ' + colors.green(formattedDiag.version));
63
- Logger.println('Node.js ' + colors.green(formattedDiag.nodeVersion));
64
- Logger.println('Platform ' + colors.green(formattedDiag.platform));
65
- Logger.println('Release ' + colors.green(formattedDiag.release));
66
- Logger.println('Architecture ' + colors.green(formattedDiag.arch));
59
+ Logger.println('clever-tools ' + styleText('green', formattedDiag.version));
60
+ // Only available in built binaries
61
+ if (formattedDiag.commitId) {
62
+ Logger.println('Commit ' + styleText('green', formattedDiag.commitId));
63
+ }
64
+ Logger.println('Node.js ' + styleText('green', formattedDiag.nodeVersion));
65
+ Logger.println('Platform ' + styleText('green', formattedDiag.platform));
66
+ Logger.println('Release ' + styleText('green', formattedDiag.release));
67
+ Logger.println('Architecture ' + styleText('green', formattedDiag.arch));
67
68
  if (formattedDiag.linuxInfos != null) {
68
- Logger.println('Linux ' + colors.green(formattedDiag.linuxInfos));
69
+ Logger.println('Linux ' + styleText('green', formattedDiag.linuxInfos));
69
70
  }
70
- Logger.println('Shell ' + colors.green(formattedDiag.shell));
71
- Logger.println('Packaged ' + colors.green(formattedDiag.isPackaged));
72
- Logger.println('Exec path ' + colors.green(formattedDiag.execPath));
73
- Logger.println('Config file ' + colors.green(formattedDiag.configFile));
71
+ Logger.println('Shell ' + styleText('green', formattedDiag.shell));
72
+ Logger.println('Packaged ' + styleText('green', String(formattedDiag.isPackaged)));
73
+ Logger.println('Exec path ' + styleText('green', formattedDiag.execPath));
74
+ Logger.println('Config file ' + styleText('green', formattedDiag.configFile));
74
75
 
75
- Logger.println('Auth source ' + colors.green(formattedDiag.authSource));
76
+ Logger.println('Auth source ' + styleText('green', formattedDiag.authSource));
76
77
 
77
- const token = formattedDiag.oAuthToken == null ? colors.red('(none)') : colors.green(formattedDiag.oAuthToken);
78
+ const token =
79
+ formattedDiag.oAuthToken == null ? styleText('red', '(none)') : styleText('green', formattedDiag.oAuthToken);
78
80
  Logger.println('oAuth token ' + token);
79
81
 
80
82
  switch (formattedDiag.authState) {
81
83
  case 'authenticated': {
82
- Logger.println('User ID ' + colors.green(formattedDiag.userId));
84
+ Logger.println('User ID ' + styleText('green', formattedDiag.userId));
83
85
  break;
84
86
  }
85
87
  case 'authentication failed': {
86
- Logger.println('User ID ' + colors.red('Authentication failed'));
88
+ Logger.println('User ID ' + styleText('red', 'Authentication failed'));
87
89
  break;
88
90
  }
89
91
  case 'not connected': {
90
- Logger.println('User ID ' + colors.red('Not connected'));
92
+ Logger.println('User ID ' + styleText('red', 'Not connected'));
91
93
  }
92
94
  }
93
95
  }
@@ -1,23 +1,23 @@
1
- import * as Application from '../models/application.js';
2
- import { Logger } from '../logger.js';
3
1
  import {
4
2
  addDomain,
5
- get as getApp,
6
3
  getAllDomains,
4
+ get as getApp,
7
5
  getFavouriteDomain as getFavouriteDomainWithError,
8
6
  markFavouriteDomain,
9
7
  removeDomain,
10
8
  unmarkFavouriteDomain,
11
9
  } from '@clevercloud/client/esm/api/v2/application.js';
12
10
  import { getSummary } from '@clevercloud/client/esm/api/v2/user.js';
13
- import { sendToApi } from '../models/send-to-api.js';
14
- import colors from 'colors/safe.js';
15
- import { parse as parseDomain } from 'tldts';
11
+ import { getDefaultLoadBalancersDnsInfo } from '@clevercloud/client/esm/api/v4/load-balancers.js';
16
12
  import { diagDomainConfig } from '@clevercloud/client/esm/utils/diag-domain-config.js';
17
13
  import { sortDomains } from '@clevercloud/client/esm/utils/domains.js';
18
- import { DnsResolver } from '../models/node-dns-resolver.js';
19
14
  import _ from 'lodash';
20
- import { getDefaultLoadBalancersDnsInfo } from '@clevercloud/client/esm/api/v4/load-balancers.js';
15
+ import { styleText } from 'node:util';
16
+ import { parse as parseDomain } from 'tldts';
17
+ import { Logger } from '../logger.js';
18
+ import * as Application from '../models/application.js';
19
+ import { DnsResolver } from '../models/node-dns-resolver.js';
20
+ import { sendToApi } from '../models/send-to-api.js';
21
21
 
22
22
  /**
23
23
  * @typedef {import('@clevercloud/client/esm/utils/diag-domain-config.types.js').DomainInfo} DomainInfo
@@ -25,7 +25,7 @@ import { getDefaultLoadBalancersDnsInfo } from '@clevercloud/client/esm/api/v4/l
25
25
  * @typedef {import('@clevercloud/client/esm/utils/diag-domain-config.types.js').DomainDiag} DomainDiag
26
26
  */
27
27
 
28
- function getFavouriteDomain ({ ownerId, appId }) {
28
+ function getFavouriteDomain({ ownerId, appId }) {
29
29
  return getFavouriteDomainWithError({ id: ownerId, appId })
30
30
  .then(sendToApi)
31
31
  .then(({ fqdn }) => fqdn)
@@ -38,21 +38,19 @@ function getFavouriteDomain ({ ownerId, appId }) {
38
38
  });
39
39
  }
40
40
 
41
- export async function list (params) {
41
+ export async function list(params) {
42
42
  const { alias, app: appIdOrName } = params.options;
43
43
  const { ownerId, appId } = await Application.resolveId(appIdOrName, alias);
44
44
 
45
45
  const app = await getApp({ id: ownerId, appId }).then(sendToApi);
46
46
  const favouriteDomain = await getFavouriteDomain({ ownerId, appId });
47
47
  return app.vhosts.forEach(({ fqdn }) => {
48
- const prefix = (fqdn === favouriteDomain)
49
- ? '* '
50
- : ' ';
48
+ const prefix = fqdn === favouriteDomain ? '* ' : ' ';
51
49
  Logger.println(prefix + fqdn);
52
50
  });
53
51
  }
54
52
 
55
- export async function add (params) {
53
+ export async function add(params) {
56
54
  const [fqdn] = params.args;
57
55
  const { alias, app: appIdOrName } = params.options;
58
56
  const { ownerId, appId } = await Application.resolveId(appIdOrName, alias);
@@ -62,7 +60,7 @@ export async function add (params) {
62
60
  Logger.println('Your domain has been successfully saved');
63
61
  }
64
62
 
65
- export async function getFavourite (params) {
63
+ export async function getFavourite(params) {
66
64
  const { alias, app: appIdOrName } = params.options;
67
65
  const { ownerId, appId } = await Application.resolveId(appIdOrName, alias);
68
66
 
@@ -75,7 +73,7 @@ export async function getFavourite (params) {
75
73
  return Logger.println(favouriteDomain);
76
74
  }
77
75
 
78
- export async function setFavourite (params) {
76
+ export async function setFavourite(params) {
79
77
  const [fqdn] = params.args;
80
78
  const { alias, app: appIdOrName } = params.options;
81
79
  const { ownerId, appId } = await Application.resolveId(appIdOrName, alias);
@@ -84,7 +82,7 @@ export async function setFavourite (params) {
84
82
  Logger.println('Your favourite domain has been successfully set');
85
83
  }
86
84
 
87
- export async function unsetFavourite (params) {
85
+ export async function unsetFavourite(params) {
88
86
  const { alias, app: appIdOrName } = params.options;
89
87
  const { ownerId, appId } = await Application.resolveId(appIdOrName, alias);
90
88
 
@@ -92,7 +90,7 @@ export async function unsetFavourite (params) {
92
90
  Logger.println('Favourite domain has been successfully unset');
93
91
  }
94
92
 
95
- export async function rm (params) {
93
+ export async function rm(params) {
96
94
  const [fqdn] = params.args;
97
95
  const { alias, app: appIdOrName } = params.options;
98
96
  const { ownerId, appId } = await Application.resolveId(appIdOrName, alias);
@@ -102,7 +100,7 @@ export async function rm (params) {
102
100
  Logger.println('Your domain has been successfully removed');
103
101
  }
104
102
 
105
- export async function diagApplication (params) {
103
+ export async function diagApplication(params) {
106
104
  const dnsResolver = new DnsResolver();
107
105
  const allDomainDiagnostics = [];
108
106
  const { alias, app: appIdOrName, format, filter } = params.options;
@@ -125,14 +123,18 @@ export async function diagApplication (params) {
125
123
  for (const { hostname, pathPrefix, isApex } of sortedDomains) {
126
124
  const resolvedDnsConfig = {
127
125
  aRecords: await dnsResolver.resolveA(hostname),
128
- cnameRecords: await dnsResolver.resolveCname(hostname) ?? [],
126
+ cnameRecords: (await dnsResolver.resolveCname(hostname)) ?? [],
129
127
  };
130
128
 
131
- const diagnosticResults = diagDomainConfig({
132
- hostname,
133
- pathPrefix,
134
- isApex,
135
- }, resolvedDnsConfig, loadBalancerDnsConfig);
129
+ const diagnosticResults = diagDomainConfig(
130
+ {
131
+ hostname,
132
+ pathPrefix,
133
+ isApex,
134
+ },
135
+ resolvedDnsConfig,
136
+ loadBalancerDnsConfig,
137
+ );
136
138
  allDomainDiagnostics.push({ ...diagnosticResults, resolvedDnsConfig });
137
139
 
138
140
  if (diagnosticResults.diagSummary === 'invalid' || diagnosticResults.diagSummary === 'no-config') {
@@ -162,8 +164,7 @@ export async function diagApplication (params) {
162
164
  }
163
165
  }
164
166
 
165
- export async function overview (params) {
166
-
167
+ export async function overview(params) {
167
168
  const { format, filter } = params.options;
168
169
 
169
170
  const summary = await getSummary().then(sendToApi);
@@ -196,39 +197,40 @@ export async function overview (params) {
196
197
  }),
197
198
  );
198
199
 
199
- const applicationsWithParsedDomain = applicationsWithDomains
200
- .flatMap(({ app, domains }) => {
201
- return domains
202
- .filter((domain) => filter == null || domain.fqdn.includes(filter))
203
- .map((domain) => {
204
-
205
- // `validateHostname` is set to `false` so that wildcard domains may be parsed correctly
206
- const parsedDomain = parseDomain(domain.fqdn, { validateHostname: false });
207
- const pathname = new URL('https://' + domain.fqdn).pathname;
208
- const subdomains = parsedDomain.subdomain !== '' ? parsedDomain.subdomain.split('.') : [];
209
-
210
- // We're trying to create a propertyPath for lodash to create a tree structure object,
211
- // the propertyPath for `aaa.bbb.ccc.example.com/the-path` would be:
212
- // ["example.com", "example.com.ccc", "example.com.ccc.bbb", "example.com.ccc.bbb.aaa", "/path-aaa"]",
213
-
214
- const sortSegments = [parsedDomain.domain, ...subdomains.reverse()];
215
- const propertyPath = sortSegments.map((item, i, all) => {
216
- return all.slice(0, i + 1).reverse().join('.');
217
- });
218
- propertyPath.push(pathname);
219
-
220
- return {
221
- ownerId: app.ownerId,
222
- ownerName: app.ownerName,
223
- appId: app.id,
224
- appName: app.name,
225
- appConsoleUrl: `${consoleUrl}/goto/${app.id}`,
226
- appVariantSlug: app.variantSlug,
227
- domain: domain.fqdn,
228
- propetyPath: propertyPath,
229
- };
200
+ const applicationsWithParsedDomain = applicationsWithDomains.flatMap(({ app, domains }) => {
201
+ return domains
202
+ .filter((domain) => filter == null || domain.fqdn.includes(filter))
203
+ .map((domain) => {
204
+ // `validateHostname` is set to `false` so that wildcard domains may be parsed correctly
205
+ const parsedDomain = parseDomain(domain.fqdn, { validateHostname: false });
206
+ const pathname = new URL('https://' + domain.fqdn).pathname;
207
+ const subdomains = parsedDomain.subdomain !== '' ? parsedDomain.subdomain.split('.') : [];
208
+
209
+ // We're trying to create a propertyPath for lodash to create a tree structure object,
210
+ // the propertyPath for `aaa.bbb.ccc.example.com/the-path` would be:
211
+ // ["example.com", "example.com.ccc", "example.com.ccc.bbb", "example.com.ccc.bbb.aaa", "/path-aaa"]",
212
+
213
+ const sortSegments = [parsedDomain.domain, ...subdomains.reverse()];
214
+ const propertyPath = sortSegments.map((item, i, all) => {
215
+ return all
216
+ .slice(0, i + 1)
217
+ .reverse()
218
+ .join('.');
230
219
  });
231
- });
220
+ propertyPath.push(pathname);
221
+
222
+ return {
223
+ ownerId: app.ownerId,
224
+ ownerName: app.ownerName,
225
+ appId: app.id,
226
+ appName: app.name,
227
+ appConsoleUrl: `${consoleUrl}/goto/${app.id}`,
228
+ appVariantSlug: app.variantSlug,
229
+ domain: domain.fqdn,
230
+ propetyPath: propertyPath,
231
+ };
232
+ });
233
+ });
232
234
 
233
235
  const applicationsWithParsedDomainAsTree = {};
234
236
  for (const { propetyPath, ...appWithDomain } of applicationsWithParsedDomain) {
@@ -246,12 +248,10 @@ export async function overview (params) {
246
248
  if (Object.keys(applicationsWithParsedDomainAsSortedTree).length === 0) {
247
249
  if (filter?.length > 0) {
248
250
  Logger.println(`No matches for filter "${filter}"`);
249
- }
250
- else {
251
+ } else {
251
252
  Logger.println('No domains');
252
253
  }
253
- }
254
- else {
254
+ } else {
255
255
  recursiveDisplay(applicationsWithParsedDomainAsSortedTree);
256
256
  }
257
257
  break;
@@ -259,8 +259,7 @@ export async function overview (params) {
259
259
  }
260
260
 
261
261
  /** @param {DomainDiag & { resolvedDnsConfig: ResolveDnsResult }} domainDiag */
262
- function reportDomainDiagnostics ({ hostname, pathPrefix, resolvedDnsConfig, diagDetails, diagSummary }) {
263
-
262
+ function reportDomainDiagnostics({ hostname, pathPrefix, resolvedDnsConfig, diagDetails, diagSummary }) {
264
263
  const validDiags = diagDetails.filter((diag) => diag.code === 'valid-a');
265
264
  const unknownDiags = diagDetails.filter((diag) => diag.code === 'unknown-a');
266
265
  const missingDiags = diagDetails.filter((diag) => diag.code === 'missing-a');
@@ -271,24 +270,24 @@ function reportDomainDiagnostics ({ hostname, pathPrefix, resolvedDnsConfig, dia
271
270
  const hasARecords = resolvedDnsConfig.aRecords.length > 0;
272
271
  const hasCnameRecord = resolvedDnsConfig.cnameRecords.length > 0;
273
272
 
274
- Logger.println('\n' + colors.blue(hostname) + colors.yellow(pathPrefix) + '\n');
273
+ Logger.println('\n' + styleText('blue', hostname) + styleText('yellow', pathPrefix) + '\n');
275
274
 
276
275
  switch (diagSummary) {
277
276
  case 'managed':
278
- printlnWithIndent(colors.green('✔ Managed by Clever Cloud'), 2);
277
+ printlnWithIndent(styleText('green', '✔ Managed by Clever Cloud'), 2);
279
278
  printlnWithIndent('ⓘ cleverapps.io domains should only be used for testing purposes', 2);
280
279
  break;
281
280
  case 'no-config':
282
- printlnWithIndent(colors.red('✘ No DNS configuration found'), 2);
281
+ printlnWithIndent(styleText('red', '✘ No DNS configuration found'), 2);
283
282
  break;
284
283
  case 'valid':
285
- printlnWithIndent(colors.green('✔ Your configuration is valid'), 2);
284
+ printlnWithIndent(styleText('green', '✔ Your configuration is valid'), 2);
286
285
  break;
287
286
  case 'invalid':
288
- printlnWithIndent(colors.red('✘ Something is wrong with your configuration'), 2);
287
+ printlnWithIndent(styleText('red', '✘ Something is wrong with your configuration'), 2);
289
288
  break;
290
289
  case 'incomplete':
291
- printlnWithIndent(colors.yellow('⚠ Your configuration is incomplete'), 2);
290
+ printlnWithIndent(styleText('yellow', '⚠ Your configuration is incomplete'), 2);
292
291
  break;
293
292
  }
294
293
 
@@ -297,7 +296,7 @@ function reportDomainDiagnostics ({ hostname, pathPrefix, resolvedDnsConfig, dia
297
296
  Logger.println('');
298
297
  validDiags.forEach((diag) => {
299
298
  const source = hasCnameRecord ? `(from CNAME ${resolvedDnsConfig.cnameRecords[0]}.)` : '';
300
- printlnWithIndent(`${diag.record.value} ${colors.green('✔ A Record OK')} ${source}`, 2);
299
+ printlnWithIndent(`${diag.record.value} ${styleText('green', '✔ A Record OK')} ${source}`, 2);
301
300
  });
302
301
  }
303
302
 
@@ -320,7 +319,7 @@ function reportDomainDiagnostics ({ hostname, pathPrefix, resolvedDnsConfig, dia
320
319
  }
321
320
 
322
321
  // Replace unknown CNAME with missing CNAME
323
- if ((diagSummary === 'invalid') && missingCname != null && unknownCname != null) {
322
+ if (diagSummary === 'invalid' && missingCname != null && unknownCname != null) {
324
323
  Logger.println('');
325
324
  printlnWithIndent('➖Remove this CNAME record:', 2);
326
325
  printlnWithIndent(unknownCname.record.value + '. ', 6);
@@ -367,7 +366,7 @@ function reportDomainDiagnostics ({ hostname, pathPrefix, resolvedDnsConfig, dia
367
366
  * @param {Array<{ fqdn: string }>} vhosts
368
367
  * @returns {Array<Partial<DomainInfo>>} Array of parsed domain objects
369
368
  */
370
- function getParsedDomains (vhosts) {
369
+ function getParsedDomains(vhosts) {
371
370
  return vhosts.map(({ fqdn }) => {
372
371
  const { hostname, pathname } = new URL('https://' + fqdn);
373
372
  const { subdomain } = parseDomain(fqdn);
@@ -382,44 +381,43 @@ function getParsedDomains (vhosts) {
382
381
  * @param {string} text - The text to be printed.
383
382
  * @param {number} indentLevel - The number of spaces to indent the text.
384
383
  */
385
- function printlnWithIndent (text, indentLevel) {
384
+ function printlnWithIndent(text, indentLevel) {
386
385
  Logger.println(' '.repeat(indentLevel) + text);
387
386
  }
388
387
 
389
- function recursiveSort (obj) {
390
-
388
+ function recursiveSort(obj) {
391
389
  if (typeof obj === 'object' && obj.appId != null) {
392
390
  return obj;
393
391
  }
394
392
 
395
393
  const sortedObj = {};
396
- Object.keys(obj).sort((a, b) => {
397
- // if the domain contains a wildcard, we want it to be the first of subdomains
398
- const aWithReplacedWildcard = a.replace(/^\*/, 'a');
399
- const bWithReplacedWildcard = b.replace(/^\*/, 'a');
400
- return aWithReplacedWildcard.localeCompare(bWithReplacedWildcard);
401
- }).forEach((key) => {
402
- sortedObj[key] = recursiveSort(obj[key]);
403
- });
394
+ Object.keys(obj)
395
+ .sort((a, b) => {
396
+ // if the domain contains a wildcard, we want it to be the first of subdomains
397
+ const aWithReplacedWildcard = a.replace(/^\*/, 'a');
398
+ const bWithReplacedWildcard = b.replace(/^\*/, 'a');
399
+ return aWithReplacedWildcard.localeCompare(bWithReplacedWildcard);
400
+ })
401
+ .forEach((key) => {
402
+ sortedObj[key] = recursiveSort(obj[key]);
403
+ });
404
404
 
405
405
  return sortedObj;
406
406
  }
407
407
 
408
- function recursiveDisplay (obj, indentLevel = 0) {
409
-
408
+ function recursiveDisplay(obj, indentLevel = 0) {
410
409
  if (typeof obj === 'object' && obj.appId != null) {
411
410
  printlnWithIndent(`${obj.ownerName} | ${obj.appName} (${obj.appVariantSlug})`, indentLevel);
412
- printlnWithIndent(colors.blue(obj.appConsoleUrl), indentLevel);
411
+ printlnWithIndent(styleText('blue', obj.appConsoleUrl), indentLevel);
413
412
  return;
414
413
  }
415
414
 
416
415
  for (const [propertyPath, subObj] of Object.entries(obj)) {
417
416
  if (propertyPath !== '/') {
418
417
  Logger.println('');
419
- printlnWithIndent(colors.yellow(propertyPath), indentLevel);
418
+ printlnWithIndent(styleText('yellow', propertyPath), indentLevel);
420
419
  recursiveDisplay(subObj, indentLevel + 2);
421
- }
422
- else {
420
+ } else {
423
421
  recursiveDisplay(subObj, indentLevel);
424
422
  }
425
423
  }
@@ -1,18 +1,15 @@
1
+ import { createDrain, deleteDrain, getDrains, updateDrainState } from '@clevercloud/client/esm/api/v2/log.js';
2
+ import { Logger } from '../logger.js';
1
3
  import * as Application from '../models/application.js';
2
4
  import { createDrainBody } from '../models/drain.js';
3
- import { Logger } from '../logger.js';
4
-
5
- import { getDrains, createDrain, deleteDrain, updateDrainState } from '@clevercloud/client/esm/api/v2/log.js';
6
5
  import { sendToApi } from '../models/send-to-api.js';
7
6
 
8
7
  // TODO: This could be useful in other commands
9
- async function getAppOrAddonId ({ alias, appIdOrName, addonId }) {
10
- return (addonId != null)
11
- ? addonId
12
- : await Application.resolveId(appIdOrName, alias).then(({ appId }) => appId);
8
+ async function getAppOrAddonId({ alias, appIdOrName, addonId }) {
9
+ return addonId != null ? addonId : await Application.resolveId(appIdOrName, alias).then(({ appId }) => appId);
13
10
  }
14
11
 
15
- export async function list (params) {
12
+ export async function list(params) {
16
13
  const { alias, app: appIdOrName, addon: addonId, format } = params.options;
17
14
 
18
15
  const appIdOrAddonId = await getAppOrAddonId({ alias, appIdOrName, addonId });
@@ -52,20 +49,35 @@ export async function list (params) {
52
49
  }
53
50
  }
54
51
 
55
- export async function create (params) {
52
+ export async function create(params) {
56
53
  const [drainTargetType, drainTargetURL] = params.args;
57
- const { alias, app: appIdOrName, addon: addonId, username, password, 'api-key': apiKey, 'index-prefix': indexPrefix, 'sd-params': structuredDataParameters } = params.options;
54
+ const {
55
+ alias,
56
+ app: appIdOrName,
57
+ addon: addonId,
58
+ username,
59
+ password,
60
+ 'api-key': apiKey,
61
+ 'index-prefix': indexPrefix,
62
+ 'sd-params': structuredDataParameters,
63
+ } = params.options;
58
64
  const drainTargetCredentials = { username, password };
59
65
  const drainTargetConfig = { apiKey, indexPrefix, structuredDataParameters };
60
66
 
61
67
  const appIdOrAddonId = await getAppOrAddonId({ alias, appIdOrName, addonId });
62
- const body = createDrainBody(appIdOrAddonId, drainTargetURL, drainTargetType, drainTargetCredentials, drainTargetConfig);
68
+ const body = createDrainBody(
69
+ appIdOrAddonId,
70
+ drainTargetURL,
71
+ drainTargetType,
72
+ drainTargetCredentials,
73
+ drainTargetConfig,
74
+ );
63
75
  await createDrain({ appId: appIdOrAddonId }, body).then(sendToApi);
64
76
 
65
77
  Logger.println('Your drain has been successfully saved');
66
78
  }
67
79
 
68
- export async function rm (params) {
80
+ export async function rm(params) {
69
81
  const [drainId] = params.args;
70
82
  const { alias, app: appIdOrName, addon: addonId } = params.options;
71
83
 
@@ -75,7 +87,7 @@ export async function rm (params) {
75
87
  Logger.println('Your drain has been successfully removed');
76
88
  }
77
89
 
78
- export async function enable (params) {
90
+ export async function enable(params) {
79
91
  const [drainId] = params.args;
80
92
  const { alias, app: appIdOrName, addon: addonId } = params.options;
81
93
 
@@ -85,7 +97,7 @@ export async function enable (params) {
85
97
  Logger.println('Your drain has been enabled');
86
98
  }
87
99
 
88
- export async function disable (params) {
100
+ export async function disable(params) {
89
101
  const [drainId] = params.args;
90
102
  const { alias, app: appIdOrName, addon: addonId } = params.options;
91
103