Prerequisites
Use Node.js 20 or later. SetSILMARIL_API_KEY and SILMARIL_API_URL from your deployment access.
Install
Classify your first request
Create one client per protected system and reuse it. Label each call with the boundary it checks.Expected result
A benign request logsBENIGN, its score, and allow. Direct classify calls return a result in every mode. To enforce Block mode, stop the event when prediction is MALICIOUS or governance.action is block, then route it with firewall outcomes.
See confidence scores for score meaning and threshold behavior.
A per-call mode wins the client setting. Either local choice is sent with the request and preserved in result.mode. Without a local override, current classify responses omit mode, so result.mode remains absent. Direct calls are decision-only regardless: the caller chooses whether to enforce according to its local mode and application policy.
A rejected promise means the call did not produce a verdict. That includes SilmarilApiError for a non-2xx API response, and a network, timeout, or abort error. With native fetch, a refused redirect raises a TypeError. Custom fetch implementations can differ. Decide whether that boundary fails open or closed.
Vercel, LangChain, and LangGraph integrations that wrap this client are documented in Framework SDKs.
Concurrent requests
Reuse one client for concurrent calls in a JavaScript runtime when those calls are independent events or different conversations. Ordered events that share onemetadata.conversationId wait for each classify() call before the next event is sent. Pass signal to classify or classifyBatch to cancel one request and its retry wait. Create a client in each worker thread.
request.signal is the caller’s AbortSignal. classifyBatch() cancels as one request. Its items stay independent of one another.
Batch calls and conversation history
classifyBatch() requires a predictions array with one result per input. Missing or mismatched results reject with an Error, including during retries.
Pass metadata: { conversationId } on each ordered classify() call. Wait for and handle its verdict or error before sending the next event. Batch calls preserve per-item metadata and treat items independently of conversation history.
See events and conversations for sequencing and modes and enforcement for returned verdicts in Warn and Shadow.
Classify in parallel
From SDK 0.10.0,protect() runs your call while its input is classified instead of waiting for the verdict first. It accepts the classify() options plus the input text, and resolves with your call’s result.
callModel, prompt, and conversationId belong to your application. Unlike direct classify(), protect() enforces the verdict.
Without a local mode,
protect() uses the Block fallback. The optional output function extracts text from the result. That text is classified as llm_output before the result is returned in Block mode, and in the background in Shadow or Warn.
Use protect() for calls whose effect can be discarded, such as a model call. Classify the arguments of a tool that writes with classify() before running it.
Classifications that share one metadata.conversationId are sent in the order they started, so protect() keeps the conversation sequence without waiting between events. Two client options bound this work: maxConcurrent (default 32) limits classifications in flight, and maxQueued (default 64) limits unjoined background classifications per conversation. A background classification retries once. Background classifications are also capped at maxConcurrent * maxQueued across all conversations. A failed one is logged with console.warn and never rejects, and one that would exceed either limit is dropped with a warning. Metadata and governance are copied when the call starts, so changing them afterwards does not change a classification already under way.
Call await fw.flush() to wait for background classifications, for example before a serverless handler returns.
Shadow mode
An explicit local Shadow mode reports would-block decisions with the same thresholds while traffic continues. In Shadow mode, LangChain handlers and Deep Agents middleware classify in the background, soonClassify runs after the callback returns; set failOpen: false to keep those checks inline. Vercel middleware classifies inline in every mode. Framework adapters resolve an adapter override first, then the client setting, then an optional response mode, and finally a Block fallback. Current classify responses omit mode, so set Shadow or Warn locally when an adapter should observe rather than block.
Enforce one boundary
enforcingHandler to the model or graph whose callbacks should enforce.
Errors
Blocking behavior depends on the integration.protect(), Vercel non-streaming generation, and LangChain callbacks throw FirewallBlockedException when they enforce a malicious or governance-block decision. The exception carries score and threshold.
generateText and model come from the Vercel integration. With Vercel streaming, an output block surfaces as an error stream part after any text already emitted. Deep Agents replaces denied tool interactions or model content with fixed safe messages in Block mode. See Deep Agents. Rethrow any non-block error from non-streaming calls according to your application error policy.
HTTP 408 handling
TypeScript retries HTTP429 only. HTTP 408, including the direct runtime request-body timeout before classification, is surfaced as SilmarilApiError. This timeout closes the connection and produces no verdict. It does not establish replay safety for model or tool operations.
Review depth
See review depth for minimum SDK versions and selection behavior. The publicReviewLevel type is "standard" | "deep". Set review in Firewall options for an explicit client default, or in classify and classifyBatch options for a per-call selection. Resolution is explicit per-call value, then explicit client default, then omission of the wire field. The SDK never invents an implicit default.
standard and deep. Invalid values, including null, fail SDK validation. Missing or mismatched backend acknowledgement produces ReviewCompatibilityError. See review depth for runtime requirements and response handling.