featurehub-sdk 1.2.3 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.claude/CLAUDE.md +85 -0
- data/.rubocop.yml +4 -2
- data/.ruby-version +1 -1
- data/CHANGELOG.md +17 -0
- data/Gemfile +3 -3
- data/Gemfile.lock +136 -63
- data/LICENSE +21 -0
- data/README.md +422 -0
- data/examples/rails_example/.env.example +13 -0
- data/examples/rails_example/.gitattributes +7 -0
- data/examples/rails_example/.gitignore +103 -0
- data/examples/rails_example/.ruby-version +1 -0
- data/examples/rails_example/Dockerfile +12 -0
- data/examples/rails_example/Gemfile +80 -0
- data/examples/rails_example/Gemfile.lock +283 -0
- data/examples/rails_example/README.md +36 -0
- data/examples/rails_example/Rakefile +8 -0
- data/examples/rails_example/app/assets/config/manifest.js +4 -0
- data/examples/rails_example/app/assets/images/.keep +0 -0
- data/examples/rails_example/app/assets/stylesheets/application.css +15 -0
- data/examples/rails_example/app/channels/application_cable/channel.rb +6 -0
- data/examples/rails_example/app/channels/application_cable/connection.rb +6 -0
- data/examples/rails_example/app/controllers/application_controller.rb +4 -0
- data/examples/rails_example/app/controllers/concerns/.keep +0 -0
- data/examples/rails_example/app/controllers/home_controller.rb +12 -0
- data/examples/rails_example/app/helpers/application_helper.rb +4 -0
- data/examples/rails_example/app/helpers/home_helper.rb +4 -0
- data/examples/rails_example/app/javascript/application.js +3 -0
- data/examples/rails_example/app/javascript/controllers/application.js +9 -0
- data/examples/rails_example/app/javascript/controllers/hello_controller.js +7 -0
- data/examples/rails_example/app/javascript/controllers/index.js +11 -0
- data/examples/rails_example/app/jobs/application_job.rb +9 -0
- data/examples/rails_example/app/mailers/application_mailer.rb +6 -0
- data/examples/rails_example/app/models/application_record.rb +5 -0
- data/examples/rails_example/app/models/concerns/.keep +0 -0
- data/examples/rails_example/app/views/home/index.html.erb +6 -0
- data/examples/rails_example/app/views/layouts/application.html.erb +16 -0
- data/examples/rails_example/app/views/layouts/mailer.html.erb +13 -0
- data/examples/rails_example/app/views/layouts/mailer.text.erb +1 -0
- data/examples/rails_example/bin/bundle +118 -0
- data/examples/rails_example/bin/importmap +5 -0
- data/examples/rails_example/bin/rails +6 -0
- data/examples/rails_example/bin/rake +6 -0
- data/examples/rails_example/bin/setup +35 -0
- data/examples/rails_example/config/application.rb +24 -0
- data/examples/rails_example/config/boot.rb +6 -0
- data/examples/rails_example/config/cable.yml +10 -0
- data/examples/rails_example/config/credentials.yml.enc +1 -0
- data/examples/rails_example/config/database.yml +25 -0
- data/examples/rails_example/config/environment.rb +7 -0
- data/examples/rails_example/config/environments/development.rb +72 -0
- data/examples/rails_example/config/environments/production.rb +95 -0
- data/examples/rails_example/config/environments/test.rb +62 -0
- data/examples/rails_example/config/importmap.rb +9 -0
- data/examples/rails_example/config/initializers/assets.rb +14 -0
- data/examples/rails_example/config/initializers/content_security_policy.rb +27 -0
- data/examples/rails_example/config/initializers/featurehub.rb +8 -0
- data/examples/rails_example/config/initializers/filter_parameter_logging.rb +10 -0
- data/examples/rails_example/config/initializers/inflections.rb +18 -0
- data/examples/rails_example/config/initializers/permissions_policy.rb +13 -0
- data/examples/rails_example/config/locales/en.yml +33 -0
- data/examples/rails_example/config/puma.rb +57 -0
- data/examples/rails_example/config/routes.rb +8 -0
- data/examples/rails_example/config/storage.yml +34 -0
- data/examples/rails_example/config.ru +8 -0
- data/examples/rails_example/db/seeds.rb +9 -0
- data/examples/rails_example/lib/assets/.keep +0 -0
- data/examples/rails_example/lib/tasks/.keep +0 -0
- data/examples/rails_example/log/.keep +0 -0
- data/examples/rails_example/public/404.html +67 -0
- data/examples/rails_example/public/422.html +67 -0
- data/examples/rails_example/public/500.html +66 -0
- data/examples/rails_example/public/apple-touch-icon-precomposed.png +0 -0
- data/examples/rails_example/public/apple-touch-icon.png +0 -0
- data/examples/rails_example/public/favicon.ico +0 -0
- data/examples/rails_example/public/robots.txt +1 -0
- data/examples/rails_example/storage/.keep +0 -0
- data/examples/rails_example/test/application_system_test_case.rb +7 -0
- data/examples/rails_example/test/channels/application_cable/connection_test.rb +15 -0
- data/examples/rails_example/test/controllers/.keep +0 -0
- data/examples/rails_example/test/controllers/home_controller_test.rb +9 -0
- data/examples/rails_example/test/fixtures/files/.keep +0 -0
- data/examples/rails_example/test/helpers/.keep +0 -0
- data/examples/rails_example/test/integration/.keep +0 -0
- data/examples/rails_example/test/mailers/.keep +0 -0
- data/examples/rails_example/test/models/.keep +0 -0
- data/examples/rails_example/test/system/.keep +0 -0
- data/examples/rails_example/test/test_helper.rb +17 -0
- data/examples/rails_example/tmp/.keep +0 -0
- data/examples/rails_example/tmp/pids/.keep +0 -0
- data/examples/rails_example/tmp/storage/.keep +0 -0
- data/examples/rails_example/vendor/.keep +0 -0
- data/examples/rails_example/vendor/javascript/.keep +0 -0
- data/examples/sinatra/.dockerignore +7 -0
- data/examples/sinatra/.gitignore +3 -0
- data/examples/sinatra/.ruby-version +1 -0
- data/examples/sinatra/Dockerfile +31 -0
- data/examples/sinatra/Gemfile +17 -0
- data/examples/sinatra/Gemfile.lock +94 -0
- data/examples/sinatra/README.adoc +10 -0
- data/examples/sinatra/app/application.rb +153 -0
- data/examples/sinatra/build.sh +2 -0
- data/examples/sinatra/conf/nginx.conf +57 -0
- data/examples/sinatra/conf/nsswitch.conf +21 -0
- data/examples/sinatra/config.ru +17 -0
- data/examples/sinatra/docker-compose.yaml +24 -0
- data/examples/sinatra/docker_start.sh +3 -0
- data/examples/sinatra/feature-flags.yaml +6 -0
- data/examples/sinatra/sinatra.iml +43 -0
- data/examples/sinatra/start.sh +5 -0
- data/examples/sinatra/thin.ru +9 -0
- data/featurehub-ruby-sdk.iml +9 -0
- data/featurehub-sdk.gemspec +45 -0
- data/lib/feature_hub/sdk/context.rb +28 -7
- data/lib/feature_hub/sdk/feature_hub_config.rb +68 -14
- data/lib/feature_hub/sdk/feature_repository.rb +52 -13
- data/lib/feature_hub/sdk/{feature_state.rb → feature_state_holder.rb} +13 -9
- data/lib/feature_hub/sdk/impl/rollout_holders.rb +3 -3
- data/lib/feature_hub/sdk/interceptors.rb +10 -6
- data/lib/feature_hub/sdk/internal_feature_repository.rb +7 -3
- data/lib/feature_hub/sdk/local_yaml_interceptor.rb +99 -0
- data/lib/feature_hub/sdk/local_yaml_store.rb +71 -0
- data/lib/feature_hub/sdk/poll_edge_service.rb +6 -11
- data/lib/feature_hub/sdk/raw_update_feature_listener.rb +19 -0
- data/lib/feature_hub/sdk/redis_session_store.rb +130 -0
- data/lib/feature_hub/sdk/strategy_attributes.rb +7 -0
- data/lib/feature_hub/sdk/streaming_edge_service.rb +5 -7
- data/lib/feature_hub/sdk/version.rb +2 -2
- data/lib/featurehub-sdk.rb +5 -1
- data/sig/feature_hub/featurehub.rbs +127 -28
- metadata +137 -14
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c3c5127a58f5d1a4c63242919d593399ee0e097dcbd54239584d3620eb00f5a9
|
|
4
|
+
data.tar.gz: 4de3a2a249d35c6dfd52249a6b42171cd27e9aac8ed4c95f2c0efdaa9947663b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9a41c73c154804782a9795337e33de707a482f2fedb41337783222f561ce1eccae41dfca59ad393a36d9fa8d214f8f54778b016092de3c04e4c9d83c9da44a95
|
|
7
|
+
data.tar.gz: aac1dfb0a3d61d77f4046b9710f146ce0f2d0562a7c324e8e03c43c7276c5eb555322f9b3e49543aeb9958b1b4328b15dc003c29da682160a3b29ac782c830af
|
data/.claude/CLAUDE.md
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# CLAUDE.md
|
|
2
|
+
|
|
3
|
+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
4
|
+
|
|
5
|
+
## Commands
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
bundle install # Install dependencies
|
|
9
|
+
bundle exec rake # Run tests + linting (default)
|
|
10
|
+
bundle exec rspec # Run tests only
|
|
11
|
+
bundle exec rubocop # Lint only
|
|
12
|
+
|
|
13
|
+
# Run a single test file
|
|
14
|
+
bundle exec rspec spec/feature_hub/sdk/feature_hub_config_spec.rb
|
|
15
|
+
|
|
16
|
+
# Run a specific test by line number
|
|
17
|
+
bundle exec rspec spec/feature_hub/sdk/feature_hub_config_spec.rb:42
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Architecture
|
|
21
|
+
|
|
22
|
+
This is the FeatureHub Ruby SDK (gem: `featurehub-sdk`, version 2.0.0), targeting Ruby >= 3.2. All code lives under `lib/feature_hub/sdk/` and is namespaced as `FeatureHub::Sdk`.
|
|
23
|
+
|
|
24
|
+
### Core Data Flow
|
|
25
|
+
|
|
26
|
+
```
|
|
27
|
+
FeatureHubConfig.init(url, api_key)
|
|
28
|
+
→ creates EdgeService (streaming SSE or polling HTTP)
|
|
29
|
+
→ edge service receives feature JSON from FeatureHub server
|
|
30
|
+
→ FeatureHubRepository stores feature states
|
|
31
|
+
|
|
32
|
+
config.new_context().user_key("id").build()
|
|
33
|
+
→ ClientEvalContext: polls edge, evaluates strategies locally
|
|
34
|
+
→ ServerEvalContext: sends context as HTTP header, server evaluates
|
|
35
|
+
|
|
36
|
+
context.feature("MY_FLAG").boolean
|
|
37
|
+
→ FeatureStateHolder checks interceptors, then calls repository.apply(strategies, ctx)
|
|
38
|
+
→ ApplyFeature matches rollout strategies, returns Applied(value)
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Key Classes
|
|
42
|
+
|
|
43
|
+
- **FeatureHubConfig** ([feature_hub_config.rb](lib/feature_hub/sdk/feature_hub_config.rb)): Entry point. Detects client vs server evaluation by checking for `*` in the API key. Manages edge service lifecycle. Call `new_context()` to get a context builder.
|
|
44
|
+
|
|
45
|
+
- **FeatureHubRepository** ([feature_repository.rb](lib/feature_hub/sdk/feature_repository.rb)): Stores features as a hash (symbol keys → `FeatureStateHolder`). Notifies listeners on changes (`:features`, `:feature`, `:delete_feature`, `:failed`). Checks interceptors before applying strategies. Tracks readiness via `@ready`.
|
|
46
|
+
|
|
47
|
+
- **FeatureStateHolder** ([feature_state_holder.rb](lib/feature_hub/sdk/feature_state_holder.rb)): Wraps feature JSON (`key`, `id`, `type`, `value`, `version`, `l` (locked), `strategies`). Provides typed accessors: `.flag`, `.string`, `.number`, `.raw_json`, `.boolean`. Supports `with_context(ctx)` for strategy evaluation.
|
|
48
|
+
|
|
49
|
+
- **Context classes** ([context.rb](lib/feature_hub/sdk/context.rb)): Fluent builder pattern — `context.user_key("x").platform("ios").country("gb").build()`. Attributes stored as `symbol → [array]`. Two subclasses: `ClientEvalFeatureContext` (local strategy eval) and `ServerEvalFeatureContext` (server-side eval, sends `x-featurehub` header).
|
|
50
|
+
|
|
51
|
+
- **Edge services**: `StreamingEdgeService` ([streaming_edge_service.rb](lib/feature_hub/sdk/streaming_edge_service.rb)) uses SSE via `ld-eventsource`. `PollingEdgeService` ([poll_edge_service.rb](lib/feature_hub/sdk/poll_edge_service.rb)) uses Faraday with `Concurrent::TimerTask`, supports ETags. Call `force_new_edge_service()` after process fork (Puma/Passenger/Unicorn).
|
|
52
|
+
|
|
53
|
+
- **ApplyFeature** ([impl/apply_features.rb](lib/feature_hub/sdk/impl/apply_features.rb)): Client-side strategy evaluator. Iterates rollout strategies, calculates percentage allocation via Murmur3 hash of `percentage_key + feature_id`, matches attribute conditions via `MatcherRegistry`. Returns `Applied(matched:, value:)`.
|
|
54
|
+
|
|
55
|
+
- **EnvironmentInterceptor** ([interceptors.rb](lib/feature_hub/sdk/interceptors.rb)): Override features at runtime via `FEATUREHUB_OVERRIDE_FEATURES=true` + `FEATUREHUB_<FEATURE_NAME>=<value>` env vars.
|
|
56
|
+
|
|
57
|
+
### Client vs Server Evaluation
|
|
58
|
+
|
|
59
|
+
- **Client-evaluated** API key contains `*` (e.g., `abc*def`): full strategy data sent to SDK, evaluated locally by `ApplyFeature`.
|
|
60
|
+
- **Server-evaluated** API key has no `*`: context attributes sent as `x-featurehub` HTTP header, server evaluates and returns resolved values.
|
|
61
|
+
|
|
62
|
+
### Strategy Attribute Matchers
|
|
63
|
+
|
|
64
|
+
`MatcherRegistry` dispatches to typed matchers based on `field_type`: `BOOLEAN`, `STRING`/`DATE`/`DATE_TIME` (via `StringMatcher`), `NUMBER`, `SEMANTIC_VERSION` (uses `sem_version` gem), `IP_ADDRESS` (CIDR support). All conditions in a strategy must match for the strategy to apply.
|
|
65
|
+
|
|
66
|
+
## RBS Type Signatures
|
|
67
|
+
|
|
68
|
+
Type definitions live in [sig/feature_hub/featurehub.rbs](sig/feature_hub/featurehub.rbs). Key signatures to be aware of:
|
|
69
|
+
|
|
70
|
+
- **Feature value type**: `[bool? | String? | Float?]` — the union type used throughout for feature values (`Applied#value`, `FeatureStateHolder#value`, `RolloutStrategy#value`, `InterceptorValue`)
|
|
71
|
+
- **`FeatureStateHolder#initialize`** takes `key:`, `repo:`, `feature_state:`, `parent_state:`, and `ctx:` — the `parent_state` and `ctx` support the `with_context` pattern for context-scoped evaluation
|
|
72
|
+
- **`InternalFeatureRepository`** is the abstract interface that `FeatureHubRepository` implements; `FeatureStateHolder` and context classes depend on this interface, not the concrete class
|
|
73
|
+
- **`ClientContext#build`** returns `ClientContext` (async); **`build_sync`** also returns `ClientContext` (blocking)
|
|
74
|
+
- **`FeatureHubConfig#repository`** takes an optional `InternalFeatureRepository?` and returns one — it acts as both getter and setter
|
|
75
|
+
- **`RolloutStrategyAttribute`**: `values` is `Array[[bool? | String? | Float?]]`; use `float_values` / `str_values` for typed access
|
|
76
|
+
- **`RolloutStrategyCondition`**: predicate methods only (e.g., `equals?`, `regex?`, `includes?`) — no raw string comparison against condition type strings
|
|
77
|
+
|
|
78
|
+
## Conventions
|
|
79
|
+
|
|
80
|
+
- `# frozen_string_literal: true` on every file
|
|
81
|
+
- Double-quoted strings (RuboCop enforced)
|
|
82
|
+
- Feature keys stored/looked up as symbols internally
|
|
83
|
+
- RuboCop: max line length 120, metrics cops disabled, documentation disabled
|
|
84
|
+
- Tests mirror lib structure: `spec/feature_hub/sdk/**/*_spec.rb`
|
|
85
|
+
- Use `instance_double` for mocking, `aggregate_failures` for multiple assertions
|
data/.rubocop.yml
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
AllCops:
|
|
2
|
-
TargetRubyVersion: 2
|
|
2
|
+
TargetRubyVersion: 3.2
|
|
3
3
|
|
|
4
4
|
Style/StringLiterals:
|
|
5
5
|
Enabled: true
|
|
@@ -35,7 +35,7 @@ Metrics/CyclomaticComplexity:
|
|
|
35
35
|
Naming/FileName:
|
|
36
36
|
Enabled: false
|
|
37
37
|
|
|
38
|
-
Gemspec/
|
|
38
|
+
Gemspec/DeprecatedAttributeAssignment:
|
|
39
39
|
Enabled: true
|
|
40
40
|
Gemspec/DeprecatedAttributeAssignment: # new in 1.30
|
|
41
41
|
Enabled: true
|
|
@@ -101,6 +101,8 @@ Style/ArgumentsForwarding: # new in 1.1
|
|
|
101
101
|
Enabled: true
|
|
102
102
|
Style/CollectionCompact: # new in 1.2
|
|
103
103
|
Enabled: true
|
|
104
|
+
Style/Documentation:
|
|
105
|
+
Enabled: false
|
|
104
106
|
Style/DocumentDynamicEvalDefinition: # new in 1.1
|
|
105
107
|
Enabled: true
|
|
106
108
|
Style/EndlessMethod: # new in 1.8
|
data/.ruby-version
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
3.
|
|
1
|
+
3.3.10
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,20 @@
|
|
|
1
|
+
## [2.0.0] - 2026-03-22
|
|
2
|
+
|
|
3
|
+
- Refactor FeatureState to FeatureStateHolder to be consistent with other SDKs
|
|
4
|
+
- Add FeatureValueType to reduce duplication
|
|
5
|
+
- Add local YAML file interceptor with an optional timer to watch for changes
|
|
6
|
+
- Add `RawUpdateFeatureListener` base class so custom listeners can react to raw edge updates (including update source tracking)
|
|
7
|
+
- Add `LocalYamlStore`: load features from a local YAML file without an Edge server, as an alternative to the value interceptor
|
|
8
|
+
- Add `RedisSessionStore`: persist features in Redis so they survive process restarts and are shared across processes (client-evaluated only)
|
|
9
|
+
- Support punch-through context evaluation for external stores so per-request context attributes are applied even when features come from Redis or YAML
|
|
10
|
+
- Add `value` accessor to `FeatureStateHolder` as a convenience shortcut alongside the typed accessors
|
|
11
|
+
- Edge services now explicitly close the repository on shutdown
|
|
12
|
+
|
|
13
|
+
## [1.3.0] - 2026-01-11
|
|
14
|
+
|
|
15
|
+
- update gem dependencies
|
|
16
|
+
- bump minimum ruby version to 3.2
|
|
17
|
+
|
|
1
18
|
## [1.2.3] - 2024-01-12
|
|
2
19
|
|
|
3
20
|
- fix for Interceptor contributed by Lukas
|
data/Gemfile
CHANGED
|
@@ -13,12 +13,12 @@ gem "rubocop", "~> 1.21"
|
|
|
13
13
|
|
|
14
14
|
gem "simplecov", "~> 0.21"
|
|
15
15
|
|
|
16
|
-
gem "concurrent-ruby", "~> 1.
|
|
16
|
+
gem "concurrent-ruby", "~> 1.3"
|
|
17
17
|
|
|
18
18
|
gem "faraday", "~> 2"
|
|
19
19
|
|
|
20
|
-
gem "murmurhash3", "~> 0.1.
|
|
20
|
+
gem "murmurhash3", "~> 0.1.7"
|
|
21
21
|
|
|
22
22
|
gem "sem_version", "~> 2.0.0"
|
|
23
23
|
|
|
24
|
-
gem "ld-eventsource", "~> 2.
|
|
24
|
+
gem "ld-eventsource", "~> 2.5.1"
|
data/Gemfile.lock
CHANGED
|
@@ -1,107 +1,180 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
featurehub-sdk (
|
|
5
|
-
concurrent-ruby (~> 1.
|
|
4
|
+
featurehub-sdk (2.0.0)
|
|
5
|
+
concurrent-ruby (~> 1.3)
|
|
6
6
|
faraday (~> 2)
|
|
7
|
-
ld-eventsource (~> 2.
|
|
8
|
-
murmurhash3 (~> 0.1.
|
|
7
|
+
ld-eventsource (~> 2.5.1)
|
|
8
|
+
murmurhash3 (~> 0.1.7)
|
|
9
9
|
sem_version (~> 2.0.0)
|
|
10
10
|
|
|
11
11
|
GEM
|
|
12
12
|
remote: https://rubygems.org/
|
|
13
13
|
specs:
|
|
14
|
-
addressable (2.8.
|
|
15
|
-
public_suffix (>= 2.0.2, <
|
|
16
|
-
ast (2.4.
|
|
17
|
-
concurrent-ruby (1.
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
faraday (2.
|
|
23
|
-
faraday-net_http (
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
14
|
+
addressable (2.8.8)
|
|
15
|
+
public_suffix (>= 2.0.2, < 8.0)
|
|
16
|
+
ast (2.4.3)
|
|
17
|
+
concurrent-ruby (1.3.6)
|
|
18
|
+
connection_pool (3.0.2)
|
|
19
|
+
diff-lcs (1.6.2)
|
|
20
|
+
docile (1.4.1)
|
|
21
|
+
domain_name (0.6.20240107)
|
|
22
|
+
faraday (2.14.0)
|
|
23
|
+
faraday-net_http (>= 2.0, < 3.5)
|
|
24
|
+
json
|
|
25
|
+
logger
|
|
26
|
+
faraday-net_http (3.4.2)
|
|
27
|
+
net-http (~> 0.5)
|
|
28
|
+
ffi (1.17.3-arm64-darwin)
|
|
29
|
+
ffi (1.17.3-x86_64-darwin)
|
|
30
|
+
ffi (1.17.3-x86_64-linux-gnu)
|
|
31
|
+
ffi-compiler (1.3.2)
|
|
32
|
+
ffi (>= 1.15.5)
|
|
29
33
|
rake
|
|
30
|
-
http (5.
|
|
34
|
+
http (5.3.1)
|
|
31
35
|
addressable (~> 2.8)
|
|
32
36
|
http-cookie (~> 1.0)
|
|
33
37
|
http-form_data (~> 2.2)
|
|
34
|
-
llhttp-ffi (~> 0.
|
|
35
|
-
http-cookie (1.0
|
|
38
|
+
llhttp-ffi (~> 0.5.0)
|
|
39
|
+
http-cookie (1.1.0)
|
|
36
40
|
domain_name (~> 0.5)
|
|
37
41
|
http-form_data (2.3.0)
|
|
38
|
-
|
|
42
|
+
json (2.19.2)
|
|
43
|
+
language_server-protocol (3.17.0.5)
|
|
44
|
+
ld-eventsource (2.5.1)
|
|
39
45
|
concurrent-ruby (~> 1.0)
|
|
40
46
|
http (>= 4.4.1, < 6.0.0)
|
|
41
|
-
|
|
47
|
+
lint_roller (1.1.0)
|
|
48
|
+
llhttp-ffi (0.5.1)
|
|
42
49
|
ffi-compiler (~> 1.0)
|
|
43
50
|
rake (~> 13.0)
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
51
|
+
logger (1.7.0)
|
|
52
|
+
murmurhash3 (0.1.7)
|
|
53
|
+
net-http (0.9.1)
|
|
54
|
+
uri (>= 0.11.1)
|
|
55
|
+
parallel (1.27.0)
|
|
56
|
+
parser (3.3.10.0)
|
|
47
57
|
ast (~> 2.4.1)
|
|
48
|
-
|
|
58
|
+
racc
|
|
59
|
+
prism (1.6.0)
|
|
60
|
+
public_suffix (6.0.2)
|
|
61
|
+
racc (1.8.1)
|
|
49
62
|
rainbow (3.1.1)
|
|
50
|
-
rake (13.
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
rspec-
|
|
59
|
-
|
|
63
|
+
rake (13.3.1)
|
|
64
|
+
redis (5.4.1)
|
|
65
|
+
redis-client (>= 0.22.0)
|
|
66
|
+
redis-client (0.28.0)
|
|
67
|
+
connection_pool
|
|
68
|
+
regexp_parser (2.11.3)
|
|
69
|
+
rspec (3.13.2)
|
|
70
|
+
rspec-core (~> 3.13.0)
|
|
71
|
+
rspec-expectations (~> 3.13.0)
|
|
72
|
+
rspec-mocks (~> 3.13.0)
|
|
73
|
+
rspec-core (3.13.6)
|
|
74
|
+
rspec-support (~> 3.13.0)
|
|
75
|
+
rspec-expectations (3.13.5)
|
|
60
76
|
diff-lcs (>= 1.2.0, < 2.0)
|
|
61
|
-
rspec-support (~> 3.
|
|
62
|
-
rspec-mocks (3.
|
|
77
|
+
rspec-support (~> 3.13.0)
|
|
78
|
+
rspec-mocks (3.13.7)
|
|
63
79
|
diff-lcs (>= 1.2.0, < 2.0)
|
|
64
|
-
rspec-support (~> 3.
|
|
65
|
-
rspec-support (3.
|
|
66
|
-
rubocop (1.
|
|
80
|
+
rspec-support (~> 3.13.0)
|
|
81
|
+
rspec-support (3.13.6)
|
|
82
|
+
rubocop (1.82.0)
|
|
83
|
+
json (~> 2.3)
|
|
84
|
+
language_server-protocol (~> 3.17.0.2)
|
|
85
|
+
lint_roller (~> 1.1.0)
|
|
67
86
|
parallel (~> 1.10)
|
|
68
|
-
parser (>= 3.
|
|
87
|
+
parser (>= 3.3.0.2)
|
|
69
88
|
rainbow (>= 2.2.2, < 4.0)
|
|
70
|
-
regexp_parser (>=
|
|
71
|
-
|
|
72
|
-
rubocop-ast (>= 1.18.0, < 2.0)
|
|
89
|
+
regexp_parser (>= 2.9.3, < 3.0)
|
|
90
|
+
rubocop-ast (>= 1.48.0, < 2.0)
|
|
73
91
|
ruby-progressbar (~> 1.7)
|
|
74
|
-
unicode-display_width (>=
|
|
75
|
-
rubocop-ast (1.
|
|
76
|
-
parser (>= 3.
|
|
77
|
-
|
|
78
|
-
|
|
92
|
+
unicode-display_width (>= 2.4.0, < 4.0)
|
|
93
|
+
rubocop-ast (1.48.0)
|
|
94
|
+
parser (>= 3.3.7.2)
|
|
95
|
+
prism (~> 1.4)
|
|
96
|
+
ruby-progressbar (1.13.0)
|
|
79
97
|
sem_version (2.0.1)
|
|
80
|
-
simplecov (0.
|
|
98
|
+
simplecov (0.22.0)
|
|
81
99
|
docile (~> 1.1)
|
|
82
100
|
simplecov-html (~> 0.11)
|
|
83
101
|
simplecov_json_formatter (~> 0.1)
|
|
84
|
-
simplecov-html (0.
|
|
102
|
+
simplecov-html (0.13.2)
|
|
85
103
|
simplecov_json_formatter (0.1.4)
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
104
|
+
unicode-display_width (3.2.0)
|
|
105
|
+
unicode-emoji (~> 4.1)
|
|
106
|
+
unicode-emoji (4.2.0)
|
|
107
|
+
uri (1.1.1)
|
|
90
108
|
|
|
91
109
|
PLATFORMS
|
|
92
|
-
|
|
110
|
+
arm64-darwin
|
|
111
|
+
x86_64-darwin-24
|
|
112
|
+
x86_64-linux
|
|
93
113
|
|
|
94
114
|
DEPENDENCIES
|
|
95
|
-
concurrent-ruby (~> 1.
|
|
115
|
+
concurrent-ruby (~> 1.3)
|
|
96
116
|
faraday (~> 2)
|
|
97
117
|
featurehub-sdk!
|
|
98
|
-
ld-eventsource (~> 2.
|
|
99
|
-
murmurhash3 (~> 0.1.
|
|
118
|
+
ld-eventsource (~> 2.5.1)
|
|
119
|
+
murmurhash3 (~> 0.1.7)
|
|
100
120
|
rake (~> 13.0)
|
|
121
|
+
redis (~> 5)
|
|
101
122
|
rspec (~> 3.0)
|
|
102
123
|
rubocop (~> 1.21)
|
|
103
124
|
sem_version (~> 2.0.0)
|
|
104
125
|
simplecov (~> 0.21)
|
|
105
126
|
|
|
127
|
+
CHECKSUMS
|
|
128
|
+
addressable (2.8.8) sha256=7c13b8f9536cf6364c03b9d417c19986019e28f7c00ac8132da4eb0fe393b057
|
|
129
|
+
ast (2.4.3) sha256=954615157c1d6a382bc27d690d973195e79db7f55e9765ac7c481c60bdb4d383
|
|
130
|
+
concurrent-ruby (1.3.6) sha256=6b56837e1e7e5292f9864f34b69c5a2cbc75c0cf5338f1ce9903d10fa762d5ab
|
|
131
|
+
connection_pool (3.0.2) sha256=33fff5ba71a12d2aa26cb72b1db8bba2a1a01823559fb01d29eb74c286e62e0a
|
|
132
|
+
diff-lcs (1.6.2) sha256=9ae0d2cba7d4df3075fe8cd8602a8604993efc0dfa934cff568969efb1909962
|
|
133
|
+
docile (1.4.1) sha256=96159be799bfa73cdb721b840e9802126e4e03dfc26863db73647204c727f21e
|
|
134
|
+
domain_name (0.6.20240107) sha256=5f693b2215708476517479bf2b3802e49068ad82167bcd2286f899536a17d933
|
|
135
|
+
faraday (2.14.0) sha256=8699cfe5d97e55268f2596f9a9d5a43736808a943714e3d9a53e6110593941cd
|
|
136
|
+
faraday-net_http (3.4.2) sha256=f147758260d3526939bf57ecf911682f94926a3666502e24c69992765875906c
|
|
137
|
+
featurehub-sdk (2.0.0)
|
|
138
|
+
ffi (1.17.3-arm64-darwin) sha256=0c690555d4cee17a7f07c04d59df39b2fba74ec440b19da1f685c6579bb0717f
|
|
139
|
+
ffi (1.17.3-x86_64-darwin) sha256=1f211811eb5cfaa25998322cdd92ab104bfbd26d1c4c08471599c511f2c00bb5
|
|
140
|
+
ffi (1.17.3-x86_64-linux-gnu) sha256=3746b01f677aae7b16dc1acb7cb3cc17b3e35bdae7676a3f568153fb0e2c887f
|
|
141
|
+
ffi-compiler (1.3.2) sha256=a94f3d81d12caf5c5d4ecf13980a70d0aeaa72268f3b9cc13358bcc6509184a0
|
|
142
|
+
http (5.3.1) sha256=c50802d8e9be3926cb84ac3b36d1a31fbbac383bc4cbecdce9053cb604231d7d
|
|
143
|
+
http-cookie (1.1.0) sha256=38a5e60d1527eebc396831b8c4b9455440509881219273a6c99943d29eadbb19
|
|
144
|
+
http-form_data (2.3.0) sha256=cc4eeb1361d9876821e31d7b1cf0b68f1cf874b201d27903480479d86448a5f3
|
|
145
|
+
json (2.19.2) sha256=e7e1bd318b2c37c4ceee2444841c86539bc462e81f40d134cf97826cb14e83cf
|
|
146
|
+
language_server-protocol (3.17.0.5) sha256=fd1e39a51a28bf3eec959379985a72e296e9f9acfce46f6a79d31ca8760803cc
|
|
147
|
+
ld-eventsource (2.5.1) sha256=19cb44b7d3f91f76b7401a1b74293b32c723389b2d6f9d81ecb803c628ac1b25
|
|
148
|
+
lint_roller (1.1.0) sha256=2c0c845b632a7d172cb849cc90c1bce937a28c5c8ccccb50dfd46a485003cc87
|
|
149
|
+
llhttp-ffi (0.5.1) sha256=9a25a7fc19311f691a78c9c0ac0fbf4675adbd0cca74310228fdf841018fa7bc
|
|
150
|
+
logger (1.7.0) sha256=196edec7cc44b66cfb40f9755ce11b392f21f7967696af15d274dde7edff0203
|
|
151
|
+
murmurhash3 (0.1.7) sha256=370a2ce2e9ab0711e51554e530b5f63956927a6554a296855f42a1a4a5ed0936
|
|
152
|
+
net-http (0.9.1) sha256=25ba0b67c63e89df626ed8fac771d0ad24ad151a858af2cc8e6a716ca4336996
|
|
153
|
+
parallel (1.27.0) sha256=4ac151e1806b755fb4e2dc2332cbf0e54f2e24ba821ff2d3dcf86bf6dc4ae130
|
|
154
|
+
parser (3.3.10.0) sha256=ce3587fa5cc55a88c4ba5b2b37621b3329aadf5728f9eafa36bbd121462aabd6
|
|
155
|
+
prism (1.6.0) sha256=bfc0281a81718c4872346bc858dc84abd3a60cae78336c65ad35c8fbff641c6b
|
|
156
|
+
public_suffix (6.0.2) sha256=bfa7cd5108066f8c9602e0d6d4114999a5df5839a63149d3e8b0f9c1d3558394
|
|
157
|
+
racc (1.8.1) sha256=4a7f6929691dbec8b5209a0b373bc2614882b55fc5d2e447a21aaa691303d62f
|
|
158
|
+
rainbow (3.1.1) sha256=039491aa3a89f42efa1d6dec2fc4e62ede96eb6acd95e52f1ad581182b79bc6a
|
|
159
|
+
rake (13.3.1) sha256=8c9e89d09f66a26a01264e7e3480ec0607f0c497a861ef16063604b1b08eb19c
|
|
160
|
+
redis (5.4.1) sha256=b5e675b57ad22b15c9bcc765d5ac26f60b675408af916d31527af9bd5a81faae
|
|
161
|
+
redis-client (0.28.0) sha256=888892f9cd8787a41c0ece00bdf5f556dfff7770326ce40bb2bc11f1bfec824b
|
|
162
|
+
regexp_parser (2.11.3) sha256=ca13f381a173b7a93450e53459075c9b76a10433caadcb2f1180f2c741fc55a4
|
|
163
|
+
rspec (3.13.2) sha256=206284a08ad798e61f86d7ca3e376718d52c0bc944626b2349266f239f820587
|
|
164
|
+
rspec-core (3.13.6) sha256=a8823c6411667b60a8bca135364351dda34cd55e44ff94c4be4633b37d828b2d
|
|
165
|
+
rspec-expectations (3.13.5) sha256=33a4d3a1d95060aea4c94e9f237030a8f9eae5615e9bd85718fe3a09e4b58836
|
|
166
|
+
rspec-mocks (3.13.7) sha256=0979034e64b1d7a838aaaddf12bf065ea4dc40ef3d4c39f01f93ae2c66c62b1c
|
|
167
|
+
rspec-support (3.13.6) sha256=2e8de3702427eab064c9352fe74488cc12a1bfae887ad8b91cba480ec9f8afb2
|
|
168
|
+
rubocop (1.82.0) sha256=237b7dc24952d7ec469a9593c7a5283315515e2e7dc24ac91532819c254fc4ec
|
|
169
|
+
rubocop-ast (1.48.0) sha256=22df9bbf3f7a6eccde0fad54e68547ae1e2a704bf8719e7c83813a99c05d2e76
|
|
170
|
+
ruby-progressbar (1.13.0) sha256=80fc9c47a9b640d6834e0dc7b3c94c9df37f08cb072b7761e4a71e22cff29b33
|
|
171
|
+
sem_version (2.0.1) sha256=6d97d4f67e28546ba90b3c290f901d6c8031ddb8e08bce962139739c4d40b183
|
|
172
|
+
simplecov (0.22.0) sha256=fe2622c7834ff23b98066bb0a854284b2729a569ac659f82621fc22ef36213a5
|
|
173
|
+
simplecov-html (0.13.2) sha256=bd0b8e54e7c2d7685927e8d6286466359b6f16b18cb0df47b508e8d73c777246
|
|
174
|
+
simplecov_json_formatter (0.1.4) sha256=529418fbe8de1713ac2b2d612aa3daa56d316975d307244399fa4838c601b428
|
|
175
|
+
unicode-display_width (3.2.0) sha256=0cdd96b5681a5949cdbc2c55e7b420facae74c4aaf9a9815eee1087cb1853c42
|
|
176
|
+
unicode-emoji (4.2.0) sha256=519e69150f75652e40bf736106cfbc8f0f73aa3fb6a65afe62fefa7f80b0f80f
|
|
177
|
+
uri (1.1.1) sha256=379fa58d27ffb1387eaada68c749d1426738bd0f654d812fcc07e7568f5c57c6
|
|
178
|
+
|
|
106
179
|
BUNDLED WITH
|
|
107
|
-
|
|
180
|
+
4.0.3
|
data/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2022 FeatureHub
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|