Raven ScottandCursor bfcc944847 fix(p2p): author profiles on messages, DM users map, and download export
Gossip profile on every send, bundle author and attachmentMetas on messages,
build DM usersById from contacts, and export attachments via download-cache
before IPC to avoid stuck downloads.

Co-authored-by: Cursor <[email protected]>
2026-05-25 00:17:48 -04:00

pearcord-platform

Application facade: one PearcordPlatform class that wires identity, database, guild mesh, DMs, invites, voice, discovery, bots, and dozens of feature modules for the Pearcord desktop sidecar and companion.

Mission

Expose a single EventEmitter API the UI drives over IPC (apps/pearcord/index.js), while owning session lifecycle (onboarding, guild/DM mode, active channel), permission checks, gossip bridging, and lazy initialization of feature registries (emoji, stickers, automation, search, …).

When to use / not

Use when:

  • Building the Pearcord app, companion read-only client, or headless smoke that needs full session semantics.
  • You want one import instead of composing pearcord-identity + pearcord-guild + pearcord-message yourself.

Do not use when:

  • Writing a minimal library that only needs constants (pearcord-shared) or raw DB access (pearcord-db).
  • Implementing a single feature in isolation — prefer the focused module (pearcord-voice, pearcord-discovery, …) and optional thin adapter.

Public API

Export Role
PearcordPlatform Main facade (~9k lines)
USER_STATUS Re-exported from pearcord-shared for UI

Session & identity

Method / property Role
ready() identity.ready(), channel descriptions, invite/attachments bootstrap if onboarded
register({ username, displayName }) _bootstrapAfterUser
importIdentityBundle(bundle) Device pair restore
onboarded, identity, storagePath, db, dbPath Session state
listGuilds(), loadGuild(guildId), createGuild({ name, publicListing? }), joinInvite(code) Guild session

v0.8.431 (Phase 468): dm.open span.end includes group, peerUserId, participantCount; discovery.list span.end includes filterTag; contacts.accept span.end includes peerUserId; dm.open/contacts.accept/discovery.list error logs use error: key. Bundle: npm run test:phase468-discovery-dm. See DISCOVERY.md, CONTACTS.md.

v0.8.430 (Phase 467): voice.leave span end includes leavingIsStage; screen.start span end includes label. Bundle: npm run test:phase467-voice-stage. See VOICE.md, STAGE_CHANNELS.md.

v0.8.454 (Phase 491): automation.hook / automation.manifest / automation.hook.dryRun spans + errors. UI automation compositor + hints. Bundle: npm run test:phase491-automation. See AUTOMATION_EXPORT.md.

v0.8.453 (Phase 490): bot.token/bot.verify/bot.install/bot.message span metadata extend. UI bot compositor + hints. Bundle: npm run test:phase490-bots. See BOTS.md.

v0.8.452 (Phase 489): slash.register customCount; slash.delete deleted; slash.invoke replyLen/commandFound. UI slash compositor + hints. Bundle: npm run test:phase489-slash. See SLASH_COMMANDS.md.

v0.8.510 (Phase 547): DM spans extend — activeChannelId on dm.send and dm.group.create ends; split DMs panel compositor; clipboard dmNewDmModalBusy. Bundle: npm run test:phase547-dms. See DM.md.

v0.8.509 (Phase 546): Contacts spans extend — contacts.block/contacts.unblock spans; activeChannelId on request/accept/decline/block/unblock ends; split contacts panel compositor; contacts-errors includes block/unblock. Bundle: npm run test:phase546-contacts. See CONTACTS.md.

v0.8.508 (Phase 545): Discovery spans extend — discovery.prune span; activeChannelId on discovery.list/publish/mesh/prune ends; split discovery panel compositor; discovery-errors includes prune. Bundle: npm run test:phase545-discovery. See DISCOVERY.md.

v0.8.507 (Phase 544): Presence spans extend — presence.image span for activity artwork; activeChannelId on presence.set/presence.activity/presence.image ends; split presence panel compositor; presence-errors includes image. Bundle: npm run test:phase544-presence. See PRESENCE.md.

v0.8.528 (Phase 565): DM UI live region #dm-panel-live; dm-errors excludes voice/stage/screen/soundboard/presence/discovery/contacts bleed; clipboard dmPanelLiveBusy/channelDmConversationCount. Bundle: npm run test:phase565-dms. See DM.md.

v0.8.560 (Phase 597): Session hub live region #session-hub-panel-live; session-errors excludes audit/compliance/slash/webhook/bot/automation/attachment/embed/message/reaction/pin/search/voice/stage/screen/soundboard/presence/discovery/contacts/dm/settings/invite bleed; clipboard sessionHubPanelLiveBusy; session.startup/guild.open/identity.register span cross-check. Bundle: npm run test:phase597-session. See SESSION.md. Settings hub depth: see SETTINGS.md (Phase 598 — complete).

v0.8.589 (Phase 626): Reaction hub depth — #reaction-hub-panel-live hub mesh note + #channelName context; reaction-errors excludes thread bleed; syncComposerReactionHint dual hub/panel refresh; reaction.list/reaction.gossip span activeChannelId re-verify. Bundle: npm run test:phase626-reactions. See REACTIONS.md. Search hub depth: Phase 627 — planned.

v0.8.588 (Phase 625): Threads hub depth — #threads-hub-panel-live hub mesh note + #channelName context; thread-errors excludes expression bleed; syncComposerThreadHint dual hub/panel refresh; thread.read span activeChannelId/guildCount. Bundle: npm run test:phase625-threads. See THREADS_PANEL.md.

v0.8.587 (Phase 624): Expression hub depth — #expression-hub-panel-live hub mesh note + #channelName context; expression-errors excludes thread bleed; syncComposerExpressionHint dual hub/panel refresh. Bundle: npm run test:phase624-expression. See EMOJI.md.

v0.8.586 (Phase 623): Stickers hub depth — #sticker-hub-panel-live hub mesh note + #channelName context; sticker-errors excludes thread bleed; syncComposerStickerHint dual hub/panel refresh. Bundle: npm run test:phase623-stickers. See STICKERS.md. Expression hub depth: see EMOJI.md (Phase 624 — complete).

v0.8.583 (Phase 620): Bots hub depth — #bots-hub-panel-live hub mesh note + active channel context; bot-errors excludes thread bleed; syncComposerBotHint dual hub/panel refresh. Bundle: npm run test:phase620-bots. See BOTS.md. Automation hub depth: see AUTOMATION_EXPORT.md (Phase 621 — complete).

v0.8.582 (Phase 619): Slash hub depth — #slash-hub-panel-live hub mesh note + active channel context; slash-errors excludes thread bleed; syncComposerSlashHint dual hub/panel refresh. Bundle: npm run test:phase619-slash. See SLASH_COMMANDS.md. Bots hub depth: see BOTS.md (Phase 620 — complete).

v0.8.581 (Phase 618): Webhooks hub depth — #webhooks-hub-panel-live hub mesh note + active channel hook count; webhook-errors excludes thread bleed; syncComposerWebhooksHint dual hub/panel refresh. Bundle: npm run test:phase618-webhooks. See WEBHOOKS.md. Slash hub depth: see SLASH_COMMANDS.md (Phase 619 — complete).

v0.8.580 (Phase 617): Compliance hub depth — #compliance-hub-panel-live hub mesh note + channel context; compliance-errors excludes thread bleed; syncComposerComplianceHint dual hub/panel refresh. Bundle: npm run test:phase617-compliance. See COMPLIANCE.md. Webhooks hub depth: see WEBHOOKS.md (Phase 618 — complete).

v0.8.579 (Phase 616): Audit hub depth — #audit-hub-panel-live hub mesh note + channel context; audit-errors excludes thread bleed; syncComposerAuditHint dual hub/panel refresh. Bundle: npm run test:phase616-audit. See AUDIT.md. Compliance hub depth: see COMPLIANCE.md (Phase 617 — complete).

v0.8.578 (Phase 615): Moderation hub depth — #moderation-hub-panel-live hub mesh note + channel context; moderation-errors excludes thread bleed; syncComposerModerationHint dual hub/panel refresh. Bundle: npm run test:phase615-moderation. See MODERATION.md. Audit hub depth: see AUDIT.md (Phase 616 — complete).

v0.8.577 (Phase 614): Pin hub depth — syncPinLivePanelDuringGuildLoading; #pin-hub-panel-live hub depth copy + mesh note; pin-errors excludes thread/automod/ban/kick/timeout bleed; clipboard pinPanelLiveBusy; pin.message/pin.unpin activeChannelId re-verify. Bundle: npm run test:phase614-pins. See PINS.md. Moderation hub depth: see MODERATION.md (Phase 615 — complete).

v0.8.576 (Phase 613): Search hub depth — syncSearchLivePanelDuringGuildLoading; #search-hub-panel-live hub depth copy + mesh note; search-errors excludes pin/thread/automod/ban/kick/timeout bleed; clipboard searchPanelLiveBusy; guild.search activeChannelId re-verify. Bundle: npm run test:phase613-search. See SEARCH.md. Pins hub depth: see PINS.md (Phase 614 — complete).

v0.8.575 (Phase 612): Reaction hub depth — syncReactionLivePanelDuringGuildLoading; #reaction-hub-panel-live hub depth copy + aria-busy; reaction-errors excludes pin/automod/ban/kick/timeout bleed; clipboard reactionPanelLiveBusy; reaction.toggle/reaction.clear activeChannelId re-verify. Bundle: npm run test:phase612-reactions. See REACTIONS.md.

v0.8.574 (Phase 611): Threads hub live region depth — #threads-panel-live + syncThreadsLivePanelDuringGuildLoading; #threads-hub-panel-live aria-busy; thread-errors excludes attachment/embed/message/reaction/pin/automod/ban/kick/timeout bleed; clipboard threadsPanelLiveBusy; thread.create/thread.archive span guildCount/activeChannelId extend. Bundle: npm run test:phase611-threads. See THREADS_PANEL.md.

v0.8.573 (Phase 610): Expression hub live region depth — #expression-panel-live + syncExpressionLivePanelDuringGuildLoading; #expression-hub-panel-live aria-busy; unified expression-errors excludes attachment/embed/message/pin/automod/ban/kick/timeout bleed; clipboard expressionPanelLiveBusy; emoji.create/sticker.send/reaction.toggle span cross-check. Bundle: npm run test:phase610-expression. See EMOJI.md.

v0.8.572 (Phase 609): Stickers hub live region depth — #sticker-panel-live + syncStickerLivePanelDuringGuildLoading; #sticker-hub-panel-live aria-busy; sticker-errors excludes attachment/embed/message/reaction/pin/automod/ban/kick/timeout bleed; clipboard stickerPanelLiveBusy; sticker.create/sticker.delete/sticker.stage/sticker.send span cross-check. Bundle: npm run test:phase609-stickers. See STICKERS.md.

v0.8.571 (Phase 608): Emoji hub live region depth — #emoji-panel-live + syncEmojiLivePanelDuringGuildLoading; #emoji-hub-panel-live aria-busy; emoji-errors excludes attachment/embed/message/reaction/pin/automod/ban/kick/timeout bleed; clipboard emojiPanelLiveBusy; emoji.create/emoji.delete/emoji.stage span cross-check. Bundle: npm run test:phase608-emoji. See EMOJI.md.

v0.8.570 (Phase 607): Automation hub live region depth — #automation-panel-live + syncAutomationLivePanelDuringGuildLoading; #automation-hub-panel-live aria-busy; automation-errors excludes attachment/embed/message/reaction/pin/automod/ban/kick/timeout bleed; clipboard automationPanelLiveBusy; automation.hook/automation.manifest/automation.dispatch span cross-check. Bundle: npm run test:phase607-automation. See AUTOMATION_EXPORT.md.

v0.8.569 (Phase 606): Bots hub live region depth — #bots-panel-live + syncBotsLivePanelDuringGuildLoading; #bots-hub-panel-live aria-busy; bot-errors excludes automation/attachment/embed/message/reaction/pin/automod/ban/kick/timeout bleed; clipboard botsPanelLiveBusy; bot.install/bot.verify/bot.message span cross-check. Bundle: npm run test:phase606-bots. See BOTS.md.

v0.8.568 (Phase 605): Slash hub live region depth — #slash-panel-live + syncSlashLivePanelDuringGuildLoading; #slash-hub-panel-live aria-busy; slash-errors excludes automation/attachment/embed/message/reaction/pin/automod/ban/kick/timeout bleed; clipboard slashPanelLiveBusy; slash.register/slash.delete/slash.invoke span cross-check. Bundle: npm run test:phase605-slash. See SLASH_COMMANDS.md. Bots hub depth: see BOTS.md (Phase 606 — planned).

v0.8.567 (Phase 604): Webhooks hub live region depth — #webhooks-panel-live + syncWebhooksLivePanelDuringGuildLoading; #webhooks-hub-panel-live aria-busy; webhook-errors excludes automation/attachment/embed/message/reaction/pin/automod/ban/kick/timeout bleed; clipboard webhooksPanelLiveBusy; webhook.create/webhook.delete/webhook.execute span cross-check. Bundle: npm run test:phase604-webhooks. See WEBHOOKS.md.

v0.8.566 (Phase 603): Compliance hub live region depth — #compliance-panel-live + syncComplianceLivePanelDuringGuildLoading; #compliance-hub-panel-live aria-busy; compliance-errors excludes slash/webhook/bot/automation/attachment/embed/message/reaction/pin/search/audit bleed; clipboard compliancePanelLiveBusy; compliance.snapshot/compliance.archive/compliance.export/digest.schedule span cross-check. Bundle: npm run test:phase603-compliance. See COMPLIANCE.md.

v0.8.565 (Phase 602): Audit hub live region depth — #audit-panel-live + syncAuditLivePanelDuringGuildLoading; #audit-hub-panel-live aria-busy; audit-errors excludes slash/webhook/bot/automation/attachment/embed/message/reaction/pin/search bleed; clipboard auditPanelLiveBusy; audit.append/audit.export/audit.schedule span cross-check. Bundle: npm run test:phase602-audit. See AUDIT.md.

v0.8.564 (Phase 601): Moderation hub live region depth — #moderation-panel-live + syncModerationLivePanelDuringGuildLoading; #moderation-hub-panel-live aria-busy; moderation-errors excludes compliance/slash/webhook/bot/automation/attachment/embed/message/reaction/pin/search bleed; clipboard moderationPanelLiveBusy; ban.member/kick.member/timeout.member/automod.setConfig span cross-check. Bundle: npm run test:phase601-moderation. See MODERATION.md.

v0.8.563 (Phase 600): Roles hub live region depth — #roles-panel-live + syncRolesLivePanelDuringGuildLoading; #roles-hub-panel-live aria-busy; role-errors excludes audit/compliance/slash/webhook/bot/automation/attachment/embed/message/reaction/pin/search/permission/moderation/session/settings bleed; clipboard rolesPanelLiveBusy; role.create/role.update/role.delete/role.reorder/role.member span cross-check. Bundle: npm run test:phase600-roles. See ROLES.md.

v0.8.562 (Phase 599): Permissions hub live region #permissions-hub-panel-live; permission-errors excludes audit/compliance/slash/webhook/bot/automation/attachment/embed/message/reaction/pin/search/role/moderation/session/settings bleed; clipboard permissionsHubPanelLiveBusy; role.create/role.update/permission.overwrite/permission.eval span cross-check. Bundle: npm run test:phase599-permissions. See PERMISSIONS.md. Roles hub depth: see ROLES.md (Phase 600 — complete).

v0.8.561 (Phase 598): Settings hub live region #settings-hub-panel-live; settings-errors excludes audit/compliance/slash/webhook/bot/automation/attachment/embed/message/reaction/pin/search/voice/stage/screen/soundboard/presence/discovery/contacts/dm/session/invite bleed; clipboard settingsHubPanelLiveBusy; guildCount on settings.guild span end; settings.prefs appearance metadata (themeChanged/densityChanged). Bundle: npm run test:phase598-settings. See SETTINGS.md.

v0.8.559 (Phase 596): Onboarding hub live region #onboarding-hub-panel-live; onboarding-errors excludes audit/compliance/slash/webhook/bot/automation/attachment/embed/message/reaction/pin/search/voice/stage/screen/soundboard/presence/discovery/contacts/dm/settings/invite bleed; clipboard onboardingHubPanelLiveBusy; guildCount on guild.create span end. Bundle: npm run test:phase596-onboarding. See ONBOARDING.md.

v0.8.558 (Phase 595): DM hub live region #dm-hub-panel-live; dm-errors excludes audit/compliance/slash/webhook/bot/automation/attachment/embed/message/reaction/pin/search/voice/stage/screen/soundboard/presence/discovery/contacts/settings/invite bleed; clipboard dmHubPanelLiveBusy; guildCount on dm.open/dm.group.create span ends. Bundle: npm run test:phase595-dms. See DM.md.

v0.8.557 (Phase 594): Contacts hub live region #contacts-hub-panel-live; contacts-errors excludes audit/compliance/slash/webhook/bot/automation/attachment/embed/message/reaction/pin/search/voice/stage/screen/soundboard/presence/discovery bleed; clipboard contactsHubPanelLiveBusy; guildCount on contacts.request/accept/decline/block/unblock span ends. Bundle: npm run test:phase594-contacts. See CONTACTS.md.

v0.8.527 (Phase 564): Contacts UI live region #contacts-panel-live; contacts-errors excludes voice/stage/screen/soundboard/presence/discovery bleed; clipboard contactsPanelLiveBusy/channelContactsAcceptedCount. Bundle: npm run test:phase564-contacts. See CONTACTS.md.

v0.8.556 (Phase 593): Discovery hub live region #discovery-hub-panel-live; discovery-errors excludes audit/compliance/slash/webhook/bot/automation/attachment/embed/message/reaction/pin/search/voice/stage/screen/soundboard/presence bleed; clipboard discoveryHubPanelLiveBusy; guildCount on discovery.list/join/filter/mesh/publish/prune span ends; new discovery.filter span. Bundle: npm run test:phase593-discovery. See DISCOVERY.md.

v0.8.526 (Phase 563): Discovery UI live region #discovery-panel-live; discovery-errors excludes voice/stage/screen/soundboard/presence bleed; clipboard discoveryPanelLiveBusy/channelDiscoveryListingCount. Bundle: npm run test:phase563-discovery. See DISCOVERY.md.

v0.8.555 (Phase 592): Presence hub live region #presence-hub-panel-live; presence-errors excludes audit/compliance/slash/webhook/bot/automation/attachment/embed/message/reaction/pin/search/voice/stage/screen/soundboard bleed; clipboard presenceHubPanelLiveBusy; guildCount on presence.set/activity/custom/image span ends. Bundle: npm run test:phase592-presence. See PRESENCE.md.

v0.8.525 (Phase 562): Presence UI live region #presence-panel-live; presence-errors excludes voice/stage/screen/soundboard bleed; clipboard presencePanelLiveBusy/channelPresencePeerCount. Bundle: npm run test:phase562-presence. See PRESENCE.md.

v0.8.554 (Phase 591): Soundboard hub live region #soundboard-hub-panel-live; soundboard-errors excludes audit/compliance/slash/webhook/bot/automation/attachment/embed/message/reaction/pin/search/voice/stage/screen bleed; clipboard soundboardHubPanelLiveBusy; guildCount on soundboard.play/upload/delete/stage span ends. Bundle: npm run test:phase591-soundboard. See SOUNDBOARD.md.

v0.8.524 (Phase 561): Soundboard UI live region #soundboard-panel-live; soundboard-errors excludes voice/stage/screen bleed; clipboard soundboard live meta. Bundle: npm run test:phase561-soundboard. See SOUNDBOARD.md.

v0.8.506 (Phase 543): Soundboard spans extend — soundboard.stage span; activeChannelId on play/upload/delete/stage ends; upload panel guild-loading guard; soundboard-errors includes stage. Bundle: npm run test:phase543-soundboard. See SOUNDBOARD.md.

v0.8.544 (Phase 581): Reaction spans extend — guildCount on reaction.toggle/reaction.gossip/reaction.list/reaction.clear. UI #expression-hub-panel-live + unified expression-errors filter; clipboard expressionHubPanelLiveBusy/channelExpressionEmojiCount/channelExpressionStickerCount. Bundle: npm run test:phase581-expression. See REACTIONS.md.

v0.8.543 (Phase 580): Sticker spans extend — guildCount on sticker.create/sticker.delete/sticker.stage/sticker.send. UI #sticker-hub-panel-live + syncStickerHubLivePanelDuringGuildLoading; sticker-errors excludes audit/compliance/slash/webhook/bot/automation/emoji bleed; clipboard stickerHubPanelLiveBusy/channelStickerCount. Bundle: npm run test:phase580-stickers. See STICKERS.md.

v0.8.505 (Phase 542): Sticker spans extend — sticker.create/sticker.delete/sticker.stage/sticker.send with spanKind + activeChannelId. UI split sticker compositor panels, lastStickerTileName, dedicated sticker-errors dev-log filter. Bundle: npm run test:phase542-stickers. See STICKERS.md.

v0.8.542 (Phase 579): Emoji spans extend — guildCount on emoji.create/emoji.delete/emoji.stage. UI #emoji-hub-panel-live + syncEmojiHubLivePanelDuringGuildLoading; emoji-errors excludes audit/compliance/slash/webhook/bot/automation bleed; clipboard emojiHubPanelLiveBusy/channelEmojiCount. Bundle: npm run test:phase579-emoji. See EMOJI.md.

v0.8.504 (Phase 541): Emoji spans extend — emoji.upsert ends with spanKind: 'emoji.create'; new emoji.delete + emoji.stage spans with activeChannelId. UI split emoji compositor panels, picker tile lastEmojiTileName, clipboard emoji busy flags. Bundle: npm run test:phase541-emoji. See EMOJI.md.

v0.8.541 (Phase 578): Automation spans extend — guildCount on automation.hook/automation.dispatch/automation.manifest/automation.hook.dryRun. UI #automation-hub-panel-live + syncAutomationHubLivePanelDuringGuildLoading; automation-errors excludes audit/compliance/slash/webhook/bot bleed; clipboard automationHubPanelLiveBusy/channelAutomationHookCount. Bundle: npm run test:phase578-automation. See AUTOMATION_EXPORT.md.

v0.8.503 (Phase 540): Automation spans extend — automation.hook/automation.manifest/automation.hook.dryRun/automation.dispatch end metadata (spanKind, activeChannelId). UI automation panel compositor wrappers, hook row lastAutomationHookRowId + roving tabindex, clipboard automation busy flags. Bundle: npm run test:phase540-automation. See AUTOMATION_EXPORT.md.

v0.8.502 (Phase 539): Bot spans extend — bot.install/bot.verify/bot.message/bot.token end metadata (spanKind, activeChannelId). UI bot panel compositor wrappers, bot row lastBotRowId + roving tabindex, clipboard bot busy flags. Bundle: npm run test:phase539-bots. See BOTS.md.

v0.8.501 (Phase 538): Slash spans extend — slash.register/slash.delete/slash.invoke end metadata (spanKind, activeChannelId). UI slash panel compositor wrappers, slash row lastSlashRowId + roving tabindex, clipboard slash busy flags. Bundle: npm run test:phase538-slash. See SLASH_COMMANDS.md.

v0.8.500 (Phase 537): Webhook spans extend — webhook.create/webhook.delete/webhook.execute end metadata (spanKind, activeChannelId). UI webhook panel compositor wrappers, webhook row lastWebhookRowId + roving tabindex, clipboard webhook busy flags. Bundle: npm run test:phase537-webhooks. See WEBHOOKS.md.

v0.8.451 (Phase 488): webhook.create channelType/hasAvatar; webhook.execute messageSent. UI webhook compositor split + hints. Bundle: npm run test:phase488-webhooks. See WEBHOOKS.md.

v0.8.450 (Phase 487): audit.append hasTarget/hasDetail; audit.export archived; compliance.snapshot signed/format. UI compliance compositor. Bundle: npm run test:phase487-compliance. See COMPLIANCE.md.

v0.8.449 (Phase 486): ban.member/kick.member reasonLen/removedMember; timeout.member durationMs; automod.evaluate blocked. UI moderation compositor split + hints. Bundle: npm run test:phase486-moderation. See MODERATION.md.

v0.8.448 (Phase 485): role.create nameLen; role.update renamed/permissionsChanged; role.delete existed; permission.overwrite allowNonZero/denyNonZero. UI roles compositor split + hints. Bundle: npm run test:phase485-roles. See ROLES.md.

v0.8.447 (Phase 484): thread.create fromMessage/hasRootMessage; thread.archive wasArchived/threadName; thread.read parentId/clearedMentions; forum.post titleLen/hasTags. UI threads compositor split + hints. Bundle: npm run test:phase484-threads. See MESSAGE_THREADS.md.

v0.8.482 (Phase 519): guild.search, guild.search.cache, and guild.search.mesh spans include spanKind on start/end. UI extends search compositor (recent chips, mesh chip, panel live region). Bundle: npm run test:phase519-search. See SEARCH.md.

v0.8.462 (Phase 499): guild.search.cache span on cache hits (scope/guildId); guild.search.mesh span after mesh merge (meshHitCount/localHitCount/mergedCount). UI split search guild-loading compositor. Bundle: npm run test:phase499-search. See SEARCH.md.

v0.8.483 (Phase 520): message.edit and message.delete spans include spanKind on start/end. UI extends messaging compositor (reply bar, slowmode pill, message list live region). Bundle: npm run test:phase520-messaging. See MESSAGING.md.

v0.8.463 (Phase 500): message.send replyToId; message.edit deltaLength; message.delete hadReactions/reactionCount. UI split messaging composer guild-loading compositor. Bundle: npm run test:phase500-messaging. See MESSAGING.md.

v0.8.484 (Phase 521): reaction.toggle and reaction.gossip spans include spanKind on start/end. UI extends reaction guild-loading compositor. Bundle: npm run test:phase521-reactions. See REACTIONS.md.

v0.8.464 (Phase 501): reaction.toggle added/hadMeBefore/gossipSent; reaction.gossip span on mesh fanout. UI syncReactionPanelsDuringGuildLoading. Bundle: npm run test:phase501-reactions. See REACTIONS.md.

v0.8.485 (Phase 522): attachment.stage, attachment.read, and embed.gossip spans include spanKind on start/end. UI extends attachment guild-loading compositor. Bundle: npm run test:phase522-attachments. See ATTACHMENTS.md.

v0.8.465 (Phase 502): attachment.stage filenameLen; attachment.read attachmentId/isImage; embed.gossip span; embed.resolve gossipSent. UI split attachment guild-loading compositor. Bundle: npm run test:phase502-attachments. See ATTACHMENTS.md, EMBEDS.md.

v0.8.490 (Phase 527): soundboard.play, soundboard.upload, and soundboard.delete spans include spanKind. UI split soundboard guild-loading compositor. Bundle: npm run test:phase527-soundboard. See SOUNDBOARD.md.

v0.8.489 (Phase 526): screen.start, screen.stop, and screen.capture spans include spanKind. UI split screen guild-loading compositor. Bundle: npm run test:phase526-screen. See SCREEN_SHARE.md.

v0.8.488 (Phase 525): stage.join and stage.speaker.* spans include spanKind. UI split stage guild-loading compositor. Bundle: npm run test:phase525-stage. See STAGE.md.

v0.8.487 (Phase 524): voice.join, voice.leave, and voice.mute spans include spanKind. UI split voice guild-loading compositor (syncVoiceBarPanelDuringGuildLoading, syncVoiceRosterPanelDuringGuildLoading, syncVoiceControlsPanelDuringGuildLoading). Bundle: npm run test:phase524-voice. See VOICE.md.

v0.8.486 (Phase 523): embed.resolve and embed.gossip spans include spanKind; resolve end adds fromCache. UI extends embed guild-loading compositor. Bundle: npm run test:phase523-embeds. See EMBEDS.md.

v0.8.466 (Phase 503): embed.resolve hasDescription; embed.gossip hasTitle/hasImage/urlHost. UI syncEmbedPanelsDuringGuildLoading. Bundle: npm run test:phase503-embeds. See EMBEDS.md.

v0.8.446 (Phase 483): guild.search includeMesh/queryLen; pin.list pinCount. UI search compositor split + hints. Bundle: npm run test:phase483-search. See SEARCH.md.

v0.8.445 (Phase 482): message.send hasAttachment/hasSticker; message.edit contentChanged; message.delete wasOwn. UI messaging compositor + hints. Bundle: npm run test:phase482-messaging. See MESSAGING.md.

v0.8.444 (Phase 481): attachment.stage byteLength/isImage; attachment.read fromLocal; embed.resolve urlLen. UI attachment compositor + clipboard staging meta. Bundle: npm run test:phase481-attachments. See ATTACHMENTS.md, EMBEDS.md.

v0.8.461 (Phase 498): inbox.mark-read unreadBefore/unreadAfter; inbox.mark-all remainingUnread; notification.open jumped/mode. UI syncInboxPanelsDuringGuildLoading + inbox-errors filter. Bundle: npm run test:phase498-inbox. See INBOX.md.

v0.8.471 (Phase 508): presence.set/presence.custom/presence.activity spans extended (previousStatus, statusChanged, customTextLength, spanKind, activityName, hasAssets). Split presence guild-loading compositor + clipboard presence meta. Bundle: npm run test:phase508-presence.

v0.8.473 (Phase 510): role.update adds previousPermissionMask/permissionMaskDelta; permission.overwrite adds replacedExisting/allowChanged/denyChanged; permission.eval after overwrite upsert; permission.overwrite.delete adds hadAllow/hadDeny. UI syncPermissionsPanelsDuringGuildLoading. Bundle: npm run test:phase510-permissions.

v0.8.472 (Phase 509): discovery.list adds queryLen/sort/minMembers; discovery.publish adds beforeListed/changed; discovery.mesh adds hadCachedStats. UI split discovery guild-loading compositor + clipboard discovery meta. Bundle: npm run test:phase509-discovery.

v0.8.460 (Phase 497): presence.set/presence.custom/presence.activity spans (peerCount, activityType, guildGossip). UI presence compositor + tightened presence-errors filter. Bundle: npm run test:phase497-presence. See PRESENCE.md.

v0.8.470 (Phase 507): soundboard.play pcmBytes/peerCountInChannel/wasGossip; soundboard.upload replacedExisting; soundboard.delete hadAttachment. Split soundboard guild-loading compositor in UI. Bundle: npm run test:phase507-soundboard. See SOUNDBOARD.md.

v0.8.459 (Phase 496): soundboard.play framesQueued/remote/listenOnly; soundboard.upload soundCount/durationMs; soundboard.delete remainingSounds. UI soundboard compositor + soundboard-errors filter. Bundle: npm run test:phase496-soundboard. See SOUNDBOARD.md.

v0.8.469 (Phase 506): screen.start peerCountInChannel/displayActive; screen.capture frameBytes/captureSource; screen.stop captureSourceWas/hadCaptureLogged. Split screen guild-loading compositor in UI. Bundle: npm run test:phase506-screen. See SCREEN_SHARE.md.

v0.8.458 (Phase 495): screen.start captureSource/activeShareCount; screen.stop remainingShares; screen.capture on first display frame. UI screen compositor + screen-errors filter. Bundle: npm run test:phase495-screen. See SCREEN_SHARE.md.

v0.8.457 (Phase 494): stage.join channelType/peerCount; stage.speaker.request pendingCount; stage.speaker.approve approvedFromPending/speakerCount; stage.speaker.demote demotedFromSpeaker. UI stage compositor + stage-errors filter. Bundle: npm run test:phase494-stage. See STAGE.md.

v0.8.468 (Phase 505): stage.join joinedFresh/switchedStage/wasInVoice; stage.speaker.request wasAudience; stage.speaker.demote speakerCountAfter/pendingCountAfter. UI split stage guild-loading compositor. Bundle: npm run test:phase505-stage. See STAGE.md.

v0.8.467 (Phase 504): voice.join listenOnlyRequested/joinedFresh; voice.leave peerCountAtLeave; voice.mute span + error log (wasMuted/wasDeafened). UI voice-errors filter: voice.join|leave|mute. Bundle: npm run test:phase504-voice. See VOICE.md.

v0.8.456 (Phase 493): voice.join channelType/peerCount; voice.leave listenOnlyWas; stage.join isModerator; screen.start wasSharing/listenOnly; screen.stop hadActive. Split voice guild-loading compositor. Bundle: npm run test:phase493-voice. See VOICE.md.

v0.8.443 (Phase 480): voice.join wasInVoice/switchedChannel; voice.leave hadMedia; screen.start hasLabel; screen.stop stopped. UI voice compositor. Bundle: npm run test:phase480-voice. See VOICE.md.

v0.8.455 (Phase 492): discovery.publish on setGuildDiscoveryListing (hasInvite, memberCount); discovery.mesh on stats refresh; discovery.list logs cache hits (fromCache: true); discovery.join span.fail. UI split discovery compositor + discovery-errors dev-log filter. Bundle: npm run test:phase492-discovery. See DISCOVERY.md.

v0.8.442 (Phase 479): discovery.list meshLive/filteredCount; discovery.join on joinPublicDiscovery; dm.open reusedChannel; contacts.accept accepted. UI discovery compositor. Bundle: npm run test:phase479-discovery. See DISCOVERY.md.

v0.8.441 (Phase 478): notification.markRead wasUnread/hadMessageId; notification.markAll unreadBefore; notification.open hasMessageId; inbox.mark-read clearedInboxCount. UI syncNotificationPanelsDuringGuildLoading compositor. Bundle: npm run test:phase478-notifications. See NOTIFICATIONS.md, INBOX.md.

v0.8.440 (Phase 477): message.send hasMention/isSlash; message.edit priorLength; message.delete hadAttachments; reaction.toggle emojiLength; pin.message/pin.unpin span start channelId. UI syncMessagingPanelsDuringGuildLoading. Bundle: npm run test:phase477-messaging. See MESSAGING.md, REACTIONS.md.

v0.8.439 (Phase 476): attachment.stage span.end adds mimeType; attachment.read adds filename/mimeType; embed.resolve adds hasTitle/hasImage. UI syncAttachmentsPanelsDuringGuildLoading. Bundle: npm run test:phase476-attachments-embeds. See ATTACHMENTS.md, EMBEDS.md.

v0.8.429 (Phase 466): attachment.read span.end includes byteLength; embed.resolve includes urlHost. Bundle: npm run test:phase466-attachments-embeds. See ATTACHMENTS.md, EMBEDS.md.

v0.8.428 (Phase 465): message.send/message.edit span.end includes contentLength; reaction.toggle includes removed. Bundle: npm run test:phase465-messaging-reactions. See MESSAGING.md, REACTIONS.md.

v0.8.427 (Phase 464): role.update span.end includes name; permission.overwrite* span.end includes targetType. Bundle: npm run test:phase464-roles-permissions. See ROLES.md, PERMISSIONS.md.

v0.8.426 (Phase 463): audit.append, audit.export (end metadata), compliance.snapshot spans with guildId. Bundle: npm run test:phase463-audit-compliance. See AUDIT.md, COMPLIANCE.md.

v0.8.425 (Phase 462): automod.evaluate on send; ban.member/kick.member/timeout.member re-verified with guildId. Bundle: npm run test:phase462-moderation-automod. See MODERATION.md, AUTOMOD.md.

v0.8.424 (Phase 461): slash.invoke span includes guildId/channelId; bot.message + bot.install spans with guildId. Bundle: npm run test:phase461-slash-bots. See SLASH_COMMANDS.md, BOTS.md.

v0.8.423 (Phase 460): embed.resolve span uses active guildId/channelId fallback; attachment.stage/attachment.read re-verified. Bundle: npm run test:phase460-attachments-embeds. See ATTACHMENTS.md, EMBEDS.md.

v0.8.422 (Phase 459): emoji.upsert + sticker.create spans include guildId + span.fail; reaction.toggle error log includes guildId/channelId (re-verified). Bundle: npm run test:phase459-reactions-emojis. See REACTIONS.md, EMOJI.md.

v0.8.421 (Phase 458): channel.delete span + gossip; thread.create, thread.archive, forum.post spans include guildId + span.fail. Bundle: npm run test:phase458-threads-forum. See MESSAGE_THREADS.md, FORUM_CHANNELS.md.

v0.8.420 (Phase 457): channel.create, channel.update (rename), and category.create spans + error logs with guildId. create-channel IPC selects new channel and emits composer focus. Bundle: npm run test:phase457-channels. See CHANNELS.md.

v0.8.419 (Phase 456): session.startup span ends with guildCount + guildId; session.startup error log. identity.register span + identity.register error. guild.open span end includes guildId. loadGuild / createGuild bust search cache and clear _lastSearchFromCache. Bundle: npm run test:phase456-onboarding-session. See SESSION.md.

v0.8.540 (Phase 577): Bot spans extend — guildCount on bot.install/bot.verify/bot.message. UI #bots-hub-panel-live + syncBotsHubLivePanelDuringGuildLoading; bot-errors excludes audit/compliance/slash/webhook bleed; clipboard botsHubPanelLiveBusy/channelBotCount. Bundle: npm run test:phase577-bots. See BOTS.md.

v0.8.539 (Phase 576): Slash spans extend — guildCount on slash.register/slash.delete/slash.invoke. UI #slash-hub-panel-live + syncSlashHubLivePanelDuringGuildLoading; slash-errors excludes audit/compliance/webhook/bot bleed; clipboard slashHubPanelLiveBusy/channelCustomSlashCount. Bundle: npm run test:phase576-slash. See SLASH_COMMANDS.md.

v0.8.538 (Phase 575): Webhook spans extend — guildCount on webhook.create/webhook.delete/webhook.execute. UI #webhooks-hub-panel-live + syncWebhooksHubLivePanelDuringGuildLoading; webhook-errors excludes audit/compliance/slash bleed; clipboard webhooksHubPanelLiveBusy/channelWebhookCount. Bundle: npm run test:phase575-webhooks. See WEBHOOKS.md.

v0.8.537 (Phase 574): Compliance spans extend — guildCount on compliance.snapshot; new compliance.archive span on export archive append; new digest.schedule span on setDigestExportSchedule. UI #compliance-hub-panel-live + syncComplianceHubLivePanelDuringGuildLoading; compliance-errors excludes audit/moderation bleed; clipboard complianceHubPanelLiveBusy/channelComplianceArchiveCount. Bundle: npm run test:phase574-compliance. See COMPLIANCE.md.

v0.8.536 (Phase 573): Audit spans extend — guildCount on audit.append/audit.export/audit.schedule; new audit.schedule span + error logging on setAuditExportSchedule. UI #audit-hub-panel-live + syncAuditHubLivePanelDuringGuildLoading; audit-errors excludes moderation bleed; clipboard auditHubPanelLiveBusy/auditExportChromeBusy/channelAuditEntryCount. Bundle: npm run test:phase573-audit. See AUDIT.md.

v0.8.535 (Phase 572): Moderation spans extend — guildCount on ban.member/kick.member/timeout.member/automod.setConfig. UI #moderation-hub-panel-live + syncModerationHubLivePanelDuringGuildLoading; moderation-errors excludes role/permission/session/automod/audit bleed; clipboard moderationHubPanelLiveBusy/moderationKickChromeBusy/channelModerationBanCount. Bundle: npm run test:phase572-moderation. See MODERATION.md.

v0.8.534 (Phase 571): Role spans extend — guildCount on role.create/role.delete/role.reorder; role.member spanKind/activeChannelId/assignedRoleCount/customRoleCount. UI #roles-hub-panel-live + syncRolesHubLivePanelDuringGuildLoading; role-errors excludes permission bleed; clipboard rolesHubPanelLiveBusy/rolesReorderChromeBusy/channelCustomRoleCount. Bundle: npm run test:phase571-roles. See ROLES.md.

v0.8.533 (Phase 570): Permission spans extend — role.update/permission.overwrite/permission.eval guildCount; permission.eval spanKind/activeChannelId. UI #permissions-panel-live + syncPermissionsLivePanelDuringGuildLoading; permission-errors/role-errors exclude session/settings/invite bleed; clipboard permissionsPanelLiveBusy/permissionsRoleChromeBusy/channelPermissionOverwriteCount. Bundle: npm run test:phase570-permissions. See PERMISSIONS.md.

v0.8.532 (Phase 569): Session spans extend — session.startup spanKind/activeChannelId; guild.open memberCount/guildCount/channelCount/spanKind. UI #session-panel-live + syncSessionLivePanelDuringGuildLoading; session-errors excludes settings/invite bleed; clipboard sessionPanelLiveBusy/sessionBootChromeBusy/channelSessionGuildCount. Bundle: npm run test:phase569-session. See SESSION.md.

v0.8.530 (Phase 567): Onboarding spans extend — identity.register/guild.create/invite.join activeChannelId; guild.create/invite.join textChannelCount. UI #onboarding-panel-live + syncOnboardingLivePanelDuringGuildLoading; onboarding-errors excludes dm/contacts/discovery/invites bleed; clipboard onboardingPanelLiveBusy/onboardingRailChromeBusy/channelOnboardingGuildCount. Bundle: npm run test:phase567-onboarding. See ONBOARDING.md.

v0.8.474 (Phase 511): Onboarding spans — identity.register (usernameLen, displayNameLen, hadGuilds), guild.create (channelCount, isFirstGuild, listOnDiscovery), invite.join (inviteLen, guildId) + matching error logs. UI syncOnboardingPanelsDuringGuildLoading, #composer-onboarding-hint, dev-log onboarding-errors + clipboard meta. Bundle: npm run test:phase511-onboarding. See ONBOARDING.md.

v0.8.531 (Phase 568): Settings spans extend — settings.prefs/notifications.prefs/guild.update activeChannelId + guildCount; UI #settings-panel-live + syncSettingsLivePanelDuringGuildLoading; settings-errors excludes onboarding/invite bleed; clipboard settingsPanelLiveBusy/settingsNavChromeBusy/channelSettingsGuildCount. Bundle: npm run test:phase568-settings. See SETTINGS.md.

v0.8.475 (Phase 512): Settings spans — settings.prefs (patchKeyCount, themeChanged), notifications.prefs, guild.update / settings.guild (nameChanged, iconChanged, nsfwGateChanged). UI syncSettingsPanelsDuringGuildLoading, #composer-settings-hint, dev-log settings-errors + clipboard meta. Bundle: npm run test:phase512-settings. See SETTINGS.md.

v0.8.476 (Phase 513): Guild-admin spans — channel.create (nameLen, hadParent), channel.delete (wasActive, channelType), channel.reorder (updatedCount, channelCount). UI syncGuildAdminPanelsDuringGuildLoading, #composer-guild-admin-hint, dev-log guild-admin-errors + clipboard meta. Bundle: npm run test:phase513-guild-admin. See CHANNELS.md.

v0.8.479 (Phase 516): Contact spans — contacts.request (peerDisplayNameLen), contacts.accept (accepted), contacts.decline (declined). UI syncContactsPanelsDuringGuildLoading, contacts-errors filter, clipboard contacts meta. Bundle: npm run test:phase516-contacts. See CONTACTS.md.

v0.8.478 (Phase 515): DM spans — dm.open (spanKind, reusedChannel, peerDisplayNameLen), dm.send (when guildId === dm), dm.group.create (participantCount, nameLen). UI syncDmsPanelsDuringGuildLoading, tightened dm-errors, clipboard DM meta. Bundle: npm run test:phase515-dms. See DM.md.

v0.8.499 (Phase 536): Compliance/audit spans extend — audit.append/audit.export/compliance.snapshot end metadata (spanKind, activeChannelId). UI compliance panel compositor wrappers, audit row lastAuditRowId + roving tabindex, clipboard compliance busy flags. Bundle: npm run test:phase536-compliance. See COMPLIANCE.md, AUDIT_LOG.md.

v0.8.523 (Phase 560): Screen spans extend — screen.start/screen.stop/screen.capture activeChannelId. UI #screen-panel-live, syncScreenPopoutLivePanelDuringGuildLoading. Bundle: npm run test:phase560-screen. See SCREEN_SHARE.md.

v0.8.522 (Phase 559): Stage spans extend — stage.join/stage.speaker.request/stage.speaker.approve/stage.speaker.demote activeChannelId. UI #stage-panel-live, syncStageHandRaiseLivePanelDuringGuildLoading. Bundle: npm run test:phase559-stage. See STAGE.md.

v0.8.521 (Phase 558): Voice spans extend — voice.join/voice.leave/voice.mute activeChannelId. UI #voice-panel-live, syncVoiceOccupancyLivePanelDuringGuildLoading. Bundle: npm run test:phase558-voice. See VOICE.md.

v0.8.553 (Phase 590): Screen spans extend — screen.start/screen.stop/screen.capture end adds guildCount. UI #screen-hub-panel-live, syncScreenHubLivePanelDuringGuildLoading; tightened screen-errors bleed exclusions. Bundle: npm run test:phase590-screen. See SCREEN_SHARE.md.

v0.8.552 (Phase 589): Stage spans extend — stage.join/stage.speaker.request/stage.speaker.approve end adds guildCount. UI #stage-hub-panel-live, syncStageHubLivePanelDuringGuildLoading; tightened stage-errors bleed exclusions. Bundle: npm run test:phase589-stage. See STAGE.md.

v0.8.551 (Phase 588): Voice spans extend — voice.join/voice.leave/voice.mute end adds guildCount. UI #voice-hub-panel-live, syncVoiceHubLivePanelDuringGuildLoading; tightened voice-errors bleed exclusions. Bundle: npm run test:phase588-voice. See VOICE.md.

v0.8.550 (Phase 587): Pin spans extend — pin.message/pin.unpin/pin.list end adds guildCount. UI #pin-hub-panel-live, syncPinHubLivePanelDuringGuildLoading; tightened pin-errors bleed exclusions. Bundle: npm run test:phase587-pins. See PINS.md.

v0.8.549 (Phase 586): Search spans extend — guild.search/search.pins end adds guildCount. UI #search-hub-panel-live, syncSearchHubLivePanelDuringGuildLoading; tightened search-errors bleed exclusions. Bundle: npm run test:phase586-search. See SEARCH.md.

v0.8.548 (Phase 585): Reaction spans extend — reaction.clear end adds guildCount (toggle/list re-verified). UI #reaction-hub-panel-live, syncReactionHubLivePanelDuringGuildLoading; tightened reaction-errors bleed exclusions. Bundle: npm run test:phase585-reactions. See REACTIONS.md.

v0.8.547 (Phase 584): Message spans extend — message.send/message.edit/message.delete end adds guildCount. UI #messaging-hub-panel-live, syncMessagingHubLivePanelDuringGuildLoading; tightened message-errors bleed exclusions. Bundle: npm run test:phase584-messaging. See MESSAGING.md.

v0.8.546 (Phase 583): Attachment spans extend — attachment.stage/attachment.read/attachment.unlink end adds guildCount. UI #attachment-hub-panel-live, syncAttachmentHubLivePanelDuringGuildLoading; tightened attachment-errors bleed exclusions. Bundle: npm run test:phase583-attachments. See ATTACHMENTS.md.

v0.8.545 (Phase 582): Embed spans extend — embed.resolve/embed.gossip/embed.clear end adds guildCount. UI #embed-hub-panel-live, syncEmbedHubLivePanelDuringGuildLoading; tightened embed-errors bleed exclusions. Bundle: npm run test:phase582-embeds. See EMBEDS.md.

v0.8.519 (Phase 556): Attachment spans extend — attachment.stage stagedCount/remainingStagingCapacity; attachment.read activeChannelId; attachment.unlink on delete. UI split attachment panels; #attachment-panel-live. Bundle: npm run test:phase556-attachments. See ATTACHMENTS.md.

v0.8.518 (Phase 555): Reaction spans extend — reaction.toggle messageReactionCount/activeChannelId; reaction.list rowCount/messageCount; reaction.clear on delete via clearReactionsForMessage. UI split reaction pills/quick-react/picker chrome/live panels; #reaction-panel-live. Bundle: npm run test:phase555-reactions. See REACTIONS.md.

v0.8.517 (Phase 554): Messaging spans extend — message.send channelMessageCount/remainingCharCapacity; message.edit editAgeMs; message.delete meshFanout. UI split messaging panels; #messaging-panel-live. Bundle: npm run test:phase554-messaging. See MESSAGING.md.

v0.8.516 (Phase 553): Search spans extend — guild.search searchSpanKind (search.messages/search.dms/search.pins), remainingResultCapacity; pin.list spanKind: search.pins. UI split search panels; #search-panel-live. Bundle: npm run test:phase553-search. See SEARCH.md.

v0.8.515 (Phase 552): Compliance spans extend — audit.append auditEntryCount, audit.export exportLimit/remainingExportCapacity, compliance.snapshot meshPushed/archiveAppended. UI split compliance panels; .compliance-panel-live. Bundle: npm run test:phase552-compliance. See COMPLIANCE.md.

v0.8.514 (Phase 551): Moderation spans extend — kick.member memberCount, timeout.member activeTimeoutCount, automod.setConfig keywordCount/blockInvites. UI split automod/ban/member panels; .moderation-panel-live/.moderation-modal-live; clipboard moderationAutomodTogglesBusy/moderationTimeoutModalBusy. Bundle: npm run test:phase551-moderation. See MODERATION.md.

v0.8.498 (Phase 535): Moderation/automod spans extend — ban.member/kick.member/timeout.member/automod.* end metadata (spanKind, activeChannelId). UI moderation panel compositor wrappers, ban/audit aria-current=location, clipboard moderation busy flags. Bundle: npm run test:phase535-moderation. See MODERATION.md.

v0.8.513 (Phase 550): Role/permission spans extend — customRoleCount on update/delete, channelOverwriteCount/remainingOverwriteCount. UI split role list + channel perm panels; .roles-panel-live/.roles-modal-live; clipboard rolesListChromeBusy/rolesChannelPermControlsBusy. ui-flow composer focus after delete/reorder role. Bundle: npm run test:phase550-roles. See ROLES.md.

v0.8.497 (Phase 534): Role/permission spans extend — role.create/update/delete/reorder and permission.overwrite* end metadata (spanKind, activeChannelId, customRoleCount). UI roles panel compositor wrappers, role/overwrite aria-current=location, clipboard roles busy flags. Bundle: npm run test:phase534-roles. See ROLES.md.

v0.8.512 (Phase 549): Guild-admin spans extend — channel.create channelCount, channel.delete remainingChannelCount, channel.reorder requestedCount/reorderedAll. UI split channel list chrome/rows + category panels; .guild-admin-modal-live; clipboard guildAdminChannelModalBusy. ui-flow composer focus after rename-channel/create-category. Bundle: npm run test:phase549-guild-admin. See CHANNELS.md.

v0.8.496 (Phase 533): Guild-admin spans extend — channel.create/delete/reorder end metadata (spanKind, activeChannelId, createdChannelId). UI panel compositor wrappers, channel row aria-current=location, clipboard guild-admin busy flags. Bundle: npm run test:phase533-guild-admin. See CHANNELS.md.

v0.8.529 (Phase 566): Invite spans extend — guild.invite (textChannelCount, guildCount), invite.revoke (guildCount). UI #invites-panel-live + syncInvitesLivePanelDuringGuildLoading; invite-errors excludes dm/contacts/discovery/presence bleed; clipboard invitesPanelLiveBusy/invitesHubChromeBusy/channelGuildTextChannelCount. Bundle: npm run test:phase566-invites. See INVITES.md.

v0.8.511 (Phase 548): Invite spans extend — guild.invite (maxUses, activeChannelId), invite.revoke (activeChannelId). UI split hub buttons/banner + join/invite modal panels, .invite-modal-live, clipboard invitesJoinModalBusy/invitesInviteModalBusy. ui-flow composer focus after create-invite. Bundle: npm run test:phase548-invites. See INVITES.md.

v0.8.495 (Phase 532): Invite spans extend — guild.invite (spanKind, hasShareCode), invite.join (activeChannelId, guildCount, spanKind), invite.revoke (spanKind). UI split compositor (syncInvitesHubPanelDuringGuildLoading, syncInvitesJoinPanelDuringGuildLoading, syncInvitesInvitePanelDuringGuildLoading), invite code aria-current=location, clipboard invitesHubBusy/invitesHubButtonsBusy/inviteCopyBusy. Bundle: npm run test:phase532-invites. See INVITES.md.

v0.8.477 (Phase 514): Invite spans — guild.invite (shareCodeLen, channelCount), invite.join (inviteGuildId, portable), invite.revoke (revoked). UI syncInvitesPanelsDuringGuildLoading, #composer-invite-hint, dev-log invite-errors + clipboard meta. Bundle: npm run test:phase514-invites. See INVITES.md.

Messaging & channels

Method Role
selectChannel(channelId) Sets messages.setChannel, read state, voice context
sendMessage, editMessage, deleteMessage Delegates to PearcordMessage + guild/DM gossip
signalTyping, toggleReaction Gossip + local state
createCategory, createForumPost, thread helpers PearcordGuild + permissions

Invites & discovery

Method Role
createInvite() PearcordInvite#create with channel snapshot
joinInvite(code) Resolve + guild.joinByInvite + mesh; pearcord://explore?…navigateDeepLink (v0.8.108)
markOnboardingExploreShown() Clear first-guild Explore prompt; onboardingExploreShown pref (v0.8.108)
setThreadsPanelFilter(filter) Filter chips; persists threadsPanelFilter in USER_PREFS (v0.8.108)
formatDiscoveryExploreBaselineDeepLink() pearcord://explore?baseline&at share URL (v0.8.107)

Voice & media

Method Role
joinVoice, leaveVoice, setVoiceMute pearcord-voice + guild gossip
setVoiceRosterChannelExpanded(channelId, expanded) USER_PREFS voiceRosterExpandedChannelIds (v0.8.110)
setDiscoveryFilter({ query, sort, minMembers, tag }) Persists discoveryExploreFilter in USER_PREFS (v0.8.111)
Voice/s screen share ingest VoiceMediaHub, ScreenShareHub wired in _openGuild

Views & companion

Property Role
mode 'home', 'guild', or DM mode
guildBans Ban rows for active guild (@pearcord/bans, limit 200) (v0.8.409)
getViewState() / snapshot builders IPC state payloads for UI
_readOnly, _companionMode Companion restrictions

Hundreds of additional methods cover moderation, bots, search, audit export, forums, stage, automod, boosts, settings mesh, contacts, notifications — each delegating to the matching pearcord-* package.

P2P surface

Platform does not implement wire protocols; it orchestrates:

Subsystem Module Topic / protocol
Guild gossip pearcord-guild pearcord-gossip-v1 on guild.topic
DM mesh pearcord-dm dmTopic / group DM topics
Contacts pearcord-contacts contactsTopic
Settings / prefs pearcord-settings userPrefsTopic
Discovery pearcord-discovery Public listings mesh
Device pair pearcord-device-sync deviceSyncTopic + DEVICE_PAIR_* RPC

_wireGuild(guild) registers setMessageHandler and forwards guild events to platform.emit (message, member, guild-sync, voice, …).

Storage

Path Owner
{storagePath}/db/ LocalDatabase — all @pearcord/* collections
{storagePath}/identity/ pearcord-identity keypairs
{storagePath}/dm-meta/ JsonStore for DM metadata
Feature dirs attachments, discovery JSON, moderation, voice state, etc.

storagePath from resolveStoragePath() (PEARCORD_STORAGE or ~/.config/pearcord).

Platform integration (core batch A wiring)

// Constructor (simplified)
this.db = new LocalDatabase(this.dbPath)
this.identity = new PearcordIdentity({ db, storagePath })
// ready() → invite, attachments, discovery when snap.user

// Guild open (_openGuild)
this.guild = new PearcordGuild({ ownerId, userId, db })
this._wireGuild(this.guild)
await this.guild.joinMesh()
this.messages = new PearcordMessage({ authorId: user.id, db })
Dependency Role in platform
pearcord-db Shared this.db
pearcord-identity this.identity, storage paths
pearcord-guild Active server + mesh
pearcord-message this.messages per channel
pearcord-invite this.invite
pearcord-shared Permissions, COLLECTIONS, deep links, id, now

pearcord-channel and pearcord-sync are not dependencies.

UI / IPC

Primary consumer: apps/pearcord/index.js sidecar reading pear-pipe JSON.

Direction Examples
UI → platform register, create-guild, join-invite, select-guild, select-channel, send-message, join-voice

v0.8.115: loadGuild / _openGuild clears stale activeChannelId, then _selectGuildChannelWithUnread picks mention-weighted unread channels before falling back to the first text channel. setSearch records searchRecentByGuild in user prefs. View: searchRecentQueries.

v0.8.397: ingestInboundGuildMessage(msg) processes guild mesh gossip while on home (mention alerts + inbox via DB member lookup). markAllNotificationsRead / openNotificationTarget / markChannelRead log structured errors. Smoke helper: simulateGuildMessage(platform, msg) in smoke-runner.cjs.

v0.8.398: parseSearchQuery + _applySearchQueryFilters for guild/channel search; pinMessage/unpinMessage log pin.message/pin.unpin spans and errors; guild.search error on search failure.

v0.8.399: banMember/kickMember/timeoutMember log ban.member/kick.member/timeout.member spans and errors; exportAuditLog logs audit.export span and audit.export error.

v0.8.400: createChannelWebhook/deleteChannelWebhook/executeChannelWebhook log webhook.* spans and errors; registerSlashCommands/deleteSlashCommand/executeSlashCommand log slash.* spans and errors.

v0.8.411 (Phase 448): Webhook and slash spans/errors include guildId metadata; webhook.execute span end includes channelId. Dev-log webhook-errors filter: webhook.create|delete|execute; slash-errors: slash.register|delete|invoke. Integrations UI permission toasts; webhook token modal autofocus. Bundle: npm run test:phase448-webhooks-integrations.

v0.8.412 (Phase 449): sendMessage/editMessage/deleteMessage/toggleReaction spans/errors include guildId + channelId; _assertCanParticipate('send'|'reaction') for distinct read-only errors. Dev-log message-errors filter: message.send|edit|delete; reaction-errors: reaction.toggle. UI: message toolbar + reaction pill keyboard roving, composer autofocus after reaction, permission toasts. Bundle: npm run test:phase449-messaging-reactions.

v0.8.413 (Phase 450): stageAttachment/readAttachmentPreview/embed.resolve spans/errors include guildId + channelId; _assertCanParticipate('attach') for read-only attach gate. Dev-log attachment-errors filter: attachment.stage|read; embed-errors: embed.resolve. UI: staging bar + btn-attach aria-busy, attach-files permission toast, staging/embed keyboard roving, empty-state hints. Bundle: npm run test:phase450-attachments-media.

v0.8.431 (Phase 468): openDM span.end adds group: false + peerUserId; openGroupDM span.end adds group: true + participantCount; discovery.list span.end adds filterTag; acceptFriendRequest span.end re-verifies peerUserId. Error logs use error: key (not err:). Dev-log clipboard: discoveryFilterTag, discoveryMeshLive, dmChannelCount, contactsPendingCount. UI: syncDiscoveryPanelsDuringGuildLoading, #composer-dm-hint, 🔒 E2E badge. Bundle: npm run test:phase468-discovery-dm.

v0.8.415 (Phase 452): openDM/openGroupDM log dm.open spans + dm.open error; sendFriendRequest/acceptFriendRequest log contacts.request/contacts.accept spans; _buildView logs discovery.list span + discovery.list error. Dev-log dm-errors filter: dm.open|group, contacts.request|accept|decline, discovery.list. UI-flow emits composer-focus-channel after DM open. Bundle: npm run test:phase452-discovery-dm.

v0.8.414 (Phase 451): joinVoiceChannel/leaveVoiceChannel/joinStageChannel/requestStageSpeak/approveStageSpeaker/demoteStageSpeaker/startScreenShare/stopScreenShare spans/errors include guildId + channelId. Dev-log voice-errors filter: voice.join|leave, stage.join|speaker.*, screen.start|stop. UI: voice/stage bars + channel list aria-busy, stage connect/speak permission toasts, stage approve keyboard, stream popout autofocus. Bundle: npm run test:phase451-voice-stage.

v0.8.402: sendMessage/editMessage/deleteMessage log message.* spans and errors; toggleReaction logs reaction.toggle span and reaction.toggle error on failure.

v0.8.403: stageAttachment/readAttachmentPreview log attachment.* spans and errors; _queueLinkEmbed logs embed.resolve span and embed.resolve error on failure.

v0.8.436 (Phase 473): role.create/role.update span.end adds hasColor and permissionMask; permission.overwrite adds allowBits/denyBits; permission.overwrite.delete adds deleted. UI syncRolesPanelsDuringGuildLoading + composer roles hint. Smokes: test:platform-role-span-metadata-extend, test:platform-permission-span-metadata-extend. Bundle: test:phase473-roles-permissions.

v0.8.439 (Phase 476): attachment.stage/attachment.read/embed.resolve span.end metadata extend (mimeType, filename, hasTitle, hasImage). UI syncAttachmentsPanelsDuringGuildLoading. Smokes: test:platform-attachment-span-metadata-extend, test:platform-embed-span-metadata-extend. Bundle: test:phase476-attachments-embeds.

v0.8.438 (Phase 475): slash.invoke span.end adds argCount/ephemeral/builtin; bot.install adds botName/permissionMask; bot.message adds contentLength/botId. UI syncSlashBotsPanelsDuringGuildLoading + ensureComposerContextHints + #composer-slash-hint. IPC bot-installed/slash-invoked. Bundle: test:phase475-slash-bots.

v0.8.437 (Phase 474): webhook.create span.end adds webhookName/channelId; webhook.delete adds deleted; webhook.execute adds contentLength/hasUsername; slash.register adds firstName. UI syncWebhooksPanelsDuringGuildLoading + composer webhooks hint. Smokes: test:platform-webhook-span-metadata-extend, test:platform-slash-span-metadata-extend. Bundle: test:phase474-webhooks-integrations.

v0.8.435 (Phase 472): ban.member/kick.member span end adds hasReason; ban.member adds banCount; timeout.member adds until; audit.export adds signed. UI extended syncModerationPanelsDuringGuildLoading + composer moderation hint. Smokes: test:platform-moderation-span-metadata-extend, test:dev-log-moderation-errors-tighten, test:dev-log-audit-errors-tighten. Bundle: test:phase472-moderation-audit.

v0.8.434 (Phase 471): thread.create span end adds parentType/threadName; thread.archive adds parentId; forum.post adds parentChannelId/messageId. Error logs use error: key. UI syncThreadsPanelsDuringGuildLoading + composer thread hint + thread-read live extend. Smokes: test:platform-thread-span-metadata-extend, test:dev-log-thread-errors-tighten. Bundle: test:phase471-threads-forum.

v0.8.433 (Phase 470): guild.search span end adds meshHitCount/localHitCount/mesh per scope; pin.message/pin.unpin span end adds messageId + pinCount. UI syncSearchPanelsDuringGuildLoading + composer search hint. Smokes: test:platform-search-span-metadata-extend, test:dev-log-search-errors-tighten, test:dev-log-pin-errors-tighten. Bundle: test:phase470-search-pins.

v0.8.432: notification.markRead span end adds kind + read; notification.markAll adds inboxCount; notification.open adds messageId; inbox.mark-read/thread.read span end adds threadRead + isDm. Error logs use error: key. UI syncNotificationPanelsDuringGuildLoading + composer notif hint + thread-read live region. Smokes: test:platform-notification-span-metadata-extend, test:dev-log-notification-errors-tighten, test:dev-log-inbox-errors-tighten. Bundle: test:phase469-notifications-inbox.

v0.8.416: openNotificationTarget span end includes guildId; markAllNotificationsRead / markNotificationRead / markChannelRead (inbox.mark-read or thread.read) span end includes guildId + channelId. Smoke: test:platform-notification-span-guild-id. Bundle: test:phase453-notifications-inbox.

v0.8.407: markNotificationRead(notificationId) wraps inbox markRead with notification.markRead span + notification.markRead error. markAllNotificationsRead span ends with count + guildId. markChannelRead logs inbox.mark-read span + error for non-thread channels (thread channels use thread.read). Smokes: test:notification-platform-errors, test:inbox-platform-errors. Bundle: test:phase444-notifications-inbox.

v0.8.409 (Phase 446): banMember/kickMember/timeoutMember spans include guildId metadata on start and error lines; exportAuditLog span includes guildId, format, filter; setAutomodConfig logs automod.setConfig span + automod.setConfig error. View snapshot adds guildBans (db.find(COLLECTIONS.BANS, { guildId }, { limit: 200 })). Bundle: test:phase446-moderation-audit.

v0.8.410 (Phase 447): createGuildCustomRole/updateGuildCustomRole/deleteGuildCustomRole/reorderGuildCustomRoles/setMemberCustomRoles spans and role.* error lines include guildId; upsertChannelPermissionOverwrite/deleteChannelPermissionOverwrite spans and permission.overwrite*.error include guildId, channelId, targetType, targetId. View snapshot adds channelPermsByChannel (effective viewChannel/sendMessages per channel) and channelOverwriteCount (guild overwrite row count). Bundle: test:phase447-roles-permissions.

v0.8.418: updateGuildSettings logs guild.update span + guild.update error; createInvite logs guild.invite span + guild.invite error (both include guildId). Smoke: test:platform-guild-settings-span-guild-id. Bundle: test:phase455-guild-settings.

v0.8.417: guild.search spans include guildId on start/end (endSearchSpan helper); pin.message/pin.unpin spans include guildId. Smoke: test:platform-search-span-guild-id. Bundle: test:phase454-search-pins.

v0.8.408: markChannelRead calls _invalidateSearchCache() when the channel is a thread (thread.read path) so search results refresh after thread read. Smoke: test:search-cache-invalidate-thread-read. Bundle: test:phase445-search-inbox.

v0.8.406: createThread/createForumPost/markChannelRead (thread channels)/archiveThread log thread.create/forum.post/thread.read/thread.archive spans and errors; audit entries for thread.create, forum.post.create, thread.archive, and thread.unarchive. Smoke: test:thread-platform-errors.

v0.8.401: createGuildCustomRole/updateGuildCustomRole/deleteGuildCustomRole/reorderGuildCustomRoles/setMemberCustomRoles log role.* spans and errors; upsertChannelPermissionOverwrite/deleteChannelPermissionOverwrite log permission.overwrite* spans and errors.

v0.8.252: Guild search mesh skipped when guildOpenNoViewableChannels; emoji batch prefetch skips negative miss TTL; sticker gossip prefetch gated on attachments; session.startup logs INFO when initial guild mesh flush was bounded. Smoke: test:guild-search-no-viewable-skip, test:sticker-prefetch-attachments-ready.

v0.8.248: Guild open filters unread/last picks with _canViewChannel; sets guildOpenNoViewableChannels when none accessible; defers _ensureGuildModules via setTimeout(0) after channel pick; emoji mesh prefetch clears miss cache on success. Smokes: test:guild-viewable-channel-pick, test:guild-open-no-viewable, test:guild-plain-beats-dual-combo.

v0.8.158: Between two mention+plain parent buckets, the category with the higher combined score wins on guild open. Smoke: test:guild-dual-combo-buckets-highest.

v0.8.157: A heavy plain-only parent bucket whose total exceeds three lower mention+plain combo categories wins on guild open. Smoke: test:guild-plain-beats-triple-combo.

v0.8.156: Among three mention+plain parent buckets, the category with the highest combined score wins on guild open. Smoke: test:guild-triple-combo-buckets-highest.

v0.8.155: Among three plain-only parent buckets, the category with the highest combined unread total wins on guild open. Smoke: test:guild-triple-plain-bucket-pick.

v0.8.154: A mention+plain parent bucket whose combined score exceeds a higher plain-only bucket wins on guild open. Smoke: test:guild-combo-beats-plain-bucket.

v0.8.153: When plain-only and mention+plain parent buckets tie on total score, the bucket with the lower minimum channel position wins. Smoke: test:guild-plain-combo-minpos-tie.

v0.8.152: Between two plain-only parent buckets, the category with the higher plain-unread total wins on guild open. Smoke: test:guild-dual-plain-bucket-pick.

v0.8.151: A plain-only parent bucket whose unread total exceeds a lighter mention+plain combo bucket wins on guild open (e.g. 1004 plain vs 1003 combo). Smoke: test:guild-plain-beats-combo-bucket.

v0.8.150: Among three mention+plain parent buckets, the category with the highest combined score wins on guild open. Smoke: test:guild-triple-combo-bucket-pick.

v0.8.149: Equal mention+plain parent-bucket totals tie-break to the bucket whose unread channels have the lower minimum position. Smoke: test:guild-combo-bucket-minpos-tie.

v0.8.148: A mention+plain category bucket beats a plain-only bucket when both have the same plain-unread count (mention adds 1000 to bucket total). Smoke: test:guild-combo-beats-plain-equal.

v0.8.147: Between two categories each with mention+plain unread, the parent bucket with the higher combined score wins. Smoke: test:guild-dual-combo-bucket-pick.

v0.8.146: A category bucket with one mention plus plain unread (score 1001 + n) beats a higher plain-only bucket in another category. Smoke: test:guild-mention-plain-bucket-pick.

v0.8.145: A root (uncategorized) bucket whose plain-unread total exceeds 1000 beats two mention-weighted category buckets. Smoke: test:guild-root-plain-triple-mention-pick.

v0.8.144: Among three parent buckets, a mention-weighted bucket (score 1001+) beats two higher plain-unread buckets. Smoke: test:guild-mention-triple-bucket-pick.

v0.8.143: Three parent buckets with equal unread totals pick the bucket with the lowest minPos. Smoke: test:guild-bucket-minpos-triple-pick.

v0.8.142: When two parent buckets share equal unread totals and equal minPos, the first bucket encountered in channel scan order wins. Smoke: test:guild-bucket-minpos-order-pick.

v0.8.141: Equal parent-bucket unread totals across root and categories tie-break to the bucket with the lower minimum channel position. Smoke: test:guild-bucket-minpos-root-pick.

v0.8.140: removeSearchRecent(query) drops a guild-scoped recent search from searchRecentByGuild. A mention in the root bucket beats higher plain unread in a category. Smokes: test:search-recent-remove, test:guild-root-mention-bucket-pick.

v0.8.139: A mention-weighted category bucket beats higher plain unread in the root (uncategorized) bucket. Smoke: test:guild-mention-root-bucket-pick.

v0.8.138: With unread in both root and category buckets, parent-bucket totals decide the pool (highest score wins). Smoke: test:guild-mixed-bucket-pick.

v0.8.137: When unread exists in only one category among several, selection stays inside that category pool. Smoke: test:guild-dual-category-isolation-pick.

v0.8.136: In a single-category unread pool, mention-weighted score (mentions × 1000 + unread) beats a lower-position channel with equal plain unread. Smoke: test:guild-mention-single-category-pick.

v0.8.135: When all unread channels share one parentId, _selectGuildChannelWithUnread limits the pool to that category before position/score tie-breaks. Smoke: test:guild-single-category-pool.

v0.8.134: Uncategorized (parentId empty) and category buckets compete by total unread score; uncategorized totals can beat a lower-total category. Smoke: test:guild-uncategorized-bucket-pick.

v0.8.133: Parent-bucket selection prefers the highest total unread score over a bucket with a lower minPos but fewer unreads. Smoke: test:guild-bucket-total-over-minpos.

v0.8.132: Within one category, a channel with a mention alert beats another with the same plain unread count (mentions × 1000 + unread). Smoke: test:guild-mention-in-bucket-pick.

v0.8.131: Within a single parent bucket, equal unread/mention scores pick the channel with the lower sibling position. Smoke: test:guild-in-bucket-position-tie.

v0.8.130: Equal parent-bucket unread totals break ties by lower minimum channel position among unread rows in that bucket (sibling index within the parent). Smoke: test:guild-bucket-minpos-tie.

v0.8.126: Parent bucket totals use mention-weighted scores (mentions × 1000 + unread), so a mention category beats higher plain unread elsewhere. Smoke: test:guild-mention-bucket-pick.

v0.8.125: _selectGuildChannelWithUnread picks the parent bucket (category or uncategorized) with the highest total unread score, then best channel within it. Smokes: test:guild-category-bucket-pick, test:guild-category-unread-pick.

v0.8.124: _unreadForChannel filters rows by channelId after HyperDB find. When all unread are in one category, _selectGuildChannelWithUnread picks only within that parentId. Smoke: test:guild-category-unread-pick.

v0.8.123: Equal unread/mention scores tie-break to lower channel.position. Smoke: test:guild-unread-position-tie.

v0.8.120: _selectGuildChannelWithUnread scores mentions × 1000 + unread; mention channel beats higher plain unread. Smoke: test:guild-mention-channel-pick.

v0.8.119: _selectGuildChannelWithUnread order: highest unread/mention score → lastChannelByGuild → first text. Smokes: test:guild-unread-over-last-channel, test:guild-unread-channel-jump.

v0.8.116: selectChannel persists savable channel types via _persistLastGuildChannel. Smoke: npm run test:guild-last-channel-prefs.

v0.8.237: View exposes sessionReady, guildLoading, guildLoadingGuildId, sessionError. Emits user-prefs and guild-loading for UI pushState. openHome() cancels in-flight loadGuild.

| platform → UI | state, message, channel, notification, session-ready, user-prefs, guild-loading, user |

See IPC.md for the full message table. UI should not import guild/message modules directly in production builds.

Tests

Most apps/pearcord/scripts/smoke-*.cjs scripts construct PearcordPlatform with a temp storagePath. Runner: npm run test:smoke / smoke-runner.cjs.

Representative targets:

  • Guild/invite: test:guild-sync, test:invite, test:storage-path
  • Mesh RPC: smoke-voice-speaking-mesh.cjs, smoke-guild-sync.cjs
  • HyperDB: test:hyperdb (db only, but platform uses same path layout)

Code example

const path = require('bare-path')
const os = require('bare-os')
const { PearcordPlatform } = require('pearcord-platform')

const storagePath = path.join(os.tmpdir(), `pearcord-demo-${Date.now()}`)
const platform = new PearcordPlatform({ storagePath })

await platform.ready()
await platform.register({ username: 'demo', displayName: 'Demo' })

const { guild } = await platform.createGuild({ name: 'Test Server' })
await platform.sendMessage('Hello from the facade')

const view = platform.getViewState?.() ?? { mode: platform.mode, guildId: guild.id }
console.log(view)

await platform.close?.()

Minimal sidecar-style usage:

platform.on('message', (msg) => { /* push to UI */ })
platform.on('session-ready', () => { /* enable guild list */ })
platform.on('user-prefs', () => pushState()) // theme/density mesh sync (v0.8.237)
platform.on('guild-loading', () => pushState()) // guild switch overlay

View fields sessionReady, guildLoading, guildLoadingGuildId, sessionError (v0.8.237). UI must not show the main shell until sessionReady is true.

v0.8.174: updateGuildSettings({ name, iconHash, nsfwGateEnabled }) persists server-wide age-restricted gate toggle on guild record. View exposes guild.nsfwGateEnabled.

Repository

Part of Pearcord.

  • Org: pearcord
  • Clone: git clone https://git.ssh.surf/pearcord/pearcord-platform.git
  • Install: npm install git+https://git.ssh.surf/pearcord/pearcord-platform.git#main

Depends on the full Pearcord module workspace (see package.json); install from monorepo modules/ for local development.

S
Description
Pearcord module: pearcord-platform
Readme
105 MiB
Languages
JavaScript 100%