basecamp-sdk 0.8.0 → 0.10.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 -1
- data/lib/basecamp/client.rb +10 -0
- data/lib/basecamp/generated/metadata.json +343 -12
- data/lib/basecamp/generated/services/automation_service.rb +1 -1
- data/lib/basecamp/generated/services/base_service.rb +13 -0
- data/lib/basecamp/generated/services/campfires_service.rb +2 -2
- data/lib/basecamp/generated/services/card_columns_service.rb +3 -3
- data/lib/basecamp/generated/services/cards_service.rb +2 -2
- data/lib/basecamp/generated/services/checkins_service.rb +5 -4
- data/lib/basecamp/generated/services/client_approvals_service.rb +1 -1
- data/lib/basecamp/generated/services/client_correspondences_service.rb +1 -1
- data/lib/basecamp/generated/services/documents_service.rb +3 -2
- data/lib/basecamp/generated/services/everything_service.rb +179 -0
- data/lib/basecamp/generated/services/forwards_service.rb +1 -1
- data/lib/basecamp/generated/services/gauges_service.rb +4 -4
- data/lib/basecamp/generated/services/message_types_service.rb +20 -15
- data/lib/basecamp/generated/services/messages_service.rb +4 -3
- data/lib/basecamp/generated/services/my_assignments_service.rb +3 -3
- data/lib/basecamp/generated/services/my_notifications_service.rb +16 -2
- data/lib/basecamp/generated/services/people_service.rb +3 -3
- data/lib/basecamp/generated/services/projects_service.rb +2 -2
- data/lib/basecamp/generated/services/recordings_service.rb +2 -2
- data/lib/basecamp/generated/services/reports_service.rb +2 -2
- data/lib/basecamp/generated/services/schedules_service.rb +14 -5
- data/lib/basecamp/generated/services/search_service.rb +14 -3
- data/lib/basecamp/generated/services/templates_service.rb +4 -5
- data/lib/basecamp/generated/services/timesheets_service.rb +4 -4
- data/lib/basecamp/generated/services/todolists_service.rb +15 -3
- data/lib/basecamp/generated/services/todos_service.rb +1 -1
- data/lib/basecamp/generated/services/tools_service.rb +4 -3
- data/lib/basecamp/generated/services/uploads_service.rb +3 -2
- data/lib/basecamp/generated/services/webhooks_service.rb +2 -2
- data/lib/basecamp/generated/services/wormholes_service.rb +44 -0
- data/lib/basecamp/generated/types.rb +656 -71
- data/lib/basecamp/http.rb +2 -1
- data/lib/basecamp/services/cards_extensions.rb +67 -0
- data/lib/basecamp/version.rb +2 -2
- data/lib/basecamp.rb +5 -0
- data/scripts/generate-services.rb +39 -10
- data/scripts/generate-types.rb +60 -1
- metadata +5 -2
data/lib/basecamp/http.rb
CHANGED
|
@@ -377,7 +377,8 @@ module Basecamp
|
|
|
377
377
|
end
|
|
378
378
|
end
|
|
379
379
|
|
|
380
|
-
|
|
380
|
+
noun = @config.max_retries == 1 ? "attempt" : "attempts"
|
|
381
|
+
raise last_error || Basecamp::ApiError.new("Request failed after #{@config.max_retries} #{noun}")
|
|
381
382
|
end
|
|
382
383
|
|
|
383
384
|
def single_request(method, url, params:, body:, attempt:, retry_count: 0, allow_cross_origin: false)
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Basecamp
|
|
4
|
+
module Services
|
|
5
|
+
# Merge-safe +update+ for cards, prepended onto the generated
|
|
6
|
+
# {CardsService} (see the +on_load+ hook in +basecamp.rb+).
|
|
7
|
+
#
|
|
8
|
+
# BC3 builds the card's update params as
|
|
9
|
+
# <tt>{ due_on: nil }.merge(card_params)</tt>
|
|
10
|
+
# (+kanban/cards_controller.rb+), so *any* update whose body omits +due_on+
|
|
11
|
+
# erases the card's due date. A sparse PUT — the natural thing to write —
|
|
12
|
+
# is therefore destructive on the raw endpoint, which remains available as
|
|
13
|
+
# {#update_verbatim}.
|
|
14
|
+
#
|
|
15
|
+
# +update+ composes the public +get+ and +update_verbatim+ methods, so
|
|
16
|
+
# hooks observe the two wire operations, not a synthetic composite.
|
|
17
|
+
#
|
|
18
|
+
# Not atomic: a concurrent due-date change landing between the GET and the
|
|
19
|
+
# PUT is overwritten with the value this call read. The window is one
|
|
20
|
+
# round-trip.
|
|
21
|
+
module CardsExtensions
|
|
22
|
+
# Updates a card without disturbing fields the caller did not mention.
|
|
23
|
+
#
|
|
24
|
+
# +due_on+ is tri-state, which is what makes this safe:
|
|
25
|
+
#
|
|
26
|
+
# * +nil+ (omitted) — the current due date is fetched and resent
|
|
27
|
+
# * <tt>""</tt> — the due date is cleared
|
|
28
|
+
# * a date — the due date is set
|
|
29
|
+
#
|
|
30
|
+
# The extra GET is only paid for in the +nil+ case, the one where the
|
|
31
|
+
# API would otherwise destroy something.
|
|
32
|
+
#
|
|
33
|
+
# Assignees are never resent on the caller's behalf: BC3 filters incoming
|
|
34
|
+
# IDs through +reachable_people+, so echoing back an id belonging to
|
|
35
|
+
# someone who has since lost board access would silently unassign them.
|
|
36
|
+
#
|
|
37
|
+
# @param card_id [Integer] card id
|
|
38
|
+
# @param title [String, nil] new title (nil = keep current)
|
|
39
|
+
# @param content [String, nil] new content (nil = keep current, "" clears)
|
|
40
|
+
# @param due_on [String, nil] new due date (nil = keep current, "" clears)
|
|
41
|
+
# @param assignee_ids [Array, nil] new assignees (nil = keep current, [] clears)
|
|
42
|
+
# @return [Hash] the updated card
|
|
43
|
+
def update(card_id:, title: nil, content: nil, due_on: nil, assignee_ids: nil)
|
|
44
|
+
resolved_due_on =
|
|
45
|
+
if due_on.nil?
|
|
46
|
+
get(card_id: card_id)["due_on"]
|
|
47
|
+
elsif due_on.to_s.empty?
|
|
48
|
+
# Clearing is encoded by OMITTING due_on — compact_params strips the
|
|
49
|
+
# nil below, and BC3 nils an omitted due date. Sending an explicit
|
|
50
|
+
# null would violate body compaction (SPEC §18), and sending ""
|
|
51
|
+
# risks a date-format error.
|
|
52
|
+
nil
|
|
53
|
+
else
|
|
54
|
+
due_on
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
update_verbatim(
|
|
58
|
+
card_id: card_id,
|
|
59
|
+
title: title,
|
|
60
|
+
content: content,
|
|
61
|
+
due_on: resolved_due_on,
|
|
62
|
+
assignee_ids: assignee_ids
|
|
63
|
+
)
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
data/lib/basecamp/version.rb
CHANGED
data/lib/basecamp.rb
CHANGED
|
@@ -10,6 +10,11 @@ loader.collapse("#{__dir__}/basecamp/generated")
|
|
|
10
10
|
loader.on_load("Basecamp::Services::TodosService") do |klass, _abspath|
|
|
11
11
|
klass.prepend(Basecamp::Services::TodosExtensions)
|
|
12
12
|
end
|
|
13
|
+
# Same shape for cards: the generated class owns the constant and the
|
|
14
|
+
# merge-safe update is prepended over the generated update_verbatim.
|
|
15
|
+
loader.on_load("Basecamp::Services::CardsService") do |klass, _abspath|
|
|
16
|
+
klass.prepend(Basecamp::Services::CardsExtensions)
|
|
17
|
+
end
|
|
13
18
|
loader.setup
|
|
14
19
|
|
|
15
20
|
# Load generated types if available
|
|
@@ -60,7 +60,8 @@ class ServiceGenerator
|
|
|
60
60
|
'CardSteps' => %w[
|
|
61
61
|
GetCardStep CreateCardStep UpdateCardStep SetCardStepCompletion
|
|
62
62
|
RepositionCardStep
|
|
63
|
-
]
|
|
63
|
+
],
|
|
64
|
+
'Wormholes' => %w[CreateWormhole UpdateWormhole DeleteWormhole]
|
|
64
65
|
},
|
|
65
66
|
'Files' => {
|
|
66
67
|
'Attachments' => %w[CreateAttachment],
|
|
@@ -116,7 +117,7 @@ class ServiceGenerator
|
|
|
116
117
|
},
|
|
117
118
|
'Todos' => {
|
|
118
119
|
'Todos' => %w[ListTodos CreateTodo GetTodo ReplaceTodo CompleteTodo UncompleteTodo TrashTodo],
|
|
119
|
-
'Todolists' => %w[GetTodolistOrGroup UpdateTodolistOrGroup ListTodolists CreateTodolist],
|
|
120
|
+
'Todolists' => %w[GetTodolistOrGroup UpdateTodolistOrGroup ListTodolists CreateTodolist RepositionTodolist],
|
|
120
121
|
'Todosets' => %w[GetTodoset],
|
|
121
122
|
'HillCharts' => %w[GetHillChart UpdateHillChartSettings],
|
|
122
123
|
'TodolistGroups' => %w[ListTodolistGroups CreateTodolistGroup RepositionTodolistGroup]
|
|
@@ -145,6 +146,9 @@ class ServiceGenerator
|
|
|
145
146
|
'RepositionCardStep' => 'reposition',
|
|
146
147
|
'CreateCardStep' => 'create',
|
|
147
148
|
'UpdateCardStep' => 'update',
|
|
149
|
+
# The plain `update` name belongs to the merge-safe composite; the raw
|
|
150
|
+
# single-PUT path keeps a name that says what it does. See #467.
|
|
151
|
+
'UpdateCard' => 'update_verbatim',
|
|
148
152
|
'SetCardStepCompletion' => 'set_completion',
|
|
149
153
|
'GetQuestionnaire' => 'get_questionnaire',
|
|
150
154
|
'GetQuestion' => 'get_question',
|
|
@@ -302,6 +306,7 @@ class ServiceGenerator
|
|
|
302
306
|
clientcorrespondences clientreply clientreplies forwardreply
|
|
303
307
|
forwardreplies campfireline campfirelines todolistgroup todolistgroups
|
|
304
308
|
todolistorgroup uploadversions hillchart hillcharts
|
|
309
|
+
wormhole wormholes
|
|
305
310
|
].freeze
|
|
306
311
|
|
|
307
312
|
def initialize(openapi_path)
|
|
@@ -396,7 +401,12 @@ class ServiceGenerator
|
|
|
396
401
|
.select { |p| p['in'] == 'query' }
|
|
397
402
|
.map do |p|
|
|
398
403
|
{
|
|
399
|
-
|
|
404
|
+
# Strip a trailing `[]` from bracketed array wire names (e.g.
|
|
405
|
+
# `bucket_ids[]`): the kwarg and the params-hash key are both clean
|
|
406
|
+
# `bucket_ids`, and Faraday's NestedParamsEncoder re-adds the `[]` when
|
|
407
|
+
# serializing the array value (a raw `bucket_ids[]` key would double to
|
|
408
|
+
# `bucket_ids[][]=`).
|
|
409
|
+
name: p['name'].sub(/\[\]\z/, ''),
|
|
400
410
|
type: schema_to_ruby_type(p['schema']),
|
|
401
411
|
required: p['required'] || false,
|
|
402
412
|
description: p['description']
|
|
@@ -417,6 +427,13 @@ class ServiceGenerator
|
|
|
417
427
|
response_schema = success_response&.dig('content', 'application/json', 'schema')
|
|
418
428
|
returns_void = response_schema.nil?
|
|
419
429
|
returns_array = response_schema&.dig('type') == 'array'
|
|
430
|
+
# Bare-array responses are usually a $ref to a single-member output alias, so
|
|
431
|
+
# the inline `type` is absent. Resolve the ref to detect them — used only for
|
|
432
|
+
# the YARD @return doc (an unpaginated bare array returns an Array, not a
|
|
433
|
+
# Hash); the pagination/body logic deliberately keys off the raw `type` so a
|
|
434
|
+
# bare array without x-basecamp-pagination stays a single request.
|
|
435
|
+
resolved_response = response_schema && response_schema['$ref'] ? resolve_schema_ref(response_schema) : response_schema
|
|
436
|
+
returns_bare_array = resolved_response&.dig('type') == 'array'
|
|
420
437
|
|
|
421
438
|
{
|
|
422
439
|
operation_id: operation_id,
|
|
@@ -433,6 +450,7 @@ class ServiceGenerator
|
|
|
433
450
|
multipart_field: multipart_field,
|
|
434
451
|
returns_void: returns_void,
|
|
435
452
|
returns_array: returns_array,
|
|
453
|
+
returns_bare_array: returns_bare_array,
|
|
436
454
|
is_mutation: http_method != 'GET',
|
|
437
455
|
has_pagination: !!operation['x-basecamp-pagination'],
|
|
438
456
|
pagination_key: operation.dig('x-basecamp-pagination', 'key')
|
|
@@ -533,7 +551,13 @@ class ServiceGenerator
|
|
|
533
551
|
def schema_to_ruby_type(schema)
|
|
534
552
|
return 'Object' unless schema
|
|
535
553
|
|
|
536
|
-
|
|
554
|
+
# Object-valued members (e.g. a `project`/`gauge`/`schedule` envelope) are passed
|
|
555
|
+
# as a Hash. Resolve $refs and treat only object-typed schemas as Hash; a string
|
|
556
|
+
# ref such as FirstWeekDay must stay String.
|
|
557
|
+
resolved = schema['$ref'] ? resolve_schema_ref(schema) : schema
|
|
558
|
+
return 'Hash' if resolved && resolved['type'] == 'object'
|
|
559
|
+
|
|
560
|
+
case resolved&.fetch('type', nil)
|
|
537
561
|
when 'integer' then 'Integer'
|
|
538
562
|
when 'boolean' then 'Boolean'
|
|
539
563
|
when 'array' then 'Array'
|
|
@@ -645,6 +669,10 @@ class ServiceGenerator
|
|
|
645
669
|
lines << ' # @return [Hash] response data'
|
|
646
670
|
elsif is_paginated
|
|
647
671
|
lines << ' # @return [Enumerator<Hash>] paginated results'
|
|
672
|
+
elsif op[:returns_bare_array]
|
|
673
|
+
# Unpaginated bare array (single request, no Link-following) — e.g. the
|
|
674
|
+
# overdue todo/card feeds. Returns the parsed JSON array, not a Hash.
|
|
675
|
+
lines << ' # @return [Array<Hash>] response data'
|
|
648
676
|
else
|
|
649
677
|
lines << ' # @return [Hash] response data'
|
|
650
678
|
end
|
|
@@ -691,10 +719,11 @@ class ServiceGenerator
|
|
|
691
719
|
kwargs << "operation: \"#{op[:method_name]}\""
|
|
692
720
|
kwargs << "is_mutation: #{op[:is_mutation]}"
|
|
693
721
|
|
|
694
|
-
project_param = op[:path_params].find { |p| p[:name]
|
|
695
|
-
resource_param = op[:path_params].reject { |p| p[:name]
|
|
722
|
+
project_param = op[:path_params].find { |p| %w[projectId bucketId].include?(p[:name]) }
|
|
723
|
+
resource_param = op[:path_params].reject { |p| %w[projectId bucketId].include?(p[:name]) }
|
|
724
|
+
.select { |p| p[:name].end_with?("Id") || p[:name] == "id" }.last
|
|
696
725
|
|
|
697
|
-
kwargs << "project_id:
|
|
726
|
+
kwargs << "project_id: #{to_snake_case(project_param[:name])}" if project_param
|
|
698
727
|
kwargs << "resource_id: #{to_snake_case(resource_param[:name])}" if resource_param
|
|
699
728
|
|
|
700
729
|
kwargs.join(', ')
|
|
@@ -788,7 +817,7 @@ class ServiceGenerator
|
|
|
788
817
|
# Build params hash for query params
|
|
789
818
|
if op[:query_params].any?
|
|
790
819
|
param_names = op[:query_params].map { |q| "#{to_snake_case(q[:name])}: #{to_snake_case(q[:name])}" }
|
|
791
|
-
lines << " params =
|
|
820
|
+
lines << " params = compact_query_params(#{param_names.join(', ')})"
|
|
792
821
|
lines << " paginate(#{path_expr}, params: params)"
|
|
793
822
|
else
|
|
794
823
|
lines << " paginate(#{path_expr})"
|
|
@@ -802,7 +831,7 @@ class ServiceGenerator
|
|
|
802
831
|
|
|
803
832
|
if op[:query_params].any?
|
|
804
833
|
param_names = op[:query_params].map { |q| "#{to_snake_case(q[:name])}: #{to_snake_case(q[:name])}" }
|
|
805
|
-
lines << " params =
|
|
834
|
+
lines << " params = compact_query_params(#{param_names.join(', ')})"
|
|
806
835
|
lines << " paginate_wrapped(#{path_expr}, key: \"#{pagination_key}\", params: params)"
|
|
807
836
|
else
|
|
808
837
|
lines << " paginate_wrapped(#{path_expr}, key: \"#{pagination_key}\")"
|
|
@@ -834,7 +863,7 @@ class ServiceGenerator
|
|
|
834
863
|
lines << " http_#{http_method}(#{path_expr}, body: #{body_expr}).json"
|
|
835
864
|
elsif op[:query_params].any?
|
|
836
865
|
param_names = op[:query_params].map { |q| "#{to_snake_case(q[:name])}: #{to_snake_case(q[:name])}" }
|
|
837
|
-
lines << " http_#{http_method}(#{path_expr}, params:
|
|
866
|
+
lines << " http_#{http_method}(#{path_expr}, params: compact_query_params(#{param_names.join(', ')})).json"
|
|
838
867
|
else
|
|
839
868
|
lines << " http_#{http_method}(#{path_expr}).json"
|
|
840
869
|
end
|
data/scripts/generate-types.rb
CHANGED
|
@@ -87,6 +87,33 @@ def generate_helpers
|
|
|
87
87
|
HELPERS
|
|
88
88
|
end
|
|
89
89
|
|
|
90
|
+
# Renders a deprecation +reason+ as one or more Ruby comment lines (#406).
|
|
91
|
+
#
|
|
92
|
+
# A reason can be sourced from a multi-line OpenAPI description. Interpolating
|
|
93
|
+
# one into a single "# @deprecated ..." line would leave every continuation on a
|
|
94
|
+
# bare, un-commented source line, which is a syntax error in the generated
|
|
95
|
+
# types.rb — Ruby is the only owned generator exposed this way (Python escapes
|
|
96
|
+
# the reason, Kotlin/TypeScript emit block comments). Splitting on line
|
|
97
|
+
# boundaries and prefixing each line with the comment leader keeps the output
|
|
98
|
+
# valid for any reason.
|
|
99
|
+
#
|
|
100
|
+
# +indent+ is the leading source indentation; +tag_prefix+ is inserted between
|
|
101
|
+
# the "# " leader and the YARD tag (the per-attribute site nests its tag under
|
|
102
|
+
# an @!attribute directive). Continuation lines are indented two columns past
|
|
103
|
+
# the tag so YARD folds them into the same tag's text.
|
|
104
|
+
#
|
|
105
|
+
# Single-line reasons render byte-identically to the previous single-line
|
|
106
|
+
# interpolation, so this is output-neutral for the current spec.
|
|
107
|
+
def deprecation_doc_lines(reason, indent:, tag_prefix: '')
|
|
108
|
+
lines = reason.to_s.split(/\r?\n/, -1)
|
|
109
|
+
out = [ "#{indent}# #{tag_prefix}@deprecated #{lines.first}" ]
|
|
110
|
+
continuation = "#{indent}# #{tag_prefix} "
|
|
111
|
+
lines.drop(1).each do |line|
|
|
112
|
+
out << (line.empty? ? "#{indent}#" : "#{continuation}#{line}")
|
|
113
|
+
end
|
|
114
|
+
out
|
|
115
|
+
end
|
|
116
|
+
|
|
90
117
|
# Main execution
|
|
91
118
|
if __FILE__ == $PROGRAM_NAME
|
|
92
119
|
openapi_path = ARGV[0] || File.expand_path('../../openapi.json', __dir__)
|
|
@@ -124,6 +151,12 @@ if __FILE__ == $PROGRAM_NAME
|
|
|
124
151
|
|
|
125
152
|
puts ''
|
|
126
153
|
puts " # #{name}"
|
|
154
|
+
# Documentation-only deprecation (see #406): YARD marks a whole class/method,
|
|
155
|
+
# not individual params, so a class-level @deprecated tag documents a wholly
|
|
156
|
+
# deprecated type.
|
|
157
|
+
if schema['deprecated']
|
|
158
|
+
puts deprecation_doc_lines(schema['x-deprecated-reason'] || 'deprecated', indent: ' ')
|
|
159
|
+
end
|
|
127
160
|
puts " class #{name}"
|
|
128
161
|
puts ' include TypeHelpers'
|
|
129
162
|
|
|
@@ -131,6 +164,19 @@ if __FILE__ == $PROGRAM_NAME
|
|
|
131
164
|
# Add system_label for schemas with flexible integer fields
|
|
132
165
|
has_flexible = ordered_props.any? { |k| properties[k]['x-go-type']&.include?('FlexibleInt64') }
|
|
133
166
|
attr_names << 'system_label' if has_flexible
|
|
167
|
+
|
|
168
|
+
# Per-attribute deprecation. The accessors are declared in one grouped
|
|
169
|
+
# attr_accessor, so a bare comment would wrongly document every attribute;
|
|
170
|
+
# a YARD @!attribute directive scopes the @deprecated tag to just this one.
|
|
171
|
+
ordered_props.each do |k|
|
|
172
|
+
ps = properties[k]
|
|
173
|
+
next unless ps['deprecated']
|
|
174
|
+
|
|
175
|
+
ruby_name = k.gsub(/([A-Z])/, '_\1').downcase.gsub(/^_/, '')
|
|
176
|
+
puts " # @!attribute [rw] #{ruby_name}"
|
|
177
|
+
puts deprecation_doc_lines(ps['x-deprecated-reason'] || 'deprecated', indent: ' ', tag_prefix: ' ')
|
|
178
|
+
end
|
|
179
|
+
|
|
134
180
|
puts " attr_accessor #{attr_names.map { |n| ":#{n}" }.join(", ")}"
|
|
135
181
|
|
|
136
182
|
unless required_props.empty?
|
|
@@ -182,7 +228,20 @@ if __FILE__ == $PROGRAM_NAME
|
|
|
182
228
|
attr_name = prop_name.gsub(/([A-Z])/, '_\1').downcase.gsub(/^_/, '')
|
|
183
229
|
puts " \"#{prop_name}\" => @#{attr_name},"
|
|
184
230
|
end
|
|
185
|
-
|
|
231
|
+
# A required-and-nullable field (OpenAPI 3.1 `type: [..., "null"]`) carries an
|
|
232
|
+
# explicit null that must survive to_h; plain .compact would drop it. Keep
|
|
233
|
+
# nil for exactly those keys — required-but-non-nullable fields still get
|
|
234
|
+
# dropped when nil, like any other nil. Everything else keeps .compact.
|
|
235
|
+
required_nullable = required_fields.select do |k|
|
|
236
|
+
t = properties[k] && properties[k]['type']
|
|
237
|
+
t.is_a?(Array) && t.include?('null')
|
|
238
|
+
end
|
|
239
|
+
if required_nullable.any?
|
|
240
|
+
keep_list = required_nullable.map { |k| "\"#{k}\"" }.join(', ')
|
|
241
|
+
puts " }.reject { |k, v| v.nil? && ![#{keep_list}].include?(k) }"
|
|
242
|
+
else
|
|
243
|
+
puts ' }.compact'
|
|
244
|
+
end
|
|
186
245
|
puts ' end'
|
|
187
246
|
puts ''
|
|
188
247
|
|
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.10.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-07-
|
|
11
|
+
date: 2026-07-29 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: faraday
|
|
@@ -196,6 +196,7 @@ files:
|
|
|
196
196
|
- lib/basecamp/generated/services/comments_service.rb
|
|
197
197
|
- lib/basecamp/generated/services/documents_service.rb
|
|
198
198
|
- lib/basecamp/generated/services/events_service.rb
|
|
199
|
+
- lib/basecamp/generated/services/everything_service.rb
|
|
199
200
|
- lib/basecamp/generated/services/forwards_service.rb
|
|
200
201
|
- lib/basecamp/generated/services/gauges_service.rb
|
|
201
202
|
- lib/basecamp/generated/services/hill_charts_service.rb
|
|
@@ -223,6 +224,7 @@ files:
|
|
|
223
224
|
- lib/basecamp/generated/services/uploads_service.rb
|
|
224
225
|
- lib/basecamp/generated/services/vaults_service.rb
|
|
225
226
|
- lib/basecamp/generated/services/webhooks_service.rb
|
|
227
|
+
- lib/basecamp/generated/services/wormholes_service.rb
|
|
226
228
|
- lib/basecamp/generated/types.rb
|
|
227
229
|
- lib/basecamp/hooks.rb
|
|
228
230
|
- lib/basecamp/http.rb
|
|
@@ -252,6 +254,7 @@ files:
|
|
|
252
254
|
- lib/basecamp/request_result.rb
|
|
253
255
|
- lib/basecamp/security.rb
|
|
254
256
|
- lib/basecamp/services/authorization_service.rb
|
|
257
|
+
- lib/basecamp/services/cards_extensions.rb
|
|
255
258
|
- lib/basecamp/services/todos_extensions.rb
|
|
256
259
|
- lib/basecamp/static_token_provider.rb
|
|
257
260
|
- lib/basecamp/token_provider.rb
|