@flexhd41/fluxor.js
v1.0.1
Published
A JavaScript/TypeScript SDK for the Fluxor platform — bot development made easy.
Maintainers
Readme
Fluxor.js
A JavaScript / TypeScript SDK for the Fluxor platform — build bots and integrations with ease.
Community port of Fluxer.Net (C# / .NET) to the Node.js ecosystem.
Features
- REST API client — 150+ typed endpoint methods covering auth, channels, guilds, users, invites, webhooks, memes, and more.
- Gateway client — WebSocket connection with automatic heartbeats, session resume, exponential-backoff reconnection, latency tracking, and 50+ typed dispatch events.
- Command framework — register commands as plain objects or class modules, with prefix matching, argument parsing, preconditions, and lifecycle hooks.
- EmbedBuilder — fluent, validated API for constructing rich embeds.
- Client-side rate limiting — sliding-window buckets per route to respect Fluxor rate limits.
- Type-safe models — snake_case interfaces matching the wire format, with required vs. optional fields and dedicated mutation payloads.
- 18 enum types —
ChannelType,MessageType,Permissions,UserFlags, and more, ported from the .NET SDK. - Error subclasses —
FluxorRateLimitError,FluxorNotFoundError,FluxorForbiddenErrorfor easy catch handling. - Zero heavy dependencies — only
wsfor WebSocket; uses nativefetch(Node 18+).
Installation
npm install fluxor.jsRequires Node.js 18+ (for native
fetch).
Quick Start
import { Client, createConsoleLogger } from "fluxor.js";
const bot = new Client("Bot YOUR_TOKEN_HERE", {
logger: createConsoleLogger("info"),
presence: { status: "online" },
});
bot.enableGracefulShutdown(); // handles SIGINT/SIGTERM
bot.on("READY", (data) => {
console.log(`Logged in as ${data.user.username}`);
console.log(`Guilds: ${bot.guilds.size}, Channels: ${bot.channels.size}`);
});
bot.on("MESSAGE_CREATE", async (msg) => {
if (msg.content === "!ping") {
await bot.send(msg.channel_id, `Pong! (${bot.ping}ms)`);
}
});
await bot.connect();Architecture
Fluxor.js exposes three levels of abstraction:
| Class | Purpose |
|-------|---------|
| Client | High-level wrapper — bundles ApiClient + GatewayClient, proxies events, maintains caches. Recommended for most bots. |
| ApiClient | REST-only client. Use when you only need HTTP calls without a live WebSocket connection. |
| GatewayClient | WebSocket-only client. Use when you want full control over the connection lifecycle. |
Configuration
Pass a FluxorConfig object to any client:
{
apiBaseUrl?: string; // Default: "https://api.fluxer.app/v1"
gatewayUrl?: string; // Default: "wss://gateway.fluxer.app/?v=1&encoding=json"
requestTimeout?: number; // REST request timeout in ms (default: 15000)
reconnectDelay?: number; // Base reconnect delay in seconds (default: 2)
maxReconnectAttempts?: number; // Max reconnects before giving up (default: Infinity)
enableRateLimiting?: boolean; // Default: true
presence?: PresenceData; // Initial bot status
ignoredGatewayEvents?: (keyof GatewayEvents)[]; // Type-safe event filter
logger?: Logger; // Any object with debug/info/warn/error methods
}Token Format
- Bot tokens must be prefixed with
Bot(with a trailing space):"Bot flx_abc123..." - User tokens must start with
flx_:"flx_abc123..."
Client Caches
After connecting, the Client automatically maintains in-memory caches:
bot.user // The bot's own User object
bot.guilds // Map<string, Guild> — keyed by guild ID
bot.channels // Map<string, Channel> — keyed by channel ID
bot.users // Map<string, User> — populated from events
bot.isReady // boolean
bot.readyAt // Date | null
bot.uptime // milliseconds since READY
bot.ping // last heartbeat round-trip latency in msSending Messages
// String shorthand
await bot.send(channelId, "Hello!");
// Full payload
await bot.send(channelId, {
content: "Check out this embed!",
embeds: [embed],
});
// Or via the API client directly
await bot.api.sendMessage(channelId, "Hello!");EmbedBuilder
import { EmbedBuilder } from "fluxor.js";
const embed = new EmbedBuilder()
.setTitle("My Embed")
.setDescription("Built with the fluent API")
.setColor(0x5865f2)
.addField("Field 1", "Value 1", true)
.addField("Field 2", "Value 2", true)
.setFooter("Fluxor.js")
.setTimestamp()
.build();
await bot.send(channelId, { embeds: [embed] });Command Framework
import { Client, CommandService } from "fluxor.js";
import type { CommandDefinition } from "fluxor.js";
const commands = new CommandService({ prefix: "!" });
const ping: CommandDefinition = {
name: "ping",
summary: "Check latency",
execute: async (ctx) => {
await ctx.reply("Pong!");
},
};
commands.addCommand(ping);
bot.on("MESSAGE_CREATE", async (msg) => {
if (!msg.author?.bot) {
const argPos = commands.hasPrefix(msg.content ?? "");
if (argPos >= 0) {
await commands.execute(msg, bot.api, bot.gateway, argPos);
}
}
});Preconditions
import { requireGuild, requireOwner } from "fluxor.js";
const adminCmd: CommandDefinition = {
name: "admin",
preconditions: [requireGuild(), requireOwner("your-user-id")],
execute: async (ctx) => { await ctx.reply("Admin only!"); },
};Argument Parsing
import { NumberParser } from "fluxor.js";
const roll: CommandDefinition = {
name: "roll",
parameters: [
{ name: "sides", type: NumberParser, optional: true, defaultValue: 6 },
],
execute: async (ctx, sides: unknown) => {
const n = sides as number;
await ctx.reply(`You rolled a ${Math.floor(Math.random() * n) + 1}`);
},
};waitFor Utility
// Wait for a specific event with an optional filter and timeout
const msg = await bot.waitFor("MESSAGE_CREATE", {
filter: (m) => m.channel_id === "123" && m.author?.id === "456",
timeout: 30_000,
});Gateway Events
Subscribe to any event name from the Fluxor gateway:
bot.on("MESSAGE_CREATE", (msg) => { ... });
bot.on("GUILD_MEMBER_ADD", (member) => { ... });
bot.on("TYPING_START", (typing) => { ... });
bot.on("HEARTBEAT_ACK", (latencyMs) => { ... });
// ... 50+ events — fully typed via GatewayEvents interfaceA raw event is also emitted for every dispatch:
bot.on("raw", ({ event, data }) => {
console.log(`Event: ${event}`, data);
});Enums
All 18 enum types from the .NET SDK are available:
import { ChannelType, MessageType, Permissions, hasPermission } from "fluxor.js";
if (channel.type === ChannelType.GuildText) { ... }
if (hasPermission(BigInt(member.permissions), Permissions.BanMembers)) { ... }Error Handling
import { FluxorApiError, FluxorRateLimitError, FluxorNotFoundError } from "fluxor.js";
try {
await bot.api.getChannel("invalid-id");
} catch (err) {
if (err instanceof FluxorNotFoundError) {
console.log("Channel not found");
} else if (err instanceof FluxorRateLimitError) {
console.log(`Rate limited, retry after ${err.retryAfter}ms`);
}
}Rate Limiting
Client-side rate limiting is enabled by default. The SDK uses a sliding-window algorithm with per-route buckets (mirroring the .NET SDK's approach):
const bot = new Client("Bot TOKEN", { enableRateLimiting: false }); // opt outProject Structure
src/
index.ts — Barrel re-exports
config.ts — FluxorConfig, defaults
errors.ts — Error classes (FluxorApiError + subclasses)
client/Client.ts — High-level Client with caches
api/ApiClient.ts — REST client (150+ methods)
gateway/
GatewayClient.ts — WebSocket client with latency tracking
opcodes.ts — FluxorOpCode enum
closeCodes.ts — Close code handling
packets.ts — Packet type definitions
builders/
EmbedBuilder.ts — Fluent embed builder with validation
commands/
CommandService.ts — Command registration & dispatch
CommandContext.ts — Per-invocation context
ModuleBase.ts — Base class for command modules
Command.ts — Core types (CommandDefinition, etc.)
preconditions.ts — requireGuild, requireOwner, requirePermissions
typeParsers.ts — Built-in argument parsers
rateLimit/
RateLimitBucket.ts — Sliding-window bucket
RateLimitManager.ts — Bucket manager
RateLimitConfig.ts — Config interface
RateLimitMappings.ts— Route-to-bucket map
types/
models.ts — 40+ data model interfaces + mutation payloads
gateway.ts — 50+ gateway event payload types
enums.ts — 18 enum / constant types
util/
logger.ts — Logger interface + console logger
token.ts — Token validation
examples/
bot.ts — Example bot with commands + embedsLicense
MIT — matching Fluxer.Net.
