Files
buzz-sheet/lib/events/invalidation.ts
T

84 lines
2.0 KiB
TypeScript

export const INVALIDATION_TYPES = [
"directory.updated",
"page.updated",
"data-source.updated",
"admin.updated",
] as const;
export type InvalidationType = (typeof INVALIDATION_TYPES)[number];
export interface InvalidationEvent {
type: InvalidationType;
id: string;
version: number;
}
export interface OutboxEventLike {
aggregateId: string;
eventType: string;
payload: Record<string, unknown>;
topic: string;
}
function isInvalidationType(value: string): value is InvalidationType {
return INVALIDATION_TYPES.some((type) => type === value);
}
export function expectedTopic(event: InvalidationEvent): string {
switch (event.type) {
case "directory.updated":
return "directory";
case "page.updated":
return `page:${event.id}`;
case "data-source.updated":
return `data-source:${event.id}`;
case "admin.updated":
return "admin";
}
}
export function toInvalidationEvent(
record: OutboxEventLike,
): InvalidationEvent | null {
if (!isInvalidationType(record.eventType)) return null;
const id = record.payload.id;
const version = record.payload.version;
if (
typeof id !== "string" ||
id !== record.aggregateId ||
typeof version !== "number" ||
!Number.isSafeInteger(version) ||
version < 0
) {
return null;
}
const event: InvalidationEvent = {
type: record.eventType,
id,
version,
};
return expectedTopic(event) === record.topic ? event : null;
}
export function parseInvalidationEvent(value: string): InvalidationEvent | null {
try {
const parsed = JSON.parse(value) as Record<string, unknown>;
const type = parsed.type;
const id = parsed.id;
const version = parsed.version;
if (
typeof type !== "string" ||
!isInvalidationType(type) ||
typeof id !== "string" ||
typeof version !== "number" ||
!Number.isSafeInteger(version) ||
version < 0
) {
return null;
}
return { type, id, version };
} catch {
return null;
}
}