clever-tools 3.11.0 → 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.
package/bin/clever.js CHANGED
@@ -16,7 +16,7 @@ import * as Application from '../src/models/application.js';
16
16
  import { AVAILABLE_ZONES } from '../src/models/application.js';
17
17
  import { EXPERIMENTAL_FEATURES } from '../src/experimental-features.js';
18
18
  import { getExitOnOption, getOutputFormatOption, getSameCommitPolicyOption } from '../src/command-options.js';
19
- import { getFeatures } from '../src/models/configuration.js';
19
+ import { getFeatures, conf } from '../src/models/configuration.js';
20
20
 
21
21
  import * as Addon from '../src/models/addon.js';
22
22
  import * as ApplicationConfiguration from '../src/models/application_configuration.js';
@@ -44,6 +44,7 @@ import * as login from '../src/commands/login.js';
44
44
  import * as logout from '../src/commands/logout.js';
45
45
  import * as logs from '../src/commands/logs.js';
46
46
  import * as makeDefault from '../src/commands/makeDefault.js';
47
+ import * as ng from '../src/commands/ng.js';
47
48
  import * as notifyEmail from '../src/commands/notify-email.js';
48
49
  import * as open from '../src/commands/open.js';
49
50
  import * as consoleModule from '../src/commands/console.js';
@@ -56,6 +57,7 @@ import * as ssh from '../src/commands/ssh.js';
56
57
  import * as status from '../src/commands/status.js';
57
58
  import * as stop from '../src/commands/stop.js';
58
59
  import * as tcpRedirs from '../src/commands/tcp-redirs.js';
60
+ import * as tokens from '../src/commands/tokens.js';
59
61
  import * as unlink from '../src/commands/unlink.js';
60
62
  import * as version from '../src/commands/version.js';
61
63
  import * as webhooks from '../src/commands/webhooks.js';
@@ -94,6 +96,39 @@ async function run () {
94
96
  kvIdOrName: cliparse.argument('kv-id', {
95
97
  description: 'Add-on/Real ID (or name, if unambiguous) of a Materia KV or Redis® add-on',
96
98
  }),
99
+ apiTokenId: cliparse.argument('api-token-id', { description: 'API token ID' }),
100
+ apiTokenName: cliparse.argument('api-token-name', { description: 'API token name' }),
101
+ ngId: cliparse.argument('id', {
102
+ description: 'Network Group ID',
103
+ parser: Parsers.ngResourceType,
104
+ }),
105
+ ngLabel: cliparse.argument('ng-label', {
106
+ description: 'Network Group label',
107
+ parser: Parsers.ngResourceType,
108
+ }),
109
+ ngIdOrLabel: cliparse.argument('ng-id-or-label', {
110
+ description: 'Network Group ID or label',
111
+ parser: Parsers.ngResourceType,
112
+ }),
113
+ ngDescription: cliparse.argument('ng-description', {
114
+ description: 'Network Group description',
115
+ }),
116
+ ngExternalPeerLabel: cliparse.argument('external-peer-label', {
117
+ description: 'External peer label',
118
+ parser: Parsers.ngResourceType,
119
+ }),
120
+ ngExternalIdOrLabel: cliparse.argument('external-peer-id-or-label', {
121
+ description: 'External peer ID or label',
122
+ parser: Parsers.ngResourceType,
123
+ }),
124
+ ngAnyIdOrLabel: cliparse.argument('id-or-label', {
125
+ description: 'ID or Label of a Network group, a member or an (external) peer',
126
+ parser: Parsers.ngResourceType,
127
+ }),
128
+ wgPublicKey: cliparse.argument('public-key', {
129
+ metavar: 'public_key',
130
+ description: 'Wireguard public key of the external peer to link to a Network Group',
131
+ }),
97
132
  addonIdOrName: cliparse.argument('addon-id', {
98
133
  description: 'Add-on ID (or name, if unambiguous)',
99
134
  parser: Parsers.addonIdOrName,
@@ -147,6 +182,36 @@ async function run () {
147
182
 
148
183
  // OPTIONS
149
184
  const opts = {
185
+ apiTokenExpiration: cliparse.option('expiration', {
186
+ aliases: ['e'],
187
+ metavar: 'expiration',
188
+ parser: Parsers.futureDateOrDuration,
189
+ description: 'Duration until API token expiration (e.g.: 1h, 4d, 2w, 6M), default 1y',
190
+ }),
191
+ // Network Groups options
192
+ ngDescription: cliparse.option('description', {
193
+ metavar: 'description',
194
+ description: 'Network Group description',
195
+ }),
196
+ ngMembersIdsToLink: cliparse.option('link', {
197
+ metavar: 'members_ids',
198
+ description: "Comma separated list of members IDs to link to a Network Group ('app_xxx', 'addon_xxx', 'external_xxx')",
199
+ parser: Parsers.commaSeparated,
200
+ }),
201
+ ngMemberLabel: cliparse.option('label', {
202
+ required: false,
203
+ metavar: 'member_label',
204
+ description: 'The member label',
205
+ parser: Parsers.ngResourceType,
206
+ }),
207
+ ngPeerGetConfig: cliparse.flag('config', {
208
+ description: 'Get the Wireguard configuration of an external peer',
209
+ }),
210
+ ngResourceType: cliparse.option('type', {
211
+ metavar: 'type',
212
+ description: 'Type of resource to look for (NetworkGroup, Member, CleverPeer, ExternalPeer)',
213
+ parser: Parsers.ngValidType,
214
+ }),
150
215
  sourceableEnvVarsList: cliparse.flag('add-export', { description: 'Display sourceable env variables setting' }),
151
216
  logsFormat: getOutputFormatOption(['json-stream']),
152
217
  activityFormat: getOutputFormatOption(['json-stream']),
@@ -746,6 +811,56 @@ async function run () {
746
811
  args: [args.alias],
747
812
  }, makeDefault.makeDefault);
748
813
 
814
+ // NETWORK GROUP COMMANDS
815
+ const ngCreateExternalPeerCommand = cliparse.command('external', {
816
+ description: 'Create an external peer in a Network Group',
817
+ args: [args.ngExternalPeerLabel, args.ngIdOrLabel, args.wgPublicKey],
818
+ }, ng.createExternalPeer);
819
+ const ngDeleteExternalPeerCommand = cliparse.command('external', {
820
+ description: 'Delete an external peer from a Network Group',
821
+ args: [args.ngExternalIdOrLabel, args.ngIdOrLabel],
822
+ }, ng.deleteExternalPeer);
823
+ const ngCreateCommand = cliparse.command('create', {
824
+ description: 'Create a Network Group',
825
+ args: [args.ngLabel],
826
+ privateOptions: [opts.ngMembersIdsToLink, opts.ngDescription, opts.optTags],
827
+ commands: [ngCreateExternalPeerCommand],
828
+ }, ng.createNg);
829
+ const ngDeleteCommand = cliparse.command('delete', {
830
+ description: 'Delete a Network Group',
831
+ args: [args.ngIdOrLabel],
832
+ commands: [ngDeleteExternalPeerCommand],
833
+ }, ng.deleteNg);
834
+ const ngLinkCommand = cliparse.command('link', {
835
+ description: 'Link an application or a database add-on by its ID to a Network Group',
836
+ args: [args.ngAnyIdOrLabel, args.ngIdOrLabel],
837
+ }, ng.linkToNg);
838
+ const ngUnlinkCommand = cliparse.command('unlink', {
839
+ description: 'Unlink an application or a database add-on by its ID from a Network Group',
840
+ args: [args.ngAnyIdOrLabel, args.ngIdOrLabel],
841
+ }, ng.unlinkFromNg);
842
+ const ngGetCommand = cliparse.command('get', {
843
+ description: 'Get details about a Network Group, a member or a peer',
844
+ args: [args.ngAnyIdOrLabel],
845
+ options: [opts.ngResourceType, opts.humanJsonOutputFormat],
846
+ }, ng.get);
847
+ const ngGetConfigCommand = cliparse.command('get-config', {
848
+ description: 'Get the Wireguard configuration of a peer in a Network Group',
849
+ args: [args.ngExternalIdOrLabel, args.ngIdOrLabel],
850
+ options: [opts.humanJsonOutputFormat],
851
+ }, ng.getPeerConfig);
852
+ const ngSearchCommand = cliparse.command('search', {
853
+ description: 'Search Network Groups, members or peers and get their details',
854
+ args: [args.ngAnyIdOrLabel],
855
+ options: [opts.ngResourceType, opts.humanJsonOutputFormat],
856
+ }, ng.search);
857
+ const networkGroupsCommand = cliparse.command('ng', {
858
+ description: 'List Network Groups',
859
+ options: [opts.orgaIdOrName],
860
+ privateOptions: [opts.humanJsonOutputFormat],
861
+ commands: [ngCreateCommand, ngDeleteCommand, ngLinkCommand, ngUnlinkCommand, ngGetCommand, ngGetConfigCommand, ngSearchCommand],
862
+ }, ng.listNg);
863
+
749
864
  // NOTIFY-EMAIL COMMAND
750
865
  const addEmailNotificationCommand = cliparse.command('add', {
751
866
  description: 'Add a new email notification',
@@ -880,6 +995,22 @@ async function run () {
880
995
  commands: [tcpRedirsListNamespacesCommand, tcpRedirsAddCommand, tcpRedirsRemoveCommand],
881
996
  }, tcpRedirs.list);
882
997
 
998
+ // TOKENS COMMANDS
999
+ const apiTokenCreateCommand = cliparse.command('create', {
1000
+ description: 'Create an API token',
1001
+ args: [args.apiTokenName],
1002
+ options: [opts.apiTokenExpiration, opts.humanJsonOutputFormat],
1003
+ }, tokens.create);
1004
+ const apiTokenRevokeCommand = cliparse.command('revoke', {
1005
+ description: 'Revoke an API token',
1006
+ args: [args.apiTokenId],
1007
+ }, tokens.revoke);
1008
+ const tokensCommands = cliparse.command('tokens', {
1009
+ description: `Manage API tokens to query Clever Cloud API from ${conf.AUTH_BRIDGE_HOST}`,
1010
+ commands: [apiTokenCreateCommand, apiTokenRevokeCommand],
1011
+ privateOptions: [opts.humanJsonOutputFormat],
1012
+ }, tokens.list);
1013
+
883
1014
  // UNLINK COMMAND
884
1015
  const appUnlinkCommand = cliparse.command('unlink', {
885
1016
  description: 'Unlink this repo from an existing application',
@@ -982,6 +1113,14 @@ async function run () {
982
1113
  commands.push(colorizeExperimentalCommand(kvRawCommand, 'kv'));
983
1114
  }
984
1115
 
1116
+ if (featuresFromConf.tokens) {
1117
+ commands.push(colorizeExperimentalCommand(tokensCommands, 'tokens'));
1118
+ }
1119
+
1120
+ if (featuresFromConf.ng) {
1121
+ commands.push(colorizeExperimentalCommand(networkGroupsCommand, 'ng'));
1122
+ }
1123
+
985
1124
  // CLI PARSER
986
1125
  const cliParser = cliparse.cli({
987
1126
  name: 'clever',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clever-tools",
3
- "version": "3.11.0",
3
+ "version": "3.12.0",
4
4
  "description": "Command Line Interface for Clever Cloud.",
5
5
  "main": "bin/clever.js",
6
6
  "type": "module",
@@ -26,12 +26,13 @@
26
26
  "scripts/*.sh"
27
27
  ],
28
28
  "dependencies": {
29
- "@clevercloud/client": "9.1.0",
29
+ "@clevercloud/client": "9.2.0",
30
+ "@inquirer/prompts": "7.3.2",
30
31
  "cliparse": "0.5.0",
31
32
  "colors": "1.4.0",
32
33
  "common-env": "6.4.0",
33
34
  "curlconverter": "3.21.0",
34
- "duration-js": "4.0.0",
35
+ "dedent": "1.5.3",
35
36
  "eventsource": "1.1.0",
36
37
  "ioredis": "5.4.1",
37
38
  "iso8601-duration": "2.1.2",
@@ -0,0 +1,61 @@
1
+ export function createApiToken ({ email, password, mfaCode, name, description, expirationDate }) {
2
+ return Promise.resolve({
3
+ method: 'post',
4
+ url: '/api-tokens',
5
+ headers: { Accept: 'application/json', 'Content-Type': 'application/json' },
6
+ body: { email, password, mfaCode, name, description, expirationDate },
7
+ });
8
+ }
9
+
10
+ export function listApiTokens () {
11
+ return Promise.resolve({
12
+ method: 'get',
13
+ url: '/api-tokens',
14
+ headers: { Accept: 'application/json' },
15
+ });
16
+ }
17
+
18
+ export function updateApiToken (apiTokenId, { name, description }) {
19
+ return Promise.resolve({
20
+ method: 'put',
21
+ url: `/api-tokens/${apiTokenId}`,
22
+ headers: { Accept: 'application/json', 'Content-Type': 'application/json' },
23
+ body: { name, description },
24
+ });
25
+ }
26
+
27
+ export function deleteApiToken (apiTokenId) {
28
+ return Promise.resolve({
29
+ method: 'delete',
30
+ url: `/api-tokens/${apiTokenId}`,
31
+ headers: { Accept: 'application/json' },
32
+ });
33
+ }
34
+
35
+ export function addOauthHeaderPlaintext (tokens) {
36
+
37
+ return async function (requestParams) {
38
+
39
+ const authorizationHeader = (
40
+ 'OAuth '
41
+ + [
42
+ `oauth_consumer_key="${tokens.OAUTH_CONSUMER_KEY}"`,
43
+ `oauth_token="${tokens.API_OAUTH_TOKEN}"`,
44
+ // %26 is URL escaped character "&"
45
+ `oauth_signature="${tokens.OAUTH_CONSUMER_SECRET}%26${tokens.API_OAUTH_TOKEN_SECRET}"`,
46
+ // oauth_nonce is not mandatory
47
+ // oauth_signature_method is not mandatory, it defaults to PLAINTEXT
48
+ // oauth_timestamp is not mandatory
49
+ // oauth_version is not mandatory, it defaults to 1.0
50
+ ].join(', ')
51
+ );
52
+
53
+ return {
54
+ ...requestParams,
55
+ headers: {
56
+ authorization: authorizationHeader,
57
+ ...requestParams.headers,
58
+ },
59
+ };
60
+ };
61
+ }
@@ -0,0 +1,18 @@
1
+ // TODO: Move this to the Clever Cloud JS Client
2
+
3
+ /**
4
+ * GET /networkgroups/organisations/{ownerId}/networkgroups/search?query
5
+ * @param {Object} params
6
+ * @param {String} params.ownerId
7
+ * @param {String} params.query
8
+ */
9
+ export function searchNetworkGroupOrResource (params) {
10
+ // no multipath for /self or /organisations/{id}
11
+ return Promise.resolve({
12
+ method: 'get',
13
+ url: `/v4/networkgroups/organisations/${params.ownerId}/networkgroups/search`,
14
+ headers: { Accept: 'application/json' },
15
+ queryParams: { query: params.query },
16
+ // no body
17
+ });
18
+ }
@@ -12,6 +12,7 @@ import { sendToApi } from '../models/send-to-api.js';
12
12
  import { toNameEqualsValueString } from '@clevercloud/client/esm/utils/env-vars.js';
13
13
  import { resolveAddonId } from '../models/ids-resolver.js';
14
14
  import { conf } from '../models/configuration.js';
15
+ import dedent from 'dedent';
15
16
 
16
17
  const formatTable = initFormatTable();
17
18
 
@@ -124,42 +125,42 @@ function displayAddon (format, addon, providerName, message) {
124
125
  const WIP_PROVIDERS = {
125
126
  keycloak: {
126
127
  status: 'beta',
127
- postCreateInstructions: [
128
- `Learn more about Keycloak on Clever Cloud: ${conf.DOC_URL}/addons/keycloak/`,
129
- ].join('\n'),
128
+ postCreateInstructions: dedent`
129
+ Learn more about Keycloak on Clever Cloud: ${conf.DOC_URL}/addons/keycloak/,
130
+ `,
130
131
  },
131
132
  kv: {
132
133
  status: 'alpha',
133
- postCreateInstructions: [
134
- colors.yellow('You can easily use Materia KV with \'redis-cli\', with such commands:'),
135
- colors.blue(`source <(clever addon env ${addon.id} -F shell)`),
136
- colors.blue('redis-cli -h $KV_HOST -p $KV_PORT --tls'),
137
- `Learn more about Materia KV on Clever Cloud: ${conf.DOC_URL}/addons/materia-kv/`,
138
- ].join('\n'),
134
+ postCreateInstructions: dedent`
135
+ ${colors.yellow('You can easily use Materia KV with \'redis-cli\', with such commands:')}
136
+ ${colors.blue(`source <(clever addon env ${addon.id} -F shell)`)}
137
+ ${colors.blue('redis-cli -h $KV_HOST -p $KV_PORT --tls')}
138
+ Learn more about Materia KV on Clever Cloud: ${conf.DOC_URL}/addons/materia-kv/
139
+ `,
139
140
  },
140
141
  'addon-matomo': {
141
142
  status: 'beta',
142
- postCreateInstructions: [
143
- `Learn more about Matomo on Clever Cloud: ${conf.DOC_URL}/addons/matomo/`,
144
- ].join('\n'),
143
+ postCreateInstructions: dedent`
144
+ Learn more about Matomo on Clever Cloud: ${conf.DOC_URL}/addons/matomo/
145
+ `,
145
146
  },
146
147
  metabase: {
147
148
  status: 'beta',
148
- postCreateInstructions: [
149
- `Learn more about Metabase on Clever Cloud: ${conf.DOC_URL}/addons/metabase/`,
150
- ].join('\n'),
149
+ postCreateInstructions: dedent`
150
+ Learn more about Metabase on Clever Cloud: ${conf.DOC_URL}/addons/metabase/
151
+ `,
151
152
  },
152
153
  otoroshi: {
153
154
  status: 'beta',
154
- postCreateInstructions: [
155
- `Learn more about Otoroshi with LLM on Clever Cloud: ${conf.DOC_URL}/addons/otoroshi/`,
156
- ].join('\n'),
155
+ postCreateInstructions: dedent`
156
+ Learn more about Otoroshi with LLM on Clever Cloud: ${conf.DOC_URL}/addons/otoroshi/
157
+ `,
157
158
  },
158
159
  'addon-pulsar': {
159
160
  status: 'beta',
160
- postCreateInstructions: [
161
- `Learn more about Pulsar on Clever Cloud: ${conf.DOC_URL}/addons/pulsar/`,
162
- ].join('\n'),
161
+ postCreateInstructions: dedent`
162
+ Learn more about Pulsar on Clever Cloud: ${conf.DOC_URL}/addons/pulsar/
163
+ `,
163
164
  },
164
165
  };
165
166
 
@@ -1,4 +1,4 @@
1
- import * as application from '@clevercloud/client/esm/api/v2/application.js';
1
+ import { update as updateApplication } from '@clevercloud/client/esm/api/v2/application.js';
2
2
 
3
3
  import * as Application from '../models/application.js';
4
4
  import * as ApplicationConfiguration from '../models/application_configuration.js';
@@ -26,7 +26,7 @@ export async function set (params) {
26
26
  const config = ApplicationConfiguration.getById(configurationName);
27
27
 
28
28
  if (config != null) {
29
- const app = await application.update({ id: ownerId, appId }, { [config.name]: ApplicationConfiguration.parse(config, configurationValue) }).then(sendToApi);
29
+ const app = await updateApplication({ id: ownerId, appId }, { [config.name]: ApplicationConfiguration.parse(config, configurationValue) }).then(sendToApi);
30
30
 
31
31
  ApplicationConfiguration.printById(app, configurationName);
32
32
  }
@@ -41,7 +41,7 @@ export async function update (params) {
41
41
  throw new Error('No configuration to update');
42
42
  }
43
43
 
44
- const app = await application.update({ id: ownerId, appId }, options).then(sendToApi);
44
+ const app = await updateApplication({ id: ownerId, appId }, options).then(sendToApi);
45
45
 
46
46
  for (const configName of Object.keys(options)) {
47
47
  ApplicationConfiguration.printByName(app, configName);
@@ -1,9 +1,10 @@
1
1
  import { spawn } from 'node:child_process';
2
- import { loadOAuthConf, conf } from '../models/configuration.js';
2
+ import { conf, loadOAuthConf } from '../models/configuration.js';
3
3
  import { addOauthHeader } from '@clevercloud/client/esm/oauth.js';
4
4
  import { Logger } from '../logger.js';
5
5
  import colors from 'colors/safe.js';
6
6
  import curlconverter from 'curlconverter';
7
+ import dedent from 'dedent';
7
8
 
8
9
  async function loadTokens () {
9
10
  const tokens = await loadOAuthConf();
@@ -16,22 +17,21 @@ async function loadTokens () {
16
17
  }
17
18
 
18
19
  function printCleverCurlHelp () {
19
- const apiDocUrlv2 = `${conf.API_DOC_URL}/v2/`;
20
- const apiDocUrlv4 = `${conf.API_DOC_URL}/v4/`;
21
-
22
- Logger.println(`Usage: clever curl
23
- Query Clever Cloud's API using Clever Tools credentials. For example:
24
-
25
- clever curl ${conf.API_HOST}/v2/self
26
- clever curl ${conf.API_HOST}/v2/summary
27
- clever curl ${conf.API_HOST}/v4/products/zones
28
- clever curl ${conf.API_HOST}/v2/organisations/<ORGANISATION_ID>/applications | jq '.[].id'
29
- clever curl ${conf.API_HOST}/v4/billing/organisations/<ORGANISATION_ID>/<INVOICE_NUMBER>.pdf > invoice.pdf
30
-
31
- Our API documentation is available here :
32
-
33
- ${apiDocUrlv2}
34
- ${apiDocUrlv4}`);
20
+ Logger.println(dedent`
21
+ Usage: clever curl
22
+ Query Clever Cloud's API using Clever Tools credentials. For example:
23
+
24
+ clever curl ${conf.API_HOST}/v2/self
25
+ clever curl ${conf.API_HOST}/v2/summary
26
+ clever curl ${conf.API_HOST}/v4/products/zones
27
+ clever curl ${conf.API_HOST}/v2/organisations/<ORGANISATION_ID>/applications | jq '.[].id'
28
+ clever curl ${conf.API_HOST}/v4/billing/organisations/<ORGANISATION_ID>/<INVOICE_NUMBER>.pdf > invoice.pdf
29
+
30
+ Our API documentation is available here :
31
+
32
+ ${conf.API_DOC_URL}/v2/
33
+ ${conf.API_DOC_URL}/v4/
34
+ `);
35
35
  }
36
36
 
37
37
  export async function curl () {
@@ -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');
@@ -2,7 +2,7 @@ import Redis from 'ioredis';
2
2
  import colors from 'colors/safe.js';
3
3
  import { Logger } from '../logger.js';
4
4
  import { sendToApi } from '../models/send-to-api.js';
5
- import { getAllEnvVars } from '@clevercloud/client/cjs/api/v2/addon.js';
5
+ import { getAllEnvVars } from '@clevercloud/client/esm/api/v2/addon.js';
6
6
  import { findAddonsByNameOrId } from '../models/ids-resolver.js';
7
7
 
8
8
  const URL_ENV_KEY = 'REDIS_URL';
@@ -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
  }