Skip to content

Commit c678d46

Browse files
Merge pull request #446 from contentstack/development
Development
2 parents 2997559 + 66c860b commit c678d46

File tree

12 files changed

+892
-60
lines changed

12 files changed

+892
-60
lines changed

.talismanrc

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ fileignoreconfig:
99
ignore_detectors:
1010
- filecontent
1111
- filename: package-lock.json
12-
checksum: bab53d56ce2609e960fdbbd1e87cc89915820e6761016ddd74ee57f931f4223d
12+
checksum: 1475ee2c6a615f4e6f8393f4a209398aa6b827e7d036302c6fc065d5914e8292
1313
- filename: .husky/pre-commit
1414
checksum: 52a664f536cf5d1be0bea19cb6031ca6e8107b45b6314fe7d47b7fad7d800632
1515
- filename: test/sanity-check/api/user-test.js
@@ -30,4 +30,11 @@ fileignoreconfig:
3030
checksum: b76ca091caa3a1b2658cd422a2d8ef3ac9996aea0aff3f982d56bb309a3d9fde
3131
- filename: test/unit/ContentstackClient-test.js
3232
checksum: 974a4f335aef025b657d139bb290233a69bed1976b947c3c674e97baffe4ce2f
33+
- filename: test/unit/ContentstackHTTPClient-test.js
34+
checksum: 4043efd843e24da9afd0272c55ef4b0432e3374b2ca12b913f1a6654df3f62be
35+
- filename: test/unit/contentstack-test.js
36+
checksum: 2597efae3c1ab8cc173d5bf205f1c76932211f8e0eb2a16444e055d83481976c
3337
version: "1.0"
38+
39+
40+

CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,15 @@
11
# Changelog
22

3+
## [v1.25.2](https://github.com/contentstack/contentstack-management-javascript/tree/v1.25.2) (2025-10-28)
4+
- Fix
5+
- Fixed HTTP client region endpoint initialization to default to 'na' region when region parameter is not provided
6+
- Test
7+
- Added comprehensive test coverage for region endpoint functionality
8+
- Added 48 test cases for getRegionEndpoint function covering all supported regions, aliases, and service endpoints
9+
- Added 14 test cases for region configuration in client initialization
10+
- Added 13 test cases for HTTP client region integration
11+
- All 626 tests passing with no regressions
12+
313
## [v1.25.1](https://github.com/contentstack/contentstack-management-javascript/tree/v1.25.1) (2025-10-06)
414
- Fix
515
- Updated delay handling to use centralized external configuration in SDK interceptor

lib/assets/regions.json

Lines changed: 211 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,211 @@
1+
{
2+
"regions": [
3+
{
4+
"id": "na",
5+
"name": "AWS North America",
6+
"cloudProvider": "AWS",
7+
"location": "North America",
8+
"alias": [
9+
"na",
10+
"us",
11+
"aws-na",
12+
"aws_na"
13+
],
14+
"isDefault": true,
15+
"endpoints": {
16+
"application": "https://app.contentstack.com",
17+
"contentDelivery": "https://cdn.contentstack.io",
18+
"contentManagement": "https://api.contentstack.io",
19+
"auth": "https://auth-api.contentstack.com",
20+
"graphqlDelivery": "https://graphql.contentstack.com",
21+
"preview": "https://rest-preview.contentstack.com",
22+
"graphqlPreview": "https://graphql-preview.contentstack.com",
23+
"images": "https://images.contentstack.io",
24+
"assets": "https://assets.contentstack.io",
25+
"automate": "https://automations-api.contentstack.com",
26+
"launch": "https://launch-api.contentstack.com",
27+
"developerHub": "https://developerhub-api.contentstack.com",
28+
"brandKit": "https://brand-kits-api.contentstack.com",
29+
"genAI": "https://ai.contentstack.com",
30+
"personalize": "https://personalize-api.contentstack.com",
31+
"personalizeEdge": "https://personalize-edge.contentstack.com"
32+
}
33+
},
34+
{
35+
"id": "eu",
36+
"name": "AWS Europe",
37+
"cloudProvider": "AWS",
38+
"location": "Europe",
39+
"alias": [
40+
"eu",
41+
"aws-eu",
42+
"aws_eu"
43+
],
44+
"isDefault": false,
45+
"endpoints": {
46+
"application": "https://eu-app.contentstack.com",
47+
"contentDelivery": "https://eu-cdn.contentstack.com",
48+
"contentManagement": "https://eu-api.contentstack.com",
49+
"auth": "https://eu-auth-api.contentstack.com",
50+
"graphqlDelivery": "https://eu-graphql.contentstack.com",
51+
"preview": "https://eu-rest-preview.contentstack.com",
52+
"graphqlPreview": "https://eu-graphql-preview.contentstack.com",
53+
"images": "https://eu-images.contentstack.com",
54+
"assets": "https://eu-assets.contentstack.com",
55+
"automate": "https://eu-prod-automations-api.contentstack.com",
56+
"launch": "https://eu-launch-api.contentstack.com",
57+
"developerHub": "https://eu-developerhub-api.contentstack.com",
58+
"brandKit": "https://eu-brand-kits-api.contentstack.com",
59+
"genAI": "https://eu-ai.contentstack.com",
60+
"personalize": "https://eu-personalize-api.contentstack.com",
61+
"personalizeEdge": "https://eu-personalize-edge.contentstack.com"
62+
}
63+
},
64+
{
65+
"id": "au",
66+
"name": "AWS Australia",
67+
"cloudProvider": "AWS",
68+
"location": "Australia",
69+
"alias": [
70+
"au",
71+
"aws-au",
72+
"aws_au"
73+
],
74+
"isDefault": false,
75+
"endpoints": {
76+
"application": "https://au-app.contentstack.com",
77+
"contentDelivery": "https://au-cdn.contentstack.com",
78+
"contentManagement": "https://au-api.contentstack.com",
79+
"auth": "https://au-auth-api.contentstack.com",
80+
"graphqlDelivery": "https://au-graphql.contentstack.com",
81+
"preview": "https://au-rest-preview.contentstack.com",
82+
"graphqlPreview": "https://au-graphql-preview.contentstack.com",
83+
"images": "https://au-images.contentstack.com",
84+
"assets": "https://au-assets.contentstack.com",
85+
"automate": "https://au-prod-automations-api.contentstack.com",
86+
"launch": "https://au-launch-api.contentstack.com",
87+
"developerHub": "https://au-developerhub-api.contentstack.com",
88+
"brandKit": "https://au-brand-kits-api.contentstack.com",
89+
"genAI": "https://au-ai.contentstack.com",
90+
"personalize": "https://au-personalize-api.contentstack.com",
91+
"personalizeEdge": "https://au-personalize-edge.contentstack.com"
92+
}
93+
},
94+
{
95+
"id": "azure-na",
96+
"name": "Azure North America",
97+
"cloudProvider": "Azure",
98+
"location": "North America",
99+
"alias": [
100+
"azure-na",
101+
"azure_na"
102+
],
103+
"isDefault": false,
104+
"endpoints": {
105+
"application": "https://azure-na-app.contentstack.com",
106+
"contentDelivery": "https://azure-na-cdn.contentstack.com",
107+
"contentManagement": "https://azure-na-api.contentstack.com",
108+
"auth": "https://azure-na-auth-api.contentstack.com",
109+
"graphqlDelivery": "https://azure-na-graphql.contentstack.com",
110+
"preview": "https://azure-na-rest-preview.contentstack.com",
111+
"graphqlPreview": "https://azure-na-graphql-preview.contentstack.com",
112+
"images": "https://azure-na-images.contentstack.com",
113+
"assets": "https://azure-na-assets.contentstack.com",
114+
"automate": "https://azure-na-automations-api.contentstack.com",
115+
"launch": "https://azure-na-launch-api.contentstack.com",
116+
"developerHub": "https://azure-na-developerhub-api.contentstack.com",
117+
"brandKit": "https://azure-na-brand-kits-api.contentstack.com",
118+
"genAI": "https://azure-na-ai.contentstack.com",
119+
"personalize": "https://azure-na-personalize-api.contentstack.com",
120+
"personalizeEdge": "https://azure-na-personalize-edge.contentstack.com"
121+
}
122+
},
123+
{
124+
"id": "azure-eu",
125+
"name": "Azure Europe",
126+
"cloudProvider": "Azure",
127+
"location": "Europe",
128+
"alias": [
129+
"azure-eu",
130+
"azure_eu"
131+
],
132+
"isDefault": false,
133+
"endpoints": {
134+
"application": "https://azure-eu-app.contentstack.com",
135+
"contentDelivery": "https://azure-eu-cdn.contentstack.com",
136+
"contentManagement": "https://azure-eu-api.contentstack.com",
137+
"auth": "https://azure-eu-auth-api.contentstack.com",
138+
"graphqlDelivery": "https://azure-eu-graphql.contentstack.com",
139+
"preview": "https://azure-eu-rest-preview.contentstack.com",
140+
"graphqlPreview": "https://azure-eu-graphql-preview.contentstack.com",
141+
"images": "https://azure-eu-images.contentstack.com",
142+
"assets": "https://azure-eu-assets.contentstack.com",
143+
"automate": "https://azure-eu-automations-api.contentstack.com",
144+
"launch": "https://azure-eu-launch-api.contentstack.com",
145+
"developerHub": "https://azure-eu-developerhub-api.contentstack.com",
146+
"brandKit": "https://azure-eu-brand-kits-api.contentstack.com",
147+
"genAI": "https://azure-eu-ai.contentstack.com",
148+
"personalize": "https://azure-eu-personalize-api.contentstack.com",
149+
"personalizeEdge": "https://azure-eu-personalize-edge.contentstack.com"
150+
}
151+
},
152+
{
153+
"id": "gcp-na",
154+
"name": "GCP North America",
155+
"cloudProvider": "GCP",
156+
"location": "North America",
157+
"alias": [
158+
"gcp-na",
159+
"gcp_na"
160+
],
161+
"isDefault": false,
162+
"endpoints": {
163+
"application": "https://gcp-na-app.contentstack.com",
164+
"contentDelivery": "https://gcp-na-cdn.contentstack.com",
165+
"contentManagement": "https://gcp-na-api.contentstack.com",
166+
"auth": "https://gcp-na-auth-api.contentstack.com",
167+
"graphqlDelivery": "https://gcp-na-graphql.contentstack.com",
168+
"preview": "https://gcp-na-rest-preview.contentstack.com",
169+
"graphqlPreview": "https://gcp-na-graphql-preview.contentstack.com",
170+
"images": "https://gcp-na-images.contentstack.com",
171+
"assets": "https://gcp-na-assets.contentstack.com",
172+
"automate": "https://gcp-na-automations-api.contentstack.com",
173+
"launch": "https://gcp-na-launch-api.contentstack.com",
174+
"developerHub": "https://gcp-na-developerhub-api.contentstack.com",
175+
"brandKit": "https://gcp-na-brand-kits-api.contentstack.com",
176+
"genAI": "https://gcp-na-brand-kits-api.contentstack.com",
177+
"personalize": "https://gcp-na-personalize-api.contentstack.com",
178+
"personalizeEdge": "https://gcp-na-personalize-edge.contentstack.com"
179+
}
180+
},
181+
{
182+
"id": "gcp-eu",
183+
"name": "GCP Europe",
184+
"cloudProvider": "GCP",
185+
"location": "Europe",
186+
"alias": [
187+
"gcp-eu",
188+
"gcp_eu"
189+
],
190+
"isDefault": false,
191+
"endpoints": {
192+
"application": "https://gcp-eu-app.contentstack.com",
193+
"contentDelivery": "https://gcp-eu-cdn.contentstack.com",
194+
"contentManagement": "https://gcp-eu-api.contentstack.com",
195+
"auth": "https://gcp-eu-auth-api.contentstack.com",
196+
"graphqlDelivery": "https://gcp-eu-graphql.contentstack.com",
197+
"preview": "https://gcp-eu-rest-preview.contentstack.com",
198+
"graphqlPreview": "https://gcp-eu-graphql-preview.contentstack.com",
199+
"images": "https://gcp-eu-images.contentstack.com",
200+
"assets": "https://gcp-eu-assets.contentstack.com",
201+
"automate": "https://gcp-eu-automations-api.contentstack.com",
202+
"launch": "https://gcp-eu-launch-api.contentstack.com",
203+
"developerHub": "https://gcp-eu-developerhub-api.contentstack.com",
204+
"brandKit": "https://gcp-eu-brand-kits-api.contentstack.com",
205+
"genAI": "https://gcp-eu-brand-kits-api.contentstack.com",
206+
"personalize": "https://gcp-eu-personalize-api.contentstack.com",
207+
"personalizeEdge": "https://gcp-eu-personalize-edge.contentstack.com"
208+
}
209+
}
210+
]
211+
}

lib/contentstack.js

Lines changed: 3 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,9 @@
44
*/
55
import packages from '../package.json'
66
import clonedeep from 'lodash/cloneDeep'
7-
import getUserAgent from './core/Util.js'
7+
import getUserAgent, { getRegionEndpoint } from './core/Util.js'
88
import contentstackClient from './contentstackClient.js'
99
import httpClient from './core/contentstackHTTPClient.js'
10-
const regionHostMap = {
11-
NA: 'api.contentstack.io',
12-
EU: 'eu-api.contentstack.com',
13-
AU: 'au-api.contentstack.com',
14-
AZURE_NA: 'azure-na-api.contentstack.com',
15-
AZURE_EU: 'azure-eu-api.contentstack.com',
16-
GCP_NA: 'gcp-na-api.contentstack.com',
17-
GCP_EU: 'gcp-eu-api.contentstack.com'
18-
}
1910

2011
/**
2112
* Create client instance
@@ -170,18 +161,10 @@ const regionHostMap = {
170161
* @returns Contentstack.Client
171162
*/
172163
export function client (params = {}) {
173-
let defaultHostName
164+
let defaultHostName = getRegionEndpoint('na')
174165

175166
if (params.region) {
176-
const region = params.region.toUpperCase()
177-
if (!regionHostMap[region]) {
178-
throw new Error(`Invalid region '${params.region}' provided. Allowed regions are: ${Object.keys(regionHostMap).join(', ')}`)
179-
}
180-
defaultHostName = regionHostMap[region]
181-
} else if (params.host) {
182-
defaultHostName = params.host
183-
} else {
184-
defaultHostName = regionHostMap['NA']
167+
defaultHostName = getRegionEndpoint(params.region.toLowerCase())
185168
}
186169

187170
const defaultParameter = {

lib/core/Util.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import { platform, release } from 'os'
2+
import regionHostMap from '../assets/regions.json'
3+
24
const HOST_REGEX = /^(?!(?:(?:https?|ftp):\/\/|internal|localhost|(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)))(?:[\w-]+\.contentstack\.(?:io|com)(?::[^\/\s:]+)?|[\w-]+(?:\.[\w-]+)*(?::[^\/\s:]+)?)(?![\/?#])$/ // eslint-disable-line
35

46
export function isHost (host) {
@@ -235,3 +237,14 @@ export const validateAndSanitizeConfig = (config) => {
235237
url: config.url.trim() // Sanitize URL by removing whitespace
236238
}
237239
}
240+
241+
export const getRegionEndpoint = (region, service = 'contentManagement') => {
242+
const regionData = regionHostMap.regions.find(r =>
243+
r.id === region ||
244+
r.alias.some(alias => alias === region)
245+
)
246+
if (!regionData) {
247+
throw new Error(`Invalid region '${region}' provided. Allowed regions are: ${regionHostMap.regions.map(r => r.id).join(', ')}`)
248+
}
249+
return regionData.endpoints[service]?.replace(/^https?:\/\//, '')
250+
}

lib/core/contentstackHTTPClient.js

Lines changed: 4 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import axios from 'axios'
22
import clonedeep from 'lodash/cloneDeep'
33
import Qs from 'qs'
44
import { ConcurrencyQueue } from './concurrency-queue'
5-
import { isHost } from './Util'
5+
import { getRegionEndpoint, isHost } from './Util'
66

77
export default function contentstackHttpClient (options) {
88
const defaultConfig = {
@@ -68,25 +68,11 @@ export default function contentstackHttpClient (options) {
6868
config.basePath = `/${config.basePath.split('/').filter(Boolean).join('/')}`
6969
}
7070
const baseURL = config.endpoint || `${protocol}://${hostname}:${port}${config.basePath}/{api-version}`
71-
let uiHostName = hostname
72-
let developerHubBaseUrl = hostname
73-
74-
if (uiHostName?.endsWith('io')) {
75-
uiHostName = uiHostName.replace('io', 'com')
76-
}
77-
78-
if (uiHostName) {
79-
uiHostName = uiHostName.replace('api', 'app')
80-
}
71+
const region = config.region || 'na'
72+
const uiHostName = getRegionEndpoint(region, 'application')
73+
const developerHubBaseUrl = getRegionEndpoint(region, 'developerHub').replace(/^/, 'https://')
8174
const uiBaseUrl = config.endpoint || `${protocol}://${uiHostName}`
8275

83-
developerHubBaseUrl = developerHubBaseUrl
84-
?.replace('api', 'developerhub-api')
85-
.replace(/^dev\d+/, 'dev') // Replaces any 'dev1', 'dev2', etc. with 'dev'
86-
.replace('io', 'com')
87-
.replace(/^http/, '') // Removing `http` if already present
88-
.replace(/^/, 'https://') // Adds 'https://' at the start if not already there
89-
9076
// set ui host name
9177
const axiosOptions = {
9278
// Axios

0 commit comments

Comments
 (0)