QVAC-18524 fix: avoid Node-only Buffer in RN duplex RPC path#1915
Merged
Conversation
ishanvohra2
previously approved these changes
May 6, 2026
Tier-based Approval Status |
lauripiisang
reviewed
May 6, 2026
simon-iribarren
previously approved these changes
May 6, 2026
lauripiisang
previously approved these changes
May 7, 2026
Contributor
|
|
On RN/Hermes the bare-rpc duplex stream polyfill calls `Buffer.from(chunk, encoding)` for string writes, which throws `Property 'Buffer' doesn't exist` because Hermes has no global `Buffer`. This blocks every transcribeStream() call on iOS/Android. - expo-rpc-client: pre-encode the JSON payload to Uint8Array via TextEncoder so the polyfill's binary branch is taken everywhere. - rpc-client: drop Buffer.from in the profiled response generator, widen DuplexWritable/DuplexReadable to accept Uint8Array/string. - transcribe API + transcription schemas: widen all TranscribeStream*Session.write(audioChunk) signatures from `Buffer` to `Buffer | Uint8Array` so RN callers can pass Uint8Array directly. - tests-qvac shared runner: stop wrapping Uint8Array slices in Buffer.from before writing. - tests-qvac mobile consumer: skip transcribe-stream-events-* on iOS under the existing QVAC-18460 TODO (same native Silero/Whisper crash path as transcription-*). - tests-qvac.mdc: add a one-liner rule about avoiding Node-only globals in shared/mobile test code. Co-authored-by: Cursor <cursoragent@cursor.com>
Replace the `Buffer | Uint8Array` parameter unions on `TranscribeStream*Session.write()` and `DuplexWritable.write()` with plain `Uint8Array`. Node `Buffer` extends `Uint8Array`, so existing `Buffer`-passing callers keep typechecking, but the public surface no longer mentions a Node-only type. Per review feedback from @lauripiisang.
NamelsKing
approved these changes
May 8, 2026
lauripiisang
approved these changes
May 8, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Note: be concise and prefer bullet points.
🎯 What problem does this PR solve?
transcribeStream()call from@qvac/sdkthrowsReferenceError: Property 'Buffer' doesn't existon the very first write.transcribe-stream-events-*e2e tests (added in QVAC-17282 feat[api]: expose whisper VAD and end-of-turn events in transcribeStream #1848 / QVAC-17282) cannot run on mobile at all today.Buffer.from(chunk, encoding)for string writes, but Hermes has no globalBuffer— sorequestStream.write(payload, "utf-8")blows up before any audio data reaches the worker.📝 How does it solve it?
Uint8ArrayviaTextEncoderincreateDuplexSessionso the polyfill's binary branch is taken on every runtime.Buffer.from(string)from the profiled duplex response generator and yield strings directly — downstreamchunk.toString()consumers work for bothBufferandstring.TranscribeStream*Session.write(audioChunk)signatures fromBuffertoBuffer | Uint8Arrayso RN callers can pass binary slices directly instead of polyfillingBuffer.Uint8Arrayslices inBuffer.from(...)inside the shared transcribe-stream test runner.transcribe-stream-events-*on iOS under the existingTODO(QVAC-18460)since the underlying native Silero/Whisper crash is identical to the one already blockingtranscription-*on iOS — flipping both skips will be a single follow-up commit when 18460 lands.tests-qvac.mdc: no Node-only globals intests/shared/ortests/mobile/.Type Changes
Additive type widening — all existing
Buffer-based callers compile and behave identically.Also widened on
TranscribeStreamMetadataSessionandTranscribeStreamConversationSession, and on theDuplexWritable/DuplexReadableinternal RPC types.Example RN/Bare-friendly usage:
🧪 How was it tested?
bun run lint+tsc --noEmitonpackages/sdk— green.npx qvac-test run:local:ios --filter transcribe-stream-events:ReferenceError: Property 'Buffer' doesn't exist~70 ms after test start.transcribe-stream-events-*continue to pass —Buffercallers compile and execute unchanged thanks to the union widening.