New Features
Hybrid Aggregation Engine
If a customer has multiple subscriptions (e.g., a base plan + a top-up), the API may return duplicatefeatureId entries. The SDK now automatically aggregates them into a single Entitlement object per feature — no manual merging required.Aggregation rules:| Feature Type | hasAccess | currentUsage | usageLimit | hardLimit |
|---|---|---|---|---|
| METER | true if remaining > 0 or unlimited | Summed | Summed | true if any item sets it |
| BOOLEAN | true if any item grants access | 0 | null | false |
| CUSTOMIZABLE | true if any item grants access | First item’s value | First item’s value | First item’s value |
resetAt and individual hardLimit values) are available on entitlement.items[].getEntitlements() — Fetch All Entitlements
Returns all aggregated entitlements as a map keyed by featureId. Replaces the old getAllEntitlements() method.getRawEntitlement(featureId) — Raw Data for a Single Feature
Returns the un-aggregated raw API items for a specific featureId. Useful when you need per-subscription details.getRawEntitlements() — Full Raw API Response
Returns the complete raw API response including the customerId wrapper, before any aggregation.ready() — Wait for Initial Fetch
Returns a promise that resolves once the initial entitlement fetch completes. If initializeAndFetch was not set, resolves immediately.New Type Exports
RawEntitlement and RawEntitlementsApiResponse are now exported for consumers who need to type the raw API objects in their own code.Breaking Changes
Unified Entitlement Interface
The separate BooleanEntitlement, ConfigEntitlement, and MeteredEntitlement types have been replaced with a single, unified Entitlement interface:BooleanEntitlement, ConfigEntitlement, MeteredEntitlement, and AnyEntitlement with Entitlement.getEntitlement() No Longer Accepts a Type Argument
The generic type parameter and second type argument have been removed. The SDK now determines the feature type automatically.Renamed Fields
| Before | After | Notes |
|---|---|---|
used | currentUsage | Aligned with the raw API field name |
limit | usageLimit | Aligned with the raw API field name |
type | featureType | Now uses uppercase API values ("METER", "BOOLEAN", "CUSTOMIZABLE") |
configuration | (removed) | No longer surfaced at the top level |
resetAt | (removed) | Access via entitlement.items[].resetAt (may differ per subscription) |
Removed Exports
The following types are no longer exported:BooleanEntitlement,ConfigEntitlement,MeteredEntitlement,AnyEntitlementEntitlementMapis nowRecord<string, Entitlement>(no union type)
getAllEntitlements() Removed
Use getEntitlements() instead, which returns the aggregated map.Changed
fetchAllEntitlements()deduplicates concurrent calls — Instead of rejecting with “already in progress”, it returns the same in-flight promise. This makesinitializeAndFetch: truesafely composable withawait fetchAllEntitlements().fetchAllEntitlements()stores raw data — Now stores both the full raw API response and the aggregated cache internally.clearCache()clears raw data — Now also clears the stored raw API response.
Fixed
initializeAndFetch: falsewas ignored — The factory used||instead of??, so passingfalsehad no effect and entitlements were always fetched on initialization. Fixed to use nullish coalescing (??).- Options table in documentation — Filled in missing type values for
accessToken(string) andonError((error: Error) => void).