schematichq 1.4.16 → 1.5.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.
Files changed (132) hide show
  1. checksums.yaml +4 -4
  2. data/.fern/metadata.json +4 -4
  3. data/.fern/replay.lock +21 -3
  4. data/.fernignore +1 -0
  5. data/CONTRIBUTING.md +2 -2
  6. data/README.md +23 -0
  7. data/WASM_VERSION +1 -1
  8. data/lib/schematic/accesstokens/client.rb +1 -1
  9. data/lib/schematic/accounts/client.rb +21 -21
  10. data/lib/schematic/accounts/types/update_onboarding_state_request_body.rb +2 -0
  11. data/lib/schematic/billing/client.rb +120 -24
  12. data/lib/schematic/billing/types/create_billing_subscription_request_body.rb +2 -0
  13. data/lib/schematic/billing/types/list_company_billing_profiles_params.rb +20 -0
  14. data/lib/schematic/billing/types/list_company_billing_profiles_request.rb +19 -0
  15. data/lib/schematic/billing/types/list_company_billing_profiles_response.rb +13 -0
  16. data/lib/schematic/billing/types/update_company_billing_profile_request_body.rb +23 -0
  17. data/lib/schematic/billing/types/update_company_billing_profile_response.rb +13 -0
  18. data/lib/schematic/catalogs/client.rb +10 -10
  19. data/lib/schematic/checkout/client.rb +9 -9
  20. data/lib/schematic/client.rb +1 -1
  21. data/lib/schematic/companies/client.rb +43 -43
  22. data/lib/schematic/components/client.rb +8 -8
  23. data/lib/schematic/componentspublic/client.rb +1 -1
  24. data/lib/schematic/credits/client.rb +372 -41
  25. data/lib/schematic/credits/types/count_credit_spend_policies_params.rb +24 -0
  26. data/lib/schematic/credits/types/count_credit_spend_policies_request.rb +23 -0
  27. data/lib/schematic/credits/types/count_credit_spend_policies_response.rb +13 -0
  28. data/lib/schematic/credits/types/create_company_credit_grant.rb +2 -0
  29. data/lib/schematic/credits/types/create_credit_spend_policy_request_body.rb +19 -0
  30. data/lib/schematic/credits/types/create_credit_spend_policy_response.rb +13 -0
  31. data/lib/schematic/credits/types/delete_credit_spend_policy_response.rb +13 -0
  32. data/lib/schematic/credits/types/get_credit_spend_policy_response.rb +13 -0
  33. data/lib/schematic/credits/types/list_credit_spend_policies_params.rb +24 -0
  34. data/lib/schematic/credits/types/list_credit_spend_policies_request.rb +23 -0
  35. data/lib/schematic/credits/types/list_credit_spend_policies_response.rb +13 -0
  36. data/lib/schematic/credits/types/release_credit_reservation_response.rb +13 -0
  37. data/lib/schematic/credits/types/reserve_credits_request_body.rb +19 -0
  38. data/lib/schematic/credits/types/reserve_credits_response.rb +13 -0
  39. data/lib/schematic/credits/types/update_credit_spend_policy_request_body.rb +15 -0
  40. data/lib/schematic/credits/types/update_credit_spend_policy_response.rb +13 -0
  41. data/lib/schematic/dataexports/client.rb +3 -3
  42. data/lib/schematic/datastream/client.rb +5 -2
  43. data/lib/schematic/datastream/resource_cache.rb +2 -4
  44. data/lib/schematic/datastream/websocket_client.rb +59 -1
  45. data/lib/schematic/entitlements/client.rb +25 -25
  46. data/lib/schematic/events/client.rb +107 -6
  47. data/lib/schematic/events/types/delete_otlp_environment_settings_response.rb +13 -0
  48. data/lib/schematic/events/types/get_otlp_environment_settings_response.rb +13 -0
  49. data/lib/schematic/events/types/upsert_otlp_environment_settings_request_body.rb +19 -0
  50. data/lib/schematic/events/types/upsert_otlp_environment_settings_response.rb +13 -0
  51. data/lib/schematic/features/client.rb +57 -17
  52. data/lib/schematic/features/types/check_and_reserve_flag_request_body.rb +21 -0
  53. data/lib/schematic/features/types/check_and_reserve_flag_response.rb +13 -0
  54. data/lib/schematic/insights/client.rb +6 -6
  55. data/lib/schematic/integrationsapi/client.rb +178 -9
  56. data/lib/schematic/integrationsapi/types/claim_stripe_sandbox_keys_request_body.rb +11 -0
  57. data/lib/schematic/integrationsapi/types/claim_stripe_sandbox_keys_response.rb +13 -0
  58. data/lib/schematic/integrationsapi/types/get_stripe_sandbox_claim_link_response.rb +13 -0
  59. data/lib/schematic/integrationsapi/types/get_stripe_sandbox_keys_response.rb +13 -0
  60. data/lib/schematic/integrationsapi/types/install_stripe_claimable_sandbox_response.rb +13 -0
  61. data/lib/schematic/integrationsapi/types/install_stripe_sandbox_request_body.rb +17 -0
  62. data/lib/schematic/integrationsapi/types/list_stripe_sandbox_countries_response.rb +13 -0
  63. data/lib/schematic/internal/multipart/multipart_form_data.rb +8 -3
  64. data/lib/schematic/internal/types/model.rb +14 -6
  65. data/lib/schematic/licenses/client.rb +3 -3
  66. data/lib/schematic/planbundle/client.rb +3 -3
  67. data/lib/schematic/plangroups/client.rb +3 -3
  68. data/lib/schematic/plangroups/types/create_plan_group_request_body.rb +2 -0
  69. data/lib/schematic/plangroups/types/update_plan_group_request_body.rb +2 -0
  70. data/lib/schematic/planmigrations/client.rb +11 -11
  71. data/lib/schematic/plans/client.rb +24 -18
  72. data/lib/schematic/plans/types/count_plans_params.rb +2 -0
  73. data/lib/schematic/plans/types/count_plans_request.rb +2 -0
  74. data/lib/schematic/plans/types/list_plans_params.rb +2 -0
  75. data/lib/schematic/plans/types/list_plans_request.rb +2 -0
  76. data/lib/schematic/scheduledcheckout/client.rb +4 -4
  77. data/lib/schematic/schematic_client.rb +15 -2
  78. data/lib/schematic/types/billing_arrears_anchor.rb +12 -0
  79. data/lib/schematic/types/billing_arrears_cadence.rb +12 -0
  80. data/lib/schematic/types/billing_credit_grant_response_data.rb +8 -0
  81. data/lib/schematic/types/billing_plan_credit_grant_response_data.rb +12 -0
  82. data/lib/schematic/types/check_and_reserve_flag_response_data.rb +39 -0
  83. data/lib/schematic/types/checkout_data_response_data.rb +4 -0
  84. data/lib/schematic/types/claimed_stripe_sandbox_keys_response_data.rb +13 -0
  85. data/lib/schematic/types/company_billing_profile_response_data.rb +35 -0
  86. data/lib/schematic/types/company_detail_response_data.rb +4 -0
  87. data/lib/schematic/types/company_override_response_data.rb +4 -0
  88. data/lib/schematic/types/company_plan_credit_grant_view.rb +12 -0
  89. data/lib/schematic/types/create_billing_plan_credit_grant_request_body.rb +12 -0
  90. data/lib/schematic/types/credit_company_grant_view.rb +14 -0
  91. data/lib/schematic/types/credit_reservation_response_data.rb +25 -0
  92. data/lib/schematic/types/credit_spend_policy_response_data.rb +25 -0
  93. data/lib/schematic/types/credit_spend_policy_scope.rb +13 -0
  94. data/lib/schematic/types/credit_usage_reason.rb +2 -0
  95. data/lib/schematic/types/event_body_inference.rb +2 -0
  96. data/lib/schematic/types/event_body_track.rb +2 -0
  97. data/lib/schematic/types/event_detail_response_data.rb +2 -0
  98. data/lib/schematic/types/event_response_data.rb +2 -0
  99. data/lib/schematic/types/flag_check_reservation_response_data.rb +23 -0
  100. data/lib/schematic/types/get_onboarding_state_resp.rb +6 -0
  101. data/lib/schematic/types/issue_temporary_access_token_response_data.rb +3 -1
  102. data/lib/schematic/types/onboarding_requirement.rb +1 -0
  103. data/lib/schematic/types/onboarding_roadmap_view.rb +11 -0
  104. data/lib/schematic/types/otlp_environment_settings_response_data.rb +23 -0
  105. data/lib/schematic/types/plan_credit_grant_view.rb +12 -0
  106. data/lib/schematic/types/plan_group_detail_response_data.rb +2 -0
  107. data/lib/schematic/types/plan_group_response_data.rb +2 -0
  108. data/lib/schematic/types/rule_condition_detail_response_data.rb +2 -0
  109. data/lib/schematic/types/rule_condition_plan_version_response_data.rb +15 -0
  110. data/lib/schematic/types/rules_engine_schema_version.rb +1 -1
  111. data/lib/schematic/types/rulesengine_company.rb +2 -0
  112. data/lib/schematic/types/rulesengine_credit_postpaid_config.rb +9 -0
  113. data/lib/schematic/types/slack_connect_invite_status.rb +15 -0
  114. data/lib/schematic/types/slack_connect_invite_view.rb +15 -0
  115. data/lib/schematic/types/stripe_integration_config.rb +6 -0
  116. data/lib/schematic/types/stripe_sandbox_claim_link.rb +15 -0
  117. data/lib/schematic/types/stripe_sandbox_countries_response_data.rb +9 -0
  118. data/lib/schematic/types/stripe_sandbox_install_response_data.rb +21 -0
  119. data/lib/schematic/types/stripe_sandbox_keys_response_data.rb +13 -0
  120. data/lib/schematic/types/temporary_access_token_issuer_type.rb +12 -0
  121. data/lib/schematic/types/temporary_access_token_response_data.rb +3 -1
  122. data/lib/schematic/types/update_billing_plan_credit_grant_request_body.rb +12 -0
  123. data/lib/schematic/types/webhook_event_detail_response_data.rb +2 -0
  124. data/lib/schematic/types/webhook_event_response_data.rb +2 -0
  125. data/lib/schematic/version.rb +1 -1
  126. data/lib/schematic/wasm/rulesengine.wasm +0 -0
  127. data/lib/schematic/webhooks/client.rb +10 -10
  128. data/lib/schematic.rb +56 -4
  129. data/reference.md +1345 -44
  130. data/testapp/app.rb +13 -2
  131. metadata +55 -3
  132. data/lib/schematic/types/release_credit_lease_request_body.rb +0 -23
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Schematic
4
+ module Credits
5
+ module Types
6
+ class CountCreditSpendPoliciesRequest < Internal::Types::Model
7
+ field :billing_credit_id, -> { String }, optional: true, nullable: false
8
+
9
+ field :company_id, -> { String }, optional: true, nullable: false
10
+
11
+ field :scope_type, -> { Schematic::Types::CreditSpendPolicyScope }, optional: true, nullable: false
12
+
13
+ field :user_id, -> { String }, optional: true, nullable: false
14
+
15
+ field :user_ids, -> { String }, optional: true, nullable: false
16
+
17
+ field :limit, -> { Integer }, optional: true, nullable: false
18
+
19
+ field :offset, -> { Integer }, optional: true, nullable: false
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Schematic
4
+ module Credits
5
+ module Types
6
+ class CountCreditSpendPoliciesResponse < Internal::Types::Model
7
+ field :data, -> { Schematic::Types::CountResponse }, optional: false, nullable: false
8
+
9
+ field :params, -> { Schematic::Credits::Types::CountCreditSpendPoliciesParams }, optional: false, nullable: false
10
+ end
11
+ end
12
+ end
13
+ end
@@ -8,6 +8,8 @@ module Schematic
8
8
 
9
9
  field :company_id, -> { String }, optional: false, nullable: false
10
10
 
11
+ field :credit_bundle_id, -> { String }, optional: true, nullable: false
12
+
11
13
  field :credit_id, -> { String }, optional: false, nullable: false
12
14
 
13
15
  field :currency, -> { String }, optional: true, nullable: false
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Schematic
4
+ module Credits
5
+ module Types
6
+ class CreateCreditSpendPolicyRequestBody < Internal::Types::Model
7
+ field :billing_credit_id, -> { String }, optional: false, nullable: false
8
+
9
+ field :company_id, -> { String }, optional: true, nullable: false
10
+
11
+ field :label, -> { String }, optional: true, nullable: false
12
+
13
+ field :max_per_draw, -> { Integer }, optional: false, nullable: false
14
+
15
+ field :user_id, -> { String }, optional: true, nullable: false
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Schematic
4
+ module Credits
5
+ module Types
6
+ class CreateCreditSpendPolicyResponse < Internal::Types::Model
7
+ field :data, -> { Schematic::Types::CreditSpendPolicyResponseData }, optional: false, nullable: false
8
+
9
+ field :params, -> { Internal::Types::Hash[String, Object] }, optional: false, nullable: false
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Schematic
4
+ module Credits
5
+ module Types
6
+ class DeleteCreditSpendPolicyResponse < Internal::Types::Model
7
+ field :data, -> { Schematic::Types::DeleteResponse }, optional: false, nullable: false
8
+
9
+ field :params, -> { Internal::Types::Hash[String, Object] }, optional: false, nullable: false
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Schematic
4
+ module Credits
5
+ module Types
6
+ class GetCreditSpendPolicyResponse < Internal::Types::Model
7
+ field :data, -> { Schematic::Types::CreditSpendPolicyResponseData }, optional: false, nullable: false
8
+
9
+ field :params, -> { Internal::Types::Hash[String, Object] }, optional: false, nullable: false
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Schematic
4
+ module Credits
5
+ module Types
6
+ # Input parameters
7
+ class ListCreditSpendPoliciesParams < Internal::Types::Model
8
+ field :billing_credit_id, -> { String }, optional: true, nullable: false
9
+
10
+ field :company_id, -> { String }, optional: true, nullable: false
11
+
12
+ field :limit, -> { Integer }, optional: true, nullable: false
13
+
14
+ field :offset, -> { Integer }, optional: true, nullable: false
15
+
16
+ field :scope_type, -> { Schematic::Types::CreditSpendPolicyScope }, optional: true, nullable: false
17
+
18
+ field :user_id, -> { String }, optional: true, nullable: false
19
+
20
+ field :user_ids, -> { Internal::Types::Array[String] }, optional: true, nullable: false
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Schematic
4
+ module Credits
5
+ module Types
6
+ class ListCreditSpendPoliciesRequest < Internal::Types::Model
7
+ field :billing_credit_id, -> { String }, optional: true, nullable: false
8
+
9
+ field :company_id, -> { String }, optional: true, nullable: false
10
+
11
+ field :scope_type, -> { Schematic::Types::CreditSpendPolicyScope }, optional: true, nullable: false
12
+
13
+ field :user_id, -> { String }, optional: true, nullable: false
14
+
15
+ field :user_ids, -> { String }, optional: true, nullable: false
16
+
17
+ field :limit, -> { Integer }, optional: true, nullable: false
18
+
19
+ field :offset, -> { Integer }, optional: true, nullable: false
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Schematic
4
+ module Credits
5
+ module Types
6
+ class ListCreditSpendPoliciesResponse < Internal::Types::Model
7
+ field :data, -> { Internal::Types::Array[Schematic::Types::CreditSpendPolicyResponseData] }, optional: false, nullable: false
8
+
9
+ field :params, -> { Schematic::Credits::Types::ListCreditSpendPoliciesParams }, optional: false, nullable: false
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Schematic
4
+ module Credits
5
+ module Types
6
+ class ReleaseCreditReservationResponse < Internal::Types::Model
7
+ field :data, -> { Schematic::Types::CreditReservationResponseData }, optional: false, nullable: false
8
+
9
+ field :params, -> { Internal::Types::Hash[String, Object] }, optional: false, nullable: false
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Schematic
4
+ module Credits
5
+ module Types
6
+ class ReserveCreditsRequestBody < Internal::Types::Model
7
+ field :amount, -> { Integer }, optional: false, nullable: false
8
+
9
+ field :company_id, -> { String }, optional: false, nullable: false
10
+
11
+ field :credit_type_id, -> { String }, optional: false, nullable: false
12
+
13
+ field :expires_at, -> { String }, optional: true, nullable: false
14
+
15
+ field :idempotency_key, -> { String }, optional: true, nullable: false
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Schematic
4
+ module Credits
5
+ module Types
6
+ class ReserveCreditsResponse < Internal::Types::Model
7
+ field :data, -> { Schematic::Types::CreditReservationResponseData }, optional: false, nullable: false
8
+
9
+ field :params, -> { Internal::Types::Hash[String, Object] }, optional: false, nullable: false
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Schematic
4
+ module Credits
5
+ module Types
6
+ class UpdateCreditSpendPolicyRequestBody < Internal::Types::Model
7
+ field :spend_policy_id, -> { String }, optional: false, nullable: false
8
+
9
+ field :label, -> { String }, optional: true, nullable: false
10
+
11
+ field :max_per_draw, -> { Integer }, optional: true, nullable: false
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Schematic
4
+ module Credits
5
+ module Types
6
+ class UpdateCreditSpendPolicyResponse < Internal::Types::Model
7
+ field :data, -> { Schematic::Types::CreditSpendPolicyResponseData }, optional: false, nullable: false
8
+
9
+ field :params, -> { Internal::Types::Hash[String, Object] }, optional: false, nullable: false
10
+ end
11
+ end
12
+ end
13
+ end
@@ -53,7 +53,7 @@ module Schematic
53
53
  end
54
54
  code = response.code.to_i
55
55
  if code.between?(200, 299)
56
- Schematic::Dataexports::Types::ListDataExportsResponse.load(response.body)
56
+ (response.body.to_s.empty? ? nil : Schematic::Dataexports::Types::ListDataExportsResponse.load(response.body))
57
57
  else
58
58
  error_class = Schematic::Errors::ResponseError.subclass_for_code(code)
59
59
  raise error_class.new(response.body, code: code)
@@ -91,7 +91,7 @@ module Schematic
91
91
  end
92
92
  code = response.code.to_i
93
93
  if code.between?(200, 299)
94
- Schematic::Dataexports::Types::CreateDataExportResponse.load(response.body)
94
+ (response.body.to_s.empty? ? nil : Schematic::Dataexports::Types::CreateDataExportResponse.load(response.body))
95
95
  else
96
96
  error_class = Schematic::Errors::ResponseError.subclass_for_code(code)
97
97
  raise error_class.new(response.body, code: code)
@@ -126,7 +126,7 @@ module Schematic
126
126
  end
127
127
  code = response.code.to_i
128
128
  if code.between?(200, 299)
129
- Schematic::Dataexports::Types::GetDataExportResponse.load(response.body)
129
+ (response.body.to_s.empty? ? nil : Schematic::Dataexports::Types::GetDataExportResponse.load(response.body))
130
130
  else
131
131
  error_class = Schematic::Errors::ResponseError.subclass_for_code(code)
132
132
  raise error_class.new(response.body, code: code)
@@ -30,7 +30,8 @@ module Schematic
30
30
  redis_key_prefix: "schematic:",
31
31
  replicator_mode: false,
32
32
  replicator_health_url: REPLICATOR_HEALTH_URL,
33
- replicator_health_interval: REPLICATOR_HEALTH_INTERVAL
33
+ replicator_health_interval: REPLICATOR_HEALTH_INTERVAL,
34
+ max_frame_size: nil
34
35
  )
35
36
  @api_key = api_key
36
37
  @base_url = base_url
@@ -40,6 +41,7 @@ module Schematic
40
41
  @replicator_mode = replicator_mode
41
42
  @replicator_health_url = replicator_health_url
42
43
  @replicator_health_interval = replicator_health_interval
44
+ @max_frame_size = max_frame_size
43
45
  @replicator_ready = false
44
46
  @cache_version = ""
45
47
  @mutex = Mutex.new
@@ -120,7 +122,8 @@ module Schematic
120
122
  api_key: @api_key,
121
123
  logger: @logger,
122
124
  message_handler: method(:handle_message),
123
- ready_handler: method(:handle_ready)
125
+ ready_handler: method(:handle_ready),
126
+ max_frame_size: @max_frame_size
124
127
  )
125
128
  @ws_client.start
126
129
  end
@@ -3,8 +3,6 @@
3
3
  module Schematic
4
4
  module DataStream
5
5
  class ResourceCache
6
- CACHE_KEY_PREFIX = "schematic"
7
-
8
6
  def initialize(primary_cache:, lookup_cache:, key_prefix:, get_id:, get_keys:, cache_version: nil)
9
7
  @primary_cache = primary_cache
10
8
  @lookup_cache = lookup_cache
@@ -65,11 +63,11 @@ module Schematic
65
63
  private
66
64
 
67
65
  def build_id_key(id)
68
- "#{CACHE_KEY_PREFIX}:#{@key_prefix}:#{@cache_version}:#{id}"
66
+ "#{@key_prefix}:#{@cache_version}:#{id}"
69
67
  end
70
68
 
71
69
  def build_lookup_key(key_name, key_value)
72
- "#{CACHE_KEY_PREFIX}:#{@key_prefix}:#{@cache_version}:#{key_name.to_s.downcase}:#{key_value}"
70
+ "#{@key_prefix}:#{@cache_version}:#{key_name.to_s.downcase}:#{key_value.to_s.downcase}"
73
71
  end
74
72
  end
75
73
  end
@@ -37,15 +37,20 @@ module Schematic
37
37
  DATASTREAM_MODE_DIRECT = "direct"
38
38
  UNKNOWN_VERSION = "unknown"
39
39
 
40
+ # Symbol the websocket gem records on Frame::Incoming#error when an incoming
41
+ # frame declares a payload larger than WebSocket.max_frame_size.
42
+ FRAME_TOO_LONG = :frame_too_long
43
+
40
44
  class WebSocketClient
41
45
  attr_reader :url, :connected, :ready
42
46
 
43
- def initialize(base_url:, api_key:, logger:, message_handler:, ready_handler: nil)
47
+ def initialize(base_url:, api_key:, logger:, message_handler:, ready_handler: nil, max_frame_size: nil)
44
48
  @base_url = base_url
45
49
  @api_key = api_key
46
50
  @logger = logger
47
51
  @message_handler = message_handler
48
52
  @ready_handler = ready_handler
53
+ @max_frame_size = max_frame_size
49
54
  @connected = false
50
55
  @ready = false
51
56
  @should_reconnect = true
@@ -60,6 +65,7 @@ module Schematic
60
65
  @stopped = false
61
66
  @url = build_ws_url(base_url)
62
67
  @last_pong = Process.clock_gettime(Process::CLOCK_MONOTONIC)
68
+ apply_max_frame_size
63
69
  end
64
70
 
65
71
  def start
@@ -211,6 +217,22 @@ module Schematic
211
217
  break
212
218
  end
213
219
  end
220
+
221
+ # WebSocket::Frame::Incoming#next swallows protocol errors unless
222
+ # WebSocket.should_raise is set: it returns nil and records the
223
+ # reason on #error, which is indistinguishable from "no complete
224
+ # frame buffered yet". The error is also sticky — the offending
225
+ # header is never consumed — so without this check an oversized
226
+ # frame stalls the stream silently while the socket stays open.
227
+ if (parser_error = @frame_parser.error)
228
+ log_frame_parser_error(parser_error)
229
+ break
230
+ end
231
+ rescue WebSocket::Error::Frame::TooLong
232
+ # Reached only when the host process has set
233
+ # WebSocket.should_raise = true.
234
+ log_frame_parser_error(FRAME_TOO_LONG)
235
+ break
214
236
  rescue IOError, Errno::ECONNRESET, OpenSSL::SSL::SSLError => e
215
237
  @logger.warn("DataStream read error: #{e.message}")
216
238
  break
@@ -321,6 +343,42 @@ module Schematic
321
343
  @write_mutex.synchronize { @socket&.write(frame.to_s) }
322
344
  end
323
345
 
346
+ # The maximum incoming frame size the websocket gem will accept. The gem
347
+ # only exposes this as WebSocket.max_frame_size, a module-level global read
348
+ # at decode time; Frame::Incoming takes no per-instance limit (passing
349
+ # max_frame_size: to its constructor is silently ignored). A per-client
350
+ # option therefore cannot be fully isolated from the rest of the process.
351
+ #
352
+ # The compromise: do nothing unless the caller explicitly asks for a limit,
353
+ # and when they do, only ever raise the global — never lower it — so we
354
+ # cannot shrink the ceiling out from under another websocket user in the
355
+ # same process. The change is logged so it is visible rather than silent.
356
+ def apply_max_frame_size
357
+ return if @max_frame_size.nil?
358
+
359
+ raise ArgumentError, "max_frame_size must be a positive Integer, got #{@max_frame_size.inspect}" unless @max_frame_size.is_a?(Integer) && @max_frame_size.positive?
360
+
361
+ current = ::WebSocket.max_frame_size
362
+ if @max_frame_size <= current
363
+ @logger.debug("DataStream max_frame_size #{@max_frame_size} is at or below the current WebSocket.max_frame_size (#{current}); leaving it unchanged")
364
+ return
365
+ end
366
+
367
+ ::WebSocket.max_frame_size = @max_frame_size
368
+ @logger.info("Raised WebSocket.max_frame_size from #{current} to #{@max_frame_size} bytes; the websocket gem stores this limit globally, so it applies to every websocket in this process")
369
+ end
370
+
371
+ def log_frame_parser_error(parser_error)
372
+ if parser_error == FRAME_TOO_LONG
373
+ @logger.error(
374
+ "DataStream received a WebSocket frame larger than the #{::WebSocket.max_frame_size} byte limit and cannot decode it. " \
375
+ "Raise the limit with datastream_options: { max_frame_size: <bytes> } (note: the websocket gem applies this limit process-wide)."
376
+ )
377
+ else
378
+ @logger.error("DataStream frame decode error: #{parser_error}")
379
+ end
380
+ end
381
+
324
382
  # Headers attached to the WebSocket handshake. The mode/client headers let
325
383
  # the backend tell direct-SDK connections apart from the
326
384
  # schematic-datastream-replicator and correlate them to a release.
@@ -68,7 +68,7 @@ module Schematic
68
68
  end
69
69
  code = response.code.to_i
70
70
  if code.between?(200, 299)
71
- Schematic::Entitlements::Types::ListCompanyOverridesResponse.load(response.body)
71
+ (response.body.to_s.empty? ? nil : Schematic::Entitlements::Types::ListCompanyOverridesResponse.load(response.body))
72
72
  else
73
73
  error_class = Schematic::Errors::ResponseError.subclass_for_code(code)
74
74
  raise error_class.new(response.body, code: code)
@@ -107,7 +107,7 @@ module Schematic
107
107
  end
108
108
  code = response.code.to_i
109
109
  if code.between?(200, 299)
110
- Schematic::Entitlements::Types::CreateCompanyOverrideResponse.load(response.body)
110
+ (response.body.to_s.empty? ? nil : Schematic::Entitlements::Types::CreateCompanyOverrideResponse.load(response.body))
111
111
  else
112
112
  error_class = Schematic::Errors::ResponseError.subclass_for_code(code)
113
113
  raise error_class.new(response.body, code: code)
@@ -142,7 +142,7 @@ module Schematic
142
142
  end
143
143
  code = response.code.to_i
144
144
  if code.between?(200, 299)
145
- Schematic::Entitlements::Types::GetCompanyOverrideResponse.load(response.body)
145
+ (response.body.to_s.empty? ? nil : Schematic::Entitlements::Types::GetCompanyOverrideResponse.load(response.body))
146
146
  else
147
147
  error_class = Schematic::Errors::ResponseError.subclass_for_code(code)
148
148
  raise error_class.new(response.body, code: code)
@@ -185,7 +185,7 @@ module Schematic
185
185
  end
186
186
  code = response.code.to_i
187
187
  if code.between?(200, 299)
188
- Schematic::Entitlements::Types::UpdateCompanyOverrideResponse.load(response.body)
188
+ (response.body.to_s.empty? ? nil : Schematic::Entitlements::Types::UpdateCompanyOverrideResponse.load(response.body))
189
189
  else
190
190
  error_class = Schematic::Errors::ResponseError.subclass_for_code(code)
191
191
  raise error_class.new(response.body, code: code)
@@ -220,7 +220,7 @@ module Schematic
220
220
  end
221
221
  code = response.code.to_i
222
222
  if code.between?(200, 299)
223
- Schematic::Entitlements::Types::DeleteCompanyOverrideResponse.load(response.body)
223
+ (response.body.to_s.empty? ? nil : Schematic::Entitlements::Types::DeleteCompanyOverrideResponse.load(response.body))
224
224
  else
225
225
  error_class = Schematic::Errors::ResponseError.subclass_for_code(code)
226
226
  raise error_class.new(response.body, code: code)
@@ -285,7 +285,7 @@ module Schematic
285
285
  end
286
286
  code = response.code.to_i
287
287
  if code.between?(200, 299)
288
- Schematic::Entitlements::Types::CountCompanyOverridesResponse.load(response.body)
288
+ (response.body.to_s.empty? ? nil : Schematic::Entitlements::Types::CountCompanyOverridesResponse.load(response.body))
289
289
  else
290
290
  error_class = Schematic::Errors::ResponseError.subclass_for_code(code)
291
291
  raise error_class.new(response.body, code: code)
@@ -335,7 +335,7 @@ module Schematic
335
335
  end
336
336
  code = response.code.to_i
337
337
  if code.between?(200, 299)
338
- Schematic::Entitlements::Types::ListFeatureCompaniesResponse.load(response.body)
338
+ (response.body.to_s.empty? ? nil : Schematic::Entitlements::Types::ListFeatureCompaniesResponse.load(response.body))
339
339
  else
340
340
  error_class = Schematic::Errors::ResponseError.subclass_for_code(code)
341
341
  raise error_class.new(response.body, code: code)
@@ -385,7 +385,7 @@ module Schematic
385
385
  end
386
386
  code = response.code.to_i
387
387
  if code.between?(200, 299)
388
- Schematic::Entitlements::Types::CountFeatureCompaniesResponse.load(response.body)
388
+ (response.body.to_s.empty? ? nil : Schematic::Entitlements::Types::CountFeatureCompaniesResponse.load(response.body))
389
389
  else
390
390
  error_class = Schematic::Errors::ResponseError.subclass_for_code(code)
391
391
  raise error_class.new(response.body, code: code)
@@ -449,7 +449,7 @@ module Schematic
449
449
  end
450
450
  code = response.code.to_i
451
451
  if code.between?(200, 299)
452
- Schematic::Entitlements::Types::ListFeatureUsageResponse.load(response.body)
452
+ (response.body.to_s.empty? ? nil : Schematic::Entitlements::Types::ListFeatureUsageResponse.load(response.body))
453
453
  else
454
454
  error_class = Schematic::Errors::ResponseError.subclass_for_code(code)
455
455
  raise error_class.new(response.body, code: code)
@@ -508,7 +508,7 @@ module Schematic
508
508
  end
509
509
  code = response.code.to_i
510
510
  if code.between?(200, 299)
511
- Schematic::Entitlements::Types::ListFeatureUsageHistoryResponse.load(response.body)
511
+ (response.body.to_s.empty? ? nil : Schematic::Entitlements::Types::ListFeatureUsageHistoryResponse.load(response.body))
512
512
  else
513
513
  error_class = Schematic::Errors::ResponseError.subclass_for_code(code)
514
514
  raise error_class.new(response.body, code: code)
@@ -561,7 +561,7 @@ module Schematic
561
561
  end
562
562
  code = response.code.to_i
563
563
  if code.between?(200, 299)
564
- Schematic::Entitlements::Types::GetFeatureUsageTimeSeriesResponse.load(response.body)
564
+ (response.body.to_s.empty? ? nil : Schematic::Entitlements::Types::GetFeatureUsageTimeSeriesResponse.load(response.body))
565
565
  else
566
566
  error_class = Schematic::Errors::ResponseError.subclass_for_code(code)
567
567
  raise error_class.new(response.body, code: code)
@@ -625,7 +625,7 @@ module Schematic
625
625
  end
626
626
  code = response.code.to_i
627
627
  if code.between?(200, 299)
628
- Schematic::Entitlements::Types::CountFeatureUsageResponse.load(response.body)
628
+ (response.body.to_s.empty? ? nil : Schematic::Entitlements::Types::CountFeatureUsageResponse.load(response.body))
629
629
  else
630
630
  error_class = Schematic::Errors::ResponseError.subclass_for_code(code)
631
631
  raise error_class.new(response.body, code: code)
@@ -675,7 +675,7 @@ module Schematic
675
675
  end
676
676
  code = response.code.to_i
677
677
  if code.between?(200, 299)
678
- Schematic::Entitlements::Types::ListFeatureUsersResponse.load(response.body)
678
+ (response.body.to_s.empty? ? nil : Schematic::Entitlements::Types::ListFeatureUsersResponse.load(response.body))
679
679
  else
680
680
  error_class = Schematic::Errors::ResponseError.subclass_for_code(code)
681
681
  raise error_class.new(response.body, code: code)
@@ -725,7 +725,7 @@ module Schematic
725
725
  end
726
726
  code = response.code.to_i
727
727
  if code.between?(200, 299)
728
- Schematic::Entitlements::Types::CountFeatureUsersResponse.load(response.body)
728
+ (response.body.to_s.empty? ? nil : Schematic::Entitlements::Types::CountFeatureUsersResponse.load(response.body))
729
729
  else
730
730
  error_class = Schematic::Errors::ResponseError.subclass_for_code(code)
731
731
  raise error_class.new(response.body, code: code)
@@ -796,7 +796,7 @@ module Schematic
796
796
  end
797
797
  code = response.code.to_i
798
798
  if code.between?(200, 299)
799
- Schematic::Entitlements::Types::ListPlanEntitlementsResponse.load(response.body)
799
+ (response.body.to_s.empty? ? nil : Schematic::Entitlements::Types::ListPlanEntitlementsResponse.load(response.body))
800
800
  else
801
801
  error_class = Schematic::Errors::ResponseError.subclass_for_code(code)
802
802
  raise error_class.new(response.body, code: code)
@@ -835,7 +835,7 @@ module Schematic
835
835
  end
836
836
  code = response.code.to_i
837
837
  if code.between?(200, 299)
838
- Schematic::Entitlements::Types::CreatePlanEntitlementResponse.load(response.body)
838
+ (response.body.to_s.empty? ? nil : Schematic::Entitlements::Types::CreatePlanEntitlementResponse.load(response.body))
839
839
  else
840
840
  error_class = Schematic::Errors::ResponseError.subclass_for_code(code)
841
841
  raise error_class.new(response.body, code: code)
@@ -870,7 +870,7 @@ module Schematic
870
870
  end
871
871
  code = response.code.to_i
872
872
  if code.between?(200, 299)
873
- Schematic::Entitlements::Types::GetPlanEntitlementResponse.load(response.body)
873
+ (response.body.to_s.empty? ? nil : Schematic::Entitlements::Types::GetPlanEntitlementResponse.load(response.body))
874
874
  else
875
875
  error_class = Schematic::Errors::ResponseError.subclass_for_code(code)
876
876
  raise error_class.new(response.body, code: code)
@@ -913,7 +913,7 @@ module Schematic
913
913
  end
914
914
  code = response.code.to_i
915
915
  if code.between?(200, 299)
916
- Schematic::Entitlements::Types::UpdatePlanEntitlementResponse.load(response.body)
916
+ (response.body.to_s.empty? ? nil : Schematic::Entitlements::Types::UpdatePlanEntitlementResponse.load(response.body))
917
917
  else
918
918
  error_class = Schematic::Errors::ResponseError.subclass_for_code(code)
919
919
  raise error_class.new(response.body, code: code)
@@ -948,7 +948,7 @@ module Schematic
948
948
  end
949
949
  code = response.code.to_i
950
950
  if code.between?(200, 299)
951
- Schematic::Entitlements::Types::DeletePlanEntitlementResponse.load(response.body)
951
+ (response.body.to_s.empty? ? nil : Schematic::Entitlements::Types::DeletePlanEntitlementResponse.load(response.body))
952
952
  else
953
953
  error_class = Schematic::Errors::ResponseError.subclass_for_code(code)
954
954
  raise error_class.new(response.body, code: code)
@@ -989,7 +989,7 @@ module Schematic
989
989
  end
990
990
  code = response.code.to_i
991
991
  if code.between?(200, 299)
992
- Schematic::Entitlements::Types::UpsertPlanEntitlementForBillingProductResponse.load(response.body)
992
+ (response.body.to_s.empty? ? nil : Schematic::Entitlements::Types::UpsertPlanEntitlementForBillingProductResponse.load(response.body))
993
993
  else
994
994
  error_class = Schematic::Errors::ResponseError.subclass_for_code(code)
995
995
  raise error_class.new(response.body, code: code)
@@ -1060,7 +1060,7 @@ module Schematic
1060
1060
  end
1061
1061
  code = response.code.to_i
1062
1062
  if code.between?(200, 299)
1063
- Schematic::Entitlements::Types::CountPlanEntitlementsResponse.load(response.body)
1063
+ (response.body.to_s.empty? ? nil : Schematic::Entitlements::Types::CountPlanEntitlementsResponse.load(response.body))
1064
1064
  else
1065
1065
  error_class = Schematic::Errors::ResponseError.subclass_for_code(code)
1066
1066
  raise error_class.new(response.body, code: code)
@@ -1098,7 +1098,7 @@ module Schematic
1098
1098
  end
1099
1099
  code = response.code.to_i
1100
1100
  if code.between?(200, 299)
1101
- Schematic::Entitlements::Types::DuplicatePlanEntitlementsResponse.load(response.body)
1101
+ (response.body.to_s.empty? ? nil : Schematic::Entitlements::Types::DuplicatePlanEntitlementsResponse.load(response.body))
1102
1102
  else
1103
1103
  error_class = Schematic::Errors::ResponseError.subclass_for_code(code)
1104
1104
  raise error_class.new(response.body, code: code)
@@ -1139,7 +1139,7 @@ module Schematic
1139
1139
  end
1140
1140
  code = response.code.to_i
1141
1141
  if code.between?(200, 299)
1142
- Schematic::Entitlements::Types::GetFeatureUsageByCompanyResponse.load(response.body)
1142
+ (response.body.to_s.empty? ? nil : Schematic::Entitlements::Types::GetFeatureUsageByCompanyResponse.load(response.body))
1143
1143
  else
1144
1144
  error_class = Schematic::Errors::ResponseError.subclass_for_code(code)
1145
1145
  raise error_class.new(response.body, code: code)
@@ -1189,7 +1189,7 @@ module Schematic
1189
1189
  end
1190
1190
  code = response.code.to_i
1191
1191
  if code.between?(200, 299)
1192
- Schematic::Entitlements::Types::GetUserUsageByCompanyResponse.load(response.body)
1192
+ (response.body.to_s.empty? ? nil : Schematic::Entitlements::Types::GetUserUsageByCompanyResponse.load(response.body))
1193
1193
  else
1194
1194
  error_class = Schematic::Errors::ResponseError.subclass_for_code(code)
1195
1195
  raise error_class.new(response.body, code: code)
@@ -1239,7 +1239,7 @@ module Schematic
1239
1239
  end
1240
1240
  code = response.code.to_i
1241
1241
  if code.between?(200, 299)
1242
- Schematic::Entitlements::Types::GetUserUsageDetailResponse.load(response.body)
1242
+ (response.body.to_s.empty? ? nil : Schematic::Entitlements::Types::GetUserUsageDetailResponse.load(response.body))
1243
1243
  else
1244
1244
  error_class = Schematic::Errors::ResponseError.subclass_for_code(code)
1245
1245
  raise error_class.new(response.body, code: code)