@hansenexus/hud 0.1.0 → 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-0cj8dkk7.js +0 -127
  6. package/chunk-1atxwdhw.js +0 -48
  7. package/chunk-24vrg16w.js +0 -39
  8. package/chunk-3j9sm249.js +0 -26
  9. package/chunk-50pq4sg6.js +0 -41
  10. package/chunk-5gtx3pza.js +0 -9
  11. package/chunk-6gw4x08j.js +0 -264
  12. package/chunk-6jt8yg4m.js +0 -117
  13. package/chunk-71se605m.js +0 -85
  14. package/chunk-82nm9wcg.js +0 -316
  15. package/chunk-8tam7r3h.js +0 -68
  16. package/chunk-babjpqkb.js +0 -52
  17. package/chunk-c5y856ad.js +0 -98
  18. package/chunk-ghxh8926.js +0 -172
  19. package/chunk-hc2g0n35.js +0 -24
  20. package/chunk-k0vr8dsy.js +0 -179
  21. package/chunk-k50yfp5d.js +0 -166
  22. package/chunk-kyeb6qeq.js +0 -95
  23. package/chunk-msqkkqw7.js +0 -140
  24. package/chunk-nm82wr8r.js +0 -58
  25. package/chunk-r06bpmy6.js +0 -79
  26. package/chunk-t9eh4t0b.js +0 -89
  27. package/chunk-tf774c4w.js +0 -115
  28. package/chunk-v086j53b.js +0 -19
  29. package/chunk-wspz08q7.js +0 -67
  30. package/chunk-xezxydm3.js +0 -47
  31. package/chunk-xjn0896g.js +0 -574
  32. package/chunk-xztw0xyt.js +0 -113
  33. package/chunk-zzrpd92r.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/package.json CHANGED
@@ -1,153 +1,62 @@
1
1
  {
2
2
  "name": "@hansenexus/hud",
3
- "version": "0.1.0",
4
- "description": "Dev HUD for React apps: drawer, panels, capability-gated access.",
3
+ "version": "0.2.0",
4
+ "description": "Modular dev HUD for React apps: status pill, floating panels, element grabber, plugin API.",
5
5
  "license": "MIT",
6
+ "type": "module",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/hansenexus/hud.git"
10
+ },
11
+ "workspaces": [
12
+ ".",
13
+ "playground"
14
+ ],
6
15
  "files": [
7
- "**/*.js",
8
- "**/*.d.mts",
16
+ "dist",
9
17
  "README.md",
10
18
  "LICENSE"
11
19
  ],
12
- "type": "module",
13
- "sideEffects": false,
14
20
  "exports": {
15
21
  ".": {
16
- "types": "./index.d.mts",
17
- "import": "./index.js"
18
- },
19
- "./hud": {
20
- "types": "./hud.d.mts",
21
- "import": "./hud.js"
22
- },
23
- "./hud-provider": {
24
- "types": "./hud-provider.d.mts",
25
- "import": "./hud-provider.js"
26
- },
27
- "./lazy-panel": {
28
- "types": "./lazy-panel.d.mts",
29
- "import": "./lazy-panel.js"
30
- },
31
- "./state-boundary": {
32
- "types": "./state-boundary.d.mts",
33
- "import": "./state-boundary.js"
34
- },
35
- "./core/mock-cookie": {
36
- "types": "./core/mock-cookie.d.mts",
37
- "import": "./core/mock-cookie.js"
38
- },
39
- "./core/api-types": {
40
- "types": "./core/api-types.d.mts",
41
- "import": "./core/api-types.js"
42
- },
43
- "./core/capabilities": {
44
- "types": "./core/capabilities.d.mts",
45
- "import": "./core/capabilities.js"
46
- },
47
- "./core/capture-buffer": {
48
- "types": "./core/capture-buffer.d.mts",
49
- "import": "./core/capture-buffer.js"
50
- },
51
- "./core/types": {
52
- "types": "./core/types.d.mts",
53
- "import": "./core/types.js"
54
- },
55
- "./core/access": {
56
- "types": "./core/access.d.mts",
57
- "import": "./core/access.js"
58
- },
59
- "./core/force-state": {
60
- "types": "./core/force-state.d.mts",
61
- "import": "./core/force-state.js"
62
- },
63
- "./panels/tokens-panel": {
64
- "types": "./panels/tokens-panel.d.mts",
65
- "import": "./panels/tokens-panel.js"
66
- },
67
- "./panels/force-state-panel": {
68
- "types": "./panels/force-state-panel.d.mts",
69
- "import": "./panels/force-state-panel.js"
70
- },
71
- "./panels/role-switcher-panel": {
72
- "types": "./panels/role-switcher-panel.d.mts",
73
- "import": "./panels/role-switcher-panel.js"
74
- },
75
- "./panels/debug-info-panel": {
76
- "types": "./panels/debug-info-panel.d.mts",
77
- "import": "./panels/debug-info-panel.js"
78
- },
79
- "./panels/sessions-panel": {
80
- "types": "./panels/sessions-panel.d.mts",
81
- "import": "./panels/sessions-panel.js"
82
- },
83
- "./panels/network-console-panel": {
84
- "types": "./panels/network-console-panel.d.mts",
85
- "import": "./panels/network-console-panel.js"
86
- },
87
- "./panels/feature-flags-panel": {
88
- "types": "./panels/feature-flags-panel.d.mts",
89
- "import": "./panels/feature-flags-panel.js"
90
- },
91
- "./panels/mock-seed-panel": {
92
- "types": "./panels/mock-seed-panel.d.mts",
93
- "import": "./panels/mock-seed-panel.js"
94
- },
95
- "./panels/vitals-panel": {
96
- "types": "./panels/vitals-panel.d.mts",
97
- "import": "./panels/vitals-panel.js"
98
- },
99
- "./panels/info-row": {
100
- "types": "./panels/info-row.d.mts",
101
- "import": "./panels/info-row.js"
102
- },
103
- "./panels/cicd-panel": {
104
- "types": "./panels/cicd-panel.d.mts",
105
- "import": "./panels/cicd-panel.js"
106
- },
107
- "./panels/variants-panel": {
108
- "types": "./panels/variants-panel.d.mts",
109
- "import": "./panels/variants-panel.js"
110
- },
111
- "./panels/unlock-panel": {
112
- "types": "./panels/unlock-panel.d.mts",
113
- "import": "./panels/unlock-panel.js"
114
- },
115
- "./panels/env-info-panel": {
116
- "types": "./panels/env-info-panel.d.mts",
117
- "import": "./panels/env-info-panel.js"
118
- },
119
- "./panels/dispatch-panel": {
120
- "types": "./panels/dispatch-panel.d.mts",
121
- "import": "./panels/dispatch-panel.js"
122
- },
123
- "./server/guard": {
124
- "types": "./server/guard.d.mts",
125
- "import": "./server/guard.js"
126
- },
127
- "./server/unlock": {
128
- "types": "./server/unlock.d.mts",
129
- "import": "./server/unlock.js"
22
+ "types": "./dist/index.d.ts",
23
+ "import": "./dist/index.js"
130
24
  }
131
25
  },
26
+ "sideEffects": false,
27
+ "scripts": {
28
+ "dev": "bun run --cwd playground dev",
29
+ "build": "tsdown",
30
+ "typecheck": "tsc --noEmit",
31
+ "lint": "biome check .",
32
+ "format": "biome check --write .",
33
+ "test": "vitest run",
34
+ "test:watch": "vitest",
35
+ "check": "bun run lint && bun run typecheck && bun run test && bun run build && bun run check:pack",
36
+ "changeset": "changeset",
37
+ "version-packages": "changeset version",
38
+ "check:pack": "bun scripts/check-pack.ts"
39
+ },
132
40
  "dependencies": {
133
- "@radix-ui/react-slot": "^1.2.4",
134
- "@radix-ui/react-switch": "^1.2.6",
135
- "@radix-ui/react-tooltip": "^1.2.8",
136
- "class-variance-authority": "^0.7.1",
137
- "clsx": "^2.1.1",
138
- "lucide-react": "^0.563.0",
139
- "motion": "^12.29.2",
140
- "tailwind-merge": "^3.4.0",
141
- "web-vitals": "^5.2.0"
41
+ "web-vitals": "^6.2.3"
142
42
  },
143
43
  "peerDependencies": {
144
- "next": ">=15",
145
- "react": "^19.2.0",
146
- "react-dom": "^19.2.0"
44
+ "react": "^19.0.0",
45
+ "react-dom": "^19.0.0"
147
46
  },
148
- "peerDependenciesMeta": {
149
- "next": {
150
- "optional": true
151
- }
47
+ "devDependencies": {
48
+ "@biomejs/biome": "^2.5.15",
49
+ "@changesets/changelog-github": "^1.0.1",
50
+ "@changesets/cli": "^3.0.3",
51
+ "@testing-library/react": "^16.3.3",
52
+ "@types/react": "^19.3.0",
53
+ "@types/react-dom": "^19.3.0",
54
+ "jsdom": "^30.1.2",
55
+ "tsdown": "^0.23.0",
56
+ "typescript": "^7.0.2",
57
+ "vitest": "^5.0.3"
58
+ },
59
+ "publishConfig": {
60
+ "access": "public"
152
61
  }
153
62
  }
package/chunk-0cj8dkk7.js DELETED
@@ -1,127 +0,0 @@
1
- import {
2
- useHud
3
- } from "./chunk-wspz08q7.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-babjpqkb.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: "production"
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-1atxwdhw.js DELETED
@@ -1,48 +0,0 @@
1
- import {
2
- HUD_UNLOCK_COOKIE,
3
- hudRequiresUnlock,
4
- hudUnlockTtlMs,
5
- readCookie,
6
- resolveHudAccess,
7
- verifyHudUnlockToken
8
- } from "./chunk-r06bpmy6.js";
9
- import {
10
- hasCapability,
11
- isHudVisible,
12
- resolveHudEnv
13
- } from "./chunk-babjpqkb.js";
14
-
15
- // server/guard.ts
16
- async function checkHudRequest(request, capability) {
17
- const env = resolveHudEnv();
18
- if (!isHudVisible(env)) {
19
- return { ok: false, status: 404, error: "not found" };
20
- }
21
- if (!hasCapability(env, capability)) {
22
- return { ok: false, status: 403, error: `capability ${capability} is denied in ${env}` };
23
- }
24
- const access = resolveHudAccess(env);
25
- if (!hudRequiresUnlock(access)) {
26
- return { ok: true, env };
27
- }
28
- const password = process.env.HUD_ACCESS_PASSWORD;
29
- if (!password) {
30
- return { ok: false, status: 401, error: "hud unlock is not configured" };
31
- }
32
- const token = readCookie(request.headers.get("cookie"), HUD_UNLOCK_COOKIE);
33
- const unlocked = await verifyHudUnlockToken(token, password, { ttlMs: hudUnlockTtlMs(access) });
34
- if (!unlocked) {
35
- return { ok: false, status: 401, error: "hud is locked" };
36
- }
37
- return { ok: true, env };
38
- }
39
- async function isHudRequestUnlocked(request) {
40
- const access = resolveHudAccess();
41
- if (!hudRequiresUnlock(access))
42
- return true;
43
- const password = process.env.HUD_ACCESS_PASSWORD;
44
- const token = readCookie(request.headers.get("cookie"), HUD_UNLOCK_COOKIE);
45
- return verifyHudUnlockToken(token, password, { ttlMs: hudUnlockTtlMs(access) });
46
- }
47
-
48
- export { checkHudRequest, isHudRequestUnlocked };
package/chunk-24vrg16w.js DELETED
@@ -1,39 +0,0 @@
1
- // core/capture-buffer.ts
2
- class CaptureBuffer {
3
- entries = [];
4
- snapshot = [];
5
- listeners = new Set;
6
- nextId = 1;
7
- maxEntries;
8
- constructor(maxEntries = 500) {
9
- this.maxEntries = maxEntries;
10
- }
11
- push(input) {
12
- const entry = { id: this.nextId++, ts: Date.now(), ...input };
13
- this.entries.push(entry);
14
- if (this.entries.length > this.maxEntries) {
15
- this.entries.splice(0, this.entries.length - this.maxEntries);
16
- }
17
- this.emit();
18
- return entry;
19
- }
20
- clear() {
21
- if (this.entries.length === 0)
22
- return;
23
- this.entries = [];
24
- this.emit();
25
- }
26
- getSnapshot = () => this.snapshot;
27
- subscribe = (listener) => {
28
- this.listeners.add(listener);
29
- return () => this.listeners.delete(listener);
30
- };
31
- emit() {
32
- this.snapshot = [...this.entries];
33
- for (const listener of this.listeners)
34
- listener();
35
- }
36
- }
37
- var captureBuffer = new CaptureBuffer(500);
38
-
39
- export { CaptureBuffer, captureBuffer };
package/chunk-3j9sm249.js DELETED
@@ -1,26 +0,0 @@
1
- import {
2
- LoadingSpinner
3
- } from "./chunk-kyeb6qeq.js";
4
- import {
5
- hasCapability,
6
- resolveHudEnv
7
- } from "./chunk-babjpqkb.js";
8
-
9
- // lazy-panel.tsx
10
- import { lazy, Suspense } from "react";
11
- import { jsx } from "react/jsx-runtime";
12
- "use client";
13
- function hudLazyPanel(meta, load, env = resolveHudEnv()) {
14
- if (!hasCapability(env, meta.capability))
15
- return null;
16
- const Panel = lazy(async () => ({ default: await load() }));
17
- return {
18
- ...meta,
19
- content: /* @__PURE__ */ jsx(Suspense, {
20
- fallback: /* @__PURE__ */ jsx(LoadingSpinner, {}),
21
- children: /* @__PURE__ */ jsx(Panel, {})
22
- })
23
- };
24
- }
25
-
26
- export { hudLazyPanel };
package/chunk-50pq4sg6.js DELETED
@@ -1,41 +0,0 @@
1
- // bridge-client.ts
2
- var cached;
3
- async function getBridgeInfo(apiBase) {
4
- if (cached !== undefined)
5
- return cached;
6
- try {
7
- const res = await fetch(`${apiBase}/bridge-info`, {
8
- headers: { "x-hud-internal": "1" }
9
- });
10
- if (!res.ok) {
11
- cached = null;
12
- return null;
13
- }
14
- const info = await res.json();
15
- const health = await fetch(`http://127.0.0.1:${info.port}/health`, {
16
- headers: { "x-hud-internal": "1" },
17
- signal: AbortSignal.timeout(1500)
18
- }).catch(() => null);
19
- cached = health?.ok ? info : null;
20
- return cached;
21
- } catch {
22
- cached = null;
23
- return null;
24
- }
25
- }
26
- function resetBridgeInfo() {
27
- cached = undefined;
28
- }
29
- async function bridgeFetch(info, path, init) {
30
- return fetch(`http://127.0.0.1:${info.port}${path}`, {
31
- ...init,
32
- headers: {
33
- ...init?.headers,
34
- Authorization: `Bearer ${info.token}`,
35
- "x-hud-internal": "1",
36
- ...init?.body ? { "Content-Type": "application/json" } : {}
37
- }
38
- });
39
- }
40
-
41
- export { getBridgeInfo, resetBridgeInfo, bridgeFetch };
package/chunk-5gtx3pza.js DELETED
@@ -1,9 +0,0 @@
1
- var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
2
- get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
3
- }) : x)(function(x) {
4
- if (typeof require !== "undefined")
5
- return require.apply(this, arguments);
6
- throw Error('Dynamic require of "' + x + '" is not supported');
7
- });
8
-
9
- export { __require };