Skip to content
This repository was archived by the owner on Apr 13, 2025. It is now read-only.

Update twurple from v5 to latest v7 #1167

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions nodecg-io-core/dashboard/bundles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,9 @@ export function renderInstanceSelector(): void {
return;
}

const currentInstance = config.data.bundles[bundle]?.find((dep) => dep.serviceType === serviceType)
?.serviceInstance;
const currentInstance = config.data.bundles[bundle]?.find(
(dep) => dep.serviceType === serviceType,
)?.serviceInstance;

let index = 0;
for (let i = 0; i < selectBundleInstance.options.length; i++) {
Expand Down
287 changes: 95 additions & 192 deletions package-lock.json

Large diffs are not rendered by default.

23 changes: 17 additions & 6 deletions samples/twitch-api/extension/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,24 @@ module.exports = function (nodecg: NodeCG.ServerAPI) {

twitchApi?.onAvailable(async (client) => {
nodecg.log.info("Twitch api client has been updated, getting user info.");
const user = await client.helix.users.getMe();
const follows = await user.getFollows();
const stream = await user.getStream();
const tokenInfo = await client.getTokenInfo();
const userId = tokenInfo.userId;

if (!userId) {
nodecg.log.info("Unable to determine authenticated user");
return;
}

const user = await client.users.getUserById(userId);
if (!user) {
nodecg.log.info("Unable to get user info");
return;
}

const follows = await user?.getFollowedChannels();
const stream = await user?.getStream();
nodecg.log.info(
`You are user "${user.name}", follow ${follows.total} people and are${
stream === null ? " not" : ""
} streaming.`,
`You are user "${user.name}", follow ${follows.total} people and are${stream === null ? " not" : ""} streaming.`,
);
});

Expand Down
4 changes: 2 additions & 2 deletions samples/twitch-chat/extension/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ module.exports = function (nodecg: NodeCG.ServerAPI) {
const twitch = requireService<TwitchChatServiceClient>(nodecg, "twitch-chat");

// Hardcoded channels for testing purposes.
// Note that this does need a # before the channel name and is case-insensitive.
const twitchChannels = ["#skate702", "#daniel0611"];
// Note that this is case-insensitive.
const twitchChannels = ["skate702", "hlxid"];

// Once the service instance has been set we add listeners for messages in the corresponding channels.
twitch?.onAvailable((client) => {
Expand Down
10 changes: 6 additions & 4 deletions samples/twitch-pubsub/extension/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,19 @@ module.exports = function (nodecg: NodeCG.ServerAPI) {
const pubsub = requireService<TwitchPubSubServiceClient>(nodecg, "twitch-pubsub");

pubsub?.onAvailable((client) => {
const channelName = "skate702";

nodecg.log.info("PubSub client has been updated, adding handlers for messages.");
client.onSubscription((message) => {
client.onSubscription(channelName, (message) => {
nodecg.log.info(`${message.userDisplayName} just subscribed (${message.cumulativeMonths} months)`);
});
client.onBits((message) => {
client.onBits(channelName, (message) => {
nodecg.log.info(`${message.userName} cheered ${message.bits} Bits`);
});
client.onBitsBadgeUnlock((message) => {
client.onBitsBadgeUnlock(channelName, (message) => {
nodecg.log.info(`${message.userName} just unlocked the ${message.badgeTier} Badge`);
});
client.onRedemption((message) => {
client.onRedemption(channelName, (message) => {
nodecg.log.info(`${message.userDisplayName} redeemed ${message.rewardTitle} (${message.message})`);
});
});
Expand Down
2 changes: 1 addition & 1 deletion services/nodecg-io-twitch-api/extension/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import NodeCG from "@nodecg/types";
import { Result, emptySuccess, success, ServiceBundle, Logger } from "nodecg-io-core";
import { ApiClient } from "@twurple/api";
import { Result, emptySuccess, success, ServiceBundle, Logger } from "nodecg-io-core";
import { createAuthProvider, getTokenInfo, TwitchServiceConfig } from "nodecg-io-twitch-auth";

export type TwitchApiServiceClient = ApiClient;
Expand Down
2 changes: 1 addition & 1 deletion services/nodecg-io-twitch-api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,6 @@
"dependencies": {
"nodecg-io-core": "^0.3.0",
"nodecg-io-twitch-auth": "^0.3.0",
"@twurple/api": "^5.3.4"
"@twurple/api": "^7.2.0"
}
}
3 changes: 2 additions & 1 deletion services/nodecg-io-twitch-chat/extension/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ class TwitchService extends ServiceBundle<TwitchServiceConfig, TwitchChatService
}

stopClient(client: TwitchChatServiceClient, logger: Logger): void {
client.quit().then(() => logger.info("Successfully stopped twitch client."));
client.quit();
logger.info("Successfully stopped twitch client.");
}

removeHandlers(client: TwitchChatServiceClient): void {
Expand Down
13 changes: 8 additions & 5 deletions services/nodecg-io-twitch-chat/extension/twitchClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,14 @@ export class TwitchChatServiceClient extends ChatClient {

// Create the actual chat client and connect
const chatClient = new TwitchChatServiceClient({ authProvider });
await chatClient.connect();
chatClient.connect();

// This also waits till it has registered itself at the IRC server, which is needed to do anything.
await new Promise((resolve, _reject) => {
chatClient.onRegister(() => resolve(undefined));
// This also waits till it has connected and registered itself at the IRC server, which is needed to do anything.
await new Promise((resolve, reject) => {
chatClient.onConnect(() => resolve(undefined));
chatClient.onAuthenticationFailure(() => {
reject("Authentication failed");
});
});

return chatClient;
Expand All @@ -31,7 +34,7 @@ export class TwitchChatServiceClient extends ChatClient {
* @param channel the channel to join
*/
join(channel: string): Promise<void> {
this.onRegister(() => {
this.onConnect(() => {
this.join(channel);
});

Expand Down
2 changes: 1 addition & 1 deletion services/nodecg-io-twitch-chat/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,6 @@
"dependencies": {
"nodecg-io-core": "^0.3.0",
"nodecg-io-twitch-auth": "^0.3.0",
"@twurple/chat": "^5.3.4"
"@twurple/chat": "^7.2.0"
}
}
40 changes: 29 additions & 11 deletions services/nodecg-io-twitch-pubsub/extension/pubSubClient.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,21 @@
import { BasicPubSubClient, SingleUserPubSubClient } from "@twurple/pubsub";
import { BasicPubSubClient, PubSubClient } from "@twurple/pubsub";
import { createAuthProvider, TwitchServiceConfig } from "nodecg-io-twitch-auth";
import { AuthProvider } from "@twurple/auth";
import { PubSubClientConfig } from "@twurple/pubsub/lib/PubSubClient";

export class TwitchPubSubServiceClient extends SingleUserPubSubClient {
export class TwitchPubSubServiceClient extends PubSubClient {
private basicClient: BasicPubSubClient;
constructor(auth: AuthProvider, basicClient: BasicPubSubClient) {
super({ authProvider: auth, pubSubClient: basicClient });
this.basicClient = basicClient;

constructor(config: PubSubClientConfig) {
super(config);

// Get reference to underlying client.
// Very ugly but not possible differently.
// This is a private field and may change but we need it
// to add listeners for disconnect/connection failures
// to the underlying basic client and force connection to
// ensure valid credentials.
//@ts-expect-error private field
this.basicClient = this._basicClient;
}

/**
Expand All @@ -17,14 +26,23 @@ export class TwitchPubSubServiceClient extends SingleUserPubSubClient {
const authProvider = await createAuthProvider(cfg);

// Create the actual pubsub client and connect
const basicClient = new BasicPubSubClient();
const pubSubClient = new TwitchPubSubServiceClient(authProvider, basicClient);
const pubSubClient = new TwitchPubSubServiceClient({ authProvider });

await basicClient.connect();
pubSubClient.basicClient.connect();
await new Promise((resolve, reject) => {
pubSubClient.basicClient.onConnect(() => resolve(null));
// 15 second timeout
setTimeout(() => reject("Timeout for PubSub connection was exceeded"), 15000);
});
return pubSubClient;
}

disconnect(): Promise<void> {
return this.basicClient.disconnect();
async disconnect(): Promise<void> {
this.basicClient.disconnect();
await new Promise((resolve, reject) => {
this.basicClient.onDisconnect(() => resolve(null));
// 15 second timeout
setTimeout(() => reject("Timeout for PubSub disconnection was exceeded"), 15000);
});
}
}
4 changes: 2 additions & 2 deletions services/nodecg-io-twitch-pubsub/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
"dependencies": {
"nodecg-io-core": "^0.3.0",
"nodecg-io-twitch-auth": "^0.3.0",
"@twurple/api": "^5.3.4",
"@twurple/pubsub": "^5.3.4"
"@twurple/api": "^7.2.0",
"@twurple/pubsub": "^7.2.0"
}
}
2 changes: 1 addition & 1 deletion utils/nodecg-io-twitch-auth/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,6 @@
"typescript": "^5.4.3"
},
"dependencies": {
"@twurple/auth": "^5.3.4"
"@twurple/auth": "^7.2.0"
}
}