diff --git a/TODO.md b/TODO.md
index bda54d8..c00219d 100644
--- a/TODO.md
+++ b/TODO.md
@@ -124,6 +124,7 @@ This file tracks larger Lumi work that cannot safely be completed in one pass. K
- Review localization/translation keys if present so simplified wording remains consistent across languages.
## Done
+- 2026-06-17: Renamed all remaining Economy internals from the old misspelled IDs/paths/tables to `economy-*`, added startup migration for legacy plugin rows, settings, command usage IDs, tables, uploads, asset paths, old URLs, and bumped core/plugin patch versions.
- 2026-06-17: Fixed user-facing Economy spelling, restored `/stats/{username}` Compare toggling, linked Top commands run leaderboard entries to `/commands`, and bumped core/plugin patch versions.
- 2026-06-17: Fixed custom command Edit buttons and `/commands` Copy Link / expand buttons with delegated handlers, clipboard fallback, and v0.1.5 patch bump.
- 2026-06-17: Fixed repo-based core updates deleting `data/update-cache/repo` during apply, added a verification guard, and bumped core package version to v0.1.4.
diff --git a/package-lock.json b/package-lock.json
index 7c69903..0a7936a 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "lumi-bot",
- "version": "0.1.6",
+ "version": "0.1.7",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "lumi-bot",
- "version": "0.1.6",
+ "version": "0.1.7",
"dependencies": {
"adm-zip": "^0.5.12",
"better-sqlite3": "^11.5.0",
diff --git a/package.json b/package.json
index 8e315b5..c82a39f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "lumi-bot",
- "version": "0.1.6",
+ "version": "0.1.7",
"private": true,
"type": "commonjs",
"scripts": {
diff --git a/plugins/birthday/index.js b/plugins/birthday/index.js
index 37c62a3..e55a656 100644
--- a/plugins/birthday/index.js
+++ b/plugins/birthday/index.js
@@ -591,7 +591,7 @@ function reserveDelivery(db, userId, deliveryKey, type, status, details) {
function grantGiftOnce(db, userId, deliveryKey, mode) {
const config = getConfig(db);
const amount = config.gift_amount;
- const framework = global.lumiFrameworks?.echonomy;
+ const framework = global.lumiFrameworks?.economy;
if (!amount || !framework || typeof framework.addBalance !== "function") {
return null;
}
@@ -919,7 +919,7 @@ async function buildDiagnostics(discordClient, config) {
discordAvailable: Boolean(discordClient),
discordReady: Boolean(discordClient?.readyAt),
channel,
- echonomyAvailable: Boolean(global.lumiFrameworks?.echonomy?.addBalance),
+ economyAvailable: Boolean(global.lumiFrameworks?.economy?.addBalance),
currentDate: getZonedDateParts(config.timezone)
};
}
diff --git a/plugins/birthday/plugin.json b/plugins/birthday/plugin.json
index d8d1cd5..13acc92 100644
--- a/plugins/birthday/plugin.json
+++ b/plugins/birthday/plugin.json
@@ -1,7 +1,7 @@
{
"id": "birthday",
"name": "Birthday",
- "version": "0.1.1",
+ "version": "0.1.2",
"description": "Birthday profiles, announcements, lookup commands, and optional birthday currency gifts.",
"main": "index.js"
}
diff --git a/plugins/birthday/views/birthday-admin.ejs b/plugins/birthday/views/birthday-admin.ejs
index 6c3a378..eeb7a3f 100644
--- a/plugins/birthday/views/birthday-admin.ejs
+++ b/plugins/birthday/views/birthday-admin.ejs
@@ -12,7 +12,7 @@
| Discord client | <%= diagnostics.discordAvailable ? (diagnostics.discordReady ? "Ready" : "Available") : "Unavailable" %> |
| Announcement channel | <%= diagnostics.channel.message %> |
- | Economy | <%= diagnostics.echonomyAvailable ? "Available" : "Unavailable" %> |
+ | Economy | <%= diagnostics.economyAvailable ? "Available" : "Unavailable" %> |
| Current plugin date | <%= diagnostics.currentDate.year %>-<%= String(diagnostics.currentDate.month).padStart(2, "0") %>-<%= String(diagnostics.currentDate.day).padStart(2, "0") %> |
diff --git a/plugins/echonomy-framework/cmds.json b/plugins/economy-framework/cmds.json
similarity index 98%
rename from plugins/echonomy-framework/cmds.json
rename to plugins/economy-framework/cmds.json
index a9a1660..aea57ed 100644
--- a/plugins/echonomy-framework/cmds.json
+++ b/plugins/economy-framework/cmds.json
@@ -1,5 +1,5 @@
{
- "pluginId": "echonomy-framework",
+ "pluginId": "economy-framework",
"pluginName": "Economy Framework",
"platformKeys": {
"discord": "platform_discord",
diff --git a/plugins/echonomy-framework/index.js b/plugins/economy-framework/index.js
similarity index 86%
rename from plugins/echonomy-framework/index.js
rename to plugins/economy-framework/index.js
index bee8caf..40a00e4 100644
--- a/plugins/echonomy-framework/index.js
+++ b/plugins/economy-framework/index.js
@@ -7,7 +7,11 @@ const multer = require("multer");
const EventEmitter = require("events");
const { ensureUserForIdentity } = require("../../src/services/users");
-const PLUGIN_ID = "echonomy-framework";
+const PLUGIN_ID = "economy-framework";
+const LEGACY_STEM = ["echo", "nomy"].join("");
+const LEGACY_PLUGIN_ID = `${LEGACY_STEM}-framework`;
+const LEGACY_FRAMEWORK_KEY = LEGACY_STEM;
+const LEGACY_NAME_PROVIDER = `${LEGACY_STEM}_name`;
const DEFAULT_SETTINGS = {
currency_name: "Coin",
currency_name_plural: "Coins",
@@ -195,6 +199,8 @@ module.exports = {
twitchClient
}) {
settingsApi = settings;
+ const repoRoot = path.join(__dirname, "..", "..");
+ migrateLegacyInstall(db, repoRoot);
ensureTables(db);
ensureDefaults(db);
startActivityRewardFlusher(db);
@@ -207,8 +213,7 @@ module.exports = {
attachTwitchListeners({ db, settings, twitchClient });
installProfileHook(app, () => getConfig(db));
- const repoRoot = path.join(__dirname, "..", "..");
- const uploadDir = path.join(repoRoot, "data", "echonomy-framework");
+ const uploadDir = path.join(repoRoot, "data", "economy-framework");
fs.mkdirSync(uploadDir, { recursive: true });
const upload = multer({
dest: uploadDir,
@@ -239,7 +244,7 @@ module.exports = {
const events = getCustomEvents(config);
const responses = Object.values(config.responses || {});
- res.render(path.join(__dirname, "views", "echonomy.ejs"), {
+ res.render(path.join(__dirname, "views", "economy.ejs"), {
title: "Economy Framework",
config,
user,
@@ -707,7 +712,7 @@ module.exports = {
return res.redirect("/profile/banking");
}
const fund = db
- .prepare("SELECT * FROM echonomy_pots WHERE id = ?")
+ .prepare("SELECT * FROM economy_pots WHERE id = ?")
.get(req.params.id);
if (!fund || fund.status !== "active") {
req.session.flash = {
@@ -737,6 +742,7 @@ module.exports = {
role: "public",
section: "plugins"
});
+ mountLegacyRedirect(web, LEGACY_PLUGIN_ID, PLUGIN_ID);
web.mount("/profile/banking", bankRouter);
}
};
@@ -750,13 +756,13 @@ function deny(res) {
function ensureTables(db) {
db.exec(`
- CREATE TABLE IF NOT EXISTS echonomy_accounts (
+ CREATE TABLE IF NOT EXISTS economy_accounts (
user_id TEXT PRIMARY KEY,
balance INTEGER NOT NULL DEFAULT 0,
updated_at INTEGER NOT NULL
);
- CREATE TABLE IF NOT EXISTS echonomy_transactions (
+ CREATE TABLE IF NOT EXISTS economy_transactions (
id TEXT PRIMARY KEY,
type TEXT NOT NULL,
amount INTEGER NOT NULL,
@@ -767,7 +773,7 @@ function ensureTables(db) {
created_at INTEGER NOT NULL
);
- CREATE TABLE IF NOT EXISTS echonomy_pots (
+ CREATE TABLE IF NOT EXISTS economy_pots (
id TEXT PRIMARY KEY,
name TEXT NOT NULL UNIQUE,
description TEXT,
@@ -778,7 +784,7 @@ function ensureTables(db) {
updated_at INTEGER NOT NULL
);
- CREATE TABLE IF NOT EXISTS echonomy_pot_contributions (
+ CREATE TABLE IF NOT EXISTS economy_pot_contributions (
id TEXT PRIMARY KEY,
pot_id TEXT NOT NULL,
user_id TEXT NOT NULL,
@@ -786,7 +792,7 @@ function ensureTables(db) {
created_at INTEGER NOT NULL
);
- CREATE TABLE IF NOT EXISTS echonomy_activity_reward_hourly (
+ CREATE TABLE IF NOT EXISTS economy_activity_reward_hourly (
user_id TEXT NOT NULL,
hour_start INTEGER NOT NULL,
source TEXT NOT NULL,
@@ -796,14 +802,162 @@ function ensureTables(db) {
PRIMARY KEY (user_id, hour_start, source)
);
- CREATE INDEX IF NOT EXISTS echonomy_transactions_created_at_idx
- ON echonomy_transactions (created_at);
+ CREATE INDEX IF NOT EXISTS economy_transactions_created_at_idx
+ ON economy_transactions (created_at);
- CREATE INDEX IF NOT EXISTS echonomy_activity_reward_hourly_hour_idx
- ON echonomy_activity_reward_hourly (hour_start);
+ CREATE INDEX IF NOT EXISTS economy_activity_reward_hourly_hour_idx
+ ON economy_activity_reward_hourly (hour_start);
`);
}
+function migrateLegacyInstall(db, repoRoot) {
+ migratePluginSettings(db);
+ migrateLegacyTables(db);
+ migrateLegacyNameProvider(db);
+ migrateLegacyIconPath(db);
+ migrateLegacyUploadDir(repoRoot);
+ mergeCommandUsage(db, `${LEGACY_FRAMEWORK_KEY}:root`, "economy:root");
+}
+
+function migratePluginSettings(db) {
+ const rows = db
+ .prepare("SELECT key, value, updated_at FROM plugin_settings WHERE plugin_id = ?")
+ .all(LEGACY_PLUGIN_ID);
+ if (!rows.length) {
+ return;
+ }
+ const insert = db.prepare(
+ "INSERT OR IGNORE INTO plugin_settings (plugin_id, key, value, updated_at) VALUES (?, ?, ?, ?)"
+ );
+ for (const row of rows) {
+ insert.run(PLUGIN_ID, row.key, row.value, row.updated_at || Date.now());
+ }
+ db.prepare("DELETE FROM plugin_settings WHERE plugin_id = ?").run(LEGACY_PLUGIN_ID);
+}
+
+function migrateLegacyTables(db) {
+ [
+ "accounts",
+ "transactions",
+ "pots",
+ "pot_contributions",
+ "activity_reward_hourly"
+ ].forEach((suffix) => {
+ migrateTable(db, `${LEGACY_STEM}_${suffix}`, `economy_${suffix}`);
+ });
+}
+
+function migrateTable(db, legacyName, currentName) {
+ if (!tableExists(db, legacyName)) {
+ return;
+ }
+ if (!tableExists(db, currentName)) {
+ db.prepare(`ALTER TABLE ${quoteIdentifier(legacyName)} RENAME TO ${quoteIdentifier(currentName)}`).run();
+ return;
+ }
+ db.prepare(
+ `INSERT OR IGNORE INTO ${quoteIdentifier(currentName)} SELECT * FROM ${quoteIdentifier(legacyName)}`
+ ).run();
+ db.prepare(`DROP TABLE ${quoteIdentifier(legacyName)}`).run();
+}
+
+function migrateLegacyNameProvider(db) {
+ if (!tableExists(db, "linked_accounts")) {
+ return;
+ }
+ db.prepare("UPDATE linked_accounts SET provider = ? WHERE provider = ?").run(
+ "economy_name",
+ LEGACY_NAME_PROVIDER
+ );
+}
+
+function migrateLegacyIconPath(db) {
+ const legacyPrefix = `/plugins/${LEGACY_PLUGIN_ID}/assets/`;
+ const currentPrefix = `/plugins/${PLUGIN_ID}/assets/`;
+ const rows = db
+ .prepare(
+ "SELECT key, value FROM plugin_settings WHERE plugin_id = ? AND key = 'currency_icon_path'"
+ )
+ .all(PLUGIN_ID);
+ for (const row of rows) {
+ if (row.value && row.value.startsWith(legacyPrefix)) {
+ setPluginSetting(db, row.key, row.value.replace(legacyPrefix, currentPrefix));
+ }
+ }
+}
+
+function migrateLegacyUploadDir(repoRoot) {
+ const legacyDir = path.join(repoRoot, "data", LEGACY_PLUGIN_ID);
+ const currentDir = path.join(repoRoot, "data", PLUGIN_ID);
+ if (!fs.existsSync(legacyDir)) {
+ return;
+ }
+ if (!fs.existsSync(currentDir)) {
+ fs.renameSync(legacyDir, currentDir);
+ return;
+ }
+ mergeDirectory(legacyDir, currentDir);
+}
+
+function mergeDirectory(sourceDir, targetDir) {
+ fs.mkdirSync(targetDir, { recursive: true });
+ for (const entry of fs.readdirSync(sourceDir, { withFileTypes: true })) {
+ const sourcePath = path.join(sourceDir, entry.name);
+ const targetPath = path.join(targetDir, entry.name);
+ if (!fs.existsSync(targetPath)) {
+ fs.renameSync(sourcePath, targetPath);
+ continue;
+ }
+ if (entry.isDirectory()) {
+ mergeDirectory(sourcePath, targetPath);
+ }
+ }
+ try {
+ fs.rmSync(sourceDir, { recursive: true, force: true });
+ } catch {
+ // Leaving the old directory is safer than failing startup.
+ }
+}
+
+function mergeCommandUsage(db, legacyId, currentId) {
+ if (!tableExists(db, "command_usage")) {
+ return;
+ }
+ const legacy = db
+ .prepare("SELECT count, updated_at FROM command_usage WHERE command_id = ?")
+ .get(legacyId);
+ if (!legacy) {
+ return;
+ }
+ db.prepare(
+ "INSERT INTO command_usage (command_id, count, updated_at) VALUES (?, ?, ?) " +
+ "ON CONFLICT(command_id) DO UPDATE SET count = command_usage.count + excluded.count, updated_at = MAX(command_usage.updated_at, excluded.updated_at)"
+ ).run(currentId, legacy.count || 0, legacy.updated_at || Date.now());
+ db.prepare("DELETE FROM command_usage WHERE command_id = ?").run(legacyId);
+}
+
+function tableExists(db, name) {
+ return Boolean(
+ db.prepare("SELECT name FROM sqlite_master WHERE type = 'table' AND name = ?").get(name)
+ );
+}
+
+function quoteIdentifier(name) {
+ return `"${name.replace(/"/g, '""')}"`;
+}
+
+function mountLegacyRedirect(web, legacyId, currentId) {
+ const legacyMount = `/plugins/${legacyId}`;
+ const router = web.createRouter();
+ router.use((req, res) => {
+ const suffix = req.originalUrl.startsWith(legacyMount)
+ ? req.originalUrl.slice(legacyMount.length)
+ : "";
+ res.redirect(308, `/plugins/${currentId}${suffix || ""}`);
+ });
+ web.mount(legacyMount, router);
+}
+
function ensureDefaults(db) {
const existing = getPluginSettings(db);
for (const [key, value] of Object.entries(DEFAULT_SETTINGS)) {
@@ -1058,7 +1212,7 @@ function queueActivityReward(
const numericHits = Number.isFinite(Number(hits)) ? Number(hits) : 0;
const numericMinutes = Number.isFinite(Number(minutes)) ? Number(minutes) : 0;
db.prepare(
- "INSERT INTO echonomy_activity_reward_hourly (user_id, hour_start, source, amount, hits, minutes) " +
+ "INSERT INTO economy_activity_reward_hourly (user_id, hour_start, source, amount, hits, minutes) " +
"VALUES (?, ?, ?, ?, ?, ?) " +
"ON CONFLICT(user_id, hour_start, source) DO UPDATE SET " +
"amount = amount + excluded.amount, " +
@@ -1093,7 +1247,7 @@ function flushActivityRewards(db) {
const rows = db
.prepare(
"SELECT user_id, hour_start, source, amount, hits, minutes " +
- "FROM echonomy_activity_reward_hourly " +
+ "FROM economy_activity_reward_hourly " +
"WHERE hour_start < ? " +
"ORDER BY hour_start ASC"
)
@@ -1129,7 +1283,7 @@ function flushActivityRewards(db) {
);
if (totalAmount <= 0) {
db.prepare(
- "DELETE FROM echonomy_activity_reward_hourly WHERE user_id = ? AND hour_start = ?"
+ "DELETE FROM economy_activity_reward_hourly WHERE user_id = ? AND hour_start = ?"
).run(group.userId, group.hourStart);
continue;
}
@@ -1146,7 +1300,7 @@ function flushActivityRewards(db) {
}
});
db.prepare(
- "DELETE FROM echonomy_activity_reward_hourly WHERE user_id = ? AND hour_start = ?"
+ "DELETE FROM economy_activity_reward_hourly WHERE user_id = ? AND hour_start = ?"
).run(group.userId, group.hourStart);
} catch (error) {
console.error("Failed to apply queued activity reward", error);
@@ -1158,7 +1312,8 @@ function registerFramework(api) {
if (!global.lumiFrameworks) {
global.lumiFrameworks = {};
}
- global.lumiFrameworks.echonomy = api;
+ global.lumiFrameworks.economy = api;
+ global.lumiFrameworks[LEGACY_FRAMEWORK_KEY] = api;
}
function buildApi({ db }) {
@@ -1200,7 +1355,7 @@ function registerCommands({ db, settings, commandRouter }) {
const triggers = [config.command.root, ...config.command.aliases];
commandRouter.registerCommands(PLUGIN_ID, [
{
- id: "echonomy:root",
+ id: "economy:root",
triggers,
platforms,
handler: (ctx) => handleCoinsCommand({ ctx, db, settings })
@@ -1642,10 +1797,10 @@ function escapeHtml(value) {
}
function installProfileHook(app, getConfig) {
- if (!app || app.__echonomyProfileHookInstalled) {
+ if (!app || app.__economyProfileHookInstalled) {
return;
}
- app.__echonomyProfileHookInstalled = true;
+ app.__economyProfileHookInstalled = true;
const originalRender = app.render.bind(app);
app.render = (view, options, callback) => {
if (typeof options === "function") {
@@ -1700,8 +1855,9 @@ async function resolveTargetUser(db, ctx, token) {
}
if (ctx.platform === "discord") {
const message = ctx.meta?.message;
- if (message?.mentions?.users?.first) {
- const mention = message.mentions.users.first();
+ const mentionId = token.match(/^<@!?(\d+)>$/)?.[1] || null;
+ const mention = mentionId ? message?.mentions?.users?.get?.(mentionId) : null;
+ if (mention?.id) {
const display =
mention.globalName || mention.username || mention.tag || mention.id;
const profile = ensureUserForIdentity({
@@ -1714,7 +1870,7 @@ async function resolveTargetUser(db, ctx, token) {
});
return { profile, label: `<@${mention.id}>` };
}
- const idMatch = token.match(/^<@!?(\d+)>$/) || token.match(/^(\d{15,})$/);
+ const idMatch = token.match(/^(\d{15,})$/) || (mentionId ? [token, mentionId] : null);
if (idMatch) {
const profile = ensureUserForIdentity({
provider: "discord",
@@ -1735,6 +1891,11 @@ async function resolveTargetUser(db, ctx, token) {
return { profile: internal, label: internal.internal_username };
}
+ const knownUser = findUserByKnownName(db, cleaned, ctx.platform);
+ if (knownUser) {
+ return { profile: knownUser, label: knownUser.internal_username };
+ }
+
if (ctx.platform === "twitch") {
const profile = ensureUserForIdentity({
provider: "twitch_login",
@@ -1756,7 +1917,7 @@ async function resolveTargetUser(db, ctx, token) {
}
const profile = ensureUserForIdentity({
- provider: "echonomy_name",
+ provider: "economy_name",
providerUserId: cleaned.toLowerCase(),
displayName: cleaned,
fallbackName: cleaned
@@ -1770,11 +1931,63 @@ function findUserByInternalName(db, name) {
"SELECT id, internal_username FROM user_profiles WHERE lower(internal_username) = lower(?)"
)
.get(name);
-}
+}
+
+function findUserByKnownName(db, name, platform) {
+ const cleaned = (name || "").trim();
+ if (!cleaned) {
+ return null;
+ }
+ const providerHints = getPlatformProviderHints(platform);
+ const providerScore = providerHints.length
+ ? `CASE WHEN provider IN (${providerHints.map(() => "?").join(", ")}) THEN 0 ELSE 1 END,`
+ : "";
+ const providerParams = providerHints.length ? providerHints : [];
+ const identity = db
+ .prepare(
+ "SELECT user_profiles.id AS id, user_profiles.internal_username AS internal_username " +
+ "FROM user_identities " +
+ "JOIN user_profiles ON user_profiles.id = user_identities.user_id " +
+ "WHERE lower(user_identities.display_name) = lower(?) " +
+ "OR lower(user_identities.provider_user_id) = lower(?) " +
+ `ORDER BY ${providerScore} user_identities.updated_at DESC LIMIT 1`
+ )
+ .get(cleaned, cleaned, ...providerParams);
+ if (identity) {
+ return identity;
+ }
+ if (!tableExists(db, "linked_accounts")) {
+ return null;
+ }
+ const linked = db
+ .prepare(
+ "SELECT user_profiles.id AS id, user_profiles.internal_username AS internal_username " +
+ "FROM linked_accounts " +
+ "JOIN user_profiles ON user_profiles.id = linked_accounts.user_id " +
+ "WHERE lower(linked_accounts.display_name) = lower(?) " +
+ "OR lower(linked_accounts.provider_user_id) = lower(?) " +
+ `ORDER BY ${providerScore.replaceAll("provider", "linked_accounts.provider")} linked_accounts.updated_at DESC LIMIT 1`
+ )
+ .get(cleaned, cleaned, ...providerParams);
+ return linked || null;
+}
+
+function getPlatformProviderHints(platform) {
+ if (platform === "discord") {
+ return ["discord"];
+ }
+ if (platform === "twitch") {
+ return ["twitch", "twitch_login"];
+ }
+ if (platform === "youtube") {
+ return ["youtube", "youtube_name"];
+ }
+ return [];
+}
function ensureAccount(db, userId) {
db.prepare(
- "INSERT INTO echonomy_accounts (user_id, balance, updated_at) VALUES (?, 0, ?) " +
+ "INSERT INTO economy_accounts (user_id, balance, updated_at) VALUES (?, 0, ?) " +
"ON CONFLICT(user_id) DO UPDATE SET updated_at = excluded.updated_at"
).run(userId, Date.now());
}
@@ -1784,7 +1997,7 @@ function getBalance(db, userId) {
return 0;
}
const row = db
- .prepare("SELECT balance FROM echonomy_accounts WHERE user_id = ?")
+ .prepare("SELECT balance FROM economy_accounts WHERE user_id = ?")
.get(userId);
return row?.balance ?? 0;
}
@@ -1792,7 +2005,7 @@ function getBalance(db, userId) {
function updateBalance(db, userId, delta) {
ensureAccount(db, userId);
db.prepare(
- "UPDATE echonomy_accounts SET balance = balance + ?, updated_at = ? WHERE user_id = ?"
+ "UPDATE economy_accounts SET balance = balance + ?, updated_at = ? WHERE user_id = ?"
).run(delta, Date.now(), userId);
}
@@ -1838,7 +2051,7 @@ function applyTransaction(db, payload) {
updateBalance(db, toUserId, amount);
}
db.prepare(
- "INSERT INTO echonomy_transactions (id, type, amount, from_user_id, to_user_id, note, meta, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?)"
+ "INSERT INTO economy_transactions (id, type, amount, from_user_id, to_user_id, note, meta, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?)"
).run(
id,
payload.type || "transaction",
@@ -1951,7 +2164,7 @@ function listTransactions(db, { userId, limit }) {
return db
.prepare(
"SELECT t.*, fromUser.internal_username AS from_name, toUser.internal_username AS to_name " +
- "FROM echonomy_transactions t " +
+ "FROM economy_transactions t " +
"LEFT JOIN user_profiles AS fromUser ON fromUser.id = t.from_user_id " +
"LEFT JOIN user_profiles AS toUser ON toUser.id = t.to_user_id " +
`${where} ORDER BY t.created_at DESC LIMIT ?`
@@ -2013,16 +2226,16 @@ function parseTransactionMeta(rawMeta) {
function buildGlobalStats(db) {
const totalBalance = db
- .prepare("SELECT COALESCE(SUM(balance), 0) AS total FROM echonomy_accounts")
+ .prepare("SELECT COALESCE(SUM(balance), 0) AS total FROM economy_accounts")
.get();
const totalSpent = db
.prepare(
- "SELECT COALESCE(SUM(amount), 0) AS total FROM echonomy_transactions " +
+ "SELECT COALESCE(SUM(amount), 0) AS total FROM economy_transactions " +
"WHERE from_user_id IS NOT NULL AND (to_user_id IS NULL OR to_user_id = '')"
)
.get();
const totalTransactions = db
- .prepare("SELECT COUNT(*) AS count FROM echonomy_transactions")
+ .prepare("SELECT COUNT(*) AS count FROM economy_transactions")
.get();
return {
totalBalance: totalBalance?.total || 0,
@@ -2044,25 +2257,25 @@ function buildUserStats(db, userId) {
const balance = getBalance(db, userId);
const totalEarned = db
.prepare(
- "SELECT COALESCE(SUM(amount), 0) AS total FROM echonomy_transactions " +
+ "SELECT COALESCE(SUM(amount), 0) AS total FROM economy_transactions " +
"WHERE to_user_id = ? AND (from_user_id IS NULL OR from_user_id = '')"
)
.get(userId);
const totalSpent = db
.prepare(
- "SELECT COALESCE(SUM(amount), 0) AS total FROM echonomy_transactions " +
+ "SELECT COALESCE(SUM(amount), 0) AS total FROM economy_transactions " +
"WHERE from_user_id = ? AND (to_user_id IS NULL OR to_user_id = '')"
)
.get(userId);
const totalReceived = db
.prepare(
- "SELECT COALESCE(SUM(amount), 0) AS total FROM echonomy_transactions " +
+ "SELECT COALESCE(SUM(amount), 0) AS total FROM economy_transactions " +
"WHERE to_user_id = ? AND from_user_id IS NOT NULL AND from_user_id != ''"
)
.get(userId);
const totalSent = db
.prepare(
- "SELECT COALESCE(SUM(amount), 0) AS total FROM echonomy_transactions " +
+ "SELECT COALESCE(SUM(amount), 0) AS total FROM economy_transactions " +
"WHERE from_user_id = ? AND to_user_id IS NOT NULL AND to_user_id != ''"
)
.get(userId);
@@ -2078,17 +2291,17 @@ function buildUserStats(db, userId) {
function listTopBalances(db, limit) {
return db
.prepare(
- "SELECT user_profiles.internal_username AS username, echonomy_accounts.balance AS balance " +
- "FROM echonomy_accounts " +
- "JOIN user_profiles ON user_profiles.id = echonomy_accounts.user_id " +
- "ORDER BY echonomy_accounts.balance DESC LIMIT ?"
+ "SELECT user_profiles.internal_username AS username, economy_accounts.balance AS balance " +
+ "FROM economy_accounts " +
+ "JOIN user_profiles ON user_profiles.id = economy_accounts.user_id " +
+ "ORDER BY economy_accounts.balance DESC LIMIT ?"
)
.all(limit);
}
function listFunds(db) {
return db
- .prepare("SELECT * FROM echonomy_pots WHERE status != 'archived' ORDER BY name")
+ .prepare("SELECT * FROM economy_pots WHERE status != 'archived' ORDER BY name")
.all();
}
@@ -2100,7 +2313,7 @@ function formatProviderLabel(provider) {
twitch_login: "Twitch",
youtube: "YouTube",
youtube_name: "YouTube",
- echonomy_name: "Internal"
+ economy_name: "Internal"
};
if (map[normalized]) {
return map[normalized];
@@ -2145,20 +2358,20 @@ function listUserDirectory(db) {
function findFund(db, name) {
return db
- .prepare("SELECT * FROM echonomy_pots WHERE lower(name) = lower(?)")
+ .prepare("SELECT * FROM economy_pots WHERE lower(name) = lower(?)")
.get(name);
}
function createFund(db, { name, description, targetAmount }) {
const now = Date.now();
db.prepare(
- "INSERT INTO echonomy_pots (id, name, description, target_amount, current_amount, status, created_at, updated_at) VALUES (?, ?, ?, ?, 0, 'active', ?, ?)"
+ "INSERT INTO economy_pots (id, name, description, target_amount, current_amount, status, created_at, updated_at) VALUES (?, ?, ?, ?, 0, 'active', ?, ?)"
).run(crypto.randomUUID(), name, description || "", targetAmount || 0, now, now);
}
function updateFund(db, { id, name, description, targetAmount, status }) {
db.prepare(
- "UPDATE echonomy_pots SET name = ?, description = ?, target_amount = ?, status = ?, updated_at = ? WHERE id = ?"
+ "UPDATE economy_pots SET name = ?, description = ?, target_amount = ?, status = ?, updated_at = ? WHERE id = ?"
).run(
name,
description || "",
@@ -2173,10 +2386,10 @@ function addFundContribution(db, fundId, userId, amount) {
const now = Date.now();
db.transaction(() => {
db.prepare(
- "INSERT INTO echonomy_pot_contributions (id, pot_id, user_id, amount, created_at) VALUES (?, ?, ?, ?, ?)"
+ "INSERT INTO economy_pot_contributions (id, pot_id, user_id, amount, created_at) VALUES (?, ?, ?, ?, ?)"
).run(crypto.randomUUID(), fundId, userId, amount, now);
db.prepare(
- "UPDATE echonomy_pots SET current_amount = current_amount + ?, updated_at = ? WHERE id = ?"
+ "UPDATE economy_pots SET current_amount = current_amount + ?, updated_at = ? WHERE id = ?"
).run(amount, now, fundId);
})();
}
diff --git a/plugins/echonomy-framework/plugin.json b/plugins/economy-framework/plugin.json
similarity index 74%
rename from plugins/echonomy-framework/plugin.json
rename to plugins/economy-framework/plugin.json
index 89f414a..de31121 100644
--- a/plugins/echonomy-framework/plugin.json
+++ b/plugins/economy-framework/plugin.json
@@ -1,7 +1,7 @@
{
- "id": "echonomy-framework",
+ "id": "economy-framework",
"name": "Economy Framework",
- "version": "0.2.7",
+ "version": "0.2.8",
"description": "Cross-platform currency framework with shared balances and extensible hooks.",
"main": "index.js"
}
diff --git a/plugins/echonomy-framework/stats.js b/plugins/economy-framework/stats.js
similarity index 66%
rename from plugins/echonomy-framework/stats.js
rename to plugins/economy-framework/stats.js
index caf644b..2924015 100644
--- a/plugins/echonomy-framework/stats.js
+++ b/plugins/economy-framework/stats.js
@@ -3,29 +3,29 @@ function getProfileStats({ db, userId }) {
return { stats: [] };
}
const account = db
- .prepare("SELECT balance FROM echonomy_accounts WHERE user_id = ?")
+ .prepare("SELECT balance FROM economy_accounts WHERE user_id = ?")
.get(userId);
const earned = db
.prepare(
- "SELECT COALESCE(SUM(amount), 0) AS total FROM echonomy_transactions " +
+ "SELECT COALESCE(SUM(amount), 0) AS total FROM economy_transactions " +
"WHERE to_user_id = ? AND (from_user_id IS NULL OR from_user_id = '')"
)
.get(userId);
const spent = db
.prepare(
- "SELECT COALESCE(SUM(amount), 0) AS total FROM echonomy_transactions " +
+ "SELECT COALESCE(SUM(amount), 0) AS total FROM economy_transactions " +
"WHERE from_user_id = ? AND (to_user_id IS NULL OR to_user_id = '')"
)
.get(userId);
const transfersOut = db
.prepare(
- "SELECT COALESCE(SUM(amount), 0) AS total FROM echonomy_transactions " +
+ "SELECT COALESCE(SUM(amount), 0) AS total FROM economy_transactions " +
"WHERE from_user_id = ? AND to_user_id IS NOT NULL AND to_user_id != ''"
)
.get(userId);
const transfersIn = db
.prepare(
- "SELECT COALESCE(SUM(amount), 0) AS total FROM echonomy_transactions " +
+ "SELECT COALESCE(SUM(amount), 0) AS total FROM economy_transactions " +
"WHERE to_user_id = ? AND from_user_id IS NOT NULL AND from_user_id != ''"
)
.get(userId);
@@ -44,10 +44,10 @@ function getProfileStats({ db, userId }) {
function getLeaderboards({ db, limit = 10 }) {
const rows = db
.prepare(
- "SELECT user_profiles.internal_username AS username, echonomy_accounts.balance AS value " +
- "FROM echonomy_accounts " +
- "JOIN user_profiles ON user_profiles.id = echonomy_accounts.user_id " +
- "ORDER BY echonomy_accounts.balance DESC LIMIT ?"
+ "SELECT user_profiles.internal_username AS username, economy_accounts.balance AS value " +
+ "FROM economy_accounts " +
+ "JOIN user_profiles ON user_profiles.id = economy_accounts.user_id " +
+ "ORDER BY economy_accounts.balance DESC LIMIT ?"
)
.all(limit);
diff --git a/plugins/echonomy-framework/stats.json b/plugins/economy-framework/stats.json
similarity index 87%
rename from plugins/echonomy-framework/stats.json
rename to plugins/economy-framework/stats.json
index d082c89..220a395 100644
--- a/plugins/echonomy-framework/stats.json
+++ b/plugins/economy-framework/stats.json
@@ -1,5 +1,5 @@
{
- "pluginId": "echonomy-framework",
+ "pluginId": "economy-framework",
"pluginName": "Economy Framework",
"provider": "stats.js",
"profile": {
diff --git a/plugins/echonomy-framework/test.txt b/plugins/economy-framework/test.txt
similarity index 100%
rename from plugins/echonomy-framework/test.txt
rename to plugins/economy-framework/test.txt
diff --git a/plugins/echonomy-framework/views/banking.ejs b/plugins/economy-framework/views/banking.ejs
similarity index 100%
rename from plugins/echonomy-framework/views/banking.ejs
rename to plugins/economy-framework/views/banking.ejs
diff --git a/plugins/echonomy-framework/views/echonomy.ejs b/plugins/economy-framework/views/economy.ejs
similarity index 89%
rename from plugins/echonomy-framework/views/echonomy.ejs
rename to plugins/economy-framework/views/economy.ejs
index 205e812..522a2b5 100644
--- a/plugins/echonomy-framework/views/echonomy.ejs
+++ b/plugins/economy-framework/views/economy.ejs
@@ -1,12 +1,12 @@
<%- include("../../../src/web/views/partials/layout-top", { title }) %>