50 lines
1.7 KiB
TypeScript
50 lines
1.7 KiB
TypeScript
import { createReactiveState } from '@/util/reactive-state.js';
|
|
import { isApplicationCommand, isAutocomplete } from './command-helpers';
|
|
import type { CommandState, ExecutableInteraction, PartialContext } from '../types';
|
|
|
|
export async function getCommandState<T>(interaction: ExecutableInteraction, ctx: PartialContext): Promise<CommandState<T>> {
|
|
const id = instanceIdFromInteraction(interaction);
|
|
|
|
let state: CommandState<T>;
|
|
|
|
// get state from kv store if possible
|
|
if (ctx.kv.has(`command-state:${id}`)) {
|
|
state = await ctx.kv.get<CommandState<T>>(`command-state:${id}`);
|
|
}
|
|
if (!state) {
|
|
state = { id: id, name: '', data: {} as T };
|
|
}
|
|
const [reactiveState, subscribe] = createReactiveState(state);
|
|
subscribe(async (newState) => {
|
|
if (ctx.kv) {
|
|
await ctx.kv.set(`command-state:${id}`, newState);
|
|
}
|
|
});
|
|
ctx.state = reactiveState;
|
|
return reactiveState;
|
|
}
|
|
|
|
function instanceIdFromInteraction(interaction: ExecutableInteraction) {
|
|
if (isAutocomplete(interaction)) {
|
|
// autocomplete should not be stateful, they get no id
|
|
return '';
|
|
}
|
|
|
|
if (isApplicationCommand(interaction)) {
|
|
// for application commands, we create a new instance id
|
|
const instance_id = crypto.randomUUID();
|
|
return instance_id;
|
|
}
|
|
|
|
const interact = interaction;
|
|
const customId: string = interact.data.custom_id;
|
|
const commandId = customId.split('_').pop();
|
|
interaction;
|
|
// command id should be a uuid
|
|
if (commandId && /^[0-9a-f]{8}-[0-9a-f]{4}-[4][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/.test(commandId)) {
|
|
return commandId;
|
|
}
|
|
console.error(`Invalid command id extracted from interaction: ${customId}`);
|
|
return '';
|
|
}
|