React Query & Devtools
Hooks for TanStack Query, plus browser and server devtools.
React Query integration
Section titled “React Query integration”Import from @nice-code/action/react-query (peer dep: @tanstack/react-query).
import { useActionQuery, useActionMutation } from "@nice-code/action/react-query";
function UserProfile({ userId }: { userId: string }) { const { data } = useActionQuery( userDomain.action.getUser, { userId }, { queryKey: ["user", userId] }, ); return <div>{data?.name}</div>;}
function RenameUser() { const { mutate } = useActionMutation(userDomain.action.updateName); return <button onClick={() => mutate({ userId: "u_1", name: "Bob" })}>Rename</button>;}Input, output, and errors are all inferred from the action schema — no manual query function, no hand-written types.
Browser devtools
Section titled “Browser devtools”A dockable in-app panel showing every action run: status, timing, input/output, routing, errors, and call stacks. Renders only when NODE_ENV === "development" (or with forceEnable). Import from @nice-code/action/devtools/browser.
import { ActionDevtoolsCore, NiceActionDevtools } from "@nice-code/action/devtools/browser";
const devtoolsCore = new ActionDevtoolsCore();devtoolsCore.attachToDomain(appRoot);
function App() { return ( <> <MyApp /> <NiceActionDevtools core={devtoolsCore} position="dock-bottom" /> </> );}Failed runs are classified by the same two axes you branch on in code (see
Error Handling): an action error is labelled Expected Error (declared)
vs Unexpected Error (undeclared / unhandled) from result.expected, and a wrapped foreign throw carries
an unhandled badge from error.isUnhandled.
Server logger
Section titled “Server logger”Logs action lifecycle (started / progress / success / error) with timings — pretty lines or newline-delimited JSON. Import from @nice-code/action/devtools/server.
import { ActionServerDevtools } from "@nice-code/action/devtools/server";
const devtools = new ActionServerDevtools({ format: "json", logPayloads: false });devtools.attachToDomain(appRoot);RuntimeCoordinate reference
Section titled “RuntimeCoordinate reference”Identifies a runtime environment and routes actions to the right handler:
RuntimeCoordinate.env("backend"); // named envRuntimeCoordinate.env("backend").specify({ perId: "worker-1" }); // env + instanceRuntimeCoordinate.env("backend").withPersistentId(id.toString()); // env + persistent instance idRuntimeCoordinate.unknown; // unspecifiedLower-level building blocks
Section titled “Lower-level building blocks”connectChannel / serveChannel are the supported entry points. For the rare routing that isn’t a single channel, the pieces they’re built on are exported — most under the @nice-code/action/advanced subpath:
acceptChannel/acceptChannelConnections— build a secure acceptor by hand with connection-aware cases.createActionFetchHandler— the web-standardfetchhandler on its own.createInMemoryChannelPair/inMemoryCarrier— wire two runtimes in-process (tests, same-process peers) with no network.createBinaryWireAdapter— the positional binary codecdefineChannelbuilds for you, for custom carriers.
Reach for these only when a single channel doesn’t model your routing.