interceptor-engine
v0.1.0
Published
Observes Gemini API calls via fetch, emits events, logs, and reports for AI observability.
Maintainers
Readme
Interceptor Engine
Interceptor Engine patches global fetch and provides real-time API observability for running apps.
- Detects Gemini calls (
generativelanguage.googleapis.com) - Emits normalized events (
api-call,api-error) - Prints live terminal logs and summary reports
- Stores in-memory history and aggregate metrics
- Redacts sensitive data in output
Prerequisites
- Node.js 18+ (or any runtime where
global.fetchexists) - Import this module before your first API call
Install
npm install interceptor-engineQuick Start (JavaScript)
const {
emitter,
setConfig,
getMetrics,
getCallHistory,
reportNow
} = require('interceptor-engine');
setConfig({
emitAllCalls: true,
realtimeConsole: true,
reportIntervalMs: 60000
});
emitter.on('api-call', (event) => {
console.log('Observed:', event.method, event.status, event.url);
});
emitter.on('api-error', (event) => {
console.error('API error:', event.error);
});
// Your app runs normally and uses fetch...
// On-demand report:
reportNow('manual-check');
console.log('Metrics:', getMetrics());
console.log('Recent calls:', getCallHistory({ limit: 5 }));Quick Start (TypeScript)
const interceptor = require('interceptor-engine') as {
emitter: import('events').EventEmitter;
setConfig: (config: Partial<InterceptorConfig>) => InterceptorConfig;
getMetrics: () => InterceptorMetrics;
getCallHistory: (options?: CallHistoryOptions) => InterceptorEvent[];
reportNow: (context?: string) => void;
};
type InterceptorConfig = {
slowThresholdMs: number;
emitGeminiCalls: boolean;
emitSlowCalls: boolean;
emitAllCalls: boolean;
maxHistory: number;
redactSensitiveData: boolean;
redactKeys: string[];
redactionText: string;
realtimeConsole: boolean;
consoleShowPromptPreview: boolean;
promptPreviewMaxChars: number;
reportIntervalMs: number;
printReportOnExit: boolean;
};
type CallHistoryOptions = {
limit?: number;
onlyGemini?: boolean;
onlyErrors?: boolean;
minTimeMs?: number;
query?: string;
};
type InterceptorEvent = {
id: number;
timestamp: string;
url: string;
method: string;
status: number | string;
time: number;
model: string;
response: string;
isAICall: boolean;
aiType: string;
prompt: string;
aiResponse: string;
requestBody: string;
error?: string;
};
type InterceptorMetrics = {
totalSeen: number;
totalCaptured: number;
geminiCalls: number;
slowCalls: number;
errorCalls: number;
totalLatencyMs: number;
avgLatencyMs: number;
historySize: number;
};
interceptor.emitter.on('api-call', (event: InterceptorEvent) => {
console.log(event.model, event.time);
});How It Works
- Module load patches
global.fetch - Every call is timed and normalized
- Gemini request/response fields are extracted when endpoint matches
- Sensitive values are redacted before logging/storage
- Event is emitted and optionally logged in real time
- History/metrics are updated for reporting and querying
Exported API
emitter
Event emitter for runtime notifications.
api-call: emitted for captured callsapi-error: emitted when a captured call fails
setConfig(nextConfig)
Updates runtime behavior. Unknown keys are ignored.
Arguments:
nextConfig.slowThresholdMs(number): ms threshold for slow callsnextConfig.emitGeminiCalls(boolean): capture Gemini callsnextConfig.emitSlowCalls(boolean): capture slow callsnextConfig.emitAllCalls(boolean): capture every fetch callnextConfig.maxHistory(number): max in-memory eventsnextConfig.redactSensitiveData(boolean): redact outputsnextConfig.redactKeys(string[]): key names for redaction matchingnextConfig.redactionText(string): replacement textnextConfig.realtimeConsole(boolean): print live call linesnextConfig.consoleShowPromptPreview(boolean): include prompt snippetnextConfig.promptPreviewMaxChars(number): prompt preview lengthnextConfig.reportIntervalMs(number): periodic report interval;<=0disablesnextConfig.printReportOnExit(boolean): print final report at process exit
Returns: current config object.
getConfig()
Returns current resolved config.
getCallHistory(options?)
Returns recent captured events.
Arguments:
options.limit(number, default50)options.onlyGemini(boolean, defaultfalse)options.onlyErrors(boolean, defaultfalse)options.minTimeMs(number, default0)options.query(string, default'')
Returns: InterceptorEvent[].
getMetrics()
Returns aggregate counters and latency stats.
reportNow(context?)
Prints a report immediately to console.
context(string, default'manual')
clearHistory()
Clears in-memory call history only.
resetMetrics()
Resets aggregate counters and uptime baseline.
startObserving() / stopObserving()
Starts/stops runtime console and periodic reporting observers.
restoreFetch()
Restores the original global fetch and stops observers.
isIntercepting()
Returns true if fetch is currently patched.
Event Shape (api-call)
{
id: 1,
timestamp: '2026-04-02T12:34:56.000Z',
url: 'https://generativelanguage.googleapis.com/...',
method: 'POST',
status: 200,
time: 123,
model: 'gemini-2.0-flash',
response: '{...}',
isAICall: true,
aiType: 'gemini',
prompt: 'User prompt text',
aiResponse: 'Model response text',
requestBody: '{...}',
error: undefined
}Real-Project Integration Pattern
Import once in your app bootstrap file:
// src/bootstrap.js
require('interceptor-engine');
// then import/start the rest of your app
require('./server');This ensures all later fetch calls are observed.
Notes
- Gemini parsing is endpoint-based; non-Gemini calls are still observable when
emitAllCallsis true. - History is in-memory only (process lifetime).
- Redaction is best-effort and configurable.
