feat(platform): Phase 105 mesh peer indicator and digest export schedule

- listAuditArchiveFetchPeers returns meshConnected per member
- automationDigestExportSchedule timer and snapshot persistence
- GUILD_SYNC slices for schedule and snapshot metadata
- runOverdueAutomationSchedules includes digest export task

Co-authored-by: Cursor <[email protected]>
This commit is contained in:
Raven Scott
2026-05-22 05:23:36 -04:00
co-authored by Cursor
parent 2eb9ece6f0
commit 7adf714b8a
+104 -6
View File
@@ -1167,12 +1167,18 @@ class PearcordPlatform extends EventEmitter {
const auditRecent = await this._exportAuditSyncSlice(guild.id)
let auditExportSchedule = null
let digestExportSchedule = null
let automationDigestExportSchedule = null
let automationDigestExportSnapshots = []
let auditExportArchives = []
let hookFailureDigest = null
await this._initDeliveryReceipts(guild.id)
if (this.deliveryReceipts) {
auditExportSchedule = await this.deliveryReceipts.exportAuditExportScheduleSlice()
digestExportSchedule = await this.deliveryReceipts.exportDigestExportScheduleSlice()
automationDigestExportSchedule =
await this.deliveryReceipts.exportAutomationDigestExportScheduleSlice()
automationDigestExportSnapshots =
await this.deliveryReceipts.exportAutomationDigestExportSnapshotsSlice(2)
auditExportArchives = await this.deliveryReceipts.exportAuditExportArchivesSlice(3)
const digestSnap = await this.deliveryReceipts.getHookFailureDigestSnapshot()
if (digestSnap) {
@@ -1232,6 +1238,8 @@ class PearcordPlatform extends EventEmitter {
auditRecent,
auditExportSchedule,
digestExportSchedule,
automationDigestExportSchedule,
automationDigestExportSnapshots,
auditExportArchives,
hookFailureDigest,
workerReleaseHint,
@@ -1342,6 +1350,13 @@ class PearcordPlatform extends EventEmitter {
payload.digestExportSchedule
)
}
if (payload.automationDigestExportSchedule) {
await this._initDeliveryReceipts(payload.guildId)
await this.deliveryReceipts.ingestAutomationDigestExportScheduleSlice(
payload.guildId,
payload.automationDigestExportSchedule
)
}
for (const archive of payload.auditExportArchives || []) {
if (!archive?.id || archive.guildId !== payload.guildId) continue
await this._initDeliveryReceipts(payload.guildId)
@@ -2057,8 +2072,9 @@ class PearcordPlatform extends EventEmitter {
}
async listAuditArchiveFetchPeers () {
if (!this.guild?.guild) return { meshPeerCount: 0, options: [] }
if (!this.guild?.guild) return { meshPeerCount: 0, meshLive: false, options: [] }
const meshPeerCount = this.guild.getStats?.()?.peers || 0
const meshLive = meshPeerCount > 0
const selfId = this.identity.user?.id || null
const presenceSnap = this.presence?.snapshot?.() || { peers: [] }
const onlineIds = new Set(
@@ -2068,8 +2084,11 @@ class PearcordPlatform extends EventEmitter {
const options = [
{
memberId: null,
label: meshPeerCount > 0 ? `Any connected peer (${meshPeerCount} on mesh)` : 'Any peer (mesh offline)',
online: meshPeerCount > 0,
label: meshLive
? `Any connected peer (${meshPeerCount} on mesh)`
: 'Any peer (mesh offline)',
online: meshLive,
meshConnected: meshLive,
isSelf: false
}
]
@@ -2079,15 +2098,17 @@ class PearcordPlatform extends EventEmitter {
if (!userId) continue
const user = await this.db.get(COLLECTIONS.USERS, { id: userId }).catch(() => null)
const name = user?.displayName || user?.username || userId.slice(0, 8)
const online = onlineIds.has(userId) || meshPeerCount > 0
const presenceOnline = onlineIds.has(userId)
const meshConnected = meshLive && presenceOnline
options.push({
memberId: userId,
label: userId === selfId ? `${name} (you)` : name,
online,
online: presenceOnline || (userId === selfId && meshLive),
meshConnected,
isSelf: userId === selfId
})
}
return { meshPeerCount, options }
return { meshPeerCount, meshLive, options }
}
_resolveAuditArchiveFetchWaiter (archive) {
@@ -2348,11 +2369,17 @@ class PearcordPlatform extends EventEmitter {
digestResult = await this.runScheduledDigestExportNow()
if (digestResult) ran.push('digest-sync')
}
let automationDigestResult = null
if (before.automationDigestExport?.overdue) {
automationDigestResult = await this.runScheduledAutomationDigestExportNow()
if (automationDigestResult) ran.push('automation-digest-export')
}
const dashboard = await this.getAutomationScheduleDashboard()
return {
ran,
auditResult,
digestResult,
automationDigestResult,
dashboard,
guildId: this.guild.guild.id
}
@@ -2364,14 +2391,77 @@ class PearcordPlatform extends EventEmitter {
}
const auditExportSchedule = await this.getAuditExportSchedule()
const digestExportSchedule = await this.getDigestExportSchedule()
const automationDigestExportSchedule = await this.getAutomationDigestExportSchedule()
const hookFailureDigest = await this.getHookFailureDigest()
return buildAutomationScheduleDashboard({
auditExportSchedule,
digestExportSchedule,
automationDigestExportSchedule,
hookFailureDigest
})
}
async getAutomationDigestExportSchedule () {
if (!this.guild?.guild) {
return { enabled: false, intervalHours: 24, format: 'text', lastExportAt: 0 }
}
await this._initDeliveryReceipts(this.guild.guild.id)
return this.deliveryReceipts.getAutomationDigestExportSchedule()
}
async setAutomationDigestExportSchedule (partial = {}) {
if (!this.guild?.guild) throw new Error('no guild')
const roles = await this._memberRoles()
if (!roleHasPermission(roles, PERMISSION.MANAGE_GUILD)) {
throw new Error('no permission to manage automation digest export schedule')
}
await this._initDeliveryReceipts(this.guild.guild.id)
const prefs = await this.deliveryReceipts.setAutomationDigestExportSchedule(partial)
this.emit('automation-digest-export-schedule', prefs)
this._startAuditExportScheduleTimer()
setTimeout(() => this._pushGuildSyncToMesh().catch(() => {}), 400)
return prefs
}
async listAutomationDigestExportSnapshots (limit = 3) {
if (!this.guild?.guild) return []
await this._initDeliveryReceipts(this.guild.guild.id)
return this.deliveryReceipts.listAutomationDigestExportSnapshots(limit)
}
async runScheduledAutomationDigestExportNow () {
return this._runScheduledAutomationDigestExportIfDue(true)
}
async _runScheduledAutomationDigestExportIfDue (force = false) {
if (!this.guild?.guild) return null
const roles = await this._memberRoles()
if (!roleHasPermission(roles, PERMISSION.MANAGE_GUILD)) return null
await this._initDeliveryReceipts(this.guild.guild.id)
const schedule = await this.deliveryReceipts.getAutomationDigestExportSchedule()
if (!schedule.enabled && !force) return null
const intervalMs = (schedule.intervalHours || 24) * 60 * 60 * 1000
const last = schedule.lastExportAt || 0
if (!force && Date.now() - last < intervalMs) return null
const exported = await this.exportAutomationScheduleDigest({
format: schedule.format || 'text'
})
const summaryLines = String(exported.body || '').split('\n').length
const snap = await this.deliveryReceipts.appendAutomationDigestExportSnapshot({
exportedAt: exported.exportedAt,
exportedBy: this.identity.user?.id || null,
format: exported.format,
summaryLines,
body: exported.body
})
await this.deliveryReceipts.setAutomationDigestExportSchedule({
lastExportAt: exported.exportedAt
})
this.emit('automation-digest-export-scheduled', { exported, snap, schedule })
setTimeout(() => this._pushGuildSyncToMesh().catch(() => {}), 400)
return { ...exported, snapshotId: snap?.id || null }
}
async exportHookFailureDigest (opts = {}) {
if (!this.guild?.guild) throw new Error('no guild')
const roles = await this._memberRoles()
@@ -5084,9 +5174,11 @@ class PearcordPlatform extends EventEmitter {
this._auditScheduleTimer = setInterval(() => {
this._runScheduledAuditExportIfDue().catch(() => {})
this._runScheduledDigestExportIfDue().catch(() => {})
this._runScheduledAutomationDigestExportIfDue().catch(() => {})
}, 60 * 1000)
this._runScheduledAuditExportIfDue().catch(() => {})
this._runScheduledDigestExportIfDue().catch(() => {})
this._runScheduledAutomationDigestExportIfDue().catch(() => {})
}
async runScheduledAuditExportNow () {
@@ -6652,6 +6744,8 @@ class PearcordPlatform extends EventEmitter {
let hookFailureDigest = null
let auditExportSchedule = null
let digestExportSchedule = null
let automationDigestExportSchedule = null
let automationDigestExportSnapshots = []
let auditExportArchives = []
let automationScheduleDashboard = null
let auditArchiveFetchPeers = null
@@ -6661,6 +6755,8 @@ class PearcordPlatform extends EventEmitter {
hookFailureDigest = await this.getHookFailureDigest()
auditExportSchedule = await this.getAuditExportSchedule()
digestExportSchedule = await this.getDigestExportSchedule()
automationDigestExportSchedule = await this.getAutomationDigestExportSchedule()
automationDigestExportSnapshots = await this.listAutomationDigestExportSnapshots(3)
auditExportArchives = await this.listAuditExportArchives(6)
automationScheduleDashboard = await this.getAutomationScheduleDashboard()
auditArchiveFetchPeers = await this.listAuditArchiveFetchPeers()
@@ -6835,6 +6931,8 @@ class PearcordPlatform extends EventEmitter {
hookFailureDigest,
auditExportSchedule,
digestExportSchedule,
automationDigestExportSchedule,
automationDigestExportSnapshots,
auditExportArchives,
automationScheduleDashboard,
auditArchiveFetchPeers,