@hansenexus/hud 0.1.0
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/LICENSE +21 -0
- package/README.md +48 -0
- package/chunk-0cj8dkk7.js +127 -0
- package/chunk-1atxwdhw.js +48 -0
- package/chunk-24vrg16w.js +39 -0
- package/chunk-3j9sm249.js +26 -0
- package/chunk-50pq4sg6.js +41 -0
- package/chunk-5gtx3pza.js +9 -0
- package/chunk-6gw4x08j.js +264 -0
- package/chunk-6jt8yg4m.js +117 -0
- package/chunk-71se605m.js +85 -0
- package/chunk-82nm9wcg.js +316 -0
- package/chunk-8tam7r3h.js +68 -0
- package/chunk-babjpqkb.js +52 -0
- package/chunk-c5y856ad.js +98 -0
- package/chunk-ghxh8926.js +172 -0
- package/chunk-hc2g0n35.js +24 -0
- package/chunk-k0vr8dsy.js +179 -0
- package/chunk-k50yfp5d.js +166 -0
- package/chunk-kyeb6qeq.js +95 -0
- package/chunk-msqkkqw7.js +140 -0
- package/chunk-nm82wr8r.js +58 -0
- package/chunk-r06bpmy6.js +79 -0
- package/chunk-t9eh4t0b.js +89 -0
- package/chunk-tf774c4w.js +115 -0
- package/chunk-v086j53b.js +19 -0
- package/chunk-wspz08q7.js +67 -0
- package/chunk-xezxydm3.js +47 -0
- package/chunk-xjn0896g.js +574 -0
- package/chunk-xztw0xyt.js +113 -0
- package/chunk-zzrpd92r.js +172 -0
- package/core/access.d.mts +53 -0
- package/core/access.js +27 -0
- package/core/api-types.d.mts +146 -0
- package/core/api-types.js +9 -0
- package/core/capabilities.d.mts +27 -0
- package/core/capabilities.js +14 -0
- package/core/capture-buffer.d.mts +37 -0
- package/core/capture-buffer.js +9 -0
- package/core/force-state.d.mts +68 -0
- package/core/force-state.js +21 -0
- package/core/mock-cookie.d.mts +30 -0
- package/core/mock-cookie.js +15 -0
- package/core/types.d.mts +59 -0
- package/core/types.js +9 -0
- package/hud-provider.d.mts +38 -0
- package/hud-provider.js +15 -0
- package/hud.d.mts +15 -0
- package/hud.js +18 -0
- package/index.d.mts +94 -0
- package/index.js +170 -0
- package/lazy-panel.d.mts +28 -0
- package/lazy-panel.js +11 -0
- package/package.json +153 -0
- package/panels/cicd-panel.d.mts +9 -0
- package/panels/cicd-panel.js +13 -0
- package/panels/debug-info-panel.d.mts +21 -0
- package/panels/debug-info-panel.js +9 -0
- package/panels/dispatch-panel.d.mts +10 -0
- package/panels/dispatch-panel.js +14 -0
- package/panels/env-info-panel.d.mts +9 -0
- package/panels/env-info-panel.js +12 -0
- package/panels/feature-flags-panel.d.mts +26 -0
- package/panels/feature-flags-panel.js +9 -0
- package/panels/force-state-panel.d.mts +11 -0
- package/panels/force-state-panel.js +113 -0
- package/panels/info-row.d.mts +21 -0
- package/panels/info-row.js +14 -0
- package/panels/mock-seed-panel.d.mts +15 -0
- package/panels/mock-seed-panel.js +14 -0
- package/panels/network-console-panel.d.mts +6 -0
- package/panels/network-console-panel.js +9 -0
- package/panels/role-switcher-panel.d.mts +28 -0
- package/panels/role-switcher-panel.js +9 -0
- package/panels/sessions-panel.d.mts +6 -0
- package/panels/sessions-panel.js +13 -0
- package/panels/tokens-panel.d.mts +38 -0
- package/panels/tokens-panel.js +9 -0
- package/panels/unlock-panel.d.mts +33 -0
- package/panels/unlock-panel.js +14 -0
- package/panels/variants-panel.d.mts +51 -0
- package/panels/variants-panel.js +12 -0
- package/panels/vitals-panel.d.mts +11 -0
- package/panels/vitals-panel.js +15 -0
- package/server/guard.d.mts +42 -0
- package/server/guard.js +12 -0
- package/server/unlock.d.mts +28 -0
- package/server/unlock.js +108 -0
- package/state-boundary.d.mts +25 -0
- package/state-boundary.js +54 -0
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import {
|
|
2
|
+
LoadingSpinner,
|
|
3
|
+
PanelSection
|
|
4
|
+
} from "./chunk-kyeb6qeq.js";
|
|
5
|
+
import {
|
|
6
|
+
Badge,
|
|
7
|
+
Button
|
|
8
|
+
} from "./chunk-xztw0xyt.js";
|
|
9
|
+
|
|
10
|
+
// panels/role-switcher-panel.tsx
|
|
11
|
+
import { Check, Shield, User } from "lucide-react";
|
|
12
|
+
import { useState } from "react";
|
|
13
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
14
|
+
"use client";
|
|
15
|
+
function RoleSwitcherPanel({ adapter }) {
|
|
16
|
+
const { roles, currentRoleId, currentUserLabel, isLoading = false, onSwitch } = adapter;
|
|
17
|
+
const [switching, setSwitching] = useState(false);
|
|
18
|
+
const [error, setError] = useState(null);
|
|
19
|
+
async function handleSwitch(roleId) {
|
|
20
|
+
if (roleId === currentRoleId)
|
|
21
|
+
return;
|
|
22
|
+
setSwitching(true);
|
|
23
|
+
setError(null);
|
|
24
|
+
try {
|
|
25
|
+
await onSwitch(roleId);
|
|
26
|
+
} catch (err) {
|
|
27
|
+
setError(err instanceof Error ? err.message : "Role switch failed");
|
|
28
|
+
} finally {
|
|
29
|
+
setSwitching(false);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
if (isLoading)
|
|
33
|
+
return /* @__PURE__ */ jsx(LoadingSpinner, {});
|
|
34
|
+
const current = roles.find((role) => role.id === currentRoleId);
|
|
35
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
36
|
+
className: "space-y-4",
|
|
37
|
+
children: [
|
|
38
|
+
/* @__PURE__ */ jsx(PanelSection, {
|
|
39
|
+
icon: Shield,
|
|
40
|
+
title: "Current Role",
|
|
41
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
42
|
+
className: "border bg-muted/30 px-3 py-2",
|
|
43
|
+
children: [
|
|
44
|
+
/* @__PURE__ */ jsxs("div", {
|
|
45
|
+
className: "flex items-center gap-2",
|
|
46
|
+
children: [
|
|
47
|
+
/* @__PURE__ */ jsx(User, {
|
|
48
|
+
className: "h-4 w-4 text-muted-foreground"
|
|
49
|
+
}),
|
|
50
|
+
/* @__PURE__ */ jsx("span", {
|
|
51
|
+
className: "text-sm font-medium",
|
|
52
|
+
children: currentUserLabel ?? "Unknown"
|
|
53
|
+
})
|
|
54
|
+
]
|
|
55
|
+
}),
|
|
56
|
+
/* @__PURE__ */ jsx(Badge, {
|
|
57
|
+
variant: "outline",
|
|
58
|
+
className: `mt-1 ${current?.badgeClassName ?? ""}`,
|
|
59
|
+
children: current?.label ?? currentRoleId ?? "—"
|
|
60
|
+
})
|
|
61
|
+
]
|
|
62
|
+
})
|
|
63
|
+
}),
|
|
64
|
+
/* @__PURE__ */ jsx(PanelSection, {
|
|
65
|
+
title: "Switch Role",
|
|
66
|
+
children: roles.map((role) => {
|
|
67
|
+
const isCurrent = role.id === currentRoleId;
|
|
68
|
+
return /* @__PURE__ */ jsxs(Button, {
|
|
69
|
+
variant: "ghost",
|
|
70
|
+
size: "sm",
|
|
71
|
+
disabled: isCurrent || switching,
|
|
72
|
+
className: "w-full justify-between text-xs",
|
|
73
|
+
onClick: () => handleSwitch(role.id),
|
|
74
|
+
children: [
|
|
75
|
+
/* @__PURE__ */ jsxs("div", {
|
|
76
|
+
className: "flex items-center gap-2",
|
|
77
|
+
children: [
|
|
78
|
+
/* @__PURE__ */ jsx("span", {
|
|
79
|
+
className: `h-2 w-2 rounded-full ${isCurrent ? "bg-primary" : "bg-muted-foreground/30"}`
|
|
80
|
+
}),
|
|
81
|
+
/* @__PURE__ */ jsx("span", {
|
|
82
|
+
children: role.label
|
|
83
|
+
})
|
|
84
|
+
]
|
|
85
|
+
}),
|
|
86
|
+
/* @__PURE__ */ jsxs("div", {
|
|
87
|
+
className: "flex items-center gap-1.5",
|
|
88
|
+
children: [
|
|
89
|
+
role.level !== undefined && /* @__PURE__ */ jsxs("span", {
|
|
90
|
+
className: "text-[10px] text-muted-foreground",
|
|
91
|
+
children: [
|
|
92
|
+
"Lvl ",
|
|
93
|
+
role.level
|
|
94
|
+
]
|
|
95
|
+
}),
|
|
96
|
+
isCurrent && /* @__PURE__ */ jsx(Check, {
|
|
97
|
+
className: "h-3 w-3 text-primary"
|
|
98
|
+
})
|
|
99
|
+
]
|
|
100
|
+
})
|
|
101
|
+
]
|
|
102
|
+
}, role.id);
|
|
103
|
+
})
|
|
104
|
+
}),
|
|
105
|
+
error && /* @__PURE__ */ jsx("p", {
|
|
106
|
+
className: "px-2 text-[10px] text-destructive",
|
|
107
|
+
children: error
|
|
108
|
+
}),
|
|
109
|
+
/* @__PURE__ */ jsx("p", {
|
|
110
|
+
className: "text-[10px] text-muted-foreground/60",
|
|
111
|
+
children: "Role changes take effect immediately. Use this for testing role-based access."
|
|
112
|
+
})
|
|
113
|
+
]
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export { RoleSwitcherPanel };
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import {
|
|
2
|
+
LoadingSpinner
|
|
3
|
+
} from "./chunk-kyeb6qeq.js";
|
|
4
|
+
import {
|
|
5
|
+
Badge,
|
|
6
|
+
Switch
|
|
7
|
+
} from "./chunk-xztw0xyt.js";
|
|
8
|
+
|
|
9
|
+
// panels/feature-flags-panel.tsx
|
|
10
|
+
import { Flag } from "lucide-react";
|
|
11
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
12
|
+
"use client";
|
|
13
|
+
function FeatureFlagsPanel({ adapter }) {
|
|
14
|
+
const { flags, isLoading = false, onToggle } = adapter;
|
|
15
|
+
if (isLoading)
|
|
16
|
+
return /* @__PURE__ */ jsx(LoadingSpinner, {});
|
|
17
|
+
const categories = [...new Set(flags.map((flag) => flag.category ?? "general"))];
|
|
18
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
19
|
+
className: "space-y-4",
|
|
20
|
+
children: [
|
|
21
|
+
categories.map((category) => /* @__PURE__ */ jsxs("div", {
|
|
22
|
+
children: [
|
|
23
|
+
/* @__PURE__ */ jsxs("h4", {
|
|
24
|
+
className: "mb-2 flex items-center gap-1.5 text-[11px] font-semibold uppercase tracking-wider text-muted-foreground",
|
|
25
|
+
children: [
|
|
26
|
+
/* @__PURE__ */ jsx(Flag, {
|
|
27
|
+
className: "h-3 w-3"
|
|
28
|
+
}),
|
|
29
|
+
category
|
|
30
|
+
]
|
|
31
|
+
}),
|
|
32
|
+
/* @__PURE__ */ jsx("div", {
|
|
33
|
+
className: "space-y-1",
|
|
34
|
+
children: flags.filter((flag) => (flag.category ?? "general") === category).map((flag) => /* @__PURE__ */ jsx(FlagRow, {
|
|
35
|
+
flag,
|
|
36
|
+
onToggle: () => void onToggle(flag.id)
|
|
37
|
+
}, flag.id))
|
|
38
|
+
})
|
|
39
|
+
]
|
|
40
|
+
}, category)),
|
|
41
|
+
flags.length === 0 && /* @__PURE__ */ jsx("p", {
|
|
42
|
+
className: "px-2 text-[10px] text-muted-foreground/60",
|
|
43
|
+
children: "No flags registered."
|
|
44
|
+
})
|
|
45
|
+
]
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
function FlagRow({ flag, onToggle }) {
|
|
49
|
+
const isOverridden = flag.enabled !== flag.defaultValue;
|
|
50
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
51
|
+
className: "flex items-center justify-between px-2 py-1.5 hover:bg-muted/50",
|
|
52
|
+
children: [
|
|
53
|
+
/* @__PURE__ */ jsxs("div", {
|
|
54
|
+
className: "min-w-0 flex-1",
|
|
55
|
+
children: [
|
|
56
|
+
/* @__PURE__ */ jsxs("div", {
|
|
57
|
+
className: "flex items-center gap-1.5",
|
|
58
|
+
children: [
|
|
59
|
+
/* @__PURE__ */ jsx("span", {
|
|
60
|
+
className: "text-xs font-medium",
|
|
61
|
+
children: flag.label
|
|
62
|
+
}),
|
|
63
|
+
isOverridden && /* @__PURE__ */ jsx(Badge, {
|
|
64
|
+
variant: "outline",
|
|
65
|
+
className: "h-4 border-amber-500/50 px-1 text-[9px] text-amber-500",
|
|
66
|
+
children: "overridden"
|
|
67
|
+
})
|
|
68
|
+
]
|
|
69
|
+
}),
|
|
70
|
+
flag.description && /* @__PURE__ */ jsx("p", {
|
|
71
|
+
className: "truncate text-[10px] text-muted-foreground",
|
|
72
|
+
children: flag.description
|
|
73
|
+
})
|
|
74
|
+
]
|
|
75
|
+
}),
|
|
76
|
+
/* @__PURE__ */ jsx(Switch, {
|
|
77
|
+
checked: flag.enabled,
|
|
78
|
+
onCheckedChange: onToggle,
|
|
79
|
+
className: "ml-2 shrink-0"
|
|
80
|
+
})
|
|
81
|
+
]
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export { FeatureFlagsPanel };
|
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Badge,
|
|
3
|
+
Button,
|
|
4
|
+
cn
|
|
5
|
+
} from "./chunk-xztw0xyt.js";
|
|
6
|
+
|
|
7
|
+
// grabber/grabber-store.ts
|
|
8
|
+
var state = { mode: "idle", payload: null };
|
|
9
|
+
var listeners = new Set;
|
|
10
|
+
function setState(next) {
|
|
11
|
+
state = next;
|
|
12
|
+
for (const listener of listeners)
|
|
13
|
+
listener();
|
|
14
|
+
}
|
|
15
|
+
function getGrabberState() {
|
|
16
|
+
return state;
|
|
17
|
+
}
|
|
18
|
+
function subscribeGrabber(listener) {
|
|
19
|
+
listeners.add(listener);
|
|
20
|
+
return () => listeners.delete(listener);
|
|
21
|
+
}
|
|
22
|
+
function startGrab() {
|
|
23
|
+
setState({ ...state, mode: "grabbing" });
|
|
24
|
+
}
|
|
25
|
+
function cancelGrab() {
|
|
26
|
+
setState({ ...state, mode: "idle" });
|
|
27
|
+
}
|
|
28
|
+
function completeGrab(payload) {
|
|
29
|
+
setState({ mode: "idle", payload });
|
|
30
|
+
}
|
|
31
|
+
function clearGrabbedPayload() {
|
|
32
|
+
setState({ ...state, payload: null });
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// ../dev-tools/drawer/dev-drawer-provider.tsx
|
|
36
|
+
import {
|
|
37
|
+
createContext,
|
|
38
|
+
useCallback,
|
|
39
|
+
useContext,
|
|
40
|
+
useEffect,
|
|
41
|
+
useMemo,
|
|
42
|
+
useState
|
|
43
|
+
} from "react";
|
|
44
|
+
import { jsx } from "react/jsx-runtime";
|
|
45
|
+
"use client";
|
|
46
|
+
var DevDrawerContext = createContext(null);
|
|
47
|
+
var DEFAULTS = {
|
|
48
|
+
defaultHeight: 40,
|
|
49
|
+
minHeight: 25,
|
|
50
|
+
maxHeight: 80,
|
|
51
|
+
shortcutKey: "d"
|
|
52
|
+
};
|
|
53
|
+
function loadStored(storageKey) {
|
|
54
|
+
if (!storageKey || typeof window === "undefined")
|
|
55
|
+
return {};
|
|
56
|
+
try {
|
|
57
|
+
const raw = localStorage.getItem(storageKey);
|
|
58
|
+
if (!raw)
|
|
59
|
+
return {};
|
|
60
|
+
const parsed = JSON.parse(raw);
|
|
61
|
+
return {
|
|
62
|
+
height: typeof parsed.height === "number" ? parsed.height : undefined,
|
|
63
|
+
activeTab: typeof parsed.activeTab === "string" ? parsed.activeTab : undefined
|
|
64
|
+
};
|
|
65
|
+
} catch {
|
|
66
|
+
return {};
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
function persist(storageKey, state2) {
|
|
70
|
+
if (!storageKey || typeof window === "undefined")
|
|
71
|
+
return;
|
|
72
|
+
try {
|
|
73
|
+
localStorage.setItem(storageKey, JSON.stringify(state2));
|
|
74
|
+
} catch {}
|
|
75
|
+
}
|
|
76
|
+
function DevDrawerProvider({ config, children }) {
|
|
77
|
+
const defaultHeight = config?.defaultHeight ?? DEFAULTS.defaultHeight;
|
|
78
|
+
const minHeight = config?.minHeight ?? DEFAULTS.minHeight;
|
|
79
|
+
const maxHeight = config?.maxHeight ?? DEFAULTS.maxHeight;
|
|
80
|
+
const shortcutKey = config?.shortcutKey === null ? null : config?.shortcutKey ?? DEFAULTS.shortcutKey;
|
|
81
|
+
const storageKey = config?.storageKey;
|
|
82
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
83
|
+
const [activeTab, setActiveTabState] = useState(config?.defaultActiveTab ?? null);
|
|
84
|
+
const [height, setHeightState] = useState(defaultHeight);
|
|
85
|
+
useEffect(() => {
|
|
86
|
+
const stored = loadStored(storageKey);
|
|
87
|
+
if (stored.height != null)
|
|
88
|
+
setHeightState(stored.height);
|
|
89
|
+
if (stored.activeTab != null)
|
|
90
|
+
setActiveTabState(stored.activeTab);
|
|
91
|
+
}, [storageKey]);
|
|
92
|
+
useEffect(() => {
|
|
93
|
+
persist(storageKey, { height, activeTab });
|
|
94
|
+
}, [storageKey, height, activeTab]);
|
|
95
|
+
useEffect(() => {
|
|
96
|
+
if (!shortcutKey)
|
|
97
|
+
return;
|
|
98
|
+
const handler = (event) => {
|
|
99
|
+
if ((event.ctrlKey || event.metaKey) && event.shiftKey && event.key.toLowerCase() === shortcutKey) {
|
|
100
|
+
event.preventDefault();
|
|
101
|
+
setIsOpen((prev) => !prev);
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
window.addEventListener("keydown", handler);
|
|
105
|
+
return () => window.removeEventListener("keydown", handler);
|
|
106
|
+
}, [shortcutKey]);
|
|
107
|
+
const toggleDrawer = useCallback(() => setIsOpen((prev) => !prev), []);
|
|
108
|
+
const openDrawer = useCallback(() => setIsOpen(true), []);
|
|
109
|
+
const closeDrawer = useCallback(() => setIsOpen(false), []);
|
|
110
|
+
const setActiveTab = useCallback((tab) => setActiveTabState(tab), []);
|
|
111
|
+
const setHeight = useCallback((next) => setHeightState(Math.min(maxHeight, Math.max(minHeight, next))), [minHeight, maxHeight]);
|
|
112
|
+
const value = useMemo(() => ({
|
|
113
|
+
isOpen,
|
|
114
|
+
activeTab,
|
|
115
|
+
height,
|
|
116
|
+
minHeight,
|
|
117
|
+
maxHeight,
|
|
118
|
+
toggleDrawer,
|
|
119
|
+
openDrawer,
|
|
120
|
+
closeDrawer,
|
|
121
|
+
setActiveTab,
|
|
122
|
+
setHeight
|
|
123
|
+
}), [
|
|
124
|
+
isOpen,
|
|
125
|
+
activeTab,
|
|
126
|
+
height,
|
|
127
|
+
minHeight,
|
|
128
|
+
maxHeight,
|
|
129
|
+
toggleDrawer,
|
|
130
|
+
openDrawer,
|
|
131
|
+
closeDrawer,
|
|
132
|
+
setActiveTab,
|
|
133
|
+
setHeight
|
|
134
|
+
]);
|
|
135
|
+
return /* @__PURE__ */ jsx(DevDrawerContext.Provider, {
|
|
136
|
+
value,
|
|
137
|
+
children
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
function useDevDrawer() {
|
|
141
|
+
const ctx = useContext(DevDrawerContext);
|
|
142
|
+
if (!ctx)
|
|
143
|
+
throw new Error("useDevDrawer must be used within a DevDrawerProvider");
|
|
144
|
+
return ctx;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// ../dev-tools/drawer/dev-drawer.tsx
|
|
148
|
+
import { Wrench, X } from "lucide-react";
|
|
149
|
+
import { jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
150
|
+
"use client";
|
|
151
|
+
function DevDrawer({
|
|
152
|
+
tabs,
|
|
153
|
+
children,
|
|
154
|
+
title = "Dev Toolbar",
|
|
155
|
+
badgeLabel = "DEV",
|
|
156
|
+
headerIcon: HeaderIcon = Wrench,
|
|
157
|
+
className
|
|
158
|
+
}) {
|
|
159
|
+
const { isOpen, activeTab, setActiveTab, closeDrawer, height, minHeight, maxHeight, setHeight } = useDevDrawer();
|
|
160
|
+
if (!isOpen)
|
|
161
|
+
return null;
|
|
162
|
+
const resolvedTabs = tabs && tabs.length > 0 ? tabs : null;
|
|
163
|
+
const currentTab = resolvedTabs?.find((tab) => tab.id === activeTab) ?? resolvedTabs?.[0];
|
|
164
|
+
const handleResizeStart = (event) => {
|
|
165
|
+
event.preventDefault();
|
|
166
|
+
const startY = event.clientY;
|
|
167
|
+
const startHeight = height;
|
|
168
|
+
function onMove(moveEvent) {
|
|
169
|
+
const delta = startY - moveEvent.clientY;
|
|
170
|
+
const deltaPercent = delta / window.innerHeight * 100;
|
|
171
|
+
setHeight(startHeight + deltaPercent);
|
|
172
|
+
}
|
|
173
|
+
function onUp() {
|
|
174
|
+
document.removeEventListener("pointermove", onMove);
|
|
175
|
+
document.removeEventListener("pointerup", onUp);
|
|
176
|
+
}
|
|
177
|
+
document.addEventListener("pointermove", onMove);
|
|
178
|
+
document.addEventListener("pointerup", onUp);
|
|
179
|
+
};
|
|
180
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
181
|
+
className: cn("fixed inset-x-0 bottom-0 z-50 border-t border-border/50 bg-background/95 backdrop-blur-md", className),
|
|
182
|
+
style: { height: `${height}vh` },
|
|
183
|
+
children: [
|
|
184
|
+
/* @__PURE__ */ jsx2("div", {
|
|
185
|
+
role: "slider",
|
|
186
|
+
tabIndex: 0,
|
|
187
|
+
"aria-label": "Resize dev drawer",
|
|
188
|
+
"aria-orientation": "horizontal",
|
|
189
|
+
"aria-valuemin": Math.round(minHeight),
|
|
190
|
+
"aria-valuemax": Math.round(maxHeight),
|
|
191
|
+
"aria-valuenow": Math.round(height),
|
|
192
|
+
className: "absolute inset-x-0 -top-1 flex h-3 cursor-ns-resize items-center justify-center focus:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
193
|
+
onPointerDown: handleResizeStart,
|
|
194
|
+
onKeyDown: (event) => {
|
|
195
|
+
if (event.key === "ArrowUp") {
|
|
196
|
+
event.preventDefault();
|
|
197
|
+
setHeight(height + 2);
|
|
198
|
+
} else if (event.key === "ArrowDown") {
|
|
199
|
+
event.preventDefault();
|
|
200
|
+
setHeight(height - 2);
|
|
201
|
+
}
|
|
202
|
+
},
|
|
203
|
+
children: /* @__PURE__ */ jsx2("div", {
|
|
204
|
+
className: "h-1 w-8 bg-muted-foreground/30"
|
|
205
|
+
})
|
|
206
|
+
}),
|
|
207
|
+
/* @__PURE__ */ jsxs("div", {
|
|
208
|
+
className: "flex h-10 items-center justify-between border-b border-border/50 px-3",
|
|
209
|
+
children: [
|
|
210
|
+
/* @__PURE__ */ jsxs("div", {
|
|
211
|
+
className: "flex items-center gap-2",
|
|
212
|
+
children: [
|
|
213
|
+
/* @__PURE__ */ jsx2(HeaderIcon, {
|
|
214
|
+
className: "h-3.5 w-3.5 text-amber-500"
|
|
215
|
+
}),
|
|
216
|
+
/* @__PURE__ */ jsx2("span", {
|
|
217
|
+
className: "text-xs font-semibold",
|
|
218
|
+
children: title
|
|
219
|
+
}),
|
|
220
|
+
badgeLabel ? /* @__PURE__ */ jsx2(Badge, {
|
|
221
|
+
variant: "outline",
|
|
222
|
+
className: "h-4 border-amber-500/30 px-1 text-[9px] text-amber-500",
|
|
223
|
+
children: badgeLabel
|
|
224
|
+
}) : null
|
|
225
|
+
]
|
|
226
|
+
}),
|
|
227
|
+
/* @__PURE__ */ jsxs("div", {
|
|
228
|
+
className: "flex items-center gap-1",
|
|
229
|
+
children: [
|
|
230
|
+
resolvedTabs?.map((tab) => {
|
|
231
|
+
const Icon = tab.icon;
|
|
232
|
+
const isActive = tab.id === (currentTab?.id ?? null);
|
|
233
|
+
return /* @__PURE__ */ jsxs(Button, {
|
|
234
|
+
variant: isActive ? "secondary" : "ghost",
|
|
235
|
+
size: "sm",
|
|
236
|
+
className: "h-6 gap-1 px-2 text-[10px]",
|
|
237
|
+
onClick: () => setActiveTab(tab.id),
|
|
238
|
+
children: [
|
|
239
|
+
Icon ? /* @__PURE__ */ jsx2(Icon, {
|
|
240
|
+
className: "h-3 w-3"
|
|
241
|
+
}) : null,
|
|
242
|
+
tab.label
|
|
243
|
+
]
|
|
244
|
+
}, tab.id);
|
|
245
|
+
}),
|
|
246
|
+
resolvedTabs ? /* @__PURE__ */ jsx2("div", {
|
|
247
|
+
className: "mx-1 h-4 w-px bg-border"
|
|
248
|
+
}) : null,
|
|
249
|
+
/* @__PURE__ */ jsx2(Button, {
|
|
250
|
+
variant: "ghost",
|
|
251
|
+
size: "icon",
|
|
252
|
+
className: "h-6 w-6",
|
|
253
|
+
onClick: closeDrawer,
|
|
254
|
+
children: /* @__PURE__ */ jsx2(X, {
|
|
255
|
+
className: "h-3 w-3"
|
|
256
|
+
})
|
|
257
|
+
})
|
|
258
|
+
]
|
|
259
|
+
})
|
|
260
|
+
]
|
|
261
|
+
}),
|
|
262
|
+
/* @__PURE__ */ jsx2("div", {
|
|
263
|
+
className: "h-[calc(100%-2.5rem)] overflow-y-auto px-3 py-3",
|
|
264
|
+
children: resolvedTabs ? currentTab?.content : children
|
|
265
|
+
})
|
|
266
|
+
]
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
// ../ui/components/tooltip.tsx
|
|
270
|
+
import * as TooltipPrimitive from "@radix-ui/react-tooltip";
|
|
271
|
+
import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
272
|
+
"use client";
|
|
273
|
+
|
|
274
|
+
// ../dev-tools/fab/dev-floating-menu.tsx
|
|
275
|
+
import { MoreHorizontal } from "lucide-react";
|
|
276
|
+
import { AnimatePresence, motion } from "motion/react";
|
|
277
|
+
|
|
278
|
+
// ../ui/components/kbd.tsx
|
|
279
|
+
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
280
|
+
|
|
281
|
+
// ../dev-tools/fab/fab-action.tsx
|
|
282
|
+
import Link from "next/link";
|
|
283
|
+
import { useCallback as useCallback2, useRef } from "react";
|
|
284
|
+
import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
285
|
+
"use client";
|
|
286
|
+
var baseClass = cn("size-9 rounded-full", "bg-background/80 backdrop-blur-sm border border-border/50", "shadow-sm hover:shadow-md transition-all duration-200");
|
|
287
|
+
var bauhausBaseClass = cn("size-9 rounded-full border backdrop-blur-2xl transition-all duration-200", "border-[rgb(var(--bauhaus-border-strong))] bg-bauhaus-bg/60 text-bauhaus-fg/55", "shadow-[0_6px_24px_rgba(0,0,0,0.45)]", "hover:bg-bauhaus-bg/80 hover:text-[var(--fab-ink)] hover:border-[var(--fab-ink)]");
|
|
288
|
+
|
|
289
|
+
// ../dev-tools/fab/use-fab-state.ts
|
|
290
|
+
import { useCallback as useCallback3, useEffect as useEffect2, useState as useState2 } from "react";
|
|
291
|
+
"use client";
|
|
292
|
+
|
|
293
|
+
// ../dev-tools/fab/dev-floating-menu.tsx
|
|
294
|
+
import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
295
|
+
"use client";
|
|
296
|
+
// ../dev-tools/fab/dock-context.tsx
|
|
297
|
+
import {
|
|
298
|
+
createContext as createContext2,
|
|
299
|
+
useCallback as useCallback4,
|
|
300
|
+
useContext as useContext2,
|
|
301
|
+
useEffect as useEffect3,
|
|
302
|
+
useMemo as useMemo2,
|
|
303
|
+
useState as useState3
|
|
304
|
+
} from "react";
|
|
305
|
+
import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
306
|
+
"use client";
|
|
307
|
+
var FloatingDockContext = createContext2(null);
|
|
308
|
+
// ../dev-tools/gate/dev-only.tsx
|
|
309
|
+
import { jsx as jsx8, Fragment } from "react/jsx-runtime";
|
|
310
|
+
"use client";
|
|
311
|
+
// ../dev-tools/panels/variants-link-panel.tsx
|
|
312
|
+
import { ArrowUpRight, Beaker } from "lucide-react";
|
|
313
|
+
import Link2 from "next/link";
|
|
314
|
+
import { jsx as jsx9, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
315
|
+
"use client";
|
|
316
|
+
export { getGrabberState, subscribeGrabber, startGrab, cancelGrab, completeGrab, clearGrabbedPayload, DevDrawerProvider, useDevDrawer, DevDrawer };
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import {
|
|
2
|
+
InfoRow,
|
|
3
|
+
LoadingSpinner,
|
|
4
|
+
PanelSection
|
|
5
|
+
} from "./chunk-kyeb6qeq.js";
|
|
6
|
+
|
|
7
|
+
// panels/debug-info-panel.tsx
|
|
8
|
+
import { Info, Monitor } from "lucide-react";
|
|
9
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
10
|
+
"use client";
|
|
11
|
+
function DebugInfoPanel({ user, isLoading = false }) {
|
|
12
|
+
if (isLoading)
|
|
13
|
+
return /* @__PURE__ */ jsx(LoadingSpinner, {});
|
|
14
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
15
|
+
className: "space-y-4",
|
|
16
|
+
children: [
|
|
17
|
+
user && /* @__PURE__ */ jsxs(PanelSection, {
|
|
18
|
+
icon: Info,
|
|
19
|
+
title: "User",
|
|
20
|
+
children: [
|
|
21
|
+
/* @__PURE__ */ jsx(InfoRow, {
|
|
22
|
+
label: "Name",
|
|
23
|
+
value: user.name ?? "—"
|
|
24
|
+
}),
|
|
25
|
+
/* @__PURE__ */ jsx(InfoRow, {
|
|
26
|
+
label: "Email",
|
|
27
|
+
value: user.email ?? "—",
|
|
28
|
+
copyable: !!user.email
|
|
29
|
+
}),
|
|
30
|
+
/* @__PURE__ */ jsx(InfoRow, {
|
|
31
|
+
label: "ID",
|
|
32
|
+
value: user.id ?? "—",
|
|
33
|
+
copyable: !!user.id
|
|
34
|
+
}),
|
|
35
|
+
/* @__PURE__ */ jsx(InfoRow, {
|
|
36
|
+
label: "Role",
|
|
37
|
+
value: user.role ?? "—"
|
|
38
|
+
}),
|
|
39
|
+
Object.entries(user.extra ?? {}).map(([label, value]) => /* @__PURE__ */ jsx(InfoRow, {
|
|
40
|
+
label,
|
|
41
|
+
value
|
|
42
|
+
}, label))
|
|
43
|
+
]
|
|
44
|
+
}),
|
|
45
|
+
/* @__PURE__ */ jsxs(PanelSection, {
|
|
46
|
+
icon: Monitor,
|
|
47
|
+
title: "Environment",
|
|
48
|
+
children: [
|
|
49
|
+
/* @__PURE__ */ jsx(InfoRow, {
|
|
50
|
+
label: "NODE_ENV",
|
|
51
|
+
value: "production"
|
|
52
|
+
}),
|
|
53
|
+
/* @__PURE__ */ jsx(InfoRow, {
|
|
54
|
+
label: "Convex URL",
|
|
55
|
+
value: process.env.NEXT_PUBLIC_CONVEX_URL ?? "not set",
|
|
56
|
+
copyable: true
|
|
57
|
+
}),
|
|
58
|
+
/* @__PURE__ */ jsx(InfoRow, {
|
|
59
|
+
label: "Origin",
|
|
60
|
+
value: typeof window !== "undefined" ? window.location.origin : "—"
|
|
61
|
+
})
|
|
62
|
+
]
|
|
63
|
+
})
|
|
64
|
+
]
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export { DebugInfoPanel };
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import {
|
|
2
|
+
HUD_CAPABILITIES
|
|
3
|
+
} from "./chunk-v086j53b.js";
|
|
4
|
+
|
|
5
|
+
// core/capabilities.ts
|
|
6
|
+
var CAPABILITY_MATRIX = {
|
|
7
|
+
development: HUD_CAPABILITIES,
|
|
8
|
+
staging: [
|
|
9
|
+
"observe.app",
|
|
10
|
+
"observe.estate",
|
|
11
|
+
"cicd.read",
|
|
12
|
+
"mock.toggle",
|
|
13
|
+
"auth.impersonate",
|
|
14
|
+
"variants.switch",
|
|
15
|
+
"variants.vote"
|
|
16
|
+
],
|
|
17
|
+
preview: [
|
|
18
|
+
"observe.app",
|
|
19
|
+
"observe.estate",
|
|
20
|
+
"cicd.read",
|
|
21
|
+
"mock.toggle",
|
|
22
|
+
"variants.switch",
|
|
23
|
+
"variants.vote"
|
|
24
|
+
],
|
|
25
|
+
production: ["observe.app", "observe.estate", "cicd.read"],
|
|
26
|
+
disabled: []
|
|
27
|
+
};
|
|
28
|
+
function resolveHudEnv() {
|
|
29
|
+
if (process.env.NEXT_PUBLIC_HUD_DISABLED === "true")
|
|
30
|
+
return "disabled";
|
|
31
|
+
if (false)
|
|
32
|
+
;
|
|
33
|
+
const explicit = process.env.NEXT_PUBLIC_HUD_ENV;
|
|
34
|
+
if (explicit === "staging" || explicit === "preview" || explicit === "production") {
|
|
35
|
+
return explicit;
|
|
36
|
+
}
|
|
37
|
+
if (process.env.VERCEL_ENV === "preview")
|
|
38
|
+
return "preview";
|
|
39
|
+
return "production";
|
|
40
|
+
}
|
|
41
|
+
function isHudVisible(env = resolveHudEnv()) {
|
|
42
|
+
if (env === "disabled")
|
|
43
|
+
return false;
|
|
44
|
+
if (env === "development")
|
|
45
|
+
return true;
|
|
46
|
+
return process.env.NEXT_PUBLIC_HUD_ENABLED === "true";
|
|
47
|
+
}
|
|
48
|
+
function hasCapability(env, capability) {
|
|
49
|
+
return CAPABILITY_MATRIX[env].includes(capability);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export { CAPABILITY_MATRIX, resolveHudEnv, isHudVisible, hasCapability };
|