xypriss 9.7.4 → 9.7.6

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 (62) hide show
  1. package/dist/cjs/src/middleware/built-in/BuiltInMiddleware.js +1 -1
  2. package/dist/cjs/src/middleware/built-in/BuiltInMiddleware.js.map +1 -1
  3. package/dist/cjs/src/plugins/builtin/RouteOptimizationPlugin.js +1 -1
  4. package/dist/cjs/src/plugins/core/manager/PluginSecurity.js +55 -57
  5. package/dist/cjs/src/plugins/core/manager/PluginSecurity.js.map +1 -1
  6. package/dist/cjs/src/plugins/types/PluginTypes.js.map +1 -1
  7. package/dist/cjs/src/server/FastServer/LogTracingMethods.js +21 -18
  8. package/dist/cjs/src/server/FastServer/LogTracingMethods.js.map +1 -1
  9. package/dist/cjs/src/server/FastServer/index.js +4 -2
  10. package/dist/cjs/src/server/FastServer/index.js.map +1 -1
  11. package/dist/cjs/src/server/components/fastapi/MonitoringManager.js +1 -1
  12. package/dist/cjs/src/server/components/fastapi/RouteManager.js +1 -1
  13. package/dist/cjs/src/server/components/fastapi/console/ConsoleInterceptor.js +63 -923
  14. package/dist/cjs/src/server/components/fastapi/console/ConsoleInterceptor.js.map +1 -1
  15. package/dist/cjs/src/server/components/fastapi/console/types.js +6 -108
  16. package/dist/cjs/src/server/components/fastapi/console/types.js.map +1 -1
  17. package/dist/cjs/src/server/core/StartupProcessor.js +1 -1
  18. package/dist/cjs/src/server/core/StartupProcessor.js.map +1 -1
  19. package/dist/cjs/src/server/core/XHSCBridge/LogProcessor.js +19 -5
  20. package/dist/cjs/src/server/core/XHSCBridge/LogProcessor.js.map +1 -1
  21. package/dist/cjs/src/server/core/XHSCBridge/index.js +4 -1
  22. package/dist/cjs/src/server/core/XHSCBridge/index.js.map +1 -1
  23. package/dist/cjs/src/server/core/XyLifecycleManager.js +8 -0
  24. package/dist/cjs/src/server/core/XyLifecycleManager.js.map +1 -1
  25. package/dist/cjs/src/server/core/XyprissApp.js +3 -2
  26. package/dist/cjs/src/server/core/XyprissApp.js.map +1 -1
  27. package/dist/cjs/src/shared/logger/DEFAULT_LOGGER_CONFIG.js +1 -2
  28. package/dist/cjs/src/shared/logger/DEFAULT_LOGGER_CONFIG.js.map +1 -1
  29. package/dist/cjs/src/shared/logger/Logger.js +38 -0
  30. package/dist/cjs/src/shared/logger/Logger.js.map +1 -1
  31. package/dist/esm/src/middleware/built-in/BuiltInMiddleware.js +1 -1
  32. package/dist/esm/src/middleware/built-in/BuiltInMiddleware.js.map +1 -1
  33. package/dist/esm/src/plugins/builtin/RouteOptimizationPlugin.js +1 -1
  34. package/dist/esm/src/plugins/core/manager/PluginSecurity.js +55 -57
  35. package/dist/esm/src/plugins/core/manager/PluginSecurity.js.map +1 -1
  36. package/dist/esm/src/plugins/types/PluginTypes.js.map +1 -1
  37. package/dist/esm/src/server/FastServer/LogTracingMethods.js +21 -18
  38. package/dist/esm/src/server/FastServer/LogTracingMethods.js.map +1 -1
  39. package/dist/esm/src/server/FastServer/index.js +4 -2
  40. package/dist/esm/src/server/FastServer/index.js.map +1 -1
  41. package/dist/esm/src/server/components/fastapi/MonitoringManager.js +1 -1
  42. package/dist/esm/src/server/components/fastapi/RouteManager.js +1 -1
  43. package/dist/esm/src/server/components/fastapi/console/ConsoleInterceptor.js +64 -924
  44. package/dist/esm/src/server/components/fastapi/console/ConsoleInterceptor.js.map +1 -1
  45. package/dist/esm/src/server/components/fastapi/console/types.js +7 -108
  46. package/dist/esm/src/server/components/fastapi/console/types.js.map +1 -1
  47. package/dist/esm/src/server/core/StartupProcessor.js +1 -1
  48. package/dist/esm/src/server/core/StartupProcessor.js.map +1 -1
  49. package/dist/esm/src/server/core/XHSCBridge/LogProcessor.js +19 -5
  50. package/dist/esm/src/server/core/XHSCBridge/LogProcessor.js.map +1 -1
  51. package/dist/esm/src/server/core/XHSCBridge/index.js +4 -1
  52. package/dist/esm/src/server/core/XHSCBridge/index.js.map +1 -1
  53. package/dist/esm/src/server/core/XyLifecycleManager.js +8 -0
  54. package/dist/esm/src/server/core/XyLifecycleManager.js.map +1 -1
  55. package/dist/esm/src/server/core/XyprissApp.js +3 -2
  56. package/dist/esm/src/server/core/XyprissApp.js.map +1 -1
  57. package/dist/esm/src/shared/logger/DEFAULT_LOGGER_CONFIG.js +1 -2
  58. package/dist/esm/src/shared/logger/DEFAULT_LOGGER_CONFIG.js.map +1 -1
  59. package/dist/esm/src/shared/logger/Logger.js +38 -0
  60. package/dist/esm/src/shared/logger/Logger.js.map +1 -1
  61. package/dist/index.d.ts +38 -90
  62. package/package.json +4 -49
@@ -1,96 +1,23 @@
1
1
  'use strict';
2
2
 
3
3
  var types = require('./types.js');
4
- var ConsoleEncryption = require('./encryption/ConsoleEncryption.js');
5
- var xyprissSecurity = require('xypriss-security');
4
+ var XHSCDirectIPC = require('../../../../xhsc/ipc/XHSCDirectIPC.js');
6
5
 
7
6
  /***************************************************************************
8
- * ConsoleInterceptor.ts - Console Interception System for FastXyPrissServer
9
- * This file contains the ConsoleInterceptor class, which intercepts and manages all console output through the unified logging system
10
- * @author Nehonix
11
- * @license NehoPSLA - PROPRIETARY SOFTWARE
12
- * @version 1.0
13
- * @copyright Copyright (c) 2025 Nehonix. All rights reserved.
14
- *
15
- * PROPRIETARY AND CONFIDENTIAL
16
- *
17
- * This software is the proprietary information of NEHONIX and is protected
18
- * by copyright law and international treaties. Unauthorized reproduction,
19
- * distribution, modification, or use of this software is strictly prohibited
20
- * and may result in severe civil and criminal penalties.
21
- *
22
- * Licensed under the NEHO Proprietary Software License Agreement (NehoPSLA).
23
- * See LICENSE.md for full terms and conditions.
24
- * Official License: http://dll.nehonix.com/NehoPSLA/license
25
- *
26
- * ACCESS RESTRICTIONS:
27
- * - This software is exclusively for use by Authorized Personnel of NEHONIX
28
- * - Intended for Internal Use only within NEHONIX operations
29
- * - No rights granted to unauthorized individuals or entities
30
- * - All modifications are works made for hire assigned to NEHONIX
31
- *
32
- * PROHIBITED ACTIVITIES:
33
- * - Copying, distributing, or sublicensing without written permission
34
- * - Reverse engineering, decompiling, or disassembling
35
- * - Creating derivative works without explicit authorization
36
- * - External use or commercial distribution outside NEHONIX
37
- *
38
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
39
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
40
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
41
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
42
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
43
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
44
- * SOFTWARE.
45
- *
46
- * For questions or permissions, contact:
47
- * NEHONIX Legal Department
48
- * Email: legal@nehonix.com
49
- * Website: www.nehonix.com
50
- ***************************************************************************** */
7
+ * ConsoleInterceptor.ts - Lightweight Console Interception System
8
+ * Delegated to XHSC (Go) for heavy lifting
9
+ *************************************************************************** */
51
10
  /**
52
- * Console Interception System (CSIS) for FastXyPrissServer
53
- * Intercepts and manages all console output through the unified logging system
11
+ * Lightweight Console Interception System (CSIS)
12
+ * When useNative is enabled, it delegates all filtering and encryption to XHSC (Go).
54
13
  */
55
14
  class ConsoleInterceptor {
56
15
  constructor(logger, config) {
57
- this.originalConsole = {};
58
16
  this.isIntercepting = false;
59
- this.errorCount = 0;
60
- this.lastSecondInterceptions = 0;
61
- this.lastSecondTimestamp = 0;
62
- this.performanceBuffer = [];
63
- // Rate limiting
64
- this.rateLimitCounter = 0;
65
- this.rateLimitWindow = Date.now();
66
- // Recursion prevention
67
- this.isProcessing = false;
68
- this.processingDepth = 0;
69
- this.maxProcessingDepth = 3;
70
- // Encryption handler
71
- this.encryptionHandler = null;
72
- // Tracing
73
- this.traceBuffer = [];
74
- this.traceHooks = [];
75
- this.pluginEngine = null;
76
17
  this.logger = logger;
77
- // Merge with user configuration
78
- const userConfig = config?.consoleInterception || {};
79
18
  this.config = {
80
19
  ...types.DEFAULT_CONSOLE_CONFIG,
81
- ...userConfig,
82
- filters: {
83
- ...types.DEFAULT_CONSOLE_CONFIG.filters,
84
- ...userConfig.filters,
85
- },
86
- fallback: {
87
- ...types.DEFAULT_CONSOLE_CONFIG.fallback,
88
- ...userConfig.fallback,
89
- },
90
- tracing: {
91
- ...types.DEFAULT_CONSOLE_CONFIG.tracing,
92
- ...userConfig.tracing,
93
- },
20
+ ...(config?.consoleInterception || {}),
94
21
  };
95
22
  this.stats = {
96
23
  totalInterceptions: 0,
@@ -101,878 +28,91 @@ class ConsoleInterceptor {
101
28
  averageOverhead: 0,
102
29
  isActive: false,
103
30
  };
104
- // Initialize method counts
105
- this.config.interceptMethods.forEach((method) => {
106
- this.stats.methodCounts[method] = 0;
107
- });
108
- // Parse preserve option configuration
109
- this.preserveOption = this.parsePreserveOption(this.config.preserveOriginal);
110
- // Initialize encryption handler if encryption is enabled
111
- this.initializeEncryptionHandler();
31
+ this.ipcPath = process.env.XYPRISS_IPC_PATH;
112
32
  }
113
- /**
114
- * Parse preserve option configuration
115
- * Supports both boolean (backward compatibility) and object configuration
116
- */
117
- parsePreserveOption(preserveOriginal) {
118
- // If it's already a PreserveOption object, use it
119
- if (typeof preserveOriginal === "object" && preserveOriginal !== null) {
120
- return {
121
- ...preserveOriginal, // Use user settings
122
- enabled: preserveOriginal.enabled ?? true,
123
- mode: preserveOriginal.mode ?? "original",
124
- showPrefix: preserveOriginal.showPrefix ?? false,
125
- allowDuplication: preserveOriginal.allowDuplication ?? false,
126
- separateStreams: preserveOriginal.separateStreams ?? false,
127
- onlyUserApp: preserveOriginal.onlyUserApp ?? true,
128
- colorize: preserveOriginal.colorize ?? true,
129
- };
130
- }
131
- // Backward compatibility: convert boolean to PreserveOption
132
- if (preserveOriginal === true) {
133
- // preserveOriginal: true = show original console output only
134
- return types.PRESERVE_PRESETS.development;
135
- }
136
- else {
137
- // preserveOriginal: false = route through logging system
138
- return types.PRESERVE_PRESETS.production;
139
- }
140
- }
141
- /**
142
- * Initialize encryption handler
143
- */
144
- initializeEncryptionHandler() {
145
- if (this.config.encryption?.enabled && this.config.encryption.key) {
146
- try {
147
- this.encryptionHandler = new ConsoleEncryption.ConsoleEncryption(this.config.encryption);
148
- this.logger.info("console", "Console encryption handler initialized");
149
- }
150
- catch (error) {
151
- this.logger.error("console", "Failed to initialize encryption handler", error);
152
- this.encryptionHandler = null;
153
- }
154
- }
155
- else {
156
- this.encryptionHandler = null;
157
- }
158
- }
159
- /**
160
- * Start console interception
161
- */
162
- start() {
33
+ async start() {
163
34
  if (!this.config.enabled || this.isIntercepting) {
164
35
  return;
165
36
  }
166
- try {
167
- this.logger.info("console", "Starting console interception system");
168
- this.backupOriginalConsole();
169
- this.interceptConsoleMethods();
170
- this.isIntercepting = true;
171
- this.stats.isActive = true;
172
- this.logger.info("console", "Console interception system started successfully");
173
- }
174
- catch (error) {
175
- this.handleError("Failed to start console interception", error);
176
- }
177
- }
178
- /**
179
- * Stop console interception and restore original console
180
- */
181
- stop() {
182
- if (!this.isIntercepting) {
183
- return;
184
- }
185
- try {
186
- this.logger.info("console", "Stopping console interception system");
187
- this.restoreOriginalConsole();
188
- this.isIntercepting = false;
189
- this.stats.isActive = false;
190
- this.logger.info("console", "Console interception system stopped");
191
- }
192
- catch (error) {
193
- this.handleError("Failed to stop console interception", error);
194
- }
195
- }
196
- /**
197
- * Get current interception statistics
198
- */
199
- getStats() {
200
- return { ...this.stats };
201
- }
202
- /**
203
- * Update configuration at runtime
204
- */
205
- updateConfig(newConfig) {
206
- // Merge configurations properly
207
- this.config = {
208
- ...this.config,
209
- ...newConfig,
210
- filters: {
211
- ...this.config.filters,
212
- ...(newConfig.filters || {}),
213
- },
214
- fallback: {
215
- ...this.config.fallback,
216
- ...(newConfig.fallback || {}),
217
- },
218
- };
219
- if (this.isIntercepting) {
220
- this.stop();
221
- this.start();
222
- }
223
- }
224
- /**
225
- * Backup original console methods
226
- */
227
- backupOriginalConsole() {
228
- this.config.interceptMethods.forEach((method) => {
229
- const consoleMethod = console[method];
230
- if (typeof consoleMethod === "function") {
231
- this.originalConsole[method] = consoleMethod.bind(console);
232
- }
233
- });
234
- }
235
- /**
236
- * Restore original console methods
237
- */
238
- restoreOriginalConsole() {
239
- Object.keys(this.originalConsole).forEach((method) => {
240
- console[method] = this.originalConsole[method];
241
- });
242
- }
243
- /**
244
- * Intercept console methods
245
- */
246
- interceptConsoleMethods() {
247
- this.config.interceptMethods.forEach((method) => {
248
- const originalMethod = this.originalConsole[method];
249
- if (!originalMethod)
250
- return;
251
- console[method] = (...args) => {
252
- this.handleInterceptedCall(method, args, originalMethod);
253
- };
254
- });
255
- }
256
- /**
257
- * Handle intercepted console call
258
- */
259
- handleInterceptedCall(method, args, originalMethod) {
260
- // Prevent recursion - if we're already processing, just call original
261
- if (this.isProcessing ||
262
- this.processingDepth >= this.maxProcessingDepth) {
263
- originalMethod(...args);
264
- return;
265
- }
266
- // Set recursion guards
267
- this.isProcessing = true;
268
- this.processingDepth++;
269
- const startTime = this.config.performanceMode ? performance.now() : 0;
270
- try {
271
- // Rate limiting check
272
- if (!this.checkRateLimit()) {
273
- this.handlePreserveDisplay(originalMethod, args);
274
- return;
275
- }
276
- // 🔧 CRITICAL FIX: Prevent recursion by ignoring logs that already have our prefixes
277
- // If it's already a formatted system log, output it directly and exit
278
- const message = args.join(" ");
279
- if (message.includes("[USERAPP]") ||
280
- message.includes("[SYSTEM]") ||
281
- message.includes("[SERVER]")) {
282
- originalMethod(...args);
283
- return;
284
- }
285
- // Create intercepted call object
286
- const interceptedCall = {
287
- method,
288
- args,
289
- timestamp: Date.now(),
290
- level: this.mapMethodToLogLevel(method),
291
- };
292
- // Classify the call
293
- this.classifyCall(interceptedCall);
294
- // Add source mapping if enabled
295
- if (this.config.sourceMapping || this.config.stackTrace) {
296
- this.addSourceInformation(interceptedCall);
297
- }
298
- // Filter the call
299
- if (!this.shouldInterceptCall(interceptedCall)) {
300
- this.handlePreserveDisplay(originalMethod, args);
301
- return;
302
- }
303
- // Process the intercepted call (async but don't wait to avoid blocking)
304
- this.processInterceptedCall(interceptedCall).catch((error) => {
305
- this.handleError("Error in async processing", error);
306
- });
307
- // Handle preserve display based on new preserve option
308
- this.handlePreserveDisplay(originalMethod, args);
309
- // 🔍 Handle tracing if enabled
310
- if (this.config.tracing?.enabled) {
311
- this.addToTraceBuffer(interceptedCall);
312
- this.triggerTraceHooks(interceptedCall);
37
+ if (this.ipcPath) {
38
+ try {
39
+ const ipc = new XHSCDirectIPC.XHSCDirectIPC(this.ipcPath);
40
+ await ipc.sendCommand("console", "update-config", this.config);
41
+ ipc.close();
42
+ this.logger.info("console", "Native XHSC console interception activated via IPC");
43
+ this.isIntercepting = true;
44
+ this.stats.isActive = true;
313
45
  }
314
- // Update statistics
315
- this.updateStats(method, startTime);
316
- }
317
- catch (error) {
318
- this.handleError(`Error processing intercepted ${method} call`, error);
319
- // Fallback to original method
320
- this.handlePreserveDisplay(originalMethod, args);
321
- }
322
- finally {
323
- // Always reset recursion guards
324
- this.processingDepth--;
325
- if (this.processingDepth <= 0) {
326
- this.isProcessing = false;
327
- this.processingDepth = 0;
46
+ catch (err) {
47
+ this.logger.error("console", `Failed to activate native interception: ${err.message}`);
328
48
  }
329
49
  }
330
- }
331
- /**
332
- * Handle preserve display based on preserve option configuration
333
- */
334
- handlePreserveDisplay(originalMethod, args) {
335
- if (!this.preserveOption.enabled) {
336
- return;
337
- }
338
- const mode = this.preserveOption.mode;
339
- switch (mode) {
340
- case "original":
341
- // Show original console output only
342
- originalMethod(...args);
343
- break;
344
- case "intercepted":
345
- // Will be handled by processInterceptedCall routing to logger
346
- break;
347
- case "both":
348
- // Show both original and intercepted (for debugging)
349
- // Always show original when mode is "both"
350
- originalMethod(...args);
351
- break;
352
- case "none":
353
- // No console output at all
354
- break;
355
- default:
356
- // Fallback to original
357
- originalMethod(...args);
358
- break;
359
- }
360
- }
361
- /**
362
- * Determine if logs should be routed to logger system
363
- */
364
- shouldRouteToLogger() {
365
- if (!this.preserveOption.enabled) {
366
- return false;
367
- }
368
- const mode = this.preserveOption.mode;
369
- return mode === "intercepted" || mode === "both";
370
- }
371
- /**
372
- * Check rate limiting
373
- */
374
- checkRateLimit() {
375
- const now = Date.now();
376
- const windowSize = 1000; // 1 second
377
- // Reset counter if we're in a new window
378
- if (now - this.rateLimitWindow >= windowSize) {
379
- this.rateLimitCounter = 0;
380
- this.rateLimitWindow = now;
381
- }
382
- this.rateLimitCounter++;
383
- return this.rateLimitCounter <= this.config.maxInterceptionsPerSecond;
384
- }
385
- /**
386
- * Map console method to log level
387
- */
388
- mapMethodToLogLevel(method) {
389
- switch (method) {
390
- case "error":
391
- return "error";
392
- case "warn":
393
- return "warn";
394
- case "info":
395
- return "info";
396
- case "debug":
397
- return "debug";
398
- case "log":
399
- default:
400
- return "info";
50
+ else {
51
+ this.logger.warn("console", "XYPRISS_IPC_PATH not set — native interception unavailable");
401
52
  }
402
53
  }
403
- /**
404
- * Add source information to intercepted call
405
- */
406
- addSourceInformation(call) {
407
- if (!this.config.sourceMapping && !this.config.stackTrace)
54
+ async stop() {
55
+ if (!this.isIntercepting)
408
56
  return;
409
- try {
410
- const stack = new Error().stack;
411
- if (stack) {
412
- const lines = stack.split("\n");
413
- // Skip the first few lines (Error, this method, handleInterceptedCall)
414
- const relevantLine = lines.find((line, index) => index > 3 &&
415
- !line.includes("ConsoleInterceptor") &&
416
- !line.includes("node_modules"));
417
- if (this.config.sourceMapping && relevantLine) {
418
- call.source = relevantLine.trim();
419
- }
420
- if (this.config.stackTrace) {
421
- call.stackTrace = lines.slice(4).join("\n");
422
- }
423
- }
424
- }
425
- catch (error) {
426
- // Silently ignore source mapping errors
427
- }
428
- }
429
- /**
430
- * Check if a message matches exclude patterns (supports regex and strings)
431
- */
432
- matchesExcludePattern(message, source) {
433
- const filters = this.config.filters;
434
- if (!filters?.excludePatterns?.length)
435
- return false;
436
- for (const pattern of filters.excludePatterns) {
437
- // Check if pattern is a regex (starts and ends with /)
438
- if (typeof pattern === "string" &&
439
- pattern.startsWith("/") &&
440
- pattern.endsWith("/")) {
441
- try {
442
- const regexPattern = pattern.slice(1, -1);
443
- const regex = new RegExp(regexPattern);
444
- if (regex.test(message) || regex.test(source)) {
445
- return true;
446
- }
447
- }
448
- catch (error) {
449
- // Invalid regex, treat as string
450
- if (source.includes(pattern) || message.includes(pattern)) {
451
- return true;
452
- }
453
- }
454
- }
455
- else {
456
- // String pattern - simple includes check
457
- if (source.includes(pattern) || message.includes(pattern)) {
458
- return true;
459
- }
460
- }
461
- }
462
- return false;
463
- }
464
- /**
465
- * Check if call should be intercepted based on filters
466
- */
467
- shouldInterceptCall(call) {
468
- const filters = this.config.filters;
469
- if (!filters)
470
- return true;
471
- // Check minimum level
472
- if (filters.minLevel) {
473
- const levelOrder = { debug: 0, info: 1, warn: 2, error: 3 };
474
- const callLevel = levelOrder[call.level] ?? 1;
475
- const minLevel = levelOrder[filters.minLevel] ?? 0;
476
- if (callLevel < minLevel)
477
- return false;
478
- }
479
- // Check message length
480
- const message = call.args.join(" ");
481
- if (filters.maxLength && message.length > filters.maxLength) {
482
- return false;
483
- }
484
- // Check exclude patterns - if matched, mark for original display
485
- const source = call.source || call.stackTrace || "";
486
- if (this.matchesExcludePattern(message, source)) {
487
- // Mark this call to be displayed in original format
488
- call.excludedByPattern = true;
489
- return false; // Don't intercept, will be shown in original format
490
- }
491
- // Check include patterns (if specified, at least one must match)
492
- if (filters.includePatterns?.length) {
493
- const hasMatch = filters.includePatterns.some((pattern) => source.includes(pattern) || message.includes(pattern));
494
- if (!hasMatch)
495
- return false;
496
- }
497
- return true;
498
- }
499
- /**
500
- * Classify intercepted call into a category
501
- */
502
- classifyCall(call) {
503
- const message = call.args.join(" ");
504
- const filters = this.config.filters;
505
- // Check user application patterns
506
- if (filters?.userAppPatterns?.length) {
507
- for (const pattern of filters.userAppPatterns) {
508
- if (message.includes(pattern)) {
509
- call.category = "userApp";
510
- return;
511
- }
57
+ if (this.ipcPath) {
58
+ try {
59
+ const ipc = new XHSCDirectIPC.XHSCDirectIPC(this.ipcPath);
60
+ await ipc.sendCommand("console", "update-config", {
61
+ ...this.config,
62
+ enabled: false,
63
+ });
64
+ ipc.close();
512
65
  }
513
- }
514
- // Check system patterns
515
- if (filters?.systemPatterns?.length) {
516
- for (const pattern of filters.systemPatterns) {
517
- if (message.includes(pattern)) {
518
- call.category = "system";
519
- return;
520
- }
66
+ catch (err) {
67
+ // Ignore stop errors
521
68
  }
522
69
  }
523
- call.category = "unknown";
70
+ this.isIntercepting = false;
71
+ this.stats.isActive = false;
524
72
  }
525
- /**
526
- * Process intercepted console call through logging system
527
- */
528
- async processInterceptedCall(call) {
529
- // Temporarily disable processing to prevent recursion
530
- const wasProcessing = this.isProcessing;
531
- this.isProcessing = true;
532
- try {
533
- // ALWAYS handle encryption if enabled (background processing)
534
- if (this.encryptionHandler && this.config.encryption?.enabled) {
535
- try {
536
- await this.encryptionHandler.encryptLogEntry(call);
537
- }
538
- catch (error) {
539
- this.logger.warn("console", "Failed to encrypt log entry", error);
540
- }
541
- }
542
- // 🔧 CRITICAL: Respect new preserve option setting
543
- if (!this.shouldRouteToLogger()) {
544
- // Don't route through logger based on preserve option mode
545
- return;
546
- }
547
- // Route through our logger system with appropriate prefix
548
- // DISPLAY: Based on preserve option configuration
549
- let displayMessage = call.args.join(" ");
550
- // Determine display format only if we're actually displaying
551
- const displayMode = this.config.encryption?.displayMode || "readable";
552
- const showEncryptionStatus = this.config.encryption?.showEncryptionStatus || false;
553
- // Apply display mode transformations if encryption is enabled
554
- if (this.encryptionHandler &&
555
- this.config.encryption?.enabled &&
556
- displayMode !== "readable") {
557
- // Get the last encrypted entry for display
558
- const encryptedLogs = this.encryptionHandler.getEncryptedLogsAsStrings();
559
- if (encryptedLogs.length > 0) {
560
- const latestEncrypted = encryptedLogs[encryptedLogs.length - 1];
561
- const encryptedHash = await this.extractEncryptedHash(latestEncrypted);
562
- const enc = typeof encryptedHash !== "string"
563
- ? encryptedHash.toString("hex")
564
- : encryptedHash;
565
- switch (displayMode) {
566
- case "encrypted":
567
- // Show only the encrypted hash
568
- displayMessage = enc;
569
- break;
570
- case "both":
571
- // Show both readable and encrypted hash
572
- displayMessage = `${call.args.join(" ")} [${enc.substring(0, 32)}...]`;
573
- break;
574
- }
575
- }
576
- }
577
- // Add encryption status indicator if enabled
578
- if (showEncryptionStatus && this.config.encryption?.enabled) {
579
- displayMessage = `${displayMessage}`;
580
- }
581
- const component = call.category === "system" ? "server" : "userApp";
582
- // Add metadata if available
583
- const metadata = [];
584
- if (call.source) {
585
- metadata.push(`[${call.source}]`);
586
- }
587
- // Route through our logging system (only if preserveOriginal is true)
588
- switch (call.level) {
589
- case "error":
590
- this.logger.error(component, displayMessage, ...metadata);
591
- break;
592
- case "warn":
593
- this.logger.warn(component, displayMessage, ...metadata);
594
- break;
595
- case "debug":
596
- this.logger.debug(component, displayMessage, ...metadata);
597
- break;
598
- default:
599
- this.logger.info(component, displayMessage, ...metadata);
600
- break;
73
+ async getStats() {
74
+ if (this.ipcPath && this.isIntercepting) {
75
+ try {
76
+ const ipc = new XHSCDirectIPC.XHSCDirectIPC(this.ipcPath);
77
+ const res = await ipc.sendCommand("console", "get-stats", {});
78
+ ipc.close();
79
+ // Merge/process remote stats if needed
80
+ // For now, return local state with remote markers
81
+ return { ...this.stats, methodCounts: res.data || {} };
601
82
  }
602
- }
603
- catch (error) {
604
- // If logging fails and preserveOriginal is true, use original console
605
- if (this.config.preserveOriginal) {
606
- const originalMethod = this.originalConsole[call.method] ||
607
- this.originalConsole.log;
608
- if (originalMethod) {
609
- originalMethod(`[USERAPP] ${call.args.join(" ")}`);
610
- }
83
+ catch (err) {
84
+ return { ...this.stats };
611
85
  }
612
86
  }
613
- finally {
614
- // Restore processing state
615
- this.isProcessing = wasProcessing;
616
- }
617
- }
618
- /**
619
- * Update statistics
620
- */
621
- updateStats(method, startTime) {
622
- this.stats.totalInterceptions++;
623
- this.stats.methodCounts[method] =
624
- (this.stats.methodCounts[method] || 0) + 1;
625
- this.stats.lastInterceptionTime = Date.now();
626
- // Calculate performance overhead
627
- if (this.config.performanceMode && startTime > 0) {
628
- const overhead = performance.now() - startTime;
629
- this.performanceBuffer.push(overhead);
630
- // Keep only last 100 measurements
631
- if (this.performanceBuffer.length > 100) {
632
- this.performanceBuffer.shift();
633
- }
634
- this.stats.averageOverhead =
635
- this.performanceBuffer.reduce((a, b) => a + b, 0) /
636
- this.performanceBuffer.length;
637
- }
638
- // Update interceptions per second
639
- const now = Date.now();
640
- if (now - this.lastSecondTimestamp >= 1000) {
641
- this.stats.interceptionsPerSecond = this.lastSecondInterceptions;
642
- this.lastSecondInterceptions = 0;
643
- this.lastSecondTimestamp = now;
644
- }
645
- else {
646
- this.lastSecondInterceptions++;
647
- }
648
- }
649
- /**
650
- * Handle errors in the interception system
651
- */
652
- handleError(message, error) {
653
- this.errorCount++;
654
- this.stats.errorCount = this.errorCount;
655
- const errorMessage = error instanceof Error ? error.message : String(error);
656
- switch (this.config.fallback.onError) {
657
- case "silent":
658
- // Do nothing
659
- break;
660
- case "throw":
661
- throw new Error(`${message}: ${errorMessage}`);
662
- case "console":
663
- default:
664
- // Use original console.error to avoid recursion
665
- if (this.originalConsole.error) {
666
- this.originalConsole.error(`[ConsoleInterceptor] ${message}:`, errorMessage);
667
- }
668
- break;
669
- }
670
- // Check for graceful degradation
671
- if (this.config.fallback.gracefulDegradation &&
672
- this.errorCount >= this.config.fallback.maxErrors) {
673
- this.logger.warn("console", "Too many errors in console interception, disabling system");
674
- this.stop();
675
- }
676
- }
677
- /**
678
- * Check if interception is currently active
679
- */
680
- isActive() {
681
- return this.isIntercepting && this.stats.isActive;
87
+ return { ...this.stats };
682
88
  }
683
- /**
684
- * Reset statistics
685
- */
686
- resetStats() {
687
- this.stats = {
688
- totalInterceptions: 0,
689
- interceptionsPerSecond: 0,
690
- errorCount: 0,
691
- lastInterceptionTime: 0,
692
- methodCounts: {},
693
- averageOverhead: 0,
694
- isActive: this.isIntercepting,
89
+ async updateConfig(newConfig) {
90
+ this.config = {
91
+ ...this.config,
92
+ ...newConfig,
695
93
  };
696
- this.config.interceptMethods.forEach((method) => {
697
- this.stats.methodCounts[method] = 0;
698
- });
699
- this.errorCount = 0;
700
- this.performanceBuffer = [];
701
- }
702
- // ENCRYPTION METHODS
703
- /**
704
- * Enable console encryption with a key
705
- * @param key - Encryption key (if not provided, will use environment variable)
706
- */
707
- enableEncryption(key) {
708
- if (!this.config.encryption) {
709
- this.config.encryption = { ...types.DEFAULT_CONSOLE_CONFIG.encryption };
710
- }
711
- // Preserve existing display mode settings when enabling encryption
712
- const existingDisplayMode = this.config.encryption.displayMode;
713
- const existingShowStatus = this.config.encryption.showEncryptionStatus;
714
- this.config.encryption.enabled = true;
715
- // Restore display mode settings if they were previously configured
716
- if (existingDisplayMode) {
717
- this.config.encryption.displayMode = existingDisplayMode;
718
- }
719
- if (existingShowStatus !== undefined) {
720
- this.config.encryption.showEncryptionStatus = existingShowStatus;
721
- }
722
- if (key) {
723
- this.config.encryption.key = key;
724
- }
725
- else {
726
- // Try to get key from environment
727
- this.config.encryption.key =
728
- process.env.XYPRISS_CONSOLE_ENCRYPTION_KEY ||
729
- process.env.ENC_SECRET_KEY ||
730
- this.generateTemporaryKey();
731
- }
732
- // Initialize or update encryption handler
733
- this.initializeEncryptionHandler();
734
- this.logger.info("console", `Console encryption enabled (displayMode: ${this.config.encryption.displayMode})`);
735
- }
736
- /**
737
- * Disable console encryption
738
- */
739
- disableEncryption() {
740
- if (this.config.encryption) {
741
- this.config.encryption.enabled = false;
742
- this.config.encryption.key = undefined;
743
- }
744
- this.logger.info("console", "Console encryption disabled");
745
- }
746
- /**
747
- * Set encryption key for console output
748
- * @param key - The encryption key to use
749
- */
750
- setEncryptionKey(key) {
751
- if (!this.config.encryption) {
752
- this.config.encryption = { ...types.DEFAULT_CONSOLE_CONFIG.encryption };
753
- }
754
- this.config.encryption.key = key;
755
- this.logger.info("console", "Console encryption key updated");
756
- }
757
- /**
758
- * Simple encrypt method - enables encryption with key
759
- * Works independently from preserveOriginal setting
760
- * @param key - Encryption key
761
- */
762
- encrypt(key) {
763
- this.enableEncryption(key);
764
- }
765
- /**
766
- * Update encryption display mode
767
- * @param displayMode - How to display encrypted logs
768
- * @param showEncryptionStatus - Whether to show encryption indicators
769
- */
770
- setEncryptionDisplayMode(displayMode, showEncryptionStatus) {
771
- if (!this.config.encryption) {
772
- this.config.encryption = { ...types.DEFAULT_CONSOLE_CONFIG.encryption };
773
- }
774
- this.config.encryption.displayMode = displayMode;
775
- if (showEncryptionStatus !== undefined) {
776
- this.config.encryption.showEncryptionStatus = showEncryptionStatus;
777
- }
778
- this.logger.info("console", `Console encryption display mode updated: ${displayMode}`);
779
- }
780
- /**
781
- * Get encrypted console logs (for external transmission)
782
- * @returns Array of encrypted log entries
783
- */
784
- getEncryptedLogs() {
785
- if (!this.encryptionHandler) {
786
- throw new Error("Encryption is not enabled or handler is not initialized");
787
- }
788
- return this.encryptionHandler.getEncryptedLogsAsStrings();
789
- }
790
- /**
791
- * Restore console logs from encrypted data
792
- * @param encryptedData - Array of encrypted log entries
793
- * @param key - Decryption key
794
- * @returns Array of decrypted log entries
795
- */
796
- async restoreFromEncrypted(encryptedData, key) {
797
- try {
798
- if (!this.encryptionHandler) {
799
- // Create a temporary encryption handler for decryption
800
- const tempConfig = {
801
- ...types.DEFAULT_CONSOLE_CONFIG.encryption,
802
- enabled: true,
803
- key,
804
- };
805
- this.encryptionHandler = new ConsoleEncryption.ConsoleEncryption(tempConfig);
94
+ if (this.ipcPath) {
95
+ try {
96
+ const ipc = new XHSCDirectIPC.XHSCDirectIPC(this.ipcPath);
97
+ await ipc.sendCommand("console", "update-config", this.config);
98
+ ipc.close();
806
99
  }
807
- const decryptedCalls = await this.encryptionHandler.restoreFromEncryptedStrings(encryptedData, key);
808
- const decryptedMessages = decryptedCalls.map((call) => call.args.join(" "));
809
- this.logger.info("console", `Restored ${decryptedMessages.length} encrypted log entries`);
810
- return decryptedMessages;
811
- }
812
- catch (error) {
813
- this.logger.error("console", "Failed to restore encrypted logs", error);
814
- throw error;
815
- }
816
- }
817
- /**
818
- * Generate a temporary encryption key (for development)
819
- */
820
- generateTemporaryKey() {
821
- const key = Math.random().toString(36).substring(2, 15) +
822
- Math.random().toString(36).substring(2, 15);
823
- this.logger.warn("console", "Using temporary encryption key. Set CONSOLE_ENCRYPTION_KEY for production.");
824
- return key;
825
- }
826
- /**
827
- * Extract encrypted hash from the full encrypted JSON structure
828
- */
829
- async extractEncryptedHash(encryptedData) {
830
- try {
831
- // Parse the encrypted JSON structure
832
- const encryptedObj = JSON.parse(encryptedData);
833
- // Get the encoding type from config
834
- const encoding = this.config.encryption?.encoding || "base64";
835
- // Extract just the encrypted data field and encode it properly
836
- const encrypt = async (out) => {
837
- const encr = await xyprissSecurity.Hash.create(encryptedObj.data, {
838
- outputFormat: out,
839
- });
840
- return encr;
841
- };
842
- if (encryptedObj.data) {
843
- switch (encoding) {
844
- case "base64":
845
- return await encrypt("base64");
846
- case "hex":
847
- return await encrypt("hex");
848
- default:
849
- return await encrypt("base64");
850
- }
100
+ catch (err) {
101
+ this.logger.error("console", `Failed to update console config: ${err.message}`);
851
102
  }
852
- // Fallback: create a hash of the entire encrypted structure
853
- const buffer = Buffer.from(encryptedData);
854
- return encoding === "base64"
855
- ? buffer.toString("base64")
856
- : buffer.toString("hex");
857
103
  }
858
- catch (error) {
859
- // If parsing fails, create a simple hash of the raw data
860
- const encoding = this.config.encryption?.encoding || "base64";
861
- const buffer = Buffer.from(encryptedData);
862
- return encoding === "base64"
863
- ? buffer.toString("base64")
864
- : buffer.toString("hex");
865
- }
866
- }
867
- /**
868
- * Check if encryption is currently enabled
869
- */
870
- isEncryptionEnabled() {
871
- return (this.config.encryption?.enabled === true &&
872
- !!this.config.encryption.key);
873
- }
874
- /**
875
- * Get encryption status and configuration
876
- */
877
- getEncryptionStatus() {
878
- const encryption = this.config.encryption;
879
- return {
880
- enabled: encryption?.enabled === true,
881
- algorithm: encryption?.algorithm,
882
- hasKey: !!encryption?.key,
883
- externalLogging: encryption?.externalLogging?.enabled,
884
- };
885
104
  }
886
- /**
887
- * Add log to trace buffer
888
- */
889
- addToTraceBuffer(log) {
890
- const maxSize = this.config.tracing?.maxBufferSize || 1000;
891
- this.traceBuffer.push({ ...log });
892
- if (this.traceBuffer.length > maxSize) {
893
- this.traceBuffer.shift();
894
- }
895
- }
896
- /**
897
- * Set plugin engine for triggering hooks
898
- */
899
105
  setPluginEngine(engine) {
900
106
  this.pluginEngine = engine;
901
107
  }
902
108
  /**
903
- * Trigger all registered trace hooks
904
- */
905
- triggerTraceHooks(log) {
906
- const logCopy = { ...log };
907
- this.traceHooks.forEach((hook) => {
908
- try {
909
- hook(logCopy);
910
- }
911
- catch (error) {
912
- // Ignore hook errors to prevent affecting main flow
913
- }
914
- });
915
- // Trigger plugin engine hooks if available
916
- if (this.pluginEngine) {
917
- try {
918
- this.pluginEngine.triggerConsoleLogHook(logCopy);
919
- }
920
- catch (error) {
921
- // Silently ignore
922
- }
923
- }
924
- }
925
- /**
926
- * Register a new trace hook
927
- * Restricted: Only allowed if explicitly permitted or in development
928
- */
929
- onTrace(hook) {
930
- // Strict security: tracing must be enabled in config
931
- if (!this.config.tracing?.enabled) {
932
- this.logger.warn("console", "Attempted to register trace hook but tracing is disabled in configuration");
933
- return;
934
- }
935
- this.traceHooks.push(hook);
936
- }
937
- /**
938
- * Get tracked logs
939
- */
940
- getTraceBuffer() {
941
- return [...this.traceBuffer];
942
- }
943
- /**
944
- * Clear trace buffer
945
- */
946
- clearTraceBuffer() {
947
- this.traceBuffer = [];
948
- }
949
- /**
950
- * Enable tracing at runtime
951
- */
952
- enableTracing(maxBufferSize) {
953
- if (!this.config.tracing) {
954
- this.config.tracing = {
955
- enabled: true,
956
- maxBufferSize: maxBufferSize || 1000,
957
- includeStack: false,
958
- };
959
- }
960
- else {
961
- this.config.tracing.enabled = true;
962
- if (maxBufferSize) {
963
- this.config.tracing.maxBufferSize = maxBufferSize;
964
- }
965
- }
966
- this.logger.info("console", "Console log tracing enabled");
967
- }
968
- /**
969
- * Disable tracing at runtime
109
+ * Called by LogProcessor when a log is received from the native engine.
110
+ * This triggers the plugin hooks if enabled.
970
111
  */
971
- disableTracing() {
972
- if (this.config.tracing) {
973
- this.config.tracing.enabled = false;
112
+ handleNativeLog(log) {
113
+ if (this.isIntercepting && this.pluginEngine?.triggerConsoleLogHook) {
114
+ this.pluginEngine.triggerConsoleLogHook(log);
974
115
  }
975
- this.logger.info("console", "Console log tracing disabled");
976
116
  }
977
117
  }
978
118