- Revert next.config.ts: remove hardcoded Cloudflare tunnel URL from
allowedDevOrigins (dev artifact, not part of the voice upload fix).
- Rewrite voice transcribe tests to use mock request objects instead of
real Request/FormData/Blob instances that cause formData() to hang
indefinitely in vitest's Node environment. All 9 tests now pass.
Made-with: Cursor
* fix(voice): enforce upload size limit before buffering (issue #7)
The previous implementation called request.formData() and audio.arrayBuffer()
before checking MAX_VOICE_UPLOAD_BYTES, meaning oversized uploads were fully
buffered into memory before rejection — a DoS/OOM risk.
Changes:
- Check Content-Length header early and return 413 if it exceeds the limit,
preventing any request body from being read into memory for oversized uploads
- Export MAX_VOICE_UPLOAD_BYTES for use in tests
- Switch from instanceof File to duck-typing (checking .arrayBuffer method)
to avoid cross-realm failures in jsdom test environments
- Return HTTP 413 Payload Too Large for oversized uploads (was 400 before)
- Retain a secondary post-buffer size check to catch missing/spoofed
Content-Length headers
Tests added (tests/unit/voiceTranscribe.test.ts):
- Content-Length exceeding limit → 413 before any buffering
- Content-Length at exactly the limit → proceeds normally
- No Content-Length header, small file → proceeds normally (200)
- No Content-Length header, oversized body → 413 after buffering
- Missing audio field → 400
- Empty audio file (0 bytes) → 400
- Malformed Content-Length header → falls through gracefully
Fixes: issue #7
* fix(issue-7): account for multipart overhead in Content-Length early check
The early Content-Length guard was comparing total multipart request size
against MAX_VOICE_UPLOAD_BYTES, but multipart/form-data includes boundary
and header overhead (~200-500 bytes). A valid file at exactly the 20 MB
limit was being rejected with 413.
Fix: add a 1 KB MULTIPART_OVERHEAD_ALLOWANCE to the early check threshold.
The post-buffer check remains the authoritative limit and measures actual
audio bytes. Updated tests to reflect the corrected early-check boundary.
---------
Co-authored-by: Neo (subagent) <neo@openclaw.local>
Co-authored-by: Neo <neo@openclaw.ai>