New Features
Duplicate featureId Aggregation
The SDK now handles customers with multiple subscriptions that grant entitlements to the same feature. Raw entries are grouped by featureId and aggregated automatically:- METER:
usageLimitandcurrentUsageare summed across entries;remainingis recalculated - BOOLEAN / CUSTOMIZABLE:
hasAccessis OR’d across entries (anytrue→true)
items array on each Entitlement.getEntitlements() — Convenience Accessor
Returns the aggregated entitlements map directly, without the AsyncState wrapper:getRawEntitlements() — Raw API Response
Access the un-aggregated API response with the customerId wrapper:getRawEntitlement(featureId) — Raw Data for a Single Feature
Returns the raw API response filtered to a specific featureId:updateEntitlement() — Client-Side Entitlement Mutation
Update an entitlement in-place, for example after recording a usage increment on the client side. The remaining field is automatically recalculated.Partial<Omit<Entitlement, 'featureId' | 'featureType' | 'items'>>.environment Prop on KelviqProvider
Supports 'production' (default) and 'sandbox', which selects the appropriate default API URL:Breaking Changes
Unified Entitlement Type
The three separate entitlement interfaces and their union type have been replaced by a single unified Entitlement interface:featureKey Renamed to featureId
All props, parameters, and type fields now use featureId to match the backend API naming:Config Renamed to Customizable
| Before | After |
|---|---|
useConfigEntitlement | useCustomizableEntitlement |
ShowWhenConfigEntitled | ShowWhenCustomizableEntitled |
ConfigEntitlement type | Unified Entitlement |
type Field Renamed to featureType with Uppercase Values
| Before | After |
|---|---|
type: 'boolean' | featureType: 'BOOLEAN' |
type: 'customizable' | featureType: 'CUSTOMIZABLE' |
type: 'metered' | featureType: 'METER' |
configuration Field Removed
ConfigEntitlement.configuration has been removed. Customizable entitlements now use the same usageLimit, currentUsage, and remaining fields as metered entitlements.Hooks Return Entitlement | null Directly
All entitlement hooks now return the entitlement object directly (or null) instead of an AsyncState wrapper. Use the top-level isLoading and error from useKelviq() for loading/error states.getEntitlement() Simplified
The generic type parameter and second argument have been removed:hasAccess() Returns boolean (Never undefined)
hasAccess(featureId) now returns false when data is unavailable instead of undefined. No need for nullish checks.Metered Field Renames
| Before | After | Notes |
|---|---|---|
limit | usageLimit | Aligned with the API |
used | currentUsage | Aligned with the API |
resetAt | (removed) | Now per-item: entitlement.items[].resetAt |
hardLimit | hardLimit | Now aggregated: true if any item sets it |
allEntitlements.data Shape Changed
The map is now keyed by featureId (previously featureKey) and contains unified Entitlement objects. Use the new getEntitlements() convenience method:Migration Checklist
- Replace all
featureKeyprops/params withfeatureId - Replace
entitlement.typewithentitlement.featureTypeand update values to uppercase - Replace
useConfigEntitlementwithuseCustomizableEntitlement - Replace
ShowWhenConfigEntitledwithShowWhenCustomizableEntitled - Replace
ConfigEntitlement.configurationwithusageLimit/currentUsage/remaining - Update hook consumers: hooks now return
Entitlement | nulldirectly (notAsyncState) - Remove type parameters from
getEntitlement()calls - Replace
limit→usageLimit,used→currentUsage - Replace
entitlement.resetAtwithentitlement.items[].resetAt - Use
getEntitlements()instead ofallEntitlements.data - Use
getRawEntitlements()for un-aggregated API data