
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
203 lines
7.6 KiB
JavaScript
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,
|
|
}; |