-
Notifications
You must be signed in to change notification settings - Fork 51
Add hook to transform toggles before updating #248
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Hi @besLisbeth this type of filtering is accomplished in Unleash using different project-scoped tokens. That's the recommended way and it's standard to all SDKs. The problem of this proposal is that either will have to be implemented in all SDKs (for consistency), which has a high cost, or it will create a drift in how our SDKs work, which is something we want to prevent. We understand that open source users are limited to one project, but that's because the expected target of Open Source users is for the smaller scale, and in those situations filtering toggles wouldn't be necessary. |
Hi @gastonfournier, unfortunately, dividing our Unleash environment on projects wouldn't help us, as we are trying to have that filtering in the one project scope |
We've got a number of feature flags with a very complex logic, both on the Model and the UI side. This prevents us from updating feature flags without reloading the page. But now, we decide to have a couple of FF that would be updating with the refreshInterval, and we need to somehow "freeze" the complex ones. Maybe you've got any other ideas on how we can accomplish this? |
Unfortunately, having multiple projects is one of the enterprise features we have and it's also more comprehensive to group features by project than filtering on the frontend side. Doing it by project also gives us the benefit of having project specific metrics. So, implementing this feature request goes against our goals.
|
Can we talk about the multi-project approach?
How can we utilize the multi-project approach to address this problem? Would we need two proxies for one project, and two proxy clients on the side of the frontend? It's more than inconvenient |
I think we need to go back to the problem statement. You want some features to be active only if the customer gave their consent. I can think of a few ways of doing that without having to modify the internals of the feature flagging system. Option 1: using Unleash contextunleash.setContextField('isOk', 'false');
userConfirmation().then((ok) => unleash.setContextField('userId', `${ok}`)); then just use 'isOk' as a constraint to whether some features are enabled or not. Option 2: having it as part of the conditionconst isOk = await userConfirmation();
if (unleash.isEnabled('flag') && isOk) {
// do something
} You could hide this complexity with a library wrapper, but because you have cases where the flags needs to account for the confirmation and other cases where it should not, I think the wrapper would add another layer of complexity. I believe both options should work fine. The first one allows you to have that control in Unleash UI, you just always include the user consent in the context and let Unleash constraints dictate which flags are enabled and which flags are not. So I'd prefer option 1, but we've also seen option 2 in some cases where you want that control to be in your code. Let me know if that works for you, I think we started discussing solutions before discussing the problem you were trying to solve. I tried my best to go back to the original problem based on your last message and the description of the issue, so feel free to add more details or correct me if the proposed solution is missing some details from the problem you're trying to solve. |
The initial goal is to somehow filter the toggles that are easy to update and can be processed in real-time from the complex ones we want to avoid until the refresh of the page. The way we are dealing with it right now - we reevaluate the fetch function from our side, and the way it's working now is bad for a lot of reasons:
Adding asynchronicity to the filtering may also add flexibility to the existing scenarios, as you showed in Option 2. Unfortunately, it seems to me that both options provided won't help us a lot. Below, I provide an example of how filtering could be added to the library in a bad existing way:
|
Can you elaborate on the reasons why? |
@gastonfournier, because you went back to the problem statement but evaluated the wrong problem |
Hi @besLisbeth, sorry for any confusion earlier.
I'm trying to find an approach that fits your goal and the way we've seen this problem solved (both in this SDK as well as in other SDKs). The common pattern is a tiny wrapper: const stickyCache = new Map<string, boolean>();
function isEnabledSticky(name: string, ctx?: Context) {
if (!stickyCache.has(name)) {
stickyCache.set(name, unleash.isEnabled(name, ctx));
}
return stickyCache.get(name)!;
}
Most teams lean on this wrapper instead of changing the SDK internals, and it's the approach I'd recommend. We definitely see the potential value here—the challenge is that we maintain ~20 SDKs. We'd rather solve it once at the protocol level (e.g., a sticky flag attribute every client understands) than introduce a special-case hook in just this SDK. Right now we're heads-down rolling out Yggdrasil across all clients, so realistically we couldn't tackle a protocol change for a few months unless we start hearing stronger demand. Still, let's keep the idea on the table and revisit when the timing's better, but do let me know if the stickyCache proposal is better aligned with your original problem. |
Describe the feature request
I would like to propose a new configuration option for the unleash-proxy-client-js library that allows clients to filter or transform the list of feature toggles before the internal state is updated. This would provide a clean, flexible way to manage which toggles are updated, without overriding core logic such as the fetch method.
Background
In the current implementation, when the Unleash proxy client fetches toggles, it updates the internal state with the entire list of toggles returned by the proxy. This behavior works well for most scenarios, but introduces limitations for more complex use cases where only a subset of toggles should be processed. In our project, we want to update the list of feature flags with not very complex logic to not break the client and not to over-complicate the logic that could result in bad UX.
To work around this, I’m currently overriding the fetch method entirely, just to inject toggle transformation logic. However, this approach has significant downsides:
My actual goal is not to replace fetch, but simply to intercept or shape the list of toggles before they’re applied to the client.
Solution suggestions
I propose introducing a new optional hook in the client configuration that allows consumers to control how the fetched toggles are processed before updating internal state.
Three possible designs:
Option A: Filtering hook
filterToggles?: (toggle: IToggle) => boolean;
Usage:
filterToggles: (toggle) => toggle.name.startsWith('app:feature:');
Option B: Transformation hook
transformToggles?: (toggles: IToggle[]) => IToggle[];
Usage:
transformToggles: (toggles) => toggles.filter(t => t.name.includes('beta'));
Option C: Asynchronous transformation hook
transformToggles?: (toggles: IToggle[]) => Promise<IToggle[]>;
Usage:
These hooks would execute after the toggle list is fetched but before the client updates its internal feature map.
I prefer Option C as it's more flexible compared with the previous ones. It also opens the door to dynamic filtering or enrichment, such as:
Benefits to have this feature overall:
This addition would significantly improve flexibility while keeping the existing API clean and backward-compatible.
I would also like to write the PR to add this functionality to the code.
What do you think?
The text was updated successfully, but these errors were encountered: