@tracehound/core 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (166) hide show
  1. package/README.md +125 -0
  2. package/dist/core/agent.d.ts +89 -0
  3. package/dist/core/agent.d.ts.map +1 -0
  4. package/dist/core/agent.js +141 -0
  5. package/dist/core/agent.js.map +1 -0
  6. package/dist/core/audit-chain.d.ts +39 -0
  7. package/dist/core/audit-chain.d.ts.map +1 -0
  8. package/dist/core/audit-chain.js +87 -0
  9. package/dist/core/audit-chain.js.map +1 -0
  10. package/dist/core/cold-storage.d.ts +87 -0
  11. package/dist/core/cold-storage.d.ts.map +1 -0
  12. package/dist/core/cold-storage.js +53 -0
  13. package/dist/core/cold-storage.js.map +1 -0
  14. package/dist/core/evidence-factory.d.ts +85 -0
  15. package/dist/core/evidence-factory.d.ts.map +1 -0
  16. package/dist/core/evidence-factory.js +96 -0
  17. package/dist/core/evidence-factory.js.map +1 -0
  18. package/dist/core/evidence.d.ts +48 -0
  19. package/dist/core/evidence.d.ts.map +1 -0
  20. package/dist/core/evidence.js +135 -0
  21. package/dist/core/evidence.js.map +1 -0
  22. package/dist/core/fail-safe.d.ts +149 -0
  23. package/dist/core/fail-safe.d.ts.map +1 -0
  24. package/dist/core/fail-safe.js +217 -0
  25. package/dist/core/fail-safe.js.map +1 -0
  26. package/dist/core/hound-ipc.d.ts +91 -0
  27. package/dist/core/hound-ipc.d.ts.map +1 -0
  28. package/dist/core/hound-ipc.js +196 -0
  29. package/dist/core/hound-ipc.js.map +1 -0
  30. package/dist/core/hound-pool.d.ts +157 -0
  31. package/dist/core/hound-pool.d.ts.map +1 -0
  32. package/dist/core/hound-pool.js +337 -0
  33. package/dist/core/hound-pool.js.map +1 -0
  34. package/dist/core/hound-process.d.ts +14 -0
  35. package/dist/core/hound-process.d.ts.map +1 -0
  36. package/dist/core/hound-process.js +112 -0
  37. package/dist/core/hound-process.js.map +1 -0
  38. package/dist/core/hound-worker.d.ts +14 -0
  39. package/dist/core/hound-worker.d.ts.map +1 -0
  40. package/dist/core/hound-worker.js +112 -0
  41. package/dist/core/hound-worker.js.map +1 -0
  42. package/dist/core/lane-queue.d.ts +121 -0
  43. package/dist/core/lane-queue.d.ts.map +1 -0
  44. package/dist/core/lane-queue.js +181 -0
  45. package/dist/core/lane-queue.js.map +1 -0
  46. package/dist/core/license-manager.d.ts +128 -0
  47. package/dist/core/license-manager.d.ts.map +1 -0
  48. package/dist/core/license-manager.js +219 -0
  49. package/dist/core/license-manager.js.map +1 -0
  50. package/dist/core/notification-emitter.d.ts +140 -0
  51. package/dist/core/notification-emitter.d.ts.map +1 -0
  52. package/dist/core/notification-emitter.js +197 -0
  53. package/dist/core/notification-emitter.js.map +1 -0
  54. package/dist/core/process-adapter.d.ts +146 -0
  55. package/dist/core/process-adapter.d.ts.map +1 -0
  56. package/dist/core/process-adapter.js +174 -0
  57. package/dist/core/process-adapter.js.map +1 -0
  58. package/dist/core/quarantine.d.ts +95 -0
  59. package/dist/core/quarantine.d.ts.map +1 -0
  60. package/dist/core/quarantine.js +221 -0
  61. package/dist/core/quarantine.js.map +1 -0
  62. package/dist/core/rate-limiter.d.ts +94 -0
  63. package/dist/core/rate-limiter.d.ts.map +1 -0
  64. package/dist/core/rate-limiter.js +156 -0
  65. package/dist/core/rate-limiter.js.map +1 -0
  66. package/dist/core/s3-cold-storage.d.ts +116 -0
  67. package/dist/core/s3-cold-storage.d.ts.map +1 -0
  68. package/dist/core/s3-cold-storage.js +198 -0
  69. package/dist/core/s3-cold-storage.js.map +1 -0
  70. package/dist/core/scheduler.d.ts +126 -0
  71. package/dist/core/scheduler.d.ts.map +1 -0
  72. package/dist/core/scheduler.js +138 -0
  73. package/dist/core/scheduler.js.map +1 -0
  74. package/dist/core/security-state.d.ts +170 -0
  75. package/dist/core/security-state.d.ts.map +1 -0
  76. package/dist/core/security-state.js +156 -0
  77. package/dist/core/security-state.js.map +1 -0
  78. package/dist/core/tier-capacity.d.ts +58 -0
  79. package/dist/core/tier-capacity.d.ts.map +1 -0
  80. package/dist/core/tier-capacity.js +89 -0
  81. package/dist/core/tier-capacity.js.map +1 -0
  82. package/dist/core/tracehound.d.ts +85 -0
  83. package/dist/core/tracehound.d.ts.map +1 -0
  84. package/dist/core/tracehound.js +90 -0
  85. package/dist/core/tracehound.js.map +1 -0
  86. package/dist/core/trust-boundary.d.ts +85 -0
  87. package/dist/core/trust-boundary.d.ts.map +1 -0
  88. package/dist/core/trust-boundary.js +71 -0
  89. package/dist/core/trust-boundary.js.map +1 -0
  90. package/dist/core/watcher.d.ts +153 -0
  91. package/dist/core/watcher.d.ts.map +1 -0
  92. package/dist/core/watcher.js +141 -0
  93. package/dist/core/watcher.js.map +1 -0
  94. package/dist/index.d.ts +53 -0
  95. package/dist/index.d.ts.map +1 -0
  96. package/dist/index.js +112 -0
  97. package/dist/index.js.map +1 -0
  98. package/dist/types/audit.d.ts +45 -0
  99. package/dist/types/audit.d.ts.map +1 -0
  100. package/dist/types/audit.js +5 -0
  101. package/dist/types/audit.js.map +1 -0
  102. package/dist/types/common.d.ts +12 -0
  103. package/dist/types/common.d.ts.map +1 -0
  104. package/dist/types/common.js +5 -0
  105. package/dist/types/common.js.map +1 -0
  106. package/dist/types/config.d.ts +98 -0
  107. package/dist/types/config.d.ts.map +1 -0
  108. package/dist/types/config.js +58 -0
  109. package/dist/types/config.js.map +1 -0
  110. package/dist/types/errors.d.ts +118 -0
  111. package/dist/types/errors.d.ts.map +1 -0
  112. package/dist/types/errors.js +266 -0
  113. package/dist/types/errors.js.map +1 -0
  114. package/dist/types/evidence.d.ts +102 -0
  115. package/dist/types/evidence.d.ts.map +1 -0
  116. package/dist/types/evidence.js +5 -0
  117. package/dist/types/evidence.js.map +1 -0
  118. package/dist/types/index.d.ts +18 -0
  119. package/dist/types/index.d.ts.map +1 -0
  120. package/dist/types/index.js +9 -0
  121. package/dist/types/index.js.map +1 -0
  122. package/dist/types/result.d.ts +62 -0
  123. package/dist/types/result.d.ts.map +1 -0
  124. package/dist/types/result.js +34 -0
  125. package/dist/types/result.js.map +1 -0
  126. package/dist/types/scent.d.ts +55 -0
  127. package/dist/types/scent.d.ts.map +1 -0
  128. package/dist/types/scent.js +5 -0
  129. package/dist/types/scent.js.map +1 -0
  130. package/dist/types/signature.d.ts +47 -0
  131. package/dist/types/signature.d.ts.map +1 -0
  132. package/dist/types/signature.js +68 -0
  133. package/dist/types/signature.js.map +1 -0
  134. package/dist/types/threat.d.ts +38 -0
  135. package/dist/types/threat.d.ts.map +1 -0
  136. package/dist/types/threat.js +18 -0
  137. package/dist/types/threat.js.map +1 -0
  138. package/dist/utils/binary-codec.d.ts +225 -0
  139. package/dist/utils/binary-codec.d.ts.map +1 -0
  140. package/dist/utils/binary-codec.js +266 -0
  141. package/dist/utils/binary-codec.js.map +1 -0
  142. package/dist/utils/compare.d.ts +26 -0
  143. package/dist/utils/compare.d.ts.map +1 -0
  144. package/dist/utils/compare.js +44 -0
  145. package/dist/utils/compare.js.map +1 -0
  146. package/dist/utils/encode.d.ts +39 -0
  147. package/dist/utils/encode.d.ts.map +1 -0
  148. package/dist/utils/encode.js +124 -0
  149. package/dist/utils/encode.js.map +1 -0
  150. package/dist/utils/hash.d.ts +19 -0
  151. package/dist/utils/hash.d.ts.map +1 -0
  152. package/dist/utils/hash.js +25 -0
  153. package/dist/utils/hash.js.map +1 -0
  154. package/dist/utils/id.d.ts +20 -0
  155. package/dist/utils/id.d.ts.map +1 -0
  156. package/dist/utils/id.js +47 -0
  157. package/dist/utils/id.js.map +1 -0
  158. package/dist/utils/runtime.d.ts +24 -0
  159. package/dist/utils/runtime.d.ts.map +1 -0
  160. package/dist/utils/runtime.js +68 -0
  161. package/dist/utils/runtime.js.map +1 -0
  162. package/dist/utils/serialize.d.ts +14 -0
  163. package/dist/utils/serialize.d.ts.map +1 -0
  164. package/dist/utils/serialize.js +27 -0
  165. package/dist/utils/serialize.js.map +1 -0
  166. package/package.json +54 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"process-adapter.js","sourceRoot":"","sources":["../../src/core/process-adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAA;AACxD,OAAO,EAAE,mBAAmB,EAAE,aAAa,EAAsB,MAAM,gBAAgB,CAAA;AA6CvF;;GAEG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAsC,MAAM,CAAC,MAAM,CAAC;IAClF,WAAW,EAAE,GAAG;IAChB,aAAa,EAAE,KAAK;IACpB,eAAe,EAAE,KAAK;IACtB,UAAU,EAAE,KAAK;CAClB,CAAC,CAAA;AAmDF,gFAAgF;AAChF,iBAAiB;AACjB,gFAAgF;AAEhF;;;;GAIG;AACH,MAAM,UAAU,oBAAoB;IAClC,OAAO;QACL,KAAK,CAAC,UAAkB,EAAE,WAA8C;YACtE,MAAM,iBAAiB,GAAG,EAAE,GAAG,mBAAmB,EAAE,GAAG,WAAW,EAAE,CAAA;YAEpE,sBAAsB;YACtB,MAAM,QAAQ,GAAa,EAAE,CAAA;YAE7B,yBAAyB;YACzB,IAAI,iBAAiB,CAAC,WAAW,EAAE,CAAC;gBAClC,QAAQ,CAAC,IAAI,CAAC,wBAAwB,iBAAiB,CAAC,WAAW,EAAE,CAAC,CAAA;YACxE,CAAC;YAED,iBAAiB;YACjB,QAAQ,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAA;YACtC,QAAQ,CAAC,IAAI,CAAC,yCAAyC,CAAC,CAAA;YAExD,sBAAsB;YACtB,yDAAyD;YACzD,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,GAAG,QAAQ,EAAE,UAAU,CAAC,EAAE;gBAC/D,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;gBAC/B,QAAQ,EAAE,KAAK;gBACf,WAAW,EAAE,IAAI;aAClB,CAAC,CAAA;YAEF,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC;gBACf,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAA;YAClD,CAAC;YAED,MAAM,MAAM,GAAG,mBAAmB,EAAE,CAAA;YAEpC,OAAO;gBACL,GAAG,EAAE,KAAK,CAAC,GAAG;gBACd,QAAQ,EAAE,KAAK;gBACf,OAAO,EAAE,MAAM;aAChB,CAAA;QACH,CAAC;QAED,IAAI,CAAC,MAAmB,EAAE,OAAoB;YAC5C,MAAM,OAAO,GAAG,aAAa,CAAC,OAAO,CAAC,CAAA;YACtC,MAAM,CAAC,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC,OAAO,CAAC,CAAA;QACvC,CAAC;QAED,IAAI,CAAC,MAAmB;YACtB,oCAAoC;YACpC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;QACjC,CAAC;QAED,MAAM,CAAC,MAAmB,EAAE,QAAsB;YAChD,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE;gBAC1C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAA;YACxB,CAAC,CAAC,CAAA;QACJ,CAAC;QAED,SAAS,CAAC,MAAmB,EAAE,QAAyB;YACtD,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE;gBACnD,MAAM,QAAQ,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;gBAC3C,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;oBAC/B,QAAQ,CAAC,OAAO,CAAC,CAAA;gBACnB,CAAC;YACH,CAAC,CAAC,CAAA;QACJ,CAAC;KACF,CAAA;AACH,CAAC;AAiBD;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB;IAQ/B,MAAM,SAAS,GAAG,IAAI,GAAG,EAA4B,CAAA;IACrD,IAAI,OAAO,GAAG,IAAI,CAAA;IAElB,MAAM,WAAW,GAIb;QACF,KAAK;YACH,MAAM,GAAG,GAAG,OAAO,EAAE,CAAA;YACrB,MAAM,KAAK,GAAqB;gBAC9B,GAAG;gBACH,KAAK,EAAE,IAAI;gBACX,aAAa,EAAE,EAAE;gBACjB,gBAAgB,EAAE,EAAE;gBACpB,gBAAgB,EAAE,EAAE;aACrB,CAAA;YACD,SAAS,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAA;YAEzB,OAAO;gBACL,GAAG;gBACH,QAAQ,EAAE,EAAE,GAAG,EAAkB;gBACjC,OAAO,EAAE,mBAAmB,EAAE;aAC/B,CAAA;QACH,CAAC;QAED,IAAI,CAAC,MAAmB,EAAE,OAAoB;YAC5C,MAAM,KAAK,GAAG,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;YACvC,IAAI,KAAK,EAAE,KAAK,EAAE,CAAC;gBACjB,KAAK,CAAC,gBAAgB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;YACtC,CAAC;QACH,CAAC;QAED,IAAI,CAAC,MAAmB;YACtB,MAAM,KAAK,GAAG,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;YACvC,IAAI,KAAK,EAAE,KAAK,EAAE,CAAC;gBACjB,KAAK,CAAC,KAAK,GAAG,KAAK,CAAA;gBACnB,KAAK,MAAM,EAAE,IAAI,KAAK,CAAC,aAAa,EAAE,CAAC;oBACrC,EAAE,CAAC,IAAI,EAAE,SAAS,CAAC,CAAA;gBACrB,CAAC;YACH,CAAC;QACH,CAAC;QAED,MAAM,CAAC,MAAmB,EAAE,QAAsB;YAChD,MAAM,KAAK,GAAG,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;YACvC,KAAK,EAAE,aAAa,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;QACrC,CAAC;QAED,SAAS,CAAC,MAAmB,EAAE,QAAyB;YACtD,MAAM,KAAK,GAAG,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;YACvC,KAAK,EAAE,gBAAgB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;QACxC,CAAC;QAED,gBAAgB;YACd,OAAO,SAAS,CAAA;QAClB,CAAC;QAED,YAAY,CAAC,GAAW,EAAE,IAAmB;YAC3C,MAAM,KAAK,GAAG,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;YAChC,IAAI,KAAK,EAAE,KAAK,EAAE,CAAC;gBACjB,KAAK,CAAC,KAAK,GAAG,KAAK,CAAA;gBACnB,KAAK,MAAM,EAAE,IAAI,KAAK,CAAC,aAAa,EAAE,CAAC;oBACrC,EAAE,CAAC,IAAI,EAAE,IAAI,CAAC,CAAA;gBAChB,CAAC;YACH,CAAC;QACH,CAAC;QAED,eAAe,CAAC,GAAW,EAAE,OAAoB;YAC/C,MAAM,KAAK,GAAG,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;YAChC,IAAI,KAAK,EAAE,KAAK,EAAE,CAAC;gBACjB,KAAK,MAAM,EAAE,IAAI,KAAK,CAAC,gBAAgB,EAAE,CAAC;oBACxC,EAAE,CAAC,OAAO,CAAC,CAAA;gBACb,CAAC;YACH,CAAC;QACH,CAAC;KACF,CAAA;IAED,OAAO,WAAW,CAAA;AACpB,CAAC"}
@@ -0,0 +1,95 @@
1
+ /**
2
+ * Quarantine - priority-based evidence storage with eviction.
3
+ */
4
+ import type { Severity } from '../types/common.js';
5
+ import type { QuarantineConfig } from '../types/config.js';
6
+ import type { EvidenceHandle, NeutralizationRecord, PurgeRecord } from '../types/evidence.js';
7
+ import type { AuditChain } from './audit-chain.js';
8
+ /** Result of insert operation */
9
+ export interface InsertResult {
10
+ status: 'inserted' | 'duplicate';
11
+ existing?: EvidenceHandle;
12
+ }
13
+ /** Quarantine statistics */
14
+ export interface QuarantineStats {
15
+ count: number;
16
+ bytes: number;
17
+ bySeverity: Record<Severity, number>;
18
+ }
19
+ /** Result of replace operation */
20
+ export interface ReplaceResult {
21
+ status: 'replaced' | 'inserted_only';
22
+ neutralized?: NeutralizationRecord;
23
+ inserted: boolean;
24
+ duplicate?: EvidenceHandle;
25
+ }
26
+ /**
27
+ * Quarantine storage with priority-based eviction.
28
+ * Stores evidence by signature and evicts lowest priority when limits exceeded.
29
+ */
30
+ export declare class Quarantine {
31
+ private config;
32
+ private auditChain;
33
+ private store;
34
+ private totalBytes;
35
+ constructor(config: QuarantineConfig, auditChain: AuditChain);
36
+ /**
37
+ * Insert evidence into quarantine.
38
+ * Triggers eviction if limits exceeded.
39
+ */
40
+ insert(evidence: EvidenceHandle): InsertResult;
41
+ /**
42
+ * Get evidence by signature.
43
+ */
44
+ get(signature: string): EvidenceHandle | null;
45
+ /**
46
+ * Check if signature exists in quarantine.
47
+ */
48
+ has(signature: string): boolean;
49
+ /**
50
+ * Neutralize evidence by signature.
51
+ * Removes from quarantine and appends to audit chain.
52
+ */
53
+ neutralize(signature: string): NeutralizationRecord | null;
54
+ /**
55
+ * Flush all evidence from quarantine.
56
+ * Returns all neutralization records.
57
+ */
58
+ flush(): NeutralizationRecord[];
59
+ /**
60
+ * Purge evidence by signature with explicit reason.
61
+ * Unlike neutralize, purge creates a PurgeRecord with reason metadata.
62
+ *
63
+ * @param signature - Evidence signature to purge
64
+ * @param reason - Reason for purge
65
+ * @returns PurgeRecord if found, null if not found
66
+ */
67
+ purge(signature: string, reason: 'timeout' | 'error' | 'abort' | 'panic'): PurgeRecord | null;
68
+ /**
69
+ * Replace evidence with new evidence atomically.
70
+ * Old evidence is neutralized and new evidence is inserted.
71
+ *
72
+ * @param oldSignature - Signature of evidence to replace
73
+ * @param newEvidence - New evidence to insert
74
+ * @returns Result with old neutralization record and new insert status
75
+ */
76
+ replace(oldSignature: string, newEvidence: EvidenceHandle): ReplaceResult;
77
+ /**
78
+ * Get current quarantine statistics.
79
+ */
80
+ get stats(): QuarantineStats;
81
+ /**
82
+ * Evict lowest priority evidence.
83
+ */
84
+ private evict;
85
+ /**
86
+ * Select evidence for eviction based on priority.
87
+ * Lowest severity first, then oldest.
88
+ */
89
+ private selectForEviction;
90
+ /**
91
+ * Check if quarantine exceeds configured limits.
92
+ */
93
+ private exceedsLimits;
94
+ }
95
+ //# sourceMappingURL=quarantine.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"quarantine.d.ts","sourceRoot":"","sources":["../../src/core/quarantine.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAA;AAClD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAA;AAC1D,OAAO,KAAK,EAAE,cAAc,EAAE,oBAAoB,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAA;AAC7F,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAElD,iCAAiC;AACjC,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,UAAU,GAAG,WAAW,CAAA;IAChC,QAAQ,CAAC,EAAE,cAAc,CAAA;CAC1B;AAED,4BAA4B;AAC5B,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,CAAA;IACb,UAAU,EAAE,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAA;CACrC;AAED,kCAAkC;AAClC,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,UAAU,GAAG,eAAe,CAAA;IACpC,WAAW,CAAC,EAAE,oBAAoB,CAAA;IAClC,QAAQ,EAAE,OAAO,CAAA;IACjB,SAAS,CAAC,EAAE,cAAc,CAAA;CAC3B;AAUD;;;GAGG;AACH,qBAAa,UAAU;IAKnB,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,UAAU;IALpB,OAAO,CAAC,KAAK,CAAoC;IACjD,OAAO,CAAC,UAAU,CAAI;gBAGZ,MAAM,EAAE,gBAAgB,EACxB,UAAU,EAAE,UAAU;IAGhC;;;OAGG;IACH,MAAM,CAAC,QAAQ,EAAE,cAAc,GAAG,YAAY;IAqB9C;;OAEG;IACH,GAAG,CAAC,SAAS,EAAE,MAAM,GAAG,cAAc,GAAG,IAAI;IAI7C;;OAEG;IACH,GAAG,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO;IAI/B;;;OAGG;IACH,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,oBAAoB,GAAG,IAAI;IAoB1D;;;OAGG;IACH,KAAK,IAAI,oBAAoB,EAAE;IAgB/B;;;;;;;OAOG;IACH,KAAK,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,GAAG,WAAW,GAAG,IAAI;IAqC7F;;;;;;;OAOG;IACH,OAAO,CAAC,YAAY,EAAE,MAAM,EAAE,WAAW,EAAE,cAAc,GAAG,aAAa;IAwBzE;;OAEG;IACH,IAAI,KAAK,IAAI,eAAe,CAiB3B;IAED;;OAEG;IACH,OAAO,CAAC,KAAK;IAoBb;;;OAGG;IACH,OAAO,CAAC,iBAAiB;IAgBzB;;OAEG;IACH,OAAO,CAAC,aAAa;CAGtB"}
@@ -0,0 +1,221 @@
1
+ /**
2
+ * Quarantine - priority-based evidence storage with eviction.
3
+ */
4
+ /** Severity ranking for eviction priority */
5
+ const SEVERITY_RANK = {
6
+ low: 0,
7
+ medium: 1,
8
+ high: 2,
9
+ critical: 3,
10
+ };
11
+ /**
12
+ * Quarantine storage with priority-based eviction.
13
+ * Stores evidence by signature and evicts lowest priority when limits exceeded.
14
+ */
15
+ export class Quarantine {
16
+ config;
17
+ auditChain;
18
+ store = new Map();
19
+ totalBytes = 0;
20
+ constructor(config, auditChain) {
21
+ this.config = config;
22
+ this.auditChain = auditChain;
23
+ }
24
+ /**
25
+ * Insert evidence into quarantine.
26
+ * Triggers eviction if limits exceeded.
27
+ */
28
+ insert(evidence) {
29
+ // Check duplicate
30
+ if (this.store.has(evidence.signature)) {
31
+ return {
32
+ status: 'duplicate',
33
+ existing: this.store.get(evidence.signature),
34
+ };
35
+ }
36
+ // Insert new evidence
37
+ this.store.set(evidence.signature, evidence);
38
+ this.totalBytes += evidence.size;
39
+ // Evict if limits exceeded
40
+ while (this.exceedsLimits()) {
41
+ this.evict(1);
42
+ }
43
+ return { status: 'inserted' };
44
+ }
45
+ /**
46
+ * Get evidence by signature.
47
+ */
48
+ get(signature) {
49
+ return this.store.get(signature) ?? null;
50
+ }
51
+ /**
52
+ * Check if signature exists in quarantine.
53
+ */
54
+ has(signature) {
55
+ return this.store.has(signature);
56
+ }
57
+ /**
58
+ * Neutralize evidence by signature.
59
+ * Removes from quarantine and appends to audit chain.
60
+ */
61
+ neutralize(signature) {
62
+ const evidence = this.store.get(signature);
63
+ if (!evidence) {
64
+ return null;
65
+ }
66
+ // Get size before neutralize (evidence will be disposed)
67
+ const size = evidence.size;
68
+ // Neutralize with audit chain
69
+ const record = evidence.neutralize(this.auditChain.lastHash);
70
+ this.auditChain.append(record);
71
+ // Remove from store
72
+ this.store.delete(signature);
73
+ this.totalBytes -= size;
74
+ return record;
75
+ }
76
+ /**
77
+ * Flush all evidence from quarantine.
78
+ * Returns all neutralization records.
79
+ */
80
+ flush() {
81
+ const records = [];
82
+ for (const [_signature, evidence] of this.store) {
83
+ const record = evidence.neutralize(this.auditChain.lastHash);
84
+ this.auditChain.append(record);
85
+ records.push(record);
86
+ }
87
+ // Clear store
88
+ this.store.clear();
89
+ this.totalBytes = 0;
90
+ return records;
91
+ }
92
+ /**
93
+ * Purge evidence by signature with explicit reason.
94
+ * Unlike neutralize, purge creates a PurgeRecord with reason metadata.
95
+ *
96
+ * @param signature - Evidence signature to purge
97
+ * @param reason - Reason for purge
98
+ * @returns PurgeRecord if found, null if not found
99
+ */
100
+ purge(signature, reason) {
101
+ const evidence = this.store.get(signature);
102
+ if (!evidence) {
103
+ return null;
104
+ }
105
+ const size = evidence.size;
106
+ const hash = evidence.hash;
107
+ // Create purge record before disposing
108
+ const record = {
109
+ id: `prg-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
110
+ reason,
111
+ scent: {
112
+ id: evidence.signature, // Using signature as proxy for scent ID
113
+ source: 'unknown', // Not available from evidence handle
114
+ timestamp: evidence.captured,
115
+ payloadHash: hash,
116
+ payloadSize: size,
117
+ },
118
+ purgeTimestamp: Date.now(),
119
+ };
120
+ // Dispose evidence (force cleanup without audit chain)
121
+ try {
122
+ evidence.transfer(); // Transfer ownership to force disposal
123
+ }
124
+ catch {
125
+ // Already disposed, ignore
126
+ }
127
+ // Remove from store
128
+ this.store.delete(signature);
129
+ this.totalBytes -= size;
130
+ return record;
131
+ }
132
+ /**
133
+ * Replace evidence with new evidence atomically.
134
+ * Old evidence is neutralized and new evidence is inserted.
135
+ *
136
+ * @param oldSignature - Signature of evidence to replace
137
+ * @param newEvidence - New evidence to insert
138
+ * @returns Result with old neutralization record and new insert status
139
+ */
140
+ replace(oldSignature, newEvidence) {
141
+ // First, neutralize old evidence
142
+ const neutralized = this.neutralize(oldSignature);
143
+ if (!neutralized) {
144
+ // Old evidence not found, just insert new
145
+ const insertResult = this.insert(newEvidence);
146
+ return {
147
+ status: 'inserted_only',
148
+ inserted: insertResult.status === 'inserted',
149
+ };
150
+ }
151
+ // Insert new evidence
152
+ const insertResult = this.insert(newEvidence);
153
+ return {
154
+ status: 'replaced',
155
+ neutralized,
156
+ inserted: insertResult.status === 'inserted',
157
+ ...(insertResult.status === 'duplicate' && { duplicate: insertResult.existing }),
158
+ };
159
+ }
160
+ /**
161
+ * Get current quarantine statistics.
162
+ */
163
+ get stats() {
164
+ const bySeverity = {
165
+ low: 0,
166
+ medium: 0,
167
+ high: 0,
168
+ critical: 0,
169
+ };
170
+ for (const evidence of this.store.values()) {
171
+ bySeverity[evidence.severity]++;
172
+ }
173
+ return {
174
+ count: this.store.size,
175
+ bytes: this.totalBytes,
176
+ bySeverity,
177
+ };
178
+ }
179
+ /**
180
+ * Evict lowest priority evidence.
181
+ */
182
+ evict(count) {
183
+ const victims = this.selectForEviction(count);
184
+ for (const evidence of victims) {
185
+ const size = evidence.size;
186
+ const signature = evidence.signature;
187
+ // Neutralize and append to audit chain
188
+ const record = evidence.neutralize(this.auditChain.lastHash);
189
+ this.auditChain.append(record);
190
+ // Remove from store
191
+ this.store.delete(signature);
192
+ this.totalBytes -= size;
193
+ // NOTE: Eviction is tracked via audit chain neutralization record.
194
+ // High/critical severity alerts are handled by Watcher observing quarantine stats.
195
+ }
196
+ }
197
+ /**
198
+ * Select evidence for eviction based on priority.
199
+ * Lowest severity first, then oldest.
200
+ */
201
+ selectForEviction(count) {
202
+ const all = Array.from(this.store.values());
203
+ // Sort: lowest severity first, then oldest
204
+ all.sort((a, b) => {
205
+ const severityDiff = SEVERITY_RANK[a.severity] - SEVERITY_RANK[b.severity];
206
+ if (severityDiff !== 0) {
207
+ return severityDiff;
208
+ }
209
+ // Same severity: oldest first
210
+ return a.captured - b.captured;
211
+ });
212
+ return all.slice(0, count);
213
+ }
214
+ /**
215
+ * Check if quarantine exceeds configured limits.
216
+ */
217
+ exceedsLimits() {
218
+ return this.store.size > this.config.maxCount || this.totalBytes > this.config.maxBytes;
219
+ }
220
+ }
221
+ //# sourceMappingURL=quarantine.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"quarantine.js","sourceRoot":"","sources":["../../src/core/quarantine.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,94 @@
1
+ /**
2
+ * Rate Limiter - sliding window with per-source tracking and cleanup.
3
+ *
4
+ * SECURITY: Prevents pool exhaustion DoS by early rejection.
5
+ * Memory Safety: TTL-based cleanup prevents memory leaks.
6
+ */
7
+ import type { RateLimitConfig } from '../types/config.js';
8
+ /**
9
+ * Result of a rate limit check.
10
+ */
11
+ export type RateLimitResult = {
12
+ allowed: true;
13
+ } | {
14
+ allowed: false;
15
+ /** True if source is in block penalty period */
16
+ blocked: boolean;
17
+ /** Milliseconds until source can retry */
18
+ retryAfter: number;
19
+ /** Human-readable reason */
20
+ reason: string;
21
+ };
22
+ /**
23
+ * Rate limiter interface per RFC-0000.
24
+ */
25
+ export interface IRateLimiter {
26
+ /**
27
+ * Check if source is allowed to proceed.
28
+ * @param source - Source identifier (IP, API key, etc.)
29
+ */
30
+ check(source: string): RateLimitResult;
31
+ /**
32
+ * Reset rate limit for a specific source.
33
+ * Used for manual unblocking.
34
+ * @param source - Source identifier
35
+ */
36
+ reset(source: string): void;
37
+ /**
38
+ * Clean up stale entries to prevent memory leaks.
39
+ * Should be called periodically.
40
+ * @returns Number of entries cleaned
41
+ */
42
+ cleanup(): number;
43
+ /**
44
+ * Get current statistics.
45
+ */
46
+ readonly stats: RateLimiterStats;
47
+ }
48
+ /**
49
+ * Rate limiter statistics.
50
+ */
51
+ export interface RateLimiterStats {
52
+ /** Total tracked sources */
53
+ sources: number;
54
+ /** Currently blocked sources */
55
+ blocked: number;
56
+ /** Total checks performed */
57
+ totalChecks: number;
58
+ /** Total rejections */
59
+ totalRejections: number;
60
+ }
61
+ /**
62
+ * Sliding window rate limiter implementation.
63
+ *
64
+ * Algorithm:
65
+ * 1. Maintain list of request timestamps per source
66
+ * 2. On check, remove timestamps outside window
67
+ * 3. If count >= maxRequests, reject and optionally block
68
+ * 4. Otherwise, record timestamp and allow
69
+ *
70
+ * Block State:
71
+ * - After maxRequests exceeded, source enters blockDurationMs penalty
72
+ * - During block, all requests rejected with blocked: true
73
+ * - After block expires, source can accumulate requests again
74
+ */
75
+ export declare class RateLimiter implements IRateLimiter {
76
+ private readonly sources;
77
+ private readonly config;
78
+ private totalChecks;
79
+ private totalRejections;
80
+ constructor(config: RateLimitConfig);
81
+ check(source: string): RateLimitResult;
82
+ reset(source: string): void;
83
+ cleanup(): number;
84
+ get stats(): RateLimiterStats;
85
+ }
86
+ /**
87
+ * Create a rate limiter instance.
88
+ * Factory function for end users.
89
+ *
90
+ * @param config - Rate limit configuration
91
+ * @returns Rate limiter instance
92
+ */
93
+ export declare function createRateLimiter(config: RateLimitConfig): IRateLimiter;
94
+ //# sourceMappingURL=rate-limiter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rate-limiter.d.ts","sourceRoot":"","sources":["../../src/core/rate-limiter.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAA;AAEzD;;GAEG;AACH,MAAM,MAAM,eAAe,GACvB;IAAE,OAAO,EAAE,IAAI,CAAA;CAAE,GACjB;IACE,OAAO,EAAE,KAAK,CAAA;IACd,gDAAgD;IAChD,OAAO,EAAE,OAAO,CAAA;IAChB,0CAA0C;IAC1C,UAAU,EAAE,MAAM,CAAA;IAClB,4BAA4B;IAC5B,MAAM,EAAE,MAAM,CAAA;CACf,CAAA;AAcL;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B;;;OAGG;IACH,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,eAAe,CAAA;IAEtC;;;;OAIG;IACH,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;IAE3B;;;;OAIG;IACH,OAAO,IAAI,MAAM,CAAA;IAEjB;;OAEG;IACH,QAAQ,CAAC,KAAK,EAAE,gBAAgB,CAAA;CACjC;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,4BAA4B;IAC5B,OAAO,EAAE,MAAM,CAAA;IACf,gCAAgC;IAChC,OAAO,EAAE,MAAM,CAAA;IACf,6BAA6B;IAC7B,WAAW,EAAE,MAAM,CAAA;IACnB,uBAAuB;IACvB,eAAe,EAAE,MAAM,CAAA;CACxB;AAED;;;;;;;;;;;;;GAaG;AACH,qBAAa,WAAY,YAAW,YAAY;IAC9C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAiC;IACzD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA2B;IAClD,OAAO,CAAC,WAAW,CAAI;IACvB,OAAO,CAAC,eAAe,CAAI;gBAEf,MAAM,EAAE,eAAe;IAmBnC,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,eAAe;IA4EtC,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAI3B,OAAO,IAAI,MAAM;IAsBjB,IAAI,KAAK,IAAI,gBAAgB,CAgB5B;CACF;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,eAAe,GAAG,YAAY,CAEvE"}
@@ -0,0 +1,156 @@
1
+ /**
2
+ * Rate Limiter - sliding window with per-source tracking and cleanup.
3
+ *
4
+ * SECURITY: Prevents pool exhaustion DoS by early rejection.
5
+ * Memory Safety: TTL-based cleanup prevents memory leaks.
6
+ */
7
+ /**
8
+ * Sliding window rate limiter implementation.
9
+ *
10
+ * Algorithm:
11
+ * 1. Maintain list of request timestamps per source
12
+ * 2. On check, remove timestamps outside window
13
+ * 3. If count >= maxRequests, reject and optionally block
14
+ * 4. Otherwise, record timestamp and allow
15
+ *
16
+ * Block State:
17
+ * - After maxRequests exceeded, source enters blockDurationMs penalty
18
+ * - During block, all requests rejected with blocked: true
19
+ * - After block expires, source can accumulate requests again
20
+ */
21
+ export class RateLimiter {
22
+ sources = new Map();
23
+ config;
24
+ totalChecks = 0;
25
+ totalRejections = 0;
26
+ constructor(config) {
27
+ // Validate config
28
+ if (config.windowMs <= 0) {
29
+ throw new Error('windowMs must be positive');
30
+ }
31
+ if (config.maxRequests <= 0) {
32
+ throw new Error('maxRequests must be positive');
33
+ }
34
+ if (config.blockDurationMs < 0) {
35
+ throw new Error('blockDurationMs cannot be negative');
36
+ }
37
+ this.config = {
38
+ windowMs: config.windowMs,
39
+ maxRequests: config.maxRequests,
40
+ blockDurationMs: config.blockDurationMs,
41
+ };
42
+ }
43
+ check(source) {
44
+ this.totalChecks++;
45
+ const now = Date.now();
46
+ // Get or create source entry
47
+ let entry = this.sources.get(source);
48
+ if (!entry) {
49
+ entry = {
50
+ timestamps: [],
51
+ blockedUntil: null,
52
+ lastActivity: now,
53
+ };
54
+ this.sources.set(source, entry);
55
+ }
56
+ // Update last activity
57
+ entry.lastActivity = now;
58
+ // Check if currently blocked
59
+ if (entry.blockedUntil !== null) {
60
+ if (now < entry.blockedUntil) {
61
+ // Still blocked
62
+ this.totalRejections++;
63
+ return {
64
+ allowed: false,
65
+ blocked: true,
66
+ retryAfter: entry.blockedUntil - now,
67
+ reason: 'Source is blocked due to rate limit violation',
68
+ };
69
+ }
70
+ else {
71
+ // Block expired, clear it
72
+ entry.blockedUntil = null;
73
+ entry.timestamps = [];
74
+ }
75
+ }
76
+ // Remove timestamps outside current window
77
+ const windowStart = now - this.config.windowMs;
78
+ entry.timestamps = entry.timestamps.filter((ts) => ts > windowStart);
79
+ // Check if limit exceeded
80
+ if (entry.timestamps.length >= this.config.maxRequests) {
81
+ this.totalRejections++;
82
+ // Apply block if configured
83
+ if (this.config.blockDurationMs > 0) {
84
+ entry.blockedUntil = now + this.config.blockDurationMs;
85
+ return {
86
+ allowed: false,
87
+ blocked: true,
88
+ retryAfter: this.config.blockDurationMs,
89
+ reason: 'Rate limit exceeded, source blocked',
90
+ };
91
+ }
92
+ // No block, just sliding window rejection
93
+ const oldestInWindow = entry.timestamps[0];
94
+ // Defensive check (should never happen since length >= maxRequests)
95
+ const retryAfter = oldestInWindow !== undefined
96
+ ? oldestInWindow + this.config.windowMs - now
97
+ : this.config.windowMs;
98
+ return {
99
+ allowed: false,
100
+ blocked: false,
101
+ retryAfter: Math.max(0, retryAfter),
102
+ reason: 'Rate limit exceeded within sliding window',
103
+ };
104
+ }
105
+ // Allow and record timestamp
106
+ entry.timestamps.push(now);
107
+ return { allowed: true };
108
+ }
109
+ reset(source) {
110
+ this.sources.delete(source);
111
+ }
112
+ cleanup() {
113
+ const now = Date.now();
114
+ // Stale threshold: no activity for window + block duration
115
+ const staleThreshold = now - this.config.windowMs - this.config.blockDurationMs;
116
+ let cleaned = 0;
117
+ for (const [source, entry] of this.sources) {
118
+ // Remove if:
119
+ // 1. Not blocked AND last activity older than stale threshold
120
+ // 2. OR blocked but block already expired AND stale
121
+ const isExpiredBlock = entry.blockedUntil !== null && entry.blockedUntil < now;
122
+ const isStale = entry.lastActivity < staleThreshold;
123
+ if (isStale && (entry.blockedUntil === null || isExpiredBlock)) {
124
+ this.sources.delete(source);
125
+ cleaned++;
126
+ }
127
+ }
128
+ return cleaned;
129
+ }
130
+ get stats() {
131
+ let blocked = 0;
132
+ const now = Date.now();
133
+ for (const entry of this.sources.values()) {
134
+ if (entry.blockedUntil !== null && entry.blockedUntil > now) {
135
+ blocked++;
136
+ }
137
+ }
138
+ return {
139
+ sources: this.sources.size,
140
+ blocked,
141
+ totalChecks: this.totalChecks,
142
+ totalRejections: this.totalRejections,
143
+ };
144
+ }
145
+ }
146
+ /**
147
+ * Create a rate limiter instance.
148
+ * Factory function for end users.
149
+ *
150
+ * @param config - Rate limit configuration
151
+ * @returns Rate limiter instance
152
+ */
153
+ export function createRateLimiter(config) {
154
+ return new RateLimiter(config);
155
+ }
156
+ //# sourceMappingURL=rate-limiter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rate-limiter.js","sourceRoot":"","sources":["../../src/core/rate-limiter.ts"],"names":[],"mappings":"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"}