@kody/twitch
README.md
181 lines · 8.3 KB · Markdown@kody/twitch
Official Twitch Glitch logo (#9146FF) from Twitch brand guidelines.
Intent
Give any Kody account reusable, headless Twitch Helix helpers for user and channel lookup, live stream status, and follows as Helix allows. Writes (chat and channel settings) preview with dryRun: true and run only after confirm: true. Author identity is always resolved from the connected token — never hard-coded to a specific channel.
This listing is meant to be forked. After you fork, connect your Twitch account and run ./smoke-test on your copy. Do not treat the live @kody/twitch integration as yours.
When To Use
- Look up Twitch users or channel title/game metadata
- Check whether one or more channels are live
- List channels the authorizing user follows, or live streams from those channels
- Read a channel’s follower total (and the follower list when Helix allows it)
- Preview a chat message or channel-title update with
dryRun: true, then apply it only afterconfirm: true - Call uncommon Helix endpoints through
./request
Do not use this package as an EventSub receiver, a chat bot framework, or a place to paste access tokens.
After you fork
- Fork this community listing into the user's Kody account (kody id stays
twitch). - Connect Twitch with the prefilled URL below, then run Smoke test on the forked package.
- Only then call lookup, stream, follow, or write helpers. Pass
integrationwhen the connection is not namedtwitch.
OAuth setup
Twitch is bring-your-own OAuth. There is no built-in Kody Twitch app. Tokens come from the hosted connect page (createAuthenticatedFetch('twitch')). Never paste a client secret or access token into chat.
Helix requires both Authorization and Client-Id. Both come from the saved integration (clientId is sent as Client-Id on every call).
- Open dev.twitch.tv/console/apps → Register Your Application.
- Set OAuth Redirect URLs to exactly
https://kody.codes/connect/oauth(the connect page shows the same value with a copy button). - Category: Application Integration.
- Note the app’s Client ID and Client Secret (paste them into Kody, not into chat).
- Open this prefilled connect URL while signed in to Kody:
https://kody.codes/connect/oauth?provider=twitchFirst-time setup also needs Twitch’s authorize and token URLs. Use this complete prefilled URL when the connection does not exist yet:
https://kody.codes/connect/oauth?provider=twitch&authorizeUrl=https%3A%2F%2Fid.twitch.tv%2Foauth2%2Fauthorize&tokenUrl=https%3A%2F%2Fid.twitch.tv%2Foauth2%2Ftoken&apiBaseUrl=https%3A%2F%2Fapi.twitch.tv%2Fhelix&flow=confidential&tokenExchangeStyle=form&allowedHosts=api.twitch.tv%2Cid.twitch.tv&dashboardUrl=https%3A%2F%2Fdev.twitch.tv%2Fconsole%2Fapps&scopes=user%3Aread%3Afollows%20moderator%3Aread%3Afollowers%20user%3Awrite%3Achat%20moderator%3Aread%3Achatters%20channel%3Amanage%3AbroadcastDecoded:
- Redirect / callback:
https://kody.codes/connect/oauth - Authorize:
https://id.twitch.tv/oauth2/authorize - Token:
https://id.twitch.tv/oauth2/token - API base:
https://api.twitch.tv/helix - Flow:
confidentialwithtokenExchangeStyle=form - Hosts:
api.twitch.tv,id.twitch.tv - Scopes:
user:read:follows,moderator:read:followers,user:write:chat,moderator:read:chatters,channel:manage:broadcast
- Paste the Client ID and Client Secret into the Kody form, continue to Twitch, and approve.
- Run Smoke test on the forked package.
Reconnect the same connection with https://kody.codes/connect/oauth?provider=twitch. Kody reuses the saved authorize/token endpoints.
To connect a second Twitch account, change provider to a distinct name such as twitch-work, then pass integration: 'twitch-work' on every helper call.
Scopes
| Scope | Used by |
|---|---|
| none extra | ./smoke-test, ./get-me, ./get-user, ./get-channel, ./get-stream |
user:read:follows | ./list-follows, ./list-followed-streams |
moderator:read:followers | ./list-followers (follower list; total is returned without it) |
moderator:read:chatters | ./list-chatters |
user:write:chat | ./send-chat-message |
channel:manage:broadcast | ./update-channel-info |
./request uses whatever scopes the saved token already has. ./smoke-test does not return names or emails.
Helix GET /channels/followers returns only the follower total unless the token user is the broadcaster or a moderator of that channel and the token includes moderator:read:followers. The old GET /users/follows endpoint is gone.
Smoke test
After connect or reconnect, invoke ./smoke-test in the forked package runtime (not a static import):
import { packages } from 'kody:runtime'
export default async function main() {
return await packages.invoke({
kodyId: 'twitch',
exportName: './smoke-test',
params: {
// integration: 'twitch-work',
},
})
}Success looks like { ok: true, integration: 'twitch', hasUserId: true, hasLogin: true }. It does not return login, display name, or email.
Low-level equivalent (execute exploration only):
import { createAuthenticatedFetch, kody } from 'kody:runtime'
export default async function main() {
const integration = await kody.integration_get({ name: 'twitch' })
const clientId = integration.integration?.clientId
if (!clientId) throw new Error('Connect Twitch first.')
const twitchFetch = await createAuthenticatedFetch('twitch')
const response = await twitchFetch('https://api.twitch.tv/helix/users', {
headers: { 'Client-Id': clientId, Accept: 'application/json' },
})
if (!response.ok) throw new Error('Twitch /users failed: ' + response.status)
const body = (await response.json()) as { data?: Array<{ id?: string }> }
return { ok: true, hasUserId: Boolean(body.data?.[0]?.id) }
}dryRun and writes
./send-chat-message, ./update-channel-info, and non-GET ./request never mutate Twitch when dryRun: true. A live write requires a fresh confirm: true after the user approved the exact payload.
import sendChatMessage from 'kody:@kody/twitch/send-chat-message'
export default async function main() {
return sendChatMessage({
broadcasterLogin: 'twitchdev',
message: 'Hello from Kody',
dryRun: true,
})
}Exports
kody:@kody/twitch— package overview, connect URL, and scopeskody:@kody/twitch/smoke-test— verify/usersaccess without returning PIIkody:@kody/twitch/get-me— authenticated user public profilekody:@kody/twitch/get-user— look up users by login or idkody:@kody/twitch/get-channel— channel title, game, and tagskody:@kody/twitch/get-stream— live/offline status for one or more channelskody:@kody/twitch/list-follows— channels the token user followskody:@kody/twitch/list-followers— follower total, plus the list when Helix allows itkody:@kody/twitch/list-followed-streams— live streams from followed channelskody:@kody/twitch/list-chatters— chatters in a channelkody:@kody/twitch/send-chat-message— preview (dryRun) or send (confirm: true)kody:@kody/twitch/update-channel-info— preview or update title/game (confirm: true)kody:@kody/twitch/request— authenticated Helix escape hatch
Examples
import getUser from 'kody:@kody/twitch/get-user'
import getStream from 'kody:@kody/twitch/get-stream'
export default async function main() {
const [user] = await getUser({ login: 'twitchdev' })
const [stream] = await getStream({ login: user.login })
return { user, stream }
}import listFollows from 'kody:@kody/twitch/list-follows'
export default async function main() {
return listFollows({ limit: 20 })
}Troubleshooting
- Connect page asks for authorize/token URLs: use the complete first-time URL in OAuth setup.
- HTTP 401 / expired token: reconnect at
https://kody.codes/connect/oauth?provider=twitch. - HTTP 403 / missing scope: add the scope on the Twitch app, then reconnect. The error names the reconnect URL.
- Follower list is empty but
totalis set: the token user is not the broadcaster/moderator, ormoderator:read:followersis missing. redirect_urimismatch: the Twitch app redirect must be exactlyhttps://kody.codes/connect/oauth.- Host approval for
api.twitch.tvstays in the account security UI.