import { CompatibleOperationOrTombstone, defs, IndexedEntry, IndexedEntryLog, processIndexedEntryLog, } from "@atcute/did-plc"; import { createEffect, createResource, createSignal, For, Show } from "solid-js"; import { localDateFromTimestamp } from "../utils/date.js"; import { createOperationHistory, DiffEntry, groupBy } from "../utils/plc-logs.js"; type PlcEvent = "handle" | "rotation_key" | "service" | "verification_method"; export const PlcLogView = (props: { did: string }) => { const [activePlcEvent, setActivePlcEvent] = createSignal(); const [validLog, setValidLog] = createSignal(undefined); const [rawLogs, setRawLogs] = createSignal(undefined); const shouldShowDiff = (diff: DiffEntry) => !activePlcEvent() || diff.type.startsWith(activePlcEvent()!); const shouldShowEntry = (diffs: DiffEntry[]) => !activePlcEvent() || diffs.some((d) => d.type.startsWith(activePlcEvent()!)); const fetchPlcLogs = async () => { const res = await fetch( `${localStorage.plcDirectory ?? "https://plc.directory"}/${props.did}/log/audit`, ); const json = await res.json(); const logs = defs.indexedEntryLog.parse(json); setRawLogs(logs); const opHistory = createOperationHistory(logs).reverse(); return Array.from(groupBy(opHistory, (item) => item.orig)); }; const validateLog = async (logs: IndexedEntryLog) => { try { await processIndexedEntryLog(props.did as any, logs); setValidLog(true); } catch (e) { console.error(e); setValidLog(false); } }; const [plcOps] = createResource<[IndexedEntry, DiffEntry[]][]>(fetchPlcLogs); createEffect(() => { const logs = rawLogs(); if (logs) { setValidLog(undefined); // Defer validation to next tick to avoid blocking rendering setTimeout(() => validateLog(logs), 0); } }); const FilterButton = (props: { icon: string; event: PlcEvent; label: string }) => { const isActive = () => activePlcEvent() === props.event; const toggleFilter = () => setActivePlcEvent(isActive() ? undefined : props.event); return ( ); }; const DiffItem = (props: { diff: DiffEntry }) => { const diff = props.diff; const getDiffConfig = () => { switch (diff.type) { case "identity_created": return { icon: "lucide--bell", title: "Identity created" }; case "identity_tombstoned": return { icon: "lucide--skull", title: "Identity tombstoned" }; case "handle_added": return { icon: "lucide--at-sign", title: "Alias added", value: diff.handle, isAddition: true, }; case "handle_removed": return { icon: "lucide--at-sign", title: "Alias removed", value: diff.handle, isRemoval: true, }; case "handle_changed": return { icon: "lucide--at-sign", title: "Alias updated", oldValue: diff.prev_handle, newValue: diff.next_handle, }; case "rotation_key_added": return { icon: "lucide--key-round", title: "Rotation key added", value: diff.rotation_key, isAddition: true, }; case "rotation_key_removed": return { icon: "lucide--key-round", title: "Rotation key removed", value: diff.rotation_key, isRemoval: true, }; case "service_added": return { icon: "lucide--hard-drive", title: "Service added", badge: diff.service_id, value: diff.service_endpoint, isAddition: true, }; case "service_removed": return { icon: "lucide--hard-drive", title: "Service removed", badge: diff.service_id, value: diff.service_endpoint, isRemoval: true, }; case "service_changed": return { icon: "lucide--hard-drive", title: "Service updated", badge: diff.service_id, oldValue: diff.prev_service_endpoint, newValue: diff.next_service_endpoint, }; case "verification_method_added": return { icon: "lucide--shield-check", title: "Verification method added", badge: diff.method_id, value: diff.method_key, isAddition: true, }; case "verification_method_removed": return { icon: "lucide--shield-check", title: "Verification method removed", badge: diff.method_id, value: diff.method_key, isRemoval: true, }; case "verification_method_changed": return { icon: "lucide--shield-check", title: "Verification method updated", badge: diff.method_id, oldValue: diff.prev_method_key, newValue: diff.next_method_key, }; default: return { icon: "lucide--circle-help", title: "Unknown log entry" }; } }; const config = getDiffConfig(); const { icon, title, value = "", oldValue = "", newValue = "", badge = "", isAddition = false, isRemoval = false, } = config; return (

{title}

#{badge} Nullified
+ {value}
{oldValue}
+ {newValue}
); }; return (

Filter by type

Valid log Log validation failed Validating log...
{([entry, diffs]) => (
{localDateFromTimestamp(new Date(entry.createdAt).getTime())}
{(diff) => }
)}
); };