#include "events.h" #include "blob.h" #include "messagechannel.h" namespace workerd::api { MessageEvent::MessageEvent(jsg::Lock& js, const jsg::JsValue& data, kj::String lastEventId, kj::Maybe> source, kj::Maybe urlForOrigin) : Event("message"), data(jsg::JsRef(js, data)), lastEventId(kj::mv(lastEventId)), maybeSource(kj::mv(source)), maybeOrigin(urlForOrigin.map([](auto& url) { return url.getOrigin(); })) {} MessageEvent::MessageEvent(jsg::Lock& js, jsg::JsRef data, kj::String lastEventId, kj::Maybe> source, kj::Maybe urlForOrigin) : Event("message"), data(kj::mv(data)), lastEventId(kj::mv(lastEventId)), maybeSource(kj::mv(source)), maybeOrigin(urlForOrigin.map([](auto& url) { return url.getOrigin(); })) {} MessageEvent::MessageEvent(jsg::Lock& js, kj::String type, const jsg::JsValue& data, kj::String lastEventId, kj::Maybe> source, kj::Maybe urlForOrigin) : Event(kj::mv(type)), data(jsg::JsRef(js, kj::mv(data))), lastEventId(kj::mv(lastEventId)), maybeSource(kj::mv(source)), maybeOrigin(urlForOrigin.map([](auto& url) { return url.getOrigin(); })) {} MessageEvent::MessageEvent(jsg::Lock& js, kj::String type, kj::OneOf, jsg::Ref> data, kj::String lastEventId, kj::Maybe> source, kj::Maybe urlForOrigin) : Event(kj::mv(type)), data(kj::mv(data)), lastEventId(kj::mv(lastEventId)), maybeSource(kj::mv(source)), maybeOrigin(urlForOrigin.map([](auto& url) { return url.getOrigin(); })) {} jsg::Ref MessageEvent::constructor( jsg::Lock& js, kj::String type, Initializer initializer) { return js.alloc(js, kj::mv(type), kj::mv(initializer.data)); } kj::OneOf> MessageEvent::getData(jsg::Lock& js) { KJ_SWITCH_ONEOF(data) { KJ_CASE_ONEOF(jsValue, jsg::JsRef) { return jsValue.getHandle(js); } KJ_CASE_ONEOF(blob, jsg::Ref) { return blob.addRef(); } } KJ_UNREACHABLE; } kj::Maybe> MessageEvent::getOrigin() { return maybeOrigin.map([](auto& a) -> kj::ArrayPtr { return a.asPtr(); }); } kj::StringPtr MessageEvent::getLastEventId() { return lastEventId; } // Per the spec, the source of a MessageEvent is one of a MessagePort, // ServiceWorker, WindowProxy, etc. The only one of these we actually // support is MessagePort, return that if its set or null if not. kj::Maybe> MessageEvent::getSource() { return maybeSource.map([](auto& port) mutable -> jsg::Ref { return port.addRef(); }); } kj::ArrayPtr> MessageEvent::getPorts() { // We don't support transferring MessagePorts in MessageEvent // for now, so we return an empty array. Later we might support // this. return nullptr; } void MessageEvent::visitForMemoryInfo(jsg::MemoryTracker& tracker) const { KJ_SWITCH_ONEOF(data) { KJ_CASE_ONEOF(jsValue, jsg::JsRef) { tracker.trackField("data", jsValue); } KJ_CASE_ONEOF(blob, jsg::Ref) { tracker.trackField("data", blob); } } tracker.trackField("source", maybeSource); } void MessageEvent::visitForGc(jsg::GcVisitor& visitor) { KJ_SWITCH_ONEOF(data) { KJ_CASE_ONEOF(jsValue, jsg::JsRef) { visitor.visit(jsValue); } KJ_CASE_ONEOF(blob, jsg::Ref) { visitor.visit(blob); } } visitor.visit(maybeSource); } // ====================================================================================== namespace { const kj::StringPtr kDefaultErrorEventName = "error"_kj; } // namespace ErrorEvent::ErrorEvent(ErrorEventInit init): Event(kDefaultErrorEventName), init(kj::mv(init)) {} ErrorEvent::ErrorEvent(kj::String type, ErrorEventInit init) : Event(kj::mv(type)), init(kj::mv(init)) {} ErrorEvent::ErrorEvent(jsg::Lock& js, jsg::JsValue error) : ErrorEvent(ErrorEventInit{.error = jsg::JsRef(js, error)}) {} jsg::Ref ErrorEvent::constructor( jsg::Lock& js, kj::String type, jsg::Optional init) { return js.alloc(kj::mv(type), kj::mv(init).orDefault({})); } kj::StringPtr ErrorEvent::getFilename() { return init.filename.orDefault(nullptr); } kj::StringPtr ErrorEvent::getMessage() { return init.message.orDefault(nullptr); } int ErrorEvent::getLineno() { return init.lineno.orDefault(0); } int ErrorEvent::getColno() { return init.colno.orDefault(0); } jsg::JsValue ErrorEvent::getError(jsg::Lock& js) { KJ_IF_SOME(error, init.error) { return error.getHandle(js); } else { return js.undefined(); } } void ErrorEvent::visitForMemoryInfo(jsg::MemoryTracker& tracker) const { tracker.trackField("message", init.message); tracker.trackField("filename", init.filename); tracker.trackField("error", init.error); } void ErrorEvent::visitForGc(jsg::GcVisitor& visitor) { visitor.visit(init.error); } // ====================================================================================== namespace { constexpr kj::StringPtr kUnhandledRejectionEventName = "unhandledrejection"_kj; constexpr kj::StringPtr kRejectionHandledEventName = "rejectionhandled"_kj; constexpr kj::StringPtr getPromiseRejectionEventName(v8::PromiseRejectEvent type) { switch (type) { case v8::PromiseRejectEvent::kPromiseRejectWithNoHandler: return kUnhandledRejectionEventName; case v8::PromiseRejectEvent::kPromiseHandlerAddedAfterReject: return kRejectionHandledEventName; default: // Events are not emitted for the other reject types. KJ_UNREACHABLE; } } } // namespace PromiseRejectionEvent::PromiseRejectionEvent( v8::PromiseRejectEvent type, jsg::V8Ref promise, jsg::Value reason) : Event(getPromiseRejectionEventName(type)), promise(kj::mv(promise)), reason(kj::mv(reason)) {} } // namespace workerd::api