nwinread 1.0.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.
package/.gitattributes ADDED
@@ -0,0 +1,2 @@
1
+ # Auto detect text files and perform LF normalization
2
+ * text=auto
package/CHANGES.md ADDED
@@ -0,0 +1,120 @@
1
+ # Resumen de Correcciones - nwinread
2
+
3
+ ## Limpieza de Archivos (8 de febrero de 2026)
4
+
5
+ ### Archivos Eliminados
6
+ - `native/eventlog_new.cc` - Archivo temporal de desarrollo
7
+ - `native/eventlog_simple.cc` - Archivo temporal de desarrollo
8
+ - `native/binding.gyp` - Duplicado innecesario
9
+ - `native/build/` - Carpeta de build duplicada
10
+ - `native/node_modules/` - Dependencias duplicadas
11
+
12
+ ### Archivos Agregados
13
+ - `.gitignore` - Para mantener el repositorio limpio
14
+
15
+ ### Estructura Final Limpia
16
+ ```
17
+ nwinread/
18
+ ├── binding.gyp # Configuración de build
19
+ ├── index.js # API principal
20
+ ├── package.json # Configuración del proyecto
21
+ ├── README.md # Documentación
22
+ ├── test.js # Pruebas
23
+ ├── CHANGES.md # Este archivo
24
+ ├── .gitignore # Archivos a ignorar en git
25
+ ├── native/
26
+ │ └── eventlog.cc # Código fuente C++
27
+ └── build/ # Resultado de compilación
28
+ └── Release/
29
+ └── eventlog.node
30
+ ```
31
+
32
+ ## Problemas Encontrados y Solucionados
33
+
34
+ ### 1. **Inconsistencia en nombres de funciones**
35
+ - **Problema**: En `index.js` se llamaba `native.readEvents()` pero en C++ se exportaba como `read`
36
+ - **Solución**: Corregido para usar `native.read()` con parámetros individuales
37
+
38
+ ### 2. **Problemas de compilación con node-addon-api**
39
+ - **Problema**: Errores de sintaxis con la versión 8.x de node-addon-api
40
+ - **Solución**: Migrado a Node-API puro (node_api.h) que es más estable
41
+
42
+ ### 3. **Configuración de binding.gyp**
43
+ - **Problema**: Configuración incorrecta para Windows y librerías
44
+ - **Solución**: Simplificado para usar Node-API puro y linking correcto a wevtapi.lib
45
+
46
+ ### 4. **Manejo de errores mejorado**
47
+ - **Problema**: Manejo básico de errores sin validación
48
+ - **Solución**: Agregado validación exhaustiva de parámetros y manejo de errores de Windows API
49
+
50
+ ### 5. **Scripts de build**
51
+ - **Problema**: Faltaban scripts convenientes para build
52
+ - **Solución**: Agregados scripts `build`, `rebuild`, `clean`, y `test` en package.json
53
+
54
+ ## Archivos Modificados/Creados
55
+
56
+ ### `package.json`
57
+ - Agregados scripts de build y prueba
58
+ - Removida dependencia de node-addon-api
59
+ - Agregada descripción del proyecto
60
+
61
+ ### `index.js`
62
+ - Corregida llamada a función nativa
63
+ - Mejorada API con parámetros explícitos
64
+ - Agregada documentación de parámetros
65
+
66
+ ### `native/eventlog.cc`
67
+ - Reescrito completamente usando Node-API puro
68
+ - Agregado manejo robusto de errores
69
+ - Mejorada validación de parámetros
70
+ - Mejor conversión de strings UTF-8/UTF-16
71
+
72
+ ### `binding.gyp`
73
+ - Simplificado para Node-API puro
74
+ - Configuración correcta para Windows
75
+ - Linking apropiado a wevtapi.lib
76
+
77
+ ### `test.js`
78
+ - Creado archivo de prueba funcional
79
+ - Prueba lectura del log de Sistema
80
+ - Validación de resultados
81
+
82
+ ### `README.md`
83
+ - Documentación completa actualizada
84
+ - Instrucciones de instalación y uso
85
+ - Ejemplos de código
86
+ - Solución de problemas comunes
87
+
88
+ ## Estado Final
89
+
90
+ ✅ **Compilación**: Exitosa sin errores
91
+ ✅ **Funcionalidad**: Módulo lee eventos de Windows correctamente
92
+ ✅ **Pruebas**: Pasan exitosamente
93
+ ✅ **API**: Interfaz limpia y bien documentada
94
+
95
+ ## Funcionalidades Implementadas
96
+
97
+ - Lectura de eventos desde cualquier canal de Windows Event Log
98
+ - Soporte para 3 modos de lectura (principio, final, watermark)
99
+ - Validación robusta de parámetros
100
+ - Manejo apropiado de errores de Windows API
101
+ - Conversión correcta de codificación UTF-8/UTF-16
102
+ - Extracción de Event Record IDs del XML
103
+ - Limitación configurable del número de eventos
104
+
105
+ ## Uso del Módulo
106
+
107
+ ```javascript
108
+ const nwinread = require('nwinread');
109
+
110
+ const result = nwinread.readEvents(
111
+ 'System', // Canal
112
+ nwinread.START_MODE.END, // Modo
113
+ 0, // Watermark
114
+ 10 // Máximo eventos
115
+ );
116
+
117
+ console.log(`Encontrados ${result.records.length} eventos`);
118
+ ```
119
+
120
+ El proyecto ahora está completamente funcional y listo para producción.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Solzimer
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,135 @@
1
+ # nwinread - Windows Event Log Reader
2
+
3
+ A native Node.js module for reading Windows event logs using the Windows Event Log API.
4
+
5
+ ## Requirements
6
+
7
+ - Windows Vista/7/8/10/11 or Windows Server 2008/2012/2016/2019/2022
8
+ - Node.js (version 14 or higher)
9
+ - Visual Studio Build Tools or Visual Studio Community
10
+ - Python (for node-gyp)
11
+
12
+ ## Installation
13
+
14
+ ```bash
15
+ npm install
16
+ npm run build
17
+ ```
18
+
19
+ ### Manual step-by-step installation
20
+
21
+ ```bash
22
+ # Install dependencies
23
+ npm install node-addon-api
24
+ npm install -g node-gyp
25
+
26
+ # Configure and compile the native module
27
+ node-gyp configure
28
+ node-gyp build
29
+
30
+ # Or use the package.json script
31
+ npm run build
32
+ ```
33
+
34
+ ## Usage
35
+
36
+ ```javascript
37
+ const nwinread = require('nwinread');
38
+
39
+ // Read events from the end of the log (all events)
40
+ const result = nwinread.readEvents(
41
+ 'System', // Channel (System, Application, Security, etc.)
42
+ nwinread.START_MODE.END, // Read mode
43
+ 0, // Watermark (for WATERMARK mode)
44
+ 10 // Maximum number of events
45
+ );
46
+
47
+ // Read events with specific ID filter
48
+ const filteredResult = nwinread.readEvents(
49
+ 'System', // Channel
50
+ nwinread.START_MODE.BEGINNING, // Read mode
51
+ 0, // Watermark
52
+ 20, // Maximum number of events
53
+ [7045, 7034, 7036] // Event IDs filter (optional)
54
+ );
55
+
56
+ console.log(`Found ${result.records.length} events`);
57
+ console.log(`Last Record ID: ${result.lastRecordId}`);
58
+
59
+ console.log(`Filtered events: ${filteredResult.records.length}`);
60
+
61
+ // Process events
62
+ result.records.forEach((event, index) => {
63
+ console.log(`Event ${index + 1}:`);
64
+ console.log(` Record ID: ${event.recordId}`);
65
+ console.log(` XML: ${event.xml.substring(0, 100)}...`);
66
+ });
67
+ ```
68
+
69
+ ## Read modes
70
+
71
+ - `START_MODE.BEGINNING` (0): Read from the beginning of the log
72
+ - `START_MODE.END` (1): Read from the end of the log
73
+ - `START_MODE.WATERMARK` (2): Read from a specific Record ID
74
+
75
+ ## API
76
+
77
+ ### readEvents(channel, mode, watermark, maxEvents, eventIds)
78
+
79
+ - **channel** (string): Event channel name (e.g.: 'System', 'Application', 'Security')
80
+ - **mode** (number): Read mode (use START_MODE constants)
81
+ - **watermark** (number): Record ID to start from (only for WATERMARK mode)
82
+ - **maxEvents** (number): Maximum number of events to read (1-10000)
83
+ - **eventIds** (array|null, optional): Array of Event IDs to filter. If `null`, `undefined`, or empty array, no filter is applied
84
+
85
+ **Returns:** Object with properties:
86
+ - `records`: Array of events with `xml` and `recordId` properties
87
+ - `lastRecordId`: ID of the last processed record
88
+
89
+ ### Event ID filtering examples
90
+
91
+ ```javascript
92
+ // No filter - all events
93
+ const allEvents = nwinread.readEvents('System', nwinread.START_MODE.BEGINNING, 0, 10);
94
+
95
+ // Filter only Windows service events
96
+ const serviceEvents = nwinread.readEvents('System', nwinread.START_MODE.BEGINNING, 0, 10, [7034, 7035, 7036, 7040, 7045]);
97
+
98
+ // Filter specific critical events
99
+ const criticalEvents = nwinread.readEvents('System', nwinread.START_MODE.BEGINNING, 0, 10, [1000, 1001, 1002]);
100
+
101
+ // Empty array = no filter (equivalent to null)
102
+ const noFilter = nwinread.readEvents('System', nwinread.START_MODE.BEGINNING, 0, 10, []);
103
+ ```
104
+
105
+ ### Common Event IDs
106
+
107
+ - **7034**: Service crashed
108
+ - **7035**: Service start/stop control sent
109
+ - **7036**: Service started/stopped
110
+ - **7040**: Service startup type changed
111
+ - **7045**: New service installed
112
+ - **1000**: Application error
113
+ - **1001**: Application hang
114
+ - **4624**: Successful account logon (Security log)
115
+ - **4625**: Failed account logon (Security log)
116
+
117
+ ## Testing
118
+
119
+ ```bash
120
+ npm test
121
+ ```
122
+
123
+ ## Troubleshooting
124
+
125
+ 1. **Compilation error**: Make sure you have Visual Studio Build Tools installed
126
+ 2. **Permission error**: Some logs require administrator privileges
127
+ 3. **Channel not found**: Verify that the channel name is correct
128
+
129
+ ## Common channels
130
+
131
+ - `System`: System events
132
+ - `Application`: Application events
133
+ - `Security`: Security events (requires admin permissions)
134
+ - `Setup`: Installation events
135
+ - `Microsoft-Windows-PowerShell/Operational`: PowerShell events
package/binding.gyp ADDED
@@ -0,0 +1,27 @@
1
+ {
2
+ "targets": [
3
+ {
4
+ "target_name": "eventlog",
5
+ "sources": [ "native/eventlog.cc" ],
6
+ "defines": [
7
+ "UNICODE",
8
+ "_UNICODE",
9
+ "WIN32_LEAN_AND_MEAN",
10
+ "_WIN32_WINNT=0x0600"
11
+ ],
12
+ "conditions": [
13
+ ['OS=="win"', {
14
+ "link_settings": {
15
+ "libraries": [ "-lwevtapi.lib" ]
16
+ },
17
+ "msvs_settings": {
18
+ "VCCLCompilerTool": {
19
+ "ExceptionHandling": 1,
20
+ "AdditionalOptions": [ "/utf-8" ]
21
+ }
22
+ }
23
+ }]
24
+ ]
25
+ }
26
+ ]
27
+ }
@@ -0,0 +1,19 @@
1
+ Microsoft Visual Studio Solution File, Format Version 12.00
2
+ # Visual Studio 2015
3
+ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "eventlog", "eventlog.vcxproj", "{3EC5C0A2-29FB-8AA2-6EDD-875B8159EA7D}"
4
+ EndProject
5
+ Global
6
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
7
+ Debug|x64 = Debug|x64
8
+ Release|x64 = Release|x64
9
+ EndGlobalSection
10
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
11
+ {3EC5C0A2-29FB-8AA2-6EDD-875B8159EA7D}.Debug|x64.ActiveCfg = Debug|x64
12
+ {3EC5C0A2-29FB-8AA2-6EDD-875B8159EA7D}.Debug|x64.Build.0 = Debug|x64
13
+ {3EC5C0A2-29FB-8AA2-6EDD-875B8159EA7D}.Release|x64.ActiveCfg = Release|x64
14
+ {3EC5C0A2-29FB-8AA2-6EDD-875B8159EA7D}.Release|x64.Build.0 = Release|x64
15
+ EndGlobalSection
16
+ GlobalSection(SolutionProperties) = preSolution
17
+ HideSolutionNode = FALSE
18
+ EndGlobalSection
19
+ EndGlobal
@@ -0,0 +1,148 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3
+ <ItemGroup Label="ProjectConfigurations">
4
+ <ProjectConfiguration Include="Debug|x64">
5
+ <Configuration>Debug</Configuration>
6
+ <Platform>x64</Platform>
7
+ </ProjectConfiguration>
8
+ <ProjectConfiguration Include="Release|x64">
9
+ <Configuration>Release</Configuration>
10
+ <Platform>x64</Platform>
11
+ </ProjectConfiguration>
12
+ </ItemGroup>
13
+ <PropertyGroup Label="Globals">
14
+ <ProjectGuid>{3EC5C0A2-29FB-8AA2-6EDD-875B8159EA7D}</ProjectGuid>
15
+ <Keyword>Win32Proj</Keyword>
16
+ <RootNamespace>eventlog</RootNamespace>
17
+ <IgnoreWarnCompileDuplicatedFilename>true</IgnoreWarnCompileDuplicatedFilename>
18
+ <PreferredToolArchitecture>x64</PreferredToolArchitecture>
19
+ <WindowsTargetPlatformVersion>10.0.22000.0</WindowsTargetPlatformVersion>
20
+ </PropertyGroup>
21
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props"/>
22
+ <PropertyGroup Label="Configuration">
23
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
24
+ </PropertyGroup>
25
+ <PropertyGroup Label="Locals">
26
+ <PlatformToolset>v143</PlatformToolset>
27
+ </PropertyGroup>
28
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props"/>
29
+ <Import Project="$(VCTargetsPath)\BuildCustomizations\masm.props"/>
30
+ <ImportGroup Label="ExtensionSettings"/>
31
+ <ImportGroup Label="PropertySheets">
32
+ <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props"/>
33
+ </ImportGroup>
34
+ <PropertyGroup Label="UserMacros"/>
35
+ <PropertyGroup>
36
+ <ExecutablePath>$(ExecutablePath);$(MSBuildProjectDirectory)\..\bin\;$(MSBuildProjectDirectory)\..\bin\</ExecutablePath>
37
+ <IgnoreImportLibrary>true</IgnoreImportLibrary>
38
+ <IntDir>$(Configuration)\obj\$(ProjectName)\</IntDir>
39
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</LinkIncremental>
40
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</LinkIncremental>
41
+ <OutDir>$(SolutionDir)$(Configuration)\</OutDir>
42
+ <TargetExt Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">.node</TargetExt>
43
+ <TargetExt Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">.node</TargetExt>
44
+ <TargetExt Condition="'$(Configuration)|$(Platform)'=='Release|x64'">.node</TargetExt>
45
+ <TargetExt Condition="'$(Configuration)|$(Platform)'=='Release|x64'">.node</TargetExt>
46
+ <TargetName>$(ProjectName)</TargetName>
47
+ <TargetPath>$(OutDir)\$(ProjectName).node</TargetPath>
48
+ </PropertyGroup>
49
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
50
+ <ClCompile>
51
+ <AdditionalIncludeDirectories>C:\Users\solzi\AppData\Local\node-gyp\Cache\22.17.0\include\node;C:\Users\solzi\AppData\Local\node-gyp\Cache\22.17.0\src;C:\Users\solzi\AppData\Local\node-gyp\Cache\22.17.0\deps\openssl\config;C:\Users\solzi\AppData\Local\node-gyp\Cache\22.17.0\deps\openssl\openssl\include;C:\Users\solzi\AppData\Local\node-gyp\Cache\22.17.0\deps\uv\include;C:\Users\solzi\AppData\Local\node-gyp\Cache\22.17.0\deps\zlib;C:\Users\solzi\AppData\Local\node-gyp\Cache\22.17.0\deps\v8\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
52
+ <AdditionalOptions>/Zc:__cplusplus -std:c++20 /Zm2000 /utf-8 %(AdditionalOptions)</AdditionalOptions>
53
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
54
+ <BufferSecurityCheck>true</BufferSecurityCheck>
55
+ <DebugInformationFormat>OldStyle</DebugInformationFormat>
56
+ <DisableSpecificWarnings>4351;4355;4800;4251;4275;4244;4267;%(DisableSpecificWarnings)</DisableSpecificWarnings>
57
+ <ExceptionHandling>Sync</ExceptionHandling>
58
+ <MinimalRebuild>false</MinimalRebuild>
59
+ <MultiProcessorCompilation>true</MultiProcessorCompilation>
60
+ <OmitFramePointers>false</OmitFramePointers>
61
+ <Optimization>Disabled</Optimization>
62
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
63
+ <PreprocessorDefinitions>NODE_GYP_MODULE_NAME=eventlog;USING_UV_SHARED=1;USING_V8_SHARED=1;V8_DEPRECATION_WARNINGS=1;_GLIBCXX_USE_CXX11_ABI=1;_FILE_OFFSET_BITS=64;WIN32;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_HAS_EXCEPTIONS=0;NOMINMAX;OPENSSL_NO_PINSHARED;OPENSSL_THREADS;UNICODE;_UNICODE;WIN32_LEAN_AND_MEAN;_WIN32_WINNT=0x0600;BUILDING_NODE_EXTENSION;HOST_BINARY=&quot;node.exe&quot;;DEBUG;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
64
+ <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
65
+ <StringPooling>true</StringPooling>
66
+ <SuppressStartupBanner>true</SuppressStartupBanner>
67
+ <TreatWarningAsError>false</TreatWarningAsError>
68
+ <WarningLevel>Level3</WarningLevel>
69
+ <WholeProgramOptimization>true</WholeProgramOptimization>
70
+ </ClCompile>
71
+ <Lib>
72
+ <AdditionalOptions>/LTCG:INCREMENTAL %(AdditionalOptions)</AdditionalOptions>
73
+ </Lib>
74
+ <Link>
75
+ <AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;delayimp.lib;&quot;C:\\Users\\solzi\\AppData\\Local\\node-gyp\\Cache\\22.17.0\\x64\\node.lib&quot;;wevtapi.lib</AdditionalDependencies>
76
+ <AdditionalOptions>/LTCG:INCREMENTAL /ignore:4199 %(AdditionalOptions)</AdditionalOptions>
77
+ <DelayLoadDLLs>node.exe;%(DelayLoadDLLs)</DelayLoadDLLs>
78
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
79
+ <GenerateDebugInformation>true</GenerateDebugInformation>
80
+ <OptimizeReferences>true</OptimizeReferences>
81
+ <OutputFile>$(OutDir)$(ProjectName).node</OutputFile>
82
+ <SuppressStartupBanner>true</SuppressStartupBanner>
83
+ <TargetExt>.node</TargetExt>
84
+ <TargetMachine>MachineX64</TargetMachine>
85
+ </Link>
86
+ <ResourceCompile>
87
+ <AdditionalIncludeDirectories>C:\Users\solzi\AppData\Local\node-gyp\Cache\22.17.0\include\node;C:\Users\solzi\AppData\Local\node-gyp\Cache\22.17.0\src;C:\Users\solzi\AppData\Local\node-gyp\Cache\22.17.0\deps\openssl\config;C:\Users\solzi\AppData\Local\node-gyp\Cache\22.17.0\deps\openssl\openssl\include;C:\Users\solzi\AppData\Local\node-gyp\Cache\22.17.0\deps\uv\include;C:\Users\solzi\AppData\Local\node-gyp\Cache\22.17.0\deps\zlib;C:\Users\solzi\AppData\Local\node-gyp\Cache\22.17.0\deps\v8\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
88
+ <PreprocessorDefinitions>NODE_GYP_MODULE_NAME=eventlog;USING_UV_SHARED=1;USING_V8_SHARED=1;V8_DEPRECATION_WARNINGS=1;_GLIBCXX_USE_CXX11_ABI=1;_FILE_OFFSET_BITS=64;WIN32;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_HAS_EXCEPTIONS=0;NOMINMAX;OPENSSL_NO_PINSHARED;OPENSSL_THREADS;UNICODE;_UNICODE;WIN32_LEAN_AND_MEAN;_WIN32_WINNT=0x0600;BUILDING_NODE_EXTENSION;HOST_BINARY=&quot;node.exe&quot;;DEBUG;_DEBUG;%(PreprocessorDefinitions);%(PreprocessorDefinitions)</PreprocessorDefinitions>
89
+ </ResourceCompile>
90
+ </ItemDefinitionGroup>
91
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
92
+ <ClCompile>
93
+ <AdditionalIncludeDirectories>C:\Users\solzi\AppData\Local\node-gyp\Cache\22.17.0\include\node;C:\Users\solzi\AppData\Local\node-gyp\Cache\22.17.0\src;C:\Users\solzi\AppData\Local\node-gyp\Cache\22.17.0\deps\openssl\config;C:\Users\solzi\AppData\Local\node-gyp\Cache\22.17.0\deps\openssl\openssl\include;C:\Users\solzi\AppData\Local\node-gyp\Cache\22.17.0\deps\uv\include;C:\Users\solzi\AppData\Local\node-gyp\Cache\22.17.0\deps\zlib;C:\Users\solzi\AppData\Local\node-gyp\Cache\22.17.0\deps\v8\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
94
+ <AdditionalOptions>/Zc:__cplusplus -std:c++20 /Zm2000 /utf-8 %(AdditionalOptions)</AdditionalOptions>
95
+ <BufferSecurityCheck>true</BufferSecurityCheck>
96
+ <DebugInformationFormat>OldStyle</DebugInformationFormat>
97
+ <DisableSpecificWarnings>4351;4355;4800;4251;4275;4244;4267;%(DisableSpecificWarnings)</DisableSpecificWarnings>
98
+ <ExceptionHandling>Sync</ExceptionHandling>
99
+ <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
100
+ <FunctionLevelLinking>true</FunctionLevelLinking>
101
+ <InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
102
+ <IntrinsicFunctions>true</IntrinsicFunctions>
103
+ <MultiProcessorCompilation>true</MultiProcessorCompilation>
104
+ <OmitFramePointers>true</OmitFramePointers>
105
+ <Optimization>Full</Optimization>
106
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
107
+ <PreprocessorDefinitions>NODE_GYP_MODULE_NAME=eventlog;USING_UV_SHARED=1;USING_V8_SHARED=1;V8_DEPRECATION_WARNINGS=1;_GLIBCXX_USE_CXX11_ABI=1;_FILE_OFFSET_BITS=64;WIN32;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_HAS_EXCEPTIONS=0;NOMINMAX;OPENSSL_NO_PINSHARED;OPENSSL_THREADS;UNICODE;_UNICODE;WIN32_LEAN_AND_MEAN;_WIN32_WINNT=0x0600;BUILDING_NODE_EXTENSION;HOST_BINARY=&quot;node.exe&quot;;%(PreprocessorDefinitions)</PreprocessorDefinitions>
108
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
109
+ <RuntimeTypeInfo>false</RuntimeTypeInfo>
110
+ <StringPooling>true</StringPooling>
111
+ <SuppressStartupBanner>true</SuppressStartupBanner>
112
+ <TreatWarningAsError>false</TreatWarningAsError>
113
+ <WarningLevel>Level3</WarningLevel>
114
+ <WholeProgramOptimization>true</WholeProgramOptimization>
115
+ </ClCompile>
116
+ <Lib>
117
+ <AdditionalOptions>/LTCG:INCREMENTAL %(AdditionalOptions)</AdditionalOptions>
118
+ </Lib>
119
+ <Link>
120
+ <AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;delayimp.lib;&quot;C:\\Users\\solzi\\AppData\\Local\\node-gyp\\Cache\\22.17.0\\x64\\node.lib&quot;;wevtapi.lib</AdditionalDependencies>
121
+ <AdditionalOptions>/LTCG:INCREMENTAL /ignore:4199 %(AdditionalOptions)</AdditionalOptions>
122
+ <DelayLoadDLLs>node.exe;%(DelayLoadDLLs)</DelayLoadDLLs>
123
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
124
+ <GenerateDebugInformation>true</GenerateDebugInformation>
125
+ <OptimizeReferences>true</OptimizeReferences>
126
+ <OutputFile>$(OutDir)$(ProjectName).node</OutputFile>
127
+ <SuppressStartupBanner>true</SuppressStartupBanner>
128
+ <TargetExt>.node</TargetExt>
129
+ <TargetMachine>MachineX64</TargetMachine>
130
+ </Link>
131
+ <ResourceCompile>
132
+ <AdditionalIncludeDirectories>C:\Users\solzi\AppData\Local\node-gyp\Cache\22.17.0\include\node;C:\Users\solzi\AppData\Local\node-gyp\Cache\22.17.0\src;C:\Users\solzi\AppData\Local\node-gyp\Cache\22.17.0\deps\openssl\config;C:\Users\solzi\AppData\Local\node-gyp\Cache\22.17.0\deps\openssl\openssl\include;C:\Users\solzi\AppData\Local\node-gyp\Cache\22.17.0\deps\uv\include;C:\Users\solzi\AppData\Local\node-gyp\Cache\22.17.0\deps\zlib;C:\Users\solzi\AppData\Local\node-gyp\Cache\22.17.0\deps\v8\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
133
+ <PreprocessorDefinitions>NODE_GYP_MODULE_NAME=eventlog;USING_UV_SHARED=1;USING_V8_SHARED=1;V8_DEPRECATION_WARNINGS=1;_GLIBCXX_USE_CXX11_ABI=1;_FILE_OFFSET_BITS=64;WIN32;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_HAS_EXCEPTIONS=0;NOMINMAX;OPENSSL_NO_PINSHARED;OPENSSL_THREADS;UNICODE;_UNICODE;WIN32_LEAN_AND_MEAN;_WIN32_WINNT=0x0600;BUILDING_NODE_EXTENSION;HOST_BINARY=&quot;node.exe&quot;;%(PreprocessorDefinitions);%(PreprocessorDefinitions)</PreprocessorDefinitions>
134
+ </ResourceCompile>
135
+ </ItemDefinitionGroup>
136
+ <ItemGroup>
137
+ <None Include="..\binding.gyp"/>
138
+ </ItemGroup>
139
+ <ItemGroup>
140
+ <ClCompile Include="..\native\eventlog.cc">
141
+ <ObjectFileName>$(IntDir)\native\eventlog.obj</ObjectFileName>
142
+ </ClCompile>
143
+ <ClCompile Include="C:\Users\solzi\AppData\Roaming\nvm\v22.17.0\node_modules\node-gyp\src\win_delay_load_hook.cc"/>
144
+ </ItemGroup>
145
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets"/>
146
+ <Import Project="$(VCTargetsPath)\BuildCustomizations\masm.targets"/>
147
+ <ImportGroup Label="ExtensionTargets"/>
148
+ </Project>
@@ -0,0 +1,55 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3
+ <ItemGroup>
4
+ <Filter Include="..">
5
+ <UniqueIdentifier>{13ED4249-1F9C-5F0F-2651-29A73F3A7059}</UniqueIdentifier>
6
+ </Filter>
7
+ <Filter Include="..\native">
8
+ <UniqueIdentifier>{751DE1B9-2CA6-B33D-2A40-92CBD5B002F3}</UniqueIdentifier>
9
+ </Filter>
10
+ <Filter Include="C:">
11
+ <UniqueIdentifier>{F87FD356-0FEB-9BC5-D1FA-368C81420008}</UniqueIdentifier>
12
+ </Filter>
13
+ <Filter Include="C:\Users">
14
+ <UniqueIdentifier>{707347A1-1ABA-A9B2-9AF4-DE122F5D7F08}</UniqueIdentifier>
15
+ </Filter>
16
+ <Filter Include="C:\Users\solzi">
17
+ <UniqueIdentifier>{36F44239-C2BD-2609-082B-8716CC7F3439}</UniqueIdentifier>
18
+ </Filter>
19
+ <Filter Include="C:\Users\solzi\AppData">
20
+ <UniqueIdentifier>{DABCEBCE-33D1-4D68-EC67-0BC19A2A0901}</UniqueIdentifier>
21
+ </Filter>
22
+ <Filter Include="C:\Users\solzi\AppData\Roaming">
23
+ <UniqueIdentifier>{06897101-0A2C-F34A-36C2-4D0BE8BF5EB9}</UniqueIdentifier>
24
+ </Filter>
25
+ <Filter Include="C:\Users\solzi\AppData\Roaming\nvm">
26
+ <UniqueIdentifier>{C6BD613B-358D-2DCD-8B8A-73765EB3E8E4}</UniqueIdentifier>
27
+ </Filter>
28
+ <Filter Include="C:\Users\solzi\AppData\Roaming\nvm\v22.17.0">
29
+ <UniqueIdentifier>{EEBCB736-7B17-79B2-FBF2-41E78D86FD71}</UniqueIdentifier>
30
+ </Filter>
31
+ <Filter Include="C:\Users\solzi\AppData\Roaming\nvm\v22.17.0\node_modules">
32
+ <UniqueIdentifier>{126A39EA-1D28-5689-C126-0DA0AB5837A0}</UniqueIdentifier>
33
+ </Filter>
34
+ <Filter Include="C:\Users\solzi\AppData\Roaming\nvm\v22.17.0\node_modules\node-gyp">
35
+ <UniqueIdentifier>{49558BB4-6D34-CA91-A65D-85A65792DC11}</UniqueIdentifier>
36
+ </Filter>
37
+ <Filter Include="C:\Users\solzi\AppData\Roaming\nvm\v22.17.0\node_modules\node-gyp\src">
38
+ <UniqueIdentifier>{F1003AD6-4B6D-45DF-3F56-5CAC869BF55E}</UniqueIdentifier>
39
+ </Filter>
40
+ <Filter Include="..">
41
+ <UniqueIdentifier>{13ED4249-1F9C-5F0F-2651-29A73F3A7059}</UniqueIdentifier>
42
+ </Filter>
43
+ </ItemGroup>
44
+ <ItemGroup>
45
+ <ClCompile Include="..\native\eventlog.cc">
46
+ <Filter>..\native</Filter>
47
+ </ClCompile>
48
+ <ClCompile Include="C:\Users\solzi\AppData\Roaming\nvm\v22.17.0\node_modules\node-gyp\src\win_delay_load_hook.cc">
49
+ <Filter>C:\Users\solzi\AppData\Roaming\nvm\v22.17.0\node_modules\node-gyp\src</Filter>
50
+ </ClCompile>
51
+ <None Include="..\binding.gyp">
52
+ <Filter>..</Filter>
53
+ </None>
54
+ </ItemGroup>
55
+ </Project>
package/index.js ADDED
@@ -0,0 +1,17 @@
1
+ const native = require('./build/Release/eventlog.node');
2
+
3
+ const START_MODE = {
4
+ BEGINNING: 0,
5
+ END: 1,
6
+ WATERMARK: 2
7
+ };
8
+
9
+ module.exports = {
10
+ START_MODE,
11
+
12
+ readEvents(channel, mode = START_MODE.BEGINNING, watermark = 0, maxEvents = 100, eventIds = null) {
13
+ // Si eventIds es null, undefined, o un array vacío, no se aplica filtro
14
+ const filterIds = (eventIds && eventIds.length > 0) ? eventIds : null;
15
+ return native.read(channel, mode, watermark, maxEvents, filterIds);
16
+ }
17
+ };
@@ -0,0 +1,298 @@
1
+ #include <node_api.h>
2
+ #include <windows.h>
3
+ #include <winevt.h>
4
+ #include <vector>
5
+ #include <string>
6
+ #include <cassert>
7
+
8
+ #pragma comment(lib, "wevtapi.lib")
9
+
10
+ enum ReadMode {
11
+ FROM_BEGINNING = 0,
12
+ FROM_END = 1,
13
+ FROM_WATERMARK = 2
14
+ };
15
+
16
+ // Convierte UTF-8 a wide string
17
+ std::wstring Utf8ToWide(const std::string& str) {
18
+ if (str.empty()) return std::wstring();
19
+
20
+ int size = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, NULL, 0);
21
+ if (size == 0) return std::wstring();
22
+
23
+ std::wstring w(size, 0);
24
+ MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, &w[0], size);
25
+ return w;
26
+ }
27
+
28
+ // Convierte wide string a UTF-8
29
+ std::string WideToUtf8(const std::wstring& wstr) {
30
+ if (wstr.empty()) return std::string();
31
+
32
+ int size = WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), -1, NULL, 0, NULL, NULL);
33
+ if (size == 0) return std::string();
34
+
35
+ std::string str(size, 0);
36
+ WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), -1, &str[0], size, NULL, NULL);
37
+ return str;
38
+ }
39
+
40
+ napi_value ReadEventLog(napi_env env, napi_callback_info info) {
41
+ napi_status status;
42
+ size_t argc = 5;
43
+ napi_value args[5];
44
+
45
+ // Obtener argumentos
46
+ status = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
47
+ assert(status == napi_ok);
48
+
49
+ if (argc < 4) {
50
+ napi_throw_type_error(env, nullptr, "Expected 4-5 arguments: (channel, mode, watermark, maxEvents, eventIds?)");
51
+ return nullptr;
52
+ }
53
+
54
+ // Extraer channel
55
+ size_t channel_len;
56
+ status = napi_get_value_string_utf8(env, args[0], nullptr, 0, &channel_len);
57
+ assert(status == napi_ok);
58
+
59
+ std::string channel(channel_len, '\0');
60
+ status = napi_get_value_string_utf8(env, args[0], &channel[0], channel_len + 1, &channel_len);
61
+ assert(status == napi_ok);
62
+
63
+ // Extraer otros argumentos
64
+ int32_t mode;
65
+ int64_t watermark;
66
+ int32_t maxEvents;
67
+
68
+ status = napi_get_value_int32(env, args[1], &mode);
69
+ assert(status == napi_ok);
70
+
71
+ status = napi_get_value_int64(env, args[2], &watermark);
72
+ assert(status == napi_ok);
73
+
74
+ status = napi_get_value_int32(env, args[3], &maxEvents);
75
+ assert(status == napi_ok);
76
+
77
+ // Procesar eventIds (parámetro opcional)
78
+ std::vector<int32_t> eventIds;
79
+ if (argc >= 5) {
80
+ napi_valuetype valueType;
81
+ status = napi_typeof(env, args[4], &valueType);
82
+
83
+ if (valueType != napi_null && valueType != napi_undefined) {
84
+ bool isArray;
85
+ status = napi_is_array(env, args[4], &isArray);
86
+ assert(status == napi_ok);
87
+
88
+ if (isArray) {
89
+ uint32_t arrayLength;
90
+ status = napi_get_array_length(env, args[4], &arrayLength);
91
+ assert(status == napi_ok);
92
+
93
+ for (uint32_t i = 0; i < arrayLength; i++) {
94
+ napi_value element;
95
+ status = napi_get_element(env, args[4], i, &element);
96
+ assert(status == napi_ok);
97
+
98
+ int32_t eventId;
99
+ status = napi_get_value_int32(env, element, &eventId);
100
+ if (status == napi_ok && eventId > 0) {
101
+ eventIds.push_back(eventId);
102
+ }
103
+ }
104
+ }
105
+ }
106
+ }
107
+
108
+ // Validar parámetros
109
+ if (channel.empty()) {
110
+ napi_throw_type_error(env, nullptr, "Channel name cannot be empty");
111
+ return nullptr;
112
+ }
113
+
114
+ if (mode < 0 || mode > 2) {
115
+ napi_throw_type_error(env, nullptr, "Invalid mode. Must be 0, 1, or 2");
116
+ return nullptr;
117
+ }
118
+
119
+ if (maxEvents <= 0 || maxEvents > 10000) {
120
+ napi_throw_type_error(env, nullptr, "maxEvents must be between 1 and 10000");
121
+ return nullptr;
122
+ }
123
+
124
+ DWORD flags = EvtQueryChannelPath;
125
+ if (mode == FROM_END) {
126
+ flags |= EvtQueryReverseDirection;
127
+ }
128
+
129
+ std::wstring query;
130
+
131
+ // Construir filtro de Event IDs si se proporcionaron
132
+ std::wstring eventIdFilter;
133
+ if (!eventIds.empty()) {
134
+ eventIdFilter = L"System/EventID=";
135
+ for (size_t i = 0; i < eventIds.size(); i++) {
136
+ if (i > 0) {
137
+ eventIdFilter += L" or System/EventID=";
138
+ }
139
+ eventIdFilter += std::to_wstring(eventIds[i]);
140
+ }
141
+ }
142
+
143
+ // Construir filtro de watermark si es necesario
144
+ std::wstring watermarkFilter;
145
+ if (mode == FROM_WATERMARK && watermark > 0) {
146
+ watermarkFilter = L"System/EventRecordID > " + std::to_wstring(watermark);
147
+ }
148
+
149
+ // Combinar filtros
150
+ if (!eventIdFilter.empty() || !watermarkFilter.empty()) {
151
+ query = L"*[";
152
+
153
+ if (!eventIdFilter.empty() && !watermarkFilter.empty()) {
154
+ query += L"(" + eventIdFilter + L") and (" + watermarkFilter + L")";
155
+ } else if (!eventIdFilter.empty()) {
156
+ query += eventIdFilter;
157
+ } else {
158
+ query += watermarkFilter;
159
+ }
160
+
161
+ query += L"]";
162
+ }
163
+
164
+ EVT_HANDLE hQuery = EvtQuery(
165
+ NULL,
166
+ Utf8ToWide(channel).c_str(),
167
+ query.empty() ? NULL : query.c_str(),
168
+ flags
169
+ );
170
+
171
+ if (!hQuery) {
172
+ DWORD errorCode = GetLastError();
173
+ std::string errorMsg = "EvtQuery failed with error code: " + std::to_string(errorCode);
174
+ napi_throw_error(env, nullptr, errorMsg.c_str());
175
+ return nullptr;
176
+ }
177
+
178
+ std::vector<EVT_HANDLE> events(maxEvents);
179
+ DWORD returned = 0;
180
+
181
+ BOOL ok = EvtNext(
182
+ hQuery,
183
+ maxEvents,
184
+ events.data(),
185
+ INFINITE,
186
+ 0,
187
+ &returned
188
+ );
189
+
190
+ // Crear array de resultados
191
+ napi_value records;
192
+ status = napi_create_array(env, &records);
193
+ assert(status == napi_ok);
194
+
195
+ uint64_t lastRecordId = watermark;
196
+ DWORD index = 0;
197
+
198
+ if (ok || GetLastError() == ERROR_NO_MORE_ITEMS) {
199
+ for (DWORD i = 0; i < returned; i++) {
200
+ DWORD bufferUsed = 0;
201
+ DWORD propCount = 0;
202
+
203
+ // Primera llamada para obtener el tamaño del buffer
204
+ EvtRender(NULL, events[i], EvtRenderEventXml, 0, NULL, &bufferUsed, &propCount);
205
+
206
+ if (bufferUsed == 0) {
207
+ EvtClose(events[i]);
208
+ continue;
209
+ }
210
+
211
+ std::vector<wchar_t> buffer(bufferUsed / sizeof(wchar_t));
212
+
213
+ // Segunda llamada para obtener los datos
214
+ if (EvtRender(NULL, events[i], EvtRenderEventXml, bufferUsed, buffer.data(), &bufferUsed, &propCount)) {
215
+ std::wstring xml(buffer.data());
216
+ std::string xmlUtf8 = WideToUtf8(xml);
217
+
218
+ // Extraer EventRecordID del XML
219
+ size_t pos = xml.find(L"<EventRecordID>");
220
+ if (pos != std::wstring::npos) {
221
+ size_t end = xml.find(L"</EventRecordID>", pos);
222
+ if (end != std::wstring::npos) {
223
+ std::wstring recordIdStr = xml.substr(pos + 15, end - (pos + 15));
224
+ try {
225
+ lastRecordId = std::stoull(recordIdStr);
226
+ } catch (...) {
227
+ // Mantener valor anterior si hay error
228
+ }
229
+ }
230
+ }
231
+
232
+ // Crear objeto record
233
+ napi_value rec;
234
+ status = napi_create_object(env, &rec);
235
+ assert(status == napi_ok);
236
+
237
+ // Agregar xml
238
+ napi_value xml_val;
239
+ status = napi_create_string_utf8(env, xmlUtf8.c_str(), xmlUtf8.length(), &xml_val);
240
+ assert(status == napi_ok);
241
+ status = napi_set_named_property(env, rec, "xml", xml_val);
242
+ assert(status == napi_ok);
243
+
244
+ // Agregar recordId
245
+ napi_value recordId_val;
246
+ status = napi_create_double(env, (double)lastRecordId, &recordId_val);
247
+ assert(status == napi_ok);
248
+ status = napi_set_named_property(env, rec, "recordId", recordId_val);
249
+ assert(status == napi_ok);
250
+
251
+ // Agregar al array
252
+ status = napi_set_element(env, records, index++, rec);
253
+ assert(status == napi_ok);
254
+ }
255
+
256
+ EvtClose(events[i]);
257
+ }
258
+ } else {
259
+ EvtClose(hQuery);
260
+ DWORD errorCode = GetLastError();
261
+ std::string errorMsg = "EvtNext failed with error code: " + std::to_string(errorCode);
262
+ napi_throw_error(env, nullptr, errorMsg.c_str());
263
+ return nullptr;
264
+ }
265
+
266
+ EvtClose(hQuery);
267
+
268
+ // Crear objeto resultado
269
+ napi_value result;
270
+ status = napi_create_object(env, &result);
271
+ assert(status == napi_ok);
272
+
273
+ status = napi_set_named_property(env, result, "records", records);
274
+ assert(status == napi_ok);
275
+
276
+ napi_value lastRecordId_val;
277
+ status = napi_create_double(env, (double)lastRecordId, &lastRecordId_val);
278
+ assert(status == napi_ok);
279
+ status = napi_set_named_property(env, result, "lastRecordId", lastRecordId_val);
280
+ assert(status == napi_ok);
281
+
282
+ return result;
283
+ }
284
+
285
+ napi_value Init(napi_env env, napi_value exports) {
286
+ napi_status status;
287
+ napi_value fn;
288
+
289
+ status = napi_create_function(env, nullptr, 0, ReadEventLog, nullptr, &fn);
290
+ assert(status == napi_ok);
291
+
292
+ status = napi_set_named_property(env, exports, "read", fn);
293
+ assert(status == napi_ok);
294
+
295
+ return exports;
296
+ }
297
+
298
+ NAPI_MODULE(NODE_GYP_MODULE_NAME, Init)
package/package.json ADDED
@@ -0,0 +1,22 @@
1
+ {
2
+ "name": "nwinread",
3
+ "version": "1.0.0",
4
+ "main": "index.js",
5
+ "scripts": {
6
+ "build": "node-gyp configure && node-gyp build",
7
+ "rebuild": "node-gyp rebuild",
8
+ "clean": "node-gyp clean",
9
+ "test": "node test.js"
10
+ },
11
+ "author": "solzimer",
12
+ "license": "MIT",
13
+ "description": "Native Windows Event Log Reader for Node.js",
14
+ "repository": {
15
+ "type": "git",
16
+ "url": "https://github.com/solzimer/nwinread.git"
17
+ },
18
+ "devDependencies": {
19
+ "node-gyp": "^10.0.0"
20
+ },
21
+ "gypfile": true
22
+ }
package/test.js ADDED
@@ -0,0 +1,34 @@
1
+ const nwinread = require('./index.js');
2
+
3
+ console.log('Testing nwinread module...');
4
+
5
+ const watermark = parseInt(process.argv[2]) || 0;
6
+ const testEventIds = process.argv[3] ? process.argv[3].split(',').map(id => parseInt(id)) : null;
7
+
8
+ console.log(`Using watermark: ${watermark}`);
9
+ console.log(`Event ID filter: ${testEventIds ? testEventIds.join(', ') : 'None (all events)'}`);
10
+
11
+ try {
12
+ // Prueba básica - leer desde el log de sistema con filtro opcional de IDs
13
+ const mode = watermark > 0 ? nwinread.START_MODE.WATERMARK : nwinread.START_MODE.BEGINNING;
14
+ const result = nwinread.readEvents('System', mode, watermark, 10, testEventIds);
15
+
16
+ console.log(`Found ${result.records.length} events`);
17
+ console.log(`Last Record ID: ${result.lastRecordId}`);
18
+
19
+ result.records.forEach((record, index) => {
20
+ console.log(`\nEvent ${index + 1}:`);
21
+ console.log(`Record ID: ${record.recordId}`);
22
+ console.log(`XML: ${record.xml.substring(0, 200)}...`); // Mostrar solo los primeros 200 caracteres
23
+ });
24
+
25
+ console.log('\nTest completed successfully!');
26
+ console.log('\nUsage examples:');
27
+ console.log(' node test.js - Read all events from beginning');
28
+ console.log(' node test.js 0 1000,1001 - Read events with IDs 1000 and 1001');
29
+ console.log(' node test.js 123 - Read from watermark 123, all events');
30
+ console.log(' node test.js 123 7045,7034,7036 - Read from watermark 123, filter by service event IDs');
31
+ } catch (error) {
32
+ console.error('Test failed:', error.message);
33
+ process.exit(1);
34
+ }