import type { Did } from "@atcute/lexicons/syntax"; import type { OAuthUserAgent } from "@atcute/oauth-browser-client"; import { beforeEach, describe, expect, it, vi } from "vitest"; import { getOrCreateDelegatedSession } from "$lib/api/actAs"; import { inviteOrganizationMembers, listOrganizationMembers, removeOrganizationMember } from "$lib/api/orgMembers"; import { addController, getScopePresets, listControllers, removeController } from "$lib/api/tranquil"; vi.mock("$lib/api/actAs", () => ({ getOrCreateDelegatedSession: vi.fn() })); vi.mock("$lib/api/tranquil", () => ({ addController: vi.fn(), getScopePresets: vi.fn(), listControllers: vi.fn(), removeController: vi.fn() })); const OWNER_SCOPES = "atproto repo:* blob:*/* rpc:* identity:* account:*?action=manage transition:generic"; const EDITOR_SCOPES = "atproto repo:*?action=create repo:*?action=update blob:*/* rpc:*"; const controller = { sub: "did:plc:controller" as Did } as OAuthUserAgent; const orgAgent = { sub: "did:plc:org" as Did } as OAuthUserAgent; const orgDid = "did:plc:org" as Did; const aliceDid = "did:plc:alice" as Did; const bobDid = "did:plc:bob" as Did; beforeEach(() => { vi.resetAllMocks(); vi.mocked(getOrCreateDelegatedSession).mockResolvedValue(orgAgent); vi.mocked(getScopePresets).mockResolvedValue([ { name: "owner", label: "Owner", description: "", scopes: OWNER_SCOPES }, { name: "editor", label: "Editor", description: "", scopes: EDITOR_SCOPES } ]); }); describe("listOrganizationMembers", () => { it("lists the active controllers of the organization with their roles", async () => { vi.mocked(listControllers).mockResolvedValue([ { did: aliceDid, handle: "alice.test", grantedScopes: OWNER_SCOPES, grantedAt: "2025-01-14T09:00:00.000Z", isActive: true, isLocal: true }, { did: bobDid, grantedScopes: EDITOR_SCOPES, grantedAt: "2025-03-02T09:00:00.000Z", isActive: true, isLocal: false }, { did: "did:plc:gone" as Did, grantedScopes: EDITOR_SCOPES, grantedAt: "2025-03-03T09:00:00.000Z", isActive: false, isLocal: false } ]); const members = await listOrganizationMembers(controller, orgDid); expect(getOrCreateDelegatedSession).toHaveBeenCalledWith(controller, orgDid); expect(listControllers).toHaveBeenCalledWith(orgAgent); expect(members).toEqual([ { did: aliceDid, handle: "alice.test", role: "owner", grantedAt: "2025-01-14T09:00:00.000Z" }, { did: bobDid, handle: undefined, role: "member", grantedAt: "2025-03-02T09:00:00.000Z" } ]); }); }); describe("inviteOrganizationMembers", () => { it("adds every invitee as a controller with the editor preset", async () => { await inviteOrganizationMembers(controller, orgDid, [aliceDid, bobDid]); expect(getScopePresets).toHaveBeenCalledWith(orgAgent); expect(vi.mocked(addController).mock.calls).toEqual([ [orgAgent, { controllerDid: aliceDid, grantedScopes: EDITOR_SCOPES }], [orgAgent, { controllerDid: bobDid, grantedScopes: EDITOR_SCOPES }] ]); }); it("refuses when the PDS has no editor preset", async () => { vi.mocked(getScopePresets).mockResolvedValue([]); await expect(inviteOrganizationMembers(controller, orgDid, [aliceDid])).rejects.toThrow( /editor role/ ); expect(addController).not.toHaveBeenCalled(); }); }); describe("removeOrganizationMember", () => { it("removes the member's grant as the organization", async () => { await removeOrganizationMember(controller, orgDid, bobDid); expect(removeController).toHaveBeenCalledWith(orgAgent, bobDid); }); });