Mock Server
@nopii/mock-server is an in-memory NoPII for local development, tests, and demos. It needs no account, no keys, and no network, and behaves the same way on every run.
Preview
Run it
npx nopii-mock --port 7431Point the SDKs at http://127.0.0.1:7431. It serves the client API, client sessions, reveal grants, and the proxy for OpenAI Chat Completions and the OpenAI Responses API, with a scripted LLM in place of a provider.
| Credential | Accepted as |
|---|---|
nsk_... | A secret key |
npk_... | A publishable key |
sk-... | A provider key on proxy routes |
See what each party received
GET /__mock/state returns a log of every request: what your backend sent, what the scripted LLM saw, and what came back. It is the quickest way to confirm that plaintext never reached a place it should not. POST /__mock/reset clears everything.
In tests
Skip HTTP entirely. The mock's fetch handles requests in memory.
import { createMockNoPII } from "@nopii/mock-server";
import { NoPIIServer } from "@nopii/node";
import { NoPII } from "@nopii/browser";
const mock = createMockNoPII({ names: ["Ada Lovelace"] });
// Mint a session the way your backend would.
const server = new NoPIIServer({ secretKey: "nsk_test", baseUrl: "http://mock", fetchImpl: mock.fetch });
const session = await server.clientSessions.create({ endUserId: "user-1" });
const nopii = NoPII.init({ baseUrl: "http://mock", sessionToken: session.token, fetchImpl: mock.fetch });
const { texts } = await nopii.tokenize("Ada Lovelace wrote the first program");
// texts[0] is "[NAME: ...] wrote the first program"A publishable key works in the mock as it does in NoPII: only with an Origin header, which tests running outside a browser do not send. Use a client session, as above.
| Option | Meaning |
|---|---|
names | Extra names detected as people. Common full names such as Jane Doe, and surnames after a title such as Dr. Patel, are detected without it, as are emails and phone numbers. |
allowedOrigins | Origins publishable keys may be used from. Defaults to any, but an Origin is still required. |
streamChunkSize | Characters per streamed chunk. Small by default, so tokens split across chunks. |
llm | Replace the scripted LLM with your own function of the messages it receives. |
How close it is to the real thing
- Its responses are checked against a snapshot of the NoPII API's own schema, so the mock cannot drift from the real API unnoticed.
- It applies the same reveal policy, including session ownership and grants.
- Detection is deliberately simple: patterns, a list of names, and common first names followed by a surname. An unusual name may be missed where the real service would catch it. It refuses the same sample Social Security numbers NoPII does, so a demo cannot appear to protect a value production would let through.
- It does not implement the Anthropic Messages proxy route or device enrollment.
Related
- Browser SDK: point it at the mock with baseUrl
- Node.js SDK: the same, on the server