@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,116 @@
1
+ /**
2
+ * S3-Compatible Cold Storage Adapter
3
+ *
4
+ * Implements IColdStorageAdapter for any S3-compatible object store:
5
+ * AWS S3, Cloudflare R2, Google Cloud Storage (S3-compat), MinIO, etc.
6
+ *
7
+ * DESIGN:
8
+ * - Zero AWS SDK dependency. Client is injected via S3LikeClient interface.
9
+ * - Binary envelope format: self-contained, no sidecar files needed.
10
+ * - Async encode/decode via Phase 4 Async Codec.
11
+ *
12
+ * RFC-0000 INVARIANTS:
13
+ * - write() is fire-and-forget (caller does not wait for confirmation)
14
+ * - Adapter errors are caught and returned, never thrown
15
+ * - Payload integrity is preserved via binary envelope with embedded hash
16
+ */
17
+ import type { EncodedPayload } from '../utils/binary-codec.js';
18
+ import type { ColdStorageReadResult, ColdStorageWriteResult, IColdStorageAdapter } from './cold-storage.js';
19
+ /**
20
+ * Minimal S3-compatible client interface.
21
+ *
22
+ * Users provide their own implementation using @aws-sdk/client-s3,
23
+ * Cloudflare R2 bindings, MinIO client, or any S3-compatible SDK.
24
+ *
25
+ * @example
26
+ * // AWS S3
27
+ * import { S3Client, PutObjectCommand, GetObjectCommand, DeleteObjectCommand, HeadBucketCommand } from '@aws-sdk/client-s3'
28
+ * const s3 = new S3Client({ region: 'us-east-1' })
29
+ * const client: S3LikeClient = {
30
+ * putObject: (p) => s3.send(new PutObjectCommand(p)).then(() => {}),
31
+ * getObject: (p) => s3.send(new GetObjectCommand(p)).then(r => ({
32
+ * Body: new Uint8Array(await r.Body!.transformToByteArray())
33
+ * })),
34
+ * deleteObject: (p) => s3.send(new DeleteObjectCommand(p)).then(() => {}),
35
+ * headBucket: (p) => s3.send(new HeadBucketCommand(p)).then(() => {}),
36
+ * }
37
+ */
38
+ export interface S3LikeClient {
39
+ putObject(params: {
40
+ Bucket: string;
41
+ Key: string;
42
+ Body: Uint8Array;
43
+ ContentType?: string;
44
+ }): Promise<void>;
45
+ getObject(params: {
46
+ Bucket: string;
47
+ Key: string;
48
+ }): Promise<{
49
+ Body: Uint8Array;
50
+ }>;
51
+ deleteObject(params: {
52
+ Bucket: string;
53
+ Key: string;
54
+ }): Promise<void>;
55
+ headBucket(params: {
56
+ Bucket: string;
57
+ }): Promise<void>;
58
+ }
59
+ /**
60
+ * S3 cold storage configuration.
61
+ */
62
+ export interface S3ColdStorageConfig {
63
+ /** Pre-configured S3-compatible client (injected, not owned) */
64
+ client: S3LikeClient;
65
+ /** Target bucket name */
66
+ bucket: string;
67
+ /** Key prefix for all evidence objects (e.g., 'tracehound/evidence/') */
68
+ prefix?: string;
69
+ }
70
+ declare const HEADER_SIZE = 78;
71
+ /**
72
+ * Pack EncodedPayload into a self-contained binary envelope.
73
+ * Used for storage — all metadata is embedded, no sidecar needed.
74
+ */
75
+ declare function packEnvelope(payload: EncodedPayload): Uint8Array;
76
+ /**
77
+ * Unpack binary envelope back to EncodedPayload.
78
+ * Returns null if envelope is invalid (wrong magic, version, or size mismatch).
79
+ */
80
+ declare function unpackEnvelope(data: Uint8Array): EncodedPayload | null;
81
+ /**
82
+ * S3-compatible cold storage adapter.
83
+ *
84
+ * Stores evidence as binary envelopes in any S3-compatible object store.
85
+ * Client is injected — no AWS SDK dependency in core.
86
+ *
87
+ * @example
88
+ * const adapter = new S3ColdStorage({
89
+ * client: myS3Client,
90
+ * bucket: 'tracehound-evidence',
91
+ * prefix: 'prod/evidence/',
92
+ * })
93
+ */
94
+ export declare class S3ColdStorage implements IColdStorageAdapter {
95
+ private readonly client;
96
+ private readonly bucket;
97
+ private readonly prefix;
98
+ constructor(config: S3ColdStorageConfig);
99
+ /**
100
+ * Resolve storage key for an evidence ID.
101
+ */
102
+ private key;
103
+ write(id: string, payload: EncodedPayload): Promise<ColdStorageWriteResult>;
104
+ read(id: string): Promise<ColdStorageReadResult>;
105
+ delete(id: string): Promise<boolean>;
106
+ isAvailable(): Promise<boolean>;
107
+ }
108
+ /**
109
+ * Create an S3-compatible cold storage adapter.
110
+ *
111
+ * @param config - S3 client, bucket, and optional key prefix
112
+ * @returns IColdStorageAdapter backed by S3-compatible storage
113
+ */
114
+ export declare function createS3ColdStorage(config: S3ColdStorageConfig): IColdStorageAdapter;
115
+ export { HEADER_SIZE, packEnvelope, unpackEnvelope };
116
+ //# sourceMappingURL=s3-cold-storage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"s3-cold-storage.d.ts","sourceRoot":"","sources":["../../src/core/s3-cold-storage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAA;AAC9D,OAAO,KAAK,EAAE,qBAAqB,EAAE,sBAAsB,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAA;AAM3G;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,WAAW,YAAY;IAC3B,SAAS,CAAC,MAAM,EAAE;QAChB,MAAM,EAAE,MAAM,CAAA;QACd,GAAG,EAAE,MAAM,CAAA;QACX,IAAI,EAAE,UAAU,CAAA;QAChB,WAAW,CAAC,EAAE,MAAM,CAAA;KACrB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAEjB,SAAS,CAAC,MAAM,EAAE;QAChB,MAAM,EAAE,MAAM,CAAA;QACd,GAAG,EAAE,MAAM,CAAA;KACZ,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,UAAU,CAAA;KAAE,CAAC,CAAA;IAEjC,YAAY,CAAC,MAAM,EAAE;QACnB,MAAM,EAAE,MAAM,CAAA;QACd,GAAG,EAAE,MAAM,CAAA;KACZ,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAEjB,UAAU,CAAC,MAAM,EAAE;QACjB,MAAM,EAAE,MAAM,CAAA;KACf,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;CAClB;AAMD;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,gEAAgE;IAChE,MAAM,EAAE,YAAY,CAAA;IACpB,yBAAyB;IACzB,MAAM,EAAE,MAAM,CAAA;IACd,yEAAyE;IACzE,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAoBD,QAAA,MAAM,WAAW,KAAK,CAAA;AAEtB;;;GAGG;AACH,iBAAS,YAAY,CAAC,OAAO,EAAE,cAAc,GAAG,UAAU,CAwBzD;AAED;;;GAGG;AACH,iBAAS,cAAc,CAAC,IAAI,EAAE,UAAU,GAAG,cAAc,GAAG,IAAI,CAyC/D;AAMD;;;;;;;;;;;;GAYG;AACH,qBAAa,aAAc,YAAW,mBAAmB;IACvD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAc;IACrC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAQ;IAC/B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAQ;gBAEnB,MAAM,EAAE,mBAAmB;IAMvC;;OAEG;IACH,OAAO,CAAC,GAAG;IAIL,KAAK,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,sBAAsB,CAAC;IAmB3E,IAAI,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,qBAAqB,CAAC;IAqBhD,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAepC,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;CAQtC;AAMD;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,mBAAmB,GAAG,mBAAmB,CAEpF;AAGD,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,cAAc,EAAE,CAAA"}
@@ -0,0 +1,198 @@
1
+ /**
2
+ * S3-Compatible Cold Storage Adapter
3
+ *
4
+ * Implements IColdStorageAdapter for any S3-compatible object store:
5
+ * AWS S3, Cloudflare R2, Google Cloud Storage (S3-compat), MinIO, etc.
6
+ *
7
+ * DESIGN:
8
+ * - Zero AWS SDK dependency. Client is injected via S3LikeClient interface.
9
+ * - Binary envelope format: self-contained, no sidecar files needed.
10
+ * - Async encode/decode via Phase 4 Async Codec.
11
+ *
12
+ * RFC-0000 INVARIANTS:
13
+ * - write() is fire-and-forget (caller does not wait for confirmation)
14
+ * - Adapter errors are caught and returned, never thrown
15
+ * - Payload integrity is preserved via binary envelope with embedded hash
16
+ */
17
+ // ─────────────────────────────────────────────────────────────────────────────
18
+ // Binary Envelope Format
19
+ // ─────────────────────────────────────────────────────────────────────────────
20
+ //
21
+ // Offset Size Description
22
+ // ────── ──── ────────────────────────
23
+ // 0 4 Magic: 0x54 0x48 0x43 0x53 ("THCS")
24
+ // 4 2 Version: 0x00 0x01
25
+ // 6 4 originalSize (uint32 BE)
26
+ // 10 4 compressedSize (uint32 BE)
27
+ // 14 64 SHA-256 hash (hex ASCII, 64 bytes)
28
+ // 78 N compressed gzip data
29
+ //
30
+ // Total header: 78 bytes
31
+ // ─────────────────────────────────────────────────────────────────────────────
32
+ const ENVELOPE_MAGIC = new Uint8Array([0x54, 0x48, 0x43, 0x53]); // "THCS"
33
+ const ENVELOPE_VERSION = 1;
34
+ const HEADER_SIZE = 78;
35
+ /**
36
+ * Pack EncodedPayload into a self-contained binary envelope.
37
+ * Used for storage — all metadata is embedded, no sidecar needed.
38
+ */
39
+ function packEnvelope(payload) {
40
+ const envelope = new Uint8Array(HEADER_SIZE + payload.compressedSize);
41
+ const view = new DataView(envelope.buffer);
42
+ // Magic
43
+ envelope.set(ENVELOPE_MAGIC, 0);
44
+ // Version
45
+ view.setUint16(4, ENVELOPE_VERSION, false); // big-endian
46
+ // originalSize
47
+ view.setUint32(6, payload.originalSize, false);
48
+ // compressedSize
49
+ view.setUint32(10, payload.compressedSize, false);
50
+ // Hash (64 ASCII hex chars)
51
+ const hashBytes = new TextEncoder().encode(payload.hash);
52
+ envelope.set(hashBytes, 14);
53
+ // Compressed data
54
+ envelope.set(payload.compressed, HEADER_SIZE);
55
+ return envelope;
56
+ }
57
+ /**
58
+ * Unpack binary envelope back to EncodedPayload.
59
+ * Returns null if envelope is invalid (wrong magic, version, or size mismatch).
60
+ */
61
+ function unpackEnvelope(data) {
62
+ if (data.length < HEADER_SIZE) {
63
+ return null;
64
+ }
65
+ // Verify magic
66
+ for (let i = 0; i < 4; i++) {
67
+ if (data[i] !== ENVELOPE_MAGIC[i]) {
68
+ return null;
69
+ }
70
+ }
71
+ const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
72
+ // Verify version
73
+ const version = view.getUint16(4, false);
74
+ if (version !== ENVELOPE_VERSION) {
75
+ return null;
76
+ }
77
+ const originalSize = view.getUint32(6, false);
78
+ const compressedSize = view.getUint32(10, false);
79
+ // Verify data length matches
80
+ if (data.length !== HEADER_SIZE + compressedSize) {
81
+ return null;
82
+ }
83
+ // Extract hash
84
+ const hashBytes = data.slice(14, 78);
85
+ const hash = new TextDecoder().decode(hashBytes);
86
+ // Extract compressed data
87
+ const compressed = data.slice(HEADER_SIZE, HEADER_SIZE + compressedSize);
88
+ return {
89
+ compressed,
90
+ hash,
91
+ originalSize,
92
+ compressedSize,
93
+ };
94
+ }
95
+ // ─────────────────────────────────────────────────────────────────────────────
96
+ // S3 Cold Storage Adapter
97
+ // ─────────────────────────────────────────────────────────────────────────────
98
+ /**
99
+ * S3-compatible cold storage adapter.
100
+ *
101
+ * Stores evidence as binary envelopes in any S3-compatible object store.
102
+ * Client is injected — no AWS SDK dependency in core.
103
+ *
104
+ * @example
105
+ * const adapter = new S3ColdStorage({
106
+ * client: myS3Client,
107
+ * bucket: 'tracehound-evidence',
108
+ * prefix: 'prod/evidence/',
109
+ * })
110
+ */
111
+ export class S3ColdStorage {
112
+ client;
113
+ bucket;
114
+ prefix;
115
+ constructor(config) {
116
+ this.client = config.client;
117
+ this.bucket = config.bucket;
118
+ this.prefix = config.prefix ?? 'tracehound/evidence/';
119
+ }
120
+ /**
121
+ * Resolve storage key for an evidence ID.
122
+ */
123
+ key(id) {
124
+ return `${this.prefix}${id}.thcs`;
125
+ }
126
+ async write(id, payload) {
127
+ try {
128
+ const envelope = packEnvelope(payload);
129
+ const key = this.key(id);
130
+ await this.client.putObject({
131
+ Bucket: this.bucket,
132
+ Key: key,
133
+ Body: envelope,
134
+ ContentType: 'application/octet-stream',
135
+ });
136
+ return { success: true, id: key };
137
+ }
138
+ catch (err) {
139
+ const message = err instanceof Error ? err.message : 'Unknown S3 write error';
140
+ return { success: false, error: message };
141
+ }
142
+ }
143
+ async read(id) {
144
+ try {
145
+ const key = this.key(id);
146
+ const response = await this.client.getObject({
147
+ Bucket: this.bucket,
148
+ Key: key,
149
+ });
150
+ const payload = unpackEnvelope(response.Body);
151
+ if (!payload) {
152
+ return { success: false, error: 'Invalid envelope format' };
153
+ }
154
+ return { success: true, payload };
155
+ }
156
+ catch (err) {
157
+ const message = err instanceof Error ? err.message : 'Unknown S3 read error';
158
+ return { success: false, error: message };
159
+ }
160
+ }
161
+ async delete(id) {
162
+ try {
163
+ const key = this.key(id);
164
+ await this.client.deleteObject({
165
+ Bucket: this.bucket,
166
+ Key: key,
167
+ });
168
+ return true;
169
+ }
170
+ catch {
171
+ return false;
172
+ }
173
+ }
174
+ async isAvailable() {
175
+ try {
176
+ await this.client.headBucket({ Bucket: this.bucket });
177
+ return true;
178
+ }
179
+ catch {
180
+ return false;
181
+ }
182
+ }
183
+ }
184
+ // ─────────────────────────────────────────────────────────────────────────────
185
+ // Factory + Exports
186
+ // ─────────────────────────────────────────────────────────────────────────────
187
+ /**
188
+ * Create an S3-compatible cold storage adapter.
189
+ *
190
+ * @param config - S3 client, bucket, and optional key prefix
191
+ * @returns IColdStorageAdapter backed by S3-compatible storage
192
+ */
193
+ export function createS3ColdStorage(config) {
194
+ return new S3ColdStorage(config);
195
+ }
196
+ // Re-export envelope utilities for advanced use cases (custom adapters)
197
+ export { HEADER_SIZE, packEnvelope, unpackEnvelope };
198
+ //# sourceMappingURL=s3-cold-storage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"s3-cold-storage.js","sourceRoot":"","sources":["../../src/core/s3-cold-storage.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,126 @@
1
+ /**
2
+ * Tick Scheduler - jittered task scheduling for background operations.
3
+ *
4
+ * RFC-0000 CRITICAL INVARIANTS:
5
+ * - skipIfBusy: true by default (prevents timing attacks)
6
+ * - Jitter applied to all ticks (prevents predictable patterns)
7
+ * - No blocking of hot-path
8
+ */
9
+ /**
10
+ * Scheduled task definition.
11
+ */
12
+ export interface ScheduledTask {
13
+ /** Unique task identifier */
14
+ id: string;
15
+ /** Task execution function */
16
+ execute: () => void | Promise<void>;
17
+ /** Interval between executions in ms */
18
+ intervalMs: number;
19
+ /** Priority (lower = higher priority) */
20
+ priority?: number;
21
+ }
22
+ /**
23
+ * Tick Scheduler configuration.
24
+ */
25
+ export interface TickSchedulerConfig {
26
+ /** Base tick interval in ms */
27
+ tickInterval: number;
28
+ /** Maximum jitter range in ms (added to tick interval) */
29
+ jitterMs: number;
30
+ /**
31
+ * Skip tick if system is busy.
32
+ * DEFAULT: true (RFC requirement for timing attack prevention)
33
+ */
34
+ skipIfBusy?: boolean;
35
+ }
36
+ /**
37
+ * Scheduler statistics (immutable snapshot).
38
+ */
39
+ export interface SchedulerStats {
40
+ /** Total ticks executed */
41
+ totalTicks: number;
42
+ /** Total tasks executed */
43
+ totalTasksExecuted: number;
44
+ /** Total ticks skipped (due to busy) */
45
+ skippedTicks: number;
46
+ /** Number of scheduled tasks */
47
+ scheduledTasks: number;
48
+ /** Whether scheduler is running */
49
+ running: boolean;
50
+ /** Whether system is currently busy */
51
+ busy: boolean;
52
+ }
53
+ /**
54
+ * Busy check function type.
55
+ * Returns true if system is busy.
56
+ */
57
+ export type BusyChecker = () => boolean;
58
+ /**
59
+ * Scheduler interface.
60
+ */
61
+ export interface IScheduler {
62
+ /**
63
+ * Start the scheduler.
64
+ */
65
+ start(): void;
66
+ /**
67
+ * Stop the scheduler.
68
+ */
69
+ stop(): void;
70
+ /**
71
+ * Schedule a task.
72
+ *
73
+ * @param task - Task definition
74
+ */
75
+ schedule(task: ScheduledTask): void;
76
+ /**
77
+ * Unschedule a task by ID.
78
+ *
79
+ * @param taskId - Task ID to remove
80
+ */
81
+ unschedule(taskId: string): void;
82
+ /**
83
+ * Set busy checker function.
84
+ * Used to determine if ticks should be skipped.
85
+ *
86
+ * @param checker - Function that returns true if busy
87
+ */
88
+ setBusyChecker(checker: BusyChecker): void;
89
+ /**
90
+ * Get scheduler statistics (immutable snapshot).
91
+ */
92
+ readonly stats: Readonly<SchedulerStats>;
93
+ }
94
+ /**
95
+ * Tick Scheduler implementation.
96
+ */
97
+ export declare class Scheduler implements IScheduler {
98
+ private readonly config;
99
+ private readonly tasks;
100
+ private tickTimeoutId;
101
+ private busyChecker;
102
+ private _running;
103
+ private _busy;
104
+ private _totalTicks;
105
+ private _totalTasksExecuted;
106
+ private _skippedTicks;
107
+ private readonly skipIfBusy;
108
+ constructor(config: TickSchedulerConfig);
109
+ start(): void;
110
+ stop(): void;
111
+ schedule(task: ScheduledTask): void;
112
+ unschedule(taskId: string): void;
113
+ setBusyChecker(checker: BusyChecker): void;
114
+ get stats(): Readonly<SchedulerStats>;
115
+ private scheduleTick;
116
+ private executeTick;
117
+ private getDueTasks;
118
+ private executeTask;
119
+ }
120
+ /**
121
+ * Create a Scheduler instance.
122
+ *
123
+ * @param config - Scheduler configuration
124
+ */
125
+ export declare function createScheduler(config: TickSchedulerConfig): IScheduler;
126
+ //# sourceMappingURL=scheduler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scheduler.d.ts","sourceRoot":"","sources":["../../src/core/scheduler.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,6BAA6B;IAC7B,EAAE,EAAE,MAAM,CAAA;IACV,8BAA8B;IAC9B,OAAO,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACnC,wCAAwC;IACxC,UAAU,EAAE,MAAM,CAAA;IAClB,yCAAyC;IACzC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,+BAA+B;IAC/B,YAAY,EAAE,MAAM,CAAA;IACpB,0DAA0D;IAC1D,QAAQ,EAAE,MAAM,CAAA;IAChB;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAA;CACrB;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,2BAA2B;IAC3B,UAAU,EAAE,MAAM,CAAA;IAClB,2BAA2B;IAC3B,kBAAkB,EAAE,MAAM,CAAA;IAC1B,wCAAwC;IACxC,YAAY,EAAE,MAAM,CAAA;IACpB,gCAAgC;IAChC,cAAc,EAAE,MAAM,CAAA;IACtB,mCAAmC;IACnC,OAAO,EAAE,OAAO,CAAA;IAChB,uCAAuC;IACvC,IAAI,EAAE,OAAO,CAAA;CACd;AAED;;;GAGG;AACH,MAAM,MAAM,WAAW,GAAG,MAAM,OAAO,CAAA;AAEvC;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB;;OAEG;IACH,KAAK,IAAI,IAAI,CAAA;IAEb;;OAEG;IACH,IAAI,IAAI,IAAI,CAAA;IAEZ;;;;OAIG;IACH,QAAQ,CAAC,IAAI,EAAE,aAAa,GAAG,IAAI,CAAA;IAEnC;;;;OAIG;IACH,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;IAEhC;;;;;OAKG;IACH,cAAc,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI,CAAA;IAE1C;;OAEG;IACH,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,cAAc,CAAC,CAAA;CACzC;AAcD;;GAEG;AACH,qBAAa,SAAU,YAAW,UAAU;IAe9B,OAAO,CAAC,QAAQ,CAAC,MAAM;IAdnC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAoC;IAC1D,OAAO,CAAC,aAAa,CAA6C;IAClE,OAAO,CAAC,WAAW,CAA2B;IAC9C,OAAO,CAAC,QAAQ,CAAQ;IACxB,OAAO,CAAC,KAAK,CAAQ;IAGrB,OAAO,CAAC,WAAW,CAAI;IACvB,OAAO,CAAC,mBAAmB,CAAI;IAC/B,OAAO,CAAC,aAAa,CAAI;IAGzB,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;gBAEP,MAAM,EAAE,mBAAmB;IAKxD,KAAK,IAAI,IAAI;IAMb,IAAI,IAAI,IAAI;IAUZ,QAAQ,CAAC,IAAI,EAAE,aAAa,GAAG,IAAI;IAOnC,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAIhC,cAAc,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI;IAI1C,IAAI,KAAK,IAAI,QAAQ,CAAC,cAAc,CAAC,CASpC;IAID,OAAO,CAAC,YAAY;IAYpB,OAAO,CAAC,WAAW;IA6BnB,OAAO,CAAC,WAAW;IAanB,OAAO,CAAC,WAAW;CAiBpB;AAMD;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,mBAAmB,GAAG,UAAU,CAEvE"}
@@ -0,0 +1,138 @@
1
+ /**
2
+ * Tick Scheduler - jittered task scheduling for background operations.
3
+ *
4
+ * RFC-0000 CRITICAL INVARIANTS:
5
+ * - skipIfBusy: true by default (prevents timing attacks)
6
+ * - Jitter applied to all ticks (prevents predictable patterns)
7
+ * - No blocking of hot-path
8
+ */
9
+ /**
10
+ * Tick Scheduler implementation.
11
+ */
12
+ export class Scheduler {
13
+ config;
14
+ tasks = new Map();
15
+ tickTimeoutId = null;
16
+ busyChecker = () => false;
17
+ _running = false;
18
+ _busy = false;
19
+ // Statistics
20
+ _totalTicks = 0;
21
+ _totalTasksExecuted = 0;
22
+ _skippedTicks = 0;
23
+ // Config with defaults
24
+ skipIfBusy;
25
+ constructor(config) {
26
+ this.config = config;
27
+ // skipIfBusy defaults to true (RFC requirement)
28
+ this.skipIfBusy = config.skipIfBusy ?? true;
29
+ }
30
+ start() {
31
+ if (this._running)
32
+ return;
33
+ this._running = true;
34
+ this.scheduleTick();
35
+ }
36
+ stop() {
37
+ if (!this._running)
38
+ return;
39
+ this._running = false;
40
+ if (this.tickTimeoutId) {
41
+ clearTimeout(this.tickTimeoutId);
42
+ this.tickTimeoutId = null;
43
+ }
44
+ }
45
+ schedule(task) {
46
+ this.tasks.set(task.id, {
47
+ task,
48
+ lastExecuted: 0,
49
+ });
50
+ }
51
+ unschedule(taskId) {
52
+ this.tasks.delete(taskId);
53
+ }
54
+ setBusyChecker(checker) {
55
+ this.busyChecker = checker;
56
+ }
57
+ get stats() {
58
+ return Object.freeze({
59
+ totalTicks: this._totalTicks,
60
+ totalTasksExecuted: this._totalTasksExecuted,
61
+ skippedTicks: this._skippedTicks,
62
+ scheduledTasks: this.tasks.size,
63
+ running: this._running,
64
+ busy: this._busy,
65
+ });
66
+ }
67
+ // ─── Private Methods ───────────────────────────────────────────────────────
68
+ scheduleTick() {
69
+ if (!this._running)
70
+ return;
71
+ // Apply jitter to interval
72
+ const jitter = Math.random() * this.config.jitterMs;
73
+ const delay = this.config.tickInterval + jitter;
74
+ this.tickTimeoutId = setTimeout(() => {
75
+ this.executeTick();
76
+ }, delay);
77
+ }
78
+ executeTick() {
79
+ if (!this._running)
80
+ return;
81
+ this._totalTicks++;
82
+ // Check if system is busy
83
+ this._busy = this.busyChecker();
84
+ if (this.skipIfBusy && this._busy) {
85
+ this._skippedTicks++;
86
+ this.scheduleTick();
87
+ return;
88
+ }
89
+ // Execute due tasks
90
+ const now = Date.now();
91
+ const dueTasks = this.getDueTasks(now);
92
+ // Sort by priority
93
+ dueTasks.sort((a, b) => (a.task.priority ?? 100) - (b.task.priority ?? 100));
94
+ for (const taskState of dueTasks) {
95
+ this.executeTask(taskState, now);
96
+ }
97
+ // Schedule next tick
98
+ this.scheduleTick();
99
+ }
100
+ getDueTasks(now) {
101
+ const dueTasks = [];
102
+ for (const [, taskState] of this.tasks) {
103
+ const elapsed = now - taskState.lastExecuted;
104
+ if (elapsed >= taskState.task.intervalMs) {
105
+ dueTasks.push(taskState);
106
+ }
107
+ }
108
+ return dueTasks;
109
+ }
110
+ executeTask(taskState, now) {
111
+ taskState.lastExecuted = now;
112
+ this._totalTasksExecuted++;
113
+ try {
114
+ const result = taskState.task.execute();
115
+ // Handle async tasks (fire-and-forget)
116
+ if (result instanceof Promise) {
117
+ result.catch(() => {
118
+ // Silently ignore task errors
119
+ });
120
+ }
121
+ }
122
+ catch {
123
+ // Silently ignore task errors
124
+ }
125
+ }
126
+ }
127
+ // ─────────────────────────────────────────────────────────────────────────────
128
+ // Factory
129
+ // ─────────────────────────────────────────────────────────────────────────────
130
+ /**
131
+ * Create a Scheduler instance.
132
+ *
133
+ * @param config - Scheduler configuration
134
+ */
135
+ export function createScheduler(config) {
136
+ return new Scheduler(config);
137
+ }
138
+ //# sourceMappingURL=scheduler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scheduler.js","sourceRoot":"","sources":["../../src/core/scheduler.ts"],"names":[],"mappings":"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"}