@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/README.md
CHANGED
|
@@ -1,47 +1,128 @@
|
|
|
1
1
|
# @hansenexus/hud
|
|
2
2
|
|
|
3
|
-
A dev HUD for React apps
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
A dev HUD for React apps: a status pill and floating panels, rendered in a shadow root so a
|
|
4
|
+
client site's CSS cannot touch it and it cannot touch the site.
|
|
5
|
+
|
|
6
|
+
> Early. The element grabber is tracked in
|
|
7
|
+
> [the PRD](https://github.com/hansenexus/hud/issues/1).
|
|
8
|
+
|
|
9
|
+
## Develop
|
|
10
|
+
|
|
11
|
+
```sh
|
|
12
|
+
bun install
|
|
13
|
+
bun run dev # playground on http://localhost:5173, HUD imported from source (HMR)
|
|
14
|
+
bun run check # lint, typecheck, test, build
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
The playground (`playground/`) is a fake client site with every element that has fought a dev
|
|
18
|
+
tool for a corner: sticky nav, a fixed booking CTA, a chat launcher and a cookie banner, plus a
|
|
19
|
+
deliberately hostile stylesheet. If the HUD changes when you edit `playground/src/site.css`, the
|
|
20
|
+
isolation leaks.
|
|
6
21
|
|
|
7
22
|
## Install
|
|
8
23
|
|
|
9
24
|
```sh
|
|
10
|
-
npm
|
|
25
|
+
bun add -d @hansenexus/hud # or npm i -D @hansenexus/hud
|
|
11
26
|
```
|
|
12
27
|
|
|
13
|
-
|
|
14
|
-
|
|
28
|
+
Peer dependencies: `react` and `react-dom` 19. Nothing else: no Tailwind, no stylesheet to import,
|
|
29
|
+
no host CSS assumptions. The HUD ships its own styles inside its shadow root.
|
|
15
30
|
|
|
16
|
-
## Use
|
|
31
|
+
## Use (Next.js)
|
|
17
32
|
|
|
18
|
-
|
|
19
|
-
import { Hud, type HudPanel, NetworkConsolePanel, VitalsPanel } from "@hansenexus/hud";
|
|
20
|
-
import { Activity, Terminal } from "lucide-react";
|
|
33
|
+
Three files. The HUD definition, client only:
|
|
21
34
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
35
|
+
```tsx
|
|
36
|
+
// src/components/dev/hud.tsx
|
|
37
|
+
import { defineHud } from "@hansenexus/hud";
|
|
38
|
+
import { vitals } from "@hansenexus/hud/plugins/vitals";
|
|
26
39
|
|
|
27
|
-
export
|
|
28
|
-
return <Hud config={{ appSlug: "my-app" }} panels={panels} />;
|
|
29
|
-
}
|
|
40
|
+
export default defineHud({ app: "my-app", plugins: [vitals()] });
|
|
30
41
|
```
|
|
31
42
|
|
|
32
|
-
|
|
43
|
+
The loader, with the build gate as a literal expression around the `import()`. Next inlines both
|
|
44
|
+
env reads, so a production build folds the ternary to `null` and emits no HUD chunk:
|
|
45
|
+
|
|
46
|
+
```tsx
|
|
47
|
+
// src/components/dev/hud-loader.tsx
|
|
48
|
+
"use client";
|
|
49
|
+
import { createHudLoader } from "@hansenexus/hud/next";
|
|
50
|
+
|
|
51
|
+
export const HudLoader = createHudLoader(
|
|
52
|
+
process.env.NODE_ENV === "development" || process.env.NEXT_PUBLIC_HUD_ENABLED === "true"
|
|
53
|
+
? () => import("./hud")
|
|
54
|
+
: null
|
|
55
|
+
);
|
|
56
|
+
```
|
|
33
57
|
|
|
34
|
-
|
|
58
|
+
Render `<HudLoader />` in the root layout. Plugin routes mount through one catch-all route, fed
|
|
59
|
+
the plugins' server halves:
|
|
35
60
|
|
|
36
|
-
|
|
37
|
-
|
|
61
|
+
```ts
|
|
62
|
+
// src/app/api/hud/[...hud]/route.ts
|
|
63
|
+
import { createHudHandler } from "@hansenexus/hud/server";
|
|
38
64
|
|
|
39
|
-
|
|
40
|
-
@source "../node_modules/@hansenexus/hud";
|
|
65
|
+
export const { GET, POST, PUT, PATCH, DELETE } = createHudHandler([/* plugins/<id>/server */]);
|
|
41
66
|
```
|
|
42
67
|
|
|
43
|
-
|
|
44
|
-
|
|
68
|
+
`createHudHandler` answers 404 to everything unless `NODE_ENV` is `development`; pass `guard` to
|
|
69
|
+
open deployed tiers deliberately. `HUD_DEV_MARKER` is rendered on the HUD root for a CI grep.
|
|
70
|
+
|
|
71
|
+
## Write a plugin
|
|
72
|
+
|
|
73
|
+
A plugin is `{ id, title?, capability?, panel?, pill?, commands?, routes? }`, shipped as two
|
|
74
|
+
halves with the same `id`: the client half (`panel`, `pill`, `commands`) and the server half
|
|
75
|
+
(`routes`), so route code never reaches a client bundle. The panel is a plain React component
|
|
76
|
+
receiving `ctx`:
|
|
77
|
+
|
|
78
|
+
| `ctx` | does |
|
|
79
|
+
| ------------- | --------------------------------------------------------------------- |
|
|
80
|
+
| `can(cap)` | capability check (core grants all; the `access` plugin narrows it) |
|
|
81
|
+
| `api(path)` | JSON fetch from the plugin's routes at `/api/hud/<id>/<path>` |
|
|
82
|
+
| `pin(edge)` | pin the panel to `left`, `right` or `bottom` |
|
|
83
|
+
| `close()` | close the panel |
|
|
84
|
+
|
|
85
|
+
Routes are keyed by path, then method: `routes: { "/runs/:id": { GET: (req, { params }) => ... } }`.
|
|
86
|
+
An unknown path answers 404, a known path with another method 405.
|
|
87
|
+
|
|
88
|
+
`playground/src/plugins/server-info` is a working example: the playground serves its routes
|
|
89
|
+
through MSW with the same `createHudHandler` an app mounts.
|
|
90
|
+
|
|
91
|
+
## Panels and shortcuts
|
|
92
|
+
|
|
93
|
+
- Open panels from the pill (`⋯` lists every panel and command). Drag by the title bar; a click
|
|
94
|
+
raises a panel.
|
|
95
|
+
- Pin a panel with ◧ ⬓ ◨ or by dropping it at the left, right or bottom edge. Pinning pushes the
|
|
96
|
+
page (padding on `<html>`) instead of covering it; pins on one edge stack. The host's
|
|
97
|
+
`position: fixed` elements and media queries still see the full window.
|
|
98
|
+
- The layout (open panels, positions, pins) is kept per `appSlug` in `localStorage`.
|
|
99
|
+
`⋯ → Reset layout` clears it.
|
|
100
|
+
- Below 768 px panels open as one full-width bottom sheet with a tab per panel; no pinning.
|
|
101
|
+
- `⌘⇧H` (Ctrl+Shift+H elsewhere) hides and restores the layout. `⌘⇧G` is reserved for the
|
|
102
|
+
element grabber.
|
|
103
|
+
|
|
104
|
+
A plugin's panel can pin itself with `ctx.pin("right")`. Plugin `commands` join the registry as
|
|
105
|
+
`<plugin id>.<command id>`, appear in the `⋯` menu and bind their `shortcut`.
|
|
106
|
+
|
|
107
|
+
## Release
|
|
108
|
+
|
|
109
|
+
Versions are driven by [Changesets](https://github.com/changesets/changesets). A PR that changes
|
|
110
|
+
what the package ships adds one with `bun run changeset` (pre-1.0: `minor` for breaking changes,
|
|
111
|
+
`patch` for the rest). On `main`, `.github/workflows/release.yml` gathers pending changesets into
|
|
112
|
+
a "chore: version packages" PR. Merging that PR publishes the new version to npm over Trusted
|
|
113
|
+
Publishing (GitHub OIDC, no `NPM_TOKEN`), tags `v<version>` and cuts a GitHub release from the
|
|
114
|
+
CHANGELOG section. `Actions > Release > Run workflow` with `dry_run` runs the gate and
|
|
115
|
+
`npm publish --dry-run` without publishing.
|
|
116
|
+
|
|
117
|
+
Versions up to 0.1.1 were published from hn-monorepo; 0.2.0 is the first release from this repo.
|
|
118
|
+
|
|
119
|
+
Provenance is off while the repo is private (npm refuses `--provenance` from a private source).
|
|
120
|
+
When the repo goes public, set `NPM_PROVENANCE: "true"` in `release.yml`.
|
|
121
|
+
|
|
122
|
+
**Owner step, once, needs npm 2FA:** npmjs.com → `@hansenexus/hud` → Settings → Trusted
|
|
123
|
+
Publisher → GitHub Actions: organization `hansenexus`, repository `hud`, workflow `release.yml`.
|
|
124
|
+
Do this before merging the first Version Packages PR. Keep the hn-monorepo publisher until
|
|
125
|
+
hn-monorepo#2740 retires its old release workflow.
|
|
45
126
|
|
|
46
127
|
## License
|
|
47
128
|
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { a as HudPlugin, n as HudCapability } from "./plugins-1QmTmZyL.js";
|
|
2
|
+
import { ComponentType } from "react";
|
|
3
|
+
//#region src/core/define-hud.d.ts
|
|
4
|
+
interface DefineHudOptions {
|
|
5
|
+
/** App slug: labels the pill and keys the persisted layout. */
|
|
6
|
+
app: string;
|
|
7
|
+
/** Client halves (`@hansenexus/hud/plugins/<id>`), in pill order. */
|
|
8
|
+
plugins: readonly HudPlugin[];
|
|
9
|
+
/** Base path of the catch-all route serving `createHudHandler`. Default "/api/hud". */
|
|
10
|
+
apiBase?: string;
|
|
11
|
+
/** Capability check. Default: grant all (core assumes development). */
|
|
12
|
+
can?: (capability: HudCapability) => boolean;
|
|
13
|
+
}
|
|
14
|
+
/** Props the loader passes in at mount time. */
|
|
15
|
+
interface HudMountProps {
|
|
16
|
+
/** Badge at the start of the pill. Default "DEV". */
|
|
17
|
+
envLabel?: string;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* The app's one HUD file:
|
|
21
|
+
*
|
|
22
|
+
* ```tsx
|
|
23
|
+
* export default defineHud({ app: "hansenexus", plugins: [vitals()] });
|
|
24
|
+
* ```
|
|
25
|
+
*
|
|
26
|
+
* Returns a component. The plugin list is frozen here, so the shell sees a
|
|
27
|
+
* stable array across renders.
|
|
28
|
+
*/
|
|
29
|
+
declare function defineHud({ app, plugins, apiBase, can }: DefineHudOptions): ComponentType<HudMountProps>;
|
|
30
|
+
//#endregion
|
|
31
|
+
export { HudMountProps as n, defineHud as r, DefineHudOptions as t };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { a as HudPlugin, d as PinEdge, f as definePlugin, n as HudCapability, o as HudPluginContext, r as HudCommand, s as HudPluginProps, t as HudApiError } from "./plugins-1QmTmZyL.js";
|
|
2
|
+
import { n as HudMountProps, r as defineHud, t as DefineHudOptions } from "./define-hud-BHQR8Lbv.js";
|
|
3
|
+
//#region src/core/marker.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Literal a consumer's CI bundle gate greps for in production client chunks.
|
|
6
|
+
* It is rendered as an attribute on the HUD root, so a bundler cannot drop it
|
|
7
|
+
* while keeping the HUD, and it is unmistakably deliberate rather than an
|
|
8
|
+
* incidental string a refactor could rename away.
|
|
9
|
+
*/
|
|
10
|
+
export declare const HUD_DEV_MARKER = "__HANSENEXUS_HUD_DEV__";
|
|
11
|
+
/** Tag name of the element that hosts the HUD's shadow root. */
|
|
12
|
+
export declare const HUD_HOST_TAG = "hn-hud";
|
|
13
|
+
//#endregion
|
|
14
|
+
//#region src/shell/hud.d.ts
|
|
15
|
+
interface HudProps {
|
|
16
|
+
/** App slug: labels the pill and keys the persisted layout. */
|
|
17
|
+
appSlug: string;
|
|
18
|
+
/** Badge shown at the start of the pill. Default "DEV". */
|
|
19
|
+
envLabel?: string;
|
|
20
|
+
/** Client halves of the plugins, in pill order. Keep the array stable across renders. */
|
|
21
|
+
plugins?: readonly HudPlugin[];
|
|
22
|
+
/** Base path of the plugin routes. Default "/api/hud". */
|
|
23
|
+
apiBase?: string;
|
|
24
|
+
/** Capability check. Default: grant all (core assumes development). Keep it stable. */
|
|
25
|
+
can?: (capability: HudCapability) => boolean;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* The HUD shell: a shadow-rooted status pill and floating panels.
|
|
29
|
+
*
|
|
30
|
+
* It renders unconditionally. Keeping it out of production builds is the
|
|
31
|
+
* loader's job, at the import site, so a bundler can drop the whole module
|
|
32
|
+
* (see `@hansenexus/hud/next`).
|
|
33
|
+
*/
|
|
34
|
+
export declare function Hud({ appSlug, envLabel, plugins, apiBase, can }: HudProps): import("react").JSX.Element;
|
|
35
|
+
//#endregion
|
|
36
|
+
export { type DefineHudOptions, HudApiError, type HudCapability, type HudCommand, type HudMountProps, type HudPlugin, type HudPluginContext, type HudPluginProps, type HudProps, type PinEdge, defineHud, definePlugin };
|