Create and Manage Forum Channels
Recognize forum and media channels, create them with tags and post settings, change one tag at a time and read their posts
A forum channel holds posts instead of messages. Each post is a public thread with its own first message. A media channel is a forum channel that can also hide media download options
The examples use the default API. The Effect entry point exports the same names
Recognize a Forum Channel
Compare type with ChannelType.Forum or ChannelType.Media. Both shapes share the post settings below, and only a forum channel has defaultForumLayout
import { ChannelFlags, ChannelType } from "@neontechspace/fluxerly"
export function forumSummary(channel) {
if (channel.type !== ChannelType.Forum && channel.type !== ChannelType.Media)
return undefined
return {
guidelines: channel.topic,
tags: (channel.availableTags ?? []).map((tag) => tag.name),
requiresTag: ((channel.flags ?? 0) & ChannelFlags.RequireTag) !== 0,
}
}
import { ChannelFlags, ChannelType, type GuildChannel } from "@neontechspace/fluxerly"
export function forumSummary(channel: GuildChannel) {
if (channel.type !== ChannelType.Forum && channel.type !== ChannelType.Media) return undefined
return {
guidelines: channel.topic,
tags: (channel.availableTags ?? []).map((tag) => tag.name),
requiresTag: ((channel.flags ?? 0) & ChannelFlags.RequireTag) !== 0,
}
}
The channels.fetchAll method lists forum and media channels but never their posts. The channels.fetch method returns a post as a thread shape when the ID names one, and channels.get can return one when the cache holds it, so compare type or use isThreadChannel before reading fields that only some shapes have
Read Post Settings
Fluxer leaves the post settings out of some payloads, such as the guildChannelDelete event. Each setting is therefore optional, and its absence means that it is unavailable, not that it has its default
availableTags: The tags a post can carry, at most 20. Only members who can manage threads may apply or remove amoderatedtagdefaultReactionEmoji: The reaction clients show on each post, or nulldefaultSortOrder: AForumSortOrdervalue, or nulldefaultForumLayout: AForumLayoutvalue, on a forum channel onlydefaultTagSetting: How a post search matches tags,"match_some"or"match_all"defaultandAuto Archive Minutes default: Defaults for new posts. Fluxer stores the archive period but does not apply it to a new postThread Rate Limit Per User flags:Channel, andFlags .Require Tag Channelon a media channelFlags .Hide Media Download Options
Flag bits, sort orders, layouts and tag settings that this SDK version does not name are kept as Fluxer sent them. Audit-log entries for forum channel changes record available_tags as ForumTag values and default_ as a ForumDefaultReaction
Read Posts
Each post is a Guild whose parentId is the forum or media channel. The appliedTagIds field lists the post's tags, and ChannelFlags.Pinned in flags marks the channel's pinned post. Read threads covers the fields every thread shares
import { ChannelType } from "@neontechspace/fluxerly"
export function postTagNames(forum, post) {
if (post.type !== ChannelType.PublicThread || post.parentId !== forum.id)
return []
const names = new Map((forum.availableTags ?? []).map((tag) => [tag.id, tag.name]))
return (post.appliedTagIds ?? []).map((id) => names.get(id) ?? id)
}
import { ChannelType, type GuildForumChannel, type GuildThreadChannel } from "@neontechspace/fluxerly"
export function postTagNames(forum: GuildForumChannel, post: GuildThreadChannel) {
if (post.type !== ChannelType.PublicThread || post.parentId !== forum.id) return []
const names = new Map((forum.availableTags ?? []).map((tag) => [tag.id, tag.name]))
return (post.appliedTagIds ?? []).map((id) => names.get(id) ?? id)
}
To read the creator and first message of up to 100 posts in one call, pass their IDs to threads
Create a Forum or Media Channel
A channels.create call takes ChannelType.Forum or ChannelType.Media together with the channel's tags and post settings. The bot needs ManageChannels
import { ChannelFlags, ChannelType, ForumLayout, ForumSortOrder } from "@neontechspace/fluxerly"
export async function createHelpForum(client, guildId) {
const result = await client.channels.create(guildId, {
type: ChannelType.Forum,
name: "help",
topic: "Ask one question per post and say what was already tried",
availableTags: [
{ name: "bug", emojiName: "🐛" },
{ name: "question" },
{ name: "staff", moderated: true },
],
defaultSortOrder: ForumSortOrder.CreationTime,
defaultForumLayout: ForumLayout.List,
flags: ChannelFlags.RequireTag,
})
return result.map((channel) => channel.id)
}
import { ChannelFlags, ChannelType, ForumLayout, ForumSortOrder, type Client } from "@neontechspace/fluxerly"
export async function createHelpForum(client: Client, guildId: string) {
const result = await client.channels.create(guildId, {
type: ChannelType.Forum,
name: "help",
topic: "Ask one question per post and say what was already tried",
availableTags: [
{ name: "bug", emojiName: "🐛" },
{ name: "question" },
{ name: "staff", moderated: true },
],
defaultSortOrder: ForumSortOrder.CreationTime,
defaultForumLayout: ForumLayout.List,
flags: ChannelFlags.RequireTag,
})
return result.map((channel) => channel.id)
}
These settings are specific to forum and media channels, and the SDK rejects a setting that the created channel type cannot have before it sends anything
topic: Posting guidelines of up to 4,096 characters, where other channels allow 1,024availableTags: Up to 20 tags. A tag has anameof 1 to 50 characters that no other tag of the channel uses, an optionalmoderatedflag, and at most one ofemojiId, a custom emoji of the community, andemojiName, a single Unicode emojidefaultReactionEmoji: The reaction on each post, with the same two emoji fieldsdefaultSortOrder,defaultForumLayoutanddefaultTagSetting: The defaults thatForumSortOrder,ForumLayoutand the tag setting names describe. A media channel has no layoutflags:Channelmakes every post carry a tag, which needs at least one tag that is notFlags .Require Tag moderated.Channelis valid on a media channel onlyFlags .Hide Media Download Options
Set Thread Defaults on Any Thread Parent
Text, announcement, forum and media channels accept default, one of the Thread values, and default, a slowmode in seconds from 0 to 21,600. A new thread copies the slowmode when its creation sets none. Fluxer stores the archive period but does not apply it, so a new thread uses Thread unless its creation sets another period. Pass null to clear a default
Change a Forum Channel
A channels.edit call accepts the same settings as creation, and it leaves every omitted setting unchanged. Passing null resets defaultReactionEmoji, defaultSortOrder, defaultForumLayout and defaultTagSetting. The flags value replaces all flags, so include Channel to keep it
The availableTags list replaces the whole tag list. An entry with an id keeps that tag and replaces its settings, an entry without one adds a tag, and a tag left out is deleted, after which posts stop showing it. A received ForumTag is valid input, so passing back forum.availableTags keeps every tag. An edit cannot see the channel's type, so Fluxer ignores a setting that does not belong to it, such as availableTags sent for a text channel
Change One Tag
Changing a single tag through a full list risks overwriting a concurrent change. The channels, channels and channels methods change one tag and return the updated channel. Each needs ManageChannels and accepts an auditReason
export async function addTag(client, forumId, name) {
const updated = await client.channels.createForumTag(forumId, { name })
return updated.map((channel) => channel.availableTags?.find((tag) => tag.name === name)?.id)
}
export async function moderateTag(client, forum, tagName) {
const tag = forum.availableTags?.find((candidate) => candidate.name === tagName)
if (tag === undefined)
return undefined
// Editing a tag replaces all of its settings, so the received tag supplies the ones that stay
return await client.channels.editForumTag(forum.id, tag.id, { ...tag, moderated: true })
}
export async function removeTag(client, forumId, tagId) {
return await client.channels.deleteForumTag(forumId, tagId)
}
import type { Client, GuildForumChannel } from "@neontechspace/fluxerly"
export async function addTag(client: Client, forumId: string, name: string) {
const updated = await client.channels.createForumTag(forumId, { name })
return updated.map((channel) => channel.availableTags?.find((tag) => tag.name === name)?.id)
}
export async function moderateTag(client: Client, forum: GuildForumChannel, tagName: string) {
const tag = forum.availableTags?.find((candidate) => candidate.name === tagName)
if (tag === undefined) return undefined
// Editing a tag replaces all of its settings, so the received tag supplies the ones that stay
return await client.channels.editForumTag(forum.id, tag.id, { ...tag, moderated: true })
}
export async function removeTag(client: Client, forumId: string, tagId: string) {
return await client.channels.deleteForumTag(forumId, tagId)
}
Fluxer assigns the ID of a new tag, so read it from the returned channel by name. An edit without moderated or an emoji resets them to false or none. Deleting an unknown tag fails, which includes a second delete of the same tag. Fluxer also rejects a change that would leave a channel with Channel without a tag that is not moderated
Start Posts
Read threads covers posts started with the bot. A webhook that belongs to a forum or media channel can start a post with threadName, as the webhook guide shows