feat(platform): Phase 720 vanity-url.json and effective-permission.json mesh API
Add dedicated mixins and get/clear export helpers, view meta fields, dedicated log spans on push, and partition-heal hooks for vanity URL and effective permission signed JSON exports (RPC 113 / 115). Co-authored-by: Cursor <[email protected]>
This commit is contained in:
@@ -2,6 +2,8 @@
|
||||
|
||||
Application facade: one `PearcordPlatform` class that wires identity, database, guild mesh, DMs, invites, voice, discovery, bots, and dozens of feature modules for the Pearcord desktop sidecar and companion.
|
||||
|
||||
**Phase 720 (v0.8.696):** Vanity URL JSON & effective permission export — `vanity-url-json-mixin.js`, `effective-permission-json-mixin.js`, `vanity-url.json` / `effective-permission.json` spans, `getVanityUrlExportJsonExport` / `getEffectivePermissionExportJsonExport`, deep links `?vanity-url-json=1` / `?effective-permission-json=1`. Bundle: `npm run test:ci-phase720`.
|
||||
|
||||
**Phase 719 (v0.8.695):** Read state JSON & webhook execute export — `read-state-json-mixin.js`, `webhook-json-mixin.js`, `read-state.json` / `webhook.json` spans, `pushReadStateExportToMesh`, `pushWebhookExecuteExportToMesh`, deep links `?read-state-json=1` / `?webhook-json=1`. Bundle: `npm run test:ci-phase719`.
|
||||
|
||||
**Phase 718 (v0.8.694):** Channel follow JSON & guild widget export — `channel-follow-json-mixin.js`, `guild-widget-json-mixin.js`, `channel-follow.json` / `guild-widget.json` spans, `pushChannelFollowExportToMesh`, `pushGuildWidgetExportToMesh`, deep links `?channel-follow-json=1` / `?guild-widget-json=1`. Bundle: `npm run test:ci-phase718`.
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
'use strict'
|
||||
|
||||
const effectivePermissionJsonMixin = {
|
||||
_effectivePermissionRegistryJsonGossipKeys: null,
|
||||
_effectivePermissionJsonHealWatermark: null,
|
||||
|
||||
_initEffectivePermissionJsonMixinState () {
|
||||
if (!this._effectivePermissionRegistryJsonGossipKeys) {
|
||||
this._effectivePermissionRegistryJsonGossipKeys = new Set()
|
||||
}
|
||||
},
|
||||
|
||||
_shouldGossipEffectivePermissionRegistryJson (slice) {
|
||||
this._initEffectivePermissionJsonMixinState()
|
||||
if (!slice?.guildId || !slice?.signature) return true
|
||||
const hash = `${slice.guildId}:${slice.exportedAt || 0}:${slice.signature}`
|
||||
if (this._effectivePermissionRegistryJsonGossipKeys.has(hash)) return false
|
||||
this._effectivePermissionRegistryJsonGossipKeys.add(hash)
|
||||
if (this._effectivePermissionRegistryJsonGossipKeys.size > 8192) {
|
||||
const first = this._effectivePermissionRegistryJsonGossipKeys.values().next().value
|
||||
if (first) this._effectivePermissionRegistryJsonGossipKeys.delete(first)
|
||||
}
|
||||
return true
|
||||
},
|
||||
|
||||
async _healEffectivePermissionJsonExportCursorOnPartition (guildId) {
|
||||
const gid = guildId || this.guild?.guild?.id || null
|
||||
const span = this.log.time('effective-permission.json', {
|
||||
spanKind: 'effective-permission.json',
|
||||
guildId: gid,
|
||||
context: 'heal.effective-permission'
|
||||
})
|
||||
try {
|
||||
if (!gid || !this.deliveryReceipts) {
|
||||
span.end({ relisted: 0, skipped: true, guildEffectivePermissionJsonCount: 0 })
|
||||
return { relisted: 0, skipped: true }
|
||||
}
|
||||
await this._initDeliveryReceipts(gid)
|
||||
const rows = await this.deliveryReceipts.listEffectivePermissionExportJsonExports(64)
|
||||
let relisted = 0
|
||||
for (const row of rows) {
|
||||
if (this._shouldGossipEffectivePermissionRegistryJson(row)) relisted++
|
||||
}
|
||||
const watermark = Date.now()
|
||||
this._effectivePermissionJsonHealWatermark = watermark
|
||||
span.end({
|
||||
relisted,
|
||||
watermark,
|
||||
guildEffectivePermissionJsonCount: rows.length,
|
||||
overwriteCount: rows[0]?.overwriteCount || 0,
|
||||
bridgeKind: 'effective-permission.json'
|
||||
})
|
||||
return { relisted, watermark, guildEffectivePermissionJsonCount: rows.length }
|
||||
} catch (err) {
|
||||
this.log.error('effective-permission.json error', {
|
||||
guildId: gid,
|
||||
context: 'heal.effective-permission',
|
||||
error: err?.message || String(err)
|
||||
})
|
||||
span.fail(err)
|
||||
return { relisted: 0, error: err?.message || String(err) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { effectivePermissionJsonMixin }
|
||||
@@ -1857,6 +1857,12 @@ class PearcordPlatform extends EventEmitter {
|
||||
const webhookJsonHeal = await this._healWebhookJsonExportCursorOnPartition(gid).catch(() => ({
|
||||
relisted: 0
|
||||
}))
|
||||
const vanityUrlJsonMeshHeal = await this._healVanityUrlJsonExportCursorOnPartition(gid).catch(() => ({
|
||||
relisted: 0
|
||||
}))
|
||||
const effectivePermissionJsonMeshHeal = await this._healEffectivePermissionJsonExportCursorOnPartition(gid).catch(() => ({
|
||||
relisted: 0
|
||||
}))
|
||||
return {
|
||||
voiceApplied,
|
||||
emojiSlots,
|
||||
@@ -1929,7 +1935,9 @@ class PearcordPlatform extends EventEmitter {
|
||||
channelFollowJsonHeal,
|
||||
guildWidgetJsonHeal,
|
||||
readStateJsonHeal,
|
||||
webhookJsonHeal
|
||||
webhookJsonHeal,
|
||||
vanityUrlJsonMeshHeal,
|
||||
effectivePermissionJsonMeshHeal
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18750,7 +18758,13 @@ class PearcordPlatform extends EventEmitter {
|
||||
openBanJson: !!parsed.openBanJson,
|
||||
openPollJson: !!parsed.openPollJson,
|
||||
openPinJson: !!parsed.openPinJson,
|
||||
openThreadJson: !!parsed.openThreadJson
|
||||
openThreadJson: !!parsed.openThreadJson,
|
||||
openReadStateJson: !!parsed.openReadStateJson,
|
||||
openWebhookJson: !!parsed.openWebhookJson,
|
||||
openVanityUrlJson: !!parsed.openVanityUrlJson,
|
||||
openEffectivePermissionJson: !!parsed.openEffectivePermissionJson,
|
||||
openChannelFollowJson: !!parsed.openChannelFollowJson,
|
||||
openGuildWidgetJson: !!parsed.openGuildWidgetJson
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23069,10 +23083,43 @@ class PearcordPlatform extends EventEmitter {
|
||||
}
|
||||
}
|
||||
|
||||
async getVanityUrlExportJsonExport () {
|
||||
const gid = this.guild?.guild?.id || null
|
||||
const span = this.log.time('vanity-url.json', { spanKind: 'vanity-url.json', guildId: gid, context: 'read' })
|
||||
try {
|
||||
if (!this.guild?.guild) { span.end({ guildVanityUrlJsonCount: 0, skipped: true }); return null }
|
||||
await this._initDeliveryReceipts(this.guild.guild.id)
|
||||
const row = await this.deliveryReceipts.getVanityUrlExportJsonExport()
|
||||
if (!row?.signature) {
|
||||
span.end({ guildVanityUrlJsonCount: row ? 1 : 0, hasSignature: false, bridgeKind: 'vanity-url.json' })
|
||||
return row
|
||||
}
|
||||
const verified = verifyVanityUrlExportJson(exportBodyFromSlice(row) || row.jsonBody || row.jsonBody, row.signature, {
|
||||
guildId: this.guild.guild.id,
|
||||
relaySecret: this.guild.guild.id
|
||||
})
|
||||
const out = { ...row, signatureValid: verified.ok, inviteCount: row.inviteCount || 0 }
|
||||
span.end({ guildVanityUrlJsonCount: 1, hasSignature: true, signatureValid: verified.ok, bridgeKind: 'vanity-url.json' })
|
||||
return out
|
||||
} catch (err) {
|
||||
this.log.error('vanity-url.json error', { guildId: gid, context: 'read', error: err?.message || String(err) })
|
||||
span.fail(err); throw err
|
||||
}
|
||||
}
|
||||
|
||||
async clearVanityUrlExportJsonExports () {
|
||||
if (!this.guild?.guild) throw new Error('no guild')
|
||||
if (!(await this._hasPerm(PERMISSION.MANAGE_GUILD))) throw new Error('no permission to clear vanity URL JSON exports')
|
||||
await this._initDeliveryReceipts(this.guild.guild.id)
|
||||
const removed = await this.deliveryReceipts.clearVanityUrlExportJsonExports()
|
||||
this.emit('vanity-url-export-json-cleared', { removed })
|
||||
return { removed }
|
||||
}
|
||||
|
||||
async pushVanityUrlExportToMesh () {
|
||||
const gid = this.guild?.guild?.id || null
|
||||
const span = this.log.time('invite.json', {
|
||||
spanKind: 'invite.json',
|
||||
const span = this.log.time('vanity-url.json', {
|
||||
spanKind: 'vanity-url.json',
|
||||
guildId: gid,
|
||||
context: 'mesh.vanity'
|
||||
})
|
||||
@@ -23104,13 +23151,13 @@ class PearcordPlatform extends EventEmitter {
|
||||
meshPushed: true
|
||||
}
|
||||
span.end({
|
||||
guildInviteJsonCount: exported.inviteCount || 0,
|
||||
guildVanityUrlJsonCount: exported.inviteCount || 0,
|
||||
meshPushed: true,
|
||||
bridgeKind: 'invite.json'
|
||||
bridgeKind: 'vanity-url.json'
|
||||
})
|
||||
return exported
|
||||
} catch (err) {
|
||||
this.log.error('invite.json error', {
|
||||
this.log.error('vanity-url.json error', {
|
||||
guildId: gid,
|
||||
context: 'mesh.vanity',
|
||||
error: err?.message || String(err)
|
||||
@@ -23384,10 +23431,43 @@ class PearcordPlatform extends EventEmitter {
|
||||
}
|
||||
}
|
||||
|
||||
async getEffectivePermissionExportJsonExport () {
|
||||
const gid = this.guild?.guild?.id || null
|
||||
const span = this.log.time('effective-permission.json', { spanKind: 'effective-permission.json', guildId: gid, context: 'read' })
|
||||
try {
|
||||
if (!this.guild?.guild) { span.end({ guildEffectivePermissionJsonCount: 0, skipped: true }); return null }
|
||||
await this._initDeliveryReceipts(this.guild.guild.id)
|
||||
const row = await this.deliveryReceipts.getEffectivePermissionExportJsonExport()
|
||||
if (!row?.signature) {
|
||||
span.end({ guildEffectivePermissionJsonCount: row ? 1 : 0, hasSignature: false, bridgeKind: 'effective-permission.json' })
|
||||
return row
|
||||
}
|
||||
const verified = verifyEffectivePermissionExportJson(exportBodyFromSlice(row) || row.jsonBody || row.jsonBody, row.signature, {
|
||||
guildId: this.guild.guild.id,
|
||||
relaySecret: this.guild.guild.id
|
||||
})
|
||||
const out = { ...row, signatureValid: verified.ok, overwriteCount: row.overwriteCount || 0 }
|
||||
span.end({ guildEffectivePermissionJsonCount: 1, hasSignature: true, signatureValid: verified.ok, bridgeKind: 'effective-permission.json' })
|
||||
return out
|
||||
} catch (err) {
|
||||
this.log.error('effective-permission.json error', { guildId: gid, context: 'read', error: err?.message || String(err) })
|
||||
span.fail(err); throw err
|
||||
}
|
||||
}
|
||||
|
||||
async clearEffectivePermissionExportJsonExports () {
|
||||
if (!this.guild?.guild) throw new Error('no guild')
|
||||
if (!(await this._hasPerm(PERMISSION.MANAGE_CHANNELS))) throw new Error('no permission to clear effective permission JSON exports')
|
||||
await this._initDeliveryReceipts(this.guild.guild.id)
|
||||
const removed = await this.deliveryReceipts.clearEffectivePermissionExportJsonExports()
|
||||
this.emit('effective-permission-export-json-cleared', { removed })
|
||||
return { removed }
|
||||
}
|
||||
|
||||
async pushEffectivePermissionExportToMesh () {
|
||||
const gid = this.guild?.guild?.id || null
|
||||
const span = this.log.time('permission.json', {
|
||||
spanKind: 'permission.json',
|
||||
const span = this.log.time('effective-permission.json', {
|
||||
spanKind: 'effective-permission.json',
|
||||
guildId: gid,
|
||||
context: 'mesh.effective'
|
||||
})
|
||||
@@ -23419,13 +23499,13 @@ class PearcordPlatform extends EventEmitter {
|
||||
meshPushed: true
|
||||
}
|
||||
span.end({
|
||||
guildPermissionJsonCount: exported.overwriteCount || 0,
|
||||
guildEffectivePermissionJsonCount: exported.overwriteCount || 0,
|
||||
meshPushed: true,
|
||||
bridgeKind: 'permission.json'
|
||||
bridgeKind: 'effective-permission.json'
|
||||
})
|
||||
return exported
|
||||
} catch (err) {
|
||||
this.log.error('permission.json error', {
|
||||
this.log.error('effective-permission.json error', {
|
||||
guildId: gid,
|
||||
context: 'mesh.effective',
|
||||
error: err?.message || String(err)
|
||||
@@ -32599,10 +32679,12 @@ class PearcordPlatform extends EventEmitter {
|
||||
let lastOAuthInstallTokenExport = null
|
||||
let inviteLinkJsonMeta = null
|
||||
let inviteLinkJsonRows = []
|
||||
let vanityUrlExportJsonMeta = null
|
||||
let vanityUrlExportJsonRows = []
|
||||
let lastVanityUrlExport = null
|
||||
let roleOverrideJsonMeta = null
|
||||
let roleOverrideJsonRows = []
|
||||
let effectivePermissionExportJsonMeta = null
|
||||
let effectivePermissionExportJsonRows = []
|
||||
let lastEffectivePermissionExport = null
|
||||
let guildPermissionOverwrites = []
|
||||
@@ -32862,6 +32944,7 @@ class PearcordPlatform extends EventEmitter {
|
||||
})
|
||||
return { ...row, signatureValid: verified.ok }
|
||||
})
|
||||
vanityUrlExportJsonMeta = await this.getVanityUrlExportJsonExport().catch(() => null)
|
||||
const vanityJsonHistory = await this.deliveryReceipts.listVanityUrlExportJsonExports(32)
|
||||
vanityUrlExportJsonRows = vanityJsonHistory.map((row) => {
|
||||
if (!row?.signature || !guild?.id) return row
|
||||
@@ -32882,6 +32965,7 @@ class PearcordPlatform extends EventEmitter {
|
||||
})
|
||||
return { ...row, signatureValid: verified.ok }
|
||||
})
|
||||
effectivePermissionExportJsonMeta = await this.getEffectivePermissionExportJsonExport().catch(() => null)
|
||||
const effectiveJsonHistory =
|
||||
await this.deliveryReceipts.listEffectivePermissionExportJsonExports(32)
|
||||
effectivePermissionExportJsonRows = effectiveJsonHistory.map((row) => {
|
||||
@@ -33665,12 +33749,18 @@ class PearcordPlatform extends EventEmitter {
|
||||
inviteLinkJsonMeta,
|
||||
inviteLinkJsonRows,
|
||||
vanityUrlExportJsonRows,
|
||||
vanityUrlExportJsonMeta,
|
||||
lastVanityUrlExport,
|
||||
guildVanityUrlJsonCount:
|
||||
(vanityUrlExportJsonRows || []).length + (guildInvites || []).length,
|
||||
guildInviteJsonCount: (inviteLinkJsonRows || []).length + (guildInvites || []).length,
|
||||
roleOverrideJsonMeta,
|
||||
roleOverrideJsonRows,
|
||||
effectivePermissionExportJsonRows,
|
||||
effectivePermissionExportJsonMeta,
|
||||
lastEffectivePermissionExport,
|
||||
guildEffectivePermissionJsonCount:
|
||||
(effectivePermissionExportJsonRows || []).length + (guildPermissionOverwrites || []).length,
|
||||
guildPermissionOverwrites,
|
||||
guildPermissionJsonCount:
|
||||
(roleOverrideJsonRows || []).length + (guildPermissionOverwrites || []).length,
|
||||
@@ -34450,6 +34540,8 @@ const { channelFollowJsonMixin } = require('./channel-follow-json-mixin')
|
||||
const { guildWidgetJsonMixin } = require('./guild-widget-json-mixin')
|
||||
const { readStateJsonMixin } = require('./read-state-json-mixin')
|
||||
const { webhookJsonMixin } = require('./webhook-json-mixin')
|
||||
const { vanityUrlJsonMixin } = require('./vanity-url-json-mixin')
|
||||
const { effectivePermissionJsonMixin } = require('./effective-permission-json-mixin')
|
||||
Object.assign(PearcordPlatform.prototype, pollSchedulingMixin)
|
||||
Object.assign(PearcordPlatform.prototype, notificationsActivityMixin)
|
||||
Object.assign(PearcordPlatform.prototype, userSettingsMixin)
|
||||
@@ -34499,3 +34591,5 @@ Object.assign(PearcordPlatform.prototype, channelFollowJsonMixin)
|
||||
Object.assign(PearcordPlatform.prototype, guildWidgetJsonMixin)
|
||||
Object.assign(PearcordPlatform.prototype, readStateJsonMixin)
|
||||
Object.assign(PearcordPlatform.prototype, webhookJsonMixin)
|
||||
Object.assign(PearcordPlatform.prototype, vanityUrlJsonMixin)
|
||||
Object.assign(PearcordPlatform.prototype, effectivePermissionJsonMixin)
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
'use strict'
|
||||
|
||||
const vanityUrlJsonMixin = {
|
||||
_vanityUrlRegistryJsonGossipKeys: null,
|
||||
_vanityUrlJsonHealWatermark: null,
|
||||
|
||||
_initVanityUrlJsonMixinState () {
|
||||
if (!this._vanityUrlRegistryJsonGossipKeys) {
|
||||
this._vanityUrlRegistryJsonGossipKeys = new Set()
|
||||
}
|
||||
},
|
||||
|
||||
_shouldGossipVanityUrlRegistryJson (slice) {
|
||||
this._initVanityUrlJsonMixinState()
|
||||
if (!slice?.guildId || !slice?.signature) return true
|
||||
const hash = `${slice.guildId}:${slice.exportedAt || 0}:${slice.signature}`
|
||||
if (this._vanityUrlRegistryJsonGossipKeys.has(hash)) return false
|
||||
this._vanityUrlRegistryJsonGossipKeys.add(hash)
|
||||
if (this._vanityUrlRegistryJsonGossipKeys.size > 8192) {
|
||||
const first = this._vanityUrlRegistryJsonGossipKeys.values().next().value
|
||||
if (first) this._vanityUrlRegistryJsonGossipKeys.delete(first)
|
||||
}
|
||||
return true
|
||||
},
|
||||
|
||||
async _healVanityUrlJsonExportCursorOnPartition (guildId) {
|
||||
const gid = guildId || this.guild?.guild?.id || null
|
||||
const span = this.log.time('vanity-url.json', {
|
||||
spanKind: 'vanity-url.json',
|
||||
guildId: gid,
|
||||
context: 'heal.vanity-url'
|
||||
})
|
||||
try {
|
||||
if (!gid || !this.deliveryReceipts) {
|
||||
span.end({ relisted: 0, skipped: true, guildVanityUrlJsonCount: 0 })
|
||||
return { relisted: 0, skipped: true }
|
||||
}
|
||||
await this._initDeliveryReceipts(gid)
|
||||
const rows = await this.deliveryReceipts.listVanityUrlExportJsonExports(64)
|
||||
let relisted = 0
|
||||
for (const row of rows) {
|
||||
if (this._shouldGossipVanityUrlRegistryJson(row)) relisted++
|
||||
}
|
||||
const watermark = Date.now()
|
||||
this._vanityUrlJsonHealWatermark = watermark
|
||||
span.end({
|
||||
relisted,
|
||||
watermark,
|
||||
guildVanityUrlJsonCount: rows.length,
|
||||
inviteCount: rows[0]?.inviteCount || 0,
|
||||
bridgeKind: 'vanity-url.json'
|
||||
})
|
||||
return { relisted, watermark, guildVanityUrlJsonCount: rows.length }
|
||||
} catch (err) {
|
||||
this.log.error('vanity-url.json error', {
|
||||
guildId: gid,
|
||||
context: 'heal.vanity-url',
|
||||
error: err?.message || String(err)
|
||||
})
|
||||
span.fail(err)
|
||||
return { relisted: 0, error: err?.message || String(err) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { vanityUrlJsonMixin }
|
||||
Reference in New Issue
Block a user