Licensing
Intent
Evaluation is free, unlimited and fully featured, and every evaluation render carries a marking. A license key removes the marking. Nothing else changes, so what you prototype against is what you ship.
Design decisions
You state the key once, on the instance. It sits beside the locale and the query budgets, because it describes the deployment rather than any document.
Verification is offline. The check runs locally through WebCrypto, and nothing is ever sent anywhere. There is no license server to be down, no call-home, and no network dependency in your render path.
Keys carry no secrets and may ship with your application. The payload is the licensee, the id and a validity window, signed. Embedding it in a bundle is the intended use, not a tolerated one.
The release date decides validity, never the clock. A key is valid when its window covers the installed version’s release date. Nothing time-bombs, so output a key covers stays covered forever, and an old version keeps working after a subscription lapses.
A refused key never throws and never gates a feature. The promise settles rather than rejecting, the instance logs a single warning, and the stream carries the marking. A licensing failure must not take a production render down.
The engine states the wording, so a target owns only where it goes. A custom target marks its output correctly without knowing the text, and no document or dataset can change what it says.
The marking must never depend on a grant. A marking blocked by a Content Security Policy would fail open, which is worse than none. It’s the one output that can’t rely on a directive a host might withhold.
API walkthrough
Activating
import { quario } from 'quario'
const q = quario({ license: 'quario_...' })
const { licensed, licensee, id } = await q.licenseq.license settles with { licensed, licensee?, id? } and never rejects.
Without a key it settles { licensed: false }.
Verification starts once, as the instance comes up, and every report that instance compiles shares the result.
Rendering around the check
render awaits settlement itself, so target output is never marked by a race.
A consumer draining report.stream(data) directly is the one case that can
outrun it. Await the promise first.
await q.license
for (const event of report.stream(data)) {
if (event.type === 'report-start' && event.marking) console.log(event.marking)
}What the marking looks like
report-start.marking carries the wording, and is absent on a licensed
stream. Each target renders it natively.
HTML opens the fragment with <div class="q-unlicensed"> as its first
element, outside the report root so an author’s declared size can’t reach
it. The shipped stylesheet leaves it unstyled, because a watermark treatment
would escape the fragment’s box onto your page.
PDF draws it once per page, after everything else, so no filled cell or background covers it.
XLSX writes it twice, as a banner in row 1 and as the workbook’s description. The whole report therefore sits one row lower than a licensed render.
CSV writes it as one trailing line, so a parser reading headers from record 1 still can.
The viewer marks the sheet, so a preview never shows an unmarked page for a render that would export marked.
In every case the presence of the marking is normative and its visual treatment isn’t.
Marking your own target
A custom target reads report-start.marking and draws it. Don’t restate the
wording, and don’t derive it from anything in the document.
import { walk } from 'quario'
await walk(report.stream(data), {
'report-start': (e) => {
if (e.marking) console.log(e.marking)
},
})Secure contexts only
crypto.subtle is a secure-context API, so a key soft-fails on a plain-HTTP
page. That’s a browser constraint rather than a quario one, and it fails the
way every other refusal does, by marking rather than throwing.
What a seat covers
A seat is a developer who writes definitions or calls the API. Deployment after that’s unlimited and royalty-free. Bundling quario into software your customers install or resell is OEM, while generating documents from your own hosted product isn’t. Pricing has the current terms.