magically-sdk
Version:
Official SDK for Magically - Build mobile apps with AI
111 lines (110 loc) • 4.1 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.APIClient = void 0;
const Logger_1 = require("./Logger");
class APIClient {
constructor(config, loggerPrefix = 'MagicallyAPI') {
this.apiKey = null;
this.config = config;
this.logger = new Logger_1.Logger(config.debug || false, loggerPrefix);
this.baseUrl = config.apiUrl || 'https://trymagically.com';
// Check for API key in environment (for edge functions)
if (typeof globalThis !== 'undefined' && 'MAGICALLY_API_KEY' in globalThis) {
this.apiKey = globalThis.MAGICALLY_API_KEY;
this.logger.info('API key detected in environment - using API key authentication');
}
}
/**
* Make an authenticated API request with automatic logging
*/
async request(endpoint, options, token) {
const startTime = Date.now();
let requestId = '';
const url = `${this.baseUrl}${endpoint}`;
const headers = {
'Content-Type': 'application/json',
...options.headers,
};
// Use API key if available (edge environment), otherwise use provided token
if (this.apiKey) {
headers['Authorization'] = `Bearer ${this.apiKey}`;
this.logger.debug('Using API key authentication for request');
}
else if (token) {
headers['Authorization'] = `Bearer ${token}`;
}
const requestConfig = {
method: options.method,
headers,
body: options.body ? JSON.stringify(options.body) : undefined,
};
// Log the request
requestId = this.logger.networkRequest(options.method, url, {
headers,
body: options.body,
operation: options.operation
});
try {
const response = await fetch(url, requestConfig);
const responseData = await response.json();
const duration = Date.now() - startTime;
if (!response.ok) {
// Log error response
this.logger.networkError(requestId, responseData, {
duration,
operation: options.operation
});
// Throw structured error
this.handleAPIError(responseData, `${options.operation || 'Request'} failed`);
}
// Log successful response
this.logger.networkResponse(requestId, {
status: response.status,
statusText: response.statusText,
duration,
data: this.sanitizeResponseData(responseData, options.operation),
operation: options.operation
});
return responseData;
}
catch (error) {
// Log network errors
if (requestId) {
this.logger.networkError(requestId, error, {
duration: Date.now() - startTime,
operation: options.operation
});
}
throw error;
}
}
/**
* Check if running in edge environment (has API key)
*/
isEdgeEnvironment() {
return this.apiKey !== null;
}
/**
* Sanitize response data for logging (avoid logging large arrays)
*/
sanitizeResponseData(data, operation) {
if (operation === 'query' && data.data && Array.isArray(data.data)) {
return {
...data,
dataCount: data.data.length,
data: '[Array of items]'
};
}
return data;
}
/**
* Handle API errors with structured error information
*/
handleAPIError(errorData, fallbackMessage) {
// Create an error with the response data attached for the Logger
const error = new Error(errorData.error || errorData.message || fallbackMessage);
error.responseData = errorData; // Preserve the original error response for Logger
throw error;
}
}
exports.APIClient = APIClient;