semanticpen
Version:
AI Article Writer & SEO Blog Generator SDK - Professional TypeScript/JavaScript library for automated content creation, AI-powered article generation, and SEO blog writing with SemanticPen
116 lines • 4.72 kB
JavaScript
import { ErrorFactory, NetworkError, TimeoutError } from '../errors';
export class BaseClient {
constructor(config) {
this.config = { ...config };
this.baseUrl = config.baseUrl || 'https://www.semanticpen.com';
this.timeout = config.timeout || 30000;
this.debug = config.debug || false;
this.validateConfig();
}
validateConfig() {
if (!this.config.apiKey || typeof this.config.apiKey !== 'string') {
throw new Error('API key is required and must be a string');
}
if (this.config.apiKey.length < 10) {
throw new Error('API key appears to be invalid (too short)');
}
if (this.timeout < 1000 || this.timeout > 300000) {
throw new Error('Timeout must be between 1000ms and 300000ms');
}
}
getDefaultHeaders() {
return {
'Authorization': `Bearer ${this.config.apiKey}`,
'Content-Type': 'application/json',
'Accept': 'application/json',
'User-Agent': 'SemanticPen-SDK/1.0.0'
};
}
buildUrl(endpoint) {
const cleanEndpoint = endpoint.startsWith('/') ? endpoint.slice(1) : endpoint;
const cleanBaseUrl = this.baseUrl.endsWith('/') ? this.baseUrl.slice(0, -1) : this.baseUrl;
return `${cleanBaseUrl}/${cleanEndpoint}`;
}
async request(endpoint, options = { method: 'GET' }) {
const url = this.buildUrl(endpoint);
const requestTimeout = options.timeout || this.timeout;
if (this.debug) {
console.log(`[SemanticPen SDK] ${options.method} ${url}`);
if (options.body) {
console.log('[SemanticPen SDK] Request body:', options.body);
}
}
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), requestTimeout);
try {
const headers = {
...this.getDefaultHeaders(),
...options.headers
};
const fetchOptions = {
method: options.method,
headers,
signal: controller.signal
};
if (options.body && options.method !== 'GET') {
fetchOptions.body = typeof options.body === 'string'
? options.body
: JSON.stringify(options.body);
}
const response = await fetch(url, fetchOptions);
clearTimeout(timeoutId);
if (this.debug) {
console.log(`[SemanticPen SDK] Response status: ${response.status}`);
}
let responseData;
const contentType = response.headers.get('content-type');
if (!contentType || contentType.includes('application/json') || contentType.includes('text/plain')) {
try {
responseData = await response.json();
}
catch (parseError) {
responseData = await response.text();
}
}
else {
responseData = await response.text();
}
if (this.debug && responseData) {
console.log('[SemanticPen SDK] Response data:', responseData);
}
if (!response.ok) {
throw ErrorFactory.fromHttpResponse(response, endpoint, responseData);
}
return responseData;
}
catch (error) {
clearTimeout(timeoutId);
if (error.name === 'AbortError') {
throw new TimeoutError(`Request timed out after ${requestTimeout}ms`, requestTimeout, `${options.method} ${endpoint}`);
}
if (error instanceof TypeError && error.message.includes('fetch')) {
throw new NetworkError('Network error: Unable to reach SemanticPen API', undefined, endpoint, { originalError: error });
}
if (error.type) {
throw error;
}
throw ErrorFactory.fromError(error, `${options.method} ${endpoint}`);
}
}
async get(endpoint, headers) {
return this.request(endpoint, { method: 'GET', headers });
}
async post(endpoint, body, headers) {
return this.request(endpoint, { method: 'POST', body, headers });
}
async put(endpoint, body, headers) {
return this.request(endpoint, { method: 'PUT', body, headers });
}
async delete(endpoint, headers) {
return this.request(endpoint, { method: 'DELETE', headers });
}
getConfig() {
return Object.freeze({ ...this.config });
}
}
//# sourceMappingURL=BaseClient.js.map