fix probe logic
This commit is contained in:
parent
7234f9d24b
commit
3dbca21334
@ -59,45 +59,23 @@ function readStringParam(
|
|||||||
return options.trim !== false ? str.trim() : str;
|
return options.trim !== false ? str.trim() : str;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Supported Twitch actions */
|
||||||
|
const TWITCH_ACTIONS = new Set(["send" as const]);
|
||||||
|
type TwitchAction = typeof TWITCH_ACTIONS extends Set<infer U> ? U : never;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Twitch message actions adapter.
|
* Twitch message actions adapter.
|
||||||
*
|
|
||||||
* Supports the "send" action for sending messages to Twitch channels.
|
|
||||||
*
|
|
||||||
* NOTE: Currently only the "send" action is supported. The action gate pattern
|
|
||||||
* (configurable actions per channel) will be added in a future update. For now,
|
|
||||||
* the available actions are hardcoded as Twitch chat only supports sending messages.
|
|
||||||
*/
|
*/
|
||||||
export const twitchMessageActions: ChannelMessageActionAdapter = {
|
export const twitchMessageActions: ChannelMessageActionAdapter = {
|
||||||
/**
|
/**
|
||||||
* List available actions for this channel.
|
* List available actions for this channel.
|
||||||
*
|
|
||||||
* Currently supports:
|
|
||||||
* - "send" - Send a message to a Twitch channel
|
|
||||||
*
|
|
||||||
* Future actions may include:
|
|
||||||
* - "ban"/"timeout" - Moderation actions
|
|
||||||
* - "announce" - Send announcements
|
|
||||||
*
|
|
||||||
* @param params - Parameters including config
|
|
||||||
* @returns Array of available action names
|
|
||||||
*/
|
*/
|
||||||
listActions: () => {
|
listActions: () => [...TWITCH_ACTIONS],
|
||||||
// Action gate pattern: In future, this will check channel config to determine
|
|
||||||
// which actions are enabled. For now, all Twitch channels support "send".
|
|
||||||
const actions = new Set<string>(["send"]);
|
|
||||||
return Array.from(actions);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if an action is supported.
|
* Check if an action is supported.
|
||||||
*
|
|
||||||
* @param params - Action to check
|
|
||||||
* @returns true if the action is supported
|
|
||||||
*/
|
*/
|
||||||
supportsAction: ({ action }) => {
|
supportsAction: ({ action }) => TWITCH_ACTIONS.has(action as TwitchAction),
|
||||||
return action === "send";
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extract tool send parameters from action arguments.
|
* Extract tool send parameters from action arguments.
|
||||||
|
|||||||
@ -22,7 +22,7 @@ const TwitchAccountSchema = z.object({
|
|||||||
enabled: z.boolean().optional(),
|
enabled: z.boolean().optional(),
|
||||||
/** Allowlist of Twitch user IDs who can interact with the bot (use IDs for safety, not usernames) */
|
/** Allowlist of Twitch user IDs who can interact with the bot (use IDs for safety, not usernames) */
|
||||||
allowFrom: z.array(z.string()).optional(),
|
allowFrom: z.array(z.string()).optional(),
|
||||||
/** Roles allowed to interact with the bot (e.g., ["mod", "vip", "sub"]) */
|
/** Roles allowed to interact with the bot (e.g., ["moderator", "vip", "subscriber"]) */
|
||||||
allowedRoles: z.array(TwitchRoleSchema).optional(),
|
allowedRoles: z.array(TwitchRoleSchema).optional(),
|
||||||
/** Require @mention to trigger bot responses */
|
/** Require @mention to trigger bot responses */
|
||||||
requireMention: z.boolean().optional(),
|
requireMention: z.boolean().optional(),
|
||||||
|
|||||||
@ -40,14 +40,6 @@ export async function probeTwitch(
|
|||||||
let client: ChatClient | undefined;
|
let client: ChatClient | undefined;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Create a timeout promise
|
|
||||||
const timeout = new Promise<never>((_, reject) => {
|
|
||||||
setTimeout(
|
|
||||||
() => reject(new Error(`connection timeout after ${timeoutMs}ms`)),
|
|
||||||
timeoutMs,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Create auth provider with the token
|
// Create auth provider with the token
|
||||||
const authProvider = new StaticAuthProvider(
|
const authProvider = new StaticAuthProvider(
|
||||||
account.clientId ?? "",
|
account.clientId ?? "",
|
||||||
@ -59,11 +51,53 @@ export async function probeTwitch(
|
|||||||
authProvider,
|
authProvider,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Race between connection and timeout
|
// Create a promise that resolves when connected
|
||||||
await Promise.race([client.connect(), timeout]);
|
const connectionPromise = new Promise<void>((resolve, reject) => {
|
||||||
|
let settled = false;
|
||||||
|
let connectListener: ReturnType<ChatClient["onConnect"]> | undefined;
|
||||||
|
let disconnectListener: ReturnType<ChatClient["onDisconnect"]> | undefined;
|
||||||
|
let authFailListener: ReturnType<ChatClient["onAuthenticationFailure"]> | undefined;
|
||||||
|
|
||||||
// Wait a moment for the connection to fully establish
|
const cleanup = () => {
|
||||||
await new Promise<void>((resolve) => setTimeout(resolve, 500));
|
if (settled) return;
|
||||||
|
settled = true;
|
||||||
|
// Remove all listeners
|
||||||
|
connectListener?.unbind();
|
||||||
|
disconnectListener?.unbind();
|
||||||
|
authFailListener?.unbind();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Success: connection established
|
||||||
|
connectListener = client?.onConnect(() => {
|
||||||
|
cleanup();
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Failure: disconnected (e.g., auth failed)
|
||||||
|
disconnectListener = client?.onDisconnect((_manually, reason) => {
|
||||||
|
cleanup();
|
||||||
|
reject(reason || new Error("Disconnected"));
|
||||||
|
});
|
||||||
|
|
||||||
|
// Failure: authentication failed
|
||||||
|
authFailListener = client?.onAuthenticationFailure(() => {
|
||||||
|
cleanup();
|
||||||
|
reject(new Error("Authentication failed"));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Create timeout promise
|
||||||
|
const timeout = new Promise<never>((_, reject) => {
|
||||||
|
setTimeout(() => reject(new Error(`timeout after ${timeoutMs}ms`)), timeoutMs);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Set up listeners BEFORE connecting, then race against timeout
|
||||||
|
client.connect();
|
||||||
|
await Promise.race([connectionPromise, timeout]);
|
||||||
|
|
||||||
|
// Clean up connection before returning
|
||||||
|
client.quit();
|
||||||
|
client = undefined;
|
||||||
|
|
||||||
// If we got here, connection was successful
|
// If we got here, connection was successful
|
||||||
return {
|
return {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user