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
package/package.json CHANGED
@@ -1,20 +1,30 @@
1
1
  {
2
2
  "name": "clever-tools",
3
- "version": "3.14.0",
3
+ "version": "4.0.0",
4
4
  "description": "Command Line Interface for Clever Cloud.",
5
- "main": "bin/clever.js",
6
- "type": "module",
7
5
  "keywords": [
8
- "clever-tools",
9
6
  "cli",
10
- "clever cloud"
7
+ "command-line",
8
+ "tool",
9
+ "clever-cloud",
10
+ "paas",
11
+ "deployment",
12
+ "cloud",
13
+ "devops",
14
+ "automation"
11
15
  ],
12
- "engines": {
13
- "node": ">=18"
16
+ "homepage": "https://github.com/CleverCloud/clever-tools",
17
+ "repository": {
18
+ "type": "git",
19
+ "url": "https://github.com/CleverCloud/clever-tools.git"
20
+ },
21
+ "bugs": {
22
+ "url": "https://github.com/CleverCloud/clever-tools/issues"
14
23
  },
15
- "pkg-node-version": "18",
16
24
  "author": "Clever Cloud <ci@clever-cloud.com>",
17
25
  "license": "Apache-2.0",
26
+ "type": "module",
27
+ "main": "bin/clever.js",
18
28
  "bin": {
19
29
  "clever": "bin/clever.js",
20
30
  "clever-tools": "bin/clever.js",
@@ -26,86 +36,60 @@
26
36
  "src",
27
37
  "scripts/*.sh"
28
38
  ],
39
+ "scripts": {
40
+ "fix-all": "npm run lint:fix && npm run format",
41
+ "format": "prettier . --write",
42
+ "format:check": "prettier . --check",
43
+ "install-local:cliparse": "(cd ../cliparse-node && npm pack) && mv ../cliparse-node/cliparse-*.tgz . && npm i -f ./cliparse-*.tgz",
44
+ "lint": "eslint",
45
+ "lint:fix": "eslint --fix",
46
+ "validate": "npm run lint && npm run format:check && npm run typecheck",
47
+ "typecheck": "tsc -p tsconfig.json"
48
+ },
29
49
  "dependencies": {
30
- "@clevercloud/client": "9.2.0",
31
- "@inquirer/prompts": "7.3.2",
50
+ "@clevercloud/client": "11.0.1",
51
+ "@inquirer/prompts": "7.8.4",
52
+ "char-regex": "2.0.2",
32
53
  "cliparse": "0.5.0",
33
- "colors": "1.4.0",
34
- "common-env": "6.4.0",
35
- "curlconverter": "3.21.0",
36
- "dedent": "1.5.3",
37
- "eventsource": "1.1.0",
38
- "ioredis": "5.4.1",
54
+ "dedent": "1.6.0",
55
+ "eventsource": "4.0.0",
56
+ "ioredis": "5.7.0",
39
57
  "iso8601-duration": "2.1.2",
40
- "isomorphic-git": "1.25.3",
58
+ "isomorphic-git": "1.33.1",
41
59
  "linux-release-info": "3.0.0",
42
60
  "lodash": "4.17.21",
43
- "mkdirp": "1.0.4",
44
- "moment": "2.29.1",
45
- "open": "8.4.0",
46
- "slugify": "1.5.3",
47
- "string-length": "4.0.2",
48
- "superagent": "6.1.0",
49
- "text-table": "0.2.0",
50
- "tldts": "6.1.30",
51
- "update-notifier": "5.1.0",
52
- "uuid": "8.3.2",
53
- "ws": "7.4.6",
61
+ "open": "10.2.0",
62
+ "semver": "7.7.2",
63
+ "slugify": "1.6.6",
64
+ "tldts": "7.0.12",
65
+ "update-notifier": "7.3.1",
54
66
  "xdg": "0.1.1"
55
67
  },
56
68
  "devDependencies": {
57
- "@commitlint/cli": "18.4.3",
58
- "@commitlint/config-conventional": "18.4.3",
59
- "@rollup/plugin-commonjs": "26.0.1",
69
+ "@aws-sdk/client-s3": "3.876.0",
70
+ "@clevercloud/eslint-config": "1.0.1",
71
+ "@commitlint/cli": "19.8.1",
72
+ "@commitlint/config-conventional": "19.8.1",
73
+ "@eslint/compat": "1.3.2",
74
+ "@rollup/plugin-commonjs": "28.0.6",
60
75
  "@rollup/plugin-json": "6.1.0",
61
- "@rollup/plugin-node-resolve": "15.2.3",
62
- "aws-sdk": "2.919.0",
63
- "chai": "4.3.4",
64
- "del": "6.0.0",
65
- "eslint": "7.27.0",
66
- "eslint-config-standard": "16.0.3",
67
- "eslint-plugin-import": "2.23.4",
68
- "eslint-plugin-node": "11.1.0",
69
- "eslint-plugin-promise": "5.1.0",
70
- "eslint-plugin-standard": "5.0.0",
71
- "fs-extra": "10.0.0",
72
- "glob": "7.1.7",
73
- "grunt": "1.4.1",
74
- "grunt-cli": "1.4.3",
75
- "grunt-http": "2.3.3",
76
- "grunt-mocha-test": "0.13.3",
77
- "magic-string": "0.30.11",
78
- "mime-types": "2.1.35",
79
- "mocha": "8.4.0",
80
- "pkg": "5.8.1",
81
- "rollup": "4.14.1",
82
- "semver": "7.3.5"
83
- },
84
- "overrides": {
85
- "pkg-fetch": "3.5.2"
86
- },
87
- "scripts": {
88
- "build": "rollup -c rollup.config.js",
89
- "pretest": "npm run lint",
90
- "test": "grunt test",
91
- "lint": "eslint bin src scripts",
92
- "lint:fix": "eslint --fix bin src scripts",
93
- "install-local:cliparse": "(cd ../cliparse-node && npm pack) && mv ../cliparse-node/cliparse-*.tgz . && npm i -f ./cliparse-*.tgz"
76
+ "@rollup/plugin-node-resolve": "16.0.1",
77
+ "@types/mime-types": "3.0.1",
78
+ "@yao-pkg/pkg": "6.6.0",
79
+ "eslint": "9.34.0",
80
+ "globals": "16.3.0",
81
+ "mime-types": "3.0.1",
82
+ "prettier": "3.6.2",
83
+ "prettier-plugin-organize-imports": "4.2.0",
84
+ "rollup": "4.49.0",
85
+ "simple-git": "3.28.0",
86
+ "tinyglobby": "0.2.14",
87
+ "typescript": "5.9.2"
94
88
  },
95
- "repository": {
96
- "type": "git",
97
- "url": "https://github.com/CleverCloud/clever-tools.git"
98
- },
99
- "bugs": {
100
- "url": "https://github.com/CleverCloud/clever-tools/issues"
101
- },
102
- "homepage": "https://github.com/CleverCloud/clever-tools",
103
- "pkg": {
104
- "scripts": [
105
- "src/**/*.js"
106
- ]
89
+ "engines": {
90
+ "node": ">=22"
107
91
  },
108
92
  "volta": {
109
- "node": "18.15.0"
93
+ "node": "22.17.0"
110
94
  }
111
95
  }
@@ -1,4 +1,4 @@
1
- export function createApiToken ({ email, password, mfaCode, name, description = '', expirationDate }) {
1
+ export function createApiToken({ email, password, mfaCode, name, description = '', expirationDate }) {
2
2
  return Promise.resolve({
3
3
  method: 'post',
4
4
  url: '/api-tokens',
@@ -7,7 +7,7 @@ export function createApiToken ({ email, password, mfaCode, name, description =
7
7
  });
8
8
  }
9
9
 
10
- export function listApiTokens () {
10
+ export function listApiTokens() {
11
11
  return Promise.resolve({
12
12
  method: 'get',
13
13
  url: '/api-tokens',
@@ -15,7 +15,7 @@ export function listApiTokens () {
15
15
  });
16
16
  }
17
17
 
18
- export function updateApiToken (apiTokenId, { name, description }) {
18
+ export function updateApiToken(apiTokenId, { name, description }) {
19
19
  return Promise.resolve({
20
20
  method: 'put',
21
21
  url: `/api-tokens/${apiTokenId}`,
@@ -24,7 +24,7 @@ export function updateApiToken (apiTokenId, { name, description }) {
24
24
  });
25
25
  }
26
26
 
27
- export function deleteApiToken (apiTokenId) {
27
+ export function deleteApiToken(apiTokenId) {
28
28
  return Promise.resolve({
29
29
  method: 'delete',
30
30
  url: `/api-tokens/${apiTokenId}`,
@@ -32,13 +32,11 @@ export function deleteApiToken (apiTokenId) {
32
32
  });
33
33
  }
34
34
 
35
- export function addOauthHeaderPlaintext (tokens) {
36
-
35
+ export function addOauthHeaderPlaintext(tokens) {
37
36
  return async function (requestParams) {
38
-
39
- const authorizationHeader = (
40
- 'OAuth '
41
- + [
37
+ const authorizationHeader =
38
+ 'OAuth ' +
39
+ [
42
40
  `oauth_consumer_key="${tokens.OAUTH_CONSUMER_KEY}"`,
43
41
  `oauth_token="${tokens.API_OAUTH_TOKEN}"`,
44
42
  // %26 is URL escaped character "&"
@@ -47,8 +45,7 @@ export function addOauthHeaderPlaintext (tokens) {
47
45
  // oauth_signature_method is not mandatory, it defaults to PLAINTEXT
48
46
  // oauth_timestamp is not mandatory
49
47
  // oauth_version is not mandatory, it defaults to 1.0
50
- ].join(', ')
51
- );
48
+ ].join(', ');
52
49
 
53
50
  return {
54
51
  ...requestParams,
@@ -6,7 +6,7 @@
6
6
  * @param {String} params.ownerId
7
7
  * @param {String} params.query
8
8
  */
9
- export function searchNetworkGroupOrResource (params) {
9
+ export function searchNetworkGroupOrResource(params) {
10
10
  // no multipath for /self or /organisations/{id}
11
11
  return Promise.resolve({
12
12
  method: 'get',
@@ -6,7 +6,7 @@
6
6
  * @param {String} params.provider
7
7
  * @param {String} params.realId
8
8
  */
9
- export function getOperator (params) {
9
+ export function getOperator(params) {
10
10
  // no multipath for /self or /organisations/{id}
11
11
  return Promise.resolve({
12
12
  method: 'get',
@@ -23,7 +23,7 @@ export function getOperator (params) {
23
23
  * @param {String} params.provider
24
24
  * @param {String} params.realId
25
25
  */
26
- export function rebootOperator (params) {
26
+ export function rebootOperator(params) {
27
27
  // no multipath for /self or /organisations/{id}
28
28
  return Promise.resolve({
29
29
  method: 'post',
@@ -40,7 +40,7 @@ export function rebootOperator (params) {
40
40
  * @param {String} params.provider
41
41
  * @param {String} params.realId
42
42
  */
43
- export function rebuildOperator (params) {
43
+ export function rebuildOperator(params) {
44
44
  // no multipath for /self or /organisations/{id}
45
45
  return Promise.resolve({
46
46
  method: 'post',
@@ -57,7 +57,7 @@ export function rebuildOperator (params) {
57
57
  * @param {String} params.provider
58
58
  * @param {String} params.realId
59
59
  */
60
- export function ngEnableOperator (params) {
60
+ export function ngEnableOperator(params) {
61
61
  // no multipath for /self or /organisations/{id}
62
62
  return Promise.resolve({
63
63
  method: 'post',
@@ -74,7 +74,7 @@ export function ngEnableOperator (params) {
74
74
  * @param {String} params.provider
75
75
  * @param {String} params.realId
76
76
  */
77
- export function ngDisableOperator (params) {
77
+ export function ngDisableOperator(params) {
78
78
  // no multipath for /self or /organisations/{id}
79
79
  return Promise.resolve({
80
80
  method: 'delete',
@@ -91,7 +91,7 @@ export function ngDisableOperator (params) {
91
91
  * @param {String} params.provider
92
92
  * @param {String} params.realId
93
93
  */
94
- export function versionCheck (params) {
94
+ export function versionCheck(params) {
95
95
  // no multipath for /self or /organisations/{id}
96
96
  return Promise.resolve({
97
97
  method: 'get',
@@ -109,7 +109,7 @@ export function versionCheck (params) {
109
109
  * @param {String} params.realId
110
110
  * @param {Object} body
111
111
  */
112
- export function versionUpdate (params, body) {
112
+ export function versionUpdate(params, body) {
113
113
  // no multipath for /self or /organisations/{id}
114
114
  return Promise.resolve({
115
115
  method: 'post',
@@ -1,6 +1,6 @@
1
1
  import cliparse from 'cliparse';
2
2
 
3
- export function getOutputFormatOption (formats = []) {
3
+ export function getOutputFormatOption(formats = []) {
4
4
  const availableFormats = ['human', 'json', ...formats];
5
5
  return cliparse.option('format', {
6
6
  aliases: ['F'],
@@ -12,13 +12,13 @@ export function getOutputFormatOption (formats = []) {
12
12
  },
13
13
  default: 'human',
14
14
  description: `Output format (${availableFormats.join(', ')})`,
15
- complete () {
15
+ complete() {
16
16
  return cliparse.autocomplete.words(availableFormats);
17
17
  },
18
18
  });
19
19
  }
20
20
 
21
- export function getSameCommitPolicyOption () {
21
+ export function getSameCommitPolicyOption() {
22
22
  const availablePolicies = ['error', 'ignore', 'restart', 'rebuild'];
23
23
  return cliparse.option('same-commit-policy', {
24
24
  aliases: ['p'],
@@ -30,13 +30,13 @@ export function getSameCommitPolicyOption () {
30
30
  },
31
31
  default: 'error',
32
32
  description: `What to do when local and remote commit are identical (${availablePolicies.join(', ')})`,
33
- complete () {
33
+ complete() {
34
34
  return cliparse.autocomplete.words(availablePolicies);
35
35
  },
36
36
  });
37
37
  }
38
38
 
39
- export function getExitOnOption () {
39
+ export function getExitOnOption() {
40
40
  const availableExitOn = ['deploy-start', 'deploy-end', 'never'];
41
41
  return cliparse.option('exit-on', {
42
42
  aliases: ['e'],
@@ -48,7 +48,7 @@ export function getExitOnOption () {
48
48
  },
49
49
  default: 'deploy-end',
50
50
  description: `Step at which the logs streaming is ended, steps are: ${availableExitOn.join(', ')}`,
51
- complete () {
51
+ complete() {
52
52
  return cliparse.autocomplete.words(availableExitOn);
53
53
  },
54
54
  });
@@ -1,15 +1,15 @@
1
- import { Logger } from './logger.js';
2
- import { getPackageJson } from './load-package-json.cjs';
3
1
  import semver from 'semver';
2
+ import pkg from '../package.json' with { type: 'json' };
3
+ import { Logger } from './logger.js';
4
4
 
5
- const pkg = getPackageJson();
6
-
7
- export function handleCommandPromise (promise) {
5
+ export function handleCommandPromise(promise) {
8
6
  promise.catch((error) => {
9
7
  Logger.error(error);
10
8
  const semverIsOk = semver.satisfies(process.version, pkg.engines.node);
11
9
  if (!semverIsOk) {
12
- Logger.warn(`You are using node ${process.version}, some of our commands require node ${pkg.engines.node}. The error may be caused by this.`);
10
+ Logger.warn(
11
+ `You are using node ${process.version}, some of our commands require node ${pkg.engines.node}. The error may be caused by this.`,
12
+ );
13
13
  }
14
14
  process.exit(1);
15
15
  });
@@ -1,10 +1,10 @@
1
- import * as Application from '../models/application.js';
2
- import { Logger } from '../logger.js';
3
- import { getHostAndTokens } from '../models/send-to-api.js';
4
1
  import { ApplicationAccessLogStream } from '@clevercloud/client/esm/streams/access-logs.js';
5
- import { JsonArray } from '../models/json-array.js';
6
- import colors from 'colors/safe.js';
2
+ import { styleText } from 'node:util';
7
3
  import { formatTable } from '../format-table.js';
4
+ import { Logger } from '../logger.js';
5
+ import * as Application from '../models/application.js';
6
+ import { JsonArray } from '../models/json-array.js';
7
+ import { getHostAndTokens } from '../models/send-to-api.js';
8
8
  import { truncateWithEllipsis } from '../models/utils.js';
9
9
 
10
10
  // 2000 logs per 100ms maximum
@@ -12,8 +12,7 @@ const THROTTLE_ELEMENTS = 2000;
12
12
  const THROTTLE_PER_IN_MILLISECONDS = 100;
13
13
  const CITY_MAX_LENGTH = 20;
14
14
 
15
- export async function accessLogs (params) {
16
-
15
+ export async function accessLogs(params) {
17
16
  // TODO: drop when add-ons are supported in API
18
17
  if (params.options.addon) {
19
18
  throw new Error('Access Logs are not available for add-ons yet');
@@ -35,10 +34,10 @@ export async function accessLogs (params) {
35
34
  });
36
35
 
37
36
  if (format === 'human') {
38
- Logger.warn(colors.yellow('/!\\ Access Logs feature is in Alpha testing phase'));
37
+ Logger.warn(styleText('yellow', '/!\\ Access Logs feature is in Alpha testing phase'));
39
38
  }
40
39
 
41
- if (format === 'json' && (!until)) {
40
+ if (format === 'json' && !until) {
42
41
  throw new Error('JSON format only works with a limiting parameter such as `before`');
43
42
  }
44
43
 
@@ -46,14 +45,14 @@ export async function accessLogs (params) {
46
45
  const jsonArray = new JsonArray();
47
46
 
48
47
  stream
49
- .on('open', (event) => {
50
- Logger.debug(colors.blue(`Logs stream (open) ${JSON.stringify({ appId })}`));
48
+ .on('open', () => {
49
+ Logger.debug(styleText('blue', `Logs stream (open) ${JSON.stringify({ appId })}`));
51
50
  if (format === 'json') {
52
51
  jsonArray.open();
53
52
  }
54
53
  })
55
54
  .on('error', (event) => {
56
- Logger.debug(colors.red(`Logs stream (error) ${event.error.message}`));
55
+ Logger.debug(styleText('red', `Logs stream (error) ${event.error.message}`));
57
56
  })
58
57
  .onLog((log) => {
59
58
  switch (format) {
@@ -87,21 +86,26 @@ export async function accessLogs (params) {
87
86
  Logger.debug(`stream closed: ${closeReason?.type}`);
88
87
  }
89
88
 
90
- function formatHuman (log) {
89
+ function formatHuman(log) {
91
90
  const { date, http, source } = log;
92
91
  const country = source.countryCode ?? '(unknown)';
93
92
  const hasSourceCity = source.city ?? '';
94
93
 
95
- return row([[
96
- colors.grey(date.toISOString(date)),
97
- source.ip,
98
- `${country}${hasSourceCity ? '/' + truncateWithEllipsis(CITY_MAX_LENGTH, source.city) : ''}`,
99
- colorStatusCode(http.response.statusCode),
100
- http.request.method.toString().padEnd(4, ' ') + ' ' + http.request.path,
101
- ]]);
94
+ return formatTable(
95
+ [
96
+ [
97
+ styleText('grey', date.toISOString(date)),
98
+ source.ip,
99
+ `${country}${hasSourceCity ? '/' + truncateWithEllipsis(CITY_MAX_LENGTH, source.city) : ''}`,
100
+ colorStatusCode(http.response.statusCode),
101
+ http.request.method.toString().padEnd(4, ' ') + ' ' + http.request.path,
102
+ ],
103
+ ],
104
+ ACCESSLOG_COLUMN_WIDTHS,
105
+ );
102
106
  }
103
107
 
104
- const row = formatTable([
108
+ const ACCESSLOG_COLUMN_WIDTHS = [
105
109
  '2024-06-24T08:05:43.880Z',
106
110
  '255.255.255.255',
107
111
  // country / city
@@ -110,20 +114,25 @@ const row = formatTable([
110
114
  // longest method name
111
115
  'OPTIONS',
112
116
  // path
113
- ]);
114
-
115
- function colorStatusCode (code) {
117
+ ];
118
+
119
+ /**
120
+ * @param {number} code
121
+ * @returns {string}
122
+ */
123
+ function colorStatusCode(code) {
124
+ const codeString = code.toString();
116
125
  if (code >= 500) {
117
- return colors.red(code);
126
+ return styleText('red', codeString);
118
127
  }
119
128
  if (code >= 400) {
120
- return colors.yellow(code);
129
+ return styleText('yellow', codeString);
121
130
  }
122
131
  if (code >= 300) {
123
- return colors.blue(code);
132
+ return styleText('blue', codeString);
124
133
  }
125
134
  if (code >= 200) {
126
- return colors.green(code);
135
+ return styleText('green', codeString);
127
136
  }
128
- return code;
137
+ return codeString;
129
138
  }