@litko/yara-x 0.2.0 → 0.3.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 (4) hide show
  1. package/README.md +141 -30
  2. package/index.d.ts +184 -93
  3. package/index.js +213 -31
  4. package/package.json +12 -9
package/README.md CHANGED
@@ -1,7 +1,5 @@
1
1
  # @litko/yara-x
2
2
 
3
- **v0.1.1**
4
-
5
3
  ## Features
6
4
 
7
5
  - High Performance: Built with [napi-rs](https://napi-rs.com) and [VirusTotal/yara-x](https://github.com/VirusTotal/yara-x)
@@ -246,11 +244,17 @@ const rules = compile(
246
244
  // Ignore specific modules
247
245
  ignoreModules: ["pe"],
248
246
 
249
- : // Error on potentially slow patterns
247
+ // Error on potentially slow patterns
250
248
  errorOnSlowPattern: true,
251
249
 
252
250
  // Error on potentially slow loops
253
251
  errorOnSlowLoop: true,
252
+
253
+ // Specify directories for include statements (v1.5.0+)
254
+ includeDirectories: ["./rules/includes", "./rules/common"],
255
+
256
+ // Enable or disable include statements (v1.5.0+)
257
+ enableIncludes: true,
254
258
  },
255
259
  );
256
260
  ```
@@ -361,33 +365,128 @@ if (warnings.length > 0) {
361
365
  }
362
366
  ```
363
367
 
368
+ ## Include Directories
369
+
370
+ ```javascript
371
+ import { compile } from "@litko/yara-x";
372
+
373
+ // Create a main rule that includes other rules
374
+ const mainRule = `
375
+ include "common/strings.yar"
376
+ include "malware/pe_patterns.yar"
377
+
378
+ rule main_detection {
379
+ condition:
380
+ common_string_rule or pe_malware_rule
381
+ }
382
+ `;
383
+
384
+ // Compile with include directories
385
+ const rules = compile(mainRule, {
386
+ includeDirectories: [
387
+ "./rules", // Base directory
388
+ "./rules/common", // Additional include path
389
+ "./rules/malware", // Another include path
390
+ ],
391
+ });
392
+
393
+ // Scan as usual
394
+ const matches = rules.scan(Buffer.from("test data"));
395
+ ```
396
+
397
+ ## Scan Performance Options
398
+
399
+ Control scanning behavior for better performance or safety.
400
+
401
+ ### Limiting Matches Per Pattern
402
+
403
+ Prevent excessive memory usage by limiting the number of matches per pattern:
404
+
405
+ ```javascript
406
+ import { compile } from "@litko/yara-x";
407
+
408
+ const rules = compile(`
409
+ rule find_pattern {
410
+ strings:
411
+ $a = "pattern"
412
+ condition:
413
+ $a
414
+ }
415
+ `);
416
+
417
+ // Limit to 1000 matches per pattern
418
+ rules.setMaxMatchesPerPattern(1000);
419
+
420
+ // Scan data with many occurrences
421
+ const data = Buffer.from("pattern ".repeat(10000));
422
+ const matches = rules.scan(data);
423
+
424
+ // Will only return up to 1000 matches per pattern
425
+ console.log(`Found ${matches[0].matches.length} matches (limited to 1000)`);
426
+ ```
427
+
428
+ ### Memory-Mapped File Control
429
+
430
+ Control whether to use memory-mapped files for scanning:
431
+
432
+ ```javascript
433
+ import { compile } from "@litko/yara-x";
434
+
435
+ const rules = compile(`
436
+ rule test {
437
+ strings:
438
+ $a = "test"
439
+ condition:
440
+ $a
441
+ }
442
+ `);
443
+
444
+ // Disable memory-mapped files for safer scanning
445
+ // (slower but safer for untrusted files)
446
+ rules.setUseMmap(false);
447
+
448
+ // Scan file without memory mapping
449
+ const matches = rules.scanFile("./sample.bin");
450
+ ```
451
+
364
452
  ## Performance Benchmarks
365
453
 
366
- **Test Setup:**
454
+ `node-yara-x` delivers exceptional performance through intelligent scanner caching and optimized Rust implementation.
367
455
 
368
- - **Hardware:** MacBook Pro (M3 Max, 36GB RAM)
369
- - **Test Data:** Generated data of varying sizes (small: 64 bytes, medium: 100KB, large: 10MB). See `__test__/benchmark.mjs` for data generation and benchmarking code.
370
- - The Large test file (10MB) is auto-generated, to prevent bloating the size of the repository.
456
+ ### Benchmark Results
371
457
 
372
- **Key Metrics (Averages):**
458
+ Test Environment: MacBook Pro M3 Max, 36GB RAM, Release build with LTO
459
+ Methodology: Statistical analysis across multiple iterations with percentile reporting
373
460
 
374
- | Operation | Average Time | Iterations | p50 | p95 | p99 |
375
- | :---------------------------------------------- | -----------: | ---------: | -------: | -------: | -------: |
376
- | Scanner Creation (Simple Rule) | 1.675 ms | 100 | 1.547 ms | 2.318 ms | 2.657 ms |
377
- | Scanner Creation (Complex Rule) | 1.878 ms | 100 | 1.848 ms | 2.005 ms | 2.865 ms |
378
- | Scanner Creation (Regex Rule) | 2.447 ms | 100 | 2.444 ms | 2.473 ms | 2.569 ms |
379
- | Scanner Creation (Multiple Rules) | 1.497 ms | 100 | 1.488 ms | 1.547 ms | 1.819 ms |
380
- | Scanning Small Data (64 bytes, Simple Rule) | 0.145 ms | 1000 | 0.143 ms | 0.156 ms | 0.169 ms |
381
- | Scanning Medium Data (100KB, Simple Rule) | 0.151 ms | 100 | 0.146 ms | 0.179 ms | 0.205 ms |
382
- | Scanning Large Data (10MB, Simple Rule) | 0.347 ms | 10 | 0.340 ms | 0.394 ms | 0.394 ms |
383
- | Scanning Medium Data (100KB, Complex Rule) | 0.219 ms | 100 | 0.215 ms | 0.254 ms | 0.269 ms |
384
- | Scanning Medium Data (100KB, Regex Rule) | 0.156 ms | 100 | 0.152 ms | 0.182 ms | 0.210 ms |
385
- | Scanning Medium Data (100KB, Multiple Rules) | 0.218 ms | 100 | 0.212 ms | 0.261 ms | 0.353 ms |
386
- | Async Scanning Medium Data (100KB, Simple Rule) | 0.012 ms | 100 | 0.011 ms | 0.016 ms | 0.027ms |
387
- | Scanning with Variables | 0.143 ms | 1000 | 0.140 ms | 0.155 ms | 0.166 ms |
388
- | Scanning with Variables (Override at Scan Time) | 0.144 ms | 1000 | 0.142 ms | 0.158 ms | 0.175 ms |
461
+ #### Scanner Creation Performance
389
462
 
390
- # API Reference
463
+ | Rule Type | Mean | p50 | p95 | p99 |
464
+ | -------------- | ------ | ------ | ------ | ------ |
465
+ | Simple Rule | 2.43ms | 2.41ms | 2.87ms | 3.11ms |
466
+ | Complex Rule | 2.57ms | 2.52ms | 2.96ms | 3.06ms |
467
+ | Regex Rule | 7.57ms | 7.47ms | 8.29ms | 8.70ms |
468
+ | Multiple Rules | 2.05ms | 2.03ms | 2.24ms | 2.42ms |
469
+
470
+ #### Scanning Performance by Data Size
471
+
472
+ | Data Size | Rule Type | Mean | Throughput |
473
+ | --------- | -------------- | ----- | ---------- |
474
+ | 64 bytes | Simple | 3μs | ~21 MB/s |
475
+ | 100KB | Simple | 6μs | ~16.7 GB/s |
476
+ | 100KB | Complex | 73μs | ~1.4 GB/s |
477
+ | 100KB | Regex | 7μs | ~14.3 GB/s |
478
+ | 100KB | Multiple Rules | 73μs | ~1.4 GB/s |
479
+ | 10MB | Simple | 204μs | ~49 GB/s |
480
+
481
+ #### Advanced Features Performance
482
+
483
+ | Feature | Mean | Notes |
484
+ | ----------------- | ---- | -------------------------- |
485
+ | Variable Scanning | 1μs | Pre-compiled variables |
486
+ | Runtime Variables | 2μs | Variables set at scan time |
487
+ | Async Scanning | 11μs | Non-blocking operations |
488
+
489
+ ## API Reference
391
490
 
392
491
  ### Functions
393
492
 
@@ -395,10 +494,10 @@ if (warnings.length > 0) {
395
494
  - `compileToWasm(ruleSource: string, outputPath: string, options?: CompilerOptions)` - Compiles yara rules from a string to WASM file.
396
495
  - `compileFileToWasm(rulesPath: string, outputPath: string, options?: CompilerOptions)` - Compiles yara rules from a file to WASM file.
397
496
  - `validate(ruleSource: string, options?: CompilerOptions)` - Validates yara rules without executing them.
398
- - `create(options?: CompilerOptions)` - Creates an empty rules scanner to add rules incrementally.
497
+ - `create()` - Creates an empty rules scanner to add rules incrementally.
399
498
  - `fromFile(rulePath: string, options?: CompilerOptions)` - Compiles yara rules from a file.
400
499
 
401
- ### yarax Methods
500
+ ### YaraX Methods
402
501
 
403
502
  - `getWarnings()` - Get compiler warnings.
404
503
  - `scan(data: Buffer, variables?: Record<string, string | number>)` - Scan a buffer.
@@ -409,10 +508,22 @@ if (warnings.length > 0) {
409
508
  - `emitWasmFileAsync(filePath: string)` - Emit compiled rules to WASM file asynchronously.
410
509
  - `addRuleSource(rules: string)` - Add rules from a string to an existing scanner.
411
510
  - `addRuleFile(filePath: string)` - Add rules from a file to an existing scanner.
412
-
413
- ### Rule Validation
414
-
415
- - `validate(rules: string, options?: CompilerOptions)` - Validate yara rules without executing them.
511
+ - `defineVariable(name: string, value: string)` - Define a variable for the YARA compiler.
512
+ - `setMaxMatchesPerPattern(maxMatches: number)` - **(v1.7.0+)** Set the maximum number of matches per pattern.
513
+ - `setUseMmap(useMmap: boolean)` - **(v1.6.0+)** Enable or disable memory-mapped files for scanning.
514
+
515
+ ### CompilerOptions
516
+
517
+ - `defineVariables?: object` - Define global variables for the YARA rules.
518
+ - `ignoreModules?: string[]` - List of module names to ignore during compilation.
519
+ - `bannedModules?: BannedModule[]` - List of banned modules that cannot be used.
520
+ - `features?: string[]` - List of features to enable for the YARA rules.
521
+ - `relaxedReSyntax?: boolean` - Use relaxed regular expression syntax.
522
+ - `conditionOptimization?: boolean` - Optimize conditions in the YARA rules.
523
+ - `errorOnSlowPattern?: boolean` - Raise an error on slow patterns.
524
+ - `errorOnSlowLoop?: boolean` - Raise an error on slow loops.
525
+ - `includeDirectories?: string[]` - **(v1.5.0+)** Directories where the compiler should look for included files.
526
+ - `enableIncludes?: boolean` - **(v1.5.0+)** Enable or disable include statements in YARA rules.
416
527
 
417
528
  ## Licenses
418
529
 
package/index.d.ts CHANGED
@@ -1,77 +1,153 @@
1
1
  /* auto-generated by NAPI-RS */
2
2
  /* eslint-disable */
3
3
  /**
4
- * YaraX struct represents the YARA rules and their associated data.
5
- * It contains the compiled rules, source code, warnings, and variables.
4
+ * The main YARA-X scanner struct.
6
5
  *
7
- * See [yara_x::Rules](https://docs.rs/yara-x/latest/yara_x/struct.Rules.html) for more details.
6
+ * This struct represents compiled YARA rules and provides methods for scanning
7
+ * data and files. It includes performance optimizations like scanner caching.
8
8
  */
9
9
  export declare class YaraX {
10
+ /** Returns the compiler warnings generated during the compilation process. */
10
11
  getWarnings(): Array<CompilerWarning>
12
+ /**
13
+ * Sets the maximum number of matches per pattern.
14
+ *
15
+ * # Arguments
16
+ *
17
+ * * `max_matches` - The maximum number of matches per pattern
18
+ */
19
+ setMaxMatchesPerPattern(maxMatches: number): void
20
+ /**
21
+ * Sets whether to use memory-mapped files for scanning.
22
+ *
23
+ * # Arguments
24
+ *
25
+ * * `use_mmap` - Whether to use memory-mapped files
26
+ */
27
+ setUseMmap(useMmap: boolean): void
11
28
  /**
12
29
  * Scans the provided data using the compiled YARA rules.
13
- * This function takes the scanned data and an optional object of variables,
14
- * and returns a vector of RuleMatch representing the matching rules found during the scan.
30
+ *
31
+ * # Arguments
32
+ *
33
+ * * `env` - The N-API environment
34
+ * * `data` - The data to scan
35
+ * * `variables` - Optional variables to set for this scan
36
+ *
37
+ * # Returns
38
+ *
39
+ * A vector of matching rules
15
40
  */
16
41
  scan(data: Buffer, variables?: Record<string, string | number>): Array<RuleMatch>
17
42
  /**
18
43
  * Scans a file using the compiled YARA rules.
19
- * This function takes the file path and an optional object of variables,
20
- * and returns a vector of RuleMatch representing the matching rules found during the scan.
44
+ *
45
+ * # Arguments
46
+ *
47
+ * * `env` - The N-API environment
48
+ * * `file_path` - Path to the file to scan
49
+ * * `variables` - Optional variables to set for this scan
50
+ *
51
+ * # Returns
52
+ *
53
+ * A vector of matching rules
21
54
  */
22
55
  scanFile(filePath: string, variables?: Record<string, string | number>): Array<RuleMatch>
23
56
  /**
24
57
  * Emits a WASM file from the compiled YARA rules.
25
- * This function takes the output path and writes the compiled rules to a WASM file.
58
+ *
59
+ * # Arguments
60
+ *
61
+ * * `output_path` - Path where the WASM file should be written
62
+ *
63
+ * # Returns
64
+ *
65
+ * Ok(()) on success, or an error if emission fails
26
66
  */
27
67
  emitWasmFile(outputPath: string): void
28
68
  /**
29
69
  * Scans the provided data asynchronously using the compiled YARA rules.
30
- * This function takes the scanned data and an optional object of variables,
31
- * and returns an AsyncTask that will resolve to a vector of RuleMatch representing the matching
32
- * rules found during the scan.
33
70
  *
34
- * This allows for non-blocking scanning of data, which can be useful for large datasets or
35
- * performance-critical applications.
71
+ * # Arguments
72
+ *
73
+ * * `data` - The data to scan
74
+ * * `variables` - Optional variables to set for this scan
75
+ *
76
+ * # Returns
77
+ *
78
+ * An async task that resolves to a vector of matching rules
36
79
  */
37
- scanAsync(data: Buffer, variables?: object | undefined | null): Promise<unknown>
80
+ scanAsync(data: Buffer, variables?: object | undefined | null): Promise<Array<RuleMatch>>
38
81
  /**
39
82
  * Scans a file asynchronously using the compiled YARA rules.
40
- * This function takes the file path and an optional object of variables,
41
- * and returns an AsyncTask that will resolve to a vector of RuleMatch representing the matching
42
- * rules found during the scan.
43
83
  *
44
- * This allows for non-blocking scanning of files, which can be useful for large files or
45
- * performance-critical applications.
84
+ * # Arguments
85
+ *
86
+ * * `file_path` - Path to the file to scan
87
+ * * `variables` - Optional variables to set for this scan
88
+ *
89
+ * # Returns
90
+ *
91
+ * An async task that resolves to a vector of matching rules
46
92
  */
47
- scanFileAsync(filePath: string, variables?: object | undefined | null): Promise<unknown>
93
+ scanFileAsync(filePath: string, variables?: object | undefined | null): Promise<Array<RuleMatch>>
48
94
  /**
49
95
  * Emits a WASM file asynchronously from the compiled YARA rules.
50
- * This function takes the output path
51
- * and returns an AsyncTask that will resolve when the WASM file is successfully emitted.
96
+ *
97
+ * # Arguments
98
+ *
99
+ * * `output_path` - Path where the WASM file should be written
100
+ *
101
+ * # Returns
102
+ *
103
+ * An async task that completes when the WASM file is written
52
104
  */
53
105
  emitWasmFileAsync(outputPath: string): Promise<unknown>
54
106
  /**
55
107
  * Adds a rule source to the YARA compiler.
56
- * This function takes a rule source string,
57
- * compiles it, and updates the YaraX instance with the new rules.
108
+ *
109
+ * # Arguments
110
+ *
111
+ * * `rule_source` - The YARA rule source code to add
112
+ *
113
+ * # Returns
114
+ *
115
+ * Ok(()) on success, or an error if compilation fails
58
116
  */
59
117
  addRuleSource(ruleSource: string): void
60
118
  /**
61
119
  * Adds a rule file to the YARA compiler.
62
- * This function takes a file path,
63
- * reads the file content, and adds it to the YaraX instance.
120
+ *
121
+ * # Arguments
122
+ *
123
+ * * `file_path` - Path to the file containing YARA rules
124
+ *
125
+ * # Returns
126
+ *
127
+ * Ok(()) on success, or an error if reading or compilation fails
64
128
  */
65
129
  addRuleFile(filePath: string): void
66
130
  /**
67
131
  * Defines a variable for the YARA compiler.
68
- * This function takes a variable name and value,
69
- * and adds it to the YaraX instance.
132
+ *
133
+ * # Arguments
134
+ *
135
+ * * `name` - The variable name
136
+ * * `value` - The variable value
137
+ *
138
+ * # Returns
139
+ *
140
+ * Ok(()) on success, or an error if compilation fails
70
141
  */
71
142
  defineVariable(name: string, value: string): void
72
143
  }
73
144
 
74
- /** BannedModule struct represents a module that is banned from being used in YARA rules. */
145
+ /**
146
+ * Represents a module that is banned from being used in YARA rules.
147
+ *
148
+ * When a banned module is encountered, compilation will fail with the
149
+ * specified error message.
150
+ */
75
151
  export interface BannedModule {
76
152
  /** The name of the banned module. */
77
153
  name: string
@@ -84,37 +160,37 @@ export interface BannedModule {
84
160
  /**
85
161
  * Compiles a YARA rule source string and returns a YaraX instance with the compiled rules.
86
162
  *
87
- * Exported as `compile` in the NAPI interface.
163
+ * # Arguments
164
+ *
165
+ * * `rule_source` - The YARA rule source code
166
+ * * `options` - Optional compiler options
88
167
  *
89
- * Example
168
+ * # Returns
90
169
  *
91
- * ```javascript
92
- * const { compile } = require('your_yara_module');
93
- * const yarax = compile('rule example { strings: $a = "example" condition: $a }');
94
- * ```
170
+ * A YaraX instance with compiled rules
95
171
  */
96
- export declare function compile(ruleSource: string, options?: CompilerOptions | undefined | null): YaraX
172
+ export declare function compile(ruleSource: string, options?: CompilerOptionsType | undefined | null): YaraXImpl
97
173
 
98
174
  /**
99
175
  * Compiles a YARA rule file to a WASM file.
100
176
  *
101
- * Exported as `compileFileToWasm` in the NAPI interface.
177
+ * # Arguments
102
178
  *
103
- * Example
179
+ * * `rule_path` - Path to the file containing YARA rules
180
+ * * `output_path` - Path where the WASM file should be written
181
+ * * `options` - Optional compiler options
104
182
  *
105
- * ```javascript
106
- * const { compileFileToWasm } = require('your_yara_module');
107
- * compileFileToWasm('path/to/rule_file.yar', 'output.wasm');
108
- * ```
183
+ * # Returns
184
+ *
185
+ * Ok(()) on success, or an error if reading, compilation, or emission fails
109
186
  */
110
- export declare function compileFileToWasm(rulePath: string, outputPath: string, options?: CompilerOptions | undefined | null): void
187
+ export declare function compileFileToWasm(rulePath: string, outputPath: string, options?: CompilerOptionsType | undefined | null): void
111
188
 
112
189
  /**
113
- * CompilerError struct represents an error generated by the YARA compiler.
190
+ * An error generated by the YARA compiler.
114
191
  *
115
- * See
116
- * [yara_x::CompileError](https://docs.rs/yara-x/latest/yara_x/errors/enum.CompileError.html)
117
- * for more details.
192
+ * Errors prevent successful compilation and must be resolved before
193
+ * the rules can be used.
118
194
  */
119
195
  export interface CompilerError {
120
196
  /** The code of the error. */
@@ -130,8 +206,10 @@ export interface CompilerError {
130
206
  }
131
207
 
132
208
  /**
133
- * CompileResult struct represents the result of compiling YARA rules.
134
- * It contains any warnings or errors generated during the compilation process.
209
+ * The result of compiling YARA rules.
210
+ *
211
+ * Contains any warnings or errors generated during the compilation process.
212
+ * If errors are present, the compilation failed.
135
213
  */
136
214
  export interface CompileResult {
137
215
  /** Any warnings generated during the compilation process. */
@@ -141,10 +219,10 @@ export interface CompileResult {
141
219
  }
142
220
 
143
221
  /**
144
- * CompilerOptions struct represents the options for the YARA compiler.
222
+ * Options for configuring the YARA compiler.
145
223
  *
146
- * See [yara_x::Compiler](https://docs.rs/yara-x/latest/yara_x/struct.Compiler.html) for more
147
- * details.
224
+ * These options control various aspects of rule compilation including
225
+ * module handling, optimization, and feature flags.
148
226
  */
149
227
  export interface CompilerOptions {
150
228
  /** Defines global variables for the YARA rules. */
@@ -163,13 +241,17 @@ export interface CompilerOptions {
163
241
  errorOnSlowPattern?: boolean
164
242
  /** Whether to raise an error on slow loops. */
165
243
  errorOnSlowLoop?: boolean
244
+ /** A list of directories where the compiler should look for included files. */
245
+ includeDirectories?: Array<string>
246
+ /** Whether to enable include statements in YARA rules. */
247
+ enableIncludes?: boolean
166
248
  }
167
249
 
168
250
  /**
169
- * CompilerWarning struct represents a warning generated by the YARA compiler.
251
+ * A warning generated by the YARA compiler.
170
252
  *
171
- * See [yara_x::CompilerWarning](https://docs.rs/yara-x/latest/yara_x/warnings/enum.Warning.html)
172
- * for more details.
253
+ * Warnings indicate potential issues that don't prevent compilation
254
+ * but may indicate problems with the rules.
173
255
  */
174
256
  export interface CompilerWarning {
175
257
  /** The code of the warning. */
@@ -187,52 +269,46 @@ export interface CompilerWarning {
187
269
  /**
188
270
  * Compiles a YARA rule source string to a WASM file.
189
271
  *
190
- * Exported as `compileToWasm` in the NAPI interface.
272
+ * # Arguments
191
273
  *
192
- * Example
274
+ * * `rule_source` - The YARA rule source code
275
+ * * `output_path` - Path where the WASM file should be written
276
+ * * `options` - Optional compiler options
193
277
  *
194
- * ```javascript
195
- * const { compileToWasm } = require('your_yara_module');
196
- * compileToWasm('rule example { strings: $a = "example" condition: $a }', 'output.wasm');
197
- * ```
278
+ * # Returns
279
+ *
280
+ * Ok(()) on success, or an error if compilation or emission fails
198
281
  */
199
- export declare function compileToWasm(ruleSource: string, outputPath: string, options?: CompilerOptions | undefined | null): void
282
+ export declare function compileToWasm(ruleSource: string, outputPath: string, options?: CompilerOptionsType | undefined | null): void
200
283
 
201
284
  /**
202
285
  * Creates a new YaraX instance with empty rules and no source code.
203
286
  *
204
- * Exported as `create` in the NAPI interface.
205
- *
206
- * Example
207
- *
208
- * ```javascript
209
- * const { create } = require('your_yara_module');
210
- * const yarax = create();
211
- *
212
- * // Now you can add rules or compile them later
287
+ * # Returns
213
288
  *
214
- * yarax.addRuleSource('rule example { strings: $a = "example" condition: $a }');
215
- * yarax.addRuleFile('path/to/rule_file.yar');
216
- * yarax.defineVariable('myVar', 'myValue');
217
- * ```
289
+ * A new YaraX instance with empty rules
218
290
  */
219
- export declare function create(): YaraX
291
+ export declare function create(): YaraXImpl
220
292
 
221
293
  /**
222
294
  * Creates a new YaraX instance from a file containing YARA rules.
223
295
  *
224
- * Exported as `fromFile` in the NAPI interface.
296
+ * # Arguments
225
297
  *
226
- * Example
298
+ * * `rule_path` - Path to the file containing YARA rules
299
+ * * `options` - Optional compiler options
227
300
  *
228
- * ```javascript
229
- * const { fromFile } = require('your_yara_module');
230
- * const yarax = fromFile('path/to/rule_file.yar');
231
- * ```
301
+ * # Returns
302
+ *
303
+ * A YaraX instance with compiled rules from the file
232
304
  */
233
- export declare function fromFile(rulePath: string, options?: CompilerOptions | undefined | null): YaraX
305
+ export declare function fromFile(rulePath: string, options?: CompilerOptionsType | undefined | null): YaraXImpl
234
306
 
235
- /** MatchData struct represents a match found by a YARA rule. */
307
+ /**
308
+ * Represents a match found by a YARA rule pattern.
309
+ *
310
+ * Contains information about where the match occurred and what data was matched.
311
+ */
236
312
  export interface MatchData {
237
313
  /** The offset of the match in the scanned data. */
238
314
  offset: number
@@ -245,9 +321,9 @@ export interface MatchData {
245
321
  }
246
322
 
247
323
  /**
248
- * RuleMatch struct represents a matching rule found during scanning.
324
+ * Represents a matching rule found during scanning.
249
325
  *
250
- * See [yara_::Match](https://docs.rs/yara-x/latest/yara_x/struct.Match.html) for more details.
326
+ * Contains the rule's metadata, tags, and all pattern matches.
251
327
  */
252
328
  export interface RuleMatch {
253
329
  /** The identifier of the rule that matched. */
@@ -262,17 +338,32 @@ export interface RuleMatch {
262
338
  matches: Array<MatchData>
263
339
  }
264
340
 
341
+ /**
342
+ * Options for configuring scanning operations.
343
+ *
344
+ * These options control resource usage and performance characteristics
345
+ * during rule scanning.
346
+ */
347
+ export interface ScanOptions {
348
+ /** Maximum number of matches per pattern. When a pattern reaches this limit, it won't produce more matches. */
349
+ maxMatchesPerPattern?: number
350
+ /** Whether to use memory-mapped files for scanning. Disabling this is safer but slower. */
351
+ useMmap?: boolean
352
+ }
353
+
265
354
  /**
266
355
  * Compiles a YARA rule source string and returns any warnings or errors generated during the
267
356
  * compilation process.
268
357
  *
269
- * Exported as `validate` in the NAPI interface.
358
+ * This function validates YARA rules without creating a scanner instance.
359
+ *
360
+ * # Arguments
361
+ *
362
+ * * `rule_source` - The YARA rule source code
363
+ * * `options` - Optional compiler options
270
364
  *
271
- * Example
365
+ * # Returns
272
366
  *
273
- * ```javascript
274
- * const { validate } = require('your_yara_module');
275
- * const result = validate('rule example { strings: $a = "example" condition: $a }');
276
- * ```
367
+ * A CompileResult containing any warnings and errors
277
368
  */
278
- export declare function validate(ruleSource: string, options?: CompilerOptions | undefined | null): CompileResult
369
+ export declare function validate(ruleSource: string, options?: CompilerOptionsType | undefined | null): CompileResult
package/index.js CHANGED
@@ -66,7 +66,7 @@ const isMuslFromChildProcess = () => {
66
66
  function requireNative() {
67
67
  if (process.env.NAPI_RS_NATIVE_LIBRARY_PATH) {
68
68
  try {
69
- nativeBinding = require(process.env.NAPI_RS_NATIVE_LIBRARY_PATH);
69
+ return require(process.env.NAPI_RS_NATIVE_LIBRARY_PATH);
70
70
  } catch (err) {
71
71
  loadErrors.push(err)
72
72
  }
@@ -78,7 +78,12 @@ function requireNative() {
78
78
  loadErrors.push(e)
79
79
  }
80
80
  try {
81
- return require('@litko/yara-x-android-arm64')
81
+ const binding = require('@litko/yara-x-android-arm64')
82
+ const bindingPackageVersion = require('@litko/yara-x-android-arm64/package.json').version
83
+ if (bindingPackageVersion !== '0.3.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
84
+ throw new Error(`Native binding package version mismatch, expected 0.3.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
85
+ }
86
+ return binding
82
87
  } catch (e) {
83
88
  loadErrors.push(e)
84
89
  }
@@ -89,7 +94,12 @@ function requireNative() {
89
94
  loadErrors.push(e)
90
95
  }
91
96
  try {
92
- return require('@litko/yara-x-android-arm-eabi')
97
+ const binding = require('@litko/yara-x-android-arm-eabi')
98
+ const bindingPackageVersion = require('@litko/yara-x-android-arm-eabi/package.json').version
99
+ if (bindingPackageVersion !== '0.3.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
100
+ throw new Error(`Native binding package version mismatch, expected 0.3.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
101
+ }
102
+ return binding
93
103
  } catch (e) {
94
104
  loadErrors.push(e)
95
105
  }
@@ -98,16 +108,39 @@ function requireNative() {
98
108
  }
99
109
  } else if (process.platform === 'win32') {
100
110
  if (process.arch === 'x64') {
111
+ if (process.report?.getReport?.()?.header?.osName?.startsWith?.('MINGW')) {
112
+ try {
113
+ return require('./yara-x.win32-x64-gnu.node')
114
+ } catch (e) {
115
+ loadErrors.push(e)
116
+ }
101
117
  try {
118
+ const binding = require('@litko/yara-x-win32-x64-gnu')
119
+ const bindingPackageVersion = require('@litko/yara-x-win32-x64-gnu/package.json').version
120
+ if (bindingPackageVersion !== '0.3.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
121
+ throw new Error(`Native binding package version mismatch, expected 0.3.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
122
+ }
123
+ return binding
124
+ } catch (e) {
125
+ loadErrors.push(e)
126
+ }
127
+ } else {
128
+ try {
102
129
  return require('./yara-x.win32-x64-msvc.node')
103
130
  } catch (e) {
104
131
  loadErrors.push(e)
105
132
  }
106
133
  try {
107
- return require('@litko/yara-x-win32-x64-msvc')
134
+ const binding = require('@litko/yara-x-win32-x64-msvc')
135
+ const bindingPackageVersion = require('@litko/yara-x-win32-x64-msvc/package.json').version
136
+ if (bindingPackageVersion !== '0.3.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
137
+ throw new Error(`Native binding package version mismatch, expected 0.3.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
138
+ }
139
+ return binding
108
140
  } catch (e) {
109
141
  loadErrors.push(e)
110
142
  }
143
+ }
111
144
  } else if (process.arch === 'ia32') {
112
145
  try {
113
146
  return require('./yara-x.win32-ia32-msvc.node')
@@ -115,7 +148,12 @@ function requireNative() {
115
148
  loadErrors.push(e)
116
149
  }
117
150
  try {
118
- return require('@litko/yara-x-win32-ia32-msvc')
151
+ const binding = require('@litko/yara-x-win32-ia32-msvc')
152
+ const bindingPackageVersion = require('@litko/yara-x-win32-ia32-msvc/package.json').version
153
+ if (bindingPackageVersion !== '0.3.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
154
+ throw new Error(`Native binding package version mismatch, expected 0.3.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
155
+ }
156
+ return binding
119
157
  } catch (e) {
120
158
  loadErrors.push(e)
121
159
  }
@@ -126,7 +164,12 @@ function requireNative() {
126
164
  loadErrors.push(e)
127
165
  }
128
166
  try {
129
- return require('@litko/yara-x-win32-arm64-msvc')
167
+ const binding = require('@litko/yara-x-win32-arm64-msvc')
168
+ const bindingPackageVersion = require('@litko/yara-x-win32-arm64-msvc/package.json').version
169
+ if (bindingPackageVersion !== '0.3.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
170
+ throw new Error(`Native binding package version mismatch, expected 0.3.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
171
+ }
172
+ return binding
130
173
  } catch (e) {
131
174
  loadErrors.push(e)
132
175
  }
@@ -140,7 +183,12 @@ function requireNative() {
140
183
  loadErrors.push(e)
141
184
  }
142
185
  try {
143
- return require('@litko/yara-x-darwin-universal')
186
+ const binding = require('@litko/yara-x-darwin-universal')
187
+ const bindingPackageVersion = require('@litko/yara-x-darwin-universal/package.json').version
188
+ if (bindingPackageVersion !== '0.3.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
189
+ throw new Error(`Native binding package version mismatch, expected 0.3.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
190
+ }
191
+ return binding
144
192
  } catch (e) {
145
193
  loadErrors.push(e)
146
194
  }
@@ -151,7 +199,12 @@ function requireNative() {
151
199
  loadErrors.push(e)
152
200
  }
153
201
  try {
154
- return require('@litko/yara-x-darwin-x64')
202
+ const binding = require('@litko/yara-x-darwin-x64')
203
+ const bindingPackageVersion = require('@litko/yara-x-darwin-x64/package.json').version
204
+ if (bindingPackageVersion !== '0.3.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
205
+ throw new Error(`Native binding package version mismatch, expected 0.3.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
206
+ }
207
+ return binding
155
208
  } catch (e) {
156
209
  loadErrors.push(e)
157
210
  }
@@ -162,7 +215,12 @@ function requireNative() {
162
215
  loadErrors.push(e)
163
216
  }
164
217
  try {
165
- return require('@litko/yara-x-darwin-arm64')
218
+ const binding = require('@litko/yara-x-darwin-arm64')
219
+ const bindingPackageVersion = require('@litko/yara-x-darwin-arm64/package.json').version
220
+ if (bindingPackageVersion !== '0.3.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
221
+ throw new Error(`Native binding package version mismatch, expected 0.3.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
222
+ }
223
+ return binding
166
224
  } catch (e) {
167
225
  loadErrors.push(e)
168
226
  }
@@ -177,7 +235,12 @@ function requireNative() {
177
235
  loadErrors.push(e)
178
236
  }
179
237
  try {
180
- return require('@litko/yara-x-freebsd-x64')
238
+ const binding = require('@litko/yara-x-freebsd-x64')
239
+ const bindingPackageVersion = require('@litko/yara-x-freebsd-x64/package.json').version
240
+ if (bindingPackageVersion !== '0.3.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
241
+ throw new Error(`Native binding package version mismatch, expected 0.3.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
242
+ }
243
+ return binding
181
244
  } catch (e) {
182
245
  loadErrors.push(e)
183
246
  }
@@ -188,7 +251,12 @@ function requireNative() {
188
251
  loadErrors.push(e)
189
252
  }
190
253
  try {
191
- return require('@litko/yara-x-freebsd-arm64')
254
+ const binding = require('@litko/yara-x-freebsd-arm64')
255
+ const bindingPackageVersion = require('@litko/yara-x-freebsd-arm64/package.json').version
256
+ if (bindingPackageVersion !== '0.3.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
257
+ throw new Error(`Native binding package version mismatch, expected 0.3.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
258
+ }
259
+ return binding
192
260
  } catch (e) {
193
261
  loadErrors.push(e)
194
262
  }
@@ -204,7 +272,12 @@ function requireNative() {
204
272
  loadErrors.push(e)
205
273
  }
206
274
  try {
207
- return require('@litko/yara-x-linux-x64-musl')
275
+ const binding = require('@litko/yara-x-linux-x64-musl')
276
+ const bindingPackageVersion = require('@litko/yara-x-linux-x64-musl/package.json').version
277
+ if (bindingPackageVersion !== '0.3.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
278
+ throw new Error(`Native binding package version mismatch, expected 0.3.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
279
+ }
280
+ return binding
208
281
  } catch (e) {
209
282
  loadErrors.push(e)
210
283
  }
@@ -215,7 +288,12 @@ function requireNative() {
215
288
  loadErrors.push(e)
216
289
  }
217
290
  try {
218
- return require('@litko/yara-x-linux-x64-gnu')
291
+ const binding = require('@litko/yara-x-linux-x64-gnu')
292
+ const bindingPackageVersion = require('@litko/yara-x-linux-x64-gnu/package.json').version
293
+ if (bindingPackageVersion !== '0.3.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
294
+ throw new Error(`Native binding package version mismatch, expected 0.3.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
295
+ }
296
+ return binding
219
297
  } catch (e) {
220
298
  loadErrors.push(e)
221
299
  }
@@ -228,7 +306,12 @@ function requireNative() {
228
306
  loadErrors.push(e)
229
307
  }
230
308
  try {
231
- return require('@litko/yara-x-linux-arm64-musl')
309
+ const binding = require('@litko/yara-x-linux-arm64-musl')
310
+ const bindingPackageVersion = require('@litko/yara-x-linux-arm64-musl/package.json').version
311
+ if (bindingPackageVersion !== '0.3.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
312
+ throw new Error(`Native binding package version mismatch, expected 0.3.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
313
+ }
314
+ return binding
232
315
  } catch (e) {
233
316
  loadErrors.push(e)
234
317
  }
@@ -239,7 +322,12 @@ function requireNative() {
239
322
  loadErrors.push(e)
240
323
  }
241
324
  try {
242
- return require('@litko/yara-x-linux-arm64-gnu')
325
+ const binding = require('@litko/yara-x-linux-arm64-gnu')
326
+ const bindingPackageVersion = require('@litko/yara-x-linux-arm64-gnu/package.json').version
327
+ if (bindingPackageVersion !== '0.3.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
328
+ throw new Error(`Native binding package version mismatch, expected 0.3.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
329
+ }
330
+ return binding
243
331
  } catch (e) {
244
332
  loadErrors.push(e)
245
333
  }
@@ -252,7 +340,12 @@ function requireNative() {
252
340
  loadErrors.push(e)
253
341
  }
254
342
  try {
255
- return require('@litko/yara-x-linux-arm-musleabihf')
343
+ const binding = require('@litko/yara-x-linux-arm-musleabihf')
344
+ const bindingPackageVersion = require('@litko/yara-x-linux-arm-musleabihf/package.json').version
345
+ if (bindingPackageVersion !== '0.3.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
346
+ throw new Error(`Native binding package version mismatch, expected 0.3.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
347
+ }
348
+ return binding
256
349
  } catch (e) {
257
350
  loadErrors.push(e)
258
351
  }
@@ -263,7 +356,46 @@ function requireNative() {
263
356
  loadErrors.push(e)
264
357
  }
265
358
  try {
266
- return require('@litko/yara-x-linux-arm-gnueabihf')
359
+ const binding = require('@litko/yara-x-linux-arm-gnueabihf')
360
+ const bindingPackageVersion = require('@litko/yara-x-linux-arm-gnueabihf/package.json').version
361
+ if (bindingPackageVersion !== '0.3.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
362
+ throw new Error(`Native binding package version mismatch, expected 0.3.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
363
+ }
364
+ return binding
365
+ } catch (e) {
366
+ loadErrors.push(e)
367
+ }
368
+ }
369
+ } else if (process.arch === 'loong64') {
370
+ if (isMusl()) {
371
+ try {
372
+ return require('./yara-x.linux-loong64-musl.node')
373
+ } catch (e) {
374
+ loadErrors.push(e)
375
+ }
376
+ try {
377
+ const binding = require('@litko/yara-x-linux-loong64-musl')
378
+ const bindingPackageVersion = require('@litko/yara-x-linux-loong64-musl/package.json').version
379
+ if (bindingPackageVersion !== '0.3.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
380
+ throw new Error(`Native binding package version mismatch, expected 0.3.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
381
+ }
382
+ return binding
383
+ } catch (e) {
384
+ loadErrors.push(e)
385
+ }
386
+ } else {
387
+ try {
388
+ return require('./yara-x.linux-loong64-gnu.node')
389
+ } catch (e) {
390
+ loadErrors.push(e)
391
+ }
392
+ try {
393
+ const binding = require('@litko/yara-x-linux-loong64-gnu')
394
+ const bindingPackageVersion = require('@litko/yara-x-linux-loong64-gnu/package.json').version
395
+ if (bindingPackageVersion !== '0.3.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
396
+ throw new Error(`Native binding package version mismatch, expected 0.3.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
397
+ }
398
+ return binding
267
399
  } catch (e) {
268
400
  loadErrors.push(e)
269
401
  }
@@ -276,7 +408,12 @@ function requireNative() {
276
408
  loadErrors.push(e)
277
409
  }
278
410
  try {
279
- return require('@litko/yara-x-linux-riscv64-musl')
411
+ const binding = require('@litko/yara-x-linux-riscv64-musl')
412
+ const bindingPackageVersion = require('@litko/yara-x-linux-riscv64-musl/package.json').version
413
+ if (bindingPackageVersion !== '0.3.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
414
+ throw new Error(`Native binding package version mismatch, expected 0.3.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
415
+ }
416
+ return binding
280
417
  } catch (e) {
281
418
  loadErrors.push(e)
282
419
  }
@@ -287,7 +424,12 @@ function requireNative() {
287
424
  loadErrors.push(e)
288
425
  }
289
426
  try {
290
- return require('@litko/yara-x-linux-riscv64-gnu')
427
+ const binding = require('@litko/yara-x-linux-riscv64-gnu')
428
+ const bindingPackageVersion = require('@litko/yara-x-linux-riscv64-gnu/package.json').version
429
+ if (bindingPackageVersion !== '0.3.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
430
+ throw new Error(`Native binding package version mismatch, expected 0.3.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
431
+ }
432
+ return binding
291
433
  } catch (e) {
292
434
  loadErrors.push(e)
293
435
  }
@@ -299,7 +441,12 @@ function requireNative() {
299
441
  loadErrors.push(e)
300
442
  }
301
443
  try {
302
- return require('@litko/yara-x-linux-ppc64-gnu')
444
+ const binding = require('@litko/yara-x-linux-ppc64-gnu')
445
+ const bindingPackageVersion = require('@litko/yara-x-linux-ppc64-gnu/package.json').version
446
+ if (bindingPackageVersion !== '0.3.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
447
+ throw new Error(`Native binding package version mismatch, expected 0.3.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
448
+ }
449
+ return binding
303
450
  } catch (e) {
304
451
  loadErrors.push(e)
305
452
  }
@@ -310,7 +457,12 @@ function requireNative() {
310
457
  loadErrors.push(e)
311
458
  }
312
459
  try {
313
- return require('@litko/yara-x-linux-s390x-gnu')
460
+ const binding = require('@litko/yara-x-linux-s390x-gnu')
461
+ const bindingPackageVersion = require('@litko/yara-x-linux-s390x-gnu/package.json').version
462
+ if (bindingPackageVersion !== '0.3.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
463
+ throw new Error(`Native binding package version mismatch, expected 0.3.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
464
+ }
465
+ return binding
314
466
  } catch (e) {
315
467
  loadErrors.push(e)
316
468
  }
@@ -320,34 +472,49 @@ function requireNative() {
320
472
  } else if (process.platform === 'openharmony') {
321
473
  if (process.arch === 'arm64') {
322
474
  try {
323
- return require('./yara-x.linux-arm64-ohos.node')
475
+ return require('./yara-x.openharmony-arm64.node')
324
476
  } catch (e) {
325
477
  loadErrors.push(e)
326
478
  }
327
479
  try {
328
- return require('@litko/yara-x-linux-arm64-ohos')
480
+ const binding = require('@litko/yara-x-openharmony-arm64')
481
+ const bindingPackageVersion = require('@litko/yara-x-openharmony-arm64/package.json').version
482
+ if (bindingPackageVersion !== '0.3.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
483
+ throw new Error(`Native binding package version mismatch, expected 0.3.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
484
+ }
485
+ return binding
329
486
  } catch (e) {
330
487
  loadErrors.push(e)
331
488
  }
332
489
  } else if (process.arch === 'x64') {
333
490
  try {
334
- return require('./yara-x.linux-x64-ohos.node')
491
+ return require('./yara-x.openharmony-x64.node')
335
492
  } catch (e) {
336
493
  loadErrors.push(e)
337
494
  }
338
495
  try {
339
- return require('@litko/yara-x-linux-x64-ohos')
496
+ const binding = require('@litko/yara-x-openharmony-x64')
497
+ const bindingPackageVersion = require('@litko/yara-x-openharmony-x64/package.json').version
498
+ if (bindingPackageVersion !== '0.3.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
499
+ throw new Error(`Native binding package version mismatch, expected 0.3.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
500
+ }
501
+ return binding
340
502
  } catch (e) {
341
503
  loadErrors.push(e)
342
504
  }
343
505
  } else if (process.arch === 'arm') {
344
506
  try {
345
- return require('./yara-x.linux-arm-ohos.node')
507
+ return require('./yara-x.openharmony-arm.node')
346
508
  } catch (e) {
347
509
  loadErrors.push(e)
348
510
  }
349
511
  try {
350
- return require('@litko/yara-x-linux-arm-ohos')
512
+ const binding = require('@litko/yara-x-openharmony-arm')
513
+ const bindingPackageVersion = require('@litko/yara-x-openharmony-arm/package.json').version
514
+ if (bindingPackageVersion !== '0.3.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
515
+ throw new Error(`Native binding package version mismatch, expected 0.3.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
516
+ }
517
+ return binding
351
518
  } catch (e) {
352
519
  loadErrors.push(e)
353
520
  }
@@ -362,22 +529,32 @@ function requireNative() {
362
529
  nativeBinding = requireNative()
363
530
 
364
531
  if (!nativeBinding || process.env.NAPI_RS_FORCE_WASI) {
532
+ let wasiBinding = null
533
+ let wasiBindingError = null
365
534
  try {
366
- nativeBinding = require('./yara-x.wasi.cjs')
535
+ wasiBinding = require('./yara-x.wasi.cjs')
536
+ nativeBinding = wasiBinding
367
537
  } catch (err) {
368
538
  if (process.env.NAPI_RS_FORCE_WASI) {
369
- loadErrors.push(err)
539
+ wasiBindingError = err
370
540
  }
371
541
  }
372
542
  if (!nativeBinding) {
373
543
  try {
374
- nativeBinding = require('@litko/yara-x-wasm32-wasi')
544
+ wasiBinding = require('@litko/yara-x-wasm32-wasi')
545
+ nativeBinding = wasiBinding
375
546
  } catch (err) {
376
547
  if (process.env.NAPI_RS_FORCE_WASI) {
548
+ wasiBindingError.cause = err
377
549
  loadErrors.push(err)
378
550
  }
379
551
  }
380
552
  }
553
+ if (process.env.NAPI_RS_FORCE_WASI === 'error' && !wasiBinding) {
554
+ const error = new Error('WASI binding not found and NAPI_RS_FORCE_WASI is set to error')
555
+ error.cause = wasiBindingError
556
+ throw error
557
+ }
381
558
  }
382
559
 
383
560
  if (!nativeBinding) {
@@ -386,7 +563,12 @@ if (!nativeBinding) {
386
563
  `Cannot find native binding. ` +
387
564
  `npm has a bug related to optional dependencies (https://github.com/npm/cli/issues/4828). ` +
388
565
  'Please try `npm i` again after removing both package-lock.json and node_modules directory.',
389
- { cause: loadErrors }
566
+ {
567
+ cause: loadErrors.reduce((err, cur) => {
568
+ cur.cause = err
569
+ return cur
570
+ }),
571
+ },
390
572
  )
391
573
  }
392
574
  throw new Error(`Failed to load native binding`)
package/package.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "@litko/yara-x",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "main": "index.js",
5
5
  "types": "index.d.ts",
6
- "packageManager": "pnpm@10.13.1",
6
+ "packageManager": "pnpm@10.18.0",
7
7
  "napi": {
8
8
  "binaryName": "yara-x",
9
9
  "targets": [
@@ -14,9 +14,9 @@
14
14
  },
15
15
  "license": "MIT",
16
16
  "devDependencies": {
17
- "@napi-rs/cli": "^3.0.0",
18
- "@napi-rs/wasm-runtime": "^1.0.0",
19
- "@types/node": "^22.13.10"
17
+ "@napi-rs/cli": "^3.3.0",
18
+ "@napi-rs/wasm-runtime": "^1.0.6",
19
+ "@types/node": "^24.6.2"
20
20
  },
21
21
  "engines": {
22
22
  "node": ">= 20"
@@ -41,7 +41,10 @@
41
41
  "universal": "napi universal",
42
42
  "version": "napi version",
43
43
  "test": "node --test __test__/index.spec.mjs",
44
- "benchmark": "node __test__/benchmark.mjs"
44
+ "benchmark": "node __test__/benchmark.mjs",
45
+ "profile": "node --expose-gc __test__/run-profiling.mjs",
46
+ "profile:baseline": "node --expose-gc __test__/run-profiling.mjs --baseline",
47
+ "profile:compare": "node --expose-gc __test__/run-profiling.mjs --compare __test__/baseline-performance.json"
45
48
  },
46
49
  "files": [
47
50
  "index.js",
@@ -56,8 +59,8 @@
56
59
  "rust"
57
60
  ],
58
61
  "optionalDependencies": {
59
- "@litko/yara-x-darwin-x64": "0.2.0",
60
- "@litko/yara-x-darwin-arm64": "0.2.0",
61
- "@litko/yara-x-linux-x64-gnu": "0.2.0"
62
+ "@litko/yara-x-darwin-x64": "0.3.0",
63
+ "@litko/yara-x-darwin-arm64": "0.3.0",
64
+ "@litko/yara-x-linux-x64-gnu": "0.3.0"
62
65
  }
63
66
  }