feat(platform): Phase 125 settings mesh, search, drafts, and folders
- Join settings mesh with per-device swarm keys and unified connection wiring - clearGuildSearchIndex, searchGuildMessages indexOnly / localIndexOnly mesh leg - setComposeDraft, reorderServerFolders, view composeDrafts + activeComposeDraft Co-authored-by: Cursor <[email protected]>
This commit is contained in:
@@ -175,6 +175,7 @@ const {
|
||||
assignGuildToFolder: assignGuildToFolderState,
|
||||
setFolderCollapsed: setFolderCollapsedState,
|
||||
renameFolder: renameServerFolderState,
|
||||
reorderFolders: reorderServerFoldersState,
|
||||
FOLDER_COLORS
|
||||
} = require('pearcord-server-folders')
|
||||
const {
|
||||
@@ -302,6 +303,7 @@ class PearcordPlatform extends EventEmitter {
|
||||
this._discoverySwarm = null
|
||||
this._contactsSwarm = null
|
||||
this._settingsSwarm = null
|
||||
this._settingsMeshWired = false
|
||||
this._devicePairSwarm = null
|
||||
this._discoveryWired = false
|
||||
this._archivePeerHealthRefreshedAt = null
|
||||
@@ -507,10 +509,39 @@ class PearcordPlatform extends EventEmitter {
|
||||
async _joinSettingsMesh () {
|
||||
if (!this.onboarded || !this.identity?.keyPair || !this.identity?.user) return
|
||||
const Hyperswarm = require('hyperswarm')
|
||||
const b4a = require('b4a')
|
||||
await this.identity.ensureDeviceSwarmKeyPair()
|
||||
if (!this._settingsSwarm) {
|
||||
this._settingsSwarm = new Hyperswarm({ keyPair: this.identity.keyPair })
|
||||
this._settingsSwarm = new Hyperswarm({
|
||||
keyPair: this.identity.getDeviceSwarmKeyPair()
|
||||
})
|
||||
}
|
||||
const meshOpts = { deviceId: this.identity.deviceId }
|
||||
if (!this._settingsMeshWired) {
|
||||
this._settingsMeshWired = true
|
||||
const { attachSettingsMesh } = require('pearcord-notifications/mesh')
|
||||
const { attachUserPrefsMesh } = require('pearcord-settings/mesh')
|
||||
const { attachProfileCosmeticsMesh } = require('pearcord-profile-cosmetics/mesh')
|
||||
this._settingsSwarm.on('connection', (conn) => {
|
||||
const peerId = b4a.toString(conn.remotePublicKey, 'hex')
|
||||
const wire = (mod, attach) => {
|
||||
if (!mod) return
|
||||
const ch = attach(mod, conn)
|
||||
mod._channels.set(peerId, ch)
|
||||
mod.emit('peer', { peerId, type: 'join' })
|
||||
}
|
||||
wire(this.notifications, attachSettingsMesh)
|
||||
wire(this.userSettings, attachUserPrefsMesh)
|
||||
wire(this.profileCosmetics, attachProfileCosmeticsMesh)
|
||||
conn.on('close', () => {
|
||||
for (const mod of [this.notifications, this.userSettings, this.profileCosmetics]) {
|
||||
if (!mod) continue
|
||||
mod._channels.delete(peerId)
|
||||
mod.emit('peer', { peerId, type: 'leave' })
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
const meshOpts = { deviceId: this.identity.deviceId, manageListeners: false }
|
||||
if (this.notifications) {
|
||||
await this.notifications.joinMesh(this._settingsSwarm, meshOpts)
|
||||
}
|
||||
@@ -1145,6 +1176,15 @@ class PearcordPlatform extends EventEmitter {
|
||||
return idx
|
||||
}
|
||||
|
||||
clearGuildSearchIndex (guildId) {
|
||||
const id = guildId || this.guild?.guild?.id
|
||||
if (!id) return false
|
||||
const idx = new GuildSearchIndex()
|
||||
this._guildSearchIndexes.set(id, idx)
|
||||
this._getSearchIndexStore().save(id, idx)
|
||||
return true
|
||||
}
|
||||
|
||||
async rebuildGuildSearchIndex (guildId) {
|
||||
const idx = new GuildSearchIndex()
|
||||
const channels = await this.db.find(COLLECTIONS.CHANNELS, { guildId })
|
||||
@@ -1204,6 +1244,7 @@ class PearcordPlatform extends EventEmitter {
|
||||
if (indexed.length) {
|
||||
return indexed.map((m) => enrichMessageRow({ ...m, channelName: m.channelName }))
|
||||
}
|
||||
if (opts.indexOnly) return []
|
||||
const channels = await this.db.find(COLLECTIONS.CHANNELS, { guildId })
|
||||
const channelById = new Map(channels.map((c) => [c.id, c]))
|
||||
const searchable = new Set(
|
||||
@@ -1259,7 +1300,10 @@ class PearcordPlatform extends EventEmitter {
|
||||
}
|
||||
|
||||
async searchGuildMessagesWithMesh (guildId, query, opts = {}) {
|
||||
const local = await this.searchGuildMessages(guildId, query, opts)
|
||||
const local = await this.searchGuildMessages(guildId, query, {
|
||||
limit: opts.limit,
|
||||
indexOnly: !!opts.localIndexOnly
|
||||
})
|
||||
if (opts.mesh === false || !this.guild?.guild) {
|
||||
return { hits: local, mesh: false, meshHitCount: 0, localHitCount: local.length }
|
||||
}
|
||||
@@ -2355,6 +2399,31 @@ class PearcordPlatform extends EventEmitter {
|
||||
return true
|
||||
}
|
||||
|
||||
async reorderServerFolders (folderIds = []) {
|
||||
const state = await this.getServerFolders()
|
||||
await this._saveServerFolders(reorderServerFoldersState(state, folderIds))
|
||||
return true
|
||||
}
|
||||
|
||||
async setComposeDraft (channelId, text) {
|
||||
if (!channelId) throw new Error('channelId required')
|
||||
const prefs = this.userSettings ? await this.userSettings.getPrefs() : {}
|
||||
const composeDrafts = { ...(prefs.composeDrafts || {}) }
|
||||
const trimmed = String(text || '').slice(0, 4000)
|
||||
if (!trimmed) {
|
||||
delete composeDrafts[channelId]
|
||||
} else {
|
||||
composeDrafts[channelId] = { text: trimmed, updatedAt: now() }
|
||||
}
|
||||
return this.updateUserPrefs({ composeDrafts })
|
||||
}
|
||||
|
||||
async getComposeDraftText (channelId) {
|
||||
if (!channelId || !this.userSettings) return ''
|
||||
const prefs = await this.userSettings.getPrefs()
|
||||
return prefs.composeDrafts?.[channelId]?.text || ''
|
||||
}
|
||||
|
||||
async markAllNotificationsRead () {
|
||||
if (!this.notifications) return 0
|
||||
return this.notifications.markAllRead()
|
||||
@@ -8714,6 +8783,10 @@ class PearcordPlatform extends EventEmitter {
|
||||
? this.getGuildSearchIndexMeta(this.guild.guild.id)
|
||||
: { persisted: false, rowCount: 0, savedAt: null },
|
||||
searchIncludeMesh: this._searchIncludeMesh,
|
||||
composeDrafts: userPrefs?.composeDrafts || {},
|
||||
activeComposeDraft: this.activeChannelId
|
||||
? (userPrefs?.composeDrafts?.[this.activeChannelId]?.text || '')
|
||||
: '',
|
||||
companionMode: this._companionMode,
|
||||
readOnly: this._readOnly,
|
||||
contacts: contactsForView,
|
||||
@@ -8856,6 +8929,7 @@ class PearcordPlatform extends EventEmitter {
|
||||
if (this._settingsSwarm) {
|
||||
await this._settingsSwarm.destroy().catch(() => {})
|
||||
this._settingsSwarm = null
|
||||
this._settingsMeshWired = false
|
||||
}
|
||||
if (this._discoverySwarm) {
|
||||
await this._discoverySwarm.destroy().catch(() => {})
|
||||
|
||||
Reference in New Issue
Block a user