TypeScript · browser & server
Two entry points with different trust boundaries. A browser helper is not a token client.
Install
Section titled “Install”Follow the GitLab npm registry setup, then:
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: link to your backend
Section titled “Browser: link to your backend”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.
Server: request and verify context
Section titled “Server: request and verify context”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 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.
Handle failures without stale data
Section titled “Handle failures without stale data”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.