@superdangerous/app-framework 4.9.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.
- package/LICENSE +21 -0
- package/README.md +652 -0
- package/dist/api/logsRouter.d.ts +20 -0
- package/dist/api/logsRouter.d.ts.map +1 -0
- package/dist/api/logsRouter.js +515 -0
- package/dist/api/logsRouter.js.map +1 -0
- package/dist/cli/dev-server.d.ts +7 -0
- package/dist/cli/dev-server.d.ts.map +1 -0
- package/dist/cli/dev-server.js +640 -0
- package/dist/cli/dev-server.js.map +1 -0
- package/dist/cli/index.d.ts +7 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +26 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/core/StandardServer.d.ts +129 -0
- package/dist/core/StandardServer.d.ts.map +1 -0
- package/dist/core/StandardServer.js +453 -0
- package/dist/core/StandardServer.js.map +1 -0
- package/dist/core/apiResponse.d.ts +69 -0
- package/dist/core/apiResponse.d.ts.map +1 -0
- package/dist/core/apiResponse.js +127 -0
- package/dist/core/apiResponse.js.map +1 -0
- package/dist/core/healthCheck.d.ts +160 -0
- package/dist/core/healthCheck.d.ts.map +1 -0
- package/dist/core/healthCheck.js +398 -0
- package/dist/core/healthCheck.js.map +1 -0
- package/dist/core/index.d.ts +40 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +40 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/logger.d.ts +117 -0
- package/dist/core/logger.d.ts.map +1 -0
- package/dist/core/logger.js +826 -0
- package/dist/core/logger.js.map +1 -0
- package/dist/core/portUtils.d.ts +71 -0
- package/dist/core/portUtils.d.ts.map +1 -0
- package/dist/core/portUtils.js +240 -0
- package/dist/core/portUtils.js.map +1 -0
- package/dist/core/storageService.d.ts +119 -0
- package/dist/core/storageService.d.ts.map +1 -0
- package/dist/core/storageService.js +405 -0
- package/dist/core/storageService.js.map +1 -0
- package/dist/desktop/bundler.d.ts +40 -0
- package/dist/desktop/bundler.d.ts.map +1 -0
- package/dist/desktop/bundler.js +176 -0
- package/dist/desktop/bundler.js.map +1 -0
- package/dist/desktop/index.d.ts +25 -0
- package/dist/desktop/index.d.ts.map +1 -0
- package/dist/desktop/index.js +15 -0
- package/dist/desktop/index.js.map +1 -0
- package/dist/desktop/native-modules.d.ts +66 -0
- package/dist/desktop/native-modules.d.ts.map +1 -0
- package/dist/desktop/native-modules.js +200 -0
- package/dist/desktop/native-modules.js.map +1 -0
- package/dist/index.d.ts +29 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +39 -0
- package/dist/index.js.map +1 -0
- package/dist/logging/LogCategories.d.ts +87 -0
- package/dist/logging/LogCategories.d.ts.map +1 -0
- package/dist/logging/LogCategories.js +205 -0
- package/dist/logging/LogCategories.js.map +1 -0
- package/dist/middleware/aiErrorHandler.d.ts +31 -0
- package/dist/middleware/aiErrorHandler.d.ts.map +1 -0
- package/dist/middleware/aiErrorHandler.js +181 -0
- package/dist/middleware/aiErrorHandler.js.map +1 -0
- package/dist/middleware/auth.d.ts +101 -0
- package/dist/middleware/auth.d.ts.map +1 -0
- package/dist/middleware/auth.js +230 -0
- package/dist/middleware/auth.js.map +1 -0
- package/dist/middleware/cors.d.ts +56 -0
- package/dist/middleware/cors.d.ts.map +1 -0
- package/dist/middleware/cors.js +123 -0
- package/dist/middleware/cors.js.map +1 -0
- package/dist/middleware/errorHandler.d.ts +13 -0
- package/dist/middleware/errorHandler.d.ts.map +1 -0
- package/dist/middleware/errorHandler.js +85 -0
- package/dist/middleware/errorHandler.js.map +1 -0
- package/dist/middleware/fileUpload.d.ts +62 -0
- package/dist/middleware/fileUpload.d.ts.map +1 -0
- package/dist/middleware/fileUpload.js +175 -0
- package/dist/middleware/fileUpload.js.map +1 -0
- package/dist/middleware/health.d.ts +48 -0
- package/dist/middleware/health.d.ts.map +1 -0
- package/dist/middleware/health.js +143 -0
- package/dist/middleware/health.js.map +1 -0
- package/dist/middleware/index.d.ts +20 -0
- package/dist/middleware/index.d.ts.map +1 -0
- package/dist/middleware/index.js +18 -0
- package/dist/middleware/index.js.map +1 -0
- package/dist/middleware/openapi.d.ts +64 -0
- package/dist/middleware/openapi.d.ts.map +1 -0
- package/dist/middleware/openapi.js +258 -0
- package/dist/middleware/openapi.js.map +1 -0
- package/dist/middleware/requestLogging.d.ts +22 -0
- package/dist/middleware/requestLogging.d.ts.map +1 -0
- package/dist/middleware/requestLogging.js +61 -0
- package/dist/middleware/requestLogging.js.map +1 -0
- package/dist/middleware/session.d.ts +84 -0
- package/dist/middleware/session.d.ts.map +1 -0
- package/dist/middleware/session.js +189 -0
- package/dist/middleware/session.js.map +1 -0
- package/dist/middleware/validation.d.ts +1337 -0
- package/dist/middleware/validation.d.ts.map +1 -0
- package/dist/middleware/validation.js +483 -0
- package/dist/middleware/validation.js.map +1 -0
- package/dist/services/aiService.d.ts +180 -0
- package/dist/services/aiService.d.ts.map +1 -0
- package/dist/services/aiService.js +547 -0
- package/dist/services/aiService.js.map +1 -0
- package/dist/services/conversationStorage.d.ts +38 -0
- package/dist/services/conversationStorage.d.ts.map +1 -0
- package/dist/services/conversationStorage.js +158 -0
- package/dist/services/conversationStorage.js.map +1 -0
- package/dist/services/crossPlatformBuffer.d.ts +84 -0
- package/dist/services/crossPlatformBuffer.d.ts.map +1 -0
- package/dist/services/crossPlatformBuffer.js +246 -0
- package/dist/services/crossPlatformBuffer.js.map +1 -0
- package/dist/services/index.d.ts +17 -0
- package/dist/services/index.d.ts.map +1 -0
- package/dist/services/index.js +18 -0
- package/dist/services/index.js.map +1 -0
- package/dist/services/networkService.d.ts +81 -0
- package/dist/services/networkService.d.ts.map +1 -0
- package/dist/services/networkService.js +268 -0
- package/dist/services/networkService.js.map +1 -0
- package/dist/services/queueService.d.ts +112 -0
- package/dist/services/queueService.d.ts.map +1 -0
- package/dist/services/queueService.js +338 -0
- package/dist/services/queueService.js.map +1 -0
- package/dist/services/settingsService.d.ts +135 -0
- package/dist/services/settingsService.d.ts.map +1 -0
- package/dist/services/settingsService.js +425 -0
- package/dist/services/settingsService.js.map +1 -0
- package/dist/services/systemMonitor.d.ts +208 -0
- package/dist/services/systemMonitor.d.ts.map +1 -0
- package/dist/services/systemMonitor.js +693 -0
- package/dist/services/systemMonitor.js.map +1 -0
- package/dist/services/updateService.d.ts +78 -0
- package/dist/services/updateService.d.ts.map +1 -0
- package/dist/services/updateService.js +252 -0
- package/dist/services/updateService.js.map +1 -0
- package/dist/services/websocketEvents.d.ts +372 -0
- package/dist/services/websocketEvents.d.ts.map +1 -0
- package/dist/services/websocketEvents.js +338 -0
- package/dist/services/websocketEvents.js.map +1 -0
- package/dist/services/websocketServer.d.ts +80 -0
- package/dist/services/websocketServer.d.ts.map +1 -0
- package/dist/services/websocketServer.js +299 -0
- package/dist/services/websocketServer.js.map +1 -0
- package/dist/settings/SettingsSchema.d.ts +151 -0
- package/dist/settings/SettingsSchema.d.ts.map +1 -0
- package/dist/settings/SettingsSchema.js +424 -0
- package/dist/settings/SettingsSchema.js.map +1 -0
- package/dist/testing/TestServer.d.ts +69 -0
- package/dist/testing/TestServer.d.ts.map +1 -0
- package/dist/testing/TestServer.js +250 -0
- package/dist/testing/TestServer.js.map +1 -0
- package/dist/types/index.d.ts +137 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +5 -0
- package/dist/types/index.js.map +1 -0
- package/dist/utils/appPaths.d.ts +74 -0
- package/dist/utils/appPaths.d.ts.map +1 -0
- package/dist/utils/appPaths.js +162 -0
- package/dist/utils/appPaths.js.map +1 -0
- package/dist/utils/fs-utils.d.ts +50 -0
- package/dist/utils/fs-utils.d.ts.map +1 -0
- package/dist/utils/fs-utils.js +114 -0
- package/dist/utils/fs-utils.js.map +1 -0
- package/dist/utils/index.d.ts +12 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +10 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/standardConfig.d.ts +61 -0
- package/dist/utils/standardConfig.d.ts.map +1 -0
- package/dist/utils/standardConfig.js +109 -0
- package/dist/utils/standardConfig.js.map +1 -0
- package/dist/utils/startupBanner.d.ts +34 -0
- package/dist/utils/startupBanner.d.ts.map +1 -0
- package/dist/utils/startupBanner.js +169 -0
- package/dist/utils/startupBanner.js.map +1 -0
- package/dist/utils/startupLogger.d.ts +45 -0
- package/dist/utils/startupLogger.d.ts.map +1 -0
- package/dist/utils/startupLogger.js +200 -0
- package/dist/utils/startupLogger.js.map +1 -0
- package/package.json +151 -0
- package/src/api/logsRouter.ts +600 -0
- package/src/cli/dev-server.ts +803 -0
- package/src/cli/index.ts +31 -0
- package/src/core/StandardServer.ts +587 -0
- package/src/core/apiResponse.ts +202 -0
- package/src/core/healthCheck.ts +565 -0
- package/src/core/index.ts +80 -0
- package/src/core/logger.ts +1092 -0
- package/src/core/portUtils.ts +319 -0
- package/src/core/storageService.ts +595 -0
- package/src/desktop/bundler.ts +271 -0
- package/src/desktop/index.ts +18 -0
- package/src/desktop/native-modules.ts +289 -0
- package/src/index.ts +142 -0
- package/src/logging/LogCategories.ts +302 -0
- package/src/middleware/aiErrorHandler.ts +278 -0
- package/src/middleware/auth.ts +329 -0
- package/src/middleware/cors.ts +187 -0
- package/src/middleware/errorHandler.ts +103 -0
- package/src/middleware/fileUpload.ts +252 -0
- package/src/middleware/health.ts +206 -0
- package/src/middleware/index.ts +71 -0
- package/src/middleware/openapi.ts +305 -0
- package/src/middleware/requestLogging.ts +92 -0
- package/src/middleware/session.ts +238 -0
- package/src/middleware/validation.ts +603 -0
- package/src/services/aiService.ts +789 -0
- package/src/services/conversationStorage.ts +232 -0
- package/src/services/crossPlatformBuffer.ts +341 -0
- package/src/services/index.ts +47 -0
- package/src/services/networkService.ts +351 -0
- package/src/services/queueService.ts +446 -0
- package/src/services/settingsService.ts +549 -0
- package/src/services/systemMonitor.ts +936 -0
- package/src/services/updateService.ts +334 -0
- package/src/services/websocketEvents.ts +409 -0
- package/src/services/websocketServer.ts +394 -0
- package/src/settings/SettingsSchema.ts +664 -0
- package/src/testing/TestServer.ts +312 -0
- package/src/types/index.ts +154 -0
- package/src/utils/appPaths.ts +196 -0
- package/src/utils/fs-utils.ts +130 -0
- package/src/utils/index.ts +15 -0
- package/src/utils/standardConfig.ts +178 -0
- package/src/utils/startupBanner.ts +287 -0
- package/src/utils/startupLogger.ts +268 -0
- package/ui/dist/index.d.mts +1221 -0
- package/ui/dist/index.d.ts +1221 -0
- package/ui/dist/index.js +73 -0
- package/ui/dist/index.js.map +1 -0
- package/ui/dist/index.mjs +73 -0
- package/ui/dist/index.mjs.map +1 -0
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Log Categories System
|
|
3
|
+
* Provides a declarative way to define log categories with automatic UI generation
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export interface LogLevel {
|
|
7
|
+
name: "error" | "warn" | "info" | "debug" | "verbose";
|
|
8
|
+
color: string;
|
|
9
|
+
badge: string;
|
|
10
|
+
priority: number;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export const LogLevels: Record<string, LogLevel> = {
|
|
14
|
+
error: {
|
|
15
|
+
name: "error",
|
|
16
|
+
color: "text-red-600 dark:text-red-400",
|
|
17
|
+
badge: "bg-red-600 text-white",
|
|
18
|
+
priority: 0,
|
|
19
|
+
},
|
|
20
|
+
warn: {
|
|
21
|
+
name: "warn",
|
|
22
|
+
color: "text-amber-600 dark:text-amber-400",
|
|
23
|
+
badge: "bg-amber-500 text-white",
|
|
24
|
+
priority: 1,
|
|
25
|
+
},
|
|
26
|
+
info: {
|
|
27
|
+
name: "info",
|
|
28
|
+
color: "text-blue-600 dark:text-blue-400",
|
|
29
|
+
badge: "bg-blue-600 text-white",
|
|
30
|
+
priority: 2,
|
|
31
|
+
},
|
|
32
|
+
debug: {
|
|
33
|
+
name: "debug",
|
|
34
|
+
color: "text-gray-600 dark:text-gray-400",
|
|
35
|
+
badge: "bg-gray-600 text-white",
|
|
36
|
+
priority: 3,
|
|
37
|
+
},
|
|
38
|
+
verbose: {
|
|
39
|
+
name: "verbose",
|
|
40
|
+
color: "text-gray-500 dark:text-gray-500",
|
|
41
|
+
badge: "bg-gray-500 text-white",
|
|
42
|
+
priority: 4,
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
export interface LogCategory {
|
|
47
|
+
id: string;
|
|
48
|
+
label: string;
|
|
49
|
+
description?: string;
|
|
50
|
+
color?: string;
|
|
51
|
+
icon?: string;
|
|
52
|
+
enabled?: boolean;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export interface LogFilter {
|
|
56
|
+
levels?: string[];
|
|
57
|
+
categories?: string[];
|
|
58
|
+
search?: string;
|
|
59
|
+
startDate?: Date;
|
|
60
|
+
endDate?: Date;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export interface LogViewerConfig {
|
|
64
|
+
categories: LogCategory[];
|
|
65
|
+
defaultLevel: string;
|
|
66
|
+
maxLogEntries: number;
|
|
67
|
+
enableRealtime: boolean;
|
|
68
|
+
enableExport: boolean;
|
|
69
|
+
enableArchives: boolean;
|
|
70
|
+
archiveRetentionDays: number;
|
|
71
|
+
horizontalScroll: boolean;
|
|
72
|
+
timestampFormat: string;
|
|
73
|
+
showCategories: boolean;
|
|
74
|
+
showMetadata: boolean;
|
|
75
|
+
theme?: "light" | "dark" | "system";
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Default log viewer configuration
|
|
80
|
+
*/
|
|
81
|
+
export const defaultLogViewerConfig: LogViewerConfig = {
|
|
82
|
+
categories: [
|
|
83
|
+
{
|
|
84
|
+
id: "system",
|
|
85
|
+
label: "System",
|
|
86
|
+
description: "Core system operations",
|
|
87
|
+
enabled: true,
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
id: "api",
|
|
91
|
+
label: "API",
|
|
92
|
+
description: "API requests and responses",
|
|
93
|
+
enabled: true,
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
id: "auth",
|
|
97
|
+
label: "Authentication",
|
|
98
|
+
description: "Authentication and authorization",
|
|
99
|
+
enabled: true,
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
id: "database",
|
|
103
|
+
label: "Database",
|
|
104
|
+
description: "Database operations",
|
|
105
|
+
enabled: true,
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
id: "service",
|
|
109
|
+
label: "Services",
|
|
110
|
+
description: "Background services",
|
|
111
|
+
enabled: true,
|
|
112
|
+
},
|
|
113
|
+
],
|
|
114
|
+
defaultLevel: "info",
|
|
115
|
+
maxLogEntries: 1000,
|
|
116
|
+
enableRealtime: true,
|
|
117
|
+
enableExport: true,
|
|
118
|
+
enableArchives: true,
|
|
119
|
+
archiveRetentionDays: 7,
|
|
120
|
+
horizontalScroll: true,
|
|
121
|
+
timestampFormat: "YYYY-MM-DD HH:mm:ss.SSS",
|
|
122
|
+
showCategories: true,
|
|
123
|
+
showMetadata: true,
|
|
124
|
+
theme: "system",
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Log entry interface
|
|
129
|
+
*/
|
|
130
|
+
export interface LogEntry {
|
|
131
|
+
id: string;
|
|
132
|
+
timestamp: string;
|
|
133
|
+
level: keyof typeof LogLevels;
|
|
134
|
+
category?: string;
|
|
135
|
+
message: string;
|
|
136
|
+
metadata?: Record<string, any>;
|
|
137
|
+
source?: string;
|
|
138
|
+
userId?: string;
|
|
139
|
+
sessionId?: string;
|
|
140
|
+
requestId?: string;
|
|
141
|
+
stack?: string;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Log aggregation for summary statistics
|
|
146
|
+
*/
|
|
147
|
+
export interface LogStats {
|
|
148
|
+
total: number;
|
|
149
|
+
byLevel: Record<string, number>;
|
|
150
|
+
byCategory: Record<string, number>;
|
|
151
|
+
errorRate: number;
|
|
152
|
+
warnRate: number;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Helper to parse log entries from different formats
|
|
157
|
+
*/
|
|
158
|
+
export function parseLogEntry(raw: string | object): LogEntry | null {
|
|
159
|
+
try {
|
|
160
|
+
if (typeof raw === "string") {
|
|
161
|
+
// Try to parse JSON log format
|
|
162
|
+
if (raw.trim().startsWith("{")) {
|
|
163
|
+
return JSON.parse(raw);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Parse text log format: "2023-10-20 10:30:45.123 [INFO] [Category] Message"
|
|
167
|
+
const match = raw.match(
|
|
168
|
+
/^(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d{3})\s+\[(\w+)\]\s+(?:\[([^\]]+)\]\s+)?(.*)$/,
|
|
169
|
+
);
|
|
170
|
+
if (match) {
|
|
171
|
+
const [, timestamp, level, category, message] = match;
|
|
172
|
+
return {
|
|
173
|
+
id: `${Date.now()}-${Math.random()}`,
|
|
174
|
+
timestamp: timestamp || "",
|
|
175
|
+
level: (level?.toLowerCase() || "info") as keyof typeof LogLevels,
|
|
176
|
+
category: category || "",
|
|
177
|
+
message: message || "",
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
} else if (typeof raw === "object") {
|
|
181
|
+
return raw as LogEntry;
|
|
182
|
+
}
|
|
183
|
+
} catch (_error) {
|
|
184
|
+
console.error("Failed to parse log entry:", _error);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
return null;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Helper to format log entries for display
|
|
192
|
+
*/
|
|
193
|
+
export function formatLogEntry(
|
|
194
|
+
entry: LogEntry,
|
|
195
|
+
format: "full" | "compact" = "full",
|
|
196
|
+
): string {
|
|
197
|
+
if (format === "compact") {
|
|
198
|
+
return `${entry.timestamp} [${entry.level.toUpperCase()}] ${entry.message}`;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
let formatted = `${entry.timestamp} [${entry.level.toUpperCase()}]`;
|
|
202
|
+
if (entry.category) {
|
|
203
|
+
formatted += ` [${entry.category}]`;
|
|
204
|
+
}
|
|
205
|
+
formatted += ` ${entry.message}`;
|
|
206
|
+
|
|
207
|
+
if (entry.metadata && Object.keys(entry.metadata).length > 0) {
|
|
208
|
+
formatted += "\n Metadata: " + JSON.stringify(entry.metadata, null, 2);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
if (entry.stack) {
|
|
212
|
+
formatted += "\n Stack: " + entry.stack;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
return formatted;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Calculate log statistics
|
|
220
|
+
*/
|
|
221
|
+
export function calculateLogStats(entries: LogEntry[]): LogStats {
|
|
222
|
+
const stats: LogStats = {
|
|
223
|
+
total: entries.length,
|
|
224
|
+
byLevel: {},
|
|
225
|
+
byCategory: {},
|
|
226
|
+
errorRate: 0,
|
|
227
|
+
warnRate: 0,
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
for (const entry of entries) {
|
|
231
|
+
// Count by level
|
|
232
|
+
stats.byLevel[entry.level] = (stats.byLevel[entry.level] || 0) + 1;
|
|
233
|
+
|
|
234
|
+
// Count by category
|
|
235
|
+
if (entry.category) {
|
|
236
|
+
stats.byCategory[entry.category] =
|
|
237
|
+
(stats.byCategory[entry.category] || 0) + 1;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// Calculate rates
|
|
242
|
+
if (stats.total > 0) {
|
|
243
|
+
stats.errorRate = (stats.byLevel.error || 0) / stats.total;
|
|
244
|
+
stats.warnRate = (stats.byLevel.warn || 0) / stats.total;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
return stats;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* Filter log entries
|
|
252
|
+
*/
|
|
253
|
+
export function filterLogEntries(
|
|
254
|
+
entries: LogEntry[],
|
|
255
|
+
filter: LogFilter,
|
|
256
|
+
): LogEntry[] {
|
|
257
|
+
return entries.filter((entry) => {
|
|
258
|
+
// Filter by level
|
|
259
|
+
if (
|
|
260
|
+
filter.levels &&
|
|
261
|
+
filter.levels.length > 0 &&
|
|
262
|
+
!filter.levels.includes(entry.level)
|
|
263
|
+
) {
|
|
264
|
+
return false;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// Filter by category
|
|
268
|
+
if (
|
|
269
|
+
filter.categories &&
|
|
270
|
+
filter.categories.length > 0 &&
|
|
271
|
+
entry.category &&
|
|
272
|
+
!filter.categories.includes(entry.category)
|
|
273
|
+
) {
|
|
274
|
+
return false;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// Filter by search term
|
|
278
|
+
if (filter.search) {
|
|
279
|
+
const searchLower = filter.search.toLowerCase();
|
|
280
|
+
const inMessage = entry.message.toLowerCase().includes(searchLower);
|
|
281
|
+
const inCategory = entry.category?.toLowerCase().includes(searchLower);
|
|
282
|
+
const inMetadata = entry.metadata
|
|
283
|
+
? JSON.stringify(entry.metadata).toLowerCase().includes(searchLower)
|
|
284
|
+
: false;
|
|
285
|
+
|
|
286
|
+
if (!inMessage && !inCategory && !inMetadata) {
|
|
287
|
+
return false;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// Filter by date range
|
|
292
|
+
const entryDate = new Date(entry.timestamp);
|
|
293
|
+
if (filter.startDate && entryDate < filter.startDate) {
|
|
294
|
+
return false;
|
|
295
|
+
}
|
|
296
|
+
if (filter.endDate && entryDate > filter.endDate) {
|
|
297
|
+
return false;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
return true;
|
|
301
|
+
});
|
|
302
|
+
}
|
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AI Error Handler Middleware
|
|
3
|
+
* Provides user-friendly error messages for AI API errors
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { Request, Response, NextFunction } from "express";
|
|
7
|
+
import { createLogger } from "../core/index.js";
|
|
8
|
+
import { ApiResponse } from "../types/index.js";
|
|
9
|
+
import { sendError, sendUnauthorized } from "../core/apiResponse.js";
|
|
10
|
+
import { AIError } from "../services/aiService.js";
|
|
11
|
+
|
|
12
|
+
let logger: any; // Will be initialized when needed
|
|
13
|
+
|
|
14
|
+
function ensureLogger() {
|
|
15
|
+
if (!logger) {
|
|
16
|
+
logger = createLogger("AIError");
|
|
17
|
+
}
|
|
18
|
+
return logger;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
interface AIErrorResponse {
|
|
22
|
+
error: string;
|
|
23
|
+
details?: string[];
|
|
24
|
+
action?: string;
|
|
25
|
+
retryAfter?: number;
|
|
26
|
+
code?: string;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* AI-specific error handler middleware
|
|
31
|
+
*/
|
|
32
|
+
export function aiErrorHandler(
|
|
33
|
+
err: any,
|
|
34
|
+
_req: Request,
|
|
35
|
+
res: Response<ApiResponse<any>>,
|
|
36
|
+
next: NextFunction,
|
|
37
|
+
): void {
|
|
38
|
+
// Only handle AI-related errors
|
|
39
|
+
if (!_req.path.startsWith("/api/ai/")) {
|
|
40
|
+
return next(err);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
ensureLogger().error("AI Error:", {
|
|
44
|
+
path: _req.path,
|
|
45
|
+
method: _req.method,
|
|
46
|
+
error: err.message,
|
|
47
|
+
status: err.statusCode || err.status,
|
|
48
|
+
stack: err.stack,
|
|
49
|
+
errorType: err.errorType,
|
|
50
|
+
provider: err.provider,
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
// Handle our custom AIError instances
|
|
54
|
+
if (err instanceof AIError) {
|
|
55
|
+
const response: AIErrorResponse = {
|
|
56
|
+
error: err.message,
|
|
57
|
+
code: err.errorType,
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
// Add provider-specific information
|
|
61
|
+
if (err.provider) {
|
|
62
|
+
response.details = [`Provider: ${err.provider}`];
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Handle specific error types
|
|
66
|
+
switch (err.errorType) {
|
|
67
|
+
case "AUTH_ERROR":
|
|
68
|
+
sendUnauthorized(res, err.message);
|
|
69
|
+
return;
|
|
70
|
+
case "RATE_LIMIT":
|
|
71
|
+
sendError(res, err.message, 429, { retryAfter: 60 });
|
|
72
|
+
return;
|
|
73
|
+
case "SERVICE_UNAVAILABLE":
|
|
74
|
+
sendError(res, err.message, 503);
|
|
75
|
+
return;
|
|
76
|
+
case "TIMEOUT":
|
|
77
|
+
sendError(res, err.message, 408);
|
|
78
|
+
return;
|
|
79
|
+
default:
|
|
80
|
+
sendError(res, err.message, err.statusCode, response);
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Handle legacy structured AI errors with user-friendly messages
|
|
86
|
+
if (err.userMessage) {
|
|
87
|
+
const response: AIErrorResponse = {
|
|
88
|
+
error: err.userMessage,
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
if (err.details) {
|
|
92
|
+
response.details = err.details;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (err.actionRequired) {
|
|
96
|
+
response.action = err.actionRequired;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (err.code) {
|
|
100
|
+
response.code = err.code;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
sendError(res, err.userMessage, err.status || 500, {
|
|
104
|
+
details: err.details,
|
|
105
|
+
action: err.actionRequired,
|
|
106
|
+
code: err.code,
|
|
107
|
+
});
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Handle OpenAI specific errors
|
|
112
|
+
if (err.message && err.message.includes("401")) {
|
|
113
|
+
sendUnauthorized(
|
|
114
|
+
res,
|
|
115
|
+
"OpenAI API authentication failed: Invalid or missing API key. Check your OpenAI API key configuration",
|
|
116
|
+
);
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (err.message && err.message.includes("429")) {
|
|
121
|
+
sendError(
|
|
122
|
+
res,
|
|
123
|
+
"OpenAI API rate limit exceeded: Too many requests. Please wait a moment before trying again",
|
|
124
|
+
429,
|
|
125
|
+
);
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
if (err.message && err.message.includes("insufficient_quota")) {
|
|
130
|
+
sendError(
|
|
131
|
+
res,
|
|
132
|
+
"OpenAI API quota exceeded: Your account has insufficient quota. Check your OpenAI account billing and usage limits",
|
|
133
|
+
402,
|
|
134
|
+
);
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// Handle Anthropic specific errors
|
|
139
|
+
if (err.message && err.message.includes("anthropic")) {
|
|
140
|
+
if (err.message.includes("401")) {
|
|
141
|
+
sendUnauthorized(
|
|
142
|
+
res,
|
|
143
|
+
"Anthropic API authentication failed: Invalid or missing API key",
|
|
144
|
+
);
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
if (err.message.includes("rate")) {
|
|
149
|
+
sendError(
|
|
150
|
+
res,
|
|
151
|
+
"Anthropic API rate limit exceeded: Too many requests",
|
|
152
|
+
429,
|
|
153
|
+
);
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// Handle JSON parse errors
|
|
159
|
+
if (err.message && err.message.includes("JSON")) {
|
|
160
|
+
sendError(
|
|
161
|
+
res,
|
|
162
|
+
"Failed to generate valid template format: The AI response was not in the expected format",
|
|
163
|
+
500,
|
|
164
|
+
);
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// Handle missing required fields
|
|
169
|
+
if (err.message && err.message.includes("missing required fields")) {
|
|
170
|
+
sendError(
|
|
171
|
+
res,
|
|
172
|
+
"Generated template is incomplete: Missing required fields",
|
|
173
|
+
500,
|
|
174
|
+
);
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// Handle API key errors
|
|
179
|
+
if (err.message && err.message.includes("API key")) {
|
|
180
|
+
sendUnauthorized(
|
|
181
|
+
res,
|
|
182
|
+
"AI API key not configured: Please configure your API key",
|
|
183
|
+
);
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// Handle timeout errors
|
|
188
|
+
if (
|
|
189
|
+
err.message &&
|
|
190
|
+
(err.message.includes("timeout") || err.message.includes("ETIMEDOUT"))
|
|
191
|
+
) {
|
|
192
|
+
sendError(
|
|
193
|
+
res,
|
|
194
|
+
"AI request timed out: The request took too long to complete",
|
|
195
|
+
504,
|
|
196
|
+
);
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// Handle network errors
|
|
201
|
+
if (
|
|
202
|
+
err.message &&
|
|
203
|
+
(err.message.includes("ECONNREFUSED") || err.message.includes("ENOTFOUND"))
|
|
204
|
+
) {
|
|
205
|
+
sendError(res, "AI service unavailable: Cannot connect to AI service", 503);
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// Default error response
|
|
210
|
+
sendError(
|
|
211
|
+
res,
|
|
212
|
+
err.message || "An error occurred while processing your AI request",
|
|
213
|
+
err.status || 500,
|
|
214
|
+
);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Rate limit handler for AI endpoints
|
|
219
|
+
*/
|
|
220
|
+
export function aiRateLimitHandler(
|
|
221
|
+
_req: Request,
|
|
222
|
+
res: Response<ApiResponse<any>>,
|
|
223
|
+
): void {
|
|
224
|
+
sendError(
|
|
225
|
+
res,
|
|
226
|
+
"Too many AI requests: Rate limit exceeded. Please wait a moment before trying again",
|
|
227
|
+
429,
|
|
228
|
+
);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Create AI error with user-friendly message
|
|
233
|
+
*/
|
|
234
|
+
export function createAIError(
|
|
235
|
+
message: string,
|
|
236
|
+
userMessage: string,
|
|
237
|
+
status: number = 500,
|
|
238
|
+
details?: string[],
|
|
239
|
+
action?: string,
|
|
240
|
+
): AIError {
|
|
241
|
+
const error = new AIError(message, status, "CUSTOM_ERROR", "unknown");
|
|
242
|
+
// Additional legacy properties for compatibility
|
|
243
|
+
(error as any).userMessage = userMessage;
|
|
244
|
+
(error as any).details = details;
|
|
245
|
+
(error as any).actionRequired = action;
|
|
246
|
+
return error;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Wrap async AI handlers with error handling
|
|
251
|
+
*/
|
|
252
|
+
export function wrapAIHandler(
|
|
253
|
+
handler: (req: Request, res: Response, next: NextFunction) => Promise<void>,
|
|
254
|
+
) {
|
|
255
|
+
return async (req: Request, res: Response, next: NextFunction) => {
|
|
256
|
+
try {
|
|
257
|
+
await handler(req, res, next);
|
|
258
|
+
} catch (_error: any) {
|
|
259
|
+
// Convert to AI error if needed
|
|
260
|
+
if (!_error.userMessage && _error.response?.data) {
|
|
261
|
+
// Handle API response errors
|
|
262
|
+
const apiError = _error.response.data;
|
|
263
|
+
_error.userMessage =
|
|
264
|
+
apiError.error?.message || apiError.message || "AI request failed";
|
|
265
|
+
_error.status = _error.response.status;
|
|
266
|
+
_error.details = apiError.error?.details || [apiError.error?.type];
|
|
267
|
+
}
|
|
268
|
+
next(_error);
|
|
269
|
+
}
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
export default {
|
|
274
|
+
aiErrorHandler,
|
|
275
|
+
aiRateLimitHandler,
|
|
276
|
+
createAIError,
|
|
277
|
+
wrapAIHandler,
|
|
278
|
+
};
|