basecamp-sdk 0.4.0 → 0.6.0
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/README.md +2 -2
- data/lib/basecamp/ambiguous_error.rb +23 -0
- data/lib/basecamp/api_error.rb +27 -0
- data/lib/basecamp/auth_error.rb +16 -0
- data/lib/basecamp/auth_strategy.rb +0 -18
- data/lib/basecamp/bearer_auth.rb +21 -0
- data/lib/basecamp/client.rb +126 -0
- data/lib/basecamp/download_result.rb +10 -0
- data/lib/basecamp/error.rb +86 -0
- data/lib/basecamp/error_code.rb +16 -0
- data/lib/basecamp/exit_code.rb +17 -0
- data/lib/basecamp/forbidden_error.rb +20 -0
- data/lib/basecamp/generated/metadata.json +12 -1
- data/lib/basecamp/{services → generated/services}/authorization_service.rb +1 -1
- data/lib/basecamp/generated/services/automation_service.rb +19 -0
- data/lib/basecamp/{services → generated/services}/base_service.rb +0 -1
- data/lib/basecamp/generated/services/card_steps_service.rb +9 -0
- data/lib/basecamp/generated/services/messages_service.rb +5 -2
- data/lib/basecamp/generated/services/search_service.rb +1 -1
- data/lib/basecamp/generated/services/tools_service.rb +3 -2
- data/lib/basecamp/generated/types.rb +3 -3
- data/lib/basecamp/http.rb +22 -13
- data/lib/basecamp/network_error.rb +16 -0
- data/lib/basecamp/not_found_error.rb +20 -0
- data/lib/basecamp/oauth/config.rb +30 -0
- data/lib/basecamp/oauth/discovery.rb +9 -41
- data/lib/basecamp/oauth/exchange.rb +20 -114
- data/lib/basecamp/oauth/exchange_request.rb +36 -0
- data/lib/basecamp/oauth/{errors.rb → oauth_error.rb} +1 -1
- data/lib/basecamp/oauth/refresh_request.rb +30 -0
- data/lib/basecamp/oauth/token.rb +52 -0
- data/lib/basecamp/oauth.rb +40 -8
- data/lib/basecamp/operation_info.rb +0 -7
- data/lib/basecamp/operation_result.rb +10 -0
- data/lib/basecamp/rate_limit_error.rb +19 -0
- data/lib/basecamp/security.rb +1 -1
- data/lib/basecamp/usage_error.rb +10 -0
- data/lib/basecamp/validation_error.rb +15 -0
- data/lib/basecamp/version.rb +1 -1
- data/lib/basecamp/webhooks/rack_middleware.rb +0 -2
- data/lib/basecamp/webhooks/receiver.rb +0 -4
- data/lib/basecamp/webhooks/verification_error.rb +7 -0
- data/lib/basecamp.rb +62 -22
- data/scripts/generate-services.rb +3 -3
- metadata +26 -43
- data/lib/basecamp/errors.rb +0 -294
- data/lib/basecamp/oauth/types.rb +0 -133
- data/lib/basecamp/services/attachments_service.rb +0 -33
- data/lib/basecamp/services/campfires_service.rb +0 -141
- data/lib/basecamp/services/card_columns_service.rb +0 -106
- data/lib/basecamp/services/card_steps_service.rb +0 -86
- data/lib/basecamp/services/card_tables_service.rb +0 -23
- data/lib/basecamp/services/cards_service.rb +0 -93
- data/lib/basecamp/services/checkins_service.rb +0 -127
- data/lib/basecamp/services/client_approvals_service.rb +0 -33
- data/lib/basecamp/services/client_correspondences_service.rb +0 -33
- data/lib/basecamp/services/client_replies_service.rb +0 -35
- data/lib/basecamp/services/comments_service.rb +0 -63
- data/lib/basecamp/services/documents_service.rb +0 -74
- data/lib/basecamp/services/events_service.rb +0 -27
- data/lib/basecamp/services/forwards_service.rb +0 -80
- data/lib/basecamp/services/lineup_service.rb +0 -67
- data/lib/basecamp/services/message_boards_service.rb +0 -24
- data/lib/basecamp/services/message_types_service.rb +0 -79
- data/lib/basecamp/services/messages_service.rb +0 -133
- data/lib/basecamp/services/people_service.rb +0 -73
- data/lib/basecamp/services/projects_service.rb +0 -67
- data/lib/basecamp/services/recordings_service.rb +0 -127
- data/lib/basecamp/services/reports_service.rb +0 -80
- data/lib/basecamp/services/schedules_service.rb +0 -156
- data/lib/basecamp/services/search_service.rb +0 -36
- data/lib/basecamp/services/subscriptions_service.rb +0 -67
- data/lib/basecamp/services/templates_service.rb +0 -96
- data/lib/basecamp/services/timeline_service.rb +0 -62
- data/lib/basecamp/services/timesheet_service.rb +0 -68
- data/lib/basecamp/services/todolist_groups_service.rb +0 -100
- data/lib/basecamp/services/todolists_service.rb +0 -104
- data/lib/basecamp/services/todos_service.rb +0 -156
- data/lib/basecamp/services/todosets_service.rb +0 -23
- data/lib/basecamp/services/tools_service.rb +0 -89
- data/lib/basecamp/services/uploads_service.rb +0 -84
- data/lib/basecamp/services/vaults_service.rb +0 -84
- data/lib/basecamp/services/webhooks_service.rb +0 -88
data/lib/basecamp/oauth.rb
CHANGED
|
@@ -1,10 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative "oauth/errors"
|
|
4
|
-
require_relative "oauth/types"
|
|
5
|
-
require_relative "oauth/discovery"
|
|
6
|
-
require_relative "oauth/exchange"
|
|
7
|
-
|
|
8
3
|
module Basecamp
|
|
9
4
|
# OAuth 2 module for Basecamp SDK.
|
|
10
5
|
#
|
|
@@ -49,8 +44,45 @@ module Basecamp
|
|
|
49
44
|
#
|
|
50
45
|
# @see https://github.com/basecamp/api/blob/master/sections/authentication.md
|
|
51
46
|
module Oauth
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
47
|
+
LAUNCHPAD_BASE_URL = "https://launchpad.37signals.com"
|
|
48
|
+
|
|
49
|
+
def self.discover(base_url, timeout: 10)
|
|
50
|
+
Discovery.new(timeout: timeout).discover(base_url)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def self.discover_launchpad(timeout: 10)
|
|
54
|
+
discover(LAUNCHPAD_BASE_URL, timeout: timeout)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def self.exchange_code(
|
|
58
|
+
token_endpoint:, code:, redirect_uri:, client_id:,
|
|
59
|
+
client_secret: nil, code_verifier: nil,
|
|
60
|
+
use_legacy_format: false, timeout: 30
|
|
61
|
+
)
|
|
62
|
+
request = ExchangeRequest.new(
|
|
63
|
+
token_endpoint: token_endpoint, code: code,
|
|
64
|
+
redirect_uri: redirect_uri, client_id: client_id,
|
|
65
|
+
client_secret: client_secret, code_verifier: code_verifier,
|
|
66
|
+
use_legacy_format: use_legacy_format
|
|
67
|
+
)
|
|
68
|
+
Exchange.new(timeout: timeout).exchange(request)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def self.refresh_token(
|
|
72
|
+
token_endpoint:, refresh_token:,
|
|
73
|
+
client_id: nil, client_secret: nil,
|
|
74
|
+
use_legacy_format: false, timeout: 30
|
|
75
|
+
)
|
|
76
|
+
request = RefreshRequest.new(
|
|
77
|
+
token_endpoint: token_endpoint, refresh_token: refresh_token,
|
|
78
|
+
client_id: client_id, client_secret: client_secret,
|
|
79
|
+
use_legacy_format: use_legacy_format
|
|
80
|
+
)
|
|
81
|
+
Exchange.new(timeout: timeout).refresh(request)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def self.token_expired?(token, buffer_seconds = 60)
|
|
85
|
+
token.expired?(buffer_seconds)
|
|
86
|
+
end
|
|
55
87
|
end
|
|
56
88
|
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Basecamp
|
|
4
|
+
# Raised when rate limited (429).
|
|
5
|
+
class RateLimitError < Error
|
|
6
|
+
def initialize(retry_after: nil, cause: nil)
|
|
7
|
+
hint = retry_after ? "Try again in #{retry_after} seconds" : "Please slow down requests"
|
|
8
|
+
super(
|
|
9
|
+
code: ErrorCode::RATE_LIMIT,
|
|
10
|
+
message: "Rate limit exceeded",
|
|
11
|
+
hint: hint,
|
|
12
|
+
http_status: 429,
|
|
13
|
+
retryable: true,
|
|
14
|
+
retry_after: retry_after,
|
|
15
|
+
cause: cause
|
|
16
|
+
)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
data/lib/basecamp/security.rb
CHANGED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Basecamp
|
|
4
|
+
# Raised when there's a usage error (invalid arguments, missing config).
|
|
5
|
+
class UsageError < Error
|
|
6
|
+
def initialize(message, hint: nil)
|
|
7
|
+
super(code: ErrorCode::USAGE, message: message, hint: hint)
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Basecamp
|
|
4
|
+
# Raised for validation errors (400, 422).
|
|
5
|
+
class ValidationError < Error
|
|
6
|
+
def initialize(message, hint: nil, http_status: 400)
|
|
7
|
+
super(
|
|
8
|
+
code: ErrorCode::VALIDATION,
|
|
9
|
+
message: message,
|
|
10
|
+
hint: hint,
|
|
11
|
+
http_status: http_status
|
|
12
|
+
)
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
data/lib/basecamp/version.rb
CHANGED
|
@@ -1,13 +1,9 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "json"
|
|
4
|
-
require_relative "event"
|
|
5
|
-
require_relative "verify"
|
|
6
4
|
|
|
7
5
|
module Basecamp
|
|
8
6
|
module Webhooks
|
|
9
|
-
class VerificationError < StandardError; end
|
|
10
|
-
|
|
11
7
|
# Receives and routes webhook events from Basecamp.
|
|
12
8
|
# Framework-agnostic: works with raw body strings and a header accessor.
|
|
13
9
|
class Receiver
|
data/lib/basecamp.rb
CHANGED
|
@@ -2,32 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
require "zeitwerk"
|
|
4
4
|
|
|
5
|
-
# Set up Zeitwerk loader
|
|
6
5
|
loader = Zeitwerk::Loader.for_gem
|
|
7
|
-
# No custom inflections - use standard Ruby camelcase (Http, Oauth, etc.)
|
|
8
|
-
|
|
9
|
-
# Ignore hand-written services - we use generated services instead (spec-conformant)
|
|
10
|
-
# EXCEPT: base_service.rb (infrastructure) and authorization_service.rb (OAuth, not in spec)
|
|
11
|
-
loader.ignore("#{__dir__}/basecamp/services")
|
|
12
|
-
|
|
13
|
-
# Collapse the generated directory so Basecamp::Generated::Services becomes Basecamp::Services
|
|
14
6
|
loader.collapse("#{__dir__}/basecamp/generated")
|
|
15
|
-
|
|
16
|
-
# Ignore errors.rb - it defines multiple classes, loaded explicitly below
|
|
17
|
-
loader.ignore("#{__dir__}/basecamp/errors.rb")
|
|
18
|
-
# Ignore auth_strategy.rb - defines both AuthStrategy and BearerAuth
|
|
19
|
-
loader.ignore("#{__dir__}/basecamp/auth_strategy.rb")
|
|
20
|
-
# Ignore operation_info.rb - defines both OperationInfo and OperationResult
|
|
21
|
-
loader.ignore("#{__dir__}/basecamp/operation_info.rb")
|
|
22
7
|
loader.setup
|
|
23
8
|
|
|
24
|
-
# Load infrastructure that generated services depend on
|
|
25
|
-
require_relative "basecamp/errors"
|
|
26
|
-
require_relative "basecamp/auth_strategy"
|
|
27
|
-
require_relative "basecamp/operation_info"
|
|
28
|
-
require_relative "basecamp/services/base_service"
|
|
29
|
-
require_relative "basecamp/services/authorization_service"
|
|
30
|
-
|
|
31
9
|
# Load generated types if available
|
|
32
10
|
begin
|
|
33
11
|
require_relative "basecamp/generated/types"
|
|
@@ -104,4 +82,66 @@ module Basecamp
|
|
|
104
82
|
|
|
105
83
|
account_id ? client.for_account(account_id) : client
|
|
106
84
|
end
|
|
85
|
+
|
|
86
|
+
# Maps an HTTP response to the appropriate error class.
|
|
87
|
+
#
|
|
88
|
+
# @param status [Integer] HTTP status code
|
|
89
|
+
# @param body [String, nil] response body (will attempt JSON parse)
|
|
90
|
+
# @param retry_after [Integer, nil] Retry-After header value
|
|
91
|
+
# @return [Error]
|
|
92
|
+
def self.error_from_response(status, body = nil, retry_after: nil)
|
|
93
|
+
message = parse_error_message(body) || "Request failed"
|
|
94
|
+
|
|
95
|
+
case status
|
|
96
|
+
when 400, 422
|
|
97
|
+
ValidationError.new(message, http_status: status)
|
|
98
|
+
when 401
|
|
99
|
+
AuthError.new(message)
|
|
100
|
+
when 403
|
|
101
|
+
ForbiddenError.new(message)
|
|
102
|
+
when 404
|
|
103
|
+
NotFoundError.new(message: message)
|
|
104
|
+
when 429
|
|
105
|
+
RateLimitError.new(retry_after: retry_after)
|
|
106
|
+
when 500
|
|
107
|
+
ApiError.new("Server error (500)", http_status: 500, retryable: true)
|
|
108
|
+
when 502, 503, 504
|
|
109
|
+
ApiError.new("Gateway error (#{status})", http_status: status, retryable: true)
|
|
110
|
+
else
|
|
111
|
+
ApiError.from_status(status, message)
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# Extracts a filename from the last path segment of a URL.
|
|
116
|
+
# Falls back to "download" if the URL is unparseable or has no path segments.
|
|
117
|
+
def self.filename_from_url(raw_url)
|
|
118
|
+
uri = URI.parse(raw_url)
|
|
119
|
+
path = uri.path
|
|
120
|
+
return "download" if path.nil? || path.empty? || path == "/" || path.end_with?("/")
|
|
121
|
+
|
|
122
|
+
segments = path.split("/").reject(&:empty?)
|
|
123
|
+
return "download" if segments.empty?
|
|
124
|
+
|
|
125
|
+
last = segments.last
|
|
126
|
+
return "download" if last.nil? || last.empty? || last == "." || last == "/"
|
|
127
|
+
|
|
128
|
+
URI::RFC2396_PARSER.unescape(last)
|
|
129
|
+
rescue URI::InvalidURIError
|
|
130
|
+
"download"
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
# Parses error message from response body.
|
|
134
|
+
# @param body [String, nil]
|
|
135
|
+
# @return [String, nil]
|
|
136
|
+
def self.parse_error_message(body)
|
|
137
|
+
return nil if body.nil? || body.empty?
|
|
138
|
+
|
|
139
|
+
Security.check_body_size!(body, Security::MAX_ERROR_BODY_BYTES, "Error")
|
|
140
|
+
|
|
141
|
+
data = JSON.parse(body)
|
|
142
|
+
msg = data["error"] || data["message"]
|
|
143
|
+
msg ? Security.truncate(msg) : nil
|
|
144
|
+
rescue JSON::ParserError, ApiError
|
|
145
|
+
nil
|
|
146
|
+
end
|
|
107
147
|
end
|
|
@@ -57,7 +57,7 @@ class ServiceGenerator
|
|
|
57
57
|
CreateCardColumn MoveCardColumn
|
|
58
58
|
],
|
|
59
59
|
'CardSteps' => %w[
|
|
60
|
-
CreateCardStep UpdateCardStep SetCardStepCompletion
|
|
60
|
+
GetCardStep CreateCardStep UpdateCardStep SetCardStepCompletion
|
|
61
61
|
RepositionCardStep
|
|
62
62
|
]
|
|
63
63
|
},
|
|
@@ -559,7 +559,7 @@ class ServiceGenerator
|
|
|
559
559
|
ruby_name = to_snake_case(b[:name])
|
|
560
560
|
type = b[:type] || 'Object'
|
|
561
561
|
type = "#{type}, nil" unless b[:required]
|
|
562
|
-
desc = b[:description] || ruby_name.gsub('_', ' ')
|
|
562
|
+
desc = (b[:description] || ruby_name.gsub('_', ' ')).gsub("\n", "\n # ")
|
|
563
563
|
format_hint = b[:format_hint] ? " (#{b[:format_hint]})" : ''
|
|
564
564
|
lines << " # @param #{ruby_name} [#{type}] #{desc}#{format_hint}"
|
|
565
565
|
end
|
|
@@ -570,7 +570,7 @@ class ServiceGenerator
|
|
|
570
570
|
ruby_name = to_snake_case(q[:name])
|
|
571
571
|
type = q[:type] || 'String'
|
|
572
572
|
type = "#{type}, nil" unless q[:required]
|
|
573
|
-
desc = q[:description] || ruby_name.gsub('_', ' ')
|
|
573
|
+
desc = (q[:description] || ruby_name.gsub('_', ' ')).gsub("\n", "\n # ")
|
|
574
574
|
lines << " # @param #{ruby_name} [#{type}] #{desc}"
|
|
575
575
|
end
|
|
576
576
|
|
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.
|
|
4
|
+
version: 0.6.0
|
|
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-16 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: faraday
|
|
@@ -178,13 +178,24 @@ files:
|
|
|
178
178
|
- Rakefile
|
|
179
179
|
- basecamp-sdk.gemspec
|
|
180
180
|
- lib/basecamp.rb
|
|
181
|
+
- lib/basecamp/ambiguous_error.rb
|
|
182
|
+
- lib/basecamp/api_error.rb
|
|
183
|
+
- lib/basecamp/auth_error.rb
|
|
181
184
|
- lib/basecamp/auth_strategy.rb
|
|
185
|
+
- lib/basecamp/bearer_auth.rb
|
|
182
186
|
- lib/basecamp/chain_hooks.rb
|
|
183
187
|
- lib/basecamp/client.rb
|
|
184
188
|
- lib/basecamp/config.rb
|
|
185
|
-
- lib/basecamp/
|
|
189
|
+
- lib/basecamp/download_result.rb
|
|
190
|
+
- lib/basecamp/error.rb
|
|
191
|
+
- lib/basecamp/error_code.rb
|
|
192
|
+
- lib/basecamp/exit_code.rb
|
|
193
|
+
- lib/basecamp/forbidden_error.rb
|
|
186
194
|
- lib/basecamp/generated/metadata.json
|
|
187
195
|
- lib/basecamp/generated/services/attachments_service.rb
|
|
196
|
+
- lib/basecamp/generated/services/authorization_service.rb
|
|
197
|
+
- lib/basecamp/generated/services/automation_service.rb
|
|
198
|
+
- lib/basecamp/generated/services/base_service.rb
|
|
188
199
|
- lib/basecamp/generated/services/boosts_service.rb
|
|
189
200
|
- lib/basecamp/generated/services/campfires_service.rb
|
|
190
201
|
- lib/basecamp/generated/services/card_columns_service.rb
|
|
@@ -226,62 +237,34 @@ files:
|
|
|
226
237
|
- lib/basecamp/hooks.rb
|
|
227
238
|
- lib/basecamp/http.rb
|
|
228
239
|
- lib/basecamp/logger_hooks.rb
|
|
240
|
+
- lib/basecamp/network_error.rb
|
|
229
241
|
- lib/basecamp/noop_hooks.rb
|
|
242
|
+
- lib/basecamp/not_found_error.rb
|
|
230
243
|
- lib/basecamp/oauth.rb
|
|
244
|
+
- lib/basecamp/oauth/config.rb
|
|
231
245
|
- lib/basecamp/oauth/discovery.rb
|
|
232
|
-
- lib/basecamp/oauth/errors.rb
|
|
233
246
|
- lib/basecamp/oauth/exchange.rb
|
|
247
|
+
- lib/basecamp/oauth/exchange_request.rb
|
|
248
|
+
- lib/basecamp/oauth/oauth_error.rb
|
|
234
249
|
- lib/basecamp/oauth/pkce.rb
|
|
235
|
-
- lib/basecamp/oauth/
|
|
250
|
+
- lib/basecamp/oauth/refresh_request.rb
|
|
251
|
+
- lib/basecamp/oauth/token.rb
|
|
236
252
|
- lib/basecamp/oauth_token_provider.rb
|
|
237
253
|
- lib/basecamp/operation_info.rb
|
|
254
|
+
- lib/basecamp/operation_result.rb
|
|
255
|
+
- lib/basecamp/rate_limit_error.rb
|
|
238
256
|
- lib/basecamp/request_info.rb
|
|
239
257
|
- lib/basecamp/request_result.rb
|
|
240
258
|
- lib/basecamp/security.rb
|
|
241
|
-
- lib/basecamp/services/attachments_service.rb
|
|
242
|
-
- lib/basecamp/services/authorization_service.rb
|
|
243
|
-
- lib/basecamp/services/base_service.rb
|
|
244
|
-
- lib/basecamp/services/campfires_service.rb
|
|
245
|
-
- lib/basecamp/services/card_columns_service.rb
|
|
246
|
-
- lib/basecamp/services/card_steps_service.rb
|
|
247
|
-
- lib/basecamp/services/card_tables_service.rb
|
|
248
|
-
- lib/basecamp/services/cards_service.rb
|
|
249
|
-
- lib/basecamp/services/checkins_service.rb
|
|
250
|
-
- lib/basecamp/services/client_approvals_service.rb
|
|
251
|
-
- lib/basecamp/services/client_correspondences_service.rb
|
|
252
|
-
- lib/basecamp/services/client_replies_service.rb
|
|
253
|
-
- lib/basecamp/services/comments_service.rb
|
|
254
|
-
- lib/basecamp/services/documents_service.rb
|
|
255
|
-
- lib/basecamp/services/events_service.rb
|
|
256
|
-
- lib/basecamp/services/forwards_service.rb
|
|
257
|
-
- lib/basecamp/services/lineup_service.rb
|
|
258
|
-
- lib/basecamp/services/message_boards_service.rb
|
|
259
|
-
- lib/basecamp/services/message_types_service.rb
|
|
260
|
-
- lib/basecamp/services/messages_service.rb
|
|
261
|
-
- lib/basecamp/services/people_service.rb
|
|
262
|
-
- lib/basecamp/services/projects_service.rb
|
|
263
|
-
- lib/basecamp/services/recordings_service.rb
|
|
264
|
-
- lib/basecamp/services/reports_service.rb
|
|
265
|
-
- lib/basecamp/services/schedules_service.rb
|
|
266
|
-
- lib/basecamp/services/search_service.rb
|
|
267
|
-
- lib/basecamp/services/subscriptions_service.rb
|
|
268
|
-
- lib/basecamp/services/templates_service.rb
|
|
269
|
-
- lib/basecamp/services/timeline_service.rb
|
|
270
|
-
- lib/basecamp/services/timesheet_service.rb
|
|
271
|
-
- lib/basecamp/services/todolist_groups_service.rb
|
|
272
|
-
- lib/basecamp/services/todolists_service.rb
|
|
273
|
-
- lib/basecamp/services/todos_service.rb
|
|
274
|
-
- lib/basecamp/services/todosets_service.rb
|
|
275
|
-
- lib/basecamp/services/tools_service.rb
|
|
276
|
-
- lib/basecamp/services/uploads_service.rb
|
|
277
|
-
- lib/basecamp/services/vaults_service.rb
|
|
278
|
-
- lib/basecamp/services/webhooks_service.rb
|
|
279
259
|
- lib/basecamp/static_token_provider.rb
|
|
280
260
|
- lib/basecamp/token_provider.rb
|
|
261
|
+
- lib/basecamp/usage_error.rb
|
|
262
|
+
- lib/basecamp/validation_error.rb
|
|
281
263
|
- lib/basecamp/version.rb
|
|
282
264
|
- lib/basecamp/webhooks/event.rb
|
|
283
265
|
- lib/basecamp/webhooks/rack_middleware.rb
|
|
284
266
|
- lib/basecamp/webhooks/receiver.rb
|
|
267
|
+
- lib/basecamp/webhooks/verification_error.rb
|
|
285
268
|
- lib/basecamp/webhooks/verify.rb
|
|
286
269
|
- scripts/generate-metadata.rb
|
|
287
270
|
- scripts/generate-services.rb
|