@devilsdev/rag-pipeline-utils 2.2.1 → 2.3.1
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.
- package/README.md +260 -19
- package/contracts/contract-schema.json +189 -0
- package/dist/index.cjs +19 -0
- package/dist/index.mjs +15 -1
- package/package.json +3 -2
- package/src/cli/commands/wizard.js +627 -0
- package/src/cli/input-sanitization-middleware.js +356 -0
- package/src/cli/templates/development.template.json +64 -0
- package/src/cli/templates/minimal.template.json +33 -0
- package/src/cli/templates/production.template.json +104 -0
- package/src/cli/templates/testing.template.json +45 -0
- package/src/config/connection-pool-config.json +259 -0
- package/src/config/memory-optimization.js +414 -0
- package/src/config/redaction-patterns.json +150 -0
- package/src/config/sanitization-rules.json +323 -0
- package/src/core/plugin-registry.js +266 -20
- package/src/dag/core/error-context.js +391 -0
- package/src/dag/core/execution-scheduler.js +350 -0
- package/src/dag/core/topology-validation.js +415 -0
- package/src/dag/dag-engine.js +26 -424
- package/src/dev/README.md +126 -0
- package/src/dev/dev-server.js +356 -0
- package/src/dev/examples/hot-reload-usage.js +355 -0
- package/src/dev/hot-reload.js +807 -0
- package/src/enterprise/sso-integration.js +67 -25
- package/src/index.js +19 -0
- package/src/observability/event-logger.js +62 -2
- package/src/plugins/optimized-openai-embedder.js +169 -0
- package/src/security/jwt-config.js +431 -0
- package/src/security/jwt-validator.js +701 -0
- package/src/utils/api-client-pool-integration.js +436 -0
- package/src/utils/batch-processor.js +710 -0
- package/src/utils/connection-pool.js +605 -0
- package/src/utils/contract-validator.js +460 -0
- package/src/utils/error-formatter.js +603 -0
- package/src/utils/examples/error-formatter-usage.js +351 -0
- package/src/utils/input-sanitizer.js +967 -0
- package/src/utils/memory-monitor.js +800 -0
- package/src/utils/secure-logger-config.js +352 -0
- package/src/utils/secure-logger.js +576 -0
|
@@ -0,0 +1,436 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* API Client Connection Pool Integration
|
|
5
|
+
*
|
|
6
|
+
* Provides seamless integration of connection pooling with popular
|
|
7
|
+
* API clients (OpenAI, Anthropic, Pinecone, etc.) and HTTP libraries.
|
|
8
|
+
*
|
|
9
|
+
* @module utils/api-client-pool-integration
|
|
10
|
+
* @since 2.3.0
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
const { getGlobalPool } = require('./connection-pool');
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Create OpenAI client with connection pooling
|
|
17
|
+
*
|
|
18
|
+
* @param {Object} OpenAI - OpenAI constructor
|
|
19
|
+
* @param {Object} config - OpenAI configuration
|
|
20
|
+
* @param {ConnectionPoolManager} pool - Connection pool (optional, uses global if not provided)
|
|
21
|
+
* @returns {Object} OpenAI client with pooling
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* const { OpenAI } = require('openai');
|
|
25
|
+
* const { createPooledOpenAIClient } = require('./api-client-pool-integration');
|
|
26
|
+
*
|
|
27
|
+
* const client = createPooledOpenAIClient(OpenAI, {
|
|
28
|
+
* apiKey: process.env.OPENAI_API_KEY,
|
|
29
|
+
* });
|
|
30
|
+
*/
|
|
31
|
+
function createPooledOpenAIClient(OpenAI, config = {}, pool = null) {
|
|
32
|
+
const connectionPool =
|
|
33
|
+
pool ||
|
|
34
|
+
getGlobalPool({
|
|
35
|
+
maxSockets: 30,
|
|
36
|
+
maxFreeSockets: 10,
|
|
37
|
+
timeout: 60000, // 60s for LLM calls
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
// Get HTTPS agent from pool
|
|
41
|
+
const httpsAgent = connectionPool.getHttpsAgent();
|
|
42
|
+
|
|
43
|
+
// Create OpenAI client with pooled agent
|
|
44
|
+
const client = new OpenAI({
|
|
45
|
+
...config,
|
|
46
|
+
httpAgent: httpsAgent,
|
|
47
|
+
// Some OpenAI SDKs might use different property names
|
|
48
|
+
fetch: createPooledFetchWrapper(connectionPool),
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
// Wrap methods to track metrics
|
|
52
|
+
return wrapClientWithMetrics(client, connectionPool, 'openai');
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Create Anthropic client with connection pooling
|
|
57
|
+
*
|
|
58
|
+
* @param {Object} Anthropic - Anthropic constructor
|
|
59
|
+
* @param {Object} config - Anthropic configuration
|
|
60
|
+
* @param {ConnectionPoolManager} pool - Connection pool (optional)
|
|
61
|
+
* @returns {Object} Anthropic client with pooling
|
|
62
|
+
*/
|
|
63
|
+
function createPooledAnthropicClient(Anthropic, config = {}, pool = null) {
|
|
64
|
+
const connectionPool =
|
|
65
|
+
pool ||
|
|
66
|
+
getGlobalPool({
|
|
67
|
+
maxSockets: 30,
|
|
68
|
+
maxFreeSockets: 10,
|
|
69
|
+
timeout: 60000,
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
const httpsAgent = connectionPool.getHttpsAgent();
|
|
73
|
+
|
|
74
|
+
const client = new Anthropic({
|
|
75
|
+
...config,
|
|
76
|
+
httpAgent: httpsAgent,
|
|
77
|
+
fetch: createPooledFetchWrapper(connectionPool),
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
return wrapClientWithMetrics(client, connectionPool, 'anthropic');
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Create pooled fetch wrapper
|
|
85
|
+
*
|
|
86
|
+
* @param {ConnectionPoolManager} pool - Connection pool
|
|
87
|
+
* @returns {Function} Fetch function with pooling
|
|
88
|
+
*/
|
|
89
|
+
function createPooledFetchWrapper(pool) {
|
|
90
|
+
return async function pooledFetch(url, options = {}) {
|
|
91
|
+
const agent = pool.getAgentForUrl(url);
|
|
92
|
+
const startTime = Date.now();
|
|
93
|
+
|
|
94
|
+
try {
|
|
95
|
+
// Check if native fetch is available
|
|
96
|
+
if (typeof fetch === 'undefined') {
|
|
97
|
+
// Fallback to https/http module
|
|
98
|
+
return makeRequestWithAgent(url, options, agent);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Use native fetch with agent
|
|
102
|
+
const response = await fetch(url, {
|
|
103
|
+
...options,
|
|
104
|
+
agent,
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
// Track successful request
|
|
108
|
+
const duration = Date.now() - startTime;
|
|
109
|
+
pool.trackRequest(duration);
|
|
110
|
+
|
|
111
|
+
return response;
|
|
112
|
+
} catch (error) {
|
|
113
|
+
// Track error
|
|
114
|
+
const errorType =
|
|
115
|
+
error.code === 'ETIMEDOUT' || error.code === 'ESOCKETTIMEDOUT'
|
|
116
|
+
? 'timeout'
|
|
117
|
+
: 'error';
|
|
118
|
+
pool.trackError(error, errorType);
|
|
119
|
+
|
|
120
|
+
throw error;
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Make HTTP request with agent (fallback for environments without fetch)
|
|
127
|
+
* @private
|
|
128
|
+
*/
|
|
129
|
+
async function makeRequestWithAgent(url, options, agent) {
|
|
130
|
+
const https = require('https');
|
|
131
|
+
const http = require('http');
|
|
132
|
+
const { URL } = require('url');
|
|
133
|
+
|
|
134
|
+
const parsedUrl = new URL(url);
|
|
135
|
+
const protocol = parsedUrl.protocol === 'https:' ? https : http;
|
|
136
|
+
|
|
137
|
+
return new Promise((resolve, reject) => {
|
|
138
|
+
const requestOptions = {
|
|
139
|
+
...options,
|
|
140
|
+
hostname: parsedUrl.hostname,
|
|
141
|
+
port: parsedUrl.port,
|
|
142
|
+
path: parsedUrl.pathname + parsedUrl.search,
|
|
143
|
+
method: options.method || 'GET',
|
|
144
|
+
headers: options.headers || {},
|
|
145
|
+
agent,
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
const req = protocol.request(requestOptions, (res) => {
|
|
149
|
+
let data = '';
|
|
150
|
+
|
|
151
|
+
res.on('data', (chunk) => {
|
|
152
|
+
data += chunk;
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
res.on('end', () => {
|
|
156
|
+
resolve({
|
|
157
|
+
ok: res.statusCode >= 200 && res.statusCode < 300,
|
|
158
|
+
status: res.statusCode,
|
|
159
|
+
statusText: res.statusMessage,
|
|
160
|
+
headers: res.headers,
|
|
161
|
+
json: async () => JSON.parse(data),
|
|
162
|
+
text: async () => data,
|
|
163
|
+
});
|
|
164
|
+
});
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
req.on('error', reject);
|
|
168
|
+
|
|
169
|
+
if (options.body) {
|
|
170
|
+
req.write(
|
|
171
|
+
typeof options.body === 'string'
|
|
172
|
+
? options.body
|
|
173
|
+
: JSON.stringify(options.body),
|
|
174
|
+
);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
req.end();
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Wrap client methods with metrics tracking
|
|
183
|
+
* @private
|
|
184
|
+
*/
|
|
185
|
+
function wrapClientWithMetrics(client, pool, clientName) {
|
|
186
|
+
// Create proxy to intercept method calls
|
|
187
|
+
return new Proxy(client, {
|
|
188
|
+
get(target, prop) {
|
|
189
|
+
const original = target[prop];
|
|
190
|
+
|
|
191
|
+
// Only wrap async methods
|
|
192
|
+
if (typeof original === 'function') {
|
|
193
|
+
return async function (...args) {
|
|
194
|
+
const startTime = Date.now();
|
|
195
|
+
|
|
196
|
+
try {
|
|
197
|
+
const result = await original.apply(target, args);
|
|
198
|
+
|
|
199
|
+
// Track successful call
|
|
200
|
+
const duration = Date.now() - startTime;
|
|
201
|
+
pool.trackRequest(duration);
|
|
202
|
+
|
|
203
|
+
return result;
|
|
204
|
+
} catch (error) {
|
|
205
|
+
// Track error
|
|
206
|
+
pool.trackError(error, 'api_error');
|
|
207
|
+
throw error;
|
|
208
|
+
}
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
return original;
|
|
213
|
+
},
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Create pooled HTTP client (generic)
|
|
219
|
+
*
|
|
220
|
+
* @param {Object} options - HTTP client options
|
|
221
|
+
* @param {ConnectionPoolManager} pool - Connection pool (optional)
|
|
222
|
+
* @returns {Object} HTTP client with pooling
|
|
223
|
+
*/
|
|
224
|
+
function createPooledHttpClient(options = {}, pool = null) {
|
|
225
|
+
const connectionPool = pool || getGlobalPool();
|
|
226
|
+
|
|
227
|
+
return {
|
|
228
|
+
get: (url, config) => makePooledRequest('GET', url, config, connectionPool),
|
|
229
|
+
post: (url, data, config) =>
|
|
230
|
+
makePooledRequest('POST', url, { ...config, data }, connectionPool),
|
|
231
|
+
put: (url, data, config) =>
|
|
232
|
+
makePooledRequest('PUT', url, { ...config, data }, connectionPool),
|
|
233
|
+
patch: (url, data, config) =>
|
|
234
|
+
makePooledRequest('PATCH', url, { ...config, data }, connectionPool),
|
|
235
|
+
delete: (url, config) =>
|
|
236
|
+
makePooledRequest('DELETE', url, config, connectionPool),
|
|
237
|
+
request: (config) =>
|
|
238
|
+
makePooledRequest(
|
|
239
|
+
config.method || 'GET',
|
|
240
|
+
config.url,
|
|
241
|
+
config,
|
|
242
|
+
connectionPool,
|
|
243
|
+
),
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Make pooled HTTP request
|
|
249
|
+
* @private
|
|
250
|
+
*/
|
|
251
|
+
async function makePooledRequest(method, url, config = {}, pool) {
|
|
252
|
+
const agent = pool.getAgentForUrl(url);
|
|
253
|
+
const startTime = Date.now();
|
|
254
|
+
|
|
255
|
+
try {
|
|
256
|
+
const options = {
|
|
257
|
+
method,
|
|
258
|
+
headers: config.headers || {},
|
|
259
|
+
agent,
|
|
260
|
+
};
|
|
261
|
+
|
|
262
|
+
if (config.data) {
|
|
263
|
+
options.body =
|
|
264
|
+
typeof config.data === 'string'
|
|
265
|
+
? config.data
|
|
266
|
+
: JSON.stringify(config.data);
|
|
267
|
+
|
|
268
|
+
if (!options.headers['Content-Type']) {
|
|
269
|
+
options.headers['Content-Type'] = 'application/json';
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
const response = await makeRequestWithAgent(url, options, agent);
|
|
274
|
+
|
|
275
|
+
// Track successful request
|
|
276
|
+
const duration = Date.now() - startTime;
|
|
277
|
+
pool.trackRequest(duration);
|
|
278
|
+
|
|
279
|
+
return response;
|
|
280
|
+
} catch (error) {
|
|
281
|
+
// Track error
|
|
282
|
+
const errorType =
|
|
283
|
+
error.code === 'ETIMEDOUT' || error.code === 'ESOCKETTIMEDOUT'
|
|
284
|
+
? 'timeout'
|
|
285
|
+
: 'error';
|
|
286
|
+
pool.trackError(error, errorType);
|
|
287
|
+
|
|
288
|
+
throw error;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* Axios interceptor for connection pooling
|
|
294
|
+
*
|
|
295
|
+
* @param {Object} axios - Axios instance
|
|
296
|
+
* @param {ConnectionPoolManager} pool - Connection pool (optional)
|
|
297
|
+
* @returns {Object} Axios instance with pooling
|
|
298
|
+
*
|
|
299
|
+
* @example
|
|
300
|
+
* const axios = require('axios');
|
|
301
|
+
* const { addAxiosPoolingInterceptor } = require('./api-client-pool-integration');
|
|
302
|
+
*
|
|
303
|
+
* const pooledAxios = addAxiosPoolingInterceptor(axios);
|
|
304
|
+
*/
|
|
305
|
+
function addAxiosPoolingInterceptor(axios, pool = null) {
|
|
306
|
+
const connectionPool = pool || getGlobalPool();
|
|
307
|
+
|
|
308
|
+
// Add default agents
|
|
309
|
+
axios.defaults.httpAgent = connectionPool.getHttpAgent();
|
|
310
|
+
axios.defaults.httpsAgent = connectionPool.getHttpsAgent();
|
|
311
|
+
|
|
312
|
+
// Add request interceptor to track timing
|
|
313
|
+
axios.interceptors.request.use(
|
|
314
|
+
(config) => {
|
|
315
|
+
config.metadata = { startTime: Date.now() };
|
|
316
|
+
return config;
|
|
317
|
+
},
|
|
318
|
+
(error) => {
|
|
319
|
+
return Promise.reject(error);
|
|
320
|
+
},
|
|
321
|
+
);
|
|
322
|
+
|
|
323
|
+
// Add response interceptor to track metrics
|
|
324
|
+
axios.interceptors.response.use(
|
|
325
|
+
(response) => {
|
|
326
|
+
const duration = Date.now() - response.config.metadata.startTime;
|
|
327
|
+
connectionPool.trackRequest(duration);
|
|
328
|
+
return response;
|
|
329
|
+
},
|
|
330
|
+
(error) => {
|
|
331
|
+
if (error.config && error.config.metadata) {
|
|
332
|
+
const duration = Date.now() - error.config.metadata.startTime;
|
|
333
|
+
|
|
334
|
+
const errorType =
|
|
335
|
+
error.code === 'ECONNABORTED' || error.message.includes('timeout')
|
|
336
|
+
? 'timeout'
|
|
337
|
+
: 'error';
|
|
338
|
+
|
|
339
|
+
connectionPool.trackError(error, errorType);
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
return Promise.reject(error);
|
|
343
|
+
},
|
|
344
|
+
);
|
|
345
|
+
|
|
346
|
+
return axios;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
/**
|
|
350
|
+
* node-fetch wrapper with connection pooling
|
|
351
|
+
*
|
|
352
|
+
* @param {Function} nodeFetch - node-fetch function
|
|
353
|
+
* @param {ConnectionPoolManager} pool - Connection pool (optional)
|
|
354
|
+
* @returns {Function} Pooled fetch function
|
|
355
|
+
*
|
|
356
|
+
* @example
|
|
357
|
+
* const fetch = require('node-fetch');
|
|
358
|
+
* const { createPooledNodeFetch } = require('./api-client-pool-integration');
|
|
359
|
+
*
|
|
360
|
+
* const pooledFetch = createPooledNodeFetch(fetch);
|
|
361
|
+
*/
|
|
362
|
+
function createPooledNodeFetch(nodeFetch, pool = null) {
|
|
363
|
+
const connectionPool = pool || getGlobalPool();
|
|
364
|
+
|
|
365
|
+
return async function pooledNodeFetch(url, options = {}) {
|
|
366
|
+
const agent = connectionPool.getAgentForUrl(url);
|
|
367
|
+
const startTime = Date.now();
|
|
368
|
+
|
|
369
|
+
try {
|
|
370
|
+
const response = await nodeFetch(url, {
|
|
371
|
+
...options,
|
|
372
|
+
agent,
|
|
373
|
+
});
|
|
374
|
+
|
|
375
|
+
// Track successful request
|
|
376
|
+
const duration = Date.now() - startTime;
|
|
377
|
+
connectionPool.trackRequest(duration);
|
|
378
|
+
|
|
379
|
+
return response;
|
|
380
|
+
} catch (error) {
|
|
381
|
+
// Track error
|
|
382
|
+
const errorType =
|
|
383
|
+
error.type === 'request-timeout' || error.code === 'ETIMEDOUT'
|
|
384
|
+
? 'timeout'
|
|
385
|
+
: 'error';
|
|
386
|
+
connectionPool.trackError(error, errorType);
|
|
387
|
+
|
|
388
|
+
throw error;
|
|
389
|
+
}
|
|
390
|
+
};
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
/**
|
|
394
|
+
* Get connection pool metrics for monitoring
|
|
395
|
+
*
|
|
396
|
+
* @param {ConnectionPoolManager} pool - Connection pool (optional)
|
|
397
|
+
* @returns {Object} Pool metrics
|
|
398
|
+
*/
|
|
399
|
+
function getPoolMetrics(pool = null) {
|
|
400
|
+
const connectionPool = pool || getGlobalPool();
|
|
401
|
+
return connectionPool.getMetrics();
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
/**
|
|
405
|
+
* Get connection pool status
|
|
406
|
+
*
|
|
407
|
+
* @param {ConnectionPoolManager} pool - Connection pool (optional)
|
|
408
|
+
* @returns {Object} Pool status
|
|
409
|
+
*/
|
|
410
|
+
function getPoolStatus(pool = null) {
|
|
411
|
+
const connectionPool = pool || getGlobalPool();
|
|
412
|
+
return connectionPool.getStatus();
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
/**
|
|
416
|
+
* Get connection pool report
|
|
417
|
+
*
|
|
418
|
+
* @param {ConnectionPoolManager} pool - Connection pool (optional)
|
|
419
|
+
* @returns {string} Human-readable pool report
|
|
420
|
+
*/
|
|
421
|
+
function getPoolReport(pool = null) {
|
|
422
|
+
const connectionPool = pool || getGlobalPool();
|
|
423
|
+
return connectionPool.getReport();
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
module.exports = {
|
|
427
|
+
createPooledOpenAIClient,
|
|
428
|
+
createPooledAnthropicClient,
|
|
429
|
+
createPooledHttpClient,
|
|
430
|
+
createPooledFetchWrapper,
|
|
431
|
+
createPooledNodeFetch,
|
|
432
|
+
addAxiosPoolingInterceptor,
|
|
433
|
+
getPoolMetrics,
|
|
434
|
+
getPoolStatus,
|
|
435
|
+
getPoolReport,
|
|
436
|
+
};
|