refactor(platform): Phase 751 guild search query & mesh resolve mixins (v0.8.727)

Extract searchGuildMessages, getGuildSearchIndexMeta, _applySearchQueryFilters,
and searchGuildMessagesWithMesh into three prototype mixins (manifest 98 rows,
runtime registry 38). Non-breaking: identical local/mesh search, structured filter
matching, and index meta reporting; platform class ~31874 lines (~127 net drop).

Co-authored-by: Cursor <[email protected]>
This commit is contained in:
Raven Scott
2026-06-03 11:50:29 -04:00
co-authored by Cursor
parent 02a879fed3
commit 713658b6bc
7 changed files with 174 additions and 134 deletions
+2
View File
@@ -54,6 +54,8 @@ Application facade: one `PearcordPlatform` class that wires identity, database,
**Phase 723 (v0.8.699):** Dedicated slash registry & invoke audit export JSON — `slash-registry-json-mixin.js`, `slash-invoke-audit-json-mixin.js`, spans `slash-registry.json` / `slash-invoke-audit.json`, `getSlashInvokeAuditExportJsonExport`, `clearSlashInvokeAuditExportJsonExports`, deep links `openSlashRegistryJson` / `openSlashInvokeAuditJson`. Bundle: `npm run test:ci-phase723`.
**Phase 751 (v0.8.727):** `platform-search-guild-messages-mixin.js`, `platform-search-query-filters-mixin.js`, `platform-search-mesh-resolve-mixin.js` (98 mixin rows, 38 runtime mixins); guild message search, structured query filters, index meta, mesh hit merge. Bundle: `npm run test:ci-phase751`.
**Phase 750 (v0.8.726):** `platform-search-index-store-mixin.js`, `platform-search-index-rebuild-mixin.js`, `platform-search-mesh-gossip-mixin.js`, `platform-discovery-mesh-refresh-mixin.js` (95 mixin rows, 35 runtime mixins); guild search index store/persist/rebuild, mesh search gossip, discovery listing refresh after mesh. Bundle: `npm run test:ci-phase750`.
**Phase 749 (v0.8.725):** `platform-view-list-cache-mixin.js`, `platform-search-cache-mixin.js`, `platform-discovery-prefs-baseline-mixin.js` (91 mixin rows, 31 runtime mixins); reaction/pin cache invalidation, search resolve cache, discovery explore baseline from prefs. Bundle: `npm run test:ci-phase749`.
+4 -1
View File
@@ -4,7 +4,7 @@
* Ordered PearcordPlatform prototype mixin registration (Phase 730).
* Preserves assign order from index.js / apply-platform-mixins (Phase 727).
*/
const PLATFORM_MIXIN_ASSIGNMENT_COUNT = 95
const PLATFORM_MIXIN_ASSIGNMENT_COUNT = 98
const PLATFORM_MIXIN_ASSIGNMENTS = [
{ module: './polls-scheduling', export: 'pollSchedulingMixin' },
@@ -101,6 +101,9 @@ const PLATFORM_MIXIN_ASSIGNMENTS = [
{ module: './platform-search-index-rebuild-mixin', export: 'platformSearchIndexRebuildMixin' },
{ module: './platform-search-mesh-gossip-mixin', export: 'platformSearchMeshGossipMixin' },
{ module: './platform-discovery-mesh-refresh-mixin', export: 'platformDiscoveryMeshRefreshMixin' },
{ module: './platform-search-guild-messages-mixin', export: 'platformSearchGuildMessagesMixin' },
{ module: './platform-search-query-filters-mixin', export: 'platformSearchQueryFiltersMixin' },
{ module: './platform-search-mesh-resolve-mixin', export: 'platformSearchMeshResolveMixin' },
{ module: './platform-diagnostics-mixin', export: 'platformDiagnosticsMixin' }
]
+4 -131
View File
@@ -4732,140 +4732,13 @@ class PearcordPlatform extends EventEmitter {
async searchGuildMessages (guildId, query, opts = {}) {
const q = String(query || '').trim().toLowerCase()
if (!q || !guildId) return []
const limit = opts.limit || 50
const idx = await this._ensureGuildSearchIndex(guildId)
const indexed = idx.search(q, { limit })
if (indexed.length) {
return indexed.map((m) => enrichmentScope.enrichMessageRow(m))
}
if (opts.indexOnly) return []
const channels = await this.db.find(sharedScope.COLLECTIONS.CHANNELS, { guildId })
const channelById = new Map(channels.map((c) => [c.id, c]))
const searchable = new Set(
channels
.filter((c) => c.type === 'text' || c.type === 'thread' || c.type === 'announcement')
.map((c) => c.id)
)
let rows = []
if (this.db.getEngine?.() === 'hyperdb') {
for (const chId of searchable) {
const chRows = await this.db.find(sharedScope.COLLECTIONS.MESSAGES, { channelId: chId })
rows.push(...chRows)
}
} else {
rows = await this.db.find(sharedScope.COLLECTIONS.MESSAGES, { guildId })
}
const seen = new Set()
const hits = rows
.filter((m) => {
if (!m?.id || seen.has(m.id)) return false
seen.add(m.id)
const enriched = enrichmentScope.enrichMessageRow(m)
const ch = channelById.get(m.channelId)
const hay = [
ch?.name || '',
String(enriched.content || ''),
enriched.hubMirror ? formatHubMirrorFallback(enriched.hubMirror) : '',
...(enriched.stickerNames || []).map((n) => `:${n}:`),
ch?.archived ? 'archived' : ''
]
.join(' ')
.toLowerCase()
return searchable.has(m.channelId) && hay.includes(q)
})
.slice(0, limit * 2)
const { rankAndEnrichSearchHits } = require('pearcord-search')
const mapped = hits.map((m) => ({
...enrichmentScope.enrichMessageRow(m),
channelName: channelById.get(m.channelId)?.name || m.channelId.slice(0, 8)
}))
return rankAndEnrichSearchHits(mapped, q, { limit })
}
async _applySearchQueryFilters (hits, rawQuery, guildId) {
const {
parseSearchQuery,
messageMatchesSearchFilters,
hasStructuredSearchFilters
} = require('pearcord-search')
const filters = parseSearchQuery(rawQuery)
if (!hasStructuredSearchFilters(filters)) return hits
const gId = guildId || this.guild?.guild?.id
const members = this.guild
? await this.guild.listMembers()
: gId
? await this.db.find(sharedScope.COLLECTIONS.MEMBERS, { guildId: gId })
: []
const usersById = await this._usersById(members)
const channels = gId ? await this.db.find(sharedScope.COLLECTIONS.CHANNELS, { guildId: gId }) : []
const channelById = new Map(channels.map((c) => [c.id, c]))
let pinnedKeys = null
if (filters.has === 'pin' && gId) {
const pins = await this.db.find(sharedScope.COLLECTIONS.PINS, { guildId: gId })
pinnedKeys = new Set(pins.map((p) => `${p.channelId}:${p.messageId}`))
}
const out = []
for (const hit of hits || []) {
const mem = members.find((m) => m.userId === hit.authorId)
const u = usersById[hit.authorId] || {}
const ch = channelById.get(hit.channelId)
const plain = this._messagePlaintext(hit)
if (
!messageMatchesSearchFilters(hit, filters, {
plaintext: plain,
authorTokens: [mem?.nickname, u.username, u.displayName].filter(Boolean),
authorId: hit.authorId,
channelName: ch?.name || hit.channelName,
isPinned: pinnedKeys ? pinnedKeys.has(`${hit.channelId}:${hit.id}`) : false,
attachmentIds: hit.attachmentIds
})
) {
continue
}
out.push(hit)
}
return out
}
getGuildSearchIndexMeta (guildId) {
const id = guildId || this.guild?.guild?.id
if (!id) return { persisted: false, rowCount: 0, savedAt: null }
const blob = this._getSearchIndexStore().load(id)
const mem = this._guildSearchIndexes.get(id)
return {
persisted: !!(blob?.rows?.length),
savedAt: blob?.savedAt || null,
rowCount: blob?.rows?.length || mem?._rows?.length || 0
}
}
async searchGuildMessagesWithMesh (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 }
}
try {
const meshHits = await this._fetchGuildSearchFromMeshOnce(guildId, query, opts)
const merged = searchScope.mergeSearchHits(local, meshHits, {
limit: opts.limit || 50,
query: String(query || '').trim()
})
return {
hits: merged.map((m) => enrichmentScope.enrichMessageRow(m)),
mesh: true,
meshHitCount: meshHits.length,
localHitCount: local.length
}
} catch {
return { hits: local, mesh: false, meshHitCount: 0, localHitCount: local.length }
}
}
+5 -2
View File
@@ -1,6 +1,6 @@
'use strict'
/** Prototype mixins extracted from PearcordPlatform class body (Phases 738750). */
/** Prototype mixins extracted from PearcordPlatform class body (Phases 738751). */
const PLATFORM_RUNTIME_MIXIN_MODULES = [
'./platform-hyperswarm-runtime-mixin',
'./platform-session-startup-mixin',
@@ -36,7 +36,10 @@ const PLATFORM_RUNTIME_MIXIN_MODULES = [
'./platform-search-index-store-mixin',
'./platform-search-index-rebuild-mixin',
'./platform-search-mesh-gossip-mixin',
'./platform-discovery-mesh-refresh-mixin'
'./platform-discovery-mesh-refresh-mixin',
'./platform-search-guild-messages-mixin',
'./platform-search-query-filters-mixin',
'./platform-search-mesh-resolve-mixin'
]
const PLATFORM_RUNTIME_MIXIN_COUNT = PLATFORM_RUNTIME_MIXIN_MODULES.length
+74
View File
@@ -0,0 +1,74 @@
'use strict'
const sharedScope = require('pearcord-shared')
const enrichmentScope = require('./platform-message-enrichment')
const { formatHubMirrorFallback } = require('pearcord-hub-cards')
const platformSearchGuildMessagesMixin = {
async searchGuildMessages (guildId, query, opts = {}) {
const q = String(query || '').trim().toLowerCase()
if (!q || !guildId) return []
const limit = opts.limit || 50
const idx = await this._ensureGuildSearchIndex(guildId)
const indexed = idx.search(q, { limit })
if (indexed.length) {
return indexed.map((m) => enrichmentScope.enrichMessageRow(m))
}
if (opts.indexOnly) return []
const channels = await this.db.find(sharedScope.COLLECTIONS.CHANNELS, { guildId })
const channelById = new Map(channels.map((c) => [c.id, c]))
const searchable = new Set(
channels
.filter((c) => c.type === 'text' || c.type === 'thread' || c.type === 'announcement')
.map((c) => c.id)
)
let rows = []
if (this.db.getEngine?.() === 'hyperdb') {
for (const chId of searchable) {
const chRows = await this.db.find(sharedScope.COLLECTIONS.MESSAGES, { channelId: chId })
rows.push(...chRows)
}
} else {
rows = await this.db.find(sharedScope.COLLECTIONS.MESSAGES, { guildId })
}
const seen = new Set()
const hits = rows
.filter((m) => {
if (!m?.id || seen.has(m.id)) return false
seen.add(m.id)
const enriched = enrichmentScope.enrichMessageRow(m)
const ch = channelById.get(m.channelId)
const hay = [
ch?.name || '',
String(enriched.content || ''),
enriched.hubMirror ? formatHubMirrorFallback(enriched.hubMirror) : '',
...(enriched.stickerNames || []).map((n) => `:${n}:`),
ch?.archived ? 'archived' : ''
]
.join(' ')
.toLowerCase()
return searchable.has(m.channelId) && hay.includes(q)
})
.slice(0, limit * 2)
const { rankAndEnrichSearchHits } = require('pearcord-search')
const mapped = hits.map((m) => ({
...enrichmentScope.enrichMessageRow(m),
channelName: channelById.get(m.channelId)?.name || m.channelId.slice(0, 8)
}))
return rankAndEnrichSearchHits(mapped, q, { limit })
},
getGuildSearchIndexMeta (guildId) {
const id = guildId || this.guild?.guild?.id
if (!id) return { persisted: false, rowCount: 0, savedAt: null }
const blob = this._getSearchIndexStore().load(id)
const mem = this._guildSearchIndexes.get(id)
return {
persisted: !!(blob?.rows?.length),
savedAt: blob?.savedAt || null,
rowCount: blob?.rows?.length || mem?._rows?.length || 0
}
}
}
module.exports = { platformSearchGuildMessagesMixin }
+33
View File
@@ -0,0 +1,33 @@
'use strict'
const searchScope = require('pearcord-search')
const enrichmentScope = require('./platform-message-enrichment')
const platformSearchMeshResolveMixin = {
async searchGuildMessagesWithMesh (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 }
}
try {
const meshHits = await this._fetchGuildSearchFromMeshOnce(guildId, query, opts)
const merged = searchScope.mergeSearchHits(local, meshHits, {
limit: opts.limit || 50,
query: String(query || '').trim()
})
return {
hits: merged.map((m) => enrichmentScope.enrichMessageRow(m)),
mesh: true,
meshHitCount: meshHits.length,
localHitCount: local.length
}
} catch {
return { hits: local, mesh: false, meshHitCount: 0, localHitCount: local.length }
}
}
}
module.exports = { platformSearchMeshResolveMixin }
+52
View File
@@ -0,0 +1,52 @@
'use strict'
const sharedScope = require('pearcord-shared')
const platformSearchQueryFiltersMixin = {
async _applySearchQueryFilters (hits, rawQuery, guildId) {
const {
parseSearchQuery,
messageMatchesSearchFilters,
hasStructuredSearchFilters
} = require('pearcord-search')
const filters = parseSearchQuery(rawQuery)
if (!hasStructuredSearchFilters(filters)) return hits
const gId = guildId || this.guild?.guild?.id
const members = this.guild
? await this.guild.listMembers()
: gId
? await this.db.find(sharedScope.COLLECTIONS.MEMBERS, { guildId: gId })
: []
const usersById = await this._usersById(members)
const channels = gId ? await this.db.find(sharedScope.COLLECTIONS.CHANNELS, { guildId: gId }) : []
const channelById = new Map(channels.map((c) => [c.id, c]))
let pinnedKeys = null
if (filters.has === 'pin' && gId) {
const pins = await this.db.find(sharedScope.COLLECTIONS.PINS, { guildId: gId })
pinnedKeys = new Set(pins.map((p) => `${p.channelId}:${p.messageId}`))
}
const out = []
for (const hit of hits || []) {
const mem = members.find((m) => m.userId === hit.authorId)
const u = usersById[hit.authorId] || {}
const ch = channelById.get(hit.channelId)
const plain = this._messagePlaintext(hit)
if (
!messageMatchesSearchFilters(hit, filters, {
plaintext: plain,
authorTokens: [mem?.nickname, u.username, u.displayName].filter(Boolean),
authorId: hit.authorId,
channelName: ch?.name || hit.channelName,
isPinned: pinnedKeys ? pinnedKeys.has(`${hit.channelId}:${hit.id}`) : false,
attachmentIds: hit.attachmentIds
})
) {
continue
}
out.push(hit)
}
return out
}
}
module.exports = { platformSearchQueryFiltersMixin }