feat: define housekeeping foundation contracts

This commit is contained in:
Simo committed 2026-08-25 19:06:23 +02:00
1 parent 3b3d7780c9
commit 7d62a04f0e
10 files changed
+338

No files matched your search

@@ -0,0 +1,121 @@
import { describe, expect, it } from "vitest";
import {
allCapabilities,
anyCapability,
type CapabilityRequirement,
fail,
type HousekeepingCommand,
type HousekeepingDomainManifest,
type HousekeepingInboxSource,
type HousekeepingInboxSourceResult,
type HousekeepingQuery,
type HousekeepingSearchProvider,
type HousekeepingSearchResult,
type HousekeepingWidgetDefinition,
type HousekeepingWorkItem,
ok,
} from ".";
const capability = anyCapability("admin.users.view");
const workItem = {
sourceId: "tickets",
itemId: "ticket-42",
deduplicationKey: "ticket:42",
domain: "people",
capability,
severity: "warning",
occurredAt: "2026-08-24T12:00:00.000Z",
titleKey: "pages.housekeeping.items.ticket",
context: { ticketId: "42" },
href: "/admin-next/people/tickets/42",
freshness: "fresh",
} satisfies HousekeepingWorkItem;
const searchResult = {
id: "user-42",
domain: "people",
title: "operator",
href: "/admin-next/people/users/42",
} satisfies HousekeepingSearchResult;
const searchProvider: HousekeepingSearchProvider = {
search: async () => ok([searchResult], "search-1"),
};
const inboxSourceResult = {
items: [workItem],
availability: "available",
} satisfies HousekeepingInboxSourceResult;
const inboxSource: HousekeepingInboxSource = {
getItems: async () => ok(inboxSourceResult, "inbox-1"),
};
const widget: HousekeepingWidgetDefinition = {
load: async () => ok({ count: 2 }, "widget-1"),
};
const query: HousekeepingQuery<{ id: number }, { id: number }> = {
id: "people.user",
owner: "people",
capability,
run: async (_context, input) => ok(input, "query-1"),
};
const command: HousekeepingCommand<{ id: number }, { id: number }> = {
id: "people.user.disable",
owner: "people",
risk: "sensitive",
capability,
requiresReason: true,
execute: async (_context, input) => ok(input, "command-1"),
};
const manifest: HousekeepingDomainManifest = {
id: "people",
labelKey: "pages.housekeeping.domains.people.title",
descriptionKey: "pages.housekeeping.domains.people.description",
iconId: "users",
previewHref: "/admin-next/people",
capability,
routes: [],
};
describe("housekeeping foundation contracts", () => {
it("creates typed success and error results", () => {
expect(ok({ count: 2 }, "corr-1")).toEqual({
ok: true,
data: { count: 2 },
correlationId: "corr-1",
});
expect(fail("CAPABILITY_DENIED", "corr-2")).toEqual({
ok: false,
error: { code: "CAPABILITY_DENIED" },
correlationId: "corr-2",
});
});
it("rejects empty capability requirements", () => {
expect(() => anyCapability()).toThrow("capability requirement is empty");
expect(() => allCapabilities()).toThrow("capability requirement is empty");
});
it("exports assignable type-only contracts", () => {
const requirements: readonly CapabilityRequirement[] = [
capability,
allCapabilities("admin.users.view"),
];
expect([
workItem,
searchProvider,
inboxSource,
widget,
query,
command,
manifest,
requirements,
]).toHaveLength(8);
});
});