Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@kasko/fe-toolbelt

Package Overview
Dependencies
Maintainers
10
Versions
74
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@kasko/fe-toolbelt - npm Package Compare versions

Comparing version 2.0.1 to 2.1.0

biome.json

5

CHANGELOG.md
# Changelog
## [v2.1.0](https://github.com/kasko/fe-toolbelt/compare/v2.0.1...v2.1.0) (2023-09-08)
## Feature
- Adds build step to minimize dependency count for webapps;
- Removes `canvas` dependency, it must be installed separately to use `graph` command;
## [v2.0.1](https://github.com/kasko/fe-toolbelt/compare/v2.0.0...v2.0.1) (2023-01-02)

@@ -3,0 +8,0 @@ ## Bugfix

2

jsconfig.json

@@ -17,4 +17,4 @@ {

"coverage",
"node_modules",
"node_modules"
]
}
{
"license": "UNLICENSED",
"name": "@kasko/fe-toolbelt",
"version": "2.0.1",
"version": "2.1.0",
"engines": {
"node": ">=8.11.x"
"node": ">=16"
},
"main": "src/app.js",
"main": "./dist/app.js",
"bin": {
"kasko-fe": "src/index.js",
"kk": "src/index.js"
"kasko-fe": "./dist/index.js",
"kk": "./dist/index.js"
},
"scripts": {
"start": "node src/index.js",
"lint": "eslint --ignore-path .gitignore .",
"test": "jest",
"test:watch": "jest --watch",
"test:ci": "npm run test -- --ci"
"build": "node scripts/build.js",
"start": "node dist/index.js",
"lint": "biome check src",
"test": "jest --ci",
"test:watch": "jest --watch"
},
"devDependencies": {
"@biomejs/biome": "^1.0.0",
"@kasko/webapp-flow-visualizer-lib": "^1.0.1",
"@types/jest": "^29.1.2",
"eslint": "^6.8.0",
"eslint-config-kasko-base": "^1.1.4",
"husky": "^3.0.5",
"jest": "^26.0.1",
"lint-staged": "^9.2.5",
"nock": "^11.3.3"
},
"dependencies": {
"@kasko/webapp-flow-visualizer-lib": "^1.0.1",
"archiver": "^3.1.1",
"axios": "^0.19.0",
"canvas": "^2.10.1",
"canvas": "^2.11.2",
"dotenv": "^8.1.0",
"esbuild": "^0.19.2",
"express": "^4.17.1",
"flat": "^5.0.1",
"form-data": "^2.5.1",
"fs-extra": "^8.1.0",
"getopts": "^2.2.3",
"js-yaml": "^3.13.1",
"marked": "^0.7.0",
"marked-terminal": "^3.3.0",
"ora": "^3.0.0"
"identity-obj-proxy": "^3.0.0",
"jest": "^26.0.1",
"js-yaml": "^4.1.0",
"msw": "^1.3.0",
"nanospinner": "^1.1.0"
},

@@ -48,15 +42,10 @@ "jest": {

"testEnvironment": "node",
"bail": true
},
"husky": {
"hooks": {
"pre-commit": "lint-staged"
"bail": true,
"setupFiles": [
"./test.setup.js"
],
"moduleNameMapper": {
"\\.md$": "identity-obj-proxy"
}
},
"lint-staged": {
"*.js": [
"yarn eslint --fix",
"git add"
]
}
}
/* This object contains aliases for flags
* e.g. `kasko-fe -v` === `kasko-fe -version` */
* e.g. `kasko-fe -v` === `kasko-fe -version` */
const alias = {

@@ -4,0 +4,0 @@ v: 'version',

@@ -21,23 +21,25 @@ const axios = require('../../axios');

*/
function assumeRole(
host,
accountId,
token,
) {
return axios.post(`https://api.${host}/v2/auth/assume_role`, {
role_name: 'KASKO/KaskoWebappDeploymentRole',
account_id: accountId,
}, {
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
},
}).then(
/**
* @param {{ data: APIAuthAssumeRoleResponse }} response
*/
(response) => response && response.data && response.data.token,
);
function assumeRole(host, accountId, token) {
return axios
.post(
`https://api.${host}/v2/auth/assume_role`,
{
role_name: 'KASKO/KaskoWebappDeploymentRole',
account_id: accountId,
},
{
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
},
},
)
.then(
/**
* @param {{ data: APIAuthAssumeRoleResponse }} response
*/
(response) => response?.data?.token,
);
}
module.exports = assumeRole;

@@ -8,6 +8,3 @@ const fs = require('fs');

const key = `${timestamp}|${location}`;
const hash = crypto
.createHash('md5')
.update(key)
.digest('hex');
const hash = crypto.createHash('md5').update(key).digest('hex');
const destination = `.tmp/app-${hash}.zip`;

@@ -14,0 +11,0 @@

@@ -22,20 +22,18 @@ const axios = require('../../axios');

*/
function deployRelease(
host,
pluginId,
fileId,
token,
version = undefined,
) {
return axios.post(`https://api.${host}/webapp_plugins/${pluginId}/code`, {
file_id: fileId,
version: normalizeVersionTag(version),
}, {
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
function deployRelease(host, pluginId, fileId, token, version = undefined) {
return axios.post(
`https://api.${host}/webapp_plugins/${pluginId}/code`,
{
file_id: fileId,
version: normalizeVersionTag(version),
},
});
{
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
},
},
);
}
module.exports = deployRelease;

@@ -10,12 +10,24 @@ const axios = require('../../axios');

*/
function deployWebapp(
host,
webappId,
fileId,
token,
) {
function deployWebapp(host, webappId, fileId, token) {
if (!webappId) {
return axios.post(`https://api.${host}/webapps`, {
return axios.post(
`https://api.${host}/webapps`,
{
file_id: fileId,
},
{
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
},
},
);
}
return axios.patch(
`https://api.${host}/webapps/${webappId}`,
{
file_id: fileId,
}, {
},
{
headers: {

@@ -25,15 +37,6 @@ Authorization: `Bearer ${token}`,

},
});
}
return axios.patch(`https://api.${host}/webapps/${webappId}`, {
file_id: fileId,
}, {
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
},
});
);
}
module.exports = deployWebapp;

@@ -1,3 +0,2 @@

/* eslint-disable no-continue,no-restricted-syntax,no-await-in-loop */
const ora = require('ora');
const { createSpinner } = require('nanospinner');
const yaml = require('js-yaml');

@@ -66,8 +65,12 @@ const fs = require('fs');

*/
async function deployV1({
plugin: name,
host = 'eu1.kaskocloud.com',
version,
'fail-on-existing-version': failOnExistingVersion = false,
} = { }, config) {
async function deployV1(
// rome-ignore lint/style/useDefaultParameterLast: <explanation>
{
plugin: name,
host = 'eu1.kaskocloud.com',
version,
'fail-on-existing-version': failOnExistingVersion = false,
} = {},
config,
) {
const plugins = Object.keys(config.plugins).map((pluginName) => ({

@@ -88,3 +91,3 @@ ...config.plugins[pluginName],

for (const plugin of filteredPlugins) {
const spinner = ora(`Deploying ${plugin.name}`).start();
const spinner = createSpinner(`Deploying ${plugin.name}`).start();
let fileId;

@@ -102,3 +105,3 @@

await deployRelease(host, plugin.id, fileId, token, version);
spinner.succeed(`Deployed ${plugin.name}`);
spinner.success({ text: `Deployed ${plugin.name}` });

@@ -109,3 +112,3 @@ if (fileId) {

} catch (e) {
spinner.fail(`Failed deploying ${plugin.name}`);
spinner.error({ text: `Failed deploying ${plugin.name}` });

@@ -123,3 +126,3 @@ if (fileId) {

if (e.response && e.response.request) {
if (e.response?.request) {
print(` ${e.response.status} ${e.response.request.method} ${e.response.request.path}`);

@@ -140,7 +143,11 @@ }

*/
async function deployV2({
plugin: name,
host = 'eu1.kaskocloud.com',
'fail-on-existing-version': failOnExistingVersion = false,
} = { }, config) {
async function deployV2(
// rome-ignore lint/style/useDefaultParameterLast: <explanation>
{
plugin: name,
host = 'eu1.kaskocloud.com',
'fail-on-existing-version': failOnExistingVersion = false,
} = {},
config,
) {
const plugins = Object.keys(config.plugins).map((pluginName) => ({

@@ -164,3 +171,3 @@ ...config.plugins[pluginName],

const buildLocation = path.join(plugin.build_location, 'products', plugin.product_id, 'webapp');
const spinner = ora(`Deploying ${plugin.name}`).start();
const spinner = createSpinner(`Deploying ${plugin.name}`).start();
let fileId;

@@ -182,3 +189,8 @@

if (!product.data.has_subproducts) {
const contentsLocation = path.join(plugin.build_location, 'products', plugin.product_id, 'contents.json');
const contentsLocation = path.join(
plugin.build_location,
'products',
plugin.product_id,
'contents.json',
);
await updateContents(host, plugin.product_id, undefined, contentsLocation, token);

@@ -196,3 +208,4 @@ }

const subProductsLocation = path.join(manifestsLocation, 'sub_products');
const subProducts = fs.readdirSync(subProductsLocation, 'utf-8')
const subProducts = fs
.readdirSync(subProductsLocation, 'utf-8')
.filter((filePath) => filePath.startsWith('spr_'));

@@ -230,4 +243,10 @@

const integrationsLocation = path.join(plugin.build_location, 'products', plugin.product_id, 'integrations');
const integrations = fs.readdirSync(integrationsLocation, 'utf-8')
const integrationsLocation = path.join(
plugin.build_location,
'products',
plugin.product_id,
'integrations',
);
const integrations = fs
.readdirSync(integrationsLocation, 'utf-8')
.filter((filePath) => filePath.startsWith('in_'));

@@ -239,9 +258,3 @@

await updateIntegration(
host,
plugin.product_id,
integrationId,
integrationPath,
token,
);
await updateIntegration(host, plugin.product_id, integrationId, integrationPath, token);
}

@@ -260,3 +273,3 @@

spinner.succeed(`Deployed ${plugin.name}`);
spinner.success({ text: `Deployed ${plugin.name}` });

@@ -267,3 +280,3 @@ if (fileId) {

} catch (e) {
spinner.fail(`Failed deploying ${plugin.name}`);
spinner.error({ text: `Failed deploying ${plugin.name}` });

@@ -281,3 +294,3 @@ if (fileId) {

if (e.response && e.response.request) {
if (e.response?.request) {
print(` ${e.response.status} ${e.response.request.method} ${e.response.request.path}`);

@@ -297,3 +310,3 @@ }

*/
function deploy(flags = { }) {
function deploy(flags = {}) {
if (!process.env.KASKO_PRIVATE_KEY) {

@@ -308,3 +321,3 @@ throw new Error('KASKO_PRIVATE_KEY environment variable must be set');

/** @type {KaskoConfig} */
const config = yaml.safeLoad(fs.readFileSync('kasko.yaml', 'utf8'));
const config = yaml.load(fs.readFileSync('kasko.yaml', 'utf8'));

@@ -322,3 +335,4 @@ switch (config.version) {

default: break;
default:
break;
}

@@ -328,1 +342,2 @@ }

module.exports = deploy;
module.exports.readme = require('./readme.md');

@@ -10,19 +10,15 @@ const axios = require('../../axios');

*/
async function getContents(
host,
productId,
subProductId,
token,
) {
async function getContents(host, productId, subProductId, token) {
try {
const subProductChunk = subProductId
? `/subproducts/${subProductId}`
: '';
const subProductChunk = subProductId ? `/subproducts/${subProductId}` : '';
return await axios.get(`https://api.${host}/v2/products/${productId}${subProductChunk}/contents`, {
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
return await axios.get(
`https://api.${host}/v2/products/${productId}${subProductChunk}/contents`,
{
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
},
},
});
);
} catch (e) {

@@ -29,0 +25,0 @@ return null;

@@ -9,7 +9,3 @@ const axios = require('../../axios');

*/
function getProductInfo(
host,
productId,
token,
) {
function getProductInfo(host, productId, token) {
return axios.get(`https://api.${host}/v2/products/${productId}`, {

@@ -16,0 +12,0 @@ headers: {

@@ -15,9 +15,3 @@ const fs = require('fs');

*/
async function updateContents(
host,
productId,
subProductId,
contentsLocation,
token,
) {
async function updateContents(host, productId, subProductId, contentsLocation, token) {
let data;

@@ -32,5 +26,3 @@

const subProductChunk = subProductId
? `/subproducts/${subProductId}`
: '';
const subProductChunk = subProductId ? `/subproducts/${subProductId}` : '';

@@ -40,5 +32,22 @@ const existingContents = await getContents(host, productId, subProductId, token);

if (!existingContents) {
return axios.post(`https://api.${host}/v2/products/${productId}${subProductChunk}/contents`, {
return axios.post(
`https://api.${host}/v2/products/${productId}${subProductChunk}/contents`,
{
data,
},
{
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
},
},
);
}
return axios.patch(
`https://api.${host}/v2/products/${productId}${subProductChunk}/contents`,
{
data,
}, {
},
{
headers: {

@@ -48,15 +57,6 @@ Authorization: `Bearer ${token}`,

},
});
}
return axios.patch(`https://api.${host}/v2/products/${productId}${subProductChunk}/contents`, {
data,
}, {
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
},
});
);
}
module.exports = updateContents;

@@ -13,9 +13,3 @@ const fs = require('fs');

*/
async function updateIntegration(
host,
productId,
integrationId,
integrationPath,
token,
) {
async function updateIntegration(host, productId, integrationId, integrationPath, token) {
let data;

@@ -30,10 +24,14 @@

return axios.patch(`https://api.${host}/v2/products/${productId}/integrations/${integrationId}`, data, {
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
return axios.patch(
`https://api.${host}/v2/products/${productId}/integrations/${integrationId}`,
data,
{
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
},
},
});
);
}
module.exports = updateIntegration;

@@ -10,8 +10,3 @@ const axios = require('../../axios');

*/
function updateProduct(
host,
productId,
data,
token,
) {
function updateProduct(host, productId, data, token) {
return axios.patch(`https://api.${host}/v2/products/${productId}`, data, {

@@ -18,0 +13,0 @@ headers: {

@@ -11,17 +11,15 @@ const axios = require('../../axios');

*/
function updateSubProduct(
host,
productId,
subProductId,
data,
token,
) {
return axios.patch(`https://api.${host}/v2/products/${productId}/subproducts/${subProductId}`, data, {
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
function updateSubProduct(host, productId, subProductId, data, token) {
return axios.patch(
`https://api.${host}/v2/products/${productId}/subproducts/${subProductId}`,
data,
{
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
},
},
});
);
}
module.exports = updateSubProduct;
const fs = require('fs');
const FormData = require('form-data');
const axios = require('../../axios');
const kaskoFetch = require('../../kasko-fetch');
/**

@@ -12,13 +12,15 @@ * @param {string} host

function uploadZip(host, file, token) {
const data = new FormData();
data.append('file', fs.createReadStream(file));
const body = new FormData();
const blob = new Blob([fs.readFileSync(file)]);
body.append('file', blob, file);
return axios.post(`https://upload.${host}/uploads`, data, {
return kaskoFetch('https://upload.${host}/uploads', {
method: 'POST',
body,
headers: {
Authorization: `Bearer ${token}`,
...data.getHeaders(),
},
}).then((response) => response.data.id);
}).then((data) => data.id);
}
module.exports = uploadZip;

@@ -10,8 +10,9 @@ const axios = require('../../axios');

const url = `${kaskoConfig.feApiUrl}/touchpoints/${kaskoConfig.touchpointId}/items/${item.id}`;
const { data } = await axios.get(url, {
params: {
language: kaskoConfig.language,
key: kaskoConfig.publicKey,
},
})
const { data } = await axios
.get(url, {
params: {
language: kaskoConfig.language,
key: kaskoConfig.publicKey,
},
})
.catch((error) => {

@@ -18,0 +19,0 @@ throw error;

@@ -15,10 +15,11 @@ const axios = require('../../axios');

const url = `${kaskoConfig.feApiUrl}/integrations/${kaskoConfig.touchpointId}`;
const { data } = await axios.get(url, {
params: {
language: kaskoConfig.language,
key: kaskoConfig.publicKey,
product_version: kaskoConfig.productVersionId,
integration_version: kaskoConfig.integrationVersionId,
},
})
const { data } = await axios
.get(url, {
params: {
language: kaskoConfig.language,
key: kaskoConfig.publicKey,
product_version: kaskoConfig.productVersionId,
integration_version: kaskoConfig.integrationVersionId,
},
})
.catch((error) => {

@@ -25,0 +26,0 @@ throw error;

@@ -10,10 +10,11 @@ const axios = require('../../axios');

const url = `${kaskoConfig.feApiUrl}/integrations/${kaskoConfig.touchpointId}/subproducts/${item.id}`;
const { data } = await axios.get(url, {
params: {
language: kaskoConfig.language,
key: kaskoConfig.publicKey,
product_version: kaskoConfig.productVersionId,
integration_version: kaskoConfig.integrationVersionId,
},
})
const { data } = await axios
.get(url, {
params: {
language: kaskoConfig.language,
key: kaskoConfig.publicKey,
product_version: kaskoConfig.productVersionId,
integration_version: kaskoConfig.integrationVersionId,
},
})
.catch((error) => {

@@ -20,0 +21,0 @@ throw error;

@@ -15,8 +15,9 @@ const axios = require('../../axios');

const url = `${kaskoConfig.feApiUrl}/touchpoints/${kaskoConfig.touchpointId}`;
const { data } = await axios.get(url, {
params: {
language: kaskoConfig.language,
key: kaskoConfig.publicKey,
},
})
const { data } = await axios
.get(url, {
params: {
language: kaskoConfig.language,
key: kaskoConfig.publicKey,
},
})
.catch((error) => {

@@ -23,0 +24,0 @@ throw error;

@@ -11,25 +11,24 @@ const KASKO_CONFIG_REGEX = /window\.kaskoConfig = {([^}]+)/;

if (!(configText && configText.trim())) {
if (!configText?.trim()) {
throw new Error('Webapp config could not be loaded');
}
const config = configText
.split(KASKO_CONFIG_SEPARATOR_REGEX)
.reduce((acc, chunk) => {
const [key, ...value] = chunk.split(':');
const trimmedKey = key.trim();
const config = configText.split(KASKO_CONFIG_SEPARATOR_REGEX).reduce((acc, chunk) => {
const [key, ...value] = chunk.split(':');
const trimmedKey = key.trim();
if (!trimmedKey) {
return acc;
}
if (!trimmedKey) {
return acc;
}
const normalizedValue = value.join(':')
.trim()
.replace(/^[']|[']$/g, '"')
.replace(/^kqsLang$/g, '"en"');
const normalizedValue = value
.join(':')
.trim()
.replace(/^[']|[']$/g, '"')
.replace(/^kqsLang$/g, '"en"');
acc[trimmedKey] = JSON.parse(normalizedValue);
acc[trimmedKey] = JSON.parse(normalizedValue);
return acc;
}, {});
return acc;
}, {});

@@ -36,0 +35,0 @@ return config;

@@ -12,9 +12,8 @@ const axios = require('../../axios');

async function getWebappData(url) {
const { data } = await axios.get(url)
.catch((error) => {
throw error;
});
const { data } = await axios.get(url).catch((error) => {
throw error;
});
if (typeof data !== 'string' || !data) {
throw new Error('Webapp couldn\'t be loaded');
throw new Error("Webapp couldn't be loaded");
}

@@ -24,8 +23,10 @@

if (!(
kaskoConfig.touchpointId
&& kaskoConfig.publicKey
&& kaskoConfig.feApiUrl
&& kaskoConfig.language
)) {
if (
!(
kaskoConfig.touchpointId &&
kaskoConfig.publicKey &&
kaskoConfig.feApiUrl &&
kaskoConfig.language
)
) {
throw new Error('Unsupported webapp configuration');

@@ -32,0 +33,0 @@ }

@@ -1,6 +0,4 @@

/* eslint-disable no-restricted-syntax */
const { build } = require('@kasko/webapp-flow-visualizer-lib');
const { createCanvas } = require('canvas');
const fs = require('fs');
const ora = require('ora');
const { createSpinner } = require('nanospinner');

@@ -26,10 +24,22 @@ const getItem = require('./getItem');

*/
async function graph({
format = 'png',
fontSize = undefined,
silent = false,
output = 'verbose',
fromCli = false,
file = false,
} = {}, attributes) {
async function graph(
// rome-ignore lint/style/useDefaultParameterLast: <explanation>
{
format = 'png',
fontSize = undefined,
silent = false,
output = 'verbose',
fromCli = false,
file = false,
} = {},
attributes,
) {
let nodeCanvas;
try {
// @ts-ignore
nodeCanvas = require('canvas');
} catch (e) {
throw new Error('Install "canvas" package to use `graph` command!');
}
const showVerboseOutput = output !== 'verbose' || !fromCli || silent;

@@ -39,3 +49,3 @@

* @param {string} text
* @returns {ora.Ora}
* @returns {import('nanospinner').Spinner}
*/

@@ -46,4 +56,4 @@ function spin(text) {

const mock = {
succeed: () => {},
fail: () => {},
success: () => {},
error: () => {},
text: null,

@@ -55,6 +65,6 @@ };

return ora(text).start();
return createSpinner(text).start();
}
/** @type {ora.Ora} */
/** @type {import('nanospinner').Spinner} */
let spinner;

@@ -66,26 +76,33 @@

spinner.succeed();
spinner.success();
spinner = spin(`Loading webapp items ${response.reduce((acc, webapp) => acc + webapp.touchpointData.items.length, 0)}`);
spinner = spin(
`Loading webapp items ${response.reduce(
(acc, webapp) => acc + webapp.touchpointData.items.length,
0,
)}`,
);
const responseItems = await Promise.all(response.map((webapp) => (
webapp.touchpointData.items.map((item) => {
if (/^ins_/.test(item.id)) {
return getSubProduct(webapp.kaskoConfig, item)
.then((itemData) => ({
const responseItems = await Promise.all(
response
.map((webapp) =>
webapp.touchpointData.items.map((item) => {
if (/^ins_/.test(item.id)) {
return getSubProduct(webapp.kaskoConfig, item).then((itemData) => ({
...webapp,
itemData,
}));
}
return getItem(webapp.kaskoConfig, item).then((itemData) => ({
...webapp,
itemData,
}));
}
}),
)
.flat(2),
);
return getItem(webapp.kaskoConfig, item)
.then((itemData) => ({
...webapp,
itemData,
}));
})
)).flat(2));
spinner.success();
spinner.succeed();
const results = [];

@@ -95,3 +112,3 @@ for (const webapp of responseItems) {

const canvas = createCanvas(0, 0, format === 'png' ? undefined : format);
const canvas = nodeCanvas.createCanvas(0, 0, format === 'png' ? undefined : format);
const data = build(

@@ -110,3 +127,3 @@ canvas,

spinner.succeed();
spinner.success();

@@ -122,3 +139,3 @@ if (output === 'json' && fromCli) {

fs.writeFileSync(fileName, data);
spinner.succeed();
spinner.success();
}

@@ -131,1 +148,2 @@ }

module.exports = graph;
module.exports.readme = require('./readme.md');

@@ -1,7 +0,5 @@

const fs = require('fs');
const path = require('path');
const print = require('../../helpers/print');
const getDocs = require('../../helpers/get-docs');
const docs = global.ESBUILD ? require('../index?nocache') : require('../index');
const docs = getDocs(path.resolve(__dirname, '../../../src/commands'));
const readme = require('./readme.md');

@@ -13,3 +11,2 @@ /**

*/
// eslint-disable-next-line no-unused-vars
function help(flags = {}, [originalCommand] = []) {

@@ -22,3 +19,3 @@ let command = originalCommand;

const docsContent = fs.readFileSync(docs[command], 'utf8');
const docsContent = docs[command]?.readme || readme;

@@ -25,0 +22,0 @@ return print(docsContent);

require('dotenv').config();
const ora = require('ora');
const { createSpinner } = require('nanospinner');
const get = require('./get-data');

@@ -9,2 +9,20 @@ const writeTouchpoint = require('./write-touchpoint');

/**
*
* @param {Promise<any>} promise
* @param {string} text
* @returns
*/
function spinPromise(promise, text) {
const spinner = createSpinner(text).start();
try {
promise.then(() => spinner.success()).catch(() => spinner.error());
} catch (e) {
spinner.error();
}
return spinner;
}
async function download({

@@ -15,3 +33,3 @@ host = 'eu1.kaskocloud.com',

language = process.env.WEBAPP_LANGUAGE,
} = { }) {
} = {}) {
// Validate

@@ -35,3 +53,3 @@ if (!key) {

});
ora.promise(downloadTouchpointAction, 'Downloading Touchpoint');
spinPromise(downloadTouchpointAction, 'Downloading Touchpoint');
const touchpoint = await downloadTouchpointAction;

@@ -41,18 +59,23 @@

const writeTouchpointAction = writeTouchpoint(touchpoint);
ora.promise(writeTouchpointAction, 'Writing Touchpoint');
spinPromise(writeTouchpointAction, 'Writing Touchpoint');
await writeTouchpointAction;
// Download and write all items (in parallel)
await Promise.all(touchpoint.items.map(async ({ id: itemId }) => {
const downloadItemAction = get(`https://feapi.${host}/touchpoints/${touchpointId}/items/${itemId}`, {
language,
key,
});
ora.promise(downloadItemAction, `Downloading Item: ${itemId}`);
const item = await downloadItemAction;
await Promise.all(
touchpoint.items.map(async ({ id: itemId }) => {
const downloadItemAction = get(
`https://feapi.${host}/touchpoints/${touchpointId}/items/${itemId}`,
{
language,
key,
},
);
spinPromise(downloadItemAction, `Downloading Item: ${itemId}`);
const item = await downloadItemAction;
const writeItemAction = writeItem(item);
ora.promise(writeItemAction, `Writing Item: ${itemId}`);
return writeItemAction;
}));
const writeItemAction = writeItem(item);
spinPromise(writeItemAction, `Writing Item: ${itemId}`);
return writeItemAction;
}),
);

@@ -68,7 +91,10 @@ // Download and write all claims settings (in parallel)

try {
const downloadClaimAction = get(`https://feapi.${host}/touchpoints/${touchpointId}/items/${itemId}/claim_settings`, {
language,
key,
});
ora.promise(downloadClaimAction, `Downloading Claims: ${itemId}`);
const downloadClaimAction = get(
`https://feapi.${host}/touchpoints/${touchpointId}/items/${itemId}/claim_settings`,
{
language,
key,
},
);
spinPromise(downloadClaimAction, `Downloading Claims: ${itemId}`);
claim = await downloadClaimAction;

@@ -85,3 +111,3 @@ } catch (e) {

const writeClaimAction = writeClaims(itemId, claim);
ora.promise(writeClaimAction, `Writing Claims: ${itemId}`);
spinPromise(writeClaimAction, `Writing Claims: ${itemId}`);
return writeClaimAction;

@@ -88,0 +114,0 @@ }),

@@ -10,5 +10,3 @@ const axios = require('../../axios');

} catch (e) {
throw new Error(
`${e.response.status} ${e.response.statusText}`,
);
throw new Error(`${e.response.status} ${e.response.statusText}`);
}

@@ -15,0 +13,0 @@ }

@@ -26,1 +26,2 @@ const download = require('./download');

module.exports = run;
module.exports.readme = require('./readme.md');

@@ -14,9 +14,16 @@ const fs = require('fs-extra');

const claim = { ...data };
claim.field_definition = { };
claim.manifest = { };
claim.content = { };
claim.field_definition = {};
claim.manifest = {};
claim.content = {};
promises.push(fs.writeFile(`${path}/claim.json`, `${JSON.stringify(claim, null, 2)}\n`));
promises.push(fs.writeFile(`${path}/manifest.json`, `${JSON.stringify(data.manifest, null, 2)}\n`));
promises.push(fs.writeFile(`${path}/field-definitions.json`, `${JSON.stringify(data.field_definition, null, 2)}\n`));
promises.push(
fs.writeFile(`${path}/manifest.json`, `${JSON.stringify(data.manifest, null, 2)}\n`),
);
promises.push(
fs.writeFile(
`${path}/field-definitions.json`,
`${JSON.stringify(data.field_definition, null, 2)}\n`,
),
);

@@ -23,0 +30,0 @@ return Promise.all(promises);

@@ -10,12 +10,26 @@ const fs = require('fs-extra');

const promises = [];
promises.push(fs.writeFile(`mock-api/resources/${data.id}/contents.csv`, `${jsonToCsv(data.content.data)}\n`));
promises.push(
fs.writeFile(`mock-api/resources/${data.id}/contents.csv`, `${jsonToCsv(data.content.data)}\n`),
);
const item = { ...data };
item.field_definition = { };
item.webapp_manifest = { };
item.content.data = { };
item.field_definition = {};
item.webapp_manifest = {};
item.content.data = {};
promises.push(fs.writeFile(`mock-api/resources/${data.id}/item.json`, `${JSON.stringify(item, null, 2)}\n`));
promises.push(fs.writeFile(`mock-api/resources/${data.id}/webapp-manifest.json`, `${JSON.stringify(data.webapp_manifest, null, 2)}\n`));
promises.push(fs.writeFile(`mock-api/resources/${data.id}/field-definitions.json`, `${JSON.stringify(data.field_definition, null, 2)}\n`));
promises.push(
fs.writeFile(`mock-api/resources/${data.id}/item.json`, `${JSON.stringify(item, null, 2)}\n`),
);
promises.push(
fs.writeFile(
`mock-api/resources/${data.id}/webapp-manifest.json`,
`${JSON.stringify(data.webapp_manifest, null, 2)}\n`,
),
);
promises.push(
fs.writeFile(
`mock-api/resources/${data.id}/field-definitions.json`,
`${JSON.stringify(data.field_definition, null, 2)}\n`,
),
);

@@ -22,0 +36,0 @@ return Promise.all(promises);

@@ -6,9 +6,18 @@ const fs = require('fs-extra');

const promises = [];
promises.push(fs.writeFile('mock-api/resources/touchpoint-contents.csv', `${jsonToCsv(data.content.data)}\n`));
promises.push(fs.writeFile('mock-api/resources/touchpoint-webapp-manifest.json', `${JSON.stringify(data.webapp_manifest, null, 2)}\n`));
promises.push(
fs.writeFile('mock-api/resources/touchpoint-contents.csv', `${jsonToCsv(data.content.data)}\n`),
);
promises.push(
fs.writeFile(
'mock-api/resources/touchpoint-webapp-manifest.json',
`${JSON.stringify(data.webapp_manifest, null, 2)}\n`,
),
);
const tp = { ...data };
tp.webapp_manifest = { };
tp.content.data = { };
promises.push(fs.writeFile('mock-api/resources/touchpoint.json', `${JSON.stringify(tp, null, 2)}\n`));
tp.webapp_manifest = {};
tp.content.data = {};
promises.push(
fs.writeFile('mock-api/resources/touchpoint.json', `${JSON.stringify(tp, null, 2)}\n`),
);

@@ -15,0 +24,0 @@ return Promise.all(promises);

const promiseChunks = require('../../utils/translations/promiseChunks');
const getItemManifest = require('./getItemManifest');

@@ -9,3 +10,3 @@

* @param {{batchSize: number, delayMs: number, spinner: Function}} options
* @returns {Promise<{}>}
* @returns {Promise<Record<string, *>[]>}
*/

@@ -18,9 +19,10 @@ async function getAllItemManifests(url, params, items, options) {

items,
({ id }) => getItemManifest(url, params, id)
// Middleware for checking if task finished or failed
.then((data) => {
itemsFinished += 1;
spinner(`Getting item data [${itemsFinished}/${items.length}]`);
return data;
}),
({ id }) =>
getItemManifest(url, params, id)
// Middleware for checking if task finished or failed
.then((data) => {
itemsFinished += 1;
spinner(`Getting item data [${itemsFinished}/${items.length}]`);
return data;
}),
chunkOptions,

@@ -27,0 +29,0 @@ );

@@ -1,2 +0,2 @@

const axios = require('../../axios');
const kaskoFetch = require('../../kasko-fetch');

@@ -7,9 +7,6 @@ /**

* @param {string} item
* @returns {Promise<{}>}
* @returns {Promise<Record<string, *>>}
*/
async function getItemManifest(url, params, item) {
const { data } = await axios.get(`${url}/items/${item}`, { params })
.catch((error) => {
throw error;
});
const data = await kaskoFetch(`${url}/items/${item}`, { method: 'get' }, params);

@@ -16,0 +13,0 @@ if (!data) {

@@ -1,2 +0,2 @@

const axios = require('../../axios');
const kaskoFetch = require('../../kasko-fetch');
const extractPaths = require('../../utils/translations/extractPaths');

@@ -7,9 +7,8 @@

* @param {Object.<string, *>} params
* @returns {Promise<{productName: string, touchpointTranslations: {}, items: []}>}
* @returns {Promise<{productName: string, touchpointTranslations: Record<string, *>, items: [], webappManifest: Record<string, *>}>}
*/
async function getTouchpointData(url, params) {
const { data } = await axios.get(url, { params })
.catch((error) => {
throw error;
});
const data = await kaskoFetch(url, {}, params).catch((error) => {
throw error;
});

@@ -16,0 +15,0 @@ if (!data) {

@@ -1,2 +0,2 @@

const ora = require('ora');
const { createSpinner } = require('nanospinner');

@@ -19,6 +19,3 @@ const getPartial = require('../../helpers/get-partial');

const leadTranslations = [
'flow.start.link',
'flow.error_used_lead.title',
];
const leadTranslations = ['flow.start.link', 'flow.error_used_lead.title'];

@@ -32,4 +29,4 @@ const REQUEST_SPECIFIC_REQUIRED_TRANSLATIONS = {

/**
* @param {{}} flags
* @param {string[]} attributes
* @param {Record<string, any>} flags
* @param {string[]=} attributes
* @returns {Promise<Output>}

@@ -51,3 +48,4 @@ */

if (typeof key === 'undefined') throw new Error('Translations: flag `key` must be defined.');
if (['verbose', 'json'].indexOf(output) < 0) throw new Error('Translations: flag `output` supports only "verbose" and "json".');
if (['verbose', 'json'].indexOf(output) < 0)
throw new Error('Translations: flag `output` supports only "verbose" and "json".');

@@ -60,4 +58,4 @@ const showVerboseOutput = output !== 'verbose' || !fromCli || silent;

return {
succeed: () => {},
fail: () => {},
success: () => {},
error: () => {},
text: null,

@@ -67,3 +65,3 @@ };

return ora(text).start();
return createSpinner(text).start();
}

@@ -78,14 +76,11 @@

const {
productName,
touchpointTranslations,
items,
webappManifest,
} = await getTouchpointData(url, requestParams)
.catch((error) => {
spinner.fail();
throw error;
});
const { productName, touchpointTranslations, items, webappManifest } = await getTouchpointData(
url,
requestParams,
).catch((error) => {
spinner.error();
throw error;
});
spinner.succeed();
spinner.success();
spinner = spin(`Getting item data [0/${items.length}]`);

@@ -98,3 +93,3 @@

if (value === false) {
spinner.fail();
spinner.error();
return;

@@ -105,83 +100,74 @@ }

},
})
.catch((error) => {
spinner.fail();
throw error;
});
}).catch((error) => {
spinner.error();
throw error;
});
spinner.succeed();
spinner.success();
spinner = spin('Preparing data');
const itemList = itemManifests.reduce(
(acc, item) => {
const activeRequests = (((item.webapp_manifest.schema || {}).config || {}).requests || []);
const requestSpecificTranslations = activeRequests.map(({ type }) => type).reduce(
(requestAcc, requestName) => {
const keys = REQUEST_SPECIFIC_REQUIRED_TRANSLATIONS[requestName];
if (!keys) return requestAcc;
const itemList = itemManifests.reduce((acc, item) => {
const activeRequests = item.webapp_manifest.schema?.config?.requests || [];
const requestSpecificTranslations = activeRequests
.map(({ type }) => type)
.reduce((requestAcc, requestName) => {
const keys = REQUEST_SPECIFIC_REQUIRED_TRANSLATIONS[requestName];
if (!keys) return requestAcc;
return requestAcc.concat(keys);
},
[],
);
const existingItemTranslations = extractPaths(item.content.data);
const fieldDefinitions = extractFieldDefinitions(item.field_definition)
.concat(...activeRequests.map(extractFieldDefinitions));
const itemAndTouchpointTranslations = touchpointTranslations
.concat(
existingItemTranslations.filter((itemKey) => touchpointTranslations.indexOf(itemKey) < 0),
);
const usedTranslations = [...new Set(
return requestAcc.concat(keys);
}, []);
const existingItemTranslations = extractPaths(item.content.data);
const fieldDefinitions = extractFieldDefinitions(item.field_definition).concat(
...activeRequests.map(extractFieldDefinitions),
);
const itemAndTouchpointTranslations = touchpointTranslations.concat(
existingItemTranslations.filter((itemKey) => touchpointTranslations.indexOf(itemKey) < 0),
);
const usedTranslations = [
...new Set(
extractContentKeys(item.webapp_manifest)
.concat(
extractContentKeys(webappManifest),
)
.concat(extractContentKeys(webappManifest))
.concat(requiredDefaults)
.concat(requestSpecificTranslations)
.concat(fieldDefinitions),
)];
const {
missingTranslations,
idleTranslations,
} = usedTranslations
.reduce(
(itemAcc, itemKey) => {
const value = getPartial(itemKey.split('.'), item.content.data);
),
];
const { missingTranslations, idleTranslations } = usedTranslations.reduce(
(itemAcc, itemKey) => {
const value = getPartial(itemKey.split('.'), item.content.data);
if (itemKey === value || value === '') {
return {
...itemAcc,
idleTranslations: itemAcc.idleTranslations.concat(itemKey),
};
}
if (itemKey === value || value === '') {
return {
...itemAcc,
idleTranslations: itemAcc.idleTranslations.concat(itemKey),
};
}
if (itemAndTouchpointTranslations.indexOf(itemKey) < 0) {
return {
...itemAcc,
missingTranslations: itemAcc.missingTranslations.concat(itemKey),
};
}
if (itemAndTouchpointTranslations.indexOf(itemKey) < 0) {
return {
...itemAcc,
missingTranslations: itemAcc.missingTranslations.concat(itemKey),
};
}
return itemAcc;
},
{
missingTranslations: [],
idleTranslations: [],
},
);
return itemAcc;
},
{
missingTranslations: [],
idleTranslations: [],
},
);
return {
...acc,
[item.id]: {
contentId: item.content.id,
missingTranslations,
idleTranslations,
usedTranslations,
fieldDefinitions,
existingTranslations: itemAndTouchpointTranslations,
},
};
},
{},
);
return {
...acc,
[item.id]: {
contentId: item.content.id,
missingTranslations,
idleTranslations,
usedTranslations,
fieldDefinitions,
existingTranslations: itemAndTouchpointTranslations,
},
};
}, {});

@@ -205,3 +191,3 @@ const summaryTemplate = {

spinner.succeed();
spinner.success();

@@ -261,2 +247,3 @@ print();

module.exports = translations;
module.exports.readme = require('./readme.md');

@@ -263,0 +250,0 @@ /**

const getopts = require('getopts');
const alias = require('../alias');

@@ -11,14 +12,7 @@

});
const [
firstCommand,
...restOfCommands
] = _;
const [firstCommand, ...restOfCommands] = _;
return [
firstCommand || 'default',
options,
restOfCommands || [],
];
return [firstCommand || 'default', options, restOfCommands || []];
}
module.exports = extractCommand;

@@ -8,7 +8,3 @@ /**

if (source && typeof source === 'object') {
return Object.values(source)
.reduce(
(acc, value) => acc.concat(getDeepValues(value, true)),
[],
);
return Object.values(source).reduce((acc, value) => acc.concat(getDeepValues(value, true)), []);
}

@@ -15,0 +11,0 @@

@@ -7,8 +7,5 @@ /**

function getPartial(path, source) {
return path.reduce(
(previous, key) => (previous ? previous[key] : undefined),
source,
);
return path.reduce((previous, key) => (previous ? previous[key] : undefined), source);
}
module.exports = getPartial;

@@ -1,10 +0,3 @@

const marked = require('marked');
const TerminalRenderer = require('marked-terminal');
const terminalMarkdown = require('../utils/terminal-markdown');
marked.setOptions({
renderer: new TerminalRenderer({
showSectionPrefix: false,
}),
});
let silent = false;

@@ -17,7 +10,6 @@

function print(...content) {
const output = marked(content.join(' ')).trim();
const output = terminalMarkdown(content.join(' ')).trim();
/* Print content to screen */
if (!silent) {
// eslint-disable-next-line no-console
console.log(output);

@@ -24,0 +16,0 @@ }

@@ -9,4 +9,4 @@ /**

const lengthB = nameB.length;
const minLength = (lengthA > lengthB) ? lengthB : lengthA;
const maxLength = (lengthA < lengthB) ? lengthB : lengthA;
const minLength = lengthA > lengthB ? lengthB : lengthA;
const maxLength = lengthA < lengthB ? lengthB : lengthA;
let equivalency = 0;

@@ -13,0 +13,0 @@

#! /usr/bin/env node
const colors = require('picocolors');
const app = require('./app');

@@ -9,14 +11,24 @@ const extractCommand = require('./helpers/extract-command');

if (typeof command === 'function') {
try {
command({
...options,
fromCli: true,
}, restOfCommands);
} catch (e) {
console.error(e);
process.exit(1);
(async () => {
if (typeof command === 'function') {
try {
await command(
{
...options,
fromCli: true,
},
restOfCommands,
);
} catch (e) {
console.log(
'\n ',
colors.bgRed(' Error '),
colors.red(e.toString().replace(/^Error: /, '')),
'\n',
);
process.exit(1);
}
} else {
app.notFound({ name: commandName });
}
} else {
app.notFound({ name: commandName });
}
})();

@@ -17,26 +17,28 @@ const getDeepValues = require('../../helpers/get-deep-values');

if (value.content_key && typeof value.content_key === 'object') {
return Object.values(value.content_key)
/**
* Need to support deeply nested `content_key` structures:
*
* ```json
* {
* "content_key": {
* "label": "form.last_name.label"
* }
* }
* ```
* as well as this:
* ```json
* {
* "content_key": {
* "last_name": {
* "label": "form.last_name.label"
* }
* }
* }
* ```
*/
.reduce((acc, subValue) => acc.concat(getDeepValues(subValue, true)), [])
.filter((subValue) => !!subValue);
return (
Object.values(value.content_key)
/**
* Need to support deeply nested `content_key` structures:
*
* ```json
* {
* "content_key": {
* "label": "form.last_name.label"
* }
* }
* ```
* as well as this:
* ```json
* {
* "content_key": {
* "last_name": {
* "label": "form.last_name.label"
* }
* }
* }
* ```
*/
.reduce((acc, subValue) => acc.concat(getDeepValues(subValue, true)), [])
.filter((subValue) => !!subValue)
);
}

@@ -59,6 +61,3 @@

Object.keys(value).forEach((key) => {
output = [
...output,
...extractContentKeys(value[key]),
];
output = [...output, ...extractContentKeys(value[key])];
});

@@ -65,0 +64,0 @@

@@ -9,12 +9,9 @@ /**

return rules.split('|').reduce(
(acc, ruleChunk) => {
const rule = ruleChunk.replace(/:.*/, '');
return rules.split('|').reduce((acc, ruleChunk) => {
const rule = ruleChunk.replace(/:.*/, '');
if (rule === '' || /^(string|integer|boolean)$/.test(rule)) return acc;
if (rule === '' || /^(string|integer|boolean)$/.test(rule)) return acc;
return [...acc, `form.${name}.errors.${rule}`];
},
[],
);
return [...acc, `form.${name}.errors.${rule}`];
}, []);
}

@@ -21,0 +18,0 @@

@@ -11,27 +11,20 @@ /**

const keys = Object.keys(object);
const results = keys.reduce(
(res, key) => {
const path = root.concat(key);
const results = keys.reduce((res, key) => {
const path = root.concat(key);
/* Ensure that empty value is missing translation */
if (object[key] === '') return res;
/* Ensure that empty value is missing translation */
if (object[key] === '') return res;
if (typeof object[key] === 'object' && object[key] !== null) {
extractPaths(object[key], path, res);
} else
if (Array.isArray(res[object[key]])) {
res[object[key]].push(path);
} else {
res[object[key]] = [path];
}
if (typeof object[key] === 'object' && object[key] !== null) {
extractPaths(object[key], path, res);
} else if (Array.isArray(res[object[key]])) {
res[object[key]].push(path);
} else {
res[object[key]] = [path];
}
return res;
},
result,
);
return res;
}, result);
const merged = Object.keys(results).reduce(
(acc, key) => [...acc, ...results[key]],
[],
);
const merged = Object.keys(results).reduce((acc, key) => [...acc, ...results[key]], []);

@@ -38,0 +31,0 @@ return merged.map((data) => data.join('.'));

@@ -27,13 +27,18 @@ /**

return chunkedData.reduce(
(chain, batch) => (
(chain, batch) =>
chain
.then((accumulatedData) => Promise.all(batch.map(mapper))
.then((newData) => (accumulatedData && typeof accumulatedData.length !== 'undefined'
? [...accumulatedData, ...newData]
: newData)))
.then((accumulatedData) =>
Promise.all(batch.map(mapper)).then((newData) =>
accumulatedData && typeof accumulatedData.length !== 'undefined'
? [...accumulatedData, ...newData]
: newData,
),
)
// Adds timeout between request chunks
.then((data) => new Promise((resolve) => {
setTimeout(resolve, dataArray.length > batchSize ? delayMs : 0, data);
}))
),
.then(
(data) =>
new Promise((resolve) => {
setTimeout(resolve, dataArray.length > batchSize ? delayMs : 0, data);
}),
),
Promise.resolve(),

@@ -40,0 +45,0 @@ );

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc