362 lines
9.9 KiB
TypeScript
362 lines
9.9 KiB
TypeScript
/**
|
|
* Ejemplos de uso de Feature Flags en comandos
|
|
* Funciona para comandos slash Y comandos de mensaje
|
|
*/
|
|
|
|
import { ChatInputCommandInteraction, Message } from "discord.js";
|
|
import { CommandSlash, CommandMessage } from "../../types/commands";
|
|
import {
|
|
withFeatureFlag,
|
|
checkFeatureFlag,
|
|
guardFeatureFlag,
|
|
abTestCommand,
|
|
} from "../lib/featureFlagCommandWrapper";
|
|
import type Amayo from "../client";
|
|
|
|
// ============================================================================
|
|
// PATRÓN 1: Usando withFeatureFlag (wrapper) - RECOMENDADO
|
|
// ============================================================================
|
|
|
|
/**
|
|
* Comando Slash con Feature Flag
|
|
* El wrapper bloquea automáticamente si el flag está disabled
|
|
*/
|
|
export const shopSlashCommand: CommandSlash = {
|
|
name: "shop",
|
|
description: "Abre la tienda",
|
|
type: "slash",
|
|
cooldown: 10,
|
|
// Envuelve el handler con el wrapper
|
|
run: withFeatureFlag(
|
|
"new_shop_system",
|
|
async (interaction: ChatInputCommandInteraction, client: Amayo) => {
|
|
// Este código solo se ejecuta si el flag está enabled
|
|
await interaction.reply("🛒 Bienvenido a la tienda!");
|
|
},
|
|
{
|
|
fallbackMessage: "🔧 La tienda está en mantenimiento.",
|
|
}
|
|
),
|
|
};
|
|
|
|
/**
|
|
* Comando de Mensaje con Feature Flag
|
|
* El mismo wrapper funciona para comandos de mensaje
|
|
*/
|
|
export const shopMessageCommand: CommandMessage = {
|
|
name: "shop",
|
|
type: "message",
|
|
cooldown: 10,
|
|
description: "Abre la tienda",
|
|
// El mismo wrapper funciona aquí
|
|
run: withFeatureFlag(
|
|
"new_shop_system",
|
|
async (message: Message, args: string[], client: Amayo) => {
|
|
// Este código solo se ejecuta si el flag está enabled
|
|
await message.reply("🛒 Bienvenido a la tienda!");
|
|
},
|
|
{
|
|
fallbackMessage: "🔧 La tienda está en mantenimiento.",
|
|
}
|
|
),
|
|
};
|
|
|
|
// ============================================================================
|
|
// PATRÓN 2: Usando guardFeatureFlag (check con respuesta automática)
|
|
// ============================================================================
|
|
|
|
/**
|
|
* Comando Slash con guard
|
|
*/
|
|
export const mineSlashCommand: CommandSlash = {
|
|
name: "mine",
|
|
description: "Minea recursos",
|
|
type: "slash",
|
|
cooldown: 10,
|
|
run: async (interaction, client) => {
|
|
// Guard que responde automáticamente si está disabled
|
|
if (!(await guardFeatureFlag("new_mining_system", interaction))) {
|
|
return; // Ya respondió automáticamente
|
|
}
|
|
|
|
// Código del comando
|
|
await interaction.reply("⛏️ Minando...");
|
|
},
|
|
};
|
|
|
|
/**
|
|
* Comando de Mensaje con guard
|
|
*/
|
|
export const mineMessageCommand: CommandMessage = {
|
|
name: "mine",
|
|
type: "message",
|
|
cooldown: 10,
|
|
run: async (message, args, client) => {
|
|
// El mismo guard funciona para mensajes
|
|
if (!(await guardFeatureFlag("new_mining_system", message))) {
|
|
return;
|
|
}
|
|
|
|
await message.reply("⛏️ Minando...");
|
|
},
|
|
};
|
|
|
|
// ============================================================================
|
|
// PATRÓN 3: Usando checkFeatureFlag (check manual)
|
|
// ============================================================================
|
|
|
|
/**
|
|
* Comando Slash con check manual
|
|
* Útil cuando necesitas lógica custom
|
|
*/
|
|
export const inventorySlashCommand: CommandSlash = {
|
|
name: "inventory",
|
|
description: "Muestra tu inventario",
|
|
type: "slash",
|
|
cooldown: 5,
|
|
run: async (interaction, client) => {
|
|
const useNewUI = await checkFeatureFlag("inventory_ui_v2", interaction);
|
|
|
|
if (useNewUI) {
|
|
// Nueva UI
|
|
await interaction.reply({
|
|
content: "📦 **Inventario v2**\n- Item 1\n- Item 2",
|
|
ephemeral: true,
|
|
});
|
|
} else {
|
|
// UI antigua
|
|
await interaction.reply({
|
|
content: "📦 Inventario: Item 1, Item 2",
|
|
ephemeral: true,
|
|
});
|
|
}
|
|
},
|
|
};
|
|
|
|
/**
|
|
* Comando de Mensaje con check manual
|
|
*/
|
|
export const inventoryMessageCommand: CommandMessage = {
|
|
name: "inventory",
|
|
type: "message",
|
|
cooldown: 5,
|
|
aliases: ["inv", "items"],
|
|
run: async (message, args, client) => {
|
|
const useNewUI = await checkFeatureFlag("inventory_ui_v2", message);
|
|
|
|
if (useNewUI) {
|
|
await message.reply("📦 **Inventario v2**\n- Item 1\n- Item 2");
|
|
} else {
|
|
await message.reply("📦 Inventario: Item 1, Item 2");
|
|
}
|
|
},
|
|
};
|
|
|
|
// ============================================================================
|
|
// PATRÓN 4: A/B Testing
|
|
// ============================================================================
|
|
|
|
/**
|
|
* Comando Slash con A/B testing
|
|
*/
|
|
export const combatSlashCommand: CommandSlash = {
|
|
name: "attack",
|
|
description: "Ataca a un enemigo",
|
|
type: "slash",
|
|
cooldown: 10,
|
|
run: async (interaction, client) => {
|
|
await abTestCommand("improved_combat_algorithm", interaction, {
|
|
variant: async () => {
|
|
// 50% de usuarios ven el nuevo algoritmo
|
|
const damage = Math.floor(Math.random() * 100) + 50;
|
|
await interaction.reply(`⚔️ Daño (nuevo): ${damage}`);
|
|
},
|
|
control: async () => {
|
|
// 50% ven el algoritmo antiguo
|
|
const damage = Math.floor(Math.random() * 50) + 25;
|
|
await interaction.reply(`⚔️ Daño (antiguo): ${damage}`);
|
|
},
|
|
});
|
|
},
|
|
};
|
|
|
|
/**
|
|
* Comando de Mensaje con A/B testing
|
|
*/
|
|
export const combatMessageCommand: CommandMessage = {
|
|
name: "attack",
|
|
type: "message",
|
|
cooldown: 10,
|
|
run: async (message, args, client) => {
|
|
await abTestCommand("improved_combat_algorithm", message, {
|
|
variant: async () => {
|
|
const damage = Math.floor(Math.random() * 100) + 50;
|
|
await message.reply(`⚔️ Daño (nuevo): ${damage}`);
|
|
},
|
|
control: async () => {
|
|
const damage = Math.floor(Math.random() * 50) + 25;
|
|
await message.reply(`⚔️ Daño (antiguo): ${damage}`);
|
|
},
|
|
});
|
|
},
|
|
};
|
|
|
|
// ============================================================================
|
|
// PATRÓN 5: Múltiples flags (migrando sistema antiguo a nuevo)
|
|
// ============================================================================
|
|
|
|
/**
|
|
* Comando que migra gradualmente de un sistema a otro
|
|
*/
|
|
export const economySlashCommand: CommandSlash = {
|
|
name: "balance",
|
|
description: "Muestra tu balance",
|
|
type: "slash",
|
|
cooldown: 5,
|
|
run: async (interaction, client) => {
|
|
const useNewEconomy = await checkFeatureFlag(
|
|
"economy_system_v2",
|
|
interaction
|
|
);
|
|
const usePremiumFeatures = await checkFeatureFlag(
|
|
"premium_features",
|
|
interaction
|
|
);
|
|
|
|
if (useNewEconomy) {
|
|
// Sistema nuevo de economía
|
|
const balance = 5000;
|
|
const streak = usePremiumFeatures ? "🔥 Racha: 7 días" : "";
|
|
|
|
await interaction.reply(
|
|
`💰 Balance: ${balance} monedas\n${streak}`.trim()
|
|
);
|
|
} else {
|
|
// Sistema antiguo
|
|
const balance = 5000;
|
|
await interaction.reply(`💰 Tienes ${balance} monedas`);
|
|
}
|
|
},
|
|
};
|
|
|
|
/**
|
|
* Lo mismo pero para comando de mensaje
|
|
*/
|
|
export const economyMessageCommand: CommandMessage = {
|
|
name: "balance",
|
|
type: "message",
|
|
cooldown: 5,
|
|
aliases: ["bal", "money"],
|
|
run: async (message, args, client) => {
|
|
const useNewEconomy = await checkFeatureFlag("economy_system_v2", message);
|
|
const usePremiumFeatures = await checkFeatureFlag(
|
|
"premium_features",
|
|
message
|
|
);
|
|
|
|
if (useNewEconomy) {
|
|
const balance = 5000;
|
|
const streak = usePremiumFeatures ? "🔥 Racha: 7 días" : "";
|
|
await message.reply(`💰 Balance: ${balance} monedas\n${streak}`.trim());
|
|
} else {
|
|
const balance = 5000;
|
|
await message.reply(`💰 Tienes ${balance} monedas`);
|
|
}
|
|
},
|
|
};
|
|
|
|
// ============================================================================
|
|
// PATRÓN 6: Comando universal (un solo run para ambos)
|
|
// ============================================================================
|
|
|
|
/**
|
|
* Helper para detectar tipo de comando
|
|
*/
|
|
function isSlashCommand(
|
|
source: ChatInputCommandInteraction | Message
|
|
): source is ChatInputCommandInteraction {
|
|
return "options" in source && "user" in source;
|
|
}
|
|
|
|
/**
|
|
* Función de negocio universal
|
|
*/
|
|
async function showProfile(
|
|
source: ChatInputCommandInteraction | Message,
|
|
userId: string
|
|
) {
|
|
const useNewProfile = await checkFeatureFlag("profile_v2", source);
|
|
|
|
const profileText = useNewProfile
|
|
? `👤 **Perfil v2**\nUsuario: <@${userId}>\nNivel: 10`
|
|
: `👤 Perfil: <@${userId}> - Nivel 10`;
|
|
|
|
if (isSlashCommand(source)) {
|
|
await source.reply(profileText);
|
|
} else {
|
|
await source.reply(profileText);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Comando Slash que usa la función universal
|
|
*/
|
|
export const profileSlashCommand: CommandSlash = {
|
|
name: "profile",
|
|
description: "Muestra tu perfil",
|
|
type: "slash",
|
|
cooldown: 5,
|
|
run: async (interaction, client) => {
|
|
await showProfile(interaction, interaction.user.id);
|
|
},
|
|
};
|
|
|
|
/**
|
|
* Comando de Mensaje que usa la misma función universal
|
|
*/
|
|
export const profileMessageCommand: CommandMessage = {
|
|
name: "profile",
|
|
type: "message",
|
|
cooldown: 5,
|
|
aliases: ["perfil", "me"],
|
|
run: async (message, args, client) => {
|
|
await showProfile(message, message.author.id);
|
|
},
|
|
};
|
|
|
|
// ============================================================================
|
|
// RESUMEN DE PATRONES
|
|
// ============================================================================
|
|
|
|
/*
|
|
* PATRÓN 1: withFeatureFlag()
|
|
* - Más limpio y declarativo
|
|
* - Bloquea automáticamente si disabled
|
|
* - Recomendado para comandos simples
|
|
*
|
|
* PATRÓN 2: guardFeatureFlag()
|
|
* - Check con respuesta automática
|
|
* - Control total del flujo
|
|
* - Bueno para lógica compleja
|
|
*
|
|
* PATRÓN 3: checkFeatureFlag()
|
|
* - Check manual sin respuesta
|
|
* - Para if/else personalizados
|
|
* - Migración gradual de sistemas
|
|
*
|
|
* PATRÓN 4: abTestCommand()
|
|
* - A/B testing directo
|
|
* - Ejecuta función u otra según flag
|
|
* - Ideal para comparar versiones
|
|
*
|
|
* PATRÓN 5: Múltiples flags
|
|
* - Combina varios checks
|
|
* - Features progresivas
|
|
* - Sistemas modulares
|
|
*
|
|
* PATRÓN 6: Función universal
|
|
* - Un solo código para ambos tipos
|
|
* - Reutilización máxima
|
|
* - Mantenimiento simplificado
|
|
*/
|