@furlow/builtins 1.0.1 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -54,7 +54,7 @@ var remindersEventHandlers = [
54
54
  // Send reminder
55
55
  {
56
56
  action: "flow_if",
57
- condition: "${reminder.dm}",
57
+ condition: "reminder.dm",
58
58
  then: [
59
59
  {
60
60
  action: "send_dm",
@@ -97,7 +97,7 @@ var remindersCommands = [
97
97
  },
98
98
  {
99
99
  action: "flow_if",
100
- condition: "${userReminders.length >= (config.reminders?.maxRemindersPerUser || 25)}",
100
+ condition: "userReminders.length >= (config.reminders?.maxRemindersPerUser || 25)",
101
101
  then: [
102
102
  { action: "reply", content: "You have too many reminders! Delete some first.", ephemeral: true },
103
103
  { action: "abort" }
@@ -149,7 +149,7 @@ var remindersCommands = [
149
149
  },
150
150
  {
151
151
  action: "flow_if",
152
- condition: "${reminders.length === 0}",
152
+ condition: "reminders.length === 0",
153
153
  then: [
154
154
  { action: "reply", content: "You have no reminders!", ephemeral: true },
155
155
  { action: "abort" }
@@ -187,7 +187,7 @@ var remindersCommands = [
187
187
  },
188
188
  {
189
189
  action: "flow_if",
190
- condition: "${reminder.length === 0}",
190
+ condition: "reminder.length === 0",
191
191
  then: [
192
192
  { action: "reply", content: "Reminder not found or not yours!", ephemeral: true },
193
193
  { action: "abort" }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/reminders/index.ts"],"sourcesContent":["/**\n * Reminders builtin module\n * Handles scheduled reminders with DM delivery\n */\n\nimport type { FurlowSpec, CommandDefinition, EventHandler, TableDefinition } from '@furlow/schema';\n\nexport interface RemindersConfig {\n /** Maximum reminders per user */\n maxRemindersPerUser?: number;\n /** Minimum reminder duration */\n minDuration?: string;\n /** Maximum reminder duration */\n maxDuration?: string;\n /** Allow DM reminders */\n allowDM?: boolean;\n}\n\nexport const remindersTables: Record<string, TableDefinition> = {\n reminders: {\n columns: {\n id: { type: 'number', primary: true },\n guild_id: { type: 'string', index: true },\n channel_id: { type: 'string' },\n user_id: { type: 'string', index: true },\n message: { type: 'string' },\n remind_at: { type: 'timestamp', index: true },\n dm: { type: 'boolean', default: false },\n created_at: { type: 'timestamp' },\n },\n },\n};\n\nexport const remindersEventHandlers: EventHandler[] = [\n // Check reminders on scheduler tick\n {\n event: 'scheduler_tick',\n actions: [\n {\n action: 'db_query',\n table: 'reminders',\n where: {},\n as: 'allReminders',\n },\n {\n action: 'set',\n key: 'dueReminders',\n value: '${allReminders.filter(r => new Date(r.remind_at) <= now())}',\n },\n {\n action: 'batch',\n items: '${dueReminders}',\n each: { action: 'emit', event: 'reminder_due', data: { reminder: '${item}' } },\n },\n ],\n },\n // Handle due reminder\n {\n event: 'reminder_due',\n actions: [\n {\n action: 'set',\n key: 'reminder',\n value: '${event.data.reminder}',\n },\n // Delete the reminder\n {\n action: 'db_delete',\n table: 'reminders',\n where: { id: '${reminder.id}' },\n },\n // Send reminder\n {\n action: 'flow_if',\n condition: '${reminder.dm}',\n then: [\n {\n action: 'send_dm',\n user: '${reminder.user_id}',\n embed: {\n title: 'Reminder',\n description: '${reminder.message}',\n color: '#5865f2',\n footer: { text: 'Set ${timestamp(reminder.created_at, \"R\")}' },\n },\n },\n ],\n else: [\n {\n action: 'send_message',\n channel: '${reminder.channel_id}',\n content: '<@${reminder.user_id}> Reminder: ${reminder.message}',\n },\n ],\n },\n ],\n },\n];\n\nexport const remindersCommands: CommandDefinition[] = [\n {\n name: 'remind',\n description: 'Set a reminder',\n options: [\n { name: 'time', description: 'When to remind (e.g., 10m, 2h, 1d)', type: 'string', required: true },\n { name: 'message', description: 'Reminder message', type: 'string', required: true },\n { name: 'dm', description: 'Send reminder via DM', type: 'boolean', required: false },\n ],\n actions: [\n // Check max reminders\n {\n action: 'db_query',\n table: 'reminders',\n where: { user_id: '${user.id}' },\n as: 'userReminders',\n },\n {\n action: 'flow_if',\n condition: '${userReminders.length >= (config.reminders?.maxRemindersPerUser || 25)}',\n then: [\n { action: 'reply', content: 'You have too many reminders! Delete some first.', ephemeral: true },\n { action: 'abort' },\n ],\n },\n // Calculate remind time\n {\n action: 'set',\n key: 'remindAt',\n value: '${addDuration(now(), args.time)}',\n },\n // Create reminder\n {\n action: 'db_insert',\n table: 'reminders',\n data: {\n guild_id: '${guild.id}',\n channel_id: '${channel.id}',\n user_id: '${user.id}',\n message: '${args.message}',\n remind_at: '${remindAt}',\n dm: '${args.dm || false}',\n created_at: '${now()}',\n },\n as: 'reminder',\n },\n {\n action: 'reply',\n embed: {\n title: 'Reminder Set',\n description: 'I\\'ll remind you ${timestamp(remindAt, \"R\")}: ${args.message}',\n color: '#57f287',\n footer: { text: 'ID: ${reminder.id}' },\n },\n ephemeral: true,\n },\n ],\n },\n {\n name: 'reminders',\n description: 'View your reminders',\n actions: [\n {\n action: 'db_query',\n table: 'reminders',\n where: { user_id: '${user.id}' },\n order_by: 'remind_at ASC',\n as: 'reminders',\n },\n {\n action: 'flow_if',\n condition: '${reminders.length === 0}',\n then: [\n { action: 'reply', content: 'You have no reminders!', ephemeral: true },\n { action: 'abort' },\n ],\n },\n {\n action: 'set',\n key: 'reminderList',\n value: '${reminders.map((r, i) => \"**\" + (i + 1) + \".** \" + truncate(r.message, 50) + \" - \" + timestamp(r.remind_at, \"R\") + \" (ID: \" + r.id + \")\").join(\"\\\\n\")}',\n },\n {\n action: 'reply',\n embed: {\n title: 'Your Reminders',\n description: '${reminderList}',\n color: '#5865f2',\n footer: { text: '${reminders.length} reminder(s)' },\n },\n ephemeral: true,\n },\n ],\n },\n {\n name: 'delreminder',\n description: 'Delete a reminder',\n options: [\n { name: 'id', description: 'Reminder ID', type: 'integer', required: true },\n ],\n actions: [\n {\n action: 'db_query',\n table: 'reminders',\n where: { id: '${args.id}', user_id: '${user.id}' },\n as: 'reminder',\n },\n {\n action: 'flow_if',\n condition: '${reminder.length === 0}',\n then: [\n { action: 'reply', content: 'Reminder not found or not yours!', ephemeral: true },\n { action: 'abort' },\n ],\n },\n {\n action: 'db_delete',\n table: 'reminders',\n where: { id: '${args.id}' },\n },\n {\n action: 'reply',\n content: 'Reminder deleted!',\n ephemeral: true,\n },\n ],\n },\n];\n\nexport function getRemindersSpec(config: RemindersConfig = {}): Partial<FurlowSpec> {\n return {\n commands: remindersCommands,\n events: remindersEventHandlers,\n state: {\n tables: remindersTables,\n },\n };\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/reminders/index.ts"],"sourcesContent":["/**\n * Reminders builtin module\n * Handles scheduled reminders with DM delivery\n */\n\nimport type { FurlowSpec, CommandDefinition, EventHandler, TableDefinition } from '@furlow/schema';\n\nexport interface RemindersConfig {\n /** Maximum reminders per user */\n maxRemindersPerUser?: number;\n /** Minimum reminder duration */\n minDuration?: string;\n /** Maximum reminder duration */\n maxDuration?: string;\n /** Allow DM reminders */\n allowDM?: boolean;\n}\n\nexport const remindersTables: Record<string, TableDefinition> = {\n reminders: {\n columns: {\n id: { type: 'number', primary: true },\n guild_id: { type: 'string', index: true },\n channel_id: { type: 'string' },\n user_id: { type: 'string', index: true },\n message: { type: 'string' },\n remind_at: { type: 'timestamp', index: true },\n dm: { type: 'boolean', default: false },\n created_at: { type: 'timestamp' },\n },\n },\n};\n\nexport const remindersEventHandlers: EventHandler[] = [\n // Check reminders on scheduler tick\n {\n event: 'scheduler_tick',\n actions: [\n {\n action: 'db_query',\n table: 'reminders',\n where: {},\n as: 'allReminders',\n },\n {\n action: 'set',\n key: 'dueReminders',\n value: '${allReminders.filter(r => new Date(r.remind_at) <= now())}',\n },\n {\n action: 'batch',\n items: '${dueReminders}',\n each: { action: 'emit', event: 'reminder_due', data: { reminder: '${item}' } },\n },\n ],\n },\n // Handle due reminder\n {\n event: 'reminder_due',\n actions: [\n {\n action: 'set',\n key: 'reminder',\n value: '${event.data.reminder}',\n },\n // Delete the reminder\n {\n action: 'db_delete',\n table: 'reminders',\n where: { id: '${reminder.id}' },\n },\n // Send reminder\n {\n action: 'flow_if',\n condition: 'reminder.dm',\n then: [\n {\n action: 'send_dm',\n user: '${reminder.user_id}',\n embed: {\n title: 'Reminder',\n description: '${reminder.message}',\n color: '#5865f2',\n footer: { text: 'Set ${timestamp(reminder.created_at, \"R\")}' },\n },\n },\n ],\n else: [\n {\n action: 'send_message',\n channel: '${reminder.channel_id}',\n content: '<@${reminder.user_id}> Reminder: ${reminder.message}',\n },\n ],\n },\n ],\n },\n];\n\nexport const remindersCommands: CommandDefinition[] = [\n {\n name: 'remind',\n description: 'Set a reminder',\n options: [\n { name: 'time', description: 'When to remind (e.g., 10m, 2h, 1d)', type: 'string', required: true },\n { name: 'message', description: 'Reminder message', type: 'string', required: true },\n { name: 'dm', description: 'Send reminder via DM', type: 'boolean', required: false },\n ],\n actions: [\n // Check max reminders\n {\n action: 'db_query',\n table: 'reminders',\n where: { user_id: '${user.id}' },\n as: 'userReminders',\n },\n {\n action: 'flow_if',\n condition: 'userReminders.length >= (config.reminders?.maxRemindersPerUser || 25)',\n then: [\n { action: 'reply', content: 'You have too many reminders! Delete some first.', ephemeral: true },\n { action: 'abort' },\n ],\n },\n // Calculate remind time\n {\n action: 'set',\n key: 'remindAt',\n value: '${addDuration(now(), args.time)}',\n },\n // Create reminder\n {\n action: 'db_insert',\n table: 'reminders',\n data: {\n guild_id: '${guild.id}',\n channel_id: '${channel.id}',\n user_id: '${user.id}',\n message: '${args.message}',\n remind_at: '${remindAt}',\n dm: '${args.dm || false}',\n created_at: '${now()}',\n },\n as: 'reminder',\n },\n {\n action: 'reply',\n embed: {\n title: 'Reminder Set',\n description: 'I\\'ll remind you ${timestamp(remindAt, \"R\")}: ${args.message}',\n color: '#57f287',\n footer: { text: 'ID: ${reminder.id}' },\n },\n ephemeral: true,\n },\n ],\n },\n {\n name: 'reminders',\n description: 'View your reminders',\n actions: [\n {\n action: 'db_query',\n table: 'reminders',\n where: { user_id: '${user.id}' },\n order_by: 'remind_at ASC',\n as: 'reminders',\n },\n {\n action: 'flow_if',\n condition: 'reminders.length === 0',\n then: [\n { action: 'reply', content: 'You have no reminders!', ephemeral: true },\n { action: 'abort' },\n ],\n },\n {\n action: 'set',\n key: 'reminderList',\n value: '${reminders.map((r, i) => \"**\" + (i + 1) + \".** \" + truncate(r.message, 50) + \" - \" + timestamp(r.remind_at, \"R\") + \" (ID: \" + r.id + \")\").join(\"\\\\n\")}',\n },\n {\n action: 'reply',\n embed: {\n title: 'Your Reminders',\n description: '${reminderList}',\n color: '#5865f2',\n footer: { text: '${reminders.length} reminder(s)' },\n },\n ephemeral: true,\n },\n ],\n },\n {\n name: 'delreminder',\n description: 'Delete a reminder',\n options: [\n { name: 'id', description: 'Reminder ID', type: 'integer', required: true },\n ],\n actions: [\n {\n action: 'db_query',\n table: 'reminders',\n where: { id: '${args.id}', user_id: '${user.id}' },\n as: 'reminder',\n },\n {\n action: 'flow_if',\n condition: 'reminder.length === 0',\n then: [\n { action: 'reply', content: 'Reminder not found or not yours!', ephemeral: true },\n { action: 'abort' },\n ],\n },\n {\n action: 'db_delete',\n table: 'reminders',\n where: { id: '${args.id}' },\n },\n {\n action: 'reply',\n content: 'Reminder deleted!',\n ephemeral: true,\n },\n ],\n },\n];\n\nexport function getRemindersSpec(config: RemindersConfig = {}): Partial<FurlowSpec> {\n return {\n commands: remindersCommands,\n events: remindersEventHandlers,\n state: {\n tables: remindersTables,\n },\n };\n}\n"],"mappings":"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","names":[]}
@@ -25,30 +25,30 @@ var starboardEventHandlers = [
25
25
  // Handle star reactions
26
26
  {
27
27
  event: "reaction_add",
28
- condition: '${(reaction.emoji.name === (config.starboard?.emoji || "\u2B50") || reaction.emoji.name === "\u{1F31F}") && config.starboard?.channel}',
28
+ condition: '(reaction.emoji.name === (config.starboard?.emoji || "\u2B50") || reaction.emoji.name === "\u{1F31F}") && config.starboard?.channel',
29
29
  actions: [
30
30
  // Check if channel is ignored
31
31
  {
32
32
  action: "flow_if",
33
- condition: "${config.starboard.ignoredChannels?.includes(channel.id)}",
33
+ condition: "config.starboard.ignoredChannels?.includes(channel.id)",
34
34
  then: [{ action: "abort" }]
35
35
  },
36
36
  // Check NSFW
37
37
  {
38
38
  action: "flow_if",
39
- condition: "${channel.nsfw && !config.starboard.nsfwAllowed}",
39
+ condition: "channel.nsfw && !config.starboard.nsfwAllowed",
40
40
  then: [{ action: "abort" }]
41
41
  },
42
42
  // Check self-star
43
43
  {
44
44
  action: "flow_if",
45
- condition: "${!config.starboard.selfStar && user.id === message.author.id}",
45
+ condition: "!config.starboard.selfStar && user.id === message.author.id",
46
46
  then: [{ action: "abort" }]
47
47
  },
48
48
  // Check bot messages
49
49
  {
50
50
  action: "flow_if",
51
- condition: "${!config.starboard.botMessages && message.author.bot}",
51
+ condition: "!config.starboard.botMessages && message.author.bot",
52
52
  then: [{ action: "abort" }]
53
53
  },
54
54
  // Check if already starred by this user
@@ -60,7 +60,7 @@ var starboardEventHandlers = [
60
60
  },
61
61
  {
62
62
  action: "flow_if",
63
- condition: "${existingStar.length > 0}",
63
+ condition: "existingStar.length > 0",
64
64
  then: [{ action: "abort" }]
65
65
  },
66
66
  // Add star
@@ -116,7 +116,7 @@ var starboardEventHandlers = [
116
116
  },
117
117
  {
118
118
  action: "flow_if",
119
- condition: "${existing.length > 0}",
119
+ condition: "existing.length > 0",
120
120
  then: [
121
121
  // Update existing starboard message
122
122
  {
@@ -136,7 +136,7 @@ var starboardEventHandlers = [
136
136
  // Create new starboard entry if threshold met
137
137
  {
138
138
  action: "flow_if",
139
- condition: "${starCount >= threshold}",
139
+ condition: "starCount >= threshold",
140
140
  then: [
141
141
  // Build embed
142
142
  {
@@ -151,12 +151,12 @@ var starboardEventHandlers = [
151
151
  embed: {
152
152
  author: {
153
153
  name: "${message.author.tag}",
154
- icon_url: "${message.author.avatarURL}"
154
+ icon_url: "${message.author.avatar}"
155
155
  },
156
156
  description: "${message.content}\n\n[Jump to message](${message.url})",
157
157
  color: "${embedColor}",
158
158
  image: "${imageUrl ? { url: imageUrl } : null}",
159
- timestamp: "${message.createdAt}",
159
+ timestamp: "${message.created_at}",
160
160
  footer: {
161
161
  text: "ID: ${message.id}"
162
162
  }
@@ -185,7 +185,7 @@ var starboardEventHandlers = [
185
185
  // Handle star removal
186
186
  {
187
187
  event: "reaction_remove",
188
- condition: '${(reaction.emoji.name === (config.starboard?.emoji || "\u2B50") || reaction.emoji.name === "\u{1F31F}") && config.starboard?.channel}',
188
+ condition: '(reaction.emoji.name === (config.starboard?.emoji || "\u2B50") || reaction.emoji.name === "\u{1F31F}") && config.starboard?.channel',
189
189
  actions: [
190
190
  // Remove star record
191
191
  {
@@ -214,11 +214,11 @@ var starboardEventHandlers = [
214
214
  },
215
215
  {
216
216
  action: "flow_if",
217
- condition: "${existing.length > 0}",
217
+ condition: "existing.length > 0",
218
218
  then: [
219
219
  {
220
220
  action: "flow_if",
221
- condition: "${starCount < (config.starboard.threshold || 3)}",
221
+ condition: "starCount < (config.starboard.threshold || 3)",
222
222
  then: [
223
223
  // Remove from starboard
224
224
  {
@@ -285,7 +285,7 @@ var starboardCommands = [
285
285
  },
286
286
  {
287
287
  action: "flow_if",
288
- condition: "${args.threshold}",
288
+ condition: "args.threshold",
289
289
  then: [
290
290
  {
291
291
  action: "set",
@@ -297,7 +297,7 @@ var starboardCommands = [
297
297
  },
298
298
  {
299
299
  action: "flow_if",
300
- condition: "${args.emoji}",
300
+ condition: "args.emoji",
301
301
  then: [
302
302
  {
303
303
  action: "set",
@@ -363,7 +363,7 @@ var starboardCommands = [
363
363
  },
364
364
  {
365
365
  action: "flow_if",
366
- condition: "${allMessages.length === 0}",
366
+ condition: "allMessages.length === 0",
367
367
  then: [
368
368
  { action: "reply", content: "No starred messages yet!", ephemeral: true },
369
369
  { action: "abort" }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/starboard/index.ts"],"sourcesContent":["/**\n * Starboard builtin module\n * Handles star reactions and hall of fame\n */\n\nimport type { FurlowSpec, CommandDefinition, EventHandler, TableDefinition } from '@furlow/schema';\n\nexport interface StarboardConfig {\n /** Starboard channel */\n channel?: string;\n /** Minimum stars required */\n threshold?: number;\n /** Emoji to use (default: star) */\n emoji?: string;\n /** Self-starring allowed */\n selfStar?: boolean;\n /** Bot messages can be starred */\n botMessages?: boolean;\n /** Ignored channels */\n ignoredChannels?: string[];\n /** NSFW channel handling */\n nsfwAllowed?: boolean;\n /** Star tiers with different thresholds */\n tiers?: Array<{\n threshold: number;\n emoji: string;\n color?: string;\n }>;\n}\n\nexport const starboardTables: Record<string, TableDefinition> = {\n starboard_messages: {\n columns: {\n id: { type: 'number', primary: true },\n guild_id: { type: 'string', index: true },\n source_channel_id: { type: 'string' },\n source_message_id: { type: 'string', unique: true },\n starboard_message_id: { type: 'string' },\n author_id: { type: 'string', index: true },\n star_count: { type: 'number', default: 0 },\n created_at: { type: 'timestamp' },\n },\n },\n starboard_stars: {\n columns: {\n id: { type: 'number', primary: true },\n message_id: { type: 'string', index: true },\n user_id: { type: 'string' },\n created_at: { type: 'timestamp' },\n },\n },\n};\n\nexport const starboardEventHandlers: EventHandler[] = [\n // Handle star reactions\n {\n event: 'reaction_add',\n condition: '${(reaction.emoji.name === (config.starboard?.emoji || \"⭐\") || reaction.emoji.name === \"🌟\") && config.starboard?.channel}',\n actions: [\n // Check if channel is ignored\n {\n action: 'flow_if',\n condition: '${config.starboard.ignoredChannels?.includes(channel.id)}',\n then: [{ action: 'abort' }],\n },\n // Check NSFW\n {\n action: 'flow_if',\n condition: '${channel.nsfw && !config.starboard.nsfwAllowed}',\n then: [{ action: 'abort' }],\n },\n // Check self-star\n {\n action: 'flow_if',\n condition: '${!config.starboard.selfStar && user.id === message.author.id}',\n then: [{ action: 'abort' }],\n },\n // Check bot messages\n {\n action: 'flow_if',\n condition: '${!config.starboard.botMessages && message.author.bot}',\n then: [{ action: 'abort' }],\n },\n // Check if already starred by this user\n {\n action: 'db_query',\n table: 'starboard_stars',\n where: { message_id: '${message.id}', user_id: '${user.id}' },\n as: 'existingStar',\n },\n {\n action: 'flow_if',\n condition: '${existingStar.length > 0}',\n then: [{ action: 'abort' }],\n },\n // Add star\n {\n action: 'db_insert',\n table: 'starboard_stars',\n data: {\n message_id: '${message.id}',\n user_id: '${user.id}',\n created_at: '${now()}',\n },\n },\n // Count stars\n {\n action: 'db_query',\n table: 'starboard_stars',\n where: { message_id: '${message.id}' },\n as: 'allStars',\n },\n {\n action: 'set',\n key: 'starCount',\n value: '${allStars.length}',\n },\n // Get threshold\n {\n action: 'set',\n key: 'threshold',\n value: '${config.starboard.threshold || 3}',\n },\n // Get appropriate tier\n {\n action: 'set',\n key: 'tier',\n value: '${config.starboard.tiers ? config.starboard.tiers.filter(t => starCount >= t.threshold).pop() : null}',\n },\n {\n action: 'set',\n key: 'displayEmoji',\n value: '${tier?.emoji || config.starboard.emoji || \"⭐\"}',\n },\n {\n action: 'set',\n key: 'embedColor',\n value: '${tier?.color || \"#ffd700\"}',\n },\n // Check if already on starboard\n {\n action: 'db_query',\n table: 'starboard_messages',\n where: { source_message_id: '${message.id}' },\n as: 'existing',\n },\n {\n action: 'flow_if',\n condition: '${existing.length > 0}',\n then: [\n // Update existing starboard message\n {\n action: 'db_update',\n table: 'starboard_messages',\n where: { source_message_id: '${message.id}' },\n data: { star_count: '${starCount}' },\n },\n {\n action: 'edit_message',\n channel: '${config.starboard.channel}',\n message: '${existing[0].starboard_message_id}',\n content: '${displayEmoji} **${starCount}** | <#${channel.id}>',\n },\n ],\n else: [\n // Create new starboard entry if threshold met\n {\n action: 'flow_if',\n condition: '${starCount >= threshold}',\n then: [\n // Build embed\n {\n action: 'set',\n key: 'imageUrl',\n value: '${message.attachments.first()?.url || message.embeds[0]?.image?.url || message.embeds[0]?.thumbnail?.url}',\n },\n {\n action: 'send_message',\n channel: '${config.starboard.channel}',\n content: '${displayEmoji} **${starCount}** | <#${channel.id}>',\n embed: {\n author: {\n name: '${message.author.tag}',\n icon_url: '${message.author.avatarURL}',\n },\n description: '${message.content}\\n\\n[Jump to message](${message.url})',\n color: '${embedColor}',\n image: '${imageUrl ? { url: imageUrl } : null}',\n timestamp: '${message.createdAt}',\n footer: {\n text: 'ID: ${message.id}',\n },\n },\n as: 'starboardMessage',\n },\n {\n action: 'db_insert',\n table: 'starboard_messages',\n data: {\n guild_id: '${guild.id}',\n source_channel_id: '${channel.id}',\n source_message_id: '${message.id}',\n starboard_message_id: '${starboardMessage.id}',\n author_id: '${message.author.id}',\n star_count: '${starCount}',\n created_at: '${now()}',\n },\n },\n ],\n },\n ],\n },\n ],\n },\n // Handle star removal\n {\n event: 'reaction_remove',\n condition: '${(reaction.emoji.name === (config.starboard?.emoji || \"⭐\") || reaction.emoji.name === \"🌟\") && config.starboard?.channel}',\n actions: [\n // Remove star record\n {\n action: 'db_delete',\n table: 'starboard_stars',\n where: { message_id: '${message.id}', user_id: '${user.id}' },\n },\n // Count remaining stars\n {\n action: 'db_query',\n table: 'starboard_stars',\n where: { message_id: '${message.id}' },\n as: 'allStars',\n },\n {\n action: 'set',\n key: 'starCount',\n value: '${allStars.length}',\n },\n // Check if on starboard\n {\n action: 'db_query',\n table: 'starboard_messages',\n where: { source_message_id: '${message.id}' },\n as: 'existing',\n },\n {\n action: 'flow_if',\n condition: '${existing.length > 0}',\n then: [\n {\n action: 'flow_if',\n condition: '${starCount < (config.starboard.threshold || 3)}',\n then: [\n // Remove from starboard\n {\n action: 'delete_message',\n channel: '${config.starboard.channel}',\n message: '${existing[0].starboard_message_id}',\n },\n {\n action: 'db_delete',\n table: 'starboard_messages',\n where: { source_message_id: '${message.id}' },\n },\n ],\n else: [\n // Update count\n {\n action: 'set',\n key: 'tier',\n value: '${config.starboard.tiers ? config.starboard.tiers.filter(t => starCount >= t.threshold).pop() : null}',\n },\n {\n action: 'set',\n key: 'displayEmoji',\n value: '${tier?.emoji || config.starboard.emoji || \"⭐\"}',\n },\n {\n action: 'db_update',\n table: 'starboard_messages',\n where: { source_message_id: '${message.id}' },\n data: { star_count: '${starCount}' },\n },\n {\n action: 'edit_message',\n channel: '${config.starboard.channel}',\n message: '${existing[0].starboard_message_id}',\n content: '${displayEmoji} **${starCount}** | <#${channel.id}>',\n },\n ],\n },\n ],\n },\n ],\n },\n];\n\nexport const starboardCommands: CommandDefinition[] = [\n {\n name: 'starboard',\n description: 'Starboard commands',\n subcommands: [\n {\n name: 'setup',\n description: 'Set up the starboard',\n options: [\n { name: 'channel', description: 'Starboard channel', type: 'channel', required: true },\n { name: 'threshold', description: 'Minimum stars required', type: 'integer', required: false },\n { name: 'emoji', description: 'Star emoji', type: 'string', required: false },\n ],\n actions: [\n {\n action: 'set',\n key: 'config.starboard.channel',\n value: '${args.channel.id}',\n scope: 'guild',\n },\n {\n action: 'flow_if',\n condition: '${args.threshold}',\n then: [\n {\n action: 'set',\n key: 'config.starboard.threshold',\n value: '${args.threshold}',\n scope: 'guild',\n },\n ],\n },\n {\n action: 'flow_if',\n condition: '${args.emoji}',\n then: [\n {\n action: 'set',\n key: 'config.starboard.emoji',\n value: '${args.emoji}',\n scope: 'guild',\n },\n ],\n },\n {\n action: 'reply',\n content: 'Starboard set up in ${args.channel}!',\n ephemeral: true,\n },\n ],\n },\n {\n name: 'stats',\n description: 'View starboard statistics',\n actions: [\n {\n action: 'db_query',\n table: 'starboard_messages',\n where: { guild_id: '${guild.id}' },\n order_by: 'star_count DESC',\n limit: 5,\n as: 'topMessages',\n },\n {\n action: 'db_query',\n table: 'starboard_messages',\n where: { guild_id: '${guild.id}' },\n as: 'allMessages',\n },\n {\n action: 'set',\n key: 'totalStars',\n value: '${allMessages.reduce((sum, m) => sum + m.star_count, 0)}',\n },\n {\n action: 'reply',\n embed: {\n title: 'Starboard Statistics',\n color: '#ffd700',\n fields: [\n { name: 'Total Starred Messages', value: '${allMessages.length}', inline: true },\n { name: 'Total Stars', value: '${totalStars}', inline: true },\n { name: 'Top Starred Messages', value: '${topMessages.map((m, i) => (i + 1) + \". \" + m.star_count + \" stars - <@\" + m.author_id + \">\").join(\"\\\\n\") || \"None yet!\"}' },\n ],\n },\n },\n ],\n },\n {\n name: 'random',\n description: 'Get a random starred message',\n actions: [\n {\n action: 'db_query',\n table: 'starboard_messages',\n where: { guild_id: '${guild.id}' },\n as: 'allMessages',\n },\n {\n action: 'flow_if',\n condition: '${allMessages.length === 0}',\n then: [\n { action: 'reply', content: 'No starred messages yet!', ephemeral: true },\n { action: 'abort' },\n ],\n },\n {\n action: 'set',\n key: 'randomMessage',\n value: '${allMessages[floor(random(0, allMessages.length))]}',\n },\n {\n action: 'reply',\n content: '⭐ **${randomMessage.star_count}** - https://discord.com/channels/${guild.id}/${randomMessage.source_channel_id}/${randomMessage.source_message_id}',\n },\n ],\n },\n ],\n },\n];\n\nexport function getStarboardSpec(config: StarboardConfig = {}): Partial<FurlowSpec> {\n return {\n events: starboardEventHandlers,\n commands: starboardCommands,\n state: {\n tables: starboardTables,\n },\n };\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/starboard/index.ts"],"sourcesContent":["/**\n * Starboard builtin module\n * Handles star reactions and hall of fame\n */\n\nimport type { FurlowSpec, CommandDefinition, EventHandler, TableDefinition } from '@furlow/schema';\n\nexport interface StarboardConfig {\n /** Starboard channel */\n channel?: string;\n /** Minimum stars required */\n threshold?: number;\n /** Emoji to use (default: star) */\n emoji?: string;\n /** Self-starring allowed */\n selfStar?: boolean;\n /** Bot messages can be starred */\n botMessages?: boolean;\n /** Ignored channels */\n ignoredChannels?: string[];\n /** NSFW channel handling */\n nsfwAllowed?: boolean;\n /** Star tiers with different thresholds */\n tiers?: Array<{\n threshold: number;\n emoji: string;\n color?: string;\n }>;\n}\n\nexport const starboardTables: Record<string, TableDefinition> = {\n starboard_messages: {\n columns: {\n id: { type: 'number', primary: true },\n guild_id: { type: 'string', index: true },\n source_channel_id: { type: 'string' },\n source_message_id: { type: 'string', unique: true },\n starboard_message_id: { type: 'string' },\n author_id: { type: 'string', index: true },\n star_count: { type: 'number', default: 0 },\n created_at: { type: 'timestamp' },\n },\n },\n starboard_stars: {\n columns: {\n id: { type: 'number', primary: true },\n message_id: { type: 'string', index: true },\n user_id: { type: 'string' },\n created_at: { type: 'timestamp' },\n },\n },\n};\n\nexport const starboardEventHandlers: EventHandler[] = [\n // Handle star reactions\n {\n event: 'reaction_add',\n condition: '(reaction.emoji.name === (config.starboard?.emoji || \"⭐\") || reaction.emoji.name === \"🌟\") && config.starboard?.channel',\n actions: [\n // Check if channel is ignored\n {\n action: 'flow_if',\n condition: 'config.starboard.ignoredChannels?.includes(channel.id)',\n then: [{ action: 'abort' }],\n },\n // Check NSFW\n {\n action: 'flow_if',\n condition: 'channel.nsfw && !config.starboard.nsfwAllowed',\n then: [{ action: 'abort' }],\n },\n // Check self-star\n {\n action: 'flow_if',\n condition: '!config.starboard.selfStar && user.id === message.author.id',\n then: [{ action: 'abort' }],\n },\n // Check bot messages\n {\n action: 'flow_if',\n condition: '!config.starboard.botMessages && message.author.bot',\n then: [{ action: 'abort' }],\n },\n // Check if already starred by this user\n {\n action: 'db_query',\n table: 'starboard_stars',\n where: { message_id: '${message.id}', user_id: '${user.id}' },\n as: 'existingStar',\n },\n {\n action: 'flow_if',\n condition: 'existingStar.length > 0',\n then: [{ action: 'abort' }],\n },\n // Add star\n {\n action: 'db_insert',\n table: 'starboard_stars',\n data: {\n message_id: '${message.id}',\n user_id: '${user.id}',\n created_at: '${now()}',\n },\n },\n // Count stars\n {\n action: 'db_query',\n table: 'starboard_stars',\n where: { message_id: '${message.id}' },\n as: 'allStars',\n },\n {\n action: 'set',\n key: 'starCount',\n value: '${allStars.length}',\n },\n // Get threshold\n {\n action: 'set',\n key: 'threshold',\n value: '${config.starboard.threshold || 3}',\n },\n // Get appropriate tier\n {\n action: 'set',\n key: 'tier',\n value: '${config.starboard.tiers ? config.starboard.tiers.filter(t => starCount >= t.threshold).pop() : null}',\n },\n {\n action: 'set',\n key: 'displayEmoji',\n value: '${tier?.emoji || config.starboard.emoji || \"⭐\"}',\n },\n {\n action: 'set',\n key: 'embedColor',\n value: '${tier?.color || \"#ffd700\"}',\n },\n // Check if already on starboard\n {\n action: 'db_query',\n table: 'starboard_messages',\n where: { source_message_id: '${message.id}' },\n as: 'existing',\n },\n {\n action: 'flow_if',\n condition: 'existing.length > 0',\n then: [\n // Update existing starboard message\n {\n action: 'db_update',\n table: 'starboard_messages',\n where: { source_message_id: '${message.id}' },\n data: { star_count: '${starCount}' },\n },\n {\n action: 'edit_message',\n channel: '${config.starboard.channel}',\n message: '${existing[0].starboard_message_id}',\n content: '${displayEmoji} **${starCount}** | <#${channel.id}>',\n },\n ],\n else: [\n // Create new starboard entry if threshold met\n {\n action: 'flow_if',\n condition: 'starCount >= threshold',\n then: [\n // Build embed\n {\n action: 'set',\n key: 'imageUrl',\n value: '${message.attachments.first()?.url || message.embeds[0]?.image?.url || message.embeds[0]?.thumbnail?.url}',\n },\n {\n action: 'send_message',\n channel: '${config.starboard.channel}',\n content: '${displayEmoji} **${starCount}** | <#${channel.id}>',\n embed: {\n author: {\n name: '${message.author.tag}',\n icon_url: '${message.author.avatar}',\n },\n description: '${message.content}\\n\\n[Jump to message](${message.url})',\n color: '${embedColor}',\n image: '${imageUrl ? { url: imageUrl } : null}',\n timestamp: '${message.created_at}',\n footer: {\n text: 'ID: ${message.id}',\n },\n },\n as: 'starboardMessage',\n },\n {\n action: 'db_insert',\n table: 'starboard_messages',\n data: {\n guild_id: '${guild.id}',\n source_channel_id: '${channel.id}',\n source_message_id: '${message.id}',\n starboard_message_id: '${starboardMessage.id}',\n author_id: '${message.author.id}',\n star_count: '${starCount}',\n created_at: '${now()}',\n },\n },\n ],\n },\n ],\n },\n ],\n },\n // Handle star removal\n {\n event: 'reaction_remove',\n condition: '(reaction.emoji.name === (config.starboard?.emoji || \"⭐\") || reaction.emoji.name === \"🌟\") && config.starboard?.channel',\n actions: [\n // Remove star record\n {\n action: 'db_delete',\n table: 'starboard_stars',\n where: { message_id: '${message.id}', user_id: '${user.id}' },\n },\n // Count remaining stars\n {\n action: 'db_query',\n table: 'starboard_stars',\n where: { message_id: '${message.id}' },\n as: 'allStars',\n },\n {\n action: 'set',\n key: 'starCount',\n value: '${allStars.length}',\n },\n // Check if on starboard\n {\n action: 'db_query',\n table: 'starboard_messages',\n where: { source_message_id: '${message.id}' },\n as: 'existing',\n },\n {\n action: 'flow_if',\n condition: 'existing.length > 0',\n then: [\n {\n action: 'flow_if',\n condition: 'starCount < (config.starboard.threshold || 3)',\n then: [\n // Remove from starboard\n {\n action: 'delete_message',\n channel: '${config.starboard.channel}',\n message: '${existing[0].starboard_message_id}',\n },\n {\n action: 'db_delete',\n table: 'starboard_messages',\n where: { source_message_id: '${message.id}' },\n },\n ],\n else: [\n // Update count\n {\n action: 'set',\n key: 'tier',\n value: '${config.starboard.tiers ? config.starboard.tiers.filter(t => starCount >= t.threshold).pop() : null}',\n },\n {\n action: 'set',\n key: 'displayEmoji',\n value: '${tier?.emoji || config.starboard.emoji || \"⭐\"}',\n },\n {\n action: 'db_update',\n table: 'starboard_messages',\n where: { source_message_id: '${message.id}' },\n data: { star_count: '${starCount}' },\n },\n {\n action: 'edit_message',\n channel: '${config.starboard.channel}',\n message: '${existing[0].starboard_message_id}',\n content: '${displayEmoji} **${starCount}** | <#${channel.id}>',\n },\n ],\n },\n ],\n },\n ],\n },\n];\n\nexport const starboardCommands: CommandDefinition[] = [\n {\n name: 'starboard',\n description: 'Starboard commands',\n subcommands: [\n {\n name: 'setup',\n description: 'Set up the starboard',\n options: [\n { name: 'channel', description: 'Starboard channel', type: 'channel', required: true },\n { name: 'threshold', description: 'Minimum stars required', type: 'integer', required: false },\n { name: 'emoji', description: 'Star emoji', type: 'string', required: false },\n ],\n actions: [\n {\n action: 'set',\n key: 'config.starboard.channel',\n value: '${args.channel.id}',\n scope: 'guild',\n },\n {\n action: 'flow_if',\n condition: 'args.threshold',\n then: [\n {\n action: 'set',\n key: 'config.starboard.threshold',\n value: '${args.threshold}',\n scope: 'guild',\n },\n ],\n },\n {\n action: 'flow_if',\n condition: 'args.emoji',\n then: [\n {\n action: 'set',\n key: 'config.starboard.emoji',\n value: '${args.emoji}',\n scope: 'guild',\n },\n ],\n },\n {\n action: 'reply',\n content: 'Starboard set up in ${args.channel}!',\n ephemeral: true,\n },\n ],\n },\n {\n name: 'stats',\n description: 'View starboard statistics',\n actions: [\n {\n action: 'db_query',\n table: 'starboard_messages',\n where: { guild_id: '${guild.id}' },\n order_by: 'star_count DESC',\n limit: 5,\n as: 'topMessages',\n },\n {\n action: 'db_query',\n table: 'starboard_messages',\n where: { guild_id: '${guild.id}' },\n as: 'allMessages',\n },\n {\n action: 'set',\n key: 'totalStars',\n value: '${allMessages.reduce((sum, m) => sum + m.star_count, 0)}',\n },\n {\n action: 'reply',\n embed: {\n title: 'Starboard Statistics',\n color: '#ffd700',\n fields: [\n { name: 'Total Starred Messages', value: '${allMessages.length}', inline: true },\n { name: 'Total Stars', value: '${totalStars}', inline: true },\n { name: 'Top Starred Messages', value: '${topMessages.map((m, i) => (i + 1) + \". \" + m.star_count + \" stars - <@\" + m.author_id + \">\").join(\"\\\\n\") || \"None yet!\"}' },\n ],\n },\n },\n ],\n },\n {\n name: 'random',\n description: 'Get a random starred message',\n actions: [\n {\n action: 'db_query',\n table: 'starboard_messages',\n where: { guild_id: '${guild.id}' },\n as: 'allMessages',\n },\n {\n action: 'flow_if',\n condition: 'allMessages.length === 0',\n then: [\n { action: 'reply', content: 'No starred messages yet!', ephemeral: true },\n { action: 'abort' },\n ],\n },\n {\n action: 'set',\n key: 'randomMessage',\n value: '${allMessages[floor(random(0, allMessages.length))]}',\n },\n {\n action: 'reply',\n content: '⭐ **${randomMessage.star_count}** - https://discord.com/channels/${guild.id}/${randomMessage.source_channel_id}/${randomMessage.source_message_id}',\n },\n ],\n },\n ],\n },\n];\n\nexport function getStarboardSpec(config: StarboardConfig = {}): Partial<FurlowSpec> {\n return {\n events: starboardEventHandlers,\n commands: starboardCommands,\n state: {\n tables: starboardTables,\n },\n };\n}\n"],"mappings":"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","names":[]}
@@ -71,7 +71,7 @@ var ticketsEventHandlers = [
71
71
  // Handle ticket creation button
72
72
  {
73
73
  event: "button_click",
74
- condition: '${interaction.customId === "ticket_create"}',
74
+ condition: 'interaction.customId === "ticket_create"',
75
75
  actions: [
76
76
  // Check max tickets
77
77
  {
@@ -86,7 +86,7 @@ var ticketsEventHandlers = [
86
86
  },
87
87
  {
88
88
  action: "flow_if",
89
- condition: "${userTickets.length >= (config.tickets.maxTicketsPerUser || 1)}",
89
+ condition: "userTickets.length >= (config.tickets.maxTicketsPerUser || 1)",
90
90
  then: [
91
91
  {
92
92
  action: "reply",
@@ -99,7 +99,7 @@ var ticketsEventHandlers = [
99
99
  // Show category selector if configured
100
100
  {
101
101
  action: "flow_if",
102
- condition: "${config.tickets.categories && config.tickets.categories.length > 0}",
102
+ condition: "config.tickets.categories && config.tickets.categories.length > 0",
103
103
  then: [
104
104
  {
105
105
  action: "reply",
@@ -129,7 +129,7 @@ var ticketsEventHandlers = [
129
129
  // Handle category selection
130
130
  {
131
131
  event: "select_menu",
132
- condition: '${interaction.customId === "ticket_category_select"}',
132
+ condition: 'interaction.customId === "ticket_category_select"',
133
133
  actions: [
134
134
  {
135
135
  action: "emit",
@@ -233,7 +233,7 @@ var ticketsEventHandlers = [
233
233
  // Handle claim button
234
234
  {
235
235
  event: "button_click",
236
- condition: '${interaction.customId === "ticket_claim"}',
236
+ condition: 'interaction.customId === "ticket_claim"',
237
237
  actions: [
238
238
  {
239
239
  action: "db_query",
@@ -243,7 +243,7 @@ var ticketsEventHandlers = [
243
243
  },
244
244
  {
245
245
  action: "flow_if",
246
- condition: "${!ticket[0]}",
246
+ condition: "!ticket[0]",
247
247
  then: [
248
248
  { action: "reply", content: "This is not a ticket channel!", ephemeral: true },
249
249
  { action: "abort" }
@@ -251,7 +251,7 @@ var ticketsEventHandlers = [
251
251
  },
252
252
  {
253
253
  action: "flow_if",
254
- condition: "${ticket[0].claimed_by}",
254
+ condition: "ticket[0].claimed_by",
255
255
  then: [
256
256
  { action: "reply", content: "This ticket is already claimed by <@${ticket[0].claimed_by}>!", ephemeral: true },
257
257
  { action: "abort" }
@@ -277,7 +277,7 @@ var ticketsEventHandlers = [
277
277
  // Handle close button
278
278
  {
279
279
  event: "button_click",
280
- condition: '${interaction.customId === "ticket_close"}',
280
+ condition: 'interaction.customId === "ticket_close"',
281
281
  actions: [
282
282
  {
283
283
  action: "db_query",
@@ -287,7 +287,7 @@ var ticketsEventHandlers = [
287
287
  },
288
288
  {
289
289
  action: "flow_if",
290
- condition: "${!ticket[0]}",
290
+ condition: "!ticket[0]",
291
291
  then: [
292
292
  { action: "reply", content: "This is not a ticket channel!", ephemeral: true },
293
293
  { action: "abort" }
@@ -313,7 +313,7 @@ var ticketsEventHandlers = [
313
313
  // Handle close confirmation
314
314
  {
315
315
  event: "button_click",
316
- condition: '${interaction.customId === "ticket_close_confirm"}',
316
+ condition: 'interaction.customId === "ticket_close_confirm"',
317
317
  actions: [
318
318
  {
319
319
  action: "db_query",
@@ -324,7 +324,7 @@ var ticketsEventHandlers = [
324
324
  // Generate transcript if configured
325
325
  {
326
326
  action: "flow_if",
327
- condition: "${config.tickets.includeTranscript && config.tickets.logChannel}",
327
+ condition: "config.tickets.includeTranscript && config.tickets.logChannel",
328
328
  then: [
329
329
  {
330
330
  action: "db_query",
@@ -371,7 +371,7 @@ var ticketsEventHandlers = [
371
371
  // DM user if configured
372
372
  {
373
373
  action: "flow_if",
374
- condition: "${config.tickets.dmOnClose}",
374
+ condition: "config.tickets.dmOnClose",
375
375
  then: [
376
376
  {
377
377
  action: "send_dm",
@@ -397,7 +397,7 @@ var ticketsEventHandlers = [
397
397
  // Handle transcript button
398
398
  {
399
399
  event: "button_click",
400
- condition: '${interaction.customId === "ticket_transcript"}',
400
+ condition: 'interaction.customId === "ticket_transcript"',
401
401
  actions: [
402
402
  {
403
403
  action: "db_query",
@@ -433,7 +433,7 @@ var ticketsEventHandlers = [
433
433
  // Log ticket messages
434
434
  {
435
435
  event: "message",
436
- condition: "${channel.parentId === config.tickets.category}",
436
+ condition: "channel.parentId === config.tickets.category",
437
437
  actions: [
438
438
  {
439
439
  action: "db_query",
@@ -443,7 +443,7 @@ var ticketsEventHandlers = [
443
443
  },
444
444
  {
445
445
  action: "flow_if",
446
- condition: "${ticket[0]}",
446
+ condition: "ticket[0]",
447
447
  then: [
448
448
  {
449
449
  action: "db_insert",
@@ -507,7 +507,7 @@ var ticketsCommands = [
507
507
  },
508
508
  {
509
509
  action: "flow_if",
510
- condition: "${!ticket[0]}",
510
+ condition: "!ticket[0]",
511
511
  then: [
512
512
  { action: "reply", content: "This is not a ticket channel!", ephemeral: true },
513
513
  { action: "abort" }
@@ -542,7 +542,7 @@ var ticketsCommands = [
542
542
  },
543
543
  {
544
544
  action: "flow_if",
545
- condition: "${!ticket[0]}",
545
+ condition: "!ticket[0]",
546
546
  then: [
547
547
  { action: "reply", content: "This is not a ticket channel!", ephemeral: true },
548
548
  { action: "abort" }
@@ -577,7 +577,7 @@ var ticketsCommands = [
577
577
  },
578
578
  {
579
579
  action: "flow_if",
580
- condition: "${!ticket[0]}",
580
+ condition: "!ticket[0]",
581
581
  then: [
582
582
  { action: "reply", content: "This is not a ticket channel!", ephemeral: true },
583
583
  { action: "abort" }