@@ -31,6 +31,7 @@ class RecordingHook : public Hook {
3131 struct TrackCall {
3232 std::string key;
3333 std::optional<double > metric_value;
34+ std::optional<Value> data;
3435 };
3536
3637 explicit RecordingHook (std::string name) : metadata_(std::move(name)) {}
@@ -77,6 +78,7 @@ class RecordingHook : public Hook {
7778 TrackCall call;
7879 call.key = std::string (series_context.Key ());
7980 call.metric_value = series_context.MetricValue ();
81+ call.data = series_context.Data ();
8082 track_calls_.push_back (call);
8183 }
8284
@@ -443,6 +445,46 @@ TEST_F(HooksTest, AfterTrackWithMetricValue) {
443445 EXPECT_EQ (*calls[0 ].metric_value , 42.5 );
444446}
445447
448+ // Test that data is properly passed to afterTrack hooks
449+ // This test would catch use-after-move bugs with ASAN
450+ TEST_F (HooksTest, AfterTrackReceivesData) {
451+ auto hook = std::make_shared<RecordingHook>(" TestHook" );
452+
453+ auto config = ConfigBuilder (" sdk-key" )
454+ .Offline (true )
455+ .Hooks (hook)
456+ .Build ()
457+ .value ();
458+
459+ Client client (std::move (config));
460+
461+ // Test with string data
462+ client.Track (context_, " test-event" , Value (" test-data" ));
463+
464+ auto const & calls = hook->GetTrackCalls ();
465+ ASSERT_EQ (calls.size (), 1 );
466+ EXPECT_EQ (calls[0 ].key , " test-event" );
467+ ASSERT_TRUE (calls[0 ].data .has_value ());
468+ EXPECT_EQ (calls[0 ].data ->AsString (), " test-data" );
469+
470+ hook->Reset ();
471+
472+ // Test with complex data
473+ auto complex_data = Value::Object ({{" field1" , Value (" value1" )}, {" field2" , Value (42 )}});
474+ client.Track (context_, " test-event-2" , complex_data, 99.5 );
475+
476+ auto const & calls2 = hook->GetTrackCalls ();
477+ ASSERT_EQ (calls2.size (), 1 );
478+ EXPECT_EQ (calls2[0 ].key , " test-event-2" );
479+ ASSERT_TRUE (calls2[0 ].data .has_value ());
480+ EXPECT_EQ (calls2[0 ].data ->Type (), Value::Type::kObject );
481+ auto const & obj = calls2[0 ].data ->AsObject ();
482+ EXPECT_EQ (obj[" field1" ].AsString (), " value1" );
483+ EXPECT_EQ (obj[" field2" ].AsInt (), 42 );
484+ ASSERT_TRUE (calls2[0 ].metric_value .has_value ());
485+ EXPECT_EQ (*calls2[0 ].metric_value , 99.5 );
486+ }
487+
446488// Requirement 1.3.4: afterTrack handlers execute in order of registration
447489TEST_F (HooksTest, AfterTrackExecutesInOrder) {
448490 auto execution_order = std::make_shared<std::vector<std::string>>();
0 commit comments