@contentstack/cli-utilities 1.0.0 → 1.0.2

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.
@@ -8,15 +8,65 @@ const ENC_KEY = 'encryptionKey';
8
8
  const ENCRYPT_CONF = true;
9
9
  const CONFIG_NAME = 'contentstack_cli';
10
10
  const ENC_CONFIG_NAME = 'contentstack_cli_obfuscate';
11
+ const OLD_CONFIG_BACKUP_FLAG = 'isOldConfigBackup';
12
+ const xdgBasedir = require('xdg-basedir');
13
+ const path = require('path');
14
+ const os = require('os');
15
+ const uniqueString = require('unique-string');
16
+ const oldConfigDirectory = xdgBasedir.config || path.join(os.tmpdir(), uniqueString());
17
+ const pathPrefix = path.join('configstore', `${CONFIG_NAME}.json`);
18
+ const oldConfigPath = path.join(oldConfigDirectory, pathPrefix);
11
19
  class Config {
12
20
  constructor() {
13
21
  this.init();
22
+ this.importOldConfig();
14
23
  }
15
24
  init() {
16
25
  return ENCRYPT_CONF === true
17
26
  ? this.getEncryptedConfig()
18
27
  : this.getDecryptedConfig();
19
28
  }
29
+ importOldConfig() {
30
+ if (!this.get(OLD_CONFIG_BACKUP_FLAG)) {
31
+ try {
32
+ const oldConfigStoreData = this.getOldConfig();
33
+ if (oldConfigStoreData) {
34
+ this.setOldConfigStoreData(oldConfigStoreData, '');
35
+ this.removeOldConfigStoreFile();
36
+ }
37
+ }
38
+ catch (error) {
39
+ console.log("No data to be imported from Old config file");
40
+ }
41
+ this.set(OLD_CONFIG_BACKUP_FLAG, true);
42
+ }
43
+ }
44
+ // Recursive function to migrate from the old config
45
+ setOldConfigStoreData(data, _path = '') {
46
+ for (const key in data) {
47
+ const value = data[key];
48
+ const setPath = _path ? _path + '.' + key : key;
49
+ if (typeof (value) == "object") {
50
+ this.setOldConfigStoreData(value, setPath);
51
+ }
52
+ else {
53
+ this.set(setPath, value);
54
+ }
55
+ }
56
+ }
57
+ removeOldConfigStoreFile() {
58
+ if ((0, fs_1.existsSync)(oldConfigPath)) {
59
+ (0, fs_1.unlinkSync)(oldConfigPath); // NOTE remove old configstore file
60
+ }
61
+ }
62
+ getOldConfig() {
63
+ try {
64
+ return JSON.parse((0, fs_1.readFileSync)(oldConfigPath, 'utf8'));
65
+ }
66
+ catch (error) {
67
+ return undefined;
68
+ }
69
+ }
20
70
  fallbackInit() {
21
71
  return new conf_1.default({ configName: CONFIG_NAME, encryptionKey: ENC_KEY });
22
72
  }
@@ -55,8 +105,8 @@ class Config {
55
105
  // NOTE reading old code base encrypted file if exist
56
106
  try {
57
107
  const config = this.fallbackInit();
58
- const configData = this.getConfigDataAndUnlinkConfigFile(config);
59
- this.getEncryptedConfig(configData, true);
108
+ const oldConfigData = this.getConfigDataAndUnlinkConfigFile(config);
109
+ this.getEncryptedConfig(oldConfigData, true);
60
110
  }
61
111
  catch (error) {
62
112
  // console.trace(error.message)
@@ -66,8 +116,8 @@ class Config {
66
116
  try {
67
117
  if (skip === false) {
68
118
  const config = new conf_1.default({ configName: CONFIG_NAME });
69
- const configData = this.getConfigDataAndUnlinkConfigFile(config);
70
- this.getEncryptedConfig(configData, true);
119
+ const oldConfigData = this.getConfigDataAndUnlinkConfigFile(config);
120
+ this.getEncryptedConfig(oldConfigData, true);
71
121
  }
72
122
  else {
73
123
  getEncryptedDataElseFallBack();
@@ -93,8 +143,8 @@ class Config {
93
143
  try {
94
144
  const encryptionKey = this.getObfuscationKey();
95
145
  let config = new conf_1.default({ configName: CONFIG_NAME, encryptionKey });
96
- const configData = this.getConfigDataAndUnlinkConfigFile(config);
97
- this.getDecryptedConfig(configData); // NOTE NOTE reinitialize the config with old data and new decrypted file
146
+ const oldConfigData = this.getConfigDataAndUnlinkConfigFile(config);
147
+ this.getDecryptedConfig(oldConfigData); // NOTE NOTE reinitialize the config with old data and new decrypted file
98
148
  }
99
149
  catch (error) {
100
150
  // console.trace(error.message)
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ const crypto_1 = tslib_1.__importDefault(require("crypto"));
5
+ const defaultValues = {
6
+ typeIdentifier: "◈",
7
+ algorithm: "aes-192-cbc",
8
+ encryptionKey: "nF2ejRQcTv",
9
+ };
10
+ class NodeCrypto {
11
+ constructor(config = defaultValues) {
12
+ const { algorithm, encryptionKey, typeIdentifier } = config;
13
+ this.algorithm = algorithm;
14
+ this.typeIdentifier = typeIdentifier;
15
+ this.key = crypto_1.default.scryptSync(encryptionKey, "salt", 24);
16
+ }
17
+ encrypt(plainData) {
18
+ const iv = crypto_1.default.randomBytes(16);
19
+ const cipher = crypto_1.default.createCipheriv(this.algorithm, this.key, iv);
20
+ let data = plainData;
21
+ switch (typeof plainData) {
22
+ case "number":
23
+ data = `${String(plainData)}${this.typeIdentifier}number`;
24
+ break;
25
+ case "object":
26
+ data = `${JSON.stringify(plainData)}${this.typeIdentifier}object`;
27
+ break;
28
+ }
29
+ const encrypted = cipher.update(data, "utf8", "hex");
30
+ return [
31
+ encrypted + cipher.final("hex"),
32
+ Buffer.from(iv).toString("hex"),
33
+ ].join("|");
34
+ }
35
+ decrypt(encryptedData) {
36
+ const [encrypted, iv] = encryptedData.split("|");
37
+ if (!iv)
38
+ throw new Error("IV not found");
39
+ const decipher = crypto_1.default.createDecipheriv(this.algorithm, this.key, Buffer.from(iv, "hex"));
40
+ const result = decipher.update(encrypted, "hex", "utf8") + decipher.final("utf8");
41
+ const [data, type] = result.split(this.typeIdentifier);
42
+ switch (type) {
43
+ case "number":
44
+ return Number(data);
45
+ case "object":
46
+ return JSON.parse(data);
47
+ }
48
+ return data;
49
+ }
50
+ }
51
+ exports.default = NodeCrypto;
package/lib/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.printFlagDeprecation = exports.configHandler = exports.messageHandler = exports.CLIError = exports.cliux = exports.logger = void 0;
3
+ exports.chooseLocalePrompt = exports.NodeCrypto = exports.printFlagDeprecation = exports.configHandler = exports.messageHandler = exports.CLIError = exports.cliux = exports.logger = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  var logger_1 = require("./logger");
6
6
  Object.defineProperty(exports, "logger", { enumerable: true, get: function () { return tslib_1.__importDefault(logger_1).default; } });
@@ -15,3 +15,7 @@ Object.defineProperty(exports, "configHandler", { enumerable: true, get: functio
15
15
  var flag_deprecation_check_1 = require("./flag-deprecation-check");
16
16
  Object.defineProperty(exports, "printFlagDeprecation", { enumerable: true, get: function () { return tslib_1.__importDefault(flag_deprecation_check_1).default; } });
17
17
  tslib_1.__exportStar(require("./http-client"), exports);
18
+ var encrypter_1 = require("./encrypter");
19
+ Object.defineProperty(exports, "NodeCrypto", { enumerable: true, get: function () { return tslib_1.__importDefault(encrypter_1).default; } });
20
+ var selectors_1 = require("./selectors");
21
+ Object.defineProperty(exports, "chooseLocalePrompt", { enumerable: true, get: function () { return selectors_1.chooseLocale; } });
@@ -3,12 +3,49 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.chooseDeliveryTokenAlias = exports.chooseTokenAlias = exports.chooseLocale = exports.chooseLocales = exports.chooseEnvironment = exports.chooseEnvironments = exports.chooseContentTypes = exports.chooseEntry = exports.chooseContentType = exports.chooseStack = exports.chooseOrganization = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const ora_1 = tslib_1.__importDefault(require("ora"));
6
+ const cli_error_1 = tslib_1.__importDefault(require("../cli-error"));
6
7
  const config_handler_1 = tslib_1.__importDefault(require("../config-handler"));
7
8
  const validations_1 = require("./validations");
9
+ const management_1 = tslib_1.__importDefault(require("@contentstack/management"));
8
10
  const inquirer = require('inquirer');
9
11
  inquirer.registerPrompt('search-list', require('inquirer-search-list'));
10
12
  inquirer.registerPrompt('search-checkbox', require('inquirer-search-checkbox'));
11
- const { Command } = require('@contentstack/cli-command');
13
+ let _region;
14
+ let _authToken;
15
+ let _managementAPIClient;
16
+ const region = () => {
17
+ if (!_region) {
18
+ _region = config_handler_1.default.get('region');
19
+ }
20
+ return _region;
21
+ };
22
+ const cmaHost = () => {
23
+ let cma = region().cma;
24
+ if (cma.startsWith('http')) {
25
+ const u = new URL(cma);
26
+ if (u.host)
27
+ return u.host;
28
+ }
29
+ return cma;
30
+ };
31
+ const managementAPIClient = (params) => {
32
+ if (params) {
33
+ _managementAPIClient = management_1.default.client(params);
34
+ }
35
+ else if (!_managementAPIClient) {
36
+ _managementAPIClient = management_1.default.client({ host: cmaHost() });
37
+ }
38
+ return _managementAPIClient;
39
+ };
40
+ const authToken = () => {
41
+ if (!_authToken) {
42
+ _authToken = config_handler_1.default.get('authtoken');
43
+ }
44
+ if (!_authToken) {
45
+ throw new cli_error_1.default('You are not logged in. Please login with command $ csdx auth:login');
46
+ }
47
+ return _authToken;
48
+ };
12
49
  function chooseOrganization(client, displayMessage, region, orgUid) {
13
50
  return new Promise(async (resolve, reject) => {
14
51
  try {
@@ -81,9 +118,7 @@ function chooseStack(client, organizationId, displayMessage, region) {
81
118
  exports.chooseStack = chooseStack;
82
119
  function chooseContentType(stackApiKey, displayMessage, region) {
83
120
  return new Promise(async (resolve, reject) => {
84
- const command = new Command();
85
- command.managementAPIClient = { host: command.cmaHost, authtoken: command.authToken };
86
- const client = command.managementAPIClient;
121
+ const client = managementAPIClient({ host: cmaHost(), authtoken: authToken() });
87
122
  try {
88
123
  const spinner = (0, ora_1.default)('Loading Content Types').start();
89
124
  // let {items: contentTypes} = await client.stack({api_key: stackApiKey}).contentType().query({include_count: true}).find()
@@ -113,9 +148,7 @@ function chooseContentType(stackApiKey, displayMessage, region) {
113
148
  exports.chooseContentType = chooseContentType;
114
149
  function chooseEntry(contentTypeUid, stackApiKey, displayMessage, region) {
115
150
  return new Promise(async (resolve, reject) => {
116
- const command = new Command();
117
- command.managementAPIClient = { host: command.cmaHost, authtoken: command.authToken };
118
- const client = command.managementAPIClient;
151
+ const client = managementAPIClient({ host: cmaHost(), authtoken: authToken() });
119
152
  try {
120
153
  const spinner = (0, ora_1.default)('Loading Entries').start();
121
154
  let entries = await getAll(client.stack({ api_key: stackApiKey }).contentType(contentTypeUid).entry());
@@ -274,7 +307,7 @@ function chooseLocales(stack, displayMessage) {
274
307
  });
275
308
  }
276
309
  exports.chooseLocales = chooseLocales;
277
- function chooseLocale(stack, displayMessage) {
310
+ function chooseLocale(stack, displayMessage, defaultLocale) {
278
311
  return new Promise(async (resolve, reject) => {
279
312
  try {
280
313
  const spinner = (0, ora_1.default)('Loading Locales').start();
@@ -290,6 +323,7 @@ function chooseLocale(stack, displayMessage) {
290
323
  type: 'search-list',
291
324
  name: 'chosenLocale',
292
325
  choices: localeList,
326
+ default: defaultLocale,
293
327
  message: displayMessage || 'Choose locale',
294
328
  loop: false,
295
329
  validate: validations_1.shouldNotBeEmpty
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contentstack/cli-utilities",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "Utilities for contentstack projects",
5
5
  "main": "lib/index.js",
6
6
  "types": "./types/index.d.ts",
@@ -32,9 +32,13 @@
32
32
  "chalk": "^4.0.0",
33
33
  "conf": "^10.1.2",
34
34
  "debug": "^4.1.1",
35
- "inquirer": "^8.0.0",
35
+ "inquirer": "^8.2.4",
36
+ "inquirer-search-checkbox": "^1.0.0",
37
+ "inquirer-search-list": "^1.2.6",
36
38
  "ora": "^5.4.0",
37
- "winston": "^3.7.2"
39
+ "unique-string": "^2.0.0",
40
+ "winston": "^3.7.2",
41
+ "xdg-basedir": "^4.0.0"
38
42
  },
39
43
  "devDependencies": {
40
44
  "@oclif/plugin-help": "^5.1.12",
@@ -1,23 +1,78 @@
1
1
  import Conf from 'conf';
2
2
  import { v4 as uuid } from 'uuid';
3
- import { existsSync, unlinkSync } from 'fs'
3
+ import { existsSync, unlinkSync, readFileSync } from 'fs';
4
4
 
5
5
  const ENC_KEY = 'encryptionKey';
6
6
  const ENCRYPT_CONF: boolean = true
7
7
  const CONFIG_NAME = 'contentstack_cli';
8
8
  const ENC_CONFIG_NAME = 'contentstack_cli_obfuscate';
9
+ const OLD_CONFIG_BACKUP_FLAG = 'isOldConfigBackup'
10
+
11
+ const xdgBasedir = require('xdg-basedir');
12
+ const path = require('path');
13
+ const os = require('os');
14
+ const uniqueString = require('unique-string');
15
+ const oldConfigDirectory = xdgBasedir.config || path.join(os.tmpdir(), uniqueString());
16
+ const pathPrefix = path.join('configstore', `${CONFIG_NAME}.json`);
17
+ const oldConfigPath = path.join(oldConfigDirectory, pathPrefix);
9
18
 
10
19
  class Config {
11
20
  private config: Conf;
12
21
 
13
22
  constructor() {
14
23
  this.init()
24
+ this.importOldConfig()
15
25
  }
16
26
 
17
27
  init() {
18
28
  return ENCRYPT_CONF === true
19
29
  ? this.getEncryptedConfig()
20
30
  : this.getDecryptedConfig()
31
+
32
+ }
33
+
34
+ importOldConfig() {
35
+ if (!this.get(OLD_CONFIG_BACKUP_FLAG)) {
36
+ try {
37
+ const oldConfigStoreData = this.getOldConfig()
38
+ if (oldConfigStoreData) {
39
+ this.setOldConfigStoreData(oldConfigStoreData, '')
40
+ this.removeOldConfigStoreFile()
41
+ }
42
+ } catch (error) {
43
+ console.log("No data to be imported from Old config file");
44
+
45
+ }
46
+ this.set(OLD_CONFIG_BACKUP_FLAG, true)
47
+ }
48
+ }
49
+
50
+ // Recursive function to migrate from the old config
51
+ setOldConfigStoreData(data, _path = '') {
52
+ for (const key in data) {
53
+ const value = data[key];
54
+ const setPath = _path ? _path + '.' + key : key
55
+ if (typeof (value) == "object") {
56
+ this.setOldConfigStoreData(value, setPath)
57
+ }
58
+ else {
59
+ this.set(setPath, value)
60
+ }
61
+ }
62
+ }
63
+
64
+ removeOldConfigStoreFile() {
65
+ if (existsSync(oldConfigPath)) {
66
+ unlinkSync(oldConfigPath) // NOTE remove old configstore file
67
+ }
68
+ }
69
+
70
+ private getOldConfig() {
71
+ try {
72
+ return JSON.parse(readFileSync(oldConfigPath, 'utf8'));
73
+ } catch (error) {
74
+ return undefined;
75
+ }
21
76
  }
22
77
 
23
78
  private fallbackInit(): Conf {
@@ -64,8 +119,8 @@ class Config {
64
119
  // NOTE reading old code base encrypted file if exist
65
120
  try {
66
121
  const config = this.fallbackInit()
67
- const configData = this.getConfigDataAndUnlinkConfigFile(config)
68
- this.getEncryptedConfig(configData, true)
122
+ const oldConfigData = this.getConfigDataAndUnlinkConfigFile(config)
123
+ this.getEncryptedConfig(oldConfigData, true)
69
124
  } catch (error) {
70
125
  // console.trace(error.message)
71
126
  }
@@ -75,8 +130,8 @@ class Config {
75
130
  try {
76
131
  if (skip === false) {
77
132
  const config = new Conf({ configName: CONFIG_NAME })
78
- const configData = this.getConfigDataAndUnlinkConfigFile(config)
79
- this.getEncryptedConfig(configData, true)
133
+ const oldConfigData = this.getConfigDataAndUnlinkConfigFile(config)
134
+ this.getEncryptedConfig(oldConfigData, true)
80
135
  } else {
81
136
  getEncryptedDataElseFallBack()
82
137
  }
@@ -102,8 +157,8 @@ class Config {
102
157
  try {
103
158
  const encryptionKey: any = this.getObfuscationKey()
104
159
  let config = new Conf({ configName: CONFIG_NAME, encryptionKey })
105
- const configData = this.getConfigDataAndUnlinkConfigFile(config)
106
- this.getDecryptedConfig(configData) // NOTE NOTE reinitialize the config with old data and new decrypted file
160
+ const oldConfigData = this.getConfigDataAndUnlinkConfigFile(config)
161
+ this.getDecryptedConfig(oldConfigData) // NOTE NOTE reinitialize the config with old data and new decrypted file
107
162
  } catch (error) {
108
163
  // console.trace(error.message)
109
164
 
@@ -0,0 +1,70 @@
1
+ import crypto from "crypto";
2
+
3
+ type CryptoConfig = {
4
+ algorithm?: string;
5
+ encryptionKey?: string;
6
+ typeIdentifier?: string;
7
+ };
8
+
9
+ const defaultValues: CryptoConfig = {
10
+ typeIdentifier: "◈",
11
+ algorithm: "aes-192-cbc",
12
+ encryptionKey: "nF2ejRQcTv",
13
+ };
14
+
15
+ export default class NodeCrypto {
16
+ private readonly key: Buffer;
17
+ private readonly algorithm: string;
18
+ private readonly typeIdentifier: string;
19
+
20
+ constructor(config: CryptoConfig = defaultValues) {
21
+ const { algorithm, encryptionKey, typeIdentifier } = config;
22
+ this.algorithm = algorithm;
23
+ this.typeIdentifier = typeIdentifier;
24
+ this.key = crypto.scryptSync(encryptionKey, "salt", 24);
25
+ }
26
+
27
+ encrypt(plainData) {
28
+ const iv = crypto.randomBytes(16);
29
+ const cipher = crypto.createCipheriv(this.algorithm, this.key, iv);
30
+ let data = plainData;
31
+
32
+ switch (typeof plainData) {
33
+ case "number":
34
+ data = `${String(plainData)}${this.typeIdentifier}number`;
35
+ break;
36
+ case "object":
37
+ data = `${JSON.stringify(plainData)}${this.typeIdentifier}object`;
38
+ break;
39
+ }
40
+
41
+ const encrypted = cipher.update(data, "utf8", "hex");
42
+
43
+ return [
44
+ encrypted + cipher.final("hex"),
45
+ Buffer.from(iv).toString("hex"),
46
+ ].join("|");
47
+ }
48
+
49
+ decrypt(encryptedData) {
50
+ const [encrypted, iv] = encryptedData.split("|");
51
+ if (!iv) throw new Error("IV not found");
52
+ const decipher = crypto.createDecipheriv(
53
+ this.algorithm,
54
+ this.key,
55
+ Buffer.from(iv, "hex")
56
+ );
57
+ const result =
58
+ decipher.update(encrypted, "hex", "utf8") + decipher.final("utf8");
59
+ const [data, type] = result.split(this.typeIdentifier);
60
+
61
+ switch (type) {
62
+ case "number":
63
+ return Number(data);
64
+ case "object":
65
+ return JSON.parse(data);
66
+ }
67
+
68
+ return data;
69
+ }
70
+ }
package/src/index.ts CHANGED
@@ -5,3 +5,5 @@ export { default as messageHandler } from './message-handler';
5
5
  export { default as configHandler } from './config-handler';
6
6
  export { default as printFlagDeprecation } from './flag-deprecation-check';
7
7
  export * from './http-client';
8
+ export { default as NodeCrypto } from './encrypter'
9
+ export { chooseLocale as chooseLocalePrompt } from './selectors';
@@ -1,4 +1,5 @@
1
1
  import ora from 'ora'
2
+ import { default as CLIError } from '../cli-error';
2
3
  import { default as config } from '../config-handler';
3
4
  import {
4
5
  Token,
@@ -10,18 +11,66 @@ import {
10
11
  Entry,
11
12
  Locale
12
13
  } from './interfaces'
13
- import { shouldNotBeEmpty } from './validations';
14
+ import { shouldNotBeEmpty } from './validations';
15
+ import ContentstackManagementSDK from '@contentstack/management';
14
16
 
15
17
  const inquirer = require('inquirer')
16
18
  inquirer.registerPrompt('search-list', require('inquirer-search-list'))
17
19
  inquirer.registerPrompt('search-checkbox', require('inquirer-search-checkbox'))
18
- const {Command} = require('@contentstack/cli-command')
20
+
21
+ interface Region {
22
+ name: string;
23
+ cma: string;
24
+ cda: string;
25
+ }
26
+
27
+ let _region: Region;
28
+ let _authToken: string;
29
+ let _managementAPIClient: ContentstackManagementSDK.ContentstackClient;
30
+
31
+ const region = (): Region => {
32
+ if (!_region) {
33
+ _region = config.get('region');
34
+ }
35
+
36
+ return _region;
37
+ }
38
+
39
+ const cmaHost = () => {
40
+ let cma = region().cma;
41
+ if (cma.startsWith('http')) {
42
+ const u = new URL(cma);
43
+ if (u.host) return u.host;
44
+ }
45
+ return cma;
46
+ }
47
+
48
+ const managementAPIClient = (params) => {
49
+ if (params) {
50
+ _managementAPIClient = ContentstackManagementSDK.client(params)
51
+ } else if (!_managementAPIClient) {
52
+ _managementAPIClient = ContentstackManagementSDK.client({ host: cmaHost() });
53
+ }
54
+
55
+ return _managementAPIClient;
56
+ }
57
+
58
+ const authToken = () => {
59
+ if (!_authToken) {
60
+ _authToken = config.get('authtoken');
61
+ }
62
+ if (!_authToken) {
63
+ throw new CLIError('You are not logged in. Please login with command $ csdx auth:login');
64
+ }
65
+
66
+ return _authToken;
67
+ }
19
68
 
20
69
  export function chooseOrganization(client: any, displayMessage?: string, region?: string, orgUid?: string): Promise<selectedOrganization> {
21
70
  return new Promise(async (resolve, reject) => {
22
71
  try {
23
72
  const spinner = ora('Loading Organizations').start()
24
- let {items: organizations} = await client.organization().fetchAll()
73
+ let { items: organizations } = await client.organization().fetchAll()
25
74
  spinner.stop()
26
75
  let orgMap: any = {}
27
76
  if (orgUid) {
@@ -29,7 +78,7 @@ export function chooseOrganization(client: any, displayMessage?: string, region?
29
78
  orgMap[org.uid] = org.name
30
79
  })
31
80
  if (orgMap[orgUid]) {
32
- resolve({orgUid: orgUid, orgName: orgMap[orgUid]})
81
+ resolve({ orgUid: orgUid, orgName: orgMap[orgUid] })
33
82
  } else {
34
83
  return reject(new Error('The given orgUid doesn\'t exist or you might not have access to it.'))
35
84
  }
@@ -46,8 +95,8 @@ export function chooseOrganization(client: any, displayMessage?: string, region?
46
95
  loop: false,
47
96
  validate: shouldNotBeEmpty
48
97
  }
49
- inquirer.prompt(inquirerConfig).then(({chosenOrganization}: {chosenOrganization: string}) => {
50
- resolve({orgUid: orgMap[chosenOrganization], orgName: chosenOrganization})
98
+ inquirer.prompt(inquirerConfig).then(({ chosenOrganization }: { chosenOrganization: string }) => {
99
+ resolve({ orgUid: orgMap[chosenOrganization], orgName: chosenOrganization })
51
100
  })
52
101
  }
53
102
  } catch (error) {
@@ -56,11 +105,11 @@ export function chooseOrganization(client: any, displayMessage?: string, region?
56
105
  })
57
106
  }
58
107
 
59
- export function chooseStack(client: any, organizationId: string, displayMessage?: string, region?: string) : Promise<Stack> {
108
+ export function chooseStack(client: any, organizationId: string, displayMessage?: string, region?: string): Promise<Stack> {
60
109
  return new Promise(async (resolve, reject) => {
61
110
  try {
62
111
  const spinner = ora('Loading Stacks').start()
63
- let {items: stacks} = await client.stack({organization_uid: organizationId}).query({query: {}}).find()
112
+ let { items: stacks } = await client.stack({ organization_uid: organizationId }).query({ query: {} }).find()
64
113
  spinner.stop()
65
114
  let stackMap: any = {}
66
115
  stacks.forEach((stack: Stack) => {
@@ -74,8 +123,8 @@ export function chooseStack(client: any, organizationId: string, displayMessage?
74
123
  message: displayMessage || 'Choose a stack',
75
124
  loop: false,
76
125
  }
77
- inquirer.prompt(inquirerConfig).then(({chosenStack}: {chosenStack: string}) => {
78
- resolve({api_key: stackMap[chosenStack], name: chosenStack})
126
+ inquirer.prompt(inquirerConfig).then(({ chosenStack }: { chosenStack: string }) => {
127
+ resolve({ api_key: stackMap[chosenStack], name: chosenStack })
79
128
  })
80
129
  } catch (error) {
81
130
  console.error(error.message)
@@ -85,13 +134,12 @@ export function chooseStack(client: any, organizationId: string, displayMessage?
85
134
 
86
135
  export function chooseContentType(stackApiKey: string, displayMessage?: string, region?: string): Promise<ContentType> {
87
136
  return new Promise(async (resolve, reject) => {
88
- const command = new Command()
89
- command.managementAPIClient = {host: command.cmaHost, authtoken: command.authToken}
90
- const client = command.managementAPIClient
137
+ const client = managementAPIClient({ host: cmaHost(), authtoken: authToken() })
138
+
91
139
  try {
92
140
  const spinner = ora('Loading Content Types').start()
93
141
  // let {items: contentTypes} = await client.stack({api_key: stackApiKey}).contentType().query({include_count: true}).find()
94
- let contentTypes = await getAll(client.stack({api_key: stackApiKey}).contentType())
142
+ let contentTypes = await getAll(client.stack({ api_key: stackApiKey }).contentType())
95
143
  spinner.stop()
96
144
  let contentTypeMap: any = {}
97
145
  contentTypes.forEach((contentType: ContentType) => {
@@ -105,23 +153,22 @@ export function chooseContentType(stackApiKey: string, displayMessage?: string,
105
153
  message: displayMessage || 'Choose a content type',
106
154
  loop: false,
107
155
  }
108
- inquirer.prompt(inquirerConfig).then(({chosenContentType}: {chosenContentType: string}) => {
109
- resolve({uid: contentTypeMap[chosenContentType], title: chosenContentType})
156
+ inquirer.prompt(inquirerConfig).then(({ chosenContentType }: { chosenContentType: string }) => {
157
+ resolve({ uid: contentTypeMap[chosenContentType], title: chosenContentType })
110
158
  })
111
159
  } catch (error) {
112
160
  console.error(error.message)
113
161
  }
114
- })
162
+ })
115
163
  }
116
164
 
117
165
  export function chooseEntry(contentTypeUid: string, stackApiKey: string, displayMessage?: string, region?: string): Promise<Entry> {
118
166
  return new Promise(async (resolve, reject) => {
119
- const command = new Command()
120
- command.managementAPIClient = {host: command.cmaHost, authtoken: command.authToken}
121
- const client = command.managementAPIClient
167
+ const client = managementAPIClient({ host: cmaHost(), authtoken: authToken() })
168
+
122
169
  try {
123
170
  const spinner = ora('Loading Entries').start()
124
- let entries = await getAll(client.stack({api_key: stackApiKey}).contentType(contentTypeUid).entry())
171
+ let entries = await getAll(client.stack({ api_key: stackApiKey }).contentType(contentTypeUid).entry())
125
172
  spinner.stop()
126
173
  let entryMap: any = {}
127
174
  entries.forEach((entry: Entry) => {
@@ -135,13 +182,13 @@ export function chooseEntry(contentTypeUid: string, stackApiKey: string, display
135
182
  message: displayMessage || 'Choose an entry',
136
183
  loop: false
137
184
  }
138
- inquirer.prompt(inquirerConfig).then(({chosenEntry}: {chosenEntry: string}) => {
139
- resolve({uid: entryMap[chosenEntry], title: chosenEntry})
185
+ inquirer.prompt(inquirerConfig).then(({ chosenEntry }: { chosenEntry: string }) => {
186
+ resolve({ uid: entryMap[chosenEntry], title: chosenEntry })
140
187
  })
141
188
  } catch (error) {
142
189
  console.error(error.message)
143
190
  }
144
- })
191
+ })
145
192
  }
146
193
 
147
194
  export function chooseContentTypes(stack: any, displayMessage?: string): Promise<ContentType[]> {
@@ -163,7 +210,7 @@ export function chooseContentTypes(stack: any, displayMessage?: string): Promise
163
210
  message: displayMessage || 'Choose a content type',
164
211
  loop: false,
165
212
  }
166
- inquirer.prompt(inquirerConfig).then(({ chosenContentTypes }: { chosenContentTypes: string[]}) => {
213
+ inquirer.prompt(inquirerConfig).then(({ chosenContentTypes }: { chosenContentTypes: string[] }) => {
167
214
  let result: ContentType[] = chosenContentTypes.map(ct => {
168
215
  let foo: ContentType = { uid: contentTypeMap[ct], title: ct }
169
216
  return foo
@@ -173,7 +220,7 @@ export function chooseContentTypes(stack: any, displayMessage?: string): Promise
173
220
  } catch (error) {
174
221
  console.error(error.message)
175
222
  }
176
- })
223
+ })
177
224
  }
178
225
 
179
226
  export function chooseEnvironments(stack: any, displayMessage?: string): Promise<Environment[]> {
@@ -272,7 +319,7 @@ export function chooseLocales(stack: any, displayMessage?: string): Promise<Loca
272
319
  })
273
320
  }
274
321
 
275
- export function chooseLocale(stack: any, displayMessage?: string): Promise<Locale> {
322
+ export function chooseLocale(stack: any, displayMessage?: string, defaultLocale?: Locale): Promise<Locale> {
276
323
  return new Promise(async (resolve, reject) => {
277
324
  try {
278
325
  const spinner = ora('Loading Locales').start()
@@ -288,6 +335,7 @@ export function chooseLocale(stack: any, displayMessage?: string): Promise<Local
288
335
  type: 'search-list',
289
336
  name: 'chosenLocale',
290
337
  choices: localeList,
338
+ default: defaultLocale,
291
339
  message: displayMessage || 'Choose locale',
292
340
  loop: false,
293
341
  validate: shouldNotBeEmpty
@@ -338,7 +386,7 @@ export function chooseDeliveryTokenAlias(): Promise<Token> {
338
386
  })
339
387
  }
340
388
 
341
- async function getAll (element: any, skip: number=0): Promise<any> {
389
+ async function getAll(element: any, skip: number = 0): Promise<any> {
342
390
  return new Promise(async resolve => {
343
391
  let result: any[] = []
344
392
  result = await fetch(element, skip, result)
@@ -348,8 +396,8 @@ async function getAll (element: any, skip: number=0): Promise<any> {
348
396
 
349
397
  async function fetch(element: any, skip: number, accumulator: any[]): Promise<any[]> {
350
398
  return new Promise(async resolve => {
351
- let queryParams = {include_count: true, skip: skip}
352
- let {items: result, count: count} = await element.query(queryParams).find()
399
+ let queryParams = { include_count: true, skip: skip }
400
+ let { items: result, count: count } = await element.query(queryParams).find()
353
401
  accumulator = accumulator.concat(result)
354
402
  skip += result.length
355
403
  if (skip < count)
@@ -0,0 +1,14 @@
1
+ declare type CryptoConfig = {
2
+ algorithm?: string;
3
+ encryptionKey?: string;
4
+ typeIdentifier?: string;
5
+ };
6
+ export default class NodeCrypto {
7
+ private readonly key;
8
+ private readonly algorithm;
9
+ private readonly typeIdentifier;
10
+ constructor(config?: CryptoConfig);
11
+ encrypt(plainData: any): string;
12
+ decrypt(encryptedData: any): any;
13
+ }
14
+ export {};
@@ -0,0 +1,230 @@
1
+ import { AxiosRequestConfig, AxiosResponse } from 'axios';
2
+ import { HttpResponse } from './http-response';
3
+ export declare class HttpClient {
4
+ /**
5
+ * The request configuration.
6
+ */
7
+ private request;
8
+ /**
9
+ * The request configuration.
10
+ */
11
+ private readonly axiosInstance;
12
+ /**
13
+ * The payload format for a JSON or form-url-encoded request.
14
+ */
15
+ private bodyFormat;
16
+ /**
17
+ * Createa new pending HTTP request instance.
18
+ */
19
+ constructor();
20
+ /**
21
+ * Create a reusable HttpClient instance.
22
+ *
23
+ * @returns {HttpClient}
24
+ */
25
+ static create(): HttpClient;
26
+ /**
27
+ * Returns the Axios request config.
28
+ *
29
+ * @returns {AxiosRequestConfig}
30
+ */
31
+ requestConfig(): AxiosRequestConfig;
32
+ /**
33
+ * Resets the request config.
34
+ *
35
+ * @returns {AxiosRequestConfig}
36
+ */
37
+ resetConfig(): HttpClient;
38
+ /**
39
+ * Use the given `baseUrl` for all requests.
40
+ *
41
+ * @param {String} baseUrl
42
+ *
43
+ * @returns {HttpClient}
44
+ */
45
+ baseUrl(baseUrl: string): HttpClient;
46
+ /**
47
+ * Add request headers.
48
+ * @returns {HttpClient}
49
+ */
50
+ headers(headers: any): HttpClient;
51
+ /**
52
+ * Add query parameters to the request.
53
+ *
54
+ * @param {Object} queryParams
55
+ *
56
+ * @returns {HttpClient}
57
+ */
58
+ queryParams(queryParams: object): HttpClient;
59
+ /**
60
+ * Add basic authentication via `username` and `password` to the request.
61
+ *
62
+ * @param {String} username
63
+ * @param {String} password
64
+ *
65
+ * @returns {HttpClient}
66
+ */
67
+ basicAuth(username: string, password: string): HttpClient;
68
+ /**
69
+ * Add an authorization `token` to the request.
70
+ *
71
+ * @param {String} token
72
+ * @param {String} type
73
+ *
74
+ * @returns {HttpClient}
75
+ */
76
+ token(token: string, type?: string): HttpClient;
77
+ /**
78
+ * Merge your own custom Axios options into the request.
79
+ *
80
+ * @param {Object} options
81
+ *
82
+ * @returns {HttpClient}
83
+ */
84
+ options(options?: AxiosRequestConfig): HttpClient;
85
+ /**
86
+ * Add a request payload.
87
+ *
88
+ * @param {*} data
89
+ *
90
+ * @returns {HttpClient}
91
+ */
92
+ payload(data: any): HttpClient;
93
+ /**
94
+ * Define the request `timeout` in milliseconds.
95
+ *
96
+ * @param {Number} timeout
97
+ *
98
+ * @returns {HttpClient}
99
+ */
100
+ timeout(timeout: number): HttpClient;
101
+ /**
102
+ * Tell HttpClient to send the request as JSON payload.
103
+ *
104
+ * @returns {HttpClient}
105
+ */
106
+ asJson(): HttpClient;
107
+ /**
108
+ * Tell HttpClient to send the request as form parameters,
109
+ * encoded as URL query parameters.
110
+ *
111
+ * @returns {HttpClient}
112
+ */
113
+ asFormParams(): HttpClient;
114
+ /**
115
+ * Set the request payload format.
116
+ *
117
+ * @param {String} format
118
+ *
119
+ * @returns {HttpClient}
120
+ */
121
+ payloadFormat(format: BodyFormat): HttpClient;
122
+ /**
123
+ * Set the `Accept` request header. This indicates what
124
+ * content type the server should return.
125
+ *
126
+ * @param {String} accept
127
+ *
128
+ * @returns {HttpClient}
129
+ */
130
+ accept(accept: string): HttpClient;
131
+ /**
132
+ * Set the `Accept` request header to JSON. This indicates
133
+ * that the server should return JSON data.
134
+ *
135
+ * @param {String} accept
136
+ *
137
+ * @returns {HttpClient}
138
+ */
139
+ acceptJson(): HttpClient;
140
+ /**
141
+ * Set the `Content-Type` request header.
142
+ *
143
+ * @param {String} contentType
144
+ *
145
+ * @returns {HttpClient}
146
+ */
147
+ contentType(contentType: string): HttpClient;
148
+ /**
149
+ * Send an HTTP GET request, optionally with the given `queryParams`.
150
+ *
151
+ * @param {String} url
152
+ * @param {Object} queryParams
153
+ *
154
+ * @returns {HttpResponse}
155
+ *
156
+ * @throws
157
+ */
158
+ get<R>(url: string, queryParams?: object): Promise<HttpResponse<R>>;
159
+ /**
160
+ * Send an HTTP POST request, optionally with the given `payload`.
161
+ *
162
+ * @param {String} url
163
+ * @param {Object} payload
164
+ *
165
+ * @returns {HttpResponse}
166
+ *
167
+ * @throws
168
+ */
169
+ post<R>(url: string, payload?: any): Promise<HttpResponse<R>>;
170
+ /**
171
+ * Send an HTTP PUT request, optionally with the given `payload`.
172
+ *
173
+ * @param {String} url
174
+ * @param {Object} payload
175
+ *
176
+ * @returns {HttpResponse}
177
+ *
178
+ * @throws
179
+ */
180
+ put<R>(url: string, payload?: any): Promise<HttpResponse<R>>;
181
+ /**
182
+ * Send an HTTP PATCH request, optionally with the given `payload`.
183
+ *
184
+ * @param {String} url
185
+ * @param {Object} payload
186
+ *
187
+ * @returns {HttpResponse}
188
+ *
189
+ * @throws
190
+ */
191
+ patch<R>(url: string, payload?: any): Promise<HttpResponse<R>>;
192
+ /**
193
+ * Send an HTTP DELETE request, optionally with the given `queryParams`.
194
+ *
195
+ * @param {String} url
196
+ * @param {Object} queryParams
197
+ *
198
+ * @returns {HttpResponse}
199
+ *
200
+ * @throws
201
+ */
202
+ delete<R>(url: string, queryParams?: object): Promise<HttpResponse<R>>;
203
+ /**
204
+ * Send the HTTP request.
205
+ *
206
+ * @param {String} method
207
+ * @param {String} url
208
+ *
209
+ * @returns {HttpResponse}
210
+ *
211
+ * @throws
212
+ */
213
+ send<R>(method: HttpMethod, url: string): Promise<HttpResponse<R>>;
214
+ /**
215
+ * Create and send the HTTP request.
216
+ *
217
+ * @param {String} method
218
+ * @param {String} url
219
+ *
220
+ * @returns {Request}
221
+ */
222
+ createAndSendRequest(method: HttpMethod, url: string): Promise<AxiosResponse>;
223
+ /**
224
+ * Returns the request payload depending on the selected request payload format.
225
+ */
226
+ prepareRequestPayload(): any;
227
+ }
228
+ declare type BodyFormat = 'json' | 'formParams';
229
+ declare type HttpMethod = 'GET' | 'HEAD' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' | 'OPTIONS';
230
+ export {};
@@ -0,0 +1,37 @@
1
+ import { AxiosResponse } from 'axios';
2
+ export declare class HttpResponse<ResponseType = any> {
3
+ /**
4
+ * The Axios response object.
5
+ */
6
+ private readonly response;
7
+ /**
8
+ * Wrap the given Axios `response` into a new response instance.
9
+ *
10
+ * @param {AxiosResponse} response
11
+ */
12
+ constructor(response: AxiosResponse);
13
+ /**
14
+ * Returns the response status.
15
+ *
16
+ * @returns {Number}
17
+ */
18
+ get status(): number;
19
+ /**
20
+ * Returns the response payload. This method is an alias for `response.payload()`.
21
+ *
22
+ * @returns {*}
23
+ */
24
+ get data(): any;
25
+ /**
26
+ * Returns the response payload.
27
+ *
28
+ * @returns {*}
29
+ */
30
+ get payload(): any;
31
+ /**
32
+ * Returns the response headers.
33
+ *
34
+ * @returns {Object}
35
+ */
36
+ get headers(): import("axios").AxiosResponseHeaders;
37
+ }
@@ -0,0 +1,4 @@
1
+ import { HttpClient } from './client';
2
+ export default HttpClient;
3
+ export * from './client';
4
+ export * from './http-response';
package/types/index.d.ts CHANGED
@@ -5,3 +5,5 @@ export { default as messageHandler } from './message-handler';
5
5
  export { default as configHandler } from './config-handler';
6
6
  export { default as printFlagDeprecation } from './flag-deprecation-check';
7
7
  export * from './http-client';
8
+ export { default as NodeCrypto } from './encrypter';
9
+ export { chooseLocale as chooseLocalePrompt } from './selectors';
@@ -7,6 +7,6 @@ export declare function chooseContentTypes(stack: any, displayMessage?: string):
7
7
  export declare function chooseEnvironments(stack: any, displayMessage?: string): Promise<Environment[]>;
8
8
  export declare function chooseEnvironment(stack: any, displayMessage?: string): Promise<Environment>;
9
9
  export declare function chooseLocales(stack: any, displayMessage?: string): Promise<Locale[]>;
10
- export declare function chooseLocale(stack: any, displayMessage?: string): Promise<Locale>;
10
+ export declare function chooseLocale(stack: any, displayMessage?: string, defaultLocale?: Locale): Promise<Locale>;
11
11
  export declare function chooseTokenAlias(): Promise<Token>;
12
12
  export declare function chooseDeliveryTokenAlias(): Promise<Token>;