@thunderkiller/video-clipper 1.5.6 → 1.6.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 (49) hide show
  1. package/dist/config/env.d.ts +4 -0
  2. package/dist/config/env.d.ts.map +1 -1
  3. package/dist/pipeline/runner.d.ts.map +1 -1
  4. package/dist/pipeline/runner.js +79 -72
  5. package/dist/pipeline/runner.js.map +1 -1
  6. package/dist/pipeline/stages/segmentAnalyzer.d.ts +1 -1
  7. package/dist/pipeline/stages/segmentAnalyzer.d.ts.map +1 -1
  8. package/dist/pipeline/stages/segmentAnalyzer.js +2 -2
  9. package/dist/pipeline/stages/segmentAnalyzer.js.map +1 -1
  10. package/dist/services/clipRefiner/index.d.ts +2 -1
  11. package/dist/services/clipRefiner/index.d.ts.map +1 -1
  12. package/dist/services/clipRefiner/index.js +3 -5
  13. package/dist/services/clipRefiner/index.js.map +1 -1
  14. package/dist/services/llmAnalyzer/LLMAnalyzer.d.ts +2 -2
  15. package/dist/services/llmAnalyzer/LLMAnalyzer.d.ts.map +1 -1
  16. package/dist/services/llmAnalyzer/LLMAnalyzer.js +2 -2
  17. package/dist/services/llmAnalyzer/LLMAnalyzer.js.map +1 -1
  18. package/dist/services/llmAnalyzer/index.d.ts +3 -2
  19. package/dist/services/llmAnalyzer/index.d.ts.map +1 -1
  20. package/dist/services/llmAnalyzer/index.js +5 -7
  21. package/dist/services/llmAnalyzer/index.js.map +1 -1
  22. package/dist/services/transcriptDetector/index.d.ts +2 -2
  23. package/dist/services/transcriptDetector/index.d.ts.map +1 -1
  24. package/dist/services/transcriptDetector/index.js.map +1 -1
  25. package/dist/types/config.d.ts +7 -0
  26. package/dist/types/config.d.ts.map +1 -1
  27. package/dist/types/config.js +12 -0
  28. package/dist/types/config.js.map +1 -1
  29. package/dist/utils/cache.d.ts +14 -18
  30. package/dist/utils/cache.d.ts.map +1 -1
  31. package/dist/utils/cache.js +32 -112
  32. package/dist/utils/cache.js.map +1 -1
  33. package/dist/utils/cacheBackend.d.ts +40 -0
  34. package/dist/utils/cacheBackend.d.ts.map +1 -0
  35. package/dist/utils/cacheBackend.js +28 -0
  36. package/dist/utils/cacheBackend.js.map +1 -0
  37. package/dist/utils/cacheFactory.d.ts +14 -0
  38. package/dist/utils/cacheFactory.d.ts.map +1 -0
  39. package/dist/utils/cacheFactory.js +31 -0
  40. package/dist/utils/cacheFactory.js.map +1 -0
  41. package/dist/utils/fileCacheBackend.d.ts +33 -0
  42. package/dist/utils/fileCacheBackend.d.ts.map +1 -0
  43. package/dist/utils/fileCacheBackend.js +123 -0
  44. package/dist/utils/fileCacheBackend.js.map +1 -0
  45. package/dist/utils/mongoCacheBackend.d.ts +51 -0
  46. package/dist/utils/mongoCacheBackend.d.ts.map +1 -0
  47. package/dist/utils/mongoCacheBackend.js +176 -0
  48. package/dist/utils/mongoCacheBackend.js.map +1 -0
  49. package/package.json +2 -1
@@ -1,34 +1,30 @@
1
+ import type { CacheBackend } from './cacheBackend.js';
1
2
  import type { TranscriptLine, LLMChunk, ChunkEvaluation, AudioEvent, SegmentRefinement } from '../types/index.js';
3
+ export type { CacheBackend };
2
4
  /**
3
- * Disk-backed cache for all pipeline stages.
5
+ * Facade that wraps a CacheBackend and implements the CacheBackend interface.
4
6
  *
5
- * Constructed once in runner.ts with the resolved cache directory and passed
6
- * down to each stage that needs caching. Pass `disabled = true` to bypass all
7
- * reads and writes (equivalent to --no-cache).
7
+ * This means `Cache` can be passed anywhere a `CacheBackend` is expected, so
8
+ * all pipeline consumers work whether they type their parameter as `Cache` or
9
+ * `CacheBackend`. The concrete backend is injected by the factory in
10
+ * cacheFactory.ts.
11
+ *
12
+ * Call `close()` at the end of the pipeline to release backend resources
13
+ * (important for the MongoDB backend which holds an open connection).
8
14
  */
9
- export declare class Cache {
10
- private readonly cacheDir;
11
- private readonly disabled;
12
- constructor(cacheDir: string, disabled?: boolean);
13
- private transcriptPath;
15
+ export declare class Cache implements CacheBackend {
16
+ readonly backend: CacheBackend;
17
+ constructor(backend: CacheBackend);
14
18
  readTranscript(videoId: string): Promise<TranscriptLine[] | null>;
15
19
  writeTranscript(videoId: string, lines: TranscriptLine[]): Promise<void>;
16
- private chunkPath;
17
20
  readChunk(chunk: LLMChunk, chunkAudioEvents?: AudioEvent[]): Promise<ChunkEvaluation | null>;
18
21
  writeChunk(chunk: LLMChunk, evaluation: ChunkEvaluation, chunkAudioEvents?: AudioEvent[]): Promise<void>;
19
- private segmentRefinementPath;
20
22
  readSegmentRefinement(start: number, end: number, reason: string): Promise<SegmentRefinement | null>;
21
23
  writeSegmentRefinement(start: number, end: number, reason: string, refined: SegmentRefinement): Promise<void>;
22
- private audioEventPath;
23
24
  readAudioEvents(videoId: string, gameProfile: string, provider: string): Promise<AudioEvent[] | null>;
24
25
  writeAudioEvents(videoId: string, gameProfile: string, provider: string, events: AudioEvent[]): Promise<void>;
25
- /**
26
- * Per-chunk audio cache — mirrors the LLM `chunks/` pattern.
27
- * Key includes videoId, gameProfile, provider, and the exact window bounds
28
- * so each 120s slice is stored independently.
29
- */
30
- private audioChunkPath;
31
26
  readAudioChunk(videoId: string, gameProfile: string, provider: string, windowStart: number, windowEnd: number): Promise<AudioEvent[] | null>;
32
27
  writeAudioChunk(videoId: string, gameProfile: string, provider: string, windowStart: number, windowEnd: number, events: AudioEvent[]): Promise<void>;
28
+ close(): Promise<void>;
33
29
  }
34
30
  //# sourceMappingURL=cache.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../src/utils/cache.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EACV,cAAc,EACd,QAAQ,EACR,eAAe,EACf,UAAU,EACV,iBAAiB,EAClB,MAAM,mBAAmB,CAAC;AA0C3B;;;;;;GAMG;AACH,qBAAa,KAAK;IAEd,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,QAAQ;gBADR,QAAQ,EAAE,MAAM,EAChB,QAAQ,GAAE,OAAe;IAK5C,OAAO,CAAC,cAAc;IAIhB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,EAAE,GAAG,IAAI,CAAC;IAKjE,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,cAAc,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAO9E,OAAO,CAAC,SAAS;IASX,SAAS,CACb,KAAK,EAAE,QAAQ,EACf,gBAAgB,GAAE,UAAU,EAAO,GAClC,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC;IAK5B,UAAU,CACd,KAAK,EAAE,QAAQ,EACf,UAAU,EAAE,eAAe,EAC3B,gBAAgB,GAAE,UAAU,EAAO,GAClC,OAAO,CAAC,IAAI,CAAC;IAQhB,OAAO,CAAC,qBAAqB;IAIvB,qBAAqB,CACzB,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC;IAK9B,sBAAsB,CAC1B,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC,IAAI,CAAC;IAOhB,OAAO,CAAC,cAAc;IAQhB,eAAe,CACnB,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,UAAU,EAAE,GAAG,IAAI,CAAC;IAQzB,gBAAgB,CACpB,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,UAAU,EAAE,GACnB,OAAO,CAAC,IAAI,CAAC;IAOhB;;;;OAIG;IACH,OAAO,CAAC,cAAc;IAchB,cAAc,CAClB,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,UAAU,EAAE,GAAG,IAAI,CAAC;IAQzB,eAAe,CACnB,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,UAAU,EAAE,GACnB,OAAO,CAAC,IAAI,CAAC;CAOjB"}
1
+ {"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../src/utils/cache.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,KAAK,EACV,cAAc,EACd,QAAQ,EACR,eAAe,EACf,UAAU,EACV,iBAAiB,EAClB,MAAM,mBAAmB,CAAC;AAE3B,YAAY,EAAE,YAAY,EAAE,CAAC;AAE7B;;;;;;;;;;GAUG;AACH,qBAAa,KAAM,YAAW,YAAY;IAC5B,QAAQ,CAAC,OAAO,EAAE,YAAY;gBAArB,OAAO,EAAE,YAAY;IAIpC,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,EAAE,GAAG,IAAI,CAAC;IAIjE,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,cAAc,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAMxE,SAAS,CACb,KAAK,EAAE,QAAQ,EACf,gBAAgB,CAAC,EAAE,UAAU,EAAE,GAC9B,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC;IAI5B,UAAU,CACd,KAAK,EAAE,QAAQ,EACf,UAAU,EAAE,eAAe,EAC3B,gBAAgB,CAAC,EAAE,UAAU,EAAE,GAC9B,OAAO,CAAC,IAAI,CAAC;IAMV,qBAAqB,CACzB,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC;IAI9B,sBAAsB,CAC1B,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC,IAAI,CAAC;IAMV,eAAe,CACnB,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,UAAU,EAAE,GAAG,IAAI,CAAC;IAIzB,gBAAgB,CACpB,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,UAAU,EAAE,GACnB,OAAO,CAAC,IAAI,CAAC;IAMV,cAAc,CAClB,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,UAAU,EAAE,GAAG,IAAI,CAAC;IAIzB,eAAe,CACnB,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,UAAU,EAAE,GACnB,OAAO,CAAC,IAAI,CAAC;IAaV,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAG7B"}
@@ -1,137 +1,57 @@
1
- import { createHash } from 'node:crypto';
2
- import { promises as fs } from 'fs';
3
- import path from 'path';
4
- import { z } from 'zod';
5
- import { log } from './logger.js';
6
- import { TranscriptLineSchema, ChunkEvaluationSchema, AudioEventSchema, SegmentRefinementSchema, } from '../types/index.js';
7
1
  /**
8
- * Serializes audio events into a stable string for cache keying.
9
- * Events are sorted by time so the key is order-independent.
10
- */
11
- function audioEventsKey(events) {
12
- if (events.length === 0)
13
- return '';
14
- const sorted = [...events].sort((a, b) => a.time - b.time);
15
- return JSON.stringify(sorted);
16
- }
17
- function hashContent(input) {
18
- return createHash('sha256').update(input).digest('hex');
19
- }
20
- async function readCacheFile(filePath, schema) {
21
- try {
22
- const raw = await fs.readFile(filePath, 'utf-8');
23
- const parsed = schema.safeParse(JSON.parse(raw));
24
- if (!parsed.success) {
25
- log.warn(`[cache] Corrupt entry at ${filePath} — ignoring`);
26
- return null;
27
- }
28
- return parsed.data;
29
- }
30
- catch {
31
- // File not found or unreadable — normal cache miss, stay silent
32
- return null;
33
- }
34
- }
35
- async function writeCacheFile(filePath, data) {
36
- try {
37
- await fs.mkdir(path.dirname(filePath), { recursive: true });
38
- await fs.writeFile(filePath, JSON.stringify(data, null, 2), 'utf-8');
39
- }
40
- catch (err) {
41
- log.warn(`[cache] Failed to write ${filePath}: ${err instanceof Error ? err.message : String(err)}`);
42
- }
43
- }
44
- /**
45
- * Disk-backed cache for all pipeline stages.
2
+ * Facade that wraps a CacheBackend and implements the CacheBackend interface.
3
+ *
4
+ * This means `Cache` can be passed anywhere a `CacheBackend` is expected, so
5
+ * all pipeline consumers work whether they type their parameter as `Cache` or
6
+ * `CacheBackend`. The concrete backend is injected by the factory in
7
+ * cacheFactory.ts.
46
8
  *
47
- * Constructed once in runner.ts with the resolved cache directory and passed
48
- * down to each stage that needs caching. Pass `disabled = true` to bypass all
49
- * reads and writes (equivalent to --no-cache).
9
+ * Call `close()` at the end of the pipeline to release backend resources
10
+ * (important for the MongoDB backend which holds an open connection).
50
11
  */
51
12
  export class Cache {
52
- cacheDir;
53
- disabled;
54
- constructor(cacheDir, disabled = false) {
55
- this.cacheDir = cacheDir;
56
- this.disabled = disabled;
57
- }
58
- // ---- Transcript ---------------------------------------------------------
59
- transcriptPath(videoId) {
60
- return path.join(this.cacheDir, 'transcript', `${hashContent(videoId)}.json`);
13
+ backend;
14
+ constructor(backend) {
15
+ this.backend = backend;
61
16
  }
17
+ // ---- Transcript -----------------------------------------------------------
62
18
  async readTranscript(videoId) {
63
- if (this.disabled)
64
- return null;
65
- return readCacheFile(this.transcriptPath(videoId), z.array(TranscriptLineSchema));
19
+ return this.backend.readTranscript(videoId);
66
20
  }
67
21
  async writeTranscript(videoId, lines) {
68
- if (this.disabled)
69
- return;
70
- await writeCacheFile(this.transcriptPath(videoId), lines);
71
- }
72
- // ---- LLM chunk results --------------------------------------------------
73
- chunkPath(chunk, chunkAudioEvents = []) {
74
- const audioKey = audioEventsKey(chunkAudioEvents);
75
- return path.join(this.cacheDir, 'chunks', `${hashContent(`${chunk.start}|${chunk.end}|${chunk.text}|${audioKey}`)}.json`);
22
+ return this.backend.writeTranscript(videoId, lines);
76
23
  }
77
- async readChunk(chunk, chunkAudioEvents = []) {
78
- if (this.disabled)
79
- return null;
80
- return readCacheFile(this.chunkPath(chunk, chunkAudioEvents), ChunkEvaluationSchema);
24
+ // ---- LLM chunk results ----------------------------------------------------
25
+ async readChunk(chunk, chunkAudioEvents) {
26
+ return this.backend.readChunk(chunk, chunkAudioEvents);
81
27
  }
82
- async writeChunk(chunk, evaluation, chunkAudioEvents = []) {
83
- if (this.disabled)
84
- return;
85
- if (evaluation.status !== 'success')
86
- return;
87
- await writeCacheFile(this.chunkPath(chunk, chunkAudioEvents), evaluation);
88
- }
89
- // ---- Segment refinement -------------------------------------------------
90
- segmentRefinementPath(start, end, reason) {
91
- return path.join(this.cacheDir, 'segments', `${hashContent(`${start}|${end}|${reason}`)}.json`);
28
+ async writeChunk(chunk, evaluation, chunkAudioEvents) {
29
+ return this.backend.writeChunk(chunk, evaluation, chunkAudioEvents);
92
30
  }
31
+ // ---- Segment refinement ---------------------------------------------------
93
32
  async readSegmentRefinement(start, end, reason) {
94
- if (this.disabled)
95
- return null;
96
- return readCacheFile(this.segmentRefinementPath(start, end, reason), SegmentRefinementSchema);
33
+ return this.backend.readSegmentRefinement(start, end, reason);
97
34
  }
98
35
  async writeSegmentRefinement(start, end, reason, refined) {
99
- if (this.disabled)
100
- return;
101
- await writeCacheFile(this.segmentRefinementPath(start, end, reason), refined);
102
- }
103
- // ---- Audio events (whole-video) -----------------------------------------
104
- audioEventPath(videoId, gameProfile, provider) {
105
- return path.join(this.cacheDir, 'audio', `${hashContent(`${videoId}|${gameProfile}|${provider}`)}.json`);
36
+ return this.backend.writeSegmentRefinement(start, end, reason, refined);
106
37
  }
38
+ // ---- Audio events (whole-video) -------------------------------------------
107
39
  async readAudioEvents(videoId, gameProfile, provider) {
108
- if (this.disabled)
109
- return null;
110
- return readCacheFile(this.audioEventPath(videoId, gameProfile, provider), z.array(AudioEventSchema));
40
+ return this.backend.readAudioEvents(videoId, gameProfile, provider);
111
41
  }
112
42
  async writeAudioEvents(videoId, gameProfile, provider, events) {
113
- if (this.disabled)
114
- return;
115
- await writeCacheFile(this.audioEventPath(videoId, gameProfile, provider), events);
116
- }
117
- // ---- Audio events (per-chunk) -------------------------------------------
118
- /**
119
- * Per-chunk audio cache — mirrors the LLM `chunks/` pattern.
120
- * Key includes videoId, gameProfile, provider, and the exact window bounds
121
- * so each 120s slice is stored independently.
122
- */
123
- audioChunkPath(videoId, gameProfile, provider, windowStart, windowEnd) {
124
- return path.join(this.cacheDir, 'audio', `${hashContent(`${videoId}|${gameProfile}|${provider}|${windowStart}|${windowEnd}`)}.json`);
43
+ return this.backend.writeAudioEvents(videoId, gameProfile, provider, events);
125
44
  }
45
+ // ---- Audio events (per-chunk) ---------------------------------------------
126
46
  async readAudioChunk(videoId, gameProfile, provider, windowStart, windowEnd) {
127
- if (this.disabled)
128
- return null;
129
- return readCacheFile(this.audioChunkPath(videoId, gameProfile, provider, windowStart, windowEnd), z.array(AudioEventSchema));
47
+ return this.backend.readAudioChunk(videoId, gameProfile, provider, windowStart, windowEnd);
130
48
  }
131
49
  async writeAudioChunk(videoId, gameProfile, provider, windowStart, windowEnd, events) {
132
- if (this.disabled)
133
- return;
134
- await writeCacheFile(this.audioChunkPath(videoId, gameProfile, provider, windowStart, windowEnd), events);
50
+ return this.backend.writeAudioChunk(videoId, gameProfile, provider, windowStart, windowEnd, events);
51
+ }
52
+ // ---- Lifecycle ------------------------------------------------------------
53
+ async close() {
54
+ return this.backend.close();
135
55
  }
136
56
  }
137
57
  //# sourceMappingURL=cache.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"cache.js","sourceRoot":"","sources":["../../src/utils/cache.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cache.js","sourceRoot":"","sources":["../../src/utils/cache.ts"],"names":[],"mappings":"AAWA;;;;;;;;;;GAUG;AACH,MAAM,OAAO,KAAK;IACK;IAArB,YAAqB,OAAqB;QAArB,YAAO,GAAP,OAAO,CAAc;IAAG,CAAC;IAE9C,8EAA8E;IAE9E,KAAK,CAAC,cAAc,CAAC,OAAe;QAClC,OAAO,IAAI,CAAC,OAAO,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;IAC9C,CAAC;IAED,KAAK,CAAC,eAAe,CAAC,OAAe,EAAE,KAAuB;QAC5D,OAAO,IAAI,CAAC,OAAO,CAAC,eAAe,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;IACtD,CAAC;IAED,8EAA8E;IAE9E,KAAK,CAAC,SAAS,CACb,KAAe,EACf,gBAA+B;QAE/B,OAAO,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,KAAK,EAAE,gBAAgB,CAAC,CAAC;IACzD,CAAC;IAED,KAAK,CAAC,UAAU,CACd,KAAe,EACf,UAA2B,EAC3B,gBAA+B;QAE/B,OAAO,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,KAAK,EAAE,UAAU,EAAE,gBAAgB,CAAC,CAAC;IACtE,CAAC;IAED,8EAA8E;IAE9E,KAAK,CAAC,qBAAqB,CACzB,KAAa,EACb,GAAW,EACX,MAAc;QAEd,OAAO,IAAI,CAAC,OAAO,CAAC,qBAAqB,CAAC,KAAK,EAAE,GAAG,EAAE,MAAM,CAAC,CAAC;IAChE,CAAC;IAED,KAAK,CAAC,sBAAsB,CAC1B,KAAa,EACb,GAAW,EACX,MAAc,EACd,OAA0B;QAE1B,OAAO,IAAI,CAAC,OAAO,CAAC,sBAAsB,CAAC,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;IAC1E,CAAC;IAED,8EAA8E;IAE9E,KAAK,CAAC,eAAe,CACnB,OAAe,EACf,WAAmB,EACnB,QAAgB;QAEhB,OAAO,IAAI,CAAC,OAAO,CAAC,eAAe,CAAC,OAAO,EAAE,WAAW,EAAE,QAAQ,CAAC,CAAC;IACtE,CAAC;IAED,KAAK,CAAC,gBAAgB,CACpB,OAAe,EACf,WAAmB,EACnB,QAAgB,EAChB,MAAoB;QAEpB,OAAO,IAAI,CAAC,OAAO,CAAC,gBAAgB,CAAC,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC;IAC/E,CAAC;IAED,8EAA8E;IAE9E,KAAK,CAAC,cAAc,CAClB,OAAe,EACf,WAAmB,EACnB,QAAgB,EAChB,WAAmB,EACnB,SAAiB;QAEjB,OAAO,IAAI,CAAC,OAAO,CAAC,cAAc,CAAC,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,WAAW,EAAE,SAAS,CAAC,CAAC;IAC7F,CAAC;IAED,KAAK,CAAC,eAAe,CACnB,OAAe,EACf,WAAmB,EACnB,QAAgB,EAChB,WAAmB,EACnB,SAAiB,EACjB,MAAoB;QAEpB,OAAO,IAAI,CAAC,OAAO,CAAC,eAAe,CACjC,OAAO,EACP,WAAW,EACX,QAAQ,EACR,WAAW,EACX,SAAS,EACT,MAAM,CACP,CAAC;IACJ,CAAC;IAED,8EAA8E;IAE9E,KAAK,CAAC,KAAK;QACT,OAAO,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;IAC9B,CAAC;CACF"}
@@ -0,0 +1,40 @@
1
+ import type { TranscriptLine, LLMChunk, ChunkEvaluation, AudioEvent, SegmentRefinement } from '../types/index.js';
2
+ /**
3
+ * Common interface implemented by every cache backend (file-based, MongoDB, etc.).
4
+ *
5
+ * All read methods return null on a cache miss or any read error.
6
+ * All write methods are fire-and-forget — failures are logged but never thrown.
7
+ * `close()` releases any underlying resources (connections, file handles, etc.).
8
+ */
9
+ export interface CacheBackend {
10
+ readTranscript(videoId: string): Promise<TranscriptLine[] | null>;
11
+ writeTranscript(videoId: string, lines: TranscriptLine[]): Promise<void>;
12
+ readChunk(chunk: LLMChunk, chunkAudioEvents?: AudioEvent[]): Promise<ChunkEvaluation | null>;
13
+ writeChunk(chunk: LLMChunk, evaluation: ChunkEvaluation, chunkAudioEvents?: AudioEvent[]): Promise<void>;
14
+ readSegmentRefinement(start: number, end: number, reason: string): Promise<SegmentRefinement | null>;
15
+ writeSegmentRefinement(start: number, end: number, reason: string, refined: SegmentRefinement): Promise<void>;
16
+ readAudioEvents(videoId: string, gameProfile: string, provider: string): Promise<AudioEvent[] | null>;
17
+ writeAudioEvents(videoId: string, gameProfile: string, provider: string, events: AudioEvent[]): Promise<void>;
18
+ readAudioChunk(videoId: string, gameProfile: string, provider: string, windowStart: number, windowEnd: number): Promise<AudioEvent[] | null>;
19
+ writeAudioChunk(videoId: string, gameProfile: string, provider: string, windowStart: number, windowEnd: number, events: AudioEvent[]): Promise<void>;
20
+ /** Release any underlying resources (DB connections, file handles, etc.). */
21
+ close(): Promise<void>;
22
+ }
23
+ /**
24
+ * No-op backend used when the cache is disabled (--no-cache flag).
25
+ * All reads return null; all writes are silent no-ops.
26
+ */
27
+ export declare class DisabledCacheBackend implements CacheBackend {
28
+ readTranscript(_videoId: string): Promise<TranscriptLine[] | null>;
29
+ writeTranscript(_videoId: string, _lines: TranscriptLine[]): Promise<void>;
30
+ readChunk(_chunk: LLMChunk, _chunkAudioEvents?: AudioEvent[]): Promise<ChunkEvaluation | null>;
31
+ writeChunk(_chunk: LLMChunk, _evaluation: ChunkEvaluation, _chunkAudioEvents?: AudioEvent[]): Promise<void>;
32
+ readSegmentRefinement(_start: number, _end: number, _reason: string): Promise<SegmentRefinement | null>;
33
+ writeSegmentRefinement(_start: number, _end: number, _reason: string, _refined: SegmentRefinement): Promise<void>;
34
+ readAudioEvents(_videoId: string, _gameProfile: string, _provider: string): Promise<AudioEvent[] | null>;
35
+ writeAudioEvents(_videoId: string, _gameProfile: string, _provider: string, _events: AudioEvent[]): Promise<void>;
36
+ readAudioChunk(_videoId: string, _gameProfile: string, _provider: string, _windowStart: number, _windowEnd: number): Promise<AudioEvent[] | null>;
37
+ writeAudioChunk(_videoId: string, _gameProfile: string, _provider: string, _windowStart: number, _windowEnd: number, _events: AudioEvent[]): Promise<void>;
38
+ close(): Promise<void>;
39
+ }
40
+ //# sourceMappingURL=cacheBackend.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cacheBackend.d.ts","sourceRoot":"","sources":["../../src/utils/cacheBackend.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,cAAc,EACd,QAAQ,EACR,eAAe,EACf,UAAU,EACV,iBAAiB,EAClB,MAAM,mBAAmB,CAAC;AAE3B;;;;;;GAMG;AACH,MAAM,WAAW,YAAY;IAE3B,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,EAAE,GAAG,IAAI,CAAC,CAAC;IAClE,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,cAAc,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAGzE,SAAS,CAAC,KAAK,EAAE,QAAQ,EAAE,gBAAgB,CAAC,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CAAC;IAC7F,UAAU,CACR,KAAK,EAAE,QAAQ,EACf,UAAU,EAAE,eAAe,EAC3B,gBAAgB,CAAC,EAAE,UAAU,EAAE,GAC9B,OAAO,CAAC,IAAI,CAAC,CAAC;IAGjB,qBAAqB,CACnB,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAAC;IACrC,sBAAsB,CACpB,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC,IAAI,CAAC,CAAC;IAGjB,eAAe,CACb,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,UAAU,EAAE,GAAG,IAAI,CAAC,CAAC;IAChC,gBAAgB,CACd,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,UAAU,EAAE,GACnB,OAAO,CAAC,IAAI,CAAC,CAAC;IAGjB,cAAc,CACZ,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,UAAU,EAAE,GAAG,IAAI,CAAC,CAAC;IAChC,eAAe,CACb,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,UAAU,EAAE,GACnB,OAAO,CAAC,IAAI,CAAC,CAAC;IAGjB,6EAA6E;IAC7E,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAED;;;GAGG;AACH,qBAAa,oBAAqB,YAAW,YAAY;IACjD,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,EAAE,GAAG,IAAI,CAAC;IAGlE,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,cAAc,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAE1E,SAAS,CACb,MAAM,EAAE,QAAQ,EAChB,iBAAiB,CAAC,EAAE,UAAU,EAAE,GAC/B,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC;IAG5B,UAAU,CACd,MAAM,EAAE,QAAQ,EAChB,WAAW,EAAE,eAAe,EAC5B,iBAAiB,CAAC,EAAE,UAAU,EAAE,GAC/B,OAAO,CAAC,IAAI,CAAC;IAEV,qBAAqB,CACzB,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC;IAG9B,sBAAsB,CAC1B,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,iBAAiB,GAC1B,OAAO,CAAC,IAAI,CAAC;IAEV,eAAe,CACnB,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,MAAM,EACpB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,UAAU,EAAE,GAAG,IAAI,CAAC;IAGzB,gBAAgB,CACpB,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,MAAM,EACpB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,UAAU,EAAE,GACpB,OAAO,CAAC,IAAI,CAAC;IAEV,cAAc,CAClB,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,MAAM,EACpB,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,UAAU,EAAE,GAAG,IAAI,CAAC;IAGzB,eAAe,CACnB,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,MAAM,EACpB,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,UAAU,EAAE,GACpB,OAAO,CAAC,IAAI,CAAC;IAEV,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAC7B"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * No-op backend used when the cache is disabled (--no-cache flag).
3
+ * All reads return null; all writes are silent no-ops.
4
+ */
5
+ export class DisabledCacheBackend {
6
+ async readTranscript(_videoId) {
7
+ return null;
8
+ }
9
+ async writeTranscript(_videoId, _lines) { }
10
+ async readChunk(_chunk, _chunkAudioEvents) {
11
+ return null;
12
+ }
13
+ async writeChunk(_chunk, _evaluation, _chunkAudioEvents) { }
14
+ async readSegmentRefinement(_start, _end, _reason) {
15
+ return null;
16
+ }
17
+ async writeSegmentRefinement(_start, _end, _reason, _refined) { }
18
+ async readAudioEvents(_videoId, _gameProfile, _provider) {
19
+ return null;
20
+ }
21
+ async writeAudioEvents(_videoId, _gameProfile, _provider, _events) { }
22
+ async readAudioChunk(_videoId, _gameProfile, _provider, _windowStart, _windowEnd) {
23
+ return null;
24
+ }
25
+ async writeAudioChunk(_videoId, _gameProfile, _provider, _windowStart, _windowEnd, _events) { }
26
+ async close() { }
27
+ }
28
+ //# sourceMappingURL=cacheBackend.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cacheBackend.js","sourceRoot":"","sources":["../../src/utils/cacheBackend.ts"],"names":[],"mappings":"AA4EA;;;GAGG;AACH,MAAM,OAAO,oBAAoB;IAC/B,KAAK,CAAC,cAAc,CAAC,QAAgB;QACnC,OAAO,IAAI,CAAC;IACd,CAAC;IACD,KAAK,CAAC,eAAe,CAAC,QAAgB,EAAE,MAAwB,IAAkB,CAAC;IAEnF,KAAK,CAAC,SAAS,CACb,MAAgB,EAChB,iBAAgC;QAEhC,OAAO,IAAI,CAAC;IACd,CAAC;IACD,KAAK,CAAC,UAAU,CACd,MAAgB,EAChB,WAA4B,EAC5B,iBAAgC,IAChB,CAAC;IAEnB,KAAK,CAAC,qBAAqB,CACzB,MAAc,EACd,IAAY,EACZ,OAAe;QAEf,OAAO,IAAI,CAAC;IACd,CAAC;IACD,KAAK,CAAC,sBAAsB,CAC1B,MAAc,EACd,IAAY,EACZ,OAAe,EACf,QAA2B,IACX,CAAC;IAEnB,KAAK,CAAC,eAAe,CACnB,QAAgB,EAChB,YAAoB,EACpB,SAAiB;QAEjB,OAAO,IAAI,CAAC;IACd,CAAC;IACD,KAAK,CAAC,gBAAgB,CACpB,QAAgB,EAChB,YAAoB,EACpB,SAAiB,EACjB,OAAqB,IACL,CAAC;IAEnB,KAAK,CAAC,cAAc,CAClB,QAAgB,EAChB,YAAoB,EACpB,SAAiB,EACjB,YAAoB,EACpB,UAAkB;QAElB,OAAO,IAAI,CAAC;IACd,CAAC;IACD,KAAK,CAAC,eAAe,CACnB,QAAgB,EAChB,YAAoB,EACpB,SAAiB,EACjB,YAAoB,EACpB,UAAkB,EAClB,OAAqB,IACL,CAAC;IAEnB,KAAK,CAAC,KAAK,KAAmB,CAAC;CAChC"}
@@ -0,0 +1,14 @@
1
+ import type { CacheBackend } from './cacheBackend.js';
2
+ import type { Config } from '../types/index.js';
3
+ /**
4
+ * Creates the appropriate CacheBackend based on config.
5
+ *
6
+ * - `disabled = true` → DisabledCacheBackend (--no-cache flag)
7
+ * - `CACHE_BACKEND = 'file'` → FileCacheBackend (default)
8
+ * - `CACHE_BACKEND = 'mongodb'` → MongoCacheBackend (requires MONGODB_URI)
9
+ *
10
+ * The caller is responsible for calling `backend.close()` when the pipeline
11
+ * finishes so that any open connections (e.g. MongoClient) are released.
12
+ */
13
+ export declare function createCacheBackend(config: Pick<Config, 'CACHE_BACKEND' | 'CACHE_DIR' | 'MONGODB_URI' | 'MONGODB_DATABASE' | 'CACHE_TTL_SECONDS'>, disabled: boolean): Promise<CacheBackend>;
14
+ //# sourceMappingURL=cacheFactory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cacheFactory.d.ts","sourceRoot":"","sources":["../../src/utils/cacheFactory.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAEhD;;;;;;;;;GASG;AACH,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,IAAI,CACV,MAAM,EACN,eAAe,GAAG,WAAW,GAAG,aAAa,GAAG,kBAAkB,GAAG,mBAAmB,CACzF,EACD,QAAQ,EAAE,OAAO,GAChB,OAAO,CAAC,YAAY,CAAC,CAgBvB"}
@@ -0,0 +1,31 @@
1
+ import { MongoClient } from 'mongodb';
2
+ import { log } from './logger.js';
3
+ import { FileCacheBackend } from './fileCacheBackend.js';
4
+ import { MongoCacheBackend } from './mongoCacheBackend.js';
5
+ import { DisabledCacheBackend } from './cacheBackend.js';
6
+ /**
7
+ * Creates the appropriate CacheBackend based on config.
8
+ *
9
+ * - `disabled = true` → DisabledCacheBackend (--no-cache flag)
10
+ * - `CACHE_BACKEND = 'file'` → FileCacheBackend (default)
11
+ * - `CACHE_BACKEND = 'mongodb'` → MongoCacheBackend (requires MONGODB_URI)
12
+ *
13
+ * The caller is responsible for calling `backend.close()` when the pipeline
14
+ * finishes so that any open connections (e.g. MongoClient) are released.
15
+ */
16
+ export async function createCacheBackend(config, disabled) {
17
+ if (disabled) {
18
+ return new DisabledCacheBackend();
19
+ }
20
+ if (config.CACHE_BACKEND === 'mongodb') {
21
+ // MONGODB_URI is guaranteed to be set by the superRefine in ConfigSchema
22
+ const uri = config.MONGODB_URI;
23
+ log.info(`[cache] Using MongoDB backend (${config.MONGODB_DATABASE})`);
24
+ const client = new MongoClient(uri);
25
+ await client.connect();
26
+ return new MongoCacheBackend(client, config.MONGODB_DATABASE, config.CACHE_TTL_SECONDS);
27
+ }
28
+ // Default: file-based backend
29
+ return new FileCacheBackend(config.CACHE_DIR);
30
+ }
31
+ //# sourceMappingURL=cacheFactory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cacheFactory.js","sourceRoot":"","sources":["../../src/utils/cacheFactory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AACtC,OAAO,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AAClC,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAIzD;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,MAGC,EACD,QAAiB;IAEjB,IAAI,QAAQ,EAAE,CAAC;QACb,OAAO,IAAI,oBAAoB,EAAE,CAAC;IACpC,CAAC;IAED,IAAI,MAAM,CAAC,aAAa,KAAK,SAAS,EAAE,CAAC;QACvC,yEAAyE;QACzE,MAAM,GAAG,GAAG,MAAM,CAAC,WAAqB,CAAC;QACzC,GAAG,CAAC,IAAI,CAAC,kCAAkC,MAAM,CAAC,gBAAgB,GAAG,CAAC,CAAC;QACvE,MAAM,MAAM,GAAG,IAAI,WAAW,CAAC,GAAG,CAAC,CAAC;QACpC,MAAM,MAAM,CAAC,OAAO,EAAE,CAAC;QACvB,OAAO,IAAI,iBAAiB,CAAC,MAAM,EAAE,MAAM,CAAC,gBAAgB,EAAE,MAAM,CAAC,iBAAiB,CAAC,CAAC;IAC1F,CAAC;IAED,8BAA8B;IAC9B,OAAO,IAAI,gBAAgB,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;AAChD,CAAC"}
@@ -0,0 +1,33 @@
1
+ import type { TranscriptLine, LLMChunk, ChunkEvaluation, AudioEvent, SegmentRefinement } from '../types/index.js';
2
+ import type { CacheBackend } from './cacheBackend.js';
3
+ /**
4
+ * Disk-backed cache backend. Each cached item is stored as a pretty-printed
5
+ * JSON file under `cacheDir`, named by a SHA-256 hash of the cache key.
6
+ *
7
+ * Directory layout:
8
+ * <cacheDir>/transcript/<hash>.json
9
+ * <cacheDir>/chunks/<hash>.json
10
+ * <cacheDir>/segments/<hash>.json
11
+ * <cacheDir>/audio/<hash>.json
12
+ */
13
+ export declare class FileCacheBackend implements CacheBackend {
14
+ private readonly cacheDir;
15
+ constructor(cacheDir: string);
16
+ private transcriptPath;
17
+ readTranscript(videoId: string): Promise<TranscriptLine[] | null>;
18
+ writeTranscript(videoId: string, lines: TranscriptLine[]): Promise<void>;
19
+ private chunkPath;
20
+ readChunk(chunk: LLMChunk, chunkAudioEvents?: AudioEvent[]): Promise<ChunkEvaluation | null>;
21
+ writeChunk(chunk: LLMChunk, evaluation: ChunkEvaluation, chunkAudioEvents?: AudioEvent[]): Promise<void>;
22
+ private segmentRefinementPath;
23
+ readSegmentRefinement(start: number, end: number, reason: string): Promise<SegmentRefinement | null>;
24
+ writeSegmentRefinement(start: number, end: number, reason: string, refined: SegmentRefinement): Promise<void>;
25
+ private audioEventPath;
26
+ readAudioEvents(videoId: string, gameProfile: string, provider: string): Promise<AudioEvent[] | null>;
27
+ writeAudioEvents(videoId: string, gameProfile: string, provider: string, events: AudioEvent[]): Promise<void>;
28
+ private audioChunkPath;
29
+ readAudioChunk(videoId: string, gameProfile: string, provider: string, windowStart: number, windowEnd: number): Promise<AudioEvent[] | null>;
30
+ writeAudioChunk(videoId: string, gameProfile: string, provider: string, windowStart: number, windowEnd: number, events: AudioEvent[]): Promise<void>;
31
+ close(): Promise<void>;
32
+ }
33
+ //# sourceMappingURL=fileCacheBackend.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fileCacheBackend.d.ts","sourceRoot":"","sources":["../../src/utils/fileCacheBackend.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EACV,cAAc,EACd,QAAQ,EACR,eAAe,EACf,UAAU,EACV,iBAAiB,EAClB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAkDtD;;;;;;;;;GASG;AACH,qBAAa,gBAAiB,YAAW,YAAY;IACvC,OAAO,CAAC,QAAQ,CAAC,QAAQ;gBAAR,QAAQ,EAAE,MAAM;IAI7C,OAAO,CAAC,cAAc;IAIhB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,EAAE,GAAG,IAAI,CAAC;IAIjE,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,cAAc,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAM9E,OAAO,CAAC,SAAS;IASX,SAAS,CACb,KAAK,EAAE,QAAQ,EACf,gBAAgB,GAAE,UAAU,EAAO,GAClC,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC;IAI5B,UAAU,CACd,KAAK,EAAE,QAAQ,EACf,UAAU,EAAE,eAAe,EAC3B,gBAAgB,GAAE,UAAU,EAAO,GAClC,OAAO,CAAC,IAAI,CAAC;IAOhB,OAAO,CAAC,qBAAqB;IAIvB,qBAAqB,CACzB,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC;IAI9B,sBAAsB,CAC1B,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC,IAAI,CAAC;IAMhB,OAAO,CAAC,cAAc;IAQhB,eAAe,CACnB,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,UAAU,EAAE,GAAG,IAAI,CAAC;IAOzB,gBAAgB,CACpB,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,UAAU,EAAE,GACnB,OAAO,CAAC,IAAI,CAAC;IAMhB,OAAO,CAAC,cAAc;IAchB,cAAc,CAClB,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,UAAU,EAAE,GAAG,IAAI,CAAC;IAOzB,eAAe,CACnB,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,UAAU,EAAE,GACnB,OAAO,CAAC,IAAI,CAAC;IASV,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAG7B"}
@@ -0,0 +1,123 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { promises as fs } from 'fs';
3
+ import path from 'path';
4
+ import { z } from 'zod';
5
+ import { log } from './logger.js';
6
+ import { TranscriptLineSchema, ChunkEvaluationSchema, AudioEventSchema, SegmentRefinementSchema, } from '../types/index.js';
7
+ // ---------------------------------------------------------------------------
8
+ // Internal helpers
9
+ // ---------------------------------------------------------------------------
10
+ /**
11
+ * Serializes audio events into a stable string for cache keying.
12
+ * Events are sorted by time so the key is order-independent.
13
+ */
14
+ function audioEventsKey(events) {
15
+ if (events.length === 0)
16
+ return '';
17
+ const sorted = [...events].sort((a, b) => a.time - b.time);
18
+ return JSON.stringify(sorted);
19
+ }
20
+ function hashContent(input) {
21
+ return createHash('sha256').update(input).digest('hex');
22
+ }
23
+ async function readCacheFile(filePath, schema) {
24
+ try {
25
+ const raw = await fs.readFile(filePath, 'utf-8');
26
+ const parsed = schema.safeParse(JSON.parse(raw));
27
+ if (!parsed.success) {
28
+ log.warn(`[cache] Corrupt entry at ${filePath} — ignoring`);
29
+ return null;
30
+ }
31
+ return parsed.data;
32
+ }
33
+ catch {
34
+ // File not found or unreadable — normal cache miss, stay silent
35
+ return null;
36
+ }
37
+ }
38
+ async function writeCacheFile(filePath, data) {
39
+ try {
40
+ await fs.mkdir(path.dirname(filePath), { recursive: true });
41
+ await fs.writeFile(filePath, JSON.stringify(data, null, 2), 'utf-8');
42
+ }
43
+ catch (err) {
44
+ log.warn(`[cache] Failed to write ${filePath}: ${err instanceof Error ? err.message : String(err)}`);
45
+ }
46
+ }
47
+ // ---------------------------------------------------------------------------
48
+ // FileCacheBackend
49
+ // ---------------------------------------------------------------------------
50
+ /**
51
+ * Disk-backed cache backend. Each cached item is stored as a pretty-printed
52
+ * JSON file under `cacheDir`, named by a SHA-256 hash of the cache key.
53
+ *
54
+ * Directory layout:
55
+ * <cacheDir>/transcript/<hash>.json
56
+ * <cacheDir>/chunks/<hash>.json
57
+ * <cacheDir>/segments/<hash>.json
58
+ * <cacheDir>/audio/<hash>.json
59
+ */
60
+ export class FileCacheBackend {
61
+ cacheDir;
62
+ constructor(cacheDir) {
63
+ this.cacheDir = cacheDir;
64
+ }
65
+ // ---- Transcript -----------------------------------------------------------
66
+ transcriptPath(videoId) {
67
+ return path.join(this.cacheDir, 'transcript', `${hashContent(videoId)}.json`);
68
+ }
69
+ async readTranscript(videoId) {
70
+ return readCacheFile(this.transcriptPath(videoId), z.array(TranscriptLineSchema));
71
+ }
72
+ async writeTranscript(videoId, lines) {
73
+ await writeCacheFile(this.transcriptPath(videoId), lines);
74
+ }
75
+ // ---- LLM chunk results ----------------------------------------------------
76
+ chunkPath(chunk, chunkAudioEvents = []) {
77
+ const audioKey = audioEventsKey(chunkAudioEvents);
78
+ return path.join(this.cacheDir, 'chunks', `${hashContent(`${chunk.start}|${chunk.end}|${chunk.text}|${audioKey}`)}.json`);
79
+ }
80
+ async readChunk(chunk, chunkAudioEvents = []) {
81
+ return readCacheFile(this.chunkPath(chunk, chunkAudioEvents), ChunkEvaluationSchema);
82
+ }
83
+ async writeChunk(chunk, evaluation, chunkAudioEvents = []) {
84
+ if (evaluation.status !== 'success')
85
+ return;
86
+ await writeCacheFile(this.chunkPath(chunk, chunkAudioEvents), evaluation);
87
+ }
88
+ // ---- Segment refinement ---------------------------------------------------
89
+ segmentRefinementPath(start, end, reason) {
90
+ return path.join(this.cacheDir, 'segments', `${hashContent(`${start}|${end}|${reason}`)}.json`);
91
+ }
92
+ async readSegmentRefinement(start, end, reason) {
93
+ return readCacheFile(this.segmentRefinementPath(start, end, reason), SegmentRefinementSchema);
94
+ }
95
+ async writeSegmentRefinement(start, end, reason, refined) {
96
+ await writeCacheFile(this.segmentRefinementPath(start, end, reason), refined);
97
+ }
98
+ // ---- Audio events (whole-video) -------------------------------------------
99
+ audioEventPath(videoId, gameProfile, provider) {
100
+ return path.join(this.cacheDir, 'audio', `${hashContent(`${videoId}|${gameProfile}|${provider}`)}.json`);
101
+ }
102
+ async readAudioEvents(videoId, gameProfile, provider) {
103
+ return readCacheFile(this.audioEventPath(videoId, gameProfile, provider), z.array(AudioEventSchema));
104
+ }
105
+ async writeAudioEvents(videoId, gameProfile, provider, events) {
106
+ await writeCacheFile(this.audioEventPath(videoId, gameProfile, provider), events);
107
+ }
108
+ // ---- Audio events (per-chunk) ---------------------------------------------
109
+ audioChunkPath(videoId, gameProfile, provider, windowStart, windowEnd) {
110
+ return path.join(this.cacheDir, 'audio', `${hashContent(`${videoId}|${gameProfile}|${provider}|${windowStart}|${windowEnd}`)}.json`);
111
+ }
112
+ async readAudioChunk(videoId, gameProfile, provider, windowStart, windowEnd) {
113
+ return readCacheFile(this.audioChunkPath(videoId, gameProfile, provider, windowStart, windowEnd), z.array(AudioEventSchema));
114
+ }
115
+ async writeAudioChunk(videoId, gameProfile, provider, windowStart, windowEnd, events) {
116
+ await writeCacheFile(this.audioChunkPath(videoId, gameProfile, provider, windowStart, windowEnd), events);
117
+ }
118
+ // ---- Lifecycle ------------------------------------------------------------
119
+ async close() {
120
+ // No-op — file handles are not kept open between operations
121
+ }
122
+ }
123
+ //# sourceMappingURL=fileCacheBackend.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fileCacheBackend.js","sourceRoot":"","sources":["../../src/utils/fileCacheBackend.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,51 @@
1
+ import type { MongoClient } from 'mongodb';
2
+ import type { TranscriptLine, LLMChunk, ChunkEvaluation, AudioEvent, SegmentRefinement } from '../types/index.js';
3
+ import type { CacheBackend } from './cacheBackend.js';
4
+ /**
5
+ * MongoDB-backed cache backend.
6
+ *
7
+ * Each cache category maps to one collection. Documents have the shape:
8
+ * { cacheKey: string, data: <payload>, createdAt: Date }
9
+ *
10
+ * Indexes created on first use (idempotent):
11
+ * - Unique index on `cacheKey` for O(1) lookups
12
+ * - TTL index on `createdAt` when `ttlSeconds > 0`
13
+ *
14
+ * All reads validate the stored payload through the same zod schemas used by
15
+ * the file backend, giving identical runtime safety guarantees.
16
+ *
17
+ * Pass `ttlSeconds = 0` (or omit) to disable TTL expiration.
18
+ */
19
+ export declare class MongoCacheBackend implements CacheBackend {
20
+ private readonly client;
21
+ private readonly db;
22
+ private readonly ttlSeconds;
23
+ /** Track which collections already have their indexes created this session. */
24
+ private readonly indexedCollections;
25
+ constructor(client: MongoClient, databaseName: string, ttlSeconds?: number);
26
+ /**
27
+ * Ensures indexes exist for a collection. Called lazily on first access per
28
+ * collection name. `createIndex` is idempotent so concurrent calls are safe.
29
+ */
30
+ private ensureIndexes;
31
+ private readDoc;
32
+ private writeDoc;
33
+ private static readonly TRANSCRIPTS;
34
+ readTranscript(videoId: string): Promise<TranscriptLine[] | null>;
35
+ writeTranscript(videoId: string, lines: TranscriptLine[]): Promise<void>;
36
+ private static readonly CHUNKS;
37
+ private chunkKey;
38
+ readChunk(chunk: LLMChunk, chunkAudioEvents?: AudioEvent[]): Promise<ChunkEvaluation | null>;
39
+ writeChunk(chunk: LLMChunk, evaluation: ChunkEvaluation, chunkAudioEvents?: AudioEvent[]): Promise<void>;
40
+ private static readonly SEGMENTS;
41
+ readSegmentRefinement(start: number, end: number, reason: string): Promise<SegmentRefinement | null>;
42
+ writeSegmentRefinement(start: number, end: number, reason: string, refined: SegmentRefinement): Promise<void>;
43
+ private static readonly AUDIO_EVENTS;
44
+ readAudioEvents(videoId: string, gameProfile: string, provider: string): Promise<AudioEvent[] | null>;
45
+ writeAudioEvents(videoId: string, gameProfile: string, provider: string, events: AudioEvent[]): Promise<void>;
46
+ private static readonly AUDIO_CHUNKS;
47
+ readAudioChunk(videoId: string, gameProfile: string, provider: string, windowStart: number, windowEnd: number): Promise<AudioEvent[] | null>;
48
+ writeAudioChunk(videoId: string, gameProfile: string, provider: string, windowStart: number, windowEnd: number, events: AudioEvent[]): Promise<void>;
49
+ close(): Promise<void>;
50
+ }
51
+ //# sourceMappingURL=mongoCacheBackend.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mongoCacheBackend.d.ts","sourceRoot":"","sources":["../../src/utils/mongoCacheBackend.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAS3C,OAAO,KAAK,EACV,cAAc,EACd,QAAQ,EACR,eAAe,EACf,UAAU,EACV,iBAAiB,EAClB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAqCtD;;;;;;;;;;;;;;GAcG;AACH,qBAAa,iBAAkB,YAAW,YAAY;IAOlD,OAAO,CAAC,QAAQ,CAAC,MAAM;IANzB,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;IACpB,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,+EAA+E;IAC/E,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAqB;gBAGrC,MAAM,EAAE,WAAW,EACpC,YAAY,EAAE,MAAM,EACpB,UAAU,SAAI;IAUhB;;;OAGG;YACW,aAAa;YAuBb,OAAO;YAyBP,QAAQ;IAoBtB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,WAAW,CAAiB;IAE9C,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,EAAE,GAAG,IAAI,CAAC;IAQjE,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,cAAc,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAQ9E,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAsB;IAEpD,OAAO,CAAC,QAAQ;IAKV,SAAS,CACb,KAAK,EAAE,QAAQ,EACf,gBAAgB,GAAE,UAAU,EAAO,GAClC,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC;IAQ5B,UAAU,CACd,KAAK,EAAE,QAAQ,EACf,UAAU,EAAE,eAAe,EAC3B,gBAAgB,GAAE,UAAU,EAAO,GAClC,OAAO,CAAC,IAAI,CAAC;IAchB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAwB;IAElD,qBAAqB,CACzB,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC;IAQ9B,sBAAsB,CAC1B,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC,IAAI,CAAC;IAYhB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAiB;IAE/C,eAAe,CACnB,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,UAAU,EAAE,GAAG,IAAI,CAAC;IAQzB,gBAAgB,CACpB,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,UAAU,EAAE,GACnB,OAAO,CAAC,IAAI,CAAC;IAYhB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAiB;IAE/C,cAAc,CAClB,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,UAAU,EAAE,GAAG,IAAI,CAAC;IAQzB,eAAe,CACnB,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,UAAU,EAAE,GACnB,OAAO,CAAC,IAAI,CAAC;IAYV,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAS7B"}