Node SDK
The statejar package on npm, a typed client for StateJar's memory API in Node 20.3 or later. It stores what a message says and returns only the memory a question needs, as the system message for your own model, and it never sends a request you did not make.
What it does
- Store.
ingest({ sessionTag, text })sends one message. StateJar extracts typed facts from it, refuses a value that fails its type, and stores a new version named by its handle (shm_…). No transcript is stored. - Recall.
recall({ sessionTag, query, audit })returnsmemory_context, the system message for your model: the whole state while it is small, only the fields the question needs once it is large.audit: truewrites the disclosure to your audit log as an audited turn. - Read and restore.
state(handle),versions(sessionTag),restore({ handle, sessionTag }),auditLog({ limit, offset, sessionTag }),auditReplay(requestId),usage()andhealth(). - Careful by design.
baseUrlis required, so nothing reaches a server you did not name. Redirects are refused. Every call has a timeout and takes anAbortSignal. Nothing is retried on its own, since a repeated write could store a message twice. A developer key is refused in a browser unless you opt in. A key never appears in an error message.
The package is ESM with its types included, and it has no dependencies. StateJar never calls a model for you: your model key stays in your code.
Install
npm install statejar
You need Node 20.3 or later. npm serves version 0.2.1 (checked on 27 Oct 2026).
Set it up
Make a developer key on the API keys page and put it in STATEJAR_API_KEY. In Node the client reads it when you pass no apiKey; in a browser it never does. There is no npx statejar login yet, but the key the Python package's statejar login stores works here too.
| Option | Default | What it does |
|---|---|---|
baseUrl | none, required | The API root, such as https://api.statejar.com/api/v1. An origin alone gets /api/v1. |
apiKey | STATEJAR_API_KEY in Node | The developer key, sent as the X-API-Key header. |
timeoutMs | 30000 | Milliseconds a call may take. Each call also takes { signal, timeoutMs }. |
dangerouslyAllowBrowserApiKey | false | Lets a developer key be used in a browser, where anyone who loads the page can read it. Call StateJar from your server instead. |
A sessionTag names the conversation (1 to 100 characters). A new tag's first message builds on your newest memory in any tag.
Check it works
The first-turn example from getting started, saved as first-turn.mjs:
import { StateJarClient } from "statejar";
const sj = new StateJarClient({
baseUrl: process.env.STATEJAR_BASE_URL ?? "https://api.statejar.com/api/v1",
// apiKey: STATEJAR_API_KEY is read automatically in Node (never in a browser)
});
const tag = "user-42"; // one tag per conversation
await sj.ingest({ sessionTag: tag, text: "I'm Meera from Pune and I prefer email." });
await sj.ingest({ sessionTag: tag, text: "My budget is ₹3,500." });
const query = "What is my budget?";
const hit = await sj.recall({ sessionTag: tag, query, audit: true });
console.log(hit.handle_used); // shm_…
console.log(hit.memory_context); // the system message for your model
node first-turn.mjs prints the handle, then the facts your model would get:
npm install of the statejar package 0.3.0 as built from StateJar's repository (npm serves 0.2.1, which has the same calls), then the first-turn example in JavaScript, its key the one statejar login stored, read into STATEJAR_API_KEY. Same account and facts as the Python run, so it ends on the same handle. Recorded 27 Oct 2026 against a local StateJar server; the output is real, with pauses over 3 s cut to 3 s. Full sizeThe recording (.cast)What it sends
- To the API you name: the text of each message you
ingestand each question yourecallwith, with your key in theX-API-Keyheader. Nothing else, and nothing you did not call. - Never: your model key or your model's replies. The package does not call a model.
- On your machine: nothing. The package stores no state and keeps no log.
- What StateJar stores: typed facts, never the messages. Every recall is in your audit log, and deleting your account deletes all of it.
Troubleshooting
Every error is a StateJarError with a kind, the HTTP status when a response arrived, and the server's detail.
config:baseUrlis missing, not an absolutehttp(s)URL, or carries a query string.auth(401): the key is missing, wrong, revoked or expired, or it belongs to another server (staging and production keys differ).rate_limited(429): a limit of your plan (what each limit counts).detailcarries the server's answer.unavailableortimeout: the request never completed: DNS, a proxy, a wrongbaseUrl, or a server slower thantimeoutMs.redirect: the server answered with a redirect, which the client refuses so your key is never sent on to another host. Use the address the redirect pointed to, such ashttps://forhttp://.- "refusing to use a developer API key in a browser": call StateJar from your server, where the key stays private.
This page as Markdown: /docs/node-sdk.md