feat(platform): Phase 490 bot span metadata (v0.8.453)
Add bot.token span, bot.verify span, and messageSent on bot.message. Co-authored-by: Cursor <[email protected]>
This commit is contained in:
@@ -39,6 +39,8 @@ Expose a single `EventEmitter` API the UI drives over IPC (`apps/pearcord/index.
|
||||
|
||||
**v0.8.430 (Phase 467):** `voice.leave` span `end` includes `leavingIsStage`; `screen.start` span `end` includes `label`. Bundle: `npm run test:phase467-voice-stage`. See [VOICE.md](../../docs/VOICE.md), [STAGE_CHANNELS.md](../../docs/STAGE_CHANNELS.md).
|
||||
|
||||
**v0.8.453 (Phase 490):** `bot.token`/`bot.verify`/`bot.install`/`bot.message` span metadata extend. UI bot compositor + hints. Bundle: `npm run test:phase490-bots`. See [BOTS.md](../../docs/BOTS.md).
|
||||
|
||||
**v0.8.452 (Phase 489):** `slash.register` `customCount`; `slash.delete` `deleted`; `slash.invoke` `replyLen`/`commandFound`. UI slash compositor + hints. Bundle: `npm run test:phase489-slash`. See [SLASH_COMMANDS.md](../../docs/SLASH_COMMANDS.md).
|
||||
|
||||
**v0.8.451 (Phase 488):** `webhook.create` `channelType`/`hasAvatar`; `webhook.execute` `messageSent`. UI webhook compositor split + hints. Bundle: `npm run test:phase488-webhooks`. See [WEBHOOKS.md](../../docs/WEBHOOKS.md).
|
||||
|
||||
@@ -9968,37 +9968,55 @@ class PearcordPlatform extends EventEmitter {
|
||||
botId = null,
|
||||
ttlMs = 7 * 86400000
|
||||
} = {}) {
|
||||
if (!this.guild?.guild) throw new Error('no guild')
|
||||
const user = this.identity.user
|
||||
if (!user) throw new Error('register first')
|
||||
await this._assertStepUp()
|
||||
const roles = await this._memberRoles()
|
||||
if (!roleHasPermission(roles, PERMISSION.MANAGE_GUILD)) {
|
||||
throw new Error('no permission to create bot install tokens')
|
||||
const guildId = this.guild?.guild?.id || null
|
||||
const span = this.log.time('bot.token', { guildId })
|
||||
try {
|
||||
if (!this.guild?.guild) throw new Error('no guild')
|
||||
const user = this.identity.user
|
||||
if (!user) throw new Error('register first')
|
||||
await this._assertStepUp()
|
||||
const roles = await this._memberRoles()
|
||||
if (!roleHasPermission(roles, PERMISSION.MANAGE_GUILD)) {
|
||||
throw new Error('no permission to create bot install tokens')
|
||||
}
|
||||
if (!this.botLimits) {
|
||||
this.botLimits = new BotRateLimits({ storagePath: this.storagePath })
|
||||
await this.botLimits.ready()
|
||||
}
|
||||
await this.botLimits.assertBotRegister(this.guild.guild.id)
|
||||
const { token, payload } = createInstallToken({
|
||||
keyPair: this.identity.keyPair,
|
||||
guildId: this.guild.guild.id,
|
||||
guildName: this.guild.guild.name,
|
||||
guildTopic: this.guild.guild.topic,
|
||||
botId: botId || id(),
|
||||
name,
|
||||
intents,
|
||||
permissions,
|
||||
botPublicKey,
|
||||
issuedBy: user.id,
|
||||
ttlMs
|
||||
})
|
||||
const bot = payloadToBotRow(payload, this.identity.snapshot().publicKey)
|
||||
await this._ingestGuildBot(bot)
|
||||
this.guild.gossipBotInstall(bot)
|
||||
this.emit('bot', bot)
|
||||
span.end({
|
||||
guildId,
|
||||
botId: bot.id,
|
||||
botName: String(bot.name || '').slice(0, 32),
|
||||
permissionMask: Number(bot.permissions) || 0,
|
||||
tokenIssued: !!token
|
||||
})
|
||||
return { token, bot, expiresAt: payload.expiresAt }
|
||||
} catch (err) {
|
||||
this.log.error('bot.token error', {
|
||||
guildId,
|
||||
error: err?.message || String(err)
|
||||
})
|
||||
span.fail(err)
|
||||
throw err
|
||||
}
|
||||
if (!this.botLimits) {
|
||||
this.botLimits = new BotRateLimits({ storagePath: this.storagePath })
|
||||
await this.botLimits.ready()
|
||||
}
|
||||
await this.botLimits.assertBotRegister(this.guild.guild.id)
|
||||
const { token, payload } = createInstallToken({
|
||||
keyPair: this.identity.keyPair,
|
||||
guildId: this.guild.guild.id,
|
||||
guildName: this.guild.guild.name,
|
||||
guildTopic: this.guild.guild.topic,
|
||||
botId: botId || id(),
|
||||
name,
|
||||
intents,
|
||||
permissions,
|
||||
botPublicKey,
|
||||
issuedBy: user.id,
|
||||
ttlMs
|
||||
})
|
||||
const bot = payloadToBotRow(payload, this.identity.snapshot().publicKey)
|
||||
await this._ingestGuildBot(bot)
|
||||
this.guild.gossipBotInstall(bot)
|
||||
this.emit('bot', bot)
|
||||
return { token, bot, expiresAt: payload.expiresAt }
|
||||
}
|
||||
|
||||
async installBotFromToken (tokenInput) {
|
||||
@@ -10020,7 +10038,8 @@ class PearcordPlatform extends EventEmitter {
|
||||
botId: bot.id,
|
||||
guildId: bot.guildId,
|
||||
botName: String(bot.name || '').slice(0, 32),
|
||||
permissionMask: Number(bot.permissions) || 0
|
||||
permissionMask: Number(bot.permissions) || 0,
|
||||
installed: true
|
||||
})
|
||||
return { bot, token: typeof tokenInput === 'string' ? tokenInput : null }
|
||||
} catch (err) {
|
||||
@@ -10034,7 +10053,26 @@ class PearcordPlatform extends EventEmitter {
|
||||
}
|
||||
|
||||
async verifyBotToken (tokenInput) {
|
||||
return verifyInstallToken(tokenInput)
|
||||
const guildId = this.guild?.guild?.id || null
|
||||
const span = this.log.time('bot.verify', { guildId })
|
||||
try {
|
||||
const result = verifyInstallToken(tokenInput, {
|
||||
expectedGuildId: guildId || undefined
|
||||
})
|
||||
span.end({
|
||||
guildId,
|
||||
ok: !!result.ok,
|
||||
botId: result.payload?.botId || null
|
||||
})
|
||||
return result
|
||||
} catch (err) {
|
||||
this.log.error('bot.verify error', {
|
||||
guildId,
|
||||
error: err?.message || String(err)
|
||||
})
|
||||
span.fail(err)
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
async sendBotMessage ({ botId, content, channelId } = {}) {
|
||||
@@ -10060,7 +10098,8 @@ class PearcordPlatform extends EventEmitter {
|
||||
guildId,
|
||||
channelId: chId,
|
||||
contentLength: String(content ?? '').length,
|
||||
botId
|
||||
botId,
|
||||
messageSent: !!msg?.id
|
||||
})
|
||||
return msg
|
||||
} catch (err) {
|
||||
|
||||
Reference in New Issue
Block a user