twitchrb 1.10.0 → 2.0.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.
Files changed (93) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +2 -2
  3. data/.rubocop.yml +1 -1
  4. data/CHANGELOG.md +104 -1
  5. data/Gemfile.lock +5 -5
  6. data/README.md +360 -45
  7. data/lib/twitch/client.rb +109 -20
  8. data/lib/twitch/collection.rb +58 -11
  9. data/lib/twitch/error_generator.rb +6 -4
  10. data/lib/twitch/eventsub_webhook.rb +140 -0
  11. data/lib/twitch/oauth.rb +50 -15
  12. data/lib/twitch/object.rb +28 -0
  13. data/lib/twitch/objects/ad_schedule.rb +4 -0
  14. data/lib/twitch/objects/analytics_report.rb +4 -0
  15. data/lib/twitch/objects/bits_leaderboard_entry.rb +4 -0
  16. data/lib/twitch/objects/charity_donation.rb +4 -0
  17. data/lib/twitch/objects/chat_settings.rb +4 -0
  18. data/lib/twitch/objects/cheermote.rb +4 -0
  19. data/lib/twitch/objects/content_classification_label.rb +4 -0
  20. data/lib/twitch/objects/drops_entitlement.rb +4 -0
  21. data/lib/twitch/objects/drops_entitlement_update.rb +4 -0
  22. data/lib/twitch/objects/extension.rb +4 -0
  23. data/lib/twitch/objects/extension_bits_product.rb +4 -0
  24. data/lib/twitch/objects/extension_configuration_segment.rb +4 -0
  25. data/lib/twitch/objects/extension_live_channel.rb +4 -0
  26. data/lib/twitch/objects/extension_secret.rb +4 -0
  27. data/lib/twitch/objects/extension_transaction.rb +4 -0
  28. data/lib/twitch/objects/guest_star_invite.rb +4 -0
  29. data/lib/twitch/objects/guest_star_session.rb +4 -0
  30. data/lib/twitch/objects/guest_star_settings.rb +4 -0
  31. data/lib/twitch/objects/shield_mode_status.rb +4 -0
  32. data/lib/twitch/objects/{tag.rb → team.rb} +1 -1
  33. data/lib/twitch/objects/user_active_extensions.rb +4 -0
  34. data/lib/twitch/objects/user_extension.rb +4 -0
  35. data/lib/twitch/resource.rb +49 -9
  36. data/lib/twitch/resources/ads.rb +18 -0
  37. data/lib/twitch/resources/analytics.rb +19 -0
  38. data/lib/twitch/resources/announcements.rb +1 -1
  39. data/lib/twitch/resources/automod.rb +8 -8
  40. data/lib/twitch/resources/badges.rb +3 -3
  41. data/lib/twitch/resources/banned_users.rb +4 -4
  42. data/lib/twitch/resources/bits.rb +16 -0
  43. data/lib/twitch/resources/blocked_terms.rb +5 -5
  44. data/lib/twitch/resources/channels.rb +7 -7
  45. data/lib/twitch/resources/charity_campaigns.rb +9 -1
  46. data/lib/twitch/resources/chat_messages.rb +1 -1
  47. data/lib/twitch/resources/chat_settings.rb +20 -0
  48. data/lib/twitch/resources/chatters.rb +1 -1
  49. data/lib/twitch/resources/clips.rb +3 -9
  50. data/lib/twitch/resources/content_classification_labels.rb +8 -0
  51. data/lib/twitch/resources/custom_power_ups.rb +1 -1
  52. data/lib/twitch/resources/custom_reward_redemptions.rb +3 -4
  53. data/lib/twitch/resources/custom_rewards.rb +5 -5
  54. data/lib/twitch/resources/drops_entitlements.rb +17 -0
  55. data/lib/twitch/resources/emotes.rb +5 -5
  56. data/lib/twitch/resources/eventsub_conduits.rb +14 -4
  57. data/lib/twitch/resources/eventsub_subscriptions.rb +9 -13
  58. data/lib/twitch/resources/extensions.rb +99 -0
  59. data/lib/twitch/resources/games.rb +5 -7
  60. data/lib/twitch/resources/goals.rb +1 -1
  61. data/lib/twitch/resources/guest_star.rb +102 -0
  62. data/lib/twitch/resources/moderators.rb +4 -4
  63. data/lib/twitch/resources/pinned_chat_messages.rb +4 -11
  64. data/lib/twitch/resources/polls.rb +1 -1
  65. data/lib/twitch/resources/predictions.rb +1 -1
  66. data/lib/twitch/resources/raids.rb +3 -4
  67. data/lib/twitch/resources/search.rb +2 -2
  68. data/lib/twitch/resources/shield_mode.rb +18 -0
  69. data/lib/twitch/resources/shoutouts.rb +1 -1
  70. data/lib/twitch/resources/stream_markers.rb +1 -1
  71. data/lib/twitch/resources/stream_schedule.rb +4 -5
  72. data/lib/twitch/resources/streams.rb +2 -2
  73. data/lib/twitch/resources/subscriptions.rb +13 -2
  74. data/lib/twitch/resources/suspicious_users.rb +6 -2
  75. data/lib/twitch/resources/teams.rb +20 -0
  76. data/lib/twitch/resources/unban_requests.rb +2 -2
  77. data/lib/twitch/resources/users.rb +37 -43
  78. data/lib/twitch/resources/videos.rb +3 -3
  79. data/lib/twitch/resources/vips.rb +3 -3
  80. data/lib/twitch/resources/warnings.rb +2 -2
  81. data/lib/twitch/resources/whispers.rb +1 -1
  82. data/lib/twitch/version.rb +1 -1
  83. data/lib/twitch.rb +33 -9
  84. data/twitchrb.gemspec +5 -5
  85. metadata +42 -18
  86. data/lib/twitch/objects/banned_event.rb +0 -4
  87. data/lib/twitch/objects/followed_user.rb +0 -4
  88. data/lib/twitch/objects/hype_train_event.rb +0 -4
  89. data/lib/twitch/objects/moderator_event.rb +0 -4
  90. data/lib/twitch/resources/banned_events.rb +0 -8
  91. data/lib/twitch/resources/hype_train_events.rb +0 -10
  92. data/lib/twitch/resources/moderator_events.rb +0 -9
  93. data/lib/twitch/resources/tags.rb +0 -18
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9fbfacc0abeb1677c2f16b79eefeaaaedb1b7ff4f3506fcf2f465ffb82735f78
4
- data.tar.gz: 2a04bfacd176f1287cacfe55c939550a8b2b92f63b207aead8ae48dc47de0508
3
+ metadata.gz: 0641bf783f69ad1e15ce425ab0a04932376a98403eb996cae29e44cb04509869
4
+ data.tar.gz: c50b205b48bc9671724f848e81329ff980873f598fb278da24c344c753ff1768
5
5
  SHA512:
6
- metadata.gz: d472b2b93b0aaacaf635079e4dd1a35d213026f0c517dd7c2f6b411f7a1caf8121fd652b46672c145730cd648f94aa5206c0655fd8d2bf08508f11b257facdb4
7
- data.tar.gz: f175c566b480a93032f9fb19cfeb490f9834d5c8f58aa4f2141fd2488f3191047f556cd90518f166e00acd8ffb581e3b214161a90aee317d4621e49dbdfa3158
6
+ metadata.gz: f5f5d1850b6595dce58b11f9b2cd4756f3ae00043ce22c6643d20fd133232270abf6d24360b4d2a2ef7c3220b1b1cf888745ac418ce7582c3cf220c022bfca4a
7
+ data.tar.gz: 32e637838de8ea70e207655e3d870a7f7f80a021f4fb3afe4211f74293f6fcfce54e525d7f79ea859908bc2cf7f26277d3109812132610e7b48b4fe0659c0322
@@ -8,7 +8,7 @@ jobs:
8
8
  continue-on-error: true
9
9
  steps:
10
10
  - name: Checkout code
11
- uses: actions/checkout@v6
11
+ uses: actions/checkout@v7
12
12
  - name: Set up Ruby
13
13
  uses: ruby/setup-ruby@v1
14
14
  with:
@@ -28,7 +28,7 @@ jobs:
28
28
  - '3.4'
29
29
  - '4.0'
30
30
  steps:
31
- - uses: actions/checkout@v6
31
+ - uses: actions/checkout@v7
32
32
  - uses: ruby/setup-ruby@v1
33
33
  with:
34
34
  ruby-version: ${{ matrix.ruby_version }}
data/.rubocop.yml CHANGED
@@ -4,7 +4,7 @@ inherit_gem: { rubocop-rails-omakase: rubocop.yml }
4
4
  AllCops:
5
5
  Exclude:
6
6
  - 'test/**/*'
7
- TargetRubyVersion: 4.0
7
+ TargetRubyVersion: 3.3
8
8
 
9
9
  # Overwrite or add rules to create your own house style
10
10
  #
data/CHANGELOG.md CHANGED
@@ -4,7 +4,110 @@ All notable changes to `twitchrb` are documented in this file.
4
4
 
5
5
  Published release notes were sourced from GitHub releases where available. Older tag-only versions and the current unreleased work were reconstructed from local git history.
6
6
 
7
- ## [1.10.0] - Unreleased
7
+ ## [2.0.0] - 2026-09-23
8
+
9
+ This release adds every remaining Helix endpoint, automatic pagination, automatic token refresh, and EventSub
10
+ webhook verification, and fixes many requests that didn't match the Twitch API reference. It contains breaking
11
+ changes, listed below.
12
+
13
+ ### Upgrading from 1.x
14
+
15
+ - **Ruby 3.3 or newer is required.**
16
+ - **Methods for endpoints Twitch has shut down were removed:**
17
+ - `hype_train_events.list` → use `hype_train_status.retrieve(broadcaster_id:)`.
18
+ - `users.follows` and `users.following?` → use `channels.followers(broadcaster_id:, user_id:)` to check whether a
19
+ user follows a channel, or `channels.followed(user_id:)` to list the channels a user follows.
20
+ - `tags.list`, `tags.stream`, and `tags.replace` → channel tags are returned by `channels.retrieve` and set with
21
+ `channels.update(broadcaster_id:, tags: [...])`.
22
+ - `banned_events.list` and `moderator_events.list` → no API replacement; use the `channel.ban`, `channel.unban`,
23
+ and `channel.moderate` EventSub subscriptions.
24
+ - **`oauth.create`, `oauth.refresh`, and `oauth.device` raise errors instead of returning `false`.** Replace checks
25
+ like `if token = oauth.refresh(...)` with a `rescue`:
26
+
27
+ ```ruby
28
+ begin
29
+ token = oauth.refresh(refresh_token: refresh_token)
30
+ rescue Twitch::Error => e
31
+ e.twitch_error_message #=> "Invalid refresh token"
32
+ end
33
+ ```
34
+
35
+ `oauth.validate` and `oauth.revoke` still return `false`.
36
+ - **Missing required arguments raise `ArgumentError`** instead of `RuntimeError`. Update any `rescue RuntimeError`.
37
+ - **`to_h` on response objects now converts nested objects to hashes too.** If you called methods on nested values
38
+ from `to_h` (e.g. `object.to_h[:current].id`), use hash access instead (`object.to_h[:current][:id]`), or call the
39
+ method on the object itself (`object.current.id`).
40
+
41
+ ### Changed
42
+ - Missing required arguments (e.g. calling `clips.list` without `broadcaster_id`, `game_id` or `id`) now raise `ArgumentError` instead of `RuntimeError`.
43
+ - **Breaking:** `oauth.create`, `oauth.refresh`, and `oauth.device` now raise errors (e.g. `Twitch::Errors::BadRequestError`, with Twitch's message in `twitch_error_message`) instead of returning `false`. `oauth.validate` and `oauth.revoke` still return `false`.
44
+ - The minimum supported Ruby version is now 3.3 (previously declared as 2.3, though the gem already required 3.1+). This matches the versions tested in CI.
45
+
46
+ ### Added
47
+ - `subscriptions.subscribed?(broadcaster_id:, user_id:)`, which returns `true` or `false` instead of raising when the user isn't subscribed.
48
+ - Automatic token refresh: pass `refresh_token:` (and `client_secret:`, unless your app is a public client) to `Twitch::Client.new`, and requests that fail because the access token expired are retried once with a refreshed token. `on_token_refresh:` is called with the new token so you can store it, and `client.refresh_access_token!` refreshes manually.
49
+ - Automatic pagination: collections from paginated endpoints now have `next_page?`, `next_page`, `each_page`, and `auto_paginate`, which lazily iterates over every item across pages (e.g. `auto_paginate.first(250)` only fetches the pages it needs).
50
+ - `Twitch::EventsubWebhook` to verify and parse EventSub webhook requests. It checks the HMAC signature in constant time, rejects messages older than 10 minutes, and gives access to the message type, challenge, subscription, and event.
51
+ - `oauth.exchange_code(code:, redirect_uri:)` for the authorization code grant flow, and `oauth.device_token(device_code:, scopes:)` to finish the device code grant flow. Previously neither flow could be completed.
52
+ - `oauth.create` sends extra keyword arguments (such as `code` and `redirect_uri`) with the request, and `scope`/`scopes` accept arrays.
53
+ - `Twitch::OAuth.new` no longer requires a `client_secret`, for public clients using the device code flow.
54
+ - `ads.schedule` and `ads.snooze` (Get Ad Schedule, Snooze Next Ad).
55
+ - `analytics.extensions` and `analytics.games`.
56
+ - `bits.leaderboard` and `bits.cheermotes`.
57
+ - `charity_campaigns.donations`.
58
+ - `chat_settings.retrieve` and `chat_settings.update`.
59
+ - `shield_mode.retrieve` and `shield_mode.update`.
60
+ - `content_classification_labels.list`.
61
+ - `teams.retrieve` and `teams.channel`.
62
+ - `drops_entitlements.list` and `drops_entitlements.update`.
63
+ - `users.extensions`, `users.active_extensions`, and `users.update_extensions`.
64
+ - An `extensions` resource covering the Extensions API: `retrieve`, `released`, `live_channels`, `configuration`, `set_configuration`, `set_required_configuration`, `send_pubsub_message`, `send_chat_message`, `secrets`, `create_secret`, `bits_products`, `update_bits_product`, and `transactions`.
65
+ - A `guest_star` resource covering the Guest Star beta API.
66
+
67
+ ### Removed
68
+ - Removed methods for endpoints Twitch has shut down, which could only return errors:
69
+ - `hype_train_events.list`, which forwarded to `hype_train_status.retrieve` with a deprecation warning since 1.10.0.
70
+ - `banned_events.list` and `moderator_events.list` (Get Banned Events / Get Moderator Events).
71
+ - `users.follows` and `users.following?` (`GET /users/follows`). Use `channels.followers` or `channels.followed` instead.
72
+ - `tags.list`, `tags.stream`, and `tags.replace` (the old Twitch-defined stream tags). Channel tags are now read with `channels.retrieve` and set with `channels.update(tags: [...])`.
73
+ - Removed the now-unused `Twitch::BannedEvent`, `Twitch::ModeratorEvent`, `Twitch::FollowedUser`, `Twitch::HypeTrainEvent`, and `Twitch::Tag` classes.
74
+
75
+ ### Fixed
76
+ - Fixed multi-value query params (e.g. `users.retrieve(ids:)`, `games.retrieve(names:)`, `streams.list(user_id: [...])`, `clips.downloads(clip_ids:)`) being sent as `id[]=1&id[]=2`. They are now sent as repeated keys (`id=1&id=2`), which is the format Helix expects.
77
+ - Fixed write endpoints sending query string parameters in the JSON body instead of the query string, contrary to the Twitch API reference. Affects `channels.update`, `custom_rewards.create`/`update`, `automod.check_status`/`check_status_multiple`/`update_settings`, `banned_users.create`, `blocked_terms.create`, `unban_requests.resolve`, `moderators.create`, `vips.create`, `raids.create`, `whispers.create`, `stream_schedule.update`/`create_segment`/`update_segment`, `users.update`, and `users.block_user` (whose `source_context` and `reason` options were being sent in the body).
78
+ - Fixed `clips.list` and `videos.list` rejecting calls that only pass `id`, which both endpoints accept.
79
+ - Fixed `eventsub_conduits.update_shards` discarding the `errors` Twitch returns for shards that failed to update. They are now available as `result.errors`, and `Collection#errors` is available for any endpoint that reports partial failures.
80
+ - `eventsub_conduits.update_shards` now sends lists of more than 100 shards in batches of 100, the most Twitch accepts per request.
81
+ - Fixed `oauth.device` sending `scope` instead of `scopes`, which Twitch requires.
82
+ - Fixed `to_h` and `to_json` on response objects leaving nested objects as `OpenStruct`s, which serialized as strings like `"#<OpenStruct ...>"`. Nested objects and arrays are now converted to plain hashes, and `as_json` is defined for Rails.
83
+ - `Collection#cursor` now works for endpoints that return `pagination` as a bare string (such as Get Extension Live Channels) instead of raising.
84
+ - `banned_users.create` no longer sends `"duration": null` for permanent bans.
85
+ - Helix and OAuth requests now have default timeouts (30s read, 10s open) instead of waiting indefinitely. Configure with the `timeout:` and `open_timeout:` options on `Twitch::Client.new` and `Twitch::OAuth.new`.
86
+
87
+ ## [1.11.0] - 2026-08-11
88
+
89
+ ### Fixed
90
+ - Fixed a `NoMethodError` crash when API responses have non-JSON bodies, such as `stream_schedule.icalendar` (which was completely broken) and HTML error pages from proxies.
91
+ - Fixed `users.retrieve` and `games.retrieve` returning `nil` when a plural lookup (`ids`, `usernames`, `names`) matched exactly one item; plural lookups now always return a `Collection`. Singular lookups with no match now return `nil` instead of an empty object.
92
+ - Fixed `oauth.revoke` always returning `true`; it now returns `false` when revocation fails, matching `validate`, `create`, and `refresh`.
93
+ - Fixed `blocked_terms.create` returning a `BannedUser` instead of a `BlockedTerm`.
94
+ - Fixed `suspicious_users.delete` crashing on 204 No Content responses; it now returns `true`.
95
+ - Fixed query string values not being escaped in request paths. Notably, `users.update_color` silently dropped hex colors like `#9146FF`.
96
+ - Errors are now raised for any 4xx/5xx response; previously 422, 502, and 504 slipped through unraised.
97
+ - `Collection#total` now reports the `total` field from the API for paginated endpoints instead of the page size, and responses without a `data` key return an empty collection instead of raising.
98
+ - Removed a leftover debug `puts` in `users.get_color`.
99
+ - Error messages for unmapped statuses no longer duplicate the Twitch message.
100
+ - Updated the minimum Faraday version to 2.14.3 to fix the uncontrolled recursion denial-of-service vulnerability in `NestedParamsEncoder` (CVE-2026-54297).
101
+
102
+ ### Changed
103
+ - The `auto_retry_rate_limit` client option (default `true`) now works: requests that hit a 429 wait until the rate limit window resets and retry once. Previously the option was accepted but ignored.
104
+ - All API errors now inherit from `Twitch::Error`, so they can be rescued with a single base class.
105
+ - `eventsub_subscriptions.create` now goes through the shared request helpers, gaining request path validation and rate limit auto-retry.
106
+
107
+ ### Added
108
+ - `users.get_color` accepts an array for `user_ids`, in line with other multi-id endpoints. Comma-separated strings still work.
109
+
110
+ ## [1.10.0] - 2026-05-16
8
111
 
9
112
  ### Added
10
113
  - Added custom power-up API support.
data/Gemfile.lock CHANGED
@@ -1,8 +1,8 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- twitchrb (1.10.0)
5
- faraday (>= 2.14.1, < 3)
4
+ twitchrb (2.0.0)
5
+ faraday (>= 2.14.3, < 3)
6
6
  ostruct (~> 0.6.0)
7
7
 
8
8
  GEM
@@ -27,7 +27,7 @@ GEM
27
27
  benchmark (0.5.0)
28
28
  bigdecimal (4.1.2)
29
29
  cgi (0.5.1)
30
- concurrent-ruby (1.3.6)
30
+ concurrent-ruby (1.3.8)
31
31
  connection_pool (3.0.2)
32
32
  crack (1.0.1)
33
33
  bigdecimal
@@ -36,7 +36,7 @@ GEM
36
36
  dotenv (3.2.0)
37
37
  drb (2.2.3)
38
38
  erb (6.0.4)
39
- faraday (2.14.2)
39
+ faraday (2.14.3)
40
40
  faraday-net_http (>= 2.0, < 3.5)
41
41
  json
42
42
  logger
@@ -51,7 +51,7 @@ GEM
51
51
  prism (>= 1.3.0)
52
52
  rdoc (>= 4.0.0)
53
53
  reline (>= 0.4.2)
54
- json (2.19.5)
54
+ json (2.21.2)
55
55
  language_server-protocol (3.17.0.5)
56
56
  lint_roller (1.1.0)
57
57
  logger (1.7.0)