On This Page

Caching

11 symbols from @neontechspace/fluxerly

Interfaces#

CacheChange#

One change applied to a client-owned cache, delivered to cache.onChange listeners after it happened

A change describes the SDK's local copy, not a remote create, update or delete, and carries no snapshot: Look the entry up with the matching get method when its value matters

interface CacheChange

The key identifies the entry within its kind, using decimal IDs: Messages use channelId:messageId, members use guildId:userId, and roles, emojis and stickers use guildId:id. Communities, channels, users and direct messages use the resource ID alone. A clear has a null key. The cache.delete() method accepts the same keys

// A set can replace an entry and a clear releases a whole kind, so track keys rather than counting events
export function trackCachedKeys(client, keys) {
    return client.cache.onChange((change) => {
        const kindKeys = keys.get(change.kind) ?? new Set()
        keys.set(change.kind, kindKeys)
        if (change.op === "clear")
            kindKeys.clear()
        else if (change.key !== null && change.op === "set")
            kindKeys.add(change.key)
        else if (change.key !== null)
            kindKeys.delete(change.key)
    })
}
import type { Client } from "@neontechspace/fluxerly"
// A set can replace an entry and a clear releases a whole kind, so track keys rather than counting events
export function trackCachedKeys(client: Client, keys: Map<string, Set<string>>) {
    return client.cache.onChange((change) => {
        const kindKeys = keys.get(change.kind) ?? new Set<string>()
        keys.set(change.kind, kindKeys)
        if (change.op === "clear") kindKeys.clear()
        else if (change.key !== null && change.op === "set") kindKeys.add(change.key)
        else if (change.key !== null) kindKeys.delete(change.key)
    })
}
key#

Entry key in the format described for this kind, or null for a clear

string | null
kind#

Cache category whose local copy changed

CacheKind
op#

What happened to the local copy

The value set means an entry was stored or replaced, even with identical content. The value delete means one entry was removed, including removal by cache.delete(), expiry, capacity eviction, an event, a write or a connection gap limited to known communities. The value clear means every entry of this kind was released at once, as by cache.clear() with or without this kind, shutdown, a connection gap of unknown scope or an event or write whose effect cannot be narrowed to single entries. No delete is reported for the entries a clear released

"set" | "clear" | "delete"

CacheDiagnostic#

Current snapshot count and accounted bytes for one local cache category, with running lookup and eviction totals since the client was created

These values measure SDK retention, not how many resources exist remotely or how much process memory is used. A disabled category reports zero for every total

interface CacheDiagnostic
accountedBytes#

Accounted UTF-8 JSON bytes of retained snapshots, excluding JavaScript overhead and caller-held copies

number
configured#

Whether this category was configured when the client was created

A Closing/Closed client accepts no further snapshots

boolean
evictions#

Snapshots this category removed on its own, by reason

Removal by events, writes, cache.delete, clears, connection gaps and shutdown is not counted

capacity

Least recently used snapshots removed to make room within maxEntries or maxBytes

number
expiry

Snapshots removed because their maxAgeMs passed

number
hits#

Local lookups, such as client.messages.get, that returned a snapshot, including lookups the SDK makes itself

number
maxBytes#

Configured client-wide accounted-byte bound, or null when this category was disabled

number | null
maxEntries#

Configured client-wide entry bound, or null when this category was disabled

number | null
misses#

Local lookups that found no snapshot, including one that had just expired

number
retainedEntries#

Snapshots still held by the SDK after expired entries are removed

number

CacheEntriesOptions#

Limit the snapshots returned by one local cache enumeration, without fetching missing resources

interface CacheEntriesOptions
limit optional#

Maximum snapshots to return, from 1 through 1,000, default 100

number

CacheObserver#

Stop receiving cache changes from client.cache.onChange

Use using to close the observer when the enclosing block ends

interface CacheObserver
id#

Identifier of this observer, such as cacheChange#3, used in its log records

string

[dispose]#

Close this observer, as using does at the end of a block

[dispose](): void

close#

Stop delivering changes, including changes recorded or waiting but not yet delivered

Listener work already started is not cancelled. Repeated calls do nothing

close(): void

CacheObserverOptions#

Bound the work one cache.onChange listener can hold, so a listener that falls behind or never finishes cannot grow memory without limit

A listener call is unfinished while its returned Promise or Effect is still running. A synchronous listener finishes each call before the next change, so these bounds never delay or drop its changes. Invalid values are misuse: The default API throws ConfigurationError, and the native API dies with it

interface CacheObserverOptions
// One call at a time, so asynchronous work sees the changes in the order they were applied
export function saveChangesInOrder(client, save) {
    return client.cache.onChange((change) => save(change.key), { concurrency: 1, maxPendingChanges: 1_000 })
}
import type { Client } from "@neontechspace/fluxerly"
// One call at a time, so asynchronous work sees the changes in the order they were applied
export function saveChangesInOrder(client: Client, save: (key: string | null) => Promise<void>) {
    return client.cache.onChange((change) => save(change.key), { concurrency: 1, maxPendingChanges: 1_000 })
}
concurrency optional#

Maximum unfinished listener calls, a positive safe integer, default 256

Later changes wait in the order they were applied until a call finishes

number
maxPendingChanges optional#

Maximum changes waiting for an unfinished call, a positive safe integer, default 256

A change that arrives while this many wait drops the oldest waiting change, logs a cache.changesDropped Warn with the observer's id and how many changes it has dropped, and counts the drop in diagnostics().counters.cacheChangesDropped

number

CachedResources#

Maps each cache category to the snapshot returned by its local lookup and enumeration methods

Message snapshots use this client's selected message fields

interface CachedResources<M extends MessageCore = Message>interface CachedResources<
  M extends MessageCore = Message
>
channels#

Community channels, distinct from private conversations

GuildChannel
directMessages#

Direct-message and group direct-message conversations

DirectMessageChannel
emojis#

Community emoji metadata, not image bytes

GuildEmoji
guilds#

Community identity and settings, without a preloaded member or role list

Guild
members#

Individual community memberships

GuildMember
messages#

Messages encountered by eligible REST calls or gateway events

M
roles#

Community role definitions

GuildRole
stickers#

Community sticker metadata, not image bytes

GuildSticker
users#

Public account profiles, not partial message authors

User

ClientCache#

Inspect, clear or remove data already held in this client's caches

These methods do not fetch, refresh or change remote resources

interface ClientCache<M extends MessageCore = Message>interface ClientCache<
  M extends MessageCore = Message
>

clear#

Release data held by this client's caches without changing which caches are enabled

Pass a kind to release only that category, or omit it to release every category. Objects already returned to the caller, requests and remote resources stay unchanged. Older in-flight reads cannot refill the cleared entries and may skip caching their results, while later reads can cache normally. Existing write-related invalidation remains in effect. Each category that held entries reports one clear change to cache.onChange listeners, and a disabled category is left as is. This runs immediately, takes no signal and can be repeated, including after closure. An invalid kind is misuse: Both APIs throw ConfigurationError without exposing the rejected value

clear(kind?: CacheKind): void

Parameters

kind optional
CacheKind

delete#

Remove one entry from a cache category by its key, without fetching, refreshing or changing the remote resource

The key uses the format described on CacheChange: channelId:messageId for messages, guildId:userId for members, guildId:id for roles, emojis and stickers, and the resource ID alone for communities, channels, users and direct messages. Objects already returned to the caller stay unchanged. Reads of this category already in flight cannot restore the removed entry and some may skip caching their other results, while later reads and events can cache it again. A removed entry reports one delete change to cache.onChange listeners, and a missing entry or disabled category is left as is. This runs immediately, takes no signal and can be repeated, including after closure. An invalid kind or key is misuse: Both APIs throw ConfigurationError without exposing the rejected value

delete(kind: CacheKind, key: string): voiddelete(
  kind: CacheKind,
  key: string
): void

Parameters

key
string
export function forgetMember(client, guildId, userId) {
    client.cache.delete("members", `${guildId}:${userId}`)
}
import type { Client } from "@neontechspace/fluxerly"
export function forgetMember(client: Client, guildId: string, userId: string) {
    client.cache.delete("members", `${guildId}:${userId}`)
}

entries#

Return frozen snapshots from one configured cache category, ordered least to most recently used

The limit option defaults to 100 and accepts a positive safe integer from 1 through 1,000. It is read once, so the validated limit is the one applied. Expired entries are released first. Enumeration neither refreshes them nor changes eviction order, while local lookups do promote recency. Unlike diagnostics, the array contains actual cached resource data, and no network request or remote completeness claim is made. It may be partial because cache limits, expiry, conflicts, gateway gaps, clear or shutdown can discard entries. A closed client produces an empty array. Invalid kind or limit is misuse: The default API throws ConfigurationError without exposing the rejected value, and the native API dies with it

entries<K extends CacheKind>(
    kind: K,
    options?: CacheEntriesOptions
): readonly CachedResources<M>[K][]entries<K extends CacheKind>(
  kind: K,
  options?: CacheEntriesOptions
): readonly CachedResources<M>[K][]

Parameters

kind
K
options optional
CacheEntriesOptions
Returns
readonly CachedResources<M>[K][]

Returns the array synchronously and takes no signal. Misuse throws ConfigurationError, and a throwing limit getter throws SdkDefect with code application.defect and the thrown value as its cause

onChange#

Observe every later change to this client's local caches: Stored or replaced entries, removed entries and whole-category clears

Changes are delivered in the order they were applied, from a microtask after the cache work that produced them, so a listener never runs inside a cache operation and can read or clear the cache itself. Lookups, enumeration and diagnostics are not changes, and a clear is reported only for a category that held at least one entry. No change is recorded while no listener is registered, and a new listener receives no earlier changes or current contents. Delivery has no ordering relative to event handlers, and listener work never changes a cache result, a REST outcome or event delivery. A failing listener is reported as a cache failure to the client-level onError, or logged at Error, and keeps receiving later changes. Client shutdown records its final clears, then closes every observer without waiting for unfinished listener calls. A listener with a free call receives those clears, and changes still waiting for a busy listener are dropped with a cache.changesDropped Warn. Registering after shutdown returns an observer that never receives a change. A listener that is not a function, or invalid options, is misuse: The default API throws ConfigurationError, and the native API dies with it

onChange(
    listener: (change: CacheChange) => unknown,
    options?: CacheObserverOptions
): CacheObserveronChange(
  listener: (change: CacheChange)
    => unknown,
  options?: CacheObserverOptions
): CacheObserver

Parameters

listener
(change: CacheChange) => unknown
options optional
CacheObserverOptions

Returns the observer synchronously. The listener runs once per change. It fails when it throws, rejects, or returns or resolves an Err result. A returned promise is not awaited, so asynchronous listener calls overlap, up to options.concurrency unfinished calls, 256 by default. Later changes then wait in order, up to options.maxPendingChanges, 256 by default, and a change arriving at that limit drops the oldest waiting change with a cache.changesDropped Warn. Waiting changes are discarded when the observer closes. A throwing options getter throws SdkDefect with code application.defect and the thrown value as its cause

export function cacheChangesExample(client, forget) {
    return client.cache.onChange((change) => {
        if (change.kind === "members" && change.op === "delete" && change.key !== null)
            forget(change.key)
    })
}
import type { Client } from "@neontechspace/fluxerly"
export function cacheChangesExample(client: Client, forget: (key: string) => void) {
    return client.cache.onChange((change) => {
        if (change.kind === "members" && change.op === "delete" && change.key !== null) forget(change.key)
    })
}

MessageCacheOptions#

Configure the message cache in either API

An options object enables caching with defaults for omitted settings. A throwing or invalid maxAgeMs callback is reported to the client-level onError option as a cache FailureReport, or logged at Error with the thrown value when no hook is set

interface MessageCacheOptions<M extends MessageCore = Message>
    extends MessageCacheSettings<M>interface MessageCacheOptions<
  M extends MessageCore = Message
>
  extends MessageCacheSettings<M>

Inherited from MessageCacheSettings: maxAgeMs, maxBytes, maxEntries

MessageCacheSettings#

Bound the message snapshots kept for local lookups in either API style

Enable the cache in ClientOptions.cache.messages before using these settings. Eligible fetch, send, reply, edit and history results, plus gateway create and update events, supply snapshots. Entry and byte limits apply across this client, not separately per channel or community. Capacity eviction removes the least recently used snapshot first. An oversized or zero-age replacement removes the older copy without retaining the new one

interface MessageCacheSettings<M extends MessageCore = Message>interface MessageCacheSettings<
  M extends MessageCore = Message
>

A cache hit is a past observation, not proof of current server state or complete channel history

Connection gaps prevent older responses from refilling affected snapshots, even after resume. If a newer read or change overlaps a pending response, that response cannot add or renew a snapshot. It can remove a different saved copy but may leave an identical copy in place

Channel deletion or visibility loss removes that channel's snapshots, and a thread deletion its thread's snapshots. Fluxer deletes a text, announcement, forum or media channel's threads with it and sends no thread deletion events, so that deletion also removes the snapshots of every channel in its community, or without community context, that the channel cache does not hold, which without the channel cache means all of them. Batch deletion evicts selected messages after dispatch even on rejection. These operations also stop older responses from entering the cache, including some pending reads of other resources

A ban that requests message deletion evicts this author's cached messages across communities because some messages lack community context. The server deletion job is asynchronous, so later observations do not establish whether the job has finished

maxAgeMs optional#

How long to keep each accepted snapshot, in milliseconds, or a synchronous function that chooses that duration

Use a nonnegative safe integer, zero to skip retention, or null to disable age expiry. Omitting this setting also disables age expiry

number | ((message: M) => number | null) | null| number
| ((message: M) => number | null)
| null

The function receives the frozen message with this client's selected fields and must return a duration or null. A throw, undefined, Promise, thenable or invalid number removes the older copy and reports a cache failure with the thrown value or an explanation. Message delivery and successful REST results still succeed when the policy fails. The SDK does not await or cancel invalid promises and thenables

Each eligible replacement starts a new age, even when values are unchanged. Local lookups change eviction order but do not renew age. Expiry removes SDK references without a lookup, although event-loop stalls can delay cleanup and garbage collection is not immediate. Capacity limits can remove a snapshot before its age limit

Keep the function nonblocking and side-effect-free, since it runs while the SDK accepts an observation. Changing state captured by the function affects later observations only

Removing a cache entry does not delete persistent data or securely erase memory

maxBytes optional#

Maximum UTF-8 JSON bytes of retained messages with this client's selected fields, as a positive safe integer

Defaults to 8,388,608 (8 MiB) and excludes runtime overhead and caller-held copies

number
maxEntries optional#

Maximum messages kept across this client, as a positive safe integer

Defaults to 1,000, not a separate allowance per channel

number

ResourceCacheSettings#

Set memory-only cache bounds for a resource category such as users, communities (the guilds category) or channels

The type parameter is the category's snapshot type, which a maxAgeMs callback receives. Use true or an options object in ClientOptions.cache to enable that category, which is otherwise disabled. The SDK keeps frozen copies of resources encountered through supported reads and events, not every remote resource. Fetches still contact Fluxer, writes still execute, and the SDK does no persistence or background refresh. It preloads nothing, except that a shard resuming a stored session refills enabled community, role and channel caches through REST unless sharding.refillCaches is false. When capacity is full, the least recently used snapshot is removed first. Expired entries, overlapping reads and lost gateway connections can make a lookup miss. A connection gap clears affected users and direct messages even if the session resumes. Community-scoped snapshots stay while the session resumes and are cleared when a new session starts, including the first, except cached threads, which a completed Resume clears. Responses started before the gap are not stored. Shutdown releases the SDK's copies, not copies still held by the application

interface ResourceCacheSettings<T = unknown>interface ResourceCacheSettings<
  T = unknown
>
maxAgeMs optional#

How long to keep each accepted snapshot, in milliseconds, or a synchronous function that chooses that duration

Use a nonnegative safe integer, zero to skip retention, or null to disable age expiry. Omitting this setting also disables age expiry

number | ((resource: T) => number | null) | null| number
| ((resource: T) => number | null)
| null

The function receives the frozen snapshot and must return a duration or null, so it can cache selectively, for example by returning zero for snapshots of communities or channels the application does not need. A throw, undefined, Promise, thenable or invalid number removes the older copy and reports a cache failure with the thrown value or an explanation. That failure goes to the client-level onError option as a cache FailureReport, or is logged at Error with the thrown value when no hook is set. Event delivery and successful REST results still succeed when the policy fails. The SDK does not await or cancel invalid promises and thenables

Each eligible replacement starts a new age, even when values are unchanged. Local lookups do not renew age, and expiry removes SDK references without fetching a replacement. Expiry runs without a lookup and can be delayed by an event-loop stall. Capacity limits can remove a snapshot before its age limit

Keep the function nonblocking and side-effect-free, since it runs while the SDK accepts an observation. Changing state captured by the function affects later observations only

maxBytes optional#

Maximum accounted UTF-8 JSON bytes kept for this category, as a positive safe integer

Defaults to 4,194,304 (4 MiB), separate from the message-cache byte budget. Permission bitfields are counted as decimal strings. Cache keys, runtime overhead and caller-held copies are excluded, so this is not an exact heap or process-memory limit

number
maxEntries optional#

Maximum snapshots kept for this category across the client, as a positive safe integer

Defaults to 1,000, not a limit per community

number

Type Aliases#

CacheKind#

The resource category to inspect or clear in the client's local cache, not a remote resource identifier

type CacheKind =
    | "messages" | "guilds" | "members" | "roles" | "channels"
    | "users" | "directMessages" | "emojis" | "stickers"type CacheKind =
    | "messages" | "guilds"
    | "members" | "roles"
    | "channels" | "users"
    | "directMessages" | "emojis"
    | "stickers"