32 symbols from @neontechspace/fluxerly/effect
Functions#
createClient #
Create a bot client from the supplied token when this Effect executes
createClient<
E = never,
R = never,
F extends MessageFields | undefined = undefined
>(
options: ClientOptions<E, R, F>
): Effect<Client<SelectedMessage<F>>, never, Scope | R>createClient<
E = never,
R = never,
F extends
| MessageFields | undefined
= undefined
>(
options: ClientOptions<E, R, F>
): Effect<
Client<SelectedMessage<F>>,
never,
Scope | R
>Use Effect to keep the client open while the bot works and shut it down when the Scope closes.
The client starts disconnected. Call connect or run to receive gateway events
Parameters
options-
ClientOptions<E, R, F>
- Returns
Effect<Client<SelectedMessage<F>>, never, Scope | R>Effect< Client<SelectedMessage<F>>, never, Scope | R >A scoped, lazy creation Effect. Invalid options, including a missing or blank token and an unsupported option key, are misuse and die with
Configuration. Its hint names an unset environment variable as the likely cause of a missing token, and the closest supported key for a misspelled option. Unexpected creation defects retain their CauseError
Client lifetime
Calling create does not create a client yet. Each execution creates a separate client in the caller's Scope and validates configuration locally, without authenticating the token
Creation starts no networking or background work. HTTP operations work without connect.
Closing the scope permanently shuts down the client and releases its credential reference.
Cache-error callbacks capture the Effect services available when creation executes.
The Effect Clock supplied at creation controls this client's REST queue and deadlines, cache expiry, collectors,
presence pacing, scheduled task timing and gateway lifetime. Supplying a different Clock for a later operation does not replace it.
Operation-specific waits and utilities document which Clock they use. Logging durations never control deadlines
Instance and caching
Omit instance for hosted Fluxer. For a self-hosted instance, pass its root. The unauthenticated well-known document supplies HTTP, gateway, image and application addresses when needed.
HTTPS and WSS are required unless that explicit instance sets allow for HTTP and WS
Caching is disabled by default. Cache settings are copied and validated without invoking retention policies or reporters. Unknown cache or message-cache option keys fail validation
Connection and sharding
Connection settings default to a 30,000 ms overall startup budget and three total attempts per assigned shard. An explicit sharding plan fixes this client's local IDs for its lifetime, while automatic sharding and a client without sharding settings may move to a larger plan when Fluxer asks for more shards. Shard zero receives direct-message gateway traffic. REST and cache budgets apply across the whole client, not separately to each shard
import { Effect } from "effect"
import { createClient } from "@neontechspace/fluxerly/effect"
export function shardingExample(token: string) {
return Effect.scoped(Effect.gen(function* () {
const client = yield* createClient({ token, sharding: { totalShards: 4, shardIds: [0, 2] } })
yield* client.connect()
return client.shards
}))
}
defineBot #
Define a bot's run options without its token, so a module can export them for both run and create from the Effect testing entry point
Returns the same object unchanged, without copying, reading or validating it. run and create check the options when their Effects run, as they do for an inline object. The function exists for type inference: Command arguments keep their declared types, such as a text argument's value as a string, and handlers keep their own error and service types, which run and create add to their requirements. An object annotated with Bot loses both. TypeScript rejects a token here, so the program passes it to run, usually from an environment variable
defineBot<
F extends MessageFields | undefined = undefined,
Events extends BotEvents<unknown, unknown, SelectedMessage<F>>
= BotEvents<unknown, unknown, SelectedMessage<F>>,
S extends Readonly<Record<string, unknown>> = { … },
C extends Readonly<
Record<
keyof S,
{
readonly arguments?: Readonly<
Record<string, CommandArgumentDescriptor>
>
readonly execute: unknown
}
>
>
= Readonly<
Record<
keyof S,
{
readonly arguments?: Readonly<
Record<string, CommandArgumentDescriptor>
>
readonly execute: unknown
}
>
>,
RouterServices = never,
OptionsError = never,
OptionsServices = never,
SetupServices = never,
ReadyServices = never
>(
options:
& Omit<
BotOptions<
unknown, unknown, OptionsError, OptionsServices, F
>,
"events" | "commands" | "token" | "setup"
>
& {
readonly commands?: BotCommandsOptions<
SelectedMessage<F>, S, C, RouterServices,
ReadyServices
>
readonly events?:
& Events
& Record<
Exclude<
keyof Events,
keyof EventMap<Message>
>,
never
>
readonly setup?: (client: Client<SelectedMessage<F>>)
=> Effect<unknown, unknown, SetupServices>
}
):
& Omit<
BotOptions<
unknown, unknown, OptionsError, OptionsServices, F
>,
"events" | "commands" | "token" | "setup"
>
& {
readonly commands?: BotCommandsOptions<
SelectedMessage<F>, S, C, RouterServices,
ReadyServices
>
readonly events?:
& Events
& Record<
Exclude<keyof Events, keyof EventMap<Message>>,
never
>
readonly setup?: (client: Client<SelectedMessage<F>>)
=> Effect<unknown, unknown, SetupServices>
}defineBot<
F extends
| MessageFields | undefined
= undefined,
Events extends BotEvents<
unknown, unknown,
SelectedMessage<F>
>
= BotEvents<
unknown, unknown,
SelectedMessage<F>
>,
S extends Readonly<
Record<string, unknown>
>
= { … },
C extends Readonly<
Record<
keyof S,
{
readonly arguments?: Readonly<
Record<
string,
CommandArgumentDescriptor
>
>
readonly execute: unknown
}
>
>
= Readonly<
Record<
keyof S,
{
readonly arguments?: Readonly<
Record<
string,
CommandArgumentDescriptor
>
>
readonly execute: unknown
}
>
>,
RouterServices = never,
OptionsError = never,
OptionsServices = never,
SetupServices = never,
ReadyServices = never
>(
options:
& Omit<
BotOptions<
unknown, unknown,
OptionsError,
OptionsServices, F
>,
| "events" | "commands"
| "token" | "setup"
>
& {
readonly commands?: BotCommandsOptions<
SelectedMessage<F>, S, C,
RouterServices,
ReadyServices
>
readonly events?:
& Events
& Record<
Exclude<
keyof Events,
keyof EventMap<Message>
>,
never
>
readonly setup?: (
client: Client<
SelectedMessage<F>
>
) => Effect<
unknown, unknown,
SetupServices
>
}
):
& Omit<
BotOptions<
unknown, unknown,
OptionsError,
OptionsServices, F
>,
| "events" | "commands"
| "token" | "setup"
>
& {
readonly commands?: BotCommandsOptions<
SelectedMessage<F>, S, C,
RouterServices,
ReadyServices
>
readonly events?:
& Events
& Record<
Exclude<
keyof Events,
keyof EventMap<Message>
>,
never
>
readonly setup?: (
client: Client<
SelectedMessage<F>
>
) => Effect<
unknown, unknown,
SetupServices
>
}Parameters
options-
& Omit< BotOptions< unknown, unknown, OptionsError, OptionsServices, F >, "events" | "commands" | "token" | "setup" > & { readonly commands?: BotCommandsOptions< SelectedMessage<F>, S, C, RouterServices, ReadyServices > readonly events?: & Events & Record< Exclude<keyof Events, keyof EventMap<Message>>, never > readonly setup?: (client: Client<SelectedMessage<F>>) => Effect<unknown, unknown, SetupServices> }& Omit< BotOptions< unknown, unknown, OptionsError, OptionsServices, F >, | "events" | "commands" | "token" | "setup" > & { readonly commands?: BotCommandsOptions< SelectedMessage<F>, S, C, RouterServices, ReadyServices > readonly events?: & Events & Record< Exclude< keyof Events, keyof EventMap<Message> >, never > readonly setup?: ( client: Client<SelectedMessage<F>> ) => Effect< unknown, unknown, SetupServices > }
- Returns
& Omit< BotOptions< unknown, unknown, OptionsError, OptionsServices, F >, "events" | "commands" | "token" | "setup" > & { readonly commands?: BotCommandsOptions< SelectedMessage<F>, S, C, RouterServices, ReadyServices > readonly events?: & Events & Record< Exclude<keyof Events, keyof EventMap<Message>>, never > readonly setup?: (client: Client<SelectedMessage<F>>) => Effect<unknown, unknown, SetupServices> }& Omit< BotOptions< unknown, unknown, OptionsError, OptionsServices, F >, | "events" | "commands" | "token" | "setup" > & { readonly commands?: BotCommandsOptions< SelectedMessage<F>, S, C, RouterServices, ReadyServices > readonly events?: & Events & Record< Exclude< keyof Events, keyof EventMap<Message> >, never > readonly setup?: ( client: Client<SelectedMessage<F>> ) => Effect< unknown, unknown, SetupServices > }
import { Effect } from "effect"
import { defineBot, runBot } from "@neontechspace/fluxerly/effect"
// A test imports bot and passes it to createTestBot from @neontechspace/fluxerly/effect/testing
export const bot = defineBot({
commands: {
prefix: "!",
commands: {
greet: {
arguments: { name: { type: "text", rest: true } },
execute: ({ reply, values }) => reply(`Hello, ${values.name}!`),
},
},
},
})
// Running this file starts the bot, while importing it from a test does not
if (import.meta.main)
await Effect.runPromiseExit(runBot({ token: process.env.FLUXER_BOT_TOKEN, processSignals: true, ...bot }))
runBot #
Run a bot from one configuration object in the application's Effect context and scope
When the Effect runs, it creates the client and registers every event handler and command before the gateway starts, so no event is missed and no handler runs before registration and setup complete. A malformed option, misspelled option key, non-function handler, unsupported event name, invalid delivery setting or invalid command is misuse and dies with Configuration. Every option is checked before any client, signal listener or request exists, even when the signal is already aborted, so misuse leaves nothing to clean up. A missing or empty token, usually from an unset environment variable, is a failure instead: Once every other option is valid, the bot fails with Configuration with field token before any client exists. Handler and command failures are reported to on, or logged with their full Cause, and do not stop the bot. By default, message and message events written by bots skip the events handlers and prefix commands. Set ignore to false to opt out. A failed setup Effect or a throwing commands register callback fails the bot with Application before it connects. A subscription that closes while the bot runs fails the bot with Critical. That includes a handler or command router set to overflow "stop" whose queue overflows. The overflow is still reported to on or logged, and the error names the event and the exceeded capacity, with the Event as its cause. Cleanup is awaited. Aborting the signal option, or SIGINT or SIGTERM when process is true, stops the bot successfully after running handlers, scheduled tasks and their requests have had up to drain, default 5,000 ms, to finish. Fiber interruption remains interruption and does not drain. Process signals stay opt-in here, because a launcher such as Node already interrupts the program on SIGINT and SIGTERM. Set process to true only when nothing else handles them and a drained stop is wanted. By default a failure or defect that stops the bot, including misuse and a missing token, is also logged once, with code lifecycle unless the client already logged that error, and sets process to 1, so running the Effect needs no further handling. Set report to false when the application handles the failure and exit status itself. Reports before client creation use the configured logging settings, print no stack for a missing token and mask the token after removing surrounding whitespace and one pair of matching quotes. An option getter that throws remains the original defect. For that report, token, logging and report are read independently and may be read again if the option snapshot already read them. A throwing reporting getter does not discard the other readable settings. Unusable logging uses the native default output, and an unreadable report setting keeps reporting enabled. No separate runtime is created and the process is not exited
runBot<
F extends MessageFields | undefined = undefined,
Events extends BotEvents<unknown, unknown, SelectedMessage<F>>
= BotEvents<unknown, unknown, SelectedMessage<F>>,
S extends Readonly<Record<string, unknown>> = { … },
C extends Readonly<
Record<
keyof S,
{
readonly arguments?: Readonly<
Record<string, CommandArgumentDescriptor>
>
readonly execute: unknown
}
>
>
= Readonly<
Record<
keyof S,
{
readonly arguments?: Readonly<
Record<string, CommandArgumentDescriptor>
>
readonly execute: unknown
}
>
>,
RouterServices = never,
OptionsError = never,
OptionsServices = never,
SetupServices = never,
ReadyServices = never
>(
options:
& Omit<
BotOptions<
unknown, unknown, OptionsError, OptionsServices, F
>,
"events" | "commands" | "setup"
>
& {
readonly commands?: BotCommandsOptions<
SelectedMessage<F>, S, C, RouterServices,
ReadyServices
>
readonly events?:
& Events
& Record<
Exclude<
keyof Events,
keyof EventMap<Message>
>,
never
>
readonly setup?: (client: Client<SelectedMessage<F>>)
=> Effect<unknown, unknown, SetupServices>
}
): Effect<
void,
| ConfigurationError | CriticalWorkerStoppedError
| ApplicationError | ConnectError,
| Exclude<RouterServices, Scope>
| Exclude<OptionsServices, Scope>
| Exclude<SetupServices, Scope>
| Exclude<ReadyServices, Scope>
| Exclude<BotEventServices<Events>, Scope>
| Exclude<BatchRequirements<C>, Scope>
>runBot<
F extends
| MessageFields | undefined
= undefined,
Events extends BotEvents<
unknown, unknown,
SelectedMessage<F>
>
= BotEvents<
unknown, unknown,
SelectedMessage<F>
>,
S extends Readonly<
Record<string, unknown>
>
= { … },
C extends Readonly<
Record<
keyof S,
{
readonly arguments?: Readonly<
Record<
string,
CommandArgumentDescriptor
>
>
readonly execute: unknown
}
>
>
= Readonly<
Record<
keyof S,
{
readonly arguments?: Readonly<
Record<
string,
CommandArgumentDescriptor
>
>
readonly execute: unknown
}
>
>,
RouterServices = never,
OptionsError = never,
OptionsServices = never,
SetupServices = never,
ReadyServices = never
>(
options:
& Omit<
BotOptions<
unknown, unknown,
OptionsError,
OptionsServices, F
>,
| "events" | "commands"
| "setup"
>
& {
readonly commands?: BotCommandsOptions<
SelectedMessage<F>, S, C,
RouterServices,
ReadyServices
>
readonly events?:
& Events
& Record<
Exclude<
keyof Events,
keyof EventMap<Message>
>,
never
>
readonly setup?: (
client: Client<
SelectedMessage<F>
>
) => Effect<
unknown, unknown,
SetupServices
>
}
): Effect<
void,
| ConfigurationError
| CriticalWorkerStoppedError
| ApplicationError
| ConnectError,
| Exclude<RouterServices, Scope>
| Exclude<OptionsServices, Scope>
| Exclude<SetupServices, Scope>
| Exclude<ReadyServices, Scope>
| Exclude<
BotEventServices<Events>,
Scope
>
| Exclude<
BatchRequirements<C>, Scope
>
>Parameters
options-
& Omit< BotOptions< unknown, unknown, OptionsError, OptionsServices, F >, "events" | "commands" | "setup" > & { readonly commands?: BotCommandsOptions< SelectedMessage<F>, S, C, RouterServices, ReadyServices > readonly events?: & Events & Record< Exclude<keyof Events, keyof EventMap<Message>>, never > readonly setup?: (client: Client<SelectedMessage<F>>) => Effect<unknown, unknown, SetupServices> }& Omit< BotOptions< unknown, unknown, OptionsError, OptionsServices, F >, "events" | "commands" | "setup" > & { readonly commands?: BotCommandsOptions< SelectedMessage<F>, S, C, RouterServices, ReadyServices > readonly events?: & Events & Record< Exclude< keyof Events, keyof EventMap<Message> >, never > readonly setup?: ( client: Client<SelectedMessage<F>> ) => Effect< unknown, unknown, SetupServices > }
- Returns
Effect< void, | ConfigurationError | CriticalWorkerStoppedError | ApplicationError | ConnectError, | Exclude<RouterServices, Scope> | Exclude<OptionsServices, Scope> | Exclude<SetupServices, Scope> | Exclude<ReadyServices, Scope> | Exclude<BotEventServices<Events>, Scope> | Exclude<BatchRequirements<C>, Scope> >Effect< void, | ConfigurationError | CriticalWorkerStoppedError | ApplicationError | ConnectError, | Exclude<RouterServices, Scope> | Exclude<OptionsServices, Scope> | Exclude<SetupServices, Scope> | Exclude<ReadyServices, Scope> | Exclude< BotEventServices<Events>, Scope > | Exclude< BatchRequirements<C>, Scope > >
import { Effect } from "effect"
import { runBot } from "@neontechspace/fluxerly/effect"
export function pingBot(token: string | undefined) {
return runBot({
token,
processSignals: true,
commands: {
prefix: "!",
commands: {
ping: { execute: ({ reply }) => reply("Pong!") },
},
},
events: {
guildCreate: ({ event }) => Effect.logInfo(`Joined ${event.name}`),
},
})
}
Classes#
FluxerClient - Effect service holding one native client, for applications that assemble their program from Layers
Interfaces#
BotEventOptions #
A native run event handler with its own delivery settings
Omitted settings use the run defaults: Overflow drop, concurrency 8 for message or a partitioned handler and 1 otherwise, and the client queue limits
interface BotEventOptions<
K extends EventName,
E = never,
R = never,
M extends MessageCore = Message
>
extends HandlerOptions<EventMap<M>[K]>interface BotEventOptions<
K extends EventName,
E = never,
R = never,
M extends MessageCore = Message
>
extends HandlerOptions<
EventMap<M>[K]
>handler#-
Called for each event
BotEventHandler<K, E, R, M> onoptional#Error -
(report: FailureReport) => Effect<unknown, E, R>(report: FailureReport) => Effect<unknown, E, R>
Inherited from Handler: concurrency, max, max, overflow, partition
CurrentBotApplication #
Read the application associated with this bot token through GET /oauth2/
No gateway connection is required. Effects start when executed and can be run again, using the caller's services, the client's default deadline (rest, 30,000 ms unless configured) and at most two transient read retries. Returns a frozen set of documented application fields, including the owner's user ID, without caching. Other owner details, redirect URIs, verification keys, client secrets, and nested bot fields are never exposed. Fluxer remains authoritative for application visibility and installability. This read neither manages an application nor opens an authorization page. Input, HTTP, and malformed-response failures use Bot. Closure uses Client. Interruption and defects remain in the Cause
interface CurrentBotApplicationimport { Effect } from "effect"
import { links, type Client } from "@neontechspace/fluxerly/effect"
export const applicationExample = (client: Client) => Effect.gen(function* () {
const application = yield* client.application.fetch()
return links.installation(application.id, { permissions: 0n })
})
fetch#
Fetch this bot token's application data from /oauth2/
Only the documented fields are returned, frozen, without cache storage, gateway events, owner profile lookup or follow-up requests. The timeout option bounds this read only and does not change the gateway startup deadline. Cancelling it affects only this read and never changes the application
fetch(
options?: RequestOptions
): Effect<BotApplication, BotApplicationOperationFailure>fetch(
options?: RequestOptions
): Effect<
BotApplication,
BotApplicationOperationFailure
>Parameters
optionsoptional-
RequestOptions
GatewayCommands #
Send gateway commands that have no SDK method, on this client's ready shards
This is an advanced escape hatch: The SDK validates the frame locally but does not know the command's meaning, and Fluxer closes the connection, ending the client, for commands it rejects. Observe replies to these commands through the raw event, subscribing before sending
interface GatewayCommandssend#
Send one command frame { op, d } on a Connected local shard
The data is copied through JSON encoding when the operation starts, so later changes to it have no effect, and the encoded frame must be at most 4,096 UTF-8 bytes, Fluxer's message limit. Undefined data is invalid. Pass null instead. Data JSON cannot encode, such as a cycle or a BigInt, fails with reason input. Heartbeat, Identify, Resume and server-only opcodes fail with reason reserved. Commands share the shard's outbound pacing with presence and request commands: At most 500 paced commands per rolling 60 seconds per session, retained across Resume and reset for a fresh Identify, sent in call order. Heartbeats, Identify and Resume are never delayed. At most 500 gateway commands may wait per shard, and further submissions fail with reason busy until transmission or cancellation releases queue capacity. Completion means the frame was handed to the connection, not that Fluxer received or accepted it. A sent Request Guild Members command, opcode 8, counts toward the 12 member requests that members allows this client in any 11 seconds, or the children of one supervisor together, but this method never refuses one for that limit. Fluxer answers an opcode it does not define, missing data or invalid command fields with close code 4001 or 4002. The SDK treats both as permanent, so the client ends. Data must match Fluxer's command schema exactly. Observe any reply through the raw event, which receives every dispatch the session accepts. A shard that loses its connection before sending fails a waiting command with reason not, and the SDK never replays it after reconnecting. Each sent command is logged at Debug with code gateway
send(
shardId: number,
op: number,
d: unknown
): Effect<void, GatewaySendFailure>send(
shardId: number,
op: number,
d: unknown
): Effect<void, GatewaySendFailure>Parameters
shardId -
number op-
number d-
unknown
- Returns
Effect<void, GatewaySendFailure>- Fails with
Interrupting the Effect withdraws a command that is still waiting for the pacing budget and immediately releases
its local queue capacity.
A command already handed to the connection cannot be withdrawn. A throw from the data's own getters or to
dies with the thrown value, and other unexpected defects remain in the Effect cause
import { Effect } from "effect"
import type { Client, RawDispatch } from "@neontechspace/fluxerly/effect"
// Commands with an SDK method, such as community counts through client.guilds.fetchCounts, use that method instead
export function sendCustomCommand(
client: Client,
command: { op: number; data: unknown; replyType: string },
onReply: (reply: RawDispatch) => void,
) {
return Effect.gen(function* () {
// Subscribe before sending so the raw reply cannot be missed. The enclosing Scope closes it
const replies = yield* client.on("raw", (dispatch) =>
Effect.sync(() => {
if (dispatch.t === command.replyType) onReply(dispatch)
}),
)
yield* client.gateway.send(0, command.op, command.data)
return replies
})
}
Instance#
Resolve the service addresses and URL helpers for the instance selected at client creation
interface InstanceThe resolve method starts when executed and uses the caller's Effect services. Concurrent callers share one document read that runs in the client Scope. Interrupting one caller releases only that caller's wait. A successful immutable result is reused without refresh until client shutdown
The resolved assets and links helpers return URLs directly, the same as in the default API.
They throw Asset or Helper for invalid input, and such a throw inside Effect code becomes a defect
import { Effect } from "effect"
import type { Client } from "@neontechspace/fluxerly/effect"
export const instanceExample = (client: Client) => Effect.gen(function* () {
const resolved = yield* client.instance.resolve({ timeoutMs: 10_000 })
const channel = resolved.links.channel({ id: "1750000000000000000" })
const avatar = resolved.assets.defaultAvatar("1750000000000000000")
return { api: resolved.endpoints.apiPublic, channel, avatar }
})
resolve#
Resolve this client's instance endpoints and its pure link and asset URL helpers
The unauthenticated discovery request is shared with other resolves, REST work or gateway startup. The timeout option defaults to 30,000 for this wait only. Cancellation releases only this wait, while other users can keep the shared discovery read alive. Document, rate-limit, timeout, closure and invalid timeout-option failures are expected failures
resolve(
options?: RequestOptions
): Effect<ResolvedInstance, InstanceResolveError>resolve(
options?: RequestOptions
): Effect<
ResolvedInstance,
InstanceResolveError
>Parameters
optionsoptional-
RequestOptions
- Returns
Effect<ResolvedInstance, InstanceResolveError>Effect< ResolvedInstance, InstanceResolveError >- Fails with
Cleanup defects remain in the Cause alongside any failure or interruption. Effect reports a failure that occurs together with a cleanup defect as a defect that keeps the failure's value
Presence#
Set the bot's status or select community members whose presence updates the bot should receive
The client retains these requests in memory, not across process restarts. Outgoing status updates send to every live locally owned shard and are spaced by at least four seconds per shard. Member selections are separate bounded gateway presence requests. No provider acknowledgement or recipient-delivery guarantee is available. The SDK performs no remote membership lookup or self filtering. Fluxer owns access and filtering
interface Presenceset#
Set the bot's requested status and optional custom status, including before connecting
The input is validated and frozen when the call runs. Omitted custom keeps the previous request, and null clears it. Expired custom statuses are not restored after reconnect. Each shard retains at most one unsent status update, replacing it with the latest intent even while gateway pacing waits. The four-second interval starts when an update reaches the socket, not when it is queued. Success means the request was accepted locally and scheduled for each shard, not acknowledged by Fluxer. Shutdown releases this intent and its timer
set(input: PresenceInput): Effect<void, PresenceFailure>set(
input: PresenceInput
): Effect<void, PresenceFailure>Parameters
input-
PresenceInput
- Returns
Effect<void, PresenceFailure>- Fails with
Unexpected defects remain in the Effect cause
import { Effect } from "effect"
import { MemberMentionPreferences, type Client } from "@neontechspace/fluxerly/effect"
export const botProfileExample = (client: Client, guildId: string) => Effect.gen(function* () {
yield* client.presence.set({ status: "online", customStatus: { text: "Ready", emoji: { name: "🌱" } } })
return yield* client.members.editSelf(guildId, { nickname: "Support", mentionFlags: MemberMentionPreferences.PreferNoMention })
})
setMembers #
Request presence updates for selected members in one community
Register a presence listener, then pass accessible non-self member IDs. Pass [] to clear the selection. Closing the listener does not clear it. No full-member subscription, member lookup or presence cache is created, and Fluxer remains authoritative for access and filtering. The community must belong to a shard assigned to this client, or the call fails with Presence reason input
setMembers(
guildId: string,
memberIds: readonly string[]
): Effect<void, PresenceFailure>setMembers(
guildId: string,
memberIds: readonly string[]
): Effect<void, PresenceFailure>Inputs are copied and retained when the call runs. Up to 1,000 distinct decimal IDs are accepted, but the full UTF-8 gateway frame must fit 4,096 bytes. Long IDs therefore reduce the effective per-community maximum. The client retains selections for at most 100 communities and 10,000 IDs. Clearing an unsent selection withdraws its queued command and releases its slot immediately. Changes to a selection that has not reached the socket replace that unsent request. Clearing a selection already sent keeps one bounded session slot until fresh Identify or confirmed community leave, because a local socket write cannot confirm that Fluxer applied a clear
After READY or RESUMED, the latest selection or clear is combined and sent at most once per 125 ms per shard.
This interval starts at actual socket transmission, and at most one member-selection command waits per shard.
Sending the same list again deliberately requests a refresh.
A matching guild creation also retries the latest selection or a previously sent clear.
None of these attempts guarantees an event or proves provider acceptance.
Initial state and transitions can be missed during recovery.
Loss of shared channel visibility can remove the provider subscription, so resend the selection after access returns.
Clear explicitly or shut down the client to release local intent.
Input or limit failures fail with Presence, and closing clients fail with Client.
The community and member IDs must be positive decimal strings without leading zeros, no greater than 9223372036854775807.
The member IDs are copied once, and that copy is validated and subscribed
Parameters
guildId -
string memberIds -
readonly string[]
- Returns
Effect<void, PresenceFailure>- Fails with
Unexpected defects remain in the Effect cause
import { Effect } from "effect"
import type { Client } from "@neontechspace/fluxerly/effect"
export const watchSelectedMember = (client: Client, guildId: string, memberId: string) => Effect.gen(function* () {
const subscription = yield* client.on("presenceUpdate", (presence) =>
Effect.sync(() => { if (presence.guildId === guildId && presence.userId === memberId) void presence.status }),
)
return yield* client.presence.setMembers(guildId, [memberId]).pipe(
Effect.as(subscription),
Effect.onError(() => subscription.close()),
)
})
RestRequest #
One request to a Fluxer API route that the SDK does not wrap, sent with the client's bot credential through the same queue, rate-limit learning, 429 waits, deadline, logging and cancellation as wrapped operations
Invalid input fails before dispatch with Rest reason input. A GET that fails with a network error or HTTP 500, 502, 503 or 504 is retried at most twice. Another method is sent again only after Fluxer confirms a rate limit with HTTP 429, so a write with an unknown outcome is never repeated automatically. Message and resource caches are neither read nor updated, and Fluxer's rate limits and permissions still apply
interface RestRequestauditoptional#Reason -
Audit-log reason sent as the X-Audit-Log-Reason header, 1 through 512 printable ASCII characters after trimming
Omission sends no header. Never included in errors, logs or diagnostics
string bodyoptional#-
JSON body, serialized when the request starts
A value JSON cannot represent fails with reason input. Its size counts against the client's queued JSON budget while the request waits. Not allowed with GET
unknown filesoptional#-
Files sent inline as multipart/form-data, with the JSON body as payload_json and each file as files[n] in order
Accepts the same byte, file and stream inputs as message attachments, with the same size, filename and upload-budget rules. The body must then be omitted or a JSON object without attachments, because the SDK sets attachments to the files' metadata as Fluxer's message routes expect. A request whose file source cannot be read again fails with reason
rateinstead of waiting out a 429. Not allowed with GETLimit readonly AttachmentInput[] method#-
HTTP method
Only POST, PUT, PATCH and DELETE may carry a body or files
"GET" | "POST" | "PUT" | "PATCH" | "DELETE"| "GET" | "POST" | "PUT" | "PATCH" | "DELETE" path#-
API path after /v1, such as /users/@me, of at most 2,048 characters
It must start with one slash and contain only URL path characters with valid percent escapes, without empty, dot or dot-dot segments, a query or a fragment. The /v1 prefix and token-authenticated webhook routes (/
webhooks/{id}/{token}) are rejected, including percent-encoded unreserved characters in those route names. These checks are case-sensitive and do not decode reserved characters. Logs, metrics and spans name the route with numeric IDs and other non-word segments replaced by placeholders string queryoptional#-
Query parameters appended to the path in insertion order
Undefined values are omitted, numbers must be finite, and booleans are sent as true or false. The encoded query may contain at most 8,192 characters
Readonly<Record<string, string | number | boolean | undefined>>Readonly< Record< string, | string | number | boolean | undefined > > timeoutoptional#Ms -
Total milliseconds across local queueing, rate-limit waits, retries and HTTP
An integer from 1 through 2,147,483,647, defaulting to the client's
rest(30,000 unless configured). Owned cleanup is awaited afterward, so completion can take longer.default Timeout Ms number
RestRequests #
Send requests to Fluxer API routes that the SDK does not wrap, with the client's bot credential and its REST scheduler
Effects start when run, need no gateway connection and default to the client's rest deadline. Interruption and unexpected faults remain in Cause rather than becoming Rest
interface RestRequestsrequest#
Send one request to a route under /v1 and resolve with its status, lower-case headers and parsed JSON body
The request waits in the client's queue and learned rate-limit windows like wrapped operations, and fails at once with reason rate and the remaining wait as retry when a window outlasts the deadline. A 429 is waited out and sent again while the deadline allows. A GET is also retried at most twice after a network error, including a connection lost while the response body arrives, or HTTP 500, 502, 503 or 504. Another method is never sent again after an uncertain outcome. The body is sent as given, including a lone surrogate, which Fluxer answers with HTTP 503. Invalid input fails with Rest reason input before any request, a non-2xx status fails with its status and sanitized api, and closure fails with Client. Message and resource caches are not updated. Percent-encoded unreserved letters cannot bypass the reserved /v1 prefix or token-webhook route checks, which remain case-sensitive. Network causes retain sanitized transport facts, not raw errors. Unknown uppercase provider codes remain in details, including on HTTP 429 when its wait exceeds the deadline. Logs, metrics and spans name only the route template, never the query, body or response
request<T = unknown>(
input: RestRequest
): Effect<RestResponse<T>, RestRequestFailure>request<T = unknown>(
input: RestRequest
): Effect<
RestResponse<T>,
RestRequestFailure
>Parameters
input-
RestRequest
- Returns
Effect<RestResponse<T>, RestRequestFailure>Effect< RestResponse<T>, RestRequestFailure >- Fails with
ScheduledTask #
A task started with client
It ends by itself after its only run, or when the client shuts down
interface ScheduledTaskclose#
Type Aliases#
BotEventContext #
Give a bot handler its event payload, client and Event
The message context also provides message as an alias for the payload and reply, which uses the client's native messages operation. The reply Effect sends only when executed and retains its normal Send and interruption behavior
type BotEventContext<
K extends EventName,
M extends MessageCore = Message
> =
& {
readonly client: Client<M>
readonly context: EventContext<K, M>
readonly event: EventMap<M>[K]
}
& (K extends "messageCreate"
? {
readonly message: M
readonly reply: (
input: ReplyInput | string,
options?: RequestOptions
) => Effect.Effect<M, SendError>
}
: { … })type BotEventContext<
K extends EventName,
M extends MessageCore = Message
> =
& {
readonly client: Client<M>
readonly context:
EventContext<K, M>
readonly event:
EventMap<M>[K]
}
& (K extends "messageCreate"
? {
readonly message: M
readonly reply: (
input:
| ReplyInput
| string,
options?:
RequestOptions
) => Effect.Effect<
M, SendError
>
}
: { … })BotEventHandler #
type BotEventHandler<
K extends EventName,
E = never,
R = never,
M extends MessageCore = Message
> = (context: BotEventContext<K, M>) => Effect.Effect<unknown, E, R>type BotEventHandler<
K extends EventName,
E = never,
R = never,
M extends MessageCore = Message
> = (
context: BotEventContext<K, M>
) => Effect.Effect<unknown, E, R>BotEventServices #
The services required by every handler in a run events object, which run adds to its own requirements
Omitted events require no services
type BotEventServices<Events> =
{
[K in keyof Events]-?:
HandlerServices<NonNullable<Events[K]>> extends infer R
? unknown extends R ? never : R
: never
}[keyof Events]type BotEventServices<Events> =
{
[K in keyof Events]-?:
HandlerServices<
NonNullable<Events[K]>
> extends infer R
? unknown extends R
? never
: R
: never
}[keyof Events]BotEvents #
One optional handler per event, as a function or an object with a handler and delivery settings
The run function delivers with overflow drop, so a full queue drops the oldest waiting event with a Warn record and a counter instead of stopping the bot. Handlers for message run up to eight at a time by default, and other events run one at a time. A failed handler is reported with its original Cause without stopping the bot
type BotEvents<
E = never,
R = never,
M extends MessageCore = Message
> = {
readonly [K in EventName]?:
BotEventHandler<K, E, R, M> | BotEventOptions<K, E, R, M>
}type BotEvents<
E = never,
R = never,
M extends MessageCore = Message
> = {
readonly [K in EventName]?:
| BotEventHandler<K, E, R, M>
| BotEventOptions<K, E, R, M>
}BotOptions #
Configure one Effect bot with client settings, optional stop signals, event handlers, prefix commands and startup work
The token accepts an unvalidated environment value. A missing or blank value is not misuse: Once the other options are valid, the bot fails with Configuration. Client settings, including message and cache callbacks, retain their native semantics. Handlers and commands are registered when the Effect runs, before the gateway starts. Reports before client creation use the configured logging settings and mask the normalized token, including a token enclosed in matching quotes. If an option getter throws, readable token, logging and report settings are retained independently for reporting. Unreadable logging uses the native default output, and unreadable report enables reporting
type BotOptions<
EventError = never,
EventServices = never,
OptionsError = never,
OptionsServices = never,
F extends MessageFields | undefined = undefined
> =
& ClientOptions<OptionsError, OptionsServices, F>
& RunBotOptions
& {
readonly commands?: BotCommandsOptions<SelectedMessage<F>>
readonly events?: BotEvents<
EventError, EventServices, SelectedMessage<F>
>
readonly ignoreBots?: boolean
readonly setup?: (client: Client<SelectedMessage<F>>)
=> Effect.Effect<unknown, unknown, Scope.Scope>
}type BotOptions<
EventError = never,
EventServices = never,
OptionsError = never,
OptionsServices = never,
F extends
| MessageFields | undefined
= undefined
> =
& ClientOptions<
OptionsError,
OptionsServices, F
>
& RunBotOptions
& {
readonly commands?: BotCommandsOptions<
SelectedMessage<F>
>
readonly events?: BotEvents<
EventError, EventServices,
SelectedMessage<F>
>
readonly ignoreBots?: boolean
readonly setup?: (
client: Client<
SelectedMessage<F>
>
) => Effect.Effect<
unknown, unknown,
Scope.Scope
>
}FluxerClientConfigOptions #
Client settings for Fluxer: The settings of create, where the token and any other top-level setting can instead be an Effect Config read when the layer is built
The token can be a Config of a Redacted or plain string, such as Config, or a Redacted or plain string. A Redacted token stays wrapped until it is passed to the client, and the client never logs it. Nested settings are not read from Config individually. Supply a Config of the whole top-level setting instead
type FluxerClientConfigOptions<E = never, R = never> =
& {
readonly [K in Exclude<
keyof ClientOptions<E, R>,
"token"
>]?:
| ClientOptions<E, R>[K]
| Config.Config<ClientOptions<E, R>[K]>
}
& {
readonly token:
| Config.Config<Redacted.Redacted<string>>
| Config.Config<string>
| Redacted.Redacted<string>
| string
}type FluxerClientConfigOptions<
E = never, R = never
> =
& {
readonly [K in Exclude<
keyof ClientOptions<E, R>,
"token"
>]?:
| ClientOptions<E, R>[K]
| Config.Config<
ClientOptions<E, R>[K]
>
}
& {
readonly token:
| Config.Config<
Redacted.Redacted<string>
>
| Config.Config<string>
| Redacted.Redacted<string>
| string
}HandlerServices #
type HandlerServices<H> =
H extends (...args: never[])
=> Effect.Effect<unknown, unknown, infer R>
? R
: H extends {
readonly handler: (...args: never[])
=> Effect.Effect<unknown, unknown, infer R>
readonly onError?: infer Hook
readonly partitionReady?: infer Ready
}
?
| R
| (Hook extends (...args: never[])
=> Effect.Effect<unknown, unknown, infer R2>
? R2
: never)
| (Ready extends (...args: never[])
=> Effect.Effect<unknown, unknown, infer R3>
? R3
: never)
: nevertype HandlerServices<H> =
H extends (...args: never[])
=> Effect.Effect<
unknown, unknown, infer R
>
? R
: H extends {
readonly handler: (
...args: never[]
) => Effect.Effect<
unknown, unknown, infer R
>
readonly onError?: infer Hook
readonly partitionReady?:
infer Ready
}
?
| R
| (Hook extends (
...args: never[]
) => Effect.Effect<
unknown, unknown,
infer R2
>
? R2
: never)
| (Ready extends (
...args: never[]
) => Effect.Effect<
unknown, unknown,
infer R3
>
? R3
: never)
: neverRe-Exports#
Declared in JavaScript & TypeScript and documented there. Import them from @neontechspace/fluxerly/effect as well
Bot#Application - Application details returned by
applicationfor this client's bot token.fetch Custom#Status Input - Text, emoji and optional expiration for the bot's custom status
Instance#Domain Migration - A web domain migration announced by instance discovery, such as hosted Fluxer moving its web app to a new domain
Instance#Endpoints - Where the selected Fluxer instance hosts its services, validated from its discovery document
Presence#Input - Set the status this bot should publish on its gateway connections
Resolved#Instance - The selected server's service addresses and matching URL helpers
Rest#Response - A successful response from
client, for any 2xx status.rest .request Schedule#Options - Choose when
clientruns a task, in both entry points.schedule Shutdown#Options - Choose how shutdown treats work that is still running, in both entry points
Connection#State - The client's current gateway connection state, not a history of events
Custom#Status Emoji - One custom-status emoji
Presence#Status - The bot's visible status while connected, with dnd meaning do not disturb