@furlow/builtins 1.0.0 → 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/afk/index.js
CHANGED
|
@@ -14,7 +14,7 @@ var afkEventHandlers = [
|
|
|
14
14
|
// Remove AFK when user sends message
|
|
15
15
|
{
|
|
16
16
|
event: "message",
|
|
17
|
-
condition: "
|
|
17
|
+
condition: "!message.author.bot",
|
|
18
18
|
actions: [
|
|
19
19
|
{
|
|
20
20
|
action: "db_query",
|
|
@@ -24,7 +24,7 @@ var afkEventHandlers = [
|
|
|
24
24
|
},
|
|
25
25
|
{
|
|
26
26
|
action: "flow_if",
|
|
27
|
-
condition: "
|
|
27
|
+
condition: "afkStatus.length > 0",
|
|
28
28
|
then: [
|
|
29
29
|
// Remove AFK
|
|
30
30
|
{
|
|
@@ -35,7 +35,7 @@ var afkEventHandlers = [
|
|
|
35
35
|
// Remove nickname prefix if set
|
|
36
36
|
{
|
|
37
37
|
action: "flow_if",
|
|
38
|
-
condition: "
|
|
38
|
+
condition: "config.afk?.nicknamePrefix && member.nickname?.startsWith(config.afk.nicknamePrefix)",
|
|
39
39
|
then: [
|
|
40
40
|
{
|
|
41
41
|
action: "set_nickname",
|
|
@@ -66,7 +66,7 @@ var afkEventHandlers = [
|
|
|
66
66
|
// Notify when AFK user is mentioned
|
|
67
67
|
{
|
|
68
68
|
event: "message",
|
|
69
|
-
condition: "
|
|
69
|
+
condition: "message.mentions.users.size > 0 && !message.author.bot",
|
|
70
70
|
actions: [
|
|
71
71
|
{
|
|
72
72
|
action: "set",
|
|
@@ -86,7 +86,7 @@ var afkEventHandlers = [
|
|
|
86
86
|
},
|
|
87
87
|
{
|
|
88
88
|
action: "flow_if",
|
|
89
|
-
condition: "
|
|
89
|
+
condition: "afkMentioned.length > 0",
|
|
90
90
|
then: [
|
|
91
91
|
{
|
|
92
92
|
action: "set",
|
|
@@ -135,7 +135,7 @@ var afkCommands = [
|
|
|
135
135
|
},
|
|
136
136
|
{
|
|
137
137
|
action: "flow_if",
|
|
138
|
-
condition: "
|
|
138
|
+
condition: "existing.length > 0",
|
|
139
139
|
then: [
|
|
140
140
|
{
|
|
141
141
|
action: "db_update",
|
|
@@ -160,7 +160,7 @@ var afkCommands = [
|
|
|
160
160
|
// Add nickname prefix if configured
|
|
161
161
|
{
|
|
162
162
|
action: "flow_if",
|
|
163
|
-
condition: "
|
|
163
|
+
condition: "config.afk?.nicknamePrefix && !member.nickname?.startsWith(config.afk.nicknamePrefix)",
|
|
164
164
|
then: [
|
|
165
165
|
{
|
|
166
166
|
action: "set_nickname",
|
package/dist/afk/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/afk/index.ts"],"sourcesContent":["/**\n * AFK builtin module\n * Handles AFK status and mention notifications\n */\n\nimport type { FurlowSpec, CommandDefinition, EventHandler, TableDefinition } from '@furlow/schema';\n\nexport interface AfkConfig {\n /** Maximum AFK reason length */\n maxReasonLength?: number;\n /** Add prefix to nickname */\n nicknamePrefix?: string;\n /** Ignore bot mentions */\n ignoreBots?: boolean;\n}\n\nexport const afkTables: Record<string, TableDefinition> = {\n afk_users: {\n columns: {\n id: { type: 'number', primary: true },\n guild_id: { type: 'string', index: true },\n user_id: { type: 'string', index: true },\n reason: { type: 'string' },\n set_at: { type: 'timestamp' },\n },\n },\n};\n\nexport const afkEventHandlers: EventHandler[] = [\n // Remove AFK when user sends message\n {\n event: 'message',\n condition: '
|
|
1
|
+
{"version":3,"sources":["../../src/afk/index.ts"],"sourcesContent":["/**\n * AFK builtin module\n * Handles AFK status and mention notifications\n */\n\nimport type { FurlowSpec, CommandDefinition, EventHandler, TableDefinition } from '@furlow/schema';\n\nexport interface AfkConfig {\n /** Maximum AFK reason length */\n maxReasonLength?: number;\n /** Add prefix to nickname */\n nicknamePrefix?: string;\n /** Ignore bot mentions */\n ignoreBots?: boolean;\n}\n\nexport const afkTables: Record<string, TableDefinition> = {\n afk_users: {\n columns: {\n id: { type: 'number', primary: true },\n guild_id: { type: 'string', index: true },\n user_id: { type: 'string', index: true },\n reason: { type: 'string' },\n set_at: { type: 'timestamp' },\n },\n },\n};\n\nexport const afkEventHandlers: EventHandler[] = [\n // Remove AFK when user sends message\n {\n event: 'message',\n condition: '!message.author.bot',\n actions: [\n {\n action: 'db_query',\n table: 'afk_users',\n where: { guild_id: '${guild.id}', user_id: '${user.id}' },\n as: 'afkStatus',\n },\n {\n action: 'flow_if',\n condition: 'afkStatus.length > 0',\n then: [\n // Remove AFK\n {\n action: 'db_delete',\n table: 'afk_users',\n where: { guild_id: '${guild.id}', user_id: '${user.id}' },\n },\n // Remove nickname prefix if set\n {\n action: 'flow_if',\n condition: 'config.afk?.nicknamePrefix && member.nickname?.startsWith(config.afk.nicknamePrefix)',\n then: [\n {\n action: 'set_nickname',\n user: '${user.id}',\n nickname: '${member.nickname.replace(config.afk.nicknamePrefix, \"\")}',\n },\n ],\n },\n {\n action: 'send_message',\n channel: '${channel.id}',\n content: 'Welcome back ${user}! I removed your AFK status.',\n as: 'welcomeBack',\n },\n {\n action: 'wait',\n duration: 5000,\n },\n {\n action: 'delete_message',\n channel: '${channel.id}',\n message: '${welcomeBack.id}',\n },\n ],\n },\n ],\n },\n // Notify when AFK user is mentioned\n {\n event: 'message',\n condition: 'message.mentions.users.size > 0 && !message.author.bot',\n actions: [\n {\n action: 'set',\n key: 'mentionedIds',\n value: '${[...message.mentions.users.keys()]}',\n },\n {\n action: 'db_query',\n table: 'afk_users',\n where: { guild_id: '${guild.id}' },\n as: 'allAfk',\n },\n {\n action: 'set',\n key: 'afkMentioned',\n value: '${allAfk.filter(a => mentionedIds.includes(a.user_id))}',\n },\n {\n action: 'flow_if',\n condition: 'afkMentioned.length > 0',\n then: [\n {\n action: 'set',\n key: 'afkMessages',\n value: '${afkMentioned.map(a => \"<@\" + a.user_id + \"> is AFK: \" + a.reason + \" (since \" + timestamp(a.set_at, \"R\") + \")\").join(\"\\\\n\")}',\n },\n {\n action: 'send_message',\n channel: '${channel.id}',\n content: '${afkMessages}',\n as: 'afkNotice',\n },\n {\n action: 'wait',\n duration: 10000,\n },\n {\n action: 'delete_message',\n channel: '${channel.id}',\n message: '${afkNotice.id}',\n },\n ],\n },\n ],\n },\n];\n\nexport const afkCommands: CommandDefinition[] = [\n {\n name: 'afk',\n description: 'Set your AFK status',\n options: [\n { name: 'reason', description: 'AFK reason', type: 'string', required: false },\n ],\n actions: [\n {\n action: 'set',\n key: 'reason',\n value: '${truncate(args.reason || \"AFK\", config.afk?.maxReasonLength || 100)}',\n },\n // Check if already AFK\n {\n action: 'db_query',\n table: 'afk_users',\n where: { guild_id: '${guild.id}', user_id: '${user.id}' },\n as: 'existing',\n },\n {\n action: 'flow_if',\n condition: 'existing.length > 0',\n then: [\n {\n action: 'db_update',\n table: 'afk_users',\n where: { guild_id: '${guild.id}', user_id: '${user.id}' },\n data: { reason: '${reason}', set_at: '${now()}' },\n },\n ],\n else: [\n {\n action: 'db_insert',\n table: 'afk_users',\n data: {\n guild_id: '${guild.id}',\n user_id: '${user.id}',\n reason: '${reason}',\n set_at: '${now()}',\n },\n },\n ],\n },\n // Add nickname prefix if configured\n {\n action: 'flow_if',\n condition: 'config.afk?.nicknamePrefix && !member.nickname?.startsWith(config.afk.nicknamePrefix)',\n then: [\n {\n action: 'set_nickname',\n user: '${user.id}',\n nickname: '${config.afk.nicknamePrefix + (member.nickname || user.username)}',\n },\n ],\n },\n {\n action: 'reply',\n content: 'I set your AFK: ${reason}',\n ephemeral: false,\n },\n ],\n },\n];\n\nexport function getAfkSpec(config: AfkConfig = {}): Partial<FurlowSpec> {\n return {\n commands: afkCommands,\n events: afkEventHandlers,\n state: {\n tables: afkTables,\n },\n };\n}\n"],"mappings":"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","names":[]}
|
|
@@ -38,7 +38,7 @@ var autoResponderTables = {
|
|
|
38
38
|
var autoResponderEventHandlers = [
|
|
39
39
|
{
|
|
40
40
|
event: "message",
|
|
41
|
-
condition: "
|
|
41
|
+
condition: "!message.author.bot || !config.autoResponder?.ignoreBots",
|
|
42
42
|
actions: [
|
|
43
43
|
// Get all triggers for this guild
|
|
44
44
|
{
|
|
@@ -53,34 +53,34 @@ var autoResponderEventHandlers = [
|
|
|
53
53
|
items: "${triggers}",
|
|
54
54
|
each: {
|
|
55
55
|
action: "flow_if",
|
|
56
|
-
condition: '
|
|
56
|
+
condition: '(() => { const t = item; const msg = t.ignore_case ? message.content.toLowerCase() : message.content; const trig = t.ignore_case ? t.trigger.toLowerCase() : t.trigger; switch(t.trigger_type) { case "exact": return msg === trig; case "contains": return msg.includes(trig); case "startswith": return msg.startsWith(trig); case "endswith": return msg.endsWith(trig); case "regex": return new RegExp(t.trigger, t.ignore_case ? "i" : "").test(message.content); default: return false; } })()',
|
|
57
57
|
then: [
|
|
58
58
|
// Check channel restrictions
|
|
59
59
|
{
|
|
60
60
|
action: "flow_if",
|
|
61
|
-
condition: "
|
|
61
|
+
condition: "item.allowed_channels?.length && !item.allowed_channels.includes(channel.id)",
|
|
62
62
|
then: [{ action: "abort" }]
|
|
63
63
|
},
|
|
64
64
|
{
|
|
65
65
|
action: "flow_if",
|
|
66
|
-
condition: "
|
|
66
|
+
condition: "item.ignored_channels?.includes(channel.id)",
|
|
67
67
|
then: [{ action: "abort" }]
|
|
68
68
|
},
|
|
69
69
|
// Check role restrictions
|
|
70
70
|
{
|
|
71
71
|
action: "flow_if",
|
|
72
|
-
condition: "
|
|
72
|
+
condition: "item.allowed_roles?.length && !item.allowed_roles.some(r => member.roles.cache.has(r))",
|
|
73
73
|
then: [{ action: "abort" }]
|
|
74
74
|
},
|
|
75
75
|
{
|
|
76
76
|
action: "flow_if",
|
|
77
|
-
condition: "
|
|
77
|
+
condition: "item.ignored_roles?.some(r => member.roles.cache.has(r))",
|
|
78
78
|
then: [{ action: "abort" }]
|
|
79
79
|
},
|
|
80
80
|
// Check cooldown
|
|
81
81
|
{
|
|
82
82
|
action: "flow_if",
|
|
83
|
-
condition: "
|
|
83
|
+
condition: "item.cooldown > 0",
|
|
84
84
|
then: [
|
|
85
85
|
{
|
|
86
86
|
action: "db_query",
|
|
@@ -90,7 +90,7 @@ var autoResponderEventHandlers = [
|
|
|
90
90
|
},
|
|
91
91
|
{
|
|
92
92
|
action: "flow_if",
|
|
93
|
-
condition: "
|
|
93
|
+
condition: "cooldown[0] && (now() - new Date(cooldown[0].last_triggered)) < item.cooldown * 1000",
|
|
94
94
|
then: [{ action: "abort" }]
|
|
95
95
|
}
|
|
96
96
|
]
|
|
@@ -98,7 +98,7 @@ var autoResponderEventHandlers = [
|
|
|
98
98
|
// Check chance
|
|
99
99
|
{
|
|
100
100
|
action: "flow_if",
|
|
101
|
-
condition: "
|
|
101
|
+
condition: "item.chance < 100 && random(1, 100) > item.chance",
|
|
102
102
|
then: [{ action: "abort" }]
|
|
103
103
|
},
|
|
104
104
|
// Execute response
|
|
@@ -109,7 +109,7 @@ var autoResponderEventHandlers = [
|
|
|
109
109
|
message: [
|
|
110
110
|
{
|
|
111
111
|
action: "flow_if",
|
|
112
|
-
condition: "
|
|
112
|
+
condition: "item.dm_response",
|
|
113
113
|
then: [
|
|
114
114
|
{ action: "send_dm", user: "${user.id}", content: "${item.response}" }
|
|
115
115
|
],
|
|
@@ -121,7 +121,7 @@ var autoResponderEventHandlers = [
|
|
|
121
121
|
embed: [
|
|
122
122
|
{
|
|
123
123
|
action: "flow_if",
|
|
124
|
-
condition: "
|
|
124
|
+
condition: "item.dm_response",
|
|
125
125
|
then: [
|
|
126
126
|
{ action: "send_dm", user: "${user.id}", embed: "${item.embed_data}" }
|
|
127
127
|
],
|
|
@@ -138,7 +138,7 @@ var autoResponderEventHandlers = [
|
|
|
138
138
|
// Delete trigger message if configured
|
|
139
139
|
{
|
|
140
140
|
action: "flow_if",
|
|
141
|
-
condition: "
|
|
141
|
+
condition: "item.delete_trigger",
|
|
142
142
|
then: [
|
|
143
143
|
{ action: "delete_message", channel: "${channel.id}", message: "${message.id}" }
|
|
144
144
|
]
|
|
@@ -146,7 +146,7 @@ var autoResponderEventHandlers = [
|
|
|
146
146
|
// Update cooldown
|
|
147
147
|
{
|
|
148
148
|
action: "flow_if",
|
|
149
|
-
condition: "
|
|
149
|
+
condition: "item.cooldown > 0",
|
|
150
150
|
then: [
|
|
151
151
|
{
|
|
152
152
|
action: "db_update",
|
|
@@ -193,7 +193,7 @@ var autoResponderCommands = [
|
|
|
193
193
|
},
|
|
194
194
|
{
|
|
195
195
|
action: "flow_if",
|
|
196
|
-
condition: "
|
|
196
|
+
condition: "existing.length >= (config.autoResponder?.maxTriggers || 50)",
|
|
197
197
|
then: [
|
|
198
198
|
{ action: "reply", content: "Maximum triggers reached!", ephemeral: true },
|
|
199
199
|
{ action: "abort" }
|
|
@@ -231,7 +231,7 @@ var autoResponderCommands = [
|
|
|
231
231
|
},
|
|
232
232
|
{
|
|
233
233
|
action: "flow_if",
|
|
234
|
-
condition: "
|
|
234
|
+
condition: "triggers.length === 0",
|
|
235
235
|
then: [
|
|
236
236
|
{ action: "reply", content: "No auto-responses configured!", ephemeral: true },
|
|
237
237
|
{ action: "abort" }
|
|
@@ -269,7 +269,7 @@ var autoResponderCommands = [
|
|
|
269
269
|
},
|
|
270
270
|
{
|
|
271
271
|
action: "flow_if",
|
|
272
|
-
condition: "
|
|
272
|
+
condition: "trigger.length === 0",
|
|
273
273
|
then: [
|
|
274
274
|
{ action: "reply", content: "Trigger not found!", ephemeral: true },
|
|
275
275
|
{ action: "abort" }
|
|
@@ -311,7 +311,7 @@ var autoResponderCommands = [
|
|
|
311
311
|
},
|
|
312
312
|
{
|
|
313
313
|
action: "flow_if",
|
|
314
|
-
condition: "
|
|
314
|
+
condition: "trigger.length === 0",
|
|
315
315
|
then: [
|
|
316
316
|
{ action: "reply", content: "Trigger not found!", ephemeral: true },
|
|
317
317
|
{ action: "abort" }
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/auto-responder/index.ts"],"sourcesContent":["/**\n * Auto-Responder builtin module\n * Handles trigger-based automatic responses\n */\n\nimport type { FurlowSpec, CommandDefinition, EventHandler, TableDefinition } from '@furlow/schema';\n\nexport interface AutoResponderConfig {\n /** Maximum triggers per guild */\n maxTriggers?: number;\n /** Ignore bots */\n ignoreBots?: boolean;\n /** Global cooldown (seconds) */\n globalCooldown?: number;\n}\n\nexport const autoResponderTables: Record<string, TableDefinition> = {\n auto_responses: {\n columns: {\n id: { type: 'number', primary: true },\n guild_id: { type: 'string', index: true },\n trigger: { type: 'string' },\n trigger_type: { type: 'string', default: 'contains' }, // exact, contains, startswith, endswith, regex\n response: { type: 'string' },\n response_type: { type: 'string', default: 'message' }, // message, embed, reaction\n embed_data: { type: 'json' },\n reaction: { type: 'string' },\n chance: { type: 'number', default: 100 }, // 0-100 percentage\n cooldown: { type: 'number', default: 0 }, // seconds\n ignore_case: { type: 'boolean', default: true },\n delete_trigger: { type: 'boolean', default: false },\n dm_response: { type: 'boolean', default: false },\n allowed_channels: { type: 'json' },\n ignored_channels: { type: 'json' },\n allowed_roles: { type: 'json' },\n ignored_roles: { type: 'json' },\n created_at: { type: 'timestamp' },\n },\n },\n auto_response_cooldowns: {\n columns: {\n id: { type: 'number', primary: true },\n response_id: { type: 'number', index: true },\n guild_id: { type: 'string' },\n last_triggered: { type: 'timestamp' },\n },\n },\n};\n\nexport const autoResponderEventHandlers: EventHandler[] = [\n {\n event: 'message',\n condition: '${!message.author.bot || !config.autoResponder?.ignoreBots}',\n actions: [\n // Get all triggers for this guild\n {\n action: 'db_query',\n table: 'auto_responses',\n where: { guild_id: '${guild.id}' },\n as: 'triggers',\n },\n // Check each trigger\n {\n action: 'batch',\n items: '${triggers}',\n each: {\n action: 'flow_if',\n condition: '${(() => { const t = item; const msg = t.ignore_case ? message.content.toLowerCase() : message.content; const trig = t.ignore_case ? t.trigger.toLowerCase() : t.trigger; switch(t.trigger_type) { case \"exact\": return msg === trig; case \"contains\": return msg.includes(trig); case \"startswith\": return msg.startsWith(trig); case \"endswith\": return msg.endsWith(trig); case \"regex\": return new RegExp(t.trigger, t.ignore_case ? \"i\" : \"\").test(message.content); default: return false; } })()}',\n then: [\n // Check channel restrictions\n {\n action: 'flow_if',\n condition: '${item.allowed_channels?.length && !item.allowed_channels.includes(channel.id)}',\n then: [{ action: 'abort' }],\n },\n {\n action: 'flow_if',\n condition: '${item.ignored_channels?.includes(channel.id)}',\n then: [{ action: 'abort' }],\n },\n // Check role restrictions\n {\n action: 'flow_if',\n condition: '${item.allowed_roles?.length && !item.allowed_roles.some(r => member.roles.cache.has(r))}',\n then: [{ action: 'abort' }],\n },\n {\n action: 'flow_if',\n condition: '${item.ignored_roles?.some(r => member.roles.cache.has(r))}',\n then: [{ action: 'abort' }],\n },\n // Check cooldown\n {\n action: 'flow_if',\n condition: '${item.cooldown > 0}',\n then: [\n {\n action: 'db_query',\n table: 'auto_response_cooldowns',\n where: { response_id: '${item.id}', guild_id: '${guild.id}' },\n as: 'cooldown',\n },\n {\n action: 'flow_if',\n condition: '${cooldown[0] && (now() - new Date(cooldown[0].last_triggered)) < item.cooldown * 1000}',\n then: [{ action: 'abort' }],\n },\n ],\n },\n // Check chance\n {\n action: 'flow_if',\n condition: '${item.chance < 100 && random(1, 100) > item.chance}',\n then: [{ action: 'abort' }],\n },\n // Execute response\n {\n action: 'flow_switch',\n value: '${item.response_type}',\n cases: {\n message: [\n {\n action: 'flow_if',\n condition: '${item.dm_response}',\n then: [\n { action: 'send_dm', user: '${user.id}', content: '${item.response}' },\n ],\n else: [\n { action: 'send_message', channel: '${channel.id}', content: '${item.response}' },\n ],\n },\n ],\n embed: [\n {\n action: 'flow_if',\n condition: '${item.dm_response}',\n then: [\n { action: 'send_dm', user: '${user.id}', embed: '${item.embed_data}' },\n ],\n else: [\n { action: 'send_message', channel: '${channel.id}', embed: '${item.embed_data}' },\n ],\n },\n ],\n reaction: [\n { action: 'add_reaction', message: '${message.id}', channel: '${channel.id}', emoji: '${item.reaction}' },\n ],\n },\n },\n // Delete trigger message if configured\n {\n action: 'flow_if',\n condition: '${item.delete_trigger}',\n then: [\n { action: 'delete_message', channel: '${channel.id}', message: '${message.id}' },\n ],\n },\n // Update cooldown\n {\n action: 'flow_if',\n condition: '${item.cooldown > 0}',\n then: [\n {\n action: 'db_update',\n table: 'auto_response_cooldowns',\n where: { response_id: '${item.id}', guild_id: '${guild.id}' },\n data: { last_triggered: '${now()}' },\n upsert: true,\n },\n ],\n },\n ],\n },\n },\n ],\n },\n];\n\nexport const autoResponderCommands: CommandDefinition[] = [\n {\n name: 'autoresponder',\n description: 'Auto-responder management',\n subcommands: [\n {\n name: 'add',\n description: 'Add an auto-response',\n options: [\n { name: 'trigger', description: 'Trigger text', type: 'string', required: true },\n { name: 'response', description: 'Response text', type: 'string', required: true },\n { name: 'type', description: 'Match type', type: 'string', required: false, choices: [\n { name: 'Contains', value: 'contains' },\n { name: 'Exact match', value: 'exact' },\n { name: 'Starts with', value: 'startswith' },\n { name: 'Ends with', value: 'endswith' },\n { name: 'Regex', value: 'regex' },\n ]},\n { name: 'chance', description: 'Response chance (1-100)', type: 'integer', required: false },\n ],\n actions: [\n // Check max triggers\n {\n action: 'db_query',\n table: 'auto_responses',\n where: { guild_id: '${guild.id}' },\n as: 'existing',\n },\n {\n action: 'flow_if',\n condition: '${existing.length >= (config.autoResponder?.maxTriggers || 50)}',\n then: [\n { action: 'reply', content: 'Maximum triggers reached!', ephemeral: true },\n { action: 'abort' },\n ],\n },\n {\n action: 'db_insert',\n table: 'auto_responses',\n data: {\n guild_id: '${guild.id}',\n trigger: '${args.trigger}',\n trigger_type: '${args.type || \"contains\"}',\n response: '${args.response}',\n chance: '${args.chance || 100}',\n created_at: '${now()}',\n },\n as: 'newTrigger',\n },\n {\n action: 'reply',\n content: 'Auto-response added! ID: ${newTrigger.id}',\n ephemeral: true,\n },\n ],\n },\n {\n name: 'list',\n description: 'List auto-responses',\n actions: [\n {\n action: 'db_query',\n table: 'auto_responses',\n where: { guild_id: '${guild.id}' },\n as: 'triggers',\n },\n {\n action: 'flow_if',\n condition: '${triggers.length === 0}',\n then: [\n { action: 'reply', content: 'No auto-responses configured!', ephemeral: true },\n { action: 'abort' },\n ],\n },\n {\n action: 'set',\n key: 'triggerList',\n value: '${triggers.map(t => \"**\" + t.id + \".** `\" + truncate(t.trigger, 30) + \"` → `\" + truncate(t.response, 30) + \"` (\" + t.trigger_type + \")\").join(\"\\\\n\")}',\n },\n {\n action: 'reply',\n embed: {\n title: 'Auto-Responses',\n description: '${triggerList}',\n color: '#5865f2',\n footer: { text: '${triggers.length} trigger(s)' },\n },\n ephemeral: true,\n },\n ],\n },\n {\n name: 'delete',\n description: 'Delete an auto-response',\n options: [\n { name: 'id', description: 'Trigger ID', type: 'integer', required: true },\n ],\n actions: [\n {\n action: 'db_query',\n table: 'auto_responses',\n where: { id: '${args.id}', guild_id: '${guild.id}' },\n as: 'trigger',\n },\n {\n action: 'flow_if',\n condition: '${trigger.length === 0}',\n then: [\n { action: 'reply', content: 'Trigger not found!', ephemeral: true },\n { action: 'abort' },\n ],\n },\n {\n action: 'db_delete',\n table: 'auto_responses',\n where: { id: '${args.id}' },\n },\n {\n action: 'db_delete',\n table: 'auto_response_cooldowns',\n where: { response_id: '${args.id}' },\n },\n {\n action: 'reply',\n content: 'Auto-response deleted!',\n ephemeral: true,\n },\n ],\n },\n {\n name: 'edit',\n description: 'Edit an auto-response',\n options: [\n { name: 'id', description: 'Trigger ID', type: 'integer', required: true },\n { name: 'trigger', description: 'New trigger', type: 'string', required: false },\n { name: 'response', description: 'New response', type: 'string', required: false },\n { name: 'cooldown', description: 'Cooldown in seconds', type: 'integer', required: false },\n { name: 'chance', description: 'Response chance (1-100)', type: 'integer', required: false },\n ],\n actions: [\n {\n action: 'db_query',\n table: 'auto_responses',\n where: { id: '${args.id}', guild_id: '${guild.id}' },\n as: 'trigger',\n },\n {\n action: 'flow_if',\n condition: '${trigger.length === 0}',\n then: [\n { action: 'reply', content: 'Trigger not found!', ephemeral: true },\n { action: 'abort' },\n ],\n },\n {\n action: 'set',\n key: 'updates',\n value: '${Object.fromEntries(Object.entries({ trigger: args.trigger, response: args.response, cooldown: args.cooldown, chance: args.chance }).filter(([_, v]) => v !== undefined))}',\n },\n {\n action: 'db_update',\n table: 'auto_responses',\n where: { id: '${args.id}' },\n data: '${updates}',\n },\n {\n action: 'reply',\n content: 'Auto-response updated!',\n ephemeral: true,\n },\n ],\n },\n ],\n },\n];\n\nexport function getAutoResponderSpec(config: AutoResponderConfig = {}): Partial<FurlowSpec> {\n return {\n commands: autoResponderCommands,\n events: autoResponderEventHandlers,\n state: {\n tables: autoResponderTables,\n },\n };\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/auto-responder/index.ts"],"sourcesContent":["/**\n * Auto-Responder builtin module\n * Handles trigger-based automatic responses\n */\n\nimport type { FurlowSpec, CommandDefinition, EventHandler, TableDefinition } from '@furlow/schema';\n\nexport interface AutoResponderConfig {\n /** Maximum triggers per guild */\n maxTriggers?: number;\n /** Ignore bots */\n ignoreBots?: boolean;\n /** Global cooldown (seconds) */\n globalCooldown?: number;\n}\n\nexport const autoResponderTables: Record<string, TableDefinition> = {\n auto_responses: {\n columns: {\n id: { type: 'number', primary: true },\n guild_id: { type: 'string', index: true },\n trigger: { type: 'string' },\n trigger_type: { type: 'string', default: 'contains' }, // exact, contains, startswith, endswith, regex\n response: { type: 'string' },\n response_type: { type: 'string', default: 'message' }, // message, embed, reaction\n embed_data: { type: 'json' },\n reaction: { type: 'string' },\n chance: { type: 'number', default: 100 }, // 0-100 percentage\n cooldown: { type: 'number', default: 0 }, // seconds\n ignore_case: { type: 'boolean', default: true },\n delete_trigger: { type: 'boolean', default: false },\n dm_response: { type: 'boolean', default: false },\n allowed_channels: { type: 'json' },\n ignored_channels: { type: 'json' },\n allowed_roles: { type: 'json' },\n ignored_roles: { type: 'json' },\n created_at: { type: 'timestamp' },\n },\n },\n auto_response_cooldowns: {\n columns: {\n id: { type: 'number', primary: true },\n response_id: { type: 'number', index: true },\n guild_id: { type: 'string' },\n last_triggered: { type: 'timestamp' },\n },\n },\n};\n\nexport const autoResponderEventHandlers: EventHandler[] = [\n {\n event: 'message',\n condition: '!message.author.bot || !config.autoResponder?.ignoreBots',\n actions: [\n // Get all triggers for this guild\n {\n action: 'db_query',\n table: 'auto_responses',\n where: { guild_id: '${guild.id}' },\n as: 'triggers',\n },\n // Check each trigger\n {\n action: 'batch',\n items: '${triggers}',\n each: {\n action: 'flow_if',\n condition: '(() => { const t = item; const msg = t.ignore_case ? message.content.toLowerCase() : message.content; const trig = t.ignore_case ? t.trigger.toLowerCase() : t.trigger; switch(t.trigger_type) { case \"exact\": return msg === trig; case \"contains\": return msg.includes(trig); case \"startswith\": return msg.startsWith(trig); case \"endswith\": return msg.endsWith(trig); case \"regex\": return new RegExp(t.trigger, t.ignore_case ? \"i\" : \"\").test(message.content); default: return false; } })()',\n then: [\n // Check channel restrictions\n {\n action: 'flow_if',\n condition: 'item.allowed_channels?.length && !item.allowed_channels.includes(channel.id)',\n then: [{ action: 'abort' }],\n },\n {\n action: 'flow_if',\n condition: 'item.ignored_channels?.includes(channel.id)',\n then: [{ action: 'abort' }],\n },\n // Check role restrictions\n {\n action: 'flow_if',\n condition: 'item.allowed_roles?.length && !item.allowed_roles.some(r => member.roles.cache.has(r))',\n then: [{ action: 'abort' }],\n },\n {\n action: 'flow_if',\n condition: 'item.ignored_roles?.some(r => member.roles.cache.has(r))',\n then: [{ action: 'abort' }],\n },\n // Check cooldown\n {\n action: 'flow_if',\n condition: 'item.cooldown > 0',\n then: [\n {\n action: 'db_query',\n table: 'auto_response_cooldowns',\n where: { response_id: '${item.id}', guild_id: '${guild.id}' },\n as: 'cooldown',\n },\n {\n action: 'flow_if',\n condition: 'cooldown[0] && (now() - new Date(cooldown[0].last_triggered)) < item.cooldown * 1000',\n then: [{ action: 'abort' }],\n },\n ],\n },\n // Check chance\n {\n action: 'flow_if',\n condition: 'item.chance < 100 && random(1, 100) > item.chance',\n then: [{ action: 'abort' }],\n },\n // Execute response\n {\n action: 'flow_switch',\n value: '${item.response_type}',\n cases: {\n message: [\n {\n action: 'flow_if',\n condition: 'item.dm_response',\n then: [\n { action: 'send_dm', user: '${user.id}', content: '${item.response}' },\n ],\n else: [\n { action: 'send_message', channel: '${channel.id}', content: '${item.response}' },\n ],\n },\n ],\n embed: [\n {\n action: 'flow_if',\n condition: 'item.dm_response',\n then: [\n { action: 'send_dm', user: '${user.id}', embed: '${item.embed_data}' },\n ],\n else: [\n { action: 'send_message', channel: '${channel.id}', embed: '${item.embed_data}' },\n ],\n },\n ],\n reaction: [\n { action: 'add_reaction', message: '${message.id}', channel: '${channel.id}', emoji: '${item.reaction}' },\n ],\n },\n },\n // Delete trigger message if configured\n {\n action: 'flow_if',\n condition: 'item.delete_trigger',\n then: [\n { action: 'delete_message', channel: '${channel.id}', message: '${message.id}' },\n ],\n },\n // Update cooldown\n {\n action: 'flow_if',\n condition: 'item.cooldown > 0',\n then: [\n {\n action: 'db_update',\n table: 'auto_response_cooldowns',\n where: { response_id: '${item.id}', guild_id: '${guild.id}' },\n data: { last_triggered: '${now()}' },\n upsert: true,\n },\n ],\n },\n ],\n },\n },\n ],\n },\n];\n\nexport const autoResponderCommands: CommandDefinition[] = [\n {\n name: 'autoresponder',\n description: 'Auto-responder management',\n subcommands: [\n {\n name: 'add',\n description: 'Add an auto-response',\n options: [\n { name: 'trigger', description: 'Trigger text', type: 'string', required: true },\n { name: 'response', description: 'Response text', type: 'string', required: true },\n { name: 'type', description: 'Match type', type: 'string', required: false, choices: [\n { name: 'Contains', value: 'contains' },\n { name: 'Exact match', value: 'exact' },\n { name: 'Starts with', value: 'startswith' },\n { name: 'Ends with', value: 'endswith' },\n { name: 'Regex', value: 'regex' },\n ]},\n { name: 'chance', description: 'Response chance (1-100)', type: 'integer', required: false },\n ],\n actions: [\n // Check max triggers\n {\n action: 'db_query',\n table: 'auto_responses',\n where: { guild_id: '${guild.id}' },\n as: 'existing',\n },\n {\n action: 'flow_if',\n condition: 'existing.length >= (config.autoResponder?.maxTriggers || 50)',\n then: [\n { action: 'reply', content: 'Maximum triggers reached!', ephemeral: true },\n { action: 'abort' },\n ],\n },\n {\n action: 'db_insert',\n table: 'auto_responses',\n data: {\n guild_id: '${guild.id}',\n trigger: '${args.trigger}',\n trigger_type: '${args.type || \"contains\"}',\n response: '${args.response}',\n chance: '${args.chance || 100}',\n created_at: '${now()}',\n },\n as: 'newTrigger',\n },\n {\n action: 'reply',\n content: 'Auto-response added! ID: ${newTrigger.id}',\n ephemeral: true,\n },\n ],\n },\n {\n name: 'list',\n description: 'List auto-responses',\n actions: [\n {\n action: 'db_query',\n table: 'auto_responses',\n where: { guild_id: '${guild.id}' },\n as: 'triggers',\n },\n {\n action: 'flow_if',\n condition: 'triggers.length === 0',\n then: [\n { action: 'reply', content: 'No auto-responses configured!', ephemeral: true },\n { action: 'abort' },\n ],\n },\n {\n action: 'set',\n key: 'triggerList',\n value: '${triggers.map(t => \"**\" + t.id + \".** `\" + truncate(t.trigger, 30) + \"` → `\" + truncate(t.response, 30) + \"` (\" + t.trigger_type + \")\").join(\"\\\\n\")}',\n },\n {\n action: 'reply',\n embed: {\n title: 'Auto-Responses',\n description: '${triggerList}',\n color: '#5865f2',\n footer: { text: '${triggers.length} trigger(s)' },\n },\n ephemeral: true,\n },\n ],\n },\n {\n name: 'delete',\n description: 'Delete an auto-response',\n options: [\n { name: 'id', description: 'Trigger ID', type: 'integer', required: true },\n ],\n actions: [\n {\n action: 'db_query',\n table: 'auto_responses',\n where: { id: '${args.id}', guild_id: '${guild.id}' },\n as: 'trigger',\n },\n {\n action: 'flow_if',\n condition: 'trigger.length === 0',\n then: [\n { action: 'reply', content: 'Trigger not found!', ephemeral: true },\n { action: 'abort' },\n ],\n },\n {\n action: 'db_delete',\n table: 'auto_responses',\n where: { id: '${args.id}' },\n },\n {\n action: 'db_delete',\n table: 'auto_response_cooldowns',\n where: { response_id: '${args.id}' },\n },\n {\n action: 'reply',\n content: 'Auto-response deleted!',\n ephemeral: true,\n },\n ],\n },\n {\n name: 'edit',\n description: 'Edit an auto-response',\n options: [\n { name: 'id', description: 'Trigger ID', type: 'integer', required: true },\n { name: 'trigger', description: 'New trigger', type: 'string', required: false },\n { name: 'response', description: 'New response', type: 'string', required: false },\n { name: 'cooldown', description: 'Cooldown in seconds', type: 'integer', required: false },\n { name: 'chance', description: 'Response chance (1-100)', type: 'integer', required: false },\n ],\n actions: [\n {\n action: 'db_query',\n table: 'auto_responses',\n where: { id: '${args.id}', guild_id: '${guild.id}' },\n as: 'trigger',\n },\n {\n action: 'flow_if',\n condition: 'trigger.length === 0',\n then: [\n { action: 'reply', content: 'Trigger not found!', ephemeral: true },\n { action: 'abort' },\n ],\n },\n {\n action: 'set',\n key: 'updates',\n value: '${Object.fromEntries(Object.entries({ trigger: args.trigger, response: args.response, cooldown: args.cooldown, chance: args.chance }).filter(([_, v]) => v !== undefined))}',\n },\n {\n action: 'db_update',\n table: 'auto_responses',\n where: { id: '${args.id}' },\n data: '${updates}',\n },\n {\n action: 'reply',\n content: 'Auto-response updated!',\n ephemeral: true,\n },\n ],\n },\n ],\n },\n];\n\nexport function getAutoResponderSpec(config: AutoResponderConfig = {}): Partial<FurlowSpec> {\n return {\n commands: autoResponderCommands,\n events: autoResponderEventHandlers,\n state: {\n tables: autoResponderTables,\n },\n };\n}\n"],"mappings":"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","names":[]}
|
package/dist/giveaways/index.js
CHANGED
|
@@ -28,7 +28,7 @@ var giveawaysEventHandlers = [
|
|
|
28
28
|
// Handle giveaway button click
|
|
29
29
|
{
|
|
30
30
|
event: "button_click",
|
|
31
|
-
condition: '
|
|
31
|
+
condition: 'interaction.customId.startsWith("giveaway_enter_")',
|
|
32
32
|
actions: [
|
|
33
33
|
{
|
|
34
34
|
action: "set",
|
|
@@ -43,7 +43,7 @@ var giveawaysEventHandlers = [
|
|
|
43
43
|
},
|
|
44
44
|
{
|
|
45
45
|
action: "flow_if",
|
|
46
|
-
condition: "
|
|
46
|
+
condition: "!giveaway[0] || giveaway[0].ended",
|
|
47
47
|
then: [
|
|
48
48
|
{ action: "reply", content: "This giveaway has ended!", ephemeral: true },
|
|
49
49
|
{ action: "abort" }
|
|
@@ -52,7 +52,7 @@ var giveawaysEventHandlers = [
|
|
|
52
52
|
// Check role requirement
|
|
53
53
|
{
|
|
54
54
|
action: "flow_if",
|
|
55
|
-
condition: "
|
|
55
|
+
condition: "giveaway[0].require_role && !member.roles.cache.has(giveaway[0].require_role)",
|
|
56
56
|
then: [
|
|
57
57
|
{ action: "reply", content: "You need the <@&${giveaway[0].require_role}> role to enter!", ephemeral: true },
|
|
58
58
|
{ action: "abort" }
|
|
@@ -67,7 +67,7 @@ var giveawaysEventHandlers = [
|
|
|
67
67
|
},
|
|
68
68
|
{
|
|
69
69
|
action: "flow_if",
|
|
70
|
-
condition: "
|
|
70
|
+
condition: "existing.length > 0",
|
|
71
71
|
then: [
|
|
72
72
|
// Remove entry
|
|
73
73
|
{
|
|
@@ -165,7 +165,7 @@ var giveawaysEventHandlers = [
|
|
|
165
165
|
// Update message
|
|
166
166
|
{
|
|
167
167
|
action: "flow_if",
|
|
168
|
-
condition: "
|
|
168
|
+
condition: "winners.length === 0",
|
|
169
169
|
then: [
|
|
170
170
|
{
|
|
171
171
|
action: "edit_message",
|
|
@@ -314,7 +314,7 @@ var giveawaysCommands = [
|
|
|
314
314
|
},
|
|
315
315
|
{
|
|
316
316
|
action: "flow_if",
|
|
317
|
-
condition: "
|
|
317
|
+
condition: "!giveaway[0]",
|
|
318
318
|
then: [
|
|
319
319
|
{ action: "reply", content: "Giveaway not found!", ephemeral: true },
|
|
320
320
|
{ action: "abort" }
|
|
@@ -348,7 +348,7 @@ var giveawaysCommands = [
|
|
|
348
348
|
},
|
|
349
349
|
{
|
|
350
350
|
action: "flow_if",
|
|
351
|
-
condition: "
|
|
351
|
+
condition: "!giveaway[0] || !giveaway[0].ended",
|
|
352
352
|
then: [
|
|
353
353
|
{ action: "reply", content: "Giveaway not found or not ended!", ephemeral: true },
|
|
354
354
|
{ action: "abort" }
|
|
@@ -372,7 +372,7 @@ var giveawaysCommands = [
|
|
|
372
372
|
},
|
|
373
373
|
{
|
|
374
374
|
action: "flow_if",
|
|
375
|
-
condition: "
|
|
375
|
+
condition: "winners.length === 0",
|
|
376
376
|
then: [
|
|
377
377
|
{ action: "reply", content: "No valid entries to reroll!", ephemeral: true },
|
|
378
378
|
{ action: "abort" }
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/giveaways/index.ts"],"sourcesContent":["/**\n * Giveaways builtin module\n * Handles giveaway creation, entries, and winner selection\n */\n\nimport type { FurlowSpec, CommandDefinition, EventHandler, TableDefinition } from '@furlow/schema';\n\nexport interface GiveawaysConfig {\n /** Default giveaway duration */\n defaultDuration?: string;\n /** Giveaway manager role */\n managerRole?: string;\n /** Require role to enter */\n requireRole?: string;\n /** Embed color */\n embedColor?: string;\n /** End emoji */\n emoji?: string;\n}\n\nexport const giveawaysTables: Record<string, TableDefinition> = {\n giveaways: {\n columns: {\n id: { type: 'number', primary: true },\n guild_id: { type: 'string', index: true },\n channel_id: { type: 'string' },\n message_id: { type: 'string', unique: true },\n host_id: { type: 'string' },\n prize: { type: 'string' },\n winners_count: { type: 'number', default: 1 },\n ends_at: { type: 'timestamp', index: true },\n ended: { type: 'boolean', default: false },\n require_role: { type: 'string' },\n created_at: { type: 'timestamp' },\n },\n },\n giveaway_entries: {\n columns: {\n id: { type: 'number', primary: true },\n giveaway_id: { type: 'number', index: true },\n user_id: { type: 'string' },\n created_at: { type: 'timestamp' },\n },\n },\n};\n\nexport const giveawaysEventHandlers: EventHandler[] = [\n // Handle giveaway button click\n {\n event: 'button_click',\n condition: '${interaction.customId.startsWith(\"giveaway_enter_\")}',\n actions: [\n {\n action: 'set',\n key: 'giveawayId',\n value: '${interaction.customId.replace(\"giveaway_enter_\", \"\")}',\n },\n {\n action: 'db_query',\n table: 'giveaways',\n where: { id: '${giveawayId}' },\n as: 'giveaway',\n },\n {\n action: 'flow_if',\n condition: '${!giveaway[0] || giveaway[0].ended}',\n then: [\n { action: 'reply', content: 'This giveaway has ended!', ephemeral: true },\n { action: 'abort' },\n ],\n },\n // Check role requirement\n {\n action: 'flow_if',\n condition: '${giveaway[0].require_role && !member.roles.cache.has(giveaway[0].require_role)}',\n then: [\n { action: 'reply', content: 'You need the <@&${giveaway[0].require_role}> role to enter!', ephemeral: true },\n { action: 'abort' },\n ],\n },\n // Check if already entered\n {\n action: 'db_query',\n table: 'giveaway_entries',\n where: { giveaway_id: '${giveawayId}', user_id: '${user.id}' },\n as: 'existing',\n },\n {\n action: 'flow_if',\n condition: '${existing.length > 0}',\n then: [\n // Remove entry\n {\n action: 'db_delete',\n table: 'giveaway_entries',\n where: { giveaway_id: '${giveawayId}', user_id: '${user.id}' },\n },\n { action: 'reply', content: 'You have left the giveaway!', ephemeral: true },\n ],\n else: [\n // Add entry\n {\n action: 'db_insert',\n table: 'giveaway_entries',\n data: {\n giveaway_id: '${giveawayId}',\n user_id: '${user.id}',\n created_at: '${now()}',\n },\n },\n { action: 'reply', content: 'You have entered the giveaway!', ephemeral: true },\n ],\n },\n // Update entry count on message\n {\n action: 'db_query',\n table: 'giveaway_entries',\n where: { giveaway_id: '${giveawayId}' },\n as: 'entries',\n },\n {\n action: 'edit_message',\n channel: '${giveaway[0].channel_id}',\n message: '${giveaway[0].message_id}',\n embed: {\n title: '${config.giveaways?.emoji || \"🎉\"} GIVEAWAY ${config.giveaways?.emoji || \"🎉\"}',\n description: '**Prize:** ${giveaway[0].prize}\\n**Hosted by:** <@${giveaway[0].host_id}>\\n**Winners:** ${giveaway[0].winners_count}\\n**Entries:** ${entries.length}\\n\\nEnds: ${timestamp(giveaway[0].ends_at, \"R\")}',\n color: '${config.giveaways?.embedColor || \"#ff73fa\"}',\n footer: { text: 'ID: ${giveaway[0].id}' },\n },\n },\n ],\n },\n // Scheduled giveaway end\n {\n event: 'scheduler_tick',\n actions: [\n {\n action: 'db_query',\n table: 'giveaways',\n where: { ended: false },\n as: 'activeGiveaways',\n },\n {\n action: 'batch',\n items: '${activeGiveaways.filter(g => new Date(g.ends_at) <= now())}',\n each: { action: 'emit', event: 'giveaway_end', data: { giveawayId: '${item.id}' } },\n },\n ],\n },\n // End giveaway\n {\n event: 'giveaway_end',\n actions: [\n {\n action: 'db_query',\n table: 'giveaways',\n where: { id: '${event.data.giveawayId}' },\n as: 'giveaway',\n },\n {\n action: 'db_query',\n table: 'giveaway_entries',\n where: { giveaway_id: '${event.data.giveawayId}' },\n as: 'entries',\n },\n // Select winners\n {\n action: 'set',\n key: 'shuffled',\n value: '${shuffle(entries)}',\n },\n {\n action: 'set',\n key: 'winners',\n value: '${shuffled.slice(0, giveaway[0].winners_count)}',\n },\n // Mark as ended\n {\n action: 'db_update',\n table: 'giveaways',\n where: { id: '${event.data.giveawayId}' },\n data: { ended: true },\n },\n // Update message\n {\n action: 'flow_if',\n condition: '${winners.length === 0}',\n then: [\n {\n action: 'edit_message',\n channel: '${giveaway[0].channel_id}',\n message: '${giveaway[0].message_id}',\n embed: {\n title: 'GIVEAWAY ENDED',\n description: '**Prize:** ${giveaway[0].prize}\\n\\nNo valid entries.',\n color: '#72767d',\n },\n components: [],\n },\n ],\n else: [\n {\n action: 'set',\n key: 'winnerMentions',\n value: '${winners.map(w => \"<@\" + w.user_id + \">\").join(\", \")}',\n },\n {\n action: 'edit_message',\n channel: '${giveaway[0].channel_id}',\n message: '${giveaway[0].message_id}',\n embed: {\n title: 'GIVEAWAY ENDED',\n description: '**Prize:** ${giveaway[0].prize}\\n\\n**Winners:** ${winnerMentions}',\n color: '#57f287',\n },\n components: [],\n },\n {\n action: 'send_message',\n channel: '${giveaway[0].channel_id}',\n content: 'Congratulations ${winnerMentions}! You won **${giveaway[0].prize}**!',\n },\n ],\n },\n ],\n },\n];\n\nexport const giveawaysCommands: CommandDefinition[] = [\n {\n name: 'giveaway',\n description: 'Giveaway management',\n subcommands: [\n {\n name: 'start',\n description: 'Start a giveaway',\n options: [\n { name: 'prize', description: 'Prize to give away', type: 'string', required: true },\n { name: 'duration', description: 'Duration (e.g., 1h, 1d, 1w)', type: 'string', required: true },\n { name: 'winners', description: 'Number of winners', type: 'integer', required: false },\n { name: 'require_role', description: 'Required role to enter', type: 'role', required: false },\n ],\n actions: [\n {\n action: 'set',\n key: 'endsAt',\n value: '${addDuration(now(), args.duration)}',\n },\n {\n action: 'send_message',\n channel: '${channel.id}',\n embed: {\n title: '${config.giveaways?.emoji || \"🎉\"} GIVEAWAY ${config.giveaways?.emoji || \"🎉\"}',\n description: '**Prize:** ${args.prize}\\n**Hosted by:** ${user}\\n**Winners:** ${args.winners || 1}\\n**Entries:** 0\\n\\nEnds: ${timestamp(endsAt, \"R\")}',\n color: '${config.giveaways?.embedColor || \"#ff73fa\"}',\n },\n components: [\n {\n type: 'action_row',\n components: [\n {\n type: 'button',\n style: 'primary',\n label: 'Enter',\n emoji: '🎉',\n custom_id: 'giveaway_enter_PLACEHOLDER',\n },\n ],\n },\n ],\n as: 'giveawayMessage',\n },\n {\n action: 'db_insert',\n table: 'giveaways',\n data: {\n guild_id: '${guild.id}',\n channel_id: '${channel.id}',\n message_id: '${giveawayMessage.id}',\n host_id: '${user.id}',\n prize: '${args.prize}',\n winners_count: '${args.winners || 1}',\n ends_at: '${endsAt}',\n require_role: '${args.require_role?.id}',\n created_at: '${now()}',\n },\n as: 'giveaway',\n },\n // Update button with correct ID\n {\n action: 'edit_message',\n channel: '${channel.id}',\n message: '${giveawayMessage.id}',\n embed: {\n title: '${config.giveaways?.emoji || \"🎉\"} GIVEAWAY ${config.giveaways?.emoji || \"🎉\"}',\n description: '**Prize:** ${args.prize}\\n**Hosted by:** ${user}\\n**Winners:** ${args.winners || 1}\\n**Entries:** 0\\n\\nEnds: ${timestamp(endsAt, \"R\")}',\n color: '${config.giveaways?.embedColor || \"#ff73fa\"}',\n footer: { text: 'ID: ${giveaway.id}' },\n },\n components: [\n {\n type: 'action_row',\n components: [\n {\n type: 'button',\n style: 'primary',\n label: 'Enter',\n emoji: '🎉',\n custom_id: 'giveaway_enter_${giveaway.id}',\n },\n ],\n },\n ],\n },\n {\n action: 'reply',\n content: 'Giveaway started!',\n ephemeral: true,\n },\n ],\n },\n {\n name: 'end',\n description: 'End a giveaway early',\n options: [\n { name: 'message_id', description: 'Giveaway message ID', type: 'string', required: true },\n ],\n actions: [\n {\n action: 'db_query',\n table: 'giveaways',\n where: { message_id: '${args.message_id}' },\n as: 'giveaway',\n },\n {\n action: 'flow_if',\n condition: '${!giveaway[0]}',\n then: [\n { action: 'reply', content: 'Giveaway not found!', ephemeral: true },\n { action: 'abort' },\n ],\n },\n {\n action: 'emit',\n event: 'giveaway_end',\n data: { giveawayId: '${giveaway[0].id}' },\n },\n {\n action: 'reply',\n content: 'Giveaway ended!',\n ephemeral: true,\n },\n ],\n },\n {\n name: 'reroll',\n description: 'Reroll winners for an ended giveaway',\n options: [\n { name: 'message_id', description: 'Giveaway message ID', type: 'string', required: true },\n { name: 'winners', description: 'Number of new winners', type: 'integer', required: false },\n ],\n actions: [\n {\n action: 'db_query',\n table: 'giveaways',\n where: { message_id: '${args.message_id}' },\n as: 'giveaway',\n },\n {\n action: 'flow_if',\n condition: '${!giveaway[0] || !giveaway[0].ended}',\n then: [\n { action: 'reply', content: 'Giveaway not found or not ended!', ephemeral: true },\n { action: 'abort' },\n ],\n },\n {\n action: 'db_query',\n table: 'giveaway_entries',\n where: { giveaway_id: '${giveaway[0].id}' },\n as: 'entries',\n },\n {\n action: 'set',\n key: 'shuffled',\n value: '${shuffle(entries)}',\n },\n {\n action: 'set',\n key: 'winners',\n value: '${shuffled.slice(0, args.winners || 1)}',\n },\n {\n action: 'flow_if',\n condition: '${winners.length === 0}',\n then: [\n { action: 'reply', content: 'No valid entries to reroll!', ephemeral: true },\n { action: 'abort' },\n ],\n },\n {\n action: 'set',\n key: 'winnerMentions',\n value: '${winners.map(w => \"<@\" + w.user_id + \">\").join(\", \")}',\n },\n {\n action: 'send_message',\n channel: '${giveaway[0].channel_id}',\n content: 'New winner(s): ${winnerMentions}! Congratulations on winning **${giveaway[0].prize}**!',\n },\n {\n action: 'reply',\n content: 'Rerolled successfully!',\n ephemeral: true,\n },\n ],\n },\n ],\n },\n];\n\nexport function getGiveawaysSpec(config: GiveawaysConfig = {}): Partial<FurlowSpec> {\n return {\n commands: giveawaysCommands,\n events: giveawaysEventHandlers,\n state: {\n tables: giveawaysTables,\n },\n };\n}\n"],"mappings":";AAoBO,IAAM,kBAAmD;AAAA,EAC9D,WAAW;AAAA,IACT,SAAS;AAAA,MACP,IAAI,EAAE,MAAM,UAAU,SAAS,KAAK;AAAA,MACpC,UAAU,EAAE,MAAM,UAAU,OAAO,KAAK;AAAA,MACxC,YAAY,EAAE,MAAM,SAAS;AAAA,MAC7B,YAAY,EAAE,MAAM,UAAU,QAAQ,KAAK;AAAA,MAC3C,SAAS,EAAE,MAAM,SAAS;AAAA,MAC1B,OAAO,EAAE,MAAM,SAAS;AAAA,MACxB,eAAe,EAAE,MAAM,UAAU,SAAS,EAAE;AAAA,MAC5C,SAAS,EAAE,MAAM,aAAa,OAAO,KAAK;AAAA,MAC1C,OAAO,EAAE,MAAM,WAAW,SAAS,MAAM;AAAA,MACzC,cAAc,EAAE,MAAM,SAAS;AAAA,MAC/B,YAAY,EAAE,MAAM,YAAY;AAAA,IAClC;AAAA,EACF;AAAA,EACA,kBAAkB;AAAA,IAChB,SAAS;AAAA,MACP,IAAI,EAAE,MAAM,UAAU,SAAS,KAAK;AAAA,MACpC,aAAa,EAAE,MAAM,UAAU,OAAO,KAAK;AAAA,MAC3C,SAAS,EAAE,MAAM,SAAS;AAAA,MAC1B,YAAY,EAAE,MAAM,YAAY;AAAA,IAClC;AAAA,EACF;AACF;AAEO,IAAM,yBAAyC;AAAA;AAAA,EAEpD;AAAA,IACE,OAAO;AAAA,IACP,WAAW;AAAA,IACX,SAAS;AAAA,MACP;AAAA,QACE,QAAQ;AAAA,QACR,KAAK;AAAA,QACL,OAAO;AAAA,MACT;AAAA,MACA;AAAA,QACE,QAAQ;AAAA,QACR,OAAO;AAAA,QACP,OAAO,EAAE,IAAI,gBAAgB;AAAA,QAC7B,IAAI;AAAA,MACN;AAAA,MACA;AAAA,QACE,QAAQ;AAAA,QACR,WAAW;AAAA,QACX,MAAM;AAAA,UACJ,EAAE,QAAQ,SAAS,SAAS,4BAA4B,WAAW,KAAK;AAAA,UACxE,EAAE,QAAQ,QAAQ;AAAA,QACpB;AAAA,MACF;AAAA;AAAA,MAEA;AAAA,QACE,QAAQ;AAAA,QACR,WAAW;AAAA,QACX,MAAM;AAAA,UACJ,EAAE,QAAQ,SAAS,SAAS,+DAA+D,WAAW,KAAK;AAAA,UAC3G,EAAE,QAAQ,QAAQ;AAAA,QACpB;AAAA,MACF;AAAA;AAAA,MAEA;AAAA,QACE,QAAQ;AAAA,QACR,OAAO;AAAA,QACP,OAAO,EAAE,aAAa,iBAAiB,SAAS,aAAa;AAAA,QAC7D,IAAI;AAAA,MACN;AAAA,MACA;AAAA,QACE,QAAQ;AAAA,QACR,WAAW;AAAA,QACX,MAAM;AAAA;AAAA,UAEJ;AAAA,YACE,QAAQ;AAAA,YACR,OAAO;AAAA,YACP,OAAO,EAAE,aAAa,iBAAiB,SAAS,aAAa;AAAA,UAC/D;AAAA,UACA,EAAE,QAAQ,SAAS,SAAS,+BAA+B,WAAW,KAAK;AAAA,QAC7E;AAAA,QACA,MAAM;AAAA;AAAA,UAEJ;AAAA,YACE,QAAQ;AAAA,YACR,OAAO;AAAA,YACP,MAAM;AAAA,cACJ,aAAa;AAAA,cACb,SAAS;AAAA,cACT,YAAY;AAAA,YACd;AAAA,UACF;AAAA,UACA,EAAE,QAAQ,SAAS,SAAS,kCAAkC,WAAW,KAAK;AAAA,QAChF;AAAA,MACF;AAAA;AAAA,MAEA;AAAA,QACE,QAAQ;AAAA,QACR,OAAO;AAAA,QACP,OAAO,EAAE,aAAa,gBAAgB;AAAA,QACtC,IAAI;AAAA,MACN;AAAA,MACA;AAAA,QACE,QAAQ;AAAA,QACR,SAAS;AAAA,QACT,SAAS;AAAA,QACT,OAAO;AAAA,UACL,OAAO;AAAA,UACP,aAAa;AAAA,UACb,OAAO;AAAA,UACP,QAAQ,EAAE,MAAM,wBAAwB;AAAA,QAC1C;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA;AAAA,EAEA;AAAA,IACE,OAAO;AAAA,IACP,SAAS;AAAA,MACP;AAAA,QACE,QAAQ;AAAA,QACR,OAAO;AAAA,QACP,OAAO,EAAE,OAAO,MAAM;AAAA,QACtB,IAAI;AAAA,MACN;AAAA,MACA;AAAA,QACE,QAAQ;AAAA,QACR,OAAO;AAAA,QACP,MAAM,EAAE,QAAQ,QAAQ,OAAO,gBAAgB,MAAM,EAAE,YAAY,aAAa,EAAE;AAAA,MACpF;AAAA,IACF;AAAA,EACF;AAAA;AAAA,EAEA;AAAA,IACE,OAAO;AAAA,IACP,SAAS;AAAA,MACP;AAAA,QACE,QAAQ;AAAA,QACR,OAAO;AAAA,QACP,OAAO,EAAE,IAAI,2BAA2B;AAAA,QACxC,IAAI;AAAA,MACN;AAAA,MACA;AAAA,QACE,QAAQ;AAAA,QACR,OAAO;AAAA,QACP,OAAO,EAAE,aAAa,2BAA2B;AAAA,QACjD,IAAI;AAAA,MACN;AAAA;AAAA,MAEA;AAAA,QACE,QAAQ;AAAA,QACR,KAAK;AAAA,QACL,OAAO;AAAA,MACT;AAAA,MACA;AAAA,QACE,QAAQ;AAAA,QACR,KAAK;AAAA,QACL,OAAO;AAAA,MACT;AAAA;AAAA,MAEA;AAAA,QACE,QAAQ;AAAA,QACR,OAAO;AAAA,QACP,OAAO,EAAE,IAAI,2BAA2B;AAAA,QACxC,MAAM,EAAE,OAAO,KAAK;AAAA,MACtB;AAAA;AAAA,MAEA;AAAA,QACE,QAAQ;AAAA,QACR,WAAW;AAAA,QACX,MAAM;AAAA,UACJ;AAAA,YACE,QAAQ;AAAA,YACR,SAAS;AAAA,YACT,SAAS;AAAA,YACT,OAAO;AAAA,cACL,OAAO;AAAA,cACP,aAAa;AAAA,cACb,OAAO;AAAA,YACT;AAAA,YACA,YAAY,CAAC;AAAA,UACf;AAAA,QACF;AAAA,QACA,MAAM;AAAA,UACJ;AAAA,YACE,QAAQ;AAAA,YACR,KAAK;AAAA,YACL,OAAO;AAAA,UACT;AAAA,UACA;AAAA,YACE,QAAQ;AAAA,YACR,SAAS;AAAA,YACT,SAAS;AAAA,YACT,OAAO;AAAA,cACL,OAAO;AAAA,cACP,aAAa;AAAA,cACb,OAAO;AAAA,YACT;AAAA,YACA,YAAY,CAAC;AAAA,UACf;AAAA,UACA;AAAA,YACE,QAAQ;AAAA,YACR,SAAS;AAAA,YACT,SAAS;AAAA,UACX;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;AAEO,IAAM,oBAAyC;AAAA,EACpD;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,aAAa;AAAA,MACX;AAAA,QACE,MAAM;AAAA,QACN,aAAa;AAAA,QACb,SAAS;AAAA,UACP,EAAE,MAAM,SAAS,aAAa,sBAAsB,MAAM,UAAU,UAAU,KAAK;AAAA,UACnF,EAAE,MAAM,YAAY,aAAa,+BAA+B,MAAM,UAAU,UAAU,KAAK;AAAA,UAC/F,EAAE,MAAM,WAAW,aAAa,qBAAqB,MAAM,WAAW,UAAU,MAAM;AAAA,UACtF,EAAE,MAAM,gBAAgB,aAAa,0BAA0B,MAAM,QAAQ,UAAU,MAAM;AAAA,QAC/F;AAAA,QACA,SAAS;AAAA,UACP;AAAA,YACE,QAAQ;AAAA,YACR,KAAK;AAAA,YACL,OAAO;AAAA,UACT;AAAA,UACA;AAAA,YACE,QAAQ;AAAA,YACR,SAAS;AAAA,YACT,OAAO;AAAA,cACL,OAAO;AAAA,cACP,aAAa;AAAA,cACb,OAAO;AAAA,YACT;AAAA,YACA,YAAY;AAAA,cACV;AAAA,gBACE,MAAM;AAAA,gBACN,YAAY;AAAA,kBACV;AAAA,oBACE,MAAM;AAAA,oBACN,OAAO;AAAA,oBACP,OAAO;AAAA,oBACP,OAAO;AAAA,oBACP,WAAW;AAAA,kBACb;AAAA,gBACF;AAAA,cACF;AAAA,YACF;AAAA,YACA,IAAI;AAAA,UACN;AAAA,UACA;AAAA,YACE,QAAQ;AAAA,YACR,OAAO;AAAA,YACP,MAAM;AAAA,cACJ,UAAU;AAAA,cACV,YAAY;AAAA,cACZ,YAAY;AAAA,cACZ,SAAS;AAAA,cACT,OAAO;AAAA,cACP,eAAe;AAAA,cACf,SAAS;AAAA,cACT,cAAc;AAAA,cACd,YAAY;AAAA,YACd;AAAA,YACA,IAAI;AAAA,UACN;AAAA;AAAA,UAEA;AAAA,YACE,QAAQ;AAAA,YACR,SAAS;AAAA,YACT,SAAS;AAAA,YACT,OAAO;AAAA,cACL,OAAO;AAAA,cACP,aAAa;AAAA,cACb,OAAO;AAAA,cACP,QAAQ,EAAE,MAAM,qBAAqB;AAAA,YACvC;AAAA,YACA,YAAY;AAAA,cACV;AAAA,gBACE,MAAM;AAAA,gBACN,YAAY;AAAA,kBACV;AAAA,oBACE,MAAM;AAAA,oBACN,OAAO;AAAA,oBACP,OAAO;AAAA,oBACP,OAAO;AAAA,oBACP,WAAW;AAAA,kBACb;AAAA,gBACF;AAAA,cACF;AAAA,YACF;AAAA,UACF;AAAA,UACA;AAAA,YACE,QAAQ;AAAA,YACR,SAAS;AAAA,YACT,WAAW;AAAA,UACb;AAAA,QACF;AAAA,MACF;AAAA,MACA;AAAA,QACE,MAAM;AAAA,QACN,aAAa;AAAA,QACb,SAAS;AAAA,UACP,EAAE,MAAM,cAAc,aAAa,uBAAuB,MAAM,UAAU,UAAU,KAAK;AAAA,QAC3F;AAAA,QACA,SAAS;AAAA,UACP;AAAA,YACE,QAAQ;AAAA,YACR,OAAO;AAAA,YACP,OAAO,EAAE,YAAY,qBAAqB;AAAA,YAC1C,IAAI;AAAA,UACN;AAAA,UACA;AAAA,YACE,QAAQ;AAAA,YACR,WAAW;AAAA,YACX,MAAM;AAAA,cACJ,EAAE,QAAQ,SAAS,SAAS,uBAAuB,WAAW,KAAK;AAAA,cACnE,EAAE,QAAQ,QAAQ;AAAA,YACpB;AAAA,UACF;AAAA,UACA;AAAA,YACE,QAAQ;AAAA,YACR,OAAO;AAAA,YACP,MAAM,EAAE,YAAY,oBAAoB;AAAA,UAC1C;AAAA,UACA;AAAA,YACE,QAAQ;AAAA,YACR,SAAS;AAAA,YACT,WAAW;AAAA,UACb;AAAA,QACF;AAAA,MACF;AAAA,MACA;AAAA,QACE,MAAM;AAAA,QACN,aAAa;AAAA,QACb,SAAS;AAAA,UACP,EAAE,MAAM,cAAc,aAAa,uBAAuB,MAAM,UAAU,UAAU,KAAK;AAAA,UACzF,EAAE,MAAM,WAAW,aAAa,yBAAyB,MAAM,WAAW,UAAU,MAAM;AAAA,QAC5F;AAAA,QACA,SAAS;AAAA,UACP;AAAA,YACE,QAAQ;AAAA,YACR,OAAO;AAAA,YACP,OAAO,EAAE,YAAY,qBAAqB;AAAA,YAC1C,IAAI;AAAA,UACN;AAAA,UACA;AAAA,YACE,QAAQ;AAAA,YACR,WAAW;AAAA,YACX,MAAM;AAAA,cACJ,EAAE,QAAQ,SAAS,SAAS,oCAAoC,WAAW,KAAK;AAAA,cAChF,EAAE,QAAQ,QAAQ;AAAA,YACpB;AAAA,UACF;AAAA,UACA;AAAA,YACE,QAAQ;AAAA,YACR,OAAO;AAAA,YACP,OAAO,EAAE,aAAa,oBAAoB;AAAA,YAC1C,IAAI;AAAA,UACN;AAAA,UACA;AAAA,YACE,QAAQ;AAAA,YACR,KAAK;AAAA,YACL,OAAO;AAAA,UACT;AAAA,UACA;AAAA,YACE,QAAQ;AAAA,YACR,KAAK;AAAA,YACL,OAAO;AAAA,UACT;AAAA,UACA;AAAA,YACE,QAAQ;AAAA,YACR,WAAW;AAAA,YACX,MAAM;AAAA,cACJ,EAAE,QAAQ,SAAS,SAAS,+BAA+B,WAAW,KAAK;AAAA,cAC3E,EAAE,QAAQ,QAAQ;AAAA,YACpB;AAAA,UACF;AAAA,UACA;AAAA,YACE,QAAQ;AAAA,YACR,KAAK;AAAA,YACL,OAAO;AAAA,UACT;AAAA,UACA;AAAA,YACE,QAAQ;AAAA,YACR,SAAS;AAAA,YACT,SAAS;AAAA,UACX;AAAA,UACA;AAAA,YACE,QAAQ;AAAA,YACR,SAAS;AAAA,YACT,WAAW;AAAA,UACb;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;AAEO,SAAS,iBAAiB,SAA0B,CAAC,GAAwB;AAClF,SAAO;AAAA,IACL,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,OAAO;AAAA,MACL,QAAQ;AAAA,IACV;AAAA,EACF;AACF;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/giveaways/index.ts"],"sourcesContent":["/**\n * Giveaways builtin module\n * Handles giveaway creation, entries, and winner selection\n */\n\nimport type { FurlowSpec, CommandDefinition, EventHandler, TableDefinition } from '@furlow/schema';\n\nexport interface GiveawaysConfig {\n /** Default giveaway duration */\n defaultDuration?: string;\n /** Giveaway manager role */\n managerRole?: string;\n /** Require role to enter */\n requireRole?: string;\n /** Embed color */\n embedColor?: string;\n /** End emoji */\n emoji?: string;\n}\n\nexport const giveawaysTables: Record<string, TableDefinition> = {\n giveaways: {\n columns: {\n id: { type: 'number', primary: true },\n guild_id: { type: 'string', index: true },\n channel_id: { type: 'string' },\n message_id: { type: 'string', unique: true },\n host_id: { type: 'string' },\n prize: { type: 'string' },\n winners_count: { type: 'number', default: 1 },\n ends_at: { type: 'timestamp', index: true },\n ended: { type: 'boolean', default: false },\n require_role: { type: 'string' },\n created_at: { type: 'timestamp' },\n },\n },\n giveaway_entries: {\n columns: {\n id: { type: 'number', primary: true },\n giveaway_id: { type: 'number', index: true },\n user_id: { type: 'string' },\n created_at: { type: 'timestamp' },\n },\n },\n};\n\nexport const giveawaysEventHandlers: EventHandler[] = [\n // Handle giveaway button click\n {\n event: 'button_click',\n condition: 'interaction.customId.startsWith(\"giveaway_enter_\")',\n actions: [\n {\n action: 'set',\n key: 'giveawayId',\n value: '${interaction.customId.replace(\"giveaway_enter_\", \"\")}',\n },\n {\n action: 'db_query',\n table: 'giveaways',\n where: { id: '${giveawayId}' },\n as: 'giveaway',\n },\n {\n action: 'flow_if',\n condition: '!giveaway[0] || giveaway[0].ended',\n then: [\n { action: 'reply', content: 'This giveaway has ended!', ephemeral: true },\n { action: 'abort' },\n ],\n },\n // Check role requirement\n {\n action: 'flow_if',\n condition: 'giveaway[0].require_role && !member.roles.cache.has(giveaway[0].require_role)',\n then: [\n { action: 'reply', content: 'You need the <@&${giveaway[0].require_role}> role to enter!', ephemeral: true },\n { action: 'abort' },\n ],\n },\n // Check if already entered\n {\n action: 'db_query',\n table: 'giveaway_entries',\n where: { giveaway_id: '${giveawayId}', user_id: '${user.id}' },\n as: 'existing',\n },\n {\n action: 'flow_if',\n condition: 'existing.length > 0',\n then: [\n // Remove entry\n {\n action: 'db_delete',\n table: 'giveaway_entries',\n where: { giveaway_id: '${giveawayId}', user_id: '${user.id}' },\n },\n { action: 'reply', content: 'You have left the giveaway!', ephemeral: true },\n ],\n else: [\n // Add entry\n {\n action: 'db_insert',\n table: 'giveaway_entries',\n data: {\n giveaway_id: '${giveawayId}',\n user_id: '${user.id}',\n created_at: '${now()}',\n },\n },\n { action: 'reply', content: 'You have entered the giveaway!', ephemeral: true },\n ],\n },\n // Update entry count on message\n {\n action: 'db_query',\n table: 'giveaway_entries',\n where: { giveaway_id: '${giveawayId}' },\n as: 'entries',\n },\n {\n action: 'edit_message',\n channel: '${giveaway[0].channel_id}',\n message: '${giveaway[0].message_id}',\n embed: {\n title: '${config.giveaways?.emoji || \"🎉\"} GIVEAWAY ${config.giveaways?.emoji || \"🎉\"}',\n description: '**Prize:** ${giveaway[0].prize}\\n**Hosted by:** <@${giveaway[0].host_id}>\\n**Winners:** ${giveaway[0].winners_count}\\n**Entries:** ${entries.length}\\n\\nEnds: ${timestamp(giveaway[0].ends_at, \"R\")}',\n color: '${config.giveaways?.embedColor || \"#ff73fa\"}',\n footer: { text: 'ID: ${giveaway[0].id}' },\n },\n },\n ],\n },\n // Scheduled giveaway end\n {\n event: 'scheduler_tick',\n actions: [\n {\n action: 'db_query',\n table: 'giveaways',\n where: { ended: false },\n as: 'activeGiveaways',\n },\n {\n action: 'batch',\n items: '${activeGiveaways.filter(g => new Date(g.ends_at) <= now())}',\n each: { action: 'emit', event: 'giveaway_end', data: { giveawayId: '${item.id}' } },\n },\n ],\n },\n // End giveaway\n {\n event: 'giveaway_end',\n actions: [\n {\n action: 'db_query',\n table: 'giveaways',\n where: { id: '${event.data.giveawayId}' },\n as: 'giveaway',\n },\n {\n action: 'db_query',\n table: 'giveaway_entries',\n where: { giveaway_id: '${event.data.giveawayId}' },\n as: 'entries',\n },\n // Select winners\n {\n action: 'set',\n key: 'shuffled',\n value: '${shuffle(entries)}',\n },\n {\n action: 'set',\n key: 'winners',\n value: '${shuffled.slice(0, giveaway[0].winners_count)}',\n },\n // Mark as ended\n {\n action: 'db_update',\n table: 'giveaways',\n where: { id: '${event.data.giveawayId}' },\n data: { ended: true },\n },\n // Update message\n {\n action: 'flow_if',\n condition: 'winners.length === 0',\n then: [\n {\n action: 'edit_message',\n channel: '${giveaway[0].channel_id}',\n message: '${giveaway[0].message_id}',\n embed: {\n title: 'GIVEAWAY ENDED',\n description: '**Prize:** ${giveaway[0].prize}\\n\\nNo valid entries.',\n color: '#72767d',\n },\n components: [],\n },\n ],\n else: [\n {\n action: 'set',\n key: 'winnerMentions',\n value: '${winners.map(w => \"<@\" + w.user_id + \">\").join(\", \")}',\n },\n {\n action: 'edit_message',\n channel: '${giveaway[0].channel_id}',\n message: '${giveaway[0].message_id}',\n embed: {\n title: 'GIVEAWAY ENDED',\n description: '**Prize:** ${giveaway[0].prize}\\n\\n**Winners:** ${winnerMentions}',\n color: '#57f287',\n },\n components: [],\n },\n {\n action: 'send_message',\n channel: '${giveaway[0].channel_id}',\n content: 'Congratulations ${winnerMentions}! You won **${giveaway[0].prize}**!',\n },\n ],\n },\n ],\n },\n];\n\nexport const giveawaysCommands: CommandDefinition[] = [\n {\n name: 'giveaway',\n description: 'Giveaway management',\n subcommands: [\n {\n name: 'start',\n description: 'Start a giveaway',\n options: [\n { name: 'prize', description: 'Prize to give away', type: 'string', required: true },\n { name: 'duration', description: 'Duration (e.g., 1h, 1d, 1w)', type: 'string', required: true },\n { name: 'winners', description: 'Number of winners', type: 'integer', required: false },\n { name: 'require_role', description: 'Required role to enter', type: 'role', required: false },\n ],\n actions: [\n {\n action: 'set',\n key: 'endsAt',\n value: '${addDuration(now(), args.duration)}',\n },\n {\n action: 'send_message',\n channel: '${channel.id}',\n embed: {\n title: '${config.giveaways?.emoji || \"🎉\"} GIVEAWAY ${config.giveaways?.emoji || \"🎉\"}',\n description: '**Prize:** ${args.prize}\\n**Hosted by:** ${user}\\n**Winners:** ${args.winners || 1}\\n**Entries:** 0\\n\\nEnds: ${timestamp(endsAt, \"R\")}',\n color: '${config.giveaways?.embedColor || \"#ff73fa\"}',\n },\n components: [\n {\n type: 'action_row',\n components: [\n {\n type: 'button',\n style: 'primary',\n label: 'Enter',\n emoji: '🎉',\n custom_id: 'giveaway_enter_PLACEHOLDER',\n },\n ],\n },\n ],\n as: 'giveawayMessage',\n },\n {\n action: 'db_insert',\n table: 'giveaways',\n data: {\n guild_id: '${guild.id}',\n channel_id: '${channel.id}',\n message_id: '${giveawayMessage.id}',\n host_id: '${user.id}',\n prize: '${args.prize}',\n winners_count: '${args.winners || 1}',\n ends_at: '${endsAt}',\n require_role: '${args.require_role?.id}',\n created_at: '${now()}',\n },\n as: 'giveaway',\n },\n // Update button with correct ID\n {\n action: 'edit_message',\n channel: '${channel.id}',\n message: '${giveawayMessage.id}',\n embed: {\n title: '${config.giveaways?.emoji || \"🎉\"} GIVEAWAY ${config.giveaways?.emoji || \"🎉\"}',\n description: '**Prize:** ${args.prize}\\n**Hosted by:** ${user}\\n**Winners:** ${args.winners || 1}\\n**Entries:** 0\\n\\nEnds: ${timestamp(endsAt, \"R\")}',\n color: '${config.giveaways?.embedColor || \"#ff73fa\"}',\n footer: { text: 'ID: ${giveaway.id}' },\n },\n components: [\n {\n type: 'action_row',\n components: [\n {\n type: 'button',\n style: 'primary',\n label: 'Enter',\n emoji: '🎉',\n custom_id: 'giveaway_enter_${giveaway.id}',\n },\n ],\n },\n ],\n },\n {\n action: 'reply',\n content: 'Giveaway started!',\n ephemeral: true,\n },\n ],\n },\n {\n name: 'end',\n description: 'End a giveaway early',\n options: [\n { name: 'message_id', description: 'Giveaway message ID', type: 'string', required: true },\n ],\n actions: [\n {\n action: 'db_query',\n table: 'giveaways',\n where: { message_id: '${args.message_id}' },\n as: 'giveaway',\n },\n {\n action: 'flow_if',\n condition: '!giveaway[0]',\n then: [\n { action: 'reply', content: 'Giveaway not found!', ephemeral: true },\n { action: 'abort' },\n ],\n },\n {\n action: 'emit',\n event: 'giveaway_end',\n data: { giveawayId: '${giveaway[0].id}' },\n },\n {\n action: 'reply',\n content: 'Giveaway ended!',\n ephemeral: true,\n },\n ],\n },\n {\n name: 'reroll',\n description: 'Reroll winners for an ended giveaway',\n options: [\n { name: 'message_id', description: 'Giveaway message ID', type: 'string', required: true },\n { name: 'winners', description: 'Number of new winners', type: 'integer', required: false },\n ],\n actions: [\n {\n action: 'db_query',\n table: 'giveaways',\n where: { message_id: '${args.message_id}' },\n as: 'giveaway',\n },\n {\n action: 'flow_if',\n condition: '!giveaway[0] || !giveaway[0].ended',\n then: [\n { action: 'reply', content: 'Giveaway not found or not ended!', ephemeral: true },\n { action: 'abort' },\n ],\n },\n {\n action: 'db_query',\n table: 'giveaway_entries',\n where: { giveaway_id: '${giveaway[0].id}' },\n as: 'entries',\n },\n {\n action: 'set',\n key: 'shuffled',\n value: '${shuffle(entries)}',\n },\n {\n action: 'set',\n key: 'winners',\n value: '${shuffled.slice(0, args.winners || 1)}',\n },\n {\n action: 'flow_if',\n condition: 'winners.length === 0',\n then: [\n { action: 'reply', content: 'No valid entries to reroll!', ephemeral: true },\n { action: 'abort' },\n ],\n },\n {\n action: 'set',\n key: 'winnerMentions',\n value: '${winners.map(w => \"<@\" + w.user_id + \">\").join(\", \")}',\n },\n {\n action: 'send_message',\n channel: '${giveaway[0].channel_id}',\n content: 'New winner(s): ${winnerMentions}! Congratulations on winning **${giveaway[0].prize}**!',\n },\n {\n action: 'reply',\n content: 'Rerolled successfully!',\n ephemeral: true,\n },\n ],\n },\n ],\n },\n];\n\nexport function getGiveawaysSpec(config: GiveawaysConfig = {}): Partial<FurlowSpec> {\n return {\n commands: giveawaysCommands,\n events: giveawaysEventHandlers,\n state: {\n tables: giveawaysTables,\n },\n };\n}\n"],"mappings":"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","names":[]}
|