@furlow/builtins 1.0.1 → 1.0.3
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
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/tickets/index.ts"],"sourcesContent":["/**\n * Tickets builtin module\n * Handles ticket creation, claiming, closing, and transcripts\n */\n\nimport type { FurlowSpec, CommandDefinition, EventHandler, TableDefinition, ComponentDefinition } from '@furlow/schema';\n\nexport interface TicketsConfig {\n /** Category to create tickets in */\n category?: string;\n /** Support roles that can see tickets */\n supportRoles?: string[];\n /** Ticket channel naming pattern */\n channelPattern?: string;\n /** Maximum open tickets per user */\n maxTicketsPerUser?: number;\n /** Ticket panel channel */\n panelChannel?: string;\n /** Log channel for ticket transcripts */\n logChannel?: string;\n /** Auto-close inactive tickets (hours) */\n autoCloseAfter?: number;\n /** Ticket categories/types */\n categories?: Array<{\n id: string;\n name: string;\n description?: string;\n emoji?: string;\n supportRoles?: string[];\n }>;\n /** DM user on ticket close */\n dmOnClose?: boolean;\n /** Include transcript on close */\n includeTranscript?: boolean;\n}\n\nexport const ticketsTables: Record<string, TableDefinition> = {\n tickets: {\n columns: {\n id: { type: 'number', primary: true },\n channel_id: { type: 'string', unique: true },\n guild_id: { type: 'string', index: true },\n user_id: { type: 'string', index: true },\n category: { type: 'string' },\n claimed_by: { type: 'string' },\n status: { type: 'string', default: 'open' },\n created_at: { type: 'timestamp' },\n closed_at: { type: 'timestamp' },\n },\n },\n ticket_messages: {\n columns: {\n id: { type: 'number', primary: true },\n ticket_id: { type: 'number', index: true },\n author_id: { type: 'string' },\n author_name: { type: 'string' },\n content: { type: 'string' },\n attachments: { type: 'json' },\n created_at: { type: 'timestamp' },\n },\n },\n};\n\nexport const ticketPanelComponents: ComponentDefinition[] = [\n {\n type: 'action_row',\n components: [\n {\n type: 'button',\n style: 'primary',\n label: 'Create Ticket',\n emoji: '📩',\n custom_id: 'ticket_create',\n },\n ],\n },\n];\n\nexport const ticketControlComponents: ComponentDefinition[] = [\n {\n type: 'action_row',\n components: [\n {\n type: 'button',\n style: 'secondary',\n label: 'Claim',\n emoji: '🙋',\n custom_id: 'ticket_claim',\n },\n {\n type: 'button',\n style: 'danger',\n label: 'Close',\n emoji: '🔒',\n custom_id: 'ticket_close',\n },\n {\n type: 'button',\n style: 'secondary',\n label: 'Transcript',\n emoji: '📜',\n custom_id: 'ticket_transcript',\n },\n ],\n },\n];\n\nexport const ticketsEventHandlers: EventHandler[] = [\n // Handle ticket creation button\n {\n event: 'button_click',\n condition: '${interaction.customId === \"ticket_create\"}',\n actions: [\n // Check max tickets\n {\n action: 'db_query',\n table: 'tickets',\n where: {\n guild_id: '${guild.id}',\n user_id: '${user.id}',\n status: 'open',\n },\n as: 'userTickets',\n },\n {\n action: 'flow_if',\n condition: '${userTickets.length >= (config.tickets.maxTicketsPerUser || 1)}',\n then: [\n {\n action: 'reply',\n content: 'You already have the maximum number of open tickets!',\n ephemeral: true,\n },\n { action: 'abort' },\n ],\n },\n // Show category selector if configured\n {\n action: 'flow_if',\n condition: '${config.tickets.categories && config.tickets.categories.length > 0}',\n then: [\n {\n action: 'reply',\n content: 'Select a ticket category:',\n ephemeral: true,\n components: [\n {\n type: 'action_row',\n components: [\n {\n type: 'select_menu',\n custom_id: 'ticket_category_select',\n placeholder: 'Select category...',\n options: '${config.tickets.categories | map(c => ({ label: c.name, value: c.id, description: c.description, emoji: c.emoji }))}',\n },\n ],\n },\n ],\n },\n ],\n else: [\n { action: 'emit', event: 'ticket_create_confirmed', data: { category: 'general' } },\n ],\n },\n ],\n },\n // Handle category selection\n {\n event: 'select_menu',\n condition: '${interaction.customId === \"ticket_category_select\"}',\n actions: [\n {\n action: 'emit',\n event: 'ticket_create_confirmed',\n data: { category: '${interaction.values[0]}' },\n },\n ],\n },\n // Create the ticket channel\n {\n event: 'ticket_create_confirmed',\n actions: [\n {\n action: 'db_query',\n table: 'tickets',\n where: { guild_id: '${guild.id}' },\n order_by: 'id DESC',\n limit: 1,\n as: 'lastTicket',\n },\n {\n action: 'set',\n key: 'ticketNumber',\n value: '${(lastTicket[0]?.id || 0) + 1}',\n },\n {\n action: 'set',\n key: 'channelName',\n value: '${(config.tickets.channelPattern || \"ticket-{number}\") | replace(\"{number}\", ticketNumber) | replace(\"{user}\", user.username) | replace(\"{category}\", event.data.category)}',\n },\n // Get support roles for this category\n {\n action: 'set',\n key: 'categoryConfig',\n value: '${config.tickets.categories?.find(c => c.id === event.data.category)}',\n },\n {\n action: 'set',\n key: 'supportRoles',\n value: '${categoryConfig?.supportRoles || config.tickets.supportRoles || []}',\n },\n // Create channel with permissions\n {\n action: 'create_channel',\n name: '${channelName}',\n type: 'text',\n parent: '${config.tickets.category}',\n permission_overwrites: [\n {\n id: '${guild.id}',\n type: 'role',\n deny: ['VIEW_CHANNEL'],\n },\n {\n id: '${user.id}',\n type: 'member',\n allow: ['VIEW_CHANNEL', 'SEND_MESSAGES', 'READ_MESSAGE_HISTORY', 'ATTACH_FILES'],\n },\n '${supportRoles | map(r => ({ id: r, type: \"role\", allow: [\"VIEW_CHANNEL\", \"SEND_MESSAGES\", \"READ_MESSAGE_HISTORY\", \"ATTACH_FILES\", \"MANAGE_MESSAGES\"] }))}',\n ],\n as: 'ticketChannel',\n },\n // Store in database\n {\n action: 'db_insert',\n table: 'tickets',\n data: {\n channel_id: '${ticketChannel.id}',\n guild_id: '${guild.id}',\n user_id: '${user.id}',\n category: '${event.data.category}',\n status: 'open',\n created_at: '${now()}',\n },\n },\n // Send opening message\n {\n action: 'send_message',\n channel: '${ticketChannel.id}',\n content: 'Welcome ${user}! Support will be with you shortly.',\n embed: {\n title: 'Ticket #${ticketNumber}',\n description: 'Please describe your issue and a staff member will assist you.',\n color: '#5865f2',\n fields: [\n { name: 'Category', value: '${categoryConfig?.name || \"General\"}', inline: true },\n { name: 'Created by', value: '${user}', inline: true },\n ],\n timestamp: '${now()}',\n },\n components: '${ticketControlComponents}',\n },\n // Reply to original interaction\n {\n action: 'update_message',\n content: 'Your ticket has been created: ${ticketChannel}',\n components: [],\n },\n ],\n },\n // Handle claim button\n {\n event: 'button_click',\n condition: '${interaction.customId === \"ticket_claim\"}',\n actions: [\n {\n action: 'db_query',\n table: 'tickets',\n where: { channel_id: '${channel.id}' },\n as: 'ticket',\n },\n {\n action: 'flow_if',\n condition: '${!ticket[0]}',\n then: [\n { action: 'reply', content: 'This is not a ticket channel!', ephemeral: true },\n { action: 'abort' },\n ],\n },\n {\n action: 'flow_if',\n condition: '${ticket[0].claimed_by}',\n then: [\n { action: 'reply', content: 'This ticket is already claimed by <@${ticket[0].claimed_by}>!', ephemeral: true },\n { action: 'abort' },\n ],\n },\n {\n action: 'db_update',\n table: 'tickets',\n where: { channel_id: '${channel.id}' },\n data: { claimed_by: '${user.id}' },\n },\n {\n action: 'send_message',\n channel: '${channel.id}',\n embed: {\n description: '${user} has claimed this ticket.',\n color: '#57f287',\n },\n },\n { action: 'reply', content: 'You have claimed this ticket!', ephemeral: true },\n ],\n },\n // Handle close button\n {\n event: 'button_click',\n condition: '${interaction.customId === \"ticket_close\"}',\n actions: [\n {\n action: 'db_query',\n table: 'tickets',\n where: { channel_id: '${channel.id}' },\n as: 'ticket',\n },\n {\n action: 'flow_if',\n condition: '${!ticket[0]}',\n then: [\n { action: 'reply', content: 'This is not a ticket channel!', ephemeral: true },\n { action: 'abort' },\n ],\n },\n // Confirm close\n {\n action: 'reply',\n content: 'Are you sure you want to close this ticket?',\n ephemeral: true,\n components: [\n {\n type: 'action_row',\n components: [\n { type: 'button', style: 'danger', label: 'Close Ticket', custom_id: 'ticket_close_confirm' },\n { type: 'button', style: 'secondary', label: 'Cancel', custom_id: 'ticket_close_cancel' },\n ],\n },\n ],\n },\n ],\n },\n // Handle close confirmation\n {\n event: 'button_click',\n condition: '${interaction.customId === \"ticket_close_confirm\"}',\n actions: [\n {\n action: 'db_query',\n table: 'tickets',\n where: { channel_id: '${channel.id}' },\n as: 'ticket',\n },\n // Generate transcript if configured\n {\n action: 'flow_if',\n condition: '${config.tickets.includeTranscript && config.tickets.logChannel}',\n then: [\n {\n action: 'db_query',\n table: 'ticket_messages',\n where: { ticket_id: '${ticket[0].id}' },\n order_by: 'created_at ASC',\n as: 'messages',\n },\n {\n action: 'set',\n key: 'transcriptText',\n value: '${messages | map(m => \"[\" + formatDate(m.created_at, \"YYYY-MM-DD HH:mm:ss\") + \"] \" + m.author_name + \": \" + m.content) | join(\"\\\\n\")}',\n },\n {\n action: 'send_message',\n channel: '${config.tickets.logChannel}',\n embed: {\n title: 'Ticket Closed',\n fields: [\n { name: 'Ticket ID', value: '${ticket[0].id}', inline: true },\n { name: 'Opened by', value: '<@${ticket[0].user_id}>', inline: true },\n { name: 'Closed by', value: '${user}', inline: true },\n { name: 'Category', value: '${ticket[0].category}', inline: true },\n ],\n color: '#ed4245',\n timestamp: '${now()}',\n },\n files: [\n {\n attachment: '${Buffer.from(transcriptText)}',\n name: 'transcript-${ticket[0].id}.txt',\n },\n ],\n },\n ],\n },\n // Update database\n {\n action: 'db_update',\n table: 'tickets',\n where: { channel_id: '${channel.id}' },\n data: { status: 'closed', closed_at: '${now()}' },\n },\n // DM user if configured\n {\n action: 'flow_if',\n condition: '${config.tickets.dmOnClose}',\n then: [\n {\n action: 'send_dm',\n user: '${ticket[0].user_id}',\n embed: {\n title: 'Ticket Closed',\n description: 'Your ticket in ${guild.name} has been closed.',\n color: '#ed4245',\n },\n },\n ],\n },\n // Delete channel after delay\n {\n action: 'send_message',\n channel: '${channel.id}',\n content: 'This ticket will be deleted in 5 seconds...',\n },\n { action: 'wait', duration: 5000 },\n { action: 'delete_channel', channel: '${channel.id}' },\n ],\n },\n // Handle transcript button\n {\n event: 'button_click',\n condition: '${interaction.customId === \"ticket_transcript\"}',\n actions: [\n {\n action: 'db_query',\n table: 'tickets',\n where: { channel_id: '${channel.id}' },\n as: 'ticket',\n },\n {\n action: 'db_query',\n table: 'ticket_messages',\n where: { ticket_id: '${ticket[0].id}' },\n order_by: 'created_at ASC',\n as: 'messages',\n },\n {\n action: 'set',\n key: 'transcriptText',\n value: '${messages | map(m => \"[\" + formatDate(m.created_at, \"YYYY-MM-DD HH:mm:ss\") + \"] \" + m.author_name + \": \" + m.content) | join(\"\\\\n\")}',\n },\n {\n action: 'reply',\n content: 'Here is the transcript:',\n ephemeral: true,\n files: [\n {\n attachment: '${Buffer.from(transcriptText)}',\n name: 'transcript-${ticket[0].id}.txt',\n },\n ],\n },\n ],\n },\n // Log ticket messages\n {\n event: 'message',\n condition: '${channel.parentId === config.tickets.category}',\n actions: [\n {\n action: 'db_query',\n table: 'tickets',\n where: { channel_id: '${channel.id}' },\n as: 'ticket',\n },\n {\n action: 'flow_if',\n condition: '${ticket[0]}',\n then: [\n {\n action: 'db_insert',\n table: 'ticket_messages',\n data: {\n ticket_id: '${ticket[0].id}',\n author_id: '${user.id}',\n author_name: '${user.tag}',\n content: '${message.content}',\n attachments: '${message.attachments | map(a => a.url)}',\n created_at: '${now()}',\n },\n },\n ],\n },\n ],\n },\n];\n\nexport const ticketsCommands: CommandDefinition[] = [\n {\n name: 'ticket',\n description: 'Ticket management commands',\n subcommands: [\n {\n name: 'panel',\n description: 'Create a ticket panel',\n options: [\n { name: 'channel', description: 'Channel to send panel', type: 'channel', required: false },\n { name: 'message', description: 'Custom panel message', type: 'string', required: false },\n ],\n actions: [\n {\n action: 'send_message',\n channel: '${args.channel?.id || channel.id}',\n embed: {\n title: 'Support Tickets',\n description: '${args.message || \"Need help? Click the button below to create a support ticket.\"}',\n color: '#5865f2',\n },\n components: '${ticketPanelComponents}',\n },\n {\n action: 'reply',\n content: 'Ticket panel created!',\n ephemeral: true,\n },\n ],\n },\n {\n name: 'add',\n description: 'Add a user to the ticket',\n options: [\n { name: 'user', description: 'User to add', type: 'user', required: true },\n ],\n actions: [\n {\n action: 'db_query',\n table: 'tickets',\n where: { channel_id: '${channel.id}' },\n as: 'ticket',\n },\n {\n action: 'flow_if',\n condition: '${!ticket[0]}',\n then: [\n { action: 'reply', content: 'This is not a ticket channel!', ephemeral: true },\n { action: 'abort' },\n ],\n },\n {\n action: 'set_channel_permissions',\n channel: '${channel.id}',\n user: '${args.user.id}',\n allow: ['VIEW_CHANNEL', 'SEND_MESSAGES', 'READ_MESSAGE_HISTORY'],\n },\n {\n action: 'send_message',\n channel: '${channel.id}',\n content: '${args.user} has been added to the ticket.',\n },\n { action: 'reply', content: 'User added!', ephemeral: true },\n ],\n },\n {\n name: 'remove',\n description: 'Remove a user from the ticket',\n options: [\n { name: 'user', description: 'User to remove', type: 'user', required: true },\n ],\n actions: [\n {\n action: 'db_query',\n table: 'tickets',\n where: { channel_id: '${channel.id}' },\n as: 'ticket',\n },\n {\n action: 'flow_if',\n condition: '${!ticket[0]}',\n then: [\n { action: 'reply', content: 'This is not a ticket channel!', ephemeral: true },\n { action: 'abort' },\n ],\n },\n {\n action: 'set_channel_permissions',\n channel: '${channel.id}',\n user: '${args.user.id}',\n deny: ['VIEW_CHANNEL'],\n },\n {\n action: 'send_message',\n channel: '${channel.id}',\n content: '${args.user.username} has been removed from the ticket.',\n },\n { action: 'reply', content: 'User removed!', ephemeral: true },\n ],\n },\n {\n name: 'rename',\n description: 'Rename the ticket channel',\n options: [\n { name: 'name', description: 'New channel name', type: 'string', required: true },\n ],\n actions: [\n {\n action: 'db_query',\n table: 'tickets',\n where: { channel_id: '${channel.id}' },\n as: 'ticket',\n },\n {\n action: 'flow_if',\n condition: '${!ticket[0]}',\n then: [\n { action: 'reply', content: 'This is not a ticket channel!', ephemeral: true },\n { action: 'abort' },\n ],\n },\n {\n action: 'edit_channel',\n channel: '${channel.id}',\n name: '${args.name}',\n },\n { action: 'reply', content: 'Ticket renamed!', ephemeral: true },\n ],\n },\n ],\n },\n];\n\nexport function getTicketsSpec(config: TicketsConfig = {}): Partial<FurlowSpec> {\n return {\n events: ticketsEventHandlers,\n commands: ticketsCommands,\n state: {\n tables: ticketsTables,\n },\n };\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/tickets/index.ts"],"sourcesContent":["/**\n * Tickets builtin module\n * Handles ticket creation, claiming, closing, and transcripts\n */\n\nimport type { FurlowSpec, CommandDefinition, EventHandler, TableDefinition, ComponentDefinition } from '@furlow/schema';\n\nexport interface TicketsConfig {\n /** Category to create tickets in */\n category?: string;\n /** Support roles that can see tickets */\n supportRoles?: string[];\n /** Ticket channel naming pattern */\n channelPattern?: string;\n /** Maximum open tickets per user */\n maxTicketsPerUser?: number;\n /** Ticket panel channel */\n panelChannel?: string;\n /** Log channel for ticket transcripts */\n logChannel?: string;\n /** Auto-close inactive tickets (hours) */\n autoCloseAfter?: number;\n /** Ticket categories/types */\n categories?: Array<{\n id: string;\n name: string;\n description?: string;\n emoji?: string;\n supportRoles?: string[];\n }>;\n /** DM user on ticket close */\n dmOnClose?: boolean;\n /** Include transcript on close */\n includeTranscript?: boolean;\n}\n\nexport const ticketsTables: Record<string, TableDefinition> = {\n tickets: {\n columns: {\n id: { type: 'number', primary: true },\n channel_id: { type: 'string', unique: true },\n guild_id: { type: 'string', index: true },\n user_id: { type: 'string', index: true },\n category: { type: 'string' },\n claimed_by: { type: 'string' },\n status: { type: 'string', default: 'open' },\n created_at: { type: 'timestamp' },\n closed_at: { type: 'timestamp' },\n },\n },\n ticket_messages: {\n columns: {\n id: { type: 'number', primary: true },\n ticket_id: { type: 'number', index: true },\n author_id: { type: 'string' },\n author_name: { type: 'string' },\n content: { type: 'string' },\n attachments: { type: 'json' },\n created_at: { type: 'timestamp' },\n },\n },\n};\n\nexport const ticketPanelComponents: ComponentDefinition[] = [\n {\n type: 'action_row',\n components: [\n {\n type: 'button',\n style: 'primary',\n label: 'Create Ticket',\n emoji: '📩',\n custom_id: 'ticket_create',\n },\n ],\n },\n];\n\nexport const ticketControlComponents: ComponentDefinition[] = [\n {\n type: 'action_row',\n components: [\n {\n type: 'button',\n style: 'secondary',\n label: 'Claim',\n emoji: '🙋',\n custom_id: 'ticket_claim',\n },\n {\n type: 'button',\n style: 'danger',\n label: 'Close',\n emoji: '🔒',\n custom_id: 'ticket_close',\n },\n {\n type: 'button',\n style: 'secondary',\n label: 'Transcript',\n emoji: '📜',\n custom_id: 'ticket_transcript',\n },\n ],\n },\n];\n\nexport const ticketsEventHandlers: EventHandler[] = [\n // Handle ticket creation button\n {\n event: 'button_click',\n condition: 'interaction.customId === \"ticket_create\"',\n actions: [\n // Check max tickets\n {\n action: 'db_query',\n table: 'tickets',\n where: {\n guild_id: '${guild.id}',\n user_id: '${user.id}',\n status: 'open',\n },\n as: 'userTickets',\n },\n {\n action: 'flow_if',\n condition: 'userTickets.length >= (config.tickets.maxTicketsPerUser || 1)',\n then: [\n {\n action: 'reply',\n content: 'You already have the maximum number of open tickets!',\n ephemeral: true,\n },\n { action: 'abort' },\n ],\n },\n // Show category selector if configured\n {\n action: 'flow_if',\n condition: 'config.tickets.categories && config.tickets.categories.length > 0',\n then: [\n {\n action: 'reply',\n content: 'Select a ticket category:',\n ephemeral: true,\n components: [\n {\n type: 'action_row',\n components: [\n {\n type: 'select_menu',\n custom_id: 'ticket_category_select',\n placeholder: 'Select category...',\n options: '${config.tickets.categories | map(c => ({ label: c.name, value: c.id, description: c.description, emoji: c.emoji }))}',\n },\n ],\n },\n ],\n },\n ],\n else: [\n { action: 'emit', event: 'ticket_create_confirmed', data: { category: 'general' } },\n ],\n },\n ],\n },\n // Handle category selection\n {\n event: 'select_menu',\n condition: 'interaction.customId === \"ticket_category_select\"',\n actions: [\n {\n action: 'emit',\n event: 'ticket_create_confirmed',\n data: { category: '${interaction.values[0]}' },\n },\n ],\n },\n // Create the ticket channel\n {\n event: 'ticket_create_confirmed',\n actions: [\n {\n action: 'db_query',\n table: 'tickets',\n where: { guild_id: '${guild.id}' },\n order_by: 'id DESC',\n limit: 1,\n as: 'lastTicket',\n },\n {\n action: 'set',\n key: 'ticketNumber',\n value: '${(lastTicket[0]?.id || 0) + 1}',\n },\n {\n action: 'set',\n key: 'channelName',\n value: '${(config.tickets.channelPattern || \"ticket-{number}\") | replace(\"{number}\", ticketNumber) | replace(\"{user}\", user.username) | replace(\"{category}\", event.data.category)}',\n },\n // Get support roles for this category\n {\n action: 'set',\n key: 'categoryConfig',\n value: '${config.tickets.categories?.find(c => c.id === event.data.category)}',\n },\n {\n action: 'set',\n key: 'supportRoles',\n value: '${categoryConfig?.supportRoles || config.tickets.supportRoles || []}',\n },\n // Create channel with permissions\n {\n action: 'create_channel',\n name: '${channelName}',\n type: 'text',\n parent: '${config.tickets.category}',\n permission_overwrites: [\n {\n id: '${guild.id}',\n type: 'role',\n deny: ['VIEW_CHANNEL'],\n },\n {\n id: '${user.id}',\n type: 'member',\n allow: ['VIEW_CHANNEL', 'SEND_MESSAGES', 'READ_MESSAGE_HISTORY', 'ATTACH_FILES'],\n },\n '${supportRoles | map(r => ({ id: r, type: \"role\", allow: [\"VIEW_CHANNEL\", \"SEND_MESSAGES\", \"READ_MESSAGE_HISTORY\", \"ATTACH_FILES\", \"MANAGE_MESSAGES\"] }))}',\n ],\n as: 'ticketChannel',\n },\n // Store in database\n {\n action: 'db_insert',\n table: 'tickets',\n data: {\n channel_id: '${ticketChannel.id}',\n guild_id: '${guild.id}',\n user_id: '${user.id}',\n category: '${event.data.category}',\n status: 'open',\n created_at: '${now()}',\n },\n },\n // Send opening message\n {\n action: 'send_message',\n channel: '${ticketChannel.id}',\n content: 'Welcome ${user}! Support will be with you shortly.',\n embed: {\n title: 'Ticket #${ticketNumber}',\n description: 'Please describe your issue and a staff member will assist you.',\n color: '#5865f2',\n fields: [\n { name: 'Category', value: '${categoryConfig?.name || \"General\"}', inline: true },\n { name: 'Created by', value: '${user}', inline: true },\n ],\n timestamp: '${now()}',\n },\n components: '${ticketControlComponents}',\n },\n // Reply to original interaction\n {\n action: 'update_message',\n content: 'Your ticket has been created: ${ticketChannel}',\n components: [],\n },\n ],\n },\n // Handle claim button\n {\n event: 'button_click',\n condition: 'interaction.customId === \"ticket_claim\"',\n actions: [\n {\n action: 'db_query',\n table: 'tickets',\n where: { channel_id: '${channel.id}' },\n as: 'ticket',\n },\n {\n action: 'flow_if',\n condition: '!ticket[0]',\n then: [\n { action: 'reply', content: 'This is not a ticket channel!', ephemeral: true },\n { action: 'abort' },\n ],\n },\n {\n action: 'flow_if',\n condition: 'ticket[0].claimed_by',\n then: [\n { action: 'reply', content: 'This ticket is already claimed by <@${ticket[0].claimed_by}>!', ephemeral: true },\n { action: 'abort' },\n ],\n },\n {\n action: 'db_update',\n table: 'tickets',\n where: { channel_id: '${channel.id}' },\n data: { claimed_by: '${user.id}' },\n },\n {\n action: 'send_message',\n channel: '${channel.id}',\n embed: {\n description: '${user} has claimed this ticket.',\n color: '#57f287',\n },\n },\n { action: 'reply', content: 'You have claimed this ticket!', ephemeral: true },\n ],\n },\n // Handle close button\n {\n event: 'button_click',\n condition: 'interaction.customId === \"ticket_close\"',\n actions: [\n {\n action: 'db_query',\n table: 'tickets',\n where: { channel_id: '${channel.id}' },\n as: 'ticket',\n },\n {\n action: 'flow_if',\n condition: '!ticket[0]',\n then: [\n { action: 'reply', content: 'This is not a ticket channel!', ephemeral: true },\n { action: 'abort' },\n ],\n },\n // Confirm close\n {\n action: 'reply',\n content: 'Are you sure you want to close this ticket?',\n ephemeral: true,\n components: [\n {\n type: 'action_row',\n components: [\n { type: 'button', style: 'danger', label: 'Close Ticket', custom_id: 'ticket_close_confirm' },\n { type: 'button', style: 'secondary', label: 'Cancel', custom_id: 'ticket_close_cancel' },\n ],\n },\n ],\n },\n ],\n },\n // Handle close confirmation\n {\n event: 'button_click',\n condition: 'interaction.customId === \"ticket_close_confirm\"',\n actions: [\n {\n action: 'db_query',\n table: 'tickets',\n where: { channel_id: '${channel.id}' },\n as: 'ticket',\n },\n // Generate transcript if configured\n {\n action: 'flow_if',\n condition: 'config.tickets.includeTranscript && config.tickets.logChannel',\n then: [\n {\n action: 'db_query',\n table: 'ticket_messages',\n where: { ticket_id: '${ticket[0].id}' },\n order_by: 'created_at ASC',\n as: 'messages',\n },\n {\n action: 'set',\n key: 'transcriptText',\n value: '${messages | map(m => \"[\" + formatDate(m.created_at, \"YYYY-MM-DD HH:mm:ss\") + \"] \" + m.author_name + \": \" + m.content) | join(\"\\\\n\")}',\n },\n {\n action: 'send_message',\n channel: '${config.tickets.logChannel}',\n embed: {\n title: 'Ticket Closed',\n fields: [\n { name: 'Ticket ID', value: '${ticket[0].id}', inline: true },\n { name: 'Opened by', value: '<@${ticket[0].user_id}>', inline: true },\n { name: 'Closed by', value: '${user}', inline: true },\n { name: 'Category', value: '${ticket[0].category}', inline: true },\n ],\n color: '#ed4245',\n timestamp: '${now()}',\n },\n files: [\n {\n attachment: '${Buffer.from(transcriptText)}',\n name: 'transcript-${ticket[0].id}.txt',\n },\n ],\n },\n ],\n },\n // Update database\n {\n action: 'db_update',\n table: 'tickets',\n where: { channel_id: '${channel.id}' },\n data: { status: 'closed', closed_at: '${now()}' },\n },\n // DM user if configured\n {\n action: 'flow_if',\n condition: 'config.tickets.dmOnClose',\n then: [\n {\n action: 'send_dm',\n user: '${ticket[0].user_id}',\n embed: {\n title: 'Ticket Closed',\n description: 'Your ticket in ${guild.name} has been closed.',\n color: '#ed4245',\n },\n },\n ],\n },\n // Delete channel after delay\n {\n action: 'send_message',\n channel: '${channel.id}',\n content: 'This ticket will be deleted in 5 seconds...',\n },\n { action: 'wait', duration: 5000 },\n { action: 'delete_channel', channel: '${channel.id}' },\n ],\n },\n // Handle transcript button\n {\n event: 'button_click',\n condition: 'interaction.customId === \"ticket_transcript\"',\n actions: [\n {\n action: 'db_query',\n table: 'tickets',\n where: { channel_id: '${channel.id}' },\n as: 'ticket',\n },\n {\n action: 'db_query',\n table: 'ticket_messages',\n where: { ticket_id: '${ticket[0].id}' },\n order_by: 'created_at ASC',\n as: 'messages',\n },\n {\n action: 'set',\n key: 'transcriptText',\n value: '${messages | map(m => \"[\" + formatDate(m.created_at, \"YYYY-MM-DD HH:mm:ss\") + \"] \" + m.author_name + \": \" + m.content) | join(\"\\\\n\")}',\n },\n {\n action: 'reply',\n content: 'Here is the transcript:',\n ephemeral: true,\n files: [\n {\n attachment: '${Buffer.from(transcriptText)}',\n name: 'transcript-${ticket[0].id}.txt',\n },\n ],\n },\n ],\n },\n // Log ticket messages\n {\n event: 'message',\n condition: 'channel.parentId === config.tickets.category',\n actions: [\n {\n action: 'db_query',\n table: 'tickets',\n where: { channel_id: '${channel.id}' },\n as: 'ticket',\n },\n {\n action: 'flow_if',\n condition: 'ticket[0]',\n then: [\n {\n action: 'db_insert',\n table: 'ticket_messages',\n data: {\n ticket_id: '${ticket[0].id}',\n author_id: '${user.id}',\n author_name: '${user.tag}',\n content: '${message.content}',\n attachments: '${message.attachments | map(a => a.url)}',\n created_at: '${now()}',\n },\n },\n ],\n },\n ],\n },\n];\n\nexport const ticketsCommands: CommandDefinition[] = [\n {\n name: 'ticket',\n description: 'Ticket management commands',\n subcommands: [\n {\n name: 'panel',\n description: 'Create a ticket panel',\n options: [\n { name: 'channel', description: 'Channel to send panel', type: 'channel', required: false },\n { name: 'message', description: 'Custom panel message', type: 'string', required: false },\n ],\n actions: [\n {\n action: 'send_message',\n channel: '${args.channel?.id || channel.id}',\n embed: {\n title: 'Support Tickets',\n description: '${args.message || \"Need help? Click the button below to create a support ticket.\"}',\n color: '#5865f2',\n },\n components: '${ticketPanelComponents}',\n },\n {\n action: 'reply',\n content: 'Ticket panel created!',\n ephemeral: true,\n },\n ],\n },\n {\n name: 'add',\n description: 'Add a user to the ticket',\n options: [\n { name: 'user', description: 'User to add', type: 'user', required: true },\n ],\n actions: [\n {\n action: 'db_query',\n table: 'tickets',\n where: { channel_id: '${channel.id}' },\n as: 'ticket',\n },\n {\n action: 'flow_if',\n condition: '!ticket[0]',\n then: [\n { action: 'reply', content: 'This is not a ticket channel!', ephemeral: true },\n { action: 'abort' },\n ],\n },\n {\n action: 'set_channel_permissions',\n channel: '${channel.id}',\n user: '${args.user.id}',\n allow: ['VIEW_CHANNEL', 'SEND_MESSAGES', 'READ_MESSAGE_HISTORY'],\n },\n {\n action: 'send_message',\n channel: '${channel.id}',\n content: '${args.user} has been added to the ticket.',\n },\n { action: 'reply', content: 'User added!', ephemeral: true },\n ],\n },\n {\n name: 'remove',\n description: 'Remove a user from the ticket',\n options: [\n { name: 'user', description: 'User to remove', type: 'user', required: true },\n ],\n actions: [\n {\n action: 'db_query',\n table: 'tickets',\n where: { channel_id: '${channel.id}' },\n as: 'ticket',\n },\n {\n action: 'flow_if',\n condition: '!ticket[0]',\n then: [\n { action: 'reply', content: 'This is not a ticket channel!', ephemeral: true },\n { action: 'abort' },\n ],\n },\n {\n action: 'set_channel_permissions',\n channel: '${channel.id}',\n user: '${args.user.id}',\n deny: ['VIEW_CHANNEL'],\n },\n {\n action: 'send_message',\n channel: '${channel.id}',\n content: '${args.user.username} has been removed from the ticket.',\n },\n { action: 'reply', content: 'User removed!', ephemeral: true },\n ],\n },\n {\n name: 'rename',\n description: 'Rename the ticket channel',\n options: [\n { name: 'name', description: 'New channel name', type: 'string', required: true },\n ],\n actions: [\n {\n action: 'db_query',\n table: 'tickets',\n where: { channel_id: '${channel.id}' },\n as: 'ticket',\n },\n {\n action: 'flow_if',\n condition: '!ticket[0]',\n then: [\n { action: 'reply', content: 'This is not a ticket channel!', ephemeral: true },\n { action: 'abort' },\n ],\n },\n {\n action: 'edit_channel',\n channel: '${channel.id}',\n name: '${args.name}',\n },\n { action: 'reply', content: 'Ticket renamed!', ephemeral: true },\n ],\n },\n ],\n },\n];\n\nexport function getTicketsSpec(config: TicketsConfig = {}): Partial<FurlowSpec> {\n return {\n events: ticketsEventHandlers,\n commands: ticketsCommands,\n state: {\n tables: ticketsTables,\n },\n };\n}\n"],"mappings":"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","names":[]}
|
package/dist/utilities/index.js
CHANGED
|
@@ -7,7 +7,7 @@ var utilitiesCommands = [
|
|
|
7
7
|
{
|
|
8
8
|
action: "set",
|
|
9
9
|
key: "boostLevel",
|
|
10
|
-
value: '${["None", "Level 1", "Level 2", "Level 3"][guild.
|
|
10
|
+
value: '${["None", "Level 1", "Level 2", "Level 3"][guild.premium_tier]}'
|
|
11
11
|
},
|
|
12
12
|
{
|
|
13
13
|
action: "set",
|
|
@@ -18,17 +18,17 @@ var utilitiesCommands = [
|
|
|
18
18
|
action: "reply",
|
|
19
19
|
embed: {
|
|
20
20
|
title: "${guild.name}",
|
|
21
|
-
thumbnail: "${guild.
|
|
21
|
+
thumbnail: "${guild.icon}",
|
|
22
22
|
color: "#5865f2",
|
|
23
23
|
fields: [
|
|
24
|
-
{ name: "Owner", value: "<@${guild.
|
|
25
|
-
{ name: "Created", value: '${timestamp(guild.
|
|
26
|
-
{ name: "Members", value: "${guild.
|
|
27
|
-
{ name: "Channels", value: "${guild.
|
|
28
|
-
{ name: "Roles", value: "${guild.
|
|
29
|
-
{ name: "Emojis", value: "${guild.
|
|
24
|
+
{ name: "Owner", value: "<@${guild.owner_id}>", inline: true },
|
|
25
|
+
{ name: "Created", value: '${timestamp(guild.created_at, "R")}', inline: true },
|
|
26
|
+
{ name: "Members", value: "${guild.member_count}", inline: true },
|
|
27
|
+
{ name: "Channels", value: "${guild.channel_count}", inline: true },
|
|
28
|
+
{ name: "Roles", value: "${guild.role_count}", inline: true },
|
|
29
|
+
{ name: "Emojis", value: "${guild.emoji_count}", inline: true },
|
|
30
30
|
{ name: "Boost Level", value: "${boostLevel}", inline: true },
|
|
31
|
-
{ name: "Boosts", value: "${guild.
|
|
31
|
+
{ name: "Boosts", value: "${guild.boost_count || 0}", inline: true },
|
|
32
32
|
{ name: "Verification", value: "${verificationLevel}", inline: true }
|
|
33
33
|
],
|
|
34
34
|
footer: { text: "ID: ${guild.id}" }
|
|
@@ -51,27 +51,27 @@ var utilitiesCommands = [
|
|
|
51
51
|
{
|
|
52
52
|
action: "set",
|
|
53
53
|
key: "targetMember",
|
|
54
|
-
value: "${
|
|
54
|
+
value: "${options.member || member}"
|
|
55
55
|
},
|
|
56
56
|
{
|
|
57
57
|
action: "set",
|
|
58
58
|
key: "roles",
|
|
59
|
-
value: '${targetMember
|
|
59
|
+
value: '${targetMember.roles | slice(0, 10) | join(", ") || "None"}'
|
|
60
60
|
},
|
|
61
61
|
{
|
|
62
62
|
action: "reply",
|
|
63
63
|
embed: {
|
|
64
64
|
title: "${targetUser.tag}",
|
|
65
|
-
thumbnail: "${targetUser.
|
|
66
|
-
color:
|
|
65
|
+
thumbnail: "${targetUser.avatar}",
|
|
66
|
+
color: "#5865f2",
|
|
67
67
|
fields: [
|
|
68
68
|
{ name: "Username", value: "${targetUser.username}", inline: true },
|
|
69
|
-
{ name: "Nickname", value: '${targetMember
|
|
69
|
+
{ name: "Nickname", value: '${targetMember.nickname || "None"}', inline: true },
|
|
70
70
|
{ name: "Bot", value: '${targetUser.bot ? "Yes" : "No"}', inline: true },
|
|
71
|
-
{ name: "Created", value: '${timestamp(targetUser.
|
|
72
|
-
{ name: "Joined", value: '${
|
|
73
|
-
{ name: "Highest Role", value: '${targetMember
|
|
74
|
-
{ name: "Roles
|
|
71
|
+
{ name: "Created", value: '${timestamp(targetUser.created_at, "R")}', inline: true },
|
|
72
|
+
{ name: "Joined", value: '${timestamp(targetMember.joined_at, "R")}', inline: true },
|
|
73
|
+
{ name: "Highest Role", value: '${targetMember.highest_role || "None"}', inline: true },
|
|
74
|
+
{ name: "Roles", value: "${roles}", inline: false }
|
|
75
75
|
],
|
|
76
76
|
footer: { text: "ID: ${targetUser.id}" }
|
|
77
77
|
}
|
|
@@ -94,9 +94,9 @@ var utilitiesCommands = [
|
|
|
94
94
|
action: "reply",
|
|
95
95
|
embed: {
|
|
96
96
|
title: "${targetUser.tag}'s Avatar",
|
|
97
|
-
image: "${targetUser.
|
|
97
|
+
image: "${targetUser.avatar}",
|
|
98
98
|
color: "#5865f2",
|
|
99
|
-
description:
|
|
99
|
+
description: "Click the image to view full size"
|
|
100
100
|
}
|
|
101
101
|
}
|
|
102
102
|
]
|
|
@@ -115,7 +115,7 @@ var utilitiesCommands = [
|
|
|
115
115
|
},
|
|
116
116
|
{
|
|
117
117
|
action: "flow_if",
|
|
118
|
-
condition: "
|
|
118
|
+
condition: "!targetUser.banner",
|
|
119
119
|
then: [
|
|
120
120
|
{ action: "reply", content: "This user has no banner!", ephemeral: true },
|
|
121
121
|
{ action: "abort" }
|
|
@@ -125,7 +125,7 @@ var utilitiesCommands = [
|
|
|
125
125
|
action: "reply",
|
|
126
126
|
embed: {
|
|
127
127
|
title: "${targetUser.tag}'s Banner",
|
|
128
|
-
image: "${targetUser.
|
|
128
|
+
image: "${targetUser.banner}",
|
|
129
129
|
color: "#5865f2"
|
|
130
130
|
}
|
|
131
131
|
}
|
|
@@ -232,7 +232,7 @@ var utilitiesCommands = [
|
|
|
232
232
|
title: "Member Count",
|
|
233
233
|
color: "#5865f2",
|
|
234
234
|
fields: [
|
|
235
|
-
{ name: "Total", value: "${guild.
|
|
235
|
+
{ name: "Total", value: "${guild.member_count}", inline: true },
|
|
236
236
|
{ name: "Humans", value: "${humans}", inline: true },
|
|
237
237
|
{ name: "Bots", value: "${bots}", inline: true }
|
|
238
238
|
]
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/utilities/index.ts"],"sourcesContent":["/**\n * Utilities builtin module\n * Common utility commands: serverinfo, userinfo, avatar, etc.\n */\n\nimport type { FurlowSpec, CommandDefinition } from '@furlow/schema';\n\nexport interface UtilitiesConfig {\n /** Commands to enable/disable */\n enabledCommands?: string[];\n}\n\nexport const utilitiesCommands: CommandDefinition[] = [\n {\n name: 'serverinfo',\n description: 'View server information',\n actions: [\n {\n action: 'set',\n key: 'boostLevel',\n value: '${[\"None\", \"Level 1\", \"Level 2\", \"Level 3\"][guild.premiumTier]}',\n },\n {\n action: 'set',\n key: 'verificationLevel',\n value: '${[\"None\", \"Low\", \"Medium\", \"High\", \"Highest\"][guild.verificationLevel]}',\n },\n {\n action: 'reply',\n embed: {\n title: '${guild.name}',\n thumbnail: '${guild.iconURL({ size: 256 })}',\n color: '#5865f2',\n fields: [\n { name: 'Owner', value: '<@${guild.ownerId}>', inline: true },\n { name: 'Created', value: '${timestamp(guild.createdAt, \"R\")}', inline: true },\n { name: 'Members', value: '${guild.memberCount}', inline: true },\n { name: 'Channels', value: '${guild.channels.cache.size}', inline: true },\n { name: 'Roles', value: '${guild.roles.cache.size}', inline: true },\n { name: 'Emojis', value: '${guild.emojis.cache.size}', inline: true },\n { name: 'Boost Level', value: '${boostLevel}', inline: true },\n { name: 'Boosts', value: '${guild.premiumSubscriptionCount || 0}', inline: true },\n { name: 'Verification', value: '${verificationLevel}', inline: true },\n ],\n footer: { text: 'ID: ${guild.id}' },\n },\n },\n ],\n },\n {\n name: 'userinfo',\n description: 'View user information',\n options: [\n { name: 'user', description: 'User to view', type: 'user', required: false },\n ],\n actions: [\n {\n action: 'set',\n key: 'targetUser',\n value: '${args.user || user}',\n },\n {\n action: 'set',\n key: 'targetMember',\n value: '${guild.members.cache.get(targetUser.id)}',\n },\n {\n action: 'set',\n key: 'roles',\n value: '${targetMember?.roles?.cache?.filter(r => r.id !== guild.id)?.sort((a, b) => b.position - a.position)?.map(r => r.toString())?.slice(0, 10)?.join(\", \") || \"None\"}',\n },\n {\n action: 'reply',\n embed: {\n title: '${targetUser.tag}',\n thumbnail: '${targetUser.avatarURL({ size: 256 })}',\n color: '${targetMember?.displayHexColor || \"#5865f2\"}',\n fields: [\n { name: 'Username', value: '${targetUser.username}', inline: true },\n { name: 'Nickname', value: '${targetMember?.nickname || \"None\"}', inline: true },\n { name: 'Bot', value: '${targetUser.bot ? \"Yes\" : \"No\"}', inline: true },\n { name: 'Created', value: '${timestamp(targetUser.createdAt, \"R\")}', inline: true },\n { name: 'Joined', value: '${targetMember?.joinedAt ? timestamp(targetMember.joinedAt, \"R\") : \"N/A\"}', inline: true },\n { name: 'Highest Role', value: '${targetMember?.roles?.highest?.toString() || \"None\"}', inline: true },\n { name: 'Roles (${targetMember?.roles?.cache?.size - 1 || 0})', value: '${roles}', inline: false },\n ],\n footer: { text: 'ID: ${targetUser.id}' },\n },\n },\n ],\n },\n {\n name: 'avatar',\n description: 'View user avatar',\n options: [\n { name: 'user', description: 'User to view', type: 'user', required: false },\n ],\n actions: [\n {\n action: 'set',\n key: 'targetUser',\n value: '${args.user || user}',\n },\n {\n action: 'reply',\n embed: {\n title: '${targetUser.tag}\\'s Avatar',\n image: '${targetUser.avatarURL({ size: 1024 }) || targetUser.defaultAvatarURL}',\n color: '#5865f2',\n description: '[PNG](${targetUser.avatarURL({ format: \"png\", size: 1024 })}) | [JPG](${targetUser.avatarURL({ format: \"jpg\", size: 1024 })}) | [WEBP](${targetUser.avatarURL({ format: \"webp\", size: 1024 })})',\n },\n },\n ],\n },\n {\n name: 'banner',\n description: 'View user banner',\n options: [\n { name: 'user', description: 'User to view', type: 'user', required: false },\n ],\n actions: [\n {\n action: 'set',\n key: 'targetUser',\n value: '${args.user || user}',\n },\n {\n action: 'flow_if',\n condition: '${!targetUser.bannerURL()}',\n then: [\n { action: 'reply', content: 'This user has no banner!', ephemeral: true },\n { action: 'abort' },\n ],\n },\n {\n action: 'reply',\n embed: {\n title: '${targetUser.tag}\\'s Banner',\n image: '${targetUser.bannerURL({ size: 1024 })}',\n color: '#5865f2',\n },\n },\n ],\n },\n {\n name: 'roleinfo',\n description: 'View role information',\n options: [\n { name: 'role', description: 'Role to view', type: 'role', required: true },\n ],\n actions: [\n {\n action: 'reply',\n embed: {\n title: '${args.role.name}',\n color: '${args.role.hexColor}',\n fields: [\n { name: 'Color', value: '${args.role.hexColor}', inline: true },\n { name: 'Position', value: '${args.role.position}', inline: true },\n { name: 'Members', value: '${args.role.members.size}', inline: true },\n { name: 'Hoisted', value: '${args.role.hoist ? \"Yes\" : \"No\"}', inline: true },\n { name: 'Mentionable', value: '${args.role.mentionable ? \"Yes\" : \"No\"}', inline: true },\n { name: 'Managed', value: '${args.role.managed ? \"Yes\" : \"No\"}', inline: true },\n { name: 'Created', value: '${timestamp(args.role.createdAt, \"R\")}', inline: true },\n ],\n footer: { text: 'ID: ${args.role.id}' },\n },\n },\n ],\n },\n {\n name: 'channelinfo',\n description: 'View channel information',\n options: [\n { name: 'channel', description: 'Channel to view', type: 'channel', required: false },\n ],\n actions: [\n {\n action: 'set',\n key: 'targetChannel',\n value: '${args.channel || channel}',\n },\n {\n action: 'reply',\n embed: {\n title: '#${targetChannel.name}',\n color: '#5865f2',\n fields: [\n { name: 'Type', value: '${targetChannel.type}', inline: true },\n { name: 'Category', value: '${targetChannel.parent?.name || \"None\"}', inline: true },\n { name: 'Position', value: '${targetChannel.position}', inline: true },\n { name: 'NSFW', value: '${targetChannel.nsfw ? \"Yes\" : \"No\"}', inline: true },\n { name: 'Created', value: '${timestamp(targetChannel.createdAt, \"R\")}', inline: true },\n { name: 'Topic', value: '${targetChannel.topic || \"None\"}', inline: false },\n ],\n footer: { text: 'ID: ${targetChannel.id}' },\n },\n },\n ],\n },\n {\n name: 'ping',\n description: 'Check bot latency',\n actions: [\n {\n action: 'reply',\n content: 'Pong! Latency: ${client.ws.ping}ms',\n },\n ],\n },\n {\n name: 'invite',\n description: 'Get bot invite link',\n actions: [\n {\n action: 'reply',\n embed: {\n title: 'Invite ${client.user.username}',\n description: '[Click here to invite](https://discord.com/oauth2/authorize?client_id=${client.user.id}&permissions=8&scope=bot%20applications.commands)',\n color: '#5865f2',\n },\n ephemeral: true,\n },\n ],\n },\n {\n name: 'membercount',\n description: 'View member count',\n actions: [\n {\n action: 'set',\n key: 'humans',\n value: '${guild.members.cache.filter(m => !m.user.bot).size}',\n },\n {\n action: 'set',\n key: 'bots',\n value: '${guild.members.cache.filter(m => m.user.bot).size}',\n },\n {\n action: 'reply',\n embed: {\n title: 'Member Count',\n color: '#5865f2',\n fields: [\n { name: 'Total', value: '${guild.memberCount}', inline: true },\n { name: 'Humans', value: '${humans}', inline: true },\n { name: 'Bots', value: '${bots}', inline: true },\n ],\n },\n },\n ],\n },\n {\n name: 'emojis',\n description: 'List server emojis',\n actions: [\n {\n action: 'set',\n key: 'staticEmojis',\n value: '${guild.emojis.cache.filter(e => !e.animated).map(e => e.toString()).slice(0, 50).join(\" \")}',\n },\n {\n action: 'set',\n key: 'animatedEmojis',\n value: '${guild.emojis.cache.filter(e => e.animated).map(e => e.toString()).slice(0, 50).join(\" \")}',\n },\n {\n action: 'reply',\n embed: {\n title: '${guild.name} Emojis',\n color: '#5865f2',\n fields: [\n { name: 'Static (${guild.emojis.cache.filter(e => !e.animated).size})', value: '${staticEmojis || \"None\"}' },\n { name: 'Animated (${guild.emojis.cache.filter(e => e.animated).size})', value: '${animatedEmojis || \"None\"}' },\n ],\n },\n },\n ],\n },\n {\n name: 'roles',\n description: 'List server roles',\n actions: [\n {\n action: 'set',\n key: 'roleList',\n value: '${guild.roles.cache.filter(r => r.id !== guild.id).sort((a, b) => b.position - a.position).map(r => r.toString()).slice(0, 40).join(\", \")}',\n },\n {\n action: 'reply',\n embed: {\n title: '${guild.name} Roles (${guild.roles.cache.size - 1})',\n description: '${roleList}',\n color: '#5865f2',\n },\n },\n ],\n },\n];\n\nexport function getUtilitiesSpec(config: UtilitiesConfig = {}): Partial<FurlowSpec> {\n return {\n commands: utilitiesCommands,\n };\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/utilities/index.ts"],"sourcesContent":["/**\n * Utilities builtin module\n * Common utility commands: serverinfo, userinfo, avatar, etc.\n */\n\nimport type { FurlowSpec, CommandDefinition } from '@furlow/schema';\n\nexport interface UtilitiesConfig {\n /** Commands to enable/disable */\n enabledCommands?: string[];\n}\n\nexport const utilitiesCommands: CommandDefinition[] = [\n {\n name: 'serverinfo',\n description: 'View server information',\n actions: [\n {\n action: 'set',\n key: 'boostLevel',\n value: '${[\"None\", \"Level 1\", \"Level 2\", \"Level 3\"][guild.premium_tier]}',\n },\n {\n action: 'set',\n key: 'verificationLevel',\n value: '${[\"None\", \"Low\", \"Medium\", \"High\", \"Highest\"][guild.verificationLevel]}',\n },\n {\n action: 'reply',\n embed: {\n title: '${guild.name}',\n thumbnail: '${guild.icon}',\n color: '#5865f2',\n fields: [\n { name: 'Owner', value: '<@${guild.owner_id}>', inline: true },\n { name: 'Created', value: '${timestamp(guild.created_at, \"R\")}', inline: true },\n { name: 'Members', value: '${guild.member_count}', inline: true },\n { name: 'Channels', value: '${guild.channel_count}', inline: true },\n { name: 'Roles', value: '${guild.role_count}', inline: true },\n { name: 'Emojis', value: '${guild.emoji_count}', inline: true },\n { name: 'Boost Level', value: '${boostLevel}', inline: true },\n { name: 'Boosts', value: '${guild.boost_count || 0}', inline: true },\n { name: 'Verification', value: '${verificationLevel}', inline: true },\n ],\n footer: { text: 'ID: ${guild.id}' },\n },\n },\n ],\n },\n {\n name: 'userinfo',\n description: 'View user information',\n options: [\n { name: 'user', description: 'User to view', type: 'user', required: false },\n ],\n actions: [\n {\n action: 'set',\n key: 'targetUser',\n value: '${args.user || user}',\n },\n {\n action: 'set',\n key: 'targetMember',\n value: '${options.member || member}',\n },\n {\n action: 'set',\n key: 'roles',\n value: '${targetMember.roles | slice(0, 10) | join(\", \") || \"None\"}',\n },\n {\n action: 'reply',\n embed: {\n title: '${targetUser.tag}',\n thumbnail: '${targetUser.avatar}',\n color: '#5865f2',\n fields: [\n { name: 'Username', value: '${targetUser.username}', inline: true },\n { name: 'Nickname', value: '${targetMember.nickname || \"None\"}', inline: true },\n { name: 'Bot', value: '${targetUser.bot ? \"Yes\" : \"No\"}', inline: true },\n { name: 'Created', value: '${timestamp(targetUser.created_at, \"R\")}', inline: true },\n { name: 'Joined', value: '${timestamp(targetMember.joined_at, \"R\")}', inline: true },\n { name: 'Highest Role', value: '${targetMember.highest_role || \"None\"}', inline: true },\n { name: 'Roles', value: '${roles}', inline: false },\n ],\n footer: { text: 'ID: ${targetUser.id}' },\n },\n },\n ],\n },\n {\n name: 'avatar',\n description: 'View user avatar',\n options: [\n { name: 'user', description: 'User to view', type: 'user', required: false },\n ],\n actions: [\n {\n action: 'set',\n key: 'targetUser',\n value: '${args.user || user}',\n },\n {\n action: 'reply',\n embed: {\n title: '${targetUser.tag}\\'s Avatar',\n image: '${targetUser.avatar}',\n color: '#5865f2',\n description: 'Click the image to view full size',\n },\n },\n ],\n },\n {\n name: 'banner',\n description: 'View user banner',\n options: [\n { name: 'user', description: 'User to view', type: 'user', required: false },\n ],\n actions: [\n {\n action: 'set',\n key: 'targetUser',\n value: '${args.user || user}',\n },\n {\n action: 'flow_if',\n condition: '!targetUser.banner',\n then: [\n { action: 'reply', content: 'This user has no banner!', ephemeral: true },\n { action: 'abort' },\n ],\n },\n {\n action: 'reply',\n embed: {\n title: '${targetUser.tag}\\'s Banner',\n image: '${targetUser.banner}',\n color: '#5865f2',\n },\n },\n ],\n },\n {\n name: 'roleinfo',\n description: 'View role information',\n options: [\n { name: 'role', description: 'Role to view', type: 'role', required: true },\n ],\n actions: [\n {\n action: 'reply',\n embed: {\n title: '${args.role.name}',\n color: '${args.role.hexColor}',\n fields: [\n { name: 'Color', value: '${args.role.hexColor}', inline: true },\n { name: 'Position', value: '${args.role.position}', inline: true },\n { name: 'Members', value: '${args.role.members.size}', inline: true },\n { name: 'Hoisted', value: '${args.role.hoist ? \"Yes\" : \"No\"}', inline: true },\n { name: 'Mentionable', value: '${args.role.mentionable ? \"Yes\" : \"No\"}', inline: true },\n { name: 'Managed', value: '${args.role.managed ? \"Yes\" : \"No\"}', inline: true },\n { name: 'Created', value: '${timestamp(args.role.createdAt, \"R\")}', inline: true },\n ],\n footer: { text: 'ID: ${args.role.id}' },\n },\n },\n ],\n },\n {\n name: 'channelinfo',\n description: 'View channel information',\n options: [\n { name: 'channel', description: 'Channel to view', type: 'channel', required: false },\n ],\n actions: [\n {\n action: 'set',\n key: 'targetChannel',\n value: '${args.channel || channel}',\n },\n {\n action: 'reply',\n embed: {\n title: '#${targetChannel.name}',\n color: '#5865f2',\n fields: [\n { name: 'Type', value: '${targetChannel.type}', inline: true },\n { name: 'Category', value: '${targetChannel.parent?.name || \"None\"}', inline: true },\n { name: 'Position', value: '${targetChannel.position}', inline: true },\n { name: 'NSFW', value: '${targetChannel.nsfw ? \"Yes\" : \"No\"}', inline: true },\n { name: 'Created', value: '${timestamp(targetChannel.createdAt, \"R\")}', inline: true },\n { name: 'Topic', value: '${targetChannel.topic || \"None\"}', inline: false },\n ],\n footer: { text: 'ID: ${targetChannel.id}' },\n },\n },\n ],\n },\n {\n name: 'ping',\n description: 'Check bot latency',\n actions: [\n {\n action: 'reply',\n content: 'Pong! Latency: ${client.ws.ping}ms',\n },\n ],\n },\n {\n name: 'invite',\n description: 'Get bot invite link',\n actions: [\n {\n action: 'reply',\n embed: {\n title: 'Invite ${client.user.username}',\n description: '[Click here to invite](https://discord.com/oauth2/authorize?client_id=${client.user.id}&permissions=8&scope=bot%20applications.commands)',\n color: '#5865f2',\n },\n ephemeral: true,\n },\n ],\n },\n {\n name: 'membercount',\n description: 'View member count',\n actions: [\n {\n action: 'set',\n key: 'humans',\n value: '${guild.members.cache.filter(m => !m.user.bot).size}',\n },\n {\n action: 'set',\n key: 'bots',\n value: '${guild.members.cache.filter(m => m.user.bot).size}',\n },\n {\n action: 'reply',\n embed: {\n title: 'Member Count',\n color: '#5865f2',\n fields: [\n { name: 'Total', value: '${guild.member_count}', inline: true },\n { name: 'Humans', value: '${humans}', inline: true },\n { name: 'Bots', value: '${bots}', inline: true },\n ],\n },\n },\n ],\n },\n {\n name: 'emojis',\n description: 'List server emojis',\n actions: [\n {\n action: 'set',\n key: 'staticEmojis',\n value: '${guild.emojis.cache.filter(e => !e.animated).map(e => e.toString()).slice(0, 50).join(\" \")}',\n },\n {\n action: 'set',\n key: 'animatedEmojis',\n value: '${guild.emojis.cache.filter(e => e.animated).map(e => e.toString()).slice(0, 50).join(\" \")}',\n },\n {\n action: 'reply',\n embed: {\n title: '${guild.name} Emojis',\n color: '#5865f2',\n fields: [\n { name: 'Static (${guild.emojis.cache.filter(e => !e.animated).size})', value: '${staticEmojis || \"None\"}' },\n { name: 'Animated (${guild.emojis.cache.filter(e => e.animated).size})', value: '${animatedEmojis || \"None\"}' },\n ],\n },\n },\n ],\n },\n {\n name: 'roles',\n description: 'List server roles',\n actions: [\n {\n action: 'set',\n key: 'roleList',\n value: '${guild.roles.cache.filter(r => r.id !== guild.id).sort((a, b) => b.position - a.position).map(r => r.toString()).slice(0, 40).join(\", \")}',\n },\n {\n action: 'reply',\n embed: {\n title: '${guild.name} Roles (${guild.roles.cache.size - 1})',\n description: '${roleList}',\n color: '#5865f2',\n },\n },\n ],\n },\n];\n\nexport function getUtilitiesSpec(config: UtilitiesConfig = {}): Partial<FurlowSpec> {\n return {\n commands: utilitiesCommands,\n };\n}\n"],"mappings":";AAYO,IAAM,oBAAyC;AAAA,EACpD;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,SAAS;AAAA,MACP;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,MACA;AAAA,QACE,QAAQ;AAAA,QACR,OAAO;AAAA,UACL,OAAO;AAAA,UACP,WAAW;AAAA,UACX,OAAO;AAAA,UACP,QAAQ;AAAA,YACN,EAAE,MAAM,SAAS,OAAO,wBAAwB,QAAQ,KAAK;AAAA,YAC7D,EAAE,MAAM,WAAW,OAAO,uCAAuC,QAAQ,KAAK;AAAA,YAC9E,EAAE,MAAM,WAAW,OAAO,yBAAyB,QAAQ,KAAK;AAAA,YAChE,EAAE,MAAM,YAAY,OAAO,0BAA0B,QAAQ,KAAK;AAAA,YAClE,EAAE,MAAM,SAAS,OAAO,uBAAuB,QAAQ,KAAK;AAAA,YAC5D,EAAE,MAAM,UAAU,OAAO,wBAAwB,QAAQ,KAAK;AAAA,YAC9D,EAAE,MAAM,eAAe,OAAO,iBAAiB,QAAQ,KAAK;AAAA,YAC5D,EAAE,MAAM,UAAU,OAAO,6BAA6B,QAAQ,KAAK;AAAA,YACnE,EAAE,MAAM,gBAAgB,OAAO,wBAAwB,QAAQ,KAAK;AAAA,UACtE;AAAA,UACA,QAAQ,EAAE,MAAM,kBAAkB;AAAA,QACpC;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,SAAS;AAAA,MACP,EAAE,MAAM,QAAQ,aAAa,gBAAgB,MAAM,QAAQ,UAAU,MAAM;AAAA,IAC7E;AAAA,IACA,SAAS;AAAA,MACP;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,MACA;AAAA,QACE,QAAQ;AAAA,QACR,KAAK;AAAA,QACL,OAAO;AAAA,MACT;AAAA,MACA;AAAA,QACE,QAAQ;AAAA,QACR,OAAO;AAAA,UACL,OAAO;AAAA,UACP,WAAW;AAAA,UACX,OAAO;AAAA,UACP,QAAQ;AAAA,YACN,EAAE,MAAM,YAAY,OAAO,0BAA0B,QAAQ,KAAK;AAAA,YAClE,EAAE,MAAM,YAAY,OAAO,sCAAsC,QAAQ,KAAK;AAAA,YAC9E,EAAE,MAAM,OAAO,OAAO,oCAAoC,QAAQ,KAAK;AAAA,YACvE,EAAE,MAAM,WAAW,OAAO,4CAA4C,QAAQ,KAAK;AAAA,YACnF,EAAE,MAAM,UAAU,OAAO,6CAA6C,QAAQ,KAAK;AAAA,YACnF,EAAE,MAAM,gBAAgB,OAAO,0CAA0C,QAAQ,KAAK;AAAA,YACtF,EAAE,MAAM,SAAS,OAAO,YAAY,QAAQ,MAAM;AAAA,UACpD;AAAA,UACA,QAAQ,EAAE,MAAM,uBAAuB;AAAA,QACzC;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,SAAS;AAAA,MACP,EAAE,MAAM,QAAQ,aAAa,gBAAgB,MAAM,QAAQ,UAAU,MAAM;AAAA,IAC7E;AAAA,IACA,SAAS;AAAA,MACP;AAAA,QACE,QAAQ;AAAA,QACR,KAAK;AAAA,QACL,OAAO;AAAA,MACT;AAAA,MACA;AAAA,QACE,QAAQ;AAAA,QACR,OAAO;AAAA,UACL,OAAO;AAAA,UACP,OAAO;AAAA,UACP,OAAO;AAAA,UACP,aAAa;AAAA,QACf;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,SAAS;AAAA,MACP,EAAE,MAAM,QAAQ,aAAa,gBAAgB,MAAM,QAAQ,UAAU,MAAM;AAAA,IAC7E;AAAA,IACA,SAAS;AAAA,MACP;AAAA,QACE,QAAQ;AAAA,QACR,KAAK;AAAA,QACL,OAAO;AAAA,MACT;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,MACA;AAAA,QACE,QAAQ;AAAA,QACR,OAAO;AAAA,UACL,OAAO;AAAA,UACP,OAAO;AAAA,UACP,OAAO;AAAA,QACT;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,SAAS;AAAA,MACP,EAAE,MAAM,QAAQ,aAAa,gBAAgB,MAAM,QAAQ,UAAU,KAAK;AAAA,IAC5E;AAAA,IACA,SAAS;AAAA,MACP;AAAA,QACE,QAAQ;AAAA,QACR,OAAO;AAAA,UACL,OAAO;AAAA,UACP,OAAO;AAAA,UACP,QAAQ;AAAA,YACN,EAAE,MAAM,SAAS,OAAO,yBAAyB,QAAQ,KAAK;AAAA,YAC9D,EAAE,MAAM,YAAY,OAAO,yBAAyB,QAAQ,KAAK;AAAA,YACjE,EAAE,MAAM,WAAW,OAAO,6BAA6B,QAAQ,KAAK;AAAA,YACpE,EAAE,MAAM,WAAW,OAAO,qCAAqC,QAAQ,KAAK;AAAA,YAC5E,EAAE,MAAM,eAAe,OAAO,2CAA2C,QAAQ,KAAK;AAAA,YACtF,EAAE,MAAM,WAAW,OAAO,uCAAuC,QAAQ,KAAK;AAAA,YAC9E,EAAE,MAAM,WAAW,OAAO,0CAA0C,QAAQ,KAAK;AAAA,UACnF;AAAA,UACA,QAAQ,EAAE,MAAM,sBAAsB;AAAA,QACxC;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,SAAS;AAAA,MACP,EAAE,MAAM,WAAW,aAAa,mBAAmB,MAAM,WAAW,UAAU,MAAM;AAAA,IACtF;AAAA,IACA,SAAS;AAAA,MACP;AAAA,QACE,QAAQ;AAAA,QACR,KAAK;AAAA,QACL,OAAO;AAAA,MACT;AAAA,MACA;AAAA,QACE,QAAQ;AAAA,QACR,OAAO;AAAA,UACL,OAAO;AAAA,UACP,OAAO;AAAA,UACP,QAAQ;AAAA,YACN,EAAE,MAAM,QAAQ,OAAO,yBAAyB,QAAQ,KAAK;AAAA,YAC7D,EAAE,MAAM,YAAY,OAAO,2CAA2C,QAAQ,KAAK;AAAA,YACnF,EAAE,MAAM,YAAY,OAAO,6BAA6B,QAAQ,KAAK;AAAA,YACrE,EAAE,MAAM,QAAQ,OAAO,wCAAwC,QAAQ,KAAK;AAAA,YAC5E,EAAE,MAAM,WAAW,OAAO,8CAA8C,QAAQ,KAAK;AAAA,YACrF,EAAE,MAAM,SAAS,OAAO,oCAAoC,QAAQ,MAAM;AAAA,UAC5E;AAAA,UACA,QAAQ,EAAE,MAAM,0BAA0B;AAAA,QAC5C;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,SAAS;AAAA,MACP;AAAA,QACE,QAAQ;AAAA,QACR,SAAS;AAAA,MACX;AAAA,IACF;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,SAAS;AAAA,MACP;AAAA,QACE,QAAQ;AAAA,QACR,OAAO;AAAA,UACL,OAAO;AAAA,UACP,aAAa;AAAA,UACb,OAAO;AAAA,QACT;AAAA,QACA,WAAW;AAAA,MACb;AAAA,IACF;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,SAAS;AAAA,MACP;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,MACA;AAAA,QACE,QAAQ;AAAA,QACR,OAAO;AAAA,UACL,OAAO;AAAA,UACP,OAAO;AAAA,UACP,QAAQ;AAAA,YACN,EAAE,MAAM,SAAS,OAAO,yBAAyB,QAAQ,KAAK;AAAA,YAC9D,EAAE,MAAM,UAAU,OAAO,aAAa,QAAQ,KAAK;AAAA,YACnD,EAAE,MAAM,QAAQ,OAAO,WAAW,QAAQ,KAAK;AAAA,UACjD;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,SAAS;AAAA,MACP;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,MACA;AAAA,QACE,QAAQ;AAAA,QACR,OAAO;AAAA,UACL,OAAO;AAAA,UACP,OAAO;AAAA,UACP,QAAQ;AAAA,YACN,EAAE,MAAM,gEAAgE,OAAO,4BAA4B;AAAA,YAC3G,EAAE,MAAM,iEAAiE,OAAO,8BAA8B;AAAA,UAChH;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,SAAS;AAAA,MACP;AAAA,QACE,QAAQ;AAAA,QACR,KAAK;AAAA,QACL,OAAO;AAAA,MACT;AAAA,MACA;AAAA,QACE,QAAQ;AAAA,QACR,OAAO;AAAA,UACL,OAAO;AAAA,UACP,aAAa;AAAA,UACb,OAAO;AAAA,QACT;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;AAEO,SAAS,iBAAiB,SAA0B,CAAC,GAAwB;AAClF,SAAO;AAAA,IACL,UAAU;AAAA,EACZ;AACF;","names":[]}
|
package/dist/welcome/index.js
CHANGED
|
@@ -6,7 +6,7 @@ var welcomeEventHandlers = [
|
|
|
6
6
|
// Auto-role assignment
|
|
7
7
|
{
|
|
8
8
|
action: "flow_if",
|
|
9
|
-
condition: "
|
|
9
|
+
condition: "config.welcome.autoRoles && config.welcome.autoRoles.length > 0",
|
|
10
10
|
then: [
|
|
11
11
|
{
|
|
12
12
|
action: "assign_role",
|
|
@@ -18,7 +18,7 @@ var welcomeEventHandlers = [
|
|
|
18
18
|
// DM new member
|
|
19
19
|
{
|
|
20
20
|
action: "flow_if",
|
|
21
|
-
condition: "
|
|
21
|
+
condition: "config.welcome.dmNewMembers",
|
|
22
22
|
then: [
|
|
23
23
|
{
|
|
24
24
|
action: "send_dm",
|
|
@@ -30,7 +30,7 @@ var welcomeEventHandlers = [
|
|
|
30
30
|
// Welcome message with image
|
|
31
31
|
{
|
|
32
32
|
action: "flow_if",
|
|
33
|
-
condition: "
|
|
33
|
+
condition: "config.welcome.useImage",
|
|
34
34
|
then: [
|
|
35
35
|
{
|
|
36
36
|
action: "canvas_render",
|
|
@@ -38,14 +38,14 @@ var welcomeEventHandlers = [
|
|
|
38
38
|
context: {
|
|
39
39
|
member: "${member}",
|
|
40
40
|
guild: "${guild}",
|
|
41
|
-
memberCount: "${guild.
|
|
41
|
+
memberCount: "${guild.member_count}"
|
|
42
42
|
},
|
|
43
43
|
as: "welcomeImage"
|
|
44
44
|
},
|
|
45
45
|
{
|
|
46
46
|
action: "send_message",
|
|
47
47
|
channel: "${config.welcome.channel}",
|
|
48
|
-
content: '${config.welcome.message || "Welcome to the server, " + member.
|
|
48
|
+
content: '${config.welcome.message || "Welcome to the server, " + member.display_name + "!"}',
|
|
49
49
|
files: [
|
|
50
50
|
{
|
|
51
51
|
attachment: "${welcomeImage}",
|
|
@@ -58,7 +58,7 @@ var welcomeEventHandlers = [
|
|
|
58
58
|
// Welcome message without image
|
|
59
59
|
{
|
|
60
60
|
action: "flow_if",
|
|
61
|
-
condition: "
|
|
61
|
+
condition: "config.welcome.embed",
|
|
62
62
|
then: [
|
|
63
63
|
{
|
|
64
64
|
action: "send_message",
|
|
@@ -66,11 +66,11 @@ var welcomeEventHandlers = [
|
|
|
66
66
|
content: "${config.welcome.message}",
|
|
67
67
|
embed: {
|
|
68
68
|
title: '${config.welcome.embed.title || "Welcome!"}',
|
|
69
|
-
description: '${config.welcome.embed.description || "Welcome to " + guild.name + ", " + member.
|
|
69
|
+
description: '${config.welcome.embed.description || "Welcome to " + guild.name + ", " + member.display_name + "!"}',
|
|
70
70
|
color: '${config.welcome.embed.color || "#5865f2"}',
|
|
71
|
-
thumbnail: "${config.welcome.embed.thumbnail || member.
|
|
71
|
+
thumbnail: "${config.welcome.embed.thumbnail || member.avatar}",
|
|
72
72
|
footer: {
|
|
73
|
-
text: '${config.welcome.embed.footer || "Member #" + guild.
|
|
73
|
+
text: '${config.welcome.embed.footer || "Member #" + guild.member_count}'
|
|
74
74
|
}
|
|
75
75
|
}
|
|
76
76
|
}
|
|
@@ -79,7 +79,7 @@ var welcomeEventHandlers = [
|
|
|
79
79
|
{
|
|
80
80
|
action: "send_message",
|
|
81
81
|
channel: "${config.welcome.channel}",
|
|
82
|
-
content: '${config.welcome.message || "Welcome to the server, " + member.
|
|
82
|
+
content: '${config.welcome.message || "Welcome to the server, " + member.display_name + "!"}'
|
|
83
83
|
}
|
|
84
84
|
]
|
|
85
85
|
}
|
|
@@ -92,18 +92,18 @@ var welcomeEventHandlers = [
|
|
|
92
92
|
actions: [
|
|
93
93
|
{
|
|
94
94
|
action: "flow_if",
|
|
95
|
-
condition: "
|
|
95
|
+
condition: "config.welcome.leaveChannel || config.welcome.channel",
|
|
96
96
|
then: [
|
|
97
97
|
{
|
|
98
98
|
action: "flow_if",
|
|
99
|
-
condition: "
|
|
99
|
+
condition: "config.welcome.leaveEmbed",
|
|
100
100
|
then: [
|
|
101
101
|
{
|
|
102
102
|
action: "send_message",
|
|
103
103
|
channel: "${config.welcome.leaveChannel || config.welcome.channel}",
|
|
104
104
|
embed: {
|
|
105
105
|
title: '${config.welcome.leaveEmbed.title || "Goodbye!"}',
|
|
106
|
-
description: '${config.welcome.leaveEmbed.description || member.
|
|
106
|
+
description: '${config.welcome.leaveEmbed.description || member.display_name + " has left the server."}',
|
|
107
107
|
color: '${config.welcome.leaveEmbed.color || "#ed4245"}'
|
|
108
108
|
}
|
|
109
109
|
}
|
|
@@ -112,7 +112,7 @@ var welcomeEventHandlers = [
|
|
|
112
112
|
{
|
|
113
113
|
action: "send_message",
|
|
114
114
|
channel: "${config.welcome.leaveChannel || config.welcome.channel}",
|
|
115
|
-
content: '${config.welcome.leaveMessage || member.
|
|
115
|
+
content: '${config.welcome.leaveMessage || member.display_name + " has left the server."}'
|
|
116
116
|
}
|
|
117
117
|
]
|
|
118
118
|
}
|
|
@@ -245,7 +245,7 @@ var welcomeCanvasGenerators = {
|
|
|
245
245
|
},
|
|
246
246
|
{
|
|
247
247
|
type: "circle_image",
|
|
248
|
-
url: "${member.
|
|
248
|
+
url: "${member.avatar}",
|
|
249
249
|
x: 400,
|
|
250
250
|
y: 100,
|
|
251
251
|
radius: 64,
|
|
@@ -265,7 +265,7 @@ var welcomeCanvasGenerators = {
|
|
|
265
265
|
},
|
|
266
266
|
{
|
|
267
267
|
type: "text",
|
|
268
|
-
text: "${member.
|
|
268
|
+
text: "${member.display_name}",
|
|
269
269
|
x: 400,
|
|
270
270
|
y: 240,
|
|
271
271
|
font: 'bold 28px "Poppins", sans-serif',
|
|
@@ -274,7 +274,7 @@ var welcomeCanvasGenerators = {
|
|
|
274
274
|
},
|
|
275
275
|
{
|
|
276
276
|
type: "text",
|
|
277
|
-
text: "Member #${guild.
|
|
277
|
+
text: "Member #${guild.member_count}",
|
|
278
278
|
x: 400,
|
|
279
279
|
y: 275,
|
|
280
280
|
font: '16px "Poppins", sans-serif',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/welcome/index.ts"],"sourcesContent":["/**\n * Welcome builtin module\n * Handles member join/leave messages, auto-role assignment, and welcome images\n */\n\nimport type { FurlowSpec, CommandDefinition, EventHandler, CanvasGenerator } from '@furlow/schema';\n\nexport interface WelcomeConfig {\n /** Channel to send welcome messages */\n channel?: string;\n /** Welcome message template */\n message?: string;\n /** Embed for welcome messages */\n embed?: {\n title?: string;\n description?: string;\n color?: string;\n thumbnail?: string;\n image?: string;\n footer?: string;\n };\n /** Use welcome image */\n useImage?: boolean;\n /** Welcome image generator name */\n imageGenerator?: string;\n /** Roles to assign on join */\n autoRoles?: string[];\n /** Leave channel (defaults to welcome channel) */\n leaveChannel?: string;\n /** Leave message template */\n leaveMessage?: string;\n /** Leave embed */\n leaveEmbed?: {\n title?: string;\n description?: string;\n color?: string;\n };\n /** DM new members */\n dmNewMembers?: boolean;\n /** DM message */\n dmMessage?: string;\n}\n\nexport const welcomeEventHandlers: EventHandler[] = [\n {\n event: 'member_join',\n actions: [\n // Auto-role assignment\n {\n action: 'flow_if',\n condition: '${config.welcome.autoRoles && config.welcome.autoRoles.length > 0}',\n then: [\n {\n action: 'assign_role',\n user: '${member.id}',\n role: '${config.welcome.autoRoles}',\n },\n ],\n },\n // DM new member\n {\n action: 'flow_if',\n condition: '${config.welcome.dmNewMembers}',\n then: [\n {\n action: 'send_dm',\n user: '${member.id}',\n content: '${config.welcome.dmMessage || \"Welcome to \" + guild.name + \"!\"}',\n },\n ],\n },\n // Welcome message with image\n {\n action: 'flow_if',\n condition: '${config.welcome.useImage}',\n then: [\n {\n action: 'canvas_render',\n generator: '${config.welcome.imageGenerator || \"welcome_card\"}',\n context: {\n member: '${member}',\n guild: '${guild}',\n memberCount: '${guild.memberCount}',\n },\n as: 'welcomeImage',\n },\n {\n action: 'send_message',\n channel: '${config.welcome.channel}',\n content: '${config.welcome.message || \"Welcome to the server, \" + member.displayName + \"!\"}',\n files: [\n {\n attachment: '${welcomeImage}',\n name: 'welcome.png',\n },\n ],\n },\n ],\n else: [\n // Welcome message without image\n {\n action: 'flow_if',\n condition: '${config.welcome.embed}',\n then: [\n {\n action: 'send_message',\n channel: '${config.welcome.channel}',\n content: '${config.welcome.message}',\n embed: {\n title: '${config.welcome.embed.title || \"Welcome!\"}',\n description: '${config.welcome.embed.description || \"Welcome to \" + guild.name + \", \" + member.displayName + \"!\"}',\n color: '${config.welcome.embed.color || \"#5865f2\"}',\n thumbnail: '${config.welcome.embed.thumbnail || member.avatarURL}',\n footer: {\n text: '${config.welcome.embed.footer || \"Member #\" + guild.memberCount}',\n },\n },\n },\n ],\n else: [\n {\n action: 'send_message',\n channel: '${config.welcome.channel}',\n content: '${config.welcome.message || \"Welcome to the server, \" + member.displayName + \"!\"}',\n },\n ],\n },\n ],\n },\n ],\n },\n {\n event: 'member_leave',\n actions: [\n {\n action: 'flow_if',\n condition: '${config.welcome.leaveChannel || config.welcome.channel}',\n then: [\n {\n action: 'flow_if',\n condition: '${config.welcome.leaveEmbed}',\n then: [\n {\n action: 'send_message',\n channel: '${config.welcome.leaveChannel || config.welcome.channel}',\n embed: {\n title: '${config.welcome.leaveEmbed.title || \"Goodbye!\"}',\n description: '${config.welcome.leaveEmbed.description || member.displayName + \" has left the server.\"}',\n color: '${config.welcome.leaveEmbed.color || \"#ed4245\"}',\n },\n },\n ],\n else: [\n {\n action: 'send_message',\n channel: '${config.welcome.leaveChannel || config.welcome.channel}',\n content: '${config.welcome.leaveMessage || member.displayName + \" has left the server.\"}',\n },\n ],\n },\n ],\n },\n ],\n },\n];\n\nexport const welcomeCommands: CommandDefinition[] = [\n {\n name: 'welcome',\n description: 'Welcome system commands',\n subcommands: [\n {\n name: 'test',\n description: 'Test the welcome message',\n actions: [\n {\n action: 'emit',\n event: 'member_join',\n data: {\n member: '${member}',\n guild: '${guild}',\n },\n },\n {\n action: 'reply',\n content: 'Welcome message test triggered!',\n ephemeral: true,\n },\n ],\n },\n {\n name: 'set-channel',\n description: 'Set the welcome channel',\n options: [\n { name: 'channel', description: 'Channel for welcome messages', type: 'channel', required: true },\n ],\n actions: [\n {\n action: 'set',\n key: 'config.welcome.channel',\n value: '${args.channel.id}',\n scope: 'guild',\n },\n {\n action: 'reply',\n content: 'Welcome channel set to ${args.channel}',\n ephemeral: true,\n },\n ],\n },\n {\n name: 'set-message',\n description: 'Set the welcome message',\n options: [\n { name: 'message', description: 'Welcome message (use {member} and {guild})', type: 'string', required: true },\n ],\n actions: [\n {\n action: 'set',\n key: 'config.welcome.message',\n value: '${args.message}',\n scope: 'guild',\n },\n {\n action: 'reply',\n content: 'Welcome message updated!',\n ephemeral: true,\n },\n ],\n },\n {\n name: 'add-autorole',\n description: 'Add an auto-role',\n options: [\n { name: 'role', description: 'Role to assign on join', type: 'role', required: true },\n ],\n actions: [\n {\n action: 'list_push',\n key: 'config.welcome.autoRoles',\n value: '${args.role.id}',\n scope: 'guild',\n },\n {\n action: 'reply',\n content: 'Auto-role ${args.role.name} added!',\n ephemeral: true,\n },\n ],\n },\n {\n name: 'remove-autorole',\n description: 'Remove an auto-role',\n options: [\n { name: 'role', description: 'Role to remove', type: 'role', required: true },\n ],\n actions: [\n {\n action: 'list_remove',\n key: 'config.welcome.autoRoles',\n value: '${args.role.id}',\n scope: 'guild',\n },\n {\n action: 'reply',\n content: 'Auto-role ${args.role.name} removed!',\n ephemeral: true,\n },\n ],\n },\n ],\n },\n];\n\nexport const welcomeCanvasGenerators: Record<string, CanvasGenerator> = {\n welcome_card: {\n width: 800,\n height: 300,\n background: '#2f3136',\n layers: [\n {\n type: 'rect',\n x: 0,\n y: 0,\n width: 800,\n height: 300,\n color: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',\n radius: 16,\n },\n {\n type: 'circle_image',\n url: '${member.avatarURL || member.defaultAvatarURL}',\n x: 400,\n y: 100,\n radius: 64,\n border: {\n width: 4,\n color: '#ffffff',\n },\n },\n {\n type: 'text',\n text: 'Welcome!',\n x: 400,\n y: 200,\n font: '32px \"Poppins\", sans-serif',\n color: '#ffffff',\n align: 'center',\n },\n {\n type: 'text',\n text: '${member.displayName}',\n x: 400,\n y: 240,\n font: 'bold 28px \"Poppins\", sans-serif',\n color: '#ffffff',\n align: 'center',\n },\n {\n type: 'text',\n text: 'Member #${guild.memberCount}',\n x: 400,\n y: 275,\n font: '16px \"Poppins\", sans-serif',\n color: 'rgba(255, 255, 255, 0.8)',\n align: 'center',\n },\n ],\n },\n};\n\nexport function getWelcomeSpec(config: WelcomeConfig = {}): Partial<FurlowSpec> {\n return {\n events: welcomeEventHandlers,\n commands: welcomeCommands,\n canvas: {\n generators: welcomeCanvasGenerators,\n },\n };\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/welcome/index.ts"],"sourcesContent":["/**\n * Welcome builtin module\n * Handles member join/leave messages, auto-role assignment, and welcome images\n */\n\nimport type { FurlowSpec, CommandDefinition, EventHandler, CanvasGenerator } from '@furlow/schema';\n\nexport interface WelcomeConfig {\n /** Channel to send welcome messages */\n channel?: string;\n /** Welcome message template */\n message?: string;\n /** Embed for welcome messages */\n embed?: {\n title?: string;\n description?: string;\n color?: string;\n thumbnail?: string;\n image?: string;\n footer?: string;\n };\n /** Use welcome image */\n useImage?: boolean;\n /** Welcome image generator name */\n imageGenerator?: string;\n /** Roles to assign on join */\n autoRoles?: string[];\n /** Leave channel (defaults to welcome channel) */\n leaveChannel?: string;\n /** Leave message template */\n leaveMessage?: string;\n /** Leave embed */\n leaveEmbed?: {\n title?: string;\n description?: string;\n color?: string;\n };\n /** DM new members */\n dmNewMembers?: boolean;\n /** DM message */\n dmMessage?: string;\n}\n\nexport const welcomeEventHandlers: EventHandler[] = [\n {\n event: 'member_join',\n actions: [\n // Auto-role assignment\n {\n action: 'flow_if',\n condition: 'config.welcome.autoRoles && config.welcome.autoRoles.length > 0',\n then: [\n {\n action: 'assign_role',\n user: '${member.id}',\n role: '${config.welcome.autoRoles}',\n },\n ],\n },\n // DM new member\n {\n action: 'flow_if',\n condition: 'config.welcome.dmNewMembers',\n then: [\n {\n action: 'send_dm',\n user: '${member.id}',\n content: '${config.welcome.dmMessage || \"Welcome to \" + guild.name + \"!\"}',\n },\n ],\n },\n // Welcome message with image\n {\n action: 'flow_if',\n condition: 'config.welcome.useImage',\n then: [\n {\n action: 'canvas_render',\n generator: '${config.welcome.imageGenerator || \"welcome_card\"}',\n context: {\n member: '${member}',\n guild: '${guild}',\n memberCount: '${guild.member_count}',\n },\n as: 'welcomeImage',\n },\n {\n action: 'send_message',\n channel: '${config.welcome.channel}',\n content: '${config.welcome.message || \"Welcome to the server, \" + member.display_name + \"!\"}',\n files: [\n {\n attachment: '${welcomeImage}',\n name: 'welcome.png',\n },\n ],\n },\n ],\n else: [\n // Welcome message without image\n {\n action: 'flow_if',\n condition: 'config.welcome.embed',\n then: [\n {\n action: 'send_message',\n channel: '${config.welcome.channel}',\n content: '${config.welcome.message}',\n embed: {\n title: '${config.welcome.embed.title || \"Welcome!\"}',\n description: '${config.welcome.embed.description || \"Welcome to \" + guild.name + \", \" + member.display_name + \"!\"}',\n color: '${config.welcome.embed.color || \"#5865f2\"}',\n thumbnail: '${config.welcome.embed.thumbnail || member.avatar}',\n footer: {\n text: '${config.welcome.embed.footer || \"Member #\" + guild.member_count}',\n },\n },\n },\n ],\n else: [\n {\n action: 'send_message',\n channel: '${config.welcome.channel}',\n content: '${config.welcome.message || \"Welcome to the server, \" + member.display_name + \"!\"}',\n },\n ],\n },\n ],\n },\n ],\n },\n {\n event: 'member_leave',\n actions: [\n {\n action: 'flow_if',\n condition: 'config.welcome.leaveChannel || config.welcome.channel',\n then: [\n {\n action: 'flow_if',\n condition: 'config.welcome.leaveEmbed',\n then: [\n {\n action: 'send_message',\n channel: '${config.welcome.leaveChannel || config.welcome.channel}',\n embed: {\n title: '${config.welcome.leaveEmbed.title || \"Goodbye!\"}',\n description: '${config.welcome.leaveEmbed.description || member.display_name + \" has left the server.\"}',\n color: '${config.welcome.leaveEmbed.color || \"#ed4245\"}',\n },\n },\n ],\n else: [\n {\n action: 'send_message',\n channel: '${config.welcome.leaveChannel || config.welcome.channel}',\n content: '${config.welcome.leaveMessage || member.display_name + \" has left the server.\"}',\n },\n ],\n },\n ],\n },\n ],\n },\n];\n\nexport const welcomeCommands: CommandDefinition[] = [\n {\n name: 'welcome',\n description: 'Welcome system commands',\n subcommands: [\n {\n name: 'test',\n description: 'Test the welcome message',\n actions: [\n {\n action: 'emit',\n event: 'member_join',\n data: {\n member: '${member}',\n guild: '${guild}',\n },\n },\n {\n action: 'reply',\n content: 'Welcome message test triggered!',\n ephemeral: true,\n },\n ],\n },\n {\n name: 'set-channel',\n description: 'Set the welcome channel',\n options: [\n { name: 'channel', description: 'Channel for welcome messages', type: 'channel', required: true },\n ],\n actions: [\n {\n action: 'set',\n key: 'config.welcome.channel',\n value: '${args.channel.id}',\n scope: 'guild',\n },\n {\n action: 'reply',\n content: 'Welcome channel set to ${args.channel}',\n ephemeral: true,\n },\n ],\n },\n {\n name: 'set-message',\n description: 'Set the welcome message',\n options: [\n { name: 'message', description: 'Welcome message (use {member} and {guild})', type: 'string', required: true },\n ],\n actions: [\n {\n action: 'set',\n key: 'config.welcome.message',\n value: '${args.message}',\n scope: 'guild',\n },\n {\n action: 'reply',\n content: 'Welcome message updated!',\n ephemeral: true,\n },\n ],\n },\n {\n name: 'add-autorole',\n description: 'Add an auto-role',\n options: [\n { name: 'role', description: 'Role to assign on join', type: 'role', required: true },\n ],\n actions: [\n {\n action: 'list_push',\n key: 'config.welcome.autoRoles',\n value: '${args.role.id}',\n scope: 'guild',\n },\n {\n action: 'reply',\n content: 'Auto-role ${args.role.name} added!',\n ephemeral: true,\n },\n ],\n },\n {\n name: 'remove-autorole',\n description: 'Remove an auto-role',\n options: [\n { name: 'role', description: 'Role to remove', type: 'role', required: true },\n ],\n actions: [\n {\n action: 'list_remove',\n key: 'config.welcome.autoRoles',\n value: '${args.role.id}',\n scope: 'guild',\n },\n {\n action: 'reply',\n content: 'Auto-role ${args.role.name} removed!',\n ephemeral: true,\n },\n ],\n },\n ],\n },\n];\n\nexport const welcomeCanvasGenerators: Record<string, CanvasGenerator> = {\n welcome_card: {\n width: 800,\n height: 300,\n background: '#2f3136',\n layers: [\n {\n type: 'rect',\n x: 0,\n y: 0,\n width: 800,\n height: 300,\n color: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',\n radius: 16,\n },\n {\n type: 'circle_image',\n url: '${member.avatar}',\n x: 400,\n y: 100,\n radius: 64,\n border: {\n width: 4,\n color: '#ffffff',\n },\n },\n {\n type: 'text',\n text: 'Welcome!',\n x: 400,\n y: 200,\n font: '32px \"Poppins\", sans-serif',\n color: '#ffffff',\n align: 'center',\n },\n {\n type: 'text',\n text: '${member.display_name}',\n x: 400,\n y: 240,\n font: 'bold 28px \"Poppins\", sans-serif',\n color: '#ffffff',\n align: 'center',\n },\n {\n type: 'text',\n text: 'Member #${guild.member_count}',\n x: 400,\n y: 275,\n font: '16px \"Poppins\", sans-serif',\n color: 'rgba(255, 255, 255, 0.8)',\n align: 'center',\n },\n ],\n },\n};\n\nexport function getWelcomeSpec(config: WelcomeConfig = {}): Partial<FurlowSpec> {\n return {\n events: welcomeEventHandlers,\n commands: welcomeCommands,\n canvas: {\n generators: welcomeCanvasGenerators,\n },\n };\n}\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@furlow/builtins",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
4
4
|
"description": "Pre-built bot components for FURLOW framework",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"furlow",
|
|
@@ -87,9 +87,9 @@
|
|
|
87
87
|
"yaml"
|
|
88
88
|
],
|
|
89
89
|
"dependencies": {
|
|
90
|
-
"@furlow/
|
|
91
|
-
"@furlow/
|
|
92
|
-
"@furlow/schema": "1.0.
|
|
90
|
+
"@furlow/discord": "1.0.3",
|
|
91
|
+
"@furlow/core": "1.0.3",
|
|
92
|
+
"@furlow/schema": "1.0.3"
|
|
93
93
|
},
|
|
94
94
|
"devDependencies": {
|
|
95
95
|
"@types/node": "^20.11.0",
|