@juspay/neurolink 7.24.1 → 7.26.0

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.
Files changed (34) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/core/baseProvider.d.ts +13 -0
  3. package/dist/core/baseProvider.js +121 -1
  4. package/dist/core/evaluationProviders.d.ts +26 -0
  5. package/dist/core/evaluationProviders.js +160 -0
  6. package/dist/index.d.ts +3 -0
  7. package/dist/index.js +2 -0
  8. package/dist/lib/core/baseProvider.d.ts +13 -0
  9. package/dist/lib/core/baseProvider.js +121 -1
  10. package/dist/lib/core/evaluationProviders.d.ts +26 -0
  11. package/dist/lib/core/evaluationProviders.js +160 -0
  12. package/dist/lib/index.d.ts +3 -0
  13. package/dist/lib/index.js +2 -0
  14. package/dist/lib/middleware/builtin/analytics.d.ts +16 -0
  15. package/dist/lib/middleware/builtin/analytics.js +130 -0
  16. package/dist/lib/middleware/factory.d.ts +54 -0
  17. package/dist/lib/middleware/factory.js +289 -0
  18. package/dist/lib/middleware/index.d.ts +58 -0
  19. package/dist/lib/middleware/index.js +67 -0
  20. package/dist/lib/middleware/registry.d.ts +78 -0
  21. package/dist/lib/middleware/registry.js +283 -0
  22. package/dist/lib/middleware/types.d.ts +144 -0
  23. package/dist/lib/middleware/types.js +1 -0
  24. package/dist/middleware/builtin/analytics.d.ts +16 -0
  25. package/dist/middleware/builtin/analytics.js +130 -0
  26. package/dist/middleware/factory.d.ts +54 -0
  27. package/dist/middleware/factory.js +289 -0
  28. package/dist/middleware/index.d.ts +58 -0
  29. package/dist/middleware/index.js +67 -0
  30. package/dist/middleware/registry.d.ts +78 -0
  31. package/dist/middleware/registry.js +283 -0
  32. package/dist/middleware/types.d.ts +144 -0
  33. package/dist/middleware/types.js +1 -0
  34. package/package.json +1 -1
@@ -1,4 +1,11 @@
1
1
  import { modelConfig } from "./modelConfiguration.js";
2
+ const PERFORMANCE_THRESHOLDS = {
3
+ EXCELLENT_SUCCESS_RATE: 0.95,
4
+ EXCELLENT_RESPONSE_TIME_MS: 2000,
5
+ GOOD_SUCCESS_RATE: 0.9,
6
+ FAIR_SUCCESS_RATE: 0.8,
7
+ };
8
+ const providerMetrics = new Map();
2
9
  /**
3
10
  * Convert new configuration format to legacy format for backwards compatibility
4
11
  */
@@ -101,3 +108,156 @@ export function getBestAvailableProvider(preferCheap = true) {
101
108
  const sortedProviders = sortProvidersByPreference(availableProviders, preferCheap);
102
109
  return sortedProviders[0];
103
110
  }
111
+ /**
112
+ Record actual provider performance for optimization
113
+ */
114
+ export function recordProviderPerformanceFromMetrics(providerName, metrics) {
115
+ const existing = providerMetrics.get(providerName) || {
116
+ responseTime: [],
117
+ successRate: 0,
118
+ tokenThroughput: 0,
119
+ costEfficiency: 0,
120
+ lastUpdated: new Date(),
121
+ sampleCount: 0,
122
+ };
123
+ // Keep rolling window of last 50 response times
124
+ existing.responseTime.push(metrics.responseTime);
125
+ if (existing.responseTime.length > 50) {
126
+ existing.responseTime.shift();
127
+ }
128
+ // Update success rate
129
+ const totalSamples = existing.sampleCount + 1;
130
+ existing.successRate =
131
+ (existing.successRate * existing.sampleCount + (metrics.success ? 1 : 0)) /
132
+ totalSamples;
133
+ // Update throughput (tokens per second)
134
+ if (metrics.responseTime > 0) {
135
+ const tokensPerSecond = metrics.tokensGenerated / (metrics.responseTime / 1000);
136
+ existing.tokenThroughput =
137
+ (existing.tokenThroughput * existing.sampleCount + tokensPerSecond) /
138
+ totalSamples;
139
+ }
140
+ // If responseTime is 0, skip updating tokenThroughput for this sample
141
+ // but still update other metrics
142
+ // Update cost efficiency (tokens per dollar)
143
+ if (metrics.cost > 0) {
144
+ const tokensPerDollar = metrics.tokensGenerated / metrics.cost;
145
+ existing.costEfficiency =
146
+ (existing.costEfficiency * existing.sampleCount + tokensPerDollar) /
147
+ totalSamples;
148
+ }
149
+ existing.sampleCount = totalSamples;
150
+ existing.lastUpdated = new Date();
151
+ providerMetrics.set(providerName, existing);
152
+ }
153
+ /**
154
+ * Get performance-optimized provider based on real metrics
155
+ */
156
+ export function getPerformanceOptimizedProvider(priority = "speed") {
157
+ const availableProviders = getAvailableProviders();
158
+ if (availableProviders.length === 0) {
159
+ return null;
160
+ }
161
+ // Score providers based on real performance data
162
+ const scoredProviders = availableProviders.map((provider) => {
163
+ const metrics = providerMetrics.get(provider.provider);
164
+ if (!metrics || metrics.sampleCount < 3) {
165
+ // Fall back to static performance ratings for providers without data
166
+ return {
167
+ provider,
168
+ score: getStaticPerformanceScore(provider, priority),
169
+ metrics: null,
170
+ };
171
+ }
172
+ let score = 0;
173
+ switch (priority) {
174
+ case "speed": {
175
+ const avgResponseTime = metrics.responseTime.reduce((a, b) => a + b, 0) /
176
+ metrics.responseTime.length;
177
+ score =
178
+ metrics.tokenThroughput * 0.6 +
179
+ (5000 / Math.max(avgResponseTime, 100)) * 0.4;
180
+ break;
181
+ }
182
+ case "cost": {
183
+ score = metrics.costEfficiency * 0.7 + metrics.successRate * 0.3;
184
+ break;
185
+ }
186
+ case "reliability": {
187
+ score = metrics.successRate * 0.8 + (metrics.sampleCount / 100) * 0.2;
188
+ break;
189
+ }
190
+ }
191
+ return { provider, score, metrics };
192
+ });
193
+ // Sort by score and return best
194
+ scoredProviders.sort((a, b) => b.score - a.score);
195
+ return scoredProviders[0].provider;
196
+ }
197
+ /**
198
+ * Helper function for providers without performance data
199
+ */
200
+ function getStaticPerformanceScore(provider, priority) {
201
+ switch (priority) {
202
+ case "speed": {
203
+ const speedScore = provider.performance?.speed || 1;
204
+ return speedScore;
205
+ }
206
+ case "cost": {
207
+ const costScore = provider.performance?.cost || 1;
208
+ return costScore;
209
+ }
210
+ case "reliability": {
211
+ const qualityScore = provider.performance?.quality || 1;
212
+ return qualityScore;
213
+ }
214
+ default: {
215
+ throw new Error(`Invalid priority: "${priority}". Must be one of: speed, cost, reliability`);
216
+ }
217
+ }
218
+ }
219
+ export function getProviderPerformanceAnalytics() {
220
+ const analytics = {};
221
+ for (const [providerName, metrics] of providerMetrics.entries()) {
222
+ if (metrics.sampleCount === 0) {
223
+ continue;
224
+ }
225
+ const avgResponseTime = metrics.responseTime.reduce((a, b) => a + b, 0) /
226
+ metrics.responseTime.length;
227
+ let recommendation = "";
228
+ if (metrics.successRate > PERFORMANCE_THRESHOLDS.EXCELLENT_SUCCESS_RATE &&
229
+ avgResponseTime < PERFORMANCE_THRESHOLDS.EXCELLENT_RESPONSE_TIME_MS) {
230
+ recommendation = "Excellent - Recommended for production";
231
+ }
232
+ else if (metrics.successRate > PERFORMANCE_THRESHOLDS.GOOD_SUCCESS_RATE) {
233
+ recommendation = "Good - Suitable for most tasks";
234
+ }
235
+ else if (metrics.successRate > PERFORMANCE_THRESHOLDS.FAIR_SUCCESS_RATE) {
236
+ recommendation = "Fair - Monitor closely";
237
+ }
238
+ else {
239
+ recommendation = "Poor - Consider alternative providers";
240
+ }
241
+ analytics[providerName] = {
242
+ avgResponseTime,
243
+ successRate: metrics.successRate,
244
+ tokenThroughput: metrics.tokenThroughput,
245
+ costEfficiency: metrics.costEfficiency,
246
+ recommendation,
247
+ sampleCount: metrics.sampleCount,
248
+ };
249
+ }
250
+ return analytics;
251
+ }
252
+ /**
253
+ * Reset performance metrics for a provider or all providers.
254
+ * @param providerName - (Optional) The name of the provider to reset. If omitted, resets all providers.
255
+ */
256
+ export function resetProviderMetrics(providerName) {
257
+ if (providerName) {
258
+ providerMetrics.delete(providerName);
259
+ }
260
+ else {
261
+ providerMetrics.clear();
262
+ }
263
+ }
@@ -18,6 +18,9 @@ export { getBestProvider, getAvailableProviders, isValidProvider, } from "./util
18
18
  export { NeuroLink } from "./neurolink.js";
19
19
  export type { ProviderStatus, MCPStatus } from "./neurolink.js";
20
20
  export type { MCPServerInfo } from "./types/mcpTypes.js";
21
+ export type { NeuroLinkMiddleware, MiddlewareContext, MiddlewareFactoryOptions, } from "./middleware/types.js";
22
+ export { MiddlewareRegistry, MiddlewareFactory } from "./middleware/index.js";
23
+ export { createAnalyticsMiddleware } from "./middleware/builtin/analytics.js";
21
24
  export declare const VERSION = "1.0.0";
22
25
  /**
23
26
  * Quick start factory function
package/dist/lib/index.js CHANGED
@@ -16,6 +16,8 @@ export { BedrockModels, OpenAIModels, VertexModels, DEFAULT_PROVIDER_CONFIGS, }
16
16
  export { getBestProvider, getAvailableProviders, isValidProvider, } from "./utils/providerUtils.js";
17
17
  // Main NeuroLink wrapper class and diagnostic types
18
18
  export { NeuroLink } from "./neurolink.js";
19
+ export { MiddlewareRegistry, MiddlewareFactory } from "./middleware/index.js";
20
+ export { createAnalyticsMiddleware } from "./middleware/builtin/analytics.js";
19
21
  // Version
20
22
  export const VERSION = "1.0.0";
21
23
  /**
@@ -0,0 +1,16 @@
1
+ import type { NeuroLinkMiddleware } from "../types.js";
2
+ /**
3
+ * Create analytics middleware for tracking AI model usage
4
+ * Collects metrics on token usage, response times, and model performance
5
+ */
6
+ export declare function createAnalyticsMiddleware(): NeuroLinkMiddleware;
7
+ /**
8
+ * Get collected metrics from analytics middleware
9
+ * Note: This is a utility function for accessing metrics
10
+ */
11
+ export declare function getAnalyticsMetrics(): Map<string, Record<string, unknown>>;
12
+ /**
13
+ * Clear collected metrics from analytics middleware
14
+ * Note: This is a utility function for clearing metrics
15
+ */
16
+ export declare function clearAnalyticsMetrics(): void;
@@ -0,0 +1,130 @@
1
+ import { logger } from "../../utils/logger.js";
2
+ /**
3
+ * Create analytics middleware for tracking AI model usage
4
+ * Collects metrics on token usage, response times, and model performance
5
+ */
6
+ export function createAnalyticsMiddleware() {
7
+ const requestMetrics = new Map();
8
+ const metadata = {
9
+ id: "analytics",
10
+ name: "Analytics Tracking",
11
+ description: "Tracks token usage, response times, and model performance metrics",
12
+ priority: 100, // High priority to ensure analytics are captured
13
+ defaultEnabled: true,
14
+ };
15
+ const middleware = {
16
+ wrapGenerate: async ({ doGenerate, params }) => {
17
+ const requestId = `analytics-${Date.now()}`;
18
+ const startTime = Date.now();
19
+ logger.debug(`[AnalyticsMiddleware] Starting request tracking`, {
20
+ requestId,
21
+ hasPrompt: !!params.prompt,
22
+ });
23
+ try {
24
+ // Execute the generation
25
+ const result = await doGenerate();
26
+ // Calculate metrics
27
+ const responseTime = Date.now() - startTime;
28
+ const analytics = {
29
+ requestId,
30
+ responseTime,
31
+ timestamp: new Date().toISOString(),
32
+ usage: {
33
+ inputTokens: result.usage?.promptTokens || 0,
34
+ outputTokens: result.usage?.completionTokens || 0,
35
+ totalTokens: (result.usage?.promptTokens || 0) +
36
+ (result.usage?.completionTokens || 0),
37
+ },
38
+ };
39
+ // Store metrics for potential retrieval
40
+ requestMetrics.set(requestId, analytics);
41
+ logger.debug(`[AnalyticsMiddleware] Request completed`, analytics);
42
+ // Add analytics to the result
43
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
44
+ const updatedResult = { ...result };
45
+ if (!updatedResult.experimental_providerMetadata) {
46
+ updatedResult.experimental_providerMetadata = {};
47
+ }
48
+ if (!updatedResult.experimental_providerMetadata.neurolink) {
49
+ updatedResult.experimental_providerMetadata.neurolink = {};
50
+ }
51
+ updatedResult.experimental_providerMetadata.neurolink.analytics =
52
+ analytics;
53
+ return updatedResult;
54
+ }
55
+ catch (error) {
56
+ const responseTime = Date.now() - startTime;
57
+ logger.error(`[AnalyticsMiddleware] Request failed`, {
58
+ requestId,
59
+ responseTime,
60
+ error: error instanceof Error ? error.message : String(error),
61
+ });
62
+ throw error;
63
+ }
64
+ },
65
+ wrapStream: async ({ doStream, params }) => {
66
+ const requestId = `analytics-stream-${Date.now()}`;
67
+ const startTime = Date.now();
68
+ logger.debug(`[AnalyticsMiddleware] Starting stream tracking`, {
69
+ requestId,
70
+ hasPrompt: !!params.prompt,
71
+ });
72
+ try {
73
+ const result = await doStream();
74
+ const streamAnalytics = {
75
+ requestId,
76
+ startTime,
77
+ timestamp: new Date().toISOString(),
78
+ streamingMode: true,
79
+ };
80
+ requestMetrics.set(requestId, streamAnalytics);
81
+ // The 'result' is a stream, so we can't directly modify it.
82
+ // Analytics for streams are typically handled after the stream is consumed.
83
+ // For this middleware, we'll log the start and rely on other mechanisms
84
+ // to capture the end-to-end stream metrics if needed.
85
+ // We will pass a new property in the `rawResponse`
86
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
87
+ const updatedResult = { ...result };
88
+ if (!updatedResult.rawResponse) {
89
+ updatedResult.rawResponse = {};
90
+ }
91
+ if (!updatedResult.rawResponse.neurolink) {
92
+ updatedResult.rawResponse.neurolink = {};
93
+ }
94
+ updatedResult.rawResponse.neurolink.analytics = streamAnalytics;
95
+ return updatedResult;
96
+ }
97
+ catch (error) {
98
+ const responseTime = Date.now() - startTime;
99
+ logger.error(`[AnalyticsMiddleware] Stream failed`, {
100
+ requestId,
101
+ responseTime,
102
+ error: error instanceof Error ? error.message : String(error),
103
+ });
104
+ throw error;
105
+ }
106
+ },
107
+ };
108
+ // Return the NeuroLinkMiddleware with metadata
109
+ return {
110
+ ...middleware,
111
+ metadata,
112
+ };
113
+ }
114
+ /**
115
+ * Get collected metrics from analytics middleware
116
+ * Note: This is a utility function for accessing metrics
117
+ */
118
+ export function getAnalyticsMetrics() {
119
+ // This would need to be implemented with a global registry
120
+ // For now, return empty map
121
+ return new Map();
122
+ }
123
+ /**
124
+ * Clear collected metrics from analytics middleware
125
+ * Note: This is a utility function for clearing metrics
126
+ */
127
+ export function clearAnalyticsMetrics() {
128
+ // This would need to be implemented with a global registry
129
+ // For now, do nothing
130
+ }
@@ -0,0 +1,54 @@
1
+ import type { LanguageModelV1 } from "ai";
2
+ import type { MiddlewareContext, MiddlewareConfig, MiddlewareFactoryOptions, MiddlewareChainStats } from "./types.js";
3
+ /**
4
+ * Middleware factory for creating and applying middleware chains
5
+ */
6
+ export declare class MiddlewareFactory {
7
+ /**
8
+ * Apply middleware to a language model
9
+ */
10
+ static applyMiddleware(model: LanguageModelV1, context: MiddlewareContext, options?: MiddlewareFactoryOptions): LanguageModelV1;
11
+ /**
12
+ * Build middleware configuration from factory options
13
+ */
14
+ private static buildMiddlewareConfig;
15
+ /**
16
+ * Get preset configuration
17
+ */
18
+ private static getPresetConfig;
19
+ /**
20
+ * Get built-in preset configurations
21
+ */
22
+ private static getBuiltInPresets;
23
+ /**
24
+ * Create middleware context from provider and options
25
+ */
26
+ static createContext(provider: string, model: string, options?: Record<string, unknown>, session?: {
27
+ sessionId?: string;
28
+ userId?: string;
29
+ }): MiddlewareContext;
30
+ /**
31
+ * Validate middleware configuration
32
+ */
33
+ static validateConfig(config: Record<string, MiddlewareConfig>): {
34
+ isValid: boolean;
35
+ errors: string[];
36
+ warnings: string[];
37
+ };
38
+ /**
39
+ * Get available presets
40
+ */
41
+ static getAvailablePresets(): Array<{
42
+ name: string;
43
+ description: string;
44
+ middleware: string[];
45
+ }>;
46
+ /**
47
+ * Get middleware chain statistics
48
+ */
49
+ static getChainStats(context: MiddlewareContext, config: Record<string, MiddlewareConfig>): MiddlewareChainStats;
50
+ /**
51
+ * Create a middleware-enabled model factory function
52
+ */
53
+ static createModelFactory(baseModelFactory: () => Promise<LanguageModelV1>, defaultOptions?: MiddlewareFactoryOptions): (context: MiddlewareContext, options?: MiddlewareFactoryOptions) => Promise<LanguageModelV1>;
54
+ }
@@ -0,0 +1,289 @@
1
+ import { wrapLanguageModel } from "ai";
2
+ import { middlewareRegistry } from "./registry.js";
3
+ import { logger } from "../utils/logger.js";
4
+ /**
5
+ * Middleware factory for creating and applying middleware chains
6
+ */
7
+ export class MiddlewareFactory {
8
+ /**
9
+ * Apply middleware to a language model
10
+ */
11
+ static applyMiddleware(model, context, options = {}) {
12
+ const startTime = Date.now();
13
+ try {
14
+ // Build middleware configuration
15
+ const middlewareConfig = this.buildMiddlewareConfig(options);
16
+ // Build middleware chain
17
+ const middlewareChain = middlewareRegistry.buildChain(context, middlewareConfig);
18
+ if (middlewareChain.length === 0) {
19
+ logger.debug("No middleware to apply", { provider: context.provider });
20
+ return model;
21
+ }
22
+ logger.debug(`Applying ${middlewareChain.length} middleware to model`, {
23
+ provider: context.provider,
24
+ model: context.model,
25
+ middlewareCount: middlewareChain.length,
26
+ });
27
+ // Apply middleware using AI SDK's wrapLanguageModel
28
+ // Cast to the expected AI SDK middleware type
29
+ const wrappedModel = wrapLanguageModel({
30
+ model,
31
+ middleware: middlewareChain,
32
+ });
33
+ const processingTime = Date.now() - startTime;
34
+ logger.debug("Middleware applied successfully", {
35
+ provider: context.provider,
36
+ middlewareCount: middlewareChain.length,
37
+ processingTime,
38
+ });
39
+ return wrappedModel;
40
+ }
41
+ catch (error) {
42
+ logger.error("Failed to apply middleware", {
43
+ provider: context.provider,
44
+ error: error instanceof Error ? error.message : String(error),
45
+ });
46
+ // Return original model on error to maintain functionality
47
+ return model;
48
+ }
49
+ }
50
+ /**
51
+ * Build middleware configuration from factory options
52
+ */
53
+ static buildMiddlewareConfig(options) {
54
+ const config = {};
55
+ // Start with all registered middleware
56
+ const allMiddleware = middlewareRegistry.list();
57
+ for (const middleware of allMiddleware) {
58
+ // Default configuration
59
+ config[middleware.metadata.id] = {
60
+ enabled: middleware.metadata.defaultEnabled || false,
61
+ config: {},
62
+ };
63
+ }
64
+ // Apply preset configuration if specified
65
+ if (options.preset) {
66
+ const presetConfig = this.getPresetConfig(options.preset);
67
+ if (presetConfig) {
68
+ Object.assign(config, presetConfig);
69
+ }
70
+ }
71
+ // Apply explicit middleware configurations
72
+ if (options.middlewareConfig) {
73
+ for (const [middlewareId, middlewareConfig] of Object.entries(options.middlewareConfig)) {
74
+ config[middlewareId] = {
75
+ ...config[middlewareId],
76
+ ...middlewareConfig,
77
+ };
78
+ }
79
+ }
80
+ // Apply enabled middleware list
81
+ if (options.enabledMiddleware) {
82
+ for (const middlewareId of options.enabledMiddleware) {
83
+ if (config[middlewareId]) {
84
+ config[middlewareId].enabled = true;
85
+ }
86
+ }
87
+ }
88
+ // Apply disabled middleware list
89
+ if (options.disabledMiddleware) {
90
+ for (const middlewareId of options.disabledMiddleware) {
91
+ if (config[middlewareId]) {
92
+ config[middlewareId].enabled = false;
93
+ }
94
+ }
95
+ }
96
+ return config;
97
+ }
98
+ /**
99
+ * Get preset configuration
100
+ */
101
+ static getPresetConfig(presetName) {
102
+ const presets = this.getBuiltInPresets();
103
+ return presets[presetName] || null;
104
+ }
105
+ /**
106
+ * Get built-in preset configurations
107
+ */
108
+ static getBuiltInPresets() {
109
+ return {
110
+ // Development preset - logging and basic analytics
111
+ development: {
112
+ logging: { enabled: true },
113
+ analytics: { enabled: true },
114
+ },
115
+ // Production preset - analytics, caching, rate limiting
116
+ production: {
117
+ analytics: { enabled: true },
118
+ caching: { enabled: true },
119
+ rateLimit: { enabled: true },
120
+ retry: { enabled: true },
121
+ },
122
+ // Security preset - guardrails and content filtering
123
+ security: {
124
+ guardrails: { enabled: true },
125
+ logging: { enabled: true },
126
+ rateLimit: { enabled: true },
127
+ },
128
+ // Performance preset - caching and optimization
129
+ performance: {
130
+ caching: { enabled: true },
131
+ retry: { enabled: true },
132
+ timeout: { enabled: true },
133
+ },
134
+ // Enterprise preset - all middleware enabled
135
+ enterprise: {
136
+ analytics: { enabled: true },
137
+ guardrails: { enabled: true },
138
+ logging: { enabled: true },
139
+ caching: { enabled: true },
140
+ rateLimit: { enabled: true },
141
+ retry: { enabled: true },
142
+ timeout: { enabled: true },
143
+ },
144
+ // Minimal preset - only essential middleware
145
+ minimal: {
146
+ analytics: { enabled: true },
147
+ },
148
+ };
149
+ }
150
+ /**
151
+ * Create middleware context from provider and options
152
+ */
153
+ static createContext(provider, model, options = {}, session) {
154
+ return {
155
+ provider,
156
+ model,
157
+ options,
158
+ session,
159
+ metadata: {
160
+ timestamp: Date.now(),
161
+ requestId: `${provider}-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
162
+ },
163
+ };
164
+ }
165
+ /**
166
+ * Validate middleware configuration
167
+ */
168
+ static validateConfig(config) {
169
+ const errors = [];
170
+ const warnings = [];
171
+ for (const [middlewareId, middlewareConfig] of Object.entries(config)) {
172
+ // Check if middleware is registered
173
+ if (!middlewareRegistry.has(middlewareId)) {
174
+ errors.push(`Middleware '${middlewareId}' is not registered`);
175
+ continue;
176
+ }
177
+ // Validate configuration structure
178
+ if (middlewareConfig.enabled !== undefined &&
179
+ typeof middlewareConfig.enabled !== "boolean") {
180
+ errors.push(`Middleware '${middlewareId}' enabled property must be boolean`);
181
+ }
182
+ if (middlewareConfig.config &&
183
+ typeof middlewareConfig.config !== "object") {
184
+ errors.push(`Middleware '${middlewareId}' config property must be an object`);
185
+ }
186
+ // Check for potential conflicts
187
+ if (middlewareConfig.conditions?.providers &&
188
+ middlewareConfig.conditions.providers.length === 0) {
189
+ warnings.push(`Middleware '${middlewareId}' has empty providers condition`);
190
+ }
191
+ }
192
+ return {
193
+ isValid: errors.length === 0,
194
+ errors,
195
+ warnings,
196
+ };
197
+ }
198
+ /**
199
+ * Get available presets
200
+ */
201
+ static getAvailablePresets() {
202
+ return [
203
+ {
204
+ name: "development",
205
+ description: "Logging and basic analytics for development",
206
+ middleware: ["logging", "analytics"],
207
+ },
208
+ {
209
+ name: "production",
210
+ description: "Optimized for production with caching and rate limiting",
211
+ middleware: ["analytics", "caching", "rateLimit", "retry"],
212
+ },
213
+ {
214
+ name: "security",
215
+ description: "Enhanced security with guardrails and monitoring",
216
+ middleware: ["guardrails", "logging", "rateLimit"],
217
+ },
218
+ {
219
+ name: "performance",
220
+ description: "Optimized for performance with caching and retries",
221
+ middleware: ["caching", "retry", "timeout"],
222
+ },
223
+ {
224
+ name: "enterprise",
225
+ description: "Full enterprise feature set with all middleware",
226
+ middleware: [
227
+ "analytics",
228
+ "guardrails",
229
+ "logging",
230
+ "caching",
231
+ "rateLimit",
232
+ "retry",
233
+ "timeout",
234
+ ],
235
+ },
236
+ {
237
+ name: "minimal",
238
+ description: "Minimal overhead with only essential features",
239
+ middleware: ["analytics"],
240
+ },
241
+ ];
242
+ }
243
+ /**
244
+ * Get middleware chain statistics
245
+ */
246
+ static getChainStats(context, config) {
247
+ const chain = middlewareRegistry.buildChain(context, config);
248
+ const stats = middlewareRegistry.getAggregatedStats();
249
+ const results = {};
250
+ let totalExecutionTime = 0;
251
+ let appliedMiddleware = 0;
252
+ for (const [middlewareId, middlewareStats] of Object.entries(stats)) {
253
+ if (config[middlewareId]?.enabled) {
254
+ results[middlewareId] = {
255
+ applied: true,
256
+ executionTime: middlewareStats.averageExecutionTime,
257
+ };
258
+ totalExecutionTime += middlewareStats.averageExecutionTime;
259
+ appliedMiddleware++;
260
+ }
261
+ }
262
+ return {
263
+ totalMiddleware: chain.length,
264
+ appliedMiddleware,
265
+ totalExecutionTime,
266
+ results,
267
+ };
268
+ }
269
+ /**
270
+ * Create a middleware-enabled model factory function
271
+ */
272
+ static createModelFactory(baseModelFactory, defaultOptions = {}) {
273
+ return async (context, options = {}) => {
274
+ // Get base model
275
+ const baseModel = await baseModelFactory();
276
+ // Merge options
277
+ const _mergedOptions = {
278
+ ...defaultOptions,
279
+ ...options,
280
+ middlewareConfig: {
281
+ ...defaultOptions.middlewareConfig,
282
+ ...options.middlewareConfig,
283
+ },
284
+ };
285
+ // Apply middleware
286
+ return this.applyMiddleware(baseModel, context, _mergedOptions);
287
+ };
288
+ }
289
+ }