repull 0.2.8 → 0.2.9

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 (54) hide show
  1. checksums.yaml +4 -4
  2. data/lib/repull/api/airbnb_api.rb +116 -129
  3. data/lib/repull/api/billing_api.rb +0 -55
  4. data/lib/repull/api/booking_com_api.rb +19 -118
  5. data/lib/repull/api/listings_api.rb +74 -0
  6. data/lib/repull/api/reservations_api.rb +0 -197
  7. data/lib/repull/api/{availability_api.rb → sandbox_api.rb} +35 -66
  8. data/lib/repull/api/vrbo_api.rb +0 -126
  9. data/lib/repull/models/{create_studio_project_request.rb → airbnb_availability_write_request.rb} +38 -52
  10. data/lib/repull/models/{create_studio_deployment201_response_data.rb → airbnb_calendar_operation.rb} +108 -57
  11. data/lib/repull/models/{update_studio_project_request.rb → airbnb_listing_action_request.rb} +55 -47
  12. data/lib/repull/models/{update_availability_request.rb → airbnb_pricing_write_request.rb} +100 -11
  13. data/lib/repull/models/{update_reservation_request.rb → booking_availability_update.rb} +124 -22
  14. data/lib/repull/models/{list_studio_deployments200_response.rb → booking_availability_update_request.rb} +90 -18
  15. data/lib/repull/models/{generate_studio_completion_request_project_id.rb → booking_availability_update_request_property_id.rb} +2 -2
  16. data/lib/repull/models/{get_studio_deployment200_response.rb → booking_availability_update_request_updates_inner.rb} +74 -117
  17. data/lib/repull/models/booking_pricing_rate_update.rb +1 -0
  18. data/lib/repull/models/booking_pricing_rate_update_restrictions.rb +65 -6
  19. data/lib/repull/models/{get_studio_project200_response.rb → listing_content_update_request.rb} +106 -10
  20. data/lib/repull/models/{upsert_studio_project_file200_response.rb → listing_content_update_request_address.rb} +53 -10
  21. data/lib/repull/models/listing_content_update_request_amenities.rb +105 -0
  22. data/lib/repull/models/{create_studio_deployment_request.rb → listing_content_update_request_amenities_one_of_inner.rb} +51 -20
  23. data/lib/repull/models/{create_studio_project_generation_request.rb → listing_content_update_request_occupancy.rb} +42 -28
  24. data/lib/repull/{api/ai_api.rb → models/listing_content_update_request_photos_inner.rb} +77 -59
  25. data/lib/repull/models/{generate_studio_completion200_response_data.rb → listing_content_update_request_photos_inner_one_of.rb} +81 -66
  26. data/lib/repull/models/{generate_studio_completion200_response.rb → listing_content_update_request_policies.rb} +116 -10
  27. data/lib/repull/models/{delete_studio_project200_response_data.rb → listing_content_update_response.rb} +26 -10
  28. data/lib/repull/models/map_airbnb_listing_request.rb +215 -0
  29. data/lib/repull/models/{create_reservation_request.rb → map_airbnb_listing_response.rb} +137 -116
  30. data/lib/repull/models/property.rb +42 -69
  31. data/lib/repull/models/reservation.rb +28 -1
  32. data/lib/repull/models/{upsert_studio_project_file_request.rb → sandbox_fixture_ref.rb} +48 -20
  33. data/lib/repull/models/{delete_studio_deployment200_response_data.rb → sandbox_reset_result.rb} +72 -11
  34. data/lib/repull/models/sandbox_reset_result_deleted.rb +216 -0
  35. data/lib/repull/models/sandbox_seed_result.rb +278 -0
  36. data/lib/repull/version.rb +1 -1
  37. data/lib/repull.rb +24 -35
  38. data/openapi/v1.json +1167 -2030
  39. metadata +26 -37
  40. data/lib/repull/api/studio_api.rb +0 -1094
  41. data/lib/repull/models/create_ai_operation200_response.rb +0 -156
  42. data/lib/repull/models/create_studio_deployment201_response.rb +0 -147
  43. data/lib/repull/models/create_studio_project201_response.rb +0 -147
  44. data/lib/repull/models/create_studio_project201_response_data.rb +0 -199
  45. data/lib/repull/models/create_studio_project_generation201_response.rb +0 -147
  46. data/lib/repull/models/create_studio_project_generation201_response_data.rb +0 -165
  47. data/lib/repull/models/delete_studio_deployment200_response.rb +0 -147
  48. data/lib/repull/models/delete_studio_project200_response.rb +0 -147
  49. data/lib/repull/models/delete_studio_project_file200_response.rb +0 -147
  50. data/lib/repull/models/delete_studio_project_file200_response_data.rb +0 -156
  51. data/lib/repull/models/generate_studio_completion_request.rb +0 -305
  52. data/lib/repull/models/list_studio_project_files200_response.rb +0 -149
  53. data/lib/repull/models/list_studio_projects200_response.rb +0 -149
  54. data/lib/repull/models/upsert_studio_project_file200_response_data.rb +0 -147
@@ -0,0 +1,105 @@
1
+ =begin
2
+ #Repull API
3
+
4
+ #The unified API for vacation rental tech. Connect to 50+ PMS platforms and 4 OTA channels through one REST API. Built-in AI operations for guest communication, pricing, and listing optimization. ## Designed for AI agents Every error response on this API includes machine-parseable fields so an LLM (Claude in MCP, Cursor, Cline, GPT, etc.) can self-recover without escalating to a human: - `error.code` — stable string identifier (e.g. `invalid_params`, `rate_limit_exceeded`) - `error.message` — human-readable cause - `error.fix` — exact recovery steps (e.g. \"Pass `check_in_after` as ISO 8601: `?check_in_after=2026-01-15`\") - `error.docs_url` — link to the canonical write-up at `https://repull.dev/docs/errors/{code}` - `error.request_id` — id to correlate with server-side logs - `error.field` / `error.value_received` / `error.valid_values` / `error.did_you_mean` — when the error is parameter-specific - `error.retry_after` — seconds to wait before retrying (rate-limit + transient upstream) `Access-Control-Expose-Headers` lists `x-request-id` and the `X-RateLimit-*` family so browsers can read them on cross-origin responses. ## Quick Start 1. Get an API key at https://repull.dev/dashboard 2. Connect a PMS: `POST /v1/connect/{provider}` 3. List properties: `GET /v1/properties` 4. Get reservations: `GET /v1/reservations` ## Authentication All requests require a Bearer token: ``` Authorization: Bearer sk_test_YOUR_API_KEY ``` Sandbox keys start with `sk_test_`, production with `sk_live_`. ## Request Correlation (X-Request-ID) Every response carries an `X-Request-ID` header, e.g. `X-Request-ID: req_01HXY...`. Include this id in support tickets and bug reports — we can trace the full request lifecycle (auth, rate limit, handler, downstream calls, log row) from a single id. You may set the header on the inbound request to forward your own trace id; we will echo it back instead of generating a new one. Accepted format: `^[\\\\w.-]{1,128}$`. The id is also embedded in error envelopes as `request_id` so server-side log diffs work even when the response headers are stripped by an intermediate proxy. ## Rate Limits The public API enforces a per-API-key sliding-window rate limit on top of the per-tier monthly + daily-AI quotas. **Default policy:** 600 requests per 60 seconds, per API key. Sliding window — there is no fixed-minute boundary you can burst across. Every response includes: | Header | Meaning | |---|---| | `X-RateLimit-Limit` | Requests permitted in the current window. | | `X-RateLimit-Remaining` | Requests left in the current window after this call. | | `X-RateLimit-Reset` | Unix epoch (seconds) when the next slot opens. | | `X-RateLimit-Policy` | Machine-readable policy descriptor, e.g. `600;w=60`. | | `Retry-After` | Seconds to wait before retrying. **Only present on 429 responses.** | **On 429 (rate_limit_exceeded):** the response body matches the standard error envelope with `code: \"rate_limit_exceeded\"`, plus `limit`, `window_seconds`, `retry_after`, and `request_id` fields. SDKs MUST honor `Retry-After` and use exponential backoff with jitter on subsequent retries — never a tight loop. Recommended backoff: ``` sleep_ms = (Retry-After * 1000) + random(0..250) ``` Monthly + daily-AI tier quotas (`free`, `starter`, `custom`) are enforced separately and also surface as 429s; they include `tier`, `scope`, and `resets_at` fields. ## Plan Limits (402 — `listings_limit_exceeded`) The Repull API also enforces a per-tier cap on **active listings**: | Tier | Active listings cap | |---|---| | `free` | 3 | | `starter` | 50 | | `custom` | unlimited | When a customer's active-listing count is above their tier cap, the API returns **`402 Payment Required`** with `error.code = \"listings_limit_exceeded\"` on every route EXCEPT: - `/v1/health` — uptime probes are never gated. - `/v1/usage/*` — so dashboards can render the over-cap state. - Any `DELETE` — so the customer can trim listings to get back under the cap without paying. Unlike 429, 402 is NOT a \"wait and retry\" condition — `Retry-After` is not set. The only paths back to 200 are: 1. `DELETE` enough listings to come back under the cap, or 2. Upgrade at `https://repull.dev/dashboard/billing`. The server-side usage cache is 60s, so the first 200 after an upgrade may take up to a minute. The envelope mirrors `rate_limit_exceeded` for SDK ergonomics: `tier`, `limit`, `active_listings`, `upgrade_url`, plus the standard `code` / `message` / `fix` / `docs_url` / `request_id`.
5
+
6
+ The version of the OpenAPI document: 1.0.0
7
+ Contact: ivan@vanio.ai
8
+ Generated by: https://openapi-generator.tech
9
+ Generator version: 7.22.0
10
+
11
+ =end
12
+
13
+ require 'date'
14
+ require 'time'
15
+
16
+ module Repull
17
+ # FULL replacement of the amenity set. Accepts canonical keys as a string[] or structured rows. Omit to leave amenities untouched; send `[]` to clear them.
18
+ module ListingContentUpdateRequestAmenities
19
+ class << self
20
+ # List of class defined in oneOf (OpenAPI v3)
21
+ def openapi_one_of
22
+ [
23
+ :'Array<ListingContentUpdateRequestAmenitiesOneOfInner>',
24
+ :'Array<String>'
25
+ ]
26
+ end
27
+
28
+ # Builds the object
29
+ # @param [Mixed] Data to be matched against the list of oneOf items
30
+ # @return [Object] Returns the model or the data itself
31
+ def build(data)
32
+ # Go through the list of oneOf items and attempt to identify the appropriate one.
33
+ # Note:
34
+ # - We do not attempt to check whether exactly one item matches.
35
+ # - No advanced validation of types in some cases (e.g. "x: { type: string }" will happily match { x: 123 })
36
+ # due to the way the deserialization is made in the base_object template (it just casts without verifying).
37
+ # - TODO: scalar values are de facto behaving as if they were nullable.
38
+ # - TODO: logging when debugging is set.
39
+ openapi_one_of.each do |klass|
40
+ begin
41
+ next if klass == :AnyType # "nullable: true"
42
+ return find_and_cast_into_type(klass, data)
43
+ rescue # rescue all errors so we keep iterating even if the current item lookup raises
44
+ end
45
+ end
46
+
47
+ openapi_one_of.include?(:AnyType) ? data : nil
48
+ end
49
+
50
+ private
51
+
52
+ SchemaMismatchError = Class.new(StandardError)
53
+
54
+ # Note: 'File' is missing here because in the regular case we get the data _after_ a call to JSON.parse.
55
+ def find_and_cast_into_type(klass, data)
56
+ return if data.nil?
57
+
58
+ case klass.to_s
59
+ when 'Boolean'
60
+ return data if data.instance_of?(TrueClass) || data.instance_of?(FalseClass)
61
+ when 'Float'
62
+ return data if data.instance_of?(Float)
63
+ when 'Integer'
64
+ return data if data.instance_of?(Integer)
65
+ when 'Time'
66
+ return Time.parse(data)
67
+ when 'Date'
68
+ return Date.iso8601(data)
69
+ when 'String'
70
+ return data if data.instance_of?(String)
71
+ when 'Object' # "type: object"
72
+ return data if data.instance_of?(Hash)
73
+ when /\AArray<(?<sub_type>.+)>\z/ # "type: array"
74
+ if data.instance_of?(Array)
75
+ sub_type = Regexp.last_match[:sub_type]
76
+ return data.map { |item| find_and_cast_into_type(sub_type, item) }
77
+ end
78
+ when /\AHash<String, (?<sub_type>.+)>\z/ # "type: object" with "additionalProperties: { ... }"
79
+ if data.instance_of?(Hash) && data.keys.all? { |k| k.instance_of?(Symbol) || k.instance_of?(String) }
80
+ sub_type = Regexp.last_match[:sub_type]
81
+ return data.each_with_object({}) { |(k, v), hsh| hsh[k] = find_and_cast_into_type(sub_type, v) }
82
+ end
83
+ else # model
84
+ const = Repull.const_get(klass)
85
+ if const
86
+ if const.respond_to?(:openapi_one_of) # nested oneOf model
87
+ model = const.build(data)
88
+ return model if model
89
+ else
90
+ # raise if data contains keys that are not known to the model
91
+ raise if const.respond_to?(:acceptable_attributes) && !(data.keys - const.acceptable_attributes).empty?
92
+ model = const.build_from_hash(data)
93
+ return model if model
94
+ end
95
+ end
96
+ end
97
+
98
+ raise # if no match by now, raise
99
+ rescue
100
+ raise SchemaMismatchError, "#{data} doesn't match the #{klass} type"
101
+ end
102
+ end
103
+ end
104
+
105
+ end
@@ -14,14 +14,22 @@ require 'date'
14
14
  require 'time'
15
15
 
16
16
  module Repull
17
- class CreateStudioDeploymentRequest < ApiModelBase
18
- # Project to deploy.
19
- attr_accessor :project_id
17
+ class ListingContentUpdateRequestAmenitiesOneOfInner < ApiModelBase
18
+ attr_accessor :amenity_key
19
+
20
+ attr_accessor :category
21
+
22
+ attr_accessor :is_present
23
+
24
+ attr_accessor :instruction
20
25
 
21
26
  # Attribute mapping from ruby-style variable name to JSON key.
22
27
  def self.attribute_map
23
28
  {
24
- :'project_id' => :'project_id'
29
+ :'amenity_key' => :'amenityKey',
30
+ :'category' => :'category',
31
+ :'is_present' => :'isPresent',
32
+ :'instruction' => :'instruction'
25
33
  }
26
34
  end
27
35
 
@@ -38,13 +46,19 @@ module Repull
38
46
  # Attribute type mapping.
39
47
  def self.openapi_types
40
48
  {
41
- :'project_id' => :'String'
49
+ :'amenity_key' => :'String',
50
+ :'category' => :'String',
51
+ :'is_present' => :'Boolean',
52
+ :'instruction' => :'String'
42
53
  }
43
54
  end
44
55
 
45
56
  # List of attributes with nullable: true
46
57
  def self.openapi_nullable
47
58
  Set.new([
59
+ :'category',
60
+ :'is_present',
61
+ :'instruction'
48
62
  ])
49
63
  end
50
64
 
@@ -52,22 +66,36 @@ module Repull
52
66
  # @param [Hash] attributes Model attributes in the form of hash
53
67
  def initialize(attributes = {})
54
68
  if (!attributes.is_a?(Hash))
55
- fail ArgumentError, "The input argument (attributes) must be a hash in `Repull::CreateStudioDeploymentRequest` initialize method"
69
+ fail ArgumentError, "The input argument (attributes) must be a hash in `Repull::ListingContentUpdateRequestAmenitiesOneOfInner` initialize method"
56
70
  end
57
71
 
58
72
  # check to see if the attribute exists and convert string to symbol for hash key
59
73
  acceptable_attribute_map = self.class.acceptable_attribute_map
60
74
  attributes = attributes.each_with_object({}) { |(k, v), h|
61
75
  if (!acceptable_attribute_map.key?(k.to_sym))
62
- fail ArgumentError, "`#{k}` is not a valid attribute in `Repull::CreateStudioDeploymentRequest`. Please check the name to make sure it's valid. List of attributes: " + acceptable_attribute_map.keys.inspect
76
+ fail ArgumentError, "`#{k}` is not a valid attribute in `Repull::ListingContentUpdateRequestAmenitiesOneOfInner`. Please check the name to make sure it's valid. List of attributes: " + acceptable_attribute_map.keys.inspect
63
77
  end
64
78
  h[k.to_sym] = v
65
79
  }
66
80
 
67
- if attributes.key?(:'project_id')
68
- self.project_id = attributes[:'project_id']
81
+ if attributes.key?(:'amenity_key')
82
+ self.amenity_key = attributes[:'amenity_key']
83
+ else
84
+ self.amenity_key = nil
85
+ end
86
+
87
+ if attributes.key?(:'category')
88
+ self.category = attributes[:'category']
89
+ end
90
+
91
+ if attributes.key?(:'is_present')
92
+ self.is_present = attributes[:'is_present']
69
93
  else
70
- self.project_id = nil
94
+ self.is_present = true
95
+ end
96
+
97
+ if attributes.key?(:'instruction')
98
+ self.instruction = attributes[:'instruction']
71
99
  end
72
100
  end
73
101
 
@@ -76,8 +104,8 @@ module Repull
76
104
  def list_invalid_properties
77
105
  warn '[DEPRECATED] the `list_invalid_properties` method is obsolete'
78
106
  invalid_properties = Array.new
79
- if @project_id.nil?
80
- invalid_properties.push('invalid value for "project_id", project_id cannot be nil.')
107
+ if @amenity_key.nil?
108
+ invalid_properties.push('invalid value for "amenity_key", amenity_key cannot be nil.')
81
109
  end
82
110
 
83
111
  invalid_properties
@@ -87,18 +115,18 @@ module Repull
87
115
  # @return true if the model is valid
88
116
  def valid?
89
117
  warn '[DEPRECATED] the `valid?` method is obsolete'
90
- return false if @project_id.nil?
118
+ return false if @amenity_key.nil?
91
119
  true
92
120
  end
93
121
 
94
122
  # Custom attribute writer method with validation
95
- # @param [Object] project_id Value to be assigned
96
- def project_id=(project_id)
97
- if project_id.nil?
98
- fail ArgumentError, 'project_id cannot be nil'
123
+ # @param [Object] amenity_key Value to be assigned
124
+ def amenity_key=(amenity_key)
125
+ if amenity_key.nil?
126
+ fail ArgumentError, 'amenity_key cannot be nil'
99
127
  end
100
128
 
101
- @project_id = project_id
129
+ @amenity_key = amenity_key
102
130
  end
103
131
 
104
132
  # Checks equality by comparing each attribute.
@@ -106,7 +134,10 @@ module Repull
106
134
  def ==(o)
107
135
  return true if self.equal?(o)
108
136
  self.class == o.class &&
109
- project_id == o.project_id
137
+ amenity_key == o.amenity_key &&
138
+ category == o.category &&
139
+ is_present == o.is_present &&
140
+ instruction == o.instruction
110
141
  end
111
142
 
112
143
  # @see the `==` method
@@ -118,7 +149,7 @@ module Repull
118
149
  # Calculates hash code according to all attributes.
119
150
  # @return [Integer] Hash code
120
151
  def hash
121
- [project_id].hash
152
+ [amenity_key, category, is_present, instruction].hash
122
153
  end
123
154
 
124
155
  # Builds the object from hash
@@ -14,14 +14,23 @@ require 'date'
14
14
  require 'time'
15
15
 
16
16
  module Repull
17
- class CreateStudioProjectGenerationRequest < ApiModelBase
18
- # Prompt to send to Repull AI.
19
- attr_accessor :prompt
17
+ class ListingContentUpdateRequestOccupancy < ApiModelBase
18
+ attr_accessor :max_guests
19
+
20
+ attr_accessor :bedrooms
21
+
22
+ attr_accessor :beds
23
+
24
+ # Decimal, e.g. 1.5.
25
+ attr_accessor :bathrooms
20
26
 
21
27
  # Attribute mapping from ruby-style variable name to JSON key.
22
28
  def self.attribute_map
23
29
  {
24
- :'prompt' => :'prompt'
30
+ :'max_guests' => :'maxGuests',
31
+ :'bedrooms' => :'bedrooms',
32
+ :'beds' => :'beds',
33
+ :'bathrooms' => :'bathrooms'
25
34
  }
26
35
  end
27
36
 
@@ -38,13 +47,20 @@ module Repull
38
47
  # Attribute type mapping.
39
48
  def self.openapi_types
40
49
  {
41
- :'prompt' => :'String'
50
+ :'max_guests' => :'Integer',
51
+ :'bedrooms' => :'Integer',
52
+ :'beds' => :'Integer',
53
+ :'bathrooms' => :'Float'
42
54
  }
43
55
  end
44
56
 
45
57
  # List of attributes with nullable: true
46
58
  def self.openapi_nullable
47
59
  Set.new([
60
+ :'max_guests',
61
+ :'bedrooms',
62
+ :'beds',
63
+ :'bathrooms'
48
64
  ])
49
65
  end
50
66
 
@@ -52,22 +68,32 @@ module Repull
52
68
  # @param [Hash] attributes Model attributes in the form of hash
53
69
  def initialize(attributes = {})
54
70
  if (!attributes.is_a?(Hash))
55
- fail ArgumentError, "The input argument (attributes) must be a hash in `Repull::CreateStudioProjectGenerationRequest` initialize method"
71
+ fail ArgumentError, "The input argument (attributes) must be a hash in `Repull::ListingContentUpdateRequestOccupancy` initialize method"
56
72
  end
57
73
 
58
74
  # check to see if the attribute exists and convert string to symbol for hash key
59
75
  acceptable_attribute_map = self.class.acceptable_attribute_map
60
76
  attributes = attributes.each_with_object({}) { |(k, v), h|
61
77
  if (!acceptable_attribute_map.key?(k.to_sym))
62
- fail ArgumentError, "`#{k}` is not a valid attribute in `Repull::CreateStudioProjectGenerationRequest`. Please check the name to make sure it's valid. List of attributes: " + acceptable_attribute_map.keys.inspect
78
+ fail ArgumentError, "`#{k}` is not a valid attribute in `Repull::ListingContentUpdateRequestOccupancy`. Please check the name to make sure it's valid. List of attributes: " + acceptable_attribute_map.keys.inspect
63
79
  end
64
80
  h[k.to_sym] = v
65
81
  }
66
82
 
67
- if attributes.key?(:'prompt')
68
- self.prompt = attributes[:'prompt']
69
- else
70
- self.prompt = nil
83
+ if attributes.key?(:'max_guests')
84
+ self.max_guests = attributes[:'max_guests']
85
+ end
86
+
87
+ if attributes.key?(:'bedrooms')
88
+ self.bedrooms = attributes[:'bedrooms']
89
+ end
90
+
91
+ if attributes.key?(:'beds')
92
+ self.beds = attributes[:'beds']
93
+ end
94
+
95
+ if attributes.key?(:'bathrooms')
96
+ self.bathrooms = attributes[:'bathrooms']
71
97
  end
72
98
  end
73
99
 
@@ -76,10 +102,6 @@ module Repull
76
102
  def list_invalid_properties
77
103
  warn '[DEPRECATED] the `list_invalid_properties` method is obsolete'
78
104
  invalid_properties = Array.new
79
- if @prompt.nil?
80
- invalid_properties.push('invalid value for "prompt", prompt cannot be nil.')
81
- end
82
-
83
105
  invalid_properties
84
106
  end
85
107
 
@@ -87,26 +109,18 @@ module Repull
87
109
  # @return true if the model is valid
88
110
  def valid?
89
111
  warn '[DEPRECATED] the `valid?` method is obsolete'
90
- return false if @prompt.nil?
91
112
  true
92
113
  end
93
114
 
94
- # Custom attribute writer method with validation
95
- # @param [Object] prompt Value to be assigned
96
- def prompt=(prompt)
97
- if prompt.nil?
98
- fail ArgumentError, 'prompt cannot be nil'
99
- end
100
-
101
- @prompt = prompt
102
- end
103
-
104
115
  # Checks equality by comparing each attribute.
105
116
  # @param [Object] Object to be compared
106
117
  def ==(o)
107
118
  return true if self.equal?(o)
108
119
  self.class == o.class &&
109
- prompt == o.prompt
120
+ max_guests == o.max_guests &&
121
+ bedrooms == o.bedrooms &&
122
+ beds == o.beds &&
123
+ bathrooms == o.bathrooms
110
124
  end
111
125
 
112
126
  # @see the `==` method
@@ -118,7 +132,7 @@ module Repull
118
132
  # Calculates hash code according to all attributes.
119
133
  # @return [Integer] Hash code
120
134
  def hash
121
- [prompt].hash
135
+ [max_guests, bedrooms, beds, bathrooms].hash
122
136
  end
123
137
 
124
138
  # Builds the object from hash
@@ -10,77 +10,95 @@ Generator version: 7.22.0
10
10
 
11
11
  =end
12
12
 
13
- require 'cgi'
13
+ require 'date'
14
+ require 'time'
14
15
 
15
16
  module Repull
16
- class AIApi
17
- attr_accessor :api_client
18
-
19
- def initialize(api_client = ApiClient.default)
20
- @api_client = api_client
21
- end
22
- # AI operation
23
- # Perform an AI-powered operation. Operations: - `respond-to-guest` — Generate a contextual guest response - `classify-intent` — Classify the intent of a guest message - `generate-listing` — Generate optimized listing description - `review-response` — Generate a review response - `price-suggestion` — Get AI pricing suggestions
24
- # @param [Hash] opts the optional parameters
25
- # @option opts [AIOperation] :ai_operation
26
- # @return [CreateAiOperation200Response]
27
- def create_ai_operation(opts = {})
28
- data, _status_code, _headers = create_ai_operation_with_http_info(opts)
29
- data
30
- end
31
-
32
- # AI operation
33
- # Perform an AI-powered operation. Operations: - &#x60;respond-to-guest&#x60; — Generate a contextual guest response - &#x60;classify-intent&#x60; — Classify the intent of a guest message - &#x60;generate-listing&#x60; — Generate optimized listing description - &#x60;review-response&#x60; — Generate a review response - &#x60;price-suggestion&#x60; — Get AI pricing suggestions
34
- # @param [Hash] opts the optional parameters
35
- # @option opts [AIOperation] :ai_operation
36
- # @return [Array<(CreateAiOperation200Response, Integer, Hash)>] CreateAiOperation200Response data, response status code and response headers
37
- def create_ai_operation_with_http_info(opts = {})
38
- if @api_client.config.debugging
39
- @api_client.config.logger.debug 'Calling API: AIApi.create_ai_operation ...'
17
+ module ListingContentUpdateRequestPhotosInner
18
+ class << self
19
+ # List of class defined in oneOf (OpenAPI v3)
20
+ def openapi_one_of
21
+ [
22
+ :'ListingContentUpdateRequestPhotosInnerOneOf',
23
+ :'String'
24
+ ]
40
25
  end
41
- # resource path
42
- local_var_path = '/v1/ai'
43
26
 
44
- # query parameters
45
- query_params = opts[:query_params] || {}
27
+ # Builds the object
28
+ # @param [Mixed] Data to be matched against the list of oneOf items
29
+ # @return [Object] Returns the model or the data itself
30
+ def build(data)
31
+ # Go through the list of oneOf items and attempt to identify the appropriate one.
32
+ # Note:
33
+ # - We do not attempt to check whether exactly one item matches.
34
+ # - No advanced validation of types in some cases (e.g. "x: { type: string }" will happily match { x: 123 })
35
+ # due to the way the deserialization is made in the base_object template (it just casts without verifying).
36
+ # - TODO: scalar values are de facto behaving as if they were nullable.
37
+ # - TODO: logging when debugging is set.
38
+ openapi_one_of.each do |klass|
39
+ begin
40
+ next if klass == :AnyType # "nullable: true"
41
+ return find_and_cast_into_type(klass, data)
42
+ rescue # rescue all errors so we keep iterating even if the current item lookup raises
43
+ end
44
+ end
46
45
 
47
- # header parameters
48
- header_params = opts[:header_params] || {}
49
- # HTTP header 'Accept' (if needed)
50
- header_params['Accept'] = @api_client.select_header_accept(['application/json']) unless header_params['Accept']
51
- # HTTP header 'Content-Type'
52
- content_type = @api_client.select_header_content_type(['application/json'])
53
- if !content_type.nil?
54
- header_params['Content-Type'] = content_type
46
+ openapi_one_of.include?(:AnyType) ? data : nil
55
47
  end
56
48
 
57
- # form parameters
58
- form_params = opts[:form_params] || {}
59
-
60
- # http body (model)
61
- post_body = opts[:debug_body] || @api_client.object_to_http_body(opts[:'ai_operation'])
49
+ private
62
50
 
63
- # return_type
64
- return_type = opts[:debug_return_type] || 'CreateAiOperation200Response'
51
+ SchemaMismatchError = Class.new(StandardError)
65
52
 
66
- # auth_names
67
- auth_names = opts[:debug_auth_names] || ['bearerAuth']
53
+ # Note: 'File' is missing here because in the regular case we get the data _after_ a call to JSON.parse.
54
+ def find_and_cast_into_type(klass, data)
55
+ return if data.nil?
68
56
 
69
- new_options = opts.merge(
70
- :operation => :"AIApi.create_ai_operation",
71
- :header_params => header_params,
72
- :query_params => query_params,
73
- :form_params => form_params,
74
- :body => post_body,
75
- :auth_names => auth_names,
76
- :return_type => return_type
77
- )
57
+ case klass.to_s
58
+ when 'Boolean'
59
+ return data if data.instance_of?(TrueClass) || data.instance_of?(FalseClass)
60
+ when 'Float'
61
+ return data if data.instance_of?(Float)
62
+ when 'Integer'
63
+ return data if data.instance_of?(Integer)
64
+ when 'Time'
65
+ return Time.parse(data)
66
+ when 'Date'
67
+ return Date.iso8601(data)
68
+ when 'String'
69
+ return data if data.instance_of?(String)
70
+ when 'Object' # "type: object"
71
+ return data if data.instance_of?(Hash)
72
+ when /\AArray<(?<sub_type>.+)>\z/ # "type: array"
73
+ if data.instance_of?(Array)
74
+ sub_type = Regexp.last_match[:sub_type]
75
+ return data.map { |item| find_and_cast_into_type(sub_type, item) }
76
+ end
77
+ when /\AHash<String, (?<sub_type>.+)>\z/ # "type: object" with "additionalProperties: { ... }"
78
+ if data.instance_of?(Hash) && data.keys.all? { |k| k.instance_of?(Symbol) || k.instance_of?(String) }
79
+ sub_type = Regexp.last_match[:sub_type]
80
+ return data.each_with_object({}) { |(k, v), hsh| hsh[k] = find_and_cast_into_type(sub_type, v) }
81
+ end
82
+ else # model
83
+ const = Repull.const_get(klass)
84
+ if const
85
+ if const.respond_to?(:openapi_one_of) # nested oneOf model
86
+ model = const.build(data)
87
+ return model if model
88
+ else
89
+ # raise if data contains keys that are not known to the model
90
+ raise if const.respond_to?(:acceptable_attributes) && !(data.keys - const.acceptable_attributes).empty?
91
+ model = const.build_from_hash(data)
92
+ return model if model
93
+ end
94
+ end
95
+ end
78
96
 
79
- data, status_code, headers = @api_client.call_api(:POST, local_var_path, new_options)
80
- if @api_client.config.debugging
81
- @api_client.config.logger.debug "API called: AIApi#create_ai_operation\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}"
97
+ raise # if no match by now, raise
98
+ rescue
99
+ raise SchemaMismatchError, "#{data} doesn't match the #{klass} type"
82
100
  end
83
- return data, status_code, headers
84
101
  end
85
102
  end
103
+
86
104
  end