JavaScript: install and configure
Install @sovaria/sdk, where it runs, create a client for browsers and for servers, every configuration option, sessions, retries and idempotency, errors and their codes, and fixes for common setup problems.
Install
npm install @sovaria/sdk| Runs in | Notes |
|---|---|
| Browsers | Modern evergreen browsers. Sessions persist in localStorage by default. |
| Node.js | Any version with global fetch (18+). Pass fetchImpl to use another implementation. |
| Deno, Bun, edge runtimes | Uses the global fetch and Web Crypto. |
| React Native | persistSession: { storage } takes a synchronous store (getItem, setItem, removeItem — for example MMKV). With an async store such as AsyncStorage, save tokens from onTokenRefreshSensitive and restore them with setAccessToken / setRefreshToken (Sign-in for mobile apps). |
Create a client
import { createClient } from '@sovaria/sdk'
export const sovaria = createClient(
import.meta.env.VITE_SOVARIA_URL, // https://<project-ref>.sovarias.in
import.meta.env.VITE_SOVARIA_ANON_KEY,
)One client per app (or per request on a server acting for users). The URL names the project, so no ids are needed. Which key goes where: Connect your app; variable names: Environment variables.
Options
| Option | Default | What it does |
|---|---|---|
persistSession | On in browsers when an anon key is given | true keeps the session in localStorage; false keeps it in memory only; { storage, key } uses another synchronous store. |
onTokenRefresh | — | Called with new tokens after sign-in or refresh (without the refresh token). |
onTokenRefreshSensitive | — | The same, including the refresh token — store it securely, never log it. |
accessToken, expiresIn | — | Start with an existing token. |
envId | Production | Talk to another environment of the project. |
orgId, projectId | Discovered from the URL | Pin them for multi-project tools. |
Retry and transport settings are set when you construct the client directly: new SovariaSDK({ baseUrl, accessToken, refreshToken, persistSession, fetchImpl, retryCount, retryBaseDelayMs }).
Retries and idempotency
- Requests that fail with
429,500,502,503or504, or with a network error, are retried — 4 attempts in all by default (retryCount), with jittered exponential backoff from 100 ms (retryBaseDelayMs, at most 10 s). After a429the SDK waits at least theRetry-Aftertime. - Writes (
POST,PUT,PATCH,DELETE) are retried too, and a retried write is applied once: every write carries oneIdempotency-Keyfrom its first attempt, so if the server applied it but the response was lost, the retry gets the stored answer instead of running it again. A retry that arrives while the first try is still running waits for it. - The key belongs to one call. To make a write safe for your own code to repeat (after a crash or a page reload, say), pass a key you can recreate, such as
order-<id>:sovaria.request(method, path, { body, idempotencyKey }). The server keeps the answer for an hour (two minutes when it carries tokens or keys); the same key with a different body gets409 IDEMPOTENCY_PAYLOAD_MISMATCH.idempotent: trueis no longer needed and is still accepted. - Access tokens are refreshed a minute before they expire, and once more after a
401; you don't need to handle expiry yourself.
Errors
Failed calls throw SovariaError with a stable code to branch on and a message you can show to users:
import { SovariaError } from '@sovaria/sdk'
try {
await sovaria.data.sql('insert into orders (total) values ($1)', [42])
} catch (err) {
if (!(err instanceof SovariaError)) throw err
switch (err.code) {
case 'UNAUTHENTICATED': return goToSignIn()
case 'PERMISSION_DENIED': return toast('You can\'t do that.')
case 'PLAN_LIMIT_REACHED':
case 'PLAN_QUOTA_EXHAUSTED': return showUpgrade(err.detail)
case 'RATE_LIMITED': return toast('Too many requests — try again in a moment.')
default: console.error(err.technicalMessage); toast(err.message)
}
}| Field | Value |
|---|---|
code | NETWORK_ERROR, UNAUTHENTICATED, PERMISSION_DENIED, NOT_FOUND, CONFLICT, INVALID_INPUT, PAYLOAD_TOO_LARGE, UNSUPPORTED_TYPE, RATE_LIMITED, PLAN_LIMIT_REACHED, PLAN_FEATURE_REQUIRED, PLAN_QUOTA_EXHAUSTED, SERVICE_UNAVAILABLE, SERVER_ERROR, BAD_REQUEST, CONFIG_ERROR, UNKNOWN |
message | A friendly sentence for end users. |
statusCode | The HTTP status (0 when no response arrived). |
serverCode | The server's own code when it sent one (SIGNUP_DISABLED, …). |
detail | The response body. |
technicalMessage | HTTP <status>: <server text> for logs. |
Troubleshooting
| Symptom | Fix |
|---|---|
403 ORIGIN_NOT_ALLOWED in the browser | Add your site's origin under Project Settings › API (Allowed origins (CORS) for browser apps). |
CONFIG_ERROR at start-up (Missing portal URL, Missing SOVARIA_URL) | The URL isn't set — check the variable names and that your bundler exposes them (VITE_, NEXT_PUBLIC_). |
Warning: publishableKey looks like a user JWT | A session token was passed where the anon key belongs; pass tokens with setAccessToken. |
| Signed out after every reload | Sessions persist by default only in browsers with an anon key; on servers pass the user's token per request. |
Every call is PERMISSION_DENIED | Your rules don't allow it yet — see How access is decided. |
Something unclear or missing on this page?Tell us