@elizaos/core 1.5.0 → 1.5.2

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 (90) hide show
  1. package/dist/browser/index.browser.js +102 -102
  2. package/dist/browser/index.browser.js.map +5 -5
  3. package/dist/browser/index.d.ts +3 -1
  4. package/dist/index.d.ts +2 -3
  5. package/dist/index.js +1 -5
  6. package/dist/node/index.d.ts +3 -1
  7. package/dist/node/index.node.js +91 -12
  8. package/dist/node/index.node.js.map +10 -10
  9. package/package.json +10 -4
  10. package/src/__tests__/action-chaining-simple.test.ts +203 -0
  11. package/src/__tests__/actions.test.ts +218 -0
  12. package/src/__tests__/buffer.test.ts +337 -0
  13. package/src/__tests__/character-validation.test.ts +309 -0
  14. package/src/__tests__/database.test.ts +750 -0
  15. package/src/__tests__/entities.test.ts +727 -0
  16. package/src/__tests__/env.test.ts +23 -0
  17. package/src/__tests__/environment.test.ts +285 -0
  18. package/src/__tests__/logger-browser-node.test.ts +716 -0
  19. package/src/__tests__/logger.test.ts +403 -0
  20. package/src/__tests__/messages.test.ts +196 -0
  21. package/src/__tests__/mockCharacter.ts +544 -0
  22. package/src/__tests__/parsing.test.ts +58 -0
  23. package/src/__tests__/prompts.test.ts +159 -0
  24. package/src/__tests__/roles.test.ts +331 -0
  25. package/src/__tests__/runtime-embedding.test.ts +343 -0
  26. package/src/__tests__/runtime.test.ts +978 -0
  27. package/src/__tests__/search.test.ts +15 -0
  28. package/src/__tests__/services-by-type.test.ts +204 -0
  29. package/src/__tests__/services.test.ts +136 -0
  30. package/src/__tests__/settings.test.ts +810 -0
  31. package/src/__tests__/utils.test.ts +1105 -0
  32. package/src/__tests__/uuid.test.ts +94 -0
  33. package/src/actions.ts +122 -0
  34. package/src/database.ts +579 -0
  35. package/src/entities.ts +406 -0
  36. package/src/index.browser.ts +48 -0
  37. package/src/index.node.ts +39 -0
  38. package/src/index.ts +50 -0
  39. package/src/logger.ts +527 -0
  40. package/src/prompts.ts +243 -0
  41. package/src/roles.ts +85 -0
  42. package/src/runtime.ts +2514 -0
  43. package/src/schemas/character.ts +149 -0
  44. package/src/search.ts +1543 -0
  45. package/src/sentry/instrument.browser.ts +65 -0
  46. package/src/sentry/instrument.node.ts +57 -0
  47. package/src/sentry/instrument.ts +82 -0
  48. package/src/services.ts +105 -0
  49. package/src/settings.ts +409 -0
  50. package/src/test_resources/constants.ts +12 -0
  51. package/src/test_resources/testSetup.ts +21 -0
  52. package/src/test_resources/types.ts +22 -0
  53. package/src/types/agent.ts +112 -0
  54. package/src/types/browser.ts +145 -0
  55. package/src/types/components.ts +184 -0
  56. package/src/types/database.ts +348 -0
  57. package/src/types/email.ts +162 -0
  58. package/src/types/environment.ts +129 -0
  59. package/src/types/events.ts +249 -0
  60. package/src/types/index.ts +29 -0
  61. package/src/types/knowledge.ts +65 -0
  62. package/src/types/lp.ts +124 -0
  63. package/src/types/memory.ts +228 -0
  64. package/src/types/message.ts +233 -0
  65. package/src/types/messaging.ts +57 -0
  66. package/src/types/model.ts +359 -0
  67. package/src/types/pdf.ts +77 -0
  68. package/src/types/plugin.ts +78 -0
  69. package/src/types/post.ts +271 -0
  70. package/src/types/primitives.ts +97 -0
  71. package/src/types/runtime.ts +190 -0
  72. package/src/types/service.ts +198 -0
  73. package/src/types/settings.ts +30 -0
  74. package/src/types/state.ts +60 -0
  75. package/src/types/task.ts +72 -0
  76. package/src/types/tee.ts +107 -0
  77. package/src/types/testing.ts +30 -0
  78. package/src/types/token.ts +96 -0
  79. package/src/types/transcription.ts +133 -0
  80. package/src/types/video.ts +108 -0
  81. package/src/types/wallet.ts +56 -0
  82. package/src/types/web-search.ts +146 -0
  83. package/src/utils/__tests__/buffer.test.ts +80 -0
  84. package/src/utils/__tests__/environment.test.ts +58 -0
  85. package/src/utils/__tests__/stringToUuid.test.ts +88 -0
  86. package/src/utils/buffer.ts +312 -0
  87. package/src/utils/environment.ts +316 -0
  88. package/src/utils/server-health.ts +117 -0
  89. package/src/utils.ts +1076 -0
  90. package/dist/tsconfig.build.tsbuildinfo +0 -1
@@ -0,0 +1,716 @@
1
+ import { describe, expect, it, beforeEach, afterEach, mock } from 'bun:test';
2
+ import { createLogger } from '../logger';
3
+ import { getEnvironment } from '../utils/environment';
4
+
5
+ /**
6
+ * Test type definitions
7
+ */
8
+ interface MockProcess {
9
+ versions?: {
10
+ node?: string;
11
+ };
12
+ env?: Record<string, string | undefined>;
13
+ }
14
+
15
+ interface MockWindow {
16
+ document?: object;
17
+ console?: Partial<Console>;
18
+ }
19
+
20
+ type MockDocument = Record<string, unknown>;
21
+
22
+ /**
23
+ * Comprehensive tests for both Node.js and Browser logger implementations
24
+ * This test suite ensures the logger works correctly in both environments
25
+ */
26
+
27
+ describe('Logger - Cross-Environment Tests', () => {
28
+ let originalProcess: typeof process | undefined;
29
+ let originalWindow: MockWindow | undefined;
30
+ let originalDocument: MockDocument | undefined;
31
+
32
+ beforeEach(() => {
33
+ // Save original globals
34
+ originalProcess = globalThis.process;
35
+ originalWindow = globalThis.window;
36
+ originalDocument = globalThis.document;
37
+ mock.restore();
38
+ });
39
+
40
+ afterEach(() => {
41
+ // Restore original globals
42
+ globalThis.process = originalProcess as typeof process;
43
+ globalThis.window = originalWindow as unknown as typeof globalThis.window;
44
+ globalThis.document = originalDocument as unknown as typeof globalThis.document;
45
+ mock.restore();
46
+ // Clear environment cache for next test
47
+ getEnvironment().clearCache();
48
+ });
49
+
50
+ describe('Environment Detection', () => {
51
+ it('should detect Node.js environment correctly', () => {
52
+ // Ensure we're in Node.js environment
53
+ globalThis.process = {
54
+ versions: { node: '20.0.0' },
55
+ env: { LOG_LEVEL: 'info' },
56
+ } as MockProcess as typeof process;
57
+ delete globalThis.window;
58
+ delete globalThis.document;
59
+
60
+ const isNode =
61
+ typeof process !== 'undefined' &&
62
+ typeof process.versions !== 'undefined' &&
63
+ typeof process.versions.node !== 'undefined';
64
+ const isBrowser =
65
+ typeof globalThis !== 'undefined' &&
66
+ typeof globalThis.window !== 'undefined' &&
67
+ typeof globalThis.document !== 'undefined';
68
+
69
+ expect(isNode).toBe(true);
70
+ expect(isBrowser).toBe(false);
71
+ });
72
+
73
+ it('should detect browser environment correctly', () => {
74
+ // Simulate browser environment
75
+ globalThis.window = {
76
+ document: {},
77
+ console: {
78
+ log: mock(),
79
+ info: mock(),
80
+ warn: mock(),
81
+ error: mock(),
82
+ debug: mock(),
83
+ trace: mock(),
84
+ },
85
+ };
86
+ globalThis.document = {};
87
+ delete globalThis.process;
88
+
89
+ const isNode =
90
+ typeof process !== 'undefined' &&
91
+ typeof process.versions !== 'undefined' &&
92
+ typeof process.versions.node !== 'undefined';
93
+ const isBrowser =
94
+ typeof globalThis !== 'undefined' &&
95
+ typeof globalThis.window !== 'undefined' &&
96
+ typeof globalThis.document !== 'undefined';
97
+
98
+ expect(isNode).toBe(false);
99
+ expect(isBrowser).toBe(true);
100
+ });
101
+ });
102
+
103
+ describe('BrowserLogger Class', () => {
104
+ beforeEach(() => {
105
+ // Clear environment cache to ensure proper detection
106
+ getEnvironment().clearCache();
107
+
108
+ // Mock browser environment
109
+ globalThis.window = {
110
+ document: {},
111
+ console: {
112
+ log: mock(),
113
+ info: mock(),
114
+ warn: mock(),
115
+ error: mock(),
116
+ debug: mock(),
117
+ trace: mock(),
118
+ clear: mock(),
119
+ },
120
+ };
121
+ globalThis.document = {};
122
+ globalThis.console = globalThis.window.console as Console;
123
+
124
+ // Clear cache again after setting up environment
125
+ getEnvironment().clearCache();
126
+ });
127
+
128
+ it('should create BrowserLogger instance with all required methods', async () => {
129
+ // Dynamically import to trigger browser detection
130
+ const module = await import('../logger');
131
+
132
+ // Create a browser logger instance, force browser type for testing
133
+ const browserLogger = module.createLogger({ test: 'browser', __forceType: 'browser' });
134
+
135
+ // Verify all required methods exist
136
+ expect(typeof browserLogger.trace).toBe('function');
137
+ expect(typeof browserLogger.debug).toBe('function');
138
+ expect(typeof browserLogger.info).toBe('function');
139
+ expect(typeof browserLogger.warn).toBe('function');
140
+ expect(typeof browserLogger.error).toBe('function');
141
+ expect(typeof browserLogger.fatal).toBe('function');
142
+
143
+ // Verify custom ElizaOS methods exist
144
+ expect(typeof browserLogger.success).toBe('function');
145
+ expect(typeof browserLogger.progress).toBe('function');
146
+ expect(typeof browserLogger.log).toBe('function');
147
+ expect(typeof browserLogger.clear).toBe('function');
148
+ expect(typeof browserLogger.child).toBe('function');
149
+ });
150
+
151
+ it('should log messages to console in browser environment', () => {
152
+ // Ensure we're in browser environment
153
+ delete globalThis.process;
154
+ globalThis.window = { document: {} };
155
+ globalThis.document = {};
156
+
157
+ // Mock console methods
158
+ const mockConsole = {
159
+ log: mock(),
160
+ info: mock(),
161
+ warn: mock(),
162
+ error: mock(),
163
+ debug: mock(),
164
+ trace: mock(),
165
+ clear: mock(),
166
+ };
167
+ globalThis.console = mockConsole as unknown as Console;
168
+
169
+ // Create browser logger with debug level to ensure all levels are logged
170
+ const browserLogger = createLogger({ level: 'debug', __forceType: 'browser' });
171
+
172
+ // Test various log levels
173
+ browserLogger.info('Info message');
174
+ browserLogger.warn('Warning message');
175
+ browserLogger.error('Error message');
176
+ browserLogger.debug('Debug message');
177
+
178
+ // Verify console methods were called
179
+ expect(mockConsole.info).toHaveBeenCalled();
180
+ expect(mockConsole.warn).toHaveBeenCalled();
181
+ expect(mockConsole.error).toHaveBeenCalled();
182
+ expect(mockConsole.debug).toHaveBeenCalled();
183
+ });
184
+
185
+ it('should format messages with objects correctly in browser', () => {
186
+ // Ensure we're in browser environment
187
+ delete globalThis.process;
188
+ globalThis.window = { document: {} };
189
+ globalThis.document = {};
190
+
191
+ const mockConsole = {
192
+ info: mock(),
193
+ log: mock(),
194
+ warn: mock(),
195
+ error: mock(),
196
+ debug: mock(),
197
+ trace: mock(),
198
+ };
199
+ globalThis.console = mockConsole as unknown as Console;
200
+
201
+ // Create logger with debug level to ensure all levels are logged
202
+ const browserLogger = createLogger({ level: 'debug', __forceType: 'browser' });
203
+
204
+ // Test with object
205
+ browserLogger.info({ user: 'john', action: 'login' }, 'User logged in');
206
+ expect(mockConsole.info).toHaveBeenCalled();
207
+
208
+ // Test with error
209
+ const error = new Error('Test error');
210
+ browserLogger.error(error);
211
+ expect(mockConsole.error).toHaveBeenCalled();
212
+
213
+ // Test custom levels (success and progress map to info)
214
+ browserLogger.success('Operation successful');
215
+ browserLogger.progress('50% complete');
216
+ expect(mockConsole.info).toHaveBeenCalled();
217
+ });
218
+
219
+ it('should respect log levels in browser environment', () => {
220
+ // Ensure we're in browser environment
221
+ delete globalThis.process;
222
+ globalThis.window = { document: {} };
223
+ globalThis.document = {};
224
+
225
+ const mockConsole = {
226
+ trace: mock(),
227
+ debug: mock(),
228
+ info: mock(),
229
+ warn: mock(),
230
+ error: mock(),
231
+ log: mock(),
232
+ };
233
+ globalThis.console = mockConsole as unknown as Console;
234
+
235
+ // Clear cache to detect browser environment
236
+ getEnvironment().clearCache();
237
+
238
+ // Create logger with warn level, force browser type for testing
239
+ const browserLogger = createLogger({ level: 'warn', __forceType: 'browser' });
240
+
241
+ // These should not log (below warn level)
242
+ browserLogger.trace('Trace message');
243
+ browserLogger.debug('Debug message');
244
+ browserLogger.info('Info message');
245
+
246
+ // These should log (warn level and above)
247
+ browserLogger.warn('Warning message');
248
+ browserLogger.error('Error message');
249
+ browserLogger.fatal('Fatal message');
250
+
251
+ // Verify only warn and above were called
252
+ expect(mockConsole.trace).not.toHaveBeenCalled();
253
+ expect(mockConsole.debug).not.toHaveBeenCalled();
254
+ expect(mockConsole.info).not.toHaveBeenCalled();
255
+ expect(mockConsole.warn).toHaveBeenCalled();
256
+ expect(mockConsole.error).toHaveBeenCalled();
257
+ });
258
+
259
+ it('should maintain in-memory log storage in browser', () => {
260
+ const browserLogger = createLogger({ __forceType: 'browser' });
261
+
262
+ // Log multiple messages
263
+ browserLogger.info('Message 1');
264
+ browserLogger.warn('Message 2');
265
+ browserLogger.error('Message 3');
266
+
267
+ // Verify messages are stored (would be accessible via inMemoryDestination)
268
+ // The actual storage is internal, but we can verify the logger doesn't crash
269
+ expect(() => browserLogger.clear()).not.toThrow();
270
+ });
271
+
272
+ it('should handle child loggers in browser', () => {
273
+ // Ensure we're in browser environment
274
+ delete globalThis.process;
275
+ globalThis.window = { document: {} };
276
+ globalThis.document = {};
277
+
278
+ const mockConsole = {
279
+ info: mock(),
280
+ log: mock(),
281
+ };
282
+ globalThis.console = mockConsole as unknown as Console;
283
+
284
+ // Clear cache to detect browser environment
285
+ getEnvironment().clearCache();
286
+
287
+ // Force browser type for testing
288
+ const parentLogger = createLogger({ parent: 'main', __forceType: 'browser' });
289
+ const childLogger = parentLogger.child({ child: 'sub' });
290
+
291
+ childLogger.info('Child message');
292
+ expect(mockConsole.info).toHaveBeenCalled();
293
+ });
294
+ });
295
+
296
+ describe('Node.js Logger (Adze backend in Node)', () => {
297
+ beforeEach(() => {
298
+ // Clear environment cache
299
+ getEnvironment().clearCache();
300
+
301
+ // Restore Node.js environment
302
+ globalThis.process =
303
+ originalProcess ||
304
+ ({
305
+ versions: { node: '20.0.0' },
306
+ env: {},
307
+ } as unknown as typeof process);
308
+ delete globalThis.window;
309
+ delete globalThis.document;
310
+
311
+ // No need to mock transports; logger uses Adze in both environments
312
+
313
+ // Clear cache again after environment setup
314
+ getEnvironment().clearCache();
315
+ });
316
+
317
+ it('should provide logger API in Node.js environment', () => {
318
+ const nodeLogger = createLogger();
319
+
320
+ // Verify core methods exist
321
+ expect(typeof nodeLogger.trace).toBe('function');
322
+ expect(typeof nodeLogger.debug).toBe('function');
323
+ expect(typeof nodeLogger.info).toBe('function');
324
+ expect(typeof nodeLogger.warn).toBe('function');
325
+ expect(typeof nodeLogger.error).toBe('function');
326
+ expect(typeof nodeLogger.fatal).toBe('function');
327
+
328
+ // Verify custom methods are added
329
+ expect(typeof nodeLogger.success).toBe('function');
330
+ expect(typeof nodeLogger.progress).toBe('function');
331
+ expect(typeof nodeLogger.log).toBe('function');
332
+ });
333
+
334
+ it('should handle child loggers correctly', () => {
335
+ const parentLogger = createLogger({ service: 'api' });
336
+ const childLogger = parentLogger.child({ request: '123' });
337
+
338
+ expect(childLogger).toBeDefined();
339
+ expect(typeof childLogger.info).toBe('function');
340
+ });
341
+
342
+ it('should support log level configuration options', () => {
343
+ process.env.LOG_LEVEL = 'debug';
344
+ process.env.LOG_JSON_FORMAT = 'true';
345
+
346
+ const nodeLogger = createLogger();
347
+ expect(nodeLogger.level).toBeDefined();
348
+
349
+ process.env.LOG_LEVEL = '';
350
+ process.env.LOG_JSON_FORMAT = '';
351
+ });
352
+ });
353
+
354
+ describe('Cross-Environment Compatibility', () => {
355
+ it('should maintain consistent API across environments', async () => {
356
+ // Test Node.js logger
357
+ globalThis.process =
358
+ originalProcess || ({ versions: { node: '20.0.0' }, env: {} } as unknown as typeof process);
359
+ delete globalThis.window;
360
+ const nodeLogger = createLogger();
361
+
362
+ // Test browser logger
363
+ globalThis.window = { document: {}, console: globalThis.console };
364
+ globalThis.document = {};
365
+ delete globalThis.process;
366
+ const browserLogger = createLogger();
367
+
368
+ // Both should have the same methods
369
+ const methods = [
370
+ 'trace',
371
+ 'debug',
372
+ 'info',
373
+ 'warn',
374
+ 'error',
375
+ 'fatal',
376
+ 'success',
377
+ 'progress',
378
+ 'log',
379
+ 'clear',
380
+ 'child',
381
+ ];
382
+
383
+ for (const method of methods) {
384
+ expect(typeof nodeLogger[method]).toBe('function');
385
+ expect(typeof browserLogger[method]).toBe('function');
386
+ }
387
+ });
388
+
389
+ it('should handle complex log objects in both environments', () => {
390
+ const testData = {
391
+ user: { id: 123, name: 'John' },
392
+ metadata: { timestamp: Date.now(), version: '1.0' },
393
+ nested: { deep: { value: 'test' } },
394
+ };
395
+
396
+ // Test in Node.js
397
+ globalThis.process =
398
+ originalProcess || ({ versions: { node: '20.0.0' }, env: {} } as unknown as typeof process);
399
+ const nodeLogger = createLogger();
400
+ expect(() => nodeLogger.info(testData, 'Complex object')).not.toThrow();
401
+
402
+ // Test in browser
403
+ globalThis.window = { document: {}, console: { info: mock() } };
404
+ globalThis.document = {};
405
+ delete globalThis.process;
406
+ const browserLogger = createLogger({ __forceType: 'browser' });
407
+ expect(() => browserLogger.info(testData, 'Complex object')).not.toThrow();
408
+ });
409
+
410
+ it('should handle errors consistently across environments', () => {
411
+ const error = new Error('Test error');
412
+ error.stack = 'Error: Test error\n at test.js:1:1';
413
+
414
+ // Node.js
415
+ globalThis.process =
416
+ originalProcess || ({ versions: { node: '20.0.0' }, env: {} } as unknown as typeof process);
417
+ const nodeLogger = createLogger();
418
+ expect(() => nodeLogger.error(error)).not.toThrow();
419
+ expect(() => nodeLogger.error({ error }, 'Error occurred')).not.toThrow();
420
+
421
+ // Browser
422
+ globalThis.window = { document: {}, console: { error: mock() } };
423
+ globalThis.document = {};
424
+ delete globalThis.process;
425
+ const browserLogger = createLogger({ __forceType: 'browser' });
426
+ expect(() => browserLogger.error(error)).not.toThrow();
427
+ expect(() => browserLogger.error({ error }, 'Error occurred')).not.toThrow();
428
+ });
429
+ });
430
+
431
+ describe('Edge Cases and Error Handling', () => {
432
+ it('should handle undefined console methods in browser', () => {
433
+ globalThis.window = { document: {} };
434
+ globalThis.document = {};
435
+ globalThis.console = {
436
+ log: mock(),
437
+ // Missing other methods
438
+ } as unknown as Console;
439
+
440
+ const browserLogger = createLogger({ __forceType: 'browser' });
441
+
442
+ // Should fallback to console.log for missing methods
443
+ expect(() => browserLogger.info('Test')).not.toThrow();
444
+ expect(() => browserLogger.warn('Test')).not.toThrow();
445
+ });
446
+
447
+ it('should handle circular references in objects', () => {
448
+ type CircularObject = Record<string, unknown> & {
449
+ name: string;
450
+ circular?: CircularObject;
451
+ };
452
+ const obj: CircularObject = { name: 'test' };
453
+ obj.circular = obj;
454
+
455
+ const browserLogger = createLogger({ __forceType: 'browser' });
456
+ expect(() => browserLogger.info(obj, 'Circular reference')).not.toThrow();
457
+ });
458
+
459
+ it('should handle very long messages', () => {
460
+ const longMessage = 'x'.repeat(10000);
461
+ const browserLogger = createLogger({ __forceType: 'browser' });
462
+ expect(() => browserLogger.info(longMessage)).not.toThrow();
463
+ });
464
+
465
+ it('should handle null and undefined values', () => {
466
+ const browserLogger = createLogger({ __forceType: 'browser' });
467
+ expect(() => browserLogger.info(null, 'Null value')).not.toThrow();
468
+ expect(() => browserLogger.info(undefined, 'Undefined value')).not.toThrow();
469
+ expect(() => browserLogger.info({ value: null })).not.toThrow();
470
+ expect(() => browserLogger.info({ value: undefined })).not.toThrow();
471
+ });
472
+ });
473
+
474
+ describe('Memory Management', () => {
475
+ it('should limit in-memory log storage', () => {
476
+ // Setup browser environment first
477
+ globalThis.window = { document: {}, console: globalThis.console };
478
+ globalThis.document = {};
479
+ delete globalThis.process;
480
+
481
+ const browserLogger = createLogger({ __forceType: 'browser' });
482
+
483
+ // Log more than the max limit (1000 by default)
484
+ for (let i = 0; i < 1100; i++) {
485
+ browserLogger.info(`Message ${i}`);
486
+ }
487
+
488
+ // Should not crash and should maintain limit
489
+ expect(() => browserLogger.clear()).not.toThrow();
490
+ });
491
+
492
+ it('should respect custom maxMemoryLogs option', () => {
493
+ // Setup browser environment
494
+ globalThis.window = { document: {}, console: globalThis.console };
495
+ globalThis.document = {};
496
+ delete globalThis.process;
497
+
498
+ // Create logger with custom maxMemoryLogs
499
+ const customLimit = 50;
500
+ const browserLogger = createLogger({
501
+ __forceType: 'browser',
502
+ maxMemoryLogs: customLimit,
503
+ });
504
+
505
+ // Log more than the custom limit
506
+ for (let i = 0; i < customLimit + 10; i++) {
507
+ browserLogger.info(`Message ${i}`);
508
+ }
509
+
510
+ // Should not crash and should maintain custom limit
511
+ expect(() => browserLogger.clear()).not.toThrow();
512
+ });
513
+
514
+ it('should clear logs properly in both environments', () => {
515
+ // Browser
516
+ const mockClear = mock();
517
+ globalThis.window = { document: {}, console: { clear: mockClear } };
518
+ globalThis.document = {};
519
+ globalThis.console = { ...globalThis.console, clear: mockClear };
520
+ delete globalThis.process;
521
+
522
+ const browserLogger = createLogger({ __forceType: 'browser' });
523
+ browserLogger.clear();
524
+ expect(mockClear).toHaveBeenCalled();
525
+
526
+ // Node.js
527
+ globalThis.process =
528
+ originalProcess || ({ versions: { node: '20.0.0' }, env: {} } as unknown as typeof process);
529
+ delete globalThis.window;
530
+ const nodeLogger = createLogger();
531
+ expect(() => nodeLogger.clear()).not.toThrow();
532
+ });
533
+
534
+ it('should not throw when using __forceType binding in Node', () => {
535
+ globalThis.process =
536
+ originalProcess || ({ versions: { node: '20.0.0' }, env: {} } as unknown as typeof process);
537
+ delete globalThis.window;
538
+ delete globalThis.document;
539
+
540
+ expect(() =>
541
+ createLogger({
542
+ __forceType: 'node',
543
+ appName: 'test-app',
544
+ userId: '123',
545
+ })
546
+ ).not.toThrow();
547
+ });
548
+ });
549
+
550
+ describe('Circular Reference Handling - Advanced Edge Cases', () => {
551
+ it('should handle multiple circular references in different arguments', () => {
552
+ const browserLogger = createLogger({ __forceType: 'browser' });
553
+
554
+ // Create multiple objects with different circular patterns
555
+ const obj1: any = { name: 'obj1', data: { value: 1 } };
556
+ const obj2: any = { name: 'obj2', data: { value: 2 } };
557
+ const obj3: any = { name: 'obj3', data: { value: 3 } };
558
+
559
+ // Create circular references
560
+ obj1.self = obj1; // Self reference
561
+ obj2.ref = obj3; // Cross reference
562
+ obj3.ref = obj2; // Cross reference back
563
+ obj1.others = [obj2, obj3]; // Array with circular refs
564
+
565
+ // Should handle all without throwing
566
+ expect(() => browserLogger.info('Multiple circulars:', obj1, obj2, obj3)).not.toThrow();
567
+ });
568
+
569
+ it('should handle deeply nested circular references with arrays', () => {
570
+ const browserLogger = createLogger({ __forceType: 'browser' });
571
+
572
+ const deepObj: any = {
573
+ level1: {
574
+ level2: {
575
+ level3: {
576
+ level4: {
577
+ level5: {
578
+ items: [],
579
+ },
580
+ },
581
+ },
582
+ },
583
+ },
584
+ };
585
+
586
+ // Create complex circular structure
587
+ deepObj.level1.level2.level3.level4.level5.items.push(deepObj);
588
+ deepObj.level1.level2.level3.level4.level5.backToLevel2 = deepObj.level1.level2;
589
+ deepObj.level1.array = [deepObj, deepObj.level1, deepObj.level1.level2];
590
+
591
+ expect(() => browserLogger.info('Deep circular:', deepObj)).not.toThrow();
592
+ });
593
+
594
+ it('should handle circular references in error objects with nested arguments', () => {
595
+ const browserLogger = createLogger({ __forceType: 'browser' });
596
+
597
+ const error: any = new Error('Test error');
598
+ const context: any = { errorRef: error, data: {} };
599
+ const metadata: any = { context, timestamp: Date.now() };
600
+
601
+ // Create circular references
602
+ error.context = context;
603
+ context.data.metadata = metadata;
604
+ metadata.error = error;
605
+
606
+ // Multiple arguments with circular references
607
+ expect(() => browserLogger.error('Complex error:', error, context, metadata)).not.toThrow();
608
+ });
609
+
610
+ it('should handle circular references with symbols and special properties', () => {
611
+ const browserLogger = createLogger({ __forceType: 'browser' });
612
+
613
+ const sym = Symbol('test');
614
+ const obj: any = {
615
+ [sym]: 'symbol value',
616
+ normalProp: 'normal',
617
+ nested: {},
618
+ };
619
+
620
+ // Add various types of circular references
621
+ obj.nested.parent = obj;
622
+ obj[Symbol.for('circular')] = obj;
623
+ Object.defineProperty(obj, 'hiddenCircular', {
624
+ value: obj,
625
+ enumerable: false,
626
+ });
627
+
628
+ expect(() => browserLogger.info('Symbol circular:', obj)).not.toThrow();
629
+ });
630
+
631
+ it('should handle circular references in mixed argument types', () => {
632
+ const browserLogger = createLogger({ __forceType: 'browser' });
633
+
634
+ const arr: any[] = [1, 2, 3];
635
+ const obj: any = { arr, name: 'test' };
636
+ const map = new Map();
637
+ const set = new Set();
638
+
639
+ // Create complex circular structure
640
+ arr.push(obj);
641
+ obj.self = obj;
642
+ map.set('obj', obj);
643
+ map.set('arr', arr);
644
+ set.add(obj);
645
+ set.add(arr);
646
+ obj.map = map;
647
+ obj.set = set;
648
+
649
+ // Test with multiple mixed-type arguments
650
+ expect(() =>
651
+ browserLogger.info('Mixed types:', obj, arr, 'string', 123, map, set)
652
+ ).not.toThrow();
653
+ });
654
+
655
+ it('should handle circular references in function properties', () => {
656
+ const browserLogger = createLogger({ __forceType: 'browser' });
657
+
658
+ const obj: any = {
659
+ name: 'function container',
660
+ callback: function () {
661
+ return obj;
662
+ },
663
+ };
664
+
665
+ // Add circular reference through function
666
+ obj.callback.parent = obj;
667
+ obj.methods = {
668
+ get: () => obj,
669
+ set: (value: any) => {
670
+ obj.value = value;
671
+ return obj;
672
+ },
673
+ };
674
+ obj.methods.container = obj;
675
+
676
+ expect(() => browserLogger.info('Function circular:', obj)).not.toThrow();
677
+ });
678
+
679
+ it('should handle circular references with prototype chain manipulation', () => {
680
+ const browserLogger = createLogger({ __forceType: 'browser' });
681
+
682
+ class CustomClass {
683
+ constructor(public name: string) {}
684
+ }
685
+
686
+ const instance: any = new CustomClass('test');
687
+ const proto: any = Object.getPrototypeOf(instance);
688
+
689
+ // Create circular through prototype
690
+ instance.proto = proto;
691
+ proto.instance = instance;
692
+ instance.self = instance;
693
+
694
+ expect(() => browserLogger.info('Prototype circular:', instance)).not.toThrow();
695
+ });
696
+
697
+ it('should handle maximum recursion depth with circular references', () => {
698
+ const browserLogger = createLogger({ __forceType: 'browser' });
699
+
700
+ // Create a chain of objects with circular reference at the end
701
+ let current: any = { level: 0 };
702
+ const root = current;
703
+
704
+ for (let i = 1; i < 100; i++) {
705
+ current.next = { level: i, prev: current };
706
+ current = current.next;
707
+ }
708
+
709
+ // Add circular reference at the end
710
+ current.next = root;
711
+ root.tail = current;
712
+
713
+ expect(() => browserLogger.info('Deep chain circular:', root)).not.toThrow();
714
+ });
715
+ });
716
+ });