feat: add count and query APIs for events and text runs at the Artboard level, and expose in WASM

Will add some tests, but want to get validation before I go much further that this is the approach we want to take to expose Events and Text Runs for a given artboard at the `rive::Artboard` level, similar to the APIs for getting the linear animation/state machine from an `Artboard`. Adding to `ArtboardImporter` seemed most appropriate but not sure there's any caveats or better ways to plumb through adding the events/runs. Maybe @luigi-rosso @philter ?

Decided on exposing `textValueRunCount()`/`textValueRunAt()` and `eventCount()`/`eventAt()` APIs on the Artboard at the cpp level to follow existing patterns. This should make it simple for other runtimes to adopt too. Another alternative is just doing an empty `find<rive::TextValueRun>()`/`find<rive::Event>()` call at each runtime level which looks like it returns a list of all the objects.

TODO:
- [x] Add tests
- [x] Check WASM size before/after new bindings

Diffs=
22077beda feat: add count and query APIs for events and text runs at the Artboard level, and expose in WASM (#6043)

Co-authored-by: Zachary Plata <plata.zach@gmail.com>
diff --git a/.rive_head b/.rive_head
index aec9b2c..8da8b8d 100644
--- a/.rive_head
+++ b/.rive_head
@@ -1 +1 @@
-f95f54140657f8b8726392a3d0b4036bb4ad70fb
+22077bedae4c277e5e8a81c732167ab5d559917c
diff --git a/include/rive/artboard.hpp b/include/rive/artboard.hpp
index b53430c..e21e34a 100644
--- a/include/rive/artboard.hpp
+++ b/include/rive/artboard.hpp
@@ -9,6 +9,8 @@
 #include "rive/math/aabb.hpp"
 #include "rive/renderer.hpp"
 #include "rive/shapes/shape_paint_container.hpp"
+#include "rive/text/text_value_run.hpp"
+#include "rive/event.hpp"
 
 #include <queue>
 #include <vector>
@@ -27,6 +29,8 @@
 class Scene;
 class StateMachineInstance;
 class Joystick;
+class TextValueRun;
+class Event;
 
 class Artboard : public ArtboardBase, public CoreContext, public ShapePaintContainer
 {
@@ -38,6 +42,8 @@
     std::vector<Core*> m_Objects;
     std::vector<LinearAnimation*> m_Animations;
     std::vector<StateMachine*> m_StateMachines;
+    std::vector<TextValueRun*> m_TextValueRuns;
+    std::vector<Event*> m_Events;
     std::vector<Component*> m_DependencyOrder;
     std::vector<Drawable*> m_Drawables;
     std::vector<DrawTarget*> m_DrawTargets;
@@ -65,6 +71,8 @@
     void addObject(Core* object);
     void addAnimation(LinearAnimation* object);
     void addStateMachine(StateMachine* object);
+    void addTextValueRun(TextValueRun* object);
+    void addEvent(Event* object);
 
 public:
     Artboard() {}
@@ -146,6 +154,12 @@
     size_t stateMachineCount() const { return m_StateMachines.size(); }
     std::string stateMachineNameAt(size_t index) const;
 
+    size_t textValueRunCount() const { return m_TextValueRuns.size(); }
+    TextValueRun* textValueRunAt(size_t index) const;
+
+    size_t eventCount() const { return m_Events.size(); }
+    Event* eventAt(size_t index) const;
+
     LinearAnimation* firstAnimation() const { return animation(0); }
     LinearAnimation* animation(const std::string& name) const;
     LinearAnimation* animation(size_t index) const;
@@ -191,6 +205,14 @@
         {
             artboardClone->m_StateMachines.push_back(stateMachine);
         }
+        for (auto textRun : m_TextValueRuns)
+        {
+            artboardClone->m_TextValueRuns.push_back(textRun);
+        }
+        for (auto event : m_Events)
+        {
+            artboardClone->m_Events.push_back(event);
+        }
 
         if (artboardClone->initialize() != StatusCode::Ok)
         {
diff --git a/include/rive/event.hpp b/include/rive/event.hpp
index 743c6c5..906f562 100644
--- a/include/rive/event.hpp
+++ b/include/rive/event.hpp
@@ -8,6 +8,7 @@
 {
 public:
     void trigger(const CallbackData& value) override;
+    StatusCode import(ImportStack& importStack) override;
 };
 } // namespace rive
 
diff --git a/include/rive/importers/artboard_importer.hpp b/include/rive/importers/artboard_importer.hpp
index a6fc955..b9fba12 100644
--- a/include/rive/importers/artboard_importer.hpp
+++ b/include/rive/importers/artboard_importer.hpp
@@ -9,6 +9,8 @@
 class Artboard;
 class LinearAnimation;
 class StateMachine;
+class TextValueRun;
+class Event;
 class ArtboardImporter : public ImportStackObject
 {
 private:
@@ -19,6 +21,8 @@
     void addComponent(Core* object);
     void addAnimation(LinearAnimation* animation);
     void addStateMachine(StateMachine* stateMachine);
+    void addTextValueRun(TextValueRun* textValueRun);
+    void addEvent(Event* event);
     StatusCode resolve() override;
     const Artboard* artboard() const { return m_Artboard; }
 
diff --git a/include/rive/text/text_value_run.hpp b/include/rive/text/text_value_run.hpp
index 3bdca17..0807b34 100644
--- a/include/rive/text/text_value_run.hpp
+++ b/include/rive/text/text_value_run.hpp
@@ -10,6 +10,7 @@
 public:
     StatusCode onAddedClean(CoreContext* context) override;
     StatusCode onAddedDirty(CoreContext* context) override;
+    StatusCode import(ImportStack& importStack) override;
     TextStyle* style() { return m_style; }
     uint32_t offset() const;
 
diff --git a/src/artboard.cpp b/src/artboard.cpp
index 8b37215..457143b 100644
--- a/src/artboard.cpp
+++ b/src/artboard.cpp
@@ -18,6 +18,8 @@
 #include "rive/joystick.hpp"
 #include "rive/animation/state_machine_instance.hpp"
 #include "rive/shapes/shape.hpp"
+#include "rive/text/text_value_run.hpp"
+#include "rive/event.hpp"
 
 #include <stack>
 #include <unordered_map>
@@ -368,6 +370,10 @@
 
 void Artboard::addStateMachine(StateMachine* object) { m_StateMachines.push_back(object); }
 
+void Artboard::addTextValueRun(TextValueRun* object) { m_TextValueRuns.push_back(object); }
+
+void Artboard::addEvent(Event* object) { m_Events.push_back(object); }
+
 Core* Artboard::resolve(uint32_t id) const
 {
     if (id >= static_cast<int>(m_Objects.size()))
@@ -709,6 +715,24 @@
     return index;
 }
 
+TextValueRun* Artboard::textValueRunAt(size_t index) const
+{
+    if (index >= m_TextValueRuns.size())
+    {
+        return nullptr;
+    }
+    return m_TextValueRuns[index];
+}
+
+Event* Artboard::eventAt(size_t index) const
+{
+    if (index >= m_Events.size())
+    {
+        return nullptr;
+    }
+    return m_Events[index];
+}
+
 // std::unique_ptr<ArtboardInstance> Artboard::instance() const
 // {
 //     std::unique_ptr<ArtboardInstance> artboardClone(new ArtboardInstance);
diff --git a/src/event.cpp b/src/event.cpp
index 84be0ee..39dade4 100644
--- a/src/event.cpp
+++ b/src/event.cpp
@@ -1,9 +1,22 @@
 #include "rive/event.hpp"
 #include "rive/animation/state_machine_instance.hpp"
+#include "rive/artboard.hpp"
+#include "rive/importers/artboard_importer.hpp"
 
 using namespace rive;
 
 void Event::trigger(const CallbackData& value)
 {
     value.context()->reportEvent(this, value.delaySeconds());
+}
+
+StatusCode Event::import(ImportStack& importStack)
+{
+    auto artboardImporter = importStack.latest<ArtboardImporter>(ArtboardBase::typeKey);
+    if (artboardImporter == nullptr)
+    {
+        return StatusCode::MissingObject;
+    }
+    artboardImporter->addEvent(this);
+    return Super::import(importStack);
 }
\ No newline at end of file
diff --git a/src/importers/artboard_importer.cpp b/src/importers/artboard_importer.cpp
index db008ba..ccb524c 100644
--- a/src/importers/artboard_importer.cpp
+++ b/src/importers/artboard_importer.cpp
@@ -2,6 +2,8 @@
 #include "rive/importers/artboard_importer.hpp"
 #include "rive/animation/linear_animation.hpp"
 #include "rive/animation/state_machine.hpp"
+#include "rive/text/text_value_run.hpp"
+#include "rive/event.hpp"
 #include "rive/artboard.hpp"
 
 using namespace rive;
@@ -20,6 +22,13 @@
     m_Artboard->addStateMachine(stateMachine);
 }
 
+void ArtboardImporter::addTextValueRun(TextValueRun* textValueRun)
+{
+    m_Artboard->addTextValueRun(textValueRun);
+}
+
+void ArtboardImporter::addEvent(Event* event) { m_Artboard->addEvent(event); }
+
 StatusCode ArtboardImporter::resolve() { return m_Artboard->initialize(); }
 
 bool ArtboardImporter::readNullObject()
diff --git a/src/text/text_value_run.cpp b/src/text/text_value_run.cpp
index f46c83b..5093ca2 100644
--- a/src/text/text_value_run.cpp
+++ b/src/text/text_value_run.cpp
@@ -3,6 +3,7 @@
 #include "rive/text/text_style.hpp"
 #include "rive/text/text_value_run.hpp"
 #include "rive/artboard.hpp"
+#include "rive/importers/artboard_importer.hpp"
 
 using namespace rive;
 
@@ -43,6 +44,17 @@
     return StatusCode::Ok;
 }
 
+StatusCode TextValueRun::import(ImportStack& importStack)
+{
+    auto artboardImporter = importStack.latest<ArtboardImporter>(ArtboardBase::typeKey);
+    if (artboardImporter == nullptr)
+    {
+        return StatusCode::MissingObject;
+    }
+    artboardImporter->addTextValueRun(this);
+    return Super::import(importStack);
+}
+
 void TextValueRun::styleIdChanged()
 {
     auto coreObject = artboard()->resolve(styleId());
diff --git a/test/state_machine_event_test.cpp b/test/state_machine_event_test.cpp
index b801a03..1b06681 100644
--- a/test/state_machine_event_test.cpp
+++ b/test/state_machine_event_test.cpp
@@ -120,6 +120,24 @@
     REQUIRE(switchButton->value() == true);
 }
 
+TEST_CASE("can query for all rive events", "[events]")
+{
+    auto file = ReadRiveFile("../../test/assets/event_on_listener.riv");
+    auto artboard = file->artboard();
+
+    auto eventCount = artboard->eventCount();
+    REQUIRE(eventCount == 4);
+}
+
+TEST_CASE("can query for a rive event at a given index", "[events]")
+{
+    auto file = ReadRiveFile("../../test/assets/event_on_listener.riv");
+    auto artboard = file->artboard();
+
+    auto event = artboard->eventAt(0);
+    REQUIRE(event->name() == "Somewhere.com");
+}
+
 TEST_CASE("events load correctly on a listener", "[events]")
 {
     auto file = ReadRiveFile("../../test/assets/event_on_listener.riv");
diff --git a/test/text_test.cpp b/test/text_test.cpp
index 701fcb2..c009a05 100644
--- a/test/text_test.cpp
+++ b/test/text_test.cpp
@@ -28,6 +28,24 @@
     artboard->draw(&renderer);
 }
 
+TEST_CASE("can query for all text runs", "[text]")
+{
+    auto file = ReadRiveFile("../../test/assets/new_text.riv");
+    auto artboard = file->artboard();
+
+    auto textRunCount = artboard->textValueRunCount();
+    REQUIRE(textRunCount == 22);
+}
+
+TEST_CASE("can query for a text run at a given index", "[text]")
+{
+    auto file = ReadRiveFile("../../test/assets/hello_world.riv");
+    auto artboard = file->artboard();
+
+    auto textRun = artboard->textValueRunAt(0);
+    REQUIRE(textRun->text() == "Hello World!");
+}
+
 TEST_CASE("simple text loads", "[text]")
 {
     auto file = ReadRiveFile("../../test/assets/hello_world.riv");