import { describe, expect, it } from "vitest"; import { ANONYMOUS_PRINCIPAL, createAuthenticatedPrincipal, type EkklesiaPrincipal, type EkklesiaUserId, isAnonymousPrincipal, isAuthenticatedPrincipal, parseEkklesiaUserId, safeParseEkklesiaUserId, } from "../src/index.js"; describe("Ekklesia identity contracts", () => { it("parses a valid opaque user id", () => { expect(parseEkklesiaUserId("user_123")).toBe("user_123"); }); it("is opaque at the type level: a plain string is not assignable without parsing", () => { // @ts-expect-error a bare string must not satisfy the branded EkklesiaUserId type. const notAllowed: EkklesiaUserId = "raw-string"; expect(notAllowed).toBe("raw-string"); // the brand adds no runtime wrapper or tag }); it("serializes as a plain opaque string despite the type-level brand", () => { const userId = parseEkklesiaUserId("user_123"); expect(JSON.stringify({ userId })).toBe('{"userId":"user_123"}'); expect(`${userId}`).toBe("user_123"); expect(typeof userId).toBe("string"); }); it("does not assume any particular id format such as UUID", () => { expect(() => parseEkklesiaUserId("not-a-uuid-at-all")).not.toThrow(); expect(() => parseEkklesiaUserId("2aKp4jPeV1QbXwyz1OH6IcAUfl2n1fc1")).not.toThrow(); }); it("rejects an empty or oversized user id", () => { expect(() => parseEkklesiaUserId("")).toThrow(); expect(() => parseEkklesiaUserId(" ")).toThrow(); expect(() => parseEkklesiaUserId("x".repeat(129))).toThrow(); expect(() => parseEkklesiaUserId(42)).toThrow(); expect(() => parseEkklesiaUserId(null)).toThrow(); expect(() => parseEkklesiaUserId(undefined)).toThrow(); }); it("exposes a safe-parse variant that never throws", () => { expect(safeParseEkklesiaUserId("user_123").success).toBe(true); const failed = safeParseEkklesiaUserId(""); expect(failed.success).toBe(false); }); it("returns a frozen, stable anonymous principal singleton", () => { expect(ANONYMOUS_PRINCIPAL).toEqual({ kind: "anonymous" }); expect(Object.isFrozen(ANONYMOUS_PRINCIPAL)).toBe(true); expect(isAnonymousPrincipal(ANONYMOUS_PRINCIPAL)).toBe(true); expect(isAuthenticatedPrincipal(ANONYMOUS_PRINCIPAL)).toBe(false); }); it("creates a frozen authenticated principal carrying only the opaque user id", () => { const principal = createAuthenticatedPrincipal("user_123"); expect(principal.kind).toBe("authenticated"); expect(principal.userId).toBe("user_123"); expect(Object.isFrozen(principal)).toBe(true); expect(isAuthenticatedPrincipal(principal)).toBe(true); expect(isAnonymousPrincipal(principal)).toBe(false); expect(Object.keys(principal).sort()).toEqual(["kind", "userId"]); }); it("rejects an invalid user id when creating an authenticated principal", () => { expect(() => createAuthenticatedPrincipal("")).toThrow(); expect(() => createAuthenticatedPrincipal(42)).toThrow(); }); it("discriminates principals on kind without any role, permission, or profile fields", () => { const principals: EkklesiaPrincipal[] = [ ANONYMOUS_PRINCIPAL, createAuthenticatedPrincipal("user_123"), ]; for (const principal of principals) { expect(["anonymous", "authenticated"]).toContain(principal.kind); expect(Object.keys(principal)).not.toContain("email"); expect(Object.keys(principal)).not.toContain("roles"); expect(Object.keys(principal)).not.toContain("permissions"); expect(Object.keys(principal)).not.toContain("organizationId"); expect(Object.keys(principal)).not.toContain("sessionToken"); } }); });