diff --git a/.github/workflows/back-merge-pr.yml b/.github/workflows/back-merge-pr.yml
new file mode 100644
index 00000000..02b378ce
--- /dev/null
+++ b/.github/workflows/back-merge-pr.yml
@@ -0,0 +1,54 @@
+name: Back-merge master to development
+
+on:
+ push:
+ branches:
+ - master
+ workflow_dispatch:
+
+permissions:
+ contents: read
+ pull-requests: write
+
+jobs:
+ open-back-merge-pr:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
+
+ - name: Open back-merge PR if needed
+ env:
+ GH_TOKEN: ${{ github.token }}
+ run: |
+ set -euo pipefail
+ BASE_BRANCH="development"
+ SOURCE_BRANCH="master"
+
+ git fetch origin "$BASE_BRANCH" "$SOURCE_BRANCH"
+
+ if ! git show-ref --verify --quiet "refs/remotes/origin/$BASE_BRANCH"; then
+ echo "Base branch '$BASE_BRANCH' does not exist on origin; skipping."
+ exit 0
+ fi
+
+ SOURCE_SHA=$(git rev-parse "origin/$SOURCE_BRANCH")
+ BASE_SHA=$(git rev-parse "origin/$BASE_BRANCH")
+
+ if [ "$SOURCE_SHA" = "$BASE_SHA" ]; then
+ echo "$SOURCE_BRANCH and $BASE_BRANCH are at the same commit; nothing to back-merge."
+ exit 0
+ fi
+
+ EXISTING=$(gh pr list --repo "${{ github.repository }}" --base "$BASE_BRANCH" --head "$SOURCE_BRANCH" --state open --json number --jq 'length')
+
+ if [ "$EXISTING" -gt 0 ]; then
+ echo "An open PR from $SOURCE_BRANCH to $BASE_BRANCH already exists; skipping."
+ exit 0
+ fi
+
+ gh pr create --repo "${{ github.repository }}" --base "$BASE_BRANCH" --head "$SOURCE_BRANCH" --title "chore: back-merge $SOURCE_BRANCH into $BASE_BRANCH" --body "Automated back-merge after changes landed on \\`$SOURCE_BRANCH\\`. Review and merge to keep \\`$BASE_BRANCH\\` in sync."
+
+ echo "Created back-merge PR $SOURCE_BRANCH -> $BASE_BRANCH."
diff --git a/.github/workflows/check-branch.yml b/.github/workflows/check-branch.yml
deleted file mode 100644
index 2332f0d0..00000000
--- a/.github/workflows/check-branch.yml
+++ /dev/null
@@ -1,20 +0,0 @@
-name: 'Check Branch'
-
-on:
- pull_request:
-
-jobs:
- check_branch:
- runs-on: ubuntu-latest
- steps:
- - name: Comment PR
- if: github.base_ref == 'master' && github.head_ref != 'staging'
- uses: thollander/actions-comment-pull-request@v2
- with:
- message: |
- We regret to inform you that you are currently not able to merge your changes into the master branch due to restrictions applied by our SRE team. To proceed with merging your changes, we kindly request that you create a pull request from the staging branch. Our team will then review the changes and work with you to ensure a successful merge into the master branch.
- - name: Check branch
- if: github.base_ref == 'master' && github.head_ref != 'staging'
- run: |
- echo "ERROR: We regret to inform you that you are currently not able to merge your changes into the master branch due to restrictions applied by our SRE team. To proceed with merging your changes, we kindly request that you create a pull request from the staging branch. Our team will then review the changes and work with you to ensure a successful merge into the master branch."
- exit 1
diff --git a/.github/workflows/check-version-bump.yml b/.github/workflows/check-version-bump.yml
new file mode 100644
index 00000000..8e710002
--- /dev/null
+++ b/.github/workflows/check-version-bump.yml
@@ -0,0 +1,86 @@
+name: Check Version Bump
+
+on:
+ pull_request:
+
+jobs:
+ version-bump:
+ name: Version & Changelog bump
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
+
+ - name: Detect changed files and version bump
+ id: detect
+ run: |
+ if git rev-parse HEAD^2 >/dev/null 2>&1; then
+ FILES=$(git diff --name-only HEAD^1 HEAD^2)
+ else
+ FILES=$(git diff --name-only HEAD~1 HEAD)
+ fi
+ VERSION_FILES_CHANGED=false
+ echo "$FILES" | grep -qx 'package.json' && VERSION_FILES_CHANGED=true
+ echo "$FILES" | grep -qx 'CHANGELOG.md' && VERSION_FILES_CHANGED=true
+ echo "version_files_changed=$VERSION_FILES_CHANGED" >> $GITHUB_OUTPUT
+ # Only lib/, webpack/, dist/, package.json count as release-affecting; .github/ and test/ do not
+ CODE_CHANGED=false
+ echo "$FILES" | grep -qE '^lib/|^webpack/|^dist/' && CODE_CHANGED=true
+ echo "$FILES" | grep -qx 'package.json' && CODE_CHANGED=true
+ echo "code_changed=$CODE_CHANGED" >> $GITHUB_OUTPUT
+
+ - name: Skip when only test/docs/.github changed
+ if: steps.detect.outputs.code_changed != 'true'
+ run: |
+ echo "No release-affecting files changed (e.g. only test/docs/.github). Skipping version-bump check."
+ exit 0
+
+ - name: Fail when version bump was missed
+ if: steps.detect.outputs.code_changed == 'true' && steps.detect.outputs.version_files_changed != 'true'
+ run: |
+ echo "::error::This PR has code changes but no version bump. Please bump the version in package.json and add an entry in CHANGELOG.md."
+ exit 1
+
+ - name: Setup Node
+ if: steps.detect.outputs.code_changed == 'true' && steps.detect.outputs.version_files_changed == 'true'
+ uses: actions/setup-node@v4
+ with:
+ node-version: '22.x'
+
+ - name: Check version bump
+ if: steps.detect.outputs.code_changed == 'true' && steps.detect.outputs.version_files_changed == 'true'
+ run: |
+ set -e
+ PKG_VERSION=$(node -p "require('./package.json').version.replace(/^v/, '')")
+ if [ -z "$PKG_VERSION" ]; then
+ echo "::error::Could not read version from package.json"
+ exit 1
+ fi
+ git fetch --tags --force 2>/dev/null || true
+ LATEST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || true)
+ if [ -z "$LATEST_TAG" ]; then
+ echo "No existing tags found. Skipping version-bump check (first release)."
+ exit 0
+ fi
+ LATEST_VERSION="${LATEST_TAG#v}"
+ LATEST_VERSION="${LATEST_VERSION%%-*}"
+ if [ "$(printf '%s\n' "$LATEST_VERSION" "$PKG_VERSION" | sort -V | tail -1)" != "$PKG_VERSION" ]; then
+ echo "::error::Version bump required: package.json version ($PKG_VERSION) is not greater than latest tag ($LATEST_TAG). Please bump the version in package.json."
+ exit 1
+ fi
+ if [ "$PKG_VERSION" = "$LATEST_VERSION" ]; then
+ echo "::error::Version bump required: package.json version ($PKG_VERSION) equals latest tag ($LATEST_TAG). Please bump the version in package.json."
+ exit 1
+ fi
+ CHANGELOG_VERSION=$(sed -nE 's/^## \[v?([0-9]+\.[0-9]+\.[0-9]+).*/\1/p' CHANGELOG.md | head -1)
+ if [ -z "$CHANGELOG_VERSION" ]; then
+ echo "::error::Could not find a version entry in CHANGELOG.md (expected line like '## [v1.0.0](...)')."
+ exit 1
+ fi
+ if [ "$CHANGELOG_VERSION" != "$PKG_VERSION" ]; then
+ echo "::error::CHANGELOG version mismatch: CHANGELOG.md top version ($CHANGELOG_VERSION) does not match package.json version ($PKG_VERSION). Please add or update the CHANGELOG entry for $PKG_VERSION."
+ exit 1
+ fi
+ echo "Version bump check passed: package.json and CHANGELOG.md are at $PKG_VERSION (latest tag: $LATEST_TAG)."
diff --git a/.github/workflows/unit-testing.yml b/.github/workflows/unit-testing.yml
index 1d93af01..8c1cd6f5 100644
--- a/.github/workflows/unit-testing.yml
+++ b/.github/workflows/unit-testing.yml
@@ -4,7 +4,6 @@ on:
pull_request:
branches:
- development
- - staging
- master
jobs:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 40a128d8..d5c6c9d3 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,10 @@
# CHANGELOG
+## v2.7.0
+
+### Jun 15, 2026
+- Enhancement: Endpoint integration
+
## v2.6.0
### Feb 23, 2026
diff --git a/pom.xml b/pom.xml
index 029cd247..ac4eb555 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,7 +5,7 @@
Delegates to {@link Endpoint#getContentstackEndpoint(String, String)} — provided as a
+ * convenience so callers can reach endpoint resolution through the same top-level class they
+ * use to create stacks.
+ *
+ * @param region region ID or alias (e.g. {@code "na"}, {@code "eu"}, {@code "azure-na"})
+ * @param service service key (e.g. {@code "contentDelivery"}, {@code "contentManagement"})
+ * @return full URL including {@code https://} scheme
+ * @throws IllegalArgumentException if the region or service is not recognised
+ */
+ public static String getContentstackEndpoint(String region, String service) {
+ return Endpoint.getContentstackEndpoint(region, service);
+ }
+
+ /**
+ * Returns the Contentstack API URL for the given region and service, optionally stripping
+ * the {@code https://} scheme.
+ *
+ * @param region region ID or alias
+ * @param service service key
+ * @param omitHttps when {@code true}, returns the bare host without {@code https://}
+ * @return URL or bare host
+ * @throws IllegalArgumentException if the region or service is not recognised
+ */
+ public static String getContentstackEndpoint(String region, String service, boolean omitHttps) {
+ return Endpoint.getContentstackEndpoint(region, service, omitHttps);
+ }
+
+ /**
+ * Returns all service endpoints for the given region as an ordered map of service key to URL.
+ *
+ * @param region region ID or alias
+ * @return map of service key → full URL
+ * @throws IllegalArgumentException if the region is not recognised
+ */
+ public static Map Region matching is case-insensitive and treats {@code -} and {@code _} as equivalent
+ * separators, so {@code "AZURE_NA"}, {@code "azure-na"}, and {@code "Azure_NA"} all resolve
+ * to the same region.
+ *
+ * Examples:
+ * The "stack integration" tests create a real Stack using the host resolved
+ * by {@code Endpoint} and exercise the Contentstack CDA using credentials from
+ * {@code src/test/resources/.env}. They share the same credential set as the
+ * rest of the integration suite and are deliberately non-destructive (read-only
+ * CDA calls only).
+ */
+@TestInstance(TestInstance.Lifecycle.PER_CLASS)
+class EndpointIT {
+
+ private static final Logger logger = Logger.getLogger(EndpointIT.class.getName());
+
+ private String apiKey;
+ private String deliveryToken;
+ private String environment;
+
+ @BeforeAll
+ public void setUp() {
+ apiKey = Credentials.API_KEY;
+ deliveryToken = Credentials.DELIVERY_TOKEN;
+ environment = Credentials.ENVIRONMENT;
+ }
+
+ // ── endpoint resolution ───────────────────────────────────────────────────
+
+ @Test
+ void testNaContentDeliveryResolvesCorrectly() {
+ String url = Endpoint.getContentstackEndpoint("na", "contentDelivery");
+ Assertions.assertEquals("https://cdn.contentstack.io", url);
+ }
+
+ @Test
+ void testEuContentDeliveryResolvesCorrectly() {
+ String url = Endpoint.getContentstackEndpoint("eu", "contentDelivery");
+ Assertions.assertEquals("https://eu-cdn.contentstack.com", url);
+ }
+
+ @Test
+ void testAzureNaContentDeliveryResolvesCorrectly() {
+ String url = Endpoint.getContentstackEndpoint("azure-na", "contentDelivery");
+ Assertions.assertEquals("https://azure-na-cdn.contentstack.com", url);
+ }
+
+ @Test
+ void testGcpNaContentDeliveryResolvesCorrectly() {
+ String url = Endpoint.getContentstackEndpoint("gcp-na", "contentDelivery");
+ Assertions.assertEquals("https://gcp-na-cdn.contentstack.com", url);
+ }
+
+ @Test
+ void testOmitHttpsStripsScheme() {
+ String host = Endpoint.getContentstackEndpoint("na", "contentDelivery", true);
+ Assertions.assertEquals("cdn.contentstack.io", host);
+ Assertions.assertFalse(host.startsWith("https://"));
+ }
+
+ @Test
+ void testGetAllEndpointsReturnsMap() {
+ Map Skipped gracefully when credentials are absent (CI without secrets).
+ */
+ @Test
+ void testRealStackWithEndpointResolvedHost() throws IllegalAccessException, InterruptedException {
+ if (apiKey == null || apiKey.isEmpty()
+ || deliveryToken == null || deliveryToken.isEmpty()) {
+ logger.warning("Skipping live API test — credentials not configured.");
+ return;
+ }
+
+ String host = Endpoint.getContentstackEndpoint("na", "contentDelivery", true);
+ Config config = new Config();
+ config.setHost(host);
+
+ Stack stack = Contentstack.stack(apiKey, deliveryToken, environment, config);
+ Assertions.assertEquals(host, stack.config.host);
+
+ CountDownLatch latch = new CountDownLatch(1);
+ boolean[] passed = {false};
+
+ stack.getContentTypes(new org.json.JSONObject(), new ContentTypesCallback() {
+ @Override
+ public void onCompletion(ContentTypesModel model, Error error) {
+ if (error == null) {
+ logger.info(() -> "Live endpoint check: fetched content types via host=" + host);
+ passed[0] = true;
+ } else {
+ logger.warning(() -> "Live endpoint check failed: " + error.getErrorMessage());
+ }
+ latch.countDown();
+ }
+ });
+
+ boolean completed = latch.await(15, TimeUnit.SECONDS);
+ Assertions.assertTrue(completed, "API call timed out after 15 seconds");
+ // Skip (not fail) when credentials are absent or point to a non-existent stack
+ Assumptions.assumeTrue(passed[0],
+ "Live API call returned an error — skipping assertion (check .env credentials)");
+ }
+
+ /**
+ * Verifies that the host resolved via {@code Endpoint} for the NA region
+ * matches the Stack default host that the SDK would have used without
+ * endpoint resolution (backward-compatible).
+ */
+ @Test
+ void testEndpointResolvedHostIsBackwardCompatibleWithDefaultNa() throws IllegalAccessException {
+ Stack defaultStack = Contentstack.stack("k", "t", "e");
+ String sdkDefaultHost = defaultStack.config.host;
+ String resolvedHost = Endpoint.getContentstackEndpoint("na", "contentDelivery", true);
+ Assertions.assertEquals(sdkDefaultHost, resolvedHost,
+ "Endpoint-resolved NA host should match the SDK's built-in default");
+ }
+
+ // ── Contentstack proxy ────────────────────────────────────────────────────
+
+ @Test
+ void testContentstackProxyMatchesEndpointDirect() {
+ String viaProxy = Contentstack.getContentstackEndpoint("eu", "contentDelivery");
+ String viaDirect = Endpoint.getContentstackEndpoint("eu", "contentDelivery");
+ Assertions.assertEquals(viaDirect, viaProxy);
+ }
+
+ @Test
+ void testContentstackProxyOmitHttps() {
+ String host = Contentstack.getContentstackEndpoint("azure-na", "contentDelivery", true);
+ Assertions.assertEquals("azure-na-cdn.contentstack.com", host);
+ Assertions.assertFalse(host.startsWith("https://"));
+ }
+
+ @Test
+ void testContentstackProxyGetAllEndpoints() {
+ MapResolution chain
+ *
+ *
+ *
+ *
+ * String url = Endpoint.getContentstackEndpoint("eu", "contentDelivery");
+ * // → "https://eu-cdn.contentstack.com"
+ *
+ * String host = Endpoint.getContentstackEndpoint("eu", "contentDelivery", true);
+ * // → "eu-cdn.contentstack.com"
+ *
+ * Map<String, String> all = Endpoint.getAllEndpoints("azure-na");
+ * // → {"contentDelivery": "https://azure-na-cdn.contentstack.com", ...}
+ *
+ */
+public class Endpoint {
+
+ static final String REGIONS_URL = "https://artifacts.contentstack.com/regions.json";
+
+ private static final Logger logger = Logger.getLogger(Endpoint.class.getSimpleName());
+
+ private static volatile JSONArray regionsCache = null;
+
+ // Ensures the live download is attempted at most once per JVM session so that
+ // genuinely invalid region strings do not trigger repeated network calls.
+ private static volatile boolean liveRefreshDone = false;
+
+ private Endpoint() {
+ }
+
+ /**
+ * Returns the URL for the given region and service.
+ *
+ * @param region the region ID or alias (e.g. {@code "na"}, {@code "eu"}, {@code "azure-na"})
+ * @param service the service key (e.g. {@code "contentDelivery"}, {@code "contentManagement"})
+ * @return the full URL including {@code https://} scheme
+ * @throws IllegalArgumentException if the region or service is not recognised
+ */
+ public static String getContentstackEndpoint(@NotNull String region, @NotNull String service) {
+ return getContentstackEndpoint(region, service, false);
+ }
+
+ /**
+ * Returns the URL for the given region and service, optionally stripping the {@code https://}
+ * scheme.
+ *
+ * @param region the region ID or alias
+ * @param service the service key
+ * @param omitHttps when {@code true}, returns the bare host without the {@code https://} prefix
+ * @return the URL (or bare host when {@code omitHttps} is {@code true})
+ * @throws IllegalArgumentException if the region or service is not recognised
+ */
+ public static String getContentstackEndpoint(@NotNull String region, @NotNull String service,
+ boolean omitHttps) {
+ if (region.trim().isEmpty()) {
+ throw new IllegalArgumentException("Empty region provided. Please provide a valid region.");
+ }
+ JSONObject regionRow = resolveRegion(region);
+ JSONObject endpoints = regionRow.getJSONObject("endpoints");
+ if (!endpoints.has(service)) {
+ throw new IllegalArgumentException(
+ "Service \"" + service + "\" not found for region \"" + region + "\"");
+ }
+ String url = endpoints.getString(service);
+ return omitHttps ? stripHttps(url) : url;
+ }
+
+ /**
+ * Returns all endpoints for the given region as an ordered map of service key to URL.
+ *
+ * @param region the region ID or alias
+ * @return map of service key → URL
+ * @throws IllegalArgumentException if the region is not recognised
+ */
+ public static Map
+ *
+ */
+ private static JSONObject resolveRegion(String region) {
+ // Tier 1 + 2: load from cache or bundled classpath
+ JSONArray regions = loadRegions();
+ try {
+ return findRegion(regions, region);
+ } catch (IllegalArgumentException notInBundled) {
+ // Tier 3: region not in bundled file — attempt one live refresh.
+ // This handles the case where Contentstack added a new region after this
+ // SDK version was released and the user hasn't upgraded yet.
+ if (!liveRefreshDone) {
+ JSONArray fresh = tryLiveRefresh();
+ if (fresh != null) {
+ try {
+ return findRegion(fresh, region);
+ } catch (IllegalArgumentException ignored) {
+ // Region absent even in the live data → fall through and throw below
+ }
+ }
+ }
+ throw notInBundled;
+ }
+ }
+
+ /**
+ * Loads regions from the in-memory cache or the bundled classpath resource.
+ * Populates the cache on the first call.
+ */
+ private static synchronized JSONArray loadRegions() {
+ if (regionsCache != null) {
+ return regionsCache;
+ }
+ // Try bundled classpath resource (packaged inside the SDK jar)
+ InputStream stream = Endpoint.class.getResourceAsStream("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/assets/regions.json");
+ if (stream != null) {
+ try (Scanner scanner = new Scanner(stream, StandardCharsets.UTF_8.name())) {
+ String raw = scanner.useDelimiter("\\A").next();
+ JSONObject root = new JSONObject(raw);
+ regionsCache = root.getJSONArray("regions");
+ return regionsCache;
+ }
+ }
+ // Bundled file absent (e.g. corrupted build) — try live download immediately
+ logger.warning("Bundled regions.json not found in classpath — attempting live download.");
+ JSONArray downloaded = tryLiveRefresh();
+ if (downloaded != null) {
+ return downloaded;
+ }
+ throw new IllegalStateException(
+ "regions.json not found in classpath and could not be downloaded from "
+ + REGIONS_URL + ". Ensure the SDK jar was built correctly, or check network access.");
+ }
+
+ /**
+ * Attempts a one-time HTTP fetch of {@value #REGIONS_URL}.
+ * Returns the parsed regions array on success, or {@code null} if the attempt is skipped
+ * or the network is unavailable. Updates the in-memory cache on success.
+ */
+ private static synchronized JSONArray tryLiveRefresh() {
+ if (liveRefreshDone) {
+ return regionsCache; // already fetched this session — return whatever we have
+ }
+ liveRefreshDone = true;
+ try {
+ logger.info("Refreshing regions from " + REGIONS_URL);
+ URL url = new URL(REGIONS_URL);
+ HttpURLConnection conn = (HttpURLConnection) url.openConnection();
+ conn.setRequestMethod("GET");
+ conn.setConnectTimeout(5_000);
+ conn.setReadTimeout(10_000);
+ conn.setRequestProperty("Accept", "application/json");
+ try (InputStream stream = conn.getInputStream();
+ Scanner scanner = new Scanner(stream, StandardCharsets.UTF_8.name())) {
+ String raw = scanner.useDelimiter("\\A").next();
+ JSONObject root = new JSONObject(raw);
+ regionsCache = root.getJSONArray("regions");
+ logger.info("regions.json refreshed from live URL (" + regionsCache.length() + " regions).");
+ return regionsCache;
+ }
+ } catch (Exception e) {
+ logger.warning("Live region refresh failed: " + e.getMessage());
+ return null;
+ }
+ }
+
+ private static JSONObject findRegion(JSONArray regions, String region) {
+ String normalized = region.trim().toLowerCase().replace('_', '-');
+
+ // Pass 1: match canonical id
+ for (int i = 0; i < regions.length(); i++) {
+ JSONObject row = regions.getJSONObject(i);
+ if (row.getString("id").equals(normalized)) {
+ return row;
+ }
+ }
+
+ // Pass 2: match aliases (case-insensitive, _ == -)
+ for (int i = 0; i < regions.length(); i++) {
+ JSONObject row = regions.getJSONObject(i);
+ JSONArray aliases = row.optJSONArray("alias");
+ if (aliases == null) {
+ continue;
+ }
+ for (int j = 0; j < aliases.length(); j++) {
+ String alias = aliases.getString(j).toLowerCase().replace('_', '-');
+ if (alias.equals(normalized)) {
+ return row;
+ }
+ }
+ }
+
+ throw new IllegalArgumentException("Invalid region: " + region);
+ }
+
+ private static String stripHttps(String url) {
+ return url.replaceFirst("^https?://", "");
+ }
+}
diff --git a/src/main/java/com/contentstack/sdk/Stack.java b/src/main/java/com/contentstack/sdk/Stack.java
index 5e7cd71a..d52ae120 100644
--- a/src/main/java/com/contentstack/sdk/Stack.java
+++ b/src/main/java/com/contentstack/sdk/Stack.java
@@ -59,40 +59,19 @@ protected Stack(@NotNull String apiKey) {
protected void setConfig(Config config) {
this.config = config;
- String urlDomain = config.host;
- if (!config.region.name().isEmpty()) {
- String region = config.region.name().toLowerCase();
- if (region.equalsIgnoreCase("eu")) {
- if (urlDomain.equalsIgnoreCase("cdn.contentstack.io")) {
- urlDomain = "cdn.contentstack.com";
+ // Explicit host (set via Config.setHost()) always takes precedence over region resolution.
+ // When no host was explicitly set, resolve the content-delivery host from regions.json via
+ // Endpoint so that new regions are picked up without SDK changes.
+ if (!config.hostOverridden) {
+ String regionId = config.region.name().toLowerCase();
+ try {
+ config.host = Endpoint.getContentstackEndpoint(regionId, "contentDelivery", true);
+ } catch (IllegalArgumentException e) {
+ // Unrecognised region: apply the legacy prefix pattern for backward compatibility
+ if (!regionId.equals("us")) {
+ config.host = regionId.replace("_", "-") + "-cdn.contentstack.com";
}
- config.host = region + "-" + urlDomain;
- } else if (region.equalsIgnoreCase("azure_na")) {
- if (urlDomain.equalsIgnoreCase("cdn.contentstack.io")) {
- urlDomain = "cdn.contentstack.com";
- }
- config.host = "azure-na" + "-" + urlDomain;
- } else if (region.equalsIgnoreCase("azure_eu")) {
- if (urlDomain.equalsIgnoreCase("cdn.contentstack.io")) {
- urlDomain = "cdn.contentstack.com";
- }
- config.host = "azure-eu" + "-" + urlDomain;
- } else if (region.equalsIgnoreCase("gcp_na")) {
- if (urlDomain.equalsIgnoreCase("cdn.contentstack.io")) {
- urlDomain = "cdn.contentstack.com";
- }
- config.host = "gcp-na" + "-" + urlDomain;
- } else if (region.equalsIgnoreCase("gcp_eu")) {
- if (urlDomain.equalsIgnoreCase("cdn.contentstack.io")) {
- urlDomain = "cdn.contentstack.com";
- }
- config.host = "gcp-eu" + "-" + urlDomain;
- } else if (region.equalsIgnoreCase("au")) {
- if (urlDomain.equalsIgnoreCase("cdn.contentstack.io")) {
- urlDomain = "cdn.contentstack.com";
- }
- config.host = region + "-" + urlDomain;
}
}
diff --git a/src/test/java/com/contentstack/sdk/EndpointIT.java b/src/test/java/com/contentstack/sdk/EndpointIT.java
new file mode 100644
index 00000000..54e15d3d
--- /dev/null
+++ b/src/test/java/com/contentstack/sdk/EndpointIT.java
@@ -0,0 +1,325 @@
+package com.contentstack.sdk;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Assumptions;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestInstance;
+
+import java.util.Map;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.logging.Logger;
+
+/**
+ * Integration tests for {@link Endpoint}.
+ *
+ *