@furlow/builtins 0.1.0
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.d.ts +21 -0
- package/dist/afk/index.js +195 -0
- package/dist/afk/index.js.map +1 -0
- package/dist/auto-responder/index.d.ts +21 -0
- package/dist/auto-responder/index.js +356 -0
- package/dist/auto-responder/index.js.map +1 -0
- package/dist/giveaways/index.d.ts +25 -0
- package/dist/giveaways/index.js +416 -0
- package/dist/giveaways/index.js.map +1 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.js +5402 -0
- package/dist/index.js.map +1 -0
- package/dist/leveling/index.d.ts +46 -0
- package/dist/leveling/index.js +521 -0
- package/dist/leveling/index.js.map +1 -0
- package/dist/logging/index.d.ts +52 -0
- package/dist/logging/index.js +519 -0
- package/dist/logging/index.js.map +1 -0
- package/dist/moderation/index.d.ts +83 -0
- package/dist/moderation/index.js +221 -0
- package/dist/moderation/index.js.map +1 -0
- package/dist/music/index.d.ts +33 -0
- package/dist/music/index.js +414 -0
- package/dist/music/index.js.map +1 -0
- package/dist/polls/index.d.ts +21 -0
- package/dist/polls/index.js +395 -0
- package/dist/polls/index.js.map +1 -0
- package/dist/reaction-roles/index.d.ts +19 -0
- package/dist/reaction-roles/index.js +551 -0
- package/dist/reaction-roles/index.js.map +1 -0
- package/dist/reminders/index.d.ts +23 -0
- package/dist/reminders/index.js +224 -0
- package/dist/reminders/index.js.map +1 -0
- package/dist/starboard/index.d.ts +35 -0
- package/dist/starboard/index.js +401 -0
- package/dist/starboard/index.js.map +1 -0
- package/dist/tickets/index.d.ts +43 -0
- package/dist/tickets/index.js +614 -0
- package/dist/tickets/index.js.map +1 -0
- package/dist/utilities/index.d.ts +15 -0
- package/dist/utilities/index.js +299 -0
- package/dist/utilities/index.js.map +1 -0
- package/dist/welcome/index.d.ts +48 -0
- package/dist/welcome/index.js +302 -0
- package/dist/welcome/index.js.map +1 -0
- package/package.json +109 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { CommandDefinition, EventHandler, TableDefinition, FurlowSpec } from '@furlow/schema';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* AFK builtin module
|
|
5
|
+
* Handles AFK status and mention notifications
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
interface AfkConfig {
|
|
9
|
+
/** Maximum AFK reason length */
|
|
10
|
+
maxReasonLength?: number;
|
|
11
|
+
/** Add prefix to nickname */
|
|
12
|
+
nicknamePrefix?: string;
|
|
13
|
+
/** Ignore bot mentions */
|
|
14
|
+
ignoreBots?: boolean;
|
|
15
|
+
}
|
|
16
|
+
declare const afkTables: Record<string, TableDefinition>;
|
|
17
|
+
declare const afkEventHandlers: EventHandler[];
|
|
18
|
+
declare const afkCommands: CommandDefinition[];
|
|
19
|
+
declare function getAfkSpec(config?: AfkConfig): Partial<FurlowSpec>;
|
|
20
|
+
|
|
21
|
+
export { type AfkConfig, afkCommands, afkEventHandlers, afkTables, getAfkSpec };
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
// src/afk/index.ts
|
|
2
|
+
var afkTables = {
|
|
3
|
+
afk_users: {
|
|
4
|
+
columns: {
|
|
5
|
+
id: { type: "number", primary: true },
|
|
6
|
+
guild_id: { type: "string", index: true },
|
|
7
|
+
user_id: { type: "string", index: true },
|
|
8
|
+
reason: { type: "string" },
|
|
9
|
+
set_at: { type: "timestamp" }
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
var afkEventHandlers = [
|
|
14
|
+
// Remove AFK when user sends message
|
|
15
|
+
{
|
|
16
|
+
event: "message",
|
|
17
|
+
condition: "${!message.author.bot}",
|
|
18
|
+
actions: [
|
|
19
|
+
{
|
|
20
|
+
action: "db_query",
|
|
21
|
+
table: "afk_users",
|
|
22
|
+
where: { guild_id: "${guild.id}", user_id: "${user.id}" },
|
|
23
|
+
as: "afkStatus"
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
action: "flow_if",
|
|
27
|
+
condition: "${afkStatus.length > 0}",
|
|
28
|
+
then: [
|
|
29
|
+
// Remove AFK
|
|
30
|
+
{
|
|
31
|
+
action: "db_delete",
|
|
32
|
+
table: "afk_users",
|
|
33
|
+
where: { guild_id: "${guild.id}", user_id: "${user.id}" }
|
|
34
|
+
},
|
|
35
|
+
// Remove nickname prefix if set
|
|
36
|
+
{
|
|
37
|
+
action: "flow_if",
|
|
38
|
+
condition: "${config.afk?.nicknamePrefix && member.nickname?.startsWith(config.afk.nicknamePrefix)}",
|
|
39
|
+
then: [
|
|
40
|
+
{
|
|
41
|
+
action: "set_nickname",
|
|
42
|
+
user: "${user.id}",
|
|
43
|
+
nickname: '${member.nickname.replace(config.afk.nicknamePrefix, "")}'
|
|
44
|
+
}
|
|
45
|
+
]
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
action: "send_message",
|
|
49
|
+
channel: "${channel.id}",
|
|
50
|
+
content: "Welcome back ${user}! I removed your AFK status.",
|
|
51
|
+
as: "welcomeBack"
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
action: "wait",
|
|
55
|
+
duration: 5e3
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
action: "delete_message",
|
|
59
|
+
channel: "${channel.id}",
|
|
60
|
+
message: "${welcomeBack.id}"
|
|
61
|
+
}
|
|
62
|
+
]
|
|
63
|
+
}
|
|
64
|
+
]
|
|
65
|
+
},
|
|
66
|
+
// Notify when AFK user is mentioned
|
|
67
|
+
{
|
|
68
|
+
event: "message",
|
|
69
|
+
condition: "${message.mentions.users.size > 0 && !message.author.bot}",
|
|
70
|
+
actions: [
|
|
71
|
+
{
|
|
72
|
+
action: "set",
|
|
73
|
+
key: "mentionedIds",
|
|
74
|
+
value: "${[...message.mentions.users.keys()]}"
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
action: "db_query",
|
|
78
|
+
table: "afk_users",
|
|
79
|
+
where: { guild_id: "${guild.id}" },
|
|
80
|
+
as: "allAfk"
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
action: "set",
|
|
84
|
+
key: "afkMentioned",
|
|
85
|
+
value: "${allAfk.filter(a => mentionedIds.includes(a.user_id))}"
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
action: "flow_if",
|
|
89
|
+
condition: "${afkMentioned.length > 0}",
|
|
90
|
+
then: [
|
|
91
|
+
{
|
|
92
|
+
action: "set",
|
|
93
|
+
key: "afkMessages",
|
|
94
|
+
value: '${afkMentioned.map(a => "<@" + a.user_id + "> is AFK: " + a.reason + " (since " + timestamp(a.set_at, "R") + ")").join("\\n")}'
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
action: "send_message",
|
|
98
|
+
channel: "${channel.id}",
|
|
99
|
+
content: "${afkMessages}",
|
|
100
|
+
as: "afkNotice"
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
action: "wait",
|
|
104
|
+
duration: 1e4
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
action: "delete_message",
|
|
108
|
+
channel: "${channel.id}",
|
|
109
|
+
message: "${afkNotice.id}"
|
|
110
|
+
}
|
|
111
|
+
]
|
|
112
|
+
}
|
|
113
|
+
]
|
|
114
|
+
}
|
|
115
|
+
];
|
|
116
|
+
var afkCommands = [
|
|
117
|
+
{
|
|
118
|
+
name: "afk",
|
|
119
|
+
description: "Set your AFK status",
|
|
120
|
+
options: [
|
|
121
|
+
{ name: "reason", description: "AFK reason", type: "string", required: false }
|
|
122
|
+
],
|
|
123
|
+
actions: [
|
|
124
|
+
{
|
|
125
|
+
action: "set",
|
|
126
|
+
key: "reason",
|
|
127
|
+
value: '${truncate(args.reason || "AFK", config.afk?.maxReasonLength || 100)}'
|
|
128
|
+
},
|
|
129
|
+
// Check if already AFK
|
|
130
|
+
{
|
|
131
|
+
action: "db_query",
|
|
132
|
+
table: "afk_users",
|
|
133
|
+
where: { guild_id: "${guild.id}", user_id: "${user.id}" },
|
|
134
|
+
as: "existing"
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
action: "flow_if",
|
|
138
|
+
condition: "${existing.length > 0}",
|
|
139
|
+
then: [
|
|
140
|
+
{
|
|
141
|
+
action: "db_update",
|
|
142
|
+
table: "afk_users",
|
|
143
|
+
where: { guild_id: "${guild.id}", user_id: "${user.id}" },
|
|
144
|
+
data: { reason: "${reason}", set_at: "${now()}" }
|
|
145
|
+
}
|
|
146
|
+
],
|
|
147
|
+
else: [
|
|
148
|
+
{
|
|
149
|
+
action: "db_insert",
|
|
150
|
+
table: "afk_users",
|
|
151
|
+
data: {
|
|
152
|
+
guild_id: "${guild.id}",
|
|
153
|
+
user_id: "${user.id}",
|
|
154
|
+
reason: "${reason}",
|
|
155
|
+
set_at: "${now()}"
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
]
|
|
159
|
+
},
|
|
160
|
+
// Add nickname prefix if configured
|
|
161
|
+
{
|
|
162
|
+
action: "flow_if",
|
|
163
|
+
condition: "${config.afk?.nicknamePrefix && !member.nickname?.startsWith(config.afk.nicknamePrefix)}",
|
|
164
|
+
then: [
|
|
165
|
+
{
|
|
166
|
+
action: "set_nickname",
|
|
167
|
+
user: "${user.id}",
|
|
168
|
+
nickname: "${config.afk.nicknamePrefix + (member.nickname || user.username)}"
|
|
169
|
+
}
|
|
170
|
+
]
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
action: "reply",
|
|
174
|
+
content: "I set your AFK: ${reason}",
|
|
175
|
+
ephemeral: false
|
|
176
|
+
}
|
|
177
|
+
]
|
|
178
|
+
}
|
|
179
|
+
];
|
|
180
|
+
function getAfkSpec(config = {}) {
|
|
181
|
+
return {
|
|
182
|
+
commands: afkCommands,
|
|
183
|
+
events: afkEventHandlers,
|
|
184
|
+
state: {
|
|
185
|
+
tables: afkTables
|
|
186
|
+
}
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
export {
|
|
190
|
+
afkCommands,
|
|
191
|
+
afkEventHandlers,
|
|
192
|
+
afkTables,
|
|
193
|
+
getAfkSpec
|
|
194
|
+
};
|
|
195
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +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: '${!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":[]}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { CommandDefinition, EventHandler, TableDefinition, FurlowSpec } from '@furlow/schema';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Auto-Responder builtin module
|
|
5
|
+
* Handles trigger-based automatic responses
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
interface AutoResponderConfig {
|
|
9
|
+
/** Maximum triggers per guild */
|
|
10
|
+
maxTriggers?: number;
|
|
11
|
+
/** Ignore bots */
|
|
12
|
+
ignoreBots?: boolean;
|
|
13
|
+
/** Global cooldown (seconds) */
|
|
14
|
+
globalCooldown?: number;
|
|
15
|
+
}
|
|
16
|
+
declare const autoResponderTables: Record<string, TableDefinition>;
|
|
17
|
+
declare const autoResponderEventHandlers: EventHandler[];
|
|
18
|
+
declare const autoResponderCommands: CommandDefinition[];
|
|
19
|
+
declare function getAutoResponderSpec(config?: AutoResponderConfig): Partial<FurlowSpec>;
|
|
20
|
+
|
|
21
|
+
export { type AutoResponderConfig, autoResponderCommands, autoResponderEventHandlers, autoResponderTables, getAutoResponderSpec };
|
|
@@ -0,0 +1,356 @@
|
|
|
1
|
+
// src/auto-responder/index.ts
|
|
2
|
+
var autoResponderTables = {
|
|
3
|
+
auto_responses: {
|
|
4
|
+
columns: {
|
|
5
|
+
id: { type: "number", primary: true },
|
|
6
|
+
guild_id: { type: "string", index: true },
|
|
7
|
+
trigger: { type: "string" },
|
|
8
|
+
trigger_type: { type: "string", default: "contains" },
|
|
9
|
+
// exact, contains, startswith, endswith, regex
|
|
10
|
+
response: { type: "string" },
|
|
11
|
+
response_type: { type: "string", default: "message" },
|
|
12
|
+
// message, embed, reaction
|
|
13
|
+
embed_data: { type: "json" },
|
|
14
|
+
reaction: { type: "string" },
|
|
15
|
+
chance: { type: "number", default: 100 },
|
|
16
|
+
// 0-100 percentage
|
|
17
|
+
cooldown: { type: "number", default: 0 },
|
|
18
|
+
// seconds
|
|
19
|
+
ignore_case: { type: "boolean", default: true },
|
|
20
|
+
delete_trigger: { type: "boolean", default: false },
|
|
21
|
+
dm_response: { type: "boolean", default: false },
|
|
22
|
+
allowed_channels: { type: "json" },
|
|
23
|
+
ignored_channels: { type: "json" },
|
|
24
|
+
allowed_roles: { type: "json" },
|
|
25
|
+
ignored_roles: { type: "json" },
|
|
26
|
+
created_at: { type: "timestamp" }
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
auto_response_cooldowns: {
|
|
30
|
+
columns: {
|
|
31
|
+
id: { type: "number", primary: true },
|
|
32
|
+
response_id: { type: "number", index: true },
|
|
33
|
+
guild_id: { type: "string" },
|
|
34
|
+
last_triggered: { type: "timestamp" }
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
var autoResponderEventHandlers = [
|
|
39
|
+
{
|
|
40
|
+
event: "message",
|
|
41
|
+
condition: "${!message.author.bot || !config.autoResponder?.ignoreBots}",
|
|
42
|
+
actions: [
|
|
43
|
+
// Get all triggers for this guild
|
|
44
|
+
{
|
|
45
|
+
action: "db_query",
|
|
46
|
+
table: "auto_responses",
|
|
47
|
+
where: { guild_id: "${guild.id}" },
|
|
48
|
+
as: "triggers"
|
|
49
|
+
},
|
|
50
|
+
// Check each trigger
|
|
51
|
+
{
|
|
52
|
+
action: "batch",
|
|
53
|
+
items: "${triggers}",
|
|
54
|
+
each: {
|
|
55
|
+
action: "flow_if",
|
|
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
|
+
then: [
|
|
58
|
+
// Check channel restrictions
|
|
59
|
+
{
|
|
60
|
+
action: "flow_if",
|
|
61
|
+
condition: "${item.allowed_channels?.length && !item.allowed_channels.includes(channel.id)}",
|
|
62
|
+
then: [{ action: "abort" }]
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
action: "flow_if",
|
|
66
|
+
condition: "${item.ignored_channels?.includes(channel.id)}",
|
|
67
|
+
then: [{ action: "abort" }]
|
|
68
|
+
},
|
|
69
|
+
// Check role restrictions
|
|
70
|
+
{
|
|
71
|
+
action: "flow_if",
|
|
72
|
+
condition: "${item.allowed_roles?.length && !item.allowed_roles.some(r => member.roles.cache.has(r))}",
|
|
73
|
+
then: [{ action: "abort" }]
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
action: "flow_if",
|
|
77
|
+
condition: "${item.ignored_roles?.some(r => member.roles.cache.has(r))}",
|
|
78
|
+
then: [{ action: "abort" }]
|
|
79
|
+
},
|
|
80
|
+
// Check cooldown
|
|
81
|
+
{
|
|
82
|
+
action: "flow_if",
|
|
83
|
+
condition: "${item.cooldown > 0}",
|
|
84
|
+
then: [
|
|
85
|
+
{
|
|
86
|
+
action: "db_query",
|
|
87
|
+
table: "auto_response_cooldowns",
|
|
88
|
+
where: { response_id: "${item.id}", guild_id: "${guild.id}" },
|
|
89
|
+
as: "cooldown"
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
action: "flow_if",
|
|
93
|
+
condition: "${cooldown[0] && (now() - new Date(cooldown[0].last_triggered)) < item.cooldown * 1000}",
|
|
94
|
+
then: [{ action: "abort" }]
|
|
95
|
+
}
|
|
96
|
+
]
|
|
97
|
+
},
|
|
98
|
+
// Check chance
|
|
99
|
+
{
|
|
100
|
+
action: "flow_if",
|
|
101
|
+
condition: "${item.chance < 100 && random(1, 100) > item.chance}",
|
|
102
|
+
then: [{ action: "abort" }]
|
|
103
|
+
},
|
|
104
|
+
// Execute response
|
|
105
|
+
{
|
|
106
|
+
action: "flow_switch",
|
|
107
|
+
value: "${item.response_type}",
|
|
108
|
+
cases: {
|
|
109
|
+
message: [
|
|
110
|
+
{
|
|
111
|
+
action: "flow_if",
|
|
112
|
+
condition: "${item.dm_response}",
|
|
113
|
+
then: [
|
|
114
|
+
{ action: "send_dm", user: "${user.id}", content: "${item.response}" }
|
|
115
|
+
],
|
|
116
|
+
else: [
|
|
117
|
+
{ action: "send_message", channel: "${channel.id}", content: "${item.response}" }
|
|
118
|
+
]
|
|
119
|
+
}
|
|
120
|
+
],
|
|
121
|
+
embed: [
|
|
122
|
+
{
|
|
123
|
+
action: "flow_if",
|
|
124
|
+
condition: "${item.dm_response}",
|
|
125
|
+
then: [
|
|
126
|
+
{ action: "send_dm", user: "${user.id}", embed: "${item.embed_data}" }
|
|
127
|
+
],
|
|
128
|
+
else: [
|
|
129
|
+
{ action: "send_message", channel: "${channel.id}", embed: "${item.embed_data}" }
|
|
130
|
+
]
|
|
131
|
+
}
|
|
132
|
+
],
|
|
133
|
+
reaction: [
|
|
134
|
+
{ action: "add_reaction", message: "${message.id}", channel: "${channel.id}", emoji: "${item.reaction}" }
|
|
135
|
+
]
|
|
136
|
+
}
|
|
137
|
+
},
|
|
138
|
+
// Delete trigger message if configured
|
|
139
|
+
{
|
|
140
|
+
action: "flow_if",
|
|
141
|
+
condition: "${item.delete_trigger}",
|
|
142
|
+
then: [
|
|
143
|
+
{ action: "delete_message", channel: "${channel.id}", message: "${message.id}" }
|
|
144
|
+
]
|
|
145
|
+
},
|
|
146
|
+
// Update cooldown
|
|
147
|
+
{
|
|
148
|
+
action: "flow_if",
|
|
149
|
+
condition: "${item.cooldown > 0}",
|
|
150
|
+
then: [
|
|
151
|
+
{
|
|
152
|
+
action: "db_update",
|
|
153
|
+
table: "auto_response_cooldowns",
|
|
154
|
+
where: { response_id: "${item.id}", guild_id: "${guild.id}" },
|
|
155
|
+
data: { last_triggered: "${now()}" },
|
|
156
|
+
upsert: true
|
|
157
|
+
}
|
|
158
|
+
]
|
|
159
|
+
}
|
|
160
|
+
]
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
]
|
|
164
|
+
}
|
|
165
|
+
];
|
|
166
|
+
var autoResponderCommands = [
|
|
167
|
+
{
|
|
168
|
+
name: "autoresponder",
|
|
169
|
+
description: "Auto-responder management",
|
|
170
|
+
subcommands: [
|
|
171
|
+
{
|
|
172
|
+
name: "add",
|
|
173
|
+
description: "Add an auto-response",
|
|
174
|
+
options: [
|
|
175
|
+
{ name: "trigger", description: "Trigger text", type: "string", required: true },
|
|
176
|
+
{ name: "response", description: "Response text", type: "string", required: true },
|
|
177
|
+
{ name: "type", description: "Match type", type: "string", required: false, choices: [
|
|
178
|
+
{ name: "Contains", value: "contains" },
|
|
179
|
+
{ name: "Exact match", value: "exact" },
|
|
180
|
+
{ name: "Starts with", value: "startswith" },
|
|
181
|
+
{ name: "Ends with", value: "endswith" },
|
|
182
|
+
{ name: "Regex", value: "regex" }
|
|
183
|
+
] },
|
|
184
|
+
{ name: "chance", description: "Response chance (1-100)", type: "integer", required: false }
|
|
185
|
+
],
|
|
186
|
+
actions: [
|
|
187
|
+
// Check max triggers
|
|
188
|
+
{
|
|
189
|
+
action: "db_query",
|
|
190
|
+
table: "auto_responses",
|
|
191
|
+
where: { guild_id: "${guild.id}" },
|
|
192
|
+
as: "existing"
|
|
193
|
+
},
|
|
194
|
+
{
|
|
195
|
+
action: "flow_if",
|
|
196
|
+
condition: "${existing.length >= (config.autoResponder?.maxTriggers || 50)}",
|
|
197
|
+
then: [
|
|
198
|
+
{ action: "reply", content: "Maximum triggers reached!", ephemeral: true },
|
|
199
|
+
{ action: "abort" }
|
|
200
|
+
]
|
|
201
|
+
},
|
|
202
|
+
{
|
|
203
|
+
action: "db_insert",
|
|
204
|
+
table: "auto_responses",
|
|
205
|
+
data: {
|
|
206
|
+
guild_id: "${guild.id}",
|
|
207
|
+
trigger: "${args.trigger}",
|
|
208
|
+
trigger_type: '${args.type || "contains"}',
|
|
209
|
+
response: "${args.response}",
|
|
210
|
+
chance: "${args.chance || 100}",
|
|
211
|
+
created_at: "${now()}"
|
|
212
|
+
},
|
|
213
|
+
as: "newTrigger"
|
|
214
|
+
},
|
|
215
|
+
{
|
|
216
|
+
action: "reply",
|
|
217
|
+
content: "Auto-response added! ID: ${newTrigger.id}",
|
|
218
|
+
ephemeral: true
|
|
219
|
+
}
|
|
220
|
+
]
|
|
221
|
+
},
|
|
222
|
+
{
|
|
223
|
+
name: "list",
|
|
224
|
+
description: "List auto-responses",
|
|
225
|
+
actions: [
|
|
226
|
+
{
|
|
227
|
+
action: "db_query",
|
|
228
|
+
table: "auto_responses",
|
|
229
|
+
where: { guild_id: "${guild.id}" },
|
|
230
|
+
as: "triggers"
|
|
231
|
+
},
|
|
232
|
+
{
|
|
233
|
+
action: "flow_if",
|
|
234
|
+
condition: "${triggers.length === 0}",
|
|
235
|
+
then: [
|
|
236
|
+
{ action: "reply", content: "No auto-responses configured!", ephemeral: true },
|
|
237
|
+
{ action: "abort" }
|
|
238
|
+
]
|
|
239
|
+
},
|
|
240
|
+
{
|
|
241
|
+
action: "set",
|
|
242
|
+
key: "triggerList",
|
|
243
|
+
value: '${triggers.map(t => "**" + t.id + ".** `" + truncate(t.trigger, 30) + "` \u2192 `" + truncate(t.response, 30) + "` (" + t.trigger_type + ")").join("\\n")}'
|
|
244
|
+
},
|
|
245
|
+
{
|
|
246
|
+
action: "reply",
|
|
247
|
+
embed: {
|
|
248
|
+
title: "Auto-Responses",
|
|
249
|
+
description: "${triggerList}",
|
|
250
|
+
color: "#5865f2",
|
|
251
|
+
footer: { text: "${triggers.length} trigger(s)" }
|
|
252
|
+
},
|
|
253
|
+
ephemeral: true
|
|
254
|
+
}
|
|
255
|
+
]
|
|
256
|
+
},
|
|
257
|
+
{
|
|
258
|
+
name: "delete",
|
|
259
|
+
description: "Delete an auto-response",
|
|
260
|
+
options: [
|
|
261
|
+
{ name: "id", description: "Trigger ID", type: "integer", required: true }
|
|
262
|
+
],
|
|
263
|
+
actions: [
|
|
264
|
+
{
|
|
265
|
+
action: "db_query",
|
|
266
|
+
table: "auto_responses",
|
|
267
|
+
where: { id: "${args.id}", guild_id: "${guild.id}" },
|
|
268
|
+
as: "trigger"
|
|
269
|
+
},
|
|
270
|
+
{
|
|
271
|
+
action: "flow_if",
|
|
272
|
+
condition: "${trigger.length === 0}",
|
|
273
|
+
then: [
|
|
274
|
+
{ action: "reply", content: "Trigger not found!", ephemeral: true },
|
|
275
|
+
{ action: "abort" }
|
|
276
|
+
]
|
|
277
|
+
},
|
|
278
|
+
{
|
|
279
|
+
action: "db_delete",
|
|
280
|
+
table: "auto_responses",
|
|
281
|
+
where: { id: "${args.id}" }
|
|
282
|
+
},
|
|
283
|
+
{
|
|
284
|
+
action: "db_delete",
|
|
285
|
+
table: "auto_response_cooldowns",
|
|
286
|
+
where: { response_id: "${args.id}" }
|
|
287
|
+
},
|
|
288
|
+
{
|
|
289
|
+
action: "reply",
|
|
290
|
+
content: "Auto-response deleted!",
|
|
291
|
+
ephemeral: true
|
|
292
|
+
}
|
|
293
|
+
]
|
|
294
|
+
},
|
|
295
|
+
{
|
|
296
|
+
name: "edit",
|
|
297
|
+
description: "Edit an auto-response",
|
|
298
|
+
options: [
|
|
299
|
+
{ name: "id", description: "Trigger ID", type: "integer", required: true },
|
|
300
|
+
{ name: "trigger", description: "New trigger", type: "string", required: false },
|
|
301
|
+
{ name: "response", description: "New response", type: "string", required: false },
|
|
302
|
+
{ name: "cooldown", description: "Cooldown in seconds", type: "integer", required: false },
|
|
303
|
+
{ name: "chance", description: "Response chance (1-100)", type: "integer", required: false }
|
|
304
|
+
],
|
|
305
|
+
actions: [
|
|
306
|
+
{
|
|
307
|
+
action: "db_query",
|
|
308
|
+
table: "auto_responses",
|
|
309
|
+
where: { id: "${args.id}", guild_id: "${guild.id}" },
|
|
310
|
+
as: "trigger"
|
|
311
|
+
},
|
|
312
|
+
{
|
|
313
|
+
action: "flow_if",
|
|
314
|
+
condition: "${trigger.length === 0}",
|
|
315
|
+
then: [
|
|
316
|
+
{ action: "reply", content: "Trigger not found!", ephemeral: true },
|
|
317
|
+
{ action: "abort" }
|
|
318
|
+
]
|
|
319
|
+
},
|
|
320
|
+
{
|
|
321
|
+
action: "set",
|
|
322
|
+
key: "updates",
|
|
323
|
+
value: "${Object.fromEntries(Object.entries({ trigger: args.trigger, response: args.response, cooldown: args.cooldown, chance: args.chance }).filter(([_, v]) => v !== undefined))}"
|
|
324
|
+
},
|
|
325
|
+
{
|
|
326
|
+
action: "db_update",
|
|
327
|
+
table: "auto_responses",
|
|
328
|
+
where: { id: "${args.id}" },
|
|
329
|
+
data: "${updates}"
|
|
330
|
+
},
|
|
331
|
+
{
|
|
332
|
+
action: "reply",
|
|
333
|
+
content: "Auto-response updated!",
|
|
334
|
+
ephemeral: true
|
|
335
|
+
}
|
|
336
|
+
]
|
|
337
|
+
}
|
|
338
|
+
]
|
|
339
|
+
}
|
|
340
|
+
];
|
|
341
|
+
function getAutoResponderSpec(config = {}) {
|
|
342
|
+
return {
|
|
343
|
+
commands: autoResponderCommands,
|
|
344
|
+
events: autoResponderEventHandlers,
|
|
345
|
+
state: {
|
|
346
|
+
tables: autoResponderTables
|
|
347
|
+
}
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
export {
|
|
351
|
+
autoResponderCommands,
|
|
352
|
+
autoResponderEventHandlers,
|
|
353
|
+
autoResponderTables,
|
|
354
|
+
getAutoResponderSpec
|
|
355
|
+
};
|
|
356
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +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":[]}
|