@furlow/builtins 1.0.1 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/afk/index.js +7 -7
- package/dist/afk/index.js.map +1 -1
- package/dist/auto-responder/index.js +17 -17
- package/dist/auto-responder/index.js.map +1 -1
- package/dist/giveaways/index.js +8 -8
- package/dist/giveaways/index.js.map +1 -1
- package/dist/index.js +181 -181
- package/dist/index.js.map +1 -1
- package/dist/leveling/index.js +15 -15
- package/dist/leveling/index.js.map +1 -1
- package/dist/logging/index.js +25 -25
- package/dist/logging/index.js.map +1 -1
- package/dist/music/index.js +10 -10
- package/dist/music/index.js.map +1 -1
- package/dist/polls/index.js +7 -7
- package/dist/polls/index.js.map +1 -1
- package/dist/reaction-roles/index.js +14 -14
- package/dist/reaction-roles/index.js.map +1 -1
- package/dist/reminders/index.js +4 -4
- package/dist/reminders/index.js.map +1 -1
- package/dist/starboard/index.js +16 -16
- package/dist/starboard/index.js.map +1 -1
- package/dist/tickets/index.js +18 -18
- package/dist/tickets/index.js.map +1 -1
- package/dist/utilities/index.js +23 -23
- package/dist/utilities/index.js.map +1 -1
- package/dist/welcome/index.js +17 -17
- package/dist/welcome/index.js.map +1 -1
- package/package.json +4 -4
package/dist/leveling/index.js
CHANGED
|
@@ -15,7 +15,7 @@ var levelingTables = {
|
|
|
15
15
|
var levelingEventHandlers = [
|
|
16
16
|
{
|
|
17
17
|
event: "message",
|
|
18
|
-
condition: "
|
|
18
|
+
condition: "!message.author.bot && !config.leveling.ignoredChannels?.includes(channel.id)",
|
|
19
19
|
actions: [
|
|
20
20
|
// Check cooldown
|
|
21
21
|
{
|
|
@@ -30,7 +30,7 @@ var levelingEventHandlers = [
|
|
|
30
30
|
// Initialize if new user
|
|
31
31
|
{
|
|
32
32
|
action: "flow_if",
|
|
33
|
-
condition: "
|
|
33
|
+
condition: "!userData || userData.length === 0",
|
|
34
34
|
then: [
|
|
35
35
|
{
|
|
36
36
|
action: "db_insert",
|
|
@@ -59,7 +59,7 @@ var levelingEventHandlers = [
|
|
|
59
59
|
},
|
|
60
60
|
{
|
|
61
61
|
action: "flow_if",
|
|
62
|
-
condition: "
|
|
62
|
+
condition: "cooldownPassed",
|
|
63
63
|
then: [
|
|
64
64
|
// Calculate XP gain
|
|
65
65
|
{
|
|
@@ -129,25 +129,25 @@ var levelingEventHandlers = [
|
|
|
129
129
|
// Handle level up
|
|
130
130
|
{
|
|
131
131
|
action: "flow_if",
|
|
132
|
-
condition: "
|
|
132
|
+
condition: "leveledUp",
|
|
133
133
|
then: [
|
|
134
134
|
// Announce level up
|
|
135
135
|
{
|
|
136
136
|
action: "flow_if",
|
|
137
|
-
condition: "
|
|
137
|
+
condition: "config.leveling.announceChannel",
|
|
138
138
|
then: [
|
|
139
139
|
{
|
|
140
140
|
action: "flow_if",
|
|
141
|
-
condition: "
|
|
141
|
+
condition: "config.leveling.levelUpEmbed",
|
|
142
142
|
then: [
|
|
143
143
|
{
|
|
144
144
|
action: "send_message",
|
|
145
145
|
channel: "${config.leveling.announceChannel}",
|
|
146
146
|
embed: {
|
|
147
147
|
title: "Level Up!",
|
|
148
|
-
description: '${config.leveling.levelUpMessage || member.
|
|
148
|
+
description: '${config.leveling.levelUpMessage || member.display_name + " has reached level " + newLevel + "!"}',
|
|
149
149
|
color: "#ffd700",
|
|
150
|
-
thumbnail: "${member.
|
|
150
|
+
thumbnail: "${member.avatar}"
|
|
151
151
|
}
|
|
152
152
|
}
|
|
153
153
|
],
|
|
@@ -155,7 +155,7 @@ var levelingEventHandlers = [
|
|
|
155
155
|
{
|
|
156
156
|
action: "send_message",
|
|
157
157
|
channel: "${config.leveling.announceChannel}",
|
|
158
|
-
content: '${config.leveling.levelUpMessage || "Congratulations " + member.
|
|
158
|
+
content: '${config.leveling.levelUpMessage || "Congratulations " + member.display_name + "! You reached level " + newLevel + "!"}'
|
|
159
159
|
}
|
|
160
160
|
]
|
|
161
161
|
}
|
|
@@ -164,12 +164,12 @@ var levelingEventHandlers = [
|
|
|
164
164
|
// Award role rewards
|
|
165
165
|
{
|
|
166
166
|
action: "flow_if",
|
|
167
|
-
condition: "
|
|
167
|
+
condition: "config.leveling.rewards && config.leveling.rewards[newLevel]",
|
|
168
168
|
then: [
|
|
169
169
|
// Remove previous rewards if not stacking
|
|
170
170
|
{
|
|
171
171
|
action: "flow_if",
|
|
172
|
-
condition: "
|
|
172
|
+
condition: "!config.leveling.stackRewards && currentLevel > 0 && config.leveling.rewards[currentLevel]",
|
|
173
173
|
then: [
|
|
174
174
|
{
|
|
175
175
|
action: "remove_role",
|
|
@@ -216,7 +216,7 @@ var levelingCommands = [
|
|
|
216
216
|
},
|
|
217
217
|
{
|
|
218
218
|
action: "flow_if",
|
|
219
|
-
condition: "
|
|
219
|
+
condition: "!userData || userData.length === 0",
|
|
220
220
|
then: [
|
|
221
221
|
{
|
|
222
222
|
action: "reply",
|
|
@@ -248,7 +248,7 @@ var levelingCommands = [
|
|
|
248
248
|
// Render rank card or embed
|
|
249
249
|
{
|
|
250
250
|
action: "flow_if",
|
|
251
|
-
condition: "
|
|
251
|
+
condition: "config.leveling.useRankCard",
|
|
252
252
|
then: [
|
|
253
253
|
{
|
|
254
254
|
action: "canvas_render",
|
|
@@ -280,7 +280,7 @@ var levelingCommands = [
|
|
|
280
280
|
embed: {
|
|
281
281
|
title: "${targetUser.username}'s Rank",
|
|
282
282
|
color: "#5865f2",
|
|
283
|
-
thumbnail: "${targetUser.
|
|
283
|
+
thumbnail: "${targetUser.avatar}",
|
|
284
284
|
fields: [
|
|
285
285
|
{ name: "Rank", value: "#${rank}", inline: true },
|
|
286
286
|
{ name: "Level", value: "${userData[0].level}", inline: true },
|
|
@@ -416,7 +416,7 @@ var levelingCanvasGenerators = {
|
|
|
416
416
|
// User avatar
|
|
417
417
|
{
|
|
418
418
|
type: "circle_image",
|
|
419
|
-
url: "${user.
|
|
419
|
+
url: "${user.avatar}",
|
|
420
420
|
x: 120,
|
|
421
421
|
y: 141,
|
|
422
422
|
radius: 80,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/leveling/index.ts"],"sourcesContent":["/**\n * Leveling builtin module\n * Handles XP, levels, rewards, leaderboards, and rank cards\n */\n\nimport type { FurlowSpec, CommandDefinition, EventHandler, CanvasGenerator, TableDefinition } from '@furlow/schema';\n\nexport interface LevelingConfig {\n /** XP per message range [min, max] */\n xpPerMessage?: [number, number];\n /** Cooldown between XP gains (seconds) */\n xpCooldown?: number;\n /** XP multiplier for roles */\n roleMultipliers?: Record<string, number>;\n /** Channels where XP is disabled */\n ignoredChannels?: string[];\n /** Roles that don't earn XP */\n ignoredRoles?: string[];\n /** Channel for level up announcements */\n announceChannel?: string;\n /** Level up message */\n levelUpMessage?: string;\n /** Use embed for level up */\n levelUpEmbed?: boolean;\n /** Level rewards (level -> role IDs) */\n rewards?: Record<number, string[]>;\n /** Stack rewards or remove previous */\n stackRewards?: boolean;\n /** Use rank card images */\n useRankCard?: boolean;\n /** Rank card generator name */\n rankCardGenerator?: string;\n /** XP curve formula */\n xpCurve?: 'linear' | 'exponential' | 'custom';\n /** Base XP for level 1 */\n baseXP?: number;\n /** XP multiplier per level */\n xpMultiplier?: number;\n}\n\nexport const levelingTables: Record<string, TableDefinition> = {\n levels: {\n columns: {\n id: { type: 'number', primary: true },\n user_id: { type: 'string', index: true },\n guild_id: { type: 'string', index: true },\n xp: { type: 'number', default: 0 },\n level: { type: 'number', default: 0 },\n total_messages: { type: 'number', default: 0 },\n last_xp_at: { type: 'timestamp' },\n },\n },\n};\n\nexport const levelingEventHandlers: EventHandler[] = [\n {\n event: 'message',\n condition: '${!message.author.bot && !config.leveling.ignoredChannels?.includes(channel.id)}',\n actions: [\n // Check cooldown\n {\n action: 'db_query',\n table: 'levels',\n where: {\n user_id: '${user.id}',\n guild_id: '${guild.id}',\n },\n as: 'userData',\n },\n // Initialize if new user\n {\n action: 'flow_if',\n condition: '${!userData || userData.length === 0}',\n then: [\n {\n action: 'db_insert',\n table: 'levels',\n data: {\n user_id: '${user.id}',\n guild_id: '${guild.id}',\n xp: 0,\n level: 0,\n total_messages: 0,\n last_xp_at: '${now()}',\n },\n },\n {\n action: 'set',\n key: 'userData',\n value: [{ xp: 0, level: 0, total_messages: 0, last_xp_at: null }],\n },\n ],\n },\n // Check cooldown\n {\n action: 'set',\n key: 'cooldownPassed',\n value: '${!userData[0].last_xp_at || (now() - userData[0].last_xp_at) > (config.leveling.xpCooldown || 60) * 1000}',\n },\n {\n action: 'flow_if',\n condition: '${cooldownPassed}',\n then: [\n // Calculate XP gain\n {\n action: 'set',\n key: 'xpRange',\n value: '${config.leveling.xpPerMessage || [15, 25]}',\n },\n {\n action: 'set',\n key: 'baseXpGain',\n value: '${random(xpRange[0], xpRange[1])}',\n },\n // Apply role multiplier\n {\n action: 'set',\n key: 'multiplier',\n value: '${config.leveling.roleMultipliers ? (member.roles | map(r => config.leveling.roleMultipliers[r.id] || 1) | max) : 1}',\n },\n {\n action: 'set',\n key: 'xpGain',\n value: '${floor(baseXpGain * multiplier)}',\n },\n // Calculate new XP and level\n {\n action: 'set',\n key: 'newXP',\n value: '${userData[0].xp + xpGain}',\n },\n {\n action: 'set',\n key: 'currentLevel',\n value: '${userData[0].level}',\n },\n // Calculate XP needed for next level\n {\n action: 'set',\n key: 'xpForNextLevel',\n value: '${config.leveling.xpCurve === \"exponential\" ? floor((config.leveling.baseXP || 100) * pow(config.leveling.xpMultiplier || 1.5, currentLevel)) : (config.leveling.baseXP || 100) * (currentLevel + 1)}',\n },\n // Check for level up\n {\n action: 'set',\n key: 'newLevel',\n value: '${newXP >= xpForNextLevel ? currentLevel + 1 : currentLevel}',\n },\n {\n action: 'set',\n key: 'leveledUp',\n value: '${newLevel > currentLevel}',\n },\n // Update database\n {\n action: 'db_update',\n table: 'levels',\n where: {\n user_id: '${user.id}',\n guild_id: '${guild.id}',\n },\n data: {\n xp: '${leveledUp ? newXP - xpForNextLevel : newXP}',\n level: '${newLevel}',\n total_messages: '${userData[0].total_messages + 1}',\n last_xp_at: '${now()}',\n },\n },\n // Handle level up\n {\n action: 'flow_if',\n condition: '${leveledUp}',\n then: [\n // Announce level up\n {\n action: 'flow_if',\n condition: '${config.leveling.announceChannel}',\n then: [\n {\n action: 'flow_if',\n condition: '${config.leveling.levelUpEmbed}',\n then: [\n {\n action: 'send_message',\n channel: '${config.leveling.announceChannel}',\n embed: {\n title: 'Level Up!',\n description: '${config.leveling.levelUpMessage || member.displayName + \" has reached level \" + newLevel + \"!\"}',\n color: '#ffd700',\n thumbnail: '${member.avatarURL}',\n },\n },\n ],\n else: [\n {\n action: 'send_message',\n channel: '${config.leveling.announceChannel}',\n content: '${config.leveling.levelUpMessage || \"Congratulations \" + member.displayName + \"! You reached level \" + newLevel + \"!\"}',\n },\n ],\n },\n ],\n },\n // Award role rewards\n {\n action: 'flow_if',\n condition: '${config.leveling.rewards && config.leveling.rewards[newLevel]}',\n then: [\n // Remove previous rewards if not stacking\n {\n action: 'flow_if',\n condition: '${!config.leveling.stackRewards && currentLevel > 0 && config.leveling.rewards[currentLevel]}',\n then: [\n {\n action: 'remove_role',\n user: '${member.id}',\n role: '${config.leveling.rewards[currentLevel]}',\n },\n ],\n },\n {\n action: 'assign_role',\n user: '${member.id}',\n role: '${config.leveling.rewards[newLevel]}',\n },\n ],\n },\n ],\n },\n ],\n },\n ],\n },\n];\n\nexport const levelingCommands: CommandDefinition[] = [\n {\n name: 'rank',\n description: 'View your rank or another user\\'s rank',\n options: [\n { name: 'user', description: 'User to check', type: 'user', required: false },\n ],\n actions: [\n {\n action: 'set',\n key: 'targetUser',\n value: '${args.user || user}',\n },\n {\n action: 'db_query',\n table: 'levels',\n where: {\n user_id: '${targetUser.id}',\n guild_id: '${guild.id}',\n },\n as: 'userData',\n },\n {\n action: 'flow_if',\n condition: '${!userData || userData.length === 0}',\n then: [\n {\n action: 'reply',\n content: '${targetUser.username} has no XP yet!',\n ephemeral: true,\n },\n ],\n else: [\n // Get leaderboard position\n {\n action: 'db_query',\n table: 'levels',\n where: {\n guild_id: '${guild.id}',\n },\n order_by: 'level DESC, xp DESC',\n as: 'leaderboard',\n },\n {\n action: 'set',\n key: 'rank',\n value: '${(leaderboard | findIndex(u => u.user_id === targetUser.id)) + 1}',\n },\n {\n action: 'set',\n key: 'xpForNextLevel',\n value: '${config.leveling.xpCurve === \"exponential\" ? floor((config.leveling.baseXP || 100) * pow(config.leveling.xpMultiplier || 1.5, userData[0].level)) : (config.leveling.baseXP || 100) * (userData[0].level + 1)}',\n },\n // Render rank card or embed\n {\n action: 'flow_if',\n condition: '${config.leveling.useRankCard}',\n then: [\n {\n action: 'canvas_render',\n generator: '${config.leveling.rankCardGenerator || \"rank_card\"}',\n context: {\n user: '${targetUser}',\n member: '${guild.members.cache.get(targetUser.id)}',\n level: '${userData[0].level}',\n xp: '${userData[0].xp}',\n xpNeeded: '${xpForNextLevel}',\n rank: '${rank}',\n totalMessages: '${userData[0].total_messages}',\n },\n as: 'rankCard',\n },\n {\n action: 'reply',\n files: [\n {\n attachment: '${rankCard}',\n name: 'rank.png',\n },\n ],\n },\n ],\n else: [\n {\n action: 'reply',\n embed: {\n title: '${targetUser.username}\\'s Rank',\n color: '#5865f2',\n thumbnail: '${targetUser.avatarURL}',\n fields: [\n { name: 'Rank', value: '#${rank}', inline: true },\n { name: 'Level', value: '${userData[0].level}', inline: true },\n { name: 'XP', value: '${userData[0].xp}/${xpForNextLevel}', inline: true },\n { name: 'Messages', value: '${userData[0].total_messages}', inline: true },\n ],\n },\n },\n ],\n },\n ],\n },\n ],\n },\n {\n name: 'leaderboard',\n description: 'View the server leaderboard',\n options: [\n { name: 'page', description: 'Page number', type: 'integer', required: false },\n ],\n actions: [\n {\n action: 'set',\n key: 'page',\n value: '${args.page || 1}',\n },\n {\n action: 'set',\n key: 'perPage',\n value: 10,\n },\n {\n action: 'db_query',\n table: 'levels',\n where: {\n guild_id: '${guild.id}',\n },\n order_by: 'level DESC, xp DESC',\n limit: '${perPage}',\n offset: '${(page - 1) * perPage}',\n as: 'leaderboard',\n },\n {\n action: 'set',\n key: 'leaderboardText',\n value: '${leaderboard | mapIndex((entry, i) => \"#\" + ((page - 1) * perPage + i + 1) + \" <@\" + entry.user_id + \"> - Level \" + entry.level + \" (\" + entry.xp + \" XP)\") | join(\"\\\\n\")}',\n },\n {\n action: 'reply',\n embed: {\n title: '${guild.name} Leaderboard',\n description: '${leaderboardText || \"No entries yet!\"}',\n color: '#ffd700',\n footer: {\n text: 'Page ${page}',\n },\n },\n },\n ],\n },\n {\n name: 'setxp',\n description: 'Set a user\\'s XP (admin)',\n options: [\n { name: 'user', description: 'User to modify', type: 'user', required: true },\n { name: 'xp', description: 'XP amount', type: 'integer', required: true },\n ],\n actions: [\n {\n action: 'db_update',\n table: 'levels',\n where: {\n user_id: '${args.user.id}',\n guild_id: '${guild.id}',\n },\n data: {\n xp: '${args.xp}',\n },\n upsert: true,\n },\n {\n action: 'reply',\n content: 'Set ${args.user.username}\\'s XP to ${args.xp}',\n ephemeral: true,\n },\n ],\n },\n {\n name: 'setlevel',\n description: 'Set a user\\'s level (admin)',\n options: [\n { name: 'user', description: 'User to modify', type: 'user', required: true },\n { name: 'level', description: 'Level', type: 'integer', required: true },\n ],\n actions: [\n {\n action: 'db_update',\n table: 'levels',\n where: {\n user_id: '${args.user.id}',\n guild_id: '${guild.id}',\n },\n data: {\n level: '${args.level}',\n xp: 0,\n },\n upsert: true,\n },\n {\n action: 'reply',\n content: 'Set ${args.user.username}\\'s level to ${args.level}',\n ephemeral: true,\n },\n ],\n },\n];\n\nexport const levelingCanvasGenerators: Record<string, CanvasGenerator> = {\n rank_card: {\n width: 934,\n height: 282,\n background: '#23272a',\n layers: [\n // Background gradient\n {\n type: 'rect',\n x: 0,\n y: 0,\n width: 934,\n height: 282,\n color: 'linear-gradient(135deg, #1a1c20 0%, #2c2f33 100%)',\n radius: 20,\n },\n // User avatar\n {\n type: 'circle_image',\n url: '${user.avatarURL || user.defaultAvatarURL}',\n x: 120,\n y: 141,\n radius: 80,\n border: {\n width: 5,\n color: '#5865f2',\n },\n },\n // Username\n {\n type: 'text',\n text: '${user.username}',\n x: 260,\n y: 120,\n font: 'bold 36px \"Poppins\", sans-serif',\n color: '#ffffff',\n align: 'left',\n },\n // Rank badge\n {\n type: 'text',\n text: 'RANK #${rank}',\n x: 850,\n y: 60,\n font: 'bold 24px \"Poppins\", sans-serif',\n color: '#7289da',\n align: 'right',\n },\n // Level badge\n {\n type: 'text',\n text: 'LEVEL ${level}',\n x: 850,\n y: 90,\n font: 'bold 32px \"Poppins\", sans-serif',\n color: '#ffffff',\n align: 'right',\n },\n // XP Progress bar background\n {\n type: 'rect',\n x: 260,\n y: 180,\n width: 600,\n height: 30,\n color: '#484b4e',\n radius: 15,\n },\n // XP Progress bar fill\n {\n type: 'progress_bar',\n x: 260,\n y: 180,\n width: 600,\n height: 30,\n progress: '${xp / xpNeeded}',\n color: 'linear-gradient(90deg, #5865f2 0%, #7289da 100%)',\n radius: 15,\n },\n // XP Text\n {\n type: 'text',\n text: '${xp} / ${xpNeeded} XP',\n x: 560,\n y: 160,\n font: '18px \"Poppins\", sans-serif',\n color: '#99aab5',\n align: 'center',\n },\n // Messages count\n {\n type: 'text',\n text: '${totalMessages} messages',\n x: 260,\n y: 240,\n font: '16px \"Poppins\", sans-serif',\n color: '#72767d',\n align: 'left',\n },\n ],\n },\n};\n\nexport function getLevelingSpec(config: LevelingConfig = {}): Partial<FurlowSpec> {\n return {\n events: levelingEventHandlers,\n commands: levelingCommands,\n state: {\n tables: levelingTables,\n },\n canvas: {\n generators: levelingCanvasGenerators,\n },\n };\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/leveling/index.ts"],"sourcesContent":["/**\n * Leveling builtin module\n * Handles XP, levels, rewards, leaderboards, and rank cards\n */\n\nimport type { FurlowSpec, CommandDefinition, EventHandler, CanvasGenerator, TableDefinition } from '@furlow/schema';\n\nexport interface LevelingConfig {\n /** XP per message range [min, max] */\n xpPerMessage?: [number, number];\n /** Cooldown between XP gains (seconds) */\n xpCooldown?: number;\n /** XP multiplier for roles */\n roleMultipliers?: Record<string, number>;\n /** Channels where XP is disabled */\n ignoredChannels?: string[];\n /** Roles that don't earn XP */\n ignoredRoles?: string[];\n /** Channel for level up announcements */\n announceChannel?: string;\n /** Level up message */\n levelUpMessage?: string;\n /** Use embed for level up */\n levelUpEmbed?: boolean;\n /** Level rewards (level -> role IDs) */\n rewards?: Record<number, string[]>;\n /** Stack rewards or remove previous */\n stackRewards?: boolean;\n /** Use rank card images */\n useRankCard?: boolean;\n /** Rank card generator name */\n rankCardGenerator?: string;\n /** XP curve formula */\n xpCurve?: 'linear' | 'exponential' | 'custom';\n /** Base XP for level 1 */\n baseXP?: number;\n /** XP multiplier per level */\n xpMultiplier?: number;\n}\n\nexport const levelingTables: Record<string, TableDefinition> = {\n levels: {\n columns: {\n id: { type: 'number', primary: true },\n user_id: { type: 'string', index: true },\n guild_id: { type: 'string', index: true },\n xp: { type: 'number', default: 0 },\n level: { type: 'number', default: 0 },\n total_messages: { type: 'number', default: 0 },\n last_xp_at: { type: 'timestamp' },\n },\n },\n};\n\nexport const levelingEventHandlers: EventHandler[] = [\n {\n event: 'message',\n condition: '!message.author.bot && !config.leveling.ignoredChannels?.includes(channel.id)',\n actions: [\n // Check cooldown\n {\n action: 'db_query',\n table: 'levels',\n where: {\n user_id: '${user.id}',\n guild_id: '${guild.id}',\n },\n as: 'userData',\n },\n // Initialize if new user\n {\n action: 'flow_if',\n condition: '!userData || userData.length === 0',\n then: [\n {\n action: 'db_insert',\n table: 'levels',\n data: {\n user_id: '${user.id}',\n guild_id: '${guild.id}',\n xp: 0,\n level: 0,\n total_messages: 0,\n last_xp_at: '${now()}',\n },\n },\n {\n action: 'set',\n key: 'userData',\n value: [{ xp: 0, level: 0, total_messages: 0, last_xp_at: null }],\n },\n ],\n },\n // Check cooldown\n {\n action: 'set',\n key: 'cooldownPassed',\n value: '${!userData[0].last_xp_at || (now() - userData[0].last_xp_at) > (config.leveling.xpCooldown || 60) * 1000}',\n },\n {\n action: 'flow_if',\n condition: 'cooldownPassed',\n then: [\n // Calculate XP gain\n {\n action: 'set',\n key: 'xpRange',\n value: '${config.leveling.xpPerMessage || [15, 25]}',\n },\n {\n action: 'set',\n key: 'baseXpGain',\n value: '${random(xpRange[0], xpRange[1])}',\n },\n // Apply role multiplier\n {\n action: 'set',\n key: 'multiplier',\n value: '${config.leveling.roleMultipliers ? (member.roles | map(r => config.leveling.roleMultipliers[r.id] || 1) | max) : 1}',\n },\n {\n action: 'set',\n key: 'xpGain',\n value: '${floor(baseXpGain * multiplier)}',\n },\n // Calculate new XP and level\n {\n action: 'set',\n key: 'newXP',\n value: '${userData[0].xp + xpGain}',\n },\n {\n action: 'set',\n key: 'currentLevel',\n value: '${userData[0].level}',\n },\n // Calculate XP needed for next level\n {\n action: 'set',\n key: 'xpForNextLevel',\n value: '${config.leveling.xpCurve === \"exponential\" ? floor((config.leveling.baseXP || 100) * pow(config.leveling.xpMultiplier || 1.5, currentLevel)) : (config.leveling.baseXP || 100) * (currentLevel + 1)}',\n },\n // Check for level up\n {\n action: 'set',\n key: 'newLevel',\n value: '${newXP >= xpForNextLevel ? currentLevel + 1 : currentLevel}',\n },\n {\n action: 'set',\n key: 'leveledUp',\n value: '${newLevel > currentLevel}',\n },\n // Update database\n {\n action: 'db_update',\n table: 'levels',\n where: {\n user_id: '${user.id}',\n guild_id: '${guild.id}',\n },\n data: {\n xp: '${leveledUp ? newXP - xpForNextLevel : newXP}',\n level: '${newLevel}',\n total_messages: '${userData[0].total_messages + 1}',\n last_xp_at: '${now()}',\n },\n },\n // Handle level up\n {\n action: 'flow_if',\n condition: 'leveledUp',\n then: [\n // Announce level up\n {\n action: 'flow_if',\n condition: 'config.leveling.announceChannel',\n then: [\n {\n action: 'flow_if',\n condition: 'config.leveling.levelUpEmbed',\n then: [\n {\n action: 'send_message',\n channel: '${config.leveling.announceChannel}',\n embed: {\n title: 'Level Up!',\n description: '${config.leveling.levelUpMessage || member.display_name + \" has reached level \" + newLevel + \"!\"}',\n color: '#ffd700',\n thumbnail: '${member.avatar}',\n },\n },\n ],\n else: [\n {\n action: 'send_message',\n channel: '${config.leveling.announceChannel}',\n content: '${config.leveling.levelUpMessage || \"Congratulations \" + member.display_name + \"! You reached level \" + newLevel + \"!\"}',\n },\n ],\n },\n ],\n },\n // Award role rewards\n {\n action: 'flow_if',\n condition: 'config.leveling.rewards && config.leveling.rewards[newLevel]',\n then: [\n // Remove previous rewards if not stacking\n {\n action: 'flow_if',\n condition: '!config.leveling.stackRewards && currentLevel > 0 && config.leveling.rewards[currentLevel]',\n then: [\n {\n action: 'remove_role',\n user: '${member.id}',\n role: '${config.leveling.rewards[currentLevel]}',\n },\n ],\n },\n {\n action: 'assign_role',\n user: '${member.id}',\n role: '${config.leveling.rewards[newLevel]}',\n },\n ],\n },\n ],\n },\n ],\n },\n ],\n },\n];\n\nexport const levelingCommands: CommandDefinition[] = [\n {\n name: 'rank',\n description: 'View your rank or another user\\'s rank',\n options: [\n { name: 'user', description: 'User to check', type: 'user', required: false },\n ],\n actions: [\n {\n action: 'set',\n key: 'targetUser',\n value: '${args.user || user}',\n },\n {\n action: 'db_query',\n table: 'levels',\n where: {\n user_id: '${targetUser.id}',\n guild_id: '${guild.id}',\n },\n as: 'userData',\n },\n {\n action: 'flow_if',\n condition: '!userData || userData.length === 0',\n then: [\n {\n action: 'reply',\n content: '${targetUser.username} has no XP yet!',\n ephemeral: true,\n },\n ],\n else: [\n // Get leaderboard position\n {\n action: 'db_query',\n table: 'levels',\n where: {\n guild_id: '${guild.id}',\n },\n order_by: 'level DESC, xp DESC',\n as: 'leaderboard',\n },\n {\n action: 'set',\n key: 'rank',\n value: '${(leaderboard | findIndex(u => u.user_id === targetUser.id)) + 1}',\n },\n {\n action: 'set',\n key: 'xpForNextLevel',\n value: '${config.leveling.xpCurve === \"exponential\" ? floor((config.leveling.baseXP || 100) * pow(config.leveling.xpMultiplier || 1.5, userData[0].level)) : (config.leveling.baseXP || 100) * (userData[0].level + 1)}',\n },\n // Render rank card or embed\n {\n action: 'flow_if',\n condition: 'config.leveling.useRankCard',\n then: [\n {\n action: 'canvas_render',\n generator: '${config.leveling.rankCardGenerator || \"rank_card\"}',\n context: {\n user: '${targetUser}',\n member: '${guild.members.cache.get(targetUser.id)}',\n level: '${userData[0].level}',\n xp: '${userData[0].xp}',\n xpNeeded: '${xpForNextLevel}',\n rank: '${rank}',\n totalMessages: '${userData[0].total_messages}',\n },\n as: 'rankCard',\n },\n {\n action: 'reply',\n files: [\n {\n attachment: '${rankCard}',\n name: 'rank.png',\n },\n ],\n },\n ],\n else: [\n {\n action: 'reply',\n embed: {\n title: '${targetUser.username}\\'s Rank',\n color: '#5865f2',\n thumbnail: '${targetUser.avatar}',\n fields: [\n { name: 'Rank', value: '#${rank}', inline: true },\n { name: 'Level', value: '${userData[0].level}', inline: true },\n { name: 'XP', value: '${userData[0].xp}/${xpForNextLevel}', inline: true },\n { name: 'Messages', value: '${userData[0].total_messages}', inline: true },\n ],\n },\n },\n ],\n },\n ],\n },\n ],\n },\n {\n name: 'leaderboard',\n description: 'View the server leaderboard',\n options: [\n { name: 'page', description: 'Page number', type: 'integer', required: false },\n ],\n actions: [\n {\n action: 'set',\n key: 'page',\n value: '${args.page || 1}',\n },\n {\n action: 'set',\n key: 'perPage',\n value: 10,\n },\n {\n action: 'db_query',\n table: 'levels',\n where: {\n guild_id: '${guild.id}',\n },\n order_by: 'level DESC, xp DESC',\n limit: '${perPage}',\n offset: '${(page - 1) * perPage}',\n as: 'leaderboard',\n },\n {\n action: 'set',\n key: 'leaderboardText',\n value: '${leaderboard | mapIndex((entry, i) => \"#\" + ((page - 1) * perPage + i + 1) + \" <@\" + entry.user_id + \"> - Level \" + entry.level + \" (\" + entry.xp + \" XP)\") | join(\"\\\\n\")}',\n },\n {\n action: 'reply',\n embed: {\n title: '${guild.name} Leaderboard',\n description: '${leaderboardText || \"No entries yet!\"}',\n color: '#ffd700',\n footer: {\n text: 'Page ${page}',\n },\n },\n },\n ],\n },\n {\n name: 'setxp',\n description: 'Set a user\\'s XP (admin)',\n options: [\n { name: 'user', description: 'User to modify', type: 'user', required: true },\n { name: 'xp', description: 'XP amount', type: 'integer', required: true },\n ],\n actions: [\n {\n action: 'db_update',\n table: 'levels',\n where: {\n user_id: '${args.user.id}',\n guild_id: '${guild.id}',\n },\n data: {\n xp: '${args.xp}',\n },\n upsert: true,\n },\n {\n action: 'reply',\n content: 'Set ${args.user.username}\\'s XP to ${args.xp}',\n ephemeral: true,\n },\n ],\n },\n {\n name: 'setlevel',\n description: 'Set a user\\'s level (admin)',\n options: [\n { name: 'user', description: 'User to modify', type: 'user', required: true },\n { name: 'level', description: 'Level', type: 'integer', required: true },\n ],\n actions: [\n {\n action: 'db_update',\n table: 'levels',\n where: {\n user_id: '${args.user.id}',\n guild_id: '${guild.id}',\n },\n data: {\n level: '${args.level}',\n xp: 0,\n },\n upsert: true,\n },\n {\n action: 'reply',\n content: 'Set ${args.user.username}\\'s level to ${args.level}',\n ephemeral: true,\n },\n ],\n },\n];\n\nexport const levelingCanvasGenerators: Record<string, CanvasGenerator> = {\n rank_card: {\n width: 934,\n height: 282,\n background: '#23272a',\n layers: [\n // Background gradient\n {\n type: 'rect',\n x: 0,\n y: 0,\n width: 934,\n height: 282,\n color: 'linear-gradient(135deg, #1a1c20 0%, #2c2f33 100%)',\n radius: 20,\n },\n // User avatar\n {\n type: 'circle_image',\n url: '${user.avatar}',\n x: 120,\n y: 141,\n radius: 80,\n border: {\n width: 5,\n color: '#5865f2',\n },\n },\n // Username\n {\n type: 'text',\n text: '${user.username}',\n x: 260,\n y: 120,\n font: 'bold 36px \"Poppins\", sans-serif',\n color: '#ffffff',\n align: 'left',\n },\n // Rank badge\n {\n type: 'text',\n text: 'RANK #${rank}',\n x: 850,\n y: 60,\n font: 'bold 24px \"Poppins\", sans-serif',\n color: '#7289da',\n align: 'right',\n },\n // Level badge\n {\n type: 'text',\n text: 'LEVEL ${level}',\n x: 850,\n y: 90,\n font: 'bold 32px \"Poppins\", sans-serif',\n color: '#ffffff',\n align: 'right',\n },\n // XP Progress bar background\n {\n type: 'rect',\n x: 260,\n y: 180,\n width: 600,\n height: 30,\n color: '#484b4e',\n radius: 15,\n },\n // XP Progress bar fill\n {\n type: 'progress_bar',\n x: 260,\n y: 180,\n width: 600,\n height: 30,\n progress: '${xp / xpNeeded}',\n color: 'linear-gradient(90deg, #5865f2 0%, #7289da 100%)',\n radius: 15,\n },\n // XP Text\n {\n type: 'text',\n text: '${xp} / ${xpNeeded} XP',\n x: 560,\n y: 160,\n font: '18px \"Poppins\", sans-serif',\n color: '#99aab5',\n align: 'center',\n },\n // Messages count\n {\n type: 'text',\n text: '${totalMessages} messages',\n x: 260,\n y: 240,\n font: '16px \"Poppins\", sans-serif',\n color: '#72767d',\n align: 'left',\n },\n ],\n },\n};\n\nexport function getLevelingSpec(config: LevelingConfig = {}): Partial<FurlowSpec> {\n return {\n events: levelingEventHandlers,\n commands: levelingCommands,\n state: {\n tables: levelingTables,\n },\n canvas: {\n generators: levelingCanvasGenerators,\n },\n };\n}\n"],"mappings":"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","names":[]}
|
package/dist/logging/index.js
CHANGED
|
@@ -3,7 +3,7 @@ var loggingEventHandlers = [
|
|
|
3
3
|
// Message Delete
|
|
4
4
|
{
|
|
5
5
|
event: "message_delete",
|
|
6
|
-
condition: "
|
|
6
|
+
condition: "config.logging.events?.messageDelete !== false && !config.logging.ignoredChannels?.includes(channel.id)",
|
|
7
7
|
actions: [
|
|
8
8
|
{
|
|
9
9
|
action: "send_message",
|
|
@@ -28,7 +28,7 @@ var loggingEventHandlers = [
|
|
|
28
28
|
// Message Edit
|
|
29
29
|
{
|
|
30
30
|
event: "message_update",
|
|
31
|
-
condition: "
|
|
31
|
+
condition: "config.logging.events?.messageEdit !== false && oldMessage.content !== newMessage.content && !config.logging.ignoredChannels?.includes(channel.id)",
|
|
32
32
|
actions: [
|
|
33
33
|
{
|
|
34
34
|
action: "send_message",
|
|
@@ -54,7 +54,7 @@ var loggingEventHandlers = [
|
|
|
54
54
|
// Bulk Message Delete
|
|
55
55
|
{
|
|
56
56
|
event: "message_bulk_delete",
|
|
57
|
-
condition: "
|
|
57
|
+
condition: "config.logging.events?.messageBulkDelete !== false",
|
|
58
58
|
actions: [
|
|
59
59
|
{
|
|
60
60
|
action: "set",
|
|
@@ -82,12 +82,12 @@ var loggingEventHandlers = [
|
|
|
82
82
|
// Member Join
|
|
83
83
|
{
|
|
84
84
|
event: "member_join",
|
|
85
|
-
condition: "
|
|
85
|
+
condition: "config.logging.events?.memberJoin !== false",
|
|
86
86
|
actions: [
|
|
87
87
|
{
|
|
88
88
|
action: "set",
|
|
89
89
|
key: "accountAge",
|
|
90
|
-
value: "${floor((now() - member.
|
|
90
|
+
value: "${floor((now() - member.joined_at) / (1000 * 60 * 60 * 24))}"
|
|
91
91
|
},
|
|
92
92
|
{
|
|
93
93
|
action: "send_message",
|
|
@@ -96,11 +96,11 @@ var loggingEventHandlers = [
|
|
|
96
96
|
title: "Member Joined",
|
|
97
97
|
description: "<@${member.id}> joined the server",
|
|
98
98
|
color: "#57f287",
|
|
99
|
-
thumbnail: "${member.
|
|
99
|
+
thumbnail: "${member.avatar}",
|
|
100
100
|
fields: [
|
|
101
101
|
{ name: "Username", value: "${member.user.tag}", inline: true },
|
|
102
102
|
{ name: "Account Age", value: "${accountAge} days", inline: true },
|
|
103
|
-
{ name: "Member Count", value: "${guild.
|
|
103
|
+
{ name: "Member Count", value: "${guild.member_count}", inline: true }
|
|
104
104
|
],
|
|
105
105
|
footer: {
|
|
106
106
|
text: "User ID: ${member.id}"
|
|
@@ -113,7 +113,7 @@ var loggingEventHandlers = [
|
|
|
113
113
|
// Member Leave
|
|
114
114
|
{
|
|
115
115
|
event: "member_leave",
|
|
116
|
-
condition: "
|
|
116
|
+
condition: "config.logging.events?.memberLeave !== false",
|
|
117
117
|
actions: [
|
|
118
118
|
{
|
|
119
119
|
action: "set",
|
|
@@ -127,11 +127,11 @@ var loggingEventHandlers = [
|
|
|
127
127
|
title: "Member Left",
|
|
128
128
|
description: "<@${member.id}> left the server",
|
|
129
129
|
color: "#ed4245",
|
|
130
|
-
thumbnail: "${member.
|
|
130
|
+
thumbnail: "${member.avatar}",
|
|
131
131
|
fields: [
|
|
132
132
|
{ name: "Username", value: "${member.user.tag}", inline: true },
|
|
133
133
|
{ name: "Roles", value: "${truncate(roles, 1024)}", inline: false },
|
|
134
|
-
{ name: "Joined At", value: '${timestamp(member.
|
|
134
|
+
{ name: "Joined At", value: '${timestamp(member.joined_at, "R")}', inline: true }
|
|
135
135
|
],
|
|
136
136
|
footer: {
|
|
137
137
|
text: "User ID: ${member.id}"
|
|
@@ -144,12 +144,12 @@ var loggingEventHandlers = [
|
|
|
144
144
|
// Member Update (roles, nickname)
|
|
145
145
|
{
|
|
146
146
|
event: "member_update",
|
|
147
|
-
condition: "
|
|
147
|
+
condition: "config.logging.events?.memberUpdate !== false",
|
|
148
148
|
actions: [
|
|
149
149
|
// Role changes
|
|
150
150
|
{
|
|
151
151
|
action: "flow_if",
|
|
152
|
-
condition: "
|
|
152
|
+
condition: "oldMember.roles.cache.size !== newMember.roles.cache.size",
|
|
153
153
|
then: [
|
|
154
154
|
{
|
|
155
155
|
action: "set",
|
|
@@ -183,7 +183,7 @@ var loggingEventHandlers = [
|
|
|
183
183
|
// Nickname changes
|
|
184
184
|
{
|
|
185
185
|
action: "flow_if",
|
|
186
|
-
condition: "
|
|
186
|
+
condition: "oldMember.nickname !== newMember.nickname",
|
|
187
187
|
then: [
|
|
188
188
|
{
|
|
189
189
|
action: "send_message",
|
|
@@ -209,7 +209,7 @@ var loggingEventHandlers = [
|
|
|
209
209
|
// Member Ban
|
|
210
210
|
{
|
|
211
211
|
event: "member_ban",
|
|
212
|
-
condition: "
|
|
212
|
+
condition: "config.logging.events?.memberBan !== false",
|
|
213
213
|
actions: [
|
|
214
214
|
{
|
|
215
215
|
action: "send_message",
|
|
@@ -218,7 +218,7 @@ var loggingEventHandlers = [
|
|
|
218
218
|
title: "Member Banned",
|
|
219
219
|
description: "<@${user.id}> was banned",
|
|
220
220
|
color: "#ed4245",
|
|
221
|
-
thumbnail: "${user.
|
|
221
|
+
thumbnail: "${user.avatar}",
|
|
222
222
|
fields: [
|
|
223
223
|
{ name: "Username", value: "${user.tag}", inline: true },
|
|
224
224
|
{ name: "Reason", value: '${ban.reason || "No reason provided"}', inline: false }
|
|
@@ -234,7 +234,7 @@ var loggingEventHandlers = [
|
|
|
234
234
|
// Member Unban
|
|
235
235
|
{
|
|
236
236
|
event: "member_unban",
|
|
237
|
-
condition: "
|
|
237
|
+
condition: "config.logging.events?.memberUnban !== false",
|
|
238
238
|
actions: [
|
|
239
239
|
{
|
|
240
240
|
action: "send_message",
|
|
@@ -243,7 +243,7 @@ var loggingEventHandlers = [
|
|
|
243
243
|
title: "Member Unbanned",
|
|
244
244
|
description: "<@${user.id}> was unbanned",
|
|
245
245
|
color: "#57f287",
|
|
246
|
-
thumbnail: "${user.
|
|
246
|
+
thumbnail: "${user.avatar}",
|
|
247
247
|
fields: [
|
|
248
248
|
{ name: "Username", value: "${user.tag}", inline: true }
|
|
249
249
|
],
|
|
@@ -258,7 +258,7 @@ var loggingEventHandlers = [
|
|
|
258
258
|
// Voice Join
|
|
259
259
|
{
|
|
260
260
|
event: "voice_join",
|
|
261
|
-
condition: "
|
|
261
|
+
condition: "config.logging.events?.voiceJoin !== false",
|
|
262
262
|
actions: [
|
|
263
263
|
{
|
|
264
264
|
action: "send_message",
|
|
@@ -278,7 +278,7 @@ var loggingEventHandlers = [
|
|
|
278
278
|
// Voice Leave
|
|
279
279
|
{
|
|
280
280
|
event: "voice_leave",
|
|
281
|
-
condition: "
|
|
281
|
+
condition: "config.logging.events?.voiceLeave !== false",
|
|
282
282
|
actions: [
|
|
283
283
|
{
|
|
284
284
|
action: "send_message",
|
|
@@ -298,7 +298,7 @@ var loggingEventHandlers = [
|
|
|
298
298
|
// Voice Move
|
|
299
299
|
{
|
|
300
300
|
event: "voice_move",
|
|
301
|
-
condition: "
|
|
301
|
+
condition: "config.logging.events?.voiceMove !== false",
|
|
302
302
|
actions: [
|
|
303
303
|
{
|
|
304
304
|
action: "send_message",
|
|
@@ -322,7 +322,7 @@ var loggingEventHandlers = [
|
|
|
322
322
|
// Channel Create
|
|
323
323
|
{
|
|
324
324
|
event: "channel_create",
|
|
325
|
-
condition: "
|
|
325
|
+
condition: "config.logging.events?.channelCreate !== false",
|
|
326
326
|
actions: [
|
|
327
327
|
{
|
|
328
328
|
action: "send_message",
|
|
@@ -343,7 +343,7 @@ var loggingEventHandlers = [
|
|
|
343
343
|
// Channel Delete
|
|
344
344
|
{
|
|
345
345
|
event: "channel_delete",
|
|
346
|
-
condition: "
|
|
346
|
+
condition: "config.logging.events?.channelDelete !== false",
|
|
347
347
|
actions: [
|
|
348
348
|
{
|
|
349
349
|
action: "send_message",
|
|
@@ -363,7 +363,7 @@ var loggingEventHandlers = [
|
|
|
363
363
|
// Role Create
|
|
364
364
|
{
|
|
365
365
|
event: "role_create",
|
|
366
|
-
condition: "
|
|
366
|
+
condition: "config.logging.events?.roleCreate !== false",
|
|
367
367
|
actions: [
|
|
368
368
|
{
|
|
369
369
|
action: "send_message",
|
|
@@ -388,7 +388,7 @@ var loggingEventHandlers = [
|
|
|
388
388
|
// Role Delete
|
|
389
389
|
{
|
|
390
390
|
event: "role_delete",
|
|
391
|
-
condition: "
|
|
391
|
+
condition: "config.logging.events?.roleDelete !== false",
|
|
392
392
|
actions: [
|
|
393
393
|
{
|
|
394
394
|
action: "send_message",
|
|
@@ -428,7 +428,7 @@ var loggingCommands = [
|
|
|
428
428
|
actions: [
|
|
429
429
|
{
|
|
430
430
|
action: "flow_if",
|
|
431
|
-
condition: '
|
|
431
|
+
condition: '!args.category || args.category === "all"',
|
|
432
432
|
then: [
|
|
433
433
|
{
|
|
434
434
|
action: "set",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/logging/index.ts"],"sourcesContent":["/**\n * Logging builtin module\n * Handles comprehensive server logging for messages, members, voice, and moderation\n */\n\nimport type { FurlowSpec, CommandDefinition, EventHandler } from '@furlow/schema';\n\nexport interface LoggingConfig {\n /** Default log channel */\n channel?: string;\n /** Separate channels per category */\n channels?: {\n messages?: string;\n members?: string;\n voice?: string;\n server?: string;\n moderation?: string;\n };\n /** Ignored channels */\n ignoredChannels?: string[];\n /** Ignored roles (users with these roles won't be logged) */\n ignoredRoles?: string[];\n /** Events to log */\n events?: {\n messageDelete?: boolean;\n messageEdit?: boolean;\n messageBulkDelete?: boolean;\n memberJoin?: boolean;\n memberLeave?: boolean;\n memberUpdate?: boolean;\n memberBan?: boolean;\n memberUnban?: boolean;\n voiceJoin?: boolean;\n voiceLeave?: boolean;\n voiceMove?: boolean;\n channelCreate?: boolean;\n channelDelete?: boolean;\n channelUpdate?: boolean;\n roleCreate?: boolean;\n roleDelete?: boolean;\n roleUpdate?: boolean;\n inviteCreate?: boolean;\n inviteDelete?: boolean;\n };\n /** Include images in logs */\n includeImages?: boolean;\n}\n\nexport const loggingEventHandlers: EventHandler[] = [\n // Message Delete\n {\n event: 'message_delete',\n condition: '${config.logging.events?.messageDelete !== false && !config.logging.ignoredChannels?.includes(channel.id)}',\n actions: [\n {\n action: 'send_message',\n channel: '${config.logging.channels?.messages || config.logging.channel}',\n embed: {\n title: 'Message Deleted',\n description: '${message.content || \"*No text content*\"}',\n color: '#ed4245',\n fields: [\n { name: 'Author', value: '${message.author ? \"<@\" + message.author.id + \">\" : \"Unknown\"}', inline: true },\n { name: 'Channel', value: '<#${channel.id}>', inline: true },\n { name: 'Message ID', value: '${message.id}', inline: true },\n ],\n footer: {\n text: 'User ID: ${message.author?.id || \"Unknown\"}',\n },\n timestamp: '${now()}',\n },\n },\n ],\n },\n // Message Edit\n {\n event: 'message_update',\n condition: '${config.logging.events?.messageEdit !== false && oldMessage.content !== newMessage.content && !config.logging.ignoredChannels?.includes(channel.id)}',\n actions: [\n {\n action: 'send_message',\n channel: '${config.logging.channels?.messages || config.logging.channel}',\n embed: {\n title: 'Message Edited',\n color: '#fee75c',\n fields: [\n { name: 'Before', value: '${truncate(oldMessage.content || \"*Empty*\", 1024)}' },\n { name: 'After', value: '${truncate(newMessage.content || \"*Empty*\", 1024)}' },\n { name: 'Author', value: '<@${newMessage.author.id}>', inline: true },\n { name: 'Channel', value: '<#${channel.id}>', inline: true },\n { name: 'Jump to Message', value: '[Click here](${newMessage.url})', inline: true },\n ],\n footer: {\n text: 'User ID: ${newMessage.author.id}',\n },\n timestamp: '${now()}',\n },\n },\n ],\n },\n // Bulk Message Delete\n {\n event: 'message_bulk_delete',\n condition: '${config.logging.events?.messageBulkDelete !== false}',\n actions: [\n {\n action: 'set',\n key: 'logContent',\n value: '${messages | map(m => \"[\" + (m.author?.tag || \"Unknown\") + \"]: \" + (m.content || \"*attachment/embed*\")) | join(\"\\\\n\")}',\n },\n {\n action: 'send_message',\n channel: '${config.logging.channels?.messages || config.logging.channel}',\n embed: {\n title: 'Bulk Messages Deleted',\n description: '${messages.length} messages were deleted in <#${channel.id}>',\n color: '#ed4245',\n timestamp: '${now()}',\n },\n files: [\n {\n attachment: '${Buffer.from(logContent)}',\n name: 'deleted-messages.txt',\n },\n ],\n },\n ],\n },\n // Member Join\n {\n event: 'member_join',\n condition: '${config.logging.events?.memberJoin !== false}',\n actions: [\n {\n action: 'set',\n key: 'accountAge',\n value: '${floor((now() - member.user.createdAt) / (1000 * 60 * 60 * 24))}',\n },\n {\n action: 'send_message',\n channel: '${config.logging.channels?.members || config.logging.channel}',\n embed: {\n title: 'Member Joined',\n description: '<@${member.id}> joined the server',\n color: '#57f287',\n thumbnail: '${member.user.avatarURL}',\n fields: [\n { name: 'Username', value: '${member.user.tag}', inline: true },\n { name: 'Account Age', value: '${accountAge} days', inline: true },\n { name: 'Member Count', value: '${guild.memberCount}', inline: true },\n ],\n footer: {\n text: 'User ID: ${member.id}',\n },\n timestamp: '${now()}',\n },\n },\n ],\n },\n // Member Leave\n {\n event: 'member_leave',\n condition: '${config.logging.events?.memberLeave !== false}',\n actions: [\n {\n action: 'set',\n key: 'roles',\n value: '${member.roles?.cache?.filter(r => r.id !== guild.id)?.map(r => r.name)?.join(\", \") || \"None\"}',\n },\n {\n action: 'send_message',\n channel: '${config.logging.channels?.members || config.logging.channel}',\n embed: {\n title: 'Member Left',\n description: '<@${member.id}> left the server',\n color: '#ed4245',\n thumbnail: '${member.user.avatarURL}',\n fields: [\n { name: 'Username', value: '${member.user.tag}', inline: true },\n { name: 'Roles', value: '${truncate(roles, 1024)}', inline: false },\n { name: 'Joined At', value: '${timestamp(member.joinedAt, \"R\")}', inline: true },\n ],\n footer: {\n text: 'User ID: ${member.id}',\n },\n timestamp: '${now()}',\n },\n },\n ],\n },\n // Member Update (roles, nickname)\n {\n event: 'member_update',\n condition: '${config.logging.events?.memberUpdate !== false}',\n actions: [\n // Role changes\n {\n action: 'flow_if',\n condition: '${oldMember.roles.cache.size !== newMember.roles.cache.size}',\n then: [\n {\n action: 'set',\n key: 'addedRoles',\n value: '${newMember.roles.cache.filter(r => !oldMember.roles.cache.has(r.id)).map(r => r.name).join(\", \")}',\n },\n {\n action: 'set',\n key: 'removedRoles',\n value: '${oldMember.roles.cache.filter(r => !newMember.roles.cache.has(r.id)).map(r => r.name).join(\", \")}',\n },\n {\n action: 'send_message',\n channel: '${config.logging.channels?.members || config.logging.channel}',\n embed: {\n title: 'Member Roles Updated',\n description: '<@${newMember.id}>\\'s roles were changed',\n color: '#5865f2',\n fields: [\n { name: 'Added Roles', value: '${addedRoles || \"None\"}', inline: true },\n { name: 'Removed Roles', value: '${removedRoles || \"None\"}', inline: true },\n ],\n footer: {\n text: 'User ID: ${newMember.id}',\n },\n timestamp: '${now()}',\n },\n },\n ],\n },\n // Nickname changes\n {\n action: 'flow_if',\n condition: '${oldMember.nickname !== newMember.nickname}',\n then: [\n {\n action: 'send_message',\n channel: '${config.logging.channels?.members || config.logging.channel}',\n embed: {\n title: 'Nickname Changed',\n description: '<@${newMember.id}>\\'s nickname was changed',\n color: '#5865f2',\n fields: [\n { name: 'Before', value: '${oldMember.nickname || oldMember.user.username}', inline: true },\n { name: 'After', value: '${newMember.nickname || newMember.user.username}', inline: true },\n ],\n footer: {\n text: 'User ID: ${newMember.id}',\n },\n timestamp: '${now()}',\n },\n },\n ],\n },\n ],\n },\n // Member Ban\n {\n event: 'member_ban',\n condition: '${config.logging.events?.memberBan !== false}',\n actions: [\n {\n action: 'send_message',\n channel: '${config.logging.channels?.moderation || config.logging.channel}',\n embed: {\n title: 'Member Banned',\n description: '<@${user.id}> was banned',\n color: '#ed4245',\n thumbnail: '${user.avatarURL}',\n fields: [\n { name: 'Username', value: '${user.tag}', inline: true },\n { name: 'Reason', value: '${ban.reason || \"No reason provided\"}', inline: false },\n ],\n footer: {\n text: 'User ID: ${user.id}',\n },\n timestamp: '${now()}',\n },\n },\n ],\n },\n // Member Unban\n {\n event: 'member_unban',\n condition: '${config.logging.events?.memberUnban !== false}',\n actions: [\n {\n action: 'send_message',\n channel: '${config.logging.channels?.moderation || config.logging.channel}',\n embed: {\n title: 'Member Unbanned',\n description: '<@${user.id}> was unbanned',\n color: '#57f287',\n thumbnail: '${user.avatarURL}',\n fields: [\n { name: 'Username', value: '${user.tag}', inline: true },\n ],\n footer: {\n text: 'User ID: ${user.id}',\n },\n timestamp: '${now()}',\n },\n },\n ],\n },\n // Voice Join\n {\n event: 'voice_join',\n condition: '${config.logging.events?.voiceJoin !== false}',\n actions: [\n {\n action: 'send_message',\n channel: '${config.logging.channels?.voice || config.logging.channel}',\n embed: {\n title: 'Voice Channel Joined',\n description: '<@${member.id}> joined <#${channel.id}>',\n color: '#57f287',\n footer: {\n text: 'User ID: ${member.id}',\n },\n timestamp: '${now()}',\n },\n },\n ],\n },\n // Voice Leave\n {\n event: 'voice_leave',\n condition: '${config.logging.events?.voiceLeave !== false}',\n actions: [\n {\n action: 'send_message',\n channel: '${config.logging.channels?.voice || config.logging.channel}',\n embed: {\n title: 'Voice Channel Left',\n description: '<@${member.id}> left <#${channel.id}>',\n color: '#ed4245',\n footer: {\n text: 'User ID: ${member.id}',\n },\n timestamp: '${now()}',\n },\n },\n ],\n },\n // Voice Move\n {\n event: 'voice_move',\n condition: '${config.logging.events?.voiceMove !== false}',\n actions: [\n {\n action: 'send_message',\n channel: '${config.logging.channels?.voice || config.logging.channel}',\n embed: {\n title: 'Voice Channel Switch',\n description: '<@${member.id}> switched voice channels',\n color: '#5865f2',\n fields: [\n { name: 'From', value: '<#${oldChannel.id}>', inline: true },\n { name: 'To', value: '<#${newChannel.id}>', inline: true },\n ],\n footer: {\n text: 'User ID: ${member.id}',\n },\n timestamp: '${now()}',\n },\n },\n ],\n },\n // Channel Create\n {\n event: 'channel_create',\n condition: '${config.logging.events?.channelCreate !== false}',\n actions: [\n {\n action: 'send_message',\n channel: '${config.logging.channels?.server || config.logging.channel}',\n embed: {\n title: 'Channel Created',\n description: '<#${channel.id}> was created',\n color: '#57f287',\n fields: [\n { name: 'Name', value: '${channel.name}', inline: true },\n { name: 'Type', value: '${channel.type}', inline: true },\n ],\n timestamp: '${now()}',\n },\n },\n ],\n },\n // Channel Delete\n {\n event: 'channel_delete',\n condition: '${config.logging.events?.channelDelete !== false}',\n actions: [\n {\n action: 'send_message',\n channel: '${config.logging.channels?.server || config.logging.channel}',\n embed: {\n title: 'Channel Deleted',\n description: '#${channel.name} was deleted',\n color: '#ed4245',\n fields: [\n { name: 'Type', value: '${channel.type}', inline: true },\n ],\n timestamp: '${now()}',\n },\n },\n ],\n },\n // Role Create\n {\n event: 'role_create',\n condition: '${config.logging.events?.roleCreate !== false}',\n actions: [\n {\n action: 'send_message',\n channel: '${config.logging.channels?.server || config.logging.channel}',\n embed: {\n title: 'Role Created',\n description: '${role.name} was created',\n color: '${role.hexColor || \"#57f287\"}',\n fields: [\n { name: 'Color', value: '${role.hexColor || \"None\"}', inline: true },\n { name: 'Hoisted', value: '${role.hoist ? \"Yes\" : \"No\"}', inline: true },\n { name: 'Mentionable', value: '${role.mentionable ? \"Yes\" : \"No\"}', inline: true },\n ],\n footer: {\n text: 'Role ID: ${role.id}',\n },\n timestamp: '${now()}',\n },\n },\n ],\n },\n // Role Delete\n {\n event: 'role_delete',\n condition: '${config.logging.events?.roleDelete !== false}',\n actions: [\n {\n action: 'send_message',\n channel: '${config.logging.channels?.server || config.logging.channel}',\n embed: {\n title: 'Role Deleted',\n description: '${role.name} was deleted',\n color: '#ed4245',\n footer: {\n text: 'Role ID: ${role.id}',\n },\n timestamp: '${now()}',\n },\n },\n ],\n },\n];\n\nexport const loggingCommands: CommandDefinition[] = [\n {\n name: 'logging',\n description: 'Logging configuration commands',\n subcommands: [\n {\n name: 'set-channel',\n description: 'Set the logging channel',\n options: [\n { name: 'channel', description: 'Channel for logs', type: 'channel', required: true },\n { name: 'category', description: 'Log category', type: 'string', required: false, choices: [\n { name: 'All', value: 'all' },\n { name: 'Messages', value: 'messages' },\n { name: 'Members', value: 'members' },\n { name: 'Voice', value: 'voice' },\n { name: 'Server', value: 'server' },\n { name: 'Moderation', value: 'moderation' },\n ]},\n ],\n actions: [\n {\n action: 'flow_if',\n condition: '${!args.category || args.category === \"all\"}',\n then: [\n {\n action: 'set',\n key: 'config.logging.channel',\n value: '${args.channel.id}',\n scope: 'guild',\n },\n ],\n else: [\n {\n action: 'set',\n key: 'config.logging.channels.${args.category}',\n value: '${args.channel.id}',\n scope: 'guild',\n },\n ],\n },\n {\n action: 'reply',\n content: 'Logging channel updated!',\n ephemeral: true,\n },\n ],\n },\n {\n name: 'toggle',\n description: 'Toggle a logging event',\n options: [\n { name: 'event', description: 'Event to toggle', type: 'string', required: true, choices: [\n { name: 'Message Delete', value: 'messageDelete' },\n { name: 'Message Edit', value: 'messageEdit' },\n { name: 'Member Join', value: 'memberJoin' },\n { name: 'Member Leave', value: 'memberLeave' },\n { name: 'Member Ban', value: 'memberBan' },\n { name: 'Voice Join', value: 'voiceJoin' },\n { name: 'Voice Leave', value: 'voiceLeave' },\n ]},\n { name: 'enabled', description: 'Enable or disable', type: 'boolean', required: true },\n ],\n actions: [\n {\n action: 'set',\n key: 'config.logging.events.${args.event}',\n value: '${args.enabled}',\n scope: 'guild',\n },\n {\n action: 'reply',\n content: '${args.event} logging ${args.enabled ? \"enabled\" : \"disabled\"}!',\n ephemeral: true,\n },\n ],\n },\n {\n name: 'ignore-channel',\n description: 'Ignore a channel from logging',\n options: [\n { name: 'channel', description: 'Channel to ignore', type: 'channel', required: true },\n ],\n actions: [\n {\n action: 'list_push',\n key: 'config.logging.ignoredChannels',\n value: '${args.channel.id}',\n scope: 'guild',\n },\n {\n action: 'reply',\n content: '${args.channel} will now be ignored from logs.',\n ephemeral: true,\n },\n ],\n },\n ],\n },\n];\n\nexport function getLoggingSpec(config: LoggingConfig = {}): Partial<FurlowSpec> {\n return {\n events: loggingEventHandlers,\n commands: loggingCommands,\n };\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/logging/index.ts"],"sourcesContent":["/**\n * Logging builtin module\n * Handles comprehensive server logging for messages, members, voice, and moderation\n */\n\nimport type { FurlowSpec, CommandDefinition, EventHandler } from '@furlow/schema';\n\nexport interface LoggingConfig {\n /** Default log channel */\n channel?: string;\n /** Separate channels per category */\n channels?: {\n messages?: string;\n members?: string;\n voice?: string;\n server?: string;\n moderation?: string;\n };\n /** Ignored channels */\n ignoredChannels?: string[];\n /** Ignored roles (users with these roles won't be logged) */\n ignoredRoles?: string[];\n /** Events to log */\n events?: {\n messageDelete?: boolean;\n messageEdit?: boolean;\n messageBulkDelete?: boolean;\n memberJoin?: boolean;\n memberLeave?: boolean;\n memberUpdate?: boolean;\n memberBan?: boolean;\n memberUnban?: boolean;\n voiceJoin?: boolean;\n voiceLeave?: boolean;\n voiceMove?: boolean;\n channelCreate?: boolean;\n channelDelete?: boolean;\n channelUpdate?: boolean;\n roleCreate?: boolean;\n roleDelete?: boolean;\n roleUpdate?: boolean;\n inviteCreate?: boolean;\n inviteDelete?: boolean;\n };\n /** Include images in logs */\n includeImages?: boolean;\n}\n\nexport const loggingEventHandlers: EventHandler[] = [\n // Message Delete\n {\n event: 'message_delete',\n condition: 'config.logging.events?.messageDelete !== false && !config.logging.ignoredChannels?.includes(channel.id)',\n actions: [\n {\n action: 'send_message',\n channel: '${config.logging.channels?.messages || config.logging.channel}',\n embed: {\n title: 'Message Deleted',\n description: '${message.content || \"*No text content*\"}',\n color: '#ed4245',\n fields: [\n { name: 'Author', value: '${message.author ? \"<@\" + message.author.id + \">\" : \"Unknown\"}', inline: true },\n { name: 'Channel', value: '<#${channel.id}>', inline: true },\n { name: 'Message ID', value: '${message.id}', inline: true },\n ],\n footer: {\n text: 'User ID: ${message.author?.id || \"Unknown\"}',\n },\n timestamp: '${now()}',\n },\n },\n ],\n },\n // Message Edit\n {\n event: 'message_update',\n condition: 'config.logging.events?.messageEdit !== false && oldMessage.content !== newMessage.content && !config.logging.ignoredChannels?.includes(channel.id)',\n actions: [\n {\n action: 'send_message',\n channel: '${config.logging.channels?.messages || config.logging.channel}',\n embed: {\n title: 'Message Edited',\n color: '#fee75c',\n fields: [\n { name: 'Before', value: '${truncate(oldMessage.content || \"*Empty*\", 1024)}' },\n { name: 'After', value: '${truncate(newMessage.content || \"*Empty*\", 1024)}' },\n { name: 'Author', value: '<@${newMessage.author.id}>', inline: true },\n { name: 'Channel', value: '<#${channel.id}>', inline: true },\n { name: 'Jump to Message', value: '[Click here](${newMessage.url})', inline: true },\n ],\n footer: {\n text: 'User ID: ${newMessage.author.id}',\n },\n timestamp: '${now()}',\n },\n },\n ],\n },\n // Bulk Message Delete\n {\n event: 'message_bulk_delete',\n condition: 'config.logging.events?.messageBulkDelete !== false',\n actions: [\n {\n action: 'set',\n key: 'logContent',\n value: '${messages | map(m => \"[\" + (m.author?.tag || \"Unknown\") + \"]: \" + (m.content || \"*attachment/embed*\")) | join(\"\\\\n\")}',\n },\n {\n action: 'send_message',\n channel: '${config.logging.channels?.messages || config.logging.channel}',\n embed: {\n title: 'Bulk Messages Deleted',\n description: '${messages.length} messages were deleted in <#${channel.id}>',\n color: '#ed4245',\n timestamp: '${now()}',\n },\n files: [\n {\n attachment: '${Buffer.from(logContent)}',\n name: 'deleted-messages.txt',\n },\n ],\n },\n ],\n },\n // Member Join\n {\n event: 'member_join',\n condition: 'config.logging.events?.memberJoin !== false',\n actions: [\n {\n action: 'set',\n key: 'accountAge',\n value: '${floor((now() - member.joined_at) / (1000 * 60 * 60 * 24))}',\n },\n {\n action: 'send_message',\n channel: '${config.logging.channels?.members || config.logging.channel}',\n embed: {\n title: 'Member Joined',\n description: '<@${member.id}> joined the server',\n color: '#57f287',\n thumbnail: '${member.avatar}',\n fields: [\n { name: 'Username', value: '${member.user.tag}', inline: true },\n { name: 'Account Age', value: '${accountAge} days', inline: true },\n { name: 'Member Count', value: '${guild.member_count}', inline: true },\n ],\n footer: {\n text: 'User ID: ${member.id}',\n },\n timestamp: '${now()}',\n },\n },\n ],\n },\n // Member Leave\n {\n event: 'member_leave',\n condition: 'config.logging.events?.memberLeave !== false',\n actions: [\n {\n action: 'set',\n key: 'roles',\n value: '${member.roles?.cache?.filter(r => r.id !== guild.id)?.map(r => r.name)?.join(\", \") || \"None\"}',\n },\n {\n action: 'send_message',\n channel: '${config.logging.channels?.members || config.logging.channel}',\n embed: {\n title: 'Member Left',\n description: '<@${member.id}> left the server',\n color: '#ed4245',\n thumbnail: '${member.avatar}',\n fields: [\n { name: 'Username', value: '${member.user.tag}', inline: true },\n { name: 'Roles', value: '${truncate(roles, 1024)}', inline: false },\n { name: 'Joined At', value: '${timestamp(member.joined_at, \"R\")}', inline: true },\n ],\n footer: {\n text: 'User ID: ${member.id}',\n },\n timestamp: '${now()}',\n },\n },\n ],\n },\n // Member Update (roles, nickname)\n {\n event: 'member_update',\n condition: 'config.logging.events?.memberUpdate !== false',\n actions: [\n // Role changes\n {\n action: 'flow_if',\n condition: 'oldMember.roles.cache.size !== newMember.roles.cache.size',\n then: [\n {\n action: 'set',\n key: 'addedRoles',\n value: '${newMember.roles.cache.filter(r => !oldMember.roles.cache.has(r.id)).map(r => r.name).join(\", \")}',\n },\n {\n action: 'set',\n key: 'removedRoles',\n value: '${oldMember.roles.cache.filter(r => !newMember.roles.cache.has(r.id)).map(r => r.name).join(\", \")}',\n },\n {\n action: 'send_message',\n channel: '${config.logging.channels?.members || config.logging.channel}',\n embed: {\n title: 'Member Roles Updated',\n description: '<@${newMember.id}>\\'s roles were changed',\n color: '#5865f2',\n fields: [\n { name: 'Added Roles', value: '${addedRoles || \"None\"}', inline: true },\n { name: 'Removed Roles', value: '${removedRoles || \"None\"}', inline: true },\n ],\n footer: {\n text: 'User ID: ${newMember.id}',\n },\n timestamp: '${now()}',\n },\n },\n ],\n },\n // Nickname changes\n {\n action: 'flow_if',\n condition: 'oldMember.nickname !== newMember.nickname',\n then: [\n {\n action: 'send_message',\n channel: '${config.logging.channels?.members || config.logging.channel}',\n embed: {\n title: 'Nickname Changed',\n description: '<@${newMember.id}>\\'s nickname was changed',\n color: '#5865f2',\n fields: [\n { name: 'Before', value: '${oldMember.nickname || oldMember.user.username}', inline: true },\n { name: 'After', value: '${newMember.nickname || newMember.user.username}', inline: true },\n ],\n footer: {\n text: 'User ID: ${newMember.id}',\n },\n timestamp: '${now()}',\n },\n },\n ],\n },\n ],\n },\n // Member Ban\n {\n event: 'member_ban',\n condition: 'config.logging.events?.memberBan !== false',\n actions: [\n {\n action: 'send_message',\n channel: '${config.logging.channels?.moderation || config.logging.channel}',\n embed: {\n title: 'Member Banned',\n description: '<@${user.id}> was banned',\n color: '#ed4245',\n thumbnail: '${user.avatar}',\n fields: [\n { name: 'Username', value: '${user.tag}', inline: true },\n { name: 'Reason', value: '${ban.reason || \"No reason provided\"}', inline: false },\n ],\n footer: {\n text: 'User ID: ${user.id}',\n },\n timestamp: '${now()}',\n },\n },\n ],\n },\n // Member Unban\n {\n event: 'member_unban',\n condition: 'config.logging.events?.memberUnban !== false',\n actions: [\n {\n action: 'send_message',\n channel: '${config.logging.channels?.moderation || config.logging.channel}',\n embed: {\n title: 'Member Unbanned',\n description: '<@${user.id}> was unbanned',\n color: '#57f287',\n thumbnail: '${user.avatar}',\n fields: [\n { name: 'Username', value: '${user.tag}', inline: true },\n ],\n footer: {\n text: 'User ID: ${user.id}',\n },\n timestamp: '${now()}',\n },\n },\n ],\n },\n // Voice Join\n {\n event: 'voice_join',\n condition: 'config.logging.events?.voiceJoin !== false',\n actions: [\n {\n action: 'send_message',\n channel: '${config.logging.channels?.voice || config.logging.channel}',\n embed: {\n title: 'Voice Channel Joined',\n description: '<@${member.id}> joined <#${channel.id}>',\n color: '#57f287',\n footer: {\n text: 'User ID: ${member.id}',\n },\n timestamp: '${now()}',\n },\n },\n ],\n },\n // Voice Leave\n {\n event: 'voice_leave',\n condition: 'config.logging.events?.voiceLeave !== false',\n actions: [\n {\n action: 'send_message',\n channel: '${config.logging.channels?.voice || config.logging.channel}',\n embed: {\n title: 'Voice Channel Left',\n description: '<@${member.id}> left <#${channel.id}>',\n color: '#ed4245',\n footer: {\n text: 'User ID: ${member.id}',\n },\n timestamp: '${now()}',\n },\n },\n ],\n },\n // Voice Move\n {\n event: 'voice_move',\n condition: 'config.logging.events?.voiceMove !== false',\n actions: [\n {\n action: 'send_message',\n channel: '${config.logging.channels?.voice || config.logging.channel}',\n embed: {\n title: 'Voice Channel Switch',\n description: '<@${member.id}> switched voice channels',\n color: '#5865f2',\n fields: [\n { name: 'From', value: '<#${oldChannel.id}>', inline: true },\n { name: 'To', value: '<#${newChannel.id}>', inline: true },\n ],\n footer: {\n text: 'User ID: ${member.id}',\n },\n timestamp: '${now()}',\n },\n },\n ],\n },\n // Channel Create\n {\n event: 'channel_create',\n condition: 'config.logging.events?.channelCreate !== false',\n actions: [\n {\n action: 'send_message',\n channel: '${config.logging.channels?.server || config.logging.channel}',\n embed: {\n title: 'Channel Created',\n description: '<#${channel.id}> was created',\n color: '#57f287',\n fields: [\n { name: 'Name', value: '${channel.name}', inline: true },\n { name: 'Type', value: '${channel.type}', inline: true },\n ],\n timestamp: '${now()}',\n },\n },\n ],\n },\n // Channel Delete\n {\n event: 'channel_delete',\n condition: 'config.logging.events?.channelDelete !== false',\n actions: [\n {\n action: 'send_message',\n channel: '${config.logging.channels?.server || config.logging.channel}',\n embed: {\n title: 'Channel Deleted',\n description: '#${channel.name} was deleted',\n color: '#ed4245',\n fields: [\n { name: 'Type', value: '${channel.type}', inline: true },\n ],\n timestamp: '${now()}',\n },\n },\n ],\n },\n // Role Create\n {\n event: 'role_create',\n condition: 'config.logging.events?.roleCreate !== false',\n actions: [\n {\n action: 'send_message',\n channel: '${config.logging.channels?.server || config.logging.channel}',\n embed: {\n title: 'Role Created',\n description: '${role.name} was created',\n color: '${role.hexColor || \"#57f287\"}',\n fields: [\n { name: 'Color', value: '${role.hexColor || \"None\"}', inline: true },\n { name: 'Hoisted', value: '${role.hoist ? \"Yes\" : \"No\"}', inline: true },\n { name: 'Mentionable', value: '${role.mentionable ? \"Yes\" : \"No\"}', inline: true },\n ],\n footer: {\n text: 'Role ID: ${role.id}',\n },\n timestamp: '${now()}',\n },\n },\n ],\n },\n // Role Delete\n {\n event: 'role_delete',\n condition: 'config.logging.events?.roleDelete !== false',\n actions: [\n {\n action: 'send_message',\n channel: '${config.logging.channels?.server || config.logging.channel}',\n embed: {\n title: 'Role Deleted',\n description: '${role.name} was deleted',\n color: '#ed4245',\n footer: {\n text: 'Role ID: ${role.id}',\n },\n timestamp: '${now()}',\n },\n },\n ],\n },\n];\n\nexport const loggingCommands: CommandDefinition[] = [\n {\n name: 'logging',\n description: 'Logging configuration commands',\n subcommands: [\n {\n name: 'set-channel',\n description: 'Set the logging channel',\n options: [\n { name: 'channel', description: 'Channel for logs', type: 'channel', required: true },\n { name: 'category', description: 'Log category', type: 'string', required: false, choices: [\n { name: 'All', value: 'all' },\n { name: 'Messages', value: 'messages' },\n { name: 'Members', value: 'members' },\n { name: 'Voice', value: 'voice' },\n { name: 'Server', value: 'server' },\n { name: 'Moderation', value: 'moderation' },\n ]},\n ],\n actions: [\n {\n action: 'flow_if',\n condition: '!args.category || args.category === \"all\"',\n then: [\n {\n action: 'set',\n key: 'config.logging.channel',\n value: '${args.channel.id}',\n scope: 'guild',\n },\n ],\n else: [\n {\n action: 'set',\n key: 'config.logging.channels.${args.category}',\n value: '${args.channel.id}',\n scope: 'guild',\n },\n ],\n },\n {\n action: 'reply',\n content: 'Logging channel updated!',\n ephemeral: true,\n },\n ],\n },\n {\n name: 'toggle',\n description: 'Toggle a logging event',\n options: [\n { name: 'event', description: 'Event to toggle', type: 'string', required: true, choices: [\n { name: 'Message Delete', value: 'messageDelete' },\n { name: 'Message Edit', value: 'messageEdit' },\n { name: 'Member Join', value: 'memberJoin' },\n { name: 'Member Leave', value: 'memberLeave' },\n { name: 'Member Ban', value: 'memberBan' },\n { name: 'Voice Join', value: 'voiceJoin' },\n { name: 'Voice Leave', value: 'voiceLeave' },\n ]},\n { name: 'enabled', description: 'Enable or disable', type: 'boolean', required: true },\n ],\n actions: [\n {\n action: 'set',\n key: 'config.logging.events.${args.event}',\n value: '${args.enabled}',\n scope: 'guild',\n },\n {\n action: 'reply',\n content: '${args.event} logging ${args.enabled ? \"enabled\" : \"disabled\"}!',\n ephemeral: true,\n },\n ],\n },\n {\n name: 'ignore-channel',\n description: 'Ignore a channel from logging',\n options: [\n { name: 'channel', description: 'Channel to ignore', type: 'channel', required: true },\n ],\n actions: [\n {\n action: 'list_push',\n key: 'config.logging.ignoredChannels',\n value: '${args.channel.id}',\n scope: 'guild',\n },\n {\n action: 'reply',\n content: '${args.channel} will now be ignored from logs.',\n ephemeral: true,\n },\n ],\n },\n ],\n },\n];\n\nexport function getLoggingSpec(config: LoggingConfig = {}): Partial<FurlowSpec> {\n return {\n events: loggingEventHandlers,\n commands: loggingCommands,\n };\n}\n"],"mappings":"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","names":[]}
|