nwinread 1.1.1 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/README.md +767 -134
  2. package/binding.gyp +30 -0
  3. package/build/binding.sln +6 -0
  4. package/build/eventlogasync.vcxproj +148 -0
  5. package/build/eventlogasync.vcxproj.filters +43 -0
  6. package/doc/ASYNC_STATUS.md +104 -0
  7. package/doc/COHERENCIA_APIS.md +154 -0
  8. package/doc/CORRECCION_NAPI.md +74 -0
  9. package/doc/CPU_EFFICIENCY_GUIDE.md +199 -0
  10. package/doc/PREBUILDS.md +180 -0
  11. package/doc/README_eventlogasync.md +134 -0
  12. package/doc/RESUMABLE_READER.md +250 -0
  13. package/doc/USAGE.md +527 -0
  14. package/index.js +206 -5
  15. package/native/eventlogasync.cc +687 -0
  16. package/package.json +33 -6
  17. package/prebuilds/metadata.json +24 -0
  18. package/prebuilds/win32-x64/eventlog.node +0 -0
  19. package/prebuilds/win32-x64/eventlogasync.node +0 -0
  20. package/prebuilds/win32-x64/meta.json +20 -0
  21. package/prebuilds/win32-x64/nwinread.node +0 -0
  22. package/scripts/generate-prebuilds-advanced.js +186 -0
  23. package/scripts/generate-prebuilds.js +86 -0
  24. package/scripts/prebuilds/win32-x64/meta.json +20 -0
  25. package/test/README.md +105 -0
  26. package/test/example_async.js +107 -0
  27. package/test/example_sync.js +76 -0
  28. package/test/test_beginning_mode.js +40 -0
  29. package/test/test_build_version.js +46 -0
  30. package/test/test_callback_simple.js +46 -0
  31. package/test/test_modes_comparison.js +74 -0
  32. package/test/test_watermark_realistic.js +75 -0
  33. package/test/test_watermark_specific.js +88 -0
  34. package/test/test_wrapper_vs_native.js +58 -0
  35. package/test/verify_sync_events.js +19 -0
  36. package/CHANGES.md +0 -120
  37. package/test.js +0 -34
  38. /package/{CONTRIBUTING.md → doc/CONTRIBUTING.md} +0 -0
  39. /package/{NAPI-SETUP.md → doc/NAPI-SETUP.md} +0 -0
package/README.md CHANGED
@@ -1,202 +1,835 @@
1
1
  # nwinread - Windows Event Log Reader
2
2
 
3
- A native Node.js module for reading Windows event logs using the Windows Event Log API.
4
-
5
- **✨ Features:**
6
- - **Universal Binaries**: Built with N-API for compatibility across Node.js versions
7
- - **Precompiled Binaries**: No compilation needed on installation
8
- - **High Performance**: Native C++ implementation using Windows Event Log API
9
- - **Event Filtering**: Filter events by Event ID for efficient processing
10
- - **Multiple Read Modes**: Read from beginning, end, or specific position
3
+ [![npm version](https://img.shields.io/npm/v/nwinread.svg)](https://www.npmjs.com/package/nwinread)
4
+ [![npm downloads](https://img.shields.io/npm/dm/nwinread.svg)](https://www.npmjs.com/package/nwinread)
5
+ [![license](https://img.shields.io/npm/l/nwinread.svg)](https://github.com/solzimer/nwinread/blob/main/LICENSE)
6
+ [![Node.js version](https://img.shields.io/node/v/nwinread.svg)](https://www.npmjs.com/package/nwinread)
7
+
8
+ A high-performance native Node.js module for reading Windows event logs using the Windows Event Log API with both synchronous and asynchronous support.
9
+
10
+ ## Table of Contents
11
+
12
+ - [Features](#features)
13
+ - [Requirements](#requirements)
14
+ - [Installation](#installation)
15
+ - [Quick Start](#quick-start)
16
+ - [API Reference](#api-reference)
17
+ - [Common Use Cases](#common-use-cases)
18
+ - [Performance & Best Practices](#performance--best-practices)
19
+ - [Examples & Testing](#examples--testing)
20
+ - [Error Handling](#error-handling)
21
+ - [Troubleshooting](#troubleshooting)
22
+ - [Contributing](#contributing)
23
+ - [License](#license)
24
+
25
+ ## Features
26
+
27
+ - **🔥 Asynchronous Subscriptions**: Real-time event monitoring with zero polling
28
+ - **📚 Synchronous Reading**: One-time queries for batch processing
29
+ - **🎯 Smart Positioning**: Read from beginning, end, or specific Record ID (watermarks)
30
+ - **⚡ Event Filtering**: Filter by Event IDs for efficient processing
31
+ - **📋 Bookmark Support**: Resume from exact positions using Windows Event Log bookmarks
32
+ - **🛡️ Cross-Version Compatible**: Built with N-API for all Node.js versions 16+
33
+ - **🚀 Precompiled Binaries**: No compilation needed for standard installations
11
34
 
12
35
  ## Requirements
13
36
 
14
- - Windows Vista/7/8/10/11 or Windows Server 2008/2012/2016/2019/2022
15
- - **Node.js 16+** (recommended for precompiled binaries)
16
- - **Node.js 10-14** (requires local compilation)
37
+ - **Windows**: Vista/7/8/10/11 or Server 2008/2012/2016/2019/2022
38
+ - **Node.js**: 16+ (recommended for precompiled binaries)
39
+ - **Permissions**: Administrator privileges required for Security log only
17
40
 
18
- ### 🐎 **Node.js Version Support:**
41
+ ## Installation
19
42
 
20
- | Node.js | Status | Installation |
21
- |---------|--------|-------------|
22
- | **16.x** | ✅ **LTS** | Instant (precompiled) |
23
- | **18.x** | ✅ **LTS** | Instant (precompiled) |
24
- | **20.x** | ✅ **LTS** | Instant (precompiled) |
25
- | **22.x** | ✅ **Current** | Instant (precompiled) |
26
- | 10-14 | ⚠️ **EOL** | Requires build tools |
43
+ ```bash
44
+ npm install nwinread
45
+ ```
27
46
 
28
- **Build requirements (only for Node.js 10-14 or development):**
29
- - Visual Studio Build Tools or Visual Studio Community
30
- - Python (for node-gyp)
47
+ **Installs instantly** using precompiled binaries for Node.js 16+
31
48
 
32
- ## Installation
49
+ ## Quick Start
33
50
 
34
- ### 🚀 **Quick Install (Recommended)**
51
+ ### Synchronous Reading (One-time queries)
35
52
 
36
- ```bash
37
- npm install nwinread
53
+ ```javascript
54
+ const eventLog = require('nwinread');
55
+
56
+ // Read recent events
57
+ const recent = eventLog.readEvents(
58
+ "System", // Channel
59
+ eventLog.START_MODE.END, // From end
60
+ 0, // Watermark (ignored for END mode)
61
+ 10 // Max events
62
+ );
63
+
64
+ console.log(`Found ${recent.records.length} recent events`);
65
+ recent.records.forEach(event => {
66
+ console.log(`Record ID: ${event.recordId}`);
67
+ console.log(`Event XML: ${event.xml.substring(0, 100)}...`);
68
+ });
38
69
  ```
39
70
 
40
- **✅ For Node.js 16+**: Installs instantly using precompiled binaries
41
- **⚠️ For Node.js 10-14**: Automatically compiles from source (requires build tools)
71
+ ### Asynchronous Monitoring (Real-time)
42
72
 
43
- ### 🔧 **Development Install**
73
+ ```javascript
74
+ const eventLog = require('nwinread');
75
+
76
+ // Monitor new events in real-time
77
+ const subscription = eventLog.subscribeFromEnd(
78
+ 'Application',
79
+ (event) => {
80
+ console.log(`🆕 New event: ${event.recordId}`);
81
+ console.log(` XML: ${event.xml.substring(0, 150)}...`);
82
+ },
83
+ (error) => {
84
+ console.error(`❌ Error: ${error.message}`);
85
+ },
86
+ [1000, 1001] // Optional: filter by Event IDs
87
+ );
44
88
 
45
- ```bash
46
- git clone https://github.com/solzimer/nwinread.git
47
- cd nwinread
48
- npm install
49
- npm run build
50
- npm test
89
+ console.log(`✅ Monitoring started. Subscription ID: ${subscription.id}`);
90
+
91
+ // Stop monitoring after 30 seconds
92
+ setTimeout(() => {
93
+ subscription.unsubscribe();
94
+ console.log('✅ Monitoring stopped');
95
+ }, 30000);
96
+ ```
97
+
98
+ ## API Reference
99
+
100
+ ### Reading Modes
101
+
102
+ | Mode | Value | Description | Synchronous | Asynchronous |
103
+ |------|-------|-------------|-------------|--------------|
104
+ | **BEGINNING** | `0` | Start from oldest events | `readEvents()` | `subscribeFromBeginning()` |
105
+ | **END** | `1` | Start from newest/future events | `readEvents()` | `subscribeFromEnd()` |
106
+ | **WATERMARK** | `2` | Start from specific Record ID | `readEvents()` | `subscribeFromWatermark()` |
107
+
108
+ ### Synchronous API
109
+
110
+ #### `readEvents(channel, mode, watermark, maxEvents, eventIds)`
111
+
112
+ ```javascript
113
+ const eventLog = require('nwinread');
114
+
115
+ // Basic syntax
116
+ eventLog.readEvents(channel, mode, watermark, maxEvents, eventIds)
117
+
118
+ // Read from beginning
119
+ const oldest = eventLog.readEvents(
120
+ "Application",
121
+ eventLog.START_MODE.BEGINNING,
122
+ 0, // Watermark ignored for BEGINNING
123
+ 50 // Max events
124
+ );
125
+
126
+ // Read recent events
127
+ const recent = eventLog.readEvents(
128
+ "System",
129
+ eventLog.START_MODE.END,
130
+ 0, // Watermark ignored for END
131
+ 20
132
+ );
133
+
134
+ // Read from specific Record ID
135
+ const fromPoint = eventLog.readEvents(
136
+ "Application",
137
+ eventLog.START_MODE.WATERMARK,
138
+ 50000, // Start from Record ID 50000
139
+ 25
140
+ );
141
+
142
+ // Read with Event ID filter
143
+ const filtered = eventLog.readEvents(
144
+ "System",
145
+ eventLog.START_MODE.END,
146
+ 0,
147
+ 30,
148
+ [1074, 6005, 6006] // Only these Event IDs
149
+ );
51
150
  ```
52
- # Install dependencies
53
- npm install
54
151
 
55
- # Build native module
56
- npm run build
152
+ **Parameters:**
153
+ - `channel` (string): Event log channel ("System", "Application", "Security", etc.)
154
+ - `mode` (number): Reading mode (0=BEGINNING, 1=END, 2=WATERMARK)
155
+ - `watermark` (number): Starting Record ID for WATERMARK mode (ignored for other modes)
156
+ - `maxEvents` (number): Maximum events to return
157
+ - `eventIds` (array, optional): Array of Event IDs to filter by
57
158
 
58
- # Or build precompiled binaries
59
- npm run prebuildify
159
+ **Returns:** Object with `records` array and `lastRecordId`
160
+
161
+ ### Asynchronous API
162
+
163
+ #### `subscribe(channel, watermark, onEvent, onError, eventIds, mode)`
164
+
165
+ **Core subscription method with precise control:**
166
+
167
+ ```javascript
168
+ const subscription = eventLog.subscribe(
169
+ 'Application', // channel
170
+ 48000, // watermark (Record ID to start from)
171
+ (event) => { // onEvent callback
172
+ console.log(`Event: ${event.recordId}`);
173
+ // event.recordId - Record ID number
174
+ // event.xml - Full event XML
175
+ },
176
+ (error) => { // onError callback
177
+ console.log(`Error: ${error.message}`);
178
+ },
179
+ [1000, 1001], // eventIds filter (optional, null for all)
180
+ eventLog.START_MODE.WATERMARK // mode (0=BEGINNING, 1=END, 2=WATERMARK)
181
+ );
182
+
183
+ console.log(`Subscription ID: ${subscription.id}`);
184
+
185
+ // Always cleanup when done
186
+ subscription.unsubscribe();
60
187
  ```
61
188
 
62
- ## Usage
189
+ #### Helper Methods (Recommended)
190
+
191
+ **`subscribeFromEnd(channel, onEvent, onError, eventIds)`**
192
+
193
+ Monitor new events only (future events):
63
194
 
64
195
  ```javascript
65
- const nwinread = require('nwinread');
196
+ const subscription = eventLog.subscribeFromEnd(
197
+ 'System',
198
+ (event) => console.log(`New: ${event.recordId}`),
199
+ (error) => console.error(error.message),
200
+ [1074, 6005] // Optional Event ID filter
201
+ );
202
+ ```
203
+
204
+ **`subscribeFromBeginning(channel, onEvent, onError, eventIds)`**
66
205
 
67
- // Read events from the end of the log (all events)
68
- const result = nwinread.readEvents(
69
- 'System', // Channel (System, Application, Security, etc.)
70
- nwinread.START_MODE.END, // Read mode
71
- 0, // Watermark (for WATERMARK mode)
72
- 10 // Maximum number of events
206
+ Process all historical events + monitor new events:
207
+
208
+ ```javascript
209
+ const subscription = eventLog.subscribeFromBeginning(
210
+ 'Application',
211
+ (event) => console.log(`Historical/New: ${event.recordId}`),
212
+ (error) => console.error(error.message)
73
213
  );
214
+ ```
215
+
216
+ **`subscribeFromWatermark(channel, watermark, onEvent, onError, eventIds)`**
74
217
 
75
- // Read events with specific ID filter
76
- const filteredResult = nwinread.readEvents(
77
- 'System', // Channel
78
- nwinread.START_MODE.BEGINNING, // Read mode
79
- 0, // Watermark
80
- 20, // Maximum number of events
81
- [7045, 7034, 7036] // Event IDs filter (optional)
218
+ Resume from specific Record ID:
219
+
220
+ ```javascript
221
+ const subscription = eventLog.subscribeFromWatermark(
222
+ 'Application',
223
+ 50000, // Start from Record ID 50000
224
+ (event) => console.log(`From 50k: ${event.recordId}`),
225
+ (error) => console.error(error.message)
82
226
  );
227
+ ```
228
+
229
+ #### EventLogSubscription Object
230
+
231
+ All subscription methods return an `EventLogSubscription` object:
232
+
233
+ ```javascript
234
+ const subscription = eventLog.subscribeFromEnd('System', onEvent, onError);
235
+
236
+ // Properties
237
+ console.log(subscription.id); // Subscription ID (number)
238
+ console.log(subscription.channel); // Channel name (string)
239
+ console.log(subscription.watermark); // Starting watermark (number)
240
+ console.log(subscription.mode); // Reading mode (number)
241
+
242
+ // Methods
243
+ subscription.isActive(); // Returns true if subscription is active
244
+ subscription.getLastRecordId(); // Get last processed Record ID
245
+ subscription.unsubscribe(); // Stop subscription and clean up
246
+ ```
83
247
 
84
- console.log(`Found ${result.records.length} events`);
85
- console.log(`Last Record ID: ${result.lastRecordId}`);
248
+ #### EventEmitter Pattern
86
249
 
87
- console.log(`Filtered events: ${filteredResult.records.length}`);
250
+ ```javascript
251
+ const emitter = eventLog.createEventEmitter('System', {
252
+ mode: eventLog.START_MODE.END,
253
+ watermark: 0,
254
+ eventIds: [1074, 6005]
255
+ });
256
+
257
+ emitter.on('event', (event) => {
258
+ console.log(`Event: ${event.recordId}`);
259
+ });
260
+
261
+ emitter.on('error', (error) => {
262
+ console.error(`Error: ${error.message}`);
263
+ });
264
+
265
+ // Cleanup
266
+ emitter.unsubscribe();
267
+ ```
268
+
269
+ ## Common Use Cases
270
+
271
+ ### Real-time System Monitoring
272
+
273
+ ```javascript
274
+ const eventLog = require('nwinread');
275
+
276
+ // Monitor system shutdown/startup events
277
+ const systemMonitor = eventLog.subscribeFromEnd("System",
278
+ (event) => {
279
+ // Extract Event ID from XML
280
+ const eventIdMatch = event.xml.match(/<EventID.*?>(\d+)<\/EventID>/);
281
+ const eventId = eventIdMatch ? eventIdMatch[1] : 'unknown';
282
+
283
+ if (eventId === '1074') {
284
+ console.log(`🔄 System shutdown initiated - Record ID: ${event.recordId}`);
285
+ } else if (eventId === '6005') {
286
+ console.log(`✅ Event Log service started - Record ID: ${event.recordId}`);
287
+ }
288
+ },
289
+ (error) => console.error(`❌ Monitor error: ${error.message}`),
290
+ [1074, 6005, 6006] // Filter critical system events
291
+ );
88
292
 
89
- // Process events
90
- result.records.forEach((event, index) => {
91
- console.log(`Event ${index + 1}:`);
92
- console.log(` Record ID: ${event.recordId}`);
93
- console.log(` XML: ${event.xml.substring(0, 100)}...`);
293
+ // Keep monitoring until interrupted
294
+ process.on('SIGINT', () => {
295
+ console.log('\n🛑 Stopping system monitor...');
296
+ systemMonitor.unsubscribe();
297
+ process.exit(0);
94
298
  });
95
299
  ```
96
300
 
97
- ## Read modes
301
+ ### Application Error Monitoring
98
302
 
99
- - `START_MODE.BEGINNING` (0): Read from the beginning of the log
100
- - `START_MODE.END` (1): Read from the end of the log
101
- - `START_MODE.WATERMARK` (2): Read from a specific Record ID
303
+ ```javascript
304
+ // Monitor ALL application events (historical + new)
305
+ const appMonitor = eventLog.subscribeFromBeginning("Application",
306
+ (event) => {
307
+ // Look for error patterns in the XML
308
+ if (event.xml.includes('Error') || event.xml.includes('Exception')) {
309
+ console.log(`🚨 Application error detected:`);
310
+ console.log(` Record ID: ${event.recordId}`);
311
+ console.log(` Time: ${new Date().toISOString()}`);
312
+ console.log(` Preview: ${event.xml.substring(0, 200)}...`);
313
+ }
314
+ },
315
+ (error) => console.error(`❌ App monitor error: ${error.message}`)
316
+ );
102
317
 
103
- ## API
318
+ // Process for 1 minute then stop
319
+ setTimeout(() => {
320
+ appMonitor.unsubscribe();
321
+ console.log('✅ Application monitoring completed');
322
+ }, 60000);
323
+ ```
104
324
 
105
- ### readEvents(channel, mode, watermark, maxEvents, eventIds)
325
+ ### Resumable Processing with Watermarks
106
326
 
107
- - **channel** (string): Event channel name (e.g.: 'System', 'Application', 'Security')
108
- - **mode** (number): Read mode (use START_MODE constants)
109
- - **watermark** (number): Record ID to start from (only for WATERMARK mode)
110
- - **maxEvents** (number): Maximum number of events to read (1-10000)
111
- - **eventIds** (array|null, optional): Array of Event IDs to filter. If `null`, `undefined`, or empty array, no filter is applied
327
+ ```javascript
328
+ // Save last processed Record ID to resume later
329
+ let lastProcessedId = 48000; // Load from database/file in real usage
330
+
331
+ const processor = eventLog.subscribeFromWatermark("Application", lastProcessedId,
332
+ (event) => {
333
+ console.log(`📝 Processing event: ${event.recordId}`);
334
+
335
+ // Your business logic here
336
+ processEvent(event);
337
+
338
+ // Update watermark for next restart
339
+ lastProcessedId = event.recordId;
340
+ // Save to database/file in real usage
341
+
342
+ console.log(`✅ Processed ${event.recordId}, next watermark: ${lastProcessedId}`);
343
+ },
344
+ (error) => {
345
+ console.error(`❌ Processing error: ${error.message}`);
346
+ // Implement retry logic here
347
+ }
348
+ );
112
349
 
113
- **Returns:** Object with properties:
114
- - `records`: Array of events with `xml` and `recordId` properties
115
- - `lastRecordId`: ID of the last processed record
350
+ function processEvent(event) {
351
+ // Your event processing logic
352
+ // Database inserts, API calls, etc.
353
+ }
354
+ ```
116
355
 
117
- ### Event ID filtering examples
356
+ ### Historical Analysis
118
357
 
119
358
  ```javascript
120
- // No filter - all events
121
- const allEvents = nwinread.readEvents('System', nwinread.START_MODE.BEGINNING, 0, 10);
359
+ const eventLog = require('nwinread');
360
+
361
+ // Analyze large batch of historical events
362
+ function analyzeEvents() {
363
+ console.log('📊 Starting historical analysis...');
364
+
365
+ const events = eventLog.readEvents(
366
+ "System",
367
+ eventLog.START_MODE.BEGINNING,
368
+ 0,
369
+ 1000 // Analyze last 1000 events
370
+ );
371
+
372
+ let errorCount = 0;
373
+ let warningCount = 0;
374
+ let infoCount = 0;
375
+
376
+ events.records.forEach(event => {
377
+ // Simple level detection (Windows Event Levels: 1=Critical, 2=Error, 3=Warning, 4=Info)
378
+ if (event.xml.includes('Level>1<') || event.xml.includes('Level>2<')) {
379
+ errorCount++;
380
+ } else if (event.xml.includes('Level>3<')) {
381
+ warningCount++;
382
+ } else if (event.xml.includes('Level>4<')) {
383
+ infoCount++;
384
+ }
385
+ });
386
+
387
+ console.log(`📈 Analysis Results:`);
388
+ console.log(` Total events: ${events.records.length}`);
389
+ console.log(` Errors: ${errorCount}`);
390
+ console.log(` Warnings: ${warningCount}`);
391
+ console.log(` Information: ${infoCount}`);
392
+ console.log(` Last Record ID: ${events.lastRecordId}`);
393
+ }
394
+
395
+ analyzeEvents();
396
+ ```
122
397
 
123
- // Filter only Windows service events
124
- const serviceEvents = nwinread.readEvents('System', nwinread.START_MODE.BEGINNING, 0, 10, [7034, 7035, 7036, 7040, 7045]);
398
+ ## Event Channels & Common Event IDs
125
399
 
126
- // Filter specific critical events
127
- const criticalEvents = nwinread.readEvents('System', nwinread.START_MODE.BEGINNING, 0, 10, [1000, 1001, 1002]);
400
+ ### System Channel (No admin required)
128
401
 
129
- // Empty array = no filter (equivalent to null)
130
- const noFilter = nwinread.readEvents('System', nwinread.START_MODE.BEGINNING, 0, 10, []);
402
+ ```javascript
403
+ const SYSTEM_EVENTS = {
404
+ SHUTDOWN: 1074, // System shutdown initiated
405
+ UNEXPECTED_SHUTDOWN: 41, // System rebooted unexpectedly
406
+ EVENTLOG_START: 6005, // Event Log service started
407
+ EVENTLOG_STOP: 6006, // Event Log service stopped
408
+ TIME_CHANGE: 4621, // System time was changed
409
+ POWER_SLEEP: 42, // System entering sleep
410
+ POWER_WAKE: 107 // System wake from sleep
411
+ };
412
+
413
+ // Monitor critical system events
414
+ const systemSub = eventLog.subscribeFromEnd("System", onEvent, onError,
415
+ [1074, 41, 6005, 6006]
416
+ );
131
417
  ```
132
418
 
133
- ### Common Event IDs
419
+ ### Application Channel (No admin required)
134
420
 
135
- - **7034**: Service crashed
136
- - **7035**: Service start/stop control sent
137
- - **7036**: Service started/stopped
138
- - **7040**: Service startup type changed
139
- - **7045**: New service installed
140
- - **1000**: Application error
141
- - **1001**: Application hang
142
- - **4624**: Successful account logon (Security log)
143
- - **4625**: Failed account logon (Security log)
421
+ ```javascript
422
+ const APPLICATION_EVENTS = {
423
+ ERROR: 1000, // Application error
424
+ WARNING: 1001, // Application warning
425
+ INFORMATION: 1002 // Application information
426
+ // Note: Most applications use custom Event IDs
427
+ };
428
+
429
+ // Monitor all application events
430
+ const appSub = eventLog.subscribeFromEnd("Application", onEvent, onError);
431
+ ```
144
432
 
145
- ## Development & Release Process
433
+ ### Security Channel (Admin required)
146
434
 
147
- ### 🏗️ **For Contributors/Maintainers:**
435
+ ```javascript
436
+ const SECURITY_EVENTS = {
437
+ LOGIN_SUCCESS: 4624, // Successful logon
438
+ LOGIN_FAILURE: 4625, // Failed logon
439
+ LOGOUT: 4634, // Account logged off
440
+ ACCOUNT_LOCKED: 4740, // Account lockout
441
+ PRIVILEGE_USE: 4673, // Privileged service called
442
+ OBJECT_ACCESS: 4656 // Handle to object requested
443
+ };
444
+
445
+ // Monitor security events (requires admin privileges)
446
+ const securitySub = eventLog.subscribeFromEnd("Security", onEvent, onError,
447
+ [4624, 4625, 4634]
448
+ );
449
+ ```
148
450
 
149
- ```bash
150
- # Development workflow
151
- npm run build # Compile locally
152
- npm run prebuildify # Generate precompiled binary for current platform
153
- npm test # Run tests
154
- npm run verify # Verify complete setup
451
+ ## Performance & Best Practices
452
+
453
+ ### High Performance Tips
454
+
455
+ ```javascript
456
+ // 1. Use Event ID filters to reduce processing
457
+ const filtered = eventLog.subscribeFromEnd("System", onEvent, onError, [1074, 6005]);
458
+
459
+ // 2. Limit synchronous batch sizes
460
+ const limited = eventLog.readEvents("Application", eventLog.START_MODE.END, 0, 100);
461
+
462
+ // 3. Process events immediately, don't accumulate
463
+ const efficient = eventLog.subscribeFromEnd("Application",
464
+ (event) => {
465
+ // Process immediately
466
+ sendToDatabase(event);
467
+ // Don't store in arrays/collections
468
+ },
469
+ onError
470
+ );
471
+ ```
472
+
473
+ ### 🛡️ Reliable Processing
474
+
475
+ ```javascript
476
+ // 1. Always handle errors gracefully
477
+ const reliable = eventLog.subscribeFromEnd("Application",
478
+ (event) => {
479
+ try {
480
+ processEvent(event);
481
+ } catch (error) {
482
+ console.error(`Event processing error: ${error.message}`);
483
+ // Log error but continue processing other events
484
+ }
485
+ },
486
+ (error) => {
487
+ console.error(`Subscription error: ${error.message}`);
488
+
489
+ // Implement automatic recovery
490
+ setTimeout(() => {
491
+ console.log('🔄 Attempting to restart subscription...');
492
+ createNewSubscription();
493
+ }, 5000);
494
+ }
495
+ );
155
496
 
156
- # Release new version
157
- npm version [patch|minor|major] # Auto-generates prebuilds
158
- git push origin --tags # Triggers CI/CD for multi-platform builds
497
+ // 2. Clean shutdown handling
498
+ process.on('SIGINT', () => {
499
+ console.log('🛑 Gracefully shutting down...');
500
+ reliable.unsubscribe();
501
+ process.exit(0);
502
+ });
503
+
504
+ // 3. Save watermarks for recovery
505
+ let lastProcessedId = loadWatermarkFromFile();
506
+ const persistent = eventLog.subscribeFromWatermark("Application", lastProcessedId,
507
+ (event) => {
508
+ processEvent(event);
509
+ lastProcessedId = event.recordId;
510
+ saveWatermarkToFile(lastProcessedId); // Persist progress
511
+ },
512
+ onError
513
+ );
159
514
  ```
160
515
 
161
- ### 📦 **Publishing Process:**
516
+ ### 💾 Memory Management
162
517
 
163
- 1. **Local Testing**: `npm test && npm run verify`
164
- 2. **Version Bump**: `npm version patch` (auto-runs prebuildify)
165
- 3. **Push Release**: `git push origin --tags`
166
- 4. **CI/CD Magic**: GitHub Actions builds for all platforms & publishes automatically
518
+ ```javascript
519
+ // 1. Unsubscribe when done
520
+ const subscription = eventLog.subscribeFromEnd("System", onEvent, onError);
521
+
522
+ // Always cleanup
523
+ setTimeout(() => {
524
+ subscription.unsubscribe(); // Frees native resources
525
+ }, 30000);
526
+
527
+ // 2. Process events in streams, not collections
528
+ // ❌ Don't accumulate events
529
+ const events = [];
530
+ const badSub = eventLog.subscribeFromEnd("Application",
531
+ (event) => events.push(event), // Memory leak!
532
+ onError
533
+ );
167
534
 
168
- **Note**: The `prepublishOnly` script ensures binaries are generated before any npm publish.
535
+ // Process immediately
536
+ const goodSub = eventLog.subscribeFromEnd("Application",
537
+ (event) => {
538
+ processEventImmediately(event); // No accumulation
539
+ },
540
+ onError
541
+ );
542
+ ```
543
+
544
+ ## Examples & Testing
169
545
 
170
- ## Testing
546
+ The repository includes comprehensive examples in the `test/` directory:
171
547
 
172
548
  ```bash
549
+ # Test synchronous reading
550
+ node test/example_sync.js
551
+
552
+ # Test asynchronous monitoring
553
+ node test/example_async.js
554
+
555
+ # Test watermark functionality
556
+ node test/test_watermark_realistic.js
557
+
558
+ # Test all reading modes
173
559
  npm test
174
560
  ```
175
561
 
562
+ ### Example Files
563
+
564
+ - `test/example_sync.js` - Synchronous reading examples
565
+ - `test/example_async.js` - Asynchronous monitoring examples
566
+ - `test/test_watermark_realistic.js` - Watermark/bookmark functionality
567
+ - `test/test_watermark_realistic.js` - Find valid Record IDs for testing
568
+
569
+ ## Error Handling
570
+
571
+ ### Common Errors
572
+
573
+ ```javascript
574
+ // Channel not found
575
+ try {
576
+ const sub = eventLog.subscribeFromEnd("InvalidChannel", onEvent, onError);
577
+ } catch (error) {
578
+ if (error.code === 15007) {
579
+ console.log('❌ Channel not found - check channel name');
580
+ }
581
+ }
582
+
583
+ // Permission denied (for Security channel)
584
+ try {
585
+ const sub = eventLog.subscribeFromEnd("Security", onEvent, onError);
586
+ } catch (error) {
587
+ if (error.message.includes('access')) {
588
+ console.log('❌ Admin privileges required for Security log');
589
+ }
590
+ }
591
+
592
+ // Invalid Record ID
593
+ try {
594
+ const sub = eventLog.subscribeFromWatermark("Application", 999999999, onEvent, onError);
595
+ } catch (error) {
596
+ if (error.code === 15027) {
597
+ console.log('❌ Invalid Record ID - may be beyond available range');
598
+ }
599
+ }
600
+ ```
601
+
602
+ ### Error Codes
603
+
604
+ | Code | Meaning | Solution |
605
+ |------|---------|----------|
606
+ | 15007 | Channel not found | Check channel name ("System", "Application", etc.) |
607
+ | 15027 | Invalid query/Record ID | Use valid Record ID within available range |
608
+ | 87 | Invalid parameter | Check parameter types and values |
609
+ | 5 | Access denied | Run as administrator for Security log |
610
+
611
+ ## Advanced Usage
612
+
613
+ ### Custom Event Processing Pipeline
614
+
615
+ ```javascript
616
+ const eventLog = require('nwinread');
617
+
618
+ class EventProcessor {
619
+ constructor() {
620
+ this.stats = { processed: 0, errors: 0 };
621
+ this.subscription = null;
622
+ }
623
+
624
+ start() {
625
+ this.subscription = eventLog.subscribeFromEnd("Application",
626
+ (event) => this.processEvent(event),
627
+ (error) => this.handleError(error),
628
+ [1000, 1001, 1002] // Filter application events
629
+ );
630
+
631
+ console.log(`✅ Event processor started. Subscription: ${this.subscription.id}`);
632
+ }
633
+
634
+ processEvent(event) {
635
+ try {
636
+ // Parse event XML
637
+ const data = this.parseEventData(event);
638
+
639
+ // Business logic
640
+ this.handleApplicationEvent(data);
641
+
642
+ this.stats.processed++;
643
+
644
+ // Log progress
645
+ if (this.stats.processed % 100 === 0) {
646
+ console.log(`📊 Processed ${this.stats.processed} events`);
647
+ }
648
+
649
+ } catch (error) {
650
+ console.error(`❌ Processing error: ${error.message}`);
651
+ this.stats.errors++;
652
+ }
653
+ }
654
+
655
+ parseEventData(event) {
656
+ // Extract structured data from event XML
657
+ const eventIdMatch = event.xml.match(/<EventID.*?>(\d+)<\/EventID>/);
658
+ const timeMatch = event.xml.match(/<TimeCreated SystemTime='([^']+)'/);
659
+
660
+ return {
661
+ recordId: event.recordId,
662
+ eventId: eventIdMatch ? parseInt(eventIdMatch[1]) : null,
663
+ timestamp: timeMatch ? new Date(timeMatch[1]) : null,
664
+ xml: event.xml
665
+ };
666
+ }
667
+
668
+ handleApplicationEvent(data) {
669
+ switch(data.eventId) {
670
+ case 1000:
671
+ this.handleErrorEvent(data);
672
+ break;
673
+ case 1001:
674
+ this.handleWarningEvent(data);
675
+ break;
676
+ case 1002:
677
+ this.handleInfoEvent(data);
678
+ break;
679
+ default:
680
+ this.handleGenericEvent(data);
681
+ }
682
+ }
683
+
684
+ handleErrorEvent(data) {
685
+ console.log(`🚨 Application Error - Record ${data.recordId} at ${data.timestamp}`);
686
+ // Send alert, log to database, etc.
687
+ }
688
+
689
+ handleWarningEvent(data) {
690
+ console.log(`⚠️ Application Warning - Record ${data.recordId}`);
691
+ // Log to monitoring system
692
+ }
693
+
694
+ handleInfoEvent(data) {
695
+ console.log(`ℹ️ Application Info - Record ${data.recordId}`);
696
+ }
697
+
698
+ handleGenericEvent(data) {
699
+ console.log(`📄 Generic event ${data.eventId} - Record ${data.recordId}`);
700
+ }
701
+
702
+ handleError(error) {
703
+ console.error(`❌ Subscription error: ${error.message}`);
704
+ this.stats.errors++;
705
+
706
+ // Implement reconnection logic
707
+ setTimeout(() => {
708
+ console.log('🔄 Attempting to restart...');
709
+ this.start();
710
+ }, 5000);
711
+ }
712
+
713
+ getStats() {
714
+ return {
715
+ ...this.stats,
716
+ isActive: this.subscription && this.subscription.isActive()
717
+ };
718
+ }
719
+
720
+ stop() {
721
+ if (this.subscription) {
722
+ this.subscription.unsubscribe();
723
+ console.log(`✅ Event processor stopped. Final stats:`, this.getStats());
724
+ }
725
+ }
726
+ }
727
+
728
+ // Usage
729
+ const processor = new EventProcessor();
730
+ processor.start();
731
+
732
+ // Stop after 60 seconds
733
+ setTimeout(() => {
734
+ processor.stop();
735
+ }, 60000);
736
+
737
+ // Graceful shutdown
738
+ process.on('SIGINT', () => {
739
+ processor.stop();
740
+ process.exit(0);
741
+ });
742
+ ```
743
+
176
744
  ## Troubleshooting
177
745
 
178
- ### **Installation Issues**
746
+ ### Installation Issues
747
+
748
+ ```bash
749
+ # For Node.js 16+
750
+ npm install nwinread # Should install instantly
751
+
752
+ # If compilation is needed (Node.js < 16)
753
+ npm install --build-from-source
754
+
755
+ # Force rebuild if having issues
756
+ npm rebuild nwinread
757
+ ```
758
+
759
+ ### Runtime Issues
760
+
761
+ 1. **"Channel not found" error**
762
+ - Verify channel name: "System", "Application", "Security"
763
+ - Check Windows Event Viewer to confirm channel exists
764
+
765
+ 2. **"Access denied" for Security log**
766
+ - Run as Administrator: `Run as administrator` in Command Prompt
767
+ - Only Security log requires admin privileges
768
+
769
+ 3. **No events received in subscription**
770
+ - Check if events exist: use `readEvents()` first
771
+ - Verify Event ID filters are correct
772
+ - For Security channel: ensure admin privileges
773
+
774
+ 4. **"Invalid Record ID" for watermarks**
775
+ - Use `readEvents()` to find valid Record ID range
776
+ - Record IDs are not sequential and vary by channel
777
+
778
+ ### Debugging
779
+
780
+ ```javascript
781
+ // Enable debugging to see internal operations
782
+ const eventLog = require('nwinread');
783
+
784
+ // Test with small batch first
785
+ const test = eventLog.readEvents("Application", eventLog.START_MODE.END, 0, 5);
786
+ console.log(`Test result: ${test.records.length} events found`);
787
+
788
+ if (test.records.length > 0) {
789
+ console.log(`Record ID range: ${test.records[0].recordId} to ${test.lastRecordId}`);
790
+
791
+ // Now try subscription with known good Record ID
792
+ const sub = eventLog.subscribeFromWatermark("Application",
793
+ test.records[0].recordId,
794
+ (event) => console.log(`✅ Event: ${event.recordId}`),
795
+ (error) => console.log(`❌ Error: ${error.message}`)
796
+ );
797
+ }
798
+ ```
799
+
800
+ ## Contributing
801
+
802
+ This is a Windows-specific native module. Development requires:
803
+
804
+ - Windows development environment
805
+ - Visual Studio Build Tools
806
+ - Node.js 16+
807
+ - Windows Event Log for testing
808
+
809
+ ```bash
810
+ # Development setup
811
+ git clone https://github.com/solzimer/nwinread.git
812
+ cd nwinread
813
+ npm install
814
+ npm run rebuild
815
+
816
+ # Run tests
817
+ npm test
818
+
819
+ # Run examples
820
+ npm run examples
821
+ ```
179
822
 
180
- 1. **"Still compiling on install"**:
181
- - ✅ Update to Node.js 16+ for precompiled binaries
182
- - ✅ Check `npm ls nwinread` shows correct version
183
- - ✅ Try `npm cache clean --force && npm install`
823
+ ## Support
184
824
 
185
- 2. **"Module not found"**:
186
- - Ensure Windows platform (module is Windows-only)
187
- - Try `npm rebuild nwinread`
188
- - ✅ Check administrator privileges if needed
825
+ - 🐛 **Bug Reports**: [GitHub Issues](https://github.com/solzimer/nwinread/issues)
826
+ - 📖 **Documentation**: This README and inline code examples
827
+ - 💡 **Feature Requests**: [GitHub Issues](https://github.com/solzimer/nwinread/issues)
189
828
 
190
- ### **Runtime Issues**
829
+ ## Changelog
191
830
 
192
- 3. **Permission error**: Some logs require administrator privileges
193
- 4. **Channel not found**: Verify that the channel name is correct
194
- 5. **Old Node.js**: Update to Node.js 16+ for best experience
831
+ See [GitHub Releases](https://github.com/solzimer/nwinread/releases) for version history and changes.
195
832
 
196
- ## Common channels
833
+ ## License
197
834
 
198
- - `System`: System events
199
- - `Application`: Application events
200
- - `Security`: Security events (requires admin permissions)
201
- - `Setup`: Installation events
202
- - `Microsoft-Windows-PowerShell/Operational`: PowerShell events
835
+ MIT License - see LICENSE file for details.