refactor(platform): organize mixins into category directories

Move 136 prototype mixins under mixins/domain, json-export, and
runtime/* so the package root stays navigable. Manifest assign order
is unchanged; apply-platform-mixins and runtime registry paths updated.

Co-authored-by: Cursor <[email protected]>
This commit is contained in:
Raven Scott
2026-06-03 17:42:26 -04:00
co-authored by Cursor
parent 08bdbf4d17
commit a5dba86570
142 changed files with 1111 additions and 393 deletions
+154
View File
@@ -0,0 +1,154 @@
'use strict'
const { isAnnouncementChannel } = require('pearcord-threads')
const announcementsMixin = {
_announcementFollowHealWatermark: null,
_announcementCrosspostHealWatermark: null,
_announcementCrosspostGossipKeys: null,
_announcementFollowGossipKeys: null,
_crosspostRateByGuild: null,
_lastCrosspostPublish: null,
_initAnnouncementMixinState () {
if (!this._announcementCrosspostGossipKeys) {
this._announcementCrosspostGossipKeys = new Set()
}
if (!this._announcementFollowGossipKeys) {
this._announcementFollowGossipKeys = new Set()
}
if (!this._crosspostRateByGuild) {
this._crosspostRateByGuild = new Map()
}
},
_shouldGossipAnnouncementCrosspost (row) {
this._initAnnouncementMixinState()
if (!row?.guildId || !row?.sourceChannelId) return true
const ids = (row.targetChannelIds || []).join(',')
const hash = `${row.guildId}:${row.sourceChannelId}:${ids}:${row.updatedAt || 0}`
if (this._announcementCrosspostGossipKeys.has(hash)) return false
this._announcementCrosspostGossipKeys.add(hash)
if (this._announcementCrosspostGossipKeys.size > 4096) {
const first = this._announcementCrosspostGossipKeys.values().next().value
if (first) this._announcementCrosspostGossipKeys.delete(first)
}
return true
},
_shouldGossipAnnouncementFollow (row) {
this._initAnnouncementMixinState()
if (!row?.guildId || !row?.channelId || !row?.userId) return true
const hash = `${row.guildId}:${row.channelId}:${row.userId}:${row.active ? '1' : '0'}:${row.updatedAt || 0}`
if (this._announcementFollowGossipKeys.has(hash)) return false
this._announcementFollowGossipKeys.add(hash)
if (this._announcementFollowGossipKeys.size > 8192) {
const first = this._announcementFollowGossipKeys.values().next().value
if (first) this._announcementFollowGossipKeys.delete(first)
}
return true
},
_checkCrosspostPublishRateLimit (guildId) {
this._initAnnouncementMixinState()
const gid = guildId || this.guild?.guild?.id
if (!gid) return true
const cap = 12
const windowMs = 60_000
const now = Date.now()
let bucket = this._crosspostRateByGuild.get(gid)
if (!bucket || now >= bucket.resetAt) {
bucket = { count: 0, resetAt: now + windowMs }
}
if (bucket.count >= cap) return false
bucket.count++
this._crosspostRateByGuild.set(gid, bucket)
return true
},
async _healAnnouncementCrosspostOnPartition (guildId) {
const gid = guildId || this.guild?.guild?.id || null
const span = this.log.time('announcement.heal', {
spanKind: 'announcement.heal',
guildId: gid,
slice: 'crosspost'
})
try {
if (!gid || !this.guild?.listChannels || !this.announcements) {
span.end({ relisted: 0, skipped: true })
return { relisted: 0, skipped: true }
}
const channels = await this.guild.listChannels().catch(() => [])
let relisted = 0
for (const ch of channels) {
if (!isAnnouncementChannel(ch) || ch.guildId && ch.guildId !== gid) continue
const targets = await this.announcements.getCrosspostTargets(gid, ch.id)
const row = {
guildId: gid,
sourceChannelId: ch.id,
targetChannelIds: targets,
updatedAt: Date.now()
}
if (this._shouldGossipAnnouncementCrosspost(row) && this.guild?.gossipAnnouncementCrosspost) {
this.guild.gossipAnnouncementCrosspost(row)
relisted++
}
}
const watermark = Date.now()
this._announcementCrosspostHealWatermark = watermark
span.end({ relisted, watermark })
return { relisted, watermark }
} catch (err) {
this.log.error('announcement.heal error', {
guildId: gid,
slice: 'crosspost',
error: err?.message || String(err)
})
span.fail(err)
return { relisted: 0, error: err?.message || String(err) }
}
},
async _healAnnouncementFollowsOnPartition (guildId) {
const gid = guildId || this.guild?.guild?.id || null
const span = this.log.time('announcement.heal', {
spanKind: 'announcement.heal',
guildId: gid,
slice: 'follow'
})
try {
if (!gid || !this.announcements?.store) {
span.end({ relisted: 0, skipped: true })
return { relisted: 0, skipped: true }
}
const userId = this.identity?.user?.id
if (!userId) {
span.end({ relisted: 0, skipped: true })
return { relisted: 0, skipped: true }
}
const follows = await this.announcements.listMyFollows(userId, gid)
let relisted = 0
for (const row of follows) {
if (row.guildId !== gid) continue
if (this._shouldGossipAnnouncementFollow(row) && this.guild?.gossipAnnouncementFollow) {
this.guild.gossipAnnouncementFollow(row)
relisted++
}
}
const watermark = Date.now()
this._announcementFollowHealWatermark = watermark
span.end({ relisted, watermark, followCount: follows.length })
return { relisted, watermark, followCount: follows.length }
} catch (err) {
this.log.error('announcement.heal error', {
guildId: gid,
slice: 'follow',
error: err?.message || String(err)
})
span.fail(err)
return { relisted: 0, error: err?.message || String(err) }
}
}
}
module.exports = { announcementsMixin }