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,11 +1,11 @@
1
- import colors from 'colors/safe.js';
2
- import { Logger } from '../logger.js';
1
+ import dedent from 'dedent';
2
+ import { styleText } from 'node:util';
3
3
  import { createApiToken, deleteApiToken, listApiTokens } from '../clever-client/auth-bridge.js';
4
+ import { promptSecret } from '../lib/prompts.js';
5
+ import { Logger } from '../logger.js';
6
+ import { conf } from '../models/configuration.js';
4
7
  import { sendToAuthBridge } from '../models/send-to-api.js';
5
8
  import { getCurrent as getCurrentUser } from '../models/user.js';
6
- import { conf } from '../models/configuration.js';
7
- import dedent from 'dedent';
8
- import { promptSecret } from '../lib/prompts.js';
9
9
 
10
10
  /**
11
11
  * Create a new API token
@@ -15,7 +15,7 @@ import { promptSecret } from '../lib/prompts.js';
15
15
  * @param {'json'|'human'} params.options.format - Output format
16
16
  * @param {number} params.options.expiration - Expiration date as timestamp
17
17
  */
18
- export async function create (params) {
18
+ export async function create(params) {
19
19
  const [apiTokenName] = params.args;
20
20
  const { expiration, format } = params.options;
21
21
  const user = await getCurrentUser();
@@ -23,8 +23,8 @@ export async function create (params) {
23
23
  if (!user.hasPassword) {
24
24
  const apiTokenListHref = new URL('/users/me/api-tokens', conf.CONSOLE_URL).href;
25
25
  throw new Error(dedent`
26
- ${colors.yellow('!')} Your Clever Cloud account is linked via GitHub and has no password. Setting one is required to create API tokens.
27
- ${colors.blue('→')} To do so, go to the following URL: ${colors.blue(apiTokenListHref)}
26
+ ${styleText('yellow', '!')} Your Clever Cloud account is linked via GitHub and has no password. Setting one is required to create API tokens.
27
+ ${styleText('blue', '→')} To do so, go to the following URL: ${styleText('blue', apiTokenListHref)}
28
28
  `);
29
29
  }
30
30
 
@@ -39,8 +39,7 @@ export async function create (params) {
39
39
  throw new Error('You cannot set an expiration date greater than 1 year');
40
40
  }
41
41
  expirationDate = new Date(expiration);
42
- }
43
- else {
42
+ } else {
44
43
  expirationDate = maxExpirationDate;
45
44
  }
46
45
 
@@ -58,16 +57,18 @@ export async function create (params) {
58
57
  name: apiTokenName,
59
58
  expirationDate: expirationDate.toISOString(),
60
59
  };
61
- const createdToken = await createApiToken(tokenData).then(sendToAuthBridge).catch((error) => {
62
- const errorCode = error?.cause?.responseBody?.code;
63
- if (errorCode === 'invalid-credential') {
64
- throw new Error('Invalid credentials, check your password');
65
- }
66
- if (errorCode === 'invalid-mfa-code') {
67
- throw new Error('Invalid credentials, check your 2FA code');
68
- }
69
- throw error;
70
- });
60
+ const createdToken = await createApiToken(tokenData)
61
+ .then(sendToAuthBridge)
62
+ .catch((error) => {
63
+ const errorCode = error?.cause?.responseBody?.code;
64
+ if (errorCode === 'invalid-credential') {
65
+ throw new Error('Invalid credentials, check your password');
66
+ }
67
+ if (errorCode === 'invalid-mfa-code') {
68
+ throw new Error('Invalid credentials, check your 2FA code');
69
+ }
70
+ throw error;
71
+ });
71
72
 
72
73
  switch (format) {
73
74
  case 'json':
@@ -76,11 +77,11 @@ export async function create (params) {
76
77
  case 'human':
77
78
  default:
78
79
  Logger.println(dedent`
79
- ${colors.green('✔')} API token successfully created! Store it securely, you won't able to print it again.
80
+ ${styleText('green', '✔')} API token successfully created! Store it securely, you won't able to print it again.
80
81
 
81
- - API token ID : ${colors.grey(createdToken.apiTokenId)}
82
- - API token : ${colors.grey(createdToken.apiToken)}
83
- - Expiration : ${colors.grey(formatDate(createdToken.expirationDate))}
82
+ - API token ID : ${styleText('grey', createdToken.apiTokenId)}
83
+ - API token : ${styleText('grey', createdToken.apiToken)}
84
+ - Expiration : ${styleText('grey', formatDate(createdToken.expirationDate))}
84
85
 
85
86
  Export this token and use it to make authenticated requests to the Clever Cloud API through the Auth Bridge:
86
87
 
@@ -100,29 +101,29 @@ export async function create (params) {
100
101
  * @param {Object} params.options.format - Output format
101
102
  * @returns {Promise<void>}
102
103
  */
103
- export async function list (params) {
104
+ export async function list(params) {
104
105
  const { format } = params.options;
105
106
 
106
107
  const tokens = await listApiTokens().then(sendToAuthBridge);
107
108
 
108
109
  if (format === 'json') {
109
110
  Logger.printJson(tokens);
110
- }
111
- else {
111
+ } else {
112
112
  if (tokens.length === 0) {
113
- Logger.println(`ℹ️ No API token found, create one with ${colors.blue('clever tokens create')} command`);
114
- }
115
- else {
116
- console.table(tokens.map((token) => {
117
- return {
118
- 'API token ID': token.apiTokenId,
119
- Name: token.name,
120
- 'Creation IP address': token.ip,
121
- Creation: formatDate(token.creationDate),
122
- Expiration: formatDate(token.expirationDate),
123
- State: token.state,
124
- };
125
- }));
113
+ Logger.println(`ℹ️ No API token found, create one with ${styleText('blue', 'clever tokens create')} command`);
114
+ } else {
115
+ console.table(
116
+ tokens.map((token) => {
117
+ return {
118
+ 'API token ID': token.apiTokenId,
119
+ Name: token.name,
120
+ 'Creation IP address': token.ip,
121
+ Creation: formatDate(token.creationDate),
122
+ Expiration: formatDate(token.expirationDate),
123
+ State: token.state,
124
+ };
125
+ }),
126
+ );
126
127
  }
127
128
  }
128
129
  }
@@ -133,14 +134,14 @@ export async function list (params) {
133
134
  * @param {string[]} params.args - Command line arguments, token ID to revoke is expected as first argument
134
135
  * @returns {Promise<void>}
135
136
  */
136
- export async function revoke (params) {
137
+ export async function revoke(params) {
137
138
  const [apiTokenId] = params.args;
138
139
 
139
140
  await deleteApiToken(apiTokenId).then(sendToAuthBridge);
140
141
 
141
- Logger.println(colors.green('✔'), 'API token successfully revoked!');
142
+ Logger.println(styleText('green', '✔'), 'API token successfully revoked!');
142
143
  }
143
144
 
144
- function formatDate (dateInput) {
145
+ function formatDate(dateInput) {
145
146
  return new Date(dateInput).toISOString().substring(0, 16).replace('T', ' ');
146
147
  }
@@ -1,12 +1,14 @@
1
+ import { styleText } from 'node:util';
2
+ import { Logger } from '../logger.js';
1
3
  import * as AppConfig from '../models/app_configuration.js';
2
4
  import * as Application from '../models/application.js';
3
- import { Logger } from '../logger.js';
4
- import colors from 'colors/safe.js';
5
5
 
6
- export async function unlink (params) {
6
+ export async function unlink(params) {
7
7
  const [alias] = params.args;
8
8
  const app = await AppConfig.getAppDetails({ alias });
9
9
 
10
10
  await Application.unlinkRepo(app.alias);
11
- Logger.printSuccess(`Application ${colors.green(app.appId)} has been successfully unlinked from local alias ${colors.green(app.alias)}!`);
12
- };
11
+ Logger.printSuccess(
12
+ `Application ${styleText('green', app.appId)} has been successfully unlinked from local alias ${styleText('green', app.alias)}!`,
13
+ );
14
+ }
@@ -1,8 +1,6 @@
1
+ import pkg from '../../package.json' with { type: 'json' };
1
2
  import { Logger } from '../logger.js';
2
- import { getPackageJson } from '../load-package-json.cjs';
3
3
 
4
- const pkg = getPackageJson();
5
-
6
- export async function version () {
4
+ export async function version() {
7
5
  Logger.println(pkg.version);
8
6
  }
@@ -1,12 +1,10 @@
1
- import colors from 'colors/safe.js';
2
-
1
+ import { createWebhook, deleteWebhook, getWebhooks } from '@clevercloud/client/esm/api/v2/notification.js';
2
+ import { styleText } from 'node:util';
3
3
  import { Logger } from '../logger.js';
4
- import { getOwnerAndApp, getOrgaIdOrUserId } from '../models/notification.js';
5
-
6
- import { getWebhooks, createWebhook, deleteWebhook } from '@clevercloud/client/esm/api/v2/notification.js';
4
+ import { getOrgaIdOrUserId, getOwnerAndApp } from '../models/notification.js';
7
5
  import { sendToApi } from '../models/send-to-api.js';
8
6
 
9
- export async function list (params) {
7
+ export async function list(params) {
10
8
  const { org, 'list-all': listAll, format } = params.options;
11
9
 
12
10
  // TODO: fix alias option
@@ -35,7 +33,7 @@ export async function list (params) {
35
33
  case 'human':
36
34
  default: {
37
35
  formattedHooks.forEach((hook) => {
38
- Logger.println(hook.name ? colors.bold(hook.name) : hook.id);
36
+ Logger.println(hook.name ? styleText('bold', hook.name) : hook.id);
39
37
  Logger.println(` id: ${hook.id}`);
40
38
  Logger.println(` services: ${hook.services.join(', ')}`);
41
39
  Logger.println(` events: ${hook.events.join(', ')}`);
@@ -46,7 +44,7 @@ export async function list (params) {
46
44
  }
47
45
  }
48
46
 
49
- export async function add (params) {
47
+ export async function add(params) {
50
48
  const { org, format, event: events, service } = params.options;
51
49
  const [name, hookUrl] = params.args;
52
50
 
@@ -56,7 +54,7 @@ export async function add (params) {
56
54
  const body = {
57
55
  name,
58
56
  urls: [{ format, url: hookUrl }],
59
- scope: (appId != null && service == null) ? [appId] : service,
57
+ scope: appId != null && service == null ? [appId] : service,
60
58
  events,
61
59
  };
62
60
 
@@ -65,7 +63,7 @@ export async function add (params) {
65
63
  Logger.println('The webhook has been added');
66
64
  }
67
65
 
68
- export async function remove (params) {
66
+ export async function remove(params) {
69
67
  const { org } = params.options;
70
68
  const [notificationId] = params.args;
71
69
 
@@ -1,9 +1,11 @@
1
1
  import dedent from 'dedent';
2
+ import { conf } from './models/configuration.js';
2
3
 
3
4
  export const EXPERIMENTAL_FEATURES = {
4
5
  kv: {
5
6
  status: 'alpha',
6
- description: 'Send commands to databases such as Materia KV or Redis® directly from Clever Tools, without other dependencies',
7
+ description:
8
+ 'Send commands to databases such as Materia KV or Redis® directly from Clever Tools, without other dependencies',
7
9
  instructions: dedent`
8
10
  Target any compatible add-on by its name or ID (with an org ID if needed) and send commands to it:
9
11
 
@@ -13,7 +15,7 @@ export const EXPERIMENTAL_FEATURES = {
13
15
  clever kv myMateriaKV -o myOrg TTL myTempKey
14
16
  clever kv redis_xxxxx --org org_xxxxx PING
15
17
 
16
- Learn more about Materia KV: https://www.clever-cloud.com/developers/doc/addons/materia-kv/
18
+ Learn more about Materia KV: ${conf.DOC_URL}/addons/materia-kv/
17
19
  `,
18
20
  },
19
21
  ng: {
@@ -41,7 +43,7 @@ export const EXPERIMENTAL_FEATURES = {
41
43
  - Search Network Groups, members or peers:
42
44
  clever ng search myQuery
43
45
 
44
- Learn more about Network Groups: https://www.clever-cloud.com/developers/doc/develop/network-groups/
46
+ Learn more about Network Groups: ${conf.DOC_URL}/develop/network-groups/
45
47
  `,
46
48
  },
47
49
  operators: {
@@ -51,10 +53,10 @@ export const EXPERIMENTAL_FEATURES = {
51
53
  clever keycloak
52
54
  clever keycloak get keycloak_xxx
53
55
  clever keycloak ng enable myKeycloak
54
-
56
+
55
57
  clever metabase version check myMetabase
56
58
  clever metabase version update myMetabase 0.53
57
-
59
+
58
60
  clever matomo open myMatomo
59
61
  clever otoroshi open logs myOtoroshi
60
62
  `,
@@ -1,20 +1,51 @@
1
- import _ from 'lodash';
2
- import table from 'text-table';
3
- import stringLength from 'string-length';
1
+ import charRegex from 'char-regex';
2
+ import { stripVTControlCharacters } from 'node:util';
4
3
 
5
- export function formatTable (columnWidth = []) {
4
+ const SEPARATOR = ' ';
6
5
 
6
+ function stringLength(string) {
7
+ if (!string) {
8
+ return 0;
9
+ }
10
+ const stringWithoutAnsi = stripVTControlCharacters(string);
11
+ if (!stringWithoutAnsi) {
12
+ return 0;
13
+ }
14
+ const stringWithSplitEmojis = stringWithoutAnsi.match(charRegex());
15
+ if (!stringWithSplitEmojis) {
16
+ return 0;
17
+ }
18
+ return stringWithSplitEmojis.length;
19
+ }
20
+
21
+ export const formatTable = (data, columnWidth = []) => {
7
22
  const fixedWidthPlaceholder = columnWidth.map((item) => {
8
- if (typeof item === 'number') {
9
- return _.repeat(' ', item);
10
- }
11
- return item;
23
+ return typeof item === 'number' ? ' '.repeat(item) : item;
12
24
  });
13
25
 
14
- return function (data) {
15
- return table([fixedWidthPlaceholder, ...data], { stringLength })
16
- .split('\n')
17
- .slice(1)
18
- .join('\n');
19
- };
20
- }
26
+ const columnSizes = [fixedWidthPlaceholder, ...data]
27
+ .map((row) => row.map((cell) => String(cell)))
28
+ .reduce((acc, row) => {
29
+ row.forEach((cell, index) => {
30
+ const cellLength = stringLength(cell);
31
+ acc[index] = Math.max(acc[index] ?? 0, cellLength);
32
+ });
33
+ return acc;
34
+ }, []);
35
+
36
+ return data
37
+ .map((row) => row.map((cell) => String(cell)))
38
+ .map((row) => {
39
+ return row
40
+ .map((cell, index) => {
41
+ const isLastColumn = index === row.length - 1;
42
+ if (isLastColumn) {
43
+ return cell;
44
+ }
45
+ const rightPaddingLength = columnSizes[index] - stringLength(cell) ?? 0;
46
+ return cell + ' '.repeat(rightPaddingLength);
47
+ })
48
+ .join(SEPARATOR);
49
+ })
50
+ .join('\n');
51
+ };
@@ -1,17 +1,4 @@
1
- import colors from 'colors/safe.js';
2
- import { getPackageJson } from './load-package-json.cjs';
3
- import updateNotifierModule from 'update-notifier';
4
-
5
- function hasParam (param, paramValue) {
6
- const index = process.argv.indexOf(param);
7
- if (index === -1) {
8
- return false;
9
- }
10
- if (paramValue != null) {
11
- return process.argv[index + 1] === paramValue;
12
- }
13
- return true;
14
- }
1
+ import { hasParam } from './lib/has-param.js';
15
2
 
16
3
  // These need to be set before Logger and other stuffs
17
4
  if (hasParam('-v') || hasParam('--verbose')) {
@@ -28,22 +15,5 @@ if (hasParam('--autocomplete-index')) {
28
15
  const colorExplicitFalse = hasParam('--no-color') || hasParam('--color', 'false');
29
16
  const colorExplicitTrue = hasParam('--color', 'true');
30
17
  if (colorExplicitFalse || (!process.stdout.isTTY && !colorExplicitTrue)) {
31
- colors.disable();
32
- }
33
-
34
- // These need to be set before Logger and other stuffs
35
- const pkg = getPackageJson();
36
- const isRunThroughPackagedBinary = process.pkg != null;
37
- const updateNotifierExplicitFalse = hasParam('--no-update-notifier') || hasParam('--update-notifier', 'false');
38
- if (!updateNotifierExplicitFalse && !isRunThroughPackagedBinary) {
39
- updateNotifierModule({
40
- pkg,
41
- tagsUrl: 'https://api.github.com/repos/CleverCloud/clever-tools/tags',
42
- }).notify({
43
- isGlobal: true,
44
- getDetails () {
45
- const docsUrl = 'https://github.com/CleverCloud/clever-tools/tree/master/docs#how-to-use-clever-tools';
46
- return `\nPlease follow this link to update your clever-tools:\n${docsUrl}`;
47
- },
48
- });
18
+ process.env.NO_COLOR = '1';
49
19
  }
@@ -0,0 +1,18 @@
1
+ import updateNotifierModule from 'update-notifier';
2
+ import pkg from '../package.json' with { type: 'json' };
3
+ import { hasParam } from './lib/has-param.js';
4
+
5
+ // These need to be set before Logger and other stuffs
6
+ const updateNotifierExplicitFalse = hasParam('--no-update-notifier') || hasParam('--update-notifier', 'false');
7
+ if (!updateNotifierExplicitFalse) {
8
+ updateNotifierModule({
9
+ pkg,
10
+ tagsUrl: 'https://api.github.com/repos/CleverCloud/clever-tools/tags',
11
+ }).notify({
12
+ isGlobal: true,
13
+ getDetails() {
14
+ const docsUrl = 'https://github.com/CleverCloud/clever-tools/tree/master/docs#how-to-use-clever-tools';
15
+ return `\nPlease follow this link to update your clever-tools:\n${docsUrl}`;
16
+ },
17
+ });
18
+ }
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Check if a specific parameter exists in the command line arguments.
3
+ * @param {string} param
4
+ * @param {string} [paramValue]
5
+ * @return {boolean}
6
+ */
7
+ export function hasParam(param, paramValue) {
8
+ const index = process.argv.indexOf(param);
9
+ if (index === -1) {
10
+ return false;
11
+ }
12
+ if (paramValue != null) {
13
+ return process.argv[index + 1] === paramValue;
14
+ }
15
+ return true;
16
+ }
@@ -1,7 +1,6 @@
1
- import colors from 'colors/safe.js';
2
- import * as networkGroup from '../models/ng.js';
3
-
1
+ import { styleText } from 'node:util';
4
2
  import { Logger } from '../logger.js';
3
+ import * as networkGroup from '../models/ng.js';
5
4
 
6
5
  /**
7
6
  * Print a Network Group
@@ -9,8 +8,7 @@ import { Logger } from '../logger.js';
9
8
  * @param {string} format Output format
10
9
  * @param {boolean} full If true, get more details about the Network Group (default: false)
11
10
  */
12
- function printNg (ng, format, full = false) {
13
-
11
+ function printNg(ng, format, full = false) {
14
12
  switch (format) {
15
13
  case 'json': {
16
14
  Logger.printJson(ng);
@@ -31,19 +29,19 @@ function printNg (ng, format, full = false) {
31
29
  if (full) {
32
30
  const members = Object.entries(ng.members)
33
31
  .sort((a, b) => a[1].domainName.localeCompare(b[1].domainName))
34
- .map(([id, member]) => ({
32
+ .map(([_id, member]) => ({
35
33
  Domain: member.domainName,
36
34
  }));
37
35
  if (members.length > 0) {
38
- Logger.println(colors.bold(' • Members:'));
36
+ Logger.println(styleText('bold', ' • Members:'));
39
37
  console.table(members);
40
38
  }
41
39
 
42
40
  const peers = Object.entries(ng.peers)
43
41
  .sort((a, b) => a[1].parentMember.localeCompare(b[1].parentMember))
44
- .map(([id, peer]) => formatPeer(peer));
42
+ .map(([_id, peer]) => formatPeer(peer));
45
43
  if (peers.length > 0) {
46
- Logger.println(colors.bold(' • Peers:'));
44
+ Logger.println(styleText('bold', ' • Peers:'));
47
45
  console.table(peers);
48
46
  }
49
47
  }
@@ -56,8 +54,7 @@ function printNg (ng, format, full = false) {
56
54
  * @param {Object} member The Network Group member to print
57
55
  * @param {string} format Output format
58
56
  */
59
- function printMember (member, format) {
60
-
57
+ function printMember(member, format) {
61
58
  switch (format) {
62
59
  case 'json': {
63
60
  Logger.printJson(member);
@@ -79,7 +76,7 @@ function printMember (member, format) {
79
76
  * @param {string} format Output format
80
77
  * @param {boolean} full If true, get more details about the peer (default: false)
81
78
  */
82
- function printPeer (peer, format, full = false) {
79
+ function printPeer(peer, format, full = false) {
83
80
  switch (format) {
84
81
  case 'json': {
85
82
  Logger.printJson(peer);
@@ -97,7 +94,7 @@ function printPeer (peer, format, full = false) {
97
94
  * @param {Object} peer
98
95
  * @param {boolean} full If true, get more details about the peer (default: false)
99
96
  */
100
- function formatPeer (peer, full = false) {
97
+ function formatPeer(peer, full = false) {
101
98
  const peerToPrint = {
102
99
  'Parent Member': peer.parentMember,
103
100
  ID: peer.id,
@@ -108,8 +105,7 @@ function formatPeer (peer, full = false) {
108
105
  if (full) {
109
106
  if (peer.endpoint.ngTerm != null) {
110
107
  peerToPrint['Host:IP'] = `${peer.endpoint.ngTerm.host}:${peer.endpoint.ngTerm.port}`;
111
- }
112
- else {
108
+ } else {
113
109
  peerToPrint.Host = peer.endpoint.ngIp;
114
110
  }
115
111
  if (peer.endpoint.publicTerm != null) {
@@ -128,18 +124,17 @@ function formatPeer (peer, full = false) {
128
124
  * @param {string} action Action to perform (search or get)
129
125
  * @param {string} type Type of item to search (NetworkGroup, Member, Peer)
130
126
  */
131
- export async function printResults (idOrLabel, org, format, action, type) {
132
-
127
+ export async function printResults(idOrLabel, org, format, action, type) {
133
128
  const exactMatch = action === 'get';
134
129
  const toLookFor = type ?? (action === 'search' ? 'all' : 'single');
135
130
 
136
131
  const found = await networkGroup.searchNgOrResource(idOrLabel, org, toLookFor, exactMatch);
137
132
 
138
133
  if (!found.length) {
139
- const searchString = idOrLabel.ngId
140
- ?? idOrLabel.memberId
141
- ?? idOrLabel.ngResourceLabel;
142
- Logger.println(`${colors.blue('!')} No Network Group or resource found for ${colors.blue(searchString)}`);
134
+ const searchString = idOrLabel.ngId ?? idOrLabel.memberId ?? idOrLabel.ngResourceLabel;
135
+ Logger.println(
136
+ `${styleText('blue', '!')} No Network Group or resource found for ${styleText('blue', searchString)}`,
137
+ );
143
138
  return;
144
139
  }
145
140
 
@@ -175,17 +170,19 @@ export async function printResults (idOrLabel, org, format, action, type) {
175
170
  case 'human':
176
171
  default: {
177
172
  if (grouped.NetworkGroup) {
178
- Logger.println(`${colors.bold(` • Found ${grouped.NetworkGroup.length} Network Group(s):`)}`);
173
+ Logger.println(`${styleText('bold', ` • Found ${grouped.NetworkGroup.length} Network Group(s):`)}`);
179
174
  grouped.NetworkGroup?.forEach((item) => printNg(item, format));
180
175
  }
181
176
 
182
177
  if (grouped.Member) {
183
- Logger.println(`${colors.bold(` • Found ${grouped.Member.length} Member(s):`)}`);
178
+ Logger.println(`${styleText('bold', ` • Found ${grouped.Member.length} Member(s):`)}`);
184
179
  grouped.Member?.forEach((item) => printMember(item, format));
185
180
  }
186
181
 
187
182
  if (grouped.ExternalPeer || grouped.CleverPeer) {
188
- Logger.println(`${colors.bold(` • Found ${grouped.ExternalPeer.length + grouped.CleverPeer.length} Peer(s):`)}`);
183
+ Logger.println(
184
+ `${styleText('bold', ` • Found ${grouped.ExternalPeer.length + grouped.CleverPeer.length} Peer(s):`)}`,
185
+ );
189
186
  grouped.CleverPeer?.forEach((item) => printPeer(item, format));
190
187
  grouped.ExternalPeer?.forEach((item) => printPeer(item, format));
191
188
  }