TypeScript is where most Jev integrations start: a Next.js route, a Cloudflare Worker, a script beside an agent. The official JavaScript and TypeScript SDK covers the first two, but "edge" is not one runtime. A Worker has no Node standard library, a Vercel function has a gateway in front of it, and a local script has neither. The request stays the same; validation and failures do not.
What the official SDK gives you
Install with npm install @typesafe-ai/sdk. The package requires Node.js 20 or newer and ships ESM, CommonJS, and TypeScript declarations, so it works from both import and require. The client reads TYPESAFE_API_KEY from the environment, and the usage guide shows the shortest path: construct new TypeSafeClient(), send a state and a question map, read response.answers.category.choice.
Questions use the exported choice(), score(), and noul() helpers, and answer types are inferred from them. That inference is the main reason to use the SDK instead of raw fetch: a choice question returns the winning label, and TypeScript knows it.
Retry defaults: maxRetries 2, 500 ms backoff doubling to 5,000 ms, jitter 0.25, retries on 408, 429, and 500-599, and Retry-After honored up to 60 seconds. The README is a quickstart; full defaults live in src/client.ts and src/types.ts. Set your budget explicitly rather than assuming the README is the contract.
Edge runtimes are not one target
The Node 20 requirement is the first constraint. Cloudflare Workers do not run Node 20 as a general runtime, so the official SDK is not the natural fit inside a Worker. Cloudflare's own Workers AI model page exposes typesafe/jev through a binding instead: env.AI.run('typesafe/jev', { state, questions }), or a REST POST /ai/run with an account ID and an AI token. No TypeSafe key appears in either path. The card lists a 32,000-token context window, marks the model third-party, and states zero data retention.
That binding changes the trust boundary. You are authenticating to Cloudflare, not TypeSafe, and the model is one entry in a catalog that also carries Cloudflare's own Clef. The Clef card describes a 27B multimodal model, Apache-2.0, built on a Qwen3.8-27B base, returning a probability for every allowed option in one forward pass. It is System One-compatible, not a TypeSafe release, and nothing on the card claims parity with Jev. A Worker can put both behind one interface, but should not assume the probabilities mean the same thing.
For a zero-dependency client that works in more JavaScript runtimes, @cmaintz/jev-core is the community option. It is ESM only, needs Node 22 or newer because it uses global fetch, and ships a TypeSafeProvider and a CloudflareProvider with validation through parseJevResponse. providerFromEnv returns null when JEV_API_KEY is unset, which lets a caller fail open. It is unofficial, and its default jev-latest can move under you; pin JEV_MODEL if you need reproducible answers.
"Works at the edge" means three things: the module format loads, the runtime has the APIs the client uses, and the timeout fits the platform. The binding path satisfies all three on Workers, at the cost of a different auth model.
Vercel: a gateway and a first-party provider
Vercel lists Jev as typesafe-ai/jev on the AI Gateway: evaluation type, $0.042 per 1M input tokens, no output charge because maximum output tokens is 0, and a 32,000-token context. TypeSafe confirmed the listing in an announcement post, and the evaluation docs explain the call shape.
Two details matter. First, evaluation is not served through the OpenAI-compatible, Anthropic-compatible, or Cohere-compatible endpoints. Through the AI SDK you need experimental_evaluate from ai on AI SDK 7 or later; everyone else posts to /v1/evaluate on ai-gateway.vercel.sh. Second, providerOptions.gateway accepts zeroDataRetention and only: ['typesafe-ai']. Both TypeSafe AI and DigitalOcean are listed, so pin the provider if residency or contracting depends on it.
The AI SDK itself is the broader TypeScript toolkit, not a Jev-specific package. The Vercel AI SDK entry records 27,329 stars and a NOASSERTION license, and its catalog README is only a pointer. The Jev-specific package is @ai-sdk/typesafe-ai, which exposes typeSafeAi.decisionModel('jev-latest') for experimental_decide. If you already use the AI SDK, the gateway plus provider is one transport for every model; if the decision sits in a tight loop, the extra hop is real. Jev on the Gateways lays out the trade.
Validate the answer, not just the status
A 200 response is not a valid decision. The response needs an answers object, the key you asked for, the right answer type, a choice in your option list, and probabilities that are finite numbers between 0 and 1. The SDK gives typed access and a response-validation error class; a gateway or a hand-rolled fetch gives you JSON.
@cmaintz/jev-core is explicit about its validation: parseJevResponse throws if there is no answers object and drops any answer that is missing, has the wrong type, names an unknown choice, or has a non-finite or out-of-range number. Callers see those as no answer and can fail safe. That is a useful model for your own adapter. A minimal runtime check looks like this:
| Check | Why it matters |
|---|---|
answers[id] exists | A partial response should not become a default branch |
type matches the question | A choice answer read as a noul is a bug |
Choice is in criteria | The model must not invent an option |
| Numbers are finite and 0-1 | NaN passes naive comparisons |
model is the one you pinned | An alias may have moved |
The generated SDK API reference documents the shapes: answers keyed by the ids you supply, Choice up to 255 options, Score 2 to 10 levels, and a 0-1 confidence on Choice and Score. A typed decision is only typed if the boundary enforces the type. Confidence is separate from the option probabilities, and boolean answers do not carry it.
Pick the surface by where the code runs
| Surface | Auth | Best fit | Main cost |
|---|---|---|---|
| Official SDK, direct | TypeSafe key | Node services, scripts, long-lived clients | You own retries and timeouts |
| Workers AI binding | Cloudflare account | Cloudflare Workers, edge-local calls | Different auth and model card |
| Vercel AI Gateway | Gateway credentials | Next.js and AI SDK apps | One network hop |
| Community client | TypeSafe or gateway | Runtimes without the official SDK | Unofficial, version lag |
A base URL change is enough to move between TypeSafe and a wire-compatible gateway, but it is not enough to make the answers equivalent. A local server can accept the JSON and still refuse question types, cap options, or return uncalibrated probabilities. Serving System One Locally covers that trade.
Versioning and failure modes
The JS changelog lists two releases: v0.5.7 on 11 September 2026 was the initial release, and v0.6.0 on 15 September 2026 made Score.criteria an ordered sequence instead of an integer-keyed dictionary. The second is breaking. The changelog stops there and does not track everything the Python SDK did, so do not infer parity.
Pin the SDK and the model. Keep the retry budget shorter than the platform's request deadline, because Retry-After can ask for up to 60 seconds. Treat a missing or malformed answer as no answer, not as a negative one. Keep the provider id in your logs; on a multi-provider gateway, the returned model is evidence. Retries and Failure Modes covers the rest of the taxonomy.
The TypeScript ecosystem gives you more surfaces than any other language, and that is the risk. Pick one, validate at its boundary, and write down which model and provider answered. The code that branches on the answer is only as trustworthy as the check in front of it.