98 lines
2.7 KiB
TypeScript
98 lines
2.7 KiB
TypeScript
import "server-only";
|
|
|
|
import { PERMS } from "@/lib/permission-slugs";
|
|
import { authorizeHousekeeping } from "../../foundation/authorization";
|
|
import { satisfiesCapability } from "../../foundation/capability-context";
|
|
import {
|
|
anyCapability,
|
|
fail,
|
|
type HousekeepingCapabilityContext,
|
|
type HousekeepingInboxSource,
|
|
ok,
|
|
} from "../../foundation/contracts";
|
|
|
|
const capability = anyCapability(PERMS.ADMIN_DASHBOARD);
|
|
|
|
export interface OperationsAccessSummary {
|
|
readonly accessibleDomains: number;
|
|
}
|
|
|
|
export interface OperationsInboxAdapters {
|
|
accessSummary(
|
|
context: HousekeepingCapabilityContext,
|
|
signal: AbortSignal,
|
|
): Promise<OperationsAccessSummary>;
|
|
}
|
|
|
|
export function createOperationsInboxSources(
|
|
adapters: OperationsInboxAdapters,
|
|
): readonly HousekeepingInboxSource[] {
|
|
return [
|
|
{
|
|
id: "operations.access-summary",
|
|
owner: "operations",
|
|
capability,
|
|
async getItems(context, signal) {
|
|
const authorization = authorizeHousekeeping(context, capability);
|
|
if (!authorization.ok) return authorization;
|
|
try {
|
|
const summary = await adapters.accessSummary(context, signal);
|
|
const occurredAt = new Date().toISOString();
|
|
return ok(
|
|
{
|
|
availability: "available" as const,
|
|
items:
|
|
summary.accessibleDomains === 0
|
|
? [
|
|
{
|
|
sourceId: "operations.access-summary",
|
|
itemId: "limited-access",
|
|
deduplicationKey:
|
|
"operations.access-summary:limited-access",
|
|
domain: "operations" as const,
|
|
capability,
|
|
severity: "warning" as const,
|
|
priority: "high" as const,
|
|
ageMs: 0,
|
|
state: "limited-access",
|
|
occurredAt,
|
|
titleKey:
|
|
"pages.housekeeping.items.operationsLimitedAccess",
|
|
href: "/ase" as const,
|
|
freshness: "fresh" as const,
|
|
actions: [],
|
|
},
|
|
]
|
|
: [],
|
|
},
|
|
authorization.correlationId,
|
|
);
|
|
} catch {
|
|
return fail(
|
|
"DEPENDENCY_UNAVAILABLE",
|
|
"errors.housekeeping.dependencyUnavailable",
|
|
authorization.correlationId,
|
|
);
|
|
}
|
|
},
|
|
},
|
|
];
|
|
}
|
|
|
|
export const OPERATIONS_INBOX_SOURCES = createOperationsInboxSources({
|
|
async accessSummary(context, signal) {
|
|
if (signal.aborted) throw new Error("aborted operations access summary");
|
|
const { HOUSEKEEPING_MANIFESTS } = await import("../../manifests");
|
|
return {
|
|
accessibleDomains: HOUSEKEEPING_MANIFESTS.filter(
|
|
(domain) =>
|
|
domain.id !== "operations" &&
|
|
satisfiesCapability(context, domain.capability) &&
|
|
domain.routes.some((route) =>
|
|
satisfiesCapability(context, route.capability),
|
|
),
|
|
).length,
|
|
};
|
|
},
|
|
});
|