UNPKG

@paritydeals/node-sdk

Version:

Node.js SDK for interacting with the ParityDeals API.

177 lines 10 kB
"use strict"; 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