feat(01-03): implement offscreen recorder ring buffer and codec strict-mode

- Add src/offscreen/recorder.ts (214 lines) — Phase 01 source of truth
  owning getDisplayMedia capture, MediaRecorder lifecycle, in-memory ring
  buffer with WebM header retention + 30 s age trim, codec strict-mode
  (D-20), and track.onended cleanup.
- Add src/offscreen/index.html — crxjs-managed bundle entry referencing
  ./recorder.ts.
- Add OffscreenLogger class to src/shared/logger.ts (uses ...args:
  unknown[] for strict-mode hygiene; legacy Logger / ContentLogger keep
  ...args: any[] per project provenance). Bundled into this commit
  because recorder.ts cannot typecheck without the import (Rule 3 —
  blocking dependency).
- Pre-stage D-13 restart-segments fallback as commented skeleton at
  bottom of recorder.ts so Plan 07's fallback path needs no re-plan.
- Defensive bootstrap (typeof chrome guard) so the pure ring-buffer +
  codec tests can import the module without stubbing the full chrome
  surface (Rule 3 — Plan 02 ring-buffer test does not stub chrome).

Flips Plan 02's RED tests to GREEN:
- tests/offscreen/ring-buffer.test.ts — 4 tests passing
- tests/offscreen/codec-check.test.ts — 2 tests passing

Handshake test also passes (single OFFSCREEN_READY emission); port
reconnect test stays RED until Plan 04 wires the reconnect loop.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-15 17:34:00 +02:00
parent edc605d475
commit fff1aea592
3 changed files with 252 additions and 0 deletions

View File

@@ -48,4 +48,32 @@ export class ContentLogger {
error(...args: any[]) {
this.logWithLevel('error', ...args);
}
}
// Логгер для Offscreen Document
// Note: uses `...args: unknown[]` (strict-mode hygiene) vs Logger / ContentLogger
// which retain the legacy `...args: any[]` — see plan 01-03 style_divergence_note.
export class OffscreenLogger {
private context: string;
constructor(context: string) {
this.context = context;
}
private logWithLevel(level: 'log' | 'warn' | 'error', ...args: unknown[]) {
const timestamp = new Date().toISOString();
console[level](`[OS:${this.context}] ${timestamp}`, ...args);
}
log(...args: unknown[]) {
this.logWithLevel('log', ...args);
}
warn(...args: unknown[]) {
this.logWithLevel('warn', ...args);
}
error(...args: unknown[]) {
this.logWithLevel('error', ...args);
}
}