feat(attachments): staged list, meta sync, and send-time UI fields

Expose stagedAttachments in view, reorder/updateMeta APIs, and apply
attachmentUiById caption/spoiler on send (Phase 662).

Co-authored-by: Cursor <[email protected]>
This commit is contained in:
Raven Scott
2026-06-02 15:49:49 -04:00
co-authored by Cursor
parent dad7d3badb
commit c3caa74566
+71
View File
@@ -11881,6 +11881,57 @@ class PearcordPlatform extends EventEmitter {
}
}
async listStagedAttachmentsForChannel (channelId = this.activeChannelId) {
if (!this.attachments || !channelId) return []
return this.attachments.listStagedForChannel(channelId)
}
async updateStagedAttachmentMeta (attachmentId, patch = {}) {
if (!this.attachments) throw new Error('attachments not ready')
const row = await this.attachments.updateMeta(attachmentId, patch)
if (this.activeChannelId && this.userSettings) {
const prefs = await this.userSettings.getPrefs()
const stagedAttachmentUi = { ...(prefs.stagedAttachmentUi || {}) }
const ch = this.activeChannelId
const prev = stagedAttachmentUi[ch] || { order: [], meta: {} }
const meta = { ...(prev.meta || {}) }
const id = String(attachmentId)
meta[id] = {
caption: row.caption ?? meta[id]?.caption ?? '',
spoiler: !!row.spoiler,
stagingOrder: row.stagingOrder ?? meta[id]?.stagingOrder ?? 0
}
stagedAttachmentUi[ch] = {
order: prev.order?.includes(id) ? prev.order : [...(prev.order || []), id],
meta,
updatedAt: now()
}
await this.userSettings.setPrefs({ stagedAttachmentUi }, { localNotify: false })
}
return row
}
async reorderStagedAttachments (orderedIds = []) {
if (!this.attachments) throw new Error('attachments not ready')
const ids = Array.isArray(orderedIds) ? orderedIds.filter(Boolean) : []
for (let i = 0; i < ids.length; i++) {
await this.attachments.updateMeta(ids[i], { stagingOrder: i })
}
if (this.activeChannelId && this.userSettings && ids.length) {
const prefs = await this.userSettings.getPrefs()
const stagedAttachmentUi = { ...(prefs.stagedAttachmentUi || {}) }
const ch = this.activeChannelId
const prev = stagedAttachmentUi[ch] || { meta: {} }
stagedAttachmentUi[ch] = {
order: ids.slice(),
meta: prev.meta || {},
updatedAt: now()
}
await this.userSettings.setPrefs({ stagedAttachmentUi }, { localNotify: false })
}
return { order: ids }
}
_voiceNoteGate (channel = null) {
const active =
channel ||
@@ -18765,6 +18816,17 @@ class PearcordPlatform extends EventEmitter {
const stickerNames = await this._normalizeStickerNames(opts.stickerNames)
if (String(content || '').trim()) await this._assertAutomod(content)
const attachmentIds = opts.attachmentIds || []
if (this.attachments && opts.attachmentUiById) {
for (const [aid, meta] of Object.entries(opts.attachmentUiById)) {
if (!attachmentIds.includes(aid)) continue
await this.attachments
.updateMeta(aid, {
caption: meta?.caption ?? '',
spoiler: !!meta?.spoiler
})
.catch(() => null)
}
}
let outbound = content
if (this.mode === 'dm' && dmEncryptionAvailable() && this._dmSealChannelId()) {
outbound = sealDmContent(content, this._dmSealChannelId())
@@ -22275,6 +22337,12 @@ class PearcordPlatform extends EventEmitter {
}
}
}
let stagedAttachments = []
if (this.attachments && this.activeChannelId) {
stagedAttachments = await this.listStagedAttachmentsForChannel(
this.activeChannelId
).catch(() => [])
}
let unreadConsistencyAudit = { ok: true, skipped: true, checked: 0, mismatches: [] }
const unreadAuditIntervalMs = Math.max(
30_000,
@@ -22371,6 +22439,9 @@ class PearcordPlatform extends EventEmitter {
memberTimeouts,
guildBans,
communicationDisabled,
stagedAttachments,
stagedAttachmentUi:
userPrefs?.stagedAttachmentUi?.[this.activeChannelId] || null,
voiceNoteDraft,
voiceStatesByChannel,
stageRolesByChannel,