import { describe, expect, it, vi } from "vitest"; import { EMPTY_MODULE_CONFIGURATION, defineModuleRuntime, isModuleHttpMethod, MODULE_HTTP_METHODS, type ModuleHttpRouteRegistrar, type ModuleRegistrationContext, } from "../src/index.js"; describe("defineModuleRuntime", () => { it("defines a frozen server runtime without duplicating the static manifest", async () => { const start = vi.fn(); const runtime = defineModuleRuntime({ id: "example", start, version: "0.1.0", }); expect(runtime).toEqual({ id: "example", start, version: "0.1.0" }); expect(Object.isFrozen(runtime)).toBe(true); }); it("rejects invalid runtime definitions", () => { expect(() => defineModuleRuntime({ id: "Not Valid", version: "0.1.0", }), ).toThrow("Invalid Ekklesia module runtime definition."); }); it("re-exports the module-http contract so a module's register hook can declare routes", async () => { expect(MODULE_HTTP_METHODS).toContain("GET"); expect(isModuleHttpMethod("GET")).toBe(true); expect(isModuleHttpMethod("get")).toBe(false); const registeredRoutes: unknown[] = []; const http: ModuleHttpRouteRegistrar = { route: (definition) => { registeredRoutes.push(definition); }, }; const runtime = defineModuleRuntime({ id: "example", version: "0.1.0", register({ http: registrar }) { registrar.route({ method: "GET", path: "/records", permission: "example.records.read", maxBodyBytes: 0, handler: () => new Response(null, { status: 204 }), }); }, }); const context: ModuleRegistrationContext = { capabilities: { provide: () => undefined, resolve: () => undefined, }, // A module declaring no configuration still receives an empty snapshot rather than // `undefined`, so module code never branches on whether the platform supplied one. config: EMPTY_MODULE_CONFIGURATION, http, moduleId: "example", realtime: { channel: () => undefined }, }; await runtime.register?.(context); expect(registeredRoutes).toHaveLength(1); expect(registeredRoutes[0]).toMatchObject({ method: "GET", path: "/records" }); }); });