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,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) {
@@ -54,7 +60,7 @@ export async function list (ownerId, appId, showAll) {
54
60
  });
55
61
  }
56
62
 
57
- function validateAddonVersionAndOptions (region, version, addonOptions, providerInfos, planType) {
63
+ function validateAddonVersionAndOptions(region, version, addonOptions, providerInfos, planType) {
58
64
  if (providerInfos != null) {
59
65
  if (version != null) {
60
66
  const type = planType.value.toLowerCase();
@@ -62,16 +68,18 @@ function validateAddonVersionAndOptions (region, version, addonOptions, provider
62
68
  const cluster = providerInfos.clusters.find(({ zone }) => zone === region);
63
69
  if (cluster == null) {
64
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
+ );
65
75
  }
66
- else if (cluster.version !== version) {
67
- throw new Error(`Invalid version ${version}, selected shared cluster only supports version ${cluster.version}`);
68
- }
69
- }
70
- else if (type === 'dedicated') {
76
+ } else if (type === 'dedicated') {
71
77
  const availableVersions = Object.keys(providerInfos.dedicated);
72
78
  const hasVersion = availableVersions.find((availableVersion) => availableVersion === version);
73
79
  if (hasVersion == null) {
74
- 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
+ );
75
83
  }
76
84
  }
77
85
  }
@@ -90,8 +98,7 @@ function validateAddonVersionAndOptions (region, version, addonOptions, provider
90
98
  }
91
99
 
92
100
  availableOptions = cluster.features;
93
- }
94
- else if (type === 'dedicated') {
101
+ } else if (type === 'dedicated') {
95
102
  availableOptions = providerInfos.dedicated[chosenVersion].features;
96
103
  }
97
104
 
@@ -102,8 +109,7 @@ function validateAddonVersionAndOptions (region, version, addonOptions, provider
102
109
  let availableOptionsError = null;
103
110
  if (optionNames.length > 0) {
104
111
  availableOptionsError = `Available options are: ${optionNames}.`;
105
- }
106
- else {
112
+ } else {
107
113
  availableOptionsError = 'No options are available for this plan.';
108
114
  }
109
115
 
@@ -116,17 +122,15 @@ function validateAddonVersionAndOptions (region, version, addonOptions, provider
116
122
  version: chosenVersion,
117
123
  ...addonOptions,
118
124
  };
119
- }
120
- else {
125
+ } else {
121
126
  if (version != null) {
122
- 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.");
123
128
  }
124
129
  return {};
125
130
  }
126
131
  }
127
132
 
128
- export async function create ({ ownerId, name, providerName, planName, region, skipConfirmation, version, addonOptions }) {
129
-
133
+ export async function create({ ownerId, name, providerName, planName, region, version, addonOptions }) {
130
134
  // TODO: We should be able to use it without {}
131
135
  const provider = await getProvider(providerName);
132
136
 
@@ -147,7 +151,9 @@ export async function create ({ ownerId, name, providerName, planName, region, s
147
151
  // This missing feature should have been added during the add-on's development phase
148
152
  // The console has a similar check so I believe we shouldn't hit this
149
153
  if (providerInfos != null && planType == null) {
150
- 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
+ );
151
157
  }
152
158
 
153
159
  const createOptions = validateAddonVersionAndOptions(region, version, addonOptions, providerInfos, planType);
@@ -166,7 +172,7 @@ export async function create ({ ownerId, name, providerName, planName, region, s
166
172
  return createdAddon;
167
173
  }
168
174
 
169
- async function getByName (ownerId, addonNameOrRealId) {
175
+ async function getByName(ownerId, addonNameOrRealId) {
170
176
  const addons = await getAllAddons({ id: ownerId }).then(sendToApi);
171
177
  const filteredAddons = addons.filter(({ name, realId }) => {
172
178
  return name === addonNameOrRealId || realId === addonNameOrRealId;
@@ -180,7 +186,7 @@ async function getByName (ownerId, addonNameOrRealId) {
180
186
  throw new Error('Ambiguous addon name');
181
187
  }
182
188
 
183
- async function getId (ownerId, addon) {
189
+ async function getId(ownerId, addon) {
184
190
  if (addon.addon_id) {
185
191
  return addon.addon_id;
186
192
  }
@@ -188,44 +194,41 @@ async function getId (ownerId, addon) {
188
194
  return addonDetails.id;
189
195
  }
190
196
 
191
- export async function link (ownerId, appId, addon) {
197
+ export async function link(ownerId, appId, addon) {
192
198
  const addonId = await getId(ownerId, addon);
193
199
  return linkAddon({ id: ownerId, appId }, JSON.stringify(addonId)).then(sendToApi);
194
200
  }
195
201
 
196
- export async function unlink (ownerId, appId, addon) {
202
+ export async function unlink(ownerId, appId, addon) {
197
203
  const addonId = await getId(ownerId, addon);
198
204
  return unlinkAddon({ id: ownerId, appId, addonId }).then(sendToApi);
199
205
  }
200
206
 
201
- export async function deleteAddon (ownerId, addonIdOrName, skipConfirmation) {
207
+ export async function deleteAddon(ownerId, addonIdOrName, skipConfirmation) {
202
208
  const addonId = await getId(ownerId, addonIdOrName);
203
209
 
204
210
  if (!skipConfirmation) {
205
- await confirm(
206
- 'Deleting the add-on can\'t be undone, are you sure?',
207
- 'No confirmation, aborting add-on deletion',
208
- );
211
+ await confirm("Deleting the add-on can't be undone, are you sure?", 'No confirmation, aborting add-on deletion');
209
212
  }
210
213
 
211
214
  return removeAddon({ id: ownerId, addonId }).then(sendToApi);
212
215
  }
213
216
 
214
- export async function rename (ownerId, addon, name) {
217
+ export async function rename(ownerId, addon, name) {
215
218
  const addonId = await getId(ownerId, addon);
216
219
  return updateAddon({ id: ownerId, addonId }, { name }).then(sendToApi);
217
220
  }
218
221
 
219
- export function completeRegion () {
222
+ export function completeRegion() {
220
223
  return cliparse.autocomplete.words(['par', 'mtl']);
221
224
  }
222
225
 
223
226
  // TODO: We need to fix this
224
- export function completePlan () {
227
+ export function completePlan() {
225
228
  return cliparse.autocomplete.words(['dev', 's', 'm', 'l', 'xl', 'xxl']);
226
229
  }
227
230
 
228
- export async function findById (addonId) {
231
+ export async function findById(addonId) {
229
232
  const { user, organisations } = await getSummary({}).then(sendToApi);
230
233
  for (const orga of [user, ...organisations]) {
231
234
  for (const simpleAddon of orga.addons) {
@@ -241,7 +244,7 @@ export async function findById (addonId) {
241
244
  throw new Error(`Could not find add-on with ID: ${addonId}`);
242
245
  }
243
246
 
244
- export async function findByName (addonName) {
247
+ export async function findByName(addonName) {
245
248
  const { user, organisations } = await getSummary({}).then(sendToApi);
246
249
  for (const orga of [user, ...organisations]) {
247
250
  for (const simpleAddon of orga.addons) {
@@ -257,8 +260,7 @@ export async function findByName (addonName) {
257
260
  throw new Error(`Could not find add-on with name ${addonName}`);
258
261
  }
259
262
 
260
- export async function findOwnerId (org, addonId) {
261
-
263
+ export async function findOwnerId(org, addonId) {
262
264
  if (org != null && org.orga_id != null) {
263
265
  return org.orga_id;
264
266
  }
@@ -271,12 +273,12 @@ export async function findOwnerId (org, addonId) {
271
273
  throw new Error(`Add-on ${addonId} does not exist`);
272
274
  }
273
275
 
274
- export function parseAddonOptions (options) {
276
+ export function parseAddonOptions(options) {
275
277
  if (options == null) {
276
278
  return {};
277
279
  }
278
280
 
279
- const pairs = options.split(/,(?=\w+=)/) || [];
281
+ const pairs = options.split(/,(?=\w+(?:-\w+)*=)/) || [];
280
282
 
281
283
  return pairs.reduce((options, pair) => {
282
284
  const [key, ...valueParts] = pair.split('=');
@@ -289,14 +291,11 @@ export function parseAddonOptions (options) {
289
291
  let formattedValue = value;
290
292
  if (value === 'true' || value === 'enabled') {
291
293
  formattedValue = 'true';
292
- }
293
- else if (value === 'false' || value === 'disabled') {
294
+ } else if (value === 'false' || value === 'disabled') {
294
295
  formattedValue = 'false';
295
- }
296
- else if (typeof key === 'string') {
296
+ } else if (typeof key === 'string') {
297
297
  formattedValue = value;
298
- }
299
- else {
298
+ } else {
300
299
  throw new Error(`Can't parse option value: ${value}. Accepted values are: enabled, disabled, true, false`);
301
300
  }
302
301
 
@@ -305,7 +304,7 @@ export function parseAddonOptions (options) {
305
304
  }, {});
306
305
  }
307
306
 
308
- function getPlan (planName, plans) {
307
+ function getPlan(planName, plans) {
309
308
  // if no plan specified, pick the cheapest one
310
309
  if (planName == null || planName === '') {
311
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 };