diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 3d2ac0b..10f3091 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.1.0" + ".": "0.2.0" } \ No newline at end of file diff --git a/.rubocop.yml b/.rubocop.yml index c10ba7a..425e81f 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -121,6 +121,10 @@ Metrics/BlockLength: Metrics/ClassLength: Enabled: false +Metrics/CollectionLiteralLength: + Exclude: + - "test/**/*" + Metrics/CyclomaticComplexity: Enabled: false diff --git a/.stats.yml b/.stats.yml index 6e8f4f5..63b5f67 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 16 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/surge%2Fsurge-f593640d38b503dfa2f7018efe014d446c67a5b66e523155cb0643cc9079564b.yml -openapi_spec_hash: b567da489f6e30c4ad893e9c5a9b7399 -config_hash: d9682af69d6ed28eac51eb95929790b6 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/surge%2Fsurge-6d6362cb88f011e556ebcc100851d12736654094d351bc5b402ea1cc05eeedbc.yml +openapi_spec_hash: 93e79d53e56fdf12b8287a5048f2c0aa +config_hash: 2005008b28252768774740897c65d562 diff --git a/CHANGELOG.md b/CHANGELOG.md index 0817f5a..56cd233 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,24 @@ # Changelog +## 0.2.0 (2025-10-09) + +Full Changelog: [v0.1.0...v0.2.0](https://github.com/surgeapi/ruby-sdk/compare/v0.1.0...v0.2.0) + +### Features + +* **api:** api update ([8a7eeeb](https://github.com/surgeapi/ruby-sdk/commit/8a7eeeb4c5248d0f0aa4da399c45d2763b98ba3b)) + + +### Bug Fixes + +* always send `filename=...` for multipart requests where a file is expected ([28bdedf](https://github.com/surgeapi/ruby-sdk/commit/28bdedfba8e9bef43abf39e08169bc2bf2edb0e8)) +* coroutine leaks from connection pool ([239043f](https://github.com/surgeapi/ruby-sdk/commit/239043f74e12856fb8e6b2a477ea9bf35945f2f2)) + + +### Chores + +* ignore linter error for tests having large collections ([4d89802](https://github.com/surgeapi/ruby-sdk/commit/4d898024ffae04e4f24591b1c54a922e1b6c51f4)) + ## 0.1.0 (2025-09-26) Full Changelog: [v0.0.1...v0.1.0](https://github.com/surgeapi/ruby-sdk/compare/v0.0.1...v0.1.0) diff --git a/Gemfile.lock b/Gemfile.lock index 342048c..8fc1b47 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -11,7 +11,7 @@ GIT PATH remote: . specs: - surge_api (0.1.0) + surge_api (0.2.0) connection_pool GEM diff --git a/README.md b/README.md index 881f444..e0aa582 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ To use this gem, install via Bundler by adding the following to your application ```ruby -gem "surge_api", "~> 0.1.0" +gem "surge_api", "~> 0.2.0" ``` diff --git a/lib/surge_api.rb b/lib/surge_api.rb index b4cd9b5..182923d 100644 --- a/lib/surge_api.rb +++ b/lib/surge_api.rb @@ -63,6 +63,8 @@ require_relative "surge_api/models/campaign_create_params" require_relative "surge_api/models/contact" require_relative "surge_api/models/contact_create_params" +require_relative "surge_api/models/contact_opted_in_webhook_event" +require_relative "surge_api/models/contact_opted_out_webhook_event" require_relative "surge_api/models/contact_retrieve_params" require_relative "surge_api/models/contact_update_params" require_relative "surge_api/models/conversation_created_webhook_event" diff --git a/lib/surge_api/file_part.rb b/lib/surge_api/file_part.rb index 38630fc..6c8c398 100644 --- a/lib/surge_api/file_part.rb +++ b/lib/surge_api/file_part.rb @@ -38,18 +38,21 @@ def to_json(*a) = read.to_json(*a) def to_yaml(*a) = read.to_yaml(*a) # @param content [Pathname, StringIO, IO, String] - # @param filename [String, nil] + # @param filename [Pathname, String, nil] # @param content_type [String, nil] def initialize(content, filename: nil, content_type: nil) - @content = content + @content_type = content_type @filename = - case content - in Pathname - filename.nil? ? content.basename.to_path : ::File.basename(filename) + case [filename, (@content = content)] + in [String | Pathname, _] + ::File.basename(filename) + in [nil, Pathname] + content.basename.to_path + in [nil, IO] + content.to_path else - filename.nil? ? nil : ::File.basename(filename) + filename end - @content_type = content_type end end end diff --git a/lib/surge_api/internal/transport/pooled_net_requester.rb b/lib/surge_api/internal/transport/pooled_net_requester.rb index b675682..1df3951 100644 --- a/lib/surge_api/internal/transport/pooled_net_requester.rb +++ b/lib/surge_api/internal/transport/pooled_net_requester.rb @@ -134,9 +134,9 @@ def execute(request) # rubocop:disable Metrics/BlockLength enum = Enumerator.new do |y| - with_pool(url, deadline: deadline) do |conn| - next if finished + next if finished + with_pool(url, deadline: deadline) do |conn| req, closing = self.class.build_request(request) do self.class.calibrate_socket_timeout(conn, deadline) end @@ -149,7 +149,7 @@ def execute(request) self.class.calibrate_socket_timeout(conn, deadline) conn.request(req) do |rsp| - y << [conn, req, rsp] + y << [req, rsp] break if finished rsp.read_body do |bytes| @@ -160,6 +160,8 @@ def execute(request) end eof = true end + ensure + conn.finish if !eof && conn&.started? end rescue Timeout::Error raise SurgeAPI::Errors::APITimeoutError.new(url: url, request: req) @@ -168,16 +170,11 @@ def execute(request) end # rubocop:enable Metrics/BlockLength - conn, _, response = enum.next + _, response = enum.next body = SurgeAPI::Internal::Util.fused_enum(enum, external: true) do finished = true - tap do - enum.next - rescue StopIteration - nil - end + loop { enum.next } ensure - conn.finish if !eof && conn&.started? closing&.call end [Integer(response.code), response, body] diff --git a/lib/surge_api/internal/type/file_input.rb b/lib/surge_api/internal/type/file_input.rb index 1a2abc9..78562b3 100644 --- a/lib/surge_api/internal/type/file_input.rb +++ b/lib/surge_api/internal/type/file_input.rb @@ -82,17 +82,20 @@ def coerce(value, state:) # # @return [Pathname, StringIO, IO, String, Object] def dump(value, state:) - # rubocop:disable Lint/DuplicateBranch case value + in StringIO | String + # https://datatracker.ietf.org/doc/html/rfc7578#section-4.2 + # while not required, a filename is recommended, and in practice many servers do expect this + SurgeAPI::FilePart.new(value, filename: "upload") in IO state[:can_retry] = false + value.to_path.nil? ? SurgeAPI::FilePart.new(value, filename: "upload") : value in SurgeAPI::FilePart if value.content.is_a?(IO) state[:can_retry] = false + value else + value end - # rubocop:enable Lint/DuplicateBranch - - value end # @api private diff --git a/lib/surge_api/internal/type/union.rb b/lib/surge_api/internal/type/union.rb index dba8d7e..40eeef2 100644 --- a/lib/surge_api/internal/type/union.rb +++ b/lib/surge_api/internal/type/union.rb @@ -12,7 +12,7 @@ module Type # puts(unwrap_webhook_event.account_id) # when SurgeAPI::CampaignApprovedWebhookEvent # puts(unwrap_webhook_event.data) - # when SurgeAPI::ConversationCreatedWebhookEvent + # when SurgeAPI::ContactOptedInWebhookEvent # puts(unwrap_webhook_event.timestamp) # else # puts(unwrap_webhook_event) diff --git a/lib/surge_api/models.rb b/lib/surge_api/models.rb index d442ca2..e0c7131 100644 --- a/lib/surge_api/models.rb +++ b/lib/surge_api/models.rb @@ -65,6 +65,10 @@ module SurgeAPI ContactCreateParams = SurgeAPI::Models::ContactCreateParams + ContactOptedInWebhookEvent = SurgeAPI::Models::ContactOptedInWebhookEvent + + ContactOptedOutWebhookEvent = SurgeAPI::Models::ContactOptedOutWebhookEvent + ContactRetrieveParams = SurgeAPI::Models::ContactRetrieveParams ContactUpdateParams = SurgeAPI::Models::ContactUpdateParams diff --git a/lib/surge_api/models/contact_opted_in_webhook_event.rb b/lib/surge_api/models/contact_opted_in_webhook_event.rb new file mode 100644 index 0000000..54263cb --- /dev/null +++ b/lib/surge_api/models/contact_opted_in_webhook_event.rb @@ -0,0 +1,54 @@ +# frozen_string_literal: true + +module SurgeAPI + module Models + class ContactOptedInWebhookEvent < SurgeAPI::Internal::Type::BaseModel + # @!attribute account_id + # The ID of the account in which this event occurred + # + # @return [String] + required :account_id, String + + # @!attribute data + # The data associated with the event + # + # @return [SurgeAPI::Models::ContactOptedInWebhookEvent::Data] + required :data, -> { SurgeAPI::ContactOptedInWebhookEvent::Data } + + # @!attribute timestamp + # The timestamp when this event occurred, in ISO8601 format + # + # @return [Time] + required :timestamp, Time + + # @!attribute type + # The type of the event. Always `contact.opted_in` for this event. + # + # @return [Symbol, :"contact.opted_in"] + required :type, const: :"contact.opted_in" + + # @!method initialize(account_id:, data:, timestamp:, type: :"contact.opted_in") + # @param account_id [String] The ID of the account in which this event occurred + # + # @param data [SurgeAPI::Models::ContactOptedInWebhookEvent::Data] The data associated with the event + # + # @param timestamp [Time] The timestamp when this event occurred, in ISO8601 format + # + # @param type [Symbol, :"contact.opted_in"] The type of the event. Always `contact.opted_in` for this event. + + # @see SurgeAPI::Models::ContactOptedInWebhookEvent#data + class Data < SurgeAPI::Internal::Type::BaseModel + # @!attribute id + # The unique identifier for the contact + # + # @return [String] + required :id, String + + # @!method initialize(id:) + # The data associated with the event + # + # @param id [String] The unique identifier for the contact + end + end + end +end diff --git a/lib/surge_api/models/contact_opted_out_webhook_event.rb b/lib/surge_api/models/contact_opted_out_webhook_event.rb new file mode 100644 index 0000000..347dd22 --- /dev/null +++ b/lib/surge_api/models/contact_opted_out_webhook_event.rb @@ -0,0 +1,54 @@ +# frozen_string_literal: true + +module SurgeAPI + module Models + class ContactOptedOutWebhookEvent < SurgeAPI::Internal::Type::BaseModel + # @!attribute account_id + # The ID of the account in which this event occurred + # + # @return [String] + required :account_id, String + + # @!attribute data + # The data associated with the event + # + # @return [SurgeAPI::Models::ContactOptedOutWebhookEvent::Data] + required :data, -> { SurgeAPI::ContactOptedOutWebhookEvent::Data } + + # @!attribute timestamp + # The timestamp when this event occurred, in ISO8601 format + # + # @return [Time] + required :timestamp, Time + + # @!attribute type + # The type of the event. Always `contact.opted_out` for this event. + # + # @return [Symbol, :"contact.opted_out"] + required :type, const: :"contact.opted_out" + + # @!method initialize(account_id:, data:, timestamp:, type: :"contact.opted_out") + # @param account_id [String] The ID of the account in which this event occurred + # + # @param data [SurgeAPI::Models::ContactOptedOutWebhookEvent::Data] The data associated with the event + # + # @param timestamp [Time] The timestamp when this event occurred, in ISO8601 format + # + # @param type [Symbol, :"contact.opted_out"] The type of the event. Always `contact.opted_out` for this event. + + # @see SurgeAPI::Models::ContactOptedOutWebhookEvent#data + class Data < SurgeAPI::Internal::Type::BaseModel + # @!attribute id + # The unique identifier for the contact + # + # @return [String] + required :id, String + + # @!method initialize(id:) + # The data associated with the event + # + # @param id [String] The unique identifier for the contact + end + end + end +end diff --git a/lib/surge_api/models/unwrap_webhook_event.rb b/lib/surge_api/models/unwrap_webhook_event.rb index e44ce1e..da5d359 100644 --- a/lib/surge_api/models/unwrap_webhook_event.rb +++ b/lib/surge_api/models/unwrap_webhook_event.rb @@ -9,6 +9,10 @@ module UnwrapWebhookEvent variant -> { SurgeAPI::CampaignApprovedWebhookEvent } + variant -> { SurgeAPI::ContactOptedInWebhookEvent } + + variant -> { SurgeAPI::ContactOptedOutWebhookEvent } + variant -> { SurgeAPI::ConversationCreatedWebhookEvent } variant -> { SurgeAPI::MessageDeliveredWebhookEvent } @@ -20,7 +24,7 @@ module UnwrapWebhookEvent variant -> { SurgeAPI::MessageSentWebhookEvent } # @!method self.variants - # @return [Array(SurgeAPI::Models::CallEndedWebhookEvent, SurgeAPI::Models::CampaignApprovedWebhookEvent, SurgeAPI::Models::ConversationCreatedWebhookEvent, SurgeAPI::Models::MessageDeliveredWebhookEvent, SurgeAPI::Models::MessageFailedWebhookEvent, SurgeAPI::Models::MessageReceivedWebhookEvent, SurgeAPI::Models::MessageSentWebhookEvent)] + # @return [Array(SurgeAPI::Models::CallEndedWebhookEvent, SurgeAPI::Models::CampaignApprovedWebhookEvent, SurgeAPI::Models::ContactOptedInWebhookEvent, SurgeAPI::Models::ContactOptedOutWebhookEvent, SurgeAPI::Models::ConversationCreatedWebhookEvent, SurgeAPI::Models::MessageDeliveredWebhookEvent, SurgeAPI::Models::MessageFailedWebhookEvent, SurgeAPI::Models::MessageReceivedWebhookEvent, SurgeAPI::Models::MessageSentWebhookEvent)] end end end diff --git a/lib/surge_api/resources/webhooks.rb b/lib/surge_api/resources/webhooks.rb index e9a071a..46e4d43 100644 --- a/lib/surge_api/resources/webhooks.rb +++ b/lib/surge_api/resources/webhooks.rb @@ -5,7 +5,7 @@ module Resources class Webhooks # @param payload [String] The raw webhook payload as a string # - # @return [SurgeAPI::Models::CallEndedWebhookEvent, SurgeAPI::Models::CampaignApprovedWebhookEvent, SurgeAPI::Models::ConversationCreatedWebhookEvent, SurgeAPI::Models::MessageDeliveredWebhookEvent, SurgeAPI::Models::MessageFailedWebhookEvent, SurgeAPI::Models::MessageReceivedWebhookEvent, SurgeAPI::Models::MessageSentWebhookEvent] + # @return [SurgeAPI::Models::CallEndedWebhookEvent, SurgeAPI::Models::CampaignApprovedWebhookEvent, SurgeAPI::Models::ContactOptedInWebhookEvent, SurgeAPI::Models::ContactOptedOutWebhookEvent, SurgeAPI::Models::ConversationCreatedWebhookEvent, SurgeAPI::Models::MessageDeliveredWebhookEvent, SurgeAPI::Models::MessageFailedWebhookEvent, SurgeAPI::Models::MessageReceivedWebhookEvent, SurgeAPI::Models::MessageSentWebhookEvent] def unwrap(payload) parsed = JSON.parse(payload, symbolize_names: true) SurgeAPI::Internal::Type::Converter.coerce(SurgeAPI::Models::UnwrapWebhookEvent, parsed) diff --git a/lib/surge_api/version.rb b/lib/surge_api/version.rb index 429e221..c0593d6 100644 --- a/lib/surge_api/version.rb +++ b/lib/surge_api/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module SurgeAPI - VERSION = "0.1.0" + VERSION = "0.2.0" end diff --git a/rbi/surge_api/file_part.rbi b/rbi/surge_api/file_part.rbi index ecc591e..a301ed9 100644 --- a/rbi/surge_api/file_part.rbi +++ b/rbi/surge_api/file_part.rbi @@ -27,7 +27,7 @@ module SurgeAPI sig do params( content: T.any(Pathname, StringIO, IO, String), - filename: T.nilable(String), + filename: T.nilable(T.any(Pathname, String)), content_type: T.nilable(String) ).returns(T.attached_class) end diff --git a/rbi/surge_api/models.rbi b/rbi/surge_api/models.rbi index 5d866a5..06f1942 100644 --- a/rbi/surge_api/models.rbi +++ b/rbi/surge_api/models.rbi @@ -27,6 +27,10 @@ module SurgeAPI ContactCreateParams = SurgeAPI::Models::ContactCreateParams + ContactOptedInWebhookEvent = SurgeAPI::Models::ContactOptedInWebhookEvent + + ContactOptedOutWebhookEvent = SurgeAPI::Models::ContactOptedOutWebhookEvent + ContactRetrieveParams = SurgeAPI::Models::ContactRetrieveParams ContactUpdateParams = SurgeAPI::Models::ContactUpdateParams diff --git a/rbi/surge_api/models/contact_opted_in_webhook_event.rbi b/rbi/surge_api/models/contact_opted_in_webhook_event.rbi new file mode 100644 index 0000000..dbcc701 --- /dev/null +++ b/rbi/surge_api/models/contact_opted_in_webhook_event.rbi @@ -0,0 +1,95 @@ +# typed: strong + +module SurgeAPI + module Models + class ContactOptedInWebhookEvent < SurgeAPI::Internal::Type::BaseModel + OrHash = + T.type_alias do + T.any( + SurgeAPI::ContactOptedInWebhookEvent, + SurgeAPI::Internal::AnyHash + ) + end + + # The ID of the account in which this event occurred + sig { returns(String) } + attr_accessor :account_id + + # The data associated with the event + sig { returns(SurgeAPI::ContactOptedInWebhookEvent::Data) } + attr_reader :data + + sig do + params(data: SurgeAPI::ContactOptedInWebhookEvent::Data::OrHash).void + end + attr_writer :data + + # The timestamp when this event occurred, in ISO8601 format + sig { returns(Time) } + attr_accessor :timestamp + + # The type of the event. Always `contact.opted_in` for this event. + sig { returns(Symbol) } + attr_accessor :type + + sig do + params( + account_id: String, + data: SurgeAPI::ContactOptedInWebhookEvent::Data::OrHash, + timestamp: Time, + type: Symbol + ).returns(T.attached_class) + end + def self.new( + # The ID of the account in which this event occurred + account_id:, + # The data associated with the event + data:, + # The timestamp when this event occurred, in ISO8601 format + timestamp:, + # The type of the event. Always `contact.opted_in` for this event. + type: :"contact.opted_in" + ) + end + + sig do + override.returns( + { + account_id: String, + data: SurgeAPI::ContactOptedInWebhookEvent::Data, + timestamp: Time, + type: Symbol + } + ) + end + def to_hash + end + + class Data < SurgeAPI::Internal::Type::BaseModel + OrHash = + T.type_alias do + T.any( + SurgeAPI::ContactOptedInWebhookEvent::Data, + SurgeAPI::Internal::AnyHash + ) + end + + # The unique identifier for the contact + sig { returns(String) } + attr_accessor :id + + # The data associated with the event + sig { params(id: String).returns(T.attached_class) } + def self.new( + # The unique identifier for the contact + id: + ) + end + + sig { override.returns({ id: String }) } + def to_hash + end + end + end + end +end diff --git a/rbi/surge_api/models/contact_opted_out_webhook_event.rbi b/rbi/surge_api/models/contact_opted_out_webhook_event.rbi new file mode 100644 index 0000000..4407c28 --- /dev/null +++ b/rbi/surge_api/models/contact_opted_out_webhook_event.rbi @@ -0,0 +1,95 @@ +# typed: strong + +module SurgeAPI + module Models + class ContactOptedOutWebhookEvent < SurgeAPI::Internal::Type::BaseModel + OrHash = + T.type_alias do + T.any( + SurgeAPI::ContactOptedOutWebhookEvent, + SurgeAPI::Internal::AnyHash + ) + end + + # The ID of the account in which this event occurred + sig { returns(String) } + attr_accessor :account_id + + # The data associated with the event + sig { returns(SurgeAPI::ContactOptedOutWebhookEvent::Data) } + attr_reader :data + + sig do + params(data: SurgeAPI::ContactOptedOutWebhookEvent::Data::OrHash).void + end + attr_writer :data + + # The timestamp when this event occurred, in ISO8601 format + sig { returns(Time) } + attr_accessor :timestamp + + # The type of the event. Always `contact.opted_out` for this event. + sig { returns(Symbol) } + attr_accessor :type + + sig do + params( + account_id: String, + data: SurgeAPI::ContactOptedOutWebhookEvent::Data::OrHash, + timestamp: Time, + type: Symbol + ).returns(T.attached_class) + end + def self.new( + # The ID of the account in which this event occurred + account_id:, + # The data associated with the event + data:, + # The timestamp when this event occurred, in ISO8601 format + timestamp:, + # The type of the event. Always `contact.opted_out` for this event. + type: :"contact.opted_out" + ) + end + + sig do + override.returns( + { + account_id: String, + data: SurgeAPI::ContactOptedOutWebhookEvent::Data, + timestamp: Time, + type: Symbol + } + ) + end + def to_hash + end + + class Data < SurgeAPI::Internal::Type::BaseModel + OrHash = + T.type_alias do + T.any( + SurgeAPI::ContactOptedOutWebhookEvent::Data, + SurgeAPI::Internal::AnyHash + ) + end + + # The unique identifier for the contact + sig { returns(String) } + attr_accessor :id + + # The data associated with the event + sig { params(id: String).returns(T.attached_class) } + def self.new( + # The unique identifier for the contact + id: + ) + end + + sig { override.returns({ id: String }) } + def to_hash + end + end + end + end +end diff --git a/rbi/surge_api/models/unwrap_webhook_event.rbi b/rbi/surge_api/models/unwrap_webhook_event.rbi index 9deec0a..1ca92a7 100644 --- a/rbi/surge_api/models/unwrap_webhook_event.rbi +++ b/rbi/surge_api/models/unwrap_webhook_event.rbi @@ -10,6 +10,8 @@ module SurgeAPI T.any( SurgeAPI::CallEndedWebhookEvent, SurgeAPI::CampaignApprovedWebhookEvent, + SurgeAPI::ContactOptedInWebhookEvent, + SurgeAPI::ContactOptedOutWebhookEvent, SurgeAPI::ConversationCreatedWebhookEvent, SurgeAPI::MessageDeliveredWebhookEvent, SurgeAPI::MessageFailedWebhookEvent, diff --git a/rbi/surge_api/resources/webhooks.rbi b/rbi/surge_api/resources/webhooks.rbi index 11466be..f9ed72b 100644 --- a/rbi/surge_api/resources/webhooks.rbi +++ b/rbi/surge_api/resources/webhooks.rbi @@ -8,6 +8,8 @@ module SurgeAPI T.any( SurgeAPI::CallEndedWebhookEvent, SurgeAPI::CampaignApprovedWebhookEvent, + SurgeAPI::ContactOptedInWebhookEvent, + SurgeAPI::ContactOptedOutWebhookEvent, SurgeAPI::ConversationCreatedWebhookEvent, SurgeAPI::MessageDeliveredWebhookEvent, SurgeAPI::MessageFailedWebhookEvent, diff --git a/sig/surge_api/file_part.rbs b/sig/surge_api/file_part.rbs index 4231660..35c0ceb 100644 --- a/sig/surge_api/file_part.rbs +++ b/sig/surge_api/file_part.rbs @@ -14,7 +14,7 @@ module SurgeAPI def initialize: ( Pathname | StringIO | IO | String content, - ?filename: String?, + ?filename: (Pathname | String)?, ?content_type: String? ) -> void end diff --git a/sig/surge_api/models.rbs b/sig/surge_api/models.rbs index 53dc00e..27ee6d3 100644 --- a/sig/surge_api/models.rbs +++ b/sig/surge_api/models.rbs @@ -25,6 +25,10 @@ module SurgeAPI class ContactCreateParams = SurgeAPI::Models::ContactCreateParams + class ContactOptedInWebhookEvent = SurgeAPI::Models::ContactOptedInWebhookEvent + + class ContactOptedOutWebhookEvent = SurgeAPI::Models::ContactOptedOutWebhookEvent + class ContactRetrieveParams = SurgeAPI::Models::ContactRetrieveParams class ContactUpdateParams = SurgeAPI::Models::ContactUpdateParams diff --git a/sig/surge_api/models/contact_opted_in_webhook_event.rbs b/sig/surge_api/models/contact_opted_in_webhook_event.rbs new file mode 100644 index 0000000..32fb286 --- /dev/null +++ b/sig/surge_api/models/contact_opted_in_webhook_event.rbs @@ -0,0 +1,45 @@ +module SurgeAPI + module Models + type contact_opted_in_webhook_event = + { + account_id: String, + data: SurgeAPI::ContactOptedInWebhookEvent::Data, + timestamp: Time, + type: :"contact.opted_in" + } + + class ContactOptedInWebhookEvent < SurgeAPI::Internal::Type::BaseModel + attr_accessor account_id: String + + attr_accessor data: SurgeAPI::ContactOptedInWebhookEvent::Data + + attr_accessor timestamp: Time + + attr_accessor type: :"contact.opted_in" + + def initialize: ( + account_id: String, + data: SurgeAPI::ContactOptedInWebhookEvent::Data, + timestamp: Time, + ?type: :"contact.opted_in" + ) -> void + + def to_hash: -> { + account_id: String, + data: SurgeAPI::ContactOptedInWebhookEvent::Data, + timestamp: Time, + type: :"contact.opted_in" + } + + type data = { id: String } + + class Data < SurgeAPI::Internal::Type::BaseModel + attr_accessor id: String + + def initialize: (id: String) -> void + + def to_hash: -> { id: String } + end + end + end +end diff --git a/sig/surge_api/models/contact_opted_out_webhook_event.rbs b/sig/surge_api/models/contact_opted_out_webhook_event.rbs new file mode 100644 index 0000000..47c8005 --- /dev/null +++ b/sig/surge_api/models/contact_opted_out_webhook_event.rbs @@ -0,0 +1,45 @@ +module SurgeAPI + module Models + type contact_opted_out_webhook_event = + { + account_id: String, + data: SurgeAPI::ContactOptedOutWebhookEvent::Data, + timestamp: Time, + type: :"contact.opted_out" + } + + class ContactOptedOutWebhookEvent < SurgeAPI::Internal::Type::BaseModel + attr_accessor account_id: String + + attr_accessor data: SurgeAPI::ContactOptedOutWebhookEvent::Data + + attr_accessor timestamp: Time + + attr_accessor type: :"contact.opted_out" + + def initialize: ( + account_id: String, + data: SurgeAPI::ContactOptedOutWebhookEvent::Data, + timestamp: Time, + ?type: :"contact.opted_out" + ) -> void + + def to_hash: -> { + account_id: String, + data: SurgeAPI::ContactOptedOutWebhookEvent::Data, + timestamp: Time, + type: :"contact.opted_out" + } + + type data = { id: String } + + class Data < SurgeAPI::Internal::Type::BaseModel + attr_accessor id: String + + def initialize: (id: String) -> void + + def to_hash: -> { id: String } + end + end + end +end diff --git a/sig/surge_api/models/unwrap_webhook_event.rbs b/sig/surge_api/models/unwrap_webhook_event.rbs index 4d1bf32..4be81d1 100644 --- a/sig/surge_api/models/unwrap_webhook_event.rbs +++ b/sig/surge_api/models/unwrap_webhook_event.rbs @@ -3,6 +3,8 @@ module SurgeAPI type unwrap_webhook_event = SurgeAPI::CallEndedWebhookEvent | SurgeAPI::CampaignApprovedWebhookEvent + | SurgeAPI::ContactOptedInWebhookEvent + | SurgeAPI::ContactOptedOutWebhookEvent | SurgeAPI::ConversationCreatedWebhookEvent | SurgeAPI::MessageDeliveredWebhookEvent | SurgeAPI::MessageFailedWebhookEvent diff --git a/sig/surge_api/resources/webhooks.rbs b/sig/surge_api/resources/webhooks.rbs index f1a556c..d9308e2 100644 --- a/sig/surge_api/resources/webhooks.rbs +++ b/sig/surge_api/resources/webhooks.rbs @@ -5,6 +5,8 @@ module SurgeAPI String payload ) -> (SurgeAPI::CallEndedWebhookEvent | SurgeAPI::CampaignApprovedWebhookEvent + | SurgeAPI::ContactOptedInWebhookEvent + | SurgeAPI::ContactOptedOutWebhookEvent | SurgeAPI::ConversationCreatedWebhookEvent | SurgeAPI::MessageDeliveredWebhookEvent | SurgeAPI::MessageFailedWebhookEvent diff --git a/test/surge_api/internal/util_test.rb b/test/surge_api/internal/util_test.rb index 337d6fc..ff77844 100644 --- a/test/surge_api/internal/util_test.rb +++ b/test/surge_api/internal/util_test.rb @@ -227,20 +227,24 @@ def test_encoding_length def test_file_encode file = Pathname(__FILE__) + fileinput = SurgeAPI::Internal::Type::Converter.dump(SurgeAPI::Internal::Type::FileInput, "abc") headers = {"content-type" => "multipart/form-data"} cases = { - "abc" => "abc", - StringIO.new("abc") => "abc", - SurgeAPI::FilePart.new("abc") => "abc", - SurgeAPI::FilePart.new(StringIO.new("abc")) => "abc", - file => /^class SurgeAPI/, - SurgeAPI::FilePart.new(file) => /^class SurgeAPI/ + "abc" => ["", "abc"], + StringIO.new("abc") => ["", "abc"], + fileinput => %w[upload abc], + SurgeAPI::FilePart.new(StringIO.new("abc")) => ["", "abc"], + file => [file.basename.to_path, /^class SurgeAPI/], + SurgeAPI::FilePart.new(file, filename: "d o g") => ["d%20o%20g", /^class SurgeAPI/] } - cases.each do |body, val| + cases.each do |body, testcase| + filename, val = testcase encoded = SurgeAPI::Internal::Util.encode_content(headers, body) cgi = FakeCGI.new(*encoded) + io = cgi[""] assert_pattern do - cgi[""].read => ^val + io.original_filename => ^filename + io.read => ^val end end end @@ -261,7 +265,14 @@ def test_hash_encode cgi = FakeCGI.new(*encoded) testcase.each do |key, val| assert_pattern do - cgi[key] => ^val + parsed = + case (p = cgi[key]) + in StringIO + p.read + else + p + end + parsed => ^val end end end @@ -299,6 +310,31 @@ def test_copy_write end class SurgeAPI::Test::UtilFusedEnumTest < Minitest::Test + def test_rewind_closing + touched = false + once = 0 + steps = 0 + enum = Enumerator.new do |y| + next if touched + + 10.times do + steps = _1 + y << _1 + end + ensure + once = once.succ + end + + fused = SurgeAPI::Internal::Util.fused_enum(enum, external: true) do + touched = true + loop { enum.next } + end + SurgeAPI::Internal::Util.close_fused!(fused) + + assert_equal(1, once) + assert_equal(0, steps) + end + def test_closing arr = [1, 2, 3] once = 0