@peers-app/peers-sdk 0.7.20 → 0.7.22

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.
@@ -1,9 +1,10 @@
1
+ type ConsoleLevel = 'debug' | 'info' | 'log' | 'warn' | 'error';
1
2
  /**
2
3
  * Setup console proxy to capture all console output and write to ConsoleLogs table.
3
4
  * Also subscribes to dataChanged events to output logs from other process instances.
4
5
  * @param processName - The name of the process (e.g., 'main', 'renderer')
5
6
  */
6
- export declare function setupConsoleProxy(processName: string): Promise<void>;
7
+ export declare function setupConsoleLogsProxy(processName: string): void;
7
8
  /**
8
9
  * Restore original console methods
9
10
  */
@@ -14,15 +15,6 @@ export declare function restoreConsole(): void;
14
15
  * @internal Exported for testing
15
16
  */
16
17
  export declare function extractCoreMessage(message: string): string;
17
- /**
18
- * Mark the logging system as initialized and flush any pending logs
19
- */
20
- export declare function markLoggingInitialized(): void;
21
- /**
22
- * Reset logging initialization state (primarily for testing)
23
- * @internal
24
- */
25
- export declare function resetLoggingState(): void;
26
18
  /**
27
19
  * Logger class for creating source-specific loggers
28
20
  *
@@ -35,6 +27,8 @@ export declare function resetLoggingState(): void;
35
27
  */
36
28
  export declare class Logger {
37
29
  private source;
30
+ private pendingLogs;
31
+ private waitingForConsoleLogsTable;
38
32
  constructor(source?: string);
39
33
  /**
40
34
  * Log a debug message
@@ -59,5 +53,7 @@ export declare class Logger {
59
53
  /**
60
54
  * Internal method to write log to database
61
55
  */
62
- private writeLog;
56
+ writeLog(level: ConsoleLevel, args: any[]): void;
57
+ flushPendingLogs(): Promise<void>;
63
58
  }
59
+ export {};
@@ -1,14 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Logger = void 0;
4
- exports.setupConsoleProxy = setupConsoleProxy;
4
+ exports.setupConsoleLogsProxy = setupConsoleLogsProxy;
5
5
  exports.restoreConsole = restoreConsole;
6
6
  exports.extractCoreMessage = extractCoreMessage;
7
- exports.markLoggingInitialized = markLoggingInitialized;
8
- exports.resetLoggingState = resetLoggingState;
9
7
  const utils_1 = require("../utils");
10
8
  const console_logs_table_1 = require("./console-logs.table");
11
- const startupDelayForWritingLogsToDB = Date.now() + 2_000;
12
9
  // Store original console methods
13
10
  const originalConsole = {
14
11
  debug: console.debug,
@@ -17,35 +14,32 @@ const originalConsole = {
17
14
  warn: console.warn,
18
15
  error: console.error,
19
16
  };
20
- let isProxySetup = false;
17
+ let isConsoleLogsProxySetup = false;
21
18
  let currentProcessName = 'unknown';
22
19
  let currentProcessInstanceId = '';
23
- // Guard against infinite recursion during log processing (single process)
24
- let isWritingLog = false;
25
- let recursionAttempts = 0;
26
- const MAX_RECURSION_ATTEMPTS = 3;
27
20
  // Guard against cross-process infinite loops
28
21
  // Track recent log signatures (hash of message + level + source)
29
22
  const recentLogSignatures = new Map();
30
23
  const LOG_SIGNATURE_WINDOW_MS = 5000; // 5 second window
31
24
  const MAX_IDENTICAL_LOGS_IN_WINDOW = 10; // Max same log in window
32
25
  // Track initialization state
33
- let isInitialized = false;
34
- const pendingLogs = [];
35
26
  const MAX_PENDING_LOGS = 1000; // Prevent memory buildup if initialization never happens
27
+ let defaultLogger = undefined;
28
+ let consoleLogsProxySubscription = undefined;
36
29
  /**
37
30
  * Setup console proxy to capture all console output and write to ConsoleLogs table.
38
31
  * Also subscribes to dataChanged events to output logs from other process instances.
39
32
  * @param processName - The name of the process (e.g., 'main', 'renderer')
40
33
  */
41
- async function setupConsoleProxy(processName) {
42
- if (isProxySetup) {
43
- console.warn('Console proxy already setup, skipping...');
34
+ function setupConsoleLogsProxy(processName) {
35
+ if (isConsoleLogsProxySetup) {
36
+ originalConsole.warn('Console logs proxy already setup, skipping...');
44
37
  return;
45
38
  }
46
- isProxySetup = true;
39
+ isConsoleLogsProxySetup = true;
47
40
  currentProcessName = processName;
48
41
  currentProcessInstanceId = (0, utils_1.newid)(); // Unique ID for this process instance
42
+ defaultLogger = new Logger(currentProcessName);
49
43
  const levels = ['debug', 'info', 'log', 'warn', 'error'];
50
44
  // Monkey-patch console methods to capture local logs
51
45
  levels.forEach((level) => {
@@ -53,130 +47,62 @@ async function setupConsoleProxy(processName) {
53
47
  console[level] = function (...args) {
54
48
  // Always call original console method first (preserve terminal output)
55
49
  original.apply(console, args);
56
- // Asynchronously write to database (don't block console output)
57
- writeLogToDatabase(level, args).catch((err) => {
58
- // Use original console to avoid infinite recursion
59
- originalConsole.error('Failed to write log to database:', err);
60
- });
50
+ defaultLogger.writeLog(level, args);
61
51
  };
62
52
  });
63
53
  // Subscribe to dataChanged events to output logs from OTHER process instances
64
- try {
65
- const consoleLogsTable = await (0, console_logs_table_1.ConsoleLogs)();
66
- consoleLogsTable.dataChanged.subscribe((evt) => {
67
- const log = evt.dataObject;
68
- // Skip if this is our own log
69
- if (log.processInstanceId === currentProcessInstanceId) {
70
- return;
71
- }
72
- // Output log from another process with prefix
73
- const colorCode = log.process === 'renderer' ? '\x1b[36m' : '\x1b[35m'; // cyan for renderer, magenta for main
74
- const resetCode = '\x1b[0m';
75
- const prefix = `${colorCode}[${log.process}]${resetCode}`;
76
- const logLevel = log.level;
77
- const logArgs = [prefix, log.message];
78
- if (log.context) {
79
- logArgs.push(log.context);
80
- }
81
- if (originalConsole[logLevel]) {
82
- originalConsole[logLevel](...logArgs);
83
- }
84
- else {
85
- originalConsole.log(...logArgs);
86
- }
87
- // Also output stack trace for errors
88
- if (log.stackTrace) {
89
- originalConsole.error(log.stackTrace);
90
- }
91
- });
92
- }
93
- catch (err) {
94
- originalConsole.error('Failed to subscribe to console logs dataChanged:', err);
95
- }
96
- console.log(`Console proxy initialized for process: ${processName} (instance: ${currentProcessInstanceId})`);
54
+ (0, console_logs_table_1.ConsoleLogs)().then(async (consoleLogsTable) => {
55
+ try {
56
+ consoleLogsProxySubscription = consoleLogsTable.dataChanged.subscribe((evt) => {
57
+ const log = evt.dataObject;
58
+ // Skip if this is our own log
59
+ if (log.processInstanceId === currentProcessInstanceId) {
60
+ return;
61
+ }
62
+ // Output log from another process with prefix
63
+ const colorCode = log.process === 'renderer' ? '\x1b[36m' : '\x1b[35m'; // cyan for renderer, magenta for main
64
+ const resetCode = '\x1b[0m';
65
+ const prefix = `${colorCode}[${log.process}]${resetCode}`;
66
+ const logLevel = log.level;
67
+ const logArgs = [prefix, log.message];
68
+ if (log.context) {
69
+ logArgs.push(log.context);
70
+ }
71
+ if (originalConsole[logLevel]) {
72
+ originalConsole[logLevel](...logArgs);
73
+ }
74
+ else {
75
+ originalConsole.log({ logLevel }, ...logArgs);
76
+ }
77
+ // Also output stack trace for errors
78
+ if (log.stackTrace) {
79
+ originalConsole.error(log.stackTrace);
80
+ }
81
+ });
82
+ }
83
+ catch (err) {
84
+ originalConsole.error('Failed to subscribe to console logs dataChanged:', err);
85
+ }
86
+ });
87
+ originalConsole.log(`Console proxy initialized for process: ${processName} (instance: ${currentProcessInstanceId})`);
97
88
  }
98
89
  /**
99
90
  * Restore original console methods
100
91
  */
101
92
  function restoreConsole() {
102
- if (!isProxySetup) {
93
+ if (!isConsoleLogsProxySetup) {
103
94
  return;
104
95
  }
96
+ consoleLogsProxySubscription?.unsubscribe();
97
+ consoleLogsProxySubscription = undefined;
105
98
  console.debug = originalConsole.debug;
106
99
  console.info = originalConsole.info;
107
100
  console.log = originalConsole.log;
108
101
  console.warn = originalConsole.warn;
109
102
  console.error = originalConsole.error;
110
- isProxySetup = false;
103
+ isConsoleLogsProxySetup = false;
111
104
  originalConsole.log('Console proxy removed, original console restored');
112
105
  }
113
- /**
114
- * Write a log entry to the ConsoleLogs table
115
- */
116
- async function writeLogToDatabase(level, args) {
117
- const timestamp = (0, utils_1.getTimestamp)();
118
- if (timestamp < startupDelayForWritingLogsToDB) {
119
- await (0, utils_1.sleep)(startupDelayForWritingLogsToDB - timestamp);
120
- }
121
- // Guard against infinite recursion (same process)
122
- if (isWritingLog) {
123
- recursionAttempts++;
124
- if (recursionAttempts >= MAX_RECURSION_ATTEMPTS) {
125
- // Break the loop by using original console
126
- originalConsole.error(`[console-logger] Infinite loop detected after ${recursionAttempts} attempts, dropping log write`, { level, args });
127
- // Reset counter after a delay to allow recovery
128
- setTimeout(() => {
129
- recursionAttempts = 0;
130
- }, 1000);
131
- return;
132
- }
133
- // Allow a few attempts in case of legitimate nested logging
134
- return;
135
- }
136
- isWritingLog = true;
137
- try {
138
- // Format message from arguments
139
- const message = formatLogMessage(args);
140
- // Extract context objects from arguments
141
- const context = extractContext(args);
142
- // Get stack trace for errors
143
- const stackTrace = level === 'error' ? getStackTrace() : undefined;
144
- // Extract source from stack trace
145
- const source = extractSource(stackTrace);
146
- // Guard against cross-process infinite loops
147
- // Extract core message to detect loops even when processes add prefixes
148
- const coreMessage = extractCoreMessage(message);
149
- // Create signature from level + source + core message (not the full message)
150
- const signature = `${level}:${source || 'unknown'}:${coreMessage.substring(0, 100)}`;
151
- if (!checkLogSignature(signature)) {
152
- // Too many identical logs in window, likely an infinite loop
153
- originalConsole.warn(`[console-logger] Cross-process infinite loop detected for log: ${signature.substring(0, 80)}...`);
154
- return;
155
- }
156
- const logRecord = {
157
- logId: (0, utils_1.newid)(),
158
- timestamp,
159
- level,
160
- process: currentProcessName,
161
- processInstanceId: currentProcessInstanceId,
162
- source,
163
- message,
164
- context,
165
- stackTrace,
166
- };
167
- const consoleLogsTable = await (0, console_logs_table_1.ConsoleLogs)();
168
- await consoleLogsTable.insert(logRecord);
169
- }
170
- catch (err) {
171
- originalConsole.error(`error while trying to write console log`, err);
172
- // Silently fail if table not available (e.g., during initialization)
173
- // Don't use console here to avoid infinite recursion
174
- }
175
- finally {
176
- isWritingLog = false;
177
- recursionAttempts = 0;
178
- }
179
- }
180
106
  /**
181
107
  * Extract core message by removing common prefixes that might be added by different processes
182
108
  * This helps detect cross-process loops where each process adds its own prefix
@@ -252,15 +178,16 @@ function formatLogMessage(args) {
252
178
  * Extract structured context objects from log arguments
253
179
  */
254
180
  function extractContext(args) {
255
- const objects = args.filter((arg) => arg && typeof arg === 'object' && !(arg instanceof Error) && !(arg instanceof Date));
256
- if (objects.length === 0) {
181
+ if (args.length === 0) {
257
182
  return undefined;
258
183
  }
259
- if (objects.length === 1) {
260
- return objects[0];
184
+ if (args.length === 1) {
185
+ const singleArg = args[0];
186
+ if (typeof singleArg !== 'object') {
187
+ return { value: singleArg };
188
+ }
261
189
  }
262
- // Merge multiple objects
263
- return Object.assign({}, ...objects);
190
+ return args;
264
191
  }
265
192
  /**
266
193
  * Get current stack trace
@@ -306,71 +233,26 @@ function extractSource(stackTrace) {
306
233
  }
307
234
  return undefined;
308
235
  }
309
- /**
310
- * Mark the logging system as initialized and flush any pending logs
311
- */
312
- function markLoggingInitialized() {
313
- isInitialized = true;
314
- // Flush pending logs sequentially with small delays to avoid recursion guard
315
- if (pendingLogs.length > 0) {
316
- originalConsole.log(`[console-logger] Flushing ${pendingLogs.length} pending logs...`);
317
- const logsToFlush = [...pendingLogs]; // Copy array
318
- pendingLogs.length = 0; // Clear the original array
319
- // Flush logs with small delays between them
320
- let delay = 0;
321
- for (const { level, source, args } of logsToFlush) {
322
- setTimeout(() => {
323
- writeLogToDatabaseWithSource(level, source, args).catch((err) => {
324
- originalConsole.error('[console-logger] Failed to flush pending log:', err);
325
- });
326
- }, delay);
327
- delay += 10; // 10ms between each log
328
- }
329
- }
330
- }
331
- /**
332
- * Reset logging initialization state (primarily for testing)
333
- * @internal
334
- */
335
- function resetLoggingState() {
336
- isInitialized = false;
337
- pendingLogs.length = 0;
338
- }
339
236
  /**
340
237
  * Write a log entry to the ConsoleLogs table with a specific source
341
238
  */
342
239
  async function writeLogToDatabaseWithSource(level, source, args) {
343
- const timestamp = (0, utils_1.getTimestamp)();
344
- if (timestamp < startupDelayForWritingLogsToDB) {
345
- await (0, utils_1.sleep)(startupDelayForWritingLogsToDB - timestamp);
346
- }
347
- // Guard against infinite recursion (same process)
348
- if (isWritingLog) {
349
- recursionAttempts++;
350
- if (recursionAttempts >= MAX_RECURSION_ATTEMPTS) {
351
- originalConsole.error(`[console-logger] Infinite loop detected after ${recursionAttempts} attempts, dropping log write`, { level, source, args });
352
- setTimeout(() => {
353
- recursionAttempts = 0;
354
- }, 1000);
355
- return;
356
- }
357
- return;
358
- }
359
- isWritingLog = true;
360
240
  try {
241
+ const timestamp = (0, utils_1.getTimestamp)();
361
242
  // Format message from arguments
362
243
  const message = formatLogMessage(args);
363
- // Extract context objects from arguments
364
- const context = extractContext(args);
365
- // Get stack trace for errors
366
- const stackTrace = level === 'error' ? getStackTrace() : undefined;
367
- // Guard against cross-process infinite loops
244
+ // Check for infinite loop before writing
245
+ // Extract core message to detect cross-process loops where prefixes are added
368
246
  const coreMessage = extractCoreMessage(message);
369
- const signature = `${level}:${source}:${coreMessage.substring(0, 100)}`;
247
+ const signature = `${level}:${coreMessage}:${source}`;
370
248
  if (!checkLogSignature(signature)) {
371
- originalConsole.warn(`[console-logger] Cross-process infinite loop detected for log: ${signature.substring(0, 80)}...`);
249
+ // This log is suspected to be part of an infinite loop, drop it
372
250
  return;
373
251
  }
252
+ // Extract context objects from arguments
253
+ const context = extractContext(args);
254
+ // Get stack trace for errors
255
+ const stackTrace = level === 'error' ? getStackTrace() : undefined;
374
256
  const logRecord = {
375
257
  logId: (0, utils_1.newid)(),
376
258
  timestamp,
@@ -386,11 +268,7 @@ async function writeLogToDatabaseWithSource(level, source, args) {
386
268
  await consoleLogsTable.insert(logRecord);
387
269
  }
388
270
  catch (err) {
389
- // Silently fail if table not available
390
- }
391
- finally {
392
- isWritingLog = false;
393
- recursionAttempts = 0;
271
+ originalConsole.error('[console-logger] Failed to write log to database:', err);
394
272
  }
395
273
  }
396
274
  /**
@@ -405,6 +283,8 @@ async function writeLogToDatabaseWithSource(level, source, args) {
405
283
  */
406
284
  class Logger {
407
285
  source;
286
+ pendingLogs = [];
287
+ waitingForConsoleLogsTable = true;
408
288
  constructor(source) {
409
289
  // If no source provided, try to extract from caller's location
410
290
  if (!source) {
@@ -412,9 +292,10 @@ class Logger {
412
292
  source = extractSource(stack) || 'unknown';
413
293
  }
414
294
  this.source = source;
415
- // ConsoleLogs().then(() => {
416
- // markLoggingInitialized();
417
- // })
295
+ (0, console_logs_table_1.ConsoleLogs)().then(() => {
296
+ this.waitingForConsoleLogsTable = false;
297
+ this.flushPendingLogs();
298
+ });
418
299
  }
419
300
  /**
420
301
  * Log a debug message
@@ -455,14 +336,14 @@ class Logger {
455
336
  * Internal method to write log to database
456
337
  */
457
338
  writeLog(level, args) {
458
- if (!isInitialized) {
339
+ if (this.waitingForConsoleLogsTable) {
459
340
  // Queue the log until system is initialized
460
- if (pendingLogs.length < MAX_PENDING_LOGS) {
461
- pendingLogs.push({ level, source: this.source, args });
341
+ if (this.pendingLogs.length < MAX_PENDING_LOGS) {
342
+ this.pendingLogs.push({ level, args });
462
343
  }
463
344
  else {
464
345
  // Drop logs if queue is full to prevent memory issues
465
- if (pendingLogs.length === MAX_PENDING_LOGS) {
346
+ if (this.pendingLogs.length === MAX_PENDING_LOGS) {
466
347
  originalConsole.warn('[console-logger] Pending log queue is full, dropping new logs until initialization');
467
348
  }
468
349
  }
@@ -473,5 +354,15 @@ class Logger {
473
354
  originalConsole.error('[console-logger] Failed to write log:', err);
474
355
  });
475
356
  }
357
+ async flushPendingLogs() {
358
+ const _pendingLogs = [...this.pendingLogs];
359
+ this.pendingLogs.length = 0;
360
+ for (const { level, args } of _pendingLogs) {
361
+ await (0, utils_1.sleep)(10); // small delay to avoid stampede
362
+ await writeLogToDatabaseWithSource(level, this.source, args).catch((err) => {
363
+ originalConsole.error('[console-logger] Failed to flush pending log:', err);
364
+ });
365
+ }
366
+ }
476
367
  }
477
368
  exports.Logger = Logger;
@@ -11,12 +11,16 @@ jest.mock('./console-logs.table', () => {
11
11
  };
12
12
  return {
13
13
  ConsoleLogs: jest.fn().mockResolvedValue(mockTable),
14
+ __mockTable: mockTable, // Export for test access
14
15
  };
15
16
  });
17
+ // Get reference to mock table
18
+ const { __mockTable: mockTable } = require('./console-logs.table');
16
19
  // Mock utils
17
20
  jest.mock('../utils', () => ({
18
21
  newid: () => 'test-id-123',
19
22
  getTimestamp: () => '2024-01-01T00:00:00.000Z',
23
+ sleep: jest.fn().mockResolvedValue(undefined),
20
24
  }));
21
25
  describe('console-logger', () => {
22
26
  let originalConsole;
@@ -62,6 +66,8 @@ describe('console-logger', () => {
62
66
  jest.clearAllMocks();
63
67
  // Restore console before each test
64
68
  (0, console_logger_1.restoreConsole)();
69
+ // Reset mock table
70
+ mockTable.insert.mockClear();
65
71
  });
66
72
  afterAll(() => {
67
73
  // Restore original console methods
@@ -73,8 +79,6 @@ describe('console-logger', () => {
73
79
  });
74
80
  describe('Single-process infinite loop detection', () => {
75
81
  it('should detect infinite loop when logging from within log handler', async () => {
76
- const { ConsoleLogs } = require('./console-logs.table');
77
- const mockTable = await ConsoleLogs();
78
82
  // Setup mock to throw error that triggers another log
79
83
  let callCount = 0;
80
84
  mockTable.insert.mockImplementation(() => {
@@ -85,23 +89,25 @@ describe('console-logger', () => {
85
89
  }
86
90
  return Promise.resolve();
87
91
  });
88
- await (0, console_logger_1.setupConsoleProxy)('test-process');
92
+ (0, console_logger_1.setupConsoleLogsProxy)('test-process');
93
+ // Wait for setup to complete
94
+ await new Promise(resolve => setTimeout(resolve, 100));
89
95
  // This should trigger the loop
90
96
  console.error('Initial error');
91
97
  // Wait for async operations
92
98
  await new Promise(resolve => setTimeout(resolve, 100));
93
99
  // Should have called insert but stopped early due to recursion guard
94
100
  expect(mockTable.insert).toHaveBeenCalled();
95
- // The recursion guard should stop it after just 1 attempt
96
- // (because isWritingLog prevents re-entry)
97
- expect(callCount).toBeLessThanOrEqual(2); // Setup log + 1 error attempt
101
+ // The calls should be limited
102
+ expect(callCount).toBeLessThanOrEqual(5);
98
103
  });
99
104
  });
100
105
  describe('Cross-process infinite loop detection', () => {
101
106
  it('should detect when same log is written too many times in window', async () => {
102
- const { ConsoleLogs } = require('./console-logs.table');
103
- const mockTable = await ConsoleLogs();
104
- await (0, console_logger_1.setupConsoleProxy)('test-process');
107
+ (0, console_logger_1.setupConsoleLogsProxy)('test-process');
108
+ // Wait for setup
109
+ await new Promise(resolve => setTimeout(resolve, 100));
110
+ mockTable.insert.mockClear();
105
111
  // Log the same message many times quickly (simulating cross-process loop)
106
112
  for (let i = 0; i < 15; i++) {
107
113
  console.error('Same error message');
@@ -111,14 +117,13 @@ describe('console-logger', () => {
111
117
  // Wait for async operations
112
118
  await new Promise(resolve => setTimeout(resolve, 100));
113
119
  // Should have stopped writing after threshold (10)
114
- // Plus 1 for the setup log
115
120
  expect(mockTable.insert.mock.calls.length).toBeLessThan(15);
116
121
  expect(mockTable.insert.mock.calls.length).toBeGreaterThan(0);
117
122
  });
118
123
  it('should NOT detect loop for different messages', async () => {
119
- const { ConsoleLogs } = require('./console-logs.table');
120
- const mockTable = await ConsoleLogs();
121
- await (0, console_logger_1.setupConsoleProxy)('test-process');
124
+ (0, console_logger_1.setupConsoleLogsProxy)('test-process');
125
+ // Wait for setup
126
+ await new Promise(resolve => setTimeout(resolve, 100));
122
127
  // Clear setup log
123
128
  mockTable.insert.mockClear();
124
129
  // Log different messages
@@ -133,9 +138,10 @@ describe('console-logger', () => {
133
138
  expect(mockTable.insert.mock.calls.length).toBeLessThanOrEqual(15);
134
139
  });
135
140
  it('should detect loop even with modified messages (prefix added)', async () => {
136
- const { ConsoleLogs } = require('./console-logs.table');
137
- const mockTable = await ConsoleLogs();
138
- await (0, console_logger_1.setupConsoleProxy)('test-process');
141
+ (0, console_logger_1.setupConsoleLogsProxy)('test-process');
142
+ // Wait for setup
143
+ await new Promise(resolve => setTimeout(resolve, 100));
144
+ mockTable.insert.mockClear();
139
145
  // Simulate cross-process loop where each process adds a prefix
140
146
  // This represents Process A logging "Error X"
141
147
  // Process B seeing it and logging "[main] Error X"
@@ -170,9 +176,10 @@ describe('console-logger', () => {
170
176
  });
171
177
  describe('Loop detection recovery', () => {
172
178
  it('should allow logging again after window expires', async () => {
173
- const { ConsoleLogs } = require('./console-logs.table');
174
- const mockTable = await ConsoleLogs();
175
- await (0, console_logger_1.setupConsoleProxy)('test-process');
179
+ (0, console_logger_1.setupConsoleLogsProxy)('test-process');
180
+ // Wait for setup
181
+ await new Promise(resolve => setTimeout(resolve, 100));
182
+ mockTable.insert.mockClear();
176
183
  // Trigger loop detection
177
184
  for (let i = 0; i < 12; i++) {
178
185
  console.error('Same error');
@@ -190,10 +197,9 @@ describe('console-logger', () => {
190
197
  });
191
198
  describe('Normal logging behavior', () => {
192
199
  it('should write logs to database for normal usage', async () => {
193
- const { ConsoleLogs } = require('./console-logs.table');
194
- await (0, console_logger_1.setupConsoleProxy)('test-process');
195
- // Get fresh mock reference after setup
196
- const mockTable = await ConsoleLogs();
200
+ (0, console_logger_1.setupConsoleLogsProxy)('test-process');
201
+ // Wait for setup to complete
202
+ await new Promise(resolve => setTimeout(resolve, 100));
197
203
  mockTable.insert.mockClear();
198
204
  console.log('Test message');
199
205
  await new Promise(resolve => setTimeout(resolve, 50));
@@ -208,15 +214,10 @@ describe('console-logger', () => {
208
214
  });
209
215
  });
210
216
  describe('Logger class', () => {
211
- beforeEach(() => {
212
- // Reset state before each Logger test
213
- (0, console_logger_1.resetLoggingState)();
214
- });
215
217
  it('should create logger with specified source', async () => {
216
- const { ConsoleLogs } = require('./console-logs.table');
217
- const mockTable = await ConsoleLogs();
218
- (0, console_logger_1.markLoggingInitialized)();
219
218
  const logger = new console_logger_1.Logger('MyModule');
219
+ // Wait for Logger to initialize
220
+ await new Promise(resolve => setTimeout(resolve, 100));
220
221
  mockTable.insert.mockClear();
221
222
  logger.log('Test message');
222
223
  await new Promise(resolve => setTimeout(resolve, 100));
@@ -226,10 +227,9 @@ describe('console-logger', () => {
226
227
  expect(call[0].message).toBe('Test message');
227
228
  });
228
229
  it('should support all log levels', async () => {
229
- const { ConsoleLogs } = require('./console-logs.table');
230
- const mockTable = await ConsoleLogs();
231
- (0, console_logger_1.markLoggingInitialized)();
232
230
  const logger = new console_logger_1.Logger('TestModule');
231
+ // Wait for Logger to initialize
232
+ await new Promise(resolve => setTimeout(resolve, 100));
233
233
  mockTable.insert.mockClear();
234
234
  logger.debug('Debug message');
235
235
  await new Promise(resolve => setTimeout(resolve, 20));
@@ -248,11 +248,14 @@ describe('console-logger', () => {
248
248
  const uniqueLevels = new Set(levels);
249
249
  expect(uniqueLevels.size).toBeGreaterThanOrEqual(4);
250
250
  });
251
- it('should queue logs before initialization', async () => {
251
+ it('should queue logs before initialization and flush after', async () => {
252
+ // Create a delayed promise for ConsoleLogs
253
+ let resolveConsoleLogs;
254
+ const delayedPromise = new Promise((resolve) => {
255
+ resolveConsoleLogs = resolve;
256
+ });
252
257
  const { ConsoleLogs } = require('./console-logs.table');
253
- const mockTable = await ConsoleLogs();
254
- // Ensure we're not initialized
255
- // (resetLoggingState was called in beforeEach)
258
+ ConsoleLogs.mockReturnValueOnce(delayedPromise);
256
259
  const logger = new console_logger_1.Logger('EarlyModule');
257
260
  // Log before initialization
258
261
  logger.log('Early message 1');
@@ -260,21 +263,19 @@ describe('console-logger', () => {
260
263
  logger.error('Early message 3');
261
264
  // Small delay to ensure logs are queued
262
265
  await new Promise(resolve => setTimeout(resolve, 50));
263
- mockTable.insert.mockClear();
264
266
  // Should not have written yet
265
267
  expect(mockTable.insert).not.toHaveBeenCalled();
266
- // Now initialize
267
- (0, console_logger_1.markLoggingInitialized)();
268
+ // Now resolve the ConsoleLogs promise
269
+ resolveConsoleLogs(mockTable);
268
270
  // Wait for flush
269
271
  await new Promise(resolve => setTimeout(resolve, 300));
270
272
  // Should have flushed pending logs
271
273
  expect(mockTable.insert.mock.calls.length).toBeGreaterThanOrEqual(2);
272
274
  });
273
275
  it('should write logs directly after initialization', async () => {
274
- const { ConsoleLogs } = require('./console-logs.table');
275
- const mockTable = await ConsoleLogs();
276
- (0, console_logger_1.markLoggingInitialized)();
277
276
  const logger = new console_logger_1.Logger('LateModule');
277
+ // Wait for initialization
278
+ await new Promise(resolve => setTimeout(resolve, 100));
278
279
  mockTable.insert.mockClear();
279
280
  logger.log('Direct message');
280
281
  await new Promise(resolve => setTimeout(resolve, 100));
@@ -282,11 +283,10 @@ describe('console-logger', () => {
282
283
  expect(mockTable.insert.mock.calls[0][0].message).toBe('Direct message');
283
284
  });
284
285
  it('should use reliable source from constructor', async () => {
285
- const { ConsoleLogs } = require('./console-logs.table');
286
- const mockTable = await ConsoleLogs();
287
- (0, console_logger_1.markLoggingInitialized)();
288
286
  const logger1 = new console_logger_1.Logger('SourceA');
289
287
  const logger2 = new console_logger_1.Logger('SourceB');
288
+ // Wait for initialization
289
+ await new Promise(resolve => setTimeout(resolve, 100));
290
290
  mockTable.insert.mockClear();
291
291
  logger1.log('From A');
292
292
  await new Promise(resolve => setTimeout(resolve, 50));
@@ -9,7 +9,7 @@ export declare const consoleLogSchema: z.ZodObject<{
9
9
  processInstanceId: z.ZodString;
10
10
  source: z.ZodOptional<z.ZodString>;
11
11
  message: z.ZodString;
12
- context: z.ZodOptional<z.ZodObject<{}, "strip", z.ZodAny, z.objectOutputType<{}, z.ZodAny, "strip">, z.objectInputType<{}, z.ZodAny, "strip">>>;
12
+ context: z.ZodOptional<z.ZodUnion<[z.ZodObject<{}, "strip", z.ZodAny, z.objectOutputType<{}, z.ZodAny, "strip">, z.objectInputType<{}, z.ZodAny, "strip">>, z.ZodArray<z.ZodAny, "many">]>>;
13
13
  stackTrace: z.ZodOptional<z.ZodString>;
14
14
  }, "strip", z.ZodTypeAny, {
15
15
  message: string;
@@ -19,7 +19,7 @@ export declare const consoleLogSchema: z.ZodObject<{
19
19
  process: string;
20
20
  processInstanceId: string;
21
21
  source?: string | undefined;
22
- context?: z.objectOutputType<{}, z.ZodAny, "strip"> | undefined;
22
+ context?: any[] | z.objectOutputType<{}, z.ZodAny, "strip"> | undefined;
23
23
  stackTrace?: string | undefined;
24
24
  }, {
25
25
  message: string;
@@ -29,7 +29,7 @@ export declare const consoleLogSchema: z.ZodObject<{
29
29
  processInstanceId: string;
30
30
  source?: string | undefined;
31
31
  timestamp?: number | undefined;
32
- context?: z.objectInputType<{}, z.ZodAny, "strip"> | undefined;
32
+ context?: any[] | z.objectInputType<{}, z.ZodAny, "strip"> | undefined;
33
33
  stackTrace?: string | undefined;
34
34
  }>;
35
35
  export type IConsoleLog = z.infer<typeof consoleLogSchema>;
@@ -51,7 +51,7 @@ exports.consoleLogSchema = zod_1.z.object({
51
51
  processInstanceId: zod_1.z.string().describe('Unique ID for this process instance to filter own logs'),
52
52
  source: zod_1.z.string().optional().describe('The source file or module that generated the log'),
53
53
  message: zod_1.z.string().describe('The log message'),
54
- context: zod_types_1.zodAnyObject.optional().describe('Additional structured context data'),
54
+ context: zod_types_1.zodAnyObjectOrArray.optional().describe('Additional structured context data'),
55
55
  stackTrace: zod_1.z.string().optional().describe('Stack trace for errors'),
56
56
  });
57
57
  const metaData = {
package/dist/rpc-types.js CHANGED
@@ -28,7 +28,8 @@ exports.rpcServerCalls = {
28
28
  };
29
29
  exports.rpcClientCalls = {
30
30
  ping: async (msg) => `pong: ${msg}`,
31
- emitEvent: rpcStub('emitEvent'),
31
+ // emitEvent: rpcStub('emitEvent') as ((event: IEventData) => Promise<boolean>),
32
+ emitEvent: ((...args) => Promise.resolve(false)),
32
33
  setClientPath: rpcStub('setClientPath'),
33
34
  openThread: rpcStub('openThread'),
34
35
  };
package/dist/utils.js CHANGED
@@ -235,6 +235,10 @@ async function retryOnErrorOrTimeout({ fn, connection, opts = {}, }) {
235
235
  throw finalError;
236
236
  }
237
237
  else {
238
+ const weightedTimeout = timeoutCount * 0.1;
239
+ const weightedInverse = 1 - weightedTimeout;
240
+ connection.errorRate = (connection.errorRate * weightedInverse) + weightedTimeout;
241
+ connection.latencyMs = (weightedTimeout * timeout) + (connection.latencyMs * weightedInverse);
238
242
  throw new Error(`Timeout after ${timeoutCount} retries waiting for ${timeout}ms`);
239
243
  }
240
244
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@peers-app/peers-sdk",
3
- "version": "0.7.20",
3
+ "version": "0.7.22",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/peers-app/peers-sdk.git"
@@ -1,41 +0,0 @@
1
- /**
2
- * Example usage of the Logger class
3
- *
4
- * This file demonstrates how to use the Logger class for reliable, source-specific logging
5
- */
6
- /**
7
- * Example function that uses the logger
8
- */
9
- export declare function processData(data: any): void;
10
- /**
11
- * Example initialization flow
12
- */
13
- export declare function initializeApp(): Promise<void>;
14
- /**
15
- * Benefits of using Logger class:
16
- *
17
- * 1. **Reliable Source Tracking**: Source is set once at construction time,
18
- * not extracted from stack traces which can be unreliable
19
- *
20
- * 2. **Initialization Safety**: Logs before system is ready are queued and
21
- * flushed once markLoggingInitialized() is called
22
- *
23
- * 3. **Infinite Loop Protection**: Inherits all the cross-process and
24
- * single-process infinite loop detection
25
- *
26
- * 4. **Type Safety**: Full TypeScript support with proper typing
27
- *
28
- * 5. **Console Passthrough**: All logs still appear in the console immediately,
29
- * database writes happen asynchronously
30
- *
31
- * Usage pattern:
32
- * ```typescript
33
- * // At the top of each file:
34
- * const logger = new Logger('FeatureName');
35
- *
36
- * // Throughout your code:
37
- * logger.log('Something happened');
38
- * logger.error('Something went wrong', error);
39
- * logger.debug('Detailed debugging info', { context });
40
- * ```
41
- */
@@ -1,74 +0,0 @@
1
- "use strict";
2
- /**
3
- * Example usage of the Logger class
4
- *
5
- * This file demonstrates how to use the Logger class for reliable, source-specific logging
6
- */
7
- Object.defineProperty(exports, "__esModule", { value: true });
8
- exports.processData = processData;
9
- exports.initializeApp = initializeApp;
10
- const console_logger_1 = require("./console-logger");
11
- // Create a logger at the top of your file with a descriptive source name
12
- const logger = new console_logger_1.Logger('MyModule');
13
- // You can also let it auto-detect the source from the filename
14
- // const logger = new Logger();
15
- /**
16
- * Example function that uses the logger
17
- */
18
- function processData(data) {
19
- logger.log('Processing data', { dataSize: data.length });
20
- try {
21
- // Do some work
22
- if (!data) {
23
- logger.warn('No data provided');
24
- return;
25
- }
26
- // More processing...
27
- logger.debug('Data processing in progress', { step: 'validation' });
28
- // Success
29
- logger.info('Data processed successfully');
30
- }
31
- catch (error) {
32
- logger.error('Failed to process data', error);
33
- throw error;
34
- }
35
- }
36
- /**
37
- * Example initialization flow
38
- */
39
- async function initializeApp() {
40
- // Early logging (before system is ready) - these get queued
41
- logger.log('Application starting...');
42
- // ... Initialize databases, connections, etc ...
43
- // Mark logging as initialized - this flushes all queued logs
44
- (0, console_logger_1.markLoggingInitialized)();
45
- logger.log('Application fully initialized');
46
- }
47
- /**
48
- * Benefits of using Logger class:
49
- *
50
- * 1. **Reliable Source Tracking**: Source is set once at construction time,
51
- * not extracted from stack traces which can be unreliable
52
- *
53
- * 2. **Initialization Safety**: Logs before system is ready are queued and
54
- * flushed once markLoggingInitialized() is called
55
- *
56
- * 3. **Infinite Loop Protection**: Inherits all the cross-process and
57
- * single-process infinite loop detection
58
- *
59
- * 4. **Type Safety**: Full TypeScript support with proper typing
60
- *
61
- * 5. **Console Passthrough**: All logs still appear in the console immediately,
62
- * database writes happen asynchronously
63
- *
64
- * Usage pattern:
65
- * ```typescript
66
- * // At the top of each file:
67
- * const logger = new Logger('FeatureName');
68
- *
69
- * // Throughout your code:
70
- * logger.log('Something happened');
71
- * logger.error('Something went wrong', error);
72
- * logger.debug('Detailed debugging info', { context });
73
- * ```
74
- */