WIP! A BB-style forum, on the ATmosphere! We're still working... we'll be back soon when we have something to show off!
node typescript hono htmx atproto

fix(appview): guard against out-of-order UPDATE in indexer; populate role_permissions in mod tests

- indexer.ts: add `if (!updated) return` before afterUpsert call so an
out-of-order firehose UPDATE that matches zero rows (CREATE not yet
received) doesn't crash with TypeError on `updated.id`
- mod.test.ts: add rolePermissions inserts for all 4 role setups so
test DB state accurately reflects the permissions each role claims
to have (ban admin: banUsers; lock/unlock mod: lockTopics)

+29 -4
+1
apps/appview/src/lib/indexer.ts
··· 576 576 ) 577 577 ) 578 578 .returning({ id: config.table.id }); 579 + if (!updated) return; // Out-of-order UPDATE before CREATE: no row to update yet 579 580 await config.afterUpsert(event, record, updated.id, tx); 580 581 } else { 581 582 await tx
+28 -4
apps/appview/src/routes/__tests__/mod.test.ts
··· 65 65 describe("POST /api/mod/ban", () => { 66 66 it("bans user successfully when admin has authority", async () => { 67 67 // Create admin and member users 68 - const { users, memberships, roles } = await import("@atbb/db"); 68 + const { users, memberships, roles, rolePermissions } = await import("@atbb/db"); 69 69 const { eq } = await import("drizzle-orm"); 70 70 71 71 // Use unique DIDs for this test ··· 103 103 .from(roles) 104 104 .where(eq(roles.rkey, "admin-role")) 105 105 .limit(1); 106 + 107 + // Grant banUsers permission to admin role 108 + await ctx.db.insert(rolePermissions).values({ 109 + roleId: adminRole.id, 110 + permission: "space.atbb.permission.banUsers", 111 + }); 106 112 107 113 // Insert memberships 108 114 const now = new Date(); ··· 633 639 describe("DELETE /api/mod/ban/:did", () => { 634 640 it("unbans user successfully when admin has authority", async () => { 635 641 // Create admin and member users 636 - const { users, memberships, roles, modActions, forums } = await import("@atbb/db"); 642 + const { users, memberships, roles, rolePermissions, modActions, forums } = await import("@atbb/db"); 637 643 const { eq } = await import("drizzle-orm"); 638 644 639 645 // Use unique DIDs for this test ··· 671 677 .from(roles) 672 678 .where(eq(roles.rkey, "unban-admin-role")) 673 679 .limit(1); 680 + 681 + // Grant banUsers permission to admin role 682 + await ctx.db.insert(rolePermissions).values({ 683 + roleId: adminRole.id, 684 + permission: "space.atbb.permission.banUsers", 685 + }); 674 686 675 687 // Insert memberships 676 688 const now = new Date(); ··· 1193 1205 1194 1206 describe("POST /api/mod/lock", () => { 1195 1207 it("locks topic successfully when moderator has authority", async () => { 1196 - const { users, memberships, roles, posts } = await import("@atbb/db"); 1208 + const { users, memberships, roles, rolePermissions, posts } = await import("@atbb/db"); 1197 1209 const { eq } = await import("drizzle-orm"); 1198 1210 1199 1211 // Use unique DIDs for this test ··· 1231 1243 .from(roles) 1232 1244 .where(eq(roles.rkey, "lock-mod-role")) 1233 1245 .limit(1); 1246 + 1247 + // Grant lockTopics permission to moderator role 1248 + await ctx.db.insert(rolePermissions).values({ 1249 + roleId: modRole.id, 1250 + permission: "space.atbb.permission.lockTopics", 1251 + }); 1234 1252 1235 1253 // Insert memberships 1236 1254 const now = new Date(); ··· 1904 1922 1905 1923 describe("DELETE /api/mod/lock/:topicId", () => { 1906 1924 it("unlocks topic successfully when moderator has authority", async () => { 1907 - const { users, memberships, roles, posts, forums, modActions } = await import("@atbb/db"); 1925 + const { users, memberships, roles, rolePermissions, posts, forums, modActions } = await import("@atbb/db"); 1908 1926 const { eq } = await import("drizzle-orm"); 1909 1927 1910 1928 // Use unique DIDs for this test ··· 1942 1960 .from(roles) 1943 1961 .where(eq(roles.rkey, "unlock-mod-role")) 1944 1962 .limit(1); 1963 + 1964 + // Grant lockTopics permission to moderator role 1965 + await ctx.db.insert(rolePermissions).values({ 1966 + roleId: modRole.id, 1967 + permission: "space.atbb.permission.lockTopics", 1968 + }); 1945 1969 1946 1970 // Insert memberships 1947 1971 const now = new Date();