diff --git a/cmake/sources/CxxSources.txt b/cmake/sources/CxxSources.txt index 5a404a2e05..f3b02426bb 100644 --- a/cmake/sources/CxxSources.txt +++ b/cmake/sources/CxxSources.txt @@ -64,6 +64,7 @@ src/bun.js/bindings/InternalModuleRegistry.cpp src/bun.js/bindings/IPC.cpp src/bun.js/bindings/isBuiltinModule.cpp src/bun.js/bindings/JS2Native.cpp +src/bun.js/bindings/JSBakeResponse.cpp src/bun.js/bindings/JSBigIntBinding.cpp src/bun.js/bindings/JSBuffer.cpp src/bun.js/bindings/JSBufferEncodingType.cpp diff --git a/src/bun.js/bindings/JSBakeResponse.cpp b/src/bun.js/bindings/JSBakeResponse.cpp new file mode 100644 index 0000000000..f65c14cc27 --- /dev/null +++ b/src/bun.js/bindings/JSBakeResponse.cpp @@ -0,0 +1,376 @@ +#include "root.h" +#include "headers.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "JSBakeResponse.h" +#include "ZigGlobalObject.h" +#include "ZigGeneratedClasses.h" + +#if !OS(WINDOWS) +#define JSC_CALLCONV "C" +#else +#define JSC_CALLCONV "C" SYSV_ABI +#endif + +namespace Bun { + +static JSC_DECLARE_HOST_FUNCTION(jsBakeResponseConstructorRender); +static JSC_DECLARE_HOST_FUNCTION(jsBakeResponseConstructorRedirect); + +static JSC_DECLARE_CUSTOM_GETTER(jsBakeResponsePrototypeGetSymbolFor); +static JSC_DECLARE_CUSTOM_GETTER(jsBakeResponsePrototypeGetType); +static JSC_DECLARE_CUSTOM_GETTER(jsBakeResponsePrototypeGetKey); +static JSC_DECLARE_CUSTOM_GETTER(jsBakeResponsePrototypeGetProps); +static JSC_DECLARE_CUSTOM_GETTER(jsBakeResponsePrototypeGetStore); +static JSC_DECLARE_CUSTOM_GETTER(jsBakeResponsePrototypeGetOwner); +static JSC_DECLARE_CUSTOM_GETTER(jsBakeResponsePrototypeGetDebugInfo); +static JSC_DECLARE_CUSTOM_GETTER(jsBakeResponsePrototypeGetDebugStack); +static JSC_DECLARE_CUSTOM_GETTER(jsBakeResponsePrototypeGetDebugTask); + +extern JSC_CALLCONV void* JSC_HOST_CALL_ATTRIBUTES ResponseClass__constructForSSR(JSC::JSGlobalObject*, JSC::CallFrame*, JSC::EncodedJSValue); +extern "C" SYSV_ABI JSC::EncodedJSValue JSC_HOST_CALL_ATTRIBUTES ResponseClass__constructError(JSC::JSGlobalObject*, JSC::CallFrame*) SYSV_ABI; +extern "C" SYSV_ABI JSC::EncodedJSValue JSC_HOST_CALL_ATTRIBUTES ResponseClass__constructJSON(JSC::JSGlobalObject*, JSC::CallFrame*) SYSV_ABI; +extern JSC_CALLCONV size_t Response__estimatedSize(void* ptr); + +static const HashTableValue JSBakeResponseConstructorTableValues[] = { + { "error"_s, static_cast(JSC::PropertyAttribute::Function | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::NativeFunctionType, ResponseClass__constructError, 0 } }, + { "json"_s, static_cast(JSC::PropertyAttribute::Function | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::NativeFunctionType, ResponseClass__constructJSON, 0 } }, + + { "render"_s, static_cast(JSC::PropertyAttribute::Function | JSC::PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::NativeFunctionType, jsBakeResponseConstructorRender, 1 } }, + { "redirect"_s, static_cast(JSC::PropertyAttribute::Function | JSC::PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::NativeFunctionType, jsBakeResponseConstructorRedirect, 1 } }, + +}; + +static const HashTableValue JSBakeResponsePrototypeTableValues[] = { + { "$$typeof"_s, static_cast(JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::GetterSetterType, jsBakeResponsePrototypeGetSymbolFor, nullptr } }, + { "type"_s, static_cast(JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::GetterSetterType, jsBakeResponsePrototypeGetType, nullptr } }, + { "key"_s, static_cast(JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::GetterSetterType, jsBakeResponsePrototypeGetKey, nullptr } }, + { "props"_s, static_cast(JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::GetterSetterType, jsBakeResponsePrototypeGetProps, nullptr } }, + { "_store"_s, static_cast(JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::GetterSetterType, jsBakeResponsePrototypeGetStore, nullptr } }, + { "_owner"_s, static_cast(JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::GetterSetterType, jsBakeResponsePrototypeGetOwner, nullptr } }, + { "_debugInfo"_s, static_cast(JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::GetterSetterType, jsBakeResponsePrototypeGetDebugInfo, nullptr } }, + { "_debugStack"_s, static_cast(JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::GetterSetterType, jsBakeResponsePrototypeGetDebugStack, nullptr } }, + { "_debugTask"_s, static_cast(JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::GetterSetterType, jsBakeResponsePrototypeGetDebugTask, nullptr } } +}; + +JSBakeResponse* JSBakeResponse::create(JSC::VM& vm, JSC::Structure* structure, void* ctx) +{ + JSBakeResponse* ptr = new (NotNull, JSC::allocateCell(vm)) JSBakeResponse(vm, structure, ctx); + ptr->finishCreation(vm); + return ptr; +} + +JSC::Structure* JSBakeResponse::createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) +{ + return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(static_cast(0b11101110), StructureFlags), info()); +} + +JSC::GCClient::IsoSubspace* JSBakeResponse::subspaceForImpl(JSC::VM& vm) +{ + return WebCore::subspaceForImpl( + vm, + [](auto& spaces) { return spaces.m_clientSubspaceForBakeResponse.get(); }, + [](auto& spaces, auto&& space) { spaces.m_clientSubspaceForBakeResponse = std::forward(space); }, + [](auto& spaces) { return spaces.m_subspaceForBakeResponse.get(); }, + [](auto& spaces, auto&& space) { spaces.m_subspaceForBakeResponse = std::forward(space); }); +} + +JSBakeResponse::JSBakeResponse(JSC::VM& vm, JSC::Structure* structure, void* sinkPtr) + : Base(vm, structure, sinkPtr) +{ +} + +void JSBakeResponse::finishCreation(JSC::VM& vm) +{ + Base::finishCreation(vm); +} + +template +void JSBakeResponse::visitChildrenImpl(JSCell* cell, Visitor& visitor) +{ + JSBakeResponse* thisObject = jsCast(cell); + Base::visitChildren(thisObject, visitor); +} + +DEFINE_VISIT_CHILDREN(JSBakeResponse); + +class JSBakeResponsePrototype final : public JSNonFinalObject { +public: + using Base = JSNonFinalObject; + + static JSBakeResponsePrototype* create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure) + { + auto* ptr = new (NotNull, JSC::allocateCell(vm)) JSBakeResponsePrototype(vm, structure); + ptr->finishCreation(vm, globalObject); + return ptr; + } + + static Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) + { + auto* structure = Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), info(), NonArray); + structure->setMayBePrototype(true); + return structure; + } + + DECLARE_INFO; + + template + static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) + { + STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSBakeResponsePrototype, Base); + return &vm.plainObjectSpace(); + } + +private: + JSBakeResponsePrototype(JSC::VM& vm, JSC::Structure* structure) + : Base(vm, structure) + { + } + + void finishCreation(JSC::VM& vm, JSC::JSGlobalObject* globalObject) + { + Base::finishCreation(vm); + reifyStaticProperties(vm, JSBakeResponse::info(), JSBakeResponsePrototypeTableValues, *this); + JSC_TO_STRING_TAG_WITHOUT_TRANSITION(); + } +}; + +JSC_DECLARE_HOST_FUNCTION(callBakeResponse); +JSC_DECLARE_HOST_FUNCTION(constructBakeResponse); + +class JSBakeResponseConstructor final : public JSC::InternalFunction { +public: + using Base = JSC::InternalFunction; + static constexpr unsigned StructureFlags = Base::StructureFlags; + + static JSBakeResponseConstructor* create(JSC::VM& vm, JSC::Structure* structure, JSC::JSObject* prototype) + { + JSBakeResponseConstructor* constructor = new (NotNull, JSC::allocateCell(vm)) JSBakeResponseConstructor(vm, structure); + constructor->finishCreation(vm, prototype); + return constructor; + } + + // DECLARE_INFO; + DECLARE_EXPORT_INFO; + + // Must be defined for each specialization class. + static JSC::EncodedJSValue JSC_HOST_CALL_ATTRIBUTES construct(JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame) + { + Zig::GlobalObject* globalObject = defaultGlobalObject(lexicalGlobalObject); + JSC::VM& vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + JSObject* newTarget = asObject(callFrame->newTarget()); + auto* constructor = globalObject->JSResponseConstructor(); + Structure* structure = globalObject->JSBakeResponseStructure(); + if (constructor != newTarget) [[unlikely]] { + auto* functionGlobalObject = defaultGlobalObject( + // ShadowRealm functions belong to a different global object. + getFunctionRealm(globalObject, newTarget)); + RETURN_IF_EXCEPTION(scope, {}); + structure = InternalFunction::createSubclassStructure(globalObject, newTarget, functionGlobalObject->JSBakeResponseStructure()); + RETURN_IF_EXCEPTION(scope, {}); + } + + JSBakeResponse* instance = JSBakeResponse::create(vm, structure, nullptr); + + void* ptr = ResponseClass__constructForSSR(globalObject, callFrame, JSValue::encode(instance)); + if (scope.exception()) [[unlikely]] { + ASSERT_WITH_MESSAGE(!ptr, "Memory leak detected: new SSRResponse() allocated memory without checking for exceptions."); + return JSValue::encode(JSC::jsUndefined()); + } + + instance->m_ctx = ptr; + + auto size = Response__estimatedSize(ptr); + vm.heap.reportExtraMemoryAllocated(instance, size); + + auto value = JSValue::encode(instance); + RELEASE_AND_RETURN(scope, value); + } + + static JSC::EncodedJSValue JSC_HOST_CALL_ATTRIBUTES call(JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame) + { + Zig::GlobalObject* globalObject = reinterpret_cast(lexicalGlobalObject); + JSC::VM& vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + Structure* structure = globalObject->JSBakeResponseStructure(); + JSBakeResponse* instance = JSBakeResponse::create(vm, structure, nullptr); + + void* ptr = ResponseClass__constructForSSR(globalObject, callFrame, JSValue::encode(instance)); + if (scope.exception()) [[unlikely]] { + ASSERT_WITH_MESSAGE(!ptr, "Memory leak detected: new SSRResponse() allocated memory without checking for exceptions."); + return JSValue::encode(JSC::jsUndefined()); + } + + instance->m_ctx = ptr; + + RETURN_IF_EXCEPTION(scope, {}); + + auto size = Response__estimatedSize(ptr); + vm.heap.reportExtraMemoryAllocated(instance, size); + + RELEASE_AND_RETURN(scope, JSValue::encode(instance)); + } + + template + static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) + { + return &vm.internalFunctionSpace(); + } + + static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) + { + return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::InternalFunctionType, StructureFlags), info()); + } + +private: + JSBakeResponseConstructor(JSC::VM& vm, JSC::Structure* structure) + : Base(vm, structure, JSBakeResponseConstructor::call, JSBakeResponseConstructor::construct) + { + } + + void finishCreation(JSC::VM& vm, JSC::JSObject* prototype) + { + Base::finishCreation(vm, 0, "SSRResponse"_s); + putDirectWithoutTransition(vm, vm.propertyNames->prototype, prototype, JSC::PropertyAttribute::DontEnum | JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::ReadOnly); + reifyStaticProperties(vm, info(), JSBakeResponseConstructorTableValues, *this); + } +}; + +const JSC::ClassInfo JSBakeResponsePrototype::s_info = { "SSRResponse"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSBakeResponsePrototype) }; +const JSC::ClassInfo JSBakeResponse::s_info = { "SSRResponse"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSBakeResponse) }; +const JSC::ClassInfo JSBakeResponseConstructor::s_info = { "SSRResponse"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSBakeResponseConstructor) }; + +JSC_DEFINE_CUSTOM_GETTER(jsBakeResponsePrototypeGetSymbolFor, (JSC::JSGlobalObject * globalObject, JSC::EncodedJSValue thisValue, JSC::PropertyName)) +{ + JSBakeResponse* response = jsDynamicCast(JSValue::decode(thisValue)); + if (!response) + return JSValue::encode(jsUndefined()); + + auto& vm = globalObject->vm(); + auto symbolKey = "react.transitional.element"_s; + return JSValue::encode(JSC::Symbol::create(vm, vm.symbolRegistry().symbolForKey(symbolKey))); +} + +JSC_DEFINE_CUSTOM_GETTER(jsBakeResponsePrototypeGetType, (JSC::JSGlobalObject * globalObject, JSC::EncodedJSValue thisValue, JSC::PropertyName)) +{ + JSBakeResponse* response = jsDynamicCast(JSValue::decode(thisValue)); + if (!response) + return JSValue::encode(jsUndefined()); + + printf("m_ctx: %p\n", response->m_ctx); + + // auto& type = response->type(); + // auto typeValue = type.get(); + // return JSValue::encode(typeValue); + String wtfstring = "Hello"_s; + auto* jsstring = JSC::jsString(globalObject->vm(), wtfstring); + return JSValue::encode(jsstring); +} + +JSC_DEFINE_CUSTOM_GETTER(jsBakeResponsePrototypeGetKey, (JSC::JSGlobalObject * globalObject, JSC::EncodedJSValue thisValue, JSC::PropertyName)) +{ + return JSValue::encode(jsNull()); +} + +JSC_DEFINE_CUSTOM_GETTER(jsBakeResponsePrototypeGetProps, (JSC::JSGlobalObject * globalObject, JSC::EncodedJSValue thisValue, JSC::PropertyName)) +{ + JSBakeResponse* response = jsDynamicCast(JSValue::decode(thisValue)); + if (!response) + return JSValue::encode(jsUndefined()); + + return JSValue::encode(JSC::constructEmptyObject(globalObject)); +} + +JSC_DEFINE_CUSTOM_GETTER(jsBakeResponsePrototypeGetStore, (JSC::JSGlobalObject * globalObject, JSC::EncodedJSValue thisValue, JSC::PropertyName)) +{ + JSBakeResponse* response = jsDynamicCast(JSValue::decode(thisValue)); + if (!response) + return JSValue::encode(jsUndefined()); + + auto& vm = globalObject->vm(); + JSObject* storeObject = JSC::constructEmptyObject(globalObject); + auto validatedIdent = JSC::Identifier::fromString(vm, "validated"_s); + storeObject->putDirect(vm, validatedIdent, jsNumber(0), 0); + return JSValue::encode(storeObject); +} + +JSC_DEFINE_CUSTOM_GETTER(jsBakeResponsePrototypeGetOwner, (JSC::JSGlobalObject * globalObject, JSC::EncodedJSValue thisValue, JSC::PropertyName)) +{ + return JSValue::encode(jsNull()); +} + +JSC_DEFINE_CUSTOM_GETTER(jsBakeResponsePrototypeGetDebugInfo, (JSC::JSGlobalObject * globalObject, JSC::EncodedJSValue thisValue, JSC::PropertyName)) +{ + return JSValue::encode(jsNull()); +} + +JSC_DEFINE_CUSTOM_GETTER(jsBakeResponsePrototypeGetDebugStack, (JSC::JSGlobalObject * globalObject, JSC::EncodedJSValue thisValue, JSC::PropertyName)) +{ + return JSValue::encode(jsNull()); +} + +JSC_DEFINE_CUSTOM_GETTER(jsBakeResponsePrototypeGetDebugTask, (JSC::JSGlobalObject * globalObject, JSC::EncodedJSValue thisValue, JSC::PropertyName)) +{ + return JSValue::encode(jsNull()); +} + +JSC_DEFINE_HOST_FUNCTION(jsBakeResponseConstructorRender, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame)) +{ + return JSValue::encode(jsUndefined()); +} + +JSC_DEFINE_HOST_FUNCTION(jsBakeResponseConstructorRedirect, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame)) +{ + return JSValue::encode(jsUndefined()); +} + +JSC_DEFINE_HOST_FUNCTION(callBakeResponse, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame)) +{ + auto& vm = globalObject->vm(); + auto throwScope = DECLARE_THROW_SCOPE(vm); + throwScope.throwException(globalObject, createTypeError(globalObject, "BakeResponse constructor cannot be called as a function"_s)); + return JSValue::encode(jsUndefined()); +} + +JSC_DEFINE_HOST_FUNCTION(constructBakeResponse, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame)) +{ + auto& vm = globalObject->vm(); + auto* zigGlobalObject = defaultGlobalObject(globalObject); + + auto* structure = createJSBakeResponseStructure(vm, zigGlobalObject); + + return JSValue::encode(JSBakeResponse::create(vm, structure, nullptr)); +} + +void setupJSBakeResponseClassStructure(JSC::LazyClassStructure::Initializer& init) +{ + auto* zigGlobal = reinterpret_cast(init.global); + auto* prototypeStructure = JSBakeResponsePrototype::createStructure(init.vm, init.global, zigGlobal->JSResponsePrototype()); + auto* prototype = JSBakeResponsePrototype::create(init.vm, init.global, prototypeStructure); + + auto* constructorStructure = JSBakeResponseConstructor::createStructure(init.vm, init.global, init.global->functionPrototype()); + auto* constructor = JSBakeResponseConstructor::create(init.vm, constructorStructure, prototype); + + auto* structure = JSBakeResponse::createStructure(init.vm, init.global, prototype); + init.setPrototype(prototype); + init.setStructure(structure); + init.setConstructor(constructor); +} + +Structure* createJSBakeResponseStructure(JSC::VM& vm, Zig::GlobalObject* globalObject) +{ + return globalObject->JSBakeResponseStructure(); +} + +} // namespace Bun diff --git a/src/bun.js/bindings/JSBakeResponse.h b/src/bun.js/bindings/JSBakeResponse.h new file mode 100644 index 0000000000..1e971bae8b --- /dev/null +++ b/src/bun.js/bindings/JSBakeResponse.h @@ -0,0 +1,45 @@ +#pragma once + +#include "JSCookieMap.h" +#include "root.h" +#include "ZigGeneratedClasses.h" + +namespace Bun { +using namespace JSC; +using namespace WebCore; + +class JSBakeResponse : public JSResponse { +public: + using Base = JSResponse; + + static JSBakeResponse* create(JSC::VM& vm, JSC::Structure* structure, void* ctx); + static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype); + + // JSC::Strong& type() { return m_type; } + + template + static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) + { + if (mode == JSC::SubspaceAccess::Concurrently) { + return nullptr; + } + + return subspaceForImpl(vm); + } + + static JSC::GCClient::IsoSubspace* subspaceForImpl(JSC::VM& vm); + + DECLARE_VISIT_CHILDREN; + DECLARE_INFO; + +private: + JSBakeResponse(JSC::VM& vm, JSC::Structure* structure, void* sinkPtr); + void finishCreation(JSC::VM& vm); + + // JSC::Strong m_type; +}; + +JSC::Structure* createJSBakeResponseStructure(JSC::VM&, Zig::GlobalObject*); +void setupJSBakeResponseClassStructure(JSC::LazyClassStructure::Initializer& init); + +} // namespace Bun diff --git a/src/bun.js/bindings/ZigGlobalObject.cpp b/src/bun.js/bindings/ZigGlobalObject.cpp index a0bcf876fa..5872540983 100644 --- a/src/bun.js/bindings/ZigGlobalObject.cpp +++ b/src/bun.js/bindings/ZigGlobalObject.cpp @@ -164,6 +164,7 @@ #include "JSPerformanceResourceTiming.h" #include "JSPerformanceTiming.h" #include "JSX509Certificate.h" +#include "JSBakeResponse.h" #include "JSSign.h" #include "JSVerify.h" #include "JSHmac.h" @@ -3365,6 +3366,11 @@ void GlobalObject::finishCreation(VM& vm) init.setConstructor(constructor); }); + m_JSBakeResponseClassStructure.initLater( + [](LazyClassStructure::Initializer& init) { + Bun::setupJSBakeResponseClassStructure(init); + }); + m_JSNetworkSinkClassStructure.initLater( [](LazyClassStructure::Initializer& init) { auto* prototype = createJSSinkPrototype(init.vm, init.global, WebCore::SinkID::NetworkSink); diff --git a/src/bun.js/bindings/ZigGlobalObject.h b/src/bun.js/bindings/ZigGlobalObject.h index 545f9bdd32..c5c932c6f6 100644 --- a/src/bun.js/bindings/ZigGlobalObject.h +++ b/src/bun.js/bindings/ZigGlobalObject.h @@ -234,6 +234,10 @@ public: JSC::JSValue HTTPSResponseSinkPrototype() const { return m_JSHTTPSResponseSinkClassStructure.prototypeInitializedOnMainThread(this); } JSC::JSValue JSReadableHTTPSResponseSinkControllerPrototype() const { return m_JSHTTPSResponseControllerPrototype.getInitializedOnMainThread(this); } + JSC::Structure* JSBakeResponseStructure() const { return m_JSBakeResponseClassStructure.getInitializedOnMainThread(this); } + JSC::JSObject* JSBakeResponseConstructor() { return m_JSBakeResponseClassStructure.constructorInitializedOnMainThread(this); } + JSC::JSValue JSBakeResponsePrototype() const { return m_JSBakeResponseClassStructure.prototypeInitializedOnMainThread(this); } + JSC::Structure* NetworkSinkStructure() const { return m_JSNetworkSinkClassStructure.getInitializedOnMainThread(this); } JSC::JSObject* NetworkSink() { return m_JSNetworkSinkClassStructure.constructorInitializedOnMainThread(this); } JSC::JSValue NetworkSinkPrototype() const { return m_JSNetworkSinkClassStructure.prototypeInitializedOnMainThread(this); } @@ -527,6 +531,7 @@ public: V(private, LazyClassStructure, m_JSFileSinkClassStructure) \ V(private, LazyClassStructure, m_JSHTTPResponseSinkClassStructure) \ V(private, LazyClassStructure, m_JSHTTPSResponseSinkClassStructure) \ + V(public, LazyClassStructure, m_JSBakeResponseClassStructure) \ V(private, LazyClassStructure, m_JSNetworkSinkClassStructure) \ \ V(private, LazyClassStructure, m_JSStringDecoderClassStructure) \ diff --git a/src/bun.js/bindings/ZigGlobalObject.lut.txt b/src/bun.js/bindings/ZigGlobalObject.lut.txt index 49b22f1412..b70c4aa828 100644 --- a/src/bun.js/bindings/ZigGlobalObject.lut.txt +++ b/src/bun.js/bindings/ZigGlobalObject.lut.txt @@ -41,6 +41,7 @@ ResolveError GlobalObject::m_JSResolveMessage ClassStructure ResolveMessage GlobalObject::m_JSResolveMessage ClassStructure Response GlobalObject::m_JSResponse ClassStructure + SSRResponse GlobalObject::m_JSBakeResponseClassStructure ClassStructure TextDecoder GlobalObject::m_JSTextDecoder ClassStructure AbortController AbortControllerConstructorCallback PropertyCallback diff --git a/src/bun.js/bindings/webcore/DOMClientIsoSubspaces.h b/src/bun.js/bindings/webcore/DOMClientIsoSubspaces.h index 44063bfc74..ce662148a5 100644 --- a/src/bun.js/bindings/webcore/DOMClientIsoSubspaces.h +++ b/src/bun.js/bindings/webcore/DOMClientIsoSubspaces.h @@ -947,6 +947,7 @@ public: std::unique_ptr m_clientSubspaceForJSPrivateKeyObject; std::unique_ptr m_clientSubspaceForServerRouteList; std::unique_ptr m_clientSubspaceForBunRequest; + std::unique_ptr m_clientSubspaceForBakeResponse; std::unique_ptr m_clientSubspaceForJSConnectionsList; std::unique_ptr m_clientSubspaceForJSHTTPParser; diff --git a/src/bun.js/bindings/webcore/DOMIsoSubspaces.h b/src/bun.js/bindings/webcore/DOMIsoSubspaces.h index ee4b3c2147..cce908c751 100644 --- a/src/bun.js/bindings/webcore/DOMIsoSubspaces.h +++ b/src/bun.js/bindings/webcore/DOMIsoSubspaces.h @@ -942,6 +942,7 @@ public: std::unique_ptr m_subspaceForJSHash; std::unique_ptr m_subspaceForServerRouteList; std::unique_ptr m_subspaceForBunRequest; + std::unique_ptr m_subspaceForBakeResponse; std::unique_ptr m_subspaceForJSDiffieHellman; std::unique_ptr m_subspaceForJSDiffieHellmanGroup; std::unique_ptr m_subspaceForJSECDH; diff --git a/src/bun.js/webcore/Response.zig b/src/bun.js/webcore/Response.zig index 3a06ff5994..d801cd65a8 100644 --- a/src/bun.js/webcore/Response.zig +++ b/src/bun.js/webcore/Response.zig @@ -30,8 +30,6 @@ redirected: bool = false, /// In the server we use a flag response_protected to protect/unprotect the response ref_count: u32 = 1, -is_jsx: bool = false, - // We must report a consistent value for this reported_estimated_size: usize = 0, @@ -626,9 +624,30 @@ pub fn constructError( } pub fn constructor(globalThis: *jsc.JSGlobalObject, callframe: *jsc.CallFrame, this_value: jsc.JSValue) bun.JSError!*Response { + return constructorImpl(globalThis, callframe, this_value, false); +} + +pub fn ResponseClass__constructForSSR(globalObject: *jsc.JSGlobalObject, callFrame: *jsc.CallFrame, thisValue: jsc.JSValue) callconv(jsc.conv) ?*anyopaque { + return @as(*Response, Response.constructor(globalObject, callFrame, thisValue) catch |err| switch (err) { + error.JSError => return null, + error.OutOfMemory => { + globalObject.throwOutOfMemory() catch {}; + return null; + }, + }); +} + +comptime { + @export(&ResponseClass__constructForSSR, .{ .name = "ResponseClass__constructForSSR" }); +} + +pub fn constructorForSSR(globalThis: *jsc.JSGlobalObject, callframe: *jsc.CallFrame, this_value: jsc.JSValue) bun.JSError!*Response { + return constructorImpl(globalThis, callframe, this_value); +} + +pub fn constructorImpl(globalThis: *jsc.JSGlobalObject, callframe: *jsc.CallFrame, this_value: jsc.JSValue, bake_ssr_response_enabled: bool) bun.JSError!*Response { var arguments = callframe.argumentsAsArray(2); - var is_jsx = false; if (!arguments[0].isUndefinedOrNull() and arguments[0].isObject()) { if (arguments[0].as(Blob)) |blob| { if (blob.isS3()) { @@ -664,21 +683,21 @@ pub fn constructor(globalThis: *jsc.JSGlobalObject, callframe: *jsc.CallFrame, t // Special case for bake: allow `return new Response( ... , { ... }` // inside of a react component - if (globalThis.allowJSXInResponseConstructor()) { - const arg = arguments[0]; - // Check if it's a JSX element (object with $$typeof) - if (try arg.isJSXElement(globalThis)) { - const vm = globalThis.bunVM(); - if (vm.dev_server_async_local_storage.get()) |async_local_storage| { - try assertStreamingDisabled(globalThis, async_local_storage, "new Response(, { ... })"); - } + if (bake_ssr_response_enabled and globalThis.allowJSXInResponseConstructor()) { + _ = this_value; + // const arg = arguments[0]; + // // Check if it's a JSX element (object with $$typeof) + // if (try arg.isJSXElement(globalThis)) { + // const vm = globalThis.bunVM(); + // if (vm.dev_server_async_local_storage.get()) |async_local_storage| { + // try assertStreamingDisabled(globalThis, async_local_storage, "new Response(, { ... })"); + // } - // Pass the response options (arguments[1]) to transformToReactElement - // so it can store them for later use when the component is rendered - const responseOptions = if (arguments[1].isObject()) arguments[1] else .js_undefined; - try JSValue.transformToReactElementWithOptions(this_value, arg, responseOptions, globalThis); - is_jsx = true; - } + // // Pass the response options (arguments[1]) to transformToReactElement + // // so it can store them for later use when the component is rendered + // const responseOptions = if (arguments[1].isObject()) arguments[1] else .js_undefined; + // try JSValue.transformToReactElementWithOptions(this_value, arg, responseOptions, globalThis); + // } } } var init: Init = (brk: { @@ -719,7 +738,6 @@ pub fn constructor(globalThis: *jsc.JSGlobalObject, callframe: *jsc.CallFrame, t var response = bun.new(Response, Response{ .body = body, .init = init, - .is_jsx = is_jsx, }); if (response.body.value == .Blob and diff --git a/src/bun.js/webcore/response.classes.ts b/src/bun.js/webcore/response.classes.ts index 424c5e8273..9b948bc120 100644 --- a/src/bun.js/webcore/response.classes.ts +++ b/src/bun.js/webcore/response.classes.ts @@ -69,6 +69,7 @@ export default [ name: "Response", construct: true, finalize: true, + final: false, JSType: "0b11101110", configurable: false, estimatedSize: true,