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;
|
||||
}
|
||||
|
||||
/** 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.
|
||||
*
|
||||
* 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 = {
|
||||
/**
|
||||
* 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: () => {
|
||||
// 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);
|
||||
},
|
||||
listActions: () => [...TWITCH_ACTIONS],
|
||||
|
||||
/**
|
||||
* Check if an action is supported.
|
||||
*
|
||||
* @param params - Action to check
|
||||
* @returns true if the action is supported
|
||||
*/
|
||||
supportsAction: ({ action }) => {
|
||||
return action === "send";
|
||||
},
|
||||
supportsAction: ({ action }) => TWITCH_ACTIONS.has(action as TwitchAction),
|
||||
|
||||
/**
|
||||
* Extract tool send parameters from action arguments.
|
||||
|
||||
@ -22,7 +22,7 @@ const TwitchAccountSchema = z.object({
|
||||
enabled: z.boolean().optional(),
|
||||
/** Allowlist of Twitch user IDs who can interact with the bot (use IDs for safety, not usernames) */
|
||||
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(),
|
||||
/** Require @mention to trigger bot responses */
|
||||
requireMention: z.boolean().optional(),
|
||||
|
||||
@ -40,14 +40,6 @@ export async function probeTwitch(
|
||||
let client: ChatClient | undefined;
|
||||
|
||||
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
|
||||
const authProvider = new StaticAuthProvider(
|
||||
account.clientId ?? "",
|
||||
@ -59,11 +51,53 @@ export async function probeTwitch(
|
||||
authProvider,
|
||||
});
|
||||
|
||||
// Race between connection and timeout
|
||||
await Promise.race([client.connect(), timeout]);
|
||||
// Create a promise that resolves when connected
|
||||
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
|
||||
await new Promise<void>((resolve) => setTimeout(resolve, 500));
|
||||
const cleanup = () => {
|
||||
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
|
||||
return {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user