diff --git a/packages/react-native/ReactCommon/cxxreact/Instance.cpp b/packages/react-native/ReactCommon/cxxreact/Instance.cpp index f6120eb76bd..e282ac8cbe6 100644 --- a/packages/react-native/ReactCommon/cxxreact/Instance.cpp +++ b/packages/react-native/ReactCommon/cxxreact/Instance.cpp @@ -317,8 +317,9 @@ void Instance::JSCallInvoker::scheduleAsync( } std::unique_ptr Instance::createRuntimeAgent( - jsinspector_modern::FrontendChannel frontendChannel) { - return nativeToJsBridge_->createRuntimeAgent(frontendChannel); + jsinspector_modern::FrontendChannel frontendChannel, + jsinspector_modern::SessionState& sessionState) { + return nativeToJsBridge_->createRuntimeAgent(frontendChannel, sessionState); } } // namespace facebook::react diff --git a/packages/react-native/ReactCommon/cxxreact/Instance.h b/packages/react-native/ReactCommon/cxxreact/Instance.h index 747ed4524e2..5b070997a34 100644 --- a/packages/react-native/ReactCommon/cxxreact/Instance.h +++ b/packages/react-native/ReactCommon/cxxreact/Instance.h @@ -153,7 +153,8 @@ class RN_EXPORT Instance : private jsinspector_modern::InstanceTargetDelegate { // From InstanceTargetDelegate std::unique_ptr createRuntimeAgent( - jsinspector_modern::FrontendChannel frontendChannel) override; + jsinspector_modern::FrontendChannel channel, + jsinspector_modern::SessionState& sessionState) override; std::shared_ptr callback_; std::shared_ptr nativeToJsBridge_; diff --git a/packages/react-native/ReactCommon/cxxreact/JSExecutor.cpp b/packages/react-native/ReactCommon/cxxreact/JSExecutor.cpp index 1989bb951f6..0cca0a7ab62 100644 --- a/packages/react-native/ReactCommon/cxxreact/JSExecutor.cpp +++ b/packages/react-native/ReactCommon/cxxreact/JSExecutor.cpp @@ -36,8 +36,10 @@ double JSExecutor::performanceNow() { std::unique_ptr JSExecutor::createRuntimeAgent( - jsinspector_modern::FrontendChannel frontendChannel) { + jsinspector_modern::FrontendChannel frontendChannel, + jsinspector_modern::SessionState& sessionState) { (void)frontendChannel; + (void)sessionState; return nullptr; } diff --git a/packages/react-native/ReactCommon/cxxreact/JSExecutor.h b/packages/react-native/ReactCommon/cxxreact/JSExecutor.h index 3fdb5f495c3..aed4ffb892e 100644 --- a/packages/react-native/ReactCommon/cxxreact/JSExecutor.h +++ b/packages/react-native/ReactCommon/cxxreact/JSExecutor.h @@ -13,7 +13,7 @@ #include #include #include -#include +#include #ifndef RN_EXPORT #define RN_EXPORT __attribute__((visibility("default"))) @@ -144,7 +144,8 @@ class RN_EXPORT JSExecutor { * Create a RuntimeAgent that can be used to debug the JS VM instance. */ virtual std::unique_ptr createRuntimeAgent( - jsinspector_modern::FrontendChannel frontendChannel); + jsinspector_modern::FrontendChannel frontendChannel, + jsinspector_modern::SessionState& sessionState); }; } // namespace facebook::react diff --git a/packages/react-native/ReactCommon/cxxreact/NativeToJsBridge.cpp b/packages/react-native/ReactCommon/cxxreact/NativeToJsBridge.cpp index c9f7b17063a..a8859d5ac87 100644 --- a/packages/react-native/ReactCommon/cxxreact/NativeToJsBridge.cpp +++ b/packages/react-native/ReactCommon/cxxreact/NativeToJsBridge.cpp @@ -345,8 +345,10 @@ NativeToJsBridge::getDecoratedNativeMethodCallInvoker( std::unique_ptr NativeToJsBridge::createRuntimeAgent( - jsinspector_modern::FrontendChannel frontendChannel) { - auto agent = m_executor->createRuntimeAgent(std::move(frontendChannel)); + jsinspector_modern::FrontendChannel frontendChannel, + jsinspector_modern::SessionState& sessionState) { + auto agent = + m_executor->createRuntimeAgent(std::move(frontendChannel), sessionState); return agent; } diff --git a/packages/react-native/ReactCommon/cxxreact/NativeToJsBridge.h b/packages/react-native/ReactCommon/cxxreact/NativeToJsBridge.h index d7d949b5f67..a28039e6794 100644 --- a/packages/react-native/ReactCommon/cxxreact/NativeToJsBridge.h +++ b/packages/react-native/ReactCommon/cxxreact/NativeToJsBridge.h @@ -15,7 +15,7 @@ #include #include #include -#include +#include namespace folly { struct dynamic; @@ -112,7 +112,8 @@ class NativeToJsBridge { * instance. */ virtual std::unique_ptr createRuntimeAgent( - jsinspector_modern::FrontendChannel frontendChannel); + jsinspector_modern::FrontendChannel frontendChannel, + jsinspector_modern::SessionState& sessionState); private: // This is used to avoid a race condition where a proxyCallback gets queued diff --git a/packages/react-native/ReactCommon/jsinspector-modern/InstanceTarget.cpp b/packages/react-native/ReactCommon/jsinspector-modern/InstanceTarget.cpp index 246baaf346f..25fda576b47 100644 --- a/packages/react-native/ReactCommon/jsinspector-modern/InstanceTarget.cpp +++ b/packages/react-native/ReactCommon/jsinspector-modern/InstanceTarget.cpp @@ -6,6 +6,7 @@ */ #include "InstanceAgent.h" +#include "SessionState.h" #include @@ -19,8 +20,9 @@ InstanceTarget::InstanceTarget(InstanceTargetDelegate& delegate) InstanceTargetDelegate::~InstanceTargetDelegate() {} std::unique_ptr InstanceTarget::createAgent( - FrontendChannel channel) { - auto runtimeAgent = delegate_.createRuntimeAgent(channel); + FrontendChannel channel, + SessionState& sessionState) { + auto runtimeAgent = delegate_.createRuntimeAgent(channel, sessionState); return std::make_unique( channel, *this, std::move(runtimeAgent)); } diff --git a/packages/react-native/ReactCommon/jsinspector-modern/InstanceTarget.h b/packages/react-native/ReactCommon/jsinspector-modern/InstanceTarget.h index 3f50756e70a..07e3f35c6d1 100644 --- a/packages/react-native/ReactCommon/jsinspector-modern/InstanceTarget.h +++ b/packages/react-native/ReactCommon/jsinspector-modern/InstanceTarget.h @@ -7,6 +7,8 @@ #pragma once +#include "SessionState.h" + #include #include @@ -41,7 +43,8 @@ class InstanceTargetDelegate { * debugging. */ virtual std::unique_ptr createRuntimeAgent( - FrontendChannel channel) = 0; + FrontendChannel channel, + SessionState& sessionState) = 0; virtual ~InstanceTargetDelegate(); }; @@ -62,7 +65,9 @@ class InstanceTarget { InstanceTarget& operator=(const InstanceTarget&) = delete; InstanceTarget& operator=(InstanceTarget&&) = delete; - std::unique_ptr createAgent(FrontendChannel channel); + std::unique_ptr createAgent( + FrontendChannel channel, + SessionState& sessionState); private: InstanceTargetDelegate& delegate_; diff --git a/packages/react-native/ReactCommon/jsinspector-modern/PageAgent.cpp b/packages/react-native/ReactCommon/jsinspector-modern/PageAgent.cpp index 5223ee719c4..fdaa060f895 100644 --- a/packages/react-native/ReactCommon/jsinspector-modern/PageAgent.cpp +++ b/packages/react-native/ReactCommon/jsinspector-modern/PageAgent.cpp @@ -32,16 +32,22 @@ static constexpr auto kModernCDPBackendNotice = PageAgent::PageAgent( FrontendChannel frontendChannel, PageTargetController& targetController, - PageTarget::SessionMetadata sessionMetadata) + PageTarget::SessionMetadata sessionMetadata, + SessionState& sessionState) : frontendChannel_(frontendChannel), targetController_(targetController), - sessionMetadata_(std::move(sessionMetadata)) {} + sessionMetadata_(std::move(sessionMetadata)), + sessionState_(sessionState) {} void PageAgent::handleRequest(const cdp::PreparsedRequest& req) { + bool shouldSendOKResponse = false; + bool isFinishedHandlingRequest = false; + + // Domain enable/disable requests: write to state (because we're the top-level + // Agent in the Session), trigger any side effects, and decide whether we are + // finished handling the request (or need to delegate to the InstanceAgent). if (req.method == "Log.enable") { - // Send an "OK" response. - frontendChannel_( - folly::toJson(folly::dynamic::object("id", req.id)("result", nullptr))); + sessionState_.isLogDomainEnabled = true; // Send a log entry identifying the modern CDP backend. sendInfoLogEntry(kModernCDPBackendNotice); @@ -51,10 +57,27 @@ void PageAgent::handleRequest(const cdp::PreparsedRequest& req) { sendInfoLogEntry("Integration: " + *sessionMetadata_.integrationName); } - return; - } + shouldSendOKResponse = true; + isFinishedHandlingRequest = false; + } else if (req.method == "Log.disable") { + sessionState_.isLogDomainEnabled = false; - if (req.method == "Page.reload") { + shouldSendOKResponse = true; + isFinishedHandlingRequest = false; + } else if (req.method == "Runtime.enable") { + sessionState_.isRuntimeDomainEnabled = true; + + shouldSendOKResponse = true; + isFinishedHandlingRequest = false; + } else if (req.method == "Runtime.disable") { + sessionState_.isRuntimeDomainEnabled = false; + + shouldSendOKResponse = true; + isFinishedHandlingRequest = false; + } + // Methods other than domain enables/disables: handle anything we know how + // to handle, and delegate to the InstanceAgent otherwise. + else if (req.method == "Page.reload") { targetController_.getDelegate().onReload({ .ignoreCache = req.params.isObject() && req.params.count("ignoreCache") ? std::optional(req.params.at("ignoreCache").asBool()) @@ -64,37 +87,13 @@ void PageAgent::handleRequest(const cdp::PreparsedRequest& req) { ? std::optional(req.params.at("scriptToEvaluateOnLoad").asString()) : std::nullopt, }); - folly::dynamic res = folly::dynamic::object("id", req.id)( - "result", folly::dynamic::object()); - std::string json = folly::toJson(res); - frontendChannel_(json); - return; - } - bool shouldSendOKResponse = false; - - if (req.method == "Runtime.enable") { - runtimeEnabled_ = true; - - // Fall through to letting the instance handle this request and send a - // response, but remember that we need to send a response in case the - // instance doesn't handle the request. - shouldSendOKResponse = true; - } - if (req.method == "Runtime.disable") { - runtimeEnabled_ = false; - folly::dynamic res = folly::dynamic::object("id", req.id)( - "result", folly::dynamic::object()); - std::string json = folly::toJson(res); - frontendChannel_(json); - - // Fall through to letting the instance handle this request and send a - // response, but remember that we need to send a response in case the - // instance doesn't handle the request. shouldSendOKResponse = true; + isFinishedHandlingRequest = true; } - if (instanceAgent_ && instanceAgent_->handleRequest(req)) { + if (!isFinishedHandlingRequest && instanceAgent_ && + instanceAgent_->handleRequest(req)) { return; } @@ -132,7 +131,7 @@ void PageAgent::setCurrentInstanceAgent( std::unique_ptr instanceAgent) { auto previousInstanceAgent = std::move(instanceAgent_); instanceAgent_ = std::move(instanceAgent); - if (!runtimeEnabled_) { + if (!sessionState_.isRuntimeDomainEnabled) { return; } if (previousInstanceAgent != nullptr) { diff --git a/packages/react-native/ReactCommon/jsinspector-modern/PageAgent.h b/packages/react-native/ReactCommon/jsinspector-modern/PageAgent.h index b7bc4038f09..f954f76d83b 100644 --- a/packages/react-native/ReactCommon/jsinspector-modern/PageAgent.h +++ b/packages/react-native/ReactCommon/jsinspector-modern/PageAgent.h @@ -8,6 +8,7 @@ #pragma once #include "PageTarget.h" +#include "SessionState.h" #include #include @@ -37,11 +38,14 @@ class PageAgent { * \param targetController An interface to the PageTarget that this agent is * attached to. The caller is responsible for ensuring that the * PageTargetDelegate and underlying PageTarget both outlive the agent. + * \param sessionMetadata Metadata about the session that created this agent. + * \param sessionState The state of the session that created this agent. */ PageAgent( FrontendChannel frontendChannel, PageTargetController& targetController, - PageTarget::SessionMetadata sessionMetadata); + PageTarget::SessionMetadata sessionMetadata, + SessionState& sessionState); /** * Handle a CDP request. The response will be sent over the provided @@ -74,7 +78,12 @@ class PageAgent { PageTargetController& targetController_; const PageTarget::SessionMetadata sessionMetadata_; std::unique_ptr instanceAgent_; - bool runtimeEnabled_{false}; + + /** + * A shared reference to the session's state. This is only safe to access + * during handleRequest and other method calls on the same thread. + */ + SessionState& sessionState_; }; } // namespace facebook::react::jsinspector_modern diff --git a/packages/react-native/ReactCommon/jsinspector-modern/PageTarget.cpp b/packages/react-native/ReactCommon/jsinspector-modern/PageTarget.cpp index fe0f2d97ce1..c47780cf7c1 100644 --- a/packages/react-native/ReactCommon/jsinspector-modern/PageTarget.cpp +++ b/packages/react-native/ReactCommon/jsinspector-modern/PageTarget.cpp @@ -11,6 +11,7 @@ #include "InstanceTarget.h" #include "PageAgent.h" #include "Parsing.h" +#include "SessionState.h" #include #include @@ -39,7 +40,8 @@ class PageTargetSession { pageAgent_( frontendChannel_, targetController, - std::move(sessionMetadata)) {} + std::move(sessionMetadata), + state_) {} /** * Called by CallbackLocalConnection to send a message to this Session's @@ -83,7 +85,7 @@ class PageTargetSession { void setCurrentInstance(InstanceTarget* instance) { if (instance) { pageAgent_.setCurrentInstanceAgent( - instance->createAgent(frontendChannel_)); + instance->createAgent(frontendChannel_, state_)); } else { pageAgent_.setCurrentInstanceAgent(nullptr); } @@ -94,6 +96,7 @@ class PageTargetSession { std::shared_ptr remote_; FrontendChannel frontendChannel_; PageAgent pageAgent_; + SessionState state_; }; PageTarget::PageTarget(PageTargetDelegate& delegate) : delegate_(delegate) {} diff --git a/packages/react-native/ReactCommon/jsinspector-modern/ReactCdp.h b/packages/react-native/ReactCommon/jsinspector-modern/ReactCdp.h index da28a4ae8bc..f19e5b8778b 100644 --- a/packages/react-native/ReactCommon/jsinspector-modern/ReactCdp.h +++ b/packages/react-native/ReactCommon/jsinspector-modern/ReactCdp.h @@ -10,3 +10,4 @@ #include #include #include +#include diff --git a/packages/react-native/ReactCommon/jsinspector-modern/SessionState.h b/packages/react-native/ReactCommon/jsinspector-modern/SessionState.h new file mode 100644 index 00000000000..ae5ac3a96b9 --- /dev/null +++ b/packages/react-native/ReactCommon/jsinspector-modern/SessionState.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +#include + +namespace facebook::react::jsinspector_modern { + +struct SessionState { + public: + // TODO: Generalise this to arbitrary domains + bool isLogDomainEnabled; + bool isRuntimeDomainEnabled; + + // Here, we will eventually allow RuntimeAgents to store their own arbitrary + // state (e.g. some sort of K/V storage of folly::dynamic?) + + // TODO: Figure out a good model for restricting write access / preventing + // agents from unintentionally clobbering each other's state. +}; + +} // namespace facebook::react::jsinspector_modern diff --git a/packages/react-native/ReactCommon/jsinspector-modern/tests/InspectorMocks.h b/packages/react-native/ReactCommon/jsinspector-modern/tests/InspectorMocks.h index b77b63efd0f..8c071b08078 100644 --- a/packages/react-native/ReactCommon/jsinspector-modern/tests/InspectorMocks.h +++ b/packages/react-native/ReactCommon/jsinspector-modern/tests/InspectorMocks.h @@ -127,14 +127,17 @@ class MockInstanceTargetDelegate : public InstanceTargetDelegate { MOCK_METHOD( std::unique_ptr, createRuntimeAgent, - (FrontendChannel channel), + (FrontendChannel channel, SessionState& sessionState), (override)); }; class MockRuntimeAgent : public RuntimeAgent { public: - inline MockRuntimeAgent(FrontendChannel frontendChannel) - : frontendChannel(std::move(frontendChannel)) {} + inline MockRuntimeAgent( + FrontendChannel frontendChannel, + SessionState& sessionState) + : frontendChannel(std::move(frontendChannel)), + sessionState(sessionState) {} // RuntimeAgent methods MOCK_METHOD( @@ -144,6 +147,7 @@ class MockRuntimeAgent : public RuntimeAgent { (override)); const FrontendChannel frontendChannel; + SessionState& sessionState; }; } // namespace facebook::react::jsinspector_modern diff --git a/packages/react-native/ReactCommon/jsinspector-modern/tests/PageTargetTest.cpp b/packages/react-native/ReactCommon/jsinspector-modern/tests/PageTargetTest.cpp index 3f7b1bc6fcf..120230ea07f 100644 --- a/packages/react-native/ReactCommon/jsinspector-modern/tests/PageTargetTest.cpp +++ b/packages/react-native/ReactCommon/jsinspector-modern/tests/PageTargetTest.cpp @@ -28,8 +28,10 @@ namespace { class PageTargetTest : public Test { protected: PageTargetTest() { - EXPECT_CALL(instanceTargetDelegate_, createRuntimeAgent(_)) - .WillRepeatedly(runtimeAgents_.lazily_make_unique()); + EXPECT_CALL(instanceTargetDelegate_, createRuntimeAgent(_, _)) + .WillRepeatedly( + runtimeAgents_ + .lazily_make_unique()); } void connect() { @@ -133,12 +135,6 @@ TEST_F(PageTargetProtocolTest, MalformedJson) { TEST_F(PageTargetProtocolTest, InjectLogsToIdentifyBackend) { InSequence s; - EXPECT_CALL(fromPage(), onMessage(JsonEq(R"({ - "id": 1, - "result": null - })"))) - .RetiresOnSaturation(); - EXPECT_CALL( fromPage(), onMessage(JsonParsed(AllOf( @@ -146,6 +142,11 @@ TEST_F(PageTargetProtocolTest, InjectLogsToIdentifyBackend) { AtJsonPtr("/params/entry", Not(IsEmpty())))))) .Times(2) .RetiresOnSaturation(); + EXPECT_CALL(fromPage(), onMessage(JsonEq(R"({ + "id": 1, + "result": {} + })"))) + .RetiresOnSaturation(); toPage_->sendMessage(R"({ "id": 1, "method": "Log.enable" @@ -385,7 +386,7 @@ TEST_F(PageTargetProtocolTest, MessageRoutingWhileNoRuntimeAgent) { TEST_F(PageTargetProtocolTest, InstanceWithNullRuntimeAgent) { InSequence s; - EXPECT_CALL(instanceTargetDelegate_, createRuntimeAgent(_)) + EXPECT_CALL(instanceTargetDelegate_, createRuntimeAgent(_, _)) .WillRepeatedly(ReturnNull()); auto& instanceTarget = page_.registerInstance(instanceTargetDelegate_); @@ -406,4 +407,41 @@ TEST_F(PageTargetProtocolTest, InstanceWithNullRuntimeAgent) { page_.unregisterInstance(instanceTarget); } +TEST_F(PageTargetProtocolTest, RuntimeAgentHasAccessToSessionState) { + InSequence s; + + // Send Runtime.enable before registering the Instance (which in turns creates + // the RuntimeAgent). + EXPECT_CALL(fromPage(), onMessage(JsonEq(R"({ + "id": 1, + "result": {} + })"))); + toPage_->sendMessage(R"({ + "id": 1, + "method": "Runtime.enable" + })"); + + page_.registerInstance(instanceTargetDelegate_); + ASSERT_TRUE(runtimeAgents_[0]); + + EXPECT_TRUE(runtimeAgents_[0]->sessionState.isRuntimeDomainEnabled); + + // Send Runtime.disable while the RuntimeAgent exists - it receives the + // message and can also observe the updated state. + EXPECT_CALL(*runtimeAgents_[0], handleRequest(Eq(cdp::preparse(R"({ + "id": 2, + "method": "Runtime.disable" + })")))); + EXPECT_CALL(fromPage(), onMessage(JsonEq(R"({ + "id": 2, + "result": {} + })"))); + toPage_->sendMessage(R"({ + "id": 2, + "method": "Runtime.disable" + })"); + + EXPECT_FALSE(runtimeAgents_[0]->sessionState.isRuntimeDomainEnabled); +} + } // namespace facebook::react::jsinspector_modern diff --git a/packages/react-native/ReactCommon/react/runtime/JSRuntimeFactory.cpp b/packages/react-native/ReactCommon/react/runtime/JSRuntimeFactory.cpp index e9e338b539a..d57cbc4645e 100644 --- a/packages/react-native/ReactCommon/react/runtime/JSRuntimeFactory.cpp +++ b/packages/react-native/ReactCommon/react/runtime/JSRuntimeFactory.cpp @@ -20,8 +20,10 @@ JSIRuntimeHolder::JSIRuntimeHolder(std::unique_ptr runtime) std::unique_ptr JSIRuntimeHolder::createInspectorAgent( - jsinspector_modern::FrontendChannel frontendChannel) { + jsinspector_modern::FrontendChannel frontendChannel, + jsinspector_modern::SessionState& sessionState) { (void)frontendChannel; + (void)sessionState; return nullptr; } diff --git a/packages/react-native/ReactCommon/react/runtime/JSRuntimeFactory.h b/packages/react-native/ReactCommon/react/runtime/JSRuntimeFactory.h index 0ffdb7896d7..61903d939ce 100644 --- a/packages/react-native/ReactCommon/react/runtime/JSRuntimeFactory.h +++ b/packages/react-native/ReactCommon/react/runtime/JSRuntimeFactory.h @@ -27,7 +27,9 @@ class JSRuntime { * \see InspectorTargetDelegate::createRuntimeAgent */ virtual std::unique_ptr - createInspectorAgent(jsinspector_modern::FrontendChannel frontendChannel) = 0; + createInspectorAgent( + jsinspector_modern::FrontendChannel frontendChannel, + jsinspector_modern::SessionState& sessionState) = 0; virtual ~JSRuntime() = default; }; @@ -50,7 +52,8 @@ class JSIRuntimeHolder : public JSRuntime { public: jsi::Runtime& getRuntime() noexcept override; std::unique_ptr createInspectorAgent( - jsinspector_modern::FrontendChannel frontendChannel) override; + jsinspector_modern::FrontendChannel frontendChannel, + jsinspector_modern::SessionState& sessionState) override; explicit JSIRuntimeHolder(std::unique_ptr runtime); diff --git a/packages/react-native/ReactCommon/react/runtime/ReactInstance.cpp b/packages/react-native/ReactCommon/react/runtime/ReactInstance.cpp index 988fd15242c..711e7e2c120 100644 --- a/packages/react-native/ReactCommon/react/runtime/ReactInstance.cpp +++ b/packages/react-native/ReactCommon/react/runtime/ReactInstance.cpp @@ -461,8 +461,10 @@ void ReactInstance::handleMemoryPressureJs(int pressureLevel) { } std::unique_ptr -ReactInstance::createRuntimeAgent(jsinspector_modern::FrontendChannel channel) { - auto agent = runtime_->createInspectorAgent(std::move(channel)); +ReactInstance::createRuntimeAgent( + jsinspector_modern::FrontendChannel channel, + jsinspector_modern::SessionState& sessionState) { + auto agent = runtime_->createInspectorAgent(std::move(channel), sessionState); return agent; } diff --git a/packages/react-native/ReactCommon/react/runtime/ReactInstance.h b/packages/react-native/ReactCommon/react/runtime/ReactInstance.h index c52b916defe..8c28a27c9d0 100644 --- a/packages/react-native/ReactCommon/react/runtime/ReactInstance.h +++ b/packages/react-native/ReactCommon/react/runtime/ReactInstance.h @@ -72,9 +72,9 @@ class ReactInstance final : private jsinspector_modern::InstanceTargetDelegate { void unregisterFromInspector(); private: - // From InstanceTargetDelegate std::unique_ptr createRuntimeAgent( - jsinspector_modern::FrontendChannel channel) override; + jsinspector_modern::FrontendChannel channel, + jsinspector_modern::SessionState& sessionState) override; std::shared_ptr runtime_; std::shared_ptr jsMessageQueueThread_;