Use the App Router on the Node.js runtime. The drawer belongs in a Client Component; the adapter and SDK belong in a server module.
Install and configure#
npm install jev-devtools @typesafe-ai/sdk server-onlyMerge the SDK externalization into your existing next.config.mjs:
export default {
serverExternalPackages: ["@typesafe-ai/sdk"],
};Externalize the SDK only. The React package entry should use Next's React instance during server rendering.
Share your server adapter#
// server/jev.ts
import "server-only";
import { getJevDevtools } from "jev-devtools/server";
export const inspector = getJevDevtools("my-next-app", () => ({
enabled: process.env.NODE_ENV === "development",
origin: "http://localhost:3000",
}));
export const jev = inspector.createClient({
apiKey: process.env.TYPESAFE_API_KEY,
});Reuse an adapter for a stable key in the same Node realm. The options factory runs once per key; restart after configuration changes. Different processes do not share history.
getJevDevtools(key, createOptions)- key
- A stable, nonempty application key.
- createOptions
- Return the server options, including enabled and origin.
Opt into server capture and inspector endpoints. Defaults to false; disabling capture does not stop inference.
enabledThe exact browser origin, including scheme, hostname, and port.
originCreate an instrumented TypeSafe client. Captures systemOne calls when recording is enabled; otherwise returns an ordinary SDK client. Keep credentials on the server.
adapter.createClient(options, metadata?)- label
- Optional capture label. Defaults to Jev request.
- source
- Capture label: sample or live. Defaults to live. This does not switch transports or prevent inference.
API reference: getJevDevtools() · createJevDevtools() · adapter.createClient()
Import this jev from Route Handlers, Server Actions, or Server Components. The stable key reuses the adapter across module reloads in the same Node realm. Restart after changing its options: the first options factory wins until disposal or restart.
Expose the optional catch-all route#
// app/api/jev-devtools/[[...path]]/route.ts
import { inspector } from "../../../../server/jev";
export const runtime = "nodejs";
export const dynamic = "force-dynamic";
export const GET = (request: Request) => inspector.handleNodeRoute(request);
export const DELETE = (request: Request) => inspector.handleNodeRoute(request);Check Host, normalize a Node framework's internal request URL, and apply the adapter's access checks. Route the base endpoint and all subpaths here.
adapter.handleNodeRoute(request)API reference: adapter.handleNodeRoute()
The optional catch-all includes both the base endpoint and its children. handleNodeRoute checks the incoming Host and normalizes framework-internal request URLs. Proxies must preserve Host; forwarded host headers are not trusted.
Mount a Client Component#
// app/devtools.tsx
"use client";
import { JevDevtools } from "jev-devtools";
export function Devtools() {
return <JevDevtools enabled={process.env.NODE_ENV === "development"} />;
}Mount the inspector once near your application root. It connects after mounting when enabled; it renders nothing during SSR.
<JevDevtools enabled defaultOpen={false} />- enabled
- Load and connect the browser inspector. Defaults to false; enable the server adapter separately.
- defaultOpen
- Whether the drawer starts expanded. Defaults to true; false starts at the launcher.
- endpoint
- Same-origin inspector path. Defaults to /api/jev-devtools; must match the server adapter.
- redactAdditionalSensitiveData
- Mask supported personal fields in the display. Does not remove captured data. Unreleased; defaults to true.
Load and connect the browser inspector. Defaults to false; enable the server adapter separately.
enabledAPI reference: JevDevtools
Render <Devtools /> once inside the root layout's <body>. It renders nothing during SSR and connects after mounting. No stylesheet import is needed.
Run locally#
npx next dev --hostname 127.0.0.1Open the URL matching your configured origin. Web Request handlers cannot inspect the connection's socket address, so bind to loopback or configure authorize. With custom session scopes, wrap inference handlers in inspector.run(request, callback); Server Actions need a trusted Request derived from server headers.
See the complete framework guide for layout code, Server Actions, custom scopes, base paths, caching, and deployment limits. The independent Next.js example is sample-only and needs no key.