clever-tools 4.4.0 → 4.5.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 (296) hide show
  1. package/bin/clever.js +208 -2128
  2. package/package.json +33 -25
  3. package/src/clever-client/auth-bridge.js +0 -9
  4. package/src/clever-client/drains.js +0 -17
  5. package/src/clever-client/operators.js +1 -1
  6. package/src/commands/README.md +65 -0
  7. package/src/commands/accesslogs/accesslogs.command.js +158 -0
  8. package/src/commands/accesslogs/accesslogs.docs.md +20 -0
  9. package/src/commands/{activity.js → activity/activity.command.js} +74 -44
  10. package/src/commands/activity/activity.docs.md +19 -0
  11. package/src/commands/addon/addon.args.js +14 -0
  12. package/src/commands/addon/addon.command.js +7 -0
  13. package/src/commands/addon/addon.create.command.js +236 -0
  14. package/src/commands/addon/addon.delete.command.js +32 -0
  15. package/src/commands/addon/addon.docs.md +156 -0
  16. package/src/commands/addon/addon.env.command.js +50 -0
  17. package/src/commands/addon/addon.list.command.js +55 -0
  18. package/src/commands/addon/addon.providers.command.js +45 -0
  19. package/src/commands/addon/addon.providers.show.command.js +99 -0
  20. package/src/commands/addon/addon.rename.command.js +24 -0
  21. package/src/commands/applications/applications.command.js +59 -0
  22. package/src/commands/applications/applications.docs.md +31 -0
  23. package/src/commands/applications/applications.list.command.js +100 -0
  24. package/src/commands/cancel-deploy/cancel-deploy.command.js +30 -0
  25. package/src/commands/cancel-deploy/cancel-deploy.docs.md +16 -0
  26. package/src/commands/config/config.args.js +10 -0
  27. package/src/commands/config/config.command.js +20 -0
  28. package/src/commands/config/config.docs.md +86 -0
  29. package/src/commands/config/config.get.command.js +21 -0
  30. package/src/commands/config/config.set.command.js +38 -0
  31. package/src/commands/config/config.update.command.js +88 -0
  32. package/src/commands/console/console.command.js +31 -0
  33. package/src/commands/console/console.docs.md +16 -0
  34. package/src/commands/create/create.command.js +173 -0
  35. package/src/commands/create/create.docs.md +27 -0
  36. package/src/commands/{curl.js → curl/curl.command.js} +10 -3
  37. package/src/commands/curl/curl.docs.md +9 -0
  38. package/src/commands/database/database.args.js +8 -0
  39. package/src/commands/database/database.backups.command.js +60 -0
  40. package/src/commands/database/database.backups.download.command.js +55 -0
  41. package/src/commands/database/database.command.js +10 -0
  42. package/src/commands/database/database.docs.md +52 -0
  43. package/src/commands/delete/delete.command.js +43 -0
  44. package/src/commands/delete/delete.docs.md +17 -0
  45. package/src/commands/deploy/deploy.command.js +166 -0
  46. package/src/commands/deploy/deploy.docs.md +22 -0
  47. package/src/commands/diag/diag.command.js +136 -0
  48. package/src/commands/diag/diag.docs.md +15 -0
  49. package/src/commands/domain/domain.add.command.js +25 -0
  50. package/src/commands/domain/domain.args.js +8 -0
  51. package/src/commands/domain/domain.command.js +38 -0
  52. package/src/commands/domain/domain.diag.command.js +204 -0
  53. package/src/commands/domain/domain.docs.md +143 -0
  54. package/src/commands/domain/domain.favourite.command.js +35 -0
  55. package/src/commands/domain/domain.favourite.set.command.js +24 -0
  56. package/src/commands/domain/domain.favourite.unset.command.js +23 -0
  57. package/src/commands/domain/domain.overview.command.js +157 -0
  58. package/src/commands/domain/domain.rm.command.js +25 -0
  59. package/src/commands/drain/drain.args.js +8 -0
  60. package/src/commands/drain/drain.command.js +56 -0
  61. package/src/commands/drain/drain.create.command.js +128 -0
  62. package/src/commands/drain/drain.disable.command.js +27 -0
  63. package/src/commands/drain/drain.docs.md +129 -0
  64. package/src/commands/drain/drain.enable.command.js +27 -0
  65. package/src/commands/drain/drain.get.command.js +38 -0
  66. package/src/commands/drain/drain.remove.command.js +26 -0
  67. package/src/commands/emails/emails.add.command.js +32 -0
  68. package/src/commands/emails/emails.args.js +8 -0
  69. package/src/commands/emails/emails.command.js +35 -0
  70. package/src/commands/emails/emails.docs.md +79 -0
  71. package/src/commands/emails/emails.open.command.js +15 -0
  72. package/src/commands/emails/emails.primary.command.js +29 -0
  73. package/src/commands/emails/emails.remove-all.command.js +54 -0
  74. package/src/commands/emails/emails.remove.command.js +25 -0
  75. package/src/commands/env/env.command.js +77 -0
  76. package/src/commands/env/env.docs.md +99 -0
  77. package/src/commands/env/env.import-vars.command.js +45 -0
  78. package/src/commands/env/env.import.command.js +29 -0
  79. package/src/commands/env/env.rm.command.js +25 -0
  80. package/src/commands/env/env.set.command.js +32 -0
  81. package/src/commands/features/features.args.js +9 -0
  82. package/src/commands/features/features.command.js +7 -0
  83. package/src/commands/features/features.disable.command.js +25 -0
  84. package/src/commands/features/features.docs.md +71 -0
  85. package/src/commands/features/features.enable.command.js +32 -0
  86. package/src/commands/features/features.info.command.js +27 -0
  87. package/src/commands/features/features.list.command.js +49 -0
  88. package/src/commands/global.args.js +45 -0
  89. package/src/commands/global.commands.js +461 -0
  90. package/src/commands/global.options.js +186 -0
  91. package/src/commands/help/help.command.js +9 -0
  92. package/src/commands/help/help.docs.md +9 -0
  93. package/src/commands/k8s/k8s.add-persistent-storage.command.js +39 -0
  94. package/src/commands/k8s/k8s.args.js +9 -0
  95. package/src/commands/k8s/k8s.command.js +12 -0
  96. package/src/commands/k8s/k8s.create.command.js +86 -0
  97. package/src/commands/k8s/k8s.delete.command.js +40 -0
  98. package/src/commands/k8s/k8s.docs.md +131 -0
  99. package/src/commands/k8s/k8s.get-kubeconfig.command.js +32 -0
  100. package/src/commands/k8s/k8s.get.command.js +43 -0
  101. package/src/commands/k8s/k8s.list.command.js +38 -0
  102. package/src/commands/keycloak/keycloak.command.js +17 -0
  103. package/src/commands/keycloak/keycloak.disable-ng.command.js +13 -0
  104. package/src/commands/keycloak/keycloak.docs.md +197 -0
  105. package/src/commands/keycloak/keycloak.enable-ng.command.js +13 -0
  106. package/src/commands/keycloak/keycloak.get.command.js +17 -0
  107. package/src/commands/keycloak/keycloak.open.command.js +13 -0
  108. package/src/commands/keycloak/keycloak.open.logs.command.js +13 -0
  109. package/src/commands/keycloak/keycloak.open.webui.command.js +13 -0
  110. package/src/commands/keycloak/keycloak.rebuild.command.js +13 -0
  111. package/src/commands/keycloak/keycloak.restart.command.js +13 -0
  112. package/src/commands/keycloak/keycloak.version.check.command.js +17 -0
  113. package/src/commands/keycloak/keycloak.version.command.js +17 -0
  114. package/src/commands/keycloak/keycloak.version.update.command.js +17 -0
  115. package/src/commands/kv/kv.command.js +99 -0
  116. package/src/commands/kv/kv.docs.md +27 -0
  117. package/src/commands/link/link.command.js +31 -0
  118. package/src/commands/link/link.docs.md +22 -0
  119. package/src/commands/{login.js → login/login.command.js} +44 -22
  120. package/src/commands/login/login.docs.md +16 -0
  121. package/src/commands/logout/logout.command.js +15 -0
  122. package/src/commands/logout/logout.docs.md +9 -0
  123. package/src/commands/logs/logs.command.js +81 -0
  124. package/src/commands/logs/logs.docs.md +22 -0
  125. package/src/commands/make-default/make-default.command.js +17 -0
  126. package/src/commands/make-default/make-default.docs.md +15 -0
  127. package/src/commands/matomo/matomo.command.js +17 -0
  128. package/src/commands/matomo/matomo.docs.md +109 -0
  129. package/src/commands/matomo/matomo.get.command.js +17 -0
  130. package/src/commands/matomo/matomo.open.command.js +13 -0
  131. package/src/commands/matomo/matomo.open.logs.command.js +13 -0
  132. package/src/commands/matomo/matomo.open.webui.command.js +13 -0
  133. package/src/commands/matomo/matomo.rebuild.command.js +13 -0
  134. package/src/commands/matomo/matomo.restart.command.js +13 -0
  135. package/src/commands/metabase/metabase.command.js +17 -0
  136. package/src/commands/metabase/metabase.docs.md +169 -0
  137. package/src/commands/metabase/metabase.get.command.js +17 -0
  138. package/src/commands/metabase/metabase.open.command.js +13 -0
  139. package/src/commands/metabase/metabase.open.logs.command.js +13 -0
  140. package/src/commands/metabase/metabase.open.webui.command.js +13 -0
  141. package/src/commands/metabase/metabase.rebuild.command.js +13 -0
  142. package/src/commands/metabase/metabase.restart.command.js +13 -0
  143. package/src/commands/metabase/metabase.version.check.command.js +17 -0
  144. package/src/commands/metabase/metabase.version.command.js +17 -0
  145. package/src/commands/metabase/metabase.version.update.command.js +17 -0
  146. package/src/commands/ng/ng.args.js +27 -0
  147. package/src/commands/ng/ng.command.js +45 -0
  148. package/src/commands/ng/ng.create.command.js +60 -0
  149. package/src/commands/ng/ng.create.external.command.js +44 -0
  150. package/src/commands/ng/ng.delete.command.js +22 -0
  151. package/src/commands/ng/ng.delete.external.command.js +25 -0
  152. package/src/commands/ng/ng.docs.md +214 -0
  153. package/src/commands/ng/ng.get-config.command.js +32 -0
  154. package/src/commands/ng/ng.get.command.js +22 -0
  155. package/src/commands/ng/ng.link.command.js +25 -0
  156. package/src/commands/ng/ng.options.js +9 -0
  157. package/src/commands/ng/ng.search.command.js +22 -0
  158. package/src/commands/ng/ng.unlink.command.js +25 -0
  159. package/src/commands/notify-email/notify-email.add.command.js +65 -0
  160. package/src/commands/notify-email/notify-email.command.js +61 -0
  161. package/src/commands/notify-email/notify-email.docs.md +60 -0
  162. package/src/commands/notify-email/notify-email.remove.command.js +24 -0
  163. package/src/commands/open/open.command.js +24 -0
  164. package/src/commands/open/open.docs.md +16 -0
  165. package/src/commands/otoroshi/otoroshi.command.js +17 -0
  166. package/src/commands/otoroshi/otoroshi.disable-ng.command.js +13 -0
  167. package/src/commands/otoroshi/otoroshi.docs.md +211 -0
  168. package/src/commands/otoroshi/otoroshi.enable-ng.command.js +13 -0
  169. package/src/commands/otoroshi/otoroshi.get-config.command.js +13 -0
  170. package/src/commands/otoroshi/otoroshi.get.command.js +17 -0
  171. package/src/commands/otoroshi/otoroshi.open.command.js +13 -0
  172. package/src/commands/otoroshi/otoroshi.open.logs.command.js +13 -0
  173. package/src/commands/otoroshi/otoroshi.open.webui.command.js +13 -0
  174. package/src/commands/otoroshi/otoroshi.rebuild.command.js +13 -0
  175. package/src/commands/otoroshi/otoroshi.restart.command.js +13 -0
  176. package/src/commands/otoroshi/otoroshi.version.check.command.js +17 -0
  177. package/src/commands/otoroshi/otoroshi.version.command.js +17 -0
  178. package/src/commands/otoroshi/otoroshi.version.update.command.js +17 -0
  179. package/src/commands/profile/profile.command.js +60 -0
  180. package/src/commands/profile/profile.docs.md +23 -0
  181. package/src/commands/profile/profile.open.command.js +12 -0
  182. package/src/commands/published-config/published-config.command.js +40 -0
  183. package/src/commands/published-config/published-config.docs.md +77 -0
  184. package/src/commands/published-config/published-config.import.command.js +29 -0
  185. package/src/commands/published-config/published-config.rm.command.js +27 -0
  186. package/src/commands/published-config/published-config.set.command.js +34 -0
  187. package/src/commands/restart/restart.command.js +77 -0
  188. package/src/commands/restart/restart.docs.md +21 -0
  189. package/src/commands/scale/scale.command.js +121 -0
  190. package/src/commands/scale/scale.docs.md +23 -0
  191. package/src/commands/service/service.command.js +91 -0
  192. package/src/commands/service/service.docs.md +104 -0
  193. package/src/commands/service/service.link-addon.command.js +24 -0
  194. package/src/commands/service/service.link-app.command.js +23 -0
  195. package/src/commands/service/service.unlink-addon.command.js +24 -0
  196. package/src/commands/service/service.unlink-app.command.js +23 -0
  197. package/src/commands/ssh/ssh.command.js +40 -0
  198. package/src/commands/ssh/ssh.docs.md +17 -0
  199. package/src/commands/ssh-keys/ssh-keys.add.command.js +41 -0
  200. package/src/commands/ssh-keys/ssh-keys.args.js +8 -0
  201. package/src/commands/ssh-keys/ssh-keys.command.js +50 -0
  202. package/src/commands/ssh-keys/ssh-keys.docs.md +66 -0
  203. package/src/commands/ssh-keys/ssh-keys.open.command.js +12 -0
  204. package/src/commands/ssh-keys/ssh-keys.remove-all.command.js +54 -0
  205. package/src/commands/ssh-keys/ssh-keys.remove.command.js +26 -0
  206. package/src/commands/status/status.command.js +122 -0
  207. package/src/commands/status/status.docs.md +17 -0
  208. package/src/commands/stop/stop.command.js +23 -0
  209. package/src/commands/stop/stop.docs.md +16 -0
  210. package/src/commands/tcp-redirs/tcp-redirs.add.command.js +24 -0
  211. package/src/commands/tcp-redirs/tcp-redirs.command.js +41 -0
  212. package/src/commands/tcp-redirs/tcp-redirs.docs.md +71 -0
  213. package/src/commands/tcp-redirs/tcp-redirs.list-namespaces.command.js +48 -0
  214. package/src/commands/tcp-redirs/tcp-redirs.options.js +11 -0
  215. package/src/commands/tcp-redirs/tcp-redirs.remove.command.js +34 -0
  216. package/src/commands/tokens/tokens.command.js +43 -0
  217. package/src/commands/tokens/tokens.create.command.js +108 -0
  218. package/src/commands/tokens/tokens.docs.md +50 -0
  219. package/src/commands/tokens/tokens.revoke.command.js +25 -0
  220. package/src/commands/unlink/unlink.command.js +21 -0
  221. package/src/commands/unlink/unlink.docs.md +15 -0
  222. package/src/commands/version/version.command.js +13 -0
  223. package/src/commands/version/version.docs.md +9 -0
  224. package/src/commands/webhooks/webhooks.add.command.js +51 -0
  225. package/src/commands/webhooks/webhooks.command.js +57 -0
  226. package/src/commands/webhooks/webhooks.docs.md +61 -0
  227. package/src/commands/webhooks/webhooks.remove.command.js +24 -0
  228. package/src/lib/cliparse-patched.js +192 -0
  229. package/src/lib/define-argument.js +7 -0
  230. package/src/lib/define-argument.types.d.ts +23 -0
  231. package/src/lib/define-command.js +7 -0
  232. package/src/lib/define-command.types.d.ts +85 -0
  233. package/src/lib/define-common.types.d.ts +18 -0
  234. package/src/lib/define-option.js +7 -0
  235. package/src/lib/define-option.types.d.ts +29 -0
  236. package/src/lib/get-command-info.js +86 -0
  237. package/src/lib/get-command-info.types.d.ts +42 -0
  238. package/src/lib/k8s.js +1 -1
  239. package/src/lib/zod-utils.js +66 -0
  240. package/src/models/addon.js +2 -19
  241. package/src/models/app_configuration.js +0 -30
  242. package/src/models/application.js +4 -5
  243. package/src/models/application_configuration.js +5 -23
  244. package/src/models/domain.js +34 -2
  245. package/src/models/exit-strategy-option.js +0 -9
  246. package/src/models/git.js +1 -4
  247. package/src/models/log-v4.js +15 -4
  248. package/src/models/log.js +5 -0
  249. package/src/models/namespaces.js +1 -2
  250. package/src/models/notification.js +1 -7
  251. package/src/parsers.js +33 -111
  252. package/src/command-options.js +0 -55
  253. package/src/command-promise-handler.js +0 -16
  254. package/src/commands/accesslogs.js +0 -138
  255. package/src/commands/addon.js +0 -391
  256. package/src/commands/applications.js +0 -123
  257. package/src/commands/cancel-deploy.js +0 -19
  258. package/src/commands/config.js +0 -47
  259. package/src/commands/console.js +0 -20
  260. package/src/commands/create.js +0 -129
  261. package/src/commands/database.js +0 -73
  262. package/src/commands/delete.js +0 -24
  263. package/src/commands/deploy.js +0 -133
  264. package/src/commands/diag.js +0 -126
  265. package/src/commands/domain.js +0 -445
  266. package/src/commands/drain.js +0 -164
  267. package/src/commands/emails.js +0 -156
  268. package/src/commands/env.js +0 -124
  269. package/src/commands/features.js +0 -87
  270. package/src/commands/k8s.js +0 -193
  271. package/src/commands/keycloak.js +0 -138
  272. package/src/commands/kv.js +0 -93
  273. package/src/commands/link.js +0 -20
  274. package/src/commands/logout.js +0 -8
  275. package/src/commands/logs.js +0 -45
  276. package/src/commands/makeDefault.js +0 -11
  277. package/src/commands/matomo.js +0 -85
  278. package/src/commands/metabase.js +0 -112
  279. package/src/commands/ng.js +0 -202
  280. package/src/commands/notify-email.js +0 -99
  281. package/src/commands/open.js +0 -13
  282. package/src/commands/otoroshi.js +0 -150
  283. package/src/commands/profile.js +0 -55
  284. package/src/commands/published-config.js +0 -70
  285. package/src/commands/restart.js +0 -52
  286. package/src/commands/scale.js +0 -66
  287. package/src/commands/service.js +0 -105
  288. package/src/commands/ssh-keys.js +0 -144
  289. package/src/commands/ssh.js +0 -20
  290. package/src/commands/status.js +0 -115
  291. package/src/commands/stop.js +0 -12
  292. package/src/commands/tcp-redirs.js +0 -80
  293. package/src/commands/tokens.js +0 -144
  294. package/src/commands/unlink.js +0 -14
  295. package/src/commands/version.js +0 -6
  296. package/src/commands/webhooks.js +0 -74
@@ -0,0 +1,136 @@
1
+ import { releaseInfo as getLinuxInfos } from 'linux-release-info';
2
+ import os from 'node:os';
3
+ import pkg from '../../../package.json' with { type: 'json' };
4
+ import { defineCommand } from '../../lib/define-command.js';
5
+ import { styleText } from '../../lib/style-text.js';
6
+ import { Logger } from '../../logger.js';
7
+ import { conf, loadOAuthConf } from '../../models/configuration.js';
8
+ import * as User from '../../models/user.js';
9
+ import { humanJsonOutputFormatOption } from '../global.options.js';
10
+
11
+ function getShell() {
12
+ const platform = os.platform();
13
+
14
+ if (platform === 'win32') {
15
+ if (process.env.PSModulePath) {
16
+ if (process.env.WT_SESSION) {
17
+ return 'PowerShell (Windows Terminal)';
18
+ }
19
+ if (process.env.PSVersionTable || process.env.POWERSHELL_DISTRIBUTION_CHANNEL) {
20
+ return 'PowerShell Core';
21
+ }
22
+ return 'Windows PowerShell';
23
+ }
24
+ if (process.env.WT_SESSION) {
25
+ return 'Windows Terminal (cmd)';
26
+ }
27
+ return process.env.ComSpec || 'cmd.exe';
28
+ }
29
+
30
+ return process.env.SHELL || 'unknown';
31
+ }
32
+
33
+ function getTerminal() {
34
+ if (process.env.WT_SESSION) {
35
+ return 'Windows Terminal';
36
+ }
37
+ return process.env.TERM_PROGRAM || process.env.TERMINAL_EMULATOR || process.env.TERM;
38
+ }
39
+
40
+ export const diagCommand = defineCommand({
41
+ description: 'Diagnose the current installation (prints various informations for support)',
42
+ since: '1.6.0',
43
+ options: {
44
+ format: humanJsonOutputFormatOption,
45
+ },
46
+ args: [],
47
+ async handler(options) {
48
+ const { format } = options;
49
+
50
+ /** @type {string} */
51
+ const userId = await User.getCurrentId().catch(() => null);
52
+ const authDetails = await loadOAuthConf();
53
+
54
+ function getAuthState() {
55
+ if (authDetails.token == null) {
56
+ return 'not connected';
57
+ }
58
+ if (userId == null) {
59
+ return 'authentication failed';
60
+ }
61
+ return 'authenticated';
62
+ }
63
+
64
+ const formattedDiag = {
65
+ version: pkg.version,
66
+ commitId: pkg.commitId,
67
+ nodeVersion: process.version,
68
+ platform: os.platform(),
69
+ release: os.release(),
70
+ arch: process.arch,
71
+ shell: getShell(),
72
+ terminal: getTerminal(),
73
+ isPackaged: process.pkg != null,
74
+ execPath: process.execPath,
75
+ configFile: conf.CONFIGURATION_FILE,
76
+ authSource: authDetails.source,
77
+ oAuthToken: authDetails.token,
78
+ authState: getAuthState(),
79
+ userId,
80
+ };
81
+
82
+ const linuxInfos = await getLinuxInfos()
83
+ .then(({ pretty_name, name, id }) => pretty_name || name || id)
84
+ .catch(() => null);
85
+ if (linuxInfos != null) {
86
+ formattedDiag.linuxInfos = linuxInfos;
87
+ }
88
+
89
+ switch (format) {
90
+ case 'json': {
91
+ Logger.printJson(formattedDiag);
92
+ break;
93
+ }
94
+ case 'human':
95
+ default: {
96
+ Logger.println('clever-tools ' + styleText('green', formattedDiag.version));
97
+ // Only available in built binaries
98
+ if (formattedDiag.commitId) {
99
+ Logger.println('Commit ' + styleText('green', formattedDiag.commitId));
100
+ }
101
+ Logger.println('Node.js ' + styleText('green', formattedDiag.nodeVersion));
102
+ Logger.println('Platform ' + styleText('green', formattedDiag.platform));
103
+ Logger.println('Release ' + styleText('green', formattedDiag.release));
104
+ Logger.println('Architecture ' + styleText('green', formattedDiag.arch));
105
+ if (formattedDiag.linuxInfos != null) {
106
+ Logger.println('Linux ' + styleText('green', formattedDiag.linuxInfos));
107
+ }
108
+ Logger.println('Shell ' + styleText('green', formattedDiag.shell));
109
+ Logger.println('Terminal ' + styleText('green', formattedDiag.terminal));
110
+ Logger.println('Packaged ' + styleText('green', formattedDiag.isPackaged));
111
+ Logger.println('Exec path ' + styleText('green', formattedDiag.execPath));
112
+ Logger.println('Config file ' + styleText('green', formattedDiag.configFile));
113
+
114
+ Logger.println('Auth source ' + styleText('green', formattedDiag.authSource));
115
+
116
+ const token =
117
+ formattedDiag.oAuthToken == null ? styleText('red', '(none)') : styleText('green', formattedDiag.oAuthToken);
118
+ Logger.println('oAuth token ' + token);
119
+
120
+ switch (formattedDiag.authState) {
121
+ case 'authenticated': {
122
+ Logger.println('User ID ' + styleText('green', formattedDiag.userId));
123
+ break;
124
+ }
125
+ case 'authentication failed': {
126
+ Logger.println('User ID ' + styleText('red', 'Authentication failed'));
127
+ break;
128
+ }
129
+ case 'not connected': {
130
+ Logger.println('User ID ' + styleText('red', 'Not connected'));
131
+ }
132
+ }
133
+ }
134
+ }
135
+ },
136
+ });
@@ -0,0 +1,15 @@
1
+ # 📖 `clever diag` command reference
2
+
3
+ ## ➡️ `clever diag` <kbd>Since 1.6.0</kbd>
4
+
5
+ Diagnose the current installation (prints various informations for support)
6
+
7
+ ```bash
8
+ clever diag [options]
9
+ ```
10
+
11
+ ### ⚙️ Options
12
+
13
+ |Name|Description|
14
+ |---|---|
15
+ |`-F`, `--format` `<format>`|Output format (human, json) (default: human)|
@@ -0,0 +1,25 @@
1
+ import { addDomain } from '@clevercloud/client/esm/api/v2/application.js';
2
+ import { defineCommand } from '../../lib/define-command.js';
3
+ import { Logger } from '../../logger.js';
4
+ import * as Application from '../../models/application.js';
5
+ import { sendToApi } from '../../models/send-to-api.js';
6
+ import { aliasOption, appIdOrNameOption } from '../global.options.js';
7
+ import { fqdnArg } from './domain.args.js';
8
+
9
+ export const domainAddCommand = defineCommand({
10
+ description: 'Add a domain name to an application',
11
+ since: '0.2.0',
12
+ options: {
13
+ alias: aliasOption,
14
+ app: appIdOrNameOption,
15
+ },
16
+ args: [fqdnArg],
17
+ async handler(options, fqdn) {
18
+ const { alias, app: appIdOrName } = options;
19
+ const { ownerId, appId } = await Application.resolveId(appIdOrName, alias);
20
+ const encodedFqdn = encodeURIComponent(fqdn);
21
+
22
+ await addDomain({ id: ownerId, appId, domain: encodedFqdn }).then(sendToApi);
23
+ Logger.println('Your domain has been successfully saved');
24
+ },
25
+ });
@@ -0,0 +1,8 @@
1
+ import { z } from 'zod';
2
+ import { defineArgument } from '../../lib/define-argument.js';
3
+
4
+ export const fqdnArg = defineArgument({
5
+ schema: z.string(),
6
+ description: 'Domain name of the application',
7
+ placeholder: 'fqdn',
8
+ });
@@ -0,0 +1,38 @@
1
+ import { get as getApp } from '@clevercloud/client/esm/api/v2/application.js';
2
+ import { defineCommand } from '../../lib/define-command.js';
3
+ import { Logger } from '../../logger.js';
4
+ import * as Application from '../../models/application.js';
5
+ import { getDomainObject, getFavouriteDomain } from '../../models/domain.js';
6
+ import { sendToApi } from '../../models/send-to-api.js';
7
+ import { aliasOption, appIdOrNameOption, humanJsonOutputFormatOption } from '../global.options.js';
8
+
9
+ export const domainCommand = defineCommand({
10
+ description: 'Manage domain names for an application',
11
+ since: '0.2.0',
12
+ options: {
13
+ alias: aliasOption,
14
+ app: appIdOrNameOption,
15
+ format: humanJsonOutputFormatOption,
16
+ },
17
+ args: [],
18
+ async handler(options) {
19
+ const { alias, app: appIdOrName, format } = options;
20
+ const { ownerId, appId } = await Application.resolveId(appIdOrName, alias);
21
+
22
+ const app = await getApp({ id: ownerId, appId }).then(sendToApi);
23
+ const favouriteDomain = await getFavouriteDomain({ ownerId, appId });
24
+
25
+ const domains = app.vhosts.map((vhost) => getDomainObject(vhost.fqdn, favouriteDomain));
26
+
27
+ switch (format) {
28
+ case 'json':
29
+ Logger.printJson(domains);
30
+ break;
31
+ default:
32
+ domains.forEach((domain) => {
33
+ Logger.println(`${domain.isFavourite ? '* ' : ' '}${domain.domainWithPathPrefix}`);
34
+ });
35
+ break;
36
+ }
37
+ },
38
+ });
@@ -0,0 +1,204 @@
1
+ import { get as getApp } from '@clevercloud/client/esm/api/v2/application.js';
2
+ import { getDefaultLoadBalancersDnsInfo } from '@clevercloud/client/esm/api/v4/load-balancers.js';
3
+ import { diagDomainConfig } from '@clevercloud/client/esm/utils/diag-domain-config.js';
4
+ import { sortDomains } from '@clevercloud/client/esm/utils/domains.js';
5
+ import { parse as parseDomain } from 'tldts';
6
+ import { z } from 'zod';
7
+ import { defineCommand } from '../../lib/define-command.js';
8
+ import { defineOption } from '../../lib/define-option.js';
9
+ import { styleText } from '../../lib/style-text.js';
10
+ import { Logger } from '../../logger.js';
11
+ import * as Application from '../../models/application.js';
12
+ import { DnsResolver } from '../../models/node-dns-resolver.js';
13
+ import { sendToApi } from '../../models/send-to-api.js';
14
+ import { aliasOption, appIdOrNameOption, humanJsonOutputFormatOption } from '../global.options.js';
15
+
16
+ function reportDomainDiagnostics({ hostname, pathPrefix, resolvedDnsConfig, diagDetails, diagSummary }) {
17
+ const validDiags = diagDetails.filter((diag) => diag.code === 'valid-a');
18
+ const unknownDiags = diagDetails.filter((diag) => diag.code === 'unknown-a');
19
+ const missingDiags = diagDetails.filter((diag) => diag.code === 'missing-a');
20
+ const suggestedCname = diagDetails.find((diag) => diag.code === 'suggested-cname');
21
+ const missingCname = diagDetails.find((diag) => diag.code === 'missing-cname');
22
+ const unknownCname = diagDetails.find((diag) => diag.code === 'unknown-cname');
23
+
24
+ const hasARecords = resolvedDnsConfig.aRecords.length > 0;
25
+ const hasCnameRecord = resolvedDnsConfig.cnameRecords.length > 0;
26
+
27
+ Logger.println('\n' + styleText('blue', hostname) + styleText('yellow', pathPrefix) + '\n');
28
+
29
+ switch (diagSummary) {
30
+ case 'managed':
31
+ Logger.printlnWithIndent(styleText('green', '✔ Managed by Clever Cloud'), 2);
32
+ Logger.printlnWithIndent('ⓘ cleverapps.io domains should only be used for testing purposes', 2);
33
+ break;
34
+ case 'no-config':
35
+ Logger.printlnWithIndent(styleText('red', '✘ No DNS configuration found'), 2);
36
+ break;
37
+ case 'valid':
38
+ Logger.printlnWithIndent(styleText('green', '✔ Your configuration is valid'), 2);
39
+ break;
40
+ case 'invalid':
41
+ Logger.printlnWithIndent(styleText('red', '✘ Something is wrong with your configuration'), 2);
42
+ break;
43
+ case 'incomplete':
44
+ Logger.printlnWithIndent(styleText('yellow', '⚠ Your configuration is incomplete'), 2);
45
+ break;
46
+ }
47
+
48
+ // Valid records
49
+ if (validDiags.length > 0) {
50
+ Logger.println('');
51
+ validDiags.forEach((diag) => {
52
+ const source = hasCnameRecord ? `(from CNAME ${resolvedDnsConfig.cnameRecords[0]}.)` : '';
53
+ Logger.printlnWithIndent(`${diag.record.value} ${styleText('green', '✔ A Record OK')} ${source}`, 2);
54
+ });
55
+ }
56
+
57
+ // Replace A with CNAME
58
+ if (diagSummary === 'valid' && suggestedCname != null) {
59
+ Logger.println('');
60
+ Logger.printlnWithIndent('ⓘ You can replace your A records with this CNAME:', 2);
61
+ Logger.printlnWithIndent(suggestedCname.record.value, 6);
62
+ }
63
+
64
+ // Replace A Records with CNAME
65
+ if (missingCname != null && unknownCname == null && (diagSummary === 'invalid' || diagSummary === 'incomplete')) {
66
+ const cnameToUse = suggestedCname != null ? suggestedCname.record.value : missingCname.record.value;
67
+
68
+ Logger.println('');
69
+ Logger.printlnWithIndent('⇄ Replace your A records with this CNAME:', 2);
70
+ Logger.printlnWithIndent(cnameToUse, 6);
71
+ Logger.println('');
72
+ Logger.printlnWithIndent('or:', 2);
73
+ }
74
+
75
+ // Replace unknown CNAME with missing CNAME
76
+ if (diagSummary === 'invalid' && missingCname != null && unknownCname != null) {
77
+ Logger.println('');
78
+ Logger.printlnWithIndent('➖Remove this CNAME record:', 2);
79
+ Logger.printlnWithIndent(unknownCname.record.value + '. ', 6);
80
+ Logger.println('');
81
+ Logger.printlnWithIndent('➕Add this CNAME record instead:', 2);
82
+ Logger.printlnWithIndent(missingCname.record.value, 6);
83
+
84
+ if (hasARecords) {
85
+ Logger.println('');
86
+ Logger.printlnWithIndent('or:', 2);
87
+ }
88
+ }
89
+
90
+ // Add CNAME
91
+ if (diagSummary === 'no-config' && missingCname != null) {
92
+ Logger.println('');
93
+ Logger.printlnWithIndent('➕Add this CNAME record:', 2);
94
+ Logger.printlnWithIndent(missingCname.record.value, 6);
95
+ }
96
+
97
+ // Remove Unknown records
98
+ if (unknownDiags.length > 0) {
99
+ Logger.println('');
100
+ Logger.printlnWithIndent('➖Remove these A records:', 2);
101
+
102
+ unknownDiags.forEach((diag) => {
103
+ const source = hasCnameRecord ? `(from CNAME ${resolvedDnsConfig.cnameRecords[0]}.)` : '';
104
+ Logger.printlnWithIndent(`${diag.record.value} ${source}`, 6);
105
+ });
106
+ }
107
+
108
+ // Add missing A records
109
+ if (missingDiags.length > 0) {
110
+ Logger.println('');
111
+ Logger.printlnWithIndent('➕Add these A records:', 2);
112
+
113
+ missingDiags.forEach((missingDiag) => Logger.printlnWithIndent(missingDiag.record.value, 6));
114
+ }
115
+ }
116
+
117
+ function getParsedDomains(vhosts) {
118
+ return vhosts.map(({ fqdn }) => {
119
+ const { hostname, pathname } = new URL('https://' + fqdn);
120
+ const { subdomain } = parseDomain(fqdn);
121
+
122
+ return { hostname, pathPrefix: pathname, isApex: subdomain === '' };
123
+ });
124
+ }
125
+
126
+ export const domainDiagCommand = defineCommand({
127
+ description: 'Check if domains associated to a specific app are properly configured',
128
+ since: '3.9.0',
129
+ options: {
130
+ filter: defineOption({
131
+ name: 'filter',
132
+ schema: z.string().default(''),
133
+ description: 'Check only domains containing the provided text',
134
+ placeholder: 'text',
135
+ }),
136
+ alias: aliasOption,
137
+ app: appIdOrNameOption,
138
+ format: humanJsonOutputFormatOption,
139
+ },
140
+ args: [],
141
+ async handler(options) {
142
+ const dnsResolver = new DnsResolver();
143
+ const allDomainDiagnostics = [];
144
+ const { alias, app: appIdOrName, format, filter } = options;
145
+ const { ownerId, appId } = await Application.resolveId(appIdOrName, alias);
146
+ const hasDomainFilter = filter.length > 0;
147
+ let hasError = false;
148
+
149
+ const app = await getApp({ id: ownerId, appId }).then(sendToApi);
150
+ const expectedDnsForPublicLoadBalancer = await getDefaultLoadBalancersDnsInfo({ ownerId, appId }).then(sendToApi);
151
+
152
+ const loadBalancerDnsConfig = {
153
+ aRecords: expectedDnsForPublicLoadBalancer[0].dns.a,
154
+ cnameRecord: expectedDnsForPublicLoadBalancer[0].dns.cname,
155
+ };
156
+
157
+ const filteredDomains = app.vhosts.filter(({ fqdn }) => fqdn.includes(filter));
158
+ const domains = getParsedDomains(filteredDomains);
159
+ const sortedDomains = domains.sort(sortDomains);
160
+
161
+ for (const { hostname, pathPrefix, isApex } of sortedDomains) {
162
+ const resolvedDnsConfig = {
163
+ aRecords: await dnsResolver.resolveA(hostname),
164
+ cnameRecords: (await dnsResolver.resolveCname(hostname)) ?? [],
165
+ };
166
+
167
+ const diagnosticResults = diagDomainConfig(
168
+ {
169
+ hostname,
170
+ pathPrefix,
171
+ isApex,
172
+ },
173
+ resolvedDnsConfig,
174
+ loadBalancerDnsConfig,
175
+ );
176
+ allDomainDiagnostics.push({ ...diagnosticResults, resolvedDnsConfig });
177
+
178
+ if (diagnosticResults.diagSummary === 'invalid' || diagnosticResults.diagSummary === 'no-config') {
179
+ hasError = true;
180
+ }
181
+ }
182
+
183
+ switch (format) {
184
+ case 'json':
185
+ Logger.printJson(allDomainDiagnostics);
186
+ break;
187
+ default: {
188
+ allDomainDiagnostics.forEach((diag) => reportDomainDiagnostics(diag));
189
+
190
+ if (allDomainDiagnostics.length === 0 && !hasDomainFilter) {
191
+ Logger.println(`\nNo domain associated to the app "${app.name}" (${app.id})`);
192
+ }
193
+
194
+ if (allDomainDiagnostics.length === 0 && hasDomainFilter) {
195
+ Logger.println(`\nNo domain matches "${filter}" for the app "${app.name}" (${app.id})`);
196
+ }
197
+ }
198
+ }
199
+
200
+ if (hasError) {
201
+ throw new Error('At least one of the domains is misconfigured');
202
+ }
203
+ },
204
+ });
@@ -0,0 +1,143 @@
1
+ # 📖 `clever domain` command reference
2
+
3
+ ## ➡️ `clever domain` <kbd>Since 0.2.0</kbd>
4
+
5
+ Manage domain names for an application
6
+
7
+ ```bash
8
+ clever domain [options]
9
+ ```
10
+
11
+ ### ⚙️ Options
12
+
13
+ |Name|Description|
14
+ |---|---|
15
+ |`-a`, `--alias` `<alias>`|Short name for the application|
16
+ |`--app` `<app-id\|app-name>`|Application to manage by its ID (or name, if unambiguous)|
17
+ |`-F`, `--format` `<format>`|Output format (human, json) (default: human)|
18
+
19
+ ## ➡️ `clever domain add` <kbd>Since 0.2.0</kbd>
20
+
21
+ Add a domain name to an application
22
+
23
+ ```bash
24
+ clever domain add <fqdn> [options]
25
+ ```
26
+
27
+ ### 📥 Arguments
28
+
29
+ |Name|Description|
30
+ |---|---|
31
+ |`fqdn`|Domain name of the application|
32
+
33
+ ### ⚙️ Options
34
+
35
+ |Name|Description|
36
+ |---|---|
37
+ |`-a`, `--alias` `<alias>`|Short name for the application|
38
+ |`--app` `<app-id\|app-name>`|Application to manage by its ID (or name, if unambiguous)|
39
+
40
+ ## ➡️ `clever domain diag` <kbd>Since 3.9.0</kbd>
41
+
42
+ Check if domains associated to a specific app are properly configured
43
+
44
+ ```bash
45
+ clever domain diag [options]
46
+ ```
47
+
48
+ ### ⚙️ Options
49
+
50
+ |Name|Description|
51
+ |---|---|
52
+ |`-a`, `--alias` `<alias>`|Short name for the application|
53
+ |`--app` `<app-id\|app-name>`|Application to manage by its ID (or name, if unambiguous)|
54
+ |`--filter` `<text>`|Check only domains containing the provided text|
55
+ |`-F`, `--format` `<format>`|Output format (human, json) (default: human)|
56
+
57
+ ## ➡️ `clever domain favourite` <kbd>Since 2.7.0</kbd>
58
+
59
+ Manage the favourite domain name for an application
60
+
61
+ ```bash
62
+ clever domain favourite [options]
63
+ ```
64
+
65
+ ### ⚙️ Options
66
+
67
+ |Name|Description|
68
+ |---|---|
69
+ |`-a`, `--alias` `<alias>`|Short name for the application|
70
+ |`--app` `<app-id\|app-name>`|Application to manage by its ID (or name, if unambiguous)|
71
+ |`-F`, `--format` `<format>`|Output format (human, json) (default: human)|
72
+
73
+ ## ➡️ `clever domain favourite set` <kbd>Since 2.7.0</kbd>
74
+
75
+ Set the favourite domain for an application
76
+
77
+ ```bash
78
+ clever domain favourite set <fqdn> [options]
79
+ ```
80
+
81
+ ### 📥 Arguments
82
+
83
+ |Name|Description|
84
+ |---|---|
85
+ |`fqdn`|Domain name of the application|
86
+
87
+ ### ⚙️ Options
88
+
89
+ |Name|Description|
90
+ |---|---|
91
+ |`-a`, `--alias` `<alias>`|Short name for the application|
92
+ |`--app` `<app-id\|app-name>`|Application to manage by its ID (or name, if unambiguous)|
93
+
94
+ ## ➡️ `clever domain favourite unset` <kbd>Since 2.7.0</kbd>
95
+
96
+ Unset the favourite domain for an application
97
+
98
+ ```bash
99
+ clever domain favourite unset [options]
100
+ ```
101
+
102
+ ### ⚙️ Options
103
+
104
+ |Name|Description|
105
+ |---|---|
106
+ |`-a`, `--alias` `<alias>`|Short name for the application|
107
+ |`--app` `<app-id\|app-name>`|Application to manage by its ID (or name, if unambiguous)|
108
+
109
+ ## ➡️ `clever domain overview` <kbd>Since 3.9.0</kbd>
110
+
111
+ Get an overview of all your domains (all orgas, all apps)
112
+
113
+ ```bash
114
+ clever domain overview [options]
115
+ ```
116
+
117
+ ### ⚙️ Options
118
+
119
+ |Name|Description|
120
+ |---|---|
121
+ |`--filter` `<text>`|Get only domains containing the provided text|
122
+ |`-F`, `--format` `<format>`|Output format (human, json) (default: human)|
123
+
124
+ ## ➡️ `clever domain rm` <kbd>Since 0.2.0</kbd>
125
+
126
+ Remove a domain name from an application
127
+
128
+ ```bash
129
+ clever domain rm <fqdn> [options]
130
+ ```
131
+
132
+ ### 📥 Arguments
133
+
134
+ |Name|Description|
135
+ |---|---|
136
+ |`fqdn`|Domain name of the application|
137
+
138
+ ### ⚙️ Options
139
+
140
+ |Name|Description|
141
+ |---|---|
142
+ |`-a`, `--alias` `<alias>`|Short name for the application|
143
+ |`--app` `<app-id\|app-name>`|Application to manage by its ID (or name, if unambiguous)|
@@ -0,0 +1,35 @@
1
+ import { defineCommand } from '../../lib/define-command.js';
2
+ import { Logger } from '../../logger.js';
3
+ import * as Application from '../../models/application.js';
4
+ import { getDomainObject, getFavouriteDomain } from '../../models/domain.js';
5
+ import { aliasOption, appIdOrNameOption, humanJsonOutputFormatOption } from '../global.options.js';
6
+
7
+ export const domainFavouriteCommand = defineCommand({
8
+ description: 'Manage the favourite domain name for an application',
9
+ since: '2.7.0',
10
+ options: {
11
+ alias: aliasOption,
12
+ app: appIdOrNameOption,
13
+ format: humanJsonOutputFormatOption,
14
+ },
15
+ args: [],
16
+ async handler(options) {
17
+ const { alias, app: appIdOrName, format } = options;
18
+ const { ownerId, appId } = await Application.resolveId(appIdOrName, alias);
19
+
20
+ const favouriteDomain = await getFavouriteDomain({ ownerId, appId });
21
+
22
+ switch (format) {
23
+ case 'json':
24
+ const domain = getDomainObject(favouriteDomain, favouriteDomain);
25
+ Logger.printJson(domain);
26
+ break;
27
+ default:
28
+ if (favouriteDomain == null) {
29
+ return Logger.println('No favourite domain set');
30
+ }
31
+ Logger.println(favouriteDomain);
32
+ break;
33
+ }
34
+ },
35
+ });
@@ -0,0 +1,24 @@
1
+ import { markFavouriteDomain } from '@clevercloud/client/esm/api/v2/application.js';
2
+ import { defineCommand } from '../../lib/define-command.js';
3
+ import { Logger } from '../../logger.js';
4
+ import * as Application from '../../models/application.js';
5
+ import { sendToApi } from '../../models/send-to-api.js';
6
+ import { aliasOption, appIdOrNameOption } from '../global.options.js';
7
+ import { fqdnArg } from './domain.args.js';
8
+
9
+ export const domainFavouriteSetCommand = defineCommand({
10
+ description: 'Set the favourite domain for an application',
11
+ since: '2.7.0',
12
+ options: {
13
+ alias: aliasOption,
14
+ app: appIdOrNameOption,
15
+ },
16
+ args: [fqdnArg],
17
+ async handler(options, fqdn) {
18
+ const { alias, app: appIdOrName } = options;
19
+ const { ownerId, appId } = await Application.resolveId(appIdOrName, alias);
20
+
21
+ await markFavouriteDomain({ id: ownerId, appId }, { fqdn }).then(sendToApi);
22
+ Logger.println('Your favourite domain has been successfully set');
23
+ },
24
+ });
@@ -0,0 +1,23 @@
1
+ import { unmarkFavouriteDomain } from '@clevercloud/client/esm/api/v2/application.js';
2
+ import { defineCommand } from '../../lib/define-command.js';
3
+ import { Logger } from '../../logger.js';
4
+ import * as Application from '../../models/application.js';
5
+ import { sendToApi } from '../../models/send-to-api.js';
6
+ import { aliasOption, appIdOrNameOption } from '../global.options.js';
7
+
8
+ export const domainFavouriteUnsetCommand = defineCommand({
9
+ description: 'Unset the favourite domain for an application',
10
+ since: '2.7.0',
11
+ options: {
12
+ alias: aliasOption,
13
+ app: appIdOrNameOption,
14
+ },
15
+ args: [],
16
+ async handler(options) {
17
+ const { alias, app: appIdOrName } = options;
18
+ const { ownerId, appId } = await Application.resolveId(appIdOrName, alias);
19
+
20
+ await unmarkFavouriteDomain({ id: ownerId, appId }).then(sendToApi);
21
+ Logger.println('Favourite domain has been successfully unset');
22
+ },
23
+ });