@vantinelai/node-sdk 0.4.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ /**
3
+ * Vantinel integrations for major AI frameworks.
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.wrapAnthropic = exports.VantinelTracingProcessor = exports.patchOpenAIAgents = void 0;
7
+ var openai_agents_1 = require("./openai-agents");
8
+ Object.defineProperty(exports, "patchOpenAIAgents", { enumerable: true, get: function () { return openai_agents_1.patchOpenAIAgents; } });
9
+ Object.defineProperty(exports, "VantinelTracingProcessor", { enumerable: true, get: function () { return openai_agents_1.VantinelTracingProcessor; } });
10
+ var anthropic_1 = require("./anthropic");
11
+ Object.defineProperty(exports, "wrapAnthropic", { enumerable: true, get: function () { return anthropic_1.wrapAnthropic; } });
@@ -0,0 +1,70 @@
1
+ /**
2
+ * OpenAI Agents SDK integration for Vantinel.
3
+ *
4
+ * Usage:
5
+ * import { VantinelClient } from '@vantinelai/node-sdk';
6
+ * import { patchOpenAIAgents } from '@vantinelai/node-sdk/integrations/openai-agents';
7
+ *
8
+ * const client = new VantinelClient({ apiKey: '...', clientId: '...' });
9
+ * patchOpenAIAgents(client);
10
+ * // Now all @openai/agents traces are automatically monitored
11
+ */
12
+ import type { VantinelClient } from '../client';
13
+ interface SpanData {
14
+ name?: string;
15
+ model?: string;
16
+ to_agent?: string;
17
+ from_agent?: string;
18
+ triggered_by?: string;
19
+ usage?: {
20
+ input_tokens?: number;
21
+ output_tokens?: number;
22
+ };
23
+ }
24
+ interface Span {
25
+ span_id?: string;
26
+ span_data?: SpanData;
27
+ started_at?: number;
28
+ ended_at?: number;
29
+ }
30
+ interface Trace {
31
+ trace_id?: string;
32
+ name?: string;
33
+ }
34
+ interface TracingProcessor {
35
+ onTraceStart(trace: Trace): void | Promise<void>;
36
+ onTraceEnd(trace: Trace): void | Promise<void>;
37
+ onSpanStart(span: Span): void | Promise<void>;
38
+ onSpanEnd(span: Span): void | Promise<void>;
39
+ }
40
+ /**
41
+ * A TracingProcessor that forwards OpenAI Agents SDK spans to Vantinel.
42
+ */
43
+ export declare class VantinelTracingProcessor implements TracingProcessor {
44
+ private client;
45
+ private spanStarts;
46
+ private sessionId;
47
+ constructor(client: VantinelClient, options?: {
48
+ sessionId?: string;
49
+ agentId?: string;
50
+ });
51
+ onTraceStart(_trace: Trace): void;
52
+ onTraceEnd(_trace: Trace): void;
53
+ onSpanStart(span: Span): void;
54
+ onSpanEnd(span: Span): void;
55
+ private extractToolName;
56
+ private extractCost;
57
+ }
58
+ /**
59
+ * Register Vantinel as a tracing processor for the OpenAI Agents SDK.
60
+ *
61
+ * @param client - VantinelClient instance
62
+ * @param options - Optional session/agent configuration
63
+ * @returns The registered VantinelTracingProcessor
64
+ * @throws If @openai/agents is not installed
65
+ */
66
+ export declare function patchOpenAIAgents(client: VantinelClient, options?: {
67
+ sessionId?: string;
68
+ agentId?: string;
69
+ }): VantinelTracingProcessor;
70
+ export {};
@@ -0,0 +1,108 @@
1
+ "use strict";
2
+ /**
3
+ * OpenAI Agents SDK integration for Vantinel.
4
+ *
5
+ * Usage:
6
+ * import { VantinelClient } from '@vantinelai/node-sdk';
7
+ * import { patchOpenAIAgents } from '@vantinelai/node-sdk/integrations/openai-agents';
8
+ *
9
+ * const client = new VantinelClient({ apiKey: '...', clientId: '...' });
10
+ * patchOpenAIAgents(client);
11
+ * // Now all @openai/agents traces are automatically monitored
12
+ */
13
+ Object.defineProperty(exports, "__esModule", { value: true });
14
+ exports.VantinelTracingProcessor = void 0;
15
+ exports.patchOpenAIAgents = patchOpenAIAgents;
16
+ const client_1 = require("../client");
17
+ /**
18
+ * A TracingProcessor that forwards OpenAI Agents SDK spans to Vantinel.
19
+ */
20
+ class VantinelTracingProcessor {
21
+ constructor(client, options) {
22
+ this.client = client;
23
+ this.spanStarts = new Map();
24
+ this.sessionId = options?.sessionId ?? `agents_${Date.now()}`;
25
+ }
26
+ onTraceStart(_trace) { }
27
+ onTraceEnd(_trace) { }
28
+ onSpanStart(span) {
29
+ const id = span.span_id ?? String(Math.random());
30
+ this.spanStarts.set(id, Date.now());
31
+ }
32
+ onSpanEnd(span) {
33
+ const id = span.span_id ?? '';
34
+ const startMs = this.spanStarts.get(id);
35
+ this.spanStarts.delete(id);
36
+ const latencyMs = startMs != null ? Date.now() - startMs : undefined;
37
+ const spanData = span.span_data;
38
+ const spanType = spanData?.constructor?.name ?? 'UnknownSpan';
39
+ const toolName = this.extractToolName(spanData, spanType);
40
+ if (!toolName)
41
+ return;
42
+ const metadata = {
43
+ framework: 'openai-agents',
44
+ span_type: spanType,
45
+ ...(spanData?.name ? { agent_name: spanData.name } : {}),
46
+ ...(spanData?.model ? { model: spanData.model } : {}),
47
+ ...(spanData?.to_agent ? { to_agent: spanData.to_agent } : {}),
48
+ ...(latencyMs != null ? { latency_ms: latencyMs } : {}),
49
+ };
50
+ const estimatedCost = this.extractCost(spanData);
51
+ // Fire-and-forget
52
+ void this.client.sendEvent({
53
+ event_type: 'tool_call',
54
+ tool_name: toolName,
55
+ tool_args_hash: id || '',
56
+ session_id: this.sessionId,
57
+ timestamp: Date.now(),
58
+ estimated_cost: estimatedCost,
59
+ latency_ms: latencyMs,
60
+ metadata,
61
+ }).catch(() => { });
62
+ }
63
+ extractToolName(spanData, spanType) {
64
+ if (!spanData)
65
+ return null;
66
+ if (spanType === 'AgentSpanData')
67
+ return `agent_run_${spanData.name ?? 'agent'}`;
68
+ if (spanType === 'FunctionSpanData')
69
+ return `tool_call_${spanData.name ?? 'function'}`;
70
+ if (spanType === 'GenerationSpanData')
71
+ return `llm_generation_${spanData.model ?? 'unknown'}`;
72
+ if (spanType === 'HandoffSpanData')
73
+ return `handoff_to_${spanData.to_agent ?? 'unknown'}`;
74
+ if (spanType === 'GuardrailSpanData')
75
+ return `guardrail_${spanData.name ?? 'guardrail'}`;
76
+ return null;
77
+ }
78
+ extractCost(spanData) {
79
+ if (!spanData?.usage)
80
+ return undefined;
81
+ const inputTokens = spanData.usage.input_tokens ?? 0;
82
+ const outputTokens = spanData.usage.output_tokens ?? 0;
83
+ const model = spanData.model ?? 'gpt-4o';
84
+ return (0, client_1.estimateCostFromTokens)(model, inputTokens, outputTokens);
85
+ }
86
+ }
87
+ exports.VantinelTracingProcessor = VantinelTracingProcessor;
88
+ /**
89
+ * Register Vantinel as a tracing processor for the OpenAI Agents SDK.
90
+ *
91
+ * @param client - VantinelClient instance
92
+ * @param options - Optional session/agent configuration
93
+ * @returns The registered VantinelTracingProcessor
94
+ * @throws If @openai/agents is not installed
95
+ */
96
+ function patchOpenAIAgents(client, options) {
97
+ let addTracingProcessor;
98
+ try {
99
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
100
+ ({ addTracingProcessor } = require('@openai/agents'));
101
+ }
102
+ catch {
103
+ throw new Error('patchOpenAIAgents requires the @openai/agents package. Install with: npm install @openai/agents');
104
+ }
105
+ const processor = new VantinelTracingProcessor(client, options);
106
+ addTracingProcessor(processor);
107
+ return processor;
108
+ }
@@ -0,0 +1,41 @@
1
+ import { VantinelConfig } from './client';
2
+ export declare class VantinelMonitor {
3
+ private client;
4
+ private sessionId;
5
+ private config;
6
+ private globalMetadata;
7
+ private static instance;
8
+ constructor(config?: VantinelConfig);
9
+ static getSingleton(config?: VantinelConfig): VantinelMonitor;
10
+ setGlobalMetadata(metadata: Record<string, unknown>): void;
11
+ private mergeMetadata;
12
+ private hashArgs;
13
+ private applyDecision;
14
+ monitor<A extends unknown[], R>(toolName: string, fn: (...args: A) => R | Promise<R>, options?: {
15
+ traceId?: string;
16
+ skip?: boolean;
17
+ costCalculator?: (result: Awaited<R>) => {
18
+ estimated_cost: number;
19
+ metadata?: Record<string, unknown>;
20
+ };
21
+ }): (...args: A) => Promise<Awaited<R>>;
22
+ captureError(toolName: string, error: Error, metadata?: Record<string, unknown>): Promise<void>;
23
+ ping(): Promise<{
24
+ ok: boolean;
25
+ latencyMs: number;
26
+ }>;
27
+ flush(): Promise<void>;
28
+ destroy(): Promise<void>;
29
+ startTrace(): string;
30
+ wrapOpenAI(openaiClient: any): any;
31
+ /**
32
+ * Wrap any LangChain chain (RunnableSequence, LLMChain, etc.) for zero-config monitoring.
33
+ *
34
+ * ```ts
35
+ * const chain = prompt.pipe(llm).pipe(parser);
36
+ * const monitored = monitor.wrapLangChain(chain);
37
+ * const result = await monitored.invoke({ question: 'What is AI?' });
38
+ * ```
39
+ */
40
+ wrapLangChain(chain: any): any;
41
+ }
@@ -0,0 +1,308 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.VantinelMonitor = void 0;
37
+ const client_1 = require("./client");
38
+ const uuid_1 = require("uuid");
39
+ const crypto = __importStar(require("crypto"));
40
+ class VantinelMonitor {
41
+ constructor(config = {}) {
42
+ this.config = {
43
+ apiKey: process.env.VANTINEL_API_KEY,
44
+ clientId: process.env.VANTINEL_CLIENT_ID,
45
+ collectorUrl: process.env.VANTINEL_COLLECTOR_URL || 'http://localhost:8000',
46
+ agentId: process.env.VANTINEL_AGENT_ID || 'default-agent',
47
+ ...config,
48
+ dryRun: process.env.VANTINEL_DRY_RUN === 'true' || config.dryRun,
49
+ shadowMode: process.env.VANTINEL_SHADOW_MODE === 'true' || config.shadowMode,
50
+ };
51
+ if (!this.config.apiKey) {
52
+ console.warn('[Vantinel] No API Key provided. Monitoring disabled.');
53
+ }
54
+ this.globalMetadata = {};
55
+ this.client = new client_1.VantinelClient(this.config);
56
+ this.sessionId = (0, uuid_1.v4)();
57
+ }
58
+ static getSingleton(config) {
59
+ if (!VantinelMonitor.instance) {
60
+ VantinelMonitor.instance = new VantinelMonitor(config ?? {});
61
+ }
62
+ return VantinelMonitor.instance;
63
+ }
64
+ setGlobalMetadata(metadata) {
65
+ this.globalMetadata = { ...this.globalMetadata, ...metadata };
66
+ }
67
+ mergeMetadata(extra) {
68
+ const merged = { ...this.globalMetadata, ...(extra ?? {}) };
69
+ return Object.keys(merged).length > 0 ? merged : undefined;
70
+ }
71
+ hashArgs(toolName, args) {
72
+ const argsStr = JSON.stringify(args);
73
+ return crypto
74
+ .createHash('sha256')
75
+ .update(`${toolName}:${argsStr}`)
76
+ .digest('hex')
77
+ .slice(0, 32);
78
+ }
79
+ async applyDecision(decision, toolName, estimatedCost) {
80
+ if (this.config.shadowMode) {
81
+ if (decision.decision === 'block' || decision.decision === 'require_approval') {
82
+ const costStr = estimatedCost !== undefined ? `$${estimatedCost.toFixed(2)}` : 'unknown';
83
+ const reason = decision.decision === 'block' ? 'Policy Violation' : 'Approval Required';
84
+ console.warn(`[Vantinel Shadow] Would have blocked \`${toolName}\` (${reason}). Estimated savings: ${costStr}`);
85
+ if (this.config.slackWebhookUrl) {
86
+ fetch(this.config.slackWebhookUrl, {
87
+ method: 'POST',
88
+ headers: { 'Content-Type': 'application/json' },
89
+ body: JSON.stringify({
90
+ text: `🚨 *Vantinel Shadow Alert*: Would have blocked \`${toolName}\` (${reason}). Estimated savings: *${costStr}*\n_Session: ${this.sessionId}_`,
91
+ }),
92
+ }).catch(() => { }); // fire-and-forget — never block the agent
93
+ }
94
+ return { ...decision, decision: 'allow' };
95
+ }
96
+ }
97
+ return decision;
98
+ }
99
+ monitor(toolName, fn, options) {
100
+ const self = this;
101
+ return async (...args) => {
102
+ if (options?.skip) {
103
+ return await fn(...args);
104
+ }
105
+ const argsHash = self.hashArgs(toolName, args);
106
+ const start = Date.now();
107
+ const preEvent = {
108
+ session_id: self.sessionId,
109
+ agent_id: self.config.agentId,
110
+ tool_name: toolName,
111
+ tool_args_hash: argsHash,
112
+ timestamp: Date.now(),
113
+ ...(options?.traceId ? { trace_id: options.traceId } : {}),
114
+ metadata: self.mergeMetadata(),
115
+ };
116
+ const rawDecision = await self.client.sendEvent(preEvent);
117
+ const decision = await self.applyDecision(rawDecision, toolName);
118
+ if (decision.decision === 'block') {
119
+ throw new Error(`[Vantinel] Tool blocked: ${decision.message || 'Policy violation'}`);
120
+ }
121
+ if (decision.decision === 'require_approval') {
122
+ console.warn('[Vantinel] Approval required but not implemented in SDK yet. Allowing.');
123
+ }
124
+ try {
125
+ const result = await fn(...args);
126
+ const latencyMs = Date.now() - start;
127
+ let estimatedCost;
128
+ let extraMeta;
129
+ if (options?.costCalculator) {
130
+ const calc = options.costCalculator(result);
131
+ estimatedCost = calc.estimated_cost;
132
+ extraMeta = calc.metadata;
133
+ }
134
+ self.client.sendEvent({
135
+ session_id: self.sessionId,
136
+ agent_id: self.config.agentId,
137
+ tool_name: toolName,
138
+ tool_args_hash: argsHash,
139
+ timestamp: Date.now(),
140
+ latency_ms: latencyMs,
141
+ ...(estimatedCost !== undefined ? { estimated_cost: estimatedCost } : {}),
142
+ ...(options?.traceId ? { trace_id: options.traceId } : {}),
143
+ event_type: 'tool_result',
144
+ metadata: self.mergeMetadata(extraMeta),
145
+ }).catch(() => { });
146
+ return result;
147
+ }
148
+ catch (err) {
149
+ await self.captureError(toolName, err instanceof Error ? err : new Error(String(err))).catch(() => { });
150
+ throw err;
151
+ }
152
+ };
153
+ }
154
+ async captureError(toolName, error, metadata) {
155
+ await this.client.sendEvent({
156
+ session_id: this.sessionId,
157
+ agent_id: this.config.agentId,
158
+ tool_name: toolName,
159
+ tool_args_hash: crypto
160
+ .createHash('sha256')
161
+ .update(toolName + error.message)
162
+ .digest('hex')
163
+ .slice(0, 32),
164
+ timestamp: Date.now(),
165
+ event_type: 'tool_error',
166
+ metadata: this.mergeMetadata({
167
+ error_message: error.message,
168
+ error_stack: error.stack,
169
+ ...(metadata ?? {}),
170
+ }),
171
+ });
172
+ }
173
+ async ping() {
174
+ return this.client.ping();
175
+ }
176
+ async flush() {
177
+ return this.client.flush();
178
+ }
179
+ async destroy() {
180
+ return this.client.destroy();
181
+ }
182
+ startTrace() {
183
+ return (0, uuid_1.v4)();
184
+ }
185
+ wrapOpenAI(openaiClient) {
186
+ if (!openaiClient?.chat?.completions?.create) {
187
+ console.warn('[Vantinel] Provided client does not look like an OpenAI client.');
188
+ return openaiClient;
189
+ }
190
+ const self = this;
191
+ const originalCreate = openaiClient.chat.completions.create.bind(openaiClient.chat.completions);
192
+ openaiClient.chat.completions.create = async (params, reqOptions) => {
193
+ const toolName = 'openai_chat';
194
+ const argsHash = self.hashArgs(toolName, params);
195
+ const rawDecision = await self.client.sendEvent({
196
+ session_id: self.sessionId,
197
+ agent_id: self.config.agentId,
198
+ tool_name: toolName,
199
+ tool_args_hash: argsHash,
200
+ timestamp: Date.now(),
201
+ metadata: self.mergeMetadata({ model: params.model }),
202
+ });
203
+ const decision = await self.applyDecision(rawDecision, toolName);
204
+ if (decision.decision === 'block') {
205
+ throw new Error(`[Vantinel] Blocked: ${decision.message}`);
206
+ }
207
+ const start = Date.now();
208
+ const response = await originalCreate(params, reqOptions);
209
+ const latencyMs = Date.now() - start;
210
+ self.client.sendEvent({
211
+ session_id: self.sessionId,
212
+ agent_id: self.config.agentId,
213
+ tool_name: toolName,
214
+ tool_args_hash: argsHash,
215
+ timestamp: Date.now(),
216
+ latency_ms: latencyMs,
217
+ event_type: 'tool_result',
218
+ metadata: self.mergeMetadata({ model: params.model }),
219
+ }).catch(() => { });
220
+ return response;
221
+ };
222
+ return openaiClient;
223
+ }
224
+ /**
225
+ * Wrap any LangChain chain (RunnableSequence, LLMChain, etc.) for zero-config monitoring.
226
+ *
227
+ * ```ts
228
+ * const chain = prompt.pipe(llm).pipe(parser);
229
+ * const monitored = monitor.wrapLangChain(chain);
230
+ * const result = await monitored.invoke({ question: 'What is AI?' });
231
+ * ```
232
+ */
233
+ wrapLangChain(chain) {
234
+ const self = this;
235
+ const chainName = chain.constructor?.name ?? 'chain';
236
+ const sendLatencyEvent = (toolLabel, argsHash, latencyMs) => {
237
+ self.client
238
+ .sendEvent({
239
+ session_id: self.sessionId,
240
+ agent_id: self.config.agentId,
241
+ tool_name: toolLabel,
242
+ tool_args_hash: argsHash,
243
+ timestamp: Date.now(),
244
+ latency_ms: latencyMs,
245
+ event_type: 'tool_result',
246
+ metadata: self.mergeMetadata(),
247
+ })
248
+ .catch((err) => {
249
+ console.warn('[Vantinel] Failed to send latency event:', err.message);
250
+ });
251
+ };
252
+ const preCheck = async (toolLabel, argsHash) => {
253
+ const rawDecision = await self.client.sendEvent({
254
+ session_id: self.sessionId,
255
+ agent_id: self.config.agentId,
256
+ tool_name: toolLabel,
257
+ tool_args_hash: argsHash,
258
+ timestamp: Date.now(),
259
+ metadata: self.mergeMetadata(),
260
+ });
261
+ const decision = await self.applyDecision(rawDecision, toolLabel);
262
+ if (decision.decision === 'block') {
263
+ throw new Error(`[Vantinel] Blocked: ${decision.message || 'Policy violation'}`);
264
+ }
265
+ };
266
+ const wrapMethod = (methodName) => async (...args) => {
267
+ const argsHash = crypto
268
+ .createHash('sha256')
269
+ .update(JSON.stringify(args))
270
+ .digest('hex')
271
+ .slice(0, 32);
272
+ const toolLabel = `langchain_${chainName}_${methodName}`;
273
+ await preCheck(toolLabel, argsHash);
274
+ const start = Date.now();
275
+ if (methodName === 'stream') {
276
+ const stream = await chain[methodName](...args);
277
+ // Wrap the async iterator to measure total stream duration
278
+ async function* wrappedStream() {
279
+ try {
280
+ for await (const chunk of stream) {
281
+ yield chunk;
282
+ }
283
+ }
284
+ finally {
285
+ const latencyMs = Date.now() - start;
286
+ sendLatencyEvent(toolLabel, argsHash, latencyMs);
287
+ }
288
+ }
289
+ return wrappedStream();
290
+ }
291
+ const result = await chain[methodName](...args);
292
+ const latencyMs = Date.now() - start;
293
+ sendLatencyEvent(toolLabel, argsHash, latencyMs);
294
+ return result;
295
+ };
296
+ return new Proxy(chain, {
297
+ get(target, prop) {
298
+ if (prop === 'invoke' || prop === 'call' || prop === 'run' || prop === 'stream') {
299
+ return wrapMethod(prop);
300
+ }
301
+ const val = target[prop];
302
+ return typeof val === 'function' ? val.bind(target) : val;
303
+ },
304
+ });
305
+ }
306
+ }
307
+ exports.VantinelMonitor = VantinelMonitor;
308
+ VantinelMonitor.instance = null;
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Generate HMAC-SHA256 signature for request authentication.
3
+ * Covers timestamp + body to prevent replay attacks and tampering.
4
+ */
5
+ export declare function hmacSign(apiKey: string, timestamp: number, body: string, nonce?: string): string;
6
+ /**
7
+ * Validate that collector URL uses HTTPS for non-local endpoints.
8
+ */
9
+ export declare function validateCollectorUrl(url: string): string;
10
+ /**
11
+ * Generate a cryptographically random nonce (16 bytes, hex-encoded).
12
+ */
13
+ export declare function generateNonce(): string;
14
+ /**
15
+ * Redact an API key for safe logging.
16
+ */
17
+ export declare function redactApiKey(apiKey: string): string;
@@ -0,0 +1,82 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.hmacSign = hmacSign;
37
+ exports.validateCollectorUrl = validateCollectorUrl;
38
+ exports.generateNonce = generateNonce;
39
+ exports.redactApiKey = redactApiKey;
40
+ const crypto = __importStar(require("crypto"));
41
+ /**
42
+ * Generate HMAC-SHA256 signature for request authentication.
43
+ * Covers timestamp + body to prevent replay attacks and tampering.
44
+ */
45
+ function hmacSign(apiKey, timestamp, body, nonce) {
46
+ const message = nonce ? `${timestamp}.${nonce}.${body}` : `${timestamp}.${body}`;
47
+ return crypto.createHmac('sha256', apiKey).update(message).digest('hex');
48
+ }
49
+ /**
50
+ * Validate that collector URL uses HTTPS for non-local endpoints.
51
+ */
52
+ function validateCollectorUrl(url) {
53
+ if (url.startsWith('https://'))
54
+ return url;
55
+ const allowedInsecure = [
56
+ 'http://localhost', 'http://127.0.0.1', 'http://0.0.0.0',
57
+ 'http://[::1]', 'http://10.', 'http://192.168.',
58
+ ];
59
+ // Include 172.16-31 range
60
+ for (let i = 16; i <= 31; i++) {
61
+ allowedInsecure.push(`http://172.${i}.`);
62
+ }
63
+ for (const prefix of allowedInsecure) {
64
+ if (url.startsWith(prefix))
65
+ return url;
66
+ }
67
+ throw new Error(`Collector URL must use HTTPS for non-local endpoints. Got: ${url}`);
68
+ }
69
+ /**
70
+ * Generate a cryptographically random nonce (16 bytes, hex-encoded).
71
+ */
72
+ function generateNonce() {
73
+ return crypto.randomBytes(16).toString('hex');
74
+ }
75
+ /**
76
+ * Redact an API key for safe logging.
77
+ */
78
+ function redactApiKey(apiKey) {
79
+ if (apiKey.length <= 8)
80
+ return '****';
81
+ return `${apiKey.slice(0, 4)}****${apiKey.slice(-4)}`;
82
+ }
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "@vantinelai/node-sdk",
3
+ "version": "0.4.5",
4
+ "description": "Vantinel AI Observability & Guardrails SDK for Node.js",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "scripts": {
8
+ "build": "tsc",
9
+ "build:secure": "tsc && javascript-obfuscator dist/ --output dist/ --compact true --control-flow-flattening true --dead-code-injection true --string-array true --string-array-encoding rc4 --self-defending true",
10
+ "prepublishOnly": "npm run build",
11
+ "test": "jest"
12
+ },
13
+ "files": [
14
+ "dist/",
15
+ "README.md",
16
+ "LICENSE"
17
+ ],
18
+ "keywords": [
19
+ "ai",
20
+ "llm",
21
+ "observability",
22
+ "guardrails",
23
+ "agent"
24
+ ],
25
+ "author": "Vantinel AI <support@vantinel.com>",
26
+ "license": "MIT",
27
+ "repository": {
28
+ "type": "git",
29
+ "url": "https://github.com/vantinel/vantinel-node.git",
30
+ "directory": "packages/node-sdk"
31
+ },
32
+ "homepage": "https://github.com/vantinel/vantinel-node/tree/main/packages/node-sdk#readme",
33
+ "bugs": {
34
+ "url": "https://github.com/vantinel/vantinel-node/issues"
35
+ },
36
+ "dependencies": {
37
+ "axios": "^1.6.0",
38
+ "uuid": "^9.0.0"
39
+ },
40
+ "devDependencies": {
41
+ "@types/jest": "^30.0.0",
42
+ "@types/node": "^20.0.0",
43
+ "@types/uuid": "^9.0.0",
44
+ "javascript-obfuscator": "^4.1.0",
45
+ "jest": "^29.0.0",
46
+ "ts-jest": "^29.0.0",
47
+ "typescript": "^5.0.0"
48
+ }
49
+ }