smplkit 1.0.14 → 1.0.15
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/README.md +14 -3
- data/lib/smplkit/client.rb +15 -11
- data/lib/smplkit/config/helpers.rb +0 -26
- data/lib/smplkit/config_resolution.rb +6 -4
- data/lib/smplkit/errors.rb +2 -2
- data/lib/smplkit/flags/helpers.rb +0 -24
- data/lib/smplkit/flags/models.rb +1 -1
- data/lib/smplkit/logging/client.rb +4 -0
- data/lib/smplkit/logging/helpers.rb +0 -26
- data/lib/smplkit/ws.rb +9 -5
- metadata +32 -14
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d5d5ed1af296c517f09ddd0a76660b157184f3bb763a61ae0fcf727c1a3f5a87
|
|
4
|
+
data.tar.gz: 487bcd0200af912fcbb1acdf52967e87bf485c1b1ced27fb564cfc96ac4ee41b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 78bd324f3ab4c18732cf2a0a4bbef41f761ebf347501d721b941083ee4a06657bbd5f3c48e0113e63522515ed5b15566b47ecc727613925b8df866b4459d4f6e
|
|
7
|
+
data.tar.gz: f66aa64fdd45800335739c0d5a8fda29e4b8c51d70c94f5412ee1bdc44f09d161ded9eefd5c9252f438796c2063d53dcdad870dd949b4d2872b9751b6c54d974
|
data/README.md
CHANGED
|
@@ -100,12 +100,23 @@ This creates `config/initializers/smplkit.rb` with documented examples for the p
|
|
|
100
100
|
|
|
101
101
|
```bash
|
|
102
102
|
bundle install
|
|
103
|
-
bundle exec rspec # unit tests
|
|
103
|
+
bundle exec rspec # unit tests — wrapper layer is held to 100% line coverage in CI
|
|
104
104
|
bundle exec rubocop # lint
|
|
105
|
-
make generate # regenerate clients
|
|
105
|
+
make generate # regenerate clients
|
|
106
106
|
```
|
|
107
107
|
|
|
108
|
-
|
|
108
|
+
`make generate` shells out to `npx --yes @openapitools/openapi-generator-cli`,
|
|
109
|
+
so it requires:
|
|
110
|
+
|
|
111
|
+
- Node.js 18+ (provides `npx`)
|
|
112
|
+
- A JRE 11+ (the openapi-generator JAR runs under Java)
|
|
113
|
+
|
|
114
|
+
Both are pre-installed on the CI matrix runners. On a developer machine,
|
|
115
|
+
install via Homebrew (`brew install node openjdk`) or your distribution's
|
|
116
|
+
package manager.
|
|
117
|
+
|
|
118
|
+
The repository follows the standard smplkit "every commit lands on `main`"
|
|
119
|
+
workflow — see CLAUDE.md.
|
|
109
120
|
|
|
110
121
|
## License
|
|
111
122
|
|
data/lib/smplkit/client.rb
CHANGED
|
@@ -31,8 +31,8 @@ module Smplkit
|
|
|
31
31
|
attr_reader :manage, :config, :flags, :logging
|
|
32
32
|
|
|
33
33
|
# Construct, yield to the block, and close on exit.
|
|
34
|
-
def self.open(**)
|
|
35
|
-
client = new(**)
|
|
34
|
+
def self.open(**kwargs)
|
|
35
|
+
client = new(**kwargs)
|
|
36
36
|
begin
|
|
37
37
|
yield client
|
|
38
38
|
ensure
|
|
@@ -185,19 +185,23 @@ module Smplkit
|
|
|
185
185
|
|
|
186
186
|
def schedule_periodic_flush
|
|
187
187
|
@flush_timer = Concurrent::TimerTask.new(execution_interval: PERIODIC_FLUSH_INTERVAL) do
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
begin
|
|
191
|
-
@manage.contexts.flush
|
|
192
|
-
@manage.flags.flush
|
|
193
|
-
@manage.loggers.flush
|
|
194
|
-
rescue StandardError => e
|
|
195
|
-
Smplkit.debug("registration", "periodic flush failed: #{e.class}: #{e.message}")
|
|
196
|
-
end
|
|
188
|
+
run_periodic_flush
|
|
197
189
|
end
|
|
198
190
|
@flush_timer.execute
|
|
199
191
|
end
|
|
200
192
|
|
|
193
|
+
# Extracted as a private method so the timer body is reachable from
|
|
194
|
+
# tests without poking into Concurrent::TimerTask internals.
|
|
195
|
+
def run_periodic_flush
|
|
196
|
+
return if @closed
|
|
197
|
+
|
|
198
|
+
@manage.contexts.flush
|
|
199
|
+
@manage.flags.flush
|
|
200
|
+
@manage.loggers.flush
|
|
201
|
+
rescue StandardError => e
|
|
202
|
+
Smplkit.debug("registration", "periodic flush failed: #{e.class}: #{e.message}")
|
|
203
|
+
end
|
|
204
|
+
|
|
201
205
|
def final_flush
|
|
202
206
|
[@manage.contexts, @manage.flags, @manage.loggers].each do |ns|
|
|
203
207
|
ns.flush
|
|
@@ -40,32 +40,6 @@ module Smplkit
|
|
|
40
40
|
)
|
|
41
41
|
end
|
|
42
42
|
|
|
43
|
-
def build_config_request_body(config)
|
|
44
|
-
items = {}
|
|
45
|
-
config.items.each do |item|
|
|
46
|
-
items[item.name] = {
|
|
47
|
-
"value" => item.value,
|
|
48
|
-
"type" => item.type,
|
|
49
|
-
"description" => item.description
|
|
50
|
-
}.compact
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
environments = config.environments.each_with_object({}) do |(env, env_obj), out|
|
|
54
|
-
out[env] = { "values" => env_obj.values_raw }
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
# The Config schema (per the OpenAPI spec) does not include +key+ in
|
|
58
|
-
# attributes — the resource +id+ carries the customer-facing key.
|
|
59
|
-
attributes = {
|
|
60
|
-
"name" => config.name,
|
|
61
|
-
"description" => config.description,
|
|
62
|
-
"parent" => config.parent_id,
|
|
63
|
-
"items" => items,
|
|
64
|
-
"environments" => environments
|
|
65
|
-
}.compact
|
|
66
|
-
{ "data" => { "type" => "config", "id" => config.key, "attributes" => attributes } }
|
|
67
|
-
end
|
|
68
|
-
|
|
69
43
|
# Deep-merge two Hashes, with +override+ winning. Mirrors the Python
|
|
70
44
|
# +deep_merge+ helper used by the resolver.
|
|
71
45
|
def deep_merge(base, override)
|
|
@@ -28,12 +28,14 @@ module Smplkit
|
|
|
28
28
|
"telemetry" => true
|
|
29
29
|
}.freeze
|
|
30
30
|
|
|
31
|
-
ResolvedConfig =
|
|
32
|
-
:api_key, :base_domain, :scheme, :environment, :service, :debug, :telemetry
|
|
31
|
+
ResolvedConfig = Struct.new(
|
|
32
|
+
:api_key, :base_domain, :scheme, :environment, :service, :debug, :telemetry,
|
|
33
|
+
keyword_init: true
|
|
33
34
|
)
|
|
34
35
|
|
|
35
|
-
ResolvedManagementConfig =
|
|
36
|
-
:api_key, :base_domain, :scheme, :debug
|
|
36
|
+
ResolvedManagementConfig = Struct.new(
|
|
37
|
+
:api_key, :base_domain, :scheme, :debug,
|
|
38
|
+
keyword_init: true
|
|
37
39
|
)
|
|
38
40
|
|
|
39
41
|
module_function
|
data/lib/smplkit/errors.rb
CHANGED
|
@@ -47,30 +47,6 @@ module Smplkit
|
|
|
47
47
|
rules: rules
|
|
48
48
|
)
|
|
49
49
|
end
|
|
50
|
-
|
|
51
|
-
# Build the JSON body for a Flag create/update request.
|
|
52
|
-
def build_flag_request_body(flag)
|
|
53
|
-
environments = flag.environments.each_with_object({}) do |(env_key, env), out|
|
|
54
|
-
out[env_key] = {
|
|
55
|
-
"enabled" => env.enabled,
|
|
56
|
-
"default" => env.default,
|
|
57
|
-
"rules" => env.rules.map { |r| { "logic" => r.logic, "value" => r.value, "description" => r.description } }
|
|
58
|
-
}
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
attributes = {
|
|
62
|
-
"id" => flag.id,
|
|
63
|
-
"name" => flag.name,
|
|
64
|
-
"type" => flag.type,
|
|
65
|
-
"default" => flag.default,
|
|
66
|
-
"description" => flag.description,
|
|
67
|
-
"environments" => environments
|
|
68
|
-
}
|
|
69
|
-
values = flag.values
|
|
70
|
-
attributes["values"] = values.map { |v| { "name" => v.name, "value" => v.value } } if values
|
|
71
|
-
|
|
72
|
-
{ "data" => { "type" => "flag", "id" => flag.id, "attributes" => attributes.compact } }
|
|
73
|
-
end
|
|
74
50
|
end
|
|
75
51
|
end
|
|
76
52
|
end
|
data/lib/smplkit/flags/models.rb
CHANGED
|
@@ -6,7 +6,7 @@ module Smplkit
|
|
|
6
6
|
#
|
|
7
7
|
# Lives in +Flag#values+. Frozen — author values via +Flag#add_value+ /
|
|
8
8
|
# +Flag#remove_value+ / +Flag#clear_values+.
|
|
9
|
-
FlagValue =
|
|
9
|
+
FlagValue = Struct.new(:name, :value, keyword_init: true)
|
|
10
10
|
|
|
11
11
|
# A single targeting rule on a +Flag+.
|
|
12
12
|
#
|
|
@@ -102,7 +102,11 @@ module Smplkit
|
|
|
102
102
|
|
|
103
103
|
return unless @adapters.empty?
|
|
104
104
|
|
|
105
|
+
# :nocov: defensive log — unreachable in practice because stdlib
|
|
106
|
+
# +Logger+ is always present, so +StdlibLoggerAdapter+ is always
|
|
107
|
+
# constructible.
|
|
105
108
|
Smplkit.debug("registration", "no logging adapters loaded; runtime features disabled")
|
|
109
|
+
# :nocov:
|
|
106
110
|
end
|
|
107
111
|
|
|
108
112
|
def observe_logger(_adapter, raw_name, level)
|
|
@@ -38,32 +38,6 @@ module Smplkit
|
|
|
38
38
|
updated_at: attrs["updated_at"]
|
|
39
39
|
)
|
|
40
40
|
end
|
|
41
|
-
|
|
42
|
-
def build_logger_body(logger)
|
|
43
|
-
attributes = {
|
|
44
|
-
"name" => logger.name,
|
|
45
|
-
"resolved_level" => logger.resolved_level&.to_s,
|
|
46
|
-
"level" => logger.level&.to_s,
|
|
47
|
-
"service" => logger.service,
|
|
48
|
-
"environment" => logger.environment,
|
|
49
|
-
"log_group_id" => logger.log_group_id,
|
|
50
|
-
"managed" => logger.managed,
|
|
51
|
-
"description" => logger.description
|
|
52
|
-
}.compact
|
|
53
|
-
{ "data" => { "type" => "logger", "id" => logger.id, "attributes" => attributes } }
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
def build_log_group_body(group)
|
|
57
|
-
attributes = {
|
|
58
|
-
"key" => group.key,
|
|
59
|
-
"name" => group.name,
|
|
60
|
-
"level" => group.level&.to_s,
|
|
61
|
-
"description" => group.description,
|
|
62
|
-
"parent_id" => group.parent_id,
|
|
63
|
-
"environments" => group.environments
|
|
64
|
-
}.compact
|
|
65
|
-
{ "data" => { "type" => "log_group", "id" => group.key, "attributes" => attributes } }
|
|
66
|
-
end
|
|
67
41
|
end
|
|
68
42
|
end
|
|
69
43
|
end
|
data/lib/smplkit/ws.rb
CHANGED
|
@@ -90,14 +90,16 @@ module Smplkit
|
|
|
90
90
|
def stop
|
|
91
91
|
Smplkit.debug("websocket", "stopping shared WebSocket")
|
|
92
92
|
@closed = true
|
|
93
|
-
@connection_status = "disconnected"
|
|
94
93
|
close_active_connection
|
|
95
94
|
thread = @ws_thread
|
|
96
95
|
@ws_thread = nil
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
96
|
+
if thread
|
|
97
|
+
thread.join(2.0)
|
|
98
|
+
thread.kill if thread.alive?
|
|
99
|
+
end
|
|
100
|
+
# Set authoritatively after the thread is dead so a racing connect
|
|
101
|
+
# call (which also sets "connecting") cannot clobber this value.
|
|
102
|
+
@connection_status = "disconnected"
|
|
101
103
|
end
|
|
102
104
|
|
|
103
105
|
# ----- URL builder ----------------------------------------------
|
|
@@ -169,6 +171,8 @@ module Smplkit
|
|
|
169
171
|
end
|
|
170
172
|
|
|
171
173
|
def connect(task)
|
|
174
|
+
return if @closed
|
|
175
|
+
|
|
172
176
|
url = build_ws_url
|
|
173
177
|
@connection_status = "connecting"
|
|
174
178
|
Smplkit.debug("websocket", "connecting to #{safe_url}")
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: smplkit
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.0.
|
|
4
|
+
version: 1.0.15
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Smpl Solutions LLC
|
|
@@ -13,44 +13,62 @@ dependencies:
|
|
|
13
13
|
name: async
|
|
14
14
|
requirement: !ruby/object:Gem::Requirement
|
|
15
15
|
requirements:
|
|
16
|
-
- - "
|
|
16
|
+
- - ">="
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '2.6'
|
|
19
|
+
- - "<"
|
|
17
20
|
- !ruby/object:Gem::Version
|
|
18
|
-
version: '
|
|
21
|
+
version: '3'
|
|
19
22
|
type: :runtime
|
|
20
23
|
prerelease: false
|
|
21
24
|
version_requirements: !ruby/object:Gem::Requirement
|
|
22
25
|
requirements:
|
|
23
|
-
- - "
|
|
26
|
+
- - ">="
|
|
24
27
|
- !ruby/object:Gem::Version
|
|
25
|
-
version: '2.
|
|
28
|
+
version: '2.6'
|
|
29
|
+
- - "<"
|
|
30
|
+
- !ruby/object:Gem::Version
|
|
31
|
+
version: '3'
|
|
26
32
|
- !ruby/object:Gem::Dependency
|
|
27
33
|
name: async-http
|
|
28
34
|
requirement: !ruby/object:Gem::Requirement
|
|
29
35
|
requirements:
|
|
30
|
-
- - "
|
|
36
|
+
- - ">="
|
|
37
|
+
- !ruby/object:Gem::Version
|
|
38
|
+
version: '0.79'
|
|
39
|
+
- - "<"
|
|
31
40
|
- !ruby/object:Gem::Version
|
|
32
|
-
version: '
|
|
41
|
+
version: '1'
|
|
33
42
|
type: :runtime
|
|
34
43
|
prerelease: false
|
|
35
44
|
version_requirements: !ruby/object:Gem::Requirement
|
|
36
45
|
requirements:
|
|
37
|
-
- - "
|
|
46
|
+
- - ">="
|
|
47
|
+
- !ruby/object:Gem::Version
|
|
48
|
+
version: '0.79'
|
|
49
|
+
- - "<"
|
|
38
50
|
- !ruby/object:Gem::Version
|
|
39
|
-
version: '
|
|
51
|
+
version: '1'
|
|
40
52
|
- !ruby/object:Gem::Dependency
|
|
41
53
|
name: async-websocket
|
|
42
54
|
requirement: !ruby/object:Gem::Requirement
|
|
43
55
|
requirements:
|
|
44
|
-
- - "
|
|
56
|
+
- - ">="
|
|
45
57
|
- !ruby/object:Gem::Version
|
|
46
|
-
version: '0.
|
|
58
|
+
version: '0.26'
|
|
59
|
+
- - "<"
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: '1'
|
|
47
62
|
type: :runtime
|
|
48
63
|
prerelease: false
|
|
49
64
|
version_requirements: !ruby/object:Gem::Requirement
|
|
50
65
|
requirements:
|
|
51
|
-
- - "
|
|
66
|
+
- - ">="
|
|
67
|
+
- !ruby/object:Gem::Version
|
|
68
|
+
version: '0.26'
|
|
69
|
+
- - "<"
|
|
52
70
|
- !ruby/object:Gem::Version
|
|
53
|
-
version: '
|
|
71
|
+
version: '1'
|
|
54
72
|
- !ruby/object:Gem::Dependency
|
|
55
73
|
name: concurrent-ruby
|
|
56
74
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -570,7 +588,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
570
588
|
requirements:
|
|
571
589
|
- - ">="
|
|
572
590
|
- !ruby/object:Gem::Version
|
|
573
|
-
version: '3.
|
|
591
|
+
version: '3.1'
|
|
574
592
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
575
593
|
requirements:
|
|
576
594
|
- - ">="
|