From 73e57878d2560d7f2291f61b59fa0a26f3865d3e Mon Sep 17 00:00:00 2001 From: Aravind Kumar Date: Mon, 8 Sep 2025 22:15:57 +0530 Subject: [PATCH 1/6] Delete secrets-scan.yml --- .github/workflows/secrets-scan.yml | 29 ----------------------------- 1 file changed, 29 deletions(-) delete mode 100644 .github/workflows/secrets-scan.yml diff --git a/.github/workflows/secrets-scan.yml b/.github/workflows/secrets-scan.yml deleted file mode 100644 index 049c02f..0000000 --- a/.github/workflows/secrets-scan.yml +++ /dev/null @@ -1,29 +0,0 @@ -name: Secrets Scan -on: - pull_request: - types: [opened, synchronize, reopened] -jobs: - security-secrets: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - with: - fetch-depth: '2' - ref: '${{ github.event.pull_request.head.ref }}' - - run: | - git reset --soft HEAD~1 - - name: Install Talisman - run: | - # Download Talisman - wget https://github.com/thoughtworks/talisman/releases/download/v1.37.0/talisman_linux_amd64 -O talisman - - # Checksum verification - checksum=$(sha256sum ./talisman | awk '{print $1}') - if [ "$checksum" != "8e0ae8bb7b160bf10c4fa1448beb04a32a35e63505b3dddff74a092bccaaa7e4" ]; then exit 1; fi - - # Make it executable - chmod +x talisman - - name: Run talisman - run: | - # Run Talisman with the pre-commit hook - ./talisman --githook pre-commit \ No newline at end of file From d9a2904e676fd0d4d71abb3277d1678c9322ef90 Mon Sep 17 00:00:00 2001 From: Aravind Kumar Date: Mon, 8 Sep 2025 22:16:00 +0530 Subject: [PATCH 2/6] Updated codeowners --- CODEOWNERS | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/CODEOWNERS b/CODEOWNERS index 1be7e0d..785adb4 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -1 +1,9 @@ -* @contentstack/security-admin +* @contentstack/devex-pr-reviewers + +.github/workflows/sca-scan.yml @contentstack/security-admin + +**/.snyk @contentstack/security-admin + +.github/workflows/policy-scan.yml @contentstack/security-admin + +.github/workflows/issues-jira.yml @contentstack/security-admin From e9974cf550147b76064f2be97ef8f8202f207c71 Mon Sep 17 00:00:00 2001 From: Nadeem Patwekar Date: Wed, 29 Oct 2025 03:54:36 +0530 Subject: [PATCH 3/6] Add region configuration and endpoint retrieval for cloud services --- lib/assets/regions.json | 211 +++++++++++++++++++++++++++++ lib/contentstack.js | 5 +- lib/core/Util.js | 14 ++ lib/core/contentstackHTTPClient.js | 9 +- 4 files changed, 231 insertions(+), 8 deletions(-) create mode 100644 lib/assets/regions.json diff --git a/lib/assets/regions.json b/lib/assets/regions.json new file mode 100644 index 0000000..eafbba9 --- /dev/null +++ b/lib/assets/regions.json @@ -0,0 +1,211 @@ +{ + "regions": [ + { + "id": "na", + "name": "AWS North America", + "cloudProvider": "AWS", + "location": "North America", + "alias": [ + "na", + "us", + "aws-na", + "aws_na" + ], + "isDefault": true, + "endpoints": { + "application": "https://app.contentstack.com", + "contentDelivery": "https://cdn.contentstack.io", + "contentManagement": "https://api.contentstack.io", + "auth": "https://auth-api.contentstack.com", + "graphqlDelivery": "https://graphql.contentstack.com", + "preview": "https://rest-preview.contentstack.com", + "graphqlPreview": "https://graphql-preview.contentstack.com", + "images": "https://images.contentstack.io", + "assets": "https://assets.contentstack.io", + "automate": "https://automations-api.contentstack.com", + "launch": "https://launch-api.contentstack.com", + "developerHub": "https://developerhub-api.contentstack.com", + "brandKit": "https://brand-kits-api.contentstack.com", + "genAI": "https://ai.contentstack.com", + "personalize": "https://personalize-api.contentstack.com", + "personalizeEdge": "https://personalize-edge.contentstack.com" + } + }, + { + "id": "eu", + "name": "AWS Europe", + "cloudProvider": "AWS", + "location": "Europe", + "alias": [ + "eu", + "aws-eu", + "aws_eu" + ], + "isDefault": false, + "endpoints": { + "application": "https://eu-app.contentstack.com", + "contentDelivery": "https://eu-cdn.contentstack.com", + "contentManagement": "https://eu-api.contentstack.com", + "auth": "https://eu-auth-api.contentstack.com", + "graphqlDelivery": "https://eu-graphql.contentstack.com", + "preview": "https://eu-rest-preview.contentstack.com", + "graphqlPreview": "https://eu-graphql-preview.contentstack.com", + "images": "https://eu-images.contentstack.com", + "assets": "https://eu-assets.contentstack.com", + "automate": "https://eu-prod-automations-api.contentstack.com", + "launch": "https://eu-launch-api.contentstack.com", + "developerHub": "https://eu-developerhub-api.contentstack.com", + "brandKit": "https://eu-brand-kits-api.contentstack.com", + "genAI": "https://eu-ai.contentstack.com", + "personalize": "https://eu-personalize-api.contentstack.com", + "personalizeEdge": "https://eu-personalize-edge.contentstack.com" + } + }, + { + "id": "au", + "name": "AWS Australia", + "cloudProvider": "AWS", + "location": "Australia", + "alias": [ + "au", + "aws-au", + "aws_au" + ], + "isDefault": false, + "endpoints": { + "application": "https://au-app.contentstack.com", + "contentDelivery": "https://au-cdn.contentstack.com", + "contentManagement": "https://au-api.contentstack.com", + "auth": "https://au-auth-api.contentstack.com", + "graphqlDelivery": "https://au-graphql.contentstack.com", + "preview": "https://au-rest-preview.contentstack.com", + "graphqlPreview": "https://au-graphql-preview.contentstack.com", + "images": "https://au-images.contentstack.com", + "assets": "https://au-assets.contentstack.com", + "automate": "https://au-prod-automations-api.contentstack.com", + "launch": "https://au-launch-api.contentstack.com", + "developerHub": "https://au-developerhub-api.contentstack.com", + "brandKit": "https://au-brand-kits-api.contentstack.com", + "genAI": "https://au-ai.contentstack.com", + "personalize": "https://au-personalize-api.contentstack.com", + "personalizeEdge": "https://au-personalize-edge.contentstack.com" + } + }, + { + "id": "azure-na", + "name": "Azure North America", + "cloudProvider": "Azure", + "location": "North America", + "alias": [ + "azure-na", + "azure_na" + ], + "isDefault": false, + "endpoints": { + "application": "https://azure-na-app.contentstack.com", + "contentDelivery": "https://azure-na-cdn.contentstack.com", + "contentManagement": "https://azure-na-api.contentstack.com", + "auth": "https://azure-na-auth-api.contentstack.com", + "graphqlDelivery": "https://azure-na-graphql.contentstack.com", + "preview": "https://azure-na-rest-preview.contentstack.com", + "graphqlPreview": "https://azure-na-graphql-preview.contentstack.com", + "images": "https://azure-na-images.contentstack.com", + "assets": "https://azure-na-assets.contentstack.com", + "automate": "https://azure-na-automations-api.contentstack.com", + "launch": "https://azure-na-launch-api.contentstack.com", + "developerHub": "https://azure-na-developerhub-api.contentstack.com", + "brandKit": "https://azure-na-brand-kits-api.contentstack.com", + "genAI": "https://azure-na-ai.contentstack.com", + "personalize": "https://azure-na-personalize-api.contentstack.com", + "personalizeEdge": "https://azure-na-personalize-edge.contentstack.com" + } + }, + { + "id": "azure-eu", + "name": "Azure Europe", + "cloudProvider": "Azure", + "location": "Europe", + "alias": [ + "azure-eu", + "azure_eu" + ], + "isDefault": false, + "endpoints": { + "application": "https://azure-eu-app.contentstack.com", + "contentDelivery": "https://azure-eu-cdn.contentstack.com", + "contentManagement": "https://azure-eu-api.contentstack.com", + "auth": "https://azure-eu-auth-api.contentstack.com", + "graphqlDelivery": "https://azure-eu-graphql.contentstack.com", + "preview": "https://azure-eu-rest-preview.contentstack.com", + "graphqlPreview": "https://azure-eu-graphql-preview.contentstack.com", + "images": "https://azure-eu-images.contentstack.com", + "assets": "https://azure-eu-assets.contentstack.com", + "automate": "https://azure-eu-automations-api.contentstack.com", + "launch": "https://azure-eu-launch-api.contentstack.com", + "developerHub": "https://azure-eu-developerhub-api.contentstack.com", + "brandKit": "https://azure-eu-brand-kits-api.contentstack.com", + "genAI": "https://azure-eu-ai.contentstack.com", + "personalize": "https://azure-eu-personalize-api.contentstack.com", + "personalizeEdge": "https://azure-eu-personalize-edge.contentstack.com" + } + }, + { + "id": "gcp-na", + "name": "GCP North America", + "cloudProvider": "GCP", + "location": "North America", + "alias": [ + "gcp-na", + "gcp_na" + ], + "isDefault": false, + "endpoints": { + "application": "https://gcp-na-app.contentstack.com", + "contentDelivery": "https://gcp-na-cdn.contentstack.com", + "contentManagement": "https://gcp-na-api.contentstack.com", + "auth": "https://gcp-na-auth-api.contentstack.com", + "graphqlDelivery": "https://gcp-na-graphql.contentstack.com", + "preview": "https://gcp-na-rest-preview.contentstack.com", + "graphqlPreview": "https://gcp-na-graphql-preview.contentstack.com", + "images": "https://gcp-na-images.contentstack.com", + "assets": "https://gcp-na-assets.contentstack.com", + "automate": "https://gcp-na-automations-api.contentstack.com", + "launch": "https://gcp-na-launch-api.contentstack.com", + "developerHub": "https://gcp-na-developerhub-api.contentstack.com", + "brandKit": "https://gcp-na-brand-kits-api.contentstack.com", + "genAI": "https://gcp-na-brand-kits-api.contentstack.com", + "personalize": "https://gcp-na-personalize-api.contentstack.com", + "personalizeEdge": "https://gcp-na-personalize-edge.contentstack.com" + } + }, + { + "id": "gcp-eu", + "name": "GCP Europe", + "cloudProvider": "GCP", + "location": "Europe", + "alias": [ + "gcp-eu", + "gcp_eu" + ], + "isDefault": false, + "endpoints": { + "application": "https://gcp-eu-app.contentstack.com", + "contentDelivery": "https://gcp-eu-cdn.contentstack.com", + "contentManagement": "https://gcp-eu-api.contentstack.com", + "auth": "https://gcp-eu-auth-api.contentstack.com", + "graphqlDelivery": "https://gcp-eu-graphql.contentstack.com", + "preview": "https://gcp-eu-rest-preview.contentstack.com", + "graphqlPreview": "https://gcp-eu-graphql-preview.contentstack.com", + "images": "https://gcp-eu-images.contentstack.com", + "assets": "https://gcp-eu-assets.contentstack.com", + "automate": "https://gcp-eu-automations-api.contentstack.com", + "launch": "https://gcp-eu-launch-api.contentstack.com", + "developerHub": "https://gcp-eu-developerhub-api.contentstack.com", + "brandKit": "https://gcp-eu-brand-kits-api.contentstack.com", + "genAI": "https://gcp-eu-brand-kits-api.contentstack.com", + "personalize": "https://gcp-eu-personalize-api.contentstack.com", + "personalizeEdge": "https://gcp-eu-personalize-edge.contentstack.com" + } + } + ] +} diff --git a/lib/contentstack.js b/lib/contentstack.js index b33a11e..2a80fe6 100644 --- a/lib/contentstack.js +++ b/lib/contentstack.js @@ -4,7 +4,7 @@ */ import packages from '../package.json' import clonedeep from 'lodash/cloneDeep' -import getUserAgent from './core/Util.js' +import getUserAgent, { getRegionEndpoint } from './core/Util.js' import contentstackClient from './contentstackClient.js' import httpClient from './core/contentstackHTTPClient.js' import Region from './core/region.js' @@ -157,8 +157,9 @@ import Region from './core/region.js' * @returns Contentstack.Client */ function client (params = {}) { + const devHubHost = params.region ? getRegionEndpoint(params.region.toLowerCase(), 'developerHub') : getRegionEndpoint("na", 'developerHub') const defaultParameter = { - defaultHostName: 'developerhub-api.contentstack.com' + defaultHostName: devHubHost } const sdkAgent = `contentstack-marketplace-sdk/${packages.version}` diff --git a/lib/core/Util.js b/lib/core/Util.js index 0aa3c27..340af4b 100644 --- a/lib/core/Util.js +++ b/lib/core/Util.js @@ -1,4 +1,7 @@ import { platform, release } from 'os' +import regionHostMap from '../assets/regions.json' + + const HOST_REGEX = /^(?!\w+:\/\/)([\w-:]+\.)+([\w-:]+)(?::(\d+))?(?!:)$/ export function isHost (host) { @@ -100,3 +103,14 @@ export default function getUserAgent (sdk, application, integration, feature) { return `${headerParts.filter((item) => item !== '').join('; ')};` } + +export const getRegionEndpoint = (region, service = 'developerHub') => { + const regionData = regionHostMap.regions.find(r => + r.id === region || + r.alias.some(alias => alias === region) + ) + if (!regionData) { + throw new Error(`Invalid region '${region}' provided. Allowed regions are: ${regionHostMap.regions.map(r => r.id).join(', ')}`) + } + return regionData.endpoints[service]?.replace(/^https?:\/\//, '') +} \ No newline at end of file diff --git a/lib/core/contentstackHTTPClient.js b/lib/core/contentstackHTTPClient.js index 28e50f1..8d01acd 100644 --- a/lib/core/contentstackHTTPClient.js +++ b/lib/core/contentstackHTTPClient.js @@ -3,7 +3,6 @@ import clonedeep from 'lodash/cloneDeep' import Qs from 'qs' import { ConcurrencyQueue } from './concurrency-queue' import { isHost } from './Util' -import Region from './region' export default function contentstackHttpClient (options) { const defaultConfig = { @@ -61,11 +60,9 @@ export default function contentstackHttpClient (options) { if (config.basePath) { config.basePath = `/${config.basePath.split('/').filter(Boolean).join('/')}` } - if (config.region && config.region !== Region.NA) { - baseUrlPath = `${protocol}://${config.region}-${hostname}:${port}${config.basePath}` - } else { - baseUrlPath = `${protocol}://${hostname}:${port}${config.basePath}` - } + + baseUrlPath = `${protocol}://${hostname}:${port}${config.basePath}` + const baseURL = config.endpoint || baseUrlPath const axiosOptions = { // Axios From 0839d3329b8e3bf8b00d04c04ed132eeee06a9d7 Mon Sep 17 00:00:00 2001 From: Nadeem Patwekar Date: Wed, 29 Oct 2025 04:08:57 +0530 Subject: [PATCH 4/6] Update changelog and version to 1.4.1; add region endpoint utility and enhance HTTP client tests for multi-cloud support --- CHANGELOG.md | 7 +- package-lock.json | 40 +++++++---- package.json | 2 +- test/unit/ContentstackHTTPClient-test.js | 4 +- test/unit/Util-test.js | 91 +++++++++++++++++++++++- test/unit/contentstack-test.js | 60 ++++++++++++++++ 6 files changed, 184 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3ed6fc8..a352820 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,11 @@ # Changelog -## [v1.4.0](https://github.com/contentstack/contentstack-marketplace-sdk/tree/v1.3.0) (2024-08-25) +## [v1.4.1](https://github.com/contentstack/contentstack-marketplace-sdk/tree/v1.4.1) (2025-10-28) + - Enhancement: Add region configuration and endpoint retrieval for cloud services + - Enhancement: Support for Azure and GCP regions with multi-cloud endpoint management + - Enhancement: New `getRegionEndpoint` utility function to retrieve region-specific service endpoints + +## [v1.4.0](https://github.com/contentstack/contentstack-marketplace-sdk/tree/v1.4.0) (2024-08-25) - Enhancement: Retry logic to make use of x-ratelimit-remaining header ## [v1.3.0](https://github.com/contentstack/contentstack-marketplace-sdk/tree/v1.3.0) (2024-08-11) diff --git a/package-lock.json b/package-lock.json index c8f3942..cf02f0d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@contentstack/marketplace-sdk", - "version": "1.4.0", + "version": "1.4.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@contentstack/marketplace-sdk", - "version": "1.4.0", + "version": "1.4.1", "license": "MIT", "dependencies": { "axios": "^1.11.0" @@ -130,6 +130,7 @@ "integrity": "sha512-UlLAnTPrFdNGoFtbSXwcGFQBtQZJCNjaN6hQNP3UPvuNXT1i82N26KL3dZeIpNalWywr9IuQuncaAfUaS1g6sQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.27.1", @@ -3240,7 +3241,6 @@ "integrity": "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@types/connect": "*", "@types/node": "*" @@ -3252,7 +3252,6 @@ "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@types/node": "*" } @@ -3305,7 +3304,6 @@ "integrity": "sha512-R+33OsgWw7rOhD1emjU7dzCDHucJrgJXMA5PYCzJxVil0dsyx5iBEPHqpPfiKNJQb7lZ1vxwoLR4Z87bBUpeGQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@types/node": "*", "@types/qs": "*", @@ -3339,8 +3337,7 @@ "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.5.tgz", "integrity": "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/@types/istanbul-lib-coverage": { "version": "2.0.6", @@ -3418,6 +3415,7 @@ "integrity": "sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@types/linkify-it": "^5", "@types/mdurl": "^2" @@ -3435,8 +3433,7 @@ "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/@types/minimatch": { "version": "5.1.2", @@ -3481,16 +3478,14 @@ "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.14.0.tgz", "integrity": "sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/@types/range-parser": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/@types/retry": { "version": "0.12.0", @@ -3505,7 +3500,6 @@ "integrity": "sha512-z6F2D3cOStZvuk2SaP6YrwkNO65iTZcwA2ZkSABegdkAh/lf+Aa/YQndZVfmEXT5vgAp6zv06VQ3ejSVjAny4w==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@types/mime": "^1", "@types/node": "*" @@ -3517,7 +3511,6 @@ "integrity": "sha512-roei0UY3LhpOJvjbIP6ZZFngyLKl5dskOtDhxY5THRSpO+ZI+nzJ+m5yUMzGrp89YRa7lvknKkMYjqQFGwA7Sg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@types/http-errors": "*", "@types/node": "*", @@ -3799,6 +3792,7 @@ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -3849,6 +3843,7 @@ "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -4188,6 +4183,7 @@ "resolved": "https://registry.npmjs.org/axios/-/axios-1.11.0.tgz", "integrity": "sha512-1Lx3WLFQWm3ooKDYZD1eXmoGO9fxYQjrycfHFC8P0sCfQVXyROp0p9PFWBehewBOdCwHc+f/b8I0fMto5eSfwA==", "license": "MIT", + "peer": true, "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.4", @@ -4807,6 +4803,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "caniuse-lite": "^1.0.30001726", "electron-to-chromium": "^1.5.173", @@ -6012,6 +6009,7 @@ "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", @@ -6149,6 +6147,7 @@ "integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@rtsao/scc": "^1.1.0", "array-includes": "^3.1.9", @@ -6206,6 +6205,7 @@ "integrity": "sha512-2abNmzAH/JpxI4gEOwd6K8wZIodK3BmHbTxz4s79OIYwwIt2gkpEXlAouJXu4H1c9ySTnRso0tsuthSOZbUMlA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "eslint-plugin-es": "^1.4.1", "eslint-utils": "^1.4.2", @@ -6227,6 +6227,7 @@ "integrity": "sha512-bY2sGqyptzFBDLh/GMbAxfdJC+b0f23ME63FOE4+Jao0oZ3E1LEwFtWJX/1pGMJLiTtrSSern2CRM/g+dfc0eQ==", "dev": true, "license": "ISC", + "peer": true, "engines": { "node": ">=6" } @@ -6251,6 +6252,7 @@ } ], "license": "MIT", + "peer": true, "peerDependencies": { "eslint": ">=5.0.0" } @@ -8490,6 +8492,7 @@ "integrity": "sha512-N4GT5on8UkZgH0O5LUavMRV1EDEhNTL0KEfRmDIeZHSV7p2XgLoY9t9VDUgL6o+yfdgYHVxuz81G8oB9VG5uyA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@jest/core": "^28.1.3", "@jest/types": "^28.1.3", @@ -10372,6 +10375,7 @@ "integrity": "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "argparse": "^2.0.1", "entities": "^4.4.0", @@ -13239,6 +13243,7 @@ "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", @@ -13650,6 +13655,7 @@ "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", @@ -14049,6 +14055,7 @@ "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", "dev": true, "license": "Apache-2.0", + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -14290,6 +14297,7 @@ "integrity": "sha512-B4t+nJqytPeuZlHuIKTbalhljIFXeNRqrUGAQgTGlfOl2lXXKXw+yZu6bicycP+PUlM44CxBjCFD6aciKFT3LQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@types/eslint-scope": "^3.7.7", "@types/estree": "^1.0.8", @@ -14339,6 +14347,7 @@ "integrity": "sha512-NLhDfH/h4O6UOy+0LSso42xvYypClINuMNBVVzX4vX98TmTaTUxwRbXdhucbFMd2qLaCTcLq/PdYrvi8onw90w==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@discoveryjs/json-ext": "^0.5.0", "@webpack-cli/configtest": "^1.2.0", @@ -14432,6 +14441,7 @@ "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", diff --git a/package.json b/package.json index 297c631..6d012bc 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@contentstack/marketplace-sdk", - "version": "1.4.0", + "version": "1.4.1", "description": "The Contentstack Marketplace SDK is used to manage the content of your Contentstack marketplace apps", "main": "./dist/node/contentstack-marketplace.js", "browser": "./dist/web/contentstack-marketplace.js", diff --git a/test/unit/ContentstackHTTPClient-test.js b/test/unit/ContentstackHTTPClient-test.js index c7e76e1..4008664 100644 --- a/test/unit/ContentstackHTTPClient-test.js +++ b/test/unit/ContentstackHTTPClient-test.js @@ -164,7 +164,7 @@ describe('Contentstack HTTP Client', () => { host: 'contentstack.com:443' }) expect(axiosInstance.defaults.region).to.be.equal('azure-eu') - expect(axiosInstance.defaults.baseURL).to.be.equal('https://azure-eu-contentstack.com:443') + expect(axiosInstance.defaults.baseURL).to.be.equal('https://contentstack.com:443') done() }) @@ -176,7 +176,7 @@ describe('Contentstack HTTP Client', () => { host: 'contentstack.com:443' }) expect(axiosInstance.defaults.region).to.be.equal('gcp-na') - expect(axiosInstance.defaults.baseURL).to.be.equal('https://gcp-na-contentstack.com:443') + expect(axiosInstance.defaults.baseURL).to.be.equal('https://contentstack.com:443') done() }) }) diff --git a/test/unit/Util-test.js b/test/unit/Util-test.js index d41bfe3..d928588 100644 --- a/test/unit/Util-test.js +++ b/test/unit/Util-test.js @@ -1,4 +1,4 @@ -import getUserAgent, { __RewireAPI__ as getUserAgentRewireApi, isHost } from '../../lib/core/Util.js' +import getUserAgent, { __RewireAPI__ as getUserAgentRewireApi, isHost, getRegionEndpoint } from '../../lib/core/Util.js' import { expect } from 'chai' import { describe, it } from 'mocha' const headerRegEx = /(app|sdk|platform|integration|os) \S+(\/\d+.\d+.\d+(-[\w\d-]+)?)?;/igm @@ -126,3 +126,92 @@ describe('Get User Agent', () => { done() }) }) + +describe('Get Region Endpoint', () => { + it('should return default NA region developerHub endpoint', done => { + const endpoint = getRegionEndpoint('na') + expect(endpoint).to.be.equal('developerhub-api.contentstack.com', 'NA region developerHub endpoint should match') + done() + }) + + it('should return NA region developerHub endpoint using alias', done => { + const endpoint = getRegionEndpoint('us') + expect(endpoint).to.be.equal('developerhub-api.contentstack.com', 'US alias should return NA developerHub endpoint') + done() + }) + + it('should return EU region developerHub endpoint', done => { + const endpoint = getRegionEndpoint('eu') + expect(endpoint).to.be.equal('eu-developerhub-api.contentstack.com', 'EU region developerHub endpoint should match') + done() + }) + + it('should return Azure NA region developerHub endpoint', done => { + const endpoint = getRegionEndpoint('azure-na') + expect(endpoint).to.be.equal('azure-na-developerhub-api.contentstack.com', 'Azure NA region developerHub endpoint should match') + done() + }) + + it('should return Azure NA region developerHub endpoint using alias', done => { + const endpoint = getRegionEndpoint('azure_na') + expect(endpoint).to.be.equal('azure-na-developerhub-api.contentstack.com', 'Azure NA alias should return developerHub endpoint') + done() + }) + + it('should return GCP NA region developerHub endpoint', done => { + const endpoint = getRegionEndpoint('gcp-na') + expect(endpoint).to.be.equal('gcp-na-developerhub-api.contentstack.com', 'GCP NA region developerHub endpoint should match') + done() + }) + + it('should return GCP EU region developerHub endpoint', done => { + const endpoint = getRegionEndpoint('gcp-eu') + expect(endpoint).to.be.equal('gcp-eu-developerhub-api.contentstack.com', 'GCP EU region developerHub endpoint should match') + done() + }) + + it('should return AU region contentManagement endpoint', done => { + const endpoint = getRegionEndpoint('au', 'contentManagement') + expect(endpoint).to.be.equal('au-api.contentstack.com', 'AU region contentManagement endpoint should match') + done() + }) + + it('should return NA region auth endpoint', done => { + const endpoint = getRegionEndpoint('na', 'auth') + expect(endpoint).to.be.equal('auth-api.contentstack.com', 'NA region auth endpoint should match') + done() + }) + + it('should return EU region contentDelivery endpoint', done => { + const endpoint = getRegionEndpoint('eu', 'contentDelivery') + expect(endpoint).to.be.equal('eu-cdn.contentstack.com', 'EU region contentDelivery endpoint should match') + done() + }) + + it('should throw error for invalid region', done => { + try { + getRegionEndpoint('invalid-region') + done(new Error('Should have thrown an error for invalid region')) + } catch (error) { + expect(error.message).to.include('Invalid region') + expect(error.message).to.include('invalid-region') + done() + } + }) + + it('should return Azure EU region application endpoint', done => { + const endpoint = getRegionEndpoint('azure-eu', 'application') + expect(endpoint).to.be.equal('azure-eu-app.contentstack.com', 'Azure EU region application endpoint should match') + done() + }) + + it('should return all regions developerHub endpoints', done => { + const regions = ['na', 'eu', 'au', 'azure-na', 'azure-eu', 'gcp-na', 'gcp-eu'] + regions.forEach(region => { + const endpoint = getRegionEndpoint(region, 'developerHub') + expect(endpoint).to.be.a('string') + expect(endpoint).to.include('contentstack.com') + }) + done() + }) +}) diff --git a/test/unit/contentstack-test.js b/test/unit/contentstack-test.js index 0e738fd..6c7072b 100644 --- a/test/unit/contentstack-test.js +++ b/test/unit/contentstack-test.js @@ -55,6 +55,66 @@ describe('Contentstack HTTP Client', () => { done() }) + it('Contentstack Http Client Default Host with NA region', done => { + createClientRewireApi.__Rewire__('client', { create: sinon.stub() }) + const createHttpClientStub = sinon.stub() + createClientRewireApi.__Rewire__('httpClient', createHttpClientStub) + createClientRewireApi.__Rewire__('contentstackClient', sinon.stub().returns({})) + client({ region: 'na' }) + expect(createHttpClientStub.args[0][0].defaultHostName).to.be.equal('developerhub-api.contentstack.com', 'NA region host name not match') + createClientRewireApi.__ResetDependency__('httpClient') + createClientRewireApi.__ResetDependency__('contentstackClient') + done() + }) + + it('Contentstack Http Client Default Host with EU region', done => { + createClientRewireApi.__Rewire__('client', { create: sinon.stub() }) + const createHttpClientStub = sinon.stub() + createClientRewireApi.__Rewire__('httpClient', createHttpClientStub) + createClientRewireApi.__Rewire__('contentstackClient', sinon.stub().returns({})) + client({ region: 'eu' }) + expect(createHttpClientStub.args[0][0].defaultHostName).to.be.equal('eu-developerhub-api.contentstack.com', 'EU region host name not match') + createClientRewireApi.__ResetDependency__('httpClient') + createClientRewireApi.__ResetDependency__('contentstackClient') + done() + }) + + it('Contentstack Http Client Default Host with Azure NA region', done => { + createClientRewireApi.__Rewire__('client', { create: sinon.stub() }) + const createHttpClientStub = sinon.stub() + createClientRewireApi.__Rewire__('httpClient', createHttpClientStub) + createClientRewireApi.__Rewire__('contentstackClient', sinon.stub().returns({})) + client({ region: 'azure-na' }) + expect(createHttpClientStub.args[0][0].defaultHostName).to.be.equal('azure-na-developerhub-api.contentstack.com', 'Azure NA region host name not match') + createClientRewireApi.__ResetDependency__('httpClient') + createClientRewireApi.__ResetDependency__('contentstackClient') + done() + }) + + it('Contentstack Http Client Default Host with GCP EU region', done => { + createClientRewireApi.__Rewire__('client', { create: sinon.stub() }) + const createHttpClientStub = sinon.stub() + createClientRewireApi.__Rewire__('httpClient', createHttpClientStub) + createClientRewireApi.__Rewire__('contentstackClient', sinon.stub().returns({})) + client({ region: 'gcp-eu' }) + expect(createHttpClientStub.args[0][0].defaultHostName).to.be.equal('gcp-eu-developerhub-api.contentstack.com', 'GCP EU region host name not match') + createClientRewireApi.__ResetDependency__('httpClient') + createClientRewireApi.__ResetDependency__('contentstackClient') + done() + }) + + it('Contentstack Http Client Default Host with uppercase region', done => { + createClientRewireApi.__Rewire__('client', { create: sinon.stub() }) + const createHttpClientStub = sinon.stub() + createClientRewireApi.__Rewire__('httpClient', createHttpClientStub) + createClientRewireApi.__Rewire__('contentstackClient', sinon.stub().returns({})) + client({ region: 'EU' }) + expect(createHttpClientStub.args[0][0].defaultHostName).to.be.equal('eu-developerhub-api.contentstack.com', 'Uppercase EU region should be handled') + createClientRewireApi.__ResetDependency__('httpClient') + createClientRewireApi.__ResetDependency__('contentstackClient') + done() + }) + it('Contentstack Http Client Default Host Custom', done => { createClientRewireApi.__Rewire__('client', { create: sinon.stub() }) const createHttpClientStub = sinon.stub() From 08ee1cd19811113a70f66a3e894d864b7c61f15f Mon Sep 17 00:00:00 2001 From: Nadeem Patwekar Date: Wed, 29 Oct 2025 04:16:28 +0530 Subject: [PATCH 5/6] Add postinstall and postupdate scripts to fetch regions.json --- package.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 6d012bc..14063ed 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,9 @@ "pretest": "rimraf coverage && npm run lint", "precommit": "npm run lint", "prepush": "npm run test:unit", - "husky-check": "npx husky && chmod +x .husky/pre-commit" + "husky-check": "npx husky && chmod +x .husky/pre-commit", + "postinstall": "curl -s --max-time 30 --fail https://artifacts.contentstack.com/regions.json -o lib/assets/regions.json || echo 'Warning: Failed to download regions.json, using existing file if available'", + "postupdate": "curl -s --max-time 30 --fail https://artifacts.contentstack.com/regions.json -o lib/assets/regions.json || echo 'Warning: Failed to download regions.json, using existing file if available'" }, "repository": { "type": "git", From 3c7a527be5052f30d416f25cd4954f84c7fd22ff Mon Sep 17 00:00:00 2001 From: Nadeem Patwekar Date: Wed, 29 Oct 2025 12:05:00 +0530 Subject: [PATCH 6/6] Update axios dependency to version 1.13.1 and add hasInstallScript flag in package-lock.json --- .talismanrc | 2 +- lib/core/Util.js | 2 +- package-lock.json | 9 +++++---- package.json | 2 +- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/.talismanrc b/.talismanrc index ce69452..90e9bf1 100644 --- a/.talismanrc +++ b/.talismanrc @@ -6,7 +6,7 @@ fileignoreconfig: - filename: test/unit/mock/execution-mock.js checksum: 89d239d37c9d8d0cdb6ac61553a7d2e2d9115a10207f7c0b387c3565c9cb6564 - filename: package-lock.json - checksum: a858212afa05186f2b39958b6608610cb150324acca7e9efc0f3d76fde347375 + checksum: e165fb372305f63445958fa6d660e5837ce419e6ca2284d4aece47b3753e24b1 - filename: docdash-template/fixtures/documents/probe.js checksum: e841ecf889d0e82367c53c48ee0b3be8bd68d7babf4777a87ced769f29686ac4 - filename: docdash-template/.travis.yml diff --git a/lib/core/Util.js b/lib/core/Util.js index 340af4b..69afa00 100644 --- a/lib/core/Util.js +++ b/lib/core/Util.js @@ -113,4 +113,4 @@ export const getRegionEndpoint = (region, service = 'developerHub') => { throw new Error(`Invalid region '${region}' provided. Allowed regions are: ${regionHostMap.regions.map(r => r.id).join(', ')}`) } return regionData.endpoints[service]?.replace(/^https?:\/\//, '') -} \ No newline at end of file +} diff --git a/package-lock.json b/package-lock.json index cf02f0d..bfe7f97 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7,9 +7,10 @@ "": { "name": "@contentstack/marketplace-sdk", "version": "1.4.1", + "hasInstallScript": true, "license": "MIT", "dependencies": { - "axios": "^1.11.0" + "axios": "^1.13.1" }, "devDependencies": { "@babel/cli": "^7.28.0", @@ -4179,9 +4180,9 @@ } }, "node_modules/axios": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.11.0.tgz", - "integrity": "sha512-1Lx3WLFQWm3ooKDYZD1eXmoGO9fxYQjrycfHFC8P0sCfQVXyROp0p9PFWBehewBOdCwHc+f/b8I0fMto5eSfwA==", + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.1.tgz", + "integrity": "sha512-hU4EGxxt+j7TQijx1oYdAjw4xuIp1wRQSsbMFwSthCWeBQur1eF+qJ5iQ5sN3Tw8YRzQNKb8jszgBdMDVqwJcw==", "license": "MIT", "peer": true, "dependencies": { diff --git a/package.json b/package.json index 14063ed..d346f3d 100644 --- a/package.json +++ b/package.json @@ -95,6 +95,6 @@ "webpack-merge": "4.2.2" }, "dependencies": { - "axios": "^1.11.0" + "axios": "^1.13.1" } }