clever-tools 3.10.1 → 3.12.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.
@@ -2,8 +2,8 @@ import { sendToApi } from '../models/send-to-api.js';
2
2
  import { getBackups } from '@clevercloud/client/esm/api/v2/backups.js';
3
3
  import { Logger } from '../logger.js';
4
4
  import { formatTable as initFormatTable } from '../format-table.js';
5
- import superagent from 'superagent';
6
5
  import fs from 'node:fs';
6
+ import { Writable } from 'node:stream';
7
7
  import { findOwnerId } from '../models/addon.js';
8
8
  import { resolveRealId, resolveAddonId } from '../models/ids-resolver.js';
9
9
 
@@ -80,14 +80,14 @@ export async function downloadBackups (params) {
80
80
  throw new Error('no backup with this ID');
81
81
  }
82
82
 
83
- const res = await superagent
84
- .get(backup.download_url)
85
- .responseType('blob');
86
-
87
- if (output) {
88
- fs.writeFileSync(output, res.body);
89
- return;
83
+ const response = await globalThis.fetch(backup.download_url);
84
+ if (!response.ok) {
85
+ throw new Error('Failed to download backup');
90
86
  }
91
87
 
92
- process.stdout.write(res.body);
88
+ await response
89
+ .body
90
+ .pipeTo(
91
+ Writable.toWeb(output ? fs.createWriteStream(output) : process.stdout),
92
+ );
93
93
  }
@@ -9,7 +9,7 @@ import {
9
9
  removeDomain,
10
10
  unmarkFavouriteDomain,
11
11
  } from '@clevercloud/client/esm/api/v2/application.js';
12
- import { getSummary } from '@clevercloud/client/cjs/api/v2/user.js';
12
+ import { getSummary } from '@clevercloud/client/esm/api/v2/user.js';
13
13
  import { sendToApi } from '../models/send-to-api.js';
14
14
  import colors from 'colors/safe.js';
15
15
  import { parse as parseDomain } from 'tldts';
@@ -17,6 +17,7 @@ import { diagDomainConfig } from '@clevercloud/client/esm/utils/diag-domain-conf
17
17
  import { sortDomains } from '@clevercloud/client/esm/utils/domains.js';
18
18
  import { DnsResolver } from '../models/node-dns-resolver.js';
19
19
  import _ from 'lodash';
20
+ import { getDefaultLoadBalancersDnsInfo } from '@clevercloud/client/esm/api/v4/load-balancers.js';
20
21
 
21
22
  /**
22
23
  * @typedef {import('@clevercloud/client/esm/utils/diag-domain-config.types.js').DomainInfo} DomainInfo
@@ -110,7 +111,7 @@ export async function diagApplication (params) {
110
111
  let hasError = false;
111
112
 
112
113
  const app = await getApp({ id: ownerId, appId }).then(sendToApi);
113
- const expectedDnsForPublicLoadBalancer = await getDefaultLoadBalancersDnsInfo({ id: ownerId, appId }).then(sendToApi);
114
+ const expectedDnsForPublicLoadBalancer = await getDefaultLoadBalancersDnsInfo({ ownerId, appId }).then(sendToApi);
114
115
 
115
116
  const loadBalancerDnsConfig = {
116
117
  aRecords: expectedDnsForPublicLoadBalancer[0].dns.a,
@@ -181,7 +182,16 @@ export async function overview (params) {
181
182
 
182
183
  const applicationsWithDomains = await Promise.all(
183
184
  applications.map(async (app) => {
184
- const domains = await getAllDomains({ id: app.ownerId, appId: app.id }).then(sendToApi);
185
+ const domains = await getAllDomains({ id: app.ownerId, appId: app.id })
186
+ .then(sendToApi)
187
+ .catch((error) => {
188
+ // if the user cannot access application domains, we simply act as if there were no domains
189
+ if (error?.response?.status === 403) {
190
+ Logger.printErrorLine(`You cannot list domains for application ${app.name} (${app.id})`);
191
+ return [];
192
+ }
193
+ throw error;
194
+ });
185
195
  return { app, domains };
186
196
  }),
187
197
  );
@@ -351,19 +361,6 @@ function reportDomainDiagnostics ({ hostname, pathPrefix, resolvedDnsConfig, dia
351
361
  }
352
362
  }
353
363
 
354
- // TODO: put in clever client
355
- function getDefaultLoadBalancersDnsInfo (params) {
356
- return Promise.resolve({
357
- method: 'get',
358
- url: `/v4/load-balancers/organisations/${params.id}/applications/${params.appId}/load-balancers/default`,
359
- headers: {
360
- Accept: 'application/json',
361
- },
362
- // no query params
363
- // no body
364
- });
365
- }
366
-
367
364
  /**
368
365
  * Parses domain information from vhosts array
369
366
  *
@@ -4,16 +4,23 @@ import colors from 'colors/safe.js';
4
4
  import * as variables from '../models/variables.js';
5
5
  import { sendToApi } from '../models/send-to-api.js';
6
6
  import { toNameEqualsValueString, validateName } from '@clevercloud/client/esm/utils/env-vars.js';
7
- import * as application from '@clevercloud/client/esm/api/v2/application.js';
7
+ import {
8
+ getAllEnvVars,
9
+ getAllEnvVarsForAddons,
10
+ getAllEnvVarsForDependencies,
11
+ updateEnvVar,
12
+ updateAllEnvVars,
13
+ removeEnvVar,
14
+ } from '@clevercloud/client/esm/api/v2/application.js';
8
15
 
9
16
  export async function list (params) {
10
17
  const { alias, app: appIdOrName, 'add-export': addExportsOption, format } = params.options;
11
18
  const { ownerId, appId } = await Application.resolveId(appIdOrName, alias);
12
19
 
13
20
  const [envFromApp, envFromAddons, envFromDeps] = await Promise.all([
14
- application.getAllEnvVars({ id: ownerId, appId }).then(sendToApi),
15
- application.getAllEnvVarsForAddons({ id: ownerId, appId }).then(sendToApi),
16
- application.getAllEnvVarsForDependencies({ id: ownerId, appId }).then(sendToApi),
21
+ getAllEnvVars({ id: ownerId, appId }).then(sendToApi),
22
+ getAllEnvVarsForAddons({ id: ownerId, appId }).then(sendToApi),
23
+ getAllEnvVarsForDependencies({ id: ownerId, appId }).then(sendToApi),
17
24
  ]);
18
25
 
19
26
  switch (format) {
@@ -69,7 +76,7 @@ export async function set (params) {
69
76
 
70
77
  const { ownerId, appId } = await Application.resolveId(appIdOrName, alias);
71
78
 
72
- await application.updateEnvVar({ id: ownerId, appId, envName }, { value }).then(sendToApi);
79
+ await updateEnvVar({ id: ownerId, appId, envName }, { value }).then(sendToApi);
73
80
 
74
81
  Logger.println('Your environment variable has been successfully saved');
75
82
  };
@@ -79,7 +86,7 @@ export async function rm (params) {
79
86
  const { alias, app: appIdOrName } = params.options;
80
87
  const { ownerId, appId } = await Application.resolveId(appIdOrName, alias);
81
88
 
82
- await application.removeEnvVar({ id: ownerId, appId, envName }).then(sendToApi);
89
+ await removeEnvVar({ id: ownerId, appId, envName }).then(sendToApi);
83
90
 
84
91
  Logger.println('Your environment variable has been successfully removed');
85
92
  };
@@ -90,7 +97,7 @@ export async function importEnv (params) {
90
97
  const { ownerId, appId } = await Application.resolveId(appIdOrName, alias);
91
98
 
92
99
  const envVars = await variables.readVariablesFromStdin(format);
93
- await application.updateAllEnvVars({ id: ownerId, appId }, envVars).then(sendToApi);
100
+ await updateAllEnvVars({ id: ownerId, appId }, envVars).then(sendToApi);
94
101
 
95
102
  Logger.println('Environment variables have been set');
96
103
  };
@@ -110,7 +117,7 @@ export async function importVarsFromLocalEnv (params) {
110
117
 
111
118
  for (const envName of envNames) {
112
119
  const value = process.env[envName] || '';
113
- await application.updateEnvVar({ id: ownerId, appId, envName }, { value }).then(sendToApi);
120
+ await updateEnvVar({ id: ownerId, appId, envName }, { value }).then(sendToApi);
114
121
  }
115
122
 
116
123
  Logger.println('Your environment variables have been successfully saved');
@@ -0,0 +1,93 @@
1
+ import { getFeatures, setFeature } from '../models/configuration.js';
2
+ import { EXPERIMENTAL_FEATURES } from '../experimental-features.js';
3
+ import { formatTable as initFormatTable } from '../format-table.js';
4
+ import { Logger } from '../logger.js';
5
+
6
+ const formatTable = initFormatTable();
7
+
8
+ export async function list (params) {
9
+ const { format } = params.options;
10
+
11
+ const featuresConf = await getFeatures();
12
+ // Add status from configuration file and remove instructions
13
+ const features = Object.entries(EXPERIMENTAL_FEATURES).map(([id, feature]) => {
14
+ const enabled = featuresConf[id] === true;
15
+ return {
16
+ id,
17
+ status: feature.status,
18
+ description: feature.description,
19
+ enabled,
20
+ };
21
+ });
22
+
23
+ // For each feature, print the object with the id, status, description and enabled
24
+ switch (format) {
25
+ case 'json': {
26
+ Logger.printJson(features);
27
+ break;
28
+ }
29
+ case 'human':
30
+ default: {
31
+ const headers = ['ID', 'STATUS', 'DESCRIPTION', 'ENABLED'];
32
+
33
+ Logger.println(formatTable([
34
+ headers,
35
+ ...features.map((feature) => [
36
+ feature.id,
37
+ feature.status,
38
+ feature.description,
39
+ feature.enabled,
40
+ ]),
41
+ ]));
42
+ }
43
+ }
44
+ }
45
+
46
+ export async function info (params) {
47
+ const { feature } = params.namedArgs;
48
+ const availableFeatures = Object.keys(EXPERIMENTAL_FEATURES);
49
+
50
+ if (!availableFeatures.includes(feature)) {
51
+ throw new Error(`Unavailable feature: ${feature}`);
52
+ }
53
+
54
+ Logger.println(EXPERIMENTAL_FEATURES[feature].instructions);
55
+ }
56
+
57
+ export async function enable (params) {
58
+ const { features } = params.namedArgs;
59
+ const availableFeatures = Object.keys(EXPERIMENTAL_FEATURES);
60
+
61
+ const unknownFeatures = features.filter((feature) => !availableFeatures.includes(feature));
62
+ if (unknownFeatures.length > 0) {
63
+ throw new Error(`Unavailable feature(s): ${unknownFeatures.join(', ')}`);
64
+ }
65
+
66
+ for (const featureName of features) {
67
+ await setFeature(featureName, true);
68
+ Logger.println(`Experimental feature '${featureName}' enabled`);
69
+ }
70
+
71
+ if (features.length === 1) {
72
+ Logger.println(EXPERIMENTAL_FEATURES[features[0]].instructions);
73
+ }
74
+ else {
75
+ Logger.println();
76
+ Logger.println("To learn more about these experimental features, use 'clever features info FEATURE_NAME'");
77
+ }
78
+ }
79
+
80
+ export async function disable (params) {
81
+ const { features } = params.namedArgs;
82
+ const availableFeatures = Object.keys(EXPERIMENTAL_FEATURES);
83
+
84
+ const unknownFeatures = features.filter((feature) => !availableFeatures.includes(feature));
85
+ if (unknownFeatures.length > 0) {
86
+ throw new Error(`Unavailable feature(s): ${unknownFeatures.join(', ')}`);
87
+ }
88
+
89
+ for (const featureName of features) {
90
+ await setFeature(featureName, false);
91
+ Logger.println(`Experimental feature '${featureName}' disabled`);
92
+ }
93
+ }
@@ -0,0 +1,93 @@
1
+ import Redis from 'ioredis';
2
+ import colors from 'colors/safe.js';
3
+ import { Logger } from '../logger.js';
4
+ import { sendToApi } from '../models/send-to-api.js';
5
+ import { getAllEnvVars } from '@clevercloud/client/esm/api/v2/addon.js';
6
+ import { findAddonsByNameOrId } from '../models/ids-resolver.js';
7
+
8
+ const URL_ENV_KEY = 'REDIS_URL';
9
+ const MAX_RETRIES_PER_REQUEST = 1;
10
+
11
+ /**
12
+ * Send a raw command to a compatible KV database
13
+ * @param {Object} params
14
+ * @param {Array<string>} params.args
15
+ * @param {Object} params.options
16
+ * @param {string} params.options.format
17
+ * @returns {Promise<void>}
18
+ */
19
+ export async function sendRawCommand (params) {
20
+ const [addonIdOrRealIdOrName] = params.args;
21
+ const { org, format } = params.options;
22
+
23
+ const addons = await findAddonsByNameOrId(addonIdOrRealIdOrName, org);
24
+
25
+ if (addons.length === 0) {
26
+ throw new Error(`Add-on ${addonIdOrRealIdOrName} not found`);
27
+ }
28
+
29
+ if (addons.length > 1) {
30
+ const formattedAddons = addons
31
+ .map(({ addonId, ownerId }) => `\n${colors.grey(`- ${addonId} (${ownerId})`)}`)
32
+ .join('');
33
+ throw new Error(`Several add-ons found for '${addonIdOrRealIdOrName}', use ID instead:${formattedAddons}`);
34
+ }
35
+
36
+ const { addonId, ownerId } = addons[0];
37
+
38
+ const url = await getAddonUrl(ownerId, addonId);
39
+
40
+ Logger.debug(`Extracted command: ${params.args.join(' ')}`);
41
+ const command = params.args.slice(1);
42
+
43
+ const result = await sendCommand(url, command);
44
+
45
+ switch (format) {
46
+ case 'json': {
47
+ Logger.printJson(result);
48
+ break;
49
+ }
50
+ case 'human':
51
+ default: {
52
+ Logger.println(result);
53
+ }
54
+ }
55
+ }
56
+
57
+ /**
58
+ * Get the URL of the compatible KV database
59
+ * @param {string} ownerId
60
+ * @param {string} addonId
61
+ * @returns {Promise<string>} the URL of the compatible KV database
62
+ */
63
+ async function getAddonUrl (ownerId, addonId) {
64
+
65
+ const envVars = await getAllEnvVars({ id: ownerId, addonId }).then(sendToApi);
66
+ const redisUrl = envVars.find((env) => env.name === URL_ENV_KEY)?.value;
67
+
68
+ if (!redisUrl) {
69
+ throw new Error(`Environment variable ${colors.red(URL_ENV_KEY)} not found, is it a Materia KV or Redis® add-on?`);
70
+ }
71
+
72
+ return redisUrl;
73
+ }
74
+
75
+ /**
76
+ * Send a command to a compatible KV database
77
+ * @param {string} url
78
+ * @param {Array<string>} command
79
+ * @returns {Promise<string>} the command result
80
+ */
81
+ async function sendCommand (url, command) {
82
+ Logger.debug(`Sending command '${command.join(' ')}' to ${url}`);
83
+ const client = new Redis(url, { maxRetriesPerRequest: MAX_RETRIES_PER_REQUEST });
84
+ try {
85
+ const result = await client.call(...command);
86
+ Logger.debug(`Command result: ${result}`);
87
+ return result;
88
+ }
89
+ finally {
90
+ await client.disconnect();
91
+ Logger.debug('Disconnected from server');
92
+ }
93
+ }
@@ -7,9 +7,11 @@ export async function link (params) {
7
7
 
8
8
  if (app.app_id != null && orgaIdOrName != null) {
9
9
  Logger.warn('You\'ve specified a unique application ID, organisation option will be ignored');
10
+ await Application.linkRepo(app, null, alias);
11
+ }
12
+ else {
13
+ await Application.linkRepo(app, orgaIdOrName, alias);
10
14
  }
11
-
12
- await Application.linkRepo(app, orgaIdOrName, alias);
13
15
 
14
16
  Logger.println('Your application has been successfully linked!');
15
17
  }
@@ -0,0 +1,202 @@
1
+ import colors from 'colors/safe.js';
2
+ import * as networkGroup from '../models/ng.js';
3
+ import * as networkGroupResources from '../models/ng-resources.js';
4
+
5
+ import { Logger } from '../logger.js';
6
+ import { printResults } from '../lib/ng-print.js';
7
+
8
+ /** Create a Network Group
9
+ * @param {Object} params
10
+ * @param {Array<Object>} params.args
11
+ * @param {Object} params.args[0] Network Group label
12
+ * @param {string} params.options.description Network Group description
13
+ * @param {Array<string>} params.options.link Array of member IDs or labels to link to the Network Group
14
+ * @param {Object} params.options.org Organisation ID or name
15
+ * @param {string} params.options.tags Comma-separated list of tags
16
+ */
17
+ export async function createNg (params) {
18
+ const [ngLabel] = params.args;
19
+ const label = ngLabel.ngResourceLabel;
20
+ const { description, link: membersIds, org, tags } = params.options;
21
+
22
+ await networkGroup.create(label, description, tags, membersIds, org);
23
+
24
+ const successMessage = `Network Group ${colors.green(label)} successfully created`;
25
+ if (membersIds == null) {
26
+ Logger.printSuccess(`${successMessage}!`);
27
+ }
28
+ else {
29
+ Logger.printSuccess(`${successMessage} with member(s):`);
30
+ Logger.println(membersIds.map((id) => colors.grey(` - ${id}`)).join('\n'));
31
+ }
32
+ }
33
+
34
+ /** Delete a Network Group
35
+ * @param {Object} params
36
+ * @param {Object} params.args[0] Network Group ID or label
37
+ * @param {Object} params.options.org Organisation ID or name
38
+ */
39
+ export async function deleteNg (params) {
40
+ const [ngIdOrLabel] = params.args;
41
+ const { org } = params.options;
42
+
43
+ await networkGroup.destroy(ngIdOrLabel, org);
44
+ const ngText = ngIdOrLabel.ngResourceLabel ?? ngIdOrLabel.ngId;
45
+ Logger.printSuccess(`Network Group ${colors.green(ngText)} successfully deleted!`);
46
+ }
47
+
48
+ /** Create an external peer in a Network Group
49
+ * @param {Object} params
50
+ * @param {Object} params.args[0] External peer ID or label
51
+ * @param {Object} params.args[1] Network Group ID or label
52
+ * @param {string} params.args[2] Wireguard public key
53
+ * @param {Object} params.options.org Organisation ID or name
54
+ */
55
+ export async function createExternalPeer (params) {
56
+ const [peerIdOrLabel, ngIdOrLabel, publicKey] = params.args;
57
+ const { org } = params.options;
58
+
59
+ await networkGroupResources.createExternalPeerWithParent(ngIdOrLabel, peerIdOrLabel.ngResourceLabel, publicKey, org);
60
+ const ngText = ngIdOrLabel.ngResourceLabel ?? ngIdOrLabel.ngId;
61
+ Logger.printSuccess(`External peer ${colors.green(peerIdOrLabel.ngResourceLabel)} successfully created in Network Group ${colors.green(ngText)}`);
62
+ }
63
+
64
+ /** Delete an external peer from a Network Group
65
+ * @param {Object} params
66
+ * @param {Object} params.args[0] External peer ID or label
67
+ * @param {Object} params.args[1] Network Group ID or label
68
+ * @param {Object} params.options.org Organisation ID or name
69
+ */
70
+ export async function deleteExternalPeer (params) {
71
+ const [peerIdOrLabel, ngIdOrLabel] = params.args;
72
+ const { org } = params.options;
73
+
74
+ const peerText = peerIdOrLabel.ngResourceLabel ?? peerIdOrLabel.memberId;
75
+ const ngText = ngIdOrLabel.ngResourceLabel ?? ngIdOrLabel.ngId;
76
+ await networkGroupResources.deleteExternalPeerWithParent(ngIdOrLabel, peerText, org);
77
+ Logger.printSuccess(`External peer ${colors.green(peerText)} successfully deleted from Network Group ${colors.green(ngText)}`);
78
+ }
79
+
80
+ /** Link a member to a Network Group
81
+ * @param {Object} params
82
+ * @param {string} params.args[0] Member ID
83
+ * @param {Object} params.args[1] Network Group ID or label
84
+ * @param {Object} params.options.org Organisation ID or name
85
+ */
86
+ export async function linkToNg (params) {
87
+ const [resourceId, ngIdOrLabel] = params.args;
88
+ const { org } = params.options;
89
+
90
+ await networkGroupResources.linkMember(ngIdOrLabel, resourceId.memberId, org);
91
+ const ngText = ngIdOrLabel.ngResourceLabel ?? ngIdOrLabel.ngId;
92
+ Logger.printSuccess(`Member ${colors.green(resourceId.memberId)} successfully linked to Network Group ${colors.green(ngText)}`);
93
+ }
94
+
95
+ /** Unlink a member from a Network Group
96
+ * @param {Object} params
97
+ * @param {string} params.args[0] Member ID
98
+ * @param {Object} params.args[1] Network Group ID or label
99
+ * @param {Object} params.options.org Organisation ID or name
100
+ */
101
+ export async function unlinkFromNg (params) {
102
+ const [resourceId, ngIdOrLabel] = params.args;
103
+ const { org } = params.options;
104
+
105
+ await networkGroupResources.unlinkMember(ngIdOrLabel, resourceId.memberId, org);
106
+ const ngText = ngIdOrLabel.ngResourceLabel ?? ngIdOrLabel.ngId;
107
+ Logger.printSuccess(`Member ${colors.green(resourceId.memberId)} successfully unlinked from Network Group ${colors.green(ngText)}`);
108
+ }
109
+
110
+ /** Print the configuration of a Network Group's peer
111
+ * @param {Object} params
112
+ * @param {Object} params.args[0] Peer ID or label
113
+ * @param {Object} params.args[1] Network Group ID or label
114
+ * @param {Object} params.options.org Organisation ID or name
115
+ * @param {string} params.options.format Output format
116
+ */
117
+ export async function getPeerConfig (params) {
118
+ const [peerIdOrLabel, ngIdOrLabel] = params.args;
119
+ const { org, format } = params.options;
120
+
121
+ const config = await networkGroup.getPeerConfig(peerIdOrLabel, ngIdOrLabel, org);
122
+
123
+ switch (format) {
124
+ case 'json': {
125
+ Logger.printJson(config);
126
+ break;
127
+ }
128
+ case 'human':
129
+ default: {
130
+ const decodedConfiguration = Buffer.from(config.configuration, 'base64').toString('utf8');
131
+ Logger.println(decodedConfiguration);
132
+ }
133
+ }
134
+ }
135
+
136
+ /** List Network Groups, their members and peers
137
+ * @param {Object} params
138
+ * @param {Object} params.options.orgaIdOrName Organisation ID or name
139
+ * @param {string} params.options.format Output format
140
+ */
141
+ export async function listNg (params) {
142
+ const { org, format } = params.options;
143
+
144
+ const ngs = await networkGroup.getAllNGs(org);
145
+
146
+ switch (format) {
147
+ case 'json': {
148
+ Logger.printJson(ngs);
149
+ break;
150
+ }
151
+ case 'human':
152
+ default: {
153
+ if (!ngs.length) {
154
+ Logger.println(`ℹ️ No Network Group found, create one with ${colors.blue('clever ng create')} command`);
155
+ return;
156
+ }
157
+ const ngList = ngs.map(({
158
+ id,
159
+ label,
160
+ networkIp,
161
+ members,
162
+ peers,
163
+ }) => ({
164
+ ID: id,
165
+ Label: label,
166
+ 'Network CIDR': networkIp,
167
+ Members: Object.keys(members).length,
168
+ Peers: Object.keys(peers).length,
169
+ }));
170
+
171
+ console.table(ngList);
172
+ }
173
+ }
174
+ }
175
+
176
+ /** Show information about a Network Group, a member or a peer
177
+ * @param {Object} params
178
+ * @param {Object} params.args[0] ID or label of the Network Group, a member or a peer
179
+ * @param {Object} params.options.org Organisation ID or name
180
+ * @param {string} params.options.format Output format
181
+ */
182
+ export async function get (params) {
183
+ const [idOrLabel] = params.args;
184
+ const { org, format } = params.options;
185
+ const type = params.options.type ?? 'single';
186
+
187
+ await printResults(idOrLabel, org, format, 'get', type);
188
+ }
189
+
190
+ /** Show information about a Network Group, a member or a peer
191
+ * @param {Object} params
192
+ * @param {Object} params.args[0] ID or label of the Network Group, a member or a peer
193
+ * @param {Object} params.options.org Organisation ID or name
194
+ * @param {string} params.options.format Output format
195
+ */
196
+ export async function search (params) {
197
+ const [idOrLabel] = params.args;
198
+ const { org, format } = params.options;
199
+ const type = params.options.type;
200
+
201
+ await printResults(idOrLabel, org, format, 'search', type);
202
+ }
@@ -1,7 +1,8 @@
1
1
  import colors from 'colors/safe.js';
2
-
2
+ import openPage from 'open';
3
3
  import { Logger } from '../logger.js';
4
4
  import * as User from '../models/user.js';
5
+ import dedent from 'dedent';
5
6
 
6
7
  export async function profile (params) {
7
8
  const { format } = params.options;
@@ -37,12 +38,20 @@ export async function profile (params) {
37
38
  }
38
39
  case 'human':
39
40
  default: {
40
- Logger.println('You\'re currently logged in as:');
41
- Logger.println(`User id ${formattedUser.id}`);
42
- Logger.println(`Name ${formattedUser.name ?? colors.red.bold('[not specified]')}`);
43
- Logger.println(`Email ${formattedUser.email}`);
44
- Logger.println(`Token expiration ${tokenExpiration}`);
45
- Logger.println(`Two factor auth ${formattedUser.has2FA ? 'yes' : 'no'}`);
41
+ Logger.println(dedent`
42
+ You're currently logged in as:
43
+ User id ${formattedUser.id}
44
+ Name ${formattedUser.name ?? colors.red.bold('[not specified]')}
45
+ Email ${formattedUser.email}
46
+ Token expiration ${tokenExpiration}
47
+ Two factor auth ${formattedUser.has2FA ? 'yes' : 'no'}
48
+ `);
46
49
  }
47
50
  }
48
51
  };
52
+
53
+ export async function openProfile () {
54
+ const URL = 'https://console.clever-cloud.com/users/me/information';
55
+ Logger.debug('Opening the profile page in your browser');
56
+ await openPage(URL, { wait: false });
57
+ }
@@ -3,13 +3,13 @@ import { Logger } from '../logger.js';
3
3
  import * as variables from '../models/variables.js';
4
4
  import { sendToApi } from '../models/send-to-api.js';
5
5
  import { toNameEqualsValueString, validateName } from '@clevercloud/client/esm/utils/env-vars.js';
6
- import * as application from '@clevercloud/client/esm/api/v2/application.js';
6
+ import { getAllExposedEnvVars, updateAllExposedEnvVars } from '@clevercloud/client/esm/api/v2/application.js';
7
7
 
8
8
  export async function list (params) {
9
9
  const { alias, app: appIdOrName, format } = params.options;
10
10
  const { ownerId, appId } = await Application.resolveId(appIdOrName, alias);
11
11
 
12
- const publishedConfigs = await application.getAllExposedEnvVars({ id: ownerId, appId }).then(sendToApi);
12
+ const publishedConfigs = await getAllExposedEnvVars({ id: ownerId, appId }).then(sendToApi);
13
13
  const pairs = Object.entries(publishedConfigs).map(([name, value]) => ({ name, value }));
14
14
 
15
15
  switch (format) {
@@ -39,9 +39,9 @@ export async function set (params) {
39
39
 
40
40
  const { ownerId, appId } = await Application.resolveId(appIdOrName, alias);
41
41
 
42
- const publishedConfigs = await application.getAllExposedEnvVars({ id: ownerId, appId }).then(sendToApi);
42
+ const publishedConfigs = await getAllExposedEnvVars({ id: ownerId, appId }).then(sendToApi);
43
43
  publishedConfigs[varName] = varValue;
44
- await application.updateAllExposedEnvVars({ id: ownerId, appId }, publishedConfigs).then(sendToApi);
44
+ await updateAllExposedEnvVars({ id: ownerId, appId }, publishedConfigs).then(sendToApi);
45
45
 
46
46
  Logger.println('Your published config item has been successfully saved');
47
47
  };
@@ -51,9 +51,9 @@ export async function rm (params) {
51
51
  const { alias, app: appIdOrName } = params.options;
52
52
  const { ownerId, appId } = await Application.resolveId(appIdOrName, alias);
53
53
 
54
- const publishedConfigs = await application.getAllExposedEnvVars({ id: ownerId, appId }).then(sendToApi);
54
+ const publishedConfigs = await getAllExposedEnvVars({ id: ownerId, appId }).then(sendToApi);
55
55
  delete publishedConfigs[varName];
56
- await application.updateAllExposedEnvVars({ id: ownerId, appId }, publishedConfigs).then(sendToApi);
56
+ await updateAllExposedEnvVars({ id: ownerId, appId }, publishedConfigs).then(sendToApi);
57
57
 
58
58
  Logger.println('Your published config item has been successfully removed');
59
59
  };
@@ -64,7 +64,7 @@ export async function importEnv (params) {
64
64
  const { ownerId, appId } = await Application.resolveId(appIdOrName, alias);
65
65
 
66
66
  const publishedConfigs = await variables.readVariablesFromStdin(format);
67
- await application.updateAllExposedEnvVars({ id: ownerId, appId }, publishedConfigs).then(sendToApi);
67
+ await updateAllExposedEnvVars({ id: ownerId, appId }, publishedConfigs).then(sendToApi);
68
68
 
69
69
  Logger.println('Your published configs have been set');
70
70
  };
@@ -1,12 +1,12 @@
1
1
  import * as Application from '../models/application.js';
2
- import * as application from '@clevercloud/client/esm/api/v2/application.js';
3
2
  import { Logger } from '../logger.js';
4
3
  import { sendToApi } from '../models/send-to-api.js';
4
+ import { undeploy as stopApplication } from '@clevercloud/client/esm/api/v2/application.js';
5
5
 
6
6
  export async function stop (params) {
7
7
  const { alias, app: appIdOrName } = params.options;
8
8
  const { ownerId, appId } = await Application.resolveId(appIdOrName, alias);
9
9
 
10
- await application.undeploy({ id: ownerId, appId }).then(sendToApi);
10
+ await stopApplication({ id: ownerId, appId }).then(sendToApi);
11
11
  Logger.println('App successfully stopped!');
12
12
  }