@cyvest/cyvest-js 2.0.1

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/dist/index.js ADDED
@@ -0,0 +1,1768 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var index_exports = {};
32
+ __export(index_exports, {
33
+ LEVEL_COLORS: () => LEVEL_COLORS,
34
+ LEVEL_ORDER: () => LEVEL_ORDER,
35
+ LEVEL_VALUES: () => LEVEL_VALUES,
36
+ areConnected: () => areConnected,
37
+ compareLevels: () => compareLevels,
38
+ countRelationshipsByType: () => countRelationshipsByType,
39
+ findChecksAtLeast: () => findChecksAtLeast,
40
+ findChecksByCheckId: () => findChecksByCheckId,
41
+ findChecksByLevel: () => findChecksByLevel,
42
+ findChecksByScope: () => findChecksByScope,
43
+ findContainersAtLeast: () => findContainersAtLeast,
44
+ findContainersByLevel: () => findContainersByLevel,
45
+ findExternalObservables: () => findExternalObservables,
46
+ findInternalObservables: () => findInternalObservables,
47
+ findLeafObservables: () => findLeafObservables,
48
+ findManuallyScored: () => findManuallyScored,
49
+ findObservablesAtLeast: () => findObservablesAtLeast,
50
+ findObservablesByLevel: () => findObservablesByLevel,
51
+ findObservablesByType: () => findObservablesByType,
52
+ findObservablesByValue: () => findObservablesByValue,
53
+ findObservablesContaining: () => findObservablesContaining,
54
+ findObservablesMatching: () => findObservablesMatching,
55
+ findObservablesWithThreatIntel: () => findObservablesWithThreatIntel,
56
+ findOrphanObservables: () => findOrphanObservables,
57
+ findPath: () => findPath,
58
+ findRootObservables: () => findRootObservables,
59
+ findThreatIntelAtLeast: () => findThreatIntelAtLeast,
60
+ findThreatIntelByLevel: () => findThreatIntelByLevel,
61
+ findThreatIntelBySource: () => findThreatIntelBySource,
62
+ findWhitelistedObservables: () => findWhitelistedObservables,
63
+ generateCheckKey: () => generateCheckKey,
64
+ generateContainerKey: () => generateContainerKey,
65
+ generateEnrichmentKey: () => generateEnrichmentKey,
66
+ generateObservableKey: () => generateObservableKey,
67
+ generateThreatIntelKey: () => generateThreatIntelKey,
68
+ getAllChecks: () => getAllChecks,
69
+ getAllContainers: () => getAllContainers,
70
+ getAllEnrichments: () => getAllEnrichments,
71
+ getAllObservableTypes: () => getAllObservableTypes,
72
+ getAllObservables: () => getAllObservables,
73
+ getAllRelationshipTypes: () => getAllRelationshipTypes,
74
+ getAllScopes: () => getAllScopes,
75
+ getAllThreatIntelSources: () => getAllThreatIntelSources,
76
+ getAllThreatIntels: () => getAllThreatIntels,
77
+ getCheck: () => getCheck,
78
+ getCheckByIdScope: () => getCheckByIdScope,
79
+ getChecksForContainer: () => getChecksForContainer,
80
+ getChecksForObservable: () => getChecksForObservable,
81
+ getColorForLevel: () => getColorForLevel,
82
+ getColorForScore: () => getColorForScore,
83
+ getContainer: () => getContainer,
84
+ getContainerByPath: () => getContainerByPath,
85
+ getCounts: () => getCounts,
86
+ getDataExtraction: () => getDataExtraction,
87
+ getEnrichment: () => getEnrichment,
88
+ getEnrichmentByName: () => getEnrichmentByName,
89
+ getEntityLevel: () => getEntityLevel,
90
+ getHighestScoringChecks: () => getHighestScoringChecks,
91
+ getHighestScoringObservables: () => getHighestScoringObservables,
92
+ getLevelFromScore: () => getLevelFromScore,
93
+ getMaliciousChecks: () => getMaliciousChecks,
94
+ getMaliciousObservables: () => getMaliciousObservables,
95
+ getObservable: () => getObservable,
96
+ getObservableByTypeValue: () => getObservableByTypeValue,
97
+ getObservableChildren: () => getObservableChildren,
98
+ getObservableGraph: () => getObservableGraph,
99
+ getObservableParents: () => getObservableParents,
100
+ getObservablesForCheck: () => getObservablesForCheck,
101
+ getReachableObservables: () => getReachableObservables,
102
+ getRelatedObservables: () => getRelatedObservables,
103
+ getRelatedObservablesByDirection: () => getRelatedObservablesByDirection,
104
+ getRelatedObservablesByType: () => getRelatedObservablesByType,
105
+ getRelationshipsForObservable: () => getRelationshipsForObservable,
106
+ getStats: () => getStats,
107
+ getStatsChecks: () => getStatsChecks,
108
+ getSuspiciousChecks: () => getSuspiciousChecks,
109
+ getSuspiciousObservables: () => getSuspiciousObservables,
110
+ getThreatIntel: () => getThreatIntel,
111
+ getThreatIntelBySourceObservable: () => getThreatIntelBySourceObservable,
112
+ getThreatIntelsForObservable: () => getThreatIntelsForObservable,
113
+ getWhitelists: () => getWhitelists,
114
+ hasLevel: () => hasLevel,
115
+ isCyvest: () => isCyvest,
116
+ isLevelAtLeast: () => isLevelAtLeast,
117
+ isLevelHigherThan: () => isLevelHigherThan,
118
+ isLevelLowerThan: () => isLevelLowerThan,
119
+ isValidLevel: () => isValidLevel,
120
+ maxLevel: () => maxLevel,
121
+ minLevel: () => minLevel,
122
+ normalizeLevel: () => normalizeLevel,
123
+ parseCheckKey: () => parseCheckKey,
124
+ parseCyvest: () => parseCyvest,
125
+ parseKeyType: () => parseKeyType,
126
+ parseObservableKey: () => parseObservableKey,
127
+ parseThreatIntelKey: () => parseThreatIntelKey,
128
+ sortChecksByLevel: () => sortChecksByLevel,
129
+ sortChecksByScore: () => sortChecksByScore,
130
+ sortObservablesByLevel: () => sortObservablesByLevel,
131
+ sortObservablesByScore: () => sortObservablesByScore,
132
+ validateKey: () => validateKey
133
+ });
134
+ module.exports = __toCommonJS(index_exports);
135
+
136
+ // src/helpers.ts
137
+ var import__ = __toESM(require("ajv/dist/2020"));
138
+ var import_ajv_formats = __toESM(require("ajv-formats"));
139
+
140
+ // ../../../schema/cyvest.schema.json
141
+ var cyvest_schema_default = {
142
+ $schema: "https://json-schema.org/draft/2020-12/schema",
143
+ $id: "https://cyvest.io/schema/investigation.json",
144
+ title: "Cyvest Investigation",
145
+ type: "object",
146
+ additionalProperties: false,
147
+ required: [
148
+ "score",
149
+ "level",
150
+ "whitelisted",
151
+ "whitelists",
152
+ "observables",
153
+ "checks",
154
+ "checks_by_level",
155
+ "threat_intels",
156
+ "enrichments",
157
+ "containers",
158
+ "stats",
159
+ "stats_checks",
160
+ "data_extraction"
161
+ ],
162
+ properties: {
163
+ score: {
164
+ type: "number"
165
+ },
166
+ level: {
167
+ $ref: "#/$defs/level"
168
+ },
169
+ whitelisted: {
170
+ type: "boolean"
171
+ },
172
+ whitelists: {
173
+ type: "array",
174
+ items: {
175
+ $ref: "#/$defs/whitelist"
176
+ },
177
+ default: []
178
+ },
179
+ observables: {
180
+ type: "object",
181
+ additionalProperties: {
182
+ $ref: "#/$defs/observable"
183
+ },
184
+ default: {}
185
+ },
186
+ checks: {
187
+ type: "object",
188
+ additionalProperties: {
189
+ type: "array",
190
+ items: {
191
+ $ref: "#/$defs/check"
192
+ },
193
+ default: []
194
+ },
195
+ default: {}
196
+ },
197
+ checks_by_level: {
198
+ type: "object",
199
+ additionalProperties: {
200
+ type: "array",
201
+ items: {
202
+ type: "string"
203
+ },
204
+ default: []
205
+ },
206
+ default: {}
207
+ },
208
+ threat_intels: {
209
+ type: "object",
210
+ additionalProperties: {
211
+ $ref: "#/$defs/threat_intel"
212
+ },
213
+ default: {}
214
+ },
215
+ enrichments: {
216
+ type: "object",
217
+ additionalProperties: {
218
+ $ref: "#/$defs/enrichment"
219
+ },
220
+ default: {}
221
+ },
222
+ containers: {
223
+ type: "object",
224
+ additionalProperties: {
225
+ $ref: "#/$defs/container"
226
+ },
227
+ default: {}
228
+ },
229
+ stats: {
230
+ $ref: "#/$defs/statistics"
231
+ },
232
+ stats_checks: {
233
+ $ref: "#/$defs/stats_checks"
234
+ },
235
+ data_extraction: {
236
+ $ref: "#/$defs/data_extraction"
237
+ }
238
+ },
239
+ $defs: {
240
+ level: {
241
+ type: "string",
242
+ enum: [
243
+ "NONE",
244
+ "TRUSTED",
245
+ "INFO",
246
+ "SAFE",
247
+ "NOTABLE",
248
+ "SUSPICIOUS",
249
+ "MALICIOUS"
250
+ ],
251
+ description: "Security level classification from NONE (lowest) to MALICIOUS (highest)."
252
+ },
253
+ relationship_direction: {
254
+ type: "string",
255
+ enum: [
256
+ "outbound",
257
+ "inbound",
258
+ "bidirectional"
259
+ ],
260
+ description: "Direction of a relationship between observables."
261
+ },
262
+ score_policy: {
263
+ type: "string",
264
+ enum: [
265
+ "auto",
266
+ "manual"
267
+ ],
268
+ description: "Score computation policy: 'auto' calculates from level, 'manual' uses explicit score."
269
+ },
270
+ score_mode: {
271
+ type: "string",
272
+ enum: [
273
+ "max",
274
+ "sum"
275
+ ],
276
+ description: "Score aggregation mode: 'max' takes highest score, 'sum' adds all scores."
277
+ },
278
+ whitelist: {
279
+ type: "object",
280
+ required: [
281
+ "identifier",
282
+ "name"
283
+ ],
284
+ properties: {
285
+ identifier: {
286
+ type: "string"
287
+ },
288
+ name: {
289
+ type: "string"
290
+ },
291
+ justification: {
292
+ type: [
293
+ "string",
294
+ "null"
295
+ ]
296
+ }
297
+ },
298
+ additionalProperties: false
299
+ },
300
+ relationship: {
301
+ type: "object",
302
+ required: [
303
+ "target_key",
304
+ "relationship_type",
305
+ "direction"
306
+ ],
307
+ properties: {
308
+ target_key: {
309
+ type: "string"
310
+ },
311
+ relationship_type: {
312
+ type: "string",
313
+ description: "Relationship label; defaults to related-to.",
314
+ examples: [
315
+ "related-to"
316
+ ]
317
+ },
318
+ direction: {
319
+ $ref: "#/$defs/relationship_direction"
320
+ }
321
+ },
322
+ additionalProperties: false
323
+ },
324
+ observable: {
325
+ type: "object",
326
+ required: [
327
+ "key",
328
+ "type",
329
+ "value",
330
+ "internal",
331
+ "whitelisted",
332
+ "comment",
333
+ "extra",
334
+ "score",
335
+ "level",
336
+ "relationships",
337
+ "threat_intels",
338
+ "generated_by_checks"
339
+ ],
340
+ properties: {
341
+ key: {
342
+ type: "string"
343
+ },
344
+ type: {
345
+ type: "string",
346
+ description: "Observable type (e.g., ipv4-addr, url). Custom values are allowed.",
347
+ examples: [
348
+ "ipv4-addr",
349
+ "ipv6-addr",
350
+ "domain-name",
351
+ "url",
352
+ "network-traffic",
353
+ "mac-addr",
354
+ "file",
355
+ "directory",
356
+ "email-addr",
357
+ "email-message",
358
+ "email-mime-part",
359
+ "user-account",
360
+ "process",
361
+ "software",
362
+ "windows-registry-key",
363
+ "artifact",
364
+ "autonomous-system",
365
+ "mutex",
366
+ "x509-certificate"
367
+ ]
368
+ },
369
+ value: {
370
+ type: "string"
371
+ },
372
+ internal: {
373
+ type: "boolean"
374
+ },
375
+ whitelisted: {
376
+ type: "boolean"
377
+ },
378
+ comment: {
379
+ type: "string"
380
+ },
381
+ extra: {
382
+ type: [
383
+ "object",
384
+ "null"
385
+ ],
386
+ default: {}
387
+ },
388
+ score: {
389
+ type: "number"
390
+ },
391
+ level: {
392
+ $ref: "#/$defs/level"
393
+ },
394
+ relationships: {
395
+ type: "array",
396
+ items: {
397
+ $ref: "#/$defs/relationship"
398
+ },
399
+ default: []
400
+ },
401
+ threat_intels: {
402
+ type: "array",
403
+ items: {
404
+ type: "string"
405
+ },
406
+ default: []
407
+ },
408
+ generated_by_checks: {
409
+ type: "array",
410
+ items: {
411
+ type: "string"
412
+ },
413
+ default: []
414
+ }
415
+ },
416
+ additionalProperties: false
417
+ },
418
+ check: {
419
+ type: "object",
420
+ required: [
421
+ "key",
422
+ "check_id",
423
+ "scope",
424
+ "description",
425
+ "comment",
426
+ "extra",
427
+ "score",
428
+ "level",
429
+ "score_policy",
430
+ "observables"
431
+ ],
432
+ properties: {
433
+ key: {
434
+ type: "string"
435
+ },
436
+ check_id: {
437
+ type: "string"
438
+ },
439
+ scope: {
440
+ type: "string"
441
+ },
442
+ description: {
443
+ type: "string"
444
+ },
445
+ comment: {
446
+ type: "string"
447
+ },
448
+ extra: {
449
+ type: [
450
+ "object",
451
+ "null"
452
+ ],
453
+ default: {}
454
+ },
455
+ score: {
456
+ type: "number"
457
+ },
458
+ level: {
459
+ $ref: "#/$defs/level"
460
+ },
461
+ score_policy: {
462
+ $ref: "#/$defs/score_policy"
463
+ },
464
+ observables: {
465
+ type: "array",
466
+ items: {
467
+ type: "string"
468
+ },
469
+ default: []
470
+ }
471
+ },
472
+ additionalProperties: false
473
+ },
474
+ threat_intel: {
475
+ type: "object",
476
+ required: [
477
+ "key",
478
+ "source",
479
+ "observable_key",
480
+ "comment",
481
+ "extra",
482
+ "score",
483
+ "level",
484
+ "taxonomies"
485
+ ],
486
+ properties: {
487
+ key: {
488
+ type: "string"
489
+ },
490
+ source: {
491
+ type: "string"
492
+ },
493
+ observable_key: {
494
+ type: "string"
495
+ },
496
+ comment: {
497
+ type: "string"
498
+ },
499
+ extra: {
500
+ type: [
501
+ "object",
502
+ "null"
503
+ ],
504
+ default: {}
505
+ },
506
+ score: {
507
+ type: "number"
508
+ },
509
+ level: {
510
+ $ref: "#/$defs/level"
511
+ },
512
+ taxonomies: {
513
+ type: "array",
514
+ items: {
515
+ type: "object"
516
+ },
517
+ default: []
518
+ }
519
+ },
520
+ additionalProperties: false
521
+ },
522
+ enrichment: {
523
+ type: "object",
524
+ required: [
525
+ "key",
526
+ "name",
527
+ "data",
528
+ "context"
529
+ ],
530
+ properties: {
531
+ key: {
532
+ type: "string"
533
+ },
534
+ name: {
535
+ type: "string"
536
+ },
537
+ data: {
538
+ type: "object"
539
+ },
540
+ context: {
541
+ type: "string"
542
+ }
543
+ },
544
+ additionalProperties: false
545
+ },
546
+ container: {
547
+ type: "object",
548
+ required: [
549
+ "key",
550
+ "path",
551
+ "description",
552
+ "checks",
553
+ "sub_containers",
554
+ "aggregated_score",
555
+ "aggregated_level"
556
+ ],
557
+ properties: {
558
+ key: {
559
+ type: "string"
560
+ },
561
+ path: {
562
+ type: "string"
563
+ },
564
+ description: {
565
+ type: "string"
566
+ },
567
+ checks: {
568
+ type: "array",
569
+ items: {
570
+ type: "string"
571
+ },
572
+ default: []
573
+ },
574
+ sub_containers: {
575
+ type: "object",
576
+ additionalProperties: {
577
+ $ref: "#/$defs/container"
578
+ },
579
+ default: {}
580
+ },
581
+ aggregated_score: {
582
+ type: "number"
583
+ },
584
+ aggregated_level: {
585
+ $ref: "#/$defs/level"
586
+ }
587
+ },
588
+ additionalProperties: false
589
+ },
590
+ statistics: {
591
+ type: "object",
592
+ required: [
593
+ "total_observables",
594
+ "internal_observables",
595
+ "external_observables",
596
+ "whitelisted_observables",
597
+ "observables_by_type",
598
+ "observables_by_level",
599
+ "observables_by_type_and_level",
600
+ "total_checks",
601
+ "applied_checks",
602
+ "checks_by_scope",
603
+ "checks_by_level",
604
+ "total_threat_intel",
605
+ "threat_intel_by_source",
606
+ "threat_intel_by_level",
607
+ "total_containers"
608
+ ],
609
+ properties: {
610
+ total_observables: {
611
+ type: "integer",
612
+ minimum: 0
613
+ },
614
+ internal_observables: {
615
+ type: "integer",
616
+ minimum: 0
617
+ },
618
+ external_observables: {
619
+ type: "integer",
620
+ minimum: 0
621
+ },
622
+ whitelisted_observables: {
623
+ type: "integer",
624
+ minimum: 0
625
+ },
626
+ observables_by_type: {
627
+ type: "object",
628
+ additionalProperties: {
629
+ type: "integer",
630
+ minimum: 0
631
+ },
632
+ default: {}
633
+ },
634
+ observables_by_level: {
635
+ type: "object",
636
+ additionalProperties: {
637
+ type: "integer",
638
+ minimum: 0
639
+ },
640
+ default: {}
641
+ },
642
+ observables_by_type_and_level: {
643
+ type: "object",
644
+ additionalProperties: {
645
+ type: "object",
646
+ additionalProperties: {
647
+ type: "integer",
648
+ minimum: 0
649
+ },
650
+ default: {}
651
+ },
652
+ default: {}
653
+ },
654
+ total_checks: {
655
+ type: "integer",
656
+ minimum: 0
657
+ },
658
+ applied_checks: {
659
+ type: "integer",
660
+ minimum: 0
661
+ },
662
+ checks_by_scope: {
663
+ type: "object",
664
+ additionalProperties: {
665
+ type: "integer",
666
+ minimum: 0
667
+ },
668
+ default: {}
669
+ },
670
+ checks_by_level: {
671
+ type: "object",
672
+ additionalProperties: {
673
+ type: "integer",
674
+ minimum: 0
675
+ },
676
+ default: {}
677
+ },
678
+ total_threat_intel: {
679
+ type: "integer",
680
+ minimum: 0
681
+ },
682
+ threat_intel_by_source: {
683
+ type: "object",
684
+ additionalProperties: {
685
+ type: "integer",
686
+ minimum: 0
687
+ },
688
+ default: {}
689
+ },
690
+ threat_intel_by_level: {
691
+ type: "object",
692
+ additionalProperties: {
693
+ type: "integer",
694
+ minimum: 0
695
+ },
696
+ default: {}
697
+ },
698
+ total_containers: {
699
+ type: "integer",
700
+ minimum: 0
701
+ }
702
+ },
703
+ additionalProperties: false
704
+ },
705
+ stats_checks: {
706
+ type: "object",
707
+ required: [
708
+ "checks",
709
+ "applied"
710
+ ],
711
+ properties: {
712
+ checks: {
713
+ type: "integer",
714
+ minimum: 0
715
+ },
716
+ applied: {
717
+ type: "integer",
718
+ minimum: 0
719
+ }
720
+ },
721
+ additionalProperties: false
722
+ },
723
+ data_extraction: {
724
+ type: "object",
725
+ required: [
726
+ "root_type",
727
+ "score_mode"
728
+ ],
729
+ properties: {
730
+ root_type: {
731
+ type: [
732
+ "string",
733
+ "null"
734
+ ],
735
+ description: "Root observable type used during data extraction.",
736
+ examples: [
737
+ "ipv4-addr",
738
+ "ipv6-addr",
739
+ "domain-name",
740
+ "url",
741
+ "network-traffic",
742
+ "mac-addr",
743
+ "file",
744
+ "directory",
745
+ "email-addr",
746
+ "email-message",
747
+ "email-mime-part",
748
+ "user-account",
749
+ "process",
750
+ "software",
751
+ "windows-registry-key",
752
+ "artifact",
753
+ "autonomous-system",
754
+ "mutex",
755
+ "x509-certificate"
756
+ ]
757
+ },
758
+ score_mode: {
759
+ $ref: "#/$defs/score_mode"
760
+ }
761
+ },
762
+ additionalProperties: false
763
+ }
764
+ }
765
+ };
766
+
767
+ // src/helpers.ts
768
+ var ajv = new import__.default({ allErrors: true });
769
+ (0, import_ajv_formats.default)(ajv);
770
+ var validateFn = null;
771
+ function getValidator() {
772
+ if (!validateFn) {
773
+ validateFn = ajv.compile(cyvest_schema_default);
774
+ }
775
+ return validateFn;
776
+ }
777
+ function parseCyvest(json) {
778
+ const validate = getValidator();
779
+ if (!validate(json)) {
780
+ const msg = ajv.errorsText(validate.errors || []);
781
+ throw new Error(`Invalid Cyvest payload: ${msg}`);
782
+ }
783
+ return json;
784
+ }
785
+ function isCyvest(json) {
786
+ const validate = getValidator();
787
+ return !!validate(json);
788
+ }
789
+
790
+ // src/keys.ts
791
+ function normalizeValue(value) {
792
+ return value.trim().toLowerCase();
793
+ }
794
+ function hashString(content, length = 16) {
795
+ let hash = 0;
796
+ for (let i = 0; i < content.length; i++) {
797
+ const char = content.charCodeAt(i);
798
+ hash = (hash << 5) - hash + char | 0;
799
+ }
800
+ const hex = Math.abs(hash).toString(16).padStart(8, "0");
801
+ return hex.slice(0, length);
802
+ }
803
+ function generateObservableKey(obsType, value) {
804
+ const normalizedType = normalizeValue(obsType);
805
+ const normalizedValue = normalizeValue(value);
806
+ return `obs:${normalizedType}:${normalizedValue}`;
807
+ }
808
+ function generateCheckKey(checkId, scope) {
809
+ const normalizedId = normalizeValue(checkId);
810
+ const normalizedScope = normalizeValue(scope);
811
+ return `chk:${normalizedId}:${normalizedScope}`;
812
+ }
813
+ function generateThreatIntelKey(source, observableKey) {
814
+ const normalizedSource = normalizeValue(source);
815
+ return `ti:${normalizedSource}:${observableKey}`;
816
+ }
817
+ function generateEnrichmentKey(name, context) {
818
+ const normalizedName = normalizeValue(name);
819
+ if (context) {
820
+ const contextHash = hashString(context, 8);
821
+ return `enr:${normalizedName}:${contextHash}`;
822
+ }
823
+ return `enr:${normalizedName}`;
824
+ }
825
+ function generateContainerKey(path) {
826
+ let normalizedPath = path.replace(/\\/g, "/").replace(/^\/+|\/+$/g, "");
827
+ normalizedPath = normalizeValue(normalizedPath);
828
+ return `ctr:${normalizedPath}`;
829
+ }
830
+ function parseKeyType(key) {
831
+ if (key.includes(":")) {
832
+ const prefix = key.split(":", 1)[0];
833
+ if (["obs", "chk", "ti", "enr", "ctr"].includes(prefix)) {
834
+ return prefix;
835
+ }
836
+ }
837
+ return null;
838
+ }
839
+ function validateKey(key, expectedType) {
840
+ if (!key || !key.includes(":")) {
841
+ return false;
842
+ }
843
+ const keyType = parseKeyType(key);
844
+ if (!keyType) {
845
+ return false;
846
+ }
847
+ if (expectedType && keyType !== expectedType) {
848
+ return false;
849
+ }
850
+ return true;
851
+ }
852
+ function parseObservableKey(key) {
853
+ if (!validateKey(key, "obs")) {
854
+ return null;
855
+ }
856
+ const parts = key.split(":");
857
+ if (parts.length >= 3) {
858
+ return {
859
+ type: parts[1],
860
+ value: parts.slice(2).join(":")
861
+ // Handle values with colons
862
+ };
863
+ }
864
+ return null;
865
+ }
866
+ function parseCheckKey(key) {
867
+ if (!validateKey(key, "chk")) {
868
+ return null;
869
+ }
870
+ const parts = key.split(":");
871
+ if (parts.length >= 3) {
872
+ return {
873
+ checkId: parts[1],
874
+ scope: parts.slice(2).join(":")
875
+ };
876
+ }
877
+ return null;
878
+ }
879
+ function parseThreatIntelKey(key) {
880
+ if (!validateKey(key, "ti")) {
881
+ return null;
882
+ }
883
+ const parts = key.split(":");
884
+ if (parts.length >= 3) {
885
+ return {
886
+ source: parts[1],
887
+ observableKey: parts.slice(2).join(":")
888
+ };
889
+ }
890
+ return null;
891
+ }
892
+
893
+ // src/levels.ts
894
+ var LEVEL_ORDER = [
895
+ "NONE",
896
+ "TRUSTED",
897
+ "INFO",
898
+ "SAFE",
899
+ "NOTABLE",
900
+ "SUSPICIOUS",
901
+ "MALICIOUS"
902
+ ];
903
+ var LEVEL_VALUES = {
904
+ NONE: 0,
905
+ TRUSTED: 1,
906
+ INFO: 2,
907
+ SAFE: 3,
908
+ NOTABLE: 4,
909
+ SUSPICIOUS: 5,
910
+ MALICIOUS: 6
911
+ };
912
+ var LEVEL_COLORS = {
913
+ NONE: "#808080",
914
+ // gray
915
+ TRUSTED: "#22c55e",
916
+ // green
917
+ INFO: "#06b6d4",
918
+ // cyan
919
+ SAFE: "#4ade80",
920
+ // bright green
921
+ NOTABLE: "#eab308",
922
+ // yellow
923
+ SUSPICIOUS: "#f97316",
924
+ // orange
925
+ MALICIOUS: "#ef4444"
926
+ // red
927
+ };
928
+ function normalizeLevel(level) {
929
+ const upper = level.toUpperCase();
930
+ if (LEVEL_ORDER.includes(upper)) {
931
+ return upper;
932
+ }
933
+ throw new Error(`Invalid level name: ${level}`);
934
+ }
935
+ function isValidLevel(level) {
936
+ return LEVEL_ORDER.includes(level.toUpperCase());
937
+ }
938
+ function getLevelFromScore(score) {
939
+ if (score < 0) {
940
+ return "TRUSTED";
941
+ }
942
+ if (score === 0) {
943
+ return "INFO";
944
+ }
945
+ if (score < 3) {
946
+ return "NOTABLE";
947
+ }
948
+ if (score < 5) {
949
+ return "SUSPICIOUS";
950
+ }
951
+ return "MALICIOUS";
952
+ }
953
+ function compareLevels(a, b) {
954
+ const valueA = LEVEL_VALUES[a];
955
+ const valueB = LEVEL_VALUES[b];
956
+ if (valueA < valueB) return -1;
957
+ if (valueA > valueB) return 1;
958
+ return 0;
959
+ }
960
+ function isLevelHigherThan(a, b) {
961
+ return LEVEL_VALUES[a] > LEVEL_VALUES[b];
962
+ }
963
+ function isLevelLowerThan(a, b) {
964
+ return LEVEL_VALUES[a] < LEVEL_VALUES[b];
965
+ }
966
+ function isLevelAtLeast(a, minLevel2) {
967
+ return LEVEL_VALUES[a] >= LEVEL_VALUES[minLevel2];
968
+ }
969
+ function maxLevel(levels) {
970
+ if (levels.length === 0) return "NONE";
971
+ return levels.reduce(
972
+ (max, level) => isLevelHigherThan(level, max) ? level : max
973
+ );
974
+ }
975
+ function minLevel(levels) {
976
+ if (levels.length === 0) return "MALICIOUS";
977
+ return levels.reduce(
978
+ (min, level) => isLevelLowerThan(level, min) ? level : min
979
+ );
980
+ }
981
+ function getColorForLevel(level) {
982
+ return LEVEL_COLORS[level];
983
+ }
984
+ function getColorForScore(score) {
985
+ return getColorForLevel(getLevelFromScore(score));
986
+ }
987
+ function hasLevel(obj) {
988
+ return typeof obj === "object" && obj !== null && "level" in obj && typeof obj.level === "string" && isValidLevel(obj.level);
989
+ }
990
+ function getEntityLevel(entity) {
991
+ if ("aggregated_level" in entity) {
992
+ return entity.aggregated_level;
993
+ }
994
+ return entity.level;
995
+ }
996
+
997
+ // src/getters.ts
998
+ function getObservable(inv, key) {
999
+ return inv.observables[key];
1000
+ }
1001
+ function getObservableByTypeValue(inv, type, value) {
1002
+ const normalizedType = type.trim().toLowerCase();
1003
+ const normalizedValue = value.trim().toLowerCase();
1004
+ for (const obs of Object.values(inv.observables)) {
1005
+ if (obs.type.toLowerCase() === normalizedType && obs.value.toLowerCase() === normalizedValue) {
1006
+ return obs;
1007
+ }
1008
+ }
1009
+ return void 0;
1010
+ }
1011
+ function getCheck(inv, key) {
1012
+ for (const checks of Object.values(inv.checks)) {
1013
+ for (const check of checks) {
1014
+ if (check.key === key) {
1015
+ return check;
1016
+ }
1017
+ }
1018
+ }
1019
+ return void 0;
1020
+ }
1021
+ function getCheckByIdScope(inv, checkId, scope) {
1022
+ const normalizedId = checkId.trim().toLowerCase();
1023
+ const normalizedScope = scope.trim().toLowerCase();
1024
+ const scopeChecks = inv.checks[normalizedScope] || inv.checks[scope];
1025
+ if (scopeChecks) {
1026
+ return scopeChecks.find(
1027
+ (c) => c.check_id.toLowerCase() === normalizedId
1028
+ );
1029
+ }
1030
+ for (const checks of Object.values(inv.checks)) {
1031
+ for (const check of checks) {
1032
+ if (check.check_id.toLowerCase() === normalizedId && check.scope.toLowerCase() === normalizedScope) {
1033
+ return check;
1034
+ }
1035
+ }
1036
+ }
1037
+ return void 0;
1038
+ }
1039
+ function getAllChecks(inv) {
1040
+ const result = [];
1041
+ for (const checks of Object.values(inv.checks)) {
1042
+ result.push(...checks);
1043
+ }
1044
+ return result;
1045
+ }
1046
+ function getThreatIntel(inv, key) {
1047
+ return inv.threat_intels[key];
1048
+ }
1049
+ function getThreatIntelBySourceObservable(inv, source, observableKey) {
1050
+ const normalizedSource = source.trim().toLowerCase();
1051
+ for (const ti of Object.values(inv.threat_intels)) {
1052
+ if (ti.source.toLowerCase() === normalizedSource && ti.observable_key === observableKey) {
1053
+ return ti;
1054
+ }
1055
+ }
1056
+ return void 0;
1057
+ }
1058
+ function getAllThreatIntels(inv) {
1059
+ return Object.values(inv.threat_intels);
1060
+ }
1061
+ function getEnrichment(inv, key) {
1062
+ return inv.enrichments[key];
1063
+ }
1064
+ function getEnrichmentByName(inv, name) {
1065
+ const normalizedName = name.trim().toLowerCase();
1066
+ for (const enr of Object.values(inv.enrichments)) {
1067
+ if (enr.name.toLowerCase() === normalizedName) {
1068
+ return enr;
1069
+ }
1070
+ }
1071
+ return void 0;
1072
+ }
1073
+ function getAllEnrichments(inv) {
1074
+ return Object.values(inv.enrichments);
1075
+ }
1076
+ function getContainer(inv, key) {
1077
+ if (inv.containers[key]) {
1078
+ return inv.containers[key];
1079
+ }
1080
+ function searchSubContainers(containers) {
1081
+ for (const container of Object.values(containers)) {
1082
+ if (container.key === key) {
1083
+ return container;
1084
+ }
1085
+ const found = searchSubContainers(container.sub_containers);
1086
+ if (found) return found;
1087
+ }
1088
+ return void 0;
1089
+ }
1090
+ return searchSubContainers(inv.containers);
1091
+ }
1092
+ function getContainerByPath(inv, path) {
1093
+ const normalizedPath = path.replace(/\\/g, "/").replace(/^\/+|\/+$/g, "").toLowerCase();
1094
+ function searchContainers(containers) {
1095
+ for (const container of Object.values(containers)) {
1096
+ if (container.path.toLowerCase() === normalizedPath) {
1097
+ return container;
1098
+ }
1099
+ const found = searchContainers(container.sub_containers);
1100
+ if (found) return found;
1101
+ }
1102
+ return void 0;
1103
+ }
1104
+ return searchContainers(inv.containers);
1105
+ }
1106
+ function getAllContainers(inv) {
1107
+ const result = [];
1108
+ function collectContainers(containers) {
1109
+ for (const container of Object.values(containers)) {
1110
+ result.push(container);
1111
+ collectContainers(container.sub_containers);
1112
+ }
1113
+ }
1114
+ collectContainers(inv.containers);
1115
+ return result;
1116
+ }
1117
+ function getAllObservables(inv) {
1118
+ return Object.values(inv.observables);
1119
+ }
1120
+ function getWhitelists(inv) {
1121
+ return inv.whitelists;
1122
+ }
1123
+ function getStats(inv) {
1124
+ return inv.stats;
1125
+ }
1126
+ function getStatsChecks(inv) {
1127
+ return inv.stats_checks;
1128
+ }
1129
+ function getDataExtraction(inv) {
1130
+ return inv.data_extraction;
1131
+ }
1132
+ function getCounts(inv) {
1133
+ return {
1134
+ observables: Object.keys(inv.observables).length,
1135
+ checks: getAllChecks(inv).length,
1136
+ threatIntels: Object.keys(inv.threat_intels).length,
1137
+ enrichments: Object.keys(inv.enrichments).length,
1138
+ containers: getAllContainers(inv).length,
1139
+ whitelists: inv.whitelists.length
1140
+ };
1141
+ }
1142
+
1143
+ // src/finders.ts
1144
+ function findObservablesByType(inv, type) {
1145
+ const normalizedType = type.trim().toLowerCase();
1146
+ return Object.values(inv.observables).filter(
1147
+ (obs) => obs.type.toLowerCase() === normalizedType
1148
+ );
1149
+ }
1150
+ function findObservablesByLevel(inv, level) {
1151
+ return Object.values(inv.observables).filter((obs) => obs.level === level);
1152
+ }
1153
+ function findObservablesAtLeast(inv, minLevel2) {
1154
+ return Object.values(inv.observables).filter(
1155
+ (obs) => isLevelAtLeast(obs.level, minLevel2)
1156
+ );
1157
+ }
1158
+ function findObservablesByValue(inv, value, caseSensitive = false) {
1159
+ const searchValue = caseSensitive ? value : value.toLowerCase();
1160
+ return Object.values(inv.observables).filter((obs) => {
1161
+ const obsValue = caseSensitive ? obs.value : obs.value.toLowerCase();
1162
+ return obsValue === searchValue;
1163
+ });
1164
+ }
1165
+ function findObservablesContaining(inv, substring, caseSensitive = false) {
1166
+ const searchStr = caseSensitive ? substring : substring.toLowerCase();
1167
+ return Object.values(inv.observables).filter((obs) => {
1168
+ const obsValue = caseSensitive ? obs.value : obs.value.toLowerCase();
1169
+ return obsValue.includes(searchStr);
1170
+ });
1171
+ }
1172
+ function findObservablesMatching(inv, pattern) {
1173
+ return Object.values(inv.observables).filter((obs) => pattern.test(obs.value));
1174
+ }
1175
+ function findInternalObservables(inv) {
1176
+ return Object.values(inv.observables).filter((obs) => obs.internal);
1177
+ }
1178
+ function findExternalObservables(inv) {
1179
+ return Object.values(inv.observables).filter((obs) => !obs.internal);
1180
+ }
1181
+ function findWhitelistedObservables(inv) {
1182
+ return Object.values(inv.observables).filter((obs) => obs.whitelisted);
1183
+ }
1184
+ function findObservablesWithThreatIntel(inv) {
1185
+ return Object.values(inv.observables).filter(
1186
+ (obs) => obs.threat_intels.length > 0
1187
+ );
1188
+ }
1189
+ function findChecksByScope(inv, scope) {
1190
+ const normalizedScope = scope.trim().toLowerCase();
1191
+ if (inv.checks[scope]) {
1192
+ return inv.checks[scope];
1193
+ }
1194
+ for (const [key, checks] of Object.entries(inv.checks)) {
1195
+ if (key.toLowerCase() === normalizedScope) {
1196
+ return checks;
1197
+ }
1198
+ }
1199
+ return [];
1200
+ }
1201
+ function findChecksByLevel(inv, level) {
1202
+ const result = [];
1203
+ for (const checks of Object.values(inv.checks)) {
1204
+ for (const check of checks) {
1205
+ if (check.level === level) {
1206
+ result.push(check);
1207
+ }
1208
+ }
1209
+ }
1210
+ return result;
1211
+ }
1212
+ function findChecksAtLeast(inv, minLevel2) {
1213
+ const result = [];
1214
+ for (const checks of Object.values(inv.checks)) {
1215
+ for (const check of checks) {
1216
+ if (isLevelAtLeast(check.level, minLevel2)) {
1217
+ result.push(check);
1218
+ }
1219
+ }
1220
+ }
1221
+ return result;
1222
+ }
1223
+ function findChecksByCheckId(inv, checkId) {
1224
+ const normalizedId = checkId.trim().toLowerCase();
1225
+ const result = [];
1226
+ for (const checks of Object.values(inv.checks)) {
1227
+ for (const check of checks) {
1228
+ if (check.check_id.toLowerCase() === normalizedId) {
1229
+ result.push(check);
1230
+ }
1231
+ }
1232
+ }
1233
+ return result;
1234
+ }
1235
+ function findManuallyScored(inv) {
1236
+ const result = [];
1237
+ for (const checks of Object.values(inv.checks)) {
1238
+ for (const check of checks) {
1239
+ if (check.score_policy === "manual") {
1240
+ result.push(check);
1241
+ }
1242
+ }
1243
+ }
1244
+ return result;
1245
+ }
1246
+ function findThreatIntelBySource(inv, source) {
1247
+ const normalizedSource = source.trim().toLowerCase();
1248
+ return Object.values(inv.threat_intels).filter(
1249
+ (ti) => ti.source.toLowerCase() === normalizedSource
1250
+ );
1251
+ }
1252
+ function findThreatIntelByLevel(inv, level) {
1253
+ return Object.values(inv.threat_intels).filter((ti) => ti.level === level);
1254
+ }
1255
+ function findThreatIntelAtLeast(inv, minLevel2) {
1256
+ return Object.values(inv.threat_intels).filter(
1257
+ (ti) => isLevelAtLeast(ti.level, minLevel2)
1258
+ );
1259
+ }
1260
+ function findContainersByLevel(inv, level) {
1261
+ const result = [];
1262
+ function searchContainers(containers) {
1263
+ for (const container of Object.values(containers)) {
1264
+ if (container.aggregated_level === level) {
1265
+ result.push(container);
1266
+ }
1267
+ searchContainers(container.sub_containers);
1268
+ }
1269
+ }
1270
+ searchContainers(inv.containers);
1271
+ return result;
1272
+ }
1273
+ function findContainersAtLeast(inv, minLevel2) {
1274
+ const result = [];
1275
+ function searchContainers(containers) {
1276
+ for (const container of Object.values(containers)) {
1277
+ if (isLevelAtLeast(container.aggregated_level, minLevel2)) {
1278
+ result.push(container);
1279
+ }
1280
+ searchContainers(container.sub_containers);
1281
+ }
1282
+ }
1283
+ searchContainers(inv.containers);
1284
+ return result;
1285
+ }
1286
+ function getChecksForObservable(inv, observableKey) {
1287
+ const result = [];
1288
+ for (const checks of Object.values(inv.checks)) {
1289
+ for (const check of checks) {
1290
+ if (check.observables.includes(observableKey)) {
1291
+ result.push(check);
1292
+ }
1293
+ }
1294
+ }
1295
+ return result;
1296
+ }
1297
+ function getThreatIntelsForObservable(inv, observableKey) {
1298
+ const observable = inv.observables[observableKey];
1299
+ if (observable) {
1300
+ return observable.threat_intels.map((tiKey) => inv.threat_intels[tiKey]).filter((ti) => ti !== void 0);
1301
+ }
1302
+ return Object.values(inv.threat_intels).filter(
1303
+ (ti) => ti.observable_key === observableKey
1304
+ );
1305
+ }
1306
+ function getObservablesForCheck(inv, checkKey) {
1307
+ for (const checks of Object.values(inv.checks)) {
1308
+ for (const check of checks) {
1309
+ if (check.key === checkKey) {
1310
+ return check.observables.map((obsKey) => inv.observables[obsKey]).filter((obs) => obs !== void 0);
1311
+ }
1312
+ }
1313
+ }
1314
+ return [];
1315
+ }
1316
+ function getChecksForContainer(inv, containerKey, recursive = false) {
1317
+ const result = [];
1318
+ function findContainer(containers) {
1319
+ for (const container2 of Object.values(containers)) {
1320
+ if (container2.key === containerKey) {
1321
+ return container2;
1322
+ }
1323
+ const found = findContainer(container2.sub_containers);
1324
+ if (found) return found;
1325
+ }
1326
+ return void 0;
1327
+ }
1328
+ function collectChecks(container2) {
1329
+ for (const checkKey of container2.checks) {
1330
+ for (const checks of Object.values(inv.checks)) {
1331
+ for (const check of checks) {
1332
+ if (check.key === checkKey) {
1333
+ result.push(check);
1334
+ }
1335
+ }
1336
+ }
1337
+ }
1338
+ if (recursive) {
1339
+ for (const subContainer of Object.values(container2.sub_containers)) {
1340
+ collectChecks(subContainer);
1341
+ }
1342
+ }
1343
+ }
1344
+ const container = findContainer(inv.containers);
1345
+ if (container) {
1346
+ collectChecks(container);
1347
+ }
1348
+ return result;
1349
+ }
1350
+ function sortObservablesByScore(observables) {
1351
+ return [...observables].sort((a, b) => b.score - a.score);
1352
+ }
1353
+ function sortChecksByScore(checks) {
1354
+ return [...checks].sort((a, b) => b.score - a.score);
1355
+ }
1356
+ function sortObservablesByLevel(observables) {
1357
+ return [...observables].sort(
1358
+ (a, b) => LEVEL_VALUES[b.level] - LEVEL_VALUES[a.level]
1359
+ );
1360
+ }
1361
+ function sortChecksByLevel(checks) {
1362
+ return [...checks].sort(
1363
+ (a, b) => LEVEL_VALUES[b.level] - LEVEL_VALUES[a.level]
1364
+ );
1365
+ }
1366
+ function getHighestScoringObservables(inv, n = 10) {
1367
+ return sortObservablesByScore(Object.values(inv.observables)).slice(0, n);
1368
+ }
1369
+ function getHighestScoringChecks(inv, n = 10) {
1370
+ const allChecks = [];
1371
+ for (const checks of Object.values(inv.checks)) {
1372
+ allChecks.push(...checks);
1373
+ }
1374
+ return sortChecksByScore(allChecks).slice(0, n);
1375
+ }
1376
+ function getMaliciousObservables(inv) {
1377
+ return findObservablesByLevel(inv, "MALICIOUS");
1378
+ }
1379
+ function getSuspiciousObservables(inv) {
1380
+ return findObservablesByLevel(inv, "SUSPICIOUS");
1381
+ }
1382
+ function getMaliciousChecks(inv) {
1383
+ return findChecksByLevel(inv, "MALICIOUS");
1384
+ }
1385
+ function getSuspiciousChecks(inv) {
1386
+ return findChecksByLevel(inv, "SUSPICIOUS");
1387
+ }
1388
+ function getAllScopes(inv) {
1389
+ return Object.keys(inv.checks);
1390
+ }
1391
+ function getAllObservableTypes(inv) {
1392
+ const types = /* @__PURE__ */ new Set();
1393
+ for (const obs of Object.values(inv.observables)) {
1394
+ types.add(obs.type);
1395
+ }
1396
+ return Array.from(types);
1397
+ }
1398
+ function getAllThreatIntelSources(inv) {
1399
+ const sources = /* @__PURE__ */ new Set();
1400
+ for (const ti of Object.values(inv.threat_intels)) {
1401
+ sources.add(ti.source);
1402
+ }
1403
+ return Array.from(sources);
1404
+ }
1405
+
1406
+ // src/graph.ts
1407
+ function getRelatedObservables(inv, observableKey) {
1408
+ const observable = inv.observables[observableKey];
1409
+ if (!observable) {
1410
+ return [];
1411
+ }
1412
+ const relatedKeys = /* @__PURE__ */ new Set();
1413
+ for (const rel of observable.relationships) {
1414
+ relatedKeys.add(rel.target_key);
1415
+ }
1416
+ for (const [key, obs] of Object.entries(inv.observables)) {
1417
+ if (key === observableKey) continue;
1418
+ for (const rel of obs.relationships) {
1419
+ if (rel.target_key === observableKey) {
1420
+ relatedKeys.add(key);
1421
+ break;
1422
+ }
1423
+ }
1424
+ }
1425
+ return Array.from(relatedKeys).map((key) => inv.observables[key]).filter((obs) => obs !== void 0);
1426
+ }
1427
+ function getObservableChildren(inv, observableKey) {
1428
+ const observable = inv.observables[observableKey];
1429
+ if (!observable) {
1430
+ return [];
1431
+ }
1432
+ return observable.relationships.filter((rel) => rel.direction === "outbound" || rel.direction === "bidirectional").map((rel) => inv.observables[rel.target_key]).filter((obs) => obs !== void 0);
1433
+ }
1434
+ function getObservableParents(inv, observableKey) {
1435
+ const parents = [];
1436
+ for (const [key, obs] of Object.entries(inv.observables)) {
1437
+ if (key === observableKey) continue;
1438
+ for (const rel of obs.relationships) {
1439
+ if (rel.target_key === observableKey && (rel.direction === "outbound" || rel.direction === "bidirectional")) {
1440
+ parents.push(obs);
1441
+ break;
1442
+ }
1443
+ }
1444
+ }
1445
+ return parents;
1446
+ }
1447
+ function getRelatedObservablesByType(inv, observableKey, relationshipType) {
1448
+ const observable = inv.observables[observableKey];
1449
+ if (!observable) {
1450
+ return [];
1451
+ }
1452
+ const normalizedType = relationshipType.toLowerCase();
1453
+ const relatedKeys = /* @__PURE__ */ new Set();
1454
+ for (const rel of observable.relationships) {
1455
+ if (rel.relationship_type.toLowerCase() === normalizedType) {
1456
+ relatedKeys.add(rel.target_key);
1457
+ }
1458
+ }
1459
+ for (const [key, obs] of Object.entries(inv.observables)) {
1460
+ if (key === observableKey) continue;
1461
+ for (const rel of obs.relationships) {
1462
+ if (rel.target_key === observableKey && rel.relationship_type.toLowerCase() === normalizedType) {
1463
+ relatedKeys.add(key);
1464
+ break;
1465
+ }
1466
+ }
1467
+ }
1468
+ return Array.from(relatedKeys).map((key) => inv.observables[key]).filter((obs) => obs !== void 0);
1469
+ }
1470
+ function getRelatedObservablesByDirection(inv, observableKey, direction) {
1471
+ const observable = inv.observables[observableKey];
1472
+ if (!observable) {
1473
+ return [];
1474
+ }
1475
+ const relatedKeys = /* @__PURE__ */ new Set();
1476
+ if (direction === "outbound" || direction === "bidirectional") {
1477
+ for (const rel of observable.relationships) {
1478
+ if (rel.direction === direction || rel.direction === "bidirectional") {
1479
+ relatedKeys.add(rel.target_key);
1480
+ }
1481
+ }
1482
+ }
1483
+ if (direction === "inbound" || direction === "bidirectional") {
1484
+ for (const [key, obs] of Object.entries(inv.observables)) {
1485
+ if (key === observableKey) continue;
1486
+ for (const rel of obs.relationships) {
1487
+ if (rel.target_key === observableKey && (rel.direction === "outbound" || rel.direction === "bidirectional")) {
1488
+ relatedKeys.add(key);
1489
+ break;
1490
+ }
1491
+ }
1492
+ }
1493
+ }
1494
+ return Array.from(relatedKeys).map((key) => inv.observables[key]).filter((obs) => obs !== void 0);
1495
+ }
1496
+ function getObservableGraph(inv) {
1497
+ const nodes = [];
1498
+ const edges = [];
1499
+ const seenEdges = /* @__PURE__ */ new Set();
1500
+ for (const [key, obs] of Object.entries(inv.observables)) {
1501
+ nodes.push({
1502
+ id: key,
1503
+ type: obs.type,
1504
+ value: obs.value,
1505
+ level: obs.level,
1506
+ score: obs.score,
1507
+ internal: obs.internal,
1508
+ whitelisted: obs.whitelisted
1509
+ });
1510
+ for (const rel of obs.relationships) {
1511
+ const edgeKey = rel.direction === "bidirectional" ? [key, rel.target_key].sort().join("--") : `${key}--${rel.target_key}`;
1512
+ if (!seenEdges.has(edgeKey)) {
1513
+ seenEdges.add(edgeKey);
1514
+ edges.push({
1515
+ source: key,
1516
+ target: rel.target_key,
1517
+ type: rel.relationship_type,
1518
+ direction: rel.direction
1519
+ });
1520
+ }
1521
+ }
1522
+ }
1523
+ return { nodes, edges };
1524
+ }
1525
+ function findRootObservables(inv) {
1526
+ const targetKeys = /* @__PURE__ */ new Set();
1527
+ for (const obs of Object.values(inv.observables)) {
1528
+ for (const rel of obs.relationships) {
1529
+ if (rel.direction === "outbound" || rel.direction === "bidirectional") {
1530
+ targetKeys.add(rel.target_key);
1531
+ }
1532
+ }
1533
+ }
1534
+ return Object.values(inv.observables).filter(
1535
+ (obs) => !targetKeys.has(obs.key)
1536
+ );
1537
+ }
1538
+ function findOrphanObservables(inv) {
1539
+ const connectedKeys = /* @__PURE__ */ new Set();
1540
+ for (const obs of Object.values(inv.observables)) {
1541
+ if (obs.relationships.length > 0) {
1542
+ connectedKeys.add(obs.key);
1543
+ for (const rel of obs.relationships) {
1544
+ connectedKeys.add(rel.target_key);
1545
+ }
1546
+ }
1547
+ }
1548
+ return Object.values(inv.observables).filter(
1549
+ (obs) => !connectedKeys.has(obs.key)
1550
+ );
1551
+ }
1552
+ function findLeafObservables(inv) {
1553
+ const hasOutbound = /* @__PURE__ */ new Set();
1554
+ const isTarget = /* @__PURE__ */ new Set();
1555
+ for (const obs of Object.values(inv.observables)) {
1556
+ for (const rel of obs.relationships) {
1557
+ if (rel.direction === "outbound" || rel.direction === "bidirectional") {
1558
+ hasOutbound.add(obs.key);
1559
+ isTarget.add(rel.target_key);
1560
+ }
1561
+ }
1562
+ }
1563
+ return Object.values(inv.observables).filter(
1564
+ (obs) => isTarget.has(obs.key) && !hasOutbound.has(obs.key)
1565
+ );
1566
+ }
1567
+ function areConnected(inv, sourceKey, targetKey) {
1568
+ if (sourceKey === targetKey) return true;
1569
+ const visited = /* @__PURE__ */ new Set();
1570
+ const queue = [sourceKey];
1571
+ while (queue.length > 0) {
1572
+ const current = queue.shift();
1573
+ if (visited.has(current)) continue;
1574
+ visited.add(current);
1575
+ const obs = inv.observables[current];
1576
+ if (!obs) continue;
1577
+ for (const rel of obs.relationships) {
1578
+ if (rel.target_key === targetKey) {
1579
+ return true;
1580
+ }
1581
+ if (!visited.has(rel.target_key)) {
1582
+ queue.push(rel.target_key);
1583
+ }
1584
+ }
1585
+ }
1586
+ return false;
1587
+ }
1588
+ function findPath(inv, sourceKey, targetKey) {
1589
+ if (sourceKey === targetKey) return [sourceKey];
1590
+ const visited = /* @__PURE__ */ new Set();
1591
+ const queue = [
1592
+ { key: sourceKey, path: [sourceKey] }
1593
+ ];
1594
+ while (queue.length > 0) {
1595
+ const { key: current, path } = queue.shift();
1596
+ if (visited.has(current)) continue;
1597
+ visited.add(current);
1598
+ const obs = inv.observables[current];
1599
+ if (!obs) continue;
1600
+ for (const rel of obs.relationships) {
1601
+ if (rel.target_key === targetKey) {
1602
+ return [...path, targetKey];
1603
+ }
1604
+ if (!visited.has(rel.target_key)) {
1605
+ queue.push({ key: rel.target_key, path: [...path, rel.target_key] });
1606
+ }
1607
+ }
1608
+ }
1609
+ return null;
1610
+ }
1611
+ function getReachableObservables(inv, startKey, maxDepth = Infinity) {
1612
+ const visited = /* @__PURE__ */ new Set();
1613
+ const result = [];
1614
+ function traverse(key, depth) {
1615
+ if (depth > maxDepth || visited.has(key)) return;
1616
+ visited.add(key);
1617
+ const obs = inv.observables[key];
1618
+ if (!obs) return;
1619
+ result.push(obs);
1620
+ for (const rel of obs.relationships) {
1621
+ traverse(rel.target_key, depth + 1);
1622
+ }
1623
+ }
1624
+ traverse(startKey, 0);
1625
+ return result;
1626
+ }
1627
+ function getAllRelationshipTypes(inv) {
1628
+ const types = /* @__PURE__ */ new Set();
1629
+ for (const obs of Object.values(inv.observables)) {
1630
+ for (const rel of obs.relationships) {
1631
+ types.add(rel.relationship_type);
1632
+ }
1633
+ }
1634
+ return Array.from(types);
1635
+ }
1636
+ function countRelationshipsByType(inv) {
1637
+ const counts = {};
1638
+ for (const obs of Object.values(inv.observables)) {
1639
+ for (const rel of obs.relationships) {
1640
+ counts[rel.relationship_type] = (counts[rel.relationship_type] || 0) + 1;
1641
+ }
1642
+ }
1643
+ return counts;
1644
+ }
1645
+ function getRelationshipsForObservable(inv, observableKey) {
1646
+ const observable = inv.observables[observableKey];
1647
+ const outbound = observable?.relationships || [];
1648
+ const inbound = [];
1649
+ for (const [key, obs] of Object.entries(inv.observables)) {
1650
+ if (key === observableKey) continue;
1651
+ for (const rel of obs.relationships) {
1652
+ if (rel.target_key === observableKey) {
1653
+ inbound.push({ ...rel, source_key: key });
1654
+ }
1655
+ }
1656
+ }
1657
+ return {
1658
+ outbound,
1659
+ inbound,
1660
+ all: [
1661
+ ...outbound,
1662
+ ...inbound
1663
+ ]
1664
+ };
1665
+ }
1666
+ // Annotate the CommonJS export names for ESM import in node:
1667
+ 0 && (module.exports = {
1668
+ LEVEL_COLORS,
1669
+ LEVEL_ORDER,
1670
+ LEVEL_VALUES,
1671
+ areConnected,
1672
+ compareLevels,
1673
+ countRelationshipsByType,
1674
+ findChecksAtLeast,
1675
+ findChecksByCheckId,
1676
+ findChecksByLevel,
1677
+ findChecksByScope,
1678
+ findContainersAtLeast,
1679
+ findContainersByLevel,
1680
+ findExternalObservables,
1681
+ findInternalObservables,
1682
+ findLeafObservables,
1683
+ findManuallyScored,
1684
+ findObservablesAtLeast,
1685
+ findObservablesByLevel,
1686
+ findObservablesByType,
1687
+ findObservablesByValue,
1688
+ findObservablesContaining,
1689
+ findObservablesMatching,
1690
+ findObservablesWithThreatIntel,
1691
+ findOrphanObservables,
1692
+ findPath,
1693
+ findRootObservables,
1694
+ findThreatIntelAtLeast,
1695
+ findThreatIntelByLevel,
1696
+ findThreatIntelBySource,
1697
+ findWhitelistedObservables,
1698
+ generateCheckKey,
1699
+ generateContainerKey,
1700
+ generateEnrichmentKey,
1701
+ generateObservableKey,
1702
+ generateThreatIntelKey,
1703
+ getAllChecks,
1704
+ getAllContainers,
1705
+ getAllEnrichments,
1706
+ getAllObservableTypes,
1707
+ getAllObservables,
1708
+ getAllRelationshipTypes,
1709
+ getAllScopes,
1710
+ getAllThreatIntelSources,
1711
+ getAllThreatIntels,
1712
+ getCheck,
1713
+ getCheckByIdScope,
1714
+ getChecksForContainer,
1715
+ getChecksForObservable,
1716
+ getColorForLevel,
1717
+ getColorForScore,
1718
+ getContainer,
1719
+ getContainerByPath,
1720
+ getCounts,
1721
+ getDataExtraction,
1722
+ getEnrichment,
1723
+ getEnrichmentByName,
1724
+ getEntityLevel,
1725
+ getHighestScoringChecks,
1726
+ getHighestScoringObservables,
1727
+ getLevelFromScore,
1728
+ getMaliciousChecks,
1729
+ getMaliciousObservables,
1730
+ getObservable,
1731
+ getObservableByTypeValue,
1732
+ getObservableChildren,
1733
+ getObservableGraph,
1734
+ getObservableParents,
1735
+ getObservablesForCheck,
1736
+ getReachableObservables,
1737
+ getRelatedObservables,
1738
+ getRelatedObservablesByDirection,
1739
+ getRelatedObservablesByType,
1740
+ getRelationshipsForObservable,
1741
+ getStats,
1742
+ getStatsChecks,
1743
+ getSuspiciousChecks,
1744
+ getSuspiciousObservables,
1745
+ getThreatIntel,
1746
+ getThreatIntelBySourceObservable,
1747
+ getThreatIntelsForObservable,
1748
+ getWhitelists,
1749
+ hasLevel,
1750
+ isCyvest,
1751
+ isLevelAtLeast,
1752
+ isLevelHigherThan,
1753
+ isLevelLowerThan,
1754
+ isValidLevel,
1755
+ maxLevel,
1756
+ minLevel,
1757
+ normalizeLevel,
1758
+ parseCheckKey,
1759
+ parseCyvest,
1760
+ parseKeyType,
1761
+ parseObservableKey,
1762
+ parseThreatIntelKey,
1763
+ sortChecksByLevel,
1764
+ sortChecksByScore,
1765
+ sortObservablesByLevel,
1766
+ sortObservablesByScore,
1767
+ validateKey
1768
+ });