// Standalone JS port of `lib/session.ts::canMutate` and `isCustomerOwner` // for offline verification. // // SessionUser shape mirrors the TypeScript interface: // { roles: Role[], isPlatform: boolean, ... } function canMutate(user) { return user.isPlatform || user.roles.includes("owner"); } function isCustomerOwner(user) { return !user.isPlatform && user.roles.includes("owner"); } const cases = [ // [user, fn, expected, note] [{ isPlatform: true, roles: ["platform_admin"] }, canMutate, true, "platform admin can mutate"], [{ isPlatform: true, roles: ["platform_operator"] }, canMutate, true, "platform operator can mutate"], [{ isPlatform: false, roles: ["owner"] }, canMutate, true, "customer owner can mutate"], [{ isPlatform: false, roles: ["user"] }, canMutate, false, "customer user cannot mutate"], [{ isPlatform: false, roles: [] }, canMutate, false, "no roles cannot mutate"], [{ isPlatform: false, roles: ["owner", "user"] }, canMutate, true, "owner+user (owner wins)"], [{ isPlatform: true, roles: ["platform_admin", "owner"] }, isCustomerOwner, false, "platform user with owner role is NOT customerOwner"], [{ isPlatform: false, roles: ["owner"] }, isCustomerOwner, true, "pure customer owner"], [{ isPlatform: false, roles: ["user"] }, isCustomerOwner, false, "customer user is not customerOwner"], [{ isPlatform: false, roles: [] }, isCustomerOwner, false, "empty roles is not customerOwner"], ]; let pass = 0, fail = 0; for (const [user, fn, expected, note] of cases) { const got = fn(user); const ok = got === expected; console.log(`${ok ? "PASS" : "FAIL"} got=${got} want=${expected} [${note}]`); if (ok) pass++; else fail++; } console.log(`\n${pass} pass, ${fail} fail`); process.exit(fail === 0 ? 0 : 1);