Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
42a776d
base data structures fot hook implementation.
NeaguGeorgiana23 Jul 7, 2026
e968609
fix linter
NeaguGeorgiana23 Jul 7, 2026
334ec2a
fix linter
NeaguGeorgiana23 Jul 7, 2026
f110e5c
Merge branch 'main' into define-hook-data-structures
NeaguGeorgiana23 Jul 7, 2026
5cc878b
Update BUILD file.
NeaguGeorgiana23 Jul 10, 2026
bd66430
Correct include guards.
NeaguGeorgiana23 Jul 10, 2026
5332610
feat: Add HookData class.
NeaguGeorgiana23 Jul 10, 2026
c8fc92d
fix linter
NeaguGeorgiana23 Jul 10, 2026
3f5f4de
fix linter
NeaguGeorgiana23 Jul 10, 2026
b0f3a15
fix linter
NeaguGeorgiana23 Jul 10, 2026
e9e8852
fix linter
NeaguGeorgiana23 Jul 10, 2026
e333df0
add HookContext structure.
NeaguGeorgiana23 Jul 13, 2026
c59de28
fix linter
NeaguGeorgiana23 Jul 13, 2026
45ca64a
fix linter
NeaguGeorgiana23 Jul 13, 2026
3b93d77
add Hooks class.
NeaguGeorgiana23 Jul 14, 2026
a4aa1c2
fix linter.
NeaguGeorgiana23 Jul 14, 2026
d7cd54a
fix linter.
NeaguGeorgiana23 Jul 14, 2026
d6ef2c6
fix linter.
NeaguGeorgiana23 Jul 14, 2026
a2f7fee
fix linter.
NeaguGeorgiana23 Jul 14, 2026
a91afca
appli agent suggestions.
NeaguGeorgiana23 Jul 14, 2026
c0482f7
Merge branch 'main' into hooks
NeaguGeorgiana23 Jul 14, 2026
a0ca155
Merge branch 'main' into hooks
NeaguGeorgiana23 Jul 14, 2026
06bd51c
Add EvaluationOpton struct.
NeaguGeorgiana23 Jul 15, 2026
b362223
fix linter.
NeaguGeorgiana23 Jul 15, 2026
6942c4e
update Provider class to allow getting hooks.
NeaguGeorgiana23 Jul 15, 2026
49bdc17
update all classes that inharit from FeatureProvider.
NeaguGeorgiana23 Jul 15, 2026
dab62a0
update BUILD files and imports.
NeaguGeorgiana23 Jul 15, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions openfeature/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ package(
default_visibility = ["//visibility:public"],
)

cc_library(
name = "base_hook",
hdrs = ["base_hook.h"],
include_prefix = "openfeature",
)

cc_library(
name = "client",
hdrs = ["client.h"],
Expand Down Expand Up @@ -50,6 +56,16 @@ cc_library(
include_prefix = "openfeature",
)

cc_library(
name = "evaluation_options",
hdrs = ["evaluation_options.h"],
include_prefix = "openfeature",
deps = [
":base_hook",
":hook_hints",
],
)

cc_library(
name = "feature_provider_status_manager",
srcs = ["feature_provider_status_manager.cpp"],
Expand All @@ -74,6 +90,20 @@ cc_library(
],
)

cc_library(
name = "flag_evaluation_details",
srcs = ["flag_evaluation_details.cpp"],
hdrs = ["flag_evaluation_details.h"],
include_prefix = "openfeature",
deps = [
":error_code",
":flag_metadata",
":reason",
":resolution_details",
":value"
],
)

cc_library(
name = "flag_metadata",
hdrs = ["flag_metadata.h"],
Expand Down Expand Up @@ -124,6 +154,21 @@ cc_library(
include_prefix = "openfeature",
)

cc_library(
name = "hook",
srcs = ["hook.cpp"],
hdrs = ["hook.h"],
include_prefix = "openfeature",
deps = [
":base_hook",
":evaluation_context",
":flag_evaluation_details",
":hook_context",
":hook_hints",
":value",
],
)

cc_library(
name = "metadata",
hdrs = ["metadata.h"],
Expand Down Expand Up @@ -153,6 +198,7 @@ cc_library(
hdrs = ["noop_provider.h"],
include_prefix = "openfeature",
deps = [
":base_hook",
":evaluation_context",
":metadata",
":provider",
Expand Down Expand Up @@ -201,6 +247,7 @@ cc_library(
deps = [
"@abseil-cpp//absl/status",
"@abseil-cpp//absl/status:statusor",
":base_hook",
":evaluation_context",
":metadata",
":resolution_details",
Expand Down
21 changes: 21 additions & 0 deletions openfeature/base_hook.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#ifndef CPP_SDK_INCLUDE_OPENFEATURE_BASE_HOOK_H_
#define CPP_SDK_INCLUDE_OPENFEATURE_BASE_HOOK_H_

namespace openfeature {

// Non-templated base class for all hooks. This will allow storing different
// hook types (e.g., BoolHook,
// StringHook) inside evaluation options.
class BaseHook {
public:
BaseHook() = default;
BaseHook(const BaseHook&) = delete;
BaseHook(BaseHook&&) = delete;
BaseHook& operator=(const BaseHook&) = delete;
BaseHook& operator=(BaseHook&&) = delete;
virtual ~BaseHook() = default;
};

} // namespace openfeature

#endif // CPP_SDK_INCLUDE_OPENFEATURE_BASE_HOOK_H_
14 changes: 14 additions & 0 deletions openfeature/evaluation_options.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#ifndef CPP_SDK_INCLUDE_OPENFEATURE_EVALUATION_OPTIONS_H_
#define CPP_SDK_INCLUDE_OPENFEATURE_EVALUATION_OPTIONS_H_
#include <memory>
#include <vector>

#include "openfeature/base_hook.h"
#include "openfeature/hook_hints.h"
namespace openfeature {
struct EvaluationOptions {
std::vector<std::shared_ptr<BaseHook>> hooks;
HookHints hook_hints;
};
} // namespace openfeature
#endif // CPP_SDK_INCLUDE_OPENFEATURE_EVALUATION_OPTIONS_H_
42 changes: 42 additions & 0 deletions openfeature/flag_evaluation_details.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#include "openfeature/flag_evaluation_details.h"

#include <optional>
#include <string>
#include <string_view>

Comment on lines +3 to +6

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Include <utility> for std::move.

The std::move utility is used heavily in this file, but <utility> is not explicitly included. Relying on transitive includes can lead to compilation failures across different compilers or standard library versions.

🛠️ Proposed fix
 `#include` <optional>
 `#include` <string>
 `#include` <string_view>
+#include <utility>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
#include <optional>
#include <string>
#include <string_view>
`#include` <optional>
`#include` <string>
`#include` <string_view>
`#include` <utility>
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@openfeature/flag_evaluation_details.cpp` around lines 3 - 6, Add an explicit
<utility> include alongside the existing standard-library headers in
flag_evaluation_details.cpp so the file directly provides std::move without
relying on transitive includes.

#include "openfeature/error_code.h"
#include "openfeature/flag_metadata.h"
#include "openfeature/reason.h"
#include "openfeature/resolution_details.h"
#include "openfeature/value.h"

namespace openfeature {

template <typename T>
FlagEvaluationDetails<T>::FlagEvaluationDetails(
std::string flag_key, T value, Reason reason,
std::optional<std::string> variant, const FlagMetadata& flag_metadata,
std::optional<ErrorCode> error_code,
std::optional<std::string> error_message)
: ResolutionDetails<T>(std::move(value), reason, std::move(variant),
flag_metadata, error_code, std::move(error_message)),
flag_key_(std::move(flag_key)) {}

template <typename T>
FlagEvaluationDetails<T>::FlagEvaluationDetails(
std::string flag_key, const ResolutionDetails<T>& resolution_details)
: ResolutionDetails<T>(resolution_details),
flag_key_(std::move(flag_key)) {}

template <typename T>
std::string_view FlagEvaluationDetails<T>::GetFlagKey() const {
return flag_key_;
}

template class FlagEvaluationDetails<bool>;
template class FlagEvaluationDetails<std::string>;
template class FlagEvaluationDetails<int64_t>;
template class FlagEvaluationDetails<double>;
template class FlagEvaluationDetails<Value>;

} // namespace openfeature
48 changes: 48 additions & 0 deletions openfeature/flag_evaluation_details.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#ifndef CPP_SDK_INCLUDE_OPENFEATURE_FLAG_EVALUATION_DETAILS_H_
#define CPP_SDK_INCLUDE_OPENFEATURE_FLAG_EVALUATION_DETAILS_H_

#include <optional>
#include <string>
#include <string_view>

#include "openfeature/error_code.h"
#include "openfeature/flag_metadata.h"
#include "openfeature/reason.h"
#include "openfeature/resolution_details.h"
#include "openfeature/value.h"

namespace openfeature {

template <typename T>
class FlagEvaluationDetails : public ResolutionDetails<T> {
public:
FlagEvaluationDetails(
std::string flag_key, T value, Reason reason,
std::optional<std::string> variant, const FlagMetadata& flag_metadata,
std::optional<ErrorCode> error_code = std::nullopt,
std::optional<std::string> error_message = std::nullopt);

FlagEvaluationDetails(std::string flag_key,
const ResolutionDetails<T>& resolution_details);

FlagEvaluationDetails(const FlagEvaluationDetails&) = default;
FlagEvaluationDetails& operator=(const FlagEvaluationDetails&) = default;
FlagEvaluationDetails(FlagEvaluationDetails&&) noexcept = default;
FlagEvaluationDetails& operator=(FlagEvaluationDetails&&) noexcept = default;
~FlagEvaluationDetails() = default;
std::string_view GetFlagKey() const;

private:
std::string flag_key_;
};

// Type aliases for common types.
using BoolFlagEvaluationDetails = FlagEvaluationDetails<bool>;
using StringFlagEvaluationDetails = FlagEvaluationDetails<std::string>;
using IntFlagEvaluationDetails = FlagEvaluationDetails<int64_t>;
using DoubleFlagEvaluationDetails = FlagEvaluationDetails<double>;
using ObjectFlagEvaluationDetails = FlagEvaluationDetails<Value>;

} // namespace openfeature

#endif // CPP_SDK_INCLUDE_OPENFEATURE_FLAG_EVALUATION_DETAILS_H_
12 changes: 12 additions & 0 deletions openfeature/hook.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#include "openfeature/hook.h"

namespace openfeature {

// Explicit template instantiations for common hook types.
template class Hook<bool>;
template class Hook<std::string>;
template class Hook<int64_t>;
template class Hook<double>;
template class Hook<Value>;

} // namespace openfeature
66 changes: 66 additions & 0 deletions openfeature/hook.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
#ifndef CPP_SDK_INCLUDE_OPENFEATURE_HOOK_H_
#define CPP_SDK_INCLUDE_OPENFEATURE_HOOK_H_

#include <cstdint>
#include <exception>
#include <optional>
#include <string>

#include "openfeature/base_hook.h"
#include "openfeature/evaluation_context.h"
#include "openfeature/flag_evaluation_details.h"
#include "openfeature/hook_context.h"
#include "openfeature/hook_hints.h"
#include "openfeature/value.h"

namespace openfeature {

// Hook allows application developers to add arbitrary behavior to the
// flag evaluation lifecycle. Hooks operate similarly to middleware in web
// frameworks. They are executed stack-wise with respect to flag resolution,
// prioritizing increasing specificity (API, Client, Invocation, Provider)
// first, and the order in which they were added second.
/// https://openfeature.dev/specification/sections/hooks
template <typename T>
class Hook : public BaseHook {
public:
Hook() = default;
Hook(const Hook&) = delete;
Hook& operator=(const Hook&) = delete;
Hook(Hook&&) = delete;
Hook& operator=(Hook&&) = delete;
~Hook() override = default;

// Runs before the flag evaluation occurs.
virtual std::optional<EvaluationContext> Before(HookContext<T>& ctx,
const HookHints& hints) {
return std::nullopt;
}
Comment on lines +34 to +38

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Use a const reference for HookContext in Before to enforce immutability.

The OpenFeature specification requires the hook context to be immutable. Passing HookContext<T>& by non-const reference in the Before method misleadingly implies that the context can be mutated in-place and prevents the method from accepting a const or temporary HookContext. Furthermore, since this is a virtual method, correcting the signature after a public release would be a breaking API change for any developers who have overridden it.

Change the signature to accept const HookContext<T>& ctx to enforce immutability and maintain consistency with the After, Error, and Finally lifecycle methods.

🛠️ Proposed fixes for the interface and test

Update the signature in this file:

   // Runs before the flag evaluation occurs.
-  virtual std::optional<EvaluationContext> Before(HookContext<T>& ctx,
+  virtual std::optional<EvaluationContext> Before(const HookContext<T>& ctx,
                                                   const HookHints& hints) {
     return std::nullopt;
   }

You will also need to update the corresponding override in test/hook_test.cpp:

-  std::optional<EvaluationContext> Before(HookContext<T>& ctx,
+  std::optional<EvaluationContext> Before(const HookContext<T>& ctx,
                                           const HookHints& hints) override {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Runs before the flag evaluation occurs.
virtual std::optional<EvaluationContext> Before(HookContext<T>& ctx,
const HookHints& hints) {
return std::nullopt;
}
// Runs before the flag evaluation occurs.
virtual std::optional<EvaluationContext> Before(const HookContext<T>& ctx,
const HookHints& hints) {
return std::nullopt;
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@openfeature/hook.h` around lines 34 - 38, Update the virtual Before method in
Hook to accept const HookContext<T>&, enforcing the immutable hook-context
contract and matching the signatures of After, Error, and Finally. Update the
corresponding Before override in hook_test.cpp so it uses the same
const-reference parameter and continues to satisfy the interface.


// Runs immediately after successful flag evaluation occurs.
virtual void After(const HookContext<T>& ctx,
const FlagEvaluationDetails<T>& details,
const HookHints& hints) {}

// Runs if an error occurs during flag evaluation or in `Before`/`After`
// stages.
virtual void Error(const HookContext<T>& ctx, const std::exception& error,
const HookHints& hints) {}

// Runs after the flag evaluation occurs, regardless of whether it was
// successful or not.
virtual void Finally(const HookContext<T>& ctx,
const FlagEvaluationDetails<T>& details,
const HookHints& hints) {}
};

// Type aliases for common hook specializations.
using BoolHook = Hook<bool>;
using StringHook = Hook<std::string>;
using IntHook = Hook<int64_t>;
using DoubleHook = Hook<double>;
using ObjectHook = Hook<Value>;

} // namespace openfeature

#endif // CPP_SDK_INCLUDE_OPENFEATURE_HOOK_H_
1 change: 1 addition & 0 deletions openfeature/memory_provider/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ cc_library(
hdrs = ["in_memory_provider.h"],
include_prefix = "openfeature",
deps = [
"//openfeature:base_hook",
"//openfeature:error_code",
"//openfeature:evaluation_context",
":flag",
Expand Down
5 changes: 5 additions & 0 deletions openfeature/memory_provider/in_memory_provider.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <utility>

#include "absl/status/statusor.h"
#include "openfeature/base_hook.h"
#include "openfeature/error_code.h"
#include "openfeature/memory_provider/flag.h"
#include "openfeature/reason.h"
Expand All @@ -21,6 +22,10 @@ Metadata InMemoryProvider::GetMetadata() const {
return Metadata{std::string(kName)};
}

std::vector<std::shared_ptr<BaseHook>> InMemoryProvider::GetHooks() const {
return {};
}

absl::Status InMemoryProvider::Init(const EvaluationContext& ctx) {
{
std::unique_lock lock(mutex_);
Expand Down
3 changes: 3 additions & 0 deletions openfeature/memory_provider/in_memory_provider.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "openfeature/base_hook.h"
#include "openfeature/evaluation_context.h"
#include "openfeature/metadata.h"
#include "openfeature/provider.h"
Expand Down Expand Up @@ -44,6 +45,8 @@ class InMemoryProvider : public FeatureProvider {
// will be added to the configuration.
void UpdateFlag(std::string key, std::any new_flag);

std::vector<std::shared_ptr<BaseHook>> GetHooks() const override;

absl::StatusOr<std::unique_ptr<BoolResolutionDetails>> GetBooleanEvaluation(
std::string_view key, bool default_value,
const EvaluationContext& ctx) override;
Expand Down
4 changes: 4 additions & 0 deletions openfeature/noop_provider.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ namespace openfeature {

Metadata NoopProvider::GetMetadata() const { return Metadata{name_}; }

std::vector<std::shared_ptr<BaseHook>> NoopProvider::GetHooks() const {
return {};
}

absl::StatusOr<std::unique_ptr<BoolResolutionDetails>>
NoopProvider::GetBooleanEvaluation(std::string_view flag, bool default_value,
const EvaluationContext& ctx) {
Expand Down
4 changes: 4 additions & 0 deletions openfeature/noop_provider.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <string_view>

#include "absl/status/statusor.h"
#include "openfeature/base_hook.h"
#include "openfeature/evaluation_context.h"
#include "openfeature/metadata.h"
#include "openfeature/provider.h"
Expand All @@ -23,6 +24,9 @@ class NoopProvider : public FeatureProvider {
// Metadata returns the metadata of the provider.
Metadata GetMetadata() const override;

// GetHooks returns an empty vector of hooks.
std::vector<std::shared_ptr<BaseHook>> GetHooks() const override;

// BooleanEvaluation returns a boolean flag.
absl::StatusOr<std::unique_ptr<BoolResolutionDetails>> GetBooleanEvaluation(
std::string_view flag, bool default_value,
Expand Down
2 changes: 2 additions & 0 deletions openfeature/provider.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "openfeature/base_hook.h"
#include "openfeature/evaluation_context.h"
#include "openfeature/metadata.h"
#include "openfeature/resolution_details.h"
Expand All @@ -24,6 +25,7 @@ class FeatureProvider {
public:
virtual ~FeatureProvider() = default;
virtual Metadata GetMetadata() const = 0;
virtual std::vector<std::shared_ptr<BaseHook>> GetHooks() const = 0;
virtual absl::StatusOr<std::unique_ptr<BoolResolutionDetails>>
GetBooleanEvaluation(std::string_view flag, bool default_value,
const EvaluationContext& ctx) = 0;
Expand Down
Loading