@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,47 @@
1
+ /**
2
+ * Signature generation and validation.
3
+ */
4
+ import type { ThreatInput } from './threat.js';
5
+ /**
6
+ * Options for signature generation.
7
+ */
8
+ export interface GenerateSignatureOptions {
9
+ /** Maximum payload size in bytes. Default: 1MB */
10
+ maxPayloadSize?: number;
11
+ }
12
+ /**
13
+ * Generate a content-based, collision-resistant threat signature.
14
+ *
15
+ * Format: {category}:{sha256(payload)}
16
+ *
17
+ * Uses deterministic serialization to ensure identical payloads
18
+ * produce identical signatures regardless of key order.
19
+ *
20
+ * SECURITY INVARIANTS:
21
+ * - Validates payload structure (rejects undefined, NaN, Infinity, etc.)
22
+ * - Checks size before hashing (memory exhaustion prevention)
23
+ * - Hashes UTF-8 bytes directly (split-brain prevention)
24
+ *
25
+ * @param threat - Threat input (without signature)
26
+ * @param options - Optional configuration
27
+ * @returns Signature string
28
+ * @throws TracehoundError if payload validation fails
29
+ */
30
+ export declare function generateSignature(threat: ThreatInput, options?: GenerateSignatureOptions): string;
31
+ /**
32
+ * Compare two signatures in constant time.
33
+ * MUST be used for all signature comparisons to prevent timing attacks.
34
+ *
35
+ * @param a - First signature
36
+ * @param b - Second signature
37
+ * @returns True if signatures are equal
38
+ */
39
+ export declare function compareSignatures(a: string, b: string): boolean;
40
+ /**
41
+ * Validate a signature format.
42
+ *
43
+ * @param sig - Signature to validate
44
+ * @returns True if valid format
45
+ */
46
+ export declare function validateSignature(sig: string): boolean;
47
+ //# sourceMappingURL=signature.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"signature.d.ts","sourceRoot":"","sources":["../../src/types/signature.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAK9C;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACvC,kDAAkD;IAClD,cAAc,CAAC,EAAE,MAAM,CAAA;CACxB;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,WAAW,EACnB,OAAO,GAAE,wBAA6B,GACrC,MAAM,CASR;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAE/D;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAetD"}
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Signature generation and validation.
3
+ */
4
+ import { constantTimeEqual } from '../utils/compare.js';
5
+ import { encodePayload } from '../utils/encode.js';
6
+ import { hashBuffer } from '../utils/hash.js';
7
+ /** Default max payload size for signature generation (1MB) */
8
+ const DEFAULT_MAX_PAYLOAD_SIZE = 1_000_000;
9
+ /**
10
+ * Generate a content-based, collision-resistant threat signature.
11
+ *
12
+ * Format: {category}:{sha256(payload)}
13
+ *
14
+ * Uses deterministic serialization to ensure identical payloads
15
+ * produce identical signatures regardless of key order.
16
+ *
17
+ * SECURITY INVARIANTS:
18
+ * - Validates payload structure (rejects undefined, NaN, Infinity, etc.)
19
+ * - Checks size before hashing (memory exhaustion prevention)
20
+ * - Hashes UTF-8 bytes directly (split-brain prevention)
21
+ *
22
+ * @param threat - Threat input (without signature)
23
+ * @param options - Optional configuration
24
+ * @returns Signature string
25
+ * @throws TracehoundError if payload validation fails
26
+ */
27
+ export function generateSignature(threat, options = {}) {
28
+ const maxSize = options.maxPayloadSize ?? DEFAULT_MAX_PAYLOAD_SIZE;
29
+ // CRITICAL: Use encodePayload for full validation
30
+ // This enforces: structure validation, size check, canonical encoding
31
+ const { bytes } = encodePayload(threat.scent.payload, maxSize);
32
+ const contentHash = hashBuffer(bytes);
33
+ return `${threat.category}:${contentHash}`;
34
+ }
35
+ /**
36
+ * Compare two signatures in constant time.
37
+ * MUST be used for all signature comparisons to prevent timing attacks.
38
+ *
39
+ * @param a - First signature
40
+ * @param b - Second signature
41
+ * @returns True if signatures are equal
42
+ */
43
+ export function compareSignatures(a, b) {
44
+ return constantTimeEqual(a, b);
45
+ }
46
+ /**
47
+ * Validate a signature format.
48
+ *
49
+ * @param sig - Signature to validate
50
+ * @returns True if valid format
51
+ */
52
+ export function validateSignature(sig) {
53
+ const colonIndex = sig.indexOf(':');
54
+ if (colonIndex === -1)
55
+ return false;
56
+ const category = sig.slice(0, colonIndex);
57
+ const contentHash = sig.slice(colonIndex + 1);
58
+ // Category must not be empty
59
+ if (category.length === 0)
60
+ return false;
61
+ // Hash must be 64 hex characters (SHA-256)
62
+ if (contentHash.length !== 64)
63
+ return false;
64
+ if (!/^[a-f0-9]+$/.test(contentHash))
65
+ return false;
66
+ return true;
67
+ }
68
+ //# sourceMappingURL=signature.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"signature.js","sourceRoot":"","sources":["../../src/types/signature.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;AACvD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAG7C,8DAA8D;AAC9D,MAAM,wBAAwB,GAAG,SAAS,CAAA;AAU1C;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,iBAAiB,CAC/B,MAAmB,EACnB,UAAoC,EAAE;IAEtC,MAAM,OAAO,GAAG,OAAO,CAAC,cAAc,IAAI,wBAAwB,CAAA;IAElE,kDAAkD;IAClD,sEAAsE;IACtE,MAAM,EAAE,KAAK,EAAE,GAAG,aAAa,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAA;IAE9D,MAAM,WAAW,GAAG,UAAU,CAAC,KAAK,CAAC,CAAA;IACrC,OAAO,GAAG,MAAM,CAAC,QAAQ,IAAI,WAAW,EAAE,CAAA;AAC5C,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,iBAAiB,CAAC,CAAS,EAAE,CAAS;IACpD,OAAO,iBAAiB,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;AAChC,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB,CAAC,GAAW;IAC3C,MAAM,UAAU,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;IACnC,IAAI,UAAU,KAAK,CAAC,CAAC;QAAE,OAAO,KAAK,CAAA;IAEnC,MAAM,QAAQ,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,UAAU,CAAC,CAAA;IACzC,MAAM,WAAW,GAAG,GAAG,CAAC,KAAK,CAAC,UAAU,GAAG,CAAC,CAAC,CAAA;IAE7C,6BAA6B;IAC7B,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,KAAK,CAAA;IAEvC,2CAA2C;IAC3C,IAAI,WAAW,CAAC,MAAM,KAAK,EAAE;QAAE,OAAO,KAAK,CAAA;IAC3C,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,WAAW,CAAC;QAAE,OAAO,KAAK,CAAA;IAElD,OAAO,IAAI,CAAA;AACb,CAAC"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Threat - a classified scent with signature.
3
+ */
4
+ import type { Severity } from './common.js';
5
+ import type { Scent, ThreatCategory } from './scent.js';
6
+ export type { ThreatCategory, ThreatSignal } from './scent.js';
7
+ /**
8
+ * A threat is a scent that has been classified as malicious
9
+ * and assigned a signature for deduplication.
10
+ */
11
+ export interface Threat {
12
+ /** Content-based, collision-resistant signature */
13
+ readonly signature: string;
14
+ /** Classification category */
15
+ readonly category: ThreatCategory;
16
+ /** Severity level */
17
+ readonly severity: Severity;
18
+ /** Original scent */
19
+ readonly scent: Scent;
20
+ }
21
+ /**
22
+ * Input for threat classification (before signature generation).
23
+ * Used internally by EvidenceFactory.
24
+ */
25
+ export interface ThreatInput {
26
+ /** Classification category */
27
+ readonly category: ThreatCategory;
28
+ /** Severity level */
29
+ readonly severity: Severity;
30
+ /** Original scent */
31
+ readonly scent: Scent;
32
+ }
33
+ /**
34
+ * Create ThreatInput from Scent with threat signal.
35
+ * Helper function for type conversion.
36
+ */
37
+ export declare function createThreatInput(scent: Scent): ThreatInput | null;
38
+ //# sourceMappingURL=threat.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"threat.d.ts","sourceRoot":"","sources":["../../src/types/threat.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AAC3C,OAAO,KAAK,EAAE,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAGvD,YAAY,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAE9D;;;GAGG;AACH,MAAM,WAAW,MAAM;IACrB,mDAAmD;IACnD,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,8BAA8B;IAC9B,QAAQ,CAAC,QAAQ,EAAE,cAAc,CAAA;IACjC,qBAAqB;IACrB,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAA;IAC3B,qBAAqB;IACrB,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAA;CACtB;AAED;;;GAGG;AACH,MAAM,WAAW,WAAW;IAC1B,8BAA8B;IAC9B,QAAQ,CAAC,QAAQ,EAAE,cAAc,CAAA;IACjC,qBAAqB;IACrB,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAA;IAC3B,qBAAqB;IACrB,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAA;CACtB;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,KAAK,GAAG,WAAW,GAAG,IAAI,CASlE"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Threat - a classified scent with signature.
3
+ */
4
+ /**
5
+ * Create ThreatInput from Scent with threat signal.
6
+ * Helper function for type conversion.
7
+ */
8
+ export function createThreatInput(scent) {
9
+ if (!scent.threat) {
10
+ return null;
11
+ }
12
+ return {
13
+ category: scent.threat.category,
14
+ severity: scent.threat.severity,
15
+ scent,
16
+ };
17
+ }
18
+ //# sourceMappingURL=threat.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"threat.js","sourceRoot":"","sources":["../../src/types/threat.ts"],"names":[],"mappings":"AAAA;;GAEG;AAoCH;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAAC,KAAY;IAC5C,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;QAClB,OAAO,IAAI,CAAA;IACb,CAAC;IACD,OAAO;QACL,QAAQ,EAAE,KAAK,CAAC,MAAM,CAAC,QAAQ;QAC/B,QAAQ,EAAE,KAAK,CAAC,MAAM,CAAC,QAAQ;QAC/B,KAAK;KACN,CAAA;AACH,CAAC"}
@@ -0,0 +1,225 @@
1
+ /**
2
+ * Binary Codec - gzip encoding for evidence storage.
3
+ *
4
+ * SECURITY INVARIANT:
5
+ * - `encode()` used in hot-path (Agent → EvidenceFactory)
6
+ * - `decode()` ONLY for cold storage / forensics
7
+ * - Agent / Hound Pool MUST NOT have access to decode
8
+ *
9
+ * INTEGRITY INVARIANT (Cold Storage):
10
+ * - Always call verify() BEFORE decode()
11
+ * - Decoding without verification is a DoS vector
12
+ * - Empty payloads are VALID (originalSize=0, compressedSize>0)
13
+ */
14
+ /**
15
+ * Hot-path codec interface.
16
+ * Used by Agent, EvidenceFactory, Hound Pool.
17
+ * NO decode access - security by design.
18
+ */
19
+ export interface HotPathCodec {
20
+ /**
21
+ * Encode bytes to compressed format.
22
+ * Used in hot-path for evidence creation.
23
+ */
24
+ encode(bytes: Uint8Array): Uint8Array;
25
+ }
26
+ /**
27
+ * Cold-path codec interface.
28
+ * Used ONLY for: evacuate, cold storage retrieval, forensics.
29
+ * Extends HotPathCodec with decode capability.
30
+ */
31
+ export interface ColdPathCodec extends HotPathCodec {
32
+ /**
33
+ * Decode compressed bytes back to original.
34
+ * NOT used in Agent/Hound hot-path.
35
+ */
36
+ decode(bytes: Uint8Array): Uint8Array;
37
+ }
38
+ /**
39
+ * Codec statistics.
40
+ */
41
+ export interface CodecStats {
42
+ /** Total encode operations */
43
+ encodeCount: number;
44
+ /** Total decode operations */
45
+ decodeCount: number;
46
+ /** Total bytes before encoding */
47
+ totalInputBytes: number;
48
+ /** Total bytes after encoding */
49
+ totalOutputBytes: number;
50
+ /** Average compression ratio */
51
+ compressionRatio: number;
52
+ }
53
+ /**
54
+ * Gzip codec implementation.
55
+ * Provides both hot-path and cold-path capabilities.
56
+ *
57
+ * USAGE:
58
+ * - Pass as HotPathCodec to Agent/EvidenceFactory
59
+ * - Pass as ColdPathCodec only to cold storage / forensics tools
60
+ */
61
+ export declare class GzipCodec implements ColdPathCodec {
62
+ private _encodeCount;
63
+ private _decodeCount;
64
+ private _totalInputBytes;
65
+ private _totalOutputBytes;
66
+ /**
67
+ * Encode bytes using gzip compression.
68
+ * Sync operation for hot-path performance.
69
+ */
70
+ encode(bytes: Uint8Array): Uint8Array;
71
+ /**
72
+ * Decode gzip compressed bytes.
73
+ * ONLY for cold storage retrieval / forensics.
74
+ */
75
+ decode(bytes: Uint8Array): Uint8Array;
76
+ /**
77
+ * Get codec statistics (immutable snapshot).
78
+ */
79
+ get stats(): Readonly<CodecStats>;
80
+ }
81
+ /**
82
+ * Create a hot-path codec (encode only).
83
+ * Use this for Agent / EvidenceFactory.
84
+ *
85
+ * @returns HotPathCodec with no decode access
86
+ */
87
+ export declare function createHotPathCodec(): HotPathCodec;
88
+ /**
89
+ * Create a cold-path codec (encode + decode).
90
+ * Use ONLY for cold storage / forensics.
91
+ *
92
+ * @returns ColdPathCodec with full access
93
+ */
94
+ export declare function createColdPathCodec(): ColdPathCodec;
95
+ /**
96
+ * Async hot-path codec interface.
97
+ * Non-blocking encode for background operations.
98
+ */
99
+ export interface AsyncHotPathCodec {
100
+ /** Async encode bytes to compressed format. */
101
+ encode(bytes: Uint8Array): Promise<Uint8Array>;
102
+ }
103
+ /**
104
+ * Async cold-path codec interface.
105
+ * Non-blocking encode + decode for cold storage operations.
106
+ * Extends AsyncHotPathCodec with decode capability.
107
+ */
108
+ export interface AsyncColdPathCodec extends AsyncHotPathCodec {
109
+ /** Async decode compressed bytes back to original. */
110
+ decode(bytes: Uint8Array): Promise<Uint8Array>;
111
+ }
112
+ /**
113
+ * Async gzip codec implementation.
114
+ * Uses Node.js non-blocking zlib for cold storage and background operations.
115
+ *
116
+ * USAGE:
117
+ * - Cold storage write/read (never blocks the event loop)
118
+ * - Batch evidence evacuation
119
+ * - Background forensic analysis
120
+ *
121
+ * NOT for hot-path — use GzipCodec (sync) for Agent/EvidenceFactory.
122
+ */
123
+ export declare class AsyncGzipCodec implements AsyncColdPathCodec {
124
+ private _encodeCount;
125
+ private _decodeCount;
126
+ private _totalInputBytes;
127
+ private _totalOutputBytes;
128
+ /**
129
+ * Async encode bytes using gzip compression.
130
+ * Non-blocking — yields to event loop during compression.
131
+ */
132
+ encode(bytes: Uint8Array): Promise<Uint8Array>;
133
+ /**
134
+ * Async decode gzip compressed bytes.
135
+ * Non-blocking — yields to event loop during decompression.
136
+ */
137
+ decode(bytes: Uint8Array): Promise<Uint8Array>;
138
+ /**
139
+ * Get codec statistics (immutable snapshot).
140
+ */
141
+ get stats(): Readonly<CodecStats>;
142
+ }
143
+ /**
144
+ * Create an async cold-path codec (encode + decode).
145
+ * Use for cold storage operations where blocking is unacceptable.
146
+ *
147
+ * @returns AsyncColdPathCodec with non-blocking encode/decode
148
+ */
149
+ export declare function createAsyncColdPathCodec(): AsyncColdPathCodec;
150
+ /**
151
+ * Encoded payload with compression and integrity hash.
152
+ * Used for cold storage serialization.
153
+ */
154
+ export interface EncodedPayload {
155
+ /** gzip compressed bytes */
156
+ readonly compressed: Uint8Array;
157
+ /** SHA-256 hash of compressed bytes (hex) */
158
+ readonly hash: string;
159
+ /** Original uncompressed size in bytes */
160
+ readonly originalSize: number;
161
+ /** Compressed size in bytes */
162
+ readonly compressedSize: number;
163
+ }
164
+ /**
165
+ * Codec error for integrity violations.
166
+ */
167
+ export declare class CodecError extends Error {
168
+ readonly code: 'INTEGRITY_VIOLATION' | 'DECODE_FAILED' | 'ENCODE_FAILED';
169
+ readonly cause?: unknown | undefined;
170
+ constructor(message: string, code: 'INTEGRITY_VIOLATION' | 'DECODE_FAILED' | 'ENCODE_FAILED', cause?: unknown | undefined);
171
+ }
172
+ /**
173
+ * Encode payload for cold storage with integrity hash.
174
+ *
175
+ * - Compresses with gzip
176
+ * - Computes SHA-256 of compressed bytes
177
+ * - Empty payloads are VALID (originalSize=0, compressedSize>0)
178
+ *
179
+ * @param payload - Raw bytes to encode
180
+ * @returns Encoded payload with hash
181
+ */
182
+ export declare function encodeWithIntegrity(payload: Uint8Array): EncodedPayload;
183
+ /**
184
+ * Verify integrity of encoded payload.
185
+ *
186
+ * MUST be called BEFORE decodeWithIntegrity().
187
+ * This is a cheap operation (hash only, no decompression).
188
+ *
189
+ * @param encoded - Payload to verify
190
+ * @returns true if hash matches, false if tampered
191
+ */
192
+ export declare function verify(encoded: EncodedPayload): boolean;
193
+ /**
194
+ * Decode payload from cold storage.
195
+ *
196
+ * CRITICAL: Call verify() first. Decoding untrusted data wastes CPU.
197
+ *
198
+ * @param encoded - Verified encoded payload
199
+ * @returns Original uncompressed bytes
200
+ * @throws CodecError if decompression fails (storage corruption)
201
+ */
202
+ export declare function decodeWithIntegrity(encoded: EncodedPayload): Uint8Array;
203
+ /**
204
+ * Async encode payload for cold storage with integrity hash.
205
+ * Non-blocking version of encodeWithIntegrity().
206
+ *
207
+ * Use for cold storage write operations where event loop must not stall.
208
+ *
209
+ * @param payload - Raw bytes to encode
210
+ * @returns Encoded payload with hash
211
+ * @throws CodecError if compression fails
212
+ */
213
+ export declare function encodeWithIntegrityAsync(payload: Uint8Array): Promise<EncodedPayload>;
214
+ /**
215
+ * Async decode payload from cold storage.
216
+ * Non-blocking version of decodeWithIntegrity().
217
+ *
218
+ * CRITICAL: Call verify() first. Decoding untrusted data wastes CPU.
219
+ *
220
+ * @param encoded - Verified encoded payload
221
+ * @returns Original uncompressed bytes
222
+ * @throws CodecError if decompression fails (storage corruption)
223
+ */
224
+ export declare function decodeWithIntegrityAsync(encoded: EncodedPayload): Promise<Uint8Array>;
225
+ //# sourceMappingURL=binary-codec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"binary-codec.d.ts","sourceRoot":"","sources":["../../src/utils/binary-codec.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,266 @@
1
+ /**
2
+ * Binary Codec - gzip encoding for evidence storage.
3
+ *
4
+ * SECURITY INVARIANT:
5
+ * - `encode()` used in hot-path (Agent → EvidenceFactory)
6
+ * - `decode()` ONLY for cold storage / forensics
7
+ * - Agent / Hound Pool MUST NOT have access to decode
8
+ *
9
+ * INTEGRITY INVARIANT (Cold Storage):
10
+ * - Always call verify() BEFORE decode()
11
+ * - Decoding without verification is a DoS vector
12
+ * - Empty payloads are VALID (originalSize=0, compressedSize>0)
13
+ */
14
+ import { promisify } from 'node:util';
15
+ import { gunzip, gunzipSync, gzip, gzipSync } from 'node:zlib';
16
+ import { hashBuffer } from './hash.js';
17
+ const gzipAsync = promisify(gzip);
18
+ const gunzipAsync = promisify(gunzip);
19
+ /**
20
+ * Gzip codec implementation.
21
+ * Provides both hot-path and cold-path capabilities.
22
+ *
23
+ * USAGE:
24
+ * - Pass as HotPathCodec to Agent/EvidenceFactory
25
+ * - Pass as ColdPathCodec only to cold storage / forensics tools
26
+ */
27
+ export class GzipCodec {
28
+ _encodeCount = 0;
29
+ _decodeCount = 0;
30
+ _totalInputBytes = 0;
31
+ _totalOutputBytes = 0;
32
+ /**
33
+ * Encode bytes using gzip compression.
34
+ * Sync operation for hot-path performance.
35
+ */
36
+ encode(bytes) {
37
+ this._encodeCount++;
38
+ this._totalInputBytes += bytes.length;
39
+ const compressed = gzipSync(bytes, {
40
+ level: 6, // Balanced speed/compression
41
+ });
42
+ const result = new Uint8Array(compressed);
43
+ this._totalOutputBytes += result.length;
44
+ return result;
45
+ }
46
+ /**
47
+ * Decode gzip compressed bytes.
48
+ * ONLY for cold storage retrieval / forensics.
49
+ */
50
+ decode(bytes) {
51
+ this._decodeCount++;
52
+ const decompressed = gunzipSync(bytes);
53
+ return new Uint8Array(decompressed);
54
+ }
55
+ /**
56
+ * Get codec statistics (immutable snapshot).
57
+ */
58
+ get stats() {
59
+ const ratio = this._totalInputBytes > 0 ? this._totalOutputBytes / this._totalInputBytes : 0;
60
+ return Object.freeze({
61
+ encodeCount: this._encodeCount,
62
+ decodeCount: this._decodeCount,
63
+ totalInputBytes: this._totalInputBytes,
64
+ totalOutputBytes: this._totalOutputBytes,
65
+ compressionRatio: ratio,
66
+ });
67
+ }
68
+ }
69
+ /**
70
+ * Create a hot-path codec (encode only).
71
+ * Use this for Agent / EvidenceFactory.
72
+ *
73
+ * @returns HotPathCodec with no decode access
74
+ */
75
+ export function createHotPathCodec() {
76
+ const codec = new GzipCodec();
77
+ // Return only HotPathCodec interface - no decode access
78
+ return {
79
+ encode: (bytes) => codec.encode(bytes),
80
+ };
81
+ }
82
+ /**
83
+ * Create a cold-path codec (encode + decode).
84
+ * Use ONLY for cold storage / forensics.
85
+ *
86
+ * @returns ColdPathCodec with full access
87
+ */
88
+ export function createColdPathCodec() {
89
+ return new GzipCodec();
90
+ }
91
+ /**
92
+ * Async gzip codec implementation.
93
+ * Uses Node.js non-blocking zlib for cold storage and background operations.
94
+ *
95
+ * USAGE:
96
+ * - Cold storage write/read (never blocks the event loop)
97
+ * - Batch evidence evacuation
98
+ * - Background forensic analysis
99
+ *
100
+ * NOT for hot-path — use GzipCodec (sync) for Agent/EvidenceFactory.
101
+ */
102
+ export class AsyncGzipCodec {
103
+ _encodeCount = 0;
104
+ _decodeCount = 0;
105
+ _totalInputBytes = 0;
106
+ _totalOutputBytes = 0;
107
+ /**
108
+ * Async encode bytes using gzip compression.
109
+ * Non-blocking — yields to event loop during compression.
110
+ */
111
+ async encode(bytes) {
112
+ this._encodeCount++;
113
+ this._totalInputBytes += bytes.length;
114
+ const compressed = await gzipAsync(bytes, { level: 6 });
115
+ const result = new Uint8Array(compressed);
116
+ this._totalOutputBytes += result.length;
117
+ return result;
118
+ }
119
+ /**
120
+ * Async decode gzip compressed bytes.
121
+ * Non-blocking — yields to event loop during decompression.
122
+ */
123
+ async decode(bytes) {
124
+ this._decodeCount++;
125
+ const decompressed = await gunzipAsync(bytes);
126
+ return new Uint8Array(decompressed);
127
+ }
128
+ /**
129
+ * Get codec statistics (immutable snapshot).
130
+ */
131
+ get stats() {
132
+ const ratio = this._totalInputBytes > 0 ? this._totalOutputBytes / this._totalInputBytes : 0;
133
+ return Object.freeze({
134
+ encodeCount: this._encodeCount,
135
+ decodeCount: this._decodeCount,
136
+ totalInputBytes: this._totalInputBytes,
137
+ totalOutputBytes: this._totalOutputBytes,
138
+ compressionRatio: ratio,
139
+ });
140
+ }
141
+ }
142
+ /**
143
+ * Create an async cold-path codec (encode + decode).
144
+ * Use for cold storage operations where blocking is unacceptable.
145
+ *
146
+ * @returns AsyncColdPathCodec with non-blocking encode/decode
147
+ */
148
+ export function createAsyncColdPathCodec() {
149
+ return new AsyncGzipCodec();
150
+ }
151
+ /**
152
+ * Codec error for integrity violations.
153
+ */
154
+ export class CodecError extends Error {
155
+ code;
156
+ cause;
157
+ constructor(message, code, cause) {
158
+ super(message);
159
+ this.code = code;
160
+ this.cause = cause;
161
+ this.name = 'CodecError';
162
+ }
163
+ }
164
+ /**
165
+ * Encode payload for cold storage with integrity hash.
166
+ *
167
+ * - Compresses with gzip
168
+ * - Computes SHA-256 of compressed bytes
169
+ * - Empty payloads are VALID (originalSize=0, compressedSize>0)
170
+ *
171
+ * @param payload - Raw bytes to encode
172
+ * @returns Encoded payload with hash
173
+ */
174
+ export function encodeWithIntegrity(payload) {
175
+ const compressed = gzipSync(payload, { level: 6 });
176
+ const compressedBytes = new Uint8Array(compressed);
177
+ const hash = hashBuffer(compressedBytes);
178
+ return {
179
+ compressed: compressedBytes,
180
+ hash,
181
+ originalSize: payload.length,
182
+ compressedSize: compressedBytes.length,
183
+ };
184
+ }
185
+ /**
186
+ * Verify integrity of encoded payload.
187
+ *
188
+ * MUST be called BEFORE decodeWithIntegrity().
189
+ * This is a cheap operation (hash only, no decompression).
190
+ *
191
+ * @param encoded - Payload to verify
192
+ * @returns true if hash matches, false if tampered
193
+ */
194
+ export function verify(encoded) {
195
+ const computed = hashBuffer(encoded.compressed);
196
+ return computed === encoded.hash;
197
+ }
198
+ /**
199
+ * Decode payload from cold storage.
200
+ *
201
+ * CRITICAL: Call verify() first. Decoding untrusted data wastes CPU.
202
+ *
203
+ * @param encoded - Verified encoded payload
204
+ * @returns Original uncompressed bytes
205
+ * @throws CodecError if decompression fails (storage corruption)
206
+ */
207
+ export function decodeWithIntegrity(encoded) {
208
+ try {
209
+ const decompressed = gunzipSync(encoded.compressed);
210
+ return new Uint8Array(decompressed);
211
+ }
212
+ catch (err) {
213
+ // Decompression failure = integrity violation or storage corruption
214
+ // NEVER swallow this error - propagate for Fail-Safe handling
215
+ throw new CodecError('Decompression failed - possible storage corruption', 'DECODE_FAILED', err);
216
+ }
217
+ }
218
+ // ============================================================================
219
+ // ASYNC COLD STORAGE INTEGRITY (Non-blocking encode/decode for cold storage)
220
+ // ============================================================================
221
+ /**
222
+ * Async encode payload for cold storage with integrity hash.
223
+ * Non-blocking version of encodeWithIntegrity().
224
+ *
225
+ * Use for cold storage write operations where event loop must not stall.
226
+ *
227
+ * @param payload - Raw bytes to encode
228
+ * @returns Encoded payload with hash
229
+ * @throws CodecError if compression fails
230
+ */
231
+ export async function encodeWithIntegrityAsync(payload) {
232
+ try {
233
+ const compressed = await gzipAsync(payload, { level: 6 });
234
+ const compressedBytes = new Uint8Array(compressed);
235
+ const hash = hashBuffer(compressedBytes);
236
+ return {
237
+ compressed: compressedBytes,
238
+ hash,
239
+ originalSize: payload.length,
240
+ compressedSize: compressedBytes.length,
241
+ };
242
+ }
243
+ catch (err) {
244
+ throw new CodecError('Async compression failed', 'ENCODE_FAILED', err);
245
+ }
246
+ }
247
+ /**
248
+ * Async decode payload from cold storage.
249
+ * Non-blocking version of decodeWithIntegrity().
250
+ *
251
+ * CRITICAL: Call verify() first. Decoding untrusted data wastes CPU.
252
+ *
253
+ * @param encoded - Verified encoded payload
254
+ * @returns Original uncompressed bytes
255
+ * @throws CodecError if decompression fails (storage corruption)
256
+ */
257
+ export async function decodeWithIntegrityAsync(encoded) {
258
+ try {
259
+ const decompressed = await gunzipAsync(encoded.compressed);
260
+ return new Uint8Array(decompressed);
261
+ }
262
+ catch (err) {
263
+ throw new CodecError('Async decompression failed - possible storage corruption', 'DECODE_FAILED', err);
264
+ }
265
+ }
266
+ //# sourceMappingURL=binary-codec.js.map