Compare commits

...

2 Commits

Author SHA1 Message Date
Claude Bot
a622bf48a6 feat: Implement CompressionStream and DecompressionStream Web APIs
This implements the Compression Streams API as specified in the
Compression Streams standard. The implementation uses Node.js zlib
streams (createDeflate, createInflate, etc.) to provide the compression/
decompression functionality, wrapped in TransformStream interfaces.

The key implementation details:
- CompressionStream/DecompressionStream are implemented as TransformStreams
- Supports deflate, deflate-raw, and gzip formats
- Uses persistent event handlers on zlib streams to feed data to the
  TransformStream controller
- Waits for 'end' event in flushAlgorithm to ensure all data is emitted
  before the stream closes

Fixes #24161
2025-10-31 02:08:59 +00:00
Claude Bot
f197b4e59d Add CompressionStream and DecompressionStream Web APIs
Implements the missing CompressionStream and DecompressionStream Web APIs to support libraries like @zip.js/zip.js@2.8.8 that require these APIs.

The implementation uses Node.js zlib streams as the backing implementation and wraps them in TransformStream-based APIs following the same pattern as TextEncoderStream.

Changes:
- Add src/js/builtins/CompressionStream.ts and DecompressionStream.ts with builtin implementations
- Add C++ bindings (JSCompressionStream.* and JSDecompressionStream.*)
- Register classes in ZigGlobalObject, DOMIsoSubspaces, DOMClientIsoSubspaces, and DOMConstructors
- Add private field symbols to BunBuiltinNames.h

Supports "deflate", "deflate-raw", and "gzip" compression formats as per the Compression Streams API spec.

Fixes #24161

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-28 19:54:25 +00:00
14 changed files with 690 additions and 0 deletions

View File

@@ -3,6 +3,9 @@
"workspaces": {
"": {
"name": "bun",
"dependencies": {
"@zip.js/zip.js": "2.8.8",
},
"devDependencies": {
"@lezer/common": "^1.2.3",
"@lezer/cpp": "^1.1.3",
@@ -164,6 +167,8 @@
"@types/react": ["@types/react@19.1.10", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-EhBeSYX0Y6ye8pNebpKrwFJq7BoQ8J5SO6NlvNwwHjSj6adXJViPQrKlsyPw7hLBLvckEMO1yxeGdR82YBBlDg=="],
"@zip.js/zip.js": ["@zip.js/zip.js@2.8.8", "", {}, "sha512-v0KutehhSAuaoFAFGLp+V4+UiZ1mIxQ8vNOYMD7k9ZJaBbtQV49MYlg568oRLiuwWDg2Di58Iw3Q0ESNWR+5JA=="],
"aggregate-error": ["aggregate-error@3.1.0", "", { "dependencies": { "clean-stack": "^2.0.0", "indent-string": "^4.0.0" } }, "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA=="],
"before-after-hook": ["before-after-hook@2.2.3", "", {}, "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ=="],

View File

@@ -91,5 +91,8 @@
"machine:windows:2019": "./scripts/machine.mjs ssh --cloud=aws --arch=x64 --instance-type c7i.2xlarge --os=windows --release=2019",
"machine:freebsd": "./scripts/machine.mjs ssh --cloud=aws --arch=x64 --instance-type c7i.large --os=freebsd --release=14.3",
"sync-webkit-source": "bun ./scripts/sync-webkit-source.ts"
},
"dependencies": {
"@zip.js/zip.js": "2.8.8"
}
}

View File

@@ -126,6 +126,8 @@
#include "JSTextEncoder.h"
#include "JSTextEncoderStream.h"
#include "JSTextDecoderStream.h"
#include "JSCompressionStream.h"
#include "JSDecompressionStream.h"
#include "JSTransformStream.h"
#include "JSTransformStreamDefaultController.h"
#include "JSURLSearchParams.h"
@@ -993,6 +995,8 @@ WEBCORE_GENERATED_CONSTRUCTOR_GETTER(SubtleCrypto);
WEBCORE_GENERATED_CONSTRUCTOR_GETTER(TextEncoder);
WEBCORE_GENERATED_CONSTRUCTOR_GETTER(TextEncoderStream);
WEBCORE_GENERATED_CONSTRUCTOR_GETTER(TextDecoderStream);
WEBCORE_GENERATED_CONSTRUCTOR_GETTER(CompressionStream);
WEBCORE_GENERATED_CONSTRUCTOR_GETTER(DecompressionStream);
WEBCORE_GENERATED_CONSTRUCTOR_GETTER(TransformStream)
WEBCORE_GENERATED_CONSTRUCTOR_GETTER(TransformStreamDefaultController)
WEBCORE_GENERATED_CONSTRUCTOR_GETTER(URLSearchParams);

View File

@@ -79,6 +79,8 @@
TextDecoderStream TextDecoderStreamConstructorCallback PropertyCallback
TextEncoder TextEncoderConstructorCallback PropertyCallback
TextEncoderStream TextEncoderStreamConstructorCallback PropertyCallback
CompressionStream CompressionStreamConstructorCallback PropertyCallback
DecompressionStream DecompressionStreamConstructorCallback PropertyCallback
TransformStream TransformStreamConstructorCallback PropertyCallback
TransformStreamDefaultController TransformStreamDefaultControllerConstructorCallback PropertyCallback
URL DOMURLConstructorCallback DontEnum|PropertyCallback

View File

@@ -509,6 +509,8 @@ public:
std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForTextEncoder;
std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForTextEncoderStream;
// std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForTextEncoderStreamEncoder;
std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForCompressionStream;
std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForDecompressionStream;
// std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForTextEvent;
// std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForTransitionEvent;
// std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForTreeWalker;

View File

@@ -435,6 +435,8 @@ enum class DOMConstructorID : uint16_t {
TextEncoder,
TextEncoderStream,
TextEncoderStreamEncoder,
CompressionStream,
DecompressionStream,
TextEvent,
TransitionEvent,
TreeWalker,

View File

@@ -494,6 +494,8 @@ public:
std::unique_ptr<IsoSubspace> m_subspaceForTextEncoder;
std::unique_ptr<IsoSubspace> m_subspaceForTextEncoderStream;
// std::unique_ptr<IsoSubspace> m_subspaceForTextEncoderStreamEncoder;
std::unique_ptr<IsoSubspace> m_subspaceForCompressionStream;
std::unique_ptr<IsoSubspace> m_subspaceForDecompressionStream;
// std::unique_ptr<IsoSubspace> m_subspaceForTextEvent;
// std::unique_ptr<IsoSubspace> m_subspaceForTransitionEvent;
// std::unique_ptr<IsoSubspace> m_subspaceForTreeWalker;

View File

@@ -0,0 +1,168 @@
/*
This file is part of the WebKit open source project.
This file has been generated by generate-bindings.pl. DO NOT MODIFY!
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include "config.h"
#include "JSCompressionStream.h"
#include "ExtendedDOMClientIsoSubspaces.h"
#include "ExtendedDOMIsoSubspaces.h"
#include "JSDOMAttribute.h"
#include "JSDOMBinding.h"
#include "JSDOMBuiltinConstructor.h"
#include "JSDOMExceptionHandling.h"
#include "JSDOMGlobalObjectInlines.h"
#include "JSDOMWrapperCache.h"
// #include "CompressionStreamBuiltins.h"
#include "WebCoreJSClientData.h"
#include <JavaScriptCore/FunctionPrototype.h>
#include <JavaScriptCore/JSCInlines.h>
#include <JavaScriptCore/JSDestructibleObjectHeapCellType.h>
#include <JavaScriptCore/SlotVisitorMacros.h>
#include <JavaScriptCore/SubspaceInlines.h>
#include <wtf/GetPtr.h>
#include <wtf/PointerPreparations.h>
namespace WebCore {
using namespace JSC;
// Attributes
static JSC_DECLARE_CUSTOM_GETTER(jsCompressionStreamConstructor);
class JSCompressionStreamPrototype final : public JSC::JSNonFinalObject {
public:
using Base = JSC::JSNonFinalObject;
static JSCompressionStreamPrototype* create(JSC::VM& vm, JSDOMGlobalObject* globalObject, JSC::Structure* structure)
{
JSCompressionStreamPrototype* ptr = new (NotNull, JSC::allocateCell<JSCompressionStreamPrototype>(vm)) JSCompressionStreamPrototype(vm, globalObject, structure);
ptr->finishCreation(vm);
return ptr;
}
DECLARE_INFO;
template<typename CellType, JSC::SubspaceAccess>
static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm)
{
STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSCompressionStreamPrototype, Base);
return &vm.plainObjectSpace();
}
static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype)
{
return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), info());
}
private:
JSCompressionStreamPrototype(JSC::VM& vm, JSC::JSGlobalObject*, JSC::Structure* structure)
: JSC::JSNonFinalObject(vm, structure)
{
}
void finishCreation(JSC::VM&);
};
STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSCompressionStreamPrototype, JSCompressionStreamPrototype::Base);
using JSCompressionStreamDOMConstructor = JSDOMBuiltinConstructor<JSCompressionStream>;
template<> const ClassInfo JSCompressionStreamDOMConstructor::s_info = { "CompressionStream"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSCompressionStreamDOMConstructor) };
template<> JSValue JSCompressionStreamDOMConstructor::prototypeForStructure(JSC::VM& vm, const JSDOMGlobalObject& globalObject)
{
UNUSED_PARAM(vm);
return globalObject.functionPrototype();
}
template<> void JSCompressionStreamDOMConstructor::initializeProperties(VM& vm, JSDOMGlobalObject& globalObject)
{
putDirect(vm, vm.propertyNames->length, jsNumber(0), JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontEnum);
JSString* nameString = jsNontrivialString(vm, "CompressionStream"_s);
m_originalName.set(vm, this, nameString);
putDirect(vm, vm.propertyNames->name, nameString, JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontEnum);
putDirect(vm, vm.propertyNames->prototype, JSCompressionStream::prototype(vm, globalObject), JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontEnum | JSC::PropertyAttribute::DontDelete);
}
template<> FunctionExecutable* JSCompressionStreamDOMConstructor::initializeExecutable(VM& vm)
{
return compressionStreamInitializeCompressionStreamCodeGenerator(vm);
}
/* Hash table for prototype */
static const HashTableValue JSCompressionStreamPrototypeTableValues[] = {
{ "constructor"_s, static_cast<unsigned>(PropertyAttribute::DontEnum), NoIntrinsic, { HashTableValue::GetterSetterType, jsCompressionStreamConstructor, 0 } },
{ "readable"_s, JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::Accessor | JSC::PropertyAttribute::Builtin, NoIntrinsic, { HashTableValue::BuiltinAccessorType, compressionStreamReadableCodeGenerator, 0 } },
{ "writable"_s, JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::Accessor | JSC::PropertyAttribute::Builtin, NoIntrinsic, { HashTableValue::BuiltinAccessorType, compressionStreamWritableCodeGenerator, 0 } },
};
const ClassInfo JSCompressionStreamPrototype::s_info = { "CompressionStream"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSCompressionStreamPrototype) };
void JSCompressionStreamPrototype::finishCreation(VM& vm)
{
Base::finishCreation(vm);
reifyStaticProperties(vm, JSCompressionStream::info(), JSCompressionStreamPrototypeTableValues, *this);
JSC_TO_STRING_TAG_WITHOUT_TRANSITION();
}
const ClassInfo JSCompressionStream::s_info = { "CompressionStream"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSCompressionStream) };
JSCompressionStream::JSCompressionStream(Structure* structure, JSDOMGlobalObject& globalObject)
: JSDOMObject(structure, globalObject)
{
}
JSObject* JSCompressionStream::createPrototype(VM& vm, JSDOMGlobalObject& globalObject)
{
auto* structure = JSCompressionStreamPrototype::createStructure(vm, &globalObject, globalObject.objectPrototype());
structure->setMayBePrototype(true);
return JSCompressionStreamPrototype::create(vm, &globalObject, structure);
}
JSObject* JSCompressionStream::prototype(VM& vm, JSDOMGlobalObject& globalObject)
{
return getDOMPrototype<JSCompressionStream>(vm, globalObject);
}
JSValue JSCompressionStream::getConstructor(VM& vm, const JSGlobalObject* globalObject)
{
return getDOMConstructor<JSCompressionStreamDOMConstructor, DOMConstructorID::CompressionStream>(vm, *jsCast<const JSDOMGlobalObject*>(globalObject));
}
void JSCompressionStream::destroy(JSC::JSCell* cell)
{
JSCompressionStream* thisObject = static_cast<JSCompressionStream*>(cell);
thisObject->JSCompressionStream::~JSCompressionStream();
}
JSC_DEFINE_CUSTOM_GETTER(jsCompressionStreamConstructor, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName))
{
auto& vm = JSC::getVM(lexicalGlobalObject);
auto throwScope = DECLARE_THROW_SCOPE(vm);
auto* prototype = jsDynamicCast<JSCompressionStreamPrototype*>(JSValue::decode(thisValue));
if (!prototype) [[unlikely]]
return throwVMTypeError(lexicalGlobalObject, throwScope);
return JSValue::encode(JSCompressionStream::getConstructor(vm, prototype->globalObject()));
}
JSC::GCClient::IsoSubspace* JSCompressionStream::subspaceForImpl(JSC::VM& vm)
{
return WebCore::subspaceForImpl<JSCompressionStream, UseCustomHeapCellType::No>(
vm, [](auto& spaces) { return spaces.m_clientSubspaceForCompressionStream.get(); }, [](auto& spaces, auto&& space) { spaces.m_clientSubspaceForCompressionStream = std::forward<decltype(space)>(space); }, [](auto& spaces) { return spaces.m_subspaceForCompressionStream.get(); }, [](auto& spaces, auto&& space) { spaces.m_subspaceForCompressionStream = std::forward<decltype(space)>(space); });
}
}

View File

@@ -0,0 +1,64 @@
/*
This file is part of the WebKit open source project.
This file has been generated by generate-bindings.pl. DO NOT MODIFY!
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#pragma once
#include "JSDOMWrapper.h"
namespace WebCore {
class JSCompressionStream : public JSDOMObject {
public:
using Base = JSDOMObject;
static JSCompressionStream* create(JSC::Structure* structure, JSDOMGlobalObject* globalObject)
{
auto& vm = JSC::getVM(globalObject);
JSCompressionStream* ptr = new (NotNull, JSC::allocateCell<JSCompressionStream>(vm)) JSCompressionStream(structure, *globalObject);
ptr->finishCreation(vm);
return ptr;
}
static JSC::JSObject* createPrototype(JSC::VM&, JSDOMGlobalObject&);
static JSC::JSObject* prototype(JSC::VM&, JSDOMGlobalObject&);
static void destroy(JSC::JSCell*);
DECLARE_INFO;
static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype)
{
return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), info(), JSC::NonArray);
}
static JSC::JSValue getConstructor(JSC::VM&, const JSC::JSGlobalObject*);
template<typename, JSC::SubspaceAccess mode> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm)
{
if constexpr (mode == JSC::SubspaceAccess::Concurrently)
return nullptr;
return subspaceForImpl(vm);
}
static JSC::GCClient::IsoSubspace* subspaceForImpl(JSC::VM& vm);
protected:
JSCompressionStream(JSC::Structure*, JSDOMGlobalObject&);
DECLARE_DEFAULT_FINISH_CREATION;
};
} // namespace WebCore

View File

@@ -0,0 +1,168 @@
/*
This file is part of the WebKit open source project.
This file has been generated by generate-bindings.pl. DO NOT MODIFY!
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include "config.h"
#include "JSDecompressionStream.h"
#include "ExtendedDOMClientIsoSubspaces.h"
#include "ExtendedDOMIsoSubspaces.h"
#include "JSDOMAttribute.h"
#include "JSDOMBinding.h"
#include "JSDOMBuiltinConstructor.h"
#include "JSDOMExceptionHandling.h"
#include "JSDOMGlobalObjectInlines.h"
#include "JSDOMWrapperCache.h"
// #include "DecompressionStreamBuiltins.h"
#include "WebCoreJSClientData.h"
#include <JavaScriptCore/FunctionPrototype.h>
#include <JavaScriptCore/JSCInlines.h>
#include <JavaScriptCore/JSDestructibleObjectHeapCellType.h>
#include <JavaScriptCore/SlotVisitorMacros.h>
#include <JavaScriptCore/SubspaceInlines.h>
#include <wtf/GetPtr.h>
#include <wtf/PointerPreparations.h>
namespace WebCore {
using namespace JSC;
// Attributes
static JSC_DECLARE_CUSTOM_GETTER(jsDecompressionStreamConstructor);
class JSDecompressionStreamPrototype final : public JSC::JSNonFinalObject {
public:
using Base = JSC::JSNonFinalObject;
static JSDecompressionStreamPrototype* create(JSC::VM& vm, JSDOMGlobalObject* globalObject, JSC::Structure* structure)
{
JSDecompressionStreamPrototype* ptr = new (NotNull, JSC::allocateCell<JSDecompressionStreamPrototype>(vm)) JSDecompressionStreamPrototype(vm, globalObject, structure);
ptr->finishCreation(vm);
return ptr;
}
DECLARE_INFO;
template<typename CellType, JSC::SubspaceAccess>
static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm)
{
STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSDecompressionStreamPrototype, Base);
return &vm.plainObjectSpace();
}
static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype)
{
return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), info());
}
private:
JSDecompressionStreamPrototype(JSC::VM& vm, JSC::JSGlobalObject*, JSC::Structure* structure)
: JSC::JSNonFinalObject(vm, structure)
{
}
void finishCreation(JSC::VM&);
};
STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSDecompressionStreamPrototype, JSDecompressionStreamPrototype::Base);
using JSDecompressionStreamDOMConstructor = JSDOMBuiltinConstructor<JSDecompressionStream>;
template<> const ClassInfo JSDecompressionStreamDOMConstructor::s_info = { "DecompressionStream"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSDecompressionStreamDOMConstructor) };
template<> JSValue JSDecompressionStreamDOMConstructor::prototypeForStructure(JSC::VM& vm, const JSDOMGlobalObject& globalObject)
{
UNUSED_PARAM(vm);
return globalObject.functionPrototype();
}
template<> void JSDecompressionStreamDOMConstructor::initializeProperties(VM& vm, JSDOMGlobalObject& globalObject)
{
putDirect(vm, vm.propertyNames->length, jsNumber(0), JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontEnum);
JSString* nameString = jsNontrivialString(vm, "DecompressionStream"_s);
m_originalName.set(vm, this, nameString);
putDirect(vm, vm.propertyNames->name, nameString, JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontEnum);
putDirect(vm, vm.propertyNames->prototype, JSDecompressionStream::prototype(vm, globalObject), JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontEnum | JSC::PropertyAttribute::DontDelete);
}
template<> FunctionExecutable* JSDecompressionStreamDOMConstructor::initializeExecutable(VM& vm)
{
return decompressionStreamInitializeDecompressionStreamCodeGenerator(vm);
}
/* Hash table for prototype */
static const HashTableValue JSDecompressionStreamPrototypeTableValues[] = {
{ "constructor"_s, static_cast<unsigned>(PropertyAttribute::DontEnum), NoIntrinsic, { HashTableValue::GetterSetterType, jsDecompressionStreamConstructor, 0 } },
{ "readable"_s, JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::Accessor | JSC::PropertyAttribute::Builtin, NoIntrinsic, { HashTableValue::BuiltinAccessorType, decompressionStreamReadableCodeGenerator, 0 } },
{ "writable"_s, JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::Accessor | JSC::PropertyAttribute::Builtin, NoIntrinsic, { HashTableValue::BuiltinAccessorType, decompressionStreamWritableCodeGenerator, 0 } },
};
const ClassInfo JSDecompressionStreamPrototype::s_info = { "DecompressionStream"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSDecompressionStreamPrototype) };
void JSDecompressionStreamPrototype::finishCreation(VM& vm)
{
Base::finishCreation(vm);
reifyStaticProperties(vm, JSDecompressionStream::info(), JSDecompressionStreamPrototypeTableValues, *this);
JSC_TO_STRING_TAG_WITHOUT_TRANSITION();
}
const ClassInfo JSDecompressionStream::s_info = { "DecompressionStream"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSDecompressionStream) };
JSDecompressionStream::JSDecompressionStream(Structure* structure, JSDOMGlobalObject& globalObject)
: JSDOMObject(structure, globalObject)
{
}
JSObject* JSDecompressionStream::createPrototype(VM& vm, JSDOMGlobalObject& globalObject)
{
auto* structure = JSDecompressionStreamPrototype::createStructure(vm, &globalObject, globalObject.objectPrototype());
structure->setMayBePrototype(true);
return JSDecompressionStreamPrototype::create(vm, &globalObject, structure);
}
JSObject* JSDecompressionStream::prototype(VM& vm, JSDOMGlobalObject& globalObject)
{
return getDOMPrototype<JSDecompressionStream>(vm, globalObject);
}
JSValue JSDecompressionStream::getConstructor(VM& vm, const JSGlobalObject* globalObject)
{
return getDOMConstructor<JSDecompressionStreamDOMConstructor, DOMConstructorID::DecompressionStream>(vm, *jsCast<const JSDOMGlobalObject*>(globalObject));
}
void JSDecompressionStream::destroy(JSC::JSCell* cell)
{
JSDecompressionStream* thisObject = static_cast<JSDecompressionStream*>(cell);
thisObject->JSDecompressionStream::~JSDecompressionStream();
}
JSC_DEFINE_CUSTOM_GETTER(jsDecompressionStreamConstructor, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName))
{
auto& vm = JSC::getVM(lexicalGlobalObject);
auto throwScope = DECLARE_THROW_SCOPE(vm);
auto* prototype = jsDynamicCast<JSDecompressionStreamPrototype*>(JSValue::decode(thisValue));
if (!prototype) [[unlikely]]
return throwVMTypeError(lexicalGlobalObject, throwScope);
return JSValue::encode(JSDecompressionStream::getConstructor(vm, prototype->globalObject()));
}
JSC::GCClient::IsoSubspace* JSDecompressionStream::subspaceForImpl(JSC::VM& vm)
{
return WebCore::subspaceForImpl<JSDecompressionStream, UseCustomHeapCellType::No>(
vm, [](auto& spaces) { return spaces.m_clientSubspaceForDecompressionStream.get(); }, [](auto& spaces, auto&& space) { spaces.m_clientSubspaceForDecompressionStream = std::forward<decltype(space)>(space); }, [](auto& spaces) { return spaces.m_subspaceForDecompressionStream.get(); }, [](auto& spaces, auto&& space) { spaces.m_subspaceForDecompressionStream = std::forward<decltype(space)>(space); });
}
}

View File

@@ -0,0 +1,64 @@
/*
This file is part of the WebKit open source project.
This file has been generated by generate-bindings.pl. DO NOT MODIFY!
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#pragma once
#include "JSDOMWrapper.h"
namespace WebCore {
class JSDecompressionStream : public JSDOMObject {
public:
using Base = JSDOMObject;
static JSDecompressionStream* create(JSC::Structure* structure, JSDOMGlobalObject* globalObject)
{
auto& vm = JSC::getVM(globalObject);
JSDecompressionStream* ptr = new (NotNull, JSC::allocateCell<JSDecompressionStream>(vm)) JSDecompressionStream(structure, *globalObject);
ptr->finishCreation(vm);
return ptr;
}
static JSC::JSObject* createPrototype(JSC::VM&, JSDOMGlobalObject&);
static JSC::JSObject* prototype(JSC::VM&, JSDOMGlobalObject&);
static void destroy(JSC::JSCell*);
DECLARE_INFO;
static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype)
{
return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), info(), JSC::NonArray);
}
static JSC::JSValue getConstructor(JSC::VM&, const JSC::JSGlobalObject*);
template<typename, JSC::SubspaceAccess mode> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm)
{
if constexpr (mode == JSC::SubspaceAccess::Concurrently)
return nullptr;
return subspaceForImpl(vm);
}
static JSC::GCClient::IsoSubspace* subspaceForImpl(JSC::VM& vm);
protected:
JSDecompressionStream(JSC::Structure*, JSDOMGlobalObject&);
DECLARE_DEFAULT_FINISH_CREATION;
};
} // namespace WebCore

View File

@@ -258,6 +258,10 @@ using namespace JSC;
macro(textDecoderStreamTransform) \
macro(textEncoderStreamEncoder) \
macro(textEncoderStreamTransform) \
macro(compressionStreamTransform) \
macro(compressionStreamCompressor) \
macro(decompressionStreamTransform) \
macro(decompressionStreamDecompressor) \
macro(toClass) \
macro(toNamespacedPath) \
macro(trace) \

View File

@@ -0,0 +1,101 @@
/*
* Copyright (C) 2025 Anthropic PBC. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
export function initializeCompressionStream(format) {
// Validate format
if (format !== "deflate" && format !== "deflate-raw" && format !== "gzip") {
throw new TypeError(`The provided value '${format}' is not a valid enum value of type CompressionFormat.`);
}
const zlib = require("node:zlib");
let compressor;
// Create the appropriate compressor based on the format
if (format === "deflate") {
compressor = zlib.createDeflate();
} else if (format === "deflate-raw") {
compressor = zlib.createDeflateRaw();
} else if (format === "gzip") {
compressor = zlib.createGzip();
}
const startAlgorithm = () => {
return Promise.$resolve();
};
const transformAlgorithm = chunk => {
const comp = $getByIdDirectPrivate(this, "compressionStreamCompressor");
return new Promise((resolve, reject) => {
comp.write(chunk, err => {
if (err) reject(err);
else resolve();
});
});
};
const flushAlgorithm = () => {
const comp = $getByIdDirectPrivate(this, "compressionStreamCompressor");
return new Promise((resolve, reject) => {
comp.once("end", () => resolve());
comp.once("error", err => reject(err));
comp.end();
});
};
const transform = $createTransformStream(startAlgorithm, transformAlgorithm, flushAlgorithm);
$putByIdDirectPrivate(this, "compressionStreamTransform", transform);
$putByIdDirectPrivate(this, "compressionStreamCompressor", compressor);
// Set up persistent data handler to feed compressed data to the transform stream
compressor.on("data", chunk => {
const transformStream = $getByIdDirectPrivate(this, "compressionStreamTransform");
const controller = $getByIdDirectPrivate(transformStream, "controller");
$transformStreamDefaultControllerEnqueue(controller, chunk);
});
compressor.on("error", err => {
const transformStream = $getByIdDirectPrivate(this, "compressionStreamTransform");
const controller = $getByIdDirectPrivate(transformStream, "controller");
$transformStreamDefaultControllerError(controller, err);
});
return this;
}
$getter;
export function readable() {
const transform = $getByIdDirectPrivate(this, "compressionStreamTransform");
if (!transform) throw $ERR_INVALID_THIS("CompressionStream");
return $getByIdDirectPrivate(transform, "readable");
}
$getter;
export function writable() {
const transform = $getByIdDirectPrivate(this, "compressionStreamTransform");
if (!transform) throw $ERR_INVALID_THIS("CompressionStream");
return $getByIdDirectPrivate(transform, "writable");
}

View File

@@ -0,0 +1,101 @@
/*
* Copyright (C) 2025 Anthropic PBC. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
export function initializeDecompressionStream(format) {
// Validate format
if (format !== "deflate" && format !== "deflate-raw" && format !== "gzip") {
throw new TypeError(`The provided value '${format}' is not a valid enum value of type CompressionFormat.`);
}
const zlib = require("node:zlib");
let decompressor;
// Create the appropriate decompressor based on the format
if (format === "deflate") {
decompressor = zlib.createInflate();
} else if (format === "deflate-raw") {
decompressor = zlib.createInflateRaw();
} else if (format === "gzip") {
decompressor = zlib.createGunzip();
}
const startAlgorithm = () => {
return Promise.$resolve();
};
const transformAlgorithm = chunk => {
const decomp = $getByIdDirectPrivate(this, "decompressionStreamDecompressor");
return new Promise((resolve, reject) => {
decomp.write(chunk, err => {
if (err) reject(err);
else resolve();
});
});
};
const flushAlgorithm = () => {
const decomp = $getByIdDirectPrivate(this, "decompressionStreamDecompressor");
return new Promise((resolve, reject) => {
decomp.once("end", () => resolve());
decomp.once("error", err => reject(err));
decomp.end();
});
};
const transform = $createTransformStream(startAlgorithm, transformAlgorithm, flushAlgorithm);
$putByIdDirectPrivate(this, "decompressionStreamTransform", transform);
$putByIdDirectPrivate(this, "decompressionStreamDecompressor", decompressor);
// Set up persistent data handler to feed decompressed data to the transform stream
decompressor.on("data", chunk => {
const transformStream = $getByIdDirectPrivate(this, "decompressionStreamTransform");
const controller = $getByIdDirectPrivate(transformStream, "controller");
$transformStreamDefaultControllerEnqueue(controller, chunk);
});
decompressor.on("error", err => {
const transformStream = $getByIdDirectPrivate(this, "decompressionStreamTransform");
const controller = $getByIdDirectPrivate(transformStream, "controller");
$transformStreamDefaultControllerError(controller, err);
});
return this;
}
$getter;
export function readable() {
const transform = $getByIdDirectPrivate(this, "decompressionStreamTransform");
if (!transform) throw $ERR_INVALID_THIS("DecompressionStream");
return $getByIdDirectPrivate(transform, "readable");
}
$getter;
export function writable() {
const transform = $getByIdDirectPrivate(this, "decompressionStreamTransform");
if (!transform) throw $ERR_INVALID_THIS("DecompressionStream");
return $getByIdDirectPrivate(transform, "writable");
}