diff --git a/.talismanrc b/.talismanrc index 40da5657de..4141174ef1 100644 --- a/.talismanrc +++ b/.talismanrc @@ -6,7 +6,7 @@ fileignoreconfig: - filename: packages/contentstack-import/test/integration/environments.test.js checksum: e71f033dad8944ffeafdf22d0514bda1d20c43e8fea0d62c96e774f3414beb31 - filename: package-lock.json - checksum: 7260d9647ed789f09e454d63f9bdd0393e6dfd93f69d4dd2a1505c1c2a60b194 + checksum: ff9b99eb4ee7a2daba9eec2652bda33762a99f644fd32827c81cfa7ac65ea4f6 - filename: packages/contentstack-auth/test/unit/tokens-validation.test.ts checksum: 676052e30d31a771ce68302d89b050d176bbef50f3abc7e9cdd4384f0e274e10 - filename: packages/contentstack-import/test/integration/auth-token.test.js diff --git a/package-lock.json b/package-lock.json index 28cd7b9c19..78c239d2f2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1212,13 +1212,13 @@ } }, "node_modules/@babel/helpers": { - "version": "7.27.6", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.27.6.tgz", - "integrity": "sha512-muE8Tt8M22638HU31A3CgfSUciwz1fhATfoVai05aPXGor//CdWDCbnlY1yvBPo07njuVOCNGCSp/GTt12lIug==", + "version": "7.28.2", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.2.tgz", + "integrity": "sha512-/V9771t+EgXz62aCcyofnQhGM8DQACbRhvzKFsXKC9QM+5MadF8ZmIm0crDMaz3+o0h0zXfJnd4EhbYbxsrcFw==", "license": "MIT", "dependencies": { "@babel/template": "^7.27.2", - "@babel/types": "^7.27.6" + "@babel/types": "^7.28.2" }, "engines": { "node": ">=6.9.0" @@ -1588,9 +1588,9 @@ } }, "node_modules/@babel/types": { - "version": "7.28.1", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.1.tgz", - "integrity": "sha512-x0LvFTekgSX+83TI28Y9wYPUfzrnl2aT5+5QLnO6v7mSJYtEEevuDRN0F0uSHRk1G1IWZC43o00Y0xDDrpBGPQ==", + "version": "7.28.2", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.2.tgz", + "integrity": "sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ==", "license": "MIT", "dependencies": { "@babel/helper-string-parser": "^7.27.1", @@ -4021,9 +4021,9 @@ } }, "node_modules/@oclif/core": { - "version": "4.5.1", - "resolved": "https://registry.npmjs.org/@oclif/core/-/core-4.5.1.tgz", - "integrity": "sha512-JAuARvXOzf75L7rqLL3TIP3OmuTf7N/cjRejkGASfRJH+09180+EGbSkPWSMCns+AaYpDMI+fdaJ6QCoa3f15A==", + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/@oclif/core/-/core-4.5.2.tgz", + "integrity": "sha512-eQcKyrEcDYeZJKu4vUWiu0ii/1Gfev6GF4FsLSgNez5/+aQyAUCjg3ZWlurf491WiYZTXCWyKAxyPWk8DKv2MA==", "license": "MIT", "dependencies": { "ansi-escapes": "^4.3.2", @@ -4050,9 +4050,9 @@ } }, "node_modules/@oclif/plugin-help": { - "version": "6.2.31", - "resolved": "https://registry.npmjs.org/@oclif/plugin-help/-/plugin-help-6.2.31.tgz", - "integrity": "sha512-o4xR98DEFf+VqY+M9B3ZooTm2T/mlGvyBHwHcnsPJCEnvzHqEA9xUlCUK4jm7FBXHhkppziMgCC2snsueLoIpQ==", + "version": "6.2.32", + "resolved": "https://registry.npmjs.org/@oclif/plugin-help/-/plugin-help-6.2.32.tgz", + "integrity": "sha512-LrmMdo9EMJciOvF8UurdoTcTMymv5npKtxMAyonZvhSvGR8YwCKnuHIh00+SO2mNtGOYam7f4xHnUmj2qmanyA==", "license": "MIT", "dependencies": { "@oclif/core": "^4" @@ -4062,13 +4062,13 @@ } }, "node_modules/@oclif/plugin-not-found": { - "version": "3.2.60", - "resolved": "https://registry.npmjs.org/@oclif/plugin-not-found/-/plugin-not-found-3.2.60.tgz", - "integrity": "sha512-TK+o2gdFK/IEOR/A9lk2Ob7qm7Z+fEaaHlNls4AfKcEgxfSGaDwGu6cF9lxtMq87pVJ47uiAjjZaBtGYmS01Wg==", + "version": "3.2.62", + "resolved": "https://registry.npmjs.org/@oclif/plugin-not-found/-/plugin-not-found-3.2.62.tgz", + "integrity": "sha512-hwUdpeExF4ZhIf0mTeegnznpfSICOr4tnk8VZ6POmEcvNEhK8OtU/zbfCQbiGNa0Zjp1oMncD1Oxh585GHUSog==", "license": "MIT", "dependencies": { - "@inquirer/prompts": "^7.6.0", - "@oclif/core": "^4.5.1", + "@inquirer/prompts": "^7.7.1", + "@oclif/core": "^4.5.2", "ansis": "^3.17.0", "fast-levenshtein": "^3.0.0" }, @@ -4077,12 +4077,12 @@ } }, "node_modules/@oclif/plugin-plugins": { - "version": "5.4.45", - "resolved": "https://registry.npmjs.org/@oclif/plugin-plugins/-/plugin-plugins-5.4.45.tgz", - "integrity": "sha512-M68eqQCaS7IHvYET1f2ZQP60jChX6emdgObcpDt5jeYifLd+MZFnGSsh5spOE3y3CAAZX5U4tCCksz++YKw0RA==", + "version": "5.4.46", + "resolved": "https://registry.npmjs.org/@oclif/plugin-plugins/-/plugin-plugins-5.4.46.tgz", + "integrity": "sha512-VSk+SwKDkGShuRGC5f5WNF/U6Y8JvLfzIaWjLxMe4GlBmln0mKhHqvcfJc2gZOiyJp1QYK638H1w/peSkoZHag==", "license": "MIT", "dependencies": { - "@oclif/core": "^4.5.1", + "@oclif/core": "^4.5.2", "ansis": "^3.17.0", "debug": "^4.4.0", "npm": "^10.9.3", @@ -4099,9 +4099,9 @@ } }, "node_modules/@oclif/plugin-warn-if-update-available": { - "version": "3.1.45", - "resolved": "https://registry.npmjs.org/@oclif/plugin-warn-if-update-available/-/plugin-warn-if-update-available-3.1.45.tgz", - "integrity": "sha512-tYGLrHZLpt+KLPDdLtpZyrzzy5OZ9uqpfaDm/jy6GUNqfoxZkhD7Kj6Fv9IpM6ePQM8hFVZpUMiWC0NO/AaDaA==", + "version": "3.1.46", + "resolved": "https://registry.npmjs.org/@oclif/plugin-warn-if-update-available/-/plugin-warn-if-update-available-3.1.46.tgz", + "integrity": "sha512-YDlr//SHmC80eZrt+0wNFWSo1cOSU60RoWdhSkAoPB3pUGPSNHZDquXDpo7KniinzYPsj1rfetCYk7UVXwYu7A==", "dev": true, "license": "MIT", "dependencies": { @@ -4319,9 +4319,9 @@ } }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.45.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.45.1.tgz", - "integrity": "sha512-NEySIFvMY0ZQO+utJkgoMiCAjMrGvnbDLHvcmlA33UXJpYBCvlBEbMMtV837uCkS+plG2umfhn0T5mMAxGrlRA==", + "version": "4.46.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.46.1.tgz", + "integrity": "sha512-oENme6QxtLCqjChRUUo3S6X8hjCXnWmJWnedD7VbGML5GUtaOtAyx+fEEXnBXVf0CBZApMQU0Idwi0FmyxzQhw==", "cpu": [ "arm" ], @@ -4332,9 +4332,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.45.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.45.1.tgz", - "integrity": "sha512-ujQ+sMXJkg4LRJaYreaVx7Z/VMgBBd89wGS4qMrdtfUFZ+TSY5Rs9asgjitLwzeIbhwdEhyj29zhst3L1lKsRQ==", + "version": "4.46.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.46.1.tgz", + "integrity": "sha512-OikvNT3qYTl9+4qQ9Bpn6+XHM+ogtFadRLuT2EXiFQMiNkXFLQfNVppi5o28wvYdHL2s3fM0D/MZJ8UkNFZWsw==", "cpu": [ "arm64" ], @@ -4345,9 +4345,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.45.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.45.1.tgz", - "integrity": "sha512-FSncqHvqTm3lC6Y13xncsdOYfxGSLnP+73k815EfNmpewPs+EyM49haPS105Rh4aF5mJKywk9X0ogzLXZzN9lA==", + "version": "4.46.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.46.1.tgz", + "integrity": "sha512-EFYNNGij2WllnzljQDQnlFTXzSJw87cpAs4TVBAWLdkvic5Uh5tISrIL6NRcxoh/b2EFBG/TK8hgRrGx94zD4A==", "cpu": [ "arm64" ], @@ -4358,9 +4358,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.45.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.45.1.tgz", - "integrity": "sha512-2/vVn/husP5XI7Fsf/RlhDaQJ7x9zjvC81anIVbr4b/f0xtSmXQTFcGIQ/B1cXIYM6h2nAhJkdMHTnD7OtQ9Og==", + "version": "4.46.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.46.1.tgz", + "integrity": "sha512-ZaNH06O1KeTug9WI2+GRBE5Ujt9kZw4a1+OIwnBHal92I8PxSsl5KpsrPvthRynkhMck4XPdvY0z26Cym/b7oA==", "cpu": [ "x64" ], @@ -4371,9 +4371,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.45.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.45.1.tgz", - "integrity": "sha512-4g1kaDxQItZsrkVTdYQ0bxu4ZIQ32cotoQbmsAnW1jAE4XCMbcBPDirX5fyUzdhVCKgPcrwWuucI8yrVRBw2+g==", + "version": "4.46.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.46.1.tgz", + "integrity": "sha512-n4SLVebZP8uUlJ2r04+g2U/xFeiQlw09Me5UFqny8HGbARl503LNH5CqFTb5U5jNxTouhRjai6qPT0CR5c/Iig==", "cpu": [ "arm64" ], @@ -4384,9 +4384,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.45.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.45.1.tgz", - "integrity": "sha512-L/6JsfiL74i3uK1Ti2ZFSNsp5NMiM4/kbbGEcOCps99aZx3g8SJMO1/9Y0n/qKlWZfn6sScf98lEOUe2mBvW9A==", + "version": "4.46.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.46.1.tgz", + "integrity": "sha512-8vu9c02F16heTqpvo3yeiu7Vi1REDEC/yES/dIfq3tSXe6mLndiwvYr3AAvd1tMNUqE9yeGYa5w7PRbI5QUV+w==", "cpu": [ "x64" ], @@ -4397,9 +4397,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.45.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.45.1.tgz", - "integrity": "sha512-RkdOTu2jK7brlu+ZwjMIZfdV2sSYHK2qR08FUWcIoqJC2eywHbXr0L8T/pONFwkGukQqERDheaGTeedG+rra6Q==", + "version": "4.46.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.46.1.tgz", + "integrity": "sha512-K4ncpWl7sQuyp6rWiGUvb6Q18ba8mzM0rjWJ5JgYKlIXAau1db7hZnR0ldJvqKWWJDxqzSLwGUhA4jp+KqgDtQ==", "cpu": [ "arm" ], @@ -4410,9 +4410,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.45.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.45.1.tgz", - "integrity": "sha512-3kJ8pgfBt6CIIr1o+HQA7OZ9mp/zDk3ctekGl9qn/pRBgrRgfwiffaUmqioUGN9hv0OHv2gxmvdKOkARCtRb8Q==", + "version": "4.46.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.46.1.tgz", + "integrity": "sha512-YykPnXsjUjmXE6j6k2QBBGAn1YsJUix7pYaPLK3RVE0bQL2jfdbfykPxfF8AgBlqtYbfEnYHmLXNa6QETjdOjQ==", "cpu": [ "arm" ], @@ -4423,9 +4423,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.45.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.45.1.tgz", - "integrity": "sha512-k3dOKCfIVixWjG7OXTCOmDfJj3vbdhN0QYEqB+OuGArOChek22hn7Uy5A/gTDNAcCy5v2YcXRJ/Qcnm4/ma1xw==", + "version": "4.46.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.46.1.tgz", + "integrity": "sha512-kKvqBGbZ8i9pCGW3a1FH3HNIVg49dXXTsChGFsHGXQaVJPLA4f/O+XmTxfklhccxdF5FefUn2hvkoGJH0ScWOA==", "cpu": [ "arm64" ], @@ -4436,9 +4436,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.45.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.45.1.tgz", - "integrity": "sha512-PmI1vxQetnM58ZmDFl9/Uk2lpBBby6B6rF4muJc65uZbxCs0EA7hhKCk2PKlmZKuyVSHAyIw3+/SiuMLxKxWog==", + "version": "4.46.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.46.1.tgz", + "integrity": "sha512-zzX5nTw1N1plmqC9RGC9vZHFuiM7ZP7oSWQGqpbmfjK7p947D518cVK1/MQudsBdcD84t6k70WNczJOct6+hdg==", "cpu": [ "arm64" ], @@ -4449,9 +4449,9 @@ ] }, "node_modules/@rollup/rollup-linux-loongarch64-gnu": { - "version": "4.45.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.45.1.tgz", - "integrity": "sha512-9UmI0VzGmNJ28ibHW2GpE2nF0PBQqsyiS4kcJ5vK+wuwGnV5RlqdczVocDSUfGX/Na7/XINRVoUgJyFIgipoRg==", + "version": "4.46.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.46.1.tgz", + "integrity": "sha512-O8CwgSBo6ewPpktFfSDgB6SJN9XDcPSvuwxfejiddbIC/hn9Tg6Ai0f0eYDf3XvB/+PIWzOQL+7+TZoB8p9Yuw==", "cpu": [ "loong64" ], @@ -4461,10 +4461,10 @@ "linux" ] }, - "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.45.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.45.1.tgz", - "integrity": "sha512-7nR2KY8oEOUTD3pBAxIBBbZr0U7U+R9HDTPNy+5nVVHDXI4ikYniH1oxQz9VoB5PbBU1CZuDGHkLJkd3zLMWsg==", + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.46.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.46.1.tgz", + "integrity": "sha512-JnCfFVEKeq6G3h3z8e60kAp8Rd7QVnWCtPm7cxx+5OtP80g/3nmPtfdCXbVl063e3KsRnGSKDHUQMydmzc/wBA==", "cpu": [ "ppc64" ], @@ -4475,9 +4475,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.45.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.45.1.tgz", - "integrity": "sha512-nlcl3jgUultKROfZijKjRQLUu9Ma0PeNv/VFHkZiKbXTBQXhpytS8CIj5/NfBeECZtY2FJQubm6ltIxm/ftxpw==", + "version": "4.46.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.46.1.tgz", + "integrity": "sha512-dVxuDqS237eQXkbYzQQfdf/njgeNw6LZuVyEdUaWwRpKHhsLI+y4H/NJV8xJGU19vnOJCVwaBFgr936FHOnJsQ==", "cpu": [ "riscv64" ], @@ -4488,9 +4488,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.45.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.45.1.tgz", - "integrity": "sha512-HJV65KLS51rW0VY6rvZkiieiBnurSzpzore1bMKAhunQiECPuxsROvyeaot/tcK3A3aGnI+qTHqisrpSgQrpgA==", + "version": "4.46.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.46.1.tgz", + "integrity": "sha512-CvvgNl2hrZrTR9jXK1ye0Go0HQRT6ohQdDfWR47/KFKiLd5oN5T14jRdUVGF4tnsN8y9oSfMOqH6RuHh+ck8+w==", "cpu": [ "riscv64" ], @@ -4501,9 +4501,9 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.45.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.45.1.tgz", - "integrity": "sha512-NITBOCv3Qqc6hhwFt7jLV78VEO/il4YcBzoMGGNxznLgRQf43VQDae0aAzKiBeEPIxnDrACiMgbqjuihx08OOw==", + "version": "4.46.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.46.1.tgz", + "integrity": "sha512-x7ANt2VOg2565oGHJ6rIuuAon+A8sfe1IeUx25IKqi49OjSr/K3awoNqr9gCwGEJo9OuXlOn+H2p1VJKx1psxA==", "cpu": [ "s390x" ], @@ -4514,9 +4514,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.45.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.45.1.tgz", - "integrity": "sha512-+E/lYl6qu1zqgPEnTrs4WysQtvc/Sh4fC2nByfFExqgYrqkKWp1tWIbe+ELhixnenSpBbLXNi6vbEEJ8M7fiHw==", + "version": "4.46.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.46.1.tgz", + "integrity": "sha512-9OADZYryz/7E8/qt0vnaHQgmia2Y0wrjSSn1V/uL+zw/i7NUhxbX4cHXdEQ7dnJgzYDS81d8+tf6nbIdRFZQoQ==", "cpu": [ "x64" ], @@ -4527,9 +4527,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.45.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.45.1.tgz", - "integrity": "sha512-a6WIAp89p3kpNoYStITT9RbTbTnqarU7D8N8F2CV+4Cl9fwCOZraLVuVFvlpsW0SbIiYtEnhCZBPLoNdRkjQFw==", + "version": "4.46.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.46.1.tgz", + "integrity": "sha512-NuvSCbXEKY+NGWHyivzbjSVJi68Xfq1VnIvGmsuXs6TCtveeoDRKutI5vf2ntmNnVq64Q4zInet0UDQ+yMB6tA==", "cpu": [ "x64" ], @@ -4540,9 +4540,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.45.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.45.1.tgz", - "integrity": "sha512-T5Bi/NS3fQiJeYdGvRpTAP5P02kqSOpqiopwhj0uaXB6nzs5JVi2XMJb18JUSKhCOX8+UE1UKQufyD6Or48dJg==", + "version": "4.46.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.46.1.tgz", + "integrity": "sha512-mWz+6FSRb82xuUMMV1X3NGiaPFqbLN9aIueHleTZCc46cJvwTlvIh7reQLk4p97dv0nddyewBhwzryBHH7wtPw==", "cpu": [ "arm64" ], @@ -4553,9 +4553,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.45.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.45.1.tgz", - "integrity": "sha512-lxV2Pako3ujjuUe9jiU3/s7KSrDfH6IgTSQOnDWr9aJ92YsFd7EurmClK0ly/t8dzMkDtd04g60WX6yl0sGfdw==", + "version": "4.46.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.46.1.tgz", + "integrity": "sha512-7Thzy9TMXDw9AU4f4vsLNBxh7/VOKuXi73VH3d/kHGr0tZ3x/ewgL9uC7ojUKmH1/zvmZe2tLapYcZllk3SO8Q==", "cpu": [ "ia32" ], @@ -4566,9 +4566,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.45.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.45.1.tgz", - "integrity": "sha512-M/fKi4sasCdM8i0aWJjCSFm2qEnYRR8AMLG2kxp6wD13+tMGA4Z1tVAuHkNRjud5SW2EM3naLuK35w9twvf6aA==", + "version": "4.46.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.46.1.tgz", + "integrity": "sha512-7GVB4luhFmGUNXXJhH2jJwZCFB3pIOixv2E3s17GQHBFUOQaISlt7aGcQgqvCaDSxTZJUzlK/QJ1FN8S94MrzQ==", "cpu": [ "x64" ], @@ -4653,13 +4653,12 @@ } }, "node_modules/@sinonjs/samsam": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-8.0.2.tgz", - "integrity": "sha512-v46t/fwnhejRSFTGqbpn9u+LQ9xJDse10gNnPgAcxgdoCDMXj/G2asWAC/8Qs+BAZDicX+MNZouXT1A7c83kVw==", + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-8.0.3.tgz", + "integrity": "sha512-hw6HbX+GyVZzmaYNh82Ecj1vdGZrqVIn/keDTg63IgAwiQPO+xCz99uG6Woqgb4tM0mUiFENKZ4cqd7IX94AXQ==", "license": "BSD-3-Clause", "dependencies": { "@sinonjs/commons": "^3.0.1", - "lodash.get": "^4.4.2", "type-detect": "^4.1.0" } }, @@ -4728,9 +4727,9 @@ } }, "node_modules/@smithy/core": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.7.1.tgz", - "integrity": "sha512-ExRCsHnXFtBPnM7MkfKBPcBBdHw1h/QS/cbNw4ho95qnyNHvnpmGbR39MIAv9KggTr5qSPxRSEL+hRXlyGyGQw==", + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.7.2.tgz", + "integrity": "sha512-JoLw59sT5Bm8SAjFCYZyuCGxK8y3vovmoVbZWLDPTH5XpPEIwpFd9m90jjVMwoypDuB/SdVgje5Y4T7w50lJaw==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -4962,13 +4961,13 @@ } }, "node_modules/@smithy/middleware-endpoint": { - "version": "4.1.16", - "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-4.1.16.tgz", - "integrity": "sha512-plpa50PIGLqzMR2ANKAw2yOW5YKS626KYKqae3atwucbz4Ve4uQ9K9BEZxDLIFmCu7hKLcrq2zmj4a+PfmUV5w==", + "version": "4.1.17", + "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-4.1.17.tgz", + "integrity": "sha512-S3hSGLKmHG1m35p/MObQCBCdRsrpbPU8B129BVzRqRfDvQqPMQ14iO4LyRw+7LNizYc605COYAcjqgawqi+6jA==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@smithy/core": "^3.7.1", + "@smithy/core": "^3.7.2", "@smithy/middleware-serde": "^4.0.8", "@smithy/node-config-provider": "^4.1.3", "@smithy/shared-ini-file-loader": "^4.0.4", @@ -4982,16 +4981,16 @@ } }, "node_modules/@smithy/middleware-retry": { - "version": "4.1.17", - "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-4.1.17.tgz", - "integrity": "sha512-gsCimeG6BApj0SBecwa1Be+Z+JOJe46iy3B3m3A8jKJHf7eIihP76Is4LwLrbJ1ygoS7Vg73lfqzejmLOrazUA==", + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-4.1.18.tgz", + "integrity": "sha512-bYLZ4DkoxSsPxpdmeapvAKy7rM5+25gR7PGxq2iMiecmbrRGBHj9s75N74Ylg+aBiw9i5jIowC/cLU2NR0qH8w==", "dev": true, "license": "Apache-2.0", "dependencies": { "@smithy/node-config-provider": "^4.1.3", "@smithy/protocol-http": "^5.1.2", "@smithy/service-error-classification": "^4.0.6", - "@smithy/smithy-client": "^4.4.8", + "@smithy/smithy-client": "^4.4.9", "@smithy/types": "^4.3.1", "@smithy/util-middleware": "^4.0.4", "@smithy/util-retry": "^4.0.6", @@ -5169,14 +5168,14 @@ } }, "node_modules/@smithy/smithy-client": { - "version": "4.4.8", - "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-4.4.8.tgz", - "integrity": "sha512-pcW691/lx7V54gE+dDGC26nxz8nrvnvRSCJaIYD6XLPpOInEZeKdV/SpSux+wqeQ4Ine7LJQu8uxMvobTIBK0w==", + "version": "4.4.9", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-4.4.9.tgz", + "integrity": "sha512-mbMg8mIUAWwMmb74LoYiArP04zWElPzDoA1jVOp3or0cjlDMgoS6WTC3QXK0Vxoc9I4zdrX0tq6qsOmaIoTWEQ==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@smithy/core": "^3.7.1", - "@smithy/middleware-endpoint": "^4.1.16", + "@smithy/core": "^3.7.2", + "@smithy/middleware-endpoint": "^4.1.17", "@smithy/middleware-stack": "^4.0.4", "@smithy/protocol-http": "^5.1.2", "@smithy/types": "^4.3.1", @@ -5284,14 +5283,14 @@ } }, "node_modules/@smithy/util-defaults-mode-browser": { - "version": "4.0.24", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-4.0.24.tgz", - "integrity": "sha512-UkQNgaQ+bidw1MgdgPO1z1k95W/v8Ej/5o/T/Is8PiVUYPspl/ZxV6WO/8DrzZQu5ULnmpB9CDdMSRwgRc21AA==", + "version": "4.0.25", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-4.0.25.tgz", + "integrity": "sha512-pxEWsxIsOPLfKNXvpgFHBGFC3pKYKUFhrud1kyooO9CJai6aaKDHfT10Mi5iiipPXN/JhKAu3qX9o75+X85OdQ==", "dev": true, "license": "Apache-2.0", "dependencies": { "@smithy/property-provider": "^4.0.4", - "@smithy/smithy-client": "^4.4.8", + "@smithy/smithy-client": "^4.4.9", "@smithy/types": "^4.3.1", "bowser": "^2.11.0", "tslib": "^2.6.2" @@ -5301,9 +5300,9 @@ } }, "node_modules/@smithy/util-defaults-mode-node": { - "version": "4.0.24", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-4.0.24.tgz", - "integrity": "sha512-phvGi/15Z4MpuQibTLOYIumvLdXb+XIJu8TA55voGgboln85jytA3wiD7CkUE8SNcWqkkb+uptZKPiuFouX/7g==", + "version": "4.0.25", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-4.0.25.tgz", + "integrity": "sha512-+w4n4hKFayeCyELZLfsSQG5mCC3TwSkmRHv4+el5CzFU8ToQpYGhpV7mrRzqlwKkntlPilT1HJy1TVeEvEjWOQ==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -5311,7 +5310,7 @@ "@smithy/credential-provider-imds": "^4.0.6", "@smithy/node-config-provider": "^4.1.3", "@smithy/property-provider": "^4.0.4", - "@smithy/smithy-client": "^4.4.8", + "@smithy/smithy-client": "^4.4.9", "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, @@ -7295,13 +7294,13 @@ } }, "node_modules/axios": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.10.0.tgz", - "integrity": "sha512-/1xYAC4MP/HEG+3duIhFr4ZQXR4sQXOIe+o6sdqzeykGLx6Upp/1p8MHqhINOvGeP7xyNHe7tsiJByc4SSVUxw==", + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.11.0.tgz", + "integrity": "sha512-1Lx3WLFQWm3ooKDYZD1eXmoGO9fxYQjrycfHFC8P0sCfQVXyROp0p9PFWBehewBOdCwHc+f/b8I0fMto5eSfwA==", "license": "MIT", "dependencies": { "follow-redirects": "^1.15.6", - "form-data": "^4.0.0", + "form-data": "^4.0.4", "proxy-from-env": "^1.1.0" } }, @@ -9579,9 +9578,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.5.189", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.189.tgz", - "integrity": "sha512-y9D1ntS1ruO/pZ/V2FtLE+JXLQe28XoRpZ7QCCo0T8LdQladzdcOVQZH/IWLVJvCw12OGMb6hYOeOAjntCmJRQ==", + "version": "1.5.191", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.191.tgz", + "integrity": "sha512-xcwe9ELcuxYLUFqZZxL19Z6HVKcvNkIwhbHUz7L3us6u12yR+7uY89dSl570f/IqNthx8dAw3tojG7i4Ni4tDA==", "license": "ISC" }, "node_modules/elegant-spinner": { @@ -9972,9 +9971,9 @@ } }, "node_modules/eslint-config-oclif": { - "version": "6.0.87", - "resolved": "https://registry.npmjs.org/eslint-config-oclif/-/eslint-config-oclif-6.0.87.tgz", - "integrity": "sha512-qU1WdrQCt+F+21dg/S1yHnjLxy9bSZ49HX9l0YqoGM4c9qHydLDIFAEEqbsgJqgz/9cQJ9jFiZUQefQfJLnAvw==", + "version": "6.0.89", + "resolved": "https://registry.npmjs.org/eslint-config-oclif/-/eslint-config-oclif-6.0.89.tgz", + "integrity": "sha512-c4SRbD8WyTzdRkLOwrimz72DxmZfjLVo1Yklsmgd2JdZiFOjtdRfqoTeefFnzxUEZQ8Ws2QijpHicYMOpbjhpg==", "dev": true, "license": "MIT", "dependencies": { @@ -9985,7 +9984,7 @@ "@typescript-eslint/eslint-plugin": "^8", "@typescript-eslint/parser": "^8", "eslint-config-oclif": "^5.2.2", - "eslint-config-xo": "^0.47.0", + "eslint-config-xo": "^0.48.0", "eslint-config-xo-space": "^0.35.0", "eslint-import-resolver-typescript": "^3.10.1", "eslint-plugin-import": "^2.32.0", @@ -9994,7 +9993,7 @@ "eslint-plugin-n": "^17.21.0", "eslint-plugin-perfectionist": "^4", "eslint-plugin-unicorn": "^56.0.1", - "typescript-eslint": "^8.37.0" + "typescript-eslint": "^8.38.0" }, "engines": { "node": ">=18.18.0" @@ -10412,9 +10411,9 @@ } }, "node_modules/eslint-config-oclif/node_modules/@eslint/js": { - "version": "9.31.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.31.0.tgz", - "integrity": "sha512-LOm5OVt7D4qiKCqoiPbA7LWmI+tbw1VbTUowBcUMgQSuM6poJufkFkYDcQpo5KfgD39TnNySV26QjOh7VFpSyw==", + "version": "9.32.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.32.0.tgz", + "integrity": "sha512-BBpRFZK3eX6uMLKz8WxFOBIFFcGFJ/g8XuwjTHCqHROSIsopI+ddn/d5Cfh36+7+e5edVS8dbSHnBNhrLEX0zg==", "dev": true, "license": "MIT", "engines": { @@ -10667,9 +10666,9 @@ } }, "node_modules/eslint-config-oclif/node_modules/eslint": { - "version": "9.31.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.31.0.tgz", - "integrity": "sha512-QldCVh/ztyKJJZLr4jXNUByx3gR+TDYZCRXEktiZoUR3PGy4qCmSbkxcIle8GEwGpb5JBZazlaJ/CxLidXdEbQ==", + "version": "9.32.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.32.0.tgz", + "integrity": "sha512-LSehfdpgMeWcTZkWZVIJl+tkZ2nuSkyyB9C27MZqFWXuph7DvaowgcTvKqxvpLW1JZIk8PN7hFY3Rj9LQ7m7lg==", "dev": true, "license": "MIT", "peer": true, @@ -10680,8 +10679,8 @@ "@eslint/config-helpers": "^0.3.0", "@eslint/core": "^0.15.0", "@eslint/eslintrc": "^3.3.1", - "@eslint/js": "9.31.0", - "@eslint/plugin-kit": "^0.3.1", + "@eslint/js": "9.32.0", + "@eslint/plugin-kit": "^0.3.4", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", @@ -10804,9 +10803,9 @@ } }, "node_modules/eslint-config-oclif/node_modules/eslint-config-xo": { - "version": "0.47.0", - "resolved": "https://registry.npmjs.org/eslint-config-xo/-/eslint-config-xo-0.47.0.tgz", - "integrity": "sha512-LWB0VXFI3EzZ5jJLH/F/Ph0XVnEe5Imqd1gEMWZqvdnQfHAPDs1E+v3WMZysmpOd57a1qUMeT/LCdkkwJlo3Dw==", + "version": "0.48.0", + "resolved": "https://registry.npmjs.org/eslint-config-xo/-/eslint-config-xo-0.48.0.tgz", + "integrity": "sha512-zINsjr18HJQtTRfod95Vz5wAwcIuN1ss8tRqFdSqj8fvXxJNYLrnEpE+Vderxu4Ydm3yIhYNyEUuP/c4wZerWA==", "dev": true, "license": "MIT", "dependencies": { @@ -10823,7 +10822,7 @@ "url": "https://github.com/sponsors/sindresorhus" }, "peerDependencies": { - "eslint": ">=9.25.0" + "eslint": ">=9.27.0" } }, "node_modules/eslint-config-oclif/node_modules/eslint-config-xo/node_modules/@stylistic/eslint-plugin": { @@ -11338,9 +11337,9 @@ } }, "node_modules/eslint-plugin-n": { - "version": "17.21.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-17.21.0.tgz", - "integrity": "sha512-1+iZ8We4ZlwVMtb/DcHG3y5/bZOdazIpa/4TySo22MLKdwrLcfrX0hbadnCvykSQCCmkAnWmIP8jZVb2AAq29A==", + "version": "17.21.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-17.21.2.tgz", + "integrity": "sha512-s3ai4Msfk5mbSvOgCkYo6k5+zP3W/OK+AvLmMmx++Ki4a5CPO7luIDwOnjUZm/t+oZYP0YADTxe+u4JqnT8+Dg==", "dev": true, "license": "MIT", "dependencies": { @@ -11349,8 +11348,8 @@ "eslint-plugin-es-x": "^7.8.0", "get-tsconfig": "^4.8.1", "globals": "^15.11.0", + "globrex": "^0.1.2", "ignore": "^5.3.2", - "minimatch": "^9.0.5", "semver": "^7.6.3", "ts-declaration-location": "^1.0.6" }, @@ -12957,6 +12956,13 @@ "node": ">=8" } }, + "node_modules/globrex": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz", + "integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==", + "dev": true, + "license": "MIT" + }, "node_modules/gopd": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", @@ -18751,13 +18757,6 @@ "dev": true, "license": "MIT" }, - "node_modules/lodash.get": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", - "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==", - "deprecated": "This package is deprecated. Use the optional chaining (?.) operator instead.", - "license": "MIT" - }, "node_modules/lodash.groupby": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/lodash.groupby/-/lodash.groupby-4.6.0.tgz", @@ -22261,9 +22260,9 @@ } }, "node_modules/nwsapi": { - "version": "2.2.20", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.20.tgz", - "integrity": "sha512-/ieB+mDe4MrrKMT8z+mQL8klXydZWGR5Dowt4RAGKbJ3kIGEx3X4ljUo+6V73IXtUPWgfOlU5B9MlGxFO5T+cA==", + "version": "2.2.21", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.21.tgz", + "integrity": "sha512-o6nIY3qwiSXl7/LuOU0Dmuctd34Yay0yeuZRLFmDPrrdHpXKFndPj3hM+YEPVHYC5fx2otBx4Ilc/gyYSAUaIA==", "license": "MIT" }, "node_modules/nyc": { @@ -22664,20 +22663,20 @@ } }, "node_modules/oclif": { - "version": "4.22.0", - "resolved": "https://registry.npmjs.org/oclif/-/oclif-4.22.0.tgz", - "integrity": "sha512-u6TnSY2pTTO4v1QZVf3Ql54BJNTyO03THGlVFdjeJtUsqy6eSz5cvNJP3v5hZBf7SYxzHF2K3JrgAV0bfcqXbg==", + "version": "4.22.5", + "resolved": "https://registry.npmjs.org/oclif/-/oclif-4.22.5.tgz", + "integrity": "sha512-1TViD9V+y3zLnnBzV3cNsKzXxMY7doEcxwny7eqiW4OHDU3PNTPWngG/aidzlKLDXGbajTdjtUpX69UXF78Ahw==", "dev": true, "license": "MIT", "dependencies": { - "@aws-sdk/client-cloudfront": "^3.844.0", - "@aws-sdk/client-s3": "^3.848.0", + "@aws-sdk/client-cloudfront": "^3.850.0", + "@aws-sdk/client-s3": "^3.850.0", "@inquirer/confirm": "^3.1.22", "@inquirer/input": "^2.2.4", "@inquirer/select": "^2.5.0", - "@oclif/core": "^4.5.1", + "@oclif/core": "^4.5.2", "@oclif/plugin-help": "^6.2.29", - "@oclif/plugin-not-found": "^3.2.59", + "@oclif/plugin-not-found": "^3.2.61", "@oclif/plugin-warn-if-update-available": "^3.1.44", "ansis": "^3.16.0", "async-retry": "^1.3.3", @@ -24687,9 +24686,9 @@ } }, "node_modules/rollup": { - "version": "4.45.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.45.1.tgz", - "integrity": "sha512-4iya7Jb76fVpQyLoiVpzUrsjQ12r3dM7fIVz+4NwoYvZOShknRmiv+iu9CClZml5ZLGb0XMcYLutK6w9tgxHDw==", + "version": "4.46.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.46.1.tgz", + "integrity": "sha512-33xGNBsDJAkzt0PvninskHlWnTIPgDtTwhg0U38CUoNP/7H6wI2Cz6dUeoNPbjdTdsYTGuiFFASuUOWovH0SyQ==", "license": "MIT", "dependencies": { "@types/estree": "1.0.8" @@ -24702,26 +24701,26 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.45.1", - "@rollup/rollup-android-arm64": "4.45.1", - "@rollup/rollup-darwin-arm64": "4.45.1", - "@rollup/rollup-darwin-x64": "4.45.1", - "@rollup/rollup-freebsd-arm64": "4.45.1", - "@rollup/rollup-freebsd-x64": "4.45.1", - "@rollup/rollup-linux-arm-gnueabihf": "4.45.1", - "@rollup/rollup-linux-arm-musleabihf": "4.45.1", - "@rollup/rollup-linux-arm64-gnu": "4.45.1", - "@rollup/rollup-linux-arm64-musl": "4.45.1", - "@rollup/rollup-linux-loongarch64-gnu": "4.45.1", - "@rollup/rollup-linux-powerpc64le-gnu": "4.45.1", - "@rollup/rollup-linux-riscv64-gnu": "4.45.1", - "@rollup/rollup-linux-riscv64-musl": "4.45.1", - "@rollup/rollup-linux-s390x-gnu": "4.45.1", - "@rollup/rollup-linux-x64-gnu": "4.45.1", - "@rollup/rollup-linux-x64-musl": "4.45.1", - "@rollup/rollup-win32-arm64-msvc": "4.45.1", - "@rollup/rollup-win32-ia32-msvc": "4.45.1", - "@rollup/rollup-win32-x64-msvc": "4.45.1", + "@rollup/rollup-android-arm-eabi": "4.46.1", + "@rollup/rollup-android-arm64": "4.46.1", + "@rollup/rollup-darwin-arm64": "4.46.1", + "@rollup/rollup-darwin-x64": "4.46.1", + "@rollup/rollup-freebsd-arm64": "4.46.1", + "@rollup/rollup-freebsd-x64": "4.46.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.46.1", + "@rollup/rollup-linux-arm-musleabihf": "4.46.1", + "@rollup/rollup-linux-arm64-gnu": "4.46.1", + "@rollup/rollup-linux-arm64-musl": "4.46.1", + "@rollup/rollup-linux-loongarch64-gnu": "4.46.1", + "@rollup/rollup-linux-ppc64-gnu": "4.46.1", + "@rollup/rollup-linux-riscv64-gnu": "4.46.1", + "@rollup/rollup-linux-riscv64-musl": "4.46.1", + "@rollup/rollup-linux-s390x-gnu": "4.46.1", + "@rollup/rollup-linux-x64-gnu": "4.46.1", + "@rollup/rollup-linux-x64-musl": "4.46.1", + "@rollup/rollup-win32-arm64-msvc": "4.46.1", + "@rollup/rollup-win32-ia32-msvc": "4.46.1", + "@rollup/rollup-win32-x64-msvc": "4.46.1", "fsevents": "~2.3.2" } }, @@ -28206,7 +28205,7 @@ "@contentstack/cli-auth": "~1.5.0", "@contentstack/cli-cm-bootstrap": "~1.15.0", "@contentstack/cli-cm-branches": "~1.5.0", - "@contentstack/cli-cm-bulk-publish": "~1.9.0", + "@contentstack/cli-cm-bulk-publish": "~1.9.1", "@contentstack/cli-cm-clone": "~1.15.0", "@contentstack/cli-cm-export": "~1.18.0", "@contentstack/cli-cm-export-to-csv": "~1.9.0", @@ -28631,7 +28630,7 @@ }, "packages/contentstack-bulk-publish": { "name": "@contentstack/cli-cm-bulk-publish", - "version": "1.9.0", + "version": "1.9.1", "license": "MIT", "dependencies": { "@contentstack/cli-command": "~1.6.0", diff --git a/packages/contentstack-bulk-publish/package.json b/packages/contentstack-bulk-publish/package.json index 269aacb941..cd4915a1b1 100644 --- a/packages/contentstack-bulk-publish/package.json +++ b/packages/contentstack-bulk-publish/package.json @@ -1,7 +1,7 @@ { "name": "@contentstack/cli-cm-bulk-publish", "description": "Contentstack CLI plugin for bulk publish actions", - "version": "1.9.0", + "version": "1.9.1", "author": "Contentstack", "bugs": "https://github.com/contentstack/cli/issues", "dependencies": { diff --git a/packages/contentstack-bulk-publish/src/consumer/publish.js b/packages/contentstack-bulk-publish/src/consumer/publish.js index e7b95649a5..62523697fa 100644 --- a/packages/contentstack-bulk-publish/src/consumer/publish.js +++ b/packages/contentstack-bulk-publish/src/consumer/publish.js @@ -11,9 +11,15 @@ const nrpApiVersionWarning = `Provided apiVersion is invalid. ${apiVersionForNRP const { getLoggerInstance, addLogs, getLogsDirPath } = require('../util/logger'); const { sanitizePath } = require('@contentstack/cli-utilities'); const logsDir = getLogsDirPath(); +const { handleRateLimit, fetchBulkPublishLimit } = require('../util/common-utility'); +const { createSmartRateLimiter } = require('../util/smart-rate-limiter'); + +// Simple delay function +const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms)); let logger; let fileNme; +let smartRateLimiter; function initializeLogger(fileName) { fileNme = fileName; @@ -60,23 +66,23 @@ function displayAssetsDetails(sanitizedData, action, mapping) { sanitizedData.forEach((asset) => { asset?.publish_details.forEach((pd) => { 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}`, - ), - ); - } + const versionText = pd.version ? `and version '${pd.version}'` : ''; + const localeText = asset.locale ? `in locale '${asset.locale}'` : ''; + console.log( + chalk.green( + `Asset UID '${asset.uid}' ${versionText} ${localeText} in environment ${pd.environment}`, + ), + ); + } }); }); } else if (action === 'bulk_unpublish') { sanitizedData.forEach((asset) => { + const versionText = asset.version ? `and version '${asset.version}'` : ''; + const localeText = asset.locale ? `in locale '${asset.locale}'` : ''; console.log( chalk.green( - `Asset UID '${asset.uid}' ${asset.version ? `and version '${asset.version}'` : ''} ${ - asset.locale ? `in locale '${asset.locale}'` : '' - }`, + `Asset UID '${asset.uid}' and version ${versionText} in locale ${localeText}`, ), ); }); @@ -86,7 +92,24 @@ async function publishEntry(data, _config, queue) { const lang = []; const entryObj = data.obj; const stack = entryObj.stack; + + // Get smart rate limiter instance (singleton per organization) + smartRateLimiter = createSmartRateLimiter(stack?.org_uid); + lang.push(entryObj.locale); + + // Check if we can process this item + if (!smartRateLimiter.canProcess(1)) { + smartRateLimiter.logStatus(); + // Put the item back in queue and wait + await delay(1000); + queue.Enqueue(data); + return; + } + + // Log request attempt + smartRateLimiter.logRequestAttempt('publish', 'entry', entryObj.entryUid); + stack .contentType(entryObj.content_type) .entry(entryObj.entryUid) @@ -96,6 +119,12 @@ async function publishEntry(data, _config, queue) { }) .then((publishEntryResponse) => { if (!publishEntryResponse.error_message) { + // Update rate limit from server response + smartRateLimiter.updateRateLimit(publishEntryResponse); + + // Log success + smartRateLimiter.logRequestSuccess('publish', 'entry', entryObj.entryUid, publishEntryResponse); + console.log( chalk.green( `entry published with ContentType uid=${entryObj.content_type} Entry uid=${entryObj.entryUid} locale=${entryObj.locale}`, @@ -111,9 +140,15 @@ async function publishEntry(data, _config, queue) { throw publishEntryResponse; } }) - .catch((error) => { + .catch(async (error) => { + // Log failure + smartRateLimiter.logRequestFailure('publish', 'entry', entryObj.entryUid, error); + if (error.errorCode === 429 && data.retry < 2) { data.retry++; + smartRateLimiter.logStatus(); + // Wait and retry + await delay(1000); queue.Enqueue(data); } else { delete entryObj.stack; @@ -141,12 +176,33 @@ async function publishEntry(data, _config, queue) { async function publishAsset(data, _config, queue) { const assetobj = data.obj; const stack = assetobj.stack; + + // Get smart rate limiter instance (singleton per organization) + smartRateLimiter = createSmartRateLimiter(stack?.org_uid); + + // Check if we can process this item + if (!smartRateLimiter.canProcess(1)) { + smartRateLimiter.logStatus(); + // Put the item back in queue and wait + await delay(1000); + queue.Enqueue(data); + return; + } + + // Log request attempt + smartRateLimiter.logRequestAttempt('publish', 'asset', assetobj.assetUid); stack .asset(assetobj.assetUid) .publish({ publishDetails: { environments: assetobj.environments, locales: [assetobj.locale || 'en-us'] } }) .then((publishAssetResponse) => { if (!publishAssetResponse.error_message) { + // Update rate limit from server response + smartRateLimiter.updateRateLimit(publishAssetResponse); + + // Log success + smartRateLimiter.logRequestSuccess('publish', 'asset', assetobj.assetUid, publishAssetResponse); + console.log(chalk.green(`asset published with Asset uid=${assetobj.assetUid}, locale=${assetobj.locale}`)); delete assetobj.stack; addLogs( @@ -158,9 +214,15 @@ async function publishAsset(data, _config, queue) { throw publishAssetResponse; } }) - .catch((error) => { + .catch(async (error) => { + // Log failure + smartRateLimiter.logRequestFailure('publish', 'asset', assetobj.assetUid, error); + if (error.errorCode === 429 && data.retry < 2) { data.retry++; + smartRateLimiter.logStatus(); + // Wait and retry + await delay(1000); queue.Enqueue(data); } else { delete assetobj.stack; @@ -183,13 +245,36 @@ async function UnpublishEntry(data, _config, queue) { const lang = []; const entryObj = data.obj; const stack = entryObj.stack; + + // Get smart rate limiter instance (singleton per organization) + smartRateLimiter = createSmartRateLimiter(stack?.org_uid); + lang.push(entryObj.locale); + + // Check if we can process this item + if (!smartRateLimiter.canProcess(1)) { + smartRateLimiter.logStatus(); + // Put the item back in queue and wait + await delay(1000); + queue.Enqueue(data); + return; + } + + // Log request attempt + smartRateLimiter.logRequestAttempt('unpublish', 'entry', entryObj.entryUid); + stack .contentType(entryObj.content_type) .entry(entryObj.entryUid) .unpublish({ publishDetails: { environments: entryObj.environments, locales: lang }, locale: entryObj.locale }) .then((unpublishEntryResponse) => { if (!unpublishEntryResponse.error_message) { + // Update rate limit from server response + smartRateLimiter.updateRateLimit(unpublishEntryResponse); + + // Log success + smartRateLimiter.logRequestSuccess('unpublish', 'entry', entryObj.entryUid, unpublishEntryResponse); + delete entryObj.stack; console.log( chalk.green( @@ -205,9 +290,15 @@ async function UnpublishEntry(data, _config, queue) { throw unpublishEntryResponse; } }) - .catch((error) => { + .catch(async (error) => { + // Log failure + smartRateLimiter.logRequestFailure('unpublish', 'entry', entryObj.entryUid, error); + if (error.errorCode === 429 && data.retry < 2) { data.retry++; + smartRateLimiter.logStatus(); + // Wait and retry + await delay(1000); queue.Enqueue(data); } else { delete entryObj.stack; @@ -230,26 +321,53 @@ async function UnpublishEntry(data, _config, queue) { async function UnpublishAsset(data, _config, queue) { const assetobj = data.obj; const stack = assetobj.stack; + + // Get smart rate limiter instance (singleton per organization) + smartRateLimiter = createSmartRateLimiter(stack?.org_uid); + + // Check if we can process this item + if (!smartRateLimiter.canProcess(1)) { + smartRateLimiter.logStatus(); + // Put the item back in queue and wait + await delay(1000); + queue.Enqueue(data); + return; + } + + // Log request attempt + smartRateLimiter.logRequestAttempt('unpublish', 'asset', assetobj.assetUid); stack .asset(assetobj.assetUid) .unpublish({ publishDetails: { environments: assetobj.environments, locales: [assetobj.locale || 'en-us'] } }) .then((unpublishAssetResponse) => { if (!unpublishAssetResponse.error_message) { + // Update rate limit from server response + smartRateLimiter.updateRateLimit(unpublishAssetResponse); + + // Log success + smartRateLimiter.logRequestSuccess('unpublish', 'asset', assetobj.assetUid, unpublishAssetResponse); + delete assetobj.stack; - console.log(`Asset unpublished with Asset uid=${assetobj.assetUid}`); + console.log(chalk.red(`Could not Unpublish because of error=${formatError(error)}`)); addLogs( logger, { options: assetobj, api_key: stack.stackHeaders.api_key, alias: stack.alias, host: stack.host }, - 'info', + 'error', ); } else { throw unpublishAssetResponse; } }) - .catch((error) => { + .catch(async (error) => { + // Log failure + smartRateLimiter.logRequestFailure('unpublish', 'asset', assetobj.assetUid, error); + if (error.errorCode === 429 && data.retry < 2) { data.retry++; + smartRateLimiter.logStatus(); + // Wait and retry + await delay(1000); queue.Enqueue(data); } else { delete assetobj.stack; @@ -283,6 +401,10 @@ async function performBulkPublish(data, _config, queue) { let conf; const bulkPublishObj = data.obj; const stack = bulkPublishObj.stack; + + // Get smart rate limiter instance (singleton per organization) + smartRateLimiter = createSmartRateLimiter(stack?.org_uid); + let payload = {}; const mapping = await getEnvironment(stack, bulkPublishObj.environments); switch (bulkPublishObj.Type) { @@ -304,15 +426,33 @@ async function performBulkPublish(data, _config, queue) { } } } + // Check if we can process this bulk operation + const entriesToProcess = bulkPublishObj.entries ? bulkPublishObj.entries.length : 1; + if (!smartRateLimiter.canProcess(entriesToProcess)) { + smartRateLimiter.logStatus(); + // Put the item back in queue and wait + await delay(1000); + queue.Enqueue(data); + return; + } + + // Log bulk request attempt + const entryIds = bulkPublishObj.entries ? bulkPublishObj.entries.map(e => e.uid).join(',') : 'bulk_entries'; + smartRateLimiter.logRequestAttempt('bulk_publish', 'entries', entryIds); + stack .bulkOperation() .publish(payload) .then((bulkPublishEntriesResponse) => { if (!bulkPublishEntriesResponse.error_message) { + // Log success + smartRateLimiter.logRequestSuccess('bulk_publish', 'entries', entryIds, bulkPublishEntriesResponse); + console.log( chalk.green(`Bulk entries sent for publish`), bulkPublishEntriesResponse.job_id ? chalk.yellow(`job_id: ${bulkPublishEntriesResponse.job_id}`) : '', ); + // Only display entry details once per bulk operation, not per entry displayEntriesDetails(bulkPublishObj.entries, 'bulk_publish', mapping); delete bulkPublishObj.stack; addLogs( @@ -324,9 +464,15 @@ async function performBulkPublish(data, _config, queue) { throw bulkPublishEntriesResponse; } }) - .catch((error) => { + .catch(async (error) => { + // Log failure + smartRateLimiter.logRequestFailure('bulk_publish', 'entries', entryIds, error); + if (error.errorCode === 429 && data.retry < 2) { data.retry++; + smartRateLimiter.logStatus(); + // Wait and retry + await delay(1000); queue.Enqueue(data); } else { delete bulkPublishObj.stack; @@ -350,24 +496,40 @@ async function performBulkPublish(data, _config, queue) { if (bulkPublishObj.apiVersion) { if (!isNaN(bulkPublishObj.apiVersion) && bulkPublishObj.apiVersion === apiVersionForNRP) { payload['api_version'] = bulkPublishObj.apiVersion; + payload.details.publish_with_reference = true; } else { if (bulkPublishObj.apiVersion !== '3') { - // because 3 is the default value for api-version, and it exists for the purpose of display only console.log(chalk.yellow(nrpApiVersionWarning)); } } } + // Check if we can process this bulk operation + const assetsToProcess = bulkPublishObj.assets ? bulkPublishObj.assets.length : 1; + if (!smartRateLimiter.canProcess(assetsToProcess)) { + smartRateLimiter.logStatus(); + // Put the item back in queue and wait + await delay(1000); + queue.Enqueue(data); + return; + } + + // Log bulk request attempt + const assetIds = bulkPublishObj.assets ? bulkPublishObj.assets.map(a => a.uid).join(',') : 'bulk_assets'; + smartRateLimiter.logRequestAttempt('bulk_publish', 'assets', assetIds); + stack .bulkOperation() .publish(payload) .then((bulkPublishAssetsResponse) => { if (!bulkPublishAssetsResponse.error_message) { + // Log success + smartRateLimiter.logRequestSuccess('bulk_publish', 'assets', assetIds, bulkPublishAssetsResponse); + console.log( - chalk.green( - `Bulk assets sent for publish`, - bulkPublishAssetsResponse.job_id ? chalk.yellow(`job_id: ${bulkPublishAssetsResponse.job_id}`) : '', - ), + chalk.green(`Bulk assets sent for publish`), + bulkPublishAssetsResponse.job_id ? chalk.yellow(`job_id: ${bulkPublishAssetsResponse.job_id}`) : '', ); + // Only display asset details once per bulk operation, not per asset displayAssetsDetails(bulkPublishObj.assets, 'bulk_publish', mapping); delete bulkPublishObj.stack; addLogs( @@ -379,15 +541,20 @@ async function performBulkPublish(data, _config, queue) { throw bulkPublishAssetsResponse; } }) - .catch((error) => { + .catch(async (error) => { + // Log failure + smartRateLimiter.logRequestFailure('bulk_publish', 'assets', assetIds, error); + if (error.errorCode === 429 && data.retry < 2) { data.retry++; + smartRateLimiter.logStatus(); + // Wait and retry + await delay(1000); queue.Enqueue(data); } else { delete bulkPublishObj.stack; console.log(chalk.red(`Bulk assets failed to publish with error ${formatError(error)}`)); - - displayAssetsDetails(sanitizedData, 'bulk_publish', mapping); + displayAssetsDetails(bulkPublishObj.assets, 'bulk_publish', mapping); addLogs( logger, { options: bulkPublishObj, api_key: stack.stackHeaders.api_key, alias: stack.alias, host: stack.host }, @@ -397,7 +564,8 @@ async function performBulkPublish(data, _config, queue) { }); break; default: - console.log('No such type'); + console.log(chalk.red(`Invalid bulk publish type: ${bulkPublishObj.Type}`)); + break; } } @@ -405,6 +573,10 @@ async function performBulkUnPublish(data, _config, queue) { let conf; const bulkUnPublishObj = data.obj; const stack = bulkUnPublishObj.stack; + + // Get smart rate limiter instance (singleton per organization) + smartRateLimiter = createSmartRateLimiter(stack?.org_uid); + let payload = {}; switch (bulkUnPublishObj.Type) { case 'entry': @@ -424,20 +596,35 @@ async function performBulkUnPublish(data, _config, queue) { } } } + // Check if we can process this bulk operation + const entriesToUnpublish = bulkUnPublishObj.entries ? bulkUnPublishObj.entries.length : 1; + if (!smartRateLimiter.canProcess(entriesToUnpublish)) { + smartRateLimiter.logStatus(); + // Put the item back in queue and wait + await delay(1000); + queue.Enqueue(data); + return; + } + + // Log bulk request attempt + const entryIds = bulkUnPublishObj.entries ? bulkUnPublishObj.entries.map(e => e.uid).join(',') : 'bulk_entries'; + smartRateLimiter.logRequestAttempt('bulk_unpublish', 'entries', entryIds); + stack .bulkOperation() .unpublish(payload) .then((bulkUnPublishEntriesResponse) => { if (!bulkUnPublishEntriesResponse.error_message) { + // Log success + smartRateLimiter.logRequestSuccess('bulk_unpublish', 'entries', entryIds, bulkUnPublishEntriesResponse); + delete bulkUnPublishObj.stack; console.log( - chalk.green( - `Bulk entries sent for Unpublish`, - bulkUnPublishEntriesResponse.job_id - ? chalk.yellow(`job_id: ${bulkUnPublishEntriesResponse.job_id}`) - : '', - ), + chalk.green(`Bulk entries sent for Unpublish`), + bulkUnPublishEntriesResponse.job_id + ? chalk.yellow(`job_id: ${bulkUnPublishEntriesResponse.job_id}`) + : '', ); displayEntriesDetails(bulkUnPublishObj.entries, 'bulk_unpublish'); addLogs( @@ -449,9 +636,15 @@ async function performBulkUnPublish(data, _config, queue) { throw bulkUnPublishEntriesResponse; } }) - .catch((error) => { + .catch(async (error) => { + // Log failure + smartRateLimiter.logRequestFailure('bulk_unpublish', 'entries', entryIds, error); + if (error.errorCode === 429 && data.retry < 2) { data.retry++; + smartRateLimiter.logStatus(); + // Wait and retry + await delay(1000); queue.Enqueue(data); } else { delete bulkUnPublishObj.stack; @@ -482,17 +675,32 @@ async function performBulkUnPublish(data, _config, queue) { } } } + // Check if we can process this bulk operation + const assetsToUnpublish = bulkUnPublishObj.assets ? bulkUnPublishObj.assets.length : 1; + if (!smartRateLimiter.canProcess(assetsToUnpublish)) { + smartRateLimiter.logStatus(); + // Put the item back in queue and wait + await delay(1000); + queue.Enqueue(data); + return; + } + + // Log bulk request attempt + const assetIds = bulkUnPublishObj.assets ? bulkUnPublishObj.assets.map(a => a.uid).join(',') : 'bulk_assets'; + smartRateLimiter.logRequestAttempt('bulk_unpublish', 'assets', assetIds); + stack .bulkOperation() .unpublish(payload) .then((bulkUnPublishAssetsResponse) => { if (!bulkUnPublishAssetsResponse.error_message) { + // Log success + smartRateLimiter.logRequestSuccess('bulk_unpublish', 'assets', assetIds, bulkUnPublishAssetsResponse); + delete bulkUnPublishObj.stack; console.log( - chalk.green( - `Bulk assets sent for Unpublish`, - bulkUnPublishAssetsResponse.job_id ? chalk.yellow(`job_id: ${bulkUnPublishAssetsResponse.job_id}`) : '', - ), + chalk.green(`Bulk assets sent for Unpublish`), + bulkUnPublishAssetsResponse.job_id ? chalk.yellow(`job_id: ${bulkUnPublishAssetsResponse.job_id}`) : '', ); displayAssetsDetails(bulkUnPublishObj.assets, 'bulk_unpublish'); addLogs( @@ -504,9 +712,15 @@ async function performBulkUnPublish(data, _config, queue) { throw bulkUnPublishAssetsResponse; } }) - .catch((error) => { + .catch(async (error) => { + // Log failure + smartRateLimiter.logRequestFailure('bulk_unpublish', 'assets', assetIds, error); + if (error.errorCode === 429 && data.retry < 2) { data.retry++; + smartRateLimiter.logStatus(); + // Wait and retry + await delay(1000); queue.Enqueue(data); } else { delete bulkUnPublishObj.stack; @@ -521,7 +735,8 @@ async function performBulkUnPublish(data, _config, queue) { }); break; default: - console.log('No such type'); + console.log(chalk.red(`Invalid bulk unpublish type: ${bulkUnPublishObj.Type}`)); + break; } } @@ -534,6 +749,9 @@ async function publishUsingVersion(data, _config, queue) { let counter = 0; const bulkPublishObj = data.obj; const stack = bulkPublishObj.stack; + + // Get smart rate limiter instance (singleton per organization) + smartRateLimiter = createSmartRateLimiter(stack?.org_uid); switch (bulkPublishObj.Type) { case 'entry': successfullyPublished = []; @@ -551,12 +769,23 @@ async function publishUsingVersion(data, _config, queue) { locale: bulkPublishObj.locale, version: entry.version, }; + // Check if we can process this item + if (!smartRateLimiter.canProcess(1)) { + smartRateLimiter.logStatus(); + // Put the item back in queue and wait + await delay(1000); + queue.Enqueue(data); + return; + } + stack .contentType(entry.content_type) .entry(entry.uid) .publish(conf) .then((publishEntriesResponse) => { if (!publishEntriesResponse.error_message) { + // Update rate limit from server response + smartRateLimiter.updateRateLimit(publishEntriesResponse); console.log(chalk.green(`Entry=${entry.uid} sent for publish`)); counter += 1; @@ -602,9 +831,12 @@ async function publishUsingVersion(data, _config, queue) { // throw bulkPublishEntriesResponse; } }) - .catch((error) => { + .catch(async (error) => { if (error.errorCode === 429 && data.retry < 2) { data.retry++; + smartRateLimiter.logStatus(); + // Wait and retry + await delay(1000); queue.Enqueue(data); } else { counter += 1; @@ -663,11 +895,22 @@ async function publishUsingVersion(data, _config, queue) { }, version: asset.version, }; + // Check if we can process this item + if (!smartRateLimiter.canProcess(1)) { + smartRateLimiter.logStatus(); + // Put the item back in queue and wait + await delay(1000); + queue.Enqueue(data); + return; + } + stack .asset(asset.uid) .publish(conf) .then((publishAssetsResponse) => { if (!publishAssetsResponse.error_message) { + // Update rate limit from server response + smartRateLimiter.updateRateLimit(publishAssetsResponse); console.log(chalk.green(`Asset=${asset.uid} sent for publish`)); counter += 1; @@ -713,9 +956,12 @@ async function publishUsingVersion(data, _config, queue) { // throw bulkPublishAssetsResponse; } }) - .catch((error) => { + .catch(async (error) => { if (error.errorCode === 429 && data.retry < 2) { data.retry++; + smartRateLimiter.logStatus(); + // Wait and retry + await delay(1000); queue.Enqueue(data); } else { counter += 1; @@ -751,8 +997,8 @@ async function publishUsingVersion(data, _config, queue) { }, 'error', ); + } } - } console.log(chalk.red(`Asset=${asset.uid} failed to publish with error ${formatError(error)}`)); } diff --git a/packages/contentstack-bulk-publish/src/producer/publish-assets.js b/packages/contentstack-bulk-publish/src/producer/publish-assets.js index 87538ab550..ac52bb803a 100644 --- a/packages/contentstack-bulk-publish/src/producer/publish-assets.js +++ b/packages/contentstack-bulk-publish/src/producer/publish-assets.js @@ -7,16 +7,22 @@ const retryFailedLogs = require('../util/retryfailed'); const { validateFile } = require('../util/fs'); const { isEmpty } = require('../util'); const { fetchBulkPublishLimit } = require('../util/common-utility'); +const { createSmartRateLimiter } = require('../util/smart-rate-limiter'); const queue = getQueue(); let logFileName; let bulkPublishSet = []; let filePath; +let smartRateLimiter; +let pendingItems = []; /* eslint-disable no-param-reassign */ async function getAssets(stack, folder, bulkPublish, environments, locale, apiVersion, bulkPublishLimit, skip = 0) { return new Promise((resolve, reject) => { + // Get smart rate limiter instance (singleton per organization) + smartRateLimiter = createSmartRateLimiter(stack?.org_uid); + let queryParams = { folder: folder, skip: skip, @@ -29,6 +35,9 @@ async function getAssets(stack, folder, bulkPublish, environments, locale, apiVe .query(queryParams) .find() .then(async (assetResponse) => { + // Update rate limit from server response + smartRateLimiter.updateRateLimit(assetResponse); + if (assetResponse && assetResponse.items.length > 0) { skip += assetResponse.items.length; let assets = assetResponse.items; @@ -47,40 +56,12 @@ async function getAssets(stack, folder, bulkPublish, environments, locale, apiVe continue; } if (bulkPublish) { - if (bulkPublishSet.length < bulkPublishLimit) { - bulkPublishSet.push({ - uid: assets[index].uid, - locale, - publish_details: assets[index].publish_details || [], - }); - } - if (bulkPublishSet.length === bulkPublishLimit) { - await queue.Enqueue({ - assets: bulkPublishSet, - Type: 'asset', - environments: environments, - locale, - stack: stack, - apiVersion, - }); - bulkPublishSet = []; - } - - if ( - assetResponse.items.length - 1 === index && - bulkPublishSet.length > 0 && - bulkPublishSet.length < bulkPublishLimit - ) { - await queue.Enqueue({ - assets: bulkPublishSet, - Type: 'asset', - environments: environments, - locale, - stack: stack, - apiVersion, - }); - bulkPublishSet = []; - } + // Add to pending items instead of immediate processing + pendingItems.push({ + uid: assets[index].uid, + locale, + publish_details: assets[index].publish_details || [], + }); } else { await queue.Enqueue({ assetUid: assets[index].uid, @@ -92,7 +73,17 @@ async function getAssets(stack, folder, bulkPublish, environments, locale, apiVe }); } } + + // Process pending items with smart rate limiting + if (pendingItems.length > 0) { + await processPendingAssets(stack, environments, locale, apiVersion); + } + if (skip === assetResponse.count) { + // Process any remaining items + if (pendingItems.length > 0) { + await processPendingAssets(stack, environments, locale, apiVersion); + } return resolve(true); } await getAssets(stack, folder, bulkPublish, environments, locale, apiVersion, bulkPublishLimit, skip); @@ -107,6 +98,51 @@ async function getAssets(stack, folder, bulkPublish, environments, locale, apiVe }); } +/** + * Process pending assets with smart rate limiting + */ +async function processPendingAssets(stack, environments, locale, apiVersion) { + const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms)); + + while (pendingItems.length > 0) { + const optimalBatchSize = smartRateLimiter.getOptimalBatchSize(pendingItems.length); + + if (optimalBatchSize === 0) { + // Rate limit exhausted, wait and retry + smartRateLimiter.logStatus(); + await delay(1000); + continue; + } + + // Take the optimal batch size + const batch = pendingItems.splice(0, optimalBatchSize); + + try { + await queue.Enqueue({ + assets: batch, + Type: 'asset', + environments: environments, + locale, + stack: stack, + apiVersion, + }); + + smartRateLimiter.logStatus(); + + } catch (error) { + if (error.errorCode === 429) { + // Rate limit error, put items back and wait + pendingItems.unshift(...batch); + smartRateLimiter.logStatus(); + await delay(1000); + } else { + // Other error, log and continue + console.log(`Error processing batch: ${error.message}`); + } + } + } +} + function setConfig(conf, bp) { if (bp) { queue.consumer = performBulkPublish; diff --git a/packages/contentstack-bulk-publish/src/producer/publish-entries.js b/packages/contentstack-bulk-publish/src/producer/publish-entries.js index 607b731696..1f716d796b 100644 --- a/packages/contentstack-bulk-publish/src/producer/publish-entries.js +++ b/packages/contentstack-bulk-publish/src/producer/publish-entries.js @@ -9,6 +9,7 @@ const retryFailedLogs = require('../util/retryfailed'); const { validateFile } = require('../util/fs'); const { isEmpty } = require('../util'); const { fetchBulkPublishLimit } = require('../util/common-utility'); +const { createSmartRateLimiter } = require('../util/smart-rate-limiter'); const VARIANTS_PUBLISH_API_VERSION = '3.2'; const queue = getQueue(); @@ -19,6 +20,8 @@ let contentTypesList = []; let allContentTypes = []; let bulkPublishSet = []; let filePath; +let smartRateLimiter; +let pendingItems = []; async function getEntries( stack, @@ -35,6 +38,9 @@ async function getEntries( return new Promise((resolve, reject) => { skipCount = skip; + // Get smart rate limiter instance (singleton per organization) + smartRateLimiter = createSmartRateLimiter(stack?.org_uid); + let queryParams = { locale: locale || 'en-us', include_count: true, @@ -55,61 +61,35 @@ async function getEntries( .query(queryParams) .find() .then(async (entriesResponse) => { + // Update rate limit from server response + smartRateLimiter.updateRateLimit(entriesResponse); + skipCount += entriesResponse.items.length; let entries = entriesResponse.items; for (let index = 0; index < entries.length; index++) { let variants = []; if (bulkPublish) { - let entry; - if (bulkPublishSet.length < bulkPublishLimit) { - entry = { - uid: entries[index].uid, - content_type: contentType, - locale, - publish_details: entries[index].publish_details || [], - }; + let entry = { + uid: entries[index].uid, + content_type: contentType, + locale, + publish_details: entries[index].publish_details || [], + }; - if (variantsFlag) { - variants = await getVariantEntries(stack, contentType, entries, index, queryParams); - if (variants.length > 0) { - entry.variant_rules = { - publish_latest_base: false, - publish_latest_base_conditionally: true, - }; - entry.variants = variants; - } + if (variantsFlag) { + variants = await getVariantEntries(stack, contentType, entries, index, queryParams); + if (variants.length > 0) { + entry.variant_rules = { + publish_latest_base: false, + publish_latest_base_conditionally: true, + }; + entry.variants = variants; } } - bulkPublishSet.push(entry); - - if (bulkPublishSet.length === bulkPublishLimit) { - await queue.Enqueue({ - entries: bulkPublishSet, - locale, - Type: 'entry', - environments: environments, - stack: stack, - apiVersion, - }); - bulkPublishSet = []; - } - - if ( - index === entries.length - 1 && - bulkPublishSet.length <= bulkPublishLimit && - bulkPublishSet.length > 0 - ) { - await queue.Enqueue({ - entries: bulkPublishSet, - locale, - Type: 'entry', - environments: environments, - stack: stack, - apiVersion, - }); - bulkPublishSet = []; - } + + // Add to pending items instead of immediate processing + pendingItems.push(entry); } else { await queue.Enqueue({ content_type: contentType, @@ -123,8 +103,16 @@ async function getEntries( } } + // Process pending items with smart rate limiting + if (pendingItems.length > 0) { + await processPendingItems(stack, environments, locale, apiVersion); + } + if (entriesResponse.count === skipCount) { - bulkPublishSet = []; + // Process any remaining items + if (pendingItems.length > 0) { + await processPendingItems(stack, environments, locale, apiVersion); + } return resolve(); } await getEntries( @@ -230,6 +218,51 @@ function setConfig(conf, bp) { filePath = initializeLogger(logFileName); } +/** + * Process pending items with smart rate limiting + */ +async function processPendingItems(stack, environments, locale, apiVersion) { + const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms)); + + while (pendingItems.length > 0) { + const optimalBatchSize = smartRateLimiter.getOptimalBatchSize(pendingItems.length); + + if (optimalBatchSize === 0) { + // Rate limit exhausted, wait and retry + smartRateLimiter.logStatus(); + await delay(1000); + continue; + } + + // Take the optimal batch size + const batch = pendingItems.splice(0, optimalBatchSize); + + try { + await queue.Enqueue({ + entries: batch, + locale, + Type: 'entry', + environments: environments, + stack: stack, + apiVersion, + }); + + smartRateLimiter.logStatus(); + + } catch (error) { + if (error.errorCode === 429) { + // Rate limit error, put items back and wait + pendingItems.unshift(...batch); + smartRateLimiter.logStatus(); + await delay(1000); + } else { + // Other error, log and continue + console.log(`Error processing batch: ${error.message}`); + } + } + } +} + async function start( { retryFailed, diff --git a/packages/contentstack-bulk-publish/src/producer/unpublish.js b/packages/contentstack-bulk-publish/src/producer/unpublish.js index 8f3650eb98..994ac17214 100644 --- a/packages/contentstack-bulk-publish/src/producer/unpublish.js +++ b/packages/contentstack-bulk-publish/src/producer/unpublish.js @@ -15,6 +15,7 @@ const { Command } = require('@contentstack/cli-command'); const command = new Command(); const { isEmpty } = require('../util'); const { fetchBulkPublishLimit } = require('../util/common-utility'); +const { createSmartRateLimiter } = require('../util/smart-rate-limiter'); const VARIANTS_UNPUBLISH_API_VERSION = '3.2'; const delay = (ms) => new Promise((res) => setTimeout(res, ms)); @@ -22,6 +23,9 @@ let bulkUnPublishSet = []; let bulkUnPulishAssetSet = []; let logFileName; let filePath; +let smartRateLimiter; +let pendingEntryItems = []; +let pendingAssetItems = []; function setConfig(conf, bup) { if (bup) { @@ -54,11 +58,14 @@ function getQueryParams(filter) { function bulkAction(stack, items, bulkUnpublish, environment, locale, apiVersion, bulkPublishLimit, variantsFlag = false) { return new Promise(async (resolve) => { + // Get smart rate limiter instance (singleton per organization) + smartRateLimiter = createSmartRateLimiter(stack?.org_uid); + for (let index = 0; index < items.length; index++) { changedFlag = true; if (bulkUnpublish) { - if (bulkUnPublishSet.length < bulkPublishLimit && items[index].type === 'entry_published') { + if (items[index].type === 'entry_published') { const entryData = { uid: items[index].data.uid, content_type: items[index].content_type_uid, @@ -68,94 +75,130 @@ function bulkAction(stack, items, bulkUnpublish, environment, locale, apiVersion if (variantsFlag && Array.isArray(items[index].data.variants) && items[index].data.variants.length > 0) { const entryWithVariants = { ...entryData, variants: items[index].data.variants }; - bulkUnPublishSet.push(entryWithVariants); + pendingEntryItems.push(entryWithVariants); } else { - bulkUnPublishSet.push(entryData); + pendingEntryItems.push(entryData); } } - if (bulkUnPulishAssetSet.length < bulkPublishLimit && items[index].type === 'asset_published') { - bulkUnPulishAssetSet.push({ + if (items[index].type === 'asset_published') { + pendingAssetItems.push({ uid: items[index].data.uid, version: items[index].data._version, publish_details: [items[index].data.publish_details] || [], }); } - - if (bulkUnPulishAssetSet.length === bulkPublishLimit) { - await queue.Enqueue({ - assets: bulkUnPulishAssetSet, - Type: 'asset', - locale: locale, - environments: [environment], - stack: stack, - apiVersion, - }); - bulkUnPulishAssetSet = []; - } - - if (bulkUnPublishSet.length === bulkPublishLimit) { - await queue.Enqueue({ - entries: bulkUnPublishSet, - locale: locale, - Type: 'entry', - environments: [environment], - stack: stack, - apiVersion, - }); - bulkUnPublishSet = []; - } - if (index === items.length - 1 && bulkUnPulishAssetSet.length <= bulkPublishLimit && bulkUnPulishAssetSet.length > 0) { - await queue.Enqueue({ - assets: bulkUnPulishAssetSet, - Type: 'asset', - locale: locale, - environments: [environment], - stack: stack, - apiVersion, - }); - bulkUnPulishAssetSet = []; - } - - if (index === items.length - 1 && bulkUnPublishSet.length <= bulkPublishLimit && bulkUnPublishSet.length > 0) { - await queue.Enqueue({ - entries: bulkUnPublishSet, - locale: locale, - Type: 'entry', - environments: [environment], - stack: stack, - apiVersion, - }); - bulkUnPublishSet = []; - } } else { if (items[index].type === 'entry_published') { - await entryQueue.Enqueue({ + await entryQueue.Enqueue({ content_type: items[index].content_type_uid, - publish_details: [items[index].data.publish_details], - environments: [environment], entryUid: items[index].data.uid, locale: items[index].data.locale || 'en-us', - Type: 'entry', + environments: [environment], stack: stack, - apiVersion, }); - } - if (items[index].type === 'asset_published') { + } else if (items[index].type === 'asset_published') { await assetQueue.Enqueue({ assetUid: items[index].data.uid, - publish_details: [items[index].data.publish_details], environments: [environment], - Type: 'entry', stack: stack, }); } } } - return resolve(); + + // Process pending items with smart rate limiting + if (bulkUnpublish) { + await processPendingUnpublishItems(stack, environment, locale, apiVersion); + } + + resolve(); }); } +/** + * Process pending unpublish items with smart rate limiting + */ +async function processPendingUnpublishItems(stack, environment, locale, apiVersion) { + // Process assets first + while (pendingAssetItems.length > 0) { + const optimalBatchSize = smartRateLimiter.getOptimalBatchSize(pendingAssetItems.length); + + if (optimalBatchSize === 0) { + // Rate limit exhausted, wait and retry + smartRateLimiter.logStatus(); + await delay(1000); + continue; + } + + // Take the optimal batch size + const batch = pendingAssetItems.splice(0, optimalBatchSize); + + try { + await queue.Enqueue({ + assets: batch, + Type: 'asset', + locale: locale, + environments: [environment], + stack: stack, + apiVersion, + }); + + smartRateLimiter.logStatus(); + + } catch (error) { + if (error.errorCode === 429) { + // Rate limit error, put items back and wait + pendingAssetItems.unshift(...batch); + smartRateLimiter.logStatus(); + await delay(1000); + } else { + // Other error, log and continue + console.log(`Error processing asset batch: ${error.message}`); + } + } + } + + // Process entries + while (pendingEntryItems.length > 0) { + const optimalBatchSize = smartRateLimiter.getOptimalBatchSize(pendingEntryItems.length); + + if (optimalBatchSize === 0) { + // Rate limit exhausted, wait and retry + smartRateLimiter.logStatus(); + await delay(1000); + continue; + } + + // Take the optimal batch size + const batch = pendingEntryItems.splice(0, optimalBatchSize); + + try { + await queue.Enqueue({ + entries: batch, + locale: locale, + Type: 'entry', + environments: [environment], + stack: stack, + apiVersion, + }); + + smartRateLimiter.logStatus(); + + } catch (error) { + if (error.errorCode === 429) { + // Rate limit error, put items back and wait + pendingEntryItems.unshift(...batch); + smartRateLimiter.logStatus(); + await delay(1000); + } else { + // Other error, log and continue + console.log(`Error processing entry batch: ${error.message}`); + } + } + } +} + async function getSyncEntries( stack, config, @@ -217,6 +260,12 @@ async function getSyncEntries( } const entriesResponse = await Stack.sync(syncData); + + // Update rate limit from server response if available + if (smartRateLimiter) { + smartRateLimiter.updateRateLimit(entriesResponse); + } + if (entriesResponse.items.length > 0) { if (variantsFlag) { queryParamsObj.apiVersion = VARIANTS_UNPUBLISH_API_VERSION; @@ -278,6 +327,11 @@ async function getVariantEntries(stack, contentType, entries, queryParams, skip .query(variantQueryParams) .find(); + // Update rate limit from server response if available + if (smartRateLimiter) { + smartRateLimiter.updateRateLimit(variantsEntriesResponse); + } + // Map the response items to extract variant UIDs const variants = variantsEntriesResponse.items.map(entry => ({ uid: entry.variants._variant._uid, diff --git a/packages/contentstack-bulk-publish/src/util/client.js b/packages/contentstack-bulk-publish/src/util/client.js index 22a73bcca7..828b63a8ef 100644 --- a/packages/contentstack-bulk-publish/src/util/client.js +++ b/packages/contentstack-bulk-publish/src/util/client.js @@ -6,6 +6,7 @@ async function getStack(data) { const options = { host: data.host, branchName: data.branch, + headers: {includeResHeaders: true}, }; const stackOptions = {}; if (data.alias) { diff --git a/packages/contentstack-bulk-publish/src/util/common-utility.js b/packages/contentstack-bulk-publish/src/util/common-utility.js index c51c0a40de..3d7b28e029 100644 --- a/packages/contentstack-bulk-publish/src/util/common-utility.js +++ b/packages/contentstack-bulk-publish/src/util/common-utility.js @@ -27,4 +27,27 @@ function fetchBulkPublishLimit(orgUid) { return bulkPublishLimit; } -module.exports = { fetchBulkPublishLimit }; +/** + * Handles the rate limit checking and adds delay if necessary. + * @param {Object} error - The error object containing the response headers. + * @param {Object} data - The data being processed, including the batch size. + * @param {Function} delay - The delay function to use for waiting. + * @param {number} xRateLimitRemaining - The xRateLimitRemaining containing the remaining balance. + * @returns {boolean} - Returns `true` if delay was applied, `false` otherwise. + */ +async function handleRateLimit(error, data, delay, xRateLimitRemaining) { + // Check if rate limit is exhausted or batch size exceeds remaining limit + if (xRateLimitRemaining === 0 || data.length > xRateLimitRemaining) { + cliux.print( + 'Bulk rate limit reached or batch size exceeds remaining limit. Retrying in 1 second...', + { color: 'yellow' }, + ); + await delay(1000); // Wait for 1 second before retrying + return true; + } else { + return false; + } +} + + +module.exports = { fetchBulkPublishLimit, handleRateLimit }; diff --git a/packages/contentstack-bulk-publish/src/util/smart-rate-limiter.js b/packages/contentstack-bulk-publish/src/util/smart-rate-limiter.js new file mode 100644 index 0000000000..c30102920e --- /dev/null +++ b/packages/contentstack-bulk-publish/src/util/smart-rate-limiter.js @@ -0,0 +1,332 @@ +const { cliux } = require('@contentstack/cli-utilities'); +const { fetchBulkPublishLimit } = require('./common-utility'); + +// Singleton instances per organization +const rateLimiterInstances = new Map(); + +class SmartRateLimiter { + constructor(orgUid) { + this.orgUid = orgUid; + this.bulkPublishLimit = fetchBulkPublishLimit(orgUid); + this.xRateLimitRemaining = this.bulkPublishLimit; + this.serverRateLimit = null; // Track the actual server rate limit + this.pendingItems = []; + this.isProcessing = false; + this.requestCount = 0; // Track total requests made + this.lastStatusLog = 0; // Prevent duplicate status logs + } + + /** + * Log request attempt + * @param {string} operation - Type of operation (publish, unpublish, etc.) + * @param {string} itemType - Type of item (entry, asset, etc.) + * @param {string} itemId - ID of the item being processed + */ + logRequestAttempt(operation, itemType, itemId) { + this.requestCount++; + // cliux.print( + // `[${this.requestCount}] ${operation.toUpperCase()} ${itemType}: ${itemId} (${this.xRateLimitRemaining} remaining)`, + // { color: 'cyan' } + // ); + } + + /** + * Log request success + * @param {string} operation - Type of operation + * @param {string} itemType - Type of item + * @param {string} itemId - ID of the item + * @param {Object} response - Server response + */ + logRequestSuccess(operation, itemType, itemId, response) { + // cliux.print( + // `[${this.requestCount}] ✓ ${operation.toUpperCase()} ${itemType}: ${itemId} - SUCCESS`, + // { color: 'green' } + // ); + + // Update rate limit from response + this.updateRateLimit(response); + } + + /** + * Log request failure + * @param {string} operation - Type of operation + * @param {string} itemType - Type of item + * @param {string} itemId - ID of the item + * @param {Object} error - Error object + */ + logRequestFailure(operation, itemType, itemId, error) { + const errorCode = error.errorCode || 'UNKNOWN'; + const errorMessage = error.message || error.error_message || 'Unknown error'; + + // cliux.print( + // `[${this.requestCount}] ✗ ${operation.toUpperCase()} ${itemType}: ${itemId} - FAILED (${errorCode})`, + // { color: 'red' } + // ); + + if (errorCode === 429) { + cliux.print( + `[${this.requestCount}] Rate limit exceeded - will retry after delay`, + { color: 'yellow' } + ); + } else { + cliux.print( + `[${this.requestCount}] Error: ${errorMessage}`, + { color: 'red' } + ); + } + } + + /** + * Log rate limit check + * @param {number} itemsToProcess - Number of items to process + * @param {boolean} canProcess - Whether processing is allowed + */ + logRateLimitCheck(itemsToProcess, canProcess) { + if (!canProcess) { + cliux.print( + `Rate limit check: Cannot process items (${this.xRateLimitRemaining} remaining) - waiting...`, + { color: 'yellow' } + ); + } else { + cliux.print( + `Rate limit check: Can process ${itemsToProcess} items (${this.xRateLimitRemaining} remaining)`, + { color: 'green' } + ); + } + } + + /** + * Update rate limit from server response + * @param {Object} response - Server response with headers + */ + updateRateLimit(response) { + if (response?.stackHeaders?.responseHeaders) { + // Handle AxiosHeaders object - try different access methods + const headers = response.stackHeaders.responseHeaders; + let remaining, limit; + + // Try different ways to access the headers + if (headers['x-ratelimit-remaining']) { + remaining = headers['x-ratelimit-remaining']; + } else if (headers.get && headers.get('x-ratelimit-remaining')) { + remaining = headers.get('x-ratelimit-remaining'); + } else if (headers.x_ratelimit_remaining) { + remaining = headers.x_ratelimit_remaining; + } + + if (headers['x-ratelimit-limit']) { + limit = headers['x-ratelimit-limit']; + } else if (headers.get && headers.get('x-ratelimit-limit')) { + limit = headers.get('x-ratelimit-limit'); + } else if (headers.x_ratelimit_limit) { + limit = headers.x_ratelimit_limit; + } + + if (remaining) { + const newRateLimit = parseInt(remaining, 10); + + // Update server rate limit if we get the total limit from headers + if (limit) { + this.serverRateLimit = parseInt(limit, 10); + } + + // Only update if the new value is different to avoid unnecessary logging + if (this.xRateLimitRemaining !== newRateLimit) { + this.xRateLimitRemaining = newRateLimit; + // cliux.print(`Rate limit updated: ${this.xRateLimitRemaining} remaining`, { color: 'blue' }); + } + } + } + } + + /** + * Get the optimal batch size based on current rate limit + * @param {number} totalItems - Total items to process + * @returns {number} - Optimal batch size + */ + getOptimalBatchSize(totalItems) { + // Be more conservative when rate limit is low + let maxBatchSize = this.xRateLimitRemaining; + + // If rate limit is 2 or less, only process 1 item at a time + if (this.xRateLimitRemaining <= 2) { + maxBatchSize = 1; + } + // If rate limit is 5 or less, limit batch size to 2 + else if (this.xRateLimitRemaining <= 5) { + maxBatchSize = Math.min(2, this.xRateLimitRemaining); + } + + // Use the smaller of: adjusted rate limit, configured batch limit, or total items + const optimalSize = Math.min( + maxBatchSize, + this.bulkPublishLimit, + totalItems + ); + + if (optimalSize <= 0) { + // cliux.print(`Rate limit exhausted (${this.xRateLimitRemaining} remaining). Waiting for reset...`, { color: 'yellow' }); + return 0; + } + return optimalSize; + } + + /** + * Check if we can process items + * @param {number} itemsToProcess - Number of items to process + * @returns {boolean} - True if can process + */ + canProcess(itemsToProcess = 1) { + // Get the optimal batch size for the requested number of items + const optimalBatchSize = this.getOptimalBatchSize(itemsToProcess); + const canProcess = optimalBatchSize > 0; + + // Add proactive delay when rate limit is low (1-2 remaining) + if (this.xRateLimitRemaining <= 2 && this.xRateLimitRemaining > 0) { + // cliux.print( + // `Rate limit low (${this.xRateLimitRemaining} remaining) - adding proactive delay to prevent 429 errors`, + // { color: 'yellow' } + // ); + return false; // Force a delay to let rate limit recover + } + // this.logRateLimitCheck(optimalBatchSize, canProcess); + return canProcess; + } + + /** + * Process items with rate limit awareness + * @param {Array} items - Items to process + * @param {Function} processFunction - Function to process items + * @param {Function} delayFunction - Delay function + * @returns {Promise} - Processed items + */ + async processItemsWithRateLimit(items, processFunction, delayFunction) { + const results = []; + let currentIndex = 0; + + while (currentIndex < items.length) { + const remainingItems = items.length - currentIndex; + const optimalBatchSize = this.getOptimalBatchSize(remainingItems); + + if (optimalBatchSize === 0) { + // Rate limit exhausted, wait and retry + cliux.print('Rate limit reached. Waiting 1 second before retry...', { color: 'yellow' }); + await delayFunction(1000); + continue; + } + + // Take the optimal batch size + const batch = items.slice(currentIndex, currentIndex + optimalBatchSize); + + try { + const result = await processFunction(batch); + results.push(result); + + // Update rate limit (assuming processFunction returns response with headers) + if (result && result.stackHeaders) { + this.updateRateLimit(result); + } + + currentIndex += optimalBatchSize; + + cliux.print(`Processed ${batch.length} items. ${items.length - currentIndex} remaining.`, { color: 'green' }); + + } catch (error) { + if (error.errorCode === 429) { + // Rate limit error, wait and retry + cliux.print('Rate limit error (429). Waiting 1 second before retry...', { color: 'yellow' }); + await delayFunction(1000); + // Don't increment currentIndex, retry the same batch + } else { + // Other error, skip this batch + cliux.print(`Error processing batch: ${error.message}`, { color: 'red' }); + currentIndex += optimalBatchSize; + } + } + } + + return results; + } + + /** + * Create batches based on rate limit + * @param {Array} items - Items to batch + * @returns {Array} - Array of batches + */ + createOptimalBatches(items) { + const batches = []; + let currentIndex = 0; + + while (currentIndex < items.length) { + const remainingItems = items.length - currentIndex; + const optimalBatchSize = this.getOptimalBatchSize(remainingItems); + + if (optimalBatchSize === 0) { + // Can't process any more items due to rate limit + break; + } + + const batch = items.slice(currentIndex, currentIndex + optimalBatchSize); + batches.push(batch); + currentIndex += optimalBatchSize; + } + + return { + batches, + remainingItems: items.slice(currentIndex) // Items that couldn't be batched due to rate limit + }; + } + + /** + * Get current rate limit status + * @returns {Object} - Rate limit status + */ + getStatus() { + return { + rateLimitRemaining: this.xRateLimitRemaining, + bulkPublishLimit: this.bulkPublishLimit, + serverRateLimit: this.serverRateLimit, + canProcess: this.xRateLimitRemaining > 0, + requestCount: this.requestCount + }; + } + + /** + * Log current status + */ + logStatus() { + const status = this.getStatus(); + const totalLimit = this.serverRateLimit || this.bulkPublishLimit; + const status_rate_limit = `${status.rateLimitRemaining}/${totalLimit}/${status.requestCount}`; + + if (this.lastStatusLog !== status_rate_limit) { + // cliux.print( + // `Rate Limit Status - Remaining: ${status.rateLimitRemaining}/${totalLimit} (Total requests: ${status.requestCount})`, + // { color: status.canProcess ? 'green' : 'yellow' } + // ); + this.lastStatusLog = status_rate_limit; + } + } +} + +/** + * Create a smart rate limiter instance (singleton per organization) + * @param {string} orgUid - Organization UID + * @returns {SmartRateLimiter} - Smart rate limiter instance + */ +function createSmartRateLimiter(orgUid) { + // Return existing instance if available for this organization + if (rateLimiterInstances.has(orgUid)) { + return rateLimiterInstances.get(orgUid); + } + + // Create new instance and store it + const instance = new SmartRateLimiter(orgUid); + rateLimiterInstances.set(orgUid, instance); + return instance; +} + +module.exports = { + SmartRateLimiter, + createSmartRateLimiter +}; \ No newline at end of file diff --git a/packages/contentstack-config/README.md b/packages/contentstack-config/README.md index d6bba66960..1dd6cfd08b 100644 --- a/packages/contentstack-config/README.md +++ b/packages/contentstack-config/README.md @@ -18,7 +18,7 @@ $ npm install -g @contentstack/cli-config $ csdx COMMAND running command... $ csdx (--version) -@contentstack/cli-config/1.14.0 darwin-arm64 node-v18.20.2 +@contentstack/cli-config/1.14.0 darwin-arm64 node-v22.14.0 $ csdx --help [COMMAND] USAGE $ csdx COMMAND @@ -326,12 +326,13 @@ Set logging configuration for CLI ``` USAGE - $ csdx config:set:log [--level debug|info|warn|error] [--path ] + $ csdx config:set:log [--level debug|info|warn|error] [--path ] [--show-console-logs] FLAGS - --level=