@hansenexus/hud 0.1.1 → 0.2.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.
Files changed (91) hide show
  1. package/README.md +42 -23
  2. package/dist/index.d.ts +39 -0
  3. package/dist/index.js +399 -0
  4. package/package.json +45 -136
  5. package/chunk-20zke7cs.js +0 -574
  6. package/chunk-24vrg16w.js +0 -39
  7. package/chunk-50pq4sg6.js +0 -41
  8. package/chunk-5gtx3pza.js +0 -9
  9. package/chunk-6cdpasm9.js +0 -79
  10. package/chunk-6jt8yg4m.js +0 -117
  11. package/chunk-6ngkpwz7.js +0 -127
  12. package/chunk-71se605m.js +0 -85
  13. package/chunk-82nm9wcg.js +0 -316
  14. package/chunk-9hw5r9y1.js +0 -67
  15. package/chunk-c5y856ad.js +0 -98
  16. package/chunk-edq4jqch.js +0 -89
  17. package/chunk-emfnvz4p.js +0 -166
  18. package/chunk-h0hmjdqa.js +0 -264
  19. package/chunk-hc2g0n35.js +0 -24
  20. package/chunk-hex3wqag.js +0 -179
  21. package/chunk-kvxve0hx.js +0 -140
  22. package/chunk-kyeb6qeq.js +0 -95
  23. package/chunk-mz55rvw3.js +0 -172
  24. package/chunk-nm82wr8r.js +0 -58
  25. package/chunk-q15xwpy8.js +0 -48
  26. package/chunk-q96mkjve.js +0 -68
  27. package/chunk-tczzx083.js +0 -26
  28. package/chunk-tf774c4w.js +0 -115
  29. package/chunk-v086j53b.js +0 -19
  30. package/chunk-vjh0d29g.js +0 -52
  31. package/chunk-xezxydm3.js +0 -47
  32. package/chunk-xztw0xyt.js +0 -113
  33. package/chunk-yn1d38pb.js +0 -172
  34. package/core/access.d.mts +0 -53
  35. package/core/access.js +0 -27
  36. package/core/api-types.d.mts +0 -146
  37. package/core/api-types.js +0 -9
  38. package/core/capabilities.d.mts +0 -27
  39. package/core/capabilities.js +0 -14
  40. package/core/capture-buffer.d.mts +0 -37
  41. package/core/capture-buffer.js +0 -9
  42. package/core/force-state.d.mts +0 -68
  43. package/core/force-state.js +0 -21
  44. package/core/mock-cookie.d.mts +0 -30
  45. package/core/mock-cookie.js +0 -15
  46. package/core/types.d.mts +0 -59
  47. package/core/types.js +0 -9
  48. package/hud-provider.d.mts +0 -38
  49. package/hud-provider.js +0 -15
  50. package/hud.d.mts +0 -15
  51. package/hud.js +0 -18
  52. package/index.d.mts +0 -94
  53. package/index.js +0 -170
  54. package/lazy-panel.d.mts +0 -28
  55. package/lazy-panel.js +0 -11
  56. package/panels/cicd-panel.d.mts +0 -9
  57. package/panels/cicd-panel.js +0 -13
  58. package/panels/debug-info-panel.d.mts +0 -21
  59. package/panels/debug-info-panel.js +0 -9
  60. package/panels/dispatch-panel.d.mts +0 -10
  61. package/panels/dispatch-panel.js +0 -14
  62. package/panels/env-info-panel.d.mts +0 -9
  63. package/panels/env-info-panel.js +0 -12
  64. package/panels/feature-flags-panel.d.mts +0 -26
  65. package/panels/feature-flags-panel.js +0 -9
  66. package/panels/force-state-panel.d.mts +0 -11
  67. package/panels/force-state-panel.js +0 -113
  68. package/panels/info-row.d.mts +0 -21
  69. package/panels/info-row.js +0 -14
  70. package/panels/mock-seed-panel.d.mts +0 -15
  71. package/panels/mock-seed-panel.js +0 -14
  72. package/panels/network-console-panel.d.mts +0 -6
  73. package/panels/network-console-panel.js +0 -9
  74. package/panels/role-switcher-panel.d.mts +0 -28
  75. package/panels/role-switcher-panel.js +0 -9
  76. package/panels/sessions-panel.d.mts +0 -6
  77. package/panels/sessions-panel.js +0 -13
  78. package/panels/tokens-panel.d.mts +0 -38
  79. package/panels/tokens-panel.js +0 -9
  80. package/panels/unlock-panel.d.mts +0 -33
  81. package/panels/unlock-panel.js +0 -14
  82. package/panels/variants-panel.d.mts +0 -51
  83. package/panels/variants-panel.js +0 -12
  84. package/panels/vitals-panel.d.mts +0 -11
  85. package/panels/vitals-panel.js +0 -15
  86. package/server/guard.d.mts +0 -42
  87. package/server/guard.js +0 -12
  88. package/server/unlock.d.mts +0 -28
  89. package/server/unlock.js +0 -108
  90. package/state-boundary.d.mts +0 -25
  91. package/state-boundary.js +0 -54
package/chunk-6cdpasm9.js DELETED
@@ -1,79 +0,0 @@
1
- import {
2
- resolveHudEnv
3
- } from "./chunk-vjh0d29g.js";
4
-
5
- // core/access.ts
6
- var HUD_UNLOCK_COOKIE = "hud-unlock";
7
- var HUD_UNLOCK_TTL_MS = {
8
- open: 0,
9
- password: 12 * 60 * 60 * 1000,
10
- flag: 2 * 60 * 60 * 1000,
11
- denied: 0
12
- };
13
- function resolveHudAccess(env = resolveHudEnv()) {
14
- if (env === "disabled")
15
- return "denied";
16
- if (env === "development")
17
- return "open";
18
- if (env === "production")
19
- return "flag";
20
- return "password";
21
- }
22
- function hudRequiresUnlock(access) {
23
- return access === "password" || access === "flag";
24
- }
25
- function hudUnlockTtlMs(access) {
26
- return HUD_UNLOCK_TTL_MS[access];
27
- }
28
- var encoder = new TextEncoder;
29
- async function hmacHex(password, message) {
30
- const key = await crypto.subtle.importKey("raw", encoder.encode(password), { name: "HMAC", hash: "SHA-256" }, false, ["sign"]);
31
- const signature = await crypto.subtle.sign("HMAC", key, encoder.encode(message));
32
- return Array.from(new Uint8Array(signature)).map((byte) => byte.toString(16).padStart(2, "0")).join("");
33
- }
34
- function timingSafeEqual(a, b) {
35
- const length = Math.max(a.length, b.length);
36
- let diff = a.length ^ b.length;
37
- for (let i = 0;i < length; i++) {
38
- diff |= (a.charCodeAt(i) || 0) ^ (b.charCodeAt(i) || 0);
39
- }
40
- return diff === 0;
41
- }
42
- async function signHudUnlockToken(password, issuedAt = Date.now()) {
43
- return `${issuedAt}.${await hmacHex(password, String(issuedAt))}`;
44
- }
45
- async function verifyHudUnlockToken(token, password, options = {}) {
46
- if (!token || !password)
47
- return false;
48
- const separator = token.indexOf(".");
49
- if (separator <= 0)
50
- return false;
51
- const issuedAtRaw = token.slice(0, separator);
52
- const signature = token.slice(separator + 1);
53
- const issuedAt = Number(issuedAtRaw);
54
- if (!Number.isSafeInteger(issuedAt) || issuedAt <= 0)
55
- return false;
56
- const now = options.now ?? Date.now();
57
- const ttlMs = options.ttlMs ?? HUD_UNLOCK_TTL_MS.flag;
58
- const age = now - issuedAt;
59
- if (age < 0 || age > ttlMs)
60
- return false;
61
- return timingSafeEqual(signature, await hmacHex(password, issuedAtRaw));
62
- }
63
- function readCookie(header, name) {
64
- if (!header)
65
- return;
66
- for (const part of header.split(";")) {
67
- const trimmed = part.trim();
68
- if (trimmed.startsWith(`${name}=`)) {
69
- return decodeURIComponent(trimmed.slice(name.length + 1));
70
- }
71
- }
72
- return;
73
- }
74
- function hudUnlockCookieString(token, ttlMs) {
75
- const base = `${HUD_UNLOCK_COOKIE}=${token ?? ""}; Path=/; HttpOnly; SameSite=Strict; Secure`;
76
- return token ? `${base}; Max-Age=${Math.floor(ttlMs / 1000)}` : `${base}; Max-Age=0`;
77
- }
78
-
79
- export { HUD_UNLOCK_COOKIE, HUD_UNLOCK_TTL_MS, resolveHudAccess, hudRequiresUnlock, hudUnlockTtlMs, timingSafeEqual, signHudUnlockToken, verifyHudUnlockToken, readCookie, hudUnlockCookieString };
package/chunk-6jt8yg4m.js DELETED
@@ -1,117 +0,0 @@
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 };
package/chunk-6ngkpwz7.js DELETED
@@ -1,127 +0,0 @@
1
- import {
2
- useHud
3
- } from "./chunk-9hw5r9y1.js";
4
- import {
5
- InfoRow,
6
- PanelSection,
7
- ShortcutRow
8
- } from "./chunk-kyeb6qeq.js";
9
- import {
10
- Badge
11
- } from "./chunk-xztw0xyt.js";
12
- import {
13
- CAPABILITY_MATRIX
14
- } from "./chunk-vjh0d29g.js";
15
- import {
16
- HUD_CAPABILITIES
17
- } from "./chunk-v086j53b.js";
18
-
19
- // panels/env-info-panel.tsx
20
- import { Boxes, Info, Monitor, ShieldCheck } from "lucide-react";
21
- import { version as reactVersion } from "react";
22
- import { jsx, jsxs } from "react/jsx-runtime";
23
- "use client";
24
- function EnvInfoPanel() {
25
- const { config, env, can } = useHud();
26
- return /* @__PURE__ */ jsxs("div", {
27
- className: "space-y-4",
28
- children: [
29
- /* @__PURE__ */ jsxs(PanelSection, {
30
- icon: Boxes,
31
- title: "App",
32
- children: [
33
- /* @__PURE__ */ jsx(InfoRow, {
34
- label: "App",
35
- value: config.appSlug
36
- }),
37
- /* @__PURE__ */ jsxs("div", {
38
- className: "flex items-center justify-between px-2 py-1",
39
- children: [
40
- /* @__PURE__ */ jsx("span", {
41
- className: "text-[10px] text-muted-foreground",
42
- children: "hud env"
43
- }),
44
- /* @__PURE__ */ jsx(Badge, {
45
- variant: "outline",
46
- className: "h-4 px-1.5 font-mono text-[10px] uppercase",
47
- children: env
48
- })
49
- ]
50
- }),
51
- /* @__PURE__ */ jsx(InfoRow, {
52
- label: "Origin",
53
- value: typeof window !== "undefined" ? window.location.origin : "—",
54
- copyable: true
55
- })
56
- ]
57
- }),
58
- /* @__PURE__ */ jsxs(PanelSection, {
59
- icon: Monitor,
60
- title: "Build",
61
- children: [
62
- /* @__PURE__ */ jsx(InfoRow, {
63
- label: "NODE_ENV",
64
- value: process.env.NODE_ENV ?? "unknown"
65
- }),
66
- /* @__PURE__ */ jsx(InfoRow, {
67
- label: "React",
68
- value: reactVersion
69
- }),
70
- /* @__PURE__ */ jsx(InfoRow, {
71
- label: "Convex URL",
72
- value: process.env.NEXT_PUBLIC_CONVEX_URL ?? "not set",
73
- copyable: true
74
- }),
75
- /* @__PURE__ */ jsx(InfoRow, {
76
- label: "App URL",
77
- value: process.env.NEXT_PUBLIC_APP_URL ?? "not set"
78
- })
79
- ]
80
- }),
81
- /* @__PURE__ */ jsxs(PanelSection, {
82
- icon: ShieldCheck,
83
- title: `Capabilities · ${env}`,
84
- children: [
85
- /* @__PURE__ */ jsx("div", {
86
- className: "grid grid-cols-2 gap-x-4",
87
- children: HUD_CAPABILITIES.map((capability) => {
88
- const granted = can(capability);
89
- return /* @__PURE__ */ jsxs("div", {
90
- className: "flex items-center justify-between px-2 py-0.5",
91
- title: granted ? undefined : `denied in ${env} (see CAPABILITY_MATRIX in core/capabilities.ts)`,
92
- children: [
93
- /* @__PURE__ */ jsx("span", {
94
- className: `font-mono text-[10px] ${granted ? "" : "text-muted-foreground/50 line-through"}`,
95
- children: capability
96
- }),
97
- /* @__PURE__ */ jsx("span", {
98
- className: `h-1.5 w-1.5 rounded-full ${granted ? "bg-emerald-500" : "bg-muted-foreground/20"}`
99
- })
100
- ]
101
- }, capability);
102
- })
103
- }),
104
- /* @__PURE__ */ jsxs("p", {
105
- className: "px-2 text-[10px] text-muted-foreground/60",
106
- children: [
107
- CAPABILITY_MATRIX[env].length,
108
- "/",
109
- HUD_CAPABILITIES.length,
110
- " granted — default deny, server routes re-check independently."
111
- ]
112
- })
113
- ]
114
- }),
115
- /* @__PURE__ */ jsx(PanelSection, {
116
- icon: Info,
117
- title: "Shortcuts",
118
- children: /* @__PURE__ */ jsx(ShortcutRow, {
119
- keys: ["⌘", "⇧", "H"],
120
- label: "Toggle hud"
121
- })
122
- })
123
- ]
124
- });
125
- }
126
-
127
- export { EnvInfoPanel };
package/chunk-71se605m.js DELETED
@@ -1,85 +0,0 @@
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 };