@ceon-oy/monitor-sdk 1.0.1 → 1.0.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.
package/README.md CHANGED
@@ -1,10 +1,32 @@
1
- # Ceon Monitor - SDK
2
-
3
- Lightweight client SDK for sending errors and messages to the Ceon Monitor service.
1
+ # Ceon Monitor SDK
2
+
3
+ Lightweight client SDK for integrating with the Ceon Monitor service. Provides error reporting, technology tracking, vulnerability auditing, and security event monitoring.
4
+
5
+ ## Table of Contents
6
+
7
+ - [Installation](#installation)
8
+ - [Quick Start](#quick-start)
9
+ - [Configuration](#configuration)
10
+ - [Features](#features)
11
+ - [Error Capture](#error-capture)
12
+ - [Technology Tracking](#technology-tracking)
13
+ - [Vulnerability Auditing](#vulnerability-auditing)
14
+ - [Security Events](#security-events)
15
+ - [Framework Examples](#framework-examples)
16
+ - [Express.js](#expressjs)
17
+ - [Next.js](#nextjs)
18
+ - [React (Monolithic)](#react-monolithic)
19
+ - [React (Separate Server/Client)](#react-separate-serverclient)
20
+ - [API Reference](#api-reference)
21
+ - [Batching Behavior](#batching-behavior)
22
+ - [Building](#building)
4
23
 
5
24
  ## Installation
6
25
 
7
26
  ```bash
27
+ # From npm (recommended)
28
+ npm install @ceon-oy/monitor-sdk
29
+
8
30
  # From GitHub
9
31
  npm install github:ceon-oy/ceon-monitor-sdk
10
32
  ```
@@ -14,7 +36,7 @@ Or add to your `package.json`:
14
36
  ```json
15
37
  {
16
38
  "dependencies": {
17
- "@ceon/monitor-sdk": "github:ceon-oy/ceon-monitor-sdk"
39
+ "@ceon-oy/monitor-sdk": "^1.0.0"
18
40
  }
19
41
  }
20
42
  ```
@@ -26,13 +48,14 @@ Or add to your `package.json`:
26
48
  ## Quick Start
27
49
 
28
50
  ```typescript
29
- import { MonitorClient } from '@ceon/monitor-sdk';
51
+ import { MonitorClient } from '@ceon-oy/monitor-sdk';
30
52
 
31
53
  // Initialize the client
32
54
  const monitor = new MonitorClient({
33
- apiKey: process.env.MONITOR_API_KEY!,
55
+ apiKey: process.env.CEON_MONITOR_API_KEY!,
34
56
  endpoint: 'https://monitor.example.com',
35
57
  environment: process.env.NODE_ENV,
58
+ trackDependencies: true, // Auto-sync package.json
36
59
  });
37
60
 
38
61
  // Capture an error
@@ -51,6 +74,9 @@ await monitor.captureMessage('User signed up', 'INFO', {
51
74
  metadata: { userId: '123', plan: 'premium' },
52
75
  });
53
76
 
77
+ // Run vulnerability audit
78
+ await monitor.auditDependencies();
79
+
54
80
  // Flush and close before shutdown
55
81
  await monitor.close();
56
82
  ```
@@ -59,131 +85,253 @@ await monitor.close();
59
85
 
60
86
  ```typescript
61
87
  interface MonitorClientConfig {
62
- apiKey: string; // Your project API key
63
- endpoint: string; // Monitor service URL
64
- environment?: string; // Environment name (default: 'production')
65
- batchSize?: number; // Errors to batch before sending (default: 10)
66
- flushIntervalMs?: number; // Auto-flush interval in ms (default: 5000)
88
+ apiKey: string; // Your project API key (required)
89
+ endpoint: string; // Monitor service URL (required)
90
+ environment?: string; // Environment name (default: 'production')
91
+ batchSize?: number; // Errors to batch before sending (default: 10)
92
+ flushIntervalMs?: number; // Auto-flush interval in ms (default: 5000)
93
+ trackDependencies?: boolean; // Auto-sync package.json (default: false)
94
+ dependencySources?: { // Multiple package.json sources
95
+ path: string;
96
+ environment: string;
97
+ }[];
98
+ excludePatterns?: string[]; // Glob patterns to exclude (e.g., '@types/*')
67
99
  }
68
100
  ```
69
101
 
70
- ## API
71
-
72
- ### `MonitorClient`
73
-
74
- #### `constructor(config: MonitorClientConfig)`
75
-
76
- Creates a new monitor client instance.
102
+ ### Basic Configuration
77
103
 
78
104
  ```typescript
79
105
  const monitor = new MonitorClient({
80
- apiKey: 'cm_your_api_key_here',
106
+ apiKey: process.env.CEON_MONITOR_API_KEY!,
81
107
  endpoint: 'https://monitor.example.com',
82
108
  environment: 'production',
83
- batchSize: 10,
84
- flushIntervalMs: 5000,
85
109
  });
86
110
  ```
87
111
 
88
- #### `captureError(error: Error, context?: ErrorContext): Promise<void>`
112
+ ### Multi-Environment Dependency Tracking
89
113
 
90
- Captures an error and queues it for sending.
114
+ For projects with separate server and client folders:
91
115
 
92
116
  ```typescript
93
- await monitor.captureError(error, {
94
- severity: 'ERROR', // DEBUG, INFO, WARNING, ERROR, CRITICAL
95
- route: '/api/users', // API route or page path
96
- method: 'POST', // HTTP method
97
- statusCode: 500, // HTTP status code
98
- userAgent: req.headers['user-agent'],
99
- ip: req.ip,
100
- requestId: req.id,
101
- metadata: { // Any additional data
102
- userId: '123',
103
- action: 'create_user',
104
- },
117
+ const monitor = new MonitorClient({
118
+ apiKey: process.env.CEON_MONITOR_API_KEY!,
119
+ endpoint: 'https://monitor.example.com',
120
+ environment: 'server',
121
+ trackDependencies: true,
122
+ dependencySources: [
123
+ { path: './package.json', environment: 'server' },
124
+ { path: '../client/package.json', environment: 'client' },
125
+ ],
126
+ excludePatterns: ['@types/*'], // Filter out TypeScript type definitions
105
127
  });
106
128
  ```
107
129
 
108
- #### `captureMessage(message: string, severity?: Severity, context?: ErrorContext): Promise<void>`
130
+ ## Features
109
131
 
110
- Captures a log message.
132
+ ### Error Capture
133
+
134
+ #### Capture an Error
135
+
136
+ ```typescript
137
+ try {
138
+ // ... your code
139
+ } catch (error) {
140
+ await monitor.captureError(error as Error, {
141
+ severity: 'ERROR', // DEBUG, INFO, WARNING, ERROR, CRITICAL
142
+ route: '/api/users', // API route or page path
143
+ method: 'POST', // HTTP method
144
+ statusCode: 500, // HTTP status code
145
+ userAgent: req.headers['user-agent'],
146
+ ip: req.ip,
147
+ requestId: req.id,
148
+ metadata: { // Any additional data
149
+ userId: '123',
150
+ action: 'create_user',
151
+ },
152
+ });
153
+ }
154
+ ```
155
+
156
+ #### Capture a Message
111
157
 
112
158
  ```typescript
113
159
  await monitor.captureMessage('Payment processed', 'INFO', {
160
+ route: '/api/payments',
114
161
  metadata: { orderId: '456', amount: 99.99 },
115
162
  });
116
163
  ```
117
164
 
118
- #### `flush(): Promise<void>`
165
+ ### Technology Tracking
119
166
 
120
- Immediately sends all queued errors. Called automatically based on `flushIntervalMs` and `batchSize`.
167
+ #### Automatic Tracking
168
+
169
+ Enable `trackDependencies: true` to automatically sync your `package.json` dependencies:
121
170
 
122
171
  ```typescript
123
- await monitor.flush();
172
+ const monitor = new MonitorClient({
173
+ apiKey: process.env.CEON_MONITOR_API_KEY!,
174
+ endpoint: 'https://monitor.example.com',
175
+ trackDependencies: true,
176
+ });
124
177
  ```
125
178
 
126
- #### `close(): Promise<void>`
179
+ #### Manual Reporting
180
+
181
+ ```typescript
182
+ await monitor.reportTechnologies([
183
+ { name: 'node', version: '20.10.0', type: 'runtime' },
184
+ { name: 'express', version: '4.18.2', type: 'framework' },
185
+ { name: 'prisma', version: '5.0.0', type: 'database' },
186
+ ]);
187
+ ```
188
+
189
+ ### Vulnerability Auditing
127
190
 
128
- Flushes remaining errors and stops the client. Call this before your application shuts down.
191
+ Run npm audit and send results to the monitoring server:
129
192
 
130
193
  ```typescript
131
- await monitor.close();
194
+ // Basic audit
195
+ const result = await monitor.auditDependencies();
196
+
197
+ if (result) {
198
+ console.log(`Scan complete: ${result.processed} vulnerabilities found`);
199
+ console.log(`Critical: ${result.summary.critical}, High: ${result.summary.high}`);
200
+ }
201
+
202
+ // Audit a specific project directory
203
+ await monitor.auditDependencies({
204
+ projectPath: '/path/to/project',
205
+ environment: 'production',
206
+ });
207
+ ```
208
+
209
+ #### Scheduled Auditing
210
+
211
+ ```typescript
212
+ // Run on app startup
213
+ monitor.auditDependencies();
214
+
215
+ // Run daily via cron
216
+ import cron from 'node-cron';
217
+
218
+ cron.schedule('0 3 * * *', async () => {
219
+ await monitor.auditDependencies();
220
+ });
221
+
222
+ // Or using setInterval
223
+ setInterval(async () => {
224
+ await monitor.auditDependencies();
225
+ }, 24 * 60 * 60 * 1000); // Daily
132
226
  ```
133
227
 
134
- ## Usage Examples
228
+ ### Security Events
135
229
 
136
- ### Express.js Error Handler
230
+ #### Report Security Event
137
231
 
138
232
  ```typescript
139
- import { MonitorClient } from '@ceon/monitor-sdk';
140
- import { ErrorRequestHandler } from 'express';
233
+ await monitor.reportSecurityEvent({
234
+ eventType: 'FAILED_LOGIN',
235
+ category: 'AUTHENTICATION',
236
+ severity: 'MEDIUM',
237
+ ip: '192.168.1.1',
238
+ identifier: 'user@example.com',
239
+ metadata: { attempts: 3 },
240
+ });
241
+ ```
242
+
243
+ #### Check for Brute Force
244
+
245
+ ```typescript
246
+ const result = await monitor.checkBruteForce({
247
+ ip: '192.168.1.1',
248
+ identifier: 'user@example.com',
249
+ threshold: 5,
250
+ windowMinutes: 15,
251
+ });
252
+
253
+ if (result.blocked) {
254
+ // Block the request
255
+ throw new Error('Too many attempts. Please try again later.');
256
+ }
257
+ ```
258
+
259
+ ## Framework Examples
141
260
 
261
+ ### Express.js
262
+
263
+ ```typescript
264
+ import express from 'express';
265
+ import { MonitorClient } from '@ceon-oy/monitor-sdk';
266
+
267
+ const app = express();
142
268
  const monitor = new MonitorClient({
143
- apiKey: process.env.MONITOR_API_KEY!,
144
- endpoint: process.env.MONITOR_ENDPOINT!,
269
+ apiKey: process.env.CEON_MONITOR_API_KEY!,
270
+ endpoint: process.env.CEON_MONITOR_ENDPOINT!,
145
271
  environment: process.env.NODE_ENV,
272
+ trackDependencies: true,
273
+ });
274
+
275
+ // Your routes
276
+ app.get('/api/health', (req, res) => {
277
+ res.json({ status: 'ok' });
146
278
  });
147
279
 
148
- export const errorHandler: ErrorRequestHandler = (err, req, res, next) => {
280
+ // Error handling middleware
281
+ app.use((err: Error, req: express.Request, res: express.Response, next: express.NextFunction) => {
149
282
  monitor.captureError(err, {
150
283
  route: req.path,
151
284
  method: req.method,
152
- statusCode: res.statusCode || 500,
153
- userAgent: req.headers['user-agent'],
285
+ statusCode: 500,
286
+ userAgent: req.get('user-agent'),
154
287
  ip: req.ip,
155
- metadata: {
156
- query: req.query,
157
- body: req.body,
158
- },
159
288
  });
160
-
161
289
  res.status(500).json({ error: 'Internal server error' });
162
- };
290
+ });
163
291
 
164
292
  // Graceful shutdown
165
293
  process.on('SIGTERM', async () => {
166
294
  await monitor.close();
167
295
  process.exit(0);
168
296
  });
297
+
298
+ app.listen(3001, () => console.log('Server running on port 3001'));
299
+ ```
300
+
301
+ ### Next.js
302
+
303
+ **1. Create a monitor utility (`lib/monitor.ts`):**
304
+
305
+ ```typescript
306
+ import { MonitorClient } from '@ceon-oy/monitor-sdk';
307
+
308
+ let monitor: MonitorClient | null = null;
309
+
310
+ export function getMonitor(): MonitorClient {
311
+ if (!monitor) {
312
+ monitor = new MonitorClient({
313
+ apiKey: process.env.CEON_MONITOR_API_KEY!,
314
+ endpoint: process.env.CEON_MONITOR_ENDPOINT || 'https://your-monitor-server.com',
315
+ environment: process.env.NODE_ENV || 'development',
316
+ trackDependencies: true,
317
+ });
318
+ }
319
+ return monitor;
320
+ }
169
321
  ```
170
322
 
171
- ### Next.js API Route
323
+ **2. Use in API routes (`app/api/example/route.ts`):**
172
324
 
173
325
  ```typescript
174
- import { MonitorClient } from '@ceon/monitor-sdk';
175
326
  import { NextRequest, NextResponse } from 'next/server';
327
+ import { getMonitor } from '@/lib/monitor';
176
328
 
177
- const monitor = new MonitorClient({
178
- apiKey: process.env.MONITOR_API_KEY!,
179
- endpoint: process.env.MONITOR_ENDPOINT!,
180
- environment: process.env.NODE_ENV,
181
- });
329
+ export async function POST(request: NextRequest) {
330
+ const monitor = getMonitor();
182
331
 
183
- export async function POST(req: NextRequest) {
184
332
  try {
185
- const body = await req.json();
186
- // ... handle request
333
+ const body = await request.json();
334
+ // Your logic here
187
335
  return NextResponse.json({ success: true });
188
336
  } catch (error) {
189
337
  await monitor.captureError(error as Error, {
@@ -191,35 +339,377 @@ export async function POST(req: NextRequest) {
191
339
  method: 'POST',
192
340
  statusCode: 500,
193
341
  });
194
- return NextResponse.json({ error: 'Internal error' }, { status: 500 });
342
+ return NextResponse.json({ error: 'Internal server error' }, { status: 500 });
343
+ }
344
+ }
345
+ ```
346
+
347
+ **3. Global error handling (`app/error.tsx`):**
348
+
349
+ ```typescript
350
+ 'use client';
351
+
352
+ import { useEffect } from 'react';
353
+
354
+ export default function Error({
355
+ error,
356
+ reset,
357
+ }: {
358
+ error: Error & { digest?: string };
359
+ reset: () => void;
360
+ }) {
361
+ useEffect(() => {
362
+ fetch('/api/log-error', {
363
+ method: 'POST',
364
+ headers: { 'Content-Type': 'application/json' },
365
+ body: JSON.stringify({
366
+ message: error.message,
367
+ stack: error.stack,
368
+ digest: error.digest,
369
+ }),
370
+ });
371
+ }, [error]);
372
+
373
+ return (
374
+ <div>
375
+ <h2>Something went wrong!</h2>
376
+ <button onClick={() => reset()}>Try again</button>
377
+ </div>
378
+ );
379
+ }
380
+ ```
381
+
382
+ **4. Create error logging API route (`app/api/log-error/route.ts`):**
383
+
384
+ ```typescript
385
+ import { NextRequest, NextResponse } from 'next/server';
386
+ import { getMonitor } from '@/lib/monitor';
387
+
388
+ export async function POST(request: NextRequest) {
389
+ const monitor = getMonitor();
390
+ const { message, stack, digest } = await request.json();
391
+
392
+ await monitor.captureMessage(message, 'ERROR', {
393
+ metadata: { stack, digest, source: 'client' },
394
+ });
395
+
396
+ return NextResponse.json({ logged: true });
397
+ }
398
+ ```
399
+
400
+ ### React (Monolithic)
401
+
402
+ For a React project with Express backend in the same folder:
403
+
404
+ ```
405
+ my-app/
406
+ ├── package.json
407
+ ├── src/
408
+ │ ├── client/ # React frontend
409
+ │ └── server/ # Express backend
410
+ ```
411
+
412
+ **Server (`src/server/index.ts`):**
413
+
414
+ ```typescript
415
+ import express from 'express';
416
+ import path from 'path';
417
+ import { MonitorClient } from '@ceon-oy/monitor-sdk';
418
+
419
+ const app = express();
420
+ app.use(express.json());
421
+
422
+ const monitor = new MonitorClient({
423
+ apiKey: process.env.CEON_MONITOR_API_KEY!,
424
+ endpoint: process.env.CEON_MONITOR_ENDPOINT!,
425
+ environment: process.env.NODE_ENV || 'development',
426
+ trackDependencies: true,
427
+ });
428
+
429
+ // Client error logging endpoint
430
+ app.post('/api/log-client-error', async (req, res) => {
431
+ const { message, stack, componentStack } = req.body;
432
+ await monitor.captureMessage(message, 'ERROR', {
433
+ metadata: { stack, componentStack, source: 'client' },
434
+ });
435
+ res.json({ logged: true });
436
+ });
437
+
438
+ // Global error handler
439
+ app.use((err: Error, req: express.Request, res: express.Response, next: express.NextFunction) => {
440
+ monitor.captureError(err, {
441
+ route: req.path,
442
+ method: req.method,
443
+ statusCode: 500,
444
+ });
445
+ res.status(500).json({ error: 'Internal server error' });
446
+ });
447
+
448
+ // Graceful shutdown
449
+ process.on('SIGTERM', async () => {
450
+ await monitor.close();
451
+ process.exit(0);
452
+ });
453
+
454
+ app.listen(3001, () => console.log('Server running on port 3001'));
455
+ ```
456
+
457
+ **React Error Boundary (`src/client/ErrorBoundary.tsx`):**
458
+
459
+ ```typescript
460
+ import React, { Component, ErrorInfo, ReactNode } from 'react';
461
+
462
+ interface Props {
463
+ children: ReactNode;
464
+ }
465
+
466
+ interface State {
467
+ hasError: boolean;
468
+ }
469
+
470
+ class ErrorBoundary extends Component<Props, State> {
471
+ constructor(props: Props) {
472
+ super(props);
473
+ this.state = { hasError: false };
474
+ }
475
+
476
+ static getDerivedStateFromError(): State {
477
+ return { hasError: true };
478
+ }
479
+
480
+ componentDidCatch(error: Error, errorInfo: ErrorInfo) {
481
+ fetch('/api/log-client-error', {
482
+ method: 'POST',
483
+ headers: { 'Content-Type': 'application/json' },
484
+ body: JSON.stringify({
485
+ message: error.message,
486
+ stack: error.stack,
487
+ componentStack: errorInfo.componentStack,
488
+ }),
489
+ });
490
+ }
491
+
492
+ render() {
493
+ if (this.state.hasError) {
494
+ return <h1>Something went wrong.</h1>;
495
+ }
496
+ return this.props.children;
195
497
  }
196
498
  }
499
+
500
+ export default ErrorBoundary;
501
+ ```
502
+
503
+ ### React (Separate Server/Client)
504
+
505
+ For projects with separate server and client folders:
506
+
507
+ ```
508
+ my-project/
509
+ ├── server/
510
+ │ ├── package.json
511
+ │ └── src/index.ts
512
+ └── client/
513
+ ├── package.json
514
+ └── src/
197
515
  ```
198
516
 
199
- ### Integration with Existing Logger
517
+ **Server (`server/src/index.ts`):**
200
518
 
201
519
  ```typescript
202
- import { MonitorClient } from '@ceon/monitor-sdk';
520
+ import express from 'express';
521
+ import cors from 'cors';
522
+ import { MonitorClient } from '@ceon-oy/monitor-sdk';
523
+
524
+ const app = express();
525
+ app.use(cors());
526
+ app.use(express.json());
203
527
 
528
+ // Multi-environment dependency tracking
204
529
  const monitor = new MonitorClient({
205
- apiKey: process.env.MONITOR_API_KEY!,
206
- endpoint: process.env.MONITOR_ENDPOINT!,
530
+ apiKey: process.env.CEON_MONITOR_API_KEY!,
531
+ endpoint: process.env.CEON_MONITOR_ENDPOINT!,
532
+ environment: process.env.NODE_ENV || 'development',
533
+ trackDependencies: true,
534
+ dependencySources: [
535
+ { path: './package.json', environment: 'server' },
536
+ { path: '../client/package.json', environment: 'client' },
537
+ ],
538
+ excludePatterns: ['@types/*'],
539
+ });
540
+
541
+ // Endpoint for client-side error logging
542
+ app.post('/api/log-error', async (req, res) => {
543
+ const { message, stack, componentStack, url, userAgent } = req.body;
544
+
545
+ await monitor.captureMessage(message, 'ERROR', {
546
+ route: url,
547
+ metadata: { stack, componentStack, userAgent, source: 'client' },
548
+ });
549
+
550
+ res.json({ logged: true });
551
+ });
552
+
553
+ // Global error handler
554
+ app.use((err: Error, req: express.Request, res: express.Response, next: express.NextFunction) => {
555
+ monitor.captureError(err, {
556
+ route: req.path,
557
+ method: req.method,
558
+ statusCode: 500,
559
+ userAgent: req.get('user-agent'),
560
+ ip: req.ip,
561
+ });
562
+ res.status(500).json({ error: 'Internal server error' });
207
563
  });
208
564
 
209
- // Wrap your existing logger
210
- export function logError(message: string, error?: Error, context?: object) {
211
- // Your existing logging
212
- console.error(message, error);
565
+ // Graceful shutdown
566
+ process.on('SIGTERM', async () => {
567
+ await monitor.close();
568
+ process.exit(0);
569
+ });
570
+
571
+ app.listen(3001, () => console.log('Server running on port 3001'));
572
+ ```
573
+
574
+ **React Error Boundary (`client/src/components/ErrorBoundary.tsx`):**
213
575
 
214
- // Also send to monitor
215
- if (error) {
216
- monitor.captureError(error, { metadata: context });
217
- } else {
218
- monitor.captureMessage(message, 'ERROR', { metadata: context });
576
+ ```typescript
577
+ import React, { Component, ErrorInfo, ReactNode } from 'react';
578
+
579
+ interface Props {
580
+ children: ReactNode;
581
+ }
582
+
583
+ interface State {
584
+ hasError: boolean;
585
+ error: Error | null;
586
+ }
587
+
588
+ class ErrorBoundary extends Component<Props, State> {
589
+ constructor(props: Props) {
590
+ super(props);
591
+ this.state = { hasError: false, error: null };
592
+ }
593
+
594
+ static getDerivedStateFromError(error: Error): State {
595
+ return { hasError: true, error };
596
+ }
597
+
598
+ componentDidCatch(error: Error, errorInfo: ErrorInfo) {
599
+ fetch(`${process.env.REACT_APP_API_URL}/api/log-error`, {
600
+ method: 'POST',
601
+ headers: { 'Content-Type': 'application/json' },
602
+ body: JSON.stringify({
603
+ message: error.message,
604
+ stack: error.stack,
605
+ componentStack: errorInfo.componentStack,
606
+ url: window.location.href,
607
+ userAgent: navigator.userAgent,
608
+ }),
609
+ }).catch(console.error);
610
+ }
611
+
612
+ render() {
613
+ if (this.state.hasError) {
614
+ return (
615
+ <div>
616
+ <h1>Something went wrong</h1>
617
+ <button onClick={() => window.location.reload()}>Reload Page</button>
618
+ </div>
619
+ );
620
+ }
621
+ return this.props.children;
219
622
  }
220
623
  }
624
+
625
+ export default ErrorBoundary;
626
+ ```
627
+
628
+ **Global error handlers (`client/src/index.tsx`):**
629
+
630
+ ```typescript
631
+ import React from 'react';
632
+ import ReactDOM from 'react-dom/client';
633
+ import App from './App';
634
+ import ErrorBoundary from './components/ErrorBoundary';
635
+
636
+ // Global error handlers
637
+ window.onerror = (message, source, lineno, colno, error) => {
638
+ fetch(`${process.env.REACT_APP_API_URL}/api/log-error`, {
639
+ method: 'POST',
640
+ headers: { 'Content-Type': 'application/json' },
641
+ body: JSON.stringify({
642
+ message: String(message),
643
+ stack: error?.stack,
644
+ url: window.location.href,
645
+ userAgent: navigator.userAgent,
646
+ }),
647
+ }).catch(console.error);
648
+ };
649
+
650
+ window.onunhandledrejection = (event) => {
651
+ fetch(`${process.env.REACT_APP_API_URL}/api/log-error`, {
652
+ method: 'POST',
653
+ headers: { 'Content-Type': 'application/json' },
654
+ body: JSON.stringify({
655
+ message: event.reason?.message || 'Unhandled Promise Rejection',
656
+ stack: event.reason?.stack,
657
+ url: window.location.href,
658
+ userAgent: navigator.userAgent,
659
+ }),
660
+ }).catch(console.error);
661
+ };
662
+
663
+ const root = ReactDOM.createRoot(document.getElementById('root')!);
664
+ root.render(
665
+ <React.StrictMode>
666
+ <ErrorBoundary>
667
+ <App />
668
+ </ErrorBoundary>
669
+ </React.StrictMode>
670
+ );
221
671
  ```
222
672
 
673
+ ## API Reference
674
+
675
+ ### `MonitorClient`
676
+
677
+ #### `constructor(config: MonitorClientConfig)`
678
+
679
+ Creates a new monitor client instance.
680
+
681
+ #### `captureError(error: Error, context?: ErrorContext): Promise<void>`
682
+
683
+ Captures an error and queues it for sending.
684
+
685
+ #### `captureMessage(message: string, severity?: Severity, context?: ErrorContext): Promise<void>`
686
+
687
+ Captures a log message with optional severity level.
688
+
689
+ #### `reportTechnologies(technologies: Technology[]): Promise<void>`
690
+
691
+ Reports technology stack information.
692
+
693
+ #### `reportSecurityEvent(event: SecurityEvent): Promise<void>`
694
+
695
+ Reports a security event.
696
+
697
+ #### `checkBruteForce(params: BruteForceParams): Promise<BruteForceResult>`
698
+
699
+ Checks for brute force attacks.
700
+
701
+ #### `auditDependencies(options?: AuditOptions): Promise<AuditResult | null>`
702
+
703
+ Runs npm audit and sends results to the server.
704
+
705
+ #### `flush(): Promise<void>`
706
+
707
+ Immediately sends all queued errors.
708
+
709
+ #### `close(): Promise<void>`
710
+
711
+ Flushes remaining errors and stops the client.
712
+
223
713
  ## Batching Behavior
224
714
 
225
715
  The SDK batches errors to reduce network overhead:
@@ -231,9 +721,9 @@ The SDK batches errors to reduce network overhead:
231
721
  - `flush()` is called manually
232
722
  - `close()` is called
233
723
 
234
- For serverless/edge environments where the process may terminate quickly, consider:
235
- - Setting `batchSize: 1` to send immediately
236
- - Calling `await monitor.flush()` at the end of each request
724
+ For serverless/edge environments where the process may terminate quickly:
725
+ - Set `batchSize: 1` to send immediately
726
+ - Call `await monitor.flush()` at the end of each request
237
727
 
238
728
  ## Building
239
729
 
@@ -258,4 +748,24 @@ interface ErrorContext {
258
748
  requestId?: string;
259
749
  metadata?: Record<string, unknown>;
260
750
  }
751
+
752
+ interface Technology {
753
+ name: string;
754
+ version: string;
755
+ type: 'runtime' | 'framework' | 'library' | 'database' | 'tool' | 'other';
756
+ environment?: string;
757
+ }
758
+
759
+ interface SecurityEvent {
760
+ eventType: string;
761
+ category: 'AUTHENTICATION' | 'AUTHORIZATION' | 'RATE_LIMIT' | 'SUSPICIOUS_ACTIVITY' | 'DATA_ACCESS';
762
+ severity: 'LOW' | 'MEDIUM' | 'HIGH' | 'CRITICAL';
763
+ ip?: string;
764
+ identifier?: string;
765
+ metadata?: Record<string, unknown>;
766
+ }
261
767
  ```
768
+
769
+ ## License
770
+
771
+ MIT
package/dist/index.js CHANGED
@@ -458,16 +458,24 @@ var MonitorClient = class {
458
458
  * @returns Audit summary with vulnerability counts
459
459
  */
460
460
  async auditDependencies(options = {}) {
461
- if (typeof require === "undefined") {
462
- console.warn("[MonitorClient] auditDependencies only works in Node.js environment");
461
+ if (typeof window !== "undefined" || typeof document !== "undefined") {
462
+ console.warn("[MonitorClient] auditDependencies only works in Node.js server environment");
463
+ return null;
464
+ }
465
+ let execSync;
466
+ let path;
467
+ let fs;
468
+ try {
469
+ execSync = require("child_process").execSync;
470
+ path = require("path");
471
+ fs = require("fs");
472
+ } catch {
473
+ console.warn("[MonitorClient] auditDependencies requires Node.js (not available in bundled/browser environments)");
463
474
  return null;
464
475
  }
465
476
  const startTime = Date.now();
466
477
  const environment = options.environment || this.environment;
467
478
  try {
468
- const { execSync } = require("child_process");
469
- const path = require("path");
470
- const fs = require("fs");
471
479
  let projectPath = options.projectPath || process.cwd();
472
480
  if (projectPath.includes("\0") || /[;&|`$(){}[\]<>]/.test(projectPath)) {
473
481
  console.error("[MonitorClient] Invalid projectPath: contains forbidden characters");
package/dist/index.mjs CHANGED
@@ -429,16 +429,24 @@ var MonitorClient = class {
429
429
  * @returns Audit summary with vulnerability counts
430
430
  */
431
431
  async auditDependencies(options = {}) {
432
- if (typeof __require === "undefined") {
433
- console.warn("[MonitorClient] auditDependencies only works in Node.js environment");
432
+ if (typeof window !== "undefined" || typeof document !== "undefined") {
433
+ console.warn("[MonitorClient] auditDependencies only works in Node.js server environment");
434
+ return null;
435
+ }
436
+ let execSync;
437
+ let path;
438
+ let fs;
439
+ try {
440
+ execSync = __require("child_process").execSync;
441
+ path = __require("path");
442
+ fs = __require("fs");
443
+ } catch {
444
+ console.warn("[MonitorClient] auditDependencies requires Node.js (not available in bundled/browser environments)");
434
445
  return null;
435
446
  }
436
447
  const startTime = Date.now();
437
448
  const environment = options.environment || this.environment;
438
449
  try {
439
- const { execSync } = __require("child_process");
440
- const path = __require("path");
441
- const fs = __require("fs");
442
450
  let projectPath = options.projectPath || process.cwd();
443
451
  if (projectPath.includes("\0") || /[;&|`$(){}[\]<>]/.test(projectPath)) {
444
452
  console.error("[MonitorClient] Invalid projectPath: contains forbidden characters");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ceon-oy/monitor-sdk",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "description": "Client SDK for Ceon Monitor - Error tracking, health monitoring, security events, and vulnerability scanning",
5
5
  "author": "Ceon",
6
6
  "license": "MIT",