{"version":3,"sources":["../src/index.ts","../src/auth.ts","../src/helix.ts","../src/chat.ts","../src/eventsub.ts","../src/cli.ts"],"sourcesContent":["export {\n  TwitchAuth,\n  TwitchAuthError, type AppAccessToken, type AuthToken, type TwitchAuthOptions, type UserAccessToken\n} from \"./auth\";\n\nexport {\n  HelixClient,\n  HelixRequestError,\n  type HelixClientOptions, type HelixRateLimit, type HelixRequestOptions,\n  type HelixResponse, type HelixTokenConfig\n} from \"./helix\";\n\nexport {\n  TwitchChatClient, type ChatEvents,\n  type ChatJoinPayload, type ChatMessage,\n  type ChatNotice, type TwitchChatClientOptions\n} from \"./chat\";\n\nexport {\n  EventSubWebSocketClient, handleEventSubWebhook, verifyTwitchSignature, type EventSubNotification,\n  type EventSubRevocation, type EventSubSession, type EventSubSubscription, type EventSubWebSocketClientOptions, type WebhookHandlerOptions,\n  type WebhookRequest,\n  type WebhookResponse\n} from \"./eventsub\";\n\nexport { VelhoOAuthSetup } from \"./cli\";\n","import { z } from \"zod\";\n\ntype FetchFn = (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;\n\nconst resolveFetch = (fetchFn?: FetchFn): FetchFn => {\n  if (fetchFn) {\n    return fetchFn;\n  }\n\n  if (typeof globalThis.fetch !== \"function\") {\n    throw new Error(\"Global fetch is not available; supply a custom fetch implementation.\");\n  }\n\n  return globalThis.fetch.bind(globalThis);\n};\n\nconst tokenResponseSchema = z.object({\n  access_token: z.string(),\n  expires_in: z.number(),\n  token_type: z.string(),\n  scope: z.array(z.string()).optional().default([]),\n  refresh_token: z.string().optional()\n});\n\nconst tokenErrorSchema = z.object({\n  status: z.number().optional(),\n  message: z.string().optional(),\n  error: z.string().optional(),\n  error_description: z.string().optional()\n});\n\nexport type TokenType = \"app\" | \"user\";\n\n/**\n * Represents the shared properties returned by Twitch OAuth token endpoints.\n * Consumers normally interact with the concrete {@link AppAccessToken} or {@link UserAccessToken} types.\n */\nexport interface BaseAuthToken {\n  accessToken: string;\n  expiresAt: number;\n  scope: string[];\n  obtainedAt: number;\n}\n\n/**\n * Cached metadata for an application access token retrieved via the client credentials flow.\n */\nexport interface AppAccessToken extends BaseAuthToken {\n  tokenType: \"app\";\n}\n\n/**\n * Cached metadata for a user access token retrieved via the refresh-token flow.\n * Includes the refresh token Twitch may rotate in the response.\n */\nexport interface UserAccessToken extends BaseAuthToken {\n  tokenType: \"user\";\n  refreshToken: string;\n}\n\nexport type AuthToken = AppAccessToken | UserAccessToken;\n\n/**\n * Configuration for {@link TwitchAuth}. The client ID and secret are required OAuth credentials.\n * Provide a custom `fetchFn` when running outside environments that supply `globalThis.fetch`.\n */\nexport interface TwitchAuthOptions {\n  clientId: string;\n  clientSecret: string;\n  fetchFn?: FetchFn;\n  tokenEndpoint?: string;\n  refreshLeewaySeconds?: number;\n}\n\ninterface TokenEntry extends BaseAuthToken {\n  refreshToken?: string;\n  tokenType: TokenType;\n}\n\nconst DEFAULT_TOKEN_ENDPOINT = \"https://id.twitch.tv/oauth2/token\";\nconst DEFAULT_REFRESH_LEEWAY = 60; // seconds\n\n/**\n * Helper for acquiring and caching Twitch OAuth tokens for both application and user contexts.\n * The class transparently refreshes tokens when they near expiry and exposes helpers to invalidate them on demand.\n */\nexport class TwitchAuth {\n  private readonly clientId: string;\n  private readonly clientSecret: string;\n  private readonly fetchFn: FetchFn;\n  private readonly tokenEndpoint: string;\n  private readonly refreshLeewayMs: number;\n  private readonly appTokens = new Map<string, TokenEntry>();\n  private readonly userTokens = new Map<string, TokenEntry>();\n\n  /**\n   * Creates a new auth helper bound to a specific Twitch client ID / secret pair.\n   */\n  constructor(options: TwitchAuthOptions) {\n    if (!options.clientId) {\n      throw new Error(\"TWITCH_CLIENT_ID is required. Please set it as an environment variable or pass it in the options.\");\n    }\n    if (!options.clientSecret) {\n      throw new Error(\"TWITCH_CLIENT_SECRET is required. Please set it as an environment variable or pass it in the options.\");\n    }\n\n    this.clientId = options.clientId;\n    this.clientSecret = options.clientSecret;\n    this.fetchFn = resolveFetch(options.fetchFn);\n    this.tokenEndpoint = options.tokenEndpoint ?? DEFAULT_TOKEN_ENDPOINT;\n    const refreshLeewaySeconds = options.refreshLeewaySeconds ?? DEFAULT_REFRESH_LEEWAY;\n    this.refreshLeewayMs = Math.max(0, refreshLeewaySeconds) * 1000;\n  }\n\n  /**\n   * Retrieves (and caches) an app access token for the requested scopes using the client credentials flow.\n   * Tokens are reused until they are close to expiry, at which point a fresh token is requested automatically.\n   */\n  async getAppAccessToken(scopes: string[] = []): Promise<AppAccessToken> {\n    const key = this.scopeKey(scopes);\n    const cached = this.appTokens.get(key);\n\n    if (cached && !this.shouldRefresh(cached)) {\n      return {\n        tokenType: \"app\",\n        accessToken: cached.accessToken,\n        expiresAt: cached.expiresAt,\n        scope: cached.scope,\n        obtainedAt: cached.obtainedAt\n      };\n    }\n\n    const result = await this.requestToken({\n      grant_type: \"client_credentials\",\n      scope: scopes.length ? scopes.join(\" \") : undefined\n    });\n\n    const entry: TokenEntry = {\n      tokenType: \"app\",\n      accessToken: result.access_token,\n      scope: result.scope,\n      expiresAt: this.computeExpiry(result.expires_in),\n      obtainedAt: Date.now()\n    };\n\n    this.appTokens.set(key, entry);\n\n    return {\n      tokenType: \"app\",\n      accessToken: entry.accessToken,\n      expiresAt: entry.expiresAt,\n      scope: entry.scope,\n      obtainedAt: entry.obtainedAt\n    };\n  }\n\n  /**\n   * Exchanges an authorization code for a user access token and refresh token.\n   * This is the final step in the OAuth 2.0 authorization code flow.\n   */\n  async exchangeAuthorizationCode(params: {\n    code: string;\n    redirectUri: string;\n  }): Promise<UserAccessToken> {\n    const result = await this.requestToken({\n      grant_type: \"authorization_code\",\n      code: params.code,\n      redirect_uri: params.redirectUri\n    });\n\n    if (!result.refresh_token) {\n      throw new TwitchAuthError(\"No refresh token received from authorization code exchange\");\n    }\n\n    const refreshToken = result.refresh_token!;\n\n    const entry: TokenEntry = {\n      tokenType: \"user\",\n      accessToken: result.access_token,\n      scope: result.scope,\n      refreshToken: refreshToken,\n      expiresAt: this.computeExpiry(result.expires_in),\n      obtainedAt: Date.now()\n    };\n\n    this.userTokens.set(refreshToken, entry);\n\n    return {\n      tokenType: \"user\",\n      accessToken: entry.accessToken,\n      expiresAt: entry.expiresAt,\n      scope: entry.scope,\n      obtainedAt: entry.obtainedAt,\n      refreshToken: refreshToken\n    };\n  }\n\n  /**\n   * Retrieves a user access token for the supplied refresh token. Optionally forces a refresh or limits scopes.\n   * Twitch may rotate the refresh token; the updated token is returned and cached.\n   */\n  async getUserAccessToken(params: {\n    refreshToken: string;\n    scopes?: string[];\n    forceRefresh?: boolean;\n  }): Promise<UserAccessToken> {\n    const refreshToken = params.refreshToken;\n    const cached = this.userTokens.get(refreshToken);\n\n    if (cached && !params.forceRefresh && !this.shouldRefresh(cached)) {\n      return {\n        tokenType: \"user\",\n        accessToken: cached.accessToken,\n        expiresAt: cached.expiresAt,\n        scope: cached.scope,\n        obtainedAt: cached.obtainedAt,\n        refreshToken: cached.refreshToken ?? refreshToken\n      };\n    }\n\n    const result = await this.requestToken({\n      grant_type: \"refresh_token\",\n      refresh_token: refreshToken,\n      scope: params.scopes && params.scopes.length ? params.scopes.join(\" \") : undefined\n    });\n\n    const newRefreshToken = result.refresh_token ?? refreshToken;\n\n    const entry: TokenEntry = {\n      tokenType: \"user\",\n      accessToken: result.access_token,\n      scope: result.scope,\n      refreshToken: newRefreshToken,\n      expiresAt: this.computeExpiry(result.expires_in),\n      obtainedAt: Date.now()\n    };\n\n    // If Twitch rotated the refresh token, replace the cache key.\n    if (refreshToken !== newRefreshToken) {\n      this.userTokens.delete(refreshToken);\n    }\n\n    this.userTokens.set(newRefreshToken, entry);\n\n    return {\n      tokenType: \"user\",\n      accessToken: entry.accessToken,\n      expiresAt: entry.expiresAt,\n      scope: entry.scope,\n      obtainedAt: entry.obtainedAt,\n      refreshToken: newRefreshToken\n    };\n  }\n\n  /**\n   * Removes the cached app token for the given scopes so the next call fetches a new one.\n   */\n  invalidateAppAccessToken(scopes: string[] = []): void {\n    const key = this.scopeKey(scopes);\n    this.appTokens.delete(key);\n  }\n\n  /**\n   * Removes the cached user token bound to the supplied refresh token.\n   */\n  invalidateUserAccessToken(refreshToken: string): void {\n    this.userTokens.delete(refreshToken);\n  }\n\n  private async requestToken(params: Record<string, string | undefined>): Promise<z.infer<typeof tokenResponseSchema>> {\n    const searchParams = new URLSearchParams({\n      client_id: this.clientId,\n      client_secret: this.clientSecret\n    });\n\n    Object.entries(params).forEach(([key, value]) => {\n      if (value !== undefined) {\n        searchParams.set(key, value);\n      }\n    });\n\n    const response = await this.fetchFn(this.tokenEndpoint, {\n      method: \"POST\",\n      headers: {\n        \"Content-Type\": \"application/x-www-form-urlencoded\"\n      },\n      body: searchParams.toString()\n    });\n\n    const raw = await response.json().catch(() => undefined);\n\n    if (!response.ok || !raw) {\n      const parsedError = tokenErrorSchema.safeParse(raw);\n      const message = parsedError.success\n        ? parsedError.data.error_description ?? parsedError.data.message ?? parsedError.data.error ?? \"Unknown token error\"\n        : \"Failed to retrieve token\";\n\n      throw new TwitchAuthError(message, response.status, parsedError.success ? parsedError.data : undefined);\n    }\n\n    const parsed = tokenResponseSchema.safeParse(raw);\n\n    if (!parsed.success) {\n      throw new TwitchAuthError(\"Unexpected token response\", response.status, raw);\n    }\n\n    return parsed.data;\n  }\n\n  private shouldRefresh(entry: TokenEntry): boolean {\n    return Date.now() + this.refreshLeewayMs >= entry.expiresAt;\n  }\n\n  private computeExpiry(expiresIn: number): number {\n    return Date.now() + expiresIn * 1000;\n  }\n\n  private scopeKey(scopes: string[]): string {\n    return scopes.slice().sort().join(\" \");\n  }\n}\n\n/**\n * Error thrown when the Twitch token endpoint responds with an error or an unexpected payload.\n */\nexport class TwitchAuthError extends Error {\n  readonly status?: number;\n  readonly details?: unknown;\n\n  constructor(message: string, status?: number, details?: unknown) {\n    super(message);\n    this.name = \"TwitchAuthError\";\n    this.status = status;\n    this.details = details;\n  }\n}\n","import { z } from \"zod\";\nimport type { TwitchAuth, AppAccessToken, UserAccessToken, AuthToken } from \"./auth\";\n\ntype FetchFn = (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;\n\nconst helixErrorSchema = z.object({\n  status: z.number(),\n  message: z.string(),\n  error: z.string().optional()\n});\n\n/**\n * Describes how the {@link HelixClient} should acquire an access token for a request.\n * Supports both app tokens (client credentials) and user tokens (refresh-token flow).\n */\nexport type HelixTokenConfig =\n  | { type: \"app\"; scopes?: string[] }\n  | { type: \"user\"; refreshToken: string; scopes?: string[]; forceRefresh?: boolean };\n\n/**\n * Options for constructing a {@link HelixClient}. You must supply a {@link TwitchAuth} instance that knows how to fetch tokens.\n */\nexport interface HelixClientOptions {\n  clientId: string;\n  auth: TwitchAuth;\n  fetchFn?: FetchFn;\n  baseUrl?: string;\n  defaultToken?: HelixTokenConfig;\n  userAgent?: string;\n}\n\n/**\n * Captures the rate limit headers returned by Twitch Helix API responses.\n */\nexport interface HelixRateLimit {\n  limit: number | null;\n  remaining: number | null;\n  resetAt: number | null;\n  resetAfterSeconds: number | null;\n  used: number | null;\n}\n\n/**\n * Per-request overrides for Helix calls. Supports custom query params, headers, body payloads, response schemas, and tokens.\n */\nexport interface HelixRequestOptions<T> {\n  query?: Record<string, QueryValue>;\n  headers?: Record<string, string | undefined>;\n  body?: unknown;\n  schema?: z.ZodType<T>;\n  token?: HelixTokenConfig;\n  signal?: AbortSignal;\n}\n\ntype QueryPrimitive = string | number | boolean;\ntype QueryValue = QueryPrimitive | Array<QueryPrimitive> | undefined;\n\n/**\n * Rich response returned from Helix helper methods, containing parsed data, HTTP metadata, and the token used.\n */\nexport interface HelixResponse<T> {\n  data: T;\n  status: number;\n  rateLimit: HelixRateLimit;\n  headers: Headers;\n  token: AuthToken;\n}\n\nconst DEFAULT_HELIX_BASE_URL = \"https://api.twitch.tv/helix\";\n\nconst resolveFetch = (fetchFn?: FetchFn): FetchFn => {\n  if (fetchFn) {\n    return fetchFn;\n  }\n\n  if (typeof globalThis.fetch !== \"function\") {\n    throw new Error(\"Global fetch is not available; supply a custom fetch implementation.\");\n  }\n\n  return globalThis.fetch.bind(globalThis);\n};\n\n/**\n * Error raised when a Helix request returns a non-2xx response. Includes parsed error payload if available.\n */\nexport class HelixRequestError<T = unknown> extends Error {\n  readonly status: number;\n  readonly details?: T;\n  readonly headers: Headers;\n\n  constructor(message: string, status: number, headers: Headers, details?: T) {\n    super(message);\n    this.name = \"HelixRequestError\";\n    this.status = status;\n    this.headers = headers;\n    this.details = details;\n  }\n}\n\n/**\n * Minimal Helix API client that reuses a {@link TwitchAuth} helper to automatically inject and refresh OAuth tokens.\n * Provides typed wrappers for the common HTTP verbs and surfaces rate-limit details for advanced throttling logic.\n */\nexport class HelixClient {\n  private readonly clientId: string;\n  private readonly auth: TwitchAuth;\n  private readonly fetchFn: FetchFn;\n  private readonly baseUrl: string;\n  private readonly defaultToken: HelixTokenConfig;\n  private readonly userAgent?: string;\n\n  /**\n   * Creates a Helix client bound to a specific application (`clientId`) and auth helper.\n   */\n  constructor(options: HelixClientOptions) {\n    if (!options.clientId) {\n      throw new Error(\"TWITCH_CLIENT_ID is required. Please set it as an environment variable or pass it in the options.\");\n    }\n\n    this.clientId = options.clientId;\n    this.auth = options.auth;\n    this.fetchFn = resolveFetch(options.fetchFn);\n    this.baseUrl = options.baseUrl ?? DEFAULT_HELIX_BASE_URL;\n    this.defaultToken = options.defaultToken ?? { type: \"app\" };\n    this.userAgent = options.userAgent;\n  }\n\n  /**\n   * Sends a GET request to the provided Helix path, applying optional query parameters and response validation.\n   */\n  async get<T = unknown>(path: string, options: HelixRequestOptions<T> = {}): Promise<HelixResponse<T>> {\n    return this.request<T>(\"GET\", path, options);\n  }\n\n  /**\n   * Sends a POST request to Helix with an optional JSON body and schema validation.\n   */\n  async post<T = unknown>(path: string, options: HelixRequestOptions<T> = {}): Promise<HelixResponse<T>> {\n    return this.request<T>(\"POST\", path, options);\n  }\n\n  /**\n   * Sends a PATCH request to Helix, typically used for partial updates.\n   */\n  async patch<T = unknown>(path: string, options: HelixRequestOptions<T> = {}): Promise<HelixResponse<T>> {\n    return this.request<T>(\"PATCH\", path, options);\n  }\n\n  /**\n   * Sends a PUT request to Helix, replacing or creating resources.\n   */\n  async put<T = unknown>(path: string, options: HelixRequestOptions<T> = {}): Promise<HelixResponse<T>> {\n    return this.request<T>(\"PUT\", path, options);\n  }\n\n  /**\n   * Sends a DELETE request to Helix, removing resources when supported by the endpoint.\n   */\n  async delete<T = unknown>(path: string, options: HelixRequestOptions<T> = {}): Promise<HelixResponse<T>> {\n    return this.request<T>(\"DELETE\", path, options);\n  }\n\n  private async request<T>(method: string, path: string, options: HelixRequestOptions<T>): Promise<HelixResponse<T>> {\n    const tokenConfig = options.token ?? this.defaultToken;\n    const url = this.buildUrl(path, options.query);\n\n    let attempt = 0;\n    let token: AuthToken | null = null;\n\n    while (attempt < 2) {\n      attempt += 1;\n      token = await this.resolveAccessToken(tokenConfig, attempt > 1);\n\n      const response = await this.fetchFn(url, {\n        method,\n        headers: this.composeHeaders(options.headers, token.accessToken, options.body !== undefined),\n        body: this.composeBody(options.body),\n        signal: options.signal\n      });\n\n      if (response.status === 401 && attempt < 2) {\n        this.invalidateToken(tokenConfig, token);\n        continue;\n      }\n\n      const rateLimit = this.parseRateLimit(response.headers);\n\n      if (!response.ok) {\n        const errorPayload = await response.json().catch(() => undefined);\n        const parsedError = helixErrorSchema.safeParse(errorPayload);\n        const message = parsedError.success ? parsedError.data.message : `Helix request failed with status ${response.status}`;\n        throw new HelixRequestError(message, response.status, response.headers, errorPayload);\n      }\n\n      const data = await this.parseResponseBody(response, options.schema);\n\n      return {\n        data,\n        status: response.status,\n        rateLimit,\n        headers: response.headers,\n        token: token\n      };\n    }\n\n    throw new HelixRequestError(\"Helix request failed after token refresh\", 401, new Headers());\n  }\n\n  private async parseResponseBody<T>(response: Response, schema?: z.ZodType<T>): Promise<T> {\n    if (response.status === 204) {\n      return schema ? schema.parse(undefined) : (undefined as T);\n    }\n\n    const text = await response.text();\n\n    if (!text) {\n      return schema ? schema.parse(undefined) : (undefined as T);\n    }\n\n    const json = JSON.parse(text) as unknown;\n\n    if (!schema) {\n      return json as T;\n    }\n\n    return schema.parse(json);\n  }\n\n  private composeHeaders(headers: Record<string, string | undefined> | undefined, accessToken: string, hasBody: boolean): HeadersInit {\n    const result = new Headers();\n    result.set(\"Client-ID\", this.clientId);\n    result.set(\"Authorization\", `Bearer ${accessToken}`);\n    result.set(\"Accept\", \"application/json\");\n\n    if (this.userAgent) {\n      result.set(\"User-Agent\", this.userAgent);\n    }\n\n    if (hasBody) {\n      result.set(\"Content-Type\", \"application/json\");\n    }\n\n    if (headers) {\n      for (const [key, value] of Object.entries(headers)) {\n        if (value !== undefined) {\n          result.set(key, value);\n        }\n      }\n    }\n\n    return result;\n  }\n\n  private composeBody(body: unknown): BodyInit | undefined {\n    if (body === undefined || body === null) {\n      return undefined;\n    }\n\n    if (typeof body === \"string\" || body instanceof ArrayBuffer || ArrayBuffer.isView(body) || body instanceof Blob) {\n      return body as BodyInit;\n    }\n\n    return JSON.stringify(body);\n  }\n\n  private buildUrl(path: string, query?: Record<string, QueryValue>): string {\n    const base = path.startsWith(\"http\") ? path : `${this.baseUrl}${path.startsWith(\"/\") ? \"\" : \"/\"}${path}`;\n    const url = new URL(base);\n\n    if (query) {\n      for (const [key, value] of Object.entries(query)) {\n        if (value === undefined) {\n          continue;\n        }\n\n        if (Array.isArray(value)) {\n          value.forEach((item) => url.searchParams.append(key, this.normalizeQueryValue(item)));\n        } else {\n          url.searchParams.set(key, this.normalizeQueryValue(value));\n        }\n      }\n    }\n\n    return url.toString();\n  }\n\n  private normalizeQueryValue(value: QueryPrimitive): string {\n    if (typeof value === \"boolean\") {\n      return value ? \"true\" : \"false\";\n    }\n\n    return String(value);\n  }\n\n  private parseRateLimit(headers: Headers): HelixRateLimit {\n    const limit = this.parseHeaderNumber(headers, \"ratelimit-limit\");\n    const remaining = this.parseHeaderNumber(headers, \"ratelimit-remaining\");\n    const reset = this.parseHeaderNumber(headers, \"ratelimit-reset\");\n    const resetAfter = this.parseHeaderNumber(headers, \"ratelimit-reset-after\");\n    const used = this.parseHeaderNumber(headers, \"ratelimit-used\");\n\n    return {\n      limit,\n      remaining,\n      resetAt: reset ? reset * 1000 : null,\n      resetAfterSeconds: resetAfter,\n      used\n    };\n  }\n\n  private parseHeaderNumber(headers: Headers, key: string): number | null {\n    const value = headers.get(key);\n    if (value === null || value === \"\") {\n      return null;\n    }\n\n    const parsed = Number(value);\n    return Number.isFinite(parsed) ? parsed : null;\n  }\n\n  private async resolveAccessToken(config: HelixTokenConfig, forceRefresh: boolean): Promise<AuthToken> {\n    if (config.type === \"app\") {\n      if (forceRefresh) {\n        this.auth.invalidateAppAccessToken(config.scopes);\n      }\n      return this.auth.getAppAccessToken(config.scopes);\n    }\n\n    if (forceRefresh) {\n      return this.auth.getUserAccessToken({ refreshToken: config.refreshToken, scopes: config.scopes, forceRefresh: true });\n    }\n\n    return this.auth.getUserAccessToken({ refreshToken: config.refreshToken, scopes: config.scopes, forceRefresh: config.forceRefresh });\n  }\n\n  private invalidateToken(config: HelixTokenConfig, token: AuthToken): void {\n    if (config.type === \"app\") {\n      this.auth.invalidateAppAccessToken(config.scopes);\n      return;\n    }\n\n    const refreshToken = token.tokenType === \"user\" ? token.refreshToken : config.refreshToken;\n    this.auth.invalidateUserAccessToken(refreshToken);\n  }\n}\n","import { EventEmitter } from \"node:events\";\nimport { setTimeout as delay } from \"node:timers/promises\";\nimport WebSocket from \"ws\";\n\n/**\n * Configuration for {@link TwitchChatClient}. Provide login credentials and optional behaviour tweaks.\n */\nexport interface TwitchChatClientOptions {\n  username: string;\n  token: string;\n  autoJoin?: string[];\n  reconnect?: boolean;\n  reconnectIntervalMs?: number;\n  url?: string;\n}\n\n/**\n * Structured chat message emitted by the client, including raw IRC payload and metadata tags.\n */\nexport interface ChatMessage {\n  raw: string;\n  channel: string;\n  username: string;\n  text: string;\n  tags: Record<string, string>;\n}\n\n/**\n * NOTICE line sent by Twitch, usually system messages such as slow-mode notices or errors.\n */\nexport interface ChatNotice {\n  raw: string;\n  message: string;\n  tags: Record<string, string>;\n}\n\n/**\n * Envelope describing users joining or leaving a channel.\n */\nexport interface ChatJoinPayload {\n  channel: string;\n  username: string;\n}\n\n/**\n * Event map for {@link TwitchChatClient}. Used to type event listeners.\n */\nexport interface ChatEvents {\n  ready: undefined;\n  reconnect: number;\n  message: ChatMessage;\n  notice: ChatNotice;\n  join: ChatJoinPayload;\n  part: ChatJoinPayload;\n  close: { code: number; reason: string };\n  error: Error;\n  raw: string;\n}\n\ntype Listener<T> = (payload: T) => void;\n\ntype ChatEventKey = keyof ChatEvents;\n\nconst DEFAULT_CHAT_URL = \"wss://irc-ws.chat.twitch.tv:443\";\nconst DEFAULT_RECONNECT_INTERVAL = 3000;\nconst CAPABILITIES = \"CAP REQ :twitch.tv/tags twitch.tv/commands twitch.tv/membership\";\n\n/**\n * Lightweight Twitch IRC client that wraps a WebSocket connection and normalises incoming events.\n * Automatically handles join queues, reconnects, and message parsing to simplify bot development.\n */\nexport class TwitchChatClient {\n  private readonly emitter = new EventEmitter();\n  private readonly options: TwitchChatClientOptions;\n  private socket?: WebSocket;\n  private ready = false;\n  private reconnectAttempts = 0;\n  private reconnectAbort = false;\n  private joinQueue = new Set<string>();\n\n  /**\n   * Creates a new chat client. The `username` must match the token owner (or a bot account).\n   */\n  constructor(options: TwitchChatClientOptions) {\n    this.options = options;\n\n    if (!this.options.username) {\n      throw new Error(\"username is required for TwitchChatClient\");\n    }\n\n    if (!this.options.token) {\n      throw new Error(\"token is required for TwitchChatClient\");\n    }\n\n    (this.options.autoJoin ?? []).forEach((channel) => this.joinQueue.add(this.normalizeChannel(channel)));\n  }\n\n  /**\n   * Opens the chat WebSocket connection. Resolves when the client is fully ready to send messages.\n   */\n  async connect(): Promise<void> {\n    if (this.socket) {\n      if (this.ready) {\n        return;\n      }\n      await this.waitForReady();\n      return;\n    }\n\n    this.reconnectAbort = false;\n    await this.establishConnection();\n    if (!this.ready) {\n      await this.waitForReady();\n    }\n  }\n\n  /**\n   * Closes the chat connection and stops automatic reconnect attempts.\n   */\n  async disconnect(code = 1000, reason = \"client disconnect\"): Promise<void> {\n    this.reconnectAbort = true;\n    if (this.socket && this.socket.readyState === WebSocket.OPEN) {\n      this.socket.close(code, reason);\n    }\n    this.socket = undefined;\n    this.ready = false;\n  }\n\n  /**\n   * Adds one or more channels to the join queue. The client joins immediately once connected.\n   */\n  join(channel: string | string[]): void {\n    const channels = Array.isArray(channel) ? channel : [channel];\n    channels.forEach((chan) => this.joinQueue.add(this.normalizeChannel(chan)));\n    this.flushJoinQueue();\n  }\n\n  /**\n   * Leaves one or more channels. If not yet joined, removes them from the pending join queue.\n   */\n  part(channel: string | string[]): void {\n    const channels = Array.isArray(channel) ? channel : [channel];\n    channels.forEach((chan) => {\n      const normalized = this.normalizeChannel(chan);\n      if (this.socket && this.socket.readyState === WebSocket.OPEN) {\n        this.sendRaw(`PART ${normalized}`);\n      }\n      this.joinQueue.delete(normalized);\n    });\n  }\n\n  /**\n   * Sends a PRIVMSG to the specified channel. Throws if the socket is not ready.\n   */\n  say(channel: string, message: string): void {\n    if (!this.ready || !this.socket || this.socket.readyState !== WebSocket.OPEN) {\n      throw new Error(\"Chat socket is not ready\");\n    }\n\n    const normalized = this.normalizeChannel(channel);\n    this.sendRaw(`PRIVMSG ${normalized} :${message}`);\n  }\n\n  /**\n   * Convenience helper to listen for chat messages and return an unsubscribe function.\n   */\n  listen(listener: Listener<ChatMessage>): () => void {\n    this.on(\"message\", listener);\n    return () => this.off(\"message\", listener);\n  }\n\n  /**\n   * Registers an event listener. Typed by {@link ChatEvents} for IntelliSense support.\n   */\n  on<K extends ChatEventKey>(event: K, listener: Listener<ChatEvents[K]>): this {\n    this.emitter.on(event, listener as (...args: unknown[]) => void);\n    return this;\n  }\n\n  /**\n   * Registers a one-off event listener that removes itself after the first emission.\n   */\n  once<K extends ChatEventKey>(event: K, listener: Listener<ChatEvents[K]>): this {\n    this.emitter.once(event, listener as (...args: unknown[]) => void);\n    return this;\n  }\n\n  /**\n   * Removes a previously registered listener.\n   */\n  off<K extends ChatEventKey>(event: K, listener: Listener<ChatEvents[K]>): this {\n    this.emitter.off(event, listener as (...args: unknown[]) => void);\n    return this;\n  }\n\n  private emit<K extends ChatEventKey>(event: K, payload: ChatEvents[K]): boolean {\n    return this.emitter.emit(event, payload);\n  }\n\n  private async establishConnection(): Promise<void> {\n    const url = this.options.url ?? DEFAULT_CHAT_URL;\n    this.socket = new WebSocket(url);\n\n    this.socket.on(\"open\", () => this.handleOpen());\n    this.socket.on(\"message\", (data) => this.handleMessage(data));\n    this.socket.on(\"close\", (code: number, reason: Buffer) => this.handleClose(code, reason));\n    this.socket.on(\"error\", (error) => this.emit(\"error\", error instanceof Error ? error : new Error(String(error))));\n  }\n\n  private handleOpen(): void {\n    if (!this.socket) {\n      return;\n    }\n\n    this.sendRaw(`PASS oauth:${this.normalizeToken(this.options.token)}`);\n    this.sendRaw(`NICK ${this.options.username}`);\n    this.sendRaw(CAPABILITIES);\n  }\n\n  private handleMessage(data: WebSocket.RawData): void {\n    const payload = typeof data === \"string\" ? data : data.toString(\"utf8\");\n    const lines = payload.split(\"\\r\\n\").filter(Boolean);\n\n    for (const line of lines) {\n      this.emit(\"raw\", line);\n\n      if (line.startsWith(\"PING\")) {\n        this.sendRaw(line.replace(\"PING\", \"PONG\"));\n        continue;\n      }\n\n      const parsed = parseIrcMessage(line);\n      if (!parsed) {\n        continue;\n      }\n\n      switch (parsed.command) {\n        case \"001\":\n        case \"GLOBALUSERSTATE\":\n          if (!this.ready) {\n            this.ready = true;\n            this.flushJoinQueue();\n            this.emit(\"ready\", undefined);\n          }\n          break;\n        case \"JOIN\":\n          if (parsed.prefix?.name) {\n            this.emit(\"join\", { channel: parsed.params[0] ?? \"\", username: parsed.prefix.name });\n          }\n          break;\n        case \"PART\":\n          if (parsed.prefix?.name) {\n            this.emit(\"part\", { channel: parsed.params[0] ?? \"\", username: parsed.prefix.name });\n          }\n          break;\n        case \"PRIVMSG\":\n          if (!parsed.prefix?.name) {\n            break;\n          }\n          this.emit(\"message\", {\n            raw: line,\n            channel: parsed.params[0] ?? \"\",\n            username: parsed.prefix.name,\n            text: parsed.trailing ?? \"\",\n            tags: parsed.tags\n          });\n          break;\n        case \"NOTICE\":\n          this.emit(\"notice\", {\n            raw: line,\n            message: parsed.trailing ?? \"\",\n            tags: parsed.tags\n          });\n          break;\n        case \"RECONNECT\":\n          void this.reconnect();\n          break;\n        default:\n          break;\n      }\n    }\n  }\n\n  private async reconnect(): Promise<void> {\n    if (!this.options.reconnect) {\n      return;\n    }\n\n    this.ready = false;\n\n    if (this.socket) {\n      try {\n        this.socket.terminate();\n      } catch {\n        // noop\n      }\n      this.socket = undefined;\n    }\n\n    if (this.reconnectAbort) {\n      return;\n    }\n\n    this.reconnectAttempts += 1;\n    this.emit(\"reconnect\", this.reconnectAttempts);\n    const delayMs = this.options.reconnectIntervalMs ?? DEFAULT_RECONNECT_INTERVAL;\n    await delay(delayMs);\n\n    if (!this.reconnectAbort) {\n      await this.establishConnection();\n    }\n  }\n\n  private handleClose(code: number, reason: Buffer): void {\n    this.emit(\"close\", { code, reason: reason.toString() });\n    this.ready = false;\n\n    if (this.options.reconnect && !this.reconnectAbort) {\n      void this.reconnect();\n    }\n  }\n\n  private flushJoinQueue(): void {\n    if (!this.ready || !this.socket || this.socket.readyState !== WebSocket.OPEN) {\n      return;\n    }\n\n    for (const channel of this.joinQueue) {\n      this.sendRaw(`JOIN ${channel}`);\n    }\n    this.joinQueue.clear();\n  }\n\n  private sendRaw(message: string): void {\n    if (!this.socket || this.socket.readyState !== WebSocket.OPEN) {\n      return;\n    }\n\n    this.socket.send(message + \"\\r\\n\");\n  }\n\n  private normalizeChannel(channel: string): string {\n    return channel.startsWith(\"#\") ? channel.toLowerCase() : `#${channel.toLowerCase()}`;\n  }\n\n  private normalizeToken(token: string): string {\n    return token.startsWith(\"oauth:\") ? token.slice(\"oauth:\".length) : token;\n  }\n\n  private async waitForReady(): Promise<void> {\n    if (this.ready) {\n      return;\n    }\n\n    await new Promise<void>((resolve, reject) => {\n      const onReady = () => {\n        cleanup();\n        resolve();\n      };\n      const onError = (error: Error) => {\n        cleanup();\n        reject(error);\n      };\n      const cleanup = () => {\n        this.off(\"ready\", onReady);\n        this.off(\"error\", onError);\n      };\n\n      this.on(\"ready\", onReady);\n      this.on(\"error\", onError);\n    });\n  }\n}\n\ninterface IrcPrefix {\n  raw: string;\n  name: string | null;\n  host: string | null;\n}\n\ninterface IrcMessage {\n  raw: string;\n  tags: Record<string, string>;\n  prefix: IrcPrefix | null;\n  command: string;\n  params: string[];\n  trailing: string | null;\n}\n\nconst tagValue = (value: string): string => value.replace(/\\\\s/g, \" \");\n\nfunction parseIrcMessage(raw: string): IrcMessage | null {\n  let rest = raw;\n  const tags: Record<string, string> = {};\n  let prefix: IrcPrefix | null = null;\n\n  if (rest.startsWith(\"@\")) {\n    const spaceIndex = rest.indexOf(\" \");\n    if (spaceIndex === -1) {\n      return null;\n    }\n    const tagSection = rest.slice(1, spaceIndex);\n    rest = rest.slice(spaceIndex + 1);\n    for (const tag of tagSection.split(\";\")) {\n      const [key, value = \"\"] = tag.split(\"=\");\n      tags[key] = tagValue(value);\n    }\n  }\n\n  if (rest.startsWith(\":\")) {\n    const spaceIndex = rest.indexOf(\" \");\n    if (spaceIndex === -1) {\n      return null;\n    }\n    const prefixSection = rest.slice(1, spaceIndex);\n    rest = rest.slice(spaceIndex + 1);\n    const [name, host] = prefixSection.split(\"!\");\n    prefix = {\n      raw: prefixSection,\n      name: name ?? null,\n      host: host ?? null\n    };\n  }\n\n  const commandEnd = rest.indexOf(\" \");\n  const command = commandEnd === -1 ? rest : rest.slice(0, commandEnd);\n  rest = commandEnd === -1 ? \"\" : rest.slice(commandEnd + 1);\n\n  const params: string[] = [];\n  let trailing: string | null = null;\n\n  while (rest) {\n    if (rest.startsWith(\":\")) {\n      trailing = rest.slice(1);\n      break;\n    }\n\n    const spaceIndex = rest.indexOf(\" \");\n    if (spaceIndex === -1) {\n      params.push(rest);\n      break;\n    }\n\n    params.push(rest.slice(0, spaceIndex));\n    rest = rest.slice(spaceIndex + 1);\n  }\n\n  if (!command) {\n    return null;\n  }\n\n  return {\n    raw,\n    tags,\n    prefix,\n    command,\n    params,\n    trailing\n  };\n}\n","import { createHmac, timingSafeEqual } from \"node:crypto\";\nimport { EventEmitter } from \"node:events\";\nimport { setTimeout as delay } from \"node:timers/promises\";\nimport WebSocket from \"ws\";\nimport { z } from \"zod\";\n\n/**\n * Required pieces of data from a Twitch EventSub webhook to verify the HMAC signature.\n */\nexport interface VerifySignatureOptions {\n  secret: string;\n  messageId: string;\n  timestamp: string;\n  body: string;\n  signature: string;\n}\n\n/**\n * Verifies that the EventSub message was signed by Twitch using the shared secret.\n */\nexport const verifyTwitchSignature = (options: VerifySignatureOptions): boolean => {\n  const { secret, messageId, timestamp, body, signature } = options;\n  const expectedPrefix = \"sha256=\";\n\n  if (!signature || !signature.startsWith(expectedPrefix)) {\n    return false;\n  }\n\n  const hmac = createHmac(\"sha256\", secret);\n  hmac.update(messageId + timestamp + body);\n  const expected = `${expectedPrefix}${hmac.digest(\"hex\")}`;\n\n  const receivedBuffer = Buffer.from(signature, \"utf8\");\n  const expectedBuffer = Buffer.from(expected, \"utf8\");\n\n  if (receivedBuffer.length !== expectedBuffer.length) {\n    return false;\n  }\n\n  return timingSafeEqual(receivedBuffer, expectedBuffer);\n};\n\nconst subscriptionSchema = z.object({\n  id: z.string(),\n  status: z.string(),\n  type: z.string(),\n  version: z.string(),\n  condition: z.record(z.string(), z.any()),\n  transport: z.object({\n    method: z.string(),\n    callback: z.string().optional(),\n    session_id: z.string().optional()\n  }).partial(),\n  cost: z.number().optional(),\n  created_at: z.string()\n});\n\n/**\n * Normalised subscription object returned alongside EventSub notifications.\n */\nexport type EventSubSubscription = z.infer<typeof subscriptionSchema>;\n\nconst webhookEnvelopeSchema = z.object({\n  challenge: z.string().optional(),\n  subscription: subscriptionSchema,\n  event: z.unknown().optional()\n});\n\n/**\n * Lightweight representation of an incoming webhook request.\n */\nexport interface WebhookRequest {\n  headers: Record<string, string | string[] | undefined>;\n  body: string;\n}\n\n/**\n * Configuration for {@link handleEventSubWebhook}. Provide the secret, notification handler, and optional schemas.\n */\nexport interface WebhookHandlerOptions<TEvent = unknown> {\n  secret: string;\n  eventSchema?: z.ZodType<TEvent>;\n  onNotification: (notification: EventSubNotification<TEvent>) => Promise<void> | void;\n  onRevocation?: (revocation: EventSubRevocation) => Promise<void> | void;\n}\n\n/**\n * Parsed EventSub notification payload delivered to webhook handlers or WebSocket clients.\n */\nexport interface EventSubNotification<T = unknown> {\n  subscription: EventSubSubscription;\n  event: T;\n  rawEvent: unknown;\n}\n\n/**\n * Notification that a previously subscribed EventSub topic has been revoked.\n */\nexport interface EventSubRevocation {\n  subscription: EventSubSubscription;\n}\n\n/**\n * Minimal HTTP response structure returned by {@link handleEventSubWebhook}.\n */\nexport interface WebhookResponse {\n  status: number;\n  headers?: Record<string, string>;\n  body?: string;\n}\n\nconst HEADER_MESSAGE_ID = \"twitch-eventsub-message-id\";\nconst HEADER_MESSAGE_TIMESTAMP = \"twitch-eventsub-message-timestamp\";\nconst HEADER_MESSAGE_TYPE = \"twitch-eventsub-message-type\";\nconst HEADER_MESSAGE_SIGNATURE = \"twitch-eventsub-message-signature\";\n\n/**\n * Validates and processes an EventSub webhook request. Handles verification challenges, notifications, and revocations.\n */\nexport const handleEventSubWebhook = async <T = unknown>(request: WebhookRequest, options: WebhookHandlerOptions<T>): Promise<WebhookResponse> => {\n  const messageId = getHeader(request.headers, HEADER_MESSAGE_ID);\n  const timestamp = getHeader(request.headers, HEADER_MESSAGE_TIMESTAMP);\n  const messageType = getHeader(request.headers, HEADER_MESSAGE_TYPE);\n  const signature = getHeader(request.headers, HEADER_MESSAGE_SIGNATURE);\n\n  if (!messageId || !timestamp || !messageType || !signature) {\n    return { status: 400, body: \"Missing Twitch EventSub headers\" };\n  }\n\n  if (!verifyTwitchSignature({\n    secret: options.secret,\n    messageId,\n    timestamp,\n    body: request.body,\n    signature\n  })) {\n    return { status: 403, body: \"Invalid signature\" };\n  }\n\n  const json = safeParseJson(request.body);\n  if (json === undefined) {\n    return { status: 400, body: \"Invalid body\" };\n  }\n\n  const parsed = webhookEnvelopeSchema.safeParse(json);\n\n  if (!parsed.success) {\n    return { status: 400, body: \"Invalid body\" };\n  }\n\n  const envelope = parsed.data;\n\n  switch (messageType) {\n    case \"webhook_callback_verification\": {\n      if (!envelope.challenge) {\n        return { status: 400, body: \"Missing challenge\" };\n      }\n      return {\n        status: 200,\n        headers: { \"Content-Type\": \"text/plain\" },\n        body: envelope.challenge\n      };\n    }\n    case \"notification\": {\n      const event = options.eventSchema ? options.eventSchema.parse(envelope.event) : (envelope.event as T);\n      await options.onNotification({\n        subscription: envelope.subscription,\n        event,\n        rawEvent: envelope.event\n      });\n      return { status: 204 };\n    }\n    case \"revocation\": {\n      if (options.onRevocation) {\n        await options.onRevocation({ subscription: envelope.subscription });\n      }\n      return { status: 204 };\n    }\n    default:\n      return { status: 400, body: `Unsupported message type: ${messageType}` };\n  }\n};\n\nconst safeParseJson = (body: string): unknown | undefined => {\n  try {\n    return JSON.parse(body);\n  } catch {\n    return undefined;\n  }\n};\n\nconst getHeader = (headers: Record<string, string | string[] | undefined>, key: string): string | undefined => {\n  const value = headers[key] ?? headers[key.toLowerCase()];\n  if (Array.isArray(value)) {\n    return value[0];\n  }\n  return value;\n};\n\n// EventSub WebSocket client --------------------------------------------------\n\ntype WebSocketEventMap = {\n  connected: EventSubSession;\n  keepalive: EventSubSession;\n  notification: EventSubNotification;\n  revocation: EventSubRevocation;\n  reconnect: { url: string };\n  close: { code: number; reason: string };\n  error: Error;\n  raw: string;\n};\n\ntype WebSocketEventKey = keyof WebSocketEventMap;\ntype Listener<T> = (payload: T) => void;\n\nconst websocketMessageSchema = z.object({\n  metadata: z.object({\n    message_id: z.string(),\n    message_type: z.string(),\n    message_timestamp: z.string(),\n    subscription_type: z.string().optional(),\n    subscription_version: z.string().optional()\n  }),\n  payload: z.object({\n    session: z\n      .object({\n        id: z.string(),\n        status: z.string(),\n        connected_at: z.string(),\n        keepalive_timeout_seconds: z.number().optional(),\n        reconnect_url: z.string().optional().nullable()\n      })\n      .optional(),\n    subscription: subscriptionSchema.optional(),\n    event: z.unknown().optional()\n  })\n});\n\n/**\n * Session metadata returned by the EventSub WebSocket endpoint.\n */\nexport type EventSubSession = {\n  id: string;\n  status: string;\n  connectedAt: string;\n  keepaliveTimeoutSeconds?: number;\n  reconnectUrl?: string | null;\n};\n\n/**\n * Options to configure the behaviour of {@link EventSubWebSocketClient}.\n */\nexport interface EventSubWebSocketClientOptions {\n  url?: string;\n  autoReconnect?: boolean;\n  reconnectIntervalMs?: number;\n  eventSchema?: z.ZodTypeAny;\n}\n\n/**\n * High-level EventSub WebSocket client that emits typed events for session lifecycle and notifications.\n */\nexport class EventSubWebSocketClient {\n  private readonly emitter = new EventEmitter();\n  private readonly options: EventSubWebSocketClientOptions;\n  private socket?: WebSocket;\n  private reconnecting = false;\n  private reconnectAbort = false;\n  private keepaliveTimer?: NodeJS.Timeout;\n  private session?: EventSubSession;\n\n  /**\n   * Creates a new EventSub WebSocket client with optional auto-reconnect and schema validation.\n   */\n  constructor(options: EventSubWebSocketClientOptions = {}) {\n    this.options = options;\n  }\n\n  /**\n   * Opens the EventSub WebSocket connection. Resolves once the welcome payload establishes a session.\n   */\n  async connect(): Promise<void> {\n    if (this.socket) {\n      if (this.session) {\n        return;\n      }\n      await this.waitForSession();\n      return;\n    }\n\n    this.reconnectAbort = false;\n    await this.establishConnection(this.options.url ?? defaultEventSubWebSocketUrl());\n    if (!this.session) {\n      await this.waitForSession();\n    }\n  }\n\n  /**\n   * Gracefully closes the WebSocket and halts reconnect logic.\n   */\n  async disconnect(code = 1000, reason = \"client disconnect\"): Promise<void> {\n    this.reconnectAbort = true;\n    this.stopKeepaliveTimer();\n\n    if (this.socket && this.socket.readyState === WebSocket.OPEN) {\n      this.socket.close(code, reason);\n    }\n\n    this.socket = undefined;\n    this.session = undefined;\n  }\n\n  /**\n   * Registers a listener for EventSub WebSocket events, typed via {@link WebSocketEventMap}.\n   */\n  on<K extends WebSocketEventKey>(event: K, listener: Listener<WebSocketEventMap[K]>): this {\n    this.emitter.on(event, listener as (...args: unknown[]) => void);\n    return this;\n  }\n\n  /**\n   * Adds a one-time listener that removes itself after handling the first event.\n   */\n  once<K extends WebSocketEventKey>(event: K, listener: Listener<WebSocketEventMap[K]>): this {\n    this.emitter.once(event, listener as (...args: unknown[]) => void);\n    return this;\n  }\n\n  /**\n   * Removes a previously registered listener.\n   */\n  off<K extends WebSocketEventKey>(event: K, listener: Listener<WebSocketEventMap[K]>): this {\n    this.emitter.off(event, listener as (...args: unknown[]) => void);\n    return this;\n  }\n\n  private emit<K extends WebSocketEventKey>(event: K, payload: WebSocketEventMap[K]): boolean {\n    return this.emitter.emit(event, payload);\n  }\n\n  private async establishConnection(url: string): Promise<void> {\n    this.socket = new WebSocket(url);\n\n    this.socket.on(\"open\", () => {\n      this.reconnecting = false;\n    });\n\n    this.socket.on(\"message\", (data) => this.handleMessage(data));\n\n    this.socket.on(\"close\", (code, reason) => {\n      this.emit(\"close\", { code, reason: reason.toString() });\n      this.stopKeepaliveTimer();\n      this.socket = undefined;\n      this.session = undefined;\n      if (this.options.autoReconnect !== false && !this.reconnectAbort) {\n        void this.scheduleReconnect();\n      }\n    });\n\n    this.socket.on(\"error\", (error) => {\n      this.emit(\"error\", error instanceof Error ? error : new Error(String(error)));\n    });\n  }\n\n  private async scheduleReconnect(): Promise<void> {\n    if (this.reconnecting) {\n      return;\n    }\n\n    this.reconnecting = true;\n    const delayMs = this.options.reconnectIntervalMs ?? 3000;\n    await delay(delayMs);\n\n    if (!this.reconnectAbort) {\n      await this.establishConnection(this.options.url ?? defaultEventSubWebSocketUrl());\n      if (!this.session) {\n        await this.waitForSession();\n      }\n    }\n  }\n\n  private handleMessage(data: WebSocket.RawData): void {\n    const text = typeof data === \"string\" ? data : data.toString(\"utf8\");\n    this.emit(\"raw\", text);\n\n    const json = safeParseJson(text);\n    if (json === undefined) {\n      this.emit(\"error\", new Error(\"Failed to parse EventSub message\"));\n      return;\n    }\n\n    const parsed = websocketMessageSchema.safeParse(json);\n\n    if (!parsed.success) {\n      this.emit(\"error\", new Error(\"Failed to parse EventSub message\"));\n      return;\n    }\n\n    const { metadata, payload } = parsed.data;\n\n    switch (metadata.message_type) {\n      case \"session_welcome\":\n        if (payload.session) {\n          const session = mapSession(payload.session);\n          this.session = session;\n          this.emit(\"connected\", session);\n          this.resetKeepaliveTimer(session.keepaliveTimeoutSeconds);\n        }\n        break;\n      case \"session_keepalive\":\n        if (payload.session) {\n          const session = mapSession(payload.session);\n          this.session = session;\n          this.emit(\"keepalive\", session);\n          this.resetKeepaliveTimer(session.keepaliveTimeoutSeconds);\n        }\n        break;\n      case \"session_reconnect\":\n        if (payload.session?.reconnect_url) {\n          this.emit(\"reconnect\", { url: payload.session.reconnect_url });\n          if (this.options.autoReconnect !== false && !this.reconnectAbort) {\n            if (this.socket && this.socket.readyState === WebSocket.OPEN) {\n              this.socket.close(1012, \"Twitch requested reconnect\");\n            }\n            void this.establishConnection(payload.session.reconnect_url);\n          }\n        }\n        break;\n      case \"notification\": {\n        if (payload.subscription) {\n          let eventPayload: unknown = payload.event;\n          if (this.options.eventSchema) {\n            eventPayload = this.options.eventSchema.parse(payload.event);\n          }\n\n          this.emit(\"notification\", {\n            subscription: payload.subscription,\n            event: eventPayload,\n            rawEvent: payload.event\n          });\n        }\n        break;\n      }\n      case \"revocation\": {\n        if (payload.subscription) {\n          this.emit(\"revocation\", { subscription: payload.subscription });\n        }\n        break;\n      }\n      default:\n        break;\n    }\n  }\n\n  private resetKeepaliveTimer(timeoutSeconds?: number): void {\n    this.stopKeepaliveTimer();\n\n    if (!timeoutSeconds) {\n      return;\n    }\n\n    const timeoutMs = Math.max(1, timeoutSeconds - 1) * 1000;\n    const timer = setTimeout(() => {\n      if (this.options.autoReconnect !== false && !this.reconnectAbort) {\n        void this.scheduleReconnect();\n      }\n    }, timeoutMs);\n\n    if (typeof timer.unref === \"function\") {\n      timer.unref();\n    }\n\n    this.keepaliveTimer = timer as NodeJS.Timeout;\n  }\n\n  private stopKeepaliveTimer(): void {\n    if (this.keepaliveTimer) {\n      clearTimeout(this.keepaliveTimer);\n      this.keepaliveTimer = undefined;\n    }\n  }\n\n  private async waitForSession(): Promise<void> {\n    if (this.session) {\n      return;\n    }\n\n    await new Promise<void>((resolve, reject) => {\n      const onConnected = (session: EventSubSession) => {\n        cleanup();\n        this.session = session;\n        resolve();\n      };\n      const onError = (error: Error) => {\n        cleanup();\n        reject(error);\n      };\n      const cleanup = () => {\n        this.off(\"connected\", onConnected);\n        this.off(\"error\", onError);\n      };\n\n      this.on(\"connected\", onConnected);\n      this.on(\"error\", onError);\n    });\n  }\n}\n\nconst mapSession = (session: {\n  id: string;\n  status: string;\n  connected_at: string;\n  keepalive_timeout_seconds?: number;\n  reconnect_url?: string | null;\n}): EventSubSession => ({\n  id: session.id,\n  status: session.status,\n  connectedAt: session.connected_at,\n  keepaliveTimeoutSeconds: session.keepalive_timeout_seconds,\n  reconnectUrl: session.reconnect_url ?? undefined\n});\n\nconst defaultEventSubWebSocketUrl = (): string => \"wss://eventsub.wss.twitch.tv/ws\";\n","#!/usr/bin/env node\n\n// Load environment variables from .env file\nimport \"dotenv/config\";\nimport { TwitchAuth } from \"./auth.js\";\nimport { realpathSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\n/**\n * Interactive OAuth setup CLI tool for velho\n * \n * This tool helps users set up their Twitch bot credentials by:\n * 1. Starting a local HTTP server\n * 2. Generating an authorization URL\n * 3. Exchanging the returned code for access + refresh tokens\n * 4. Persisting TWITCH_BOT_REFRESH_TOKEN and TWITCH_BOT_USERNAME to .env\n */\n\ninterface CliOptions {\n    port?: number;\n    host?: string;\n    scopes?: string[];\n    envFile?: string;\n}\n\nclass VelhoOAuthSetup {\n    private readonly clientId: string;\n    private readonly clientSecret: string;\n    private readonly auth: TwitchAuth;\n    private readonly port: number;\n    private readonly host: string;\n    private readonly redirectUri: string;\n    private readonly scopes: string[];\n    private readonly envFile: string;\n    private readonly state: string;\n    private server?: any;\n\n    constructor(options: CliOptions = {}) {\n        this.clientId = process.env.TWITCH_CLIENT_ID || \"\";\n        this.clientSecret = process.env.TWITCH_CLIENT_SECRET || \"\";\n\n        if (!this.clientId || !this.clientSecret) {\n            console.error(\"❌ Missing TWITCH_CLIENT_ID or TWITCH_CLIENT_SECRET in environment.\");\n            console.error(\"Please set these environment variables and try again.\");\n            process.exit(1);\n        }\n\n        this.auth = new TwitchAuth({\n            clientId: this.clientId,\n            clientSecret: this.clientSecret,\n        });\n\n        this.port = options.port || Number(process.env.OAUTH_PORT) || 5173;\n        this.host = options.host || \"localhost\";\n        this.redirectUri = `http://${this.host}:${this.port}/callback`;\n        this.scopes = options.scopes || [\"chat:read\", \"chat:edit\"];\n        this.envFile = options.envFile || \".env\";\n        this.state = Math.random().toString(36).slice(2);\n    }\n\n    private buildAuthorizeUrl(): string {\n        const params = new URLSearchParams({\n            client_id: this.clientId,\n            redirect_uri: this.redirectUri,\n            response_type: \"code\",\n            scope: this.scopes.join(\" \"),\n            state: this.state,\n        });\n        return `https://id.twitch.tv/oauth2/authorize?${params.toString()}`;\n    }\n\n    private async exchangeCodeForTokens(code: string) {\n        return await this.auth.exchangeAuthorizationCode({\n            code,\n            redirectUri: this.redirectUri,\n        });\n    }\n\n    private async fetchUserLogin(accessToken: string): Promise<string> {\n        const res = await fetch(\"https://api.twitch.tv/helix/users\", {\n            headers: {\n                Authorization: `Bearer ${accessToken}`,\n                \"Client-Id\": this.clientId,\n            },\n        });\n\n        if (!res.ok) {\n            const text = await res.text();\n            throw new Error(`Failed to fetch user: ${res.status} ${text}`);\n        }\n\n        const json = (await res.json()) as { data: Array<{ login: string }> };\n        if (!json.data?.[0]?.login) {\n            throw new Error(\"Unexpected users response\");\n        }\n\n        return json.data[0].login.toLowerCase();\n    }\n\n    private async upsertEnv(entries: Record<string, string>): Promise<void> {\n        const fs = await import(\"node:fs/promises\");\n        const path = await import(\"node:path\");\n        const envPath = path.resolve(process.cwd(), this.envFile);\n\n        let content = \"\";\n        try {\n            content = await fs.readFile(envPath, \"utf8\");\n        } catch {\n            content = \"\";\n        }\n\n        const lines = content.split(/\\r?\\n/);\n        const map = new Map<string, string>();\n\n        for (const line of lines) {\n            if (!line || line.trim().startsWith(\"#\")) continue;\n            const idx = line.indexOf(\"=\");\n            if (idx === -1) continue;\n            const key = line.slice(0, idx).trim();\n            const val = line.slice(idx + 1);\n            if (key) map.set(key, val);\n        }\n\n        for (const [k, v] of Object.entries(entries)) {\n            map.set(k, v);\n        }\n\n        const out = Array.from(map.entries())\n            .map(([k, v]) => `${k}=${v}`)\n            .join(\"\\n\") + \"\\n\";\n\n        await fs.writeFile(envPath, out, \"utf8\");\n    }\n\n    private async createServer() {\n        // Try to use Bun's server if available, otherwise fall back to Node.js\n        if (typeof (globalThis as any).Bun !== \"undefined\" && (globalThis as any).Bun.serve) {\n            return (globalThis as any).Bun.serve({\n                port: this.port,\n                fetch: this.handleRequest.bind(this),\n            });\n        } else {\n            // Fallback to Node.js HTTP server\n            const { createServer } = await import(\"node:http\");\n            return createServer((req: any, res: any) => {\n                this.handleNodeRequest(req, res);\n            }).listen(this.port);\n        }\n    }\n\n    private async handleRequest(req: Request): Promise<Response> {\n        const url = new URL(req.url);\n\n        if (url.pathname === \"/\") {\n            const authorizeUrl = this.buildAuthorizeUrl();\n            const html = `<!doctype html><html><body>\n        <h1>Twitch Bot Authorization</h1>\n        <p><a href=\"${authorizeUrl}\">Click here to authorize the bot</a></p>\n        <p>If the link doesn't open, copy this URL into your browser:</p>\n        <pre>${authorizeUrl}</pre>\n      </body></html>`;\n            return new Response(html, { headers: { \"Content-Type\": \"text/html\" } });\n        }\n\n        if (url.pathname === \"/callback\") {\n            return this.handleCallback(url);\n        }\n\n        return new Response(\"Not Found\", { status: 404 });\n    }\n\n    private async handleNodeRequest(req: any, res: any) {\n        const url = new URL(req.url, `http://${this.host}:${this.port}`);\n\n        if (url.pathname === \"/\") {\n            const authorizeUrl = this.buildAuthorizeUrl();\n            const html = `<!doctype html><html><body>\n        <h1>Twitch Bot Authorization</h1>\n        <p><a href=\"${authorizeUrl}\">Click here to authorize the bot</a></p>\n        <p>If the link doesn't open, copy this URL into your browser:</p>\n        <pre>${authorizeUrl}</pre>\n      </body></html>`;\n            res.writeHead(200, { \"Content-Type\": \"text/html\" });\n            res.end(html);\n            return;\n        }\n\n        if (url.pathname === \"/callback\") {\n            const response = await this.handleCallback(url);\n            res.writeHead(response.status, Object.fromEntries(response.headers.entries()));\n            res.end(await response.text());\n            return;\n        }\n\n        res.writeHead(404);\n        res.end(\"Not Found\");\n    }\n\n    private async handleCallback(url: URL): Promise<Response> {\n        const returnedState = url.searchParams.get(\"state\") ?? \"\";\n        const code = url.searchParams.get(\"code\");\n        const error = url.searchParams.get(\"error\");\n\n        if (error) {\n            return new Response(`Authorization error: ${error}`, { status: 400 });\n        }\n        if (!code) {\n            return new Response(\"Missing authorization code\", { status: 400 });\n        }\n        if (returnedState !== this.state) {\n            return new Response(\"State mismatch\", { status: 400 });\n        }\n\n        try {\n            const userToken = await this.exchangeCodeForTokens(code);\n            const login = await this.fetchUserLogin(userToken.accessToken);\n\n            await this.upsertEnv({\n                TWITCH_BOT_REFRESH_TOKEN: userToken.refreshToken,\n                TWITCH_BOT_USERNAME: login,\n            });\n\n            const html = `<!doctype html><html><body>\n        <h2>✅ Authorization complete</h2>\n        <p>Saved TWITCH_BOT_REFRESH_TOKEN and TWITCH_BOT_USERNAME to ${this.envFile}.</p>\n        <p>You can close this window now.</p>\n      </body></html>`;\n\n            // Close server shortly after success\n            queueMicrotask(() => {\n                setTimeout(() => {\n                    this.stop();\n                    console.log(`\\n✅ Saved credentials to ${this.envFile}. You can now run your bot!\\n`);\n                }, 250);\n            });\n\n            return new Response(html, { headers: { \"Content-Type\": \"text/html\" } });\n        } catch (e) {\n            const msg = e instanceof Error ? e.message : String(e);\n            return new Response(`Token exchange failed: ${msg}`, { status: 500 });\n        }\n    }\n\n    private stop() {\n        if (this.server) {\n            if (typeof this.server.stop === \"function\") {\n                this.server.stop(true);\n            } else if (typeof this.server.close === \"function\") {\n                this.server.close();\n            }\n        }\n    }\n\n    async run(): Promise<void> {\n        console.log(`\\n🚀 Starting Twitch OAuth setup server...`);\n        console.log(`📡 Server listening on http://${this.host}:${this.port}`);\n        console.log(`🔗 Open this URL to authorize the bot:\\n`);\n        console.log(this.buildAuthorizeUrl());\n        console.log(`\\n⏳ Waiting for authorization...`);\n\n        this.server = await this.createServer();\n\n        // Handle graceful shutdown\n        process.on(\"SIGINT\", () => {\n            console.log(\"\\n👋 Shutting down...\");\n            this.stop();\n            process.exit(0);\n        });\n    }\n}\n\n// CLI interface\nasync function main() {\n    const args = process.argv.slice(2);\n    const options: CliOptions = {};\n\n    // Parse command line arguments\n    for (let i = 0; i < args.length; i++) {\n        const arg = args[i];\n        switch (arg) {\n            case \"--port\":\n            case \"-p\":\n                options.port = parseInt(args[++i]);\n                break;\n            case \"--host\":\n            case \"-h\":\n                options.host = args[++i];\n                break;\n            case \"--scopes\":\n            case \"-s\":\n                options.scopes = args[++i].split(\",\");\n                break;\n            case \"--env-file\":\n            case \"-e\":\n                options.envFile = args[++i];\n                break;\n            case \"--help\":\n                console.log(`\nTwitch OAuth Setup Tool for velho\n\nUsage: velho-setup [options]\n\nOptions:\n  -p, --port <number>     Port for the OAuth server (default: 5173)\n  -h, --host <string>     Host for the OAuth server (default: localhost)\n  -s, --scopes <string>   Comma-separated list of scopes (default: chat:read,chat:edit)\n  -e, --env-file <path>   Path to .env file (default: .env)\n  --help                  Show this help message\n\nEnvironment Variables Required:\n  TWITCH_CLIENT_ID        Your Twitch application client ID\n  TWITCH_CLIENT_SECRET    Your Twitch application client secret\n\nExample:\n  velho-setup --port 3000 --scopes chat:read,chat:edit,moderator:read:followers\n`);\n                process.exit(0);\n        }\n    }\n\n    const setup = new VelhoOAuthSetup(options);\n    await setup.run();\n}\n\n// Run if this file is executed directly (ESM only)\nconst invokedFromCli = (() => {\n    const candidate = process.argv[1];\n    if (!candidate || candidate.startsWith(\"-\")) {\n        return false;\n    }\n\n    try {\n        const entryPath = realpathSync(fileURLToPath(import.meta.url));\n        const invokedPath = realpathSync(resolve(candidate));\n        return entryPath === invokedPath;\n    } catch {\n        return false;\n    }\n})();\n\nif (invokedFromCli) {\n    main().catch((error) => {\n        console.error(\"❌ Setup failed:\", error.message);\n        process.exit(1);\n    });\n}\n\nexport { VelhoOAuthSetup };\n"],"mappings":"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","names":["import_zod","resolveFetch","WebSocket","delay","resolve","import_node_events","import_promises","import_ws","import_zod","WebSocket","delay","resolve"]}