noot
This commit is contained in:
parent
97d85d7fc9
commit
e55886cd8f
@ -31,7 +31,7 @@ export async function update_wynn_items() {
|
||||
return
|
||||
}
|
||||
found_new = true
|
||||
log.info(`updating wynn with new hash`, { old: currenthash, new: dataHash })
|
||||
log.info('updating wynn with new hash', { old: currenthash, new: dataHash })
|
||||
for (const [displayName, item] of Object.entries(parsed)) {
|
||||
const json = stringify(item)
|
||||
if (!json) {
|
||||
|
||||
@ -27,7 +27,7 @@ select * from ranked
|
||||
where ranked.uid = ${guild_id}
|
||||
`
|
||||
|
||||
if (result.length == 0) {
|
||||
if (result.length === 0) {
|
||||
return {
|
||||
content: 'No guild found.',
|
||||
}
|
||||
@ -36,9 +36,9 @@ where ranked.uid = ${guild_id}
|
||||
const guild = result[0]
|
||||
|
||||
const output = [
|
||||
`# 🏰 Guild Information`,
|
||||
'# 🏰 Guild Information',
|
||||
`## **[${guild.prefix}] ${guild.name}**\n`,
|
||||
`### 📊 Statistics`,
|
||||
'### 📊 Statistics',
|
||||
`> **Level:** \`${guild.level}\``,
|
||||
`> **Total XP:** \`${formatNumber(guild.xp)}\``,
|
||||
`> **XP Rank:** \`#${guild.xp_rank >= 1000 ? '1000+' : guild.xp_rank}\``,
|
||||
@ -81,7 +81,7 @@ export async function formGuildOnlineMessage(guild_id: string): Promise<CreateMe
|
||||
.array()
|
||||
.assert(result)
|
||||
|
||||
if (members.length == 0) {
|
||||
if (members.length === 0) {
|
||||
return {
|
||||
content: '😴 No guild members are currently online.',
|
||||
}
|
||||
@ -97,7 +97,7 @@ export async function formGuildOnlineMessage(guild_id: string): Promise<CreateMe
|
||||
// Group members by server
|
||||
const membersByServer = members.reduce(
|
||||
(acc, member) => {
|
||||
if (acc[member.server] == undefined) {
|
||||
if (acc[member.server] === undefined) {
|
||||
acc[member.server] = []
|
||||
}
|
||||
acc[member.server].push(member)
|
||||
@ -122,7 +122,7 @@ export async function formGuildOnlineMessage(guild_id: string): Promise<CreateMe
|
||||
})
|
||||
|
||||
const output = [
|
||||
`# 🟢 Online Guild Members`,
|
||||
'# 🟢 Online Guild Members',
|
||||
`**[${guildPrefix}] ${guildName}**\n`,
|
||||
`📊 **Total Online:** \`${members.length}\` members across \`${sortedServers.length}\` servers\n`,
|
||||
...serverSections,
|
||||
@ -203,12 +203,12 @@ export async function formGuildLeaderboardMessage(guild_id: string): Promise<Cre
|
||||
const avgContribution = Math.floor(totalXP / members.length)
|
||||
|
||||
const output = [
|
||||
`# 📊 Guild XP Leaderboard`,
|
||||
'# 📊 Guild XP Leaderboard',
|
||||
`**[${guildPrefix}] ${guildName}**\n`,
|
||||
`📈 **Total Guild XP:** \`${totalXP.toLocaleString()}\``,
|
||||
`👥 **Total Members:** \`${members.length}\``,
|
||||
`📊 **Average Contribution:** \`${avgContribution.toLocaleString()}\`\n`,
|
||||
`### Top Contributors`,
|
||||
'### Top Contributors',
|
||||
'```',
|
||||
leaderboardTable,
|
||||
'```',
|
||||
|
||||
@ -100,7 +100,6 @@ export const scrape_online_players = async () => {
|
||||
log.warn(`failed to get uuid for ${playerName}`, {
|
||||
err: e,
|
||||
})
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -113,7 +112,6 @@ export const scrape_online_players = async () => {
|
||||
log.warn(`failed to update server for ${playerName}`, {
|
||||
err: e,
|
||||
})
|
||||
continue
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@ -4,7 +4,7 @@ import { c } from '#/di'
|
||||
|
||||
// di
|
||||
import '#/services/temporal'
|
||||
import path from 'path'
|
||||
import path from 'node:path'
|
||||
import { Client, ScheduleNotFoundError, type ScheduleOptions, ScheduleOverlapPolicy } from '@temporalio/client'
|
||||
import { NativeConnection, Worker } from '@temporalio/worker'
|
||||
import { PG } from '#/services/pg'
|
||||
@ -129,7 +129,7 @@ export class WorkerCommand extends Command {
|
||||
if (!config.resolve.alias) config.resolve.alias = {}
|
||||
config.resolve.alias = {
|
||||
'#': path.resolve(process.cwd(), 'src/'),
|
||||
...config.resolve!.alias,
|
||||
...config.resolve?.alias,
|
||||
}
|
||||
return config
|
||||
},
|
||||
|
||||
@ -111,27 +111,44 @@ const TEST_COMMANDS = [
|
||||
},
|
||||
] as const satisfies CreateApplicationCommand[]
|
||||
|
||||
// Helper function to create a mock handler structure with all required commands
|
||||
function createMockHandlers() {
|
||||
return {
|
||||
simple: vi.fn(),
|
||||
complex: {
|
||||
list: vi.fn(),
|
||||
create: vi.fn(),
|
||||
},
|
||||
admin: {
|
||||
user: {
|
||||
ban: vi.fn(),
|
||||
kick: vi.fn(),
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Helper function to create a complete test setup
|
||||
function createTestSetup() {
|
||||
const handlers = createMockHandlers()
|
||||
const notFoundHandler = vi.fn()
|
||||
|
||||
const handler = createCommandHandler<typeof TEST_COMMANDS>({
|
||||
commands: TEST_COMMANDS,
|
||||
handler: handlers,
|
||||
notFoundHandler,
|
||||
})
|
||||
|
||||
return {
|
||||
handlers,
|
||||
notFoundHandler,
|
||||
handler,
|
||||
}
|
||||
}
|
||||
|
||||
describe('createCommandHandler', () => {
|
||||
it('should handle a simple command with required string argument', async () => {
|
||||
const simpleHandler = vi.fn()
|
||||
const notFoundHandler = vi.fn()
|
||||
|
||||
const handler = createCommandHandler<typeof TEST_COMMANDS>({
|
||||
handler: {
|
||||
simple: simpleHandler,
|
||||
complex: {
|
||||
list: vi.fn(),
|
||||
create: vi.fn(),
|
||||
},
|
||||
admin: {
|
||||
user: {
|
||||
ban: vi.fn(),
|
||||
kick: vi.fn(),
|
||||
},
|
||||
},
|
||||
},
|
||||
notFoundHandler,
|
||||
})
|
||||
const { handlers, notFoundHandler, handler } = createTestSetup()
|
||||
|
||||
const interactionData: InteractionData = {
|
||||
name: 'simple',
|
||||
@ -140,31 +157,12 @@ describe('createCommandHandler', () => {
|
||||
|
||||
await handler(interactionData)
|
||||
|
||||
expect(simpleHandler).toHaveBeenCalledWith({ message: 'Hello world' })
|
||||
expect(handlers.simple).toHaveBeenCalledWith({ message: 'Hello world' })
|
||||
expect(notFoundHandler).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('should handle a simple command with optional arguments', async () => {
|
||||
const simpleHandler = vi.fn()
|
||||
const notFoundHandler = vi.fn()
|
||||
let a: ExtractCommands<typeof TEST_COMMANDS>
|
||||
|
||||
const handler = createCommandHandler<typeof TEST_COMMANDS>({
|
||||
handler: {
|
||||
simple: simpleHandler,
|
||||
complex: {
|
||||
list: vi.fn(),
|
||||
create: vi.fn(),
|
||||
},
|
||||
admin: {
|
||||
user: {
|
||||
ban: vi.fn(),
|
||||
kick: vi.fn(),
|
||||
},
|
||||
},
|
||||
},
|
||||
notFoundHandler,
|
||||
})
|
||||
const { handlers, handler } = createTestSetup()
|
||||
|
||||
const interactionData: InteractionData = {
|
||||
name: 'simple',
|
||||
@ -176,30 +174,11 @@ describe('createCommandHandler', () => {
|
||||
|
||||
await handler(interactionData)
|
||||
|
||||
expect(simpleHandler).toHaveBeenCalledWith({ message: 'Hello', count: 5 })
|
||||
expect(handlers.simple).toHaveBeenCalledWith({ message: 'Hello', count: 5 })
|
||||
})
|
||||
|
||||
it('should handle subcommands correctly', async () => {
|
||||
const listHandler = vi.fn()
|
||||
const createHandler = vi.fn()
|
||||
const notFoundHandler = vi.fn()
|
||||
|
||||
const handler = createCommandHandler<typeof TEST_COMMANDS>({
|
||||
handler: {
|
||||
simple: vi.fn(),
|
||||
complex: {
|
||||
list: listHandler,
|
||||
create: createHandler,
|
||||
},
|
||||
admin: {
|
||||
user: {
|
||||
ban: vi.fn(),
|
||||
kick: vi.fn(),
|
||||
},
|
||||
},
|
||||
},
|
||||
notFoundHandler,
|
||||
})
|
||||
const { handlers, notFoundHandler, handler } = createTestSetup()
|
||||
|
||||
const interactionData: InteractionData = {
|
||||
name: 'complex',
|
||||
@ -217,30 +196,13 @@ describe('createCommandHandler', () => {
|
||||
|
||||
await handler(interactionData)
|
||||
|
||||
expect(createHandler).toHaveBeenCalledWith({ name: 'Test Item', enabled: true })
|
||||
expect(listHandler).not.toHaveBeenCalled()
|
||||
expect(handlers.complex.create).toHaveBeenCalledWith({ name: 'Test Item', enabled: true })
|
||||
expect(handlers.complex.list).not.toHaveBeenCalled()
|
||||
expect(notFoundHandler).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('should call notFoundHandler for unknown commands', async () => {
|
||||
const notFoundHandler = vi.fn()
|
||||
|
||||
const handler = createCommandHandler<typeof TEST_COMMANDS>({
|
||||
handler: {
|
||||
simple: vi.fn(),
|
||||
complex: {
|
||||
list: vi.fn(),
|
||||
create: vi.fn(),
|
||||
},
|
||||
admin: {
|
||||
user: {
|
||||
ban: vi.fn(),
|
||||
kick: vi.fn(),
|
||||
},
|
||||
},
|
||||
},
|
||||
notFoundHandler,
|
||||
})
|
||||
const { notFoundHandler, handler } = createTestSetup()
|
||||
|
||||
const interactionData: InteractionData = {
|
||||
name: 'unknown',
|
||||
@ -253,24 +215,7 @@ describe('createCommandHandler', () => {
|
||||
})
|
||||
|
||||
it('should call notFoundHandler for unknown subcommands', async () => {
|
||||
const notFoundHandler = vi.fn()
|
||||
|
||||
const handler = createCommandHandler<typeof TEST_COMMANDS>({
|
||||
handler: {
|
||||
simple: vi.fn(),
|
||||
complex: {
|
||||
list: vi.fn(),
|
||||
create: vi.fn(),
|
||||
},
|
||||
admin: {
|
||||
user: {
|
||||
ban: vi.fn(),
|
||||
kick: vi.fn(),
|
||||
},
|
||||
},
|
||||
},
|
||||
notFoundHandler,
|
||||
})
|
||||
const { notFoundHandler, handler } = createTestSetup()
|
||||
|
||||
const interactionData: InteractionData = {
|
||||
name: 'complex',
|
||||
@ -289,24 +234,7 @@ describe('createCommandHandler', () => {
|
||||
})
|
||||
|
||||
it('should handle missing interaction data', async () => {
|
||||
const notFoundHandler = vi.fn()
|
||||
|
||||
const handler = createCommandHandler<typeof TEST_COMMANDS>({
|
||||
handler: {
|
||||
simple: vi.fn(),
|
||||
complex: {
|
||||
list: vi.fn(),
|
||||
create: vi.fn(),
|
||||
},
|
||||
admin: {
|
||||
user: {
|
||||
ban: vi.fn(),
|
||||
kick: vi.fn(),
|
||||
},
|
||||
},
|
||||
},
|
||||
notFoundHandler,
|
||||
})
|
||||
const { notFoundHandler, handler } = createTestSetup()
|
||||
|
||||
await handler(null as any)
|
||||
expect(notFoundHandler).toHaveBeenCalledWith({})
|
||||
@ -316,26 +244,7 @@ describe('createCommandHandler', () => {
|
||||
})
|
||||
|
||||
it('should handle subcommand groups recursively', async () => {
|
||||
const banHandler = vi.fn()
|
||||
const kickHandler = vi.fn()
|
||||
const notFoundHandler = vi.fn()
|
||||
|
||||
const handler = createCommandHandler<typeof TEST_COMMANDS>({
|
||||
handler: {
|
||||
simple: vi.fn(),
|
||||
complex: {
|
||||
list: vi.fn(),
|
||||
create: vi.fn(),
|
||||
},
|
||||
admin: {
|
||||
user: {
|
||||
ban: banHandler,
|
||||
kick: kickHandler,
|
||||
},
|
||||
},
|
||||
},
|
||||
notFoundHandler,
|
||||
})
|
||||
const { handlers, notFoundHandler, handler } = createTestSetup()
|
||||
|
||||
const interactionData: InteractionData = {
|
||||
name: 'admin',
|
||||
@ -359,30 +268,13 @@ describe('createCommandHandler', () => {
|
||||
|
||||
await handler(interactionData)
|
||||
|
||||
expect(banHandler).toHaveBeenCalledWith({ user: '123456789', reason: 'Spam' })
|
||||
expect(kickHandler).not.toHaveBeenCalled()
|
||||
expect(handlers.admin.user.ban).toHaveBeenCalledWith({ user: '123456789', reason: 'Spam' })
|
||||
expect(handlers.admin.user.kick).not.toHaveBeenCalled()
|
||||
expect(notFoundHandler).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('should handle commands without options', async () => {
|
||||
const simpleHandler = vi.fn()
|
||||
|
||||
const handler = createCommandHandler<typeof TEST_COMMANDS>({
|
||||
handler: {
|
||||
simple: simpleHandler,
|
||||
complex: {
|
||||
list: vi.fn(),
|
||||
create: vi.fn(),
|
||||
},
|
||||
admin: {
|
||||
user: {
|
||||
ban: vi.fn(),
|
||||
kick: vi.fn(),
|
||||
},
|
||||
},
|
||||
},
|
||||
notFoundHandler: vi.fn(),
|
||||
})
|
||||
const { handlers, handler } = createTestSetup()
|
||||
|
||||
const interactionData: InteractionData = {
|
||||
name: 'simple',
|
||||
@ -391,28 +283,11 @@ describe('createCommandHandler', () => {
|
||||
|
||||
await handler(interactionData)
|
||||
|
||||
expect(simpleHandler).toHaveBeenCalledWith({})
|
||||
expect(handlers.simple).toHaveBeenCalledWith({})
|
||||
})
|
||||
|
||||
it('should ignore subcommand options when parsing top-level args', async () => {
|
||||
const simpleHandler = vi.fn()
|
||||
|
||||
const handler = createCommandHandler<typeof TEST_COMMANDS>({
|
||||
handler: {
|
||||
simple: simpleHandler,
|
||||
complex: {
|
||||
list: vi.fn(),
|
||||
create: vi.fn(),
|
||||
},
|
||||
admin: {
|
||||
user: {
|
||||
ban: vi.fn(),
|
||||
kick: vi.fn(),
|
||||
},
|
||||
},
|
||||
},
|
||||
notFoundHandler: vi.fn(),
|
||||
})
|
||||
const { handlers, handler } = createTestSetup()
|
||||
|
||||
const interactionData: InteractionData = {
|
||||
name: 'simple',
|
||||
@ -425,7 +300,7 @@ describe('createCommandHandler', () => {
|
||||
|
||||
await handler(interactionData)
|
||||
|
||||
expect(simpleHandler).toHaveBeenCalledWith({ message: 'Hello' })
|
||||
expect(handlers.simple).toHaveBeenCalledWith({ message: 'Hello' })
|
||||
})
|
||||
})
|
||||
|
||||
@ -482,6 +357,7 @@ describe('ExtractCommands type utility', () => {
|
||||
it('should infer types correctly without manual typing', () => {
|
||||
// This test verifies that args are inferred correctly without manual type annotations
|
||||
const handler = createCommandHandler<typeof TEST_COMMANDS>({
|
||||
commands: TEST_COMMANDS,
|
||||
notFoundHandler: async () => {},
|
||||
handler: {
|
||||
simple: async (args) => {
|
||||
@ -551,7 +427,9 @@ describe('ExtractCommands type utility', () => {
|
||||
expect(handlers).toBeDefined()
|
||||
})
|
||||
|
||||
it('should handle different option types', () => {
|
||||
it('should handle different option types', async () => {
|
||||
const { type } = await import('arktype')
|
||||
|
||||
const TYPE_TEST_COMMANDS = [
|
||||
{
|
||||
name: 'types',
|
||||
@ -573,31 +451,54 @@ describe('ExtractCommands type utility', () => {
|
||||
|
||||
type TypeHandlers = ExtractCommands<typeof TYPE_TEST_COMMANDS>
|
||||
|
||||
// Define arktype validators for each expected type
|
||||
const argsValidator = type({
|
||||
str: 'string',
|
||||
int: 'number.integer',
|
||||
bool: 'boolean',
|
||||
user: 'string', // User IDs are strings
|
||||
channel: 'string', // Channel IDs are strings
|
||||
role: 'string', // Role IDs are strings
|
||||
num: 'number',
|
||||
mention: 'string', // Mentionable IDs are strings
|
||||
attach: 'string', // Attachment IDs are strings
|
||||
})
|
||||
|
||||
const handlers: TypeHandlers = {
|
||||
types: async (args) => {
|
||||
// Test that all types are correctly mapped
|
||||
const str: string = args.str
|
||||
const int: number = args.int
|
||||
const bool: boolean = args.bool
|
||||
const user: string = args.user
|
||||
const channel: string = args.channel
|
||||
const role: string = args.role
|
||||
const num: number = args.num
|
||||
const mention: string = args.mention
|
||||
const attach: string = args.attach
|
||||
|
||||
expect(str).toBeDefined()
|
||||
expect(int).toBeDefined()
|
||||
expect(bool).toBeDefined()
|
||||
expect(user).toBeDefined()
|
||||
expect(channel).toBeDefined()
|
||||
expect(role).toBeDefined()
|
||||
expect(num).toBeDefined()
|
||||
expect(mention).toBeDefined()
|
||||
expect(attach).toBeDefined()
|
||||
// Validate the args using arktype
|
||||
const result = argsValidator(args)
|
||||
|
||||
// Check if validation passed (result is the validated object, not wrapped)
|
||||
if (result instanceof type.errors) {
|
||||
expect.fail(`Validation failed: ${result.summary}`)
|
||||
} else {
|
||||
// Test that all types are correctly mapped
|
||||
expect(typeof result.str).toBe('string')
|
||||
expect(typeof result.int).toBe('number')
|
||||
expect(Number.isInteger(result.int)).toBe(true)
|
||||
expect(typeof result.bool).toBe('boolean')
|
||||
expect(typeof result.user).toBe('string')
|
||||
expect(typeof result.channel).toBe('string')
|
||||
expect(typeof result.role).toBe('string')
|
||||
expect(typeof result.num).toBe('number')
|
||||
expect(typeof result.mention).toBe('string')
|
||||
expect(typeof result.attach).toBe('string')
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
expect(handlers).toBeDefined()
|
||||
// Test with actual values
|
||||
await handlers.types({
|
||||
str: 'hello',
|
||||
int: 42,
|
||||
bool: true,
|
||||
user: '123456789',
|
||||
channel: '987654321',
|
||||
role: '555555555',
|
||||
num: 3.14,
|
||||
mention: '111111111',
|
||||
attach: '999999999',
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -1,5 +1,9 @@
|
||||
import { ApplicationCommandOptionTypes, DiscordApplicationCommandOption, type CreateApplicationCommand, type DiscordInteractionDataOption } from '@discordeno/types'
|
||||
import type { InteractionData } from '..'
|
||||
import { ApplicationCommandOptionTypes } from '@discordeno/types'
|
||||
import type {CreateApplicationCommand,
|
||||
DiscordInteractionDataOption,
|
||||
DiscordInteractionData,
|
||||
DiscordApplicationCommandOption
|
||||
}from '@discordeno/types'
|
||||
import type { SLASH_COMMANDS } from './slash_commands'
|
||||
|
||||
// Map option types to their TypeScript types
|
||||
@ -21,12 +25,12 @@ type GetOption<Options, Name> = Options extends readonly DiscordApplicationComma
|
||||
// Extract the argument types from command options
|
||||
export type ExtractArgs<Options extends readonly DiscordApplicationCommandOption[]> = {
|
||||
[K in Options[number]['name']]: GetOption<Options, K> extends { type: infer T; required?: infer R }
|
||||
? T extends keyof OptionTypeMap
|
||||
? R extends true
|
||||
? OptionTypeMap[T]
|
||||
: OptionTypeMap[T] | undefined
|
||||
: never
|
||||
: never
|
||||
? T extends keyof OptionTypeMap
|
||||
? R extends true
|
||||
? OptionTypeMap[T]
|
||||
: OptionTypeMap[T] | undefined
|
||||
: never
|
||||
: never
|
||||
}
|
||||
|
||||
// Handler function type that accepts typed arguments
|
||||
@ -36,36 +40,36 @@ type HandlerFunction<Args = Record<string, never>> = (args: Args) => Promise<voi
|
||||
|
||||
// Get subcommand or subcommand group by name
|
||||
type GetSubcommandOrGroup<Options, Name> = Options extends readonly DiscordApplicationCommandOption[]
|
||||
? Options[number] extends infer O
|
||||
? O extends { name: Name; type: ApplicationCommandOptionTypes.SubCommand | ApplicationCommandOptionTypes.SubCommandGroup }
|
||||
? O
|
||||
: never
|
||||
: never
|
||||
: never
|
||||
? Options[number] extends infer O
|
||||
? O extends { name: Name; type: ApplicationCommandOptionTypes.SubCommand | ApplicationCommandOptionTypes.SubCommandGroup }
|
||||
? O
|
||||
: never
|
||||
: never
|
||||
: never
|
||||
|
||||
// Check if all options are subcommands or subcommand groups
|
||||
type HasOnlySubcommands<Options extends readonly DiscordApplicationCommandOption[]> = Options[number] extends { type: ApplicationCommandOptionTypes.SubCommand | ApplicationCommandOptionTypes.SubCommandGroup } ? true : false
|
||||
|
||||
// Extract subcommand or subcommand group names from options
|
||||
type SubcommandNames<Options extends readonly DiscordApplicationCommandOption[]> = Options[number] extends { name: infer N; type: ApplicationCommandOptionTypes.SubCommand | ApplicationCommandOptionTypes.SubCommandGroup }
|
||||
? N extends string
|
||||
? N
|
||||
: never
|
||||
: never
|
||||
? N extends string
|
||||
? N
|
||||
: never
|
||||
: never
|
||||
|
||||
// Type to extract subcommand handlers (recursive for groups)
|
||||
export type SubcommandHandlers<Options extends readonly DiscordApplicationCommandOption[]> = {
|
||||
[K in SubcommandNames<Options>]: GetSubcommandOrGroup<Options, K> extends { type: infer T; options?: infer SubOpts }
|
||||
? T extends ApplicationCommandOptionTypes.SubCommandGroup
|
||||
? SubOpts extends readonly DiscordApplicationCommandOption[]
|
||||
? SubcommandHandlers<SubOpts>
|
||||
: never
|
||||
: T extends ApplicationCommandOptionTypes.SubCommand
|
||||
? SubOpts extends readonly DiscordApplicationCommandOption[]
|
||||
? HandlerFunction<ExtractArgs<SubOpts>>
|
||||
: HandlerFunction<Record<string, never>>
|
||||
: never
|
||||
: never
|
||||
? T extends ApplicationCommandOptionTypes.SubCommandGroup
|
||||
? SubOpts extends readonly DiscordApplicationCommandOption[]
|
||||
? SubcommandHandlers<SubOpts>
|
||||
: never
|
||||
: T extends ApplicationCommandOptionTypes.SubCommand
|
||||
? SubOpts extends readonly DiscordApplicationCommandOption[]
|
||||
? HandlerFunction<ExtractArgs<SubOpts>>
|
||||
: HandlerFunction<Record<string, never>>
|
||||
: never
|
||||
: never
|
||||
}
|
||||
|
||||
// Get command by name from array
|
||||
@ -74,12 +78,12 @@ type GetCommand<Commands extends readonly any[], Name> = Commands[number] extend
|
||||
// Main type to extract command handlers from slash commands
|
||||
export type ExtractCommands<T extends readonly CreateApplicationCommand[]> = {
|
||||
[Name in T[number]['name']]: GetCommand<T, Name> extends { options?: infer Options }
|
||||
? Options extends readonly DiscordApplicationCommandOption[]
|
||||
? HasOnlySubcommands<Options> extends true
|
||||
? SubcommandHandlers<Options>
|
||||
: HandlerFunction<ExtractArgs<Options>>
|
||||
: HandlerFunction<Record<string, never>>
|
||||
: HandlerFunction<Record<string, never>>
|
||||
? Options extends readonly DiscordApplicationCommandOption[]
|
||||
? HasOnlySubcommands<Options> extends true
|
||||
? SubcommandHandlers<Options>
|
||||
: HandlerFunction<ExtractArgs<Options>>
|
||||
: HandlerFunction<Record<string, never>>
|
||||
: HandlerFunction<Record<string, never>>
|
||||
}
|
||||
|
||||
// Type representing the possible output of ExtractCommands
|
||||
@ -149,11 +153,11 @@ export function createCommandHandler<T extends readonly CreateApplicationCommand
|
||||
handler,
|
||||
notFoundHandler,
|
||||
}: {
|
||||
commands: T,
|
||||
handler: ExtractCommands<T>
|
||||
notFoundHandler: HandlerFunction<{path?: string}>
|
||||
}) {
|
||||
return async (data: InteractionData): Promise<void> => {
|
||||
commands: T,
|
||||
handler: ExtractCommands<T>
|
||||
notFoundHandler: HandlerFunction<{path?: string}>
|
||||
}) {
|
||||
return async (data: DiscordInteractionData): Promise<void> => {
|
||||
if (!data || !data.name) {
|
||||
await notFoundHandler({})
|
||||
return
|
||||
|
||||
@ -2,7 +2,7 @@ import { ApplicationCommandOptionTypes, ApplicationCommandTypes, type CreateAppl
|
||||
|
||||
export const SLASH_COMMANDS = [
|
||||
{
|
||||
name: `guild`,
|
||||
name: 'guild',
|
||||
description: 'guild commands',
|
||||
type: ApplicationCommandTypes.ChatInput,
|
||||
options: [
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import { Intents, type InteractionTypes } from '@discordeno/types'
|
||||
import type { DiscordInteractionData} from '@discordeno/types'
|
||||
import type { Bot, CompleteDesiredProperties, DesiredPropertiesBehavior } from 'discordeno'
|
||||
export const intents = [
|
||||
Intents.GuildModeration,
|
||||
@ -56,11 +57,8 @@ export interface InteractionRef {
|
||||
acknowledged?: boolean
|
||||
}
|
||||
|
||||
// Type for the interaction data payload
|
||||
export type InteractionData = Parameters<NonNullable<BotType['events']['interactionCreate']>>[0]['data']
|
||||
|
||||
// Type for the complete interaction handling payload
|
||||
export interface InteractionCreatePayload {
|
||||
ref: InteractionRef
|
||||
data: InteractionData
|
||||
data: DiscordInteractionData
|
||||
}
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
import { c } from '#/di'
|
||||
|
||||
export class EventMux {
|
||||
constructor() {}
|
||||
}
|
||||
|
||||
@ -6,10 +6,10 @@ export class TabWriter {
|
||||
}
|
||||
|
||||
add(row: string[]) {
|
||||
if (this.columns.length == 0) {
|
||||
if (this.columns.length === 0) {
|
||||
this.columns = new Array(row.length).fill(0).map(() => [])
|
||||
}
|
||||
if (row.length != this.columns.length) {
|
||||
if (row.length !== this.columns.length) {
|
||||
throw new Error(`Row length ${row.length} does not match columns length ${this.columns.length}`)
|
||||
}
|
||||
for (let i = 0; i < row.length; i++) {
|
||||
@ -19,7 +19,7 @@ export class TabWriter {
|
||||
|
||||
build() {
|
||||
let out = ''
|
||||
if (this.columns.length == 0) {
|
||||
if (this.columns.length === 0) {
|
||||
return ''
|
||||
}
|
||||
const columnWidths = this.columns.map((col) => col.reduce((a, b) => Math.max(a, b.length + this.spacing), 0))
|
||||
|
||||
@ -42,7 +42,7 @@ export class WApi {
|
||||
: // When a stale state has a determined value to expire, we can use it.
|
||||
// Or if the cached value cannot enter in stale state.
|
||||
(value.state === 'stale' && value.ttl) || (value.state === 'cached' && !canStale(value))
|
||||
? value.createdAt + value.ttl!
|
||||
? value.createdAt + (value.ttl || 0)
|
||||
: // otherwise, we can't determine when it should expire, so we keep
|
||||
// it indefinitely.
|
||||
undefined
|
||||
|
||||
@ -12,7 +12,7 @@ export class SuperJsonPayloadConverter implements PayloadConverterWithEncoding {
|
||||
|
||||
public toPayload(value: unknown): Payload | undefined {
|
||||
if (value === undefined) return undefined
|
||||
let ejson
|
||||
let ejson: any
|
||||
try {
|
||||
ejson = superjson.stringify(value)
|
||||
} catch (e) {
|
||||
|
||||
@ -26,13 +26,13 @@ const workflowHandleApplicationCommand = async (payload: InteractionCreatePayloa
|
||||
})
|
||||
}
|
||||
if (!data || !data.name) {
|
||||
await notFoundHandler(`Invalid command data`)
|
||||
await notFoundHandler('Invalid command data')
|
||||
return
|
||||
}
|
||||
const commandHandler = createCommandHandler({
|
||||
commands: SLASH_COMMANDS,
|
||||
notFoundHandler: async () => {
|
||||
await notFoundHandler(`command not found`)
|
||||
await notFoundHandler('command not found')
|
||||
},
|
||||
handler: {
|
||||
player: {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user