smplkit 3.0.134 → 3.0.135

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cf2f498b2e69289af423a44bb47b11c024cb9fa6f6a5d92c59c9386a2495636c
4
- data.tar.gz: 6427e58289966df501d6484c772c662256e16536d346b60681268bb1f7a93aba
3
+ metadata.gz: 0c1cba1222e1ec1109993202959fa417b65752d969da90230f6f4ed913de9753
4
+ data.tar.gz: d1656093905daa0e565c6fb20c482b922251d2a4eb0dfbc7ca8684bc323abac5
5
5
  SHA512:
6
- metadata.gz: 1f34027f5bd130aab9c529b2336c81bae00c1ebe17c28128a3abddd9ba6adeea2c437a858e7aaba2f008a4526dc5eb09240c4e569f07dd2071179f653c449078
7
- data.tar.gz: 5c341e78b89c8a5b8ad314a7fd75867b8937817dbe43e86b4f7f572acbbb73ed4d6ac11a9aea05fa83a98a0c29f3cb46efeb174a6693be6374d54068e0b4fa59
6
+ metadata.gz: 4c18d2ec862ee1ad4b58539f326aaa55e6868de62205fe037998a00f90cb6d3c60676d80ab3f94771d8923d9c08543133d861358dc9c18dd1ff35a57ae15e783
7
+ data.tar.gz: d9225dd299dbbeac794f58a7fbd48713e10166e4f7e266a4eedd4ead1649c7315542de018a5d1bfe1aa1796cb7f82d4c04bfac4fdab30ab1ecd21ac4ba48ad2c
@@ -102,7 +102,7 @@ module Smplkit
102
102
  MetricsReporter.new(http_client: @app_http, environment: cfg.environment, service: cfg.service)
103
103
  end
104
104
 
105
- @ws_manager = nil
105
+ @event_stream = nil
106
106
  # Platform's cross-cutting CRUD on one client; wired into this parent so
107
107
  # it borrows the shared app transport, and owns the context-registration
108
108
  # buffer. Built BEFORE flags so the contexts seam below is available.
@@ -111,17 +111,17 @@ module Smplkit
111
111
  # (the settings sub-client uses Faraday directly).
112
112
  @account = Account::AccountClient.new(api_key: cfg.api_key, base_url: app_url, extra_headers: extra_headers)
113
113
  # Config's full surface on one client; wired into this parent so it
114
- # borrows the shared config transport and WebSocket.
114
+ # borrows the shared config transport and event stream.
115
115
  @config = Config::ConfigClient.new(parent: self, transport: @transports.config_http, metrics: @metrics)
116
116
  # Flags' full surface on one client; wired into this parent so it borrows
117
- # the shared flags transport and WebSocket. ``contexts`` is the injection
118
- # seam for evaluation-context registration, wired to
117
+ # the shared flags transport and event stream. ``contexts`` is the
118
+ # injection seam for evaluation-context registration, wired to
119
119
  # ``client.platform.contexts``.
120
120
  @flags = Flags::FlagsClient.new(
121
121
  parent: self, transport: @transports.flags_http, contexts: @platform.contexts, metrics: @metrics
122
122
  )
123
123
  # Logging's full surface on one client; wired into this parent so it
124
- # borrows the shared logging transport and WebSocket. The two management
124
+ # borrows the shared logging transport and event stream. The two management
125
125
  # sub-clients live at client.logging.loggers / client.logging.log_groups.
126
126
  @logging = Logging::LoggingClient.new(parent: self, transport: @transports.logging_http, metrics: @metrics)
127
127
  # Audit's full surface on one client; this runtime instance scopes audit
@@ -148,35 +148,35 @@ module Smplkit
148
148
  @init_thread = nil
149
149
  end
150
150
 
151
- # Optionally pre-warm the SDK and block until the live socket is up.
151
+ # Optionally pre-warm the SDK and block until the live stream is up.
152
152
  #
153
153
  # Eagerly connects config and flags — flushing discovery, pre-fetching all
154
- # flags and configs into the local cache, opening the live-updates WebSocket
155
- # — and waits for the handshake to complete. After this returns, +flag.get+
156
- # / +client.config.subscribe+ hit cache (no first-request connect tax) and
157
- # any +on_change+ listeners receive every server event from this point
158
- # forward.
154
+ # flags and configs into the local cache, opening the live-updates event
155
+ # stream — and waits for the connect to complete. After this returns,
156
+ # +flag.get+ / +client.config.subscribe+ hit cache (no first-request
157
+ # connect tax) and any +on_change+ listeners receive every server event
158
+ # from this point forward.
159
159
  #
160
160
  # Optional: config and flags connect lazily on first live use, so this is
161
- # purely a pre-warm / WebSocket-ready barrier. Logging integration is *not*
161
+ # purely a pre-warm / stream-ready barrier. Logging integration is *not*
162
162
  # connected here — call +client.logging.install+ separately if you want it
163
163
  # (it installs adapters and hooks into your application's logger, which
164
164
  # should be opt-in).
165
165
  #
166
166
  # @param timeout [Float] Maximum seconds to wait for the live-updates
167
- # WebSocket handshake before giving up. Defaults to +10.0+.
167
+ # event stream to connect before giving up. Defaults to +10.0+.
168
168
  # @return [void]
169
- # @raise [Smplkit::TimeoutError] If the WebSocket fails to connect within
170
- # +timeout+ seconds.
169
+ # @raise [Smplkit::TimeoutError] If the event stream fails to connect
170
+ # within +timeout+ seconds.
171
171
  def wait_until_ready(timeout: 10.0)
172
172
  @flags._ensure_connected
173
173
  @config._ensure_connected
174
- ws = _ensure_ws
174
+ stream = _ensure_event_stream
175
175
  deadline = monotonic_now + timeout
176
- while ws.connection_status != "connected"
176
+ while stream.connection_status != "connected"
177
177
  if monotonic_now >= deadline
178
- raise TimeoutError, "Live-updates websocket did not connect within #{timeout}s " \
179
- "(status: #{ws.connection_status.inspect})"
178
+ raise TimeoutError, "Live-updates event stream did not connect within #{timeout}s " \
179
+ "(status: #{stream.connection_status.inspect})"
180
180
  end
181
181
 
182
182
  sleep(0.05)
@@ -235,8 +235,8 @@ module Smplkit
235
235
  @logging._close
236
236
  @flags._close
237
237
  @audit._close
238
- @ws_manager&.stop
239
- @ws_manager = nil
238
+ @event_stream&.stop
239
+ @event_stream = nil
240
240
  # Close the shared per-service HTTP transports (app/config/flags/logging/
241
241
  # jobs). client.platform/account borrow the app transport and close
242
242
  # nothing; client.audit owns and closed its own transport above.
@@ -256,7 +256,7 @@ module Smplkit
256
256
  #
257
257
  # Idempotent and thread-safe (lock + flag); a no-op after +close+. Triggered
258
258
  # by the first config/flags/logging operation, +set_context+,
259
- # +wait_until_ready+, or WebSocket open — never at construction.
259
+ # +wait_until_ready+, or event stream open — never at construction.
260
260
  def _ensure_started
261
261
  @start_lock.synchronize do
262
262
  return if @started || @closed
@@ -267,13 +267,13 @@ module Smplkit
267
267
  @init_thread = Thread.new { register_service_context }
268
268
  end
269
269
 
270
- def _ensure_ws
270
+ def _ensure_event_stream
271
271
  _ensure_started
272
- if @ws_manager.nil?
273
- @ws_manager = SharedWebSocket.new(app_base_url: @app_base_url, api_key: @api_key, metrics: @metrics)
274
- @ws_manager.start
272
+ if @event_stream.nil?
273
+ @event_stream = EventStream.new(app_base_url: @app_base_url, api_key: @api_key, metrics: @metrics)
274
+ @event_stream.start
275
275
  end
276
- @ws_manager
276
+ @event_stream
277
277
  end
278
278
 
279
279
  private
@@ -14,17 +14,17 @@
14
14
  # resolved read), +bind+ (a live Struct/Hash binding), +on_change+, and
15
15
  # +refresh+. The first live call transparently flushes discovery, fetches and
16
16
  # resolves every config into the local cache, and opens the live-updates
17
- # WebSocket — no explicit install step.
17
+ # event stream — no explicit install step.
18
18
  #
19
19
  # The client supports two construction shapes:
20
20
  #
21
21
  # * *Wired* into +Smplkit::Client+ — borrows the parent's config transport for
22
- # both runtime fetch and CRUD and the parent's shared WebSocket for the live
23
- # channel. This is the common path.
22
+ # both runtime fetch and CRUD and the parent's shared event stream for the
23
+ # live channel. This is the common path.
24
24
  # * *Standalone* — +ConfigClient.new(api_key: ..., base_url: ..., ...)+ builds
25
25
  # and owns its own config transport, and on first live use opens and owns its
26
- # own WebSocket. +close+ tears down only the owned transport and owned
27
- # WebSocket.
26
+ # own event stream. +close+ tears down only the owned transport and owned
27
+ # event stream.
28
28
  module Smplkit
29
29
  module Config
30
30
  # Module-level helpers for the config client. Extracted so they can be
@@ -339,7 +339,7 @@ module Smplkit
339
339
  # resolver fills in whatever is missing (+~/.smplkit+ / env vars /
340
340
  # defaults). +environment+/+service+ resolve the same way (constructor
341
341
  # argument wins). The app base URL is returned alongside so a standalone
342
- # client can open its own WebSocket against the event gateway.
342
+ # client can open its own event stream against the app service.
343
343
  #
344
344
  # @api private
345
345
  # @param api_key [String, nil] API key, or +nil+ to resolve it.
@@ -392,7 +392,7 @@ module Smplkit
392
392
  # is pure CRUD. The live surface (+subscribe+ / +get_value+ / +bind+ /
393
393
  # +on_change+ / +refresh+) connects lazily on first use — the first call
394
394
  # flushes discovery, fetches and resolves all configs into the local cache,
395
- # and opens the live-updates WebSocket. No explicit install step is
395
+ # and opens the live-updates event stream. No explicit install step is
396
396
  # required.
397
397
  class ConfigClient
398
398
  # Sentinel distinguishing "no default supplied" from an explicit +nil+
@@ -418,8 +418,8 @@ module Smplkit
418
418
  # @param debug [Boolean, nil] Enable SDK debug logging.
419
419
  # @param extra_headers [Hash{String => String}, nil] Extra headers
420
420
  # attached to every request.
421
- # @param streaming [Boolean] Live updates over WebSocket (default
422
- # +true+): the first live call opens a shared socket and config changes
421
+ # @param streaming [Boolean] Live updates over the event stream (default
422
+ # +true+): the first live call opens a shared stream and config changes
423
423
  # stream in. Set +false+ for the stateless read-through surface: the
424
424
  # first live call still fetches and resolves every config once
425
425
  # (blocking), reads stay local, +refresh+ re-fetches on demand, and NO
@@ -478,8 +478,8 @@ module Smplkit
478
478
  @connected = false
479
479
  @lock = Mutex.new
480
480
  @listeners = [] # [callback, config_id_or_nil, item_key_or_nil]
481
- @ws_manager = nil
482
- @owns_ws = false
481
+ @event_stream = nil
482
+ @owns_stream = false
483
483
  end
484
484
 
485
485
  # ----------------------------------------------------------------
@@ -648,7 +648,7 @@ module Smplkit
648
648
  # authoritative and synced onto the bound object; if it is brand-new, the
649
649
  # cache entry is seeded in-memory from the bound object's values resolved
650
650
  # through its bound parent chain (no network round-trip). On every
651
- # WebSocket-delivered change thereafter the bound object is mutated in
651
+ # stream-delivered change thereafter the bound object is mutated in
652
652
  # place. Readers always see the current resolved value with no proxy
653
653
  # indirection.
654
654
  #
@@ -677,7 +677,7 @@ module Smplkit
677
677
 
678
678
  parent_id = register_binding_declaration(id, config, parent)
679
679
 
680
- # Register the binding BEFORE syncing so WebSocket dispatch finds it.
680
+ # Register the binding BEFORE syncing so event dispatch finds it.
681
681
  @bindings[id] = config
682
682
  @bound_parents[id] = parent_id
683
683
  seed_or_sync_binding(id, config)
@@ -803,17 +803,17 @@ module Smplkit
803
803
 
804
804
  # Release resources — only those this client owns.
805
805
  #
806
- # Tears down the owned WebSocket (opened by a standalone client on first
807
- # live use) and the owned HTTP transport (standalone construction). A
808
- # wired client borrows the parent's transport and WebSocket and closes
809
- # neither.
806
+ # Tears down the owned event stream (opened by a standalone client on
807
+ # first live use) and the owned HTTP transport (standalone construction).
808
+ # A wired client borrows the parent's transport and event stream and
809
+ # closes neither.
810
810
  #
811
811
  # @return [void]
812
812
  def close
813
- if @owns_ws && @ws_manager
814
- @ws_manager.stop
815
- @ws_manager = nil
816
- @owns_ws = false
813
+ if @owns_stream && @event_stream
814
+ @event_stream.stop
815
+ @event_stream = nil
816
+ @owns_stream = false
817
817
  end
818
818
  nil
819
819
  end
@@ -848,29 +848,31 @@ module Smplkit
848
848
  private
849
849
 
850
850
  # ----------------------------------------------------------------
851
- # Live surface: lazy connect + transport / WebSocket helpers
851
+ # Live surface: lazy connect + transport / event stream helpers
852
852
  # ----------------------------------------------------------------
853
853
 
854
- def ensure_ws
855
- return @parent._ensure_ws unless @parent.nil?
854
+ def ensure_event_stream
855
+ return @parent._ensure_event_stream unless @parent.nil?
856
856
 
857
- if @ws_manager.nil?
858
- @ws_manager = SharedWebSocket.new(
857
+ if @event_stream.nil?
858
+ @event_stream = EventStream.new(
859
859
  app_base_url: @app_base_url, api_key: @standalone_api_key, metrics: @metrics
860
860
  )
861
- @ws_manager.start
862
- @owns_ws = true
861
+ @event_stream.start
862
+ @owns_stream = true
863
863
  end
864
- @ws_manager
864
+ @event_stream
865
865
  end
866
866
 
867
867
  # Open the live connection to the running Smpl Config service.
868
868
  #
869
869
  # Flushes any buffered discovery declarations, fetches and resolves every
870
870
  # config for the configured environment into the local cache, opens the
871
- # shared WebSocket, and subscribes to +config_changed+ / +config_deleted+
872
- # / +configs_changed+ events. In stateless mode (+streaming: false+) no
873
- # socket is ever created; +refresh+ re-fetches on demand.
871
+ # shared event stream, and subscribes to +config_changed+ /
872
+ # +config_deleted+ / +configs_changed+ events. Also registers the
873
+ # bulk-refresh path as the stream's reconnect refetch, so a stream outage
874
+ # ends with a full re-sync. In stateless mode (+streaming: false+) no
875
+ # stream is ever created; +refresh+ re-fetches on demand.
874
876
  #
875
877
  # Idempotent and internal — every live method calls it on first use, so
876
878
  # the live surface auto-connects with no explicit step.
@@ -892,10 +894,11 @@ module Smplkit
892
894
  @connected = true
893
895
  return unless @streaming
894
896
 
895
- @ws_manager = ensure_ws
896
- @ws_manager.on("config_changed") { |data| handle_config_changed(data) }
897
- @ws_manager.on("config_deleted") { |data| handle_config_deleted(data) }
898
- @ws_manager.on("configs_changed") { |data| handle_configs_changed(data) }
897
+ @event_stream = ensure_event_stream
898
+ @event_stream.on("config_changed") { |data| handle_config_changed(data) }
899
+ @event_stream.on("config_deleted") { |data| handle_config_deleted(data) }
900
+ @event_stream.on("configs_changed") { |data| handle_configs_changed(data) }
901
+ @event_stream.on_reconnect { handle_configs_changed({}) }
899
902
  end
900
903
 
901
904
  # List configs directly from the API for the runtime cache.
@@ -1047,7 +1050,7 @@ module Smplkit
1047
1050
  #
1048
1051
  # A freshly-bound config lives only as a seed until it is flushed and
1049
1052
  # fetched; without this, any cache rebuild (a manual refresh, or a
1050
- # WebSocket event for another config) would drop it. Server-present
1053
+ # push event for another config) would drop it. Server-present
1051
1054
  # configs are already in +new_cache+ and are authoritative — only bound
1052
1055
  # ids missing from it are re-seeded.
1053
1056
  def merge_pending_seeds(new_cache)
@@ -1124,7 +1127,7 @@ module Smplkit
1124
1127
  end
1125
1128
 
1126
1129
  # ----------------------------------------------------------------
1127
- # Internal: event handlers (called by SharedWebSocket)
1130
+ # Internal: event handlers (called by EventStream)
1128
1131
  # ----------------------------------------------------------------
1129
1132
 
1130
1133
  # Re-resolve every config in +store+ and fire change listeners.
@@ -1189,7 +1192,7 @@ module Smplkit
1189
1192
 
1190
1193
  new_store[key] = cfg
1191
1194
  ensure_ancestors_cached(new_store)
1192
- rebuild_from_store(new_store, source: "websocket")
1195
+ rebuild_from_store(new_store, source: "push")
1193
1196
  rescue StandardError => e
1194
1197
  Smplkit.debug("config", "config_changed handler failed for #{key.inspect}: #{e.class}: #{e.message}")
1195
1198
  end
@@ -1202,11 +1205,11 @@ module Smplkit
1202
1205
  new_store = @lock.synchronize { @raw_config_store.dup }
1203
1206
  return if new_store.delete(key).nil?
1204
1207
 
1205
- rebuild_from_store(new_store, source: "websocket")
1208
+ rebuild_from_store(new_store, source: "push")
1206
1209
  end
1207
1210
 
1208
1211
  def handle_configs_changed(_data)
1209
- do_refresh("websocket")
1212
+ do_refresh("push")
1210
1213
  rescue StandardError => e
1211
1214
  Smplkit.debug("config", "configs_changed refresh failed: #{e.class}: #{e.message}")
1212
1215
  end