diff --git a/.fern/metadata.json b/.fern/metadata.json index cb6e7f3..7d3d867 100644 --- a/.fern/metadata.json +++ b/.fern/metadata.json @@ -13,6 +13,6 @@ "webrick": ">= 1.0" } }, - "originGitCommit": "df83a2723a19055c70199e3b0b78b77e9c394838", - "sdkVersion": "1.4.5" + "originGitCommit": "26286134afce586aa5dbd02bffc9f25da6217032", + "sdkVersion": "1.4.6" } \ No newline at end of file diff --git a/.fern/replay.lock b/.fern/replay.lock index 2fdceff..54a0a96 100644 --- a/.fern/replay.lock +++ b/.fern/replay.lock @@ -24,206 +24,11 @@ generations: cli_version: unknown generator_versions: fernapi/fern-ruby-sdk: 1.1.13 -current_generation: 7ff89cac80a7358534185779ed4992b755919d97 -patches: - - id: patch-46462128 - content_hash: sha256:416a511ede0736c55e936299b78f07a3935feedab63c1270dbb2230687fc6be4 - original_commit: 46462128cacb25b73fac7770060cf427ff0d9e6d - original_message: add tests and address nits - original_author: Christopher Brady - base_generation: 7ff89cac80a7358534185779ed4992b755919d97 - files: - - lib/schematic/datastream/merge.rb - patch_content: | - diff --git a/lib/schematic/datastream/merge.rb b/lib/schematic/datastream/merge.rb - index f4dd4e5..5c32683 100644 - --- a/lib/schematic/datastream/merge.rb - +++ b/lib/schematic/datastream/merge.rb - @@ -46,7 +46,7 @@ module Schematic - end - end - - - if (updated_balances&.any? || metrics_updated) && !entitlements_in_partial - + if (updated_balances || metrics_updated) && !entitlements_in_partial - result[:entitlements] = sync_entitlements( - result[:entitlements], result[:metrics], updated_balances, metrics_updated - ) - @@ -152,9 +152,8 @@ module Schematic - end - end - - - # The partial's credit_balances may be keyed by string or symbol depending - - # on how the message was parsed, while an entitlement's credit_id is a - - # string value, so check both key forms. - + # credit_balances keys may be symbols (deep_copy symbolizes) while an - + # entitlement's credit_id is always a string, so check both forms. - def fetch_balance(balances, credit_id) - return [true, balances[credit_id]] if balances.key?(credit_id) - return [true, balances[credit_id.to_sym]] if balances.key?(credit_id.to_sym) - theirs_snapshot: - lib/schematic/datastream/merge.rb: | - # frozen_string_literal: true - - require "json" - - module Schematic - module DataStream - module Merge - module_function - - def deep_copy(obj) - JSON.parse(JSON.generate(obj), symbolize_names: true) - rescue StandardError - obj.dup - end - - COMPANY_MAP_FIELDS = %i[credit_balances keys traits].freeze - COMPANY_ARRAY_FIELDS = %i[billing_product_ids entitlements plan_ids plan_version_ids rules].freeze - - # Partials don't carry refreshed entitlements, so when their derived - # fields change in another part of the company we sync them here to match - # server behavior (see schematic-python merge.partial_company): - # - credit_remaining <- credit_balances[credit_id] - # - usage <- metric value matching (event_name, metric_period, month_reset) - # Both are skipped when the partial also sends entitlements wholesale. - def partial_company(existing, partial_data) - return existing unless partial_data.is_a?(Hash) - - result = deep_copy(existing) - entitlements_in_partial = partial_data.key?(:entitlements) || partial_data.key?("entitlements") - updated_balances = nil - metrics_updated = false - - partial_data.each do |key, value| - sym_key = key.to_sym - if COMPANY_MAP_FIELDS.include?(sym_key) - result[sym_key] ||= {} - result[sym_key] = result[sym_key].merge(value) if value.is_a?(Hash) - updated_balances = (value.is_a?(Hash) ? value : {}) if sym_key == :credit_balances - elsif COMPANY_ARRAY_FIELDS.include?(sym_key) - result[sym_key] = value if value.is_a?(Array) - elsif sym_key == :metrics - result[sym_key] = upsert_metrics(result[sym_key] || [], value || []) - metrics_updated = true - else - result[sym_key] = value - end - end - - if (updated_balances || metrics_updated) && !entitlements_in_partial - result[:entitlements] = sync_entitlements( - result[:entitlements], result[:metrics], updated_balances, metrics_updated - ) - end - - result - end - - USER_MAP_FIELDS = %i[keys traits].freeze - - def partial_user(existing, partial_data) - return existing unless partial_data.is_a?(Hash) - - result = deep_copy(existing) - - partial_data.each do |key, value| - sym_key = key.to_sym - if USER_MAP_FIELDS.include?(sym_key) - result[sym_key] ||= {} - result[sym_key] = result[sym_key].merge(value) if value.is_a?(Hash) - elsif sym_key == :rules - result[sym_key] = value if value.is_a?(Array) - else - result[sym_key] = value - end - end - - result - end - - def upsert_metrics(existing, incoming) - return incoming if existing.nil? || existing.empty? - return existing if incoming.nil? || incoming.empty? - - result = existing.map { |metric| deep_copy(metric) } - - incoming.each do |inc_metric| - match_idx = result.index do |ex| - metrics_match?(ex, inc_metric) - end - - if match_idx - result[match_idx] = inc_metric - else - result << inc_metric - end - end - - result - end - - def metrics_match?(left, right) - get_metric_field(left, :event_subtype) == get_metric_field(right, :event_subtype) && - get_metric_field(left, :period) == get_metric_field(right, :period) && - get_metric_field(left, :month_reset) == get_metric_field(right, :month_reset) - end - - def get_metric_field(metric, field) - metric[field] || metric[field.to_s] - end - - # Re-derive entitlement usage / credit_remaining from the merged metrics - # and the just-updated credit balances. Mirrors schematic-python so that - # entitlement usage reflects DataStream track events immediately. - def sync_entitlements(entitlements, metrics, updated_balances, metrics_updated) - return entitlements unless entitlements.is_a?(Array) && !entitlements.empty? - - metrics_lookup = {} - if metrics_updated && metrics.is_a?(Array) - metrics.each do |metric| - next unless metric.is_a?(Hash) - - key = [ - get_metric_field(metric, :event_subtype) || "", - get_metric_field(metric, :period) || "", - get_metric_field(metric, :month_reset) || "" - ] - value = get_metric_field(metric, :value) - metrics_lookup[key] = value.nil? ? 0 : value - end - end - - entitlements.map do |ent| - next ent unless ent.is_a?(Hash) - - new_ent = deep_copy(ent) - - credit_id = get_metric_field(ent, :credit_id) - if updated_balances && credit_id - present, balance = fetch_balance(updated_balances, credit_id) - new_ent[:credit_remaining] = balance if present - end - - event_name = get_metric_field(ent, :event_name) - unless metrics_lookup.empty? || event_name.nil? - period = get_metric_field(ent, :metric_period) || "all_time" - month_reset = get_metric_field(ent, :month_reset) || "first_of_month" - matched = metrics_lookup[[event_name, period, month_reset]] - new_ent[:usage] = matched unless matched.nil? - end - - new_ent - end - end - - # credit_balances keys may be symbols (deep_copy symbolizes) while an - # entitlement's credit_id is always a string, so check both forms. - def fetch_balance(balances, credit_id) - return [true, balances[credit_id]] if balances.key?(credit_id) - return [true, balances[credit_id.to_sym]] if balances.key?(credit_id.to_sym) - - [false, nil] - end - end - end - end + - commit_sha: 8487841eae05855059210650ab3ee913538f1afc + tree_hash: 391a12403ced58b9d8dfaa76de05467a95b1b8f9 + timestamp: 2026-06-22T18:51:25.550Z + cli_version: unknown + generator_versions: + fernapi/fern-ruby-sdk: 1.1.13 +current_generation: 8487841eae05855059210650ab3ee913538f1afc +patches: [] diff --git a/Gemfile.lock b/Gemfile.lock index 6011ae3..0ce66c4 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: . specs: - schematichq (1.4.5) + schematichq (1.4.6) wasmtime (>= 19.0) websocket (>= 1.2) diff --git a/lib/schematic.rb b/lib/schematic.rb index 7970d21..cae6cee 100644 --- a/lib/schematic.rb +++ b/lib/schematic.rb @@ -85,6 +85,8 @@ require_relative "schematic/types/billing_coupon_response_data" require_relative "schematic/billing/types/list_coupons_response" require_relative "schematic/billing/types/upsert_billing_coupon_response" +require_relative "schematic/billing/types/delete_billing_coupon_response" +require_relative "schematic/billing/types/delete_billing_customer_response" require_relative "schematic/types/billing_customer_response_data" require_relative "schematic/billing/types/upsert_billing_customer_response" require_relative "schematic/billing/types/list_customers_with_subscriptions_params" @@ -98,6 +100,7 @@ require_relative "schematic/types/invoice_response_data" require_relative "schematic/billing/types/list_invoices_response" require_relative "schematic/billing/types/upsert_invoice_response" +require_relative "schematic/billing/types/delete_billing_invoice_response" require_relative "schematic/billing/types/list_meters_params" require_relative "schematic/types/billing_meter_response_data" require_relative "schematic/billing/types/list_meters_response" @@ -622,6 +625,8 @@ require_relative "schematic/webhooks/types/get_webhook_response" require_relative "schematic/webhooks/types/update_webhook_response" require_relative "schematic/webhooks/types/delete_webhook_response" +require_relative "schematic/types/test_webhook_response_data" +require_relative "schematic/webhooks/types/send_test_webhook_action_response" require_relative "schematic/webhooks/types/count_webhooks_params" require_relative "schematic/webhooks/types/count_webhooks_response" require_relative "schematic/types/api_error" @@ -908,5 +913,6 @@ require_relative "schematic/webhooks/types/list_webhooks_request" require_relative "schematic/webhooks/types/create_webhook_request_body" require_relative "schematic/webhooks/types/update_webhook_request_body" +require_relative "schematic/webhooks/types/test_webhook_request_body" require_relative "schematic/webhooks/types/count_webhooks_request" require_relative "schematic/environment" diff --git a/lib/schematic/billing/client.rb b/lib/schematic/billing/client.rb index 6fab89a..c0da2c7 100644 --- a/lib/schematic/billing/client.rb +++ b/lib/schematic/billing/client.rb @@ -86,6 +86,70 @@ def upsert_billing_coupon(request_options: {}, **params) end end + # @param request_options [Hash] + # @param params [Hash] + # @option request_options [String] :base_url + # @option request_options [Hash{String => Object}] :additional_headers + # @option request_options [Hash{String => Object}] :additional_query_parameters + # @option request_options [Hash{String => Object}] :additional_body_parameters + # @option request_options [Integer] :timeout_in_seconds + # @option params [String] :billing_id + # + # @return [Schematic::Billing::Types::DeleteBillingCouponResponse] + def delete_billing_coupon(request_options: {}, **params) + params = Schematic::Internal::Types::Utils.normalize_keys(params) + request = Schematic::Internal::JSON::Request.new( + base_url: request_options[:base_url], + method: "DELETE", + path: "billing/coupons/#{URI.encode_uri_component(params[:billing_id].to_s)}", + request_options: request_options + ) + begin + response = @client.send(request) + rescue Net::HTTPRequestTimeout + raise Schematic::Errors::TimeoutError + end + code = response.code.to_i + if code.between?(200, 299) + Schematic::Billing::Types::DeleteBillingCouponResponse.load(response.body) + else + error_class = Schematic::Errors::ResponseError.subclass_for_code(code) + raise error_class.new(response.body, code: code) + end + end + + # @param request_options [Hash] + # @param params [Hash] + # @option request_options [String] :base_url + # @option request_options [Hash{String => Object}] :additional_headers + # @option request_options [Hash{String => Object}] :additional_query_parameters + # @option request_options [Hash{String => Object}] :additional_body_parameters + # @option request_options [Integer] :timeout_in_seconds + # @option params [String] :billing_id + # + # @return [Schematic::Billing::Types::DeleteBillingCustomerResponse] + def delete_billing_customer(request_options: {}, **params) + params = Schematic::Internal::Types::Utils.normalize_keys(params) + request = Schematic::Internal::JSON::Request.new( + base_url: request_options[:base_url], + method: "DELETE", + path: "billing/customer/#{URI.encode_uri_component(params[:billing_id].to_s)}", + request_options: request_options + ) + begin + response = @client.send(request) + rescue Net::HTTPRequestTimeout + raise Schematic::Errors::TimeoutError + end + code = response.code.to_i + if code.between?(200, 299) + Schematic::Billing::Types::DeleteBillingCustomerResponse.load(response.body) + else + error_class = Schematic::Errors::ResponseError.subclass_for_code(code) + raise error_class.new(response.body, code: code) + end + end + # @param request_options [Hash] # @param params [Schematic::Billing::Types::CreateBillingCustomerRequestBody] # @option request_options [String] :base_url @@ -292,6 +356,38 @@ def upsert_invoice(request_options: {}, **params) end end + # @param request_options [Hash] + # @param params [Hash] + # @option request_options [String] :base_url + # @option request_options [Hash{String => Object}] :additional_headers + # @option request_options [Hash{String => Object}] :additional_query_parameters + # @option request_options [Hash{String => Object}] :additional_body_parameters + # @option request_options [Integer] :timeout_in_seconds + # @option params [String] :billing_id + # + # @return [Schematic::Billing::Types::DeleteBillingInvoiceResponse] + def delete_billing_invoice(request_options: {}, **params) + params = Schematic::Internal::Types::Utils.normalize_keys(params) + request = Schematic::Internal::JSON::Request.new( + base_url: request_options[:base_url], + method: "DELETE", + path: "billing/invoices/#{URI.encode_uri_component(params[:billing_id].to_s)}", + request_options: request_options + ) + begin + response = @client.send(request) + rescue Net::HTTPRequestTimeout + raise Schematic::Errors::TimeoutError + end + code = response.code.to_i + if code.between?(200, 299) + Schematic::Billing::Types::DeleteBillingInvoiceResponse.load(response.body) + else + error_class = Schematic::Errors::ResponseError.subclass_for_code(code) + raise error_class.new(response.body, code: code) + end + end + # @param request_options [Hash] # @param params [Hash] # @option request_options [String] :base_url diff --git a/lib/schematic/billing/types/delete_billing_coupon_response.rb b/lib/schematic/billing/types/delete_billing_coupon_response.rb new file mode 100644 index 0000000..d7d6dbb --- /dev/null +++ b/lib/schematic/billing/types/delete_billing_coupon_response.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +module Schematic + module Billing + module Types + class DeleteBillingCouponResponse < Internal::Types::Model + field :data, -> { Schematic::Types::DeleteResponse }, optional: false, nullable: false + field :params, -> { Internal::Types::Hash[String, Object] }, optional: false, nullable: false + end + end + end +end diff --git a/lib/schematic/billing/types/delete_billing_customer_response.rb b/lib/schematic/billing/types/delete_billing_customer_response.rb new file mode 100644 index 0000000..4d8bd80 --- /dev/null +++ b/lib/schematic/billing/types/delete_billing_customer_response.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +module Schematic + module Billing + module Types + class DeleteBillingCustomerResponse < Internal::Types::Model + field :data, -> { Schematic::Types::DeleteResponse }, optional: false, nullable: false + field :params, -> { Internal::Types::Hash[String, Object] }, optional: false, nullable: false + end + end + end +end diff --git a/lib/schematic/billing/types/delete_billing_invoice_response.rb b/lib/schematic/billing/types/delete_billing_invoice_response.rb new file mode 100644 index 0000000..0b7f525 --- /dev/null +++ b/lib/schematic/billing/types/delete_billing_invoice_response.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +module Schematic + module Billing + module Types + class DeleteBillingInvoiceResponse < Internal::Types::Model + field :data, -> { Schematic::Types::DeleteResponse }, optional: false, nullable: false + field :params, -> { Internal::Types::Hash[String, Object] }, optional: false, nullable: false + end + end + end +end diff --git a/lib/schematic/client.rb b/lib/schematic/client.rb index 4613f55..cbf180d 100644 --- a/lib/schematic/client.rb +++ b/lib/schematic/client.rb @@ -10,7 +10,7 @@ def initialize(api_key:, base_url: nil) @raw_client = Schematic::Internal::Http::RawClient.new( base_url: base_url || Schematic::Environment::DEFAULT, headers: { - "User-Agent" => "schematichq/1.4.5", + "User-Agent" => "schematichq/1.4.6", "X-Fern-Language" => "Ruby", "X-Schematic-Api-Key" => api_key.to_s } diff --git a/lib/schematic/types/test_webhook_response_data.rb b/lib/schematic/types/test_webhook_response_data.rb new file mode 100644 index 0000000..ce5f51d --- /dev/null +++ b/lib/schematic/types/test_webhook_response_data.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +module Schematic + module Types + class TestWebhookResponseData < Internal::Types::Model + field :response_code, -> { Integer }, optional: false, nullable: false + field :success, -> { Internal::Types::Boolean }, optional: false, nullable: false + end + end +end diff --git a/lib/schematic/version.rb b/lib/schematic/version.rb index bdfd52b..b2a5626 100644 --- a/lib/schematic/version.rb +++ b/lib/schematic/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module Schematic - VERSION = "1.4.5" + VERSION = "1.4.6" end diff --git a/lib/schematic/webhooks/client.rb b/lib/schematic/webhooks/client.rb index b77cb68..d712bf4 100644 --- a/lib/schematic/webhooks/client.rb +++ b/lib/schematic/webhooks/client.rb @@ -309,6 +309,43 @@ def delete_webhook(request_options: {}, **params) end end + # @param request_options [Hash] + # @param params [Schematic::Webhooks::Types::TestWebhookRequestBody] + # @option request_options [String] :base_url + # @option request_options [Hash{String => Object}] :additional_headers + # @option request_options [Hash{String => Object}] :additional_query_parameters + # @option request_options [Hash{String => Object}] :additional_body_parameters + # @option request_options [Integer] :timeout_in_seconds + # @option params [String] :webhook_id + # + # @return [Schematic::Webhooks::Types::SendTestWebhookActionResponse] + def send_test_webhook_action(request_options: {}, **params) + params = Schematic::Internal::Types::Utils.normalize_keys(params) + request_data = Schematic::Webhooks::Types::TestWebhookRequestBody.new(params).to_h + non_body_param_names = ["webhook_id"] + body = request_data.except(*non_body_param_names) + + request = Schematic::Internal::JSON::Request.new( + base_url: request_options[:base_url], + method: "POST", + path: "webhooks/#{URI.encode_uri_component(params[:webhook_id].to_s)}/test", + body: body, + request_options: request_options + ) + begin + response = @client.send(request) + rescue Net::HTTPRequestTimeout + raise Schematic::Errors::TimeoutError + end + code = response.code.to_i + if code.between?(200, 299) + Schematic::Webhooks::Types::SendTestWebhookActionResponse.load(response.body) + else + error_class = Schematic::Errors::ResponseError.subclass_for_code(code) + raise error_class.new(response.body, code: code) + end + end + # @param request_options [Hash] # @param params [Hash] # @option request_options [String] :base_url diff --git a/lib/schematic/webhooks/types/send_test_webhook_action_response.rb b/lib/schematic/webhooks/types/send_test_webhook_action_response.rb new file mode 100644 index 0000000..a627e13 --- /dev/null +++ b/lib/schematic/webhooks/types/send_test_webhook_action_response.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +module Schematic + module Webhooks + module Types + class SendTestWebhookActionResponse < Internal::Types::Model + field :data, -> { Schematic::Types::TestWebhookResponseData }, optional: false, nullable: false + field :params, -> { Internal::Types::Hash[String, Object] }, optional: false, nullable: false + end + end + end +end diff --git a/lib/schematic/webhooks/types/test_webhook_request_body.rb b/lib/schematic/webhooks/types/test_webhook_request_body.rb new file mode 100644 index 0000000..613f05b --- /dev/null +++ b/lib/schematic/webhooks/types/test_webhook_request_body.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +module Schematic + module Webhooks + module Types + class TestWebhookRequestBody < Internal::Types::Model + field :webhook_id, -> { String }, optional: false, nullable: false + field :request_type, -> { Schematic::Types::WebhookRequestType }, optional: false, nullable: false + end + end + end +end diff --git a/reference.md b/reference.md index 468b011..1254b06 100644 --- a/reference.md +++ b/reference.md @@ -1446,6 +1446,102 @@ client.billing.upsert_billing_coupon( + + + + +
client.billing.delete_billing_coupon(billing_id) -> Schematic::Billing::Types::DeleteBillingCouponResponse +
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```ruby +client.billing.delete_billing_coupon(billing_id: "billing_id") +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**billing_id:** `String` — billing_id + +
+
+ +
+
+ +**request_options:** `Schematic::Billing::RequestOptions` + +
+
+
+
+ + +
+
+
+ +
client.billing.delete_billing_customer(billing_id) -> Schematic::Billing::Types::DeleteBillingCustomerResponse +
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```ruby +client.billing.delete_billing_customer(billing_id: "billing_id") +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**billing_id:** `String` — billing_id + +
+
+ +
+
+ +**request_options:** `Schematic::Billing::RequestOptions` + +
+
+
+
+ +
@@ -1977,6 +2073,54 @@ client.billing.upsert_invoice( + + + + +
client.billing.delete_billing_invoice(billing_id) -> Schematic::Billing::Types::DeleteBillingInvoiceResponse +
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```ruby +client.billing.delete_billing_invoice(billing_id: "billing_id") +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**billing_id:** `String` — billing_id + +
+
+ +
+
+ +**request_options:** `Schematic::Billing::RequestOptions` + +
+
+
+
+ +
@@ -19309,6 +19453,65 @@ client.webhooks.delete_webhook(webhook_id: "webhook_id") + + + + +
client.webhooks.send_test_webhook_action(webhook_id, request) -> Schematic::Webhooks::Types::SendTestWebhookActionResponse +
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```ruby +client.webhooks.send_test_webhook_action( + webhook_id: "webhook_id", + request_type: "subscription.trial.ended" +) +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**webhook_id:** `String` — webhook_id + +
+
+ +
+
+ +**request_type:** `Schematic::Types::WebhookRequestType` + +
+
+ +
+
+ +**request_options:** `Schematic::Webhooks::RequestOptions` + +
+
+
+
+ +