@legioncodeinc/hive 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 +661 -0
- package/README.md +262 -0
- package/dist/cli-commands.d.ts +41 -0
- package/dist/cli-commands.js +76 -0
- package/dist/cli-commands.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +46 -0
- package/dist/cli.js.map +1 -0
- package/dist/daemon/dashboard/app.js +118 -0
- package/dist/daemon/dashboard/host.d.ts +90 -0
- package/dist/daemon/dashboard/host.js +172 -0
- package/dist/daemon/dashboard/host.js.map +1 -0
- package/dist/daemon/dashboard/web-assets.d.ts +88 -0
- package/dist/daemon/dashboard/web-assets.js +195 -0
- package/dist/daemon/dashboard/web-assets.js.map +1 -0
- package/dist/daemon/fleet-status.d.ts +15 -0
- package/dist/daemon/fleet-status.js +56 -0
- package/dist/daemon/fleet-status.js.map +1 -0
- package/dist/daemon/gate.d.ts +55 -0
- package/dist/daemon/gate.js +128 -0
- package/dist/daemon/gate.js.map +1 -0
- package/dist/daemon/proxy.d.ts +38 -0
- package/dist/daemon/proxy.js +126 -0
- package/dist/daemon/proxy.js.map +1 -0
- package/dist/daemon/registry.d.ts +31 -0
- package/dist/daemon/registry.js +120 -0
- package/dist/daemon/registry.js.map +1 -0
- package/dist/daemon/server.d.ts +41 -0
- package/dist/daemon/server.js +126 -0
- package/dist/daemon/server.js.map +1 -0
- package/dist/daemon/setup-auth.d.ts +37 -0
- package/dist/daemon/setup-auth.js +51 -0
- package/dist/daemon/setup-auth.js.map +1 -0
- package/dist/daemon/telemetry-proxy.d.ts +47 -0
- package/dist/daemon/telemetry-proxy.js +63 -0
- package/dist/daemon/telemetry-proxy.js.map +1 -0
- package/dist/dashboard/contracts.d.ts +235 -0
- package/dist/dashboard/contracts.js +43 -0
- package/dist/dashboard/contracts.js.map +1 -0
- package/dist/dashboard/web/app.d.ts +44 -0
- package/dist/dashboard/web/app.js +179 -0
- package/dist/dashboard/web/app.js.map +1 -0
- package/dist/dashboard/web/boot-route.d.ts +23 -0
- package/dist/dashboard/web/boot-route.js +29 -0
- package/dist/dashboard/web/boot-route.js.map +1 -0
- package/dist/dashboard/web/build-graph-button.d.ts +46 -0
- package/dist/dashboard/web/build-graph-button.js +81 -0
- package/dist/dashboard/web/build-graph-button.js.map +1 -0
- package/dist/dashboard/web/buzzing-screen.d.ts +30 -0
- package/dist/dashboard/web/buzzing-screen.js +135 -0
- package/dist/dashboard/web/buzzing-screen.js.map +1 -0
- package/dist/dashboard/web/folder-picker.d.ts +54 -0
- package/dist/dashboard/web/folder-picker.js +125 -0
- package/dist/dashboard/web/folder-picker.js.map +1 -0
- package/dist/dashboard/web/graph-layout.d.ts +101 -0
- package/dist/dashboard/web/graph-layout.js +0 -0
- package/dist/dashboard/web/graph-layout.js.map +1 -0
- package/dist/dashboard/web/harness-strip.d.ts +38 -0
- package/dist/dashboard/web/harness-strip.js +65 -0
- package/dist/dashboard/web/harness-strip.js.map +1 -0
- package/dist/dashboard/web/health-rail.d.ts +26 -0
- package/dist/dashboard/web/health-rail.js +61 -0
- package/dist/dashboard/web/health-rail.js.map +1 -0
- package/dist/dashboard/web/main.d.ts +22 -0
- package/dist/dashboard/web/main.js +51 -0
- package/dist/dashboard/web/main.js.map +1 -0
- package/dist/dashboard/web/needs-project.d.ts +51 -0
- package/dist/dashboard/web/needs-project.js +69 -0
- package/dist/dashboard/web/needs-project.js.map +1 -0
- package/dist/dashboard/web/page-frame.d.ts +95 -0
- package/dist/dashboard/web/page-frame.js +98 -0
- package/dist/dashboard/web/page-frame.js.map +1 -0
- package/dist/dashboard/web/pages/coming-soon.d.ts +23 -0
- package/dist/dashboard/web/pages/coming-soon.js +19 -0
- package/dist/dashboard/web/pages/coming-soon.js.map +1 -0
- package/dist/dashboard/web/pages/dashboard.d.ts +32 -0
- package/dist/dashboard/web/pages/dashboard.js +205 -0
- package/dist/dashboard/web/pages/dashboard.js.map +1 -0
- package/dist/dashboard/web/pages/graph.d.ts +72 -0
- package/dist/dashboard/web/pages/graph.js +362 -0
- package/dist/dashboard/web/pages/graph.js.map +1 -0
- package/dist/dashboard/web/pages/harnesses.d.ts +65 -0
- package/dist/dashboard/web/pages/harnesses.js +210 -0
- package/dist/dashboard/web/pages/harnesses.js.map +1 -0
- package/dist/dashboard/web/pages/health.d.ts +22 -0
- package/dist/dashboard/web/pages/health.js +91 -0
- package/dist/dashboard/web/pages/health.js.map +1 -0
- package/dist/dashboard/web/pages/lifecycle-panel.d.ts +60 -0
- package/dist/dashboard/web/pages/lifecycle-panel.js +187 -0
- package/dist/dashboard/web/pages/lifecycle-panel.js.map +1 -0
- package/dist/dashboard/web/pages/logs.d.ts +55 -0
- package/dist/dashboard/web/pages/logs.js +311 -0
- package/dist/dashboard/web/pages/logs.js.map +1 -0
- package/dist/dashboard/web/pages/memories.d.ts +35 -0
- package/dist/dashboard/web/pages/memories.js +439 -0
- package/dist/dashboard/web/pages/memories.js.map +1 -0
- package/dist/dashboard/web/pages/projects.d.ts +38 -0
- package/dist/dashboard/web/pages/projects.js +325 -0
- package/dist/dashboard/web/pages/projects.js.map +1 -0
- package/dist/dashboard/web/pages/roi-chart.d.ts +52 -0
- package/dist/dashboard/web/pages/roi-chart.js +133 -0
- package/dist/dashboard/web/pages/roi-chart.js.map +1 -0
- package/dist/dashboard/web/pages/roi.d.ts +93 -0
- package/dist/dashboard/web/pages/roi.js +375 -0
- package/dist/dashboard/web/pages/roi.js.map +1 -0
- package/dist/dashboard/web/pages/settings.d.ts +103 -0
- package/dist/dashboard/web/pages/settings.js +420 -0
- package/dist/dashboard/web/pages/settings.js.map +1 -0
- package/dist/dashboard/web/pages/sync.d.ts +59 -0
- package/dist/dashboard/web/pages/sync.js +280 -0
- package/dist/dashboard/web/pages/sync.js.map +1 -0
- package/dist/dashboard/web/panels.d.ts +178 -0
- package/dist/dashboard/web/panels.js +471 -0
- package/dist/dashboard/web/panels.js.map +1 -0
- package/dist/dashboard/web/primitives.d.ts +80 -0
- package/dist/dashboard/web/primitives.js +208 -0
- package/dist/dashboard/web/primitives.js.map +1 -0
- package/dist/dashboard/web/readiness-splash.d.ts +39 -0
- package/dist/dashboard/web/readiness-splash.js +201 -0
- package/dist/dashboard/web/readiness-splash.js.map +1 -0
- package/dist/dashboard/web/registry.d.ts +96 -0
- package/dist/dashboard/web/registry.js +99 -0
- package/dist/dashboard/web/registry.js.map +1 -0
- package/dist/dashboard/web/router.d.ts +48 -0
- package/dist/dashboard/web/router.js +76 -0
- package/dist/dashboard/web/router.js.map +1 -0
- package/dist/dashboard/web/scope-context.d.ts +155 -0
- package/dist/dashboard/web/scope-context.js +266 -0
- package/dist/dashboard/web/scope-context.js.map +1 -0
- package/dist/dashboard/web/service-icons.d.ts +33 -0
- package/dist/dashboard/web/service-icons.js +80 -0
- package/dist/dashboard/web/service-icons.js.map +1 -0
- package/dist/dashboard/web/setup-gate.d.ts +116 -0
- package/dist/dashboard/web/setup-gate.js +272 -0
- package/dist/dashboard/web/setup-gate.js.map +1 -0
- package/dist/dashboard/web/sidebar.d.ts +63 -0
- package/dist/dashboard/web/sidebar.js +91 -0
- package/dist/dashboard/web/sidebar.js.map +1 -0
- package/dist/dashboard/web/use-fleet-telemetry.d.ts +111 -0
- package/dist/dashboard/web/use-fleet-telemetry.js +278 -0
- package/dist/dashboard/web/use-fleet-telemetry.js.map +1 -0
- package/dist/dashboard/web/wire.d.ts +1937 -0
- package/dist/dashboard/web/wire.js +1837 -0
- package/dist/dashboard/web/wire.js.map +1 -0
- package/dist/errors.d.ts +5 -0
- package/dist/errors.js +11 -0
- package/dist/errors.js.map +1 -0
- package/dist/install/registry.d.ts +35 -0
- package/dist/install/registry.js +110 -0
- package/dist/install/registry.js.map +1 -0
- package/dist/lock.d.ts +10 -0
- package/dist/lock.js +87 -0
- package/dist/lock.js.map +1 -0
- package/dist/service/commands.d.ts +15 -0
- package/dist/service/commands.js +49 -0
- package/dist/service/commands.js.map +1 -0
- package/dist/service/index.d.ts +38 -0
- package/dist/service/index.js +174 -0
- package/dist/service/index.js.map +1 -0
- package/dist/service/platform.d.ts +37 -0
- package/dist/service/platform.js +67 -0
- package/dist/service/platform.js.map +1 -0
- package/dist/service/templates.d.ts +10 -0
- package/dist/service/templates.js +120 -0
- package/dist/service/templates.js.map +1 -0
- package/dist/shared/constants.d.ts +15 -0
- package/dist/shared/constants.js +19 -0
- package/dist/shared/constants.js.map +1 -0
- package/dist/shared/daemon-routing.d.ts +11 -0
- package/dist/shared/daemon-routing.js +38 -0
- package/dist/shared/daemon-routing.js.map +1 -0
- package/dist/shared/fleet-readiness.d.ts +18 -0
- package/dist/shared/fleet-readiness.js +9 -0
- package/dist/shared/fleet-readiness.js.map +1 -0
- package/dist/shared/fleet-telemetry.d.ts +68 -0
- package/dist/shared/fleet-telemetry.js +61 -0
- package/dist/shared/fleet-telemetry.js.map +1 -0
- package/dist/shared/lifecycle-flags.d.ts +34 -0
- package/dist/shared/lifecycle-flags.js +39 -0
- package/dist/shared/lifecycle-flags.js.map +1 -0
- package/dist/shared/memory-types.d.ts +55 -0
- package/dist/shared/memory-types.js +75 -0
- package/dist/shared/memory-types.js.map +1 -0
- package/dist/shared/service-status.d.ts +82 -0
- package/dist/shared/service-status.js +97 -0
- package/dist/shared/service-status.js.map +1 -0
- package/dist/telemetry/emit.d.ts +197 -0
- package/dist/telemetry/emit.js +196 -0
- package/dist/telemetry/emit.js.map +1 -0
- package/package.json +50 -0
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The viewable dashboard HOST — PRD-001b Wave 2.
|
|
3
|
+
*
|
|
4
|
+
* Adapted from honeycomb `src/daemon/runtime/dashboard/host.ts`. hive is a standalone Hono
|
|
5
|
+
* process that serves the migrated React SPA at the ROOT (`/`), not under `/dashboard`. It serves
|
|
6
|
+
* the INDEX SHELL of the real React app bundled production-clean by esbuild
|
|
7
|
+
* (`src/dashboard/web/main.tsx` → `dist/daemon/dashboard/app.js`). The shell is `<div id="root">`
|
|
8
|
+
* plus a `<link>` to the design-system CSS and a `<script>` to the bundled app; the app then
|
|
9
|
+
* hydrates ITSELF from the daemon endpoints its `wire` targets.
|
|
10
|
+
*
|
|
11
|
+
* NO `unpkg`/CDN React, NO in-browser `@babel/standalone`, NO `type="text/babel"`: the shell
|
|
12
|
+
* references ONLY same-origin loopback assets the host serves, and carries NO token/secret.
|
|
13
|
+
*
|
|
14
|
+
* ── The routes this host registers (hive serves at the root) ───────────────
|
|
15
|
+
* GET /app.js → the esbuild bundle (React + ReactDOM + the app)
|
|
16
|
+
* GET /styles.css → the concatenated design-system CSS
|
|
17
|
+
* GET /honeycomb-memory-cluster.svg → the brand mark
|
|
18
|
+
* GET /fonts/:name → an allow-listed brand font
|
|
19
|
+
* GET * → the index shell ({@link renderShell}), a CATCH-ALL
|
|
20
|
+
*
|
|
21
|
+
* PRD-003a split this into two entry points, {@link mountDashboardAssets} and
|
|
22
|
+
* {@link mountDashboardShellFallback}, because the shell is now served for EVERY path-based SPA
|
|
23
|
+
* route (`/`, `/projects`, ..., `/buzzing`, `/login`, and any client-only deep link), not just `/`.
|
|
24
|
+
* The shell route must therefore be a catch-all (`*`) registered LAST in `server.ts` — AFTER the
|
|
25
|
+
* asset routes below, `/health`, `/api/fleet-status`, and the `/api/*` `/setup/*` BFF proxy — so
|
|
26
|
+
* those more specific routes win (Hono composes matching handlers in registration order; the first
|
|
27
|
+
* one that returns a response without calling `next()` wins). {@link mountDashboardHost} keeps
|
|
28
|
+
* calling both in the safe order for standalone callers (e.g. a bare test `Hono()` with nothing
|
|
29
|
+
* else registered) where that ordering concern does not arise.
|
|
30
|
+
*/
|
|
31
|
+
import type { Hono } from "hono";
|
|
32
|
+
import { type WebAssets } from "./web-assets.js";
|
|
33
|
+
/** The default landing path (the dashboard) — served by the catch-all, like every other route. */
|
|
34
|
+
export declare const DASHBOARD_HOST_PATH: "/";
|
|
35
|
+
/** The same-origin path the host serves the bundled app JS at. */
|
|
36
|
+
export declare const DASHBOARD_APP_PATH: "/app.js";
|
|
37
|
+
/** The same-origin path the host serves the concatenated design-system CSS at. */
|
|
38
|
+
export declare const DASHBOARD_CSS_PATH: "/styles.css";
|
|
39
|
+
/** The same-origin path the host serves the brand mark at. */
|
|
40
|
+
export declare const DASHBOARD_LOGO_PATH: "/honeycomb-memory-cluster.svg";
|
|
41
|
+
/**
|
|
42
|
+
* The same-origin path prefix the host serves the brand fonts under. The served DS CSS's
|
|
43
|
+
* `@font-face` URLs are rewritten to this prefix (see `web-assets.ts` `rewriteFontUrls`) so the
|
|
44
|
+
* browser fetches `/fonts/<file>` instead of the unserved on-disk `../logos/fonts/<file>`. The
|
|
45
|
+
* `:name` is matched against a FIXED allow-list in `web-assets.ts` `font()` — anything not in the
|
|
46
|
+
* six known filenames 404s (no attacker-controlled path component).
|
|
47
|
+
*/
|
|
48
|
+
export declare const DASHBOARD_FONT_PATH: "/fonts/:name";
|
|
49
|
+
/** Options for {@link mountDashboardHost}. */
|
|
50
|
+
export interface MountDashboardHostOptions {
|
|
51
|
+
/**
|
|
52
|
+
* The web-asset reader (the CSS/logo/bundle/fonts source). Defaults to {@link createWebAssets}
|
|
53
|
+
* (resolve the repo `assets/` + the bundle beside this module). A test injects a fixture reader
|
|
54
|
+
* so the host suite never depends on the real tree or a built bundle.
|
|
55
|
+
*/
|
|
56
|
+
readonly assets?: WebAssets;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Build the index SHELL HTML. It is a COMPLETE page: doctype, head with the DS CSS `<link>` + the
|
|
60
|
+
* inline layout CSS, a `<div id="root">` (the app mounts here) carrying the asset base, and the
|
|
61
|
+
* bundled-app `<script type="module">`. NO inline data, NO token/secret, NO CDN/Babel reference —
|
|
62
|
+
* the bundle is same-origin loopback. The app self-hydrates.
|
|
63
|
+
*/
|
|
64
|
+
export declare function renderShell(): string;
|
|
65
|
+
/**
|
|
66
|
+
* Attach the FOUR static-asset routes (app JS, CSS, logo, fonts) onto hive's Hono app. These
|
|
67
|
+
* are specific, fixed paths — register them BEFORE {@link mountDashboardShellFallback}'s catch-all
|
|
68
|
+
* so they win. The asset routes serve no secret/token (a not-yet-built bundle 404s rather than
|
|
69
|
+
* 500s), and — per PRD-003a — they are also EXEMPT from the portal landing gate (`gate.ts`): the
|
|
70
|
+
* bundle must load even when the shell just redirected the browser to `/buzzing` or `/login`,
|
|
71
|
+
* since those exempt screens are served by the same SPA bundle.
|
|
72
|
+
*/
|
|
73
|
+
export declare function mountDashboardAssets(app: Hono, options?: MountDashboardHostOptions): void;
|
|
74
|
+
/**
|
|
75
|
+
* Attach the SPA shell CATCH-ALL onto hive's Hono app (PRD-003a g-AC-1 / g-AC-2). Register this
|
|
76
|
+
* LAST — after the asset routes above, `/health`, `/api/fleet-status`, and the `/api/*` `/setup/*`
|
|
77
|
+
* BFF proxy — so those specific routes win; `*` then serves the identical shell for every gated
|
|
78
|
+
* page path the portal gate (`gate.ts`) let through, PLUS the two gate-exempt screens (`/buzzing`,
|
|
79
|
+
* `/login`) and any unknown/client-only deep link. The bundled app self-hydrates by reading
|
|
80
|
+
* `location.pathname`, so one shell byte-for-byte serves every screen (D-1: no server templating).
|
|
81
|
+
*/
|
|
82
|
+
export declare function mountDashboardShellFallback(app: Hono): void;
|
|
83
|
+
/**
|
|
84
|
+
* Attach the viewable dashboard host onto hive's Hono app: the four static-asset routes plus
|
|
85
|
+
* the shell catch-all, in the safe order. Call this ONLY when nothing else needs to be registered
|
|
86
|
+
* in between (e.g. a standalone test `Hono()`); `server.ts` calls {@link mountDashboardAssets} and
|
|
87
|
+
* {@link mountDashboardShellFallback} separately so `/health`, `/api/fleet-status`, and the BFF
|
|
88
|
+
* proxy can be registered between them (see the module doc for why the ordering matters).
|
|
89
|
+
*/
|
|
90
|
+
export declare function mountDashboardHost(app: Hono, options?: MountDashboardHostOptions): void;
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The viewable dashboard HOST — PRD-001b Wave 2.
|
|
3
|
+
*
|
|
4
|
+
* Adapted from honeycomb `src/daemon/runtime/dashboard/host.ts`. hive is a standalone Hono
|
|
5
|
+
* process that serves the migrated React SPA at the ROOT (`/`), not under `/dashboard`. It serves
|
|
6
|
+
* the INDEX SHELL of the real React app bundled production-clean by esbuild
|
|
7
|
+
* (`src/dashboard/web/main.tsx` → `dist/daemon/dashboard/app.js`). The shell is `<div id="root">`
|
|
8
|
+
* plus a `<link>` to the design-system CSS and a `<script>` to the bundled app; the app then
|
|
9
|
+
* hydrates ITSELF from the daemon endpoints its `wire` targets.
|
|
10
|
+
*
|
|
11
|
+
* NO `unpkg`/CDN React, NO in-browser `@babel/standalone`, NO `type="text/babel"`: the shell
|
|
12
|
+
* references ONLY same-origin loopback assets the host serves, and carries NO token/secret.
|
|
13
|
+
*
|
|
14
|
+
* ── The routes this host registers (hive serves at the root) ───────────────
|
|
15
|
+
* GET /app.js → the esbuild bundle (React + ReactDOM + the app)
|
|
16
|
+
* GET /styles.css → the concatenated design-system CSS
|
|
17
|
+
* GET /honeycomb-memory-cluster.svg → the brand mark
|
|
18
|
+
* GET /fonts/:name → an allow-listed brand font
|
|
19
|
+
* GET * → the index shell ({@link renderShell}), a CATCH-ALL
|
|
20
|
+
*
|
|
21
|
+
* PRD-003a split this into two entry points, {@link mountDashboardAssets} and
|
|
22
|
+
* {@link mountDashboardShellFallback}, because the shell is now served for EVERY path-based SPA
|
|
23
|
+
* route (`/`, `/projects`, ..., `/buzzing`, `/login`, and any client-only deep link), not just `/`.
|
|
24
|
+
* The shell route must therefore be a catch-all (`*`) registered LAST in `server.ts` — AFTER the
|
|
25
|
+
* asset routes below, `/health`, `/api/fleet-status`, and the `/api/*` `/setup/*` BFF proxy — so
|
|
26
|
+
* those more specific routes win (Hono composes matching handlers in registration order; the first
|
|
27
|
+
* one that returns a response without calling `next()` wins). {@link mountDashboardHost} keeps
|
|
28
|
+
* calling both in the safe order for standalone callers (e.g. a bare test `Hono()` with nothing
|
|
29
|
+
* else registered) where that ordering concern does not arise.
|
|
30
|
+
*/
|
|
31
|
+
import { createWebAssets } from "./web-assets.js";
|
|
32
|
+
/** The default landing path (the dashboard) — served by the catch-all, like every other route. */
|
|
33
|
+
export const DASHBOARD_HOST_PATH = "/";
|
|
34
|
+
/** The same-origin path the host serves the bundled app JS at. */
|
|
35
|
+
export const DASHBOARD_APP_PATH = "/app.js";
|
|
36
|
+
/** The same-origin path the host serves the concatenated design-system CSS at. */
|
|
37
|
+
export const DASHBOARD_CSS_PATH = "/styles.css";
|
|
38
|
+
/** The same-origin path the host serves the brand mark at. */
|
|
39
|
+
export const DASHBOARD_LOGO_PATH = "/honeycomb-memory-cluster.svg";
|
|
40
|
+
/**
|
|
41
|
+
* The same-origin path prefix the host serves the brand fonts under. The served DS CSS's
|
|
42
|
+
* `@font-face` URLs are rewritten to this prefix (see `web-assets.ts` `rewriteFontUrls`) so the
|
|
43
|
+
* browser fetches `/fonts/<file>` instead of the unserved on-disk `../logos/fonts/<file>`. The
|
|
44
|
+
* `:name` is matched against a FIXED allow-list in `web-assets.ts` `font()` — anything not in the
|
|
45
|
+
* six known filenames 404s (no attacker-controlled path component).
|
|
46
|
+
*/
|
|
47
|
+
export const DASHBOARD_FONT_PATH = "/fonts/:name";
|
|
48
|
+
/**
|
|
49
|
+
* The asset base the app resolves host-served assets under. hive serves the mark at the ROOT
|
|
50
|
+
* (`/honeycomb-memory-cluster.svg`), so the base is empty — the app's `${assetBase}/…svg`
|
|
51
|
+
* resolves to `/…svg`. main.tsx sanitizes this DOM-read value; an empty string is the safe default.
|
|
52
|
+
*/
|
|
53
|
+
const ASSET_BASE = "";
|
|
54
|
+
/**
|
|
55
|
+
* The static layout CSS the UI kit declares inline (`.wrap`, `.grid2`, `.kpirow`, `.mem-enter`,
|
|
56
|
+
* `.col`). Ported verbatim so the served page lays out exactly like honeycomb's. The DS TOKENS +
|
|
57
|
+
* component styles come from the linked `/styles.css`; this is only the page's grid/animation rules.
|
|
58
|
+
*/
|
|
59
|
+
const LAYOUT_CSS = [
|
|
60
|
+
"body { margin: 0; background: var(--bg-canvas); min-height: 100vh; }",
|
|
61
|
+
".wrap { max-width: 1180px; margin: 0 auto; padding: 28px 28px 48px; }",
|
|
62
|
+
".grid2 { display: grid; grid-template-columns: 1.15fr 1fr; gap: 16px; }",
|
|
63
|
+
"@media (max-width: 900px) { .grid2 { grid-template-columns: 1fr; } }",
|
|
64
|
+
".kpirow { display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px; }",
|
|
65
|
+
"@media (max-width: 720px) { .kpirow { grid-template-columns: repeat(2, 1fr); } }",
|
|
66
|
+
".mem-enter { opacity: 1; }",
|
|
67
|
+
"@media (prefers-reduced-motion: no-preference) {",
|
|
68
|
+
" .mem-enter { animation: memIn var(--dur-base) var(--ease-out) both; }",
|
|
69
|
+
" @keyframes memIn { from { transform: translateY(10px); } to { transform: none; } }",
|
|
70
|
+
"}",
|
|
71
|
+
".col { display: flex; flex-direction: column; gap: 16px; }",
|
|
72
|
+
].join("\n");
|
|
73
|
+
/**
|
|
74
|
+
* Build the index SHELL HTML. It is a COMPLETE page: doctype, head with the DS CSS `<link>` + the
|
|
75
|
+
* inline layout CSS, a `<div id="root">` (the app mounts here) carrying the asset base, and the
|
|
76
|
+
* bundled-app `<script type="module">`. NO inline data, NO token/secret, NO CDN/Babel reference —
|
|
77
|
+
* the bundle is same-origin loopback. The app self-hydrates.
|
|
78
|
+
*/
|
|
79
|
+
export function renderShell() {
|
|
80
|
+
return [
|
|
81
|
+
"<!doctype html>",
|
|
82
|
+
'<html lang="en">',
|
|
83
|
+
"<head>",
|
|
84
|
+
'<meta charset="utf-8">',
|
|
85
|
+
'<meta name="viewport" content="width=device-width, initial-scale=1">',
|
|
86
|
+
"<title>Hive — Dashboard</title>",
|
|
87
|
+
`<link rel="stylesheet" href="${DASHBOARD_CSS_PATH}">`,
|
|
88
|
+
`<link rel="icon" href="${DASHBOARD_LOGO_PATH}">`,
|
|
89
|
+
`<style>${LAYOUT_CSS}</style>`,
|
|
90
|
+
"</head>",
|
|
91
|
+
"<body>",
|
|
92
|
+
`<div id="root" data-asset-base="${ASSET_BASE}"></div>`,
|
|
93
|
+
`<script type="module" src="${DASHBOARD_APP_PATH}"></script>`,
|
|
94
|
+
"</body>",
|
|
95
|
+
"</html>",
|
|
96
|
+
].join("\n");
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Attach the FOUR static-asset routes (app JS, CSS, logo, fonts) onto hive's Hono app. These
|
|
100
|
+
* are specific, fixed paths — register them BEFORE {@link mountDashboardShellFallback}'s catch-all
|
|
101
|
+
* so they win. The asset routes serve no secret/token (a not-yet-built bundle 404s rather than
|
|
102
|
+
* 500s), and — per PRD-003a — they are also EXEMPT from the portal landing gate (`gate.ts`): the
|
|
103
|
+
* bundle must load even when the shell just redirected the browser to `/buzzing` or `/login`,
|
|
104
|
+
* since those exempt screens are served by the same SPA bundle.
|
|
105
|
+
*/
|
|
106
|
+
export function mountDashboardAssets(app, options = {}) {
|
|
107
|
+
const assets = options.assets ?? createWebAssets();
|
|
108
|
+
// GET /app.js — the esbuild bundle (React + ReactDOM + the dashboard app).
|
|
109
|
+
app.get(DASHBOARD_APP_PATH, (c) => {
|
|
110
|
+
const asset = assets.appJs();
|
|
111
|
+
if (asset === null)
|
|
112
|
+
return c.text("dashboard bundle not built", 404);
|
|
113
|
+
return c.body(asset.body, 200, { "content-type": asset.contentType, "cache-control": "no-cache" });
|
|
114
|
+
});
|
|
115
|
+
// GET /styles.css — the concatenated design-system CSS.
|
|
116
|
+
app.get(DASHBOARD_CSS_PATH, (c) => {
|
|
117
|
+
const asset = assets.css();
|
|
118
|
+
if (asset === null)
|
|
119
|
+
return c.text("dashboard styles unavailable", 404);
|
|
120
|
+
return c.body(asset.body, 200, { "content-type": asset.contentType, "cache-control": "no-cache" });
|
|
121
|
+
});
|
|
122
|
+
// GET /honeycomb-memory-cluster.svg — the brand mark. Served `no-cache` too: it shares the
|
|
123
|
+
// un-hashed URL contract with the shell, and revalidating a ~1 KB SVG over loopback is free.
|
|
124
|
+
app.get(DASHBOARD_LOGO_PATH, (c) => {
|
|
125
|
+
const asset = assets.logo();
|
|
126
|
+
if (asset === null)
|
|
127
|
+
return c.text("dashboard logo unavailable", 404);
|
|
128
|
+
return c.body(asset.body, 200, { "content-type": asset.contentType, "cache-control": "no-cache" });
|
|
129
|
+
});
|
|
130
|
+
// GET /fonts/<file> — the brand fonts. The DS CSS's `@font-face` URLs are rewritten to this
|
|
131
|
+
// route. `:name` is allow-listed in `font()` (only the six known filenames resolve; anything
|
|
132
|
+
// else — incl. traversal — 404s). Fonts carry no secret; a long-lived immutable cache-control.
|
|
133
|
+
app.get(DASHBOARD_FONT_PATH, (c) => {
|
|
134
|
+
const asset = assets.font(c.req.param("name"));
|
|
135
|
+
if (asset === null)
|
|
136
|
+
return c.text("dashboard font not found", 404);
|
|
137
|
+
return c.body(asset.body, 200, {
|
|
138
|
+
"content-type": asset.contentType,
|
|
139
|
+
"cache-control": "public, max-age=31536000, immutable",
|
|
140
|
+
});
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Attach the SPA shell CATCH-ALL onto hive's Hono app (PRD-003a g-AC-1 / g-AC-2). Register this
|
|
145
|
+
* LAST — after the asset routes above, `/health`, `/api/fleet-status`, and the `/api/*` `/setup/*`
|
|
146
|
+
* BFF proxy — so those specific routes win; `*` then serves the identical shell for every gated
|
|
147
|
+
* page path the portal gate (`gate.ts`) let through, PLUS the two gate-exempt screens (`/buzzing`,
|
|
148
|
+
* `/login`) and any unknown/client-only deep link. The bundled app self-hydrates by reading
|
|
149
|
+
* `location.pathname`, so one shell byte-for-byte serves every screen (D-1: no server templating).
|
|
150
|
+
*/
|
|
151
|
+
export function mountDashboardShellFallback(app) {
|
|
152
|
+
// `no-cache` (revalidate every load): the shell + app.js + css filenames are NOT content-hashed,
|
|
153
|
+
// so an upgrade rebuilds them in place at the SAME URL. Without a revalidation directive the
|
|
154
|
+
// browser heuristically caches the bundle and keeps running a STALE app.js across a restart.
|
|
155
|
+
// `no-cache` forces a re-pull on each load (cheap over loopback), so a rebuilt dashboard runs.
|
|
156
|
+
app.get("*", (c) => {
|
|
157
|
+
c.header("cache-control", "no-cache");
|
|
158
|
+
return c.html(renderShell());
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Attach the viewable dashboard host onto hive's Hono app: the four static-asset routes plus
|
|
163
|
+
* the shell catch-all, in the safe order. Call this ONLY when nothing else needs to be registered
|
|
164
|
+
* in between (e.g. a standalone test `Hono()`); `server.ts` calls {@link mountDashboardAssets} and
|
|
165
|
+
* {@link mountDashboardShellFallback} separately so `/health`, `/api/fleet-status`, and the BFF
|
|
166
|
+
* proxy can be registered between them (see the module doc for why the ordering matters).
|
|
167
|
+
*/
|
|
168
|
+
export function mountDashboardHost(app, options = {}) {
|
|
169
|
+
mountDashboardAssets(app, options);
|
|
170
|
+
mountDashboardShellFallback(app);
|
|
171
|
+
}
|
|
172
|
+
//# sourceMappingURL=host.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"host.js","sourceRoot":"","sources":["../../../src/daemon/dashboard/host.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The daemon-side ASSET RESOLVER for the bundled dashboard web app — PRD-001b Wave 2.
|
|
3
|
+
*
|
|
4
|
+
* Adapted from honeycomb `src/daemon/runtime/dashboard/web-assets.ts`. hive serves the
|
|
5
|
+
* dashboard at the ROOT (`/`), not under `/dashboard`, so the served asset routes and the
|
|
6
|
+
* `@font-face` URL prefix are rooted at `/` instead of `/dashboard`. The bundle esbuild emits
|
|
7
|
+
* is `app.js` beside this module (`dist/daemon/dashboard/app.js`), not honeycomb's
|
|
8
|
+
* `dashboard-app.js`.
|
|
9
|
+
*
|
|
10
|
+
* The host (`host.ts`) serves, on loopback:
|
|
11
|
+
*
|
|
12
|
+
* GET / → the index SHELL (`<div id="root">` + <link> + <script>)
|
|
13
|
+
* GET /app.js → the esbuild bundle (React + ReactDOM + the app)
|
|
14
|
+
* GET /styles.css → the concatenated DS CSS (tokens + base, no @import chain)
|
|
15
|
+
* GET /honeycomb-memory-cluster.svg → the brand mark
|
|
16
|
+
* GET /fonts/:name → an allow-listed brand font
|
|
17
|
+
*
|
|
18
|
+
* This module owns LOCATING those source assets on disk and reading them. It lives under
|
|
19
|
+
* `src/daemon/` (it does Node `fs` IO) and is the ONLY place the host touches the filesystem.
|
|
20
|
+
*
|
|
21
|
+
* ── Why concatenate the CSS here (not ship the @import chain) ─────────────────
|
|
22
|
+
* `assets/styles.css` is `@import url('tokens/…')` lines — those resolve RELATIVE to the
|
|
23
|
+
* served URL. Rather than serve five files + rewrite the relative URLs, we read the token
|
|
24
|
+
* files in declared order and concatenate them into ONE payload. One request, no relative
|
|
25
|
+
* `@import` resolution, deterministic across install layouts.
|
|
26
|
+
*
|
|
27
|
+
* ── Resolution + injectability ───────────────────────────────────────────────
|
|
28
|
+
* The assets dir defaults to {@link resolveAssetsDir} (walk up from this module to the repo
|
|
29
|
+
* root that contains `assets/styles.css`). A test injects a fixture dir so it never depends
|
|
30
|
+
* on the real tree. Reads fail SOFT (a missing asset yields an empty string / a 404 at the
|
|
31
|
+
* route), never a throw that would 500 the page.
|
|
32
|
+
*/
|
|
33
|
+
/**
|
|
34
|
+
* The bundled web-app filename the build emits beside this module. esbuild
|
|
35
|
+
* (`esbuild.config.mjs`) bundles `src/dashboard/web/main.tsx` → `dist/daemon/dashboard/app.js`.
|
|
36
|
+
*/
|
|
37
|
+
export declare const DASHBOARD_APP_BUNDLE: "app.js";
|
|
38
|
+
/**
|
|
39
|
+
* Resolve the repo `assets/` directory by walking up from this module until a dir with
|
|
40
|
+
* `assets/styles.css` is found. Works from `src/` (tsc/vitest run from source) and from the
|
|
41
|
+
* built `dist/daemon/dashboard/` layout. Returns `null` when no `assets/` is found (a stripped install).
|
|
42
|
+
*/
|
|
43
|
+
export declare function resolveAssetsDir(startUrl?: string): string | null;
|
|
44
|
+
/**
|
|
45
|
+
* Resolve the directory the bundled `app.js` lives in. esbuild emits it beside this module's
|
|
46
|
+
* compiled output (`dist/daemon/dashboard/`), so the bundle sits next to it. From source
|
|
47
|
+
* (vitest) the bundle may not exist yet — the read fails soft. Returns `null` when the dir
|
|
48
|
+
* cannot be resolved.
|
|
49
|
+
*/
|
|
50
|
+
export declare function resolveBundleDir(startUrl?: string): string | null;
|
|
51
|
+
/** Options for {@link createWebAssets}. */
|
|
52
|
+
export interface WebAssetsOptions {
|
|
53
|
+
/** The `assets/` source dir. Defaults to {@link resolveAssetsDir}. A test injects a fixture. */
|
|
54
|
+
readonly assetsDir?: string | null;
|
|
55
|
+
/** The dir the bundled app JS lives in. Defaults to {@link resolveBundleDir}. */
|
|
56
|
+
readonly bundleDir?: string | null;
|
|
57
|
+
/** Override the bundled app JS content directly (a test serves a stub bundle). */
|
|
58
|
+
readonly appJs?: string;
|
|
59
|
+
}
|
|
60
|
+
/** A served text asset: its UTF-8 body + content type, or `null` when missing (→ 404). */
|
|
61
|
+
export interface ServedAsset {
|
|
62
|
+
readonly body: string;
|
|
63
|
+
readonly contentType: string;
|
|
64
|
+
}
|
|
65
|
+
/** A served BINARY asset (the fonts): raw bytes + content type, or `null` when missing (→ 404). */
|
|
66
|
+
export interface ServedBinaryAsset {
|
|
67
|
+
readonly body: ArrayBuffer;
|
|
68
|
+
readonly contentType: string;
|
|
69
|
+
}
|
|
70
|
+
/** The host-facing asset reader: the concatenated CSS, the logo, the app bundle, and the fonts. */
|
|
71
|
+
export interface WebAssets {
|
|
72
|
+
/** The concatenated DS CSS (tokens + base), font URLs rewritten, or `null` when the assets dir is missing. */
|
|
73
|
+
css(): ServedAsset | null;
|
|
74
|
+
/** The brand logo SVG, or `null` when missing. */
|
|
75
|
+
logo(): ServedAsset | null;
|
|
76
|
+
/** The bundled web-app JS, or `null` when the bundle has not been built. */
|
|
77
|
+
appJs(): ServedAsset | null;
|
|
78
|
+
/** A brand font's bytes + content type for an allow-listed `name`, or `null` (→ 404) otherwise. */
|
|
79
|
+
font(name: string): ServedBinaryAsset | null;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Build the host-side asset reader. Resolves the assets + bundle dirs once and reads on
|
|
83
|
+
* demand. Every read fails soft (missing → `null` → the route 404s), so a stripped install or
|
|
84
|
+
* a not-yet-built bundle never 500s the page. The CSS is concatenated from the token files in
|
|
85
|
+
* declared order so the served page needs ONE stylesheet request and no relative `@import`
|
|
86
|
+
* resolution.
|
|
87
|
+
*/
|
|
88
|
+
export declare function createWebAssets(options?: WebAssetsOptions): WebAssets;
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The daemon-side ASSET RESOLVER for the bundled dashboard web app — PRD-001b Wave 2.
|
|
3
|
+
*
|
|
4
|
+
* Adapted from honeycomb `src/daemon/runtime/dashboard/web-assets.ts`. hive serves the
|
|
5
|
+
* dashboard at the ROOT (`/`), not under `/dashboard`, so the served asset routes and the
|
|
6
|
+
* `@font-face` URL prefix are rooted at `/` instead of `/dashboard`. The bundle esbuild emits
|
|
7
|
+
* is `app.js` beside this module (`dist/daemon/dashboard/app.js`), not honeycomb's
|
|
8
|
+
* `dashboard-app.js`.
|
|
9
|
+
*
|
|
10
|
+
* The host (`host.ts`) serves, on loopback:
|
|
11
|
+
*
|
|
12
|
+
* GET / → the index SHELL (`<div id="root">` + <link> + <script>)
|
|
13
|
+
* GET /app.js → the esbuild bundle (React + ReactDOM + the app)
|
|
14
|
+
* GET /styles.css → the concatenated DS CSS (tokens + base, no @import chain)
|
|
15
|
+
* GET /honeycomb-memory-cluster.svg → the brand mark
|
|
16
|
+
* GET /fonts/:name → an allow-listed brand font
|
|
17
|
+
*
|
|
18
|
+
* This module owns LOCATING those source assets on disk and reading them. It lives under
|
|
19
|
+
* `src/daemon/` (it does Node `fs` IO) and is the ONLY place the host touches the filesystem.
|
|
20
|
+
*
|
|
21
|
+
* ── Why concatenate the CSS here (not ship the @import chain) ─────────────────
|
|
22
|
+
* `assets/styles.css` is `@import url('tokens/…')` lines — those resolve RELATIVE to the
|
|
23
|
+
* served URL. Rather than serve five files + rewrite the relative URLs, we read the token
|
|
24
|
+
* files in declared order and concatenate them into ONE payload. One request, no relative
|
|
25
|
+
* `@import` resolution, deterministic across install layouts.
|
|
26
|
+
*
|
|
27
|
+
* ── Resolution + injectability ───────────────────────────────────────────────
|
|
28
|
+
* The assets dir defaults to {@link resolveAssetsDir} (walk up from this module to the repo
|
|
29
|
+
* root that contains `assets/styles.css`). A test injects a fixture dir so it never depends
|
|
30
|
+
* on the real tree. Reads fail SOFT (a missing asset yields an empty string / a 404 at the
|
|
31
|
+
* route), never a throw that would 500 the page.
|
|
32
|
+
*/
|
|
33
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
34
|
+
import { dirname, join } from "node:path";
|
|
35
|
+
import { fileURLToPath } from "node:url";
|
|
36
|
+
/** The token files, in the SAME order `assets/styles.css` @imports them (order matters). */
|
|
37
|
+
const CSS_FILES = ["tokens/fonts.css", "tokens/colors.css", "tokens/typography.css", "tokens/spacing.css", "tokens/base.css"];
|
|
38
|
+
/** The design-system logo the header renders. */
|
|
39
|
+
const LOGO_FILE = "logos/honeycomb-memory-cluster.svg";
|
|
40
|
+
/**
|
|
41
|
+
* The on-disk dir (under `assets/`) the brand fonts live in, and the FIXED allow-list of the
|
|
42
|
+
* six font filenames the host will serve. The host route serves ONLY a name in this set — there
|
|
43
|
+
* is NO attacker-controlled path component (mirrors {@link LOGO_FILE}'s hard-coded-filename
|
|
44
|
+
* safety). Anything not in this set yields `null` → a 404 at the route.
|
|
45
|
+
*/
|
|
46
|
+
const FONTS_DIR = "logos/fonts";
|
|
47
|
+
const FONT_FILES = [
|
|
48
|
+
"Inter-VariableFont_opsz_wght.ttf",
|
|
49
|
+
"Inter-Italic-VariableFont_opsz_wght.ttf",
|
|
50
|
+
"JetBrainsMono-Regular.woff2",
|
|
51
|
+
"JetBrainsMono-Medium.woff2",
|
|
52
|
+
"JetBrainsMono-SemiBold.woff2",
|
|
53
|
+
"JetBrainsMono-Bold.woff2",
|
|
54
|
+
];
|
|
55
|
+
const FONT_ALLOW = new Set(FONT_FILES);
|
|
56
|
+
/** The same-origin path hive serves the fonts under (origin-rooted; see {@link rewriteFontUrls}). */
|
|
57
|
+
const FONT_ROUTE_PREFIX = "/fonts/";
|
|
58
|
+
/** Map a font filename to its `content-type` by extension (`.woff2` → `font/woff2`, `.ttf` → `font/ttf`). */
|
|
59
|
+
function fontContentType(name) {
|
|
60
|
+
return name.endsWith(".woff2") ? "font/woff2" : "font/ttf";
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Rewrite the DS `@font-face` `url(...)` prefix in the SERVED CSS so the fonts resolve to the
|
|
64
|
+
* host's `/fonts/<file>` route instead of the on-disk `../logos/fonts/<file>` (which the host
|
|
65
|
+
* does not serve at that path → 404). The replacement is ORIGIN-ROOTED (leading `/`) so it
|
|
66
|
+
* resolves regardless of the stylesheet's own URL. ONLY the `logos/fonts/` prefix is touched — the
|
|
67
|
+
* `../` is consumed with it, and no other `url(...)` (the mark SVG etc.) is mangled. Byte-identical
|
|
68
|
+
* otherwise.
|
|
69
|
+
*/
|
|
70
|
+
function rewriteFontUrls(css) {
|
|
71
|
+
return css.replaceAll("../logos/fonts/", FONT_ROUTE_PREFIX).replaceAll("logos/fonts/", FONT_ROUTE_PREFIX);
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* The bundled web-app filename the build emits beside this module. esbuild
|
|
75
|
+
* (`esbuild.config.mjs`) bundles `src/dashboard/web/main.tsx` → `dist/daemon/dashboard/app.js`.
|
|
76
|
+
*/
|
|
77
|
+
export const DASHBOARD_APP_BUNDLE = "app.js";
|
|
78
|
+
/**
|
|
79
|
+
* Resolve the repo `assets/` directory by walking up from this module until a dir with
|
|
80
|
+
* `assets/styles.css` is found. Works from `src/` (tsc/vitest run from source) and from the
|
|
81
|
+
* built `dist/daemon/dashboard/` layout. Returns `null` when no `assets/` is found (a stripped install).
|
|
82
|
+
*/
|
|
83
|
+
export function resolveAssetsDir(startUrl = import.meta.url) {
|
|
84
|
+
let dir;
|
|
85
|
+
try {
|
|
86
|
+
dir = dirname(fileURLToPath(startUrl));
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
// Walk up to the filesystem root looking for `<dir>/assets/styles.css`.
|
|
92
|
+
for (let i = 0; i < 12; i++) {
|
|
93
|
+
const candidate = join(dir, "assets");
|
|
94
|
+
if (existsSync(join(candidate, "styles.css")))
|
|
95
|
+
return candidate;
|
|
96
|
+
const parent = dirname(dir);
|
|
97
|
+
if (parent === dir)
|
|
98
|
+
break;
|
|
99
|
+
dir = parent;
|
|
100
|
+
}
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Resolve the directory the bundled `app.js` lives in. esbuild emits it beside this module's
|
|
105
|
+
* compiled output (`dist/daemon/dashboard/`), so the bundle sits next to it. From source
|
|
106
|
+
* (vitest) the bundle may not exist yet — the read fails soft. Returns `null` when the dir
|
|
107
|
+
* cannot be resolved.
|
|
108
|
+
*/
|
|
109
|
+
export function resolveBundleDir(startUrl = import.meta.url) {
|
|
110
|
+
try {
|
|
111
|
+
return dirname(fileURLToPath(startUrl));
|
|
112
|
+
}
|
|
113
|
+
catch {
|
|
114
|
+
return null;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
/** Read a UTF-8 file, returning `null` (never throwing) on any IO error. */
|
|
118
|
+
function readSoft(path) {
|
|
119
|
+
try {
|
|
120
|
+
return existsSync(path) ? readFileSync(path, "utf-8") : null;
|
|
121
|
+
}
|
|
122
|
+
catch {
|
|
123
|
+
return null;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Read a file as a raw `ArrayBuffer` (fonts are binary; a UTF-8 round-trip would corrupt them).
|
|
128
|
+
* Returns an exact-length `ArrayBuffer` slice so the served body is a non-shared buffer Hono
|
|
129
|
+
* accepts as a binary `Data`.
|
|
130
|
+
*/
|
|
131
|
+
function readBinarySoft(path) {
|
|
132
|
+
try {
|
|
133
|
+
if (!existsSync(path))
|
|
134
|
+
return null;
|
|
135
|
+
const buf = readFileSync(path);
|
|
136
|
+
return buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength);
|
|
137
|
+
}
|
|
138
|
+
catch {
|
|
139
|
+
return null;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Build the host-side asset reader. Resolves the assets + bundle dirs once and reads on
|
|
144
|
+
* demand. Every read fails soft (missing → `null` → the route 404s), so a stripped install or
|
|
145
|
+
* a not-yet-built bundle never 500s the page. The CSS is concatenated from the token files in
|
|
146
|
+
* declared order so the served page needs ONE stylesheet request and no relative `@import`
|
|
147
|
+
* resolution.
|
|
148
|
+
*/
|
|
149
|
+
export function createWebAssets(options = {}) {
|
|
150
|
+
const assetsDir = options.assetsDir === undefined ? resolveAssetsDir() : options.assetsDir;
|
|
151
|
+
const bundleDir = options.bundleDir === undefined ? resolveBundleDir() : options.bundleDir;
|
|
152
|
+
const appJsOverride = options.appJs;
|
|
153
|
+
return {
|
|
154
|
+
css() {
|
|
155
|
+
if (assetsDir === null)
|
|
156
|
+
return null;
|
|
157
|
+
const parts = [];
|
|
158
|
+
for (const rel of CSS_FILES) {
|
|
159
|
+
const text = readSoft(join(assetsDir, rel));
|
|
160
|
+
if (text !== null)
|
|
161
|
+
parts.push(`/* ${rel} */\n${text}`);
|
|
162
|
+
}
|
|
163
|
+
if (parts.length === 0)
|
|
164
|
+
return null;
|
|
165
|
+
// Rewrite the `@font-face` URL prefix so the fonts resolve to the served `/fonts/` route
|
|
166
|
+
// (the host does not serve the on-disk `../logos/fonts/` path → 404). See rewriteFontUrls.
|
|
167
|
+
return { body: rewriteFontUrls(parts.join("\n\n")), contentType: "text/css; charset=utf-8" };
|
|
168
|
+
},
|
|
169
|
+
logo() {
|
|
170
|
+
if (assetsDir === null)
|
|
171
|
+
return null;
|
|
172
|
+
const svg = readSoft(join(assetsDir, LOGO_FILE));
|
|
173
|
+
return svg === null ? null : { body: svg, contentType: "image/svg+xml" };
|
|
174
|
+
},
|
|
175
|
+
font(name) {
|
|
176
|
+
if (assetsDir === null)
|
|
177
|
+
return null;
|
|
178
|
+
// Allow-list ONLY: a name not in the fixed six is rejected (→ 404). No attacker-controlled
|
|
179
|
+
// path component — `name` is never joined unless it is a known leaf filename.
|
|
180
|
+
if (!FONT_ALLOW.has(name))
|
|
181
|
+
return null;
|
|
182
|
+
const bytes = readBinarySoft(join(assetsDir, FONTS_DIR, name));
|
|
183
|
+
return bytes === null ? null : { body: bytes, contentType: fontContentType(name) };
|
|
184
|
+
},
|
|
185
|
+
appJs() {
|
|
186
|
+
if (appJsOverride !== undefined)
|
|
187
|
+
return { body: appJsOverride, contentType: "text/javascript; charset=utf-8" };
|
|
188
|
+
if (bundleDir === null)
|
|
189
|
+
return null;
|
|
190
|
+
const js = readSoft(join(bundleDir, DASHBOARD_APP_BUNDLE));
|
|
191
|
+
return js === null ? null : { body: js, contentType: "text/javascript; charset=utf-8" };
|
|
192
|
+
},
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
//# sourceMappingURL=web-assets.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"web-assets.js","sourceRoot":"","sources":["../../../src/daemon/dashboard/web-assets.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { isFleetReady, V1_REQUIRED_PEERS, type FleetDaemonStatus, type FleetHealth, type FleetStatusResponse } from "../shared/fleet-readiness.js";
|
|
2
|
+
export type { FleetDaemonStatus, FleetHealth, FleetStatusResponse };
|
|
3
|
+
export { isFleetReady, V1_REQUIRED_PEERS };
|
|
4
|
+
/**
|
|
5
|
+
* Minimal init surface for the status fetch. `redirect` is pinned (fs-AC-9 defense in depth on top
|
|
6
|
+
* of the loopback URL pin): native fetch defaults to `redirect: "follow"`, so a rogue or compromised
|
|
7
|
+
* loopback service answering on :3852 could 3xx-redirect hive's fetch to a non-loopback origin,
|
|
8
|
+
* silently defeating `isLoopbackBaseUrl()` (which only validates the initial URL). Pinning
|
|
9
|
+
* `redirect: "error"` makes fetch reject on any redirect, so the off-loopback request never fires.
|
|
10
|
+
*/
|
|
11
|
+
export type FleetFetchInit = {
|
|
12
|
+
readonly redirect?: "error" | "follow" | "manual";
|
|
13
|
+
};
|
|
14
|
+
export type FetchImpl = (input: string, init?: FleetFetchInit) => Promise<Response>;
|
|
15
|
+
export declare function fetchFleetStatus(fetchImpl?: FetchImpl, url?: string): Promise<FleetStatusResponse>;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { DOCTOR_STATUS_URL } from "../shared/constants.js";
|
|
3
|
+
import { isLoopbackBaseUrl } from "../shared/daemon-routing.js";
|
|
4
|
+
import { isFleetReady, V1_REQUIRED_PEERS } from "../shared/fleet-readiness.js";
|
|
5
|
+
export { isFleetReady, V1_REQUIRED_PEERS };
|
|
6
|
+
const UNREACHABLE_RESPONSE = {
|
|
7
|
+
supervisor: "unreachable",
|
|
8
|
+
daemons: []
|
|
9
|
+
};
|
|
10
|
+
const FleetHealthSchema = z.enum(["ok", "degraded", "unreachable", "unknown"]);
|
|
11
|
+
const FleetDaemonSchema = z.object({
|
|
12
|
+
name: z.string().min(1),
|
|
13
|
+
health: FleetHealthSchema,
|
|
14
|
+
escalation: z.unknown().nullable().optional()
|
|
15
|
+
});
|
|
16
|
+
const DoctorStatusSchema = z.object({
|
|
17
|
+
health: FleetHealthSchema,
|
|
18
|
+
daemons: z.array(FleetDaemonSchema).optional().default([]),
|
|
19
|
+
asOf: z.string().min(1)
|
|
20
|
+
});
|
|
21
|
+
export async function fetchFleetStatus(fetchImpl = fetch, url = DOCTOR_STATUS_URL) {
|
|
22
|
+
if (!isLoopbackBaseUrl(url)) {
|
|
23
|
+
return UNREACHABLE_RESPONSE;
|
|
24
|
+
}
|
|
25
|
+
try {
|
|
26
|
+
const response = await fetchImpl(url, { redirect: "error" });
|
|
27
|
+
if (!response.ok) {
|
|
28
|
+
return UNREACHABLE_RESPONSE;
|
|
29
|
+
}
|
|
30
|
+
let parsedJson;
|
|
31
|
+
try {
|
|
32
|
+
parsedJson = await response.json();
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
return UNREACHABLE_RESPONSE;
|
|
36
|
+
}
|
|
37
|
+
const parsed = DoctorStatusSchema.safeParse(parsedJson);
|
|
38
|
+
if (!parsed.success) {
|
|
39
|
+
return UNREACHABLE_RESPONSE;
|
|
40
|
+
}
|
|
41
|
+
return {
|
|
42
|
+
supervisor: "reachable",
|
|
43
|
+
health: parsed.data.health,
|
|
44
|
+
daemons: parsed.data.daemons.map((daemon) => ({
|
|
45
|
+
name: daemon.name,
|
|
46
|
+
health: daemon.health,
|
|
47
|
+
escalation: daemon.escalation ?? null
|
|
48
|
+
})),
|
|
49
|
+
asOf: parsed.data.asOf
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
return UNREACHABLE_RESPONSE;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=fleet-status.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fleet-status.js","sourceRoot":"","sources":["../../src/daemon/fleet-status.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,EACL,YAAY,EACZ,iBAAiB,EAIlB,MAAM,8BAA8B,CAAC;AAGtC,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,CAAC;AAE3C,MAAM,oBAAoB,GAAG;IAC3B,UAAU,EAAE,aAAa;IACzB,OAAO,EAAE,EAAE;CAC2B,CAAC;AAEzC,MAAM,iBAAiB,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,UAAU,EAAE,aAAa,EAAE,SAAS,CAAC,CAAC,CAAC;AAE/E,MAAM,iBAAiB,GAAG,CAAC,CAAC,MAAM,CAAC;IACjC,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACvB,MAAM,EAAE,iBAAiB;IACzB,UAAU,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE;CAC9C,CAAC,CAAC;AAEH,MAAM,kBAAkB,GAAG,CAAC,CAAC,MAAM,CAAC;IAClC,MAAM,EAAE,iBAAiB;IACzB,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC;IAC1D,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;CACxB,CAAC,CAAC;AAYH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,YAAuB,KAAK,EAC5B,MAAc,iBAAiB;IAE/B,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,EAAE,CAAC;QAC5B,OAAO,oBAAoB,CAAC;IAC9B,CAAC;IAED,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAC,GAAG,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC;QAC7D,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,OAAO,oBAAoB,CAAC;QAC9B,CAAC;QAED,IAAI,UAAmB,CAAC;QACxB,IAAI,CAAC;YACH,UAAU,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;QACrC,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,oBAAoB,CAAC;QAC9B,CAAC;QAED,MAAM,MAAM,GAAG,kBAAkB,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;QACxD,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACpB,OAAO,oBAAoB,CAAC;QAC9B,CAAC;QAED,OAAO;YACL,UAAU,EAAE,WAAW;YACvB,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,MAAM;YAC1B,OAAO,EAAE,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;gBAC5C,IAAI,EAAE,MAAM,CAAC,IAAI;gBACjB,MAAM,EAAE,MAAM,CAAC,MAAM;gBACrB,UAAU,EAAE,MAAM,CAAC,UAAU,IAAI,IAAI;aACtC,CAAC,CAAC;YACH,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,IAAI;SACvB,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,oBAAoB,CAAC;IAC9B,CAAC;AACH,CAAC"}
|