Skip to content

License setup — Web

You ran pnpm add @dvai-bridge/core. You want to ship to a real domain. Here's everything you need.

TL;DR

Drop your dvai-license.jwt into your static-assets folder — public/ for Vite, Next.js, CRA; static/ for SvelteKit. Ship.

The SDK fetches /dvai-license.jwt from the same origin at startup. Signature verification runs offline. Production behaviour unlocks. On localhost, the SDK ignores license problems entirely.

Where the file goes

Default — auto-discovered. Your origin must serve the file at /dvai-license.jwt. For most bundlers that means the static-assets folder:

FrameworkDrop the file at
Vite (React, Vue, Svelte, vanilla)public/dvai-license.jwt
Next.jspublic/dvai-license.jwt
Create React Apppublic/dvai-license.jwt
SvelteKitstatic/dvai-license.jwt
Astropublic/dvai-license.jwt
Webpack (no plugin)whatever path your output.publicPath resolves to

Verify — hit https://<your-domain>/dvai-license.jwt in a browser. You should see the JWT text. If your edge or CDN strips unknown file extensions, register .jwt as text/plain or application/jwt.

Code: with vs. without

Without a license — development, localhost:

ts
import { DVAI } from "@dvai-bridge/core";

const dvai = new DVAI({
  backend: "auto",
  modelId: "Llama-3.2-1B-Instruct-Q4_K_M",
});

await dvai.initialize();
// On localhost: dvai.licenseStatus.kind === "free-dev"

With a license — production, default discovery:

ts
// Same code as above. Nothing changes.
// As long as /dvai-license.jwt is served from the same origin,
// dvai.licenseStatus.kind will be "commercial" or "trial" after init.

With a license at a non-default path:

ts
const dvai = new DVAI({
  backend: "auto",
  modelId: "Llama-3.2-1B-Instruct-Q4_K_M",
  licenseKeyPath: "/assets/dvai-license.jwt", // any same-origin URL
});

With the JWT injected inline — env var, CI secret, etc:

ts
const dvai = new DVAI({
  backend: "auto",
  modelId: "Llama-3.2-1B-Instruct-Q4_K_M",
  licenseToken: import.meta.env.VITE_DVAI_LICENSE_JWT,
});

Precedence — licenseToken wins over licenseKeyPath, which wins over auto-discovery.

What happens without a license

In production — any non-localhost origin — initialize() throws LicenseRequiredError:

ts
import { DVAI, LicenseRequiredError } from "@dvai-bridge/core";

try {
  await dvai.initialize();
} catch (err) {
  if (err instanceof LicenseRequiredError) {
    // err.message is verbose — points at the discovery paths and
    // the dev-mode bypass list.
    // err.status.kind is "free-prod" or "free-expired".
    console.error(err.message);
  }
}

The error message ships the resolution steps inline. Surface it in your error reporter — Sentry, console, server log — and you'll see exactly which check failed.

Testing locally without a license

You don't have to do anything. localhost, 127.0.0.1, *.local, and RFC1918 hostnames all auto-detect as dev mode. The SDK starts and logs licenseStatus.kind === "free-dev".

Serving your dev build from a non-localhost host — e.g. a real DNS name behind ngrok? Force dev mode:

ts
// Pick one of these before DVAI's first initialize():
window.localStorage.setItem("DVAI_FORCE_DEV", "true");

To rehearse production behaviour on localhost:

ts
window.localStorage.setItem("DVAI_FORCE_PROD", "true");

When validation fails

Common failures and what they mean:

Error reason fragmentWhat's wrongFix
not a well-formed JWTFile is empty, truncated, or HTML 404 pageVerify /dvai-license.jwt returns the raw token
unsupported algToken signed with the wrong algorithmRe-issue with ES256
kid ... is not in the SDK's public-key registryYou're on an old SDK that pre-dates a key rotationUpgrade @dvai-bridge/core
signed with the placeholder keyYou're using a development SDK that hasn't shipped a real keyReplace publicKeys.ts with your generated key
signature did not verifyToken was tampered with or wrong keyRe-download from your licensor
does not authorise platform "web"License doesn't include "web" in its platforms claimRe-issue covering web
audience entries ... do not matchToken bound to a different hostnameRe-issue with the right aud, or use a *.your-domain.com wildcard
expiredPast expRenew

Every reason logs to console when validation fails — even when the SDK throws.

See also