diff --git a/.github/workflows/unit-test.yml b/.github/workflows/unit-test.yml index 05b9244a97..5d2d76c2a4 100644 --- a/.github/workflows/unit-test.yml +++ b/.github/workflows/unit-test.yml @@ -54,13 +54,12 @@ jobs: - name: Run tests for Contentstack Auth working-directory: ./packages/contentstack-auth - run: npm run test + run: npm run test:unit # - name: Run tests for Contentstack Import Setup # working-directory: ./packages/contentstack-import-setup # run: npm run test:unit - - name: Run tests for Contentstack Bulk Publish working-directory: ./packages/contentstack-bulk-publish run: npm run test:unit diff --git a/.talismanrc b/.talismanrc index 758cb4dca1..80faf4a8bd 100644 --- a/.talismanrc +++ b/.talismanrc @@ -2,7 +2,7 @@ fileignoreconfig: - filename: package-lock.json checksum: 5e64367e6f00c41d8fec66e335f66202d97a0e75006c9ecd331ce8f5856e296a - filename: pnpm-lock.yaml - checksum: aa6177859aaa87caf2892e8034657fd485c3abe7c13a833fd28449a1d33fa950 + checksum: 050da770b23a0ca135648f7c857f4511fda57a6c125906698d7cf2e2efdeacf7 - filename: packages/contentstack-import-setup/test/unit/backup-handler.test.ts checksum: 0582d62b88834554cf12951c8690a73ef3ddbb78b82d2804d994cf4148e1ef93 - filename: packages/contentstack-import-setup/test/config.json @@ -78,7 +78,7 @@ fileignoreconfig: - filename: packages/contentstack-clone/src/commands/cm/stacks/clone.js checksum: 433a84a882ea3f12b27127d47d289dfc64dda6b6fc956369f5851daaa57ae493 - filename: packages/contentstack-clone/src/lib/util/clone-handler.js - checksum: 7024f22a6ed3908d7cf074bbd8e7107e2d9f43bbcc42939b28d360c89d44cc29 + checksum: f901c84eac8545b328952332216de516697da2de098298496ba6ff1e75a0a659 - filename: packages/contentstack-bulk-publish/src/util/generate-bulk-publish-url.js checksum: 5f7c1e2fac3e7fab21e861d609c54ca7191ee09fd076dd0adc66604043bf7a43 - filename: packages/contentstack-import/src/utils/interactive.ts @@ -141,8 +141,6 @@ fileignoreconfig: checksum: 93bdd99ee566fd38545b38a8b528947af1d42a31908aca85e2cb221e39a5b6cc - filename: packages/contentstack-export/test/unit/export/modules/stack.test.ts checksum: bb0f20845d85fd56197f1a8c67b8f71c57dcd1836ed9cfd86d1f49f41e84d3a0 - - filename: packages/contentstack-export/test/unit/export/modules/taxonomies.test.ts - checksum: 5b1d2ba5ec9100fd6174e9c6771b7e49c93a09fa2d6aedadd338e56bc3e3610f - filename: packages/contentstack-export/test/unit/export/modules/custom-roles.test.ts checksum: 39f0166a8030ee8f504301f3a42cc71b46ddc027189b90029ef19800b79a46e5 - filename: packages/contentstack-export/test/unit/export/modules/workflows.test.ts @@ -179,16 +177,6 @@ fileignoreconfig: checksum: a5cd371d7f327c083027da4157b3c5b4df548f2c2c3ad6193aa133031994252e - filename: packages/contentstack-import/test/unit/utils/common-helper.test.ts checksum: 61b3cfe0c0571dcc366e372990e3c11ced2b49703ac88155110d33897e58ca5d - - filename: packages/contentstack-import/test/unit/import/module-importer.test.ts - checksum: aa265917b806286c8d4d1d3f422cf5d6736a0cf6a5f50f2e9c04ec0f81eee376 - - filename: packages/contentstack-export/test/unit/utils/interactive.test.ts - checksum: b619744ebba28dbafe3a0e65781a61a6823ccaa3eb84e2b380a323c105324c1a - - filename: packages/contentstack-import/test/unit/import/modules/index.test.ts - checksum: aab773ccbe05b990a4b934396ee2fcd2a780e7d886d080740cfddd8a4d4f73f7 - - filename: packages/contentstack-import/test/unit/import/modules/personalize.test.ts - checksum: ea4140a1516630fbfcdd61c4fe216414b733b4df2410b5d090d58ab1a22e7dbf - - filename: packages/contentstack-import/test/unit/import/modules/variant-entries.test.ts - checksum: abcc2ce0b305afb655eb46a1652b3d9e807a2a2e0eef1caeb16c8ae83af4f1a1 - filename: packages/contentstack-import/test/unit/utils/import-path-resolver.test.ts checksum: 05436c24619b2d79b51eda9ce9a338182cc69b078ede60d310bfd55a62db8369 - filename: packages/contentstack-import/test/unit/utils/interactive.test.ts @@ -201,10 +189,17 @@ fileignoreconfig: checksum: eca2702d1f7ed075b9b857964b9e56f69b16e4a31942423d6b1265e4bf398db5 - filename: packages/contentstack-import/test/unit/utils/logger.test.ts checksum: 794e06e657a7337c8f094d6042fb04c779683f97b860efae14e075098d2af024 + - filename: packages/contentstack-export/test/unit/utils/marketplace-app-helper.test.ts + checksum: c454b0f52739cb9adef3d44f5ce123826f6c78d7709bd84eb281f84fb3a46606 + - filename: packages/contentstack-export/test/unit/export/modules/labels.test.ts + checksum: 978b2e96ee2682286b9aee6d76de0caa5a42c9e9371cb4041340f4e5f6f6ca1b + - filename: packages/contentstack-export/test/unit/export/modules/marketplace-apps.test.ts + checksum: 720d0b915078ceecc153e352fdb28850e7ea29fe0cd317643f55906f83e0bdbd - filename: packages/contentstack-import-setup/src/import/modules/taxonomies.ts checksum: c1bccc885b3f41f187f150c739b4bbd1608b01f09b0d9be0ad9214127cac071d - filename: packages/contentstack-import-setup/src/commands/cm/stacks/import-setup.ts checksum: 06035980b36802260f190af6e63632efe167f5b336693163f59268f3e788fba1 - filename: packages/contentstack-import-setup/src/utils/constants.ts checksum: fcfabb4c53ee822e05903db77595413842d656b55e2869bae97bb6c0e0e209c3 + version: '1.0' diff --git a/LICENSE b/LICENSE index 25403cd591..aff1142eed 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2025 Contentstack +Copyright (c) 2026 Contentstack Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/MIGRATION.md b/MIGRATION.md index 2eebeba746..98c4621478 100644 --- a/MIGRATION.md +++ b/MIGRATION.md @@ -130,6 +130,31 @@ csdx cm:stacks:migration -k b*******9ca0 --file-path "../contentstack-migration/ **Migration Action:** use the import/export commands instead. +### 5. 🔌 HTML RTE to JSON RTE Migration (Separate Plugin) + +**What Changed:** +- HTML RTE to JSON RTE migration has been extracted into a separate plugin +- Now requires separate installation as `@contentstack/cli-cm-migrate-rte` + +**Installation:** + +```bash +npm install -g @contentstack/cli-cm-migrate-rte +``` + +**Commands:** + +```bash +# Migrate HTML RTE to JSON RTE +csdx cm:entries:migrate-html-rte --config-path path/to/config.json + +# Or using alias +csdx cm:migrate-rte --config-path path/to/config.json +``` + +**Migration Action:** +- Install `@contentstack/cli-cm-migrate-rte` separately if you use RTE migration + ## Troubleshooting ### Common Issues diff --git a/package-lock.json b/package-lock.json index fd0ab74499..90f346ac8a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1038,6 +1038,9 @@ } }, "node_modules/@aws/lambda-invoke-store": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@aws/lambda-invoke-store/-/lambda-invoke-store-0.2.2.tgz", + "integrity": "sha512-C0NBLsIqzDIae8HFw9YIrIBsbc0xTiOtt7fAukGPnqQ/+zZNaq+4jhuccltK0QuWHBnNm/a6kLIRA6GFiM10eg==", "version": "0.2.2", "resolved": "https://registry.npmjs.org/@aws/lambda-invoke-store/-/lambda-invoke-store-0.2.2.tgz", "integrity": "sha512-C0NBLsIqzDIae8HFw9YIrIBsbc0xTiOtt7fAukGPnqQ/+zZNaq+4jhuccltK0QuWHBnNm/a6kLIRA6GFiM10eg==", @@ -1805,6 +1808,9 @@ } }, "node_modules/@contentstack/utils": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/@contentstack/utils/-/utils-1.6.3.tgz", + "integrity": "sha512-FU1hFks9vnJ5e9cwBTPgnf3obx/fuKh+c3Gtc71mq1Mrub3/z4rJZJWLJ2kublVKnXWnhz+Yt66rshxO/TT9IQ==", "version": "1.6.3", "resolved": "https://registry.npmjs.org/@contentstack/utils/-/utils-1.6.3.tgz", "integrity": "sha512-FU1hFks9vnJ5e9cwBTPgnf3obx/fuKh+c3Gtc71mq1Mrub3/z4rJZJWLJ2kublVKnXWnhz+Yt66rshxO/TT9IQ==", @@ -1846,6 +1852,9 @@ } }, "node_modules/@emnapi/core": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.7.1.tgz", + "integrity": "sha512-o1uhUASyo921r2XtHYOHy7gdkGLge8ghBEQHMWmyJFoXlpU58kIrhhN3w26lpQb6dspetweapMn2CSNwQ8I4wg==", "version": "1.7.1", "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.7.1.tgz", "integrity": "sha512-o1uhUASyo921r2XtHYOHy7gdkGLge8ghBEQHMWmyJFoXlpU58kIrhhN3w26lpQb6dspetweapMn2CSNwQ8I4wg==", @@ -1858,6 +1867,9 @@ } }, "node_modules/@emnapi/runtime": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.7.1.tgz", + "integrity": "sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA==", "version": "1.7.1", "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.7.1.tgz", "integrity": "sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA==", @@ -2483,6 +2495,9 @@ } }, "node_modules/@eslint/css-tree": { + "version": "3.6.8", + "resolved": "https://registry.npmjs.org/@eslint/css-tree/-/css-tree-3.6.8.tgz", + "integrity": "sha512-s0f40zY7dlMp8i0Jf0u6l/aSswS0WRAgkhgETgiCJRcxIWb4S/Sp9uScKHWbkM3BnoFLbJbmOYk5AZUDFVxaLA==", "version": "3.6.8", "resolved": "https://registry.npmjs.org/@eslint/css-tree/-/css-tree-3.6.8.tgz", "integrity": "sha512-s0f40zY7dlMp8i0Jf0u6l/aSswS0WRAgkhgETgiCJRcxIWb4S/Sp9uScKHWbkM3BnoFLbJbmOYk5AZUDFVxaLA==", @@ -2844,6 +2859,9 @@ } }, "node_modules/@inquirer/ansi": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@inquirer/ansi/-/ansi-1.0.2.tgz", + "integrity": "sha512-S8qNSZiYzFd0wAcyG5AXCvUHC5Sr7xpZ9wZ2py9XR88jUz8wooStVx5M6dRzczbBWjic9NP7+rY0Xi7qqK/aMQ==", "version": "1.0.2", "resolved": "https://registry.npmjs.org/@inquirer/ansi/-/ansi-1.0.2.tgz", "integrity": "sha512-S8qNSZiYzFd0wAcyG5AXCvUHC5Sr7xpZ9wZ2py9XR88jUz8wooStVx5M6dRzczbBWjic9NP7+rY0Xi7qqK/aMQ==", @@ -2962,6 +2980,9 @@ } }, "node_modules/@inquirer/figures": { + "version": "1.0.15", + "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.15.tgz", + "integrity": "sha512-t2IEY+unGHOzAaVM5Xx6DEWKeXlDDcNPeDyUpsRc6CUhBfU3VQOEl+Vssh7VNp1dR8MdUJBWhuObjXCsVpjN5g==", "version": "1.0.15", "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.15.tgz", "integrity": "sha512-t2IEY+unGHOzAaVM5Xx6DEWKeXlDDcNPeDyUpsRc6CUhBfU3VQOEl+Vssh7VNp1dR8MdUJBWhuObjXCsVpjN5g==", @@ -3024,10 +3045,32 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, + "node_modules/@isaacs/balanced-match": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@isaacs/balanced-match/-/balanced-match-4.0.1.tgz", + "integrity": "sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==", + "license": "MIT", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/@isaacs/brace-expansion": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@isaacs/brace-expansion/-/brace-expansion-5.0.0.tgz", + "integrity": "sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==", + "license": "MIT", + "dependencies": { + "@isaacs/balanced-match": "^4.0.1" + }, + "engines": { + "node": "20 || >=22" + } + }, "node_modules/@isaacs/cliui": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, "license": "ISC", "dependencies": { "string-width": "^5.1.2", @@ -3045,6 +3088,7 @@ "version": "6.2.2", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -3057,6 +3101,7 @@ "version": "6.2.3", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -3069,12 +3114,14 @@ "version": "9.2.2", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true, "license": "MIT" }, "node_modules/@isaacs/cliui/node_modules/string-width": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, "license": "MIT", "dependencies": { "eastasianwidth": "^0.2.0", @@ -3092,6 +3139,7 @@ "version": "7.1.2", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", + "dev": true, "license": "MIT", "dependencies": { "ansi-regex": "^6.0.1" @@ -3107,6 +3155,7 @@ "version": "8.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^6.1.0", @@ -3162,6 +3211,9 @@ } }, "node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": { + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", + "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", "version": "3.14.2", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", @@ -3733,6 +3785,9 @@ } }, "node_modules/@oclif/plugin-help": { + "version": "6.2.36", + "resolved": "https://registry.npmjs.org/@oclif/plugin-help/-/plugin-help-6.2.36.tgz", + "integrity": "sha512-NBQIg5hEMhvdbi4mSrdqRGl5XJ0bqTAHq6vDCCCDXUcfVtdk3ZJbSxtRVWyVvo9E28vwqu6MZyHOJylevqcHbA==", "version": "6.2.36", "resolved": "https://registry.npmjs.org/@oclif/plugin-help/-/plugin-help-6.2.36.tgz", "integrity": "sha512-NBQIg5hEMhvdbi4mSrdqRGl5XJ0bqTAHq6vDCCCDXUcfVtdk3ZJbSxtRVWyVvo9E28vwqu6MZyHOJylevqcHbA==", @@ -3745,11 +3800,15 @@ } }, "node_modules/@oclif/plugin-not-found": { + "version": "3.2.73", + "resolved": "https://registry.npmjs.org/@oclif/plugin-not-found/-/plugin-not-found-3.2.73.tgz", + "integrity": "sha512-2bQieTGI9XNFe9hKmXQjJmHV5rZw+yn7Rud1+C5uLEo8GaT89KZbiLTJgL35tGILahy/cB6+WAs812wjw7TK6w==", "version": "3.2.73", "resolved": "https://registry.npmjs.org/@oclif/plugin-not-found/-/plugin-not-found-3.2.73.tgz", "integrity": "sha512-2bQieTGI9XNFe9hKmXQjJmHV5rZw+yn7Rud1+C5uLEo8GaT89KZbiLTJgL35tGILahy/cB6+WAs812wjw7TK6w==", "license": "MIT", "dependencies": { + "@inquirer/prompts": "^7.10.1", "@inquirer/prompts": "^7.10.1", "@oclif/core": "^4.8.0", "ansis": "^3.17.0", @@ -3760,6 +3819,9 @@ } }, "node_modules/@oclif/plugin-not-found/node_modules/@inquirer/checkbox": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-4.3.2.tgz", + "integrity": "sha512-VXukHf0RR1doGe6Sm4F0Em7SWYLTHSsbGfJdS9Ja2bX5/D5uwVOEjr07cncLROdBvmnvCATYEWlHqYmXv2IlQA==", "version": "4.3.2", "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-4.3.2.tgz", "integrity": "sha512-VXukHf0RR1doGe6Sm4F0Em7SWYLTHSsbGfJdS9Ja2bX5/D5uwVOEjr07cncLROdBvmnvCATYEWlHqYmXv2IlQA==", @@ -3770,6 +3832,11 @@ "@inquirer/figures": "^1.0.15", "@inquirer/type": "^3.0.10", "yoctocolors-cjs": "^2.1.3" + "@inquirer/ansi": "^1.0.2", + "@inquirer/core": "^10.3.2", + "@inquirer/figures": "^1.0.15", + "@inquirer/type": "^3.0.10", + "yoctocolors-cjs": "^2.1.3" }, "engines": { "node": ">=18" @@ -3784,6 +3851,9 @@ } }, "node_modules/@oclif/plugin-not-found/node_modules/@inquirer/confirm": { + "version": "5.1.21", + "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-5.1.21.tgz", + "integrity": "sha512-KR8edRkIsUayMXV+o3Gv+q4jlhENF9nMYUZs9PA2HzrXeHI8M5uDag70U7RJn9yyiMZSbtF5/UexBtAVtZGSbQ==", "version": "5.1.21", "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-5.1.21.tgz", "integrity": "sha512-KR8edRkIsUayMXV+o3Gv+q4jlhENF9nMYUZs9PA2HzrXeHI8M5uDag70U7RJn9yyiMZSbtF5/UexBtAVtZGSbQ==", @@ -3791,6 +3861,8 @@ "dependencies": { "@inquirer/core": "^10.3.2", "@inquirer/type": "^3.0.10" + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10" }, "engines": { "node": ">=18" @@ -3805,11 +3877,17 @@ } }, "node_modules/@oclif/plugin-not-found/node_modules/@inquirer/core": { + "version": "10.3.2", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-10.3.2.tgz", + "integrity": "sha512-43RTuEbfP8MbKzedNqBrlhhNKVwoK//vUFNW3Q3vZ88BLcrs4kYpGg+B2mm5p2K/HfygoCxuKwJJiv8PbGmE0A==", "version": "10.3.2", "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-10.3.2.tgz", "integrity": "sha512-43RTuEbfP8MbKzedNqBrlhhNKVwoK//vUFNW3Q3vZ88BLcrs4kYpGg+B2mm5p2K/HfygoCxuKwJJiv8PbGmE0A==", "license": "MIT", "dependencies": { + "@inquirer/ansi": "^1.0.2", + "@inquirer/figures": "^1.0.15", + "@inquirer/type": "^3.0.10", "@inquirer/ansi": "^1.0.2", "@inquirer/figures": "^1.0.15", "@inquirer/type": "^3.0.10", @@ -3818,6 +3896,7 @@ "signal-exit": "^4.1.0", "wrap-ansi": "^6.2.0", "yoctocolors-cjs": "^2.1.3" + "yoctocolors-cjs": "^2.1.3" }, "engines": { "node": ">=18" @@ -3832,6 +3911,9 @@ } }, "node_modules/@oclif/plugin-not-found/node_modules/@inquirer/editor": { + "version": "4.2.23", + "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-4.2.23.tgz", + "integrity": "sha512-aLSROkEwirotxZ1pBaP8tugXRFCxW94gwrQLxXfrZsKkfjOYC1aRvAZuhpJOb5cu4IBTJdsCigUlf2iCOu4ZDQ==", "version": "4.2.23", "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-4.2.23.tgz", "integrity": "sha512-aLSROkEwirotxZ1pBaP8tugXRFCxW94gwrQLxXfrZsKkfjOYC1aRvAZuhpJOb5cu4IBTJdsCigUlf2iCOu4ZDQ==", @@ -3840,6 +3922,9 @@ "@inquirer/core": "^10.3.2", "@inquirer/external-editor": "^1.0.3", "@inquirer/type": "^3.0.10" + "@inquirer/core": "^10.3.2", + "@inquirer/external-editor": "^1.0.3", + "@inquirer/type": "^3.0.10" }, "engines": { "node": ">=18" @@ -3854,6 +3939,9 @@ } }, "node_modules/@oclif/plugin-not-found/node_modules/@inquirer/expand": { + "version": "4.0.23", + "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-4.0.23.tgz", + "integrity": "sha512-nRzdOyFYnpeYTTR2qFwEVmIWypzdAx/sIkCMeTNTcflFOovfqUk+HcFhQQVBftAh9gmGrpFj6QcGEqrDMDOiew==", "version": "4.0.23", "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-4.0.23.tgz", "integrity": "sha512-nRzdOyFYnpeYTTR2qFwEVmIWypzdAx/sIkCMeTNTcflFOovfqUk+HcFhQQVBftAh9gmGrpFj6QcGEqrDMDOiew==", @@ -3862,6 +3950,9 @@ "@inquirer/core": "^10.3.2", "@inquirer/type": "^3.0.10", "yoctocolors-cjs": "^2.1.3" + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10", + "yoctocolors-cjs": "^2.1.3" }, "engines": { "node": ">=18" @@ -3876,11 +3967,15 @@ } }, "node_modules/@oclif/plugin-not-found/node_modules/@inquirer/external-editor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-1.0.3.tgz", + "integrity": "sha512-RWbSrDiYmO4LbejWY7ttpxczuwQyZLBUyygsA9Nsv95hpzUWwnNTVQmAq3xuh7vNwCp07UTmE5i11XAEExx4RA==", "version": "1.0.3", "resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-1.0.3.tgz", "integrity": "sha512-RWbSrDiYmO4LbejWY7ttpxczuwQyZLBUyygsA9Nsv95hpzUWwnNTVQmAq3xuh7vNwCp07UTmE5i11XAEExx4RA==", "license": "MIT", "dependencies": { + "chardet": "^2.1.1", "chardet": "^2.1.1", "iconv-lite": "^0.7.0" }, @@ -3897,6 +3992,9 @@ } }, "node_modules/@oclif/plugin-not-found/node_modules/@inquirer/input": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-4.3.1.tgz", + "integrity": "sha512-kN0pAM4yPrLjJ1XJBjDxyfDduXOuQHrBB8aLDMueuwUGn+vNpF7Gq7TvyVxx8u4SHlFFj4trmj+a2cbpG4Jn1g==", "version": "4.3.1", "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-4.3.1.tgz", "integrity": "sha512-kN0pAM4yPrLjJ1XJBjDxyfDduXOuQHrBB8aLDMueuwUGn+vNpF7Gq7TvyVxx8u4SHlFFj4trmj+a2cbpG4Jn1g==", @@ -3904,6 +4002,8 @@ "dependencies": { "@inquirer/core": "^10.3.2", "@inquirer/type": "^3.0.10" + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10" }, "engines": { "node": ">=18" @@ -3918,6 +4018,9 @@ } }, "node_modules/@oclif/plugin-not-found/node_modules/@inquirer/number": { + "version": "3.0.23", + "resolved": "https://registry.npmjs.org/@inquirer/number/-/number-3.0.23.tgz", + "integrity": "sha512-5Smv0OK7K0KUzUfYUXDXQc9jrf8OHo4ktlEayFlelCjwMXz0299Y8OrI+lj7i4gCBY15UObk76q0QtxjzFcFcg==", "version": "3.0.23", "resolved": "https://registry.npmjs.org/@inquirer/number/-/number-3.0.23.tgz", "integrity": "sha512-5Smv0OK7K0KUzUfYUXDXQc9jrf8OHo4ktlEayFlelCjwMXz0299Y8OrI+lj7i4gCBY15UObk76q0QtxjzFcFcg==", @@ -3925,6 +4028,8 @@ "dependencies": { "@inquirer/core": "^10.3.2", "@inquirer/type": "^3.0.10" + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10" }, "engines": { "node": ">=18" @@ -3939,6 +4044,9 @@ } }, "node_modules/@oclif/plugin-not-found/node_modules/@inquirer/password": { + "version": "4.0.23", + "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-4.0.23.tgz", + "integrity": "sha512-zREJHjhT5vJBMZX/IUbyI9zVtVfOLiTO66MrF/3GFZYZ7T4YILW5MSkEYHceSii/KtRk+4i3RE7E1CUXA2jHcA==", "version": "4.0.23", "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-4.0.23.tgz", "integrity": "sha512-zREJHjhT5vJBMZX/IUbyI9zVtVfOLiTO66MrF/3GFZYZ7T4YILW5MSkEYHceSii/KtRk+4i3RE7E1CUXA2jHcA==", @@ -3947,6 +4055,9 @@ "@inquirer/ansi": "^1.0.2", "@inquirer/core": "^10.3.2", "@inquirer/type": "^3.0.10" + "@inquirer/ansi": "^1.0.2", + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10" }, "engines": { "node": ">=18" @@ -3961,6 +4072,9 @@ } }, "node_modules/@oclif/plugin-not-found/node_modules/@inquirer/prompts": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-7.10.1.tgz", + "integrity": "sha512-Dx/y9bCQcXLI5ooQ5KyvA4FTgeo2jYj/7plWfV5Ak5wDPKQZgudKez2ixyfz7tKXzcJciTxqLeK7R9HItwiByg==", "version": "7.10.1", "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-7.10.1.tgz", "integrity": "sha512-Dx/y9bCQcXLI5ooQ5KyvA4FTgeo2jYj/7plWfV5Ak5wDPKQZgudKez2ixyfz7tKXzcJciTxqLeK7R9HItwiByg==", @@ -3976,6 +4090,16 @@ "@inquirer/rawlist": "^4.1.11", "@inquirer/search": "^3.2.2", "@inquirer/select": "^4.4.2" + "@inquirer/checkbox": "^4.3.2", + "@inquirer/confirm": "^5.1.21", + "@inquirer/editor": "^4.2.23", + "@inquirer/expand": "^4.0.23", + "@inquirer/input": "^4.3.1", + "@inquirer/number": "^3.0.23", + "@inquirer/password": "^4.0.23", + "@inquirer/rawlist": "^4.1.11", + "@inquirer/search": "^3.2.2", + "@inquirer/select": "^4.4.2" }, "engines": { "node": ">=18" @@ -3990,6 +4114,9 @@ } }, "node_modules/@oclif/plugin-not-found/node_modules/@inquirer/rawlist": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-4.1.11.tgz", + "integrity": "sha512-+LLQB8XGr3I5LZN/GuAHo+GpDJegQwuPARLChlMICNdwW7OwV2izlCSCxN6cqpL0sMXmbKbFcItJgdQq5EBXTw==", "version": "4.1.11", "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-4.1.11.tgz", "integrity": "sha512-+LLQB8XGr3I5LZN/GuAHo+GpDJegQwuPARLChlMICNdwW7OwV2izlCSCxN6cqpL0sMXmbKbFcItJgdQq5EBXTw==", @@ -3998,6 +4125,9 @@ "@inquirer/core": "^10.3.2", "@inquirer/type": "^3.0.10", "yoctocolors-cjs": "^2.1.3" + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10", + "yoctocolors-cjs": "^2.1.3" }, "engines": { "node": ">=18" @@ -4012,6 +4142,9 @@ } }, "node_modules/@oclif/plugin-not-found/node_modules/@inquirer/search": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@inquirer/search/-/search-3.2.2.tgz", + "integrity": "sha512-p2bvRfENXCZdWF/U2BXvnSI9h+tuA8iNqtUKb9UWbmLYCRQxd8WkvwWvYn+3NgYaNwdUkHytJMGG4MMLucI1kA==", "version": "3.2.2", "resolved": "https://registry.npmjs.org/@inquirer/search/-/search-3.2.2.tgz", "integrity": "sha512-p2bvRfENXCZdWF/U2BXvnSI9h+tuA8iNqtUKb9UWbmLYCRQxd8WkvwWvYn+3NgYaNwdUkHytJMGG4MMLucI1kA==", @@ -4021,6 +4154,10 @@ "@inquirer/figures": "^1.0.15", "@inquirer/type": "^3.0.10", "yoctocolors-cjs": "^2.1.3" + "@inquirer/core": "^10.3.2", + "@inquirer/figures": "^1.0.15", + "@inquirer/type": "^3.0.10", + "yoctocolors-cjs": "^2.1.3" }, "engines": { "node": ">=18" @@ -4035,6 +4172,9 @@ } }, "node_modules/@oclif/plugin-not-found/node_modules/@inquirer/select": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-4.4.2.tgz", + "integrity": "sha512-l4xMuJo55MAe+N7Qr4rX90vypFwCajSakx59qe/tMaC1aEHWLyw68wF4o0A4SLAY4E0nd+Vt+EyskeDIqu1M6w==", "version": "4.4.2", "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-4.4.2.tgz", "integrity": "sha512-l4xMuJo55MAe+N7Qr4rX90vypFwCajSakx59qe/tMaC1aEHWLyw68wF4o0A4SLAY4E0nd+Vt+EyskeDIqu1M6w==", @@ -4045,6 +4185,11 @@ "@inquirer/figures": "^1.0.15", "@inquirer/type": "^3.0.10", "yoctocolors-cjs": "^2.1.3" + "@inquirer/ansi": "^1.0.2", + "@inquirer/core": "^10.3.2", + "@inquirer/figures": "^1.0.15", + "@inquirer/type": "^3.0.10", + "yoctocolors-cjs": "^2.1.3" }, "engines": { "node": ">=18" @@ -4059,6 +4204,9 @@ } }, "node_modules/@oclif/plugin-not-found/node_modules/@inquirer/type": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-3.0.10.tgz", + "integrity": "sha512-BvziSRxfz5Ov8ch0z/n3oijRSEcEsHnhggm4xFZe93DHcUCTlutlq9Ox4SVENAfcRD22UQq7T/atg9Wr3k09eA==", "version": "3.0.10", "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-3.0.10.tgz", "integrity": "sha512-BvziSRxfz5Ov8ch0z/n3oijRSEcEsHnhggm4xFZe93DHcUCTlutlq9Ox4SVENAfcRD22UQq7T/atg9Wr3k09eA==", @@ -4161,6 +4309,9 @@ } }, "node_modules/@oclif/plugin-plugins": { + "version": "5.4.54", + "resolved": "https://registry.npmjs.org/@oclif/plugin-plugins/-/plugin-plugins-5.4.54.tgz", + "integrity": "sha512-yzdukEfvvyXx31AhN+YhxLhuQdx2SrZDcRtPl5CNkuqh/uNSB2BuA3xpurdv2qotpaw/Z9InRl+Sa9bLp/4aLA==", "version": "5.4.54", "resolved": "https://registry.npmjs.org/@oclif/plugin-plugins/-/plugin-plugins-5.4.54.tgz", "integrity": "sha512-yzdukEfvvyXx31AhN+YhxLhuQdx2SrZDcRtPl5CNkuqh/uNSB2BuA3xpurdv2qotpaw/Z9InRl+Sa9bLp/4aLA==", @@ -4183,6 +4334,9 @@ } }, "node_modules/@oclif/plugin-warn-if-update-available": { + "version": "3.1.53", + "resolved": "https://registry.npmjs.org/@oclif/plugin-warn-if-update-available/-/plugin-warn-if-update-available-3.1.53.tgz", + "integrity": "sha512-ALxKMNFFJQJV1Z2OMVTV+q7EbKHhnTAPcTgkgHeXCNdW5nFExoXuwusZLS4Zv2o83j9UoDx1R/CSX7QZVgEHTA==", "version": "3.1.53", "resolved": "https://registry.npmjs.org/@oclif/plugin-warn-if-update-available/-/plugin-warn-if-update-available-3.1.53.tgz", "integrity": "sha512-ALxKMNFFJQJV1Z2OMVTV+q7EbKHhnTAPcTgkgHeXCNdW5nFExoXuwusZLS4Zv2o83j9UoDx1R/CSX7QZVgEHTA==", @@ -4201,6 +4355,9 @@ } }, "node_modules/@oclif/test": { + "version": "4.1.15", + "resolved": "https://registry.npmjs.org/@oclif/test/-/test-4.1.15.tgz", + "integrity": "sha512-OVTmz3RxnOWYPoE9sbB9Przfph+QSLMvHUfqEwXZKupuOHCJAJX0QDUfVyh1pK+XYEQ2RUaF+qhxqBfIfaahBw==", "version": "4.1.15", "resolved": "https://registry.npmjs.org/@oclif/test/-/test-4.1.15.tgz", "integrity": "sha512-OVTmz3RxnOWYPoE9sbB9Przfph+QSLMvHUfqEwXZKupuOHCJAJX0QDUfVyh1pK+XYEQ2RUaF+qhxqBfIfaahBw==", @@ -4267,6 +4424,7 @@ "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, "license": "MIT", "optional": true, "engines": { @@ -5777,6 +5935,9 @@ } }, "node_modules/@tsconfig/node10": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.12.tgz", + "integrity": "sha512-UCYBaeFvM11aU2y3YPZ//O5Rhj+xKyzy7mvcIoAjASbigy8mHMryP5cK7dgjlz2hWxh1g5pLw084E0a/wlUSFQ==", "version": "1.0.12", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.12.tgz", "integrity": "sha512-UCYBaeFvM11aU2y3YPZ//O5Rhj+xKyzy7mvcIoAjASbigy8mHMryP5cK7dgjlz2hWxh1g5pLw084E0a/wlUSFQ==", @@ -6075,6 +6236,9 @@ "license": "MIT" }, "node_modules/@types/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-FOvQ0YPD5NOfPgMzJihoT+Za5pdkDJWcbpuj1DjaKZIr/gxodQjY/uWEFlTNqW2ugXHUiL8lRQgw63dzKHZdeQ==", "version": "4.17.21", "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-FOvQ0YPD5NOfPgMzJihoT+Za5pdkDJWcbpuj1DjaKZIr/gxodQjY/uWEFlTNqW2ugXHUiL8lRQgw63dzKHZdeQ==", @@ -6301,6 +6465,9 @@ "license": "MIT" }, "node_modules/@types/yargs": { + "version": "17.0.35", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.35.tgz", + "integrity": "sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==", "version": "17.0.35", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.35.tgz", "integrity": "sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==", @@ -6318,67 +6485,67 @@ "license": "MIT" }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.62.0.tgz", - "integrity": "sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==", + "version": "8.49.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.49.0.tgz", + "integrity": "sha512-JXij0vzIaTtCwu6SxTh8qBc66kmf1xs7pI4UOiMDFVct6q86G0Zs7KRcEoJgY3Cav3x5Tq0MF5jwgpgLqgKG3A==", "dev": true, "license": "MIT", "dependencies": { - "@eslint-community/regexpp": "^4.4.0", - "@typescript-eslint/scope-manager": "5.62.0", - "@typescript-eslint/type-utils": "5.62.0", - "@typescript-eslint/utils": "5.62.0", - "debug": "^4.3.4", - "graphemer": "^1.4.0", - "ignore": "^5.2.0", - "natural-compare-lite": "^1.4.0", - "semver": "^7.3.7", - "tsutils": "^3.21.0" + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "8.49.0", + "@typescript-eslint/type-utils": "8.49.0", + "@typescript-eslint/utils": "8.49.0", + "@typescript-eslint/visitor-keys": "8.49.0", + "ignore": "^7.0.0", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.1.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^5.0.0", - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "@typescript-eslint/parser": "^8.49.0", + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" } }, "node_modules/@typescript-eslint/parser": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.62.0.tgz", - "integrity": "sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==", + "version": "8.49.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.49.0.tgz", + "integrity": "sha512-N9lBGA9o9aqb1hVMc9hzySbhKibHmB+N3IpoShyV6HyQYRGIhlrO5rQgttypi+yEeKsKI4idxC8Jw6gXKD4THA==", "dev": true, - "license": "BSD-2-Clause", - "peer": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "5.62.0", - "@typescript-eslint/types": "5.62.0", - "@typescript-eslint/typescript-estree": "5.62.0", + "@typescript-eslint/scope-manager": "8.49.0", + "@typescript-eslint/types": "8.49.0", + "@typescript-eslint/typescript-estree": "8.49.0", + "@typescript-eslint/visitor-keys": "8.49.0", "debug": "^4.3.4" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" } }, "node_modules/@typescript-eslint/project-service": { @@ -6418,17 +6585,17 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz", - "integrity": "sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==", + "version": "8.49.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.49.0.tgz", + "integrity": "sha512-npgS3zi+/30KSOkXNs0LQXtsg9ekZ8OISAOLGWA/ZOEn0ZH74Ginfl7foziV8DT+D98WfQ5Kopwqb/PZOaIJGg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "5.62.0", - "@typescript-eslint/visitor-keys": "5.62.0" + "@typescript-eslint/types": "8.49.0", + "@typescript-eslint/visitor-keys": "8.49.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", @@ -6453,41 +6620,38 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.62.0.tgz", - "integrity": "sha512-xsSQreu+VnfbqQpW5vnCJdq1Z3Q0U31qiWmRhr98ONQmcp/yhiPJFPq8MXiJVLiksmOKSjIldZzkebzHuCGzew==", + "version": "8.49.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.49.0.tgz", + "integrity": "sha512-KTExJfQ+svY8I10P4HdxKzWsvtVnsuCifU5MvXrRwoP2KOlNZ9ADNEWWsQTJgMxLzS5VLQKDjkCT/YzgsnqmZg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/typescript-estree": "5.62.0", - "@typescript-eslint/utils": "5.62.0", + "@typescript-eslint/types": "8.49.0", + "@typescript-eslint/typescript-estree": "8.49.0", + "@typescript-eslint/utils": "8.49.0", "debug": "^4.3.4", - "tsutils": "^3.21.0" + "ts-api-utils": "^2.1.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "*" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" } }, "node_modules/@typescript-eslint/types": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.62.0.tgz", - "integrity": "sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==", + "version": "8.49.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.49.0.tgz", + "integrity": "sha512-e9k/fneezorUo6WShlQpMxXh8/8wfyc+biu6tnAqA81oWrEic0k21RHzP9uqqpyBBeBKu4T+Bsjy9/b8u7obXQ==", "dev": true, "license": "MIT", "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", @@ -6495,99 +6659,88 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz", - "integrity": "sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==", + "version": "8.49.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.49.0.tgz", + "integrity": "sha512-jrLdRuAbPfPIdYNppHJ/D0wN+wwNfJ32YTAm10eJVsFmrVpXQnDWBn8niCSMlWjvml8jsce5E/O+86IQtTbJWA==", "dev": true, - "license": "BSD-2-Clause", + "license": "MIT", "dependencies": { - "@typescript-eslint/types": "5.62.0", - "@typescript-eslint/visitor-keys": "5.62.0", + "@typescript-eslint/project-service": "8.49.0", + "@typescript-eslint/tsconfig-utils": "8.49.0", + "@typescript-eslint/types": "8.49.0", + "@typescript-eslint/visitor-keys": "8.49.0", "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "semver": "^7.3.7", - "tsutils": "^3.21.0" + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.1.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, - "license": "MIT", - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" } }, "node_modules/@typescript-eslint/utils": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.62.0.tgz", - "integrity": "sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==", + "version": "8.49.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.49.0.tgz", + "integrity": "sha512-N3W7rJw7Rw+z1tRsHZbK395TWSYvufBXumYtEGzypgMUthlg0/hmCImeA8hgO2d2G4pd7ftpxxul2J8OdtdaFA==", "dev": true, "license": "MIT", "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@types/json-schema": "^7.0.9", - "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.62.0", - "@typescript-eslint/types": "5.62.0", - "@typescript-eslint/typescript-estree": "5.62.0", - "eslint-scope": "^5.1.1", - "semver": "^7.3.7" + "@eslint-community/eslint-utils": "^4.7.0", + "@typescript-eslint/scope-manager": "8.49.0", + "@typescript-eslint/types": "8.49.0", + "@typescript-eslint/typescript-estree": "8.49.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz", - "integrity": "sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==", + "version": "8.49.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.49.0.tgz", + "integrity": "sha512-LlKaciDe3GmZFphXIc79THF/YYBugZ7FS1pO581E/edlVVNbZKDy93evqmrfQ9/Y4uN0vVhX4iuchq26mK/iiA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "5.62.0", - "eslint-visitor-keys": "^3.3.0" + "@typescript-eslint/types": "8.49.0", + "eslint-visitor-keys": "^4.2.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" } }, + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, "node_modules/@ungap/structured-clone": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", @@ -7683,11 +7836,15 @@ "license": "MIT" }, "node_modules/body-parser": { + "version": "1.20.4", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.4.tgz", + "integrity": "sha512-ZTgYYLMOXY9qKU/57FAo8F+HA2dGX7bqGc71txDRC1rS4frdFI5R7NhluHxH6M0YItAP0sHB4uqAOcYKxO6uGA==", "version": "1.20.4", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.4.tgz", "integrity": "sha512-ZTgYYLMOXY9qKU/57FAo8F+HA2dGX7bqGc71txDRC1rS4frdFI5R7NhluHxH6M0YItAP0sHB4uqAOcYKxO6uGA==", "license": "MIT", "dependencies": { + "bytes": "~3.1.2", "bytes": "~3.1.2", "content-type": "~1.0.5", "debug": "2.6.9", @@ -7698,8 +7855,15 @@ "on-finished": "~2.4.1", "qs": "~6.14.0", "raw-body": "~2.5.3", + "destroy": "~1.2.0", + "http-errors": "~2.0.1", + "iconv-lite": "~0.4.24", + "on-finished": "~2.4.1", + "qs": "~6.14.0", + "raw-body": "~2.5.3", "type-is": "~1.6.18", "unpipe": "~1.0.0" + "unpipe": "~1.0.0" }, "engines": { "node": ">= 0.8", @@ -7722,6 +7886,9 @@ "license": "MIT" }, "node_modules/bowser": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.13.1.tgz", + "integrity": "sha512-OHawaAbjwx6rqICCKgSG0SAnT05bzd7ppyKLVUITZpANBaaMFBAsaNkto3LoQ31tyFP5kNujE8Cdx85G9VzOkw==", "version": "2.13.1", "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.13.1.tgz", "integrity": "sha512-OHawaAbjwx6rqICCKgSG0SAnT05bzd7ppyKLVUITZpANBaaMFBAsaNkto3LoQ31tyFP5kNujE8Cdx85G9VzOkw==", @@ -7767,6 +7934,9 @@ "license": "ISC" }, "node_modules/browserslist": { + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", + "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", "version": "4.28.1", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", @@ -7792,6 +7962,11 @@ "electron-to-chromium": "^1.5.263", "node-releases": "^2.0.27", "update-browserslist-db": "^1.2.0" + "baseline-browser-mapping": "^2.9.0", + "caniuse-lite": "^1.0.30001759", + "electron-to-chromium": "^1.5.263", + "node-releases": "^2.0.27", + "update-browserslist-db": "^1.2.0" }, "bin": { "browserslist": "cli.js" @@ -8415,6 +8590,15 @@ "node": ">=0.10.0" } }, + "node_modules/cli-truncate/node_modules/slice-ansi": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-0.0.4.tgz", + "integrity": "sha512-up04hB2hR92PgjpyU3y/eg91yIBILyjVY26NvvciY3EVVPjybkMszMpXQ9QAkcS3I5rtJBDLoTxxg+qvW8c7rw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/cli-truncate/node_modules/string-width": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", @@ -8515,6 +8699,9 @@ "license": "MIT" }, "node_modules/color": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/color/-/color-5.0.3.tgz", + "integrity": "sha512-ezmVcLR3xAVp8kYOm4GS45ZLLgIE6SPAFoduLr6hTDajwb3KZ2F46gulK3XpcwRFb5KKGCSezCBAY4Dw4HsyXA==", "version": "5.0.3", "resolved": "https://registry.npmjs.org/color/-/color-5.0.3.tgz", "integrity": "sha512-ezmVcLR3xAVp8kYOm4GS45ZLLgIE6SPAFoduLr6hTDajwb3KZ2F46gulK3XpcwRFb5KKGCSezCBAY4Dw4HsyXA==", @@ -8522,6 +8709,8 @@ "dependencies": { "color-convert": "^3.1.3", "color-string": "^2.1.3" + "color-convert": "^3.1.3", + "color-string": "^2.1.3" }, "engines": { "node": ">=18" @@ -8546,6 +8735,9 @@ "license": "MIT" }, "node_modules/color-string": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-2.1.4.tgz", + "integrity": "sha512-Bb6Cq8oq0IjDOe8wJmi4JeNn763Xs9cfrBcaylK1tPypWzyoy2G3l90v9k64kjphl/ZJjPIShFztenRomi8WTg==", "version": "2.1.4", "resolved": "https://registry.npmjs.org/color-string/-/color-string-2.1.4.tgz", "integrity": "sha512-Bb6Cq8oq0IjDOe8wJmi4JeNn763Xs9cfrBcaylK1tPypWzyoy2G3l90v9k64kjphl/ZJjPIShFztenRomi8WTg==", @@ -8558,6 +8750,9 @@ } }, "node_modules/color-string/node_modules/color-name": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-2.1.0.tgz", + "integrity": "sha512-1bPaDNFm0axzE4MEAzKPuqKWeRaT43U/hyxKPBdqTfmPF+d6n7FSoTFxLVULUJOmiLp01KjhIPPH+HrXZJN4Rg==", "version": "2.1.0", "resolved": "https://registry.npmjs.org/color-name/-/color-name-2.1.0.tgz", "integrity": "sha512-1bPaDNFm0axzE4MEAzKPuqKWeRaT43U/hyxKPBdqTfmPF+d6n7FSoTFxLVULUJOmiLp01KjhIPPH+HrXZJN4Rg==", @@ -8567,6 +8762,9 @@ } }, "node_modules/color/node_modules/color-convert": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-3.1.3.tgz", + "integrity": "sha512-fasDH2ont2GqF5HpyO4w0+BcewlhHEZOFn9c1ckZdHpJ56Qb7MHhH/IcJZbBGgvdtwdwNbLvxiBEdg336iA9Sg==", "version": "3.1.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-3.1.3.tgz", "integrity": "sha512-fasDH2ont2GqF5HpyO4w0+BcewlhHEZOFn9c1ckZdHpJ56Qb7MHhH/IcJZbBGgvdtwdwNbLvxiBEdg336iA9Sg==", @@ -8579,6 +8777,9 @@ } }, "node_modules/color/node_modules/color-name": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-2.1.0.tgz", + "integrity": "sha512-1bPaDNFm0axzE4MEAzKPuqKWeRaT43U/hyxKPBdqTfmPF+d6n7FSoTFxLVULUJOmiLp01KjhIPPH+HrXZJN4Rg==", "version": "2.1.0", "resolved": "https://registry.npmjs.org/color-name/-/color-name-2.1.0.tgz", "integrity": "sha512-1bPaDNFm0axzE4MEAzKPuqKWeRaT43U/hyxKPBdqTfmPF+d6n7FSoTFxLVULUJOmiLp01KjhIPPH+HrXZJN4Rg==", @@ -8751,6 +8952,20 @@ "typedarray": "^0.0.6" } }, + "node_modules/concat-stream/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/conf": { "version": "10.2.0", "resolved": "https://registry.npmjs.org/conf/-/conf-10.2.0.tgz", @@ -8854,6 +9069,9 @@ } }, "node_modules/contentstack": { + "version": "3.26.3", + "resolved": "https://registry.npmjs.org/contentstack/-/contentstack-3.26.3.tgz", + "integrity": "sha512-mN1/Z8YV1HoIw03oEgnoHlaX/ueOLZH4unbf3zJt6uOJSO51gDFfOQEnKsTfUfWkyks9xUmED3WzPMxpnxdqcQ==", "version": "3.26.3", "resolved": "https://registry.npmjs.org/contentstack/-/contentstack-3.26.3.tgz", "integrity": "sha512-mN1/Z8YV1HoIw03oEgnoHlaX/ueOLZH4unbf3zJt6uOJSO51gDFfOQEnKsTfUfWkyks9xUmED3WzPMxpnxdqcQ==", @@ -8876,6 +9094,9 @@ "license": "MIT" }, "node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", "version": "0.7.2", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", @@ -8885,12 +9106,18 @@ } }, "node_modules/cookie-signature": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.7.tgz", + "integrity": "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==", "version": "1.0.7", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.7.tgz", "integrity": "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==", "license": "MIT" }, "node_modules/core-js-compat": { + "version": "3.47.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.47.0.tgz", + "integrity": "sha512-IGfuznZ/n7Kp9+nypamBhvwdwLsW6KC8IOaURw2doAK5e98AG3acVLdh0woOnEqCfUtS+Vu882JE4k/DAm3ItQ==", "version": "3.47.0", "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.47.0.tgz", "integrity": "sha512-IGfuznZ/n7Kp9+nypamBhvwdwLsW6KC8IOaURw2doAK5e98AG3acVLdh0woOnEqCfUtS+Vu882JE4k/DAm3ItQ==", @@ -8898,6 +9125,7 @@ "license": "MIT", "dependencies": { "browserslist": "^4.28.0" + "browserslist": "^4.28.0" }, "funding": { "type": "opencollective", @@ -8952,6 +9180,7 @@ "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, "license": "MIT", "dependencies": { "path-key": "^3.1.0", @@ -8966,12 +9195,14 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, "license": "ISC" }, "node_modules/cross-spawn/node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, "license": "ISC", "dependencies": { "isexe": "^2.0.0" @@ -9482,6 +9713,7 @@ "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true, "license": "MIT" }, "node_modules/ee-first": { @@ -9506,6 +9738,9 @@ } }, "node_modules/electron-to-chromium": { + "version": "1.5.267", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.267.tgz", + "integrity": "sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==", "version": "1.5.267", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.267.tgz", "integrity": "sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==", @@ -9931,6 +10166,7 @@ "dependencies": { "@eslint/compat": "^1.4.1", "@eslint/eslintrc": "^3.3.3", + "@eslint/eslintrc": "^3.3.3", "@eslint/js": "^9.38.0", "@stylistic/eslint-plugin": "^3.1.0", "@typescript-eslint/eslint-plugin": "^8", @@ -10170,41 +10406,6 @@ "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/eslint-config-oclif-typescript/node_modules/eslint-import-resolver-typescript": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.10.1.tgz", - "integrity": "sha512-A1rHYb06zjMGAxdLSkN2fXPBwuSaQ0iO5M/hdyS0Ajj1VBaRp0sPD3dn1FhME3c/JluGFbwSxyCfqdSbtQLAHQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "@nolyfill/is-core-module": "1.0.39", - "debug": "^4.4.0", - "get-tsconfig": "^4.10.0", - "is-bun-module": "^2.0.0", - "stable-hash": "^0.0.5", - "tinyglobby": "^0.2.13", - "unrs-resolver": "^1.6.2" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint-import-resolver-typescript" - }, - "peerDependencies": { - "eslint": "*", - "eslint-plugin-import": "*", - "eslint-plugin-import-x": "*" - }, - "peerDependenciesMeta": { - "eslint-plugin-import": { - "optional": true - }, - "eslint-plugin-import-x": { - "optional": true - } - } - }, "node_modules/eslint-config-oclif-typescript/node_modules/eslint-plugin-n": { "version": "15.7.0", "resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-15.7.0.tgz", @@ -10339,6 +10540,9 @@ } }, "node_modules/eslint-config-oclif/node_modules/@eslint/eslintrc": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.3.tgz", + "integrity": "sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==", "version": "3.3.3", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.3.tgz", "integrity": "sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==", @@ -10352,6 +10556,7 @@ "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.1", + "js-yaml": "^4.1.1", "minimatch": "^3.1.2", "strip-json-comments": "^3.1.1" }, @@ -10599,6 +10804,17 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/eslint-config-oclif/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "node_modules/eslint-config-oclif/node_modules/ci-info": { "version": "3.9.0", "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", @@ -10775,6 +10991,9 @@ } }, "node_modules/eslint-config-oclif/node_modules/eslint-config-xo/node_modules/@stylistic/eslint-plugin": { + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin/-/eslint-plugin-5.6.1.tgz", + "integrity": "sha512-JCs+MqoXfXrRPGbGmho/zGS/jMcn3ieKl/A8YImqib76C8kjgZwq5uUFzc30lJkMvcchuRn6/v8IApLxli3Jyw==", "version": "5.6.1", "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin/-/eslint-plugin-5.6.1.tgz", "integrity": "sha512-JCs+MqoXfXrRPGbGmho/zGS/jMcn3ieKl/A8YImqib76C8kjgZwq5uUFzc30lJkMvcchuRn6/v8IApLxli3Jyw==", @@ -10783,6 +11002,7 @@ "dependencies": { "@eslint-community/eslint-utils": "^4.9.0", "@typescript-eslint/types": "^8.47.0", + "@typescript-eslint/types": "^8.47.0", "eslint-visitor-keys": "^4.2.1", "espree": "^10.4.0", "estraverse": "^5.3.0", @@ -10808,41 +11028,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/eslint-config-oclif/node_modules/eslint-import-resolver-typescript": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.10.1.tgz", - "integrity": "sha512-A1rHYb06zjMGAxdLSkN2fXPBwuSaQ0iO5M/hdyS0Ajj1VBaRp0sPD3dn1FhME3c/JluGFbwSxyCfqdSbtQLAHQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "@nolyfill/is-core-module": "1.0.39", - "debug": "^4.4.0", - "get-tsconfig": "^4.10.0", - "is-bun-module": "^2.0.0", - "stable-hash": "^0.0.5", - "tinyglobby": "^0.2.13", - "unrs-resolver": "^1.6.2" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint-import-resolver-typescript" - }, - "peerDependencies": { - "eslint": "*", - "eslint-plugin-import": "*", - "eslint-plugin-import-x": "*" - }, - "peerDependenciesMeta": { - "eslint-plugin-import": { - "optional": true - }, - "eslint-plugin-import-x": { - "optional": true - } - } - }, "node_modules/eslint-config-oclif/node_modules/eslint-scope": { "version": "8.4.0", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", @@ -10954,17 +11139,6 @@ "node": "*" } }, - "node_modules/eslint-config-oclif/node_modules/minimatch/node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, "node_modules/eslint-config-xo": { "version": "0.44.0", "resolved": "https://registry.npmjs.org/eslint-config-xo/-/eslint-config-xo-0.44.0.tgz", @@ -11025,6 +11199,41 @@ "ms": "^2.1.1" } }, + "node_modules/eslint-import-resolver-typescript": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.10.1.tgz", + "integrity": "sha512-A1rHYb06zjMGAxdLSkN2fXPBwuSaQ0iO5M/hdyS0Ajj1VBaRp0sPD3dn1FhME3c/JluGFbwSxyCfqdSbtQLAHQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "@nolyfill/is-core-module": "1.0.39", + "debug": "^4.4.0", + "get-tsconfig": "^4.10.0", + "is-bun-module": "^2.0.0", + "stable-hash": "^0.0.5", + "tinyglobby": "^0.2.13", + "unrs-resolver": "^1.6.2" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint-import-resolver-typescript" + }, + "peerDependencies": { + "eslint": "*", + "eslint-plugin-import": "*", + "eslint-plugin-import-x": "*" + }, + "peerDependenciesMeta": { + "eslint-plugin-import": { + "optional": true + }, + "eslint-plugin-import-x": { + "optional": true + } + } + }, "node_modules/eslint-module-utils": { "version": "2.12.1", "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.12.1.tgz", @@ -11507,27 +11716,20 @@ } }, "node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", "dev": true, "license": "BSD-2-Clause", "dependencies": { "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" + "estraverse": "^5.2.0" }, "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/eslint-scope/node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=4.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/eslint-utils": { @@ -11600,27 +11802,10 @@ "concat-map": "0.0.1" } }, - "node_modules/eslint/node_modules/eslint-scope": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", - "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint/node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "node_modules/eslint/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true, "license": "MIT" }, @@ -11793,6 +11978,9 @@ } }, "node_modules/express": { + "version": "4.22.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.22.1.tgz", + "integrity": "sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g==", "version": "4.22.1", "resolved": "https://registry.npmjs.org/express/-/express-4.22.1.tgz", "integrity": "sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g==", @@ -11802,9 +11990,13 @@ "array-flatten": "1.1.1", "body-parser": "~1.20.3", "content-disposition": "~0.5.4", + "body-parser": "~1.20.3", + "content-disposition": "~0.5.4", "content-type": "~1.0.4", "cookie": "~0.7.1", "cookie-signature": "~1.0.6", + "cookie": "~0.7.1", + "cookie-signature": "~1.0.6", "debug": "2.6.9", "depd": "2.0.0", "encodeurl": "~2.0.0", @@ -11813,19 +12005,28 @@ "finalhandler": "~1.3.1", "fresh": "~0.5.2", "http-errors": "~2.0.0", + "finalhandler": "~1.3.1", + "fresh": "~0.5.2", + "http-errors": "~2.0.0", "merge-descriptors": "1.0.3", "methods": "~1.1.2", "on-finished": "~2.4.1", + "on-finished": "~2.4.1", "parseurl": "~1.3.3", "path-to-regexp": "~0.1.12", + "path-to-regexp": "~0.1.12", "proxy-addr": "~2.0.7", "qs": "~6.14.0", + "qs": "~6.14.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", "send": "~0.19.0", "serve-static": "~1.16.2", + "send": "~0.19.0", + "serve-static": "~1.16.2", "setprototypeof": "1.2.0", "statuses": "~2.0.1", + "statuses": "~2.0.1", "type-is": "~1.6.18", "utils-merge": "1.0.1", "vary": "~1.1.2" @@ -12167,6 +12368,9 @@ } }, "node_modules/finalhandler": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.2.tgz", + "integrity": "sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg==", "version": "1.3.2", "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.2.tgz", "integrity": "sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg==", @@ -12176,8 +12380,10 @@ "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "on-finished": "~2.4.1", + "on-finished": "~2.4.1", "parseurl": "~1.3.3", "statuses": "~2.0.2", + "statuses": "~2.0.2", "unpipe": "~1.0.0" }, "engines": { @@ -12318,23 +12524,6 @@ "node": "^10.12.0 || >=12.0.0" } }, - "node_modules/flat-cache/node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", - "dev": true, - "license": "ISC", - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/flatted": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", @@ -12398,9 +12587,9 @@ } }, "node_modules/form-data": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz", - "integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", + "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", "license": "MIT", "dependencies": { "asynckit": "^0.4.0", @@ -12451,42 +12640,6 @@ "readable-stream": "^2.0.0" } }, - "node_modules/from2/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "license": "MIT" - }, - "node_modules/from2/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/from2/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "license": "MIT" - }, - "node_modules/from2/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, "node_modules/fromentries": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/fromentries/-/fromentries-1.3.2.tgz", @@ -13269,6 +13422,9 @@ } }, "node_modules/http-errors": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", "version": "2.0.1", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", @@ -13279,6 +13435,11 @@ "setprototypeof": "~1.2.0", "statuses": "~2.0.2", "toidentifier": "~1.0.1" + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" }, "engines": { "node": ">= 0.8" @@ -14013,11 +14174,15 @@ } }, "node_modules/inquirer/node_modules/@inquirer/external-editor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-1.0.3.tgz", + "integrity": "sha512-RWbSrDiYmO4LbejWY7ttpxczuwQyZLBUyygsA9Nsv95hpzUWwnNTVQmAq3xuh7vNwCp07UTmE5i11XAEExx4RA==", "version": "1.0.3", "resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-1.0.3.tgz", "integrity": "sha512-RWbSrDiYmO4LbejWY7ttpxczuwQyZLBUyygsA9Nsv95hpzUWwnNTVQmAq3xuh7vNwCp07UTmE5i11XAEExx4RA==", "license": "MIT", "dependencies": { + "chardet": "^2.1.1", "chardet": "^2.1.1", "iconv-lite": "^0.7.0" }, @@ -14835,9 +15000,9 @@ } }, "node_modules/isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", "license": "MIT" }, "node_modules/isexe": { @@ -14913,36 +15078,6 @@ "node": ">=8" } }, - "node_modules/istanbul-lib-processinfo/node_modules/p-map": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz", - "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "aggregate-error": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-processinfo/node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", - "dev": true, - "license": "ISC", - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/istanbul-lib-processinfo/node_modules/uuid": { "version": "8.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", @@ -15014,6 +15149,7 @@ "version": "3.4.3", "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, "license": "BlueOak-1.0.0", "dependencies": { "@isaacs/cliui": "^8.0.2" @@ -16014,6 +16150,9 @@ "license": "MIT" }, "node_modules/js-yaml": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", "version": "4.1.1", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", @@ -16503,6 +16642,18 @@ "node": ">=4" } }, + "node_modules/listr-update-renderer/node_modules/log-symbols": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-1.0.2.tgz", + "integrity": "sha512-mmPrW0Fh2fxOzdBbFv4g1m6pR72haFLPJ2G5SJEELf1y+iaQrDG6cWCPjy54RHYbZAt7X+ls690Kw62AdWXBzQ==", + "license": "MIT", + "dependencies": { + "chalk": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/listr-update-renderer/node_modules/strip-ansi": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", @@ -16677,6 +16828,15 @@ "node": ">=0.10.0" } }, + "node_modules/listr/node_modules/p-map": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz", + "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/localStorage": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/localStorage/-/localStorage-1.0.4.tgz", @@ -16800,79 +16960,19 @@ "license": "MIT" }, "node_modules/log-symbols": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-1.0.2.tgz", - "integrity": "sha512-mmPrW0Fh2fxOzdBbFv4g1m6pR72haFLPJ2G5SJEELf1y+iaQrDG6cWCPjy54RHYbZAt7X+ls690Kw62AdWXBzQ==", - "license": "MIT", - "dependencies": { - "chalk": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/log-symbols/node_modules/ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/log-symbols/node_modules/ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/log-symbols/node_modules/chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", "license": "MIT", "dependencies": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" }, "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/log-symbols/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "license": "MIT", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/log-symbols/node_modules/strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", - "license": "MIT", - "dependencies": { - "ansi-regex": "^2.0.0" + "node": ">=10" }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/log-symbols/node_modules/supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", - "license": "MIT", - "engines": { - "node": ">=0.8.0" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/log-update": { @@ -20463,19 +20563,6 @@ "node": ">=8" } }, - "node_modules/nyc/node_modules/p-map": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz", - "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "aggregate-error": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/nyc/node_modules/resolve-from": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", @@ -20486,23 +20573,6 @@ "node": ">=8" } }, - "node_modules/nyc/node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", - "dev": true, - "license": "ISC", - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/nyc/node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", @@ -20733,6 +20803,9 @@ "@oclif/plugin-help": "^6.2.36", "@oclif/plugin-not-found": "^3.2.73", "@oclif/plugin-warn-if-update-available": "^3.1.53", + "@oclif/plugin-help": "^6.2.36", + "@oclif/plugin-not-found": "^3.2.73", + "@oclif/plugin-warn-if-update-available": "^3.1.53", "ansis": "^3.16.0", "async-retry": "^1.3.3", "change-case": "^4", @@ -21169,12 +21242,16 @@ } }, "node_modules/p-map": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz", - "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz", + "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==", + "dev": true, "license": "MIT", + "dependencies": { + "aggregate-error": "^3.0.0" + }, "engines": { - "node": ">=6" + "node": ">=8" } }, "node_modules/p-try": { @@ -21328,6 +21405,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -21340,26 +21418,29 @@ "license": "MIT" }, "node_modules/path-scurry": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", - "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.1.tgz", + "integrity": "sha512-oWyT4gICAu+kaA7QWk/jvCHWarMKNs6pXOGWKDTr7cw4IGcUbW+PeTfbaQiLGheFRpjo6O9J0PmyMfQPjH71oA==", "license": "BlueOak-1.0.0", "dependencies": { - "lru-cache": "^10.2.0", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" }, "engines": { - "node": ">=16 || 14 >=14.18" + "node": "20 || >=22" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, "node_modules/path-scurry/node_modules/lru-cache": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "license": "ISC" + "version": "11.2.4", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.4.tgz", + "integrity": "sha512-B5Y16Jr9LB9dHVkh6ZevG+vAbOsNOYCX+sXvFWFu7B3Iz5mijW3zdbMyhsh8ANd2mSWBYdJgnqi+mL7/LrOPYg==", + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } }, "node_modules/path-scurry/node_modules/minipass": { "version": "7.1.2", @@ -21646,6 +21727,9 @@ } }, "node_modules/pretty-format/node_modules/@types/yargs": { + "version": "15.0.20", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.20.tgz", + "integrity": "sha512-KIkX+/GgfFitlASYCGoSF+T4XRXhOubJLhkLVtSfsRTe9jWMmuM2g28zQ41BtPTG7TRBb2xHW+LCNVE9QR/vsg==", "version": "15.0.20", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.20.tgz", "integrity": "sha512-KIkX+/GgfFitlASYCGoSF+T4XRXhOubJLhkLVtSfsRTe9jWMmuM2g28zQ41BtPTG7TRBb2xHW+LCNVE9QR/vsg==", @@ -21710,42 +21794,6 @@ "through2": "~2.0.3" } }, - "node_modules/progress-stream/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "license": "MIT" - }, - "node_modules/progress-stream/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/progress-stream/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "license": "MIT" - }, - "node_modules/progress-stream/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, "node_modules/progress-stream/node_modules/through2": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", @@ -22003,6 +22051,9 @@ } }, "node_modules/raw-body": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.3.tgz", + "integrity": "sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==", "version": "2.5.3", "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.3.tgz", "integrity": "sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==", @@ -22012,6 +22063,10 @@ "http-errors": "~2.0.1", "iconv-lite": "~0.4.24", "unpipe": "~1.0.0" + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.4.24", + "unpipe": "~1.0.0" }, "engines": { "node": ">= 0.8" @@ -22176,19 +22231,26 @@ } }, "node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "license": "MIT", "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, + "node_modules/readable-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, "node_modules/readdirp": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", @@ -22673,6 +22735,9 @@ } }, "node_modules/rewire/node_modules/@eslint/eslintrc": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.3.tgz", + "integrity": "sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==", "version": "3.3.3", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.3.tgz", "integrity": "sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==", @@ -22686,6 +22751,7 @@ "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.1", + "js-yaml": "^4.1.1", "minimatch": "^3.1.2", "strip-json-comments": "^3.1.1" }, @@ -22906,12 +22972,14 @@ } }, "node_modules/rimraf": { - "version": "5.0.10", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.10.tgz", - "integrity": "sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, "license": "ISC", "dependencies": { - "glob": "^10.3.7" + "glob": "^7.1.3" }, "bin": { "rimraf": "dist/esm/bin.mjs" @@ -23101,6 +23169,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/safe-array-concat/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "license": "MIT" + }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -23137,6 +23211,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/safe-push-apply/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "license": "MIT" + }, "node_modules/safe-regex-test": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", @@ -23191,6 +23271,7 @@ "depd": "2.0.0", "destroy": "1.2.0", "encodeurl": "~2.0.0", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", "fresh": "~0.5.2", @@ -23257,6 +23338,79 @@ "node": ">= 0.8.0" } }, + "node_modules/serve-static/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/serve-static/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/serve-static/node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "license": "MIT", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/serve-static/node_modules/send": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/serve-static/node_modules/send/node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/serve-static/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", @@ -23319,6 +23473,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" @@ -23331,6 +23486,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -23696,7 +23852,10 @@ "integrity": "sha512-up04hB2hR92PgjpyU3y/eg91yIBILyjVY26NvvciY3EVVPjybkMszMpXQ9QAkcS3I5rtJBDLoTxxg+qvW8c7rw==", "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" } }, "node_modules/smartwrap": { @@ -23992,23 +24151,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/spawn-wrap/node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", - "dev": true, - "license": "ISC", - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/spawn-wrap/node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", @@ -24135,6 +24277,9 @@ } }, "node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", "version": "2.0.2", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", @@ -24191,6 +24336,20 @@ "readable-stream": "^3.5.0" } }, + "node_modules/stream-browserify/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/stream-connect": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/stream-connect/-/stream-connect-1.0.2.tgz", @@ -24238,14 +24397,20 @@ } }, "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "license": "MIT", "dependencies": { - "safe-buffer": "~5.2.0" + "safe-buffer": "~5.1.0" } }, + "node_modules/string_decoder/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, "node_modules/string-length": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", @@ -24279,6 +24444,7 @@ "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", @@ -24362,6 +24528,7 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" @@ -24522,24 +24689,6 @@ "node": ">=4" } }, - "node_modules/table/node_modules/slice-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", - "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/slice-ansi?sponsor=1" - } - }, "node_modules/tapable": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz", @@ -24762,6 +24911,10 @@ "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", "license": "MIT" + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "license": "MIT" }, "node_modules/traverse": { "version": "0.6.11", @@ -24838,6 +24991,9 @@ } }, "node_modules/ts-jest": { + "version": "29.4.6", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.4.6.tgz", + "integrity": "sha512-fSpWtOO/1AjSNQguk43hb/JCo16oJDnMJf3CdEGNkqsEX3t0KX96xvyX1D7PfLCpVoKu4MfVrqUkFyblYoY4lA==", "version": "29.4.6", "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.4.6.tgz", "integrity": "sha512-fSpWtOO/1AjSNQguk43hb/JCo16oJDnMJf3CdEGNkqsEX3t0KX96xvyX1D7PfLCpVoKu4MfVrqUkFyblYoY4lA==", @@ -25009,36 +25165,17 @@ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "license": "0BSD" }, - "node_modules/tsutils": { - "version": "3.21.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", - "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", - "dev": true, - "license": "MIT", - "dependencies": { - "tslib": "^1.8.1" - }, - "engines": { - "node": ">= 6" - }, - "peerDependencies": { - "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" - } - }, - "node_modules/tsutils/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true, - "license": "0BSD" - }, "node_modules/tsx": { + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz", + "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==", "version": "4.21.0", "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz", "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==", "dev": true, "license": "MIT", "dependencies": { + "esbuild": "~0.27.0", "esbuild": "~0.27.0", "get-tsconfig": "^4.7.5" }, @@ -25828,6 +25965,9 @@ "license": "BSD-2-Clause" }, "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", "version": "5.0.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", @@ -25835,6 +25975,8 @@ "dependencies": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" } }, "node_modules/which": { @@ -25898,6 +26040,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/which-builtin-type/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "license": "MIT" + }, "node_modules/which-collection": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", @@ -25956,6 +26104,9 @@ } }, "node_modules/winston": { + "version": "3.19.0", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.19.0.tgz", + "integrity": "sha512-LZNJgPzfKR+/J3cHkxcpHKpKKvGfDZVPS4hfJCc4cCG0CgYzvlD6yE/S3CIL/Yt91ak327YCpiF/0MyeZHEHKA==", "version": "3.19.0", "resolved": "https://registry.npmjs.org/winston/-/winston-3.19.0.tgz", "integrity": "sha512-LZNJgPzfKR+/J3cHkxcpHKpKKvGfDZVPS4hfJCc4cCG0CgYzvlD6yE/S3CIL/Yt91ak327YCpiF/0MyeZHEHKA==", @@ -25991,6 +26142,34 @@ "node": ">= 12.0.0" } }, + "node_modules/winston-transport/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/winston/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/word-wrap": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", @@ -26060,6 +26239,7 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", @@ -26362,14 +26542,14 @@ }, "packages/contentstack-audit": { "name": "@contentstack/cli-audit", - "version": "1.16.0", + "version": "1.16.1", "license": "MIT", "dependencies": { "@contentstack/cli-command": "~1.6.1", "@contentstack/cli-utilities": "~1.15.0", "@oclif/core": "^4.3.0", "@oclif/plugin-help": "^6.2.28", - "@oclif/plugin-plugins": "^5.4.38", + "@oclif/plugin-plugins": "^5.4.54", "chalk": "^4.1.2", "fast-csv": "^4.3.6", "fs-extra": "^11.3.0", @@ -26437,6 +26617,7 @@ "packages/contentstack-auth": { "name": "@contentstack/cli-auth", "version": "1.6.2", + "version": "1.6.2", "license": "MIT", "dependencies": { "@contentstack/cli-command": "~1.6.1", @@ -26659,6 +26840,7 @@ "packages/contentstack-branches": { "name": "@contentstack/cli-cm-branches", "version": "1.6.1", + "version": "1.6.1", "license": "MIT", "dependencies": { "@contentstack/cli-command": "~1.6.1", @@ -26718,6 +26900,175 @@ "node": ">=14.0.0" } }, + "packages/contentstack-bulk-publish/node_modules/@contentstack/cli-config": { + "version": "1.15.3", + "resolved": "https://registry.npmjs.org/@contentstack/cli-config/-/cli-config-1.15.3.tgz", + "integrity": "sha512-sZlJt2C28ReIZpFcBNkXy41QDZvMhDzpLfD3EjGLZYGD82/qqT/7mhdsOScigu5PXUmhHI1z+5yx/DaAEAkBnQ==", + "license": "MIT", + "dependencies": { + "@contentstack/cli-command": "~1.6.1", + "@contentstack/cli-utilities": "~1.15.0", + "@oclif/core": "^4.3.0", + "@oclif/plugin-help": "^6.2.28", + "lodash": "^4.17.21" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "packages/contentstack-bulk-publish/node_modules/@contentstack/cli-config/node_modules/@contentstack/cli-command": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@contentstack/cli-command/-/cli-command-1.6.1.tgz", + "integrity": "sha512-WS4k2i+chuwmOrHqJC2N4aWOEpQ+DxrHXtMhya2uMwH25ES203C0o4hm+NwD2gi7Ea5AQycBoi8JHOF0vAQ4WA==", + "license": "MIT", + "dependencies": { + "@contentstack/cli-utilities": "~1.14.0", + "@oclif/core": "^4.3.0", + "@oclif/plugin-help": "^6.2.28", + "contentstack": "^3.25.3" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "packages/contentstack-bulk-publish/node_modules/@contentstack/cli-config/node_modules/@contentstack/cli-command/node_modules/@contentstack/cli-utilities": { + "version": "1.14.4", + "resolved": "https://registry.npmjs.org/@contentstack/cli-utilities/-/cli-utilities-1.14.4.tgz", + "integrity": "sha512-Pg124tYh/p688aerqVgk8lEsCF8F5Ky35yes3KO23Wzt44Hvzps7X27psOTHs/aD4jhZkw3aB+jTItQlL84b8g==", + "license": "MIT", + "dependencies": { + "@contentstack/management": "~1.25.1", + "@contentstack/marketplace-sdk": "^1.4.0", + "@oclif/core": "^4.3.0", + "axios": "^1.9.0", + "chalk": "^4.1.2", + "cli-cursor": "^3.1.0", + "cli-progress": "^3.12.0", + "cli-table": "^0.3.11", + "conf": "^10.2.0", + "dotenv": "^16.5.0", + "figures": "^3.2.0", + "inquirer": "8.2.6", + "inquirer-search-checkbox": "^1.0.0", + "inquirer-search-list": "^1.2.6", + "js-yaml": "^4.1.0", + "klona": "^2.0.6", + "lodash": "^4.17.21", + "mkdirp": "^1.0.4", + "open": "^8.4.2", + "ora": "^5.4.1", + "papaparse": "^5.5.3", + "recheck": "~4.4.5", + "rxjs": "^6.6.7", + "traverse": "^0.6.11", + "tty-table": "^4.2.3", + "unique-string": "^2.0.0", + "uuid": "^9.0.1", + "winston": "^3.17.0", + "xdg-basedir": "^4.0.0" + } + }, + "packages/contentstack-bulk-publish/node_modules/@contentstack/cli-config/node_modules/inquirer": { + "version": "8.2.6", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.6.tgz", + "integrity": "sha512-M1WuAmb7pn9zdFRtQYk26ZBoY043Sse0wVDdk4Bppr+JOXyQYybdtvK+l9wUibhtjdjvtoiNy8tk+EgsYIUqKg==", + "license": "MIT", + "dependencies": { + "ansi-escapes": "^4.2.1", + "chalk": "^4.1.1", + "cli-cursor": "^3.1.0", + "cli-width": "^3.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.21", + "mute-stream": "0.0.8", + "ora": "^5.4.1", + "run-async": "^2.4.0", + "rxjs": "^7.5.5", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6", + "wrap-ansi": "^6.0.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "packages/contentstack-bulk-publish/node_modules/@contentstack/cli-config/node_modules/inquirer/node_modules/rxjs": { + "version": "7.8.2", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", + "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "packages/contentstack-bulk-publish/node_modules/@contentstack/management": { + "version": "1.25.1", + "resolved": "https://registry.npmjs.org/@contentstack/management/-/management-1.25.1.tgz", + "integrity": "sha512-454V3zGw4nrxnlYxXm82Z+yNjuechiN+TRE7SXWyHFUsexYVpKNyGyKZCvG6b4JymRTVUZpy/KnFixo01GP9Sg==", + "license": "MIT", + "dependencies": { + "assert": "^2.1.0", + "axios": "^1.12.2", + "buffer": "^6.0.3", + "form-data": "^4.0.4", + "husky": "^9.1.7", + "lodash": "^4.17.21", + "otplib": "^12.0.1", + "qs": "^6.14.0", + "stream-browserify": "^3.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "packages/contentstack-bulk-publish/node_modules/chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "license": "MIT" + }, + "packages/contentstack-bulk-publish/node_modules/external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "license": "MIT", + "dependencies": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + }, + "engines": { + "node": ">=4" + } + }, + "packages/contentstack-bulk-publish/node_modules/tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "license": "MIT", + "dependencies": { + "os-tmpdir": "~1.0.2" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "packages/contentstack-bulk-publish/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, "packages/contentstack-clone": { "name": "@contentstack/cli-cm-clone", "version": "2.0.0-beta.2", @@ -26738,8 +27089,7 @@ "merge": "^2.1.1", "ora": "^5.4.1", "prompt": "^1.3.0", - "rimraf": "^5.0.10", - "winston": "^3.17.0" + "rimraf": "^6.1.0" }, "devDependencies": { "@oclif/test": "^4.1.13", @@ -26869,6 +27219,7 @@ "version": "1.6.2", "license": "MIT", "dependencies": { + "@contentstack/cli-utilities": "~1.15.0", "@contentstack/cli-utilities": "~1.15.0", "@oclif/core": "^4.3.0", "@oclif/plugin-help": "^6.2.28", @@ -27143,6 +27494,20 @@ "url": "https://opencollective.com/eslint" } }, + "packages/contentstack-dev-dependencies/node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, "packages/contentstack-dev-dependencies/node_modules/eslint-utils": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", @@ -27204,6 +27569,16 @@ "node": ">=4" } }, + "packages/contentstack-dev-dependencies/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, "packages/contentstack-dev-dependencies/node_modules/glob-parent": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", @@ -27228,6 +27603,9 @@ } }, "packages/contentstack-dev-dependencies/node_modules/js-yaml": { + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", + "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", "version": "3.14.2", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", @@ -27282,8 +27660,8 @@ "winston": "^3.17.0" }, "devDependencies": { - "@contentstack/cli-auth": "~1.6.1", - "@contentstack/cli-config": "~1.15.1", + "@contentstack/cli-auth": "~1.6.2", + "@contentstack/cli-config": "~1.15.3", "@contentstack/cli-dev-dependencies": "~1.3.1", "@oclif/plugin-help": "^6.2.28", "@oclif/test": "^4.1.13", @@ -27312,7 +27690,7 @@ }, "packages/contentstack-export-to-csv": { "name": "@contentstack/cli-cm-export-to-csv", - "version": "1.10.0", + "version": "1.10.1", "license": "MIT", "dependencies": { "@contentstack/cli-command": "~1.6.1", @@ -27512,6 +27890,20 @@ "url": "https://opencollective.com/eslint" } }, + "packages/contentstack-export-to-csv/node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, "packages/contentstack-export-to-csv/node_modules/eslint-utils": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", @@ -27573,6 +27965,16 @@ "node": ">=4" } }, + "packages/contentstack-export-to-csv/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, "packages/contentstack-export-to-csv/node_modules/glob-parent": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", @@ -27597,6 +27999,9 @@ } }, "packages/contentstack-export-to-csv/node_modules/js-yaml": { + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", + "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", "version": "3.14.2", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", @@ -27645,12 +28050,104 @@ "url": "https://github.com/sponsors/isaacs" } }, - "packages/contentstack-export/node_modules/@sinonjs/fake-timers": { - "version": "11.3.1", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-11.3.1.tgz", - "integrity": "sha512-EVJO7nW5M/F5Tur0Rf2z/QoMo+1Ia963RiMtapiQrEWvY0iBUvADo8Beegwjpnle5BHkyHuoxSTW3jF43H1XRA==", + "packages/contentstack-export/node_modules/@contentstack/cli-config": { + "version": "1.15.3", + "resolved": "https://registry.npmjs.org/@contentstack/cli-config/-/cli-config-1.15.3.tgz", + "integrity": "sha512-sZlJt2C28ReIZpFcBNkXy41QDZvMhDzpLfD3EjGLZYGD82/qqT/7mhdsOScigu5PXUmhHI1z+5yx/DaAEAkBnQ==", "dev": true, - "license": "BSD-3-Clause", + "license": "MIT", + "dependencies": { + "@contentstack/cli-command": "~1.6.1", + "@contentstack/cli-utilities": "~1.15.0", + "@oclif/core": "^4.3.0", + "@oclif/plugin-help": "^6.2.28", + "lodash": "^4.17.21" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "packages/contentstack-export/node_modules/@contentstack/cli-config/node_modules/@contentstack/cli-command": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@contentstack/cli-command/-/cli-command-1.6.1.tgz", + "integrity": "sha512-WS4k2i+chuwmOrHqJC2N4aWOEpQ+DxrHXtMhya2uMwH25ES203C0o4hm+NwD2gi7Ea5AQycBoi8JHOF0vAQ4WA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@contentstack/cli-utilities": "~1.14.0", + "@oclif/core": "^4.3.0", + "@oclif/plugin-help": "^6.2.28", + "contentstack": "^3.25.3" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "packages/contentstack-export/node_modules/@contentstack/cli-config/node_modules/@contentstack/cli-command/node_modules/@contentstack/cli-utilities": { + "version": "1.14.4", + "resolved": "https://registry.npmjs.org/@contentstack/cli-utilities/-/cli-utilities-1.14.4.tgz", + "integrity": "sha512-Pg124tYh/p688aerqVgk8lEsCF8F5Ky35yes3KO23Wzt44Hvzps7X27psOTHs/aD4jhZkw3aB+jTItQlL84b8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@contentstack/management": "~1.25.1", + "@contentstack/marketplace-sdk": "^1.4.0", + "@oclif/core": "^4.3.0", + "axios": "^1.9.0", + "chalk": "^4.1.2", + "cli-cursor": "^3.1.0", + "cli-progress": "^3.12.0", + "cli-table": "^0.3.11", + "conf": "^10.2.0", + "dotenv": "^16.5.0", + "figures": "^3.2.0", + "inquirer": "8.2.6", + "inquirer-search-checkbox": "^1.0.0", + "inquirer-search-list": "^1.2.6", + "js-yaml": "^4.1.0", + "klona": "^2.0.6", + "lodash": "^4.17.21", + "mkdirp": "^1.0.4", + "open": "^8.4.2", + "ora": "^5.4.1", + "papaparse": "^5.5.3", + "recheck": "~4.4.5", + "rxjs": "^6.6.7", + "traverse": "^0.6.11", + "tty-table": "^4.2.3", + "unique-string": "^2.0.0", + "uuid": "^9.0.1", + "winston": "^3.17.0", + "xdg-basedir": "^4.0.0" + } + }, + "packages/contentstack-export/node_modules/@contentstack/management": { + "version": "1.25.1", + "resolved": "https://registry.npmjs.org/@contentstack/management/-/management-1.25.1.tgz", + "integrity": "sha512-454V3zGw4nrxnlYxXm82Z+yNjuechiN+TRE7SXWyHFUsexYVpKNyGyKZCvG6b4JymRTVUZpy/KnFixo01GP9Sg==", + "dev": true, + "license": "MIT", + "dependencies": { + "assert": "^2.1.0", + "axios": "^1.12.2", + "buffer": "^6.0.3", + "form-data": "^4.0.4", + "husky": "^9.1.7", + "lodash": "^4.17.21", + "otplib": "^12.0.1", + "qs": "^6.14.0", + "stream-browserify": "^3.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "packages/contentstack-export/node_modules/@sinonjs/fake-timers": { + "version": "11.3.1", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-11.3.1.tgz", + "integrity": "sha512-EVJO7nW5M/F5Tur0Rf2z/QoMo+1Ia963RiMtapiQrEWvY0iBUvADo8Beegwjpnle5BHkyHuoxSTW3jF43H1XRA==", + "dev": true, + "license": "BSD-3-Clause", "dependencies": { "@sinonjs/commons": "^3.0.1" } @@ -27672,6 +28169,65 @@ "@types/sinonjs__fake-timers": "*" } }, + "packages/contentstack-export/node_modules/chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "dev": true, + "license": "MIT" + }, + "packages/contentstack-export/node_modules/external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dev": true, + "license": "MIT", + "dependencies": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + }, + "engines": { + "node": ">=4" + } + }, + "packages/contentstack-export/node_modules/inquirer": { + "version": "8.2.6", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.6.tgz", + "integrity": "sha512-M1WuAmb7pn9zdFRtQYk26ZBoY043Sse0wVDdk4Bppr+JOXyQYybdtvK+l9wUibhtjdjvtoiNy8tk+EgsYIUqKg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-escapes": "^4.2.1", + "chalk": "^4.1.1", + "cli-cursor": "^3.1.0", + "cli-width": "^3.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.21", + "mute-stream": "0.0.8", + "ora": "^5.4.1", + "run-async": "^2.4.0", + "rxjs": "^7.5.5", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6", + "wrap-ansi": "^6.0.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "packages/contentstack-export/node_modules/inquirer/node_modules/rxjs": { + "version": "7.8.2", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", + "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" + } + }, "packages/contentstack-export/node_modules/nise": { "version": "5.1.9", "resolved": "https://registry.npmjs.org/nise/-/nise-5.1.9.tgz", @@ -27725,6 +28281,34 @@ "node": ">=8" } }, + "packages/contentstack-export/node_modules/tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "os-tmpdir": "~1.0.2" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "packages/contentstack-export/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, "packages/contentstack-import": { "name": "@contentstack/cli-cm-import", "version": "2.0.0-beta.2", @@ -27883,6 +28467,35 @@ "node": ">=14.0.0" } }, + "packages/contentstack-seed/node_modules/@contentstack/cli-cm-import": { + "version": "1.30.0", + "resolved": "https://registry.npmjs.org/@contentstack/cli-cm-import/-/cli-cm-import-1.30.0.tgz", + "integrity": "sha512-FD+KY+RkAwBP2GK7rg8Zbgp/a4fMSYcXUqwqCZRRlgHUl1T9LOjXAtwktgqHBOdN596WPPihVFh8XZ9wWIwWpA==", + "license": "MIT", + "dependencies": { + "@contentstack/cli-audit": "~1.16.1", + "@contentstack/cli-command": "~1.7.0", + "@contentstack/cli-utilities": "~1.15.0", + "@contentstack/cli-variants": "~1.3.5", + "@contentstack/management": "~1.22.0", + "@oclif/core": "^4.3.0", + "big-json": "^3.2.0", + "bluebird": "^3.7.2", + "chalk": "^4.1.2", + "debug": "^4.4.1", + "fs-extra": "^11.3.0", + "lodash": "^4.17.21", + "marked": "^4.3.0", + "merge": "^2.1.1", + "mkdirp": "^1.0.4", + "promise-limit": "^2.7.0", + "uuid": "^9.0.1", + "winston": "^3.17.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, "packages/contentstack-seed/node_modules/diff": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", @@ -27922,6 +28535,7 @@ "packages/contentstack-utilities": { "name": "@contentstack/cli-utilities", "version": "1.15.0", + "version": "1.15.0", "license": "MIT", "dependencies": { "@contentstack/management": "~1.25.1", @@ -27938,7 +28552,7 @@ "inquirer": "8.2.7", "inquirer-search-checkbox": "^1.0.0", "inquirer-search-list": "^1.2.6", - "js-yaml": "^4.1.0", + "js-yaml": "^4.1.1", "klona": "^2.0.6", "lodash": "^4.17.21", "mkdirp": "^1.0.4", @@ -28066,6 +28680,7 @@ "version": "2.0.0-beta.2", "license": "MIT", "dependencies": { + "@contentstack/cli-utilities": "~1.15.0", "@contentstack/cli-utilities": "~1.15.0", "@oclif/core": "^4.3.0", "@oclif/plugin-help": "^6.2.28", @@ -28107,6 +28722,107 @@ "engines": { "node": ">=14.17" } + }, + "packages/contentstack/node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "dev": true, + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "packages/contentstack/node_modules/glob": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", + "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "packages/contentstack/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, + "packages/contentstack/node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "packages/contentstack/node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "packages/contentstack/node_modules/rimraf": { + "version": "5.0.10", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.10.tgz", + "integrity": "sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^10.3.7" + }, + "bin": { + "rimraf": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "packages/contentstack/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } } } } diff --git a/packages/contentstack-audit/README.md b/packages/contentstack-audit/README.md index 327e843014..6a25bd15d9 100644 --- a/packages/contentstack-audit/README.md +++ b/packages/contentstack-audit/README.md @@ -19,7 +19,7 @@ $ npm install -g @contentstack/cli-audit $ csdx COMMAND running command... $ csdx (--version|-v) -@contentstack/cli-audit/1.14.2 darwin-arm64 node-v22.14.0 +@contentstack/cli-audit/1.16.1 darwin-arm64 node-v23.11.0 $ csdx --help [COMMAND] USAGE $ csdx COMMAND @@ -273,7 +273,7 @@ USAGE $ csdx help [COMMAND...] [-n] ARGUMENTS - COMMAND... Command to show help for. + [COMMAND...] Command to show help for. FLAGS -n, --nested-commands Include all nested commands in the output. @@ -282,8 +282,7 @@ DESCRIPTION Display help for csdx. ``` -_See code: [@oclif/plugin-help](https://github.com/oclif/plugin-help/blob/v6.2.33/src/commands/help.ts)_ -_See code: [@oclif/plugin-help](https://github.com/oclif/plugin-help/blob/v6.2.33/src/commands/help.ts)_ +_See code: [@oclif/plugin-help](https://github.com/oclif/plugin-help/blob/v6.2.34/src/commands/help.ts)_ ## `csdx plugins` @@ -306,7 +305,7 @@ EXAMPLES $ csdx plugins ``` -_See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v5.4.49/src/commands/plugins/index.ts)_ +_See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v5.4.52/src/commands/plugins/index.ts)_ ## `csdx plugins:add PLUGIN` @@ -380,7 +379,7 @@ EXAMPLES $ csdx plugins:inspect myplugin ``` -_See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v5.4.49/src/commands/plugins/inspect.ts)_ +_See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v5.4.52/src/commands/plugins/inspect.ts)_ ## `csdx plugins:install PLUGIN` @@ -429,7 +428,7 @@ EXAMPLES $ csdx plugins:install someuser/someplugin ``` -_See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v5.4.49/src/commands/plugins/install.ts)_ +_See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v5.4.52/src/commands/plugins/install.ts)_ ## `csdx plugins:link PATH` @@ -460,7 +459,7 @@ EXAMPLES $ csdx plugins:link myplugin ``` -_See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v5.4.49/src/commands/plugins/link.ts)_ +_See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v5.4.52/src/commands/plugins/link.ts)_ ## `csdx plugins:remove [PLUGIN]` @@ -471,7 +470,7 @@ USAGE $ csdx plugins:remove [PLUGIN...] [-h] [-v] ARGUMENTS - PLUGIN... plugin to uninstall + [PLUGIN...] plugin to uninstall FLAGS -h, --help Show CLI help. @@ -501,7 +500,7 @@ FLAGS --reinstall Reinstall all plugins after uninstalling. ``` -_See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v5.4.49/src/commands/plugins/reset.ts)_ +_See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v5.4.52/src/commands/plugins/reset.ts)_ ## `csdx plugins:uninstall [PLUGIN]` @@ -512,7 +511,7 @@ USAGE $ csdx plugins:uninstall [PLUGIN...] [-h] [-v] ARGUMENTS - PLUGIN... plugin to uninstall + [PLUGIN...] plugin to uninstall FLAGS -h, --help Show CLI help. @@ -529,7 +528,7 @@ EXAMPLES $ csdx plugins:uninstall myplugin ``` -_See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v5.4.49/src/commands/plugins/uninstall.ts)_ +_See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v5.4.52/src/commands/plugins/uninstall.ts)_ ## `csdx plugins:unlink [PLUGIN]` @@ -540,7 +539,7 @@ USAGE $ csdx plugins:unlink [PLUGIN...] [-h] [-v] ARGUMENTS - PLUGIN... plugin to uninstall + [PLUGIN...] plugin to uninstall FLAGS -h, --help Show CLI help. @@ -573,5 +572,5 @@ DESCRIPTION Update installed plugins. ``` -_See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v5.4.49/src/commands/plugins/update.ts)_ +_See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v5.4.52/src/commands/plugins/update.ts)_ diff --git a/packages/contentstack-audit/package.json b/packages/contentstack-audit/package.json index f8d0eff690..d107d41b95 100644 --- a/packages/contentstack-audit/package.json +++ b/packages/contentstack-audit/package.json @@ -1,6 +1,6 @@ { "name": "@contentstack/cli-audit", - "version": "1.16.0", + "version": "1.16.1", "description": "Contentstack audit plugin", "author": "Contentstack CLI", "homepage": "https://github.com/contentstack/cli", @@ -18,11 +18,11 @@ "/oclif.manifest.json" ], "dependencies": { - "@contentstack/cli-command": "~1.6.1", + "@contentstack/cli-command": "~1.7.0", "@contentstack/cli-utilities": "~1.15.0", "@oclif/core": "^4.3.0", "@oclif/plugin-help": "^6.2.28", - "@oclif/plugin-plugins": "^5.4.38", + "@oclif/plugin-plugins": "^5.4.54", "chalk": "^4.1.2", "fast-csv": "^4.3.6", "fs-extra": "^11.3.0", diff --git a/packages/contentstack-audit/src/audit-base-command.ts b/packages/contentstack-audit/src/audit-base-command.ts index c588581241..caeb54f03e 100644 --- a/packages/contentstack-audit/src/audit-base-command.ts +++ b/packages/contentstack-audit/src/audit-base-command.ts @@ -271,11 +271,11 @@ export abstract class AuditBaseCommand extends BaseCommand { }); }); }); + + describe('prepareReport method - Report file names', () => { + fancy + .stdout({ print: process.env.PRINT === 'true' || false }) + .stub(winston.transports, 'File', () => fsTransport) + .stub(winston, 'createLogger', createMockWinstonLogger) + .stub(fs, 'createWriteStream', () => new PassThrough()) + .stub(fs, 'mkdirSync', () => {}) + .stub(fs, 'existsSync', () => true) + .it('should generate report file with correct spelling: Entries_Select_field (not feild)', async () => { + const writeFileSyncSpy = sinon.spy(fs, 'writeFileSync'); + class CMD extends AuditBaseCommand { + async run() { + await this.init(); + this.sharedConfig.reportPath = resolve(__dirname, 'mock', 'contents'); + + await this.prepareReport('Entries_Select_field', { + entry1: { + name: 'Test Entry', + display_name: 'Select Field', + missingRefs: ['ref1'], + }, + }); + + const jsonCall = writeFileSyncSpy.getCalls().find(call => + typeof call.args[0] === 'string' && call.args[0].includes('.json') + ); + return jsonCall ? (jsonCall.args[0] as string) : undefined; + } + } + + const result = await CMD.run([]); + writeFileSyncSpy.restore(); + expect(result).to.include('Entries_Select_field.json'); + expect(result).to.not.include('Entries_Select_feild'); + }); + + fancy + .stdout({ print: process.env.PRINT === 'true' || false }) + .stub(winston.transports, 'File', () => fsTransport) + .stub(winston, 'createLogger', createMockWinstonLogger) + .stub(fs, 'createWriteStream', () => new PassThrough()) + .stub(fs, 'mkdirSync', () => {}) + .stub(fs, 'existsSync', () => true) + .it('should generate report file with correct spelling: Entries_Mandatory_field (not feild)', async () => { + const writeFileSyncSpy = sinon.spy(fs, 'writeFileSync'); + class CMD extends AuditBaseCommand { + async run() { + await this.init(); + this.sharedConfig.reportPath = resolve(__dirname, 'mock', 'contents'); + + await this.prepareReport('Entries_Mandatory_field', { + entry1: { + name: 'Test Entry', + display_name: 'Mandatory Field', + missingRefs: ['ref1'], + }, + }); + + const jsonCall = writeFileSyncSpy.getCalls().find(call => + typeof call.args[0] === 'string' && call.args[0].includes('.json') + ); + return jsonCall ? (jsonCall.args[0] as string) : undefined; + } + } + + const result = await CMD.run([]); + writeFileSyncSpy.restore(); + expect(result).to.include('Entries_Mandatory_field.json'); + expect(result).to.not.include('Entries_Mandatory_feild'); + }); + + fancy + .stdout({ print: process.env.PRINT === 'true' || false }) + .stub(winston.transports, 'File', () => fsTransport) + .stub(winston, 'createLogger', createMockWinstonLogger) + .stub(fs, 'createWriteStream', () => new PassThrough()) + .stub(fs, 'mkdirSync', () => {}) + .stub(fs, 'existsSync', () => true) + .it('should generate report file with correct spelling: Entries_Title_field (not feild)', async () => { + const writeFileSyncSpy = sinon.spy(fs, 'writeFileSync'); + class CMD extends AuditBaseCommand { + async run() { + await this.init(); + this.sharedConfig.reportPath = resolve(__dirname, 'mock', 'contents'); + + await this.prepareReport('Entries_Title_field', { + entry1: { + name: 'Test Entry', + display_name: 'Title Field', + missingRefs: ['ref1'], + }, + }); + + const jsonCall = writeFileSyncSpy.getCalls().find(call => + typeof call.args[0] === 'string' && call.args[0].includes('.json') + ); + return jsonCall ? (jsonCall.args[0] as string) : undefined; + } + } + + const result = await CMD.run([]); + writeFileSyncSpy.restore(); + expect(result).to.include('Entries_Title_field.json'); + expect(result).to.not.include('Entries_Title_feild'); + }); + }); + + describe('Config - ReportTitleForEntries keys', () => { + it('should have correct spelling in ReportTitleForEntries config', () => { + const config = require('../../src/config').default; + + // Verify correct spelling (field, not feild) + expect(config.ReportTitleForEntries).to.have.property('Entries_Select_field'); + expect(config.ReportTitleForEntries).to.have.property('Entries_Mandatory_field'); + expect(config.ReportTitleForEntries).to.have.property('Entries_Title_field'); + + // Verify old typo is not present + expect(config.ReportTitleForEntries).to.not.have.property('Entries_Select_feild'); + expect(config.ReportTitleForEntries).to.not.have.property('Entries_Mandatory_feild'); + expect(config.ReportTitleForEntries).to.not.have.property('Entries_Title_feild'); + + // Verify values match keys + expect(config.ReportTitleForEntries.Entries_Select_field).to.equal('Entries_Select_field'); + expect(config.ReportTitleForEntries.Entries_Mandatory_field).to.equal('Entries_Mandatory_field'); + expect(config.ReportTitleForEntries.Entries_Title_field).to.equal('Entries_Title_field'); + }); + + it('should have correct spelling in feild_level_modules array', () => { + const config = require('../../src/config').default; + + // Verify correct spelling in the array + expect(config.feild_level_modules).to.include('Entries_Select_field'); + expect(config.feild_level_modules).to.include('Entries_Mandatory_field'); + expect(config.feild_level_modules).to.include('Entries_Title_field'); + + // Verify old typo is not present + expect(config.feild_level_modules).to.not.include('Entries_Select_feild'); + expect(config.feild_level_modules).to.not.include('Entries_Mandatory_feild'); + expect(config.feild_level_modules).to.not.include('Entries_Title_feild'); + }); + }); }); diff --git a/packages/contentstack-auth/README.md b/packages/contentstack-auth/README.md index 5c38944bd8..232af38e13 100644 --- a/packages/contentstack-auth/README.md +++ b/packages/contentstack-auth/README.md @@ -18,7 +18,7 @@ $ npm install -g @contentstack/cli-auth $ csdx COMMAND running command... $ csdx (--version) -@contentstack/cli-auth/1.6.2 darwin-arm64 node-v22.14.0 +@contentstack/cli-auth/1.6.2 darwin-arm64 node-v22.13.1 $ csdx --help [COMMAND] USAGE $ csdx COMMAND @@ -145,7 +145,7 @@ FLAGS -e, --environment= Environment name for delivery token -k, --stack-api-key= Stack API Key -m, --management Set this flag to save management token - -t, --token= Add the token name + -t, --token= [env: TOKEN] Add the token name -y, --yes Use this flag to skip confirmation DESCRIPTION diff --git a/packages/contentstack-auth/package.json b/packages/contentstack-auth/package.json index c4a326cd52..6ed99c4b24 100644 --- a/packages/contentstack-auth/package.json +++ b/packages/contentstack-auth/package.json @@ -22,7 +22,7 @@ "test:unit:report": "nyc --extension .ts mocha --forbid-only \"test/unit/**/*.test.ts\"" }, "dependencies": { - "@contentstack/cli-command": "~1.6.1", + "@contentstack/cli-command": "~1.7.0", "@contentstack/cli-utilities": "~1.15.0", "@oclif/core": "^4.3.0", "@oclif/plugin-help": "^6.2.28", diff --git a/packages/contentstack-auth/src/commands/auth/login.ts b/packages/contentstack-auth/src/commands/auth/login.ts index 73ff392398..5af919a995 100644 --- a/packages/contentstack-auth/src/commands/auth/login.ts +++ b/packages/contentstack-auth/src/commands/auth/login.ts @@ -55,12 +55,12 @@ export default class LoginCommand extends BaseCommand { log.debug('LoginCommand run method started', this.contextDetails); try { - log.debug('Initializing management API client', this.contextDetails); + log.debug('Initializing the Management API client.', this.contextDetails); const managementAPIClient = await managementSDKClient({ host: this.cmaHost, skipTokenValidity: true }); - log.debug('Management API client initialized successfully', this.contextDetails); + log.debug('Management API client initialized successfully.', this.contextDetails); const { flags: loginFlags } = await this.parse(LoginCommand); - log.debug('Token add flags parsed', { ...this.contextDetails, flags: loginFlags }); + log.debug('Token add flags parsed.', { ...this.contextDetails, flags: loginFlags }); authHandler.client = managementAPIClient; log.debug('Auth handler client set', this.contextDetails); @@ -86,7 +86,7 @@ export default class LoginCommand extends BaseCommand { await this.login(username, password); } } catch (error) { - log.debug('Login command failed', { + log.debug('Login failed.', { ...this.contextDetails, error, }); @@ -116,7 +116,7 @@ export default class LoginCommand extends BaseCommand { } const user: User = await authHandler.login(username, password, tfaToken); - log.debug('Auth handler login completed', { + log.debug('Auth handler login completed.', { ...this.contextDetails, hasUser: !!user, hasAuthToken: !!user?.authtoken, @@ -124,18 +124,18 @@ export default class LoginCommand extends BaseCommand { }); if (typeof user !== 'object' || !user.authtoken || !user.email) { - log.debug('Login failed - invalid user response', { ...this.contextDetails, user }); - throw new CLIError('Failed to login - invalid response'); + log.debug('Login failed: Invalid user response', { ...this.contextDetails, user }); + throw new CLIError('Login failed: Invalid response.'); } - log.debug('Setting config data for basic auth', this.contextDetails); + log.debug('Setting configuration data for basic authentication.', this.contextDetails); await oauthHandler.setConfigData('basicAuth', user); - log.debug('Config data set successfully', this.contextDetails); + log.debug('Configuration data set successfully.', this.contextDetails); log.success(messageHandler.parse('CLI_AUTH_LOGIN_SUCCESS'), this.contextDetails); - log.debug('Login process completed successfully', this.contextDetails); + log.debug('Login completed successfully.', this.contextDetails); } catch (error) { - log.debug('Login process failed', { ...this.contextDetails, error }); + log.debug('Login failed.', { ...this.contextDetails, error }); throw error; } } diff --git a/packages/contentstack-auth/src/commands/auth/logout.ts b/packages/contentstack-auth/src/commands/auth/logout.ts index 3140750a63..6f0a016ef2 100644 --- a/packages/contentstack-auth/src/commands/auth/logout.ts +++ b/packages/contentstack-auth/src/commands/auth/logout.ts @@ -61,7 +61,7 @@ export default class LogoutCommand extends BaseCommand { } try { - log.debug('Initializing management API client for logout', this.contextDetails); + log.debug('Initializing the Management API client for logout.', this.contextDetails); const managementAPIClient = await managementSDKClient({ host: this.cmaHost, skipTokenValidity: true }); log.debug('Management API client initialized successfully', this.contextDetails); @@ -75,9 +75,9 @@ export default class LogoutCommand extends BaseCommand { if (await oauthHandler.isAuthorisationTypeBasic()) { log.debug('Using basic authentication for logout', this.contextDetails); const authToken = configHandler.get('authtoken'); - log.debug('Retrieved auth token for logout', { ...this.contextDetails, hasAuthToken: !!authToken }); + log.debug('Authentication token retrieved for logout.', { ...this.contextDetails, hasAuthToken: !!authToken }); await authHandler.logout(authToken); - log.debug('Basic auth logout completed', this.contextDetails); + log.debug('Basic authentication logout completed.', this.contextDetails); } else if (await oauthHandler.isAuthorisationTypeOAuth()) { log.debug('Using OAuth authentication for logout', this.contextDetails); await oauthHandler.oauthLogout(); @@ -86,7 +86,7 @@ export default class LogoutCommand extends BaseCommand { cliux.loader(''); log.success(messageHandler.parse('CLI_AUTH_LOGOUT_SUCCESS'), this.contextDetails); - log.debug('Logout process completed successfully', this.contextDetails); + log.debug('Logout completed successfully.', this.contextDetails); } else { log.debug('User not confirmed or not authenticated, skipping logout', { ...this.contextDetails, @@ -96,14 +96,14 @@ export default class LogoutCommand extends BaseCommand { log.success(messageHandler.parse('CLI_AUTH_LOGOUT_ALREADY'), this.contextDetails); } } catch (error) { - log.debug('Logout command failed', { ...this.contextDetails, error: error.message }); + log.debug('Logout failed.', { ...this.contextDetails, error: error.message }); cliux.print('CLI_AUTH_LOGOUT_FAILED', { color: 'yellow' }); handleAndLogError(error, { ...this.contextDetails }); } finally { if (confirm === true) { - log.debug('Setting config data for logout', this.contextDetails); + log.debug('Setting configuration data for logout.', this.contextDetails); await oauthHandler.setConfigData('logout'); - log.debug('Config data set for logout', this.contextDetails); + log.debug('Configuration data set for logout.', this.contextDetails); } } } diff --git a/packages/contentstack-auth/src/commands/auth/tokens/add.ts b/packages/contentstack-auth/src/commands/auth/tokens/add.ts index 8ca4a46cbb..b95cb11b70 100644 --- a/packages/contentstack-auth/src/commands/auth/tokens/add.ts +++ b/packages/contentstack-auth/src/commands/auth/tokens/add.ts @@ -82,11 +82,11 @@ export default class TokensAddCommand extends BaseCommand] [--delivery] [--management] [-e ] [-k ] [-y] [--token ]'; async run(): Promise { - log.debug('TokensAddCommand run method started', this.contextDetails); + log.debug('TokensAddCommand run method started.', this.contextDetails); this.contextDetails.module = 'tokens-add'; const { flags: addTokenFlags } = await this.parse(TokensAddCommand); - log.debug('Token add flags parsed', { ...this.contextDetails, flags: addTokenFlags }); + log.debug('Token add flags parsed.', { ...this.contextDetails, flags: addTokenFlags }); let isAliasExist = false; const skipAliasReplaceConfirmation = addTokenFlags.force || addTokenFlags.yes; @@ -141,7 +141,7 @@ export default class TokensAddCommand extends BaseCommand { - log.debug('TokensListCommand run method started', this.contextDetails); + log.debug('TokensListCommand run method started.', this.contextDetails); this.contextDetails.module = 'tokens-list'; try { - log.debug('Retrieving tokens from configuration', this.contextDetails); + log.debug('Retrieving tokens from configuration.', this.contextDetails); const managementTokens = configHandler.get('tokens'); - log.debug('Tokens retrieved from configuration', {...this.contextDetails, tokenCount: managementTokens ? Object.keys(managementTokens).length : 0 }); + log.debug('Tokens retrieved from configuration.', {...this.contextDetails, tokenCount: managementTokens ? Object.keys(managementTokens).length : 0 }); const tokens: Record[] = []; if (managementTokens && Object.keys(managementTokens).length > 0) { - log.debug('Processing tokens for display', this.contextDetails); + log.debug('Processing tokens for display.', this.contextDetails); Object.keys(managementTokens).forEach(function (item) { tokens.push({ alias: item, @@ -46,7 +46,7 @@ export default class TokensListCommand extends BaseCommand = []; if (token || ignore) { - log.debug('Token found or ignore flag set, proceeding with removal', {...this.contextDetails, hasToken: !!token, ignore }); + log.debug('Token found, or ignore flag set.', {...this.contextDetails, hasToken: !!token, ignore }); configHandler.delete(`tokens.${alias}`); - log.debug('Token removed from configuration', {...this.contextDetails, alias }); + log.debug('Token removed from configuration.', {...this.contextDetails, alias }); return cliux.success(`CLI_AUTH_TOKENS_REMOVE_SUCCESS`); } if (tokens && Object.keys(tokens).length > 0) { - log.debug('Building token options for user selection', this.contextDetails); + log.debug('Building token options for user selection.', this.contextDetails); Object.keys(tokens).forEach(function (item) { const tokenOption = `${item}: ${tokens[item].token} : ${tokens[item].apiKey}${ tokens[item].environment ? ' : ' + tokens[item].environment + ' ' : '' @@ -48,11 +48,11 @@ export default class TokensRemoveCommand extends BaseCommand = await cliux.inquire({ name: 'selectedTokens', message: 'CLI_AUTH_TOKENS_REMOVE_SELECT_TOKEN', @@ -62,7 +62,7 @@ export default class TokensRemoveCommand extends BaseCommand { const selectedToken = element.split(':')[0]; log.debug(`Removing token: ${selectedToken}`, this.contextDetails); @@ -79,9 +79,9 @@ export default class TokensRemoveCommand extends BaseCommand { log.debug('WhoamiCommand run method started', this.contextDetails); try { - log.debug('Checking user email from context', { ...this.contextDetails, hasEmail: !!this.email }); + log.debug('Checking user email from context.', { ...this.contextDetails, hasEmail: !!this.email }); if (this.email) { log.debug('User email found, displaying user information', { ...this.contextDetails, email: this.email }); cliux.print('CLI_AUTH_WHOAMI_LOGGED_IN_AS', { color: 'white' }); cliux.print(this.email, { color: 'green' }); - log.debug('Whoami command completed successfully', this.contextDetails); + log.debug('whoami command completed successfully.', this.contextDetails); } else { - log.debug('No user email found in context', this.contextDetails); + log.debug('No user email found in context.', this.contextDetails); log.error(messageHandler.parse('CLI_AUTH_WHOAMI_FAILED'), this.contextDetails); } } catch (error) { - log.debug('Whoami command failed', { ...this.contextDetails, error }); + log.debug('whoami command failed.', { ...this.contextDetails, error }); cliux.print('CLI_AUTH_WHOAMI_FAILED', { color: 'yellow' }); handleAndLogError(error, { ...this.contextDetails }); } diff --git a/packages/contentstack-auth/src/utils/auth-handler.ts b/packages/contentstack-auth/src/utils/auth-handler.ts index 7ecdc26cd7..7d263ebaac 100644 --- a/packages/contentstack-auth/src/utils/auth-handler.ts +++ b/packages/contentstack-auth/src/utils/auth-handler.ts @@ -10,11 +10,11 @@ class AuthHandler { private _client; private _host; set client(contentStackClient) { - log.debug('Setting ContentStack client', { module: 'auth-handler' }); + log.debug('Setting Contentstack client.', { module: 'auth-handler' }); this._client = contentStackClient; } set host(contentStackHost) { - log.debug(`Setting ContentStack host: ${contentStackHost}`, { module: 'auth-handler' }); + log.debug(`Setting Contentstack host: ${contentStackHost}`, { module: 'auth-handler' }); this._host = contentStackHost; } @@ -68,13 +68,13 @@ class AuthHandler { * @throws CLIError if SMS request fails */ private async requestSMSOTP(loginPayload: any): Promise { - log.debug('Sending SMS OTP request', { module: 'auth-handler' }); + log.debug('Sending SMS OTP request.', { module: 'auth-handler' }); try { await this._client.axiosInstance.post('/user/request_token_sms', { user: loginPayload }); - log.debug('SMS OTP request successful', { module: 'auth-handler' }); + log.debug('SMS OTP request successful.', { module: 'auth-handler' }); cliux.print('CLI_AUTH_LOGIN_SECURITY_CODE_SEND_SUCCESS'); } catch (error) { - log.debug('SMS OTP request failed', { module: 'auth-handler', error }); + log.debug('SMS OTP request failed.', { module: 'auth-handler', error }); throw error; } } @@ -98,7 +98,7 @@ class AuthHandler { } = { email, password }; if (tfaToken) { loginPayload.tfa_token = tfaToken; - log.debug('Adding TFA token to login payload', { module: 'auth-handler' }); + log.debug('Adding TFA token to login payload.', { module: 'auth-handler' }); } log.debug('Making login API call', { @@ -124,17 +124,17 @@ class AuthHandler { try { resolve(await this.login(email, password, tfToken)); } catch (error) { - log.debug('Login with TFA token failed', { module: 'auth-handler', error }); + log.debug('Login with TFA token failed.', { module: 'auth-handler', error }); cliux.print('CLI_AUTH_2FA_FAILED', { color: 'red' }); reject(error); } } else { - log.debug('Login failed - no user found', { module: 'auth-handler', result }); + log.debug('Login failed: no user found.', { module: 'auth-handler', result }); reject(new Error(messageHandler.parse('CLI_AUTH_LOGIN_NO_USER'))); } }) .catch((error: any) => { - log.debug('Login API call failed', { module: 'auth-handler', error: error?.errorMessage || error }); + log.debug('Login API call failed.', { module: 'auth-handler', error: error?.errorMessage || error }); cliux.print('CLI_AUTH_LOGIN_FAILED', { color: 'yellow' }); handleAndLogError(error, { module: 'auth-handler' }); }); @@ -158,25 +158,25 @@ class AuthHandler { * @returns {Promise} Promise object returns response object from Contentstack */ async logout(authtoken: string): Promise { - log.debug('Starting logout process', { module: 'auth-handler', hasAuthToken: !!authtoken }); + log.debug('Starting logout process.', { module: 'auth-handler', hasAuthToken: !!authtoken }); return new Promise((resolve, reject) => { if (authtoken) { - log.debug('Making logout API call', { module: 'auth-handler' }); + log.debug('Making logout API call.', { module: 'auth-handler' }); this._client .logout(authtoken) .then(function (response: object) { - log.debug('Logout API call successful', { module: 'auth-handler', response }); + log.debug('Logout API call successful.', { module: 'auth-handler', response }); return resolve(response); }) .catch((error: Error) => { - log.debug('Logout API call failed', { module: 'auth-handler', error: error.message }); + log.debug('Logout API call failed.', { module: 'auth-handler', error: error.message }); cliux.print('CLI_AUTH_LOGOUT_FAILED', { color: 'yellow' }); reject(error); }); } else { - log.debug('Logout failed - no auth token provided', { module: 'auth-handler' }); + log.debug('Logout failed: no auth token provided.', { module: 'auth-handler' }); reject(new Error(messageHandler.parse('CLI_AUTH_LOGOUT_NO_TOKEN'))); } }); @@ -188,25 +188,25 @@ class AuthHandler { * @returns {Promise} Promise object returns response object from Contentstack */ async validateAuthtoken(authtoken: string): Promise { - log.debug('Starting token validation', { module: 'auth-handler', hasAuthToken: !!authtoken }); + log.debug('Starting token validation.', { module: 'auth-handler', hasAuthToken: !!authtoken }); return new Promise((resolve, reject) => { if (authtoken) { - log.debug('Making token validation API call', { module: 'auth-handler' }); + log.debug('Making token validation API call.', { module: 'auth-handler' }); this._client .getUser() .then((user: object) => { - log.debug('Token validation successful', { module: 'auth-handler', user }); + log.debug('Token validation successful.', { module: 'auth-handler', user }); resolve(user); }) .catch((error: Error) => { - log.debug('Token validation failed', { module: 'auth-handler', error: error.message }); + log.debug('Token validation failed.', { module: 'auth-handler', error: error.message }); cliux.print('CLI_AUTH_TOKEN_VALIDATION_FAILED', { color: 'yellow' }); handleAndLogError(error, { module: 'auth-handler' }); }); } else { - log.debug('Token validation failed - no auth token provided', { module: 'auth-handler' }); + log.debug('Token validation failed: no auth token provided.', { module: 'auth-handler' }); reject(new Error(messageHandler.parse('CLI_AUTH_TOKEN_VALIDATION_NO_TOKEN'))); } }); diff --git a/packages/contentstack-auth/src/utils/tokens-validation.ts b/packages/contentstack-auth/src/utils/tokens-validation.ts index 94ae7a7855..ab230dbf07 100644 --- a/packages/contentstack-auth/src/utils/tokens-validation.ts +++ b/packages/contentstack-auth/src/utils/tokens-validation.ts @@ -11,28 +11,28 @@ export const validateEnvironment = async ( apiKey: string, environment: string, ): Promise => { - log.debug('Starting environment validation', { module: 'tokens-validation', apiKeyStatus: apiKey ? 'provided' : 'not-provided', environment }); + log.debug('Starting environment validation.', { module: 'tokens-validation', apiKeyStatus: apiKey ? 'provided' : 'not-provided', environment }); let result: { valid: boolean; message: string }; try { - log.debug('Making environment validation API call', { module: 'tokens-validation', environment }); + log.debug('Making environment validation API call.', { module: 'tokens-validation', environment }); const validationResult = await contentStackClient.Stack({ api_key: apiKey }).environment(environment).fetch(); - log.debug('Environment validation API response received', { module: 'tokens-validation', validationResult }); + log.debug('Environment validation API response received.', { module: 'tokens-validation', validationResult }); if (validationResult.name === environment) { - log.debug('Environment validation successful', { module: 'tokens-validation', environment, validationResult }); + log.debug('Environment validation successful.', { module: 'tokens-validation', environment, validationResult }); result = { valid: true, message: validationResult }; } else { - log.debug('Environment validation failed - name mismatch', { module: 'tokens-validation', expected: environment, actual: validationResult.name }); + log.debug('Environment validation failed: name mismatch.', { module: 'tokens-validation', expected: environment, actual: validationResult.name }); result = { valid: false, message: messageHandler.parse('CLI_AUTH_TOKENS_VALIDATION_INVALID_ENVIRONMENT_NAME') }; } } catch (error) { - log.debug('Environment validation API call failed', { module: 'tokens-validation', error: error.message, environment }); + log.debug('Environment validation API call failed.', { module: 'tokens-validation', error: error.message, environment }); handleAndLogError(error, { apiKey, environment }, ); result = { valid: false, message: 'CLI_AUTH_TOKENS_VALIDATION_INVALID_ENVIRONMENT_NAME' }; } - log.debug('Environment validation completed', { module: 'tokens-validation', result }); + log.debug('Environment validation completed.', { module: 'tokens-validation', result }); return result; }; @@ -43,27 +43,27 @@ export const validateEnvironment = async ( * @returns */ export const validateAPIKey = async (contentStackClient: any, apiKey: string): Promise => { - log.debug('Starting API key validation', { module: 'tokens-validation', apiKeyStatus: apiKey ? 'provided' : 'not-provided' }); + log.debug('Starting API key validation.', { module: 'tokens-validation', apiKeyStatus: apiKey ? 'provided' : 'not-provided' }); let result: { valid: boolean; message: string }; try { - log.debug('Making API key validation API call', { module: 'tokens-validation' }); + log.debug('Making API key validation API call.', { module: 'tokens-validation' }); const validateAPIKeyResult = await contentStackClient.stack({ api_key: apiKey }).fetch(); - log.debug('API key validation API response received', { module: 'tokens-validation', validateAPIKeyResult }); + log.debug('API key validation API response received.', { module: 'tokens-validation', validateAPIKeyResult }); if (validateAPIKeyResult.api_key === apiKey) { - log.debug('API key validation successful', { module: 'tokens-validation', apiKey: validateAPIKeyResult.api_key }); + log.debug('API key validation successful.', { module: 'tokens-validation', apiKey: validateAPIKeyResult.api_key }); result = { valid: true, message: validateAPIKeyResult }; } else { - log.debug('API key validation failed - key mismatch', { module: 'tokens-validation', expected: apiKey, actual: validateAPIKeyResult.api_key }); + log.debug('API key validation failed: key mismatch.', { module: 'tokens-validation', expected: apiKey, actual: validateAPIKeyResult.api_key }); result = { valid: false, message: messageHandler.parse('CLI_AUTH_TOKENS_VALIDATION_INVALID_API_KEY') }; } } catch (error) { - log.debug('API key validation API call failed', { module: 'tokens-validation', error: error.message }); + log.debug('API key validation API call failed.', { module: 'tokens-validation', error: error.message }); handleAndLogError(error, { apiKey }, ); result = { valid: false, message: messageHandler.parse('CLI_AUTH_TOKENS_VALIDATION_INVALID_API_KEY') }; } - log.debug('API key validation completed', { module: 'tokens-validation', result }); + log.debug('API key validation completed.', { module: 'tokens-validation', result }); return result; }; diff --git a/packages/contentstack-bootstrap/src/bootstrap/utils.ts b/packages/contentstack-bootstrap/src/bootstrap/utils.ts index 91575eb1d6..1266a3fd13 100644 --- a/packages/contentstack-bootstrap/src/bootstrap/utils.ts +++ b/packages/contentstack-bootstrap/src/bootstrap/utils.ts @@ -138,7 +138,7 @@ export const setupEnvironments = async ( cliux.print(messageHandler.parse('CLI_BOOTSTRAP_APP_FAILED_TO_CREATE_ENV_FILE_FOR_ENV', environment.name)); } } else { - cliux.print('No environments name found for the environment'); + cliux.print('No environment name found for the selected environment.'); } } } else { diff --git a/packages/contentstack-bootstrap/src/commands/cm/bootstrap.ts b/packages/contentstack-bootstrap/src/commands/cm/bootstrap.ts index 2a353d1d5d..8cf129cf30 100644 --- a/packages/contentstack-bootstrap/src/commands/cm/bootstrap.ts +++ b/packages/contentstack-bootstrap/src/commands/cm/bootstrap.ts @@ -147,7 +147,7 @@ export default class BootstrapCommand extends Command { } else if (appType === 'starterapp') { selectedApp = await inquireApp(config.starterApps); } else { - this.error('Invalid app type provided ' + appType, { exit: 1 }); + this.error('Invalid app type provided: ' + appType, { exit: 1 }); } } diff --git a/packages/contentstack-branches/package.json b/packages/contentstack-branches/package.json index 4e358485bc..356b0db145 100644 --- a/packages/contentstack-branches/package.json +++ b/packages/contentstack-branches/package.json @@ -5,7 +5,7 @@ "author": "Contentstack", "bugs": "https://github.com/contentstack/cli/issues", "dependencies": { - "@contentstack/cli-command": "~1.6.1", + "@contentstack/cli-command": "~1.7.0", "@oclif/core": "^4.3.0", "@oclif/plugin-help": "^6.2.28", "@contentstack/cli-utilities": "~1.15.0", diff --git a/packages/contentstack-branches/src/branch/merge-handler.ts b/packages/contentstack-branches/src/branch/merge-handler.ts index 67d0f0369d..0d27552152 100644 --- a/packages/contentstack-branches/src/branch/merge-handler.ts +++ b/packages/contentstack-branches/src/branch/merge-handler.ts @@ -280,7 +280,7 @@ export default class MergeHandler { mergeContent[module].deleted = moduleBranchCompareData.deleted; break; default: - cliux.error(`error: Invalid strategy ${strategy}`); + cliux.error(`Error: Invalid strategy '${strategy}'`); process.exit(1); } } diff --git a/packages/contentstack-branches/src/commands/cm/branches/delete.ts b/packages/contentstack-branches/src/commands/cm/branches/delete.ts index b6787b13cf..19eab092a7 100644 --- a/packages/contentstack-branches/src/commands/cm/branches/delete.ts +++ b/packages/contentstack-branches/src/commands/cm/branches/delete.ts @@ -47,7 +47,7 @@ export default class BranchDeleteCommand extends Command { if (!branchDeleteFlags.yes) { const confirmBranch = await interactive.askBranchNameConfirmation(); if (confirmBranch !== branchDeleteFlags.uid) { - cliux.error(`error: To delete the branch, enter a valid branch name '${branchDeleteFlags.uid}'`); + cliux.error(`Error: To delete the branch, enter a valid branch name '${branchDeleteFlags.uid}'`); process.exit(1); } } diff --git a/packages/contentstack-branches/src/utils/asset-folder-create-script.ts b/packages/contentstack-branches/src/utils/asset-folder-create-script.ts index a358c9e286..0a41c0a092 100644 --- a/packages/contentstack-branches/src/utils/asset-folder-create-script.ts +++ b/packages/contentstack-branches/src/utils/asset-folder-create-script.ts @@ -143,13 +143,13 @@ export function assetFolderCreateScript(contentType) { migration.addTask(createAssetTask()); } else { if (apiKey.length === 0) { - console.error('Please provide api key using --stack-api-key flag'); + console.error('Provide the API key using the --stack-api-key flag.'); } if (!compareBranch) { - console.error('Please provide compare branch through --config compare-branch: flag'); + console.error('Specify the compare branch using the --config compare-branch: flag.'); } if (branch.length === 0) { - console.error('Please provide branch name through --branch flag'); + console.error('Specify the branch name using the --branch flag.'); } } } diff --git a/packages/contentstack-branches/src/utils/entry-create-script.ts b/packages/contentstack-branches/src/utils/entry-create-script.ts index bfda436afc..dabd71ff9b 100644 --- a/packages/contentstack-branches/src/utils/entry-create-script.ts +++ b/packages/contentstack-branches/src/utils/entry-create-script.ts @@ -599,13 +599,13 @@ export function entryCreateScript(contentType) { migration.addTask(createEntryTask()); } else { if (apiKey.length === 0) { - console.error('Please provide api key using --stack-api-key flag'); + console.error('Provide the API key using the --stack-api-key flag.'); } if (!compareBranch) { - console.error('Please provide compare branch through --config compare-branch: flag'); + console.error('Specify the compare branch using the --config compare-branch: flag.'); } if (branch.length === 0) { - console.error('Please provide branch name through --branch flag'); + console.error('Specify the branch name using the --branch flag.'); } } }; diff --git a/packages/contentstack-branches/src/utils/entry-create-update-script.ts b/packages/contentstack-branches/src/utils/entry-create-update-script.ts index a47fcdb9b1..ac4ea205c1 100644 --- a/packages/contentstack-branches/src/utils/entry-create-update-script.ts +++ b/packages/contentstack-branches/src/utils/entry-create-update-script.ts @@ -669,13 +669,13 @@ export function entryCreateUpdateScript(contentType) { migration.addTask(updateEntryTask()); } else { if (apiKey.length === 0) { - console.error('Please provide api key using --stack-api-key flag'); + console.error('Provide the API key using the --stack-api-key flag.'); } if (!compareBranch) { - console.error('Please provide compare branch through --config compare-branch: flag'); + console.error('Specify the compare branch using the --config compare-branch: flag.'); } if (branch.length === 0) { - console.error('Please provide branch name through --branch flag'); + console.error('Specify the branch name using the --branch flag.'); } } };`; diff --git a/packages/contentstack-branches/src/utils/entry-update-script.ts b/packages/contentstack-branches/src/utils/entry-update-script.ts index 88ea7eb77c..8c1fa73f32 100644 --- a/packages/contentstack-branches/src/utils/entry-update-script.ts +++ b/packages/contentstack-branches/src/utils/entry-update-script.ts @@ -666,13 +666,13 @@ export function entryUpdateScript(contentType) { migration.addTask(updateEntryTask()); } else { if (apiKey.length === 0) { - console.error('Please provide api key using --stack-api-key flag'); + console.error('Provide the API key using the --stack-api-key flag.'); } if (!compareBranch) { - console.error('Please provide compare branch through --config compare-branch: flag'); + console.error('Specify the compare branch using the --config compare-branch: flag.'); } if (branch.length === 0) { - console.error('Please provide branch name through --branch flag'); + console.error('Specify the branch name using the --branch flag.'); } } };`; diff --git a/packages/contentstack-branches/src/utils/interactive.ts b/packages/contentstack-branches/src/utils/interactive.ts index 50b6bef4f8..dc8730fd6f 100644 --- a/packages/contentstack-branches/src/utils/interactive.ts +++ b/packages/contentstack-branches/src/utils/interactive.ts @@ -97,7 +97,7 @@ export async function selectMergeStrategy(): Promise { }) .then((name) => name as string) .catch((err) => { - cliux.error('Failed to collect the merge strategy'); + cliux.error('Failed to retrieve the merge strategy.'); process.exit(1); }); @@ -120,7 +120,7 @@ export async function selectMergeStrategySubOptions(): Promise { }) .then((name) => name as string) .catch((err) => { - cliux.error('Failed to collect the merge strategy'); + cliux.error('Failed to retrieve the merge strategy.'); process.exit(1); }); @@ -166,7 +166,7 @@ export async function selectContentMergePreference(): Promise { }) .then((name) => name as string) .catch((err) => { - cliux.error('Failed to collect the preference'); + cliux.error('Failed to retrieve the preference.'); process.exit(1); }); diff --git a/packages/contentstack-bulk-publish/README.md b/packages/contentstack-bulk-publish/README.md index 72fb87ab24..6c7fad8d90 100644 --- a/packages/contentstack-bulk-publish/README.md +++ b/packages/contentstack-bulk-publish/README.md @@ -18,7 +18,7 @@ $ npm install -g @contentstack/cli-cm-bulk-publish $ csdx COMMAND running command... $ csdx (--version) -@contentstack/cli-cm-bulk-publish/1.10.1 darwin-arm64 node-v22.14.0 +@contentstack/cli-cm-bulk-publish/1.10.3 darwin-arm64 node-v22.14.0 $ csdx --help [COMMAND] USAGE $ csdx COMMAND diff --git a/packages/contentstack-bulk-publish/package.json b/packages/contentstack-bulk-publish/package.json index 2141aeeaa7..7ef08e0846 100644 --- a/packages/contentstack-bulk-publish/package.json +++ b/packages/contentstack-bulk-publish/package.json @@ -1,12 +1,12 @@ { "name": "@contentstack/cli-cm-bulk-publish", "description": "Contentstack CLI plugin for bulk publish actions", - "version": "1.10.1", + "version": "1.10.3", "author": "Contentstack", "bugs": "https://github.com/contentstack/cli/issues", "dependencies": { - "@contentstack/cli-command": "~1.6.1", - "@contentstack/cli-config": "~1.15.0", + "@contentstack/cli-command": "~1.7.0", + "@contentstack/cli-config": "~1.15.3", "@contentstack/cli-utilities": "~1.15.0", "@oclif/core": "^4.3.0", "@oclif/plugin-help": "^6.2.28", diff --git a/packages/contentstack-bulk-publish/src/commands/cm/assets/publish.js b/packages/contentstack-bulk-publish/src/commands/cm/assets/publish.js index f5baa17886..a032678c03 100644 --- a/packages/contentstack-bulk-publish/src/commands/cm/assets/publish.js +++ b/packages/contentstack-bulk-publish/src/commands/cm/assets/publish.js @@ -50,7 +50,7 @@ class AssetsPublishCommand extends Command { } else if (updatedFlags['stack-api-key']) { config.stackApiKey = updatedFlags['stack-api-key']; } else { - this.error('Please use `--alias` or `--stack-api-key` to proceed.', { exit: 2 }); + this.error('Use the `--alias` or `--stack-api-key` flag to proceed.', { exit: 2 }); } updatedFlags.bulkPublish = updatedFlags.bulkPublish === 'false' ? false : true; if (updatedFlags.folderUid === undefined) { @@ -104,10 +104,10 @@ class AssetsPublishCommand extends Command { this.error(message, { exit: 2 }); } } else { - this.error('Confirmation failed'); + this.error('Confirmation failed.'); } } else { - this.error('Validation failed'); + this.error('Validation failed.'); } } @@ -118,7 +118,7 @@ class AssetsPublishCommand extends Command { } if (sourceEnv && !deliveryToken) { - this.error('Specify source environment delivery token. Please check --help for more details', { exit: 2 }); + this.error('Specify the source environment delivery token. Run --help for more details.', { exit: 2 }); } if (!environments || environments.length === 0) { diff --git a/packages/contentstack-bulk-publish/src/commands/cm/assets/unpublish.js b/packages/contentstack-bulk-publish/src/commands/cm/assets/unpublish.js index d127464f34..75aa85d142 100644 --- a/packages/contentstack-bulk-publish/src/commands/cm/assets/unpublish.js +++ b/packages/contentstack-bulk-publish/src/commands/cm/assets/unpublish.js @@ -53,7 +53,7 @@ class UnpublishCommand extends Command { } else if (updatedFlags['stack-api-key']) { config.stackApiKey = updatedFlags['stack-api-key']; } else { - this.error('Please use `--alias` or `--stack-api-key` to proceed.', { exit: 2 }); + this.error('Use the `--alias` or `--stack-api-key` flag to proceed.', { exit: 2 }); } if (!updatedFlags.deliveryToken) { updatedFlags.deliveryToken = await cliux.prompt('Enter delivery token of your source environment'); @@ -62,7 +62,7 @@ class UnpublishCommand extends Command { stack = await getStack(config); } if (!updatedFlags.deliveryToken && updatedFlags.deliveryToken.length === 0) { - this.error('Delivery Token is required for executing this command', { exit: 2 }); + this.error('A delivery token is required to execute this command.', { exit: 2 }); } if (await this.confirmFlags(updatedFlags)) { diff --git a/packages/contentstack-bulk-publish/src/commands/cm/bulk-publish/cross-publish.js b/packages/contentstack-bulk-publish/src/commands/cm/bulk-publish/cross-publish.js index 81f6ddb338..5ca4af0315 100644 --- a/packages/contentstack-bulk-publish/src/commands/cm/bulk-publish/cross-publish.js +++ b/packages/contentstack-bulk-publish/src/commands/cm/bulk-publish/cross-publish.js @@ -41,7 +41,7 @@ class CrossPublishCommand extends Command { } else if (updatedFlags['stack-api-key']) { config.stackApiKey = updatedFlags['stack-api-key']; } else { - this.error('Please use `--alias` or `--stack-api-key` to proceed.', { exit: 2 }); + this.error('Use the `--alias` or `--stack-api-key` flag to proceed.', { exit: 2 }); } if (!updatedFlags.deliveryToken) { updatedFlags.deliveryToken = await cliux.prompt('Enter delivery token of your source environment'); @@ -52,7 +52,7 @@ class CrossPublishCommand extends Command { } if (!updatedFlags.deliveryToken && updatedFlags.deliveryToken.length === 0) { - this.error('Delivery Token is required for executing this command', { exit: 2 }); + this.error('A delivery token is required to execute this command.', { exit: 2 }); } if (await this.confirmFlags(updatedFlags)) { diff --git a/packages/contentstack-bulk-publish/src/commands/cm/entries/publish-modified.js b/packages/contentstack-bulk-publish/src/commands/cm/entries/publish-modified.js index 30c2decc63..7d93ffbd55 100644 --- a/packages/contentstack-bulk-publish/src/commands/cm/entries/publish-modified.js +++ b/packages/contentstack-bulk-publish/src/commands/cm/entries/publish-modified.js @@ -51,7 +51,7 @@ class PublishModifiedCommand extends Command { } else if (updatedFlags['stack-api-key']) { config.stackApiKey = updatedFlags['stack-api-key']; } else { - this.error('Please use `--alias` or `--stack-api-key` to proceed.', { exit: 2 }); + this.error('Use the `--alias` or `--stack-api-key` flag to proceed.', { exit: 2 }); } updatedFlags.bulkPublish = updatedFlags.bulkPublish !== 'false'; stack = await getStack(config); diff --git a/packages/contentstack-bulk-publish/src/commands/cm/entries/publish-non-localized-fields.js b/packages/contentstack-bulk-publish/src/commands/cm/entries/publish-non-localized-fields.js index 834abdeb4f..2551f75514 100644 --- a/packages/contentstack-bulk-publish/src/commands/cm/entries/publish-non-localized-fields.js +++ b/packages/contentstack-bulk-publish/src/commands/cm/entries/publish-non-localized-fields.js @@ -60,7 +60,7 @@ class NonlocalizedFieldChangesCommand extends Command { } else if (updatedFlags['stack-api-key']) { config.stackApiKey = updatedFlags['stack-api-key']; } else { - this.error('Please use `--alias` or `--stack-api-key` to proceed.', { exit: 2 }); + this.error('Use the `--alias` or `--stack-api-key` flag to proceed.', { exit: 2 }); } stack = await getStack(config); } diff --git a/packages/contentstack-bulk-publish/src/commands/cm/entries/publish-only-unpublished.js b/packages/contentstack-bulk-publish/src/commands/cm/entries/publish-only-unpublished.js index febfa9f96c..57577a68a2 100644 --- a/packages/contentstack-bulk-publish/src/commands/cm/entries/publish-only-unpublished.js +++ b/packages/contentstack-bulk-publish/src/commands/cm/entries/publish-only-unpublished.js @@ -8,7 +8,7 @@ class PublishOnlyUnpublished extends Command { try { await publishOnlyUnpublishedService.apply(this, [PublishOnlyUnpublished]); } catch (error) { - this.error(error, { exit: 2 }); + this.error(error?.message || error, { exit: 2 }); } } } diff --git a/packages/contentstack-bulk-publish/src/commands/cm/entries/publish.js b/packages/contentstack-bulk-publish/src/commands/cm/entries/publish.js index 92ec008a82..fc32da49ce 100644 --- a/packages/contentstack-bulk-publish/src/commands/cm/entries/publish.js +++ b/packages/contentstack-bulk-publish/src/commands/cm/entries/publish.js @@ -64,7 +64,7 @@ class PublishEntriesCommand extends Command { } else if (updatedFlags['stack-api-key']) { config.stackApiKey = updatedFlags['stack-api-key']; } else { - this.error('Please use `--alias` or `--stack-api-key` to proceed.', { exit: 2 }); + this.error('Use the `--alias` or `--stack-api-key` flag to proceed.', { exit: 2 }); } updatedFlags.bulkPublish = updatedFlags.bulkPublish !== 'false'; stack = await getStack(config); @@ -131,7 +131,7 @@ class PublishEntriesCommand extends Command { } if (sourceEnv && !deliveryToken) { - this.error('Specify source environment delivery token. Please check --help for more details', { exit: 2 }); + this.error('Specify the source environment delivery token. Run --help for more details.', { exit: 2 }); } if (publishAllContentTypes && contentTypes && contentTypes.length > 0) { diff --git a/packages/contentstack-bulk-publish/src/commands/cm/entries/unpublish.js b/packages/contentstack-bulk-publish/src/commands/cm/entries/unpublish.js index 8aa29a7d87..2402a4c193 100644 --- a/packages/contentstack-bulk-publish/src/commands/cm/entries/unpublish.js +++ b/packages/contentstack-bulk-publish/src/commands/cm/entries/unpublish.js @@ -56,7 +56,7 @@ class UnpublishCommand extends Command { } else if (updatedFlags['stack-api-key']) { config.stackApiKey = updatedFlags['stack-api-key']; } else { - this.error('Please use `--alias` or `--stack-api-key` to proceed.', { exit: 2 }); + this.error('Use the `--alias` or `--stack-api-key` flag to proceed.', { exit: 2 }); } if (!updatedFlags.deliveryToken) { updatedFlags.deliveryToken = await cliux.prompt('Enter delivery token of your source environment'); @@ -65,7 +65,7 @@ class UnpublishCommand extends Command { stack = await getStack(config); } if (!updatedFlags.deliveryToken && updatedFlags.deliveryToken.length === 0) { - this.error('Delivery Token is required for executing this command', { exit: 2 }); + this.error('A delivery token is required to execute this command.', { exit: 2 }); } if (await this.confirmFlags(updatedFlags)) { diff --git a/packages/contentstack-bulk-publish/src/commands/cm/entries/update-and-publish.js b/packages/contentstack-bulk-publish/src/commands/cm/entries/update-and-publish.js index b60a99a021..ec36a1768b 100644 --- a/packages/contentstack-bulk-publish/src/commands/cm/entries/update-and-publish.js +++ b/packages/contentstack-bulk-publish/src/commands/cm/entries/update-and-publish.js @@ -50,7 +50,7 @@ class UpdateAndPublishCommand extends Command { } else if (updatedFlags['stack-api-key']) { config.stackApiKey = updatedFlags['stack-api-key']; } else { - this.error('Please use `--alias` or `--stack-api-key` to proceed.', { exit: 2 }); + this.error('Use the `--alias` or `--stack-api-key` flag to proceed.', { exit: 2 }); } updatedFlags.bulkPublish = updatedFlags.bulkPublish === 'false' ? false : true; diff --git a/packages/contentstack-bulk-publish/src/commands/cm/stacks/publish-clear-logs.js b/packages/contentstack-bulk-publish/src/commands/cm/stacks/publish-clear-logs.js index 018f308d22..7f36ef17ee 100644 --- a/packages/contentstack-bulk-publish/src/commands/cm/stacks/publish-clear-logs.js +++ b/packages/contentstack-bulk-publish/src/commands/cm/stacks/publish-clear-logs.js @@ -37,7 +37,7 @@ class ClearCommand extends Command { } this.log('Log files have been cleared'); } else { - this.error(`The log directory doesn't exist.`); + this.error(`The log directory does not exist.`); } } catch (e) { return; @@ -50,7 +50,7 @@ class ClearCommand extends Command { this.log('Total number of log files - ', files.length); }); } else { - this.error(`The log directory doesn't exist.`); + this.error(`The log directory does not exist.`); } } } diff --git a/packages/contentstack-bulk-publish/src/commands/cm/stacks/publish-configure.js b/packages/contentstack-bulk-publish/src/commands/cm/stacks/publish-configure.js index 1a59d10674..e403e3d7e1 100644 --- a/packages/contentstack-bulk-publish/src/commands/cm/stacks/publish-configure.js +++ b/packages/contentstack-bulk-publish/src/commands/cm/stacks/publish-configure.js @@ -13,12 +13,12 @@ class ConfigureCommand extends Command { try { this.getToken(configureFlags.alias); } catch (error) { - this.error(`The configured management token alias ${configureFlags.alias} has not been added yet. Add it using 'csdx auth:tokens:add -a ${configureFlags.alias}'`, { exit: 2 }) + this.error(`The configured management token alias '${configureFlags.alias}' has not been added yet. Add it using 'csdx auth:tokens:add -a ${configureFlags.alias}'.`, { exit: 2 }) } } else if (configureFlags['stack-api-key']) { configureFlags.stackApiKey = configureFlags['stack-api-key']; } else { - this.error('Please use `--alias` or `--stack-api-key` to proceed.', { exit: 2 }); + this.error('Use the `--alias` or `--stack-api-key` flag to proceed.', { exit: 2 }); } this.setConfig(configureFlags); diff --git a/packages/contentstack-bulk-publish/src/commands/cm/stacks/unpublish.js b/packages/contentstack-bulk-publish/src/commands/cm/stacks/unpublish.js index b2c867996f..2b24cea396 100644 --- a/packages/contentstack-bulk-publish/src/commands/cm/stacks/unpublish.js +++ b/packages/contentstack-bulk-publish/src/commands/cm/stacks/unpublish.js @@ -57,7 +57,7 @@ class UnpublishCommand extends Command { } else if (updatedFlags['stack-api-key']) { config.stackApiKey = updatedFlags['stack-api-key']; } else { - this.error('Please use `--alias` or `--stack-api-key` to proceed.', { exit: 2 }); + this.error('Use the `--alias` or `--stack-api-key` flag to proceed.', { exit: 2 }); } if (!updatedFlags.deliveryToken) { updatedFlags.deliveryToken = await cliux.prompt('Enter delivery token of your source environment'); @@ -66,7 +66,7 @@ class UnpublishCommand extends Command { stack = await getStack(config); } if (!updatedFlags.deliveryToken && updatedFlags.deliveryToken.length === 0) { - this.error('Delivery Token is required for executing this command', { exit: 2 }); + this.error('A delivery token is required to execute this command.', { exit: 2 }); } if (await this.confirmFlags(updatedFlags)) { diff --git a/packages/contentstack-bulk-publish/src/consumer/publish.js b/packages/contentstack-bulk-publish/src/consumer/publish.js index e7b95649a5..2138c48bab 100644 --- a/packages/contentstack-bulk-publish/src/consumer/publish.js +++ b/packages/contentstack-bulk-publish/src/consumer/publish.js @@ -35,22 +35,25 @@ function removePublishDetails(elements) { function displayEntriesDetails(sanitizedData, action, mapping = []) { if (action === 'bulk_publish') { sanitizedData.forEach((entry) => { - entry?.publish_details.forEach((pd) => { - if (Object.keys(mapping).includes(pd.environment)) { + if (Array.isArray(entry?.publish_details) && entry.publish_details.length > 0) { + const matchingPublishDetails = entry.publish_details.filter((pd) => + Object.keys(mapping).includes(pd.environment) + ); + if (matchingPublishDetails.length > 0) { + const pd = matchingPublishDetails[0]; console.log( chalk.green( - `Entry UID '${entry.uid}' of CT '${entry.content_type}' in locale '${entry.locale}' version '${pd.version}' in environment '${pd.environment}'`, + `Entry UID: '${entry.uid}', Content Type: '${entry.content_type}', Locale: '${entry.locale}', Version: '${pd.version}', Environment: '${pd.environment}'`, ), - ) + ); } - }); - if(!Array.isArray(entry.publish_details)){ - console.log(chalk.green(`Entry UID '${entry.uid}' of CT '${entry.content_type}' in locale '${entry.locale}'`)); + } else if (!Array.isArray(entry.publish_details)) { + console.log(chalk.green(`Entry UID: '${entry.uid}', Content Type: '${entry.content_type}', Locale: '${entry.locale}'`)); } }); } else if (action === 'bulk_unpublish') { sanitizedData.forEach((entry) => { - console.log(chalk.green(`Entry UID '${entry.uid}' of CT '${entry.content_type}' in locale '${entry.locale}'`)); + console.log(chalk.green(`Entry UID: '${entry.uid}', Content Type: '${entry.content_type}', Locale: '${entry.locale}'`)); }); } } @@ -62,9 +65,9 @@ function displayAssetsDetails(sanitizedData, action, mapping) { if (Object.keys(mapping).includes(pd.environment)) { console.log( chalk.green( - `Asset UID '${asset.uid}' ${pd.version ? `and version '${pd.version}'` : ''} ${ - asset.locale ? `in locale '${asset.locale}'` : '' - } in environment ${pd.environment}`, + `Asset UID: '${asset.uid}'${pd.version ? `, Version: '${pd.version}'` : ''}${ + asset.locale ? `, Locale: '${asset.locale}'` : '' + }, Environment: ${pd.environment}`, ), ); } @@ -74,8 +77,8 @@ function displayAssetsDetails(sanitizedData, action, mapping) { sanitizedData.forEach((asset) => { console.log( chalk.green( - `Asset UID '${asset.uid}' ${asset.version ? `and version '${asset.version}'` : ''} ${ - asset.locale ? `in locale '${asset.locale}'` : '' + `Asset UID: '${asset.uid}'${asset.version ? `, Version: '${asset.version}'` : ''}${ + asset.locale ? `, Locale: '${asset.locale}'` : '' }`, ), ); @@ -98,7 +101,7 @@ async function publishEntry(data, _config, queue) { if (!publishEntryResponse.error_message) { console.log( chalk.green( - `entry published with ContentType uid=${entryObj.content_type} Entry uid=${entryObj.entryUid} locale=${entryObj.locale}`, + `Entry published. Content Type UID: ${entryObj.content_type}, Entry UID: ${entryObj.entryUid}, Locale: ${entryObj.locale}`, ), ); delete entryObj.stack; @@ -119,9 +122,9 @@ async function publishEntry(data, _config, queue) { delete entryObj.stack; console.log( chalk.red( - `entry could not be published with ContentType uid=${entryObj.content_type} entry uid=${ + `Entry could not be published. Content Type UID: ${entryObj.content_type}, Entry UID: ${ entryObj.entryUid - } locale=${entryObj.locale} error=${formatError(error)}`, + }, Locale: ${entryObj.locale}, Error: ${formatError(error)}`, ), ); addLogs( @@ -147,7 +150,7 @@ async function publishAsset(data, _config, queue) { .publish({ publishDetails: { environments: assetobj.environments, locales: [assetobj.locale || 'en-us'] } }) .then((publishAssetResponse) => { if (!publishAssetResponse.error_message) { - console.log(chalk.green(`asset published with Asset uid=${assetobj.assetUid}, locale=${assetobj.locale}`)); + console.log(chalk.green(`Asset published. Asset UID: ${assetobj.assetUid}, Locale: ${assetobj.locale}`)); delete assetobj.stack; addLogs( logger, @@ -164,7 +167,7 @@ async function publishAsset(data, _config, queue) { queue.Enqueue(data); } else { delete assetobj.stack; - console.log(chalk.red(`Could not publish because of Error=${formatError(error)}`)); + console.log(chalk.red(`Could not publish. Error: ${formatError(error)}`)); addLogs( logger, { @@ -193,7 +196,7 @@ async function UnpublishEntry(data, _config, queue) { delete entryObj.stack; console.log( chalk.green( - `Entry unpublished with ContentType uid=${entryObj.content_type} Entry uid=${entryObj.entryUid} locale=${entryObj.locale}`, + `Entry unpublished. Content Type UID: ${entryObj.content_type}, Entry UID: ${entryObj.entryUid}, Locale: ${entryObj.locale}`, ), ); addLogs( @@ -213,9 +216,9 @@ async function UnpublishEntry(data, _config, queue) { delete entryObj.stack; console.log( chalk.red( - `Entry could not be unpublished with ContentType uid=${entryObj.content_type} Entry uid=${ + `Entry could not be unpublished. Content Type UID: ${entryObj.content_type}, Entry UID: ${ entryObj.entryUid - } locale=${entryObj.locale} error=${formatError(error)}`, + }, Locale: ${entryObj.locale}, Error: ${formatError(error)}`, ), ); addLogs( @@ -237,7 +240,7 @@ async function UnpublishAsset(data, _config, queue) { .then((unpublishAssetResponse) => { if (!unpublishAssetResponse.error_message) { delete assetobj.stack; - console.log(`Asset unpublished with Asset uid=${assetobj.assetUid}`); + console.log(`The asset with UID '${assetobj.assetUid}' has been unpublished.`); addLogs( logger, { options: assetobj, api_key: stack.stackHeaders.api_key, alias: stack.alias, host: stack.host }, @@ -253,7 +256,7 @@ async function UnpublishAsset(data, _config, queue) { queue.Enqueue(data); } else { delete assetobj.stack; - console.log(chalk.red(`Could not Unpublish because of error=${formatError(error)}`)); + console.log(chalk.red(`Could not unpublish. Error: ${formatError(error)}`)); addLogs( logger, { options: assetobj, api_key: stack.stackHeaders.api_key, alias: stack.alias, host: stack.host }, @@ -330,7 +333,7 @@ async function performBulkPublish(data, _config, queue) { queue.Enqueue(data); } else { delete bulkPublishObj.stack; - console.log(chalk.red(`Bulk entries failed to publish with error ${formatError(error)}`)); + console.log(chalk.red(`Bulk entries failed to publish. Error: ${formatError(error)}`)); displayEntriesDetails(bulkPublishObj.entries, 'bulk_publish', mapping); addLogs( logger, @@ -385,7 +388,7 @@ async function performBulkPublish(data, _config, queue) { queue.Enqueue(data); } else { delete bulkPublishObj.stack; - console.log(chalk.red(`Bulk assets failed to publish with error ${formatError(error)}`)); + console.log(chalk.red(`Bulk assets failed to publish. Error: ${formatError(error)}`)); displayAssetsDetails(sanitizedData, 'bulk_publish', mapping); addLogs( @@ -397,7 +400,7 @@ async function performBulkPublish(data, _config, queue) { }); break; default: - console.log('No such type'); + console.log('No such type found. If it is for a content type, use "No such content type found."'); } } @@ -455,7 +458,7 @@ async function performBulkUnPublish(data, _config, queue) { queue.Enqueue(data); } else { delete bulkUnPublishObj.stack; - console.log(chalk.red(`Bulk entries failed to Unpublish with error ${formatError(error)}`)); + console.log(chalk.red(`Bulk entries failed to unpublish. Error: ${formatError(error)}`)); displayEntriesDetails(bulkUnPublishObj.entries, 'bulk_unpublish'); addLogs( logger, @@ -510,7 +513,7 @@ async function performBulkUnPublish(data, _config, queue) { queue.Enqueue(data); } else { delete bulkUnPublishObj.stack; - console.log(chalk.red(`Bulk assets failed to Unpublish with error ${formatError(error)}`)); + console.log(chalk.red(`Bulk assets failed to unpublish. Error: ${formatError(error)}`)); displayAssetsDetails(bulkUnPublishObj.assets, 'bulk_unpublish'); addLogs( logger, @@ -643,7 +646,7 @@ async function publishUsingVersion(data, _config, queue) { } } - console.log(chalk.red(`Entry=${entry.uid} failed to publish with error ${formatError(error)}`)); + console.log(chalk.red(`Entry '${entry.uid}' failed to publish. Error: ${formatError(error)}`)); } }); }); diff --git a/packages/contentstack-bulk-publish/src/producer/add-fields.js b/packages/contentstack-bulk-publish/src/producer/add-fields.js index e3853dfb57..2f83d46768 100644 --- a/packages/contentstack-bulk-publish/src/producer/add-fields.js +++ b/packages/contentstack-bulk-publish/src/producer/add-fields.js @@ -62,6 +62,124 @@ function removeUnwanted(entry, unwantedkeys) { return entry; } +function isLinkObject(obj, keyName) { + if (obj === null || typeof obj !== 'object' || Array.isArray(obj)) { + return false; + } + + const linkKeyNames = ['link', 'card_link']; + if (linkKeyNames.includes(keyName)) { + return true; + } + + const hasTitle = 'title' in obj && obj.title !== undefined; + const hasUrl = 'url' in obj && obj.url !== undefined; + const hasHref = 'href' in obj && obj.href !== undefined; + + return hasTitle && (hasUrl || hasHref); +} + +function ensureHrefIsString(linkObj) { + if (linkObj.href === undefined || linkObj.href === null) { + linkObj.href = ''; + } else if (typeof linkObj.href !== 'string') { + linkObj.href = String(linkObj.href); + } +} + +function isValidJsonRte(obj) { + return obj !== null && + typeof obj === 'object' && + !Array.isArray(obj) && + typeof obj.type === 'string' && + obj.type !== ''; +} + +function cleanJsonFields(obj) { + if (obj === null || obj === undefined || typeof obj !== 'object') { + return obj; + } + + if (Array.isArray(obj)) { + return obj.map((item) => cleanJsonFields(item)); + } + + const cleaned = {}; + for (const key in obj) { + if (!obj.hasOwnProperty(key)) { + continue; + } + let value = obj[key]; + const isJsonField = key.endsWith('_rte') || key === 'json_rte'; + const isAccessibilityField = key.endsWith('_accessibility') || key === 'image_preset_accessibility'; + + if (isJsonField) { + if (value === '' || value === null || value === undefined) { + continue; + } + if (typeof value === 'object' && !Array.isArray(value)) { + const keyCount = Object.keys(value).length; + if (keyCount === 0) { + continue; + } + if (!isValidJsonRte(value)) { + continue; + } + cleaned[key] = value; + } else { + continue; + } + } else if (isAccessibilityField && value === '') { + cleaned[key] = {}; + } else if (typeof value === 'object' && value !== null && !Array.isArray(value)) { + value = cleanJsonFields(value); + if (value !== null && typeof value === 'object') { + cleaned[key] = value; + } + } else { + cleaned[key] = value; + } + } + return cleaned; +} + +function convertUrlToHref(obj) { + if (obj === null || obj === undefined) { + return obj; + } + + if (Array.isArray(obj)) { + return obj.map((item) => convertUrlToHref(item)); + } + + if (typeof obj === 'object') { + const converted = {}; + for (const key in obj) { + const value = obj[key]; + + if (isLinkObject(value, key)) { + converted[key] = { ...value }; + if (converted[key].url !== undefined && converted[key].href === undefined) { + if (typeof converted[key].url === 'string') { + converted[key].href = converted[key].url; + } else if (converted[key].url === null || converted[key].url === undefined) { + converted[key].href = ''; + } else { + converted[key].href = String(converted[key].url); + } + delete converted[key].url; + } + ensureHrefIsString(converted[key]); + } else { + converted[key] = convertUrlToHref(value); + } + } + return converted; + } + + return obj; +} + function fileFields(entry, uid, multiple) { if (entry[uid]) { if (typeof entry[uid] === 'object' || Array.isArray(entry[uid])) { @@ -106,6 +224,11 @@ function addFields(contentType, entry) { } } else if (schema.enum) { entry[schema.uid] = null; + } else if (schema.data_type === 'json') { + const isJsonRteField = schema.uid && (schema.uid.endsWith('_rte') || schema.uid === 'json_rte'); + if (!isJsonRteField) { + entry[schema.uid] = {}; + } } else if (Object.prototype.hasOwnProperty.call(defaults, schema.data_type)) { entry[schema.uid] = defaults[schema.data_type]; } else { @@ -126,19 +249,31 @@ function addFields(contentType, entry) { if (schema.data_type === 'group' && !schema.multiple) { addFields(schema.schema, entry[schema.uid]); + if (entry[schema.uid]) { + entry[schema.uid] = convertUrlToHref(entry[schema.uid]); + } } if (schema.data_type === 'group' && schema.multiple) { entry[schema.uid].forEach((field) => { addFields(schema.schema, field); }); + if (entry[schema.uid]) { + entry[schema.uid] = convertUrlToHref(entry[schema.uid]); + } } if (schema.data_type === 'global_field' && !schema.multiple) { addFields(schema.schema, entry[schema.uid]); + if (entry[schema.uid]) { + entry[schema.uid] = convertUrlToHref(entry[schema.uid]); + } } if (schema.data_type === 'global_field' && schema.multiple) { entry[schema.uid].forEach((field) => { addFields(schema.schema, field); }); + if (entry[schema.uid]) { + entry[schema.uid] = convertUrlToHref(entry[schema.uid]); + } } if (schema.data_type === 'blocks') { if (!entry[schema.uid] && !Array.isArray(entry[schema.uid])) { @@ -156,6 +291,9 @@ function addFields(contentType, entry) { if (filterBlockFields.length > 0) { filterBlockFields.forEach((bfield) => { addFields(block.schema, bfield[block.uid]); + if (bfield[block.uid]) { + bfield[block.uid] = convertUrlToHref(bfield[block.uid]); + } }); } else { entry[schema.uid].push({ [block.uid]: {} }); @@ -169,6 +307,9 @@ function addFields(contentType, entry) { if (filterBlockFields.length > 0) { filterBlockFields.forEach((bfield) => { addFields(block.schema, bfield[block.uid]); + if (bfield[block.uid]) { + bfield[block.uid] = convertUrlToHref(bfield[block.uid]); + } }); } } @@ -221,8 +362,14 @@ async function getEntries( for (let index = 0; index < entriesResponse.items.length; index++) { let updatedEntry = addFields(schema, entries[index]); if (updatedEntry.changedFlag || forceUpdate) { - updatedEntry = removeUnwanted(entries[index], deleteFields); - const flag = await updateEntry(updatedEntry, locale); + let entryData = JSON.parse(JSON.stringify(updatedEntry.entry)); + entryData = removeUnwanted(entryData, deleteFields); + entryData = cleanJsonFields(entryData); + entryData = convertUrlToHref(entryData); + entryData = cleanJsonFields(entryData); + const entry = stack.contentType(contentType).entry(entries[index].uid); + Object.assign(entry, entryData); + const flag = await updateEntry(entry, locale); if (flag) { if (bulkPublish) { if (bulkPublishSet.length < bulkPublishLimit) { @@ -256,10 +403,10 @@ async function getEntries( }); } } else { - console.log(`Update Failed for entryUid ${entries[index].uid} with contentType ${contentType}`); + console.log(`Update failed for entry UID '${entries[index].uid}' of content type '${contentType}'.`); } } else { - console.log(`No change Observed for contentType ${contentType} with entry ${entries[index].uid}`); + console.log(`No changes detected for content type '${contentType}' and entry UID '${entries[index].uid}'.`); } if (index === entriesResponse.items.length - 1 && bulkPublishSet.length > 0 && bulkPublishSet.length < bulkPublishLimit) { @@ -342,19 +489,17 @@ async function start( bulkPublishLimit ); } catch (err) { - console.log(`Failed to get Entries with contentType ${contentTypes[i]} and locale ${locales[j]}`); + console.log(`Failed to retrieve entries for content type '${contentTypes[i]}' and locale '${locales[j]}'.`); } } }) .catch((err) => { - console.log(`Failed to fetch schema${JSON.stringify(err)}`); + console.log(`Failed to fetch schema: ${JSON.stringify(err)}`); }); } } } -// start() - module.exports = { start, getContentTypeSchema, diff --git a/packages/contentstack-bulk-publish/src/producer/cross-publish.js b/packages/contentstack-bulk-publish/src/producer/cross-publish.js index 3a13f35ee4..f77f34b7f9 100644 --- a/packages/contentstack-bulk-publish/src/producer/cross-publish.js +++ b/packages/contentstack-bulk-publish/src/producer/cross-publish.js @@ -225,7 +225,7 @@ async function getSyncEntries( await bulkAction(stack, entriesResponse.items, bulkPublish, filter, destEnv, apiVersion, bulkPublishLimit, variantsFlag); } if (!entriesResponse.pagination_token) { - if (!changedFlag) console.log('No Entries/Assets Found published on specified environment'); + if (!changedFlag) console.log('No entries or assets found published in the specified environment.'); return resolve(); } setTimeout(async () => { diff --git a/packages/contentstack-bulk-publish/src/producer/publish-edits.js b/packages/contentstack-bulk-publish/src/producer/publish-edits.js index 83f31695fb..dfc57a15d5 100644 --- a/packages/contentstack-bulk-publish/src/producer/publish-edits.js +++ b/packages/contentstack-bulk-publish/src/producer/publish-edits.js @@ -107,7 +107,7 @@ async function getEntries(stack, contentType, environmentUid, locale, bulkPublis } if (responseEntries.count === skipCount) { if (!changedFlag) - console.log(`No Edits Were observed on specified Environment for contentType ${contentType}`); + console.log(`No edits were detected in the specified environment for content type ${contentType}`); bulkPublishSet = []; return resolve(); } diff --git a/packages/contentstack-bulk-publish/src/producer/publish-unpublished-env.js b/packages/contentstack-bulk-publish/src/producer/publish-unpublished-env.js index 0bcfcc89ff..7e2c4c0b62 100644 --- a/packages/contentstack-bulk-publish/src/producer/publish-unpublished-env.js +++ b/packages/contentstack-bulk-publish/src/producer/publish-unpublished-env.js @@ -122,7 +122,7 @@ async function getEntries(stack, contentType, environmentUid, locale, bulkPublis } } if (responseEntries.count === skipCount) { - if (!changedFlag) console.log(`No Draft Entries of contentType ${contentType} was found`); + if (!changedFlag) console.log(`No draft entries found for content type ${contentType}`); bulkPublishSet = []; return resolve(); } diff --git a/packages/contentstack-bulk-publish/src/producer/unpublish.js b/packages/contentstack-bulk-publish/src/producer/unpublish.js index e774a85cac..95b45b9786 100644 --- a/packages/contentstack-bulk-publish/src/producer/unpublish.js +++ b/packages/contentstack-bulk-publish/src/producer/unpublish.js @@ -229,7 +229,7 @@ async function getSyncEntries( await bulkAction(stack, entriesResponse.items, bulkUnpublish, environment, locale, apiVersion, bulkPublishLimit, false); } if (entriesResponse.items.length === 0 && !entriesResponse.pagination_token) { - if (!changedFlag) console.log('No Entries/Assets Found published on specified environment'); + if (!changedFlag) console.log('No entries or assets found published in the specified environment.'); return resolve(); } diff --git a/packages/contentstack-bulk-publish/src/util/index.js b/packages/contentstack-bulk-publish/src/util/index.js index 9651b8761d..ad067baaaf 100644 --- a/packages/contentstack-bulk-publish/src/util/index.js +++ b/packages/contentstack-bulk-publish/src/util/index.js @@ -2,7 +2,7 @@ const chalk = require('chalk'); const fs = require('fs'); function prettyPrint(data) { - console.log(chalk.yellow('Configuration to be used for executing this command:')); + console.log(chalk.yellow('Configuration to use for executing this command:')); Object.keys(data).forEach((key, _index) => { console.log(chalk.grey(`${key}: ${data[key]}`)); }); diff --git a/packages/contentstack-bulk-publish/src/util/logger.js b/packages/contentstack-bulk-publish/src/util/logger.js index 16434dd504..400f5ed1ae 100644 --- a/packages/contentstack-bulk-publish/src/util/logger.js +++ b/packages/contentstack-bulk-publish/src/util/logger.js @@ -47,7 +47,7 @@ module.exports.addLogs = (logger, data, Type) => { logger.info(data); break; default: - console.log('Unknown logging level'); + console.log('Unknown log level.'); } }; diff --git a/packages/contentstack-bulk-publish/src/util/store.js b/packages/contentstack-bulk-publish/src/util/store.js index cf745f6cf4..ad98bfc8f4 100644 --- a/packages/contentstack-bulk-publish/src/util/store.js +++ b/packages/contentstack-bulk-publish/src/util/store.js @@ -12,7 +12,7 @@ function save(key, data) { console.log(chalk.red(error)); return; } - console.log(chalk.green(`Configuration file has been successfully created at ${filePath}`)); + console.log(chalk.green(`Configuration file successfully created at '${filePath}'.`)); }); } @@ -53,7 +53,7 @@ function updateMissing(key, flags) { savedConfig = get(key, pathValidator(flags.config)); Object.keys(savedConfig).forEach((element) => { if (flags[element] === undefined) { - console.log(`Using ${element} from config file`); + console.log(`Using '${element}' from the configuration file.`); flags[element] = savedConfig[element]; } }); diff --git a/packages/contentstack-bulk-publish/test/unit/commands/assets/publish.test.js b/packages/contentstack-bulk-publish/test/unit/commands/assets/publish.test.js index 3201988118..fb42fdd299 100644 --- a/packages/contentstack-bulk-publish/test/unit/commands/assets/publish.test.js +++ b/packages/contentstack-bulk-publish/test/unit/commands/assets/publish.test.js @@ -57,7 +57,7 @@ describe('AssetsPublish', () => { it('Should fail when alias and stack api key flags are not passed', async () => { const args = ['--environments', environments[0], '--locales', locales[0], '--yes']; - const expectedError = 'Please use `--alias` or `--stack-api-key` to proceed.'; + const expectedError = 'Use the `--alias` or `--stack-api-key` flag to proceed.'; try { await AssetsPublish.run(args); } catch (error) { diff --git a/packages/contentstack-bulk-publish/test/unit/commands/assets/unpublish.test.js b/packages/contentstack-bulk-publish/test/unit/commands/assets/unpublish.test.js index 42c8b62a50..157a768d91 100644 --- a/packages/contentstack-bulk-publish/test/unit/commands/assets/unpublish.test.js +++ b/packages/contentstack-bulk-publish/test/unit/commands/assets/unpublish.test.js @@ -90,7 +90,7 @@ describe('AssetsUnpublish Command', () => { try { await UnpublishCommand.run(['--environment', 'env', '--locale', 'en-us', '--yes']); } catch (error) { - expect(error.message).to.equal('Please use `--alias` or `--stack-api-key` to proceed.'); + expect(error.message).to.equal('Use the `--alias` or `--stack-api-key` flag to proceed.'); expect(runStub.called).to.be.false; } }); diff --git a/packages/contentstack-bulk-publish/test/unit/commands/bulk-publish/cross-publish.test.js b/packages/contentstack-bulk-publish/test/unit/commands/bulk-publish/cross-publish.test.js index 69f3b7a55e..f6337514b1 100644 --- a/packages/contentstack-bulk-publish/test/unit/commands/bulk-publish/cross-publish.test.js +++ b/packages/contentstack-bulk-publish/test/unit/commands/bulk-publish/cross-publish.test.js @@ -102,7 +102,7 @@ describe('CrossPublish', () => { 'token123', ]); } catch (error) { - expect(error.message).to.include('Please use `--alias` or `--stack-api-key` to proceed.'); + expect(error.message).to.include('Use the `--alias` or `--stack-api-key` flag to proceed.'); } }); diff --git a/packages/contentstack-bulk-publish/test/unit/commands/entries/publish-modified.test.js b/packages/contentstack-bulk-publish/test/unit/commands/entries/publish-modified.test.js index 5ede06e909..c8a24b1a9e 100644 --- a/packages/contentstack-bulk-publish/test/unit/commands/entries/publish-modified.test.js +++ b/packages/contentstack-bulk-publish/test/unit/commands/entries/publish-modified.test.js @@ -53,7 +53,7 @@ describe('EntriesPublishModified Command', () => { await EntriesPublishModified.run(args); } catch (error) { expect(error).to.be.an('error'); - expect(error.message).to.equal('Please use `--alias` or `--stack-api-key` to proceed.'); + expect(error.message).to.equal('Use the `--alias` or `--stack-api-key` flag to proceed.'); expect(runStub.calledOnce).to.be.true; } }); diff --git a/packages/contentstack-bulk-publish/test/unit/commands/entries/publish-non-localized-fields.test.js b/packages/contentstack-bulk-publish/test/unit/commands/entries/publish-non-localized-fields.test.js index 83544a0fcb..c189faaa8f 100644 --- a/packages/contentstack-bulk-publish/test/unit/commands/entries/publish-non-localized-fields.test.js +++ b/packages/contentstack-bulk-publish/test/unit/commands/entries/publish-non-localized-fields.test.js @@ -50,7 +50,7 @@ describe('EntriesPublishNonLocalizedFields', () => { environments[1], '--yes', ]; - const expectedError = 'Please use `--alias` or `--stack-api-key` to proceed.'; + const expectedError = 'Use the `--alias` or `--stack-api-key` flag to proceed.'; try { await EntriesPublishNonLocalizedFields.run(args); diff --git a/packages/contentstack-bulk-publish/test/unit/commands/entries/publish-only-unpublished.test.js b/packages/contentstack-bulk-publish/test/unit/commands/entries/publish-only-unpublished.test.js index 1c88160cf2..eacbc7fcd9 100644 --- a/packages/contentstack-bulk-publish/test/unit/commands/entries/publish-only-unpublished.test.js +++ b/packages/contentstack-bulk-publish/test/unit/commands/entries/publish-only-unpublished.test.js @@ -50,7 +50,7 @@ describe('EntriesPublishOnlyUnpublished', () => { '--yes', ]; - const expectedError = 'Please use `--alias` or `--stack-api-key` to proceed.'; + const expectedError = 'Use the `--alias` or `--stack-api-key` flag to proceed.'; runStub = sinon.stub(EntriesPublishOnlyUnpublished.prototype, 'run').callsFake(function () { throw new Error(expectedError); diff --git a/packages/contentstack-bulk-publish/test/unit/commands/entries/publish.test.js b/packages/contentstack-bulk-publish/test/unit/commands/entries/publish.test.js index 212fd125db..e1fa2018d4 100644 --- a/packages/contentstack-bulk-publish/test/unit/commands/entries/publish.test.js +++ b/packages/contentstack-bulk-publish/test/unit/commands/entries/publish.test.js @@ -59,7 +59,7 @@ describe('EntriesPublish Command', () => { '--yes', ]; - const expectedError = 'Please use `--alias` or `--stack-api-key` to proceed.'; + const expectedError = 'Use the `--alias` or `--stack-api-key` flag to proceed.'; try { await EntriesPublish.run(args); diff --git a/packages/contentstack-bulk-publish/test/unit/commands/entries/unpublish.test.js b/packages/contentstack-bulk-publish/test/unit/commands/entries/unpublish.test.js index f17cb02817..8c29666cd0 100644 --- a/packages/contentstack-bulk-publish/test/unit/commands/entries/unpublish.test.js +++ b/packages/contentstack-bulk-publish/test/unit/commands/entries/unpublish.test.js @@ -90,7 +90,7 @@ describe('EntriesUnpublish Command', () => { try { await EntriesUnpublish.run(['--environment', 'env', '--locale', 'en-us', '--yes']); } catch (error) { - expect(error.message).to.equal('Please use `--alias` or `--stack-api-key` to proceed.'); + expect(error.message).to.equal('Use the `--alias` or `--stack-api-key` flag to proceed.'); expect(runStub.called).to.be.false; } }); diff --git a/packages/contentstack-bulk-publish/test/unit/commands/entries/update-and-publish.test.js b/packages/contentstack-bulk-publish/test/unit/commands/entries/update-and-publish.test.js index df7db33689..4af1e01c82 100644 --- a/packages/contentstack-bulk-publish/test/unit/commands/entries/update-and-publish.test.js +++ b/packages/contentstack-bulk-publish/test/unit/commands/entries/update-and-publish.test.js @@ -51,7 +51,7 @@ describe('EntriesUpdateAndPublish', () => { it('Should fail when alias and stack api key flags are not passed', async () => { const args = ['--content-types', contentTypes[0], '-e', environments[0], '--locales', locales[0], '--yes']; const entriesUpdateAndPublishSpy = sinon.spy(EntriesUpdateAndPublish.prototype, 'run'); - const expectedError = 'Please use `--alias` or `--stack-api-key` to proceed.'; + const expectedError = 'Use the `--alias` or `--stack-api-key` flag to proceed.'; try { await EntriesUpdateAndPublish.run(args); } catch (error) { diff --git a/packages/contentstack-bulk-publish/test/unit/commands/stacks/publish.test.js b/packages/contentstack-bulk-publish/test/unit/commands/stacks/publish.test.js index 36237f663b..5ebdd2a86d 100644 --- a/packages/contentstack-bulk-publish/test/unit/commands/stacks/publish.test.js +++ b/packages/contentstack-bulk-publish/test/unit/commands/stacks/publish.test.js @@ -59,7 +59,7 @@ describe('StackPublish', () => { '--yes', ]; - const expectedError = 'Please use `--alias` or `--stack-api-key` to proceed.'; + const expectedError = 'Use the `--alias` or `--stack-api-key` flag to proceed.'; runStub = sinon.stub(StackPublish.prototype, 'run').callsFake(function () { throw new Error(expectedError); diff --git a/packages/contentstack-bulk-publish/test/unit/commands/stacks/unpublish.test.js b/packages/contentstack-bulk-publish/test/unit/commands/stacks/unpublish.test.js index ed25eb69b8..a26cf70487 100644 --- a/packages/contentstack-bulk-publish/test/unit/commands/stacks/unpublish.test.js +++ b/packages/contentstack-bulk-publish/test/unit/commands/stacks/unpublish.test.js @@ -76,7 +76,7 @@ describe('StackUnpublish', () => { '--yes', ]; - const expectedError = 'Please use `--alias` or `--stack-api-key` to proceed.'; + const expectedError = 'Use the `--alias` or `--stack-api-key` flag to proceed.'; runStub = sinon.stub(StackUnpublish.prototype, 'run').callsFake(function () { throw new Error(expectedError); diff --git a/packages/contentstack-clone/package.json b/packages/contentstack-clone/package.json index 3649a96a1f..8b60510d6e 100644 --- a/packages/contentstack-clone/package.json +++ b/packages/contentstack-clone/package.json @@ -8,7 +8,7 @@ "@colors/colors": "^1.6.0", "@contentstack/cli-cm-export": "~2.0.0-beta.2", "@contentstack/cli-cm-import": "~2.0.0-beta.2", - "@contentstack/cli-command": "~1.6.1", + "@contentstack/cli-command": "~1.7.0", "@contentstack/cli-utilities": "~1.15.0", "@oclif/core": "^4.3.0", "@oclif/plugin-help": "^6.2.28", @@ -20,8 +20,7 @@ "merge": "^2.1.1", "ora": "^5.4.1", "prompt": "^1.3.0", - "rimraf": "^5.0.10", - "winston": "^3.17.0" + "rimraf": "^6.1.0" }, "devDependencies": { "@oclif/test": "^4.1.13", diff --git a/packages/contentstack-clone/src/commands/cm/stacks/clone.js b/packages/contentstack-clone/src/commands/cm/stacks/clone.js index a1b5a44bcc..ec54dd99c5 100644 --- a/packages/contentstack-clone/src/commands/cm/stacks/clone.js +++ b/packages/contentstack-clone/src/commands/cm/stacks/clone.js @@ -1,5 +1,5 @@ const { Command } = require('@contentstack/cli-command'); -const { configHandler, flags, isAuthenticated, managementSDKClient } = require('@contentstack/cli-utilities'); +const { configHandler, flags, isAuthenticated, managementSDKClient, log, handleAndLogError } = require('@contentstack/cli-utilities'); const { CloneHandler } = require('../../../lib/util/clone-handler'); const path = require('path'); const { rimraf } = require('rimraf'); @@ -9,6 +9,44 @@ const { readdirSync, readFileSync } = require('fs'); let config = {}; class StackCloneCommand extends Command { + /** + * Determine authentication method based on user preference + */ + determineAuthenticationMethod(sourceManagementTokenAlias, destinationManagementTokenAlias) { + // Track authentication method + let authenticationMethod = 'unknown'; + + // Determine authentication method based on user preference + if (sourceManagementTokenAlias || destinationManagementTokenAlias) { + authenticationMethod = 'Management Token'; + } else if (isAuthenticated()) { + // Check if user is authenticated via OAuth + const isOAuthUser = configHandler.get('authorisationType') === 'OAUTH' || false; + if (isOAuthUser) { + authenticationMethod = 'OAuth'; + } else { + authenticationMethod = 'Basic Auth'; + } + } else { + authenticationMethod = 'Basic Auth'; + } + + return authenticationMethod; + } + + /** + * Create clone context object for logging + */ + createCloneContext(authenticationMethod) { + return { + command: this.context?.info?.command || 'cm:stacks:clone', + module: 'clone', + email: configHandler.get('email') || '', + sessionId: this.context?.sessionId || '', + authenticationMethod: authenticationMethod || 'Basic Auth', + }; + } + async run() { try { let self = this; @@ -31,14 +69,27 @@ class StackCloneCommand extends Command { const handleClone = async () => { const listOfTokens = configHandler.get('tokens'); + const authenticationMethod = this.determineAuthenticationMethod( + sourceManagementTokenAlias, + destinationManagementTokenAlias, + ); + const cloneContext = this.createCloneContext(authenticationMethod); + log.debug('Starting clone operation setup', cloneContext); if (externalConfigPath) { + log.debug(`Loading external configuration from: ${externalConfigPath}`, cloneContext); let externalConfig = readFileSync(externalConfigPath, 'utf-8'); externalConfig = JSON.parse(externalConfig); config = merge.recursive(config, externalConfig); } config.forceStopMarketplaceAppsPrompt = yes; config.skipAudit = cloneCommandFlags['skip-audit']; + log.debug('Clone configuration prepared', { + ...cloneContext, + cloneType: config.cloneType, + skipAudit: config.skipAudit, + forceStopMarketplaceAppsPrompt: config.forceStopMarketplaceAppsPrompt + }); if (cloneType) { config.cloneType = cloneType; @@ -67,15 +118,18 @@ class StackCloneCommand extends Command { if (sourceManagementTokenAlias && listOfTokens[sourceManagementTokenAlias]) { config.source_alias = sourceManagementTokenAlias; config.source_stack = listOfTokens[sourceManagementTokenAlias].apiKey; + log.debug(`Using source token alias: ${sourceManagementTokenAlias}`, cloneContext); } else if (sourceManagementTokenAlias) { - console.log(`Provided source token alias (${sourceManagementTokenAlias}) not found in your config.!`); + log.warn(`Provided source token alias (${sourceManagementTokenAlias}) not found in your config.!`, cloneContext); } if (destinationManagementTokenAlias && listOfTokens[destinationManagementTokenAlias]) { config.destination_alias = destinationManagementTokenAlias; config.target_stack = listOfTokens[destinationManagementTokenAlias].apiKey; + log.debug(`Using destination token alias: ${destinationManagementTokenAlias}`, cloneContext); } else if (destinationManagementTokenAlias) { - console.log( + log.warn( `Provided destination token alias (${destinationManagementTokenAlias}) not found in your config.!`, + cloneContext, ); } if (importWebhookStatus) { @@ -83,18 +137,23 @@ class StackCloneCommand extends Command { } const managementAPIClient = await managementSDKClient(config); + log.debug('Management API client initialized successfully', cloneContext); - await this.removeContentDirIfNotEmptyBeforeClone(pathdir); // NOTE remove if folder not empty before clone - this.registerCleanupOnInterrupt(pathdir); + log.debug(`Content directory path: ${pathdir}`, cloneContext); + await this.removeContentDirIfNotEmptyBeforeClone(pathdir, cloneContext); // NOTE remove if folder not empty before clone + this.registerCleanupOnInterrupt(pathdir, cloneContext); config.auth_token = configHandler.get('authtoken'); config.host = this.cmaHost; config.cdn = this.cdaHost; config.pathDir = pathdir; + config.cloneContext = cloneContext; + log.debug('Clone configuration finalized', cloneContext); const cloneHandler = new CloneHandler(config); cloneHandler.setClient(managementAPIClient); + log.debug('Starting clone operation', cloneContext); cloneHandler.execute().catch((error) => { - console.log(error); + handleAndLogError(error, cloneContext); }); }; @@ -103,7 +162,7 @@ class StackCloneCommand extends Command { if (isAuthenticated()) { handleClone(); } else { - console.log('Please login to execute this command, csdx auth:login'); + log.error('Log in to execute this command,csdx auth:login', cloneContext); this.exit(1); } } else { @@ -112,76 +171,76 @@ class StackCloneCommand extends Command { } else if (isAuthenticated()) { handleClone(); } else { - console.log('Please login to execute this command, csdx auth:login'); + log.error('Please login to execute this command, csdx auth:login', cloneContext); this.exit(1); } } catch (error) { if (error) { - await this.cleanUp(pathdir); - // eslint-disable-next-line no-console - console.log(error.message || error); + await this.cleanUp(pathdir, null, cloneContext); + log.error('Stack clone command failed', { ...cloneContext, error: error?.message || error }); } } } - async removeContentDirIfNotEmptyBeforeClone(dir) { + async removeContentDirIfNotEmptyBeforeClone(dir, cloneContext) { try { + log.debug('Checking if content directory is empty', { ...cloneContext, dir }); const dirNotEmpty = readdirSync(dir).length; if (dirNotEmpty) { - await this.cleanUp(dir); + log.debug('Content directory is not empty, cleaning up', { ...cloneContext, dir }); + await this.cleanUp(dir, null, cloneContext); } } catch (error) { const omit = ['ENOENT']; // NOTE add emittable error codes in the array if (!omit.includes(error.code)) { - console.log(error.message); + log.error('Error checking content directory', { ...cloneContext, error: error?.message, code: error.code }); } } } - async cleanUp(pathDir, message) { + async cleanUp(pathDir, message, cloneContext) { try { + log.debug('Starting cleanup', { ...cloneContext, pathDir }); await rimraf(pathDir); if (message) { - // eslint-disable-next-line no-console - console.log(message); + log.info(message, cloneContext); } + log.debug('Cleanup completed', { ...cloneContext, pathDir }); } catch (err) { if (err) { - console.log('\nCleaning up'); + log.debug('Cleaning up', cloneContext); const skipCodeArr = ['ENOENT', 'EBUSY', 'EPERM', 'EMFILE', 'ENOTEMPTY']; if (skipCodeArr.includes(err.code)) { + log.debug('Cleanup error code is in skip list, exiting', { ...cloneContext, code: err?.code }); process.exit(); } } } } - registerCleanupOnInterrupt(pathDir) { + registerCleanupOnInterrupt(pathDir, cloneContext) { const interrupt = ['SIGINT', 'SIGQUIT', 'SIGTERM']; const exceptions = ['unhandledRejection', 'uncaughtException']; const cleanUp = async (exitOrError) => { if (exitOrError) { - // eslint-disable-next-line no-console - console.log('\nCleaning up'); - await this.cleanUp(pathDir); - // eslint-disable-next-line no-console - console.log('done'); - // eslint-disable-next-line no-process-exit + log.debug('Cleaning up on interrupt', cloneContext); + await this.cleanUp(pathDir, null, cloneContext); + log.info('Cleanup done', cloneContext); if (exitOrError instanceof Promise) { exitOrError.catch((error) => { - console.log((error && error.message) || ''); + log.error('Error during cleanup', { ...cloneContext, error: (error && error?.message) || '' }); }); } else if (exitOrError.message) { - console.log(exitOrError.message); + log.error('Cleanup error', { ...cloneContext, error: exitOrError?.message }); } else if (exitOrError.errorMessage) { - console.log(exitOrError.message); + log.error('Cleanup error', { ...cloneContext, error: exitOrError?.errorMessage }); } if (exitOrError === true) process.exit(); diff --git a/packages/contentstack-clone/src/lib/util/clone-handler.js b/packages/contentstack-clone/src/lib/util/clone-handler.js index 1449bd0cbf..0bd4aab725 100644 --- a/packages/contentstack-clone/src/lib/util/clone-handler.js +++ b/packages/contentstack-clone/src/lib/util/clone-handler.js @@ -21,7 +21,7 @@ const { Clone, HandleBranchCommand, } = require('../helpers/command-helpers'); -const { configHandler, getBranchFromAlias } = require('@contentstack/cli-utilities'); +const { configHandler, getBranchFromAlias, log } = require('@contentstack/cli-utilities'); let client = {}; let config; @@ -76,6 +76,7 @@ class CloneHandler { cloneCommand = new Clone(); this.pathDir = opt.pathDir; process.stdin.setMaxListeners(50); + log.debug('Initializing CloneHandler', config.cloneContext, { pathDir: opt.pathDir, cloneType: opt.cloneType }); } setClient(managementSDKClient) { client = managementSDKClient; @@ -84,19 +85,24 @@ class CloneHandler { handleOrgSelection(options = {}) { return new Promise(async (resolve, reject) => { const { msg = '', isSource = true } = options || {}; + log.debug('Handling organization selection', config.cloneContext); const orgList = await this.getOrganizationChoices(msg).catch(reject); - if (orgList) { - const orgSelected = await inquirer.prompt(orgList); + if (orgList) { + log.debug(`Found ${orgList.choices?.length || 0} organization(s) to choose from`, config.cloneContext); + const orgSelected = await inquirer.prompt(orgList); + log.debug(`Organization selected: ${orgSelected.Organization}`, config.cloneContext); - if (isSource) { - config.sourceOrg = orgUidList[orgSelected.Organization]; - } else { - config.targetOrg = orgUidList[orgSelected.Organization]; - } + if (isSource) { + config.sourceOrg = orgUidList[orgSelected.Organization]; + log.debug(`Source organization UID: ${config.sourceOrg}`, config.cloneContext); + } else { + config.targetOrg = orgUidList[orgSelected.Organization]; + log.debug(`Target organization UID: ${config.targetOrg}`, config.cloneContext); + } - resolve(orgSelected); - } + resolve(orgSelected); + } }); } @@ -104,13 +110,16 @@ class CloneHandler { return new Promise(async (resolve, reject) => { try { const { org = {}, msg = '', isSource = true } = options || {}; + log.debug('Handling stack selection', config.cloneContext, { isSource, orgName: org.Organization, msg }); const stackList = await this.getStack(org, msg, isSource).catch(reject); if (stackList) { this.displayBackOptionMessage(); + log.debug(`Found ${stackList.choices?.length || 0} stack(s) to choose from`, config.cloneContext); const selectedStack = await inquirer.prompt(stackList); + log.debug(`Stack selected: ${selectedStack.stack}`, config.cloneContext); if (this.executingCommand != 1) { return reject(); } @@ -118,9 +127,11 @@ class CloneHandler { config.sourceStackName = selectedStack.stack; master_locale = masterLocaleList[selectedStack.stack]; config.source_stack = stackUidList[selectedStack.stack]; + log.debug(`Source stack configured`, config.cloneContext); } else { config.target_stack = stackUidList[selectedStack.stack]; config.destinationStackName = selectedStack.stack; + log.debug(`Target stack configured`, config.cloneContext); } resolve(selectedStack); @@ -136,6 +147,7 @@ class CloneHandler { return new Promise(async (resolve, reject) => { let spinner; try { + log.debug('Handling branch selection', config.cloneContext, { isSource, returnBranch, stackApiKey: isSource ? config.source_stack : config.target_stack }); const stackAPIClient = client.stack({ api_key: isSource ? config.source_stack : config.target_stack, management_token: config.management_token, @@ -143,22 +155,27 @@ class CloneHandler { // NOTE validate if source branch is exist if (isSource && config.sourceStackBranch) { + log.debug('Validating source branch exists', { ...config.cloneContext, branch: config.sourceStackBranch }); await this.validateIfBranchExist(stackAPIClient, true); return resolve(); } else if(isSource && config.sourceStackBranchAlias) { + log.debug('Resolving source branch alias', { ...config.cloneContext, alias: config.sourceStackBranchAlias }); await this.resolveBranchAliases(true); return resolve(); } // NOTE Validate target branch is exist if (!isSource && config.targetStackBranch) { + log.debug('Validating target branch exists', { ...config.cloneContext, branch: config.targetStackBranch }); await this.validateIfBranchExist(stackAPIClient, false); return resolve(); } else if (!isSource && config.targetStackBranchAlias) { + log.debug('Resolving target branch alias', { ...config.cloneContext, alias: config.targetStackBranchAlias }); await this.resolveBranchAliases(); return resolve(); } spinner = ora('Fetching Branches').start(); + log.debug(`Querying branches for stack: ${isSource ? config.source_stack : config.target_stack}`, config.cloneContext); const result = await stackAPIClient .branch() .query() @@ -167,6 +184,7 @@ class CloneHandler { .catch((_err) => {}); const condition = result && Array.isArray(result) && result.length > 0; + log.debug(`Found ${result?.length || 0} branch(es)`, config.cloneContext); // NOTE if want to get only list of branches (Pass param -> returnBranch = true ) if (returnBranch) { @@ -185,8 +203,10 @@ class CloneHandler { } if (isSource) { config.sourceStackBranch = branch; + log.debug(`Source branch selected: ${branch}`, config.cloneContext); } else { config.targetStackBranch = branch; + log.debug(`Target branch selected: ${branch}`, config.cloneContext); } } else { spinner.succeed('No branches found.!'); @@ -196,7 +216,6 @@ class CloneHandler { } } catch (e) { if (spinner) spinner.fail(); - console.error(e && e.message); return reject(e); } }); @@ -210,6 +229,7 @@ class CloneHandler { }; try { const branch = isSource ? config.sourceStackBranch : config.targetStackBranch; + log.debug('Validating branch existence', config.cloneContext); spinner = ora(`Validation if ${isSource ? 'source' : 'target'} branch exist.!`).start(); const isBranchExist = await stackAPIClient .branch(branch) @@ -217,8 +237,10 @@ class CloneHandler { .then((data) => data); if (isBranchExist && typeof isBranchExist === 'object') { + log.debug('Branch validation successful', config.cloneContext); completeSpinner(`${isSource ? 'Source' : 'Target'} branch verified.!`); } else { + log.error('Branch not found', config.cloneContext); completeSpinner(`${isSource ? 'Source' : 'Target'} branch not found.!`, 'fail'); process.exit(); } @@ -247,8 +269,10 @@ class CloneHandler { return new Promise(async (resolve, reject) => { let keyPressHandler; try { + log.debug('Starting clone execution', { ...config.cloneContext, sourceStack: config.source_stack, targetStack: config.target_stack }); if (!config.source_stack) { const orgMsg = 'Choose an organization where your source stack exists:'; + log.debug('Source stack not provided, prompting for organization', config.cloneContext); this.setExectingCommand(0); this.removeBackKeyPressHandler(); const org = await cloneCommand.execute(new HandleOrgCommand({ msg: orgMsg, isSource: true }, this)); @@ -278,17 +302,21 @@ class CloneHandler { return reject('Org not found.'); } } else { + log.debug('Source stack provided, proceeding with branch selection and export', config.cloneContext); this.setExectingCommand(2); await this.handleBranchSelection({ api_key: config.sourceStack }); + log.debug('Starting export operation', config.cloneContext); const exportRes = await cloneCommand.execute(new HandleExportCommand(null, this)); await cloneCommand.execute(new SetBranchCommand(null, this)); if (exportRes) { + log.debug('Export completed, proceeding with destination setup', config.cloneContext); this.executeDestination().catch((error) => { return reject(error); }); } } + log.debug('Clone execution completed successfully', config.cloneContext); return resolve(); } catch (error) { return reject(error); @@ -327,10 +355,12 @@ class CloneHandler { async executeExport() { try { + log.debug('Executing export operation', config.cloneContext); const exportRes = await cloneCommand.execute(new HandleExportCommand(null, this)); await cloneCommand.execute(new SetBranchCommand(null, this)); if (exportRes) { + log.debug('Export operation completed, proceeding with destination', config.cloneContext); this.executeDestination().catch(() => { throw ''; }); @@ -346,8 +376,10 @@ class CloneHandler { return new Promise(async (resolve, reject) => { let keyPressHandler; try { + log.debug('Executing destination setup', config.cloneContext); let canCreateStack = false; if (!config.target_stack) { + log.debug('Target stack not provided, prompting for stack creation', config.cloneContext); canCreateStack = await inquirer.prompt(stackCreationConfirmation); } @@ -397,6 +429,7 @@ class CloneHandler { await this.executeBranchDestinationPrompt(params); } + log.debug('Destination setup completed successfully', config.cloneContext); return resolve(); } catch (error) { reject(error); @@ -469,10 +502,12 @@ class CloneHandler { choices: [], }; return new Promise(async (resolve, reject) => { + log.debug('Fetching organization choices', config.cloneContext); const spinner = ora('Fetching Organization').start(); try { let organizations; const configOrgUid = configHandler.get('oauthOrgUid'); + log.debug('Getting organizations', config.cloneContext, { hasConfigOrgUid: !!configOrgUid }); if (configOrgUid) { organizations = await client.organization(configOrgUid).fetch(); @@ -481,6 +516,7 @@ class CloneHandler { } spinner.succeed('Fetched Organization'); + log.debug('Fetched organizations', config.cloneContext); for (const element of organizations.items || [organizations]) { orgUidList[element.name] = element.uid; orgChoice.choices.push(element.name); @@ -501,12 +537,15 @@ class CloneHandler { message: stkMessage !== undefined ? stkMessage : 'Select the stack', choices: [], }; + log.debug('Fetching stacks', config.cloneContext); const spinner = ora('Fetching stacks').start(); try { const organization_uid = orgUidList[answer.Organization]; + log.debug('Querying stacks for organization', config.cloneContext, { organizationUid: organization_uid }); const stackList = client.stack().query({ organization_uid }).find(); stackList .then((stacklist) => { + log.debug('Fetched stacks', config.cloneContext, { count: stacklist.items ? stacklist.items.length : 0 }); for (const element of stacklist.items) { stackUidList[element.name] = element.api_key; masterLocaleList[element.name] = element.master_locale; @@ -530,9 +569,11 @@ class CloneHandler { return new Promise(async (resolve, reject) => { try { const { orgUid } = options; + log.debug('Creating new stack', config.cloneContext, { orgUid, masterLocale: master_locale, stackName: config.stackName }); this.displayBackOptionMessage(); let inputvalue; if (!config.stackName) { + log.debug('Stack name not provided, prompting user', config.cloneContext); prompt.start(); prompt.message = ''; this.setCreateNewStackPrompt(prompt); @@ -542,17 +583,24 @@ class CloneHandler { inputvalue = { stack: config.stackName }; } if (this.executingCommand === 0 || !inputvalue) { + log.debug('Stack creation cancelled or invalid input', config.cloneContext); return reject(); } let stack = { name: inputvalue.stack, master_locale: master_locale }; + log.debug('Creating stack with configuration', config.cloneContext); const spinner = ora('Creating New stack').start(); + log.debug('Sending stack creation API request', config.cloneContext); let newStack = client.stack().create({ stack }, { organization_uid: orgUid }); newStack .then((result) => { + log.debug('Stack created successfully', config.cloneContext, { + stackName: result.name, + }); spinner.succeed('New Stack created Successfully name as ' + result.name); config.target_stack = result.api_key; config.destinationStackName = result.name; + log.debug('Target stack configuration updated', config.cloneContext); return resolve(result); }) .catch((error) => { @@ -589,12 +637,15 @@ class CloneHandler { async resolveBranchAliases(isSource = false) { try { + log.debug('Resolving branch aliases', { ...config.cloneContext, isSource, alias: isSource ? config.sourceStackBranchAlias : config.targetStackBranchAlias }); if (isSource) { const sourceStack = client.stack({ api_key: config.source_stack }); config.sourceStackBranch = await getBranchFromAlias(sourceStack, config.sourceStackBranchAlias); + log.debug('Source branch alias resolved', { ...config.cloneContext, alias: config.sourceStackBranchAlias, branch: config.sourceStackBranch }); } else { const targetStack = client.stack({ api_key: config.target_stack }); config.targetStackBranch = await getBranchFromAlias(targetStack, config.targetStackBranchAlias); + log.debug('Target branch alias resolved', { ...config.cloneContext, alias: config.targetStackBranchAlias, branch: config.targetStackBranch }); } } catch (error) { throw error; @@ -604,6 +655,7 @@ class CloneHandler { async cloneTypeSelection() { console.clear(); return new Promise(async (resolve, reject) => { + log.debug('Starting clone type selection', config.cloneContext); const choices = [ 'Structure (all modules except entries & assets)', 'Structure with content (all modules including entries & assets)', @@ -619,83 +671,139 @@ class CloneHandler { let successMsg; let selectedValue = {}; config['data'] = path.join(__dirname.split('src')[0], 'contents', config.sourceStackBranch || ''); + log.debug(`Clone data directory: ${config['data']}`, config.cloneContext); if (!config.cloneType) { + log.debug('Clone type not specified, prompting user for selection', config.cloneContext); selectedValue = await inquirer.prompt(cloneTypeSelection); + } else { + log.debug(`Using pre-configured clone type: ${config.cloneType}`, config.cloneContext); } if (config.cloneType === 'a' || selectedValue.type === 'Structure (all modules except entries & assets)') { config['modules'] = structureList; successMsg = 'Stack clone Structure completed'; + log.debug(`Clone type: Structure only. Modules to clone: ${structureList.join(', ')}`, config.cloneContext); } else { successMsg = 'Stack clone completed with structure and content'; + log.debug('Clone type: Structure with content (all modules)', config.cloneContext); } this.cmdImport() - .then(() => resolve(successMsg)) + .then(() => { + log.debug('Clone type selection and import completed successfully', config.cloneContext); + resolve(successMsg); + }) .catch(reject); }); } async cmdExport() { return new Promise((resolve, reject) => { + log.debug('Preparing export command', { ...config.cloneContext, sourceStack: config.source_stack, cloneType: config.cloneType }); // Creating export specific config by merging external configurations let exportConfig = Object.assign({}, cloneDeep(config), { ...config?.export }); delete exportConfig.import; delete exportConfig.export; - const cmd = ['-k', exportConfig.source_stack, '-d', __dirname.split('src')[0] + 'contents']; + const exportDir = __dirname.split('src')[0] + 'contents'; + log.debug(`Export directory: ${exportDir}`, config.cloneContext); + const cmd = ['-k', exportConfig.source_stack, '-d', exportDir]; + if (exportConfig.cloneType === 'a') { exportConfig.filteredModules = ['stack'].concat(structureList); + log.debug(`Filtered modules for structure-only export: ${exportConfig.filteredModules.join(', ')}`, config.cloneContext); } if (exportConfig.source_alias) { cmd.push('-a', exportConfig.source_alias); + log.debug(`Using source alias: ${exportConfig.source_alias}`, config.cloneContext); } if (exportConfig.sourceStackBranch) { cmd.push('--branch', exportConfig.sourceStackBranch); + log.debug(`Using source branch: ${exportConfig.sourceStackBranch}`, config.cloneContext); } - if (exportConfig.forceStopMarketplaceAppsPrompt) cmd.push('-y'); + if (exportConfig.forceStopMarketplaceAppsPrompt) { + cmd.push('-y'); + log.debug('Force stop marketplace apps prompt enabled', config.cloneContext); + } + const configFilePath = path.join(__dirname, 'dummyConfig.json'); cmd.push('-c'); - cmd.push(path.join(__dirname, 'dummyConfig.json')); - - fs.writeFileSync(path.join(__dirname, 'dummyConfig.json'), JSON.stringify(exportConfig)); + cmd.push(configFilePath); + log.debug(`Writing export config to: ${configFilePath}`, config.cloneContext); + + fs.writeFileSync(configFilePath, JSON.stringify(exportConfig)); + log.debug('Export command prepared', config.cloneContext, { + cmd: cmd.join(' '), + exportDir, + sourceStack: exportConfig.source_stack, + branch: exportConfig.sourceStackBranch + }); + log.debug('Running export command', config.cloneContext, { cmd }); let exportData = exportCmd.run(cmd); - exportData.then(() => resolve(true)).catch(reject); + exportData.then(() => { + log.debug('Export command completed successfully', config.cloneContext); + resolve(true); + }).catch((error) => { + reject(error); + }); }); } async cmdImport() { return new Promise(async (resolve, _reject) => { + log.debug('Preparing import command', { ...config.cloneContext, targetStack: config.target_stack, targetBranch: config.targetStackBranch }); // Creating export specific config by merging external configurations let importConfig = Object.assign({}, cloneDeep(config), { ...config?.import }); delete importConfig.import; delete importConfig.export; - const cmd = ['-c', path.join(__dirname, 'dummyConfig.json')]; + const configFilePath = path.join(__dirname, 'dummyConfig.json'); + const cmd = ['-c', configFilePath]; if (importConfig.destination_alias) { cmd.push('-a', importConfig.destination_alias); + log.debug(`Using destination alias: ${importConfig.destination_alias}`, config.cloneContext); } if (!importConfig.data && importConfig.sourceStackBranch) { - cmd.push('-d', path.join(importConfig.pathDir, importConfig.sourceStackBranch)); + const dataPath = path.join(importConfig.pathDir, importConfig.sourceStackBranch); + cmd.push('-d', dataPath); + log.debug(`Import data path: ${dataPath}`, config.cloneContext); } if (importConfig.targetStackBranch) { cmd.push('--branch', importConfig.targetStackBranch); + log.debug(`Using target branch: ${importConfig.targetStackBranch}`, config.cloneContext); } if (importConfig.importWebhookStatus) { cmd.push('--import-webhook-status', importConfig.importWebhookStatus); + log.debug(`Import webhook status: ${importConfig.importWebhookStatus}`, config.cloneContext); } - if (importConfig.skipAudit) cmd.push('--skip-audit'); + if (importConfig.skipAudit) { + cmd.push('--skip-audit'); + log.debug('Skip audit flag enabled', config.cloneContext); + } - if (importConfig.forceStopMarketplaceAppsPrompt) cmd.push('-y'); + if (importConfig.forceStopMarketplaceAppsPrompt) { + cmd.push('-y'); + log.debug('Force stop marketplace apps prompt enabled', config.cloneContext); + } - fs.writeFileSync(path.join(__dirname, 'dummyConfig.json'), JSON.stringify(importConfig)); + log.debug(`Writing import config to: ${configFilePath}`, config.cloneContext); + fs.writeFileSync(configFilePath, JSON.stringify(importConfig)); + log.debug('Import command prepared', config.cloneContext, { + cmd: cmd.join(' '), + targetStack: importConfig.target_stack, + targetBranch: importConfig.targetStackBranch, + dataPath: importConfig.data || path.join(importConfig.pathDir, importConfig.sourceStackBranch) + }); + log.debug('Running import command', config.cloneContext, { cmd }); await importCmd.run(cmd); - fs.writeFileSync(path.join(__dirname, 'dummyConfig.json'), JSON.stringify({})); + log.debug('Import command completed successfully', config.cloneContext); + log.debug('Clearing import config file', config.cloneContext); + fs.writeFileSync(configFilePath, JSON.stringify({})); return resolve(); }); } diff --git a/packages/contentstack-clone/src/lib/util/log.js b/packages/contentstack-clone/src/lib/util/log.js deleted file mode 100644 index 7d806cd9a8..0000000000 --- a/packages/contentstack-clone/src/lib/util/log.js +++ /dev/null @@ -1,105 +0,0 @@ -/*! - * Contentstack Import - * Copyright (c) 2024 Contentstack LLC - * MIT Licensed - */ - -var winston = require('winston'); -var path = require('path'); -var mkdirp = require('mkdirp'); -const { pathValidator, sanitizePath } = require('@contentstack/cli-utilities'); -var slice = Array.prototype.slice; - -function returnString(args) { - var returnStr = ''; - if (args && args.length) { - returnStr = args - .map(function (item) { - if (item && typeof item === 'object') { - return JSON.stringify(item); - } - return item; - }) - .join(' ') - .trim(); - } - return returnStr; -} - -var myCustomLevels = { - levels: { - error: 0, - warn: 1, - info: 2, - debug: 3, - }, - colors: { - info: 'blue', - debug: 'green', - warn: 'yellow', - error: 'red', - }, -}; - -function init(_logPath, logfileName) { - var logsDir = pathValidator(path.resolve(sanitizePath(_logPath), 'logs', 'import')); - // Create dir if doesn't already exist - mkdirp.sync(logsDir); - var logPath = path.join(sanitizePath(logsDir), pathValidator(sanitizePath(logfileName)) + '.log'); - - var transports = [ - new winston.transports.File({ - filename: logPath, - maxFiles: 20, - maxsize: 1000000, - tailable: true, - json: true, - }), - ]; - - transports.push(new winston.transports.Console()); - - var logger = winston.createLogger({ - transports: transports, - levels: myCustomLevels.levels, - }); - - return { - log: function () { - var args = slice.call(arguments); - var logString = returnString(args); - if (logString) { - logger.log('info', logString); - } - }, - warn: function () { - var args = slice.call(arguments); - var logString = returnString(args); - if (logString) { - logger.log('warn', logString); - } - }, - error: function () { - var args = slice.call(arguments); - var logString = returnString(args); - if (logString) { - logger.log('error', logString); - } - }, - debug: function () { - var args = slice.call(arguments); - var logString = returnString(args); - if (logString) { - logger.log('debug', logString); - } - }, - }; -} - -exports.addlogs = async (config, message, type) => { - if (type !== 'error') { - init(config.oldPath, type).log(message); - } else { - init(config.oldPath, type).error(message); - } -}; diff --git a/packages/contentstack-command/package.json b/packages/contentstack-command/package.json index 8a6c096d5a..c6fd25be6c 100644 --- a/packages/contentstack-command/package.json +++ b/packages/contentstack-command/package.json @@ -1,7 +1,7 @@ { "name": "@contentstack/cli-command", "description": "Contentstack CLI plugin for configuration", - "version": "1.6.2", + "version": "1.7.0", "author": "Contentstack", "main": "lib/index.js", "types": "lib/index.d.ts", diff --git a/packages/contentstack-command/src/index.ts b/packages/contentstack-command/src/index.ts index 77051b4283..e82bee1075 100644 --- a/packages/contentstack-command/src/index.ts +++ b/packages/contentstack-command/src/index.ts @@ -21,7 +21,7 @@ abstract class ContentstackCommand extends Command { if (this._email) return this._email; this._email = configHandler.get('email'); if (this._email) return this._email; - throw new CLIError('You are not logged in. Please login with command $ csdx auth:login'); + throw new CLIError('You are not logged in. Run the command: $ csdx auth:login'); } get deliveryAPIClient() { @@ -105,6 +105,9 @@ abstract class ContentstackCommand extends Command { get personalizeUrl() { return this.region.personalizeUrl; } + get composableStudioUrl() { + return this.region.composableStudioUrl; + } } module.exports = { diff --git a/packages/contentstack-command/src/interfaces/index.ts b/packages/contentstack-command/src/interfaces/index.ts index 4538fef85b..262acce498 100644 --- a/packages/contentstack-command/src/interfaces/index.ts +++ b/packages/contentstack-command/src/interfaces/index.ts @@ -5,5 +5,6 @@ export interface Region { developerHubUrl: string; personalizeUrl: string; launchHubUrl: string; + composableStudioUrl: string; uiHost: string; } diff --git a/packages/contentstack-config/package.json b/packages/contentstack-config/package.json index 84c0a95104..0bec09d167 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.15.3", + "version": "1.16.1", "author": "Contentstack", "scripts": { "build": "npm run clean && npm run compile", @@ -21,7 +21,7 @@ "test:unit:report": "nyc --extension .ts mocha --forbid-only \"test/unit/**/*.test.ts\"" }, "dependencies": { - "@contentstack/cli-command": "~1.6.1", + "@contentstack/cli-command": "~1.7.0", "@contentstack/cli-utilities": "~1.15.0", "@oclif/core": "^4.3.0", "@oclif/plugin-help": "^6.2.28", diff --git a/packages/contentstack-config/src/commands/config/get/base-branch.ts b/packages/contentstack-config/src/commands/config/get/base-branch.ts index cf8dbdfe0d..71c4b05f4b 100644 --- a/packages/contentstack-config/src/commands/config/get/base-branch.ts +++ b/packages/contentstack-config/src/commands/config/get/base-branch.ts @@ -25,7 +25,7 @@ export default class BranchGetCommand extends Command { cliux.print(`error: ${messageHandler.parse('CLI_CONFIG_BRANCH_LIST_NO_BRANCHES')}`, { color: 'red' }); } } catch (error) { - cliux.error('error', error); + cliux.error('Error', error); } } } diff --git a/packages/contentstack-config/src/commands/config/get/early-access-header.ts b/packages/contentstack-config/src/commands/config/get/early-access-header.ts index 883cae1220..93c2bff299 100644 --- a/packages/contentstack-config/src/commands/config/get/early-access-header.ts +++ b/packages/contentstack-config/src/commands/config/get/early-access-header.ts @@ -24,7 +24,7 @@ export default class GetEarlyAccessHeaderCommand extends Command { ]; cliux.table(tableHeaders, tableData); } else { - cliux.print(`No Early Access header found!`, { color: 'red' }); + cliux.print(`Early Access header not found.`, { color: 'red' }); } } catch (error) { this.log('Unable to retrieve the Early Access header config', error instanceof Error ? error.message : error); diff --git a/packages/contentstack-config/src/commands/config/get/log.ts b/packages/contentstack-config/src/commands/config/get/log.ts index 8b2307a12c..6195bc3850 100644 --- a/packages/contentstack-config/src/commands/config/get/log.ts +++ b/packages/contentstack-config/src/commands/config/get/log.ts @@ -34,7 +34,7 @@ export default class LogGetCommand extends Command { color: 'dim', }); } catch (error) { - cliux.error('error', error); + cliux.error('Error', error); } } } diff --git a/packages/contentstack-config/src/commands/config/get/region.ts b/packages/contentstack-config/src/commands/config/get/region.ts index 5763ae9ac9..d49295d5bc 100644 --- a/packages/contentstack-config/src/commands/config/get/region.ts +++ b/packages/contentstack-config/src/commands/config/get/region.ts @@ -10,18 +10,17 @@ export default class RegionGetCommand extends BaseCommand 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.'); + cliux.error('Utilization 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.'); + cliux.error('The number of utilization percentages must match the number of limit names.'); return; } else { config.utilize = utilize.split(',').map((v: string) => v.trim()); @@ -85,7 +85,7 @@ export default class SetRateLimitCommand extends BaseCommand --cda --ui-host --name "India" --developer-hub ', '$ csdx config:set:region --cma --cda --ui-host --name "India" --personalize ', '$ csdx config:set:region --cma --cda --ui-host --name "India" --launch ', - '$ csdx config:set:region --cda --cma --ui-host --name "India" --developer-hub --launch --personalize ', + '$ csdx config:set:region --cma --cda --ui-host --name "India" --studio ', + '$ csdx config:set:region --cda --cma --ui-host --name "India" --developer-hub --launch --personalize --studio ', ]; static args: ArgInput = { @@ -78,6 +82,7 @@ export default class RegionSetCommand extends BaseCommand { it("Should execute 'config:set:region --AZURE-NA'", () => { const result = spawnSync('csdx', ['config:set:region', 'AZURE-NA'], { encoding: 'utf-8' }); const output = result.stdout + result.stderr; - expect(output).to.include('Region has been set to AZURE-NA'); - expect(output).to.include('CDA HOST: https://azure-na-cdn.contentstack.com'); - expect(output).to.include('CMA HOST: https://azure-na-api.contentstack.com'); + expect(output).to.include('CDA host: https://azure-na-cdn.contentstack.com'); + expect(output).to.include('CMA host: https://azure-na-api.contentstack.com'); }); it("Should execute 'config:get:region' and return the current region", () => { @@ -16,16 +15,15 @@ describe('ContentStack-Config Plugin Tests', () => { const output = result.stdout + result.stderr; expect(output).to.include('Currently using'); - expect(output).to.include('CDA HOST:'); - expect(output).to.include('CMA HOST:'); + expect(output).to.include('CDA host:'); + expect(output).to.include('CMA host:'); }); it("Should execute 'config:set:region AWS-NA' and set AWS-NA region", () => { const result = spawnSync('csdx', ['config:set:region', 'AWS-NA'], { encoding: 'utf-8' }); const output = result.stdout + result.stderr; - expect(output).to.include('Region has been set to AWS-NA'); - expect(output).to.include('CDA HOST: https://cdn.contentstack.io'); - expect(output).to.include('CMA HOST: https://api.contentstack.io'); + expect(output).to.include('CDA host: https://cdn.contentstack.io'); + expect(output).to.include('CMA host: https://api.contentstack.io'); }); }); diff --git a/packages/contentstack-config/test/unit/commands/rate-limit.test.ts b/packages/contentstack-config/test/unit/commands/rate-limit.test.ts index 429848964a..c1585b9213 100644 --- a/packages/contentstack-config/test/unit/commands/rate-limit.test.ts +++ b/packages/contentstack-config/test/unit/commands/rate-limit.test.ts @@ -59,7 +59,7 @@ describe('Rate Limit Commands', () => { 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.'); + expect(errorMessage).to.equal('Utilization percentages must be numbers between 0 and 100.'); expect(exitStub.calledWith(1)).to.be.true; @@ -74,7 +74,7 @@ describe('Rate Limit Commands', () => { await SetRateLimitCommand.run(args); expect(errorMessage).to.equal( - 'The number of utilization percentages must match the number of limit names provided.', + 'The number of utilization percentages must match the number of limit names.', ); expect(exitStub.calledWith(1)).to.be.true; @@ -90,7 +90,7 @@ describe('Rate Limit Commands', () => { await SetRateLimitCommand.run(args); expect(errorMessage).to.equal( - 'The number of utilization percentages must match the number of limit names provided.', + 'The number of utilization percentages must match the number of limit names.', ); expect(exitStub.calledWith(1)).to.be.true; diff --git a/packages/contentstack-config/test/unit/commands/region.test.ts b/packages/contentstack-config/test/unit/commands/region.test.ts index 7063bb954e..8802287981 100644 --- a/packages/contentstack-config/test/unit/commands/region.test.ts +++ b/packages/contentstack-config/test/unit/commands/region.test.ts @@ -17,6 +17,7 @@ describe('Region command', function () { developerHubUrl: 'https://developerhub-api.contentstack.com', launchHubUrl: 'https://launch-api.contentstack.com', personalizeUrl: 'https://personalization-api.contentstack.com', + composableStudioUrl: 'https://composable-studio-api.contentstack.com', }; let cliuxPrintStub: sinon.SinonStub; let configGetStub: sinon.SinonStub; @@ -69,6 +70,7 @@ describe('Region command', function () { expect(result.developerHubUrl).to.equal('https://developerhub-api.contentstack.com'); expect(result.personalizeUrl).to.equal('https://personalize-api.contentstack.com'); expect(result.launchHubUrl).to.equal('https://launch-api.contentstack.com'); + expect(result.composableStudioUrl).to.equal('https://composable-studio-api.contentstack.com'); }); it('should set EU region', function () { @@ -80,6 +82,7 @@ describe('Region command', function () { expect(result.developerHubUrl).to.equal('https://eu-developerhub-api.contentstack.com'); expect(result.personalizeUrl).to.equal('https://eu-personalize-api.contentstack.com'); expect(result.launchHubUrl).to.equal('https://eu-launch-api.contentstack.com'); + expect(result.composableStudioUrl).to.equal('https://eu-composable-studio-api.contentstack.com'); }); it('should set AU region', function () { @@ -91,6 +94,7 @@ describe('Region command', function () { expect(result.developerHubUrl).to.equal('https://au-developerhub-api.contentstack.com'); expect(result.personalizeUrl).to.equal('https://au-personalize-api.contentstack.com'); expect(result.launchHubUrl).to.equal('https://au-launch-api.contentstack.com'); + expect(result.composableStudioUrl).to.equal('https://au-composable-studio-api.contentstack.com'); }); it('should set AWS-NA region', function () { @@ -102,6 +106,7 @@ describe('Region command', function () { expect(result.developerHubUrl).to.equal('https://developerhub-api.contentstack.com'); expect(result.personalizeUrl).to.equal('https://personalize-api.contentstack.com'); expect(result.launchHubUrl).to.equal('https://launch-api.contentstack.com'); + expect(result.composableStudioUrl).to.equal('https://composable-studio-api.contentstack.com'); }); it('should set AWS-EU region', function () { @@ -113,6 +118,7 @@ describe('Region command', function () { expect(result.developerHubUrl).to.equal('https://eu-developerhub-api.contentstack.com'); expect(result.personalizeUrl).to.equal('https://eu-personalize-api.contentstack.com'); expect(result.launchHubUrl).to.equal('https://eu-launch-api.contentstack.com'); + expect(result.composableStudioUrl).to.equal('https://eu-composable-studio-api.contentstack.com'); }); it('should set AWS-AU region', function () { @@ -124,6 +130,7 @@ describe('Region command', function () { expect(result.developerHubUrl).to.equal('https://au-developerhub-api.contentstack.com'); expect(result.personalizeUrl).to.equal('https://au-personalize-api.contentstack.com'); expect(result.launchHubUrl).to.equal('https://au-launch-api.contentstack.com'); + expect(result.composableStudioUrl).to.equal('https://au-composable-studio-api.contentstack.com'); }); it('should set AZURE-NA region', function () { @@ -135,6 +142,7 @@ describe('Region command', function () { expect(result.developerHubUrl).to.equal('https://azure-na-developerhub-api.contentstack.com'); expect(result.personalizeUrl).to.equal('https://azure-na-personalize-api.contentstack.com'); expect(result.launchHubUrl).to.equal('https://azure-na-launch-api.contentstack.com'); + expect(result.composableStudioUrl).to.equal('https://azure-na-composable-studio-api.contentstack.com'); }); it('should set AZURE-EU region', function () { @@ -146,6 +154,7 @@ describe('Region command', function () { expect(result.developerHubUrl).to.equal('https://azure-eu-developerhub-api.contentstack.com'); expect(result.personalizeUrl).to.equal('https://azure-eu-personalize-api.contentstack.com'); expect(result.launchHubUrl).to.equal('https://azure-eu-launch-api.contentstack.com'); + expect(result.composableStudioUrl).to.equal('https://azure-eu-composable-studio-api.contentstack.com'); }); it('should set GCP-NA region', function () { @@ -157,6 +166,7 @@ describe('Region command', function () { expect(result.developerHubUrl).to.equal('https://gcp-na-developerhub-api.contentstack.com'); expect(result.personalizeUrl).to.equal('https://gcp-na-personalize-api.contentstack.com'); expect(result.launchHubUrl).to.equal('https://gcp-na-launch-api.contentstack.com'); + expect(result.composableStudioUrl).to.equal('https://gcp-na-composable-studio-api.contentstack.com'); }); it('should set GCP-EU region', function () { @@ -168,6 +178,7 @@ describe('Region command', function () { expect(result.developerHubUrl).to.equal('https://gcp-eu-developerhub-api.contentstack.com'); expect(result.personalizeUrl).to.equal('https://gcp-eu-personalize-api.contentstack.com'); expect(result.launchHubUrl).to.equal('https://gcp-eu-launch-api.contentstack.com'); + expect(result.composableStudioUrl).to.equal('https://gcp-eu-composable-studio-api.contentstack.com'); }); it('should return undefined for invalid region', function () { @@ -263,6 +274,18 @@ describe('Region command', function () { expect(result.launchHubUrl).to.equal(customRegion.launchHubUrl); }); + it('should set a custom region with studio URL', function () { + const customRegion = { + cma: 'https://custom-cma.com', + cda: 'https://custom-cda.com', + uiHost: 'https://custom-ui.com', + name: 'Custom Region', + composableStudioUrl: 'https://custom-composable-studio.com', + }; + const result = UserConfig.setCustomRegion(customRegion); + expect(result.composableStudioUrl).to.equal(customRegion.composableStudioUrl); + }); + it('should set a custom region with all optional URLs', function () { const customRegion = { cma: 'https://custom-cma.com', @@ -272,6 +295,7 @@ describe('Region command', function () { developerHubUrl: 'https://custom-developer-hub.com', personalizeUrl: 'https://custom-personalize.com', launchHubUrl: 'https://custom-launch.com', + composableStudioUrl: 'https://custom-composable-studio.com', }; const result = UserConfig.setCustomRegion(customRegion); expect(result).to.deep.equal(customRegion); @@ -286,6 +310,7 @@ describe('Region command', function () { developerHubUrl: 'https://custom-developer-hub.com', personalizeUrl: 'https://custom-personalize.com', launchHubUrl: 'https://custom-launch.com', + composableStudioUrl: 'https://custom-composable-studio.com', invalidProperty: 'should be removed', }; const result = UserConfig.setCustomRegion(customRegion); diff --git a/packages/contentstack-export-to-csv/package.json b/packages/contentstack-export-to-csv/package.json index be677eb3a1..700af06280 100644 --- a/packages/contentstack-export-to-csv/package.json +++ b/packages/contentstack-export-to-csv/package.json @@ -1,11 +1,11 @@ { "name": "@contentstack/cli-cm-export-to-csv", "description": "Export entities to csv", - "version": "1.10.0", + "version": "1.10.1", "author": "Abhinav Gupta @abhinav-from-contentstack", "bugs": "https://github.com/contentstack/cli/issues", "dependencies": { - "@contentstack/cli-command": "~1.6.1", + "@contentstack/cli-command": "~1.7.0", "@contentstack/cli-utilities": "~1.15.0", "@oclif/core": "^4.3.0", "@oclif/plugin-help": "^6.2.32", diff --git a/packages/contentstack-export-to-csv/src/commands/cm/export-to-csv.js b/packages/contentstack-export-to-csv/src/commands/cm/export-to-csv.js index 2c98a30506..96461c8320 100644 --- a/packages/contentstack-export-to-csv/src/commands/cm/export-to-csv.js +++ b/packages/contentstack-export-to-csv/src/commands/cm/export-to-csv.js @@ -395,7 +395,7 @@ class ExportToCsvCommand extends Command { token: listOfTokens[managementTokenAlias].token, }; } else if (managementTokenAlias) { - this.error('Provided management token alias not found in your config.!'); + this.error('The provided management token alias was not found in your config.'); } return { apiClient, diff --git a/packages/contentstack-export-to-csv/src/util/index.js b/packages/contentstack-export-to-csv/src/util/index.js index e1b2cfc7c9..e2b8923605 100644 --- a/packages/contentstack-export-to-csv/src/util/index.js +++ b/packages/contentstack-export-to-csv/src/util/index.js @@ -378,7 +378,7 @@ function getContentTypeCount(stackAPIClient) { } function exitProgram() { - debug('Exiting'); + debug('Exiting...'); // eslint-disable-next-line no-undef process.exit(); } diff --git a/packages/contentstack-export/messages/index.json b/packages/contentstack-export/messages/index.json index 16fda7957d..3cba26d11b 100644 --- a/packages/contentstack-export/messages/index.json +++ b/packages/contentstack-export/messages/index.json @@ -11,58 +11,64 @@ "ASSET_VERSIONED_QUERY_FAILED": "Failed to query versioned asset data from the API", "ASSET_COUNT_QUERY_FAILED": "Failed to retrieve total asset count", -"CONTENT_TYPE_EXPORT_COMPLETE": "Content types exported successfully", -"CONTENT_TYPE_NO_TYPES": "No content types found", -"CONTENT_TYPE_EXPORT_FAILED": "Failed to export content types", -"CONTENT_TYPE_NO_TYPES_RETURNED": "API returned no content types for the given query", - -"ENVIRONMENT_EXPORT_COMPLETE": "Successfully exported %s environment(s)", -"ENVIRONMENT_EXPORT_SUCCESS": "Environment '%s' exported successfully", -"ENVIRONMENT_NOT_FOUND": "No environments found in the current stack", - -"EXTENSION_EXPORT_COMPLETE": "Successfully exported %s extension(s)", -"EXTENSION_EXPORT_SUCCESS": "Extension '%s' exported successfully", -"EXTENSION_NOT_FOUND": "No extensions found in the current stack", - -"GLOBAL_FIELDS_EXPORT_COMPLETE": "Successfully exported %s global field(s)", - -"LABELS_EXPORT_COMPLETE": "Successfully exported %s label(s)", -"LABEL_EXPORT_SUCCESS": "Label '%s' exported successfully", -"LABELS_NOT_FOUND": "No labels found in the current stack", - -"LOCALES_EXPORT_COMPLETE": "Successfully exported %s locale(s) including %s master locale(s)", - -"TAXONOMY_EXPORT_COMPLETE": "Successfully exported %s taxonomy entries", -"TAXONOMY_EXPORT_SUCCESS": "Taxonomy '%s' exported successfully", -"TAXONOMY_NOT_FOUND": "No taxonomies found in the current stack", - -"WEBHOOK_EXPORT_COMPLETE": "Successfully exported %s webhook(s)", -"WEBHOOK_EXPORT_SUCCESS": "Webhook '%s' exported successfully", -"WEBHOOK_NOT_FOUND": "No webhooks found in the current stack", - -"WORKFLOW_EXPORT_COMPLETE": "Successfully exported %s workflow(s)", -"WORKFLOW_EXPORT_SUCCESS": "Workflow '%s' exported successfully", -"WORKFLOW_NOT_FOUND": "No workflows found in the current stack", - -"PERSONALIZE_URL_NOT_SET": "Cannot export Personalize project: URL not configured", -"PERSONALIZE_SKIPPING_WITH_MANAGEMENT_TOKEN": "Skipping Personalize project export: Management token not supported", -"PERSONALIZE_MODULE_NOT_IMPLEMENTED": "Module '%s' implementation not found", -"PERSONALIZE_NOT_ENABLED": "Personalize feature is not enabled for this organization", - -"MARKETPLACE_APPS_EXPORT_COMPLETE": "Successfully exported %s marketplace app(s)", -"MARKETPLACE_APP_CONFIG_EXPORT": "Exporting configuration for app '%s'", -"MARKETPLACE_APP_CONFIG_SUCCESS": "Successfully exported configuration for app '%s'", -"MARKETPLACE_APP_EXPORT_SUCCESS": "Successfully exported app '%s'", -"MARKETPLACE_APPS_NOT_FOUND": "No marketplace apps found in the current stack", -"MARKETPLACE_APP_CONFIG_EXPORT_FAILED": "Failed to export configuration for app '%s'", -"MARKETPLACE_APP_MANIFEST_EXPORT_FAILED": "Failed to export manifest for app '%s'", - -"ENTRIES_EXPORT_COMPLETE": "Successfully exported entries (Content Type: %s, Locale: %s)", -"ENTRIES_EXPORT_SUCCESS": "All entries exported successfully", -"ENTRIES_VERSIONED_EXPORT_SUCCESS": "Successfully exported versioned entry (Content Type: %s, UID: %s, Locale: %s)", -"ENTRIES_EXPORT_VERSIONS_FAILED": "Failed to export versions for content type '%s' (UID: %s)", - -"BRANCH_EXPORT_FAILED": "Failed to export contents from branch (UID: %s)", + "CONTENT_TYPE_EXPORT_COMPLETE": "Content types exported successfully", + "CONTENT_TYPE_NO_TYPES": "No content types found", + "CONTENT_TYPE_EXPORT_FAILED": "Failed to export content types", + "CONTENT_TYPE_NO_TYPES_RETURNED": "API returned no content types for the given query", + + "ENVIRONMENT_EXPORT_COMPLETE": "Successfully exported %s environment(s)", + "ENVIRONMENT_EXPORT_SUCCESS": "Environment '%s' exported successfully", + "ENVIRONMENT_NOT_FOUND": "No environments found in the current stack", + + "EXTENSION_EXPORT_COMPLETE": "Successfully exported %s extension(s)", + "EXTENSION_EXPORT_SUCCESS": "Extension '%s' exported successfully", + "EXTENSION_NOT_FOUND": "No extensions found in the current stack", + + "GLOBAL_FIELDS_EXPORT_COMPLETE": "Successfully exported %s global field(s)", + + "LABELS_EXPORT_COMPLETE": "Successfully exported %s label(s)", + "LABEL_EXPORT_SUCCESS": "Label '%s' exported successfully", + "LABELS_NOT_FOUND": "No labels found in the current stack", + + "LOCALES_EXPORT_COMPLETE": "Successfully exported %s locale(s) including %s master locale(s)", + + "TAXONOMY_EXPORT_COMPLETE": "Successfully exported %s taxonomy entries", + "TAXONOMY_EXPORT_SUCCESS": "Taxonomy '%s' exported successfully", + "TAXONOMY_NOT_FOUND": "No taxonomies found in the current stack", + + "WEBHOOK_EXPORT_COMPLETE": "Successfully exported %s webhook(s)", + "WEBHOOK_EXPORT_SUCCESS": "Webhook '%s' exported successfully", + "WEBHOOK_NOT_FOUND": "No webhooks found in the current stack", + + "WORKFLOW_EXPORT_COMPLETE": "Successfully exported %s workflow(s)", + "WORKFLOW_EXPORT_SUCCESS": "Workflow '%s' exported successfully", + "WORKFLOW_NOT_FOUND": "No workflows found in the current stack", + + "PERSONALIZE_URL_NOT_SET": "Cannot export Personalize project: URL not configured", + "PERSONALIZE_SKIPPING_WITH_MANAGEMENT_TOKEN": "Skipping Personalize project export: Management token not supported", + "PERSONALIZE_MODULE_NOT_IMPLEMENTED": "Module '%s' implementation not found", + "PERSONALIZE_NOT_ENABLED": "Personalize feature is not enabled for this organization", + + "MARKETPLACE_APPS_EXPORT_COMPLETE": "Successfully exported %s marketplace app(s)", + "MARKETPLACE_APP_CONFIG_EXPORT": "Exporting configuration for app '%s'", + "MARKETPLACE_APP_CONFIG_SUCCESS": "Successfully exported configuration for app '%s'", + "MARKETPLACE_APP_EXPORT_SUCCESS": "Successfully exported app '%s'", + "MARKETPLACE_APPS_NOT_FOUND": "No marketplace apps found in the current stack", + "MARKETPLACE_APP_CONFIG_EXPORT_FAILED": "Failed to export configuration for app '%s'", + "MARKETPLACE_APP_MANIFEST_EXPORT_FAILED": "Failed to export manifest for app '%s'", + + "COMPOSABLE_STUDIO_EXPORT_START": "Starting Studio project export...", + "COMPOSABLE_STUDIO_NOT_FOUND": "No Studio project found for this stack", + "COMPOSABLE_STUDIO_EXPORT_COMPLETE": "Successfully exported Studio project '%s'", + "COMPOSABLE_STUDIO_EXPORT_FAILED": "Failed to export Studio project: %s", + "COMPOSABLE_STUDIO_AUTH_REQUIRED": "To export Studio projects, you must be logged in", + + "ENTRIES_EXPORT_COMPLETE": "Successfully exported entries (Content Type: %s, Locale: %s)", + "ENTRIES_EXPORT_SUCCESS": "All entries exported successfully", + "ENTRIES_VERSIONED_EXPORT_SUCCESS": "Successfully exported versioned entry (Content Type: %s, UID: %s, Locale: %s)", + "ENTRIES_EXPORT_VERSIONS_FAILED": "Failed to export versions for content type '%s' (UID: %s)", + + "BRANCH_EXPORT_FAILED": "Failed to export contents from branch (UID: %s)", "ROLES_NO_CUSTOM_ROLES": "No custom roles found in the current stack", "ROLES_EXPORTING_ROLE": "Exporting role '%s'", diff --git a/packages/contentstack-export/package.json b/packages/contentstack-export/package.json index 231b4b6f34..19c85c1a34 100644 --- a/packages/contentstack-export/package.json +++ b/packages/contentstack-export/package.json @@ -21,8 +21,8 @@ "winston": "^3.17.0" }, "devDependencies": { - "@contentstack/cli-auth": "~1.6.1", - "@contentstack/cli-config": "~1.15.1", + "@contentstack/cli-auth": "~1.6.2", + "@contentstack/cli-config": "~1.15.3", "@contentstack/cli-dev-dependencies": "~1.3.1", "@oclif/plugin-help": "^6.2.28", "@oclif/test": "^4.1.13", diff --git a/packages/contentstack-export/src/commands/cm/stacks/export.ts b/packages/contentstack-export/src/commands/cm/stacks/export.ts index 5304f4d059..70753050bc 100644 --- a/packages/contentstack-export/src/commands/cm/stacks/export.ts +++ b/packages/contentstack-export/src/commands/cm/stacks/export.ts @@ -79,7 +79,7 @@ export default class ExportCommand extends Command { module: flags.string({ char: 'm', description: - '[optional] Specific module name. If not specified, the export command will export all the modules to the stack. The available modules are assets, content-types, entries, environments, extensions, marketplace-apps, global-fields, labels, locales, webhooks, workflows, custom-roles, and taxonomies.', + '[optional] Specific module name. If not specified, the export command will export all the modules to the stack. The available modules are assets, content-types, entries, environments, extensions, marketplace-apps, global-fields, labels, locales, webhooks, workflows, custom-roles, taxonomies, and studio.', parse: printFlagDeprecation(['-m'], ['--module']), }), 'content-types': flags.string({ @@ -185,5 +185,9 @@ export default class ExportCommand extends Command { if (this.personalizeUrl) { exportConfig.modules.personalize.baseURL[exportConfig.region.name] = this.personalizeUrl; } + + if (this.composableStudioUrl) { + exportConfig.modules['composable-studio'].apiBaseUrl = this.composableStudioUrl; + } } } diff --git a/packages/contentstack-export/src/config/index.ts b/packages/contentstack-export/src/config/index.ts index dee5213920..14fe590b32 100644 --- a/packages/contentstack-export/src/config/index.ts +++ b/packages/contentstack-export/src/config/index.ts @@ -39,6 +39,7 @@ const config: DefaultConfig = { 'entries', 'labels', 'marketplace-apps', + 'composable-studio', ], locales: { dirName: 'locales', @@ -212,6 +213,12 @@ const config: DefaultConfig = { dirName: 'marketplace_apps', fileName: 'marketplace_apps.json', }, + 'composable-studio': { + dirName: 'composable_studio', + fileName: 'composable_studio.json', + apiBaseUrl: 'https://composable-studio-api.contentstack.com', + apiVersion: 'v1', + }, taxonomies: { dirName: 'taxonomies', fileName: 'taxonomies.json', diff --git a/packages/contentstack-export/src/export/module-exporter.ts b/packages/contentstack-export/src/export/module-exporter.ts index 90bc73f854..2e86dbedd3 100644 --- a/packages/contentstack-export/src/export/module-exporter.ts +++ b/packages/contentstack-export/src/export/module-exporter.ts @@ -104,7 +104,7 @@ class ModuleExporter { } async exportByModuleByName(moduleName: Modules) { - log.info(`Exporting module: ${moduleName}`, this.exportConfig.context); + log.info(`Exporting module: '${moduleName}'...`, this.exportConfig.context); // export the modules by name // calls the module runner which inturn calls the module itself await startModuleExport({ @@ -122,9 +122,8 @@ class ModuleExporter { } if (!this.exportConfig.skipDependencies) { - const { - modules: { [moduleName]: { dependencies = [] } = {} }, - } = this.exportConfig; + const moduleConfig = this.exportConfig.modules[moduleName as keyof typeof this.exportConfig.modules]; + const dependencies = (moduleConfig as any)?.dependencies || []; if (dependencies.length > 0) { exportModules = exportModules.concat(dependencies); diff --git a/packages/contentstack-export/src/export/modules/composable-studio.ts b/packages/contentstack-export/src/export/modules/composable-studio.ts new file mode 100644 index 0000000000..8faff8c2b5 --- /dev/null +++ b/packages/contentstack-export/src/export/modules/composable-studio.ts @@ -0,0 +1,138 @@ +import { resolve as pResolve } from 'node:path'; +import { + cliux, + isAuthenticated, + log, + messageHandler, + handleAndLogError, + HttpClient, + authenticationHandler, +} from '@contentstack/cli-utilities'; + +import { fsUtil, getOrgUid } from '../../utils'; +import { ModuleClassParams, ComposableStudioConfig, ExportConfig, ComposableStudioProject } from '../../types'; + +export default class ExportComposableStudio { + protected composableStudioConfig: ComposableStudioConfig; + protected composableStudioProject: ComposableStudioProject | null = null; + protected apiClient: HttpClient; + public composableStudioPath: string; + public exportConfig: ExportConfig; + + constructor({ exportConfig }: Omit) { + this.exportConfig = exportConfig; + this.composableStudioConfig = exportConfig.modules['composable-studio']; + this.exportConfig.context.module = 'composable-studio'; + + // Initialize HttpClient with Studio API base URL + this.apiClient = new HttpClient(); + this.apiClient.baseUrl(`${this.composableStudioConfig.apiBaseUrl}/${this.composableStudioConfig.apiVersion}`); + } + + async start(): Promise { + log.debug('Starting Studio project export process...', this.exportConfig.context); + + if (!isAuthenticated()) { + cliux.print( + 'WARNING!!! To export Studio projects, you must be logged in. Please check csdx auth:login --help to log in', + { color: 'yellow' }, + ); + return Promise.resolve(); + } + + this.composableStudioPath = pResolve( + this.exportConfig.data, + this.exportConfig.branchName || '', + this.composableStudioConfig.dirName, + ); + log.debug(`Studio folder path: ${this.composableStudioPath}`, this.exportConfig.context); + + await fsUtil.makeDirectory(this.composableStudioPath); + log.debug('Created Studio directory', this.exportConfig.context); + + this.exportConfig.org_uid = this.exportConfig.org_uid || (await getOrgUid(this.exportConfig)); + log.debug(`Organization UID: ${this.exportConfig.org_uid}`, this.exportConfig.context); + + await this.exportProjects(); + log.debug('Studio project export process completed', this.exportConfig.context); + } + + /** + * Export Studio projects connected to the current stack + */ + async exportProjects(): Promise { + log.debug('Starting Studio project export...', this.exportConfig.context); + + try { + // Get authentication details - following personalization-api-adapter pattern + log.debug('Initializing Studio API authentication...', this.exportConfig.context); + await authenticationHandler.getAuthDetails(); + const token = authenticationHandler.accessToken; + log.debug( + `Authentication type: ${authenticationHandler.isOauthEnabled ? 'OAuth' : 'Token'}`, + this.exportConfig.context, + ); + + // Set authentication headers based on auth type + if (authenticationHandler.isOauthEnabled) { + log.debug('Setting OAuth authorization header', this.exportConfig.context); + this.apiClient.headers({ authorization: token }); + } else { + log.debug('Setting authtoken header', this.exportConfig.context); + this.apiClient.headers({ authtoken: token }); + } + + // Set organization_uid header + this.apiClient.headers({ + organization_uid: this.exportConfig.org_uid, + Accept: 'application/json', + }); + + const apiUrl = '/projects'; + log.debug( + `Fetching projects from: ${this.composableStudioConfig.apiBaseUrl}${apiUrl}`, + this.exportConfig.context, + ); + + // Make API call to fetch projects using HttpClient + const response = await this.apiClient.get(apiUrl); + + if (response.status < 200 || response.status >= 300) { + throw new Error(`API call failed with status ${response.status}: ${JSON.stringify(response.data)}`); + } + + const data = response.data; + log.debug(`Fetched ${data.projects?.length || 0} total projects`, this.exportConfig.context); + + // Filter projects connected to this stack + const connectedProject = data.projects?.filter( + (project: ComposableStudioProject) => project.connectedStackApiKey === this.exportConfig.apiKey, + ); + + if (!connectedProject || connectedProject.length === 0) { + log.info(messageHandler.parse('COMPOSABLE_STUDIO_NOT_FOUND'), this.exportConfig.context); + return; + } + + // Use the first connected project (stacks should have only one project) + this.composableStudioProject = connectedProject[0]; + log.debug(`Found Studio project: ${this.composableStudioProject.name}`, this.exportConfig.context); + + // Write the project to file + const composableStudioFilePath = pResolve(this.composableStudioPath, this.composableStudioConfig.fileName); + log.debug(`Writing Studio project to: ${composableStudioFilePath}`, this.exportConfig.context); + + fsUtil.writeFile(composableStudioFilePath, this.composableStudioProject as unknown as Record); + + log.success( + messageHandler.parse('COMPOSABLE_STUDIO_EXPORT_COMPLETE', this.composableStudioProject.name), + this.exportConfig.context, + ); + } catch (error: any) { + log.debug('Error occurred while exporting Studio project', this.exportConfig.context); + handleAndLogError(error, { + ...this.exportConfig.context, + }); + } + } +} diff --git a/packages/contentstack-export/src/export/modules/custom-roles.ts b/packages/contentstack-export/src/export/modules/custom-roles.ts index 48bb96fdcc..7deb696b6f 100644 --- a/packages/contentstack-export/src/export/modules/custom-roles.ts +++ b/packages/contentstack-export/src/export/modules/custom-roles.ts @@ -121,11 +121,11 @@ export default class ExportCustomRoles extends BaseClass { .role() .fetchAll({ include_rules: true, include_permissions: true }) .then((data: any) => { - log.debug(`Fetched ${data.items?.length || 0} total roles`, this.exportConfig.context); + log.debug(`Fetched ${data.items?.length || 0} roles from the stack.`, this.exportConfig.context); return data; }) .catch((err: any) => { - log.debug('Error occurred while fetching roles', this.exportConfig.context); + log.debug('An error occurred while fetching roles.', this.exportConfig.context); return handleAndLogError(err, { ...this.exportConfig.context }); }); @@ -149,7 +149,7 @@ export default class ExportCustomRoles extends BaseClass { }); const customRolesFilePath = pResolve(this.rolesFolderPath, this.customRolesConfig.fileName); - log.debug(`Writing custom roles to: ${customRolesFilePath}`, this.exportConfig.context); + log.debug(`Writing custom roles to: ${customRolesFilePath}.`, this.exportConfig.context); fsUtil.writeFile(customRolesFilePath, this.customRoles); } @@ -161,11 +161,11 @@ export default class ExportCustomRoles extends BaseClass { .query({}) .find() .then((data: any) => { - log.debug(`Fetched ${data?.items?.length || 0} locales`, this.exportConfig.context); + log.debug(`Fetched ${data?.items?.length || 0} locales.`, this.exportConfig.context); return data; }) .catch((err: any) => { - log.debug('Error occurred while fetching locales', this.exportConfig.context); + log.debug('An error occurred while fetching locales.', this.exportConfig.context); return handleAndLogError(err, { ...this.exportConfig.context }); }); @@ -194,7 +194,7 @@ export default class ExportCustomRoles extends BaseClass { this.exportConfig.context, ); forEach(rulesLocales.locales, (locale: any) => { - log.debug(`Adding locale ${locale} to custom roles mapping`, this.exportConfig.context); + log.debug(`Adding locale ${locale} to the custom roles mapping.`, this.exportConfig.context); this.localesMap[locale] = 1; }); } @@ -215,7 +215,7 @@ export default class ExportCustomRoles extends BaseClass { log.debug(`Writing custom roles locales to: ${this.customRolesLocalesFilepath}`, this.exportConfig.context); fsUtil.writeFile(this.customRolesLocalesFilepath, this.localesMap); } else { - log.debug('No custom role locales found to process', this.exportConfig.context); + log.debug('No custom role locales found to process.', this.exportConfig.context); } // Track progress for mapping completion diff --git a/packages/contentstack-export/src/export/modules/entries.ts b/packages/contentstack-export/src/export/modules/entries.ts index 616a069f55..e4187af9ba 100644 --- a/packages/contentstack-export/src/export/modules/entries.ts +++ b/packages/contentstack-export/src/export/modules/entries.ts @@ -322,7 +322,7 @@ export default class EntriesExport extends BaseClass { log.debug('Initialized FsUtility for writing entries', this.exportConfig.context); } - log.debug(`Writing ${entriesSearchResponse.items.length} entries to file`, this.exportConfig.context); + log.debug(`Writing ${entriesSearchResponse.items.length} entries to file...`, this.exportConfig.context); this.entriesFileHelper.writeIntoFile(entriesSearchResponse.items, { mapKeyVal: true }); // Track progress for individual entries @@ -331,14 +331,14 @@ export default class EntriesExport extends BaseClass { }); if (this.entriesConfig.exportVersions) { - log.debug('Exporting entry versions is enabled', this.exportConfig.context); + log.debug('Exporting entry versions is enabled.', this.exportConfig.context); let versionedEntryPath = path.join( sanitizePath(this.entriesDirPath), sanitizePath(options.contentType), sanitizePath(options.locale), 'versions', ); - log.debug(`Creating versioned entries directory at: ${versionedEntryPath}`, this.exportConfig.context); + log.debug(`Creating versioned entries directory at: ${versionedEntryPath}.`, this.exportConfig.context); fsUtil.makeDirectory(versionedEntryPath); await this.fetchEntriesVersions(entriesSearchResponse.items, { locale: options.locale, @@ -393,7 +393,7 @@ export default class EntriesExport extends BaseClass { entries: any, options: { locale: string; contentType: string; versionedEntryPath: string }, ): Promise { - log.debug(`Fetching versions for ${entries.length} entries`, this.exportConfig.context); + log.debug(`Fetching versions for ${entries.length} entries...`, this.exportConfig.context); const onSuccess = ({ response, apiData: entry }: any) => { const versionFilePath = path.join(sanitizePath(options.versionedEntryPath), sanitizePath(`${entry.uid}.json`)); @@ -459,7 +459,7 @@ export default class EntriesExport extends BaseClass { return new Promise(async (resolve, reject) => { return await this.getEntryByVersion(apiParams.queryParam, entry) .then((response) => { - log.debug(`Successfully fetched versions for entry: ${entry.uid}`, this.exportConfig.context); + log.debug(`Successfully fetched versions for entry UID: ${entry.uid}`, this.exportConfig.context); apiParams.resolve({ response, apiData: entry, @@ -467,7 +467,7 @@ export default class EntriesExport extends BaseClass { resolve(true); }) .catch((error) => { - log.debug(`Failed to fetch versions for entry: ${entry.uid}`, this.exportConfig.context); + log.debug(`Failed to fetch versions for entry UID: ${entry.uid}`, this.exportConfig.context); apiParams.reject({ error, apiData: entry, @@ -490,7 +490,7 @@ export default class EntriesExport extends BaseClass { version: entry._version, }; - log.debug(`Fetching entry version ${entry._version} for uid: ${entry.uid}`, this.exportConfig.context); + log.debug(`Fetching entry version ${entry._version} for entry UID: '${entry.uid}'.`, this.exportConfig.context); const entryResponse = await this.stackAPIClient .contentType(options.contentType) diff --git a/packages/contentstack-export/src/export/modules/environments.ts b/packages/contentstack-export/src/export/modules/environments.ts index 68961f3e17..80e2ae8a9b 100644 --- a/packages/contentstack-export/src/export/modules/environments.ts +++ b/packages/contentstack-export/src/export/modules/environments.ts @@ -80,9 +80,9 @@ export default class ExportEnvironments extends BaseClass { async getEnvironments(skip = 0): Promise { if (skip) { this.qs.skip = skip; - log.debug(`Fetching environments with skip: ${skip}`, this.exportConfig.context); + log.debug(`Fetching environments with skip value: ${skip}`, this.exportConfig.context); } else { - log.debug('Fetching environments with initial query', this.exportConfig.context); + log.debug('Fetching environments with initial query...', this.exportConfig.context); } log.debug(`Query parameters: ${JSON.stringify(this.qs)}`, this.exportConfig.context); @@ -96,21 +96,21 @@ export default class ExportEnvironments extends BaseClass { log.debug(`Fetched ${items?.length || 0} environments out of total ${count}`, this.exportConfig.context); if (items?.length) { - log.debug(`Processing ${items.length} environments`, this.exportConfig.context); + log.debug(`Processing ${items.length} environments.`, this.exportConfig.context); this.sanitizeAttribs(items); skip += this.environmentConfig.limit || 100; if (skip >= count) { - log.debug('Completed fetching all environments', this.exportConfig.context); + log.debug('Completed fetching all environments.', this.exportConfig.context); return; } - log.debug(`Continuing to fetch environments with skip: ${skip}`, this.exportConfig.context); + log.debug(`Continuing environment fetch with skip value: ${skip}`, this.exportConfig.context); return await this.getEnvironments(skip); } else { - log.debug('No environments found to process', this.exportConfig.context); + log.debug('No environments found to process.', this.exportConfig.context); } }) .catch((error: any) => { - log.debug('Error occurred while fetching environments', this.exportConfig.context); + log.debug('An error occurred while fetching environments.', this.exportConfig.context); handleAndLogError(error, { ...this.exportConfig.context }); }); } diff --git a/packages/contentstack-export/src/export/modules/extensions.ts b/packages/contentstack-export/src/export/modules/extensions.ts index 7665aa30c9..f8260bb76d 100644 --- a/packages/contentstack-export/src/export/modules/extensions.ts +++ b/packages/contentstack-export/src/export/modules/extensions.ts @@ -81,9 +81,9 @@ export default class ExportExtensions extends BaseClass { async getExtensions(skip = 0): Promise { if (skip) { this.qs.skip = skip; - log.debug(`Fetching extensions with skip: ${skip}`, this.exportConfig.context); + log.debug(`Fetching extensions with skip value: ${skip}`, this.exportConfig.context); } else { - log.debug('Fetching extensions with initial query', this.exportConfig.context); + log.debug('Fetching extensions with initial query...', this.exportConfig.context); } log.debug(`Query parameters: ${JSON.stringify(this.qs)}`, this.exportConfig.context); @@ -97,21 +97,21 @@ export default class ExportExtensions extends BaseClass { log.debug(`Fetched ${items?.length || 0} extensions out of total ${count}`, this.exportConfig.context); if (items?.length) { - log.debug(`Processing ${items.length} extensions`, this.exportConfig.context); + log.debug(`Processing ${items.length} extensions...`, this.exportConfig.context); this.sanitizeAttribs(items); skip += this.extensionConfig.limit || 100; if (skip >= count) { - log.debug('Completed fetching all extensions', this.exportConfig.context); + log.debug('Completed fetching all extensions.', this.exportConfig.context); return; } - log.debug(`Continuing to fetch extensions with skip: ${skip}`, this.exportConfig.context); + log.debug(`Continuing to fetch extensions with skip: ${skip}.`, this.exportConfig.context); return await this.getExtensions(skip); } else { - log.debug('No extensions found to process', this.exportConfig.context); + log.debug('No extensions found to process.', this.exportConfig.context); } }) .catch((error: any) => { - log.debug('Error occurred while fetching extensions', this.exportConfig.context); + log.debug('An error occurred while fetching extensions.', this.exportConfig.context); handleAndLogError(error, { ...this.exportConfig.context }); }); } diff --git a/packages/contentstack-export/src/export/modules/global-fields.ts b/packages/contentstack-export/src/export/modules/global-fields.ts index 0d74f8da3b..a6c7dd0b7e 100644 --- a/packages/contentstack-export/src/export/modules/global-fields.ts +++ b/packages/contentstack-export/src/export/modules/global-fields.ts @@ -74,7 +74,7 @@ export default class GlobalFieldsExport extends BaseClass { await this.getGlobalFields(); const globalFieldsFilePath = path.join(this.globalFieldsDirPath, this.globalFieldsConfig.fileName); - log.debug(`Writing global fields to: ${globalFieldsFilePath}`, this.exportConfig.context); + log.debug(`Writing global fields to: '${globalFieldsFilePath}'`, this.exportConfig.context); fsUtil.writeFile(globalFieldsFilePath, this.globalFields); log.success( @@ -84,7 +84,7 @@ export default class GlobalFieldsExport extends BaseClass { this.completeProgress(true); } catch (error) { - log.debug('Error occurred during global fields export', this.exportConfig.context); + log.debug('An error occurred during global fields export.', this.exportConfig.context); handleAndLogError(error, { ...this.exportConfig.context }); this.completeProgress(false, error?.message || 'Global fields export failed'); } @@ -93,7 +93,7 @@ export default class GlobalFieldsExport extends BaseClass { async getGlobalFields(skip: number = 0): Promise { if (skip) { this.qs.skip = skip; - log.debug(`Fetching global fields with skip: ${skip}`, this.exportConfig.context); + log.debug(`Fetching global fields with skip: ${skip}.`, this.exportConfig.context); } log.debug(`Query parameters: ${JSON.stringify(this.qs)}`, this.exportConfig.context); @@ -107,17 +107,17 @@ export default class GlobalFieldsExport extends BaseClass { ); if (Array.isArray(globalFieldsFetchResponse.items) && globalFieldsFetchResponse.items.length > 0) { - log.debug(`Processing ${globalFieldsFetchResponse.items.length} global fields`, this.exportConfig.context); + log.debug(`Processing ${globalFieldsFetchResponse.items.length} global fields...`, this.exportConfig.context); this.sanitizeAttribs(globalFieldsFetchResponse.items); skip += this.globalFieldsConfig.limit || 100; if (skip >= globalFieldsFetchResponse.count) { - log.debug('Completed fetching all global fields', this.exportConfig.context); + log.debug('Completed fetching all global fields.', this.exportConfig.context); return; } - log.debug(`Continuing to fetch global fields with skip: ${skip}`, this.exportConfig.context); + log.debug(`Continuing to fetch global fields with skip: ${skip}.`, this.exportConfig.context); return await this.getGlobalFields(skip); } else { - log.debug('No global fields found to process', this.exportConfig.context); + log.debug('No global fields found to process.', this.exportConfig.context); } } diff --git a/packages/contentstack-export/src/export/modules/labels.ts b/packages/contentstack-export/src/export/modules/labels.ts index aa9edab2bf..269f4b0461 100644 --- a/packages/contentstack-export/src/export/modules/labels.ts +++ b/packages/contentstack-export/src/export/modules/labels.ts @@ -82,9 +82,9 @@ export default class ExportLabels extends BaseClass { async getLabels(skip = 0): Promise { if (skip) { this.qs.skip = skip; - log.debug(`Fetching labels with skip: ${skip}`, this.exportConfig.context); + log.debug(`Fetching labels with skip: ${skip}.`, this.exportConfig.context); } else { - log.debug('Fetching labels with initial query', this.exportConfig.context); + log.debug('Fetching labels with initial query...', this.exportConfig.context); } log.debug(`Query parameters: ${JSON.stringify(this.qs)}`, this.exportConfig.context); @@ -98,17 +98,17 @@ export default class ExportLabels extends BaseClass { log.debug(`Fetched ${items?.length || 0} labels out of total ${count}`, this.exportConfig.context); if (items?.length) { - log.debug(`Processing ${items.length} labels`, this.exportConfig.context); + log.debug(`Processing ${items.length} labels...`, this.exportConfig.context); this.sanitizeAttribs(items); skip += this.labelConfig.limit || 100; if (skip >= count) { - log.debug('Completed fetching all labels', this.exportConfig.context); + log.debug('Completed fetching all labels.', this.exportConfig.context); return; } - log.debug(`Continuing to fetch labels with skip: ${skip}`, this.exportConfig.context); + log.debug(`Continuing to fetch labels with skip: ${skip}.`, this.exportConfig.context); return await this.getLabels(skip); } else { - log.debug('No labels found to process', this.exportConfig.context); + log.debug('No labels found to process.', this.exportConfig.context); } }) .catch((error: any) => { diff --git a/packages/contentstack-export/src/export/modules/locales.ts b/packages/contentstack-export/src/export/modules/locales.ts index 58cc3960ee..48c6306e2b 100644 --- a/packages/contentstack-export/src/export/modules/locales.ts +++ b/packages/contentstack-export/src/export/modules/locales.ts @@ -105,7 +105,7 @@ export default class LocaleExport extends BaseClass { async getLocales(skip: number = 0): Promise { if (skip) { this.qs.skip = skip; - log.debug(`Fetching locales with skip: ${skip}`, this.exportConfig.context); + log.debug(`Fetching locales with skip: ${skip}.`, this.exportConfig.context); } log.debug(`Query parameters: ${JSON.stringify(this.qs)}`, this.exportConfig.context); @@ -117,18 +117,18 @@ export default class LocaleExport extends BaseClass { ); if (Array.isArray(localesFetchResponse.items) && localesFetchResponse.items.length > 0) { - log.debug(`Processing ${localesFetchResponse.items.length} locales`, this.exportConfig.context); + log.debug(`Processing ${localesFetchResponse.items.length} locales...`, this.exportConfig.context); this.sanitizeAttribs(localesFetchResponse.items); skip += this.localeConfig.limit || 100; if (skip > localesFetchResponse.count) { - log.debug('Completed fetching all locales', this.exportConfig.context); + log.debug('Completed fetching all locales.', this.exportConfig.context); return; } - log.debug(`Continuing to fetch locales with skip: ${skip}`, this.exportConfig.context); + log.debug(`Continuing to fetch locales with skip: ${skip}.`, this.exportConfig.context); return await this.getLocales(skip); } else { - log.debug('No locales found to process', this.exportConfig.context); + log.debug('No locales found to process.', this.exportConfig.context); } } diff --git a/packages/contentstack-export/src/export/modules/marketplace-apps.ts b/packages/contentstack-export/src/export/modules/marketplace-apps.ts index 9aa5854ef4..e58b0efb1a 100644 --- a/packages/contentstack-export/src/export/modules/marketplace-apps.ts +++ b/packages/contentstack-export/src/export/modules/marketplace-apps.ts @@ -135,11 +135,11 @@ export default class ExportMarketplaceApps extends BaseClass { this.exportConfig.org_uid = await getOrgUid(this.exportConfig); this.query = { target_uids: this.exportConfig.source_stack }; - log.debug(`Organization UID: ${this.exportConfig.org_uid}`, this.exportConfig.context); + log.debug(`Organization UID: '${this.exportConfig.org_uid}'.`, this.exportConfig.context); // NOTE init marketplace app sdk const host = this.developerHubBaseUrl.split('://').pop(); - log.debug(`Initializing marketplace SDK with host: ${host}`, this.exportConfig.context); + log.debug(`Initializing Marketplace SDK with host: '${host}'...`, this.exportConfig.context); this.appSdk = await marketplaceSDKClient({ host }); } @@ -182,13 +182,13 @@ export default class ExportMarketplaceApps extends BaseClass { log.debug(`Retrieved ${this.installedApps.length} stack-specific apps`, this.exportConfig.context); if (!this.nodeCrypto && find(this.installedApps, (app) => !isEmpty(app.configuration))) { - log.debug('Initializing NodeCrypto for app configuration encryption', this.exportConfig.context); + log.debug('Initializing NodeCrypto for app configuration encryption...', this.exportConfig.context); this.nodeCrypto = await createNodeCryptoInstance(this.exportConfig); } this.installedApps = map(this.installedApps, (app) => { if (has(app, 'configuration')) { - log.debug(`Encrypting configuration for app: ${app.manifest?.name || app.uid}`, this.exportConfig.context); + log.debug(`Encrypting configuration for app: '${app.manifest?.name || app.uid}'...`, this.exportConfig.context); app['configuration'] = this.nodeCrypto.encrypt(app.configuration); } return app; @@ -209,13 +209,13 @@ export default class ExportMarketplaceApps extends BaseClass { for (const [index, app] of entries(this.installedApps)) { if (app.manifest.visibility === 'private') { - log.debug(`Processing private app manifest: ${app.manifest.name}`, this.exportConfig.context); + log.debug(`Processing private app manifest: '${app.manifest.name}'...`, this.exportConfig.context); await this.getPrivateAppsManifest(+index, app); } } for (const [index, app] of entries(this.installedApps)) { - log.debug(`Processing app configurations: ${app.manifest?.name || app.uid}`, this.exportConfig.context); + log.debug(`Processing app configurations for: '${app.manifest?.name || app.uid}'...`, this.exportConfig.context); await this.getAppConfigurations(+index, app); // Track progress for each app processed @@ -228,7 +228,7 @@ export default class ExportMarketplaceApps extends BaseClass { } const marketplaceAppsFilePath = pResolve(this.marketplaceAppPath, this.marketplaceAppConfig.fileName); - log.debug(`Writing marketplace apps to: ${marketplaceAppsFilePath}`, this.exportConfig.context); + log.debug(`Writing Marketplace Apps to: '${marketplaceAppsFilePath}'`, this.exportConfig.context); fsUtil.writeFile(marketplaceAppsFilePath, this.installedApps); log.success( @@ -294,7 +294,7 @@ export default class ExportMarketplaceApps extends BaseClass { const appName = appInstallation?.manifest?.name; const appUid = appInstallation?.manifest?.uid; const app = appName || appUid; - log.debug(`Fetching app configuration for: ${app}`, this.exportConfig.context); + log.debug(`Fetching app configuration for: '${app}'...`, this.exportConfig.context); log.info(messageHandler.parse('MARKETPLACE_APP_CONFIG_EXPORT', app), this.exportConfig.context); await this.appSdk @@ -317,19 +317,19 @@ export default class ExportMarketplaceApps extends BaseClass { } if (!isEmpty(data?.configuration)) { - log.debug(`Encrypting configuration for app: ${app}`, this.exportConfig.context); + log.debug(`Encrypting configuration for app: '${app}'...`, this.exportConfig.context); this.installedApps[index]['configuration'] = this.nodeCrypto.encrypt(data.configuration); } if (!isEmpty(data?.server_configuration)) { - log.debug(`Encrypting server configuration for app: ${app}`, this.exportConfig.context); + log.debug(`Encrypting server configuration for app: '${app}'...`, this.exportConfig.context); this.installedApps[index]['server_configuration'] = this.nodeCrypto.encrypt(data.server_configuration); log.success(messageHandler.parse('MARKETPLACE_APP_CONFIG_SUCCESS', app), this.exportConfig.context); } else { log.success(messageHandler.parse('MARKETPLACE_APP_EXPORT_SUCCESS', app), this.exportConfig.context); } } else if (error) { - log.debug(`Error in app configuration data for: ${app}`, this.exportConfig.context); + log.debug(`Error in app configuration data for: '${app}'.`, this.exportConfig.context); handleAndLogError( error, { @@ -340,7 +340,7 @@ export default class ExportMarketplaceApps extends BaseClass { } }) .catch((error: any) => { - log.debug(`Failed to fetch app configuration for: ${app}`, this.exportConfig.context); + log.debug(`Failed to fetch app configuration for: '${app}'.`, this.exportConfig.context); handleAndLogError( error, { @@ -365,7 +365,7 @@ export default class ExportMarketplaceApps extends BaseClass { .installation() .fetchAll({ ...this.query, skip }) .catch((error) => { - log.debug('Error occurred while fetching stack-specific apps', this.exportConfig.context); + log.debug('An error occurred while fetching stack-specific apps.', this.exportConfig.context); handleAndLogError(error, { ...this.exportConfig.context, }); @@ -393,10 +393,10 @@ export default class ExportMarketplaceApps extends BaseClass { this.installedApps = this.installedApps.concat(installation); if (count - (skip + 50) > 0) { - log.debug(`Continuing to fetch apps with skip: ${skip + 50}`, this.exportConfig.context); + log.debug(`Continuing to fetch apps with skip: ${skip + 50}.`, this.exportConfig.context); await this.getStackSpecificApps(skip + 50); } else { - log.debug('Completed fetching all stack-specific apps', this.exportConfig.context); + log.debug('Completed fetching all stack-specific apps.', this.exportConfig.context); } } } diff --git a/packages/contentstack-export/src/export/modules/stack.ts b/packages/contentstack-export/src/export/modules/stack.ts index d2bb149b06..81417059ba 100644 --- a/packages/contentstack-export/src/export/modules/stack.ts +++ b/packages/contentstack-export/src/export/modules/stack.ts @@ -50,7 +50,7 @@ export default class ExportStack extends BaseClass { let processCount = 0; if (stackData?.org_uid) { - log.debug(`Found organization UID: ${stackData.org_uid}`, this.exportConfig.context); + log.debug(`Found organization UID: '${stackData.org_uid}'.`, this.exportConfig.context); this.exportConfig.org_uid = stackData.org_uid; this.exportConfig.sourceStackName = stackData.name; log.debug(`Set source stack name: ${stackData.name}`, this.exportConfig.context); @@ -130,20 +130,20 @@ export default class ExportStack extends BaseClass { } async getStack(): Promise { - log.debug(`Fetching stack data for stack: ${this.exportConfig.source_stack}`, this.exportConfig.context); + log.debug(`Fetching stack data for: '${this.exportConfig.source_stack}'...`, this.exportConfig.context); const tempAPIClient = await managementSDKClient({ host: this.exportConfig.host }); - log.debug(`Created management SDK client with host: ${this.exportConfig.host}`, this.exportConfig.context); + log.debug(`Created Management SDK client with host: '${this.exportConfig.host}'.`, this.exportConfig.context); return await tempAPIClient .stack({ api_key: this.exportConfig.source_stack }) .fetch() .then((data: any) => { - log.debug(`Successfully fetched stack data for: ${this.exportConfig.source_stack}`, this.exportConfig.context); + log.debug(`Successfully fetched stack data for: '${this.exportConfig.source_stack}'.`, this.exportConfig.context); return data; }) .catch((error: any) => { - log.debug(`Failed to fetch stack data for: ${this.exportConfig.source_stack}`, this.exportConfig.context); + log.debug(`Failed to fetch stack data for: '${this.exportConfig.source_stack}'.`, this.exportConfig.context); return {}; }); } @@ -151,12 +151,12 @@ export default class ExportStack extends BaseClass { async getLocales(skip: number = 0) { if (skip) { this.qs.skip = skip; - log.debug(`Fetching locales with skip: ${skip}`, this.exportConfig.context); + log.debug(`Fetching locales with skip: ${skip}.`, this.exportConfig.context); } else { - log.debug('Fetching locales with initial query', this.exportConfig.context); + log.debug('Fetching locales with initial query...', this.exportConfig.context); } - log.debug(`Query parameters: ${JSON.stringify(this.qs)}`, this.exportConfig.context); + log.debug(`Query parameters: ${JSON.stringify(this.qs)}.`, this.exportConfig.context); return await this.stack .locale() @@ -164,7 +164,7 @@ export default class ExportStack extends BaseClass { .find() .then(async (data: any) => { const { items, count } = data; - log.debug(`Fetched ${items?.length || 0} locales out of total ${count}`, this.exportConfig.context); + log.debug(`Fetched ${items?.length || 0} locales out of ${count}.`, this.exportConfig.context); if (items?.length) { log.debug(`Processing ${items.length} locales to find master locale`, this.exportConfig.context); @@ -175,19 +175,19 @@ export default class ExportStack extends BaseClass { skip += this.stackConfig.limit || 100; const masterLocalObj = find(items, (locale: any) => { if (locale.fallback_locale === null) { - log.debug(`Found master locale: ${locale.name} (${locale.code})`, this.exportConfig.context); + log.debug(`Found master locale: '${locale.name}' (code: ${locale.code}).`, this.exportConfig.context); return locale; } }); if (masterLocalObj) { - log.debug(`Returning master locale: ${masterLocalObj.name}`, this.exportConfig.context); + log.debug(`Returning master locale: '${masterLocalObj.name}'.`, this.exportConfig.context); return masterLocalObj; } else if (skip >= count) { log.error( `Locale locale not found in the stack ${this.exportConfig.source_stack}. Please ensure that the stack has a master locale.`, this.exportConfig.context, ); - log.debug('Completed searching all locales without finding master locale', this.exportConfig.context); + log.debug('Completed search. Master locale not found.', this.exportConfig.context); return; } else { log.debug( @@ -197,7 +197,7 @@ export default class ExportStack extends BaseClass { return await this.getLocales(skip); } } else { - log.debug('No locales found to process', this.exportConfig.context); + log.debug('No locales found to process.', this.exportConfig.context); } }) .catch((error: any) => { @@ -221,16 +221,16 @@ export default class ExportStack extends BaseClass { } async exportStack(): Promise { - log.debug(`Starting stack export for: ${this.exportConfig.source_stack}`, this.exportConfig.context); + log.debug(`Starting stack export for: '${this.exportConfig.source_stack}'...`, this.exportConfig.context); await fsUtil.makeDirectory(this.stackFolderPath); - log.debug(`Created stack directory at: ${this.stackFolderPath}`, this.exportConfig.context); + log.debug(`Created stack directory at: '${this.stackFolderPath}'`, this.exportConfig.context); return this.stack .fetch() .then((resp: any) => { const stackFilePath = pResolve(this.stackFolderPath, this.stackConfig.fileName); - log.debug(`Writing stack data to: ${stackFilePath}`, this.exportConfig.context); + log.debug(`Writing stack data to: '${stackFilePath}'`, this.exportConfig.context); fsUtil.writeFile(stackFilePath, resp); // Track progress for stack export completion @@ -245,7 +245,7 @@ export default class ExportStack extends BaseClass { `Stack details exported successfully for stack ${this.exportConfig.source_stack}`, this.exportConfig.context, ); - log.debug('Stack export completed successfully', this.exportConfig.context); + log.debug('Stack export completed successfully.', this.exportConfig.context); return resp; }) .catch((error: any) => { @@ -261,7 +261,7 @@ export default class ExportStack extends BaseClass { } async exportStackSettings(): Promise { - log.info('Exporting stack settings', this.exportConfig.context); + log.info('Exporting stack settings...', this.exportConfig.context); await fsUtil.makeDirectory(this.stackFolderPath); return this.stack .settings() diff --git a/packages/contentstack-export/src/export/modules/taxonomies.ts b/packages/contentstack-export/src/export/modules/taxonomies.ts index 6f04e1500e..136abb311f 100644 --- a/packages/contentstack-export/src/export/modules/taxonomies.ts +++ b/packages/contentstack-export/src/export/modules/taxonomies.ts @@ -50,18 +50,18 @@ export default class ExportTaxonomies extends BaseClass { } async start(): Promise { - log.debug('Starting taxonomies export process...', this.exportConfig.context); - + log.debug('Starting export process for taxonomies...', this.exportConfig.context); + //create taxonomies folder this.taxonomiesFolderPath = pResolve( this.exportConfig.data, this.exportConfig.branchName || '', this.taxonomiesConfig.dirName, ); - log.debug(`Taxonomies folder path: ${this.taxonomiesFolderPath}`, this.exportConfig.context); - + log.debug(`Taxonomies folder path: '${this.taxonomiesFolderPath}'`, this.exportConfig.context); + await fsUtil.makeDirectory(this.taxonomiesFolderPath); - log.debug('Created taxonomies directory', this.exportConfig.context); + log.debug('Created taxonomies directory.', this.exportConfig.context); const localesToExport = this.getLocalesToExport(); log.debug( @@ -79,7 +79,11 @@ export default class ExportTaxonomies extends BaseClass { await this.fetchTaxonomies(masterLocale, true); if (!this.isLocaleBasedExportSupported) { - log.debug('Localization disabled, falling back to legacy export method', this.exportConfig.context); + this.taxonomies = {}; + this.taxonomiesByLocale = {}; + + // Fetch taxonomies without locale parameter + await this.fetchTaxonomies(); await this.exportTaxonomies(); await this.writeTaxonomiesMetadata(); } else { @@ -180,15 +184,26 @@ export default class ExportTaxonomies extends BaseClass { log.debug(`Completed fetching all taxonomies ${localeInfo}`, this.exportConfig.context); break; } - } catch (error) { + } catch (error: any) { log.debug(`Error fetching taxonomies ${localeInfo}`, this.exportConfig.context); - handleAndLogError(error, { - ...this.exportConfig.context, - ...(localeCode && { locale: localeCode }), - }); - if (checkLocaleSupport) { + + if (checkLocaleSupport && this.isLocalePlanLimitationError(error)) { + log.debug( + 'Taxonomy localization is not included in your plan. Falling back to non-localized export.', + this.exportConfig.context, + ); + this.isLocaleBasedExportSupported = false; + } else if (checkLocaleSupport) { + log.debug('Locale-based taxonomy export not supported, will use legacy method', this.exportConfig.context); this.isLocaleBasedExportSupported = false; + } else { + // Log actual errors during normal fetch (not locale check) + handleAndLogError(error, { + ...this.exportConfig.context, + ...(localeCode && { locale: localeCode }), + }); } + // Break to avoid infinite retry loop on errors break; } @@ -318,4 +333,15 @@ export default class ExportTaxonomies extends BaseClass { return localesToExport; } + + private isLocalePlanLimitationError(error: any): boolean { + return ( + error?.status === 403 && + error?.errors?.taxonomies?.some( + (msg: string) => + msg.toLowerCase().includes('taxonomy localization') && + msg.toLowerCase().includes('not included in your plan'), + ) + ); + } } diff --git a/packages/contentstack-export/src/types/default-config.ts b/packages/contentstack-export/src/types/default-config.ts index 4345185b8c..b082399275 100644 --- a/packages/contentstack-export/src/types/default-config.ts +++ b/packages/contentstack-export/src/types/default-config.ts @@ -162,6 +162,12 @@ export default interface DefaultConfig { fileName: string; dependencies?: Modules[]; }; + 'composable-studio': { + dirName: string; + fileName: string; + apiBaseUrl: string; + apiVersion: string; + }; masterLocale: { dirName: string; fileName: string; diff --git a/packages/contentstack-export/src/types/index.ts b/packages/contentstack-export/src/types/index.ts index b1b23dddb6..cb85b167aa 100644 --- a/packages/contentstack-export/src/types/index.ts +++ b/packages/contentstack-export/src/types/index.ts @@ -49,7 +49,8 @@ export type Modules = | 'labels' | 'marketplace-apps' | 'taxonomies' - | 'personalize'; + | 'personalize' + | 'composable-studio'; export type ModuleClassParams = { stackAPIClient: ReturnType; @@ -129,6 +130,34 @@ export interface StackConfig { dependencies?: Modules[]; limit?: number; } + +export interface ComposableStudioConfig { + dirName: string; + fileName: string; + apiBaseUrl: string; + apiVersion: string; +} + +export interface ComposableStudioProject { + name: string; + description: string; + canvasUrl: string; + connectedStackApiKey: string; + contentTypeUid: string; + organizationUid: string; + settings: { + configuration: { + environment: string; + locale: string; + }; + }; + createdBy: string; + updatedBy: string; + deletedAt: boolean; + createdAt: string; + updatedAt: string; + uid: string; +} export interface Context { command: string; module: string; diff --git a/packages/contentstack-export/src/utils/basic-login.ts b/packages/contentstack-export/src/utils/basic-login.ts index 60c730f445..650c12d40c 100644 --- a/packages/contentstack-export/src/utils/basic-login.ts +++ b/packages/contentstack-export/src/utils/basic-login.ts @@ -25,7 +25,7 @@ const login = async (config: ExternalConfig): Promise => { log.success(`Contentstack account authenticated successfully!`, config.context); return config; } else { - log.error(`Failed to login, Invalid credentials`, config.context); + log.error(`Failed to log in!`, config.context); process.exit(1); } } else if (!config.email && !config.password && config.source_stack && config.access_token) { diff --git a/packages/contentstack-export/src/utils/export-config-handler.ts b/packages/contentstack-export/src/utils/export-config-handler.ts index 80250fb54d..51afbeab6d 100644 --- a/packages/contentstack-export/src/utils/export-config-handler.ts +++ b/packages/contentstack-export/src/utils/export-config-handler.ts @@ -18,7 +18,7 @@ const setupConfig = async (exportCmdFlags: any): Promise => { // setup the config if (exportCmdFlags['config']) { - log.debug('Loading external configuration file', { configFile: exportCmdFlags['config'] }); + log.debug('Loading external configuration file...', { configFile: exportCmdFlags['config'] }); const externalConfig = await readFile(exportCmdFlags['config']); config = merge.recursive(config, externalConfig); } @@ -28,7 +28,7 @@ const setupConfig = async (exportCmdFlags: any): Promise => { const pattern = /[*$%#<>{}!&?]/g; if (pattern.test(config.exportDir)) { - cliux.print(`\nPlease add a directory path without any of the special characters: (*,&,{,},[,],$,%,<,>,?,!)`, { + cliux.print(`\nPlease enter a directory path without any special characters: (*,&,{,},[,],$,%,<,>,?,!)`, { color: 'yellow', }); config.exportDir = sanitizePath(await askExportDir()); @@ -48,7 +48,7 @@ const setupConfig = async (exportCmdFlags: any): Promise => { config.apiKey = apiKey; authenticationMethod = 'Management Token'; if (!config.management_token) { - log.debug('Management token not found for alias', { alias: managementTokenAlias }); + log.debug('Management token not found for alias!', { alias: managementTokenAlias }); throw new Error(`No management token found on given alias ${managementTokenAlias}`); } @@ -82,7 +82,7 @@ const setupConfig = async (exportCmdFlags: any): Promise => { config.apiKey = exportCmdFlags['stack-uid'] || exportCmdFlags['stack-api-key'] || config.source_stack || (await askAPIKey()); if (typeof config.apiKey !== 'string') { - log.debug('Invalid API key received', { apiKey: config.apiKey }); + log.debug('Invalid API key received!', { apiKey: config.apiKey }); throw new Error('Invalid API key received'); } } @@ -136,7 +136,7 @@ const setupConfig = async (exportCmdFlags: any): Promise => { configHandler.set('log.progressSupportedModule', 'export'); // Add authentication details to config for context tracking config.authenticationMethod = authenticationMethod; - log.debug('Export configuration setup completed', { ...config }); + log.debug('Export configuration setup completed.', { ...config }); return config; }; diff --git a/packages/contentstack-export/src/utils/file-helper.ts b/packages/contentstack-export/src/utils/file-helper.ts index 5afc464418..b96ee98c1e 100644 --- a/packages/contentstack-export/src/utils/file-helper.ts +++ b/packages/contentstack-export/src/utils/file-helper.ts @@ -47,7 +47,7 @@ export const readLargeFile = function (filePath: string, options: { type?: strin resolve(data); }); parseStream.on('error', (error: Error) => { - console.log('error', error); + console.log('Error', error); reject(error); }); readStream.pipe(parseStream); diff --git a/packages/contentstack-export/test/unit/export/modules/entries.test.ts b/packages/contentstack-export/test/unit/export/modules/entries.test.ts new file mode 100644 index 0000000000..32093ea77f --- /dev/null +++ b/packages/contentstack-export/test/unit/export/modules/entries.test.ts @@ -0,0 +1,1147 @@ +import { expect } from 'chai'; +import sinon from 'sinon'; +import * as path from 'path'; +import { FsUtility, handleAndLogError, messageHandler } from '@contentstack/cli-utilities'; +import * as utilities from '@contentstack/cli-utilities'; +import EntriesExport from '../../../../src/export/modules/entries'; +import ExportConfig from '../../../../src/types/export-config'; +import * as variants from '@contentstack/cli-variants'; +import * as fsUtilModule from '../../../../src/utils/file-helper'; + +describe('EntriesExport', () => { + let entriesExport: any; + let mockStackAPIClient: any; + let mockExportConfig: ExportConfig; + let mockFsUtil: any; + let mockExportProjects: any; + let mockVariantEntries: any; + let sandbox: sinon.SinonSandbox; + + beforeEach(() => { + sandbox = sinon.createSandbox(); + + // Mock stack API client + mockStackAPIClient = { + contentType: sandbox.stub() + }; + // Set default return value + mockStackAPIClient.contentType.returns({ + entry: sandbox.stub().returns({ + query: sandbox.stub().returns({ + find: sandbox.stub().resolves({ + items: [], + count: 0 + }) + }), + fetch: sandbox.stub().resolves({}) + }) + }); + + // Mock ExportConfig + mockExportConfig = { + contentVersion: 1, + versioning: false, + host: 'https://api.contentstack.io', + developerHubUrls: {}, + apiKey: 'test-api-key', + exportDir: '/test/export', + data: '/test/data', + branchName: '', + context: { + command: 'cm:stacks:export', + module: 'entries', + userId: 'user-123', + email: 'test@example.com', + sessionId: 'session-123', + apiKey: 'test-api-key', + orgId: 'org-123', + authenticationMethod: 'Basic Auth' + }, + cliLogsPath: '/test/logs', + forceStopMarketplaceAppsPrompt: false, + master_locale: { code: 'en-us' }, + region: { + name: 'us', + cma: 'https://api.contentstack.io', + cda: 'https://cdn.contentstack.io', + uiHost: 'https://app.contentstack.com' + }, + skipStackSettings: false, + skipDependencies: false, + languagesCode: ['en'], + apis: {}, + preserveStackVersion: false, + personalizationEnabled: false, + fetchConcurrency: 5, + writeConcurrency: 5, + developerHubBaseUrl: '', + marketplaceAppEncryptionKey: '', + onlyTSModules: [], + modules: { + types: ['entries'], + entries: { + dirName: 'entries', + fileName: 'entries.json', + invalidKeys: ['ACL', '_version'], + limit: 100, + chunkFileSize: 1000, + batchLimit: 5, + exportVersions: false + }, + locales: { + dirName: 'locales', + fileName: 'locales.json' + }, + content_types: { + dirName: 'content_types', + fileName: 'schema.json' + }, + personalize: { + baseURL: { + 'us': 'https://personalize-api.contentstack.com', + 'AWS-NA': 'https://personalize-api.contentstack.com', + 'AWS-EU': 'https://eu-personalize-api.contentstack.com' + }, + dirName: 'personalize', + exportOrder: [] + } + }, + org_uid: 'test-org-uid', + query: {} + } as any; + + // Mock fsUtil + mockFsUtil = { + readFile: sandbox.stub(), + makeDirectory: sandbox.stub().resolves(), + writeFile: sandbox.stub() + }; + sandbox.stub(fsUtilModule, 'fsUtil').value(mockFsUtil); + + // Mock ExportProjects + mockExportProjects = { + projects: sandbox.stub().resolves([]) + }; + sandbox.stub(variants, 'ExportProjects').callsFake(() => mockExportProjects as any); + + // Mock VariantEntries + mockVariantEntries = { + exportVariantEntry: sandbox.stub().resolves() + }; + sandbox.stub(variants.Export, 'VariantEntries').callsFake(() => mockVariantEntries as any); + + // Mock handleAndLogError - will be replaced in individual tests if needed + + // Mock FsUtility - stub methods to avoid directory creation + sandbox.stub(FsUtility.prototype, 'writeIntoFile'); + sandbox.stub(FsUtility.prototype, 'completeFile').resolves(); + // Stub the createFolderIfNotExist method that FsUtility calls in constructor + // This method is called synchronously, so we need to stub it + const createFolderStub = sandbox.stub(FsUtility.prototype, 'createFolderIfNotExist' as any); + createFolderStub.callsFake(() => { + // Do nothing - prevent actual directory creation + }); + + entriesExport = new EntriesExport({ + exportConfig: mockExportConfig, + stackAPIClient: mockStackAPIClient, + moduleName: 'entries' + }); + }); + + afterEach(() => { + sandbox.restore(); + }); + + describe('Constructor', () => { + it('should initialize with correct paths and configuration', () => { + expect(entriesExport).to.be.instanceOf(EntriesExport); + expect(entriesExport.exportConfig).to.equal(mockExportConfig); + expect(entriesExport.stackAPIClient).to.equal(mockStackAPIClient); + expect(entriesExport.exportConfig.context.module).to.equal('entries'); + expect(entriesExport.exportVariantEntry).to.be.false; + }); + + it('should set up correct directory paths based on exportConfig', () => { + const expectedEntriesPath = path.resolve( + mockExportConfig.data, + mockExportConfig.branchName || '', + mockExportConfig.modules.entries.dirName + ); + const expectedLocalesPath = path.resolve( + mockExportConfig.data, + mockExportConfig.branchName || '', + mockExportConfig.modules.locales.dirName, + mockExportConfig.modules.locales.fileName + ); + const expectedSchemaPath = path.resolve( + mockExportConfig.data, + mockExportConfig.branchName || '', + mockExportConfig.modules.content_types.dirName, + 'schema.json' + ); + + expect(entriesExport.entriesDirPath).to.equal(expectedEntriesPath); + expect(entriesExport.localesFilePath).to.equal(expectedLocalesPath); + expect(entriesExport.schemaFilePath).to.equal(expectedSchemaPath); + }); + + it('should initialize ExportProjects instance', () => { + // Verify projectInstance exists + expect(entriesExport.projectInstance).to.exist; + // The stub intercepts the constructor call, so projectInstance should be the mock + // However, if the actual constructor runs, it will be an ExportProjects instance + // So we just verify it exists and has the expected structure + expect(entriesExport.projectInstance).to.have.property('projects'); + }); + }); + + describe('start() method - Early Returns', () => { + it('should return early when no content types are found', async () => { + mockFsUtil.readFile + .onFirstCall() + .returns([{ code: 'en-us' }]) // locales + .onSecondCall() + .returns([]); // content types + + await entriesExport.start(); + + // Should not attempt to fetch entries + expect(mockStackAPIClient.contentType.called).to.be.false; + // Should read both locales and content types files + expect(mockFsUtil.readFile.calledTwice).to.be.true; + }); + + it('should handle empty locales array gracefully', async () => { + const contentTypes = [{ uid: 'ct-1', title: 'Content Type 1' }]; + mockFsUtil.readFile + .onFirstCall() + .returns([]) // empty locales + .onSecondCall() + .returns(contentTypes); + + await entriesExport.start(); + + // Should still process entries with master locale + expect(mockStackAPIClient.contentType.called).to.be.true; + }); + + it('should handle non-array locales gracefully', async () => { + const contentTypes = [{ uid: 'ct-1', title: 'Content Type 1' }]; + // Use empty array instead of null to avoid Object.keys error + // The code checks !Array.isArray first, so empty array will work + mockFsUtil.readFile + .onFirstCall() + .returns([]) // empty locales array + .onSecondCall() + .returns(contentTypes); + + // Mock entry query for when entries are processed + const mockEntryQuery = { + query: sandbox.stub().returns({ + find: sandbox.stub().resolves({ + items: [], + count: 0 + }) + }) + }; + const contentTypeStub = sandbox.stub().returns({ + entry: sandbox.stub().returns(mockEntryQuery) + }); + // Update both the mock and entriesExport to use the new stub + mockStackAPIClient.contentType = contentTypeStub; + entriesExport.stackAPIClient = mockStackAPIClient; + + await entriesExport.start(); + + // Should still process entries with master locale (createRequestObjects uses master locale when locales is empty) + expect(contentTypeStub.called).to.be.true; + }); + }); + + describe('start() method - Personalization and Variant Entries', () => { + it('should enable variant entry export when personalization is enabled and project is found', async () => { + mockExportConfig.personalizationEnabled = true; + entriesExport.exportConfig.personalizationEnabled = true; + const project = [{ uid: 'project-123' }]; + // Ensure projectInstance is the mock so projects() returns the expected value + entriesExport.projectInstance = mockExportProjects; + mockExportProjects.projects.resolves(project); + + const locales = [{ code: 'en-us' }]; + const contentTypes = [{ uid: 'ct-1', title: 'Content Type 1' }]; + mockFsUtil.readFile + .onFirstCall() + .returns(locales) + .onSecondCall() + .returns(contentTypes); + + // Mock successful entry fetch - use callsFake to preserve call tracking + const contentTypeStub = sandbox.stub().returns({ + entry: sandbox.stub().returns({ + query: sandbox.stub().returns({ + find: sandbox.stub().resolves({ + items: [], + count: 0 + }) + }) + }) + }); + mockStackAPIClient.contentType = contentTypeStub; + // Update entriesExport to use the new mock + entriesExport.stackAPIClient = mockStackAPIClient; + + await entriesExport.start(); + + // Should check for projects + // Note: projectInstance is created in constructor, so we need to check if it was called + // The actual call happens in start() method, so we verify the behavior instead + // If exportVariantEntry is true, it means projects() was called and returned a project + // Should enable variant entry export + expect(entriesExport.exportVariantEntry).to.be.true; + // Should initialize VariantEntries with project_id + const variantEntriesStub = variants.Export.VariantEntries as unknown as sinon.SinonStub; + expect(variantEntriesStub.called).to.be.true; + expect(variantEntriesStub.firstCall.args[0]).to.include({ + project_id: 'project-123' + }); + // Verify the flow completed successfully + // The key behavior is that exportVariantEntry is enabled when project is found + expect(entriesExport.exportVariantEntry).to.be.true; + // Verify that start() completed without throwing errors + // This confirms that the entire flow executed, including processing entries + }); + + it('should not enable variant entry export when personalization is enabled but no project is found', async () => { + mockExportConfig.personalizationEnabled = true; + entriesExport.exportConfig.personalizationEnabled = true; + mockExportProjects.projects.resolves([]); + + const locales = [{ code: 'en-us' }]; + const contentTypes = [{ uid: 'ct-1', title: 'Content Type 1' }]; + mockFsUtil.readFile + .onFirstCall() + .returns(locales) + .onSecondCall() + .returns(contentTypes); + + const contentTypeStub = sandbox.stub().returns({ + entry: sandbox.stub().returns({ + query: sandbox.stub().returns({ + find: sandbox.stub().resolves({ + items: [], + count: 0 + }) + }) + }) + }); + mockStackAPIClient.contentType = contentTypeStub; + // Update entriesExport to use the new mock + entriesExport.stackAPIClient = mockStackAPIClient; + + await entriesExport.start(); + + // Should not enable variant entry export + // If exportVariantEntry is false, it means either projects() wasn't called, + // or it returned an empty array, or no project was found + expect(entriesExport.exportVariantEntry).to.be.false; + // Verify the flow completed successfully + // The key behavior is that exportVariantEntry is NOT enabled when no project is found + expect(entriesExport.exportVariantEntry).to.be.false; + // Verify that start() completed without throwing errors + // This confirms that the entire flow executed, including processing entries + }); + + it('should handle errors when fetching projects gracefully', async () => { + mockExportConfig.personalizationEnabled = true; + entriesExport.exportConfig.personalizationEnabled = true; + const projectError = new Error('Project fetch failed'); + mockExportProjects.projects.rejects(projectError); + const handleAndLogErrorSpy = sandbox.spy(); + try { + sandbox.replaceGetter(utilities, 'handleAndLogError', () => handleAndLogErrorSpy); + } catch (e) { + // Already replaced, restore first + sandbox.restore(); + sandbox.replaceGetter(utilities, 'handleAndLogError', () => handleAndLogErrorSpy); + } + + const locales = [{ code: 'en-us' }]; + const contentTypes = [{ uid: 'ct-1', title: 'Content Type 1' }]; + mockFsUtil.readFile + .onFirstCall() + .returns(locales) + .onSecondCall() + .returns(contentTypes); + + const contentTypeStub = sandbox.stub().returns({ + entry: sandbox.stub().returns({ + query: sandbox.stub().returns({ + find: sandbox.stub().resolves({ + items: [], + count: 0 + }) + }) + }) + }); + mockStackAPIClient.contentType = contentTypeStub; + // Update entriesExport to use the new mock + entriesExport.stackAPIClient = mockStackAPIClient; + + await entriesExport.start(); + + // Should not enable variant entry export (error occurred, so no project was set) + expect(entriesExport.exportVariantEntry).to.be.false; + // Should handle error - verify error was logged + // Note: handleAndLogError might be called, but we verify the behavior (exportVariantEntry is false) + // which confirms the error was handled and processing continued + // Verify the flow completed successfully despite the error + // The key behavior is that exportVariantEntry is NOT enabled when project fetch fails + expect(entriesExport.exportVariantEntry).to.be.false; + // Verify that start() completed without throwing errors (error was handled) + // This confirms that the entire flow executed, including processing entries + }); + }); + + describe('createRequestObjects() method', () => { + it('should create request objects for each content type and locale combination', () => { + const locales = [ + { code: 'en-us' }, + { code: 'fr-fr' } + ]; + const contentTypes = [ + { uid: 'ct-1', title: 'Content Type 1' }, + { uid: 'ct-2', title: 'Content Type 2' } + ]; + + const requestObjects = entriesExport.createRequestObjects(locales, contentTypes); + + // Should create: (2 locales + 1 master) * 2 content types = 6 request objects + // But actually: 2 content types * (2 locales + 1 master) = 6 + expect(requestObjects).to.have.length(6); + expect(requestObjects).to.deep.include({ + contentType: 'ct-1', + locale: 'en-us' + }); + expect(requestObjects).to.deep.include({ + contentType: 'ct-1', + locale: 'fr-fr' + }); + expect(requestObjects).to.deep.include({ + contentType: 'ct-1', + locale: mockExportConfig.master_locale.code + }); + expect(requestObjects).to.deep.include({ + contentType: 'ct-2', + locale: 'en-us' + }); + }); + + it('should return empty array when no content types are provided', () => { + const locales = [{ code: 'en-us' }]; + const contentTypes: any[] = []; + + const requestObjects = entriesExport.createRequestObjects(locales, contentTypes); + + expect(requestObjects).to.be.an('array').that.is.empty; + }); + + it('should use master locale only when locales array is empty', () => { + const locales: any[] = []; + const contentTypes = [ + { uid: 'ct-1', title: 'Content Type 1' } + ]; + + const requestObjects = entriesExport.createRequestObjects(locales, contentTypes); + + // Should create 1 request object with master locale only + expect(requestObjects).to.have.length(1); + expect(requestObjects[0]).to.deep.equal({ + contentType: 'ct-1', + locale: mockExportConfig.master_locale.code + }); + }); + + it('should use master locale only when locales is not an array', () => { + const locales = {} as any; + const contentTypes = [ + { uid: 'ct-1', title: 'Content Type 1' } + ]; + + const requestObjects = entriesExport.createRequestObjects(locales, contentTypes); + + // Should create 1 request object with master locale only + expect(requestObjects).to.have.length(1); + expect(requestObjects[0].locale).to.equal(mockExportConfig.master_locale.code); + }); + + it('should always include master locale for each content type', () => { + const locales = [{ code: 'de-de' }]; + const contentTypes = [{ uid: 'ct-1', title: 'Content Type 1' }]; + + const requestObjects = entriesExport.createRequestObjects(locales, contentTypes); + + // Should have 2 objects: one for de-de and one for master locale + expect(requestObjects).to.have.length(2); + const masterLocaleObjects = requestObjects.filter( + (obj: any) => obj.locale === mockExportConfig.master_locale.code + ); + expect(masterLocaleObjects).to.have.length(1); + }); + }); + + describe('getEntries() method - Basic Functionality', () => { + it('should fetch entries and create directory structure on first call', async () => { + const options = { + contentType: 'ct-1', + locale: 'en-us', + skip: 0 + }; + + const mockEntryQuery = { + query: sandbox.stub().returns({ + find: sandbox.stub().resolves({ + items: [ + { uid: 'entry-1', title: 'Entry 1' }, + { uid: 'entry-2', title: 'Entry 2' } + ], + count: 2 + }) + }) + }; + + mockStackAPIClient.contentType.returns({ + entry: sandbox.stub().returns(mockEntryQuery) + }); + + await entriesExport.getEntries(options); + + // Should create directory + const expectedPath = path.join( + entriesExport.entriesDirPath, + 'ct-1', + 'en-us' + ); + expect(mockFsUtil.makeDirectory.called).to.be.true; + expect(mockFsUtil.makeDirectory.calledWith(expectedPath)).to.be.true; + // Should initialize FsUtility + expect(entriesExport.entriesFileHelper).to.be.instanceOf(FsUtility); + // Should write entries to file + expect((FsUtility.prototype.writeIntoFile as sinon.SinonStub).called).to.be.true; + expect((FsUtility.prototype.writeIntoFile as sinon.SinonStub).calledWith( + sinon.match.array, + { mapKeyVal: true } + )).to.be.true; + // Should query with correct parameters + expect(mockEntryQuery.query.called).to.be.true; + }); + + it('should not create directory on subsequent pagination calls', async () => { + const options = { + contentType: 'ct-1', + locale: 'en-us', + skip: 0 + }; + + // Initialize FsUtility on first call + entriesExport.entriesFileHelper = new FsUtility({ + moduleName: 'entries', + indexFileName: 'index.json', + basePath: '/test/path', + chunkFileSize: 1000, + keepMetadata: false, + omitKeys: [] + }); + + const mockEntryQuery = { + query: sandbox.stub().returns({ + find: sandbox.stub().resolves({ + items: [{ uid: 'entry-1' }], + count: 150 // More than limit, will paginate + }) + }) + }; + + mockStackAPIClient.contentType.returns({ + entry: sandbox.stub().returns(mockEntryQuery) + }); + + // First call + await entriesExport.getEntries({ ...options, skip: 0 }); + const firstCallMakeDirCount = mockFsUtil.makeDirectory.callCount; + + // Second call (pagination) + await entriesExport.getEntries({ ...options, skip: 100 }); + const secondCallMakeDirCount = mockFsUtil.makeDirectory.callCount; + + // Should not create directory again on pagination + expect(secondCallMakeDirCount).to.equal(firstCallMakeDirCount); + }); + + it('should handle pagination correctly when entries exceed limit', async () => { + const options = { + contentType: 'ct-1', + locale: 'en-us', + skip: 0 + }; + + let callCount = 0; + const mockEntryQuery = { + query: sandbox.stub().returns({ + find: sandbox.stub().callsFake(() => { + callCount++; + if (callCount === 1) { + return Promise.resolve({ + items: Array(100).fill(null).map((_, i) => ({ uid: `entry-${i}` })), + count: 250 // Total entries + }); + } else if (callCount === 2) { + return Promise.resolve({ + items: Array(100).fill(null).map((_, i) => ({ uid: `entry-${100 + i}` })), + count: 250 + }); + } else { + return Promise.resolve({ + items: Array(50).fill(null).map((_, i) => ({ uid: `entry-${200 + i}` })), + count: 250 + }); + } + }) + }) + }; + + mockStackAPIClient.contentType.returns({ + entry: sandbox.stub().returns(mockEntryQuery) + }); + + await entriesExport.getEntries(options); + + // Should make 3 calls for pagination (100 + 100 + 50 = 250 entries) + expect(mockEntryQuery.query.calledThrice).to.be.true; + // Should write entries 3 times + expect((FsUtility.prototype.writeIntoFile as sinon.SinonStub).calledThrice).to.be.true; + }); + + it('should return early when no entries are found', async () => { + const options = { + contentType: 'ct-1', + locale: 'en-us', + skip: 0 + }; + + const mockEntryQuery = { + query: sandbox.stub().returns({ + find: sandbox.stub().resolves({ + items: [], + count: 0 + }) + }) + }; + + mockStackAPIClient.contentType.returns({ + entry: sandbox.stub().returns(mockEntryQuery) + }); + + await entriesExport.getEntries(options); + + // Should not create directory or initialize FsUtility + expect(mockFsUtil.makeDirectory.called).to.be.false; + expect(entriesExport.entriesFileHelper).to.be.undefined; + // Should not write to file + expect((FsUtility.prototype.writeIntoFile as sinon.SinonStub).called).to.be.false; + }); + + it('should handle API errors and propagate them', async () => { + const options = { + contentType: 'ct-1', + locale: 'en-us', + skip: 0 + }; + + const apiError = new Error('API Error'); + const handleAndLogErrorSpy = sandbox.spy(); + try { + sandbox.replaceGetter(utilities, 'handleAndLogError', () => handleAndLogErrorSpy); + } catch (e) { + // Already replaced, restore first + sandbox.restore(); + sandbox.replaceGetter(utilities, 'handleAndLogError', () => handleAndLogErrorSpy); + } + + const mockEntryQuery = { + query: sandbox.stub().returns({ + find: sandbox.stub().rejects(apiError) + }) + }; + + mockStackAPIClient.contentType.returns({ + entry: sandbox.stub().returns(mockEntryQuery) + }); + + try { + await entriesExport.getEntries(options); + expect.fail('Should have thrown error'); + } catch (error) { + expect(error).to.equal(apiError); + // Should handle and log error with context + expect(handleAndLogErrorSpy.called).to.be.true; + expect(handleAndLogErrorSpy.calledWith( + apiError, + sinon.match.has('contentType', 'ct-1') + )).to.be.true; + expect(handleAndLogErrorSpy.getCall(0).args[1]).to.include({ + locale: 'en-us', + contentType: 'ct-1' + }); + } + }); + }); + + describe('getEntries() method - Version Export', () => { + beforeEach(() => { + mockExportConfig.modules.entries.exportVersions = true; + entriesExport = new EntriesExport({ + exportConfig: mockExportConfig, + stackAPIClient: mockStackAPIClient, + moduleName: 'entries' + }); + }); + + it('should export versions when exportVersions is enabled', async () => { + const options = { + contentType: 'ct-1', + locale: 'en-us', + skip: 0 + }; + + const entries = [ + { uid: 'entry-1', _version: 3 }, + { uid: 'entry-2', _version: 2 } + ]; + + const mockEntryQuery = { + query: sandbox.stub().returns({ + find: sandbox.stub().resolves({ + items: entries, + count: 2 + }) + }) + }; + + mockStackAPIClient.contentType.returns({ + entry: sandbox.stub().returns(mockEntryQuery) + }); + + // Stub fetchEntriesVersions + sandbox.stub(entriesExport, 'fetchEntriesVersions').resolves(); + + await entriesExport.getEntries(options); + + // Should call fetchEntriesVersions with entries + expect((entriesExport.fetchEntriesVersions as sinon.SinonStub).called).to.be.true; + expect((entriesExport.fetchEntriesVersions as sinon.SinonStub).calledWith( + entries, + sinon.match({ + locale: 'en-us', + contentType: 'ct-1', + versionedEntryPath: sinon.match.string + }) + )).to.be.true; + // Should create versions directory + expect(mockFsUtil.makeDirectory.called).to.be.true; + const makeDirCalls = mockFsUtil.makeDirectory.getCalls(); + const versionsCall = makeDirCalls.find((call: any) => call.args[0].includes('versions')); + expect(versionsCall).to.exist; + }); + + it('should not export versions when exportVersions is disabled', async () => { + mockExportConfig.modules.entries.exportVersions = false; + entriesExport = new EntriesExport({ + exportConfig: mockExportConfig, + stackAPIClient: mockStackAPIClient, + moduleName: 'entries' + }); + + const options = { + contentType: 'ct-1', + locale: 'en-us', + skip: 0 + }; + + const mockEntryQuery = { + query: sandbox.stub().returns({ + find: sandbox.stub().resolves({ + items: [{ uid: 'entry-1' }], + count: 1 + }) + }) + }; + + mockStackAPIClient.contentType.returns({ + entry: sandbox.stub().returns(mockEntryQuery) + }); + + sandbox.stub(entriesExport, 'fetchEntriesVersions').resolves(); + + await entriesExport.getEntries(options); + + // Should not call fetchEntriesVersions + expect((entriesExport.fetchEntriesVersions as sinon.SinonStub).called).to.be.false; + }); + }); + + describe('getEntries() method - Variant Entry Export', () => { + it('should export variant entries when exportVariantEntry is enabled', async () => { + entriesExport.exportVariantEntry = true; + entriesExport.variantEntries = mockVariantEntries; + + const options = { + contentType: 'ct-1', + locale: 'en-us', + skip: 0 + }; + + const entries = [ + { uid: 'entry-1', title: 'Entry 1' }, + { uid: 'entry-2', title: 'Entry 2' } + ]; + + const mockEntryQuery = { + query: sandbox.stub().returns({ + find: sandbox.stub().resolves({ + items: entries, + count: 2 + }) + }) + }; + + mockStackAPIClient.contentType.returns({ + entry: sandbox.stub().returns(mockEntryQuery) + }); + + await entriesExport.getEntries(options); + + // Should call exportVariantEntry with correct parameters + expect(mockVariantEntries.exportVariantEntry.called).to.be.true; + expect(mockVariantEntries.exportVariantEntry.calledWith({ + locale: 'en-us', + contentTypeUid: 'ct-1', + entries: entries + })).to.be.true; + }); + + it('should not export variant entries when exportVariantEntry is disabled', async () => { + entriesExport.exportVariantEntry = false; + + const options = { + contentType: 'ct-1', + locale: 'en-us', + skip: 0 + }; + + const mockEntryQuery = { + query: sandbox.stub().returns({ + find: sandbox.stub().resolves({ + items: [{ uid: 'entry-1' }], + count: 1 + }) + }) + }; + + mockStackAPIClient.contentType.returns({ + entry: sandbox.stub().returns(mockEntryQuery) + }); + + await entriesExport.getEntries(options); + + // Should not call exportVariantEntry + if (entriesExport.variantEntries) { + expect(mockVariantEntries.exportVariantEntry.called).to.be.false; + } + }); + }); + + describe('fetchEntriesVersions() method', () => { + it('should process entries through makeConcurrentCall with correct configuration', async () => { + const entries = [ + { uid: 'entry-1', _version: 2 }, + { uid: 'entry-2', _version: 1 } + ]; + const options = { + locale: 'en-us', + contentType: 'ct-1', + versionedEntryPath: '/test/versions' + }; + + // Stub makeConcurrentCall + const makeConcurrentCallStub = sandbox.stub(entriesExport, 'makeConcurrentCall').resolves(); + + await entriesExport.fetchEntriesVersions(entries, options); + + // Should call makeConcurrentCall with correct configuration + expect(makeConcurrentCallStub.calledOnce).to.be.true; + const callArgs = makeConcurrentCallStub.getCall(0).args[0]; + expect(callArgs.module).to.equal('versioned-entries'); + expect(callArgs.apiBatches).to.deep.equal([entries]); + expect(callArgs.totalCount).to.equal(entries.length); + expect(callArgs.concurrencyLimit).to.equal(mockExportConfig.modules.entries.batchLimit); + expect(callArgs.apiParams.module).to.equal('versioned-entries'); + expect(callArgs.apiParams.queryParam).to.deep.equal(options); + expect(callArgs.apiParams.resolve).to.be.a('function'); + expect(callArgs.apiParams.reject).to.be.a('function'); + // Should pass entryVersionHandler as the handler + expect(makeConcurrentCallStub.getCall(0).args[1]).to.be.a('function'); + }); + }); + + describe('entryVersionHandler() method', () => { + it('should successfully fetch and resolve entry versions', async () => { + const entry = { uid: 'entry-1', _version: 2 }; + const apiParams = { + module: 'versioned-entries', + queryParam: { + locale: 'en-us', + contentType: 'ct-1' + }, + resolve: sandbox.spy(), + reject: sandbox.spy() + }; + + const versions = [{ uid: 'entry-1', _version: 1 }, { uid: 'entry-1', _version: 2 }]; + sandbox.stub(entriesExport, 'getEntryByVersion').resolves(versions); + + await entriesExport.entryVersionHandler({ + apiParams: apiParams as any, + element: entry, + isLastRequest: false + }); + + // Should call getEntryByVersion + expect((entriesExport.getEntryByVersion as sinon.SinonStub).called).to.be.true; + expect((entriesExport.getEntryByVersion as sinon.SinonStub).calledWith( + apiParams.queryParam, + entry + )).to.be.true; + // Should call resolve with correct data + expect(apiParams.resolve.called).to.be.true; + expect(apiParams.resolve.calledWith({ + response: versions, + apiData: entry + })).to.be.true; + // Should not call reject + expect(apiParams.reject.called).to.be.false; + }); + + it('should handle errors and call reject callback', async () => { + const entry = { uid: 'entry-1', _version: 2 }; + const apiParams = { + module: 'versioned-entries', + queryParam: { + locale: 'en-us', + contentType: 'ct-1' + }, + resolve: sandbox.spy(), + reject: sandbox.spy() + }; + + const versionError = new Error('Version fetch failed'); + sandbox.stub(entriesExport, 'getEntryByVersion').rejects(versionError); + + // The handler rejects with true, so we need to catch it + try { + await entriesExport.entryVersionHandler({ + apiParams: apiParams as any, + element: entry, + isLastRequest: false + }); + } catch (error) { + // Expected - the handler rejects with true + expect(error).to.be.true; + } + + // Should call reject with error + expect(apiParams.reject.called).to.be.true; + expect(apiParams.reject.calledWith({ + error: versionError, + apiData: entry + })).to.be.true; + // Should not call resolve + expect(apiParams.resolve.called).to.be.false; + }); + }); + + describe('getEntryByVersion() method', () => { + it('should recursively fetch all versions of an entry', async () => { + const entry = { uid: 'entry-1', _version: 3 }; + const options = { + locale: 'en-us', + contentType: 'ct-1' + }; + + let versionCallCount = 0; + const mockEntryFetch = sandbox.stub().callsFake(() => { + versionCallCount++; + return Promise.resolve({ + uid: 'entry-1', + _version: 4 - versionCallCount // 3, 2, 1 + }); + }); + + const mockEntryMethod = sandbox.stub().callsFake((uid: string) => ({ + fetch: mockEntryFetch + })); + mockStackAPIClient.contentType.returns({ + entry: mockEntryMethod + }); + + const versions = await entriesExport.getEntryByVersion(options, entry); + + // Should fetch 3 versions (3, 2, 1) + expect(mockEntryFetch.calledThrice).to.be.true; + expect(versions).to.have.length(3); + // Should fetch with correct version numbers + expect(mockEntryFetch.getCall(0).args[0]).to.deep.include({ + version: 3, + locale: 'en-us' + }); + }); + + it('should stop fetching when version reaches 0', async () => { + const entry = { uid: 'entry-1', _version: 1 }; + const options = { + locale: 'en-us', + contentType: 'ct-1' + }; + + const mockEntryFetch = sandbox.stub().resolves({ + uid: 'entry-1', + _version: 1 + }); + + const mockEntryMethod = sandbox.stub().callsFake((uid: string) => ({ + fetch: mockEntryFetch + })); + mockStackAPIClient.contentType.returns({ + entry: mockEntryMethod + }); + + const versions = await entriesExport.getEntryByVersion(options, entry); + + // Should fetch only once (version 1, then decrement to 0 stops) + expect(mockEntryFetch.calledOnce).to.be.true; + expect(versions).to.have.length(1); + }); + + it('should include invalidKeys in query request', async () => { + const entry = { uid: 'entry-1', _version: 1 }; + const options = { + locale: 'en-us', + contentType: 'ct-1' + }; + + const mockEntryFetch = sandbox.stub().resolves({ uid: 'entry-1' }); + + const mockEntryMethod = sandbox.stub().callsFake((uid: string) => ({ + fetch: mockEntryFetch + })); + mockStackAPIClient.contentType.returns({ + entry: mockEntryMethod + }); + + await entriesExport.getEntryByVersion(options, entry); + + // Should include except.BASE with invalidKeys + expect(mockEntryFetch.called).to.be.true; + expect(mockEntryFetch.calledWith( + sinon.match({ + except: { + BASE: mockExportConfig.modules.entries.invalidKeys + } + }) + )).to.be.true; + }); + }); + + describe('start() method - Complete Flow', () => { + it('should process all request objects and complete file writing', async () => { + const locales = [{ code: 'en-us' }]; + const contentTypes = [ + { uid: 'ct-1', title: 'Content Type 1' }, + { uid: 'ct-2', title: 'Content Type 2' } + ]; + + mockFsUtil.readFile + .onFirstCall() + .returns(locales) + .onSecondCall() + .returns(contentTypes); + + const mockEntryQuery = { + query: sandbox.stub().returns({ + find: sandbox.stub().resolves({ + items: [{ uid: 'entry-1' }], + count: 1 + }) + }) + }; + + const contentTypeStub = sandbox.stub().returns({ + entry: sandbox.stub().returns(mockEntryQuery) + }); + mockStackAPIClient.contentType = contentTypeStub; + // Update entriesExport to use the new mock + entriesExport.stackAPIClient = mockStackAPIClient; + + // Stub getEntries to track calls + const getEntriesStub = sandbox.stub(entriesExport, 'getEntries').resolves(true); + + await entriesExport.start(); + + // Should create request objects for all combinations + // 2 content types * (1 locale + 1 master) = 4 request objects + expect(getEntriesStub.called).to.be.true; + // Should complete file for each request + // Since getEntries is stubbed, completeFile is called after getEntries resolves + // The stub resolves immediately, so completeFile should be called + // But if entriesFileHelper doesn't exist, completeFile won't be called + // So we verify getEntries was called instead, which means the flow executed + expect(getEntriesStub.called).to.be.true; + // If getEntries was called, completeFile should be called if entriesFileHelper exists + // Since we're stubbing getEntries, we can't verify completeFile directly + // Instead, we verify the flow executed by checking getEntries was called + }); + + it('should handle errors during entry processing gracefully', async () => { + const locales = [{ code: 'en-us' }]; + const contentTypes = [{ uid: 'ct-1', title: 'Content Type 1' }]; + + mockFsUtil.readFile + .onFirstCall() + .returns(locales) + .onSecondCall() + .returns(contentTypes); + + const processingError = new Error('Entry processing failed'); + sandbox.stub(entriesExport, 'getEntries').rejects(processingError); + + const handleAndLogErrorSpy = sandbox.spy(); + try { + sandbox.replaceGetter(utilities, 'handleAndLogError', () => handleAndLogErrorSpy); + } catch (e) { + // Already replaced, restore first + sandbox.restore(); + sandbox.replaceGetter(utilities, 'handleAndLogError', () => handleAndLogErrorSpy); + } + + await entriesExport.start(); + + // Should handle error + expect(handleAndLogErrorSpy.called).to.be.true; + expect(handleAndLogErrorSpy.calledWith( + processingError, + sinon.match.has('module', 'entries') + )).to.be.true; + }); + }); +}); + diff --git a/packages/contentstack-export/test/unit/export/modules/labels.test.ts b/packages/contentstack-export/test/unit/export/modules/labels.test.ts new file mode 100644 index 0000000000..af4bce1066 --- /dev/null +++ b/packages/contentstack-export/test/unit/export/modules/labels.test.ts @@ -0,0 +1,601 @@ +import { expect } from 'chai'; +import sinon from 'sinon'; +import { FsUtility, handleAndLogError } from '@contentstack/cli-utilities'; +import ExportLabels from '../../../../src/export/modules/labels'; +import ExportConfig from '../../../../src/types/export-config'; + +describe('ExportLabels', () => { + let exportLabels: any; + let mockStackClient: any; + let mockExportConfig: ExportConfig; + + beforeEach(() => { + mockStackClient = { + label: sinon.stub().returns({ + query: sinon.stub().returns({ + find: sinon.stub().resolves({ + items: [ + { uid: 'label-1', name: 'Test Label 1', parent: [] }, + { uid: 'label-2', name: 'Test Label 2', parent: ['label-1'] } + ], + count: 2 + }) + }) + }) + }; + + mockExportConfig = { + contentVersion: 1, + versioning: false, + host: 'https://api.contentstack.io', + developerHubUrls: {}, + apiKey: 'test-api-key', + exportDir: '/test/export', + data: '/test/data', + branchName: '', + context: { + command: 'cm:stacks:export', + module: 'labels', + userId: 'user-123', + email: 'test@example.com', + sessionId: 'session-123', + apiKey: 'test-api-key', + orgId: 'org-123', + authenticationMethod: 'Basic Auth' + }, + cliLogsPath: '/test/logs', + forceStopMarketplaceAppsPrompt: false, + master_locale: { code: 'en-us' }, + region: { + name: 'us', + cma: 'https://api.contentstack.io', + cda: 'https://cdn.contentstack.io', + uiHost: 'https://app.contentstack.com' + }, + skipStackSettings: false, + skipDependencies: false, + languagesCode: ['en'], + apis: { + userSession: '', + globalfields: '', + locales: '', + labels: '', + environments: '', + assets: '', + content_types: '', + entries: '', + users: '', + extension: '', + webhooks: '', + stacks: '' + }, + preserveStackVersion: false, + personalizationEnabled: false, + fetchConcurrency: 5, + writeConcurrency: 5, + developerHubBaseUrl: '', + marketplaceAppEncryptionKey: '', + onlyTSModules: [], + modules: { + types: ['labels'], + labels: { + dirName: 'labels', + fileName: 'labels.json', + invalidKeys: ['ACL', '_version'], + limit: 100 + } + } + } as any; + + exportLabels = new ExportLabels({ + exportConfig: mockExportConfig, + stackAPIClient: mockStackClient, + moduleName: 'labels' + }); + + // Stub FsUtility methods + sinon.stub(FsUtility.prototype, 'writeFile').resolves(); + sinon.stub(FsUtility.prototype, 'makeDirectory').resolves(); + }); + + afterEach(() => { + sinon.restore(); + }); + + describe('Constructor', () => { + it('should initialize with correct parameters', () => { + expect(exportLabels).to.be.instanceOf(ExportLabels); + }); + + it('should set context module to labels', () => { + expect(exportLabels.exportConfig.context.module).to.equal('labels'); + }); + + it('should initialize labels object as empty', () => { + expect(exportLabels.labels).to.be.an('object'); + expect(Object.keys(exportLabels.labels).length).to.equal(0); + }); + + it('should initialize labelConfig from exportConfig', () => { + expect(exportLabels.labelConfig).to.exist; + expect(exportLabels.labelConfig.dirName).to.equal('labels'); + expect(exportLabels.labelConfig.fileName).to.equal('labels.json'); + }); + + it('should initialize query string with include_count', () => { + expect(exportLabels.qs).to.exist; + expect(exportLabels.qs.include_count).to.be.true; + }); + }); + + describe('getLabels() method', () => { + it('should fetch and process labels correctly', async () => { + exportLabels.labels = {}; + + const labels = [ + { uid: 'label-1', name: 'Test Label 1', parent: [] }, + { uid: 'label-2', name: 'Test Label 2', parent: ['label-1'] } + ]; + + exportLabels.client = { + label: sinon.stub().returns({ + query: sinon.stub().returns({ + find: sinon.stub().resolves({ + items: labels, + count: 2 + }) + }) + }) + }; + + await exportLabels.getLabels(); + + // Verify labels were processed + expect(Object.keys(exportLabels.labels).length).to.equal(2); + expect(exportLabels.labels['label-1']).to.exist; + expect(exportLabels.labels['label-1'].name).to.equal('Test Label 1'); + }); + + it('should call getLabels recursively when more labels exist', async () => { + let callCount = 0; + mockStackClient.label.returns({ + query: sinon.stub().returns({ + find: sinon.stub().callsFake(() => { + callCount++; + if (callCount === 1) { + return Promise.resolve({ + items: Array(100).fill({ uid: `label-${callCount}`, name: 'Test Label' }), + count: 150 + }); + } else { + return Promise.resolve({ + items: Array(50).fill({ uid: `label-${callCount}`, name: 'Test Label' }), + count: 150 + }); + } + }) + }) + }); + + await exportLabels.getLabels(); + + // Verify multiple calls were made for recursive fetching + expect(callCount).to.be.greaterThan(1); + }); + + it('should handle skip parameter correctly', async () => { + let queryParams: any[] = []; + mockStackClient.label.returns({ + query: sinon.stub().callsFake((params) => { + queryParams.push(params); + return { + find: sinon.stub().resolves({ + items: [], + count: 0 + }) + }; + }) + }); + + await exportLabels.getLabels(50); + + // Verify skip was set in query params + expect(queryParams.length).to.be.greaterThan(0); + expect(queryParams[0].skip).to.equal(50); + }); + + it('should use limit from config when calculating skip', async () => { + exportLabels.labelConfig.limit = 50; + let skipValues: number[] = []; + let callCount = 0; + + mockStackClient.label.returns({ + query: sinon.stub().returns({ + find: sinon.stub().callsFake(() => { + callCount++; + if (callCount === 1) { + skipValues.push(0); + return Promise.resolve({ + items: Array(50).fill({ uid: 'test', name: 'Test' }), + count: 100 + }); + } else { + skipValues.push(50); + return Promise.resolve({ + items: [], + count: 100 + }); + } + }) + }) + }); + + await exportLabels.getLabels(); + + // Verify skip was incremented by limit (50) + expect(skipValues).to.include(50); + }); + + it('should use default limit of 100 when limit is not in config', async () => { + exportLabels.labelConfig.limit = undefined; + let skipValues: number[] = []; + let callCount = 0; + + mockStackClient.label.returns({ + query: sinon.stub().returns({ + find: sinon.stub().callsFake(() => { + callCount++; + if (callCount === 1) { + skipValues.push(0); + return Promise.resolve({ + items: Array(100).fill({ uid: 'test', name: 'Test' }), + count: 200 + }); + } else { + skipValues.push(100); + return Promise.resolve({ + items: [], + count: 200 + }); + } + }) + }) + }); + + await exportLabels.getLabels(); + + // Verify skip was incremented by default limit (100) + expect(skipValues).to.include(100); + }); + + it('should stop recursion when skip >= count', async () => { + let callCount = 0; + mockStackClient.label.returns({ + query: sinon.stub().returns({ + find: sinon.stub().callsFake(() => { + callCount++; + return Promise.resolve({ + items: Array(50).fill({ uid: 'test', name: 'Test' }), + count: 50 + }); + }) + }) + }); + + await exportLabels.getLabels(); + + // Should only be called once since skip (100) >= count (50) after first call + expect(callCount).to.equal(1); + }); + + it('should handle API errors gracefully', async () => { + mockStackClient.label.returns({ + query: sinon.stub().returns({ + find: sinon.stub().rejects(new Error('API Error')) + }) + }); + + // The method should complete without throwing (error is caught and handled) + await exportLabels.getLabels(); + + // Verify method completed - labels should still exist (initialized in constructor) + expect(exportLabels.labels).to.exist; + }); + + it('should handle no items response', async () => { + mockStackClient.label.returns({ + query: sinon.stub().returns({ + find: sinon.stub().resolves({ + items: [], + count: 0 + }) + }) + }); + + const initialCount = Object.keys(exportLabels.labels).length; + await exportLabels.getLabels(); + + // Verify no new labels were added + expect(Object.keys(exportLabels.labels).length).to.equal(initialCount); + }); + + it('should handle empty items array', async () => { + mockStackClient.label.returns({ + query: sinon.stub().returns({ + find: sinon.stub().resolves({ + items: null, + count: 0 + }) + }) + }); + + const initialCount = Object.keys(exportLabels.labels).length; + await exportLabels.getLabels(); + + // Verify no processing occurred with null items + expect(Object.keys(exportLabels.labels).length).to.equal(initialCount); + }); + + it('should handle items with undefined length', async () => { + mockStackClient.label.returns({ + query: sinon.stub().returns({ + find: sinon.stub().resolves({ + items: undefined, + count: 0 + }) + }) + }); + + const initialCount = Object.keys(exportLabels.labels).length; + await exportLabels.getLabels(); + + // Verify no processing occurred with undefined items + expect(Object.keys(exportLabels.labels).length).to.equal(initialCount); + }); + }); + + describe('start() method', () => { + it('should complete full export flow and write files', async () => { + const writeFileStub = FsUtility.prototype.writeFile as sinon.SinonStub; + const makeDirectoryStub = FsUtility.prototype.makeDirectory as sinon.SinonStub; + + const labels = [ + { uid: 'label-1', name: 'Test Label 1', parent: [] }, + { uid: 'label-2', name: 'Test Label 2', parent: ['label-1'] } + ]; + + exportLabels.client = { + label: sinon.stub().returns({ + query: sinon.stub().returns({ + find: sinon.stub().resolves({ + items: labels, + count: 2 + }) + }) + }) + }; + + await exportLabels.start(); + + // Verify directory was created + expect(makeDirectoryStub.called).to.be.true; + // Verify labels were processed + expect(Object.keys(exportLabels.labels).length).to.equal(2); + expect(exportLabels.labels['label-1']).to.exist; + expect(exportLabels.labels['label-2']).to.exist; + // Verify file was written + expect(writeFileStub.called).to.be.true; + }); + + it('should handle empty labels and log NOT_FOUND', async () => { + const writeFileStub = FsUtility.prototype.writeFile as sinon.SinonStub; + // Reset the stub to ensure clean state + writeFileStub.resetHistory(); + + exportLabels.client = { + label: sinon.stub().returns({ + query: sinon.stub().returns({ + find: sinon.stub().resolves({ + items: [], + count: 0 + }) + }) + }) + }; + + exportLabels.labels = {}; + await exportLabels.start(); + + // Verify writeFile was NOT called when labels are empty + // isEmpty({}) returns true, so writeFile should not be called + expect(writeFileStub.called).to.be.false; + }); + + it('should handle undefined labels scenario', async () => { + // This test verifies that if labels becomes undefined (edge case), + // the code will throw when trying to call Object.keys on undefined + // In practice, labels is always initialized in constructor, so this shouldn't happen + exportLabels.labels = undefined as any; + + // Mock getLabels to not modify labels + const getLabelsStub = sinon.stub(exportLabels, 'getLabels').resolves(); + + try { + await exportLabels.start(); + // If we get here, the code might have been fixed to handle undefined + // But currently Object.keys(undefined) will throw + expect.fail('Should have thrown an error when labels is undefined'); + } catch (error: any) { + // Object.keys will throw on undefined + expect(error).to.exist; + } + + getLabelsStub.restore(); + }); + + it('should set labelsFolderPath correctly', async () => { + exportLabels.client = { + label: sinon.stub().returns({ + query: sinon.stub().returns({ + find: sinon.stub().resolves({ + items: [ + { uid: 'label-1', name: 'Test Label 1', parent: [] } + ], + count: 1 + }) + }) + }) + }; + + await exportLabels.start(); + + // Verify labelsFolderPath was set + expect(exportLabels.labelsFolderPath).to.exist; + expect(exportLabels.labelsFolderPath).to.include('labels'); + }); + + it('should handle branchName in path when provided', async () => { + mockExportConfig.branchName = 'test-branch'; + exportLabels = new ExportLabels({ + exportConfig: mockExportConfig, + stackAPIClient: mockStackClient, + moduleName: 'labels' + }); + + exportLabels.client = { + label: sinon.stub().returns({ + query: sinon.stub().returns({ + find: sinon.stub().resolves({ + items: [ + { uid: 'label-1', name: 'Test Label 1', parent: [] } + ], + count: 1 + }) + }) + }) + }; + + await exportLabels.start(); + + // Verify branchName is included in path + expect(exportLabels.labelsFolderPath).to.include('test-branch'); + }); + + it('should write file with correct path and data', async () => { + const writeFileStub = FsUtility.prototype.writeFile as sinon.SinonStub; + + exportLabels.client = { + label: sinon.stub().returns({ + query: sinon.stub().returns({ + find: sinon.stub().resolves({ + items: [ + { uid: 'label-1', name: 'Test Label 1', parent: [] } + ], + count: 1 + }) + }) + }) + }; + + await exportLabels.start(); + + // Verify writeFile was called with correct arguments + expect(writeFileStub.called).to.be.true; + const writeFileArgs = writeFileStub.firstCall.args; + expect(writeFileArgs[0]).to.include('labels.json'); + expect(writeFileArgs[1]).to.equal(exportLabels.labels); + }); + }); + + describe('sanitizeAttribs() method', () => { + it('should sanitize label attributes and remove invalid keys', () => { + exportLabels.labels = {}; + + const labels = [ + { uid: 'label-1', name: 'Test Label 1', ACL: 'remove', _version: 'remove', parent: [] }, + { uid: 'label-2', name: 'Test Label 2', ACL: 'remove', _version: 'remove', parent: ['label-1'] } + ]; + + exportLabels.sanitizeAttribs(labels); + + expect(exportLabels.labels['label-1']).to.exist; + expect(exportLabels.labels['label-1'].name).to.equal('Test Label 1'); + expect(exportLabels.labels['label-1'].uid).to.equal('label-1'); + // Verify invalid keys were removed + expect(exportLabels.labels['label-1'].ACL).to.be.undefined; + expect(exportLabels.labels['label-1']._version).to.be.undefined; + }); + + it('should handle labels without name field', () => { + exportLabels.labels = {}; + + const labels = [ + { uid: 'label-1', ACL: 'remove' } + ]; + + exportLabels.sanitizeAttribs(labels); + + expect(exportLabels.labels['label-1']).to.exist; + expect(exportLabels.labels['label-1'].ACL).to.be.undefined; + }); + + it('should handle empty labels array', () => { + exportLabels.labels = {}; + + const labels: any[] = []; + + exportLabels.sanitizeAttribs(labels); + + expect(Object.keys(exportLabels.labels).length).to.equal(0); + }); + + it('should handle labels with null or undefined values', () => { + exportLabels.labels = {}; + + const labels = [ + { uid: 'label-1', name: null as any, parent: [] as any[] }, + { uid: 'label-2', name: undefined as any, parent: [] as any[] } + ]; + + exportLabels.sanitizeAttribs(labels); + + expect(exportLabels.labels['label-1']).to.exist; + expect(exportLabels.labels['label-2']).to.exist; + }); + + it('should preserve valid keys after sanitization', () => { + exportLabels.labels = {}; + + const labels = [ + { + uid: 'label-1', + name: 'Test Label', + parent: ['parent-1'], + color: '#FF0000', + ACL: 'remove', + _version: 'remove' + } + ]; + + exportLabels.sanitizeAttribs(labels); + + expect(exportLabels.labels['label-1'].uid).to.equal('label-1'); + expect(exportLabels.labels['label-1'].name).to.equal('Test Label'); + expect(exportLabels.labels['label-1'].parent).to.deep.equal(['parent-1']); + expect(exportLabels.labels['label-1'].color).to.equal('#FF0000'); + // Invalid keys should be removed + expect(exportLabels.labels['label-1'].ACL).to.be.undefined; + expect(exportLabels.labels['label-1']._version).to.be.undefined; + }); + + it('should handle labels array with undefined length', () => { + exportLabels.labels = {}; + + const labels: any = { length: undefined }; + + // This should not throw an error + expect(() => exportLabels.sanitizeAttribs(labels)).to.not.throw(); + }); + }); +}); + diff --git a/packages/contentstack-export/test/unit/export/modules/marketplace-apps.test.ts b/packages/contentstack-export/test/unit/export/modules/marketplace-apps.test.ts new file mode 100644 index 0000000000..94e6cd9886 --- /dev/null +++ b/packages/contentstack-export/test/unit/export/modules/marketplace-apps.test.ts @@ -0,0 +1,803 @@ +import { expect } from 'chai'; +import sinon from 'sinon'; +import { FsUtility, cliux, isAuthenticated, marketplaceSDKClient, NodeCrypto } from '@contentstack/cli-utilities'; +import * as utilities from '@contentstack/cli-utilities'; +import ExportMarketplaceApps from '../../../../src/export/modules/marketplace-apps'; +import ExportConfig from '../../../../src/types/export-config'; +import * as marketplaceAppHelper from '../../../../src/utils/marketplace-app-helper'; + +describe('ExportMarketplaceApps', () => { + let exportMarketplaceApps: any; + let mockExportConfig: ExportConfig; + let mockAppSdk: any; + let mockNodeCrypto: any; + + beforeEach(() => { + mockExportConfig = { + contentVersion: 1, + versioning: false, + host: 'https://api.contentstack.io', + developerHubUrls: {}, + apiKey: 'test-api-key', + exportDir: '/test/export', + data: '/test/data', + branchName: '', + source_stack: 'test-stack-uid', + org_uid: 'test-org-uid', + context: { + command: 'cm:stacks:export', + module: 'marketplace-apps', + userId: 'user-123', + email: 'test@example.com', + sessionId: 'session-123', + apiKey: 'test-api-key', + orgId: 'org-123', + authenticationMethod: 'Basic Auth' + }, + cliLogsPath: '/test/logs', + forceStopMarketplaceAppsPrompt: false, + master_locale: { code: 'en-us' }, + region: { + name: 'us', + cma: 'https://api.contentstack.io', + cda: 'https://cdn.contentstack.io', + uiHost: 'https://app.contentstack.com' + }, + skipStackSettings: false, + skipDependencies: false, + languagesCode: ['en'], + apis: {}, + preserveStackVersion: false, + personalizationEnabled: false, + fetchConcurrency: 5, + writeConcurrency: 5, + developerHubBaseUrl: 'https://developer-api.contentstack.io', + marketplaceAppEncryptionKey: 'test-encryption-key', + onlyTSModules: [], + modules: { + types: ['marketplace-apps'], + marketplace_apps: { + dirName: 'marketplace-apps', + fileName: 'marketplace-apps.json' + } + }, + query: undefined + } as any; + + exportMarketplaceApps = new ExportMarketplaceApps({ + exportConfig: mockExportConfig + }); + + // Mock app SDK + mockAppSdk = { + marketplace: sinon.stub().returns({ + installation: sinon.stub().returns({ + fetchAll: sinon.stub().resolves({ + items: [], + count: 0 + }) + }), + app: sinon.stub().returns({ + fetch: sinon.stub().resolves({}) + }) + }) + }; + + // Mock NodeCrypto + mockNodeCrypto = { + encrypt: sinon.stub().returns('encrypted-data') + }; + + // Stub utility functions + sinon.stub(FsUtility.prototype, 'writeFile').resolves(); + sinon.stub(FsUtility.prototype, 'makeDirectory').resolves(); + // Note: isAuthenticated is non-configurable, so we'll stub it per test when needed using sinon.replace + sinon.stub(utilities, 'marketplaceSDKClient').resolves(mockAppSdk); + sinon.stub(marketplaceAppHelper, 'getOrgUid').resolves('test-org-uid'); + sinon.stub(marketplaceAppHelper, 'getDeveloperHubUrl').resolves('https://developer-api.contentstack.io'); + sinon.stub(marketplaceAppHelper, 'createNodeCryptoInstance').resolves(mockNodeCrypto); + }); + + afterEach(() => { + sinon.restore(); + }); + + describe('Constructor', () => { + it('should initialize with correct parameters', () => { + expect(exportMarketplaceApps).to.be.instanceOf(ExportMarketplaceApps); + }); + + it('should set context module to marketplace-apps', () => { + expect(exportMarketplaceApps.exportConfig.context.module).to.equal('marketplace-apps'); + }); + + it('should initialize marketplaceAppConfig from exportConfig', () => { + expect(exportMarketplaceApps.marketplaceAppConfig).to.exist; + expect(exportMarketplaceApps.marketplaceAppConfig.dirName).to.equal('marketplace-apps'); + expect(exportMarketplaceApps.marketplaceAppConfig.fileName).to.equal('marketplace-apps.json'); + }); + + it('should initialize installedApps as empty array', () => { + expect(exportMarketplaceApps.installedApps).to.be.an('array'); + expect(exportMarketplaceApps.installedApps.length).to.equal(0); + }); + }); + + describe('start() method', () => { + it('should return early if user is not authenticated', async () => { + // Stub configHandler.get to control isAuthenticated() behavior + // isAuthenticated() returns true when authorisationType is 'OAUTH' or 'BASIC', false otherwise + const configHandlerGetStub = sinon.stub(utilities.configHandler, 'get'); + configHandlerGetStub.withArgs('authorisationType').returns(undefined); // Not authenticated + const printStub = sinon.stub(cliux, 'print'); + + await exportMarketplaceApps.start(); + + expect(printStub.called).to.be.true; + expect(printStub.firstCall.args[0]).to.include('WARNING'); + printStub.restore(); + configHandlerGetStub.restore(); + }); + + it('should complete full export flow when authenticated', async () => { + // Stub configHandler.get to make isAuthenticated() return true + const configHandlerGetStub = sinon.stub(utilities.configHandler, 'get'); + configHandlerGetStub.withArgs('authorisationType').returns('BASIC'); // Authenticated + const makeDirectoryStub = FsUtility.prototype.makeDirectory as sinon.SinonStub; + const writeFileStub = FsUtility.prototype.writeFile as sinon.SinonStub; + + // Setup mock app SDK to return apps + mockAppSdk.marketplace.returns({ + installation: sinon.stub().returns({ + fetchAll: sinon.stub().resolves({ + items: [ + { + uid: 'installation-1', + manifest: { uid: 'app-1', name: 'Test App', visibility: 'public' }, + configuration: {} as any + } + ], + count: 1 + }) + }), + app: sinon.stub().returns({ + fetch: sinon.stub().resolves({}) + }) + }); + + // Mock exportApps to avoid complex setup + const exportAppsStub = sinon.stub(exportMarketplaceApps, 'exportApps').resolves(); + + await exportMarketplaceApps.start(); + + expect(makeDirectoryStub.called).to.be.true; + expect(exportMarketplaceApps.marketplaceAppPath).to.exist; + expect(exportMarketplaceApps.developerHubBaseUrl).to.equal('https://developer-api.contentstack.io'); + expect(exportMarketplaceApps.exportConfig.org_uid).to.equal('test-org-uid'); + expect(exportMarketplaceApps.query).to.deep.equal({ target_uids: 'test-stack-uid' }); + expect(exportMarketplaceApps.appSdk).to.equal(mockAppSdk); + + exportAppsStub.restore(); + configHandlerGetStub.restore(); + }); + + it('should set marketplaceAppPath correctly', async () => { + const configHandlerGetStub = sinon.stub(utilities.configHandler, 'get'); + configHandlerGetStub.withArgs('authorisationType').returns('BASIC'); + const exportAppsStub = sinon.stub(exportMarketplaceApps, 'exportApps').resolves(); + + await exportMarketplaceApps.start(); + + expect(exportMarketplaceApps.marketplaceAppPath).to.include('marketplace-apps'); + expect(exportMarketplaceApps.marketplaceAppPath).to.include('/test/data'); + + exportAppsStub.restore(); + configHandlerGetStub.restore(); + }); + + it('should handle branchName in path when provided', async () => { + mockExportConfig.branchName = 'test-branch'; + exportMarketplaceApps = new ExportMarketplaceApps({ + exportConfig: mockExportConfig + }); + + const configHandlerGetStub = sinon.stub(utilities.configHandler, 'get'); + configHandlerGetStub.withArgs('authorisationType').returns('BASIC'); + const exportAppsStub = sinon.stub(exportMarketplaceApps, 'exportApps').resolves(); + + await exportMarketplaceApps.start(); + + expect(exportMarketplaceApps.marketplaceAppPath).to.include('test-branch'); + + exportAppsStub.restore(); + configHandlerGetStub.restore(); + }); + + it('should use developerHubBaseUrl from config when provided', async () => { + mockExportConfig.developerHubBaseUrl = 'https://custom-devhub.com'; + exportMarketplaceApps = new ExportMarketplaceApps({ + exportConfig: mockExportConfig + }); + + const configHandlerGetStub = sinon.stub(utilities.configHandler, 'get'); + configHandlerGetStub.withArgs('authorisationType').returns('BASIC'); + const exportAppsStub = sinon.stub(exportMarketplaceApps, 'exportApps').resolves(); + + await exportMarketplaceApps.start(); + + expect(exportMarketplaceApps.developerHubBaseUrl).to.equal('https://custom-devhub.com'); + + exportAppsStub.restore(); + configHandlerGetStub.restore(); + }); + + it('should initialize marketplace SDK with correct host', async () => { + const configHandlerGetStub = sinon.stub(utilities.configHandler, 'get'); + configHandlerGetStub.withArgs('authorisationType').returns('BASIC'); + const exportAppsStub = sinon.stub(exportMarketplaceApps, 'exportApps').resolves(); + + await exportMarketplaceApps.start(); + + expect((utilities.marketplaceSDKClient as sinon.SinonStub).called).to.be.true; + const sdkArgs = (utilities.marketplaceSDKClient as sinon.SinonStub).firstCall.args[0]; + expect(sdkArgs.host).to.equal('developer-api.contentstack.io'); + + exportAppsStub.restore(); + configHandlerGetStub.restore(); + }); + }); + + describe('exportApps() method', () => { + beforeEach(() => { + exportMarketplaceApps.appSdk = mockAppSdk; + exportMarketplaceApps.query = { target_uids: 'test-stack-uid' }; + exportMarketplaceApps.exportConfig.org_uid = 'test-org-uid'; + }); + + it('should process external query with app_uids', async () => { + mockExportConfig.query = { + modules: { + 'marketplace-apps': { + app_uid: { $in: ['app-1', 'app-2'] } + } + } + }; + exportMarketplaceApps.exportConfig = mockExportConfig; + + const getStackSpecificAppsStub = sinon.stub(exportMarketplaceApps, 'getStackSpecificApps').resolves(); + const getAppManifestAndAppConfigStub = sinon.stub(exportMarketplaceApps, 'getAppManifestAndAppConfig').resolves(); + + await exportMarketplaceApps.exportApps(); + + expect(exportMarketplaceApps.query.app_uids).to.equal('app-1,app-2'); + expect(getStackSpecificAppsStub.called).to.be.true; + expect(getAppManifestAndAppConfigStub.called).to.be.true; + + getStackSpecificAppsStub.restore(); + getAppManifestAndAppConfigStub.restore(); + }); + + it('should process external query with installation_uids', async () => { + mockExportConfig.query = { + modules: { + 'marketplace-apps': { + installation_uid: { $in: ['inst-1', 'inst-2'] } + } + } + }; + exportMarketplaceApps.exportConfig = mockExportConfig; + + const getStackSpecificAppsStub = sinon.stub(exportMarketplaceApps, 'getStackSpecificApps').resolves(); + const getAppManifestAndAppConfigStub = sinon.stub(exportMarketplaceApps, 'getAppManifestAndAppConfig').resolves(); + + await exportMarketplaceApps.exportApps(); + + expect(exportMarketplaceApps.query.installation_uids).to.equal('inst-1,inst-2'); + + getStackSpecificAppsStub.restore(); + getAppManifestAndAppConfigStub.restore(); + }); + + it('should encrypt app configurations when present', async () => { + exportMarketplaceApps.installedApps = [ + { + uid: 'inst-1', + manifest: { uid: 'app-1', name: 'Test App' }, + configuration: { key: 'value' } + } + ]; + + const getStackSpecificAppsStub = sinon.stub(exportMarketplaceApps, 'getStackSpecificApps').resolves(); + const getAppManifestAndAppConfigStub = sinon.stub(exportMarketplaceApps, 'getAppManifestAndAppConfig').resolves(); + + await exportMarketplaceApps.exportApps(); + + expect(exportMarketplaceApps.nodeCrypto).to.exist; + expect(mockNodeCrypto.encrypt.called).to.be.true; + expect(exportMarketplaceApps.installedApps[0].configuration).to.equal('encrypted-data'); + + getStackSpecificAppsStub.restore(); + getAppManifestAndAppConfigStub.restore(); + }); + + it('should not initialize NodeCrypto when no configurations exist', async () => { + exportMarketplaceApps.installedApps = [ + { + uid: 'inst-1', + manifest: { uid: 'app-1', name: 'Test App' } + // No configuration property at all + } + ]; + + const getStackSpecificAppsStub = sinon.stub(exportMarketplaceApps, 'getStackSpecificApps').resolves(); + const getAppManifestAndAppConfigStub = sinon.stub(exportMarketplaceApps, 'getAppManifestAndAppConfig').resolves(); + + await exportMarketplaceApps.exportApps(); + + // NodeCrypto should not be initialized if no configurations + expect((marketplaceAppHelper.createNodeCryptoInstance as sinon.SinonStub).called).to.be.false; + + getStackSpecificAppsStub.restore(); + getAppManifestAndAppConfigStub.restore(); + }); + }); + + describe('getStackSpecificApps() method', () => { + beforeEach(() => { + exportMarketplaceApps.appSdk = mockAppSdk; + exportMarketplaceApps.exportConfig.org_uid = 'test-org-uid'; + exportMarketplaceApps.query = { target_uids: 'test-stack-uid' }; + }); + + it('should fetch and process stack-specific apps', async () => { + const apps = [ + { + uid: 'installation-1', + manifest: { uid: 'app-1', name: 'Test App 1' }, + someFunction: () => {} + }, + { + uid: 'installation-2', + manifest: { uid: 'app-2', name: 'Test App 2' }, + someFunction: () => {} + } + ]; + + mockAppSdk.marketplace.returns({ + installation: sinon.stub().returns({ + fetchAll: sinon.stub().resolves({ + items: apps, + count: 2 + }) + }) + }); + + await exportMarketplaceApps.getStackSpecificApps(); + + expect(exportMarketplaceApps.installedApps.length).to.equal(2); + expect(exportMarketplaceApps.installedApps[0].uid).to.equal('installation-1'); + expect(exportMarketplaceApps.installedApps[0].someFunction).to.be.undefined; // Functions should be removed + }); + + it('should call recursively when more apps exist', async () => { + let callCount = 0; + mockAppSdk.marketplace.returns({ + installation: sinon.stub().returns({ + fetchAll: sinon.stub().callsFake(() => { + callCount++; + if (callCount === 1) { + return Promise.resolve({ + items: Array(50).fill({ uid: 'app', manifest: {} }), + count: 100 + }); + } else { + return Promise.resolve({ + items: Array(50).fill({ uid: 'app2', manifest: {} }), + count: 100 + }); + } + }) + }) + }); + + await exportMarketplaceApps.getStackSpecificApps(); + + expect(callCount).to.be.greaterThan(1); + expect(exportMarketplaceApps.installedApps.length).to.equal(100); + }); + + it('should stop recursion when all apps are fetched', async () => { + let callCount = 0; + mockAppSdk.marketplace.returns({ + installation: sinon.stub().returns({ + fetchAll: sinon.stub().callsFake(() => { + callCount++; + return Promise.resolve({ + items: Array(30).fill({ uid: 'app', manifest: {} }), + count: 30 + }); + }) + }) + }); + + await exportMarketplaceApps.getStackSpecificApps(); + + // Should only be called once since count (30) - (skip + 50) = -20, which is not > 0 + expect(callCount).to.equal(1); + }); + + it('should handle API errors gracefully', async () => { + mockAppSdk.marketplace.returns({ + installation: sinon.stub().returns({ + fetchAll: sinon.stub().rejects(new Error('API Error')) + }) + }); + + await exportMarketplaceApps.getStackSpecificApps(); + + // Should complete without throwing + expect(exportMarketplaceApps.installedApps).to.exist; + }); + + it('should handle empty apps response', async () => { + mockAppSdk.marketplace.returns({ + installation: sinon.stub().returns({ + fetchAll: sinon.stub().resolves({ + items: [], + count: 0 + }) + }) + }); + + const initialLength = exportMarketplaceApps.installedApps.length; + await exportMarketplaceApps.getStackSpecificApps(); + + expect(exportMarketplaceApps.installedApps.length).to.equal(initialLength); + }); + + it('should remove function properties from apps', async () => { + const appWithFunction = { + uid: 'inst-1', + manifest: { uid: 'app-1' }, + regularProperty: 'value', + functionProperty: () => {}, + anotherFunction: function() {} + }; + + mockAppSdk.marketplace.returns({ + installation: sinon.stub().returns({ + fetchAll: sinon.stub().resolves({ + items: [appWithFunction], + count: 1 + }) + }) + }); + + await exportMarketplaceApps.getStackSpecificApps(); + + expect(exportMarketplaceApps.installedApps[0].regularProperty).to.equal('value'); + expect(exportMarketplaceApps.installedApps[0].functionProperty).to.be.undefined; + expect(exportMarketplaceApps.installedApps[0].anotherFunction).to.be.undefined; + }); + }); + + describe('getAppManifestAndAppConfig() method', () => { + beforeEach(() => { + exportMarketplaceApps.appSdk = mockAppSdk; + exportMarketplaceApps.exportConfig.org_uid = 'test-org-uid'; + exportMarketplaceApps.marketplaceAppPath = '/test/path'; + }); + + it('should log NOT_FOUND when no apps exist', async () => { + exportMarketplaceApps.installedApps = []; + + await exportMarketplaceApps.getAppManifestAndAppConfig(); + + const writeFileStub = FsUtility.prototype.writeFile as sinon.SinonStub; + expect(writeFileStub.called).to.be.false; + }); + + it('should process private app manifests', async () => { + exportMarketplaceApps.installedApps = [ + { + uid: 'inst-1', + manifest: { + uid: 'app-1', + name: 'Private App', + visibility: 'private' + } + } + ]; + + const getPrivateAppsManifestStub = sinon.stub(exportMarketplaceApps, 'getPrivateAppsManifest').resolves(); + const getAppConfigurationsStub = sinon.stub(exportMarketplaceApps, 'getAppConfigurations').resolves(); + const writeFileStub = FsUtility.prototype.writeFile as sinon.SinonStub; + + await exportMarketplaceApps.getAppManifestAndAppConfig(); + + expect(getPrivateAppsManifestStub.called).to.be.true; + expect(getAppConfigurationsStub.called).to.be.true; + expect(writeFileStub.called).to.be.true; + + getPrivateAppsManifestStub.restore(); + getAppConfigurationsStub.restore(); + }); + + it('should skip private app manifest processing for public apps', async () => { + exportMarketplaceApps.installedApps = [ + { + uid: 'inst-1', + manifest: { + uid: 'app-1', + name: 'Public App', + visibility: 'public' + } + } + ]; + + const getPrivateAppsManifestStub = sinon.stub(exportMarketplaceApps, 'getPrivateAppsManifest').resolves(); + const getAppConfigurationsStub = sinon.stub(exportMarketplaceApps, 'getAppConfigurations').resolves(); + + await exportMarketplaceApps.getAppManifestAndAppConfig(); + + // Should not be called for public apps + expect(getPrivateAppsManifestStub.called).to.be.false; + expect(getAppConfigurationsStub.called).to.be.true; + + getPrivateAppsManifestStub.restore(); + getAppConfigurationsStub.restore(); + }); + + it('should write file with correct path and data', async () => { + exportMarketplaceApps.installedApps = [ + { + uid: 'inst-1', + manifest: { uid: 'app-1', name: 'Test App', visibility: 'public' } + } + ]; + + const getAppConfigurationsStub = sinon.stub(exportMarketplaceApps, 'getAppConfigurations').resolves(); + const writeFileStub = FsUtility.prototype.writeFile as sinon.SinonStub; + + await exportMarketplaceApps.getAppManifestAndAppConfig(); + + expect(writeFileStub.called).to.be.true; + const writeFileArgs = writeFileStub.firstCall.args; + expect(writeFileArgs[0]).to.include('marketplace-apps.json'); + expect(writeFileArgs[1]).to.equal(exportMarketplaceApps.installedApps); + + getAppConfigurationsStub.restore(); + }); + }); + + describe('getPrivateAppsManifest() method', () => { + beforeEach(() => { + exportMarketplaceApps.appSdk = mockAppSdk; + exportMarketplaceApps.exportConfig.org_uid = 'test-org-uid'; + exportMarketplaceApps.installedApps = [ + { + uid: 'inst-1', + manifest: { + uid: 'app-1', + name: 'Private App', + visibility: 'private' + } + } + ]; + }); + + it('should fetch and update private app manifest', async () => { + const fetchedManifest = { + uid: 'app-1', + name: 'Private App Updated', + visibility: 'private', + oauth: { client_id: 'test-client-id' } + }; + + mockAppSdk.marketplace.returns({ + app: sinon.stub().returns({ + fetch: sinon.stub().resolves(fetchedManifest) + }) + }); + + await exportMarketplaceApps.getPrivateAppsManifest(0, exportMarketplaceApps.installedApps[0]); + + expect(exportMarketplaceApps.installedApps[0].manifest).to.deep.equal(fetchedManifest); + }); + + it('should handle API errors gracefully', async () => { + mockAppSdk.marketplace.returns({ + app: sinon.stub().returns({ + fetch: sinon.stub().rejects(new Error('API Error')) + }) + }); + + const originalManifest = exportMarketplaceApps.installedApps[0].manifest; + + await exportMarketplaceApps.getPrivateAppsManifest(0, exportMarketplaceApps.installedApps[0]); + + // Manifest should remain unchanged on error + expect(exportMarketplaceApps.installedApps[0].manifest).to.equal(originalManifest); + }); + + it('should fetch manifest with include_oauth option', async () => { + const fetchStub = sinon.stub().resolves({ uid: 'app-1', name: 'Private App' }); + mockAppSdk.marketplace.returns({ + app: sinon.stub().returns({ + fetch: fetchStub + }) + }); + + await exportMarketplaceApps.getPrivateAppsManifest(0, exportMarketplaceApps.installedApps[0]); + + expect(fetchStub.called).to.be.true; + expect(fetchStub.firstCall.args[0]).to.deep.equal({ include_oauth: true }); + }); + }); + + describe('getAppConfigurations() method', () => { + beforeEach(() => { + exportMarketplaceApps.appSdk = mockAppSdk; + exportMarketplaceApps.exportConfig.org_uid = 'test-org-uid'; + exportMarketplaceApps.nodeCrypto = mockNodeCrypto; + exportMarketplaceApps.installedApps = [ + { + uid: 'inst-1', + manifest: { + uid: 'app-1', + name: 'Test App' + } + } + ]; + }); + + it('should fetch and encrypt app configuration', async () => { + const installationData = { + data: { + configuration: { key: 'value' } + } + }; + + mockAppSdk.marketplace.returns({ + installation: sinon.stub().returns({ + installationData: sinon.stub().resolves(installationData) + }) + }); + + await exportMarketplaceApps.getAppConfigurations(0, exportMarketplaceApps.installedApps[0]); + + expect(exportMarketplaceApps.installedApps[0].configuration).to.equal('encrypted-data'); + expect(mockNodeCrypto.encrypt.called).to.be.true; + }); + + it('should fetch and encrypt server configuration', async () => { + const installationData = { + data: { + server_configuration: { secret: 'value' } + } + }; + + mockAppSdk.marketplace.returns({ + installation: sinon.stub().returns({ + installationData: sinon.stub().resolves(installationData) + }) + }); + + await exportMarketplaceApps.getAppConfigurations(0, exportMarketplaceApps.installedApps[0]); + + expect(exportMarketplaceApps.installedApps[0].server_configuration).to.equal('encrypted-data'); + expect(mockNodeCrypto.encrypt.called).to.be.true; + }); + + it('should initialize NodeCrypto if not already initialized', async () => { + exportMarketplaceApps.nodeCrypto = undefined; + const installationData = { + data: { + configuration: { key: 'value' } + } + }; + + mockAppSdk.marketplace.returns({ + installation: sinon.stub().returns({ + installationData: sinon.stub().resolves(installationData) + }) + }); + + await exportMarketplaceApps.getAppConfigurations(0, exportMarketplaceApps.installedApps[0]); + + expect((marketplaceAppHelper.createNodeCryptoInstance as sinon.SinonStub).called).to.be.true; + expect(exportMarketplaceApps.nodeCrypto).to.exist; + }); + + it('should handle empty configuration gracefully', async () => { + const installationData = { + data: { + configuration: null + } as any + }; + + mockAppSdk.marketplace.returns({ + installation: sinon.stub().returns({ + installationData: sinon.stub().resolves(installationData) + }) + }); + + await exportMarketplaceApps.getAppConfigurations(0, exportMarketplaceApps.installedApps[0]); + + expect(mockNodeCrypto.encrypt.called).to.be.false; + }); + + it('should handle API errors gracefully', async () => { + mockAppSdk.marketplace.returns({ + installation: sinon.stub().returns({ + installationData: sinon.stub().rejects(new Error('API Error')) + }) + }); + + await exportMarketplaceApps.getAppConfigurations(0, exportMarketplaceApps.installedApps[0]); + + // Should complete without throwing + expect(exportMarketplaceApps.installedApps[0]).to.exist; + }); + + it('should handle error in installation data response', async () => { + const installationData = { + data: null, + error: { message: 'Error fetching data' } + } as any; + + mockAppSdk.marketplace.returns({ + installation: sinon.stub().returns({ + installationData: sinon.stub().resolves(installationData) + }) + }); + + await exportMarketplaceApps.getAppConfigurations(0, exportMarketplaceApps.installedApps[0]); + + // Should handle error gracefully + expect(exportMarketplaceApps.installedApps[0]).to.exist; + }); + + it('should use app name when available, otherwise use uid', async () => { + exportMarketplaceApps.installedApps[0].manifest.name = 'Test App Name'; + const installationData = { + data: { + configuration: { key: 'value' } + } + }; + + mockAppSdk.marketplace.returns({ + installation: sinon.stub().returns({ + installationData: sinon.stub().resolves(installationData) + }) + }); + + await exportMarketplaceApps.getAppConfigurations(0, exportMarketplaceApps.installedApps[0]); + + // Should process successfully with app name + expect(exportMarketplaceApps.installedApps[0].configuration).to.exist; + }); + + it('should use app uid when name is not available', async () => { + exportMarketplaceApps.installedApps[0].manifest.name = undefined; + exportMarketplaceApps.installedApps[0].manifest.uid = 'app-uid-123'; + const installationData = { + data: { + configuration: { key: 'value' } + } + }; + + mockAppSdk.marketplace.returns({ + installation: sinon.stub().returns({ + installationData: sinon.stub().resolves(installationData) + }) + }); + + await exportMarketplaceApps.getAppConfigurations(0, exportMarketplaceApps.installedApps[0]); + + // Should process successfully with app uid + expect(exportMarketplaceApps.installedApps[0].configuration).to.exist; + }); + }); +}); + diff --git a/packages/contentstack-export/test/unit/export/modules/personalize.test.ts b/packages/contentstack-export/test/unit/export/modules/personalize.test.ts new file mode 100644 index 0000000000..aff1807c02 --- /dev/null +++ b/packages/contentstack-export/test/unit/export/modules/personalize.test.ts @@ -0,0 +1,587 @@ +import { expect } from 'chai'; +import sinon from 'sinon'; +import { handleAndLogError, messageHandler } from '@contentstack/cli-utilities'; +import * as utilities from '@contentstack/cli-utilities'; +import ExportPersonalize from '../../../../src/export/modules/personalize'; +import ExportConfig from '../../../../src/types/export-config'; +import * as variants from '@contentstack/cli-variants'; + +describe('ExportPersonalize', () => { + let exportPersonalize: any; + let mockExportConfig: ExportConfig; + let mockExportProjects: any; + let mockExportEvents: any; + let mockExportAttributes: any; + let mockExportAudiences: any; + let mockExportExperiences: any; + + beforeEach(() => { + mockExportConfig = { + contentVersion: 1, + versioning: false, + host: 'https://api.contentstack.io', + developerHubUrls: {}, + apiKey: 'test-api-key', + exportDir: '/test/export', + data: '/test/data', + branchName: '', + context: { + command: 'cm:stacks:export', + module: 'personalize', + userId: 'user-123', + email: 'test@example.com', + sessionId: 'session-123', + apiKey: 'test-api-key', + orgId: 'org-123', + authenticationMethod: 'Basic Auth' + }, + cliLogsPath: '/test/logs', + forceStopMarketplaceAppsPrompt: false, + master_locale: { code: 'en-us' }, + region: { + name: 'us', + cma: 'https://api.contentstack.io', + cda: 'https://cdn.contentstack.io', + uiHost: 'https://app.contentstack.com' + }, + skipStackSettings: false, + skipDependencies: false, + languagesCode: ['en'], + apis: {}, + preserveStackVersion: false, + personalizationEnabled: true, + fetchConcurrency: 5, + writeConcurrency: 5, + developerHubBaseUrl: '', + marketplaceAppEncryptionKey: '', + onlyTSModules: [], + modules: { + types: ['personalize'], + personalize: { + dirName: 'personalize', + baseURL: { + 'AWS-NA': 'https://personalize-api.contentstack.com', + 'AWS-EU': 'https://eu-personalize-api.contentstack.com', + 'AWS-AU': 'https://au-personalize-api.contentstack.com', + 'AZURE-NA': 'https://azure-na-personalize-api.contentstack.com', + 'AZURE-EU': 'https://azure-eu-personalize-api.contentstack.com', + 'GCP-NA': 'https://gcp-na-personalize-api.contentstack.com', + 'GCP-EU': 'https://gcp-eu-personalize-api.contentstack.com', + 'us': 'https://personalize-api.contentstack.com' + }, + exportOrder: ['events', 'attributes', 'audiences', 'experiences'], + projects: { + dirName: 'projects', + fileName: 'projects.json' + }, + attributes: { + dirName: 'attributes', + fileName: 'attributes.json' + }, + audiences: { + dirName: 'audiences', + fileName: 'audiences.json' + }, + events: { + dirName: 'events', + fileName: 'events.json' + }, + experiences: { + dirName: 'experiences', + fileName: 'experiences.json', + thresholdTimer: 60000, + checkIntervalDuration: 10000 + } + } + }, + management_token: undefined + } as any; + + // Mock ExportProjects - this can modify personalizationEnabled + mockExportProjects = { + start: sinon.stub().callsFake(async () => { + // Simulate ExportProjects behavior: it may set personalizationEnabled based on project existence + // For most tests, we'll keep it true, but can be changed per test + return Promise.resolve(); + }) + }; + + // Mock ExportEvents + mockExportEvents = { + start: sinon.stub().resolves() + }; + + // Mock ExportAttributes + mockExportAttributes = { + start: sinon.stub().resolves() + }; + + // Mock ExportAudiences + mockExportAudiences = { + start: sinon.stub().resolves() + }; + + // Mock ExportExperiences + mockExportExperiences = { + start: sinon.stub().resolves() + }; + + // Stub the variant class constructors - these need to return the mock instances + sinon.stub(variants, 'ExportProjects').value(function() { return mockExportProjects; } as any); + sinon.stub(variants, 'ExportEvents').value(function() { return mockExportEvents; } as any); + sinon.stub(variants, 'ExportAttributes').value(function() { return mockExportAttributes; } as any); + sinon.stub(variants, 'ExportAudiences').value(function() { return mockExportAudiences; } as any); + sinon.stub(variants, 'ExportExperiences').value(function() { return mockExportExperiences; } as any); + + exportPersonalize = new ExportPersonalize({ + exportConfig: mockExportConfig, + stackAPIClient: {} as any, + moduleName: 'personalize' + }); + }); + + afterEach(() => { + sinon.restore(); + }); + + describe('Constructor', () => { + it('should initialize with exportConfig and set context module', () => { + expect(exportPersonalize).to.be.instanceOf(ExportPersonalize); + expect(exportPersonalize.exportConfig).to.equal(mockExportConfig); + expect(exportPersonalize.exportConfig.context.module).to.equal('personalize'); + }); + + it('should initialize personalizeConfig from exportConfig modules', () => { + expect(exportPersonalize.personalizeConfig).to.exist; + expect(exportPersonalize.personalizeConfig.dirName).to.equal('personalize'); + expect(exportPersonalize.personalizeConfig.baseURL).to.deep.equal(mockExportConfig.modules.personalize.baseURL); + expect(exportPersonalize.personalizeConfig.exportOrder).to.deep.equal(['events', 'attributes', 'audiences', 'experiences']); + }); + }); + + describe('start() method - Early Return Conditions', () => { + it('should set personalizationEnabled to false and return early when baseURL is not configured for region', async () => { + const originalValue = mockExportConfig.personalizationEnabled; + mockExportConfig.region.name = 'invalid-region'; + exportPersonalize = new ExportPersonalize({ + exportConfig: mockExportConfig, + stackAPIClient: {} as any, + moduleName: 'personalize' + }); + + await exportPersonalize.start(); + + // Should set personalizationEnabled to false + expect(mockExportConfig.personalizationEnabled).to.be.false; + // Should not proceed with ExportProjects + expect(mockExportProjects.start.called).to.be.false; + // Should not process any modules + expect(mockExportEvents.start.called).to.be.false; + }); + + it('should set personalizationEnabled to false and return early when management_token is present', async () => { + mockExportConfig.management_token = 'test-management-token'; + const originalValue = mockExportConfig.personalizationEnabled; + + await exportPersonalize.start(); + + // Should set personalizationEnabled to false + expect(mockExportConfig.personalizationEnabled).to.be.false; + // Should not proceed with ExportProjects + expect(mockExportProjects.start.called).to.be.false; + // Should not process any modules + expect(mockExportEvents.start.called).to.be.false; + }); + + it('should proceed when baseURL is configured for the region', async () => { + mockExportConfig.region.name = 'us'; + exportPersonalize = new ExportPersonalize({ + exportConfig: mockExportConfig, + stackAPIClient: {} as any, + moduleName: 'personalize' + }); + + await exportPersonalize.start(); + + // Should proceed with ExportProjects + expect(mockExportProjects.start.calledOnce).to.be.true; + }); + }); + + describe('start() method - ExportProjects Integration', () => { + it('should skip module processing when ExportProjects disables personalization (no projects found)', async () => { + // Simulate ExportProjects finding no projects - sets personalizationEnabled to false + mockExportProjects.start.callsFake(async () => { + mockExportConfig.personalizationEnabled = false; + }); + + await exportPersonalize.start(); + + expect(mockExportProjects.start.calledOnce).to.be.true; + // Verify the state change: personalizationEnabled was set to false by ExportProjects + expect(mockExportConfig.personalizationEnabled).to.be.false; + // Verify the behavioral outcome: no modules were processed due to the state change + // This is the key behavior - the state change controls module processing + expect(mockExportEvents.start.called).to.be.false; + expect(mockExportAttributes.start.called).to.be.false; + expect(mockExportAudiences.start.called).to.be.false; + expect(mockExportExperiences.start.called).to.be.false; + }); + + it('should process all modules in exportOrder when ExportProjects enables personalization (projects found)', async () => { + // Simulate ExportProjects finding projects - sets personalizationEnabled to true + mockExportProjects.start.callsFake(async () => { + mockExportConfig.personalizationEnabled = true; + }); + + await exportPersonalize.start(); + + expect(mockExportProjects.start.calledOnce).to.be.true; + // Verify the state: personalizationEnabled is true after ExportProjects + expect(mockExportConfig.personalizationEnabled).to.be.true; + // Verify the behavioral outcome: all modules in exportOrder were processed + // This demonstrates that the state change (true) triggers module processing + expect(mockExportEvents.start.calledOnce).to.be.true; + expect(mockExportAttributes.start.calledOnce).to.be.true; + expect(mockExportAudiences.start.calledOnce).to.be.true; + expect(mockExportExperiences.start.calledOnce).to.be.true; + }); + + it('should respect personalizationEnabled state set by ExportProjects regardless of initial value', async () => { + // Test that ExportProjects has the authority to change the state and that change affects behavior + mockExportConfig.personalizationEnabled = false; // Start with false + mockExportProjects.start.callsFake(async () => { + // ExportProjects finds projects and enables personalization + mockExportConfig.personalizationEnabled = true; + }); + + await exportPersonalize.start(); + + // Verify ExportProjects changed the state from false to true + // This tests that ExportProjects can override the initial state + expect(mockExportConfig.personalizationEnabled).to.be.true; + // Verify the behavioral consequence: modules were processed because state changed to true + // This demonstrates the state-driven behavior, not just function calls + expect(mockExportEvents.start.calledOnce).to.be.true; + expect(mockExportAttributes.start.calledOnce).to.be.true; + expect(mockExportAudiences.start.calledOnce).to.be.true; + expect(mockExportExperiences.start.calledOnce).to.be.true; + }); + }); + + describe('start() method - Module Processing Order', () => { + beforeEach(() => { + // Ensure personalizationEnabled stays true + mockExportProjects.start.callsFake(async () => { + mockExportConfig.personalizationEnabled = true; + }); + }); + + it('should process modules in the order specified by exportOrder', async () => { + mockExportConfig.modules.personalize.exportOrder = ['events', 'attributes', 'audiences', 'experiences']; + const executionOrder: string[] = []; + + mockExportEvents.start.callsFake(async () => { + executionOrder.push('events'); + expect(executionOrder).to.deep.equal(['events']); + }); + mockExportAttributes.start.callsFake(async () => { + executionOrder.push('attributes'); + expect(executionOrder).to.deep.equal(['events', 'attributes']); + }); + mockExportAudiences.start.callsFake(async () => { + executionOrder.push('audiences'); + expect(executionOrder).to.deep.equal(['events', 'attributes', 'audiences']); + }); + mockExportExperiences.start.callsFake(async () => { + executionOrder.push('experiences'); + expect(executionOrder).to.deep.equal(['events', 'attributes', 'audiences', 'experiences']); + }); + + await exportPersonalize.start(); + + expect(executionOrder).to.deep.equal(['events', 'attributes', 'audiences', 'experiences']); + }); + + it('should process modules sequentially, not in parallel', async () => { + let currentModule: string | null = null; + const moduleStartTimes: Record = {}; + + mockExportEvents.start.callsFake(async () => { + expect(currentModule).to.be.null; + currentModule = 'events'; + moduleStartTimes.events = Date.now(); + await new Promise(resolve => setTimeout(resolve, 10)); + currentModule = null; + }); + mockExportAttributes.start.callsFake(async () => { + expect(currentModule).to.be.null; + currentModule = 'attributes'; + moduleStartTimes.attributes = Date.now(); + await new Promise(resolve => setTimeout(resolve, 10)); + currentModule = null; + }); + mockExportAudiences.start.callsFake(async () => { + expect(currentModule).to.be.null; + currentModule = 'audiences'; + moduleStartTimes.audiences = Date.now(); + await new Promise(resolve => setTimeout(resolve, 10)); + currentModule = null; + }); + mockExportExperiences.start.callsFake(async () => { + expect(currentModule).to.be.null; + currentModule = 'experiences'; + moduleStartTimes.experiences = Date.now(); + await new Promise(resolve => setTimeout(resolve, 10)); + currentModule = null; + }); + + await exportPersonalize.start(); + + // Verify sequential execution (each starts after previous completes) + expect(moduleStartTimes.attributes).to.be.greaterThan(moduleStartTimes.events); + expect(moduleStartTimes.audiences).to.be.greaterThan(moduleStartTimes.attributes); + expect(moduleStartTimes.experiences).to.be.greaterThan(moduleStartTimes.audiences); + }); + + it('should handle custom exportOrder configuration', async () => { + mockExportConfig.modules.personalize.exportOrder = ['experiences', 'events', 'audiences', 'attributes']; + const executionOrder: string[] = []; + + mockExportExperiences.start.callsFake(async () => { + executionOrder.push('experiences'); + }); + mockExportEvents.start.callsFake(async () => { + executionOrder.push('events'); + }); + mockExportAudiences.start.callsFake(async () => { + executionOrder.push('audiences'); + }); + mockExportAttributes.start.callsFake(async () => { + executionOrder.push('attributes'); + }); + + await exportPersonalize.start(); + + expect(executionOrder).to.deep.equal(['experiences', 'events', 'audiences', 'attributes']); + }); + }); + + describe('start() method - Unknown Module Handling', () => { + beforeEach(() => { + mockExportProjects.start.callsFake(async () => { + mockExportConfig.personalizationEnabled = true; + }); + }); + + it('should skip unknown modules in exportOrder but continue with valid ones', async () => { + mockExportConfig.modules.personalize.exportOrder = ['events', 'unknown-module', 'attributes', 'another-unknown']; + const executedModules: string[] = []; + + mockExportEvents.start.callsFake(async () => { + executedModules.push('events'); + }); + mockExportAttributes.start.callsFake(async () => { + executedModules.push('attributes'); + }); + + await exportPersonalize.start(); + + // Should execute valid modules + expect(executedModules).to.include('events'); + expect(executedModules).to.include('attributes'); + // Should not throw error for unknown modules + expect(mockExportEvents.start.calledOnce).to.be.true; + expect(mockExportAttributes.start.calledOnce).to.be.true; + }); + + it('should handle exportOrder with only unknown modules gracefully without throwing errors', async () => { + // Setup: ExportProjects enables personalization, but exportOrder contains only unknown modules + mockExportProjects.start.callsFake(async () => { + mockExportConfig.personalizationEnabled = true; + }); + mockExportConfig.modules.personalize.exportOrder = ['unknown-1', 'unknown-2']; + + // Should complete without throwing errors + let errorThrown = false; + try { + await exportPersonalize.start(); + } catch (error) { + errorThrown = true; + } + expect(errorThrown).to.be.false; + + // Verify ExportProjects completed successfully + expect(mockExportProjects.start.calledOnce).to.be.true; + // Verify personalizationEnabled remains true (no error occurred) + expect(mockExportConfig.personalizationEnabled).to.be.true; + // Verify no known modules were processed (since exportOrder only had unknown modules) + expect(mockExportEvents.start.called).to.be.false; + expect(mockExportAttributes.start.called).to.be.false; + expect(mockExportAudiences.start.called).to.be.false; + expect(mockExportExperiences.start.called).to.be.false; + // The key behavior: unknown modules are skipped gracefully, process completes successfully + }); + }); + + describe('start() method - Error Handling', () => { + it('should set personalizationEnabled to false and handle Forbidden error specially', async () => { + mockExportProjects.start.rejects('Forbidden'); + const originalValue = mockExportConfig.personalizationEnabled; + + await exportPersonalize.start(); + + // Should set personalizationEnabled to false + expect(mockExportConfig.personalizationEnabled).to.be.false; + // Should not process modules + expect(mockExportEvents.start.called).to.be.false; + }); + + it('should set personalizationEnabled to false and call handleAndLogError for non-Forbidden errors', async () => { + const testError = new Error('API Connection Error'); + mockExportProjects.start.rejects(testError); + const handleAndLogErrorSpy = sinon.spy(); + sinon.replaceGetter(utilities, 'handleAndLogError', () => handleAndLogErrorSpy); + + await exportPersonalize.start(); + + // Should set personalizationEnabled to false + expect(mockExportConfig.personalizationEnabled).to.be.false; + // Should call handleAndLogError with the error and context + expect(handleAndLogErrorSpy.calledOnce).to.be.true; + expect(handleAndLogErrorSpy.getCall(0).args[0]).to.equal(testError); + expect(handleAndLogErrorSpy.getCall(0).args[1]).to.deep.include(mockExportConfig.context); + }); + + it('should set personalizationEnabled to false when module processing fails', async () => { + mockExportProjects.start.callsFake(async () => { + mockExportConfig.personalizationEnabled = true; + }); + const moduleError = new Error('Events export failed'); + mockExportEvents.start.rejects(moduleError); + const handleAndLogErrorSpy = sinon.spy(); + sinon.replaceGetter(utilities, 'handleAndLogError', () => handleAndLogErrorSpy); + + try { + await exportPersonalize.start(); + } catch (error) { + // Error may propagate + } + + // Should set personalizationEnabled to false on error + expect(mockExportConfig.personalizationEnabled).to.be.false; + }); + + it('should handle errors in ExportProjects and prevent module processing', async () => { + const projectsError = new Error('Projects export failed'); + mockExportProjects.start.rejects(projectsError); + const handleAndLogErrorSpy = sinon.spy(); + sinon.replaceGetter(utilities, 'handleAndLogError', () => handleAndLogErrorSpy); + + await exportPersonalize.start(); + + // Should not process modules after error + expect(mockExportEvents.start.called).to.be.false; + expect(mockExportAttributes.start.called).to.be.false; + expect(mockExportConfig.personalizationEnabled).to.be.false; + }); + }); + + describe('start() method - Region Configuration', () => { + it('should work with all supported region names', async () => { + const supportedRegions = ['AWS-NA', 'AWS-EU', 'AWS-AU', 'AZURE-NA', 'AZURE-EU', 'GCP-NA', 'GCP-EU', 'us']; + + for (const regionName of supportedRegions) { + mockExportConfig.region.name = regionName; + exportPersonalize = new ExportPersonalize({ + exportConfig: mockExportConfig, + stackAPIClient: {} as any, + moduleName: 'personalize' + }); + + mockExportProjects.start.resetHistory(); + + await exportPersonalize.start(); + + // Should proceed with ExportProjects for all supported regions + expect(mockExportProjects.start.calledOnce, `Should work for region: ${regionName}`).to.be.true; + } + }); + }); + + describe('start() method - Complete Flow', () => { + it('should complete full export flow successfully when all conditions are met', async () => { + mockExportProjects.start.callsFake(async () => { + mockExportConfig.personalizationEnabled = true; + }); + + // Track execution order to verify sequential processing + const executionOrder: string[] = []; + mockExportEvents.start.callsFake(async () => { + executionOrder.push('events'); + return Promise.resolve(); + }); + mockExportAttributes.start.callsFake(async () => { + executionOrder.push('attributes'); + return Promise.resolve(); + }); + mockExportAudiences.start.callsFake(async () => { + executionOrder.push('audiences'); + return Promise.resolve(); + }); + mockExportExperiences.start.callsFake(async () => { + executionOrder.push('experiences'); + return Promise.resolve(); + }); + + // Execute the full flow + await exportPersonalize.start(); + + expect(mockExportProjects.start.calledOnce).to.be.true; + // Verify all modules were processed in the correct order + expect(executionOrder).to.deep.equal(['events', 'attributes', 'audiences', 'experiences']); + expect(mockExportEvents.start.calledOnce).to.be.true; + expect(mockExportAttributes.start.calledOnce).to.be.true; + expect(mockExportAudiences.start.calledOnce).to.be.true; + expect(mockExportExperiences.start.calledOnce).to.be.true; + expect(mockExportConfig.personalizationEnabled).to.be.true; + }); + + it('should handle partial module failures: stop processing, log error, and disable personalization', async () => { + // Setup: ExportProjects enables personalization, first module succeeds, second fails + mockExportProjects.start.callsFake(async () => { + mockExportConfig.personalizationEnabled = true; + }); + + const attributesError = new Error('Attributes export failed'); + mockExportEvents.start.resolves(); + mockExportAttributes.start.rejects(attributesError); + + const handleAndLogErrorSpy = sinon.spy(); + sinon.replaceGetter(utilities, 'handleAndLogError', () => handleAndLogErrorSpy); + + try { + await exportPersonalize.start(); + } catch (error) { + // Error may propagate, but should be handled in catch block + } + + // Verify ExportProjects completed + expect(mockExportProjects.start.calledOnce).to.be.true; + // Verify first module (events) was processed successfully + expect(mockExportEvents.start.calledOnce).to.be.true; + // Should have attempted to process attributes (second module, which fails) + expect(mockExportAttributes.start.calledOnce).to.be.true; + // Verify error handling: handleAndLogError was called with correct error and context + expect(handleAndLogErrorSpy.calledOnce).to.be.true; + expect(handleAndLogErrorSpy.getCall(0).args[0]).to.equal(attributesError); + expect(handleAndLogErrorSpy.getCall(0).args[1]).to.deep.include(mockExportConfig.context); + // Verify state change: personalizationEnabled set to false due to error + expect(mockExportConfig.personalizationEnabled).to.be.false; + // Verify subsequent modules were NOT processed after the error + // This is the key behavior - error stops the processing chain + expect(mockExportAudiences.start.called).to.be.false; + expect(mockExportExperiences.start.called).to.be.false; + }); + }); +}); diff --git a/packages/contentstack-export/test/unit/export/modules/stack.test.ts b/packages/contentstack-export/test/unit/export/modules/stack.test.ts index 828fdd85f0..8fa749c724 100644 --- a/packages/contentstack-export/test/unit/export/modules/stack.test.ts +++ b/packages/contentstack-export/test/unit/export/modules/stack.test.ts @@ -1,6 +1,7 @@ import { expect } from 'chai'; import sinon from 'sinon'; -import { FsUtility } from '@contentstack/cli-utilities'; +import { FsUtility, isAuthenticated, managementSDKClient, handleAndLogError } from '@contentstack/cli-utilities'; +import * as utilities from '@contentstack/cli-utilities'; import ExportStack from '../../../../src/export/modules/stack'; import ExportConfig from '../../../../src/types/export-config'; @@ -265,11 +266,6 @@ describe('ExportStack', () => { }); }); - describe('getStack() method', () => { - - - }); - describe('getLocales() method', () => { it('should fetch and return master locale', async () => { const locale = await exportStack.getLocales(); @@ -342,6 +338,78 @@ describe('ExportStack', () => { expect(locale).to.be.undefined; }); + it('should handle master locale not found after searching all pages', async () => { + let callCount = 0; + const limit = (exportStack as any).stackConfig.limit || 100; + const localeStub = { + query: sinon.stub().returns({ + find: sinon.stub().callsFake(() => { + callCount++; + // Return batches without master locale until all pages are exhausted + // First call: 100 items, count 100, skip will be 100, which equals count, so it stops + return Promise.resolve({ + items: Array(limit).fill({ uid: `locale-${callCount}`, code: 'en', fallback_locale: 'en-us' }), + count: limit // Only limit items, so skip will equal count and stop + }); + }) + }) + }; + + mockStackClient.locale.returns(localeStub); + const locale = await exportStack.getLocales(); + + // Should return undefined when master locale not found after all pages + expect(locale).to.be.undefined; + // Should have searched through available pages + expect(callCount).to.be.greaterThan(0); + }); + + it('should handle getLocales with skip parameter', async () => { + const localeStub = { + query: sinon.stub().returns({ + find: sinon.stub().resolves({ + items: [{ uid: 'locale-master', code: 'en-us', fallback_locale: null, name: 'English' }], + count: 1 + }) + }) + }; + + mockStackClient.locale.returns(localeStub); + const locale = await exportStack.getLocales(100); + + // Should find master locale even when starting with skip + expect(locale).to.exist; + expect(locale.code).to.equal('en-us'); + // Verify skip was set in query + expect((exportStack as any).qs.skip).to.equal(100); + }); + + it('should handle error and propagate it when fetching locales fails', async () => { + const localeError = new Error('Locale fetch failed'); + const localeStub = { + query: sinon.stub().returns({ + find: sinon.stub().rejects(localeError) + }) + }; + + mockStackClient.locale.returns(localeStub); + const handleAndLogErrorSpy = sinon.spy(); + sinon.replaceGetter(utilities, 'handleAndLogError', () => handleAndLogErrorSpy); + + try { + await exportStack.getLocales(); + expect.fail('Should have thrown error'); + } catch (error) { + expect(error).to.equal(localeError); + // Should handle and log error + expect(handleAndLogErrorSpy.called).to.be.true; + expect(handleAndLogErrorSpy.calledWith( + localeError, + sinon.match.has('module', 'stack') + )).to.be.true; + } + }); + it('should find master locale in first batch when present', async () => { const localeStub = { query: sinon.stub().returns({ @@ -366,19 +434,52 @@ describe('ExportStack', () => { it('should export stack successfully and write to file', async () => { const writeFileStub = FsUtility.prototype.writeFile as sinon.SinonStub; const makeDirectoryStub = FsUtility.prototype.makeDirectory as sinon.SinonStub; + const stackData = { name: 'Test Stack', uid: 'stack-uid', org_uid: 'org-123' }; + mockStackClient.fetch = sinon.stub().resolves(stackData); - await exportStack.exportStack(); + const result = await exportStack.exportStack(); expect(writeFileStub.called).to.be.true; expect(makeDirectoryStub.called).to.be.true; + // Should return the stack data + expect(result).to.deep.equal(stackData); + // Verify file was written with correct path + const writeCall = writeFileStub.getCall(0); + expect(writeCall.args[0]).to.include('stack.json'); + expect(writeCall.args[1]).to.deep.equal(stackData); }); it('should handle errors when exporting stack without throwing', async () => { - mockStackClient.fetch = sinon.stub().rejects(new Error('Stack fetch failed')); + const stackError = new Error('Stack fetch failed'); + mockStackClient.fetch = sinon.stub().rejects(stackError); + const handleAndLogErrorSpy = sinon.spy(); + sinon.replaceGetter(utilities, 'handleAndLogError', () => handleAndLogErrorSpy); // Should complete without throwing despite error - // The assertion is that await doesn't throw + const result = await exportStack.exportStack(); + + // Should return undefined on error + expect(result).to.be.undefined; + // Should handle and log error + expect(handleAndLogErrorSpy.called).to.be.true; + expect(handleAndLogErrorSpy.calledWith( + stackError, + sinon.match.has('module', 'stack') + )).to.be.true; + }); + + it('should create directory before writing stack file', async () => { + const makeDirectoryStub = FsUtility.prototype.makeDirectory as sinon.SinonStub; + const writeFileStub = FsUtility.prototype.writeFile as sinon.SinonStub; + mockStackClient.fetch = sinon.stub().resolves({ name: 'Test Stack' }); + await exportStack.exportStack(); + + // Directory should be created before file write + expect(makeDirectoryStub.called).to.be.true; + expect(writeFileStub.called).to.be.true; + // Verify directory creation happens before file write + expect(makeDirectoryStub.calledBefore(writeFileStub)).to.be.true; }); }); @@ -386,19 +487,56 @@ describe('ExportStack', () => { it('should export stack settings successfully and write to file', async () => { const writeFileStub = FsUtility.prototype.writeFile as sinon.SinonStub; const makeDirectoryStub = FsUtility.prototype.makeDirectory as sinon.SinonStub; + const settingsData = { + name: 'Stack Settings', + description: 'Settings description', + settings: { global: { example: 'value' } } + }; + mockStackClient.settings = sinon.stub().resolves(settingsData); - await exportStack.exportStackSettings(); + const result = await exportStack.exportStackSettings(); expect(writeFileStub.called).to.be.true; expect(makeDirectoryStub.called).to.be.true; + // Should return the settings data + expect(result).to.deep.equal(settingsData); + // Verify file was written with correct path + const writeCall = writeFileStub.getCall(0); + expect(writeCall.args[0]).to.include('settings.json'); + expect(writeCall.args[1]).to.deep.equal(settingsData); }); it('should handle errors when exporting settings without throwing', async () => { - mockStackClient.settings = sinon.stub().rejects(new Error('Settings fetch failed')); + const settingsError = new Error('Settings fetch failed'); + mockStackClient.settings = sinon.stub().rejects(settingsError); + const handleAndLogErrorSpy = sinon.spy(); + sinon.replaceGetter(utilities, 'handleAndLogError', () => handleAndLogErrorSpy); // Should complete without throwing despite error - // The assertion is that await doesn't throw + const result = await exportStack.exportStackSettings(); + + // Should return undefined on error + expect(result).to.be.undefined; + // Should handle and log error + expect(handleAndLogErrorSpy.called).to.be.true; + expect(handleAndLogErrorSpy.calledWith( + settingsError, + sinon.match.has('module', 'stack') + )).to.be.true; + }); + + it('should create directory before writing settings file', async () => { + const makeDirectoryStub = FsUtility.prototype.makeDirectory as sinon.SinonStub; + const writeFileStub = FsUtility.prototype.writeFile as sinon.SinonStub; + mockStackClient.settings = sinon.stub().resolves({ name: 'Settings' }); + await exportStack.exportStackSettings(); + + // Directory should be created before file write + expect(makeDirectoryStub.called).to.be.true; + expect(writeFileStub.called).to.be.true; + // Verify directory creation happens before file write + expect(makeDirectoryStub.calledBefore(writeFileStub)).to.be.true; }); }); diff --git a/packages/contentstack-export/test/unit/export/modules/taxonomies.test.ts b/packages/contentstack-export/test/unit/export/modules/taxonomies.test.ts index 91eddcf39c..06b86229ad 100644 --- a/packages/contentstack-export/test/unit/export/modules/taxonomies.test.ts +++ b/packages/contentstack-export/test/unit/export/modules/taxonomies.test.ts @@ -311,6 +311,376 @@ describe('ExportTaxonomies', () => { expect(Object.keys(exportTaxonomies.taxonomies).length).to.equal(0); }); + + // const taxonomies = [ + // { uid: 'taxonomy-1', name: 'Category' }, + // { uid: 'taxonomy-2', name: 'Tag' } + // ]; + + // exportTaxonomies.sanitizeTaxonomiesAttribs(taxonomies, 'en-us'); + + // expect(exportTaxonomies.taxonomies['taxonomy-1']).to.exist; + // expect(exportTaxonomies.taxonomies['taxonomy-2']).to.exist; + // // Verify taxonomies are tracked by locale + // expect(exportTaxonomies.taxonomiesByLocale['en-us']).to.exist; + // expect(exportTaxonomies.taxonomiesByLocale['en-us'].has('taxonomy-1')).to.be.true; + // expect(exportTaxonomies.taxonomiesByLocale['en-us'].has('taxonomy-2')).to.be.true; + // }); + + it('should not duplicate taxonomy metadata when processing same taxonomy multiple times', () => { + const taxonomies1 = [{ uid: 'taxonomy-1', name: 'Category', field1: 'value1' }]; + const taxonomies2 = [{ uid: 'taxonomy-1', name: 'Category', field2: 'value2' }]; + + exportTaxonomies.sanitizeTaxonomiesAttribs(taxonomies1); + exportTaxonomies.sanitizeTaxonomiesAttribs(taxonomies2); + + // Should only have one entry for taxonomy-1 + expect(Object.keys(exportTaxonomies.taxonomies).length).to.equal(1); + // Should have the first processed version (field1, not field2) + expect(exportTaxonomies.taxonomies['taxonomy-1'].field1).to.equal('value1'); + expect(exportTaxonomies.taxonomies['taxonomy-1'].field2).to.be.undefined; + }); + }); + + describe('getLocalesToExport() method', () => { + it('should return master locale when no locales file exists', () => { + const readFileStub = FsUtility.prototype.readFile as sinon.SinonStub; + readFileStub.throws(new Error('File not found')); + + const locales = exportTaxonomies.getLocalesToExport(); + + expect(locales).to.be.an('array'); + expect(locales.length).to.equal(1); + expect(locales[0]).to.equal('en-us'); // master locale + }); + + // const localesData = { + // 'locale-1': { code: 'en-us', name: 'English' }, + // 'locale-2': { code: 'es-es', name: 'Spanish' }, + // 'locale-3': { code: 'fr-fr', name: 'French' } + // }; + // const readFileStub = FsUtility.prototype.readFile as sinon.SinonStub; + // readFileStub.returns(localesData); + + // const locales = exportTaxonomies.getLocalesToExport(); + + // expect(locales.length).to.equal(4); // 3 from file + 1 master locale + // expect(locales).to.include('en-us'); + // expect(locales).to.include('es-es'); + // expect(locales).to.include('fr-fr'); + // }); + + it('should handle locales file with missing code field', () => { + const localesData = { + 'locale-1': { name: 'English' }, // missing code + 'locale-2': { code: 'es-es', name: 'Spanish' } + }; + const readFileStub = FsUtility.prototype.readFile as sinon.SinonStub; + readFileStub.returns(localesData); + + const locales = exportTaxonomies.getLocalesToExport(); + + // Should only include locales with code field + expect(locales.length).to.equal(2); // 1 from file + 1 master locale + expect(locales).to.include('en-us'); + expect(locales).to.include('es-es'); + }); + + it('should deduplicate locales with same code', () => { + const localesData = { + 'locale-1': { code: 'en-us', name: 'English US' }, + 'locale-2': { code: 'en-us', name: 'English UK' }, // duplicate code + 'locale-3': { code: 'es-es', name: 'Spanish' } + }; + const readFileStub = FsUtility.prototype.readFile as sinon.SinonStub; + readFileStub.returns(localesData); + + const locales = exportTaxonomies.getLocalesToExport(); + + // Should deduplicate en-us + expect(locales.length).to.equal(2); // 1 unique from file + 1 master locale (but master is also en-us, so total 2) + expect(locales).to.include('en-us'); + expect(locales).to.include('es-es'); + }); + + it('should handle empty locales file', () => { + const readFileStub = FsUtility.prototype.readFile as sinon.SinonStub; + readFileStub.returns({}); + + const locales = exportTaxonomies.getLocalesToExport(); + + expect(locales.length).to.equal(1); // Only master locale + expect(locales[0]).to.equal('en-us'); + }); + }); + + describe('processLocaleExport() method', () => { + it('should export taxonomies for locale when taxonomies exist', async () => { + const exportTaxonomiesStub = sinon.stub(exportTaxonomies, 'exportTaxonomies').resolves(); + exportTaxonomies.taxonomiesByLocale['en-us'] = new Set(['taxonomy-1', 'taxonomy-2']); + + await exportTaxonomies.processLocaleExport('en-us'); + + expect(exportTaxonomiesStub.called).to.be.true; + expect(exportTaxonomiesStub.calledWith('en-us')).to.be.true; + + exportTaxonomiesStub.restore(); + }); + + it('should skip export when no taxonomies exist for locale', async () => { + const exportTaxonomiesStub = sinon.stub(exportTaxonomies, 'exportTaxonomies').resolves(); + exportTaxonomies.taxonomiesByLocale['en-us'] = new Set(); + + await exportTaxonomies.processLocaleExport('en-us'); + + expect(exportTaxonomiesStub.called).to.be.false; + + exportTaxonomiesStub.restore(); + }); + + it('should handle locale with undefined taxonomies set', async () => { + const exportTaxonomiesStub = sinon.stub(exportTaxonomies, 'exportTaxonomies').resolves(); + exportTaxonomies.taxonomiesByLocale['en-us'] = undefined as any; + + await exportTaxonomies.processLocaleExport('en-us'); + + expect(exportTaxonomiesStub.called).to.be.false; + + exportTaxonomiesStub.restore(); + }); + }); + + describe('writeTaxonomiesMetadata() method', () => { + + it('should skip writing when taxonomies object is empty', () => { + const writeFileStub = FsUtility.prototype.writeFile as sinon.SinonStub; + exportTaxonomies.taxonomies = {}; + + exportTaxonomies.writeTaxonomiesMetadata(); + + expect(writeFileStub.called).to.be.false; + }); + + it('should skip writing when taxonomies is null or undefined', () => { + const writeFileStub = FsUtility.prototype.writeFile as sinon.SinonStub; + exportTaxonomies.taxonomies = null as any; + + exportTaxonomies.writeTaxonomiesMetadata(); + + expect(writeFileStub.called).to.be.false; + }); + }); + + describe('fetchTaxonomies() method - locale-based export', () => { + it('should fetch taxonomies with locale code', async () => { + const taxonomies = [ + { uid: 'taxonomy-1', name: 'Category', locale: 'en-us' }, + { uid: 'taxonomy-2', name: 'Tag', locale: 'en-us' } + ]; + + mockStackClient.taxonomy.returns({ + query: sinon.stub().returns({ + find: sinon.stub().resolves({ + items: taxonomies, + count: 2 + }) + }) + }); + + await exportTaxonomies.fetchTaxonomies('en-us'); + + expect(Object.keys(exportTaxonomies.taxonomies).length).to.equal(2); + expect(exportTaxonomies.taxonomiesByLocale['en-us']).to.exist; + expect(exportTaxonomies.taxonomiesByLocale['en-us'].has('taxonomy-1')).to.be.true; + }); + + it('should detect locale-based export support when items have locale field', async () => { + const taxonomies = [ + { uid: 'taxonomy-1', name: 'Category', locale: 'en-us' } + ]; + + mockStackClient.taxonomy.returns({ + query: sinon.stub().returns({ + find: sinon.stub().resolves({ + items: taxonomies, + count: 1 + }) + }) + }); + + await exportTaxonomies.fetchTaxonomies('en-us', true); + + // Should support locale-based export when items have locale field + expect(exportTaxonomies.isLocaleBasedExportSupported).to.be.true; + }); + + it('should disable locale-based export when items lack locale field', async () => { + const taxonomies = [ + { uid: 'taxonomy-1', name: 'Category' } // no locale field + ]; + + mockStackClient.taxonomy.returns({ + query: sinon.stub().returns({ + find: sinon.stub().resolves({ + items: taxonomies, + count: 1 + }) + }) + }); + + await exportTaxonomies.fetchTaxonomies('en-us', true); + + // Should disable locale-based export when items lack locale field + expect(exportTaxonomies.isLocaleBasedExportSupported).to.be.false; + }); + + it('should disable locale-based export on API error when checkLocaleSupport is true', async () => { + // Create a structured API error (not a plan limitation error) + const apiError: any = new Error('API Error'); + apiError.status = 500; + apiError.errors = { general: ['Internal server error'] }; + + mockStackClient.taxonomy.returns({ + query: sinon.stub().returns({ + find: sinon.stub().rejects(apiError) + }) + }); + + await exportTaxonomies.fetchTaxonomies('en-us', true); + + // Should disable locale-based export on error + expect(exportTaxonomies.isLocaleBasedExportSupported).to.be.false; + }); + + it('should handle taxonomy localization plan limitation error gracefully', async () => { + // Create the exact 403 error from the plan limitation + const planLimitationError: any = new Error('Forbidden'); + planLimitationError.status = 403; + planLimitationError.statusText = 'Forbidden'; + planLimitationError.errors = { + taxonomies: ['Taxonomy localization is not included in your plan. Please contact the support@contentstack.com team for assistance.'] + }; + + mockStackClient.taxonomy.returns({ + query: sinon.stub().returns({ + find: sinon.stub().rejects(planLimitationError) + }) + }); + + await exportTaxonomies.fetchTaxonomies('en-us', true); + + // Should disable locale-based export and not throw error + expect(exportTaxonomies.isLocaleBasedExportSupported).to.be.false; + }); + }); + + describe('exportTaxonomies() method - locale-based export', () => { + + it('should skip export when no taxonomies for locale', async () => { + const mockMakeAPICall = sinon.stub(exportTaxonomies, 'makeAPICall').resolves(); + exportTaxonomies.taxonomiesByLocale['en-us'] = new Set(); + + await exportTaxonomies.exportTaxonomies('en-us'); + + expect(mockMakeAPICall.called).to.be.false; + + mockMakeAPICall.restore(); + }); + }); + + describe('start() method - locale-based export scenarios', () => { + it('should use legacy export when locale-based export is not supported', async () => { + const mockFetchTaxonomies = sinon.stub(exportTaxonomies, 'fetchTaxonomies').callsFake(async (locale, checkSupport) => { + if (checkSupport) { + exportTaxonomies.isLocaleBasedExportSupported = false; + } + }); + const mockExportTaxonomies = sinon.stub(exportTaxonomies, 'exportTaxonomies').resolves(); + const mockWriteMetadata = sinon.stub(exportTaxonomies, 'writeTaxonomiesMetadata').resolves(); + const mockGetLocales = sinon.stub(exportTaxonomies, 'getLocalesToExport').returns(['en-us']); + + await exportTaxonomies.start(); + + // Should use legacy export (no locale parameter) + expect(mockExportTaxonomies.called).to.be.true; + expect(mockExportTaxonomies.calledWith()).to.be.true; // Called without locale + expect(mockWriteMetadata.called).to.be.true; + + mockFetchTaxonomies.restore(); + mockExportTaxonomies.restore(); + mockWriteMetadata.restore(); + mockGetLocales.restore(); + }); + + it('should clear taxonomies and re-fetch when falling back to legacy export', async () => { + let fetchCallCount = 0; + const mockFetchTaxonomies = sinon.stub(exportTaxonomies, 'fetchTaxonomies').callsFake(async (locale, checkSupport) => { + fetchCallCount++; + if (checkSupport) { + // First call fails locale check + exportTaxonomies.isLocaleBasedExportSupported = false; + exportTaxonomies.taxonomies = { 'partial-data': { uid: 'partial-data' } }; // Simulate partial data + } else { + // Second call should have cleared data + expect(exportTaxonomies.taxonomies).to.deep.equal({}); + } + }); + const mockExportTaxonomies = sinon.stub(exportTaxonomies, 'exportTaxonomies').resolves(); + const mockWriteMetadata = sinon.stub(exportTaxonomies, 'writeTaxonomiesMetadata').resolves(); + const mockGetLocales = sinon.stub(exportTaxonomies, 'getLocalesToExport').returns(['en-us']); + + await exportTaxonomies.start(); + + // Should call fetchTaxonomies twice: once for check, once for legacy + expect(fetchCallCount).to.equal(2); + // First call with locale, second without + expect(mockFetchTaxonomies.firstCall.args).to.deep.equal(['en-us', true]); + expect(mockFetchTaxonomies.secondCall.args).to.deep.equal([]); + + mockFetchTaxonomies.restore(); + mockExportTaxonomies.restore(); + mockWriteMetadata.restore(); + mockGetLocales.restore(); + }); + + it('should use locale-based export when supported', async () => { + const mockFetchTaxonomies = sinon.stub(exportTaxonomies, 'fetchTaxonomies').callsFake(async (locale, checkSupport) => { + if (checkSupport) { + exportTaxonomies.isLocaleBasedExportSupported = true; + } + if (locale && typeof locale === 'string' && !exportTaxonomies.taxonomiesByLocale[locale]) { + exportTaxonomies.taxonomiesByLocale[locale] = new Set(['taxonomy-1']); + } + }); + const mockProcessLocale = sinon.stub(exportTaxonomies, 'processLocaleExport').resolves(); + const mockWriteMetadata = sinon.stub(exportTaxonomies, 'writeTaxonomiesMetadata').resolves(); + const mockGetLocales = sinon.stub(exportTaxonomies, 'getLocalesToExport').returns(['en-us', 'es-es']); + + await exportTaxonomies.start(); + + // Should process each locale + expect(mockProcessLocale.called).to.be.true; + expect(mockProcessLocale.callCount).to.equal(2); // Two locales + expect(mockWriteMetadata.called).to.be.true; + + mockFetchTaxonomies.restore(); + mockProcessLocale.restore(); + mockWriteMetadata.restore(); + mockGetLocales.restore(); + }); + + it('should return early when no locales to export', async () => { + const mockGetLocales = sinon.stub(exportTaxonomies, 'getLocalesToExport').returns([]); + const mockFetchTaxonomies = sinon.stub(exportTaxonomies, 'fetchTaxonomies').resolves(); + + await exportTaxonomies.start(); + + // Should not fetch taxonomies when no locales + expect(mockFetchTaxonomies.called).to.be.false; + + mockGetLocales.restore(); + mockFetchTaxonomies.restore(); + }); }); }); diff --git a/packages/contentstack-export/test/unit/utils/logger.test.ts b/packages/contentstack-export/test/unit/utils/logger.test.ts new file mode 100644 index 0000000000..9e973037f5 --- /dev/null +++ b/packages/contentstack-export/test/unit/utils/logger.test.ts @@ -0,0 +1,205 @@ +import { expect } from 'chai'; +import sinon from 'sinon'; +import * as os from 'os'; +import * as path from 'path'; +import * as loggerModule from '../../../src/utils/logger'; +import { ExportConfig } from '../../../src/types'; + +describe('Logger', () => { + let mockExportConfig: ExportConfig; + let sandbox: sinon.SinonSandbox; + + beforeEach(() => { + sandbox = sinon.createSandbox(); + + mockExportConfig = { + contentVersion: 1, + versioning: false, + host: 'https://api.contentstack.io', + developerHubUrls: {}, + apiKey: 'test-api-key', + exportDir: path.join(os.tmpdir(), 'test-export'), + data: path.join(os.tmpdir(), 'test-data'), + cliLogsPath: path.join(os.tmpdir(), 'test-logs') as string, + branchName: '', + context: { + command: 'cm:stacks:export', + module: 'test', + userId: 'user-123', + email: 'test@example.com', + sessionId: 'session-123', + apiKey: 'test-api-key', + orgId: 'org-123', + authenticationMethod: 'Basic Auth' + }, + forceStopMarketplaceAppsPrompt: false, + master_locale: { code: 'en-us' }, + region: { + name: 'us', + cma: 'https://api.contentstack.io', + cda: 'https://cdn.contentstack.io', + uiHost: 'https://app.contentstack.com' + }, + skipStackSettings: false, + skipDependencies: false, + languagesCode: ['en'], + apis: {}, + preserveStackVersion: false, + personalizationEnabled: false, + fetchConcurrency: 5, + writeConcurrency: 5, + developerHubBaseUrl: '', + marketplaceAppEncryptionKey: '', + onlyTSModules: [], + modules: {} + } as any; + }); + + afterEach(() => { + sandbox.restore(); + // Clean up loggers after each test + loggerModule.unlinkFileLogger(); + }); + + describe('log() function', () => { + it('should log message when type is not error', async () => { + // Should complete without throwing + await loggerModule.log(mockExportConfig, 'Test message', 'info'); + + // Verify function completed successfully + expect(true).to.be.true; // Basic assertion that function executed + }); + + it('should log error message when type is error', async () => { + // Should complete without throwing + await loggerModule.log(mockExportConfig, 'Error message', 'error'); + + // Verify function completed successfully + expect(true).to.be.true; // Basic assertion that function executed + }); + + it('should use cliLogsPath when available', async () => { + // Should complete without throwing + await loggerModule.log(mockExportConfig, 'Test', 'info'); + + // Verify function completed successfully + expect(true).to.be.true; + }); + + it('should fallback to data path when cliLogsPath is not available', async () => { + const configWithoutLogsPath = { ...mockExportConfig, cliLogsPath: undefined as any }; + + // Should complete without throwing + await loggerModule.log(configWithoutLogsPath, 'Test', 'info'); + + // Verify function completed successfully + expect(true).to.be.true; + }); + + it('should handle object arguments in log message', async () => { + const testObject = { key: 'value', message: 'test' }; + + // Should complete without throwing + await loggerModule.log(mockExportConfig, testObject, 'info'); + + // Verify function completed successfully + expect(true).to.be.true; + }); + + it('should remove ANSI escape codes from log messages', async () => { + const ansiMessage = '\u001B[31mRed text\u001B[0m'; + + // Should complete without throwing + await loggerModule.log(mockExportConfig, ansiMessage, 'info'); + + // Verify function completed successfully + expect(true).to.be.true; + }); + + it('should handle null message arguments', async () => { + // Should complete without throwing + await loggerModule.log(mockExportConfig, null as any, 'info'); + + // Verify function completed successfully + expect(true).to.be.true; + }); + + it('should handle undefined message arguments', async () => { + // Should complete without throwing + await loggerModule.log(mockExportConfig, undefined as any, 'info'); + + // Verify function completed successfully + expect(true).to.be.true; + }); + }); + + describe('unlinkFileLogger() function', () => { + it('should handle undefined logger gracefully', () => { + // Should not throw when logger is not initialized + expect(() => loggerModule.unlinkFileLogger()).to.not.throw(); + }); + + it('should remove file transports after logger is initialized', async () => { + // Initialize logger by calling log + await loggerModule.log(mockExportConfig, 'init', 'info'); + + // Should not throw when removing file transports + expect(() => loggerModule.unlinkFileLogger()).to.not.throw(); + }); + + it('should handle multiple calls gracefully', async () => { + // Initialize logger + await loggerModule.log(mockExportConfig, 'init', 'info'); + + // Should handle multiple calls + loggerModule.unlinkFileLogger(); + expect(() => loggerModule.unlinkFileLogger()).to.not.throw(); + }); + }); + + describe('Logger behavior - integration', () => { + it('should handle different log types correctly', async () => { + // Test all log types + await loggerModule.log(mockExportConfig, 'Info message', 'info'); + await loggerModule.log(mockExportConfig, 'Error message', 'error'); + + // Verify all completed successfully + expect(true).to.be.true; + }); + + it('should handle complex object logging', async () => { + const complexObject = { + nested: { + data: 'value', + array: [1, 2, 3], + nullValue: null as any, + undefinedValue: undefined as any + } + }; + + // Should complete without throwing + await loggerModule.log(mockExportConfig, complexObject, 'info'); + + // Verify function completed successfully + expect(true).to.be.true; + }); + + it('should handle empty string messages', async () => { + // Should complete without throwing + await loggerModule.log(mockExportConfig, '', 'info'); + + // Verify function completed successfully + expect(true).to.be.true; + }); + + it('should handle very long messages', async () => { + const longMessage = 'A'.repeat(10); + + // Should complete without throwing + await loggerModule.log(mockExportConfig, longMessage, 'info'); + + // Verify function completed successfully + expect(true).to.be.true; + }); + }); +}); diff --git a/packages/contentstack-export/test/unit/utils/marketplace-app-helper.test.ts b/packages/contentstack-export/test/unit/utils/marketplace-app-helper.test.ts new file mode 100644 index 0000000000..561b2673fa --- /dev/null +++ b/packages/contentstack-export/test/unit/utils/marketplace-app-helper.test.ts @@ -0,0 +1,376 @@ +import { expect } from 'chai'; +import sinon from 'sinon'; +import * as utilities from '@contentstack/cli-utilities'; +import { getDeveloperHubUrl, getOrgUid, createNodeCryptoInstance } from '../../../src/utils/marketplace-app-helper'; +import { ExportConfig } from '../../../src/types'; + +describe('Marketplace App Helper Utils', () => { + let sandbox: sinon.SinonSandbox; + let mockExportConfig: ExportConfig; + + beforeEach(() => { + sandbox = sinon.createSandbox(); + + mockExportConfig = { + contentVersion: 1, + versioning: false, + host: 'https://api.contentstack.io', + developerHubUrls: {}, + apiKey: 'test-api-key', + exportDir: '/test/export', + data: '/test/data', + branchName: '', + source_stack: 'test-stack-uid', + context: { + command: 'cm:stacks:export', + module: 'marketplace-apps', + userId: 'user-123', + email: 'test@example.com', + sessionId: 'session-123', + apiKey: 'test-api-key', + orgId: 'org-123', + authenticationMethod: 'Basic Auth' + }, + cliLogsPath: '/test/logs', + forceStopMarketplaceAppsPrompt: false, + master_locale: { code: 'en-us' }, + region: { + name: 'us', + cma: 'https://api.contentstack.io', + cda: 'https://cdn.contentstack.io', + uiHost: 'https://app.contentstack.com' + }, + skipStackSettings: false, + skipDependencies: false, + languagesCode: ['en'], + apis: {}, + preserveStackVersion: false, + personalizationEnabled: false, + fetchConcurrency: 5, + writeConcurrency: 5, + developerHubBaseUrl: '', + marketplaceAppEncryptionKey: 'test-encryption-key', + onlyTSModules: [], + modules: { + types: ['marketplace-apps'], + marketplace_apps: { + dirName: 'marketplace-apps', + fileName: 'marketplace-apps.json' + } + } + } as any; + }); + + afterEach(() => { + sandbox.restore(); + }); + + describe('getDeveloperHubUrl', () => { + it('should return developer hub URL by calling createDeveloperHubUrl', async () => { + // Since createDeveloperHubUrl is non-configurable, we test the actual behavior + // The function is a simple wrapper, so we verify it returns a value + const result = await getDeveloperHubUrl(mockExportConfig); + + // Should return a URL (actual implementation behavior) + expect(result).to.be.a('string'); + expect(result).to.include('developer'); + }); + + it('should handle different host URLs', async () => { + mockExportConfig.host = 'https://eu-api.contentstack.com'; + + const result = await getDeveloperHubUrl(mockExportConfig); + + // Should return a URL based on the host + expect(result).to.be.a('string'); + expect(result.length).to.be.greaterThan(0); + }); + + it('should return a valid URL string', async () => { + const result = await getDeveloperHubUrl(mockExportConfig); + + expect(result).to.be.a('string'); + expect(result.length).to.be.greaterThan(0); + }); + }); + + describe('getOrgUid', () => { + it('should fetch and return org_uid from stack data', async () => { + const mockStackData = { + org_uid: 'test-org-uid-123', + name: 'Test Stack', + uid: 'stack-uid' + }; + + const mockFetch = sandbox.stub().resolves(mockStackData); + const mockStack = sandbox.stub().returns({ fetch: mockFetch }); + const mockAPIClient = { + stack: mockStack + }; + + // Use replaceGetter since managementSDKClient is a getter + const managementSDKClientSpy = sandbox.spy(async (config: any) => { + expect(config).to.deep.equal({ host: 'https://api.contentstack.io' }); + return mockAPIClient; + }); + sandbox.replaceGetter(utilities, 'managementSDKClient', () => managementSDKClientSpy); + + const result = await getOrgUid(mockExportConfig); + + expect(managementSDKClientSpy.calledOnce).to.be.true; + expect(mockStack.calledOnce).to.be.true; + expect(mockStack.firstCall.args[0]).to.deep.equal({ api_key: 'test-stack-uid' }); + expect(mockFetch.calledOnce).to.be.true; + expect(result).to.equal('test-org-uid-123'); + }); + + it('should use source_stack from config as api_key', async () => { + mockExportConfig.source_stack = 'custom-stack-key'; + const mockStackData = { org_uid: 'org-123' }; + + const mockFetch = sandbox.stub().resolves(mockStackData); + const mockStack = sandbox.stub().returns({ fetch: mockFetch }); + const mockAPIClient = { stack: mockStack }; + + sandbox.replaceGetter(utilities, 'managementSDKClient', () => async () => mockAPIClient); + + await getOrgUid(mockExportConfig); + + expect(mockStack.firstCall.args[0]).to.deep.equal({ api_key: 'custom-stack-key' }); + }); + + it('should handle API errors gracefully', async () => { + const mockError = new Error('API Error'); + const handleAndLogErrorSpy = sandbox.spy(); + sandbox.replaceGetter(utilities, 'handleAndLogError', () => handleAndLogErrorSpy); + + const mockFetch = sandbox.stub().rejects(mockError); + const mockStack = sandbox.stub().returns({ fetch: mockFetch }); + const mockAPIClient = { stack: mockStack }; + + const managementSDKClientSpy = sandbox.spy(async () => mockAPIClient); + sandbox.replaceGetter(utilities, 'managementSDKClient', () => managementSDKClientSpy); + + const result = await getOrgUid(mockExportConfig); + + expect(handleAndLogErrorSpy.calledOnce).to.be.true; + expect(handleAndLogErrorSpy.getCall(0).args[0]).to.equal(mockError); + expect(handleAndLogErrorSpy.getCall(0).args[1]).to.deep.equal(mockExportConfig.context); + expect(result).to.be.undefined; + }); + + it('should return undefined when stack data is null', async () => { + const mockFetch = sandbox.stub().resolves(null); + const mockStack = sandbox.stub().returns({ fetch: mockFetch }); + const mockAPIClient = { stack: mockStack }; + + sandbox.replaceGetter(utilities, 'managementSDKClient', () => async () => mockAPIClient); + + const result = await getOrgUid(mockExportConfig); + + expect(result).to.be.undefined; + }); + + it('should return undefined when stack data has no org_uid', async () => { + const mockStackData = { + name: 'Test Stack', + uid: 'stack-uid' + // No org_uid property + }; + + const mockFetch = sandbox.stub().resolves(mockStackData); + const mockStack = sandbox.stub().returns({ fetch: mockFetch }); + const mockAPIClient = { stack: mockStack }; + + sandbox.replaceGetter(utilities, 'managementSDKClient', () => async () => mockAPIClient); + + const result = await getOrgUid(mockExportConfig); + + expect(result).to.be.undefined; + }); + + it('should use the correct host from config', async () => { + mockExportConfig.host = 'https://eu-api.contentstack.com'; + const mockStackData = { org_uid: 'org-123' }; + + const mockFetch = sandbox.stub().resolves(mockStackData); + const mockStack = sandbox.stub().returns({ fetch: mockFetch }); + const mockAPIClient = { stack: mockStack }; + + const managementSDKClientSpy = sandbox.spy(async (config: any) => { + expect(config).to.deep.equal({ host: 'https://eu-api.contentstack.com' }); + return mockAPIClient; + }); + sandbox.replaceGetter(utilities, 'managementSDKClient', () => managementSDKClientSpy); + + await getOrgUid(mockExportConfig); + + expect(managementSDKClientSpy.calledOnce).to.be.true; + }); + }); + + describe('createNodeCryptoInstance', () => { + it('should use marketplaceAppEncryptionKey when forceStopMarketplaceAppsPrompt is true', async () => { + mockExportConfig.forceStopMarketplaceAppsPrompt = true; + mockExportConfig.marketplaceAppEncryptionKey = 'test-key-123'; + + const mockNodeCrypto = { encrypt: sandbox.stub() }; + const nodeCryptoConstructorSpy = sandbox.spy((args: any) => { + expect(args.encryptionKey).to.equal('test-key-123'); + return mockNodeCrypto; + }); + sandbox.replaceGetter(utilities, 'NodeCrypto', () => nodeCryptoConstructorSpy as any); + + const result = await createNodeCryptoInstance(mockExportConfig); + + expect(nodeCryptoConstructorSpy.calledOnce).to.be.true; + expect(nodeCryptoConstructorSpy.getCall(0).args[0].encryptionKey).to.equal('test-key-123'); + expect(result).to.exist; + }); + + it('should prompt user for encryption key when forceStopMarketplaceAppsPrompt is false', async () => { + mockExportConfig.forceStopMarketplaceAppsPrompt = false; + mockExportConfig.marketplaceAppEncryptionKey = 'default-key'; + + const mockInquireResponse = 'user-entered-key'; + const inquireStub = sandbox.stub(utilities.cliux, 'inquire').resolves(mockInquireResponse); + + const mockNodeCrypto = { encrypt: sandbox.stub() }; + const nodeCryptoConstructorSpy = sandbox.spy((args: any) => { + expect(args.encryptionKey).to.equal(mockInquireResponse); + return mockNodeCrypto; + }); + sandbox.replaceGetter(utilities, 'NodeCrypto', () => nodeCryptoConstructorSpy as any); + + const result = await createNodeCryptoInstance(mockExportConfig); + + expect(inquireStub.calledOnce).to.be.true; + const inquireArgs = inquireStub.getCall(0).args[0] as any; + expect(inquireArgs.type).to.equal('input'); + expect(inquireArgs.name).to.equal('name'); + expect(inquireArgs.default).to.equal('default-key'); + expect(inquireArgs.message).to.equal('Enter Marketplace app configurations encryption key'); + expect(inquireArgs.validate).to.be.a('function'); + + // Test validation function + expect(inquireArgs.validate('')).to.equal("Encryption key can't be empty."); + expect(inquireArgs.validate('valid-key')).to.equal(true); + + expect(nodeCryptoConstructorSpy.calledOnce).to.be.true; + expect(nodeCryptoConstructorSpy.getCall(0).args[0].encryptionKey).to.equal(mockInquireResponse); + expect(result).to.exist; + }); + + it('should use default encryption key from config when prompting', async () => { + mockExportConfig.forceStopMarketplaceAppsPrompt = false; + mockExportConfig.marketplaceAppEncryptionKey = 'my-default-key'; + + const inquireStub = sandbox.stub(utilities.cliux, 'inquire').resolves('user-key'); + + sandbox.replaceGetter(utilities, 'NodeCrypto', () => sandbox.fake.returns({ encrypt: sandbox.stub() } as any) as any); + + await createNodeCryptoInstance(mockExportConfig); + + const inquireArgs = inquireStub.firstCall.args[0] as any; + expect(inquireArgs.default).to.equal('my-default-key'); + }); + + it('should validate that encryption key is not empty', async () => { + mockExportConfig.forceStopMarketplaceAppsPrompt = false; + + const inquireStub = sandbox.stub(utilities.cliux, 'inquire').callsFake(async (options: any) => { + // Test validation + const opts = Array.isArray(options) ? options[0] : options; + // Empty string should return error message + expect(opts.validate('')).to.equal("Encryption key can't be empty."); + // Non-empty strings should return true (validation doesn't trim) + expect(opts.validate('valid-key')).to.equal(true); + expect(opts.validate('another-valid-key-123')).to.equal(true); + + return 'valid-key'; + }); + + sandbox.replaceGetter(utilities, 'NodeCrypto', () => sandbox.fake.returns({ encrypt: sandbox.stub() } as any) as any); + + await createNodeCryptoInstance(mockExportConfig); + + expect(inquireStub.calledOnce).to.be.true; + }); + + it('should create NodeCrypto instance with correct arguments', async () => { + mockExportConfig.forceStopMarketplaceAppsPrompt = true; + mockExportConfig.marketplaceAppEncryptionKey = 'test-encryption-key'; + + let capturedArgs: any; + const nodeCryptoConstructorSpy = sandbox.spy((args: any) => { + capturedArgs = args; + return { encrypt: sandbox.stub() } as any; + }); + sandbox.replaceGetter(utilities, 'NodeCrypto', () => nodeCryptoConstructorSpy as any); + + await createNodeCryptoInstance(mockExportConfig); + + expect(nodeCryptoConstructorSpy.calledOnce).to.be.true; + expect(capturedArgs).to.deep.equal({ encryptionKey: 'test-encryption-key' }); + }); + + it('should handle empty marketplaceAppEncryptionKey in config', async () => { + mockExportConfig.forceStopMarketplaceAppsPrompt = true; + mockExportConfig.marketplaceAppEncryptionKey = ''; + + const nodeCryptoConstructorSpy = sandbox.spy((args: any) => { + expect(args.encryptionKey).to.equal(''); + return { encrypt: sandbox.stub() } as any; + }); + sandbox.replaceGetter(utilities, 'NodeCrypto', () => nodeCryptoConstructorSpy as any); + + await createNodeCryptoInstance(mockExportConfig); + + expect(nodeCryptoConstructorSpy.getCall(0).args[0].encryptionKey).to.equal(''); + }); + + it('should handle undefined marketplaceAppEncryptionKey in config when prompting', async () => { + mockExportConfig.forceStopMarketplaceAppsPrompt = false; + mockExportConfig.marketplaceAppEncryptionKey = undefined as any; + + const inquireStub = sandbox.stub(utilities.cliux, 'inquire').resolves('prompted-key'); + + sandbox.replaceGetter(utilities, 'NodeCrypto', () => sandbox.fake.returns({ encrypt: sandbox.stub() } as any) as any); + + await createNodeCryptoInstance(mockExportConfig); + + const inquireArgs = inquireStub.firstCall.args[0] as any; + expect(inquireArgs.default).to.be.undefined; + }); + + it('should return NodeCrypto instance', async () => { + mockExportConfig.forceStopMarketplaceAppsPrompt = true; + mockExportConfig.marketplaceAppEncryptionKey = 'test-key'; + + const mockNodeCrypto = { + encrypt: sandbox.stub().returns('encrypted-data') + }; + + sandbox.replaceGetter(utilities, 'NodeCrypto', () => sandbox.fake.returns(mockNodeCrypto) as any); + + const result = await createNodeCryptoInstance(mockExportConfig); + + expect(result).to.equal(mockNodeCrypto); + expect(result.encrypt).to.be.a('function'); + }); + + it('should not prompt when forceStopMarketplaceAppsPrompt is true even if key is empty', async () => { + mockExportConfig.forceStopMarketplaceAppsPrompt = true; + mockExportConfig.marketplaceAppEncryptionKey = ''; + + const inquireStub = sandbox.stub(utilities.cliux, 'inquire'); + + sandbox.replaceGetter(utilities, 'NodeCrypto', () => sandbox.fake.returns({ encrypt: sandbox.stub() } as any) as any); + + await createNodeCryptoInstance(mockExportConfig); + + expect(inquireStub.called).to.be.false; + }); + }); +}); + diff --git a/packages/contentstack-import-setup/README.md b/packages/contentstack-import-setup/README.md index 41d492f0bc..3b608e5f02 100644 --- a/packages/contentstack-import-setup/README.md +++ b/packages/contentstack-import-setup/README.md @@ -47,7 +47,7 @@ $ npm install -g @contentstack/cli-cm-import-setup $ csdx COMMAND running command... $ csdx (--version) -@contentstack/cli-cm-import-setup/1.7.0 darwin-arm64 node-v22.13.1 +@contentstack/cli-cm-import-setup/1.7.1 darwin-arm64 node-v22.13.1 $ csdx --help [COMMAND] USAGE $ csdx COMMAND diff --git a/packages/contentstack-import-setup/package.json b/packages/contentstack-import-setup/package.json index d2b13452c8..c693a46621 100644 --- a/packages/contentstack-import-setup/package.json +++ b/packages/contentstack-import-setup/package.json @@ -5,7 +5,7 @@ "author": "Contentstack", "bugs": "https://github.com/contentstack/cli/issues", "dependencies": { - "@contentstack/cli-command": "~1.6.1", + "@contentstack/cli-command": "~1.7.0", "@contentstack/cli-utilities": "~1.15.0", "@oclif/core": "^4.3.0", "big-json": "^3.2.0", diff --git a/packages/contentstack-import-setup/src/commands/cm/stacks/import-setup.ts b/packages/contentstack-import-setup/src/commands/cm/stacks/import-setup.ts index af1e0dd937..4fa2afddbf 100644 --- a/packages/contentstack-import-setup/src/commands/cm/stacks/import-setup.ts +++ b/packages/contentstack-import-setup/src/commands/cm/stacks/import-setup.ts @@ -13,8 +13,8 @@ import { configHandler, } from '@contentstack/cli-utilities'; -import { ImportConfig } from '../../../types'; -import { setupImportConfig, log } from '../../../utils'; +import { ImportConfig, Context } from '../../../types'; +import { setupImportConfig } from '../../../utils'; import { ImportSetup } from '../../../import'; export default class ImportSetupCommand extends Command { @@ -69,6 +69,10 @@ export default class ImportSetupCommand extends Command { try { const { flags } = await this.parse(ImportSetupCommand); let importSetupConfig = await setupImportConfig(flags); + // Prepare the context object + const context = this.createImportSetupContext(importSetupConfig.apiKey, (importSetupConfig as any).authenticationMethod); + importSetupConfig.context = { ...context }; + // Note setting host to create cma client importSetupConfig.host = this.cmaHost; importSetupConfig.region = this.region; @@ -97,12 +101,11 @@ export default class ImportSetupCommand extends Command { log( importSetupConfig, `Backup folder and mapper files have been successfully created for the stack using the API key ${importSetupConfig.apiKey}.`, - 'success', + importSetupConfig.context, ); - log( - importSetupConfig, + log.success( `The backup folder has been created at '${pathValidator(path.join(importSetupConfig.backupDir))}'.`, - 'success', + importSetupConfig.context, ); } catch (error) { CLIProgressManager.printGlobalSummary(); diff --git a/packages/contentstack-import-setup/src/import/import-setup.ts b/packages/contentstack-import-setup/src/import/import-setup.ts index 76eaaf2de6..716ee60c08 100644 --- a/packages/contentstack-import-setup/src/import/import-setup.ts +++ b/packages/contentstack-import-setup/src/import/import-setup.ts @@ -1,7 +1,6 @@ import { ImportConfig, Modules } from '../types'; -import { backupHandler, log, setupBranchConfig } from '../utils'; -import { ContentstackClient } from '@contentstack/cli-utilities'; -import { validateBranch } from '../utils'; +import { backupHandler, setupBranchConfig, validateBranch } from '../utils'; +import { ContentstackClient, log, handleAndLogError } from '@contentstack/cli-utilities'; export default class ImportSetup { protected config: ImportConfig; @@ -64,8 +63,10 @@ export default class ImportSetup { * @returns {Promise} */ protected async runModuleImports() { + log.debug('Starting module imports', { modules: Object.keys(this.dependencyTree) }); for (const moduleName in this.dependencyTree) { try { + log.debug(`Importing module: ${moduleName}`, { moduleName, dependencies: this.dependencyTree[moduleName] }); const modulePath = `./modules/${moduleName}`; const { default: ModuleClass } = await import(modulePath); @@ -77,11 +78,13 @@ export default class ImportSetup { const moduleInstance = new ModuleClass(modulePayload); await moduleInstance.start(); + log.debug(`Module ${moduleName} imported successfully`); } catch (error) { - log(this.config, `Error occurred while importing '${moduleName}'`, 'error'); + handleAndLogError(error, { ...this.config.context, moduleName }, `Error occurred while importing '${moduleName}'`); throw error; } } + log.debug('All module imports completed'); } /** @@ -98,16 +101,22 @@ export default class ImportSetup { this.config.org_uid = stackDetails.org_uid as string; } + log.debug('Creating backup directory'); const backupDir = await backupHandler(this.config); if (backupDir) { this.config.backupDir = backupDir; + log.debug('Backup directory created', { backupDir }); } + + log.debug('Setting up branch configuration'); await setupBranchConfig(this.config, this.stackAPIClient); + log.debug('Branch configuration completed', { branchName: this.config.branchName }); await this.generateDependencyTree(); await this.runModuleImports(); + log.debug('Import setup process completed successfully'); } catch (error) { - console.log(error); + handleAndLogError(error, { ...this.config.context }, 'Import setup failed'); throw error; } } diff --git a/packages/contentstack-import-setup/src/import/modules/assets.ts b/packages/contentstack-import-setup/src/import/modules/assets.ts index 70e3220304..ef19f832e5 100644 --- a/packages/contentstack-import-setup/src/import/modules/assets.ts +++ b/packages/contentstack-import-setup/src/import/modules/assets.ts @@ -1,9 +1,9 @@ import * as chalk from 'chalk'; -import { log, fsUtil } from '../../utils'; +import { fsUtil } from '../../utils'; import { join } from 'path'; import { AssetRecord, ImportConfig, ModuleClassParams } from '../../types'; import { isEmpty, orderBy, values } from 'lodash'; -import { formatError, FsUtility, sanitizePath } from '@contentstack/cli-utilities'; +import { FsUtility, sanitizePath, log, handleAndLogError } from '@contentstack/cli-utilities'; import BaseImportSetup from './base-setup'; import { MODULE_NAMES, MODULE_CONTEXTS, PROCESS_NAMES, PROCESS_STATUS } from '../../utils'; @@ -96,6 +96,7 @@ export default class AssetImportSetup extends BaseImportSetup { * @returns {Promise} Promise */ async fetchAndMapAssets(): Promise { + log.debug('Starting asset fetch and mapping', { assetsFolderPath: this.assetsFolderPath }); const processName = 'mapping assets'; const indexFileName = 'assets.json'; const basePath = this.assetsFolderPath; @@ -132,7 +133,7 @@ export default class AssetImportSetup extends BaseImportSetup { /* eslint-disable @typescript-eslint/no-unused-vars, guard-for-in */ for (const index in indexer) { const chunk = await fs.readChunkFiles.next().catch((error) => { - log(this.config, error, 'error'); + log.error(String(error), { error }); }); if (chunk) { @@ -163,7 +164,7 @@ export default class AssetImportSetup extends BaseImportSetup { } if (!isEmpty(this.duplicateAssets)) { fsUtil.writeFile(this.duplicateAssetPath, this.duplicateAssets); - log(this.config, `Duplicate asset files are stored at: ${this.duplicateAssetPath}.`, 'info'); + log.info(`Duplicate asset files are stored at: ${this.duplicateAssetPath}.`); } } } diff --git a/packages/contentstack-import-setup/src/import/modules/base-setup.ts b/packages/contentstack-import-setup/src/import/modules/base-setup.ts index 69bea1cde1..799d49324e 100644 --- a/packages/contentstack-import-setup/src/import/modules/base-setup.ts +++ b/packages/contentstack-import-setup/src/import/modules/base-setup.ts @@ -1,5 +1,5 @@ -import { log, fsUtil } from '../../utils'; -import { ApiOptions, CustomPromiseHandler, EnvType, ImportConfig, ModuleClassParams } from '../../types'; +import { fsUtil } from '../../utils'; +import { ApiOptions, CustomPromiseHandler, EnvType, ImportConfig, ModuleClassParams, Modules } from '../../types'; import { chunk, entries, isEmpty, isEqual, last } from 'lodash'; import { CLIProgressManager, configHandler } from '@contentstack/cli-utilities'; @@ -16,9 +16,22 @@ export default class BaseImportSetup { this.dependencies = dependencies; } + /** + * Set the module name in context directly + * @param module - Module name to set + * @returns {void} + */ + protected initializeContext(module?: Modules): void { + if (this.config.context && module) { + this.config.context.module = module; + } + } + async setupDependencies() { + log.debug('Setting up dependencies', { dependencies: this.dependencies }); for (const moduleName of this.dependencies) { try { + log.debug(`Importing dependency module: ${moduleName}`); const modulePath = `./${moduleName}`; const { default: ModuleClass } = await import(modulePath); @@ -29,8 +42,9 @@ export default class BaseImportSetup { const moduleInstance = new ModuleClass(modulePayload); await moduleInstance.start(); + log.debug(`Dependency module ${moduleName} imported successfully`); } catch (error) { - log(this.config, `Error importing '${moduleName}': ${error.message}`, 'error'); + handleAndLogError(error, { ...this.config.context }, `Error importing '${moduleName}'`); } } } @@ -143,7 +157,7 @@ export default class BaseImportSetup { // info: Batch No. 20 of import assets is complete if (currentIndexer) batchMsg += `Current chunk processing is (${currentIndexer}/${indexerCount})`; - log(this.config, `Batch No. (${batchNo}/${totelBatches}) of ${processName} is complete`, 'success'); + log.success(`Batch No. (${batchNo}/${totelBatches}) of ${processName} is complete`); } // if (this.config.modules.assets.displayExecutionTime) { diff --git a/packages/contentstack-import-setup/src/import/modules/content-types.ts b/packages/contentstack-import-setup/src/import/modules/content-types.ts index c06036a33c..ba73a9ae50 100644 --- a/packages/contentstack-import-setup/src/import/modules/content-types.ts +++ b/packages/contentstack-import-setup/src/import/modules/content-types.ts @@ -1,5 +1,5 @@ import * as chalk from 'chalk'; -import { log, fsUtil } from '../../utils'; +import { fsUtil } from '../../utils'; import { join } from 'path'; import { ImportConfig, ModuleClassParams } from '../../types'; import ExtensionImportSetup from './extensions'; diff --git a/packages/contentstack-import-setup/src/import/modules/entries.ts b/packages/contentstack-import-setup/src/import/modules/entries.ts index 412a5e6a76..24ce30f29b 100644 --- a/packages/contentstack-import-setup/src/import/modules/entries.ts +++ b/packages/contentstack-import-setup/src/import/modules/entries.ts @@ -1,4 +1,3 @@ -import { log } from '../../utils'; import { ModuleClassParams } from '../../types'; import BaseImportSetup from './base-setup'; import { MODULE_NAMES, MODULE_CONTEXTS, PROCESS_NAMES, PROCESS_STATUS } from '../../utils'; diff --git a/packages/contentstack-import-setup/src/import/modules/extensions.ts b/packages/contentstack-import-setup/src/import/modules/extensions.ts index 31e108d7f4..2bb7666315 100644 --- a/packages/contentstack-import-setup/src/import/modules/extensions.ts +++ b/packages/contentstack-import-setup/src/import/modules/extensions.ts @@ -1,5 +1,5 @@ import * as chalk from 'chalk'; -import { log, fsUtil } from '../../utils'; +import { fsUtil, fileHelper } from '../../utils'; import { join } from 'path'; import { ImportConfig, ModuleClassParams } from '../../types'; import { isEmpty } from 'lodash'; @@ -71,9 +71,9 @@ export default class ExtensionImportSetup extends BaseImportSetup { progress.completeProcess(PROCESS_NAMES.EXTENSIONS_MAPPER_GENERATION, true); this.completeProgress(true); - log(this.config, `The required setup files for extensions have been generated successfully.`, 'success'); + log.success(`The required setup files for extensions have been generated successfully.`); } else { - log(this.config, 'No extensions found in the content folder.', 'info'); + log.info('No extensions found in the content folder.'); } } catch (error) { this.completeProgress(false, error?.message || 'Extensions mapper generation failed'); diff --git a/packages/contentstack-import-setup/src/import/modules/global-fields.ts b/packages/contentstack-import-setup/src/import/modules/global-fields.ts index 1ade770000..1b2b1e1a40 100644 --- a/packages/contentstack-import-setup/src/import/modules/global-fields.ts +++ b/packages/contentstack-import-setup/src/import/modules/global-fields.ts @@ -1,5 +1,5 @@ import * as chalk from 'chalk'; -import { log, fsUtil } from '../../utils'; +import { fsUtil } from '../../utils'; import { join } from 'path'; import { ImportConfig, ModuleClassParams } from '../../types'; import BaseImportSetup from './base-setup'; diff --git a/packages/contentstack-import-setup/src/import/modules/marketplace-apps.ts b/packages/contentstack-import-setup/src/import/modules/marketplace-apps.ts index 7757a12acd..b59c44b4bc 100644 --- a/packages/contentstack-import-setup/src/import/modules/marketplace-apps.ts +++ b/packages/contentstack-import-setup/src/import/modules/marketplace-apps.ts @@ -1,4 +1,4 @@ -import { log, fsUtil } from '../../utils'; +import { fsUtil, fileHelper } from '../../utils'; import { join } from 'path'; import { ImportConfig, ModuleClassParams } from '../../types'; import { get, isEmpty } from 'lodash'; @@ -10,6 +10,8 @@ import { NodeCrypto, createDeveloperHubUrl, sanitizePath, + log, + handleAndLogError, } from '@contentstack/cli-utilities'; import BaseImportSetup from './base-setup'; import { MODULE_NAMES, MODULE_CONTEXTS, PROCESS_NAMES, PROCESS_STATUS } from '../../utils'; @@ -93,7 +95,7 @@ export default class marketplaceAppImportSetup extends BaseImportSetup { log(this.config, `The required setup files for Marketplace apps have been generated successfully.`, 'success'); } else { - log(this.config, 'No Marketplace apps found in the content folder.', 'info'); + log.info('No Marketplace apps found in the content folder.'); } } catch (error) { this.completeProgress(false, error?.message || 'Marketplace apps mapper generation failed'); diff --git a/packages/contentstack-import-setup/src/import/modules/taxonomies.ts b/packages/contentstack-import-setup/src/import/modules/taxonomies.ts index 10e1f8cf56..98e8f6a15c 100644 --- a/packages/contentstack-import-setup/src/import/modules/taxonomies.ts +++ b/packages/contentstack-import-setup/src/import/modules/taxonomies.ts @@ -2,7 +2,7 @@ import { join } from 'path'; import omit from 'lodash/omit'; import isEmpty from 'lodash/isEmpty'; -import { log, fsUtil, fileHelper } from '../../utils'; +import { fsUtil, fileHelper } from '../../utils'; import { ImportConfig, ModuleClassParams, TaxonomyQueryParams } from '../../types'; import { sanitizePath } from '@contentstack/cli-utilities'; import BaseImportSetup from './base-setup'; @@ -111,7 +111,7 @@ export default class TaxonomiesImportSetup extends BaseImportSetup { this.completeProgress(true); log(this.config, `The required setup files for taxonomies have been generated successfully.`, 'success'); } else { - log(this.config, 'No taxonomies found in the content folder.', 'info'); + log.info('No taxonomies found in the content folder.'); } } catch (error) { this.completeProgress(false, error?.message || 'Taxonomies mapper generation failed'); @@ -159,7 +159,7 @@ export default class TaxonomiesImportSetup extends BaseImportSetup { const locales = this.loadAvailableLocales(); for (const localeCode of Object.keys(locales)) { - log(this.config, `Processing taxonomies for locale: ${localeCode}`, 'info'); + log.info(`Processing taxonomies for locale: ${localeCode}`); for (const taxonomy of Object.values(taxonomies) as any) { try { @@ -213,11 +213,11 @@ export default class TaxonomiesImportSetup extends BaseImportSetup { // Check if master locale folder exists (indicates new locale-based structure) if (!fileHelper.fileExistsSync(masterLocaleFolder)) { - log(this.config, 'No locale-based folder structure detected', 'info'); + log.info('No locale-based folder structure detected'); return false; } - log(this.config, 'Locale-based folder structure detected', 'info'); + log.info('Locale-based folder structure detected'); return true; } @@ -237,17 +237,17 @@ export default class TaxonomiesImportSetup extends BaseImportSetup { // The file contains an object with UID as key, extract the code const firstLocale = Object.values(masterLocaleData)[0]; if (firstLocale?.code) { - log(this.config, `Master locale loaded from file: ${firstLocale.code}`, 'info'); + log.info(`Master locale loaded from file: ${firstLocale.code}`); return firstLocale.code; } } catch (error) { - log(this.config, 'Error reading master-locale.json, using fallback', 'warn'); + log.warn('Error reading master-locale.json, using fallback', { error }); } } // Fallback to config or default const fallbackCode = this.config.master_locale?.code || 'en-us'; - log(this.config, `Using fallback master locale: ${fallbackCode}`, 'info'); + log.info(`Using fallback master locale: ${fallbackCode}`); return fallbackCode; } @@ -264,7 +264,7 @@ export default class TaxonomiesImportSetup extends BaseImportSetup { // Then load additional locales from locales.json if it exists if (!fileHelper.fileExistsSync(this.localesFilePath)) { - log(this.config, 'No locales file found, using only master locale', 'info'); + log.info('No locales file found, using only master locale'); return locales; } @@ -277,14 +277,10 @@ export default class TaxonomiesImportSetup extends BaseImportSetup { } } - log( - this.config, - `Loaded ${Object.keys(locales).length} locales (1 master + ${Object.keys(locales).length - 1} additional)`, - 'info', - ); + log.info(`Loaded ${Object.keys(locales).length} locales (1 master + ${Object.keys(locales).length - 1} additional)`); return locales; } catch (error) { - log(this.config, 'Error loading locales file, using only master locale', 'error'); + log.error('Error loading locales file, using only master locale', { error }); return locales; } } @@ -374,10 +370,9 @@ export default class TaxonomiesImportSetup extends BaseImportSetup { if (err?.errorMessage || err?.message) { const errorMsg = err?.errorMessage || err?.errors?.taxonomy || err?.errors?.term || err?.message; - log(this.config, `${errorMsg}${taxInfo}`, 'error'); + log.error(`${errorMsg}${taxInfo}`, { error: err, taxonomyUid, locale }); } else { - log(this.config, `Error fetching taxonomy data${taxInfo}!`, 'error'); - log(this.config, err, 'error'); + log.error(`Error fetching taxonomy data${taxInfo}!`, { error: err, taxonomyUid, locale }); } } } diff --git a/packages/contentstack-import-setup/src/types/import-config.ts b/packages/contentstack-import-setup/src/types/import-config.ts index 5c68eb773c..eed1ca79ca 100644 --- a/packages/contentstack-import-setup/src/types/import-config.ts +++ b/packages/contentstack-import-setup/src/types/import-config.ts @@ -1,4 +1,4 @@ -import { Modules } from '.'; +import { Modules, Context } from '.'; import DefaultConfig from './default-config'; export interface ExternalConfig { @@ -23,6 +23,7 @@ export interface Context { } export default interface ImportConfig extends DefaultConfig, ExternalConfig { + context?: Context; cliLogsPath?: string; contentDir: string; data: string; diff --git a/packages/contentstack-import-setup/src/types/index.ts b/packages/contentstack-import-setup/src/types/index.ts index 844e765f5a..df9c0b0bda 100644 --- a/packages/contentstack-import-setup/src/types/index.ts +++ b/packages/contentstack-import-setup/src/types/index.ts @@ -152,3 +152,14 @@ export type TaxonomyQueryParams = { depth?: number; locale?: string; }; + +export interface Context { + command: string; + module: string; + userId: string | undefined; + email: string | undefined; + sessionId: string | undefined; + apiKey: string; + orgId: string; + authenticationMethod?: string; +} diff --git a/packages/contentstack-import-setup/src/utils/common-helper.ts b/packages/contentstack-import-setup/src/utils/common-helper.ts index 9ab103e1d0..40aad278a0 100644 --- a/packages/contentstack-import-setup/src/utils/common-helper.ts +++ b/packages/contentstack-import-setup/src/utils/common-helper.ts @@ -1,5 +1,5 @@ import chalk from 'chalk'; -import { log } from '../utils'; +import { log } from '@contentstack/cli-utilities'; import { ImportConfig } from 'src/types'; export const validateBranch = async (stackAPIClient: any, config: ImportConfig, branch: any) => { @@ -8,8 +8,8 @@ export const validateBranch = async (stackAPIClient: any, config: ImportConfig, const data = await stackAPIClient.branch(branch).fetch(); if (data && typeof data === 'object') { if (data.error_message) { - log(config, chalk.red(data.error_message), 'error'); - log(config, chalk.red('No branch found with the name ' + branch), 'error'); + log.error(chalk.red(data.error_message), { error: data.error_message }); + log.error(chalk.red('No branch found with the name ' + branch), { branch }); reject({ message: 'No branch found with the name ' + branch, error: data.error_message }); } else { resolve(data); @@ -18,7 +18,7 @@ export const validateBranch = async (stackAPIClient: any, config: ImportConfig, reject({ message: 'No branch found with the name ' + branch, error: {} }); } } catch (error) { - log(config, chalk.red('No branch found with the name ' + branch), 'error'); + log.error(chalk.red('No branch found with the name ' + branch), { error, branch }); reject({ message: 'No branch found with the name ' + branch, error }); } }); diff --git a/packages/contentstack-import-setup/src/utils/file-helper.ts b/packages/contentstack-import-setup/src/utils/file-helper.ts index e5c613b90d..3c972dd436 100644 --- a/packages/contentstack-import-setup/src/utils/file-helper.ts +++ b/packages/contentstack-import-setup/src/utils/file-helper.ts @@ -2,7 +2,7 @@ import * as fs from 'fs'; import * as path from 'path'; import mkdirp from 'mkdirp'; import * as bigJSON from 'big-json'; -import { FsUtility, sanitizePath } from '@contentstack/cli-utilities'; +import { FsUtility, sanitizePath, log } from '@contentstack/cli-utilities'; export const readFileSync = function (filePath: string, parse: boolean = true): any { let data; @@ -53,7 +53,7 @@ export const readLargeFile = function (filePath: string, opts?: any): Promise => { config.contentDir = sanitizePath(importCmdFlags['data'] || importCmdFlags['data-dir'] || config.data || (await askContentDir())); const pattern = /[*$%#<>{}!&?]/g; if (pattern.test(config.contentDir)) { - cliux.print(`\nPlease add a directory path without any of the special characters: (*,&,{,},[,],$,%,<,>,?,!)`, { + cliux.print(`\nPlease enter a directory path without special characters: (*,&,{,},[,],$,%,<,>,?,!)`, { color: 'yellow', }); config.contentDir = sanitizePath(await askContentDir()); diff --git a/packages/contentstack-import-setup/src/utils/login-handler.ts b/packages/contentstack-import-setup/src/utils/login-handler.ts index 996e7797a8..62692807a1 100644 --- a/packages/contentstack-import-setup/src/utils/login-handler.ts +++ b/packages/contentstack-import-setup/src/utils/login-handler.ts @@ -7,8 +7,7 @@ * MIT Licensed */ -import { log } from './logger'; -import { managementSDKClient, isAuthenticated } from '@contentstack/cli-utilities'; +import { managementSDKClient, isAuthenticated, log } from '@contentstack/cli-utilities'; import { ImportConfig } from '../types'; const login = async (config: ImportConfig): Promise => { @@ -22,7 +21,7 @@ const login = async (config: ImportConfig): Promise => { authtoken: config.authtoken, 'X-User-Agent': 'contentstack-export/v', }; - log(config, 'Contentstack account authenticated successfully!', 'success'); + log.success('Contentstack account authenticated successfully!'); return config; } else { throw new Error('Invalid auth token received after login'); @@ -37,10 +36,10 @@ const login = async (config: ImportConfig): Promise => { const stack = await stackAPIClient.fetch().catch((error: any) => { let errorstack_key = error?.errors?.api_key; if (errorstack_key) { - log(config, 'Stack Api key ' + errorstack_key[0] + 'Please enter valid Key', 'error'); + log.error('Stack Api key ' + errorstack_key[0] + 'Please enter valid Key', { error }); throw error; } - log(config, error?.errorMessage, 'error'); + log.error(error?.errorMessage || 'Unknown error', { error }); throw error; }); config.destinationStackName = stack.name; diff --git a/packages/contentstack-import-setup/src/utils/setup-branch.ts b/packages/contentstack-import-setup/src/utils/setup-branch.ts index 8bcdd81238..2d7ac98151 100644 --- a/packages/contentstack-import-setup/src/utils/setup-branch.ts +++ b/packages/contentstack-import-setup/src/utils/setup-branch.ts @@ -30,6 +30,6 @@ export const setupBranchConfig = async ( log.debug(`Setting default target branch to 'main'`); } } catch (error) { - log.debug('Failed to fetch branches', { error }); + log.error('Failed to fetch branches', { error }); } }; diff --git a/packages/contentstack-import/messages/index.json b/packages/contentstack-import/messages/index.json index 9e26dfeeb6..32280640fb 100644 --- a/packages/contentstack-import/messages/index.json +++ b/packages/contentstack-import/messages/index.json @@ -1 +1,10 @@ -{} \ No newline at end of file +{ + "COMPOSABLE_STUDIO_IMPORT_START": "Starting Studio project import...", + "COMPOSABLE_STUDIO_NOT_FOUND": "No Studio project found in exported data", + "COMPOSABLE_STUDIO_SKIP_EXISTING": "Skipping Studio import - target stack already has a connected project", + "COMPOSABLE_STUDIO_IMPORT_COMPLETE": "Successfully imported Studio project '%s'", + "COMPOSABLE_STUDIO_IMPORT_FAILED": "Failed to import Studio project: %s", + "COMPOSABLE_STUDIO_NAME_CONFLICT": "Project name '%s' already exists. Please provide a new name:", + "COMPOSABLE_STUDIO_SUGGEST_NAME": "Suggested name: %s", + "COMPOSABLE_STUDIO_ENV_MAPPING_FAILED": "Warning: Could not map environment '%s', using empty environment" +} diff --git a/packages/contentstack-import/package.json b/packages/contentstack-import/package.json index a52b631d19..f8b38f1953 100644 --- a/packages/contentstack-import/package.json +++ b/packages/contentstack-import/package.json @@ -5,8 +5,8 @@ "author": "Contentstack", "bugs": "https://github.com/contentstack/cli/issues", "dependencies": { - "@contentstack/cli-audit": "~1.16.0", - "@contentstack/cli-command": "~1.6.1", + "@contentstack/cli-audit": "~1.16.1", + "@contentstack/cli-command": "~1.7.0", "@contentstack/cli-utilities": "~1.15.0", "@contentstack/management": "~1.22.0", "@contentstack/cli-variants": "~2.0.0-beta.2", diff --git a/packages/contentstack-import/src/commands/cm/stacks/import.ts b/packages/contentstack-import/src/commands/cm/stacks/import.ts index 968c348cc3..538673e686 100644 --- a/packages/contentstack-import/src/commands/cm/stacks/import.ts +++ b/packages/contentstack-import/src/commands/cm/stacks/import.ts @@ -76,7 +76,7 @@ export default class ImportCommand extends Command { required: false, char: 'm', description: - '[optional] Specify the module to import into the target stack. If not specified, the import command will import all the modules into the stack. The available modules are assets, content-types, entries, environments, extensions, marketplace-apps, global-fields, labels, locales, webhooks, workflows, custom-roles, personalize projects, and taxonomies.', + '[optional] Specify the module to import into the target stack. If not specified, the import command will import all the modules into the stack. The available modules are assets, content-types, entries, environments, extensions, marketplace-apps, global-fields, labels, locales, webhooks, workflows, custom-roles, personalize projects, taxonomies, and composable-studio.', parse: printFlagDeprecation(['-m'], ['--module']), }), 'backup-dir': flags.string({ @@ -93,7 +93,7 @@ export default class ImportCommand extends Command { }), 'branch-alias': flags.string({ description: - "Specify the branch alias where you want to import your content. If not specified, the content is imported into the main branch by default.", + 'Specify the branch alias where you want to import your content. If not specified, the content is imported into the main branch by default.', exclusive: ['branch'], }), 'import-webhook-status': flags.string({ @@ -159,13 +159,14 @@ export default class ImportCommand extends Command { // Prepare the context object const context = this.createImportContext(importConfig.apiKey, importConfig.authenticationMethod); importConfig.context = { ...context }; - //log.info(`Using Cli Version: ${this.context?.cliVersion}`, importConfig.context); + // log.info(`Using CLI version: ${this.context?.cliVersion}`, importConfig.context); // Note setting host to create cma client importConfig.host = this.cmaHost; importConfig.region = this.region; if (this.developerHubUrl) importConfig.developerHubBaseUrl = this.developerHubUrl; if (this.personalizeUrl) importConfig.modules.personalize.baseURL[importConfig.region.name] = this.personalizeUrl; + if (this.composableStudioUrl) importConfig.modules['composable-studio'].apiBaseUrl = this.composableStudioUrl; const managementAPIClient: ContentstackClient = await managementSDKClient(importConfig); diff --git a/packages/contentstack-import/src/config/index.ts b/packages/contentstack-import/src/config/index.ts index 8afa6d5115..9dcbba22d9 100644 --- a/packages/contentstack-import/src/config/index.ts +++ b/packages/contentstack-import/src/config/index.ts @@ -44,6 +44,7 @@ const config: DefaultConfig = { 'variant-entries', 'labels', 'webhooks', + 'composable-studio', ], locales: { dirName: 'locales', @@ -199,6 +200,12 @@ const config: DefaultConfig = { locale: 'en-us', }, }, + 'composable-studio': { + dirName: 'composable_studio', + fileName: 'composable_studio.json', + apiBaseUrl: 'https://composable-studio-api.contentstack.com', + apiVersion: 'v1', + }, }, languagesCode: [ 'af-za', diff --git a/packages/contentstack-import/src/import/modules/assets.ts b/packages/contentstack-import/src/import/modules/assets.ts index e5625e1a3c..2b98580b38 100644 --- a/packages/contentstack-import/src/import/modules/assets.ts +++ b/packages/contentstack-import/src/import/modules/assets.ts @@ -127,13 +127,13 @@ export default class ImportAssets extends BaseClass { const folders = this.fs.readFile(foldersPath); if (isEmpty(folders)) { - log.info('No folders found to import', this.importConfig.context); + log.info('No folders found to import.', this.importConfig.context); return; } - log.debug(`Found ${folders.length} folders to import`, this.importConfig.context); + log.debug(`Found ${folders.length} folders to import.`, this.importConfig.context); const batches = this.constructFolderImportOrder(folders); - log.debug(`Organized folders into ${batches.length} batches for import`, this.importConfig.context); + log.debug(`Organized folders into ${batches.length} batches for import.`, this.importConfig.context); const onSuccess = ({ response, apiData: { uid, name } = { uid: null, name: '' } }: any) => { this.assetsFolderMap[uid] = response.uid; @@ -166,7 +166,7 @@ export default class ImportAssets extends BaseClass { }; const batch = map(unionBy(batches, 'parent_uid'), 'parent_uid'); - log.debug(`Processing ${batch.length} folder batches`, this.importConfig.context); + log.debug(`Processing ${batch.length} folder batches.`, this.importConfig.context); for (const parent_uid of batch) { const currentBatch = filter(batches, { parent_uid }); @@ -252,7 +252,7 @@ export default class ImportAssets extends BaseClass { log.debug(`Processing ${apiContent.length} assets in chunk`, this.importConfig.context); if (isVersion && this.assetConfig.importSameStructure) { - log.debug('Processing version 1 assets first', this.importConfig.context); + log.debug('Processing version 1 assets first...', this.importConfig.context); const versionOneAssets = filter(apiContent, ({ _version }) => _version === 1); await this.makeConcurrentCall({ @@ -357,7 +357,7 @@ export default class ImportAssets extends BaseClass { async publish() { const fs = new FsUtility({ basePath: this.assetsPath, indexFileName: 'assets.json' }); if (isEmpty(this.assetsUidMap)) { - log.debug('Loading asset UID mappings from file', this.importConfig.context); + log.debug('Loading asset UID mappings from file...', this.importConfig.context); this.assetsUidMap = fs.readFile(this.assetUidMapperPath, true) as any; } @@ -393,7 +393,7 @@ export default class ImportAssets extends BaseClass { if (environments.length === 0 || locales.length === 0) { log.debug( - `Skipping publish for asset ${asset.uid} - no valid environments/locales`, + `Skipping publish for asset ${asset.uid}: no valid environments/locales`, this.importConfig.context, ); apiOptions.entity = undefined; @@ -409,7 +409,7 @@ export default class ImportAssets extends BaseClass { apiOptions.uid = this.assetsUidMap[asset.uid] as string; if (!apiOptions.uid) { - log.debug(`Skipping publish for asset ${asset.uid} - no UID mapping found`, this.importConfig.context); + log.debug(`Skipping publish for asset ${asset.uid}: no UID mapping found.`, this.importConfig.context); apiOptions.entity = undefined; } @@ -468,7 +468,7 @@ export default class ImportAssets extends BaseClass { } if (this.importConfig.replaceExisting) { - log.debug('Setting up root folder for import', this.importConfig.context); + log.debug('Setting up root folder for import...', this.importConfig.context); // Note: adds a root folder to distinguish latest asset uploads // Todo: This temporary approach should be updated with asset and folder overwrite strategy, which follows // folder overwrite @@ -492,7 +492,7 @@ export default class ImportAssets extends BaseClass { }); importOrder.unshift(this.rootFolder); - log.debug('Added root folder to import order', this.importConfig.context); + log.debug('Added root folder to import order.', this.importConfig.context); } return importOrder; } diff --git a/packages/contentstack-import/src/import/modules/composable-studio.ts b/packages/contentstack-import/src/import/modules/composable-studio.ts new file mode 100644 index 0000000000..521384692d --- /dev/null +++ b/packages/contentstack-import/src/import/modules/composable-studio.ts @@ -0,0 +1,301 @@ +import { join } from 'node:path'; +import { + cliux, + log, + messageHandler, + handleAndLogError, + HttpClient, + authenticationHandler, +} from '@contentstack/cli-utilities'; +import isEmpty from 'lodash/isEmpty'; + +import { fsUtil, fileHelper } from '../../utils'; +import { ImportConfig, ModuleClassParams, ComposableStudioConfig, ComposableStudioProject } from '../../types'; + +export default class ImportComposableStudio { + private importConfig: ImportConfig; + private composableStudioConfig: ComposableStudioConfig; + private composableStudioPath: string; + private composableStudioFilePath: string; + private apiClient: HttpClient; + private envUidMapperPath: string; + private envUidMapper: Record; + + constructor({ importConfig }: ModuleClassParams) { + this.importConfig = importConfig; + this.importConfig.context.module = 'composable-studio'; + this.composableStudioConfig = importConfig.modules['composable-studio']; + + // Setup paths + this.composableStudioPath = join(this.importConfig.backupDir, this.composableStudioConfig.dirName); + this.composableStudioFilePath = join(this.composableStudioPath, this.composableStudioConfig.fileName); + this.envUidMapperPath = join(this.importConfig.backupDir, 'mapper', 'environments', 'uid-mapping.json'); + this.envUidMapper = {}; + + // Initialize HttpClient with Studio API base URL + this.apiClient = new HttpClient(); + this.apiClient.baseUrl(`${this.composableStudioConfig.apiBaseUrl}/${this.composableStudioConfig.apiVersion}`); + } + + /** + * Entry point for Studio import + */ + async start(): Promise { + if (this.importConfig.management_token) { + log.warn('Skipping Studio project import when using management token', this.importConfig.context); + return; + } + + log.debug('Starting Studio project import process...', this.importConfig.context); + + try { + // Initialize authentication + const authInitialized = await this.addAuthHeaders(); + if (!authInitialized) { + log.warn('Skipping Studio project import when using OAuth authentication', this.importConfig.context); + return; + } + + // Load environment UID mapper + await this.loadEnvironmentMapper(); + + // Read exported project data + const exportedProject = await this.readExportedProject(); + if (!exportedProject) { + log.warn(messageHandler.parse('COMPOSABLE_STUDIO_NOT_FOUND'), this.importConfig.context); + return; + } + + log.debug(`Exported project found: ${exportedProject.name}`, this.importConfig.context); + + // Check if target stack already has a connected project + const existingProject = await this.getExistingProject(); + if (existingProject) { + log.warn(messageHandler.parse('COMPOSABLE_STUDIO_SKIP_EXISTING'), this.importConfig.context); + return; + } + + // Import the project with name conflict handling + await this.importProject(exportedProject); + + log.success( + messageHandler.parse('COMPOSABLE_STUDIO_IMPORT_COMPLETE', exportedProject.name), + this.importConfig.context, + ); + } catch (error) { + handleAndLogError(error, { ...this.importConfig.context }); + } + } + + /** + * Initialize authentication headers for API calls + */ + async addAuthHeaders(): Promise { + log.debug('Initializing Studio API authentication...', this.importConfig.context); + + // Get authentication details - following personalization-api-adapter pattern + await authenticationHandler.getAuthDetails(); + const token = authenticationHandler.accessToken; + log.debug( + `Authentication type: ${authenticationHandler.isOauthEnabled ? 'OAuth' : 'Token'}`, + this.importConfig.context, + ); + + // Set authentication headers based on auth type + if (authenticationHandler.isOauthEnabled) { + log.debug( + 'Skipping setting OAuth authorization header when using OAuth authentication', + this.importConfig.context, + ); + return false; + } else { + // TODO: Currenlty assuming if auth type is not OAuth, it is Basic Auth and we are setting authtoken header + log.debug('Setting authtoken header', this.importConfig.context); + this.apiClient.headers({ authtoken: token }); + } + + // Set organization_uid header + this.apiClient.headers({ + organization_uid: this.importConfig.org_uid, + 'Content-Type': 'application/json', + Accept: 'application/json', + }); + + log.debug('Studio API authentication initialized', this.importConfig.context); + return true; + } + + /** + * Load environment UID mapper from backup directory + */ + async loadEnvironmentMapper(): Promise { + log.debug('Loading environment UID mapper...', this.importConfig.context); + + if (fileHelper.fileExistsSync(this.envUidMapperPath)) { + this.envUidMapper = fileHelper.readFileSync(this.envUidMapperPath) as Record; + log.debug( + `Environment mapper loaded with ${Object.keys(this.envUidMapper).length} mappings`, + this.importConfig.context, + ); + } else { + log.debug('No environment UID mapper found', this.importConfig.context); + } + } + + /** + * Read exported project from file system + */ + async readExportedProject(): Promise { + log.debug(`Reading exported project from: ${this.composableStudioFilePath}`, this.importConfig.context); + + if (!fileHelper.fileExistsSync(this.composableStudioFilePath)) { + log.debug('Studio project file does not exist', this.importConfig.context); + return null; + } + + const projectData = fileHelper.readFileSync(this.composableStudioFilePath) as ComposableStudioProject; + + if (!projectData || isEmpty(projectData)) { + log.debug('Studio project file is empty', this.importConfig.context); + return null; + } + + return projectData; + } + + /** + * Check if target stack already has a connected project + */ + async getExistingProject(): Promise { + log.debug('Checking if target stack already has a connected project...', this.importConfig.context); + + try { + const apiUrl = '/projects'; + log.debug( + `Fetching projects from: ${this.composableStudioConfig.apiBaseUrl}${apiUrl}`, + this.importConfig.context, + ); + + const response = await this.apiClient.get(apiUrl); + + if (response.status < 200 || response.status >= 300) { + throw new Error(`API call failed with status ${response.status}: ${JSON.stringify(response.data)}`); + } + + const projects = response.data?.projects || []; + log.debug(`Found ${projects.length} projects in organization`, this.importConfig.context); + + // Filter projects by connected stack API key + const connectedProject = projects.find( + (project: ComposableStudioProject) => project.connectedStackApiKey === this.importConfig.apiKey, + ); + + if (connectedProject) { + log.debug(`Target stack already has connected project: ${connectedProject.name}`, this.importConfig.context); + return connectedProject; + } + + log.debug('Target stack does not have a connected project', this.importConfig.context); + return null; + } catch (error) { + log.debug(`Error checking for existing project: ${error.message}`, this.importConfig.context); + throw error; + } + } + + /** + * Import project with name conflict handling + */ + async importProject(exportedProject: ComposableStudioProject): Promise { + log.debug('Starting project import...', this.importConfig.context); + + // Map environment UID + const mappedEnvironmentUid = this.mapEnvironmentUid(exportedProject.settings.configuration.environment); + + // Prepare project data for import + const projectData = { + name: exportedProject.name, + connectedStackApiKey: this.importConfig.apiKey, + contentTypeUid: exportedProject.contentTypeUid, + description: exportedProject.description || '', + canvasUrl: exportedProject.canvasUrl || '/', + settings: { + configuration: { + environment: mappedEnvironmentUid, + locale: exportedProject?.settings?.configuration?.locale || '', + }, + }, + }; + + log.debug(`Project data prepared: ${JSON.stringify(projectData, null, 2)}`, this.importConfig.context); + + // Try to create project with name conflict retry loop + let projectCreated = false; + let currentName = projectData.name; + let attemptCount = 0; + + while (!projectCreated) { + attemptCount++; + log.debug(`Attempt ${attemptCount} to create project with name: ${currentName}`, this.importConfig.context); + + projectData.name = currentName; + const response = await this.apiClient.post('/projects', projectData); + + if (response.status >= 200 && response.status < 300) { + projectCreated = true; + log.debug(`Project created successfully with UID: ${response.data?.uid}`, this.importConfig.context); + } else { + throw new Error(`API call failed with status ${response.status}: ${JSON.stringify(response.data)}`); + } + } + } + + /** + * Map environment UID from source to target + */ + mapEnvironmentUid(sourceEnvUid: string): string { + if (!sourceEnvUid) { + log.debug('Source environment UID is empty', this.importConfig.context); + return ''; + } + + log.debug(`Mapping source environment UID: ${sourceEnvUid}`, this.importConfig.context); + + if (isEmpty(this.envUidMapper)) { + log.warn(messageHandler.parse('COMPOSABLE_STUDIO_ENV_MAPPING_FAILED', sourceEnvUid), this.importConfig.context); + return ''; + } + + const mappedUid = this.envUidMapper[sourceEnvUid]; + + if (!mappedUid) { + log.warn(messageHandler.parse('COMPOSABLE_STUDIO_ENV_MAPPING_FAILED', sourceEnvUid), this.importConfig.context); + return ''; + } + + log.debug(`Mapped environment UID: ${sourceEnvUid} → ${mappedUid}`, this.importConfig.context); + return mappedUid; + } + + /** + * Prompt user for a new project name when conflict occurs + */ + async promptForNewProjectName(currentName: string): Promise { + const suggestedName = `Copy of ${currentName}`; + + log.warn(messageHandler.parse('COMPOSABLE_STUDIO_NAME_CONFLICT', currentName), this.importConfig.context); + log.info(messageHandler.parse('COMPOSABLE_STUDIO_SUGGEST_NAME', suggestedName), this.importConfig.context); + + const response: any = await cliux.inquire({ + type: 'input', + name: 'projectName', + message: 'Enter new project name:', + default: suggestedName, + }); + + const newName = response.projectName || suggestedName; + log.debug(`User provided new project name: ${newName}`, this.importConfig.context); + + return newName; + } +} diff --git a/packages/contentstack-import/src/import/modules/content-types.ts b/packages/contentstack-import/src/import/modules/content-types.ts index bb82baaf02..87f30e1b6b 100644 --- a/packages/contentstack-import/src/import/modules/content-types.ts +++ b/packages/contentstack-import/src/import/modules/content-types.ts @@ -151,7 +151,7 @@ export default class ContentTypesImport extends BaseClass { PROCESS_NAMES.CONTENT_TYPES_CREATE, ); if (error.errorCode === 115 && (error.errors.uid || error.errors.title)) { - log.info(`${uid} content type already exist`, this.importConfig.context); + log.info(`${uid} content type already exists.`, this.importConfig.context); log.debug(`Skipping existing content type: ${uid}`, this.importConfig.context); } else { handleAndLogError(error, { ...this.importConfig.context, uid }, `Failed to seed content type ${uid}`); @@ -351,7 +351,7 @@ export default class ContentTypesImport extends BaseClass { if (!apiContent || apiContent?.length === 0) { log.info(`No extensions found to be updated.`, this.importConfig.context); - log.debug('Skipping extensions update - no pending extensions', this.importConfig.context); + log.debug('Skipping extensions update – no pending extensions.', this.importConfig.context); return; } @@ -387,7 +387,7 @@ export default class ContentTypesImport extends BaseClass { } }; - log.debug('Starting extensions update process', this.importConfig.context); + log.debug('Starting extensions update process...', this.importConfig.context); return await this.makeConcurrentCall( { apiContent, diff --git a/packages/contentstack-import/src/import/modules/custom-roles.ts b/packages/contentstack-import/src/import/modules/custom-roles.ts index cb8973ffaf..f06aa5321b 100644 --- a/packages/contentstack-import/src/import/modules/custom-roles.ts +++ b/packages/contentstack-import/src/import/modules/custom-roles.ts @@ -83,7 +83,7 @@ export default class ImportCustomRoles extends BaseClass { } async getLocalesUidMap(): Promise { - log.debug('Fetching target stack locales', this.importConfig.context); + log.debug('Fetching target stack locales...', this.importConfig.context); const { items } = await this.stack .locale() .query() @@ -100,18 +100,18 @@ export default class ImportCustomRoles extends BaseClass { this.targetLocalesMap = {}; this.sourceLocalesMap = {}; - log.debug('Building target locales mapping', this.importConfig.context); + log.debug('Building target locales mapping...', this.importConfig.context); forEach(items, (locale: any) => { this.targetLocalesMap[locale.code] = locale.uid; }); - log.debug('Building source locales mapping', this.importConfig.context); + log.debug('Building source locales mapping...', this.importConfig.context); for (const key in this.customRolesLocales) { const sourceLocales = this.customRolesLocales[key] as Record; this.sourceLocalesMap[sourceLocales.code] = key; } - log.debug('Creating locale UID mapping', this.importConfig.context); + log.debug('Creating locale UID mapping...', this.importConfig.context); for (const key in this.sourceLocalesMap) { const sourceLocaleKey = this.sourceLocalesMap[key] as string; this.localesUidMap[sourceLocaleKey] = this.targetLocalesMap[key]; @@ -122,9 +122,9 @@ export default class ImportCustomRoles extends BaseClass { } async importCustomRoles() { - log.debug('Starting custom roles import process', this.importConfig.context); + log.debug('Starting custom roles import process...', this.importConfig.context); if (this.customRoles === undefined || isEmpty(this.customRoles)) { - log.info('No custom-roles found', this.importConfig.context); + log.info('No custom roles found', this.importConfig.context); return; } @@ -255,7 +255,7 @@ export default class ImportCustomRoles extends BaseClass { rule.environments = map(rule.environments, (env: any) => this.environmentsUidMap[env]); log.debug(`Transformed ${originalEnvs} environment UIDs for rule`, this.importConfig.context); } else { - log.debug('No environment UID mappings available for transformation', this.importConfig.context); + log.debug('No environment UID mappings available for transformation.', this.importConfig.context); } } else if (rule.module === 'locale') { if (!isEmpty(this.localesUidMap)) { @@ -263,7 +263,7 @@ export default class ImportCustomRoles extends BaseClass { rule.locales = map(rule.locales, (locale: any) => this.localesUidMap[locale]); log.debug(`Transformed ${originalLocales} locale UIDs for rule`, this.importConfig.context); } else { - log.debug('No locale UID mappings available for transformation', this.importConfig.context); + log.debug('No locale UID mappings available for transformation.', this.importConfig.context); } } else if (rule.module === 'entry') { if (!isEmpty(this.entriesUidMap)) { @@ -271,7 +271,7 @@ export default class ImportCustomRoles extends BaseClass { rule.entries = map(rule.entries, (entry: any) => this.entriesUidMap[entry]); log.debug(`Transformed ${originalEntries} entry UIDs for rule`, this.importConfig.context); } else { - log.debug('No entry UID mappings available for transformation', this.importConfig.context); + log.debug('No entry UID mappings available for transformation.', this.importConfig.context); } } return rule; diff --git a/packages/contentstack-import/src/import/modules/entries.ts b/packages/contentstack-import/src/import/modules/entries.ts index beeee5a90b..d3ca6dfc21 100644 --- a/packages/contentstack-import/src/import/modules/entries.ts +++ b/packages/contentstack-import/src/import/modules/entries.ts @@ -1170,7 +1170,7 @@ export default class EntriesImport extends BaseClass { any >[]; if (!cTsWithFieldRules || cTsWithFieldRules?.length === 0) { - log.debug('No content types with field rules found to update', this.importConfig.context); + log.debug('No content types with field rules found to update.', this.importConfig.context); return; } diff --git a/packages/contentstack-import/src/import/modules/environments.ts b/packages/contentstack-import/src/import/modules/environments.ts index db9ba6ddb2..e9681e49c1 100644 --- a/packages/contentstack-import/src/import/modules/environments.ts +++ b/packages/contentstack-import/src/import/modules/environments.ts @@ -64,9 +64,9 @@ export default class ImportEnvironments extends BaseClass { } async importEnvironments() { - log.debug('Validating environments data', this.importConfig.context); + log.debug('Validating environment data...', this.importConfig.context); if (this.environments === undefined || isEmpty(this.environments)) { - log.info('No Environment Found', this.importConfig.context); + log.info('No environment found.', this.importConfig.context); return; } @@ -132,7 +132,7 @@ export default class ImportEnvironments extends BaseClass { false, ); - log.debug('Environments import process completed', this.importConfig.context); + log.debug('Environment import process completed.', this.importConfig.context); } /** diff --git a/packages/contentstack-import/src/import/modules/extensions.ts b/packages/contentstack-import/src/import/modules/extensions.ts index eb205d792d..072fab6b49 100644 --- a/packages/contentstack-import/src/import/modules/extensions.ts +++ b/packages/contentstack-import/src/import/modules/extensions.ts @@ -97,7 +97,7 @@ export default class ImportExtensions extends BaseClass { async importExtensions(): Promise { log.debug('Starting Create process', this.importConfig.context); if (this.extensions === undefined || isEmpty(this.extensions)) { - log.info('No Extensions Found', this.importConfig.context); + log.info('No extensions found.', this.importConfig.context); return; } diff --git a/packages/contentstack-import/src/import/modules/global-fields.ts b/packages/contentstack-import/src/import/modules/global-fields.ts index bc13201eaa..888d624b80 100644 --- a/packages/contentstack-import/src/import/modules/global-fields.ts +++ b/packages/contentstack-import/src/import/modules/global-fields.ts @@ -178,7 +178,7 @@ export default class ImportGlobalFields extends BaseClass { ); } if (!this.importConfig.skipExisting) { - log.info(`Global fields '${uid}' already exist`, this.importConfig.context); + log.info(`Global field '${uid}' already exists.`, this.importConfig.context); } } else { this.progressManager?.tick( diff --git a/packages/contentstack-import/src/import/modules/labels.ts b/packages/contentstack-import/src/import/modules/labels.ts index 397a860987..ae8558712b 100644 --- a/packages/contentstack-import/src/import/modules/labels.ts +++ b/packages/contentstack-import/src/import/modules/labels.ts @@ -84,7 +84,7 @@ export default class ImportLabels extends BaseClass { async importLabels() { log.debug('Validating labels data', this.importConfig.context); if (this.labels === undefined || isEmpty(this.labels)) { - log.info('No Labels Found', this.importConfig.context); + log.info('No labels found.', this.importConfig.context); return; } @@ -150,7 +150,7 @@ export default class ImportLabels extends BaseClass { log.debug(`Serializing label: ${label.name} (${label.uid})`, this.importConfig.context); if (this.labelUidMapper.hasOwnProperty(label.uid)) { - log.info(`Label '${label.name}' already exists. Skipping it to avoid duplicates!`, this.importConfig.context); + log.info(`Label '${label.name}' already exists. Skipping to avoid duplicates.`, this.importConfig.context); log.debug(`Skipping label serialization for: ${label.uid}`, this.importConfig.context); this.progressManager?.tick( true, @@ -174,7 +174,7 @@ export default class ImportLabels extends BaseClass { } async updateLabels() { - log.debug('Starting labels update process', this.importConfig.context); + log.debug('Starting labels update process...', this.importConfig.context); if (!isEmpty(this.labels)) { const apiContent = values(this.labels); log.debug(`Updating ${apiContent.length} labels`, this.importConfig.context); @@ -219,10 +219,10 @@ export default class ImportLabels extends BaseClass { false, ); } else { - log.debug('No labels to update', this.importConfig.context); + log.debug('No labels to update.', this.importConfig.context); } - log.debug('Labels update process completed', this.importConfig.context); + log.debug('Labels update process completed.', this.importConfig.context); } /** diff --git a/packages/contentstack-import/src/import/modules/marketplace-apps.ts b/packages/contentstack-import/src/import/modules/marketplace-apps.ts index 46b8daf3c3..a904fd77a9 100644 --- a/packages/contentstack-import/src/import/modules/marketplace-apps.ts +++ b/packages/contentstack-import/src/import/modules/marketplace-apps.ts @@ -153,30 +153,30 @@ export default class ImportMarketplaceApps extends BaseClass { * validates app installation, and generates a UID mapper. */ async importMarketplaceApps(): Promise { - log.debug('Setting up security configuration for marketplace apps', this.importConfig.context); + log.debug('Setting up security configuration for Marketplace Apps...', this.importConfig.context); // NOTE set default encryptionKey const cryptoArgs = { encryptionKey: this.importConfig.marketplaceAppEncryptionKey }; if (this.importConfig.forceStopMarketplaceAppsPrompt) { - log.debug('Using forced security configuration without validation', this.importConfig.context); + log.debug('Using forced security configuration without validation.', this.importConfig.context); this.nodeCrypto = new NodeCrypto(cryptoArgs); } // NOTE getting all apps to validate if it's already installed in the stack to manage conflict - log.debug('Getting all stack-specific apps for validation', this.importConfig.context); + log.debug('Getting all stack-specific apps for validation...', this.importConfig.context); this.installedApps = await getAllStackSpecificApps(this.importConfig); log.debug(`Found ${this.installedApps?.length || 0} already installed apps`, this.importConfig.context); - log.info('Starting marketplace app installation', this.importConfig.context); + log.info('Starting Marketplace App installation...', this.importConfig.context); for (let app of this.marketplaceApps) { log.debug(`Processing app: ${app.manifest?.name || app.manifest?.uid}`, this.importConfig.context); await this.installApps(app); } - log.debug('Generating UID mapper', this.importConfig.context); + log.debug('Generating UID mapper...', this.importConfig.context); const uidMapper = await this.generateUidMapper(); - log.debug('Writing UID mappings to file', this.importConfig.context); + log.debug('Writing UID mappings to file...', this.importConfig.context); fsUtil.writeFile(this.marketPlaceUidMapperPath, { app_uid: this.appUidMapping, extension_uid: uidMapper || {}, @@ -197,24 +197,24 @@ export default class ImportMarketplaceApps extends BaseClass { * unknown>`. */ async generateUidMapper(): Promise> { - log.debug('Generating UID mapper for extensions', this.importConfig.context); + log.debug('Generating UID mapper for extensions...', this.importConfig.context); const listOfNewMeta = []; const listOfOldMeta = []; const extensionUidMap: Record = {}; // NOTE After installation getting all apps to create mapper. - log.debug('Fetching updated list of installed apps', this.importConfig.context); + log.debug('Fetching updated list of installed apps...', this.importConfig.context); this.installedApps = (await getAllStackSpecificApps(this.importConfig)) || []; log.debug(`Found ${this.installedApps?.length || 0} installed apps after installation`, this.importConfig.context); - log.debug('Processing old metadata from marketplace apps', this.importConfig.context); + log.debug('Processing old metadata from Marketplace Apps...', this.importConfig.context); for (const app of this.marketplaceApps) { const appMeta = map(app?.ui_location?.locations, 'meta').flat(); listOfOldMeta.push(...appMeta); log.debug(`Added ${appMeta.length} meta entries from app: ${app.manifest?.name}`, this.importConfig.context); } - log.debug('Processing new metadata from installed apps', this.importConfig.context); + log.debug('Processing new metadata from installed apps...', this.importConfig.context); for (const app of this.installedApps) { const appMeta = map(app?.ui_location?.locations, 'meta').flat(); listOfNewMeta.push(...appMeta); @@ -263,7 +263,7 @@ export default class ImportMarketplaceApps extends BaseClass { ); if (!appConfig) { - log.debug('No app configuration found requiring encryption', this.importConfig.context); + log.debug('No app configuration found requiring encryption.', this.importConfig.context); return defaultValue; } @@ -273,11 +273,11 @@ export default class ImportMarketplaceApps extends BaseClass { try { appConfig = !isEmpty(appConfig.configuration) ? appConfig.configuration : appConfig.server_configuration; - log.debug('Creating NodeCrypto instance with security configuration', this.importConfig.context); + log.debug('Creating NodeCrypto instance with security configuration...', this.importConfig.context); this.nodeCrypto = new NodeCrypto({ encryptionKey }); - log.debug('Testing security configuration with app data', this.importConfig.context); + log.debug('Testing security configuration with app data...', this.importConfig.context); this.nodeCrypto.decrypt(appConfig); - log.debug('Security configuration validation successful', this.importConfig.context); + log.debug('Security configuration validation successful.', this.importConfig.context); } catch (error) { log.debug(`Security configuration validation failed: ${error.message}`, this.importConfig.context); if (retry < this.importConfig.getEncryptionKeyMaxRetry && error.code === 'ERR_OSSL_EVP_BAD_DECRYPT') { @@ -296,7 +296,7 @@ export default class ImportMarketplaceApps extends BaseClass { `Maximum retry limit exceeded. Closing the process, please try again.! attempt(${retry}/${this.importConfig.getEncryptionKeyMaxRetry})`, { color: 'red' }, ); - log.debug('Maximum retry limit exceeded for encryption validation', this.importConfig.context); + log.debug('Maximum retry limit exceeded for encryption validation.', this.importConfig.context); process.exit(1); } } @@ -311,7 +311,7 @@ export default class ImportMarketplaceApps extends BaseClass { * @returns a Promise that resolves to void. */ async handleAllPrivateAppsCreationProcess(): Promise { - log.debug('Filtering private apps from marketplace apps', this.importConfig.context); + log.debug('Filtering private apps from Marketplace Apps...', this.importConfig.context); const privateApps = filter(this.marketplaceApps, { manifest: { visibility: 'private' } }); log.debug(`Found ${privateApps.length} private apps to process`, this.importConfig.context); @@ -326,7 +326,7 @@ export default class ImportMarketplaceApps extends BaseClass { this.importConfig.canCreatePrivateApp = canCreatePrivateApp; if (canCreatePrivateApp) { - log.info('Starting developer hub private apps re-creation', this.importConfig.context); + log.info('Starting Developer Hub private apps re-creation...', this.importConfig.context); log.debug(`Processing ${privateApps.length} private apps for creation`, this.importConfig.context); for (let app of privateApps) { @@ -391,12 +391,12 @@ export default class ImportMarketplaceApps extends BaseClass { .installation(app.uid) .fetch() .catch((): void => { - log.debug(`App ${app.manifest?.name} not found in developer hub`, this.importConfig.context); + log.debug(`App ${app.manifest?.name} not found in Developer Hub.`, this.importConfig.context); return undefined; }); // NOTE Keeping this to avoid Unhandled exception const exists = !isEmpty(installation); - log.debug(`Private app ${app.manifest?.name} exists in developer hub: ${exists}`, this.importConfig.context); + log.debug(`Private app ${app.manifest?.name} exists in Developer Hub: ${exists}`, this.importConfig.context); return exists; } @@ -419,7 +419,7 @@ export default class ImportMarketplaceApps extends BaseClass { ); if (updateUiLocation && !isEmpty(app?.ui_location?.locations)) { - log.debug(`Updating UI locations for app: ${app.name}`, this.importConfig.context); + log.debug(`Updating UI locations for app: ${app.name}...`, this.importConfig.context); app.ui_location.locations = this.updateManifestUILocations(app?.ui_location?.locations, appSuffix); } @@ -526,7 +526,7 @@ export default class ImportMarketplaceApps extends BaseClass { */ async appCreationCallback(app: any, response: any, appSuffix: number): Promise { const { statusText, message } = response || {}; - log.debug(`Processing app creation callback for: ${app.name} (suffix: ${appSuffix})`, this.importConfig.context); + log.debug(`Processing app creation callback for: ${app.name} (suffix: ${appSuffix})...`, this.importConfig.context); if (message) { log.debug(`App creation response has message: ${message}`, this.importConfig.context); @@ -551,10 +551,10 @@ export default class ImportMarketplaceApps extends BaseClass { ), ) ) { - log.debug('User chose to proceed despite error', this.importConfig.context); + log.debug('User chose to proceed despite error.', this.importConfig.context); Promise.resolve(); } else { - log.debug('User chose to exit due to error', this.importConfig.context); + log.debug('User chose to exit due to error.', this.importConfig.context); process.exit(); } } @@ -688,10 +688,10 @@ export default class ImportMarketplaceApps extends BaseClass { async updateAppsConfig(app: Installation): Promise { const { installation_uid, configuration, server_configuration } = app; const appName = app.manifest.name || app.manifest.uid; - log.debug(`Updating app configuration for: ${appName} (${installation_uid})`, this.importConfig.context); + log.debug(`Updating configuration for: ${appName} (${installation_uid})`, this.importConfig.context); if (!isEmpty(configuration)) { - log.debug(`Updating app configuration for: ${appName}`, this.importConfig.context); + log.debug(`Updating configuration for: ${appName}`, this.importConfig.context); await this.appSdk .marketplace(this.importConfig.org_uid) .installation(installation_uid) @@ -702,18 +702,18 @@ export default class ImportMarketplaceApps extends BaseClass { log.info(formatError(data.message), this.importConfig.context); } else { log.success(`${appName} app config updated successfully.!`, this.importConfig.context); - log.debug(`Configuration update successful for: ${appName}`, this.importConfig.context); + log.debug(`Configuration update was successful for: ${appName}`, this.importConfig.context); } }) .catch((error: any) => { log.debug(error, this.importConfig.context); log.error(formatError(error), this.importConfig.context); - log.debug(`Configuration update failed for: ${appName}`, this.importConfig.context); + log.debug(`Configuration update failed for: ${appName}.`, this.importConfig.context); }); } if (!isEmpty(server_configuration)) { - log.debug(`Updating server configuration for: ${appName}`, this.importConfig.context); + log.debug(`Updating server configuration for: ${appName}...`, this.importConfig.context); await this.appSdk .marketplace(this.importConfig.org_uid) .installation(installation_uid) @@ -724,13 +724,13 @@ export default class ImportMarketplaceApps extends BaseClass { log.error(formatError(data.message), this.importConfig.context); } else { log.success(`${appName} app server config updated successfully.!`, this.importConfig.context); - log.debug(`Server configuration update successful for: ${appName}`, this.importConfig.context); + log.debug(`Server configuration update was successful for: ${appName}.`, this.importConfig.context); } }) .catch((error: any) => { log.debug(error, this.importConfig.context); log.error(formatError(error), this.importConfig.context); - log.debug(`Server configuration update failed for: ${appName}`, this.importConfig.context); + log.debug(`Server configuration update failed for: ${appName}.`, this.importConfig.context); }); } } diff --git a/packages/contentstack-import/src/import/modules/taxonomies.ts b/packages/contentstack-import/src/import/modules/taxonomies.ts index fc25786d81..327b30bb26 100644 --- a/packages/contentstack-import/src/import/modules/taxonomies.ts +++ b/packages/contentstack-import/src/import/modules/taxonomies.ts @@ -191,7 +191,7 @@ export default class ImportTaxonomies extends BaseClass { * @method createSuccessAndFailedFile */ createSuccessAndFailedFile() { - log.debug('Creating success and failed files for taxonomies and terms', this.importConfig.context); + log.debug('Creating success and failed files for taxonomies and terms...', this.importConfig.context); const createdTaxCount = Object.keys(this.createdTaxonomies || {})?.length; const failedTaxCount = Object.keys(this.failedTaxonomies || {})?.length; diff --git a/packages/contentstack-import/src/types/default-config.ts b/packages/contentstack-import/src/types/default-config.ts index 05d98eb991..2b7c3bd95a 100644 --- a/packages/contentstack-import/src/types/default-config.ts +++ b/packages/contentstack-import/src/types/default-config.ts @@ -158,6 +158,12 @@ export default interface DefaultConfig { locale: string; } & AnyProperty; } & AnyProperty; + 'composable-studio': { + dirName: string; + fileName: string; + apiBaseUrl: string; + apiVersion: string; + }; }; languagesCode: string[]; apis: { @@ -198,5 +204,5 @@ export default interface DefaultConfig { globalModules: string[]; skipAssetsPublish?: boolean; skipEntriesPublish?: boolean; - entriesPublish: boolean, + entriesPublish: boolean; } diff --git a/packages/contentstack-import/src/types/index.ts b/packages/contentstack-import/src/types/index.ts index c9fe5634d6..e2b798863c 100644 --- a/packages/contentstack-import/src/types/index.ts +++ b/packages/contentstack-import/src/types/index.ts @@ -50,7 +50,8 @@ export type Modules = | 'marketplace-apps' | 'taxonomies' | 'personalize' - | 'variant-entries'; + | 'variant-entries' + | 'composable-studio'; export type ModuleClassParams = { stackAPIClient: ReturnType; @@ -127,4 +128,4 @@ export interface Context { apiKey: string; orgId: string; authenticationMethod?: string; -} \ No newline at end of file +} diff --git a/packages/contentstack-import/src/utils/content-type-helper.ts b/packages/contentstack-import/src/utils/content-type-helper.ts index b1fa5fd194..942ddc8c59 100644 --- a/packages/contentstack-import/src/utils/content-type-helper.ts +++ b/packages/contentstack-import/src/utils/content-type-helper.ts @@ -132,7 +132,7 @@ export const removeReferenceFields = async function ( } catch (error) { // Else warn and modify the schema object. isContentTypeError = true; - log.warn(`Content-type ${schema[i].reference_to[j]} does not exist. Removing the field from schema`); + log.warn(`Content type ${schema[i].reference_to[j]} does not exist. Removing the field from schema...`); } } @@ -209,7 +209,7 @@ export const updateFieldRules = function (contentType: any) { fieldDataTypeMap[field.uid] = field.data_type; } - log.debug(`Created field data type mapping for ${Object.keys(fieldDataTypeMap).length} fields`); + log.debug(`Created field data type mapping for ${Object.keys(fieldDataTypeMap).length} fields.`); const fieldRules = [...contentType.field_rules]; let len = fieldRules.length; diff --git a/packages/contentstack-import/src/utils/file-helper.ts b/packages/contentstack-import/src/utils/file-helper.ts index e5c613b90d..225f5c49b5 100644 --- a/packages/contentstack-import/src/utils/file-helper.ts +++ b/packages/contentstack-import/src/utils/file-helper.ts @@ -53,7 +53,7 @@ export const readLargeFile = function (filePath: string, opts?: any): Promise => { ); const pattern = /[*$%#<>{}!&?]/g; if (pattern.test(config.contentDir)) { - cliux.print(`\nPlease add a directory path without any of the special characters: (*,&,{,},[,],$,%,<,>,?,!)`, { + cliux.print(`\nPlease enter a directory path without any special characters: (*,&,{,},[,],$,%,<,>,?,!)`, { color: 'yellow', }); config.contentDir = sanitizePath(await askContentDir()); @@ -140,7 +140,7 @@ const setupConfig = async (importCmdFlags: any): Promise => { // Add authentication details to config for context tracking config.authenticationMethod = authenticationMethod; - log.debug('Import configuration setup completed', { ...config }); + log.debug('Import configuration setup completed.', { ...config }); return config; }; diff --git a/packages/contentstack-import/src/utils/login-handler.ts b/packages/contentstack-import/src/utils/login-handler.ts index c8cfa499c6..859a4bf594 100644 --- a/packages/contentstack-import/src/utils/login-handler.ts +++ b/packages/contentstack-import/src/utils/login-handler.ts @@ -49,7 +49,7 @@ const login = async (config: ImportConfig): Promise => { if (errorstack_key) { const keyError = errorstack_key[0]; - log.error(`Invalid stack API token: ${keyError} Please enter valid stack API token.`); + log.error(`Invalid stack API token: ${keyError}. Please enter a valid stack API token.`); throw error; } diff --git a/packages/contentstack-import/src/utils/taxonomies-helper.ts b/packages/contentstack-import/src/utils/taxonomies-helper.ts index f102cecf5d..e94aaf7154 100644 --- a/packages/contentstack-import/src/utils/taxonomies-helper.ts +++ b/packages/contentstack-import/src/utils/taxonomies-helper.ts @@ -12,7 +12,7 @@ import { ImportConfig } from '../types'; * @param {ImportConfig} importConfig */ export const lookUpTaxonomy = function (importConfig: ImportConfig, schema: any, taxonomies: Record) { - log.debug(`Starting taxonomy lookup for schema with ${Object.keys(schema).length} fields`); + log.debug(`Starting taxonomy lookup for schema with ${Object.keys(schema).length} fields.`); for (let i in schema) { if (schema[i].data_type === 'taxonomy') { diff --git a/packages/contentstack-import/test/unit/import/modules/locales.test.ts b/packages/contentstack-import/test/unit/import/modules/locales.test.ts index 143dbe297e..fc3631e810 100644 --- a/packages/contentstack-import/test/unit/import/modules/locales.test.ts +++ b/packages/contentstack-import/test/unit/import/modules/locales.test.ts @@ -16,10 +16,10 @@ describe('ImportLocales', () => { beforeEach(() => { sandbox = sinon.createSandbox(); tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'locales-test-')); - + // Create necessary directories fs.mkdirSync(path.join(tempDir, 'mapper', 'languages'), { recursive: true }); - + // Create mock config mockConfig = { data: tempDir, @@ -33,51 +33,87 @@ describe('ImportLocales', () => { locales: { dirName: 'locales', fileName: 'locales.json', - requiredKeys: ['uid', 'code', 'name'] + requiredKeys: ['uid', 'code', 'name'], }, masterLocale: { dirName: 'locales', fileName: 'master_locale.json', - requiredKeys: ['uid', 'code', 'name'] + requiredKeys: ['uid', 'code', 'name'], + }, + customRoles: { + dirName: 'custom_roles', + fileName: 'custom_roles.json', + customRolesLocalesFileName: 'custom_roles_locales.json', }, - customRoles: { dirName: 'custom_roles', fileName: 'custom_roles.json', customRolesLocalesFileName: 'custom_roles_locales.json' }, environments: { dirName: 'environments', fileName: 'environments.json' }, labels: { dirName: 'labels', fileName: 'labels.json' }, extensions: { dirName: 'extensions', fileName: 'extensions.json', validKeys: ['uid', 'title'] }, webhooks: { dirName: 'webhooks', fileName: 'webhooks.json' }, releases: { dirName: 'releases', fileName: 'releases.json', invalidKeys: ['uid'] }, workflows: { dirName: 'workflows', fileName: 'workflows.json', invalidKeys: ['uid'] }, - assets: { - dirName: 'assets', - assetBatchLimit: 10, - fileName: 'assets.json', - importSameStructure: false, - uploadAssetsConcurrency: 1, - displayExecutionTime: false, - importFoldersConcurrency: 1, - includeVersionedAssets: false, - host: 'https://api.contentstack.io', - folderValidKeys: ['uid', 'name'], - validKeys: ['uid', 'title'] + assets: { + dirName: 'assets', + assetBatchLimit: 10, + fileName: 'assets.json', + importSameStructure: false, + uploadAssetsConcurrency: 1, + displayExecutionTime: false, + importFoldersConcurrency: 1, + includeVersionedAssets: false, + host: 'https://api.contentstack.io', + folderValidKeys: ['uid', 'name'], + validKeys: ['uid', 'title'], + }, + 'assets-old': { + dirName: 'assets', + fileName: 'assets.json', + limit: 100, + host: 'https://api.contentstack.io', + validKeys: ['uid', 'title'], + assetBatchLimit: 10, + uploadAssetsConcurrency: 1, + importFoldersConcurrency: 1, + }, + content_types: { + dirName: 'content_types', + fileName: 'content_types.json', + validKeys: ['uid', 'title'], + limit: 100, + }, + 'content-types': { + dirName: 'content_types', + fileName: 'content_types.json', + validKeys: ['uid', 'title'], + limit: 100, + }, + entries: { + dirName: 'entries', + fileName: 'entries.json', + invalidKeys: ['uid'], + limit: 100, + assetBatchLimit: 10, }, - 'assets-old': { - dirName: 'assets', - fileName: 'assets.json', - limit: 100, - host: 'https://api.contentstack.io', - validKeys: ['uid', 'title'], - assetBatchLimit: 10, - uploadAssetsConcurrency: 1, - importFoldersConcurrency: 1 + globalfields: { + dirName: 'globalfields', + fileName: 'globalfields.json', + validKeys: ['uid', 'title'], + limit: 100, + }, + 'global-fields': { + dirName: 'globalfields', + fileName: 'globalfields.json', + validKeys: ['uid', 'title'], + limit: 100, }, - content_types: { dirName: 'content_types', fileName: 'content_types.json', validKeys: ['uid', 'title'], limit: 100 }, - 'content-types': { dirName: 'content_types', fileName: 'content_types.json', validKeys: ['uid', 'title'], limit: 100 }, - entries: { dirName: 'entries', fileName: 'entries.json', invalidKeys: ['uid'], limit: 100, assetBatchLimit: 10 }, - globalfields: { dirName: 'globalfields', fileName: 'globalfields.json', validKeys: ['uid', 'title'], limit: 100 }, - 'global-fields': { dirName: 'globalfields', fileName: 'globalfields.json', validKeys: ['uid', 'title'], limit: 100 }, stack: { dirName: 'stack', fileName: 'stack.json' }, marketplace_apps: { dirName: 'marketplace_apps', fileName: 'marketplace_apps.json' }, taxonomies: { dirName: 'taxonomies', fileName: 'taxonomies.json' }, + 'composable-studio': { + dirName: 'composable-studio', + fileName: 'composable-studio.json', + apiBaseUrl: 'https://composable-studio-api.contentstack.com/v1', + apiVersion: 'v1', + }, personalize: { baseURL: {}, dirName: 'personalize', @@ -87,9 +123,19 @@ describe('ImportLocales', () => { attributes: { dirName: 'attributes', fileName: 'attributes.json' }, audiences: { dirName: 'audiences', fileName: 'audiences.json' }, events: { dirName: 'events', fileName: 'events.json' }, - experiences: { dirName: 'experiences', fileName: 'experiences.json', thresholdTimer: 1000, checkIntervalDuration: 100 } + experiences: { + dirName: 'experiences', + fileName: 'experiences.json', + thresholdTimer: 1000, + checkIntervalDuration: 100, + }, + }, + variantEntry: { + dirName: 'variant_entries', + fileName: 'variant_entries.json', + apiConcurrency: 1, + query: { locale: 'en-us' }, }, - variantEntry: { dirName: 'variant_entries', fileName: 'variant_entries.json', apiConcurrency: 1, query: { locale: 'en-us' } } }, branches: [{ uid: 'main', source: 'main' }], isAuthenticated: true, @@ -111,7 +157,7 @@ describe('ImportLocales', () => { globalfields: '/v3/globalfields', folders: '/v3/folders', stacks: '/v3/stacks', - labels: '/v3/labels' + labels: '/v3/labels', }, rateLimit: 5, preserveStackVersion: false, @@ -135,29 +181,29 @@ describe('ImportLocales', () => { contentVersion: 1, region: 'us' as any, 'exclude-global-modules': false, - context: { + context: { module: 'locales', command: 'import', userId: 'test-user', email: 'test@example.com', sessionId: 'test-session', - stack: 'test-stack' - } as any + stack: 'test-stack', + } as any, }; // Create mock stack API client mockStackAPIClient = { locale: sandbox.stub().returns({ fetch: sandbox.stub(), - update: sandbox.stub() - }) + update: sandbox.stub(), + }), }; // Create module class params const moduleParams: ModuleClassParams = { importConfig: mockConfig, stackAPIClient: mockStackAPIClient, - moduleName: 'locales' as any + moduleName: 'locales' as any, }; // Create instance @@ -234,14 +280,17 @@ describe('ImportLocales', () => { it('should process languages successfully', async () => { const mockLanguages = [ { uid: 'lang1', code: 'en-us', name: 'English' }, - { uid: 'lang2', code: 'es-es', name: 'Spanish' } + { uid: 'lang2', code: 'es-es', name: 'Spanish' }, ]; const mockMasterLanguage = { uid: 'master', code: 'en-us', name: 'English' }; fsUtilStub - .onFirstCall().returns(mockLanguages) - .onSecondCall().returns(mockMasterLanguage) - .onThirdCall().returns({}); + .onFirstCall() + .returns(mockLanguages) + .onSecondCall() + .returns(mockMasterLanguage) + .onThirdCall() + .returns({}); fileHelperStub.resolves(); makeConcurrentCallStub.resolves(); @@ -253,14 +302,10 @@ describe('ImportLocales', () => { }); it('should handle case when UID mapper file does not exist', async () => { - const mockLanguages = [ - { uid: 'lang1', code: 'en-us', name: 'English' } - ]; + const mockLanguages = [{ uid: 'lang1', code: 'en-us', name: 'English' }]; const mockMasterLanguage = { uid: 'master', code: 'en-us', name: 'English' }; - fsUtilStub - .onFirstCall().returns(mockLanguages) - .onSecondCall().returns(mockMasterLanguage); + fsUtilStub.onFirstCall().returns(mockLanguages).onSecondCall().returns(mockMasterLanguage); fileHelperStub.resolves(); makeConcurrentCallStub.resolves(); @@ -277,15 +322,16 @@ describe('ImportLocales', () => { }); it('should handle case when UID mapper file exists but returns null', async () => { - const mockLanguages = [ - { uid: 'lang1', code: 'en-us', name: 'English' } - ]; + const mockLanguages = [{ uid: 'lang1', code: 'en-us', name: 'English' }]; const mockMasterLanguage = { uid: 'master', code: 'en-us', name: 'English' }; fsUtilStub - .onFirstCall().returns(mockLanguages) - .onSecondCall().returns(mockMasterLanguage) - .onThirdCall().returns(null); // UID mapper file returns null + .onFirstCall() + .returns(mockLanguages) + .onSecondCall() + .returns(mockMasterLanguage) + .onThirdCall() + .returns(null); // UID mapper file returns null fileHelperStub.resolves(); makeConcurrentCallStub.resolves(); @@ -303,15 +349,14 @@ describe('ImportLocales', () => { it('should handle errors in checkAndUpdateMasterLocale', async () => { const mockLanguages = [{ uid: 'lang1', code: 'en-us', name: 'English' }]; - fsUtilStub - .onFirstCall().returns(mockLanguages) - .onSecondCall().returns({}) - .onThirdCall().returns({}); + fsUtilStub.onFirstCall().returns(mockLanguages).onSecondCall().returns({}).onThirdCall().returns({}); fileHelperStub.resolves(); makeConcurrentCallStub.resolves(); // Mock checkAndUpdateMasterLocale to throw error - const checkAndUpdateMasterLocaleStub = sandbox.stub(localesInstance, 'checkAndUpdateMasterLocale').rejects(new Error('Test error')); + const checkAndUpdateMasterLocaleStub = sandbox + .stub(localesInstance, 'checkAndUpdateMasterLocale') + .rejects(new Error('Test error')); await localesInstance.start(); @@ -321,10 +366,7 @@ describe('ImportLocales', () => { it('should handle errors in createLocales', async () => { const mockLanguages = [{ uid: 'lang1', code: 'en-us', name: 'English' }]; - fsUtilStub - .onFirstCall().returns(mockLanguages) - .onSecondCall().returns({}) - .onThirdCall().returns({}); + fsUtilStub.onFirstCall().returns(mockLanguages).onSecondCall().returns({}).onThirdCall().returns({}); fileHelperStub.resolves(); makeConcurrentCallStub.rejects(new Error('Create locales error')); @@ -335,14 +377,9 @@ describe('ImportLocales', () => { it('should handle errors in updateLocales', async () => { const mockLanguages = [{ uid: 'lang1', code: 'en-us', name: 'English' }]; - fsUtilStub - .onFirstCall().returns(mockLanguages) - .onSecondCall().returns({}) - .onThirdCall().returns({}); + fsUtilStub.onFirstCall().returns(mockLanguages).onSecondCall().returns({}).onThirdCall().returns({}); fileHelperStub.resolves(); - makeConcurrentCallStub - .onFirstCall().resolves() - .onSecondCall().rejects(new Error('Update locales error')); + makeConcurrentCallStub.onFirstCall().resolves().onSecondCall().rejects(new Error('Update locales error')); await localesInstance.start(); @@ -379,7 +416,7 @@ describe('ImportLocales', () => { it('should handle master language code mismatch', async () => { localesInstance['sourceMasterLanguage'] = { - 'lang1': { uid: 'lang1', code: 'es-es', name: 'Spanish' } + lang1: { uid: 'lang1', code: 'es-es', name: 'Spanish' }, }; localesInstance['masterLanguage'] = { code: 'en-us' }; @@ -391,13 +428,13 @@ describe('ImportLocales', () => { it('should handle master language code match with same names', async () => { const mockMasterLang = { uid: 'master', code: 'en-us', name: 'English' }; localesInstance['sourceMasterLanguage'] = { - 'master': mockMasterLang + master: mockMasterLang, }; localesInstance['masterLanguage'] = { code: 'en-us' }; const mockLocaleClient = { fetch: sandbox.stub().resolves({ name: 'English' }), - update: sandbox.stub().resolves() + update: sandbox.stub().resolves(), }; mockStackAPIClient.locale.returns(mockLocaleClient); @@ -411,18 +448,20 @@ describe('ImportLocales', () => { it('should handle master language code match with different names - user confirms update', async () => { const mockMasterLang = { uid: 'master', code: 'en-us', name: 'English Updated' }; localesInstance['sourceMasterLanguage'] = { - 'master': mockMasterLang + master: mockMasterLang, }; localesInstance['masterLanguage'] = { code: 'en-us' }; const mockLocaleClient = { fetch: sandbox.stub().resolves({ name: 'English' }), - update: sandbox.stub().resolves() + update: sandbox.stub().resolves(), }; mockStackAPIClient.locale.returns(mockLocaleClient); // Mock cliux.inquire to return true (user confirms) - const inquireStub = sandbox.stub(require('@contentstack/cli-utilities').cliux, 'inquire').resolves({ confirmation: true }); + const inquireStub = sandbox + .stub(require('@contentstack/cli-utilities').cliux, 'inquire') + .resolves({ confirmation: true }); await localesInstance.checkAndUpdateMasterLocale(); @@ -436,18 +475,20 @@ describe('ImportLocales', () => { it('should handle master language code match with different names - user declines update', async () => { const mockMasterLang = { uid: 'master', code: 'en-us', name: 'English Updated' }; localesInstance['sourceMasterLanguage'] = { - 'master': mockMasterLang + master: mockMasterLang, }; localesInstance['masterLanguage'] = { code: 'en-us' }; const mockLocaleClient = { fetch: sandbox.stub().resolves({ name: 'English' }), - update: sandbox.stub().resolves() + update: sandbox.stub().resolves(), }; mockStackAPIClient.locale.returns(mockLocaleClient); // Mock cliux.inquire to return false (user declines) - const inquireStub = sandbox.stub(require('@contentstack/cli-utilities').cliux, 'inquire').resolves({ confirmation: false }); + const inquireStub = sandbox + .stub(require('@contentstack/cli-utilities').cliux, 'inquire') + .resolves({ confirmation: false }); await localesInstance.checkAndUpdateMasterLocale(); @@ -462,18 +503,20 @@ describe('ImportLocales', () => { it('should handle master language code match with different names - user declines update (proper flow)', async () => { const mockMasterLang = { uid: 'master', code: 'en-us', name: 'English Updated' }; localesInstance['sourceMasterLanguage'] = { - 'master': mockMasterLang + master: mockMasterLang, }; localesInstance['masterLanguage'] = { code: 'en-us' }; const mockLocaleClient = { fetch: sandbox.stub().resolves({ name: 'English' }), - update: sandbox.stub().resolves() + update: sandbox.stub().resolves(), }; mockStackAPIClient.locale.returns(mockLocaleClient); // Mock cliux.inquire to return false (user declines) - const inquireStub = sandbox.stub(require('@contentstack/cli-utilities').cliux, 'inquire').resolves({ confirmation: false }); + const inquireStub = sandbox + .stub(require('@contentstack/cli-utilities').cliux, 'inquire') + .resolves({ confirmation: false }); await localesInstance.checkAndUpdateMasterLocale(); @@ -484,22 +527,23 @@ describe('ImportLocales', () => { // Verify line 172 is covered - user declined update }); - it('should handle user declining update with proper error handling', async () => { const mockMasterLang = { uid: 'master', code: 'en-us', name: 'English Updated' }; localesInstance['sourceMasterLanguage'] = { - 'master': mockMasterLang + master: mockMasterLang, }; localesInstance['masterLanguage'] = { code: 'en-us' }; const mockLocaleClient = { fetch: sandbox.stub().resolves({ name: 'English' }), - update: sandbox.stub().resolves() + update: sandbox.stub().resolves(), }; mockStackAPIClient.locale.returns(mockLocaleClient); // Mock cliux.inquire to return false (user declines) - const inquireStub = sandbox.stub(require('@contentstack/cli-utilities').cliux, 'inquire').resolves({ confirmation: false }); + const inquireStub = sandbox + .stub(require('@contentstack/cli-utilities').cliux, 'inquire') + .resolves({ confirmation: false }); // Mock handleAndLogError to prevent any errors const handleAndLogErrorStub = sandbox.stub(require('@contentstack/cli-utilities'), 'handleAndLogError'); @@ -521,18 +565,20 @@ describe('ImportLocales', () => { it('should handle master language not found in source', async () => { const mockMasterLang = { uid: 'master', code: 'en-us', name: 'English Updated' }; localesInstance['sourceMasterLanguage'] = { - 'master': mockMasterLang // Use 'master' key to match the uid + master: mockMasterLang, // Use 'master' key to match the uid }; localesInstance['masterLanguage'] = { code: 'en-us' }; const mockLocaleClient = { fetch: sandbox.stub().resolves({ name: 'English' }), - update: sandbox.stub().resolves() + update: sandbox.stub().resolves(), }; mockStackAPIClient.locale.returns(mockLocaleClient); // Mock cliux.inquire to return true (user confirms) - const inquireStub = sandbox.stub(require('@contentstack/cli-utilities').cliux, 'inquire').resolves({ confirmation: true }); + const inquireStub = sandbox + .stub(require('@contentstack/cli-utilities').cliux, 'inquire') + .resolves({ confirmation: true }); await localesInstance.checkAndUpdateMasterLocale(); @@ -544,23 +590,23 @@ describe('ImportLocales', () => { expect(mockLocaleClient.update.called).to.be.true; }); - - it('should handle master language not found in source with undefined uid', async () => { // Create a scenario where sourceMasterLangDetails[0] exists but has no uid localesInstance['sourceMasterLanguage'] = { - 'some-key': { code: 'en-us', name: 'English Updated' } // No uid property + 'some-key': { code: 'en-us', name: 'English Updated' }, // No uid property }; localesInstance['masterLanguage'] = { code: 'en-us' }; const mockLocaleClient = { fetch: sandbox.stub().resolves({ name: 'English' }), - update: sandbox.stub().resolves() + update: sandbox.stub().resolves(), }; mockStackAPIClient.locale.returns(mockLocaleClient); // Mock cliux.inquire to return true (user confirms) - const inquireStub = sandbox.stub(require('@contentstack/cli-utilities').cliux, 'inquire').resolves({ confirmation: true }); + const inquireStub = sandbox + .stub(require('@contentstack/cli-utilities').cliux, 'inquire') + .resolves({ confirmation: true }); // The code will try to access sourceMasterLanguage.name when sourceMasterLanguage is undefined // So we need to handle this gracefully @@ -579,13 +625,13 @@ describe('ImportLocales', () => { it('should handle fetch error', async () => { const mockMasterLang = { uid: 'master', code: 'en-us', name: 'English Updated' }; localesInstance['sourceMasterLanguage'] = { - 'master': mockMasterLang + master: mockMasterLang, }; localesInstance['masterLanguage'] = { code: 'en-us' }; const mockLocaleClient = { fetch: sandbox.stub().rejects(new Error('Fetch error')), - update: sandbox.stub().resolves() + update: sandbox.stub().resolves(), }; mockStackAPIClient.locale.returns(mockLocaleClient); @@ -606,18 +652,20 @@ describe('ImportLocales', () => { it('should handle update error', async () => { const mockMasterLang = { uid: 'master', code: 'en-us', name: 'English Updated' }; localesInstance['sourceMasterLanguage'] = { - 'master': mockMasterLang + master: mockMasterLang, }; localesInstance['masterLanguage'] = { code: 'en-us' }; const mockLocaleClient = { fetch: sandbox.stub().resolves({ name: 'English' }), - update: sandbox.stub().rejects(new Error('Update error')) + update: sandbox.stub().rejects(new Error('Update error')), }; mockStackAPIClient.locale.returns(mockLocaleClient); // Mock cliux.inquire to return true (user confirms) - const inquireStub = sandbox.stub(require('@contentstack/cli-utilities').cliux, 'inquire').resolves({ confirmation: true }); + const inquireStub = sandbox + .stub(require('@contentstack/cli-utilities').cliux, 'inquire') + .resolves({ confirmation: true }); // The code will try to access this.config.context in the error handler // So we need to handle this gracefully @@ -637,18 +685,20 @@ describe('ImportLocales', () => { it('should handle update error with proper error handling', async () => { const mockMasterLang = { uid: 'master', code: 'en-us', name: 'English Updated' }; localesInstance['sourceMasterLanguage'] = { - 'master': mockMasterLang + master: mockMasterLang, }; localesInstance['masterLanguage'] = { code: 'en-us' }; const mockLocaleClient = { fetch: sandbox.stub().resolves({ name: 'English' }), - update: sandbox.stub().rejects(new Error('Update error')) + update: sandbox.stub().rejects(new Error('Update error')), }; mockStackAPIClient.locale.returns(mockLocaleClient); // Mock cliux.inquire to return true (user confirms) - const inquireStub = sandbox.stub(require('@contentstack/cli-utilities').cliux, 'inquire').resolves({ confirmation: true }); + const inquireStub = sandbox + .stub(require('@contentstack/cli-utilities').cliux, 'inquire') + .resolves({ confirmation: true }); // Mock handleAndLogError to prevent the error from being thrown const handleAndLogErrorStub = sandbox.stub(require('@contentstack/cli-utilities'), 'handleAndLogError'); @@ -668,16 +718,19 @@ describe('ImportLocales', () => { expect(mockLocaleClient.update.called).to.be.true; }); - it('should handle writeConcurrency fallback (line 52)', () => { // Test the branch: this.localeConfig.writeConcurrency || this.config.writeConcurrency const tempConfig = JSON.parse(JSON.stringify(mockConfig)); tempConfig.modules.locales = { ...tempConfig.modules.locales, writeConcurrency: undefined }; tempConfig.writeConcurrency = 5; - - const moduleClassParams = { importConfig: tempConfig, stackAPIClient: mockStackAPIClient, moduleName: 'locales' as any }; + + const moduleClassParams = { + importConfig: tempConfig, + stackAPIClient: mockStackAPIClient, + moduleName: 'locales' as any, + }; const testInstance = new ImportLocales(moduleClassParams); - + expect(testInstance['reqConcurrency']).to.equal(5); }); @@ -685,13 +738,16 @@ describe('ImportLocales', () => { const tempConfig = JSON.parse(JSON.stringify(mockConfig)); tempConfig.modules.locales = { ...tempConfig.modules.locales, writeConcurrency: 10 }; tempConfig.writeConcurrency = 5; - - const moduleClassParams = { importConfig: tempConfig, stackAPIClient: mockStackAPIClient, moduleName: 'locales' as any }; + + const moduleClassParams = { + importConfig: tempConfig, + stackAPIClient: mockStackAPIClient, + moduleName: 'locales' as any, + }; const testInstance = new ImportLocales(moduleClassParams); - + expect(testInstance['reqConcurrency']).to.equal(10); }); - }); describe('createLocales', () => { @@ -707,7 +763,7 @@ describe('ImportLocales', () => { const mockLanguages = [ { uid: 'lang1', code: 'en-us', name: 'English' }, { uid: 'lang2', code: 'es-es', name: 'Spanish' }, - { uid: 'lang3', code: 'fr-fr', name: 'French' } + { uid: 'lang3', code: 'fr-fr', name: 'French' }, ]; localesInstance['languages'] = mockLanguages; localesInstance['masterLanguage'] = { code: 'en-us' }; @@ -738,9 +794,7 @@ describe('ImportLocales', () => { }); it('should handle onSuccess callback', async () => { - const mockLanguages = [ - { uid: 'lang1', code: 'es-es', name: 'Spanish' } - ]; + const mockLanguages = [{ uid: 'lang1', code: 'es-es', name: 'Spanish' }]; localesInstance['languages'] = mockLanguages; localesInstance['masterLanguage'] = { code: 'en-us' }; @@ -759,9 +813,7 @@ describe('ImportLocales', () => { }); it('should handle onReject callback with error code 247', async () => { - const mockLanguages = [ - { uid: 'lang1', code: 'es-es', name: 'Spanish' } - ]; + const mockLanguages = [{ uid: 'lang1', code: 'es-es', name: 'Spanish' }]; localesInstance['languages'] = mockLanguages; localesInstance['masterLanguage'] = { code: 'en-us' }; @@ -779,9 +831,7 @@ describe('ImportLocales', () => { }); it('should handle onReject callback with other error', async () => { - const mockLanguages = [ - { uid: 'lang1', code: 'es-es', name: 'Spanish' } - ]; + const mockLanguages = [{ uid: 'lang1', code: 'es-es', name: 'Spanish' }]; localesInstance['languages'] = mockLanguages; localesInstance['masterLanguage'] = { code: 'en-us' }; @@ -811,7 +861,7 @@ describe('ImportLocales', () => { it('should update all locales', async () => { const mockLanguages = [ { uid: 'lang1', code: 'en-us', name: 'English' }, - { uid: 'lang2', code: 'es-es', name: 'Spanish' } + { uid: 'lang2', code: 'es-es', name: 'Spanish' }, ]; localesInstance['languages'] = mockLanguages; @@ -826,9 +876,7 @@ describe('ImportLocales', () => { }); it('should handle onSuccess callback', async () => { - const mockLanguages = [ - { uid: 'lang1', code: 'en-us', name: 'English' } - ]; + const mockLanguages = [{ uid: 'lang1', code: 'en-us', name: 'English' }]; localesInstance['languages'] = mockLanguages; makeConcurrentCallStub.callsFake(async (args: any) => { @@ -844,9 +892,7 @@ describe('ImportLocales', () => { }); it('should handle onReject callback', async () => { - const mockLanguages = [ - { uid: 'lang1', code: 'en-us', name: 'English' } - ]; + const mockLanguages = [{ uid: 'lang1', code: 'en-us', name: 'English' }]; localesInstance['languages'] = mockLanguages; makeConcurrentCallStub.callsFake(async (args: any) => { @@ -865,9 +911,7 @@ describe('ImportLocales', () => { describe('Edge Cases', () => { it('should handle undefined apiData in callbacks', async () => { const makeConcurrentCallStub = sandbox.stub(localesInstance, 'makeConcurrentCall'); - const mockLanguages = [ - { uid: 'lang1', code: 'es-es', name: 'Spanish' } - ]; + const mockLanguages = [{ uid: 'lang1', code: 'es-es', name: 'Spanish' }]; localesInstance['languages'] = mockLanguages; localesInstance['masterLanguage'] = { code: 'en-us' }; @@ -881,9 +925,7 @@ describe('ImportLocales', () => { it('should handle undefined response in callbacks', async () => { const makeConcurrentCallStub = sandbox.stub(localesInstance, 'makeConcurrentCall'); - const mockLanguages = [ - { uid: 'lang1', code: 'es-es', name: 'Spanish' } - ]; + const mockLanguages = [{ uid: 'lang1', code: 'es-es', name: 'Spanish' }]; localesInstance['languages'] = mockLanguages; localesInstance['masterLanguage'] = { code: 'en-us' }; @@ -894,5 +936,4 @@ describe('ImportLocales', () => { expect(makeConcurrentCallStub.calledOnce).to.be.true; }); }); - }); diff --git a/packages/contentstack-import/test/unit/utils/extension-helper.test.ts b/packages/contentstack-import/test/unit/utils/extension-helper.test.ts index 7871775f3e..c9b5672182 100644 --- a/packages/contentstack-import/test/unit/utils/extension-helper.test.ts +++ b/packages/contentstack-import/test/unit/utils/extension-helper.test.ts @@ -34,44 +34,69 @@ describe('Extension Helper', () => { contentDir: '/test/content', data: '/test/content', modules: { + 'composable-studio': { + dirName: 'composable_studio', + fileName: 'composable_studio.json', + apiBaseUrl: 'https://composable-studio-api.contentstack.com', + apiVersion: 'v1', + }, apiConcurrency: 1, types: [], locales: { dirName: 'locales', fileName: 'locales.json', requiredKeys: ['code', 'name'] }, - customRoles: { dirName: 'custom_roles', fileName: 'custom_roles.json', customRolesLocalesFileName: 'custom_roles_locales.json' }, + customRoles: { + dirName: 'custom_roles', + fileName: 'custom_roles.json', + customRolesLocalesFileName: 'custom_roles_locales.json', + }, environments: { dirName: 'environments', fileName: 'environments.json' }, labels: { dirName: 'labels', fileName: 'labels.json' }, extensions: { dirName: 'extensions', fileName: 'extensions.json', validKeys: ['uid', 'title'] }, webhooks: { dirName: 'webhooks', fileName: 'webhooks.json' }, releases: { dirName: 'releases', fileName: 'releases.json', invalidKeys: ['uid'] }, workflows: { dirName: 'workflows', fileName: 'workflows.json', invalidKeys: ['uid'] }, - assets: { - dirName: 'assets', - assetBatchLimit: 10, - fileName: 'assets.json', - importSameStructure: false, - uploadAssetsConcurrency: 1, - displayExecutionTime: false, - importFoldersConcurrency: 1, - includeVersionedAssets: false, - host: 'https://api.contentstack.io', - folderValidKeys: ['uid', 'name'], - validKeys: ['uid', 'title'] + assets: { + dirName: 'assets', + assetBatchLimit: 10, + fileName: 'assets.json', + importSameStructure: false, + uploadAssetsConcurrency: 1, + displayExecutionTime: false, + importFoldersConcurrency: 1, + includeVersionedAssets: false, + host: 'https://api.contentstack.io', + folderValidKeys: ['uid', 'name'], + validKeys: ['uid', 'title'], + }, + 'assets-old': { + dirName: 'assets', + fileName: 'assets.json', + limit: 100, + host: 'https://api.contentstack.io', + validKeys: ['uid', 'title'], + assetBatchLimit: 10, + uploadAssetsConcurrency: 1, + importFoldersConcurrency: 1, }, - 'assets-old': { - dirName: 'assets', - fileName: 'assets.json', - limit: 100, - host: 'https://api.contentstack.io', - validKeys: ['uid', 'title'], - assetBatchLimit: 10, - uploadAssetsConcurrency: 1, - importFoldersConcurrency: 1 + content_types: { + dirName: 'content_types', + fileName: 'content_types.json', + validKeys: ['uid', 'title'], + limit: 100, + }, + 'content-types': { + dirName: 'content_types', + fileName: 'content_types.json', + validKeys: ['uid', 'title'], + limit: 100, }, - content_types: { dirName: 'content_types', fileName: 'content_types.json', validKeys: ['uid', 'title'], limit: 100 }, - 'content-types': { dirName: 'content_types', fileName: 'content_types.json', validKeys: ['uid', 'title'], limit: 100 }, entries: { dirName: 'entries', fileName: 'entries.json', invalidKeys: ['uid'], limit: 100, assetBatchLimit: 10 }, globalfields: { dirName: 'globalfields', fileName: 'globalfields.json', validKeys: ['uid', 'title'], limit: 100 }, - 'global-fields': { dirName: 'globalfields', fileName: 'globalfields.json', validKeys: ['uid', 'title'], limit: 100 }, + 'global-fields': { + dirName: 'globalfields', + fileName: 'globalfields.json', + validKeys: ['uid', 'title'], + limit: 100, + }, stack: { dirName: 'stack', fileName: 'stack.json' }, marketplace_apps: { dirName: 'marketplace_apps', fileName: 'marketplace_apps.json' }, masterLocale: { dirName: 'master_locale', fileName: 'master_locale.json', requiredKeys: ['code', 'name'] }, @@ -85,9 +110,19 @@ describe('Extension Helper', () => { attributes: { dirName: 'attributes', fileName: 'attributes.json' }, audiences: { dirName: 'audiences', fileName: 'audiences.json' }, events: { dirName: 'events', fileName: 'events.json' }, - experiences: { dirName: 'experiences', fileName: 'experiences.json', thresholdTimer: 1000, checkIntervalDuration: 100 } + experiences: { + dirName: 'experiences', + fileName: 'experiences.json', + thresholdTimer: 1000, + checkIntervalDuration: 100, + }, + }, + variantEntry: { + dirName: 'variant_entries', + fileName: 'variant_entries.json', + apiConcurrency: 1, + query: { locale: 'en-us' }, }, - variantEntry: { dirName: 'variant_entries', fileName: 'variant_entries.json', apiConcurrency: 1, query: { locale: 'en-us' } } }, branches: [{ uid: 'main', source: 'main' }], isAuthenticated: true, @@ -110,7 +145,7 @@ describe('Extension Helper', () => { globalfields: '/v3/globalfields', folders: '/v3/folders', stacks: '/v3/stacks', - labels: '/v3/labels' + labels: '/v3/labels', }, rateLimit: 5, preserveStackVersion: false, @@ -134,7 +169,7 @@ describe('Extension Helper', () => { contentVersion: 1, region: 'us' as any, 'exclude-global-modules': false, - context: {} as any + context: {} as any, }); describe('lookupExtension', () => { @@ -152,10 +187,10 @@ describe('Extension Helper', () => { { uid: 'nested-field', data_type: 'text', - extension_uid: 'ext-123' - } - ] - } + extension_uid: 'ext-123', + }, + ], + }, ]; const preserveStackVersion = false; const installedExtensions = {}; @@ -178,12 +213,12 @@ describe('Extension Helper', () => { schema: [ { uid: 'block-field', - data_type: 'text' - } - ] - } - ] - } + data_type: 'text', + }, + ], + }, + ], + }, ]; const preserveStackVersion = false; const installedExtensions = {}; @@ -207,12 +242,12 @@ describe('Extension Helper', () => { { uid: 'block-field', data_type: 'text', - extension_uid: 'ext-123' - } - ] - } - ] - } + extension_uid: 'ext-123', + }, + ], + }, + ], + }, ]; const preserveStackVersion = false; const installedExtensions = {}; @@ -229,8 +264,8 @@ describe('Extension Helper', () => { uid: 'ref-field', data_type: 'reference', reference_to: 'content-type-1', - field_metadata: {} as any - } + field_metadata: {} as any, + }, ]; const preserveStackVersion = false; const installedExtensions = {}; @@ -248,8 +283,8 @@ describe('Extension Helper', () => { uid: 'ref-field', data_type: 'reference', reference_to: 'content-type-1', - field_metadata: {} as any - } + field_metadata: {} as any, + }, ]; const preserveStackVersion = true; const installedExtensions = {}; @@ -268,13 +303,13 @@ describe('Extension Helper', () => { data_type: 'reference', extension_uid: 'old-ext-123', field_metadata: { - ref_multiple_content_types: true - } - } + ref_multiple_content_types: true, + }, + }, ]; const preserveStackVersion = false; const installedExtensions = { - 'old-ext-123': 'new-ext-456' + 'old-ext-123': 'new-ext-456', }; lookupExtension(config, schema, preserveStackVersion, installedExtensions); @@ -288,12 +323,12 @@ describe('Extension Helper', () => { { uid: 'text-field', data_type: 'text', - extension_uid: 'old-ext-123' - } + extension_uid: 'old-ext-123', + }, ]; const preserveStackVersion = false; const installedExtensions = { - 'old-ext-123': 'new-ext-456' + 'old-ext-123': 'new-ext-456', }; lookupExtension(config, schema, preserveStackVersion, installedExtensions); @@ -307,14 +342,14 @@ describe('Extension Helper', () => { { uid: 'global-field', data_type: 'global_field', - reference_to: 'global-field-123' - } + reference_to: 'global-field-123', + }, ]; const preserveStackVersion = false; const installedExtensions = {}; const globalFieldsMapping = { - 'global-field-123': 'mapped-global-field-456' + 'global-field-123': 'mapped-global-field-456', }; fsUtilityStub.withArgs(path.join(tempDir, 'mapper/globalfields/uid-mapping.json')).returns(globalFieldsMapping); @@ -330,8 +365,8 @@ describe('Extension Helper', () => { { uid: 'global-field', data_type: 'global_field', - reference_to: 'global-field-123' - } + reference_to: 'global-field-123', + }, ]; const preserveStackVersion = false; const installedExtensions = {}; @@ -349,14 +384,14 @@ describe('Extension Helper', () => { { uid: 'ext-field', data_type: 'text', - extension_uid: 'old-ext-123' - } + extension_uid: 'old-ext-123', + }, ]; const preserveStackVersion = false; const installedExtensions = {}; const extensionMapping = { - 'old-ext-123': 'new-ext-456' + 'old-ext-123': 'new-ext-456', }; fsUtilityStub.withArgs(path.join(tempDir, 'mapper/extensions/uid-mapping.json')).returns(extensionMapping); @@ -374,9 +409,9 @@ describe('Extension Helper', () => { data_type: 'text', extension_uid: 'old-ext-123', field_metadata: { - extension: true - } - } + extension: true, + }, + }, ]; const preserveStackVersion = false; const installedExtensions = {}; @@ -396,13 +431,13 @@ describe('Extension Helper', () => { data_type: 'text', extension_uid: 'old-ext-123', field_metadata: { - extension: true - } - } + extension: true, + }, + }, ]; const preserveStackVersion = false; const installedExtensions = { - 'old-ext-123': 'new-ext-456' + 'old-ext-123': 'new-ext-456', }; fsUtilityStub.withArgs(path.join(tempDir, 'mapper/extensions/uid-mapping.json')).returns({}); @@ -418,24 +453,26 @@ describe('Extension Helper', () => { { uid: 'json-field', data_type: 'json', - plugins: ['plugin-1', 'plugin-2'] - } + plugins: ['plugin-1', 'plugin-2'], + }, ]; const preserveStackVersion = false; const installedExtensions = {}; const extensionMapping = { - 'plugin-1': 'mapped-plugin-1' + 'plugin-1': 'mapped-plugin-1', }; const marketplaceMapping = { extension_uid: { - 'plugin-2': 'mapped-plugin-2' - } + 'plugin-2': 'mapped-plugin-2', + }, }; fsUtilityStub.withArgs(path.join(tempDir, 'mapper/extensions/uid-mapping.json')).returns(extensionMapping); - fsUtilityStub.withArgs(path.join(tempDir, 'mapper/marketplace_apps/uid-mapping.json')).returns(marketplaceMapping); + fsUtilityStub + .withArgs(path.join(tempDir, 'mapper/marketplace_apps/uid-mapping.json')) + .returns(marketplaceMapping); lookupExtension(config, schema, preserveStackVersion, installedExtensions); @@ -448,8 +485,8 @@ describe('Extension Helper', () => { { uid: 'json-field', data_type: 'json', - plugins: ['plugin-1', 'plugin-2'] - } + plugins: ['plugin-1', 'plugin-2'], + }, ]; const preserveStackVersion = false; const installedExtensions = {}; @@ -468,8 +505,8 @@ describe('Extension Helper', () => { { uid: 'json-field', data_type: 'json', - plugins: [] as string[] - } + plugins: [] as string[], + }, ]; const preserveStackVersion = false; const installedExtensions = {}; @@ -485,27 +522,27 @@ describe('Extension Helper', () => { { uid: 'text-field', data_type: 'text', - extension_uid: 'ext-1' + extension_uid: 'ext-1', }, { uid: 'ref-field', data_type: 'reference', reference_to: 'content-type-1', - field_metadata: {} as any + field_metadata: {} as any, }, { uid: 'global-field', data_type: 'global_field', - reference_to: 'global-1' - } + reference_to: 'global-1', + }, ]; const preserveStackVersion = false; const installedExtensions = { - 'ext-1': 'new-ext-1' + 'ext-1': 'new-ext-1', }; const globalFieldsMapping = { - 'global-1': 'mapped-global-1' + 'global-1': 'mapped-global-1', }; fsUtilityStub.withArgs(path.join(tempDir, 'mapper/globalfields/uid-mapping.json')).returns(globalFieldsMapping); @@ -523,13 +560,13 @@ describe('Extension Helper', () => { { uid: 'global-field', data_type: 'global_field', - reference_to: 'global-1' + reference_to: 'global-1', }, { uid: 'ext-field', data_type: 'text', - extension_uid: 'ext-1' - } + extension_uid: 'ext-1', + }, ]; const preserveStackVersion = false; const installedExtensions = {}; @@ -561,14 +598,14 @@ describe('Extension Helper', () => { data_type: 'reference', reference_to: 'content-type-1', field_metadata: { - ref_multiple_content_types: true + ref_multiple_content_types: true, }, - extension_uid: 'ext-123' - } + extension_uid: 'ext-123', + }, ]; const preserveStackVersion = false; const installedExtensions = { - 'ext-123': 'new-ext-456' + 'ext-123': 'new-ext-456', }; lookupExtension(config, schema, preserveStackVersion, installedExtensions); @@ -584,24 +621,26 @@ describe('Extension Helper', () => { { uid: 'json-field', data_type: 'json', - plugins: ['marketplace-plugin-1', 'extension-plugin-1'] - } + plugins: ['marketplace-plugin-1', 'extension-plugin-1'], + }, ]; const preserveStackVersion = false; const installedExtensions = {}; const extensionMapping = { - 'extension-plugin-1': 'mapped-extension-plugin-1' + 'extension-plugin-1': 'mapped-extension-plugin-1', }; const marketplaceMapping = { extension_uid: { - 'marketplace-plugin-1': 'mapped-marketplace-plugin-1' - } + 'marketplace-plugin-1': 'mapped-marketplace-plugin-1', + }, }; fsUtilityStub.withArgs(path.join(tempDir, 'mapper/extensions/uid-mapping.json')).returns(extensionMapping); - fsUtilityStub.withArgs(path.join(tempDir, 'mapper/marketplace_apps/uid-mapping.json')).returns(marketplaceMapping); + fsUtilityStub + .withArgs(path.join(tempDir, 'mapper/marketplace_apps/uid-mapping.json')) + .returns(marketplaceMapping); lookupExtension(config, schema, preserveStackVersion, installedExtensions); @@ -614,14 +653,14 @@ describe('Extension Helper', () => { { uid: 'ext-field', data_type: 'text', - extension_uid: 'old-ext-123' - } + extension_uid: 'old-ext-123', + }, ]; const preserveStackVersion = false; const installedExtensions = {}; const extensionMapping = { - 'old-ext-123': 'new-ext-456' + 'old-ext-123': 'new-ext-456', }; fsUtilityStub.withArgs(path.join(tempDir, 'mapper/extensions/uid-mapping.json')).returns(extensionMapping); diff --git a/packages/contentstack-migration/examples/01-transform-contenttype.js b/packages/contentstack-migration/examples/01-transform-contenttype.js index ee95904248..abf6d8e024 100644 --- a/packages/contentstack-migration/examples/01-transform-contenttype.js +++ b/packages/contentstack-migration/examples/01-transform-contenttype.js @@ -109,7 +109,7 @@ module.exports = async ({migration, stackSDKInstance}) => { entries.push(entryObj) } } catch (error) { - console.log(error) + console.log('Error', error) } }, } diff --git a/packages/contentstack-migration/examples/02-publishing-entries.js b/packages/contentstack-migration/examples/02-publishing-entries.js index 2eaf54749f..e21313cff7 100644 --- a/packages/contentstack-migration/examples/02-publishing-entries.js +++ b/packages/contentstack-migration/examples/02-publishing-entries.js @@ -23,7 +23,7 @@ module.exports = async ({migration, stackSDKInstance}) => { entry.publish({publishDetails, locale: 'en-us'}) } } catch (error) { - console.log(error) + console.log('Error', error) } }, } diff --git a/packages/contentstack-migration/examples/06-update-environment.js b/packages/contentstack-migration/examples/06-update-environment.js index 59d364d0fb..a622e6a437 100644 --- a/packages/contentstack-migration/examples/06-update-environment.js +++ b/packages/contentstack-migration/examples/06-update-environment.js @@ -16,7 +16,7 @@ module.exports = async ({ migration, config }) => { fs.accessSync(directory, fs.constants.W_OK); return true; } catch (err) { - console.log(`Permission Denied! You do not have the necessary write access for this directory.`); + console.log(`Permission denied. You do not have the necessary write access for this directory.`); return false; } } @@ -33,7 +33,7 @@ module.exports = async ({ migration, config }) => { if (!source || !destination) { throw new Error(`The Source or Destination Directory Path are not valid`); } else { - console.log(`You have permission to write to directory`); + console.log(`You have permission to write to the directory.`); } } catch (err) { console.log( @@ -63,7 +63,7 @@ module.exports = async ({ migration, config }) => { if (sourceUid && destUid) { envMapper[sourceUid] = destUid; } else { - console.log(`No Mapper Provided for the environment ${sourceName} or ${destName}`); + console.log(`No mapper provided for environment ${sourceName} or ${destName}`); } } } catch (err) { @@ -145,7 +145,7 @@ module.exports = async ({ migration, config }) => { ); }); } else { - console.log(`No Entries Exist for Content-type ${ct} in loclae ${locale}`); + console.log(`No entries exist for content type ${ct} in locale ${locale}`); } } } diff --git a/packages/contentstack-migration/examples/rename-field/01-rename-field.js b/packages/contentstack-migration/examples/rename-field/01-rename-field.js index 57f8fda237..72f461e882 100644 --- a/packages/contentstack-migration/examples/rename-field/01-rename-field.js +++ b/packages/contentstack-migration/examples/rename-field/01-rename-field.js @@ -89,7 +89,7 @@ module.exports = ({ migration, stackSDKInstance }) => { await entry.update() } } catch (error) { - console.log(error) + console.log('Error', error) } }, } diff --git a/packages/contentstack-migration/examples/rename-field/02-publishing-entries.js b/packages/contentstack-migration/examples/rename-field/02-publishing-entries.js index f17c3640a6..cbbe29a11e 100644 --- a/packages/contentstack-migration/examples/rename-field/02-publishing-entries.js +++ b/packages/contentstack-migration/examples/rename-field/02-publishing-entries.js @@ -24,7 +24,7 @@ module.exports = async ({migration, stackSDKInstance}) => { entry.publish({publishDetails, locale: 'en-us'}) } } catch (error) { - console.log(error) + console.log('Error', error) } }, } diff --git a/packages/contentstack-migration/src/modules/parser.js b/packages/contentstack-migration/src/modules/parser.js index 444adeeb22..8fbc763a96 100644 --- a/packages/contentstack-migration/src/modules/parser.js +++ b/packages/contentstack-migration/src/modules/parser.js @@ -72,7 +72,7 @@ class Parser { base.dispatch(callsite, null, { typeErrors }, 'typeError'); } } else { - console.log(error); + console.log('Error', error); // eslint-disable-next-line const [, filename, line] = error.stack.match(/\/([\/\w-_\.]+\.js):(\d*):(\d*)/); const callsite = { diff --git a/packages/contentstack-migration/src/utils/error-helper.js b/packages/contentstack-migration/src/utils/error-helper.js index 4858a1eed5..f1d3e8b9be 100644 --- a/packages/contentstack-migration/src/utils/error-helper.js +++ b/packages/contentstack-migration/src/utils/error-helper.js @@ -95,7 +95,7 @@ module.exports = (errors, filePath) => { } if (isEmpty(messages) && errors !== undefined && isEmpty(errorsByFile)) { logger.log('error', { errors: errors }); - console.log(chalk`{bold.red Migration unsuccessful}`); + console.log(chalk`{bold.red migration unsuccessful}`); } else { logger.log('error', { error: messages.join('\n') }); } diff --git a/packages/contentstack-migration/src/utils/modules.js b/packages/contentstack-migration/src/utils/modules.js index 6af8df0212..758c8313e1 100644 --- a/packages/contentstack-migration/src/utils/modules.js +++ b/packages/contentstack-migration/src/utils/modules.js @@ -12,7 +12,7 @@ function checkWritePermissionToDirectory(directory) { fs.accessSync(directory, fs.constants.W_OK); return true; } catch (err) { - console.log(`Permission Denied! You do not have the necessary write access for this directory.`); + console.log(`Permission denied. You do not have the necessary write access for this directory.`); return false; } } diff --git a/packages/contentstack-seed/package.json b/packages/contentstack-seed/package.json index f54cb018eb..83419c1e04 100644 --- a/packages/contentstack-seed/package.json +++ b/packages/contentstack-seed/package.json @@ -6,7 +6,7 @@ "bugs": "https://github.com/contentstack/cli/issues", "dependencies": { "@contentstack/cli-cm-import": "~2.0.0-beta.2", - "@contentstack/cli-command": "~1.6.1", + "@contentstack/cli-command": "~1.7.0", "@contentstack/cli-utilities": "~1.15.0", "@contentstack/management": "~1.22.0", "inquirer": "8.2.7", diff --git a/packages/contentstack-seed/src/seed/github/client.ts b/packages/contentstack-seed/src/seed/github/client.ts index 3484c2f4ab..2bd9a70133 100644 --- a/packages/contentstack-seed/src/seed/github/client.ts +++ b/packages/contentstack-seed/src/seed/github/client.ts @@ -111,7 +111,7 @@ export default class GitHubClient { const response: Record = await this.makeHeadApiCall(repo); return response.statusCode === 200; } catch (error) { - console.log(error); + console.log('Error', error); // do nothing } diff --git a/packages/contentstack-utilities/package.json b/packages/contentstack-utilities/package.json index 68430b1f92..f73b89fe24 100644 --- a/packages/contentstack-utilities/package.json +++ b/packages/contentstack-utilities/package.json @@ -46,7 +46,7 @@ "inquirer": "8.2.7", "inquirer-search-checkbox": "^1.0.0", "inquirer-search-list": "^1.2.6", - "js-yaml": "^4.1.0", + "js-yaml": "^4.1.1", "klona": "^2.0.6", "lodash": "^4.17.21", "mkdirp": "^1.0.4", diff --git a/packages/contentstack-utilities/src/auth-handler.ts b/packages/contentstack-utilities/src/auth-handler.ts index a7c2746a2e..c7157fd33e 100644 --- a/packages/contentstack-utilities/src/auth-handler.ts +++ b/packages/contentstack-utilities/src/auth-handler.ts @@ -137,7 +137,7 @@ class AuthHandler { await this.createHTTPServer(); await this.openOAuthURL(); } catch (error) { - this.logger.error('OAuth login failed', error.message); + this.logger.error('OAuth login failed!', error.message); throw error; } } @@ -148,7 +148,7 @@ class AuthHandler { const queryObject = url.parse(req.url, true).query; if (!queryObject.code) { - cliux.error('Error occoured while login with OAuth, please login with command - csdx auth:login --oauth'); + cliux.error('Error occurred while logging in with OAuth!'); return sendErrorResponse(res); } @@ -158,7 +158,7 @@ class AuthHandler { await this.getAccessToken(queryObject.code as string); await this.setOAuthBaseURL(); - cliux.print('Access token fetched using auth code successfully.'); + cliux.print('Access token successfully fetched using auth code.'); cliux.print( `You can review the access permissions on the page - ${this.OAuthBaseURL}/#!/marketplace/authorized-apps`, ); @@ -166,7 +166,7 @@ class AuthHandler { sendSuccessResponse(res); stopServer(); } catch (error) { - cliux.error('Error occoured while login with OAuth, please login with command - csdx auth:login --oauth'); + cliux.error('Error occurred while logging in with OAuth!'); cliux.error(error); sendErrorResponse(res); stopServer(); @@ -340,8 +340,8 @@ class AuthHandler { throw error; } } else { - cliux.error('Invalid/Empty access token.'); - throw new Error('Invalid/Empty access token'); + cliux.error('Invalid or empty access token.'); + throw new Error('Invalid or empty access token.'); } } @@ -394,7 +394,7 @@ class AuthHandler { const oauthValidUpto = new Date(); oauthValidUpto.setTime(oauthDate.getTime() + 59 * 60 * 1000); if (force) { - cliux.print('Force refreshing the token'); + cliux.print('Forcing token refresh...'); return this.refreshToken(); } else { if (oauthValidUpto > now) { @@ -418,7 +418,7 @@ class AuthHandler { } } } else { - cliux.print('No OAuth set'); + cliux.print('No OAuth configuration set.'); this.unsetConfigData(); } } diff --git a/packages/contentstack-utilities/src/config-handler.ts b/packages/contentstack-utilities/src/config-handler.ts index e32c79a355..45f24f49b4 100644 --- a/packages/contentstack-utilities/src/config-handler.ts +++ b/packages/contentstack-utilities/src/config-handler.ts @@ -52,7 +52,7 @@ class Config { this.removeOldConfigStoreFile(); } } catch (error) { - console.log('No data to be imported from Old config file'); + console.log('No data to import from old configuration file.'); } this.set(OLD_CONFIG_BACKUP_FLAG, true); diff --git a/packages/contentstack-utilities/src/flag-deprecation-check.ts b/packages/contentstack-utilities/src/flag-deprecation-check.ts index 4fe3fdf9c4..ce034703af 100644 --- a/packages/contentstack-utilities/src/flag-deprecation-check.ts +++ b/packages/contentstack-utilities/src/flag-deprecation-check.ts @@ -21,19 +21,19 @@ export default function (deprecatedFlags = [], suggestions = [], customMessage?: }); if (isCommandHasDeprecationFlag) { - let depreactionMessage = ''; + let deprecationMessage = ''; if (customMessage) { - depreactionMessage = customMessage; + deprecationMessage = customMessage; } else { - depreactionMessage = `WARNING!!! You're using the old (soon to be deprecated) Contentstack CLI flags (${deprecatedFlags.join( + deprecationMessage = `WARNING!!! You're using the old (soon to be deprecated) Contentstack CLI flags (${deprecatedFlags.join( ', ', )}).`; if (suggestions.length > 0) { - depreactionMessage += ` We recommend you to use the updated flags (${suggestions.join(', ')}).`; + deprecationMessage += ` We recommend you to use the updated flags (${suggestions.join(', ')}).`; } } - cliux.print(depreactionMessage, { color: 'yellow' }); + cliux.print(deprecationMessage, { color: 'yellow' }); } return input; diff --git a/packages/contentstack-utilities/src/logger.ts b/packages/contentstack-utilities/src/logger.ts index a38ca510ac..24d21f52e2 100644 --- a/packages/contentstack-utilities/src/logger.ts +++ b/packages/contentstack-utilities/src/logger.ts @@ -29,7 +29,7 @@ export class LoggerService { try { stringifiedParam = JSON.stringify(info.obj); } catch (error) { - console.log('warning: failed to log the result'); + console.log('Warning: Failed to log the result'); } // parse message info.message = messageHandler.parse(info.message as string); diff --git a/packages/contentstack-utilities/src/logger/log.ts b/packages/contentstack-utilities/src/logger/log.ts index b1ae6861bb..fb40f7f0d1 100644 --- a/packages/contentstack-utilities/src/logger/log.ts +++ b/packages/contentstack-utilities/src/logger/log.ts @@ -5,6 +5,7 @@ import { default as Logger } from './logger'; import { CLIErrorHandler } from './cli-error-handler'; import { ErrorContext } from '../interfaces'; import { configHandler } from '..'; +import { getSessionLogPath } from './session-path'; let loggerInstance: Logger | null = null; @@ -105,4 +106,6 @@ function getLogPath(): string { return path.join(os.homedir(), 'contentstack', 'logs'); } +// Re-export getSessionLogPath for external use +export { getSessionLogPath } from './session-path'; export { v2Logger, cliErrorHandler, handleAndLogError, getLogPath }; diff --git a/packages/contentstack-utilities/src/logger/logger.ts b/packages/contentstack-utilities/src/logger/logger.ts index c3612b7dbd..31668d3f8a 100644 --- a/packages/contentstack-utilities/src/logger/logger.ts +++ b/packages/contentstack-utilities/src/logger/logger.ts @@ -4,7 +4,7 @@ import { normalize } from 'path'; import * as winston from 'winston'; import { levelColors, logLevels, PROGRESS_SUPPORTED_MODULES } from '../constants/logging'; import { LoggerConfig, LogLevel, LogType } from '../interfaces/index'; -import { configHandler } from '..'; +import { getSessionLogPath } from './session-path'; export default class Logger { private loggers: Record; @@ -37,7 +37,9 @@ export default class Logger { } getLoggerInstance(level: 'error' | 'info' | 'warn' | 'debug' | 'hidden' = 'info'): winston.Logger { - const filePath = normalize(process.env.CS_CLI_LOG_PATH || this.config.basePath).replace(/^(\.\.(\/|\\|$))+/, ''); + // Use session-based path for date-organized logging + const sessionPath = getSessionLogPath(); + const filePath = normalize(sessionPath).replace(/^(\.\.(\/|\\|$))+/, ''); return this.createLogger(level === 'hidden' ? 'error' : level, filePath); } diff --git a/packages/contentstack-utilities/src/logger/session-path.ts b/packages/contentstack-utilities/src/logger/session-path.ts new file mode 100644 index 0000000000..2d5de07efd --- /dev/null +++ b/packages/contentstack-utilities/src/logger/session-path.ts @@ -0,0 +1,51 @@ +import * as fs from 'fs'; +import * as path from 'path'; +import { configHandler, formatDate, formatTime } from '..'; +import { getLogPath } from './log'; + +/** + * Get the session-based log path for date-organized logging + * Structure: {basePath}/{YYYY-MM-DD}/{command}-{YYYYMMDD-HHMMSS}-{sessionId}/ + * + * @returns The session-specific log directory path + */ +export function getSessionLogPath(): string { + // Get base log path + const basePath = getLogPath(); + + // Get current date in YYYY-MM-DD format + const now = new Date(); + const dateStr = now.toISOString().split('T')[0]; // YYYY-MM-DD + + // Get command ID (fallback to 'unknown' if not set) + let commandId = configHandler.get('currentCommandId') || 'unknown'; + // Sanitize command ID - remove colons and replace with hyphens for folder name + commandId = commandId?.replace(/:/g, '-'); + + // Use helper methods to format date and time + const dateStrFormatted = formatDate(now); // YYYYMMDD + const timeStrFormatted = formatTime(now); // HHMMSS + const timestamp = `${dateStrFormatted}-${timeStrFormatted}`; // YYYYMMDD-HHMMSS + + let sessionId = configHandler.get('sessionId'); + if (!sessionId) { + // Format: first 8 chars of command + timestamp (YYYYMMDDHHMMSS) + const timestampForId = `${dateStrFormatted}${timeStrFormatted}`; // YYYYMMDDHHMMSS + const commandHash = commandId.substring(0, 8).padEnd(8, '0'); // Use first 8 chars of command + sessionId = `${commandHash}-${timestampForId}`; + } + + // Create session folder name: command-YYYYMMDD-HHMMSS-sessionId + const sessionFolderName = `${commandId}-${timestamp}-${sessionId}`; + + // Build full session path + const sessionPath = path.join(basePath, dateStr, sessionFolderName); + + // Ensure directory exists + if (!fs.existsSync(sessionPath)) { + fs.mkdirSync(sessionPath, { recursive: true }); + } + + return sessionPath; +} + diff --git a/packages/contentstack-utilities/src/message-handler.ts b/packages/contentstack-utilities/src/message-handler.ts index 92c37bfe02..bbeb78a096 100644 --- a/packages/contentstack-utilities/src/message-handler.ts +++ b/packages/contentstack-utilities/src/message-handler.ts @@ -23,7 +23,7 @@ class Messages { if (error.code === 'ENOENT') { this.messages = {}; } else { - throw new CLIError(error.message); + throw new CLIError(`Error: ${error.message}`); } } } diff --git a/packages/contentstack-utilities/test/unit/auth-handler.test.ts b/packages/contentstack-utilities/test/unit/auth-handler.test.ts index de7e37279c..295da6f037 100644 --- a/packages/contentstack-utilities/test/unit/auth-handler.test.ts +++ b/packages/contentstack-utilities/test/unit/auth-handler.test.ts @@ -360,7 +360,7 @@ describe('Auth Handler', () => { throw new Error('Expected getUserDetails to throw'); // ensure failure if no error is thrown } catch (error) { expect(error).to.be.instanceOf(Error); - expect(error.message).to.equal('Invalid/Empty access token'); + expect(error.message).to.equal('Invalid or empty access token.'); } }); }); @@ -503,7 +503,7 @@ describe('Auth Handler', () => { await authHandler.compareOAuthExpiry(); } catch (error) { expect(error).to.be.undefined; - expect(cliuxPrintStub.calledOnceWithExactly('Force refreshing the token')).to.be.true; + expect(cliuxPrintStub.calledOnceWithExactly('Forcing token refresh...')).to.be.true; expect(refreshTokenStub.calledOnce).to.be.true; expect(unsetConfigDataStub.called).to.be.false; } diff --git a/packages/contentstack-utilities/test/unit/cliErrorHandler.test.ts b/packages/contentstack-utilities/test/unit/cliErrorHandler.test.ts index 864de0ed0c..d2aa074245 100644 --- a/packages/contentstack-utilities/test/unit/cliErrorHandler.test.ts +++ b/packages/contentstack-utilities/test/unit/cliErrorHandler.test.ts @@ -7,7 +7,7 @@ describe('CLIErrorHandler', () => { let errorHandler: CLIErrorHandler; beforeEach(() => { - errorHandler = new CLIErrorHandler(); + errorHandler = new CLIErrorHandler(); }); fancy.it('should normalize string error to Error object', () => { @@ -36,7 +36,7 @@ describe('CLIErrorHandler', () => { expect(hidden).to.equal(true); }); - fancy.it('should extract debug payload correctly', () => { + fancy.it('should extract error payload correctly', () => { const error = new Error('API error'); (error as any).status = 500; (error as any).statusText = 'Internal Server Error'; @@ -52,11 +52,14 @@ describe('CLIErrorHandler', () => { data: { error: 'fail' }, headers: { 'content-type': 'application/json' }, }; + (error as any).status = 500; // Also set status on error directly - const debugPayload = errorHandler['extractErrorPayload'](error); - expect(debugPayload.request.method).to.equal('GET'); - expect(debugPayload.response.status).to.equal(500); - expect(debugPayload.status).to.equal(500); + const errorPayload = errorHandler['extractErrorPayload'](error); + expect(errorPayload.request.method).to.equal('GET'); + expect(errorPayload.response.status).to.equal(500); + expect(errorPayload.status).to.equal(500); + expect(errorPayload.name).to.equal('Error'); + expect(errorPayload.message).to.equal('API error'); }); fancy.it('should return full classified error with context', () => { @@ -68,7 +71,7 @@ describe('CLIErrorHandler', () => { }); expect(classified.type).to.equal(ERROR_TYPES.SERVER_ERROR); - expect(classified.message).to.equal('Test error (HTTP 502)'); + expect(classified.message).to.equal('Test error'); expect(classified.meta?.operation).to.equal('testOp'); expect(classified.meta?.component).to.equal('testComponent'); expect(classified.meta?.email).to.be.undefined; @@ -87,16 +90,15 @@ describe('CLIErrorHandler', () => { sessionId: 's1', userId: 'u1', orgId: 'o1', - operation: 'test', - component: 'testComponent', - }); + }, 'API_ERROR'); + // extractMeta only extracts specific fields: operation, component, userId, sessionId, orgId, email + // apiKey is not extracted by extractMeta expect(meta).to.deep.equal({ email: 'a@b.com', sessionId: 's1', userId: 'u1', orgId: 'o1', - operation: 'test', - component: 'testComponent', + errorType: 'API_ERROR', }); }); @@ -109,6 +111,6 @@ describe('CLIErrorHandler', () => { const result = errorHandler.classifyError(invalidError); expect(result.type).to.equal(ERROR_TYPES.NORMALIZATION); - expect(result.message).to.include('Failed to process error'); + expect(result.message).to.equal('Failed to process error'); }); }); diff --git a/packages/contentstack-utilities/test/unit/helper.test.ts b/packages/contentstack-utilities/test/unit/helper.test.ts index c7ee34b3d3..2a7e716e4b 100644 --- a/packages/contentstack-utilities/test/unit/helper.test.ts +++ b/packages/contentstack-utilities/test/unit/helper.test.ts @@ -27,7 +27,7 @@ describe('Testing the Validate function', () => { describe('Testing the getBranchFromAlias function', () => { describe('When branch alias exists and resolves successfully', () => { it('should return the branch UID', async () => { - const mockStack = { + const mockStack: any = { branchAlias: (alias: string) => ({ fetch: async () => ({ uid: 'main-branch' }) }) @@ -60,7 +60,7 @@ describe('Testing the getBranchFromAlias function', () => { }); it('should throw error for null branchAlias', async () => { - const mockStack = { + const mockStack: any = { branchAlias: (alias: string) => ({ fetch: async () => ({ uid: 'main-branch' }) }) @@ -76,7 +76,7 @@ describe('Testing the getBranchFromAlias function', () => { }); it('should throw error for undefined branchAlias', async () => { - const mockStack = { + const mockStack: any = { branchAlias: (alias: string) => ({ fetch: async () => ({ uid: 'main-branch' }) }) @@ -92,14 +92,14 @@ describe('Testing the getBranchFromAlias function', () => { }); it('should throw error for non-string branchAlias', async () => { - const mockStack = { + const mockStack: any = { branchAlias: (alias: string) => ({ fetch: async () => ({ uid: 'main-branch' }) }) }; try { - await getBranchFromAlias(mockStack, 123); + await getBranchFromAlias(mockStack, 123 as any); expect.fail('Expected function to throw an error'); } catch (error) { expect(error).to.be.instanceOf(Error); @@ -108,7 +108,7 @@ describe('Testing the getBranchFromAlias function', () => { }); it('should throw error for empty string branchAlias', async () => { - const mockStack = { + const mockStack: any = { branchAlias: (alias: string) => ({ fetch: async () => ({ uid: 'main-branch' }) }) @@ -126,7 +126,7 @@ describe('Testing the getBranchFromAlias function', () => { describe('When branch alias does not exist', () => { it('should throw an error', async () => { - const mockStack = { + const mockStack: any = { branchAlias: (alias: string) => ({ fetch: async () => { throw new Error('Branch alias not found'); @@ -146,7 +146,7 @@ describe('Testing the getBranchFromAlias function', () => { describe('When response is missing UID', () => { it('should throw error for response without uid', async () => { - const mockStack = { + const mockStack: any = { branchAlias: (alias: string) => ({ fetch: async () => ({ name: 'main-branch' }) // missing uid }) @@ -162,7 +162,7 @@ describe('Testing the getBranchFromAlias function', () => { }); it('should throw error for response with null uid', async () => { - const mockStack = { + const mockStack: any = { branchAlias: (alias: string) => ({ fetch: async () => ({ uid: null }) }) @@ -178,7 +178,7 @@ describe('Testing the getBranchFromAlias function', () => { }); it('should throw error for response with undefined uid', async () => { - const mockStack = { + const mockStack: any = { branchAlias: (alias: string) => ({ fetch: async () => ({ uid: undefined }) }) @@ -194,7 +194,7 @@ describe('Testing the getBranchFromAlias function', () => { }); it('should throw error for response with empty string uid', async () => { - const mockStack = { + const mockStack: any = { branchAlias: (alias: string) => ({ fetch: async () => ({ uid: '' }) }) @@ -210,7 +210,7 @@ describe('Testing the getBranchFromAlias function', () => { }); it('should throw error for empty response object', async () => { - const mockStack = { + const mockStack: any = { branchAlias: (alias: string) => ({ fetch: async () => ({}) }) @@ -229,7 +229,7 @@ describe('Testing the getBranchFromAlias function', () => { describe('When network error occurs', () => { it('should throw the network error', async () => { const networkError = new Error('Network timeout'); - const mockStack = { + const mockStack: any = { branchAlias: (alias: string) => ({ fetch: async () => { throw networkError; diff --git a/packages/contentstack-utilities/test/unit/logger.test.ts b/packages/contentstack-utilities/test/unit/logger.test.ts index d9af947c2c..502d9d5d94 100644 --- a/packages/contentstack-utilities/test/unit/logger.test.ts +++ b/packages/contentstack-utilities/test/unit/logger.test.ts @@ -1,7 +1,12 @@ import { expect } from 'chai'; import { fancy } from 'fancy-test'; import sinon from 'sinon'; +import * as fs from 'fs'; +import * as path from 'path'; +import * as os from 'os'; import Logger from '../../src/logger/logger'; +import { getSessionLogPath } from '../../src/logger/session-path'; +import configHandler from '../../src/config-handler'; describe('Logger', () => { let logger: Logger; @@ -32,48 +37,37 @@ describe('Logger', () => { other: 'safe', }; - const redacted = logger['redact'](testMeta); - expect(redacted.password).to.equal('[REDACTED]'); + // Test file mode redaction (consoleMode = false) + const redacted = logger['redact'](testMeta, false); + // In file mode, only token and secret are redacted (not password or email) expect(redacted.token).to.equal('[REDACTED]'); - expect(redacted.email).to.equal('[REDACTED]'); expect(redacted.other).to.equal('safe'); + + // Test console mode redaction (consoleMode = true) + const consoleRedacted = logger['redact'](testMeta, true); + // In console mode, password and token are redacted (email is not in consoleSensitiveKeys) + expect(consoleRedacted.password).to.equal('[REDACTED]'); + expect(consoleRedacted.token).to.equal('[REDACTED]'); + expect(consoleRedacted.email).to.equal('user@example.com'); // Email is not redacted + expect(consoleRedacted.other).to.equal('safe'); }); - fancy.it('should handle complex nested objects in redaction', () => { - const complexObj = { - user: { - email: 'test@example.com', - profile: { - password: 'secret123', - settings: { - apiKey: 'key123', - normal: 'value' - } - } - }, - config: { - token: 'token123', - other: 'safe' - } - }; - - const redacted = logger['redact'](complexObj); - expect(redacted.user.email).to.equal('[REDACTED]'); - expect(redacted.user.profile.password).to.equal('[REDACTED]'); - expect(redacted.user.profile.settings.apiKey).to.equal('[REDACTED]'); - expect(redacted.user.profile.settings.normal).to.equal('value'); - expect(redacted.config.token).to.equal('[REDACTED]'); - expect(redacted.config.other).to.equal('safe'); - }); + // Note: isLogEntry method doesn't exist in the Logger class + // This test is removed as it tests non-existent functionality fancy.it('should log error messages using error method', () => { const errorLogger = logger['loggers'].error; const spy = sinon.spy(); + const originalError = errorLogger.error.bind(errorLogger); errorLogger.error = spy; logger.error('error message', { some: 'meta' }); expect(spy.calledOnce).to.be.true; + // The logger adds level: 'error' to meta expect(spy.calledWith('error message', { some: 'meta', level: 'error' })).to.be.true; + + // Restore original + errorLogger.error = originalError; }); fancy.it('should return correct result from shouldLog()', () => { @@ -87,11 +81,18 @@ describe('Logger', () => { fancy.it('logSuccess should call success info logger', () => { const successLogger = logger['loggers'].success; const spy = sinon.spy(); - successLogger.info = spy; + const originalLog = successLogger.log.bind(successLogger); + successLogger.log = spy; logger.logSuccess({ type: 'test', message: 'Success message' }); expect(spy.calledOnce).to.be.true; - expect(spy.args[0][0].message).to.equal('Success message'); + // logSuccess creates a logPayload object with level, message, timestamp, and meta + const logPayload = spy.args[0][0]; + expect(logPayload.message).to.equal('Success message'); + expect(logPayload.meta.type).to.equal('test'); + + // Restore original + successLogger.log = originalLog; }); fancy.it('shouldLog should handle file target level filtering', () => { @@ -99,13 +100,19 @@ describe('Logger', () => { expect(result).to.equal(false); }); - fancy.it('success logger should include success type in meta', () => { + fancy.it('success logger should call log method', () => { + const successLogger = logger['loggers'].success; const spy = sinon.spy(); - logger['loggers'].success.info = spy; + const originalLog = successLogger.log.bind(successLogger); + successLogger.log = spy; logger.success('It worked!', { extra: 'meta' }); expect(spy.calledOnce).to.be.true; - expect(spy.args[0][1].type).to.equal('success'); + // success() calls log('success', message, meta) + expect(spy.calledWith('success', 'It worked!', { extra: 'meta' })).to.be.true; + + // Restore original + successLogger.log = originalLog; }); fancy.it('logError with hidden true logs to debug logger', () => { @@ -135,9 +142,16 @@ describe('Logger', () => { token: 'abc', [Symbol.for('splat')]: [{ password: '1234' }], }; - const result = logger['redact'](obj); + // Test file mode (consoleMode = false) - token is redacted, password is not + const result = logger['redact'](obj, false); expect(result.token).to.equal('[REDACTED]'); - expect(result[Symbol.for('splat')][0].password).to.equal('[REDACTED]'); + // In file mode, password is not redacted + expect(result[Symbol.for('splat')][0].password).to.equal('1234'); + + // Test console mode (consoleMode = true) - both token and password are redacted + const consoleResult = logger['redact'](obj, true); + expect(consoleResult.token).to.equal('[REDACTED]'); + expect(consoleResult[Symbol.for('splat')][0].password).to.equal('[REDACTED]'); }); fancy.it('redact should return original if klona fails', () => { @@ -164,7 +178,7 @@ describe('Logger', () => { logger.logWarn({ type: 'testType', message: 'Warn occurred', - context: { module: 'test' }, + context: { context: 'warnContext' }, meta: { custom: 'value' } }); @@ -217,69 +231,224 @@ describe('Logger', () => { expect(defaultLogger['shouldLog']('info', 'console')).to.equal(true); expect(defaultLogger['shouldLog']('debug', 'console')).to.equal(false); }); +}); - fancy.it('shouldLog should handle undefined levels gracefully', () => { - expect(logger['shouldLog']('unknown' as any, 'console')).to.equal(true); // Should default to info level - }); - - fancy.it('success method should use info logger with success type', () => { - const successLogger = logger['loggers'].success; - const spy = sinon.spy(); - successLogger.info = spy; +describe('Session Log Path', () => { + let sandbox: sinon.SinonSandbox; + let tempDir: string; - logger.success('Success message', { extra: 'data' }); - expect(spy.calledOnce).to.be.true; - expect(spy.args[0][1].type).to.equal('success'); + beforeEach(() => { + sandbox = sinon.createSandbox(); + // Create a temporary directory for testing + tempDir = path.join(os.tmpdir(), `csdx-log-test-${Date.now()}`); + fs.mkdirSync(tempDir, { recursive: true }); }); - fancy.it('logSuccess should use info method instead of log', () => { - const successLogger = logger['loggers'].success; - const spy = sinon.spy(); - successLogger.info = spy; + afterEach(() => { + sandbox.restore(); + // Clean up temp directory + if (fs.existsSync(tempDir)) { + fs.rmSync(tempDir, { recursive: true, force: true }); + } + }); - logger.logSuccess({ - type: 'test', - message: 'Test success', - data: { test: 'data' }, + fancy + .stub(configHandler, 'get', (...args: any[]) => { + const key = args[0]; + if (key === 'log.path') return tempDir; + if (key === 'currentCommandId') return 'import'; + if (key === 'sessionId') return 'test-session-123'; + return undefined; + }) + .it('should create session path with correct date folder structure', () => { + const sessionPath = getSessionLogPath(); + + // Verify path contains date folder (YYYY-MM-DD) + const dateRegex = /\d{4}-\d{2}-\d{2}/; + expect(sessionPath).to.match(dateRegex); + + // Verify path contains session folder with command-timestamp-sessionId format + const sessionFolderRegex = /import-\d{8}-\d{6}-test-session-123/; + expect(sessionPath).to.match(sessionFolderRegex); + + // Verify directory was created + expect(fs.existsSync(sessionPath)).to.be.true; + + // Verify it's a directory + const stats = fs.statSync(sessionPath); + expect(stats.isDirectory()).to.be.true; }); - expect(spy.calledOnce).to.be.true; - expect(spy.args[0][0].meta.type).to.equal('test'); - expect(spy.args[0][0].meta.data.test).to.equal('data'); - }); + fancy + .stub(configHandler, 'get', (...args: any[]) => { + const key = args[0]; + if (key === 'log.path') return tempDir; + if (key === 'currentCommandId') return 'export:stack'; + if (key === 'sessionId') return 'test-session-456'; + return undefined; + }) + .it('should sanitize command ID by replacing colons with hyphens', () => { + const sessionPath = getSessionLogPath(); + + // Verify colons are replaced with hyphens + expect(sessionPath).to.include('export-stack'); + expect(sessionPath).to.not.include('export:stack'); + + // Verify directory was created + expect(fs.existsSync(sessionPath)).to.be.true; + }); - fancy.it('should handle redaction errors gracefully', () => { - const problematicLogger = new Logger({ - basePath: './logs', - consoleLogLevel: 'info', - logLevel: 'info', + fancy + .stub(configHandler, 'get', (...args: any[]) => { + const key = args[0]; + if (key === 'log.path') return tempDir; + if (key === 'currentCommandId') return undefined; + if (key === 'sessionId') return 'test-session-789'; + return undefined; + }) + .it('should use "unknown" as command ID when not set', () => { + const sessionPath = getSessionLogPath(); + + // Verify "unknown" is used as command ID + expect(sessionPath).to.include('unknown-'); + + // Verify directory was created + expect(fs.existsSync(sessionPath)).to.be.true; }); - const obj = { - password: 'secret', - get circular() { - return this; - }, - }; + fancy + .stub(configHandler, 'get', (...args: any[]) => { + const key = args[0]; + if (key === 'log.path') return tempDir; + if (key === 'currentCommandId') return 'auth'; + if (key === 'sessionId') return undefined; + return undefined; + }) + .stub(configHandler, 'set', () => {}) + .it('should generate sessionId when not set', () => { + const sessionPath = getSessionLogPath(); + + // Verify path contains a session ID (short UUID format) + // Short UUIDs are typically 22 characters + const sessionIdMatch = sessionPath.match(/auth-\d{8}-\d{6}-(.+)$/); + expect(sessionIdMatch).to.not.be.null; + expect(sessionIdMatch![1]).to.have.length.greaterThan(0); + + // Verify directory was created + expect(fs.existsSync(sessionPath)).to.be.true; + }); - // Should not throw error - const result = problematicLogger['redact'](obj); - // If redaction fails, it should return the original object - expect(result).to.not.be.undefined; - }); + fancy + .stub(configHandler, 'get', (...args: any[]) => { + const key = args[0]; + if (key === 'log.path') return tempDir; + if (key === 'currentCommandId') return 'test-command'; + if (key === 'sessionId') return 'session-abc'; + return undefined; + }) + .it('should create session path with correct format: command-YYYYMMDD-HHMMSS-sessionId', () => { + const sessionPath = getSessionLogPath(); + + // Extract the session folder name + const parts = sessionPath.split(path.sep); + const sessionFolder = parts[parts.length - 1]; + + // Verify format: command-YYYYMMDD-HHMMSS-sessionId + const formatRegex = /^test-command-\d{8}-\d{6}-session-abc$/; + expect(sessionFolder).to.match(formatRegex); + + // Verify date folder format: YYYY-MM-DD + const dateFolder = parts[parts.length - 2]; + const dateRegex = /^\d{4}-\d{2}-\d{2}$/; + expect(dateFolder).to.match(dateRegex); + }); - fancy.it('should detect sensitive keys correctly', () => { - expect(logger['isSensitiveKey']('password')).to.be.true; - expect(logger['isSensitiveKey']('authtoken')).to.be.true; - expect(logger['isSensitiveKey']('api_key')).to.be.true; - expect(logger['isSensitiveKey']('management-token')).to.be.true; - expect(logger['isSensitiveKey']('normalKey')).to.be.false; - expect(logger['isSensitiveKey']('')).to.be.false; - }); + fancy + .stub(configHandler, 'get', (...args: any[]) => { + const key = args[0]; + if (key === 'log.path') return tempDir; + if (key === 'currentCommandId') return 'import'; + if (key === 'sessionId') return 'test-session'; + return undefined; + }) + .it('should create nested directories recursively', () => { + const sessionPath = getSessionLogPath(); + + // Verify all parent directories exist + const dateFolder = path.dirname(sessionPath); + const baseFolder = path.dirname(dateFolder); + + expect(fs.existsSync(baseFolder)).to.be.true; + expect(fs.existsSync(dateFolder)).to.be.true; + expect(fs.existsSync(sessionPath)).to.be.true; + }); - fancy.it('should handle non-string keys in sensitive key detection', () => { - expect(logger['isSensitiveKey'](123 as any)).to.be.false; - expect(logger['isSensitiveKey'](null as any)).to.be.false; - expect(logger['isSensitiveKey'](undefined as any)).to.be.false; - }); + fancy + .stub(configHandler, 'get', (...args: any[]) => { + const key = args[0]; + if (key === 'log.path') return tempDir; + if (key === 'currentCommandId') return 'import'; + if (key === 'sessionId') return 'test-session'; + return undefined; + }) + .it('should use session path for logger file paths', () => { + // Get the session path before creating logger to ensure consistency + // (Logger constructor calls getSessionLogPath multiple times, but with same stub + // it should generate the same path within the same second) + const expectedSessionPath = getSessionLogPath(); + + // Verify the session path has the correct structure + expect(expectedSessionPath).to.match(/import-\d{8}-\d{6}-test-session/); + expect(expectedSessionPath).to.match(/\d{4}-\d{2}-\d{2}/); // Contains date folder + + const logger = new Logger({ + basePath: tempDir, + consoleLogLevel: 'info', + logLevel: 'info', + }); + + const winLogger = logger.getLoggerInstance('error'); + + // The winston logger should have transports configured + expect(winLogger.transports).to.have.length.greaterThan(0); + + // Verify file transport exists + const fileTransport = winLogger.transports.find((t: any) => t.filename); + expect(fileTransport).to.not.be.undefined; + + // Logger constructor calls getSessionLogPath() 5 times, creating log files + // Write a log entry to ensure the file is actually created + winLogger.error('Test log entry'); + + // Winston may write asynchronously, so we need to check the actual file path + // Get the actual filename from winston transport + const winstonFilePath = (fileTransport as any).filename; + + // Winston stores the full path in filename, but it might be normalized + // If it's just a filename, resolve it relative to the session path + let actualLogFile: string; + if (path.isAbsolute(winstonFilePath)) { + actualLogFile = winstonFilePath; + } else if (winstonFilePath.includes('/')) { + // Relative path - resolve from tempDir + actualLogFile = path.resolve(tempDir, winstonFilePath); + } else { + // Just filename - use expected session path + actualLogFile = path.join(expectedSessionPath, winstonFilePath); + } + + // Verify the log file path contains the session structure + expect(actualLogFile).to.match(/import-\d{8}-\d{6}-test-session/); + expect(actualLogFile).to.match(/error\.log$/); + + // Verify the directory structure exists + const logDir = path.dirname(actualLogFile); + expect(fs.existsSync(logDir)).to.be.true; + expect(logDir).to.match(/import-\d{8}-\d{6}-test-session/); + + // Verify the date folder exists + const dateFolder = path.dirname(logDir); + expect(fs.existsSync(dateFolder)).to.be.true; + expect(dateFolder).to.match(/\d{4}-\d{2}-\d{2}/); + }); }); diff --git a/packages/contentstack-variants/src/export/audiences.ts b/packages/contentstack-variants/src/export/audiences.ts index 92c1084cc7..da97798e21 100644 --- a/packages/contentstack-variants/src/export/audiences.ts +++ b/packages/contentstack-variants/src/export/audiences.ts @@ -52,7 +52,7 @@ export default class ExportAudiences extends PersonalizationAdapter { if (!this.events?.length) { log.debug('No events found, completing export', this.exportConfig.context); - log.info('No Events found with the given project!', this.exportConfig.context); + log.info('No events found for the given project.', this.exportConfig.context); return; } diff --git a/packages/contentstack-variants/src/export/experiences.ts b/packages/contentstack-variants/src/export/experiences.ts index b39d2e1aeb..312439efb3 100644 --- a/packages/contentstack-variants/src/export/experiences.ts +++ b/packages/contentstack-variants/src/export/experiences.ts @@ -61,7 +61,7 @@ export default class ExportExperiences extends PersonalizationAdapter { if (PAUSE) { if (latestVersionUsed) { - log.debug(`Creating new PAUSE version for: ${experience.uid}`, this.config.context); + log.debug(`Creating new PAUSED version for: ${experience.uid}`, this.config.context); await this.createExperienceVersion(experience.uid, PAUSE); } else { - log.debug(`Updating experience version to PAUSE for: ${experience.uid}`, this.config.context); + log.debug(`Updating experience version to PAUSED for: ${experience.uid}`, this.config.context); await this.updateExperienceVersion(experience.uid, experience.latestVersion, PAUSE); } } @@ -343,7 +343,7 @@ export default class Experiences extends PersonalizationAdapter { this.cmsVariantGroups[expUid] = expRes._cms?.variantGroup ?? {}; return expUid; // Return the expUid for filtering later } else { - log.debug(`Variants/variant group not ready for experience: ${expUid}`, this.config.context); + log.debug(`Variants or variant group not ready for experience: ${expUid}`, this.config.context); } }); @@ -385,7 +385,7 @@ export default class Experiences extends PersonalizationAdapter { // Read the created content types from the file this.createdCTs = fsUtil.readFile(this.cTsSuccessPath, true) as any; if (!this.createdCTs) { - log.debug('No Content types created, skipping following process', this.config.context); + log.warn('No content types created.', this.config.context); return; } diff --git a/packages/contentstack-variants/src/import/variant-entries.ts b/packages/contentstack-variants/src/import/variant-entries.ts index bda2cf61e6..2c4ca54d8f 100644 --- a/packages/contentstack-variants/src/import/variant-entries.ts +++ b/packages/contentstack-variants/src/import/variant-entries.ts @@ -603,7 +603,7 @@ export default class VariantEntries extends VariantAdapter 0) { log.debug(`Processing ${variantEntry.publish_details.length} publish details`, this.config.context); } else { - log.debug('No publish details found for variant entry', this.config.context); + log.debug('No publish details found for variant entry.', this.config.context); } if (variantEntry.publish_details && variantEntry.publish_details?.length > 0) { diff --git a/packages/contentstack-variants/src/types/export-config.ts b/packages/contentstack-variants/src/types/export-config.ts index 61d3e512e7..8ddc75173e 100644 --- a/packages/contentstack-variants/src/types/export-config.ts +++ b/packages/contentstack-variants/src/types/export-config.ts @@ -20,7 +20,8 @@ export type Modules = | 'labels' | 'marketplace-apps' | 'taxonomies' - | 'personalize'; + | 'personalize' + | 'composable-studio'; export type branch = { uid: string; @@ -182,6 +183,11 @@ export interface DefaultConfig { fileName: string; dependencies?: Modules[]; }; + 'composable-studio': { + dirName: string; + fileName: string; + apiBaseUrl: string; + }; masterLocale: { dirName: string; fileName: string; diff --git a/packages/contentstack-variants/src/utils/personalization-api-adapter.ts b/packages/contentstack-variants/src/utils/personalization-api-adapter.ts index 39e5e2f454..24779f80d1 100644 --- a/packages/contentstack-variants/src/utils/personalization-api-adapter.ts +++ b/packages/contentstack-variants/src/utils/personalization-api-adapter.ts @@ -357,7 +357,7 @@ export class PersonalizationAdapter extends AdapterHelper impl } async getAttributes(): Promise { - log.debug('Fetching attributes from personalization API', this.exportConfig?.context ); + log.debug('Fetching attributes from Personalize API...', this.exportConfig?.context ); const data = await this.apiClient.get('/attributes'); const result = (await this.handleVariantAPIRes(data)) as AttributeStruct[]; log.info(`Fetched ${result?.length || 0} attributes`, this.exportConfig?.context ); diff --git a/packages/contentstack-variants/src/utils/variant-api-adapter.ts b/packages/contentstack-variants/src/utils/variant-api-adapter.ts index 5dfcb74037..1cfc271b93 100644 --- a/packages/contentstack-variants/src/utils/variant-api-adapter.ts +++ b/packages/contentstack-variants/src/utils/variant-api-adapter.ts @@ -53,10 +53,10 @@ export class VariantHttpClient extends AdapterHelper implement this.exportConfig?.context, ); if (authenticationHandler.isOauthEnabled) { - log.debug('Setting OAuth authorization header', this.exportConfig?.context); + log.debug('Setting OAuth authorization header...', this.exportConfig?.context); this.apiClient.headers({ authorization: token }); } else { - log.debug('Setting authtoken header', this.exportConfig?.context); + log.debug('Setting authtoken header...', this.exportConfig?.context); this.apiClient.headers({ authtoken: token }); } } @@ -109,7 +109,7 @@ export class VariantHttpClient extends AdapterHelper implement ); if (variantConfig.serveMockData && callback) { - log.debug('Using mock data for variant entries', this.exportConfig?.context); + log.debug('Using mock data for variant entries...', this.exportConfig?.context); let data = [] as Record[]; if (existsSync(variantConfig.mockDataPath)) { @@ -174,10 +174,10 @@ export class VariantHttpClient extends AdapterHelper implement } if (callback) { - log.debug('Executing callback with variant entries', this.exportConfig?.context); + log.debug('Executing callback with variant entries...', this.exportConfig?.context); callback(response.entries); } else { - log.debug('Adding variant entries to collection', this.exportConfig?.context); + log.debug('Adding variant entries to collection...', this.exportConfig?.context); entries = entries.concat(response.entries); } @@ -200,7 +200,7 @@ export class VariantHttpClient extends AdapterHelper implement } if (returnResult) { - log.debug('Returning variant entries result', this.exportConfig?.context ); + log.debug('Returning variant entries result...', this.exportConfig?.context ); return { entries }; } } @@ -329,7 +329,7 @@ export class VariantHttpClient extends AdapterHelper implement log.debug(`API response status: ${status}`, this.exportConfig?.context); if (status >= 200 && status < 300) { - log.debug('API request successful', this.exportConfig?.context); + log.debug('API request successful.', this.exportConfig?.context); return data; } @@ -406,17 +406,17 @@ export class VariantAdapter { log.debug('Initializing VariantAdapter...', this.exportConfig?.context); if (config.httpClient) { - log.debug('Using HTTP client variant instance', this.exportConfig?.context); + log.debug('Using HTTP client variant instance.', this.exportConfig?.context); const { httpClient, Adapter, ...restConfig } = config; this.variantInstance = new Adapter(restConfig, options); } else { - log.debug('Using SDK variant instance', this.exportConfig?.context); + log.debug('Using SDK variant instance.', this.exportConfig?.context); const { Adapter, ...restConfig } = config; this.variantInstance = new Adapter(restConfig); } this.messages = messages; - log.debug('VariantAdapter initialized successfully', this.exportConfig?.context); + log.debug('VariantAdapter initialized successfully.', this.exportConfig?.context); } /** diff --git a/packages/contentstack/src/hooks/init/context-init.ts b/packages/contentstack/src/hooks/init/context-init.ts index 28b43008ae..4d87969130 100644 --- a/packages/contentstack/src/hooks/init/context-init.ts +++ b/packages/contentstack/src/hooks/init/context-init.ts @@ -1,8 +1,13 @@ import { CsdxContext } from '../../utils'; +import { configHandler } from '@contentstack/cli-utilities'; /** * Set the cli context */ export default function (opts): void { + // Store command ID for session-based log organization + if (opts.id) { + configHandler.set('currentCommandId', opts.id); + } this.config.context = new CsdxContext(opts, this.config); } diff --git a/packages/contentstack/src/hooks/prerun/auth-guard.ts b/packages/contentstack/src/hooks/prerun/auth-guard.ts index 6eef92a0b6..94898da40f 100644 --- a/packages/contentstack/src/hooks/prerun/auth-guard.ts +++ b/packages/contentstack/src/hooks/prerun/auth-guard.ts @@ -15,27 +15,27 @@ export default async function (opts): Promise { this.exit(); return; } - cliux.print(`\n Currently using ${region.name} region \n`, { color: 'grey' }); + cliux.print(`Currently using region: ${region.name}`, { color: 'grey' }); } // Auth guard if (protectedCommands[opts.Command.id]) { if (!isAuthenticated()) { - newLogger.error('No auth token found for command', opts.Command.id); - cliux.error('Please login to execute the command'); + newLogger.error('No auth token found for command.', opts.Command.id); + cliux.error('Please log in to execute the command'); this.exit(); } const client = await managementSDKClient({host: region.cma}) try { const result = await client.getUser(); if (!result) { - newLogger.error('error in auth validation'); - cliux.error('Please login to execute the command'); + newLogger.error('Error in auth validation'); + cliux.error('Please log in to execute the command'); this.exit(); } - newLogger.debug('logged in user', result.data); + newLogger.debug('Logged-in user', result.data); } catch (error) { - newLogger.error('error in auth validation', error); - cliux.error('Please login to execute the command'); + newLogger.error('Error in auth validation', error); + cliux.error('Please log in to execute the command'); process.exit(); } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9f99a14628..66fd5fcfb8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -93,6 +93,9 @@ importers: '@oclif/plugin-help': 6.2.36 '@oclif/plugin-not-found': 3.2.73_@types+node@14.18.63 '@oclif/plugin-plugins': 5.4.54 + '@oclif/plugin-help': 6.2.36 + '@oclif/plugin-not-found': 3.2.73_@types+node@14.18.63 + '@oclif/plugin-plugins': 5.4.54 chalk: 4.1.2 cli-progress: 3.12.0 debug: 4.4.3 @@ -104,8 +107,9 @@ importers: semver: 7.7.3 short-uuid: 4.2.2 uuid: 9.0.1 - winston: 3.18.3 + winston: 3.19.0 devDependencies: + '@oclif/test': 4.1.15_@oclif+core@4.8.0 '@oclif/test': 4.1.15_@oclif+core@4.8.0 '@types/chai': 4.3.20 '@types/inquirer': 9.0.9 @@ -137,7 +141,7 @@ importers: '@contentstack/cli-utilities': ~1.15.0 '@oclif/core': ^4.3.0 '@oclif/plugin-help': ^6.2.28 - '@oclif/plugin-plugins': ^5.4.38 + '@oclif/plugin-plugins': ^5.4.54 '@oclif/test': ^4.1.13 '@types/chai': ^4.3.20 '@types/fs-extra': ^11.0.4 @@ -167,13 +171,16 @@ importers: '@oclif/core': 4.8.0 '@oclif/plugin-help': 6.2.36 '@oclif/plugin-plugins': 5.4.54 + '@oclif/plugin-help': 6.2.36 + '@oclif/plugin-plugins': 5.4.54 chalk: 4.1.2 fast-csv: 4.3.6 fs-extra: 11.3.2 lodash: 4.17.21 uuid: 9.0.1 - winston: 3.18.3 + winston: 3.19.0 devDependencies: + '@oclif/test': 4.1.15_@oclif+core@4.8.0 '@oclif/test': 4.1.15_@oclif+core@4.8.0 '@types/chai': 4.3.20 '@types/fs-extra': 11.0.4 @@ -222,10 +229,12 @@ importers: '@contentstack/cli-utilities': link:../contentstack-utilities '@oclif/core': 4.8.0 '@oclif/plugin-help': 6.2.36 + '@oclif/plugin-help': 6.2.36 otplib: 12.0.1 devDependencies: '@fancy-test/nock': 0.1.1 '@oclif/test': 4.1.15_@oclif+core@4.8.0 + '@oclif/test': 4.1.15_@oclif+core@4.8.0 '@types/chai': 4.3.20 '@types/mkdirp': 1.0.2 '@types/mocha': 8.2.3 @@ -274,10 +283,12 @@ importers: '@contentstack/cli-utilities': link:../contentstack-utilities '@oclif/core': 4.8.0 '@oclif/plugin-help': 6.2.36 + '@oclif/plugin-help': 6.2.36 inquirer: 8.2.7_@types+node@14.18.63 mkdirp: 1.0.4 tar: 6.2.1 devDependencies: + '@oclif/test': 4.1.15_@oclif+core@4.8.0 '@oclif/test': 4.1.15_@oclif+core@4.8.0 '@types/inquirer': 9.0.9 '@types/mkdirp': 1.0.2 @@ -296,9 +307,10 @@ importers: packages/contentstack-branches: specifiers: - '@contentstack/cli-command': ~1.6.1 + '@contentstack/cli-command': ~1.7.0 '@contentstack/cli-dev-dependencies': ~1.3.0 '@contentstack/cli-utilities': ~1.15.0 + '@contentstack/cli-utilities': ~1.15.0 '@oclif/core': ^4.3.0 '@oclif/plugin-help': ^6.2.28 '@types/flat': ^5.0.5 @@ -321,6 +333,7 @@ importers: '@contentstack/cli-utilities': link:../contentstack-utilities '@oclif/core': 4.8.0 '@oclif/plugin-help': 6.2.36 + '@oclif/plugin-help': 6.2.36 chalk: 4.1.2 just-diff: 6.0.2 lodash: 4.17.21 @@ -360,16 +373,18 @@ importers: winston: ^3.17.0 dependencies: '@contentstack/cli-command': link:../contentstack-command - '@contentstack/cli-config': link:../contentstack-config + '@contentstack/cli-config': 1.15.3 '@contentstack/cli-utilities': link:../contentstack-utilities '@oclif/core': 4.8.0 '@oclif/plugin-help': 6.2.36 + '@oclif/plugin-help': 6.2.36 chalk: 4.1.2 dotenv: 16.6.1 inquirer: 8.2.7 lodash: 4.17.21 - winston: 3.18.3 + winston: 3.19.0 devDependencies: + '@oclif/test': 4.1.15_@oclif+core@4.8.0 '@oclif/test': 4.1.15_@oclif+core@4.8.0 chai: 4.5.0 eslint: 8.57.1 @@ -402,9 +417,8 @@ importers: oclif: ^4.17.46 ora: ^5.4.1 prompt: ^1.3.0 - rimraf: ^5.0.10 + rimraf: ^6.1.0 sinon: ^19.0.5 - winston: ^3.17.0 dependencies: '@colors/colors': 1.6.0 '@contentstack/cli-cm-export': link:../contentstack-export @@ -413,6 +427,7 @@ importers: '@contentstack/cli-utilities': link:../contentstack-utilities '@oclif/core': 4.8.0 '@oclif/plugin-help': 6.2.36 + '@oclif/plugin-help': 6.2.36 chalk: 4.1.2 inquirer: 8.2.6 inquirer-search-checkbox: 1.0.0 @@ -421,9 +436,9 @@ importers: merge: 2.1.1 ora: 5.4.1 prompt: 1.3.0 - rimraf: 5.0.10 - winston: 3.18.3 + rimraf: 6.1.2 devDependencies: + '@oclif/test': 4.1.15_@oclif+core@4.8.0 '@oclif/test': 4.1.15_@oclif+core@4.8.0 chai: 4.5.0 eslint: 8.57.1 @@ -435,6 +450,7 @@ importers: packages/contentstack-command: specifiers: + '@contentstack/cli-utilities': ~1.15.0 '@contentstack/cli-utilities': ~1.15.0 '@oclif/core': ^4.3.0 '@oclif/plugin-help': ^6.2.28 @@ -456,6 +472,7 @@ importers: '@oclif/plugin-help': 6.2.36 contentstack: 3.26.2 devDependencies: + '@oclif/test': 4.1.15_@oclif+core@4.8.0 '@oclif/test': 4.1.15_@oclif+core@4.8.0 '@types/mkdirp': 1.0.2 '@types/mocha': 8.2.3 @@ -495,8 +512,10 @@ importers: '@contentstack/cli-utilities': link:../contentstack-utilities '@oclif/core': 4.8.0 '@oclif/plugin-help': 6.2.36 + '@oclif/plugin-help': 6.2.36 lodash: 4.17.21 devDependencies: + '@oclif/test': 4.1.15_@oclif+core@4.8.0 '@oclif/test': 4.1.15_@oclif+core@4.8.0 '@types/chai': 4.3.20 '@types/mocha': 8.2.3 @@ -528,6 +547,7 @@ importers: dependencies: '@oclif/core': 4.8.0 '@oclif/test': 4.1.15_@oclif+core@4.8.0 + '@oclif/test': 4.1.15_@oclif+core@4.8.0 fancy-test: 2.0.42 lodash: 4.17.21 devDependencies: @@ -540,9 +560,9 @@ importers: packages/contentstack-export: specifiers: - '@contentstack/cli-auth': ~1.6.1 - '@contentstack/cli-command': ~1.6.1 - '@contentstack/cli-config': ~1.15.1 + '@contentstack/cli-auth': ~1.6.2 + '@contentstack/cli-command': ~1.7.0 + '@contentstack/cli-config': ~1.15.3 '@contentstack/cli-dev-dependencies': ~1.3.1 '@contentstack/cli-utilities': ~1.15.0 '@contentstack/cli-variants': ~2.0.0-beta @@ -591,13 +611,15 @@ importers: mkdirp: 1.0.4 progress-stream: 2.0.0 promise-limit: 2.7.0 - winston: 3.18.3 + winston: 3.19.0 devDependencies: '@contentstack/cli-auth': link:../contentstack-auth - '@contentstack/cli-config': link:../contentstack-config + '@contentstack/cli-config': 1.15.3 '@contentstack/cli-dev-dependencies': link:../contentstack-dev-dependencies '@oclif/plugin-help': 6.2.36 '@oclif/test': 4.1.15_@oclif+core@4.8.0 + '@oclif/plugin-help': 6.2.36 + '@oclif/test': 4.1.15_@oclif+core@4.8.0 '@types/big-json': 3.2.5 '@types/chai': 4.3.20 '@types/mkdirp': 1.0.2 @@ -642,11 +664,13 @@ importers: '@contentstack/cli-utilities': link:../contentstack-utilities '@oclif/core': 4.8.0 '@oclif/plugin-help': 6.2.36 + '@oclif/plugin-help': 6.2.36 fast-csv: 4.3.6 inquirer: 8.2.7 inquirer-checkbox-plus-prompt: 1.4.2_inquirer@8.2.7 mkdirp: 3.0.1 devDependencies: + '@oclif/test': 4.1.15_@oclif+core@4.8.0 '@oclif/test': 4.1.15_@oclif+core@4.8.0 '@types/chai': 4.3.20 '@types/mocha': 10.0.10 @@ -715,8 +739,9 @@ importers: mkdirp: 1.0.4 promise-limit: 2.7.0 uuid: 9.0.1 - winston: 3.18.3 + winston: 3.19.0 devDependencies: + '@oclif/test': 4.1.15_@oclif+core@4.8.0 '@oclif/test': 4.1.15_@oclif+core@4.8.0 '@types/big-json': 3.2.5 '@types/bluebird': 3.5.42 @@ -780,7 +805,7 @@ importers: lodash: 4.17.21 merge: 2.1.1 mkdirp: 1.0.4 - winston: 3.18.3 + winston: 3.19.0 devDependencies: '@types/big-json': 3.2.5 '@types/bluebird': 3.5.42 @@ -801,7 +826,7 @@ importers: oclif: 4.22.50_@types+node@14.18.63 rewire: 9.0.1 ts-node: 10.9.2_ogreqof3k35xezedraj6pnd45y - tsx: 4.20.6 + tsx: 4.21.0 typescript: 4.9.5 packages/contentstack-migration: @@ -830,14 +855,16 @@ importers: '@contentstack/cli-utilities': link:../contentstack-utilities '@oclif/core': 4.8.0 '@oclif/plugin-help': 6.2.36 + '@oclif/plugin-help': 6.2.36 async: 3.2.6 callsites: 3.1.0 cardinal: 2.1.1 chalk: 4.1.2 concat-stream: 2.0.0 listr: 0.14.3 - winston: 3.18.3 + winston: 3.19.0 devDependencies: + '@oclif/test': 4.1.15_@oclif+core@4.8.0 '@oclif/test': 4.1.15_@oclif+core@4.8.0 chai: 4.5.0 eslint: 8.57.1 @@ -873,7 +900,7 @@ importers: ts-node: ^8.10.2 typescript: ^4.9.5 dependencies: - '@contentstack/cli-cm-import': link:../contentstack-import + '@contentstack/cli-cm-import': 1.30.0 '@contentstack/cli-command': link:../contentstack-command '@contentstack/cli-utilities': link:../contentstack-utilities '@contentstack/management': 1.22.0 @@ -889,6 +916,7 @@ importers: '@types/tar': 6.1.13 '@types/tmp': 0.2.6 axios: 1.13.2 + axios: 1.13.2 eslint: 8.57.1 eslint-config-oclif: 6.0.119_avq3eyf5kaj6ssrwo7fvkrwnji eslint-config-oclif-typescript: 3.1.14_avq3eyf5kaj6ssrwo7fvkrwnji @@ -926,7 +954,7 @@ importers: inquirer: 8.2.7 inquirer-search-checkbox: ^1.0.0 inquirer-search-list: ^1.2.6 - js-yaml: ^4.1.0 + js-yaml: ^4.1.1 klona: ^2.0.6 lodash: ^4.17.21 mkdirp: ^1.0.4 @@ -951,6 +979,7 @@ importers: '@contentstack/marketplace-sdk': 1.4.0 '@oclif/core': 4.8.0 axios: 1.13.2 + axios: 1.13.2 chalk: 4.1.2 cli-cursor: 3.1.0 cli-progress: 3.12.0 @@ -962,6 +991,7 @@ importers: inquirer-search-checkbox: 1.0.0 inquirer-search-list: 1.2.6 js-yaml: 4.1.1 + js-yaml: 4.1.1 klona: 2.0.6 lodash: 4.17.21 mkdirp: 1.0.4 @@ -974,7 +1004,7 @@ importers: tty-table: 4.2.3 unique-string: 2.0.0 uuid: 9.0.1 - winston: 3.18.3 + winston: 3.19.0 xdg-basedir: 4.0.0 devDependencies: '@types/chai': 4.3.20 @@ -999,6 +1029,7 @@ importers: specifiers: '@contentstack/cli-dev-dependencies': ^1.3.0 '@contentstack/cli-utilities': ~1.15.0 + '@contentstack/cli-utilities': ~1.15.0 '@oclif/core': ^4.3.0 '@oclif/plugin-help': ^6.2.28 '@oclif/test': ^4.1.13 @@ -1014,9 +1045,10 @@ importers: '@contentstack/cli-utilities': link:../contentstack-utilities '@oclif/core': 4.8.0 '@oclif/plugin-help': 6.2.36 + '@oclif/plugin-help': 6.2.36 lodash: 4.17.21 mkdirp: 1.0.4 - winston: 3.18.3 + winston: 3.19.0 devDependencies: '@contentstack/cli-dev-dependencies': link:../contentstack-dev-dependencies '@oclif/test': 4.1.15_@oclif+core@4.8.0 @@ -1028,6 +1060,7 @@ importers: packages: + /@apollo/client/3.14.0_graphql@16.12.0: /@apollo/client/3.14.0_graphql@16.12.0: resolution: {integrity: sha512-0YQKKRIxiMlIou+SekQqdCo0ZTHxOcES+K8vKB53cIDpwABNR0P0yRzPgsbgcj3zRJniD93S/ontsnZsCLZrxQ==} peerDependencies: @@ -1046,12 +1079,15 @@ packages: subscriptions-transport-ws: optional: true dependencies: + '@graphql-typed-document-node/core': 3.2.0_graphql@16.12.0 '@graphql-typed-document-node/core': 3.2.0_graphql@16.12.0 '@wry/caches': 1.0.1 '@wry/equality': 0.5.7 '@wry/trie': 0.5.0 graphql: 16.12.0 graphql-tag: 2.12.6_graphql@16.12.0 + graphql: 16.12.0 + graphql-tag: 2.12.6_graphql@16.12.0 hoist-non-react-statics: 3.3.2 optimism: 0.18.1 prop-types: 15.8.1 @@ -1070,6 +1106,7 @@ packages: dependencies: '@aws-crypto/util': 5.2.0 '@aws-sdk/types': 3.936.0 + '@aws-sdk/types': 3.936.0 tslib: 2.8.1 dev: true @@ -1078,6 +1115,7 @@ packages: dependencies: '@aws-crypto/util': 5.2.0 '@aws-sdk/types': 3.936.0 + '@aws-sdk/types': 3.936.0 tslib: 2.8.1 dev: true @@ -1087,6 +1125,7 @@ packages: '@aws-crypto/supports-web-crypto': 5.2.0 '@aws-crypto/util': 5.2.0 '@aws-sdk/types': 3.936.0 + '@aws-sdk/types': 3.936.0 '@aws-sdk/util-locate-window': 3.893.0 '@smithy/util-utf8': 2.3.0 tslib: 2.8.1 @@ -1099,6 +1138,7 @@ packages: '@aws-crypto/supports-web-crypto': 5.2.0 '@aws-crypto/util': 5.2.0 '@aws-sdk/types': 3.936.0 + '@aws-sdk/types': 3.936.0 '@aws-sdk/util-locate-window': 3.893.0 '@smithy/util-utf8': 2.3.0 tslib: 2.8.1 @@ -1110,6 +1150,7 @@ packages: dependencies: '@aws-crypto/util': 5.2.0 '@aws-sdk/types': 3.936.0 + '@aws-sdk/types': 3.936.0 tslib: 2.8.1 dev: true @@ -1122,6 +1163,7 @@ packages: /@aws-crypto/util/5.2.0: resolution: {integrity: sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==} dependencies: + '@aws-sdk/types': 3.936.0 '@aws-sdk/types': 3.936.0 '@smithy/util-utf8': 2.3.0 tslib: 2.8.1 @@ -1171,6 +1213,7 @@ packages: '@smithy/util-stream': 4.5.6 '@smithy/util-utf8': 4.2.0 '@smithy/util-waiter': 4.2.5 + '@smithy/util-waiter': 4.2.5 tslib: 2.8.1 transitivePeerDependencies: - aws-crt @@ -1234,6 +1277,7 @@ packages: '@smithy/util-stream': 4.5.6 '@smithy/util-utf8': 4.2.0 '@smithy/util-waiter': 4.2.5 + '@smithy/util-waiter': 4.2.5 tslib: 2.8.1 transitivePeerDependencies: - aws-crt @@ -1300,6 +1344,7 @@ packages: '@smithy/types': 4.9.0 '@smithy/util-base64': 4.3.0 '@smithy/util-middleware': 4.2.5 + '@smithy/util-middleware': 4.2.5 '@smithy/util-utf8': 4.2.0 tslib: 2.8.1 dev: true @@ -1387,6 +1432,8 @@ packages: tslib: 2.8.1 transitivePeerDependencies: - aws-crt + transitivePeerDependencies: + - aws-crt dev: true /@aws-sdk/credential-provider-process/3.936.0: @@ -1432,23 +1479,34 @@ packages: - aws-crt dev: true + /@aws-sdk/middleware-bucket-endpoint/3.936.0: + resolution: {integrity: sha512-XLSVVfAorUxZh6dzF+HTOp4R1B5EQcdpGcPliWr0KUj2jukgjZEcqbBmjyMF/p9bmyQsONX80iURF1HLAlW0qg==} /@aws-sdk/middleware-bucket-endpoint/3.936.0: resolution: {integrity: sha512-XLSVVfAorUxZh6dzF+HTOp4R1B5EQcdpGcPliWr0KUj2jukgjZEcqbBmjyMF/p9bmyQsONX80iURF1HLAlW0qg==} engines: {node: '>=18.0.0'} dependencies: + '@aws-sdk/types': 3.936.0 '@aws-sdk/types': 3.936.0 '@aws-sdk/util-arn-parser': 3.893.0 '@smithy/node-config-provider': 4.3.5 '@smithy/protocol-http': 5.3.5 '@smithy/types': 4.9.0 + '@smithy/node-config-provider': 4.3.5 + '@smithy/protocol-http': 5.3.5 + '@smithy/types': 4.9.0 '@smithy/util-config-provider': 4.2.0 tslib: 2.8.1 dev: true + /@aws-sdk/middleware-expect-continue/3.936.0: + resolution: {integrity: sha512-Eb4ELAC23bEQLJmUMYnPWcjD3FZIsmz2svDiXEcxRkQU9r7NRID7pM7C5NPH94wOfiCk0b2Y8rVyFXW0lGQwbA==} /@aws-sdk/middleware-expect-continue/3.936.0: resolution: {integrity: sha512-Eb4ELAC23bEQLJmUMYnPWcjD3FZIsmz2svDiXEcxRkQU9r7NRID7pM7C5NPH94wOfiCk0b2Y8rVyFXW0lGQwbA==} engines: {node: '>=18.0.0'} dependencies: + '@aws-sdk/types': 3.936.0 + '@smithy/protocol-http': 5.3.5 + '@smithy/types': 4.9.0 '@aws-sdk/types': 3.936.0 '@smithy/protocol-http': 5.3.5 '@smithy/types': 4.9.0 @@ -1470,38 +1528,58 @@ packages: '@smithy/types': 4.9.0 '@smithy/util-middleware': 4.2.5 '@smithy/util-stream': 4.5.6 + '@smithy/node-config-provider': 4.3.5 + '@smithy/protocol-http': 5.3.5 + '@smithy/types': 4.9.0 + '@smithy/util-middleware': 4.2.5 + '@smithy/util-stream': 4.5.6 '@smithy/util-utf8': 4.2.0 tslib: 2.8.1 dev: true + /@aws-sdk/middleware-host-header/3.936.0: + resolution: {integrity: sha512-tAaObaAnsP1XnLGndfkGWFuzrJYuk9W0b/nLvol66t8FZExIAf/WdkT2NNAWOYxljVs++oHnyHBCxIlaHrzSiw==} /@aws-sdk/middleware-host-header/3.936.0: resolution: {integrity: sha512-tAaObaAnsP1XnLGndfkGWFuzrJYuk9W0b/nLvol66t8FZExIAf/WdkT2NNAWOYxljVs++oHnyHBCxIlaHrzSiw==} engines: {node: '>=18.0.0'} dependencies: + '@aws-sdk/types': 3.936.0 + '@smithy/protocol-http': 5.3.5 + '@smithy/types': 4.9.0 '@aws-sdk/types': 3.936.0 '@smithy/protocol-http': 5.3.5 '@smithy/types': 4.9.0 tslib: 2.8.1 dev: true + /@aws-sdk/middleware-location-constraint/3.936.0: + resolution: {integrity: sha512-SCMPenDtQMd9o5da9JzkHz838w3327iqXk3cbNnXWqnNRx6unyW8FL0DZ84gIY12kAyVHz5WEqlWuekc15ehfw==} /@aws-sdk/middleware-location-constraint/3.936.0: resolution: {integrity: sha512-SCMPenDtQMd9o5da9JzkHz838w3327iqXk3cbNnXWqnNRx6unyW8FL0DZ84gIY12kAyVHz5WEqlWuekc15ehfw==} engines: {node: '>=18.0.0'} dependencies: + '@aws-sdk/types': 3.936.0 + '@smithy/types': 4.9.0 '@aws-sdk/types': 3.936.0 '@smithy/types': 4.9.0 tslib: 2.8.1 dev: true + /@aws-sdk/middleware-logger/3.936.0: + resolution: {integrity: sha512-aPSJ12d3a3Ea5nyEnLbijCaaYJT2QjQ9iW+zGh5QcZYXmOGWbKVyPSxmVOboZQG+c1M8t6d2O7tqrwzIq8L8qw==} /@aws-sdk/middleware-logger/3.936.0: resolution: {integrity: sha512-aPSJ12d3a3Ea5nyEnLbijCaaYJT2QjQ9iW+zGh5QcZYXmOGWbKVyPSxmVOboZQG+c1M8t6d2O7tqrwzIq8L8qw==} engines: {node: '>=18.0.0'} dependencies: + '@aws-sdk/types': 3.936.0 + '@smithy/types': 4.9.0 '@aws-sdk/types': 3.936.0 '@smithy/types': 4.9.0 tslib: 2.8.1 dev: true + /@aws-sdk/middleware-recursion-detection/3.936.0: + resolution: {integrity: sha512-l4aGbHpXM45YNgXggIux1HgsCVAvvBoqHPkqLnqMl9QVapfuSTjJHfDYDsx1Xxct6/m7qSMUzanBALhiaGO2fA==} /@aws-sdk/middleware-recursion-detection/3.936.0: resolution: {integrity: sha512-l4aGbHpXM45YNgXggIux1HgsCVAvvBoqHPkqLnqMl9QVapfuSTjJHfDYDsx1Xxct6/m7qSMUzanBALhiaGO2fA==} engines: {node: '>=18.0.0'} @@ -1529,14 +1607,20 @@ packages: '@smithy/util-config-provider': 4.2.0 '@smithy/util-middleware': 4.2.5 '@smithy/util-stream': 4.5.6 + '@smithy/util-middleware': 4.2.5 + '@smithy/util-stream': 4.5.6 '@smithy/util-utf8': 4.2.0 tslib: 2.8.1 dev: true + /@aws-sdk/middleware-ssec/3.936.0: + resolution: {integrity: sha512-/GLC9lZdVp05ozRik5KsuODR/N7j+W+2TbfdFL3iS+7un+gnP6hC8RDOZd6WhpZp7drXQ9guKiTAxkZQwzS8DA==} /@aws-sdk/middleware-ssec/3.936.0: resolution: {integrity: sha512-/GLC9lZdVp05ozRik5KsuODR/N7j+W+2TbfdFL3iS+7un+gnP6hC8RDOZd6WhpZp7drXQ9guKiTAxkZQwzS8DA==} engines: {node: '>=18.0.0'} dependencies: + '@aws-sdk/types': 3.936.0 + '@smithy/types': 4.9.0 '@aws-sdk/types': 3.936.0 '@smithy/types': 4.9.0 tslib: 2.8.1 @@ -1601,10 +1685,16 @@ packages: - aws-crt dev: true + /@aws-sdk/region-config-resolver/3.936.0: + resolution: {integrity: sha512-wOKhzzWsshXGduxO4pqSiNyL9oUtk4BEvjWm9aaq6Hmfdoydq6v6t0rAGHWPjFwy9z2haovGRi3C8IxdMB4muw==} /@aws-sdk/region-config-resolver/3.936.0: resolution: {integrity: sha512-wOKhzzWsshXGduxO4pqSiNyL9oUtk4BEvjWm9aaq6Hmfdoydq6v6t0rAGHWPjFwy9z2haovGRi3C8IxdMB4muw==} engines: {node: '>=18.0.0'} dependencies: + '@aws-sdk/types': 3.936.0 + '@smithy/config-resolver': 4.4.3 + '@smithy/node-config-provider': 4.3.5 + '@smithy/types': 4.9.0 '@aws-sdk/types': 3.936.0 '@smithy/config-resolver': 4.4.3 '@smithy/node-config-provider': 4.3.5 @@ -1639,10 +1729,13 @@ packages: - aws-crt dev: true + /@aws-sdk/types/3.936.0: + resolution: {integrity: sha512-uz0/VlMd2pP5MepdrHizd+T+OKfyK4r3OA9JI+L/lPKg0YFQosdJNCKisr6o70E3dh8iMpFYxF1UN/4uZsyARg==} /@aws-sdk/types/3.936.0: resolution: {integrity: sha512-uz0/VlMd2pP5MepdrHizd+T+OKfyK4r3OA9JI+L/lPKg0YFQosdJNCKisr6o70E3dh8iMpFYxF1UN/4uZsyARg==} engines: {node: '>=18.0.0'} dependencies: + '@smithy/types': 4.9.0 '@smithy/types': 4.9.0 tslib: 2.8.1 dev: true @@ -1654,10 +1747,16 @@ packages: tslib: 2.8.1 dev: true + /@aws-sdk/util-endpoints/3.936.0: + resolution: {integrity: sha512-0Zx3Ntdpu+z9Wlm7JKUBOzS9EunwKAb4KdGUQQxDqh5Lc3ta5uBoub+FgmVuzwnmBu9U1Os8UuwVTH0Lgu+P5w==} /@aws-sdk/util-endpoints/3.936.0: resolution: {integrity: sha512-0Zx3Ntdpu+z9Wlm7JKUBOzS9EunwKAb4KdGUQQxDqh5Lc3ta5uBoub+FgmVuzwnmBu9U1Os8UuwVTH0Lgu+P5w==} engines: {node: '>=18.0.0'} dependencies: + '@aws-sdk/types': 3.936.0 + '@smithy/types': 4.9.0 + '@smithy/url-parser': 4.2.5 + '@smithy/util-endpoints': 3.2.5 '@aws-sdk/types': 3.936.0 '@smithy/types': 4.9.0 '@smithy/url-parser': 4.2.5 @@ -1672,6 +1771,8 @@ packages: tslib: 2.8.1 dev: true + /@aws-sdk/util-user-agent-browser/3.936.0: + resolution: {integrity: sha512-eZ/XF6NxMtu+iCma58GRNRxSq4lHo6zHQLOZRIeL/ghqYJirqHdenMOwrzPettj60KWlv827RVebP9oNVrwZbw==} /@aws-sdk/util-user-agent-browser/3.936.0: resolution: {integrity: sha512-eZ/XF6NxMtu+iCma58GRNRxSq4lHo6zHQLOZRIeL/ghqYJirqHdenMOwrzPettj60KWlv827RVebP9oNVrwZbw==} dependencies: @@ -1697,10 +1798,13 @@ packages: tslib: 2.8.1 dev: true + /@aws-sdk/xml-builder/3.930.0: + resolution: {integrity: sha512-YIfkD17GocxdmlUVc3ia52QhcWuRIUJonbF8A2CYfcWNV3HzvAqpcPeC0bYUhkK+8e8YO1ARnLKZQE0TlwzorA==} /@aws-sdk/xml-builder/3.930.0: resolution: {integrity: sha512-YIfkD17GocxdmlUVc3ia52QhcWuRIUJonbF8A2CYfcWNV3HzvAqpcPeC0bYUhkK+8e8YO1ARnLKZQE0TlwzorA==} engines: {node: '>=18.0.0'} dependencies: + '@smithy/types': 4.9.0 '@smithy/types': 4.9.0 fast-xml-parser: 5.2.5 tslib: 2.8.1 @@ -2054,6 +2158,26 @@ packages: /@colors/colors/1.6.0: resolution: {integrity: sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==} engines: {node: '>=0.1.90'} + + /@contentstack/cli-audit/1.16.1_debug@4.4.3: + resolution: {integrity: sha512-CRe92i7op3RlD5JQu+PY+KelITaTAb3lX22M//Cz7GzW356HyDTNtWydO5MOkPCTt6OkLNz0I9zYY2SPNCRAsw==} + engines: {node: '>=16'} + hasBin: true + dependencies: + '@contentstack/cli-command': 1.7.0_debug@4.4.3 + '@contentstack/cli-utilities': 1.15.0_debug@4.4.3 + '@oclif/core': 4.8.0 + '@oclif/plugin-help': 6.2.36 + '@oclif/plugin-plugins': 5.4.54 + chalk: 4.1.2 + fast-csv: 4.3.6 + fs-extra: 11.3.2 + lodash: 4.17.21 + uuid: 9.0.1 + winston: 3.19.0 + transitivePeerDependencies: + - debug + - supports-color dev: false /@contentstack/cli-audit/1.16.1_debug@4.4.3: @@ -2164,6 +2288,12 @@ packages: '@rollup/plugin-json': 6.1.0_rollup@4.53.3 '@rollup/plugin-node-resolve': 16.0.3_rollup@4.53.3 '@rollup/plugin-typescript': 12.3.0_jskuoxsrne6v3mi2gnh7j7672u + '@oclif/plugin-help': 6.2.36 + '@oclif/plugin-plugins': 5.4.54 + '@rollup/plugin-commonjs': 28.0.9_rollup@4.53.3 + '@rollup/plugin-json': 6.1.0_rollup@4.53.3 + '@rollup/plugin-node-resolve': 16.0.3_rollup@4.53.3 + '@rollup/plugin-typescript': 12.3.0_jskuoxsrne6v3mi2gnh7j7672u '@types/express': 4.17.25 '@types/express-serve-static-core': 4.19.7 adm-zip: 0.5.16 @@ -2191,13 +2321,84 @@ packages: - typescript dev: false - /@contentstack/cli-utilities/1.14.4_debug@4.4.3: + /@contentstack/cli-utilities/1.14.4: resolution: {integrity: sha512-Pg124tYh/p688aerqVgk8lEsCF8F5Ky35yes3KO23Wzt44Hvzps7X27psOTHs/aD4jhZkw3aB+jTItQlL84b8g==} dependencies: - '@contentstack/management': 1.25.1_debug@4.4.3 + '@contentstack/management': 1.25.1 + '@contentstack/marketplace-sdk': 1.4.0 + '@oclif/core': 4.8.0 + axios: 1.13.2 + chalk: 4.1.2 + cli-cursor: 3.1.0 + cli-progress: 3.12.0 + cli-table: 0.3.11 + conf: 10.2.0 + dotenv: 16.6.1 + figures: 3.2.0 + inquirer: 8.2.6 + inquirer-search-checkbox: 1.0.0 + inquirer-search-list: 1.2.6 + js-yaml: 4.1.1 + klona: 2.0.6 + lodash: 4.17.21 + mkdirp: 1.0.4 + open: 8.4.2 + ora: 5.4.1 + papaparse: 5.5.3 + recheck: 4.4.5 + rxjs: 6.6.7 + traverse: 0.6.11 + tty-table: 4.2.3 + unique-string: 2.0.0 + uuid: 9.0.1 + winston: 3.19.0 + xdg-basedir: 4.0.0 + transitivePeerDependencies: + - debug + + /@contentstack/cli-utilities/1.15.0: + resolution: {integrity: sha512-Q3csEjZk7rdEvbhRyq41jMT9nFduxR7zVpyGAkYdialh4KjMHxJvzVUdmYuA3PA92xoTlFdcY97yXPQJpmptTw==} + dependencies: + '@contentstack/management': 1.22.0 + '@contentstack/marketplace-sdk': 1.4.0 + '@oclif/core': 4.8.0 + axios: 1.13.2 + chalk: 4.1.2 + cli-cursor: 3.1.0 + cli-progress: 3.12.0 + cli-table: 0.3.11 + conf: 10.2.0 + dotenv: 16.6.1 + figures: 3.2.0 + inquirer: 8.2.6 + inquirer-search-checkbox: 1.0.0 + inquirer-search-list: 1.2.6 + js-yaml: 4.1.1 + klona: 2.0.6 + lodash: 4.17.21 + mkdirp: 1.0.4 + open: 8.4.2 + ora: 5.4.1 + papaparse: 5.5.3 + recheck: 4.4.5 + rxjs: 6.6.7 + traverse: 0.6.11 + tty-table: 4.2.3 + unique-string: 2.0.0 + uuid: 9.0.1 + winston: 3.19.0 + xdg-basedir: 4.0.0 + transitivePeerDependencies: + - debug + + /@contentstack/cli-utilities/1.15.0_debug@4.4.3: + resolution: {integrity: sha512-Q3csEjZk7rdEvbhRyq41jMT9nFduxR7zVpyGAkYdialh4KjMHxJvzVUdmYuA3PA92xoTlFdcY97yXPQJpmptTw==} + dependencies: + '@contentstack/management': 1.22.0_debug@4.4.3 '@contentstack/marketplace-sdk': 1.4.0_debug@4.4.3 '@oclif/core': 4.8.0 axios: 1.13.2_debug@4.4.3 + axios: 1.13.2_debug@4.4.3 chalk: 4.1.2 cli-cursor: 3.1.0 cli-progress: 3.12.0 @@ -2209,6 +2410,7 @@ packages: inquirer-search-checkbox: 1.0.0 inquirer-search-list: 1.2.6 js-yaml: 4.1.1 + js-yaml: 4.1.1 klona: 2.0.6 lodash: 4.17.21 mkdirp: 1.0.4 @@ -2221,7 +2423,7 @@ packages: tty-table: 4.2.3 unique-string: 2.0.0 uuid: 9.0.1 - winston: 3.18.3 + winston: 3.19.0 xdg-basedir: 4.0.0 transitivePeerDependencies: - debug @@ -2269,15 +2471,16 @@ packages: dependencies: assert: 2.1.0 axios: 1.13.2 + axios: 1.13.2 buffer: 6.0.3 form-data: 4.0.5 + form-data: 4.0.5 husky: 9.1.7 lodash: 4.17.21 qs: 6.14.0 stream-browserify: 3.0.0 transitivePeerDependencies: - debug - dev: false /@contentstack/management/1.22.0_debug@4.4.3: resolution: {integrity: sha512-TmwCKhdZnmGpcTuXn5JWbvMqbu0PqEn8Z/oEUlCelAxpo9vSC2qS4aejJtLTqC3Gii/7cJwjqF1BoFpwSO5J9A==} @@ -2285,8 +2488,10 @@ packages: dependencies: assert: 2.1.0 axios: 1.13.2_debug@4.4.3 + axios: 1.13.2_debug@4.4.3 buffer: 6.0.3 form-data: 4.0.5 + form-data: 4.0.5 husky: 9.1.7 lodash: 4.17.21 qs: 6.14.0 @@ -2301,8 +2506,10 @@ packages: dependencies: assert: 2.1.0 axios: 1.13.2 + axios: 1.13.2 buffer: 6.0.3 form-data: 4.0.5 + form-data: 4.0.5 husky: 9.1.7 lodash: 4.17.21 otplib: 12.0.1 @@ -2333,14 +2540,15 @@ packages: resolution: {integrity: sha512-vUi9hoSh5ytr2KmuIKx+g7QDJqevIsM7UX12deCsCTdYH1q7eSrYwpv+jFH+TfrDQUYa71T/xrIF0QiTMUMqdA==} dependencies: axios: 1.13.2 + axios: 1.13.2 transitivePeerDependencies: - debug - dev: false /@contentstack/marketplace-sdk/1.4.0_debug@4.4.3: resolution: {integrity: sha512-vUi9hoSh5ytr2KmuIKx+g7QDJqevIsM7UX12deCsCTdYH1q7eSrYwpv+jFH+TfrDQUYa71T/xrIF0QiTMUMqdA==} dependencies: axios: 1.13.2_debug@4.4.3 + axios: 1.13.2_debug@4.4.3 transitivePeerDependencies: - debug dev: false @@ -2363,8 +2571,9 @@ packages: '@so-ric/colorspace': 1.1.6 enabled: 2.0.0 kuler: 2.0.0 - dev: false + /@emnapi/core/1.7.1: + resolution: {integrity: sha512-o1uhUASyo921r2XtHYOHy7gdkGLge8ghBEQHMWmyJFoXlpU58kIrhhN3w26lpQb6dspetweapMn2CSNwQ8I4wg==} /@emnapi/core/1.7.1: resolution: {integrity: sha512-o1uhUASyo921r2XtHYOHy7gdkGLge8ghBEQHMWmyJFoXlpU58kIrhhN3w26lpQb6dspetweapMn2CSNwQ8I4wg==} requiresBuild: true @@ -2374,6 +2583,8 @@ packages: dev: true optional: true + /@emnapi/runtime/1.7.1: + resolution: {integrity: sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA==} /@emnapi/runtime/1.7.1: resolution: {integrity: sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA==} requiresBuild: true @@ -2655,12 +2866,14 @@ packages: eslint-visitor-keys: 3.4.3 dev: true + /@eslint-community/eslint-utils/4.9.0_eslint@9.39.1: /@eslint-community/eslint-utils/4.9.0_eslint@9.39.1: resolution: {integrity: sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 dependencies: + eslint: 9.39.1 eslint: 9.39.1 eslint-visitor-keys: 3.4.3 dev: true @@ -2735,6 +2948,8 @@ packages: '@types/json-schema': 7.0.15 dev: true + /@eslint/css-tree/3.6.8: + resolution: {integrity: sha512-s0f40zY7dlMp8i0Jf0u6l/aSswS0WRAgkhgETgiCJRcxIWb4S/Sp9uScKHWbkM3BnoFLbJbmOYk5AZUDFVxaLA==} /@eslint/css-tree/3.6.8: resolution: {integrity: sha512-s0f40zY7dlMp8i0Jf0u6l/aSswS0WRAgkhgETgiCJRcxIWb4S/Sp9uScKHWbkM3BnoFLbJbmOYk5AZUDFVxaLA==} engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} @@ -2749,6 +2964,7 @@ packages: dependencies: '@eslint/core': 0.14.0 '@eslint/css-tree': 3.6.8 + '@eslint/css-tree': 3.6.8 '@eslint/plugin-kit': 0.3.5 dev: true @@ -2763,6 +2979,7 @@ packages: ignore: 4.0.6 import-fresh: 3.3.1 js-yaml: 3.14.2 + js-yaml: 3.14.2 minimatch: 3.1.2 strip-json-comments: 3.1.1 transitivePeerDependencies: @@ -2780,14 +2997,15 @@ packages: ignore: 5.3.2 import-fresh: 3.3.1 js-yaml: 4.1.1 + js-yaml: 4.1.1 minimatch: 3.1.2 strip-json-comments: 3.1.1 transitivePeerDependencies: - supports-color dev: true - /@eslint/eslintrc/3.3.1: - resolution: {integrity: sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==} + /@eslint/eslintrc/3.3.3: + resolution: {integrity: sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} dependencies: ajv: 6.12.6 @@ -2797,6 +3015,7 @@ packages: ignore: 5.3.2 import-fresh: 3.3.1 js-yaml: 4.1.1 + js-yaml: 4.1.1 minimatch: 3.1.2 strip-json-comments: 3.1.1 transitivePeerDependencies: @@ -2808,6 +3027,8 @@ packages: engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true + /@eslint/js/9.39.1: + resolution: {integrity: sha512-S26Stp4zCy88tH94QbBv3XCuzRQiZ9yXofEILmglYTh/Ug/a9/umqvgFtYBAo3Lp0nsI/5/qH1CCrbdK3AP1Tw==} /@eslint/js/9.39.1: resolution: {integrity: sha512-S26Stp4zCy88tH94QbBv3XCuzRQiZ9yXofEILmglYTh/Ug/a9/umqvgFtYBAo3Lp0nsI/5/qH1CCrbdK3AP1Tw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -2872,12 +3093,14 @@ packages: lodash.uniq: 4.5.0 dev: false + /@graphql-typed-document-node/core/3.2.0_graphql@16.12.0: /@graphql-typed-document-node/core/3.2.0_graphql@16.12.0: resolution: {integrity: sha512-mB9oAsNCm9aM3/SOv4YtBMqZbYj10R7dkq8byBqxGY/ncFwhf2oQzMV+LCRlWoDSEBJ3COiR1yeDvMtsoOsuFQ==} peerDependencies: graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 dependencies: graphql: 16.12.0 + graphql: 16.12.0 dev: false /@humanfs/core/0.19.1: @@ -2942,10 +3165,14 @@ packages: engines: {node: '>=18.18'} dev: true + /@inquirer/ansi/1.0.2: + resolution: {integrity: sha512-S8qNSZiYzFd0wAcyG5AXCvUHC5Sr7xpZ9wZ2py9XR88jUz8wooStVx5M6dRzczbBWjic9NP7+rY0Xi7qqK/aMQ==} /@inquirer/ansi/1.0.2: resolution: {integrity: sha512-S8qNSZiYzFd0wAcyG5AXCvUHC5Sr7xpZ9wZ2py9XR88jUz8wooStVx5M6dRzczbBWjic9NP7+rY0Xi7qqK/aMQ==} engines: {node: '>=18'} + /@inquirer/checkbox/4.3.2: + resolution: {integrity: sha512-VXukHf0RR1doGe6Sm4F0Em7SWYLTHSsbGfJdS9Ja2bX5/D5uwVOEjr07cncLROdBvmnvCATYEWlHqYmXv2IlQA==} /@inquirer/checkbox/4.3.2: resolution: {integrity: sha512-VXukHf0RR1doGe6Sm4F0Em7SWYLTHSsbGfJdS9Ja2bX5/D5uwVOEjr07cncLROdBvmnvCATYEWlHqYmXv2IlQA==} engines: {node: '>=18'} @@ -2959,9 +3186,15 @@ packages: '@inquirer/core': 10.3.2 '@inquirer/figures': 1.0.15 '@inquirer/type': 3.0.10 - yoctocolors-cjs: 2.1.3 - dev: true + '@inquirer/ansi': 1.0.2 + '@inquirer/core': 10.3.2 + '@inquirer/figures': 1.0.15 + '@inquirer/type': 3.0.10 + yoctocolors-cjs: 2.1.3 + dev: true + /@inquirer/checkbox/4.3.2_@types+node@14.18.63: + resolution: {integrity: sha512-VXukHf0RR1doGe6Sm4F0Em7SWYLTHSsbGfJdS9Ja2bX5/D5uwVOEjr07cncLROdBvmnvCATYEWlHqYmXv2IlQA==} /@inquirer/checkbox/4.3.2_@types+node@14.18.63: resolution: {integrity: sha512-VXukHf0RR1doGe6Sm4F0Em7SWYLTHSsbGfJdS9Ja2bX5/D5uwVOEjr07cncLROdBvmnvCATYEWlHqYmXv2IlQA==} engines: {node: '>=18'} @@ -2971,6 +3204,10 @@ packages: '@types/node': optional: true dependencies: + '@inquirer/ansi': 1.0.2 + '@inquirer/core': 10.3.2_@types+node@14.18.63 + '@inquirer/figures': 1.0.15 + '@inquirer/type': 3.0.10_@types+node@14.18.63 '@inquirer/ansi': 1.0.2 '@inquirer/core': 10.3.2_@types+node@14.18.63 '@inquirer/figures': 1.0.15 @@ -3003,6 +3240,8 @@ packages: '@inquirer/type': 1.5.5 dev: true + /@inquirer/confirm/5.1.21: + resolution: {integrity: sha512-KR8edRkIsUayMXV+o3Gv+q4jlhENF9nMYUZs9PA2HzrXeHI8M5uDag70U7RJn9yyiMZSbtF5/UexBtAVtZGSbQ==} /@inquirer/confirm/5.1.21: resolution: {integrity: sha512-KR8edRkIsUayMXV+o3Gv+q4jlhENF9nMYUZs9PA2HzrXeHI8M5uDag70U7RJn9yyiMZSbtF5/UexBtAVtZGSbQ==} engines: {node: '>=18'} @@ -3014,8 +3253,12 @@ packages: dependencies: '@inquirer/core': 10.3.2 '@inquirer/type': 3.0.10 + '@inquirer/core': 10.3.2 + '@inquirer/type': 3.0.10 dev: true + /@inquirer/confirm/5.1.21_@types+node@14.18.63: + resolution: {integrity: sha512-KR8edRkIsUayMXV+o3Gv+q4jlhENF9nMYUZs9PA2HzrXeHI8M5uDag70U7RJn9yyiMZSbtF5/UexBtAVtZGSbQ==} /@inquirer/confirm/5.1.21_@types+node@14.18.63: resolution: {integrity: sha512-KR8edRkIsUayMXV+o3Gv+q4jlhENF9nMYUZs9PA2HzrXeHI8M5uDag70U7RJn9yyiMZSbtF5/UexBtAVtZGSbQ==} engines: {node: '>=18'} @@ -3025,6 +3268,8 @@ packages: '@types/node': optional: true dependencies: + '@inquirer/core': 10.3.2_@types+node@14.18.63 + '@inquirer/type': 3.0.10_@types+node@14.18.63 '@inquirer/core': 10.3.2_@types+node@14.18.63 '@inquirer/type': 3.0.10_@types+node@14.18.63 '@types/node': 14.18.63 @@ -3043,6 +3288,8 @@ packages: '@types/node': 20.19.25 dev: true + /@inquirer/core/10.3.2: + resolution: {integrity: sha512-43RTuEbfP8MbKzedNqBrlhhNKVwoK//vUFNW3Q3vZ88BLcrs4kYpGg+B2mm5p2K/HfygoCxuKwJJiv8PbGmE0A==} /@inquirer/core/10.3.2: resolution: {integrity: sha512-43RTuEbfP8MbKzedNqBrlhhNKVwoK//vUFNW3Q3vZ88BLcrs4kYpGg+B2mm5p2K/HfygoCxuKwJJiv8PbGmE0A==} engines: {node: '>=18'} @@ -3052,6 +3299,9 @@ packages: '@types/node': optional: true dependencies: + '@inquirer/ansi': 1.0.2 + '@inquirer/figures': 1.0.15 + '@inquirer/type': 3.0.10 '@inquirer/ansi': 1.0.2 '@inquirer/figures': 1.0.15 '@inquirer/type': 3.0.10 @@ -3062,6 +3312,8 @@ packages: yoctocolors-cjs: 2.1.3 dev: true + /@inquirer/core/10.3.2_@types+node@14.18.63: + resolution: {integrity: sha512-43RTuEbfP8MbKzedNqBrlhhNKVwoK//vUFNW3Q3vZ88BLcrs4kYpGg+B2mm5p2K/HfygoCxuKwJJiv8PbGmE0A==} /@inquirer/core/10.3.2_@types+node@14.18.63: resolution: {integrity: sha512-43RTuEbfP8MbKzedNqBrlhhNKVwoK//vUFNW3Q3vZ88BLcrs4kYpGg+B2mm5p2K/HfygoCxuKwJJiv8PbGmE0A==} engines: {node: '>=18'} @@ -3071,6 +3323,9 @@ packages: '@types/node': optional: true dependencies: + '@inquirer/ansi': 1.0.2 + '@inquirer/figures': 1.0.15 + '@inquirer/type': 3.0.10_@types+node@14.18.63 '@inquirer/ansi': 1.0.2 '@inquirer/figures': 1.0.15 '@inquirer/type': 3.0.10_@types+node@14.18.63 @@ -3105,6 +3360,7 @@ packages: resolution: {integrity: sha512-F2VBt7W/mwqEU4bL0RnHNZmC/OxzNx9cOYxHqnXX3MP6ruYvZUZAW9imgN9+h/uBT/oP8Gh888J2OZSbjSeWcg==} engines: {node: '>=18'} dependencies: + '@inquirer/figures': 1.0.15 '@inquirer/figures': 1.0.15 '@inquirer/type': 2.0.0 '@types/mute-stream': 0.0.4 @@ -3119,6 +3375,8 @@ packages: yoctocolors-cjs: 2.1.3 dev: true + /@inquirer/editor/4.2.23: + resolution: {integrity: sha512-aLSROkEwirotxZ1pBaP8tugXRFCxW94gwrQLxXfrZsKkfjOYC1aRvAZuhpJOb5cu4IBTJdsCigUlf2iCOu4ZDQ==} /@inquirer/editor/4.2.23: resolution: {integrity: sha512-aLSROkEwirotxZ1pBaP8tugXRFCxW94gwrQLxXfrZsKkfjOYC1aRvAZuhpJOb5cu4IBTJdsCigUlf2iCOu4ZDQ==} engines: {node: '>=18'} @@ -3131,8 +3389,13 @@ packages: '@inquirer/core': 10.3.2 '@inquirer/external-editor': 1.0.3 '@inquirer/type': 3.0.10 + '@inquirer/core': 10.3.2 + '@inquirer/external-editor': 1.0.3 + '@inquirer/type': 3.0.10 dev: true + /@inquirer/editor/4.2.23_@types+node@14.18.63: + resolution: {integrity: sha512-aLSROkEwirotxZ1pBaP8tugXRFCxW94gwrQLxXfrZsKkfjOYC1aRvAZuhpJOb5cu4IBTJdsCigUlf2iCOu4ZDQ==} /@inquirer/editor/4.2.23_@types+node@14.18.63: resolution: {integrity: sha512-aLSROkEwirotxZ1pBaP8tugXRFCxW94gwrQLxXfrZsKkfjOYC1aRvAZuhpJOb5cu4IBTJdsCigUlf2iCOu4ZDQ==} engines: {node: '>=18'} @@ -3142,6 +3405,9 @@ packages: '@types/node': optional: true dependencies: + '@inquirer/core': 10.3.2_@types+node@14.18.63 + '@inquirer/external-editor': 1.0.3_@types+node@14.18.63 + '@inquirer/type': 3.0.10_@types+node@14.18.63 '@inquirer/core': 10.3.2_@types+node@14.18.63 '@inquirer/external-editor': 1.0.3_@types+node@14.18.63 '@inquirer/type': 3.0.10_@types+node@14.18.63 @@ -3162,6 +3428,8 @@ packages: '@types/node': 20.19.25 dev: true + /@inquirer/expand/4.0.23: + resolution: {integrity: sha512-nRzdOyFYnpeYTTR2qFwEVmIWypzdAx/sIkCMeTNTcflFOovfqUk+HcFhQQVBftAh9gmGrpFj6QcGEqrDMDOiew==} /@inquirer/expand/4.0.23: resolution: {integrity: sha512-nRzdOyFYnpeYTTR2qFwEVmIWypzdAx/sIkCMeTNTcflFOovfqUk+HcFhQQVBftAh9gmGrpFj6QcGEqrDMDOiew==} engines: {node: '>=18'} @@ -3171,11 +3439,15 @@ packages: '@types/node': optional: true dependencies: + '@inquirer/core': 10.3.2 + '@inquirer/type': 3.0.10 '@inquirer/core': 10.3.2 '@inquirer/type': 3.0.10 yoctocolors-cjs: 2.1.3 dev: true + /@inquirer/expand/4.0.23_@types+node@14.18.63: + resolution: {integrity: sha512-nRzdOyFYnpeYTTR2qFwEVmIWypzdAx/sIkCMeTNTcflFOovfqUk+HcFhQQVBftAh9gmGrpFj6QcGEqrDMDOiew==} /@inquirer/expand/4.0.23_@types+node@14.18.63: resolution: {integrity: sha512-nRzdOyFYnpeYTTR2qFwEVmIWypzdAx/sIkCMeTNTcflFOovfqUk+HcFhQQVBftAh9gmGrpFj6QcGEqrDMDOiew==} engines: {node: '>=18'} @@ -3185,6 +3457,8 @@ packages: '@types/node': optional: true dependencies: + '@inquirer/core': 10.3.2_@types+node@14.18.63 + '@inquirer/type': 3.0.10_@types+node@14.18.63 '@inquirer/core': 10.3.2_@types+node@14.18.63 '@inquirer/type': 3.0.10_@types+node@14.18.63 '@types/node': 14.18.63 @@ -3205,6 +3479,8 @@ packages: yoctocolors-cjs: 2.1.3 dev: true + /@inquirer/external-editor/1.0.3: + resolution: {integrity: sha512-RWbSrDiYmO4LbejWY7ttpxczuwQyZLBUyygsA9Nsv95hpzUWwnNTVQmAq3xuh7vNwCp07UTmE5i11XAEExx4RA==} /@inquirer/external-editor/1.0.3: resolution: {integrity: sha512-RWbSrDiYmO4LbejWY7ttpxczuwQyZLBUyygsA9Nsv95hpzUWwnNTVQmAq3xuh7vNwCp07UTmE5i11XAEExx4RA==} engines: {node: '>=18'} @@ -3217,6 +3493,8 @@ packages: chardet: 2.1.1 iconv-lite: 0.7.0 + /@inquirer/external-editor/1.0.3_@types+node@14.18.63: + resolution: {integrity: sha512-RWbSrDiYmO4LbejWY7ttpxczuwQyZLBUyygsA9Nsv95hpzUWwnNTVQmAq3xuh7vNwCp07UTmE5i11XAEExx4RA==} /@inquirer/external-editor/1.0.3_@types+node@14.18.63: resolution: {integrity: sha512-RWbSrDiYmO4LbejWY7ttpxczuwQyZLBUyygsA9Nsv95hpzUWwnNTVQmAq3xuh7vNwCp07UTmE5i11XAEExx4RA==} engines: {node: '>=18'} @@ -3244,6 +3522,8 @@ packages: iconv-lite: 0.7.0 dev: true + /@inquirer/figures/1.0.15: + resolution: {integrity: sha512-t2IEY+unGHOzAaVM5Xx6DEWKeXlDDcNPeDyUpsRc6CUhBfU3VQOEl+Vssh7VNp1dR8MdUJBWhuObjXCsVpjN5g==} /@inquirer/figures/1.0.15: resolution: {integrity: sha512-t2IEY+unGHOzAaVM5Xx6DEWKeXlDDcNPeDyUpsRc6CUhBfU3VQOEl+Vssh7VNp1dR8MdUJBWhuObjXCsVpjN5g==} engines: {node: '>=18'} @@ -3256,6 +3536,8 @@ packages: '@inquirer/type': 1.5.5 dev: true + /@inquirer/input/4.3.1: + resolution: {integrity: sha512-kN0pAM4yPrLjJ1XJBjDxyfDduXOuQHrBB8aLDMueuwUGn+vNpF7Gq7TvyVxx8u4SHlFFj4trmj+a2cbpG4Jn1g==} /@inquirer/input/4.3.1: resolution: {integrity: sha512-kN0pAM4yPrLjJ1XJBjDxyfDduXOuQHrBB8aLDMueuwUGn+vNpF7Gq7TvyVxx8u4SHlFFj4trmj+a2cbpG4Jn1g==} engines: {node: '>=18'} @@ -3267,8 +3549,12 @@ packages: dependencies: '@inquirer/core': 10.3.2 '@inquirer/type': 3.0.10 + '@inquirer/core': 10.3.2 + '@inquirer/type': 3.0.10 dev: true + /@inquirer/input/4.3.1_@types+node@14.18.63: + resolution: {integrity: sha512-kN0pAM4yPrLjJ1XJBjDxyfDduXOuQHrBB8aLDMueuwUGn+vNpF7Gq7TvyVxx8u4SHlFFj4trmj+a2cbpG4Jn1g==} /@inquirer/input/4.3.1_@types+node@14.18.63: resolution: {integrity: sha512-kN0pAM4yPrLjJ1XJBjDxyfDduXOuQHrBB8aLDMueuwUGn+vNpF7Gq7TvyVxx8u4SHlFFj4trmj+a2cbpG4Jn1g==} engines: {node: '>=18'} @@ -3278,6 +3564,8 @@ packages: '@types/node': optional: true dependencies: + '@inquirer/core': 10.3.2_@types+node@14.18.63 + '@inquirer/type': 3.0.10_@types+node@14.18.63 '@inquirer/core': 10.3.2_@types+node@14.18.63 '@inquirer/type': 3.0.10_@types+node@14.18.63 '@types/node': 14.18.63 @@ -3296,6 +3584,8 @@ packages: '@types/node': 20.19.25 dev: true + /@inquirer/number/3.0.23: + resolution: {integrity: sha512-5Smv0OK7K0KUzUfYUXDXQc9jrf8OHo4ktlEayFlelCjwMXz0299Y8OrI+lj7i4gCBY15UObk76q0QtxjzFcFcg==} /@inquirer/number/3.0.23: resolution: {integrity: sha512-5Smv0OK7K0KUzUfYUXDXQc9jrf8OHo4ktlEayFlelCjwMXz0299Y8OrI+lj7i4gCBY15UObk76q0QtxjzFcFcg==} engines: {node: '>=18'} @@ -3307,8 +3597,12 @@ packages: dependencies: '@inquirer/core': 10.3.2 '@inquirer/type': 3.0.10 + '@inquirer/core': 10.3.2 + '@inquirer/type': 3.0.10 dev: true + /@inquirer/number/3.0.23_@types+node@14.18.63: + resolution: {integrity: sha512-5Smv0OK7K0KUzUfYUXDXQc9jrf8OHo4ktlEayFlelCjwMXz0299Y8OrI+lj7i4gCBY15UObk76q0QtxjzFcFcg==} /@inquirer/number/3.0.23_@types+node@14.18.63: resolution: {integrity: sha512-5Smv0OK7K0KUzUfYUXDXQc9jrf8OHo4ktlEayFlelCjwMXz0299Y8OrI+lj7i4gCBY15UObk76q0QtxjzFcFcg==} engines: {node: '>=18'} @@ -3318,6 +3612,8 @@ packages: '@types/node': optional: true dependencies: + '@inquirer/core': 10.3.2_@types+node@14.18.63 + '@inquirer/type': 3.0.10_@types+node@14.18.63 '@inquirer/core': 10.3.2_@types+node@14.18.63 '@inquirer/type': 3.0.10_@types+node@14.18.63 '@types/node': 14.18.63 @@ -3336,6 +3632,8 @@ packages: '@types/node': 20.19.25 dev: true + /@inquirer/password/4.0.23: + resolution: {integrity: sha512-zREJHjhT5vJBMZX/IUbyI9zVtVfOLiTO66MrF/3GFZYZ7T4YILW5MSkEYHceSii/KtRk+4i3RE7E1CUXA2jHcA==} /@inquirer/password/4.0.23: resolution: {integrity: sha512-zREJHjhT5vJBMZX/IUbyI9zVtVfOLiTO66MrF/3GFZYZ7T4YILW5MSkEYHceSii/KtRk+4i3RE7E1CUXA2jHcA==} engines: {node: '>=18'} @@ -3348,8 +3646,13 @@ packages: '@inquirer/ansi': 1.0.2 '@inquirer/core': 10.3.2 '@inquirer/type': 3.0.10 + '@inquirer/ansi': 1.0.2 + '@inquirer/core': 10.3.2 + '@inquirer/type': 3.0.10 dev: true + /@inquirer/password/4.0.23_@types+node@14.18.63: + resolution: {integrity: sha512-zREJHjhT5vJBMZX/IUbyI9zVtVfOLiTO66MrF/3GFZYZ7T4YILW5MSkEYHceSii/KtRk+4i3RE7E1CUXA2jHcA==} /@inquirer/password/4.0.23_@types+node@14.18.63: resolution: {integrity: sha512-zREJHjhT5vJBMZX/IUbyI9zVtVfOLiTO66MrF/3GFZYZ7T4YILW5MSkEYHceSii/KtRk+4i3RE7E1CUXA2jHcA==} engines: {node: '>=18'} @@ -3359,6 +3662,9 @@ packages: '@types/node': optional: true dependencies: + '@inquirer/ansi': 1.0.2 + '@inquirer/core': 10.3.2_@types+node@14.18.63 + '@inquirer/type': 3.0.10_@types+node@14.18.63 '@inquirer/ansi': 1.0.2 '@inquirer/core': 10.3.2_@types+node@14.18.63 '@inquirer/type': 3.0.10_@types+node@14.18.63 @@ -3379,6 +3685,8 @@ packages: '@types/node': 20.19.25 dev: true + /@inquirer/prompts/7.10.1: + resolution: {integrity: sha512-Dx/y9bCQcXLI5ooQ5KyvA4FTgeo2jYj/7plWfV5Ak5wDPKQZgudKez2ixyfz7tKXzcJciTxqLeK7R9HItwiByg==} /@inquirer/prompts/7.10.1: resolution: {integrity: sha512-Dx/y9bCQcXLI5ooQ5KyvA4FTgeo2jYj/7plWfV5Ak5wDPKQZgudKez2ixyfz7tKXzcJciTxqLeK7R9HItwiByg==} engines: {node: '>=18'} @@ -3398,8 +3706,20 @@ packages: '@inquirer/rawlist': 4.1.11 '@inquirer/search': 3.2.2 '@inquirer/select': 4.4.2 + '@inquirer/checkbox': 4.3.2 + '@inquirer/confirm': 5.1.21 + '@inquirer/editor': 4.2.23 + '@inquirer/expand': 4.0.23 + '@inquirer/input': 4.3.1 + '@inquirer/number': 3.0.23 + '@inquirer/password': 4.0.23 + '@inquirer/rawlist': 4.1.11 + '@inquirer/search': 3.2.2 + '@inquirer/select': 4.4.2 dev: true + /@inquirer/prompts/7.10.1_@types+node@14.18.63: + resolution: {integrity: sha512-Dx/y9bCQcXLI5ooQ5KyvA4FTgeo2jYj/7plWfV5Ak5wDPKQZgudKez2ixyfz7tKXzcJciTxqLeK7R9HItwiByg==} /@inquirer/prompts/7.10.1_@types+node@14.18.63: resolution: {integrity: sha512-Dx/y9bCQcXLI5ooQ5KyvA4FTgeo2jYj/7plWfV5Ak5wDPKQZgudKez2ixyfz7tKXzcJciTxqLeK7R9HItwiByg==} engines: {node: '>=18'} @@ -3409,6 +3729,16 @@ packages: '@types/node': optional: true dependencies: + '@inquirer/checkbox': 4.3.2_@types+node@14.18.63 + '@inquirer/confirm': 5.1.21_@types+node@14.18.63 + '@inquirer/editor': 4.2.23_@types+node@14.18.63 + '@inquirer/expand': 4.0.23_@types+node@14.18.63 + '@inquirer/input': 4.3.1_@types+node@14.18.63 + '@inquirer/number': 3.0.23_@types+node@14.18.63 + '@inquirer/password': 4.0.23_@types+node@14.18.63 + '@inquirer/rawlist': 4.1.11_@types+node@14.18.63 + '@inquirer/search': 3.2.2_@types+node@14.18.63 + '@inquirer/select': 4.4.2_@types+node@14.18.63 '@inquirer/checkbox': 4.3.2_@types+node@14.18.63 '@inquirer/confirm': 5.1.21_@types+node@14.18.63 '@inquirer/editor': 4.2.23_@types+node@14.18.63 @@ -3443,6 +3773,8 @@ packages: '@types/node': 20.19.25 dev: true + /@inquirer/rawlist/4.1.11: + resolution: {integrity: sha512-+LLQB8XGr3I5LZN/GuAHo+GpDJegQwuPARLChlMICNdwW7OwV2izlCSCxN6cqpL0sMXmbKbFcItJgdQq5EBXTw==} /@inquirer/rawlist/4.1.11: resolution: {integrity: sha512-+LLQB8XGr3I5LZN/GuAHo+GpDJegQwuPARLChlMICNdwW7OwV2izlCSCxN6cqpL0sMXmbKbFcItJgdQq5EBXTw==} engines: {node: '>=18'} @@ -3452,11 +3784,15 @@ packages: '@types/node': optional: true dependencies: + '@inquirer/core': 10.3.2 + '@inquirer/type': 3.0.10 '@inquirer/core': 10.3.2 '@inquirer/type': 3.0.10 yoctocolors-cjs: 2.1.3 dev: true + /@inquirer/rawlist/4.1.11_@types+node@14.18.63: + resolution: {integrity: sha512-+LLQB8XGr3I5LZN/GuAHo+GpDJegQwuPARLChlMICNdwW7OwV2izlCSCxN6cqpL0sMXmbKbFcItJgdQq5EBXTw==} /@inquirer/rawlist/4.1.11_@types+node@14.18.63: resolution: {integrity: sha512-+LLQB8XGr3I5LZN/GuAHo+GpDJegQwuPARLChlMICNdwW7OwV2izlCSCxN6cqpL0sMXmbKbFcItJgdQq5EBXTw==} engines: {node: '>=18'} @@ -3466,6 +3802,8 @@ packages: '@types/node': optional: true dependencies: + '@inquirer/core': 10.3.2_@types+node@14.18.63 + '@inquirer/type': 3.0.10_@types+node@14.18.63 '@inquirer/core': 10.3.2_@types+node@14.18.63 '@inquirer/type': 3.0.10_@types+node@14.18.63 '@types/node': 14.18.63 @@ -3486,6 +3824,8 @@ packages: yoctocolors-cjs: 2.1.3 dev: true + /@inquirer/search/3.2.2: + resolution: {integrity: sha512-p2bvRfENXCZdWF/U2BXvnSI9h+tuA8iNqtUKb9UWbmLYCRQxd8WkvwWvYn+3NgYaNwdUkHytJMGG4MMLucI1kA==} /@inquirer/search/3.2.2: resolution: {integrity: sha512-p2bvRfENXCZdWF/U2BXvnSI9h+tuA8iNqtUKb9UWbmLYCRQxd8WkvwWvYn+3NgYaNwdUkHytJMGG4MMLucI1kA==} engines: {node: '>=18'} @@ -3495,12 +3835,17 @@ packages: '@types/node': optional: true dependencies: + '@inquirer/core': 10.3.2 + '@inquirer/figures': 1.0.15 + '@inquirer/type': 3.0.10 '@inquirer/core': 10.3.2 '@inquirer/figures': 1.0.15 '@inquirer/type': 3.0.10 yoctocolors-cjs: 2.1.3 dev: true + /@inquirer/search/3.2.2_@types+node@14.18.63: + resolution: {integrity: sha512-p2bvRfENXCZdWF/U2BXvnSI9h+tuA8iNqtUKb9UWbmLYCRQxd8WkvwWvYn+3NgYaNwdUkHytJMGG4MMLucI1kA==} /@inquirer/search/3.2.2_@types+node@14.18.63: resolution: {integrity: sha512-p2bvRfENXCZdWF/U2BXvnSI9h+tuA8iNqtUKb9UWbmLYCRQxd8WkvwWvYn+3NgYaNwdUkHytJMGG4MMLucI1kA==} engines: {node: '>=18'} @@ -3510,6 +3855,9 @@ packages: '@types/node': optional: true dependencies: + '@inquirer/core': 10.3.2_@types+node@14.18.63 + '@inquirer/figures': 1.0.15 + '@inquirer/type': 3.0.10_@types+node@14.18.63 '@inquirer/core': 10.3.2_@types+node@14.18.63 '@inquirer/figures': 1.0.15 '@inquirer/type': 3.0.10_@types+node@14.18.63 @@ -3538,11 +3886,14 @@ packages: dependencies: '@inquirer/core': 9.2.1 '@inquirer/figures': 1.0.15 + '@inquirer/figures': 1.0.15 '@inquirer/type': 1.5.5 ansi-escapes: 4.3.2 yoctocolors-cjs: 2.1.3 dev: true + /@inquirer/select/4.4.2: + resolution: {integrity: sha512-l4xMuJo55MAe+N7Qr4rX90vypFwCajSakx59qe/tMaC1aEHWLyw68wF4o0A4SLAY4E0nd+Vt+EyskeDIqu1M6w==} /@inquirer/select/4.4.2: resolution: {integrity: sha512-l4xMuJo55MAe+N7Qr4rX90vypFwCajSakx59qe/tMaC1aEHWLyw68wF4o0A4SLAY4E0nd+Vt+EyskeDIqu1M6w==} engines: {node: '>=18'} @@ -3552,6 +3903,10 @@ packages: '@types/node': optional: true dependencies: + '@inquirer/ansi': 1.0.2 + '@inquirer/core': 10.3.2 + '@inquirer/figures': 1.0.15 + '@inquirer/type': 3.0.10 '@inquirer/ansi': 1.0.2 '@inquirer/core': 10.3.2 '@inquirer/figures': 1.0.15 @@ -3559,6 +3914,8 @@ packages: yoctocolors-cjs: 2.1.3 dev: true + /@inquirer/select/4.4.2_@types+node@14.18.63: + resolution: {integrity: sha512-l4xMuJo55MAe+N7Qr4rX90vypFwCajSakx59qe/tMaC1aEHWLyw68wF4o0A4SLAY4E0nd+Vt+EyskeDIqu1M6w==} /@inquirer/select/4.4.2_@types+node@14.18.63: resolution: {integrity: sha512-l4xMuJo55MAe+N7Qr4rX90vypFwCajSakx59qe/tMaC1aEHWLyw68wF4o0A4SLAY4E0nd+Vt+EyskeDIqu1M6w==} engines: {node: '>=18'} @@ -3568,6 +3925,10 @@ packages: '@types/node': optional: true dependencies: + '@inquirer/ansi': 1.0.2 + '@inquirer/core': 10.3.2_@types+node@14.18.63 + '@inquirer/figures': 1.0.15 + '@inquirer/type': 3.0.10_@types+node@14.18.63 '@inquirer/ansi': 1.0.2 '@inquirer/core': 10.3.2_@types+node@14.18.63 '@inquirer/figures': 1.0.15 @@ -3606,6 +3967,8 @@ packages: mute-stream: 1.0.0 dev: true + /@inquirer/type/3.0.10: + resolution: {integrity: sha512-BvziSRxfz5Ov8ch0z/n3oijRSEcEsHnhggm4xFZe93DHcUCTlutlq9Ox4SVENAfcRD22UQq7T/atg9Wr3k09eA==} /@inquirer/type/3.0.10: resolution: {integrity: sha512-BvziSRxfz5Ov8ch0z/n3oijRSEcEsHnhggm4xFZe93DHcUCTlutlq9Ox4SVENAfcRD22UQq7T/atg9Wr3k09eA==} engines: {node: '>=18'} @@ -3616,6 +3979,8 @@ packages: optional: true dev: true + /@inquirer/type/3.0.10_@types+node@14.18.63: + resolution: {integrity: sha512-BvziSRxfz5Ov8ch0z/n3oijRSEcEsHnhggm4xFZe93DHcUCTlutlq9Ox4SVENAfcRD22UQq7T/atg9Wr3k09eA==} /@inquirer/type/3.0.10_@types+node@14.18.63: resolution: {integrity: sha512-BvziSRxfz5Ov8ch0z/n3oijRSEcEsHnhggm4xFZe93DHcUCTlutlq9Ox4SVENAfcRD22UQq7T/atg9Wr3k09eA==} engines: {node: '>=18'} @@ -3642,14 +4007,12 @@ packages: /@isaacs/balanced-match/4.0.1: resolution: {integrity: sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==} engines: {node: 20 || >=22} - dev: true /@isaacs/brace-expansion/5.0.0: resolution: {integrity: sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==} engines: {node: 20 || >=22} dependencies: '@isaacs/balanced-match': 4.0.1 - dev: true /@isaacs/cliui/8.0.2: resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} @@ -3661,6 +4024,7 @@ packages: strip-ansi-cjs: /strip-ansi/6.0.1 wrap-ansi: 8.1.0 wrap-ansi-cjs: /wrap-ansi/7.0.0 + dev: true /@istanbuljs/load-nyc-config/1.1.0: resolution: {integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==} @@ -3670,6 +4034,7 @@ packages: find-up: 4.1.0 get-package-type: 0.1.0 js-yaml: 3.14.2 + js-yaml: 3.14.2 resolve-from: 5.0.0 dev: true @@ -3950,6 +4315,8 @@ packages: resolution: {integrity: sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==} requiresBuild: true dependencies: + '@emnapi/core': 1.7.1 + '@emnapi/runtime': 1.7.1 '@emnapi/core': 1.7.1 '@emnapi/runtime': 1.7.1 '@tybys/wasm-util': 0.10.1 @@ -4005,16 +4372,21 @@ packages: wordwrap: 1.0.0 wrap-ansi: 7.0.0 + /@oclif/plugin-help/6.2.36: + resolution: {integrity: sha512-NBQIg5hEMhvdbi4mSrdqRGl5XJ0bqTAHq6vDCCCDXUcfVtdk3ZJbSxtRVWyVvo9E28vwqu6MZyHOJylevqcHbA==} /@oclif/plugin-help/6.2.36: resolution: {integrity: sha512-NBQIg5hEMhvdbi4mSrdqRGl5XJ0bqTAHq6vDCCCDXUcfVtdk3ZJbSxtRVWyVvo9E28vwqu6MZyHOJylevqcHbA==} engines: {node: '>=18.0.0'} dependencies: '@oclif/core': 4.8.0 + /@oclif/plugin-not-found/3.2.73: + resolution: {integrity: sha512-2bQieTGI9XNFe9hKmXQjJmHV5rZw+yn7Rud1+C5uLEo8GaT89KZbiLTJgL35tGILahy/cB6+WAs812wjw7TK6w==} /@oclif/plugin-not-found/3.2.73: resolution: {integrity: sha512-2bQieTGI9XNFe9hKmXQjJmHV5rZw+yn7Rud1+C5uLEo8GaT89KZbiLTJgL35tGILahy/cB6+WAs812wjw7TK6w==} engines: {node: '>=18.0.0'} dependencies: + '@inquirer/prompts': 7.10.1 '@inquirer/prompts': 7.10.1 '@oclif/core': 4.8.0 ansis: 3.17.0 @@ -4023,10 +4395,13 @@ packages: - '@types/node' dev: true + /@oclif/plugin-not-found/3.2.73_@types+node@14.18.63: + resolution: {integrity: sha512-2bQieTGI9XNFe9hKmXQjJmHV5rZw+yn7Rud1+C5uLEo8GaT89KZbiLTJgL35tGILahy/cB6+WAs812wjw7TK6w==} /@oclif/plugin-not-found/3.2.73_@types+node@14.18.63: resolution: {integrity: sha512-2bQieTGI9XNFe9hKmXQjJmHV5rZw+yn7Rud1+C5uLEo8GaT89KZbiLTJgL35tGILahy/cB6+WAs812wjw7TK6w==} engines: {node: '>=18.0.0'} dependencies: + '@inquirer/prompts': 7.10.1_@types+node@14.18.63 '@inquirer/prompts': 7.10.1_@types+node@14.18.63 '@oclif/core': 4.8.0 ansis: 3.17.0 @@ -4046,6 +4421,8 @@ packages: - '@types/node' dev: true + /@oclif/plugin-plugins/5.4.54: + resolution: {integrity: sha512-yzdukEfvvyXx31AhN+YhxLhuQdx2SrZDcRtPl5CNkuqh/uNSB2BuA3xpurdv2qotpaw/Z9InRl+Sa9bLp/4aLA==} /@oclif/plugin-plugins/5.4.54: resolution: {integrity: sha512-yzdukEfvvyXx31AhN+YhxLhuQdx2SrZDcRtPl5CNkuqh/uNSB2BuA3xpurdv2qotpaw/Z9InRl+Sa9bLp/4aLA==} engines: {node: '>=18.0.0'} @@ -4065,6 +4442,8 @@ packages: - supports-color dev: false + /@oclif/plugin-warn-if-update-available/3.1.53: + resolution: {integrity: sha512-ALxKMNFFJQJV1Z2OMVTV+q7EbKHhnTAPcTgkgHeXCNdW5nFExoXuwusZLS4Zv2o83j9UoDx1R/CSX7QZVgEHTA==} /@oclif/plugin-warn-if-update-available/3.1.53: resolution: {integrity: sha512-ALxKMNFFJQJV1Z2OMVTV+q7EbKHhnTAPcTgkgHeXCNdW5nFExoXuwusZLS4Zv2o83j9UoDx1R/CSX7QZVgEHTA==} engines: {node: '>=18.0.0'} @@ -4079,6 +4458,8 @@ packages: - supports-color dev: true + /@oclif/test/4.1.15_@oclif+core@4.8.0: + resolution: {integrity: sha512-OVTmz3RxnOWYPoE9sbB9Przfph+QSLMvHUfqEwXZKupuOHCJAJX0QDUfVyh1pK+XYEQ2RUaF+qhxqBfIfaahBw==} /@oclif/test/4.1.15_@oclif+core@4.8.0: resolution: {integrity: sha512-OVTmz3RxnOWYPoE9sbB9Przfph+QSLMvHUfqEwXZKupuOHCJAJX0QDUfVyh1pK+XYEQ2RUaF+qhxqBfIfaahBw==} engines: {node: '>=18.0.0'} @@ -4093,20 +4474,17 @@ packages: /@otplib/core/12.0.1: resolution: {integrity: sha512-4sGntwbA/AC+SbPhbsziRiD+jNDdIzsZ3JUyfZwjtKyc/wufl1pnSIaG4Uqx8ymPagujub0o92kgBnB89cuAMA==} - dev: false /@otplib/plugin-crypto/12.0.1: resolution: {integrity: sha512-qPuhN3QrT7ZZLcLCyKOSNhuijUi9G5guMRVrxq63r9YNOxxQjPm59gVxLM+7xGnHnM6cimY57tuKsjK7y9LM1g==} dependencies: '@otplib/core': 12.0.1 - dev: false /@otplib/plugin-thirty-two/12.0.1: resolution: {integrity: sha512-MtT+uqRso909UkbrrYpJ6XFjj9D+x2Py7KjTO9JDPhL0bJUYVu5kFP4TFZW4NFAywrAtFRxOVY261u0qwb93gA==} dependencies: '@otplib/core': 12.0.1 thirty-two: 1.0.2 - dev: false /@otplib/preset-default/12.0.1: resolution: {integrity: sha512-xf1v9oOJRyXfluBhMdpOkr+bsE+Irt+0D5uHtvg6x1eosfmHCsCC6ej/m7FXiWqdo0+ZUI6xSKDhJwc8yfiOPQ==} @@ -4114,7 +4492,6 @@ packages: '@otplib/core': 12.0.1 '@otplib/plugin-crypto': 12.0.1 '@otplib/plugin-thirty-two': 12.0.1 - dev: false /@otplib/preset-v11/12.0.1: resolution: {integrity: sha512-9hSetMI7ECqbFiKICrNa4w70deTUfArtwXykPUvSHWOdzOlfa9ajglu7mNCntlvxycTiOAXkQGwjQCzzDEMRMg==} @@ -4122,12 +4499,12 @@ packages: '@otplib/core': 12.0.1 '@otplib/plugin-crypto': 12.0.1 '@otplib/plugin-thirty-two': 12.0.1 - dev: false /@pkgjs/parseargs/0.11.0: resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} requiresBuild: true + dev: true optional: true /@pnpm/config.env-replace/1.1.0: @@ -4151,6 +4528,7 @@ packages: config-chain: 1.1.13 dev: true + /@rollup/plugin-commonjs/28.0.9_rollup@4.53.3: /@rollup/plugin-commonjs/28.0.9_rollup@4.53.3: resolution: {integrity: sha512-PIR4/OHZ79romx0BVVll/PkwWpJ7e5lsqFa3gFfcrFPWwLXLV39JVUzQV9RKjWerE7B845Hqjj9VYlQeieZ2dA==} engines: {node: '>=16.0.0 || 14 >= 14.17'} @@ -4160,6 +4538,7 @@ packages: rollup: optional: true dependencies: + '@rollup/pluginutils': 5.3.0_rollup@4.53.3 '@rollup/pluginutils': 5.3.0_rollup@4.53.3 commondir: 1.0.1 estree-walker: 2.0.2 @@ -4168,8 +4547,10 @@ packages: magic-string: 0.30.21 picomatch: 4.0.3 rollup: 4.53.3 + rollup: 4.53.3 dev: false + /@rollup/plugin-json/6.1.0_rollup@4.53.3: /@rollup/plugin-json/6.1.0_rollup@4.53.3: resolution: {integrity: sha512-EGI2te5ENk1coGeADSIwZ7G2Q8CJS2sF120T7jLw4xFw9n7wIOXHo+kIYRAoVpJAN+kmqZSoO3Fp4JtoNF4ReA==} engines: {node: '>=14.0.0'} @@ -4181,8 +4562,11 @@ packages: dependencies: '@rollup/pluginutils': 5.3.0_rollup@4.53.3 rollup: 4.53.3 + '@rollup/pluginutils': 5.3.0_rollup@4.53.3 + rollup: 4.53.3 dev: false + /@rollup/plugin-node-resolve/16.0.3_rollup@4.53.3: /@rollup/plugin-node-resolve/16.0.3_rollup@4.53.3: resolution: {integrity: sha512-lUYM3UBGuM93CnMPG1YocWu7X802BrNF3jW2zny5gQyLQgRFJhV1Sq0Zi74+dh/6NBx1DxFC4b4GXg9wUCG5Qg==} engines: {node: '>=14.0.0'} @@ -4192,14 +4576,17 @@ packages: rollup: optional: true dependencies: + '@rollup/pluginutils': 5.3.0_rollup@4.53.3 '@rollup/pluginutils': 5.3.0_rollup@4.53.3 '@types/resolve': 1.20.2 deepmerge: 4.3.1 is-module: 1.0.0 resolve: 1.22.11 rollup: 4.53.3 + rollup: 4.53.3 dev: false + /@rollup/plugin-typescript/12.3.0_jskuoxsrne6v3mi2gnh7j7672u: /@rollup/plugin-typescript/12.3.0_jskuoxsrne6v3mi2gnh7j7672u: resolution: {integrity: sha512-7DP0/p7y3t67+NabT9f8oTBFE6gGkto4SA6Np2oudYmZE/m1dt8RB0SjL1msMxFpLo631qjRCcBlAbq1ml/Big==} engines: {node: '>=14.0.0'} @@ -4213,13 +4600,16 @@ packages: tslib: optional: true dependencies: + '@rollup/pluginutils': 5.3.0_rollup@4.53.3 '@rollup/pluginutils': 5.3.0_rollup@4.53.3 resolve: 1.22.11 rollup: 4.53.3 + rollup: 4.53.3 tslib: 2.8.1 typescript: 4.9.5 dev: false + /@rollup/pluginutils/5.3.0_rollup@4.53.3: /@rollup/pluginutils/5.3.0_rollup@4.53.3: resolution: {integrity: sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==} engines: {node: '>=14.0.0'} @@ -4233,8 +4623,11 @@ packages: estree-walker: 2.0.2 picomatch: 4.0.3 rollup: 4.53.3 + rollup: 4.53.3 dev: false + /@rollup/rollup-android-arm-eabi/4.53.3: + resolution: {integrity: sha512-mRSi+4cBjrRLoaal2PnqH82Wqyb+d3HsPUN/W+WslCXsZsyHa9ZeQQX/pQsZaVIWDkPcpV6jJ+3KLbTbgnwv8w==} /@rollup/rollup-android-arm-eabi/4.53.3: resolution: {integrity: sha512-mRSi+4cBjrRLoaal2PnqH82Wqyb+d3HsPUN/W+WslCXsZsyHa9ZeQQX/pQsZaVIWDkPcpV6jJ+3KLbTbgnwv8w==} cpu: [arm] @@ -4243,6 +4636,8 @@ packages: dev: false optional: true + /@rollup/rollup-android-arm64/4.53.3: + resolution: {integrity: sha512-CbDGaMpdE9sh7sCmTrTUyllhrg65t6SwhjlMJsLr+J8YjFuPmCEjbBSx4Z/e4SmDyH3aB5hGaJUP2ltV/vcs4w==} /@rollup/rollup-android-arm64/4.53.3: resolution: {integrity: sha512-CbDGaMpdE9sh7sCmTrTUyllhrg65t6SwhjlMJsLr+J8YjFuPmCEjbBSx4Z/e4SmDyH3aB5hGaJUP2ltV/vcs4w==} cpu: [arm64] @@ -4251,6 +4646,8 @@ packages: dev: false optional: true + /@rollup/rollup-darwin-arm64/4.53.3: + resolution: {integrity: sha512-Nr7SlQeqIBpOV6BHHGZgYBuSdanCXuw09hon14MGOLGmXAFYjx1wNvquVPmpZnl0tLjg25dEdr4IQ6GgyToCUA==} /@rollup/rollup-darwin-arm64/4.53.3: resolution: {integrity: sha512-Nr7SlQeqIBpOV6BHHGZgYBuSdanCXuw09hon14MGOLGmXAFYjx1wNvquVPmpZnl0tLjg25dEdr4IQ6GgyToCUA==} cpu: [arm64] @@ -4259,6 +4656,8 @@ packages: dev: false optional: true + /@rollup/rollup-darwin-x64/4.53.3: + resolution: {integrity: sha512-DZ8N4CSNfl965CmPktJ8oBnfYr3F8dTTNBQkRlffnUarJ2ohudQD17sZBa097J8xhQ26AwhHJ5mvUyQW8ddTsQ==} /@rollup/rollup-darwin-x64/4.53.3: resolution: {integrity: sha512-DZ8N4CSNfl965CmPktJ8oBnfYr3F8dTTNBQkRlffnUarJ2ohudQD17sZBa097J8xhQ26AwhHJ5mvUyQW8ddTsQ==} cpu: [x64] @@ -4267,6 +4666,8 @@ packages: dev: false optional: true + /@rollup/rollup-freebsd-arm64/4.53.3: + resolution: {integrity: sha512-yMTrCrK92aGyi7GuDNtGn2sNW+Gdb4vErx4t3Gv/Tr+1zRb8ax4z8GWVRfr3Jw8zJWvpGHNpss3vVlbF58DZ4w==} /@rollup/rollup-freebsd-arm64/4.53.3: resolution: {integrity: sha512-yMTrCrK92aGyi7GuDNtGn2sNW+Gdb4vErx4t3Gv/Tr+1zRb8ax4z8GWVRfr3Jw8zJWvpGHNpss3vVlbF58DZ4w==} cpu: [arm64] @@ -4275,6 +4676,8 @@ packages: dev: false optional: true + /@rollup/rollup-freebsd-x64/4.53.3: + resolution: {integrity: sha512-lMfF8X7QhdQzseM6XaX0vbno2m3hlyZFhwcndRMw8fbAGUGL3WFMBdK0hbUBIUYcEcMhVLr1SIamDeuLBnXS+Q==} /@rollup/rollup-freebsd-x64/4.53.3: resolution: {integrity: sha512-lMfF8X7QhdQzseM6XaX0vbno2m3hlyZFhwcndRMw8fbAGUGL3WFMBdK0hbUBIUYcEcMhVLr1SIamDeuLBnXS+Q==} cpu: [x64] @@ -4283,6 +4686,8 @@ packages: dev: false optional: true + /@rollup/rollup-linux-arm-gnueabihf/4.53.3: + resolution: {integrity: sha512-k9oD15soC/Ln6d2Wv/JOFPzZXIAIFLp6B+i14KhxAfnq76ajt0EhYc5YPeX6W1xJkAdItcVT+JhKl1QZh44/qw==} /@rollup/rollup-linux-arm-gnueabihf/4.53.3: resolution: {integrity: sha512-k9oD15soC/Ln6d2Wv/JOFPzZXIAIFLp6B+i14KhxAfnq76ajt0EhYc5YPeX6W1xJkAdItcVT+JhKl1QZh44/qw==} cpu: [arm] @@ -4291,6 +4696,8 @@ packages: dev: false optional: true + /@rollup/rollup-linux-arm-musleabihf/4.53.3: + resolution: {integrity: sha512-vTNlKq+N6CK/8UktsrFuc+/7NlEYVxgaEgRXVUVK258Z5ymho29skzW1sutgYjqNnquGwVUObAaxae8rZ6YMhg==} /@rollup/rollup-linux-arm-musleabihf/4.53.3: resolution: {integrity: sha512-vTNlKq+N6CK/8UktsrFuc+/7NlEYVxgaEgRXVUVK258Z5ymho29skzW1sutgYjqNnquGwVUObAaxae8rZ6YMhg==} cpu: [arm] @@ -4299,6 +4706,8 @@ packages: dev: false optional: true + /@rollup/rollup-linux-arm64-gnu/4.53.3: + resolution: {integrity: sha512-RGrFLWgMhSxRs/EWJMIFM1O5Mzuz3Xy3/mnxJp/5cVhZ2XoCAxJnmNsEyeMJtpK+wu0FJFWz+QF4mjCA7AUQ3w==} /@rollup/rollup-linux-arm64-gnu/4.53.3: resolution: {integrity: sha512-RGrFLWgMhSxRs/EWJMIFM1O5Mzuz3Xy3/mnxJp/5cVhZ2XoCAxJnmNsEyeMJtpK+wu0FJFWz+QF4mjCA7AUQ3w==} cpu: [arm64] @@ -4307,6 +4716,8 @@ packages: dev: false optional: true + /@rollup/rollup-linux-arm64-musl/4.53.3: + resolution: {integrity: sha512-kASyvfBEWYPEwe0Qv4nfu6pNkITLTb32p4yTgzFCocHnJLAHs+9LjUu9ONIhvfT/5lv4YS5muBHyuV84epBo/A==} /@rollup/rollup-linux-arm64-musl/4.53.3: resolution: {integrity: sha512-kASyvfBEWYPEwe0Qv4nfu6pNkITLTb32p4yTgzFCocHnJLAHs+9LjUu9ONIhvfT/5lv4YS5muBHyuV84epBo/A==} cpu: [arm64] @@ -4315,6 +4726,8 @@ packages: dev: false optional: true + /@rollup/rollup-linux-loong64-gnu/4.53.3: + resolution: {integrity: sha512-JiuKcp2teLJwQ7vkJ95EwESWkNRFJD7TQgYmCnrPtlu50b4XvT5MOmurWNrCj3IFdyjBQ5p9vnrX4JM6I8OE7g==} /@rollup/rollup-linux-loong64-gnu/4.53.3: resolution: {integrity: sha512-JiuKcp2teLJwQ7vkJ95EwESWkNRFJD7TQgYmCnrPtlu50b4XvT5MOmurWNrCj3IFdyjBQ5p9vnrX4JM6I8OE7g==} cpu: [loong64] @@ -4323,6 +4736,8 @@ packages: dev: false optional: true + /@rollup/rollup-linux-ppc64-gnu/4.53.3: + resolution: {integrity: sha512-EoGSa8nd6d3T7zLuqdojxC20oBfNT8nexBbB/rkxgKj5T5vhpAQKKnD+h3UkoMuTyXkP5jTjK/ccNRmQrPNDuw==} /@rollup/rollup-linux-ppc64-gnu/4.53.3: resolution: {integrity: sha512-EoGSa8nd6d3T7zLuqdojxC20oBfNT8nexBbB/rkxgKj5T5vhpAQKKnD+h3UkoMuTyXkP5jTjK/ccNRmQrPNDuw==} cpu: [ppc64] @@ -4331,6 +4746,8 @@ packages: dev: false optional: true + /@rollup/rollup-linux-riscv64-gnu/4.53.3: + resolution: {integrity: sha512-4s+Wped2IHXHPnAEbIB0YWBv7SDohqxobiiPA1FIWZpX+w9o2i4LezzH/NkFUl8LRci/8udci6cLq+jJQlh+0g==} /@rollup/rollup-linux-riscv64-gnu/4.53.3: resolution: {integrity: sha512-4s+Wped2IHXHPnAEbIB0YWBv7SDohqxobiiPA1FIWZpX+w9o2i4LezzH/NkFUl8LRci/8udci6cLq+jJQlh+0g==} cpu: [riscv64] @@ -4339,6 +4756,8 @@ packages: dev: false optional: true + /@rollup/rollup-linux-riscv64-musl/4.53.3: + resolution: {integrity: sha512-68k2g7+0vs2u9CxDt5ktXTngsxOQkSEV/xBbwlqYcUrAVh6P9EgMZvFsnHy4SEiUl46Xf0IObWVbMvPrr2gw8A==} /@rollup/rollup-linux-riscv64-musl/4.53.3: resolution: {integrity: sha512-68k2g7+0vs2u9CxDt5ktXTngsxOQkSEV/xBbwlqYcUrAVh6P9EgMZvFsnHy4SEiUl46Xf0IObWVbMvPrr2gw8A==} cpu: [riscv64] @@ -4347,6 +4766,8 @@ packages: dev: false optional: true + /@rollup/rollup-linux-s390x-gnu/4.53.3: + resolution: {integrity: sha512-VYsFMpULAz87ZW6BVYw3I6sWesGpsP9OPcyKe8ofdg9LHxSbRMd7zrVrr5xi/3kMZtpWL/wC+UIJWJYVX5uTKg==} /@rollup/rollup-linux-s390x-gnu/4.53.3: resolution: {integrity: sha512-VYsFMpULAz87ZW6BVYw3I6sWesGpsP9OPcyKe8ofdg9LHxSbRMd7zrVrr5xi/3kMZtpWL/wC+UIJWJYVX5uTKg==} cpu: [s390x] @@ -4355,6 +4776,8 @@ packages: dev: false optional: true + /@rollup/rollup-linux-x64-gnu/4.53.3: + resolution: {integrity: sha512-3EhFi1FU6YL8HTUJZ51imGJWEX//ajQPfqWLI3BQq4TlvHy4X0MOr5q3D2Zof/ka0d5FNdPwZXm3Yyib/UEd+w==} /@rollup/rollup-linux-x64-gnu/4.53.3: resolution: {integrity: sha512-3EhFi1FU6YL8HTUJZ51imGJWEX//ajQPfqWLI3BQq4TlvHy4X0MOr5q3D2Zof/ka0d5FNdPwZXm3Yyib/UEd+w==} cpu: [x64] @@ -4363,6 +4786,8 @@ packages: dev: false optional: true + /@rollup/rollup-linux-x64-musl/4.53.3: + resolution: {integrity: sha512-eoROhjcc6HbZCJr+tvVT8X4fW3/5g/WkGvvmwz/88sDtSJzO7r/blvoBDgISDiCjDRZmHpwud7h+6Q9JxFwq1Q==} /@rollup/rollup-linux-x64-musl/4.53.3: resolution: {integrity: sha512-eoROhjcc6HbZCJr+tvVT8X4fW3/5g/WkGvvmwz/88sDtSJzO7r/blvoBDgISDiCjDRZmHpwud7h+6Q9JxFwq1Q==} cpu: [x64] @@ -4371,6 +4796,8 @@ packages: dev: false optional: true + /@rollup/rollup-openharmony-arm64/4.53.3: + resolution: {integrity: sha512-OueLAWgrNSPGAdUdIjSWXw+u/02BRTcnfw9PN41D2vq/JSEPnJnVuBgw18VkN8wcd4fjUs+jFHVM4t9+kBSNLw==} /@rollup/rollup-openharmony-arm64/4.53.3: resolution: {integrity: sha512-OueLAWgrNSPGAdUdIjSWXw+u/02BRTcnfw9PN41D2vq/JSEPnJnVuBgw18VkN8wcd4fjUs+jFHVM4t9+kBSNLw==} cpu: [arm64] @@ -4379,6 +4806,8 @@ packages: dev: false optional: true + /@rollup/rollup-win32-arm64-msvc/4.53.3: + resolution: {integrity: sha512-GOFuKpsxR/whszbF/bzydebLiXIHSgsEUp6M0JI8dWvi+fFa1TD6YQa4aSZHtpmh2/uAlj/Dy+nmby3TJ3pkTw==} /@rollup/rollup-win32-arm64-msvc/4.53.3: resolution: {integrity: sha512-GOFuKpsxR/whszbF/bzydebLiXIHSgsEUp6M0JI8dWvi+fFa1TD6YQa4aSZHtpmh2/uAlj/Dy+nmby3TJ3pkTw==} cpu: [arm64] @@ -4387,6 +4816,8 @@ packages: dev: false optional: true + /@rollup/rollup-win32-ia32-msvc/4.53.3: + resolution: {integrity: sha512-iah+THLcBJdpfZ1TstDFbKNznlzoxa8fmnFYK4V67HvmuNYkVdAywJSoteUszvBQ9/HqN2+9AZghbajMsFT+oA==} /@rollup/rollup-win32-ia32-msvc/4.53.3: resolution: {integrity: sha512-iah+THLcBJdpfZ1TstDFbKNznlzoxa8fmnFYK4V67HvmuNYkVdAywJSoteUszvBQ9/HqN2+9AZghbajMsFT+oA==} cpu: [ia32] @@ -4395,6 +4826,8 @@ packages: dev: false optional: true + /@rollup/rollup-win32-x64-gnu/4.53.3: + resolution: {integrity: sha512-J9QDiOIZlZLdcot5NXEepDkstocktoVjkaKUtqzgzpt2yWjGlbYiKyp05rWwk4nypbYUNoFAztEgixoLaSETkg==} /@rollup/rollup-win32-x64-gnu/4.53.3: resolution: {integrity: sha512-J9QDiOIZlZLdcot5NXEepDkstocktoVjkaKUtqzgzpt2yWjGlbYiKyp05rWwk4nypbYUNoFAztEgixoLaSETkg==} cpu: [x64] @@ -4403,6 +4836,8 @@ packages: dev: false optional: true + /@rollup/rollup-win32-x64-msvc/4.53.3: + resolution: {integrity: sha512-UhTd8u31dXadv0MopwGgNOBpUVROFKWVQgAg5N1ESyCz8AuBcMqm4AuTjrwgQKGDfoFuz02EuMRHQIw/frmYKQ==} /@rollup/rollup-win32-x64-msvc/4.53.3: resolution: {integrity: sha512-UhTd8u31dXadv0MopwGgNOBpUVROFKWVQgAg5N1ESyCz8AuBcMqm4AuTjrwgQKGDfoFuz02EuMRHQIw/frmYKQ==} cpu: [x64] @@ -4477,10 +4912,13 @@ packages: resolution: {integrity: sha512-DE427ROAphMQzU4ENbliGYrBSYPXF+TtLg9S8vzeA+OF4ZKzoDdzfL8sxuMUGS/lgRhM6j1URSk9ghf7Xo1tyA==} dev: true + /@smithy/abort-controller/4.2.5: + resolution: {integrity: sha512-j7HwVkBw68YW8UmFRcjZOmssE77Rvk0GWAIN1oFBhsaovQmZWYCIcGa9/pwRB0ExI8Sk9MWNALTjftjHZea7VA==} /@smithy/abort-controller/4.2.5: resolution: {integrity: sha512-j7HwVkBw68YW8UmFRcjZOmssE77Rvk0GWAIN1oFBhsaovQmZWYCIcGa9/pwRB0ExI8Sk9MWNALTjftjHZea7VA==} engines: {node: '>=18.0.0'} dependencies: + '@smithy/types': 4.9.0 '@smithy/types': 4.9.0 tslib: 2.8.1 dev: true @@ -4500,15 +4938,21 @@ packages: tslib: 2.8.1 dev: true + /@smithy/config-resolver/4.4.3: + resolution: {integrity: sha512-ezHLe1tKLUxDJo2LHtDuEDyWXolw8WGOR92qb4bQdWq/zKenO5BvctZGrVJBK08zjezSk7bmbKFOXIVyChvDLw==} /@smithy/config-resolver/4.4.3: resolution: {integrity: sha512-ezHLe1tKLUxDJo2LHtDuEDyWXolw8WGOR92qb4bQdWq/zKenO5BvctZGrVJBK08zjezSk7bmbKFOXIVyChvDLw==} engines: {node: '>=18.0.0'} dependencies: + '@smithy/node-config-provider': 4.3.5 + '@smithy/types': 4.9.0 '@smithy/node-config-provider': 4.3.5 '@smithy/types': 4.9.0 '@smithy/util-config-provider': 4.2.0 '@smithy/util-endpoints': 3.2.5 '@smithy/util-middleware': 4.2.5 + '@smithy/util-endpoints': 3.2.5 + '@smithy/util-middleware': 4.2.5 tslib: 2.8.1 dev: true @@ -4516,6 +4960,9 @@ packages: resolution: {integrity: sha512-6gnIz3h+PEPQGDj8MnRSjDvKBah042jEoPgjFGJ4iJLBE78L4lY/n98x14XyPF4u3lN179Ub/ZKFY5za9GeLQw==} engines: {node: '>=18.0.0'} dependencies: + '@smithy/middleware-serde': 4.2.6 + '@smithy/protocol-http': 5.3.5 + '@smithy/types': 4.9.0 '@smithy/middleware-serde': 4.2.6 '@smithy/protocol-http': 5.3.5 '@smithy/types': 4.9.0 @@ -4523,15 +4970,23 @@ packages: '@smithy/util-body-length-browser': 4.2.0 '@smithy/util-middleware': 4.2.5 '@smithy/util-stream': 4.5.6 + '@smithy/util-middleware': 4.2.5 + '@smithy/util-stream': 4.5.6 '@smithy/util-utf8': 4.2.0 '@smithy/uuid': 1.1.0 tslib: 2.8.1 dev: true + /@smithy/credential-provider-imds/4.2.5: + resolution: {integrity: sha512-BZwotjoZWn9+36nimwm/OLIcVe+KYRwzMjfhd4QT7QxPm9WY0HiOV8t/Wlh+HVUif0SBVV7ksq8//hPaBC/okQ==} /@smithy/credential-provider-imds/4.2.5: resolution: {integrity: sha512-BZwotjoZWn9+36nimwm/OLIcVe+KYRwzMjfhd4QT7QxPm9WY0HiOV8t/Wlh+HVUif0SBVV7ksq8//hPaBC/okQ==} engines: {node: '>=18.0.0'} dependencies: + '@smithy/node-config-provider': 4.3.5 + '@smithy/property-provider': 4.2.5 + '@smithy/types': 4.9.0 + '@smithy/url-parser': 4.2.5 '@smithy/node-config-provider': 4.3.5 '@smithy/property-provider': 4.2.5 '@smithy/types': 4.9.0 @@ -4539,55 +4994,78 @@ packages: tslib: 2.8.1 dev: true + /@smithy/eventstream-codec/4.2.5: + resolution: {integrity: sha512-Ogt4Zi9hEbIP17oQMd68qYOHUzmH47UkK7q7Gl55iIm9oKt27MUGrC5JfpMroeHjdkOliOA4Qt3NQ1xMq/nrlA==} /@smithy/eventstream-codec/4.2.5: resolution: {integrity: sha512-Ogt4Zi9hEbIP17oQMd68qYOHUzmH47UkK7q7Gl55iIm9oKt27MUGrC5JfpMroeHjdkOliOA4Qt3NQ1xMq/nrlA==} engines: {node: '>=18.0.0'} dependencies: '@aws-crypto/crc32': 5.2.0 '@smithy/types': 4.9.0 + '@smithy/types': 4.9.0 '@smithy/util-hex-encoding': 4.2.0 tslib: 2.8.1 dev: true + /@smithy/eventstream-serde-browser/4.2.5: + resolution: {integrity: sha512-HohfmCQZjppVnKX2PnXlf47CW3j92Ki6T/vkAT2DhBR47e89pen3s4fIa7otGTtrVxmj7q+IhH0RnC5kpR8wtw==} /@smithy/eventstream-serde-browser/4.2.5: resolution: {integrity: sha512-HohfmCQZjppVnKX2PnXlf47CW3j92Ki6T/vkAT2DhBR47e89pen3s4fIa7otGTtrVxmj7q+IhH0RnC5kpR8wtw==} engines: {node: '>=18.0.0'} dependencies: + '@smithy/eventstream-serde-universal': 4.2.5 + '@smithy/types': 4.9.0 '@smithy/eventstream-serde-universal': 4.2.5 '@smithy/types': 4.9.0 tslib: 2.8.1 dev: true + /@smithy/eventstream-serde-config-resolver/4.3.5: + resolution: {integrity: sha512-ibjQjM7wEXtECiT6my1xfiMH9IcEczMOS6xiCQXoUIYSj5b1CpBbJ3VYbdwDy8Vcg5JHN7eFpOCGk8nyZAltNQ==} /@smithy/eventstream-serde-config-resolver/4.3.5: resolution: {integrity: sha512-ibjQjM7wEXtECiT6my1xfiMH9IcEczMOS6xiCQXoUIYSj5b1CpBbJ3VYbdwDy8Vcg5JHN7eFpOCGk8nyZAltNQ==} engines: {node: '>=18.0.0'} dependencies: + '@smithy/types': 4.9.0 '@smithy/types': 4.9.0 tslib: 2.8.1 dev: true + /@smithy/eventstream-serde-node/4.2.5: + resolution: {integrity: sha512-+elOuaYx6F2H6x1/5BQP5ugv12nfJl66GhxON8+dWVUEDJ9jah/A0tayVdkLRP0AeSac0inYkDz5qBFKfVp2Gg==} /@smithy/eventstream-serde-node/4.2.5: resolution: {integrity: sha512-+elOuaYx6F2H6x1/5BQP5ugv12nfJl66GhxON8+dWVUEDJ9jah/A0tayVdkLRP0AeSac0inYkDz5qBFKfVp2Gg==} engines: {node: '>=18.0.0'} dependencies: + '@smithy/eventstream-serde-universal': 4.2.5 + '@smithy/types': 4.9.0 '@smithy/eventstream-serde-universal': 4.2.5 '@smithy/types': 4.9.0 tslib: 2.8.1 dev: true + /@smithy/eventstream-serde-universal/4.2.5: + resolution: {integrity: sha512-G9WSqbST45bmIFaeNuP/EnC19Rhp54CcVdX9PDL1zyEB514WsDVXhlyihKlGXnRycmHNmVv88Bvvt4EYxWef/Q==} /@smithy/eventstream-serde-universal/4.2.5: resolution: {integrity: sha512-G9WSqbST45bmIFaeNuP/EnC19Rhp54CcVdX9PDL1zyEB514WsDVXhlyihKlGXnRycmHNmVv88Bvvt4EYxWef/Q==} engines: {node: '>=18.0.0'} dependencies: + '@smithy/eventstream-codec': 4.2.5 + '@smithy/types': 4.9.0 '@smithy/eventstream-codec': 4.2.5 '@smithy/types': 4.9.0 tslib: 2.8.1 dev: true + /@smithy/fetch-http-handler/5.3.6: + resolution: {integrity: sha512-3+RG3EA6BBJ/ofZUeTFJA7mHfSYrZtQIrDP9dI8Lf7X6Jbos2jptuLrAAteDiFVrmbEmLSuRG/bUKzfAXk7dhg==} /@smithy/fetch-http-handler/5.3.6: resolution: {integrity: sha512-3+RG3EA6BBJ/ofZUeTFJA7mHfSYrZtQIrDP9dI8Lf7X6Jbos2jptuLrAAteDiFVrmbEmLSuRG/bUKzfAXk7dhg==} engines: {node: '>=18.0.0'} dependencies: + '@smithy/protocol-http': 5.3.5 + '@smithy/querystring-builder': 4.2.5 + '@smithy/types': 4.9.0 '@smithy/protocol-http': 5.3.5 '@smithy/querystring-builder': 4.2.5 '@smithy/types': 4.9.0 @@ -4595,6 +5073,8 @@ packages: tslib: 2.8.1 dev: true + /@smithy/hash-blob-browser/4.2.6: + resolution: {integrity: sha512-8P//tA8DVPk+3XURk2rwcKgYwFvwGwmJH/wJqQiSKwXZtf/LiZK+hbUZmPj/9KzM+OVSwe4o85KTp5x9DUZTjw==} /@smithy/hash-blob-browser/4.2.6: resolution: {integrity: sha512-8P//tA8DVPk+3XURk2rwcKgYwFvwGwmJH/wJqQiSKwXZtf/LiZK+hbUZmPj/9KzM+OVSwe4o85KTp5x9DUZTjw==} engines: {node: '>=18.0.0'} @@ -4602,32 +5082,42 @@ packages: '@smithy/chunked-blob-reader': 5.2.0 '@smithy/chunked-blob-reader-native': 4.2.1 '@smithy/types': 4.9.0 + '@smithy/types': 4.9.0 tslib: 2.8.1 dev: true + /@smithy/hash-node/4.2.5: + resolution: {integrity: sha512-DpYX914YOfA3UDT9CN1BM787PcHfWRBB43fFGCYrZFUH0Jv+5t8yYl+Pd5PW4+QzoGEDvn5d5QIO4j2HyYZQSA==} /@smithy/hash-node/4.2.5: resolution: {integrity: sha512-DpYX914YOfA3UDT9CN1BM787PcHfWRBB43fFGCYrZFUH0Jv+5t8yYl+Pd5PW4+QzoGEDvn5d5QIO4j2HyYZQSA==} engines: {node: '>=18.0.0'} dependencies: + '@smithy/types': 4.9.0 '@smithy/types': 4.9.0 '@smithy/util-buffer-from': 4.2.0 '@smithy/util-utf8': 4.2.0 tslib: 2.8.1 dev: true + /@smithy/hash-stream-node/4.2.5: + resolution: {integrity: sha512-6+do24VnEyvWcGdHXomlpd0m8bfZePpUKBy7m311n+JuRwug8J4dCanJdTymx//8mi0nlkflZBvJe+dEO/O12Q==} /@smithy/hash-stream-node/4.2.5: resolution: {integrity: sha512-6+do24VnEyvWcGdHXomlpd0m8bfZePpUKBy7m311n+JuRwug8J4dCanJdTymx//8mi0nlkflZBvJe+dEO/O12Q==} engines: {node: '>=18.0.0'} dependencies: + '@smithy/types': 4.9.0 '@smithy/types': 4.9.0 '@smithy/util-utf8': 4.2.0 tslib: 2.8.1 dev: true + /@smithy/invalid-dependency/4.2.5: + resolution: {integrity: sha512-2L2erASEro1WC5nV+plwIMxrTXpvpfzl4e+Nre6vBVRR2HKeGGcvpJyyL3/PpiSg+cJG2KpTmZmq934Olb6e5A==} /@smithy/invalid-dependency/4.2.5: resolution: {integrity: sha512-2L2erASEro1WC5nV+plwIMxrTXpvpfzl4e+Nre6vBVRR2HKeGGcvpJyyL3/PpiSg+cJG2KpTmZmq934Olb6e5A==} engines: {node: '>=18.0.0'} dependencies: + '@smithy/types': 4.9.0 '@smithy/types': 4.9.0 tslib: 2.8.1 dev: true @@ -4646,19 +5136,26 @@ packages: tslib: 2.8.1 dev: true + /@smithy/md5-js/4.2.5: + resolution: {integrity: sha512-Bt6jpSTMWfjCtC0s79gZ/WZ1w90grfmopVOWqkI2ovhjpD5Q2XRXuecIPB9689L2+cCySMbaXDhBPU56FKNDNg==} /@smithy/md5-js/4.2.5: resolution: {integrity: sha512-Bt6jpSTMWfjCtC0s79gZ/WZ1w90grfmopVOWqkI2ovhjpD5Q2XRXuecIPB9689L2+cCySMbaXDhBPU56FKNDNg==} engines: {node: '>=18.0.0'} dependencies: + '@smithy/types': 4.9.0 '@smithy/types': 4.9.0 '@smithy/util-utf8': 4.2.0 tslib: 2.8.1 dev: true + /@smithy/middleware-content-length/4.2.5: + resolution: {integrity: sha512-Y/RabVa5vbl5FuHYV2vUCwvh/dqzrEY/K2yWPSqvhFUwIY0atLqO4TienjBXakoy4zrKAMCZwg+YEqmH7jaN7A==} /@smithy/middleware-content-length/4.2.5: resolution: {integrity: sha512-Y/RabVa5vbl5FuHYV2vUCwvh/dqzrEY/K2yWPSqvhFUwIY0atLqO4TienjBXakoy4zrKAMCZwg+YEqmH7jaN7A==} engines: {node: '>=18.0.0'} dependencies: + '@smithy/protocol-http': 5.3.5 + '@smithy/types': 4.9.0 '@smithy/protocol-http': 5.3.5 '@smithy/types': 4.9.0 tslib: 2.8.1 @@ -4693,37 +5190,55 @@ packages: tslib: 2.8.1 dev: true + /@smithy/middleware-serde/4.2.6: + resolution: {integrity: sha512-VkLoE/z7e2g8pirwisLz8XJWedUSY8my/qrp81VmAdyrhi94T+riBfwP+AOEEFR9rFTSonC/5D2eWNmFabHyGQ==} /@smithy/middleware-serde/4.2.6: resolution: {integrity: sha512-VkLoE/z7e2g8pirwisLz8XJWedUSY8my/qrp81VmAdyrhi94T+riBfwP+AOEEFR9rFTSonC/5D2eWNmFabHyGQ==} engines: {node: '>=18.0.0'} dependencies: + '@smithy/protocol-http': 5.3.5 + '@smithy/types': 4.9.0 '@smithy/protocol-http': 5.3.5 '@smithy/types': 4.9.0 tslib: 2.8.1 dev: true + /@smithy/middleware-stack/4.2.5: + resolution: {integrity: sha512-bYrutc+neOyWxtZdbB2USbQttZN0mXaOyYLIsaTbJhFsfpXyGWUxJpEuO1rJ8IIJm2qH4+xJT0mxUSsEDTYwdQ==} /@smithy/middleware-stack/4.2.5: resolution: {integrity: sha512-bYrutc+neOyWxtZdbB2USbQttZN0mXaOyYLIsaTbJhFsfpXyGWUxJpEuO1rJ8IIJm2qH4+xJT0mxUSsEDTYwdQ==} engines: {node: '>=18.0.0'} dependencies: + '@smithy/types': 4.9.0 '@smithy/types': 4.9.0 tslib: 2.8.1 dev: true + /@smithy/node-config-provider/4.3.5: + resolution: {integrity: sha512-UTurh1C4qkVCtqggI36DGbLB2Kv8UlcFdMXDcWMbqVY2uRg0XmT9Pb4Vj6oSQ34eizO1fvR0RnFV4Axw4IrrAg==} /@smithy/node-config-provider/4.3.5: resolution: {integrity: sha512-UTurh1C4qkVCtqggI36DGbLB2Kv8UlcFdMXDcWMbqVY2uRg0XmT9Pb4Vj6oSQ34eizO1fvR0RnFV4Axw4IrrAg==} engines: {node: '>=18.0.0'} dependencies: + '@smithy/property-provider': 4.2.5 + '@smithy/shared-ini-file-loader': 4.4.0 + '@smithy/types': 4.9.0 '@smithy/property-provider': 4.2.5 '@smithy/shared-ini-file-loader': 4.4.0 '@smithy/types': 4.9.0 tslib: 2.8.1 dev: true + /@smithy/node-http-handler/4.4.5: + resolution: {integrity: sha512-CMnzM9R2WqlqXQGtIlsHMEZfXKJVTIrqCNoSd/QpAyp+Dw0a1Vps13l6ma1fH8g7zSPNsA59B/kWgeylFuA/lw==} /@smithy/node-http-handler/4.4.5: resolution: {integrity: sha512-CMnzM9R2WqlqXQGtIlsHMEZfXKJVTIrqCNoSd/QpAyp+Dw0a1Vps13l6ma1fH8g7zSPNsA59B/kWgeylFuA/lw==} engines: {node: '>=18.0.0'} dependencies: + '@smithy/abort-controller': 4.2.5 + '@smithy/protocol-http': 5.3.5 + '@smithy/querystring-builder': 4.2.5 + '@smithy/types': 4.9.0 '@smithy/abort-controller': 4.2.5 '@smithy/protocol-http': 5.3.5 '@smithy/querystring-builder': 4.2.5 @@ -4731,54 +5246,74 @@ packages: tslib: 2.8.1 dev: true + /@smithy/property-provider/4.2.5: + resolution: {integrity: sha512-8iLN1XSE1rl4MuxvQ+5OSk/Zb5El7NJZ1td6Tn+8dQQHIjp59Lwl6bd0+nzw6SKm2wSSriH2v/I9LPzUic7EOg==} /@smithy/property-provider/4.2.5: resolution: {integrity: sha512-8iLN1XSE1rl4MuxvQ+5OSk/Zb5El7NJZ1td6Tn+8dQQHIjp59Lwl6bd0+nzw6SKm2wSSriH2v/I9LPzUic7EOg==} engines: {node: '>=18.0.0'} dependencies: + '@smithy/types': 4.9.0 '@smithy/types': 4.9.0 tslib: 2.8.1 dev: true + /@smithy/protocol-http/5.3.5: + resolution: {integrity: sha512-RlaL+sA0LNMp03bf7XPbFmT5gN+w3besXSWMkA8rcmxLSVfiEXElQi4O2IWwPfxzcHkxqrwBFMbngB8yx/RvaQ==} /@smithy/protocol-http/5.3.5: resolution: {integrity: sha512-RlaL+sA0LNMp03bf7XPbFmT5gN+w3besXSWMkA8rcmxLSVfiEXElQi4O2IWwPfxzcHkxqrwBFMbngB8yx/RvaQ==} engines: {node: '>=18.0.0'} dependencies: + '@smithy/types': 4.9.0 '@smithy/types': 4.9.0 tslib: 2.8.1 dev: true + /@smithy/querystring-builder/4.2.5: + resolution: {integrity: sha512-y98otMI1saoajeik2kLfGyRp11e5U/iJYH/wLCh3aTV/XutbGT9nziKGkgCaMD1ghK7p6htHMm6b6scl9JRUWg==} /@smithy/querystring-builder/4.2.5: resolution: {integrity: sha512-y98otMI1saoajeik2kLfGyRp11e5U/iJYH/wLCh3aTV/XutbGT9nziKGkgCaMD1ghK7p6htHMm6b6scl9JRUWg==} engines: {node: '>=18.0.0'} dependencies: + '@smithy/types': 4.9.0 '@smithy/types': 4.9.0 '@smithy/util-uri-escape': 4.2.0 tslib: 2.8.1 dev: true + /@smithy/querystring-parser/4.2.5: + resolution: {integrity: sha512-031WCTdPYgiQRYNPXznHXof2YM0GwL6SeaSyTH/P72M1Vz73TvCNH2Nq8Iu2IEPq9QP2yx0/nrw5YmSeAi/AjQ==} /@smithy/querystring-parser/4.2.5: resolution: {integrity: sha512-031WCTdPYgiQRYNPXznHXof2YM0GwL6SeaSyTH/P72M1Vz73TvCNH2Nq8Iu2IEPq9QP2yx0/nrw5YmSeAi/AjQ==} engines: {node: '>=18.0.0'} dependencies: + '@smithy/types': 4.9.0 '@smithy/types': 4.9.0 tslib: 2.8.1 dev: true + /@smithy/service-error-classification/4.2.5: + resolution: {integrity: sha512-8fEvK+WPE3wUAcDvqDQG1Vk3ANLR8Px979te96m84CbKAjBVf25rPYSzb4xU4hlTyho7VhOGnh5i62D/JVF0JQ==} /@smithy/service-error-classification/4.2.5: resolution: {integrity: sha512-8fEvK+WPE3wUAcDvqDQG1Vk3ANLR8Px979te96m84CbKAjBVf25rPYSzb4xU4hlTyho7VhOGnh5i62D/JVF0JQ==} engines: {node: '>=18.0.0'} dependencies: '@smithy/types': 4.9.0 + '@smithy/types': 4.9.0 dev: true + /@smithy/shared-ini-file-loader/4.4.0: + resolution: {integrity: sha512-5WmZ5+kJgJDjwXXIzr1vDTG+RhF9wzSODQBfkrQ2VVkYALKGvZX1lgVSxEkgicSAFnFhPj5rudJV0zoinqS0bA==} /@smithy/shared-ini-file-loader/4.4.0: resolution: {integrity: sha512-5WmZ5+kJgJDjwXXIzr1vDTG+RhF9wzSODQBfkrQ2VVkYALKGvZX1lgVSxEkgicSAFnFhPj5rudJV0zoinqS0bA==} engines: {node: '>=18.0.0'} dependencies: + '@smithy/types': 4.9.0 '@smithy/types': 4.9.0 tslib: 2.8.1 dev: true + /@smithy/signature-v4/5.3.5: + resolution: {integrity: sha512-xSUfMu1FT7ccfSXkoLl/QRQBi2rOvi3tiBZU2Tdy3I6cgvZ6SEi9QNey+lqps/sJRnogIS+lq+B1gxxbra2a/w==} /@smithy/signature-v4/5.3.5: resolution: {integrity: sha512-xSUfMu1FT7ccfSXkoLl/QRQBi2rOvi3tiBZU2Tdy3I6cgvZ6SEi9QNey+lqps/sJRnogIS+lq+B1gxxbra2a/w==} engines: {node: '>=18.0.0'} @@ -4786,8 +5321,11 @@ packages: '@smithy/is-array-buffer': 4.2.0 '@smithy/protocol-http': 5.3.5 '@smithy/types': 4.9.0 + '@smithy/protocol-http': 5.3.5 + '@smithy/types': 4.9.0 '@smithy/util-hex-encoding': 4.2.0 '@smithy/util-middleware': 4.2.5 + '@smithy/util-middleware': 4.2.5 '@smithy/util-uri-escape': 4.2.0 '@smithy/util-utf8': 4.2.0 tslib: 2.8.1 @@ -4806,6 +5344,8 @@ packages: tslib: 2.8.1 dev: true + /@smithy/types/4.9.0: + resolution: {integrity: sha512-MvUbdnXDTwykR8cB1WZvNNwqoWVaTRA0RLlLmf/cIFNMM2cKWz01X4Ly6SMC4Kks30r8tT3Cty0jmeWfiuyHTA==} /@smithy/types/4.9.0: resolution: {integrity: sha512-MvUbdnXDTwykR8cB1WZvNNwqoWVaTRA0RLlLmf/cIFNMM2cKWz01X4Ly6SMC4Kks30r8tT3Cty0jmeWfiuyHTA==} engines: {node: '>=18.0.0'} @@ -4813,10 +5353,14 @@ packages: tslib: 2.8.1 dev: true + /@smithy/url-parser/4.2.5: + resolution: {integrity: sha512-VaxMGsilqFnK1CeBX+LXnSuaMx4sTL/6znSZh2829txWieazdVxr54HmiyTsIbpOTLcf5nYpq9lpzmwRdxj6rQ==} /@smithy/url-parser/4.2.5: resolution: {integrity: sha512-VaxMGsilqFnK1CeBX+LXnSuaMx4sTL/6znSZh2829txWieazdVxr54HmiyTsIbpOTLcf5nYpq9lpzmwRdxj6rQ==} engines: {node: '>=18.0.0'} dependencies: + '@smithy/querystring-parser': 4.2.5 + '@smithy/types': 4.9.0 '@smithy/querystring-parser': 4.2.5 '@smithy/types': 4.9.0 tslib: 2.8.1 @@ -4891,10 +5435,14 @@ packages: tslib: 2.8.1 dev: true + /@smithy/util-endpoints/3.2.5: + resolution: {integrity: sha512-3O63AAWu2cSNQZp+ayl9I3NapW1p1rR5mlVHcF6hAB1dPZUQFfRPYtplWX/3xrzWthPGj5FqB12taJJCfH6s8A==} /@smithy/util-endpoints/3.2.5: resolution: {integrity: sha512-3O63AAWu2cSNQZp+ayl9I3NapW1p1rR5mlVHcF6hAB1dPZUQFfRPYtplWX/3xrzWthPGj5FqB12taJJCfH6s8A==} engines: {node: '>=18.0.0'} dependencies: + '@smithy/node-config-provider': 4.3.5 + '@smithy/types': 4.9.0 '@smithy/node-config-provider': 4.3.5 '@smithy/types': 4.9.0 tslib: 2.8.1 @@ -4907,27 +5455,39 @@ packages: tslib: 2.8.1 dev: true + /@smithy/util-middleware/4.2.5: + resolution: {integrity: sha512-6Y3+rvBF7+PZOc40ybeZMcGln6xJGVeY60E7jy9Mv5iKpMJpHgRE6dKy9ScsVxvfAYuEX4Q9a65DQX90KaQ3bA==} /@smithy/util-middleware/4.2.5: resolution: {integrity: sha512-6Y3+rvBF7+PZOc40ybeZMcGln6xJGVeY60E7jy9Mv5iKpMJpHgRE6dKy9ScsVxvfAYuEX4Q9a65DQX90KaQ3bA==} engines: {node: '>=18.0.0'} dependencies: + '@smithy/types': 4.9.0 '@smithy/types': 4.9.0 tslib: 2.8.1 dev: true + /@smithy/util-retry/4.2.5: + resolution: {integrity: sha512-GBj3+EZBbN4NAqJ/7pAhsXdfzdlznOh8PydUijy6FpNIMnHPSMO2/rP4HKu+UFeikJxShERk528oy7GT79YiJg==} /@smithy/util-retry/4.2.5: resolution: {integrity: sha512-GBj3+EZBbN4NAqJ/7pAhsXdfzdlznOh8PydUijy6FpNIMnHPSMO2/rP4HKu+UFeikJxShERk528oy7GT79YiJg==} engines: {node: '>=18.0.0'} dependencies: + '@smithy/service-error-classification': 4.2.5 + '@smithy/types': 4.9.0 '@smithy/service-error-classification': 4.2.5 '@smithy/types': 4.9.0 tslib: 2.8.1 dev: true + /@smithy/util-stream/4.5.6: + resolution: {integrity: sha512-qWw/UM59TiaFrPevefOZ8CNBKbYEP6wBAIlLqxn3VAIo9rgnTNc4ASbVrqDmhuwI87usnjhdQrxodzAGFFzbRQ==} /@smithy/util-stream/4.5.6: resolution: {integrity: sha512-qWw/UM59TiaFrPevefOZ8CNBKbYEP6wBAIlLqxn3VAIo9rgnTNc4ASbVrqDmhuwI87usnjhdQrxodzAGFFzbRQ==} engines: {node: '>=18.0.0'} dependencies: + '@smithy/fetch-http-handler': 5.3.6 + '@smithy/node-http-handler': 4.4.5 + '@smithy/types': 4.9.0 '@smithy/fetch-http-handler': 5.3.6 '@smithy/node-http-handler': 4.4.5 '@smithy/types': 4.9.0 @@ -4961,10 +5521,14 @@ packages: tslib: 2.8.1 dev: true + /@smithy/util-waiter/4.2.5: + resolution: {integrity: sha512-Dbun99A3InifQdIrsXZ+QLcC0PGBPAdrl4cj1mTgJvyc9N2zf7QSxg8TBkzsCmGJdE3TLbO9ycwpY0EkWahQ/g==} /@smithy/util-waiter/4.2.5: resolution: {integrity: sha512-Dbun99A3InifQdIrsXZ+QLcC0PGBPAdrl4cj1mTgJvyc9N2zf7QSxg8TBkzsCmGJdE3TLbO9ycwpY0EkWahQ/g==} engines: {node: '>=18.0.0'} dependencies: + '@smithy/abort-controller': 4.2.5 + '@smithy/types': 4.9.0 '@smithy/abort-controller': 4.2.5 '@smithy/types': 4.9.0 tslib: 2.8.1 @@ -4980,9 +5544,9 @@ packages: /@so-ric/colorspace/1.1.6: resolution: {integrity: sha512-/KiKkpHNOBgkFJwu9sh48LkHSMYGyuTcSFK/qMBdnOAlrRJzRSXAOFB5qwzaVQuDl8wAvHVMkaASQDReTahxuw==} dependencies: + color: 5.0.3 color: 5.0.3 text-hex: 1.0.0 - dev: false /@stylistic/eslint-plugin/3.1.0_avq3eyf5kaj6ssrwo7fvkrwnji: resolution: {integrity: sha512-pA6VOrOqk0+S8toJYhQGv2MWpQQR0QpeUo9AhNkC49Y26nxBQ/nH1rta9bUU1rPw2fJ1zZEMV5oCX5AazT7J2g==} @@ -5052,6 +5616,8 @@ packages: - typescript dev: true + /@stylistic/eslint-plugin/5.6.1_eslint@7.32.0: + resolution: {integrity: sha512-JCs+MqoXfXrRPGbGmho/zGS/jMcn3ieKl/A8YImqib76C8kjgZwq5uUFzc30lJkMvcchuRn6/v8IApLxli3Jyw==} /@stylistic/eslint-plugin/5.6.1_eslint@7.32.0: resolution: {integrity: sha512-JCs+MqoXfXrRPGbGmho/zGS/jMcn3ieKl/A8YImqib76C8kjgZwq5uUFzc30lJkMvcchuRn6/v8IApLxli3Jyw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -5067,6 +5633,8 @@ packages: picomatch: 4.0.3 dev: true + /@stylistic/eslint-plugin/5.6.1_eslint@8.57.1: + resolution: {integrity: sha512-JCs+MqoXfXrRPGbGmho/zGS/jMcn3ieKl/A8YImqib76C8kjgZwq5uUFzc30lJkMvcchuRn6/v8IApLxli3Jyw==} /@stylistic/eslint-plugin/5.6.1_eslint@8.57.1: resolution: {integrity: sha512-JCs+MqoXfXrRPGbGmho/zGS/jMcn3ieKl/A8YImqib76C8kjgZwq5uUFzc30lJkMvcchuRn6/v8IApLxli3Jyw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -5269,6 +5837,8 @@ packages: resolution: {integrity: sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==} dev: true + /@types/lodash/4.17.21: + resolution: {integrity: sha512-FOvQ0YPD5NOfPgMzJihoT+Za5pdkDJWcbpuj1DjaKZIr/gxodQjY/uWEFlTNqW2ugXHUiL8lRQgw63dzKHZdeQ==} /@types/lodash/4.17.21: resolution: {integrity: sha512-FOvQ0YPD5NOfPgMzJihoT+Za5pdkDJWcbpuj1DjaKZIr/gxodQjY/uWEFlTNqW2ugXHUiL8lRQgw63dzKHZdeQ==} @@ -5420,7 +5990,6 @@ packages: /@types/triple-beam/1.3.5: resolution: {integrity: sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==} - dev: false /@types/uuid/9.0.8: resolution: {integrity: sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==} @@ -5434,12 +6003,16 @@ packages: resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==} dev: true + /@types/yargs/15.0.20: + resolution: {integrity: sha512-KIkX+/GgfFitlASYCGoSF+T4XRXhOubJLhkLVtSfsRTe9jWMmuM2g28zQ41BtPTG7TRBb2xHW+LCNVE9QR/vsg==} /@types/yargs/15.0.20: resolution: {integrity: sha512-KIkX+/GgfFitlASYCGoSF+T4XRXhOubJLhkLVtSfsRTe9jWMmuM2g28zQ41BtPTG7TRBb2xHW+LCNVE9QR/vsg==} dependencies: '@types/yargs-parser': 21.0.3 dev: true + /@types/yargs/17.0.35: + resolution: {integrity: sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==} /@types/yargs/17.0.35: resolution: {integrity: sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==} dependencies: @@ -5569,11 +6142,9 @@ packages: '@typescript-eslint/utils': 8.48.0_avq3eyf5kaj6ssrwo7fvkrwnji '@typescript-eslint/visitor-keys': 8.48.0 eslint: 8.57.1 - graphemer: 1.4.0 ignore: 7.0.5 natural-compare: 1.4.0 - ts-api-utils: 2.1.0_typescript@4.9.5 - typescript: 4.9.5 + ts-api-utils: 2.1.0 transitivePeerDependencies: - supports-color dev: true @@ -5621,6 +6192,8 @@ packages: natural-compare: 1.4.0 ts-api-utils: 2.1.0_typescript@5.9.3 typescript: 5.9.3 + ts-api-utils: 2.1.0_typescript@5.9.3 + typescript: 5.9.3 transitivePeerDependencies: - supports-color dev: true @@ -6108,6 +6681,7 @@ packages: minimatch: 9.0.5 semver: 7.7.3 tinyglobby: 0.2.15 + tinyglobby: 0.2.15 ts-api-utils: 2.1.0 transitivePeerDependencies: - supports-color @@ -6127,6 +6701,7 @@ packages: minimatch: 9.0.5 semver: 7.7.3 tinyglobby: 0.2.15 + tinyglobby: 0.2.15 ts-api-utils: 2.1.0_typescript@4.9.5 typescript: 4.9.5 transitivePeerDependencies: @@ -6147,6 +6722,7 @@ packages: minimatch: 9.0.5 semver: 7.7.3 tinyglobby: 0.2.15 + tinyglobby: 0.2.15 ts-api-utils: 2.1.0_typescript@5.9.3 typescript: 5.9.3 transitivePeerDependencies: @@ -6598,7 +7174,6 @@ packages: optional: true dependencies: ajv: 8.17.1 - dev: false /ajv/6.12.6: resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} @@ -6632,7 +7207,6 @@ packages: /ansi-escapes/3.2.0: resolution: {integrity: sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==} engines: {node: '>=4'} - dev: false /ansi-escapes/4.3.2: resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} @@ -6648,7 +7222,6 @@ packages: /ansi-regex/3.0.1: resolution: {integrity: sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==} engines: {node: '>=4'} - dev: false /ansi-regex/5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} @@ -6657,6 +7230,7 @@ packages: /ansi-regex/6.2.2: resolution: {integrity: sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==} engines: {node: '>=12'} + dev: true /ansi-styles/2.2.1: resolution: {integrity: sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==} @@ -6683,6 +7257,7 @@ packages: /ansi-styles/6.2.3: resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} engines: {node: '>=12'} + dev: true /ansicolors/0.3.2: resolution: {integrity: sha512-QXu7BPrP29VllRxH8GwB7x5iX5qWKAAMLqKQGWTeLWVlNHNOpVMJ91dsxQAIWXpjuW5wqvxu3Jd/nRjrJ+0pqg==} @@ -6869,7 +7444,6 @@ packages: object-is: 1.1.6 object.assign: 4.1.7 util: 0.12.5 - dev: false /assertion-error/1.1.0: resolution: {integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==} @@ -6909,7 +7483,6 @@ packages: /atomically/1.7.0: resolution: {integrity: sha512-Xcz9l0z7y9yQ9rdDaxlmaI4uJHf/T8g9hOEzJcsEqX2SjCj4J20uK7+ldkDHMbpJDK76wF7xEIgxc/vSlsfw5w==} engines: {node: '>=10.12.0'} - dev: false /available-typed-arrays/1.0.7: resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} @@ -6917,20 +7490,26 @@ packages: dependencies: possible-typed-array-names: 1.1.0 + /axios/1.13.2: + resolution: {integrity: sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA==} /axios/1.13.2: resolution: {integrity: sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA==} dependencies: follow-redirects: 1.15.11 form-data: 4.0.5 + form-data: 4.0.5 proxy-from-env: 1.1.0 transitivePeerDependencies: - debug + /axios/1.13.2_debug@4.4.3: + resolution: {integrity: sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA==} /axios/1.13.2_debug@4.4.3: resolution: {integrity: sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA==} dependencies: follow-redirects: 1.15.11_debug@4.4.3 form-data: 4.0.5 + form-data: 4.0.5 proxy-from-env: 1.1.0 transitivePeerDependencies: - debug @@ -7016,7 +7595,6 @@ packages: /base64-js/1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} - dev: false /baseline-browser-mapping/2.8.31: resolution: {integrity: sha512-a28v2eWrrRWPpJSzxc+mKwm0ZtVx/G8SepdQZDArnXYU/XS+IF6mp8aB/4E+hH1tyGCoDo3KlUCdlSxGDsRkAw==} @@ -7045,13 +7623,12 @@ packages: buffer: 5.7.1 inherits: 2.0.4 readable-stream: 3.6.2 - dev: false /bluebird/3.7.2: resolution: {integrity: sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==} - /body-parser/1.20.3: - resolution: {integrity: sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==} + /body-parser/1.20.4: + resolution: {integrity: sha512-ZTgYYLMOXY9qKU/57FAo8F+HA2dGX7bqGc71txDRC1rS4frdFI5R7NhluHxH6M0YItAP0sHB4uqAOcYKxO6uGA==} engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} dependencies: bytes: 3.1.2 @@ -7059,11 +7636,11 @@ packages: debug: 2.6.9 depd: 2.0.0 destroy: 1.2.0 - http-errors: 2.0.0 + http-errors: 2.0.1 iconv-lite: 0.4.24 on-finished: 2.4.1 - qs: 6.13.0 - raw-body: 2.5.2 + qs: 6.14.0 + raw-body: 2.5.3 type-is: 1.6.18 unpipe: 1.0.0 transitivePeerDependencies: @@ -7097,7 +7674,6 @@ packages: resolution: {integrity: sha512-yjxDAYyK/pBvws9H4xKYpLDpYKEH6CzrBPAuXq3x18I+c/2MkVtT3qAr7Oloi6Dss9qNhPVueAAVU1CSeNDIXw==} dependencies: wcwidth: 1.0.1 - dev: false /browser-stdout/1.3.1: resolution: {integrity: sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==} @@ -7136,14 +7712,12 @@ packages: dependencies: base64-js: 1.5.1 ieee754: 1.2.1 - dev: false /buffer/6.0.3: resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} dependencies: base64-js: 1.5.1 ieee754: 1.2.1 - dev: false /builtin-modules/3.3.0: resolution: {integrity: sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==} @@ -7336,11 +7910,9 @@ packages: /chardet/0.4.2: resolution: {integrity: sha512-j/Toj7f1z98Hh2cYo2BVr85EpIRWqUi7rtRSGxh/cqUjqrnJe9l9UE7IUGd2vQ2p+kSHLkSzObQPZPLUC6TQwg==} - dev: false /chardet/0.7.0: resolution: {integrity: sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==} - dev: false /chardet/2.1.1: resolution: {integrity: sha512-PsezH1rqdV9VvyNhxxOW32/d75r01NY7TQCmOqomRo15ZSOKbpTFVsfjghxo6JloQUCGnH4k1LGu0R4yCLlWQQ==} @@ -7408,7 +7980,6 @@ packages: engines: {node: '>=4'} dependencies: restore-cursor: 2.0.0 - dev: false /cli-cursor/3.1.0: resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==} @@ -7429,7 +8000,6 @@ packages: engines: {node: '>=4'} dependencies: string-width: 4.2.3 - dev: false /cli-spinners/2.9.2: resolution: {integrity: sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==} @@ -7440,7 +8010,6 @@ packages: engines: {node: '>= 0.2.0'} dependencies: colors: 1.0.3 - dev: false /cli-truncate/0.2.1: resolution: {integrity: sha512-f4r4yJnbT++qUPI9NR4XLDLq41gQ+uqnPItWG0F5ZkehuNiTTa3EY0S4AqTSUOeJ7/zU41oWPQSNkW5BqPL9bg==} @@ -7452,12 +8021,10 @@ packages: /cli-width/2.2.1: resolution: {integrity: sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw==} - dev: false /cli-width/3.0.0: resolution: {integrity: sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==} engines: {node: '>= 10'} - dev: false /cli-width/4.1.0: resolution: {integrity: sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==} @@ -7489,7 +8056,6 @@ packages: /clone/1.0.4: resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==} engines: {node: '>=0.8'} - dev: false /co/4.6.0: resolution: {integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==} @@ -7524,6 +8090,8 @@ packages: dependencies: color-name: 1.1.4 + /color-convert/3.1.3: + resolution: {integrity: sha512-fasDH2ont2GqF5HpyO4w0+BcewlhHEZOFn9c1ckZdHpJ56Qb7MHhH/IcJZbBGgvdtwdwNbLvxiBEdg336iA9Sg==} /color-convert/3.1.3: resolution: {integrity: sha512-fasDH2ont2GqF5HpyO4w0+BcewlhHEZOFn9c1ckZdHpJ56Qb7MHhH/IcJZbBGgvdtwdwNbLvxiBEdg336iA9Sg==} engines: {node: '>=14.6'} @@ -7537,11 +8105,14 @@ packages: /color-name/1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + /color-name/2.1.0: + resolution: {integrity: sha512-1bPaDNFm0axzE4MEAzKPuqKWeRaT43U/hyxKPBdqTfmPF+d6n7FSoTFxLVULUJOmiLp01KjhIPPH+HrXZJN4Rg==} /color-name/2.1.0: resolution: {integrity: sha512-1bPaDNFm0axzE4MEAzKPuqKWeRaT43U/hyxKPBdqTfmPF+d6n7FSoTFxLVULUJOmiLp01KjhIPPH+HrXZJN4Rg==} engines: {node: '>=12.20'} - dev: false + /color-string/2.1.4: + resolution: {integrity: sha512-Bb6Cq8oq0IjDOe8wJmi4JeNn763Xs9cfrBcaylK1tPypWzyoy2G3l90v9k64kjphl/ZJjPIShFztenRomi8WTg==} /color-string/2.1.4: resolution: {integrity: sha512-Bb6Cq8oq0IjDOe8wJmi4JeNn763Xs9cfrBcaylK1tPypWzyoy2G3l90v9k64kjphl/ZJjPIShFztenRomi8WTg==} engines: {node: '>=18'} @@ -7549,6 +8120,8 @@ packages: color-name: 2.1.0 dev: false + /color/5.0.3: + resolution: {integrity: sha512-ezmVcLR3xAVp8kYOm4GS45ZLLgIE6SPAFoduLr6hTDajwb3KZ2F46gulK3XpcwRFb5KKGCSezCBAY4Dw4HsyXA==} /color/5.0.3: resolution: {integrity: sha512-ezmVcLR3xAVp8kYOm4GS45ZLLgIE6SPAFoduLr6hTDajwb3KZ2F46gulK3XpcwRFb5KKGCSezCBAY4Dw4HsyXA==} engines: {node: '>=18'} @@ -7560,7 +8133,6 @@ packages: /colors/1.0.3: resolution: {integrity: sha512-pFGrxThWcWQ2MsAz6RtgeWe4NK2kUE1WfsrvvlctdII745EW9I0yflqhe7++M5LEc7bV2c/9/5zc8sFcpL0Drw==} engines: {node: '>=0.1.90'} - dev: false /combined-stream/1.0.8: resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} @@ -7640,7 +8212,6 @@ packages: onetime: 5.1.2 pkg-up: 3.1.0 semver: 7.7.3 - dev: false /config-chain/1.1.13: resolution: {integrity: sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==} @@ -7678,15 +8249,14 @@ packages: resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} engines: {node: '>= 0.6'} - /contentstack/3.26.2: - resolution: {integrity: sha512-q6JVBxAcQRuvpwzrT3XbsuCei/AKZXD4nK4fuc1AYg6PE6Rjnq1v5S5PjSFVCk7N4JCct7OQDQs0xmOSXyRyyQ==} + /contentstack/3.26.3: + resolution: {integrity: sha512-mN1/Z8YV1HoIw03oEgnoHlaX/ueOLZH4unbf3zJt6uOJSO51gDFfOQEnKsTfUfWkyks9xUmED3WzPMxpnxdqcQ==} engines: {node: '>= 10.14.2'} dependencies: '@contentstack/utils': 1.6.2 es6-promise: 4.2.8 husky: 9.1.7 localStorage: 1.0.4 - dev: false /convert-source-map/1.9.0: resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==} @@ -7696,15 +8266,17 @@ packages: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} dev: true - /cookie-signature/1.0.6: - resolution: {integrity: sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==} + /cookie-signature/1.0.7: + resolution: {integrity: sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==} dev: false - /cookie/0.7.1: - resolution: {integrity: sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==} + /cookie/0.7.2: + resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} engines: {node: '>= 0.6'} dev: false + /core-js-compat/3.47.0: + resolution: {integrity: sha512-IGfuznZ/n7Kp9+nypamBhvwdwLsW6KC8IOaURw2doAK5e98AG3acVLdh0woOnEqCfUtS+Vu882JE4k/DAm3ItQ==} /core-js-compat/3.47.0: resolution: {integrity: sha512-IGfuznZ/n7Kp9+nypamBhvwdwLsW6KC8IOaURw2doAK5e98AG3acVLdh0woOnEqCfUtS+Vu882JE4k/DAm3ItQ==} dependencies: @@ -7764,23 +8336,20 @@ packages: path-key: 3.1.1 shebang-command: 2.0.0 which: 2.0.2 + dev: true /crypto-random-string/2.0.0: resolution: {integrity: sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==} engines: {node: '>=8'} - dev: false /csv-generate/3.4.3: resolution: {integrity: sha512-w/T+rqR0vwvHqWs/1ZyMDWtHHSJaN06klRqJXBEpDJaM/+dZkso0OKh1VcuuYvK3XM53KysVNq8Ko/epCK8wOw==} - dev: false /csv-parse/4.16.3: resolution: {integrity: sha512-cO1I/zmz4w2dcKHVvpCr7JVRu8/FymG5OEpmvsZYlccYolPBLoVGKUHgNoc4ZGkFeFlWGEDmMyBM+TTqRdW/wg==} - dev: false /csv-stringify/5.6.5: resolution: {integrity: sha512-PjiQ659aQ+fUTQqSrd1XEDnOr52jh30RBurfzkscaE2tPaFsDH5wOAHJiw8XAHphRknCwMUE9KRayc4K/NbO8A==} - dev: false /csv/5.5.3: resolution: {integrity: sha512-QTaY0XjjhTQOdguARF0lGKm5/mEq9PD9/VhZZegHDIBq2tQwgNpHc3dneD4mGo2iJs+fTKv5Bp0fZ+BRuY3Z0g==} @@ -7790,7 +8359,6 @@ packages: csv-parse: 4.16.3 csv-stringify: 5.6.5 stream-transform: 2.1.3 - dev: false /cycle/1.0.3: resolution: {integrity: sha512-TVF6svNzeQCOpjCqsy0/CSy8VgObG3wXusJ73xW2GbG5rGx7lC8zxDSURicsXI2UsGdi2L0QNRCi745/wUDvsA==} @@ -7830,7 +8398,6 @@ packages: engines: {node: '>=10'} dependencies: mimic-fn: 3.1.0 - dev: false /debug/2.6.9: resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} @@ -7933,7 +8500,6 @@ packages: resolution: {integrity: sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==} dependencies: clone: 1.0.4 - dev: false /defer-to-connect/2.0.1: resolution: {integrity: sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==} @@ -7951,7 +8517,6 @@ packages: /define-lazy-prop/2.0.0: resolution: {integrity: sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==} engines: {node: '>=8'} - dev: false /define-properties/1.2.1: resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} @@ -8066,7 +8631,6 @@ packages: engines: {node: '>=10'} dependencies: is-obj: 2.0.0 - dev: false /dotenv-expand/9.0.0: resolution: {integrity: sha512-uW8Hrhp5ammm9x7kBLR6jDfujgaDarNA02tprvZdyrJ7MpdzD1KyrIHG4l+YoC2fJ2UcdFdNWNWIjt+sexBHJw==} @@ -8087,6 +8651,7 @@ packages: /eastasianwidth/0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + dev: true /ee-first/1.1.1: resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} @@ -8122,10 +8687,10 @@ packages: /emoji-regex/9.2.2: resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + dev: true /enabled/2.0.0: resolution: {integrity: sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==} - dev: false /encodeurl/1.0.2: resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==} @@ -8167,7 +8732,6 @@ packages: /env-paths/2.2.1: resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} engines: {node: '>=6'} - dev: false /error-ex/1.3.4: resolution: {integrity: sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==} @@ -8277,7 +8841,6 @@ packages: /es6-promise/4.2.8: resolution: {integrity: sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==} - dev: false /esbuild/0.25.12: resolution: {integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==} @@ -8593,9 +9156,11 @@ packages: '@eslint/css': 0.10.0 '@eslint/json': 0.13.2 '@stylistic/eslint-plugin': 5.6.1_eslint@7.32.0 + '@stylistic/eslint-plugin': 5.6.1_eslint@7.32.0 confusing-browser-globals: 1.0.11 eslint: 7.32.0 globals: 16.5.0 + globals: 16.5.0 dev: true /eslint-config-xo/0.49.0_eslint@8.57.1: @@ -8607,9 +9172,11 @@ packages: '@eslint/css': 0.10.0 '@eslint/json': 0.13.2 '@stylistic/eslint-plugin': 5.6.1_eslint@8.57.1 + '@stylistic/eslint-plugin': 5.6.1_eslint@8.57.1 confusing-browser-globals: 1.0.11 eslint: 8.57.1 globals: 16.5.0 + globals: 16.5.0 dev: true /eslint-import-resolver-node/0.3.9: @@ -8829,6 +9396,7 @@ packages: debug: 3.2.7 doctrine: 2.1.0 eslint: 7.32.0 + eslint: 7.32.0 eslint-import-resolver-node: 0.3.9 eslint-module-utils: 2.12.1_dbj3zyqk523ljsvtt2wfpbcpby hasown: 2.0.2 @@ -8884,6 +9452,7 @@ packages: - supports-color dev: true + /eslint-plugin-import/2.32.0_ar3c7zjwtto324sxhascv2p7uq: /eslint-plugin-import/2.32.0_ar3c7zjwtto324sxhascv2p7uq: resolution: {integrity: sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==} engines: {node: '>=4'} @@ -8896,6 +9465,7 @@ packages: dependencies: '@rtsao/scc': 1.1.0 '@typescript-eslint/parser': 6.21.0_avq3eyf5kaj6ssrwo7fvkrwnji + '@typescript-eslint/parser': 6.21.0_avq3eyf5kaj6ssrwo7fvkrwnji array-includes: 3.1.9 array.prototype.findlastindex: 1.2.6 array.prototype.flat: 1.3.3 @@ -8903,8 +9473,10 @@ packages: debug: 3.2.7 doctrine: 2.1.0 eslint: 8.57.1 + eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 eslint-module-utils: 2.12.1_yb2aych2lrsetdffcibe7ggstq + eslint-module-utils: 2.12.1_yb2aych2lrsetdffcibe7ggstq hasown: 2.0.2 is-core-module: 2.16.1 is-glob: 4.0.3 @@ -9274,6 +9846,7 @@ packages: ci-info: 4.3.1 clean-regexp: 1.0.0 core-js-compat: 3.47.0 + core-js-compat: 3.47.0 eslint: 7.32.0 esquery: 1.6.0 globals: 15.15.0 @@ -9299,6 +9872,7 @@ packages: ci-info: 4.3.1 clean-regexp: 1.0.0 core-js-compat: 3.47.0 + core-js-compat: 3.47.0 eslint: 8.57.1 esquery: 1.6.0 globals: 15.15.0 @@ -9416,6 +9990,7 @@ packages: imurmurhash: 0.1.4 is-glob: 4.0.3 js-yaml: 3.14.2 + js-yaml: 3.14.2 json-stable-stringify-without-jsonify: 1.0.1 levn: 0.4.1 lodash.merge: 4.6.2 @@ -9470,6 +10045,7 @@ packages: is-glob: 4.0.3 is-path-inside: 3.0.3 js-yaml: 4.1.1 + js-yaml: 4.1.1 json-stable-stringify-without-jsonify: 1.0.1 levn: 0.4.1 lodash.merge: 4.6.2 @@ -9482,6 +10058,8 @@ packages: - supports-color dev: true + /eslint/9.39.1: + resolution: {integrity: sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g==} /eslint/9.39.1: resolution: {integrity: sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -9492,6 +10070,7 @@ packages: jiti: optional: true dependencies: + '@eslint-community/eslint-utils': 4.9.0_eslint@9.39.1 '@eslint-community/eslint-utils': 4.9.0_eslint@9.39.1 '@eslint-community/regexpp': 4.12.2 '@eslint/config-array': 0.21.1 @@ -9644,38 +10223,38 @@ packages: jest-util: 29.7.0 dev: true - /express/4.21.2: - resolution: {integrity: sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==} + /express/4.22.1: + resolution: {integrity: sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g==} engines: {node: '>= 0.10.0'} dependencies: accepts: 1.3.8 array-flatten: 1.1.1 - body-parser: 1.20.3 + body-parser: 1.20.4 content-disposition: 0.5.4 content-type: 1.0.5 - cookie: 0.7.1 - cookie-signature: 1.0.6 + cookie: 0.7.2 + cookie-signature: 1.0.7 debug: 2.6.9 depd: 2.0.0 encodeurl: 2.0.0 escape-html: 1.0.3 etag: 1.8.1 - finalhandler: 1.3.1 + finalhandler: 1.3.2 fresh: 0.5.2 - http-errors: 2.0.0 + http-errors: 2.0.1 merge-descriptors: 1.0.3 methods: 1.1.2 on-finished: 2.4.1 parseurl: 1.3.3 path-to-regexp: 0.1.12 proxy-addr: 2.0.7 - qs: 6.13.0 + qs: 6.14.0 range-parser: 1.2.1 safe-buffer: 5.2.1 - send: 0.19.0 + send: 0.19.1 serve-static: 1.16.2 setprototypeof: 1.2.0 - statuses: 2.0.1 + statuses: 2.0.2 type-is: 1.6.18 utils-merge: 1.0.1 vary: 1.1.2 @@ -9690,7 +10269,6 @@ packages: chardet: 0.4.2 iconv-lite: 0.4.24 tmp: 0.0.33 - dev: false /external-editor/3.1.0: resolution: {integrity: sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==} @@ -9699,7 +10277,6 @@ packages: chardet: 0.7.0 iconv-lite: 0.4.24 tmp: 0.0.33 - dev: false /eyes/0.1.8: resolution: {integrity: sha512-GipyPsXO1anza0AOZdy69Im7hGFCNB7Y/NGjDlZGJ3GJJLtwNSb2vrzYrTYJRrRloVx7pl+bhUaTB8yiccPvFQ==} @@ -9796,7 +10373,6 @@ packages: /fecha/4.2.3: resolution: {integrity: sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==} - dev: false /figlet/1.8.1: resolution: {integrity: sha512-kEC3Sme+YvA8Hkibv0NR1oClGcWia0VB2fC1SlMy027cwe795Xx40Xiv/nw/iFAwQLupymWh+uhAAErn/7hwPg==} @@ -9817,14 +10393,12 @@ packages: engines: {node: '>=4'} dependencies: escape-string-regexp: 1.0.5 - dev: false /figures/3.2.0: resolution: {integrity: sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==} engines: {node: '>=8'} dependencies: escape-string-regexp: 1.0.5 - dev: false /file-entry-cache/6.0.1: resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} @@ -9860,8 +10434,8 @@ packages: to-regex-range: 5.0.1 dev: true - /finalhandler/1.3.1: - resolution: {integrity: sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==} + /finalhandler/1.3.2: + resolution: {integrity: sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg==} engines: {node: '>= 0.8'} dependencies: debug: 2.6.9 @@ -9869,7 +10443,7 @@ packages: escape-html: 1.0.3 on-finished: 2.4.1 parseurl: 1.3.3 - statuses: 2.0.1 + statuses: 2.0.2 unpipe: 1.0.0 transitivePeerDependencies: - supports-color @@ -9906,7 +10480,6 @@ packages: engines: {node: '>=6'} dependencies: locate-path: 3.0.0 - dev: false /find-up/4.1.0: resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} @@ -9957,7 +10530,6 @@ packages: /fn.name/1.1.0: resolution: {integrity: sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==} - dev: false /follow-redirects/1.15.11: resolution: {integrity: sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==} @@ -10000,12 +10572,15 @@ packages: dependencies: cross-spawn: 7.0.6 signal-exit: 4.1.0 + dev: true /form-data-encoder/2.1.4: resolution: {integrity: sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw==} engines: {node: '>= 14.17'} dev: true + /form-data/4.0.5: + resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==} /form-data/4.0.5: resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==} engines: {node: '>= 6'} @@ -10102,7 +10677,6 @@ packages: /fuzzy/0.1.3: resolution: {integrity: sha512-/gZffu4ykarLrCiP3Ygsa86UAo1E5vEVlvTrpkKywXSbP9Xhln3oSp9QSV57gEq3JFFpGJ4GZ+5zdEp3FcUh4w==} engines: {node: '>= 0.6.0'} - dev: false /generator-function/2.0.1: resolution: {integrity: sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==} @@ -10205,6 +10779,8 @@ packages: is-glob: 4.0.3 dev: true + /glob/10.5.0: + resolution: {integrity: sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==} /glob/10.5.0: resolution: {integrity: sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==} hasBin: true @@ -10215,6 +10791,16 @@ packages: minipass: 7.1.2 package-json-from-dist: 1.0.1 path-scurry: 1.11.1 + dev: true + + /glob/13.0.0: + resolution: {integrity: sha512-tvZgpqk6fz4BaNZ66ZsRaZnbHvP/jG3uKJvAZOwEVUL4RTA5nJeeLYfyN9/VA8NX/V3IBG+hkeuGpKjvELkVhA==} + engines: {node: 20 || >=22} + dependencies: + minimatch: 10.1.1 + minipass: 7.1.2 + path-scurry: 2.0.1 + dev: false /glob/7.2.3: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} @@ -10257,6 +10843,8 @@ packages: engines: {node: '>=18'} dev: true + /globals/16.5.0: + resolution: {integrity: sha512-c/c15i26VrJ4IRt5Z89DnIzCGDn9EcebibhAOjw5ibqEHsE1wLUgkPn9RDmNcUKyU87GeaL633nyJ+pplFR2ZQ==} /globals/16.5.0: resolution: {integrity: sha512-c/c15i26VrJ4IRt5Z89DnIzCGDn9EcebibhAOjw5ibqEHsE1wLUgkPn9RDmNcUKyU87GeaL633nyJ+pplFR2ZQ==} engines: {node: '>=18'} @@ -10329,22 +10917,25 @@ packages: /grapheme-splitter/1.0.4: resolution: {integrity: sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==} - dev: false /graphemer/1.4.0: resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} dev: true + /graphql-tag/2.12.6_graphql@16.12.0: /graphql-tag/2.12.6_graphql@16.12.0: resolution: {integrity: sha512-FdSNcu2QQcWnM2VNvSCCDCVS5PpPqpzgFT8+GXzqJuoDd0CBncxCY278u4mhRO7tMgo2JjgJA5aZ+nWSQ/Z+xg==} engines: {node: '>=10'} peerDependencies: graphql: ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 dependencies: + graphql: 16.12.0 graphql: 16.12.0 tslib: 2.8.1 dev: false + /graphql/16.12.0: + resolution: {integrity: sha512-DKKrynuQRne0PNpEbzuEdHlYOMksHSUI8Zc9Unei5gTsMNA2/vMpoMz/yKba50pejK56qj98qM0SjYxAKi13gQ==} /graphql/16.12.0: resolution: {integrity: sha512-DKKrynuQRne0PNpEbzuEdHlYOMksHSUI8Zc9Unei5gTsMNA2/vMpoMz/yKba50pejK56qj98qM0SjYxAKi13gQ==} engines: {node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0} @@ -10501,7 +11092,6 @@ packages: engines: {node: '>=0.10.0'} dependencies: safer-buffer: 2.1.2 - dev: false /iconv-lite/0.7.0: resolution: {integrity: sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==} @@ -10511,7 +11101,6 @@ packages: /ieee754/1.2.1: resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} - dev: false /ignore/4.0.6: resolution: {integrity: sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==} @@ -10599,7 +11188,6 @@ packages: figures: 2.0.0 fuzzy: 0.1.3 inquirer: 3.3.0 - dev: false /inquirer-search-list/1.2.6: resolution: {integrity: sha512-C4pKSW7FOYnkAloH8rB4FiM91H1v08QFZZJh6KRt//bMfdDBIhgdX8wjHvrVH2bu5oIo6wYqGpzSBxkeClPxew==} @@ -10608,7 +11196,6 @@ packages: figures: 2.0.0 fuzzy: 0.1.3 inquirer: 3.3.0 - dev: false /inquirer/3.3.0: resolution: {integrity: sha512-h+xtnyk4EwKvFWHrUYsWErEVR+igKtLdchu+o0Z1RL7VU/jVMFbYir2bp6bAj8efFNxWqHX0dIss6fJQ+/+qeQ==} @@ -10627,7 +11214,6 @@ packages: string-width: 2.1.1 strip-ansi: 4.0.0 through: 2.3.8 - dev: false /inquirer/8.2.6: resolution: {integrity: sha512-M1WuAmb7pn9zdFRtQYk26ZBoY043Sse0wVDdk4Bppr+JOXyQYybdtvK+l9wUibhtjdjvtoiNy8tk+EgsYIUqKg==} @@ -10648,12 +11234,12 @@ packages: strip-ansi: 6.0.1 through: 2.3.8 wrap-ansi: 6.2.0 - dev: false /inquirer/8.2.7: resolution: {integrity: sha512-UjOaSel/iddGZJ5xP/Eixh6dY1XghiBw4XK13rCCIJcJfyhhoul/7KhLLUGtebEj6GDYM6Vnx/mVsjx2L/mFIA==} engines: {node: '>=12.0.0'} dependencies: + '@inquirer/external-editor': 1.0.3 '@inquirer/external-editor': 1.0.3 ansi-escapes: 4.3.2 chalk: 4.1.2 @@ -10677,6 +11263,7 @@ packages: resolution: {integrity: sha512-UjOaSel/iddGZJ5xP/Eixh6dY1XghiBw4XK13rCCIJcJfyhhoul/7KhLLUGtebEj6GDYM6Vnx/mVsjx2L/mFIA==} engines: {node: '>=12.0.0'} dependencies: + '@inquirer/external-editor': 1.0.3_@types+node@14.18.63 '@inquirer/external-editor': 1.0.3_@types+node@14.18.63 ansi-escapes: 4.3.2 chalk: 4.1.2 @@ -10728,7 +11315,6 @@ packages: dependencies: call-bound: 1.0.4 has-tostringtag: 1.0.2 - dev: false /is-array-buffer/3.0.5: resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==} @@ -10836,7 +11422,6 @@ packages: /is-fullwidth-code-point/2.0.0: resolution: {integrity: sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==} engines: {node: '>=4'} - dev: false /is-fullwidth-code-point/3.0.0: resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} @@ -10888,7 +11473,6 @@ packages: dependencies: call-bind: 1.0.8 define-properties: 1.2.1 - dev: false /is-negative-zero/2.0.3: resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==} @@ -10909,7 +11493,6 @@ packages: /is-obj/2.0.0: resolution: {integrity: sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==} engines: {node: '>=8'} - dev: false /is-observable/1.1.0: resolution: {integrity: sha512-NqCa4Sa2d+u7BWc6CukaObG3Fh+CU9bvixbpcXYhy2VvYS7vVGIdAgnIS5Ks3A/cqk4rebLJ9s8zBstT2aKnIA==} @@ -11051,6 +11634,7 @@ packages: /isexe/2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + dev: true /isexe/3.1.1: resolution: {integrity: sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==} @@ -11157,6 +11741,7 @@ packages: '@isaacs/cliui': 8.0.2 optionalDependencies: '@pkgjs/parseargs': 0.11.0 + dev: true /jake/10.9.4: resolution: {integrity: sha512-wpHYzhxiVQL+IV05BLE2Xn34zW1S223hvjtqk0+gsPrwd/8JNLXJgZZM/iPFsYc1xyphF+6M6EvdE5E9MBGkDA==} @@ -11637,6 +12222,8 @@ packages: /js-tokens/4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + /js-yaml/3.14.2: + resolution: {integrity: sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==} /js-yaml/3.14.2: resolution: {integrity: sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==} hasBin: true @@ -11645,6 +12232,8 @@ packages: esprima: 4.0.1 dev: true + /js-yaml/4.1.1: + resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} /js-yaml/4.1.1: resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} hasBin: true @@ -11758,7 +12347,6 @@ packages: /json-schema-typed/7.0.3: resolution: {integrity: sha512-7DE8mpG+/fVw+dTpjbxnx47TaMnDfOI1jwft9g1VybltZCduyRQPJPvc+zzKY9WPHxhPWczyFuYa6I8Mw4iU5A==} - dev: false /json-stable-stringify-without-jsonify/1.0.1: resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} @@ -11831,16 +12419,13 @@ packages: /kleur/4.1.5: resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==} engines: {node: '>=6'} - dev: false /klona/2.0.6: resolution: {integrity: sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==} engines: {node: '>= 8'} - dev: false /kuler/2.0.0: resolution: {integrity: sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==} - dev: false /leven/3.1.0: resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} @@ -11922,7 +12507,6 @@ packages: /localStorage/1.0.4: resolution: {integrity: sha512-r35zrihcDiX+dqWlJSeIwS9nrF95OQTgqMFm3FB2D/+XgdmZtcutZOb7t0xXkhOEM8a9kpuu7cc28g1g36I5DQ==} engines: {node: '>= v0.2.0'} - dev: false /locate-path/3.0.0: resolution: {integrity: sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==} @@ -11930,7 +12514,6 @@ packages: dependencies: p-locate: 3.0.0 path-exists: 3.0.0 - dev: false /locate-path/5.0.0: resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} @@ -12046,7 +12629,6 @@ packages: ms: 2.1.3 safe-stable-stringify: 2.5.0 triple-beam: 1.4.1 - dev: false /loose-envify/1.4.0: resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} @@ -12075,6 +12657,11 @@ packages: /lru-cache/10.4.3: resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} + /lru-cache/11.2.4: + resolution: {integrity: sha512-B5Y16Jr9LB9dHVkh6ZevG+vAbOsNOYCX+sXvFWFu7B3Iz5mijW3zdbMyhsh8ANd2mSWBYdJgnqi+mL7/LrOPYg==} + engines: {node: 20 || >=22} + dev: false + /lru-cache/5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} dependencies: @@ -12204,7 +12791,6 @@ packages: /mimic-fn/1.2.0: resolution: {integrity: sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==} engines: {node: '>=4'} - dev: false /mimic-fn/2.1.0: resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} @@ -12240,7 +12826,6 @@ packages: engines: {node: 20 || >=22} dependencies: '@isaacs/brace-expansion': 5.0.0 - dev: true /minimatch/3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} @@ -12303,7 +12888,6 @@ packages: /mixme/0.5.10: resolution: {integrity: sha512-5H76ANWinB1H3twpJ6JY8uvAtpmFvHNArpilJAjXRKXSDDLPIMoZArw5SH0q9z+lLs8IrMw7Q2VWpWimFKFT1Q==} engines: {node: '>= 8.0.0'} - dev: false /mkdirp/1.0.4: resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} @@ -12335,6 +12919,7 @@ packages: glob: 8.1.0 he: 1.2.0 js-yaml: 4.1.1 + js-yaml: 4.1.1 log-symbols: 4.1.0 minimatch: 5.1.6 ms: 2.1.3 @@ -12359,11 +12944,9 @@ packages: /mute-stream/0.0.7: resolution: {integrity: sha512-r65nCZhrbXXb6dXOACihYApHw2Q6pV0M3V0PSxd74N0+D8nzAdEAITq2oAjA1jVnKI+tGvEBUpqiMh0+rW6zDQ==} - dev: false /mute-stream/0.0.8: resolution: {integrity: sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==} - dev: false /mute-stream/1.0.0: resolution: {integrity: sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==} @@ -12668,7 +13251,6 @@ packages: dependencies: call-bind: 1.0.8 define-properties: 1.2.1 - dev: false /object-keys/1.1.1: resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} @@ -12738,6 +13320,9 @@ packages: '@oclif/plugin-help': 6.2.36 '@oclif/plugin-not-found': 3.2.73 '@oclif/plugin-warn-if-update-available': 3.1.53 + '@oclif/plugin-help': 6.2.36 + '@oclif/plugin-not-found': 3.2.73 + '@oclif/plugin-warn-if-update-available': 3.1.53 ansis: 3.17.0 async-retry: 1.3.3 change-case: 4.1.2 @@ -12773,6 +13358,9 @@ packages: '@oclif/plugin-help': 6.2.36 '@oclif/plugin-not-found': 3.2.73_@types+node@14.18.63 '@oclif/plugin-warn-if-update-available': 3.1.53 + '@oclif/plugin-help': 6.2.36 + '@oclif/plugin-not-found': 3.2.73_@types+node@14.18.63 + '@oclif/plugin-warn-if-update-available': 3.1.53 ansis: 3.17.0 async-retry: 1.3.3 change-case: 4.1.2 @@ -12845,14 +13433,12 @@ packages: resolution: {integrity: sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==} dependencies: fn.name: 1.1.0 - dev: false /onetime/2.0.1: resolution: {integrity: sha512-oyyPpiMaKARvvcgip+JV+7zci5L8D1W9RZIz2l1o08AM3pfspitVWnPt3mzHcBPp12oYMTy0pqrFs/C+m3EwsQ==} engines: {node: '>=4'} dependencies: mimic-fn: 1.2.0 - dev: false /onetime/5.1.2: resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} @@ -12874,7 +13460,6 @@ packages: define-lazy-prop: 2.0.0 is-docker: 2.2.1 is-wsl: 2.2.0 - dev: false /optimism/0.18.1: resolution: {integrity: sha512-mLXNwWPa9dgFyDqkNi54sjDyNJ9/fTI6WGBLgnXku1vdKY/jovHfZT5r+aiVeFFLOz+foPNOm5YJ4mqgld2GBQ==} @@ -12930,7 +13515,6 @@ packages: /os-tmpdir/1.0.2: resolution: {integrity: sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==} engines: {node: '>=0.10.0'} - dev: false /otplib/12.0.1: resolution: {integrity: sha512-xDGvUOQjop7RDgxTQ+o4pOol0/3xSZzawTiPKRrHnQWAy0WjhNs/5HdIDJCrqC4MBynmjXgULc6YfioaxZeFgg==} @@ -12938,7 +13522,6 @@ packages: '@otplib/core': 12.0.1 '@otplib/preset-default': 12.0.1 '@otplib/preset-v11': 12.0.1 - dev: false /own-keys/1.0.1: resolution: {integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==} @@ -12981,7 +13564,6 @@ packages: engines: {node: '>=6'} dependencies: p-limit: 2.3.0 - dev: false /p-locate/4.1.0: resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} @@ -13027,7 +13609,6 @@ packages: /papaparse/5.5.3: resolution: {integrity: sha512-5QvjGxYVjxO59MGU2lHVYpRWBBtKHnlIAcSe1uNFCkkptUh63NFRj0FJQm7nR67puEruUci/ZkjmEFrjCAyP4A==} - dev: false /param-case/3.0.4: resolution: {integrity: sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==} @@ -13093,7 +13674,6 @@ packages: /path-exists/3.0.0: resolution: {integrity: sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==} engines: {node: '>=4'} - dev: false /path-exists/4.0.0: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} @@ -13112,6 +13692,7 @@ packages: /path-key/3.1.1: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} + dev: true /path-key/4.0.0: resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==} @@ -13127,6 +13708,15 @@ packages: dependencies: lru-cache: 10.4.3 minipass: 7.1.2 + dev: true + + /path-scurry/2.0.1: + resolution: {integrity: sha512-oWyT4gICAu+kaA7QWk/jvCHWarMKNs6pXOGWKDTr7cw4IGcUbW+PeTfbaQiLGheFRpjo6O9J0PmyMfQPjH71oA==} + engines: {node: 20 || >=22} + dependencies: + lru-cache: 11.2.4 + minipass: 7.1.2 + dev: false /path-to-regexp/0.1.12: resolution: {integrity: sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==} @@ -13178,7 +13768,6 @@ packages: engines: {node: '>=8'} dependencies: find-up: 3.0.0 - dev: false /pluralize/8.0.0: resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==} @@ -13318,19 +13907,11 @@ packages: resolution: {integrity: sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==} dev: true - /qs/6.13.0: - resolution: {integrity: sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==} - engines: {node: '>=0.6'} - dependencies: - side-channel: 1.1.0 - dev: false - /qs/6.14.0: resolution: {integrity: sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==} engines: {node: '>=0.6'} dependencies: side-channel: 1.1.0 - dev: false /queue-microtask/1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} @@ -13356,12 +13937,12 @@ packages: engines: {node: '>= 0.6'} dev: false - /raw-body/2.5.2: - resolution: {integrity: sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==} + /raw-body/2.5.3: + resolution: {integrity: sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==} engines: {node: '>= 0.8'} dependencies: bytes: 3.1.2 - http-errors: 2.0.0 + http-errors: 2.0.1 iconv-lite: 0.4.24 unpipe: 1.0.0 dev: false @@ -13423,7 +14004,6 @@ packages: inherits: 2.0.4 string_decoder: 1.3.0 util-deprecate: 1.0.2 - dev: false /readdirp/3.6.0: resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} @@ -13435,7 +14015,6 @@ packages: /recheck-jar/4.4.5: resolution: {integrity: sha512-a2kMzcfr+ntT0bObNLY22EUNV6Z6WeZ+DybRmPOUXVWzGcqhRcrK74tpgrYt3FdzTlSh85pqoryAPmrNkwLc0g==} requiresBuild: true - dev: false optional: true /recheck-linux-x64/4.4.5: @@ -13443,7 +14022,6 @@ packages: cpu: [x64] os: [linux] requiresBuild: true - dev: false optional: true /recheck-macos-x64/4.4.5: @@ -13451,7 +14029,6 @@ packages: cpu: [x64] os: [darwin] requiresBuild: true - dev: false optional: true /recheck-windows-x64/4.4.5: @@ -13459,7 +14036,6 @@ packages: cpu: [x64] os: [win32] requiresBuild: true - dev: false optional: true /recheck/4.4.5: @@ -13470,7 +14046,6 @@ packages: recheck-linux-x64: 4.4.5 recheck-macos-x64: 4.4.5 recheck-windows-x64: 4.4.5 - dev: false /rechoir/0.6.2: resolution: {integrity: sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==} @@ -13643,7 +14218,6 @@ packages: dependencies: onetime: 2.0.1 signal-exit: 3.0.7 - dev: false /restore-cursor/3.1.0: resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==} @@ -13679,6 +14253,7 @@ packages: /rewire/9.0.1: resolution: {integrity: sha512-dnbLeTwHpXvWJjswC6CshXUUnnpE5AVhlayVRvDJhJx5ejbO4nbj1IXqN2urErgB7TpHUAMpf6iPDhQIxeSQOQ==} dependencies: + eslint: 9.39.1 eslint: 9.39.1 pirates: 4.0.7 transitivePeerDependencies: @@ -13707,6 +14282,28 @@ packages: dependencies: '@types/estree': 1.0.8 optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.53.3 + '@rollup/rollup-android-arm64': 4.53.3 + '@rollup/rollup-darwin-arm64': 4.53.3 + '@rollup/rollup-darwin-x64': 4.53.3 + '@rollup/rollup-freebsd-arm64': 4.53.3 + '@rollup/rollup-freebsd-x64': 4.53.3 + '@rollup/rollup-linux-arm-gnueabihf': 4.53.3 + '@rollup/rollup-linux-arm-musleabihf': 4.53.3 + '@rollup/rollup-linux-arm64-gnu': 4.53.3 + '@rollup/rollup-linux-arm64-musl': 4.53.3 + '@rollup/rollup-linux-loong64-gnu': 4.53.3 + '@rollup/rollup-linux-ppc64-gnu': 4.53.3 + '@rollup/rollup-linux-riscv64-gnu': 4.53.3 + '@rollup/rollup-linux-riscv64-musl': 4.53.3 + '@rollup/rollup-linux-s390x-gnu': 4.53.3 + '@rollup/rollup-linux-x64-gnu': 4.53.3 + '@rollup/rollup-linux-x64-musl': 4.53.3 + '@rollup/rollup-openharmony-arm64': 4.53.3 + '@rollup/rollup-win32-arm64-msvc': 4.53.3 + '@rollup/rollup-win32-ia32-msvc': 4.53.3 + '@rollup/rollup-win32-x64-gnu': 4.53.3 + '@rollup/rollup-win32-x64-msvc': 4.53.3 '@rollup/rollup-android-arm-eabi': 4.53.3 '@rollup/rollup-android-arm64': 4.53.3 '@rollup/rollup-darwin-arm64': 4.53.3 @@ -13735,7 +14332,6 @@ packages: /run-async/2.4.1: resolution: {integrity: sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==} engines: {node: '>=0.12.0'} - dev: false /run-parallel/1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} @@ -13747,18 +14343,15 @@ packages: resolution: {integrity: sha512-3xPNZGW93oCjiO7PtKxRK6iOVYBWBvtf9QHDfU23Oc+dLIQmAV//UnyXV/yihv81VS/UqoQPk4NegS8EFi55Hg==} dependencies: rx-lite: 4.0.8 - dev: false /rx-lite/4.0.8: resolution: {integrity: sha512-Cun9QucwK6MIrp3mry/Y7hqD1oFqTYLQ4pGxaHTjIdaFDWRGGLikqp6u8LcWJnzpoALg9hap+JGk8sFIUuEGNA==} - dev: false /rxjs/6.6.7: resolution: {integrity: sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==} engines: {npm: '>=2.0.0'} dependencies: tslib: 1.14.1 - dev: false /rxjs/7.8.2: resolution: {integrity: sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==} @@ -13800,7 +14393,6 @@ packages: /safe-stable-stringify/2.5.0: resolution: {integrity: sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==} engines: {node: '>=10'} - dev: false /safer-buffer/2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} @@ -13841,6 +14433,27 @@ packages: - supports-color dev: false + /send/0.19.1: + resolution: {integrity: sha512-p4rRk4f23ynFEfcD9LA0xRYngj+IyGiEYyqqOak8kaN0TvNmuxC2dcVeBn62GpCeR2CpWqyHCNScTP91QbAVFg==} + engines: {node: '>= 0.8.0'} + dependencies: + debug: 2.6.9 + depd: 2.0.0 + destroy: 1.2.0 + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + fresh: 0.5.2 + http-errors: 2.0.0 + mime: 1.6.0 + ms: 2.1.3 + on-finished: 2.4.1 + range-parser: 1.2.1 + statuses: 2.0.1 + transitivePeerDependencies: + - supports-color + dev: false + /sentence-case/3.0.4: resolution: {integrity: sha512-8LS0JInaQMCRoQ7YUytAo/xUu5W2XnQxV2HI/6uM6U7CITS1RqPElr30V6uIqyMKM9lJGRVFy5/4CuzcixNYSg==} dependencies: @@ -13914,6 +14527,7 @@ packages: engines: {node: '>=8'} dependencies: shebang-regex: 3.0.0 + dev: true /shebang-regex/1.0.0: resolution: {integrity: sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==} @@ -13923,6 +14537,7 @@ packages: /shebang-regex/3.0.0: resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} engines: {node: '>=8'} + dev: true /shelljs/0.10.0: resolution: {integrity: sha512-Jex+xw5Mg2qMZL3qnzXIfaxEtBaC4n7xifqaqtrZDdlheR70OGkydrPJWT0V1cA1k3nanC86x9FwAmQl6w3Klw==} @@ -14060,7 +14675,6 @@ packages: strip-ansi: 6.0.1 wcwidth: 1.0.1 yargs: 15.4.1 - dev: false /snake-case/3.0.4: resolution: {integrity: sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==} @@ -14179,7 +14793,6 @@ packages: /stack-trace/0.0.10: resolution: {integrity: sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==} - dev: false /stack-utils/2.0.6: resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} @@ -14219,7 +14832,6 @@ packages: dependencies: inherits: 2.0.4 readable-stream: 3.6.2 - dev: false /stream-connect/1.0.2: resolution: {integrity: sha512-68Kl+79cE0RGKemKkhxTSg8+6AGrqBt+cbZAXevg2iJ6Y3zX4JhA/sZeGzLpxW9cXhmqAcE7KnJCisUmIUfnFQ==} @@ -14233,7 +14845,6 @@ packages: resolution: {integrity: sha512-9GHUiM5hMiCi6Y03jD2ARC1ettBXkQBoQAe7nJsPknnI0ow10aXjTnew8QtYQmLjzn974BnmWEAJgCY6ZP1DeQ==} dependencies: mixme: 0.5.10 - dev: false /stream-via/1.0.4: resolution: {integrity: sha512-DBp0lSvX5G9KGRDTkR/R+a29H+Wk2xItOF+MpZLLNDWbEV9tGPnqLPxHEYjmiz8xGtJHRIqmI+hCjmNzqoA4nQ==} @@ -14263,7 +14874,6 @@ packages: dependencies: is-fullwidth-code-point: 2.0.0 strip-ansi: 4.0.0 - dev: false /string-width/4.2.3: resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} @@ -14329,7 +14939,6 @@ packages: resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} dependencies: safe-buffer: 5.2.1 - dev: false /strip-ansi/3.0.1: resolution: {integrity: sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==} @@ -14343,7 +14952,6 @@ packages: engines: {node: '>=4'} dependencies: ansi-regex: 3.0.1 - dev: false /strip-ansi/6.0.1: resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} @@ -14356,6 +14964,7 @@ packages: engines: {node: '>=12'} dependencies: ansi-regex: 6.2.2 + dev: true /strip-bom/3.0.0: resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} @@ -14500,7 +15109,6 @@ packages: /text-hex/1.0.0: resolution: {integrity: sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==} - dev: false /text-table/0.2.0: resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} @@ -14509,11 +15117,9 @@ packages: /thirty-two/1.0.2: resolution: {integrity: sha512-OEI0IWCe+Dw46019YLl6V10Us5bi574EvlJEOcAkB29IzQ/mYD1A6RyNHLjZPiHCmuodxvgF6U+vZO1L15lxVA==} engines: {node: '>=0.2.6'} - dev: false /through/2.3.8: resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} - dev: false /through2/2.0.5: resolution: {integrity: sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==} @@ -14545,7 +15151,6 @@ packages: engines: {node: '>=0.6.0'} dependencies: os-tmpdir: 1.0.2 - dev: false /tmp/0.2.5: resolution: {integrity: sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow==} @@ -14578,12 +15183,10 @@ packages: gopd: 1.2.0 typedarray.prototype.slice: 1.0.5 which-typed-array: 1.1.19 - dev: false /triple-beam/1.4.1: resolution: {integrity: sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==} engines: {node: '>= 14.0.0'} - dev: false /ts-api-utils/1.4.3_typescript@4.9.5: resolution: {integrity: sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw==} @@ -14661,8 +15264,8 @@ packages: tslib: 2.8.1 dev: false - /ts-jest/29.4.5_67xnt3v64q2pgz6kguni4h37hu: - resolution: {integrity: sha512-HO3GyiWn2qvTQA4kTgjDcXiMwYQt68a1Y8+JuLRVpdIzm+UOLSHgl/XqR4c6nzJkq5rOkjc02O2I7P7l/Yof0Q==} + /ts-jest/29.4.6_67xnt3v64q2pgz6kguni4h37hu: + resolution: {integrity: sha512-fSpWtOO/1AjSNQguk43hb/JCo16oJDnMJf3CdEGNkqsEX3t0KX96xvyX1D7PfLCpVoKu4MfVrqUkFyblYoY4lA==} engines: {node: ^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0} hasBin: true peerDependencies: @@ -14717,6 +15320,7 @@ packages: dependencies: '@cspotcode/source-map-support': 0.8.1 '@tsconfig/node10': 1.0.12 + '@tsconfig/node10': 1.0.12 '@tsconfig/node12': 1.0.11 '@tsconfig/node14': 1.0.3 '@tsconfig/node16': 1.0.4 @@ -14748,6 +15352,7 @@ packages: dependencies: '@cspotcode/source-map-support': 0.8.1 '@tsconfig/node10': 1.0.12 + '@tsconfig/node10': 1.0.12 '@tsconfig/node12': 1.0.11 '@tsconfig/node14': 1.0.3 '@tsconfig/node16': 1.0.4 @@ -14779,6 +15384,7 @@ packages: dependencies: '@cspotcode/source-map-support': 0.8.1 '@tsconfig/node10': 1.0.12 + '@tsconfig/node10': 1.0.12 '@tsconfig/node12': 1.0.11 '@tsconfig/node14': 1.0.3 '@tsconfig/node16': 1.0.4 @@ -14833,8 +15439,8 @@ packages: typescript: 4.9.5 dev: true - /tsx/4.20.6: - resolution: {integrity: sha512-ytQKuwgmrrkDTFP4LjR0ToE2nqgy886GpvRSpU0JAnrdBYppuY5rLkRUYPU1yCryb24SsKBTL/hlDQAEFVwtZg==} + /tsx/4.21.0: + resolution: {integrity: sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==} engines: {node: '>=18.0.0'} hasBin: true dependencies: @@ -14856,7 +15462,6 @@ packages: strip-ansi: 6.0.1 wcwidth: 1.0.1 yargs: 17.7.2 - dev: false /tunnel-agent/0.6.0: resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} @@ -14972,7 +15577,6 @@ packages: math-intrinsics: 1.1.0 typed-array-buffer: 1.0.3 typed-array-byte-offset: 1.0.4 - dev: false /typedarray/0.0.6: resolution: {integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==} @@ -15102,7 +15706,6 @@ packages: engines: {node: '>=8'} dependencies: crypto-random-string: 2.0.0 - dev: false /universalify/0.1.2: resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} @@ -15177,7 +15780,6 @@ packages: /util-deprecate/1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} - dev: false /util/0.12.5: resolution: {integrity: sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==} @@ -15187,7 +15789,6 @@ packages: is-generator-function: 1.1.2 is-typed-array: 1.1.15 which-typed-array: 1.1.19 - dev: false /utils-merge/1.0.1: resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==} @@ -15201,7 +15802,6 @@ packages: /uuid/9.0.1: resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==} hasBin: true - dev: false /v8-compile-cache-lib/3.0.1: resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} @@ -15256,7 +15856,6 @@ packages: resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==} dependencies: defaults: 1.0.4 - dev: false /webidl-conversions/3.0.1: resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} @@ -15334,6 +15933,7 @@ packages: hasBin: true dependencies: isexe: 2.0.0 + dev: true /which/4.0.0: resolution: {integrity: sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==} @@ -15356,7 +15956,6 @@ packages: logform: 2.7.0 readable-stream: 3.6.2 triple-beam: 1.4.1 - dev: false /winston/2.4.7: resolution: {integrity: sha512-vLB4BqzCKDnnZH9PHGoS2ycawueX4HLqENXQitvFHczhgW2vFpSOn31LZtVr1KU8YTw7DS4tM+cqyovxo8taVg==} @@ -15370,8 +15969,8 @@ packages: stack-trace: 0.0.10 dev: false - /winston/3.18.3: - resolution: {integrity: sha512-NoBZauFNNWENgsnC9YpgyYwOVrl2m58PpQ8lNHjV3kosGs7KJ7Npk9pCUE+WJlawVSe8mykWDKWFSVfs3QO9ww==} + /winston/3.19.0: + resolution: {integrity: sha512-LZNJgPzfKR+/J3cHkxcpHKpKKvGfDZVPS4hfJCc4cCG0CgYzvlD6yE/S3CIL/Yt91ak327YCpiF/0MyeZHEHKA==} engines: {node: '>= 12.0.0'} dependencies: '@colors/colors': 1.6.0 @@ -15385,7 +15984,6 @@ packages: stack-trace: 0.0.10 triple-beam: 1.4.1 winston-transport: 4.9.0 - dev: false /word-wrap/1.2.5: resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} @@ -15438,6 +16036,7 @@ packages: ansi-styles: 6.2.3 string-width: 5.1.2 strip-ansi: 7.1.2 + dev: true /wrappy/1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} @@ -15462,7 +16061,6 @@ packages: /xdg-basedir/4.0.0: resolution: {integrity: sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==} engines: {node: '>=8'} - dev: false /xmlcreate/2.0.4: resolution: {integrity: sha512-nquOebG4sngPmGPICTS5EnxqhKbCmz5Ox5hsszI2T6U5qdrJizBc+0ilYSEjTSzU0yZcmvppztXe/5Al5fUwdg==}