F9Alejandro 695cad9ec8
Initial Commit:
Added example plugins: Counter, Console, Ping

Changes to be committed:
	modified:   .gitignore
	modified:   README.md
	new file:   compiled/counter.wasm
	new file:   compiled/ping.wasm
	new file:   console/LICENSE
	new file:   console/README.md
	new file:   console/esbuild.js
	new file:   console/package-lock.json
	new file:   console/package.json
	new file:   console/src/index.d.ts
	new file:   console/src/index.js
	new file:   counter/LICENSE
	new file:   counter/README.md
	new file:   counter/esbuild.js
	new file:   counter/package-lock.json
	new file:   counter/package.json
	new file:   counter/src/index.d.ts
	new file:   counter/src/index.js
	new file:   ping/LICENSE
	new file:   ping/README.md
	new file:   ping/esbuild.js
	new file:   ping/package-lock.json
	new file:   ping/package.json
	new file:   ping/src/index.d.ts
	new file:   ping/src/index.js
2025-04-26 00:02:46 -04:00

203 lines
7.6 KiB
JavaScript

// js-src/counter/index.js - Counter Command (Refactored for Readability)
// --- Constants ---
// Interaction Types (from Discord API)
const InteractionType = {
APPLICATION_COMMAND: 2,
MESSAGE_COMPONENT: 3,
MODAL_SUBMIT: 5,
};
// Component Types (from Discord API)
const ComponentType = {
ACTION_ROW: 1,
BUTTON: 2,
// Add SELECT_MENU, TEXT_INPUT etc. here if needed
};
// Button Styles (from Discord API)
const ButtonStyle = {
PRIMARY: 1, // Blue
SECONDARY: 2, // Gray
SUCCESS: 3, // Green
DANGER: 4, // Red
LINK: 5,
};
const PLUGIN_NAME = "counter"; // Used in Custom IDs
// --- Command Definition ---
const counterCommandDefinition = {
Name: PLUGIN_NAME,
Description: "Starts an interactive counter (readable version).",
Options: [],
};
function get_command_definition() {
try {
// Output the command definition JSON for the Go host
Host.outputString(JSON.stringify(counterCommandDefinition));
return 0; // Success
} catch (e) {
console.error(`[${PLUGIN_NAME}] Error stringifying command definition:`, e);
Host.outputString(`{"error": "Failed to generate command definition"}`);
return 1; // Indicate failure
}
}
// --- Helper Functions ---
/**
* Parses the counter's custom ID format "counter:action:count".
* @param {string} customId - The custom ID string.
* @returns {object|null} An object { action: string, count: number } or null if invalid.
*/
function parseCounterCustomId(customId) {
if (!customId || typeof customId !== 'string') {
console.error(`[${PLUGIN_NAME}] Invalid customId type received:`, customId);
return null;
}
const parts = customId.split(':');
// Expecting 3 parts: pluginName, action, countString
if (parts.length === 3 && parts[0] === PLUGIN_NAME) {
const action = parts[1];
const count = parseInt(parts[2], 10); // Base 10
if (!isNaN(count) && (action === 'increment' || action === 'decrement')) {
// Successfully parsed
return { action, count };
} else {
console.error(`[${PLUGIN_NAME}] Failed to parse valid action/count from CustomID parts:`, parts);
}
} else {
console.error(`[${PLUGIN_NAME}] CustomID did not match expected format 'pluginName:action:count':`, customId);
}
return null; // Indicate failure
}
/**
* Creates the Action Row containing the counter buttons.
* @param {number} currentCount - The count to embed in the buttons' custom IDs.
* @returns {Array} An array containing a single Action Row component object.
*/
function createCounterActionRow(currentCount) {
return [ // Array always starts with Action Rows
{
type: ComponentType.ACTION_ROW,
components: [ // Components within the Action Row
{
type: ComponentType.BUTTON,
style: ButtonStyle.PRIMARY,
label: "Increment (+)",
custom_id: `${PLUGIN_NAME}:increment:${currentCount}`
},
{
type: ComponentType.BUTTON,
style: ButtonStyle.DANGER,
label: "Decrement (-)",
custom_id: `${PLUGIN_NAME}:decrement:${currentCount}`
}
]
}
];
}
/**
* Creates the JSON response object to send back to the Go host.
* @param {string} content - The message content.
* @param {Array|null} components - The array of components (e.g., action rows), or null.
* @param {boolean} ephemeral - Whether the response should be ephemeral.
* @returns {object} The response object ready for stringification.
*/
function createPluginResponse(content, components = null, ephemeral = false) {
const response = { content, ephemeral };
if (components) {
response.components = components;
}
return response;
}
// --- Main Interaction Handler ---
function handle_interaction() {
console.log(`[${PLUGIN_NAME}] handle_interaction called.`);
try {
// --- 1. Get Input Data ---
const inputJson = Host.inputString();
console.log(`[${PLUGIN_NAME}] Raw Input (first 500):`, inputJson.substring(0, 500));
let interactionData;
try {
interactionData = JSON.parse(inputJson);
} catch (parseErr) {
console.error(`[${PLUGIN_NAME}] Failed to parse input JSON:`, parseErr);
const errResp = createPluginResponse("Error: Couldn't understand interaction data.", null, true);
Host.outputString(JSON.stringify(errResp));
return 1; // Indicate failure
}
console.log(`[${PLUGIN_NAME}] Parsed Interaction Type:`, interactionData.type);
// --- 2. Determine Current State & Action ---
let currentCount = 0;
let action = "start"; // Default for initial command
if (interactionData.type === InteractionType.MESSAGE_COMPONENT) {
console.log(`[${PLUGIN_NAME}] Processing Message Component interaction.`);
const customId = interactionData.data.custom_id;
const parsedId = parseCounterCustomId(customId);
if (parsedId) {
action = parsedId.action;
currentCount = parsedId.count;
console.log(`[${PLUGIN_NAME}] Parsed action: ${action}, count: ${currentCount}`);
} else {
// Error already logged in parseCounterCustomId
const errResp = createPluginResponse("Error: Invalid button state received.", null, true);
Host.outputString(JSON.stringify(errResp));
return 0; // Return normally but show error
}
} else if (interactionData.type === InteractionType.APPLICATION_COMMAND) {
console.log(`[${PLUGIN_NAME}] Processing Application Command interaction (start).`);
// Use default action='start', currentCount=0
} else {
console.error(`[${PLUGIN_NAME}] Received unexpected interaction type:`, interactionData.type);
const errResp = createPluginResponse("Error: Unexpected interaction type received.", null, true);
Host.outputString(JSON.stringify(errResp));
return 0; // Return normally but show error
}
// --- 3. Calculate New State ---
let newCount = currentCount;
if (action === 'increment') {
newCount++;
} else if (action === 'decrement') {
newCount--;
} // 'start' action uses the initial newCount = currentCount = 0
console.log(`[${PLUGIN_NAME}] New count calculated: ${newCount}`);
// --- 4. Construct Response ---
const responseContent = `Count: ${newCount}`;
const responseComponents = createCounterActionRow(newCount);
const response = createPluginResponse(responseContent, responseComponents, false);
console.log(`[${PLUGIN_NAME}] Sending response JSON:`, JSON.stringify(response));
Host.outputString(JSON.stringify(response));
return 0; // Success
} catch (e) {
// --- 5. Handle Unexpected Errors ---
console.error(`[${PLUGIN_NAME}] Uncaught error in handle_interaction:`, e);
// Send generic error back to user if possible
const errResp = createPluginResponse(`Internal Error: ${e.message || 'Unknown error in counter plugin'}`, null, true);
try { Host.outputString(JSON.stringify(errResp)); } catch (_) {} // Best effort error reporting
return 1; // Indicate failure via exit code
}
}
// --- Exports ---
module.exports = {
get_command_definition,
handle_interaction,
};