smplkit 3.0.134 → 3.0.136

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.
@@ -18,18 +18,18 @@ require "digest"
18
18
  # +json_flag+) whose +.get+ evaluates against the cached definitions, plus
19
19
  # +refresh+ / +stats+ / +on_change+. The first live call transparently flushes
20
20
  # discovery, fetches all flag definitions into the local cache, and opens the
21
- # live-updates WebSocket — no explicit install step.
21
+ # live-updates event stream — no explicit install step.
22
22
  #
23
23
  # The client supports two construction shapes:
24
24
  #
25
25
  # * *Wired* into +Smplkit::Client+ — borrows the parent's flags transport for
26
- # both runtime fetch and CRUD, the parent's shared WebSocket for the live
26
+ # both runtime fetch and CRUD, the parent's shared event stream for the live
27
27
  # channel, and +client.platform.contexts+ for evaluation-context
28
28
  # registration. This is the common path.
29
29
  # * *Standalone* — +FlagsClient.new(api_key: ..., base_url: ..., ...)+ builds
30
30
  # and owns its own flags transport and a contexts client (against its own app
31
- # transport), and on first live use opens and owns its own WebSocket. +close+
32
- # tears down only the owned transports and owned WebSocket.
31
+ # transport), and on first live use opens and owns its own event stream.
32
+ # +close+ tears down only the owned transports and owned event stream.
33
33
  module Smplkit
34
34
  module Flags
35
35
  # Describes a flag definition change. Frozen — fields are set at construction.
@@ -37,7 +37,7 @@ module Smplkit
37
37
  # @!attribute [r] id
38
38
  # @return [String] id of the flag whose definition changed.
39
39
  # @!attribute [r] source
40
- # @return [String] origin of the change (e.g. +"websocket"+ for a live
40
+ # @return [String] origin of the change (e.g. +"push"+ for a live
41
41
  # update or +"manual"+ for a refresh).
42
42
  # @!attribute [r] deleted
43
43
  # @return [Boolean] whether the change was a deletion of the flag.
@@ -148,7 +148,7 @@ module Smplkit
148
148
  # defaults). +environment+/+service+ resolve the same way (constructor
149
149
  # argument wins). The app transport backs the standalone contexts client
150
150
  # (evaluation-context registration); the app base URL is returned so a
151
- # standalone client can open its own WebSocket against the event gateway.
151
+ # standalone client can open its own event stream against the app service.
152
152
  #
153
153
  # @api private
154
154
  def self.flags_transport(api_key:, base_url:, profile:, base_domain:, scheme:,
@@ -186,8 +186,8 @@ module Smplkit
186
186
  # is pure CRUD. The live surface (+boolean_flag+ / +string_flag+ /
187
187
  # +number_flag+ / +json_flag+ / +refresh+ / +stats+ / +on_change+) connects
188
188
  # lazily on first use — the first call flushes discovery, fetches all flag
189
- # definitions into the local cache, and opens the live-updates WebSocket. No
190
- # explicit install step is required.
189
+ # definitions into the local cache, and opens the live-updates event
190
+ # stream. No explicit install step is required.
191
191
  class FlagsClient
192
192
  # @param api_key [String, nil] API key. When omitted, resolved from
193
193
  # +SMPLKIT_API_KEY+ or +~/.smplkit+.
@@ -207,8 +207,8 @@ module Smplkit
207
207
  # @param debug [Boolean, nil] Enable SDK debug logging.
208
208
  # @param extra_headers [Hash{String => String}, nil] Extra headers
209
209
  # attached to every request.
210
- # @param streaming [Boolean] Live updates over WebSocket (default
211
- # +true+): the first live call opens a shared socket and flag changes
210
+ # @param streaming [Boolean] Live updates over the event stream (default
211
+ # +true+): the first live call opens a shared stream and flag changes
212
212
  # stream in. Set +false+ for the stateless read-through surface: the
213
213
  # first live call still fetches all flag definitions once (blocking),
214
214
  # evaluation stays local, +refresh+ re-fetches on demand, and NO socket
@@ -263,13 +263,13 @@ module Smplkit
263
263
  # Live-surface state.
264
264
  @flag_store = {}
265
265
  @connected = false
266
- @ws_subscribed = false
266
+ @stream_subscribed = false
267
267
  @cache = ResolutionCache.new
268
268
  @handles = {}
269
269
  @global_listeners = []
270
270
  @key_listeners = Hash.new { |h, k| h[k] = [] }
271
- @ws_manager = nil
272
- @owns_ws = false
271
+ @event_stream = nil
272
+ @owns_stream = false
273
273
  @lock = Mutex.new
274
274
  end
275
275
 
@@ -566,16 +566,16 @@ module Smplkit
566
566
 
567
567
  # Release resources — only those this client owns.
568
568
  #
569
- # Tears down the owned WebSocket (standalone install). A wired client
570
- # borrows the parent's transport, WebSocket, and contexts client and
569
+ # Tears down the owned event stream (standalone install). A wired client
570
+ # borrows the parent's transport, event stream, and contexts client and
571
571
  # closes none of them.
572
572
  #
573
573
  # @return [void]
574
574
  def close
575
- if @owns_ws && @ws_manager
576
- @ws_manager.stop
577
- @ws_manager = nil
578
- @owns_ws = false
575
+ if @owns_stream && @event_stream
576
+ @event_stream.stop
577
+ @event_stream = nil
578
+ @owns_stream = false
579
579
  end
580
580
  # Owned flags/app transports (standalone construction) release their
581
581
  # Faraday connections on GC; there is no explicit shutdown to call.
@@ -680,29 +680,31 @@ module Smplkit
680
680
  end
681
681
 
682
682
  # ----------------------------------------------------------------
683
- # Live surface: lazy connect + transport / WebSocket helpers
683
+ # Live surface: lazy connect + transport / event stream helpers
684
684
  # ----------------------------------------------------------------
685
685
 
686
- def ensure_ws
687
- return @parent._ensure_ws unless @parent.nil?
686
+ def ensure_event_stream
687
+ return @parent._ensure_event_stream unless @parent.nil?
688
688
 
689
- if @ws_manager.nil?
690
- @ws_manager = SharedWebSocket.new(
689
+ if @event_stream.nil?
690
+ @event_stream = EventStream.new(
691
691
  app_base_url: @app_base_url, api_key: @standalone_api_key, metrics: @metrics
692
692
  )
693
- @ws_manager.start
694
- @owns_ws = true
693
+ @event_stream.start
694
+ @owns_stream = true
695
695
  end
696
- @ws_manager
696
+ @event_stream
697
697
  end
698
698
 
699
699
  # Open the live connection to the running Smpl Flags service.
700
700
  #
701
701
  # Flushes any buffered discovery declarations, fetches all flag
702
- # definitions into the local cache, opens the shared WebSocket, and
702
+ # definitions into the local cache, opens the shared event stream, and
703
703
  # subscribes to +flag_changed+ / +flag_deleted+ / +flags_changed+ events.
704
- # In stateless mode (+streaming: false+) no socket is ever created;
705
- # +refresh+ re-fetches on demand.
704
+ # Also registers the bulk-refresh path as the stream's reconnect refetch,
705
+ # so a stream outage ends with a full re-sync. In stateless mode
706
+ # (+streaming: false+) no stream is ever created; +refresh+ re-fetches on
707
+ # demand.
706
708
  #
707
709
  # Idempotent and internal — every live method calls it on first use, so
708
710
  # the live surface auto-connects with no explicit step.
@@ -723,13 +725,14 @@ module Smplkit
723
725
  @connected = true
724
726
  return unless @streaming
725
727
 
726
- @ws_manager = ensure_ws
727
- return if @ws_subscribed
728
+ @event_stream = ensure_event_stream
729
+ return if @stream_subscribed
728
730
 
729
- @ws_manager.on("flag_changed") { |data| handle_flag_changed(data) }
730
- @ws_manager.on("flag_deleted") { |data| handle_flag_deleted(data) }
731
- @ws_manager.on("flags_changed") { |data| handle_flags_changed(data) }
732
- @ws_subscribed = true
731
+ @event_stream.on("flag_changed") { |data| handle_flag_changed(data) }
732
+ @event_stream.on("flag_deleted") { |data| handle_flag_deleted(data) }
733
+ @event_stream.on("flags_changed") { |data| handle_flags_changed(data) }
734
+ @event_stream.on_reconnect { handle_flags_changed({}) }
735
+ @stream_subscribed = true
733
736
  end
734
737
 
735
738
  def do_refresh(_source)
@@ -759,7 +762,7 @@ module Smplkit
759
762
  end
760
763
 
761
764
  # ----------------------------------------------------------------
762
- # Internal: event handlers (called by SharedWebSocket)
765
+ # Internal: event handlers (called by EventStream)
763
766
  # ----------------------------------------------------------------
764
767
 
765
768
  def handle_flag_changed(data)
@@ -770,7 +773,7 @@ module Smplkit
770
773
  new_data = fetch_flag_single_data(key)
771
774
  @flag_store[key] = new_data
772
775
  @cache.clear
773
- fire_change_listeners(key, "websocket") if pre != new_data
776
+ fire_change_listeners(key, "push") if pre != new_data
774
777
  end
775
778
 
776
779
  def handle_flag_deleted(data)
@@ -780,7 +783,7 @@ module Smplkit
780
783
  existed = @flag_store.key?(key)
781
784
  @flag_store.delete(key)
782
785
  @cache.clear
783
- fire_change_listeners(key, "websocket", deleted: true) if existed
786
+ fire_change_listeners(key, "push", deleted: true) if existed
784
787
  end
785
788
 
786
789
  def handle_flags_changed(_data)
@@ -788,7 +791,7 @@ module Smplkit
788
791
  begin
789
792
  fetch_all_flags
790
793
  rescue StandardError => e
791
- Smplkit.debug("ws", "flags refresh after flags_changed failed: #{e.message}")
794
+ Smplkit.debug("flags", "flags refresh after flags_changed failed: #{e.message}")
792
795
  return
793
796
  end
794
797
  @cache.clear
@@ -798,7 +801,7 @@ module Smplkit
798
801
  return if changed.empty?
799
802
 
800
803
  # Global listener fires once.
801
- first_event = FlagChangeEvent.new(id: changed.first, source: "websocket")
804
+ first_event = FlagChangeEvent.new(id: changed.first, source: "push")
802
805
  @global_listeners.each do |cb|
803
806
  cb.call(first_event)
804
807
  rescue StandardError => e
@@ -808,7 +811,7 @@ module Smplkit
808
811
  # Per-key listeners fire for each changed key.
809
812
  changed.each do |k|
810
813
  deleted = pre_store.key?(k) && !post_store.key?(k)
811
- event = FlagChangeEvent.new(id: k, source: "websocket", deleted: deleted)
814
+ event = FlagChangeEvent.new(id: k, source: "push", deleted: deleted)
812
815
  @key_listeners[k].each do |cb|
813
816
  cb.call(event)
814
817
  rescue StandardError => e
@@ -268,8 +268,8 @@ module Smplkit
268
268
  # The Smpl Jobs client — accessed via +client.jobs+.
269
269
  #
270
270
  # Unlike Config/Flags/Logging, Jobs has no live "phone-home" agent — no
271
- # environment registration, no WebSocket — so its entire surface lives on
272
- # one client. Defining a job, triggering a run, and reading run history are
271
+ # environment registration, no event stream — so its entire surface lives
272
+ # on one client. Defining a job, triggering a run, and reading run history are
273
273
  # all plain request/response calls here:
274
274
  #
275
275
  # client.jobs.{new_recurring_job,new_manual_job,schedule,get,list,delete,run,usage}
@@ -4,8 +4,8 @@ module Smplkit
4
4
  # Smpl Jobs surface — exposed through +client.jobs.*+.
5
5
  #
6
6
  # Unlike Config/Flags/Logging, Jobs has no live "phone-home" agent — no
7
- # environment registration, no WebSocket — so its entire surface lives on a
8
- # single client. A {Job} is an active record: build it with
7
+ # environment registration, no event stream — so its entire surface lives on
8
+ # a single client. A {Job} is an active record: build it with
9
9
  # +client.jobs.new_recurring_job(...)+ / +new_manual_job(...)+ /
10
10
  # +schedule(...)+, set fields, and call {Job#save} (create when new,
11
11
  # full-replace update when it already exists) or {Job#delete}. Runs are
@@ -20,19 +20,19 @@
20
20
  # * *Live surface* — directly on the client. +register_adapter+ is a PRE-install
21
21
  # configuration call (allowed before +install+). +install+ opens the live
22
22
  # connection (monkey-patches the app's logging framework, discovers loggers,
23
- # fetches + applies levels, opens the shared WebSocket). +on_change+ /
23
+ # fetches + applies levels, opens the shared event stream). +on_change+ /
24
24
  # +refresh+ require +install+ first; calling them earlier raises
25
25
  # +NotInstalledError+.
26
26
  #
27
27
  # The client supports two construction shapes:
28
28
  #
29
29
  # * *Wired* into +Smplkit::Client+ — borrows the parent's logging transport for
30
- # both runtime fetch and CRUD and the parent's shared WebSocket for the live
31
- # channel. This is the common path.
30
+ # both runtime fetch and CRUD and the parent's shared event stream for the
31
+ # live channel. This is the common path.
32
32
  # * *Standalone* — +LoggingClient.new(api_key: ..., base_url: ..., ...)+ builds
33
- # and owns its own logging transport and an app transport (the WebSocket
34
- # gateway lives on the app service), and on +install+ opens and owns its own
35
- # WebSocket. +close+ tears down only the owned transports and owned WebSocket.
33
+ # and owns its own logging transport and an app transport (the event stream
34
+ # lives on the app service), and on +install+ opens and owns its own event
35
+ # stream. +close+ tears down only the owned transports and owned event stream.
36
36
  module Smplkit
37
37
  module Logging
38
38
  NOT_INSTALLED_MESSAGE = "Smpl Logging live operations require install() first — this opens a live " \
@@ -45,10 +45,9 @@ module Smplkit
45
45
  # client takes after it has already resolved them); otherwise the management
46
46
  # config resolver fills in whatever is missing (+~/.smplkit+ / env vars /
47
47
  # defaults). +environment+/+service+ resolve the same way (constructor
48
- # argument wins). The app transport is needed for the WebSocket gateway,
49
- # which lives on the app service (like flags); the app base URL is returned
50
- # so a standalone client can open its own WebSocket against the event
51
- # gateway.
48
+ # argument wins). The app transport is needed because the event stream
49
+ # lives on the app service (like flags); the app base URL is returned so a
50
+ # standalone client can open its own event stream against the app service.
52
51
  #
53
52
  # @api private
54
53
  def self.logging_transport(api_key:, base_url:, profile:, base_domain:, scheme:,
@@ -97,7 +96,7 @@ module Smplkit
97
96
  # +"INFO"+, +"DEBUG"+) — the same value the resolution algorithm returns.
98
97
  # @!attribute [rw] source
99
98
  # @return [String] Short string identifying the trigger — typically
100
- # +"websocket"+ or +"manual"+ (a +refresh+ call).
99
+ # +"push"+ (a live update) or +"manual"+ (a +refresh+ call).
101
100
  LoggerChangeEvent = Struct.new(:id, :level, :source, keyword_init: true) do
102
101
  def ==(other)
103
102
  other.is_a?(LoggerChangeEvent) &&
@@ -457,8 +456,8 @@ module Smplkit
457
456
  # @param debug [Boolean, nil] Enable SDK debug logging.
458
457
  # @param extra_headers [Hash{String => String}, nil] Extra headers
459
458
  # attached to every request.
460
- # @param streaming [Boolean] Live updates over WebSocket (default
461
- # +true+): +install+ opens a shared socket and server-side level
459
+ # @param streaming [Boolean] Live updates over the event stream (default
460
+ # +true+): +install+ opens a shared stream and server-side level
462
461
  # changes stream in. Set +false+ for the stateless apply-once surface:
463
462
  # +install+ still loads adapters, flushes discovery, and applies the
464
463
  # server's levels — all blocking — but NO socket or background thread
@@ -514,8 +513,8 @@ module Smplkit
514
513
  @key_listeners = Hash.new { |h, k| h[k] = [] }
515
514
  @adapters = []
516
515
  @explicit_adapters = false
517
- @ws_manager = nil
518
- @owns_ws = false
516
+ @event_stream = nil
517
+ @owns_stream = false
519
518
  @lock = Mutex.new
520
519
  end
521
520
 
@@ -545,12 +544,12 @@ module Smplkit
545
544
  @adapters.dup
546
545
  end
547
546
 
548
- # --- Live surface: install (gate) + transport / WebSocket helpers ---
547
+ # --- Live surface: install (gate) + transport / event stream helpers ---
549
548
 
550
549
  # Hook smplkit into the application's logging machinery.
551
550
  #
552
551
  # Loads adapters, scans existing loggers, applies levels from the smplkit
553
- # server, and wires WebSocket handlers for live updates. This IS the
552
+ # server, and wires event stream handlers for live updates. This IS the
554
553
  # explicit consent gate — +on_change+ / +refresh+ require it first.
555
554
  #
556
555
  # Idempotent — safe to call multiple times.
@@ -600,12 +599,15 @@ module Smplkit
600
599
  "(logging: #{@logging_http&.config&.host}): #{e.class}: #{e.message}")
601
600
  end
602
601
 
603
- # 7. Register WebSocket event handlers for real-time level updates.
604
- # In stateless mode (+streaming: false+) no socket is ever created
605
- # level changes then arrive only via +refresh+.
602
+ # 7. Register event stream handlers for real-time level updates, plus
603
+ # the bulk-refresh path as the stream's reconnect refetch so a stream
604
+ # outage ends with a full re-sync. In stateless mode
605
+ # (+streaming: false+) no stream is ever created — level changes then
606
+ # arrive only via +refresh+.
606
607
  if @streaming
607
- @ws_manager = ensure_ws
608
- ws_handlers.each { |event, handler| @ws_manager.on(event, &handler) }
608
+ @event_stream = ensure_event_stream
609
+ stream_handlers.each { |event, handler| @event_stream.on(event, &handler) }
610
+ @event_stream.on_reconnect(refetch_callback)
609
611
  end
610
612
 
611
613
  @connected = true
@@ -643,9 +645,9 @@ module Smplkit
643
645
 
644
646
  # Release resources — only those this client owns.
645
647
  #
646
- # Uninstalls the adapter hooks, unsubscribes from the WebSocket, and tears
647
- # down the owned WebSocket (standalone install). A wired client borrows the
648
- # parent's transport and WebSocket and closes neither.
648
+ # Uninstalls the adapter hooks, unsubscribes from the event stream, and
649
+ # tears down the owned event stream (standalone install). A wired client
650
+ # borrows the parent's transport and event stream and closes neither.
649
651
  def close
650
652
  Smplkit.debug("lifecycle", "LoggingClient.close() called")
651
653
  @adapters.each do |adapter|
@@ -653,13 +655,14 @@ module Smplkit
653
655
  rescue StandardError => e
654
656
  Smplkit.debug("logging", "adapter #{adapter.name} uninstall_hook failed: #{e.class}: #{e.message}")
655
657
  end
656
- if @ws_manager
657
- ws_handlers.each { |event, handler| @ws_manager.off(event, handler) }
658
- if @owns_ws
659
- @ws_manager.stop
660
- @owns_ws = false
658
+ if @event_stream
659
+ stream_handlers.each { |event, handler| @event_stream.off(event, handler) }
660
+ @event_stream.off_reconnect(refetch_callback)
661
+ if @owns_stream
662
+ @event_stream.stop
663
+ @owns_stream = false
661
664
  end
662
- @ws_manager = nil
665
+ @event_stream = nil
663
666
  end
664
667
  @connected = false
665
668
  end
@@ -674,7 +677,7 @@ module Smplkit
674
677
  #
675
678
  # Mirrors Ruby's +File.open+ block form: the client is closed
676
679
  # automatically when the block returns or raises, so a standalone client's
677
- # owned transports and WebSocket are always torn down.
680
+ # owned transports and event stream are always torn down.
678
681
  #
679
682
  # Smplkit::LoggingClient.open(environment: "production") do |logging|
680
683
  # logging.loggers.new("sqlalchemy.engine").save
@@ -701,10 +704,10 @@ module Smplkit
701
704
 
702
705
  # Memoized event → handler map so +install+ registers and +close+
703
706
  # unsubscribes the exact same callback objects. They are stored as procs
704
- # (not bound methods) because +SharedWebSocket#off+ removes by object
707
+ # (not bound methods) because +EventStream#off+ removes by object
705
708
  # identity, and +on(event, &proc)+ stores the very proc passed here.
706
- def ws_handlers
707
- @ws_handlers ||= {
709
+ def stream_handlers
710
+ @stream_handlers ||= {
708
711
  "logger_changed" => proc { |data| handle_logger_changed(data) },
709
712
  "logger_deleted" => proc { |data| handle_logger_deleted(data) },
710
713
  "group_changed" => proc { |data| handle_group_changed(data) },
@@ -713,17 +716,24 @@ module Smplkit
713
716
  }
714
717
  end
715
718
 
716
- def ensure_ws
717
- return @parent._ensure_ws unless @parent.nil?
719
+ # Memoized reconnect refetch — the same bulk-refresh path the
720
+ # +loggers_changed+ handler runs, registered with the stream on
721
+ # +install+ and deregistered (by object identity) on +close+.
722
+ def refetch_callback
723
+ @refetch_callback ||= proc { handle_loggers_changed({}) }
724
+ end
725
+
726
+ def ensure_event_stream
727
+ return @parent._ensure_event_stream unless @parent.nil?
718
728
 
719
- if @ws_manager.nil?
720
- @ws_manager = SharedWebSocket.new(
729
+ if @event_stream.nil?
730
+ @event_stream = EventStream.new(
721
731
  app_base_url: @app_base_url, api_key: @standalone_api_key, metrics: @metrics
722
732
  )
723
- @ws_manager.start
724
- @owns_ws = true
733
+ @event_stream.start
734
+ @owns_stream = true
725
735
  end
726
- @ws_manager
736
+ @event_stream
727
737
  end
728
738
 
729
739
  # --- Internal ---
@@ -777,8 +787,8 @@ module Smplkit
777
787
  # path).
778
788
  #
779
789
  # Silent — does not fire change-listener events. Use
780
- # +fetch_and_apply_deltas+ from the WS / refresh paths to get per-logger
781
- # fanout.
790
+ # +fetch_and_apply_deltas+ from the push / refresh paths to get
791
+ # per-logger fanout.
782
792
  def fetch_and_apply(trigger: "unknown")
783
793
  fetch_cache(trigger)
784
794
  apply_levels
@@ -858,58 +868,58 @@ module Smplkit
858
868
  end
859
869
  end
860
870
 
861
- # --- Internal: event handlers (called by SharedWebSocket) ---
871
+ # --- Internal: event handlers (called by EventStream) ---
862
872
 
863
873
  def handle_logger_changed(data)
864
874
  key = data["id"] || ""
865
- Smplkit.debug("websocket", "logger_changed: fetching logger #{key.inspect}")
875
+ Smplkit.debug("events", "logger_changed: fetching logger #{key.inspect}")
866
876
  pre = snapshot_effective_levels
867
877
  begin
868
878
  entry_id, entry = @loggers.get_logger_entry(key)
869
879
  @loggers_cache[entry_id || key] = entry
870
880
  rescue StandardError => e
871
- Smplkit.debug("websocket", "failed to fetch logger #{key.inspect} after WS event: #{e.class}: #{e.message}")
881
+ Smplkit.debug("events", "failed to fetch logger #{key.inspect} after push event: #{e.class}: #{e.message}")
872
882
  return
873
883
  end
874
- apply_deltas_and_fire(pre, "websocket")
884
+ apply_deltas_and_fire(pre, "push")
875
885
  end
876
886
 
877
887
  def handle_logger_deleted(data)
878
888
  key = data["id"] || ""
879
- Smplkit.debug("websocket", "logger_deleted: removing logger #{key.inspect}")
889
+ Smplkit.debug("events", "logger_deleted: removing logger #{key.inspect}")
880
890
  pre = snapshot_effective_levels
881
891
  @loggers_cache.delete(key)
882
- apply_deltas_and_fire(pre, "websocket")
892
+ apply_deltas_and_fire(pre, "push")
883
893
  end
884
894
 
885
895
  def handle_group_changed(data)
886
896
  key = data["id"] || ""
887
- Smplkit.debug("websocket", "group_changed: fetching group #{key.inspect}")
897
+ Smplkit.debug("events", "group_changed: fetching group #{key.inspect}")
888
898
  pre = snapshot_effective_levels
889
899
  begin
890
900
  entry_id, entry = @log_groups.get_group_entry(key)
891
901
  @groups_cache[entry_id || key] = entry
892
902
  rescue StandardError => e
893
- Smplkit.debug("websocket",
894
- "failed to fetch log group #{key.inspect} after WS event: #{e.class}: #{e.message}")
903
+ Smplkit.debug("events",
904
+ "failed to fetch log group #{key.inspect} after push event: #{e.class}: #{e.message}")
895
905
  return
896
906
  end
897
- apply_deltas_and_fire(pre, "websocket")
907
+ apply_deltas_and_fire(pre, "push")
898
908
  end
899
909
 
900
910
  def handle_group_deleted(data)
901
911
  key = data["id"] || ""
902
- Smplkit.debug("websocket", "group_deleted: removing group #{key.inspect}")
912
+ Smplkit.debug("events", "group_deleted: removing group #{key.inspect}")
903
913
  pre = snapshot_effective_levels
904
914
  @groups_cache.delete(key)
905
- apply_deltas_and_fire(pre, "websocket")
915
+ apply_deltas_and_fire(pre, "push")
906
916
  end
907
917
 
908
918
  def handle_loggers_changed(_data)
909
- Smplkit.debug("websocket", "loggers_changed: full re-fetch")
910
- fetch_and_apply_deltas(trigger: "loggers_changed WS event", source: "websocket")
919
+ Smplkit.debug("events", "loggers_changed: full re-fetch")
920
+ fetch_and_apply_deltas(trigger: "loggers_changed event", source: "push")
911
921
  rescue StandardError => e
912
- Smplkit.debug("websocket",
922
+ Smplkit.debug("events",
913
923
  "failed to re-fetch/apply logging levels after loggers_changed event: #{e.class}: #{e.message}")
914
924
  end
915
925
  end
@@ -65,7 +65,7 @@ module Smplkit
65
65
  #
66
66
  # Construction is side-effect-free: each transport connects lazily on its
67
67
  # first call. +app_url+ is carried alongside so the account settings client
68
- # and the WebSocket can reach the app service. +close+ tears down the
68
+ # and the event stream can reach the app service. +close+ tears down the
69
69
  # underlying Faraday connection pools.
70
70
  #
71
71
  # @api private
@@ -26,8 +26,8 @@ module Smplkit
26
26
  spec ? spec.version.to_s : VERSION
27
27
  end
28
28
 
29
- # The default User-Agent stamped on every outbound request (HTTP and the
30
- # WebSocket handshake) when the caller has not supplied their own.
29
+ # The default User-Agent stamped on every outbound request (including the
30
+ # live-updates event stream) when the caller has not supplied their own.
31
31
  #
32
32
  # The platform sits behind a WAF that rejects requests carrying no
33
33
  # User-Agent, and an SDK-identifying value keeps support/telemetry able to
data/lib/smplkit.rb CHANGED
@@ -43,7 +43,7 @@ require_relative "smplkit/log_level"
43
43
  require_relative "smplkit/context"
44
44
  require_relative "smplkit/config_resolution"
45
45
  require_relative "smplkit/metrics"
46
- require_relative "smplkit/ws"
46
+ require_relative "smplkit/event_stream"
47
47
 
48
48
  # Internal foundation shared by every product client.
49
49
  require_relative "smplkit/buffers"
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: 3.0.134
4
+ version: 3.0.136
5
5
  platform: ruby
6
6
  authors:
7
7
  - Smpl Solutions LLC
@@ -49,26 +49,6 @@ dependencies:
49
49
  - - "<"
50
50
  - !ruby/object:Gem::Version
51
51
  version: '1'
52
- - !ruby/object:Gem::Dependency
53
- name: async-websocket
54
- requirement: !ruby/object:Gem::Requirement
55
- requirements:
56
- - - ">="
57
- - !ruby/object:Gem::Version
58
- version: '0.26'
59
- - - "<"
60
- - !ruby/object:Gem::Version
61
- version: '1'
62
- type: :runtime
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - ">="
67
- - !ruby/object:Gem::Version
68
- version: '0.26'
69
- - - "<"
70
- - !ruby/object:Gem::Version
71
- version: '1'
72
52
  - !ruby/object:Gem::Dependency
73
53
  name: concurrent-ruby
74
54
  requirement: !ruby/object:Gem::Requirement
@@ -933,6 +913,7 @@ files:
933
913
  - lib/smplkit/context.rb
934
914
  - lib/smplkit/debug.rb
935
915
  - lib/smplkit/errors.rb
916
+ - lib/smplkit/event_stream.rb
936
917
  - lib/smplkit/flags/client.rb
937
918
  - lib/smplkit/flags/helpers.rb
938
919
  - lib/smplkit/flags/models.rb
@@ -960,7 +941,6 @@ files:
960
941
  - lib/smplkit/railtie.rb
961
942
  - lib/smplkit/transport.rb
962
943
  - lib/smplkit/version.rb
963
- - lib/smplkit/ws.rb
964
944
  - sig/smplkit.rbs
965
945
  - sig/smplkit/config.rbs
966
946
  - sig/smplkit/flags.rbs