UNPKG

@ethicalzen/sdk

Version:

Official EthicalZen SDK for Node.js - AI safety guardrails made simple

220 lines (219 loc) 7.84 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.EthicalZenProxyClient = void 0; const axios_1 = __importDefault(require("axios")); /** * EthicalZen Proxy Client * * Initialize once with gateway URL and certificate, then make normal REST API calls. * The SDK automatically adds certificate headers, and the gateway intercepts, validates, * and forwards requests to their original destination. * * **How it works:** * 1. Client calls normal URL: `https://api.openai.com/v1/chat/completions` * 2. SDK adds `X-Certificate-ID` header automatically * 3. Gateway intercepts request, validates input with guardrails * 4. Gateway forwards to original URL if validation passes * 5. Gateway intercepts response, validates output with guardrails * 6. Gateway returns response to client if validation passes * * @example * ```typescript * // Initialize once with certificate * const client = new EthicalZenProxyClient({ * gatewayURL: 'http://gateway:8080', * certificateId: 'hipaa-compliant-llm-v1', * apiKey: 'sk-openai-key' * }); * * // Make normal API calls - uses REAL URL, certificate added automatically * const response = await client.post('https://api.openai.com/v1/chat/completions', { * model: "gpt-4", * messages: [{ role: "user", content: "Hello" }] * }); * * // Response is validated by gateway before reaching client * console.log(response.data); * ``` */ class EthicalZenProxyClient { constructor(config) { if (!config.gatewayURL) { throw new Error('Gateway URL is required'); } if (!config.certificateId) { throw new Error('Certificate ID is required'); } this.gatewayURL = config.gatewayURL.replace(/\/$/, ''); // Remove trailing slash this.certificateId = config.certificateId; this.tenantId = config.tenantId || 'demo'; // Default to 'demo' tenant // Create axios client that intercepts all requests this.client = axios_1.default.create({ timeout: config.timeout || 30000, headers: { 'User-Agent': '@ethicalzen/sdk/0.1.0', ...(config.apiKey && { 'X-API-Key': config.apiKey }) } }); // Store API key for use in interceptor const apiKey = config.apiKey; // Add request interceptor to package certificate as header and route through gateway this.client.interceptors.request.use((requestConfig) => { if (!requestConfig.url) return requestConfig; const originalURL = requestConfig.url; // Route through gateway's /api/proxy endpoint requestConfig.url = `${this.gatewayURL}/api/proxy`; // Add our headers while PRESERVING existing headers (like Authorization) // Order matters: existing headers first, then our overrides const newHeaders = { // Default Content-Type (can be overridden by existing) 'Content-Type': 'application/json', // Gateway authentication ...(apiKey && { 'X-API-Key': apiKey }), // DC (Deterministic Contract) headers 'X-DC-Id': this.certificateId, 'X-DC-Digest': 'sha256-sdk-auto', 'X-DC-Suite': 'S1', 'X-Tenant-ID': this.tenantId, 'X-Target-Endpoint': originalURL, }; // Merge: keep existing headers (like Authorization), add our headers if (requestConfig.headers && typeof requestConfig.headers === 'object') { Object.assign(requestConfig.headers, newHeaders); } else { requestConfig.headers = newHeaders; } return requestConfig; }); } /** * Make a POST request through the gateway * * @param url - Normal service URL (e.g., https://api.openai.com/v1/chat/completions) * @param data - Request body * @param config - Optional axios config * @returns Response from target service (after gateway validation) * * **Note:** SDK automatically packages certificate and routes through gateway. * You use the REAL service URL, not a proxy URL. * * @example * ```typescript * // Use REAL OpenAI URL - SDK handles gateway routing automatically * const response = await client.post( * 'https://api.openai.com/v1/chat/completions', * { * model: "gpt-4", * messages: [{ role: "user", content: "Hello" }] * } * ); * ``` */ async post(url, data, config) { // Interceptor automatically adds certificate and routes through gateway return this.client.post(url, data, config); } /** * Make a GET request through the gateway * * @param url - Normal service URL * @param config - Optional axios config * @returns Response from target service (after gateway validation) * * @example * ```typescript * const response = await client.get('https://api.example.com/data'); * ``` */ async get(url, config) { return this.client.get(url, config); } /** * Make a PUT request through the gateway * * @param url - Normal service URL * @param data - Request body * @param config - Optional axios config * @returns Response from target service (after gateway validation) */ async put(url, data, config) { return this.client.put(url, data, config); } /** * Make a PATCH request through the gateway * * @param url - Normal service URL * @param data - Request body * @param config - Optional axios config * @returns Response from target service (after gateway validation) */ async patch(url, data, config) { return this.client.patch(url, data, config); } /** * Make a DELETE request through the gateway * * @param url - Normal service URL * @param config - Optional axios config * @returns Response from target service (after gateway validation) */ async delete(url, config) { return this.client.delete(url, config); } /** * Make a request with custom method through the gateway * * @param config - Axios request config with method and url * @returns Response from target service (after gateway validation) */ async request(config) { if (!config.url) { throw new Error('URL is required in request config'); } return this.client.request(config); } /** * Get the current gateway URL * @returns Gateway base URL */ getGatewayURL() { return this.gatewayURL; } /** * Get the current certificate ID * @returns Certificate ID */ getCertificateId() { return this.certificateId; } /** * Get the current tenant ID * @returns Tenant ID */ getTenantId() { return this.tenantId; } /** * Get proxy URL for a specific target (for reference/debugging) * Note: The actual routing uses /api/proxy with headers, not this URL format * * @param targetURL - Target service URL * @returns Formatted proxy URL (for reference only) */ getProxyURL(targetURL) { return `${this.gatewayURL}/api/proxy`; } /** * Get the underlying axios instance for advanced usage * @returns Axios instance with interceptors configured */ getAxiosInstance() { return this.client; } } exports.EthicalZenProxyClient = EthicalZenProxyClient;