basecamp-sdk 0.7.0 → 0.7.1

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 67da09be280f8e08a9639f77ea7d08f70e5327609cac6a46812bf76069a09a18
4
- data.tar.gz: 98f22496c4a83e17e076e2339848ee6c1738b4f5382889114acb053ea010ffe1
3
+ metadata.gz: '08447be78a091d1fd44c4ca85addf5d7f262f383e5d085d6765199362323d3de'
4
+ data.tar.gz: 538782581af8739afa7046e204b628fdbb6ed96f2822b92806b669c63b302708
5
5
  SHA512:
6
- metadata.gz: 27cae3068542c51e3a02a994deaf8b68d6a91e8ddae6d5ce1ac7b98123718e5aa884879ee5ee679b432b30074d5f1c00d62ca2bd714ca144a2d3b352b398c961
7
- data.tar.gz: 8da2274e9fcaa49289e5e6c0587dd396f2f56012146fa490decef7fb195be3223cd34f23c1ba3e227a6538b9620473ac98dbf856aeabfa845de59ff0bc984d1a
6
+ metadata.gz: 90a91f187db4d1c0213169fba7c033a3da6f7efc5e2ef71c25318e1cbef39e2d3b7383477fd804257f7148ea44625f068658a1b1d6339585cda73a2a7f34a798
7
+ data.tar.gz: 052e7117c71e54bd7a415266b444e48e2344bc08b16475841e43934bdb7257c51cd283de7806f9b7893210611a778d36be3053dc3d5bee689f5107677e6cbc91
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://basecamp.com/schemas/sdk-metadata.json",
3
3
  "version": "1.0.0",
4
- "generated": "2026-03-23T21:15:35Z",
4
+ "generated": "2026-03-25T06:39:18Z",
5
5
  "operations": {
6
6
  "GetAccount": {
7
7
  "retry": {
@@ -14,6 +14,20 @@
14
14
  ]
15
15
  }
16
16
  },
17
+ "UpdateAccountLogo": {
18
+ "retry": {
19
+ "maxAttempts": 2,
20
+ "baseDelayMs": 1000,
21
+ "backoff": "exponential",
22
+ "retryOn": [
23
+ 429,
24
+ 503
25
+ ]
26
+ },
27
+ "idempotent": {
28
+ "natural": true
29
+ }
30
+ },
17
31
  "RemoveAccountLogo": {
18
32
  "retry": {
19
33
  "maxAttempts": 2,
@@ -1088,7 +1102,7 @@
1088
1102
  },
1089
1103
  "UpdateMyProfile": {
1090
1104
  "retry": {
1091
- "maxAttempts": 2,
1105
+ "maxAttempts": 3,
1092
1106
  "baseDelayMs": 1000,
1093
1107
  "backoff": "exponential",
1094
1108
  "retryOn": [
@@ -27,10 +27,11 @@ module Basecamp
27
27
  # Update an existing answer
28
28
  # @param answer_id [Integer] answer id ID
29
29
  # @param content [String] content
30
+ # @param group_on [String, nil] group on (YYYY-MM-DD)
30
31
  # @return [void]
31
- def update_answer(answer_id:, content:)
32
+ def update_answer(answer_id:, content:, group_on: nil)
32
33
  with_operation(service: "checkins", operation: "update_answer", is_mutation: true, resource_id: answer_id) do
33
- http_put("/question_answers/#{answer_id}", body: compact_params(content: content))
34
+ http_put("/question_answers/#{answer_id}", body: compact_params(content: content, group_on: group_on))
34
35
  nil
35
36
  end
36
37
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Auto-generated from OpenAPI spec. Do not edit manually.
4
- # Generated: 2026-03-23T21:15:35Z
4
+ # Generated: 2026-03-25T06:39:18Z
5
5
 
6
6
  require "json"
7
7
  require "time"
@@ -80,7 +80,7 @@ module Basecamp
80
80
  @active = parse_boolean(data["active"])
81
81
  @frozen = parse_boolean(data["frozen"])
82
82
  @limits = parse_type(data["limits"], "AccountLimits")
83
- @logo = data["logo"]
83
+ @logo = parse_type(data["logo"], "AccountLogo")
84
84
  @owner_name = data["owner_name"]
85
85
  @paused = parse_boolean(data["paused"])
86
86
  @settings = parse_type(data["settings"], "AccountSettings")
@@ -139,6 +139,26 @@ module Basecamp
139
139
  end
140
140
  end
141
141
 
142
+ # AccountLogo
143
+ class AccountLogo
144
+ include TypeHelpers
145
+ attr_accessor :url
146
+
147
+ def initialize(data = {})
148
+ @url = data["url"]
149
+ end
150
+
151
+ def to_h
152
+ {
153
+ "url" => @url,
154
+ }.compact
155
+ end
156
+
157
+ def to_json(*args)
158
+ to_h.to_json(*args)
159
+ end
160
+ end
161
+
142
162
  # AccountSettings
143
163
  class AccountSettings
144
164
  include TypeHelpers
@@ -1479,7 +1499,7 @@ module Basecamp
1479
1499
  # GaugeNeedle
1480
1500
  class GaugeNeedle
1481
1501
  include TypeHelpers
1482
- attr_accessor :created_at, :id, :updated_at, :app_url, :bookmark_url, :boosts_count, :boosts_url, :bucket, :color, :comment_count, :comments_count, :comments_url, :creator, :description, :inherits_status, :parent, :position, :status, :subscription_url, :title, :type, :url, :visible_to_clients
1502
+ attr_accessor :created_at, :id, :updated_at, :app_url, :bookmark_url, :boosts_count, :boosts_url, :bucket, :color, :comments_count, :comments_url, :creator, :description, :inherits_status, :parent, :position, :status, :subscription_url, :title, :type, :url, :visible_to_clients
1483
1503
 
1484
1504
  # @return [Array<Symbol>]
1485
1505
  def self.required_fields
@@ -1496,7 +1516,6 @@ module Basecamp
1496
1516
  @boosts_url = data["boosts_url"]
1497
1517
  @bucket = parse_type(data["bucket"], "RecordingBucket")
1498
1518
  @color = data["color"]
1499
- @comment_count = parse_integer(data["comment_count"])
1500
1519
  @comments_count = parse_integer(data["comments_count"])
1501
1520
  @comments_url = data["comments_url"]
1502
1521
  @creator = parse_type(data["creator"], "Person")
@@ -1523,7 +1542,6 @@ module Basecamp
1523
1542
  "boosts_url" => @boosts_url,
1524
1543
  "bucket" => @bucket,
1525
1544
  "color" => @color,
1526
- "comment_count" => @comment_count,
1527
1545
  "comments_count" => @comments_count,
1528
1546
  "comments_url" => @comments_url,
1529
1547
  "creator" => @creator,
@@ -2228,7 +2246,7 @@ module Basecamp
2228
2246
  # Person
2229
2247
  class Person
2230
2248
  include TypeHelpers
2231
- attr_accessor :id, :name, :admin, :attachable_sgid, :avatar_url, :bio, :can_access_hill_charts, :can_access_timesheet, :can_manage_people, :can_manage_projects, :can_ping, :client, :company, :created_at, :email_address, :employee, :location, :owner, :personable_type, :time_zone, :title, :updated_at
2249
+ attr_accessor :id, :name, :admin, :attachable_sgid, :avatar_url, :bio, :can_access_hill_charts, :can_access_timesheet, :can_manage_people, :can_manage_projects, :can_ping, :client, :company, :created_at, :email_address, :employee, :location, :owner, :personable_type, :time_zone, :title, :updated_at, :system_label
2232
2250
 
2233
2251
  # @return [Array<Symbol>]
2234
2252
  def self.required_fields
@@ -2237,6 +2255,7 @@ module Basecamp
2237
2255
 
2238
2256
  def initialize(data = {})
2239
2257
  @id = parse_integer(data["id"])
2258
+ @system_label = data["system_label"]
2240
2259
  @name = data["name"]
2241
2260
  @admin = parse_boolean(data["admin"])
2242
2261
  @attachable_sgid = data["attachable_sgid"]
@@ -2667,7 +2686,7 @@ module Basecamp
2667
2686
  # QuestionAnswerUpdatePayload
2668
2687
  class QuestionAnswerUpdatePayload
2669
2688
  include TypeHelpers
2670
- attr_accessor :content
2689
+ attr_accessor :content, :group_on
2671
2690
 
2672
2691
  # @return [Array<Symbol>]
2673
2692
  def self.required_fields
@@ -2676,11 +2695,13 @@ module Basecamp
2676
2695
 
2677
2696
  def initialize(data = {})
2678
2697
  @content = data["content"]
2698
+ @group_on = data["group_on"]
2679
2699
  end
2680
2700
 
2681
2701
  def to_h
2682
2702
  {
2683
2703
  "content" => @content,
2704
+ "group_on" => @group_on,
2684
2705
  }.compact
2685
2706
  end
2686
2707
 
data/lib/basecamp/http.rb CHANGED
@@ -12,6 +12,29 @@ module Basecamp
12
12
  # Default User-Agent header
13
13
  USER_AGENT = "basecamp-sdk-ruby/#{VERSION} (api:#{API_VERSION})".freeze
14
14
 
15
+ # Normalizes Person-shaped objects in parsed JSON.
16
+ # For objects with personable_type and a string id:
17
+ # - Numeric strings: coerced to Integer, no system_label
18
+ # - Non-numeric sentinels (e.g. "basecamp"): id becomes 0, system_label preserves original
19
+ def self.normalize_person_ids(obj)
20
+ case obj
21
+ when Hash
22
+ if obj.key?("personable_type") && obj["id"].is_a?(String)
23
+ raw_id = obj["id"]
24
+ numeric = Integer(raw_id, exception: false)
25
+ if numeric
26
+ obj["id"] = numeric
27
+ else
28
+ obj["system_label"] = raw_id
29
+ obj["id"] = 0
30
+ end
31
+ end
32
+ obj.each_value { |v| normalize_person_ids(v) }
33
+ when Array
34
+ obj.each { |item| normalize_person_ids(item) }
35
+ end
36
+ end
37
+
15
38
  # @param config [Config] configuration settings
16
39
  # @param token_provider [TokenProvider, nil] OAuth token provider (deprecated, use auth_strategy)
17
40
  # @param auth_strategy [AuthStrategy, nil] authentication strategy
@@ -122,6 +145,7 @@ module Basecamp
122
145
 
123
146
  begin
124
147
  items = JSON.parse(response.body)
148
+ Http.normalize_person_ids(items)
125
149
  rescue JSON::ParserError => e
126
150
  raise Basecamp::ApiError.new("Failed to parse paginated response (page #{page}): #{Security.truncate(e.message)}")
127
151
  end
@@ -167,6 +191,7 @@ module Basecamp
167
191
 
168
192
  begin
169
193
  data = JSON.parse(response.body)
194
+ Http.normalize_person_ids(data)
170
195
  rescue JSON::ParserError => e
171
196
  raise Basecamp::ApiError.new("Failed to parse paginated response (page #{page}): #{Security.truncate(e.message)}")
172
197
  end
@@ -206,6 +231,7 @@ module Basecamp
206
231
 
207
232
  begin
208
233
  first_data = JSON.parse(first_response.body)
234
+ Http.normalize_person_ids(first_data)
209
235
  rescue JSON::ParserError => e
210
236
  raise Basecamp::ApiError.new(
211
237
  "Failed to parse paginated response (page 1): #{Security.truncate(e.message)}"
@@ -239,6 +265,7 @@ module Basecamp
239
265
 
240
266
  begin
241
267
  data = JSON.parse(response.body)
268
+ Http.normalize_person_ids(data)
242
269
  rescue JSON::ParserError => e
243
270
  raise Basecamp::ApiError.new(
244
271
  "Failed to parse paginated response (page #{page}): " \
@@ -511,12 +538,14 @@ module Basecamp
511
538
  @headers = headers
512
539
  end
513
540
 
514
- # Parses the response body as JSON.
541
+ # Parses the response body as JSON, normalizing Person-shaped objects.
515
542
  # @return [Hash, Array]
516
543
  def json
517
544
  @json ||= begin
518
545
  Security.check_body_size!(@body, Security::MAX_RESPONSE_BODY_BYTES)
519
- JSON.parse(@body)
546
+ result = JSON.parse(@body)
547
+ Http.normalize_person_ids(result)
548
+ result
520
549
  end
521
550
  end
522
551
 
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Basecamp
4
- VERSION = "0.7.0"
4
+ VERSION = "0.7.1"
5
5
  API_VERSION = "2026-01-26"
6
6
  end
@@ -128,6 +128,9 @@ if __FILE__ == $PROGRAM_NAME
128
128
  puts ' include TypeHelpers'
129
129
 
130
130
  attr_names = ordered_props.map { |k| k.gsub(/([A-Z])/, '_\1').downcase.gsub(/^_/, '') }
131
+ # Add system_label for schemas with flexible integer fields
132
+ has_flexible = ordered_props.any? { |k| properties[k]['x-go-type']&.include?('FlexibleInt64') }
133
+ attr_names << 'system_label' if has_flexible
131
134
  puts " attr_accessor #{attr_names.map { |n| ":#{n}" }.join(", ")}"
132
135
 
133
136
  unless required_props.empty?
@@ -165,6 +168,10 @@ if __FILE__ == $PROGRAM_NAME
165
168
  end
166
169
 
167
170
  puts " @#{attr_name} = #{converter}"
171
+ # Add system_label after flexible integer id fields
172
+ if prop_schema['x-go-type']&.include?('FlexibleInt64')
173
+ puts ' @system_label = data["system_label"]'
174
+ end
168
175
  end
169
176
  puts ' end'
170
177
  puts ''
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: basecamp-sdk
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0
4
+ version: 0.7.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Basecamp
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-03-24 00:00:00.000000000 Z
11
+ date: 2026-03-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday