const assert = require("assert"); const fs = require("fs"); const path = require("path"); const root = path.join(__dirname, ".."); const sandbox = fs.mkdtempSync(path.join(root, ".tmp-lumi-command-policies-")); const serviceDir = path.join(sandbox, "src", "services"); let database = null; (async () => { try { fs.cpSync(path.join(root, "src", "services"), serviceDir, { recursive: true }); database = require(path.join(serviceDir, "db.js")); database.migrate(); const conditional = require(path.join(serviceDir, "command-conditional.js")); const policies = require(path.join(serviceDir, "command-policies.js")); const defaultGroup = policies.listGroups().find((group) => group.is_default); assert(defaultGroup, "a protected default command group must be created automatically"); assert.throws(() => policies.deleteGroup(defaultGroup.id), /cannot be deleted/); const replies = conditional.normalizeConditionalReplies([ { keyword: "backseating", response: "Please avoid backseating." }, { keyword: "spoilers", response: "No spoilers." } ]); assert.strictEqual(conditional.findConditionalReply(replies, "backseating").match.response, "Please avoid backseating."); const fuzzy = conditional.findConditionalReply(replies, "backseatng"); assert.strictEqual(fuzzy.match.keyword, "backseating"); assert.strictEqual(fuzzy.fuzzy, true); assert.strictEqual(conditional.findConditionalReply(replies, "something unrelated").match, null); const aliases = conditional.conditionalRepliesFromBody({ conditional_keyword: "backseat, backseating, hints", conditional_response: "Please ask before helping." }); assert.strictEqual(aliases.ok, true); assert.strictEqual(aliases.replies[0].keyword, "backseat, backseating, hints"); assert.strictEqual(conditional.normalizeConditionalReplyRows(JSON.stringify(aliases.replies))[0].keyword, "backseat, backseating, hints"); for (const alias of ["backseat", "backseating", "hints"]) { assert.strictEqual(conditional.findConditionalReply(aliases.replies, alias).match.response, "Please ask before helping."); } const duplicateAlias = conditional.conditionalRepliesFromBody({ conditional_keyword: ["spoilers, leaks", "leaks"], conditional_response: ["First", "Second"] }); assert.strictEqual(duplicateAlias.ok, false); assert.match(duplicateAlias.errors[0], /leaks.*more than once/); const groupId = policies.createGroup({ name: "Verification group", policy: { window: { uses: 3, seconds: 30, scope: "global" }, requirement: { role: "subscriber", subscriberTier: 2 }, cost: { amount: 5 } } }); const key = policies.commandKey("verification", "hello"); policies.saveCommandPolicy(key, { window: { uses: 1, seconds: 60, scope: "user" }, requirement: false, cost: { amount: 2 } }, [groupId]); const resolved = policies.resolvePolicy(key); assert.strictEqual(resolved.windows.length, 1, "a direct rate limit must replace group limits"); assert.strictEqual(resolved.windows[0].value.uses, 1); assert.strictEqual(resolved.requirements.length, 0, "a direct public setting must replace group roles"); assert.strictEqual(resolved.cost, 2, "a direct cost must replace the group cost"); policies.updateGroup(defaultGroup.id, { name: defaultGroup.name, description: defaultGroup.description, policy: { window: { uses: 4, seconds: 90, scope: "global" } } }); const inheritedKey = policies.commandKey("verification", "inherited"); assert.strictEqual(policies.resolvePolicy(inheritedKey).windows[0].value.uses, 4, "the default group must apply without explicit membership"); policies.saveCommandPolicies([ { commandKey: inheritedKey, policy: { cost: { amount: 3 } }, groupIds: [] }, { commandKey: policies.commandKey("verification", "second"), policy: { requirement: false }, groupIds: [groupId] } ]); assert.strictEqual(policies.resolvePolicy(inheritedKey).cost, 3, "batch saves must persist every submitted command"); const charges = []; global.lumiFrameworks = { economy: { removeBalance(payload) { charges.push(["charge", payload]); return { ok: true }; }, addBalance(payload) { charges.push(["refund", payload]); return "refund-id"; } } }; const ctx = { platform: "discord", trigger: "hello", raw: "!hello", user: { id: "verification-user", platformId: "platform-user" }, platformUser: { id: "platform-user" }, meta: {} }; const first = await policies.beginCommandUse({ commandKey: key, ctx }); assert.strictEqual(first.allowed, true); assert.strictEqual(charges[0][0], "charge"); const limited = await policies.beginCommandUse({ commandKey: key, ctx }); assert.strictEqual(limited.allowed, false, "the second use inside the window must be denied"); await first.rollback("verification"); assert.strictEqual(charges[1][0], "refund", "failed commands must refund their logged currency cost"); const afterRollback = await policies.beginCommandUse({ commandKey: key, ctx }); assert.strictEqual(afterRollback.allowed, true, "rollback must release the rate-limit reservation"); await afterRollback.commit(); const dbColumns = database.db.prepare("PRAGMA table_info(custom_commands)").all().map((column) => column.name); assert(dbColumns.includes("conditional_replies_json")); assert(dbColumns.includes("conditional_fuzzy")); assert(database.db.prepare("PRAGMA table_info(command_groups)").all().some((column) => column.name === "is_default")); for (const table of ["command_groups", "command_group_members", "command_policies", "command_policy_uses", "command_stream_sessions"]) { assert(database.db.prepare("SELECT name FROM sqlite_master WHERE type = 'table' AND name = ?").get(table), `missing ${table}`); } const server = fs.readFileSync(path.join(root, "src", "web", "server.js"), "utf8"); const view = fs.readFileSync(path.join(root, "src", "web", "views", "admin-command-policies.ejs"), "utf8"); const commandView = fs.readFileSync(path.join(root, "src", "web", "views", "admin-commands.ejs"), "utf8"); assert(server.includes('/admin/command-policies') && server.includes('commandPolicyFromBody')); assert(view.includes("Command groups") && view.includes("Save all command settings")); assert(view.includes("data-policy-search") && view.includes("data-policy-setting-filter")); assert(view.includes("Protected default") && view.includes("data-command-policy-batch")); assert(commandView.includes('value="conditional"') && commandView.includes("data-conditional-replies")); assert(commandView.includes("Separate aliases with commas")); database.db.close(); database = null; console.log("Command policies and conditional commands verified."); } finally { try { database?.db?.close?.(); } catch {} fs.rmSync(sandbox, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); } })().catch((error) => { console.error(error); process.exitCode = 1; });