Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
0f5e332
webstreams: native CompressionStream/DecompressionStream/TextEncoderS…
robobun Aug 1, 2026
a7f304b
[autofix.ci] apply automated fixes
autofix-ci[bot] Aug 1, 2026
f420b4f
CompressionStream: accept string chunks and report ERR_STREAM_NULL_VA…
robobun Aug 1, 2026
7ff7cdd
ci: retrigger gate (previous run polluted by stash leftovers)
robobun Aug 1, 2026
6197c4e
webstreams: JSCompressionStream/JSDecompressionStream/JSTextEncoderSt…
robobun Aug 1, 2026
9d11774
setUpNativeTransformStream: readableHighWaterMark=1 so the first writ…
robobun Aug 2, 2026
4cb3373
webstreams: native-sink output path for byte-producing TransformStrea…
robobun Aug 2, 2026
95e47f1
webstreams: utf-8 TextDecoderStream fast path, TextEncoderStream nati…
robobun Aug 2, 2026
c97b498
[autofix.ci] apply automated fixes
autofix-ci[bot] Aug 2, 2026
8ead549
address review: detach before sink onClose end(), drop scratch borrow…
robobun Aug 2, 2026
06e4324
TextDecoderStream: store encoding label on the cell (.encoding was fl…
robobun Aug 2, 2026
b212f15
native-sink backpressure: detect pending-JSPromise (JSController sink…
robobun Aug 2, 2026
1a08658
test: CompressionStream -> native HTTP sink backpressure (pull source…
robobun Aug 2, 2026
4c4f76b
test: request-body -> DecompressionStream backpressure; req.clone().t…
robobun Aug 2, 2026
e455f6c
CompressionStream: offload >128KB chunks to WorkPool via AnyTaskJob (…
robobun Aug 2, 2026
1be5fe0
test: cap compression backpressure TOTAL at 200 and gate streams.test…
robobun Aug 2, 2026
e7d0bd1
split JSCompressionStream.cpp into JSCompressionStream / JSDecompress…
robobun Aug 2, 2026
8c455c0
CompressionStream async codec: dedicated WorkTask variant, single Str…
robobun Aug 2, 2026
72daee1
test: cover Bun__CompressionStream__deliverAsync native-sink arm (>12…
robobun Aug 2, 2026
58451a8
[autofix.ci] apply automated fixes
autofix-ci[bot] Aug 2, 2026
92b9b1a
test: TextEncoderStream -> TextDecoderStream -> TextEncoderStream cha…
robobun Aug 2, 2026
28f7309
Merge branch 'main' into claude/farm/cc1a3bf2/native-compression-text…
robobun Aug 4, 2026
e7dd41c
TransformStream.prototype.{readable,writable}: exact classInfo brand …
robobun Aug 4, 2026
97aca89
remove dead TextEncoderStreamEncoder JS wrapper class; fix clippy und…
robobun Aug 4, 2026
420ca97
delete code made dead by the native {De,}CompressionStream / Text{En,…
robobun Aug 4, 2026
d071d7d
Merge remote-tracking branch 'origin/main' into claude/farm/cc1a3bf2/…
robobun Aug 4, 2026
be8658e
Delete JSSink::<T>::js_write_bytes (callers removed in codegen)
robobun Aug 4, 2026
ed5be66
codegen: drop JSSink__writeBytes dispatcher + per-sink thunks
robobun Aug 4, 2026
1965780
Reroute CompressionStreamCoder__transformInto via sink_handle_from_id
robobun Aug 4, 2026
2a3f684
Add Http/Https/H3Response/ArrayBuffer variants to SinkHandle
robobun Aug 4, 2026
059cd31
Reroute TextEncoderStreamEncoder IntoSink via sink_handle_from_id
robobun Aug 4, 2026
1091cbe
Swap JSSink__writeBytes -> Bun__NativeTransformSink__writeBytes in de…
robobun Aug 4, 2026
36b1aaa
Forward-declare Bun__NativeTransformSink__writeBytes in WebStreamsInt…
robobun Aug 4, 2026
6d41079
Update JSTransformStream.h comment to reference SinkHandle dispatcher
robobun Aug 4, 2026
8433435
rsisSinkWrite: route via Bun__NativeTransformSink__writeBytes
robobun Aug 4, 2026
229e306
Sink.rs: add sink_handle_from_id + Bun__NativeTransformSink__writeBytes
robobun Aug 4, 2026
1781642
native transform streams: route sink write through SinkHandle; drop b…
robobun Aug 4, 2026
96284b6
Drop redundant extern decl; WebStreamsInternals.h provides it
robobun Aug 4, 2026
1cf217c
Sink.rs: allow not_unsafe_ptr_arg_deref on writeBytes FFI
robobun Aug 4, 2026
2869e0d
JS{De,}CompressionStream: drop write-only m_format field
robobun Aug 4, 2026
bb790d2
TextEncoderStreamEncoder: early-return on SinkHandle::None
robobun Aug 4, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions src/codegen/generate-jssink.ts
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ function header() {
static size_t memoryCost(void* sinkPtr);

${controller}(JSC::VM& vm, JSC::Structure* structure, void* sinkPtr, uintptr_t onDestroy)
: Base(vm, structure, sinkPtr, onDestroy)
: Base(vm, structure, sinkPtr, SinkID::${name}, onDestroy)
{
}

Expand Down Expand Up @@ -208,19 +208,24 @@ class JSReadableSinkControllerBase : public JSC::JSDestructibleObject {
public:
using Base = JSC::JSDestructibleObject;

DECLARE_INFO;

void* wrapped() const { return m_sinkPtr; }
SinkID sinkId() const { return m_sinkId; }

void* m_sinkPtr;
SinkID m_sinkId;
mutable WriteBarrier<JSC::JSObject> m_onPull;
mutable WriteBarrier<JSC::JSObject> m_onClose;
mutable JSC::Weak<JSObject> m_weakReadableStream;
uintptr_t m_onDestroy { 0 };

protected:
JSReadableSinkControllerBase(JSC::VM& vm, JSC::Structure* structure, void* sinkPtr, uintptr_t onDestroy)
JSReadableSinkControllerBase(JSC::VM& vm, JSC::Structure* structure, void* sinkPtr, SinkID sinkId, uintptr_t onDestroy)
: Base(vm, structure)
{
m_sinkPtr = sinkPtr;
m_sinkId = sinkId;
m_onDestroy = onDestroy;
}
};
Expand Down Expand Up @@ -301,6 +306,8 @@ using namespace JSC;

${classes.map(name => `extern "C" size_t ${name}__memoryCost(void* sinkPtr);`).join("\n")}
${classes.map(name => `extern "C" void ${name}__controllerDetached(void* sinkPtr, JSC::EncodedJSValue controllerValue);`).join("\n")}

const ClassInfo JSReadableSinkControllerBase::s_info = { "ReadableSinkController"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSReadableSinkControllerBase) };
`;
var templ = head;

Expand Down
1 change: 1 addition & 0 deletions src/event_loop/ConcurrentTask.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ pub mod task_tag {
NativeBrotli,
NativeZlib,
NativeZstd,
CompressionStreamCoderTask,
Open,
PasswordHashResult,
PasswordVerifyResult,
Expand Down
3 changes: 0 additions & 3 deletions src/js/builtins.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -410,8 +410,6 @@ declare function $streamErrored(): TODO;
declare function $streamReadable(): TODO;
declare function $streamWritable(): TODO;
declare function $syscall(): TODO;
declare function $textDecoderStreamDecoder(): TODO;
declare function $textEncoderStreamEncoder(): TODO;
declare function $toNamespacedPath(): TODO;
declare function $url(): TODO;
declare function $view(): TODO;
Expand Down Expand Up @@ -627,7 +625,6 @@ declare function $ERR_STREAM_CANNOT_PIPE(): Error;
declare function $ERR_STREAM_WRITE_AFTER_END(): Error;
declare function $ERR_STREAM_UNSHIFT_AFTER_END_EVENT(): Error;
declare function $ERR_STREAM_PUSH_AFTER_EOF(): Error;
declare function $ERR_TRAILING_JUNK_AFTER_STREAM_END(): TypeError;
declare function $ERR_STREAM_UNABLE_TO_PIPE(): Error;
declare function $ERR_ILLEGAL_CONSTRUCTOR(): TypeError;
declare function $ERR_SERVER_ALREADY_LISTEN(): Error;
Expand Down
2 changes: 0 additions & 2 deletions src/js/builtins/BunBuiltinNames.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ using namespace JSC;
macro(ReadableStreamDefaultController) \
macro(ReadableStreamDefaultReader) \
macro(SQL) \
macro(TextEncoderStreamEncoder) \
macro(TransformStream) \
macro(TransformStreamDefaultController) \
macro(WritableStream) \
Expand Down Expand Up @@ -80,7 +79,6 @@ using namespace JSC;
macro(disturbed) \
macro(domain) \
macro(drain) \
macro(encode) \
macro(encoding) \
macro(end) \
macro(errno) \
Expand Down
33 changes: 0 additions & 33 deletions src/js/builtins/CompressionStream.ts

This file was deleted.

35 changes: 0 additions & 35 deletions src/js/builtins/DecompressionStream.ts

This file was deleted.

74 changes: 15 additions & 59 deletions src/js/internal/webstreams_adapters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,6 @@ const SafePromisePrototypeFinally = $Promise.prototype.finally;

const constants_zlib = $processBindingConstants.zlib;

const kValidateChunk = Symbol("kValidateChunk");
const kDestroyOnSyncError = Symbol("kDestroyOnSyncError");

function tryTransferToNativeReadable(stream, options) {
const ptr = stream.$bunNativePtr;
if (!ptr || ptr === -1) {
Expand Down Expand Up @@ -191,7 +188,7 @@ function handleKnownInternalErrors(cause: Error | null): Error | null {

const noop = () => {};

function newWritableStreamFromStreamWritable(streamWritable, options = kEmptyObject) {
function newWritableStreamFromStreamWritable(streamWritable) {
// Not using the internal/streams/utils isWritableNodeStream utility
// here because it will return false if streamWritable is a Duplex
// whose writable option is false. For a Duplex that is not writable,
Expand Down Expand Up @@ -268,34 +265,20 @@ function newWritableStreamFromStreamWritable(streamWritable, options = kEmptyObj
},

write(chunk) {
try {
options[kValidateChunk]?.(chunk);
if (!streamWritable.writableObjectMode && isAnyArrayBuffer(chunk)) {
chunk = new Uint8Array(chunk);
}
const needDrainBefore = streamWritable.writableNeedDrain;
if (needDrainBefore || !streamWritable.write(chunk)) {
backpressurePromise = PromiseWithResolvers();
// write() may set writableNeedDrain; the post-write value is
// what decides whether we resolve immediately.
if (!streamWritable.writableNeedDrain) {
backpressurePromise.resolve();
}
return SafePromisePrototypeFinally.$call(backpressurePromise.promise, () => {
backpressurePromise = undefined;
});
}
} catch (error) {
// When the kDestroyOnSyncError flag is set (e.g. for
// CompressionStream), a sync throw must also destroy the
// stream so the readable side is errored too. Without this
// the readable side hangs forever. This replicates the
// TransformStream semantics: error both sides on any throw
// in the transform path.
if (options[kDestroyOnSyncError]) {
destroyer(streamWritable, error);
if (!streamWritable.writableObjectMode && isAnyArrayBuffer(chunk)) {
chunk = new Uint8Array(chunk);
}
const needDrainBefore = streamWritable.writableNeedDrain;
if (needDrainBefore || !streamWritable.write(chunk)) {
backpressurePromise = PromiseWithResolvers();
// write() may set writableNeedDrain; the post-write value is
// what decides whether we resolve immediately.
Comment thread
robobun marked this conversation as resolved.
if (!streamWritable.writableNeedDrain) {
backpressurePromise.resolve();
}
throw error;
return SafePromisePrototypeFinally.$call(backpressurePromise.promise, () => {
backpressurePromise = undefined;
});
}
},

Expand Down Expand Up @@ -634,15 +617,7 @@ function newReadableWritablePairFromDuplex(duplex, options = kEmptyObject) {
return { readable, writable };
}

const writableOptions = {
__proto__: null,
[kValidateChunk]: options[kValidateChunk],
[kDestroyOnSyncError]: options[kDestroyOnSyncError],
};

const writable = isWritable(duplex)
? newWritableStreamFromStreamWritable(duplex, writableOptions)
: new WritableStream();
const writable = isWritable(duplex) ? newWritableStreamFromStreamWritable(duplex) : new WritableStream();

if (!isWritable(duplex)) writable.close();

Expand Down Expand Up @@ -840,31 +815,12 @@ function newStreamDuplexFromReadableWritablePair(pair = kEmptyObject, options =
return duplex;
}

// Shared by CompressionStream and DecompressionStream: per the Compression
// Streams spec, chunks must be BufferSource (ArrayBuffer or ArrayBufferView
// not backed by SharedArrayBuffer), and an invalid chunk must error both
// sides of the pair synchronously.
function newBufferSourceTransformPairFromDuplex(duplex) {
const { isArrayBufferView, isSharedArrayBuffer } = require("node:util/types");
return newReadableWritablePairFromDuplex(duplex, {
[kValidateChunk]: function validateBufferSourceChunk(chunk) {
if (isSharedArrayBuffer(isArrayBufferView(chunk) ? chunk.buffer : chunk)) {
throw $ERR_INVALID_ARG_TYPE("chunk", ["ArrayBuffer", "Buffer", "TypedArray", "DataView"], chunk);
}
},
[kDestroyOnSyncError]: true,
});
}

export default {
newWritableStreamFromStreamWritable,
newReadableStreamFromStreamReadable,
newStreamWritableFromWritableStream,
newStreamReadableFromReadableStream,
newReadableWritablePairFromDuplex,
newStreamDuplexFromReadableWritablePair,
newBufferSourceTransformPairFromDuplex,
kValidateChunk,
kDestroyOnSyncError,
_ReadableFromWeb: ReadableFromWeb,
};
9 changes: 0 additions & 9 deletions src/js/node/zlib.ts
Original file line number Diff line number Diff line change
Expand Up @@ -197,8 +197,6 @@ function ZlibBase(opts, mode, handle, { flush, finishFlush, fullFlush }) {
this._defaultFullFlushFlag = fullFlush;
this._info = opts && opts.info;
this._maxOutputLength = maxOutputLength;

this._rejectGarbageAfterEnd = opts?.rejectGarbageAfterEnd === true;
}
$toClass(ZlibBase, "ZlibBase", Transform);

Expand Down Expand Up @@ -509,13 +507,6 @@ function processCallback() {
// This applies to streams where we don't check data past the end of
// what was consumed; that is, everything except Gunzip/Unzip.

if (self._rejectGarbageAfterEnd) {
const err = $ERR_TRAILING_JUNK_AFTER_STREAM_END();
self.destroy(err);
this.cb(err);
return;
}

self.push(null);
}

Expand Down
Loading
Loading