Skip to content

Upstream API sync: Boosts API, timesheet path fixes, boost fields#83

Merged
jeremy merged 4 commits intomainfrom
api-bump
Feb 8, 2026
Merged

Upstream API sync: Boosts API, timesheet path fixes, boost fields#83
jeremy merged 4 commits intomainfrom
api-bump

Conversation

@jeremy
Copy link
Member

@jeremy jeremy commented Feb 8, 2026

Summary

Brings the SDK current with upstream Basecamp API changes (2026-02-07):

  • Fix timesheet paths: 4 operations corrected from /buckets/ to /projects/ (GetProjectTimesheet, GetRecordingTimesheet, GetTimesheetEntry, UpdateTimesheetEntry)
  • Add boost/content_type fields: boosts_count and boosts_url on 12 recording types; content_type on CreateCampfireLineInput for rich text campfire lines
  • New Boosts API: 6 endpoints — ListRecordingBoosts, ListEventBoosts, GetBoost, CreateRecordingBoost, CreateEventBoost, DeleteBoost — with full service wiring in all three SDKs
  • Update API provenance to current upstream HEADs

Commits

  1. Fix timesheet paths and add boost/content_type fields to recording types — spec fixes + field additions, regenerated all SDKs, updated TS/Ruby tests for new paths
  2. Add Boosts API with 6 endpoints — new Smithy operations + tag, generator mappings, client wiring, generated services, new test suites (TS + Ruby)
  3. Update API provenance to 2026-02-07 upstream HEADs — stamps bc3_api and bc3 revisions

Test plan

  • make check passes (all three SDKs compile and test green)
  • Verify boost endpoints work against staging
  • Verify timesheet endpoints resolve correctly with /projects/ paths

Timesheet operations incorrectly used /buckets/ paths instead of /projects/:
- GetProjectTimesheet, GetRecordingTimesheet, GetTimesheetEntry,
  UpdateTimesheetEntry now use /{accountId}/projects/{projectId}/...

Add boosts_count and boosts_url fields to 12 recording type structures:
Todo, Todolist, Comment, Message, Document, Upload, ScheduleEntry,
CampfireLine, Card, ForwardReply, QuestionAnswer, Event.

Add optional content_type parameter to CreateCampfireLine for rich text.
New Boosts service modeling the Basecamp Boosts API:
- ListRecordingBoosts (GET /recordings/{id}/boosts.json)
- ListEventBoosts (GET /recordings/{id}/events/{id}/boosts.json)
- GetBoost (GET /boosts/{id})
- CreateRecordingBoost (POST /recordings/{id}/boosts.json)
- CreateEventBoost (POST /recordings/{id}/events/{id}/boosts.json)
- DeleteBoost (DELETE /boosts/{id})

Includes generated services for all three SDKs (Go, TypeScript, Ruby),
client wiring, and test coverage for all 6 operations.
bc3-api: f7413a2717ced5e38f1ca215cbd95e9d74b02db3
bc3:     37be1c9481c88845c02ac8e4b95319b8d29ad460
Copilot AI review requested due to automatic review settings February 8, 2026 06:24
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Synchronizes the SDK with upstream Basecamp API changes (2026-02-07), including corrected timesheet routing under /projects/ and introducing the new Boosts API across the generated clients/tests.

Changes:

  • Updated Timesheets endpoints from /buckets/{projectId}/... to /projects/{projectId}/... and adjusted corresponding TS/Ruby tests.
  • Added Boosts API operations (list/get/create/delete) plus generated service wiring and new test suites (TS + Ruby).
  • Added new fields (boosts_count, boosts_url, content_type) into the Smithy spec and regenerated SDK artifacts/metadata.

Reviewed changes

Copilot reviewed 16 out of 31 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
typescript/tests/services/reports.test.ts Updates mocked timesheet URLs to /projects/... in TS tests.
typescript/tests/services/boosts.test.ts Adds new TS test suite for BoostsService.
typescript/src/index.ts Exports the new Boosts service/types from the TS package entrypoint.
typescript/src/generated/services/timesheets.ts Updates generated TimesheetsService paths to /projects/....
typescript/src/generated/services/index.ts Adds BoostsService to generated service exports.
typescript/src/generated/services/campfires.ts Adds contentType request field and maps it to content_type.
typescript/src/generated/services/boosts.ts New generated Boosts service implementation.
typescript/src/generated/schema.d.ts Updates generated schema typings for boosts + timesheet path changes.
typescript/src/generated/path-mapping.ts Maps new Boosts endpoints and moves timesheet operations to /projects/....
typescript/src/generated/openapi-stripped.json Updates stripped OpenAPI source for boosts + timesheet path changes.
typescript/src/generated/metadata.json Regenerated TS operation metadata including retry/pagination for boosts and updated timesheet ops.
typescript/src/client.ts Wires BoostsService into the TS client.
typescript/scripts/generate-services.ts Adds Boosts tag-to-service mapping for TS generation.
spec/overlays/tags.smithy Tags Boosts operations for generation.
spec/basecamp.smithy Adds Boosts API shapes/ops, timesheet path fixes, and boosts fields/content_type additions.
spec/api-provenance.json Updates upstream revision stamps to 2026-02-07.
ruby/test/basecamp/services/timesheet_service_test.rb Updates Ruby timesheet tests to expect /projects/... paths.
ruby/test/basecamp/services/campfires_service_test.rb Adds Ruby test for content_type on campfire line creation.
ruby/test/basecamp/services/boosts_service_test.rb Adds Ruby test suite for BoostsService.
ruby/scripts/generate-services.rb Adds Boosts tag-to-service mapping for Ruby generation.
ruby/lib/basecamp/generated/types.rb Regenerates Ruby types to include Boost + boosts_count/url fields.
ruby/lib/basecamp/generated/services/timesheets_service.rb Updates generated Ruby timesheet paths to /projects/....
ruby/lib/basecamp/generated/services/campfires_service.rb Adds content_type support to Ruby campfire line creation.
ruby/lib/basecamp/generated/services/boosts_service.rb Adds generated BoostsService in Ruby.
ruby/lib/basecamp/generated/metadata.json Regenerates Ruby operation metadata (boosts + moved timesheet ops).
ruby/lib/basecamp/client.rb Exposes boosts accessor on the Ruby client.
go/pkg/basecamp/url-routes.json Adds route entries for Boosts + new /projects/... timesheet routes.
go/pkg/basecamp/api-provenance.json Updates Go provenance stamps to 2026-02-07.
behavior-model.json Adds behavior/retry/pagination metadata for Boosts operations.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Add METHOD_NAME_OVERRIDES for compound boost operations and "boost" to
isSimpleResource so generated interface names read cleanly:
- ListForRecordingBoostOptions (was ListRecordingBoostsBoostOptions)
- CreateForRecordingBoostRequest (was CreateRecordingBoostBoostRequest)
- ListForEventBoostOptions (was ListEventBoostsBoostOptions)
- CreateForEventBoostRequest (was CreateEventBoostBoostRequest)

Method names also simplified: get/delete for single-boost ops,
listForRecording/createForRecording/listForEvent/createForEvent for
scoped operations.
@jeremy jeremy merged commit b047360 into main Feb 8, 2026
22 checks passed
@jeremy jeremy deleted the api-bump branch February 8, 2026 06:39
jeremy added a commit that referenced this pull request Feb 8, 2026
Wraps the generated Boosts API client methods added in PR #83:
- ListRecording, ListEvent, Get, CreateRecording, CreateEvent, Delete
- Converter boostFromGenerated maps generated types to clean SDK types
- Lazy-init Boosts() accessor on AccountClient
- Fixture-based tests for unmarshal and request serialization
jeremy added a commit that referenced this pull request Feb 8, 2026
…nt (#84)

* Go SDK: Add BoostsService with 6 operations

Wraps the generated Boosts API client methods added in PR #83:
- ListRecording, ListEvent, Get, CreateRecording, CreateEvent, Delete
- Converter boostFromGenerated maps generated types to clean SDK types
- Lazy-init Boosts() accessor on AccountClient
- Fixture-based tests for unmarshal and request serialization

* Go SDK: Expose content_type on CreateLine for campfire messages

Add CreateLineOptions parameter to CampfiresService.CreateLine so callers
can send HTML content. Validates content_type is text/plain or text/html.
Adds LineContentTypePlain and LineContentTypeHTML constants.

* Wire drift check into make check and CI

- Add test coverage detection to check-service-drift.sh (warns on
  wrapped operations with no tests calling the generated client)
- Add go-check-drift to the check target so make catches drift
- Add drift check step to the Go test job in CI

* Address Copilot review feedback

- Remove unused CreateBoostRequest type (service methods take raw content
  string, matching CreateLine pattern; struct was only used in tests)
- Remove noisy UNTESTED detection from drift check script — tests exercise
  service wrappers, not .gen.* directly, so the grep produced all-false-
  positive output for every wrapped operation

* Address Codex review: variadic CreateLine opts, service-level validation tests

- Change CreateLine signature from *CreateLineOptions to ...CreateLineOptions
  to preserve source compatibility with existing 4-arg callers
- Add service-level validation tests for CampfiresService (empty content,
  invalid content_type, valid content_types, no-options backward compat)
- Add service-level validation tests for BoostsService (empty content
  rejected, valid content accepted)

* Add httptest-based service contract tests for Boosts and CreateLine

BoostsService tests (7 new):
- ListRecording: 200 response, X-Total-Count header parsing, converter mapping
- ListRecording empty: 200 with [] body
- Get: 200 with full converter mapping (Booster, Recording)
- Get 404: not_found error
- CreateRecording: 201, verifies request body content wiring
- Delete: 204 success
- Delete 404: not_found error

CampfiresService CreateLine tests (3 new, replacing panic-based tests):
- NoOptions: POST with content only, no content_type in request body
- HTMLOption: content_type=text/html flows through to request body
- PlainOption: content_type=text/plain flows through to request body

Uses testBoostsServer/testCampfiresServer helpers that wire httptest.Server
through NewClient → ForAccount → service, exercising the full call path
including generated client, checkResponse, and type converters.

* Address review: gofmt, remove panic tests, cover all 6 Boost ops, reject extra opts

- Fix trailing newline gofmt issue in boosts_test.go
- Remove panic-recovery validation tests (superseded by httptest tests)
- Add httptest tests for ListEvent and CreateEvent (all 6 BoostsService
  operations now have service contract tests)
- Reject len(opts) > 1 in CreateLine with ErrUsage instead of silently
  ignoring extra options
- Fix unparam lint: test helpers return *Service only, not (*Service, *Server)
jeremy added a commit that referenced this pull request Feb 8, 2026
Flatten the 6 new Boost operation URIs from PR #83 to remove
/buckets/{projectId} nesting, matching the flat branch convention.
Regenerate all SDK clients and update tests for flat paths.

Add web-URL flattening to Go router so it can match Basecamp web URLs
(which still contain /buckets/{projectId}) against the flat route table.
jeremy added a commit that referenced this pull request Feb 8, 2026
Flatten the 6 new Boost operation URIs from PR #83 to remove
/buckets/{projectId} nesting, matching the flat branch convention.
Regenerate all SDK clients and update tests for flat paths.

Add web-URL flattening to Go router so it can match Basecamp web URLs
(which still contain /buckets/{projectId}) against the flat route table.
jeremy added a commit that referenced this pull request Feb 20, 2026
Flatten the 6 new Boost operation URIs from PR #83 to remove
/buckets/{projectId} nesting, matching the flat branch convention.
Regenerate all SDK clients and update tests for flat paths.

Add web-URL flattening to Go router so it can match Basecamp web URLs
(which still contain /buckets/{projectId}) against the flat route table.
jeremy added a commit that referenced this pull request Feb 20, 2026
Flatten the 6 new Boost operation URIs from PR #83 to remove
/buckets/{projectId} nesting, matching the flat branch convention.
Regenerate all SDK clients and update tests for flat paths.

Add web-URL flattening to Go router so it can match Basecamp web URLs
(which still contain /buckets/{projectId}) against the flat route table.
jeremy added a commit that referenced this pull request Feb 26, 2026
Flatten the 6 new Boost operation URIs from PR #83 to remove
/buckets/{projectId} nesting, matching the flat branch convention.
Regenerate all SDK clients and update tests for flat paths.

Add web-URL flattening to Go router so it can match Basecamp web URLs
(which still contain /buckets/{projectId}) against the flat route table.
jeremy added a commit that referenced this pull request Feb 27, 2026
Flatten the 6 new Boost operation URIs from PR #83 to remove
/buckets/{projectId} nesting, matching the flat branch convention.
Regenerate all SDK clients and update tests for flat paths.

Add web-URL flattening to Go router so it can match Basecamp web URLs
(which still contain /buckets/{projectId}) against the flat route table.
jeremy added a commit that referenced this pull request Feb 27, 2026
* Flatten Smithy spec routes to remove nested URL scoping

Resources are uniquely identified and don't need parentage context in
their URLs. Remove /buckets/{projectId} prefix and other nested scoping
from ~80 operations, changing paths like:

  /{accountId}/buckets/{projectId}/todos/{todoId}

to flat paths like:

  /{accountId}/todos/{todoId}

Project-scoped operations under /projects/{projectId}/ are retained
since those genuinely operate on the project resource itself.

* Regenerate all SDK clients from flattened OpenAPI spec

* Update Go service layer for flat routes

Remove projectID parameter from all service methods that no longer
need bucket scoping. Retain projectID only for genuinely project-scoped
operations (ListProjectPeople, UpdateProjectAccess).

Also simplifies lineup marker requests to match spec (name/date only),
and removes BucketID from OperationInfo and OpenTelemetry spans.

* Update Go tests for flat route signatures

Remove projectID arguments from test calls, update lineup test
fixtures to use name/date fields, and remove BucketID from
observability test assertions.

* Update TypeScript tests for flat routes

Remove /buckets/{projectId} from MSW mock URLs, remove projectId
arguments from service calls, update lineup tests to use name/date
fields, and remove project_id from OpenTelemetry span assertions.

* Update Ruby tests for flat routes

Remove project_id: keyword arguments from service test calls, update
WebMock stub URLs to use flat paths, update lineup tests to use
name/date fields, and fix card step completion tests to use
set_card_step_completion on CardTablesService.

* Update conformance runner for flat routes

Remove projectId argument from CreateTodo and ListTodos calls in
the conformance test runner.

* Remove unused bucketID parameters from Go service methods

Nine methods still accepted a bucketID parameter that was silently
discarded — callers would pass a value that got thrown away. Remove
the parameter from: CampfiresService.GetLine, DeleteLine, GetChatbot,
UpdateChatbot, DeleteChatbot; ForwardsService.GetReply;
ClientRepliesService.Get; CardsService.Move; CardStepsService.Reposition.

Also remove dead ProjectPath() and RequireProject() methods from Client.

* Remove stale bucketID comments from Go service files

Clean 121 comment lines across 22 files that referenced bucketID
parameters that no longer exist in function signatures.

* Flatten conformance test paths to match new flat routes

Remove /buckets/{projectId} prefix from test path patterns and
projectId from pathParams in pagination, idempotency, and status-code
conformance tests. Update schema.json example accordingly.

* Update README examples and cleanup stale bucket references

Remove projectId arguments from Go, TypeScript, and Ruby README code
examples to match flattened service signatures. Update TS
normalizeUrlPath JSDoc comment. Remove dead bucket_path codegen logic
from Ruby service generator.

* Flatten timesheet entry operations added by PR #76

The rebase onto main brought in 3 new timesheet entry operations
(Get, Create, Update) with nested /buckets/{projectId}/ URIs.
Flatten these to match the rest of the flat branch, regenerate
all SDK clients, and update the Go service layer and conformance
runner accordingly.

* Remove dead hand-written TypeScript service files

These 31 files were superseded by generated services in
src/generated/services/ but never deleted. The entry point
(src/index.ts) already imports from generated, so these were
unused dead code. Only base.ts and authorization.ts remain
as hand-written services (they talk to different endpoints).

The ts-service branch will address generating a single unified
service layer that matches the ergonomics of these originals.

* Fix Ruby card_steps test and remove stale .plan.md

Update card_steps_service_test.rb to use the regenerated method
name (card_steps.set_completion instead of card_tables.set_card_step_completion).
Remove .plan.md that was accidentally included during rebase.

* Regenerate all SDK clients from canonical openapi.json

Post-rebase regeneration to ensure generated files match the
canonical openapi.json built from the Smithy spec.

* Flatten Boost API operations and regenerate all SDK clients

Flatten the 6 new Boost operation URIs from PR #83 to remove
/buckets/{projectId} nesting, matching the flat branch convention.
Regenerate all SDK clients and update tests for flat paths.

Add web-URL flattening to Go router so it can match Basecamp web URLs
(which still contain /buckets/{projectId}) against the flat route table.

* Flatten Go BoostsService and CreateLine for flat branch

Remove bucketID parameter from all 6 BoostsService methods and
update CreateLine test calls to match flat campfire signatures.

* Fix URL router missing .json-suffixed API URLs

The route table strips .json suffixes during generation, but the
router was matching against the raw path. API URLs like
basecampapi.com/.../boosts.json returned nil because the route
table stores .../boosts without the suffix.

Fix by normalizing .json in extractPath alongside other URL
normalization (scheme, host, query, trailing slash).

* Flatten webhook get-with-deliveries test URLs for flat branch

Remove /buckets/{projectId} from TS and Ruby webhook test that
was added in PR #85 for the recent_deliveries fixture test.

* Fix Go SDK build: wrap *int64 Id fields with derefInt64() in all converters

The required-fields PR changed all Id fields in generated types from
int64 to *int64. Update all *FromGenerated converter functions to use
derefInt64() for pointer-to-value conversion, and update test struct
literals to pass pointer values.

* Regenerate all SDK clients from Smithy spec and fix CI

Rebuild openapi.json from Smithy, then regenerate Ruby, TypeScript,
and Kotlin SDKs. Updates Kotlin conformance tests and TodosServiceTest
for flat URL signatures (projectId removed). Fixes apidiff CI cache
key to include go.mod hash so the tool rebuilds on Go version bumps.

* Fix spec routes C1, C2, C5, C6 and regenerate all SDKs

C1: GetProjectTimeline now bucket-scoped at /buckets/{projectId}/timeline.json
C2: GetProjectTimesheet now bucket-scoped at /buckets/{projectId}/timesheet.json
C5: Timesheet entry routes use /timesheet_entries/{entryId} (underscore separator)
C6: ListWebhooks/CreateWebhook now bucket-scoped at /buckets/{bucketId}/webhooks.json

Propagated across Go (generated + hand-written), Ruby, TypeScript, Kotlin, Swift.
Go URL router handles /projects/ → /buckets/ normalization for web URLs.
TS normalizeUrlPath uses context overrides for bucketId vs projectId.
Conformance tests cover all four route fixes (Go 31/31, Kotlin 30/30+1 skip).

* Fix PR review comments: update stale docs and comments

- Go README: Add bucketID to webhook Create/List examples
- Go README: Define boardID variable in message board example
- timesheet.go: Remove stale projectID reference from RecordingReport comment
- message_types.go: Update List comment to reflect account-level scope

* Fix timeline/timesheet paths: /buckets/ → /projects/

BC3 serves GetProjectTimeline and GetProjectTimesheet at
/projects/{projectId}/... not /buckets/{projectId}/...
Main branch already had this fix but flat never picked it up.

* Update conformance and SDK tests for /projects/ timeline/timesheet paths
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants