# DiscordJS API The runner does not bundle discord.js in the Vite graph. It uses the host: ```js await BridgeSwarm.ready() const { Client, GatewayIntentBits, Events, SlashCommandBuilder, REST, Routes, } = BridgeSwarm.DiscordJS const client = new Client({ intents: [GatewayIntentBits.Guilds, GatewayIntentBits.DirectMessages], }) client.once(Events.ClientReady, (c) => { console.log('Logged in as', c.user.tag) }) client.on(Events.InteractionCreate, async (ix) => { if (ix.isChatInputCommand() && ix.commandName === 'ping') { await ix.reply('pong') } }) await client.login(token) ``` ## Same names, different process Class names match **discord.js 14**. The `Client` instance lives in the Bare host. Method calls are RPC. That is why [fidelity](/docs/runtime/fidelity) exists: caches are snapshots. `Events.ClientReady` may also appear as `Ready` / `clientReady` depending on host build. TabBot’s runner listens to several aliases. ## REST `new REST().setToken(token)` then `Routes.applicationCommands(appId)` is how TabBot registers slash commands. On the Code track, export `commands` instead of calling REST yourself — a second PUT overwrites the merged list (modules + your builders). ## Gateway ping `client.ws.ping` is a snapshot. For a live heartbeat, `await client.invoke?.('ws.ping')` (a number, or `-1` until the first heartbeat ACK after login/reload). `/ping` should defer and wait a few seconds rather than treating `-1` as n/a. ## invoke() Escape hatch for host methods that are not on the JS stub. See [invoke()](/docs/runtime/invoke).