basecamp-sdk 0.2.2 → 0.2.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.
- checksums.yaml +4 -4
- data/lib/basecamp/errors.rb +6 -1
- data/lib/basecamp/generated/metadata.json +28 -1
- data/lib/basecamp/generated/services/campfires_service.rb +23 -0
- data/lib/basecamp/generated/types.rb +40 -6
- data/lib/basecamp/http.rb +8 -5
- data/lib/basecamp/version.rb +1 -1
- data/scripts/generate-services.rb +3 -0
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 2d9ac0d518ad24aed0762084bbe6d5e086652d2b10cd6d7f28ba0afa839fa2cd
|
|
4
|
+
data.tar.gz: 7dbc3a032f0e0fbe6f2993db0c588d44b4a2aaebde9764004820845eac3bacc5
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 2914132d8a9a6a9dba9b14bd10e36fbab735ec9a564342cb9f44aed6c4c766687f4462e9264284bba46a31d3ab614ddf9fdc9350c7726e17517ba358769b6a05
|
|
7
|
+
data.tar.gz: be5c86123641a00cb716b2c1d87daaff532fe5da7c6aa30665401a9d0eefdad300895f1ce2cce937c984f1b59e046916b3b9197baf55da2c4f85ec90d1dd47c0
|
data/lib/basecamp/errors.rb
CHANGED
|
@@ -56,6 +56,9 @@ module Basecamp
|
|
|
56
56
|
# @return [Integer, nil] seconds to wait before retrying (for rate limits)
|
|
57
57
|
attr_reader :retry_after
|
|
58
58
|
|
|
59
|
+
# @return [String, nil] X-Request-Id from the response
|
|
60
|
+
attr_reader :request_id
|
|
61
|
+
|
|
59
62
|
# @return [Exception, nil] original error that caused this error
|
|
60
63
|
attr_reader :cause
|
|
61
64
|
|
|
@@ -65,14 +68,16 @@ module Basecamp
|
|
|
65
68
|
# @param http_status [Integer, nil] HTTP status code
|
|
66
69
|
# @param retryable [Boolean] whether operation can be retried
|
|
67
70
|
# @param retry_after [Integer, nil] seconds to wait before retry
|
|
71
|
+
# @param request_id [String, nil] X-Request-Id from response
|
|
68
72
|
# @param cause [Exception, nil] underlying cause
|
|
69
|
-
def initialize(code:, message:, hint: nil, http_status: nil, retryable: false, retry_after: nil, cause: nil)
|
|
73
|
+
def initialize(code:, message:, hint: nil, http_status: nil, retryable: false, retry_after: nil, request_id: nil, cause: nil)
|
|
70
74
|
super(message)
|
|
71
75
|
@code = code
|
|
72
76
|
@hint = hint
|
|
73
77
|
@http_status = http_status
|
|
74
78
|
@retryable = retryable
|
|
75
79
|
@retry_after = retry_after
|
|
80
|
+
@request_id = request_id
|
|
76
81
|
@cause = cause
|
|
77
82
|
end
|
|
78
83
|
|
|
@@ -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-
|
|
4
|
+
"generated": "2026-03-09T19:39:33Z",
|
|
5
5
|
"operations": {
|
|
6
6
|
"CreateAttachment": {
|
|
7
7
|
"retry": {
|
|
@@ -515,6 +515,33 @@
|
|
|
515
515
|
"natural": true
|
|
516
516
|
}
|
|
517
517
|
},
|
|
518
|
+
"ListCampfireUploads": {
|
|
519
|
+
"retry": {
|
|
520
|
+
"maxAttempts": 3,
|
|
521
|
+
"baseDelayMs": 1000,
|
|
522
|
+
"backoff": "exponential",
|
|
523
|
+
"retryOn": [
|
|
524
|
+
429,
|
|
525
|
+
503
|
|
526
|
+
]
|
|
527
|
+
},
|
|
528
|
+
"pagination": {
|
|
529
|
+
"style": "link",
|
|
530
|
+
"totalCountHeader": "X-Total-Count",
|
|
531
|
+
"maxPageSize": 50
|
|
532
|
+
}
|
|
533
|
+
},
|
|
534
|
+
"CreateCampfireUpload": {
|
|
535
|
+
"retry": {
|
|
536
|
+
"maxAttempts": 3,
|
|
537
|
+
"baseDelayMs": 2000,
|
|
538
|
+
"backoff": "exponential",
|
|
539
|
+
"retryOn": [
|
|
540
|
+
429,
|
|
541
|
+
503
|
|
542
|
+
]
|
|
543
|
+
}
|
|
544
|
+
},
|
|
518
545
|
"ListPingablePeople": {
|
|
519
546
|
"retry": {
|
|
520
547
|
"maxAttempts": 3,
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "uri"
|
|
4
|
+
|
|
3
5
|
module Basecamp
|
|
4
6
|
module Services
|
|
5
7
|
# Service for Campfires operations
|
|
@@ -117,6 +119,27 @@ module Basecamp
|
|
|
117
119
|
nil
|
|
118
120
|
end
|
|
119
121
|
end
|
|
122
|
+
|
|
123
|
+
# List uploaded files in a campfire
|
|
124
|
+
# @param campfire_id [Integer] campfire id ID
|
|
125
|
+
# @return [Enumerator<Hash>] paginated results
|
|
126
|
+
def list_uploads(campfire_id:)
|
|
127
|
+
wrap_paginated(service: "campfires", operation: "list_uploads", is_mutation: false, resource_id: campfire_id) do
|
|
128
|
+
paginate("/chats/#{campfire_id}/uploads.json")
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
# Upload a file to a campfire
|
|
133
|
+
# @param campfire_id [Integer] campfire id ID
|
|
134
|
+
# @param data [String] Binary file data to upload
|
|
135
|
+
# @param content_type [String] MIME type of the file (e.g., "application/pdf", "image/png")
|
|
136
|
+
# @param name [String] Filename for the uploaded file (e.g. "report.pdf").
|
|
137
|
+
# @return [Hash] response data
|
|
138
|
+
def create_upload(campfire_id:, data:, content_type:, name:)
|
|
139
|
+
with_operation(service: "campfires", operation: "create_upload", is_mutation: true, resource_id: campfire_id) do
|
|
140
|
+
http_post_raw("/chats/#{campfire_id}/uploads.json?name=#{URI.encode_www_form_component(name.to_s)}", body: data, content_type: content_type).json
|
|
141
|
+
end
|
|
142
|
+
end
|
|
120
143
|
end
|
|
121
144
|
end
|
|
122
145
|
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-
|
|
4
|
+
# Generated: 2026-03-09T19:39:33Z
|
|
5
5
|
|
|
6
6
|
require "json"
|
|
7
7
|
require "time"
|
|
@@ -136,7 +136,7 @@ module Basecamp
|
|
|
136
136
|
# Campfire
|
|
137
137
|
class Campfire
|
|
138
138
|
include TypeHelpers
|
|
139
|
-
attr_accessor :app_url, :bucket, :created_at, :creator, :id, :inherits_status, :status, :title, :type, :updated_at, :url, :visible_to_clients, :bookmark_url, :lines_url, :position, :subscription_url, :topic
|
|
139
|
+
attr_accessor :app_url, :bucket, :created_at, :creator, :id, :inherits_status, :status, :title, :type, :updated_at, :url, :visible_to_clients, :bookmark_url, :files_url, :lines_url, :position, :subscription_url, :topic
|
|
140
140
|
|
|
141
141
|
# @return [Array<Symbol>]
|
|
142
142
|
def self.required_fields
|
|
@@ -157,6 +157,7 @@ module Basecamp
|
|
|
157
157
|
@url = data["url"]
|
|
158
158
|
@visible_to_clients = parse_boolean(data["visible_to_clients"])
|
|
159
159
|
@bookmark_url = data["bookmark_url"]
|
|
160
|
+
@files_url = data["files_url"]
|
|
160
161
|
@lines_url = data["lines_url"]
|
|
161
162
|
@position = parse_integer(data["position"])
|
|
162
163
|
@subscription_url = data["subscription_url"]
|
|
@@ -178,6 +179,7 @@ module Basecamp
|
|
|
178
179
|
"url" => @url,
|
|
179
180
|
"visible_to_clients" => @visible_to_clients,
|
|
180
181
|
"bookmark_url" => @bookmark_url,
|
|
182
|
+
"files_url" => @files_url,
|
|
181
183
|
"lines_url" => @lines_url,
|
|
182
184
|
"position" => @position,
|
|
183
185
|
"subscription_url" => @subscription_url,
|
|
@@ -193,17 +195,16 @@ module Basecamp
|
|
|
193
195
|
# CampfireLine
|
|
194
196
|
class CampfireLine
|
|
195
197
|
include TypeHelpers
|
|
196
|
-
attr_accessor :app_url, :bucket, :
|
|
198
|
+
attr_accessor :app_url, :bucket, :created_at, :creator, :id, :inherits_status, :parent, :status, :title, :type, :updated_at, :url, :visible_to_clients, :attachments, :bookmark_url, :boosts_count, :boosts_url, :content
|
|
197
199
|
|
|
198
200
|
# @return [Array<Symbol>]
|
|
199
201
|
def self.required_fields
|
|
200
|
-
%i[app_url bucket
|
|
202
|
+
%i[app_url bucket created_at creator id inherits_status parent status title type updated_at url visible_to_clients].freeze
|
|
201
203
|
end
|
|
202
204
|
|
|
203
205
|
def initialize(data = {})
|
|
204
206
|
@app_url = data["app_url"]
|
|
205
207
|
@bucket = parse_type(data["bucket"], "TodoBucket")
|
|
206
|
-
@content = data["content"]
|
|
207
208
|
@created_at = parse_datetime(data["created_at"])
|
|
208
209
|
@creator = parse_type(data["creator"], "Person")
|
|
209
210
|
@id = parse_integer(data["id"])
|
|
@@ -215,16 +216,17 @@ module Basecamp
|
|
|
215
216
|
@updated_at = parse_datetime(data["updated_at"])
|
|
216
217
|
@url = data["url"]
|
|
217
218
|
@visible_to_clients = parse_boolean(data["visible_to_clients"])
|
|
219
|
+
@attachments = parse_array(data["attachments"], "CampfireLineAttachment")
|
|
218
220
|
@bookmark_url = data["bookmark_url"]
|
|
219
221
|
@boosts_count = parse_integer(data["boosts_count"])
|
|
220
222
|
@boosts_url = data["boosts_url"]
|
|
223
|
+
@content = data["content"]
|
|
221
224
|
end
|
|
222
225
|
|
|
223
226
|
def to_h
|
|
224
227
|
{
|
|
225
228
|
"app_url" => @app_url,
|
|
226
229
|
"bucket" => @bucket,
|
|
227
|
-
"content" => @content,
|
|
228
230
|
"created_at" => @created_at,
|
|
229
231
|
"creator" => @creator,
|
|
230
232
|
"id" => @id,
|
|
@@ -236,9 +238,41 @@ module Basecamp
|
|
|
236
238
|
"updated_at" => @updated_at,
|
|
237
239
|
"url" => @url,
|
|
238
240
|
"visible_to_clients" => @visible_to_clients,
|
|
241
|
+
"attachments" => @attachments,
|
|
239
242
|
"bookmark_url" => @bookmark_url,
|
|
240
243
|
"boosts_count" => @boosts_count,
|
|
241
244
|
"boosts_url" => @boosts_url,
|
|
245
|
+
"content" => @content,
|
|
246
|
+
}.compact
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
def to_json(*args)
|
|
250
|
+
to_h.to_json(*args)
|
|
251
|
+
end
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
# CampfireLineAttachment
|
|
255
|
+
class CampfireLineAttachment
|
|
256
|
+
include TypeHelpers
|
|
257
|
+
attr_accessor :byte_size, :content_type, :download_url, :filename, :title, :url
|
|
258
|
+
|
|
259
|
+
def initialize(data = {})
|
|
260
|
+
@byte_size = parse_integer(data["byte_size"])
|
|
261
|
+
@content_type = data["content_type"]
|
|
262
|
+
@download_url = data["download_url"]
|
|
263
|
+
@filename = data["filename"]
|
|
264
|
+
@title = data["title"]
|
|
265
|
+
@url = data["url"]
|
|
266
|
+
end
|
|
267
|
+
|
|
268
|
+
def to_h
|
|
269
|
+
{
|
|
270
|
+
"byte_size" => @byte_size,
|
|
271
|
+
"content_type" => @content_type,
|
|
272
|
+
"download_url" => @download_url,
|
|
273
|
+
"filename" => @filename,
|
|
274
|
+
"title" => @title,
|
|
275
|
+
"url" => @url,
|
|
242
276
|
}.compact
|
|
243
277
|
end
|
|
244
278
|
|
data/lib/basecamp/http.rb
CHANGED
|
@@ -244,7 +244,7 @@ module Basecamp
|
|
|
244
244
|
status: response.status,
|
|
245
245
|
headers: response.headers
|
|
246
246
|
)
|
|
247
|
-
rescue Faraday::ClientError => e
|
|
247
|
+
rescue Faraday::ServerError, Faraday::ClientError => e
|
|
248
248
|
duration = Process.clock_gettime(Process::CLOCK_MONOTONIC) - start_time
|
|
249
249
|
error = handle_error(e)
|
|
250
250
|
result = RequestResult.new(
|
|
@@ -299,7 +299,7 @@ module Basecamp
|
|
|
299
299
|
status: response.status,
|
|
300
300
|
headers: response.headers
|
|
301
301
|
)
|
|
302
|
-
rescue Faraday::ClientError => e
|
|
302
|
+
rescue Faraday::ServerError, Faraday::ClientError => e
|
|
303
303
|
duration = Process.clock_gettime(Process::CLOCK_MONOTONIC) - start_time
|
|
304
304
|
error = handle_error(e)
|
|
305
305
|
result = RequestResult.new(
|
|
@@ -325,12 +325,12 @@ module Basecamp
|
|
|
325
325
|
headers = error.response&.dig(:headers) || {}
|
|
326
326
|
|
|
327
327
|
retry_after = parse_retry_after(headers["Retry-After"] || headers["retry-after"])
|
|
328
|
+
request_id = headers["X-Request-Id"] || headers["x-request-id"]
|
|
328
329
|
|
|
329
|
-
case status
|
|
330
|
+
err = case status
|
|
330
331
|
when 401
|
|
331
332
|
# Try token refresh; flag for caller to retry
|
|
332
333
|
@token_refreshed = @token_provider&.refreshable? && @token_provider.refresh
|
|
333
|
-
|
|
334
334
|
Basecamp::AuthError.new("Authentication failed")
|
|
335
335
|
when 403
|
|
336
336
|
Basecamp::ForbiddenError.new("Access denied")
|
|
@@ -342,13 +342,16 @@ module Basecamp
|
|
|
342
342
|
message = Security.truncate(Basecamp.parse_error_message(body) || "Validation failed")
|
|
343
343
|
Basecamp::ValidationError.new(message, http_status: status)
|
|
344
344
|
when 500
|
|
345
|
-
Basecamp::APIError.new("Server error (500)", http_status: 500)
|
|
345
|
+
Basecamp::APIError.new("Server error (500)", http_status: 500, retryable: true)
|
|
346
346
|
when 502, 503, 504
|
|
347
347
|
Basecamp::APIError.new("Gateway error (#{status})", http_status: status, retryable: true)
|
|
348
348
|
else
|
|
349
349
|
message = Security.truncate(Basecamp.parse_error_message(body) || "Request failed (HTTP #{status})")
|
|
350
350
|
Basecamp::APIError.from_status(status || 0, message)
|
|
351
351
|
end
|
|
352
|
+
|
|
353
|
+
err.instance_variable_set(:@request_id, request_id) if request_id
|
|
354
|
+
err
|
|
352
355
|
end
|
|
353
356
|
|
|
354
357
|
def build_url(path)
|
data/lib/basecamp/version.rb
CHANGED
|
@@ -45,6 +45,7 @@ class ServiceGenerator
|
|
|
45
45
|
GetCampfire ListCampfires
|
|
46
46
|
ListChatbots CreateChatbot GetChatbot UpdateChatbot DeleteChatbot
|
|
47
47
|
ListCampfireLines CreateCampfireLine GetCampfireLine DeleteCampfireLine
|
|
48
|
+
ListCampfireUploads CreateCampfireUpload
|
|
48
49
|
]
|
|
49
50
|
},
|
|
50
51
|
'Card Tables' => {
|
|
@@ -188,6 +189,8 @@ class ServiceGenerator
|
|
|
188
189
|
'CreateCampfireLine' => 'create_line',
|
|
189
190
|
'GetCampfireLine' => 'get_line',
|
|
190
191
|
'DeleteCampfireLine' => 'delete_line',
|
|
192
|
+
'ListCampfireUploads' => 'list_uploads',
|
|
193
|
+
'CreateCampfireUpload' => 'create_upload',
|
|
191
194
|
# Forwards - use specific names to avoid conflicts between forwards, replies, and inbox
|
|
192
195
|
'GetForward' => 'get',
|
|
193
196
|
'ListForwards' => 'list',
|
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.2.
|
|
4
|
+
version: 0.2.3
|
|
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-
|
|
11
|
+
date: 2026-03-09 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: faraday
|