Phase 434: home-mode mention ingest and notification error logging (v0.8.397).
Persist guild inbound handler as ingestInboundGuildMessage for home view, resolve mentions from DB members when guild mesh is detached, and add structured error logs for mark-all, open notification, and mark-channel-read. Co-authored-by: Cursor <[email protected]>
This commit is contained in:
@@ -135,6 +135,8 @@ Primary consumer: `apps/pearcord/index.js` sidecar reading pear-pipe JSON.
|
||||
|
||||
**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.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`.
|
||||
|
||||
@@ -880,6 +880,12 @@ class PearcordPlatform extends EventEmitter {
|
||||
return { mode: 'home' }
|
||||
}
|
||||
|
||||
/** Ingest a guild message from mesh gossip (works while on home after join). */
|
||||
async ingestInboundGuildMessage (msg) {
|
||||
if (!this._ingestInboundGuildMessage) throw new Error('guild message handler unavailable')
|
||||
return this._ingestInboundGuildMessage(msg)
|
||||
}
|
||||
|
||||
async _initDmSession () {
|
||||
const user = this.identity.user
|
||||
if (!user) throw new Error('register first')
|
||||
@@ -2909,7 +2915,7 @@ class PearcordPlatform extends EventEmitter {
|
||||
}
|
||||
|
||||
_wireGuild (guildInstance) {
|
||||
guildInstance.setMessageHandler(async (msg) => {
|
||||
this._ingestInboundGuildMessage = async (msg) => {
|
||||
const row = enrichMessageRow(msg)
|
||||
const existing = await this.db.get(COLLECTIONS.MESSAGES, {
|
||||
channelId: row.channelId,
|
||||
@@ -2920,14 +2926,15 @@ class PearcordPlatform extends EventEmitter {
|
||||
await this._onInboundMessage(row)
|
||||
this._queueLinkEmbed(row).catch(() => {})
|
||||
const ch = await this.db.get(COLLECTIONS.CHANNELS, {
|
||||
guildId: this.guild?.guild?.id,
|
||||
guildId: row.guildId || this.guild?.guild?.id,
|
||||
id: row.channelId
|
||||
})
|
||||
if (ch) this._indexMessageForSearch(row, ch)
|
||||
this._fanoutBotEvent(BOT_EVENTS.MESSAGE_CREATE, { message: row })
|
||||
this.emit('message', row)
|
||||
return row
|
||||
})
|
||||
}
|
||||
guildInstance.setMessageHandler(this._ingestInboundGuildMessage)
|
||||
guildInstance.on('message', (msg) => this.emit('message', msg))
|
||||
guildInstance.on('message-delete', (p) => this.emit('message-delete', p))
|
||||
guildInstance.on('presence', (payload) => {
|
||||
@@ -3340,7 +3347,9 @@ class PearcordPlatform extends EventEmitter {
|
||||
async _onInboundMessage (msg) {
|
||||
const user = this.identity.user
|
||||
if (!user || msg.authorId === user.id || !msg.guildId) return
|
||||
const members = this.guild ? await this.guild.listMembers() : []
|
||||
const members = this.guild
|
||||
? await this.guild.listMembers()
|
||||
: await this.db.find(COLLECTIONS.MEMBERS, { guildId: msg.guildId })
|
||||
const usersById = await this._usersById(members)
|
||||
const plain = this._messagePlaintext(msg)
|
||||
const mentioned = resolveMentionedUserIds(plain, members, usersById)
|
||||
@@ -3520,7 +3529,18 @@ class PearcordPlatform extends EventEmitter {
|
||||
|
||||
async markAllNotificationsRead () {
|
||||
if (!this.notifications) return 0
|
||||
return this.notifications.markAllRead()
|
||||
const span = this.log.time('notification.markAll')
|
||||
try {
|
||||
const count = await this.notifications.markAllRead()
|
||||
span.end({ count })
|
||||
return count
|
||||
} catch (err) {
|
||||
this.log.error('notification.markAll error', {
|
||||
err: err?.message || String(err)
|
||||
})
|
||||
span.fail(err)
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
async listAuditLog (limit = 50, opts = {}) {
|
||||
@@ -6465,16 +6485,39 @@ class PearcordPlatform extends EventEmitter {
|
||||
}
|
||||
|
||||
async openNotificationTarget ({ guildId, channelId, messageId } = {}) {
|
||||
const span = this.log.time('notification.open', {
|
||||
guildId: guildId || null,
|
||||
channelId: channelId || null,
|
||||
messageId: messageId || null
|
||||
})
|
||||
try {
|
||||
if (guildId && this.guild?.guild?.id !== guildId) {
|
||||
await this.loadGuild(guildId)
|
||||
}
|
||||
if (channelId && this.activeChannelId !== channelId) {
|
||||
await this.selectChannel(channelId)
|
||||
}
|
||||
let result
|
||||
if (messageId) {
|
||||
return this.jumpToMessage(messageId)
|
||||
result = await this.jumpToMessage(messageId)
|
||||
} else {
|
||||
result = { found: !!channelId, channelId: channelId || this.activeChannelId }
|
||||
}
|
||||
span.end({
|
||||
found: !!result?.found,
|
||||
channelId: result?.channelId || channelId || this.activeChannelId
|
||||
})
|
||||
return result
|
||||
} catch (err) {
|
||||
this.log.error('notification.open error', {
|
||||
guildId: guildId || null,
|
||||
channelId: channelId || null,
|
||||
messageId: messageId || null,
|
||||
err: err?.message || String(err)
|
||||
})
|
||||
span.fail(err)
|
||||
throw err
|
||||
}
|
||||
return { found: !!channelId, channelId: channelId || this.activeChannelId }
|
||||
}
|
||||
|
||||
formatGuildDeepLink (opts = {}) {
|
||||
@@ -6956,6 +6999,7 @@ class PearcordPlatform extends EventEmitter {
|
||||
async markChannelRead (channelId, guildId) {
|
||||
const user = this.identity.user
|
||||
if (!user || !channelId || !guildId) return
|
||||
try {
|
||||
const at = Date.now()
|
||||
await this.db.insert(COLLECTIONS.READ_STATE, {
|
||||
userId: user.id,
|
||||
@@ -6980,6 +7024,14 @@ class PearcordPlatform extends EventEmitter {
|
||||
if (this.notifications) {
|
||||
await this.notifications.clearForChannel(guildId, channelId)
|
||||
}
|
||||
} catch (err) {
|
||||
this.log.error('inbox.mark-read error', {
|
||||
channelId,
|
||||
guildId,
|
||||
err: err?.message || String(err)
|
||||
})
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
async _unreadForChannel (channelId, guildId) {
|
||||
|
||||
Reference in New Issue
Block a user