Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
## Change log

### Version: 1.3.3
#### Date: Oct-27-2025
- Fix: Used common serialize method for query params

### Version: 1.3.1
#### Date: Sept-01-2025
- Fix: Replace URLSearchParams.set() with React Native compatible implementation
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@contentstack/core",
"version": "1.3.2",
"version": "1.3.3",
"type": "commonjs",
"main": "./dist/cjs/src/index.js",
"types": "./dist/cjs/src/index.d.ts",
Expand Down
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export * from './lib/contentstack-core';
export * from './lib/types';
export * from './lib/contentstack-error';
export * from './lib/api-error';
export * from './lib/request';
export * from './lib/retryPolicy/delivery-sdk-handlers';
72 changes: 72 additions & 0 deletions src/lib/api-error.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/**
* Custom error class for API errors with optimized error handling
*/
export class APIError extends Error {
public error_code: number | string;
public status: number;
public error_message: string;

constructor(message: string, error_code: number | string, status: number) {
super(message);
this.name = 'APIError';
this.error_code = error_code;
this.status = status;
this.error_message = message;

// Remove the stack trace completely to avoid showing internal error handling
this.stack = undefined;
}

/**
* Creates an APIError from an Axios error response
* @param err - The Axios error object
* @returns Formatted APIError with meaningful information
*/
static fromAxiosError(err: any): APIError {
if (err.response?.data) {
return APIError.fromResponseData(err.response.data, err.response.status);
} else if (err.message) {
// For network errors or other non-HTTP errors
return new APIError(err.message, err.code || 'NETWORK_ERROR', 0);
} else {
// Fallback for unknown errors
return new APIError('Unknown error occurred', 'UNKNOWN_ERROR', 0);
}
}

/**
* Creates an APIError from response data
* @param responseData - The response data from the API
* @param status - The HTTP status code
* @returns Formatted APIError
*/
static fromResponseData(responseData: any, status: number): APIError {
// Extract error message with fallback chain
const errorMessage = APIError.extractErrorMessage(responseData);

// Extract error code with fallback chain
const errorCode = APIError.extractErrorCode(responseData, status);

return new APIError(errorMessage, errorCode, status);
}

/**
* Extracts error message from response data with multiple fallback options
*/
private static extractErrorMessage(responseData: any): string {
if (responseData.error_message) return responseData.error_message;
if (responseData.message) return responseData.message;
if (responseData.error) return responseData.error;
if (typeof responseData === 'string') return responseData;
return 'Request failed';
}

/**
* Extracts error code from response data with fallback to status
*/
private static extractErrorCode(responseData: any, status: number): number | string {
if (responseData.error_code) return responseData.error_code;
if (responseData.code) return responseData.code;
return status;
}
}
28 changes: 13 additions & 15 deletions src/lib/request.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,14 @@
import { AxiosInstance } from './types';
import { serialize } from './param-serializer';
import { APIError } from './api-error';

/**
* Handles array parameters properly with & separators
* React Native compatible implementation without URLSearchParams.set()
*/
function serializeParams(params: any): string {
if (!params) return '';

const parts: string[] = [];
Object.keys(params).forEach(key => {
const value = params[key];
if (Array.isArray(value)) {
value.forEach(item => {
parts.push(`${encodeURIComponent(key)}=${encodeURIComponent(item)}`);
});
} else if (value !== null && value !== undefined) {
parts.push(`${encodeURIComponent(key)}=${encodeURIComponent(value)}`);
}
});

return parts.join('&');
return serialize(params);
}

/**
Expand Down Expand Up @@ -48,6 +37,15 @@ async function makeRequest(instance: AxiosInstance, url: string, requestConfig:
}
}

/**
* Handles and formats errors from Axios requests
* @param err - The error object from Axios
* @returns Formatted error object with meaningful information
*/
function handleRequestError(err: any): Error {
return APIError.fromAxiosError(err);
}

export async function getData(instance: AxiosInstance, url: string, data?: any) {
try {
if (instance.stackConfig && instance.stackConfig.live_preview) {
Expand Down Expand Up @@ -87,6 +85,6 @@ export async function getData(instance: AxiosInstance, url: string, data?: any)
throw response;
}
} catch (err: any) {
throw err;
throw handleRequestError(err);
}
}
1 change: 1 addition & 0 deletions test/contentstack-core.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ describe('contentstackCore', () => {
it('should call the onError function when an error occurs', async () => {
const onError = jest.fn();
const options = {
defaultHostname: 'cdn.contentstack.io',
onError,
};

Expand Down
Loading