schematichq 1.4.2 → 1.4.3

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 (65) hide show
  1. checksums.yaml +4 -4
  2. data/.fern/metadata.json +2 -2
  3. data/README.md +33 -3
  4. data/WASM_VERSION +1 -1
  5. data/lib/schematic/billing/client.rb +32 -0
  6. data/lib/schematic/billing/types/delete_payment_method_by_external_id_response.rb +12 -0
  7. data/lib/schematic/client.rb +1 -1
  8. data/lib/schematic/companies/client.rb +6 -2
  9. data/lib/schematic/companies/types/count_companies_params.rb +1 -0
  10. data/lib/schematic/companies/types/count_companies_request.rb +1 -0
  11. data/lib/schematic/companies/types/list_companies_params.rb +1 -0
  12. data/lib/schematic/companies/types/list_companies_request.rb +1 -0
  13. data/lib/schematic/credits/client.rb +102 -0
  14. data/lib/schematic/credits/types/acquire_credit_lease_request_body.rb +14 -0
  15. data/lib/schematic/credits/types/acquire_credit_lease_response.rb +12 -0
  16. data/lib/schematic/credits/types/extend_credit_lease_request_body.rb +13 -0
  17. data/lib/schematic/credits/types/extend_credit_lease_response.rb +12 -0
  18. data/lib/schematic/credits/types/release_credit_lease_response.rb +12 -0
  19. data/lib/schematic/datastream/merge.rb +71 -0
  20. data/lib/schematic/entitlements/types/create_billing_linked_plan_entitlement_request_body.rb +1 -0
  21. data/lib/schematic/entitlements/types/create_plan_entitlement_request_body.rb +1 -0
  22. data/lib/schematic/entitlements/types/update_plan_entitlement_request_body.rb +1 -0
  23. data/lib/schematic/event_buffer.rb +7 -1
  24. data/lib/schematic/logger.rb +1 -1
  25. data/lib/schematic/planmigrations/client.rb +101 -0
  26. data/lib/schematic/planmigrations/types/create_migration_input.rb +17 -0
  27. data/lib/schematic/planmigrations/types/create_migration_response.rb +12 -0
  28. data/lib/schematic/planmigrations/types/retry_company_migration_response.rb +12 -0
  29. data/lib/schematic/planmigrations/types/retry_migration_request_body.rb +12 -0
  30. data/lib/schematic/planmigrations/types/retry_migration_response.rb +12 -0
  31. data/lib/schematic/plans/client.rb +39 -2
  32. data/lib/schematic/plans/types/count_plans_params.rb +1 -0
  33. data/lib/schematic/plans/types/count_plans_request.rb +1 -0
  34. data/lib/schematic/plans/types/list_plans_params.rb +1 -0
  35. data/lib/schematic/plans/types/list_plans_request.rb +1 -0
  36. data/lib/schematic/plans/types/mark_custom_plan_billing_paid_response.rb +12 -0
  37. data/lib/schematic/schematic_client.rb +46 -13
  38. data/lib/schematic/types/checkout_subscription.rb +1 -0
  39. data/lib/schematic/types/company_plan_detail_response_data.rb +2 -1
  40. data/lib/schematic/types/create_entitlement_in_bundle_request_body.rb +1 -0
  41. data/lib/schematic/types/credit_lease_response_data.rb +16 -0
  42. data/lib/schematic/types/custom_plan_billing_response_data.rb +1 -0
  43. data/lib/schematic/types/event_body_track.rb +1 -0
  44. data/lib/schematic/types/feature_view.rb +1 -0
  45. data/lib/schematic/types/integration_config.rb +1 -0
  46. data/lib/schematic/types/integration_type.rb +1 -0
  47. data/lib/schematic/types/mark_custom_plan_billing_paid_request_body.rb +23 -0
  48. data/lib/schematic/types/migration_error_code.rb +21 -0
  49. data/lib/schematic/types/plan_detail_response_data.rb +1 -0
  50. data/lib/schematic/types/plan_entitlement_response_data.rb +1 -0
  51. data/lib/schematic/types/plan_group_plan_detail_response_data.rb +2 -1
  52. data/lib/schematic/types/plan_price_cadence.rb +13 -0
  53. data/lib/schematic/types/plan_version_company_migration_response_data.rb +1 -0
  54. data/lib/schematic/types/plan_version_migration_response_data.rb +1 -0
  55. data/lib/schematic/types/plan_view_public_response_data.rb +2 -1
  56. data/lib/schematic/types/release_credit_lease_request_body.rb +23 -0
  57. data/lib/schematic/types/stripe_integration_config.rb +0 -1
  58. data/lib/schematic/types/usage_based_entitlement_request_body.rb +1 -0
  59. data/lib/schematic/types/usage_based_entitlement_response_data.rb +1 -0
  60. data/lib/schematic/types/work_os_integration_config.rb +10 -0
  61. data/lib/schematic/version.rb +1 -1
  62. data/lib/schematic/wasm/rulesengine.wasm +0 -0
  63. data/lib/schematic.rb +18 -0
  64. data/reference.md +582 -2
  65. metadata +20 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3d21af200007a5f9fad7ebc682971bbad191e98c0b5f7cd10b691627651069c7
4
- data.tar.gz: e944d620948b8acdb24d375eed9365982edf50c8ff089a6f4c74821cbb88a4c3
3
+ metadata.gz: 52c3520cf93bf33b5709b843536791c05f1f79cde2521fed583179802ea01a13
4
+ data.tar.gz: b321618dcbe10659189f72554ee428638e022fc8afb044a11cc87fc59c441624
5
5
  SHA512:
6
- metadata.gz: 980692b9e74fbbf6683623e2502bd5ef153d78f5c20245bdb5d3cc26787eaa142f6ac345ba5873acfb29a2fa93a2e0c0beab40717c692e5f3154d731219fad9d
7
- data.tar.gz: 0f16bc4c9d391123750a85530d21a7a4a841cf8962d2cc867912f2935f0627e732cbff5c1c56ed677302704636290f962794066c18d9cb6f4e2d74dc63f3890d
6
+ metadata.gz: c3c953562cb84790a3bd211f88eac886330a71e20c2d83d815a5216883a6eade2981e34df357c923dd9bae64571203600528855b747df3798e7e1d11ef9051b8
7
+ data.tar.gz: 2c3cead033c8c600ef24f886541fa8102b6cff15299aef884225f58e292793eedb356305ebc5c80fc0cdd4f5288ddd1cd33b29dca4284a999a1e904a25129bb9
data/.fern/metadata.json CHANGED
@@ -13,6 +13,6 @@
13
13
  "webrick": ">= 1.0"
14
14
  }
15
15
  },
16
- "originGitCommit": "3dc12b536625ca1efbb649f6c55df7da258c7e05",
17
- "sdkVersion": "1.4.2"
16
+ "originGitCommit": "a3057c10aa6a1daa708dc714c89ce943f67a722a",
17
+ "sdkVersion": "1.4.3"
18
18
  }
data/README.md CHANGED
@@ -127,7 +127,7 @@ client = Schematic::SchematicClient.new(
127
127
  client.close
128
128
  ```
129
129
 
130
- You can also adjust the log level of the built-in console logger:
130
+ You can also adjust the log level of the built-in console logger via the `log_level` option:
131
131
 
132
132
  ```ruby
133
133
  require "schematichq"
@@ -135,11 +135,11 @@ require "schematichq"
135
135
  api_key = ENV["SCHEMATIC_API_KEY"]
136
136
  client = Schematic::SchematicClient.new(
137
137
  api_key: api_key,
138
- logger: Schematic::ConsoleLogger.new(level: :debug)
138
+ log_level: :debug
139
139
  )
140
140
  ```
141
141
 
142
- If no logger is provided, the client will use a default console logger at the `:info` level that outputs to stderr.
142
+ If no logger is provided, the client will use a default console logger at the `:warn` level that outputs to stderr. The `log_level` option only applies to this built-in logger; when you supply your own `logger`, its level is left untouched.
143
143
 
144
144
  ## Usage Examples
145
145
 
@@ -216,6 +216,36 @@ client.track({
216
216
  })
217
217
  ```
218
218
 
219
+ #### Event options
220
+
221
+ Both `track` and `identify` accept an `options:` keyword for optional event metadata. Only fields you set are sent.
222
+
223
+ ```ruby
224
+ client.track(
225
+ { event: "query-tokens", company: { "id" => "your-company-id" }, quantity: 1500 },
226
+ options: {
227
+ # Dedupe key. Duplicate events with the same key are dropped
228
+ # server-side for 24 hours.
229
+ idempotency_key: "evt_2026_05_21_query_tokens",
230
+ # Timestamp the event occurred (Time or ISO 8601 String). Required
231
+ # when trusted_client_clock is true.
232
+ sent_at: Time.now.utc,
233
+ # Use sent_at as the effective event time instead of server receipt
234
+ # time. Requires a secret API key and sent_at.
235
+ trusted_client_clock: true,
236
+ # Import historical data without affecting billing. Requires a secret
237
+ # API key and trusted_client_clock.
238
+ backfill: false
239
+ }
240
+ )
241
+
242
+ client.identify(
243
+ { keys: { "user_id" => "your-user-id" }, name: "Wile E. Coyote" },
244
+ # identify only supports idempotency_key.
245
+ options: { idempotency_key: "ident_your-user-id" }
246
+ )
247
+ ```
248
+
219
249
  ### Creating and updating companies
220
250
 
221
251
  Although it is faster to create companies and users via identify events, if you need to handle a response, you can use the companies API to upsert companies. Because you use your own identifiers to identify companies, rather than a Schematic company ID, creating and updating companies are both done via the same upsert operation:
data/WASM_VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.0
1
+ 0.2.0
@@ -442,6 +442,38 @@ module Schematic
442
442
  end
443
443
  end
444
444
 
445
+ # @param request_options [Hash]
446
+ # @param params [Hash]
447
+ # @option request_options [String] :base_url
448
+ # @option request_options [Hash{String => Object}] :additional_headers
449
+ # @option request_options [Hash{String => Object}] :additional_query_parameters
450
+ # @option request_options [Hash{String => Object}] :additional_body_parameters
451
+ # @option request_options [Integer] :timeout_in_seconds
452
+ # @option params [String] :billing_id
453
+ #
454
+ # @return [Schematic::Billing::Types::DeletePaymentMethodByExternalIdResponse]
455
+ def delete_payment_method_by_external_id(request_options: {}, **params)
456
+ params = Schematic::Internal::Types::Utils.normalize_keys(params)
457
+ request = Schematic::Internal::JSON::Request.new(
458
+ base_url: request_options[:base_url],
459
+ method: "DELETE",
460
+ path: "billing/payment-methods/#{URI.encode_uri_component(params[:billing_id].to_s)}",
461
+ request_options: request_options
462
+ )
463
+ begin
464
+ response = @client.send(request)
465
+ rescue Net::HTTPRequestTimeout
466
+ raise Schematic::Errors::TimeoutError
467
+ end
468
+ code = response.code.to_i
469
+ if code.between?(200, 299)
470
+ Schematic::Billing::Types::DeletePaymentMethodByExternalIdResponse.load(response.body)
471
+ else
472
+ error_class = Schematic::Errors::ResponseError.subclass_for_code(code)
473
+ raise error_class.new(response.body, code: code)
474
+ end
475
+ end
476
+
445
477
  # @param request_options [Hash]
446
478
  # @param params [Hash]
447
479
  # @option request_options [String] :base_url
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Schematic
4
+ module Billing
5
+ module Types
6
+ class DeletePaymentMethodByExternalIdResponse < Internal::Types::Model
7
+ field :data, -> { Schematic::Types::DeleteResponse }, optional: false, nullable: false
8
+ field :params, -> { Internal::Types::Hash[String, Object] }, optional: false, nullable: false
9
+ end
10
+ end
11
+ end
12
+ end
@@ -10,7 +10,7 @@ module Schematic
10
10
  @raw_client = Schematic::Internal::Http::RawClient.new(
11
11
  base_url: base_url || Schematic::Environment::DEFAULT,
12
12
  headers: {
13
- "User-Agent" => "schematichq/1.4.2",
13
+ "User-Agent" => "schematichq/1.4.3",
14
14
  "X-Fern-Language" => "Ruby",
15
15
  "X-Schematic-Api-Key" => api_key.to_s
16
16
  }
@@ -24,6 +24,7 @@ module Schematic
24
24
  # @option params [String, nil] :plan_id
25
25
  # @option params [String, nil] :plan_ids
26
26
  # @option params [String, nil] :plan_version_id
27
+ # @option params [String, nil] :plan_version_ids
27
28
  # @option params [String, nil] :q
28
29
  # @option params [String, nil] :sort_order_column
29
30
  # @option params [Schematic::Types::SortDirection, nil] :sort_order_direction
@@ -40,7 +41,7 @@ module Schematic
40
41
  # @return [Schematic::Companies::Types::ListCompaniesResponse]
41
42
  def list_companies(request_options: {}, **params)
42
43
  params = Schematic::Internal::Types::Utils.normalize_keys(params)
43
- query_param_names = %i[credit_type_ids has_scheduled_downgrade ids monetized_subscriptions plan_id plan_ids plan_version_id q sort_order_column sort_order_direction subscription_statuses subscription_types with_entitlement_for without_feature_override_for without_plan without_subscription with_subscription limit offset]
44
+ query_param_names = %i[credit_type_ids has_scheduled_downgrade ids monetized_subscriptions plan_id plan_ids plan_version_id plan_version_ids q sort_order_column sort_order_direction subscription_statuses subscription_types with_entitlement_for without_feature_override_for without_plan without_subscription with_subscription limit offset]
44
45
  query_params = {}
45
46
  query_params["credit_type_ids"] = params[:credit_type_ids] if params.key?(:credit_type_ids)
46
47
  query_params["has_scheduled_downgrade"] = params[:has_scheduled_downgrade] if params.key?(:has_scheduled_downgrade)
@@ -49,6 +50,7 @@ module Schematic
49
50
  query_params["plan_id"] = params[:plan_id] if params.key?(:plan_id)
50
51
  query_params["plan_ids"] = params[:plan_ids] if params.key?(:plan_ids)
51
52
  query_params["plan_version_id"] = params[:plan_version_id] if params.key?(:plan_version_id)
53
+ query_params["plan_version_ids"] = params[:plan_version_ids] if params.key?(:plan_version_ids)
52
54
  query_params["q"] = params[:q] if params.key?(:q)
53
55
  query_params["sort_order_column"] = params[:sort_order_column] if params.key?(:sort_order_column)
54
56
  query_params["sort_order_direction"] = params[:sort_order_direction] if params.key?(:sort_order_direction)
@@ -203,6 +205,7 @@ module Schematic
203
205
  # @option params [String, nil] :plan_id
204
206
  # @option params [String, nil] :plan_ids
205
207
  # @option params [String, nil] :plan_version_id
208
+ # @option params [String, nil] :plan_version_ids
206
209
  # @option params [String, nil] :q
207
210
  # @option params [String, nil] :sort_order_column
208
211
  # @option params [Schematic::Types::SortDirection, nil] :sort_order_direction
@@ -219,7 +222,7 @@ module Schematic
219
222
  # @return [Schematic::Companies::Types::CountCompaniesResponse]
220
223
  def count_companies(request_options: {}, **params)
221
224
  params = Schematic::Internal::Types::Utils.normalize_keys(params)
222
- query_param_names = %i[credit_type_ids has_scheduled_downgrade ids monetized_subscriptions plan_id plan_ids plan_version_id q sort_order_column sort_order_direction subscription_statuses subscription_types with_entitlement_for without_feature_override_for without_plan without_subscription with_subscription limit offset]
225
+ query_param_names = %i[credit_type_ids has_scheduled_downgrade ids monetized_subscriptions plan_id plan_ids plan_version_id plan_version_ids q sort_order_column sort_order_direction subscription_statuses subscription_types with_entitlement_for without_feature_override_for without_plan without_subscription with_subscription limit offset]
223
226
  query_params = {}
224
227
  query_params["credit_type_ids"] = params[:credit_type_ids] if params.key?(:credit_type_ids)
225
228
  query_params["has_scheduled_downgrade"] = params[:has_scheduled_downgrade] if params.key?(:has_scheduled_downgrade)
@@ -228,6 +231,7 @@ module Schematic
228
231
  query_params["plan_id"] = params[:plan_id] if params.key?(:plan_id)
229
232
  query_params["plan_ids"] = params[:plan_ids] if params.key?(:plan_ids)
230
233
  query_params["plan_version_id"] = params[:plan_version_id] if params.key?(:plan_version_id)
234
+ query_params["plan_version_ids"] = params[:plan_version_ids] if params.key?(:plan_version_ids)
231
235
  query_params["q"] = params[:q] if params.key?(:q)
232
236
  query_params["sort_order_column"] = params[:sort_order_column] if params.key?(:sort_order_column)
233
237
  query_params["sort_order_direction"] = params[:sort_order_direction] if params.key?(:sort_order_direction)
@@ -14,6 +14,7 @@ module Schematic
14
14
  field :plan_id, -> { String }, optional: true, nullable: false
15
15
  field :plan_ids, -> { Internal::Types::Array[String] }, optional: true, nullable: false
16
16
  field :plan_version_id, -> { String }, optional: true, nullable: false
17
+ field :plan_version_ids, -> { Internal::Types::Array[String] }, optional: true, nullable: false
17
18
  field :q, -> { String }, optional: true, nullable: false
18
19
  field :sort_order_column, -> { String }, optional: true, nullable: false
19
20
  field :sort_order_direction, -> { Schematic::Types::SortDirection }, optional: true, nullable: false
@@ -11,6 +11,7 @@ module Schematic
11
11
  field :plan_id, -> { String }, optional: true, nullable: false
12
12
  field :plan_ids, -> { String }, optional: true, nullable: false
13
13
  field :plan_version_id, -> { String }, optional: true, nullable: false
14
+ field :plan_version_ids, -> { String }, optional: true, nullable: false
14
15
  field :q, -> { String }, optional: true, nullable: false
15
16
  field :sort_order_column, -> { String }, optional: true, nullable: false
16
17
  field :sort_order_direction, -> { Schematic::Types::SortDirection }, optional: true, nullable: false
@@ -14,6 +14,7 @@ module Schematic
14
14
  field :plan_id, -> { String }, optional: true, nullable: false
15
15
  field :plan_ids, -> { Internal::Types::Array[String] }, optional: true, nullable: false
16
16
  field :plan_version_id, -> { String }, optional: true, nullable: false
17
+ field :plan_version_ids, -> { Internal::Types::Array[String] }, optional: true, nullable: false
17
18
  field :q, -> { String }, optional: true, nullable: false
18
19
  field :sort_order_column, -> { String }, optional: true, nullable: false
19
20
  field :sort_order_direction, -> { Schematic::Types::SortDirection }, optional: true, nullable: false
@@ -11,6 +11,7 @@ module Schematic
11
11
  field :plan_id, -> { String }, optional: true, nullable: false
12
12
  field :plan_ids, -> { String }, optional: true, nullable: false
13
13
  field :plan_version_id, -> { String }, optional: true, nullable: false
14
+ field :plan_version_ids, -> { String }, optional: true, nullable: false
14
15
  field :q, -> { String }, optional: true, nullable: false
15
16
  field :sort_order_column, -> { String }, optional: true, nullable: false
16
17
  field :sort_order_direction, -> { Schematic::Types::SortDirection }, optional: true, nullable: false
@@ -747,6 +747,108 @@ module Schematic
747
747
  end
748
748
  end
749
749
 
750
+ # @param request_options [Hash]
751
+ # @param params [Schematic::Credits::Types::AcquireCreditLeaseRequestBody]
752
+ # @option request_options [String] :base_url
753
+ # @option request_options [Hash{String => Object}] :additional_headers
754
+ # @option request_options [Hash{String => Object}] :additional_query_parameters
755
+ # @option request_options [Hash{String => Object}] :additional_body_parameters
756
+ # @option request_options [Integer] :timeout_in_seconds
757
+ #
758
+ # @return [Schematic::Credits::Types::AcquireCreditLeaseResponse]
759
+ def acquire_credit_lease(request_options: {}, **params)
760
+ params = Schematic::Internal::Types::Utils.normalize_keys(params)
761
+ request = Schematic::Internal::JSON::Request.new(
762
+ base_url: request_options[:base_url],
763
+ method: "POST",
764
+ path: "billing/credits/lease",
765
+ body: Schematic::Credits::Types::AcquireCreditLeaseRequestBody.new(params).to_h,
766
+ request_options: request_options
767
+ )
768
+ begin
769
+ response = @client.send(request)
770
+ rescue Net::HTTPRequestTimeout
771
+ raise Schematic::Errors::TimeoutError
772
+ end
773
+ code = response.code.to_i
774
+ if code.between?(200, 299)
775
+ Schematic::Credits::Types::AcquireCreditLeaseResponse.load(response.body)
776
+ else
777
+ error_class = Schematic::Errors::ResponseError.subclass_for_code(code)
778
+ raise error_class.new(response.body, code: code)
779
+ end
780
+ end
781
+
782
+ # @param request_options [Hash]
783
+ # @param params [Schematic::Credits::Types::ExtendCreditLeaseRequestBody]
784
+ # @option request_options [String] :base_url
785
+ # @option request_options [Hash{String => Object}] :additional_headers
786
+ # @option request_options [Hash{String => Object}] :additional_query_parameters
787
+ # @option request_options [Hash{String => Object}] :additional_body_parameters
788
+ # @option request_options [Integer] :timeout_in_seconds
789
+ # @option params [String] :lease_id
790
+ #
791
+ # @return [Schematic::Credits::Types::ExtendCreditLeaseResponse]
792
+ def extend_credit_lease(request_options: {}, **params)
793
+ params = Schematic::Internal::Types::Utils.normalize_keys(params)
794
+ request_data = Schematic::Credits::Types::ExtendCreditLeaseRequestBody.new(params).to_h
795
+ non_body_param_names = ["lease_id"]
796
+ body = request_data.except(*non_body_param_names)
797
+
798
+ request = Schematic::Internal::JSON::Request.new(
799
+ base_url: request_options[:base_url],
800
+ method: "PUT",
801
+ path: "billing/credits/lease/#{URI.encode_uri_component(params[:lease_id].to_s)}/extend",
802
+ body: body,
803
+ request_options: request_options
804
+ )
805
+ begin
806
+ response = @client.send(request)
807
+ rescue Net::HTTPRequestTimeout
808
+ raise Schematic::Errors::TimeoutError
809
+ end
810
+ code = response.code.to_i
811
+ if code.between?(200, 299)
812
+ Schematic::Credits::Types::ExtendCreditLeaseResponse.load(response.body)
813
+ else
814
+ error_class = Schematic::Errors::ResponseError.subclass_for_code(code)
815
+ raise error_class.new(response.body, code: code)
816
+ end
817
+ end
818
+
819
+ # @param request_options [Hash]
820
+ # @param params [Schematic::Types::ReleaseCreditLeaseRequestBody]
821
+ # @option request_options [String] :base_url
822
+ # @option request_options [Hash{String => Object}] :additional_headers
823
+ # @option request_options [Hash{String => Object}] :additional_query_parameters
824
+ # @option request_options [Hash{String => Object}] :additional_body_parameters
825
+ # @option request_options [Integer] :timeout_in_seconds
826
+ # @option params [String] :lease_id
827
+ #
828
+ # @return [Schematic::Credits::Types::ReleaseCreditLeaseResponse]
829
+ def release_credit_lease(request_options: {}, **params)
830
+ params = Schematic::Internal::Types::Utils.normalize_keys(params)
831
+ request = Schematic::Internal::JSON::Request.new(
832
+ base_url: request_options[:base_url],
833
+ method: "PUT",
834
+ path: "billing/credits/lease/#{URI.encode_uri_component(params[:lease_id].to_s)}/release",
835
+ body: params,
836
+ request_options: request_options
837
+ )
838
+ begin
839
+ response = @client.send(request)
840
+ rescue Net::HTTPRequestTimeout
841
+ raise Schematic::Errors::TimeoutError
842
+ end
843
+ code = response.code.to_i
844
+ if code.between?(200, 299)
845
+ Schematic::Credits::Types::ReleaseCreditLeaseResponse.load(response.body)
846
+ else
847
+ error_class = Schematic::Errors::ResponseError.subclass_for_code(code)
848
+ raise error_class.new(response.body, code: code)
849
+ end
850
+ end
851
+
750
852
  # @param request_options [Hash]
751
853
  # @param params [Hash]
752
854
  # @option request_options [String] :base_url
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Schematic
4
+ module Credits
5
+ module Types
6
+ class AcquireCreditLeaseRequestBody < Internal::Types::Model
7
+ field :company_id, -> { String }, optional: false, nullable: false
8
+ field :credit_type_id, -> { String }, optional: false, nullable: false
9
+ field :expires_at, -> { String }, optional: true, nullable: false
10
+ field :requested_amount, -> { Integer }, optional: false, nullable: false
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Schematic
4
+ module Credits
5
+ module Types
6
+ class AcquireCreditLeaseResponse < Internal::Types::Model
7
+ field :data, -> { Schematic::Types::CreditLeaseResponseData }, optional: false, nullable: false
8
+ field :params, -> { Internal::Types::Hash[String, Object] }, optional: false, nullable: false
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Schematic
4
+ module Credits
5
+ module Types
6
+ class ExtendCreditLeaseRequestBody < Internal::Types::Model
7
+ field :lease_id, -> { String }, optional: false, nullable: false
8
+ field :additional_amount, -> { Integer }, optional: false, nullable: false
9
+ field :expires_at, -> { String }, optional: true, nullable: false
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Schematic
4
+ module Credits
5
+ module Types
6
+ class ExtendCreditLeaseResponse < Internal::Types::Model
7
+ field :data, -> { Schematic::Types::CreditLeaseResponseData }, optional: false, nullable: false
8
+ field :params, -> { Internal::Types::Hash[String, Object] }, optional: false, nullable: false
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Schematic
4
+ module Credits
5
+ module Types
6
+ class ReleaseCreditLeaseResponse < Internal::Types::Model
7
+ field :data, -> { Schematic::Types::CreditLeaseResponseData }, optional: false, nullable: false
8
+ field :params, -> { Internal::Types::Hash[String, Object] }, optional: false, nullable: false
9
+ end
10
+ end
11
+ end
12
+ end
@@ -16,25 +16,42 @@ module Schematic
16
16
  COMPANY_MAP_FIELDS = %i[credit_balances keys traits].freeze
17
17
  COMPANY_ARRAY_FIELDS = %i[billing_product_ids entitlements plan_ids plan_version_ids rules].freeze
18
18
 
19
+ # Partials don't carry refreshed entitlements, so when their derived
20
+ # fields change in another part of the company we sync them here to match
21
+ # server behavior (see schematic-python merge.partial_company):
22
+ # - credit_remaining <- credit_balances[credit_id]
23
+ # - usage <- metric value matching (event_name, metric_period, month_reset)
24
+ # Both are skipped when the partial also sends entitlements wholesale.
19
25
  def partial_company(existing, partial_data)
20
26
  return existing unless partial_data.is_a?(Hash)
21
27
 
22
28
  result = deep_copy(existing)
29
+ entitlements_in_partial = partial_data.key?(:entitlements) || partial_data.key?("entitlements")
30
+ updated_balances = nil
31
+ metrics_updated = false
23
32
 
24
33
  partial_data.each do |key, value|
25
34
  sym_key = key.to_sym
26
35
  if COMPANY_MAP_FIELDS.include?(sym_key)
27
36
  result[sym_key] ||= {}
28
37
  result[sym_key] = result[sym_key].merge(value) if value.is_a?(Hash)
38
+ updated_balances = (value.is_a?(Hash) ? value : {}) if sym_key == :credit_balances
29
39
  elsif COMPANY_ARRAY_FIELDS.include?(sym_key)
30
40
  result[sym_key] = value if value.is_a?(Array)
31
41
  elsif sym_key == :metrics
32
42
  result[sym_key] = upsert_metrics(result[sym_key] || [], value || [])
43
+ metrics_updated = true
33
44
  else
34
45
  result[sym_key] = value
35
46
  end
36
47
  end
37
48
 
49
+ if (updated_balances&.any? || metrics_updated) && !entitlements_in_partial
50
+ result[:entitlements] = sync_entitlements(
51
+ result[:entitlements], result[:metrics], updated_balances, metrics_updated
52
+ )
53
+ end
54
+
38
55
  result
39
56
  end
40
57
 
@@ -90,6 +107,60 @@ module Schematic
90
107
  def get_metric_field(metric, field)
91
108
  metric[field] || metric[field.to_s]
92
109
  end
110
+
111
+ # Re-derive entitlement usage / credit_remaining from the merged metrics
112
+ # and the just-updated credit balances. Mirrors schematic-python so that
113
+ # entitlement usage reflects DataStream track events immediately.
114
+ def sync_entitlements(entitlements, metrics, updated_balances, metrics_updated)
115
+ return entitlements unless entitlements.is_a?(Array) && !entitlements.empty?
116
+
117
+ metrics_lookup = {}
118
+ if metrics_updated && metrics.is_a?(Array)
119
+ metrics.each do |metric|
120
+ next unless metric.is_a?(Hash)
121
+
122
+ key = [
123
+ get_metric_field(metric, :event_subtype) || "",
124
+ get_metric_field(metric, :period) || "",
125
+ get_metric_field(metric, :month_reset) || ""
126
+ ]
127
+ value = get_metric_field(metric, :value)
128
+ metrics_lookup[key] = value.nil? ? 0 : value
129
+ end
130
+ end
131
+
132
+ entitlements.map do |ent|
133
+ next ent unless ent.is_a?(Hash)
134
+
135
+ new_ent = deep_copy(ent)
136
+
137
+ credit_id = get_metric_field(ent, :credit_id)
138
+ if updated_balances && credit_id
139
+ present, balance = fetch_balance(updated_balances, credit_id)
140
+ new_ent[:credit_remaining] = balance if present
141
+ end
142
+
143
+ event_name = get_metric_field(ent, :event_name)
144
+ unless metrics_lookup.empty? || event_name.nil?
145
+ period = get_metric_field(ent, :metric_period) || "all_time"
146
+ month_reset = get_metric_field(ent, :month_reset) || "first_of_month"
147
+ matched = metrics_lookup[[event_name, period, month_reset]]
148
+ new_ent[:usage] = matched unless matched.nil?
149
+ end
150
+
151
+ new_ent
152
+ end
153
+ end
154
+
155
+ # The partial's credit_balances may be keyed by string or symbol depending
156
+ # on how the message was parsed, while an entitlement's credit_id is a
157
+ # string value, so check both key forms.
158
+ def fetch_balance(balances, credit_id)
159
+ return [true, balances[credit_id]] if balances.key?(credit_id)
160
+ return [true, balances[credit_id.to_sym]] if balances.key?(credit_id.to_sym)
161
+
162
+ [false, nil]
163
+ end
93
164
  end
94
165
  end
95
166
  end
@@ -29,6 +29,7 @@ module Schematic
29
29
  field :quarterly_unit_price_decimal, -> { String }, optional: true, nullable: false
30
30
  field :soft_limit, -> { Integer }, optional: true, nullable: false
31
31
  field :tier_mode, -> { Schematic::Types::BillingTiersMode }, optional: true, nullable: false
32
+ field :usage_quantity, -> { Integer }, optional: true, nullable: false
32
33
  field :value_bool, -> { Internal::Types::Boolean }, optional: true, nullable: false
33
34
  field :value_credit_id, -> { String }, optional: true, nullable: false
34
35
  field :value_numeric, -> { Integer }, optional: true, nullable: false
@@ -27,6 +27,7 @@ module Schematic
27
27
  field :quarterly_unit_price_decimal, -> { String }, optional: true, nullable: false
28
28
  field :soft_limit, -> { Integer }, optional: true, nullable: false
29
29
  field :tier_mode, -> { Schematic::Types::BillingTiersMode }, optional: true, nullable: false
30
+ field :usage_quantity, -> { Integer }, optional: true, nullable: false
30
31
  field :value_bool, -> { Internal::Types::Boolean }, optional: true, nullable: false
31
32
  field :value_credit_id, -> { String }, optional: true, nullable: false
32
33
  field :value_numeric, -> { Integer }, optional: true, nullable: false
@@ -25,6 +25,7 @@ module Schematic
25
25
  field :quarterly_unit_price_decimal, -> { String }, optional: true, nullable: false
26
26
  field :soft_limit, -> { Integer }, optional: true, nullable: false
27
27
  field :tier_mode, -> { Schematic::Types::BillingTiersMode }, optional: true, nullable: false
28
+ field :usage_quantity, -> { Integer }, optional: true, nullable: false
28
29
  field :value_bool, -> { Internal::Types::Boolean }, optional: true, nullable: false
29
30
  field :value_credit_id, -> { String }, optional: true, nullable: false
30
31
  field :value_numeric, -> { Integer }, optional: true, nullable: false
@@ -176,13 +176,19 @@ module Schematic
176
176
  # Transform to capture service payload format (differs from Fern API):
177
177
  # - Field is `type` not `event_type`
178
178
  # - Each event includes `api_key`
179
+ # Optional metadata (idempotency_key, trusted_client_clock, backfill) is
180
+ # only included when the caller set it, so we never send explicit nulls.
179
181
  def event_to_capture_payload(event)
180
- {
182
+ payload = {
181
183
  api_key: @api_key,
182
184
  type: event[:event_type],
183
185
  body: event[:body],
184
186
  sent_at: event[:sent_at] || Time.now.utc.iso8601
185
187
  }
188
+ payload[:idempotency_key] = event[:idempotency_key] unless event[:idempotency_key].nil?
189
+ payload[:trusted_client_clock] = event[:trusted_client_clock] unless event[:trusted_client_clock].nil?
190
+ payload[:backfill] = event[:backfill] unless event[:backfill].nil?
191
+ payload
186
192
  end
187
193
  end
188
194
  end
@@ -26,7 +26,7 @@ module Schematic
26
26
 
27
27
  attr_accessor :level
28
28
 
29
- def initialize(level: :info)
29
+ def initialize(level: :warn)
30
30
  @level = level
31
31
  @mutex = Mutex.new
32
32
  @io = $stderr