@hansenexus/hud 0.1.1 → 0.3.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/README.md +106 -25
- package/dist/define-hud-BHQR8Lbv.d.ts +31 -0
- package/dist/index.d.ts +36 -0
- package/dist/index.js +1198 -0
- package/dist/next.d.ts +48 -0
- package/dist/next.js +77 -0
- package/dist/plugins/vitals.d.ts +25 -0
- package/dist/plugins/vitals.js +109 -0
- package/dist/plugins-1QmTmZyL.d.ts +76 -0
- package/dist/plugins-CzUiTn_r.js +68 -0
- package/dist/server.d.ts +39 -0
- package/dist/server.js +106 -0
- package/package.json +55 -133
- package/chunk-20zke7cs.js +0 -574
- package/chunk-24vrg16w.js +0 -39
- package/chunk-50pq4sg6.js +0 -41
- package/chunk-5gtx3pza.js +0 -9
- package/chunk-6cdpasm9.js +0 -79
- package/chunk-6jt8yg4m.js +0 -117
- package/chunk-6ngkpwz7.js +0 -127
- package/chunk-71se605m.js +0 -85
- package/chunk-82nm9wcg.js +0 -316
- package/chunk-9hw5r9y1.js +0 -67
- package/chunk-c5y856ad.js +0 -98
- package/chunk-edq4jqch.js +0 -89
- package/chunk-emfnvz4p.js +0 -166
- package/chunk-h0hmjdqa.js +0 -264
- package/chunk-hc2g0n35.js +0 -24
- package/chunk-hex3wqag.js +0 -179
- package/chunk-kvxve0hx.js +0 -140
- package/chunk-kyeb6qeq.js +0 -95
- package/chunk-mz55rvw3.js +0 -172
- package/chunk-nm82wr8r.js +0 -58
- package/chunk-q15xwpy8.js +0 -48
- package/chunk-q96mkjve.js +0 -68
- package/chunk-tczzx083.js +0 -26
- package/chunk-tf774c4w.js +0 -115
- package/chunk-v086j53b.js +0 -19
- package/chunk-vjh0d29g.js +0 -52
- package/chunk-xezxydm3.js +0 -47
- package/chunk-xztw0xyt.js +0 -113
- package/chunk-yn1d38pb.js +0 -172
- package/core/access.d.mts +0 -53
- package/core/access.js +0 -27
- package/core/api-types.d.mts +0 -146
- package/core/api-types.js +0 -9
- package/core/capabilities.d.mts +0 -27
- package/core/capabilities.js +0 -14
- package/core/capture-buffer.d.mts +0 -37
- package/core/capture-buffer.js +0 -9
- package/core/force-state.d.mts +0 -68
- package/core/force-state.js +0 -21
- package/core/mock-cookie.d.mts +0 -30
- package/core/mock-cookie.js +0 -15
- package/core/types.d.mts +0 -59
- package/core/types.js +0 -9
- package/hud-provider.d.mts +0 -38
- package/hud-provider.js +0 -15
- package/hud.d.mts +0 -15
- package/hud.js +0 -18
- package/index.d.mts +0 -94
- package/index.js +0 -170
- package/lazy-panel.d.mts +0 -28
- package/lazy-panel.js +0 -11
- package/panels/cicd-panel.d.mts +0 -9
- package/panels/cicd-panel.js +0 -13
- package/panels/debug-info-panel.d.mts +0 -21
- package/panels/debug-info-panel.js +0 -9
- package/panels/dispatch-panel.d.mts +0 -10
- package/panels/dispatch-panel.js +0 -14
- package/panels/env-info-panel.d.mts +0 -9
- package/panels/env-info-panel.js +0 -12
- package/panels/feature-flags-panel.d.mts +0 -26
- package/panels/feature-flags-panel.js +0 -9
- package/panels/force-state-panel.d.mts +0 -11
- package/panels/force-state-panel.js +0 -113
- package/panels/info-row.d.mts +0 -21
- package/panels/info-row.js +0 -14
- package/panels/mock-seed-panel.d.mts +0 -15
- package/panels/mock-seed-panel.js +0 -14
- package/panels/network-console-panel.d.mts +0 -6
- package/panels/network-console-panel.js +0 -9
- package/panels/role-switcher-panel.d.mts +0 -28
- package/panels/role-switcher-panel.js +0 -9
- package/panels/sessions-panel.d.mts +0 -6
- package/panels/sessions-panel.js +0 -13
- package/panels/tokens-panel.d.mts +0 -38
- package/panels/tokens-panel.js +0 -9
- package/panels/unlock-panel.d.mts +0 -33
- package/panels/unlock-panel.js +0 -14
- package/panels/variants-panel.d.mts +0 -51
- package/panels/variants-panel.js +0 -12
- package/panels/vitals-panel.d.mts +0 -11
- package/panels/vitals-panel.js +0 -15
- package/server/guard.d.mts +0 -42
- package/server/guard.js +0 -12
- package/server/unlock.d.mts +0 -28
- package/server/unlock.js +0 -108
- package/state-boundary.d.mts +0 -25
- package/state-boundary.js +0 -54
package/chunk-tf774c4w.js
DELETED
|
@@ -1,115 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
captureBuffer
|
|
3
|
-
} from "./chunk-24vrg16w.js";
|
|
4
|
-
import {
|
|
5
|
-
Button
|
|
6
|
-
} from "./chunk-xztw0xyt.js";
|
|
7
|
-
|
|
8
|
-
// panels/network-console-panel.tsx
|
|
9
|
-
import { Trash2 } from "lucide-react";
|
|
10
|
-
import { useState, useSyncExternalStore } from "react";
|
|
11
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
12
|
-
"use client";
|
|
13
|
-
var FILTERS = ["all", "log", "warn", "error", "fetch", "longtask"];
|
|
14
|
-
var KIND_CLASS = {
|
|
15
|
-
log: "text-muted-foreground",
|
|
16
|
-
warn: "text-amber-500",
|
|
17
|
-
error: "text-red-500",
|
|
18
|
-
fetch: "text-sky-500",
|
|
19
|
-
longtask: "text-violet-500"
|
|
20
|
-
};
|
|
21
|
-
function statusClass(status) {
|
|
22
|
-
if (status === undefined)
|
|
23
|
-
return "";
|
|
24
|
-
if (status === 0 || status >= 500)
|
|
25
|
-
return "text-red-500";
|
|
26
|
-
if (status >= 400)
|
|
27
|
-
return "text-amber-500";
|
|
28
|
-
return "text-emerald-500";
|
|
29
|
-
}
|
|
30
|
-
function NetworkConsolePanel() {
|
|
31
|
-
const entries = useSyncExternalStore(captureBuffer.subscribe, captureBuffer.getSnapshot, captureBuffer.getSnapshot);
|
|
32
|
-
const [filter, setFilter] = useState("all");
|
|
33
|
-
const visible = filter === "all" ? entries : entries.filter((e) => e.kind === filter);
|
|
34
|
-
return /* @__PURE__ */ jsxs("div", {
|
|
35
|
-
className: "flex h-full flex-col gap-2",
|
|
36
|
-
children: [
|
|
37
|
-
/* @__PURE__ */ jsxs("div", {
|
|
38
|
-
className: "flex items-center gap-1",
|
|
39
|
-
children: [
|
|
40
|
-
FILTERS.map((f) => /* @__PURE__ */ jsxs(Button, {
|
|
41
|
-
variant: filter === f ? "secondary" : "ghost",
|
|
42
|
-
size: "sm",
|
|
43
|
-
className: "h-6 px-2 font-mono text-[10px]",
|
|
44
|
-
onClick: () => setFilter(f),
|
|
45
|
-
children: [
|
|
46
|
-
f,
|
|
47
|
-
f !== "all" && /* @__PURE__ */ jsx("span", {
|
|
48
|
-
className: "ml-1 text-muted-foreground/60",
|
|
49
|
-
children: entries.filter((e) => e.kind === f).length
|
|
50
|
-
})
|
|
51
|
-
]
|
|
52
|
-
}, f)),
|
|
53
|
-
/* @__PURE__ */ jsxs(Button, {
|
|
54
|
-
variant: "ghost",
|
|
55
|
-
size: "sm",
|
|
56
|
-
className: "ml-auto h-6 px-2 text-[10px]",
|
|
57
|
-
onClick: () => captureBuffer.clear(),
|
|
58
|
-
children: [
|
|
59
|
-
/* @__PURE__ */ jsx(Trash2, {
|
|
60
|
-
className: "mr-1 h-3 w-3"
|
|
61
|
-
}),
|
|
62
|
-
"clear"
|
|
63
|
-
]
|
|
64
|
-
})
|
|
65
|
-
]
|
|
66
|
-
}),
|
|
67
|
-
/* @__PURE__ */ jsxs("div", {
|
|
68
|
-
className: "min-h-0 flex-1 overflow-auto rounded-md border bg-muted/10 p-2",
|
|
69
|
-
children: [
|
|
70
|
-
visible.length === 0 && /* @__PURE__ */ jsx("p", {
|
|
71
|
-
className: "px-1 text-[10px] text-muted-foreground/60",
|
|
72
|
-
children: "Nothing captured yet — console, fetch, and long tasks land here."
|
|
73
|
-
}),
|
|
74
|
-
visible.slice(-200).map((entry) => /* @__PURE__ */ jsx(EntryRow, {
|
|
75
|
-
entry
|
|
76
|
-
}, entry.id))
|
|
77
|
-
]
|
|
78
|
-
})
|
|
79
|
-
]
|
|
80
|
-
});
|
|
81
|
-
}
|
|
82
|
-
function EntryRow({ entry }) {
|
|
83
|
-
const time = new Date(entry.ts).toLocaleTimeString(undefined, { hour12: false });
|
|
84
|
-
return /* @__PURE__ */ jsxs("div", {
|
|
85
|
-
className: "flex items-baseline gap-2 px-1 py-0.5 font-mono text-[10.5px] hover:bg-muted/40",
|
|
86
|
-
children: [
|
|
87
|
-
/* @__PURE__ */ jsx("span", {
|
|
88
|
-
className: "shrink-0 text-muted-foreground/50",
|
|
89
|
-
children: time
|
|
90
|
-
}),
|
|
91
|
-
/* @__PURE__ */ jsx("span", {
|
|
92
|
-
className: `w-14 shrink-0 uppercase ${KIND_CLASS[entry.kind]}`,
|
|
93
|
-
children: entry.kind
|
|
94
|
-
}),
|
|
95
|
-
/* @__PURE__ */ jsx("span", {
|
|
96
|
-
className: "min-w-0 flex-1 truncate",
|
|
97
|
-
title: entry.text,
|
|
98
|
-
children: entry.text
|
|
99
|
-
}),
|
|
100
|
-
entry.status !== undefined && /* @__PURE__ */ jsx("span", {
|
|
101
|
-
className: `shrink-0 ${statusClass(entry.status)}`,
|
|
102
|
-
children: entry.status || "ERR"
|
|
103
|
-
}),
|
|
104
|
-
entry.durationMs !== undefined && /* @__PURE__ */ jsxs("span", {
|
|
105
|
-
className: "shrink-0 text-muted-foreground/60",
|
|
106
|
-
children: [
|
|
107
|
-
entry.durationMs,
|
|
108
|
-
" ms"
|
|
109
|
-
]
|
|
110
|
-
})
|
|
111
|
-
]
|
|
112
|
-
});
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
export { NetworkConsolePanel };
|
package/chunk-v086j53b.js
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
// core/types.ts
|
|
2
|
-
var HUD_BUNDLE_MARKER = "__HN_HUD_BUNDLE_MARKER__";
|
|
3
|
-
var HUD_CAPABILITIES = [
|
|
4
|
-
"observe.app",
|
|
5
|
-
"observe.estate",
|
|
6
|
-
"cicd.read",
|
|
7
|
-
"cicd.trigger",
|
|
8
|
-
"inject.seed",
|
|
9
|
-
"mock.toggle",
|
|
10
|
-
"auth.impersonate",
|
|
11
|
-
"dispatch.local",
|
|
12
|
-
"dispatch.hermes",
|
|
13
|
-
"variants.switch",
|
|
14
|
-
"variants.vote",
|
|
15
|
-
"variants.generate",
|
|
16
|
-
"state.force"
|
|
17
|
-
];
|
|
18
|
-
|
|
19
|
-
export { HUD_BUNDLE_MARKER, HUD_CAPABILITIES };
|
package/chunk-vjh0d29g.js
DELETED
|
@@ -1,52 +0,0 @@
|
|
|
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 (process.env.NODE_ENV === "development")
|
|
32
|
-
return "development";
|
|
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 };
|
package/chunk-xezxydm3.js
DELETED
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
// panels/use-poll.ts
|
|
2
|
-
import { useEffect, useState } from "react";
|
|
3
|
-
"use client";
|
|
4
|
-
function usePoll(url, intervalMs = 60000) {
|
|
5
|
-
const [state, setState] = useState({ loading: url !== null });
|
|
6
|
-
useEffect(() => {
|
|
7
|
-
if (!url)
|
|
8
|
-
return;
|
|
9
|
-
let cancelled = false;
|
|
10
|
-
async function tick() {
|
|
11
|
-
if (document.hidden)
|
|
12
|
-
return;
|
|
13
|
-
try {
|
|
14
|
-
const res = await fetch(url, { headers: { Accept: "application/json" } });
|
|
15
|
-
if (cancelled)
|
|
16
|
-
return;
|
|
17
|
-
if (res.redirected || res.status === 401 || res.status === 403) {
|
|
18
|
-
setState({ loading: false, error: "auth required" });
|
|
19
|
-
return;
|
|
20
|
-
}
|
|
21
|
-
if (!res.ok) {
|
|
22
|
-
setState({ loading: false, error: `HTTP ${res.status}` });
|
|
23
|
-
return;
|
|
24
|
-
}
|
|
25
|
-
const data = await res.json();
|
|
26
|
-
if (!cancelled)
|
|
27
|
-
setState({ loading: false, data });
|
|
28
|
-
} catch (error) {
|
|
29
|
-
if (!cancelled) {
|
|
30
|
-
setState({
|
|
31
|
-
loading: false,
|
|
32
|
-
error: error instanceof Error ? error.message : "request failed"
|
|
33
|
-
});
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
tick();
|
|
38
|
-
const timer = setInterval(() => void tick(), intervalMs);
|
|
39
|
-
return () => {
|
|
40
|
-
cancelled = true;
|
|
41
|
-
clearInterval(timer);
|
|
42
|
-
};
|
|
43
|
-
}, [url, intervalMs]);
|
|
44
|
-
return state;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
export { usePoll };
|
package/chunk-xztw0xyt.js
DELETED
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
// ../ui/lib/utils.ts
|
|
2
|
-
import { clsx } from "clsx";
|
|
3
|
-
import { twMerge } from "tailwind-merge";
|
|
4
|
-
function cn(...inputs) {
|
|
5
|
-
return twMerge(clsx(inputs));
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
// ../ui/components/badge.tsx
|
|
9
|
-
import { Slot } from "@radix-ui/react-slot";
|
|
10
|
-
import { cva } from "class-variance-authority";
|
|
11
|
-
import { jsx } from "react/jsx-runtime";
|
|
12
|
-
var badgeVariants = cva("inline-flex items-center justify-center rounded-full border border-transparent px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-[color,box-shadow] overflow-hidden", {
|
|
13
|
-
variants: {
|
|
14
|
-
variant: {
|
|
15
|
-
default: "bg-primary text-primary-foreground [a&]:hover:bg-primary/90",
|
|
16
|
-
secondary: "bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90",
|
|
17
|
-
destructive: "bg-destructive text-white [a&]:hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
|
|
18
|
-
outline: "border-border text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground",
|
|
19
|
-
ghost: "[a&]:hover:bg-accent [a&]:hover:text-accent-foreground",
|
|
20
|
-
link: "text-primary underline-offset-4 [a&]:hover:underline",
|
|
21
|
-
success: "bg-emerald-500/15 text-emerald-700 border-emerald-500/20 dark:text-emerald-300 dark:bg-emerald-400/15 dark:border-emerald-400/25 [a&]:hover:bg-emerald-500/25",
|
|
22
|
-
warning: "bg-amber-500/15 text-amber-700 border-amber-500/20 dark:text-amber-300 dark:bg-amber-400/15 dark:border-amber-400/25 [a&]:hover:bg-amber-500/25",
|
|
23
|
-
info: "bg-blue-500/15 text-blue-700 border-blue-500/20 dark:text-blue-300 dark:bg-blue-400/15 dark:border-blue-400/25 [a&]:hover:bg-blue-500/25",
|
|
24
|
-
muted: "bg-muted text-muted-foreground border-transparent [a&]:hover:bg-muted/80"
|
|
25
|
-
}
|
|
26
|
-
},
|
|
27
|
-
defaultVariants: {
|
|
28
|
-
variant: "default"
|
|
29
|
-
}
|
|
30
|
-
});
|
|
31
|
-
function Badge({
|
|
32
|
-
className,
|
|
33
|
-
variant = "default",
|
|
34
|
-
asChild = false,
|
|
35
|
-
...props
|
|
36
|
-
}) {
|
|
37
|
-
const Comp = asChild ? Slot : "span";
|
|
38
|
-
return /* @__PURE__ */ jsx(Comp, {
|
|
39
|
-
"data-slot": "badge",
|
|
40
|
-
"data-variant": variant,
|
|
41
|
-
className: cn(badgeVariants({ variant }), className),
|
|
42
|
-
...props
|
|
43
|
-
});
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
// ../ui/components/button.tsx
|
|
47
|
-
import { Slot as Slot2 } from "@radix-ui/react-slot";
|
|
48
|
-
import { cva as cva2 } from "class-variance-authority";
|
|
49
|
-
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
50
|
-
var buttonVariants = cva2("inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive", {
|
|
51
|
-
variants: {
|
|
52
|
-
variant: {
|
|
53
|
-
default: "bg-primary text-primary-foreground hover:bg-primary/90",
|
|
54
|
-
destructive: "bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
|
|
55
|
-
outline: "border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50",
|
|
56
|
-
secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
|
57
|
-
ghost: "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
|
|
58
|
-
link: "text-primary underline-offset-4 hover:underline"
|
|
59
|
-
},
|
|
60
|
-
size: {
|
|
61
|
-
default: "h-9 px-4 py-2 has-[>svg]:px-3",
|
|
62
|
-
xs: "h-6 gap-1 rounded-md px-2 text-xs has-[>svg]:px-1.5 [&_svg:not([class*='size-'])]:size-3",
|
|
63
|
-
sm: "h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5",
|
|
64
|
-
lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
|
|
65
|
-
icon: "size-9",
|
|
66
|
-
"icon-xs": "size-6 rounded-md [&_svg:not([class*='size-'])]:size-3",
|
|
67
|
-
"icon-sm": "size-8",
|
|
68
|
-
"icon-lg": "size-10"
|
|
69
|
-
}
|
|
70
|
-
},
|
|
71
|
-
defaultVariants: {
|
|
72
|
-
variant: "default",
|
|
73
|
-
size: "default"
|
|
74
|
-
}
|
|
75
|
-
});
|
|
76
|
-
function Button({
|
|
77
|
-
className,
|
|
78
|
-
variant = "default",
|
|
79
|
-
size = "default",
|
|
80
|
-
asChild = false,
|
|
81
|
-
...props
|
|
82
|
-
}) {
|
|
83
|
-
const Comp = asChild ? Slot2 : "button";
|
|
84
|
-
return /* @__PURE__ */ jsx2(Comp, {
|
|
85
|
-
"data-slot": "button",
|
|
86
|
-
"data-variant": variant,
|
|
87
|
-
"data-size": size,
|
|
88
|
-
className: cn(buttonVariants({ variant, size, className })),
|
|
89
|
-
...props
|
|
90
|
-
});
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
// ../ui/components/switch.tsx
|
|
94
|
-
import * as SwitchPrimitive from "@radix-ui/react-switch";
|
|
95
|
-
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
96
|
-
"use client";
|
|
97
|
-
function Switch({
|
|
98
|
-
className,
|
|
99
|
-
size = "default",
|
|
100
|
-
...props
|
|
101
|
-
}) {
|
|
102
|
-
return /* @__PURE__ */ jsx3(SwitchPrimitive.Root, {
|
|
103
|
-
"data-slot": "switch",
|
|
104
|
-
"data-size": size,
|
|
105
|
-
className: cn("peer data-[state=checked]:bg-primary data-[state=unchecked]:bg-input focus-visible:border-ring focus-visible:ring-ring/50 dark:data-[state=unchecked]:bg-input/80 group/switch inline-flex shrink-0 items-center rounded-full border border-transparent shadow-xs transition-all outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 data-[size=default]:h-[1.15rem] data-[size=default]:w-8 data-[size=sm]:h-3.5 data-[size=sm]:w-6", className),
|
|
106
|
-
...props,
|
|
107
|
-
children: /* @__PURE__ */ jsx3(SwitchPrimitive.Thumb, {
|
|
108
|
-
"data-slot": "switch-thumb",
|
|
109
|
-
className: cn("bg-background dark:data-[state=unchecked]:bg-foreground dark:data-[state=checked]:bg-primary-foreground pointer-events-none block rounded-full ring-0 transition-transform group-data-[size=default]/switch:size-4 group-data-[size=sm]/switch:size-3 data-[state=checked]:translate-x-[calc(100%-2px)] data-[state=unchecked]:translate-x-0")
|
|
110
|
-
})
|
|
111
|
-
});
|
|
112
|
-
}
|
|
113
|
-
export { cn, Badge, Button, Switch };
|
package/chunk-yn1d38pb.js
DELETED
|
@@ -1,172 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
usePoll
|
|
3
|
-
} from "./chunk-xezxydm3.js";
|
|
4
|
-
import {
|
|
5
|
-
useHud
|
|
6
|
-
} from "./chunk-9hw5r9y1.js";
|
|
7
|
-
import {
|
|
8
|
-
LoadingSpinner,
|
|
9
|
-
PanelSection
|
|
10
|
-
} from "./chunk-kyeb6qeq.js";
|
|
11
|
-
import {
|
|
12
|
-
Badge
|
|
13
|
-
} from "./chunk-xztw0xyt.js";
|
|
14
|
-
import {
|
|
15
|
-
__require
|
|
16
|
-
} from "./chunk-5gtx3pza.js";
|
|
17
|
-
|
|
18
|
-
// panels/vitals-panel.tsx
|
|
19
|
-
import { Activity, ServerCrash } from "lucide-react";
|
|
20
|
-
import { useEffect, useSyncExternalStore } from "react";
|
|
21
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
22
|
-
"use client";
|
|
23
|
-
var VITAL_ORDER = ["LCP", "INP", "CLS", "TTFB", "FCP"];
|
|
24
|
-
var vitals = new Map;
|
|
25
|
-
var vitalsSnapshot = new Map;
|
|
26
|
-
var vitalListeners = new Set;
|
|
27
|
-
var vitalsStarted = false;
|
|
28
|
-
function recordVital(name, value, rating) {
|
|
29
|
-
vitals.set(name, { value, rating });
|
|
30
|
-
vitalsSnapshot = new Map(vitals);
|
|
31
|
-
for (const listener of vitalListeners)
|
|
32
|
-
listener();
|
|
33
|
-
}
|
|
34
|
-
function startVitals() {
|
|
35
|
-
if (vitalsStarted || typeof window === "undefined")
|
|
36
|
-
return;
|
|
37
|
-
vitalsStarted = true;
|
|
38
|
-
import("web-vitals").then(({ onCLS, onFCP, onLCP, onTTFB, onINP }) => {
|
|
39
|
-
const report = (metric) => recordVital(metric.name, metric.value, metric.rating);
|
|
40
|
-
onCLS(report, { reportAllChanges: true });
|
|
41
|
-
onINP(report, { reportAllChanges: true });
|
|
42
|
-
onLCP(report);
|
|
43
|
-
onFCP(report);
|
|
44
|
-
onTTFB(report);
|
|
45
|
-
});
|
|
46
|
-
}
|
|
47
|
-
function subscribeVitals(listener) {
|
|
48
|
-
vitalListeners.add(listener);
|
|
49
|
-
return () => vitalListeners.delete(listener);
|
|
50
|
-
}
|
|
51
|
-
function getVitalsSnapshot() {
|
|
52
|
-
const out = {};
|
|
53
|
-
for (const [name, sample] of vitals)
|
|
54
|
-
out[name] = Number(sample.value.toFixed(2));
|
|
55
|
-
return out;
|
|
56
|
-
}
|
|
57
|
-
function formatVital(name, value) {
|
|
58
|
-
if (name === "CLS")
|
|
59
|
-
return value.toFixed(3);
|
|
60
|
-
if (value >= 1000)
|
|
61
|
-
return `${(value / 1000).toFixed(2)} s`;
|
|
62
|
-
return `${Math.round(value)} ms`;
|
|
63
|
-
}
|
|
64
|
-
var RATING_CLASS = {
|
|
65
|
-
good: "text-emerald-500",
|
|
66
|
-
"needs-improvement": "text-amber-500",
|
|
67
|
-
poor: "text-red-500"
|
|
68
|
-
};
|
|
69
|
-
function VitalsPanel() {
|
|
70
|
-
const { config } = useHud();
|
|
71
|
-
const samples = useSyncExternalStore(subscribeVitals, () => vitalsSnapshot, () => vitalsSnapshot);
|
|
72
|
-
useEffect(() => {
|
|
73
|
-
startVitals();
|
|
74
|
-
}, []);
|
|
75
|
-
const apiBase = config.apiBase ?? "/api/hud";
|
|
76
|
-
const signoz = usePoll(`${apiBase}/signoz?service=${encodeURIComponent(config.appSlug)}`, 60000);
|
|
77
|
-
return /* @__PURE__ */ jsxs("div", {
|
|
78
|
-
className: "space-y-4",
|
|
79
|
-
children: [
|
|
80
|
-
/* @__PURE__ */ jsxs(PanelSection, {
|
|
81
|
-
icon: Activity,
|
|
82
|
-
title: "Web Vitals · this page load",
|
|
83
|
-
children: [
|
|
84
|
-
/* @__PURE__ */ jsx("div", {
|
|
85
|
-
className: "flex flex-wrap gap-2 px-2",
|
|
86
|
-
children: VITAL_ORDER.map((name) => {
|
|
87
|
-
const sample = samples.get(name);
|
|
88
|
-
return /* @__PURE__ */ jsxs("div", {
|
|
89
|
-
className: "min-w-[92px] rounded-md border bg-muted/20 px-3 py-2",
|
|
90
|
-
children: [
|
|
91
|
-
/* @__PURE__ */ jsx("div", {
|
|
92
|
-
className: "text-[10px] uppercase tracking-wider text-muted-foreground",
|
|
93
|
-
children: name
|
|
94
|
-
}),
|
|
95
|
-
/* @__PURE__ */ jsx("div", {
|
|
96
|
-
className: `font-mono text-sm font-semibold ${sample ? RATING_CLASS[sample.rating] : "text-muted-foreground/50"}`,
|
|
97
|
-
children: sample ? formatVital(name, sample.value) : "—"
|
|
98
|
-
})
|
|
99
|
-
]
|
|
100
|
-
}, name);
|
|
101
|
-
})
|
|
102
|
-
}),
|
|
103
|
-
/* @__PURE__ */ jsx("p", {
|
|
104
|
-
className: "px-2 text-[10px] text-muted-foreground/60",
|
|
105
|
-
children: "CLS/INP update live; LCP/FCP/TTFB are per page load. History lands in SigNoz via /api/otel/vitals."
|
|
106
|
-
})
|
|
107
|
-
]
|
|
108
|
-
}),
|
|
109
|
-
/* @__PURE__ */ jsxs(PanelSection, {
|
|
110
|
-
icon: ServerCrash,
|
|
111
|
-
title: `Server · ${config.appSlug} (1h)`,
|
|
112
|
-
children: [
|
|
113
|
-
signoz.loading && /* @__PURE__ */ jsx(LoadingSpinner, {}),
|
|
114
|
-
signoz.error && /* @__PURE__ */ jsxs("p", {
|
|
115
|
-
className: "px-2 text-[10px] text-amber-500",
|
|
116
|
-
children: [
|
|
117
|
-
"hub unreachable — ",
|
|
118
|
-
signoz.error
|
|
119
|
-
]
|
|
120
|
-
}),
|
|
121
|
-
signoz.data && /* @__PURE__ */ jsxs("div", {
|
|
122
|
-
className: "space-y-1 px-2",
|
|
123
|
-
children: [
|
|
124
|
-
/* @__PURE__ */ jsxs("div", {
|
|
125
|
-
className: "flex items-center gap-2",
|
|
126
|
-
children: [
|
|
127
|
-
/* @__PURE__ */ jsx(ServerStat, {
|
|
128
|
-
label: "error rate",
|
|
129
|
-
value: signoz.data.errorRate,
|
|
130
|
-
unit: "/s"
|
|
131
|
-
}),
|
|
132
|
-
/* @__PURE__ */ jsx(ServerStat, {
|
|
133
|
-
label: "p95",
|
|
134
|
-
value: signoz.data.p95Latency,
|
|
135
|
-
unit: " ms"
|
|
136
|
-
}),
|
|
137
|
-
/* @__PURE__ */ jsx(ServerStat, {
|
|
138
|
-
label: "req rate",
|
|
139
|
-
value: signoz.data.requestCount,
|
|
140
|
-
unit: "/s"
|
|
141
|
-
})
|
|
142
|
-
]
|
|
143
|
-
}),
|
|
144
|
-
signoz.data.source === "mock" && /* @__PURE__ */ jsx(Badge, {
|
|
145
|
-
variant: "outline",
|
|
146
|
-
className: "h-4 px-1.5 text-[9px] text-muted-foreground",
|
|
147
|
-
children: "mock data — SIGNOZ_QUERY_URL unset"
|
|
148
|
-
})
|
|
149
|
-
]
|
|
150
|
-
})
|
|
151
|
-
]
|
|
152
|
-
})
|
|
153
|
-
]
|
|
154
|
-
});
|
|
155
|
-
}
|
|
156
|
-
function ServerStat({ label, value, unit }) {
|
|
157
|
-
return /* @__PURE__ */ jsxs("div", {
|
|
158
|
-
className: "min-w-[92px] rounded-md border bg-muted/20 px-3 py-2",
|
|
159
|
-
children: [
|
|
160
|
-
/* @__PURE__ */ jsx("div", {
|
|
161
|
-
className: "text-[10px] uppercase tracking-wider text-muted-foreground",
|
|
162
|
-
children: label
|
|
163
|
-
}),
|
|
164
|
-
/* @__PURE__ */ jsx("div", {
|
|
165
|
-
className: "font-mono text-sm font-semibold",
|
|
166
|
-
children: value === null ? "—" : `${value.toFixed(value < 10 ? 2 : 0)}${unit}`
|
|
167
|
-
})
|
|
168
|
-
]
|
|
169
|
-
});
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
export { getVitalsSnapshot, VitalsPanel };
|
package/core/access.d.mts
DELETED
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
import { HudEnv } from './types.mjs';
|
|
2
|
-
import 'lucide-react';
|
|
3
|
-
import 'react';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Access ladder for the hud: the second lock on top of the env matrix.
|
|
7
|
-
*
|
|
8
|
-
* `isHudVisible()` decides whether the hud exists at all (the flag). This
|
|
9
|
-
* module decides whether the operator opening it has proved who they are:
|
|
10
|
-
* outside development every deployed tier additionally needs an unlock
|
|
11
|
-
* cookie signed with `HUD_ACCESS_PASSWORD` (server-only, 1Password).
|
|
12
|
-
*
|
|
13
|
-
* Levels mirror `resolveDevRoutesAccess()` in @hn-monorepo/dev-routes so the
|
|
14
|
-
* vocabulary is the same across both dev surfaces:
|
|
15
|
-
*
|
|
16
|
-
* - `open`: development, no password.
|
|
17
|
-
* - `password`: preview/staging, flag + password, 12 h unlock.
|
|
18
|
-
* - `flag`: production, flag + password, 2 h unlock, observe-only caps.
|
|
19
|
-
* - `denied`: explicitly disabled; nothing unlocks it.
|
|
20
|
-
*
|
|
21
|
-
* The token is an HMAC over its own issue time, so it carries no secret and
|
|
22
|
-
* cannot be extended by the holder; re-issuing needs the password again.
|
|
23
|
-
*/
|
|
24
|
-
|
|
25
|
-
type HudAccess = "open" | "password" | "flag" | "denied";
|
|
26
|
-
/** httpOnly cookie holding the signed unlock token. */
|
|
27
|
-
declare const HUD_UNLOCK_COOKIE = "hud-unlock";
|
|
28
|
-
/** Unlock lifetime per tier. Production is deliberately the shortest window. */
|
|
29
|
-
declare const HUD_UNLOCK_TTL_MS: Record<HudAccess, number>;
|
|
30
|
-
declare function resolveHudAccess(env?: HudEnv): HudAccess;
|
|
31
|
-
/** Whether this tier needs a valid unlock cookie before any hud data flows. */
|
|
32
|
-
declare function hudRequiresUnlock(access: HudAccess): boolean;
|
|
33
|
-
/** TTL for the tier the current env resolves to. */
|
|
34
|
-
declare function hudUnlockTtlMs(access: HudAccess): number;
|
|
35
|
-
/** Length-independent, constant-time comparison of two hex digests. */
|
|
36
|
-
declare function timingSafeEqual(a: string, b: string): boolean;
|
|
37
|
-
/**
|
|
38
|
-
* Mint an unlock token. Format `<issuedAt>.<hmac>`; the issue time is in the
|
|
39
|
-
* clear on purpose so expiry is verifiable without server state, and it is
|
|
40
|
-
* covered by the signature so it cannot be back-dated.
|
|
41
|
-
*/
|
|
42
|
-
declare function signHudUnlockToken(password: string, issuedAt?: number): Promise<string>;
|
|
43
|
-
interface HudUnlockVerifyOptions {
|
|
44
|
-
now?: number;
|
|
45
|
-
ttlMs?: number;
|
|
46
|
-
}
|
|
47
|
-
declare function verifyHudUnlockToken(token: string | undefined, password: string | undefined, options?: HudUnlockVerifyOptions): Promise<boolean>;
|
|
48
|
-
/** Parse a single cookie out of a raw `Cookie:` header. */
|
|
49
|
-
declare function readCookie(header: string | null | undefined, name: string): string | undefined;
|
|
50
|
-
/** Serialized `Set-Cookie` value for the unlock token (or its removal). */
|
|
51
|
-
declare function hudUnlockCookieString(token: string | null, ttlMs: number): string;
|
|
52
|
-
|
|
53
|
-
export { HUD_UNLOCK_COOKIE, HUD_UNLOCK_TTL_MS, type HudAccess, type HudUnlockVerifyOptions, hudRequiresUnlock, hudUnlockCookieString, hudUnlockTtlMs, readCookie, resolveHudAccess, signHudUnlockToken, timingSafeEqual, verifyHudUnlockToken };
|
package/core/access.js
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
HUD_UNLOCK_COOKIE,
|
|
3
|
-
HUD_UNLOCK_TTL_MS,
|
|
4
|
-
hudRequiresUnlock,
|
|
5
|
-
hudUnlockCookieString,
|
|
6
|
-
hudUnlockTtlMs,
|
|
7
|
-
readCookie,
|
|
8
|
-
resolveHudAccess,
|
|
9
|
-
signHudUnlockToken,
|
|
10
|
-
timingSafeEqual,
|
|
11
|
-
verifyHudUnlockToken
|
|
12
|
-
} from "../chunk-6cdpasm9.js";
|
|
13
|
-
import"../chunk-vjh0d29g.js";
|
|
14
|
-
import"../chunk-v086j53b.js";
|
|
15
|
-
import"../chunk-5gtx3pza.js";
|
|
16
|
-
export {
|
|
17
|
-
verifyHudUnlockToken,
|
|
18
|
-
timingSafeEqual,
|
|
19
|
-
signHudUnlockToken,
|
|
20
|
-
resolveHudAccess,
|
|
21
|
-
readCookie,
|
|
22
|
-
hudUnlockTtlMs,
|
|
23
|
-
hudUnlockCookieString,
|
|
24
|
-
hudRequiresUnlock,
|
|
25
|
-
HUD_UNLOCK_TTL_MS,
|
|
26
|
-
HUD_UNLOCK_COOKIE
|
|
27
|
-
};
|