Read Every Failure

Requests return a Result to check, and the SDK repeats a write only after a rate limit

A signpost with one arm marked by a check and one by a cross

Calls Return a Result

A request such as a reply does not throw when Fluxer refuses it or the network drops. It returns a Result, a value that holds either what the request produced or why it failed

Check isErr() first, then read value. A missing permission or a network error arrives as the Result's error, so no try and catch is needed

Results in the Core Concepts
TypeScript
import { describeError, type Client, type Message } from "@neontechspace/fluxerly"export async function replyHello(client: Client, message: Message) {    if (message.author.isBot) return    const result = await client.messages.reply(message, `Hello, ${message.author.username}!`)    if (result.isErr()) {        console.error(describeError(result.error))        return    }    return result.value}

Retry Only When It Is Safe

A send that failed may still have been posted, for example when the answer was lost on its way back. Sending again would reply twice

errors.isRetryable says yes only when repeating the call is safe, such as when the first attempt never left the bot. Any other failure is returned, and the SDK reports it with its message and suggested fix

The SDK keeps the same rule for itself. It sends a write again only after Fluxer asks it to wait for a rate limit, never a write whose outcome is unknown

Reliability in the Docs
A circular arrow on a stand
TypeScript
import { errors, runBot } from "@neontechspace/fluxerly"await runBot({    token: process.env.FLUXER_BOT_TOKEN,    events: {        messageCreate: async ({ message, reply }) => {            if (message.content !== "!ping") return undefined            const first = await reply("Pong!")            if (first.isOk() || !errors.isRetryable(first.error)) return first            await new Promise((resolve) => setTimeout(resolve, errors.retryAfterMs(first.error) ?? 1_000))            return reply("Pong!")        },    },})

Failures with No Caller Go to onError

A handler that throws or a command that fails has no caller to return to. The SDK sends each one to onError, a hook you pass to runBot, with the original error and the IDs of the message involved, never its content

Without a hook, the SDK logs the failure in full. Reports wait their turn while the hook is busy, and any that cannot wait are logged instead and counted, so none disappear

Handle Failures in One Place
TypeScript
import { runBot } from "@neontechspace/fluxerly"export function runReportedBot(token: string | undefined, report: (text: string) => void) {    return runBot({        token,        onError: (failure) => report(failure.describe()),        events: {            messageCreate: ({ message, reply }) => {                if (message.content !== "!ping") return undefined                return reply("Pong!")            },        },    })}

Errors with a Code and a Hint

Every SDK error has a fixed code, a hint with the next step when there is one, and details that are safe to log. errors.apiCode names Fluxer's own reason, such as missingPermissions

describeError prints all of it with the chain of causes, and masks credentials on the way

Read an SDK Error
TypeScript
import { describeError, errors, type Client, type Message } from "@neontechspace/fluxerly"export async function replyOrExplain(client: Client, message: Message) {    const result = await client.messages.reply(message, "Pong!")    if (result.isOk()) return result.value    const error = result.error    console.warn(error.code) // A fixed code, such as message.send.rejected    console.warn(error.hint) // The suggested next step, when there is one    if (errors.apiCode(error) === "missingPermissions") {        console.warn(error.details.requiredPermissions) // Such as ["ViewChannel", "SendMessages"]    }    console.error(describeError(error)) // All of it, with the chain of causes}

What the Log Says

When a handler fails, the log prints one Error record with the event, the IDs of the message and the error. An expected SDK error shows its code, hint and details instead of stack frames

This one is a reply the bot was not allowed to send. The hint names the permissions to grant and where, and no record ever contains the token

Read the Default Output
Terminal

ERRORevents[events.handlerFailed]

The messageCreate handler failed: Message send failed: Fluxer reports that the bot lacks a required permission (MISSING_PERMISSIONS, HTTP 403)

event=messageCreatesubscriptionId=messageCreate#1messageId=1456074443980800006channelId=1456074443980800002guildId=1456074443980800001

MessageError [message.send.rejected]: Message send failed: Fluxer reports that the bot lacks a required permission (MISSING_PERMISSIONS, HTTP 403)

HintThe bot needs View channel and Send messages for this operation. Grant them to the bot's role in the community settings or the channel's permission overrides. Embeds also need Embed links, files need Attach files, and a forward needs View channel in its source channel

Detailsoperation=sendreason=rejectedoutcome=rejectedstatus=403apiError=MISSING_PERMISSIONSrequiredPermissions=["ViewChannel","SendMessages"]