Skip to content
Jarvis home →
Docs / SDK guides / TypeScript · browser & server

TypeScript · browser & server

Two entry points with different trust boundaries. A browser helper is not a token client.

TYPESCRIPTSDK 0.2.0-alpha.1Updated Sep 9, 2026

Follow the GitLab npm registry setup, then:

Terminal
npm install --save-exact @jarvis/sdk@0.2.0-alpha.1
Import Runs in Responsibility
@jarvis/sdk Browser or backend Identity types, compound identity key and BFF navigation URL
@jarvis/sdk/personal Confidential backend / trusted server runner Consent, grants, disclosure and package verification
browser.ts
import { signInURL } from '@jarvis/sdk';
// A route YOU implement in the product backend, not a Jarvis API endpoint.
// Replace this example origin with your configured, cookie-isolated origin.
export const signInHref = signInURL(
'https://app.example.com/auth/jarvis/start',
'/onboarding',
);
// Use signInHref on an <a> element. No client secret or token in this module.
// The backend must independently allowlist the `next` return path.

signInURL does not authenticate anyone. The backend independently validates next and performs the OIDC flow. identityKey is a helper for already verified identity, not a JWT verifier. There is no TypeScript OIDC code-exchange client in this version; use the Go backend for the documented path.

Use a server with fetch, AbortSignal.timeout, atob/btoa and Web Crypto Ed25519 support. These examples are checked with Node 22 and TypeScript 5.9.2. Other runtimes require their own compatibility check.

server.ts
// SERVER ONLY. Never import this module into a browser bundle.
import { PersonalClient, type PersonalConfig } from '@jarvis/sdk/personal';
// All bindings come from a verified, backend-owned product session.
export function personalForSession(
session: Pick<PersonalConfig, 'issuer' | 'clientID' | 'subject' | 'accessToken'>,
) {
return new PersonalClient({
baseURL: 'https://jarvis-api-dev.k8s1.aviproduction.org/external/v1',
...session,
});
}
export async function requestContext(
client: PersonalClient,
registeredReturnURL: string,
) {
return client.createConsent({
fields: ['person.preferred_name'],
purpose: 'job_application',
redirect_uri: registeredReturnURL,
});
}
// IDs come from your user-bound operation record, not callback parameters.
export async function readApprovedContext(
client: PersonalClient, requestID: string, workUnit: string,
) {
const decision = await client.getConsent(requestID);
if (decision.status !== 'approved' || !decision.grant_id) {
throw new Error('Context not approved; keep the product session');
}
return client.disclose({
grant_id: decision.grant_id,
purpose: 'job_application',
fields: ['person.preferred_name'],
work_unit: workUnit,
}); // Verifies signature + expected bindings. Do not log personal values.
}

Persist the consent request ID before redirecting to consent_url. The return handler must use the request ID from its own user-bound operation record and read the decision from Jarvis. Persist a work-unit ID before disclosure so a transport retry does not accidentally describe a new operation.

The accessToken callback must load a current token from the authenticated backend session. It must not read a token from a URL, localStorage, an LLM prompt or an employer page. The SDK does not refresh tokens or retry failed requests for you.

PersonalAPIError exposes status and the stable code. Stop on denial, stale work units, expired grants or unavailable services. Verification failure rejects the package; do not catch it and use the decoded payload anyway.

See the error reference and context lifecycle. The SDK returns personal values: keep them out of telemetry, exception dumps and debug consoles.