noot
This commit is contained in:
parent
a43c1959c0
commit
542070a4cb
Binary file not shown.
@ -49,7 +49,7 @@
|
|||||||
"pino": "^9.6.0",
|
"pino": "^9.6.0",
|
||||||
"pino-logfmt": "^0.1.1",
|
"pino-logfmt": "^0.1.1",
|
||||||
"pino-pretty": "^13.0.0",
|
"pino-pretty": "^13.0.0",
|
||||||
"postgres": "^3.4.5",
|
"postgres": "^3.4.7",
|
||||||
"superjson": "^2.2.2",
|
"superjson": "^2.2.2",
|
||||||
"ts-markdown-builder": "^0.4.0",
|
"ts-markdown-builder": "^0.4.0",
|
||||||
"why-is-node-running": "^3.2.2",
|
"why-is-node-running": "^3.2.2",
|
||||||
|
|||||||
@ -1,12 +1,13 @@
|
|||||||
import { type InteractionCallbackData, type InteractionCallbackOptions, MessageFlags } from 'discordeno'
|
import { type InteractionCallbackData, type InteractionCallbackOptions, MessageFlags } from 'discordeno'
|
||||||
import { c } from '#/di'
|
import { c } from '#/di'
|
||||||
import type { InteractionRef } from '#/discord'
|
import type { InteractionRef } from '#/discord'
|
||||||
|
import { InteractionResponseTypes } from '@discordeno/types'
|
||||||
import { Bot } from '#/discord/bot'
|
import { Bot } from '#/discord/bot'
|
||||||
|
|
||||||
// from https://github.com/discordeno/discordeno/blob/21.0.0/packages/bot/src/transformers/interaction.ts#L33
|
// from https://github.com/discordeno/discordeno/blob/21.0.0/packages/bot/src/transformers/interaction.ts#L33
|
||||||
export const reply_to_interaction = async (props: {
|
export const reply_to_interaction = async (props: {
|
||||||
ref: InteractionRef
|
ref: InteractionRef
|
||||||
type: number
|
type: InteractionResponseTypes
|
||||||
options?: InteractionCallbackOptions & { isPrivate?: boolean; content?: string }
|
options?: InteractionCallbackOptions & { isPrivate?: boolean; content?: string }
|
||||||
}) => {
|
}) => {
|
||||||
const bot = await c.getAsync(Bot)
|
const bot = await c.getAsync(Bot)
|
||||||
@ -19,9 +20,16 @@ export const reply_to_interaction = async (props: {
|
|||||||
data.flags = MessageFlags.Ephemeral
|
data.flags = MessageFlags.Ephemeral
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ref.acknowledged) {
|
switch (type) {
|
||||||
return await bot.helpers.sendFollowupMessage(ref.token, data)
|
case InteractionResponseTypes.UpdateMessage:
|
||||||
|
if(ref.acknowledged) {
|
||||||
|
return await bot.helpers.editOriginalInteractionResponse(ref.token, data)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
if (ref.acknowledged) {
|
||||||
|
const followUp = await bot.helpers.sendFollowupMessage(ref.token, data)
|
||||||
|
return followUp
|
||||||
|
}
|
||||||
|
return await bot.helpers.sendInteractionResponse(ref.id, ref.token, { type, data }, { withResponse: options?.withResponse })
|
||||||
}
|
}
|
||||||
|
|
||||||
return await bot.helpers.sendInteractionResponse(ref.id, ref.token, { type, data }, { withResponse: options?.withResponse })
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,35 +1,43 @@
|
|||||||
import { c } from '#/di'
|
import { c } from '#/di'
|
||||||
import { PG } from '#/services/pg'
|
import { PG } from '#/services/pg'
|
||||||
import { DiscordGuildSettingsService, DISCORD_GUILD_SETTING_KEYS } from '#/services/guild_settings'
|
import { DiscordGuildSettingsService, DiscordGuildSettingKey, DiscordGuildSettingValue } from '#/services/guild_settings'
|
||||||
import { logger } from '#/logger'
|
import { logger } from '#/logger'
|
||||||
|
|
||||||
export interface SetDiscordGuildSettingParams<T> {
|
export interface SetDiscordGuildSettingParams<K extends DiscordGuildSettingKey> {
|
||||||
discordGuildId: bigint
|
guildId: bigint
|
||||||
key: string
|
key: K
|
||||||
value: T
|
value: DiscordGuildSettingValue<K>
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function set_discord_guild_setting<T>(params: SetDiscordGuildSettingParams<T>): Promise<void> {
|
export async function set_discord_guild_setting<K extends DiscordGuildSettingKey>(
|
||||||
|
params: SetDiscordGuildSettingParams<K>
|
||||||
|
): Promise<void> {
|
||||||
const settingsService = await c.getAsync(DiscordGuildSettingsService)
|
const settingsService = await c.getAsync(DiscordGuildSettingsService)
|
||||||
|
|
||||||
await settingsService.setSetting(params.discordGuildId, params.key, params.value)
|
await settingsService.setSetting(params.guildId, params.key, params.value)
|
||||||
|
|
||||||
logger.info({
|
logger.info({
|
||||||
discordGuildId: params.discordGuildId,
|
guildId: params.guildId,
|
||||||
key: params.key,
|
key: params.key,
|
||||||
}, 'discord guild setting updated')
|
}, 'discord guild setting updated')
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function get_discord_guild_setting<T>(discordGuildId: bigint, key: string): Promise<T | null> {
|
export async function get_discord_guild_setting<K extends DiscordGuildSettingKey>(
|
||||||
|
guildId: bigint,
|
||||||
|
key: K
|
||||||
|
): Promise<DiscordGuildSettingValue<K> | null> {
|
||||||
const settingsService = await c.getAsync(DiscordGuildSettingsService)
|
const settingsService = await c.getAsync(DiscordGuildSettingsService)
|
||||||
|
|
||||||
return await settingsService.getSetting<T>(discordGuildId, key)
|
return await settingsService.getSetting(guildId, key)
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function delete_discord_guild_setting(discordGuildId: bigint, key: string): Promise<boolean> {
|
export async function delete_discord_guild_setting(
|
||||||
|
guildId: bigint,
|
||||||
|
key: DiscordGuildSettingKey
|
||||||
|
): Promise<boolean> {
|
||||||
const settingsService = await c.getAsync(DiscordGuildSettingsService)
|
const settingsService = await c.getAsync(DiscordGuildSettingsService)
|
||||||
|
|
||||||
return await settingsService.deleteSetting(discordGuildId, key)
|
return await settingsService.deleteSetting(guildId, key)
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function get_wynn_guild_info(guildNameOrTag: string): Promise<{ uid: string; name: string; prefix: string } | null> {
|
export async function get_wynn_guild_info(guildNameOrTag: string): Promise<{ uid: string; name: string; prefix: string } | null> {
|
||||||
|
|||||||
@ -2,12 +2,27 @@ import { InjectionToken } from '@needle-di/core'
|
|||||||
import { createBot } from 'discordeno'
|
import { createBot } from 'discordeno'
|
||||||
import { config } from '#/config'
|
import { config } from '#/config'
|
||||||
import { c } from '#/di'
|
import { c } from '#/di'
|
||||||
import { type BotType, createBotParameters } from './index'
|
import { logger } from '#/logger'
|
||||||
|
import { type BotType, desiredProperties, intents } from './index'
|
||||||
|
|
||||||
const createBotWithToken = (token: string) => {
|
const createBotWithToken = (token: string) => {
|
||||||
return createBot({
|
return createBot({
|
||||||
...createBotParameters,
|
intents: intents.reduce((acc, curr) => acc | curr, 1 as any),
|
||||||
|
desiredProperties,
|
||||||
token,
|
token,
|
||||||
|
loggerFactory: (name: 'REST' | 'GATEWAY' | 'BOT') => {
|
||||||
|
// Create a child logger with the component name
|
||||||
|
const childLogger = logger.child({ component: `discordeno-${name.toLowerCase()}` })
|
||||||
|
|
||||||
|
// Return logger object with required methods
|
||||||
|
return {
|
||||||
|
debug: (message: string, ...args: any[]) => childLogger.debug({ args }, message),
|
||||||
|
info: (message: string, ...args: any[]) => childLogger.info({ args }, message),
|
||||||
|
warn: (message: string, ...args: any[]) => childLogger.warn({ args }, message),
|
||||||
|
error: (message: string, ...args: any[]) => childLogger.error({ args }, message),
|
||||||
|
fatal: (message: string, ...args: any[]) => childLogger.fatal({ args }, message),
|
||||||
|
}
|
||||||
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
export const Bot = new InjectionToken<BotType>('DISCORD_BOT')
|
export const Bot = new InjectionToken<BotType>('DISCORD_BOT')
|
||||||
|
|||||||
@ -31,6 +31,8 @@ export const events = () => {
|
|||||||
token: interaction.token,
|
token: interaction.token,
|
||||||
type: interaction.type,
|
type: interaction.type,
|
||||||
acknowledged: interaction.acknowledged,
|
acknowledged: interaction.acknowledged,
|
||||||
|
guildId: interaction.guildId,
|
||||||
|
channelId: interaction.channel.id || interaction.channelId,
|
||||||
},
|
},
|
||||||
data,
|
data,
|
||||||
},
|
},
|
||||||
@ -59,5 +61,5 @@ export const events = () => {
|
|||||||
],
|
],
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
} as BotType['events']
|
} as const satisfies BotType['events']
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { Intents, type InteractionTypes } from '@discordeno/types'
|
import { Intents, type InteractionTypes } from '@discordeno/types'
|
||||||
import type { Bot, CompleteDesiredProperties, DesiredPropertiesBehavior, DiscordInteractionContextType, Guild, Interaction, InteractionData, Member, Message } from 'discordeno'
|
import type { Bot, CompleteDesiredProperties, DesiredPropertiesBehavior, DiscordInteractionContextType, InteractionData, RecursivePartial, TransformersDesiredProperties } from 'discordeno'
|
||||||
export const intents = [
|
export const intents = [
|
||||||
Intents.GuildModeration,
|
Intents.GuildModeration,
|
||||||
Intents.GuildWebhooks,
|
Intents.GuildWebhooks,
|
||||||
@ -18,68 +18,61 @@ export const intents = [
|
|||||||
Intents.GuildMessages,
|
Intents.GuildMessages,
|
||||||
] as const
|
] as const
|
||||||
|
|
||||||
|
|
||||||
|
export const desiredProperties = {
|
||||||
|
interaction: {
|
||||||
|
id: true,
|
||||||
|
data: true,
|
||||||
|
type: true,
|
||||||
|
token: true,
|
||||||
|
message: true,
|
||||||
|
channelId: true,
|
||||||
|
channel: true,
|
||||||
|
guildId: true,
|
||||||
|
guild: true,
|
||||||
|
user: true,
|
||||||
|
member: true,
|
||||||
|
context: true,
|
||||||
|
},
|
||||||
|
message: {
|
||||||
|
id: true,
|
||||||
|
member: true,
|
||||||
|
guildId: true,
|
||||||
|
},
|
||||||
|
} as const satisfies RecursivePartial<TransformersDesiredProperties>
|
||||||
|
|
||||||
|
export type DesiredProperties = typeof desiredProperties
|
||||||
|
|
||||||
export const createBotParameters = {
|
export const createBotParameters = {
|
||||||
intents: intents.reduce((acc, curr) => acc | curr, Intents.Guilds),
|
intents: intents.reduce((acc, curr) => acc | curr, Intents.Guilds),
|
||||||
desiredProperties: {
|
desiredProperties,
|
||||||
interaction: {
|
|
||||||
id: true,
|
|
||||||
data: true,
|
|
||||||
type: true,
|
|
||||||
token: true,
|
|
||||||
message: true,
|
|
||||||
channelId: true,
|
|
||||||
channel: true,
|
|
||||||
guildId: true,
|
|
||||||
guild: true,
|
|
||||||
user: true,
|
|
||||||
member: true,
|
|
||||||
},
|
|
||||||
message: {
|
|
||||||
id: true,
|
|
||||||
member: true,
|
|
||||||
guildId: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
} as const
|
} as const
|
||||||
|
|
||||||
// Extract the type of desired properties from our parameters
|
export type BotType = Bot<CompleteDesiredProperties<DesiredProperties>, DesiredPropertiesBehavior.RemoveKey>
|
||||||
type ExtractedDesiredProperties = typeof createBotParameters.desiredProperties
|
|
||||||
|
|
||||||
// The BotType uses the CompleteDesiredProperties helper to fill in the missing properties
|
|
||||||
export type BotType = Bot<CompleteDesiredProperties<ExtractedDesiredProperties>, DesiredPropertiesBehavior.RemoveKey>
|
|
||||||
|
|
||||||
// Type for the interaction reference passed to workflows/activities
|
// Type for the interaction reference passed to workflows/activities
|
||||||
export interface InteractionRef {
|
export interface InteractionRef {
|
||||||
|
// id of the interaction
|
||||||
id: bigint
|
id: bigint
|
||||||
|
/** A continuation token for responding to the interaction */
|
||||||
token: string
|
token: string
|
||||||
type: InteractionTypes
|
type: InteractionTypes
|
||||||
acknowledged?: boolean
|
acknowledged?: boolean
|
||||||
/** Id of the application this interaction is for */
|
|
||||||
applicationId: bigint;
|
|
||||||
/** Guild that the interaction was sent from */
|
|
||||||
/** The guild it was sent from */
|
/** The guild it was sent from */
|
||||||
guildId: bigint;
|
guildId?: bigint;
|
||||||
/**
|
channelId?: bigint;
|
||||||
* The ID of channel it was sent from
|
|
||||||
*
|
|
||||||
* @remarks
|
|
||||||
* It is recommended that you begin using this channel field to identify the source channel of the interaction as they may deprecate the existing channel_id field in the future.
|
|
||||||
*/
|
|
||||||
channelId: bigint;
|
|
||||||
/** Guild member data for the invoking user, including permissions */
|
/** Guild member data for the invoking user, including permissions */
|
||||||
memberId?: bigint ;
|
memberId?: bigint ;
|
||||||
/** User object for the invoking user, if invoked in a DM */
|
/** User object for the invoking user, if invoked in a DM */
|
||||||
userId?: bigint;
|
userId?: bigint;
|
||||||
/** A continuation token for responding to the interaction */
|
|
||||||
/** Read-only property, always `1` */
|
|
||||||
version: 1;
|
|
||||||
/** For the message the button was attached to */
|
/** For the message the button was attached to */
|
||||||
messageId?: bigint;
|
messageId?: bigint;
|
||||||
|
|
||||||
|
// locale of the interaction
|
||||||
locale?: string;
|
locale?: string;
|
||||||
/** The guild's preferred locale, if invoked in a guild */
|
/** The guild's preferred locale, if invoked in a guild */
|
||||||
guildLocale?: string;
|
guildLocale?: string;
|
||||||
/** The computed permissions for a bot or app in the context of a specific interaction (including channel overwrites) */
|
|
||||||
appPermissions: bigint;
|
|
||||||
/** Context where the interaction was triggered from */
|
/** Context where the interaction was triggered from */
|
||||||
context?: DiscordInteractionContextType;
|
context?: DiscordInteractionContextType;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,6 +3,8 @@ import { c } from '#/di'
|
|||||||
import { PG } from '#/services/pg'
|
import { PG } from '#/services/pg'
|
||||||
import { logger } from '#/logger'
|
import { logger } from '#/logger'
|
||||||
import { JSONValue } from 'postgres'
|
import { JSONValue } from 'postgres'
|
||||||
|
import { snowflake } from '#/utils/types'
|
||||||
|
import { inject } from '@needle-di/core'
|
||||||
|
|
||||||
// Define the guild settings types
|
// Define the guild settings types
|
||||||
export const DiscordGuildSettingSchema = type({
|
export const DiscordGuildSettingSchema = type({
|
||||||
@ -13,35 +15,61 @@ export const DiscordGuildSettingSchema = type({
|
|||||||
|
|
||||||
export type DiscordGuildSetting = typeof DiscordGuildSettingSchema.infer
|
export type DiscordGuildSetting = typeof DiscordGuildSettingSchema.infer
|
||||||
|
|
||||||
// Common setting keys as constants
|
|
||||||
export const DISCORD_GUILD_SETTING_KEYS = {
|
// Define setting schemas with arktype
|
||||||
WYNN_GUILD: 'wynn_guild', // The associated Wynncraft guild ID
|
export const DISCORD_GUILD_SETTING_SCHEMAS = {
|
||||||
ANNOUNCEMENT_CHANNEL: 'announcement_channel',
|
wynn_guild: type('string.uuid'),
|
||||||
MEMBER_ROLE: 'member_role',
|
rank_roles: type({
|
||||||
OFFICER_ROLE: 'officer_role',
|
member: snowflake.optional(),
|
||||||
NOTIFICATION_SETTINGS: 'notification_settings',
|
recruiter: snowflake.optional(),
|
||||||
FEATURES: 'features',
|
captain: snowflake.optional(),
|
||||||
|
strategist: snowflake.optional(),
|
||||||
|
chief: snowflake.optional(),
|
||||||
|
owner: snowflake.optional(),
|
||||||
|
}),
|
||||||
|
features: type({
|
||||||
|
autoRole: 'boolean',
|
||||||
|
warTracking: 'boolean',
|
||||||
|
activityTracking: 'boolean',
|
||||||
|
leaderboard: 'boolean',
|
||||||
|
}),
|
||||||
} as const
|
} as const
|
||||||
|
|
||||||
export type DiscordGuildSettingKey = typeof DISCORD_GUILD_SETTING_KEYS[keyof typeof DISCORD_GUILD_SETTING_KEYS]
|
export type DiscordGuildSettingKey = keyof typeof DISCORD_GUILD_SETTING_SCHEMAS
|
||||||
|
|
||||||
|
export type DiscordGuildSettingValue<K extends DiscordGuildSettingKey> =
|
||||||
|
typeof DISCORD_GUILD_SETTING_SCHEMAS[K]['infer']
|
||||||
|
|
||||||
export class DiscordGuildSettingsService {
|
export class DiscordGuildSettingsService {
|
||||||
constructor(private readonly pg: PG) {}
|
constructor(private readonly pg = inject(PG)) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a specific setting for a guild
|
* Get a specific setting for a guild
|
||||||
*/
|
*/
|
||||||
async getSetting<T>(guildId: bigint, key: string): Promise<T | null> {
|
async getSetting<K extends DiscordGuildSettingKey>(
|
||||||
|
guildId: bigint,
|
||||||
|
key: K
|
||||||
|
): Promise<DiscordGuildSettingValue<K> | null> {
|
||||||
const { sql } = this.pg
|
const { sql } = this.pg
|
||||||
|
|
||||||
const result = await sql<{ value: T }[]>`
|
const result = await sql<{ value: unknown }[]>`
|
||||||
SELECT value
|
SELECT value
|
||||||
FROM discord.guild_settings
|
FROM discord.guild_settings
|
||||||
WHERE guild_id = ${guildId.toString()} AND key = ${key}
|
WHERE guild_id = ${guildId.toString()} AND key = ${key}
|
||||||
`
|
`
|
||||||
|
|
||||||
if (result.length === 0) return null
|
if (result.length === 0) return null
|
||||||
return result[0].value
|
|
||||||
|
// Validate the value with arktype
|
||||||
|
const schema = DISCORD_GUILD_SETTING_SCHEMAS[key]
|
||||||
|
const parsed = schema(result[0].value)
|
||||||
|
|
||||||
|
if (parsed instanceof type.errors) {
|
||||||
|
logger.error({ guildId, key, errors: parsed.summary }, 'Invalid guild setting value in database')
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
return parsed as DiscordGuildSettingValue<K>
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -62,12 +90,24 @@ export class DiscordGuildSettingsService {
|
|||||||
/**
|
/**
|
||||||
* Set a setting for a guild (upsert)
|
* Set a setting for a guild (upsert)
|
||||||
*/
|
*/
|
||||||
async setSetting<T extends JSONValue>(guildId: bigint, key: string, value: T): Promise<void> {
|
async setSetting<K extends DiscordGuildSettingKey>(
|
||||||
|
guildId: bigint,
|
||||||
|
key: K,
|
||||||
|
value: DiscordGuildSettingValue<K>
|
||||||
|
): Promise<void> {
|
||||||
const { sql } = this.pg
|
const { sql } = this.pg
|
||||||
|
|
||||||
|
// Validate the value with arktype
|
||||||
|
const schema = DISCORD_GUILD_SETTING_SCHEMAS[key]
|
||||||
|
const parsed = schema(value)
|
||||||
|
|
||||||
|
if (parsed instanceof type.errors) {
|
||||||
|
throw new Error(`Invalid value for guild setting ${key}: ${parsed.summary}`)
|
||||||
|
}
|
||||||
|
|
||||||
await sql`
|
await sql`
|
||||||
INSERT INTO discord.guild_settings (guild_id, key, value)
|
INSERT INTO discord.guild_settings (guild_id, key, value)
|
||||||
VALUES (${guildId.toString()}, ${key}, ${sql.json(value)})
|
VALUES (${guildId.toString()}, ${key}, ${sql.json(parsed as JSONValue)})
|
||||||
ON CONFLICT (guild_id, key)
|
ON CONFLICT (guild_id, key)
|
||||||
DO UPDATE SET
|
DO UPDATE SET
|
||||||
value = EXCLUDED.value
|
value = EXCLUDED.value
|
||||||
@ -79,7 +119,7 @@ export class DiscordGuildSettingsService {
|
|||||||
/**
|
/**
|
||||||
* Delete a specific setting for a guild
|
* Delete a specific setting for a guild
|
||||||
*/
|
*/
|
||||||
async deleteSetting(guildId: bigint, key: string): Promise<boolean> {
|
async deleteSetting(guildId: bigint, key: DiscordGuildSettingKey): Promise<boolean> {
|
||||||
const { sql } = this.pg
|
const { sql } = this.pg
|
||||||
|
|
||||||
const result = await sql`
|
const result = await sql`
|
||||||
|
|||||||
1
ts/src/utils/types/index.ts
Normal file
1
ts/src/utils/types/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export * from './snowflake'
|
||||||
15
ts/src/utils/types/snowflake.ts
Normal file
15
ts/src/utils/types/snowflake.ts
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import { type } from 'arktype'
|
||||||
|
|
||||||
|
// Custom arktype for Discord snowflake IDs (bigint)
|
||||||
|
export const snowflake = type('string|bigint').pipe((value, ctx) => {
|
||||||
|
if (typeof value === 'bigint') return value
|
||||||
|
|
||||||
|
// Parse string as base 10 bigint
|
||||||
|
try {
|
||||||
|
return BigInt(value)
|
||||||
|
} catch {
|
||||||
|
return ctx.error(`Invalid snowflake ID: ${value}`)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
export type Snowflake = bigint
|
||||||
@ -50,7 +50,7 @@ const workflowHandleApplicationCommand = async (payload: InteractionCreatePayloa
|
|||||||
info: async (args) => {
|
info: async (args) => {
|
||||||
const { workflowId } = workflowInfo()
|
const { workflowId } = workflowInfo()
|
||||||
const handle = await startChild(handleCommandGuildInfo, {
|
const handle = await startChild(handleCommandGuildInfo, {
|
||||||
args: [{ ref, discordGuildId: payload.guildId ? BigInt(payload.guildId) : undefined }],
|
args: [{ ref }],
|
||||||
workflowId: `${workflowId}-guild-info`,
|
workflowId: `${workflowId}-guild-info`,
|
||||||
})
|
})
|
||||||
await handle.result()
|
await handle.result()
|
||||||
@ -58,7 +58,7 @@ const workflowHandleApplicationCommand = async (payload: InteractionCreatePayloa
|
|||||||
online: async (args) => {
|
online: async (args) => {
|
||||||
const { workflowId } = workflowInfo()
|
const { workflowId } = workflowInfo()
|
||||||
const handle = await startChild(handleCommandGuildOnline, {
|
const handle = await startChild(handleCommandGuildOnline, {
|
||||||
args: [{ ref, discordGuildId: payload.guildId ? BigInt(payload.guildId) : undefined }],
|
args: [{ ref }],
|
||||||
workflowId: `${workflowId}-guild-online`,
|
workflowId: `${workflowId}-guild-online`,
|
||||||
})
|
})
|
||||||
await handle.result()
|
await handle.result()
|
||||||
@ -66,7 +66,7 @@ const workflowHandleApplicationCommand = async (payload: InteractionCreatePayloa
|
|||||||
leaderboard: async (args) => {
|
leaderboard: async (args) => {
|
||||||
const { workflowId } = workflowInfo()
|
const { workflowId } = workflowInfo()
|
||||||
const handle = await startChild(handleCommandGuildLeaderboard, {
|
const handle = await startChild(handleCommandGuildLeaderboard, {
|
||||||
args: [{ ref, discordGuildId: payload.guildId ? BigInt(payload.guildId) : undefined }],
|
args: [{ ref }],
|
||||||
workflowId: `${workflowId}-guild-leaderboard`,
|
workflowId: `${workflowId}-guild-leaderboard`,
|
||||||
})
|
})
|
||||||
await handle.result()
|
await handle.result()
|
||||||
@ -79,7 +79,6 @@ const workflowHandleApplicationCommand = async (payload: InteractionCreatePayloa
|
|||||||
args: [{
|
args: [{
|
||||||
ref,
|
ref,
|
||||||
args,
|
args,
|
||||||
discordGuildId: BigInt(payload.guildId!),
|
|
||||||
}],
|
}],
|
||||||
})
|
})
|
||||||
await handle.result()
|
await handle.result()
|
||||||
|
|||||||
@ -2,7 +2,6 @@ import { proxyActivities } from '@temporalio/workflow'
|
|||||||
import type * as activities from '#/activities'
|
import type * as activities from '#/activities'
|
||||||
import { WYNN_GUILD_ID } from '#/constants'
|
import { WYNN_GUILD_ID } from '#/constants'
|
||||||
import type { InteractionRef } from '#/discord'
|
import type { InteractionRef } from '#/discord'
|
||||||
import { DISCORD_GUILD_SETTING_KEYS } from '#/services/guild_settings'
|
|
||||||
|
|
||||||
const { formGuildInfoMessage, formGuildOnlineMessage, formGuildLeaderboardMessage, reply_to_interaction, get_discord_guild_setting } = proxyActivities<typeof activities>({
|
const { formGuildInfoMessage, formGuildOnlineMessage, formGuildLeaderboardMessage, reply_to_interaction, get_discord_guild_setting } = proxyActivities<typeof activities>({
|
||||||
startToCloseTimeout: '30 seconds',
|
startToCloseTimeout: '30 seconds',
|
||||||
@ -19,7 +18,7 @@ export async function handleCommandGuildInfo(payload: CommandPayload): Promise<v
|
|||||||
// Try to get the associated Wynncraft guild for this Discord guild
|
// Try to get the associated Wynncraft guild for this Discord guild
|
||||||
let guildId = WYNN_GUILD_ID // Default fallback
|
let guildId = WYNN_GUILD_ID // Default fallback
|
||||||
if (discordGuildId) {
|
if (discordGuildId) {
|
||||||
const wynnGuild = await get_discord_guild_setting<{ uid: string }>(discordGuildId, DISCORD_GUILD_SETTING_KEYS.WYNN_GUILD)
|
const wynnGuild = await get_discord_guild_setting(discordGuildId, 'wynn_guild')
|
||||||
if (wynnGuild?.uid) {
|
if (wynnGuild?.uid) {
|
||||||
guildId = wynnGuild.uid
|
guildId = wynnGuild.uid
|
||||||
}
|
}
|
||||||
@ -39,7 +38,7 @@ export async function handleCommandGuildOnline(payload: CommandPayload): Promise
|
|||||||
// Try to get the associated Wynncraft guild for this Discord guild
|
// Try to get the associated Wynncraft guild for this Discord guild
|
||||||
let guildId = WYNN_GUILD_ID // Default fallback
|
let guildId = WYNN_GUILD_ID // Default fallback
|
||||||
if (discordGuildId) {
|
if (discordGuildId) {
|
||||||
const wynnGuild = await get_discord_guild_setting<{ uid: string }>(discordGuildId, DISCORD_GUILD_SETTING_KEYS.WYNN_GUILD)
|
const wynnGuild = await get_discord_guild_setting(discordGuildId, 'wynn_guild')
|
||||||
if (wynnGuild?.uid) {
|
if (wynnGuild?.uid) {
|
||||||
guildId = wynnGuild.uid
|
guildId = wynnGuild.uid
|
||||||
}
|
}
|
||||||
@ -59,7 +58,7 @@ export async function handleCommandGuildLeaderboard(payload: CommandPayload): Pr
|
|||||||
// Try to get the associated Wynncraft guild for this Discord guild
|
// Try to get the associated Wynncraft guild for this Discord guild
|
||||||
let guildId = WYNN_GUILD_ID // Default fallback
|
let guildId = WYNN_GUILD_ID // Default fallback
|
||||||
if (discordGuildId) {
|
if (discordGuildId) {
|
||||||
const wynnGuild = await get_discord_guild_setting<{ uid: string }>(discordGuildId, DISCORD_GUILD_SETTING_KEYS.WYNN_GUILD)
|
const wynnGuild = await get_discord_guild_setting(discordGuildId, 'wynn_guild')
|
||||||
if (wynnGuild?.uid) {
|
if (wynnGuild?.uid) {
|
||||||
guildId = wynnGuild.uid
|
guildId = wynnGuild.uid
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import { proxyActivities } from '@temporalio/workflow'
|
import { proxyActivities } from '@temporalio/workflow'
|
||||||
import type * as activities from '#/activities'
|
import type * as activities from '#/activities'
|
||||||
import type { InteractionRef } from '#/discord'
|
import type { InteractionRef } from '#/discord'
|
||||||
import { DISCORD_GUILD_SETTING_KEYS } from '#/services/guild_settings'
|
import { InteractionResponseTypes } from '@discordeno/types'
|
||||||
|
|
||||||
const { reply_to_interaction, set_discord_guild_setting, get_wynn_guild_info } = proxyActivities<typeof activities>({
|
const { reply_to_interaction, set_discord_guild_setting, get_wynn_guild_info } = proxyActivities<typeof activities>({
|
||||||
startToCloseTimeout: '10 seconds',
|
startToCloseTimeout: '10 seconds',
|
||||||
@ -12,17 +12,30 @@ export interface SetWynnGuildPayload {
|
|||||||
args: {
|
args: {
|
||||||
guild: string
|
guild: string
|
||||||
}
|
}
|
||||||
discordGuildId: bigint
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function handleCommandSetWynnGuild(payload: SetWynnGuildPayload): Promise<void> {
|
export async function handleCommandSetWynnGuild(payload: SetWynnGuildPayload): Promise<void> {
|
||||||
const { ref, args, discordGuildId } = payload
|
const { ref, args } = payload
|
||||||
|
|
||||||
// Defer the response since this might take a moment
|
// Defer the response since this might take a moment
|
||||||
await reply_to_interaction({
|
await reply_to_interaction({
|
||||||
ref,
|
ref,
|
||||||
type: 5, // Deferred response
|
type: InteractionResponseTypes.DeferredChannelMessageWithSource,
|
||||||
})
|
})
|
||||||
|
ref.acknowledged = true
|
||||||
|
|
||||||
|
|
||||||
|
if (!ref.guildId) {
|
||||||
|
await reply_to_interaction({
|
||||||
|
ref,
|
||||||
|
type: InteractionResponseTypes.UpdateMessage,
|
||||||
|
options: {
|
||||||
|
content: `❌ Could not find discord guild. Please try again.`,
|
||||||
|
isPrivate: true,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Validate the Wynncraft guild exists
|
// Validate the Wynncraft guild exists
|
||||||
@ -31,7 +44,7 @@ export async function handleCommandSetWynnGuild(payload: SetWynnGuildPayload): P
|
|||||||
if (!guildInfo) {
|
if (!guildInfo) {
|
||||||
await reply_to_interaction({
|
await reply_to_interaction({
|
||||||
ref,
|
ref,
|
||||||
type: 7, // Update the deferred response
|
type: InteractionResponseTypes.UpdateMessage, // Update the deferred response
|
||||||
options: {
|
options: {
|
||||||
content: `❌ Could not find Wynncraft guild "${args.guild}". Please check the guild name and try again.`,
|
content: `❌ Could not find Wynncraft guild "${args.guild}". Please check the guild name and try again.`,
|
||||||
isPrivate: true,
|
isPrivate: true,
|
||||||
@ -42,19 +55,14 @@ export async function handleCommandSetWynnGuild(payload: SetWynnGuildPayload): P
|
|||||||
|
|
||||||
// Set the association in the database using the generic activity
|
// Set the association in the database using the generic activity
|
||||||
await set_discord_guild_setting({
|
await set_discord_guild_setting({
|
||||||
discordGuildId,
|
guildId: ref.guildId,
|
||||||
key: DISCORD_GUILD_SETTING_KEYS.WYNN_GUILD,
|
key: 'wynn_guild',
|
||||||
value: {
|
value: guildInfo.uid,
|
||||||
uid: guildInfo.uid,
|
|
||||||
name: guildInfo.name,
|
|
||||||
prefix: guildInfo.prefix,
|
|
||||||
linkedAt: new Date().toISOString(),
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
|
|
||||||
await reply_to_interaction({
|
await reply_to_interaction({
|
||||||
ref,
|
ref,
|
||||||
type: 7, // Update the deferred response
|
type: InteractionResponseTypes.UpdateMessage, // Update the deferred response
|
||||||
options: {
|
options: {
|
||||||
content: `✅ Successfully linked this Discord server to Wynncraft guild **[${guildInfo.prefix}] ${guildInfo.name}**`,
|
content: `✅ Successfully linked this Discord server to Wynncraft guild **[${guildInfo.prefix}] ${guildInfo.name}**`,
|
||||||
isPrivate: true,
|
isPrivate: true,
|
||||||
@ -63,7 +71,7 @@ export async function handleCommandSetWynnGuild(payload: SetWynnGuildPayload): P
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
await reply_to_interaction({
|
await reply_to_interaction({
|
||||||
ref,
|
ref,
|
||||||
type: 7, // Update the deferred response
|
type: InteractionResponseTypes.UpdateMessage, // Update the deferred response
|
||||||
options: {
|
options: {
|
||||||
content: `❌ An error occurred while setting the guild: ${error}`,
|
content: `❌ An error occurred while setting the guild: ${error}`,
|
||||||
isPrivate: true,
|
isPrivate: true,
|
||||||
|
|||||||
10
ts/yarn.lock
10
ts/yarn.lock
@ -1922,7 +1922,7 @@ __metadata:
|
|||||||
pino: "npm:^9.6.0"
|
pino: "npm:^9.6.0"
|
||||||
pino-logfmt: "npm:^0.1.1"
|
pino-logfmt: "npm:^0.1.1"
|
||||||
pino-pretty: "npm:^13.0.0"
|
pino-pretty: "npm:^13.0.0"
|
||||||
postgres: "npm:^3.4.5"
|
postgres: "npm:^3.4.7"
|
||||||
rollup: "npm:^4.34.8"
|
rollup: "npm:^4.34.8"
|
||||||
superjson: "npm:^2.2.2"
|
superjson: "npm:^2.2.2"
|
||||||
ts-markdown-builder: "npm:^0.4.0"
|
ts-markdown-builder: "npm:^0.4.0"
|
||||||
@ -4178,10 +4178,10 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"postgres@npm:^3.4.5":
|
"postgres@npm:^3.4.7":
|
||||||
version: 3.4.5
|
version: 3.4.7
|
||||||
resolution: "postgres@npm:3.4.5"
|
resolution: "postgres@npm:3.4.7"
|
||||||
checksum: 10c0/53415acea77e97bdc1eeb861048f34964e2236e4d4d42f408fc9b901e62bfcf7443a487ebfdad18b57b468c6e297bf8d22097106a200f62eb1262eb5a71355df
|
checksum: 10c0/b2e61b1064d38e7e1df8291f6d5a7e11f892a3240e00cf2b5e5542bf9abbfe97f3963164aeb56b42c1ab6b8aae3454c57f5bbc1791df0769375542740a7cde72
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user