Seyfert v4.3.0: The One Where Everything Gets Smarter
Guild message search, shard lifecycle hooks, permission overhaul, zombie connection slayer, and channel overwrites done right.
April 8, 2026
The "We Fixed Things You Didn't Know Were Broken" Release
Some releases add flashy new components. This one makes your bot actually survive the real world. Seyfert v4.3.0 brings guild message search, shard lifecycle awareness, a permission system that finally respects bigint, and a heartbeat mechanism that kills zombie connections before they kill your bot.
You're welcome.
Guild Message Search
Ever wanted to search messages in a guild without scrolling through Discord like a caveman? Now your bot can do it programmatically.
const results = await guild.searchMessages({
content: 'bug report',
author_id: '366779196975874049',
channel_id: '1234567890',
sort_by: GuildSearchSortBy.Relevance,
sort_order: GuildSearchSortOrder.Desc,
});
for (const message of results.messages) {
console.log(`Found: ${message.content}`);
}Filter by author, channel, content, mentions, attachments, embeds, link hostnames — basically everything Discord's search bar can do, but from code.
The API returns HTTP 202 while the search index is warming up. Pass wait: true and Seyfert handles the retry logic automatically so you don't have to write yet another polling loop. Leave it off if you'd rather handle the indexing state yourself.
Shard Lifecycle Hooks
Shards disconnect. It happens. The question is: do you know when it happens?
const client = new Client({
onShardDisconnect({ shardId, code, reason }) {
logger.warn(`Shard ${shardId} disconnected: ${code} — ${reason}`);
metrics.increment('shard.disconnect');
},
onShardReconnect({ shardId }) {
logger.info(`Shard ${shardId} reconnected`);
metrics.increment('shard.reconnect');
},
});Build alerting, dashboards, or just stop wondering why your bot went silent for 30 seconds at 3 AM.
Request Outcome Hooks
The API layer now lets you tap into every outgoing request's outcome:
const client = new Client({
onSuccessRequest(data) {
metrics.histogram('api.latency', data.latency);
},
onFailRequest(data) {
logger.error(`API call failed: ${data.route} — ${data.status}`);
alerting.notify('api-failure', data);
},
});Observability shouldn't require wrapping every API call in a try-catch. Now it doesn't.
Channel Permission Overwrites
Managing channel permissions used to mean talking to the raw API. Not anymore.
// Edit or create an overwrite
await channel.permissions.edit({
id: roleId,
type: OverwriteType.Role,
allow: ['SendMessages', 'ViewChannel'],
deny: ['ManageMessages'],
});
// Remove an overwrite
await channel.permissions.delete(roleId);Cache stays in sync automatically. No manual invalidation needed.
The Permission Overhaul
Here's the one that's been quietly causing problems: Discord permissions are bigint. They always have been. But parts of Seyfert were treating them as number.
That worked fine until someone needed a permission bit above 2^53. Now everything uses bigint consistently:
appPermissionson interactions:BigInt()instead ofNumber()InteractionGuildMemberpermissions: properly parsed asbigintBitFieldResolvableno longer acceptsnumber— onlykeyof T | bigintPermissions.resolve()drops thenumbercasePermissions.toString()added for clean serialization
PermissionStrings now accepts key strings, enum values, or bigint:
@Declare({ botPermissions: ['ManageMessages'] }) // key string
@Declare({ botPermissions: [PermissionFlagsBits.ManageMessages] }) // bigint enumBoth work. Use whichever reads better in your codebase.
Zombie Connection Slayer
The gateway now implements an ACK timeout. If Discord doesn't acknowledge a heartbeat within 1.5x the heartbeat interval, the connection is considered dead and gets recycled.
Previously, a shard could sit there pretending to be alive while Discord had long forgotten about it. Those zombie connections are now detected and killed before they cause problems.
The offline send queue was also fixed — splice() instead of map() — so queued messages actually get sent when the shard comes back online instead of being silently discarded. Fun bug.
Enums in integrationTypes & contexts
The @Declare decorator now accepts both string keys and enum values:
@Declare({
integrationTypes: ['GuildInstall', 'UserInstall'],
contexts: ['Guild', 'BotDM', 'PrivateChannel'],
})
// Or with enums
@Declare({
integrationTypes: [ApplicationIntegrationType.GuildInstall],
contexts: [InteractionContextType.Guild],
})Pick your style. We don't judge.
Webhook Method Cleanup
Webhook message methods (fetch, delete) now use structured parameter objects instead of positional arguments:
// Fetch with thread context
const msg = await webhook.messages.fetch({
messageId: '123',
threadId: '456',
});
// Delete from a thread
await webhook.messages.delete({
messageId: '123',
threadId: '456',
});Cleaner API, easier to extend, harder to accidentally swap messageId and threadId.
TimestampStyle: The Rename
The TimestampStyle enum got a correction. The old names didn't match what Discord actually renders:
| Old Name | New Name | Format |
|---|---|---|
LongTime | MediumTime | 16:20:30 |
ShortDateTime | LongDateShortTime | 20 April 2021 16:20 |
LongDateTime | FullDateShortTime | Tuesday, 20 April 2021 16:20 |
| — | ShortDateShortTime (new) | 20/04/2021 16:20 |
| — | ShortDateMediumTime (new) | 20/04/2021 16:20:30 |
If you used the old names, update them. The new names actually describe what you get.
Array Query Params
Seyfert was serializing array query parameters as ?ids=1,2,3. Discord expects ?ids=1&ids=2&ids=3. Fixed. If you were wondering why some bulk API calls were failing silently, this was probably it.
Bug Fixes
getInputValue Type Check
getInputValue was filtering by component type before reading the value, which broke for the new modal component types. It now just reads the value. The component is already in the modal — we know it's valid.
deleteMessage Parameter Consistency
Webhook deleteMessage and related methods now use consistent parameter shapes across the board.
Upgrade
pnpm install [email protected]Not every release reinvents the wheel. Sometimes it just makes the wheel stop falling off at highway speeds.
Seyfert v4.3.0 — smarter, sturdier, slightly less likely to ghost you at 3 AM.