KERNIT Documentation
Node SDK-style client
Use this SDK-style Node client when you want application code to call scan, resolve, and apply as stable methods instead of repeating multipart request code in every workflow.
Client Shape#
This is not a published npm package yet. It is the official docs-side client shape KERNIT will keep aligned with the OpenAPI contract until a packaged SDK is released.
import { readFile, writeFile } from 'node:fs/promises';
import { basename } from 'node:path';
export class KernitHyperlinker {
constructor({ apiKey, baseUrl = 'https://api.kernit.org' }) {
if (!apiKey) throw new Error('apiKey is required');
this.apiKey = apiKey;
this.baseUrl = baseUrl.replace(/\/$/, '');
}
async multipart(endpoint, fields, filePath) {
const form = new FormData();
const file = new Blob([await readFile(filePath)], {
type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
});
form.set('file', file, basename(filePath));
for (const [key, value] of Object.entries(fields)) {
if (value === undefined || value === null) continue;
form.set(key, typeof value === 'string' ? value : JSON.stringify(value));
}
const response = await fetch(this.baseUrl + endpoint, {
method: 'POST',
headers: { Authorization: 'Bearer ' + this.apiKey },
body: form
});
const text = await response.text();
if (!response.ok) throw new Error(endpoint + ' failed: ' + response.status + ' ' + text);
return JSON.parse(text);
}
scan(filePath, settings) {
return this.multipart('/hyperlink-scan', { settings }, filePath);
}
resolve(filePath, { settings, scanFingerprint }) {
return this.multipart('/hyperlink-crossref', { settings, scanFingerprint }, filePath);
}
apply(filePath, { settings, scanFingerprint, scanToken, decisions, resolvedWorks = {} }) {
return this.multipart('/hyperlink-apply', {
settings,
scanFingerprint,
scanToken,
decisions,
resolvedWorks
}, filePath);
}
}
const kernit = new KernitHyperlinker({ apiKey: process.env.KERNIT_API_KEY });
const settings = {
"refs": true,
"figures": "number",
"tables": "number",
"equations": "number",
"sections": "number",
"doi": true,
"crossref": true,
"refTitleLink": false,
"linkColor": "#0077BD",
"xrefLinkColor": "#0077BD"
};
const scan = await kernit.scan('paper.docx', settings);
const resolved = await kernit.resolve('paper.docx', { settings, scanFingerprint: scan.scanFingerprint });
const decisions = scan.matches.map((match) => ({
refId: match.refId,
status: match.confidence >= 0.9 ? 'approved' : 'skipped',
targetId: match.targetId
}));
const applied = await kernit.apply('paper.docx', {
settings,
scanFingerprint: scan.scanFingerprint,
scanToken: scan.scanToken,
resolvedWorks: resolved.resolvedWorks || {},
decisions
});
await writeFile('paper.linked.docx', Buffer.from(applied.docx, 'base64'));Method Contract#
| Method | Endpoint | Purpose |
|---|---|---|
scan(filePath, settings) | /hyperlink-scan | Create review rows and scan state. |
resolve(filePath, state) | /hyperlink-crossref | Resolve bibliography evidence. |
apply(filePath, state) | /hyperlink-apply | Write approved links into the DOCX. |
Was this page useful?Send a lightweight docs feedback event.