clever-tools 3.13.1 → 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 +62 -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 +33 -32
  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 +28 -11
  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 +26 -21
  64. package/src/models/activity.js +3 -3
  65. package/src/models/addon.js +54 -56
  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,21 +1,26 @@
1
- import cliparse from 'cliparse';
2
-
3
- import { get as getAddon, getAll as getAllAddons, getAllEnvVars, remove as removeAddon, create as createAddon, update as updateAddon } from '@clevercloud/client/esm/api/v2/addon.js';
1
+ import {
2
+ create as createAddon,
3
+ get as getAddon,
4
+ getAll as getAllAddons,
5
+ getAllEnvVars,
6
+ remove as removeAddon,
7
+ update as updateAddon,
8
+ } from '@clevercloud/client/esm/api/v2/addon.js';
9
+ import { getAllLinkedAddons, linkAddon, unlinkAddon } from '@clevercloud/client/esm/api/v2/application.js';
4
10
  import { getAllAddonProviders } from '@clevercloud/client/esm/api/v2/product.js';
5
11
  import { getSummary } from '@clevercloud/client/esm/api/v2/user.js';
6
12
  import { getAddonProvider } from '@clevercloud/client/esm/api/v4/addon-providers.js';
7
-
13
+ import cliparse from 'cliparse';
8
14
  import { confirm } from '../lib/prompts.js';
9
15
  import { Logger } from '../logger.js';
10
- import { sendToApi } from '../models/send-to-api.js';
11
16
  import { resolveOwnerId } from './ids-resolver.js';
12
- import { getAllLinkedAddons, linkAddon, unlinkAddon } from '@clevercloud/client/esm/api/v2/application.js';
17
+ import { sendToApi } from './send-to-api.js';
13
18
 
14
- export function listProviders () {
19
+ export function listProviders() {
15
20
  return getAllAddonProviders({}).then(sendToApi);
16
21
  }
17
22
 
18
- export async function getProvider (providerName) {
23
+ export async function getProvider(providerName) {
19
24
  const providers = await listProviders();
20
25
  const provider = providers.find((p) => p.id === providerName);
21
26
  if (provider == null) {
@@ -24,8 +29,9 @@ export async function getProvider (providerName) {
24
29
  return provider;
25
30
  }
26
31
 
27
- export function getProviderInfos (providerName) {
28
- return getAddonProvider({ providerId: providerName }).then(sendToApi)
32
+ export function getProviderInfos(providerName) {
33
+ return getAddonProvider({ providerId: providerName })
34
+ .then(sendToApi)
29
35
  .catch(() => {
30
36
  // An error can occur because the add-on api doesn't implement this endpoint yet
31
37
  // This is fine, just ignore it
@@ -34,7 +40,7 @@ export function getProviderInfos (providerName) {
34
40
  });
35
41
  }
36
42
 
37
- export async function list (ownerId, appId, showAll) {
43
+ export async function list(ownerId, appId, showAll) {
38
44
  const allAddons = await getAllAddons({ id: ownerId }).then(sendToApi);
39
45
 
40
46
  if (appId == null) {
@@ -43,9 +49,8 @@ export async function list (ownerId, appId, showAll) {
43
49
  }
44
50
 
45
51
  const myAddons = await getAllLinkedAddons({ id: ownerId, appId }).then(sendToApi);
46
-
47
- if (showAll == null) {
48
- return myAddons;
52
+ if (!showAll) {
53
+ return myAddons.map((addon) => ({ ...addon, isLinked: true }));
49
54
  }
50
55
 
51
56
  const myAddonIds = myAddons.map((addon) => addon.id);
@@ -55,7 +60,7 @@ export async function list (ownerId, appId, showAll) {
55
60
  });
56
61
  }
57
62
 
58
- function validateAddonVersionAndOptions (region, version, addonOptions, providerInfos, planType) {
63
+ function validateAddonVersionAndOptions(region, version, addonOptions, providerInfos, planType) {
59
64
  if (providerInfos != null) {
60
65
  if (version != null) {
61
66
  const type = planType.value.toLowerCase();
@@ -63,16 +68,18 @@ function validateAddonVersionAndOptions (region, version, addonOptions, provider
63
68
  const cluster = providerInfos.clusters.find(({ zone }) => zone === region);
64
69
  if (cluster == null) {
65
70
  throw new Error(`Can't find cluster for region ${region}`);
71
+ } else if (cluster.version !== version) {
72
+ throw new Error(
73
+ `Invalid version ${version}, selected shared cluster only supports version ${cluster.version}`,
74
+ );
66
75
  }
67
- else if (cluster.version !== version) {
68
- throw new Error(`Invalid version ${version}, selected shared cluster only supports version ${cluster.version}`);
69
- }
70
- }
71
- else if (type === 'dedicated') {
76
+ } else if (type === 'dedicated') {
72
77
  const availableVersions = Object.keys(providerInfos.dedicated);
73
78
  const hasVersion = availableVersions.find((availableVersion) => availableVersion === version);
74
79
  if (hasVersion == null) {
75
- throw new Error(`Invalid version ${addonOptions.version}, available versions are: ${availableVersions.join(', ')}`);
80
+ throw new Error(
81
+ `Invalid version ${addonOptions.version}, available versions are: ${availableVersions.join(', ')}`,
82
+ );
76
83
  }
77
84
  }
78
85
  }
@@ -91,8 +98,7 @@ function validateAddonVersionAndOptions (region, version, addonOptions, provider
91
98
  }
92
99
 
93
100
  availableOptions = cluster.features;
94
- }
95
- else if (type === 'dedicated') {
101
+ } else if (type === 'dedicated') {
96
102
  availableOptions = providerInfos.dedicated[chosenVersion].features;
97
103
  }
98
104
 
@@ -103,8 +109,7 @@ function validateAddonVersionAndOptions (region, version, addonOptions, provider
103
109
  let availableOptionsError = null;
104
110
  if (optionNames.length > 0) {
105
111
  availableOptionsError = `Available options are: ${optionNames}.`;
106
- }
107
- else {
112
+ } else {
108
113
  availableOptionsError = 'No options are available for this plan.';
109
114
  }
110
115
 
@@ -117,17 +122,15 @@ function validateAddonVersionAndOptions (region, version, addonOptions, provider
117
122
  version: chosenVersion,
118
123
  ...addonOptions,
119
124
  };
120
- }
121
- else {
125
+ } else {
122
126
  if (version != null) {
123
- throw new Error('You provided a version for an add-on that doesn\'t support choosing the version.');
127
+ throw new Error("You provided a version for an add-on that doesn't support choosing the version.");
124
128
  }
125
129
  return {};
126
130
  }
127
131
  }
128
132
 
129
- export async function create ({ ownerId, name, providerName, planName, region, skipConfirmation, version, addonOptions }) {
130
-
133
+ export async function create({ ownerId, name, providerName, planName, region, version, addonOptions }) {
131
134
  // TODO: We should be able to use it without {}
132
135
  const provider = await getProvider(providerName);
133
136
 
@@ -148,7 +151,9 @@ export async function create ({ ownerId, name, providerName, planName, region, s
148
151
  // This missing feature should have been added during the add-on's development phase
149
152
  // The console has a similar check so I believe we shouldn't hit this
150
153
  if (providerInfos != null && planType == null) {
151
- throw new Error('Internal error. The selected plan misses the TYPE feature. Please contact our support with the command line you used');
154
+ throw new Error(
155
+ 'Internal error. The selected plan misses the TYPE feature. Please contact our support with the command line you used',
156
+ );
152
157
  }
153
158
 
154
159
  const createOptions = validateAddonVersionAndOptions(region, version, addonOptions, providerInfos, planType);
@@ -167,7 +172,7 @@ export async function create ({ ownerId, name, providerName, planName, region, s
167
172
  return createdAddon;
168
173
  }
169
174
 
170
- async function getByName (ownerId, addonNameOrRealId) {
175
+ async function getByName(ownerId, addonNameOrRealId) {
171
176
  const addons = await getAllAddons({ id: ownerId }).then(sendToApi);
172
177
  const filteredAddons = addons.filter(({ name, realId }) => {
173
178
  return name === addonNameOrRealId || realId === addonNameOrRealId;
@@ -181,7 +186,7 @@ async function getByName (ownerId, addonNameOrRealId) {
181
186
  throw new Error('Ambiguous addon name');
182
187
  }
183
188
 
184
- async function getId (ownerId, addon) {
189
+ async function getId(ownerId, addon) {
185
190
  if (addon.addon_id) {
186
191
  return addon.addon_id;
187
192
  }
@@ -189,44 +194,41 @@ async function getId (ownerId, addon) {
189
194
  return addonDetails.id;
190
195
  }
191
196
 
192
- export async function link (ownerId, appId, addon) {
197
+ export async function link(ownerId, appId, addon) {
193
198
  const addonId = await getId(ownerId, addon);
194
199
  return linkAddon({ id: ownerId, appId }, JSON.stringify(addonId)).then(sendToApi);
195
200
  }
196
201
 
197
- export async function unlink (ownerId, appId, addon) {
202
+ export async function unlink(ownerId, appId, addon) {
198
203
  const addonId = await getId(ownerId, addon);
199
204
  return unlinkAddon({ id: ownerId, appId, addonId }).then(sendToApi);
200
205
  }
201
206
 
202
- export async function deleteAddon (ownerId, addonIdOrName, skipConfirmation) {
207
+ export async function deleteAddon(ownerId, addonIdOrName, skipConfirmation) {
203
208
  const addonId = await getId(ownerId, addonIdOrName);
204
209
 
205
210
  if (!skipConfirmation) {
206
- await confirm(
207
- 'Deleting the add-on can\'t be undone, are you sure?',
208
- 'No confirmation, aborting add-on deletion',
209
- );
211
+ await confirm("Deleting the add-on can't be undone, are you sure?", 'No confirmation, aborting add-on deletion');
210
212
  }
211
213
 
212
214
  return removeAddon({ id: ownerId, addonId }).then(sendToApi);
213
215
  }
214
216
 
215
- export async function rename (ownerId, addon, name) {
217
+ export async function rename(ownerId, addon, name) {
216
218
  const addonId = await getId(ownerId, addon);
217
219
  return updateAddon({ id: ownerId, addonId }, { name }).then(sendToApi);
218
220
  }
219
221
 
220
- export function completeRegion () {
222
+ export function completeRegion() {
221
223
  return cliparse.autocomplete.words(['par', 'mtl']);
222
224
  }
223
225
 
224
226
  // TODO: We need to fix this
225
- export function completePlan () {
227
+ export function completePlan() {
226
228
  return cliparse.autocomplete.words(['dev', 's', 'm', 'l', 'xl', 'xxl']);
227
229
  }
228
230
 
229
- export async function findById (addonId) {
231
+ export async function findById(addonId) {
230
232
  const { user, organisations } = await getSummary({}).then(sendToApi);
231
233
  for (const orga of [user, ...organisations]) {
232
234
  for (const simpleAddon of orga.addons) {
@@ -242,7 +244,7 @@ export async function findById (addonId) {
242
244
  throw new Error(`Could not find add-on with ID: ${addonId}`);
243
245
  }
244
246
 
245
- export async function findByName (addonName) {
247
+ export async function findByName(addonName) {
246
248
  const { user, organisations } = await getSummary({}).then(sendToApi);
247
249
  for (const orga of [user, ...organisations]) {
248
250
  for (const simpleAddon of orga.addons) {
@@ -258,8 +260,7 @@ export async function findByName (addonName) {
258
260
  throw new Error(`Could not find add-on with name ${addonName}`);
259
261
  }
260
262
 
261
- export async function findOwnerId (org, addonId) {
262
-
263
+ export async function findOwnerId(org, addonId) {
263
264
  if (org != null && org.orga_id != null) {
264
265
  return org.orga_id;
265
266
  }
@@ -272,12 +273,12 @@ export async function findOwnerId (org, addonId) {
272
273
  throw new Error(`Add-on ${addonId} does not exist`);
273
274
  }
274
275
 
275
- export function parseAddonOptions (options) {
276
+ export function parseAddonOptions(options) {
276
277
  if (options == null) {
277
278
  return {};
278
279
  }
279
280
 
280
- const pairs = options.split(/,(?=\w+=)/) || [];
281
+ const pairs = options.split(/,(?=\w+(?:-\w+)*=)/) || [];
281
282
 
282
283
  return pairs.reduce((options, pair) => {
283
284
  const [key, ...valueParts] = pair.split('=');
@@ -290,14 +291,11 @@ export function parseAddonOptions (options) {
290
291
  let formattedValue = value;
291
292
  if (value === 'true' || value === 'enabled') {
292
293
  formattedValue = 'true';
293
- }
294
- else if (value === 'false' || value === 'disabled') {
294
+ } else if (value === 'false' || value === 'disabled') {
295
295
  formattedValue = 'false';
296
- }
297
- else if (typeof key === 'string') {
296
+ } else if (typeof key === 'string') {
298
297
  formattedValue = value;
299
- }
300
- else {
298
+ } else {
301
299
  throw new Error(`Can't parse option value: ${value}. Accepted values are: enabled, disabled, true, false`);
302
300
  }
303
301
 
@@ -306,7 +304,7 @@ export function parseAddonOptions (options) {
306
304
  }, {});
307
305
  }
308
306
 
309
- function getPlan (planName, plans) {
307
+ function getPlan(planName, plans) {
310
308
  // if no plan specified, pick the cheapest one
311
309
  if (planName == null || planName === '') {
312
310
  return plans.sort((p1, p2) => p1.price - p2.price)[0];
@@ -1,15 +1,13 @@
1
+ import _ from 'lodash';
1
2
  import { promises as fs } from 'node:fs';
2
3
  import path from 'node:path';
3
-
4
- import _ from 'lodash';
5
4
  import { slugify } from '../lib/slugify.js';
6
-
7
5
  import { Logger } from '../logger.js';
8
- import * as User from './user.js';
9
6
  import { conf } from './configuration.js';
7
+ import * as User from './user.js';
10
8
 
11
9
  // TODO: Maybe use fs-utils findPath()
12
- export async function loadApplicationConf (ignoreParentConfig = false, pathToFolder) {
10
+ export async function loadApplicationConf(ignoreParentConfig = false, pathToFolder) {
13
11
  if (pathToFolder == null) {
14
12
  pathToFolder = path.dirname(conf.APP_CONFIGURATION_FILE);
15
13
  }
@@ -19,17 +17,16 @@ export async function loadApplicationConf (ignoreParentConfig = false, pathToFol
19
17
  try {
20
18
  const contents = await fs.readFile(fullPath);
21
19
  return JSON.parse(contents);
22
- }
23
- catch (error) {
20
+ } catch (error) {
24
21
  Logger.info('Cannot load app configuration from ' + conf.APP_CONFIGURATION_FILE + ' (' + error + ')');
25
22
  if (ignoreParentConfig || path.parse(pathToFolder).root === pathToFolder) {
26
23
  return { apps: [] };
27
24
  }
28
25
  return loadApplicationConf(ignoreParentConfig, path.normalize(path.join(pathToFolder, '..')));
29
26
  }
30
- };
27
+ }
31
28
 
32
- export async function addLinkedApplication (appData, alias, ignoreParentConfig) {
29
+ export async function addLinkedApplication(appData, alias, ignoreParentConfig) {
33
30
  const currentConfig = await loadApplicationConf(ignoreParentConfig);
34
31
 
35
32
  const appEntry = {
@@ -50,9 +47,9 @@ export async function addLinkedApplication (appData, alias, ignoreParentConfig)
50
47
  }
51
48
 
52
49
  return persistConfig(currentConfig);
53
- };
50
+ }
54
51
 
55
- export async function removeLinkedApplication ({ appId, alias }) {
52
+ export async function removeLinkedApplication({ appId, alias }) {
56
53
  const currentConfig = await loadApplicationConf();
57
54
  const appToUnlink = currentConfig.apps.find((a) => a.app_id === appId || a.alias === alias);
58
55
  if (appToUnlink == null) {
@@ -70,9 +67,9 @@ export async function removeLinkedApplication ({ appId, alias }) {
70
67
 
71
68
  await persistConfig(newConfig);
72
69
  return true;
73
- };
70
+ }
74
71
 
75
- export function findApp (config, alias) {
72
+ export function findApp(config, alias) {
76
73
  if (_.isEmpty(config.apps)) {
77
74
  throw new Error('There is no linked or targeted application. Use `--app` option or `clever link` command.');
78
75
  }
@@ -83,7 +80,9 @@ export function findApp (config, alias) {
83
80
  throw new Error(`There are no applications matching alias ${alias}`);
84
81
  }
85
82
  if (secondAppByAlias != null) {
86
- throw new Error(`There are several applications matching alias ${alias}. This should not happen, your \`.clever.json\` should be fixed.`);
83
+ throw new Error(
84
+ `There are several applications matching alias ${alias}. This should not happen, your \`.clever.json\` should be fixed.`,
85
+ );
87
86
  }
88
87
  return appByAlias;
89
88
  }
@@ -91,7 +90,7 @@ export function findApp (config, alias) {
91
90
  return findDefaultApp(config);
92
91
  }
93
92
 
94
- export function checkAlreadyLinked (apps, name, alias) {
93
+ export function checkAlreadyLinked(apps, name, alias) {
95
94
  const appAliasExists = apps.some((app) => app.alias != null && app.alias === alias);
96
95
  if (appAliasExists) {
97
96
  throw new Error(`An application is already linked with the alias '${alias}'`);
@@ -103,7 +102,7 @@ export function checkAlreadyLinked (apps, name, alias) {
103
102
  }
104
103
  }
105
104
 
106
- function findDefaultApp (config) {
105
+ function findDefaultApp(config) {
107
106
  if (_.isEmpty(config.apps)) {
108
107
  throw new Error('There is no linked or targeted application. Use `--app` option or `clever link` command.');
109
108
  }
@@ -111,7 +110,9 @@ function findDefaultApp (config) {
111
110
  if (config.default != null) {
112
111
  const defaultApp = _.find(config.apps, { app_id: config.default });
113
112
  if (defaultApp == null) {
114
- throw new Error('The default application is not listed anymore. This should not happen, your `.clever.json` should be fixed.');
113
+ throw new Error(
114
+ 'The default application is not listed anymore. This should not happen, your `.clever.json` should be fixed.',
115
+ );
115
116
  }
116
117
  return defaultApp;
117
118
  }
@@ -121,10 +122,12 @@ function findDefaultApp (config) {
121
122
  }
122
123
 
123
124
  const aliases = _.map(config.apps, 'alias').join(', ');
124
- throw new Error(`Several applications are linked. You can specify one with the "--alias" option. Run "clever applications" to list linked applications. Available aliases: ${aliases}`);
125
+ throw new Error(
126
+ `Several applications are linked. You can specify one with the "--alias" option. Run "clever applications" to list linked applications. Available aliases: ${aliases}`,
127
+ );
125
128
  }
126
129
 
127
- async function getAppDetailsForId (appId) {
130
+ async function getAppDetailsForId(appId) {
128
131
  const config = await loadApplicationConf();
129
132
 
130
133
  if (_.isEmpty(config.apps)) {
@@ -136,19 +139,19 @@ async function getAppDetailsForId (appId) {
136
139
  throw new Error(`There are no applications matching id '${appId}'`);
137
140
  }
138
141
  if (secondAppById != null) {
139
- throw new Error(`There are several applications matching id '${appId}'.`
140
- + 'This should not happen, your `.clever.json` should be fixed.');
142
+ throw new Error(
143
+ `There are several applications matching id '${appId}'.` +
144
+ 'This should not happen, your `.clever.json` should be fixed.',
145
+ );
141
146
  }
142
147
 
143
148
  return appById;
144
149
  }
145
150
 
146
- export async function getAppDetails ({ alias }) {
151
+ export async function getAppDetails({ alias }) {
147
152
  const config = await loadApplicationConf();
148
153
  const app = findApp(config, alias);
149
- const ownerId = (app.org_id != null)
150
- ? app.org_id
151
- : await User.getCurrentId();
154
+ const ownerId = app.org_id != null ? app.org_id : await User.getCurrentId();
152
155
  return {
153
156
  appId: app.app_id,
154
157
  ownerId: ownerId,
@@ -156,24 +159,23 @@ export async function getAppDetails ({ alias }) {
156
159
  name: app.name,
157
160
  alias: app.alias,
158
161
  };
159
- };
162
+ }
160
163
 
161
- export async function getMostNaturalName (appId) {
164
+ export async function getMostNaturalName(appId) {
162
165
  try {
163
166
  const details = await getAppDetailsForId(appId);
164
167
  return details.alias || details.name || appId;
165
- }
166
- catch {
168
+ } catch {
167
169
  return appId;
168
170
  }
169
171
  }
170
172
 
171
- function persistConfig (modifiedConfig) {
173
+ function persistConfig(modifiedConfig) {
172
174
  const jsonContents = JSON.stringify(modifiedConfig, null, 2);
173
175
  return fs.writeFile(conf.APP_CONFIGURATION_FILE, jsonContents);
174
- };
176
+ }
175
177
 
176
- export async function setDefault (alias) {
178
+ export async function setDefault(alias) {
177
179
  const config = await loadApplicationConf();
178
180
  const app = findApp(config, alias);
179
181
  const newConfig = { ...config, default: app.app_id };