Add JSDoc to every public export in cursorTelemetryBuffer so the module
meets the 80% docstring-coverage threshold, and make two silent-drop
paths observable:
- endSession() now returns the number of pending batches evicted by the
maxPendingBatches cap and emits console.warn when any are dropped.
- prependBatch() defensively trims and warns if an unusual retry pattern
would push the queue past the cap (normal retry after takeNextBatch()
stays a no-op).
Tests cover both drop paths.
Address review feedback on #471 from @coderabbitai. The BMP-only
codepoint ranges missed two classes of characters:
- Non-BMP Han extensions (CJK Unified Ideographs Extension B, C, D, E, F)
such as 𠀀. A long string of Extension-B characters would still be
tokenized as a single unbreakable unit and overflow the box.
- Halfwidth Katakana (U+FF65-U+FF9F) such as カ. Same failure mode.
Switch to Unicode script property escapes (\\p{Script=Han},
\\p{Script=Hiragana}, \\p{Script=Katakana}, \\p{Script=Hangul}) which
cover these cases without enumerating ranges. tsconfig target is ES2020;
property escapes require ES2018+ so this is safe.
Verified coverage: 漢 あ ア 가 𠀀 カ all match; A and digits do not.
- Added Japanese (ja-JP) translations for common, editor, dialogs, launch, settings, shortcuts, and timeline.
- Updated translations for existing locales (en, es, fr, ko-KR, tr, zh-CN, zh-TW) to include new keys for "showInFolder", "loadingVideo", "trim", and "speed".
- Refactored VideoEditor and timeline Item components to utilize localized strings for various user interface elements and notifications.
- Enhanced user experience by providing localized messages for project loading, exporting, and timeline actions.
renderText split each line on whitespace, which works for Latin text
but leaves CJK strings as a single unbreakable token because CJK
scripts have no word-separating whitespace. Result: CJK annotation
text overflows the clipped annotation box even though the editor's
HTML preview wraps it correctly via CSS word-break: break-word.
Replace the ad-hoc whitespace split with a tokenizeForWrap helper
that emits each CJK character (Hiragana, Katakana, Hangul Syllables,
CJK Unified Ideographs + Extension A, and CJK Compatibility
Ideographs) as its own token, while keeping Latin words + whitespace
intact. The existing width-measurement wrap loop then handles CJK
per-character, matching the editor's behavior.
Closes#449
- Remove trailing comma in SUPPORTED_LOCALES that caused Locale type to
include undefined, fixing all downstream type errors
- Remove unused webcamSizePreset from useMemo dependency array
- Use parsed.toString() instead of raw url in shell.openExternal per
Electron security best practice
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The main branch has already applied the same tutorial.help key
restructuring with slightly different intermediate values.
Adopting main's version to resolve merge conflicts.
AudioProcessor.process and renderPitchPreservedTimelineAudio accepted
validatedDurationSec as optional, so the speed-aware path fell back to
media.duration when it was absent. HTMLMediaElement.duration can be
Infinity for the same MediaRecorder/Chromium Linux containers this PR
targets, which would make effectiveEnd and the playback stop checks
unreliable.
The only caller (VideoExporter.process) already threads
streamingDecoder's validatedDuration through, so make the parameter
required. Drop the media.duration fallback, the Number.isFinite guard
on readEndSec, and the two `!== undefined` checks in the tick loop.
While here:
- Document that +0.5 on readEndSec mirrors streamingDecoder.decodeAll's
read window so trim-only and speed-aware paths stay in sync.
- Replace the unreachable silent-blob fallback at the end of
renderPitchPreservedTimelineAudio with a loud invariant throw, so a
broken recorder contract surfaces instead of yielding empty audio.
The earlier NaN/Infinity guard collapsed both duration hints to 0 when
the container reported invalid values, which turned scanEndSec into
0.5s. The packet scan then read only the first half-second, scannedDuration
capped there, and validateDuration fell back to that wrong value for the
entire export — exactly the Chromium Linux case this PR is meant to fix.
Use a 24h sentinel as the read endpoint when no hint is usable. An
explicit end is still required (some containers are truncated without
one, per prior comment), but the sentinel is large enough to exceed any
realistic recording so the scan reaches real EOF.
Startup trim-skip only consulted the first active region at t=0, so
back-to-back or overlapping trims starting at zero (e.g. [0,500ms]
followed by [500ms,1000ms]) left the second region un-skipped. The
in-flight tick loop would catch it, but MediaRecorder was already
running by then, capturing up to one rAF frame of trimmed audio into
the blob and shifting the downstream timeline.
Loop findActiveTrimRegion from the advancing startPosition until no
region matches or startPosition >= effectiveEnd, bounded by
trimRegions.length for safety. Recompute initialSpeedRegion from the
final startPosition so playbackRate reflects the true start point.
mediaInfo.duration from web-demuxer can be NaN or Infinity on Chromium
Linux (same MediaRecorder bug this PR otherwise addresses). That value
flowed straight into Math.max + demuxer.read() as scanEndSec, producing
an invalid range argument and breaking the ground-truth packet scan.
Guard both mediaInfo.duration and videoStream.duration with
Number.isFinite before Math.max; validateDuration() already handled the
downstream use.
Drop redundant WebDemuxer.read() / getDecoderConfig() type casts while
here — the generics infer the chunk/config type from the media string
literal, so the `as ReadableStream<EncodedVideoChunk>` and
`as AudioDecoderConfig` are no-ops.
- validateDuration returns 0 instead of NaN when both container is
NaN and scanned is zero
- Use Math.abs for divergence check so container under-reporting is
also corrected (not just over-reporting)