Reading and Caching Data
History reads, opt-in caches and collectors, with cached copies kept apart from fresh fetches

History Without the Gateway
Reading earlier messages is a request to Fluxer, so it works without the gateway connection. iterateHistory reads newest first and asks for the next page only when the loop needs it, within the maxItems bound you set
When the text is known, search asks Fluxer's search index for a page of results. While Fluxer is still preparing that index, the helper returns undefined instead of an empty answer that looks final
import type { Client, Message } from "@neontechspace/fluxerly"export async function findRecentMessage( client: Client, channelId: string, matches: (message: Message) => boolean, ) { for await (const item of client.messages.iterateHistory(channelId, { maxItems: 200 })) { if (item.isErr()) return item if (matches(item.value)) return item } return undefined}import type { Client } from "@neontechspace/fluxerly"export async function searchChannel(client: Client, channelId: string, text: string) { const result = await client.messages.search({ channelId }, { content: text, limit: 10 }) if (result.isErr()) return result if (result.value.indexing) return undefined return result.value.messages }Caches You Size and Choose
A cache is a local copy of Fluxer data, and the client keeps none unless asked. Each category you turn on is bounded, by default to 1,000 entries and 4 MiB (8 MiB for messages), and a maxAgeMs function decides per entry. The value null keeps it and 0 skips it
Community data stays when a session resumes, except cached threads, which are cleared. A new session clears community data. Messages that a lost connection could have changed are cleared either way

import { createClient } from "@neontechspace/fluxerly"export function createCachedClient(token: string, watched: ReadonlySet<string>) { return createClient({ token, cache: { guilds: true, // Keep channels of watched communities with no age limit, skip all others channels: { maxAgeMs: (channel) => (watched.has(channel.guildId) ? null : 0) }, messages: { maxEntries: 500, maxBytes: 2_000_000, maxAgeMs: 60_000 }, }, })}Local Get, Remote Fetch
messages.get returns the copy the client already holds, without a request, or undefined. fetch asks Fluxer for the current state. The two stay separate calls, so the code always shows which one it uses
A cached copy is a snapshot of what the client last saw, and Fluxer still decides what a request may do. After a clear, a read already in flight cannot put the removed entry back
Fluxer still checks every request, whatever the cache holds
Use the Cache, Then Fetchimport { orThrow, type Client, type MessageReference } from "@neontechspace/fluxerly"export async function readCachedOrFetch(client: Client, message: MessageReference) { const cached = client.messages.get(message) if (cached !== undefined) return cached return orThrow(await client.messages.fetch(message, { timeoutMs: 5_000 })) }
Ask, Then Collect the Answer
waitFor returns the next matching event, or a failed Result if none arrives within timeoutMs, 30 seconds by default. A collector gathers matching messages or reactions for a limited time, and created before the question is sent, it cannot miss a fast reply
await using closes the collector when the helper returns or throws, and waits for its cleanup. A lost connection fails the collection instead of returning answers that may be incomplete
import { orThrow, type Client } from "@neontechspace/fluxerly"export async function askPreferredName(client: Client, channelId: string, userId: string) { await using collector = client.messages.collect(channelId, { filter: (message) => message.author.id === userId && !message.author.isBot, maxMessages: 1, timeoutMs: 30_000, }) orThrow(await client.messages.send(channelId, "What name should the bot use?")) const answer = orThrow(await collector.result()) return answer.messages[0]?.content }import { orThrow, type Client, type MessageReference } from "@neontechspace/fluxerly"export async function waitForConfirmation(client: Client, message: MessageReference, userId: string) { await using collector = client.messages.collectReactions(message, { emoji: "✅", filter: (reaction) => reaction.userId === userId, maxReactions: 1, timeoutMs: 20_000, }) const result = orThrow(await collector.result()) return result.reactions.length > 0 }Invalid Events Are Logged and Skipped
When Fluxer sends a known event that fails validation, the SDK logs gateway.dispatchRejected with the event type and the failing field, skips the event and keeps the session running
It also clears the cache entries that event could have changed. A bot that would rather stop can set gateway.onMalformedDispatch to "terminate"
import type { Client } from "@neontechspace/fluxerly"// Gateway events that failed validation. Each was logged as gateway.dispatchRejected // and skipped, the cache entries it could have changed were cleared, and the session// kept runningexport function skippedGatewayEvents(client: Client) { return client.diagnostics().counters.eventsDropped.malformed }













