Skip to content

Commit 77c124d

Browse files
authored
Merge pull request #16 from growthbook/feat/enc-sticky-parity
Add support for Encrypted features, Sticky Bucketing and Fix evaluate_Expieriment flow
2 parents 7726fc0 + 9249c23 commit 77c124d

File tree

15 files changed

+2009
-203
lines changed

15 files changed

+2009
-203
lines changed

.gitignore

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,5 +32,5 @@ out.zip
3232
*.zip
3333
*.pkg
3434

35-
# Test Channel
36-
test-channel
35+
# Test Channel (run locally with brs-desktop, not committed)
36+
test-channel/

CHANGELOG.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,32 @@
22

33
All notable changes to the GrowthBook Roku SDK.
44

5+
## [2.0.0] - 2026-02-10
6+
7+
### Added
8+
- **Encrypted Features** - AES-128-CBC decryption for encrypted feature payloads (`roEVPCipher`, Roku OS 9.2+)
9+
- Supports `encryptedFeatures` and `encryptedSavedGroups` in API responses
10+
- Configure with `decryptionKey` option
11+
- **Sticky Bucketing** - Persistent experiment assignments across sessions
12+
- `GrowthBookInMemoryStickyBucketService()` for testing and simple use
13+
- `GrowthBookRegistryStickyBucketService()` for persistent storage via `roRegistrySection`
14+
- Supports `fallbackAttribute` for anonymous-to-logged-in user transitions
15+
- Version blocking via `minBucketVersion` and `bucketVersion`
16+
- **Tracking Plugin System** - Extensible plugin architecture for event tracking
17+
- `registerTrackingPlugin()` to add plugins at runtime
18+
- Plugins receive `onExperimentViewed` and `onFeatureUsage` events
19+
- Built-in `GrowthBookTrackingPlugin` for data warehouse integration with batched HTTP delivery
20+
- **Refresh Features API** - On-demand feature updates via `refreshFeatures()`
21+
- **Fallback Attribute Support** - `fallbackAttribute` in hash context for sticky bucketing prerequisites
22+
- **Decrypt & Sticky Bucket Test Coverage** - Both test runners (BrightScript + JS validator) now cover all spec categories
23+
- 327/327 spec tests passing (100%)
24+
25+
### Improved
26+
- **Platform Compatibility** - Cipher operations wrapped in try/catch for cross-platform resilience
27+
- **Feature Parsing** - `_parseFeatures()` now handles encrypted payloads, encrypted saved groups, and plain saved groups
28+
29+
---
30+
531
## [1.3.1] - 2026-02-03
632

733
### Changes

README.md

Lines changed: 91 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,22 +3,25 @@
33
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
44
[![BrightScript](https://img.shields.io/badge/BrightScript-2.0-purple.svg)](https://developer.roku.com/docs/references/brightscript/language/brightscript-language-reference.md)
55
[![Roku](https://img.shields.io/badge/Roku-SceneGraph-6f3f9f.svg)](https://developer.roku.com/)
6-
[![Version](https://img.shields.io/badge/version-1.3.1-blue.svg)](CHANGELOG.md)
6+
[![Version](https://img.shields.io/badge/version-2.0.0-blue.svg)](CHANGELOG.md)
77
[![Production Ready](https://img.shields.io/badge/status-production%20ready-green.svg)](docs/INTEGRATION_GUIDE.md)
88

99
Official [GrowthBook](https://www.growthbook.io/) SDK for Roku/BrightScript applications. Add feature flags and A/B testing to your Roku channels with a simple, lightweight SDK.
1010

11-
**Current Version:** v1.3.1[View Changelog](CHANGELOG.md) | [Integration Guide](docs/INTEGRATION_GUIDE.md) | [Quick Start](docs/QUICKSTART.md)
11+
**Current Version:** v2.0.0[View Changelog](CHANGELOG.md) | [Integration Guide](docs/INTEGRATION_GUIDE.md) | [Quick Start](docs/QUICKSTART.md)
1212

1313
## Features
1414

1515
- 🚀 **Lightweight** - Core SDK is ~50KB, minimal memory footprint
1616
-**Fast** - Feature evaluation in <1ms, optimized for Roku devices
17-
- 🎯 **Full Spec Alignment** - Supports v1.3.0 logic (filters, namespaces, ranges, and truthiness)
17+
- 🎯 **Full Spec Alignment** - 327/327 spec tests passing (evalCondition, hash, bucketing, features, decrypt, stickyBucket)
1818
- 🧪 **A/B Testing** - Run experiments with accurate traffic splits and holdout groups
1919
- 🔄 **Consistent Bucketing** - Same user always sees same variation (cross-platform)
20-
- 📊 **Analytics Ready** - Detailed experiment tracking and feature usage callbacks
21-
- 🔒 **Secure** - Support for encrypted feature payloads
20+
- 📊 **Analytics Ready** - Tracking callbacks, feature usage events, and plugin system
21+
- 🔒 **Encrypted Features** - AES-128-CBC decryption for secure feature payloads (Roku OS 9.2+)
22+
- 📌 **Sticky Bucketing** - Persistent experiment assignments with in-memory and registry-based storage
23+
- 🔌 **Tracking Plugins** - Extensible plugin architecture with built-in data warehouse integration
24+
- 🔃 **On-Demand Refresh** - Manual feature refresh via `refreshFeatures()`
2225
- 📦 **Ropm Support** - Easy dependency management via ropm
2326
- 🎨 **No Dependencies** - Pure BrightScript, works on all Roku devices (Roku 3+, OS 9.0+)
2427

@@ -618,10 +621,11 @@ Then reference the SDK:
618621
|--------|------|-------------|
619622
| `apiHost` | string | GrowthBook API host (default: `https://cdn.growthbook.io`) |
620623
| `clientKey` | string | **Required** - Your SDK client key from GrowthBook |
621-
| `decryptionKey` | string | Optional - Decrypt encrypted feature payloads |
624+
| `decryptionKey` | string | Decrypt encrypted feature payloads (Roku OS 9.2+) |
622625
| `attributes` | object | User attributes for targeting (e.g., `{id: "user-123", premium: true}`) |
623626
| `trackingCallback` | function | Callback fired when user is placed in an experiment |
624627
| `onFeatureUsage` | function | Callback fired on every feature evaluation |
628+
| `stickyBucketService` | object | Sticky bucket storage service (in-memory or registry-based) |
625629
| `enableDevMode` | boolean | Enable verbose logging for debugging |
626630

627631
### Core Methods
@@ -667,6 +671,28 @@ gb.setAttributes({
667671
})
668672
```
669673

674+
#### `refreshFeatures() as boolean`
675+
676+
Re-fetch features from the GrowthBook API. Useful for long-running apps.
677+
678+
```brightscript
679+
if gb.refreshFeatures()
680+
print "Features refreshed"
681+
end if
682+
```
683+
684+
#### `registerTrackingPlugin(plugin as object)`
685+
686+
Register a tracking plugin to receive experiment and feature usage events.
687+
688+
```brightscript
689+
plugin = GrowthBookTrackingPlugin({
690+
ingestorHost: "https://analytics.example.com",
691+
clientKey: "sdk_YOUR_KEY"
692+
})
693+
gb.registerTrackingPlugin(plugin)
694+
```
695+
670696
#### `evalFeature(featureKey as string) as object`
671697

672698
Get detailed feature evaluation result.
@@ -681,16 +707,71 @@ print result.ruleId ' ID of the matching rule
681707

682708
### Advanced Targeting
683709

684-
The SDK version 1.3.1+ supports all GrowthBook advanced targeting rules:
710+
The SDK v2.0.0 supports all GrowthBook advanced targeting rules:
685711

686712
- **Filters**: Complex user segmentation using hash-based filtering.
687-
- **Ranges (Intervals)**: Precise traffic control for experiments and rollouts (v1.1.0+).
713+
- **Ranges (Intervals)**: Precise traffic control for experiments and rollouts.
688714
- **Namespaces**: Mutually exclusive experiments to prevent overlap.
689715
- **Prerequisites**: Dependent feature flags (flag A requires flag B).
690716
- **Forced Variations**: Global variation overrides for testing.
717+
- **Sticky Bucketing**: Persistent variation assignments across sessions.
691718

692719
These are handled automatically by the SDK based on your GrowthBook configuration.
693720

721+
### Encrypted Features
722+
723+
Decrypt encrypted feature payloads from the GrowthBook API. Requires Roku OS 9.2+.
724+
725+
```brightscript
726+
gb = GrowthBook({
727+
clientKey: "sdk_YOUR_KEY",
728+
decryptionKey: "your-base64-decryption-key",
729+
attributes: { id: "user-123" }
730+
})
731+
gb.init() ' Encrypted features are decrypted automatically
732+
```
733+
734+
### Sticky Bucketing
735+
736+
Persist experiment assignments so users always see the same variation, even across sessions or after attribute changes.
737+
738+
```brightscript
739+
' In-memory (for testing or single-session use)
740+
sbs = GrowthBookInMemoryStickyBucketService()
741+
742+
' Registry-based (persists across app restarts)
743+
sbs = GrowthBookRegistryStickyBucketService()
744+
745+
gb = GrowthBook({
746+
clientKey: "sdk_YOUR_KEY",
747+
attributes: { id: "user-123" },
748+
stickyBucketService: sbs
749+
})
750+
gb.init()
751+
```
752+
753+
### Tracking Plugins
754+
755+
Register plugins to receive experiment and feature usage events. The built-in `GrowthBookTrackingPlugin` sends batched events to a configurable HTTP endpoint.
756+
757+
```brightscript
758+
plugin = GrowthBookTrackingPlugin({
759+
ingestorHost: "https://analytics.example.com",
760+
clientKey: "sdk_YOUR_KEY",
761+
batchSize: 10
762+
})
763+
764+
gb = GrowthBook({
765+
clientKey: "sdk_YOUR_KEY",
766+
attributes: { id: "user-123" }
767+
})
768+
gb.init()
769+
gb.registerTrackingPlugin(plugin)
770+
771+
' Events are batched and sent automatically
772+
if gb.isOn("new-feature") then doSomething()
773+
```
774+
694775
## Examples
695776

696777
See the `examples/` directory for complete working examples:
@@ -769,8 +850,8 @@ Minimum Roku OS: 9.0+
769850

770851
- No Server-Sent Events (SSE) streaming support (Roku limitation)
771852
- No Visual Editor experiments (SceneGraph only)
772-
- AES decryption requires `roEVPCipher` component (Roku OS 9.2+)
773-
- Network requests are asynchronous only
853+
- Encrypted features require `roEVPCipher` component (Roku OS 9.2+)
854+
- Network requests are synchronous (no background polling)
774855

775856
## Contributing
776857

0 commit comments

Comments
 (0)