fix: close housekeeping foundation review findings
This commit is contained in:
1 parent
ebc263da35
commit
08f8d54888
21 files changed
+593
-46
No files matched your search
@@ -7,6 +7,11 @@ import type {
|
||||
|
||||
const approvedDomainIds = new Set<string>(HOUSEKEEPING_DOMAIN_IDS);
|
||||
const knownCapabilitySlugs = new Set<string>(Object.values(PERMS));
|
||||
interface OwnedRegistryEntry {
|
||||
id: string;
|
||||
owner: HousekeepingDomainManifest["id"];
|
||||
capability: CapabilityRequirement;
|
||||
}
|
||||
|
||||
export interface HousekeepingRegistry {
|
||||
domains: readonly HousekeepingDomainManifest[];
|
||||
@@ -18,6 +23,7 @@ export function createHousekeepingRegistry(
|
||||
const domainIds = new Set<string>();
|
||||
const routeIds = new Set<string>();
|
||||
const routeHrefs = new Set<string>();
|
||||
const registryEntryIds = new Set<string>();
|
||||
|
||||
for (const manifest of manifests) {
|
||||
if (!approvedDomainIds.has(manifest.id)) {
|
||||
@@ -34,6 +40,29 @@ export function createHousekeepingRegistry(
|
||||
validateNonEmpty(manifest.labelKey, "label key");
|
||||
validateNonEmpty(manifest.descriptionKey, "description key");
|
||||
validateCapability(manifest.capability);
|
||||
validateOwnedRegistryEntries(
|
||||
manifest.searchProviders,
|
||||
manifest.id,
|
||||
"search provider",
|
||||
registryEntryIds,
|
||||
);
|
||||
validateOwnedRegistryEntries(
|
||||
manifest.inboxSources,
|
||||
manifest.id,
|
||||
"inbox source",
|
||||
registryEntryIds,
|
||||
);
|
||||
validateOwnedRegistryEntries(
|
||||
manifest.widgets,
|
||||
manifest.id,
|
||||
"widget",
|
||||
registryEntryIds,
|
||||
);
|
||||
for (const widget of manifest.widgets) {
|
||||
if (widget.kind !== "mandatory" && widget.kind !== "optional") {
|
||||
throw new Error(`invalid widget kind: ${widget.id}`);
|
||||
}
|
||||
}
|
||||
|
||||
for (const route of manifest.routes) {
|
||||
validateNonEmpty(route.id, "route id");
|
||||
@@ -56,18 +85,51 @@ export function createHousekeepingRegistry(
|
||||
return { domains: Object.freeze([...manifests]) };
|
||||
}
|
||||
|
||||
function validateOwnedRegistryEntries(
|
||||
entries: readonly OwnedRegistryEntry[],
|
||||
owner: HousekeepingDomainManifest["id"],
|
||||
kind: "search provider" | "inbox source" | "widget",
|
||||
ids: Set<string>,
|
||||
): void {
|
||||
for (const entry of entries) {
|
||||
validateNonEmpty(entry.id, `${kind} id`);
|
||||
if (ids.has(entry.id)) {
|
||||
throw new Error(`duplicate ${kind} id: ${entry.id}`);
|
||||
}
|
||||
ids.add(entry.id);
|
||||
|
||||
if (entry.owner !== owner) {
|
||||
throw new Error(`${kind} owner mismatch: ${entry.id}`);
|
||||
}
|
||||
|
||||
validateCapability(entry.capability);
|
||||
}
|
||||
}
|
||||
|
||||
function validateNonEmpty(value: string, name: string): void {
|
||||
if (!value.trim()) {
|
||||
if (typeof value !== "string" || !value.trim()) {
|
||||
throw new Error(`empty ${name}`);
|
||||
}
|
||||
}
|
||||
|
||||
function validateCapability(requirement: CapabilityRequirement): void {
|
||||
if (
|
||||
typeof requirement !== "object" ||
|
||||
requirement === null ||
|
||||
(requirement.mode !== "any" && requirement.mode !== "all") ||
|
||||
!Array.isArray(requirement.slugs)
|
||||
) {
|
||||
throw new Error("invalid capability requirement");
|
||||
}
|
||||
|
||||
if (requirement.slugs.length === 0) {
|
||||
throw new Error("empty capability requirement");
|
||||
}
|
||||
|
||||
for (const slug of requirement.slugs) {
|
||||
if (typeof slug !== "string") {
|
||||
throw new Error("invalid capability requirement");
|
||||
}
|
||||
if (!knownCapabilitySlugs.has(slug)) {
|
||||
throw new Error(`unknown capability slug: ${slug}`);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user