- The raw-source contract tests read files from disk (rawSources.testkit) instead of import.meta.glob, which knip counted as importing every src file — its unused-files lane could never name an orphan. knip now names src/watchMain.tsx as an entry (registered in docs/gates.md). - vite build fails when index.html or watch.html is not emitted. - The watch-entry import walk follows dynamic import() too. - audit_metrics.py's plan-code patterns are held equal to the guard's. - CrashBoundary is domain-free: it moves into components/ui.
31 lines
1.1 KiB
TypeScript
31 lines
1.1 KiB
TypeScript
import type { ReactNode } from "react";
|
|
import i18n from "../i18n";
|
|
import { notify } from "../lib/notifications";
|
|
import { CrashBoundary, type CrashCopy } from "./ui/CrashBoundary";
|
|
|
|
const copy = (): CrashCopy => ({
|
|
title: i18n.t("errors.boundary.title"),
|
|
subtitle: i18n.t("errors.boundary.subtitle"),
|
|
reload: i18n.t("errors.boundary.reload"),
|
|
});
|
|
|
|
// A fatal notification, kept in the center across the reload.
|
|
const onCrash = () =>
|
|
notify({
|
|
level: "fatal",
|
|
title: i18n.t("errors.boundary.notifTitle"),
|
|
// Never the raw `error.message`: a JS engine's English ("Cannot read properties of undefined…")
|
|
// is no message for the reader — the `ui.crash` log carries it for diagnosis.
|
|
message: i18n.t("errors.boundary.notifMessage"),
|
|
requiresInteraction: true,
|
|
});
|
|
|
|
// The app's crash boundary: `CrashBoundary` in the app's language, plus the notice in the center.
|
|
export default function ErrorBoundary({ children }: { children: ReactNode }) {
|
|
return (
|
|
<CrashBoundary copy={copy} onCrash={onCrash}>
|
|
{children}
|
|
</CrashBoundary>
|
|
);
|
|
}
|