@djangocfg/debuger 2.1.356 → 2.1.357

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -21,7 +21,15 @@ interface DebugPanelProps {
21
21
  defaultHeight?: number;
22
22
  defaultWidth?: number;
23
23
  }
24
- declare function DebugPanel({ tabs: customTabs, position, defaultHeight, defaultWidth, }: DebugPanelProps): react_jsx_runtime.JSX.Element | null;
24
+ /**
25
+ * DebugPanel — floating debug panel with tabs (logs, audio, custom).
26
+ *
27
+ * Memoised: re-renders only when `tabs`, `position`, `defaultHeight`
28
+ * or `defaultWidth` change. `tabs` array is compared by reference —
29
+ * consumers should define it outside the component or memoise it.
30
+ */
31
+ declare function DebugPanelRaw({ tabs: customTabs, position, defaultHeight, defaultWidth, }: DebugPanelProps): react_jsx_runtime.JSX.Element | null;
32
+ declare const DebugPanel: React.MemoExoticComponent<typeof DebugPanelRaw>;
25
33
 
26
34
  interface DebugButtonProps {
27
35
  className?: string;
@@ -30,16 +38,32 @@ interface DebugButtonProps {
30
38
  /** Explicitly disable. Default: undefined (auto — visible in dev, hidden in prod, ?debug=1 always works) */
31
39
  enabled?: boolean;
32
40
  }
33
- declare function DebugButton({ className, panel, enabled }: DebugButtonProps): react_jsx_runtime.JSX.Element | null;
41
+ declare function DebugButtonRaw({ className, panel, enabled }: DebugButtonProps): react_jsx_runtime.JSX.Element | null;
42
+ declare const DebugButton: React.MemoExoticComponent<typeof DebugButtonRaw>;
34
43
 
35
- declare function LogsPanel({ isActive }: {
44
+ /**
45
+ * LogsPanel — virtualised log viewer with filters and search.
46
+ *
47
+ * Memoised: re-renders only when `isActive` changes. Internal filter
48
+ * state and log store subscriptions are isolated and do not propagate
49
+ * to parent components.
50
+ */
51
+ declare function LogsPanelRaw({ isActive }: {
36
52
  isActive: boolean;
37
53
  }): react_jsx_runtime.JSX.Element;
54
+ declare const LogsPanel: React.MemoExoticComponent<typeof LogsPanelRaw>;
38
55
 
39
56
  interface AudioDebugPanelProps {
40
57
  isActive: boolean;
41
58
  }
42
- declare function AudioDebugPanel({ isActive }: AudioDebugPanelProps): react_jsx_runtime.JSX.Element;
59
+ /**
60
+ * AudioDebugPanel — real-time audio event log with metrics.
61
+ *
62
+ * Memoised: re-renders only when `isActive` changes. Internal event
63
+ * log state is managed by the hook and does not break memoisation.
64
+ */
65
+ declare function AudioDebugPanelRaw({ isActive }: AudioDebugPanelProps): react_jsx_runtime.JSX.Element;
66
+ declare const AudioDebugPanel: React.MemoExoticComponent<typeof AudioDebugPanelRaw>;
43
67
 
44
68
  interface StorePanelProps {
45
69
  /** Display label shown above the JSON tree */
@@ -74,8 +98,13 @@ interface StorePanelProps {
74
98
  * getState={() => useTimelineStore.getState()}
75
99
  * isActive={isActive}
76
100
  * />
101
+ *
102
+ * Memoised: re-renders only when `label`, `getState`, `intervalMs` or
103
+ * `isActive` change. `getState` is compared by reference — callers should
104
+ * stabilise it (e.g. define outside the component or wrap in useCallback).
77
105
  */
78
- declare function StorePanel({ label, getState, intervalMs, isActive }: StorePanelProps): react_jsx_runtime.JSX.Element;
106
+ declare function StorePanelRaw({ label, getState, intervalMs, isActive }: StorePanelProps): react_jsx_runtime.JSX.Element;
107
+ declare const StorePanel: React.MemoExoticComponent<typeof StorePanelRaw>;
79
108
 
80
109
  type DebugTab = 'logs' | 'audio' | 'pipeline' | 'custom';
81
110
  interface DebugStore {
package/dist/index.mjs CHANGED
@@ -3,7 +3,7 @@ export { clearAudioEventBuffer, emitAudioEvent, emitDebugEvent, hasAudioListener
3
3
  import { useDebugLogStore, useDebugFilteredLogs, useDebugLogCount, useDebugErrorCount } from './chunk-YFJMBXZY.mjs';
4
4
  export { createDebugLogger, debugLog, useDebugErrorCount, useDebugFilteredLogs, useDebugLogCount, useDebugLogStore } from './chunk-YFJMBXZY.mjs';
5
5
  import { __name } from './chunk-2JTKI4GS.mjs';
6
- import { useState, useRef, useEffect, useCallback, useMemo } from 'react';
6
+ import { memo, useState, useRef, useEffect, useCallback, useMemo } from 'react';
7
7
  import { CheckCircle, AlertCircle, AlertTriangle, Info, Bug, ChevronUp, ChevronDown, Search, Download, Trash2, Radio, ScrollText, Maximize2, Minimize2, X, Database } from 'lucide-react';
8
8
  import { Badge, Input, Tooltip, TooltipTrigger, Button, TooltipContent, CopyButton, ScrollArea } from '@djangocfg/ui-core/components';
9
9
  import { cn, isDev } from '@djangocfg/ui-core/lib';
@@ -93,7 +93,7 @@ var LOG_LEVEL_CONFIG = {
93
93
  success: { icon: CheckCircle, color: "text-green-500" }
94
94
  };
95
95
  var LOG_LEVELS = Object.keys(LOG_LEVEL_CONFIG);
96
- function LogEntryRow({ entry, expanded, onToggle }) {
96
+ var LogEntryRow = memo(/* @__PURE__ */ __name(function LogEntryRow2({ entry, expanded, onToggle }) {
97
97
  const config = LOG_LEVEL_CONFIG[entry.level];
98
98
  const Icon = config.icon;
99
99
  const pad = /* @__PURE__ */ __name((n, len = 2) => String(n).padStart(len, "0"), "pad");
@@ -127,9 +127,8 @@ function LogEntryRow({ entry, expanded, onToggle }) {
127
127
  hasStack && /* @__PURE__ */ jsx("pre", { className: "mt-2 text-[10px] text-red-400 whitespace-pre-wrap font-mono bg-red-950/20 p-2 rounded", children: entry.stack })
128
128
  ] })
129
129
  ] });
130
- }
131
- __name(LogEntryRow, "LogEntryRow");
132
- function LogsPanel({ isActive }) {
130
+ }, "LogEntryRow"));
131
+ function LogsPanelRaw({ isActive }) {
133
132
  const [expandedLogs, setExpandedLogs] = useState(/* @__PURE__ */ new Set());
134
133
  const [searchQuery, setSearchQuery] = useState("");
135
134
  const [selectedLevels, setSelectedLevels] = useState(
@@ -266,7 +265,8 @@ function LogsPanel({ isActive }) {
266
265
  }) }) })
267
266
  ] });
268
267
  }
269
- __name(LogsPanel, "LogsPanel");
268
+ __name(LogsPanelRaw, "LogsPanelRaw");
269
+ var LogsPanel = memo(LogsPanelRaw);
270
270
  var MAX_EVENTS = 200;
271
271
  function useAudioEventLog(active) {
272
272
  const [events, setEvents] = useState([]);
@@ -372,7 +372,7 @@ function formatTs(ts) {
372
372
  return `${String(d.getHours()).padStart(2, "0")}:${String(d.getMinutes()).padStart(2, "0")}:${String(d.getSeconds()).padStart(2, "0")}.${String(d.getMilliseconds()).padStart(3, "0")}`;
373
373
  }
374
374
  __name(formatTs, "formatTs");
375
- function AudioDebugPanel({ isActive }) {
375
+ function AudioDebugPanelRaw({ isActive }) {
376
376
  const { events, clear, seekRate, syncIntervalMs, kindCounts } = useAudioEventLog(isActive);
377
377
  const [debugMode, setDebugMode] = useState(getDebugAudioMode);
378
378
  const handleSetDebugAudio = useCallback((mode) => {
@@ -443,7 +443,8 @@ function AudioDebugPanel({ isActive }) {
443
443
  }) }) })
444
444
  ] });
445
445
  }
446
- __name(AudioDebugPanel, "AudioDebugPanel");
446
+ __name(AudioDebugPanelRaw, "AudioDebugPanelRaw");
447
+ var AudioDebugPanel = memo(AudioDebugPanelRaw);
447
448
  var BUILTIN_TABS = [
448
449
  { id: "logs", label: "Logs", icon: ScrollText },
449
450
  { id: "audio", label: "Audio", icon: Radio }
@@ -454,7 +455,7 @@ var POSITION_CLASSES = {
454
455
  "top-right": "top-4 right-4",
455
456
  "top-left": "top-4 left-4"
456
457
  };
457
- function DebugPanel({
458
+ function DebugPanelRaw({
458
459
  tabs: customTabs = [],
459
460
  position = "bottom-left",
460
461
  defaultHeight = 480,
@@ -539,8 +540,9 @@ function DebugPanel({
539
540
  }
540
541
  );
541
542
  }
542
- __name(DebugPanel, "DebugPanel");
543
- function DebugButton({ className, panel = {}, enabled }) {
543
+ __name(DebugPanelRaw, "DebugPanelRaw");
544
+ var DebugPanel = memo(DebugPanelRaw);
545
+ function DebugButtonRaw({ className, panel = {}, enabled }) {
544
546
  const isOpen = useDebugStore((s) => s.isOpen);
545
547
  const isUnlocked = useDebugStore((s) => s.isUnlocked);
546
548
  const unlock = useDebugStore((s) => s.unlock);
@@ -614,7 +616,8 @@ function DebugButton({ className, panel = {}, enabled }) {
614
616
  /* @__PURE__ */ jsx(DebugPanel, { ...panel })
615
617
  ] });
616
618
  }
617
- __name(DebugButton, "DebugButton");
619
+ __name(DebugButtonRaw, "DebugButtonRaw");
620
+ var DebugButton = memo(DebugButtonRaw);
618
621
  function shallowEqual(a, b) {
619
622
  if (a === b) return true;
620
623
  if (typeof a !== "object" || typeof b !== "object") return false;
@@ -643,7 +646,7 @@ function useStoreSnapshot(getState, intervalMs = 200, active = true) {
643
646
  return snapshot;
644
647
  }
645
648
  __name(useStoreSnapshot, "useStoreSnapshot");
646
- function StorePanel({ label, getState, intervalMs = 200, isActive }) {
649
+ function StorePanelRaw({ label, getState, intervalMs = 200, isActive }) {
647
650
  const snapshot = useStoreSnapshot(getState, intervalMs, isActive);
648
651
  return /* @__PURE__ */ jsxs("div", { className: "flex flex-col h-full", children: [
649
652
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 border-b border-border px-3 py-2 shrink-0", children: [
@@ -658,7 +661,8 @@ function StorePanel({ label, getState, intervalMs = 200, isActive }) {
658
661
  /* @__PURE__ */ jsx(ScrollArea, { className: "flex-1", children: /* @__PURE__ */ jsx("div", { className: "p-2", children: /* @__PURE__ */ jsx(LazyJsonTree, { data: snapshot, mode: "full" }) }) })
659
662
  ] });
660
663
  }
661
- __name(StorePanel, "StorePanel");
664
+ __name(StorePanelRaw, "StorePanelRaw");
665
+ var StorePanel = memo(StorePanelRaw);
662
666
  var MAX_EVENTS2 = 300;
663
667
  function useCustomEventLog(active, channel) {
664
668
  const [events, setEvents] = useState([]);
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/store/debugStore.ts","../src/hooks/useDebugShortcut.ts","../src/bridges/monitorBridge.ts","../src/panels/LogsPanel.tsx","../src/hooks/useAudioEventLog.ts","../src/panels/AudioDebugPanel.tsx","../src/DebugPanel.tsx","../src/DebugButton.tsx","../src/hooks/useStoreSnapshot.ts","../src/panels/StorePanel.tsx","../src/hooks/useCustomEventLog.ts"],"names":["isDev","useState","useRef","useCallback","useEffect","jsxs","jsx","Badge","cn","Button","Trash2","Radio","Bug","Tooltip","TooltipTrigger","TooltipContent","ScrollArea","LazyJsonTree","MAX_EVENTS"],"mappings":"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","file":"index.mjs","sourcesContent":["'use client';\n\nimport { create } from 'zustand';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport type DebugTab = 'logs' | 'audio' | 'pipeline' | 'custom';\n\nexport interface DebugStore {\n isOpen: boolean;\n tab: DebugTab;\n isUnlocked: boolean;\n open: () => void;\n close: () => void;\n toggle: () => void;\n setTab: (t: DebugTab) => void;\n unlock: (key: string) => boolean;\n}\n\n// ============================================================================\n// Store\n// ============================================================================\n\nexport const useDebugStore = create<DebugStore>((set) => ({\n isOpen: false,\n tab: 'logs',\n isUnlocked: false,\n\n open: () => set({ isOpen: true }),\n close: () => set({ isOpen: false }),\n toggle: () => set((s) => ({ isOpen: !s.isOpen })),\n setTab: (tab) => set({ tab }),\n\n unlock: (_key) => {\n // Any non-empty value unlocks — no secret key required\n const valid = true;\n if (valid) set({ isUnlocked: true });\n return valid;\n },\n}));\n","'use client';\n\nimport { useHotkey } from '@djangocfg/ui-core/hooks';\nimport { useDebugStore } from '../store/debugStore';\n\n/**\n * Registers a global keyboard shortcut to toggle the debug panel.\n * Default: Cmd+D (meta+d) on Mac / Win+D on Windows.\n *\n * Guards:\n * - In production: only fires if `isUnlocked === true`\n */\nexport function useDebugShortcut(): void {\n const toggle = useDebugStore((s) => s.toggle);\n const isUnlocked = useDebugStore((s) => s.isUnlocked);\n const isDev = typeof process !== 'undefined' && process.env?.NODE_ENV !== 'production';\n\n useHotkey(\n 'meta+d',\n (e) => {\n e.preventDefault();\n if (!isDev && !isUnlocked) return;\n toggle();\n },\n { preventDefault: true },\n );\n}\n","'use client';\n\n/**\n * monitorBridge — subscribes to @djangocfg/monitor store and forwards\n * captured events into debugger's logStore.\n *\n * Call once at app startup (e.g. inside DebugPanel or a provider).\n * Safe to call multiple times — only installs one subscription.\n *\n * @example\n * import { installMonitorBridge } from '@djangocfg/debuger/bridges'\n * installMonitorBridge()\n */\n\nimport { monitorStore, EventLevel } from '@djangocfg/monitor/client';\nimport { useDebugLogStore } from '../logger/logStore';\nimport type { LogLevel } from '../logger/types';\n\nlet _installed = false;\n\nexport function installMonitorBridge(): (() => void) | undefined {\n if (typeof window === 'undefined') return;\n if (_installed) return;\n\n let prevLen = monitorStore.getState().buffer.length;\n\n const unsub = monitorStore.subscribe((state) => {\n const buffer = state.buffer;\n if (buffer.length <= prevLen) { prevLen = buffer.length; return; }\n const newEvents = buffer.slice(prevLen);\n prevLen = buffer.length;\n\n for (const event of newEvents) {\n const level: LogLevel =\n event.level === EventLevel.ERROR ? 'error'\n : event.level === EventLevel.WARNING ? 'warn'\n : 'info';\n\n useDebugLogStore.getState().addLog({\n level,\n component: `monitor:${event.event_type ?? 'event'}`,\n message: event.message ?? '',\n data: {\n ...(event.url && { url: event.url }),\n ...(event.session_id && { session_id: event.session_id }),\n ...(event.http_status !== undefined && {\n http_status: event.http_status,\n http_method: event.http_method,\n http_url: event.http_url,\n }),\n ...(event.extra ? { extra: event.extra } : {}),\n },\n stack: event.stack_trace,\n });\n }\n });\n\n _installed = true;\n return () => {\n unsub();\n _installed = false;\n };\n}\n","'use client';\n\nimport React, { useState, useCallback, useEffect, useRef } from 'react';\nimport {\n useDebugLogStore,\n useDebugFilteredLogs,\n useDebugLogCount,\n useDebugErrorCount,\n type LogLevel,\n type LogEntry,\n} from '../logger';\nimport {\n Button,\n CopyButton,\n Badge,\n Input,\n Tooltip,\n TooltipContent,\n TooltipTrigger,\n} from '@djangocfg/ui-core/components';\nimport { LazyJsonTree } from '@djangocfg/ui-tools';\nimport { useVirtualizer, type VirtualItem } from '@tanstack/react-virtual';\nimport {\n Bug, Trash2, Download, ChevronDown, ChevronUp,\n AlertCircle, Info, AlertTriangle, CheckCircle, Search,\n} from 'lucide-react';\nimport { cn } from '@djangocfg/ui-core/lib';\n\n// ============================================================================\n// Constants\n// ============================================================================\n\nconst ROW_ESTIMATE_PX = 32;\nconst OVERSCAN = 5;\n\nconst LOG_LEVEL_CONFIG: Record<LogLevel, { icon: React.ElementType; color: string }> = {\n debug: { icon: Bug, color: 'text-muted-foreground' },\n info: { icon: Info, color: 'text-blue-500' },\n warn: { icon: AlertTriangle, color: 'text-yellow-500' },\n error: { icon: AlertCircle, color: 'text-red-500' },\n success: { icon: CheckCircle, color: 'text-green-500' },\n};\n\nconst LOG_LEVELS = Object.keys(LOG_LEVEL_CONFIG) as LogLevel[];\n\n// ============================================================================\n// LogEntryRow\n// ============================================================================\n\ninterface LogEntryRowProps {\n entry: LogEntry;\n expanded: boolean;\n onToggle: () => void;\n}\n\nfunction LogEntryRow({ entry, expanded, onToggle }: LogEntryRowProps) {\n const config = LOG_LEVEL_CONFIG[entry.level];\n const Icon = config.icon;\n const pad = (n: number, len = 2) => String(n).padStart(len, '0');\n const d = entry.timestamp;\n const time = `${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}.${pad(d.getMilliseconds(), 3)}`;\n const hasData = entry.data && Object.keys(entry.data).length > 0;\n const hasStack = !!entry.stack;\n const isExpandable = hasData || hasStack;\n\n return (\n <div className=\"border-b border-border/50 last:border-0\">\n <button\n type=\"button\"\n onClick={isExpandable ? onToggle : undefined}\n disabled={!isExpandable}\n className={cn(\n 'flex w-full items-start gap-2 px-3 py-1.5 text-left text-xs',\n isExpandable ? 'hover:bg-muted/50 cursor-pointer' : 'cursor-default'\n )}\n >\n <Icon className={cn('h-3.5 w-3.5 mt-0.5 shrink-0', config.color)} />\n <span className=\"text-muted-foreground font-mono shrink-0\">{time}</span>\n <Badge variant=\"outline\" className=\"shrink-0 text-[10px] px-1 py-0\">{entry.component}</Badge>\n <span className=\"flex-1 truncate\">{entry.message}</span>\n {isExpandable && (\n <span className=\"shrink-0 text-muted-foreground\">\n {expanded ? <ChevronUp className=\"h-3 w-3\" /> : <ChevronDown className=\"h-3 w-3\" />}\n </span>\n )}\n </button>\n {expanded && isExpandable && (\n <div className=\"px-3 pb-2 pl-8\">\n {hasData && <div className=\"mt-1\"><LazyJsonTree data={entry.data} mode=\"compact\" /></div>}\n {hasStack && (\n <pre className=\"mt-2 text-[10px] text-red-400 whitespace-pre-wrap font-mono bg-red-950/20 p-2 rounded\">\n {entry.stack}\n </pre>\n )}\n </div>\n )}\n </div>\n );\n}\n\n// ============================================================================\n// LogsPanel\n// ============================================================================\n\nexport function LogsPanel({ isActive }: { isActive: boolean }) {\n const [expandedLogs, setExpandedLogs] = useState<Set<string>>(new Set());\n const [searchQuery, setSearchQuery] = useState('');\n const [selectedLevels, setSelectedLevels] = useState<Set<LogLevel>>(\n new Set(['debug', 'info', 'warn', 'error', 'success'])\n );\n const [componentFilter, setComponentFilter] = useState('');\n\n const logs = useDebugFilteredLogs();\n const logCount = useDebugLogCount();\n const errorCount = useDebugErrorCount();\n const clearLogs = useDebugLogStore((s) => s.clearLogs);\n const setFilter = useDebugLogStore((s) => s.setFilter);\n const exportLogs = useDebugLogStore((s) => s.exportLogs);\n\n // Virtualizer\n const scrollRef = useRef<HTMLDivElement>(null);\n const virtualizer = useVirtualizer({\n count: logs.length,\n getScrollElement: () => scrollRef.current,\n estimateSize: () => ROW_ESTIMATE_PX,\n overscan: OVERSCAN,\n });\n\n useEffect(() => {\n if (!isActive) return;\n setFilter({\n levels: Array.from(selectedLevels),\n component: componentFilter || undefined,\n search: searchQuery || undefined,\n });\n }, [isActive, selectedLevels, componentFilter, searchQuery, setFilter]);\n\n const handleToggleExpand = useCallback((id: string) => {\n setExpandedLogs((prev) => {\n const next = new Set(prev);\n next.has(id) ? next.delete(id) : next.add(id);\n return next;\n });\n }, []);\n\n const handleToggleLevel = useCallback((level: LogLevel) => {\n setSelectedLevels((prev) => {\n const next = new Set(prev);\n next.has(level) ? next.delete(level) : next.add(level);\n return next;\n });\n }, []);\n\n const handleExport = useCallback(() => {\n const json = exportLogs();\n const blob = new Blob([json], { type: 'application/json' });\n const url = URL.createObjectURL(blob);\n const a = document.createElement('a');\n a.href = url;\n a.download = `debug-logs-${new Date().toISOString().slice(0, 19).replace(/:/g, '-')}.json`;\n a.click();\n URL.revokeObjectURL(url);\n }, [exportLogs]);\n\n const handleClear = useCallback(() => {\n clearLogs();\n setExpandedLogs(new Set());\n }, [clearLogs]);\n\n const logsJson = exportLogs();\n const virtualItems = virtualizer.getVirtualItems();\n const totalSize = virtualizer.getTotalSize();\n\n return (\n <div className=\"flex flex-col h-full\">\n {/* Stats */}\n <div className=\"flex items-center gap-2 border-b border-border px-3 py-1.5 shrink-0\">\n <Badge variant=\"secondary\" className=\"text-[10px]\">{logCount} logs</Badge>\n {errorCount > 0 && <Badge variant=\"destructive\" className=\"text-[10px]\">{errorCount} errors</Badge>}\n </div>\n\n {/* Filters */}\n <div className=\"flex flex-wrap items-center gap-2 border-b border-border px-3 py-2 shrink-0\">\n <div className=\"relative flex-1 min-w-[140px]\">\n <Search className=\"absolute left-2 top-1/2 h-3.5 w-3.5 -translate-y-1/2 text-muted-foreground\" />\n <Input\n placeholder=\"Search...\"\n value={searchQuery}\n onChange={(e) => setSearchQuery(e.target.value)}\n className=\"h-7 pl-7 text-xs\"\n />\n </div>\n <Input\n placeholder=\"Component...\"\n value={componentFilter}\n onChange={(e) => setComponentFilter(e.target.value)}\n className=\"h-7 w-24 text-xs\"\n />\n <div className=\"flex items-center gap-0.5\">\n {LOG_LEVELS.map((level) => {\n const { icon: Icon, color } = LOG_LEVEL_CONFIG[level];\n const active = selectedLevels.has(level);\n return (\n <Tooltip key={level}>\n <TooltipTrigger asChild>\n <Button variant={active ? 'secondary' : 'ghost'} size=\"icon\" className=\"h-6 w-6\" onClick={() => handleToggleLevel(level)}>\n <Icon className={cn('h-3.5 w-3.5', active && color)} />\n </Button>\n </TooltipTrigger>\n <TooltipContent>{level}</TooltipContent>\n </Tooltip>\n );\n })}\n </div>\n <div className=\"flex items-center gap-0.5 ml-auto\">\n <CopyButton value={logsJson} size=\"icon\" className=\"h-6 w-6\" />\n <Tooltip>\n <TooltipTrigger asChild>\n <Button variant=\"ghost\" size=\"icon\" className=\"h-6 w-6\" onClick={handleExport}>\n <Download className=\"h-3.5 w-3.5\" />\n </Button>\n </TooltipTrigger>\n <TooltipContent>Export JSON</TooltipContent>\n </Tooltip>\n <Tooltip>\n <TooltipTrigger asChild>\n <Button variant=\"ghost\" size=\"icon\" className=\"h-6 w-6\" onClick={handleClear}>\n <Trash2 className=\"h-3.5 w-3.5\" />\n </Button>\n </TooltipTrigger>\n <TooltipContent>Clear</TooltipContent>\n </Tooltip>\n </div>\n </div>\n\n {/* Virtualized log list */}\n <div ref={scrollRef} className=\"flex-1 overflow-auto\">\n {logs.length === 0 ? (\n <div className=\"flex flex-col items-center justify-center py-10 text-muted-foreground\">\n <Bug className=\"h-8 w-8 mb-2 opacity-40\" />\n <p className=\"text-sm\">No logs yet</p>\n </div>\n ) : (\n <div style={{ height: `${totalSize}px`, position: 'relative' }}>\n {virtualItems.map((vItem: VirtualItem) => {\n const entry = logs[vItem.index];\n return (\n <div\n key={entry.id}\n data-index={vItem.index}\n ref={virtualizer.measureElement}\n style={{ position: 'absolute', top: 0, left: 0, width: '100%', transform: `translateY(${vItem.start}px)` }}\n >\n <LogEntryRow\n entry={entry}\n expanded={expandedLogs.has(entry.id)}\n onToggle={() => handleToggleExpand(entry.id)}\n />\n </div>\n );\n })}\n </div>\n )}\n </div>\n </div>\n );\n}\n","'use client';\n\nimport { useState, useEffect, useRef, useCallback } from 'react';\nimport { subscribeAudioEvents, clearAudioEventBuffer } from '../emitters/audioEmitter';\nimport type { AudioDebugEvent, AudioEventKind } from '../emitters/audioEmitter';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface AudioLogEntry extends AudioDebugEvent {\n /** Local unique key for React rendering */\n id: string;\n}\n\nexport interface UseAudioEventLogResult {\n events: AudioLogEntry[];\n clear: () => void;\n /** Seek events per second (rolling 5s window) */\n seekRate: number;\n /** Average interval between 'sync' ticks in ms (e.g. RAF loop cadence) */\n syncIntervalMs: number | null;\n /** Running count per event kind */\n kindCounts: Partial<Record<AudioEventKind, number>>;\n}\n\n// ============================================================================\n// Constants\n// ============================================================================\n\nconst MAX_EVENTS = 200;\n\n// ============================================================================\n// Hook\n// ============================================================================\n\n/**\n * Subscribes to audio debug events and maintains a ring-buffer log.\n *\n * RAF batching: incoming events are queued in a ref and flushed into React\n * state once per animation frame — prevents render storms at 60fps.\n *\n * Only subscribes while `active` is true (panel tab is visible).\n */\nexport function useAudioEventLog(active: boolean): UseAudioEventLogResult {\n const [events, setEvents] = useState<AudioLogEntry[]>([]);\n const [syncIntervalMs, setSyncIntervalMs] = useState<number | null>(null);\n const [kindCounts, setKindCounts] = useState<Partial<Record<AudioEventKind, number>>>({});\n const [seekRate, setSeekRate] = useState(0);\n\n // Refs — mutated in the emitter callback without triggering renders\n const queueRef = useRef<AudioLogEntry[]>([]);\n const counterRef = useRef(0);\n const lastSyncTs = useRef<number | null>(null);\n const seekTimestamps = useRef<number[]>([]);\n const kindCountsRef = useRef<Partial<Record<AudioEventKind, number>>>({});\n\n const clear = useCallback(() => {\n clearAudioEventBuffer();\n queueRef.current = [];\n counterRef.current = 0;\n kindCountsRef.current = {};\n seekTimestamps.current = [];\n lastSyncTs.current = null;\n setEvents([]);\n setSyncIntervalMs(null);\n setKindCounts({});\n setSeekRate(0);\n }, []);\n\n // Subscribe — enqueue events without touching React state\n useEffect(() => {\n if (!active) return;\n\n const unsubscribe = subscribeAudioEvents((event) => {\n const entry: AudioLogEntry = { ...event, id: String(++counterRef.current) };\n queueRef.current.push(entry);\n\n // Track sync interval (no setState — RAF will pick it up)\n if (event.kind === 'sync') {\n if (lastSyncTs.current !== null) {\n const interval = event.ts - lastSyncTs.current;\n // Store on ref; RAF flush will call setSyncIntervalMs\n (entry as AudioLogEntry & { _interval?: number })._interval = interval;\n }\n lastSyncTs.current = event.ts;\n }\n\n // Track seeks\n if (event.kind === 'seek') {\n seekTimestamps.current.push(event.ts);\n }\n\n // Accumulate kind counts on ref\n kindCountsRef.current = {\n ...kindCountsRef.current,\n [event.kind]: (kindCountsRef.current[event.kind] ?? 0) + 1,\n };\n });\n\n return unsubscribe;\n }, [active]);\n\n // RAF flush loop — drains queue into React state once per frame\n useEffect(() => {\n if (!active) return;\n let rafId: number;\n\n const flush = () => {\n if (queueRef.current.length > 0) {\n const incoming = queueRef.current.splice(0);\n\n // Extract sync interval from last sync event in batch\n const lastSync = [...incoming].reverse().find((e) => e.kind === 'sync') as\n | (AudioLogEntry & { _interval?: number })\n | undefined;\n if (lastSync?._interval !== undefined) {\n setSyncIntervalMs(lastSync._interval);\n }\n\n setEvents((prev) => {\n const next = [...prev, ...incoming];\n return next.length > MAX_EVENTS ? next.slice(-MAX_EVENTS) : next;\n });\n\n setKindCounts({ ...kindCountsRef.current });\n }\n rafId = requestAnimationFrame(flush);\n };\n\n rafId = requestAnimationFrame(flush);\n return () => cancelAnimationFrame(rafId);\n }, [active]);\n\n // Rolling seek rate — recompute every second\n useEffect(() => {\n if (!active) return;\n const id = setInterval(() => {\n const now = Date.now();\n seekTimestamps.current = seekTimestamps.current.filter((t) => now - t < 5000);\n setSeekRate(Math.round((seekTimestamps.current.length / 5) * 10) / 10);\n }, 1000);\n return () => clearInterval(id);\n }, [active]);\n\n return { events, clear, seekRate, syncIntervalMs, kindCounts };\n}\n","'use client';\n\nimport React, { useCallback, useState } from 'react';\nimport {\n Button,\n Badge,\n ScrollArea,\n} from '@djangocfg/ui-core/components';\nimport { cn } from '@djangocfg/ui-core/lib';\nimport { Trash2, Radio } from 'lucide-react';\nimport { useAudioEventLog } from '../hooks/useAudioEventLog';\nimport type { AudioEventKind } from '../emitters/audioEmitter';\n\n// ============================================================================\n// Types / constants\n// ============================================================================\n\ntype DebugAudioMode = 'off' | 'on' | 'verbose';\n\nconst DEBUG_MODES: DebugAudioMode[] = ['off', 'on', 'verbose'];\n\nconst KIND_STYLES: Record<AudioEventKind, { label: string; className: string }> = {\n play: { label: 'play', className: 'text-green-400' },\n pause: { label: 'pause', className: 'text-yellow-400' },\n seek: { label: 'seek', className: 'text-blue-400' },\n ended: { label: 'ended', className: 'text-muted-foreground' },\n sync: { label: 'sync', className: 'text-muted-foreground/50' },\n load: { label: 'load', className: 'text-purple-400' },\n error: { label: 'error', className: 'text-red-400' },\n engine: { label: 'eng', className: 'text-cyan-400' },\n custom: { label: 'custom', className: 'text-orange-400' },\n};\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\nfunction getDebugAudioMode(): DebugAudioMode {\n try {\n const v = localStorage.getItem('DEBUG_AUDIO');\n if (v === 'verbose') return 'verbose';\n if (v) return 'on';\n } catch { /* ssr */ }\n return 'off';\n}\n\nfunction formatTs(ts: number): string {\n const d = new Date(ts);\n return `${String(d.getHours()).padStart(2, '0')}:${String(d.getMinutes()).padStart(2, '0')}:${String(d.getSeconds()).padStart(2, '0')}.${String(d.getMilliseconds()).padStart(3, '0')}`;\n}\n\n// ============================================================================\n// Component\n// ============================================================================\n\ninterface AudioDebugPanelProps {\n isActive: boolean;\n}\n\nexport function AudioDebugPanel({ isActive }: AudioDebugPanelProps) {\n const { events, clear, seekRate, syncIntervalMs, kindCounts } = useAudioEventLog(isActive);\n const [debugMode, setDebugMode] = useState<DebugAudioMode>(getDebugAudioMode);\n\n const handleSetDebugAudio = useCallback((mode: DebugAudioMode) => {\n if (mode === 'off') {\n localStorage.removeItem('DEBUG_AUDIO');\n } else {\n localStorage.setItem('DEBUG_AUDIO', mode === 'verbose' ? 'verbose' : '1');\n }\n setDebugMode(mode);\n }, []);\n\n const kindEntries = Object.entries(kindCounts) as [AudioEventKind, number][];\n const activeKinds = kindEntries.filter(([, count]) => count > 0);\n const reversedEvents = [...events].reverse();\n\n return (\n <div className=\"flex flex-col h-full\">\n {/* Metrics bar */}\n <div className=\"flex flex-wrap items-center gap-2 border-b border-border px-3 py-2 text-xs\">\n <span className=\"text-muted-foreground\">\n Sync interval:{' '}\n <span className=\"text-foreground font-mono\">\n {syncIntervalMs !== null ? `${syncIntervalMs.toFixed(1)}ms` : '—'}\n </span>\n </span>\n <span className=\"text-muted-foreground\">\n Seeks/s: <span className=\"text-foreground font-mono\">{seekRate}</span>\n </span>\n <span className=\"text-muted-foreground\">\n Total: <span className=\"text-foreground font-mono\">{events.length}</span>\n </span>\n\n <div className=\"flex gap-1 flex-wrap ml-auto\">\n {activeKinds.map(([kind, count]) => (\n <Badge key={kind} variant=\"outline\" className={cn('text-[10px] px-1 py-0', KIND_STYLES[kind]?.className)}>\n {KIND_STYLES[kind]?.label ?? kind} {count}\n </Badge>\n ))}\n </div>\n\n <Button variant=\"ghost\" size=\"icon\" className=\"h-6 w-6 ml-1\" onClick={clear}>\n <Trash2 className=\"h-3.5 w-3.5\" />\n </Button>\n </div>\n\n {/* DEBUG_AUDIO toggles */}\n <div className=\"flex items-center gap-1.5 border-b border-border px-3 py-1.5\">\n <span className=\"text-[10px] text-muted-foreground mr-1\">DEBUG_AUDIO:</span>\n {DEBUG_MODES.map((mode) => (\n <button\n key={mode}\n type=\"button\"\n className={cn(\n 'text-[10px] px-2 py-0.5 rounded border transition-colors',\n debugMode === mode\n ? 'border-primary bg-primary/10 text-primary'\n : 'border-border hover:bg-muted text-muted-foreground'\n )}\n onClick={() => handleSetDebugAudio(mode)}\n >\n {mode}\n </button>\n ))}\n </div>\n\n {/* Event log */}\n <ScrollArea className=\"flex-1\">\n {reversedEvents.length === 0 ? (\n <div className=\"flex flex-col items-center justify-center py-10 text-muted-foreground\">\n <Radio className=\"h-8 w-8 mb-2 opacity-40\" />\n <p className=\"text-sm\">No audio events yet</p>\n <p className=\"text-xs mt-1\">\n Wire <code className=\"text-xs\">emitAudioEvent()</code> into your audio engine\n </p>\n </div>\n ) : (\n <div className=\"divide-y divide-border/30\">\n {reversedEvents.map((entry) => {\n const style = KIND_STYLES[entry.kind] ?? { label: entry.kind, className: 'text-foreground' };\n return (\n <div key={entry.id} className=\"flex items-start gap-2 px-3 py-1 text-xs\">\n <span className=\"font-mono text-muted-foreground shrink-0 w-[88px]\">{formatTs(entry.ts)}</span>\n <span className={cn('shrink-0 w-12 font-medium', style.className)}>{style.label}</span>\n {entry.trackId && (\n <span className=\"shrink-0 font-mono text-muted-foreground\">{entry.trackId.slice(0, 6)}</span>\n )}\n <span className=\"truncate text-foreground/80\">{entry.msg}</span>\n </div>\n );\n })}\n </div>\n )}\n </ScrollArea>\n </div>\n );\n}\n","'use client';\n\nimport React, { useMemo, useState, useEffect } from 'react';\nimport { installMonitorBridge } from './bridges';\nimport { MONITOR_VERSION } from '@djangocfg/monitor/client';\nimport {\n Button,\n Badge,\n Tooltip,\n TooltipContent,\n TooltipTrigger,\n} from '@djangocfg/ui-core/components';\nimport { cn } from '@djangocfg/ui-core/lib';\nimport { useDebugErrorCount } from './logger';\nimport {\n X, Bug, Minimize2, Maximize2,\n ScrollText, Radio,\n} from 'lucide-react';\nimport { useDebugStore } from './store/debugStore';\nimport type { DebugTab } from './store/debugStore';\nimport { LogsPanel } from './panels/LogsPanel';\nimport { AudioDebugPanel } from './panels/AudioDebugPanel';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface CustomDebugTab {\n /** Unique id — will be added to DebugTab union at runtime */\n id: string;\n label: string;\n icon: React.ElementType;\n panel: React.ComponentType<{ isActive: boolean }>;\n}\n\nexport interface DebugPanelProps {\n /** Additional app-specific tabs */\n tabs?: CustomDebugTab[];\n position?: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left';\n defaultHeight?: number;\n defaultWidth?: number;\n}\n\n// ============================================================================\n// Built-in tabs\n// ============================================================================\n\nconst BUILTIN_TABS = [\n { id: 'logs', label: 'Logs', icon: ScrollText },\n { id: 'audio', label: 'Audio', icon: Radio },\n] as const;\n\nconst POSITION_CLASSES: Record<NonNullable<DebugPanelProps['position']>, string> = {\n 'bottom-right': 'bottom-4 right-4',\n 'bottom-left': 'bottom-4 left-4',\n 'top-right': 'top-4 right-4',\n 'top-left': 'top-4 left-4',\n};\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport function DebugPanel({\n tabs: customTabs = [],\n position = 'bottom-left',\n defaultHeight = 480,\n defaultWidth = 560,\n}: DebugPanelProps) {\n const isOpen = useDebugStore((s) => s.isOpen);\n const activeTab = useDebugStore((s) => s.tab);\n const setTab = useDebugStore((s) => s.setTab);\n const close = useDebugStore((s) => s.close);\n const errorCount = useDebugErrorCount();\n\n const [isMinimized, setIsMinimized] = useState(false);\n\n useEffect(() => {\n const unsub = installMonitorBridge();\n return () => unsub?.();\n }, []);\n\n const allTabs = useMemo(() => [\n ...BUILTIN_TABS,\n ...customTabs.map((t) => ({ id: t.id, label: t.label, icon: t.icon })),\n ], [customTabs]);\n\n const panelHeight = isMinimized ? 48 : defaultHeight;\n\n if (!isOpen) return null;\n\n return (\n <div\n className={cn(\n 'fixed z-[100] flex flex-col overflow-hidden rounded-lg border border-border bg-background shadow-xl',\n POSITION_CLASSES[position]\n )}\n style={{ width: defaultWidth, height: panelHeight, backgroundColor: 'hsl(var(--background, 0 0% 4%))' }}\n >\n {/* Header */}\n <div className=\"flex items-center gap-2 border-b border-border px-3 py-2 shrink-0\" style={{ backgroundColor: 'hsl(var(--muted, 0 0% 10%) / 0.5)' }}>\n <Bug className=\"h-4 w-4 text-primary\" />\n <span className=\"text-sm font-medium\">Debug</span>\n <span className=\"text-[10px] text-muted-foreground font-mono\">v{MONITOR_VERSION}</span>\n\n {errorCount > 0 && (\n <Badge variant=\"destructive\" className=\"ml-1 text-[10px]\">{errorCount} errors</Badge>\n )}\n\n {/* Tab bar */}\n {!isMinimized && (\n <div className=\"flex items-center gap-0.5 ml-3\">\n {allTabs.map((tab) => {\n const Icon = tab.icon;\n const isActive = activeTab === tab.id;\n return (\n <button\n key={tab.id}\n type=\"button\"\n onClick={() => setTab(tab.id as DebugTab)}\n className={cn(\n 'flex items-center gap-1.5 px-2 py-0.5 rounded text-xs transition-colors',\n isActive\n ? 'bg-background text-foreground shadow-sm'\n : 'text-muted-foreground hover:text-foreground hover:bg-muted'\n )}\n >\n <Icon className=\"h-3 w-3\" />\n {tab.label}\n </button>\n );\n })}\n </div>\n )}\n\n <div className=\"flex items-center gap-1 ml-auto\">\n <Tooltip>\n <TooltipTrigger asChild>\n <Button variant=\"ghost\" size=\"icon\" className=\"h-6 w-6\" onClick={() => setIsMinimized((v) => !v)}>\n {isMinimized ? <Maximize2 className=\"h-3.5 w-3.5\" /> : <Minimize2 className=\"h-3.5 w-3.5\" />}\n </Button>\n </TooltipTrigger>\n <TooltipContent>{isMinimized ? 'Expand' : 'Minimize'}</TooltipContent>\n </Tooltip>\n <Tooltip>\n <TooltipTrigger asChild>\n <Button variant=\"ghost\" size=\"icon\" className=\"h-6 w-6\" onClick={close}>\n <X className=\"h-3.5 w-3.5\" />\n </Button>\n </TooltipTrigger>\n <TooltipContent>Close</TooltipContent>\n </Tooltip>\n </div>\n </div>\n\n {/* Panel content */}\n {!isMinimized && (\n <div className=\"flex-1 overflow-hidden\">\n {activeTab === 'logs' && <LogsPanel isActive={activeTab === 'logs'} />}\n {activeTab === 'audio' && <AudioDebugPanel isActive={activeTab === 'audio'} />}\n {customTabs.map((tab) => {\n const Panel = tab.panel;\n return (\n <div key={tab.id} className={cn('h-full', activeTab !== tab.id && 'hidden')}>\n <Panel isActive={activeTab === tab.id} />\n </div>\n );\n })}\n </div>\n )}\n </div>\n );\n}\n","'use client';\n\nimport React, { useCallback, useEffect, useRef } from 'react';\nimport { Bug } from 'lucide-react';\nimport {\n Tooltip,\n TooltipContent,\n TooltipTrigger,\n} from '@djangocfg/ui-core/components';\nimport { cn, isDev } from '@djangocfg/ui-core/lib';\nimport { useDebugMode } from '@djangocfg/monitor/client';\nimport { useDebugStore } from './store/debugStore';\nimport { useDebugShortcut } from './hooks/useDebugShortcut';\nimport { useDebugErrorCount } from './logger';\nimport { DebugPanel } from './DebugPanel';\nimport type { DebugPanelProps } from './DebugPanel';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface DebugButtonProps {\n className?: string;\n /** Props forwarded to DebugPanel */\n panel?: Omit<DebugPanelProps, never>;\n /** Explicitly disable. Default: undefined (auto — visible in dev, hidden in prod, ?debug=1 always works) */\n enabled?: boolean;\n}\n\n// ============================================================================\n// DebugButton\n//\n// Visibility rules (simple):\n// 1. enabled === false AND no ?debug=1 → hidden completely\n// 2. isDev OR ?debug=1 (localStorage) → visible (unlocked)\n// 3. prod without ?debug=1 → invisible click trap (easter egg: 5 clicks)\n// ============================================================================\n\nexport function DebugButton({ className, panel = {}, enabled }: DebugButtonProps) {\n // All hooks called unconditionally (React rules of hooks)\n const isOpen = useDebugStore((s) => s.isOpen);\n const isUnlocked = useDebugStore((s) => s.isUnlocked);\n const unlock = useDebugStore((s) => s.unlock);\n const toggle = useDebugStore((s) => s.toggle);\n const isDebugMode = useDebugMode();\n const errorCount = useDebugErrorCount();\n useDebugShortcut();\n\n // Should this button be visible (unlocked)?\n const shouldUnlock = isDev || isDebugMode;\n\n // eslint-disable-next-line no-console\n // if (typeof window !== 'undefined') console.info('[DebugButton]', { isDev, isDebugMode, shouldUnlock, isUnlocked, enabled });\n\n // Auto-unlock in dev or when ?debug=1\n useEffect(() => {\n if (shouldUnlock) unlock('1');\n }, [shouldUnlock, unlock]);\n\n // Hide Next.js dev indicator while panel is open\n useEffect(() => {\n if (typeof document === 'undefined') return;\n const apply = () => {\n document.querySelectorAll<HTMLElement>('nextjs-portal').forEach((el) => {\n el.style.display = isOpen ? 'none' : '';\n });\n };\n apply();\n const observer = new MutationObserver(apply);\n observer.observe(document.body, { childList: true });\n return () => observer.disconnect();\n }, [isOpen]);\n\n // Easter egg: 5 clicks in 2s → unlock\n const clicks = useRef<number[]>([]);\n const handleEasterEgg = useCallback(() => {\n const now = Date.now();\n clicks.current = [...clicks.current.filter((t) => now - t < 2000), now];\n if (clicks.current.length >= 5) {\n clicks.current = [];\n unlock('1');\n toggle();\n }\n }, [unlock, toggle]);\n\n // === Render decision (after all hooks) ===\n\n // Explicitly disabled AND no debug override → don't render at all\n if (enabled === false && !isDebugMode) return null;\n\n // Not unlocked → invisible click trap for easter egg\n if (!isUnlocked) {\n return (\n <div\n className=\"fixed bottom-5 left-5 w-9 h-9 z-[99999] opacity-0 cursor-default\"\n onClick={handleEasterEgg}\n />\n );\n }\n\n // Unlocked → visible debug button\n return (\n <>\n {!isOpen && (\n <div className={cn('fixed bottom-5 z-[99999]', isDev ? 'left-16' : 'left-5')}>\n <Tooltip>\n <TooltipTrigger asChild>\n <button\n type=\"button\"\n className={cn(\n 'relative w-9 h-9 flex items-center justify-center rounded-full',\n 'bg-black/80 backdrop-blur-xl',\n 'shadow-[0_0_0_1px_#171717,inset_0_0_0_1px_hsla(0,0%,100%,0.14),0px_16px_32px_-8px_rgba(0,0,0,0.24)]',\n 'transition-all duration-150 hover:scale-105',\n 'focus:outline-none focus-visible:ring-2 focus-visible:ring-white/50',\n errorCount > 0 && 'bg-red-600/90',\n className,\n )}\n onClick={toggle}\n >\n <Bug className={cn('h-4 w-4', errorCount > 0 ? 'text-white' : 'text-white/80')} />\n {errorCount > 0 && (\n <span className=\"absolute -right-1 -top-1 flex h-4 min-w-4 items-center justify-center rounded-full bg-white text-[10px] font-semibold text-red-600 shadow-sm\">\n {errorCount}\n </span>\n )}\n </button>\n </TooltipTrigger>\n <TooltipContent side=\"top\">Debug Panel <kbd className=\"ml-1 text-[10px] opacity-60\">⌘D</kbd></TooltipContent>\n </Tooltip>\n </div>\n )}\n <DebugPanel {...panel} />\n </>\n );\n}\n","'use client';\n\nimport { useState, useEffect, useRef } from 'react';\n\n// ============================================================================\n// Shallow equal (avoids unnecessary re-renders)\n// ============================================================================\n\nfunction shallowEqual(a: unknown, b: unknown): boolean {\n if (a === b) return true;\n if (typeof a !== 'object' || typeof b !== 'object') return false;\n if (a === null || b === null) return false;\n const keysA = Object.keys(a as object);\n const keysB = Object.keys(b as object);\n if (keysA.length !== keysB.length) return false;\n for (const key of keysA) {\n if ((a as Record<string, unknown>)[key] !== (b as Record<string, unknown>)[key]) return false;\n }\n return true;\n}\n\n// ============================================================================\n// Hook\n// ============================================================================\n\n/**\n * Polling-based external Zustand store snapshot.\n *\n * Reads the store state via `getState()` on an interval — NOT via reactive\n * subscription. This prevents debug panel renders from being triggered by\n * high-frequency store updates and avoids Zustand v5 infinite loop issues\n * (returning new object references from selectors without useShallow).\n *\n * Only polls while `active` is true (panel tab is visible).\n *\n * @param getState A stable function that returns the current store state slice.\n * Use `() => useMyStore.getState()` — the hook ref-stabilizes it.\n * @param intervalMs Poll interval in ms. Default 200ms.\n * @param active Whether to poll. Pass `isActive` from panel props.\n *\n * @example\n * const snap = useStoreSnapshot(\n * () => useTimelineStore.getState(),\n * 200,\n * isActive\n * );\n */\nexport function useStoreSnapshot<T>(\n getState: () => T,\n intervalMs = 200,\n active = true,\n): T {\n const getStateRef = useRef(getState);\n getStateRef.current = getState;\n\n const [snapshot, setSnapshot] = useState<T>(() => getState());\n\n useEffect(() => {\n if (!active) return;\n\n const id = setInterval(() => {\n const next = getStateRef.current();\n setSnapshot((prev) => (shallowEqual(prev, next) ? prev : next));\n }, intervalMs);\n\n return () => clearInterval(id);\n }, [active, intervalMs]);\n\n return snapshot;\n}\n","'use client';\n\nimport React from 'react';\nimport { ScrollArea } from '@djangocfg/ui-core/components';\nimport { LazyJsonTree } from '@djangocfg/ui-tools';\nimport { Database } from 'lucide-react';\nimport { useStoreSnapshot } from '../hooks/useStoreSnapshot';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface StorePanelProps {\n /** Display label shown above the JSON tree */\n label: string;\n /**\n * Getter for the store state slice to display.\n * Use `() => useMyStore.getState()` — stable function ref is not required,\n * the hook handles stabilization internally.\n */\n getState: () => Record<string, unknown>;\n /**\n * Poll interval in ms. Default 200ms.\n * Use higher values for stores that update very frequently.\n */\n intervalMs?: number;\n /** Only polls when active (panel tab is visible) */\n isActive: boolean;\n}\n\n// ============================================================================\n// Component\n// ============================================================================\n\n/**\n * Generic Zustand store viewer for the debug panel.\n *\n * Uses polling (not reactive subscription) to read external store state.\n * This avoids Zustand v5 infinite loop issues and prevents the debug panel\n * from re-rendering on every store change.\n *\n * @example — in consuming app's custom tab:\n * import { StorePanel } from '@org/debuger';\n * import { useTimelineStore } from '@stores/timelineStore';\n *\n * <StorePanel\n * label=\"Timeline Store\"\n * getState={() => useTimelineStore.getState()}\n * isActive={isActive}\n * />\n */\nexport function StorePanel({ label, getState, intervalMs = 200, isActive }: StorePanelProps) {\n const snapshot = useStoreSnapshot(getState, intervalMs, isActive);\n\n return (\n <div className=\"flex flex-col h-full\">\n <div className=\"flex items-center gap-2 border-b border-border px-3 py-2 shrink-0\">\n <Database className=\"h-3.5 w-3.5 text-muted-foreground\" />\n <span className=\"text-xs font-medium text-muted-foreground\">{label}</span>\n <span className=\"ml-auto text-[10px] text-muted-foreground/60\">\n polling {intervalMs}ms\n </span>\n </div>\n <ScrollArea className=\"flex-1\">\n <div className=\"p-2\">\n <LazyJsonTree data={snapshot} mode=\"full\" />\n </div>\n </ScrollArea>\n </div>\n );\n}\n","'use client';\n\nimport { useState, useEffect, useRef, useCallback } from 'react';\nimport { subscribeCustomEvents } from '../emitters/customEmitter';\nimport type { CustomDebugEvent } from '../emitters/customEmitter';\n\nexport interface CustomLogEntry extends CustomDebugEvent {\n id: string;\n}\n\nconst MAX_EVENTS = 300;\n\n/**\n * Subscribes to custom channel events and maintains a ring-buffer per channel.\n * Pass `channel` to filter — or undefined to receive all channels.\n */\nexport function useCustomEventLog(active: boolean, channel?: string) {\n const [events, setEvents] = useState<CustomLogEntry[]>([]);\n const counterRef = useRef(0);\n\n const clear = useCallback(() => setEvents([]), []);\n\n useEffect(() => {\n if (!active) return;\n\n const unsubscribe = subscribeCustomEvents((event) => {\n if (channel && event.channel !== channel) return;\n const entry: CustomLogEntry = { ...event, id: String(++counterRef.current) };\n setEvents((prev) => {\n const next = [...prev, entry];\n return next.length > MAX_EVENTS ? next.slice(-MAX_EVENTS) : next;\n });\n });\n\n return unsubscribe;\n }, [active, channel]);\n\n return { events, clear };\n}\n"]}
1
+ {"version":3,"sources":["../src/store/debugStore.ts","../src/hooks/useDebugShortcut.ts","../src/bridges/monitorBridge.ts","../src/panels/LogsPanel.tsx","../src/hooks/useAudioEventLog.ts","../src/panels/AudioDebugPanel.tsx","../src/DebugPanel.tsx","../src/DebugButton.tsx","../src/hooks/useStoreSnapshot.ts","../src/panels/StorePanel.tsx","../src/hooks/useCustomEventLog.ts"],"names":["isDev","LogEntryRow","useState","useRef","useCallback","useEffect","jsxs","jsx","Badge","cn","Button","Trash2","memo","Radio","Bug","Tooltip","TooltipTrigger","TooltipContent","ScrollArea","LazyJsonTree","MAX_EVENTS"],"mappings":"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","file":"index.mjs","sourcesContent":["'use client';\n\nimport { create } from 'zustand';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport type DebugTab = 'logs' | 'audio' | 'pipeline' | 'custom';\n\nexport interface DebugStore {\n isOpen: boolean;\n tab: DebugTab;\n isUnlocked: boolean;\n open: () => void;\n close: () => void;\n toggle: () => void;\n setTab: (t: DebugTab) => void;\n unlock: (key: string) => boolean;\n}\n\n// ============================================================================\n// Store\n// ============================================================================\n\nexport const useDebugStore = create<DebugStore>((set) => ({\n isOpen: false,\n tab: 'logs',\n isUnlocked: false,\n\n open: () => set({ isOpen: true }),\n close: () => set({ isOpen: false }),\n toggle: () => set((s) => ({ isOpen: !s.isOpen })),\n setTab: (tab) => set({ tab }),\n\n unlock: (_key) => {\n // Any non-empty value unlocks — no secret key required\n const valid = true;\n if (valid) set({ isUnlocked: true });\n return valid;\n },\n}));\n","'use client';\n\nimport { useHotkey } from '@djangocfg/ui-core/hooks';\nimport { useDebugStore } from '../store/debugStore';\n\n/**\n * Registers a global keyboard shortcut to toggle the debug panel.\n * Default: Cmd+D (meta+d) on Mac / Win+D on Windows.\n *\n * Guards:\n * - In production: only fires if `isUnlocked === true`\n */\nexport function useDebugShortcut(): void {\n const toggle = useDebugStore((s) => s.toggle);\n const isUnlocked = useDebugStore((s) => s.isUnlocked);\n const isDev = typeof process !== 'undefined' && process.env?.NODE_ENV !== 'production';\n\n useHotkey(\n 'meta+d',\n (e) => {\n e.preventDefault();\n if (!isDev && !isUnlocked) return;\n toggle();\n },\n { preventDefault: true },\n );\n}\n","'use client';\n\n/**\n * monitorBridge — subscribes to @djangocfg/monitor store and forwards\n * captured events into debugger's logStore.\n *\n * Call once at app startup (e.g. inside DebugPanel or a provider).\n * Safe to call multiple times — only installs one subscription.\n *\n * @example\n * import { installMonitorBridge } from '@djangocfg/debuger/bridges'\n * installMonitorBridge()\n */\n\nimport { monitorStore, EventLevel } from '@djangocfg/monitor/client';\nimport { useDebugLogStore } from '../logger/logStore';\nimport type { LogLevel } from '../logger/types';\n\nlet _installed = false;\n\nexport function installMonitorBridge(): (() => void) | undefined {\n if (typeof window === 'undefined') return;\n if (_installed) return;\n\n let prevLen = monitorStore.getState().buffer.length;\n\n const unsub = monitorStore.subscribe((state) => {\n const buffer = state.buffer;\n if (buffer.length <= prevLen) { prevLen = buffer.length; return; }\n const newEvents = buffer.slice(prevLen);\n prevLen = buffer.length;\n\n for (const event of newEvents) {\n const level: LogLevel =\n event.level === EventLevel.ERROR ? 'error'\n : event.level === EventLevel.WARNING ? 'warn'\n : 'info';\n\n useDebugLogStore.getState().addLog({\n level,\n component: `monitor:${event.event_type ?? 'event'}`,\n message: event.message ?? '',\n data: {\n ...(event.url && { url: event.url }),\n ...(event.session_id && { session_id: event.session_id }),\n ...(event.http_status !== undefined && {\n http_status: event.http_status,\n http_method: event.http_method,\n http_url: event.http_url,\n }),\n ...(event.extra ? { extra: event.extra } : {}),\n },\n stack: event.stack_trace,\n });\n }\n });\n\n _installed = true;\n return () => {\n unsub();\n _installed = false;\n };\n}\n","'use client';\n\nimport React, { memo, useState, useCallback, useEffect, useRef } from 'react';\nimport {\n useDebugLogStore,\n useDebugFilteredLogs,\n useDebugLogCount,\n useDebugErrorCount,\n type LogLevel,\n type LogEntry,\n} from '../logger';\nimport {\n Button,\n CopyButton,\n Badge,\n Input,\n Tooltip,\n TooltipContent,\n TooltipTrigger,\n} from '@djangocfg/ui-core/components';\nimport { LazyJsonTree } from '@djangocfg/ui-tools';\nimport { useVirtualizer, type VirtualItem } from '@tanstack/react-virtual';\nimport {\n Bug, Trash2, Download, ChevronDown, ChevronUp,\n AlertCircle, Info, AlertTriangle, CheckCircle, Search,\n} from 'lucide-react';\nimport { cn } from '@djangocfg/ui-core/lib';\n\n// ============================================================================\n// Constants\n// ============================================================================\n\nconst ROW_ESTIMATE_PX = 32;\nconst OVERSCAN = 5;\n\nconst LOG_LEVEL_CONFIG: Record<LogLevel, { icon: React.ElementType; color: string }> = {\n debug: { icon: Bug, color: 'text-muted-foreground' },\n info: { icon: Info, color: 'text-blue-500' },\n warn: { icon: AlertTriangle, color: 'text-yellow-500' },\n error: { icon: AlertCircle, color: 'text-red-500' },\n success: { icon: CheckCircle, color: 'text-green-500' },\n};\n\nconst LOG_LEVELS = Object.keys(LOG_LEVEL_CONFIG) as LogLevel[];\n\n// ============================================================================\n// LogEntryRow\n// ============================================================================\n\ninterface LogEntryRowProps {\n entry: LogEntry;\n expanded: boolean;\n onToggle: () => void;\n}\n\n/**\n * LogEntryRow — single virtualised log entry.\n *\n * Memoised: re-renders only when `entry` reference, `expanded`, or\n * `onToggle` reference change. `entry` is treated as immutable.\n */\nconst LogEntryRow = memo(function LogEntryRow({ entry, expanded, onToggle }: LogEntryRowProps) {\n const config = LOG_LEVEL_CONFIG[entry.level];\n const Icon = config.icon;\n const pad = (n: number, len = 2) => String(n).padStart(len, '0');\n const d = entry.timestamp;\n const time = `${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}.${pad(d.getMilliseconds(), 3)}`;\n const hasData = entry.data && Object.keys(entry.data).length > 0;\n const hasStack = !!entry.stack;\n const isExpandable = hasData || hasStack;\n\n return (\n <div className=\"border-b border-border/50 last:border-0\">\n <button\n type=\"button\"\n onClick={isExpandable ? onToggle : undefined}\n disabled={!isExpandable}\n className={cn(\n 'flex w-full items-start gap-2 px-3 py-1.5 text-left text-xs',\n isExpandable ? 'hover:bg-muted/50 cursor-pointer' : 'cursor-default'\n )}\n >\n <Icon className={cn('h-3.5 w-3.5 mt-0.5 shrink-0', config.color)} />\n <span className=\"text-muted-foreground font-mono shrink-0\">{time}</span>\n <Badge variant=\"outline\" className=\"shrink-0 text-[10px] px-1 py-0\">{entry.component}</Badge>\n <span className=\"flex-1 truncate\">{entry.message}</span>\n {isExpandable && (\n <span className=\"shrink-0 text-muted-foreground\">\n {expanded ? <ChevronUp className=\"h-3 w-3\" /> : <ChevronDown className=\"h-3 w-3\" />}\n </span>\n )}\n </button>\n {expanded && isExpandable && (\n <div className=\"px-3 pb-2 pl-8\">\n {hasData && <div className=\"mt-1\"><LazyJsonTree data={entry.data} mode=\"compact\" /></div>}\n {hasStack && (\n <pre className=\"mt-2 text-[10px] text-red-400 whitespace-pre-wrap font-mono bg-red-950/20 p-2 rounded\">\n {entry.stack}\n </pre>\n )}\n </div>\n )}\n </div>\n );\n});\n\n// ============================================================================\n// LogsPanel\n// ============================================================================\n\n/**\n * LogsPanel — virtualised log viewer with filters and search.\n *\n * Memoised: re-renders only when `isActive` changes. Internal filter\n * state and log store subscriptions are isolated and do not propagate\n * to parent components.\n */\nfunction LogsPanelRaw({ isActive }: { isActive: boolean }) {\n const [expandedLogs, setExpandedLogs] = useState<Set<string>>(new Set());\n const [searchQuery, setSearchQuery] = useState('');\n const [selectedLevels, setSelectedLevels] = useState<Set<LogLevel>>(\n new Set(['debug', 'info', 'warn', 'error', 'success'])\n );\n const [componentFilter, setComponentFilter] = useState('');\n\n const logs = useDebugFilteredLogs();\n const logCount = useDebugLogCount();\n const errorCount = useDebugErrorCount();\n const clearLogs = useDebugLogStore((s) => s.clearLogs);\n const setFilter = useDebugLogStore((s) => s.setFilter);\n const exportLogs = useDebugLogStore((s) => s.exportLogs);\n\n // Virtualizer\n const scrollRef = useRef<HTMLDivElement>(null);\n const virtualizer = useVirtualizer({\n count: logs.length,\n getScrollElement: () => scrollRef.current,\n estimateSize: () => ROW_ESTIMATE_PX,\n overscan: OVERSCAN,\n });\n\n useEffect(() => {\n if (!isActive) return;\n setFilter({\n levels: Array.from(selectedLevels),\n component: componentFilter || undefined,\n search: searchQuery || undefined,\n });\n }, [isActive, selectedLevels, componentFilter, searchQuery, setFilter]);\n\n const handleToggleExpand = useCallback((id: string) => {\n setExpandedLogs((prev) => {\n const next = new Set(prev);\n next.has(id) ? next.delete(id) : next.add(id);\n return next;\n });\n }, []);\n\n const handleToggleLevel = useCallback((level: LogLevel) => {\n setSelectedLevels((prev) => {\n const next = new Set(prev);\n next.has(level) ? next.delete(level) : next.add(level);\n return next;\n });\n }, []);\n\n const handleExport = useCallback(() => {\n const json = exportLogs();\n const blob = new Blob([json], { type: 'application/json' });\n const url = URL.createObjectURL(blob);\n const a = document.createElement('a');\n a.href = url;\n a.download = `debug-logs-${new Date().toISOString().slice(0, 19).replace(/:/g, '-')}.json`;\n a.click();\n URL.revokeObjectURL(url);\n }, [exportLogs]);\n\n const handleClear = useCallback(() => {\n clearLogs();\n setExpandedLogs(new Set());\n }, [clearLogs]);\n\n const logsJson = exportLogs();\n const virtualItems = virtualizer.getVirtualItems();\n const totalSize = virtualizer.getTotalSize();\n\n return (\n <div className=\"flex flex-col h-full\">\n {/* Stats */}\n <div className=\"flex items-center gap-2 border-b border-border px-3 py-1.5 shrink-0\">\n <Badge variant=\"secondary\" className=\"text-[10px]\">{logCount} logs</Badge>\n {errorCount > 0 && <Badge variant=\"destructive\" className=\"text-[10px]\">{errorCount} errors</Badge>}\n </div>\n\n {/* Filters */}\n <div className=\"flex flex-wrap items-center gap-2 border-b border-border px-3 py-2 shrink-0\">\n <div className=\"relative flex-1 min-w-[140px]\">\n <Search className=\"absolute left-2 top-1/2 h-3.5 w-3.5 -translate-y-1/2 text-muted-foreground\" />\n <Input\n placeholder=\"Search...\"\n value={searchQuery}\n onChange={(e) => setSearchQuery(e.target.value)}\n className=\"h-7 pl-7 text-xs\"\n />\n </div>\n <Input\n placeholder=\"Component...\"\n value={componentFilter}\n onChange={(e) => setComponentFilter(e.target.value)}\n className=\"h-7 w-24 text-xs\"\n />\n <div className=\"flex items-center gap-0.5\">\n {LOG_LEVELS.map((level) => {\n const { icon: Icon, color } = LOG_LEVEL_CONFIG[level];\n const active = selectedLevels.has(level);\n return (\n <Tooltip key={level}>\n <TooltipTrigger asChild>\n <Button variant={active ? 'secondary' : 'ghost'} size=\"icon\" className=\"h-6 w-6\" onClick={() => handleToggleLevel(level)}>\n <Icon className={cn('h-3.5 w-3.5', active && color)} />\n </Button>\n </TooltipTrigger>\n <TooltipContent>{level}</TooltipContent>\n </Tooltip>\n );\n })}\n </div>\n <div className=\"flex items-center gap-0.5 ml-auto\">\n <CopyButton value={logsJson} size=\"icon\" className=\"h-6 w-6\" />\n <Tooltip>\n <TooltipTrigger asChild>\n <Button variant=\"ghost\" size=\"icon\" className=\"h-6 w-6\" onClick={handleExport}>\n <Download className=\"h-3.5 w-3.5\" />\n </Button>\n </TooltipTrigger>\n <TooltipContent>Export JSON</TooltipContent>\n </Tooltip>\n <Tooltip>\n <TooltipTrigger asChild>\n <Button variant=\"ghost\" size=\"icon\" className=\"h-6 w-6\" onClick={handleClear}>\n <Trash2 className=\"h-3.5 w-3.5\" />\n </Button>\n </TooltipTrigger>\n <TooltipContent>Clear</TooltipContent>\n </Tooltip>\n </div>\n </div>\n\n {/* Virtualized log list */}\n <div ref={scrollRef} className=\"flex-1 overflow-auto\">\n {logs.length === 0 ? (\n <div className=\"flex flex-col items-center justify-center py-10 text-muted-foreground\">\n <Bug className=\"h-8 w-8 mb-2 opacity-40\" />\n <p className=\"text-sm\">No logs yet</p>\n </div>\n ) : (\n <div style={{ height: `${totalSize}px`, position: 'relative' }}>\n {virtualItems.map((vItem: VirtualItem) => {\n const entry = logs[vItem.index];\n return (\n <div\n key={entry.id}\n data-index={vItem.index}\n ref={virtualizer.measureElement}\n style={{ position: 'absolute', top: 0, left: 0, width: '100%', transform: `translateY(${vItem.start}px)` }}\n >\n <LogEntryRow\n entry={entry}\n expanded={expandedLogs.has(entry.id)}\n onToggle={() => handleToggleExpand(entry.id)}\n />\n </div>\n );\n })}\n </div>\n )}\n </div>\n </div>\n );\n}\n\nexport const LogsPanel = memo(LogsPanelRaw);\n","'use client';\n\nimport { useState, useEffect, useRef, useCallback } from 'react';\nimport { subscribeAudioEvents, clearAudioEventBuffer } from '../emitters/audioEmitter';\nimport type { AudioDebugEvent, AudioEventKind } from '../emitters/audioEmitter';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface AudioLogEntry extends AudioDebugEvent {\n /** Local unique key for React rendering */\n id: string;\n}\n\nexport interface UseAudioEventLogResult {\n events: AudioLogEntry[];\n clear: () => void;\n /** Seek events per second (rolling 5s window) */\n seekRate: number;\n /** Average interval between 'sync' ticks in ms (e.g. RAF loop cadence) */\n syncIntervalMs: number | null;\n /** Running count per event kind */\n kindCounts: Partial<Record<AudioEventKind, number>>;\n}\n\n// ============================================================================\n// Constants\n// ============================================================================\n\nconst MAX_EVENTS = 200;\n\n// ============================================================================\n// Hook\n// ============================================================================\n\n/**\n * Subscribes to audio debug events and maintains a ring-buffer log.\n *\n * RAF batching: incoming events are queued in a ref and flushed into React\n * state once per animation frame — prevents render storms at 60fps.\n *\n * Only subscribes while `active` is true (panel tab is visible).\n */\nexport function useAudioEventLog(active: boolean): UseAudioEventLogResult {\n const [events, setEvents] = useState<AudioLogEntry[]>([]);\n const [syncIntervalMs, setSyncIntervalMs] = useState<number | null>(null);\n const [kindCounts, setKindCounts] = useState<Partial<Record<AudioEventKind, number>>>({});\n const [seekRate, setSeekRate] = useState(0);\n\n // Refs — mutated in the emitter callback without triggering renders\n const queueRef = useRef<AudioLogEntry[]>([]);\n const counterRef = useRef(0);\n const lastSyncTs = useRef<number | null>(null);\n const seekTimestamps = useRef<number[]>([]);\n const kindCountsRef = useRef<Partial<Record<AudioEventKind, number>>>({});\n\n const clear = useCallback(() => {\n clearAudioEventBuffer();\n queueRef.current = [];\n counterRef.current = 0;\n kindCountsRef.current = {};\n seekTimestamps.current = [];\n lastSyncTs.current = null;\n setEvents([]);\n setSyncIntervalMs(null);\n setKindCounts({});\n setSeekRate(0);\n }, []);\n\n // Subscribe — enqueue events without touching React state\n useEffect(() => {\n if (!active) return;\n\n const unsubscribe = subscribeAudioEvents((event) => {\n const entry: AudioLogEntry = { ...event, id: String(++counterRef.current) };\n queueRef.current.push(entry);\n\n // Track sync interval (no setState — RAF will pick it up)\n if (event.kind === 'sync') {\n if (lastSyncTs.current !== null) {\n const interval = event.ts - lastSyncTs.current;\n // Store on ref; RAF flush will call setSyncIntervalMs\n (entry as AudioLogEntry & { _interval?: number })._interval = interval;\n }\n lastSyncTs.current = event.ts;\n }\n\n // Track seeks\n if (event.kind === 'seek') {\n seekTimestamps.current.push(event.ts);\n }\n\n // Accumulate kind counts on ref\n kindCountsRef.current = {\n ...kindCountsRef.current,\n [event.kind]: (kindCountsRef.current[event.kind] ?? 0) + 1,\n };\n });\n\n return unsubscribe;\n }, [active]);\n\n // RAF flush loop — drains queue into React state once per frame\n useEffect(() => {\n if (!active) return;\n let rafId: number;\n\n const flush = () => {\n if (queueRef.current.length > 0) {\n const incoming = queueRef.current.splice(0);\n\n // Extract sync interval from last sync event in batch\n const lastSync = [...incoming].reverse().find((e) => e.kind === 'sync') as\n | (AudioLogEntry & { _interval?: number })\n | undefined;\n if (lastSync?._interval !== undefined) {\n setSyncIntervalMs(lastSync._interval);\n }\n\n setEvents((prev) => {\n const next = [...prev, ...incoming];\n return next.length > MAX_EVENTS ? next.slice(-MAX_EVENTS) : next;\n });\n\n setKindCounts({ ...kindCountsRef.current });\n }\n rafId = requestAnimationFrame(flush);\n };\n\n rafId = requestAnimationFrame(flush);\n return () => cancelAnimationFrame(rafId);\n }, [active]);\n\n // Rolling seek rate — recompute every second\n useEffect(() => {\n if (!active) return;\n const id = setInterval(() => {\n const now = Date.now();\n seekTimestamps.current = seekTimestamps.current.filter((t) => now - t < 5000);\n setSeekRate(Math.round((seekTimestamps.current.length / 5) * 10) / 10);\n }, 1000);\n return () => clearInterval(id);\n }, [active]);\n\n return { events, clear, seekRate, syncIntervalMs, kindCounts };\n}\n","'use client';\n\nimport React, { memo, useCallback, useState } from 'react';\nimport {\n Button,\n Badge,\n ScrollArea,\n} from '@djangocfg/ui-core/components';\nimport { cn } from '@djangocfg/ui-core/lib';\nimport { Trash2, Radio } from 'lucide-react';\nimport { useAudioEventLog } from '../hooks/useAudioEventLog';\nimport type { AudioEventKind } from '../emitters/audioEmitter';\n\n// ============================================================================\n// Types / constants\n// ============================================================================\n\ntype DebugAudioMode = 'off' | 'on' | 'verbose';\n\nconst DEBUG_MODES: DebugAudioMode[] = ['off', 'on', 'verbose'];\n\nconst KIND_STYLES: Record<AudioEventKind, { label: string; className: string }> = {\n play: { label: 'play', className: 'text-green-400' },\n pause: { label: 'pause', className: 'text-yellow-400' },\n seek: { label: 'seek', className: 'text-blue-400' },\n ended: { label: 'ended', className: 'text-muted-foreground' },\n sync: { label: 'sync', className: 'text-muted-foreground/50' },\n load: { label: 'load', className: 'text-purple-400' },\n error: { label: 'error', className: 'text-red-400' },\n engine: { label: 'eng', className: 'text-cyan-400' },\n custom: { label: 'custom', className: 'text-orange-400' },\n};\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\nfunction getDebugAudioMode(): DebugAudioMode {\n try {\n const v = localStorage.getItem('DEBUG_AUDIO');\n if (v === 'verbose') return 'verbose';\n if (v) return 'on';\n } catch { /* ssr */ }\n return 'off';\n}\n\nfunction formatTs(ts: number): string {\n const d = new Date(ts);\n return `${String(d.getHours()).padStart(2, '0')}:${String(d.getMinutes()).padStart(2, '0')}:${String(d.getSeconds()).padStart(2, '0')}.${String(d.getMilliseconds()).padStart(3, '0')}`;\n}\n\n// ============================================================================\n// Component\n// ============================================================================\n\ninterface AudioDebugPanelProps {\n isActive: boolean;\n}\n\n/**\n * AudioDebugPanel — real-time audio event log with metrics.\n *\n * Memoised: re-renders only when `isActive` changes. Internal event\n * log state is managed by the hook and does not break memoisation.\n */\nfunction AudioDebugPanelRaw({ isActive }: AudioDebugPanelProps) {\n const { events, clear, seekRate, syncIntervalMs, kindCounts } = useAudioEventLog(isActive);\n const [debugMode, setDebugMode] = useState<DebugAudioMode>(getDebugAudioMode);\n\n const handleSetDebugAudio = useCallback((mode: DebugAudioMode) => {\n if (mode === 'off') {\n localStorage.removeItem('DEBUG_AUDIO');\n } else {\n localStorage.setItem('DEBUG_AUDIO', mode === 'verbose' ? 'verbose' : '1');\n }\n setDebugMode(mode);\n }, []);\n\n const kindEntries = Object.entries(kindCounts) as [AudioEventKind, number][];\n const activeKinds = kindEntries.filter(([, count]) => count > 0);\n const reversedEvents = [...events].reverse();\n\n return (\n <div className=\"flex flex-col h-full\">\n {/* Metrics bar */}\n <div className=\"flex flex-wrap items-center gap-2 border-b border-border px-3 py-2 text-xs\">\n <span className=\"text-muted-foreground\">\n Sync interval:{' '}\n <span className=\"text-foreground font-mono\">\n {syncIntervalMs !== null ? `${syncIntervalMs.toFixed(1)}ms` : '—'}\n </span>\n </span>\n <span className=\"text-muted-foreground\">\n Seeks/s: <span className=\"text-foreground font-mono\">{seekRate}</span>\n </span>\n <span className=\"text-muted-foreground\">\n Total: <span className=\"text-foreground font-mono\">{events.length}</span>\n </span>\n\n <div className=\"flex gap-1 flex-wrap ml-auto\">\n {activeKinds.map(([kind, count]) => (\n <Badge key={kind} variant=\"outline\" className={cn('text-[10px] px-1 py-0', KIND_STYLES[kind]?.className)}>\n {KIND_STYLES[kind]?.label ?? kind} {count}\n </Badge>\n ))}\n </div>\n\n <Button variant=\"ghost\" size=\"icon\" className=\"h-6 w-6 ml-1\" onClick={clear}>\n <Trash2 className=\"h-3.5 w-3.5\" />\n </Button>\n </div>\n\n {/* DEBUG_AUDIO toggles */}\n <div className=\"flex items-center gap-1.5 border-b border-border px-3 py-1.5\">\n <span className=\"text-[10px] text-muted-foreground mr-1\">DEBUG_AUDIO:</span>\n {DEBUG_MODES.map((mode) => (\n <button\n key={mode}\n type=\"button\"\n className={cn(\n 'text-[10px] px-2 py-0.5 rounded border transition-colors',\n debugMode === mode\n ? 'border-primary bg-primary/10 text-primary'\n : 'border-border hover:bg-muted text-muted-foreground'\n )}\n onClick={() => handleSetDebugAudio(mode)}\n >\n {mode}\n </button>\n ))}\n </div>\n\n {/* Event log */}\n <ScrollArea className=\"flex-1\">\n {reversedEvents.length === 0 ? (\n <div className=\"flex flex-col items-center justify-center py-10 text-muted-foreground\">\n <Radio className=\"h-8 w-8 mb-2 opacity-40\" />\n <p className=\"text-sm\">No audio events yet</p>\n <p className=\"text-xs mt-1\">\n Wire <code className=\"text-xs\">emitAudioEvent()</code> into your audio engine\n </p>\n </div>\n ) : (\n <div className=\"divide-y divide-border/30\">\n {reversedEvents.map((entry) => {\n const style = KIND_STYLES[entry.kind] ?? { label: entry.kind, className: 'text-foreground' };\n return (\n <div key={entry.id} className=\"flex items-start gap-2 px-3 py-1 text-xs\">\n <span className=\"font-mono text-muted-foreground shrink-0 w-[88px]\">{formatTs(entry.ts)}</span>\n <span className={cn('shrink-0 w-12 font-medium', style.className)}>{style.label}</span>\n {entry.trackId && (\n <span className=\"shrink-0 font-mono text-muted-foreground\">{entry.trackId.slice(0, 6)}</span>\n )}\n <span className=\"truncate text-foreground/80\">{entry.msg}</span>\n </div>\n );\n })}\n </div>\n )}\n </ScrollArea>\n </div>\n );\n}\n\nexport const AudioDebugPanel = memo(AudioDebugPanelRaw);\n","'use client';\n\nimport React, { memo, useMemo, useState, useEffect } from 'react';\nimport { installMonitorBridge } from './bridges';\nimport { MONITOR_VERSION } from '@djangocfg/monitor/client';\nimport {\n Button,\n Badge,\n Tooltip,\n TooltipContent,\n TooltipTrigger,\n} from '@djangocfg/ui-core/components';\nimport { cn } from '@djangocfg/ui-core/lib';\nimport { useDebugErrorCount } from './logger';\nimport {\n X, Bug, Minimize2, Maximize2,\n ScrollText, Radio,\n} from 'lucide-react';\nimport { useDebugStore } from './store/debugStore';\nimport type { DebugTab } from './store/debugStore';\nimport { LogsPanel } from './panels/LogsPanel';\nimport { AudioDebugPanel } from './panels/AudioDebugPanel';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface CustomDebugTab {\n /** Unique id — will be added to DebugTab union at runtime */\n id: string;\n label: string;\n icon: React.ElementType;\n panel: React.ComponentType<{ isActive: boolean }>;\n}\n\nexport interface DebugPanelProps {\n /** Additional app-specific tabs */\n tabs?: CustomDebugTab[];\n position?: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left';\n defaultHeight?: number;\n defaultWidth?: number;\n}\n\n// ============================================================================\n// Built-in tabs\n// ============================================================================\n\nconst BUILTIN_TABS = [\n { id: 'logs', label: 'Logs', icon: ScrollText },\n { id: 'audio', label: 'Audio', icon: Radio },\n] as const;\n\nconst POSITION_CLASSES: Record<NonNullable<DebugPanelProps['position']>, string> = {\n 'bottom-right': 'bottom-4 right-4',\n 'bottom-left': 'bottom-4 left-4',\n 'top-right': 'top-4 right-4',\n 'top-left': 'top-4 left-4',\n};\n\n// ============================================================================\n// Component\n// ============================================================================\n\n/**\n * DebugPanel — floating debug panel with tabs (logs, audio, custom).\n *\n * Memoised: re-renders only when `tabs`, `position`, `defaultHeight`\n * or `defaultWidth` change. `tabs` array is compared by reference —\n * consumers should define it outside the component or memoise it.\n */\nfunction DebugPanelRaw({\n tabs: customTabs = [],\n position = 'bottom-left',\n defaultHeight = 480,\n defaultWidth = 560,\n}: DebugPanelProps) {\n const isOpen = useDebugStore((s) => s.isOpen);\n const activeTab = useDebugStore((s) => s.tab);\n const setTab = useDebugStore((s) => s.setTab);\n const close = useDebugStore((s) => s.close);\n const errorCount = useDebugErrorCount();\n\n const [isMinimized, setIsMinimized] = useState(false);\n\n useEffect(() => {\n const unsub = installMonitorBridge();\n return () => unsub?.();\n }, []);\n\n const allTabs = useMemo(() => [\n ...BUILTIN_TABS,\n ...customTabs.map((t) => ({ id: t.id, label: t.label, icon: t.icon })),\n ], [customTabs]);\n\n const panelHeight = isMinimized ? 48 : defaultHeight;\n\n if (!isOpen) return null;\n\n return (\n <div\n className={cn(\n 'fixed z-[100] flex flex-col overflow-hidden rounded-lg border border-border bg-background shadow-xl',\n POSITION_CLASSES[position]\n )}\n style={{ width: defaultWidth, height: panelHeight, backgroundColor: 'hsl(var(--background, 0 0% 4%))' }}\n >\n {/* Header */}\n <div className=\"flex items-center gap-2 border-b border-border px-3 py-2 shrink-0\" style={{ backgroundColor: 'hsl(var(--muted, 0 0% 10%) / 0.5)' }}>\n <Bug className=\"h-4 w-4 text-primary\" />\n <span className=\"text-sm font-medium\">Debug</span>\n <span className=\"text-[10px] text-muted-foreground font-mono\">v{MONITOR_VERSION}</span>\n\n {errorCount > 0 && (\n <Badge variant=\"destructive\" className=\"ml-1 text-[10px]\">{errorCount} errors</Badge>\n )}\n\n {/* Tab bar */}\n {!isMinimized && (\n <div className=\"flex items-center gap-0.5 ml-3\">\n {allTabs.map((tab) => {\n const Icon = tab.icon;\n const isActive = activeTab === tab.id;\n return (\n <button\n key={tab.id}\n type=\"button\"\n onClick={() => setTab(tab.id as DebugTab)}\n className={cn(\n 'flex items-center gap-1.5 px-2 py-0.5 rounded text-xs transition-colors',\n isActive\n ? 'bg-background text-foreground shadow-sm'\n : 'text-muted-foreground hover:text-foreground hover:bg-muted'\n )}\n >\n <Icon className=\"h-3 w-3\" />\n {tab.label}\n </button>\n );\n })}\n </div>\n )}\n\n <div className=\"flex items-center gap-1 ml-auto\">\n <Tooltip>\n <TooltipTrigger asChild>\n <Button variant=\"ghost\" size=\"icon\" className=\"h-6 w-6\" onClick={() => setIsMinimized((v) => !v)}>\n {isMinimized ? <Maximize2 className=\"h-3.5 w-3.5\" /> : <Minimize2 className=\"h-3.5 w-3.5\" />}\n </Button>\n </TooltipTrigger>\n <TooltipContent>{isMinimized ? 'Expand' : 'Minimize'}</TooltipContent>\n </Tooltip>\n <Tooltip>\n <TooltipTrigger asChild>\n <Button variant=\"ghost\" size=\"icon\" className=\"h-6 w-6\" onClick={close}>\n <X className=\"h-3.5 w-3.5\" />\n </Button>\n </TooltipTrigger>\n <TooltipContent>Close</TooltipContent>\n </Tooltip>\n </div>\n </div>\n\n {/* Panel content */}\n {!isMinimized && (\n <div className=\"flex-1 overflow-hidden\">\n {activeTab === 'logs' && <LogsPanel isActive={activeTab === 'logs'} />}\n {activeTab === 'audio' && <AudioDebugPanel isActive={activeTab === 'audio'} />}\n {customTabs.map((tab) => {\n const Panel = tab.panel;\n return (\n <div key={tab.id} className={cn('h-full', activeTab !== tab.id && 'hidden')}>\n <Panel isActive={activeTab === tab.id} />\n </div>\n );\n })}\n </div>\n )}\n </div>\n );\n}\n\nexport const DebugPanel = memo(DebugPanelRaw);\n","'use client';\n\nimport React, { memo, useCallback, useEffect, useRef } from 'react';\nimport { Bug } from 'lucide-react';\nimport {\n Tooltip,\n TooltipContent,\n TooltipTrigger,\n} from '@djangocfg/ui-core/components';\nimport { cn, isDev } from '@djangocfg/ui-core/lib';\nimport { useDebugMode } from '@djangocfg/monitor/client';\nimport { useDebugStore } from './store/debugStore';\nimport { useDebugShortcut } from './hooks/useDebugShortcut';\nimport { useDebugErrorCount } from './logger';\nimport { DebugPanel } from './DebugPanel';\nimport type { DebugPanelProps } from './DebugPanel';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface DebugButtonProps {\n className?: string;\n /** Props forwarded to DebugPanel */\n panel?: Omit<DebugPanelProps, never>;\n /** Explicitly disable. Default: undefined (auto — visible in dev, hidden in prod, ?debug=1 always works) */\n enabled?: boolean;\n}\n\n// ============================================================================\n// DebugButton\n//\n// Visibility rules (simple):\n// 1. enabled === false AND no ?debug=1 → hidden completely\n// 2. isDev OR ?debug=1 (localStorage) → visible (unlocked)\n// 3. prod without ?debug=1 → invisible click trap (easter egg: 5 clicks)\n//\n// Memoised: re-renders only when `className`, `panel`, or `enabled` change.\n// Internal store subscriptions (isOpen, isUnlocked, errorCount) are handled\n// by zustand selectors and do not cause parent re-renders.\n// ============================================================================\n\nfunction DebugButtonRaw({ className, panel = {}, enabled }: DebugButtonProps) {\n // All hooks called unconditionally (React rules of hooks)\n const isOpen = useDebugStore((s) => s.isOpen);\n const isUnlocked = useDebugStore((s) => s.isUnlocked);\n const unlock = useDebugStore((s) => s.unlock);\n const toggle = useDebugStore((s) => s.toggle);\n const isDebugMode = useDebugMode();\n const errorCount = useDebugErrorCount();\n useDebugShortcut();\n\n // Should this button be visible (unlocked)?\n const shouldUnlock = isDev || isDebugMode;\n\n // eslint-disable-next-line no-console\n // if (typeof window !== 'undefined') console.info('[DebugButton]', { isDev, isDebugMode, shouldUnlock, isUnlocked, enabled });\n\n // Auto-unlock in dev or when ?debug=1\n useEffect(() => {\n if (shouldUnlock) unlock('1');\n }, [shouldUnlock, unlock]);\n\n // Hide Next.js dev indicator while panel is open\n useEffect(() => {\n if (typeof document === 'undefined') return;\n const apply = () => {\n document.querySelectorAll<HTMLElement>('nextjs-portal').forEach((el) => {\n el.style.display = isOpen ? 'none' : '';\n });\n };\n apply();\n const observer = new MutationObserver(apply);\n observer.observe(document.body, { childList: true });\n return () => observer.disconnect();\n }, [isOpen]);\n\n // Easter egg: 5 clicks in 2s → unlock\n const clicks = useRef<number[]>([]);\n const handleEasterEgg = useCallback(() => {\n const now = Date.now();\n clicks.current = [...clicks.current.filter((t) => now - t < 2000), now];\n if (clicks.current.length >= 5) {\n clicks.current = [];\n unlock('1');\n toggle();\n }\n }, [unlock, toggle]);\n\n // === Render decision (after all hooks) ===\n\n // Explicitly disabled AND no debug override → don't render at all\n if (enabled === false && !isDebugMode) return null;\n\n // Not unlocked → invisible click trap for easter egg\n if (!isUnlocked) {\n return (\n <div\n className=\"fixed bottom-5 left-5 w-9 h-9 z-[99999] opacity-0 cursor-default\"\n onClick={handleEasterEgg}\n />\n );\n }\n\n // Unlocked → visible debug button\n return (\n <>\n {!isOpen && (\n <div className={cn('fixed bottom-5 z-[99999]', isDev ? 'left-16' : 'left-5')}>\n <Tooltip>\n <TooltipTrigger asChild>\n <button\n type=\"button\"\n className={cn(\n 'relative w-9 h-9 flex items-center justify-center rounded-full',\n 'bg-black/80 backdrop-blur-xl',\n 'shadow-[0_0_0_1px_#171717,inset_0_0_0_1px_hsla(0,0%,100%,0.14),0px_16px_32px_-8px_rgba(0,0,0,0.24)]',\n 'transition-all duration-150 hover:scale-105',\n 'focus:outline-none focus-visible:ring-2 focus-visible:ring-white/50',\n errorCount > 0 && 'bg-red-600/90',\n className,\n )}\n onClick={toggle}\n >\n <Bug className={cn('h-4 w-4', errorCount > 0 ? 'text-white' : 'text-white/80')} />\n {errorCount > 0 && (\n <span className=\"absolute -right-1 -top-1 flex h-4 min-w-4 items-center justify-center rounded-full bg-white text-[10px] font-semibold text-red-600 shadow-sm\">\n {errorCount}\n </span>\n )}\n </button>\n </TooltipTrigger>\n <TooltipContent side=\"top\">Debug Panel <kbd className=\"ml-1 text-[10px] opacity-60\">⌘D</kbd></TooltipContent>\n </Tooltip>\n </div>\n )}\n <DebugPanel {...panel} />\n </>\n );\n}\n\nexport const DebugButton = memo(DebugButtonRaw);\n","'use client';\n\nimport { useState, useEffect, useRef } from 'react';\n\n// ============================================================================\n// Shallow equal (avoids unnecessary re-renders)\n// ============================================================================\n\nfunction shallowEqual(a: unknown, b: unknown): boolean {\n if (a === b) return true;\n if (typeof a !== 'object' || typeof b !== 'object') return false;\n if (a === null || b === null) return false;\n const keysA = Object.keys(a as object);\n const keysB = Object.keys(b as object);\n if (keysA.length !== keysB.length) return false;\n for (const key of keysA) {\n if ((a as Record<string, unknown>)[key] !== (b as Record<string, unknown>)[key]) return false;\n }\n return true;\n}\n\n// ============================================================================\n// Hook\n// ============================================================================\n\n/**\n * Polling-based external Zustand store snapshot.\n *\n * Reads the store state via `getState()` on an interval — NOT via reactive\n * subscription. This prevents debug panel renders from being triggered by\n * high-frequency store updates and avoids Zustand v5 infinite loop issues\n * (returning new object references from selectors without useShallow).\n *\n * Only polls while `active` is true (panel tab is visible).\n *\n * @param getState A stable function that returns the current store state slice.\n * Use `() => useMyStore.getState()` — the hook ref-stabilizes it.\n * @param intervalMs Poll interval in ms. Default 200ms.\n * @param active Whether to poll. Pass `isActive` from panel props.\n *\n * @example\n * const snap = useStoreSnapshot(\n * () => useTimelineStore.getState(),\n * 200,\n * isActive\n * );\n */\nexport function useStoreSnapshot<T>(\n getState: () => T,\n intervalMs = 200,\n active = true,\n): T {\n const getStateRef = useRef(getState);\n getStateRef.current = getState;\n\n const [snapshot, setSnapshot] = useState<T>(() => getState());\n\n useEffect(() => {\n if (!active) return;\n\n const id = setInterval(() => {\n const next = getStateRef.current();\n setSnapshot((prev) => (shallowEqual(prev, next) ? prev : next));\n }, intervalMs);\n\n return () => clearInterval(id);\n }, [active, intervalMs]);\n\n return snapshot;\n}\n","'use client';\n\nimport React, { memo } from 'react';\nimport { ScrollArea } from '@djangocfg/ui-core/components';\nimport { LazyJsonTree } from '@djangocfg/ui-tools';\nimport { Database } from 'lucide-react';\nimport { useStoreSnapshot } from '../hooks/useStoreSnapshot';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface StorePanelProps {\n /** Display label shown above the JSON tree */\n label: string;\n /**\n * Getter for the store state slice to display.\n * Use `() => useMyStore.getState()` — stable function ref is not required,\n * the hook handles stabilization internally.\n */\n getState: () => Record<string, unknown>;\n /**\n * Poll interval in ms. Default 200ms.\n * Use higher values for stores that update very frequently.\n */\n intervalMs?: number;\n /** Only polls when active (panel tab is visible) */\n isActive: boolean;\n}\n\n// ============================================================================\n// Component\n// ============================================================================\n\n/**\n * Generic Zustand store viewer for the debug panel.\n *\n * Uses polling (not reactive subscription) to read external store state.\n * This avoids Zustand v5 infinite loop issues and prevents the debug panel\n * from re-rendering on every store change.\n *\n * @example — in consuming app's custom tab:\n * import { StorePanel } from '@org/debuger';\n * import { useTimelineStore } from '@stores/timelineStore';\n *\n * <StorePanel\n * label=\"Timeline Store\"\n * getState={() => useTimelineStore.getState()}\n * isActive={isActive}\n * />\n *\n * Memoised: re-renders only when `label`, `getState`, `intervalMs` or\n * `isActive` change. `getState` is compared by reference — callers should\n * stabilise it (e.g. define outside the component or wrap in useCallback).\n */\nfunction StorePanelRaw({ label, getState, intervalMs = 200, isActive }: StorePanelProps) {\n const snapshot = useStoreSnapshot(getState, intervalMs, isActive);\n\n return (\n <div className=\"flex flex-col h-full\">\n <div className=\"flex items-center gap-2 border-b border-border px-3 py-2 shrink-0\">\n <Database className=\"h-3.5 w-3.5 text-muted-foreground\" />\n <span className=\"text-xs font-medium text-muted-foreground\">{label}</span>\n <span className=\"ml-auto text-[10px] text-muted-foreground/60\">\n polling {intervalMs}ms\n </span>\n </div>\n <ScrollArea className=\"flex-1\">\n <div className=\"p-2\">\n <LazyJsonTree data={snapshot} mode=\"full\" />\n </div>\n </ScrollArea>\n </div>\n );\n}\n\nexport const StorePanel = memo(StorePanelRaw);\n","'use client';\n\nimport { useState, useEffect, useRef, useCallback } from 'react';\nimport { subscribeCustomEvents } from '../emitters/customEmitter';\nimport type { CustomDebugEvent } from '../emitters/customEmitter';\n\nexport interface CustomLogEntry extends CustomDebugEvent {\n id: string;\n}\n\nconst MAX_EVENTS = 300;\n\n/**\n * Subscribes to custom channel events and maintains a ring-buffer per channel.\n * Pass `channel` to filter — or undefined to receive all channels.\n */\nexport function useCustomEventLog(active: boolean, channel?: string) {\n const [events, setEvents] = useState<CustomLogEntry[]>([]);\n const counterRef = useRef(0);\n\n const clear = useCallback(() => setEvents([]), []);\n\n useEffect(() => {\n if (!active) return;\n\n const unsubscribe = subscribeCustomEvents((event) => {\n if (channel && event.channel !== channel) return;\n const entry: CustomLogEntry = { ...event, id: String(++counterRef.current) };\n setEvents((prev) => {\n const next = [...prev, entry];\n return next.length > MAX_EVENTS ? next.slice(-MAX_EVENTS) : next;\n });\n });\n\n return unsubscribe;\n }, [active, channel]);\n\n return { events, clear };\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@djangocfg/debuger",
3
- "version": "2.1.356",
3
+ "version": "2.1.357",
4
4
  "description": "Floating debug panel for DjangoCFG — logs, store inspection, monitor bridge, Cmd+D shortcut",
5
5
  "keywords": [
6
6
  "debug",
@@ -63,10 +63,10 @@
63
63
  "react-dom": "^19.1.0",
64
64
  "zustand": "^5.0.0",
65
65
  "consola": "^3.4.2",
66
- "@djangocfg/ui-core": "^2.1.356",
67
- "@djangocfg/ui-tools": "^2.1.356",
66
+ "@djangocfg/ui-core": "^2.1.357",
67
+ "@djangocfg/ui-tools": "^2.1.357",
68
68
  "@tanstack/react-virtual": "^3.0.0",
69
- "@djangocfg/monitor": "^2.1.356",
69
+ "@djangocfg/monitor": "^2.1.357",
70
70
  "lucide-react": ">=0.400.0"
71
71
  },
72
72
  "peerDependenciesMeta": {
@@ -78,8 +78,8 @@
78
78
  }
79
79
  },
80
80
  "devDependencies": {
81
- "@djangocfg/typescript-config": "^2.1.356",
82
- "@djangocfg/monitor": "^2.1.356",
81
+ "@djangocfg/typescript-config": "^2.1.357",
82
+ "@djangocfg/monitor": "^2.1.357",
83
83
  "lucide-react": "^0.545.0",
84
84
  "@types/node": "^25.2.3",
85
85
  "@types/react": "^19.1.0",
@@ -1,6 +1,6 @@
1
1
  'use client';
2
2
 
3
- import React, { useCallback, useEffect, useRef } from 'react';
3
+ import React, { memo, useCallback, useEffect, useRef } from 'react';
4
4
  import { Bug } from 'lucide-react';
5
5
  import {
6
6
  Tooltip,
@@ -34,9 +34,13 @@ export interface DebugButtonProps {
34
34
  // 1. enabled === false AND no ?debug=1 → hidden completely
35
35
  // 2. isDev OR ?debug=1 (localStorage) → visible (unlocked)
36
36
  // 3. prod without ?debug=1 → invisible click trap (easter egg: 5 clicks)
37
+ //
38
+ // Memoised: re-renders only when `className`, `panel`, or `enabled` change.
39
+ // Internal store subscriptions (isOpen, isUnlocked, errorCount) are handled
40
+ // by zustand selectors and do not cause parent re-renders.
37
41
  // ============================================================================
38
42
 
39
- export function DebugButton({ className, panel = {}, enabled }: DebugButtonProps) {
43
+ function DebugButtonRaw({ className, panel = {}, enabled }: DebugButtonProps) {
40
44
  // All hooks called unconditionally (React rules of hooks)
41
45
  const isOpen = useDebugStore((s) => s.isOpen);
42
46
  const isUnlocked = useDebugStore((s) => s.isUnlocked);
@@ -134,3 +138,5 @@ export function DebugButton({ className, panel = {}, enabled }: DebugButtonProps
134
138
  </>
135
139
  );
136
140
  }
141
+
142
+ export const DebugButton = memo(DebugButtonRaw);