Please lmk if this isn’t a question for here (I’m really new to this).
I’m trying to subscribe to get notified whenever certain streamers go live, but for some reason I keep getting the error { error: 'Bad Request', status: 400, message: 'invalid transport and auth combination' }
I’m not sure what I’m doing wrong and would really appreciate any help. I put my whole code down below, as well as the docs pages I was looking at.
import axios from 'axios';
import WebSocket from 'ws';
const clientId = '7fv78wh6keb4j3c8oeoff979ejifdh';
const clientSecret = 'SECRET';
const channelName = 'CHANNEL_HERE';
export default class wsmanager {
/** @type { WebSocket } */
#ws;
#heartbeatint;
#authheaders;
#startHeartbeat() {
const timeBetweenPings = 30000;
this.#heartbeatint = setInterval(() => this.#ws.send(), timeBetweenPings);
console.log(`heartbeat started with interval ${timeBetweenPings}ms`);
}
async getTwitchOAuthToken() {
const tokenUrl = 'https://id.twitch.tv/oauth2/token';
const params = new URLSearchParams({
client_id: clientId,
client_secret: clientSecret,
grant_type: 'client_credentials',
});
try {
const response = await axios.post(tokenUrl, params);
const { access_token } = response.data;
return access_token;
} catch (error) {
console.error('Error obtaining OAuth token:', error.response.data);
throw error;
}
}
async getBroadcasterUserId(username, token) {
const userUrl = `https://api.twitch.tv/helix/users?login=${username}`;
try {
const response = await fetch(userUrl, {
method: 'GET',
headers: this.#authheaders,
});
if (!response.ok) {
throw new Error(`Error fetching user data: ${response.statusText}`);
}
const data = await response.json();
if (data.data.length === 0) {
throw new Error(`User not found: ${username}`);
}
const userId = data.data[0].id;
return userId;
} catch (error) {
console.error('Error fetching broadcaster user ID:', error);
throw error;
}
}
async connectToWebSocket(token) {
this.#authheaders = {
'Authorization': `Bearer ${token}`,
'Client-Id': '7fv78wh6keb4j3c8oeoff979ejifdh',
'Content-Type': 'application/json'
};
const wsUrl = 'wss://eventsub.wss.twitch.tv/ws',
uid = await this.getBroadcasterUserId(channelName, token)
this.#ws = new WebSocket(wsUrl);
this.#ws.on('open', () => {
console.log('Connected to Twitch WebSocket');
// Optionally, you can authenticate or subscribe to events here
});
this.#ws.on('message', (data) => {
const message = JSON.parse(data);
if (message.metadata && message.metadata.message_type === 'session_welcome') {
this.#startHeartbeat();
this.subscribeToStreamOnline(uid, token, message.payload.session.id);
}
});
this.#ws.on('close', (ev) => {
console.log('WebSocket connection closed with code', ev);
});
this.#ws.on('error', (error) => {
console.error('WebSocket error:', error);
});
}
async subscribeToStreamOnline(userId, token, session_id) {
const eventSubUrl = 'https://api.twitch.tv/helix/eventsub/subscriptions';
const body = {
type: 'stream.online',
version: '1',
condition: {
'broadcaster_user_id': userId,
},
transport: {
'method': 'websocket',
'session_id': session_id
},
};
try {
const response = await fetch(eventSubUrl, {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Client-Id': clientId,
'Content-Type': 'application/json',
},
body: JSON.stringify(body),
});
if (!response.ok) {
console.error(await response.json());
throw new Error();
}
const data = await response.json();
console.log('Subscription successful:', data);
} catch (error) {
console.error('Error subscribing to event:', error);
throw error;
}
}
async init() {
try {
const token = await this.getTwitchOAuthToken();
await this.connectToWebSocket(token);
} catch (error) {
console.error('Failed to connect or subscribe:', error.message);
}
}
constructor() { };
}
const temp = new wsmanager();
temp.init();