UNPKG

framework

Version:

The (AI) Framework: turnkey, zero-config AI orchestration that wraps a coding-agent CLI (Claude Code) as a black box and takes you from an idea to a running app. Vite for AI.

137 lines 5.67 kB
/** * A minimal Discord gateway client (#680): the inbound half of the Discord integration, which * until now was outbound-only — a webhook `POST` can notify, but it cannot read a reply (#627). * * Deliberately hand-rolled over the global `WebSocket` rather than pulling in `discord.js`. The * package has three runtime dependencies and builds everything else on node builtins behind * injectable seams; a client library for the handful of opcodes below would be the largest * dependency in the package by an order of magnitude. * * Implements only what a chat bot needs: identify, heartbeat, resume, and message events. */ /** Gateway opcodes we act on. */ export declare const OP: { readonly dispatch: 0; readonly heartbeat: 1; readonly identify: 2; readonly resume: 6; readonly reconnect: 7; readonly invalidSession: 9; readonly hello: 10; readonly heartbeatAck: 11; }; /** * Gateway intents. `MESSAGE_CONTENT` is privileged: it must be enabled on the application in * Discord's developer portal, or the gateway connects and every message arrives with an empty * `content`. That failure is silent, which is why {@link DiscordGateway} logs it explicitly. */ export declare const INTENTS: { readonly guildMessages: number; readonly directMessages: number; readonly messageContent: number; }; /** The intents a chat bot needs: messages in channels and DMs, plus their text. */ export declare const CHAT_INTENTS: number; /** * The socket seam. Mirrors the slice of `WebSocket` this uses, so a test drives the protocol * with a fake and no network — the same shape the watchers use for `fetch`. */ export interface GatewaySocket { send(data: string): void; close(): void; onMessage(handler: (data: string) => void): void; onClose(handler: () => void): void; onError(handler: (err: unknown) => void): void; } /** Opens a {@link GatewaySocket} for a url. */ export type SocketFactory = (url: string) => GatewaySocket; /** A cancellable timer, so heartbeats are deterministic under test. */ export interface Timer { stop(): void; } /** Schedules `fn` every `ms`. Default wraps `setInterval` and unrefs it. */ export type IntervalFactory = (fn: () => void, ms: number) => Timer; /** Schedules `fn` once after `ms`. Default wraps `setTimeout` and unrefs it. */ export type DelayFactory = (fn: () => void, ms: number) => Timer; /** One inbound chat message, narrowed to what routing needs. */ export interface DiscordMessage { id: string; channelId: string; /** Message text. Empty when the privileged MESSAGE_CONTENT intent is not enabled. */ content: string; authorId: string; authorName: string; /** Whether the author is a bot (including us): never act on these, or two bots loop forever. */ fromBot: boolean; /** Set when the message replies to another, used to thread an answer back to its gate. */ replyToId?: string; } /** What {@link DiscordGateway} reports to its owner. */ export interface GatewayHandlers { onMessage(message: DiscordMessage): void; /** Connected and identified; carries our own user id so we can ignore our own messages. */ onReady?(selfId: string): void; /** Non-fatal diagnostics (a failed resume, a missing intent). */ onLog?(message: string): void; } /** Injectable seams for {@link DiscordGateway}. */ export interface GatewayDeps { socket?: SocketFactory; interval?: IntervalFactory; delay?: DelayFactory; url?: string; } /** * A connected Discord bot session. Owns the socket, the heartbeat, and the resume state; hands * every chat message to its {@link GatewayHandlers}. * * Errors are swallowed into `onLog` rather than thrown: a notifier must never take the daemon * down, which is the same contract the intervention/activity watchers follow. */ export declare class DiscordGateway { private readonly token; private readonly handlers; private readonly deps; private socket; private heartbeat; private sequence; private sessionId; private resumeUrl; private acked; private selfId; /** Set by {@link stop}, so a socket closing on our own terms never reconnects. */ private stopped; /** Consecutive reconnects, for the backoff. Reset once a connection actually works. */ private attempts; private pendingReconnect; constructor(token: string, handlers: GatewayHandlers, deps?: GatewayDeps); /** Open the connection and identify. Safe to call once; use {@link stop} to end it. */ connect(): void; /** * Close the connection for good. This is what takes the bot offline on `Ctrl+C` (#680): the * daemon calls it from its shutdown block, and no reconnect follows. */ stop(): void; /** Our own user id once READY has landed. */ get userId(): string | undefined; private open; /** * A closed socket we did not close ourselves: resume if we can, else identify fresh. * * Backed off, and that is not a nicety: a connection that fails immediately (offline, a bad * token) closes as fast as it opens, so reconnecting inline is a tight loop that pins a core * and gets the bot rate-limited. Doubles to a cap, and resets once a connection works. */ private reopen; private receive; private onHello; private identify; private resume; private sendHeartbeat; private onDispatch; private send; private log; } /** Narrow a MESSAGE_CREATE payload; `undefined` when it is not a shape we can use. */ export declare function parseMessage(data: unknown): DiscordMessage | undefined; //# sourceMappingURL=gateway.d.ts.map