unbound-claude-code
Version:
Claude Code with Unbound integration - Drop-in replacement for Claude Code with multi-provider routing and cost optimization
121 lines ⢠4.49 kB
JavaScript
;
/**
* Unbound Code Interceptor
*
* Intercepts and logs requests. Used for debugging.
* Uses environment variables to redirect Claude to Unbound gateway.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.UnboundInterceptor = void 0;
exports.initializeUnboundInterceptor = initializeUnboundInterceptor;
exports.getUnboundInterceptor = getUnboundInterceptor;
exports.setUnboundApiKey = setUnboundApiKey;
const global_1 = require("./global");
class UnboundInterceptor {
constructor(config = {}) {
this.config = {
baseUrl: `${global_1.UNBOUND_BASE_URL}/v1`,
logLevel: "info",
...config,
};
}
setApiKey(apiKey) {
// No-op: API key is now handled via environment variables
console.log("API key set via environment variables");
}
logRequest(url, method, headers, body) {
console.log('\nš REQUEST INTERCEPTED');
console.log('ā'.repeat(50));
console.log(`š URL: ${url}`);
console.log(`š§ Method: ${method}`);
console.log('\nš Headers:');
if (headers) {
if (headers instanceof Headers) {
headers.forEach((value, key) => {
// Mask sensitive headers
const maskedValue = key.toLowerCase().includes('authorization') || key.toLowerCase().includes('key')
? `${value.substring(0, 10)}...`
: value;
console.log(` ${key}: ${maskedValue}`);
});
}
else {
Object.entries(headers).forEach(([key, value]) => {
const maskedValue = key.toLowerCase().includes('authorization') || key.toLowerCase().includes('key')
? `${String(value).substring(0, 10)}...`
: value;
console.log(` ${key}: ${maskedValue}`);
});
}
}
console.log('\nš¦ Body:');
if (body) {
try {
const bodyStr = typeof body === 'string' ? body : body.toString();
const parsedBody = JSON.parse(bodyStr);
console.log('š¦ Request Payload:');
console.log(JSON.stringify(parsedBody, null, 2));
// Specifically log messages if they exist
if (parsedBody.messages) {
console.log('\nš¬ Messages being sent:');
parsedBody.messages.forEach((msg, index) => {
console.log(` Message ${index + 1} (${msg.role}):`);
console.log(` ${msg.content}`);
});
}
}
catch (e) {
console.log('š¦ Request Body (raw):');
console.log(body);
}
}
else {
console.log('[No body]');
}
console.log('ā'.repeat(50));
}
instrumentFetch() {
if (!global.fetch) {
return;
}
// Check if already instrumented
if (global.fetch.__unboundIntercepted) {
return;
}
const originalFetch = global.fetch;
const interceptor = this;
global.fetch = async function (input, init = {}) {
const url = typeof input === 'string' ? input : input instanceof URL ? input.toString() : input.url;
const method = init.method || 'GET';
// Enable this to log all outgoing requests for debugging
// interceptor.logRequest(url, method, init.headers, init.body);
// Pass through to original fetch
return originalFetch(input, init);
};
// Mark fetch as instrumented
global.fetch.__unboundIntercepted = true;
}
instrumentAll() {
this.instrumentFetch();
}
}
exports.UnboundInterceptor = UnboundInterceptor;
// Global interceptor instance
let globalInterceptor = null;
function initializeUnboundInterceptor(config) {
if (globalInterceptor) {
return globalInterceptor;
}
globalInterceptor = new UnboundInterceptor(config);
globalInterceptor.instrumentAll();
return globalInterceptor;
}
function getUnboundInterceptor() {
return globalInterceptor;
}
function setUnboundApiKey(apiKey) {
if (globalInterceptor) {
globalInterceptor.setApiKey(apiKey);
}
}
//# sourceMappingURL=interceptor.js.map