Releases: tirthpatell/threads-go
v1.9.0
Security-focused release. Hardens OAuth against login CSRF (CWE-352) and tightens log redaction, ownership checks, and rate-limit thread-safety. Contains API breakage on the auth surface only.
Breaking changes
-
Authenticator.GetAuthURLnow returns (authURL, state, err) instead of just a URL string. Callers must persist state (session/cookie) and pass it back on exchange. -
Authenticator.ExchangeCodeForTokennow requires (ctx, code, expectedState, receivedState). The two states are compared with crypto/subtle.ConstantTimeCompare before any network call; mismatch or empty values return a ValidationError.Migration: see
examples/authentication/main.go.
Security fixes
- OAuth state CSRF (HIGH, CWE-352): state is generated with crypto/rand and surfaced to the caller; the predictable time-based fallback was removed (fail-closed on rand errors).
- Debug-log redaction: access_token, client_secret, input_token, code, and refresh_token are redacted from request URLs before logging.
- validatePostOwnership: prefers numeric owner ID over username and fails closed on empty identifiers — previously two empty strings compared equal and silently authorised deletion.
- DisableRateLimiting / EnableRateLimiting: the HTTPClient's limiter is now an atomic.Pointer so toggling from one goroutine is race-safe against an in-flight request on another.
CI / chores
- Bump schneegans/dynamic-badges-action v1.7.0 → v1.8.0 (supersedes #25).
- Bump codecov/codecov-action v5 → v6 (supersedes #26).
- Drop TestIntegration_GIFPosts — Tenor API deprecated.
Full Changelog: v1.8.0...v1.9.0
v1.8.0
Breaking Changes
This release includes source-incompatible changes to exported interfaces and types. Code that implements these interfaces (e.g., mocks, test wrappers) or reads these fields will need updates.
| Change | Before | After |
|---|---|---|
| PostDeleter.DeletePost return | error | (string, error) — returns deleted_id |
| PostReader.GetUserMentions param | *PaginationOptions | *PostsOptions — adds since/until support |
| Post.ReplyAudience type | string | ReplyAudience (typed constant) |
| Post.HideStatus type | string | HideStatus (typed constant) |
| Post.TextEntities type | []TextEntity | *TextEntitiesResponse (API returns {"data": [...]} wrapper) |
New Features
- App Access Tokens — GetAppAccessToken() and GetAppAccessTokenShorthand() for app-level auth (e.g., oEmbed API)
- Ghost Posts on interface — GetUserGhostPosts added to PostReader interface
- Mentions time filtering — GetUserMentions now supports since/until unix timestamp parameters
- Response media type constants — MediaTypeResponseText (TEXT_POST), MediaTypeResponseCarousel (CAROUSEL_ALBUM), MediaTypeAudio, MediaTypeRepostFacade
- Typed reply/hide constants — ReplyAudience (5 values) and HideStatus (6 values) for type-safe response handling
- Geo-gating error codes — ErrCodeFeatureNotAvailable, ErrCodeGeoGatingInvalidCountryCodes
- Container error constants — 10 typed ContainerErr* constants for programmatic error handling
Bug Fixes
- Post struct missing fields — Added IsSpoilerMedia, TextEntities, TextAttachment, AllowlistedCountryCodes, LocationID, Location
- User.RecentlySearchedKeywords — Fixed type from []string to []RecentSearch (struct with Query/Timestamp) and wired field mapping
- User.IsEligibleForGeoGating — Added missing boolean field
- TotalValue.LinkURL — Added for per-link click metric breakdowns
- ContainerBuilder.SetIsGhostPost — Now order-independent with SetMediaType; SetIsGhostPost(false) correctly clears the flag
Validation Improvements
- Poll options: require sequential ordering (D requires C), reject whitespace-only options, enforce 1–25 char length
- Alt text: enforce 1000-character max on image/video posts
- Text styling: validate style values against allowed set (bold, italic, highlight, underline, strikethrough)
- Timestamps: since/until validated against MinSearchTimestamp on all endpoints (GetUserPostsWithOptions, GetUserMentions, GetPublicProfilePosts, GetUserReplies), with since <= until ordering check
- ValidatePostsOptions centralizes pagination + timestamp validation
Documentation
- Rate limit formula (4800 × Impressions) and per-operation defaults documented on QuotaConfig
- views/shares insight metrics marked as "in development" per API docs
- DeletePost documents 100/24hr limit and threads_delete scope requirement
- GetAppAccessToken notes RFC 6749 deviation (GET exposes client_secret)
Other
- Version constant updated from 1.1.0 to 1.8.0 (was stale; aligns with release tags)
- Test coverage improvements across all new code paths
- Replace Dependabot with govulncheck, increase coverage to 93.6%, add Codecov
Full Changelog: v1.7.1...v1.8.0
v1.7.1
What's Changed
- fix: use unicode character count for text length validation by @shyuan in #18
- fix: library improvements - bug fixes, tests, and coverage badge by @tirthpatell in #19
- fix: restrict GITHUB_TOKEN permissions in CI workflows by @tirthpatell in #20
- docs: update README, examples, and docs for recent API features by @tirthpatell in #21
New Contributors
Full Changelog: v1.7.0...v1.7.1
v1.7.0
What's Changed
- fix: improve retry logic, error metadata, and container lifecycle by @tirthpatell in #17
Full Changelog: v1.6.0...v1.7.0
v1.6.0
What's Changed
- feat: Add March 2026 API updates and fix carousel ordering by @tirthpatell in #16
Full Changelog: v1.5.0...v1.6.0
v1.5.0
What's Changed
- feat: Add February 2026 Threads API updates by @tirthpatell in #15
Full Changelog: v1.4.0...v1.5.0
v1.4.0
What's Changed
- feat: Add January 2026 Threads API updates by @tirthpatell in #14
Full Changelog: v1.3.0...v1.4.0
v1.3.0
What's Changed
- feat: Add December 2025 Threads API updates by @tirthpatell in #12
- fix: wait for child containers before creating carousel by @tirthpatell in #13
Full Changelog: v1.2.0...v1.3.0
v1.2.0
What's Changed
Feature: Changelog Updates (Nov-Dec 2025)
- Ghost Posts (Dec 15, 2025)
- Creation:
- Added IsGhostPost field to TextPostContent.
- Updated ContainerBuilder to support the is_ghost_post parameter.
- Implemented validation to ensure ghost posts cannot be replies.
- Retrieval:
- Added GetUserGhostPosts(ctx, userID, opts) method to posts_read.go, targeting the specific GET /{user-id}/ghost_posts endpoint.
- Updated Post struct with GhostPostStatus and GhostPostExpirationTimestamp.
- Defined GhostPostFields constant to request the correct fields.
- Link Limits (Dec 8, 2025)
- Validation:
- Added MaxLinks = 5 constant.
- Implemented ValidateLinkCount in Validator to enforce the 5-link limit.
- The validation logic correctly counts unique URLs and integrates link_attachment (counting it only if it differs from URLs in the text body), strictly following API documentation
examples. - Applied this validation to Text, Image, Video, and Carousel post content.
- Follower Discovery Limits (Nov 20, 2025)
- Verification: Verified that the client's existing dynamic rate limiting handles the reduced follower discovery limit (1,000 -> 100) correctly via X-RateLimit-Limit headers without
requiring code changes.
Full Changelog: v1.1.0...v1.2.0
v1.1.0
Versioning Note
- Starting with this release, threads-go is adopting proper https://semver.org/. Previously, patch versions were incorrectly bumped for new features.
- This release jumps from v1.0.4 to v1.1.0 to reflect the new feature additions.
New Features
- GIF Attachment Support
- You can now attach GIFs to text posts using the Threads API
gif_attachmentparameter. Tenor is currently the only supported GIF provider.
- You can now attach GIFs to text posts using the Threads API
Note: GIFs can only be attached to text-only posts (not image, video, or carousel posts).
What's Changed
- build(deps): bump actions/checkout from 5 to 6 in /.github/workflows by @dependabot in #8
- feat: add GIF attachment support for text posts by @tirthpatell in #9
Full Changelog: v1.0.4...v1.1.0