JavaScript · fetch, no dependencies
/**
* Hera — protect, open, and check containment.
*
* Runs unchanged on Node 18+, Deno, Bun and any edge runtime with fetch.
* SERVER SIDE ONLY: the API key is a credential and must never reach a
* browser bundle.
*/
const BASE_URL = process.env.QX_BASE_URL;
const API_KEY = process.env.QX_API_KEY; // from a secret store
class ContainmentError extends Error {}
async function call(method, path, body, { idempotent = false } = {}) {
const headers = { Authorization: `Bearer ${API_KEY}` };
if (body !== undefined) headers['Content-Type'] = 'application/json';
if (idempotent) headers['Idempotency-Key'] = crypto.randomUUID();
const response = await fetch(`${BASE_URL}${path}`, {
method,
headers,
body: body === undefined ? undefined : JSON.stringify(body),
// Refuse a redirect rather than following it: by the time a redirect is
// followed, the Authorization header has already been sent somewhere.
redirect: 'error',
});
if (!response.ok) {
const detail = await response.json().catch(() => ({}));
if (response.status === 422) {
throw new ContainmentError(detail.detail ?? 'containment failed');
}
throw new Error(`${response.status} ${detail.type ?? 'error'}: ${detail.detail ?? ''}`);
}
return response.json();
}
const b64 = {
encode: (bytes) => Buffer.from(bytes).toString('base64'),
decode: (text) => new Uint8Array(Buffer.from(text, 'base64')),
};
export async function protect(plaintext, domain) {
return call('POST', '/v1/protect', {
data: b64.encode(plaintext),
domain,
}, { idempotent: true });
}
export async function openRecord(sealed) {
const result = await call('POST', '/v1/open', {
payload: sealed.payload,
recovery: sealed.recovery,
});
return b64.decode(result.data);
}
export async function sphereHealth(domain) {
return call('GET', `/v1/spheres/health?domain=${encodeURIComponent(domain)}`);
}
// ── Round trip ────────────────────────────────────────────────────────────
const message = new TextEncoder().encode('account 4471 closing balance 918204');
const sealed = await protect(message, 'ledger.balances');
console.log(`tier ${sealed.tier}, ${sealed.barriers} barriers`);
// STORE THESE APART — together they are the plaintext.
// sealed.payload -> record store
// sealed.recovery -> secret store, different access control
console.log(new TextDecoder().decode(await openRecord(sealed)));
const health = await sphereHealth('ledger.balances');
console.log('containment healthy:', health.healthy);
for (const sphere of health.spheres) {
console.log(` sphere ${sphere.index}: ${sphere.verdict}`);
}