Skip to content
Source
Sign inSign up

KeybindingsUpdateToast.logic.ts

46 lines1.5 KB

1import type { ServerConfigStreamEvent } from "@t3tools/contracts";
2​
3const KEYBINDINGS_TOAST_COOLDOWN_MS = 2_000;
4​
5export type KeybindingsUpdateToastDecision =
6 | { readonly _tag: "Success" }
7 | { readonly _tag: "InvalidConfiguration"; readonly message: string };
8​
9export interface KeybindingsUpdateToastController {
10 readonly handle: (event: ServerConfigStreamEvent | null) => KeybindingsUpdateToastDecision | null;
12​
13export function createKeybindingsUpdateToastController(input: {
14 readonly now?: () => number;
15}): KeybindingsUpdateToastController {
16 const now = input.now ?? Date.now;
17 let lastToast: { readonly key: string; readonly at: number } | null = null;
18​
19 return {
20 handle: (event) => {
21 if (event?.type !== "keybindingsUpdated") {
22 return null;
23 }
24​
25 const issue = event.payload.issues.find((entry) => entry.kind.startsWith("keybindings."));
26 const decision: KeybindingsUpdateToastDecision = issue
27 ? { _tag: "InvalidConfiguration", message: issue.message }
28 : { _tag: "Success" };
29​
30 // A save and the server's file watcher each publish the same snapshot,
31 // so an identical toast inside the cooldown is the same change twice.
32 const key = issue ? `invalid:${issue.message}` : "success";
33 const currentTime = now();
34 if (
35 lastToast !== null &&
36 lastToast.key === key &&
37 currentTime - lastToast.at < KEYBINDINGS_TOAST_COOLDOWN_MS
38 ) {
39 return null;
40 }
41​
42 lastToast = { key, at: currentTime };
43 return decision;
44 },
45 };