@streetjs/devtools
v1.0.0
Published
Street Framework Interactive Developer Experience: a browser bundle delivering the Playground (route/middleware/plugin testing + OpenAPI viewer), Route Explorer, Dependency Graph Visualizer, and API Inspector, gated by a token-based, read-only authn/authz
Maintainers
Readme
@streetjs/devtools
The StreetJS Framework Interactive Developer Experience — a single, self-contained browser bundle that lets you explore and exercise a running StreetJS application. It is generated by this package and embedded into the GitHub Pages docs site.
Four tools, delivered as a browser experience:
- Playground — route, middleware, and plugin testing plus an OpenAPI viewer.
- Route Explorer — a visual route tree; each registered route shows its HTTP method and path.
- Dependency Graph Visualizer — module dependencies drawn as nodes and edges.
- API Inspector — issue a request and inspect the response status, headers, and body; on failure it shows an error and retains the submitted input.
The tools reuse the pure data builders from streetjs
(buildRouteTree, buildDependencyGraph, inspectorSuccess/inspectorFailure,
openApiToHtml) so the framework and the tools agree on the data model.
Security: token-gated and read-only (enforced)
The access model is declared and enforced, not just documented.
- Authentication — token-gated. Every request the tools make against the
inspected app requires a bearer access token. The raw token is never stored;
DevtoolsAuthGatekeeps only its SHA-256 hash and compares it in constant time (crypto.timingSafeEqual). Missing / empty / wrong token →401. - Authorization — read-only. Even an authenticated caller may only issue
safe methods (
GET,HEAD,OPTIONS). Any mutating method →403. The tools cannot change the inspected app's state.
The authoritative gate is DevtoolsAuthGate (server side). The browser client
mirrors the same policy: nothing leaves the page without a token, mutating
operations are disabled, and the token lives in memory only.
import { DevtoolsAuthGate } from '@streetjs/devtools';
const gate = DevtoolsAuthGate.fromToken(process.env.DEVTOOLS_TOKEN!);
const decision = gate.authorizeHeader(req.headers.authorization, req.method);
if (!decision.allowed) {
res.statusCode = decision.status; // 401 (unauthenticated) | 403 (read-only)
res.end(decision.reason);
}Generate the bundle
npm run build # compile to dist/
npm run build:docs # emit docs/devtools/index.html for the Pages site
npx streetjs-devtools --out path/to/index.html # render the demo bundleFor a live app:
import { buildDevtoolsData, renderDevtoolsBundle } from '@streetjs/devtools';
const html = renderDevtoolsBundle(
buildDevtoolsData(app, { baseUrl: 'https://api.example.com', dependencyEntry: 'src/main.ts' }),
);Tests
npm run test:run # compile tests then run them with node:testCovers the gate's fail-closed enforcement (token + read-only), the gated API Inspector flow (success, denial-before-network, failure with retained input), and the browser bundle rendering (all four tools, route tree, embedded graph, script-tag escaping).
