@gguf/claw
Version:
WhatsApp gateway CLI (Baileys web) with Pi RPC agent
179 lines (162 loc) • 5.7 kB
text/typescript
/**
* Twitch status issues collector.
*
* Detects and reports configuration issues for Twitch accounts.
*/
import type { ChannelAccountSnapshot, ChannelStatusIssue } from "./types.js";
import { getAccountConfig } from "./config.js";
import { resolveTwitchToken } from "./token.js";
import { isAccountConfigured } from "./utils/twitch.js";
/**
* Collect status issues for Twitch accounts.
*
* Analyzes account snapshots and detects configuration problems,
* authentication issues, and other potential problems.
*
* @param accounts - Array of account snapshots to analyze
* @param getCfg - Optional function to get full config for additional checks
* @returns Array of detected status issues
*
* @example
* const issues = collectTwitchStatusIssues(accountSnapshots);
* if (issues.length > 0) {
* console.warn("Twitch configuration issues detected:");
* issues.forEach(issue => console.warn(`- ${issue.message}`));
* }
*/
export function collectTwitchStatusIssues(
accounts: ChannelAccountSnapshot[],
getCfg?: () => unknown,
): ChannelStatusIssue[] {
const issues: ChannelStatusIssue[] = [];
for (const entry of accounts) {
const accountId = entry.accountId;
if (!accountId) {
continue;
}
let account: ReturnType<typeof getAccountConfig> | null = null;
let cfg: Parameters<typeof resolveTwitchToken>[0] | undefined;
if (getCfg) {
try {
cfg = getCfg() as {
channels?: { twitch?: { accounts?: Record<string, unknown> } };
};
account = getAccountConfig(cfg, accountId);
} catch {
// Ignore config access errors
}
}
if (!entry.configured) {
issues.push({
channel: "twitch",
accountId,
kind: "config",
message: "Twitch account is not properly configured",
fix: "Add required fields: username, accessToken, and clientId to your account configuration",
});
continue;
}
if (entry.enabled === false) {
issues.push({
channel: "twitch",
accountId,
kind: "config",
message: "Twitch account is disabled",
fix: "Set enabled: true in your account configuration to enable this account",
});
continue;
}
if (account && account.username && account.accessToken && !account.clientId) {
issues.push({
channel: "twitch",
accountId,
kind: "config",
message: "Twitch client ID is required",
fix: "Add clientId to your Twitch account configuration (from Twitch Developer Portal)",
});
}
const tokenResolution = cfg
? resolveTwitchToken(cfg as Parameters<typeof resolveTwitchToken>[0], { accountId })
: { token: "", source: "none" };
if (account && isAccountConfigured(account, tokenResolution.token)) {
if (account.accessToken?.startsWith("oauth:")) {
issues.push({
channel: "twitch",
accountId,
kind: "config",
message: "Token contains 'oauth:' prefix (will be stripped)",
fix: "The 'oauth:' prefix is optional. You can use just the token value, or keep it as-is (it will be normalized automatically).",
});
}
if (account.clientSecret && !account.refreshToken) {
issues.push({
channel: "twitch",
accountId,
kind: "config",
message: "clientSecret provided without refreshToken",
fix: "For automatic token refresh, provide both clientSecret and refreshToken. Otherwise, clientSecret is not needed.",
});
}
if (account.allowFrom && account.allowFrom.length === 0) {
issues.push({
channel: "twitch",
accountId,
kind: "config",
message: "allowFrom is configured but empty",
fix: "Either add user IDs to allowFrom, remove the allowFrom field, or use allowedRoles instead.",
});
}
if (
account.allowedRoles?.includes("all") &&
account.allowFrom &&
account.allowFrom.length > 0
) {
issues.push({
channel: "twitch",
accountId,
kind: "intent",
message: "allowedRoles is set to 'all' but allowFrom is also configured",
fix: "When allowedRoles is 'all', the allowFrom list is not needed. Remove allowFrom or set allowedRoles to specific roles.",
});
}
}
if (entry.lastError) {
issues.push({
channel: "twitch",
accountId,
kind: "runtime",
message: `Last error: ${entry.lastError}`,
fix: "Check your token validity and network connection. Ensure the bot has the required OAuth scopes.",
});
}
if (
entry.configured &&
!entry.running &&
!entry.lastStartAt &&
!entry.lastInboundAt &&
!entry.lastOutboundAt
) {
issues.push({
channel: "twitch",
accountId,
kind: "runtime",
message: "Account has never connected successfully",
fix: "Start the Twitch gateway to begin receiving messages. Check logs for connection errors.",
});
}
if (entry.running && entry.lastStartAt) {
const uptime = Date.now() - entry.lastStartAt;
const daysSinceStart = uptime / (1000 * 60 * 60 * 24);
if (daysSinceStart > 7) {
issues.push({
channel: "twitch",
accountId,
kind: "runtime",
message: `Connection has been running for ${Math.floor(daysSinceStart)} days`,
fix: "Consider restarting the connection periodically to refresh the connection. Twitch tokens may expire after long periods.",
});
}
}
}
return issues;
}