@paritydeals/node-sdk
Version:
Node.js SDK for interacting with the ParityDeals API.
177 lines • 10 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.ParityDeals = void 0;
// src/client.ts
const axios_1 = __importDefault(require("axios"));
const constants_1 = require("./constants");
const exceptions_1 = require("./exceptions");
// Import resource operation classes
const reporting_1 = require("./reporting");
const checkout_1 = require("./checkout");
const entitlements_1 = require("./entitlements");
const customers_1 = require("./customers");
const subscription_1 = require("./subscription");
const utils_1 = require("./utils");
const defaultLogger = {
debug: (...args) => { if (typeof process !== 'undefined' && process.env?.NODE_ENV === 'development')
console.debug('[ParityDealsSDK DEBUG]', ...args); },
info: (...args) => console.info('[ParityDealsSDK INFO]', ...args),
warn: (...args) => console.warn('[ParityDealsSDK WARN]', ...args),
error: (...args) => console.error('[ParityDealsSDK ERROR]', ...args),
};
class ParityDeals {
constructor(options) {
if (!options.accessToken) {
throw new Error("accessToken is required to initialize the ParityDeals client.");
}
this.accessToken = options.accessToken;
if (options.logger === false) {
this.logger = { debug: () => { }, info: () => { }, warn: () => { }, error: () => { } };
}
else {
this.logger = options.logger || defaultLogger;
}
const { environment = 'production' } = options;
if (environment === 'sandbox') {
this.defaultBaseUrl = (options.baseUrl || constants_1.SANDBOX_API_URL).replace(/\/$/, '');
this.edgeApiUrl = (options.edgeApiUrl || constants_1.SANDBOX_EDGE_API_URL).replace(/\/$/, '');
}
else {
this.defaultBaseUrl = (options.baseUrl || constants_1.DEFAULT_API_URL).replace(/\/$/, '');
this.edgeApiUrl = (options.edgeApiUrl || constants_1.EDGE_API_URL).replace(/\/$/, '');
}
this.apiVersion = options.apiVersion || constants_1.DEFAULT_API_VERSION;
this.logger.info(`ParityDeals client initialized. Environment: ${environment}, Default Base URL: ${this.defaultBaseUrl}, Edge URL: ${this.edgeApiUrl}, API Version: ${this.apiVersion}`);
this.httpClient = axios_1.default.create({
timeout: options.timeout || constants_1.DEFAULT_TIMEOUT_MS,
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
},
adapter: options.adapter,
});
this.reporting = new reporting_1.ReportingOperations(this);
this.checkout = new checkout_1.CheckoutOperations(this);
this.entitlements = new entitlements_1.EntitlementsOperations(this);
this.customers = new customers_1.CustomersOperations(this);
this.subscription = new subscription_1.SubscriptionOperations(this);
}
_getHeaders() {
return {
'Content-Type': 'application/json',
'Accept': 'application/json',
'Authorization': `Bearer ${this.accessToken}`,
};
}
/** @internal */
_prepareUrl(endpointModulePath, useEdgeUrl = false) {
const baseUrlToUse = useEdgeUrl ? this.edgeApiUrl : this.defaultBaseUrl;
let path = endpointModulePath;
if (!path.startsWith('/')) {
path = '/' + path;
}
let prefix = constants_1.API_BASE_PATH_PREFIX;
if (!prefix.startsWith('/')) {
prefix = '/' + prefix;
}
if (prefix.endsWith('/')) {
prefix = prefix.slice(0, -1);
}
const url = `${baseUrlToUse}${prefix}/${this.apiVersion}${path}`;
this.logger.debug(`Prepared URL: ${url} (using base: ${baseUrlToUse})`);
return url;
}
/** @internal */
async _request(method, endpointModulePath, payload, queryParams, useEdgeUrl = false) {
const fullUrl = this._prepareUrl(endpointModulePath, useEdgeUrl);
this.logger.info(`Making ${method} request to: ${fullUrl}`);
let processedPayload = payload;
let processedQueryParams = queryParams;
if (payload && (method === 'POST' || method === 'PUT' || method === 'PATCH')) {
processedPayload = (0, utils_1.keysToSnakeCase)(payload);
this.logger.debug(`Request body (snake_case): ${JSON.stringify(processedPayload).substring(0, 500)}...`);
}
if (queryParams && method === 'GET') {
processedQueryParams = (0, utils_1.prepareSnakeCaseParams)(queryParams);
this.logger.debug(`Request query params (snake_case): ${JSON.stringify(processedQueryParams)}`);
}
try {
const response = await this.httpClient.request({
method,
url: fullUrl,
data: processedPayload,
params: processedQueryParams,
headers: this._getHeaders(),
});
this.logger.debug(`Response received. Status: ${response.status}, URL: ${response.config?.url || fullUrl}`);
if (response.data && typeof response.data === 'object') {
this.logger.debug(`Response data snippet: ${JSON.stringify(response.data).substring(0, 200)}...`);
}
else if (response.data) {
this.logger.debug(`Response data snippet (non-JSON): ${String(response.data).substring(0, 200)}...`);
}
else {
this.logger.debug("Response data is empty or undefined.");
}
if (response.status === 204 && (method === 'DELETE' || method === 'POST')) {
this.logger.info(`Successful API call with 204 No Content. URL: ${fullUrl}, Method: ${method}`);
return { message: "Operation completed successfully (204 No Content)." };
}
if (response.status >= 200 && response.status < 300) {
this.logger.info(`Successful API call. Status: ${response.status}, URL: ${fullUrl}, Method: ${method}`);
return response.data === undefined ? {} : response.data;
}
this.logger.warn(`Unhandled successful status code: ${response.status} for ${method} ${fullUrl}. Treating as error.`);
throw new exceptions_1.ApiError(`Unhandled successful status code: ${response.status}`, response.status, response.data, undefined, fullUrl, method);
}
catch (error) {
const requestUrl = error?.config?.url || error?.request?.responseURL || fullUrl; // Try to get URL from different places
const requestMethod = (error?.config?.method || method).toUpperCase();
// Prioritize checking if it's an error with a response object (like AxiosError with response)
if (error && typeof error === 'object' && error.response && typeof error.response.status === 'number') {
const errResponse = error.response;
const status = errResponse.status;
const errorDetails = errResponse.data;
const originalError = error; // Keep the original error object as cause
this.logger.error(`API Error with response: ${error.message || 'HTTP Error'}, Status: ${status}, Method: ${requestMethod}, URL: ${requestUrl}`, errorDetails ? `Data: ${JSON.stringify(errorDetails)}` : '');
const apiResponseMessage = errorDetails?.message || errorDetails?.detail || (typeof errorDetails === 'string' ? errorDetails : null);
const finalMessage = apiResponseMessage || error.message || "An API error occurred";
if (status === 400) {
throw new exceptions_1.InvalidRequestError(finalMessage, status, errorDetails, originalError, requestUrl, requestMethod);
}
else if (status === 401) {
throw new exceptions_1.AuthenticationError(finalMessage, status, errorDetails, originalError, requestUrl, requestMethod);
}
else if (status === 403) {
throw new exceptions_1.AuthenticationError(finalMessage, status, errorDetails, originalError, requestUrl, requestMethod);
}
else if (status === 404) {
throw new exceptions_1.NotFoundError(finalMessage, status, errorDetails, originalError, requestUrl, requestMethod);
}
else if (status >= 500) {
throw new exceptions_1.ServerError(finalMessage, status, errorDetails, originalError, requestUrl, requestMethod);
}
else {
// Other HTTP errors with a response that don't fit specific categories
throw new exceptions_1.ApiError(finalMessage, status, errorDetails, originalError, requestUrl, requestMethod);
}
}
else if (axios_1.default.isAxiosError(error)) {
// This will now catch Axios errors that *don't* have a .response
// (e.g., network errors, true timeouts before response)
const axiosError = error;
this.logger.error(`Axios API Error without response: ${axiosError.message}, Method: ${requestMethod}, URL: ${requestUrl}`);
throw new exceptions_1.ApiError(axiosError.message, undefined, undefined, axiosError, requestUrl, requestMethod);
}
// For truly non-Axios errors
this.logger.error(`Unexpected non-Axios error during API request: ${error}`);
const err = error instanceof Error ? error : new Error(String(error));
throw new exceptions_1.ApiError(`An unexpected error occurred: ${err.message}`, undefined, undefined, err, requestUrl, requestMethod);
}
}
}
exports.ParityDeals = ParityDeals;
//# sourceMappingURL=client.js.map