diff --git a/package-lock.json b/package-lock.json index c0a4602d71..92e51d3a22 100644 --- a/package-lock.json +++ b/package-lock.json @@ -881,9 +881,9 @@ } }, "node_modules/@contentstack/management/node_modules/form-data": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", - "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.2.tgz", + "integrity": "sha512-sJe+TQb2vIaIyO783qN6BlMYWMw3WBOHA1Ay2qxsnjuafEOQFJ2JakedOQirT6D5XPRxDvS7AHYyem9fTpb4LQ==", "license": "MIT", "dependencies": { "asynckit": "^0.4.0", @@ -7267,9 +7267,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.5.34", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.34.tgz", - "integrity": "sha512-/TZAiChbAflBNjCg+VvstbcwAtIL/VdMFO3NgRFIzBjpvPzWOTIbbO8kNb6RwU4bt9TP7K+3KqBKw/lOU+Y+GA==", + "version": "1.5.35", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.35.tgz", + "integrity": "sha512-hOSRInrIDm0Brzp4IHW2F/VM+638qOL2CzE0DgpnGzKW27C95IqqeqgKz/hxHGnvPxvQGpHUGD5qRVC9EZY2+A==", "dev": true, "license": "ISC" }, @@ -9615,9 +9615,9 @@ } }, "node_modules/form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz", + "integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==", "license": "MIT", "dependencies": { "asynckit": "^0.4.0", @@ -26964,26 +26964,26 @@ }, "packages/contentstack": { "name": "@contentstack/cli", - "version": "1.27.1", + "version": "1.28.0", "license": "MIT", "dependencies": { "@contentstack/cli-audit": "~1.7.2", "@contentstack/cli-auth": "~1.3.22", "@contentstack/cli-cm-bootstrap": "~1.13.0", - "@contentstack/cli-cm-branches": "~1.1.4", - "@contentstack/cli-cm-bulk-publish": "~1.4.9", + "@contentstack/cli-cm-branches": "~1.2.0", + "@contentstack/cli-cm-bulk-publish": "~1.5.0", "@contentstack/cli-cm-clone": "~1.13.0", - "@contentstack/cli-cm-export": "~1.14.0", + "@contentstack/cli-cm-export": "~1.14.1", "@contentstack/cli-cm-export-to-csv": "~1.7.3", - "@contentstack/cli-cm-import": "~1.19.0", + "@contentstack/cli-cm-import": "~1.19.1", "@contentstack/cli-cm-migrate-rte": "~1.4.20", "@contentstack/cli-cm-seed": "~1.10.0", "@contentstack/cli-command": "~1.3.2", - "@contentstack/cli-config": "~1.7.3", + "@contentstack/cli-config": "~1.8.0", "@contentstack/cli-launch": "~1.2.3", "@contentstack/cli-migration": "~1.6.3", "@contentstack/cli-utilities": "~1.8.0", - "@contentstack/cli-variants": "~1.1.0", + "@contentstack/cli-variants": "~1.1.1", "@contentstack/management": "~1.17.0", "@oclif/core": "^3.26.5", "@oclif/plugin-help": "^5", @@ -27417,7 +27417,7 @@ }, "packages/contentstack-branches": { "name": "@contentstack/cli-cm-branches", - "version": "1.1.4", + "version": "1.2.0", "license": "MIT", "dependencies": { "@contentstack/cli-command": "~1.3.2", @@ -27441,7 +27441,7 @@ }, "devDependencies": { "@contentstack/cli-auth": "~1.3.22", - "@contentstack/cli-config": "~1.7.3", + "@contentstack/cli-config": "~1.8.0", "@contentstack/cli-dev-dependencies": "~1.2.4", "@oclif/plugin-help": "^5.1.19", "@oclif/test": "^2.5.6", @@ -27466,7 +27466,7 @@ }, "packages/contentstack-bulk-publish": { "name": "@contentstack/cli-cm-bulk-publish", - "version": "1.4.9", + "version": "1.5.0", "license": "MIT", "dependencies": { "@contentstack/cli-command": "~1.3.2", @@ -27508,8 +27508,8 @@ "license": "MIT", "dependencies": { "@colors/colors": "^1.5.0", - "@contentstack/cli-cm-export": "~1.14.0", - "@contentstack/cli-cm-import": "~1.19.0", + "@contentstack/cli-cm-export": "~1.14.1", + "@contentstack/cli-cm-import": "~1.19.1", "@contentstack/cli-command": "~1.3.2", "@contentstack/cli-utilities": "~1.8.0", "async": "^3.2.4", @@ -27691,7 +27691,7 @@ }, "packages/contentstack-config": { "name": "@contentstack/cli-config", - "version": "1.7.3", + "version": "1.8.0", "license": "MIT", "dependencies": { "@contentstack/cli-command": "~1.3.2", @@ -28098,12 +28098,12 @@ }, "packages/contentstack-export": { "name": "@contentstack/cli-cm-export", - "version": "1.14.0", + "version": "1.14.1", "license": "MIT", "dependencies": { "@contentstack/cli-command": "~1.3.2", "@contentstack/cli-utilities": "~1.8.0", - "@contentstack/cli-variants": "~1.1.0", + "@contentstack/cli-variants": "~1.1.1", "@oclif/core": "^3.26.5", "async": "^3.2.4", "big-json": "^3.2.0", @@ -28122,7 +28122,7 @@ }, "devDependencies": { "@contentstack/cli-auth": "~1.3.22", - "@contentstack/cli-config": "~1.7.3", + "@contentstack/cli-config": "~1.8.0", "@contentstack/cli-dev-dependencies": "~1.2.4", "@oclif/plugin-help": "^5.1.19", "@oclif/test": "^2.5.6", @@ -28679,13 +28679,13 @@ }, "packages/contentstack-import": { "name": "@contentstack/cli-cm-import", - "version": "1.19.0", + "version": "1.19.1", "license": "MIT", "dependencies": { "@contentstack/cli-audit": "~1.7.2", "@contentstack/cli-command": "~1.3.2", "@contentstack/cli-utilities": "~1.8.0", - "@contentstack/cli-variants": "~1.1.0", + "@contentstack/cli-variants": "~1.1.1", "@contentstack/management": "~1.17.0", "@oclif/core": "^3.26.5", "big-json": "^3.2.0", @@ -28741,10 +28741,10 @@ "@contentstack/cli-command": "~1.3.2", "@contentstack/cli-utilities": "~1.8.0", "@oclif/core": "^3.27.0", - "@oclif/plugin-help": "^5", + "@oclif/plugin-help": "^5.2.20", "@oclif/plugin-plugins": "^5.4.14", "@types/express": "^4.17.21", - "@types/express-serve-static-core": "^4.19.6", + "@types/express-serve-static-core": "^4.17.34", "adm-zip": "^0.5.16", "chalk": "^4.1.2", "cross-fetch": "^3.1.8", @@ -29127,7 +29127,7 @@ "version": "1.10.0", "license": "MIT", "dependencies": { - "@contentstack/cli-cm-import": "~1.19.0", + "@contentstack/cli-cm-import": "~1.19.1", "@contentstack/cli-command": "~1.3.2", "@contentstack/cli-utilities": "~1.8.0", "inquirer": "8.2.4", @@ -29295,7 +29295,7 @@ }, "packages/contentstack-variants": { "name": "@contentstack/cli-variants", - "version": "1.1.0", + "version": "1.1.1", "license": "MIT", "dependencies": { "@contentstack/cli-utilities": "^1.8.0", diff --git a/packages/contentstack-audit/README.md b/packages/contentstack-audit/README.md index 8cd4f52d3d..ca2a518bf6 100644 --- a/packages/contentstack-audit/README.md +++ b/packages/contentstack-audit/README.md @@ -269,7 +269,7 @@ EXAMPLES $ csdx plugins ``` -_See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v5.4.9/src/commands/plugins/index.ts)_ +_See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v5.4.14/src/commands/plugins/index.ts)_ ## `csdx plugins:add PLUGIN` @@ -343,7 +343,7 @@ EXAMPLES $ csdx plugins:inspect myplugin ``` -_See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v5.4.9/src/commands/plugins/inspect.ts)_ +_See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v5.4.14/src/commands/plugins/inspect.ts)_ ## `csdx plugins:install PLUGIN` @@ -392,7 +392,7 @@ EXAMPLES $ csdx plugins:install someuser/someplugin ``` -_See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v5.4.9/src/commands/plugins/install.ts)_ +_See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v5.4.14/src/commands/plugins/install.ts)_ ## `csdx plugins:link PATH` @@ -412,6 +412,7 @@ FLAGS DESCRIPTION Links a plugin into the CLI for development. + Installation of a linked plugin will override a user-installed or core plugin. e.g. If you have a user-installed or core plugin that has a 'hello' command, installing a linked plugin with a 'hello' @@ -422,7 +423,7 @@ EXAMPLES $ csdx plugins:link myplugin ``` -_See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v5.4.9/src/commands/plugins/link.ts)_ +_See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v5.4.14/src/commands/plugins/link.ts)_ ## `csdx plugins:remove [PLUGIN]` @@ -463,7 +464,7 @@ FLAGS --reinstall Reinstall all plugins after uninstalling. ``` -_See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v5.4.9/src/commands/plugins/reset.ts)_ +_See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v5.4.14/src/commands/plugins/reset.ts)_ ## `csdx plugins:uninstall [PLUGIN]` @@ -491,7 +492,7 @@ EXAMPLES $ csdx plugins:uninstall myplugin ``` -_See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v5.4.9/src/commands/plugins/uninstall.ts)_ +_See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v5.4.14/src/commands/plugins/uninstall.ts)_ ## `csdx plugins:unlink [PLUGIN]` @@ -535,5 +536,5 @@ DESCRIPTION Update installed plugins. ``` -_See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v5.4.9/src/commands/plugins/update.ts)_ +_See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v5.4.14/src/commands/plugins/update.ts)_ diff --git a/packages/contentstack-auth/src/commands/auth/login.ts b/packages/contentstack-auth/src/commands/auth/login.ts index cae77fb6e6..8b61d65ca8 100644 --- a/packages/contentstack-auth/src/commands/auth/login.ts +++ b/packages/contentstack-auth/src/commands/auth/login.ts @@ -66,6 +66,9 @@ export default class LoginCommand extends BaseCommand { } } catch (error) { let errorMessage = formatError(error) || 'Something went wrong while logging. Please try again.'; + if (typeof errorMessage === 'object' && Object.keys(errorMessage)?.length === 0) { + console.log(error); + } this.logger.error('login failed', errorMessage); cliux.error('CLI_AUTH_LOGIN_FAILED'); cliux.error(errorMessage); diff --git a/packages/contentstack-auth/test/integration/auth.test.ts b/packages/contentstack-auth/test/integration/auth.test.ts index cc5fa2b821..e41c9312f5 100644 --- a/packages/contentstack-auth/test/integration/auth.test.ts +++ b/packages/contentstack-auth/test/integration/auth.test.ts @@ -25,6 +25,7 @@ describe('contentstack-auth plugin test', () => { describe('Check auth:login command with wrong credentials', () => { test + .loadConfig({ root: process.cwd() }) // @ts-ignore .stub(CliUx, 'inquire', async (inquire) => { switch (inquire.name) { @@ -34,24 +35,27 @@ describe('contentstack-auth plugin test', () => { return 'WrongPassword@12345%$#@!'; // NOTE forcing wrong password } }) + .stub(process,'exit',()=>{}) .stdout({ print: PRINT_LOGS || false }) .command(['auth:login']) .it('Login should fail due to wrong credentials.!', (ctx) => { - expect(ctx.stdout).to.a('string').includes('Login Error\nLooks like your email or password is invalid'); + expect(ctx.stdout).to.be.includes('Login Error\nLooks like your email or password is invalid. Please try again or reset your password.'); }); }); describe('Check auth:login command with --username, --password flags and wrong credentials', () => { - test + test.loadConfig({ root: process.cwd() }) .stdout({ print: PRINT_LOGS || false }) + .stub(process,'exit',()=>{}) .command(['auth:login', `--username=${username}`, '--password=WrongPassword@12345%$#@!']) .it('Login should fail due to wrong credentials.!', (ctx) => { - expect(ctx.stdout).to.a('string').includes('Login Error\nLooks like your email or password is invalid'); + expect(ctx.stdout).to.a('string').includes('Login Error\nLooks like your email or password is invalid. Please try again or reset your password.'); }); }); + //NOTE describe('Check auth:login command with correct credentials.', () => { - test + test.loadConfig({ root: process.cwd() }) // @ts-ignore .stub(CliUx, 'inquire', async (inquire) => { switch (inquire.name) { @@ -69,17 +73,17 @@ describe('contentstack-auth plugin test', () => { }); describe('Check auth:logout command', () => { - test + test.loadConfig({ root: process.cwd() }) .stub(CliUx, 'inquire', async () => 'Yes') .stdout({ print: PRINT_LOGS || false }) - .command(['auth:logout']) + .command(['auth:logout','--yes']) .it('Logout should succeed.!', (ctx) => { expect(ctx.stdout).to.a('string').includes('Successfully logged out'); }); }); describe('Check auth:login command with --username, --password flags', () => { - test + test.loadConfig({ root: process.cwd() }) .stdout({ print: PRINT_LOGS || false }) .command(['auth:login', `-u=${username}`, `-p=${password}`]) .it('Login should succeed!', (ctx) => { @@ -95,7 +99,7 @@ describe('contentstack-auth plugin test', () => { after(() => { mail = ''; }); - test + test.loadConfig({ root: process.cwd() }) .stdout({ print: PRINT_LOGS || false }) .command(['whoami']) .it('shows user email who logged in', (ctx) => { diff --git a/packages/contentstack-branches/README.md b/packages/contentstack-branches/README.md index 74f0e2f782..2098948b1f 100755 --- a/packages/contentstack-branches/README.md +++ b/packages/contentstack-branches/README.md @@ -37,7 +37,7 @@ $ npm install -g @contentstack/cli-cm-branches $ csdx COMMAND running command... $ csdx (--version) -@contentstack/cli-cm-branches/1.1.4 darwin-arm64 node-v22.2.0 +@contentstack/cli-cm-branches/1.2.0 darwin-arm64 node-v22.2.0 $ csdx --help [COMMAND] USAGE $ csdx COMMAND diff --git a/packages/contentstack-branches/package.json b/packages/contentstack-branches/package.json index 533a3736ac..da524dd6a1 100644 --- a/packages/contentstack-branches/package.json +++ b/packages/contentstack-branches/package.json @@ -1,7 +1,7 @@ { "name": "@contentstack/cli-cm-branches", "description": "Contentstack CLI plugin to do branches operations", - "version": "1.1.4", + "version": "1.2.0", "author": "Contentstack", "bugs": "https://github.com/contentstack/cli/issues", "dependencies": { @@ -26,7 +26,7 @@ }, "devDependencies": { "@contentstack/cli-auth": "~1.3.22", - "@contentstack/cli-config": "~1.7.3", + "@contentstack/cli-config": "~1.8.0", "@contentstack/cli-dev-dependencies": "~1.2.4", "@oclif/plugin-help": "^5.1.19", "@oclif/test": "^2.5.6", diff --git a/packages/contentstack-branches/src/utils/entry-create-script.ts b/packages/contentstack-branches/src/utils/entry-create-script.ts index fccb08d55e..ca5d06038d 100644 --- a/packages/contentstack-branches/src/utils/entry-create-script.ts +++ b/packages/contentstack-branches/src/utils/entry-create-script.ts @@ -108,6 +108,13 @@ export function entryCreateScript(contentType) { findAssetIdsFromJsonRte(entry, schema); parent.pop(); } + if ( + schema[i].data_type === 'json' && + schema[i].field_metadata.extension && + schema[i].field_metadata.is_asset + ) { + fetchAssetFromFileFields(parent,schema[i],entry); + } if ( schema[i].data_type === 'text' && schema[i].field_metadata && @@ -121,43 +128,47 @@ export function entryCreateScript(contentType) { parent.pop(); } if (schema[i].data_type === 'file') { - parent.push(schema[i].uid); - let updatedEntry = entry; - for (let i = 0; i < parent.length; i++) { - updatedEntry = updatedEntry[parent[i]]; - } - const imgDetails = updatedEntry; - if (schema[i].multiple) { - if (imgDetails && imgDetails.length) { - imgDetails.forEach((img) => { - const obj = { - uid: img.uid, - parent_uid: img.parent_uid, - description: img.description, - title: img.title, - filename: img.filename, - url: img.url, - }; - cAssetDetails.push(obj); - }); - } - } else { - if (imgDetails) { - const obj = { - uid: imgDetails.uid, - parent_uid: imgDetails.parent_uid, - description: imgDetails.description, - title: imgDetails.title, - filename: imgDetails.filename, - url: imgDetails.url, - }; - cAssetDetails.push(obj); - } - } - parent.pop(); + fetchAssetFromFileFields(parent,schema[i],entry); } } }; + + function fetchAssetFromFileFields (parent, schema, entry) { + parent.push(schema.uid); + let updatedEntry = entry; + for (let i = 0; i < parent.length; i++) { + updatedEntry = updatedEntry[parent[i]]; + } + const imgDetails = updatedEntry; + if (schema.multiple) { + if (imgDetails && imgDetails.length) { + imgDetails.forEach((img) => { + const obj = { + uid: img.uid, + parent_uid: img.parent_uid, + description: img.description, + title: img.title, + filename: img.filename, + url: img.url, + }; + assetDetails.push(obj); + }); + } + } else { + if (imgDetails) { + const obj = { + uid: imgDetails.uid, + parent_uid: imgDetails.parent_uid, + description: imgDetails.description, + title: imgDetails.title, + filename: imgDetails.filename, + url: imgDetails.url, + }; + assetDetails.push(obj); + } + } + parent.pop(); + } function findAssetIdsFromHtmlRte(entryObj, ctSchema) { const regex = / { - const obj = { - uid: img.uid, - parent_uid: img.parent_uid, - description: img.description, - title: img.title, - filename: img.filename, - url: img.url, - }; - assetDetails.push(obj); - }); - } - } else { - if (imgDetails) { - const obj = { - uid: imgDetails.uid, - parent_uid: imgDetails.parent_uid, - description: imgDetails.description, - title: imgDetails.title, - filename: imgDetails.filename, - url: imgDetails.url, - }; - assetDetails.push(obj); - } - } - parent.pop(); + fetchAssetFromFileFields(parent,schema[i],entry); } } }; + function fetchAssetFromFileFields (parent, schema, entry) { + parent.push(schema.uid); + let updatedEntry = entry; + for (let i = 0; i < parent.length; i++) { + updatedEntry = updatedEntry[parent[i]]; + } + const imgDetails = updatedEntry; + if (schema.multiple) { + if (imgDetails && imgDetails.length) { + imgDetails.forEach((img) => { + const obj = { + uid: img.uid, + parent_uid: img.parent_uid, + description: img.description, + title: img.title, + filename: img.filename, + url: img.url, + }; + assetDetails.push(obj); + }); + } + } else { + if (imgDetails) { + const obj = { + uid: imgDetails.uid, + parent_uid: imgDetails.parent_uid, + description: imgDetails.description, + title: imgDetails.title, + filename: imgDetails.filename, + url: imgDetails.url, + }; + assetDetails.push(obj); + } + } + parent.pop(); + } function findAssetIdsFromHtmlRte(entryObj, ctSchema) { const regex = / { - const obj = { - uid: img.uid, - parent_uid: img.parent_uid, - description: img.description, - title: img.title, - filename: img.filename, - url: img.url, - }; - assetDetails.push(obj); - }); - } - } else { - if (imgDetails) { - const obj = { - uid: imgDetails.uid, - parent_uid: imgDetails.parent_uid, - description: imgDetails.description, - title: imgDetails.title, - filename: imgDetails.filename, - url: imgDetails.url, - }; - assetDetails.push(obj); - } - } - parent.pop(); + fetchAssetFromFileFields(parent,schema[i],entry); } } }; - + + function fetchAssetFromFileFields (parent, schema, entry) { + parent.push(schema.uid); + let updatedEntry = entry; + for (let i = 0; i < parent.length; i++) { + updatedEntry = updatedEntry[parent[i]]; + } + const imgDetails = updatedEntry; + if (schema.multiple) { + if (imgDetails && imgDetails.length) { + imgDetails.forEach((img) => { + const obj = { + uid: img.uid, + parent_uid: img.parent_uid, + description: img.description, + title: img.title, + filename: img.filename, + url: img.url, + }; + assetDetails.push(obj); + }); + } + } else { + if (imgDetails) { + const obj = { + uid: imgDetails.uid, + parent_uid: imgDetails.parent_uid, + description: imgDetails.description, + title: imgDetails.title, + filename: imgDetails.filename, + url: imgDetails.url, + }; + assetDetails.push(obj); + } + } + parent.pop(); + } + function findAssetIdsFromHtmlRte(entryObj, ctSchema) { const regex = / { let queryParams = { folder: folder, @@ -33,18 +34,27 @@ async function getAssets(stack, folder, bulkPublish, environments, locale, apiVe let assets = assetResponse.items; for (let index = 0; index < assetResponse.items.length; index++) { if (assets[index].is_dir === true) { - await getAssets(stack, assets[index].uid, bulkPublish, environments, locale, apiVersion, 0); + await getAssets( + stack, + assets[index].uid, + bulkPublish, + environments, + locale, + apiVersion, + bulkPublishLimit, + 0, + ); continue; } if (bulkPublish) { - if (bulkPublishSet.length < 10) { + if (bulkPublishSet.length < bulkPublishLimit) { bulkPublishSet.push({ uid: assets[index].uid, locale, publish_details: assets[index].publish_details || [], }); } - if (bulkPublishSet.length === 10) { + if (bulkPublishSet.length === bulkPublishLimit) { await queue.Enqueue({ assets: bulkPublishSet, Type: 'asset', @@ -56,7 +66,11 @@ async function getAssets(stack, folder, bulkPublish, environments, locale, apiVe bulkPublishSet = []; } - if (assetResponse.items.length - 1 === index && bulkPublishSet.length > 0 && bulkPublishSet.length < 10) { + if ( + assetResponse.items.length - 1 === index && + bulkPublishSet.length > 0 && + bulkPublishSet.length < bulkPublishLimit + ) { await queue.Enqueue({ assets: bulkPublishSet, Type: 'asset', @@ -81,7 +95,7 @@ async function getAssets(stack, folder, bulkPublish, environments, locale, apiVe if (skip === assetResponse.count) { return resolve(true); } - await getAssets(stack, folder, bulkPublish, environments, locale, apiVersion, skip); + await getAssets(stack, folder, bulkPublish, environments, locale, apiVersion, bulkPublishLimit, skip); return resolve(); } else { resolve(); @@ -133,8 +147,9 @@ async function start({ retryFailed, bulkPublish, environments, folderUid, locale } } else if (folderUid) { setConfig(config, bulkPublish); + const bulkPublishLimit = fetchBulkPublishLimit(stack?.org_uid); for (const element of locales) { - await getAssets(stack, folderUid, bulkPublish, environments, element, apiVersion); + await getAssets(stack, folderUid, bulkPublish, environments, element, apiVersion, bulkPublishLimit); } } } diff --git a/packages/contentstack-bulk-publish/src/producer/publish-entries.js b/packages/contentstack-bulk-publish/src/producer/publish-entries.js index 126260ce73..0f6cce121f 100644 --- a/packages/contentstack-bulk-publish/src/producer/publish-entries.js +++ b/packages/contentstack-bulk-publish/src/producer/publish-entries.js @@ -8,6 +8,7 @@ const { performBulkPublish, publishEntry, initializeLogger } = require('../consu const retryFailedLogs = require('../util/retryfailed'); const { validateFile } = require('../util/fs'); const { isEmpty } = require('../util'); +const { fetchBulkPublishLimit } = require('../util/common-utility'); const queue = getQueue(); @@ -18,7 +19,16 @@ let allContentTypes = []; let bulkPublishSet = []; let filePath; -async function getEntries(stack, contentType, locale, bulkPublish, environments, apiVersion, skip = 0) { +async function getEntries( + stack, + contentType, + locale, + bulkPublish, + environments, + apiVersion, + bulkPublishLimit, + skip = 0, +) { return new Promise((resolve, reject) => { skipCount = skip; @@ -39,7 +49,7 @@ async function getEntries(stack, contentType, locale, bulkPublish, environments, let entries = entriesResponse.items; for (let index = 0; index < entriesResponse.items.length; index++) { if (bulkPublish) { - if (bulkPublishSet.length < 10) { + if (bulkPublishSet.length < bulkPublishLimit) { bulkPublishSet.push({ uid: entries[index].uid, content_type: contentType, @@ -48,21 +58,21 @@ async function getEntries(stack, contentType, locale, bulkPublish, environments, }); } - if (bulkPublishSet.length === 10) { + if (bulkPublishSet.length === bulkPublishLimit) { await queue.Enqueue({ entries: bulkPublishSet, locale, Type: 'entry', environments: environments, stack: stack, - apiVersion + apiVersion, }); bulkPublishSet = []; } if ( index === entriesResponse.items.length - 1 && - bulkPublishSet.length <= 10 && + bulkPublishSet.length <= bulkPublishLimit && bulkPublishSet.length > 0 ) { await queue.Enqueue({ @@ -71,7 +81,7 @@ async function getEntries(stack, contentType, locale, bulkPublish, environments, Type: 'entry', environments: environments, stack: stack, - apiVersion + apiVersion, }); bulkPublishSet = []; } // bulkPublish @@ -92,7 +102,16 @@ async function getEntries(stack, contentType, locale, bulkPublish, environments, bulkPublishSet = []; return resolve(); } - await getEntries(stack, contentType, locale, bulkPublish, environments, apiVersion, skipCount); + await getEntries( + stack, + contentType, + locale, + bulkPublish, + environments, + apiVersion, + bulkPublishLimit, + skipCount, + ); return resolve(); }) .catch((error) => reject(error)); @@ -170,10 +189,19 @@ async function start( } else { allContentTypes = contentTypes; } + const bulkPublishLimit = fetchBulkPublishLimit(stack?.org_uid); for (let loc = 0; loc < locales.length; loc += 1) { for (let i = 0; i < allContentTypes.length; i += 1) { /* eslint-disable no-await-in-loop */ - await getEntries(stack, allContentTypes[i].uid || allContentTypes[i], locales[loc], bulkPublish, environments, apiVersion); + await getEntries( + stack, + allContentTypes[i].uid || allContentTypes[i], + locales[loc], + bulkPublish, + environments, + apiVersion, + bulkPublishLimit, + ); /* eslint-enable no-await-in-loop */ } } diff --git a/packages/contentstack-bulk-publish/src/util/client.js b/packages/contentstack-bulk-publish/src/util/client.js index 12ad2c4164..22a73bcca7 100644 --- a/packages/contentstack-bulk-publish/src/util/client.js +++ b/packages/contentstack-bulk-publish/src/util/client.js @@ -15,12 +15,18 @@ async function getStack(data) { stackOptions.api_key = tokenDetails.apiKey; } else if (data.stackApiKey) { if (!isAuthenticated()) { - throw new Error('Please login to proceed further. Or use `--alias` instead of `--stack-api-key` to proceed without logging in.') + throw new Error( + 'Please login to proceed further. Or use `--alias` instead of `--stack-api-key` to proceed without logging in.', + ); } stackOptions.api_key = data.stackApiKey; } const managementClient = await managementSDKClient(options); const stack = managementClient.stack(stackOptions); + if (data.stackApiKey && isAuthenticated()) { + const stackDetails = await stack.fetch(); + stack.org_uid = stackDetails.org_uid; + } stack.alias = data.alias; stack.host = data.host; return stack; diff --git a/packages/contentstack-bulk-publish/src/util/common-utility.js b/packages/contentstack-bulk-publish/src/util/common-utility.js new file mode 100644 index 0000000000..c51c0a40de --- /dev/null +++ b/packages/contentstack-bulk-publish/src/util/common-utility.js @@ -0,0 +1,30 @@ +const { configHandler, cliux } = require('@contentstack/cli-utilities'); + +function fetchBulkPublishLimit(orgUid) { + const plan = configHandler.get('rateLimit'); + let bulkPublishLimit = 1; // Default limit according to the default plan + + if (plan) { + const orgPlan = plan[orgUid]?.bulkLimit; + const defaultPlan = plan['default']?.bulkLimit; + + if (orgPlan?.value && orgPlan?.utilize) { + bulkPublishLimit = Math.ceil((orgPlan.value * orgPlan.utilize) / 100); + } else if (defaultPlan?.value && defaultPlan?.utilize) { + bulkPublishLimit = Math.ceil((defaultPlan.value * defaultPlan.utilize) / 100); + } + } else { + cliux.print( + 'Bulk publish limit not found in config. Using default limit. Please set the limit using $csdx config:set:rate-limit', + { color: 'yellow' }, + ); + // TODO: Update the link once the rate-limit documentation is ready + cliux.print( + 'Suggestions: To set the rate limit, visit https://www.contentstack.com/docs/developers/cli#get-started-with-contentstack-command-line-interface-cli', + { color: 'blue' }, + ); + } + return bulkPublishLimit; +} + +module.exports = { fetchBulkPublishLimit }; diff --git a/packages/contentstack-clone/package.json b/packages/contentstack-clone/package.json index b0e6a3f5b4..e8fa497b33 100644 --- a/packages/contentstack-clone/package.json +++ b/packages/contentstack-clone/package.json @@ -6,8 +6,8 @@ "bugs": "https://github.com/rohitmishra209/cli-cm-clone/issues", "dependencies": { "@colors/colors": "^1.5.0", - "@contentstack/cli-cm-export": "~1.14.0", - "@contentstack/cli-cm-import": "~1.19.0", + "@contentstack/cli-cm-export": "~1.14.1", + "@contentstack/cli-cm-import": "~1.19.1", "@contentstack/cli-command": "~1.3.2", "@contentstack/cli-utilities": "~1.8.0", "async": "^3.2.4", diff --git a/packages/contentstack-config/README.md b/packages/contentstack-config/README.md index 6029836d4d..e4d0841a5a 100644 --- a/packages/contentstack-config/README.md +++ b/packages/contentstack-config/README.md @@ -18,7 +18,7 @@ $ npm install -g @contentstack/cli-config $ csdx COMMAND running command... $ csdx (--version) -@contentstack/cli-config/1.7.3 darwin-arm64 node-v22.2.0 +@contentstack/cli-config/1.8.0 darwin-arm64 node-v22.2.0 $ csdx --help [COMMAND] USAGE $ csdx COMMAND @@ -32,13 +32,16 @@ USAGE * [`csdx config:get:base-branch`](#csdx-configgetbase-branch) * [`csdx config:get:ea-header`](#csdx-configgetea-header) * [`csdx config:get:early-access-header`](#csdx-configgetearly-access-header) +* [`csdx config:get:rate-limit`](#csdx-configgetrate-limit) * [`csdx config:get:region`](#csdx-configgetregion) * [`csdx config:remove:base-branch`](#csdx-configremovebase-branch) * [`csdx config:remove:ea-header`](#csdx-configremoveea-header) * [`csdx config:remove:early-access-header`](#csdx-configremoveearly-access-header) +* [`csdx config:remove:rate-limit`](#csdx-configremoverate-limit) * [`csdx config:set:base-branch`](#csdx-configsetbase-branch) * [`csdx config:set:ea-header`](#csdx-configsetea-header) * [`csdx config:set:early-access-header`](#csdx-configsetearly-access-header) +* [`csdx config:set:rate-limit`](#csdx-configsetrate-limit) * [`csdx config:set:region [REGION]`](#csdx-configsetregion-region) ## `csdx config:get:base-branch` @@ -96,6 +99,23 @@ EXAMPLES _See code: [src/commands/config/get/early-access-header.ts](https://github.com/contentstack/cli/blob/main/packages/contentstack-config/src/commands/config/get/early-access-header.ts)_ +## `csdx config:get:rate-limit` + +Get rate-limit of organizations + +``` +USAGE + $ csdx config:get:rate-limit + +DESCRIPTION + Get rate-limit of organizations + +EXAMPLES + $ csdx config:get:rate-limit +``` + +_See code: [src/commands/config/get/rate-limit.ts](https://github.com/contentstack/cli/blob/main/packages/contentstack-config/src/commands/config/get/rate-limit.ts)_ + ## `csdx config:get:region` Get current region set for CLI @@ -186,6 +206,26 @@ EXAMPLES _See code: [src/commands/config/remove/early-access-header.ts](https://github.com/contentstack/cli/blob/main/packages/contentstack-config/src/commands/config/remove/early-access-header.ts)_ +## `csdx config:remove:rate-limit` + +Remove rate-limit of the organization + +``` +USAGE + $ csdx config:remove:rate-limit [--org ] + +FLAGS + --org= Provide the organization UID + +DESCRIPTION + Remove rate-limit of the organization + +EXAMPLES + $ csdx config:remove:rate-limit --org <> +``` + +_See code: [src/commands/config/remove/rate-limit.ts](https://github.com/contentstack/cli/blob/main/packages/contentstack-config/src/commands/config/remove/rate-limit.ts)_ + ## `csdx config:set:base-branch` Set branch for CLI @@ -259,6 +299,33 @@ EXAMPLES _See code: [src/commands/config/set/early-access-header.ts](https://github.com/contentstack/cli/blob/main/packages/contentstack-config/src/commands/config/set/early-access-header.ts)_ +## `csdx config:set:rate-limit` + +Set rate-limit for CLI + +``` +USAGE + $ csdx config:set:rate-limit [--org ] [--utilize ] [--limit-name ] [--default] + +FLAGS + --default Reset to default rate limit + --limit-name=... [Optional] Provide the limit names separated by commas ['limit', 'getLimit', 'bulkLimit'] + --org= Provide the organization UID + --utilize= [default: 50] Provide the utilization percentages for rate limit, separated by commas + +DESCRIPTION + Set rate-limit for CLI + +EXAMPLES + $ csdx config:set:rate-limit --org <> + + $ csdx config:set:rate-limit --org <> --utilize 70,80 --limit-name getLimit,limit + + $ csdx config:set:rate-limit --org <> --default +``` + +_See code: [src/commands/config/set/rate-limit.ts](https://github.com/contentstack/cli/blob/main/packages/contentstack-config/src/commands/config/set/rate-limit.ts)_ + ## `csdx config:set:region [REGION]` Set region for CLI diff --git a/packages/contentstack-config/package.json b/packages/contentstack-config/package.json index c8ef75a741..a61b82daa0 100644 --- a/packages/contentstack-config/package.json +++ b/packages/contentstack-config/package.json @@ -1,7 +1,7 @@ { "name": "@contentstack/cli-config", "description": "Contentstack CLI plugin for configuration", - "version": "1.7.3", + "version": "1.8.0", "author": "Contentstack", "scripts": { "build": "npm run clean && npm run compile", @@ -81,7 +81,10 @@ "config:get:region": "RGT", "config:set:region": "RST", "config:get:base-branch": "BRGT", - "config:set:base-branch": "BRST" + "config:set:base-branch": "BRST", + "config:set:rate-limit": "RLST", + "config:get:rate-limit": "RLGT", + "config:remove:rate-limit": "RLRM" } }, "repository": "contentstack/cli" diff --git a/packages/contentstack-config/src/commands/config/get/rate-limit.ts b/packages/contentstack-config/src/commands/config/get/rate-limit.ts new file mode 100644 index 0000000000..a3cb1e18d3 --- /dev/null +++ b/packages/contentstack-config/src/commands/config/get/rate-limit.ts @@ -0,0 +1,40 @@ +import { cliux, configHandler } from '@contentstack/cli-utilities'; +import { Command } from '@contentstack/cli-command'; +import { RateLimitConfig } from '../../../interfaces'; + +export default class RateLimitGetCommand extends Command { + static description: string = 'Get rate-limit of organizations'; + static examples = ['$ csdx config:get:rate-limit']; + + async run() { + try { + const rateLimit = configHandler.get('rateLimit') || {}; + const formatLimit = (limit) => (limit ? `${limit.value}(${limit.utilize}%)` : '0'); + const tableData = Object.entries(rateLimit).map(([org, limits]: [string, RateLimitConfig]) => ({ + Org: org === 'default' ? 'default' : org, + 'Get Limit': formatLimit(limits.getLimit), + Limit: formatLimit(limits.limit), + 'Bulk Limit': formatLimit(limits.bulkLimit), + })); + + const columns = { + Org: { + minWidth: 10, + }, + 'Get Limit': { + minWidth: 20, + }, + Limit: { + minWidth: 20, + }, + 'Bulk Limit': { + minWidth: 20, + }, + }; + + cliux.table(tableData, columns, { printLine: cliux.print }); + } catch (error) { + this.log('Unable to retrieve the rate limits configuration', error instanceof Error ? error.message : error); + } + } +} diff --git a/packages/contentstack-config/src/commands/config/remove/rate-limit.ts b/packages/contentstack-config/src/commands/config/remove/rate-limit.ts new file mode 100644 index 0000000000..2157ef512f --- /dev/null +++ b/packages/contentstack-config/src/commands/config/remove/rate-limit.ts @@ -0,0 +1,33 @@ +import { cliux, configHandler, FlagInput, flags } from '@contentstack/cli-utilities'; +import { Command } from '@contentstack/cli-command'; +import { askOrgID } from '../../../utils/interactive'; + +export default class RateLimitRemoveCommand extends Command { + static description: string = 'Remove rate-limit of the organization'; + + static flags: FlagInput = { + org: flags.string({ + description: 'Provide the organization UID', + }), + }; + static examples = ['$ csdx config:remove:rate-limit --org <>']; + async run() { + try { + const { flags } = await this.parse(RateLimitRemoveCommand); + let { org } = flags; + if (!org) { + org = await askOrgID(); + } + const rateLimit = configHandler.get('rateLimit') || {}; + + if (!rateLimit[org]) { + cliux.print(`No rate limit found for the organization UID: ${org}`, { color: 'red' }); + return; + } + configHandler.delete(`rateLimit.${org}`); + cliux.print(`Rate limit entry for organization UID ${org} has been removed.`, { color: 'green' }); + } catch (error) { + this.log('Unable to remove the rate limit entry', error instanceof Error ? error.message : error); + } + } +} diff --git a/packages/contentstack-config/src/commands/config/set/rate-limit.ts b/packages/contentstack-config/src/commands/config/set/rate-limit.ts new file mode 100644 index 0000000000..4016a9b071 --- /dev/null +++ b/packages/contentstack-config/src/commands/config/set/rate-limit.ts @@ -0,0 +1,89 @@ +import { flags, isAuthenticated, FlagInput, managementSDKClient, cliux } from '@contentstack/cli-utilities'; +import { RateLimitHandler } from '../../../utils/rate-limit-handler'; +import { BaseCommand } from '../../../base-command'; +import { askOrgID } from '../../../utils/interactive'; +import { SetRateLimitConfig } from '../../../interfaces'; +import { limitNamesConfig } from '../../../utils/common-utilities'; + +export default class SetRateLimitCommand extends BaseCommand { + static description = 'Set rate-limit for CLI'; + + static flags: FlagInput = { + org: flags.string({ + description: 'Provide the organization UID', + }), + + utilize: flags.string({ + description: 'Provide the utilization percentages for rate limit, separated by commas', + default: '50', + }), + + 'limit-name': flags.string({ + description: "[Optional] Provide the limit names separated by commas ['limit', 'getLimit', 'bulkLimit']", + multiple: true, + }), + + default: flags.boolean({ + default: false, + description: 'Reset to default rate limit', + }), + }; + + static examples = [ + '$ csdx config:set:rate-limit --org <>', + '$ csdx config:set:rate-limit --org <> --utilize 70,80 --limit-name getLimit,limit', + '$ csdx config:set:rate-limit --org <> --default', + ]; + + public async run(): Promise { + if (!isAuthenticated()) { + const err = { errorMessage: 'You are not logged in. Please login with command $ csdx auth:login' }; + cliux.print(err.errorMessage, { color: 'red' }); + this.exit(1); + } + + const { flags } = await this.parse(SetRateLimitCommand); + let { org, utilize, 'limit-name': limitName } = flags; + const config: SetRateLimitConfig = { org: '', limitName: limitNamesConfig, host: this.cmaHost }; + + if (!org) { + org = await askOrgID(); + } + config.org = org; + config.default = flags.default; + if (utilize) { + const utilizeValues = utilize?.split(',')?.map((u: string) => Number(u.trim())); + if (utilizeValues.some((u: number) => isNaN(u) || u < 0 || u > 100)) { + cliux.error('Utilize percentages must be numbers between 0 and 100.'); + return; + } + if (limitName?.length > 0 && limitName[0]?.split(',')?.length !== utilizeValues.length) { + cliux.error('The number of utilization percentages must match the number of limit names provided.'); + return; + } else { + config.utilize = utilize.split(',').map((v: string) => v.trim()); + } + } + + if (limitName) { + const invalidLimitNames = limitName[0].split(',').map((name: string) => name.trim()); + + if (invalidLimitNames.some((name: string) => !limitNamesConfig.includes(name))) { + cliux.error(`Invalid limit names provided: ${invalidLimitNames.join(', ')}`); + return; + } else { + config['limit-name'] = limitName[0].split(',').map((n) => n.trim()); + } + } + + const limitHandler = new RateLimitHandler(); + const managementAPIClient = await managementSDKClient(config); + limitHandler.setClient(managementAPIClient); + try { + await limitHandler.setRateLimit(config); + } catch (error) { + cliux.error(`Error: Something went wrong while setting rate limit for org: ${org}`); + cliux.error(error); + } + } +} diff --git a/packages/contentstack-config/src/interfaces/index.ts b/packages/contentstack-config/src/interfaces/index.ts index e1e684c6af..9cff3cc608 100644 --- a/packages/contentstack-config/src/interfaces/index.ts +++ b/packages/contentstack-config/src/interfaces/index.ts @@ -19,3 +19,22 @@ export interface Region { personalizeUrl: string; launchHubUrl: string; } + +export interface Limit { + value: number; + utilize: number; +} + +export interface RateLimitConfig { + getLimit?: Limit; + limit?: Limit + bulkLimit?: Limit +} + +export interface SetRateLimitConfig { + org: string; + utilize?: number; + limitName?: string[]; + default?: boolean; + host?: string; +} diff --git a/packages/contentstack-config/src/utils/common-utilities.ts b/packages/contentstack-config/src/utils/common-utilities.ts new file mode 100644 index 0000000000..1dcead8f66 --- /dev/null +++ b/packages/contentstack-config/src/utils/common-utilities.ts @@ -0,0 +1,7 @@ +export const limitNamesConfig = ['getLimit', 'limit', 'bulkLimit']; + +export const defaultRalteLimitConfig = { + getLimit: { value: 10, utilize: 50 }, + limit: { value: 10, utilize: 50 }, + bulkLimit: { value: 1, utilize: 50 }, +}; diff --git a/packages/contentstack-config/src/utils/interactive.ts b/packages/contentstack-config/src/utils/interactive.ts index 04b32e9047..0beb8c7eba 100644 --- a/packages/contentstack-config/src/utils/interactive.ts +++ b/packages/contentstack-config/src/utils/interactive.ts @@ -96,3 +96,11 @@ export async function askEarlyAccessHeaderAlias(): Promise { validate: inquireRequireFieldValidation, }); } + +export const askOrgID = async (): Promise => { + return cliux.inquire({ + type: 'input', + message: 'Provide the organization UID', + name: 'org', + }); +}; diff --git a/packages/contentstack-config/src/utils/rate-limit-handler.ts b/packages/contentstack-config/src/utils/rate-limit-handler.ts new file mode 100644 index 0000000000..37ee116525 --- /dev/null +++ b/packages/contentstack-config/src/utils/rate-limit-handler.ts @@ -0,0 +1,72 @@ +import { cliux, configHandler } from '@contentstack/cli-utilities'; +import { limitNamesConfig, defaultRalteLimitConfig } from '../utils/common-utilities'; +import { Limit } from '../interfaces'; + +let client: any; + +export class RateLimitHandler { + setClient(managementSDKClient) { + client = managementSDKClient; + } + + async setRateLimit(config) { + const rateLimit = configHandler.get('rateLimit'); + rateLimit.default = { ...defaultRalteLimitConfig }; + + if (config.default) { + rateLimit[config.org] = { ...rateLimit.default }; + configHandler.set('rateLimit', rateLimit); + cliux.success(`Rate limit reset to default for org: ${config.org}`); + return; + } + + if (!rateLimit[config.org]) { + rateLimit[config.org] = { ...rateLimit.default }; + } + const limitNames = Array.isArray(config['limit-name']) ? config['limit-name'] : []; + const utilizeValues = Array.isArray(config.utilize) ? config.utilize.map((v) => Number(v)) : []; + const unavailableLimits = []; + + try { + const organizations = await client.organization(config.org).fetch({ include_plan: true }); + const features = organizations.plan?.features || []; + + const limitsToUpdate: { [key: string]: Limit } = { ...rateLimit[config.org] }; + let utilizationMap = {}; + limitNames.forEach((name, index) => { + if (utilizeValues[index] !== undefined) { + utilizationMap[name] = utilizeValues[index]; + } + }); + + limitNamesConfig.forEach((limitName) => { + const feature = features.find((f: { uid: string }) => f.uid === limitName); + if (feature) { + limitsToUpdate[limitName] = { + value: feature.limit || rateLimit[config.org][limitName]?.value || rateLimit.default[limitName]?.value, + utilize: utilizationMap[limitName] || defaultRalteLimitConfig[limitName]?.utilize, + }; + } else { + unavailableLimits.push(limitName); + } + }); + + if (unavailableLimits.length > 0) { + cliux.print(`You have not subscribed to these limits: ${unavailableLimits.join(', ')}`, { + color: 'yellow', + }); + } + rateLimit[config.org] = limitsToUpdate; + configHandler.set('rateLimit', rateLimit); + cliux.success(`Rate limit has been set successfully for org: ${config.org}`); + + Object.entries(limitsToUpdate).forEach(([limit, { value, utilize }]) => { + if (!unavailableLimits.includes(limit)) { + cliux.success(`${limit}: ${value}(${utilize}%)`); + } + }); + } catch (error) { + throw new Error(error); + } + } +} diff --git a/packages/contentstack-config/test/unit/commands/rate-limit.test.ts b/packages/contentstack-config/test/unit/commands/rate-limit.test.ts new file mode 100644 index 0000000000..8f0a1e8685 --- /dev/null +++ b/packages/contentstack-config/test/unit/commands/rate-limit.test.ts @@ -0,0 +1,178 @@ +import { expect } from 'chai'; +import { stub, restore } from 'sinon'; // Import restore for cleaning up +import { cliux, configHandler, isAuthenticated } from '@contentstack/cli-utilities'; +import SetRateLimitCommand from '../../../src/commands/config/set/rate-limit'; +import GetRateLimitCommand from '../../../src/commands/config/get/rate-limit'; +import RemoveRateLimitCommand from '../../../src/commands/config/remove/rate-limit'; +import { askOrgID } from '../../../src/utils/interactive'; +import { RateLimitHandler } from '../../../src/utils/rate-limit-handler'; +import { defaultRalteLimitConfig } from '../../../src/utils/common-utilities'; + +describe('Rate Limit Commands', () => { + let originalCliuxError: typeof cliux.error; + let originalCliuxPrint: typeof cliux.print; + let originalIsAuthenticated: () => boolean; + let errorMessage: any; + let printMessage: any; + let authenticated = isAuthenticated; + let rateLimitHandler: RateLimitHandler; + let mockClient: any; + + beforeEach(() => { + originalCliuxError = cliux.error; + originalCliuxPrint = cliux.print; + originalIsAuthenticated = isAuthenticated; + + cliux.error = (message: string) => { + errorMessage = message; + }; + cliux.print = (message: string) => { + printMessage = message; + }; + rateLimitHandler = new RateLimitHandler(); + mockClient = { + organization: stub().returns({ + fetch: stub().resolves({ plan: { features: [{ uid: 'getLimit' }, { uid: 'bulkLimit' }] } }), + }), + }; + rateLimitHandler.setClient(mockClient); + restore(); + + restore(); + }); + + afterEach(() => { + cliux.error = originalCliuxError; + cliux.print = originalCliuxPrint; + authenticated = originalIsAuthenticated; + }); + + describe('Set Rate Limit Command', () => { + it('Set Rate Limit: with all flags, should be successful', async () => { + const stub1 = stub(SetRateLimitCommand.prototype, 'run').resolves(); + const args = ['--org', 'test-org-id', '--utilize', '70,80', '--limit-name', 'getLimit,bulkLimit']; + await SetRateLimitCommand.run(args); + expect(stub1.calledOnce).to.be.true; + }); + + it('Set Rate Limit: should handle invalid utilization percentages', async () => { + const args = ['--org', 'test-org-id', '--utilize', '150', '--limit-name', 'getLimit']; + await SetRateLimitCommand.run(args); + expect(errorMessage).to.equal('Utilize percentages must be numbers between 0 and 100.'); + }); + + it('Set Rate Limit: should handle mismatch between utilize percentages and limit names', async () => { + const args = ['--org', 'test-org-id', '--utilize', '70', '--limit-name', 'getLimit,postLimit']; + await SetRateLimitCommand.run(args); + expect(errorMessage).to.equal( + 'The number of utilization percentages must match the number of limit names provided.', + ); + }); + + it('Set Rate Limit: should handle invalid number of limit names', async () => { + const args = ['--org', 'test-org-id', '--utilize', '70,80', '--limit-name', 'getLimit']; + await SetRateLimitCommand.run(args); + expect(errorMessage).to.equal( + 'The number of utilization percentages must match the number of limit names provided.', + ); + }); + + it('Set Rate Limit: should prompt for the organization UID', async () => { + const inquireStub = stub(cliux, 'inquire').resolves('test-org-id'); + const orgID = await askOrgID(); + expect(orgID).to.equal('test-org-id'); + inquireStub.restore(); + }); + + it('Set Rate Limit: should handle API client failure gracefully', async () => { + const handler = new RateLimitHandler(); + handler.setClient({ + organization: () => { + throw new Error('Client Error'); + }, + }); + const config = { org: 'test-org-id', utilize: ['70'], 'limit-name': ['getLimit'] }; + await handler.setRateLimit(config); + expect(errorMessage).to.include('Error: Unable to set the rate limit'); + }); + + it('Set Rate Limit: should handle unauthenticated user', async () => { + const isAuthenticatedStub = stub().returns(false); + authenticated = isAuthenticatedStub; + const args = ['--org', 'test-org-id', '--utilize', '70,80', '--limit-name', 'getLimit,bulkLimit']; + try { + await SetRateLimitCommand.run(args); + } catch (error) { + expect(errorMessage).to.equal('You are not logged in. Please login with command $ csdx auth:login'); + expect(error?.code).to.equal(1); + } + }); + it('should set default rate limit for organization', async () => { + const config = { org: 'test-org-id', default: true }; + await rateLimitHandler.setRateLimit(config); + const rateLimit = configHandler.get('rateLimit'); + expect(rateLimit['test-org-id']).to.deep.equal(defaultRalteLimitConfig); + }); + + it('should set rate limit when only utilization percentages are provided', async () => { + const config = { + org: 'test-org-id', + utilize: ['70'], + 'limit-name': ['getLimit'], + }; + await rateLimitHandler.setRateLimit(config); + const rateLimit = configHandler.get('rateLimit'); + expect(rateLimit['test-org-id']['getLimit'].utilize).to.equal(70); + }); + }); + + describe('Get Rate Limit Command', () => { + const rateLimit = { + 'test-org-id': { + getLimit: { value: 10, utilize: 70 }, + bulkLimit: { value: 1, utilize: 80 }, + }, + }; + + it('Get Rate Limit: should print the rate limit for the given organization', async () => { + configHandler.set('rateLimit', rateLimit); + await GetRateLimitCommand.run(['--org', 'test-org-id']); + expect(printMessage).to.include(' test-org-id 10(70%) 0 1(80%) '); + }); + + it('Get Rate Limit: should throw an error if the organization is not found', async () => { + configHandler.set('rateLimit', {}); + try { + await GetRateLimitCommand.run(['--org', 'non-existent-org']); + } catch (error) { + expect(errorMessage).to.equal('Error: Organization not found'); + } + }); + }); + + describe('Remove Rate Limit Command', () => { + const rateLimit = { + 'test-org-id': { + getLimit: { value: 10, utilize: 70 }, + bulkLimit: { value: 1, utilize: 80 }, + }, + }; + + it('Remove Rate Limit: should remove the rate limit for the given organization', async () => { + configHandler.set('rateLimit', rateLimit); + await RemoveRateLimitCommand.run(['--org', 'test-org-id']); + const updatedRateLimit = configHandler.get('rateLimit'); + expect(updatedRateLimit['test-org-id']).to.be.undefined; + expect(printMessage).to.equal('Rate limit entry for organization UID test-org-id has been removed.'); + }); + + it('Remove Rate Limit: should throw an error if the organization is not found', async () => { + configHandler.set('rateLimit', {}); + try { + await RemoveRateLimitCommand.run(['--org', 'non-existent-org']); + } catch (error) { + expect(errorMessage).to.equal('Error: Organization not found'); + } + }); + }); +}); diff --git a/packages/contentstack-export/README.md b/packages/contentstack-export/README.md index 71fe5f1f73..719360825f 100755 --- a/packages/contentstack-export/README.md +++ b/packages/contentstack-export/README.md @@ -48,7 +48,7 @@ $ npm install -g @contentstack/cli-cm-export $ csdx COMMAND running command... $ csdx (--version) -@contentstack/cli-cm-export/1.14.0 darwin-arm64 node-v22.2.0 +@contentstack/cli-cm-export/1.14.1 darwin-arm64 node-v22.2.0 $ csdx --help [COMMAND] USAGE $ csdx COMMAND diff --git a/packages/contentstack-export/package.json b/packages/contentstack-export/package.json index f2807ddbf4..aca3b69cd6 100644 --- a/packages/contentstack-export/package.json +++ b/packages/contentstack-export/package.json @@ -1,12 +1,12 @@ { "name": "@contentstack/cli-cm-export", "description": "Contentstack CLI plugin to export content from stack", - "version": "1.14.0", + "version": "1.14.1", "author": "Contentstack", "bugs": "https://github.com/contentstack/cli/issues", "dependencies": { "@contentstack/cli-command": "~1.3.2", - "@contentstack/cli-variants": "~1.1.0", + "@contentstack/cli-variants": "~1.1.1", "@contentstack/cli-utilities": "~1.8.0", "@oclif/core": "^3.26.5", "async": "^3.2.4", @@ -26,7 +26,7 @@ }, "devDependencies": { "@contentstack/cli-auth": "~1.3.22", - "@contentstack/cli-config": "~1.7.3", + "@contentstack/cli-config": "~1.8.0", "@contentstack/cli-dev-dependencies": "~1.2.4", "@oclif/plugin-help": "^5.1.19", "@oclif/test": "^2.5.6", diff --git a/packages/contentstack-import/README.md b/packages/contentstack-import/README.md index 7a8b367abf..d5cc0408eb 100644 --- a/packages/contentstack-import/README.md +++ b/packages/contentstack-import/README.md @@ -47,7 +47,7 @@ $ npm install -g @contentstack/cli-cm-import $ csdx COMMAND running command... $ csdx (--version) -@contentstack/cli-cm-import/1.19.0 darwin-arm64 node-v22.2.0 +@contentstack/cli-cm-import/1.19.1 darwin-arm64 node-v22.2.0 $ csdx --help [COMMAND] USAGE $ csdx COMMAND diff --git a/packages/contentstack-import/package.json b/packages/contentstack-import/package.json index 9024cd8a4f..5c30eedaf3 100644 --- a/packages/contentstack-import/package.json +++ b/packages/contentstack-import/package.json @@ -1,7 +1,7 @@ { "name": "@contentstack/cli-cm-import", "description": "Contentstack CLI plugin to import content into stack", - "version": "1.19.0", + "version": "1.19.1", "author": "Contentstack", "bugs": "https://github.com/contentstack/cli/issues", "dependencies": { @@ -9,7 +9,7 @@ "@contentstack/cli-command": "~1.3.2", "@contentstack/cli-utilities": "~1.8.0", "@contentstack/management": "~1.17.0", - "@contentstack/cli-variants": "~1.1.0", + "@contentstack/cli-variants": "~1.1.1", "@oclif/core": "^3.26.5", "big-json": "^3.2.0", "bluebird": "^3.7.2", diff --git a/packages/contentstack-launch/package.json b/packages/contentstack-launch/package.json index 9c04c997c4..d31663225d 100755 --- a/packages/contentstack-launch/package.json +++ b/packages/contentstack-launch/package.json @@ -21,10 +21,10 @@ "@contentstack/cli-command": "~1.3.2", "@contentstack/cli-utilities": "~1.8.0", "@oclif/core": "^3.27.0", - "@oclif/plugin-help": "^5", + "@oclif/plugin-help": "^5.2.20", "@oclif/plugin-plugins": "^5.4.14", "@types/express": "^4.17.21", - "@types/express-serve-static-core": "^4.19.6", + "@types/express-serve-static-core": "^4.17.34", "adm-zip": "^0.5.16", "chalk": "^4.1.2", "cross-fetch": "^3.1.8", diff --git a/packages/contentstack-seed/package.json b/packages/contentstack-seed/package.json index 6209e20c41..cc81afc951 100644 --- a/packages/contentstack-seed/package.json +++ b/packages/contentstack-seed/package.json @@ -5,7 +5,7 @@ "author": "Contentstack", "bugs": "https://github.com/contentstack/cli/issues", "dependencies": { - "@contentstack/cli-cm-import": "~1.19.0", + "@contentstack/cli-cm-import": "~1.19.1", "@contentstack/cli-command": "~1.3.2", "@contentstack/cli-utilities": "~1.8.0", "inquirer": "8.2.4", diff --git a/packages/contentstack-variants/.gitignore b/packages/contentstack-variants/.gitignore index e0f971471f..fca81bd236 100644 --- a/packages/contentstack-variants/.gitignore +++ b/packages/contentstack-variants/.gitignore @@ -8,4 +8,4 @@ node_modules .DS_Store coverage -/tsconfig.tsbuildinfo \ No newline at end of file +/tsconfig.tsbuildinfo diff --git a/packages/contentstack-variants/package.json b/packages/contentstack-variants/package.json index f76506fa06..5cc360a5d0 100644 --- a/packages/contentstack-variants/package.json +++ b/packages/contentstack-variants/package.json @@ -1,6 +1,6 @@ { "name": "@contentstack/cli-variants", - "version": "1.1.0", + "version": "1.1.1", "description": "Variants plugin", "main": "lib/index.js", "types": "lib/index.d.ts", diff --git a/packages/contentstack-variants/src/import/variant-entries.ts b/packages/contentstack-variants/src/import/variant-entries.ts index 7f78f572a4..9cff1da62a 100644 --- a/packages/contentstack-variants/src/import/variant-entries.ts +++ b/packages/contentstack-variants/src/import/variant-entries.ts @@ -56,14 +56,12 @@ export default class VariantEntries extends VariantAdapter] + +FLAGS + --org= Provide the organization UID + +DESCRIPTION + Remove rate-limit of the organization + +EXAMPLES + $ csdx config:remove:rate-limit --org <> +``` + +_See code: [@contentstack/cli-config](https://github.com/contentstack/cli/blob/main/packages/contentstack-config/src/commands/config/remove/rate-limit.ts)_ + ## `csdx config:set:base-branch` Set branch for CLI @@ -3157,6 +3197,33 @@ EXAMPLES _See code: [@contentstack/cli-config](https://github.com/contentstack/cli/blob/main/packages/contentstack-config/src/commands/config/set/early-access-header.ts)_ +## `csdx config:set:rate-limit` + +Set rate-limit for CLI + +``` +USAGE + $ csdx config:set:rate-limit [--org ] [--utilize ] [--limit-name ...] [--default] + +FLAGS + --default Reset to default rate limit + --limit-name=... [Optional] Provide the limit names separated by commas ['limit', 'getLimit', 'bulkLimit'] + --org= Provide the organization UID + --utilize= [default: 50] Provide the utilization percentages for rate limit, separated by commas + +DESCRIPTION + Set rate-limit for CLI + +EXAMPLES + $ csdx config:set:rate-limit --org <> + + $ csdx config:set:rate-limit --org <> --utilize 70,80 --limit-name getLimit,limit + + $ csdx config:set:rate-limit --org <> --default +``` + +_See code: [@contentstack/cli-config](https://github.com/contentstack/cli/blob/main/packages/contentstack-config/src/commands/config/set/rate-limit.ts)_ + ## `csdx config:set:region [REGION]` Set region for CLI diff --git a/packages/contentstack/package.json b/packages/contentstack/package.json index dc6adf0869..8d842be637 100755 --- a/packages/contentstack/package.json +++ b/packages/contentstack/package.json @@ -1,7 +1,7 @@ { "name": "@contentstack/cli", "description": "Command-line tool (CLI) to interact with Contentstack", - "version": "1.27.1", + "version": "1.28.0", "author": "Contentstack", "bin": { "csdx": "./bin/run.js" @@ -25,21 +25,21 @@ "@contentstack/cli-audit": "~1.7.2", "@contentstack/cli-auth": "~1.3.22", "@contentstack/cli-cm-bootstrap": "~1.13.0", - "@contentstack/cli-cm-branches": "~1.1.4", - "@contentstack/cli-cm-bulk-publish": "~1.4.9", - "@contentstack/cli-cm-export": "~1.14.0", + "@contentstack/cli-cm-branches": "~1.2.0", + "@contentstack/cli-cm-bulk-publish": "~1.5.0", + "@contentstack/cli-cm-export": "~1.14.1", "@contentstack/cli-cm-clone": "~1.13.0", "@contentstack/cli-cm-export-to-csv": "~1.7.3", - "@contentstack/cli-cm-import": "~1.19.0", + "@contentstack/cli-cm-import": "~1.19.1", "@contentstack/cli-cm-migrate-rte": "~1.4.20", "@contentstack/cli-cm-seed": "~1.10.0", "@contentstack/cli-command": "~1.3.2", - "@contentstack/cli-config": "~1.7.3", + "@contentstack/cli-config": "~1.8.0", "@contentstack/cli-launch": "~1.2.3", "@contentstack/cli-migration": "~1.6.3", "@contentstack/cli-utilities": "~1.8.0", "@contentstack/management": "~1.17.0", - "@contentstack/cli-variants": "~1.1.0", + "@contentstack/cli-variants": "~1.1.1", "@oclif/core": "^3.26.5", "@oclif/plugin-help": "^5", "@oclif/plugin-not-found": "^2.4.0", @@ -152,7 +152,8 @@ ], "hooks": { "prerun": [ - "./lib/hooks/prerun/command-deprecation-check" + "./lib/hooks/prerun/command-deprecation-check", + "./lib/hooks/prerun/default-rate-limit-check" ], "init": [ "./lib/hooks/init/context-init", diff --git a/packages/contentstack/src/hooks/prerun/default-rate-limit-check.ts b/packages/contentstack/src/hooks/prerun/default-rate-limit-check.ts new file mode 100644 index 0000000000..4a1e368beb --- /dev/null +++ b/packages/contentstack/src/hooks/prerun/default-rate-limit-check.ts @@ -0,0 +1,19 @@ +import { cliux, configHandler } from '@contentstack/cli-utilities'; + +export default function (): void { + const rateLimit = configHandler.get('rateLimit'); + if (!rateLimit?.default) { + const defaultPlan = { + getLimit: { value: 10, utilize: 50 }, + limit: { value: 10, utilize: 50 }, + bulkLimit: { value: 1, utilize: 50 }, + }; + configHandler.set('rateLimit', { default: defaultPlan }); + cliux.print( + `Default rate limit configuration is set to ${JSON.stringify( + defaultPlan, + )}. Please use this command csdx config:set:rate-limit to set the custom rate limit config.`, + { color: 'blue' }, + ); + } +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 86b8e8ce31..695cc8097f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -13,20 +13,20 @@ importers: '@contentstack/cli-audit': ~1.7.2 '@contentstack/cli-auth': ~1.3.22 '@contentstack/cli-cm-bootstrap': ~1.13.0 - '@contentstack/cli-cm-branches': ~1.1.4 - '@contentstack/cli-cm-bulk-publish': ~1.4.9 + '@contentstack/cli-cm-branches': ~1.2.0 + '@contentstack/cli-cm-bulk-publish': ~1.5.0 '@contentstack/cli-cm-clone': ~1.13.0 - '@contentstack/cli-cm-export': ~1.14.0 + '@contentstack/cli-cm-export': ~1.14.1 '@contentstack/cli-cm-export-to-csv': ~1.7.3 - '@contentstack/cli-cm-import': ~1.19.0 + '@contentstack/cli-cm-import': ~1.19.1 '@contentstack/cli-cm-migrate-rte': ~1.4.20 '@contentstack/cli-cm-seed': ~1.10.0 '@contentstack/cli-command': ~1.3.2 - '@contentstack/cli-config': ~1.7.3 + '@contentstack/cli-config': ~1.8.0 '@contentstack/cli-launch': ~1.2.3 '@contentstack/cli-migration': ~1.6.3 '@contentstack/cli-utilities': ~1.8.0 - '@contentstack/cli-variants': ~1.1.0 + '@contentstack/cli-variants': ~1.1.1 '@contentstack/management': ~1.17.0 '@oclif/core': ^3.26.5 '@oclif/plugin-help': ^5 @@ -304,7 +304,7 @@ importers: specifiers: '@contentstack/cli-auth': ~1.3.22 '@contentstack/cli-command': ~1.3.2 - '@contentstack/cli-config': ~1.7.3 + '@contentstack/cli-config': ~1.8.0 '@contentstack/cli-dev-dependencies': ~1.2.4 '@contentstack/cli-utilities': ~1.8.0 '@oclif/core': ^3.26.5 @@ -425,8 +425,8 @@ importers: packages/contentstack-clone: specifiers: '@colors/colors': ^1.5.0 - '@contentstack/cli-cm-export': ~1.14.0 - '@contentstack/cli-cm-import': ~1.19.0 + '@contentstack/cli-cm-export': ~1.14.1 + '@contentstack/cli-cm-import': ~1.19.1 '@contentstack/cli-command': ~1.3.2 '@contentstack/cli-utilities': ~1.8.0 '@oclif/test': ^2.5.6 @@ -610,10 +610,10 @@ importers: specifiers: '@contentstack/cli-auth': ~1.3.22 '@contentstack/cli-command': ~1.3.2 - '@contentstack/cli-config': ~1.7.3 + '@contentstack/cli-config': ~1.8.0 '@contentstack/cli-dev-dependencies': ~1.2.4 '@contentstack/cli-utilities': ~1.8.0 - '@contentstack/cli-variants': ~1.1.0 + '@contentstack/cli-variants': ~1.1.1 '@oclif/core': ^3.26.5 '@oclif/plugin-help': ^5.1.19 '@oclif/test': ^2.5.6 @@ -737,7 +737,7 @@ importers: '@contentstack/cli-audit': ~1.7.2 '@contentstack/cli-command': ~1.3.2 '@contentstack/cli-utilities': ~1.8.0 - '@contentstack/cli-variants': ~1.1.0 + '@contentstack/cli-variants': ~1.1.1 '@contentstack/management': ~1.17.0 '@oclif/core': ^3.26.5 '@oclif/test': ^2.5.6 @@ -829,14 +829,14 @@ importers: '@contentstack/cli-command': ~1.3.2 '@contentstack/cli-utilities': ~1.8.0 '@oclif/core': ^3.27.0 - '@oclif/plugin-help': ^5 + '@oclif/plugin-help': ^5.2.20 '@oclif/plugin-plugins': ^5.4.14 '@oclif/test': ^2.5.6 '@types/adm-zip': ^0.5.5 '@types/chai': ^4.3.20 '@types/esm': ^3.2.2 '@types/express': ^4.17.21 - '@types/express-serve-static-core': ^4.19.6 + '@types/express-serve-static-core': ^4.17.34 '@types/ini': ^1.3.34 '@types/lodash': ^4.17.10 '@types/node': ^16.18.113 @@ -876,7 +876,7 @@ importers: dotenv: 16.4.5 esm: 3.2.25 express: 4.21.1 - form-data: 4.0.0 + form-data: 4.0.1 graphql: 16.9.0 ini: 3.0.1 lodash: 4.17.21 @@ -996,7 +996,7 @@ importers: packages/contentstack-seed: specifiers: - '@contentstack/cli-cm-import': ~1.19.0 + '@contentstack/cli-cm-import': ~1.19.1 '@contentstack/cli-command': ~1.3.2 '@contentstack/cli-utilities': ~1.8.0 '@oclif/plugin-help': ^5.1.19 @@ -1643,7 +1643,7 @@ packages: engines: {node: '>=8.0.0'} dependencies: axios: 1.7.7_debug@4.3.7 - form-data: 3.0.1 + form-data: 3.0.2 lodash: 4.17.21 qs: 6.13.0 transitivePeerDependencies: @@ -4743,7 +4743,7 @@ packages: resolution: {integrity: sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==} dependencies: follow-redirects: 1.15.9 - form-data: 4.0.0 + form-data: 4.0.1 proxy-from-env: 1.1.0 transitivePeerDependencies: - debug @@ -4753,7 +4753,7 @@ packages: resolution: {integrity: sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==} dependencies: follow-redirects: 1.15.9_debug@4.3.7 - form-data: 4.0.0 + form-data: 4.0.1 proxy-from-env: 1.1.0 transitivePeerDependencies: - debug @@ -4942,7 +4942,7 @@ packages: hasBin: true dependencies: caniuse-lite: 1.0.30001667 - electron-to-chromium: 1.5.34 + electron-to-chromium: 1.5.35 node-releases: 2.0.18 update-browserslist-db: 1.1.1_browserslist@4.24.0 dev: true @@ -6188,8 +6188,8 @@ packages: dependencies: jake: 10.9.2 - /electron-to-chromium/1.5.34: - resolution: {integrity: sha512-/TZAiChbAflBNjCg+VvstbcwAtIL/VdMFO3NgRFIzBjpvPzWOTIbbO8kNb6RwU4bt9TP7K+3KqBKw/lOU+Y+GA==} + /electron-to-chromium/1.5.35: + resolution: {integrity: sha512-hOSRInrIDm0Brzp4IHW2F/VM+638qOL2CzE0DgpnGzKW27C95IqqeqgKz/hxHGnvPxvQGpHUGD5qRVC9EZY2+A==} dev: true /elegant-spinner/1.0.1: @@ -7793,8 +7793,8 @@ packages: cross-spawn: 7.0.3 signal-exit: 4.1.0 - /form-data/3.0.1: - resolution: {integrity: sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==} + /form-data/3.0.2: + resolution: {integrity: sha512-sJe+TQb2vIaIyO783qN6BlMYWMw3WBOHA1Ay2qxsnjuafEOQFJ2JakedOQirT6D5XPRxDvS7AHYyem9fTpb4LQ==} engines: {node: '>= 6'} dependencies: asynckit: 0.4.0 @@ -7802,8 +7802,8 @@ packages: mime-types: 2.1.35 dev: false - /form-data/4.0.0: - resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==} + /form-data/4.0.1: + resolution: {integrity: sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==} engines: {node: '>= 6'} dependencies: asynckit: 0.4.0 @@ -9752,7 +9752,7 @@ packages: decimal.js: 10.4.3 domexception: 4.0.0 escodegen: 2.1.0 - form-data: 4.0.0 + form-data: 4.0.1 html-encoding-sniffer: 3.0.0 http-proxy-agent: 5.0.0 https-proxy-agent: 5.0.1