Co-authored-by: Cursor <[email protected]>
pearcord-guild
Guild lifecycle, channel tree (including threads and forums), member joins, and the Hyperswarm gossip mesh for server-scoped realtime events.
Mission
Create and load guilds in local storage, join peers on pearcord:guild:{guildId} topics, fan out RPC gossip (messages, reactions, voice, roles, audit, …), and attach auxiliary protomux channels for attachments, voice media, and screen share.
When to use / not
Use when:
- Implementing server creation, invite joins, channel CRUD, or guild-scoped P2P replication.
- Extending gossip handlers (
_onGossip) or adding newRPC.*fanout methods.
Do not use when:
- You only need a thin channel CRUD helper without mesh — see
pearcord-channel(minimal; production path is this module). - You need DM conversations — use
pearcord-dm. - You need the full desktop API — use
pearcord-platform, which ownsPearcordGuildinstances.
Public API
| Export | Role |
|---|---|
PearcordGuild |
Main class (EventEmitter) |
PearcordGuild#create({ name, iconHash? }) |
New guild + owner member + general text + Voice Lobby; nsfwGateEnabled defaults true (v0.8.174) |
PearcordGuild#joinByInvite(invite, userId) |
Materialize guild/channels from invite; add member; bump invite uses |
PearcordGuild#setActiveGuild(guild) |
Set this.guild for list/create operations |
PearcordGuild#joinMesh(opts?) / #leaveMesh() |
Hyperswarm on topicToBuffer(guild.topic); bounded flush() via PEARCORD_GUILD_SWARM_FLUSH_MS (default 2.5s) |
PearcordGuild#listChannels() / #listMembers() |
DB queries with thread meta attached |
PearcordGuild#createChannel, #createCategory, #createThread, #createForumThread |
Channel tree |
v0.8.426 (Phase 463): gossipAudit, gossipAuditExportSnapshot, gossipAuditExportCsvSync, and gossipAuditExportArchive re-verified for P2P audit/compliance trail. Platform compliance.snapshot span wraps export snapshot gossip. See AUDIT.md, COMPLIANCE.md.
v0.8.425 (Phase 462): gossipBan / gossipKick / gossipTimeout / gossipAutomodConfig re-verified on mesh. See MODERATION.md, AUTOMOD.md.
v0.8.424 (Phase 461): gossipSlashCommand / gossipSlashCommandDelete / gossipBotInstall re-verified; bot messages via gossipMessage. See SLASH_COMMANDS.md, BOTS.md.
v0.8.423 (Phase 460): gossipAttachmentMeta + link-embed gossip re-verified on mesh (attachment.stage, embed.resolve platform spans). See ATTACHMENTS.md, EMBEDS.md.
v0.8.422 (Phase 459): gossipEmojiUpsert / gossipStickerUpsert / gossipReaction re-verified on mesh (platform spans emoji.upsert, sticker.create, reaction.toggle with guildId). See EMOJI.md, REACTIONS.md.
v0.8.421 (Phase 458): deleteChannel + gossipChannelDelete (RPC.CHANNEL_DELETE); inbound _ingestChannelDelete on mesh.
v0.8.420 (Phase 457): Platform wraps createChannel / createCategory / renameChannel with channel.create, category.create, and channel.update spans (see CHANNELS.md).
| PearcordGuild#reorderChannelsInParent | Reassign position for siblings under one category/root |
| PearcordGuild#moveChannelToParent | Move channel into category (v0.8.168) |
| PearcordGuild#reorderCategories | Reassign position for category rows |
| PearcordGuild#updateChannel, #ingestChannel | Upsert + thread meta; voice/stage userLimit (0–99); nsfw flag (v0.8.173) |
| PearcordGuild#setMessageHandler(fn) | Inbound RPC.MESSAGE_CREATE persistence hook (platform sets this) |
| PearcordGuild#gossip* / #sendVoiceMedia / #sendScreenMedia | Outbound RPC (see index.js for full list) |
| PearcordGuild#simulateGossip(method, payload) | Bare smoke injection without live peers |
| PearcordGuild#getStats() | { guildId, peers, openGossip, topic } |
| PearcordGuild#fetchAttachmentFromPeers | P2P attachment pull via pearcord-drive |
| PearcordGuild#setVoiceMediaHub / #setScreenShareHub / #setAttachmentProvider | Wire media meshes |
| ./mesh | attachGossipMesh, broadcastGossip, GOSSIP_PROTOCOL |
P2P surface
| Protocol | Transport | Purpose |
|---|---|---|
pearcord-gossip-v1 |
Protomux on Hyperswarm connection | JSON payloads in encodeRpc frames; handler _onGossip |
| Drive attach mesh | pearcord-drive/attach-mesh |
Binary attachment fetch |
| Voice media | pearcord-voice-media |
Live audio frames |
| Screen share | pearcord-screen-share |
Display frames |
Topic: guildTopic(guildId) → topicToBuffer for swarm.join. Server and client mode enabled.
Inbound events emitted include: message, message-delete, presence, typing, reaction, channel, channel-update, member, guild-sync, voice-state, peer, and many feature-specific events (audit, bots, stickers, …).
Storage
Uses shared LocalDatabase (opts.db or opts.dbPath):
@pearcord/guilds,channels,members,messages,invites,thread-meta,bans, etc.
Guild rows include topic: pearcord:guild:{id} for swarm discovery.
Platform integration
const { PearcordGuild } = require('pearcord-guild')
// createGuild / loadGuild / joinInvite:
this.guild = new PearcordGuild({ ownerId, userId, db: this.db })
await this.guild.ready()
this.guild.setActiveGuild(guildRecord)
this._wireGuild(this.guild) // setMessageHandler + event bridges
await this.guild.joinMesh()
_wireGuild connects gossip to platform emit('message'), search indexing, bot fanout, and db.insert. Outbound sends use this.guild.gossipMessage(msg) from sendMessage / edits / deletes.
Channel creation in production uses guild.createChannel / createCategory, not pearcord-channel.
UI / IPC
Indirect only. IPC create-guild, select-guild, join-invite, send-message, voice join, etc. all route through platform methods that delegate to PearcordGuild.
Related docs
- GUILD_SYNC.md — history bundle on peer join
- VOICE.md —
RPC.VOICE_STATE - VOICE_MEDIA.md — media mesh
- ATTACH_MESH_LIVE.md — attachment gossip
- MESSAGE_THREADS.md — thread channels
- FORUM_CHANNELS.md — forum posts
- MODERATION.md — bans, kicks, audit RPC
- MODULES.md
- IPC.md
Tests
-
apps/pearcord:npm run test:guild-sync—smoke-guild-sync.cjs -
smoke-guild-settings.cjs,smoke-guild-deep-link.cjs -
Many mesh smokes call
platform.guild.simulateGossip(RPC.*, payload) -
v0.8.418 (Phase 455): Server settings UI uses
syncGuildSettingsPanelDuringGuildLoadingduring guild switch; platformguild.updatespan onupdateGuildSettingsgossip path. See GUILD_SETTINGS.md. -
v0.8.410 (Phase 447): Custom roles and channel overwrites are platform-owned (
pearcord-guild-roles+channelPermissions); gossip still fans outROLE_UPSERT/ channel overwrite RPC fromPearcordGuild. Regression bundle:npm run test:phase447-roles-permissions(see ROLES.md).
Code example
const { PearcordGuild } = require('pearcord-guild')
const { LocalDatabase } = require('pearcord-db')
const Hyperswarm = require('hyperswarm')
const db = new LocalDatabase('./pearcord-storage/db')
const guild = new PearcordGuild({ ownerId: 'user-1', userId: 'user-1', db })
await guild.ready()
const { guild: g, channels } = await guild.create({ name: 'My Server' })
guild.setMessageHandler(async (msg) => {
await db.insert(require('pearcord-shared').COLLECTIONS.MESSAGES, msg)
return msg
})
await guild.joinMesh()
guild.gossipTyping({ userId: 'user-1', channelId: channels[0].id, guildId: g.id, at: Date.now() })
Repository
Part of Pearcord.
- Org:
pearcord - Clone:
git clone https://git.ssh.surf/pearcord/pearcord-guild.git - Install:
npm install git+https://git.ssh.surf/pearcord/pearcord-guild.git#main